xref: /csrg-svn/sys/netinet/in.c (revision 44472)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  *
7  *	@(#)in.c	7.15 (Berkeley) 06/28/90
8  */
9 
10 #include "param.h"
11 #include "ioctl.h"
12 #include "mbuf.h"
13 #include "protosw.h"
14 #include "socket.h"
15 #include "socketvar.h"
16 #include "user.h"
17 #include "in_systm.h"
18 #include "../net/if.h"
19 #include "../net/route.h"
20 #include "../net/af.h"
21 #include "in.h"
22 #include "in_var.h"
23 
24 #ifdef INET
25 /*
26  * Formulate an Internet address from network + host.
27  */
28 struct in_addr
29 in_makeaddr(net, host)
30 	u_long net, host;
31 {
32 	register struct in_ifaddr *ia;
33 	register u_long mask;
34 	u_long addr;
35 
36 	if (IN_CLASSA(net))
37 		mask = IN_CLASSA_HOST;
38 	else if (IN_CLASSB(net))
39 		mask = IN_CLASSB_HOST;
40 	else
41 		mask = IN_CLASSC_HOST;
42 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
43 		if ((ia->ia_netmask & net) == ia->ia_net) {
44 			mask = ~ia->ia_subnetmask;
45 			break;
46 		}
47 	addr = htonl(net | (host & mask));
48 	return (*(struct in_addr *)&addr);
49 }
50 
51 /*
52  * Return the network number from an internet address.
53  */
54 u_long
55 in_netof(in)
56 	struct in_addr in;
57 {
58 	register u_long i = ntohl(in.s_addr);
59 	register u_long net;
60 	register struct in_ifaddr *ia;
61 
62 	if (IN_CLASSA(i))
63 		net = i & IN_CLASSA_NET;
64 	else if (IN_CLASSB(i))
65 		net = i & IN_CLASSB_NET;
66 	else if (IN_CLASSC(i))
67 		net = i & IN_CLASSC_NET;
68 	else
69 		return (0);
70 
71 	/*
72 	 * Check whether network is a subnet;
73 	 * if so, return subnet number.
74 	 */
75 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
76 		if (net == ia->ia_net)
77 			return (i & ia->ia_subnetmask);
78 	return (net);
79 }
80 
81 /*
82  * Compute and save network mask as sockaddr from an internet address.
83  */
84 in_sockmaskof(in, sockmask)
85 	struct in_addr in;
86 	register struct sockaddr_in *sockmask;
87 {
88 	register u_long net;
89 	register u_long mask;
90     {
91 	register u_long i = ntohl(in.s_addr);
92 
93 	if (i == 0)
94 		net = 0, mask = 0;
95 	else if (IN_CLASSA(i))
96 		net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
97 	else if (IN_CLASSB(i))
98 		net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
99 	else if (IN_CLASSC(i))
100 		net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
101 	else
102 		net = i, mask = -1;
103     }
104     {
105 	register struct in_ifaddr *ia;
106 	/*
107 	 * Check whether network is a subnet;
108 	 * if so, return subnet number.
109 	 */
110 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
111 		if (net == ia->ia_net)
112 			mask =  ia->ia_subnetmask;
113     }
114     {
115 	register char *cpbase = (char *)&(sockmask->sin_addr);
116 	register char *cp = (char *)(1 + &(sockmask->sin_addr));
117 
118 	sockmask->sin_addr.s_addr = htonl(mask);
119 	sockmask->sin_len = 0;
120 	while (--cp >= cpbase)
121 		if (*cp) {
122 			sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
123 			break;
124 		}
125     }
126 }
127 
128 /*
129  * Return the host portion of an internet address.
130  */
131 u_long
132 in_lnaof(in)
133 	struct in_addr in;
134 {
135 	register u_long i = ntohl(in.s_addr);
136 	register u_long net, host;
137 	register struct in_ifaddr *ia;
138 
139 	if (IN_CLASSA(i)) {
140 		net = i & IN_CLASSA_NET;
141 		host = i & IN_CLASSA_HOST;
142 	} else if (IN_CLASSB(i)) {
143 		net = i & IN_CLASSB_NET;
144 		host = i & IN_CLASSB_HOST;
145 	} else if (IN_CLASSC(i)) {
146 		net = i & IN_CLASSC_NET;
147 		host = i & IN_CLASSC_HOST;
148 	} else
149 		return (i);
150 
151 	/*
152 	 * Check whether network is a subnet;
153 	 * if so, use the modified interpretation of `host'.
154 	 */
155 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
156 		if (net == ia->ia_net)
157 			return (host &~ ia->ia_subnetmask);
158 	return (host);
159 }
160 
161 #ifndef SUBNETSARELOCAL
162 #define	SUBNETSARELOCAL	1
163 #endif
164 int subnetsarelocal = SUBNETSARELOCAL;
165 /*
166  * Return 1 if an internet address is for a ``local'' host
167  * (one to which we have a connection).  If subnetsarelocal
168  * is true, this includes other subnets of the local net.
169  * Otherwise, it includes only the directly-connected (sub)nets.
170  */
171 in_localaddr(in)
172 	struct in_addr in;
173 {
174 	register u_long i = ntohl(in.s_addr);
175 	register struct in_ifaddr *ia;
176 
177 	if (subnetsarelocal) {
178 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
179 			if ((i & ia->ia_netmask) == ia->ia_net)
180 				return (1);
181 	} else {
182 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
183 			if ((i & ia->ia_subnetmask) == ia->ia_subnet)
184 				return (1);
185 	}
186 	return (0);
187 }
188 
189 /*
190  * Determine whether an IP address is in a reserved set of addresses
191  * that may not be forwarded, or whether datagrams to that destination
192  * may be forwarded.
193  */
194 in_canforward(in)
195 	struct in_addr in;
196 {
197 	register u_long i = ntohl(in.s_addr);
198 	register u_long net;
199 
200 	if (IN_EXPERIMENTAL(i))
201 		return (0);
202 	if (IN_CLASSA(i)) {
203 		net = i & IN_CLASSA_NET;
204 		if (net == 0 || net == IN_LOOPBACKNET)
205 			return (0);
206 	}
207 	return (1);
208 }
209 
210 int	in_interfaces;		/* number of external internet interfaces */
211 extern	struct ifnet loif;
212 
213 /*
214  * Generic internet control operations (ioctl's).
215  * Ifp is 0 if not an interface-specific ioctl.
216  */
217 /* ARGSUSED */
218 in_control(so, cmd, data, ifp)
219 	struct socket *so;
220 	int cmd;
221 	caddr_t data;
222 	register struct ifnet *ifp;
223 {
224 	register struct ifreq *ifr = (struct ifreq *)data;
225 	register struct in_ifaddr *ia = 0;
226 	register struct ifaddr *ifa;
227 	struct in_ifaddr *oia;
228 	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
229 	struct mbuf *m;
230 	struct sockaddr_in oldaddr;
231 	int error, hostIsNew, maskIsNew;
232 	u_long i;
233 
234 	/*
235 	 * Find address for this interface, if it exists.
236 	 */
237 	if (ifp)
238 		for (ia = in_ifaddr; ia; ia = ia->ia_next)
239 			if (ia->ia_ifp == ifp)
240 				break;
241 
242 	switch (cmd) {
243 
244 	case SIOCAIFADDR:
245 	case SIOCDIFADDR:
246 		if (ifra->ifra_addr.sin_family == AF_INET)
247 		    for (oia = ia; ia; ia = ia->ia_next) {
248 			if (ia->ia_ifp == ifp  &&
249 			    ia->ia_addr.sin_addr.s_addr ==
250 				ifra->ifra_addr.sin_addr.s_addr)
251 			    break;
252 		}
253 		if (cmd == SIOCDIFADDR && ia == 0)
254 			return (EADDRNOTAVAIL);
255 		/* FALLTHROUGH */
256 	case SIOCSIFADDR:
257 	case SIOCSIFNETMASK:
258 	case SIOCSIFDSTADDR:
259 		if (error = suser(u.u_cred, &u.u_acflag))
260 			return (error);
261 
262 		if (ifp == 0)
263 			panic("in_control");
264 		if (ia == (struct in_ifaddr *)0) {
265 			m = m_getclr(M_WAIT, MT_IFADDR);
266 			if (m == (struct mbuf *)NULL)
267 				return (ENOBUFS);
268 			if (ia = in_ifaddr) {
269 				for ( ; ia->ia_next; ia = ia->ia_next)
270 					;
271 				ia->ia_next = mtod(m, struct in_ifaddr *);
272 			} else
273 				in_ifaddr = mtod(m, struct in_ifaddr *);
274 			ia = mtod(m, struct in_ifaddr *);
275 			if (ifa = ifp->if_addrlist) {
276 				for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
277 					;
278 				ifa->ifa_next = (struct ifaddr *) ia;
279 			} else
280 				ifp->if_addrlist = (struct ifaddr *) ia;
281 			ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
282 			ia->ia_ifa.ifa_dstaddr
283 					= (struct sockaddr *)&ia->ia_dstaddr;
284 			ia->ia_ifa.ifa_netmask
285 					= (struct sockaddr *)&ia->ia_sockmask;
286 			ia->ia_sockmask.sin_len = 8;
287 			if (ifp->if_flags & IFF_BROADCAST) {
288 				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
289 				ia->ia_broadaddr.sin_family = AF_INET;
290 			}
291 			ia->ia_ifp = ifp;
292 			if (ifp != &loif)
293 				in_interfaces++;
294 		}
295 		break;
296 
297 	case SIOCSIFBRDADDR:
298 		if (error = suser(u.u_cred, &u.u_acflag))
299 			return (error);
300 		/* FALLTHROUGH */
301 
302 	case SIOCGIFADDR:
303 	case SIOCGIFNETMASK:
304 	case SIOCGIFDSTADDR:
305 	case SIOCGIFBRDADDR:
306 		if (ia == (struct in_ifaddr *)0)
307 			return (EADDRNOTAVAIL);
308 		break;
309 
310 	default:
311 		return (EOPNOTSUPP);
312 		break;
313 	}
314 	switch (cmd) {
315 
316 	case SIOCGIFADDR:
317 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
318 		break;
319 
320 	case SIOCGIFBRDADDR:
321 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
322 			return (EINVAL);
323 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
324 		break;
325 
326 	case SIOCGIFDSTADDR:
327 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
328 			return (EINVAL);
329 		*((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
330 		break;
331 
332 	case SIOCGIFNETMASK:
333 		*((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
334 		break;
335 
336 	case SIOCSIFDSTADDR:
337 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
338 			return (EINVAL);
339 		oldaddr = ia->ia_dstaddr;
340 		ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
341 		if (ifp->if_ioctl &&
342 		    (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
343 			ia->ia_dstaddr = oldaddr;
344 			return (error);
345 		}
346 		if (ia->ia_flags & IFA_ROUTE) {
347 			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
348 			rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
349 			ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_addr;
350 			rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
351 		}
352 		break;
353 
354 	case SIOCSIFBRDADDR:
355 		if ((ifp->if_flags & IFF_BROADCAST) == 0)
356 			return (EINVAL);
357 		ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
358 		break;
359 
360 	case SIOCSIFADDR:
361 		return (in_ifinit(ifp, ia,
362 		    (struct sockaddr_in *) &ifr->ifr_addr, 1));
363 
364 	case SIOCSIFNETMASK:
365 		i = ifra->ifra_addr.sin_addr.s_addr;
366 		ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
367 		break;
368 
369 	case SIOCAIFADDR:
370 		maskIsNew = 0;
371 		hostIsNew = 1;
372 		error = 0;
373 		if (ia->ia_addr.sin_family == AF_INET) {
374 			if (ifra->ifra_addr.sin_len == 0) {
375 				ifra->ifra_addr = ia->ia_addr;
376 				hostIsNew = 0;
377 			} else if (ifra->ifra_addr.sin_addr.s_addr ==
378 					       ia->ia_addr.sin_addr.s_addr)
379 				hostIsNew = 0;
380 		}
381 		if (ifra->ifra_mask.sin_len) {
382 			in_ifscrub(ifp, ia);
383 			ia->ia_sockmask = ifra->ifra_mask;
384 			ia->ia_subnetmask =
385 			     ntohl(ia->ia_sockmask.sin_addr.s_addr);
386 			maskIsNew = 1;
387 		}
388 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
389 		    (ifra->ifra_dstaddr.sin_family == AF_INET)) {
390 			in_ifscrub(ifp, ia);
391 			ia->ia_dstaddr = ifra->ifra_dstaddr;
392 			maskIsNew  = 1; /* We lie; but the effect's the same */
393 		}
394 		if (ifra->ifra_addr.sin_family == AF_INET &&
395 		    (hostIsNew || maskIsNew))
396 			error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
397 		if ((ifp->if_flags & IFF_BROADCAST) &&
398 		    (ifra->ifra_broadaddr.sin_family == AF_INET))
399 			ia->ia_broadaddr = ifra->ifra_broadaddr;
400 		return (error);
401 
402 	case SIOCDIFADDR:
403 		in_ifscrub(ifp, ia);
404 		if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
405 			ifp->if_addrlist = ifa->ifa_next;
406 		else {
407 			while (ifa->ifa_next &&
408 			       (ifa->ifa_next != (struct ifaddr *)ia))
409 				    ifa = ifa->ifa_next;
410 			if (ifa->ifa_next)
411 				ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
412 			else
413 				printf("Couldn't unlink inifaddr from ifp\n");
414 		}
415 		oia = ia;
416 		if (oia == (ia = in_ifaddr))
417 			in_ifaddr = ia->ia_next;
418 		else {
419 			while (ia->ia_next && (ia->ia_next != oia))
420 				ia = ia->ia_next;
421 			if (ia->ia_next)
422 				ia->ia_next = oia->ia_next;
423 			else
424 				printf("Didn't unlink inifadr from list\n");
425 		}
426 		(void) m_free(dtom(oia));
427 		break;
428 
429 	default:
430 		if (ifp == 0 || ifp->if_ioctl == 0)
431 			return (EOPNOTSUPP);
432 		return ((*ifp->if_ioctl)(ifp, cmd, data));
433 	}
434 	return (0);
435 }
436 
437 /*
438  * Delete any existing route for an interface.
439  */
440 in_ifscrub(ifp, ia)
441 	register struct ifnet *ifp;
442 	register struct in_ifaddr *ia;
443 {
444 
445 	if ((ia->ia_flags & IFA_ROUTE) == 0)
446 		return;
447 	if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
448 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
449 	else
450 		rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
451 	ia->ia_flags &= ~IFA_ROUTE;
452 }
453 
454 /*
455  * Initialize an interface's internet address
456  * and routing table entry.
457  */
458 in_ifinit(ifp, ia, sin, scrub)
459 	register struct ifnet *ifp;
460 	register struct in_ifaddr *ia;
461 	struct sockaddr_in *sin;
462 {
463 	register u_long i = ntohl(sin->sin_addr.s_addr);
464 	struct sockaddr_in oldaddr;
465 	int s = splimp(), error;
466 
467 	oldaddr = ia->ia_addr;
468 	ia->ia_addr = *sin;
469 	/*
470 	 * Give the interface a chance to initialize
471 	 * if this is its first address,
472 	 * and to validate the address if necessary.
473 	 */
474 	if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
475 		splx(s);
476 		ia->ia_addr = oldaddr;
477 		return (error);
478 	}
479 	if (scrub) {
480 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
481 		in_ifscrub(ifp, ia);
482 		ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
483 	}
484 	if (IN_CLASSA(i))
485 		ia->ia_netmask = IN_CLASSA_NET;
486 	else if (IN_CLASSB(i))
487 		ia->ia_netmask = IN_CLASSB_NET;
488 	else
489 		ia->ia_netmask = IN_CLASSC_NET;
490 	ia->ia_net = i & ia->ia_netmask;
491 	/*
492 	 * The subnet mask includes at least the standard network part,
493 	 * but may already have been set to a larger value.
494 	 */
495 	ia->ia_subnetmask |= ia->ia_netmask;
496 	ia->ia_subnet = i & ia->ia_subnetmask;
497 	ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
498 	{
499 		register char *cp = (char *) (1 + &(ia->ia_sockmask.sin_addr));
500 		register char *cpbase = (char *) &(ia->ia_sockmask.sin_addr);
501 		while (--cp >= cpbase)
502 			if (*cp) {
503 				ia->ia_sockmask.sin_len =
504 					1 + cp - (char *) &(ia->ia_sockmask);
505 				break;
506 			}
507 	}
508 	if (ifp->if_flags & IFF_BROADCAST) {
509 		ia->ia_broadaddr.sin_addr =
510 			in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
511 		ia->ia_netbroadcast.s_addr =
512 		    htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
513 	}
514 	/*
515 	 * Add route for the network.
516 	 */
517 	if (ifp->if_flags & IFF_LOOPBACK) {
518 		ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
519 		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
520 	} else if (ifp->if_flags & IFF_POINTOPOINT &&
521 		 ia->ia_dstaddr.sin_family == AF_INET)
522 		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
523 	else {
524 		rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_UP);
525 	}
526 	ia->ia_flags |= IFA_ROUTE;
527 	splx(s);
528 	return (0);
529 }
530 
531 /*
532  * Return address info for specified internet network.
533  */
534 struct in_ifaddr *
535 in_iaonnetof(net)
536 	u_long net;
537 {
538 	register struct in_ifaddr *ia;
539 
540 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
541 		if (ia->ia_subnet == net)
542 			return (ia);
543 	return ((struct in_ifaddr *)0);
544 }
545 
546 /*
547  * Return 1 if the address might be a local broadcast address.
548  */
549 in_broadcast(in)
550 	struct in_addr in;
551 {
552 	register struct in_ifaddr *ia;
553 	u_long t;
554 
555 	/*
556 	 * Look through the list of addresses for a match
557 	 * with a broadcast address.
558 	 */
559 	for (ia = in_ifaddr; ia; ia = ia->ia_next)
560 	    if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
561 		if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
562 		     return (1);
563 		/*
564 		 * Check for old-style (host 0) broadcast.
565 		 */
566 		if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
567 		    return (1);
568 	}
569 	if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
570 		return (1);
571 	return (0);
572 }
573 #endif
574