in.c revision 87124
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 * 3. All advertising materials mentioning features or use of this software 141541Srgrimes * must display the following acknowledgement: 151541Srgrimes * This product includes software developed by the University of 161541Srgrimes * California, Berkeley and its contributors. 171541Srgrimes * 4. Neither the name of the University nor the names of its contributors 181541Srgrimes * may be used to endorse or promote products derived from this software 191541Srgrimes * without specific prior written permission. 201541Srgrimes * 211541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311541Srgrimes * SUCH DAMAGE. 321541Srgrimes * 3310939Swollman * @(#)in.c 8.4 (Berkeley) 1/9/95 3450477Speter * $FreeBSD: head/sys/netinet/in.c 87124 2001-11-30 14:00:55Z brian $ 351541Srgrimes */ 361541Srgrimes 371541Srgrimes#include <sys/param.h> 381549Srgrimes#include <sys/systm.h> 3924204Sbde#include <sys/sockio.h> 401541Srgrimes#include <sys/malloc.h> 411541Srgrimes#include <sys/socket.h> 4212704Sphk#include <sys/kernel.h> 4312704Sphk#include <sys/sysctl.h> 441541Srgrimes 451541Srgrimes#include <net/if.h> 4655009Sshin#include <net/if_types.h> 471541Srgrimes#include <net/route.h> 481541Srgrimes 491541Srgrimes#include <netinet/in.h> 501541Srgrimes#include <netinet/in_var.h> 5181127Sume#include <netinet/in_pcb.h> 521541Srgrimes 536363Sphk#include <netinet/igmp_var.h> 546363Sphk 5530354Sphkstatic MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); 5630309Sphk 5755009Sshinstatic int in_mask2len __P((struct in_addr *)); 5855009Sshinstatic void in_len2mask __P((struct in_addr *, int)); 5955009Sshinstatic int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 6083366Sjulian struct ifnet *, struct thread *)); 6155009Sshin 6212296Sphkstatic void in_socktrim __P((struct sockaddr_in *)); 6312296Sphkstatic int in_ifinit __P((struct ifnet *, 6412296Sphk struct in_ifaddr *, struct sockaddr_in *, int)); 651541Srgrimes 6618193Swollmanstatic int subnetsarelocal = 0; 6712704SphkSYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, 6812704Sphk &subnetsarelocal, 0, ""); 6921666Swollman 7021666Swollmanstruct in_multihead in_multihead; /* XXX BSS initialization */ 7121666Swollman 7281127Sumeextern struct inpcbinfo ripcbinfo; 7381127Sumeextern struct inpcbinfo udbinfo; 7481127Sume 751541Srgrimes/* 761541Srgrimes * Return 1 if an internet address is for a ``local'' host 771541Srgrimes * (one to which we have a connection). If subnetsarelocal 781541Srgrimes * is true, this includes other subnets of the local net. 791541Srgrimes * Otherwise, it includes only the directly-connected (sub)nets. 801541Srgrimes */ 811549Srgrimesint 821541Srgrimesin_localaddr(in) 831541Srgrimes struct in_addr in; 841541Srgrimes{ 851541Srgrimes register u_long i = ntohl(in.s_addr); 861541Srgrimes register struct in_ifaddr *ia; 871541Srgrimes 881541Srgrimes if (subnetsarelocal) { 8974362Sphk TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 901541Srgrimes if ((i & ia->ia_netmask) == ia->ia_net) 911541Srgrimes return (1); 921541Srgrimes } else { 9372012Sphk TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 941541Srgrimes if ((i & ia->ia_subnetmask) == ia->ia_subnet) 951541Srgrimes return (1); 961541Srgrimes } 971541Srgrimes return (0); 981541Srgrimes} 991541Srgrimes 1001541Srgrimes/* 1011541Srgrimes * Determine whether an IP address is in a reserved set of addresses 1021541Srgrimes * that may not be forwarded, or whether datagrams to that destination 1031541Srgrimes * may be forwarded. 1041541Srgrimes */ 1051549Srgrimesint 1061541Srgrimesin_canforward(in) 1071541Srgrimes struct in_addr in; 1081541Srgrimes{ 1091541Srgrimes register u_long i = ntohl(in.s_addr); 1101541Srgrimes register u_long net; 1111541Srgrimes 1121541Srgrimes if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) 1131541Srgrimes return (0); 1141541Srgrimes if (IN_CLASSA(i)) { 1151541Srgrimes net = i & IN_CLASSA_NET; 1161541Srgrimes if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) 1171541Srgrimes return (0); 1181541Srgrimes } 1191541Srgrimes return (1); 1201541Srgrimes} 1211541Srgrimes 1221541Srgrimes/* 1231541Srgrimes * Trim a mask in a sockaddr 1241541Srgrimes */ 12512296Sphkstatic void 1261541Srgrimesin_socktrim(ap) 1271541Srgrimesstruct sockaddr_in *ap; 1281541Srgrimes{ 1291541Srgrimes register char *cplim = (char *) &ap->sin_addr; 1301541Srgrimes register char *cp = (char *) (&ap->sin_addr + 1); 1311541Srgrimes 1321541Srgrimes ap->sin_len = 0; 1334127Swollman while (--cp >= cplim) 1341541Srgrimes if (*cp) { 1351541Srgrimes (ap)->sin_len = cp - (char *) (ap) + 1; 1361541Srgrimes break; 1371541Srgrimes } 1381541Srgrimes} 1391541Srgrimes 14055009Sshinstatic int 14155009Sshinin_mask2len(mask) 14255009Sshin struct in_addr *mask; 14355009Sshin{ 14455009Sshin int x, y; 14555009Sshin u_char *p; 14655009Sshin 14755009Sshin p = (u_char *)mask; 14855009Sshin for (x = 0; x < sizeof(*mask); x++) { 14955009Sshin if (p[x] != 0xff) 15055009Sshin break; 15155009Sshin } 15255009Sshin y = 0; 15355009Sshin if (x < sizeof(*mask)) { 15455009Sshin for (y = 0; y < 8; y++) { 15555009Sshin if ((p[x] & (0x80 >> y)) == 0) 15655009Sshin break; 15755009Sshin } 15855009Sshin } 15955009Sshin return x * 8 + y; 16055009Sshin} 16155009Sshin 16255009Sshinstatic void 16355009Sshinin_len2mask(mask, len) 16455009Sshin struct in_addr *mask; 16555009Sshin int len; 16655009Sshin{ 16755009Sshin int i; 16855009Sshin u_char *p; 16955009Sshin 17055009Sshin p = (u_char *)mask; 17155009Sshin bzero(mask, sizeof(*mask)); 17255009Sshin for (i = 0; i < len / 8; i++) 17355009Sshin p[i] = 0xff; 17455009Sshin if (len % 8) 17555009Sshin p[i] = (0xff00 >> (len % 8)) & 0xff; 17655009Sshin} 17755009Sshin 17812704Sphkstatic int in_interfaces; /* number of external internet interfaces */ 1791541Srgrimes 1801541Srgrimes/* 1811541Srgrimes * Generic internet control operations (ioctl's). 1821541Srgrimes * Ifp is 0 if not an interface-specific ioctl. 1831541Srgrimes */ 1841541Srgrimes/* ARGSUSED */ 1851549Srgrimesint 18683366Sjulianin_control(so, cmd, data, ifp, td) 1871541Srgrimes struct socket *so; 18836735Sdfr u_long cmd; 1891541Srgrimes caddr_t data; 1901541Srgrimes register struct ifnet *ifp; 19183366Sjulian struct thread *td; 1921541Srgrimes{ 1931541Srgrimes register struct ifreq *ifr = (struct ifreq *)data; 19414632Sfenner register struct in_ifaddr *ia = 0, *iap; 1951541Srgrimes register struct ifaddr *ifa; 19684102Sjlemon struct in_addr dst; 1971541Srgrimes struct in_ifaddr *oia; 1981541Srgrimes struct in_aliasreq *ifra = (struct in_aliasreq *)data; 1991541Srgrimes struct sockaddr_in oldaddr; 20087124Sbrian int error, hostIsNew, iaIsNew, maskIsNew, s; 2011541Srgrimes 20287124Sbrian iaIsNew = 0; 20387124Sbrian 20455009Sshin switch (cmd) { 20555009Sshin case SIOCALIFADDR: 20655009Sshin case SIOCDLIFADDR: 20783366Sjulian if (td && (error = suser_td(td)) != 0) 20855009Sshin return error; 20955009Sshin /*fall through*/ 21055009Sshin case SIOCGLIFADDR: 21155009Sshin if (!ifp) 21255009Sshin return EINVAL; 21383366Sjulian return in_lifaddr_ioctl(so, cmd, data, ifp, td); 21455009Sshin } 21555009Sshin 2161541Srgrimes /* 2171541Srgrimes * Find address for this interface, if it exists. 21814632Sfenner * 21914632Sfenner * If an alias address was specified, find that one instead of 22084102Sjlemon * the first one on the interface, if possible. 2211541Srgrimes */ 22284102Sjlemon if (ifp) { 22384102Sjlemon dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; 22484102Sjlemon LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) 22584102Sjlemon if (iap->ia_ifp == ifp && 22684102Sjlemon iap->ia_addr.sin_addr.s_addr == dst.s_addr) { 22784102Sjlemon ia = iap; 22884102Sjlemon break; 22984102Sjlemon } 23084102Sjlemon if (ia == NULL) 23184102Sjlemon TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 23284102Sjlemon iap = ifatoia(ifa); 23384102Sjlemon if (iap->ia_addr.sin_family == AF_INET) { 23414632Sfenner ia = iap; 23514632Sfenner break; 23614632Sfenner } 23714632Sfenner } 23884102Sjlemon } 2391541Srgrimes 2401541Srgrimes switch (cmd) { 2411541Srgrimes 2421541Srgrimes case SIOCAIFADDR: 2431541Srgrimes case SIOCDIFADDR: 24441575Seivind if (ifp == 0) 24541575Seivind return (EADDRNOTAVAIL); 2468071Swollman if (ifra->ifra_addr.sin_family == AF_INET) { 24771999Sphk for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) { 2488071Swollman if (ia->ia_ifp == ifp && 2498071Swollman ia->ia_addr.sin_addr.s_addr == 2508071Swollman ifra->ifra_addr.sin_addr.s_addr) 2518071Swollman break; 2528071Swollman } 2538876Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) 2548071Swollman && (cmd == SIOCAIFADDR) 2558071Swollman && (ifra->ifra_dstaddr.sin_addr.s_addr 2568071Swollman == INADDR_ANY)) { 2579563Swollman return EDESTADDRREQ; 2588071Swollman } 2591541Srgrimes } 2601541Srgrimes if (cmd == SIOCDIFADDR && ia == 0) 2611541Srgrimes return (EADDRNOTAVAIL); 2621541Srgrimes /* FALLTHROUGH */ 2631541Srgrimes case SIOCSIFADDR: 2641541Srgrimes case SIOCSIFNETMASK: 2651541Srgrimes case SIOCSIFDSTADDR: 26683366Sjulian if (td && (error = suser_td(td)) != 0) 26725201Swollman return error; 2681541Srgrimes 2691541Srgrimes if (ifp == 0) 27041575Seivind return (EADDRNOTAVAIL); 2711541Srgrimes if (ia == (struct in_ifaddr *)0) { 27220407Swollman ia = (struct in_ifaddr *) 27369781Sdwmalone malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO); 27420407Swollman if (ia == (struct in_ifaddr *)NULL) 2751541Srgrimes return (ENOBUFS); 27615092Sdg /* 27715092Sdg * Protect from ipintr() traversing address list 27815092Sdg * while we're modifying it. 27915092Sdg */ 28015092Sdg s = splnet(); 28120407Swollman 28220407Swollman TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link); 28320407Swollman ifa = &ia->ia_ifa; 28420407Swollman TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 28515092Sdg 28620407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 28720407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 28820407Swollman ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 2891541Srgrimes ia->ia_sockmask.sin_len = 8; 29085740Sdes ia->ia_sockmask.sin_family = AF_INET; 2911541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 2921541Srgrimes ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); 2931541Srgrimes ia->ia_broadaddr.sin_family = AF_INET; 2941541Srgrimes } 2951541Srgrimes ia->ia_ifp = ifp; 2968090Spst if (!(ifp->if_flags & IFF_LOOPBACK)) 2971541Srgrimes in_interfaces++; 29815092Sdg splx(s); 29987124Sbrian iaIsNew = 1; 3001541Srgrimes } 3011541Srgrimes break; 3021541Srgrimes 3031541Srgrimes case SIOCSIFBRDADDR: 30483366Sjulian if (td && (error = suser_td(td)) != 0) 30525201Swollman return error; 3061541Srgrimes /* FALLTHROUGH */ 3071541Srgrimes 3081541Srgrimes case SIOCGIFADDR: 3091541Srgrimes case SIOCGIFNETMASK: 3101541Srgrimes case SIOCGIFDSTADDR: 3111541Srgrimes case SIOCGIFBRDADDR: 3121541Srgrimes if (ia == (struct in_ifaddr *)0) 3131541Srgrimes return (EADDRNOTAVAIL); 3141541Srgrimes break; 3151541Srgrimes } 3161541Srgrimes switch (cmd) { 3171541Srgrimes 3181541Srgrimes case SIOCGIFADDR: 3191541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; 32087124Sbrian return (0); 3211541Srgrimes 3221541Srgrimes case SIOCGIFBRDADDR: 3231541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 3241541Srgrimes return (EINVAL); 3251541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; 32687124Sbrian return (0); 3271541Srgrimes 3281541Srgrimes case SIOCGIFDSTADDR: 3291541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 3301541Srgrimes return (EINVAL); 3311541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; 33287124Sbrian return (0); 3331541Srgrimes 3341541Srgrimes case SIOCGIFNETMASK: 3351541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; 33687124Sbrian return (0); 3371541Srgrimes 3381541Srgrimes case SIOCSIFDSTADDR: 3391541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 3401541Srgrimes return (EINVAL); 3411541Srgrimes oldaddr = ia->ia_dstaddr; 3421541Srgrimes ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; 3431541Srgrimes if (ifp->if_ioctl && (error = (*ifp->if_ioctl) 3441541Srgrimes (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { 3451541Srgrimes ia->ia_dstaddr = oldaddr; 3461541Srgrimes return (error); 3471541Srgrimes } 3481541Srgrimes if (ia->ia_flags & IFA_ROUTE) { 3491541Srgrimes ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; 3501541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 3511541Srgrimes ia->ia_ifa.ifa_dstaddr = 3521541Srgrimes (struct sockaddr *)&ia->ia_dstaddr; 3531541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 3541541Srgrimes } 35587124Sbrian return (0); 3561541Srgrimes 3571541Srgrimes case SIOCSIFBRDADDR: 3581541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 3591541Srgrimes return (EINVAL); 3601541Srgrimes ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr; 36187124Sbrian return (0); 3621541Srgrimes 3631541Srgrimes case SIOCSIFADDR: 36487124Sbrian error = in_ifinit(ifp, ia, 36587124Sbrian (struct sockaddr_in *) &ifr->ifr_addr, 1); 36687124Sbrian if (error != 0 && iaIsNew) 36787124Sbrian break; 36887124Sbrian return (0); 3691541Srgrimes 3701541Srgrimes case SIOCSIFNETMASK: 37185740Sdes ia->ia_sockmask.sin_addr = ifra->ifra_addr.sin_addr; 37285740Sdes ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr); 37387124Sbrian return (0); 3741541Srgrimes 3751541Srgrimes case SIOCAIFADDR: 3761541Srgrimes maskIsNew = 0; 3771541Srgrimes hostIsNew = 1; 3781541Srgrimes error = 0; 3791541Srgrimes if (ia->ia_addr.sin_family == AF_INET) { 3801541Srgrimes if (ifra->ifra_addr.sin_len == 0) { 3811541Srgrimes ifra->ifra_addr = ia->ia_addr; 3821541Srgrimes hostIsNew = 0; 3831541Srgrimes } else if (ifra->ifra_addr.sin_addr.s_addr == 3841541Srgrimes ia->ia_addr.sin_addr.s_addr) 3851541Srgrimes hostIsNew = 0; 3861541Srgrimes } 3871541Srgrimes if (ifra->ifra_mask.sin_len) { 3881541Srgrimes in_ifscrub(ifp, ia); 3891541Srgrimes ia->ia_sockmask = ifra->ifra_mask; 39085740Sdes ia->ia_sockmask.sin_family = AF_INET; 3911541Srgrimes ia->ia_subnetmask = 3921541Srgrimes ntohl(ia->ia_sockmask.sin_addr.s_addr); 3931541Srgrimes maskIsNew = 1; 3941541Srgrimes } 3951541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) && 3961541Srgrimes (ifra->ifra_dstaddr.sin_family == AF_INET)) { 3971541Srgrimes in_ifscrub(ifp, ia); 3981541Srgrimes ia->ia_dstaddr = ifra->ifra_dstaddr; 3991541Srgrimes maskIsNew = 1; /* We lie; but the effect's the same */ 4001541Srgrimes } 4011541Srgrimes if (ifra->ifra_addr.sin_family == AF_INET && 4021541Srgrimes (hostIsNew || maskIsNew)) 4031541Srgrimes error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); 40487124Sbrian if (error != 0 && iaIsNew) 40587124Sbrian break; 40687124Sbrian 4071541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) && 4081541Srgrimes (ifra->ifra_broadaddr.sin_family == AF_INET)) 4091541Srgrimes ia->ia_broadaddr = ifra->ifra_broadaddr; 4101541Srgrimes return (error); 4111541Srgrimes 4121541Srgrimes case SIOCDIFADDR: 41374299Sru /* 41474299Sru * in_ifscrub kills the interface route. 41574299Sru */ 4161541Srgrimes in_ifscrub(ifp, ia); 41715092Sdg /* 41874299Sru * in_ifadown gets rid of all the rest of 41974299Sru * the routes. This is not quite the right 42074299Sru * thing to do, but at least if we are running 42174299Sru * a routing process they will come back. 42274299Sru */ 42376469Sru in_ifadown(&ia->ia_ifa, 1); 42481127Sume /* 42581127Sume * XXX horrible hack to detect that we are being called 42681127Sume * from if_detach() 42781127Sume */ 42883130Sjlemon if (ifaddr_byindex(ifp->if_index) != NULL) { 42981127Sume in_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp); 43081127Sume in_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp); 43181127Sume } 43287124Sbrian error = 0; 4331541Srgrimes break; 4341541Srgrimes 4351541Srgrimes default: 4361541Srgrimes if (ifp == 0 || ifp->if_ioctl == 0) 4371541Srgrimes return (EOPNOTSUPP); 4381541Srgrimes return ((*ifp->if_ioctl)(ifp, cmd, data)); 4391541Srgrimes } 44087124Sbrian 44187124Sbrian /* 44287124Sbrian * Protect from ipintr() traversing address list while we're modifying 44387124Sbrian * it. 44487124Sbrian */ 44587124Sbrian s = splnet(); 44687124Sbrian TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 44787124Sbrian TAILQ_REMOVE(&in_ifaddrhead, ia, ia_link); 44887124Sbrian LIST_REMOVE(ia, ia_hash); 44987124Sbrian IFAFREE(&ia->ia_ifa); 45087124Sbrian splx(s); 45187124Sbrian 45287124Sbrian return (error); 4531541Srgrimes} 4541541Srgrimes 4551541Srgrimes/* 45655009Sshin * SIOC[GAD]LIFADDR. 45755009Sshin * SIOCGLIFADDR: get first address. (?!?) 45855009Sshin * SIOCGLIFADDR with IFLR_PREFIX: 45955009Sshin * get first address that matches the specified prefix. 46055009Sshin * SIOCALIFADDR: add the specified address. 46155009Sshin * SIOCALIFADDR with IFLR_PREFIX: 46255009Sshin * EINVAL since we can't deduce hostid part of the address. 46355009Sshin * SIOCDLIFADDR: delete the specified address. 46455009Sshin * SIOCDLIFADDR with IFLR_PREFIX: 46555009Sshin * delete the first address that matches the specified prefix. 46655009Sshin * return values: 46755009Sshin * EINVAL on invalid parameters 46855009Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 46955009Sshin * other values may be returned from in_ioctl() 47055009Sshin */ 47155009Sshinstatic int 47283366Sjulianin_lifaddr_ioctl(so, cmd, data, ifp, td) 47355009Sshin struct socket *so; 47455009Sshin u_long cmd; 47555009Sshin caddr_t data; 47655009Sshin struct ifnet *ifp; 47783366Sjulian struct thread *td; 47855009Sshin{ 47955009Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 48055009Sshin struct ifaddr *ifa; 48155009Sshin 48255009Sshin /* sanity checks */ 48355009Sshin if (!data || !ifp) { 48455009Sshin panic("invalid argument to in_lifaddr_ioctl"); 48555009Sshin /*NOTRECHED*/ 48655009Sshin } 48755009Sshin 48855009Sshin switch (cmd) { 48955009Sshin case SIOCGLIFADDR: 49055009Sshin /* address must be specified on GET with IFLR_PREFIX */ 49155009Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 49255009Sshin break; 49355009Sshin /*FALLTHROUGH*/ 49455009Sshin case SIOCALIFADDR: 49555009Sshin case SIOCDLIFADDR: 49655009Sshin /* address must be specified on ADD and DELETE */ 49755917Sshin if (iflr->addr.ss_family != AF_INET) 49855009Sshin return EINVAL; 49955917Sshin if (iflr->addr.ss_len != sizeof(struct sockaddr_in)) 50055009Sshin return EINVAL; 50155009Sshin /* XXX need improvement */ 50255917Sshin if (iflr->dstaddr.ss_family 50355917Sshin && iflr->dstaddr.ss_family != AF_INET) 50455009Sshin return EINVAL; 50555917Sshin if (iflr->dstaddr.ss_family 50655917Sshin && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in)) 50755009Sshin return EINVAL; 50855009Sshin break; 50955009Sshin default: /*shouldn't happen*/ 51055009Sshin return EOPNOTSUPP; 51155009Sshin } 51255009Sshin if (sizeof(struct in_addr) * 8 < iflr->prefixlen) 51355009Sshin return EINVAL; 51455009Sshin 51555009Sshin switch (cmd) { 51655009Sshin case SIOCALIFADDR: 51755009Sshin { 51855009Sshin struct in_aliasreq ifra; 51955009Sshin 52055009Sshin if (iflr->flags & IFLR_PREFIX) 52155009Sshin return EINVAL; 52255009Sshin 52355009Sshin /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 52455009Sshin bzero(&ifra, sizeof(ifra)); 52555009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 52655009Sshin sizeof(ifra.ifra_name)); 52755009Sshin 52855917Sshin bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len); 52955009Sshin 53055917Sshin if (iflr->dstaddr.ss_family) { /*XXX*/ 53155009Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 53255917Sshin iflr->dstaddr.ss_len); 53355009Sshin } 53455009Sshin 53555009Sshin ifra.ifra_mask.sin_family = AF_INET; 53655009Sshin ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); 53755009Sshin in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); 53855009Sshin 53983366Sjulian return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td); 54055009Sshin } 54155009Sshin case SIOCGLIFADDR: 54255009Sshin case SIOCDLIFADDR: 54355009Sshin { 54455009Sshin struct in_ifaddr *ia; 54555009Sshin struct in_addr mask, candidate, match; 54655009Sshin struct sockaddr_in *sin; 54755009Sshin int cmp; 54855009Sshin 54955009Sshin bzero(&mask, sizeof(mask)); 55055009Sshin if (iflr->flags & IFLR_PREFIX) { 55155009Sshin /* lookup a prefix rather than address. */ 55255009Sshin in_len2mask(&mask, iflr->prefixlen); 55355009Sshin 55455009Sshin sin = (struct sockaddr_in *)&iflr->addr; 55555009Sshin match.s_addr = sin->sin_addr.s_addr; 55655009Sshin match.s_addr &= mask.s_addr; 55755009Sshin 55855009Sshin /* if you set extra bits, that's wrong */ 55955009Sshin if (match.s_addr != sin->sin_addr.s_addr) 56055009Sshin return EINVAL; 56155009Sshin 56255009Sshin cmp = 1; 56355009Sshin } else { 56455009Sshin if (cmd == SIOCGLIFADDR) { 56555009Sshin /* on getting an address, take the 1st match */ 56655009Sshin cmp = 0; /*XXX*/ 56755009Sshin } else { 56855009Sshin /* on deleting an address, do exact match */ 56955009Sshin in_len2mask(&mask, 32); 57055009Sshin sin = (struct sockaddr_in *)&iflr->addr; 57155009Sshin match.s_addr = sin->sin_addr.s_addr; 57255009Sshin 57355009Sshin cmp = 1; 57455009Sshin } 57555009Sshin } 57655009Sshin 57755009Sshin TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 57855009Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 57955009Sshin continue; 58055009Sshin if (!cmp) 58155009Sshin break; 58255009Sshin candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr; 58355009Sshin candidate.s_addr &= mask.s_addr; 58455009Sshin if (candidate.s_addr == match.s_addr) 58555009Sshin break; 58655009Sshin } 58755009Sshin if (!ifa) 58855009Sshin return EADDRNOTAVAIL; 58955009Sshin ia = (struct in_ifaddr *)ifa; 59055009Sshin 59155009Sshin if (cmd == SIOCGLIFADDR) { 59255009Sshin /* fill in the if_laddrreq structure */ 59355009Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len); 59455009Sshin 59555009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 59655009Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 59755009Sshin ia->ia_dstaddr.sin_len); 59855009Sshin } else 59955009Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 60055009Sshin 60155009Sshin iflr->prefixlen = 60255009Sshin in_mask2len(&ia->ia_sockmask.sin_addr); 60355009Sshin 60455009Sshin iflr->flags = 0; /*XXX*/ 60555009Sshin 60655009Sshin return 0; 60755009Sshin } else { 60855009Sshin struct in_aliasreq ifra; 60955009Sshin 61055009Sshin /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 61155009Sshin bzero(&ifra, sizeof(ifra)); 61255009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 61355009Sshin sizeof(ifra.ifra_name)); 61455009Sshin 61555009Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 61655009Sshin ia->ia_addr.sin_len); 61755009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 61855009Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 61955009Sshin ia->ia_dstaddr.sin_len); 62055009Sshin } 62155009Sshin bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr, 62255009Sshin ia->ia_sockmask.sin_len); 62355009Sshin 62455009Sshin return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, 62583366Sjulian ifp, td); 62655009Sshin } 62755009Sshin } 62855009Sshin } 62955009Sshin 63055009Sshin return EOPNOTSUPP; /*just for safety*/ 63155009Sshin} 63255009Sshin 63355009Sshin/* 6341541Srgrimes * Delete any existing route for an interface. 6351541Srgrimes */ 63622672Swollmanvoid 6371541Srgrimesin_ifscrub(ifp, ia) 6381541Srgrimes register struct ifnet *ifp; 6391541Srgrimes register struct in_ifaddr *ia; 6401541Srgrimes{ 6411541Srgrimes 6421541Srgrimes if ((ia->ia_flags & IFA_ROUTE) == 0) 6431541Srgrimes return; 6441541Srgrimes if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) 6451541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 6461541Srgrimes else 6471541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 6481541Srgrimes ia->ia_flags &= ~IFA_ROUTE; 6491541Srgrimes} 6501541Srgrimes 6511541Srgrimes/* 6521541Srgrimes * Initialize an interface's internet address 6531541Srgrimes * and routing table entry. 6541541Srgrimes */ 65512296Sphkstatic int 6561541Srgrimesin_ifinit(ifp, ia, sin, scrub) 6571541Srgrimes register struct ifnet *ifp; 6581541Srgrimes register struct in_ifaddr *ia; 6591541Srgrimes struct sockaddr_in *sin; 6601541Srgrimes int scrub; 6611541Srgrimes{ 6621541Srgrimes register u_long i = ntohl(sin->sin_addr.s_addr); 6631541Srgrimes struct sockaddr_in oldaddr; 6642112Swollman int s = splimp(), flags = RTF_UP, error; 6651541Srgrimes 6661541Srgrimes oldaddr = ia->ia_addr; 6671541Srgrimes ia->ia_addr = *sin; 6681541Srgrimes /* 6691541Srgrimes * Give the interface a chance to initialize 6701541Srgrimes * if this is its first address, 6711541Srgrimes * and to validate the address if necessary. 6721541Srgrimes */ 6731541Srgrimes if (ifp->if_ioctl && 6741541Srgrimes (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { 6751541Srgrimes splx(s); 6761541Srgrimes ia->ia_addr = oldaddr; 6771541Srgrimes return (error); 6781541Srgrimes } 67984317Sjlemon if (oldaddr.sin_family == AF_INET) 68084317Sjlemon LIST_REMOVE(ia, ia_hash); 68184317Sjlemon if (ia->ia_addr.sin_family == AF_INET) 68284317Sjlemon LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), 68384317Sjlemon ia, ia_hash); 6841541Srgrimes splx(s); 6851541Srgrimes if (scrub) { 6861541Srgrimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 6871541Srgrimes in_ifscrub(ifp, ia); 6881541Srgrimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 6891541Srgrimes } 6901541Srgrimes if (IN_CLASSA(i)) 6911541Srgrimes ia->ia_netmask = IN_CLASSA_NET; 6921541Srgrimes else if (IN_CLASSB(i)) 6931541Srgrimes ia->ia_netmask = IN_CLASSB_NET; 6941541Srgrimes else 6951541Srgrimes ia->ia_netmask = IN_CLASSC_NET; 6961541Srgrimes /* 6971541Srgrimes * The subnet mask usually includes at least the standard network part, 6981541Srgrimes * but may may be smaller in the case of supernetting. 6991541Srgrimes * If it is set, we believe it. 7001541Srgrimes */ 7011541Srgrimes if (ia->ia_subnetmask == 0) { 7021541Srgrimes ia->ia_subnetmask = ia->ia_netmask; 7031541Srgrimes ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); 7041541Srgrimes } else 7051541Srgrimes ia->ia_netmask &= ia->ia_subnetmask; 7061541Srgrimes ia->ia_net = i & ia->ia_netmask; 7071541Srgrimes ia->ia_subnet = i & ia->ia_subnetmask; 7081541Srgrimes in_socktrim(&ia->ia_sockmask); 7091541Srgrimes /* 7101541Srgrimes * Add route for the network. 7111541Srgrimes */ 7121541Srgrimes ia->ia_ifa.ifa_metric = ifp->if_metric; 7131541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 7141541Srgrimes ia->ia_broadaddr.sin_addr.s_addr = 7151541Srgrimes htonl(ia->ia_subnet | ~ia->ia_subnetmask); 7161541Srgrimes ia->ia_netbroadcast.s_addr = 7171541Srgrimes htonl(ia->ia_net | ~ ia->ia_netmask); 7181541Srgrimes } else if (ifp->if_flags & IFF_LOOPBACK) { 7191541Srgrimes ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; 7201541Srgrimes flags |= RTF_HOST; 7211541Srgrimes } else if (ifp->if_flags & IFF_POINTOPOINT) { 7221541Srgrimes if (ia->ia_dstaddr.sin_family != AF_INET) 7231541Srgrimes return (0); 7241541Srgrimes flags |= RTF_HOST; 7251541Srgrimes } 7261541Srgrimes if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) 7271541Srgrimes ia->ia_flags |= IFA_ROUTE; 72887124Sbrian 72987124Sbrian if (error != 0 && ia->ia_dstaddr.sin_family == AF_INET) { 73087124Sbrian ia->ia_addr = oldaddr; 73187124Sbrian return (error); 73287124Sbrian } 73387124Sbrian 73478064Sume /* XXX check if the subnet route points to the same interface */ 73578064Sume if (error == EEXIST) 73678064Sume error = 0; 7377280Swollman 7381541Srgrimes /* 7391541Srgrimes * If the interface supports multicast, join the "all hosts" 7401541Srgrimes * multicast group on that interface. 7411541Srgrimes */ 7421541Srgrimes if (ifp->if_flags & IFF_MULTICAST) { 7431541Srgrimes struct in_addr addr; 7441541Srgrimes 7451541Srgrimes addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 7461541Srgrimes in_addmulti(&addr, ifp); 7471541Srgrimes } 7481541Srgrimes return (error); 7491541Srgrimes} 7501541Srgrimes 7511541Srgrimes 7521541Srgrimes/* 7531541Srgrimes * Return 1 if the address might be a local broadcast address. 7541541Srgrimes */ 7551549Srgrimesint 7561541Srgrimesin_broadcast(in, ifp) 7571541Srgrimes struct in_addr in; 7581541Srgrimes struct ifnet *ifp; 7591541Srgrimes{ 7601541Srgrimes register struct ifaddr *ifa; 7611541Srgrimes u_long t; 7621541Srgrimes 7631541Srgrimes if (in.s_addr == INADDR_BROADCAST || 7641541Srgrimes in.s_addr == INADDR_ANY) 7651541Srgrimes return 1; 7661541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 7671541Srgrimes return 0; 7681541Srgrimes t = ntohl(in.s_addr); 7691541Srgrimes /* 7701541Srgrimes * Look through the list of addresses for a match 7711541Srgrimes * with a broadcast address. 7721541Srgrimes */ 7731541Srgrimes#define ia ((struct in_ifaddr *)ifa) 77474362Sphk TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 7751541Srgrimes if (ifa->ifa_addr->sa_family == AF_INET && 7761541Srgrimes (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || 7771541Srgrimes in.s_addr == ia->ia_netbroadcast.s_addr || 7781541Srgrimes /* 7791541Srgrimes * Check for old-style (host 0) broadcast. 7801541Srgrimes */ 78113351Sguido t == ia->ia_subnet || t == ia->ia_net) && 78213351Sguido /* 78313351Sguido * Check for an all one subnetmask. These 78413351Sguido * only exist when an interface gets a secondary 78513351Sguido * address. 78613351Sguido */ 78713351Sguido ia->ia_subnetmask != (u_long)0xffffffff) 7881541Srgrimes return 1; 7891541Srgrimes return (0); 7901541Srgrimes#undef ia 7911541Srgrimes} 7921541Srgrimes/* 7931541Srgrimes * Add an address to the list of IP multicast addresses for a given interface. 7941541Srgrimes */ 7951541Srgrimesstruct in_multi * 7961541Srgrimesin_addmulti(ap, ifp) 7971541Srgrimes register struct in_addr *ap; 7981541Srgrimes register struct ifnet *ifp; 7991541Srgrimes{ 8001541Srgrimes register struct in_multi *inm; 80121666Swollman int error; 80221666Swollman struct sockaddr_in sin; 80321666Swollman struct ifmultiaddr *ifma; 8041541Srgrimes int s = splnet(); 8051541Srgrimes 8061541Srgrimes /* 80721666Swollman * Call generic routine to add membership or increment 80821666Swollman * refcount. It wants addresses in the form of a sockaddr, 80921666Swollman * so we build one here (being careful to zero the unused bytes). 8101541Srgrimes */ 81121666Swollman bzero(&sin, sizeof sin); 81221666Swollman sin.sin_family = AF_INET; 81321666Swollman sin.sin_len = sizeof sin; 81421666Swollman sin.sin_addr = *ap; 81521666Swollman error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma); 81621666Swollman if (error) { 81721666Swollman splx(s); 81821666Swollman return 0; 8191541Srgrimes } 8207280Swollman 82121666Swollman /* 82221666Swollman * If ifma->ifma_protospec is null, then if_addmulti() created 82321666Swollman * a new record. Otherwise, we are done. 82421666Swollman */ 82564853Sbde if (ifma->ifma_protospec != 0) { 82664853Sbde splx(s); 82721666Swollman return ifma->ifma_protospec; 82864853Sbde } 82921666Swollman 83021666Swollman /* XXX - if_addmulti uses M_WAITOK. Can this really be called 83121666Swollman at interrupt time? If so, need to fix if_addmulti. XXX */ 83269781Sdwmalone inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR, 83369781Sdwmalone M_NOWAIT | M_ZERO); 83421666Swollman if (inm == NULL) { 83521666Swollman splx(s); 83621666Swollman return (NULL); 8371541Srgrimes } 83821666Swollman 83921666Swollman inm->inm_addr = *ap; 84021666Swollman inm->inm_ifp = ifp; 84121666Swollman inm->inm_ifma = ifma; 84221666Swollman ifma->ifma_protospec = inm; 84321666Swollman LIST_INSERT_HEAD(&in_multihead, inm, inm_link); 84421666Swollman 84521666Swollman /* 84621666Swollman * Let IGMP know that we have joined a new IP multicast group. 84721666Swollman */ 84821666Swollman igmp_joingroup(inm); 8491541Srgrimes splx(s); 8501541Srgrimes return (inm); 8511541Srgrimes} 8521541Srgrimes 8531541Srgrimes/* 8541541Srgrimes * Delete a multicast address record. 8551541Srgrimes */ 8561549Srgrimesvoid 8571541Srgrimesin_delmulti(inm) 8581541Srgrimes register struct in_multi *inm; 8591541Srgrimes{ 86021666Swollman struct ifmultiaddr *ifma = inm->inm_ifma; 86145997Sluigi struct in_multi my_inm; 8621541Srgrimes int s = splnet(); 8631541Srgrimes 86445997Sluigi my_inm.inm_ifp = NULL ; /* don't send the leave msg */ 86521666Swollman if (ifma->ifma_refcount == 1) { 8661541Srgrimes /* 8671541Srgrimes * No remaining claims to this record; let IGMP know that 8681541Srgrimes * we are leaving the multicast group. 86945997Sluigi * But do it after the if_delmulti() which might reset 87045997Sluigi * the interface and nuke the packet. 8711541Srgrimes */ 87245997Sluigi my_inm = *inm ; 87321666Swollman ifma->ifma_protospec = 0; 87421666Swollman LIST_REMOVE(inm, inm_link); 8751541Srgrimes free(inm, M_IPMADDR); 8761541Srgrimes } 87721666Swollman /* XXX - should be separate API for when we have an ifma? */ 87821666Swollman if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); 87945997Sluigi if (my_inm.inm_ifp != NULL) 88045997Sluigi igmp_leavegroup(&my_inm); 8811541Srgrimes splx(s); 8821541Srgrimes} 883