Annotation of sys/netinet/in.c, Revision 1.1.1.1
1.1 nbrk 1: /* $OpenBSD: in.c,v 1.49 2007/07/20 19:00:35 claudio Exp $ */
2: /* $NetBSD: in.c,v 1.26 1996/02/13 23:41:39 christos Exp $ */
3:
4: /*
5: * Copyright (C) 2001 WIDE Project. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. Neither the name of the project nor the names of its contributors
16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
19: * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22: * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29: * SUCH DAMAGE.
30: */
31:
32: /*
33: * Copyright (c) 1982, 1986, 1991, 1993
34: * The Regents of the University of California. All rights reserved.
35: *
36: * Redistribution and use in source and binary forms, with or without
37: * modification, are permitted provided that the following conditions
38: * are met:
39: * 1. Redistributions of source code must retain the above copyright
40: * notice, this list of conditions and the following disclaimer.
41: * 2. Redistributions in binary form must reproduce the above copyright
42: * notice, this list of conditions and the following disclaimer in the
43: * documentation and/or other materials provided with the distribution.
44: * 3. Neither the name of the University nor the names of its contributors
45: * may be used to endorse or promote products derived from this software
46: * without specific prior written permission.
47: *
48: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58: * SUCH DAMAGE.
59: *
60: * @(#)in.c 8.2 (Berkeley) 11/15/93
61: */
62:
63: #include <sys/param.h>
64: #include <sys/systm.h>
65: #include <sys/ioctl.h>
66: #include <sys/malloc.h>
67: #include <sys/socket.h>
68: #include <sys/socketvar.h>
69:
70: #include <net/if.h>
71: #include <net/route.h>
72:
73: #include "carp.h"
74: #if NCARP > 0
75: #include <net/if_types.h>
76: #endif
77:
78: #include <netinet/in.h>
79: #include <netinet/in_var.h>
80: #include <netinet/igmp_var.h>
81:
82: #ifdef MROUTING
83: #include <netinet/ip_mroute.h>
84: #endif
85:
86: #include "ether.h"
87:
88: #ifdef INET
89:
90: int in_mask2len(struct in_addr *);
91: void in_len2mask(struct in_addr *, int);
92: int in_lifaddr_ioctl(struct socket *, u_long, caddr_t,
93: struct ifnet *);
94:
95: int in_addprefix(struct in_ifaddr *, int);
96: int in_scrubprefix(struct in_ifaddr *);
97:
98: #ifndef SUBNETSARELOCAL
99: #define SUBNETSARELOCAL 0
100: #endif
101:
102: #ifndef HOSTZEROBROADCAST
103: #define HOSTZEROBROADCAST 1
104: #endif
105:
106: int subnetsarelocal = SUBNETSARELOCAL;
107: int hostzeroisbroadcast = HOSTZEROBROADCAST;
108:
109: /*
110: * Return 1 if an internet address is for a ``local'' host
111: * (one to which we have a connection). If subnetsarelocal
112: * is true, this includes other subnets of the local net.
113: * Otherwise, it includes only the directly-connected (sub)nets.
114: */
115: int
116: in_localaddr(in)
117: struct in_addr in;
118: {
119: struct in_ifaddr *ia;
120:
121: if (subnetsarelocal) {
122: TAILQ_FOREACH(ia, &in_ifaddr, ia_list)
123: if ((in.s_addr & ia->ia_netmask) == ia->ia_net)
124: return (1);
125: } else {
126: TAILQ_FOREACH(ia, &in_ifaddr, ia_list)
127: if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet)
128: return (1);
129: }
130: return (0);
131: }
132:
133: /*
134: * Determine whether an IP address is in a reserved set of addresses
135: * that may not be forwarded, or whether datagrams to that destination
136: * may be forwarded.
137: */
138: int
139: in_canforward(in)
140: struct in_addr in;
141: {
142: u_int32_t net;
143:
144: if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr))
145: return (0);
146: if (IN_CLASSA(in.s_addr)) {
147: net = in.s_addr & IN_CLASSA_NET;
148: if (net == 0 || net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
149: return (0);
150: }
151: return (1);
152: }
153:
154: /*
155: * Trim a mask in a sockaddr
156: */
157: void
158: in_socktrim(ap)
159: struct sockaddr_in *ap;
160: {
161: char *cplim = (char *) &ap->sin_addr;
162: char *cp = (char *) (&ap->sin_addr + 1);
163:
164: ap->sin_len = 0;
165: while (--cp >= cplim)
166: if (*cp) {
167: (ap)->sin_len = cp - (char *) (ap) + 1;
168: break;
169: }
170: }
171:
172: int
173: in_mask2len(mask)
174: struct in_addr *mask;
175: {
176: int x, y;
177: u_char *p;
178:
179: p = (u_char *)mask;
180: for (x = 0; x < sizeof(*mask); x++) {
181: if (p[x] != 0xff)
182: break;
183: }
184: y = 0;
185: if (x < sizeof(*mask)) {
186: for (y = 0; y < 8; y++) {
187: if ((p[x] & (0x80 >> y)) == 0)
188: break;
189: }
190: }
191: return x * 8 + y;
192: }
193:
194: void
195: in_len2mask(mask, len)
196: struct in_addr *mask;
197: int len;
198: {
199: int i;
200: u_char *p;
201:
202: p = (u_char *)mask;
203: bzero(mask, sizeof(*mask));
204: for (i = 0; i < len / 8; i++)
205: p[i] = 0xff;
206: if (len % 8)
207: p[i] = (0xff00 >> (len % 8)) & 0xff;
208: }
209:
210: int in_interfaces; /* number of external internet interfaces */
211:
212: /*
213: * Generic internet control operations (ioctl's).
214: * Ifp is 0 if not an interface-specific ioctl.
215: */
216: /* ARGSUSED */
217: int
218: in_control(so, cmd, data, ifp)
219: struct socket *so;
220: u_long cmd;
221: caddr_t data;
222: struct ifnet *ifp;
223: {
224: struct ifreq *ifr = (struct ifreq *)data;
225: struct in_ifaddr *ia = 0;
226: struct in_aliasreq *ifra = (struct in_aliasreq *)data;
227: struct sockaddr_in oldaddr;
228: int error, hostIsNew, maskIsNew;
229: int newifaddr;
230: int s;
231:
232: switch (cmd) {
233: case SIOCALIFADDR:
234: case SIOCDLIFADDR:
235: if ((so->so_state & SS_PRIV) == 0)
236: return (EPERM);
237: /* FALLTHROUGH */
238: case SIOCGLIFADDR:
239: if (!ifp)
240: return EINVAL;
241: return in_lifaddr_ioctl(so, cmd, data, ifp);
242: }
243:
244: /*
245: * Find address for this interface, if it exists.
246: */
247: if (ifp)
248: TAILQ_FOREACH(ia, &in_ifaddr, ia_list)
249: if (ia->ia_ifp == ifp)
250: break;
251:
252: switch (cmd) {
253:
254: case SIOCAIFADDR:
255: case SIOCDIFADDR:
256: if (ifra->ifra_addr.sin_family == AF_INET)
257: for (; ia != TAILQ_END(&in_ifaddr);
258: ia = TAILQ_NEXT(ia, ia_list)) {
259: if (ia->ia_ifp == ifp &&
260: ia->ia_addr.sin_addr.s_addr ==
261: ifra->ifra_addr.sin_addr.s_addr)
262: break;
263: }
264: if (cmd == SIOCDIFADDR && ia == 0)
265: return (EADDRNOTAVAIL);
266: /* FALLTHROUGH */
267: case SIOCSIFADDR:
268: case SIOCSIFNETMASK:
269: case SIOCSIFDSTADDR:
270: if ((so->so_state & SS_PRIV) == 0)
271: return (EPERM);
272:
273: if (ifp == 0)
274: panic("in_control");
275: if (ia == (struct in_ifaddr *)0) {
276: ia = (struct in_ifaddr *)
277: malloc(sizeof *ia, M_IFADDR, M_WAITOK);
278: bzero((caddr_t)ia, sizeof *ia);
279: s = splsoftnet();
280: TAILQ_INSERT_TAIL(&in_ifaddr, ia, ia_list);
281: TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia,
282: ifa_list);
283: ia->ia_addr.sin_family = AF_INET;
284: ia->ia_addr.sin_len = sizeof(ia->ia_addr);
285: ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
286: ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
287: ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
288: ia->ia_sockmask.sin_len = 8;
289: if (ifp->if_flags & IFF_BROADCAST) {
290: ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
291: ia->ia_broadaddr.sin_family = AF_INET;
292: }
293: ia->ia_ifp = ifp;
294: LIST_INIT(&ia->ia_multiaddrs);
295: if ((ifp->if_flags & IFF_LOOPBACK) == 0)
296: in_interfaces++;
297: splx(s);
298:
299: newifaddr = 1;
300: } else
301: newifaddr = 0;
302: break;
303:
304: case SIOCSIFBRDADDR:
305: if ((so->so_state & SS_PRIV) == 0)
306: return (EPERM);
307: /* FALLTHROUGH */
308:
309: case SIOCGIFADDR:
310: case SIOCGIFNETMASK:
311: case SIOCGIFDSTADDR:
312: case SIOCGIFBRDADDR:
313: if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
314: struct in_ifaddr *ia2;
315:
316: for (ia2 = ia; ia2 != TAILQ_END(&in_ifaddr);
317: ia2 = TAILQ_NEXT(ia2, ia_list)) {
318: if (ia2->ia_ifp == ifp &&
319: ia2->ia_addr.sin_addr.s_addr ==
320: satosin(&ifr->ifr_addr)->sin_addr.s_addr)
321: break;
322: }
323: if (ia2 && ia2->ia_ifp == ifp)
324: ia = ia2;
325: }
326: if (ia == (struct in_ifaddr *)0)
327: return (EADDRNOTAVAIL);
328: break;
329: }
330: switch (cmd) {
331:
332: case SIOCGIFADDR:
333: *satosin(&ifr->ifr_addr) = ia->ia_addr;
334: break;
335:
336: case SIOCGIFBRDADDR:
337: if ((ifp->if_flags & IFF_BROADCAST) == 0)
338: return (EINVAL);
339: *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
340: break;
341:
342: case SIOCGIFDSTADDR:
343: if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
344: return (EINVAL);
345: *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
346: break;
347:
348: case SIOCGIFNETMASK:
349: *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
350: break;
351:
352: case SIOCSIFDSTADDR:
353: if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
354: return (EINVAL);
355: s = splsoftnet();
356: oldaddr = ia->ia_dstaddr;
357: ia->ia_dstaddr = *satosin(&ifr->ifr_dstaddr);
358: if (ifp->if_ioctl && (error = (*ifp->if_ioctl)
359: (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) {
360: ia->ia_dstaddr = oldaddr;
361: splx(s);
362: return (error);
363: }
364: if (ia->ia_flags & IFA_ROUTE) {
365: ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr);
366: rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
367: ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
368: rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
369: }
370: splx(s);
371: break;
372:
373: case SIOCSIFBRDADDR:
374: if ((ifp->if_flags & IFF_BROADCAST) == 0)
375: return (EINVAL);
376: ia->ia_broadaddr = *satosin(&ifr->ifr_broadaddr);
377: break;
378:
379: case SIOCSIFADDR:
380: s = splsoftnet();
381: error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), 1);
382: if (!error)
383: dohooks(ifp->if_addrhooks, 0);
384: else if (newifaddr) {
385: splx(s);
386: goto cleanup;
387: }
388: splx(s);
389: return error;
390:
391: case SIOCSIFNETMASK:
392: ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr =
393: ifra->ifra_addr.sin_addr.s_addr;
394: break;
395:
396: case SIOCAIFADDR:
397: maskIsNew = 0;
398: hostIsNew = 1;
399: error = 0;
400: s = splsoftnet();
401: if (ia->ia_addr.sin_family == AF_INET) {
402: if (ifra->ifra_addr.sin_len == 0) {
403: ifra->ifra_addr = ia->ia_addr;
404: hostIsNew = 0;
405: } else if (ifra->ifra_addr.sin_addr.s_addr ==
406: ia->ia_addr.sin_addr.s_addr)
407: hostIsNew = 0;
408: }
409: if (ifra->ifra_mask.sin_len) {
410: in_ifscrub(ifp, ia);
411: ia->ia_sockmask = ifra->ifra_mask;
412: ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr;
413: maskIsNew = 1;
414: }
415: if ((ifp->if_flags & IFF_POINTOPOINT) &&
416: (ifra->ifra_dstaddr.sin_family == AF_INET)) {
417: in_ifscrub(ifp, ia);
418: ia->ia_dstaddr = ifra->ifra_dstaddr;
419: maskIsNew = 1; /* We lie; but the effect's the same */
420: }
421: if (ifra->ifra_addr.sin_family == AF_INET &&
422: (hostIsNew || maskIsNew)) {
423: error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
424: }
425: if ((ifp->if_flags & IFF_BROADCAST) &&
426: (ifra->ifra_broadaddr.sin_family == AF_INET))
427: ia->ia_broadaddr = ifra->ifra_broadaddr;
428: if (!error)
429: dohooks(ifp->if_addrhooks, 0);
430: else if (newifaddr) {
431: splx(s);
432: goto cleanup;
433: }
434: splx(s);
435: return (error);
436:
437: case SIOCDIFADDR: {
438:
439: error = 0;
440: cleanup:
441: /*
442: * Even if the individual steps were safe, shouldn't
443: * these kinds of changes happen atomically? What
444: * should happen to a packet that was routed after
445: * the scrub but before the other steps?
446: */
447: s = splsoftnet();
448: in_ifscrub(ifp, ia);
449: TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
450: TAILQ_REMOVE(&in_ifaddr, ia, ia_list);
451: if (ia->ia_allhosts != NULL) {
452: in_delmulti(ia->ia_allhosts);
453: ia->ia_allhosts = NULL;
454: }
455: IFAFREE((&ia->ia_ifa));
456: dohooks(ifp->if_addrhooks, 0);
457: splx(s);
458: return (error);
459: }
460:
461: #ifdef MROUTING
462: case SIOCGETVIFCNT:
463: case SIOCGETSGCNT:
464: return (mrt_ioctl(so, cmd, data));
465: #endif /* MROUTING */
466:
467: default:
468: if (ifp == 0 || ifp->if_ioctl == 0)
469: return (EOPNOTSUPP);
470: return ((*ifp->if_ioctl)(ifp, cmd, data));
471: }
472: return (0);
473: }
474:
475: /*
476: * SIOC[GAD]LIFADDR.
477: * SIOCGLIFADDR: get first address. (???)
478: * SIOCGLIFADDR with IFLR_PREFIX:
479: * get first address that matches the specified prefix.
480: * SIOCALIFADDR: add the specified address.
481: * SIOCALIFADDR with IFLR_PREFIX:
482: * EINVAL since we can't deduce hostid part of the address.
483: * SIOCDLIFADDR: delete the specified address.
484: * SIOCDLIFADDR with IFLR_PREFIX:
485: * delete the first address that matches the specified prefix.
486: * return values:
487: * EINVAL on invalid parameters
488: * EADDRNOTAVAIL on prefix match failed/specified address not found
489: * other values may be returned from in_ioctl()
490: */
491: int
492: in_lifaddr_ioctl(so, cmd, data, ifp)
493: struct socket *so;
494: u_long cmd;
495: caddr_t data;
496: struct ifnet *ifp;
497: {
498: struct if_laddrreq *iflr = (struct if_laddrreq *)data;
499: struct ifaddr *ifa;
500: struct sockaddr *sa;
501:
502: /* sanity checks */
503: if (!data || !ifp) {
504: panic("invalid argument to in_lifaddr_ioctl");
505: /*NOTRECHED*/
506: }
507:
508: switch (cmd) {
509: case SIOCGLIFADDR:
510: /* address must be specified on GET with IFLR_PREFIX */
511: if ((iflr->flags & IFLR_PREFIX) == 0)
512: break;
513: /*FALLTHROUGH*/
514: case SIOCALIFADDR:
515: case SIOCDLIFADDR:
516: /* address must be specified on ADD and DELETE */
517: sa = (struct sockaddr *)&iflr->addr;
518: if (sa->sa_family != AF_INET)
519: return EINVAL;
520: if (sa->sa_len != sizeof(struct sockaddr_in))
521: return EINVAL;
522: /* XXX need improvement */
523: sa = (struct sockaddr *)&iflr->dstaddr;
524: if (sa->sa_family
525: && sa->sa_family != AF_INET)
526: return EINVAL;
527: if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in))
528: return EINVAL;
529: break;
530: default: /*shouldn't happen*/
531: #if 0
532: panic("invalid cmd to in_lifaddr_ioctl");
533: /*NOTREACHED*/
534: #else
535: return EOPNOTSUPP;
536: #endif
537: }
538: if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
539: return EINVAL;
540:
541: switch (cmd) {
542: case SIOCALIFADDR:
543: {
544: struct in_aliasreq ifra;
545:
546: if (iflr->flags & IFLR_PREFIX)
547: return EINVAL;
548:
549: /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR). */
550: bzero(&ifra, sizeof(ifra));
551: bcopy(iflr->iflr_name, ifra.ifra_name,
552: sizeof(ifra.ifra_name));
553:
554: bcopy(&iflr->addr, &ifra.ifra_addr,
555: ((struct sockaddr *)&iflr->addr)->sa_len);
556:
557: if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /*XXX*/
558: bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
559: ((struct sockaddr *)&iflr->dstaddr)->sa_len);
560: }
561:
562: ifra.ifra_mask.sin_family = AF_INET;
563: ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
564: in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
565:
566: return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp);
567: }
568: case SIOCGLIFADDR:
569: case SIOCDLIFADDR:
570: {
571: struct in_ifaddr *ia;
572: struct in_addr mask, candidate, match;
573: struct sockaddr_in *sin;
574: int cmp;
575:
576: bzero(&mask, sizeof(mask));
577: if (iflr->flags & IFLR_PREFIX) {
578: /* lookup a prefix rather than address. */
579: in_len2mask(&mask, iflr->prefixlen);
580:
581: sin = (struct sockaddr_in *)&iflr->addr;
582: match.s_addr = sin->sin_addr.s_addr;
583: match.s_addr &= mask.s_addr;
584:
585: /* if you set extra bits, that's wrong */
586: if (match.s_addr != sin->sin_addr.s_addr)
587: return EINVAL;
588:
589: cmp = 1;
590: } else {
591: if (cmd == SIOCGLIFADDR) {
592: /* on getting an address, take the 1st match */
593: cmp = 0; /*XXX*/
594: } else {
595: /* on deleting an address, do exact match */
596: in_len2mask(&mask, 32);
597: sin = (struct sockaddr_in *)&iflr->addr;
598: match.s_addr = sin->sin_addr.s_addr;
599:
600: cmp = 1;
601: }
602: }
603:
604: TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
605: if (ifa->ifa_addr->sa_family != AF_INET)
606: continue;
607: if (!cmp)
608: break;
609: candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr;
610: candidate.s_addr &= mask.s_addr;
611: if (candidate.s_addr == match.s_addr)
612: break;
613: }
614: if (!ifa)
615: return EADDRNOTAVAIL;
616: ia = (struct in_ifaddr *)ifa;
617:
618: if (cmd == SIOCGLIFADDR) {
619: /* fill in the if_laddrreq structure */
620: bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
621:
622: if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
623: bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
624: ia->ia_dstaddr.sin_len);
625: } else
626: bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
627:
628: iflr->prefixlen =
629: in_mask2len(&ia->ia_sockmask.sin_addr);
630:
631: iflr->flags = 0; /*XXX*/
632:
633: return 0;
634: } else {
635: struct in_aliasreq ifra;
636:
637: /* fill in_aliasreq and do ioctl(SIOCDIFADDR) */
638: bzero(&ifra, sizeof(ifra));
639: bcopy(iflr->iflr_name, ifra.ifra_name,
640: sizeof(ifra.ifra_name));
641:
642: bcopy(&ia->ia_addr, &ifra.ifra_addr,
643: ia->ia_addr.sin_len);
644: if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
645: bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
646: ia->ia_dstaddr.sin_len);
647: }
648: bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
649: ia->ia_sockmask.sin_len);
650:
651: return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, ifp);
652: }
653: }
654: }
655:
656: return EOPNOTSUPP; /*just for safety*/
657: }
658:
659: /*
660: * Delete any existing route for an interface.
661: */
662: void
663: in_ifscrub(ifp, ia)
664: struct ifnet *ifp;
665: struct in_ifaddr *ia;
666: {
667: in_scrubprefix(ia);
668: }
669:
670: /*
671: * Initialize an interface's internet address
672: * and routing table entry.
673: */
674: int
675: in_ifinit(ifp, ia, sin, scrub)
676: struct ifnet *ifp;
677: struct in_ifaddr *ia;
678: struct sockaddr_in *sin;
679: int scrub;
680: {
681: u_int32_t i = sin->sin_addr.s_addr;
682: struct sockaddr_in oldaddr;
683: int s = splnet(), flags = RTF_UP, error;
684:
685: oldaddr = ia->ia_addr;
686: ia->ia_addr = *sin;
687: /*
688: * Give the interface a chance to initialize
689: * if this is its first address,
690: * and to validate the address if necessary.
691: */
692: if (ifp->if_ioctl &&
693: (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
694: ia->ia_addr = oldaddr;
695: splx(s);
696: return (error);
697: }
698: splx(s);
699:
700: /*
701: * How should a packet be routed during
702: * an address change--and is it safe?
703: * Is the "ifp" even in a consistent state?
704: * Be safe for now.
705: */
706: splassert(IPL_SOFTNET);
707:
708: if (scrub) {
709: ia->ia_ifa.ifa_addr = sintosa(&oldaddr);
710: in_ifscrub(ifp, ia);
711: ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
712: }
713: if (IN_CLASSA(i))
714: ia->ia_netmask = IN_CLASSA_NET;
715: else if (IN_CLASSB(i))
716: ia->ia_netmask = IN_CLASSB_NET;
717: else
718: ia->ia_netmask = IN_CLASSC_NET;
719: /*
720: * The subnet mask usually includes at least the standard network part,
721: * but may may be smaller in the case of supernetting.
722: * If it is set, we believe it.
723: */
724: if (ia->ia_subnetmask == 0) {
725: ia->ia_subnetmask = ia->ia_netmask;
726: ia->ia_sockmask.sin_addr.s_addr = ia->ia_subnetmask;
727: } else
728: ia->ia_netmask &= ia->ia_subnetmask;
729: ia->ia_net = i & ia->ia_netmask;
730: ia->ia_subnet = i & ia->ia_subnetmask;
731: in_socktrim(&ia->ia_sockmask);
732: /*
733: * Add route for the network.
734: */
735: ia->ia_ifa.ifa_metric = ifp->if_metric;
736: if (ifp->if_flags & IFF_BROADCAST) {
737: ia->ia_broadaddr.sin_addr.s_addr =
738: ia->ia_subnet | ~ia->ia_subnetmask;
739: ia->ia_netbroadcast.s_addr =
740: ia->ia_net | ~ia->ia_netmask;
741: } else if (ifp->if_flags & IFF_LOOPBACK) {
742: ia->ia_dstaddr = ia->ia_addr;
743: flags |= RTF_HOST;
744: } else if (ifp->if_flags & IFF_POINTOPOINT) {
745: if (ia->ia_dstaddr.sin_family != AF_INET)
746: return (0);
747: flags |= RTF_HOST;
748: }
749: error = in_addprefix(ia, flags);
750: /*
751: * If the interface supports multicast, join the "all hosts"
752: * multicast group on that interface.
753: */
754: if ((ifp->if_flags & IFF_MULTICAST) && ia->ia_allhosts == NULL) {
755: struct in_addr addr;
756:
757: addr.s_addr = INADDR_ALLHOSTS_GROUP;
758: ia->ia_allhosts = in_addmulti(&addr, ifp);
759: }
760: return (error);
761: }
762:
763: #define rtinitflags(x) \
764: ((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \
765: ? RTF_HOST : 0)
766:
767: /*
768: * add a route to prefix ("connected route" in cisco terminology).
769: * does nothing if there's some interface address with the same prefix already.
770: */
771: int
772: in_addprefix(target, flags)
773: struct in_ifaddr *target;
774: int flags;
775: {
776: struct in_ifaddr *ia;
777: struct in_addr prefix, mask, p;
778: int error;
779:
780: if ((flags & RTF_HOST) != 0)
781: prefix = target->ia_dstaddr.sin_addr;
782: else {
783: prefix = target->ia_addr.sin_addr;
784: mask = target->ia_sockmask.sin_addr;
785: prefix.s_addr &= mask.s_addr;
786: }
787:
788: TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
789: if (rtinitflags(ia)) {
790: p = ia->ia_dstaddr.sin_addr;
791: if (prefix.s_addr != p.s_addr)
792: continue;
793: } else {
794: p = ia->ia_addr.sin_addr;
795: p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
796: if (prefix.s_addr != p.s_addr ||
797: mask.s_addr != ia->ia_sockmask.sin_addr.s_addr)
798: continue;
799: }
800: if ((ia->ia_flags & IFA_ROUTE) == 0)
801: continue;
802: #if NCARP > 0
803: /* move to a real interface instead of carp interface */
804: if (ia->ia_ifp->if_type == IFT_CARP &&
805: target->ia_ifp->if_type != IFT_CARP) {
806: rtinit(&(ia->ia_ifa), (int)RTM_DELETE,
807: rtinitflags(ia));
808: ia->ia_flags &= ~IFA_ROUTE;
809: break;
810: }
811: #endif
812: /*
813: * if we got a matching prefix route inserted by other
814: * interface adderss, we don't need to bother
815: */
816: return 0;
817: }
818:
819: /*
820: * noone seem to have prefix route. insert it.
821: */
822: error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags);
823: if (!error)
824: target->ia_flags |= IFA_ROUTE;
825: return error;
826: }
827:
828: /*
829: * remove a route to prefix ("connected route" in cisco terminology).
830: * re-installs the route by using another interface address, if there's one
831: * with the same prefix (otherwise we lose the route mistakenly).
832: */
833: int
834: in_scrubprefix(target)
835: struct in_ifaddr *target;
836: {
837: struct in_ifaddr *ia;
838: struct in_addr prefix, mask, p;
839: int error;
840:
841: if ((target->ia_flags & IFA_ROUTE) == 0)
842: return 0;
843:
844: if (rtinitflags(target))
845: prefix = target->ia_dstaddr.sin_addr;
846: else {
847: prefix = target->ia_addr.sin_addr;
848: mask = target->ia_sockmask.sin_addr;
849: prefix.s_addr &= mask.s_addr;
850: }
851:
852: TAILQ_FOREACH(ia, &in_ifaddr, ia_list) {
853: if (rtinitflags(ia))
854: p = ia->ia_dstaddr.sin_addr;
855: else {
856: p = ia->ia_addr.sin_addr;
857: p.s_addr &= ia->ia_sockmask.sin_addr.s_addr;
858: }
859:
860: if (prefix.s_addr != p.s_addr)
861: continue;
862:
863: /*
864: * if we got a matching prefix route, move IFA_ROUTE to him
865: */
866: if ((ia->ia_flags & IFA_ROUTE) == 0) {
867: rtinit(&(target->ia_ifa), (int)RTM_DELETE,
868: rtinitflags(target));
869: target->ia_flags &= ~IFA_ROUTE;
870:
871: error = rtinit(&ia->ia_ifa, (int)RTM_ADD,
872: rtinitflags(ia) | RTF_UP);
873: if (error == 0)
874: ia->ia_flags |= IFA_ROUTE;
875: return error;
876: }
877: }
878:
879: /*
880: * noone seem to have prefix route. remove it.
881: */
882: rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target));
883: target->ia_flags &= ~IFA_ROUTE;
884: return 0;
885: }
886:
887: #undef rtinitflags
888:
889: /*
890: * Return 1 if the address might be a local broadcast address.
891: */
892: int
893: in_broadcast(in, ifp)
894: struct in_addr in;
895: struct ifnet *ifp;
896: {
897: struct ifnet *ifn, *if_first, *if_target;
898: struct ifaddr *ifa;
899:
900: if (in.s_addr == INADDR_BROADCAST ||
901: in.s_addr == INADDR_ANY)
902: return 1;
903:
904: if (ifp == NULL) {
905: if_first = TAILQ_FIRST(&ifnet);
906: if_target = 0;
907: } else {
908: if_first = ifp;
909: if_target = TAILQ_NEXT(ifp, if_list);
910: }
911:
912: #define ia (ifatoia(ifa))
913: /*
914: * Look through the list of addresses for a match
915: * with a broadcast address.
916: * If ifp is NULL, check against all the interfaces.
917: */
918: for (ifn = if_first; ifn != if_target; ifn = TAILQ_NEXT(ifn, if_list)) {
919: if ((ifn->if_flags & IFF_BROADCAST) == 0)
920: continue;
921: TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list)
922: if (ifa->ifa_addr->sa_family == AF_INET &&
923: in.s_addr != ia->ia_addr.sin_addr.s_addr &&
924: (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
925: in.s_addr == ia->ia_netbroadcast.s_addr ||
926: (hostzeroisbroadcast &&
927: /*
928: * Check for old-style (host 0) broadcast.
929: */
930: (in.s_addr == ia->ia_subnet ||
931: in.s_addr == ia->ia_net))))
932: return 1;
933: }
934: return (0);
935: #undef ia
936: }
937:
938: /*
939: * Add an address to the list of IP multicast addresses for a given interface.
940: */
941: struct in_multi *
942: in_addmulti(ap, ifp)
943: struct in_addr *ap;
944: struct ifnet *ifp;
945: {
946: struct in_multi *inm;
947: struct ifreq ifr;
948: struct in_ifaddr *ia;
949: int s = splsoftnet();
950:
951: /*
952: * See if address already in list.
953: */
954: IN_LOOKUP_MULTI(*ap, ifp, inm);
955: if (inm != NULL) {
956: /*
957: * Found it; just increment the reference count.
958: */
959: ++inm->inm_refcount;
960: } else {
961: /*
962: * New address; allocate a new multicast record
963: * and link it into the interface's multicast list.
964: */
965: inm = (struct in_multi *)malloc(sizeof(*inm),
966: M_IPMADDR, M_NOWAIT);
967: if (inm == NULL) {
968: splx(s);
969: return (NULL);
970: }
971: inm->inm_addr = *ap;
972: inm->inm_refcount = 1;
973: IFP_TO_IA(ifp, ia);
974: if (ia == NULL) {
975: free(inm, M_IPMADDR);
976: splx(s);
977: return (NULL);
978: }
979: inm->inm_ia = ia;
980: ia->ia_ifa.ifa_refcnt++;
981: LIST_INSERT_HEAD(&ia->ia_multiaddrs, inm, inm_list);
982: /*
983: * Ask the network driver to update its multicast reception
984: * filter appropriately for the new address.
985: */
986: satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
987: satosin(&ifr.ifr_addr)->sin_family = AF_INET;
988: satosin(&ifr.ifr_addr)->sin_addr = *ap;
989: if ((ifp->if_ioctl == NULL) ||
990: (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
991: LIST_REMOVE(inm, inm_list);
992: IFAFREE(&inm->inm_ia->ia_ifa);
993: free(inm, M_IPMADDR);
994: splx(s);
995: return (NULL);
996: }
997: /*
998: * Let IGMP know that we have joined a new IP multicast group.
999: */
1000: igmp_joingroup(inm);
1001: }
1002: splx(s);
1003: return (inm);
1004: }
1005:
1006: /*
1007: * Delete a multicast address record.
1008: */
1009: void
1010: in_delmulti(inm)
1011: struct in_multi *inm;
1012: {
1013: struct ifreq ifr;
1014: struct ifnet *ifp;
1015: int s = splsoftnet();
1016:
1017: if (--inm->inm_refcount == 0) {
1018: /*
1019: * No remaining claims to this record; let IGMP know that
1020: * we are leaving the multicast group.
1021: */
1022: igmp_leavegroup(inm);
1023: /*
1024: * Unlink from list.
1025: */
1026: LIST_REMOVE(inm, inm_list);
1027: ifp = inm->inm_ia->ia_ifp;
1028: IFAFREE(&inm->inm_ia->ia_ifa);
1029:
1030: if (ifp) {
1031: /*
1032: * Notify the network driver to update its multicast
1033: * reception filter.
1034: */
1035: satosin(&ifr.ifr_addr)->sin_family = AF_INET;
1036: satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
1037: (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
1038: }
1039: free(inm, M_IPMADDR);
1040: }
1041: splx(s);
1042: }
1043:
1044: #endif
CVSweb