Annotation of sys/netinet/in.c, Revision 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