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 */ 2306182fdbdSPeter Wemm ifnet_addrs[ifp->if_index] = 0; 2316182fdbdSPeter Wemm while (ifnet_addrs[if_index] == 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)) { 2366182fdbdSPeter Wemm TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 2376182fdbdSPeter Wemm IFAFREE(ifa); 2386182fdbdSPeter Wemm } 2396182fdbdSPeter Wemm 2406182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 2416182fdbdSPeter Wemm } 2426182fdbdSPeter Wemm 243df8bae1dSRodney W. Grimes /* 244df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 245df8bae1dSRodney W. Grimes */ 246df8bae1dSRodney W. Grimes /*ARGSUSED*/ 247df8bae1dSRodney W. Grimes struct ifaddr * 248df8bae1dSRodney W. Grimes ifa_ifwithaddr(addr) 249df8bae1dSRodney W. Grimes register struct sockaddr *addr; 250df8bae1dSRodney W. Grimes { 251df8bae1dSRodney W. Grimes register struct ifnet *ifp; 252df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 253df8bae1dSRodney W. Grimes 254df8bae1dSRodney W. Grimes #define equal(a1, a2) \ 255df8bae1dSRodney W. Grimes (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 25629412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) 25759562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 25859562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 259df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 260df8bae1dSRodney W. Grimes continue; 261df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr)) 262df8bae1dSRodney W. Grimes return (ifa); 263df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && 26482cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 26582cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 266df8bae1dSRodney W. Grimes equal(ifa->ifa_broadaddr, addr)) 267df8bae1dSRodney W. Grimes return (ifa); 268df8bae1dSRodney W. Grimes } 269df8bae1dSRodney W. Grimes return ((struct ifaddr *)0); 270df8bae1dSRodney W. Grimes } 271df8bae1dSRodney W. Grimes /* 272df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 273df8bae1dSRodney W. Grimes */ 274df8bae1dSRodney W. Grimes /*ARGSUSED*/ 275df8bae1dSRodney W. Grimes struct ifaddr * 276df8bae1dSRodney W. Grimes ifa_ifwithdstaddr(addr) 277df8bae1dSRodney W. Grimes register struct sockaddr *addr; 278df8bae1dSRodney W. Grimes { 279df8bae1dSRodney W. Grimes register struct ifnet *ifp; 280df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 281df8bae1dSRodney W. Grimes 28229412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) 283df8bae1dSRodney W. Grimes if (ifp->if_flags & IFF_POINTOPOINT) 28459562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 28559562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 286df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 287df8bae1dSRodney W. Grimes continue; 28855088a1cSDavid Greenman if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) 289df8bae1dSRodney W. Grimes return (ifa); 290df8bae1dSRodney W. Grimes } 291df8bae1dSRodney W. Grimes return ((struct ifaddr *)0); 292df8bae1dSRodney W. Grimes } 293df8bae1dSRodney W. Grimes 294df8bae1dSRodney W. Grimes /* 295df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 296df8bae1dSRodney W. Grimes * is most specific found. 297df8bae1dSRodney W. Grimes */ 298df8bae1dSRodney W. Grimes struct ifaddr * 299df8bae1dSRodney W. Grimes ifa_ifwithnet(addr) 300df8bae1dSRodney W. Grimes struct sockaddr *addr; 301df8bae1dSRodney W. Grimes { 302df8bae1dSRodney W. Grimes register struct ifnet *ifp; 303df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 304df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 305df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 306df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 307df8bae1dSRodney W. Grimes 3087e2a6151SJulian Elischer /* 3097e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 3107e2a6151SJulian Elischer * so do that if we can. 3117e2a6151SJulian Elischer */ 312df8bae1dSRodney W. Grimes if (af == AF_LINK) { 313df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 314df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 315df8bae1dSRodney W. Grimes return (ifnet_addrs[sdl->sdl_index - 1]); 316df8bae1dSRodney W. Grimes } 3177e2a6151SJulian Elischer 3187e2a6151SJulian Elischer /* 3197e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 3207e2a6151SJulian Elischer * addresses in this address family. 3217e2a6151SJulian Elischer */ 32229412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { 32359562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 32459562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 325df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 326df8bae1dSRodney W. Grimes 327523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 328df8bae1dSRodney W. Grimes next: continue; 32982cd038dSYoshinobu Inoue if ( 33082cd038dSYoshinobu Inoue #ifdef INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */ 33182cd038dSYoshinobu Inoue addr->sa_family != AF_INET6 && 33282cd038dSYoshinobu Inoue #endif 33382cd038dSYoshinobu Inoue ifp->if_flags & IFF_POINTOPOINT) { 3347e2a6151SJulian Elischer /* 3357e2a6151SJulian Elischer * This is a bit broken as it doesn't 3367e2a6151SJulian Elischer * take into account that the remote end may 3377e2a6151SJulian Elischer * be a single node in the network we are 3387e2a6151SJulian Elischer * looking for. 3397e2a6151SJulian Elischer * The trouble is that we don't know the 3407e2a6151SJulian Elischer * netmask for the remote end. 3417e2a6151SJulian Elischer */ 342fcd6781aSGarrett Wollman if (ifa->ifa_dstaddr != 0 343fcd6781aSGarrett Wollman && equal(addr, ifa->ifa_dstaddr)) 344b2af64fdSDavid Greenman return (ifa); 3453740e2adSDavid Greenman } else { 3467e2a6151SJulian Elischer /* 3477ed8f465SJulian Elischer * if we have a special address handler, 3487ed8f465SJulian Elischer * then use it instead of the generic one. 3497ed8f465SJulian Elischer */ 3507ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 3517ed8f465SJulian Elischer if ((*ifa->ifa_claim_addr)(ifa, addr)) { 3527ed8f465SJulian Elischer return (ifa); 3537ed8f465SJulian Elischer } else { 3547ed8f465SJulian Elischer continue; 3557ed8f465SJulian Elischer } 3567ed8f465SJulian Elischer } 3577ed8f465SJulian Elischer 3587ed8f465SJulian Elischer /* 3597e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 3607e2a6151SJulian Elischer * If a bit dissagrees with what we are 3617e2a6151SJulian Elischer * looking for, mask it with the netmask 3627e2a6151SJulian Elischer * to see if it really matters. 3637e2a6151SJulian Elischer * (A byte at a time) 3647e2a6151SJulian Elischer */ 365523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 366523a02aaSDavid Greenman continue; 367df8bae1dSRodney W. Grimes cp = addr_data; 368df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 369df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 3707e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 3717e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 372df8bae1dSRodney W. Grimes while (cp3 < cplim) 373df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 3747e2a6151SJulian Elischer goto next; /* next address! */ 3757e2a6151SJulian Elischer /* 3767e2a6151SJulian Elischer * If the netmask of what we just found 3777e2a6151SJulian Elischer * is more specific than what we had before 3787e2a6151SJulian Elischer * (if we had one) then remember the new one 3797e2a6151SJulian Elischer * before continuing to search 3807e2a6151SJulian Elischer * for an even better one. 3817e2a6151SJulian Elischer */ 382df8bae1dSRodney W. Grimes if (ifa_maybe == 0 || 383df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 384df8bae1dSRodney W. Grimes (caddr_t)ifa_maybe->ifa_netmask)) 385df8bae1dSRodney W. Grimes ifa_maybe = ifa; 386df8bae1dSRodney W. Grimes } 387b2af64fdSDavid Greenman } 388b2af64fdSDavid Greenman } 389df8bae1dSRodney W. Grimes return (ifa_maybe); 390df8bae1dSRodney W. Grimes } 391df8bae1dSRodney W. Grimes 392df8bae1dSRodney W. Grimes /* 393df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 394df8bae1dSRodney W. Grimes * a given address. 395df8bae1dSRodney W. Grimes */ 396df8bae1dSRodney W. Grimes struct ifaddr * 397df8bae1dSRodney W. Grimes ifaof_ifpforaddr(addr, ifp) 398df8bae1dSRodney W. Grimes struct sockaddr *addr; 399df8bae1dSRodney W. Grimes register struct ifnet *ifp; 400df8bae1dSRodney W. Grimes { 401df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 402df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 403df8bae1dSRodney W. Grimes register char *cplim; 404df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 405df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 406df8bae1dSRodney W. Grimes 407df8bae1dSRodney W. Grimes if (af >= AF_MAX) 408df8bae1dSRodney W. Grimes return (0); 40959562606SGarrett Wollman for (ifa = ifp->if_addrhead.tqh_first; ifa; 41059562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 411df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 412df8bae1dSRodney W. Grimes continue; 413381dd1d2SJulian Elischer if (ifa_maybe == 0) 414df8bae1dSRodney W. Grimes ifa_maybe = ifa; 415df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 416df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr) || 417df8bae1dSRodney W. Grimes (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 418df8bae1dSRodney W. Grimes return (ifa); 419df8bae1dSRodney W. Grimes continue; 420df8bae1dSRodney W. Grimes } 421b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 422b2af64fdSDavid Greenman if (equal(addr, ifa->ifa_dstaddr)) 423b2af64fdSDavid Greenman return (ifa); 4243740e2adSDavid Greenman } else { 425df8bae1dSRodney W. Grimes cp = addr->sa_data; 426df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 427df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 428df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 429df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 430df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 431df8bae1dSRodney W. Grimes break; 432df8bae1dSRodney W. Grimes if (cp3 == cplim) 433df8bae1dSRodney W. Grimes return (ifa); 434df8bae1dSRodney W. Grimes } 435b2af64fdSDavid Greenman } 436df8bae1dSRodney W. Grimes return (ifa_maybe); 437df8bae1dSRodney W. Grimes } 438df8bae1dSRodney W. Grimes 439df8bae1dSRodney W. Grimes #include <net/route.h> 440df8bae1dSRodney W. Grimes 441df8bae1dSRodney W. Grimes /* 442df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 443df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 444df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 445df8bae1dSRodney W. Grimes */ 4463bda9f9bSPoul-Henning Kamp static void 447df8bae1dSRodney W. Grimes link_rtrequest(cmd, rt, sa) 448df8bae1dSRodney W. Grimes int cmd; 449df8bae1dSRodney W. Grimes register struct rtentry *rt; 450df8bae1dSRodney W. Grimes struct sockaddr *sa; 451df8bae1dSRodney W. Grimes { 452df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 453df8bae1dSRodney W. Grimes struct sockaddr *dst; 454df8bae1dSRodney W. Grimes struct ifnet *ifp; 455df8bae1dSRodney W. Grimes 456df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 457df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 458df8bae1dSRodney W. Grimes return; 4599448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 4609448326fSPoul-Henning Kamp if (ifa) { 461df8bae1dSRodney W. Grimes IFAFREE(rt->rt_ifa); 462df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 463df8bae1dSRodney W. Grimes ifa->ifa_refcnt++; 464df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 465df8bae1dSRodney W. Grimes ifa->ifa_rtrequest(cmd, rt, sa); 466df8bae1dSRodney W. Grimes } 467df8bae1dSRodney W. Grimes } 468df8bae1dSRodney W. Grimes 469df8bae1dSRodney W. Grimes /* 470df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 471df8bae1dSRodney W. Grimes * the transition. 472df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 473df8bae1dSRodney W. Grimes */ 474df8bae1dSRodney W. Grimes void 475e8c2601dSPoul-Henning Kamp if_unroute(ifp, flag, fam) 476df8bae1dSRodney W. Grimes register struct ifnet *ifp; 477e8c2601dSPoul-Henning Kamp int flag, fam; 478df8bae1dSRodney W. Grimes { 479df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 480df8bae1dSRodney W. Grimes 481e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 48298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 483e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 484e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 485df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 486df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 487df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 488df8bae1dSRodney W. Grimes } 489df8bae1dSRodney W. Grimes 490df8bae1dSRodney W. Grimes /* 491df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 492df8bae1dSRodney W. Grimes * the transition. 493df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 494df8bae1dSRodney W. Grimes */ 495df8bae1dSRodney W. Grimes void 496e8c2601dSPoul-Henning Kamp if_route(ifp, flag, fam) 497df8bae1dSRodney W. Grimes register struct ifnet *ifp; 498e8c2601dSPoul-Henning Kamp int flag, fam; 499df8bae1dSRodney W. Grimes { 500176395b2SGarrett Wollman register struct ifaddr *ifa; 501df8bae1dSRodney W. Grimes 502e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 50398b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 504e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 505e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 506df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 507df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 50882cd038dSYoshinobu Inoue #ifdef INET6 50982cd038dSYoshinobu Inoue in6_if_up(ifp); 51082cd038dSYoshinobu Inoue #endif 511df8bae1dSRodney W. Grimes } 512df8bae1dSRodney W. Grimes 513df8bae1dSRodney W. Grimes /* 514e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 515e8c2601dSPoul-Henning Kamp * the transition. 516e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 517e8c2601dSPoul-Henning Kamp */ 518e8c2601dSPoul-Henning Kamp void 519e8c2601dSPoul-Henning Kamp if_down(ifp) 520e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 521e8c2601dSPoul-Henning Kamp { 522e8c2601dSPoul-Henning Kamp 523e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 524e8c2601dSPoul-Henning Kamp } 525e8c2601dSPoul-Henning Kamp 526e8c2601dSPoul-Henning Kamp /* 527e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 528e8c2601dSPoul-Henning Kamp * the transition. 529e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 530e8c2601dSPoul-Henning Kamp */ 531e8c2601dSPoul-Henning Kamp void 532e8c2601dSPoul-Henning Kamp if_up(ifp) 533e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 534e8c2601dSPoul-Henning Kamp { 535e8c2601dSPoul-Henning Kamp 536e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 537e8c2601dSPoul-Henning Kamp } 538e8c2601dSPoul-Henning Kamp 539e8c2601dSPoul-Henning Kamp /* 540df8bae1dSRodney W. Grimes * Flush an interface queue. 541df8bae1dSRodney W. Grimes */ 5423bda9f9bSPoul-Henning Kamp static void 543df8bae1dSRodney W. Grimes if_qflush(ifq) 544df8bae1dSRodney W. Grimes register struct ifqueue *ifq; 545df8bae1dSRodney W. Grimes { 546df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 547df8bae1dSRodney W. Grimes 548df8bae1dSRodney W. Grimes n = ifq->ifq_head; 5499448326fSPoul-Henning Kamp while ((m = n) != 0) { 550df8bae1dSRodney W. Grimes n = m->m_act; 551df8bae1dSRodney W. Grimes m_freem(m); 552df8bae1dSRodney W. Grimes } 553df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 554df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 555df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 556df8bae1dSRodney W. Grimes } 557df8bae1dSRodney W. Grimes 558df8bae1dSRodney W. Grimes /* 559df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 560df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 561df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 562df8bae1dSRodney W. Grimes */ 5633bda9f9bSPoul-Henning Kamp static void 564df8bae1dSRodney W. Grimes if_slowtimo(arg) 565df8bae1dSRodney W. Grimes void *arg; 566df8bae1dSRodney W. Grimes { 567df8bae1dSRodney W. Grimes register struct ifnet *ifp; 568df8bae1dSRodney W. Grimes int s = splimp(); 569df8bae1dSRodney W. Grimes 57029412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { 571df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 572df8bae1dSRodney W. Grimes continue; 573df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 5744a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 575df8bae1dSRodney W. Grimes } 576df8bae1dSRodney W. Grimes splx(s); 577df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 578df8bae1dSRodney W. Grimes } 579df8bae1dSRodney W. Grimes 580df8bae1dSRodney W. Grimes /* 581df8bae1dSRodney W. Grimes * Map interface name to 582df8bae1dSRodney W. Grimes * interface structure pointer. 583df8bae1dSRodney W. Grimes */ 584df8bae1dSRodney W. Grimes struct ifnet * 585df8bae1dSRodney W. Grimes ifunit(name) 586df8bae1dSRodney W. Grimes register char *name; 587df8bae1dSRodney W. Grimes { 58801f0fef3SJulian Elischer char namebuf[IFNAMSIZ + 1]; 58901f0fef3SJulian Elischer register char *cp, *cp2; 59001f0fef3SJulian Elischer char *end; 591df8bae1dSRodney W. Grimes register struct ifnet *ifp; 592df8bae1dSRodney W. Grimes int unit; 593df8bae1dSRodney W. Grimes unsigned len; 59401f0fef3SJulian Elischer register char c = '\0'; 595df8bae1dSRodney W. Grimes 596df8bae1dSRodney W. Grimes /* 59701f0fef3SJulian Elischer * Look for a non numeric part 59801f0fef3SJulian Elischer */ 59901f0fef3SJulian Elischer end = name + IFNAMSIZ; 60001f0fef3SJulian Elischer cp2 = namebuf; 60101f0fef3SJulian Elischer cp = name; 60201f0fef3SJulian Elischer while ((cp < end) && (c = *cp)) { 60301f0fef3SJulian Elischer if (c >= '0' && c <= '9') 60401f0fef3SJulian Elischer break; 60501f0fef3SJulian Elischer *cp2++ = c; 60601f0fef3SJulian Elischer cp++; 60701f0fef3SJulian Elischer } 60801f0fef3SJulian Elischer if ((cp == end) || (c == '\0') || (cp == name)) 60901f0fef3SJulian Elischer return ((struct ifnet *)0); 61001f0fef3SJulian Elischer *cp2 = '\0'; 61101f0fef3SJulian Elischer /* 61201f0fef3SJulian Elischer * check we have a legal number (limit to 7 digits?) 613df8bae1dSRodney W. Grimes */ 614df8bae1dSRodney W. Grimes len = cp - name + 1; 61501f0fef3SJulian Elischer for (unit = 0; 61601f0fef3SJulian Elischer ((c = *cp) >= '0') && (c <= '9') && (unit < 1000000); cp++ ) 61701f0fef3SJulian Elischer unit = (unit * 10) + (c - '0'); 61858639ed3SGarrett Wollman if (*cp != '\0') 61958639ed3SGarrett Wollman return 0; /* no trailing garbage allowed */ 62001f0fef3SJulian Elischer /* 62101f0fef3SJulian Elischer * Now search all the interfaces for this name/number 62201f0fef3SJulian Elischer */ 62329412182SGarrett Wollman for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_link.tqe_next) { 62401f0fef3SJulian Elischer if (bcmp(ifp->if_name, namebuf, len)) 625df8bae1dSRodney W. Grimes continue; 626df8bae1dSRodney W. Grimes if (unit == ifp->if_unit) 627df8bae1dSRodney W. Grimes break; 628df8bae1dSRodney W. Grimes } 629df8bae1dSRodney W. Grimes return (ifp); 630df8bae1dSRodney W. Grimes } 631df8bae1dSRodney W. Grimes 63282cd038dSYoshinobu Inoue 63382cd038dSYoshinobu Inoue /* 63482cd038dSYoshinobu Inoue * Map interface name in a sockaddr_dl to 63582cd038dSYoshinobu Inoue * interface structure pointer. 63682cd038dSYoshinobu Inoue */ 63782cd038dSYoshinobu Inoue struct ifnet * 63882cd038dSYoshinobu Inoue if_withname(sa) 63982cd038dSYoshinobu Inoue struct sockaddr *sa; 64082cd038dSYoshinobu Inoue { 64182cd038dSYoshinobu Inoue char ifname[IFNAMSIZ+1]; 64282cd038dSYoshinobu Inoue struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 64382cd038dSYoshinobu Inoue 64482cd038dSYoshinobu Inoue if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) || 64582cd038dSYoshinobu Inoue (sdl->sdl_nlen > IFNAMSIZ) ) 64682cd038dSYoshinobu Inoue return NULL; 64782cd038dSYoshinobu Inoue 64882cd038dSYoshinobu Inoue /* 64982cd038dSYoshinobu Inoue * ifunit wants a null-terminated name. It may not be null-terminated 65082cd038dSYoshinobu Inoue * in the sockaddr. We don't want to change the caller's sockaddr, 65182cd038dSYoshinobu Inoue * and there might not be room to put the trailing null anyway, so we 65282cd038dSYoshinobu Inoue * make a local copy that we know we can null terminate safely. 65382cd038dSYoshinobu Inoue */ 65482cd038dSYoshinobu Inoue 65582cd038dSYoshinobu Inoue bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen); 65682cd038dSYoshinobu Inoue ifname[sdl->sdl_nlen] = '\0'; 65782cd038dSYoshinobu Inoue return ifunit(ifname); 65882cd038dSYoshinobu Inoue } 65982cd038dSYoshinobu Inoue 66082cd038dSYoshinobu Inoue 661df8bae1dSRodney W. Grimes /* 662df8bae1dSRodney W. Grimes * Interface ioctls. 663df8bae1dSRodney W. Grimes */ 664df8bae1dSRodney W. Grimes int 665df8bae1dSRodney W. Grimes ifioctl(so, cmd, data, p) 666df8bae1dSRodney W. Grimes struct socket *so; 667ecbb00a2SDoug Rabson u_long cmd; 668df8bae1dSRodney W. Grimes caddr_t data; 669df8bae1dSRodney W. Grimes struct proc *p; 670df8bae1dSRodney W. Grimes { 671df8bae1dSRodney W. Grimes register struct ifnet *ifp; 672df8bae1dSRodney W. Grimes register struct ifreq *ifr; 673413dd0baSPoul-Henning Kamp struct ifstat *ifs; 674df8bae1dSRodney W. Grimes int error; 67582cd038dSYoshinobu Inoue short oif_flags; 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes switch (cmd) { 678df8bae1dSRodney W. Grimes 679df8bae1dSRodney W. Grimes case SIOCGIFCONF: 680df8bae1dSRodney W. Grimes case OSIOCGIFCONF: 681df8bae1dSRodney W. Grimes return (ifconf(cmd, data)); 682df8bae1dSRodney W. Grimes } 683df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 684df8bae1dSRodney W. Grimes ifp = ifunit(ifr->ifr_name); 685df8bae1dSRodney W. Grimes if (ifp == 0) 686df8bae1dSRodney W. Grimes return (ENXIO); 687df8bae1dSRodney W. Grimes switch (cmd) { 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 690df8bae1dSRodney W. Grimes ifr->ifr_flags = ifp->if_flags; 691df8bae1dSRodney W. Grimes break; 692df8bae1dSRodney W. Grimes 693df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 694df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 695df8bae1dSRodney W. Grimes break; 696df8bae1dSRodney W. Grimes 697a7028af7SDavid Greenman case SIOCGIFMTU: 698a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 699a7028af7SDavid Greenman break; 700a7028af7SDavid Greenman 701074c4a4eSGarrett Wollman case SIOCGIFPHYS: 702074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 703074c4a4eSGarrett Wollman break; 704074c4a4eSGarrett Wollman 705df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 706f711d546SPoul-Henning Kamp error = suser(p); 7079448326fSPoul-Henning Kamp if (error) 708df8bae1dSRodney W. Grimes return (error); 7094add131eSPoul-Henning Kamp ifr->ifr_prevflags = ifp->if_flags; 710cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 711cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 7122f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 713cf4b9371SPoul-Henning Kamp (ifr->ifr_flags & IFF_UP) == 0) { 714df8bae1dSRodney W. Grimes int s = splimp(); 715df8bae1dSRodney W. Grimes if_down(ifp); 716df8bae1dSRodney W. Grimes splx(s); 717cf4b9371SPoul-Henning Kamp } else if (ifr->ifr_flags & IFF_UP && 718cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 719df8bae1dSRodney W. Grimes int s = splimp(); 720df8bae1dSRodney W. Grimes if_up(ifp); 721df8bae1dSRodney W. Grimes splx(s); 722df8bae1dSRodney W. Grimes } 723df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 724df8bae1dSRodney W. Grimes (ifr->ifr_flags &~ IFF_CANTCHANGE); 725df8bae1dSRodney W. Grimes if (ifp->if_ioctl) 726df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 72798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 728df8bae1dSRodney W. Grimes break; 729df8bae1dSRodney W. Grimes 730df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 731f711d546SPoul-Henning Kamp error = suser(p); 7329448326fSPoul-Henning Kamp if (error) 733df8bae1dSRodney W. Grimes return (error); 734df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 73598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 736df8bae1dSRodney W. Grimes break; 737df8bae1dSRodney W. Grimes 738074c4a4eSGarrett Wollman case SIOCSIFPHYS: 739f711d546SPoul-Henning Kamp error = suser(p); 740e39a0280SGary Palmer if (error) 741e39a0280SGary Palmer return error; 742e39a0280SGary Palmer if (!ifp->if_ioctl) 743e39a0280SGary Palmer return EOPNOTSUPP; 744e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 745e39a0280SGary Palmer if (error == 0) 74698b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 747e39a0280SGary Palmer return(error); 748074c4a4eSGarrett Wollman 749a7028af7SDavid Greenman case SIOCSIFMTU: 75082cd038dSYoshinobu Inoue { 75182cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 75282cd038dSYoshinobu Inoue 753f711d546SPoul-Henning Kamp error = suser(p); 7549448326fSPoul-Henning Kamp if (error) 755a7028af7SDavid Greenman return (error); 756a7028af7SDavid Greenman if (ifp->if_ioctl == NULL) 757a7028af7SDavid Greenman return (EOPNOTSUPP); 758aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 75975ee03cbSDavid Greenman return (EINVAL); 760e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 761e39a0280SGary Palmer if (error == 0) 76298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 76382cd038dSYoshinobu Inoue /* 76482cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 76582cd038dSYoshinobu Inoue */ 76682cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 76782cd038dSYoshinobu Inoue #ifdef INET6 76882cd038dSYoshinobu Inoue nd6_setmtu(ifp); 76982cd038dSYoshinobu Inoue #endif 77082cd038dSYoshinobu Inoue } 771e39a0280SGary Palmer return (error); 77282cd038dSYoshinobu Inoue } 773a7028af7SDavid Greenman 774df8bae1dSRodney W. Grimes case SIOCADDMULTI: 775df8bae1dSRodney W. Grimes case SIOCDELMULTI: 776f711d546SPoul-Henning Kamp error = suser(p); 7779448326fSPoul-Henning Kamp if (error) 778df8bae1dSRodney W. Grimes return (error); 779477180fbSGarrett Wollman 780477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 781477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 782477180fbSGarrett Wollman return EOPNOTSUPP; 783477180fbSGarrett Wollman 784477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 785477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 786477180fbSGarrett Wollman return EINVAL; 787477180fbSGarrett Wollman 788477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 789477180fbSGarrett Wollman struct ifmultiaddr *ifma; 790477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 791477180fbSGarrett Wollman } else { 792477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 793477180fbSGarrett Wollman } 794e39a0280SGary Palmer if (error == 0) 79598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 796477180fbSGarrett Wollman return error; 797df8bae1dSRodney W. Grimes 798a912e453SPeter Wemm case SIOCSIFMEDIA: 799d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 800f711d546SPoul-Henning Kamp error = suser(p); 801a912e453SPeter Wemm if (error) 802a912e453SPeter Wemm return (error); 803a912e453SPeter Wemm if (ifp->if_ioctl == 0) 804a912e453SPeter Wemm return (EOPNOTSUPP); 805a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 806a912e453SPeter Wemm if (error == 0) 80798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 808a912e453SPeter Wemm return error; 809a912e453SPeter Wemm 810413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 811413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 812413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 813413dd0baSPoul-Henning Kamp 814a912e453SPeter Wemm case SIOCGIFMEDIA: 815d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 816a912e453SPeter Wemm if (ifp->if_ioctl == 0) 817a912e453SPeter Wemm return (EOPNOTSUPP); 818a912e453SPeter Wemm return ((*ifp->if_ioctl)(ifp, cmd, data)); 819a912e453SPeter Wemm 820df8bae1dSRodney W. Grimes default: 82182cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 822df8bae1dSRodney W. Grimes if (so->so_proto == 0) 823df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 824df8bae1dSRodney W. Grimes #ifndef COMPAT_43 82582cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 8262c37256eSGarrett Wollman data, 827bc6d9b80SJoerg Wunsch ifp, p)); 828df8bae1dSRodney W. Grimes #else 829df8bae1dSRodney W. Grimes { 830df8bae1dSRodney W. Grimes int ocmd = cmd; 831df8bae1dSRodney W. Grimes 832df8bae1dSRodney W. Grimes switch (cmd) { 833df8bae1dSRodney W. Grimes 834df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 835df8bae1dSRodney W. Grimes case SIOCSIFADDR: 836df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 837df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 838df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 839df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 840df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 841df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 842df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 843df8bae1dSRodney W. Grimes } 844df8bae1dSRodney W. Grimes #else 845df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 846df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 847df8bae1dSRodney W. Grimes #endif 848df8bae1dSRodney W. Grimes break; 849df8bae1dSRodney W. Grimes 850df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 851df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 852df8bae1dSRodney W. Grimes break; 853df8bae1dSRodney W. Grimes 854df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 855df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 856df8bae1dSRodney W. Grimes break; 857df8bae1dSRodney W. Grimes 858df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 859df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 860df8bae1dSRodney W. Grimes break; 861df8bae1dSRodney W. Grimes 862df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 863df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 864df8bae1dSRodney W. Grimes } 8652c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 8662c37256eSGarrett Wollman cmd, 8672c37256eSGarrett Wollman data, 868a29f300eSGarrett Wollman ifp, p)); 869df8bae1dSRodney W. Grimes switch (ocmd) { 870df8bae1dSRodney W. Grimes 871df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 872df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 873df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 874df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 875df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 87682cd038dSYoshinobu Inoue 87782cd038dSYoshinobu Inoue } 87882cd038dSYoshinobu Inoue } 87982cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 88082cd038dSYoshinobu Inoue 88182cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 88282cd038dSYoshinobu Inoue #ifdef INET6 88382cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 88482cd038dSYoshinobu Inoue int s = splimp(); 88582cd038dSYoshinobu Inoue in6_if_up(ifp); 88682cd038dSYoshinobu Inoue splx(s); 88782cd038dSYoshinobu Inoue } 88882cd038dSYoshinobu Inoue #endif 889df8bae1dSRodney W. Grimes } 890df8bae1dSRodney W. Grimes return (error); 891df8bae1dSRodney W. Grimes 892df8bae1dSRodney W. Grimes } 893df8bae1dSRodney W. Grimes return (0); 894df8bae1dSRodney W. Grimes } 895df8bae1dSRodney W. Grimes 896df8bae1dSRodney W. Grimes /* 897963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 898963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 899963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 900963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 901963e4c2aSGarrett Wollman */ 902963e4c2aSGarrett Wollman int 903963e4c2aSGarrett Wollman ifpromisc(ifp, pswitch) 904963e4c2aSGarrett Wollman struct ifnet *ifp; 905963e4c2aSGarrett Wollman int pswitch; 906963e4c2aSGarrett Wollman { 907963e4c2aSGarrett Wollman struct ifreq ifr; 9084a26224cSGarrett Wollman int error; 909963e4c2aSGarrett Wollman 910963e4c2aSGarrett Wollman if (pswitch) { 911963e4c2aSGarrett Wollman /* 912963e4c2aSGarrett Wollman * If the device is not configured up, we cannot put it in 913963e4c2aSGarrett Wollman * promiscuous mode. 914963e4c2aSGarrett Wollman */ 915963e4c2aSGarrett Wollman if ((ifp->if_flags & IFF_UP) == 0) 916963e4c2aSGarrett Wollman return (ENETDOWN); 917963e4c2aSGarrett Wollman if (ifp->if_pcount++ != 0) 918963e4c2aSGarrett Wollman return (0); 919963e4c2aSGarrett Wollman ifp->if_flags |= IFF_PROMISC; 920e9a30d00SGarrett Wollman log(LOG_INFO, "%s%d: promiscuous mode enabled\n", 921963e4c2aSGarrett Wollman ifp->if_name, ifp->if_unit); 922963e4c2aSGarrett Wollman } else { 923963e4c2aSGarrett Wollman if (--ifp->if_pcount > 0) 924963e4c2aSGarrett Wollman return (0); 925963e4c2aSGarrett Wollman ifp->if_flags &= ~IFF_PROMISC; 926cd9e4cabSSheldon Hearn log(LOG_INFO, "%s%d: promiscuous mode disabled\n", 927cd9e4cabSSheldon Hearn ifp->if_name, ifp->if_unit); 928963e4c2aSGarrett Wollman } 929963e4c2aSGarrett Wollman ifr.ifr_flags = ifp->if_flags; 9304a26224cSGarrett Wollman error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 9314a26224cSGarrett Wollman if (error == 0) 9324a26224cSGarrett Wollman rt_ifmsg(ifp); 9334a26224cSGarrett Wollman return error; 934963e4c2aSGarrett Wollman } 935963e4c2aSGarrett Wollman 936963e4c2aSGarrett Wollman /* 937df8bae1dSRodney W. Grimes * Return interface configuration 938df8bae1dSRodney W. Grimes * of system. List may be used 939df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 940df8bae1dSRodney W. Grimes * other information. 941df8bae1dSRodney W. Grimes */ 942df8bae1dSRodney W. Grimes /*ARGSUSED*/ 9433bda9f9bSPoul-Henning Kamp static int 944df8bae1dSRodney W. Grimes ifconf(cmd, data) 945ecbb00a2SDoug Rabson u_long cmd; 946df8bae1dSRodney W. Grimes caddr_t data; 947df8bae1dSRodney W. Grimes { 948df8bae1dSRodney W. Grimes register struct ifconf *ifc = (struct ifconf *)data; 94929412182SGarrett Wollman register struct ifnet *ifp = ifnet.tqh_first; 950df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 951df8bae1dSRodney W. Grimes struct ifreq ifr, *ifrp; 952df8bae1dSRodney W. Grimes int space = ifc->ifc_len, error = 0; 953df8bae1dSRodney W. Grimes 954df8bae1dSRodney W. Grimes ifrp = ifc->ifc_req; 95529412182SGarrett Wollman for (; space > sizeof (ifr) && ifp; ifp = ifp->if_link.tqe_next) { 9561ce9bf88SPoul-Henning Kamp char workbuf[64]; 95775c13541SPoul-Henning Kamp int ifnlen, addrs; 9582624cf89SGarrett Wollman 9592127f260SArchie Cobbs ifnlen = snprintf(workbuf, sizeof(workbuf), 9602127f260SArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 9611ce9bf88SPoul-Henning Kamp if(ifnlen + 1 > sizeof ifr.ifr_name) { 9622624cf89SGarrett Wollman error = ENAMETOOLONG; 9632624cf89SGarrett Wollman } else { 9641ce9bf88SPoul-Henning Kamp strcpy(ifr.ifr_name, workbuf); 9652624cf89SGarrett Wollman } 9662624cf89SGarrett Wollman 96775c13541SPoul-Henning Kamp addrs = 0; 96875c13541SPoul-Henning Kamp ifa = ifp->if_addrhead.tqh_first; 96959562606SGarrett Wollman for ( ; space > sizeof (ifr) && ifa; 97059562606SGarrett Wollman ifa = ifa->ifa_link.tqe_next) { 971df8bae1dSRodney W. Grimes register struct sockaddr *sa = ifa->ifa_addr; 97275c13541SPoul-Henning Kamp if (curproc->p_prison && prison_if(curproc, sa)) 97375c13541SPoul-Henning Kamp continue; 97475c13541SPoul-Henning Kamp addrs++; 975df8bae1dSRodney W. Grimes #ifdef COMPAT_43 976df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 977df8bae1dSRodney W. Grimes struct osockaddr *osa = 978df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 979df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 980df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 981df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 982df8bae1dSRodney W. Grimes sizeof (ifr)); 983df8bae1dSRodney W. Grimes ifrp++; 984df8bae1dSRodney W. Grimes } else 985df8bae1dSRodney W. Grimes #endif 986df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 987df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 988df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 989df8bae1dSRodney W. Grimes sizeof (ifr)); 990df8bae1dSRodney W. Grimes ifrp++; 991df8bae1dSRodney W. Grimes } else { 992df8bae1dSRodney W. Grimes space -= sa->sa_len - sizeof(*sa); 993df8bae1dSRodney W. Grimes if (space < sizeof (ifr)) 994df8bae1dSRodney W. Grimes break; 995df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 996df8bae1dSRodney W. Grimes sizeof (ifr.ifr_name)); 997df8bae1dSRodney W. Grimes if (error == 0) 998df8bae1dSRodney W. Grimes error = copyout((caddr_t)sa, 999df8bae1dSRodney W. Grimes (caddr_t)&ifrp->ifr_addr, sa->sa_len); 1000df8bae1dSRodney W. Grimes ifrp = (struct ifreq *) 1001df8bae1dSRodney W. Grimes (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 1002df8bae1dSRodney W. Grimes } 1003df8bae1dSRodney W. Grimes if (error) 1004df8bae1dSRodney W. Grimes break; 1005df8bae1dSRodney W. Grimes space -= sizeof (ifr); 1006df8bae1dSRodney W. Grimes } 100775c13541SPoul-Henning Kamp if (!addrs) { 100875c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 100975c13541SPoul-Henning Kamp error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 101075c13541SPoul-Henning Kamp sizeof (ifr)); 101175c13541SPoul-Henning Kamp if (error) 101275c13541SPoul-Henning Kamp break; 101375c13541SPoul-Henning Kamp space -= sizeof (ifr), ifrp++; 101475c13541SPoul-Henning Kamp } 1015df8bae1dSRodney W. Grimes } 1016df8bae1dSRodney W. Grimes ifc->ifc_len -= space; 1017df8bae1dSRodney W. Grimes return (error); 1018df8bae1dSRodney W. Grimes } 1019df8bae1dSRodney W. Grimes 10201158dfb7SGarrett Wollman /* 10211158dfb7SGarrett Wollman * Just like if_promisc(), but for all-multicast-reception mode. 10221158dfb7SGarrett Wollman */ 10231158dfb7SGarrett Wollman int 10241158dfb7SGarrett Wollman if_allmulti(ifp, onswitch) 10251158dfb7SGarrett Wollman struct ifnet *ifp; 10261158dfb7SGarrett Wollman int onswitch; 10271158dfb7SGarrett Wollman { 10281158dfb7SGarrett Wollman int error = 0; 10291158dfb7SGarrett Wollman int s = splimp(); 10301158dfb7SGarrett Wollman 10311158dfb7SGarrett Wollman if (onswitch) { 10321158dfb7SGarrett Wollman if (ifp->if_amcount++ == 0) { 10331158dfb7SGarrett Wollman ifp->if_flags |= IFF_ALLMULTI; 10341158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 10351158dfb7SGarrett Wollman } 10361158dfb7SGarrett Wollman } else { 10371158dfb7SGarrett Wollman if (ifp->if_amcount > 1) { 10381158dfb7SGarrett Wollman ifp->if_amcount--; 10391158dfb7SGarrett Wollman } else { 10401158dfb7SGarrett Wollman ifp->if_amcount = 0; 10411158dfb7SGarrett Wollman ifp->if_flags &= ~IFF_ALLMULTI; 10421158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 10431158dfb7SGarrett Wollman } 10441158dfb7SGarrett Wollman } 10451158dfb7SGarrett Wollman splx(s); 10464a26224cSGarrett Wollman 10474a26224cSGarrett Wollman if (error == 0) 10484a26224cSGarrett Wollman rt_ifmsg(ifp); 10491158dfb7SGarrett Wollman return error; 10501158dfb7SGarrett Wollman } 10511158dfb7SGarrett Wollman 10521158dfb7SGarrett Wollman /* 10531158dfb7SGarrett Wollman * Add a multicast listenership to the interface in question. 10541158dfb7SGarrett Wollman * The link layer provides a routine which converts 10551158dfb7SGarrett Wollman */ 10561158dfb7SGarrett Wollman int 1057373f88edSGarrett Wollman if_addmulti(ifp, sa, retifma) 10581158dfb7SGarrett Wollman struct ifnet *ifp; /* interface to manipulate */ 10591158dfb7SGarrett Wollman struct sockaddr *sa; /* address to add */ 1060b2053118SGarrett Wollman struct ifmultiaddr **retifma; 10611158dfb7SGarrett Wollman { 10621158dfb7SGarrett Wollman struct sockaddr *llsa, *dupsa; 10631158dfb7SGarrett Wollman int error, s; 10641158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 10651158dfb7SGarrett Wollman 106657af7922SJulian Elischer /* 106757af7922SJulian Elischer * If the matching multicast address already exists 106857af7922SJulian Elischer * then don't add a new one, just add a reference 106957af7922SJulian Elischer */ 10701158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 10711158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) { 107257af7922SJulian Elischer if (equal(sa, ifma->ifma_addr)) { 10731158dfb7SGarrett Wollman ifma->ifma_refcount++; 107457af7922SJulian Elischer if (retifma) 107557af7922SJulian Elischer *retifma = ifma; 10761158dfb7SGarrett Wollman return 0; 10771158dfb7SGarrett Wollman } 107857af7922SJulian Elischer } 10791158dfb7SGarrett Wollman 10801158dfb7SGarrett Wollman /* 10811158dfb7SGarrett Wollman * Give the link layer a chance to accept/reject it, and also 10821158dfb7SGarrett Wollman * find out which AF_LINK address this maps to, if it isn't one 10831158dfb7SGarrett Wollman * already. 10841158dfb7SGarrett Wollman */ 10851158dfb7SGarrett Wollman if (ifp->if_resolvemulti) { 10861158dfb7SGarrett Wollman error = ifp->if_resolvemulti(ifp, &llsa, sa); 10871158dfb7SGarrett Wollman if (error) return error; 10881158dfb7SGarrett Wollman } else { 10891158dfb7SGarrett Wollman llsa = 0; 10901158dfb7SGarrett Wollman } 10911158dfb7SGarrett Wollman 10921158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK); 10931158dfb7SGarrett Wollman MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK); 10941158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 10951158dfb7SGarrett Wollman 10961158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 10971158dfb7SGarrett Wollman ifma->ifma_lladdr = llsa; 10981158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 10991158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1100373f88edSGarrett Wollman ifma->ifma_protospec = 0; 1101477180fbSGarrett Wollman rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1102373f88edSGarrett Wollman 11031158dfb7SGarrett Wollman /* 11041158dfb7SGarrett Wollman * Some network interfaces can scan the address list at 11051158dfb7SGarrett Wollman * interrupt time; lock them out. 11061158dfb7SGarrett Wollman */ 11071158dfb7SGarrett Wollman s = splimp(); 11081158dfb7SGarrett Wollman LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 11091158dfb7SGarrett Wollman splx(s); 1110373f88edSGarrett Wollman *retifma = ifma; 11111158dfb7SGarrett Wollman 11121158dfb7SGarrett Wollman if (llsa != 0) { 11131158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 11141158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) { 11151158dfb7SGarrett Wollman if (equal(ifma->ifma_addr, llsa)) 11161158dfb7SGarrett Wollman break; 11171158dfb7SGarrett Wollman } 11181158dfb7SGarrett Wollman if (ifma) { 11191158dfb7SGarrett Wollman ifma->ifma_refcount++; 11201158dfb7SGarrett Wollman } else { 11211158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, 11221158dfb7SGarrett Wollman M_IFMADDR, M_WAITOK); 1123477180fbSGarrett Wollman MALLOC(dupsa, struct sockaddr *, llsa->sa_len, 1124477180fbSGarrett Wollman M_IFMADDR, M_WAITOK); 1125477180fbSGarrett Wollman bcopy(llsa, dupsa, llsa->sa_len); 1126477180fbSGarrett Wollman ifma->ifma_addr = dupsa; 11271158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 11281158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 11291158dfb7SGarrett Wollman s = splimp(); 11301158dfb7SGarrett Wollman LIST_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 11311158dfb7SGarrett Wollman splx(s); 11321158dfb7SGarrett Wollman } 113357af7922SJulian Elischer } 11341158dfb7SGarrett Wollman /* 11351158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 11361158dfb7SGarrett Wollman * interface to let them know about it. 11371158dfb7SGarrett Wollman */ 11381158dfb7SGarrett Wollman s = splimp(); 11391158dfb7SGarrett Wollman ifp->if_ioctl(ifp, SIOCADDMULTI, 0); 11401158dfb7SGarrett Wollman splx(s); 11411158dfb7SGarrett Wollman 11421158dfb7SGarrett Wollman return 0; 11431158dfb7SGarrett Wollman } 11441158dfb7SGarrett Wollman 11451158dfb7SGarrett Wollman /* 11461158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 11471158dfb7SGarrett Wollman * if the request does not match an existing membership. 11481158dfb7SGarrett Wollman */ 11491158dfb7SGarrett Wollman int 11501158dfb7SGarrett Wollman if_delmulti(ifp, sa) 11511158dfb7SGarrett Wollman struct ifnet *ifp; 11521158dfb7SGarrett Wollman struct sockaddr *sa; 11531158dfb7SGarrett Wollman { 11541158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 11551158dfb7SGarrett Wollman int s; 11561158dfb7SGarrett Wollman 11571158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 11581158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) 11591158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 11601158dfb7SGarrett Wollman break; 11611158dfb7SGarrett Wollman if (ifma == 0) 11621158dfb7SGarrett Wollman return ENOENT; 11631158dfb7SGarrett Wollman 11641158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 11651158dfb7SGarrett Wollman ifma->ifma_refcount--; 11661158dfb7SGarrett Wollman return 0; 11671158dfb7SGarrett Wollman } 11681158dfb7SGarrett Wollman 1169477180fbSGarrett Wollman rt_newmaddrmsg(RTM_DELMADDR, ifma); 11701158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 11711158dfb7SGarrett Wollman s = splimp(); 11721158dfb7SGarrett Wollman LIST_REMOVE(ifma, ifma_link); 11731158dfb7SGarrett Wollman splx(s); 11741158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 11751158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 11761158dfb7SGarrett Wollman if (sa == 0) 11771158dfb7SGarrett Wollman return 0; 11781158dfb7SGarrett Wollman 11791158dfb7SGarrett Wollman /* 11801158dfb7SGarrett Wollman * Now look for the link-layer address which corresponds to 11811158dfb7SGarrett Wollman * this network address. It had been squirreled away in 11821158dfb7SGarrett Wollman * ifma->ifma_lladdr for this purpose (so we don't have 11831158dfb7SGarrett Wollman * to call ifp->if_resolvemulti() again), and we saved that 11841158dfb7SGarrett Wollman * value in sa above. If some nasty deleted the 11851158dfb7SGarrett Wollman * link-layer address out from underneath us, we can deal because 11861158dfb7SGarrett Wollman * the address we stored was is not the same as the one which was 11871158dfb7SGarrett Wollman * in the record for the link-layer address. (So we don't complain 11881158dfb7SGarrett Wollman * in that case.) 11891158dfb7SGarrett Wollman */ 11901158dfb7SGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 11911158dfb7SGarrett Wollman ifma = ifma->ifma_link.le_next) 11921158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 11931158dfb7SGarrett Wollman break; 11941158dfb7SGarrett Wollman if (ifma == 0) 11951158dfb7SGarrett Wollman return 0; 11961158dfb7SGarrett Wollman 11971158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 11981158dfb7SGarrett Wollman ifma->ifma_refcount--; 11991158dfb7SGarrett Wollman return 0; 12001158dfb7SGarrett Wollman } 12011158dfb7SGarrett Wollman 12021158dfb7SGarrett Wollman s = splimp(); 12031158dfb7SGarrett Wollman LIST_REMOVE(ifma, ifma_link); 1204c7323482SBill Paul ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 12051158dfb7SGarrett Wollman splx(s); 12061158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 12071158dfb7SGarrett Wollman free(sa, M_IFMADDR); 12081158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 12091158dfb7SGarrett Wollman 12101158dfb7SGarrett Wollman return 0; 12111158dfb7SGarrett Wollman } 12121158dfb7SGarrett Wollman 1213373f88edSGarrett Wollman struct ifmultiaddr * 1214373f88edSGarrett Wollman ifmaof_ifpforaddr(sa, ifp) 1215373f88edSGarrett Wollman struct sockaddr *sa; 1216373f88edSGarrett Wollman struct ifnet *ifp; 1217373f88edSGarrett Wollman { 1218373f88edSGarrett Wollman struct ifmultiaddr *ifma; 1219373f88edSGarrett Wollman 1220373f88edSGarrett Wollman for (ifma = ifp->if_multiaddrs.lh_first; ifma; 1221373f88edSGarrett Wollman ifma = ifma->ifma_link.le_next) 1222373f88edSGarrett Wollman if (equal(ifma->ifma_addr, sa)) 1223373f88edSGarrett Wollman break; 1224373f88edSGarrett Wollman 1225373f88edSGarrett Wollman return ifma; 1226373f88edSGarrett Wollman } 1227373f88edSGarrett Wollman 1228602d513cSGarrett Wollman SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 12292c37256eSGarrett Wollman SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 1230