|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * Copyright (c) 1982, 1986, 1991, 1993 ! 24: * The Regents of the University of California. All rights reserved. ! 25: * ! 26: * Redistribution and use in source and binary forms, with or without ! 27: * modification, are permitted provided that the following conditions ! 28: * are met: ! 29: * 1. Redistributions of source code must retain the above copyright ! 30: * notice, this list of conditions and the following disclaimer. ! 31: * 2. Redistributions in binary form must reproduce the above copyright ! 32: * notice, this list of conditions and the following disclaimer in the ! 33: * documentation and/or other materials provided with the distribution. ! 34: * 3. All advertising materials mentioning features or use of this software ! 35: * must display the following acknowledgement: ! 36: * This product includes software developed by the University of ! 37: * California, Berkeley and its contributors. ! 38: * 4. Neither the name of the University nor the names of its contributors ! 39: * may be used to endorse or promote products derived from this software ! 40: * without specific prior written permission. ! 41: * ! 42: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 43: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 44: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 45: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 46: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 47: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 48: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 49: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 50: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 51: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 52: * SUCH DAMAGE. ! 53: * ! 54: * @(#)in.c 8.4 (Berkeley) 1/9/95 ! 55: */ ! 56: ! 57: #include <sys/param.h> ! 58: #include <sys/systm.h> ! 59: #include <sys/sockio.h> ! 60: #include <sys/socketvar.h> ! 61: #include <sys/malloc.h> ! 62: #include <sys/proc.h> ! 63: #include <sys/socket.h> ! 64: #include <sys/kernel.h> ! 65: #include <sys/sysctl.h> ! 66: ! 67: #include <net/if.h> ! 68: #include <net/route.h> ! 69: ! 70: #include <netinet/in.h> ! 71: #include <netinet/in_var.h> ! 72: #include <netinet/in_pcb.h> ! 73: ! 74: #include <netinet/igmp_var.h> ! 75: #include <net/dlil.h> ! 76: ! 77: #include <netinet/ip_var.h> ! 78: ! 79: #include <netinet/tcp.h> ! 80: #include <netinet/tcp_timer.h> ! 81: #include <netinet/tcp_var.h> ! 82: ! 83: #include <sys/file.h> ! 84: ! 85: ! 86: /* ! 87: static MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); ! 88: */ ! 89: ! 90: static void in_socktrim __P((struct sockaddr_in *)); ! 91: static int in_ifinit __P((struct ifnet *, ! 92: struct in_ifaddr *, struct sockaddr_in *, int)); ! 93: ! 94: static int subnetsarelocal = 0; ! 95: SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, ! 96: &subnetsarelocal, 0, ""); ! 97: ! 98: struct in_multihead in_multihead; /* XXX BSS initialization */ ! 99: ! 100: extern void arp_rtrequest(); ! 101: ! 102: ! 103: /* ! 104: * Return 1 if an internet address is for a ``local'' host ! 105: * (one to which we have a connection). If subnetsarelocal ! 106: * is true, this includes other subnets of the local net. ! 107: * Otherwise, it includes only the directly-connected (sub)nets. ! 108: */ ! 109: int ! 110: in_localaddr(in) ! 111: struct in_addr in; ! 112: { ! 113: register u_long i = ntohl(in.s_addr); ! 114: register struct in_ifaddr *ia; ! 115: ! 116: if (subnetsarelocal) { ! 117: for (ia = in_ifaddrhead.tqh_first; ia; ! 118: ia = ia->ia_link.tqe_next) ! 119: if ((i & ia->ia_netmask) == ia->ia_net) ! 120: return (1); ! 121: } else { ! 122: for (ia = in_ifaddrhead.tqh_first; ia; ! 123: ia = ia->ia_link.tqe_next) ! 124: if ((i & ia->ia_subnetmask) == ia->ia_subnet) ! 125: return (1); ! 126: } ! 127: return (0); ! 128: } ! 129: ! 130: /* ! 131: * Determine whether an IP address is in a reserved set of addresses ! 132: * that may not be forwarded, or whether datagrams to that destination ! 133: * may be forwarded. ! 134: */ ! 135: int ! 136: in_canforward(in) ! 137: struct in_addr in; ! 138: { ! 139: register u_long i = ntohl(in.s_addr); ! 140: register u_long net; ! 141: ! 142: if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) ! 143: return (0); ! 144: if (IN_CLASSA(i)) { ! 145: net = i & IN_CLASSA_NET; ! 146: if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) ! 147: return (0); ! 148: } ! 149: return (1); ! 150: } ! 151: ! 152: /* ! 153: * Trim a mask in a sockaddr ! 154: */ ! 155: static void ! 156: in_socktrim(ap) ! 157: struct sockaddr_in *ap; ! 158: { ! 159: register char *cplim = (char *) &ap->sin_addr; ! 160: register char *cp = (char *) (&ap->sin_addr + 1); ! 161: ! 162: ap->sin_len = 0; ! 163: while (--cp >= cplim) ! 164: if (*cp) { ! 165: (ap)->sin_len = cp - (char *) (ap) + 1; ! 166: break; ! 167: } ! 168: } ! 169: ! 170: static int in_interfaces; /* number of external internet interfaces */ ! 171: ! 172: /* ! 173: * Generic internet control operations (ioctl's). ! 174: * Ifp is 0 if not an interface-specific ioctl. ! 175: */ ! 176: /* ARGSUSED */ ! 177: int ! 178: in_control(so, cmd, data, ifp, p) ! 179: struct socket *so; ! 180: u_long cmd; ! 181: caddr_t data; ! 182: register struct ifnet *ifp; ! 183: struct proc *p; ! 184: { ! 185: register struct ifreq *ifr = (struct ifreq *)data; ! 186: register struct in_ifaddr *ia = 0, *iap; ! 187: register struct ifaddr *ifa; ! 188: struct in_ifaddr *oia; ! 189: struct in_aliasreq *ifra = (struct in_aliasreq *)data; ! 190: struct sockaddr_in oldaddr; ! 191: int error, hostIsNew, maskIsNew, s; ! 192: u_long i, dl_tag; ! 193: ! 194: /* ! 195: * Find address for this interface, if it exists. ! 196: * ! 197: * If an alias address was specified, find that one instead of ! 198: * the first one on the interface. ! 199: */ ! 200: if (ifp) ! 201: for (iap = in_ifaddrhead.tqh_first; iap; ! 202: iap = iap->ia_link.tqe_next) ! 203: if (iap->ia_ifp == ifp) { ! 204: if (((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr == ! 205: iap->ia_addr.sin_addr.s_addr) { ! 206: ia = iap; ! 207: break; ! 208: } else if (ia == NULL) { ! 209: ia = iap; ! 210: if (ifr->ifr_addr.sa_family != AF_INET) ! 211: break; ! 212: } ! 213: } ! 214: ! 215: switch (cmd) { ! 216: ! 217: case SIOCAIFADDR: ! 218: case SIOCDIFADDR: ! 219: if (ifp == 0) ! 220: return (EADDRNOTAVAIL); ! 221: if (ifra->ifra_addr.sin_family == AF_INET) { ! 222: for (oia = ia; ia; ia = ia->ia_link.tqe_next) { ! 223: if (ia->ia_ifp == ifp && ! 224: ia->ia_addr.sin_addr.s_addr == ! 225: ifra->ifra_addr.sin_addr.s_addr) ! 226: break; ! 227: } ! 228: if ((ifp->if_flags & IFF_POINTOPOINT) ! 229: && (cmd == SIOCAIFADDR) ! 230: && (ifra->ifra_dstaddr.sin_addr.s_addr ! 231: == INADDR_ANY)) { ! 232: return EDESTADDRREQ; ! 233: } ! 234: } ! 235: if (cmd == SIOCDIFADDR && ia == 0) ! 236: return (EADDRNOTAVAIL); ! 237: /* FALLTHROUGH */ ! 238: case SIOCSIFADDR: ! 239: case SIOCSIFNETMASK: ! 240: case SIOCSIFDSTADDR: ! 241: ! 242: #if ISFB31 ! 243: if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 244: return error; ! 245: #else ! 246: if ((so->so_state & SS_PRIV) == 0) ! 247: return (EPERM); ! 248: #endif ! 249: ! 250: if (ifp == 0) ! 251: return (EADDRNOTAVAIL); ! 252: if (ia == (struct in_ifaddr *)0) { ! 253: ia = (struct in_ifaddr *) ! 254: _MALLOC(sizeof *ia, M_IFADDR, M_WAITOK); ! 255: if (ia == (struct in_ifaddr *)NULL) ! 256: return (ENOBUFS); ! 257: bzero((caddr_t)ia, sizeof *ia); ! 258: /* ! 259: * Protect from ipintr() traversing address list ! 260: * while we're modifying it. ! 261: */ ! 262: s = splnet(); ! 263: ! 264: TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link); ! 265: ifa = &ia->ia_ifa; ! 266: TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); ! 267: ! 268: /* ! 269: * Temorary code for protocol attachment XXX ! 270: */ ! 271: ! 272: if (strcmp(ifp->if_name, "en") == 0) ! 273: dl_tag = ether_attach_inet(ifp); ! 274: ! 275: if (strcmp(ifp->if_name, "lo") == 0) ! 276: dl_tag = lo_attach_inet(ifp); ! 277: /* End of temp code */ ! 278: ! 279: ifa->ifa_dlt = dl_tag; ! 280: ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; ! 281: ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; ! 282: ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; ! 283: ia->ia_sockmask.sin_len = 8; ! 284: if (ifp->if_flags & IFF_BROADCAST) { ! 285: ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); ! 286: ia->ia_broadaddr.sin_family = AF_INET; ! 287: } ! 288: ia->ia_ifp = ifp; ! 289: if (!(ifp->if_flags & IFF_LOOPBACK)) ! 290: in_interfaces++; ! 291: splx(s); ! 292: } ! 293: break; ! 294: ! 295: case SIOCSIFBRDADDR: ! 296: #if ISFB31 ! 297: if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0) ! 298: return error; ! 299: #else ! 300: if ((so->so_state & SS_PRIV) == 0) ! 301: return (EPERM); ! 302: #endif ! 303: /* FALLTHROUGH */ ! 304: ! 305: case SIOCGIFADDR: ! 306: case SIOCGIFNETMASK: ! 307: case SIOCGIFDSTADDR: ! 308: case SIOCGIFBRDADDR: ! 309: if (ia == (struct in_ifaddr *)0) ! 310: return (EADDRNOTAVAIL); ! 311: break; ! 312: } ! 313: switch (cmd) { ! 314: ! 315: case SIOCGIFADDR: ! 316: *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; ! 317: break; ! 318: ! 319: case SIOCGIFBRDADDR: ! 320: if ((ifp->if_flags & IFF_BROADCAST) == 0) ! 321: return (EINVAL); ! 322: *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; ! 323: break; ! 324: ! 325: case SIOCGIFDSTADDR: ! 326: if ((ifp->if_flags & IFF_POINTOPOINT) == 0) ! 327: return (EINVAL); ! 328: *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; ! 329: break; ! 330: ! 331: case SIOCGIFNETMASK: ! 332: *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; ! 333: break; ! 334: ! 335: case SIOCSIFDSTADDR: ! 336: if ((ifp->if_flags & IFF_POINTOPOINT) == 0) ! 337: return (EINVAL); ! 338: oldaddr = ia->ia_dstaddr; ! 339: ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; ! 340: if (ifp->if_ioctl && ! 341: (error = dlil_ioctl(0, ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { ! 342: ia->ia_dstaddr = oldaddr; ! 343: return (error); ! 344: } ! 345: if (ia->ia_flags & IFA_ROUTE) { ! 346: ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; ! 347: rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); ! 348: ia->ia_ifa.ifa_dstaddr = ! 349: (struct sockaddr *)&ia->ia_dstaddr; ! 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: } ! 398: if ((ifp->if_flags & IFF_BROADCAST) && ! 399: (ifra->ifra_broadaddr.sin_family == AF_INET)) ! 400: ia->ia_broadaddr = ifra->ifra_broadaddr; ! 401: return (error); ! 402: ! 403: case SIOCDIFADDR: ! 404: in_ifscrub(ifp, ia); ! 405: /* ! 406: * Protect from ipintr() traversing address list ! 407: * while we're modifying it. ! 408: */ ! 409: s = splnet(); ! 410: ! 411: ifa = &ia->ia_ifa; ! 412: TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); ! 413: oia = ia; ! 414: TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link); ! 415: IFAFREE(&oia->ia_ifa); ! 416: splx(s); ! 417: break; ! 418: ! 419: case SIOCSETOT: { ! 420: /* ! 421: * Inspiration from tcp_ctloutput() and ip_ctloutput() ! 422: */ ! 423: struct inpcb *inp, *cloned_inp; ! 424: int error = 0; ! 425: int cloned_fd = *(int *)data; ! 426: ! 427: s = splnet(); /* XXX */ ! 428: inp = sotoinpcb(so); ! 429: if (inp == NULL) { ! 430: splx(s); ! 431: break; ! 432: } ! 433: ! 434: /* let's make sure it's either -1 or a valid file descriptor */ ! 435: if (cloned_fd != -1) { ! 436: struct socket *cloned_so; ! 437: struct file *cloned_fp; ! 438: error = getsock(p->p_fd, cloned_fd, &cloned_fp); ! 439: if (error){ ! 440: splx(s); ! 441: break; ! 442: } ! 443: cloned_so = (struct socket *)cloned_fp->f_data; ! 444: cloned_inp = sotoinpcb(cloned_so); ! 445: } else { ! 446: cloned_inp = NULL; ! 447: } ! 448: ! 449: if (cloned_inp == NULL) { ! 450: /* OT always uses IP_PORTRANGE_HIGH */ ! 451: inp->inp_flags &= ~(INP_LOWPORT); ! 452: inp->inp_flags |= INP_HIGHPORT; ! 453: } else { ! 454: inp->inp_ip_tos = cloned_inp->inp_ip_tos; ! 455: inp->inp_ip_ttl = cloned_inp->inp_ip_ttl; ! 456: inp->inp_flags = cloned_inp->inp_flags; ! 457: ! 458: /* Multicast options */ ! 459: if (cloned_inp->inp_moptions != NULL) { ! 460: int i; ! 461: struct ip_moptions *cloned_imo = cloned_inp->inp_moptions; ! 462: struct ip_moptions *imo = inp->inp_moptions; ! 463: ! 464: if (imo == NULL) { ! 465: /* ! 466: * No multicast option buffer attached to the pcb; ! 467: * allocate one. ! 468: */ ! 469: splx(); ! 470: imo = (struct ip_moptions*) ! 471: _MALLOC(sizeof(*imo), M_IPMOPTS, M_WAITOK); ! 472: if (imo == NULL) { ! 473: error = ENOBUFS; ! 474: break; ! 475: } ! 476: s = splnet(); /* XXX */ ! 477: inp->inp_moptions = imo; ! 478: } ! 479: imo->imo_multicast_ifp = cloned_imo->imo_multicast_ifp; ! 480: imo->imo_multicast_vif = cloned_imo->imo_multicast_vif; ! 481: imo->imo_multicast_ttl = cloned_imo->imo_multicast_ttl; ! 482: imo->imo_multicast_loop = cloned_imo->imo_multicast_loop; ! 483: imo->imo_num_memberships = cloned_imo->imo_num_memberships; ! 484: for (i = 0; i < cloned_imo->imo_num_memberships; i++) { ! 485: imo->imo_membership[i] = ! 486: in_addmulti(&cloned_imo->imo_membership[i]->inm_addr, ! 487: cloned_imo->imo_membership[i]->inm_ifp); ! 488: } ! 489: } ! 490: } ! 491: splx(s); ! 492: break; ! 493: } ! 494: ! 495: default: ! 496: if (ifp == 0 || ifp->if_ioctl == 0) ! 497: return (EOPNOTSUPP); ! 498: return dlil_ioctl(0, ifp, cmd, (caddr_t) data); ! 499: } ! 500: return (0); ! 501: } ! 502: ! 503: /* ! 504: * Delete any existing route for an interface. ! 505: */ ! 506: void ! 507: in_ifscrub(ifp, ia) ! 508: register struct ifnet *ifp; ! 509: register struct in_ifaddr *ia; ! 510: { ! 511: ! 512: if ((ia->ia_flags & IFA_ROUTE) == 0) ! 513: return; ! 514: if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) ! 515: rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); ! 516: else ! 517: rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); ! 518: ia->ia_flags &= ~IFA_ROUTE; ! 519: } ! 520: ! 521: /* ! 522: * Initialize an interface's internet address ! 523: * and routing table entry. ! 524: */ ! 525: static int ! 526: in_ifinit(ifp, ia, sin, scrub) ! 527: register struct ifnet *ifp; ! 528: register struct in_ifaddr *ia; ! 529: struct sockaddr_in *sin; ! 530: int scrub; ! 531: { ! 532: register u_long i = ntohl(sin->sin_addr.s_addr); ! 533: struct sockaddr_in oldaddr; ! 534: int s = splimp(), flags = RTF_UP, error; ! 535: u_long dl_tag; ! 536: ! 537: ! 538: ! 539: oldaddr = ia->ia_addr; ! 540: ia->ia_addr = *sin; ! 541: /* ! 542: * Give the interface a chance to initialize ! 543: * if this is its first address, ! 544: * and to validate the address if necessary. ! 545: */ ! 546: if (ifp->if_ioctl && ! 547: (error = dlil_ioctl(0, ifp, SIOCSIFADDR, (caddr_t)ia))) { ! 548: splx(s); ! 549: ia->ia_addr = oldaddr; ! 550: return (error); ! 551: } ! 552: ! 553: dlil_ioctl(ia->ia_ifa.ifa_dlt, 0, SIOCSIFADDR, (caddr_t) ia); ! 554: ! 555: splx(s); ! 556: if (scrub) { ! 557: ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; ! 558: in_ifscrub(ifp, ia); ! 559: ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; ! 560: } ! 561: if (IN_CLASSA(i)) ! 562: ia->ia_netmask = IN_CLASSA_NET; ! 563: else if (IN_CLASSB(i)) ! 564: ia->ia_netmask = IN_CLASSB_NET; ! 565: else ! 566: ia->ia_netmask = IN_CLASSC_NET; ! 567: /* ! 568: * The subnet mask usually includes at least the standard network part, ! 569: * but may may be smaller in the case of supernetting. ! 570: * If it is set, we believe it. ! 571: */ ! 572: if (ia->ia_subnetmask == 0) { ! 573: ia->ia_subnetmask = ia->ia_netmask; ! 574: ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); ! 575: } else ! 576: ia->ia_netmask &= ia->ia_subnetmask; ! 577: ia->ia_net = i & ia->ia_netmask; ! 578: ia->ia_subnet = i & ia->ia_subnetmask; ! 579: in_socktrim(&ia->ia_sockmask); ! 580: /* ! 581: * Add route for the network. ! 582: */ ! 583: ia->ia_ifa.ifa_metric = ifp->if_metric; ! 584: if (ifp->if_flags & IFF_BROADCAST) { ! 585: ia->ia_broadaddr.sin_addr.s_addr = ! 586: htonl(ia->ia_subnet | ~ia->ia_subnetmask); ! 587: ia->ia_netbroadcast.s_addr = ! 588: htonl(ia->ia_net | ~ ia->ia_netmask); ! 589: } else if (ifp->if_flags & IFF_LOOPBACK) { ! 590: ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; ! 591: flags |= RTF_HOST; ! 592: } else if (ifp->if_flags & IFF_POINTOPOINT) { ! 593: if (ia->ia_dstaddr.sin_family != AF_INET) ! 594: return (0); ! 595: flags |= RTF_HOST; ! 596: } ! 597: if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) ! 598: ia->ia_flags |= IFA_ROUTE; ! 599: ! 600: /* ! 601: * If the interface supports multicast, join the "all hosts" ! 602: * multicast group on that interface. ! 603: */ ! 604: if (ifp->if_flags & IFF_MULTICAST) { ! 605: struct in_addr addr; ! 606: ! 607: addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); ! 608: in_addmulti(&addr, ifp); ! 609: } ! 610: return (error); ! 611: } ! 612: ! 613: ! 614: /* ! 615: * Return 1 if the address might be a local broadcast address. ! 616: */ ! 617: int ! 618: in_broadcast(in, ifp) ! 619: struct in_addr in; ! 620: struct ifnet *ifp; ! 621: { ! 622: register struct ifaddr *ifa; ! 623: u_long t; ! 624: ! 625: if (in.s_addr == INADDR_BROADCAST || ! 626: in.s_addr == INADDR_ANY) ! 627: return 1; ! 628: if ((ifp->if_flags & IFF_BROADCAST) == 0) ! 629: return 0; ! 630: t = ntohl(in.s_addr); ! 631: /* ! 632: * Look through the list of addresses for a match ! 633: * with a broadcast address. ! 634: */ ! 635: #define ia ((struct in_ifaddr *)ifa) ! 636: for (ifa = ifp->if_addrhead.tqh_first; ifa; ! 637: ifa = ifa->ifa_link.tqe_next) ! 638: if (ifa->ifa_addr->sa_family == AF_INET && ! 639: (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || ! 640: in.s_addr == ia->ia_netbroadcast.s_addr || ! 641: /* ! 642: * Check for old-style (host 0) broadcast. ! 643: */ ! 644: t == ia->ia_subnet || t == ia->ia_net) && ! 645: /* ! 646: * Check for an all one subnetmask. These ! 647: * only exist when an interface gets a secondary ! 648: * address. ! 649: */ ! 650: ia->ia_subnetmask != (u_long)0xffffffff) ! 651: return 1; ! 652: return (0); ! 653: #undef ia ! 654: } ! 655: /* ! 656: * Add an address to the list of IP multicast addresses for a given interface. ! 657: */ ! 658: struct in_multi * ! 659: in_addmulti(ap, ifp) ! 660: register struct in_addr *ap; ! 661: register struct ifnet *ifp; ! 662: { ! 663: register struct in_multi *inm; ! 664: int error; ! 665: struct sockaddr_in sin; ! 666: struct ifmultiaddr *ifma; ! 667: int s = splnet(); ! 668: ! 669: /* ! 670: * Call generic routine to add membership or increment ! 671: * refcount. It wants addresses in the form of a sockaddr, ! 672: * so we build one here (being careful to zero the unused bytes). ! 673: */ ! 674: bzero(&sin, sizeof sin); ! 675: sin.sin_family = AF_INET; ! 676: sin.sin_len = sizeof sin; ! 677: sin.sin_addr = *ap; ! 678: error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma); ! 679: if (error) { ! 680: splx(s); ! 681: return 0; ! 682: } ! 683: ! 684: /* ! 685: * If ifma->ifma_protospec is null, then if_addmulti() created ! 686: * a new record. Otherwise, we are done. ! 687: */ ! 688: if (ifma->ifma_protospec != 0) ! 689: return ifma->ifma_protospec; ! 690: ! 691: /* XXX - if_addmulti uses M_WAITOK. Can this really be called ! 692: at interrupt time? If so, need to fix if_addmulti. XXX */ ! 693: inm = (struct in_multi *) _MALLOC(sizeof(*inm), M_IPMADDR, M_NOWAIT); ! 694: if (inm == NULL) { ! 695: splx(s); ! 696: return (NULL); ! 697: } ! 698: ! 699: bzero(inm, sizeof *inm); ! 700: inm->inm_addr = *ap; ! 701: inm->inm_ifp = ifp; ! 702: inm->inm_ifma = ifma; ! 703: ifma->ifma_protospec = inm; ! 704: LIST_INSERT_HEAD(&in_multihead, inm, inm_link); ! 705: ! 706: /* ! 707: * Let IGMP know that we have joined a new IP multicast group. ! 708: */ ! 709: igmp_joingroup(inm); ! 710: splx(s); ! 711: return (inm); ! 712: } ! 713: ! 714: /* ! 715: * Delete a multicast address record. ! 716: */ ! 717: void ! 718: in_delmulti(inm) ! 719: register struct in_multi *inm; ! 720: { ! 721: struct ifmultiaddr *ifma = inm->inm_ifma; ! 722: int s = splnet(); ! 723: ! 724: if (ifma->ifma_refcount == 1) { ! 725: /* ! 726: * No remaining claims to this record; let IGMP know that ! 727: * we are leaving the multicast group. ! 728: */ ! 729: igmp_leavegroup(inm); ! 730: ifma->ifma_protospec = 0; ! 731: LIST_REMOVE(inm, inm_link); ! 732: FREE(inm, M_IPMADDR); ! 733: } ! 734: /* XXX - should be separate API for when we have an ifma? */ ! 735: if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); ! 736: splx(s); ! 737: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.