summaryrefslogtreecommitdiff
path: root/pfinet/linux-inet/devinet.c
blob: 946536bec044d81c4e46ca7b8964e36aa96c31ed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
/*
 *	NET3	IP device support routines.
 *
 *		This program is free software; you can redistribute it and/or
 *		modify it under the terms of the GNU General Public License
 *		as published by the Free Software Foundation; either version
 *		2 of the License, or (at your option) any later version.
 *
 *	Derived from the IP parts of dev.c 1.0.19
 * 		Authors:	Ross Biro, <bir7@leland.Stanford.Edu>
 *				Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
 *				Mark Evans, <evansmp@uhura.aston.ac.uk>
 *
 *	Additional Authors:
 *		Alan Cox, <gw4pts@gw4pts.ampr.org>
 */
 
#include <asm/segment.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/socket.h>
#include <linux/sockios.h>
#include <linux/in.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
#include <linux/if_ether.h>
#include <linux/inet.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include "ip.h"
#include "route.h"
#include "protocol.h"
#include "tcp.h"
#include <linux/skbuff.h>
#include "sock.h"
#include "arp.h"

/* 
 *	Determine a default network mask, based on the IP address. 
 */
 
unsigned long ip_get_mask(unsigned long addr)
{
  	unsigned long dst;

  	if (addr == 0L) 
  		return(0L);	/* special case */

  	dst = ntohl(addr);
  	if (IN_CLASSA(dst)) 
  		return(htonl(IN_CLASSA_NET));
  	if (IN_CLASSB(dst)) 
  		return(htonl(IN_CLASSB_NET));
  	if (IN_CLASSC(dst)) 
  		return(htonl(IN_CLASSC_NET));
  
  	/*
  	 *	Something else, probably a multicast. 
  	 */
  	 
  	return(0);
}

/* 
 *	Check the address for our address, broadcasts, etc. 
 *
 *	I intend to fix this to at the very least cache the last
 *	resolved entry.
 */
 
int ip_chk_addr(unsigned long addr)
{
	struct device *dev;
	unsigned long mask;

	/* 
	 *	Accept both `all ones' and `all zeros' as BROADCAST. 
	 *	(Support old BSD in other words). This old BSD 
	 *	support will go very soon as it messes other things
	 *	up.
	 *	Also accept `loopback broadcast' as BROADCAST.
	 */

	if (addr == INADDR_ANY || addr == INADDR_BROADCAST ||
	    addr == htonl(0x7FFFFFFFL))
		return IS_BROADCAST;

	mask = ip_get_mask(addr);

	/*
	 *	Accept all of the `loopback' class A net. 
	 */
	 
	if ((addr & mask) == htonl(0x7F000000L))
		return IS_MYADDR;

	/*
	 *	OK, now check the interface addresses. 
	 */
	 
	for (dev = dev_base; dev != NULL; dev = dev->next) 
	{
		if (!(dev->flags & IFF_UP))
			continue;
		/*
		 *	If the protocol address of the device is 0 this is special
		 *	and means we are address hunting (eg bootp).
		 */
		 
		if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/)
			return IS_MYADDR;
		/*
		 *	Is it the exact IP address? 
		 */
		 
		if (addr == dev->pa_addr)
			return IS_MYADDR;
		/*
		 *	Is it our broadcast address? 
		 */
		 
		if ((dev->flags & IFF_BROADCAST) && addr == dev->pa_brdaddr)
			return IS_BROADCAST;
		/*
		 *	Nope. Check for a subnetwork broadcast. 
		 */
		 
		if (((addr ^ dev->pa_addr) & dev->pa_mask) == 0) 
		{
			if ((addr & ~dev->pa_mask) == 0)
				return IS_BROADCAST;
			if ((addr & ~dev->pa_mask) == ~dev->pa_mask)
				return IS_BROADCAST;
		}
		
		/*
	 	 *	Nope. Check for Network broadcast. 
	 	 */
	 	 
		if (((addr ^ dev->pa_addr) & mask) == 0) 
		{
			if ((addr & ~mask) == 0)
				return IS_BROADCAST;
			if ((addr & ~mask) == ~mask)
				return IS_BROADCAST;
		}
	}
	if(IN_MULTICAST(ntohl(addr)))
		return IS_MULTICAST;
	return 0;		/* no match at all */
}


/*
 *	Retrieve our own address.
 *
 *	Because the loopback address (127.0.0.1) is already recognized
 *	automatically, we can use the loopback interface's address as
 *	our "primary" interface.  This is the address used by IP et
 *	al when it doesn't know which address to use (i.e. it does not
 *	yet know from or to which interface to go...).
 */
 
unsigned long ip_my_addr(void)
{
  	struct device *dev;

  	for (dev = dev_base; dev != NULL; dev = dev->next) 
  	{
		if (dev->flags & IFF_LOOPBACK) 
			return(dev->pa_addr);
  	}
  	return(0);
}

/*
 *	Find an interface that can handle addresses for a certain address. 
 *
 *	This needs optimising, since it's relatively trivial to collapse
 *	the two loops into one.
 */
 
struct device * ip_dev_check(unsigned long addr)
{
	struct device *dev;

	for (dev = dev_base; dev; dev = dev->next) 
	{
		if (!(dev->flags & IFF_UP))
			continue;
		if (!(dev->flags & IFF_POINTOPOINT))
			continue;
		if (addr != dev->pa_dstaddr)
			continue;
		return dev;
	}
	for (dev = dev_base; dev; dev = dev->next) 
	{
		if (!(dev->flags & IFF_UP))
			continue;
		if (dev->flags & IFF_POINTOPOINT)
			continue;
		if (dev->pa_mask & (addr ^ dev->pa_addr))
			continue;
		return dev;
	}
	return NULL;
}