123175Smckusick /* 248464Skarels * Copyright (c) 1982, 1986, 1991 Regents of the University of California. 332787Sbostic * All rights reserved. 423175Smckusick * 544472Sbostic * %sccs.include.redist.c% 632787Sbostic * 7*61335Sbostic * @(#)in.c 7.33 (Berkeley) 06/04/93 823175Smckusick */ 97159Ssam 1056531Sbostic #include <sys/param.h> 1156531Sbostic #include <sys/ioctl.h> 1256531Sbostic #include <sys/errno.h> 1356531Sbostic #include <sys/malloc.h> 1456531Sbostic #include <sys/socket.h> 1556531Sbostic #include <sys/socketvar.h> 167159Ssam 1756531Sbostic #include <net/if.h> 1856531Sbostic #include <net/route.h> 1956531Sbostic #include <net/af.h> 2056531Sbostic 2156531Sbostic #include <netinet/in_systm.h> 2256531Sbostic #include <netinet/in.h> 2356531Sbostic #include <netinet/in_var.h> 24*61335Sbostic #include <netinet/if_ether.h> 2556531Sbostic 267159Ssam #ifdef INET 277159Ssam /* 288595Sroot * Return the network number from an internet address. 297159Ssam */ 3024805Skarels u_long 317159Ssam in_netof(in) 327159Ssam struct in_addr in; 337159Ssam { 348937Sroot register u_long i = ntohl(in.s_addr); 3518377Skarels register u_long net; 3618377Skarels register struct in_ifaddr *ia; 377159Ssam 3818377Skarels if (IN_CLASSA(i)) 3918377Skarels net = i & IN_CLASSA_NET; 4018377Skarels else if (IN_CLASSB(i)) 4118377Skarels net = i & IN_CLASSB_NET; 4231392Skarels else if (IN_CLASSC(i)) 4331392Skarels net = i & IN_CLASSC_NET; 4454716Ssklower else if (IN_CLASSD(i)) 4554716Ssklower net = i & IN_CLASSD_NET; 4618377Skarels else 4731392Skarels return (0); 4816413Skarels 4916413Skarels /* 5018377Skarels * Check whether network is a subnet; 5116413Skarels * if so, return subnet number. 5216413Skarels */ 5318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 5424805Skarels if (net == ia->ia_net) 5518377Skarels return (i & ia->ia_subnetmask); 5616413Skarels return (net); 577159Ssam } 587159Ssam 5926381Skarels #ifndef SUBNETSARELOCAL 6026381Skarels #define SUBNETSARELOCAL 1 6126381Skarels #endif 6226381Skarels int subnetsarelocal = SUBNETSARELOCAL; 6316377Skarels /* 6418377Skarels * Return 1 if an internet address is for a ``local'' host 6526381Skarels * (one to which we have a connection). If subnetsarelocal 6626381Skarels * is true, this includes other subnets of the local net. 6726381Skarels * Otherwise, it includes only the directly-connected (sub)nets. 6817271Skarels */ 6917271Skarels in_localaddr(in) 7017271Skarels struct in_addr in; 7117271Skarels { 7217271Skarels register u_long i = ntohl(in.s_addr); 7318377Skarels register struct in_ifaddr *ia; 7417271Skarels 7530697Skarels if (subnetsarelocal) { 7630697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 7730697Skarels if ((i & ia->ia_netmask) == ia->ia_net) 7830697Skarels return (1); 7930697Skarels } else { 8030697Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 8130697Skarels if ((i & ia->ia_subnetmask) == ia->ia_subnet) 8230697Skarels return (1); 8330697Skarels } 8418377Skarels return (0); 8518377Skarels } 8618377Skarels 8731392Skarels /* 8831392Skarels * Determine whether an IP address is in a reserved set of addresses 8931392Skarels * that may not be forwarded, or whether datagrams to that destination 9031392Skarels * may be forwarded. 9131392Skarels */ 9231392Skarels in_canforward(in) 9331392Skarels struct in_addr in; 9431392Skarels { 9531392Skarels register u_long i = ntohl(in.s_addr); 9631392Skarels register u_long net; 9731392Skarels 9858998Ssklower if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) 9931392Skarels return (0); 10031392Skarels if (IN_CLASSA(i)) { 10131392Skarels net = i & IN_CLASSA_NET; 10257938Ssklower if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) 10331392Skarels return (0); 10431392Skarels } 10531392Skarels return (1); 10631392Skarels } 10731392Skarels 10858998Ssklower /* 10958998Ssklower * Trim a mask in a sockaddr 11058998Ssklower */ 11158998Ssklower void 11258998Ssklower in_socktrim(ap) 11358998Ssklower struct sockaddr_in *ap; 11458998Ssklower { 11558998Ssklower register char *cplim = (char *) &ap->sin_addr; 11658998Ssklower register char *cp = (char *) (&ap->sin_addr + 1); 11758998Ssklower 11858998Ssklower ap->sin_len = 0; 11958998Ssklower while (--cp > cplim) 12058998Ssklower if (*cp) { 12158998Ssklower (ap)->sin_len = cp - (char *) (ap) + 1; 12258998Ssklower break; 12358998Ssklower } 12458998Ssklower } 12558998Ssklower 12624805Skarels int in_interfaces; /* number of external internet interfaces */ 12724805Skarels extern struct ifnet loif; 12824805Skarels 12918377Skarels /* 13018377Skarels * Generic internet control operations (ioctl's). 13118377Skarels * Ifp is 0 if not an interface-specific ioctl. 13218377Skarels */ 13324805Skarels /* ARGSUSED */ 13418377Skarels in_control(so, cmd, data, ifp) 13518377Skarels struct socket *so; 13618377Skarels int cmd; 13718377Skarels caddr_t data; 13818377Skarels register struct ifnet *ifp; 13918377Skarels { 14018377Skarels register struct ifreq *ifr = (struct ifreq *)data; 14118377Skarels register struct in_ifaddr *ia = 0; 14237471Ssklower register struct ifaddr *ifa; 14337471Ssklower struct in_ifaddr *oia; 14437471Ssklower struct in_aliasreq *ifra = (struct in_aliasreq *)data; 14537471Ssklower struct sockaddr_in oldaddr; 14637471Ssklower int error, hostIsNew, maskIsNew; 14737471Ssklower u_long i; 14818377Skarels 14918377Skarels /* 15018377Skarels * Find address for this interface, if it exists. 15118377Skarels */ 15218377Skarels if (ifp) 15318377Skarels for (ia = in_ifaddr; ia; ia = ia->ia_next) 15418377Skarels if (ia->ia_ifp == ifp) 15518377Skarels break; 15618377Skarels 15718377Skarels switch (cmd) { 15818377Skarels 15937471Ssklower case SIOCAIFADDR: 16037471Ssklower case SIOCDIFADDR: 16137471Ssklower if (ifra->ifra_addr.sin_family == AF_INET) 16237471Ssklower for (oia = ia; ia; ia = ia->ia_next) { 16337471Ssklower if (ia->ia_ifp == ifp && 16437471Ssklower ia->ia_addr.sin_addr.s_addr == 16537471Ssklower ifra->ifra_addr.sin_addr.s_addr) 16637471Ssklower break; 16737471Ssklower } 16837471Ssklower if (cmd == SIOCDIFADDR && ia == 0) 16937471Ssklower return (EADDRNOTAVAIL); 17037471Ssklower /* FALLTHROUGH */ 17118377Skarels case SIOCSIFADDR: 17218377Skarels case SIOCSIFNETMASK: 17326456Skarels case SIOCSIFDSTADDR: 17448464Skarels if ((so->so_state & SS_PRIV) == 0) 17548464Skarels return (EPERM); 17618377Skarels 17718377Skarels if (ifp == 0) 17818377Skarels panic("in_control"); 17918377Skarels if (ia == (struct in_ifaddr *)0) { 18052028Ssklower oia = (struct in_ifaddr *) 18152028Ssklower malloc(sizeof *oia, M_IFADDR, M_WAITOK); 18252028Ssklower if (oia == (struct in_ifaddr *)NULL) 18318377Skarels return (ENOBUFS); 18452028Ssklower bzero((caddr_t)oia, sizeof *oia); 18518377Skarels if (ia = in_ifaddr) { 18618377Skarels for ( ; ia->ia_next; ia = ia->ia_next) 18752915Storek continue; 18852028Ssklower ia->ia_next = oia; 18918377Skarels } else 19052028Ssklower in_ifaddr = oia; 19152028Ssklower ia = oia; 19218377Skarels if (ifa = ifp->if_addrlist) { 19318377Skarels for ( ; ifa->ifa_next; ifa = ifa->ifa_next) 19452915Storek continue; 19518377Skarels ifa->ifa_next = (struct ifaddr *) ia; 19618377Skarels } else 19718377Skarels ifp->if_addrlist = (struct ifaddr *) ia; 19837471Ssklower ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 19937471Ssklower ia->ia_ifa.ifa_dstaddr 20037471Ssklower = (struct sockaddr *)&ia->ia_dstaddr; 20137471Ssklower ia->ia_ifa.ifa_netmask 20237471Ssklower = (struct sockaddr *)&ia->ia_sockmask; 20337471Ssklower ia->ia_sockmask.sin_len = 8; 20437471Ssklower if (ifp->if_flags & IFF_BROADCAST) { 20537471Ssklower ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); 20637471Ssklower ia->ia_broadaddr.sin_family = AF_INET; 20737471Ssklower } 20818377Skarels ia->ia_ifp = ifp; 20924805Skarels if (ifp != &loif) 21024805Skarels in_interfaces++; 21117271Skarels } 21218377Skarels break; 21326317Skarels 21426317Skarels case SIOCSIFBRDADDR: 21548464Skarels if ((so->so_state & SS_PRIV) == 0) 21648464Skarels return (EPERM); 21726317Skarels /* FALLTHROUGH */ 21826317Skarels 21939183Ssklower case SIOCGIFADDR: 22039183Ssklower case SIOCGIFNETMASK: 22139183Ssklower case SIOCGIFDSTADDR: 22239183Ssklower case SIOCGIFBRDADDR: 22326317Skarels if (ia == (struct in_ifaddr *)0) 22426317Skarels return (EADDRNOTAVAIL); 22526317Skarels break; 22617271Skarels } 22718377Skarels switch (cmd) { 22818377Skarels 22918377Skarels case SIOCGIFADDR: 23037471Ssklower *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; 23118377Skarels break; 23218377Skarels 23318377Skarels case SIOCGIFBRDADDR: 23418377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 23518377Skarels return (EINVAL); 23637471Ssklower *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; 23718377Skarels break; 23818377Skarels 23918377Skarels case SIOCGIFDSTADDR: 24018377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 24118377Skarels return (EINVAL); 24237471Ssklower *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; 24318377Skarels break; 24418377Skarels 24518377Skarels case SIOCGIFNETMASK: 24637471Ssklower *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; 24718377Skarels break; 24818377Skarels 24918377Skarels case SIOCSIFDSTADDR: 25018377Skarels if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 25118377Skarels return (EINVAL); 25227066Skarels oldaddr = ia->ia_dstaddr; 25337471Ssklower ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; 25452619Ssklower if (ifp->if_ioctl && (error = (*ifp->if_ioctl) 25552619Ssklower (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { 25627066Skarels ia->ia_dstaddr = oldaddr; 25718377Skarels return (error); 25827066Skarels } 25927066Skarels if (ia->ia_flags & IFA_ROUTE) { 26037471Ssklower ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; 26137471Ssklower rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 26245454Ssklower ia->ia_ifa.ifa_dstaddr = 26345454Ssklower (struct sockaddr *)&ia->ia_dstaddr; 26437471Ssklower rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 26527066Skarels } 26618377Skarels break; 26718377Skarels 26818377Skarels case SIOCSIFBRDADDR: 26918377Skarels if ((ifp->if_flags & IFF_BROADCAST) == 0) 27018377Skarels return (EINVAL); 27137471Ssklower ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr; 27218377Skarels break; 27318377Skarels 27418377Skarels case SIOCSIFADDR: 27534500Skarels return (in_ifinit(ifp, ia, 27637471Ssklower (struct sockaddr_in *) &ifr->ifr_addr, 1)); 27718377Skarels 27818377Skarels case SIOCSIFNETMASK: 27937471Ssklower i = ifra->ifra_addr.sin_addr.s_addr; 28037471Ssklower ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i); 28118377Skarels break; 28218377Skarels 28337471Ssklower case SIOCAIFADDR: 28444368Skarels maskIsNew = 0; 28544368Skarels hostIsNew = 1; 28644368Skarels error = 0; 28737471Ssklower if (ia->ia_addr.sin_family == AF_INET) { 28837471Ssklower if (ifra->ifra_addr.sin_len == 0) { 28937471Ssklower ifra->ifra_addr = ia->ia_addr; 29037471Ssklower hostIsNew = 0; 29137471Ssklower } else if (ifra->ifra_addr.sin_addr.s_addr == 29237471Ssklower ia->ia_addr.sin_addr.s_addr) 29337471Ssklower hostIsNew = 0; 29437471Ssklower } 29537471Ssklower if (ifra->ifra_mask.sin_len) { 29637471Ssklower in_ifscrub(ifp, ia); 29737471Ssklower ia->ia_sockmask = ifra->ifra_mask; 29837471Ssklower ia->ia_subnetmask = 29944368Skarels ntohl(ia->ia_sockmask.sin_addr.s_addr); 30037471Ssklower maskIsNew = 1; 30137471Ssklower } 30237471Ssklower if ((ifp->if_flags & IFF_POINTOPOINT) && 30337471Ssklower (ifra->ifra_dstaddr.sin_family == AF_INET)) { 30437471Ssklower in_ifscrub(ifp, ia); 30537471Ssklower ia->ia_dstaddr = ifra->ifra_dstaddr; 30637471Ssklower maskIsNew = 1; /* We lie; but the effect's the same */ 30737471Ssklower } 30837471Ssklower if (ifra->ifra_addr.sin_family == AF_INET && 30944368Skarels (hostIsNew || maskIsNew)) 31037471Ssklower error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); 31137471Ssklower if ((ifp->if_flags & IFF_BROADCAST) && 31237471Ssklower (ifra->ifra_broadaddr.sin_family == AF_INET)) 31337471Ssklower ia->ia_broadaddr = ifra->ifra_broadaddr; 31437471Ssklower return (error); 31537471Ssklower 31637471Ssklower case SIOCDIFADDR: 31737471Ssklower in_ifscrub(ifp, ia); 31837471Ssklower if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia) 31937471Ssklower ifp->if_addrlist = ifa->ifa_next; 32037471Ssklower else { 32137471Ssklower while (ifa->ifa_next && 32237471Ssklower (ifa->ifa_next != (struct ifaddr *)ia)) 32337471Ssklower ifa = ifa->ifa_next; 32437471Ssklower if (ifa->ifa_next) 32544368Skarels ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next; 32637471Ssklower else 32737471Ssklower printf("Couldn't unlink inifaddr from ifp\n"); 32837471Ssklower } 32937471Ssklower oia = ia; 33044368Skarels if (oia == (ia = in_ifaddr)) 33137471Ssklower in_ifaddr = ia->ia_next; 33244368Skarels else { 33344368Skarels while (ia->ia_next && (ia->ia_next != oia)) 33437471Ssklower ia = ia->ia_next; 33537471Ssklower if (ia->ia_next) 33644368Skarels ia->ia_next = oia->ia_next; 33737471Ssklower else 33837471Ssklower printf("Didn't unlink inifadr from list\n"); 33937471Ssklower } 34052028Ssklower IFAFREE((&oia->ia_ifa)); 34137471Ssklower break; 34237471Ssklower 34318377Skarels default: 34418377Skarels if (ifp == 0 || ifp->if_ioctl == 0) 34518377Skarels return (EOPNOTSUPP); 34618377Skarels return ((*ifp->if_ioctl)(ifp, cmd, data)); 34718377Skarels } 34817271Skarels return (0); 34917271Skarels } 35017271Skarels 35117271Skarels /* 35237471Ssklower * Delete any existing route for an interface. 35337471Ssklower */ 354*61335Sbostic void 35537471Ssklower in_ifscrub(ifp, ia) 35637471Ssklower register struct ifnet *ifp; 35737471Ssklower register struct in_ifaddr *ia; 35837471Ssklower { 35937471Ssklower 36037471Ssklower if ((ia->ia_flags & IFA_ROUTE) == 0) 36137471Ssklower return; 36237471Ssklower if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) 36337471Ssklower rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 36437471Ssklower else 36537471Ssklower rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 36637471Ssklower ia->ia_flags &= ~IFA_ROUTE; 36737471Ssklower } 36837471Ssklower 36937471Ssklower /* 37018377Skarels * Initialize an interface's internet address 37118377Skarels * and routing table entry. 3727159Ssam */ 37337471Ssklower in_ifinit(ifp, ia, sin, scrub) 3747159Ssam register struct ifnet *ifp; 37518377Skarels register struct in_ifaddr *ia; 37618377Skarels struct sockaddr_in *sin; 37752274Storek int scrub; 3787159Ssam { 37918377Skarels register u_long i = ntohl(sin->sin_addr.s_addr); 38037471Ssklower struct sockaddr_in oldaddr; 38154716Ssklower int s = splimp(), flags = RTF_UP, error, ether_output(); 3827159Ssam 38327066Skarels oldaddr = ia->ia_addr; 38437471Ssklower ia->ia_addr = *sin; 38518377Skarels /* 38626317Skarels * Give the interface a chance to initialize 38726317Skarels * if this is its first address, 38826317Skarels * and to validate the address if necessary. 38926317Skarels */ 39052274Storek if (ifp->if_ioctl && 39152274Storek (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { 39226317Skarels splx(s); 39327066Skarels ia->ia_addr = oldaddr; 39426317Skarels return (error); 39526317Skarels } 39650134Ssklower if (ifp->if_output == ether_output) { /* XXX: Another Kludge */ 39750134Ssklower ia->ia_ifa.ifa_rtrequest = arp_rtrequest; 39850134Ssklower ia->ia_ifa.ifa_flags |= RTF_CLONING; 39950134Ssklower } 40045454Ssklower splx(s); 40137471Ssklower if (scrub) { 40237471Ssklower ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 40337471Ssklower in_ifscrub(ifp, ia); 40437471Ssklower ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 40518377Skarels } 40618377Skarels if (IN_CLASSA(i)) 40718377Skarels ia->ia_netmask = IN_CLASSA_NET; 40818377Skarels else if (IN_CLASSB(i)) 40918377Skarels ia->ia_netmask = IN_CLASSB_NET; 41018377Skarels else 41118377Skarels ia->ia_netmask = IN_CLASSC_NET; 41218377Skarels ia->ia_net = i & ia->ia_netmask; 41318377Skarels /* 41418377Skarels * The subnet mask includes at least the standard network part, 41518377Skarels * but may already have been set to a larger value. 41618377Skarels */ 41718377Skarels ia->ia_subnetmask |= ia->ia_netmask; 41818377Skarels ia->ia_subnet = i & ia->ia_subnetmask; 41937471Ssklower ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); 42058998Ssklower in_socktrim(&ia->ia_sockmask); 42145454Ssklower /* 42245454Ssklower * Add route for the network. 42345454Ssklower */ 42452617Ssklower ia->ia_ifa.ifa_metric = ifp->if_metric; 42518377Skarels if (ifp->if_flags & IFF_BROADCAST) { 42658998Ssklower ia->ia_broadaddr.sin_addr.s_addr = 42758998Ssklower htonl(ia->ia_subnet | ~ia->ia_subnetmask); 42825195Skarels ia->ia_netbroadcast.s_addr = 42958998Ssklower htonl(ia->ia_net | ~ ia->ia_netmask); 43045454Ssklower } else if (ifp->if_flags & IFF_LOOPBACK) { 43137471Ssklower ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; 43245454Ssklower flags |= RTF_HOST; 43345454Ssklower } else if (ifp->if_flags & IFF_POINTOPOINT) { 43445454Ssklower if (ia->ia_dstaddr.sin_family != AF_INET) 43545454Ssklower return (0); 43645454Ssklower flags |= RTF_HOST; 43727066Skarels } 43845454Ssklower if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) 43945454Ssklower ia->ia_flags |= IFA_ROUTE; 44054716Ssklower /* 44154716Ssklower * If the interface supports multicast, join the "all hosts" 44254716Ssklower * multicast group on that interface. 44354716Ssklower */ 44454716Ssklower if (ifp->if_flags & IFF_MULTICAST) { 44554716Ssklower struct in_addr addr; 44654716Ssklower 44754716Ssklower addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 44854716Ssklower in_addmulti(&addr, ifp); 44954716Ssklower } 45045454Ssklower return (error); 4517159Ssam } 45218377Skarels 45318377Skarels 45418377Skarels /* 45530523Skarels * Return 1 if the address might be a local broadcast address. 45618377Skarels */ 45758998Ssklower in_broadcast(in, ifp) 45818377Skarels struct in_addr in; 45958998Ssklower struct ifnet *ifp; 46018377Skarels { 46158998Ssklower register struct ifaddr *ifa; 46230523Skarels u_long t; 46318377Skarels 46458998Ssklower if (in.s_addr == INADDR_BROADCAST || 46558998Ssklower in.s_addr == INADDR_ANY) 46658998Ssklower return 1; 46758998Ssklower if ((ifp->if_flags & IFF_BROADCAST) == 0) 46858998Ssklower return 0; 46958998Ssklower t = ntohl(in.s_addr); 47018377Skarels /* 47118377Skarels * Look through the list of addresses for a match 47218377Skarels * with a broadcast address. 47318377Skarels */ 47458998Ssklower #define ia ((struct in_ifaddr *)ifa) 47558998Ssklower for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next) 47658998Ssklower if (ifa->ifa_addr->sa_family == AF_INET && 47758998Ssklower (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || 47858998Ssklower in.s_addr == ia->ia_netbroadcast.s_addr || 47958998Ssklower /* 48058998Ssklower * Check for old-style (host 0) broadcast. 48158998Ssklower */ 48258998Ssklower t == ia->ia_subnet || t == ia->ia_net)) 48358998Ssklower return 1; 484*61335Sbostic return (0); 48558998Ssklower #undef ia 48618377Skarels } 48754716Ssklower /* 48854716Ssklower * Add an address to the list of IP multicast addresses for a given interface. 48954716Ssklower */ 49054716Ssklower struct in_multi * 49154716Ssklower in_addmulti(ap, ifp) 49254716Ssklower register struct in_addr *ap; 49354716Ssklower register struct ifnet *ifp; 49454716Ssklower { 49554716Ssklower register struct in_multi *inm; 49654716Ssklower struct ifreq ifr; 49754716Ssklower struct in_ifaddr *ia; 49854716Ssklower int s = splnet(); 49954716Ssklower 50054716Ssklower /* 50154716Ssklower * See if address already in list. 50254716Ssklower */ 50354716Ssklower IN_LOOKUP_MULTI(*ap, ifp, inm); 50454716Ssklower if (inm != NULL) { 50554716Ssklower /* 50654716Ssklower * Found it; just increment the reference count. 50754716Ssklower */ 50854716Ssklower ++inm->inm_refcount; 50954716Ssklower } 51054716Ssklower else { 51154716Ssklower /* 51254716Ssklower * New address; allocate a new multicast record 51354716Ssklower * and link it into the interface's multicast list. 51454716Ssklower */ 51554716Ssklower inm = (struct in_multi *)malloc(sizeof(*inm), 51654716Ssklower M_IPMADDR, M_NOWAIT); 51754716Ssklower if (inm == NULL) { 51854716Ssklower splx(s); 51954716Ssklower return (NULL); 52054716Ssklower } 52154716Ssklower inm->inm_addr = *ap; 52254716Ssklower inm->inm_ifp = ifp; 52354716Ssklower inm->inm_refcount = 1; 52454716Ssklower IFP_TO_IA(ifp, ia); 52554716Ssklower if (ia == NULL) { 52654716Ssklower free(inm, M_IPMADDR); 52754716Ssklower splx(s); 52854716Ssklower return (NULL); 52954716Ssklower } 53054716Ssklower inm->inm_ia = ia; 53158413Ssklower inm->inm_next = ia->ia_multiaddrs; 53258413Ssklower ia->ia_multiaddrs = inm; 53354716Ssklower /* 53454716Ssklower * Ask the network driver to update its multicast reception 53554716Ssklower * filter appropriately for the new address. 53654716Ssklower */ 53754716Ssklower ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET; 53854716Ssklower ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap; 53958413Ssklower if ((ifp->if_ioctl == NULL) || 54058413Ssklower (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) { 54158413Ssklower ia->ia_multiaddrs = inm->inm_next; 54254716Ssklower free(inm, M_IPMADDR); 54354716Ssklower splx(s); 54454716Ssklower return (NULL); 54554716Ssklower } 54654716Ssklower /* 54754716Ssklower * Let IGMP know that we have joined a new IP multicast group. 54854716Ssklower */ 54954716Ssklower igmp_joingroup(inm); 55054716Ssklower } 55154716Ssklower splx(s); 55254716Ssklower return (inm); 55354716Ssklower } 55454716Ssklower 55554716Ssklower /* 55654716Ssklower * Delete a multicast address record. 55754716Ssklower */ 55854716Ssklower int 55954716Ssklower in_delmulti(inm) 56054716Ssklower register struct in_multi *inm; 56154716Ssklower { 56254716Ssklower register struct in_multi **p; 56354716Ssklower struct ifreq ifr; 56454716Ssklower int s = splnet(); 56554716Ssklower 56654716Ssklower if (--inm->inm_refcount == 0) { 56754716Ssklower /* 56854716Ssklower * No remaining claims to this record; let IGMP know that 56954716Ssklower * we are leaving the multicast group. 57054716Ssklower */ 57154716Ssklower igmp_leavegroup(inm); 57254716Ssklower /* 57354716Ssklower * Unlink from list. 57454716Ssklower */ 57554716Ssklower for (p = &inm->inm_ia->ia_multiaddrs; 57654716Ssklower *p != inm; 57754716Ssklower p = &(*p)->inm_next) 57854716Ssklower continue; 57954716Ssklower *p = (*p)->inm_next; 58054716Ssklower /* 58154716Ssklower * Notify the network driver to update its multicast reception 58254716Ssklower * filter. 58354716Ssklower */ 58454716Ssklower ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET; 58554716Ssklower ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr = 58654716Ssklower inm->inm_addr; 58754716Ssklower (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI, 58854716Ssklower (caddr_t)&ifr); 58954716Ssklower free(inm, M_IPMADDR); 59054716Ssklower } 59154716Ssklower splx(s); 59254716Ssklower } 5937159Ssam #endif 594