Annotation of src/sys/netinet/in.c, revision 1.26
1.1 dillon 1: /*
2: * Copyright (c) 1982, 1986, 1991, 1993
3: * The Regents of the University of California. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: * 3. All advertising materials mentioning features or use of this software
14: * must display the following acknowledgement:
15: * This product includes software developed by the University of
16: * California, Berkeley and its contributors.
17: * 4. Neither the name of the University nor the names of its contributors
18: * may be used to endorse or promote products derived from this software
19: * without specific prior written permission.
20: *
21: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31: * SUCH DAMAGE.
32: *
33: * @(#)in.c 8.4 (Berkeley) 1/9/95
34: * $FreeBSD: src/sys/netinet/in.c,v 1.44.2.14 2002/11/08 00:45:50 suz Exp $
1.5 dillon 35: * $DragonFly$
1.1 dillon 36: */
37:
38: #include "opt_bootp.h"
1.26 ! sephe 39:
1.1 dillon 40: #include <sys/param.h>
41: #include <sys/systm.h>
42: #include <sys/sockio.h>
43: #include <sys/malloc.h>
44: #include <sys/proc.h>
1.26 ! sephe 45: #include <sys/msgport.h>
1.1 dillon 46: #include <sys/socket.h>
1.26 ! sephe 47:
1.1 dillon 48: #include <sys/kernel.h>
49: #include <sys/sysctl.h>
1.15 dillon 50: #include <sys/thread2.h>
1.1 dillon 51:
52: #include <net/if.h>
53: #include <net/if_types.h>
54: #include <net/route.h>
1.26 ! sephe 55: #include <net/netmsg2.h>
1.1 dillon 56:
57: #include <netinet/in.h>
58: #include <netinet/in_var.h>
59: #include <netinet/in_pcb.h>
60:
61: #include <netinet/igmp_var.h>
62:
1.20 swildner 63: MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address");
1.1 dillon 64:
1.7 rob 65: static int in_mask2len (struct in_addr *);
66: static void in_len2mask (struct in_addr *, int);
67: static int in_lifaddr_ioctl (struct socket *, u_long, caddr_t,
68: struct ifnet *, struct thread *);
1.1 dillon 69:
1.7 rob 70: static void in_socktrim (struct sockaddr_in *);
71: static int in_ifinit (struct ifnet *,
72: struct in_ifaddr *, struct sockaddr_in *, int);
1.1 dillon 73:
1.26 ! sephe 74: static void in_control_dispatch(struct netmsg *);
! 75: static int in_control_internal(u_long, caddr_t, struct ifnet *,
! 76: struct thread *);
! 77:
1.1 dillon 78: static int subnetsarelocal = 0;
1.13 hsu 79: SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
1.1 dillon 80: &subnetsarelocal, 0, "");
81:
82: struct in_multihead in_multihead; /* XXX BSS initialization */
83:
84: extern struct inpcbinfo ripcbinfo;
85: extern struct inpcbinfo udbinfo;
86:
87: /*
88: * Return 1 if an internet address is for a ``local'' host
89: * (one to which we have a connection). If subnetsarelocal
90: * is true, this includes other subnets of the local net.
91: * Otherwise, it includes only the directly-connected (sub)nets.
92: */
93: int
1.18 swildner 94: in_localaddr(struct in_addr in)
1.1 dillon 95: {
1.6 rob 96: u_long i = ntohl(in.s_addr);
97: struct in_ifaddr *ia;
1.1 dillon 98:
99: if (subnetsarelocal) {
100: TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
101: if ((i & ia->ia_netmask) == ia->ia_net)
102: return (1);
103: } else {
104: TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link)
105: if ((i & ia->ia_subnetmask) == ia->ia_subnet)
106: return (1);
107: }
108: return (0);
109: }
110:
111: /*
112: * Determine whether an IP address is in a reserved set of addresses
113: * that may not be forwarded, or whether datagrams to that destination
114: * may be forwarded.
115: */
116: int
1.18 swildner 117: in_canforward(struct in_addr in)
1.1 dillon 118: {
1.6 rob 119: u_long i = ntohl(in.s_addr);
120: u_long net;
1.1 dillon 121:
122: if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i))
123: return (0);
124: if (IN_CLASSA(i)) {
125: net = i & IN_CLASSA_NET;
126: if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
127: return (0);
128: }
129: return (1);
130: }
131:
132: /*
133: * Trim a mask in a sockaddr
134: */
135: static void
1.18 swildner 136: in_socktrim(struct sockaddr_in *ap)
1.1 dillon 137: {
1.6 rob 138: char *cplim = (char *) &ap->sin_addr;
139: char *cp = (char *) (&ap->sin_addr + 1);
1.1 dillon 140:
141: ap->sin_len = 0;
142: while (--cp >= cplim)
1.13 hsu 143: if (*cp) {
1.1 dillon 144: (ap)->sin_len = cp - (char *) (ap) + 1;
145: break;
146: }
147: }
148:
149: static int
1.18 swildner 150: in_mask2len(struct in_addr *mask)
1.1 dillon 151: {
152: int x, y;
153: u_char *p;
154:
155: p = (u_char *)mask;
1.14 hsu 156: for (x = 0; x < sizeof *mask; x++) {
1.1 dillon 157: if (p[x] != 0xff)
158: break;
159: }
160: y = 0;
1.14 hsu 161: if (x < sizeof *mask) {
1.1 dillon 162: for (y = 0; y < 8; y++) {
163: if ((p[x] & (0x80 >> y)) == 0)
164: break;
165: }
166: }
167: return x * 8 + y;
168: }
169:
170: static void
1.18 swildner 171: in_len2mask(struct in_addr *mask, int len)
1.1 dillon 172: {
173: int i;
174: u_char *p;
175:
176: p = (u_char *)mask;
1.14 hsu 177: bzero(mask, sizeof *mask);
1.1 dillon 178: for (i = 0; i < len / 8; i++)
179: p[i] = 0xff;
180: if (len % 8)
181: p[i] = (0xff00 >> (len % 8)) & 0xff;
182: }
183:
184: static int in_interfaces; /* number of external internet interfaces */
185:
1.26 ! sephe 186: struct in_control_arg {
! 187: u_long cmd;
! 188: caddr_t data;
! 189: struct ifnet *ifp;
! 190: struct thread *td;
! 191: };
! 192:
! 193: static void
! 194: in_control_dispatch(struct netmsg *nmsg)
! 195: {
! 196: struct lwkt_msg *msg = &nmsg->nm_lmsg;
! 197: const struct in_control_arg *arg = msg->u.ms_resultp;
! 198: int error;
! 199:
! 200: error = in_control_internal(arg->cmd, arg->data, arg->ifp, arg->td);
! 201: lwkt_replymsg(msg, error);
! 202: }
! 203:
1.1 dillon 204: /*
205: * Generic internet control operations (ioctl's).
206: * Ifp is 0 if not an interface-specific ioctl.
1.5 dillon 207: *
208: * NOTE! td might be NULL.
1.1 dillon 209: */
210: /* ARGSUSED */
211: int
1.18 swildner 212: in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
213: struct thread *td)
1.1 dillon 214: {
1.26 ! sephe 215: struct netmsg nmsg;
! 216: struct in_control_arg arg;
! 217: struct lwkt_msg *msg;
! 218: int error;
1.1 dillon 219:
220: switch (cmd) {
221: case SIOCALIFADDR:
222: case SIOCDLIFADDR:
1.5 dillon 223: if (td && (error = suser(td)) != 0)
1.1 dillon 224: return error;
225: /*fall through*/
226: case SIOCGLIFADDR:
227: if (!ifp)
228: return EINVAL;
1.4 dillon 229: return in_lifaddr_ioctl(so, cmd, data, ifp, td);
1.1 dillon 230: }
231:
1.26 ! sephe 232: KASSERT(cmd != SIOCALIFADDR && cmd != SIOCDLIFADDR,
! 233: ("recursive SIOC%cLIFADDR!\n",
! 234: cmd == SIOCDLIFADDR ? 'D' : 'A'));
! 235:
! 236: switch (cmd) {
! 237: case SIOCSIFDSTADDR:
! 238: case SIOCSIFBRDADDR:
! 239: case SIOCSIFADDR:
! 240: case SIOCSIFNETMASK:
! 241: case SIOCAIFADDR:
! 242: case SIOCDIFADDR:
! 243: bzero(&arg, sizeof(arg));
! 244: arg.cmd = cmd;
! 245: arg.data = data;
! 246: arg.ifp = ifp;
! 247: arg.td = td;
! 248:
! 249: netmsg_init(&nmsg, &curthread->td_msgport, 0,
! 250: in_control_dispatch);
! 251: msg = &nmsg.nm_lmsg;
! 252: msg->u.ms_resultp = &arg;
! 253:
! 254: lwkt_domsg(cpu_portfn(0), msg, 0);
! 255: return msg->ms_error;
! 256: default:
! 257: return in_control_internal(cmd, data, ifp, td);
! 258: }
! 259: }
! 260:
! 261: static int
! 262: in_control_internal(u_long cmd, caddr_t data, struct ifnet *ifp,
! 263: struct thread *td)
! 264: {
! 265: struct ifreq *ifr = (struct ifreq *)data;
! 266: struct in_ifaddr *ia = 0, *iap;
! 267: struct in_addr dst;
! 268: struct in_ifaddr *oia;
! 269: struct in_aliasreq *ifra = (struct in_aliasreq *)data;
! 270: struct sockaddr_in oldaddr;
! 271: int hostIsNew, iaIsNew, maskIsNew;
! 272: int error = 0;
! 273:
! 274: iaIsNew = 0;
! 275:
1.1 dillon 276: /*
277: * Find address for this interface, if it exists.
278: *
279: * If an alias address was specified, find that one instead of
280: * the first one on the interface, if possible
281: */
282: if (ifp) {
283: dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr;
284: LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash)
285: if (iap->ia_ifp == ifp &&
286: iap->ia_addr.sin_addr.s_addr == dst.s_addr) {
287: ia = iap;
288: break;
289: }
1.26 ! sephe 290: if (ia == NULL) {
! 291: struct ifaddr_container *ifac;
! 292:
! 293: TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid],
! 294: ifa_link) {
! 295: iap = ifatoia(ifac->ifa);
1.1 dillon 296: if (iap->ia_addr.sin_family == AF_INET) {
297: ia = iap;
298: break;
299: }
300: }
1.26 ! sephe 301: }
1.1 dillon 302: }
303:
304: switch (cmd) {
305:
306: case SIOCAIFADDR:
307: case SIOCDIFADDR:
1.25 sephe 308: if (ifp == NULL)
1.1 dillon 309: return (EADDRNOTAVAIL);
310: if (ifra->ifra_addr.sin_family == AF_INET) {
311: for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) {
312: if (ia->ia_ifp == ifp &&
313: ia->ia_addr.sin_addr.s_addr ==
314: ifra->ifra_addr.sin_addr.s_addr)
315: break;
316: }
317: if ((ifp->if_flags & IFF_POINTOPOINT)
318: && (cmd == SIOCAIFADDR)
319: && (ifra->ifra_dstaddr.sin_addr.s_addr
320: == INADDR_ANY)) {
321: return EDESTADDRREQ;
322: }
323: }
1.25 sephe 324: if (cmd == SIOCDIFADDR && ia == NULL)
1.1 dillon 325: return (EADDRNOTAVAIL);
326: /* FALLTHROUGH */
327: case SIOCSIFADDR:
328: case SIOCSIFNETMASK:
329: case SIOCSIFDSTADDR:
1.5 dillon 330: if (td && (error = suser(td)) != 0)
1.1 dillon 331: return error;
332:
1.25 sephe 333: if (ifp == NULL)
1.1 dillon 334: return (EADDRNOTAVAIL);
1.23 sephe 335: if (ia == NULL) {
1.26 ! sephe 336: struct ifaddr *ifa;
! 337:
! 338: ia = ifa_create(sizeof(*ia), M_WAITOK);
1.24 sephe 339:
1.1 dillon 340: /*
1.21 sephe 341: * Protect from NETISR_IP traversing address list
1.1 dillon 342: * while we're modifying it.
343: */
1.15 dillon 344: crit_enter();
1.1 dillon 345:
346: TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
347: ifa = &ia->ia_ifa;
1.26 ! sephe 348: ifa_iflink(ifa, ifp, 1);
1.1 dillon 349:
350: ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
351: ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
352: ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
353: ia->ia_sockmask.sin_len = 8;
354: ia->ia_sockmask.sin_family = AF_INET;
355: if (ifp->if_flags & IFF_BROADCAST) {
1.14 hsu 356: ia->ia_broadaddr.sin_len = sizeof ia->ia_addr;
1.1 dillon 357: ia->ia_broadaddr.sin_family = AF_INET;
358: }
359: ia->ia_ifp = ifp;
360: if (!(ifp->if_flags & IFF_LOOPBACK))
361: in_interfaces++;
362: iaIsNew = 1;
1.15 dillon 363: crit_exit();
1.1 dillon 364: }
365: break;
366:
367: case SIOCSIFBRDADDR:
1.5 dillon 368: if (td && (error = suser(td)) != 0)
1.1 dillon 369: return error;
370: /* FALLTHROUGH */
371:
372: case SIOCGIFADDR:
373: case SIOCGIFNETMASK:
374: case SIOCGIFDSTADDR:
375: case SIOCGIFBRDADDR:
1.25 sephe 376: if (ia == NULL)
1.1 dillon 377: return (EADDRNOTAVAIL);
378: break;
379: }
380: switch (cmd) {
381:
382: case SIOCGIFADDR:
383: *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
384: return (0);
385:
386: case SIOCGIFBRDADDR:
387: if ((ifp->if_flags & IFF_BROADCAST) == 0)
388: return (EINVAL);
389: *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
390: return (0);
391:
392: case SIOCGIFDSTADDR:
393: if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
394: return (EINVAL);
395: *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
396: return (0);
397:
398: case SIOCGIFNETMASK:
399: *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
400: return (0);
401:
402: case SIOCSIFDSTADDR:
403: if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
404: return (EINVAL);
405: oldaddr = ia->ia_dstaddr;
406: ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
1.17 dillon 407: lwkt_serialize_enter(ifp->if_serializer);
1.9 hsu 408: if (ifp->if_ioctl &&
1.17 dillon 409: (error = ifp->if_ioctl(ifp, SIOCSIFDSTADDR, (caddr_t)ia,
1.9 hsu 410: td->td_proc->p_ucred))) {
1.1 dillon 411: ia->ia_dstaddr = oldaddr;
1.17 dillon 412: lwkt_serialize_exit(ifp->if_serializer);
1.1 dillon 413: return (error);
414: }
415: if (ia->ia_flags & IFA_ROUTE) {
416: ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
1.13 hsu 417: rtinit(&ia->ia_ifa, RTM_DELETE, RTF_HOST);
1.1 dillon 418: ia->ia_ifa.ifa_dstaddr =
419: (struct sockaddr *)&ia->ia_dstaddr;
1.13 hsu 420: rtinit(&ia->ia_ifa, RTM_ADD, RTF_HOST | RTF_UP);
1.1 dillon 421: }
1.17 dillon 422: lwkt_serialize_exit(ifp->if_serializer);
1.1 dillon 423: return (0);
424:
425: case SIOCSIFBRDADDR:
426: if ((ifp->if_flags & IFF_BROADCAST) == 0)
427: return (EINVAL);
428: ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
429: return (0);
430:
431: case SIOCSIFADDR:
432: error = in_ifinit(ifp, ia,
433: (struct sockaddr_in *) &ifr->ifr_addr, 1);
434: if (error != 0 && iaIsNew)
435: break;
1.12 joerg 436: if (error == 0)
437: EVENTHANDLER_INVOKE(ifaddr_event, ifp);
1.1 dillon 438: return (0);
439:
440: case SIOCSIFNETMASK:
441: ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr;
442: ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr);
443: return (0);
444:
445: case SIOCAIFADDR:
446: maskIsNew = 0;
447: hostIsNew = 1;
448: error = 0;
449: if (ia->ia_addr.sin_family == AF_INET) {
450: if (ifra->ifra_addr.sin_len == 0) {
451: ifra->ifra_addr = ia->ia_addr;
452: hostIsNew = 0;
453: } else if (ifra->ifra_addr.sin_addr.s_addr ==
454: ia->ia_addr.sin_addr.s_addr)
455: hostIsNew = 0;
456: }
457: if (ifra->ifra_mask.sin_len) {
458: in_ifscrub(ifp, ia);
459: ia->ia_sockmask = ifra->ifra_mask;
460: ia->ia_sockmask.sin_family = AF_INET;
461: ia->ia_subnetmask =
462: ntohl(ia->ia_sockmask.sin_addr.s_addr);
463: maskIsNew = 1;
464: }
465: if ((ifp->if_flags & IFF_POINTOPOINT) &&
466: (ifra->ifra_dstaddr.sin_family == AF_INET)) {
467: in_ifscrub(ifp, ia);
468: ia->ia_dstaddr = ifra->ifra_dstaddr;
469: maskIsNew = 1; /* We lie; but the effect's the same */
470: }
471: if (ifra->ifra_addr.sin_family == AF_INET &&
472: (hostIsNew || maskIsNew))
473: error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
474:
475: if (error != 0 && iaIsNew)
476: break;
477:
478: if ((ifp->if_flags & IFF_BROADCAST) &&
479: (ifra->ifra_broadaddr.sin_family == AF_INET))
480: ia->ia_broadaddr = ifra->ifra_broadaddr;
1.12 joerg 481: if (error == 0)
482: EVENTHANDLER_INVOKE(ifaddr_event, ifp);
1.1 dillon 483: return (error);
484:
485: case SIOCDIFADDR:
486: /*
487: * in_ifscrub kills the interface route.
488: */
489: in_ifscrub(ifp, ia);
490: /*
491: * in_ifadown gets rid of all the rest of
492: * the routes. This is not quite the right
493: * thing to do, but at least if we are running
494: * a routing process they will come back.
495: */
496: in_ifadown(&ia->ia_ifa, 1);
1.12 joerg 497: EVENTHANDLER_INVOKE(ifaddr_event, ifp);
1.1 dillon 498: error = 0;
499: break;
500:
501: default:
1.9 hsu 502: if (ifp == NULL || ifp->if_ioctl == NULL)
1.1 dillon 503: return (EOPNOTSUPP);
1.17 dillon 504: lwkt_serialize_enter(ifp->if_serializer);
505: error = ifp->if_ioctl(ifp, cmd, data, td->td_proc->p_ucred);
506: lwkt_serialize_exit(ifp->if_serializer);
507: return (error);
1.1 dillon 508: }
509:
1.26 ! sephe 510: ifa_ifunlink(&ia->ia_ifa, ifp);
! 511:
1.1 dillon 512: /*
1.21 sephe 513: * Protect from NETISR_IP traversing address list while we're modifying
1.1 dillon 514: * it.
515: */
1.26 ! sephe 516: crit_enter(); /* XXX MP */
1.1 dillon 517: TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link);
518: LIST_REMOVE(ia, ia_hash);
1.26 ! sephe 519: crit_exit(); /* XXX MP */
! 520:
! 521: ifa_destroy(&ia->ia_ifa);
1.1 dillon 522:
523: return (error);
524: }
525:
526: /*
527: * SIOC[GAD]LIFADDR.
528: * SIOCGLIFADDR: get first address. (?!?)
529: * SIOCGLIFADDR with IFLR_PREFIX:
530: * get first address that matches the specified prefix.
531: * SIOCALIFADDR: add the specified address.
532: * SIOCALIFADDR with IFLR_PREFIX:
533: * EINVAL since we can't deduce hostid part of the address.
534: * SIOCDLIFADDR: delete the specified address.
535: * SIOCDLIFADDR with IFLR_PREFIX:
536: * delete the first address that matches the specified prefix.
537: * return values:
538: * EINVAL on invalid parameters
539: * EADDRNOTAVAIL on prefix match failed/specified address not found
540: * other values may be returned from in_ioctl()
1.5 dillon 541: *
542: * NOTE! td might be NULL.
1.1 dillon 543: */
544: static int
1.18 swildner 545: in_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp,
546: struct thread *td)
1.1 dillon 547: {
548: struct if_laddrreq *iflr = (struct if_laddrreq *)data;
549:
550: /* sanity checks */
551: if (!data || !ifp) {
552: panic("invalid argument to in_lifaddr_ioctl");
553: /*NOTRECHED*/
554: }
555:
556: switch (cmd) {
557: case SIOCGLIFADDR:
558: /* address must be specified on GET with IFLR_PREFIX */
559: if ((iflr->flags & IFLR_PREFIX) == 0)
560: break;
561: /*FALLTHROUGH*/
562: case SIOCALIFADDR:
563: case SIOCDLIFADDR:
564: /* address must be specified on ADD and DELETE */
565: if (iflr->addr.ss_family != AF_INET)
566: return EINVAL;
567: if (iflr->addr.ss_len != sizeof(struct sockaddr_in))
568: return EINVAL;
569: /* XXX need improvement */
570: if (iflr->dstaddr.ss_family
571: && iflr->dstaddr.ss_family != AF_INET)
572: return EINVAL;
573: if (iflr->dstaddr.ss_family
574: && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in))
575: return EINVAL;
576: break;
577: default: /*shouldn't happen*/
578: return EOPNOTSUPP;
579: }
580: if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
581: return EINVAL;
582:
583: switch (cmd) {
584: case SIOCALIFADDR:
585: {
586: struct in_aliasreq ifra;
587:
588: if (iflr->flags & IFLR_PREFIX)
589: return EINVAL;
590:
591: /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
1.14 hsu 592: bzero(&ifra, sizeof ifra);
593: bcopy(iflr->iflr_name, ifra.ifra_name, sizeof ifra.ifra_name);
1.1 dillon 594:
595: bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len);
596:
597: if (iflr->dstaddr.ss_family) { /*XXX*/
598: bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
599: iflr->dstaddr.ss_len);
600: }
601:
602: ifra.ifra_mask.sin_family = AF_INET;
603: ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
604: in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
605:
1.4 dillon 606: return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td);
1.1 dillon 607: }
608: case SIOCGLIFADDR:
609: case SIOCDLIFADDR:
610: {
1.26 ! sephe 611: struct ifaddr_container *ifac;
1.1 dillon 612: struct in_ifaddr *ia;
613: struct in_addr mask, candidate, match;
614: struct sockaddr_in *sin;
615: int cmp;
616:
1.14 hsu 617: bzero(&mask, sizeof mask);
1.1 dillon 618: if (iflr->flags & IFLR_PREFIX) {
619: /* lookup a prefix rather than address. */
620: in_len2mask(&mask, iflr->prefixlen);
621:
622: sin = (struct sockaddr_in *)&iflr->addr;
623: match.s_addr = sin->sin_addr.s_addr;
624: match.s_addr &= mask.s_addr;
625:
626: /* if you set extra bits, that's wrong */
627: if (match.s_addr != sin->sin_addr.s_addr)
628: return EINVAL;
629:
630: cmp = 1;
631: } else {
632: if (cmd == SIOCGLIFADDR) {
633: /* on getting an address, take the 1st match */
1.23 sephe 634: match.s_addr = 0; /* gcc4 warning */
1.1 dillon 635: cmp = 0; /*XXX*/
636: } else {
637: /* on deleting an address, do exact match */
638: in_len2mask(&mask, 32);
639: sin = (struct sockaddr_in *)&iflr->addr;
640: match.s_addr = sin->sin_addr.s_addr;
641:
642: cmp = 1;
643: }
644: }
645:
1.26 ! sephe 646: TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
! 647: struct ifaddr *ifa = ifac->ifa;
! 648:
1.1 dillon 649: if (ifa->ifa_addr->sa_family != AF_INET6)
650: continue;
651: if (!cmp)
652: break;
1.26 ! sephe 653: candidate.s_addr =
! 654: ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr;
1.1 dillon 655: candidate.s_addr &= mask.s_addr;
656: if (candidate.s_addr == match.s_addr)
657: break;
658: }
1.26 ! sephe 659: if (ifac == NULL)
1.1 dillon 660: return EADDRNOTAVAIL;
1.26 ! sephe 661: ia = (struct in_ifaddr *)(ifac->ifa);
1.1 dillon 662:
663: if (cmd == SIOCGLIFADDR) {
664: /* fill in the if_laddrreq structure */
665: bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
666:
667: if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
668: bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
669: ia->ia_dstaddr.sin_len);
670: } else
1.14 hsu 671: bzero(&iflr->dstaddr, sizeof iflr->dstaddr);
1.1 dillon 672:
673: iflr->prefixlen =
674: in_mask2len(&ia->ia_sockmask.sin_addr);
675:
676: iflr->flags = 0; /*XXX*/
677:
678: return 0;
679: } else {
680: struct in_aliasreq ifra;
681:
682: /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
1.14 hsu 683: bzero(&ifra, sizeof ifra);
1.1 dillon 684: bcopy(iflr->iflr_name, ifra.ifra_name,
1.14 hsu 685: sizeof ifra.ifra_name);
1.1 dillon 686:
687: bcopy(&ia->ia_addr, &ifra.ifra_addr,
688: ia->ia_addr.sin_len);
689: if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
690: bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
691: ia->ia_dstaddr.sin_len);
692: }
693: bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
694: ia->ia_sockmask.sin_len);
695:
696: return in_control(so, SIOCDIFADDR, (caddr_t)&ifra,
1.4 dillon 697: ifp, td);
1.1 dillon 698: }
699: }
700: }
701:
702: return EOPNOTSUPP; /*just for safety*/
703: }
704:
705: /*
706: * Delete any existing route for an interface.
707: */
708: void
1.18 swildner 709: in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
1.1 dillon 710: {
711:
712: if ((ia->ia_flags & IFA_ROUTE) == 0)
713: return;
714: if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
1.13 hsu 715: rtinit(&ia->ia_ifa, RTM_DELETE, RTF_HOST);
1.1 dillon 716: else
1.13 hsu 717: rtinit(&ia->ia_ifa, RTM_DELETE, 0);
1.1 dillon 718: ia->ia_flags &= ~IFA_ROUTE;
719: }
720:
721: /*
722: * Initialize an interface's internet address
723: * and routing table entry.
724: */
725: static int
1.18 swildner 726: in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, int scrub)
1.1 dillon 727: {
1.6 rob 728: u_long i = ntohl(sin->sin_addr.s_addr);
1.1 dillon 729: struct sockaddr_in oldaddr;
1.15 dillon 730: int flags = RTF_UP, error = 0;
731:
1.17 dillon 732: lwkt_serialize_enter(ifp->if_serializer);
1.1 dillon 733:
734: oldaddr = ia->ia_addr;
735: if (oldaddr.sin_family == AF_INET)
736: LIST_REMOVE(ia, ia_hash);
737: ia->ia_addr = *sin;
738: if (ia->ia_addr.sin_family == AF_INET)
739: LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
740: ia, ia_hash);
741: /*
742: * Give the interface a chance to initialize
743: * if this is its first address,
744: * and to validate the address if necessary.
745: */
746: if (ifp->if_ioctl &&
1.17 dillon 747: (error = ifp->if_ioctl(ifp, SIOCSIFADDR, (caddr_t)ia, NULL))) {
748: lwkt_serialize_exit(ifp->if_serializer);
1.1 dillon 749: /* LIST_REMOVE(ia, ia_hash) is done in in_control */
750: ia->ia_addr = oldaddr;
751: if (ia->ia_addr.sin_family == AF_INET)
752: LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr),
753: ia, ia_hash);
754: return (error);
755: }
1.17 dillon 756: lwkt_serialize_exit(ifp->if_serializer);
1.1 dillon 757: if (scrub) {
758: ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
759: in_ifscrub(ifp, ia);
760: ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
761: }
762: if (IN_CLASSA(i))
763: ia->ia_netmask = IN_CLASSA_NET;
764: else if (IN_CLASSB(i))
765: ia->ia_netmask = IN_CLASSB_NET;
766: else
767: ia->ia_netmask = IN_CLASSC_NET;
768: /*
769: * The subnet mask usually includes at least the standard network part,
770: * but may may be smaller in the case of supernetting.
771: * If it is set, we believe it.
772: */
773: if (ia->ia_subnetmask == 0) {
774: ia->ia_subnetmask = ia->ia_netmask;
775: ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
776: } else
777: ia->ia_netmask &= ia->ia_subnetmask;
778: ia->ia_net = i & ia->ia_netmask;
779: ia->ia_subnet = i & ia->ia_subnetmask;
780: in_socktrim(&ia->ia_sockmask);
781: /*
782: * Add route for the network.
783: */
784: ia->ia_ifa.ifa_metric = ifp->if_metric;
785: if (ifp->if_flags & IFF_BROADCAST) {
786: ia->ia_broadaddr.sin_addr.s_addr =
787: htonl(ia->ia_subnet | ~ia->ia_subnetmask);
788: ia->ia_netbroadcast.s_addr =
789: htonl(ia->ia_net | ~ ia->ia_netmask);
790: } else if (ifp->if_flags & IFF_LOOPBACK) {
791: ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
792: flags |= RTF_HOST;
793: } else if (ifp->if_flags & IFF_POINTOPOINT) {
794: if (ia->ia_dstaddr.sin_family != AF_INET)
795: return (0);
796: flags |= RTF_HOST;
797: }
798:
799: /*-
800: * Don't add host routes for interface addresses of
801: * 0.0.0.0 --> 0.255.255.255 netmask 255.0.0.0. This makes it
802: * possible to assign several such address pairs with consistent
803: * results (no host route) and is required by BOOTP.
804: *
805: * XXX: This is ugly ! There should be a way for the caller to
806: * say that they don't want a host route.
807: */
808: if (ia->ia_addr.sin_addr.s_addr != INADDR_ANY ||
809: ia->ia_netmask != IN_CLASSA_NET ||
810: ia->ia_dstaddr.sin_addr.s_addr != htonl(IN_CLASSA_HOST)) {
811: if ((error = rtinit(&ia->ia_ifa, (int)RTM_ADD, flags)) != 0) {
812: ia->ia_addr = oldaddr;
813: return (error);
814: }
815: ia->ia_flags |= IFA_ROUTE;
816: }
817:
818: /*
819: * If the interface supports multicast, join the "all hosts"
820: * multicast group on that interface.
821: */
822: if (ifp->if_flags & IFF_MULTICAST) {
823: struct in_addr addr;
824:
825: addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
826: in_addmulti(&addr, ifp);
827: }
828: return (error);
829: }
830:
831:
832: /*
833: * Return 1 if the address might be a local broadcast address.
834: */
835: int
1.13 hsu 836: in_broadcast(struct in_addr in, struct ifnet *ifp)
1.1 dillon 837: {
1.26 ! sephe 838: struct ifaddr_container *ifac;
1.1 dillon 839: u_long t;
840:
841: if (in.s_addr == INADDR_BROADCAST ||
842: in.s_addr == INADDR_ANY)
843: return 1;
844: if ((ifp->if_flags & IFF_BROADCAST) == 0)
845: return 0;
846: t = ntohl(in.s_addr);
847: /*
848: * Look through the list of addresses for a match
849: * with a broadcast address.
850: */
851: #define ia ((struct in_ifaddr *)ifa)
1.26 ! sephe 852: TAILQ_FOREACH(ifac, &ifp->if_addrheads[mycpuid], ifa_link) {
! 853: struct ifaddr *ifa = ifac->ifa;
! 854:
1.1 dillon 855: if (ifa->ifa_addr->sa_family == AF_INET &&
856: (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
857: in.s_addr == ia->ia_netbroadcast.s_addr ||
858: /*
859: * Check for old-style (host 0) broadcast.
860: */
861: t == ia->ia_subnet || t == ia->ia_net) &&
862: /*
863: * Check for an all one subnetmask. These
864: * only exist when an interface gets a secondary
865: * address.
866: */
867: ia->ia_subnetmask != (u_long)0xffffffff)
868: return 1;
1.26 ! sephe 869: }
1.1 dillon 870: return (0);
871: #undef ia
872: }
873: /*
874: * Add an address to the list of IP multicast addresses for a given interface.
875: */
876: struct in_multi *
1.18 swildner 877: in_addmulti(struct in_addr *ap, struct ifnet *ifp)
1.1 dillon 878: {
1.6 rob 879: struct in_multi *inm;
1.1 dillon 880: int error;
881: struct sockaddr_in sin;
882: struct ifmultiaddr *ifma;
883:
884: /*
885: * Call generic routine to add membership or increment
886: * refcount. It wants addresses in the form of a sockaddr,
887: * so we build one here (being careful to zero the unused bytes).
888: */
889: bzero(&sin, sizeof sin);
890: sin.sin_family = AF_INET;
891: sin.sin_len = sizeof sin;
892: sin.sin_addr = *ap;
1.15 dillon 893: crit_enter();
1.1 dillon 894: error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
895: if (error) {
1.15 dillon 896: crit_exit();
1.1 dillon 897: return 0;
898: }
899:
900: /*
901: * If ifma->ifma_protospec is null, then if_addmulti() created
902: * a new record. Otherwise, we are done.
903: */
904: if (ifma->ifma_protospec != 0) {
1.15 dillon 905: crit_exit();
1.1 dillon 906: return ifma->ifma_protospec;
907: }
908:
909: /* XXX - if_addmulti uses M_WAITOK. Can this really be called
910: at interrupt time? If so, need to fix if_addmulti. XXX */
1.19 dillon 911: inm = kmalloc(sizeof *inm, M_IPMADDR, M_WAITOK | M_ZERO);
1.1 dillon 912: inm->inm_addr = *ap;
913: inm->inm_ifp = ifp;
914: inm->inm_ifma = ifma;
915: ifma->ifma_protospec = inm;
916: LIST_INSERT_HEAD(&in_multihead, inm, inm_link);
917:
918: /*
919: * Let IGMP know that we have joined a new IP multicast group.
920: */
921: igmp_joingroup(inm);
1.15 dillon 922: crit_exit();
1.1 dillon 923: return (inm);
924: }
925:
926: /*
927: * Delete a multicast address record.
928: */
929: void
1.18 swildner 930: in_delmulti(struct in_multi *inm)
1.1 dillon 931: {
1.15 dillon 932: struct ifmultiaddr *ifma;
1.1 dillon 933: struct in_multi my_inm;
934:
1.15 dillon 935: crit_enter();
936: ifma = inm->inm_ifma;
1.1 dillon 937: my_inm.inm_ifp = NULL ; /* don't send the leave msg */
938: if (ifma->ifma_refcount == 1) {
939: /*
940: * No remaining claims to this record; let IGMP know that
941: * we are leaving the multicast group.
942: * But do it after the if_delmulti() which might reset
943: * the interface and nuke the packet.
944: */
945: my_inm = *inm ;
946: ifma->ifma_protospec = 0;
947: LIST_REMOVE(inm, inm_link);
1.19 dillon 948: kfree(inm, M_IPMADDR);
1.1 dillon 949: }
950: /* XXX - should be separate API for when we have an ifma? */
951: if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
952: if (my_inm.inm_ifp != NULL)
953: igmp_leavegroup(&my_inm);
1.15 dillon 954: crit_exit();
1.1 dillon 955: }
1.16 joerg 956:
957: void
958: in_ifdetach(struct ifnet *ifp)
959: {
960: in_pcbpurgeif0(LIST_FIRST(&ripcbinfo.pcblisthead), ifp);
961: in_pcbpurgeif0(LIST_FIRST(&udbinfo.pcblisthead), ifp);
962: }