1139823Simp/*- 21541Srgrimes * Copyright (c) 1982, 1986, 1991, 1993 31541Srgrimes * The Regents of the University of California. All rights reserved. 4137668Smlaier * Copyright (C) 2001 WIDE Project. All rights reserved. 51541Srgrimes * 61541Srgrimes * Redistribution and use in source and binary forms, with or without 71541Srgrimes * modification, are permitted provided that the following conditions 81541Srgrimes * are met: 91541Srgrimes * 1. Redistributions of source code must retain the above copyright 101541Srgrimes * notice, this list of conditions and the following disclaimer. 111541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer in the 131541Srgrimes * documentation and/or other materials provided with the distribution. 141541Srgrimes * 4. Neither the name of the University nor the names of its contributors 151541Srgrimes * may be used to endorse or promote products derived from this software 161541Srgrimes * without specific prior written permission. 171541Srgrimes * 181541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 191541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 201541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 211541Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 221541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 231541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 241541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 251541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 261541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 271541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 281541Srgrimes * SUCH DAMAGE. 291541Srgrimes * 3010939Swollman * @(#)in.c 8.4 (Berkeley) 1/9/95 311541Srgrimes */ 321541Srgrimes 33172467Ssilby#include <sys/cdefs.h> 34172467Ssilby__FBSDID("$FreeBSD$"); 35172467Ssilby 36204902Sqingli#include "opt_mpath.h" 37143868Sglebius 381541Srgrimes#include <sys/param.h> 391549Srgrimes#include <sys/systm.h> 4024204Sbde#include <sys/sockio.h> 411541Srgrimes#include <sys/malloc.h> 42164033Srwatson#include <sys/priv.h> 431541Srgrimes#include <sys/socket.h> 44186948Sbz#include <sys/jail.h> 4512704Sphk#include <sys/kernel.h> 46186948Sbz#include <sys/proc.h> 4712704Sphk#include <sys/sysctl.h> 48192011Sqingli#include <sys/syslog.h> 491541Srgrimes 501541Srgrimes#include <net/if.h> 51195914Sqingli#include <net/if_var.h> 52215207Sgnn#include <net/if_arp.h> 53192011Sqingli#include <net/if_dl.h> 54186119Sqingli#include <net/if_llatbl.h> 5555009Sshin#include <net/if_types.h> 561541Srgrimes#include <net/route.h> 57192011Sqingli#include <net/vnet.h> 581541Srgrimes 59228571Sglebius#include <netinet/if_ether.h> 601541Srgrimes#include <netinet/in.h> 611541Srgrimes#include <netinet/in_var.h> 6281127Sume#include <netinet/in_pcb.h> 63170613Sbms#include <netinet/ip_var.h> 64228571Sglebius#include <netinet/ip_carp.h> 65189592Sbms#include <netinet/igmp_var.h> 66195699Srwatson#include <netinet/udp.h> 67195699Srwatson#include <netinet/udp_var.h> 681541Srgrimes 6992723Salfredstatic int in_mask2len(struct in_addr *); 7092723Salfredstatic void in_len2mask(struct in_addr *, int); 7192723Salfredstatic int in_lifaddr_ioctl(struct socket *, u_long, caddr_t, 7292723Salfred struct ifnet *, struct thread *); 7355009Sshin 7492723Salfredstatic void in_socktrim(struct sockaddr_in *); 75228571Sglebiusstatic int in_ifinit(struct ifnet *, struct in_ifaddr *, 76230207Sglebius struct sockaddr_in *, int, int); 77167729Sbmsstatic void in_purgemaddrs(struct ifnet *); 781541Srgrimes 79228571Sglebiusstatic VNET_DEFINE(int, nosameprefix); 80228571Sglebius#define V_nosameprefix VNET(nosameprefix) 81228571SglebiusSYSCTL_VNET_INT(_net_inet_ip, OID_AUTO, no_same_prefix, CTLFLAG_RW, 82228571Sglebius &VNET_NAME(nosameprefix), 0, 83149221Sglebius "Refuse to create same prefixes on different interfaces"); 8421666Swollman 85207369SbzVNET_DECLARE(struct inpcbinfo, ripcbinfo); 86207369Sbz#define V_ripcbinfo VNET(ripcbinfo) 87207369Sbz 881541Srgrimes/* 891541Srgrimes * Return 1 if an internet address is for a ``local'' host 90226401Sglebius * (one to which we have a connection). 911541Srgrimes */ 921549Srgrimesint 93169454Srwatsonin_localaddr(struct in_addr in) 941541Srgrimes{ 951541Srgrimes register u_long i = ntohl(in.s_addr); 961541Srgrimes register struct in_ifaddr *ia; 971541Srgrimes 98194951Srwatson IN_IFADDR_RLOCK(); 99226401Sglebius TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 100226401Sglebius if ((i & ia->ia_subnetmask) == ia->ia_subnet) { 101226401Sglebius IN_IFADDR_RUNLOCK(); 102226401Sglebius return (1); 103194951Srwatson } 1041541Srgrimes } 105194951Srwatson IN_IFADDR_RUNLOCK(); 1061541Srgrimes return (0); 1071541Srgrimes} 1081541Srgrimes 1091541Srgrimes/* 110133486Sandre * Return 1 if an internet address is for the local host and configured 111133486Sandre * on one of its interfaces. 112133486Sandre */ 113133486Sandreint 114169454Srwatsonin_localip(struct in_addr in) 115133486Sandre{ 116133486Sandre struct in_ifaddr *ia; 117133486Sandre 118194951Srwatson IN_IFADDR_RLOCK(); 119133486Sandre LIST_FOREACH(ia, INADDR_HASH(in.s_addr), ia_hash) { 120194951Srwatson if (IA_SIN(ia)->sin_addr.s_addr == in.s_addr) { 121194951Srwatson IN_IFADDR_RUNLOCK(); 122184295Sbz return (1); 123194951Srwatson } 124133486Sandre } 125194951Srwatson IN_IFADDR_RUNLOCK(); 126184295Sbz return (0); 127133486Sandre} 128133486Sandre 129133486Sandre/* 1301541Srgrimes * Determine whether an IP address is in a reserved set of addresses 1311541Srgrimes * that may not be forwarded, or whether datagrams to that destination 1321541Srgrimes * may be forwarded. 1331541Srgrimes */ 1341549Srgrimesint 135169454Srwatsonin_canforward(struct in_addr in) 1361541Srgrimes{ 1371541Srgrimes register u_long i = ntohl(in.s_addr); 1381541Srgrimes register u_long net; 1391541Srgrimes 140166450Sbms if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i) || IN_LINKLOCAL(i)) 1411541Srgrimes return (0); 1421541Srgrimes if (IN_CLASSA(i)) { 1431541Srgrimes net = i & IN_CLASSA_NET; 1441541Srgrimes if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) 1451541Srgrimes return (0); 1461541Srgrimes } 1471541Srgrimes return (1); 1481541Srgrimes} 1491541Srgrimes 1501541Srgrimes/* 1511541Srgrimes * Trim a mask in a sockaddr 1521541Srgrimes */ 15312296Sphkstatic void 154169454Srwatsonin_socktrim(struct sockaddr_in *ap) 1551541Srgrimes{ 1561541Srgrimes register char *cplim = (char *) &ap->sin_addr; 1571541Srgrimes register char *cp = (char *) (&ap->sin_addr + 1); 1581541Srgrimes 1591541Srgrimes ap->sin_len = 0; 1604127Swollman while (--cp >= cplim) 161133874Srwatson if (*cp) { 1621541Srgrimes (ap)->sin_len = cp - (char *) (ap) + 1; 1631541Srgrimes break; 1641541Srgrimes } 1651541Srgrimes} 1661541Srgrimes 16755009Sshinstatic int 16855009Sshinin_mask2len(mask) 16955009Sshin struct in_addr *mask; 17055009Sshin{ 17155009Sshin int x, y; 17255009Sshin u_char *p; 17355009Sshin 17455009Sshin p = (u_char *)mask; 17555009Sshin for (x = 0; x < sizeof(*mask); x++) { 17655009Sshin if (p[x] != 0xff) 17755009Sshin break; 17855009Sshin } 17955009Sshin y = 0; 18055009Sshin if (x < sizeof(*mask)) { 18155009Sshin for (y = 0; y < 8; y++) { 18255009Sshin if ((p[x] & (0x80 >> y)) == 0) 18355009Sshin break; 18455009Sshin } 18555009Sshin } 186184295Sbz return (x * 8 + y); 18755009Sshin} 18855009Sshin 18955009Sshinstatic void 190169454Srwatsonin_len2mask(struct in_addr *mask, int len) 19155009Sshin{ 19255009Sshin int i; 19355009Sshin u_char *p; 19455009Sshin 19555009Sshin p = (u_char *)mask; 19655009Sshin bzero(mask, sizeof(*mask)); 19755009Sshin for (i = 0; i < len / 8; i++) 19855009Sshin p[i] = 0xff; 19955009Sshin if (len % 8) 20055009Sshin p[i] = (0xff00 >> (len % 8)) & 0xff; 20155009Sshin} 20255009Sshin 2031541Srgrimes/* 2041541Srgrimes * Generic internet control operations (ioctl's). 205191443Srwatson * 206191443Srwatson * ifp is NULL if not an interface-specific ioctl. 2071541Srgrimes */ 2081541Srgrimes/* ARGSUSED */ 2091549Srgrimesint 210169454Srwatsonin_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp, 211169454Srwatson struct thread *td) 2121541Srgrimes{ 2131541Srgrimes register struct ifreq *ifr = (struct ifreq *)data; 214184295Sbz register struct in_ifaddr *ia, *iap; 2151541Srgrimes register struct ifaddr *ifa; 216168032Sbms struct in_addr allhosts_addr; 21784102Sjlemon struct in_addr dst; 218189592Sbms struct in_ifinfo *ii; 2191541Srgrimes struct in_aliasreq *ifra = (struct in_aliasreq *)data; 220194951Srwatson int error, hostIsNew, iaIsNew, maskIsNew; 221168032Sbms int iaIsFirst; 222228768Sglebius u_long ocmd = cmd; 2231541Srgrimes 224228768Sglebius /* 225228768Sglebius * Pre-10.x compat: OSIOCAIFADDR passes a shorter 226228768Sglebius * struct in_aliasreq, without ifra_vhid. 227228768Sglebius */ 228228768Sglebius if (cmd == OSIOCAIFADDR) 229228768Sglebius cmd = SIOCAIFADDR; 230228768Sglebius 231184295Sbz ia = NULL; 232168032Sbms iaIsFirst = 0; 23387124Sbrian iaIsNew = 0; 234168032Sbms allhosts_addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP); 23587124Sbrian 236191443Srwatson /* 237191443Srwatson * Filter out ioctls we implement directly; forward the rest on to 238191443Srwatson * in_lifaddr_ioctl() and ifp->if_ioctl(). 239191443Srwatson */ 24055009Sshin switch (cmd) { 241191443Srwatson case SIOCGIFADDR: 242191443Srwatson case SIOCGIFBRDADDR: 243191443Srwatson case SIOCGIFDSTADDR: 244191443Srwatson case SIOCGIFNETMASK: 245227791Sglebius case SIOCDIFADDR: 246227791Sglebius break; 247227791Sglebius case SIOCAIFADDR: 248227791Sglebius /* 249227791Sglebius * ifra_addr must be present and be of INET family. 250227791Sglebius * ifra_broadaddr and ifra_mask are optional. 251227791Sglebius */ 252227791Sglebius if (ifra->ifra_addr.sin_len != sizeof(struct sockaddr_in) || 253227791Sglebius ifra->ifra_addr.sin_family != AF_INET) 254227791Sglebius return (EINVAL); 255227791Sglebius if (ifra->ifra_broadaddr.sin_len != 0 && 256227831Sglebius (ifra->ifra_broadaddr.sin_len != 257227831Sglebius sizeof(struct sockaddr_in) || 258227791Sglebius ifra->ifra_broadaddr.sin_family != AF_INET)) 259227791Sglebius return (EINVAL); 260228768Sglebius#if 0 261228768Sglebius /* 262228768Sglebius * ifconfig(8) in pre-10.x doesn't set sin_family for the 263228768Sglebius * mask. The code is disabled for the 10.x timeline, to 264228768Sglebius * make SIOCAIFADDR compatible with 9.x ifconfig(8). 265228768Sglebius * The code should be enabled in 11.x 266228768Sglebius */ 267227791Sglebius if (ifra->ifra_mask.sin_len != 0 && 268227791Sglebius (ifra->ifra_mask.sin_len != sizeof(struct sockaddr_in) || 269227791Sglebius ifra->ifra_mask.sin_family != AF_INET)) 270227791Sglebius return (EINVAL); 271228768Sglebius#endif 272227791Sglebius break; 273191443Srwatson case SIOCSIFADDR: 274191443Srwatson case SIOCSIFBRDADDR: 275191443Srwatson case SIOCSIFDSTADDR: 276191443Srwatson case SIOCSIFNETMASK: 277230207Sglebius /* We no longer support that old commands. */ 278230207Sglebius return (EINVAL); 279191443Srwatson 28055009Sshin case SIOCALIFADDR: 281164033Srwatson if (td != NULL) { 282164033Srwatson error = priv_check(td, PRIV_NET_ADDIFADDR); 283164033Srwatson if (error) 284164033Srwatson return (error); 285164033Srwatson } 286184295Sbz if (ifp == NULL) 287184295Sbz return (EINVAL); 288164033Srwatson return in_lifaddr_ioctl(so, cmd, data, ifp, td); 289164033Srwatson 29055009Sshin case SIOCDLIFADDR: 291164033Srwatson if (td != NULL) { 292164033Srwatson error = priv_check(td, PRIV_NET_DELIFADDR); 293164033Srwatson if (error) 294164033Srwatson return (error); 295164033Srwatson } 296184295Sbz if (ifp == NULL) 297184295Sbz return (EINVAL); 298164033Srwatson return in_lifaddr_ioctl(so, cmd, data, ifp, td); 299164033Srwatson 30055009Sshin case SIOCGLIFADDR: 301184295Sbz if (ifp == NULL) 302184295Sbz return (EINVAL); 30383366Sjulian return in_lifaddr_ioctl(so, cmd, data, ifp, td); 304191443Srwatson 305191443Srwatson default: 306191443Srwatson if (ifp == NULL || ifp->if_ioctl == NULL) 307191443Srwatson return (EOPNOTSUPP); 308191443Srwatson return ((*ifp->if_ioctl)(ifp, cmd, data)); 30955009Sshin } 31055009Sshin 311191443Srwatson if (ifp == NULL) 312191443Srwatson return (EADDRNOTAVAIL); 313191443Srwatson 3141541Srgrimes /* 315191456Srwatson * Security checks before we get involved in any work. 316191456Srwatson */ 317191456Srwatson switch (cmd) { 318191456Srwatson case SIOCAIFADDR: 319191456Srwatson if (td != NULL) { 320191456Srwatson error = priv_check(td, PRIV_NET_ADDIFADDR); 321191456Srwatson if (error) 322191456Srwatson return (error); 323191456Srwatson } 324191456Srwatson break; 325191456Srwatson 326191456Srwatson case SIOCDIFADDR: 327191456Srwatson if (td != NULL) { 328191456Srwatson error = priv_check(td, PRIV_NET_DELIFADDR); 329191456Srwatson if (error) 330191456Srwatson return (error); 331191456Srwatson } 332191456Srwatson break; 333191456Srwatson } 334191456Srwatson 335191456Srwatson /* 3361541Srgrimes * Find address for this interface, if it exists. 33714632Sfenner * 338191443Srwatson * If an alias address was specified, find that one instead of the 339191443Srwatson * first one on the interface, if possible. 3401541Srgrimes */ 341191443Srwatson dst = ((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr; 342194951Srwatson IN_IFADDR_RLOCK(); 343191443Srwatson LIST_FOREACH(iap, INADDR_HASH(dst.s_addr), ia_hash) { 344191443Srwatson if (iap->ia_ifp == ifp && 345191443Srwatson iap->ia_addr.sin_addr.s_addr == dst.s_addr) { 346191443Srwatson if (td == NULL || prison_check_ip4(td->td_ucred, 347191443Srwatson &dst) == 0) 348191443Srwatson ia = iap; 349191443Srwatson break; 350191443Srwatson } 351191443Srwatson } 352194760Srwatson if (ia != NULL) 353194760Srwatson ifa_ref(&ia->ia_ifa); 354194951Srwatson IN_IFADDR_RUNLOCK(); 355191443Srwatson if (ia == NULL) { 356229621Sjhb IF_ADDR_RLOCK(ifp); 357191443Srwatson TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 358191443Srwatson iap = ifatoia(ifa); 359191443Srwatson if (iap->ia_addr.sin_family == AF_INET) { 360191443Srwatson if (td != NULL && 361191443Srwatson prison_check_ip4(td->td_ucred, 362191443Srwatson &iap->ia_addr.sin_addr) != 0) 363191443Srwatson continue; 364191443Srwatson ia = iap; 36584102Sjlemon break; 36684102Sjlemon } 367191443Srwatson } 368194760Srwatson if (ia != NULL) 369194760Srwatson ifa_ref(&ia->ia_ifa); 370229621Sjhb IF_ADDR_RUNLOCK(ifp); 37184102Sjlemon } 372191443Srwatson if (ia == NULL) 373191443Srwatson iaIsFirst = 1; 3741541Srgrimes 375191500Srwatson error = 0; 3761541Srgrimes switch (cmd) { 3771541Srgrimes case SIOCAIFADDR: 3781541Srgrimes case SIOCDIFADDR: 379227958Sglebius if (ifra->ifra_addr.sin_family == AF_INET) { 380194760Srwatson struct in_ifaddr *oia; 381194760Srwatson 382194951Srwatson IN_IFADDR_RLOCK(); 38371999Sphk for (oia = ia; ia; ia = TAILQ_NEXT(ia, ia_link)) { 3848071Swollman if (ia->ia_ifp == ifp && 3858071Swollman ia->ia_addr.sin_addr.s_addr == 3868071Swollman ifra->ifra_addr.sin_addr.s_addr) 3878071Swollman break; 3888071Swollman } 389194760Srwatson if (ia != NULL && ia != oia) 390194760Srwatson ifa_ref(&ia->ia_ifa); 391194760Srwatson if (oia != NULL && ia != oia) 392194760Srwatson ifa_free(&oia->ia_ifa); 393194951Srwatson IN_IFADDR_RUNLOCK(); 3948876Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) 3958071Swollman && (cmd == SIOCAIFADDR) 3968071Swollman && (ifra->ifra_dstaddr.sin_addr.s_addr 3978071Swollman == INADDR_ANY)) { 398191500Srwatson error = EDESTADDRREQ; 399194760Srwatson goto out; 4008071Swollman } 4011541Srgrimes } 402191500Srwatson if (cmd == SIOCDIFADDR && ia == NULL) { 403191500Srwatson error = EADDRNOTAVAIL; 404194760Srwatson goto out; 405191500Srwatson } 406184295Sbz if (ia == NULL) { 40720407Swollman ia = (struct in_ifaddr *) 408191500Srwatson malloc(sizeof *ia, M_IFADDR, M_NOWAIT | 409191500Srwatson M_ZERO); 410191500Srwatson if (ia == NULL) { 411191500Srwatson error = ENOBUFS; 412194760Srwatson goto out; 413191500Srwatson } 414191500Srwatson 41520407Swollman ifa = &ia->ia_ifa; 416194602Srwatson ifa_init(ifa); 41720407Swollman ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr; 41820407Swollman ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr; 41920407Swollman ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask; 420108033Shsu 4211541Srgrimes ia->ia_sockmask.sin_len = 8; 42285740Sdes ia->ia_sockmask.sin_family = AF_INET; 4231541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 4241541Srgrimes ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); 4251541Srgrimes ia->ia_broadaddr.sin_family = AF_INET; 4261541Srgrimes } 4271541Srgrimes ia->ia_ifp = ifp; 428151824Sglebius 429194760Srwatson ifa_ref(ifa); /* if_addrhead */ 430229621Sjhb IF_ADDR_WLOCK(ifp); 431191285Srwatson TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link); 432229621Sjhb IF_ADDR_WUNLOCK(ifp); 433194760Srwatson ifa_ref(ifa); /* in_ifaddrhead */ 434194951Srwatson IN_IFADDR_WLOCK(); 435181803Sbz TAILQ_INSERT_TAIL(&V_in_ifaddrhead, ia, ia_link); 436194951Srwatson IN_IFADDR_WUNLOCK(); 43787124Sbrian iaIsNew = 1; 4381541Srgrimes } 4391541Srgrimes break; 4401541Srgrimes 4411541Srgrimes case SIOCGIFADDR: 4421541Srgrimes case SIOCGIFNETMASK: 4431541Srgrimes case SIOCGIFDSTADDR: 4441541Srgrimes case SIOCGIFBRDADDR: 445191500Srwatson if (ia == NULL) { 446191500Srwatson error = EADDRNOTAVAIL; 447194760Srwatson goto out; 448191500Srwatson } 4491541Srgrimes break; 4501541Srgrimes } 451191500Srwatson 452191500Srwatson /* 453194760Srwatson * Most paths in this switch return directly or via out. Only paths 454194760Srwatson * that remove the address break in order to hit common removal code. 455191500Srwatson */ 4561541Srgrimes switch (cmd) { 4571541Srgrimes case SIOCGIFADDR: 4581541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr; 459194760Srwatson goto out; 4601541Srgrimes 4611541Srgrimes case SIOCGIFBRDADDR: 462191500Srwatson if ((ifp->if_flags & IFF_BROADCAST) == 0) { 463191500Srwatson error = EINVAL; 464194760Srwatson goto out; 465191500Srwatson } 4661541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr; 467194760Srwatson goto out; 4681541Srgrimes 4691541Srgrimes case SIOCGIFDSTADDR: 470191500Srwatson if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { 471191500Srwatson error = EINVAL; 472194760Srwatson goto out; 473191500Srwatson } 4741541Srgrimes *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr; 475194760Srwatson goto out; 4761541Srgrimes 4771541Srgrimes case SIOCGIFNETMASK: 4781541Srgrimes *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask; 479194760Srwatson goto out; 4801541Srgrimes 4811541Srgrimes case SIOCAIFADDR: 4821541Srgrimes maskIsNew = 0; 4831541Srgrimes hostIsNew = 1; 4841541Srgrimes error = 0; 485227959Sglebius if (ifra->ifra_addr.sin_addr.s_addr == 486227791Sglebius ia->ia_addr.sin_addr.s_addr) 487227791Sglebius hostIsNew = 0; 4881541Srgrimes if (ifra->ifra_mask.sin_len) { 489238945Sglebius /* 490197210Sqingli * QL: XXX 491197210Sqingli * Need to scrub the prefix here in case 492197210Sqingli * the issued command is SIOCAIFADDR with 493197210Sqingli * the same address, but with a different 494197210Sqingli * prefix length. And if the prefix length 495238945Sglebius * is the same as before, then the call is 496197210Sqingli * un-necessarily executed here. 497197210Sqingli */ 498222438Sqingli in_ifscrub(ifp, ia, LLE_STATIC); 4991541Srgrimes ia->ia_sockmask = ifra->ifra_mask; 50085740Sdes ia->ia_sockmask.sin_family = AF_INET; 5011541Srgrimes ia->ia_subnetmask = 502238945Sglebius ntohl(ia->ia_sockmask.sin_addr.s_addr); 5031541Srgrimes maskIsNew = 1; 5041541Srgrimes } 5051541Srgrimes if ((ifp->if_flags & IFF_POINTOPOINT) && 5061541Srgrimes (ifra->ifra_dstaddr.sin_family == AF_INET)) { 507222438Sqingli in_ifscrub(ifp, ia, LLE_STATIC); 5081541Srgrimes ia->ia_dstaddr = ifra->ifra_dstaddr; 5091541Srgrimes maskIsNew = 1; /* We lie; but the effect's the same */ 5101541Srgrimes } 511227801Sglebius if (hostIsNew || maskIsNew) 512230207Sglebius error = in_ifinit(ifp, ia, &ifra->ifra_addr, maskIsNew, 513230207Sglebius (ocmd == cmd ? ifra->ifra_vhid : 0)); 51487124Sbrian if (error != 0 && iaIsNew) 515201811Sqingli break; 51687124Sbrian 5171541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) && 518227791Sglebius ifra->ifra_broadaddr.sin_len) 5191541Srgrimes ia->ia_broadaddr = ifra->ifra_broadaddr; 520168032Sbms if (error == 0) { 521189603Sbms ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]); 522189592Sbms if (iaIsFirst && 523189592Sbms (ifp->if_flags & IFF_MULTICAST) != 0) { 524189592Sbms error = in_joingroup(ifp, &allhosts_addr, 525189592Sbms NULL, &ii->ii_allhosts); 526189592Sbms } 527126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 528168032Sbms } 529194760Srwatson goto out; 5301541Srgrimes 5311541Srgrimes case SIOCDIFADDR: 53274299Sru /* 53374299Sru * in_ifscrub kills the interface route. 53474299Sru */ 535222143Sqingli in_ifscrub(ifp, ia, LLE_STATIC); 536191500Srwatson 53715092Sdg /* 53874299Sru * in_ifadown gets rid of all the rest of 53974299Sru * the routes. This is not quite the right 54074299Sru * thing to do, but at least if we are running 54174299Sru * a routing process they will come back. 54274299Sru */ 54376469Sru in_ifadown(&ia->ia_ifa, 1); 544126264Smlaier EVENTHANDLER_INVOKE(ifaddr_event, ifp); 54587124Sbrian error = 0; 5461541Srgrimes break; 5471541Srgrimes 5481541Srgrimes default: 549191443Srwatson panic("in_control: unsupported ioctl"); 5501541Srgrimes } 55187124Sbrian 552228571Sglebius if (ia->ia_ifa.ifa_carp) 553228571Sglebius (*carp_detach_p)(&ia->ia_ifa); 554228571Sglebius 555229621Sjhb IF_ADDR_WLOCK(ifp); 556213932Sbz /* Re-check that ia is still part of the list. */ 557213932Sbz TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 558213932Sbz if (ifa == &ia->ia_ifa) 559213932Sbz break; 560213932Sbz } 561213932Sbz if (ifa == NULL) { 562213932Sbz /* 563213932Sbz * If we lost the race with another thread, there is no need to 564213932Sbz * try it again for the next loop as there is no other exit 565213932Sbz * path between here and out. 566213932Sbz */ 567229621Sjhb IF_ADDR_WUNLOCK(ifp); 568213932Sbz error = EADDRNOTAVAIL; 569213932Sbz goto out; 570213932Sbz } 571191285Srwatson TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); 572229621Sjhb IF_ADDR_WUNLOCK(ifp); 573239395Srrs ifa_free(&ia->ia_ifa); /* if_addrhead */ 574194951Srwatson 575194951Srwatson IN_IFADDR_WLOCK(); 576181803Sbz TAILQ_REMOVE(&V_in_ifaddrhead, ia, ia_link); 577194760Srwatson 578227791Sglebius LIST_REMOVE(ia, ia_hash); 579227791Sglebius IN_IFADDR_WUNLOCK(); 580227791Sglebius /* 581227791Sglebius * If this is the last IPv4 address configured on this 582227791Sglebius * interface, leave the all-hosts group. 583227791Sglebius * No state-change report need be transmitted. 584227791Sglebius */ 585227791Sglebius IFP_TO_IA(ifp, iap); 586227791Sglebius if (iap == NULL) { 587227791Sglebius ii = ((struct in_ifinfo *)ifp->if_afdata[AF_INET]); 588227791Sglebius IN_MULTI_LOCK(); 589227791Sglebius if (ii->ii_allhosts) { 590227791Sglebius (void)in_leavegroup_locked(ii->ii_allhosts, NULL); 591227791Sglebius ii->ii_allhosts = NULL; 592227791Sglebius } 593227791Sglebius IN_MULTI_UNLOCK(); 594194951Srwatson } else 595227791Sglebius ifa_free(&iap->ia_ifa); 596227791Sglebius 597194951Srwatson ifa_free(&ia->ia_ifa); /* in_ifaddrhead */ 598194760Srwatsonout: 599194760Srwatson if (ia != NULL) 600194760Srwatson ifa_free(&ia->ia_ifa); 60187124Sbrian return (error); 6021541Srgrimes} 6031541Srgrimes 6041541Srgrimes/* 60555009Sshin * SIOC[GAD]LIFADDR. 60655009Sshin * SIOCGLIFADDR: get first address. (?!?) 60755009Sshin * SIOCGLIFADDR with IFLR_PREFIX: 60855009Sshin * get first address that matches the specified prefix. 60955009Sshin * SIOCALIFADDR: add the specified address. 61055009Sshin * SIOCALIFADDR with IFLR_PREFIX: 61155009Sshin * EINVAL since we can't deduce hostid part of the address. 61255009Sshin * SIOCDLIFADDR: delete the specified address. 61355009Sshin * SIOCDLIFADDR with IFLR_PREFIX: 61455009Sshin * delete the first address that matches the specified prefix. 61555009Sshin * return values: 61655009Sshin * EINVAL on invalid parameters 61755009Sshin * EADDRNOTAVAIL on prefix match failed/specified address not found 61855009Sshin * other values may be returned from in_ioctl() 61955009Sshin */ 62055009Sshinstatic int 621169454Srwatsonin_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, 622169454Srwatson struct ifnet *ifp, struct thread *td) 62355009Sshin{ 62455009Sshin struct if_laddrreq *iflr = (struct if_laddrreq *)data; 62555009Sshin struct ifaddr *ifa; 62655009Sshin 62755009Sshin /* sanity checks */ 628184295Sbz if (data == NULL || ifp == NULL) { 62955009Sshin panic("invalid argument to in_lifaddr_ioctl"); 63055009Sshin /*NOTRECHED*/ 63155009Sshin } 63255009Sshin 63355009Sshin switch (cmd) { 63455009Sshin case SIOCGLIFADDR: 63555009Sshin /* address must be specified on GET with IFLR_PREFIX */ 63655009Sshin if ((iflr->flags & IFLR_PREFIX) == 0) 63755009Sshin break; 63855009Sshin /*FALLTHROUGH*/ 63955009Sshin case SIOCALIFADDR: 64055009Sshin case SIOCDLIFADDR: 64155009Sshin /* address must be specified on ADD and DELETE */ 64255917Sshin if (iflr->addr.ss_family != AF_INET) 643184295Sbz return (EINVAL); 64455917Sshin if (iflr->addr.ss_len != sizeof(struct sockaddr_in)) 645184295Sbz return (EINVAL); 64655009Sshin /* XXX need improvement */ 64755917Sshin if (iflr->dstaddr.ss_family 64855917Sshin && iflr->dstaddr.ss_family != AF_INET) 649184295Sbz return (EINVAL); 65055917Sshin if (iflr->dstaddr.ss_family 65155917Sshin && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in)) 652184295Sbz return (EINVAL); 65355009Sshin break; 65455009Sshin default: /*shouldn't happen*/ 655184295Sbz return (EOPNOTSUPP); 65655009Sshin } 65755009Sshin if (sizeof(struct in_addr) * 8 < iflr->prefixlen) 658184295Sbz return (EINVAL); 65955009Sshin 66055009Sshin switch (cmd) { 66155009Sshin case SIOCALIFADDR: 66255009Sshin { 66355009Sshin struct in_aliasreq ifra; 66455009Sshin 66555009Sshin if (iflr->flags & IFLR_PREFIX) 666184295Sbz return (EINVAL); 66755009Sshin 668229476Sjhb /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR). */ 66955009Sshin bzero(&ifra, sizeof(ifra)); 67055009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 67155009Sshin sizeof(ifra.ifra_name)); 67255009Sshin 67355917Sshin bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len); 67455009Sshin 67555917Sshin if (iflr->dstaddr.ss_family) { /*XXX*/ 67655009Sshin bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, 67755917Sshin iflr->dstaddr.ss_len); 67855009Sshin } 67955009Sshin 68055009Sshin ifra.ifra_mask.sin_family = AF_INET; 68155009Sshin ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); 68255009Sshin in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); 68355009Sshin 684184295Sbz return (in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, td)); 68555009Sshin } 68655009Sshin case SIOCGLIFADDR: 68755009Sshin case SIOCDLIFADDR: 68855009Sshin { 68955009Sshin struct in_ifaddr *ia; 69055009Sshin struct in_addr mask, candidate, match; 69155009Sshin struct sockaddr_in *sin; 69255009Sshin 69355009Sshin bzero(&mask, sizeof(mask)); 694170855Smjacob bzero(&match, sizeof(match)); 69555009Sshin if (iflr->flags & IFLR_PREFIX) { 69655009Sshin /* lookup a prefix rather than address. */ 69755009Sshin in_len2mask(&mask, iflr->prefixlen); 69855009Sshin 69955009Sshin sin = (struct sockaddr_in *)&iflr->addr; 70055009Sshin match.s_addr = sin->sin_addr.s_addr; 70155009Sshin match.s_addr &= mask.s_addr; 70255009Sshin 70355009Sshin /* if you set extra bits, that's wrong */ 70455009Sshin if (match.s_addr != sin->sin_addr.s_addr) 705184295Sbz return (EINVAL); 70655009Sshin 70755009Sshin } else { 708170855Smjacob /* on getting an address, take the 1st match */ 709170855Smjacob /* on deleting an address, do exact match */ 710170855Smjacob if (cmd != SIOCGLIFADDR) { 71155009Sshin in_len2mask(&mask, 32); 71255009Sshin sin = (struct sockaddr_in *)&iflr->addr; 71355009Sshin match.s_addr = sin->sin_addr.s_addr; 71455009Sshin } 71555009Sshin } 71655009Sshin 717229621Sjhb IF_ADDR_RLOCK(ifp); 71855009Sshin TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 719229476Sjhb if (ifa->ifa_addr->sa_family != AF_INET) 72055009Sshin continue; 721170855Smjacob if (match.s_addr == 0) 72255009Sshin break; 723229478Sjhb sin = (struct sockaddr_in *)&ifa->ifa_addr; 724229478Sjhb candidate.s_addr = sin->sin_addr.s_addr; 72555009Sshin candidate.s_addr &= mask.s_addr; 72655009Sshin if (candidate.s_addr == match.s_addr) 72755009Sshin break; 72855009Sshin } 729229477Sjhb if (ifa != NULL) 730229477Sjhb ifa_ref(ifa); 731229621Sjhb IF_ADDR_RUNLOCK(ifp); 732184295Sbz if (ifa == NULL) 733184295Sbz return (EADDRNOTAVAIL); 73455009Sshin ia = (struct in_ifaddr *)ifa; 73555009Sshin 73655009Sshin if (cmd == SIOCGLIFADDR) { 73755009Sshin /* fill in the if_laddrreq structure */ 73855009Sshin bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len); 73955009Sshin 74055009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 74155009Sshin bcopy(&ia->ia_dstaddr, &iflr->dstaddr, 74255009Sshin ia->ia_dstaddr.sin_len); 74355009Sshin } else 74455009Sshin bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); 74555009Sshin 74655009Sshin iflr->prefixlen = 74755009Sshin in_mask2len(&ia->ia_sockmask.sin_addr); 74855009Sshin 74955009Sshin iflr->flags = 0; /*XXX*/ 750229477Sjhb ifa_free(ifa); 75155009Sshin 752184295Sbz return (0); 75355009Sshin } else { 75455009Sshin struct in_aliasreq ifra; 75555009Sshin 756229476Sjhb /* fill in_aliasreq and do ioctl(SIOCDIFADDR) */ 75755009Sshin bzero(&ifra, sizeof(ifra)); 75855009Sshin bcopy(iflr->iflr_name, ifra.ifra_name, 75955009Sshin sizeof(ifra.ifra_name)); 76055009Sshin 76155009Sshin bcopy(&ia->ia_addr, &ifra.ifra_addr, 76255009Sshin ia->ia_addr.sin_len); 76355009Sshin if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { 76455009Sshin bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, 76555009Sshin ia->ia_dstaddr.sin_len); 76655009Sshin } 76755009Sshin bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr, 76855009Sshin ia->ia_sockmask.sin_len); 769229477Sjhb ifa_free(ifa); 77055009Sshin 771184295Sbz return (in_control(so, SIOCDIFADDR, (caddr_t)&ifra, 772184295Sbz ifp, td)); 77355009Sshin } 77455009Sshin } 77555009Sshin } 77655009Sshin 777184295Sbz return (EOPNOTSUPP); /*just for safety*/ 77855009Sshin} 77955009Sshin 78055009Sshin/* 7811541Srgrimes * Delete any existing route for an interface. 7821541Srgrimes */ 78322672Swollmanvoid 784222143Sqingliin_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia, u_int flags) 7851541Srgrimes{ 786169454Srwatson 787222143Sqingli in_scrubprefix(ia, flags); 7881541Srgrimes} 7891541Srgrimes 7901541Srgrimes/* 7911541Srgrimes * Initialize an interface's internet address 7921541Srgrimes * and routing table entry. 7931541Srgrimes */ 79412296Sphkstatic int 795169454Srwatsonin_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin, 796230207Sglebius int masksupplied, int vhid) 7971541Srgrimes{ 7981541Srgrimes register u_long i = ntohl(sin->sin_addr.s_addr); 799244665Sglebius int flags, error = 0; 8001541Srgrimes 801227791Sglebius IN_IFADDR_WLOCK(); 802227791Sglebius if (ia->ia_addr.sin_family == AF_INET) 803105748Ssuz LIST_REMOVE(ia, ia_hash); 8041541Srgrimes ia->ia_addr = *sin; 805227791Sglebius LIST_INSERT_HEAD(INADDR_HASH(ia->ia_addr.sin_addr.s_addr), 806227791Sglebius ia, ia_hash); 807227791Sglebius IN_IFADDR_WUNLOCK(); 808227791Sglebius 809228571Sglebius if (vhid > 0) { 810228571Sglebius if (carp_attach_p != NULL) 811228571Sglebius error = (*carp_attach_p)(&ia->ia_ifa, vhid); 812228571Sglebius else 813228571Sglebius error = EPROTONOSUPPORT; 814228571Sglebius } 815228571Sglebius if (error) 816228571Sglebius return (error); 817228571Sglebius 8181541Srgrimes /* 819244989Speter * Give the interface a chance to initialize 820244989Speter * if this is its first address, 821244989Speter * and to validate the address if necessary. 8221541Srgrimes */ 823227791Sglebius if (ifp->if_ioctl != NULL && 824227791Sglebius (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia)) != 0) 825146883Siedowse /* LIST_REMOVE(ia, ia_hash) is done in in_control */ 826146883Siedowse return (error); 827227791Sglebius 8281541Srgrimes /* 829226401Sglebius * Be compatible with network classes, if netmask isn't supplied, 830226401Sglebius * guess it based on classes. 8311541Srgrimes */ 832228313Sglebius if (!masksupplied) { 833226401Sglebius if (IN_CLASSA(i)) 834226401Sglebius ia->ia_subnetmask = IN_CLASSA_NET; 835226401Sglebius else if (IN_CLASSB(i)) 836226401Sglebius ia->ia_subnetmask = IN_CLASSB_NET; 837226401Sglebius else 838226401Sglebius ia->ia_subnetmask = IN_CLASSC_NET; 8391541Srgrimes ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask); 840226401Sglebius } 8411541Srgrimes ia->ia_subnet = i & ia->ia_subnetmask; 8421541Srgrimes in_socktrim(&ia->ia_sockmask); 843244665Sglebius 8441541Srgrimes /* 8451541Srgrimes * Add route for the network. 8461541Srgrimes */ 847244665Sglebius flags = RTF_UP; 8481541Srgrimes ia->ia_ifa.ifa_metric = ifp->if_metric; 8491541Srgrimes if (ifp->if_flags & IFF_BROADCAST) { 850226402Sglebius if (ia->ia_subnetmask == IN_RFC3021_MASK) 851226402Sglebius ia->ia_broadaddr.sin_addr.s_addr = INADDR_BROADCAST; 852226402Sglebius else 853226402Sglebius ia->ia_broadaddr.sin_addr.s_addr = 854226402Sglebius htonl(ia->ia_subnet | ~ia->ia_subnetmask); 8551541Srgrimes } else if (ifp->if_flags & IFF_LOOPBACK) { 856137833Smlaier ia->ia_dstaddr = ia->ia_addr; 8571541Srgrimes flags |= RTF_HOST; 8581541Srgrimes } else if (ifp->if_flags & IFF_POINTOPOINT) { 8591541Srgrimes if (ia->ia_dstaddr.sin_family != AF_INET) 8601541Srgrimes return (0); 8611541Srgrimes flags |= RTF_HOST; 8621541Srgrimes } 863228571Sglebius if (!vhid && (error = in_addprefix(ia, flags)) != 0) 864137628Smlaier return (error); 86594326Sbrian 866192085Sqingli if (ia->ia_addr.sin_addr.s_addr == INADDR_ANY) 867192085Sqingli return (0); 868192085Sqingli 869227791Sglebius if (ifp->if_flags & IFF_POINTOPOINT && 870227791Sglebius ia->ia_dstaddr.sin_addr.s_addr == ia->ia_addr.sin_addr.s_addr) 871203401Sqingli return (0); 872203401Sqingli 873192011Sqingli /* 874192011Sqingli * add a loopback route to self 875192011Sqingli */ 876228571Sglebius if (V_useloopback && !vhid && !(ifp->if_flags & IFF_LOOPBACK)) { 877201282Sqingli struct route ia_ro; 878201282Sqingli 879201282Sqingli bzero(&ia_ro, sizeof(ia_ro)); 880201282Sqingli *((struct sockaddr_in *)(&ia_ro.ro_dst)) = ia->ia_addr; 881231852Sbz rtalloc_ign_fib(&ia_ro, 0, RT_DEFAULT_FIB); 882201282Sqingli if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) && 883201282Sqingli (ia_ro.ro_rt->rt_ifp == V_loif)) { 884201282Sqingli RT_LOCK(ia_ro.ro_rt); 885201282Sqingli RT_ADDREF(ia_ro.ro_rt); 886201282Sqingli RTFREE_LOCKED(ia_ro.ro_rt); 887201282Sqingli } else 888238945Sglebius error = ifa_add_loopback_route((struct ifaddr *)ia, 889238945Sglebius (struct sockaddr *)&ia->ia_addr); 890201282Sqingli if (error == 0) 891201282Sqingli ia->ia_flags |= IFA_RTSELF; 892201282Sqingli if (ia_ro.ro_rt != NULL) 893201282Sqingli RTFREE(ia_ro.ro_rt); 894201282Sqingli } 895192011Sqingli 8961541Srgrimes return (error); 8971541Srgrimes} 8981541Srgrimes 899137628Smlaier#define rtinitflags(x) \ 900137628Smlaier ((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \ 901137628Smlaier ? RTF_HOST : 0) 902201285Sqingli 903137628Smlaier/* 904238945Sglebius * Generate a routing message when inserting or deleting 905201285Sqingli * an interface address alias. 906201285Sqingli */ 907238945Sglebiusstatic void in_addralias_rtmsg(int cmd, struct in_addr *prefix, 908201285Sqingli struct in_ifaddr *target) 909201285Sqingli{ 910201285Sqingli struct route pfx_ro; 911201285Sqingli struct sockaddr_in *pfx_addr; 912201285Sqingli struct rtentry msg_rt; 913201285Sqingli 914201285Sqingli /* QL: XXX 915201285Sqingli * This is a bit questionable because there is no 916201285Sqingli * additional route entry added/deleted for an address 917201285Sqingli * alias. Therefore this route report is inaccurate. 918201285Sqingli */ 919201285Sqingli bzero(&pfx_ro, sizeof(pfx_ro)); 920201285Sqingli pfx_addr = (struct sockaddr_in *)(&pfx_ro.ro_dst); 921201285Sqingli pfx_addr->sin_len = sizeof(*pfx_addr); 922201285Sqingli pfx_addr->sin_family = AF_INET; 923201285Sqingli pfx_addr->sin_addr = *prefix; 924201285Sqingli rtalloc_ign_fib(&pfx_ro, 0, 0); 925201285Sqingli if (pfx_ro.ro_rt != NULL) { 926201285Sqingli msg_rt = *pfx_ro.ro_rt; 927201285Sqingli 928201285Sqingli /* QL: XXX 929201285Sqingli * Point the gateway to the new interface 930238945Sglebius * address as if a new prefix route entry has 931238945Sglebius * been added through the new address alias. 932238945Sglebius * All other parts of the rtentry is accurate, 933201285Sqingli * e.g., rt_key, rt_mask, rt_ifp etc. 934201285Sqingli */ 935238945Sglebius msg_rt.rt_gateway = (struct sockaddr *)&target->ia_addr; 936238945Sglebius rt_newaddrmsg(cmd, (struct ifaddr *)target, 0, &msg_rt); 937201285Sqingli RTFREE(pfx_ro.ro_rt); 938201285Sqingli } 939201285Sqingli return; 940201285Sqingli} 941201285Sqingli 942201285Sqingli/* 943170855Smjacob * Check if we have a route for the given prefix already or add one accordingly. 944137628Smlaier */ 945228571Sglebiusint 946169454Srwatsonin_addprefix(struct in_ifaddr *target, int flags) 947137628Smlaier{ 948137628Smlaier struct in_ifaddr *ia; 949151555Sglebius struct in_addr prefix, mask, p, m; 950137628Smlaier int error; 9511541Srgrimes 952170855Smjacob if ((flags & RTF_HOST) != 0) { 953137628Smlaier prefix = target->ia_dstaddr.sin_addr; 954170855Smjacob mask.s_addr = 0; 955170855Smjacob } else { 956137628Smlaier prefix = target->ia_addr.sin_addr; 957137628Smlaier mask = target->ia_sockmask.sin_addr; 958137628Smlaier prefix.s_addr &= mask.s_addr; 959137628Smlaier } 960137628Smlaier 961194951Srwatson IN_IFADDR_RLOCK(); 962181803Sbz TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 963151555Sglebius if (rtinitflags(ia)) { 964224747Skevlo p = ia->ia_dstaddr.sin_addr; 965151555Sglebius 966151555Sglebius if (prefix.s_addr != p.s_addr) 967151555Sglebius continue; 968151555Sglebius } else { 969151555Sglebius p = ia->ia_addr.sin_addr; 970151555Sglebius m = ia->ia_sockmask.sin_addr; 971151555Sglebius p.s_addr &= m.s_addr; 972151555Sglebius 973151555Sglebius if (prefix.s_addr != p.s_addr || 974151555Sglebius mask.s_addr != m.s_addr) 975151555Sglebius continue; 976137628Smlaier } 977137628Smlaier 978137628Smlaier /* 979137628Smlaier * If we got a matching prefix route inserted by other 980137628Smlaier * interface address, we are done here. 981137628Smlaier */ 982149221Sglebius if (ia->ia_flags & IFA_ROUTE) { 983204902Sqingli#ifdef RADIX_MPATH 984238945Sglebius if (ia->ia_addr.sin_addr.s_addr == 985212209Sbz target->ia_addr.sin_addr.s_addr) { 986212209Sbz IN_IFADDR_RUNLOCK(); 987204902Sqingli return (EEXIST); 988212209Sbz } else 989204902Sqingli break; 990204902Sqingli#endif 991228571Sglebius if (V_nosameprefix) { 992194951Srwatson IN_IFADDR_RUNLOCK(); 993149221Sglebius return (EEXIST); 994194951Srwatson } else { 995201285Sqingli in_addralias_rtmsg(RTM_ADD, &prefix, target); 996194951Srwatson IN_IFADDR_RUNLOCK(); 997149221Sglebius return (0); 998194951Srwatson } 999149221Sglebius } 1000137628Smlaier } 1001194951Srwatson IN_IFADDR_RUNLOCK(); 1002137628Smlaier 1003137628Smlaier /* 1004137628Smlaier * No-one seem to have this prefix route, so we try to insert it. 1005137628Smlaier */ 1006137628Smlaier error = rtinit(&target->ia_ifa, (int)RTM_ADD, flags); 1007137628Smlaier if (!error) 1008137628Smlaier target->ia_flags |= IFA_ROUTE; 1009184295Sbz return (error); 1010137628Smlaier} 1011137628Smlaier 10121541Srgrimes/* 1013137628Smlaier * If there is no other address in the system that can serve a route to the 1014137628Smlaier * same prefix, remove the route. Hand over the route to the new address 1015137628Smlaier * otherwise. 1016137628Smlaier */ 1017228571Sglebiusint 1018222143Sqingliin_scrubprefix(struct in_ifaddr *target, u_int flags) 1019137628Smlaier{ 1020137628Smlaier struct in_ifaddr *ia; 1021228454Sglebius struct in_addr prefix, mask, p, m; 1022201282Sqingli int error = 0; 1023192476Sqingli struct sockaddr_in prefix0, mask0; 1024137628Smlaier 1025195914Sqingli /* 1026195914Sqingli * Remove the loopback route to the interface address. 1027195914Sqingli * The "useloopback" setting is not consulted because if the 1028195914Sqingli * user configures an interface address, turns off this 1029195914Sqingli * setting, and then tries to delete that interface address, 1030195914Sqingli * checking the current setting of "useloopback" would leave 1031195914Sqingli * that interface address loopback route untouched, which 1032195914Sqingli * would be wrong. Therefore the interface address loopback route 1033195914Sqingli * deletion is unconditional. 1034195914Sqingli */ 1035192085Sqingli if ((target->ia_addr.sin_addr.s_addr != INADDR_ANY) && 1036201282Sqingli !(target->ia_ifp->if_flags & IFF_LOOPBACK) && 1037201282Sqingli (target->ia_flags & IFA_RTSELF)) { 1038201282Sqingli struct route ia_ro; 1039201282Sqingli int freeit = 0; 1040201282Sqingli 1041201282Sqingli bzero(&ia_ro, sizeof(ia_ro)); 1042201282Sqingli *((struct sockaddr_in *)(&ia_ro.ro_dst)) = target->ia_addr; 1043201282Sqingli rtalloc_ign_fib(&ia_ro, 0, 0); 1044201282Sqingli if ((ia_ro.ro_rt != NULL) && (ia_ro.ro_rt->rt_ifp != NULL) && 1045201282Sqingli (ia_ro.ro_rt->rt_ifp == V_loif)) { 1046201282Sqingli RT_LOCK(ia_ro.ro_rt); 1047201282Sqingli if (ia_ro.ro_rt->rt_refcnt <= 1) 1048201282Sqingli freeit = 1; 1049226114Sqingli else if (flags & LLE_STATIC) { 1050201282Sqingli RT_REMREF(ia_ro.ro_rt); 1051226114Sqingli target->ia_flags &= ~IFA_RTSELF; 1052226114Sqingli } 1053201282Sqingli RTFREE_LOCKED(ia_ro.ro_rt); 1054201282Sqingli } 1055222143Sqingli if (freeit && (flags & LLE_STATIC)) { 1056201282Sqingli error = ifa_del_loopback_route((struct ifaddr *)target, 1057238945Sglebius (struct sockaddr *)&target->ia_addr); 1058222143Sqingli if (error == 0) 1059222143Sqingli target->ia_flags &= ~IFA_RTSELF; 1060222143Sqingli } 1061226120Sqingli if ((flags & LLE_STATIC) && 1062226120Sqingli !(target->ia_ifp->if_flags & IFF_NOARP)) 1063222143Sqingli /* remove arp cache */ 1064222143Sqingli arp_ifscrub(target->ia_ifp, IA_SIN(target)->sin_addr.s_addr); 1065192011Sqingli } 1066192011Sqingli 1067228454Sglebius if (rtinitflags(target)) { 1068137628Smlaier prefix = target->ia_dstaddr.sin_addr; 1069228454Sglebius mask.s_addr = 0; 1070228454Sglebius } else { 1071137628Smlaier prefix = target->ia_addr.sin_addr; 1072137628Smlaier mask = target->ia_sockmask.sin_addr; 1073137628Smlaier prefix.s_addr &= mask.s_addr; 1074137628Smlaier } 1075137628Smlaier 1076201285Sqingli if ((target->ia_flags & IFA_ROUTE) == 0) { 1077201285Sqingli in_addralias_rtmsg(RTM_DELETE, &prefix, target); 1078201285Sqingli return (0); 1079201285Sqingli } 1080201285Sqingli 1081194951Srwatson IN_IFADDR_RLOCK(); 1082181803Sbz TAILQ_FOREACH(ia, &V_in_ifaddrhead, ia_link) { 1083228454Sglebius if (rtinitflags(ia)) { 1084137628Smlaier p = ia->ia_dstaddr.sin_addr; 1085228454Sglebius 1086228454Sglebius if (prefix.s_addr != p.s_addr) 1087228454Sglebius continue; 1088228454Sglebius } else { 1089137628Smlaier p = ia->ia_addr.sin_addr; 1090228454Sglebius m = ia->ia_sockmask.sin_addr; 1091228454Sglebius p.s_addr &= m.s_addr; 1092228454Sglebius 1093228454Sglebius if (prefix.s_addr != p.s_addr || 1094228454Sglebius mask.s_addr != m.s_addr) 1095228454Sglebius continue; 1096137628Smlaier } 1097137628Smlaier 1098228454Sglebius if ((ia->ia_ifp->if_flags & IFF_UP) == 0) 1099137628Smlaier continue; 1100137628Smlaier 1101137628Smlaier /* 1102137628Smlaier * If we got a matching prefix address, move IFA_ROUTE and 1103137628Smlaier * the route itself to it. Make sure that routing daemons 1104137628Smlaier * get a heads-up. 1105137628Smlaier */ 1106228571Sglebius if ((ia->ia_flags & IFA_ROUTE) == 0) { 1107219828Spluknet ifa_ref(&ia->ia_ifa); 1108194951Srwatson IN_IFADDR_RUNLOCK(); 1109222438Sqingli error = rtinit(&(target->ia_ifa), (int)RTM_DELETE, 1110137628Smlaier rtinitflags(target)); 1111222438Sqingli if (error == 0) 1112222438Sqingli target->ia_flags &= ~IFA_ROUTE; 1113222438Sqingli else 1114222438Sqingli log(LOG_INFO, "in_scrubprefix: err=%d, old prefix delete failed\n", 1115222438Sqingli error); 1116137628Smlaier error = rtinit(&ia->ia_ifa, (int)RTM_ADD, 1117137628Smlaier rtinitflags(ia) | RTF_UP); 1118137628Smlaier if (error == 0) 1119137628Smlaier ia->ia_flags |= IFA_ROUTE; 1120222438Sqingli else 1121222438Sqingli log(LOG_INFO, "in_scrubprefix: err=%d, new prefix add failed\n", 1122222438Sqingli error); 1123219828Spluknet ifa_free(&ia->ia_ifa); 1124184295Sbz return (error); 1125137628Smlaier } 1126137628Smlaier } 1127194951Srwatson IN_IFADDR_RUNLOCK(); 1128137628Smlaier 1129137628Smlaier /* 1130192476Sqingli * remove all L2 entries on the given prefix 1131192476Sqingli */ 1132192476Sqingli bzero(&prefix0, sizeof(prefix0)); 1133192476Sqingli prefix0.sin_len = sizeof(prefix0); 1134192476Sqingli prefix0.sin_family = AF_INET; 1135192476Sqingli prefix0.sin_addr.s_addr = target->ia_subnet; 1136192476Sqingli bzero(&mask0, sizeof(mask0)); 1137192476Sqingli mask0.sin_len = sizeof(mask0); 1138192476Sqingli mask0.sin_family = AF_INET; 1139192476Sqingli mask0.sin_addr.s_addr = target->ia_subnetmask; 1140238945Sglebius lltable_prefix_free(AF_INET, (struct sockaddr *)&prefix0, 1141238945Sglebius (struct sockaddr *)&mask0, flags); 1142192476Sqingli 1143192476Sqingli /* 1144137628Smlaier * As no-one seem to have this prefix, we can remove the route. 1145137628Smlaier */ 1146222438Sqingli error = rtinit(&(target->ia_ifa), (int)RTM_DELETE, rtinitflags(target)); 1147222438Sqingli if (error == 0) 1148222438Sqingli target->ia_flags &= ~IFA_ROUTE; 1149222438Sqingli else 1150222438Sqingli log(LOG_INFO, "in_scrubprefix: err=%d, prefix delete failed\n", error); 1151222438Sqingli return (error); 1152137628Smlaier} 1153137628Smlaier 1154137628Smlaier#undef rtinitflags 1155137628Smlaier 1156137628Smlaier/* 11571541Srgrimes * Return 1 if the address might be a local broadcast address. 11581541Srgrimes */ 11591549Srgrimesint 1160169454Srwatsonin_broadcast(struct in_addr in, struct ifnet *ifp) 11611541Srgrimes{ 11621541Srgrimes register struct ifaddr *ifa; 11631541Srgrimes u_long t; 11641541Srgrimes 11651541Srgrimes if (in.s_addr == INADDR_BROADCAST || 11661541Srgrimes in.s_addr == INADDR_ANY) 1167184295Sbz return (1); 11681541Srgrimes if ((ifp->if_flags & IFF_BROADCAST) == 0) 1169184295Sbz return (0); 11701541Srgrimes t = ntohl(in.s_addr); 11711541Srgrimes /* 11721541Srgrimes * Look through the list of addresses for a match 11731541Srgrimes * with a broadcast address. 11741541Srgrimes */ 11751541Srgrimes#define ia ((struct in_ifaddr *)ifa) 117674362Sphk TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 11771541Srgrimes if (ifa->ifa_addr->sa_family == AF_INET && 11781541Srgrimes (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr || 11791541Srgrimes /* 1180226402Sglebius * Check for old-style (host 0) broadcast, but 1181226402Sglebius * taking into account that RFC 3021 obsoletes it. 11821541Srgrimes */ 1183238945Sglebius (ia->ia_subnetmask != IN_RFC3021_MASK && 1184238945Sglebius t == ia->ia_subnet)) && 118513351Sguido /* 118613351Sguido * Check for an all one subnetmask. These 118713351Sguido * only exist when an interface gets a secondary 118813351Sguido * address. 118913351Sguido */ 1190238945Sglebius ia->ia_subnetmask != (u_long)0xffffffff) 1191184295Sbz return (1); 11921541Srgrimes return (0); 11931541Srgrimes#undef ia 11941541Srgrimes} 1195167729Sbms 11961541Srgrimes/* 1197189592Sbms * On interface removal, clean up IPv4 data structures hung off of the ifnet. 1198189592Sbms */ 1199189592Sbmsvoid 1200189592Sbmsin_ifdetach(struct ifnet *ifp) 1201189592Sbms{ 1202189592Sbms 1203189592Sbms in_pcbpurgeif0(&V_ripcbinfo, ifp); 1204189592Sbms in_pcbpurgeif0(&V_udbinfo, ifp); 1205189592Sbms in_purgemaddrs(ifp); 1206189592Sbms} 1207189592Sbms 1208189592Sbms/* 1209167729Sbms * Delete all IPv4 multicast address records, and associated link-layer 1210167729Sbms * multicast address records, associated with ifp. 1211189592Sbms * XXX It looks like domifdetach runs AFTER the link layer cleanup. 1212189931Sbms * XXX This should not race with ifma_protospec being set during 1213189931Sbms * a new allocation, if it does, we have bigger problems. 1214162718Sbms */ 1215167729Sbmsstatic void 1216167729Sbmsin_purgemaddrs(struct ifnet *ifp) 1217162718Sbms{ 1218189592Sbms LIST_HEAD(,in_multi) purgeinms; 1219189592Sbms struct in_multi *inm, *tinm; 1220189592Sbms struct ifmultiaddr *ifma; 1221162718Sbms 1222189592Sbms LIST_INIT(&purgeinms); 1223162718Sbms IN_MULTI_LOCK(); 1224189592Sbms 1225189592Sbms /* 1226189592Sbms * Extract list of in_multi associated with the detaching ifp 1227189592Sbms * which the PF_INET layer is about to release. 1228189592Sbms * We need to do this as IF_ADDR_LOCK() may be re-acquired 1229189592Sbms * by code further down. 1230189592Sbms */ 1231229621Sjhb IF_ADDR_RLOCK(ifp); 1232189592Sbms TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 1233189931Sbms if (ifma->ifma_addr->sa_family != AF_INET || 1234189931Sbms ifma->ifma_protospec == NULL) 1235189592Sbms continue; 1236189931Sbms#if 0 1237189931Sbms KASSERT(ifma->ifma_protospec != NULL, 1238189931Sbms ("%s: ifma_protospec is NULL", __func__)); 1239189931Sbms#endif 1240189592Sbms inm = (struct in_multi *)ifma->ifma_protospec; 1241189592Sbms LIST_INSERT_HEAD(&purgeinms, inm, inm_link); 1242162718Sbms } 1243229621Sjhb IF_ADDR_RUNLOCK(ifp); 1244150296Srwatson 1245189592Sbms LIST_FOREACH_SAFE(inm, &purgeinms, inm_link, tinm) { 1246191476Srwatson LIST_REMOVE(inm, inm_link); 1247189592Sbms inm_release_locked(inm); 1248189592Sbms } 1249189592Sbms igmp_ifdetach(ifp); 1250150296Srwatson 1251189592Sbms IN_MULTI_UNLOCK(); 1252150296Srwatson} 1253186119Sqingli 1254186119Sqinglistruct in_llentry { 1255186119Sqingli struct llentry base; 1256186119Sqingli struct sockaddr_in l3_addr4; 1257186119Sqingli}; 1258186119Sqingli 1259232054Skmacy/* 1260232054Skmacy * Deletes an address from the address table. 1261232054Skmacy * This function is called by the timer functions 1262232054Skmacy * such as arptimer() and nd6_llinfo_timer(), and 1263232054Skmacy * the caller does the locking. 1264232054Skmacy */ 1265232054Skmacystatic void 1266232054Skmacyin_lltable_free(struct lltable *llt, struct llentry *lle) 1267232054Skmacy{ 1268232054Skmacy LLE_WUNLOCK(lle); 1269232054Skmacy LLE_LOCK_DESTROY(lle); 1270232054Skmacy free(lle, M_LLTABLE); 1271232054Skmacy} 1272232054Skmacy 1273186119Sqinglistatic struct llentry * 1274186119Sqingliin_lltable_new(const struct sockaddr *l3addr, u_int flags) 1275186119Sqingli{ 1276186119Sqingli struct in_llentry *lle; 1277186119Sqingli 1278234087Sglebius lle = malloc(sizeof(struct in_llentry), M_LLTABLE, M_NOWAIT | M_ZERO); 1279186119Sqingli if (lle == NULL) /* NB: caller generates msg */ 1280186119Sqingli return NULL; 1281186119Sqingli 1282186119Sqingli /* 1283186119Sqingli * For IPv4 this will trigger "arpresolve" to generate 1284186119Sqingli * an ARP request. 1285186119Sqingli */ 1286216075Sglebius lle->base.la_expire = time_uptime; /* mark expired */ 1287186119Sqingli lle->l3_addr4 = *(const struct sockaddr_in *)l3addr; 1288186119Sqingli lle->base.lle_refcnt = 1; 1289232054Skmacy lle->base.lle_free = in_lltable_free; 1290186119Sqingli LLE_LOCK_INIT(&lle->base); 1291238990Sglebius callout_init_rw(&lle->base.la_timer, &lle->base.lle_lock, 1292238990Sglebius CALLOUT_RETURNUNLOCKED); 1293238990Sglebius 1294238990Sglebius return (&lle->base); 1295186119Sqingli} 1296186119Sqingli 1297192476Sqingli#define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \ 1298192476Sqingli (((ntohl((d)->sin_addr.s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 ) 1299192476Sqingli 1300192476Sqinglistatic void 1301238945Sglebiusin_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix, 1302238945Sglebius const struct sockaddr *mask, u_int flags) 1303192476Sqingli{ 1304192476Sqingli const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix; 1305192476Sqingli const struct sockaddr_in *msk = (const struct sockaddr_in *)mask; 1306192476Sqingli struct llentry *lle, *next; 1307238945Sglebius int i; 1308215207Sgnn size_t pkts_dropped; 1309192476Sqingli 1310238990Sglebius IF_AFDATA_WLOCK(llt->llt_ifp); 1311238945Sglebius for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 1312192476Sqingli LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { 1313238945Sglebius /* 1314222143Sqingli * (flags & LLE_STATIC) means deleting all entries 1315238945Sglebius * including static ARP entries. 1316222143Sqingli */ 1317238945Sglebius if (IN_ARE_MASKED_ADDR_EQUAL(satosin(L3_ADDR(lle)), 1318238945Sglebius pfx, msk) && ((flags & LLE_STATIC) || 1319238945Sglebius !(lle->la_flags & LLE_STATIC))) { 1320192476Sqingli LLE_WLOCK(lle); 1321238990Sglebius if (callout_stop(&lle->la_timer)) 1322206481Sbz LLE_REMREF(lle); 1323215207Sgnn pkts_dropped = llentry_free(lle); 1324215207Sgnn ARPSTAT_ADD(dropped, pkts_dropped); 1325192476Sqingli } 1326192476Sqingli } 1327192476Sqingli } 1328238990Sglebius IF_AFDATA_WUNLOCK(llt->llt_ifp); 1329192476Sqingli} 1330192476Sqingli 1331192476Sqingli 1332186119Sqinglistatic int 1333201282Sqingliin_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr) 1334186119Sqingli{ 1335186119Sqingli struct rtentry *rt; 1336186119Sqingli 1337186119Sqingli KASSERT(l3addr->sa_family == AF_INET, 1338186119Sqingli ("sin_family %d", l3addr->sa_family)); 1339186119Sqingli 1340186119Sqingli /* XXX rtalloc1 should take a const param */ 1341186119Sqingli rt = rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0); 1342223862Szec 1343225946Sqingli if (rt == NULL) 1344225946Sqingli return (EINVAL); 1345225946Sqingli 1346223862Szec /* 1347223862Szec * If the gateway for an existing host route matches the target L3 1348225946Sqingli * address, which is a special route inserted by some implementation 1349225946Sqingli * such as MANET, and the interface is of the correct type, then 1350225946Sqingli * allow for ARP to proceed. 1351223862Szec */ 1352225947Sqingli if (rt->rt_flags & RTF_GATEWAY) { 1353226224Sqingli if (!(rt->rt_flags & RTF_HOST) || !rt->rt_ifp || 1354238945Sglebius rt->rt_ifp->if_type != IFT_ETHER || 1355238945Sglebius (rt->rt_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 || 1356238945Sglebius memcmp(rt->rt_gateway->sa_data, l3addr->sa_data, 1357238945Sglebius sizeof(in_addr_t)) != 0) { 1358226224Sqingli RTFREE_LOCKED(rt); 1359226224Sqingli return (EINVAL); 1360226224Sqingli } 1361225947Sqingli } 1362225947Sqingli 1363225947Sqingli /* 1364238945Sglebius * Make sure that at least the destination address is covered 1365238945Sglebius * by the route. This is for handling the case where 2 or more 1366225947Sqingli * interfaces have the same prefix. An incoming packet arrives 1367225947Sqingli * on one interface and the corresponding outgoing packet leaves 1368225947Sqingli * another interface. 1369225947Sqingli */ 1370226713Sqingli if (!(rt->rt_flags & RTF_HOST) && rt->rt_ifp != ifp) { 1371226224Sqingli const char *sa, *mask, *addr, *lim; 1372225947Sqingli int len; 1373225947Sqingli 1374226713Sqingli mask = (const char *)rt_mask(rt); 1375226713Sqingli /* 1376226713Sqingli * Just being extra cautious to avoid some custom 1377226713Sqingli * code getting into trouble. 1378226713Sqingli */ 1379226713Sqingli if (mask == NULL) { 1380226713Sqingli RTFREE_LOCKED(rt); 1381226713Sqingli return (EINVAL); 1382226713Sqingli } 1383226713Sqingli 1384226224Sqingli sa = (const char *)rt_key(rt); 1385226224Sqingli addr = (const char *)l3addr; 1386226224Sqingli len = ((const struct sockaddr_in *)l3addr)->sin_len; 1387225947Sqingli lim = addr + len; 1388225947Sqingli 1389225947Sqingli for ( ; addr < lim; sa++, mask++, addr++) { 1390225947Sqingli if ((*sa ^ *addr) & *mask) { 1391198418Sqingli#ifdef DIAGNOSTIC 1392225947Sqingli log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n", 1393225947Sqingli inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr)); 1394197696Sqingli#endif 1395226224Sqingli RTFREE_LOCKED(rt); 1396226224Sqingli return (EINVAL); 1397225947Sqingli } 1398225947Sqingli } 1399186119Sqingli } 1400225947Sqingli 1401186119Sqingli RTFREE_LOCKED(rt); 1402226224Sqingli return (0); 1403186119Sqingli} 1404186119Sqingli 1405186119Sqingli/* 1406186119Sqingli * Return NULL if not found or marked for deletion. 1407186119Sqingli * If found return lle read locked. 1408186119Sqingli */ 1409186119Sqinglistatic struct llentry * 1410186119Sqingliin_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) 1411186119Sqingli{ 1412186119Sqingli const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; 1413186119Sqingli struct ifnet *ifp = llt->llt_ifp; 1414186119Sqingli struct llentry *lle; 1415186119Sqingli struct llentries *lleh; 1416186119Sqingli u_int hashkey; 1417186119Sqingli 1418186119Sqingli IF_AFDATA_LOCK_ASSERT(ifp); 1419186119Sqingli KASSERT(l3addr->sa_family == AF_INET, 1420186119Sqingli ("sin_family %d", l3addr->sa_family)); 1421186119Sqingli 1422186119Sqingli hashkey = sin->sin_addr.s_addr; 1423186119Sqingli lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; 1424186119Sqingli LIST_FOREACH(lle, lleh, lle_next) { 1425238945Sglebius struct sockaddr_in *sa2 = satosin(L3_ADDR(lle)); 1426186119Sqingli if (lle->la_flags & LLE_DELETED) 1427186119Sqingli continue; 1428186708Sqingli if (sa2->sin_addr.s_addr == sin->sin_addr.s_addr) 1429186119Sqingli break; 1430186119Sqingli } 1431186119Sqingli if (lle == NULL) { 1432198418Sqingli#ifdef DIAGNOSTIC 1433186119Sqingli if (flags & LLE_DELETE) 1434238967Sglebius log(LOG_INFO, "interface address is missing from cache = %p in delete\n", lle); 1435186119Sqingli#endif 1436186119Sqingli if (!(flags & LLE_CREATE)) 1437186119Sqingli return (NULL); 1438186119Sqingli /* 1439186119Sqingli * A route that covers the given address must have 1440186119Sqingli * been installed 1st because we are doing a resolution, 1441186119Sqingli * verify this. 1442186119Sqingli */ 1443186119Sqingli if (!(flags & LLE_IFADDR) && 1444201282Sqingli in_lltable_rtcheck(ifp, flags, l3addr) != 0) 1445186119Sqingli goto done; 1446186119Sqingli 1447186119Sqingli lle = in_lltable_new(l3addr, flags); 1448186119Sqingli if (lle == NULL) { 1449186119Sqingli log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); 1450186119Sqingli goto done; 1451186119Sqingli } 1452186119Sqingli lle->la_flags = flags & ~LLE_CREATE; 1453186119Sqingli if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { 1454186119Sqingli bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); 1455186119Sqingli lle->la_flags |= (LLE_VALID | LLE_STATIC); 1456186119Sqingli } 1457186119Sqingli 1458186119Sqingli lle->lle_tbl = llt; 1459186119Sqingli lle->lle_head = lleh; 1460238990Sglebius lle->la_flags |= LLE_LINKED; 1461186119Sqingli LIST_INSERT_HEAD(lleh, lle, lle_next); 1462186119Sqingli } else if (flags & LLE_DELETE) { 1463186119Sqingli if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { 1464186119Sqingli LLE_WLOCK(lle); 1465238990Sglebius lle->la_flags |= LLE_DELETED; 1466237263Snp EVENTHANDLER_INVOKE(lle_event, lle, LLENTRY_DELETED); 1467198418Sqingli#ifdef DIAGNOSTIC 1468249742Soleg log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); 1469186119Sqingli#endif 1470249742Soleg if ((lle->la_flags & 1471249742Soleg (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) 1472249742Soleg llentry_free(lle); 1473249742Soleg else 1474249742Soleg LLE_WUNLOCK(lle); 1475186119Sqingli } 1476186119Sqingli lle = (void *)-1; 1477238967Sglebius 1478186119Sqingli } 1479186544Sbz if (LLE_IS_VALID(lle)) { 1480186119Sqingli if (flags & LLE_EXCLUSIVE) 1481186119Sqingli LLE_WLOCK(lle); 1482186119Sqingli else 1483186119Sqingli LLE_RLOCK(lle); 1484186119Sqingli } 1485186119Sqinglidone: 1486186119Sqingli return (lle); 1487186119Sqingli} 1488186119Sqingli 1489186119Sqinglistatic int 1490186119Sqingliin_lltable_dump(struct lltable *llt, struct sysctl_req *wr) 1491186119Sqingli{ 1492186119Sqingli#define SIN(lle) ((struct sockaddr_in *) L3_ADDR(lle)) 1493186119Sqingli struct ifnet *ifp = llt->llt_ifp; 1494186119Sqingli struct llentry *lle; 1495186119Sqingli /* XXX stack use */ 1496186119Sqingli struct { 1497186119Sqingli struct rt_msghdr rtm; 1498246143Sglebius struct sockaddr_in sin; 1499186119Sqingli struct sockaddr_dl sdl; 1500186119Sqingli } arpc; 1501186119Sqingli int error, i; 1502186119Sqingli 1503196535Srwatson LLTABLE_LOCK_ASSERT(); 1504186119Sqingli 1505186119Sqingli error = 0; 1506186119Sqingli for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { 1507186119Sqingli LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { 1508186119Sqingli struct sockaddr_dl *sdl; 1509238967Sglebius 1510186119Sqingli /* skip deleted entries */ 1511198111Sqingli if ((lle->la_flags & LLE_DELETED) == LLE_DELETED) 1512186119Sqingli continue; 1513186980Sbz /* Skip if jailed and not a valid IP of the prison. */ 1514188144Sjamie if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0) 1515186980Sbz continue; 1516186119Sqingli /* 1517186119Sqingli * produce a msg made of: 1518186119Sqingli * struct rt_msghdr; 1519246143Sglebius * struct sockaddr_in; (IPv4) 1520186119Sqingli * struct sockaddr_dl; 1521186119Sqingli */ 1522186119Sqingli bzero(&arpc, sizeof(arpc)); 1523186119Sqingli arpc.rtm.rtm_msglen = sizeof(arpc); 1524186935Sharti arpc.rtm.rtm_version = RTM_VERSION; 1525186935Sharti arpc.rtm.rtm_type = RTM_GET; 1526186935Sharti arpc.rtm.rtm_flags = RTF_UP; 1527186935Sharti arpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; 1528186119Sqingli arpc.sin.sin_family = AF_INET; 1529186119Sqingli arpc.sin.sin_len = sizeof(arpc.sin); 1530186119Sqingli arpc.sin.sin_addr.s_addr = SIN(lle)->sin_addr.s_addr; 1531186119Sqingli 1532186119Sqingli /* publish */ 1533246143Sglebius if (lle->la_flags & LLE_PUB) 1534186119Sqingli arpc.rtm.rtm_flags |= RTF_ANNOUNCE; 1535186119Sqingli 1536186119Sqingli sdl = &arpc.sdl; 1537186119Sqingli sdl->sdl_family = AF_LINK; 1538186119Sqingli sdl->sdl_len = sizeof(*sdl); 1539186119Sqingli sdl->sdl_index = ifp->if_index; 1540186119Sqingli sdl->sdl_type = ifp->if_type; 1541198111Sqingli if ((lle->la_flags & LLE_VALID) == LLE_VALID) { 1542198111Sqingli sdl->sdl_alen = ifp->if_addrlen; 1543198111Sqingli bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); 1544198111Sqingli } else { 1545198111Sqingli sdl->sdl_alen = 0; 1546198111Sqingli bzero(LLADDR(sdl), ifp->if_addrlen); 1547198111Sqingli } 1548186119Sqingli 1549186119Sqingli arpc.rtm.rtm_rmx.rmx_expire = 1550186119Sqingli lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; 1551186500Sqingli arpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); 1552186119Sqingli if (lle->la_flags & LLE_STATIC) 1553186119Sqingli arpc.rtm.rtm_flags |= RTF_STATIC; 1554186119Sqingli arpc.rtm.rtm_index = ifp->if_index; 1555186119Sqingli error = SYSCTL_OUT(wr, &arpc, sizeof(arpc)); 1556186119Sqingli if (error) 1557186119Sqingli break; 1558186119Sqingli } 1559186119Sqingli } 1560186119Sqingli return error; 1561186119Sqingli#undef SIN 1562186119Sqingli} 1563186119Sqingli 1564186119Sqinglivoid * 1565186119Sqingliin_domifattach(struct ifnet *ifp) 1566189592Sbms{ 1567189592Sbms struct in_ifinfo *ii; 1568189592Sbms struct lltable *llt; 1569189592Sbms 1570189592Sbms ii = malloc(sizeof(struct in_ifinfo), M_IFADDR, M_WAITOK|M_ZERO); 1571189592Sbms 1572189592Sbms llt = lltable_init(ifp, AF_INET); 1573186119Sqingli if (llt != NULL) { 1574192476Sqingli llt->llt_prefix_free = in_lltable_prefix_free; 1575186119Sqingli llt->llt_lookup = in_lltable_lookup; 1576186119Sqingli llt->llt_dump = in_lltable_dump; 1577186119Sqingli } 1578189592Sbms ii->ii_llt = llt; 1579189592Sbms 1580189592Sbms ii->ii_igmp = igmp_domifattach(ifp); 1581189592Sbms 1582189592Sbms return ii; 1583186119Sqingli} 1584186119Sqingli 1585186119Sqinglivoid 1586189592Sbmsin_domifdetach(struct ifnet *ifp, void *aux) 1587186119Sqingli{ 1588189592Sbms struct in_ifinfo *ii = (struct in_ifinfo *)aux; 1589186119Sqingli 1590189592Sbms igmp_domifdetach(ifp); 1591189592Sbms lltable_free(ii->ii_llt); 1592189592Sbms free(ii, M_IFADDR); 1593186119Sqingli} 1594