xref: /csrg-svn/sys/netinet/in.c (revision 32787)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
6  * provided that this notice is preserved and that due credit is given
7  * to the University of California at Berkeley. The name of the University
8  * may not be used to endorse or promote products derived from this
9  * software without specific prior written permission. This software
10  * is provided ``as is'' without express or implied warranty.
11  *
12  *	@(#)in.c	7.6 (Berkeley) 12/07/87
13  */
14 
15 #include "param.h"
16 #include "ioctl.h"
17 #include "mbuf.h"
18 #include "protosw.h"
19 #include "socket.h"
20 #include "socketvar.h"
21 #include "uio.h"
22 #include "dir.h"
23 #include "user.h"
24 #include "in_systm.h"
25 #include "../net/if.h"
26 #include "../net/route.h"
27 #include "../net/af.h"
28 #include "in.h"
29 #include "in_var.h"
30 
31 #ifdef INET
32 inet_hash(sin, hp)
33 	register struct sockaddr_in *sin;
34 	struct afhash *hp;
35 {
36 	register u_long n;
37 
38 	n = in_netof(sin->sin_addr);
39 	if (n)
40 	    while ((n & 0xff) == 0)
41 		n >>= 8;
42 	hp->afh_nethash = n;
43 	hp->afh_hosthash = ntohl(sin->sin_addr.s_addr);
44 }
45 
46 inet_netmatch(sin1, sin2)
47 	struct sockaddr_in *sin1, *sin2;
48 {
49 
50 	return (in_netof(sin1->sin_addr) == in_netof(sin2->sin_addr));
51 }
52 
53 /*
54  * Formulate an Internet address from network + host.
55  */
56 struct in_addr
57 in_makeaddr(net, host)
58 	u_long net, host;
59 {
60 	register struct in_ifaddr *ia;
61 	register u_long mask;
62 	u_long addr;
63 
64 	if (IN_CLASSA(net))
65 		mask = IN_CLASSA_HOST;
66 	else if (IN_CLASSB(net))
67 		mask = IN_CLASSB_HOST;
68 	else
69 		mask = IN_CLASSC_HOST;
70 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
71 		if ((ia->ia_netmask & net) == ia->ia_net) {
72 			mask = ~ia->ia_subnetmask;
73 			break;
74 		}
75 	addr = htonl(net | (host & mask));
76 	return (*(struct in_addr *)&addr);
77 }
78 
79 /*
80  * Return the network number from an internet address.
81  */
82 u_long
83 in_netof(in)
84 	struct in_addr in;
85 {
86 	register u_long i = ntohl(in.s_addr);
87 	register u_long net;
88 	register struct in_ifaddr *ia;
89 
90 	if (IN_CLASSA(i))
91 		net = i & IN_CLASSA_NET;
92 	else if (IN_CLASSB(i))
93 		net = i & IN_CLASSB_NET;
94 	else if (IN_CLASSC(i))
95 		net = i & IN_CLASSC_NET;
96 	else
97 		return (0);
98 
99 	/*
100 	 * Check whether network is a subnet;
101 	 * if so, return subnet number.
102 	 */
103 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
104 		if (net == ia->ia_net)
105 			return (i & ia->ia_subnetmask);
106 	return (net);
107 }
108 
109 /*
110  * Return the host portion of an internet address.
111  */
112 u_long
113 in_lnaof(in)
114 	struct in_addr in;
115 {
116 	register u_long i = ntohl(in.s_addr);
117 	register u_long net, host;
118 	register struct in_ifaddr *ia;
119 
120 	if (IN_CLASSA(i)) {
121 		net = i & IN_CLASSA_NET;
122 		host = i & IN_CLASSA_HOST;
123 	} else if (IN_CLASSB(i)) {
124 		net = i & IN_CLASSB_NET;
125 		host = i & IN_CLASSB_HOST;
126 	} else if (IN_CLASSC(i)) {
127 		net = i & IN_CLASSC_NET;
128 		host = i & IN_CLASSC_HOST;
129 	} else
130 		return (i);
131 
132 	/*
133 	 * Check whether network is a subnet;
134 	 * if so, use the modified interpretation of `host'.
135 	 */
136 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
137 		if (net == ia->ia_net)
138 			return (host &~ ia->ia_subnetmask);
139 	return (host);
140 }
141 
142 #ifndef SUBNETSARELOCAL
143 #define	SUBNETSARELOCAL	1
144 #endif
145 int subnetsarelocal = SUBNETSARELOCAL;
146 /*
147  * Return 1 if an internet address is for a ``local'' host
148  * (one to which we have a connection).  If subnetsarelocal
149  * is true, this includes other subnets of the local net.
150  * Otherwise, it includes only the directly-connected (sub)nets.
151  */
152 in_localaddr(in)
153 	struct in_addr in;
154 {
155 	register u_long i = ntohl(in.s_addr);
156 	register struct in_ifaddr *ia;
157 
158 	if (subnetsarelocal) {
159 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
160 			if ((i & ia->ia_netmask) == ia->ia_net)
161 				return (1);
162 	} else {
163 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
164 			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
165 				return (1);
166 	}
167 	return (0);
168 }
169 
170 /*
171  * Determine whether an IP address is in a reserved set of addresses
172  * that may not be forwarded, or whether datagrams to that destination
173  * may be forwarded.
174  */
175 in_canforward(in)
176 	struct in_addr in;
177 {
178 	register u_long i = ntohl(in.s_addr);
179 	register u_long net;
180 
181 	if (IN_EXPERIMENTAL(i))
182 		return (0);
183 	if (IN_CLASSA(i)) {
184 		net = i & IN_CLASSA_NET;
185 		if (net == 0 || net == IN_LOOPBACKNET)
186 			return (0);
187 	}
188 	return (1);
189 }
190 
191 int	in_interfaces;		/* number of external internet interfaces */
192 extern	struct ifnet loif;
193 
194 /*
195  * Generic internet control operations (ioctl's).
196  * Ifp is 0 if not an interface-specific ioctl.
197  */
198 /* ARGSUSED */
199 in_control(so, cmd, data, ifp)
200 	struct socket *so;
201 	int cmd;
202 	caddr_t data;
203 	register struct ifnet *ifp;
204 {
205 	register struct ifreq *ifr = (struct ifreq *)data;
206 	register struct in_ifaddr *ia = 0;
207 	u_long tmp;
208 	struct ifaddr *ifa;
209 	struct mbuf *m;
210 	int error;
211 
212 	/*
213 	 * Find address for this interface, if it exists.
214 	 */
215 	if (ifp)
216 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
217 			if (ia->ia_ifp == ifp)
218 				break;
219 
220 	switch (cmd) {
221 
222 	case SIOCSIFADDR:
223 	case SIOCSIFNETMASK:
224 	case SIOCSIFDSTADDR:
225 		if (!suser())
226 			return (u.u_error);
227 
228 		if (ifp == 0)
229 			panic("in_control");
230 		if (ia == (struct in_ifaddr *)0) {
231 			m = m_getclr(M_WAIT, MT_IFADDR);
232 			if (m == (struct mbuf *)NULL)
233 				return (ENOBUFS);
234 			if (ia = in_ifaddr) {
235 				for ( ; ia->ia_next; ia = ia->ia_next)
236 					;
237 				ia->ia_next = mtod(m, struct in_ifaddr *);
238 			} else
239 				in_ifaddr = mtod(m, struct in_ifaddr *);
240 			ia = mtod(m, struct in_ifaddr *);
241 			if (ifa = ifp->if_addrlist) {
242 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
243 					;
244 				ifa->ifa_next = (struct ifaddr *) ia;
245 			} else
246 				ifp->if_addrlist = (struct ifaddr *) ia;
247 			ia->ia_ifp = ifp;
248 			IA_SIN(ia)->sin_family = AF_INET;
249 			if (ifp != &loif)
250 				in_interfaces++;
251 		}
252 		break;
253 
254 	case SIOCSIFBRDADDR:
255 		if (!suser())
256 			return (u.u_error);
257 		/* FALLTHROUGH */
258 
259 	default:
260 		if (ia == (struct in_ifaddr *)0)
261 			return (EADDRNOTAVAIL);
262 		break;
263 	}
264 
265 	switch (cmd) {
266 
267 	case SIOCGIFADDR:
268 		ifr->ifr_addr = ia->ia_addr;
269 		break;
270 
271 	case SIOCGIFBRDADDR:
272 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
273 			return (EINVAL);
274 		ifr->ifr_dstaddr = ia->ia_broadaddr;
275 		break;
276 
277 	case SIOCGIFDSTADDR:
278 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
279 			return (EINVAL);
280 		ifr->ifr_dstaddr = ia->ia_dstaddr;
281 		break;
282 
283 	case SIOCGIFNETMASK:
284 #define	satosin(sa)	((struct sockaddr_in *)(sa))
285 		satosin(&ifr->ifr_addr)->sin_family = AF_INET;
286 		satosin(&ifr->ifr_addr)->sin_addr.s_addr = htonl(ia->ia_subnetmask);
287 		break;
288 
289 	case SIOCSIFDSTADDR:
290 	    {
291 		struct sockaddr oldaddr;
292 
293 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
294 			return (EINVAL);
295 		oldaddr = ia->ia_dstaddr;
296 		ia->ia_dstaddr = ifr->ifr_dstaddr;
297 		if (ifp->if_ioctl &&
298 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
299 			ia->ia_dstaddr = oldaddr;
300 			return (error);
301 		}
302 		if (ia->ia_flags & IFA_ROUTE) {
303 			rtinit(&oldaddr, &ia->ia_addr, (int)SIOCDELRT,
304 			    RTF_HOST);
305 			rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
306 			    RTF_HOST|RTF_UP);
307 		}
308 	    }
309 		break;
310 
311 	case SIOCSIFBRDADDR:
312 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
313 			return (EINVAL);
314 		ia->ia_broadaddr = ifr->ifr_broadaddr;
315 		tmp = ntohl(satosin(&ia->ia_broadaddr)->sin_addr.s_addr);
316 		if ((tmp &~ ia->ia_subnetmask) == ~ia->ia_subnetmask)
317 			tmp |= ~ia->ia_netmask;
318 		else if ((tmp &~ ia->ia_subnetmask) == 0)
319 			tmp &= ia->ia_netmask;
320 		ia->ia_netbroadcast.s_addr = htonl(tmp);
321 		break;
322 
323 	case SIOCSIFADDR:
324 		return (in_ifinit(ifp, ia, &ifr->ifr_addr));
325 
326 	case SIOCSIFNETMASK:
327 		ia->ia_subnetmask = ntohl(satosin(&ifr->ifr_addr)->sin_addr.s_addr);
328 		break;
329 
330 	default:
331 		if (ifp == 0 || ifp->if_ioctl == 0)
332 			return (EOPNOTSUPP);
333 		return ((*ifp->if_ioctl)(ifp, cmd, data));
334 	}
335 	return (0);
336 }
337 
338 /*
339  * Initialize an interface's internet address
340  * and routing table entry.
341  */
342 in_ifinit(ifp, ia, sin)
343 	register struct ifnet *ifp;
344 	register struct in_ifaddr *ia;
345 	struct sockaddr_in *sin;
346 {
347 	register u_long i = ntohl(sin->sin_addr.s_addr);
348 	struct sockaddr oldaddr;
349 	struct sockaddr_in netaddr;
350 	int s = splimp(), error;
351 
352 	oldaddr = ia->ia_addr;
353 	ia->ia_addr = *(struct sockaddr *)sin;
354 
355 	/*
356 	 * Give the interface a chance to initialize
357 	 * if this is its first address,
358 	 * and to validate the address if necessary.
359 	 */
360 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
361 		splx(s);
362 		ia->ia_addr = oldaddr;
363 		return (error);
364 	}
365 
366 	/*
367 	 * Delete any previous route for an old address.
368 	 */
369 	bzero((caddr_t)&netaddr, sizeof (netaddr));
370 	netaddr.sin_family = AF_INET;
371 	if (ia->ia_flags & IFA_ROUTE) {
372 		if (ifp->if_flags & IFF_LOOPBACK)
373 			rtinit(&oldaddr, &oldaddr, (int)SIOCDELRT, RTF_HOST);
374 		else if (ifp->if_flags & IFF_POINTOPOINT)
375 			rtinit(&ia->ia_dstaddr, &oldaddr, (int)SIOCDELRT,
376 			    RTF_HOST);
377 		else {
378 			netaddr.sin_addr = in_makeaddr(ia->ia_subnet,
379 			    INADDR_ANY);
380 			rtinit((struct sockaddr *)&netaddr, &oldaddr,
381 			    (int)SIOCDELRT, 0);
382 		}
383 		ia->ia_flags &= ~IFA_ROUTE;
384 	}
385 	if (IN_CLASSA(i))
386 		ia->ia_netmask = IN_CLASSA_NET;
387 	else if (IN_CLASSB(i))
388 		ia->ia_netmask = IN_CLASSB_NET;
389 	else
390 		ia->ia_netmask = IN_CLASSC_NET;
391 	ia->ia_net = i & ia->ia_netmask;
392 	/*
393 	 * The subnet mask includes at least the standard network part,
394 	 * but may already have been set to a larger value.
395 	 */
396 	ia->ia_subnetmask |= ia->ia_netmask;
397 	ia->ia_subnet = i & ia->ia_subnetmask;
398 	if (ifp->if_flags & IFF_BROADCAST) {
399 		ia->ia_broadaddr.sa_family = AF_INET;
400 		((struct sockaddr_in *)(&ia->ia_broadaddr))->sin_addr =
401 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
402 		ia->ia_netbroadcast.s_addr =
403 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
404 	}
405 	/*
406 	 * Add route for the network.
407 	 */
408 	if (ifp->if_flags & IFF_LOOPBACK)
409 		rtinit(&ia->ia_addr, &ia->ia_addr, (int)SIOCADDRT,
410 		    RTF_HOST|RTF_UP);
411 	else if (ifp->if_flags & IFF_POINTOPOINT)
412 		rtinit(&ia->ia_dstaddr, &ia->ia_addr, (int)SIOCADDRT,
413 		    RTF_HOST|RTF_UP);
414 	else {
415 		netaddr.sin_addr = in_makeaddr(ia->ia_subnet, INADDR_ANY);
416 		rtinit((struct sockaddr *)&netaddr, &ia->ia_addr,
417 		    (int)SIOCADDRT, RTF_UP);
418 	}
419 	ia->ia_flags |= IFA_ROUTE;
420 	splx(s);
421 	return (0);
422 }
423 
424 /*
425  * Return address info for specified internet network.
426  */
427 struct in_ifaddr *
428 in_iaonnetof(net)
429 	u_long net;
430 {
431 	register struct in_ifaddr *ia;
432 
433 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
434 		if (ia->ia_subnet == net)
435 			return (ia);
436 	return ((struct in_ifaddr *)0);
437 }
438 
439 /*
440  * Return 1 if the address might be a local broadcast address.
441  */
442 in_broadcast(in)
443 	struct in_addr in;
444 {
445 	register struct in_ifaddr *ia;
446 	u_long t;
447 
448 	/*
449 	 * Look through the list of addresses for a match
450 	 * with a broadcast address.
451 	 */
452 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
453 	    if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
454 		if (satosin(&ia->ia_broadaddr)->sin_addr.s_addr == in.s_addr)
455 		     return (1);
456 		/*
457 		 * Check for old-style (host 0) broadcast.
458 		 */
459 		if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
460 		    return (1);
461 	}
462 	if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
463 		return (1);
464 	return (0);
465 }
466 #endif
467