in.c revision 133874
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1982, 1986, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice, this list of conditions and the following disclaimer. 101541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111541Srgrimes * notice, this list of conditions and the following disclaimer in the 121541Srgrimes * documentation and/or other materials provided with the distribution. 131541Srgrimes * 4. Neither the name of the University nor the names of its contributors 141541Srgrimes * may be used to endorse or promote products derived from this software 151541Srgrimes * without specific prior written permission. 161541Srgrimes * 171541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271541Srgrimes * SUCH DAMAGE. 281541Srgrimes * 2910939Swollman * @(#)in.c 8.4 (Berkeley) 1/9/95 3050477Speter * $FreeBSD: head/sys/netinet/in.c 133874 2004-08-16 18:32:07Z rwatson $ 311541Srgrimes */ 321541Srgrimes 331541Srgrimes#include <sys/param.h> 341549Srgrimes#include <sys/systm.h> 3524204Sbde#include <sys/sockio.h> 361541Srgrimes#include <sys/malloc.h> 371541Srgrimes#include <sys/socket.h> 3812704Sphk#include <sys/kernel.h> 3912704Sphk#include <sys/sysctl.h> 401541Srgrimes 411541Srgrimes#include <net/if.h> 4255009Sshin#include <net/if_types.h> 431541Srgrimes#include <net/route.h> 441541Srgrimes 451541Srgrimes#include <netinet/in.h> 461541Srgrimes#include <netinet/in_var.h> 4781127Sume#include <netinet/in_pcb.h> 481541Srgrimes 496363Sphk#include <netinet/igmp_var.h> 506363Sphk 5130354Sphkstatic MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); 5230309Sphk 5392723Salfredstatic int in_mask2len(struct in_addr *); 5492723Salfredstatic void in_len2mask(struct in_addr *, int); 5592723Salfredstatic int in_lifaddr_ioctl(struct socket *, u_long, caddr_t, 5692723Salfred struct ifnet *, struct thread *); 5755009Sshin 5892723Salfredstatic void in_socktrim(struct sockaddr_in *); 5992723Salfredstatic int in_ifinit(struct ifnet *, 6092723Salfred struct in_ifaddr *, struct sockaddr_in *, int); 611541Srgrimes 6218193Swollmanstatic int subnetsarelocal = 0; 63133874SrwatsonSYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, 64123998Sru &subnetsarelocal, 0, "Treat all subnets as directly connected"); 6521666Swollman 6621666Swollmanstruct in_multihead in_multihead; /* XXX BSS initialization */ 6721666Swollman 6881127Sumeextern struct inpcbinfo ripcbinfo; 6981127Sumeextern struct inpcbinfo udbinfo; 7081127Sume 711541Srgrimes/* 721541Srgrimes * Return 1 if an internet address is for a ``local'' host 731541Srgrimes * (one to which we have a connection). If subnetsarelocal 741541Srgrimes * is true, this includes other subnets of the local net. 751541Srgrimes * Otherwise, it includes only the directly-connected (sub)nets. 761541Srgrimes */ 771549Srgrimesint 781541Srgrimesin_localaddr(in) 791541Srgrimes struct in_addr in; 801541Srgrimes{ 811541Srgrimes register u_long i = ntohl(in.s_addr); 821541Srgrimes register struct in_ifaddr *ia; 831541Srgrimes 841541Srgrimes if (subnetsarelocal) { 8574362Sphk TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 861541Srgrimes if ((i & ia->ia_netmask) == ia->ia_net) 871541Srgrimes return (1); 881541Srgrimes } else { 8972012Sphk TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 901541Srgrimes if ((i & ia->ia_subnetmask) == ia->ia_subnet) 911541Srgrimes return (1); 921541Srgrimes } 931541Srgrimes return (0); 941541Srgrimes} 951541Srgrimes 961541Srgrimes/* 97133486Sandre * Return 1 if an internet address is for the local host and configured 98133486Sandre * on one of its interfaces. 99133486Sandre */ 100133486Sandreint 101133486Sandrein_localip(in) 102133486Sandre struct in_addr in; 103133486Sandre{ 104133486Sandre struct in_ifaddr *ia; 105133486Sandre 106133486Sandre LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) { 107133486Sandre if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr) 108133486Sandre return 1; 109133486Sandre } 110133486Sandre return 0; 111133486Sandre} 112133486Sandre 113133486Sandre/* 1141541Srgrimes * Determine whether an IP address is in a reserved set of addresses 1151541Srgrimes * that may not be forwarded, or whether datagrams to that destination 1161541Srgrimes * may be forwarded. 1171541Srgrimes */ 1181549Srgrimesint 1191541Srgrimesin_canforward(in) 1201541Srgrimes struct in_addr in; 1211541Srgrimes{ 1221541Srgrimes register u_long i = ntohl(in.s_addr); 1231541Srgrimes register u_long net; 1241541Srgrimes 1251541Srgrimes if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) 1261541Srgrimes return (0); 1271541Srgrimes if (IN_CLASSA(i)) { 1281541Srgrimes net = i & IN_CLASSA_NET; 1291541Srgrimes if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) 1301541Srgrimes return (0); 1311541Srgrimes } 1321541Srgrimes return (1); 1331541Srgrimes} 1341541Srgrimes 1351541Srgrimes/* 1361541Srgrimes * Trim a mask in a sockaddr 1371541Srgrimes */ 13812296Sphkstatic void 1391541Srgrimesin_socktrim(ap) 1401541Srgrimesstruct sockaddr_in *ap; 1411541Srgrimes{ 1421541Srgrimes register char *cplim = (char *) &ap->sin_addr; 1431541Srgrimes register char *cp = (char *) (&ap->sin_addr + 1); 1441541Srgrimes 1451541Srgrimes ap->sin_len = 0; 1464127Swollman while (--cp >= cplim) 147133874Srwatson if (*cp) { 1481541Srgrimes (ap)->sin_len = cp - (char *) (ap) + 1; 1491541Srgrimes break; 1501541Srgrimes } 1511541Srgrimes} 1521541Srgrimes 15355009Sshinstatic int 15455009Sshinin_mask2len(mask) 15555009Sshin struct in_addr *mask; 15655009Sshin{ 15755009Sshin int x, y; 15855009Sshin u_char *p; 15955009Sshin 16055009Sshin p = (u_char *)mask; 16155009Sshin for (x = 0; x < sizeof(*mask); x++) { 16255009Sshin if (p[x] != 0xff) 16355009Sshin break; 16455009Sshin } 16555009Sshin y = 0; 16655009Sshin if (x < sizeof(*mask)) { 16755009Sshin for (y = 0; y < 8; y++) { 16855009Sshin if ((p[x] & (0x80 >> y)) == 0) 16955009Sshin break; 17055009Sshin } 17155009Sshin } 17255009Sshin return x * 8 + y; 17355009Sshin} 17455009Sshin 17555009Sshinstatic void 17655009Sshinin_len2mask(mask, len) 17755009Sshin struct in_addr *mask; 17855009Sshin int len; 17955009Sshin{ 18055009Sshin int i; 18155009Sshin u_char *p; 18255009Sshin 18355009Sshin p = (u_char *)mask; 18455009Sshin bzero(mask, sizeof(*mask)); 18555009Sshin for (i = 0; i < len / 8; i++) 18655009Sshin p[i] = 0xff; 18755009Sshin if (len % 8) 18855009Sshin p[i] = (0xff00 >> (len % 8)) & 0xff; 18955009Sshin} 19055009Sshin 1911541Srgrimes/* 1921541Srgrimes * Generic internet control operations (ioctl's). 1931541Srgrimes * Ifp is 0 if not an interface-specific ioctl. 1941541Srgrimes */ 1951541Srgrimes/* ARGSUSED */ 1961549Srgrimesint 19783366Sjulianin_control(so, cmd, data, ifp, td) 1981541Srgrimes struct socket *so; 19936735Sdfr u_long cmd; 2001541Srgrimes caddr_t data; 2011541Srgrimes register struct ifnet *ifp; 20283366Sjulian struct thread *td; 2031541Srgrimes{ 2041541Srgrimes register struct ifreq *ifr = (struct ifreq *)data; 20514632Sfenner register struct in_ifaddr *ia = 0, *iap; 2061541Srgrimes register struct ifaddr *ifa; 20784102Sjlemon struct in_addr dst; 2081541Srgrimes struct in_ifaddr *oia; 2091541Srgrimes struct in_aliasreq *ifra = (struct in_aliasreq *)data; 2101541Srgrimes struct sockaddr_in oldaddr; 21187124Sbrian int error, hostIsNew, iaIsNew, maskIsNew, s; 2121541Srgrimes 21387124Sbrian iaIsNew = 0; 21487124Sbrian 21555009Sshin switch (cmd) { 21655009Sshin case SIOCALIFADDR: 21755009Sshin case SIOCDLIFADDR: 21893593Sjhb if (td && (error = suser(td)) != 0) 21955009Sshin return error; 22055009Sshin /*fall through*/ 22155009Sshin case SIOCGLIFADDR: 22255009Sshin if (!ifp) 22355009Sshin return EINVAL; 22483366Sjulian return in_lifaddr_ioctl(so, cmd, data, ifp, td); 22555009Sshin } 22655009Sshin 2271541Srgrimes /* 2281541Srgrimes * Find address for this interface, if it exists. 22914632Sfenner * 23014632Sfenner * If an alias address was specified, find that one instead of 23184102Sjlemon * the first one on the interface, if possible. 2321541Srgrimes */ 23384102Sjlemon if (ifp) { 23484102Sjlemon dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; 23584102Sjlemon LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) 23684102Sjlemon if (iap->ia_ifp == ifp && 23784102Sjlemon iap->ia_addr.sin_addr.s_addr == dst.s_addr) { 23884102Sjlemon ia = iap; 23984102Sjlemon break; 24084102Sjlemon } 24184102Sjlemon if (ia == NULL) 24284102Sjlemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 24384102Sjlemon iap = ifatoia(ifa); 24484102Sjlemon if (iap->ia_addr.sin_family == AF_INET) { 24514632Sfenner ia = iap; 24614632Sfenner break; 24714632Sfenner } 24814632Sfenner } 24984102Sjlemon } 2501541Srgrimes 2511541Srgrimes switch (cmd) { 2521541Srgrimes 2531541Srgrimes case SIOCAIFADDR: 2541541Srgrimes case SIOCDIFADDR: 25541575Seivind if (ifp == 0) 25641575Seivind return (EADDRNOTAVAIL); 2578071Swollman if (ifra->ifra_addr.sin_family == AF_INET) { 25871999Sphk for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) { 2598071Swollman if (ia->ia_ifp == ifp && 2608071Swollman ia->ia_addr.sin_addr.s_addr == 2618071Swollman ifra->ifra_addr.sin_addr.s_addr) 2628071Swollman break; 2638071Swollman } 2648876Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) 2658071Swollman && (cmd == SIOCAIFADDR) 2668071Swollman && (ifra->ifra_dstaddr.sin_addr.s_addr 2678071Swollman == INADDR_ANY)) { 2689563Swollman return EDESTADDRREQ; 2698071Swollman } 2701541Srgrimes } 2711541Srgrimes if (cmd == SIOCDIFADDR && ia == 0) 2721541Srgrimes return (EADDRNOTAVAIL); 2731541Srgrimes /* FALLTHROUGH */ 2741541Srgrimes case SIOCSIFADDR: 2751541Srgrimes case SIOCSIFNETMASK: 2761541Srgrimes case SIOCSIFDSTADDR: 27793593Sjhb if (td && (error = suser(td)) != 0) 27825201Swollman return error; 2791541Srgrimes 2801541Srgrimes if (ifp == 0) 28141575Seivind return (EADDRNOTAVAIL); 2821541Srgrimes if (ia == (struct in_ifaddr *)0) { 28320407Swollman ia = (struct in_ifaddr *) 284111119Simp malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO); 28520407Swollman if (ia == (struct in_ifaddr *)NULL) 2861541Srgrimes return (ENOBUFS); 28715092Sdg /* 28815092Sdg * Protect from ipintr() traversing address list 28915092Sdg * while we're modifying it. 29015092Sdg */ 29115092Sdg s = splnet(); 29220407Swollman TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link); 293108033Shsu 29420407Swollman ifa = &ia->ia_ifa; 295108033Shsu IFA_LOCK_INIT(ifa); 29620407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 29720407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 29820407Swollman ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 299108033Shsu ifa->ifa_refcnt = 1; 300108033Shsu TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 301108033Shsu 3021541Srgrimes ia->ia_sockmask.sin_len = 8; 30385740Sdes ia->ia_sockmask.sin_family = AF_INET; 3041541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 3051541Srgrimes ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); 3061541Srgrimes ia->ia_broadaddr.sin_family = AF_INET; 3071541Srgrimes } 3081541Srgrimes ia->ia_ifp = ifp; 30915092Sdg splx(s); 31087124Sbrian iaIsNew = 1; 3111541Srgrimes } 3121541Srgrimes break; 3131541Srgrimes 3141541Srgrimes case SIOCSIFBRDADDR: 31593593Sjhb if (td && (error = suser(td)) != 0) 31625201Swollman return error; 3171541Srgrimes /* FALLTHROUGH */ 3181541Srgrimes 3191541Srgrimes case SIOCGIFADDR: 3201541Srgrimes case SIOCGIFNETMASK: 3211541Srgrimes case SIOCGIFDSTADDR: 3221541Srgrimes case SIOCGIFBRDADDR: 3231541Srgrimes if (ia == (struct in_ifaddr *)0) 3241541Srgrimes return (EADDRNOTAVAIL); 3251541Srgrimes break; 3261541Srgrimes } 3271541Srgrimes switch (cmd) { 3281541Srgrimes 3291541Srgrimes case SIOCGIFADDR: 3301541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; 33187124Sbrian return (0); 3321541Srgrimes 3331541Srgrimes case SIOCGIFBRDADDR: 3341541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 3351541Srgrimes return (EINVAL); 3361541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; 33787124Sbrian return (0); 3381541Srgrimes 3391541Srgrimes case SIOCGIFDSTADDR: 3401541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 3411541Srgrimes return (EINVAL); 3421541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; 34387124Sbrian return (0); 3441541Srgrimes 3451541Srgrimes case SIOCGIFNETMASK: 3461541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; 34787124Sbrian return (0); 3481541Srgrimes 3491541Srgrimes case SIOCSIFDSTADDR: 3501541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 3511541Srgrimes return (EINVAL); 3521541Srgrimes oldaddr = ia->ia_dstaddr; 3531541Srgrimes ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; 3541541Srgrimes if (ifp->if_ioctl && (error = (*ifp->if_ioctl) 3551541Srgrimes (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { 3561541Srgrimes ia->ia_dstaddr = oldaddr; 3571541Srgrimes return (error); 3581541Srgrimes } 3591541Srgrimes if (ia->ia_flags & IFA_ROUTE) { 3601541Srgrimes ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; 3611541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 3621541Srgrimes ia->ia_ifa.ifa_dstaddr = 3631541Srgrimes (struct sockaddr *)&ia->ia_dstaddr; 3641541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 3651541Srgrimes } 36687124Sbrian return (0); 3671541Srgrimes 3681541Srgrimes case SIOCSIFBRDADDR: 3691541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 3701541Srgrimes return (EINVAL); 3711541Srgrimes ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr; 37287124Sbrian return (0); 3731541Srgrimes 3741541Srgrimes case SIOCSIFADDR: 37587124Sbrian error = in_ifinit(ifp, ia, 37687124Sbrian (struct sockaddr_in *) &ifr->ifr_addr, 1); 37787124Sbrian if (error != 0 && iaIsNew) 37887124Sbrian break; 379126264Smlaier if (error == 0) 380126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 38187124Sbrian return (0); 3821541Srgrimes 3831541Srgrimes case SIOCSIFNETMASK: 38485740Sdes ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr; 38585740Sdes ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr); 38687124Sbrian return (0); 3871541Srgrimes 3881541Srgrimes case SIOCAIFADDR: 3891541Srgrimes maskIsNew = 0; 3901541Srgrimes hostIsNew = 1; 3911541Srgrimes error = 0; 3921541Srgrimes if (ia->ia_addr.sin_family == AF_INET) { 3931541Srgrimes if (ifra->ifra_addr.sin_len == 0) { 3941541Srgrimes ifra->ifra_addr = ia->ia_addr; 3951541Srgrimes hostIsNew = 0; 3961541Srgrimes } else if (ifra->ifra_addr.sin_addr.s_addr == 3971541Srgrimes ia->ia_addr.sin_addr.s_addr) 3981541Srgrimes hostIsNew = 0; 3991541Srgrimes } 4001541Srgrimes if (ifra->ifra_mask.sin_len) { 4011541Srgrimes in_ifscrub(ifp, ia); 4021541Srgrimes ia->ia_sockmask = ifra->ifra_mask; 40385740Sdes ia->ia_sockmask.sin_family = AF_INET; 4041541Srgrimes ia->ia_subnetmask = 4051541Srgrimes ntohl(ia->ia_sockmask.sin_addr.s_addr); 4061541Srgrimes maskIsNew = 1; 4071541Srgrimes } 4081541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) && 4091541Srgrimes (ifra->ifra_dstaddr.sin_family == AF_INET)) { 4101541Srgrimes in_ifscrub(ifp, ia); 4111541Srgrimes ia->ia_dstaddr = ifra->ifra_dstaddr; 4121541Srgrimes maskIsNew = 1; /* We lie; but the effect's the same */ 4131541Srgrimes } 4141541Srgrimes if (ifra->ifra_addr.sin_family == AF_INET && 4151541Srgrimes (hostIsNew || maskIsNew)) 4161541Srgrimes error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); 41787124Sbrian if (error != 0 && iaIsNew) 41887124Sbrian break; 41987124Sbrian 4201541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) && 4211541Srgrimes (ifra->ifra_broadaddr.sin_family == AF_INET)) 4221541Srgrimes ia->ia_broadaddr = ifra->ifra_broadaddr; 423126264Smlaier if (error == 0) 424126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 4251541Srgrimes return (error); 4261541Srgrimes 4271541Srgrimes case SIOCDIFADDR: 42874299Sru /* 42974299Sru * in_ifscrub kills the interface route. 43074299Sru */ 4311541Srgrimes in_ifscrub(ifp, ia); 43215092Sdg /* 43374299Sru * in_ifadown gets rid of all the rest of 43474299Sru * the routes. This is not quite the right 43574299Sru * thing to do, but at least if we are running 43674299Sru * a routing process they will come back. 43774299Sru */ 43876469Sru in_ifadown(&ia->ia_ifa, 1); 43981127Sume /* 44081127Sume * XXX horrible hack to detect that we are being called 44181127Sume * from if_detach() 44281127Sume */ 443121922Ssam if (ifaddr_byindex(ifp->if_index) == NULL) { 44498102Shsu in_pcbpurgeif0(&ripcbinfo, ifp); 44598102Shsu in_pcbpurgeif0(&udbinfo, ifp); 44681127Sume } 447126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 44887124Sbrian error = 0; 4491541Srgrimes break; 4501541Srgrimes 4511541Srgrimes default: 4521541Srgrimes if (ifp == 0 || ifp->if_ioctl == 0) 4531541Srgrimes return (EOPNOTSUPP); 4541541Srgrimes return ((*ifp->if_ioctl)(ifp, cmd, data)); 4551541Srgrimes } 45687124Sbrian 45787124Sbrian /* 45887124Sbrian * Protect from ipintr() traversing address list while we're modifying 45987124Sbrian * it. 46087124Sbrian */ 46187124Sbrian s = splnet(); 46287124Sbrian TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 46387124Sbrian TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link); 46487124Sbrian LIST_REMOVE(ia, ia_hash); 46587124Sbrian IFAFREE(&ia->ia_ifa); 46687124Sbrian splx(s); 46787124Sbrian 46887124Sbrian return (error); 4691541Srgrimes} 4701541Srgrimes 4711541Srgrimes/* 47255009Sshin * SIOC[GAD]LIFADDR. 47355009Sshin * SIOCGLIFADDR: get first address. (?!?) 47455009Sshin * SIOCGLIFADDR with IFLR_PREFIX: 47555009Sshin * get first address that matches the specified prefix. 47655009Sshin * SIOCALIFADDR: add the specified address. 47755009Sshin * SIOCALIFADDR with IFLR_PREFIX: 47855009Sshin * EINVAL since we can't deduce hostid part of the address. 47955009Sshin * SIOCDLIFADDR: delete the specified address. 48055009Sshin * SIOCDLIFADDR with IFLR_PREFIX: 48155009Sshin * delete the first address that matches the specified prefix. 48255009Sshin * return values: 48355009Sshin * EINVAL on invalid parameters 48455009Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 48555009Sshin * other values may be returned from in_ioctl() 48655009Sshin */ 48755009Sshinstatic int 48883366Sjulianin_lifaddr_ioctl(so, cmd, data, ifp, td) 48955009Sshin struct socket *so; 49055009Sshin u_long cmd; 49155009Sshin caddr_t data; 49255009Sshin struct ifnet *ifp; 49383366Sjulian struct thread *td; 49455009Sshin{ 49555009Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 49655009Sshin struct ifaddr *ifa; 49755009Sshin 49855009Sshin /* sanity checks */ 49955009Sshin if (!data || !ifp) { 50055009Sshin panic("invalid argument to in_lifaddr_ioctl"); 50155009Sshin /*NOTRECHED*/ 50255009Sshin } 50355009Sshin 50455009Sshin switch (cmd) { 50555009Sshin case SIOCGLIFADDR: 50655009Sshin /* address must be specified on GET with IFLR_PREFIX */ 50755009Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 50855009Sshin break; 50955009Sshin /*FALLTHROUGH*/ 51055009Sshin case SIOCALIFADDR: 51155009Sshin case SIOCDLIFADDR: 51255009Sshin /* address must be specified on ADD and DELETE */ 51355917Sshin if (iflr->addr.ss_family != AF_INET) 51455009Sshin return EINVAL; 51555917Sshin if (iflr->addr.ss_len != sizeof(struct sockaddr_in)) 51655009Sshin return EINVAL; 51755009Sshin /* XXX need improvement */ 51855917Sshin if (iflr->dstaddr.ss_family 51955917Sshin && iflr->dstaddr.ss_family != AF_INET) 52055009Sshin return EINVAL; 52155917Sshin if (iflr->dstaddr.ss_family 52255917Sshin && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in)) 52355009Sshin return EINVAL; 52455009Sshin break; 52555009Sshin default: /*shouldn't happen*/ 52655009Sshin return EOPNOTSUPP; 52755009Sshin } 52855009Sshin if (sizeof(struct in_addr) * 8 < iflr->prefixlen) 52955009Sshin return EINVAL; 53055009Sshin 53155009Sshin switch (cmd) { 53255009Sshin case SIOCALIFADDR: 53355009Sshin { 53455009Sshin struct in_aliasreq ifra; 53555009Sshin 53655009Sshin if (iflr->flags & IFLR_PREFIX) 53755009Sshin return EINVAL; 53855009Sshin 53955009Sshin /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 54055009Sshin bzero(&ifra, sizeof(ifra)); 54155009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 54255009Sshin sizeof(ifra.ifra_name)); 54355009Sshin 54455917Sshin bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len); 54555009Sshin 54655917Sshin if (iflr->dstaddr.ss_family) { /*XXX*/ 54755009Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 54855917Sshin iflr->dstaddr.ss_len); 54955009Sshin } 55055009Sshin 55155009Sshin ifra.ifra_mask.sin_family = AF_INET; 55255009Sshin ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); 55355009Sshin in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); 55455009Sshin 55583366Sjulian return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td); 55655009Sshin } 55755009Sshin case SIOCGLIFADDR: 55855009Sshin case SIOCDLIFADDR: 55955009Sshin { 56055009Sshin struct in_ifaddr *ia; 56155009Sshin struct in_addr mask, candidate, match; 56255009Sshin struct sockaddr_in *sin; 56355009Sshin int cmp; 56455009Sshin 56555009Sshin bzero(&mask, sizeof(mask)); 56655009Sshin if (iflr->flags & IFLR_PREFIX) { 56755009Sshin /* lookup a prefix rather than address. */ 56855009Sshin in_len2mask(&mask, iflr->prefixlen); 56955009Sshin 57055009Sshin sin = (struct sockaddr_in *)&iflr->addr; 57155009Sshin match.s_addr = sin->sin_addr.s_addr; 57255009Sshin match.s_addr &= mask.s_addr; 57355009Sshin 57455009Sshin /* if you set extra bits, that's wrong */ 57555009Sshin if (match.s_addr != sin->sin_addr.s_addr) 57655009Sshin return EINVAL; 57755009Sshin 57855009Sshin cmp = 1; 57955009Sshin } else { 58055009Sshin if (cmd == SIOCGLIFADDR) { 58155009Sshin /* on getting an address, take the 1st match */ 58255009Sshin cmp = 0; /*XXX*/ 58355009Sshin } else { 58455009Sshin /* on deleting an address, do exact match */ 58555009Sshin in_len2mask(&mask, 32); 58655009Sshin sin = (struct sockaddr_in *)&iflr->addr; 58755009Sshin match.s_addr = sin->sin_addr.s_addr; 58855009Sshin 58955009Sshin cmp = 1; 59055009Sshin } 59155009Sshin } 59255009Sshin 59355009Sshin TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 59455009Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 59555009Sshin continue; 59655009Sshin if (!cmp) 59755009Sshin break; 59855009Sshin candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr; 59955009Sshin candidate.s_addr &= mask.s_addr; 60055009Sshin if (candidate.s_addr == match.s_addr) 60155009Sshin break; 60255009Sshin } 60355009Sshin if (!ifa) 60455009Sshin return EADDRNOTAVAIL; 60555009Sshin ia = (struct in_ifaddr *)ifa; 60655009Sshin 60755009Sshin if (cmd == SIOCGLIFADDR) { 60855009Sshin /* fill in the if_laddrreq structure */ 60955009Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len); 61055009Sshin 61155009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 61255009Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 61355009Sshin ia->ia_dstaddr.sin_len); 61455009Sshin } else 61555009Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 61655009Sshin 61755009Sshin iflr->prefixlen = 61855009Sshin in_mask2len(&ia->ia_sockmask.sin_addr); 61955009Sshin 62055009Sshin iflr->flags = 0; /*XXX*/ 62155009Sshin 62255009Sshin return 0; 62355009Sshin } else { 62455009Sshin struct in_aliasreq ifra; 62555009Sshin 62655009Sshin /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 62755009Sshin bzero(&ifra, sizeof(ifra)); 62855009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 62955009Sshin sizeof(ifra.ifra_name)); 63055009Sshin 63155009Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 63255009Sshin ia->ia_addr.sin_len); 63355009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 63455009Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 63555009Sshin ia->ia_dstaddr.sin_len); 63655009Sshin } 63755009Sshin bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr, 63855009Sshin ia->ia_sockmask.sin_len); 63955009Sshin 64055009Sshin return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, 64183366Sjulian ifp, td); 64255009Sshin } 64355009Sshin } 64455009Sshin } 64555009Sshin 64655009Sshin return EOPNOTSUPP; /*just for safety*/ 64755009Sshin} 64855009Sshin 64955009Sshin/* 6501541Srgrimes * Delete any existing route for an interface. 6511541Srgrimes */ 65222672Swollmanvoid 6531541Srgrimesin_ifscrub(ifp, ia) 6541541Srgrimes register struct ifnet *ifp; 6551541Srgrimes register struct in_ifaddr *ia; 6561541Srgrimes{ 6571541Srgrimes 6581541Srgrimes if ((ia->ia_flags & IFA_ROUTE) == 0) 6591541Srgrimes return; 6601541Srgrimes if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) 6611541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 6621541Srgrimes else 6631541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 6641541Srgrimes ia->ia_flags &= ~IFA_ROUTE; 6651541Srgrimes} 6661541Srgrimes 6671541Srgrimes/* 6681541Srgrimes * Initialize an interface's internet address 6691541Srgrimes * and routing table entry. 6701541Srgrimes */ 67112296Sphkstatic int 6721541Srgrimesin_ifinit(ifp, ia, sin, scrub) 6731541Srgrimes register struct ifnet *ifp; 6741541Srgrimes register struct in_ifaddr *ia; 6751541Srgrimes struct sockaddr_in *sin; 6761541Srgrimes int scrub; 6771541Srgrimes{ 6781541Srgrimes register u_long i = ntohl(sin->sin_addr.s_addr); 6791541Srgrimes struct sockaddr_in oldaddr; 68094326Sbrian int s = splimp(), flags = RTF_UP, error = 0; 6811541Srgrimes 6821541Srgrimes oldaddr = ia->ia_addr; 683105748Ssuz if (oldaddr.sin_family == AF_INET) 684105748Ssuz LIST_REMOVE(ia, ia_hash); 6851541Srgrimes ia->ia_addr = *sin; 686105748Ssuz if (ia->ia_addr.sin_family == AF_INET) 687105748Ssuz LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), 688105748Ssuz ia, ia_hash); 6891541Srgrimes /* 6901541Srgrimes * Give the interface a chance to initialize 6911541Srgrimes * if this is its first address, 6921541Srgrimes * and to validate the address if necessary. 6931541Srgrimes */ 6941541Srgrimes if (ifp->if_ioctl && 6951541Srgrimes (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { 6961541Srgrimes splx(s); 697105748Ssuz /* LIST_REMOVE(ia, ia_hash) is done in in_control */ 6981541Srgrimes ia->ia_addr = oldaddr; 699105748Ssuz if (ia->ia_addr.sin_family == AF_INET) 700105748Ssuz LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), 701105748Ssuz ia, ia_hash); 7021541Srgrimes return (error); 7031541Srgrimes } 7041541Srgrimes splx(s); 7051541Srgrimes if (scrub) { 7061541Srgrimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 7071541Srgrimes in_ifscrub(ifp, ia); 7081541Srgrimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 7091541Srgrimes } 7101541Srgrimes if (IN_CLASSA(i)) 7111541Srgrimes ia->ia_netmask = IN_CLASSA_NET; 7121541Srgrimes else if (IN_CLASSB(i)) 7131541Srgrimes ia->ia_netmask = IN_CLASSB_NET; 7141541Srgrimes else 7151541Srgrimes ia->ia_netmask = IN_CLASSC_NET; 7161541Srgrimes /* 7171541Srgrimes * The subnet mask usually includes at least the standard network part, 7181541Srgrimes * but may may be smaller in the case of supernetting. 7191541Srgrimes * If it is set, we believe it. 7201541Srgrimes */ 7211541Srgrimes if (ia->ia_subnetmask == 0) { 7221541Srgrimes ia->ia_subnetmask = ia->ia_netmask; 7231541Srgrimes ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); 7241541Srgrimes } else 7251541Srgrimes ia->ia_netmask &= ia->ia_subnetmask; 7261541Srgrimes ia->ia_net = i & ia->ia_netmask; 7271541Srgrimes ia->ia_subnet = i & ia->ia_subnetmask; 7281541Srgrimes in_socktrim(&ia->ia_sockmask); 7291541Srgrimes /* 7301541Srgrimes * Add route for the network. 7311541Srgrimes */ 7321541Srgrimes ia->ia_ifa.ifa_metric = ifp->if_metric; 7331541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 7341541Srgrimes ia->ia_broadaddr.sin_addr.s_addr = 7351541Srgrimes htonl(ia->ia_subnet | ~ia->ia_subnetmask); 7361541Srgrimes ia->ia_netbroadcast.s_addr = 7371541Srgrimes htonl(ia->ia_net | ~ ia->ia_netmask); 7381541Srgrimes } else if (ifp->if_flags & IFF_LOOPBACK) { 7391541Srgrimes ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; 7401541Srgrimes flags |= RTF_HOST; 7411541Srgrimes } else if (ifp->if_flags & IFF_POINTOPOINT) { 7421541Srgrimes if (ia->ia_dstaddr.sin_family != AF_INET) 7431541Srgrimes return (0); 7441541Srgrimes flags |= RTF_HOST; 7451541Srgrimes } 74694326Sbrian 74794326Sbrian /*- 74894326Sbrian * Don't add host routes for interface addresses of 74994326Sbrian * 0.0.0.0 --> 0.255.255.255 netmask 255.0.0.0. This makes it 75094326Sbrian * possible to assign several such address pairs with consistent 75194326Sbrian * results (no host route) and is required by BOOTP. 75294326Sbrian * 75394326Sbrian * XXX: This is ugly ! There should be a way for the caller to 75494326Sbrian * say that they don't want a host route. 75594326Sbrian */ 75694326Sbrian if (ia->ia_addr.sin_addr.s_addr != INADDR_ANY || 75794326Sbrian ia->ia_netmask != IN_CLASSA_NET || 75894326Sbrian ia->ia_dstaddr.sin_addr.s_addr != htonl(IN_CLASSA_HOST)) { 75994326Sbrian if ((error = rtinit(&ia->ia_ifa, (int)RTM_ADD, flags)) != 0) { 76094326Sbrian ia->ia_addr = oldaddr; 76194326Sbrian return (error); 76294326Sbrian } 7631541Srgrimes ia->ia_flags |= IFA_ROUTE; 76487124Sbrian } 76587124Sbrian 7661541Srgrimes /* 7671541Srgrimes * If the interface supports multicast, join the "all hosts" 7681541Srgrimes * multicast group on that interface. 7691541Srgrimes */ 7701541Srgrimes if (ifp->if_flags & IFF_MULTICAST) { 7711541Srgrimes struct in_addr addr; 7721541Srgrimes 7731541Srgrimes addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 7741541Srgrimes in_addmulti(&addr, ifp); 7751541Srgrimes } 7761541Srgrimes return (error); 7771541Srgrimes} 7781541Srgrimes 7791541Srgrimes 7801541Srgrimes/* 7811541Srgrimes * Return 1 if the address might be a local broadcast address. 7821541Srgrimes */ 7831549Srgrimesint 7841541Srgrimesin_broadcast(in, ifp) 7851541Srgrimes struct in_addr in; 786133874Srwatson struct ifnet *ifp; 7871541Srgrimes{ 7881541Srgrimes register struct ifaddr *ifa; 7891541Srgrimes u_long t; 7901541Srgrimes 7911541Srgrimes if (in.s_addr == INADDR_BROADCAST || 7921541Srgrimes in.s_addr == INADDR_ANY) 7931541Srgrimes return 1; 7941541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 7951541Srgrimes return 0; 7961541Srgrimes t = ntohl(in.s_addr); 7971541Srgrimes /* 7981541Srgrimes * Look through the list of addresses for a match 7991541Srgrimes * with a broadcast address. 8001541Srgrimes */ 8011541Srgrimes#define ia ((struct in_ifaddr *)ifa) 80274362Sphk TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 8031541Srgrimes if (ifa->ifa_addr->sa_family == AF_INET && 8041541Srgrimes (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || 8051541Srgrimes in.s_addr == ia->ia_netbroadcast.s_addr || 8061541Srgrimes /* 8071541Srgrimes * Check for old-style (host 0) broadcast. 8081541Srgrimes */ 80913351Sguido t == ia->ia_subnet || t == ia->ia_net) && 81013351Sguido /* 81113351Sguido * Check for an all one subnetmask. These 81213351Sguido * only exist when an interface gets a secondary 81313351Sguido * address. 81413351Sguido */ 81513351Sguido ia->ia_subnetmask != (u_long)0xffffffff) 8161541Srgrimes return 1; 8171541Srgrimes return (0); 8181541Srgrimes#undef ia 8191541Srgrimes} 8201541Srgrimes/* 8211541Srgrimes * Add an address to the list of IP multicast addresses for a given interface. 8221541Srgrimes */ 8231541Srgrimesstruct in_multi * 8241541Srgrimesin_addmulti(ap, ifp) 8251541Srgrimes register struct in_addr *ap; 8261541Srgrimes register struct ifnet *ifp; 8271541Srgrimes{ 8281541Srgrimes register struct in_multi *inm; 82921666Swollman int error; 83021666Swollman struct sockaddr_in sin; 83121666Swollman struct ifmultiaddr *ifma; 8321541Srgrimes int s = splnet(); 8331541Srgrimes 8341541Srgrimes /* 83521666Swollman * Call generic routine to add membership or increment 83621666Swollman * refcount. It wants addresses in the form of a sockaddr, 83721666Swollman * so we build one here (being careful to zero the unused bytes). 8381541Srgrimes */ 83921666Swollman bzero(&sin, sizeof sin); 84021666Swollman sin.sin_family = AF_INET; 84121666Swollman sin.sin_len = sizeof sin; 84221666Swollman sin.sin_addr = *ap; 84321666Swollman error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma); 84421666Swollman if (error) { 84521666Swollman splx(s); 84621666Swollman return 0; 8471541Srgrimes } 8487280Swollman 84921666Swollman /* 85021666Swollman * If ifma->ifma_protospec is null, then if_addmulti() created 85121666Swollman * a new record. Otherwise, we are done. 85221666Swollman */ 85364853Sbde if (ifma->ifma_protospec != 0) { 85464853Sbde splx(s); 85521666Swollman return ifma->ifma_protospec; 85664853Sbde } 85721666Swollman 858111119Simp /* XXX - if_addmulti uses M_WAITOK. Can this really be called 85921666Swollman at interrupt time? If so, need to fix if_addmulti. XXX */ 86069781Sdwmalone inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR, 86169781Sdwmalone M_NOWAIT | M_ZERO); 86221666Swollman if (inm == NULL) { 86321666Swollman splx(s); 86421666Swollman return (NULL); 8651541Srgrimes } 86621666Swollman 86721666Swollman inm->inm_addr = *ap; 86821666Swollman inm->inm_ifp = ifp; 86921666Swollman inm->inm_ifma = ifma; 87021666Swollman ifma->ifma_protospec = inm; 87121666Swollman LIST_INSERT_HEAD(&in_multihead, inm, inm_link); 87221666Swollman 87321666Swollman /* 87421666Swollman * Let IGMP know that we have joined a new IP multicast group. 87521666Swollman */ 87621666Swollman igmp_joingroup(inm); 8771541Srgrimes splx(s); 8781541Srgrimes return (inm); 8791541Srgrimes} 8801541Srgrimes 8811541Srgrimes/* 8821541Srgrimes * Delete a multicast address record. 8831541Srgrimes */ 8841549Srgrimesvoid 8851541Srgrimesin_delmulti(inm) 8861541Srgrimes register struct in_multi *inm; 8871541Srgrimes{ 88821666Swollman struct ifmultiaddr *ifma = inm->inm_ifma; 88945997Sluigi struct in_multi my_inm; 8901541Srgrimes int s = splnet(); 8911541Srgrimes 89245997Sluigi my_inm.inm_ifp = NULL ; /* don't send the leave msg */ 89321666Swollman if (ifma->ifma_refcount == 1) { 8941541Srgrimes /* 8951541Srgrimes * No remaining claims to this record; let IGMP know that 8961541Srgrimes * we are leaving the multicast group. 89745997Sluigi * But do it after the if_delmulti() which might reset 89845997Sluigi * the interface and nuke the packet. 8991541Srgrimes */ 90045997Sluigi my_inm = *inm ; 90121666Swollman ifma->ifma_protospec = 0; 90221666Swollman LIST_REMOVE(inm, inm_link); 9031541Srgrimes free(inm, M_IPMADDR); 9041541Srgrimes } 90521666Swollman /* XXX - should be separate API for when we have an ifma? */ 90621666Swollman if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); 90745997Sluigi if (my_inm.inm_ifp != NULL) 90845997Sluigi igmp_leavegroup(&my_inm); 9091541Srgrimes splx(s); 9101541Srgrimes} 911