in.c revision 74299
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 74299 2001-03-15 14:52:12Z ru $ 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> 511541Srgrimes 526363Sphk#include <netinet/igmp_var.h> 536363Sphk 5455009Sshin#include "gif.h" 5555009Sshin#if NGIF > 0 5655009Sshin#include <net/if_gif.h> 5755009Sshin#endif 5855009Sshin 5930354Sphkstatic MALLOC_DEFINE(M_IPMADDR, "in_multi", "internet multicast address"); 6030309Sphk 6155009Sshinstatic int in_mask2len __P((struct in_addr *)); 6255009Sshinstatic void in_len2mask __P((struct in_addr *, int)); 6355009Sshinstatic int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, 6455009Sshin struct ifnet *, struct proc *)); 6555009Sshin 6612296Sphkstatic void in_socktrim __P((struct sockaddr_in *)); 6712296Sphkstatic int in_ifinit __P((struct ifnet *, 6812296Sphk struct in_ifaddr *, struct sockaddr_in *, int)); 691541Srgrimes 7018193Swollmanstatic int subnetsarelocal = 0; 7112704SphkSYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, 7212704Sphk &subnetsarelocal, 0, ""); 7321666Swollman 7421666Swollmanstruct in_multihead in_multihead; /* XXX BSS initialization */ 7521666Swollman 761541Srgrimes/* 771541Srgrimes * Return 1 if an internet address is for a ``local'' host 781541Srgrimes * (one to which we have a connection). If subnetsarelocal 791541Srgrimes * is true, this includes other subnets of the local net. 801541Srgrimes * Otherwise, it includes only the directly-connected (sub)nets. 811541Srgrimes */ 821549Srgrimesint 831541Srgrimesin_localaddr(in) 841541Srgrimes struct in_addr in; 851541Srgrimes{ 861541Srgrimes register u_long i = ntohl(in.s_addr); 871541Srgrimes register struct in_ifaddr *ia; 881541Srgrimes 891541Srgrimes if (subnetsarelocal) { 9071999Sphk for (ia = TAILQ_FIRST(&in_ifaddrhead); ia; 9171999Sphk ia = TAILQ_NEXT(ia, ia_link)) 921541Srgrimes if ((i & ia->ia_netmask) == ia->ia_net) 931541Srgrimes return (1); 941541Srgrimes } else { 9572012Sphk TAILQ_FOREACH(ia, &in_ifaddrhead, ia_link) 961541Srgrimes if ((i & ia->ia_subnetmask) == ia->ia_subnet) 971541Srgrimes return (1); 981541Srgrimes } 991541Srgrimes return (0); 1001541Srgrimes} 1011541Srgrimes 1021541Srgrimes/* 1031541Srgrimes * Determine whether an IP address is in a reserved set of addresses 1041541Srgrimes * that may not be forwarded, or whether datagrams to that destination 1051541Srgrimes * may be forwarded. 1061541Srgrimes */ 1071549Srgrimesint 1081541Srgrimesin_canforward(in) 1091541Srgrimes struct in_addr in; 1101541Srgrimes{ 1111541Srgrimes register u_long i = ntohl(in.s_addr); 1121541Srgrimes register u_long net; 1131541Srgrimes 1141541Srgrimes if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i)) 1151541Srgrimes return (0); 1161541Srgrimes if (IN_CLASSA(i)) { 1171541Srgrimes net = i & IN_CLASSA_NET; 1181541Srgrimes if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) 1191541Srgrimes return (0); 1201541Srgrimes } 1211541Srgrimes return (1); 1221541Srgrimes} 1231541Srgrimes 1241541Srgrimes/* 1251541Srgrimes * Trim a mask in a sockaddr 1261541Srgrimes */ 12712296Sphkstatic void 1281541Srgrimesin_socktrim(ap) 1291541Srgrimesstruct sockaddr_in *ap; 1301541Srgrimes{ 1311541Srgrimes register char *cplim = (char *) &ap->sin_addr; 1321541Srgrimes register char *cp = (char *) (&ap->sin_addr + 1); 1331541Srgrimes 1341541Srgrimes ap->sin_len = 0; 1354127Swollman while (--cp >= cplim) 1361541Srgrimes if (*cp) { 1371541Srgrimes (ap)->sin_len = cp - (char *) (ap) + 1; 1381541Srgrimes break; 1391541Srgrimes } 1401541Srgrimes} 1411541Srgrimes 14255009Sshinstatic int 14355009Sshinin_mask2len(mask) 14455009Sshin struct in_addr *mask; 14555009Sshin{ 14655009Sshin int x, y; 14755009Sshin u_char *p; 14855009Sshin 14955009Sshin p = (u_char *)mask; 15055009Sshin for (x = 0; x < sizeof(*mask); x++) { 15155009Sshin if (p[x] != 0xff) 15255009Sshin break; 15355009Sshin } 15455009Sshin y = 0; 15555009Sshin if (x < sizeof(*mask)) { 15655009Sshin for (y = 0; y < 8; y++) { 15755009Sshin if ((p[x] & (0x80 >> y)) == 0) 15855009Sshin break; 15955009Sshin } 16055009Sshin } 16155009Sshin return x * 8 + y; 16255009Sshin} 16355009Sshin 16455009Sshinstatic void 16555009Sshinin_len2mask(mask, len) 16655009Sshin struct in_addr *mask; 16755009Sshin int len; 16855009Sshin{ 16955009Sshin int i; 17055009Sshin u_char *p; 17155009Sshin 17255009Sshin p = (u_char *)mask; 17355009Sshin bzero(mask, sizeof(*mask)); 17455009Sshin for (i = 0; i < len / 8; i++) 17555009Sshin p[i] = 0xff; 17655009Sshin if (len % 8) 17755009Sshin p[i] = (0xff00 >> (len % 8)) & 0xff; 17855009Sshin} 17955009Sshin 18012704Sphkstatic int in_interfaces; /* number of external internet interfaces */ 1811541Srgrimes 1821541Srgrimes/* 1831541Srgrimes * Generic internet control operations (ioctl's). 1841541Srgrimes * Ifp is 0 if not an interface-specific ioctl. 1851541Srgrimes */ 1861541Srgrimes/* ARGSUSED */ 1871549Srgrimesint 18825201Swollmanin_control(so, cmd, data, ifp, p) 1891541Srgrimes struct socket *so; 19036735Sdfr u_long cmd; 1911541Srgrimes caddr_t data; 1921541Srgrimes register struct ifnet *ifp; 19325201Swollman struct proc *p; 1941541Srgrimes{ 1951541Srgrimes register struct ifreq *ifr = (struct ifreq *)data; 19614632Sfenner register struct in_ifaddr *ia = 0, *iap; 1971541Srgrimes register struct ifaddr *ifa; 1981541Srgrimes struct in_ifaddr *oia; 1991541Srgrimes struct in_aliasreq *ifra = (struct in_aliasreq *)data; 2001541Srgrimes struct sockaddr_in oldaddr; 20115092Sdg int error, hostIsNew, maskIsNew, s; 2021541Srgrimes u_long i; 2031541Srgrimes 20455009Sshin#if NGIF > 0 20555009Sshin if (ifp && ifp->if_type == IFT_GIF) { 20655009Sshin switch (cmd) { 20755009Sshin case SIOCSIFPHYADDR: 20862587Sitojun case SIOCDIFPHYADDR: 20955009Sshin if (p && 21055009Sshin (error = suser(p)) != 0) 21155009Sshin return(error); 21255009Sshin case SIOCGIFPSRCADDR: 21355009Sshin case SIOCGIFPDSTADDR: 21455009Sshin return gif_ioctl(ifp, cmd, data); 21555009Sshin } 21655009Sshin } 21755009Sshin#endif 21855009Sshin 21955009Sshin switch (cmd) { 22055009Sshin case SIOCALIFADDR: 22155009Sshin case SIOCDLIFADDR: 22255009Sshin if (p && (error = suser(p)) != 0) 22355009Sshin return error; 22455009Sshin /*fall through*/ 22555009Sshin case SIOCGLIFADDR: 22655009Sshin if (!ifp) 22755009Sshin return EINVAL; 22855009Sshin return in_lifaddr_ioctl(so, cmd, data, ifp, p); 22955009Sshin } 23055009Sshin 2311541Srgrimes /* 2321541Srgrimes * Find address for this interface, if it exists. 23314632Sfenner * 23414632Sfenner * If an alias address was specified, find that one instead of 23514632Sfenner * the first one on the interface. 2361541Srgrimes */ 2371541Srgrimes if (ifp) 23871999Sphk for (iap = TAILQ_FIRST(&in_ifaddrhead); iap; 23971999Sphk iap = TAILQ_NEXT(iap, ia_link)) 24014632Sfenner if (iap->ia_ifp == ifp) { 24114632Sfenner if (((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr == 24214632Sfenner iap->ia_addr.sin_addr.s_addr) { 24314632Sfenner ia = iap; 24414632Sfenner break; 24514632Sfenner } else if (ia == NULL) { 24614632Sfenner ia = iap; 24714632Sfenner if (ifr->ifr_addr.sa_family != AF_INET) 24814632Sfenner break; 24914632Sfenner } 25014632Sfenner } 2511541Srgrimes 2521541Srgrimes switch (cmd) { 2531541Srgrimes 2541541Srgrimes case SIOCAIFADDR: 2551541Srgrimes case SIOCDIFADDR: 25641575Seivind if (ifp == 0) 25741575Seivind return (EADDRNOTAVAIL); 2588071Swollman if (ifra->ifra_addr.sin_family == AF_INET) { 25971999Sphk for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) { 2608071Swollman if (ia->ia_ifp == ifp && 2618071Swollman ia->ia_addr.sin_addr.s_addr == 2628071Swollman ifra->ifra_addr.sin_addr.s_addr) 2638071Swollman break; 2648071Swollman } 2658876Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) 2668071Swollman && (cmd == SIOCAIFADDR) 2678071Swollman && (ifra->ifra_dstaddr.sin_addr.s_addr 2688071Swollman == INADDR_ANY)) { 2699563Swollman return EDESTADDRREQ; 2708071Swollman } 2711541Srgrimes } 2721541Srgrimes if (cmd == SIOCDIFADDR && ia == 0) 2731541Srgrimes return (EADDRNOTAVAIL); 2741541Srgrimes /* FALLTHROUGH */ 2751541Srgrimes case SIOCSIFADDR: 2761541Srgrimes case SIOCSIFNETMASK: 2771541Srgrimes case SIOCSIFDSTADDR: 27846112Sphk if (p && (error = suser(p)) != 0) 27925201Swollman return error; 2801541Srgrimes 2811541Srgrimes if (ifp == 0) 28241575Seivind return (EADDRNOTAVAIL); 2831541Srgrimes if (ia == (struct in_ifaddr *)0) { 28420407Swollman ia = (struct in_ifaddr *) 28569781Sdwmalone malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO); 28620407Swollman if (ia == (struct in_ifaddr *)NULL) 2871541Srgrimes return (ENOBUFS); 28815092Sdg /* 28915092Sdg * Protect from ipintr() traversing address list 29015092Sdg * while we're modifying it. 29115092Sdg */ 29215092Sdg s = splnet(); 29320407Swollman 29420407Swollman TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link); 29520407Swollman ifa = &ia->ia_ifa; 29620407Swollman TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 29715092Sdg 29820407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 29920407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 30020407Swollman ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 3011541Srgrimes ia->ia_sockmask.sin_len = 8; 3021541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 3031541Srgrimes ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); 3041541Srgrimes ia->ia_broadaddr.sin_family = AF_INET; 3051541Srgrimes } 3061541Srgrimes ia->ia_ifp = ifp; 3078090Spst if (!(ifp->if_flags & IFF_LOOPBACK)) 3081541Srgrimes in_interfaces++; 30915092Sdg splx(s); 3101541Srgrimes } 3111541Srgrimes break; 3121541Srgrimes 3131541Srgrimes case SIOCSIFBRDADDR: 31446112Sphk if (p && (error = suser(p)) != 0) 31525201Swollman return error; 3161541Srgrimes /* FALLTHROUGH */ 3171541Srgrimes 3181541Srgrimes case SIOCGIFADDR: 3191541Srgrimes case SIOCGIFNETMASK: 3201541Srgrimes case SIOCGIFDSTADDR: 3211541Srgrimes case SIOCGIFBRDADDR: 3221541Srgrimes if (ia == (struct in_ifaddr *)0) 3231541Srgrimes return (EADDRNOTAVAIL); 3241541Srgrimes break; 3251541Srgrimes } 3261541Srgrimes switch (cmd) { 3271541Srgrimes 3281541Srgrimes case SIOCGIFADDR: 3291541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; 3301541Srgrimes break; 3311541Srgrimes 3321541Srgrimes case SIOCGIFBRDADDR: 3331541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 3341541Srgrimes return (EINVAL); 3351541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; 3361541Srgrimes break; 3371541Srgrimes 3381541Srgrimes case SIOCGIFDSTADDR: 3391541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 3401541Srgrimes return (EINVAL); 3411541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; 3421541Srgrimes break; 3431541Srgrimes 3441541Srgrimes case SIOCGIFNETMASK: 3451541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; 3461541Srgrimes break; 3471541Srgrimes 3481541Srgrimes case SIOCSIFDSTADDR: 3491541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 3501541Srgrimes return (EINVAL); 3511541Srgrimes oldaddr = ia->ia_dstaddr; 3521541Srgrimes ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr; 3531541Srgrimes if (ifp->if_ioctl && (error = (*ifp->if_ioctl) 3541541Srgrimes (ifp, SIOCSIFDSTADDR, (caddr_t)ia))) { 3551541Srgrimes ia->ia_dstaddr = oldaddr; 3561541Srgrimes return (error); 3571541Srgrimes } 3581541Srgrimes if (ia->ia_flags & IFA_ROUTE) { 3591541Srgrimes ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr; 3601541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 3611541Srgrimes ia->ia_ifa.ifa_dstaddr = 3621541Srgrimes (struct sockaddr *)&ia->ia_dstaddr; 3631541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP); 3641541Srgrimes } 3651541Srgrimes break; 3661541Srgrimes 3671541Srgrimes case SIOCSIFBRDADDR: 3681541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 3691541Srgrimes return (EINVAL); 3701541Srgrimes ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr; 3711541Srgrimes break; 3721541Srgrimes 3731541Srgrimes case SIOCSIFADDR: 3741541Srgrimes return (in_ifinit(ifp, ia, 3751541Srgrimes (struct sockaddr_in *) &ifr->ifr_addr, 1)); 3761541Srgrimes 3771541Srgrimes case SIOCSIFNETMASK: 3781541Srgrimes i = ifra->ifra_addr.sin_addr.s_addr; 3791541Srgrimes ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i); 3801541Srgrimes break; 3811541Srgrimes 3821541Srgrimes case SIOCAIFADDR: 3831541Srgrimes maskIsNew = 0; 3841541Srgrimes hostIsNew = 1; 3851541Srgrimes error = 0; 3861541Srgrimes if (ia->ia_addr.sin_family == AF_INET) { 3871541Srgrimes if (ifra->ifra_addr.sin_len == 0) { 3881541Srgrimes ifra->ifra_addr = ia->ia_addr; 3891541Srgrimes hostIsNew = 0; 3901541Srgrimes } else if (ifra->ifra_addr.sin_addr.s_addr == 3911541Srgrimes ia->ia_addr.sin_addr.s_addr) 3921541Srgrimes hostIsNew = 0; 3931541Srgrimes } 3941541Srgrimes if (ifra->ifra_mask.sin_len) { 3951541Srgrimes in_ifscrub(ifp, ia); 3961541Srgrimes ia->ia_sockmask = ifra->ifra_mask; 3971541Srgrimes ia->ia_subnetmask = 3981541Srgrimes ntohl(ia->ia_sockmask.sin_addr.s_addr); 3991541Srgrimes maskIsNew = 1; 4001541Srgrimes } 4011541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) && 4021541Srgrimes (ifra->ifra_dstaddr.sin_family == AF_INET)) { 4031541Srgrimes in_ifscrub(ifp, ia); 4041541Srgrimes ia->ia_dstaddr = ifra->ifra_dstaddr; 4051541Srgrimes maskIsNew = 1; /* We lie; but the effect's the same */ 4061541Srgrimes } 4071541Srgrimes if (ifra->ifra_addr.sin_family == AF_INET && 4081541Srgrimes (hostIsNew || maskIsNew)) 4091541Srgrimes error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0); 4101541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) && 4111541Srgrimes (ifra->ifra_broadaddr.sin_family == AF_INET)) 4121541Srgrimes ia->ia_broadaddr = ifra->ifra_broadaddr; 4131541Srgrimes return (error); 4141541Srgrimes 4151541Srgrimes case SIOCDIFADDR: 41674299Sru /* 41774299Sru * in_ifscrub kills the interface route. 41874299Sru */ 4191541Srgrimes in_ifscrub(ifp, ia); 42015092Sdg /* 42174299Sru * in_ifadown gets rid of all the rest of 42274299Sru * the routes. This is not quite the right 42374299Sru * thing to do, but at least if we are running 42474299Sru * a routing process they will come back. 42574299Sru */ 42674299Sru in_ifadown(&ia->ia_ifa); 42774299Sru 42874299Sru /* 42915092Sdg * Protect from ipintr() traversing address list 43015092Sdg * while we're modifying it. 43115092Sdg */ 43215092Sdg s = splnet(); 43315092Sdg 43420407Swollman ifa = &ia->ia_ifa; 43520407Swollman TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 4361541Srgrimes oia = ia; 43720407Swollman TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link); 43821666Swollman IFAFREE(&oia->ia_ifa); 43915092Sdg splx(s); 4401541Srgrimes break; 4411541Srgrimes 4421541Srgrimes default: 4431541Srgrimes if (ifp == 0 || ifp->if_ioctl == 0) 4441541Srgrimes return (EOPNOTSUPP); 4451541Srgrimes return ((*ifp->if_ioctl)(ifp, cmd, data)); 4461541Srgrimes } 4471541Srgrimes return (0); 4481541Srgrimes} 4491541Srgrimes 4501541Srgrimes/* 45155009Sshin * SIOC[GAD]LIFADDR. 45255009Sshin * SIOCGLIFADDR: get first address. (?!?) 45355009Sshin * SIOCGLIFADDR with IFLR_PREFIX: 45455009Sshin * get first address that matches the specified prefix. 45555009Sshin * SIOCALIFADDR: add the specified address. 45655009Sshin * SIOCALIFADDR with IFLR_PREFIX: 45755009Sshin * EINVAL since we can't deduce hostid part of the address. 45855009Sshin * SIOCDLIFADDR: delete the specified address. 45955009Sshin * SIOCDLIFADDR with IFLR_PREFIX: 46055009Sshin * delete the first address that matches the specified prefix. 46155009Sshin * return values: 46255009Sshin * EINVAL on invalid parameters 46355009Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 46455009Sshin * other values may be returned from in_ioctl() 46555009Sshin */ 46655009Sshinstatic int 46755009Sshinin_lifaddr_ioctl(so, cmd, data, ifp, p) 46855009Sshin struct socket *so; 46955009Sshin u_long cmd; 47055009Sshin caddr_t data; 47155009Sshin struct ifnet *ifp; 47255009Sshin struct proc *p; 47355009Sshin{ 47455009Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 47555009Sshin struct ifaddr *ifa; 47655009Sshin 47755009Sshin /* sanity checks */ 47855009Sshin if (!data || !ifp) { 47955009Sshin panic("invalid argument to in_lifaddr_ioctl"); 48055009Sshin /*NOTRECHED*/ 48155009Sshin } 48255009Sshin 48355009Sshin switch (cmd) { 48455009Sshin case SIOCGLIFADDR: 48555009Sshin /* address must be specified on GET with IFLR_PREFIX */ 48655009Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 48755009Sshin break; 48855009Sshin /*FALLTHROUGH*/ 48955009Sshin case SIOCALIFADDR: 49055009Sshin case SIOCDLIFADDR: 49155009Sshin /* address must be specified on ADD and DELETE */ 49255917Sshin if (iflr->addr.ss_family != AF_INET) 49355009Sshin return EINVAL; 49455917Sshin if (iflr->addr.ss_len != sizeof(struct sockaddr_in)) 49555009Sshin return EINVAL; 49655009Sshin /* XXX need improvement */ 49755917Sshin if (iflr->dstaddr.ss_family 49855917Sshin && iflr->dstaddr.ss_family != AF_INET) 49955009Sshin return EINVAL; 50055917Sshin if (iflr->dstaddr.ss_family 50155917Sshin && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in)) 50255009Sshin return EINVAL; 50355009Sshin break; 50455009Sshin default: /*shouldn't happen*/ 50555009Sshin return EOPNOTSUPP; 50655009Sshin } 50755009Sshin if (sizeof(struct in_addr) * 8 < iflr->prefixlen) 50855009Sshin return EINVAL; 50955009Sshin 51055009Sshin switch (cmd) { 51155009Sshin case SIOCALIFADDR: 51255009Sshin { 51355009Sshin struct in_aliasreq ifra; 51455009Sshin 51555009Sshin if (iflr->flags & IFLR_PREFIX) 51655009Sshin return EINVAL; 51755009Sshin 51855009Sshin /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ 51955009Sshin bzero(&ifra, sizeof(ifra)); 52055009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 52155009Sshin sizeof(ifra.ifra_name)); 52255009Sshin 52355917Sshin bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len); 52455009Sshin 52555917Sshin if (iflr->dstaddr.ss_family) { /*XXX*/ 52655009Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 52755917Sshin iflr->dstaddr.ss_len); 52855009Sshin } 52955009Sshin 53055009Sshin ifra.ifra_mask.sin_family = AF_INET; 53155009Sshin ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); 53255009Sshin in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); 53355009Sshin 53455009Sshin return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, p); 53555009Sshin } 53655009Sshin case SIOCGLIFADDR: 53755009Sshin case SIOCDLIFADDR: 53855009Sshin { 53955009Sshin struct in_ifaddr *ia; 54055009Sshin struct in_addr mask, candidate, match; 54155009Sshin struct sockaddr_in *sin; 54255009Sshin int cmp; 54355009Sshin 54455009Sshin bzero(&mask, sizeof(mask)); 54555009Sshin if (iflr->flags & IFLR_PREFIX) { 54655009Sshin /* lookup a prefix rather than address. */ 54755009Sshin in_len2mask(&mask, iflr->prefixlen); 54855009Sshin 54955009Sshin sin = (struct sockaddr_in *)&iflr->addr; 55055009Sshin match.s_addr = sin->sin_addr.s_addr; 55155009Sshin match.s_addr &= mask.s_addr; 55255009Sshin 55355009Sshin /* if you set extra bits, that's wrong */ 55455009Sshin if (match.s_addr != sin->sin_addr.s_addr) 55555009Sshin return EINVAL; 55655009Sshin 55755009Sshin cmp = 1; 55855009Sshin } else { 55955009Sshin if (cmd == SIOCGLIFADDR) { 56055009Sshin /* on getting an address, take the 1st match */ 56155009Sshin cmp = 0; /*XXX*/ 56255009Sshin } else { 56355009Sshin /* on deleting an address, do exact match */ 56455009Sshin in_len2mask(&mask, 32); 56555009Sshin sin = (struct sockaddr_in *)&iflr->addr; 56655009Sshin match.s_addr = sin->sin_addr.s_addr; 56755009Sshin 56855009Sshin cmp = 1; 56955009Sshin } 57055009Sshin } 57155009Sshin 57255009Sshin TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 57355009Sshin if (ifa->ifa_addr->sa_family != AF_INET6) 57455009Sshin continue; 57555009Sshin if (!cmp) 57655009Sshin break; 57755009Sshin candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr; 57855009Sshin candidate.s_addr &= mask.s_addr; 57955009Sshin if (candidate.s_addr == match.s_addr) 58055009Sshin break; 58155009Sshin } 58255009Sshin if (!ifa) 58355009Sshin return EADDRNOTAVAIL; 58455009Sshin ia = (struct in_ifaddr *)ifa; 58555009Sshin 58655009Sshin if (cmd == SIOCGLIFADDR) { 58755009Sshin /* fill in the if_laddrreq structure */ 58855009Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len); 58955009Sshin 59055009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 59155009Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 59255009Sshin ia->ia_dstaddr.sin_len); 59355009Sshin } else 59455009Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 59555009Sshin 59655009Sshin iflr->prefixlen = 59755009Sshin in_mask2len(&ia->ia_sockmask.sin_addr); 59855009Sshin 59955009Sshin iflr->flags = 0; /*XXX*/ 60055009Sshin 60155009Sshin return 0; 60255009Sshin } else { 60355009Sshin struct in_aliasreq ifra; 60455009Sshin 60555009Sshin /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ 60655009Sshin bzero(&ifra, sizeof(ifra)); 60755009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 60855009Sshin sizeof(ifra.ifra_name)); 60955009Sshin 61055009Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 61155009Sshin ia->ia_addr.sin_len); 61255009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 61355009Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 61455009Sshin ia->ia_dstaddr.sin_len); 61555009Sshin } 61655009Sshin bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr, 61755009Sshin ia->ia_sockmask.sin_len); 61855009Sshin 61955009Sshin return in_control(so, SIOCDIFADDR, (caddr_t)&ifra, 62055009Sshin ifp, p); 62155009Sshin } 62255009Sshin } 62355009Sshin } 62455009Sshin 62555009Sshin return EOPNOTSUPP; /*just for safety*/ 62655009Sshin} 62755009Sshin 62855009Sshin/* 6291541Srgrimes * Delete any existing route for an interface. 6301541Srgrimes */ 63122672Swollmanvoid 6321541Srgrimesin_ifscrub(ifp, ia) 6331541Srgrimes register struct ifnet *ifp; 6341541Srgrimes register struct in_ifaddr *ia; 6351541Srgrimes{ 6361541Srgrimes 6371541Srgrimes if ((ia->ia_flags & IFA_ROUTE) == 0) 6381541Srgrimes return; 6391541Srgrimes if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT)) 6401541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST); 6411541Srgrimes else 6421541Srgrimes rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0); 6431541Srgrimes ia->ia_flags &= ~IFA_ROUTE; 6441541Srgrimes} 6451541Srgrimes 6461541Srgrimes/* 6471541Srgrimes * Initialize an interface's internet address 6481541Srgrimes * and routing table entry. 6491541Srgrimes */ 65012296Sphkstatic int 6511541Srgrimesin_ifinit(ifp, ia, sin, scrub) 6521541Srgrimes register struct ifnet *ifp; 6531541Srgrimes register struct in_ifaddr *ia; 6541541Srgrimes struct sockaddr_in *sin; 6551541Srgrimes int scrub; 6561541Srgrimes{ 6571541Srgrimes register u_long i = ntohl(sin->sin_addr.s_addr); 6581541Srgrimes struct sockaddr_in oldaddr; 6592112Swollman int s = splimp(), flags = RTF_UP, error; 6601541Srgrimes 6611541Srgrimes oldaddr = ia->ia_addr; 6621541Srgrimes ia->ia_addr = *sin; 6631541Srgrimes /* 6641541Srgrimes * Give the interface a chance to initialize 6651541Srgrimes * if this is its first address, 6661541Srgrimes * and to validate the address if necessary. 6671541Srgrimes */ 6681541Srgrimes if (ifp->if_ioctl && 6691541Srgrimes (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) { 6701541Srgrimes splx(s); 6711541Srgrimes ia->ia_addr = oldaddr; 6721541Srgrimes return (error); 6731541Srgrimes } 6741541Srgrimes splx(s); 6751541Srgrimes if (scrub) { 6761541Srgrimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr; 6771541Srgrimes in_ifscrub(ifp, ia); 6781541Srgrimes ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; 6791541Srgrimes } 6801541Srgrimes if (IN_CLASSA(i)) 6811541Srgrimes ia->ia_netmask = IN_CLASSA_NET; 6821541Srgrimes else if (IN_CLASSB(i)) 6831541Srgrimes ia->ia_netmask = IN_CLASSB_NET; 6841541Srgrimes else 6851541Srgrimes ia->ia_netmask = IN_CLASSC_NET; 6861541Srgrimes /* 6871541Srgrimes * The subnet mask usually includes at least the standard network part, 6881541Srgrimes * but may may be smaller in the case of supernetting. 6891541Srgrimes * If it is set, we believe it. 6901541Srgrimes */ 6911541Srgrimes if (ia->ia_subnetmask == 0) { 6921541Srgrimes ia->ia_subnetmask = ia->ia_netmask; 6931541Srgrimes ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); 6941541Srgrimes } else 6951541Srgrimes ia->ia_netmask &= ia->ia_subnetmask; 6961541Srgrimes ia->ia_net = i & ia->ia_netmask; 6971541Srgrimes ia->ia_subnet = i & ia->ia_subnetmask; 6981541Srgrimes in_socktrim(&ia->ia_sockmask); 6991541Srgrimes /* 7001541Srgrimes * Add route for the network. 7011541Srgrimes */ 7021541Srgrimes ia->ia_ifa.ifa_metric = ifp->if_metric; 7031541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 7041541Srgrimes ia->ia_broadaddr.sin_addr.s_addr = 7051541Srgrimes htonl(ia->ia_subnet | ~ia->ia_subnetmask); 7061541Srgrimes ia->ia_netbroadcast.s_addr = 7071541Srgrimes htonl(ia->ia_net | ~ ia->ia_netmask); 7081541Srgrimes } else if (ifp->if_flags & IFF_LOOPBACK) { 7091541Srgrimes ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr; 7101541Srgrimes flags |= RTF_HOST; 7111541Srgrimes } else if (ifp->if_flags & IFF_POINTOPOINT) { 7121541Srgrimes if (ia->ia_dstaddr.sin_family != AF_INET) 7131541Srgrimes return (0); 7141541Srgrimes flags |= RTF_HOST; 7151541Srgrimes } 7161541Srgrimes if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0) 7171541Srgrimes ia->ia_flags |= IFA_ROUTE; 7187280Swollman 7191541Srgrimes /* 7201541Srgrimes * If the interface supports multicast, join the "all hosts" 7211541Srgrimes * multicast group on that interface. 7221541Srgrimes */ 7231541Srgrimes if (ifp->if_flags & IFF_MULTICAST) { 7241541Srgrimes struct in_addr addr; 7251541Srgrimes 7261541Srgrimes addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 7271541Srgrimes in_addmulti(&addr, ifp); 7281541Srgrimes } 7291541Srgrimes return (error); 7301541Srgrimes} 7311541Srgrimes 7321541Srgrimes 7331541Srgrimes/* 7341541Srgrimes * Return 1 if the address might be a local broadcast address. 7351541Srgrimes */ 7361549Srgrimesint 7371541Srgrimesin_broadcast(in, ifp) 7381541Srgrimes struct in_addr in; 7391541Srgrimes struct ifnet *ifp; 7401541Srgrimes{ 7411541Srgrimes register struct ifaddr *ifa; 7421541Srgrimes u_long t; 7431541Srgrimes 7441541Srgrimes if (in.s_addr == INADDR_BROADCAST || 7451541Srgrimes in.s_addr == INADDR_ANY) 7461541Srgrimes return 1; 7471541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 7481541Srgrimes return 0; 7491541Srgrimes t = ntohl(in.s_addr); 7501541Srgrimes /* 7511541Srgrimes * Look through the list of addresses for a match 7521541Srgrimes * with a broadcast address. 7531541Srgrimes */ 7541541Srgrimes#define ia ((struct in_ifaddr *)ifa) 75571999Sphk for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 75671999Sphk ifa = TAILQ_NEXT(ifa, ifa_link)) 7571541Srgrimes if (ifa->ifa_addr->sa_family == AF_INET && 7581541Srgrimes (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || 7591541Srgrimes in.s_addr == ia->ia_netbroadcast.s_addr || 7601541Srgrimes /* 7611541Srgrimes * Check for old-style (host 0) broadcast. 7621541Srgrimes */ 76313351Sguido t == ia->ia_subnet || t == ia->ia_net) && 76413351Sguido /* 76513351Sguido * Check for an all one subnetmask. These 76613351Sguido * only exist when an interface gets a secondary 76713351Sguido * address. 76813351Sguido */ 76913351Sguido ia->ia_subnetmask != (u_long)0xffffffff) 7701541Srgrimes return 1; 7711541Srgrimes return (0); 7721541Srgrimes#undef ia 7731541Srgrimes} 7741541Srgrimes/* 7751541Srgrimes * Add an address to the list of IP multicast addresses for a given interface. 7761541Srgrimes */ 7771541Srgrimesstruct in_multi * 7781541Srgrimesin_addmulti(ap, ifp) 7791541Srgrimes register struct in_addr *ap; 7801541Srgrimes register struct ifnet *ifp; 7811541Srgrimes{ 7821541Srgrimes register struct in_multi *inm; 78321666Swollman int error; 78421666Swollman struct sockaddr_in sin; 78521666Swollman struct ifmultiaddr *ifma; 7861541Srgrimes int s = splnet(); 7871541Srgrimes 7881541Srgrimes /* 78921666Swollman * Call generic routine to add membership or increment 79021666Swollman * refcount. It wants addresses in the form of a sockaddr, 79121666Swollman * so we build one here (being careful to zero the unused bytes). 7921541Srgrimes */ 79321666Swollman bzero(&sin, sizeof sin); 79421666Swollman sin.sin_family = AF_INET; 79521666Swollman sin.sin_len = sizeof sin; 79621666Swollman sin.sin_addr = *ap; 79721666Swollman error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma); 79821666Swollman if (error) { 79921666Swollman splx(s); 80021666Swollman return 0; 8011541Srgrimes } 8027280Swollman 80321666Swollman /* 80421666Swollman * If ifma->ifma_protospec is null, then if_addmulti() created 80521666Swollman * a new record. Otherwise, we are done. 80621666Swollman */ 80764853Sbde if (ifma->ifma_protospec != 0) { 80864853Sbde splx(s); 80921666Swollman return ifma->ifma_protospec; 81064853Sbde } 81121666Swollman 81221666Swollman /* XXX - if_addmulti uses M_WAITOK. Can this really be called 81321666Swollman at interrupt time? If so, need to fix if_addmulti. XXX */ 81469781Sdwmalone inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR, 81569781Sdwmalone M_NOWAIT | M_ZERO); 81621666Swollman if (inm == NULL) { 81721666Swollman splx(s); 81821666Swollman return (NULL); 8191541Srgrimes } 82021666Swollman 82121666Swollman inm->inm_addr = *ap; 82221666Swollman inm->inm_ifp = ifp; 82321666Swollman inm->inm_ifma = ifma; 82421666Swollman ifma->ifma_protospec = inm; 82521666Swollman LIST_INSERT_HEAD(&in_multihead, inm, inm_link); 82621666Swollman 82721666Swollman /* 82821666Swollman * Let IGMP know that we have joined a new IP multicast group. 82921666Swollman */ 83021666Swollman igmp_joingroup(inm); 8311541Srgrimes splx(s); 8321541Srgrimes return (inm); 8331541Srgrimes} 8341541Srgrimes 8351541Srgrimes/* 8361541Srgrimes * Delete a multicast address record. 8371541Srgrimes */ 8381549Srgrimesvoid 8391541Srgrimesin_delmulti(inm) 8401541Srgrimes register struct in_multi *inm; 8411541Srgrimes{ 84221666Swollman struct ifmultiaddr *ifma = inm->inm_ifma; 84345997Sluigi struct in_multi my_inm; 8441541Srgrimes int s = splnet(); 8451541Srgrimes 84645997Sluigi my_inm.inm_ifp = NULL ; /* don't send the leave msg */ 84721666Swollman if (ifma->ifma_refcount == 1) { 8481541Srgrimes /* 8491541Srgrimes * No remaining claims to this record; let IGMP know that 8501541Srgrimes * we are leaving the multicast group. 85145997Sluigi * But do it after the if_delmulti() which might reset 85245997Sluigi * the interface and nuke the packet. 8531541Srgrimes */ 85445997Sluigi my_inm = *inm ; 85521666Swollman ifma->ifma_protospec = 0; 85621666Swollman LIST_REMOVE(inm, inm_link); 8571541Srgrimes free(inm, M_IPMADDR); 8581541Srgrimes } 85921666Swollman /* XXX - should be separate API for when we have an ifma? */ 86021666Swollman if_delmulti(ifma->ifma_ifp, ifma->ifma_addr); 86145997Sluigi if (my_inm.inm_ifp != NULL) 86245997Sluigi igmp_leavegroup(&my_inm); 8631541Srgrimes splx(s); 8641541Srgrimes} 865