1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1980, 1986, 1993 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)if.c 8.3 (Berkeley) 1/4/94 34c3aac50fSPeter Wemm * $FreeBSD$ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 375591b823SEivind Eklund #include "opt_compat.h" 38cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 395591b823SEivind Eklund 40df8bae1dSRodney W. Grimes #include <sys/param.h> 414d1d4912SBruce Evans #include <sys/malloc.h> 42df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 43df8bae1dSRodney W. Grimes #include <sys/systm.h> 44df8bae1dSRodney W. Grimes #include <sys/proc.h> 45df8bae1dSRodney W. Grimes #include <sys/socket.h> 46df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 47df8bae1dSRodney W. Grimes #include <sys/protosw.h> 48df8bae1dSRodney W. Grimes #include <sys/kernel.h> 4951a53488SBruce Evans #include <sys/sockio.h> 50963e4c2aSGarrett Wollman #include <sys/syslog.h> 51602d513cSGarrett Wollman #include <sys/sysctl.h> 52df8bae1dSRodney W. Grimes 53df8bae1dSRodney W. Grimes #include <net/if.h> 54df8bae1dSRodney W. Grimes #include <net/if_dl.h> 559448326fSPoul-Henning Kamp #include <net/radix.h> 56df8bae1dSRodney W. Grimes 5782cd038dSYoshinobu Inoue #ifdef INET6 5882cd038dSYoshinobu Inoue /*XXX*/ 5982cd038dSYoshinobu Inoue #include <netinet/in.h> 6082cd038dSYoshinobu Inoue #endif 6182cd038dSYoshinobu Inoue 622b14f991SJulian Elischer /* 632b14f991SJulian Elischer * System initialization 642b14f991SJulian Elischer */ 652b14f991SJulian Elischer 66ecbb00a2SDoug Rabson static int ifconf __P((u_long, caddr_t)); 674590fd3aSDavid Greenman static void ifinit __P((void *)); 683bda9f9bSPoul-Henning Kamp static void if_qflush __P((struct ifqueue *)); 693bda9f9bSPoul-Henning Kamp static void if_slowtimo __P((void *)); 703bda9f9bSPoul-Henning Kamp static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *)); 713bda9f9bSPoul-Henning Kamp 722b14f991SJulian Elischer SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) 732b14f991SJulian Elischer 74a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 75a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 762b14f991SJulian Elischer 77df8bae1dSRodney W. Grimes int ifqmaxlen = IFQ_MAXLEN; 7829412182SGarrett Wollman struct ifnethead ifnet; /* depend on static init XXX */ 79df8bae1dSRodney W. Grimes 8082cd038dSYoshinobu Inoue #ifdef INET6 8182cd038dSYoshinobu Inoue /* 8282cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 8382cd038dSYoshinobu Inoue * should be more generalized? 8482cd038dSYoshinobu Inoue */ 8582cd038dSYoshinobu Inoue extern void nd6_setmtu __P((struct ifnet *)); 8682cd038dSYoshinobu Inoue #endif 8782cd038dSYoshinobu Inoue 88df8bae1dSRodney W. Grimes /* 89df8bae1dSRodney W. Grimes * Network interface utility routines. 90df8bae1dSRodney W. Grimes * 91df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 92df8bae1dSRodney W. Grimes * parameters. 93df8bae1dSRodney W. Grimes */ 942b14f991SJulian Elischer /* ARGSUSED*/ 95df8bae1dSRodney W. Grimes void 9627501cb6SBruce Evans ifinit(dummy) 9727501cb6SBruce Evans void *dummy; 98df8bae1dSRodney W. Grimes { 998ba5bdaeSPeter Wemm struct ifnet *ifp; 1008ba5bdaeSPeter Wemm int s; 101df8bae1dSRodney W. Grimes 1028ba5bdaeSPeter Wemm s = splimp(); 10329412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) 104e0ea20bcSPoul-Henning Kamp if (ifp->if_snd.ifq_maxlen == 0) { 105e0ea20bcSPoul-Henning Kamp printf("%s%d XXX: driver didn't set ifq_maxlen\n", 106e0ea20bcSPoul-Henning Kamp ifp->if_name, ifp->if_unit); 107df8bae1dSRodney W. Grimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 108e0ea20bcSPoul-Henning Kamp } 1098ba5bdaeSPeter Wemm splx(s); 110df8bae1dSRodney W. Grimes if_slowtimo(0); 111df8bae1dSRodney W. Grimes } 112df8bae1dSRodney W. Grimes 113bbd17bf8SGarrett Wollman int if_index = 0; 114bbd17bf8SGarrett Wollman struct ifaddr **ifnet_addrs; 11582cd038dSYoshinobu Inoue struct ifnet **ifindex2ifnet = NULL; 1163bda9f9bSPoul-Henning Kamp 117df8bae1dSRodney W. Grimes 118df8bae1dSRodney W. Grimes /* 119df8bae1dSRodney W. Grimes * Attach an interface to the 120df8bae1dSRodney W. Grimes * list of "active" interfaces. 121df8bae1dSRodney W. Grimes */ 122df8bae1dSRodney W. Grimes void 123df8bae1dSRodney W. Grimes if_attach(ifp) 124df8bae1dSRodney W. Grimes struct ifnet *ifp; 125df8bae1dSRodney W. Grimes { 126df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 1271ce9bf88SPoul-Henning Kamp int namelen, masklen; 1281ce9bf88SPoul-Henning Kamp char workbuf[64]; 129df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 130df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 131df8bae1dSRodney W. Grimes static int if_indexlim = 8; 13229412182SGarrett Wollman static int inited; 133f23b4c91SGarrett Wollman 13429412182SGarrett Wollman if (!inited) { 13529412182SGarrett Wollman TAILQ_INIT(&ifnet); 13629412182SGarrett Wollman inited = 1; 13729412182SGarrett Wollman } 138df8bae1dSRodney W. Grimes 13929412182SGarrett Wollman TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 140df8bae1dSRodney W. Grimes ifp->if_index = ++if_index; 14159562606SGarrett Wollman /* 14259562606SGarrett Wollman * XXX - 14359562606SGarrett Wollman * The old code would work if the interface passed a pre-existing 14459562606SGarrett Wollman * chain of ifaddrs to this code. We don't trust our callers to 14559562606SGarrett Wollman * properly initialize the tailq, however, so we no longer allow 14659562606SGarrett Wollman * this unlikely case. 14759562606SGarrett Wollman */ 14859562606SGarrett Wollman TAILQ_INIT(&ifp->if_addrhead); 14982cd038dSYoshinobu Inoue TAILQ_INIT(&ifp->if_prefixhead); 1501158dfb7SGarrett Wollman LIST_INIT(&ifp->if_multiaddrs); 15198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 152df8bae1dSRodney W. Grimes if (ifnet_addrs == 0 || if_index >= if_indexlim) { 153df8bae1dSRodney W. Grimes unsigned n = (if_indexlim <<= 1) * sizeof(ifa); 15482cd038dSYoshinobu Inoue caddr_t q = malloc(n, M_IFADDR, M_WAITOK); 15582cd038dSYoshinobu Inoue bzero(q, n); 156df8bae1dSRodney W. Grimes if (ifnet_addrs) { 157df8bae1dSRodney W. Grimes bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); 158df8bae1dSRodney W. Grimes free((caddr_t)ifnet_addrs, M_IFADDR); 159df8bae1dSRodney W. Grimes } 16082cd038dSYoshinobu Inoue ifnet_addrs = (struct ifaddr **)q; 16182cd038dSYoshinobu Inoue 16282cd038dSYoshinobu Inoue /* grow ifindex2ifnet */ 16382cd038dSYoshinobu Inoue n = if_indexlim * sizeof(struct ifnet *); 16482cd038dSYoshinobu Inoue q = malloc(n, M_IFADDR, M_WAITOK); 16582cd038dSYoshinobu Inoue bzero(q, n); 16682cd038dSYoshinobu Inoue if (ifindex2ifnet) { 16782cd038dSYoshinobu Inoue bcopy((caddr_t)ifindex2ifnet, q, n/2); 16882cd038dSYoshinobu Inoue free((caddr_t)ifindex2ifnet, M_IFADDR); 169df8bae1dSRodney W. Grimes } 17082cd038dSYoshinobu Inoue ifindex2ifnet = (struct ifnet **)q; 17182cd038dSYoshinobu Inoue } 17282cd038dSYoshinobu Inoue 17382cd038dSYoshinobu Inoue ifindex2ifnet[if_index] = ifp; 17482cd038dSYoshinobu Inoue 175df8bae1dSRodney W. Grimes /* 176df8bae1dSRodney W. Grimes * create a Link Level name for this device 177df8bae1dSRodney W. Grimes */ 1782127f260SArchie Cobbs namelen = snprintf(workbuf, sizeof(workbuf), 1792127f260SArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 180df8bae1dSRodney W. Grimes #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 1811ce9bf88SPoul-Henning Kamp masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; 182df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 183df8bae1dSRodney W. Grimes #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 184df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 185df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 1868a261b8fSDoug Rabson socksize = ROUNDUP(socksize); 187df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 1889448326fSPoul-Henning Kamp ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK); 1899448326fSPoul-Henning Kamp if (ifa) { 190df8bae1dSRodney W. Grimes bzero((caddr_t)ifa, ifasize); 191df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 192df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 193df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 1941ce9bf88SPoul-Henning Kamp bcopy(workbuf, sdl->sdl_data, namelen); 1951ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 196df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 197df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 198df8bae1dSRodney W. Grimes ifnet_addrs[if_index - 1] = ifa; 199df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 200df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = link_rtrequest; 201df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 202df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 203df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 204df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 205df8bae1dSRodney W. Grimes while (namelen != 0) 206df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 20759562606SGarrett Wollman TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 208df8bae1dSRodney W. Grimes } 209df8bae1dSRodney W. Grimes } 2106182fdbdSPeter Wemm 2116182fdbdSPeter Wemm /* 2126182fdbdSPeter Wemm * Detach an interface, removing it from the 2136182fdbdSPeter Wemm * list of "active" interfaces. 2146182fdbdSPeter Wemm */ 2156182fdbdSPeter Wemm void 2166182fdbdSPeter Wemm if_detach(ifp) 2176182fdbdSPeter Wemm struct ifnet *ifp; 2186182fdbdSPeter Wemm { 2196182fdbdSPeter Wemm struct ifaddr *ifa; 2206182fdbdSPeter Wemm 2216182fdbdSPeter Wemm /* 2226182fdbdSPeter Wemm * Remove routes and flush queues. 2236182fdbdSPeter Wemm */ 2246182fdbdSPeter Wemm if_down(ifp); 2256182fdbdSPeter Wemm 2266182fdbdSPeter Wemm /* 2276182fdbdSPeter Wemm * Remove address from ifnet_addrs[] and maybe decrement if_index. 2286182fdbdSPeter Wemm * Clean up all addresses. 2296182fdbdSPeter Wemm */ 230aa6be122SWarner Losh ifnet_addrs[ifp->if_index - 1] = 0; 231aa6be122SWarner Losh while (if_index > 0 && ifnet_addrs[if_index - 1] == 0) 2326182fdbdSPeter Wemm if_index--; 2336182fdbdSPeter Wemm 2346182fdbdSPeter Wemm for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 2356182fdbdSPeter Wemm ifa = TAILQ_FIRST(&ifp->if_addrhead)) { 236aa6be122SWarner Losh #if 1 /* ONOE */ 237aa6be122SWarner Losh /* XXX: Ugly!! ad hoc just for INET */ 238aa6be122SWarner Losh if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 239aa6be122SWarner Losh struct ifaliasreq ifr; 240aa6be122SWarner Losh 241aa6be122SWarner Losh bzero(&ifr, sizeof(ifr)); 242aa6be122SWarner Losh if (ifa->ifa_addr) 243aa6be122SWarner Losh ifr.ifra_addr = *ifa->ifa_addr; 244aa6be122SWarner Losh if (ifa->ifa_dstaddr) 245aa6be122SWarner Losh ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 246aa6be122SWarner Losh if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 247aa6be122SWarner Losh NULL) == 0) 248aa6be122SWarner Losh continue; 249aa6be122SWarner Losh } 250aa6be122SWarner Losh #endif /* ONOE */ 2516182fdbdSPeter Wemm TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 2526182fdbdSPeter Wemm IFAFREE(ifa); 2536182fdbdSPeter Wemm } 2546182fdbdSPeter Wemm 2556182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 2566182fdbdSPeter Wemm } 2576182fdbdSPeter Wemm 258df8bae1dSRodney W. Grimes /* 259df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 260df8bae1dSRodney W. Grimes */ 261df8bae1dSRodney W. Grimes /*ARGSUSED*/ 262df8bae1dSRodney W. Grimes struct ifaddr * 263df8bae1dSRodney W. Grimes ifa_ifwithaddr(addr) 264df8bae1dSRodney W. Grimes register struct sockaddr *addr; 265df8bae1dSRodney W. Grimes { 266df8bae1dSRodney W. Grimes register struct ifnet *ifp; 267df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 268df8bae1dSRodney W. Grimes 269df8bae1dSRodney W. Grimes #define equal(a1, a2) \ 270df8bae1dSRodney W. Grimes (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 27129412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) 27259562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 27359562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 274df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 275df8bae1dSRodney W. Grimes continue; 276df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr)) 277df8bae1dSRodney W. Grimes return (ifa); 278df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && 27982cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 28082cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 281df8bae1dSRodney W. Grimes equal(ifa->ifa_broadaddr, addr)) 282df8bae1dSRodney W. Grimes return (ifa); 283df8bae1dSRodney W. Grimes } 284df8bae1dSRodney W. Grimes return ((struct ifaddr *)0); 285df8bae1dSRodney W. Grimes } 286df8bae1dSRodney W. Grimes /* 287df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 288df8bae1dSRodney W. Grimes */ 289df8bae1dSRodney W. Grimes /*ARGSUSED*/ 290df8bae1dSRodney W. Grimes struct ifaddr * 291df8bae1dSRodney W. Grimes ifa_ifwithdstaddr(addr) 292df8bae1dSRodney W. Grimes register struct sockaddr *addr; 293df8bae1dSRodney W. Grimes { 294df8bae1dSRodney W. Grimes register struct ifnet *ifp; 295df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 296df8bae1dSRodney W. Grimes 29729412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) 298df8bae1dSRodney W. Grimes if (ifp->if_flags & IFF_POINTOPOINT) 29959562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 30059562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 301df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 302df8bae1dSRodney W. Grimes continue; 30355088a1cSDavid Greenman if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) 304df8bae1dSRodney W. Grimes return (ifa); 305df8bae1dSRodney W. Grimes } 306df8bae1dSRodney W. Grimes return ((struct ifaddr *)0); 307df8bae1dSRodney W. Grimes } 308df8bae1dSRodney W. Grimes 309df8bae1dSRodney W. Grimes /* 310df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 311df8bae1dSRodney W. Grimes * is most specific found. 312df8bae1dSRodney W. Grimes */ 313df8bae1dSRodney W. Grimes struct ifaddr * 314df8bae1dSRodney W. Grimes ifa_ifwithnet(addr) 315df8bae1dSRodney W. Grimes struct sockaddr *addr; 316df8bae1dSRodney W. Grimes { 317df8bae1dSRodney W. Grimes register struct ifnet *ifp; 318df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 319df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 320df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 321df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 322df8bae1dSRodney W. Grimes 3237e2a6151SJulian Elischer /* 3247e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 3257e2a6151SJulian Elischer * so do that if we can. 3267e2a6151SJulian Elischer */ 327df8bae1dSRodney W. Grimes if (af == AF_LINK) { 328df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 329df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 330df8bae1dSRodney W. Grimes return (ifnet_addrs[sdl->sdl_index - 1]); 331df8bae1dSRodney W. Grimes } 3327e2a6151SJulian Elischer 3337e2a6151SJulian Elischer /* 3347e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 3357e2a6151SJulian Elischer * addresses in this address family. 3367e2a6151SJulian Elischer */ 33729412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { 33859562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 33959562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 340df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 341df8bae1dSRodney W. Grimes 342523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 343df8bae1dSRodney W. Grimes next: continue; 34482cd038dSYoshinobu Inoue if ( 34582cd038dSYoshinobu Inoue #ifdef INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */ 34682cd038dSYoshinobu Inoue addr->sa_family != AF_INET6 && 34782cd038dSYoshinobu Inoue #endif 34882cd038dSYoshinobu Inoue ifp->if_flags & IFF_POINTOPOINT) { 3497e2a6151SJulian Elischer /* 3507e2a6151SJulian Elischer * This is a bit broken as it doesn't 3517e2a6151SJulian Elischer * take into account that the remote end may 3527e2a6151SJulian Elischer * be a single node in the network we are 3537e2a6151SJulian Elischer * looking for. 3547e2a6151SJulian Elischer * The trouble is that we don't know the 3557e2a6151SJulian Elischer * netmask for the remote end. 3567e2a6151SJulian Elischer */ 357fcd6781aSGarrett Wollman if (ifa->ifa_dstaddr != 0 358fcd6781aSGarrett Wollman && equal(addr, ifa->ifa_dstaddr)) 359b2af64fdSDavid Greenman return (ifa); 3603740e2adSDavid Greenman } else { 3617e2a6151SJulian Elischer /* 3627ed8f465SJulian Elischer * if we have a special address handler, 3637ed8f465SJulian Elischer * then use it instead of the generic one. 3647ed8f465SJulian Elischer */ 3657ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 3667ed8f465SJulian Elischer if ((*ifa->ifa_claim_addr)(ifa, addr)) { 3677ed8f465SJulian Elischer return (ifa); 3687ed8f465SJulian Elischer } else { 3697ed8f465SJulian Elischer continue; 3707ed8f465SJulian Elischer } 3717ed8f465SJulian Elischer } 3727ed8f465SJulian Elischer 3737ed8f465SJulian Elischer /* 3747e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 3757e2a6151SJulian Elischer * If a bit dissagrees with what we are 3767e2a6151SJulian Elischer * looking for, mask it with the netmask 3777e2a6151SJulian Elischer * to see if it really matters. 3787e2a6151SJulian Elischer * (A byte at a time) 3797e2a6151SJulian Elischer */ 380523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 381523a02aaSDavid Greenman continue; 382df8bae1dSRodney W. Grimes cp = addr_data; 383df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 384df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 3857e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 3867e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 387df8bae1dSRodney W. Grimes while (cp3 < cplim) 388df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 3897e2a6151SJulian Elischer goto next; /* next address! */ 3907e2a6151SJulian Elischer /* 3917e2a6151SJulian Elischer * If the netmask of what we just found 3927e2a6151SJulian Elischer * is more specific than what we had before 3937e2a6151SJulian Elischer * (if we had one) then remember the new one 3947e2a6151SJulian Elischer * before continuing to search 3957e2a6151SJulian Elischer * for an even better one. 3967e2a6151SJulian Elischer */ 397df8bae1dSRodney W. Grimes if (ifa_maybe == 0 || 398df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 399df8bae1dSRodney W. Grimes (caddr_t)ifa_maybe->ifa_netmask)) 400df8bae1dSRodney W. Grimes ifa_maybe = ifa; 401df8bae1dSRodney W. Grimes } 402b2af64fdSDavid Greenman } 403b2af64fdSDavid Greenman } 404df8bae1dSRodney W. Grimes return (ifa_maybe); 405df8bae1dSRodney W. Grimes } 406df8bae1dSRodney W. Grimes 407df8bae1dSRodney W. Grimes /* 408df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 409df8bae1dSRodney W. Grimes * a given address. 410df8bae1dSRodney W. Grimes */ 411df8bae1dSRodney W. Grimes struct ifaddr * 412df8bae1dSRodney W. Grimes ifaof_ifpforaddr(addr, ifp) 413df8bae1dSRodney W. Grimes struct sockaddr *addr; 414df8bae1dSRodney W. Grimes register struct ifnet *ifp; 415df8bae1dSRodney W. Grimes { 416df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 417df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 418df8bae1dSRodney W. Grimes register char *cplim; 419df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 420df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 421df8bae1dSRodney W. Grimes 422df8bae1dSRodney W. Grimes if (af >= AF_MAX) 423df8bae1dSRodney W. Grimes return (0); 42459562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 42559562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 426df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 427df8bae1dSRodney W. Grimes continue; 428381dd1d2SJulian Elischer if (ifa_maybe == 0) 429df8bae1dSRodney W. Grimes ifa_maybe = ifa; 430df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 431df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr) || 432df8bae1dSRodney W. Grimes (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 433df8bae1dSRodney W. Grimes return (ifa); 434df8bae1dSRodney W. Grimes continue; 435df8bae1dSRodney W. Grimes } 436b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 437b2af64fdSDavid Greenman if (equal(addr, ifa->ifa_dstaddr)) 438b2af64fdSDavid Greenman return (ifa); 4393740e2adSDavid Greenman } else { 440df8bae1dSRodney W. Grimes cp = addr->sa_data; 441df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 442df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 443df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 444df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 445df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 446df8bae1dSRodney W. Grimes break; 447df8bae1dSRodney W. Grimes if (cp3 == cplim) 448df8bae1dSRodney W. Grimes return (ifa); 449df8bae1dSRodney W. Grimes } 450b2af64fdSDavid Greenman } 451df8bae1dSRodney W. Grimes return (ifa_maybe); 452df8bae1dSRodney W. Grimes } 453df8bae1dSRodney W. Grimes 454df8bae1dSRodney W. Grimes #include <net/route.h> 455df8bae1dSRodney W. Grimes 456df8bae1dSRodney W. Grimes /* 457df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 458df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 459df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 460df8bae1dSRodney W. Grimes */ 4613bda9f9bSPoul-Henning Kamp static void 462df8bae1dSRodney W. Grimes link_rtrequest(cmd, rt, sa) 463df8bae1dSRodney W. Grimes int cmd; 464df8bae1dSRodney W. Grimes register struct rtentry *rt; 465df8bae1dSRodney W. Grimes struct sockaddr *sa; 466df8bae1dSRodney W. Grimes { 467df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 468df8bae1dSRodney W. Grimes struct sockaddr *dst; 469df8bae1dSRodney W. Grimes struct ifnet *ifp; 470df8bae1dSRodney W. Grimes 471df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 472df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 473df8bae1dSRodney W. Grimes return; 4749448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 4759448326fSPoul-Henning Kamp if (ifa) { 476df8bae1dSRodney W. Grimes IFAFREE(rt->rt_ifa); 477df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 478df8bae1dSRodney W. Grimes ifa->ifa_refcnt++; 479df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 480df8bae1dSRodney W. Grimes ifa->ifa_rtrequest(cmd, rt, sa); 481df8bae1dSRodney W. Grimes } 482df8bae1dSRodney W. Grimes } 483df8bae1dSRodney W. Grimes 484df8bae1dSRodney W. Grimes /* 485df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 486df8bae1dSRodney W. Grimes * the transition. 487df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 488df8bae1dSRodney W. Grimes */ 489df8bae1dSRodney W. Grimes void 490e8c2601dSPoul-Henning Kamp if_unroute(ifp, flag, fam) 491df8bae1dSRodney W. Grimes register struct ifnet *ifp; 492e8c2601dSPoul-Henning Kamp int flag, fam; 493df8bae1dSRodney W. Grimes { 494df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 495df8bae1dSRodney W. Grimes 496e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 49798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 498e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 499e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 500df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 501df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 502df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 503df8bae1dSRodney W. Grimes } 504df8bae1dSRodney W. Grimes 505df8bae1dSRodney W. Grimes /* 506df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 507df8bae1dSRodney W. Grimes * the transition. 508df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 509df8bae1dSRodney W. Grimes */ 510df8bae1dSRodney W. Grimes void 511e8c2601dSPoul-Henning Kamp if_route(ifp, flag, fam) 512df8bae1dSRodney W. Grimes register struct ifnet *ifp; 513e8c2601dSPoul-Henning Kamp int flag, fam; 514df8bae1dSRodney W. Grimes { 515176395b2SGarrett Wollman register struct ifaddr *ifa; 516df8bae1dSRodney W. Grimes 517e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 51898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 519e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 520e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 521df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 522df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 52382cd038dSYoshinobu Inoue #ifdef INET6 52482cd038dSYoshinobu Inoue in6_if_up(ifp); 52582cd038dSYoshinobu Inoue #endif 526df8bae1dSRodney W. Grimes } 527df8bae1dSRodney W. Grimes 528df8bae1dSRodney W. Grimes /* 529e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 530e8c2601dSPoul-Henning Kamp * the transition. 531e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 532e8c2601dSPoul-Henning Kamp */ 533e8c2601dSPoul-Henning Kamp void 534e8c2601dSPoul-Henning Kamp if_down(ifp) 535e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 536e8c2601dSPoul-Henning Kamp { 537e8c2601dSPoul-Henning Kamp 538e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 539e8c2601dSPoul-Henning Kamp } 540e8c2601dSPoul-Henning Kamp 541e8c2601dSPoul-Henning Kamp /* 542e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 543e8c2601dSPoul-Henning Kamp * the transition. 544e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 545e8c2601dSPoul-Henning Kamp */ 546e8c2601dSPoul-Henning Kamp void 547e8c2601dSPoul-Henning Kamp if_up(ifp) 548e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 549e8c2601dSPoul-Henning Kamp { 550e8c2601dSPoul-Henning Kamp 551e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 552e8c2601dSPoul-Henning Kamp } 553e8c2601dSPoul-Henning Kamp 554e8c2601dSPoul-Henning Kamp /* 555df8bae1dSRodney W. Grimes * Flush an interface queue. 556df8bae1dSRodney W. Grimes */ 5573bda9f9bSPoul-Henning Kamp static void 558df8bae1dSRodney W. Grimes if_qflush(ifq) 559df8bae1dSRodney W. Grimes register struct ifqueue *ifq; 560df8bae1dSRodney W. Grimes { 561df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 562df8bae1dSRodney W. Grimes 563df8bae1dSRodney W. Grimes n = ifq->ifq_head; 5649448326fSPoul-Henning Kamp while ((m = n) != 0) { 565df8bae1dSRodney W. Grimes n = m->m_act; 566df8bae1dSRodney W. Grimes m_freem(m); 567df8bae1dSRodney W. Grimes } 568df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 569df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 570df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 571df8bae1dSRodney W. Grimes } 572df8bae1dSRodney W. Grimes 573df8bae1dSRodney W. Grimes /* 574df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 575df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 576df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 577df8bae1dSRodney W. Grimes */ 5783bda9f9bSPoul-Henning Kamp static void 579df8bae1dSRodney W. Grimes if_slowtimo(arg) 580df8bae1dSRodney W. Grimes void *arg; 581df8bae1dSRodney W. Grimes { 582df8bae1dSRodney W. Grimes register struct ifnet *ifp; 583df8bae1dSRodney W. Grimes int s = splimp(); 584df8bae1dSRodney W. Grimes 58529412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { 586df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 587df8bae1dSRodney W. Grimes continue; 588df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 5894a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 590df8bae1dSRodney W. Grimes } 591df8bae1dSRodney W. Grimes splx(s); 592df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 593df8bae1dSRodney W. Grimes } 594df8bae1dSRodney W. Grimes 595df8bae1dSRodney W. Grimes /* 596df8bae1dSRodney W. Grimes * Map interface name to 597df8bae1dSRodney W. Grimes * interface structure pointer. 598df8bae1dSRodney W. Grimes */ 599df8bae1dSRodney W. Grimes struct ifnet * 6008b7805e4SBoris Popov ifunit(char *name) 601df8bae1dSRodney W. Grimes { 60201f0fef3SJulian Elischer char namebuf[IFNAMSIZ + 1]; 6038b7805e4SBoris Popov char *cp; 6048b7805e4SBoris Popov struct ifnet *ifp; 605df8bae1dSRodney W. Grimes int unit; 6068b7805e4SBoris Popov unsigned len, m; 6078b7805e4SBoris Popov char c; 608df8bae1dSRodney W. Grimes 6098b7805e4SBoris Popov len = strlen(name); 6108b7805e4SBoris Popov if (len < 2 || len > IFNAMSIZ) 6118b7805e4SBoris Popov return NULL; 6128b7805e4SBoris Popov cp = name + len - 1; 6138b7805e4SBoris Popov c = *cp; 6148b7805e4SBoris Popov if (c < '0' || c > '9') 6158b7805e4SBoris Popov return NULL; /* trailing garbage */ 6168b7805e4SBoris Popov unit = 0; 6178b7805e4SBoris Popov m = 1; 6188b7805e4SBoris Popov do { 6198b7805e4SBoris Popov if (cp == name) 6208b7805e4SBoris Popov return NULL; /* no interface name */ 6218b7805e4SBoris Popov unit += (c - '0') * m; 6228b7805e4SBoris Popov if (unit > 1000000) 6238b7805e4SBoris Popov return NULL; /* number is unreasonable */ 6248b7805e4SBoris Popov m *= 10; 6258b7805e4SBoris Popov c = *--cp; 6268b7805e4SBoris Popov } while (c >= '0' && c <= '9'); 627df8bae1dSRodney W. Grimes len = cp - name + 1; 6288b7805e4SBoris Popov bcopy(name, namebuf, len); 6298b7805e4SBoris Popov namebuf[len] = '\0'; 63001f0fef3SJulian Elischer /* 63101f0fef3SJulian Elischer * Now search all the interfaces for this name/number 63201f0fef3SJulian Elischer */ 63329412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { 6348b7805e4SBoris Popov if (strcmp(ifp->if_name, namebuf)) 635df8bae1dSRodney W. Grimes continue; 636df8bae1dSRodney W. Grimes if (unit == ifp->if_unit) 637df8bae1dSRodney W. Grimes break; 638df8bae1dSRodney W. Grimes } 639df8bae1dSRodney W. Grimes return (ifp); 640df8bae1dSRodney W. Grimes } 641df8bae1dSRodney W. Grimes 64282cd038dSYoshinobu Inoue 64382cd038dSYoshinobu Inoue /* 64482cd038dSYoshinobu Inoue * Map interface name in a sockaddr_dl to 64582cd038dSYoshinobu Inoue * interface structure pointer. 64682cd038dSYoshinobu Inoue */ 64782cd038dSYoshinobu Inoue struct ifnet * 64882cd038dSYoshinobu Inoue if_withname(sa) 64982cd038dSYoshinobu Inoue struct sockaddr *sa; 65082cd038dSYoshinobu Inoue { 65182cd038dSYoshinobu Inoue char ifname[IFNAMSIZ+1]; 65282cd038dSYoshinobu Inoue struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 65382cd038dSYoshinobu Inoue 65482cd038dSYoshinobu Inoue if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) || 65582cd038dSYoshinobu Inoue (sdl->sdl_nlen > IFNAMSIZ) ) 65682cd038dSYoshinobu Inoue return NULL; 65782cd038dSYoshinobu Inoue 65882cd038dSYoshinobu Inoue /* 65982cd038dSYoshinobu Inoue * ifunit wants a null-terminated name. It may not be null-terminated 66082cd038dSYoshinobu Inoue * in the sockaddr. We don't want to change the caller's sockaddr, 66182cd038dSYoshinobu Inoue * and there might not be room to put the trailing null anyway, so we 66282cd038dSYoshinobu Inoue * make a local copy that we know we can null terminate safely. 66382cd038dSYoshinobu Inoue */ 66482cd038dSYoshinobu Inoue 66582cd038dSYoshinobu Inoue bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen); 66682cd038dSYoshinobu Inoue ifname[sdl->sdl_nlen] = '\0'; 66782cd038dSYoshinobu Inoue return ifunit(ifname); 66882cd038dSYoshinobu Inoue } 66982cd038dSYoshinobu Inoue 67082cd038dSYoshinobu Inoue 671df8bae1dSRodney W. Grimes /* 672df8bae1dSRodney W. Grimes * Interface ioctls. 673df8bae1dSRodney W. Grimes */ 674df8bae1dSRodney W. Grimes int 675df8bae1dSRodney W. Grimes ifioctl(so, cmd, data, p) 676df8bae1dSRodney W. Grimes struct socket *so; 677ecbb00a2SDoug Rabson u_long cmd; 678df8bae1dSRodney W. Grimes caddr_t data; 679df8bae1dSRodney W. Grimes struct proc *p; 680df8bae1dSRodney W. Grimes { 681df8bae1dSRodney W. Grimes register struct ifnet *ifp; 682df8bae1dSRodney W. Grimes register struct ifreq *ifr; 683413dd0baSPoul-Henning Kamp struct ifstat *ifs; 684df8bae1dSRodney W. Grimes int error; 68582cd038dSYoshinobu Inoue short oif_flags; 686df8bae1dSRodney W. Grimes 687df8bae1dSRodney W. Grimes switch (cmd) { 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes case SIOCGIFCONF: 690df8bae1dSRodney W. Grimes case OSIOCGIFCONF: 691df8bae1dSRodney W. Grimes return (ifconf(cmd, data)); 692df8bae1dSRodney W. Grimes } 693df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 694df8bae1dSRodney W. Grimes ifp = ifunit(ifr->ifr_name); 695df8bae1dSRodney W. Grimes if (ifp == 0) 696df8bae1dSRodney W. Grimes return (ENXIO); 697df8bae1dSRodney W. Grimes switch (cmd) { 698df8bae1dSRodney W. Grimes 699df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 700df8bae1dSRodney W. Grimes ifr->ifr_flags = ifp->if_flags; 701df8bae1dSRodney W. Grimes break; 702df8bae1dSRodney W. Grimes 703df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 704df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 705df8bae1dSRodney W. Grimes break; 706df8bae1dSRodney W. Grimes 707a7028af7SDavid Greenman case SIOCGIFMTU: 708a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 709a7028af7SDavid Greenman break; 710a7028af7SDavid Greenman 711074c4a4eSGarrett Wollman case SIOCGIFPHYS: 712074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 713074c4a4eSGarrett Wollman break; 714074c4a4eSGarrett Wollman 715df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 716f711d546SPoul-Henning Kamp error = suser(p); 7179448326fSPoul-Henning Kamp if (error) 718df8bae1dSRodney W. Grimes return (error); 7194add131eSPoul-Henning Kamp ifr->ifr_prevflags = ifp->if_flags; 720cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 721cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 7222f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 723cf4b9371SPoul-Henning Kamp (ifr->ifr_flags & IFF_UP) == 0) { 724df8bae1dSRodney W. Grimes int s = splimp(); 725df8bae1dSRodney W. Grimes if_down(ifp); 726df8bae1dSRodney W. Grimes splx(s); 727cf4b9371SPoul-Henning Kamp } else if (ifr->ifr_flags & IFF_UP && 728cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 729df8bae1dSRodney W. Grimes int s = splimp(); 730df8bae1dSRodney W. Grimes if_up(ifp); 731df8bae1dSRodney W. Grimes splx(s); 732df8bae1dSRodney W. Grimes } 733df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 734df8bae1dSRodney W. Grimes (ifr->ifr_flags &~ IFF_CANTCHANGE); 735df8bae1dSRodney W. Grimes if (ifp->if_ioctl) 736df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 73798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 738df8bae1dSRodney W. Grimes break; 739df8bae1dSRodney W. Grimes 740df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 741f711d546SPoul-Henning Kamp error = suser(p); 7429448326fSPoul-Henning Kamp if (error) 743df8bae1dSRodney W. Grimes return (error); 744df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 74598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 746df8bae1dSRodney W. Grimes break; 747df8bae1dSRodney W. Grimes 748074c4a4eSGarrett Wollman case SIOCSIFPHYS: 749f711d546SPoul-Henning Kamp error = suser(p); 750e39a0280SGary Palmer if (error) 751e39a0280SGary Palmer return error; 752e39a0280SGary Palmer if (!ifp->if_ioctl) 753e39a0280SGary Palmer return EOPNOTSUPP; 754e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 755e39a0280SGary Palmer if (error == 0) 75698b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 757e39a0280SGary Palmer return(error); 758074c4a4eSGarrett Wollman 759a7028af7SDavid Greenman case SIOCSIFMTU: 76082cd038dSYoshinobu Inoue { 76182cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 76282cd038dSYoshinobu Inoue 763f711d546SPoul-Henning Kamp error = suser(p); 7649448326fSPoul-Henning Kamp if (error) 765a7028af7SDavid Greenman return (error); 766a7028af7SDavid Greenman if (ifp->if_ioctl == NULL) 767a7028af7SDavid Greenman return (EOPNOTSUPP); 768aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 76975ee03cbSDavid Greenman return (EINVAL); 770e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 771e39a0280SGary Palmer if (error == 0) 77298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 77382cd038dSYoshinobu Inoue /* 77482cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 77582cd038dSYoshinobu Inoue */ 77682cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 77782cd038dSYoshinobu Inoue #ifdef INET6 77882cd038dSYoshinobu Inoue nd6_setmtu(ifp); 77982cd038dSYoshinobu Inoue #endif 78082cd038dSYoshinobu Inoue } 781e39a0280SGary Palmer return (error); 78282cd038dSYoshinobu Inoue } 783a7028af7SDavid Greenman 784df8bae1dSRodney W. Grimes case SIOCADDMULTI: 785df8bae1dSRodney W. Grimes case SIOCDELMULTI: 786f711d546SPoul-Henning Kamp error = suser(p); 7879448326fSPoul-Henning Kamp if (error) 788df8bae1dSRodney W. Grimes return (error); 789477180fbSGarrett Wollman 790477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 791477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 792477180fbSGarrett Wollman return EOPNOTSUPP; 793477180fbSGarrett Wollman 794477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 795477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 796477180fbSGarrett Wollman return EINVAL; 797477180fbSGarrett Wollman 798477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 799477180fbSGarrett Wollman struct ifmultiaddr *ifma; 800477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 801477180fbSGarrett Wollman } else { 802477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 803477180fbSGarrett Wollman } 804e39a0280SGary Palmer if (error == 0) 80598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 806477180fbSGarrett Wollman return error; 807df8bae1dSRodney W. Grimes 808a912e453SPeter Wemm case SIOCSIFMEDIA: 809d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 810f711d546SPoul-Henning Kamp error = suser(p); 811a912e453SPeter Wemm if (error) 812a912e453SPeter Wemm return (error); 813a912e453SPeter Wemm if (ifp->if_ioctl == 0) 814a912e453SPeter Wemm return (EOPNOTSUPP); 815a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 816a912e453SPeter Wemm if (error == 0) 81798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 818a912e453SPeter Wemm return error; 819a912e453SPeter Wemm 820413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 821413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 822413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 823413dd0baSPoul-Henning Kamp 824a912e453SPeter Wemm case SIOCGIFMEDIA: 825d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 826a912e453SPeter Wemm if (ifp->if_ioctl == 0) 827a912e453SPeter Wemm return (EOPNOTSUPP); 828a912e453SPeter Wemm return ((*ifp->if_ioctl)(ifp, cmd, data)); 829a912e453SPeter Wemm 830df8bae1dSRodney W. Grimes default: 83182cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 832df8bae1dSRodney W. Grimes if (so->so_proto == 0) 833df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 834df8bae1dSRodney W. Grimes #ifndef COMPAT_43 83582cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 8362c37256eSGarrett Wollman data, 837bc6d9b80SJoerg Wunsch ifp, p)); 838df8bae1dSRodney W. Grimes #else 839df8bae1dSRodney W. Grimes { 840df8bae1dSRodney W. Grimes int ocmd = cmd; 841df8bae1dSRodney W. Grimes 842df8bae1dSRodney W. Grimes switch (cmd) { 843df8bae1dSRodney W. Grimes 844df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 845df8bae1dSRodney W. Grimes case SIOCSIFADDR: 846df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 847df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 848df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 849df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 850df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 851df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 852df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 853df8bae1dSRodney W. Grimes } 854df8bae1dSRodney W. Grimes #else 855df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 856df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 857df8bae1dSRodney W. Grimes #endif 858df8bae1dSRodney W. Grimes break; 859df8bae1dSRodney W. Grimes 860df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 861df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 862df8bae1dSRodney W. Grimes break; 863df8bae1dSRodney W. Grimes 864df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 865df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 866df8bae1dSRodney W. Grimes break; 867df8bae1dSRodney W. Grimes 868df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 869df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 870df8bae1dSRodney W. Grimes break; 871df8bae1dSRodney W. Grimes 872df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 873df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 874df8bae1dSRodney W. Grimes } 8752c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 8762c37256eSGarrett Wollman cmd, 8772c37256eSGarrett Wollman data, 878a29f300eSGarrett Wollman ifp, p)); 879df8bae1dSRodney W. Grimes switch (ocmd) { 880df8bae1dSRodney W. Grimes 881df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 882df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 883df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 884df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 885df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 88682cd038dSYoshinobu Inoue 88782cd038dSYoshinobu Inoue } 88882cd038dSYoshinobu Inoue } 88982cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 89082cd038dSYoshinobu Inoue 89182cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 89282cd038dSYoshinobu Inoue #ifdef INET6 89382cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 89482cd038dSYoshinobu Inoue int s = splimp(); 89582cd038dSYoshinobu Inoue in6_if_up(ifp); 89682cd038dSYoshinobu Inoue splx(s); 89782cd038dSYoshinobu Inoue } 89882cd038dSYoshinobu Inoue #endif 899df8bae1dSRodney W. Grimes } 900df8bae1dSRodney W. Grimes return (error); 901df8bae1dSRodney W. Grimes 902df8bae1dSRodney W. Grimes } 903df8bae1dSRodney W. Grimes return (0); 904df8bae1dSRodney W. Grimes } 905df8bae1dSRodney W. Grimes 906df8bae1dSRodney W. Grimes /* 907963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 908963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 909963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 910963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 911963e4c2aSGarrett Wollman */ 912963e4c2aSGarrett Wollman int 913963e4c2aSGarrett Wollman ifpromisc(ifp, pswitch) 914963e4c2aSGarrett Wollman struct ifnet *ifp; 915963e4c2aSGarrett Wollman int pswitch; 916963e4c2aSGarrett Wollman { 917963e4c2aSGarrett Wollman struct ifreq ifr; 9184a26224cSGarrett Wollman int error; 919963e4c2aSGarrett Wollman 920963e4c2aSGarrett Wollman if (pswitch) { 921963e4c2aSGarrett Wollman /* 922963e4c2aSGarrett Wollman * If the device is not configured up, we cannot put it in 923963e4c2aSGarrett Wollman * promiscuous mode. 924963e4c2aSGarrett Wollman */ 925963e4c2aSGarrett Wollman if ((ifp->if_flags & IFF_UP) == 0) 926963e4c2aSGarrett Wollman return (ENETDOWN); 927963e4c2aSGarrett Wollman if (ifp->if_pcount++ != 0) 928963e4c2aSGarrett Wollman return (0); 929963e4c2aSGarrett Wollman ifp->if_flags |= IFF_PROMISC; 930e9a30d00SGarrett Wollman log(LOG_INFO, "%s%d: promiscuous mode enabled\n", 931963e4c2aSGarrett Wollman ifp->if_name, ifp->if_unit); 932963e4c2aSGarrett Wollman } else { 933963e4c2aSGarrett Wollman if (--ifp->if_pcount > 0) 934963e4c2aSGarrett Wollman return (0); 935963e4c2aSGarrett Wollman ifp->if_flags &= ~IFF_PROMISC; 936cd9e4cabSSheldon Hearn log(LOG_INFO, "%s%d: promiscuous mode disabled\n", 937cd9e4cabSSheldon Hearn ifp->if_name, ifp->if_unit); 938963e4c2aSGarrett Wollman } 939963e4c2aSGarrett Wollman ifr.ifr_flags = ifp->if_flags; 9404a26224cSGarrett Wollman error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 9414a26224cSGarrett Wollman if (error == 0) 9424a26224cSGarrett Wollman rt_ifmsg(ifp); 9434a26224cSGarrett Wollman return error; 944963e4c2aSGarrett Wollman } 945963e4c2aSGarrett Wollman 946963e4c2aSGarrett Wollman /* 947df8bae1dSRodney W. Grimes * Return interface configuration 948df8bae1dSRodney W. Grimes * of system. List may be used 949df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 950df8bae1dSRodney W. Grimes * other information. 951df8bae1dSRodney W. Grimes */ 952df8bae1dSRodney W. Grimes /*ARGSUSED*/ 9533bda9f9bSPoul-Henning Kamp static int 954df8bae1dSRodney W. Grimes ifconf(cmd, data) 955ecbb00a2SDoug Rabson u_long cmd; 956df8bae1dSRodney W. Grimes caddr_t data; 957df8bae1dSRodney W. Grimes { 958df8bae1dSRodney W. Grimes register struct ifconf *ifc = (struct ifconf *)data; 95929412182SGarrett Wollman register struct ifnet *ifp = ifnet.tqh_first; 960df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 961df8bae1dSRodney W. Grimes struct ifreq ifr, *ifrp; 962df8bae1dSRodney W. Grimes int space = ifc->ifc_len, error = 0; 963df8bae1dSRodney W. Grimes 964df8bae1dSRodney W. Grimes ifrp = ifc->ifc_req; 96529412182SGarrett Wollman for (; space > sizeof (ifr) && ifp; ifp = ifp->if_link.tqe_next) { 9661ce9bf88SPoul-Henning Kamp char workbuf[64]; 96775c13541SPoul-Henning Kamp int ifnlen, addrs; 9682624cf89SGarrett Wollman 9692127f260SArchie Cobbs ifnlen = snprintf(workbuf, sizeof(workbuf), 9702127f260SArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 9711ce9bf88SPoul-Henning Kamp if(ifnlen + 1 > sizeof ifr.ifr_name) { 9722624cf89SGarrett Wollman error = ENAMETOOLONG; 9732624cf89SGarrett Wollman } else { 9741ce9bf88SPoul-Henning Kamp strcpy(ifr.ifr_name, workbuf); 9752624cf89SGarrett Wollman } 9762624cf89SGarrett Wollman 97775c13541SPoul-Henning Kamp addrs = 0; 97875c13541SPoul-Henning Kamp ifa = ifp->if_addrhead.tqh_first; 97959562606SGarrett Wollman for ( ; space > sizeof (ifr) && ifa; 98059562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 981df8bae1dSRodney W. Grimes register struct sockaddr *sa = ifa->ifa_addr; 98275c13541SPoul-Henning Kamp if (curproc->p_prison && prison_if(curproc, sa)) 98375c13541SPoul-Henning Kamp continue; 98475c13541SPoul-Henning Kamp addrs++; 985df8bae1dSRodney W. Grimes #ifdef COMPAT_43 986df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 987df8bae1dSRodney W. Grimes struct osockaddr *osa = 988df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 989df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 990df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 991df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 992df8bae1dSRodney W. Grimes sizeof (ifr)); 993df8bae1dSRodney W. Grimes ifrp++; 994df8bae1dSRodney W. Grimes } else 995df8bae1dSRodney W. Grimes #endif 996df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 997df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 998df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 999df8bae1dSRodney W. Grimes sizeof (ifr)); 1000df8bae1dSRodney W. Grimes ifrp++; 1001df8bae1dSRodney W. Grimes } else { 1002df8bae1dSRodney W. Grimes space -= sa->sa_len - sizeof(*sa); 1003df8bae1dSRodney W. Grimes if (space < sizeof (ifr)) 1004df8bae1dSRodney W. Grimes break; 1005df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1006df8bae1dSRodney W. Grimes sizeof (ifr.ifr_name)); 1007df8bae1dSRodney W. Grimes if (error == 0) 1008df8bae1dSRodney W. Grimes error = copyout((caddr_t)sa, 1009df8bae1dSRodney W. Grimes (caddr_t)&ifrp->ifr_addr, sa->sa_len); 1010df8bae1dSRodney W. Grimes ifrp = (struct ifreq *) 1011df8bae1dSRodney W. Grimes (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 1012df8bae1dSRodney W. Grimes } 1013df8bae1dSRodney W. Grimes if (error) 1014df8bae1dSRodney W. Grimes break; 1015df8bae1dSRodney W. Grimes space -= sizeof (ifr); 1016df8bae1dSRodney W. Grimes } 101775c13541SPoul-Henning Kamp if (!addrs) { 101875c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 101975c13541SPoul-Henning Kamp error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 102075c13541SPoul-Henning Kamp sizeof (ifr)); 102175c13541SPoul-Henning Kamp if (error) 102275c13541SPoul-Henning Kamp break; 102375c13541SPoul-Henning Kamp space -= sizeof (ifr), ifrp++; 102475c13541SPoul-Henning Kamp } 1025df8bae1dSRodney W. Grimes } 1026df8bae1dSRodney W. Grimes ifc->ifc_len -= space; 1027df8bae1dSRodney W. Grimes return (error); 1028df8bae1dSRodney W. Grimes } 1029df8bae1dSRodney W. Grimes 10301158dfb7SGarrett Wollman /* 10311158dfb7SGarrett Wollman * Just like if_promisc(), but for all-multicast-reception mode. 10321158dfb7SGarrett Wollman */ 10331158dfb7SGarrett Wollman int 10341158dfb7SGarrett Wollman if_allmulti(ifp, onswitch) 10351158dfb7SGarrett Wollman struct ifnet *ifp; 10361158dfb7SGarrett Wollman int onswitch; 10371158dfb7SGarrett Wollman { 10381158dfb7SGarrett Wollman int error = 0; 10391158dfb7SGarrett Wollman int s = splimp(); 10401158dfb7SGarrett Wollman 10411158dfb7SGarrett Wollman if (onswitch) { 10421158dfb7SGarrett Wollman if (ifp->if_amcount++ == 0) { 10431158dfb7SGarrett Wollman ifp->if_flags |= IFF_ALLMULTI; 10441158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 10451158dfb7SGarrett Wollman } 10461158dfb7SGarrett Wollman } else { 10471158dfb7SGarrett Wollman if (ifp->if_amcount > 1) { 10481158dfb7SGarrett Wollman ifp->if_amcount--; 10491158dfb7SGarrett Wollman } else { 10501158dfb7SGarrett Wollman ifp->if_amcount = 0; 10511158dfb7SGarrett Wollman ifp->if_flags &= ~IFF_ALLMULTI; 10521158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 10531158dfb7SGarrett Wollman } 10541158dfb7SGarrett Wollman } 10551158dfb7SGarrett Wollman splx(s); 10564a26224cSGarrett Wollman 10574a26224cSGarrett Wollman if (error == 0) 10584a26224cSGarrett Wollman rt_ifmsg(ifp); 10591158dfb7SGarrett Wollman return error; 10601158dfb7SGarrett Wollman } 10611158dfb7SGarrett Wollman 10621158dfb7SGarrett Wollman /* 10631158dfb7SGarrett Wollman * Add a multicast listenership to the interface in question. 10641158dfb7SGarrett Wollman * The link layer provides a routine which converts 10651158dfb7SGarrett Wollman */ 10661158dfb7SGarrett Wollman int 1067373f88edSGarrett Wollman if_addmulti(ifp, sa, retifma) 10681158dfb7SGarrett Wollman struct ifnet *ifp; /* interface to manipulate */ 10691158dfb7SGarrett Wollman struct sockaddr *sa; /* address to add */ 1070b2053118SGarrett Wollman struct ifmultiaddr **retifma; 10711158dfb7SGarrett Wollman { 10721158dfb7SGarrett Wollman struct sockaddr *llsa, *dupsa; 10731158dfb7SGarrett Wollman int error, s; 10741158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 10751158dfb7SGarrett Wollman 107657af7922SJulian Elischer /* 107757af7922SJulian Elischer * If the matching multicast address already exists 107857af7922SJulian Elischer * then don't add a new one, just add a reference 107957af7922SJulian Elischer */ 10801158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 10811158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) { 108257af7922SJulian Elischer if (equal(sa, ifma->ifma_addr)) { 10831158dfb7SGarrett Wollman ifma->ifma_refcount++; 108457af7922SJulian Elischer if (retifma) 108557af7922SJulian Elischer *retifma = ifma; 10861158dfb7SGarrett Wollman return 0; 10871158dfb7SGarrett Wollman } 108857af7922SJulian Elischer } 10891158dfb7SGarrett Wollman 10901158dfb7SGarrett Wollman /* 10911158dfb7SGarrett Wollman * Give the link layer a chance to accept/reject it, and also 10921158dfb7SGarrett Wollman * find out which AF_LINK address this maps to, if it isn't one 10931158dfb7SGarrett Wollman * already. 10941158dfb7SGarrett Wollman */ 10951158dfb7SGarrett Wollman if (ifp->if_resolvemulti) { 10961158dfb7SGarrett Wollman error = ifp->if_resolvemulti(ifp, &llsa, sa); 10971158dfb7SGarrett Wollman if (error) return error; 10981158dfb7SGarrett Wollman } else { 10991158dfb7SGarrett Wollman llsa = 0; 11001158dfb7SGarrett Wollman } 11011158dfb7SGarrett Wollman 11021158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK); 11031158dfb7SGarrett Wollman MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK); 11041158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 11051158dfb7SGarrett Wollman 11061158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 11071158dfb7SGarrett Wollman ifma->ifma_lladdr = llsa; 11081158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 11091158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1110373f88edSGarrett Wollman ifma->ifma_protospec = 0; 1111477180fbSGarrett Wollman rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1112373f88edSGarrett Wollman 11131158dfb7SGarrett Wollman /* 11141158dfb7SGarrett Wollman * Some network interfaces can scan the address list at 11151158dfb7SGarrett Wollman * interrupt time; lock them out. 11161158dfb7SGarrett Wollman */ 11171158dfb7SGarrett Wollman s = splimp(); 11181158dfb7SGarrett Wollman LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 11191158dfb7SGarrett Wollman splx(s); 1120373f88edSGarrett Wollman *retifma = ifma; 11211158dfb7SGarrett Wollman 11221158dfb7SGarrett Wollman if (llsa != 0) { 11231158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 11241158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) { 11251158dfb7SGarrett Wollman if (equal(ifma->ifma_addr, llsa)) 11261158dfb7SGarrett Wollman break; 11271158dfb7SGarrett Wollman } 11281158dfb7SGarrett Wollman if (ifma) { 11291158dfb7SGarrett Wollman ifma->ifma_refcount++; 11301158dfb7SGarrett Wollman } else { 11311158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, 11321158dfb7SGarrett Wollman M_IFMADDR, M_WAITOK); 1133477180fbSGarrett Wollman MALLOC(dupsa, struct sockaddr *, llsa->sa_len, 1134477180fbSGarrett Wollman M_IFMADDR, M_WAITOK); 1135477180fbSGarrett Wollman bcopy(llsa, dupsa, llsa->sa_len); 1136477180fbSGarrett Wollman ifma->ifma_addr = dupsa; 11371158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 11381158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 11391158dfb7SGarrett Wollman s = splimp(); 11401158dfb7SGarrett Wollman LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 11411158dfb7SGarrett Wollman splx(s); 11421158dfb7SGarrett Wollman } 114357af7922SJulian Elischer } 11441158dfb7SGarrett Wollman /* 11451158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 11461158dfb7SGarrett Wollman * interface to let them know about it. 11471158dfb7SGarrett Wollman */ 11481158dfb7SGarrett Wollman s = splimp(); 11491158dfb7SGarrett Wollman ifp->if_ioctl(ifp, SIOCADDMULTI, 0); 11501158dfb7SGarrett Wollman splx(s); 11511158dfb7SGarrett Wollman 11521158dfb7SGarrett Wollman return 0; 11531158dfb7SGarrett Wollman } 11541158dfb7SGarrett Wollman 11551158dfb7SGarrett Wollman /* 11561158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 11571158dfb7SGarrett Wollman * if the request does not match an existing membership. 11581158dfb7SGarrett Wollman */ 11591158dfb7SGarrett Wollman int 11601158dfb7SGarrett Wollman if_delmulti(ifp, sa) 11611158dfb7SGarrett Wollman struct ifnet *ifp; 11621158dfb7SGarrett Wollman struct sockaddr *sa; 11631158dfb7SGarrett Wollman { 11641158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 11651158dfb7SGarrett Wollman int s; 11661158dfb7SGarrett Wollman 11671158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 11681158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) 11691158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 11701158dfb7SGarrett Wollman break; 11711158dfb7SGarrett Wollman if (ifma == 0) 11721158dfb7SGarrett Wollman return ENOENT; 11731158dfb7SGarrett Wollman 11741158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 11751158dfb7SGarrett Wollman ifma->ifma_refcount--; 11761158dfb7SGarrett Wollman return 0; 11771158dfb7SGarrett Wollman } 11781158dfb7SGarrett Wollman 1179477180fbSGarrett Wollman rt_newmaddrmsg(RTM_DELMADDR, ifma); 11801158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 11811158dfb7SGarrett Wollman s = splimp(); 11821158dfb7SGarrett Wollman LIST_REMOVE(ifma, ifma_link); 11831158dfb7SGarrett Wollman splx(s); 11841158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 11851158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 11861158dfb7SGarrett Wollman if (sa == 0) 11871158dfb7SGarrett Wollman return 0; 11881158dfb7SGarrett Wollman 11891158dfb7SGarrett Wollman /* 11901158dfb7SGarrett Wollman * Now look for the link-layer address which corresponds to 11911158dfb7SGarrett Wollman * this network address. It had been squirreled away in 11921158dfb7SGarrett Wollman * ifma->ifma_lladdr for this purpose (so we don't have 11931158dfb7SGarrett Wollman * to call ifp->if_resolvemulti() again), and we saved that 11941158dfb7SGarrett Wollman * value in sa above. If some nasty deleted the 11951158dfb7SGarrett Wollman * link-layer address out from underneath us, we can deal because 11961158dfb7SGarrett Wollman * the address we stored was is not the same as the one which was 11971158dfb7SGarrett Wollman * in the record for the link-layer address. (So we don't complain 11981158dfb7SGarrett Wollman * in that case.) 11991158dfb7SGarrett Wollman */ 12001158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 12011158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) 12021158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 12031158dfb7SGarrett Wollman break; 12041158dfb7SGarrett Wollman if (ifma == 0) 12051158dfb7SGarrett Wollman return 0; 12061158dfb7SGarrett Wollman 12071158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 12081158dfb7SGarrett Wollman ifma->ifma_refcount--; 12091158dfb7SGarrett Wollman return 0; 12101158dfb7SGarrett Wollman } 12111158dfb7SGarrett Wollman 12121158dfb7SGarrett Wollman s = splimp(); 12131158dfb7SGarrett Wollman LIST_REMOVE(ifma, ifma_link); 1214c7323482SBill Paul ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 12151158dfb7SGarrett Wollman splx(s); 12161158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 12171158dfb7SGarrett Wollman free(sa, M_IFMADDR); 12181158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 12191158dfb7SGarrett Wollman 12201158dfb7SGarrett Wollman return 0; 12211158dfb7SGarrett Wollman } 12221158dfb7SGarrett Wollman 1223373f88edSGarrett Wollman struct ifmultiaddr * 1224373f88edSGarrett Wollman ifmaof_ifpforaddr(sa, ifp) 1225373f88edSGarrett Wollman struct sockaddr *sa; 1226373f88edSGarrett Wollman struct ifnet *ifp; 1227373f88edSGarrett Wollman { 1228373f88edSGarrett Wollman struct ifmultiaddr *ifma; 1229373f88edSGarrett Wollman 1230373f88edSGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 1231373f88edSGarrett Wollman ifma = ifma->ifma_link.le_next) 1232373f88edSGarrett Wollman if (equal(ifma->ifma_addr, sa)) 1233373f88edSGarrett Wollman break; 1234373f88edSGarrett Wollman 1235373f88edSGarrett Wollman return ifma; 1236373f88edSGarrett Wollman } 1237373f88edSGarrett Wollman 1238602d513cSGarrett Wollman SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 12392c37256eSGarrett Wollman SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 1240