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" 390d0f9d1eSYoshinobu Inoue #include "opt_inet.h" 405591b823SEivind Eklund 41df8bae1dSRodney W. Grimes #include <sys/param.h> 424d1d4912SBruce Evans #include <sys/malloc.h> 43df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 44df8bae1dSRodney W. Grimes #include <sys/systm.h> 45df8bae1dSRodney W. Grimes #include <sys/proc.h> 46df8bae1dSRodney W. Grimes #include <sys/socket.h> 47df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 48df8bae1dSRodney W. Grimes #include <sys/protosw.h> 49df8bae1dSRodney W. Grimes #include <sys/kernel.h> 5051a53488SBruce Evans #include <sys/sockio.h> 51963e4c2aSGarrett Wollman #include <sys/syslog.h> 52602d513cSGarrett Wollman #include <sys/sysctl.h> 5391421ba2SRobert Watson #include <sys/jail.h> 54df8bae1dSRodney W. Grimes 55df8bae1dSRodney W. Grimes #include <net/if.h> 56b106252cSBill Paul #include <net/if_arp.h> 57df8bae1dSRodney W. Grimes #include <net/if_dl.h> 5866ce51ceSArchie Cobbs #include <net/if_types.h> 5930aad87dSBrooks Davis #include <net/if_var.h> 609448326fSPoul-Henning Kamp #include <net/radix.h> 615500d3beSWarner Losh #include <net/route.h> 62df8bae1dSRodney W. Grimes 630d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6) 6482cd038dSYoshinobu Inoue /*XXX*/ 6582cd038dSYoshinobu Inoue #include <netinet/in.h> 660d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h> 673411310dSYoshinobu Inoue #ifdef INET6 68978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h> 69978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h> 703411310dSYoshinobu Inoue #endif 7182cd038dSYoshinobu Inoue #endif 7282cd038dSYoshinobu Inoue 732b14f991SJulian Elischer /* 742b14f991SJulian Elischer * System initialization 752b14f991SJulian Elischer */ 762b14f991SJulian Elischer 77ecbb00a2SDoug Rabson static int ifconf __P((u_long, caddr_t)); 784590fd3aSDavid Greenman static void ifinit __P((void *)); 793bda9f9bSPoul-Henning Kamp static void if_qflush __P((struct ifqueue *)); 803bda9f9bSPoul-Henning Kamp static void if_slowtimo __P((void *)); 813bda9f9bSPoul-Henning Kamp static void link_rtrequest __P((int, struct rtentry *, struct sockaddr *)); 825500d3beSWarner Losh static int if_rtdel __P((struct radix_node *, void *)); 833bda9f9bSPoul-Henning Kamp 842b14f991SJulian Elischer SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) 852b14f991SJulian Elischer 86a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 87a1c995b6SPoul-Henning Kamp MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 882b14f991SJulian Elischer 89df8bae1dSRodney W. Grimes int ifqmaxlen = IFQ_MAXLEN; 9029412182SGarrett Wollman struct ifnethead ifnet; /* depend on static init XXX */ 91df8bae1dSRodney W. Grimes 9282cd038dSYoshinobu Inoue #ifdef INET6 9382cd038dSYoshinobu Inoue /* 9482cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 9582cd038dSYoshinobu Inoue * should be more generalized? 9682cd038dSYoshinobu Inoue */ 9782cd038dSYoshinobu Inoue extern void nd6_setmtu __P((struct ifnet *)); 9882cd038dSYoshinobu Inoue #endif 9982cd038dSYoshinobu Inoue 10030aad87dSBrooks Davis struct if_clone *if_clone_lookup __P((const char *, int *)); 10130aad87dSBrooks Davis int if_clone_list __P((struct if_clonereq *)); 10230aad87dSBrooks Davis 10330aad87dSBrooks Davis LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 10430aad87dSBrooks Davis int if_cloners_count; 10530aad87dSBrooks Davis 106df8bae1dSRodney W. Grimes /* 107df8bae1dSRodney W. Grimes * Network interface utility routines. 108df8bae1dSRodney W. Grimes * 109df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 110df8bae1dSRodney W. Grimes * parameters. 111df8bae1dSRodney W. Grimes */ 1122b14f991SJulian Elischer /* ARGSUSED*/ 113df8bae1dSRodney W. Grimes void 11427501cb6SBruce Evans ifinit(dummy) 11527501cb6SBruce Evans void *dummy; 116df8bae1dSRodney W. Grimes { 1178ba5bdaeSPeter Wemm struct ifnet *ifp; 1188ba5bdaeSPeter Wemm int s; 119df8bae1dSRodney W. Grimes 1208ba5bdaeSPeter Wemm s = splimp(); 121fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 122e0ea20bcSPoul-Henning Kamp if (ifp->if_snd.ifq_maxlen == 0) { 123e0ea20bcSPoul-Henning Kamp printf("%s%d XXX: driver didn't set ifq_maxlen\n", 124e0ea20bcSPoul-Henning Kamp ifp->if_name, ifp->if_unit); 125df8bae1dSRodney W. Grimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 126e0ea20bcSPoul-Henning Kamp } 1275e980e22SJohn Baldwin if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) { 128df5e1987SJonathan Lemon printf("%s%d XXX: driver didn't initialize queue mtx\n", 129df5e1987SJonathan Lemon ifp->if_name, ifp->if_unit); 130df5e1987SJonathan Lemon mtx_init(&ifp->if_snd.ifq_mtx, "unknown", MTX_DEF); 131df5e1987SJonathan Lemon } 132df5e1987SJonathan Lemon } 1338ba5bdaeSPeter Wemm splx(s); 134df8bae1dSRodney W. Grimes if_slowtimo(0); 135df8bae1dSRodney W. Grimes } 136df8bae1dSRodney W. Grimes 137bbd17bf8SGarrett Wollman int if_index = 0; 138bbd17bf8SGarrett Wollman struct ifaddr **ifnet_addrs; 13982cd038dSYoshinobu Inoue struct ifnet **ifindex2ifnet = NULL; 1403bda9f9bSPoul-Henning Kamp 141df8bae1dSRodney W. Grimes 142df8bae1dSRodney W. Grimes /* 143df8bae1dSRodney W. Grimes * Attach an interface to the 144df8bae1dSRodney W. Grimes * list of "active" interfaces. 145df8bae1dSRodney W. Grimes */ 146df8bae1dSRodney W. Grimes void 147df8bae1dSRodney W. Grimes if_attach(ifp) 148df8bae1dSRodney W. Grimes struct ifnet *ifp; 149df8bae1dSRodney W. Grimes { 150df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 1511ce9bf88SPoul-Henning Kamp int namelen, masklen; 1521ce9bf88SPoul-Henning Kamp char workbuf[64]; 153df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 154df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 155df8bae1dSRodney W. Grimes static int if_indexlim = 8; 15629412182SGarrett Wollman static int inited; 157f23b4c91SGarrett Wollman 15829412182SGarrett Wollman if (!inited) { 15929412182SGarrett Wollman TAILQ_INIT(&ifnet); 16029412182SGarrett Wollman inited = 1; 16129412182SGarrett Wollman } 162df8bae1dSRodney W. Grimes 16329412182SGarrett Wollman TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 164df8bae1dSRodney W. Grimes ifp->if_index = ++if_index; 16559562606SGarrett Wollman /* 16659562606SGarrett Wollman * XXX - 16759562606SGarrett Wollman * The old code would work if the interface passed a pre-existing 16859562606SGarrett Wollman * chain of ifaddrs to this code. We don't trust our callers to 16959562606SGarrett Wollman * properly initialize the tailq, however, so we no longer allow 17059562606SGarrett Wollman * this unlikely case. 17159562606SGarrett Wollman */ 17259562606SGarrett Wollman TAILQ_INIT(&ifp->if_addrhead); 17382cd038dSYoshinobu Inoue TAILQ_INIT(&ifp->if_prefixhead); 1746817526dSPoul-Henning Kamp TAILQ_INIT(&ifp->if_multiaddrs); 17598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 176df8bae1dSRodney W. Grimes if (ifnet_addrs == 0 || if_index >= if_indexlim) { 177df8bae1dSRodney W. Grimes unsigned n = (if_indexlim <<= 1) * sizeof(ifa); 1787cc0979fSDavid Malone caddr_t q = malloc(n, M_IFADDR, M_WAITOK | M_ZERO); 179df8bae1dSRodney W. Grimes if (ifnet_addrs) { 180df8bae1dSRodney W. Grimes bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); 181df8bae1dSRodney W. Grimes free((caddr_t)ifnet_addrs, M_IFADDR); 182df8bae1dSRodney W. Grimes } 18382cd038dSYoshinobu Inoue ifnet_addrs = (struct ifaddr **)q; 18482cd038dSYoshinobu Inoue 18582cd038dSYoshinobu Inoue /* grow ifindex2ifnet */ 18682cd038dSYoshinobu Inoue n = if_indexlim * sizeof(struct ifnet *); 1877cc0979fSDavid Malone q = malloc(n, M_IFADDR, M_WAITOK | M_ZERO); 18882cd038dSYoshinobu Inoue if (ifindex2ifnet) { 18982cd038dSYoshinobu Inoue bcopy((caddr_t)ifindex2ifnet, q, n/2); 19082cd038dSYoshinobu Inoue free((caddr_t)ifindex2ifnet, M_IFADDR); 191df8bae1dSRodney W. Grimes } 19282cd038dSYoshinobu Inoue ifindex2ifnet = (struct ifnet **)q; 19382cd038dSYoshinobu Inoue } 19482cd038dSYoshinobu Inoue 19582cd038dSYoshinobu Inoue ifindex2ifnet[if_index] = ifp; 19682cd038dSYoshinobu Inoue 197df5e1987SJonathan Lemon mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_name, MTX_DEF); 198df5e1987SJonathan Lemon 199df8bae1dSRodney W. Grimes /* 200df8bae1dSRodney W. Grimes * create a Link Level name for this device 201df8bae1dSRodney W. Grimes */ 2022127f260SArchie Cobbs namelen = snprintf(workbuf, sizeof(workbuf), 2032127f260SArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 204df8bae1dSRodney W. Grimes #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 2051ce9bf88SPoul-Henning Kamp masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; 206df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 207df8bae1dSRodney W. Grimes #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 208df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 209df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 2108a261b8fSDoug Rabson socksize = ROUNDUP(socksize); 211df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 2127cc0979fSDavid Malone ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); 2139448326fSPoul-Henning Kamp if (ifa) { 214df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 215df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 216df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 2171ce9bf88SPoul-Henning Kamp bcopy(workbuf, sdl->sdl_data, namelen); 2181ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 219df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 220df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 221df8bae1dSRodney W. Grimes ifnet_addrs[if_index - 1] = ifa; 222df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 223df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = link_rtrequest; 224df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 225df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 226df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 227df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 228df8bae1dSRodney W. Grimes while (namelen != 0) 229df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 23059562606SGarrett Wollman TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 231df8bae1dSRodney W. Grimes } 232df8bae1dSRodney W. Grimes } 2336182fdbdSPeter Wemm 2346182fdbdSPeter Wemm /* 2356182fdbdSPeter Wemm * Detach an interface, removing it from the 2366182fdbdSPeter Wemm * list of "active" interfaces. 2376182fdbdSPeter Wemm */ 2386182fdbdSPeter Wemm void 2396182fdbdSPeter Wemm if_detach(ifp) 2406182fdbdSPeter Wemm struct ifnet *ifp; 2416182fdbdSPeter Wemm { 2426182fdbdSPeter Wemm struct ifaddr *ifa; 2435500d3beSWarner Losh struct radix_node_head *rnh; 2445500d3beSWarner Losh int s; 2455500d3beSWarner Losh int i; 2466182fdbdSPeter Wemm 2476182fdbdSPeter Wemm /* 2486182fdbdSPeter Wemm * Remove routes and flush queues. 2496182fdbdSPeter Wemm */ 2505500d3beSWarner Losh s = splnet(); 2516182fdbdSPeter Wemm if_down(ifp); 2526182fdbdSPeter Wemm 2536182fdbdSPeter Wemm /* 2546182fdbdSPeter Wemm * Remove address from ifnet_addrs[] and maybe decrement if_index. 2556182fdbdSPeter Wemm * Clean up all addresses. 2566182fdbdSPeter Wemm */ 257aa6be122SWarner Losh ifnet_addrs[ifp->if_index - 1] = 0; 258aa6be122SWarner Losh while (if_index > 0 && ifnet_addrs[if_index - 1] == 0) 2596182fdbdSPeter Wemm if_index--; 2606182fdbdSPeter Wemm 2616182fdbdSPeter Wemm for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 2626182fdbdSPeter Wemm ifa = TAILQ_FIRST(&ifp->if_addrhead)) { 2630d0f9d1eSYoshinobu Inoue #ifdef INET 264aa6be122SWarner Losh /* XXX: Ugly!! ad hoc just for INET */ 265aa6be122SWarner Losh if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 266aa6be122SWarner Losh struct ifaliasreq ifr; 267aa6be122SWarner Losh 268aa6be122SWarner Losh bzero(&ifr, sizeof(ifr)); 269aa6be122SWarner Losh ifr.ifra_addr = *ifa->ifa_addr; 270aa6be122SWarner Losh if (ifa->ifa_dstaddr) 271aa6be122SWarner Losh ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 272aa6be122SWarner Losh if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 273aa6be122SWarner Losh NULL) == 0) 274aa6be122SWarner Losh continue; 275aa6be122SWarner Losh } 2760d0f9d1eSYoshinobu Inoue #endif /* INET */ 2770d0f9d1eSYoshinobu Inoue #ifdef INET6 2780d0f9d1eSYoshinobu Inoue if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 27933841545SHajimu UMEMOTO in6_purgeaddr(ifa); 280978ee2edSJun-ichiro itojun Hagino /* ifp_addrhead is already updated */ 2810d0f9d1eSYoshinobu Inoue continue; 2820d0f9d1eSYoshinobu Inoue } 2830d0f9d1eSYoshinobu Inoue #endif /* INET6 */ 2846182fdbdSPeter Wemm TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 2856182fdbdSPeter Wemm IFAFREE(ifa); 2866182fdbdSPeter Wemm } 2876182fdbdSPeter Wemm 28833841545SHajimu UMEMOTO #ifdef INET6 28933841545SHajimu UMEMOTO /* 29033841545SHajimu UMEMOTO * Remove all IPv6 kernel structs related to ifp. This should be done 29133841545SHajimu UMEMOTO * before removing routing entries below, since IPv6 interface direct 29233841545SHajimu UMEMOTO * routes are expected to be removed by the IPv6-specific kernel API. 29333841545SHajimu UMEMOTO * Otherwise, the kernel will detect some inconsistency and bark it. 29433841545SHajimu UMEMOTO */ 29533841545SHajimu UMEMOTO in6_ifdetach(ifp); 29633841545SHajimu UMEMOTO #endif 29733841545SHajimu UMEMOTO 2985500d3beSWarner Losh /* 2995500d3beSWarner Losh * Delete all remaining routes using this interface 3005500d3beSWarner Losh * Unfortuneatly the only way to do this is to slog through 3015500d3beSWarner Losh * the entire routing table looking for routes which point 3025500d3beSWarner Losh * to this interface...oh well... 3035500d3beSWarner Losh */ 3045500d3beSWarner Losh for (i = 1; i <= AF_MAX; i++) { 3055500d3beSWarner Losh if ((rnh = rt_tables[i]) == NULL) 3065500d3beSWarner Losh continue; 3075500d3beSWarner Losh (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); 3085500d3beSWarner Losh } 3095500d3beSWarner Losh 3106182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 311df5e1987SJonathan Lemon mtx_destroy(&ifp->if_snd.ifq_mtx); 3125500d3beSWarner Losh splx(s); 3135500d3beSWarner Losh } 3145500d3beSWarner Losh 3155500d3beSWarner Losh /* 3165500d3beSWarner Losh * Delete Routes for a Network Interface 3175500d3beSWarner Losh * 3185500d3beSWarner Losh * Called for each routing entry via the rnh->rnh_walktree() call above 3195500d3beSWarner Losh * to delete all route entries referencing a detaching network interface. 3205500d3beSWarner Losh * 3215500d3beSWarner Losh * Arguments: 3225500d3beSWarner Losh * rn pointer to node in the routing table 3235500d3beSWarner Losh * arg argument passed to rnh->rnh_walktree() - detaching interface 3245500d3beSWarner Losh * 3255500d3beSWarner Losh * Returns: 3265500d3beSWarner Losh * 0 successful 3275500d3beSWarner Losh * errno failed - reason indicated 3285500d3beSWarner Losh * 3295500d3beSWarner Losh */ 3305500d3beSWarner Losh static int 3315500d3beSWarner Losh if_rtdel(rn, arg) 3325500d3beSWarner Losh struct radix_node *rn; 3335500d3beSWarner Losh void *arg; 3345500d3beSWarner Losh { 3355500d3beSWarner Losh struct rtentry *rt = (struct rtentry *)rn; 3365500d3beSWarner Losh struct ifnet *ifp = arg; 3375500d3beSWarner Losh int err; 3385500d3beSWarner Losh 3395500d3beSWarner Losh if (rt->rt_ifp == ifp) { 3405500d3beSWarner Losh 3415500d3beSWarner Losh /* 3425500d3beSWarner Losh * Protect (sorta) against walktree recursion problems 3435500d3beSWarner Losh * with cloned routes 3445500d3beSWarner Losh */ 3455500d3beSWarner Losh if ((rt->rt_flags & RTF_UP) == 0) 3465500d3beSWarner Losh return (0); 3475500d3beSWarner Losh 3485500d3beSWarner Losh err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 3495500d3beSWarner Losh rt_mask(rt), rt->rt_flags, 3505500d3beSWarner Losh (struct rtentry **) NULL); 3515500d3beSWarner Losh if (err) { 3525500d3beSWarner Losh log(LOG_WARNING, "if_rtdel: error %d\n", err); 3535500d3beSWarner Losh } 3545500d3beSWarner Losh } 3555500d3beSWarner Losh 3565500d3beSWarner Losh return (0); 3576182fdbdSPeter Wemm } 3586182fdbdSPeter Wemm 359df8bae1dSRodney W. Grimes /* 36030aad87dSBrooks Davis * Create a clone network interface. 36130aad87dSBrooks Davis */ 36230aad87dSBrooks Davis int 36330aad87dSBrooks Davis if_clone_create(name, len) 36430aad87dSBrooks Davis char *name; 36530aad87dSBrooks Davis int len; 36630aad87dSBrooks Davis { 36730aad87dSBrooks Davis struct if_clone *ifc; 36830aad87dSBrooks Davis char *dp; 36930aad87dSBrooks Davis int wildcard; 37030aad87dSBrooks Davis int unit; 37130aad87dSBrooks Davis int err; 37230aad87dSBrooks Davis 37330aad87dSBrooks Davis ifc = if_clone_lookup(name, &unit); 37430aad87dSBrooks Davis if (ifc == NULL) 37530aad87dSBrooks Davis return (EINVAL); 37630aad87dSBrooks Davis 37730aad87dSBrooks Davis if (ifunit(name) != NULL) 37830aad87dSBrooks Davis return (EEXIST); 37930aad87dSBrooks Davis 38030aad87dSBrooks Davis wildcard = (unit < 0); 38130aad87dSBrooks Davis 38230aad87dSBrooks Davis err = (*ifc->ifc_create)(ifc, &unit); 38330aad87dSBrooks Davis if (err != 0) 38430aad87dSBrooks Davis return (err); 38530aad87dSBrooks Davis 38630aad87dSBrooks Davis /* In the wildcard case, we need to update the name. */ 38730aad87dSBrooks Davis if (wildcard) { 38830aad87dSBrooks Davis for (dp = name; *dp != '\0'; dp++); 38930aad87dSBrooks Davis if (snprintf(dp, len - (dp-name), "%d", unit) > 39030aad87dSBrooks Davis len - (dp-name) - 1) { 39130aad87dSBrooks Davis /* 39230aad87dSBrooks Davis * This can only be a programmer error and 39330aad87dSBrooks Davis * there's no straightforward way to recover if 39430aad87dSBrooks Davis * it happens. 39530aad87dSBrooks Davis */ 39630aad87dSBrooks Davis panic("if_clone_create(): interface name too long"); 39730aad87dSBrooks Davis } 39830aad87dSBrooks Davis 39930aad87dSBrooks Davis } 40030aad87dSBrooks Davis 40130aad87dSBrooks Davis return (0); 40230aad87dSBrooks Davis } 40330aad87dSBrooks Davis 40430aad87dSBrooks Davis /* 40530aad87dSBrooks Davis * Destroy a clone network interface. 40630aad87dSBrooks Davis */ 40730aad87dSBrooks Davis int 40830aad87dSBrooks Davis if_clone_destroy(name) 40930aad87dSBrooks Davis const char *name; 41030aad87dSBrooks Davis { 41130aad87dSBrooks Davis struct if_clone *ifc; 41230aad87dSBrooks Davis struct ifnet *ifp; 41330aad87dSBrooks Davis 41430aad87dSBrooks Davis ifc = if_clone_lookup(name, NULL); 41530aad87dSBrooks Davis if (ifc == NULL) 41630aad87dSBrooks Davis return (EINVAL); 41730aad87dSBrooks Davis 41830aad87dSBrooks Davis ifp = ifunit(name); 41930aad87dSBrooks Davis if (ifp == NULL) 42030aad87dSBrooks Davis return (ENXIO); 42130aad87dSBrooks Davis 42230aad87dSBrooks Davis if (ifc->ifc_destroy == NULL) 42330aad87dSBrooks Davis return (EOPNOTSUPP); 42430aad87dSBrooks Davis 42530aad87dSBrooks Davis (*ifc->ifc_destroy)(ifp); 42630aad87dSBrooks Davis return (0); 42730aad87dSBrooks Davis } 42830aad87dSBrooks Davis 42930aad87dSBrooks Davis /* 43030aad87dSBrooks Davis * Look up a network interface cloner. 43130aad87dSBrooks Davis */ 43230aad87dSBrooks Davis struct if_clone * 43330aad87dSBrooks Davis if_clone_lookup(name, unitp) 43430aad87dSBrooks Davis const char *name; 43530aad87dSBrooks Davis int *unitp; 43630aad87dSBrooks Davis { 43730aad87dSBrooks Davis struct if_clone *ifc; 43830aad87dSBrooks Davis const char *cp; 43930aad87dSBrooks Davis int i; 44030aad87dSBrooks Davis 44130aad87dSBrooks Davis for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 44230aad87dSBrooks Davis for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 44330aad87dSBrooks Davis if (ifc->ifc_name[i] != *cp) 44430aad87dSBrooks Davis goto next_ifc; 44530aad87dSBrooks Davis } 44630aad87dSBrooks Davis goto found_name; 44730aad87dSBrooks Davis next_ifc: 44830aad87dSBrooks Davis ifc = LIST_NEXT(ifc, ifc_list); 44930aad87dSBrooks Davis } 45030aad87dSBrooks Davis 45130aad87dSBrooks Davis /* No match. */ 45230aad87dSBrooks Davis return ((struct if_clone *)NULL); 45330aad87dSBrooks Davis 45430aad87dSBrooks Davis found_name: 45530aad87dSBrooks Davis if (*cp == '\0') { 45630aad87dSBrooks Davis i = -1; 45730aad87dSBrooks Davis } else { 45830aad87dSBrooks Davis for (i = 0; *cp != '\0'; cp++) { 45930aad87dSBrooks Davis if (*cp < '0' || *cp > '9') { 46030aad87dSBrooks Davis /* Bogus unit number. */ 46130aad87dSBrooks Davis return (NULL); 46230aad87dSBrooks Davis } 46330aad87dSBrooks Davis i = (i * 10) + (*cp - '0'); 46430aad87dSBrooks Davis } 46530aad87dSBrooks Davis } 46630aad87dSBrooks Davis 46730aad87dSBrooks Davis if (unitp != NULL) 46830aad87dSBrooks Davis *unitp = i; 46930aad87dSBrooks Davis return (ifc); 47030aad87dSBrooks Davis } 47130aad87dSBrooks Davis 47230aad87dSBrooks Davis /* 47330aad87dSBrooks Davis * Register a network interface cloner. 47430aad87dSBrooks Davis */ 47530aad87dSBrooks Davis void 47630aad87dSBrooks Davis if_clone_attach(ifc) 47730aad87dSBrooks Davis struct if_clone *ifc; 47830aad87dSBrooks Davis { 47930aad87dSBrooks Davis 48030aad87dSBrooks Davis LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 48130aad87dSBrooks Davis if_cloners_count++; 48230aad87dSBrooks Davis } 48330aad87dSBrooks Davis 48430aad87dSBrooks Davis /* 48530aad87dSBrooks Davis * Unregister a network interface cloner. 48630aad87dSBrooks Davis */ 48730aad87dSBrooks Davis void 48830aad87dSBrooks Davis if_clone_detach(ifc) 48930aad87dSBrooks Davis struct if_clone *ifc; 49030aad87dSBrooks Davis { 49130aad87dSBrooks Davis 49230aad87dSBrooks Davis LIST_REMOVE(ifc, ifc_list); 49330aad87dSBrooks Davis if_cloners_count--; 49430aad87dSBrooks Davis } 49530aad87dSBrooks Davis 49630aad87dSBrooks Davis /* 49730aad87dSBrooks Davis * Provide list of interface cloners to userspace. 49830aad87dSBrooks Davis */ 49930aad87dSBrooks Davis int 50030aad87dSBrooks Davis if_clone_list(ifcr) 50130aad87dSBrooks Davis struct if_clonereq *ifcr; 50230aad87dSBrooks Davis { 50330aad87dSBrooks Davis char outbuf[IFNAMSIZ], *dst; 50430aad87dSBrooks Davis struct if_clone *ifc; 50530aad87dSBrooks Davis int count, error = 0; 50630aad87dSBrooks Davis 50730aad87dSBrooks Davis ifcr->ifcr_total = if_cloners_count; 50830aad87dSBrooks Davis if ((dst = ifcr->ifcr_buffer) == NULL) { 50930aad87dSBrooks Davis /* Just asking how many there are. */ 51030aad87dSBrooks Davis return (0); 51130aad87dSBrooks Davis } 51230aad87dSBrooks Davis 51330aad87dSBrooks Davis if (ifcr->ifcr_count < 0) 51430aad87dSBrooks Davis return (EINVAL); 51530aad87dSBrooks Davis 51630aad87dSBrooks Davis count = (if_cloners_count < ifcr->ifcr_count) ? 51730aad87dSBrooks Davis if_cloners_count : ifcr->ifcr_count; 51830aad87dSBrooks Davis 51930aad87dSBrooks Davis for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 52030aad87dSBrooks Davis ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 52130aad87dSBrooks Davis strncpy(outbuf, ifc->ifc_name, IFNAMSIZ); 52230aad87dSBrooks Davis outbuf[IFNAMSIZ - 1] = '\0'; /* sanity */ 52330aad87dSBrooks Davis error = copyout(outbuf, dst, IFNAMSIZ); 52430aad87dSBrooks Davis if (error) 52530aad87dSBrooks Davis break; 52630aad87dSBrooks Davis } 52730aad87dSBrooks Davis 52830aad87dSBrooks Davis return (error); 52930aad87dSBrooks Davis } 53030aad87dSBrooks Davis 53130aad87dSBrooks Davis /* 532df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 533df8bae1dSRodney W. Grimes */ 534df8bae1dSRodney W. Grimes /*ARGSUSED*/ 535df8bae1dSRodney W. Grimes struct ifaddr * 536df8bae1dSRodney W. Grimes ifa_ifwithaddr(addr) 537df8bae1dSRodney W. Grimes register struct sockaddr *addr; 538df8bae1dSRodney W. Grimes { 539df8bae1dSRodney W. Grimes register struct ifnet *ifp; 540df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 541df8bae1dSRodney W. Grimes 542df8bae1dSRodney W. Grimes #define equal(a1, a2) \ 543df8bae1dSRodney W. Grimes (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 544fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) 54537d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 546df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 547df8bae1dSRodney W. Grimes continue; 548df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr)) 549df8bae1dSRodney W. Grimes return (ifa); 550df8bae1dSRodney W. Grimes if ((ifp->if_flags & IFF_BROADCAST) && ifa->ifa_broadaddr && 55182cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 55282cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 553df8bae1dSRodney W. Grimes equal(ifa->ifa_broadaddr, addr)) 554df8bae1dSRodney W. Grimes return (ifa); 555df8bae1dSRodney W. Grimes } 556df8bae1dSRodney W. Grimes return ((struct ifaddr *)0); 557df8bae1dSRodney W. Grimes } 558df8bae1dSRodney W. Grimes /* 559df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 560df8bae1dSRodney W. Grimes */ 561df8bae1dSRodney W. Grimes /*ARGSUSED*/ 562df8bae1dSRodney W. Grimes struct ifaddr * 563df8bae1dSRodney W. Grimes ifa_ifwithdstaddr(addr) 564df8bae1dSRodney W. Grimes register struct sockaddr *addr; 565df8bae1dSRodney W. Grimes { 566df8bae1dSRodney W. Grimes register struct ifnet *ifp; 567df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 568df8bae1dSRodney W. Grimes 569fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) 570df8bae1dSRodney W. Grimes if (ifp->if_flags & IFF_POINTOPOINT) 57137d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 572df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 573df8bae1dSRodney W. Grimes continue; 57455088a1cSDavid Greenman if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) 575df8bae1dSRodney W. Grimes return (ifa); 576df8bae1dSRodney W. Grimes } 577df8bae1dSRodney W. Grimes return ((struct ifaddr *)0); 578df8bae1dSRodney W. Grimes } 579df8bae1dSRodney W. Grimes 580df8bae1dSRodney W. Grimes /* 581df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 582df8bae1dSRodney W. Grimes * is most specific found. 583df8bae1dSRodney W. Grimes */ 584df8bae1dSRodney W. Grimes struct ifaddr * 585df8bae1dSRodney W. Grimes ifa_ifwithnet(addr) 586df8bae1dSRodney W. Grimes struct sockaddr *addr; 587df8bae1dSRodney W. Grimes { 588df8bae1dSRodney W. Grimes register struct ifnet *ifp; 589df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 590df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 591df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 592df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 593df8bae1dSRodney W. Grimes 5947e2a6151SJulian Elischer /* 5957e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 5967e2a6151SJulian Elischer * so do that if we can. 5977e2a6151SJulian Elischer */ 598df8bae1dSRodney W. Grimes if (af == AF_LINK) { 599df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 600df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 601df8bae1dSRodney W. Grimes return (ifnet_addrs[sdl->sdl_index - 1]); 602df8bae1dSRodney W. Grimes } 6037e2a6151SJulian Elischer 6047e2a6151SJulian Elischer /* 6057e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 6067e2a6151SJulian Elischer * addresses in this address family. 6077e2a6151SJulian Elischer */ 608fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 60937d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 610df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 611df8bae1dSRodney W. Grimes 612523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 613df8bae1dSRodney W. Grimes next: continue; 61482cd038dSYoshinobu Inoue if ( 61582cd038dSYoshinobu Inoue #ifdef INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */ 61682cd038dSYoshinobu Inoue addr->sa_family != AF_INET6 && 61782cd038dSYoshinobu Inoue #endif 61882cd038dSYoshinobu Inoue ifp->if_flags & IFF_POINTOPOINT) { 6197e2a6151SJulian Elischer /* 6207e2a6151SJulian Elischer * This is a bit broken as it doesn't 6217e2a6151SJulian Elischer * take into account that the remote end may 6227e2a6151SJulian Elischer * be a single node in the network we are 6237e2a6151SJulian Elischer * looking for. 6247e2a6151SJulian Elischer * The trouble is that we don't know the 6257e2a6151SJulian Elischer * netmask for the remote end. 6267e2a6151SJulian Elischer */ 627fcd6781aSGarrett Wollman if (ifa->ifa_dstaddr != 0 628fcd6781aSGarrett Wollman && equal(addr, ifa->ifa_dstaddr)) 629b2af64fdSDavid Greenman return (ifa); 6303740e2adSDavid Greenman } else { 6317e2a6151SJulian Elischer /* 6327ed8f465SJulian Elischer * if we have a special address handler, 6337ed8f465SJulian Elischer * then use it instead of the generic one. 6347ed8f465SJulian Elischer */ 6357ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 6367ed8f465SJulian Elischer if ((*ifa->ifa_claim_addr)(ifa, addr)) { 6377ed8f465SJulian Elischer return (ifa); 6387ed8f465SJulian Elischer } else { 6397ed8f465SJulian Elischer continue; 6407ed8f465SJulian Elischer } 6417ed8f465SJulian Elischer } 6427ed8f465SJulian Elischer 6437ed8f465SJulian Elischer /* 6447e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 6457e2a6151SJulian Elischer * If a bit dissagrees with what we are 6467e2a6151SJulian Elischer * looking for, mask it with the netmask 6477e2a6151SJulian Elischer * to see if it really matters. 6487e2a6151SJulian Elischer * (A byte at a time) 6497e2a6151SJulian Elischer */ 650523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 651523a02aaSDavid Greenman continue; 652df8bae1dSRodney W. Grimes cp = addr_data; 653df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 654df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 6557e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 6567e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 657df8bae1dSRodney W. Grimes while (cp3 < cplim) 658df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 6597e2a6151SJulian Elischer goto next; /* next address! */ 6607e2a6151SJulian Elischer /* 6617e2a6151SJulian Elischer * If the netmask of what we just found 6627e2a6151SJulian Elischer * is more specific than what we had before 6637e2a6151SJulian Elischer * (if we had one) then remember the new one 6647e2a6151SJulian Elischer * before continuing to search 6657e2a6151SJulian Elischer * for an even better one. 6667e2a6151SJulian Elischer */ 667df8bae1dSRodney W. Grimes if (ifa_maybe == 0 || 668df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 669df8bae1dSRodney W. Grimes (caddr_t)ifa_maybe->ifa_netmask)) 670df8bae1dSRodney W. Grimes ifa_maybe = ifa; 671df8bae1dSRodney W. Grimes } 672b2af64fdSDavid Greenman } 673b2af64fdSDavid Greenman } 674df8bae1dSRodney W. Grimes return (ifa_maybe); 675df8bae1dSRodney W. Grimes } 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes /* 678df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 679df8bae1dSRodney W. Grimes * a given address. 680df8bae1dSRodney W. Grimes */ 681df8bae1dSRodney W. Grimes struct ifaddr * 682df8bae1dSRodney W. Grimes ifaof_ifpforaddr(addr, ifp) 683df8bae1dSRodney W. Grimes struct sockaddr *addr; 684df8bae1dSRodney W. Grimes register struct ifnet *ifp; 685df8bae1dSRodney W. Grimes { 686df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 687df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 688df8bae1dSRodney W. Grimes register char *cplim; 689df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 690df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 691df8bae1dSRodney W. Grimes 692df8bae1dSRodney W. Grimes if (af >= AF_MAX) 693df8bae1dSRodney W. Grimes return (0); 69437d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 695df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 696df8bae1dSRodney W. Grimes continue; 697381dd1d2SJulian Elischer if (ifa_maybe == 0) 698df8bae1dSRodney W. Grimes ifa_maybe = ifa; 699df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 700df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr) || 701df8bae1dSRodney W. Grimes (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 702df8bae1dSRodney W. Grimes return (ifa); 703df8bae1dSRodney W. Grimes continue; 704df8bae1dSRodney W. Grimes } 705b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 706b2af64fdSDavid Greenman if (equal(addr, ifa->ifa_dstaddr)) 707b2af64fdSDavid Greenman return (ifa); 7083740e2adSDavid Greenman } else { 709df8bae1dSRodney W. Grimes cp = addr->sa_data; 710df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 711df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 712df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 713df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 714df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 715df8bae1dSRodney W. Grimes break; 716df8bae1dSRodney W. Grimes if (cp3 == cplim) 717df8bae1dSRodney W. Grimes return (ifa); 718df8bae1dSRodney W. Grimes } 719b2af64fdSDavid Greenman } 720df8bae1dSRodney W. Grimes return (ifa_maybe); 721df8bae1dSRodney W. Grimes } 722df8bae1dSRodney W. Grimes 723df8bae1dSRodney W. Grimes #include <net/route.h> 724df8bae1dSRodney W. Grimes 725df8bae1dSRodney W. Grimes /* 726df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 727df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 728df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 729df8bae1dSRodney W. Grimes */ 7303bda9f9bSPoul-Henning Kamp static void 731df8bae1dSRodney W. Grimes link_rtrequest(cmd, rt, sa) 732df8bae1dSRodney W. Grimes int cmd; 733df8bae1dSRodney W. Grimes register struct rtentry *rt; 734df8bae1dSRodney W. Grimes struct sockaddr *sa; 735df8bae1dSRodney W. Grimes { 736df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 737df8bae1dSRodney W. Grimes struct sockaddr *dst; 738df8bae1dSRodney W. Grimes struct ifnet *ifp; 739df8bae1dSRodney W. Grimes 740df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 741df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 742df8bae1dSRodney W. Grimes return; 7439448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 7449448326fSPoul-Henning Kamp if (ifa) { 745df8bae1dSRodney W. Grimes IFAFREE(rt->rt_ifa); 746df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 747df8bae1dSRodney W. Grimes ifa->ifa_refcnt++; 748df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 749df8bae1dSRodney W. Grimes ifa->ifa_rtrequest(cmd, rt, sa); 750df8bae1dSRodney W. Grimes } 751df8bae1dSRodney W. Grimes } 752df8bae1dSRodney W. Grimes 753df8bae1dSRodney W. Grimes /* 754df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 755df8bae1dSRodney W. Grimes * the transition. 756df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 757df8bae1dSRodney W. Grimes */ 758df8bae1dSRodney W. Grimes void 759e8c2601dSPoul-Henning Kamp if_unroute(ifp, flag, fam) 760df8bae1dSRodney W. Grimes register struct ifnet *ifp; 761e8c2601dSPoul-Henning Kamp int flag, fam; 762df8bae1dSRodney W. Grimes { 763df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 764df8bae1dSRodney W. Grimes 765e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 76698b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 767e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 768e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 769df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 770df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 771df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 772df8bae1dSRodney W. Grimes } 773df8bae1dSRodney W. Grimes 774df8bae1dSRodney W. Grimes /* 775df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 776df8bae1dSRodney W. Grimes * the transition. 777df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 778df8bae1dSRodney W. Grimes */ 779df8bae1dSRodney W. Grimes void 780e8c2601dSPoul-Henning Kamp if_route(ifp, flag, fam) 781df8bae1dSRodney W. Grimes register struct ifnet *ifp; 782e8c2601dSPoul-Henning Kamp int flag, fam; 783df8bae1dSRodney W. Grimes { 784176395b2SGarrett Wollman register struct ifaddr *ifa; 785df8bae1dSRodney W. Grimes 786e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 78798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 788e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 789e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 790df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 791df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 79282cd038dSYoshinobu Inoue #ifdef INET6 79382cd038dSYoshinobu Inoue in6_if_up(ifp); 79482cd038dSYoshinobu Inoue #endif 795df8bae1dSRodney W. Grimes } 796df8bae1dSRodney W. Grimes 797df8bae1dSRodney W. Grimes /* 798e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 799e8c2601dSPoul-Henning Kamp * the transition. 800e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 801e8c2601dSPoul-Henning Kamp */ 802e8c2601dSPoul-Henning Kamp void 803e8c2601dSPoul-Henning Kamp if_down(ifp) 804e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 805e8c2601dSPoul-Henning Kamp { 806e8c2601dSPoul-Henning Kamp 807e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 808e8c2601dSPoul-Henning Kamp } 809e8c2601dSPoul-Henning Kamp 810e8c2601dSPoul-Henning Kamp /* 811e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 812e8c2601dSPoul-Henning Kamp * the transition. 813e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 814e8c2601dSPoul-Henning Kamp */ 815e8c2601dSPoul-Henning Kamp void 816e8c2601dSPoul-Henning Kamp if_up(ifp) 817e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 818e8c2601dSPoul-Henning Kamp { 819e8c2601dSPoul-Henning Kamp 820e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 821e8c2601dSPoul-Henning Kamp } 822e8c2601dSPoul-Henning Kamp 823e8c2601dSPoul-Henning Kamp /* 824df8bae1dSRodney W. Grimes * Flush an interface queue. 825df8bae1dSRodney W. Grimes */ 8263bda9f9bSPoul-Henning Kamp static void 827df8bae1dSRodney W. Grimes if_qflush(ifq) 828df8bae1dSRodney W. Grimes register struct ifqueue *ifq; 829df8bae1dSRodney W. Grimes { 830df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 831df8bae1dSRodney W. Grimes 832df8bae1dSRodney W. Grimes n = ifq->ifq_head; 8339448326fSPoul-Henning Kamp while ((m = n) != 0) { 834df8bae1dSRodney W. Grimes n = m->m_act; 835df8bae1dSRodney W. Grimes m_freem(m); 836df8bae1dSRodney W. Grimes } 837df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 838df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 839df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 840df8bae1dSRodney W. Grimes } 841df8bae1dSRodney W. Grimes 842df8bae1dSRodney W. Grimes /* 843df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 844df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 845df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 846df8bae1dSRodney W. Grimes */ 8473bda9f9bSPoul-Henning Kamp static void 848df8bae1dSRodney W. Grimes if_slowtimo(arg) 849df8bae1dSRodney W. Grimes void *arg; 850df8bae1dSRodney W. Grimes { 851df8bae1dSRodney W. Grimes register struct ifnet *ifp; 852df8bae1dSRodney W. Grimes int s = splimp(); 853df8bae1dSRodney W. Grimes 854fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 855df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 856df8bae1dSRodney W. Grimes continue; 857df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 8584a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 859df8bae1dSRodney W. Grimes } 860df8bae1dSRodney W. Grimes splx(s); 861df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 862df8bae1dSRodney W. Grimes } 863df8bae1dSRodney W. Grimes 864df8bae1dSRodney W. Grimes /* 865df8bae1dSRodney W. Grimes * Map interface name to 866df8bae1dSRodney W. Grimes * interface structure pointer. 867df8bae1dSRodney W. Grimes */ 868df8bae1dSRodney W. Grimes struct ifnet * 86930aad87dSBrooks Davis ifunit(const char *name) 870df8bae1dSRodney W. Grimes { 87101f0fef3SJulian Elischer char namebuf[IFNAMSIZ + 1]; 87230aad87dSBrooks Davis const char *cp; 8738b7805e4SBoris Popov struct ifnet *ifp; 874df8bae1dSRodney W. Grimes int unit; 8758b7805e4SBoris Popov unsigned len, m; 8768b7805e4SBoris Popov char c; 877df8bae1dSRodney W. Grimes 8788b7805e4SBoris Popov len = strlen(name); 8798b7805e4SBoris Popov if (len < 2 || len > IFNAMSIZ) 8808b7805e4SBoris Popov return NULL; 8818b7805e4SBoris Popov cp = name + len - 1; 8828b7805e4SBoris Popov c = *cp; 8838b7805e4SBoris Popov if (c < '0' || c > '9') 8848b7805e4SBoris Popov return NULL; /* trailing garbage */ 8858b7805e4SBoris Popov unit = 0; 8868b7805e4SBoris Popov m = 1; 8878b7805e4SBoris Popov do { 8888b7805e4SBoris Popov if (cp == name) 8898b7805e4SBoris Popov return NULL; /* no interface name */ 8908b7805e4SBoris Popov unit += (c - '0') * m; 8918b7805e4SBoris Popov if (unit > 1000000) 8928b7805e4SBoris Popov return NULL; /* number is unreasonable */ 8938b7805e4SBoris Popov m *= 10; 8948b7805e4SBoris Popov c = *--cp; 8958b7805e4SBoris Popov } while (c >= '0' && c <= '9'); 896df8bae1dSRodney W. Grimes len = cp - name + 1; 8978b7805e4SBoris Popov bcopy(name, namebuf, len); 8988b7805e4SBoris Popov namebuf[len] = '\0'; 89901f0fef3SJulian Elischer /* 90001f0fef3SJulian Elischer * Now search all the interfaces for this name/number 90101f0fef3SJulian Elischer */ 902fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 9038b7805e4SBoris Popov if (strcmp(ifp->if_name, namebuf)) 904df8bae1dSRodney W. Grimes continue; 905df8bae1dSRodney W. Grimes if (unit == ifp->if_unit) 906df8bae1dSRodney W. Grimes break; 907df8bae1dSRodney W. Grimes } 908df8bae1dSRodney W. Grimes return (ifp); 909df8bae1dSRodney W. Grimes } 910df8bae1dSRodney W. Grimes 91182cd038dSYoshinobu Inoue 91282cd038dSYoshinobu Inoue /* 91382cd038dSYoshinobu Inoue * Map interface name in a sockaddr_dl to 91482cd038dSYoshinobu Inoue * interface structure pointer. 91582cd038dSYoshinobu Inoue */ 91682cd038dSYoshinobu Inoue struct ifnet * 91782cd038dSYoshinobu Inoue if_withname(sa) 91882cd038dSYoshinobu Inoue struct sockaddr *sa; 91982cd038dSYoshinobu Inoue { 92082cd038dSYoshinobu Inoue char ifname[IFNAMSIZ+1]; 92182cd038dSYoshinobu Inoue struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 92282cd038dSYoshinobu Inoue 92382cd038dSYoshinobu Inoue if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) || 92482cd038dSYoshinobu Inoue (sdl->sdl_nlen > IFNAMSIZ) ) 92582cd038dSYoshinobu Inoue return NULL; 92682cd038dSYoshinobu Inoue 92782cd038dSYoshinobu Inoue /* 92882cd038dSYoshinobu Inoue * ifunit wants a null-terminated name. It may not be null-terminated 92982cd038dSYoshinobu Inoue * in the sockaddr. We don't want to change the caller's sockaddr, 93082cd038dSYoshinobu Inoue * and there might not be room to put the trailing null anyway, so we 93182cd038dSYoshinobu Inoue * make a local copy that we know we can null terminate safely. 93282cd038dSYoshinobu Inoue */ 93382cd038dSYoshinobu Inoue 93482cd038dSYoshinobu Inoue bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen); 93582cd038dSYoshinobu Inoue ifname[sdl->sdl_nlen] = '\0'; 93682cd038dSYoshinobu Inoue return ifunit(ifname); 93782cd038dSYoshinobu Inoue } 93882cd038dSYoshinobu Inoue 93982cd038dSYoshinobu Inoue 940df8bae1dSRodney W. Grimes /* 941df8bae1dSRodney W. Grimes * Interface ioctls. 942df8bae1dSRodney W. Grimes */ 943df8bae1dSRodney W. Grimes int 944df8bae1dSRodney W. Grimes ifioctl(so, cmd, data, p) 945df8bae1dSRodney W. Grimes struct socket *so; 946ecbb00a2SDoug Rabson u_long cmd; 947df8bae1dSRodney W. Grimes caddr_t data; 948df8bae1dSRodney W. Grimes struct proc *p; 949df8bae1dSRodney W. Grimes { 950df8bae1dSRodney W. Grimes register struct ifnet *ifp; 951df8bae1dSRodney W. Grimes register struct ifreq *ifr; 952413dd0baSPoul-Henning Kamp struct ifstat *ifs; 953df8bae1dSRodney W. Grimes int error; 95482cd038dSYoshinobu Inoue short oif_flags; 955df8bae1dSRodney W. Grimes 956df8bae1dSRodney W. Grimes switch (cmd) { 957df8bae1dSRodney W. Grimes 958df8bae1dSRodney W. Grimes case SIOCGIFCONF: 959df8bae1dSRodney W. Grimes case OSIOCGIFCONF: 960df8bae1dSRodney W. Grimes return (ifconf(cmd, data)); 961df8bae1dSRodney W. Grimes } 962df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 96330aad87dSBrooks Davis 96430aad87dSBrooks Davis switch (cmd) { 96530aad87dSBrooks Davis case SIOCIFCREATE: 96630aad87dSBrooks Davis case SIOCIFDESTROY: 96730aad87dSBrooks Davis if ((error = suser(p)) != 0) 96830aad87dSBrooks Davis return (error); 96930aad87dSBrooks Davis return ((cmd == SIOCIFCREATE) ? 97030aad87dSBrooks Davis if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) : 97130aad87dSBrooks Davis if_clone_destroy(ifr->ifr_name)); 97230aad87dSBrooks Davis 97330aad87dSBrooks Davis case SIOCIFGCLONERS: 97430aad87dSBrooks Davis return (if_clone_list((struct if_clonereq *)data)); 97530aad87dSBrooks Davis } 97630aad87dSBrooks Davis 977df8bae1dSRodney W. Grimes ifp = ifunit(ifr->ifr_name); 978df8bae1dSRodney W. Grimes if (ifp == 0) 979df8bae1dSRodney W. Grimes return (ENXIO); 980df8bae1dSRodney W. Grimes switch (cmd) { 981df8bae1dSRodney W. Grimes 982df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 983df8bae1dSRodney W. Grimes ifr->ifr_flags = ifp->if_flags; 984df8bae1dSRodney W. Grimes break; 985df8bae1dSRodney W. Grimes 986df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 987df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 988df8bae1dSRodney W. Grimes break; 989df8bae1dSRodney W. Grimes 990a7028af7SDavid Greenman case SIOCGIFMTU: 991a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 992a7028af7SDavid Greenman break; 993a7028af7SDavid Greenman 994074c4a4eSGarrett Wollman case SIOCGIFPHYS: 995074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 996074c4a4eSGarrett Wollman break; 997074c4a4eSGarrett Wollman 998df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 999f711d546SPoul-Henning Kamp error = suser(p); 10009448326fSPoul-Henning Kamp if (error) 1001df8bae1dSRodney W. Grimes return (error); 10024add131eSPoul-Henning Kamp ifr->ifr_prevflags = ifp->if_flags; 1003cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 1004cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 10052f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 1006cf4b9371SPoul-Henning Kamp (ifr->ifr_flags & IFF_UP) == 0) { 1007df8bae1dSRodney W. Grimes int s = splimp(); 1008df8bae1dSRodney W. Grimes if_down(ifp); 1009df8bae1dSRodney W. Grimes splx(s); 1010cf4b9371SPoul-Henning Kamp } else if (ifr->ifr_flags & IFF_UP && 1011cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 1012df8bae1dSRodney W. Grimes int s = splimp(); 1013df8bae1dSRodney W. Grimes if_up(ifp); 1014df8bae1dSRodney W. Grimes splx(s); 1015df8bae1dSRodney W. Grimes } 1016df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 1017df8bae1dSRodney W. Grimes (ifr->ifr_flags &~ IFF_CANTCHANGE); 1018df8bae1dSRodney W. Grimes if (ifp->if_ioctl) 1019df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 102098b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1021df8bae1dSRodney W. Grimes break; 1022df8bae1dSRodney W. Grimes 1023df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 1024f711d546SPoul-Henning Kamp error = suser(p); 10259448326fSPoul-Henning Kamp if (error) 1026df8bae1dSRodney W. Grimes return (error); 1027df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 102898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1029df8bae1dSRodney W. Grimes break; 1030df8bae1dSRodney W. Grimes 1031074c4a4eSGarrett Wollman case SIOCSIFPHYS: 1032f711d546SPoul-Henning Kamp error = suser(p); 1033e39a0280SGary Palmer if (error) 1034e39a0280SGary Palmer return error; 1035e39a0280SGary Palmer if (!ifp->if_ioctl) 1036e39a0280SGary Palmer return EOPNOTSUPP; 1037e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 1038e39a0280SGary Palmer if (error == 0) 103998b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1040e39a0280SGary Palmer return(error); 1041074c4a4eSGarrett Wollman 1042a7028af7SDavid Greenman case SIOCSIFMTU: 104382cd038dSYoshinobu Inoue { 104482cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 104582cd038dSYoshinobu Inoue 1046f711d546SPoul-Henning Kamp error = suser(p); 10479448326fSPoul-Henning Kamp if (error) 1048a7028af7SDavid Greenman return (error); 1049a7028af7SDavid Greenman if (ifp->if_ioctl == NULL) 1050a7028af7SDavid Greenman return (EOPNOTSUPP); 1051aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 105275ee03cbSDavid Greenman return (EINVAL); 1053e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 105448f71763SRuslan Ermilov if (error == 0) { 105598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 105648f71763SRuslan Ermilov rt_ifmsg(ifp); 105748f71763SRuslan Ermilov } 105882cd038dSYoshinobu Inoue /* 105982cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 106082cd038dSYoshinobu Inoue */ 106182cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 106282cd038dSYoshinobu Inoue #ifdef INET6 106382cd038dSYoshinobu Inoue nd6_setmtu(ifp); 106482cd038dSYoshinobu Inoue #endif 106582cd038dSYoshinobu Inoue } 1066e39a0280SGary Palmer return (error); 106782cd038dSYoshinobu Inoue } 1068a7028af7SDavid Greenman 1069df8bae1dSRodney W. Grimes case SIOCADDMULTI: 1070df8bae1dSRodney W. Grimes case SIOCDELMULTI: 1071f711d546SPoul-Henning Kamp error = suser(p); 10729448326fSPoul-Henning Kamp if (error) 1073df8bae1dSRodney W. Grimes return (error); 1074477180fbSGarrett Wollman 1075477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 1076477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 1077477180fbSGarrett Wollman return EOPNOTSUPP; 1078477180fbSGarrett Wollman 1079477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 1080477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 1081477180fbSGarrett Wollman return EINVAL; 1082477180fbSGarrett Wollman 1083477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 1084477180fbSGarrett Wollman struct ifmultiaddr *ifma; 1085477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 1086477180fbSGarrett Wollman } else { 1087477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 1088477180fbSGarrett Wollman } 1089e39a0280SGary Palmer if (error == 0) 109098b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1091477180fbSGarrett Wollman return error; 1092df8bae1dSRodney W. Grimes 109341b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 109441b3e8e5SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 109541b3e8e5SJun-ichiro itojun Hagino #ifdef INET6 109641b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 109741b3e8e5SJun-ichiro itojun Hagino #endif 109833841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 1099a912e453SPeter Wemm case SIOCSIFMEDIA: 1100d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 1101f711d546SPoul-Henning Kamp error = suser(p); 1102a912e453SPeter Wemm if (error) 1103a912e453SPeter Wemm return (error); 1104a912e453SPeter Wemm if (ifp->if_ioctl == 0) 1105a912e453SPeter Wemm return (EOPNOTSUPP); 1106a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 1107a912e453SPeter Wemm if (error == 0) 110898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1109a912e453SPeter Wemm return error; 1110a912e453SPeter Wemm 1111413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 1112413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 1113413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 1114413dd0baSPoul-Henning Kamp 111533841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 111633841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 111733841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 1118a912e453SPeter Wemm case SIOCGIFMEDIA: 1119d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 1120a912e453SPeter Wemm if (ifp->if_ioctl == 0) 1121a912e453SPeter Wemm return (EOPNOTSUPP); 1122a912e453SPeter Wemm return ((*ifp->if_ioctl)(ifp, cmd, data)); 1123a912e453SPeter Wemm 1124b106252cSBill Paul case SIOCSIFLLADDR: 1125b106252cSBill Paul error = suser(p); 1126b106252cSBill Paul if (error) 1127b106252cSBill Paul return (error); 112866ce51ceSArchie Cobbs return if_setlladdr(ifp, 112966ce51ceSArchie Cobbs ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 113066ce51ceSArchie Cobbs 1131df8bae1dSRodney W. Grimes default: 113282cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 1133df8bae1dSRodney W. Grimes if (so->so_proto == 0) 1134df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 1135df8bae1dSRodney W. Grimes #ifndef COMPAT_43 113682cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 11372c37256eSGarrett Wollman data, 1138bc6d9b80SJoerg Wunsch ifp, p)); 1139df8bae1dSRodney W. Grimes #else 1140df8bae1dSRodney W. Grimes { 1141df8bae1dSRodney W. Grimes int ocmd = cmd; 1142df8bae1dSRodney W. Grimes 1143df8bae1dSRodney W. Grimes switch (cmd) { 1144df8bae1dSRodney W. Grimes 1145df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 1146df8bae1dSRodney W. Grimes case SIOCSIFADDR: 1147df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 1148df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 1149df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 1150df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 1151df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 1152df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 1153df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1154df8bae1dSRodney W. Grimes } 1155df8bae1dSRodney W. Grimes #else 1156df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 1157df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1158df8bae1dSRodney W. Grimes #endif 1159df8bae1dSRodney W. Grimes break; 1160df8bae1dSRodney W. Grimes 1161df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1162df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 1163df8bae1dSRodney W. Grimes break; 1164df8bae1dSRodney W. Grimes 1165df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1166df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 1167df8bae1dSRodney W. Grimes break; 1168df8bae1dSRodney W. Grimes 1169df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1170df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 1171df8bae1dSRodney W. Grimes break; 1172df8bae1dSRodney W. Grimes 1173df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1174df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 1175df8bae1dSRodney W. Grimes } 11762c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 11772c37256eSGarrett Wollman cmd, 11782c37256eSGarrett Wollman data, 1179a29f300eSGarrett Wollman ifp, p)); 1180df8bae1dSRodney W. Grimes switch (ocmd) { 1181df8bae1dSRodney W. Grimes 1182df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1183df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1184df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1185df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1186df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 118782cd038dSYoshinobu Inoue 118882cd038dSYoshinobu Inoue } 118982cd038dSYoshinobu Inoue } 119082cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 119182cd038dSYoshinobu Inoue 119282cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 119382cd038dSYoshinobu Inoue #ifdef INET6 11943411310dSYoshinobu Inoue DELAY(100);/* XXX: temporal workaround for fxp issue*/ 119582cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 119682cd038dSYoshinobu Inoue int s = splimp(); 119782cd038dSYoshinobu Inoue in6_if_up(ifp); 119882cd038dSYoshinobu Inoue splx(s); 119982cd038dSYoshinobu Inoue } 120082cd038dSYoshinobu Inoue #endif 1201df8bae1dSRodney W. Grimes } 1202df8bae1dSRodney W. Grimes return (error); 1203df8bae1dSRodney W. Grimes 1204df8bae1dSRodney W. Grimes } 1205df8bae1dSRodney W. Grimes return (0); 1206df8bae1dSRodney W. Grimes } 1207df8bae1dSRodney W. Grimes 1208df8bae1dSRodney W. Grimes /* 1209963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 1210963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 1211963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 1212963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 1213963e4c2aSGarrett Wollman */ 1214963e4c2aSGarrett Wollman int 1215963e4c2aSGarrett Wollman ifpromisc(ifp, pswitch) 1216963e4c2aSGarrett Wollman struct ifnet *ifp; 1217963e4c2aSGarrett Wollman int pswitch; 1218963e4c2aSGarrett Wollman { 1219963e4c2aSGarrett Wollman struct ifreq ifr; 12204a26224cSGarrett Wollman int error; 12214f3c11a6SBill Fenner int oldflags, oldpcount; 1222963e4c2aSGarrett Wollman 12234f3c11a6SBill Fenner oldpcount = ifp->if_pcount; 12242c514a31SBrian Somers oldflags = ifp->if_flags; 1225963e4c2aSGarrett Wollman if (pswitch) { 1226963e4c2aSGarrett Wollman /* 1227963e4c2aSGarrett Wollman * If the device is not configured up, we cannot put it in 1228963e4c2aSGarrett Wollman * promiscuous mode. 1229963e4c2aSGarrett Wollman */ 1230963e4c2aSGarrett Wollman if ((ifp->if_flags & IFF_UP) == 0) 1231963e4c2aSGarrett Wollman return (ENETDOWN); 1232963e4c2aSGarrett Wollman if (ifp->if_pcount++ != 0) 1233963e4c2aSGarrett Wollman return (0); 1234963e4c2aSGarrett Wollman ifp->if_flags |= IFF_PROMISC; 1235963e4c2aSGarrett Wollman } else { 1236963e4c2aSGarrett Wollman if (--ifp->if_pcount > 0) 1237963e4c2aSGarrett Wollman return (0); 1238963e4c2aSGarrett Wollman ifp->if_flags &= ~IFF_PROMISC; 1239963e4c2aSGarrett Wollman } 1240963e4c2aSGarrett Wollman ifr.ifr_flags = ifp->if_flags; 12414a26224cSGarrett Wollman error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 12424f3c11a6SBill Fenner if (error == 0) { 12434f3c11a6SBill Fenner log(LOG_INFO, "%s%d: promiscuous mode %s\n", 12444f3c11a6SBill Fenner ifp->if_name, ifp->if_unit, 12454f3c11a6SBill Fenner (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 12464a26224cSGarrett Wollman rt_ifmsg(ifp); 12474f3c11a6SBill Fenner } else { 12484f3c11a6SBill Fenner ifp->if_pcount = oldpcount; 12492c514a31SBrian Somers ifp->if_flags = oldflags; 12504f3c11a6SBill Fenner } 12514a26224cSGarrett Wollman return error; 1252963e4c2aSGarrett Wollman } 1253963e4c2aSGarrett Wollman 1254963e4c2aSGarrett Wollman /* 1255df8bae1dSRodney W. Grimes * Return interface configuration 1256df8bae1dSRodney W. Grimes * of system. List may be used 1257df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 1258df8bae1dSRodney W. Grimes * other information. 1259df8bae1dSRodney W. Grimes */ 1260df8bae1dSRodney W. Grimes /*ARGSUSED*/ 12613bda9f9bSPoul-Henning Kamp static int 1262df8bae1dSRodney W. Grimes ifconf(cmd, data) 1263ecbb00a2SDoug Rabson u_long cmd; 1264df8bae1dSRodney W. Grimes caddr_t data; 1265df8bae1dSRodney W. Grimes { 1266df8bae1dSRodney W. Grimes register struct ifconf *ifc = (struct ifconf *)data; 126722f29826SPoul-Henning Kamp register struct ifnet *ifp = TAILQ_FIRST(&ifnet); 1268df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 1269df8bae1dSRodney W. Grimes struct ifreq ifr, *ifrp; 1270df8bae1dSRodney W. Grimes int space = ifc->ifc_len, error = 0; 1271df8bae1dSRodney W. Grimes 1272df8bae1dSRodney W. Grimes ifrp = ifc->ifc_req; 127322f29826SPoul-Henning Kamp for (; space > sizeof (ifr) && ifp; ifp = TAILQ_NEXT(ifp, if_link)) { 12741ce9bf88SPoul-Henning Kamp char workbuf[64]; 127575c13541SPoul-Henning Kamp int ifnlen, addrs; 12762624cf89SGarrett Wollman 12772127f260SArchie Cobbs ifnlen = snprintf(workbuf, sizeof(workbuf), 12782127f260SArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 12791ce9bf88SPoul-Henning Kamp if(ifnlen + 1 > sizeof ifr.ifr_name) { 12802624cf89SGarrett Wollman error = ENAMETOOLONG; 1281b3f1e629SGuido van Rooij break; 12822624cf89SGarrett Wollman } else { 12831ce9bf88SPoul-Henning Kamp strcpy(ifr.ifr_name, workbuf); 12842624cf89SGarrett Wollman } 12852624cf89SGarrett Wollman 128675c13541SPoul-Henning Kamp addrs = 0; 128722f29826SPoul-Henning Kamp ifa = TAILQ_FIRST(&ifp->if_addrhead); 128859562606SGarrett Wollman for ( ; space > sizeof (ifr) && ifa; 128922f29826SPoul-Henning Kamp ifa = TAILQ_NEXT(ifa, ifa_link)) { 1290df8bae1dSRodney W. Grimes register struct sockaddr *sa = ifa->ifa_addr; 129191421ba2SRobert Watson if (jailed(curproc->p_ucred) && 129291421ba2SRobert Watson prison_if(curproc->p_ucred, sa)) 129375c13541SPoul-Henning Kamp continue; 129475c13541SPoul-Henning Kamp addrs++; 1295df8bae1dSRodney W. Grimes #ifdef COMPAT_43 1296df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 1297df8bae1dSRodney W. Grimes struct osockaddr *osa = 1298df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 1299df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1300df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 1301df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1302df8bae1dSRodney W. Grimes sizeof (ifr)); 1303df8bae1dSRodney W. Grimes ifrp++; 1304df8bae1dSRodney W. Grimes } else 1305df8bae1dSRodney W. Grimes #endif 1306df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 1307df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1308df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1309df8bae1dSRodney W. Grimes sizeof (ifr)); 1310df8bae1dSRodney W. Grimes ifrp++; 1311df8bae1dSRodney W. Grimes } else { 1312d91a068eSGuido van Rooij if (space < sizeof (ifr) + sa->sa_len - 1313d91a068eSGuido van Rooij sizeof(*sa)) 1314b3f1e629SGuido van Rooij break; 1315df8bae1dSRodney W. Grimes space -= sa->sa_len - sizeof(*sa); 1316df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1317df8bae1dSRodney W. Grimes sizeof (ifr.ifr_name)); 1318df8bae1dSRodney W. Grimes if (error == 0) 1319df8bae1dSRodney W. Grimes error = copyout((caddr_t)sa, 1320df8bae1dSRodney W. Grimes (caddr_t)&ifrp->ifr_addr, sa->sa_len); 1321df8bae1dSRodney W. Grimes ifrp = (struct ifreq *) 1322df8bae1dSRodney W. Grimes (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 1323df8bae1dSRodney W. Grimes } 1324df8bae1dSRodney W. Grimes if (error) 1325df8bae1dSRodney W. Grimes break; 1326df8bae1dSRodney W. Grimes space -= sizeof (ifr); 1327df8bae1dSRodney W. Grimes } 1328b3f1e629SGuido van Rooij if (error) 1329b3f1e629SGuido van Rooij break; 133075c13541SPoul-Henning Kamp if (!addrs) { 133175c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 133275c13541SPoul-Henning Kamp error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 133375c13541SPoul-Henning Kamp sizeof (ifr)); 133475c13541SPoul-Henning Kamp if (error) 133575c13541SPoul-Henning Kamp break; 1336b3f1e629SGuido van Rooij space -= sizeof (ifr); 1337b3f1e629SGuido van Rooij ifrp++; 133875c13541SPoul-Henning Kamp } 1339df8bae1dSRodney W. Grimes } 1340df8bae1dSRodney W. Grimes ifc->ifc_len -= space; 1341df8bae1dSRodney W. Grimes return (error); 1342df8bae1dSRodney W. Grimes } 1343df8bae1dSRodney W. Grimes 13441158dfb7SGarrett Wollman /* 13451158dfb7SGarrett Wollman * Just like if_promisc(), but for all-multicast-reception mode. 13461158dfb7SGarrett Wollman */ 13471158dfb7SGarrett Wollman int 13481158dfb7SGarrett Wollman if_allmulti(ifp, onswitch) 13491158dfb7SGarrett Wollman struct ifnet *ifp; 13501158dfb7SGarrett Wollman int onswitch; 13511158dfb7SGarrett Wollman { 13521158dfb7SGarrett Wollman int error = 0; 13531158dfb7SGarrett Wollman int s = splimp(); 13541158dfb7SGarrett Wollman 13551158dfb7SGarrett Wollman if (onswitch) { 13561158dfb7SGarrett Wollman if (ifp->if_amcount++ == 0) { 13571158dfb7SGarrett Wollman ifp->if_flags |= IFF_ALLMULTI; 13581158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 13591158dfb7SGarrett Wollman } 13601158dfb7SGarrett Wollman } else { 13611158dfb7SGarrett Wollman if (ifp->if_amcount > 1) { 13621158dfb7SGarrett Wollman ifp->if_amcount--; 13631158dfb7SGarrett Wollman } else { 13641158dfb7SGarrett Wollman ifp->if_amcount = 0; 13651158dfb7SGarrett Wollman ifp->if_flags &= ~IFF_ALLMULTI; 13661158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 13671158dfb7SGarrett Wollman } 13681158dfb7SGarrett Wollman } 13691158dfb7SGarrett Wollman splx(s); 13704a26224cSGarrett Wollman 13714a26224cSGarrett Wollman if (error == 0) 13724a26224cSGarrett Wollman rt_ifmsg(ifp); 13731158dfb7SGarrett Wollman return error; 13741158dfb7SGarrett Wollman } 13751158dfb7SGarrett Wollman 13761158dfb7SGarrett Wollman /* 13771158dfb7SGarrett Wollman * Add a multicast listenership to the interface in question. 13781158dfb7SGarrett Wollman * The link layer provides a routine which converts 13791158dfb7SGarrett Wollman */ 13801158dfb7SGarrett Wollman int 1381373f88edSGarrett Wollman if_addmulti(ifp, sa, retifma) 13821158dfb7SGarrett Wollman struct ifnet *ifp; /* interface to manipulate */ 13831158dfb7SGarrett Wollman struct sockaddr *sa; /* address to add */ 1384b2053118SGarrett Wollman struct ifmultiaddr **retifma; 13851158dfb7SGarrett Wollman { 13861158dfb7SGarrett Wollman struct sockaddr *llsa, *dupsa; 13871158dfb7SGarrett Wollman int error, s; 13881158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 13891158dfb7SGarrett Wollman 139057af7922SJulian Elischer /* 139157af7922SJulian Elischer * If the matching multicast address already exists 139257af7922SJulian Elischer * then don't add a new one, just add a reference 139357af7922SJulian Elischer */ 13946817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 139557af7922SJulian Elischer if (equal(sa, ifma->ifma_addr)) { 13961158dfb7SGarrett Wollman ifma->ifma_refcount++; 139757af7922SJulian Elischer if (retifma) 139857af7922SJulian Elischer *retifma = ifma; 13991158dfb7SGarrett Wollman return 0; 14001158dfb7SGarrett Wollman } 140157af7922SJulian Elischer } 14021158dfb7SGarrett Wollman 14031158dfb7SGarrett Wollman /* 14041158dfb7SGarrett Wollman * Give the link layer a chance to accept/reject it, and also 14051158dfb7SGarrett Wollman * find out which AF_LINK address this maps to, if it isn't one 14061158dfb7SGarrett Wollman * already. 14071158dfb7SGarrett Wollman */ 14081158dfb7SGarrett Wollman if (ifp->if_resolvemulti) { 14091158dfb7SGarrett Wollman error = ifp->if_resolvemulti(ifp, &llsa, sa); 14101158dfb7SGarrett Wollman if (error) return error; 14111158dfb7SGarrett Wollman } else { 14121158dfb7SGarrett Wollman llsa = 0; 14131158dfb7SGarrett Wollman } 14141158dfb7SGarrett Wollman 14151158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK); 14161158dfb7SGarrett Wollman MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK); 14171158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 14181158dfb7SGarrett Wollman 14191158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 14201158dfb7SGarrett Wollman ifma->ifma_lladdr = llsa; 14211158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 14221158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1423373f88edSGarrett Wollman ifma->ifma_protospec = 0; 1424477180fbSGarrett Wollman rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1425373f88edSGarrett Wollman 14261158dfb7SGarrett Wollman /* 14271158dfb7SGarrett Wollman * Some network interfaces can scan the address list at 14281158dfb7SGarrett Wollman * interrupt time; lock them out. 14291158dfb7SGarrett Wollman */ 14301158dfb7SGarrett Wollman s = splimp(); 14316817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 14321158dfb7SGarrett Wollman splx(s); 1433373f88edSGarrett Wollman *retifma = ifma; 14341158dfb7SGarrett Wollman 14351158dfb7SGarrett Wollman if (llsa != 0) { 14366817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 14371158dfb7SGarrett Wollman if (equal(ifma->ifma_addr, llsa)) 14381158dfb7SGarrett Wollman break; 14391158dfb7SGarrett Wollman } 14401158dfb7SGarrett Wollman if (ifma) { 14411158dfb7SGarrett Wollman ifma->ifma_refcount++; 14421158dfb7SGarrett Wollman } else { 14431158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, 14441158dfb7SGarrett Wollman M_IFMADDR, M_WAITOK); 1445477180fbSGarrett Wollman MALLOC(dupsa, struct sockaddr *, llsa->sa_len, 1446477180fbSGarrett Wollman M_IFMADDR, M_WAITOK); 1447477180fbSGarrett Wollman bcopy(llsa, dupsa, llsa->sa_len); 1448477180fbSGarrett Wollman ifma->ifma_addr = dupsa; 14491158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 14501158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 14511158dfb7SGarrett Wollman s = splimp(); 14526817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 14531158dfb7SGarrett Wollman splx(s); 14541158dfb7SGarrett Wollman } 145557af7922SJulian Elischer } 14561158dfb7SGarrett Wollman /* 14571158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 14581158dfb7SGarrett Wollman * interface to let them know about it. 14591158dfb7SGarrett Wollman */ 14601158dfb7SGarrett Wollman s = splimp(); 14611158dfb7SGarrett Wollman ifp->if_ioctl(ifp, SIOCADDMULTI, 0); 14621158dfb7SGarrett Wollman splx(s); 14631158dfb7SGarrett Wollman 14641158dfb7SGarrett Wollman return 0; 14651158dfb7SGarrett Wollman } 14661158dfb7SGarrett Wollman 14671158dfb7SGarrett Wollman /* 14681158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 14691158dfb7SGarrett Wollman * if the request does not match an existing membership. 14701158dfb7SGarrett Wollman */ 14711158dfb7SGarrett Wollman int 14721158dfb7SGarrett Wollman if_delmulti(ifp, sa) 14731158dfb7SGarrett Wollman struct ifnet *ifp; 14741158dfb7SGarrett Wollman struct sockaddr *sa; 14751158dfb7SGarrett Wollman { 14761158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 14771158dfb7SGarrett Wollman int s; 14781158dfb7SGarrett Wollman 14796817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 14801158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 14811158dfb7SGarrett Wollman break; 14821158dfb7SGarrett Wollman if (ifma == 0) 14831158dfb7SGarrett Wollman return ENOENT; 14841158dfb7SGarrett Wollman 14851158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 14861158dfb7SGarrett Wollman ifma->ifma_refcount--; 14871158dfb7SGarrett Wollman return 0; 14881158dfb7SGarrett Wollman } 14891158dfb7SGarrett Wollman 1490477180fbSGarrett Wollman rt_newmaddrmsg(RTM_DELMADDR, ifma); 14911158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 14921158dfb7SGarrett Wollman s = splimp(); 14936817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 1494ccb7cc8dSYaroslav Tykhiy /* 1495ccb7cc8dSYaroslav Tykhiy * Make sure the interface driver is notified 1496ccb7cc8dSYaroslav Tykhiy * in the case of a link layer mcast group being left. 1497ccb7cc8dSYaroslav Tykhiy */ 1498ccb7cc8dSYaroslav Tykhiy if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) 1499ccb7cc8dSYaroslav Tykhiy ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 15001158dfb7SGarrett Wollman splx(s); 15011158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 15021158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 15031158dfb7SGarrett Wollman if (sa == 0) 15041158dfb7SGarrett Wollman return 0; 15051158dfb7SGarrett Wollman 15061158dfb7SGarrett Wollman /* 15071158dfb7SGarrett Wollman * Now look for the link-layer address which corresponds to 15081158dfb7SGarrett Wollman * this network address. It had been squirreled away in 15091158dfb7SGarrett Wollman * ifma->ifma_lladdr for this purpose (so we don't have 15101158dfb7SGarrett Wollman * to call ifp->if_resolvemulti() again), and we saved that 15111158dfb7SGarrett Wollman * value in sa above. If some nasty deleted the 15121158dfb7SGarrett Wollman * link-layer address out from underneath us, we can deal because 15131158dfb7SGarrett Wollman * the address we stored was is not the same as the one which was 15141158dfb7SGarrett Wollman * in the record for the link-layer address. (So we don't complain 15151158dfb7SGarrett Wollman * in that case.) 15161158dfb7SGarrett Wollman */ 15176817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 15181158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 15191158dfb7SGarrett Wollman break; 15201158dfb7SGarrett Wollman if (ifma == 0) 15211158dfb7SGarrett Wollman return 0; 15221158dfb7SGarrett Wollman 15231158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 15241158dfb7SGarrett Wollman ifma->ifma_refcount--; 15251158dfb7SGarrett Wollman return 0; 15261158dfb7SGarrett Wollman } 15271158dfb7SGarrett Wollman 15281158dfb7SGarrett Wollman s = splimp(); 15296817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 1530c7323482SBill Paul ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 15311158dfb7SGarrett Wollman splx(s); 15321158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 15331158dfb7SGarrett Wollman free(sa, M_IFMADDR); 15341158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 15351158dfb7SGarrett Wollman 15361158dfb7SGarrett Wollman return 0; 15371158dfb7SGarrett Wollman } 15381158dfb7SGarrett Wollman 153966ce51ceSArchie Cobbs /* 154066ce51ceSArchie Cobbs * Set the link layer address on an interface. 154166ce51ceSArchie Cobbs * 154266ce51ceSArchie Cobbs * At this time we only support certain types of interfaces, 154366ce51ceSArchie Cobbs * and we don't allow the length of the address to change. 154466ce51ceSArchie Cobbs */ 154566ce51ceSArchie Cobbs int 154666ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 154766ce51ceSArchie Cobbs { 154866ce51ceSArchie Cobbs struct sockaddr_dl *sdl; 154966ce51ceSArchie Cobbs struct ifaddr *ifa; 155066ce51ceSArchie Cobbs 155166ce51ceSArchie Cobbs ifa = ifnet_addrs[ifp->if_index - 1]; 155266ce51ceSArchie Cobbs if (ifa == NULL) 155366ce51ceSArchie Cobbs return (EINVAL); 155466ce51ceSArchie Cobbs sdl = (struct sockaddr_dl *)ifa->ifa_addr; 155566ce51ceSArchie Cobbs if (sdl == NULL) 155666ce51ceSArchie Cobbs return (EINVAL); 155766ce51ceSArchie Cobbs if (len != sdl->sdl_alen) /* don't allow length to change */ 155866ce51ceSArchie Cobbs return (EINVAL); 155966ce51ceSArchie Cobbs switch (ifp->if_type) { 156066ce51ceSArchie Cobbs case IFT_ETHER: /* these types use struct arpcom */ 156166ce51ceSArchie Cobbs case IFT_FDDI: 156266ce51ceSArchie Cobbs case IFT_XETHER: 156366ce51ceSArchie Cobbs case IFT_ISO88025: 1564b7bffa71SYaroslav Tykhiy case IFT_L2VLAN: 156566ce51ceSArchie Cobbs bcopy(lladdr, ((struct arpcom *)ifp->if_softc)->ac_enaddr, len); 156666ce51ceSArchie Cobbs bcopy(lladdr, LLADDR(sdl), len); 156766ce51ceSArchie Cobbs break; 156866ce51ceSArchie Cobbs default: 156966ce51ceSArchie Cobbs return (ENODEV); 157066ce51ceSArchie Cobbs } 157166ce51ceSArchie Cobbs /* 157266ce51ceSArchie Cobbs * If the interface is already up, we need 157366ce51ceSArchie Cobbs * to re-init it in order to reprogram its 157466ce51ceSArchie Cobbs * address filter. 157566ce51ceSArchie Cobbs */ 157666ce51ceSArchie Cobbs if ((ifp->if_flags & IFF_UP) != 0) { 157766ce51ceSArchie Cobbs ifp->if_flags &= ~IFF_UP; 157866ce51ceSArchie Cobbs (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL); 157966ce51ceSArchie Cobbs ifp->if_flags |= IFF_UP; 158066ce51ceSArchie Cobbs (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL); 158166ce51ceSArchie Cobbs } 158266ce51ceSArchie Cobbs return (0); 158366ce51ceSArchie Cobbs } 158466ce51ceSArchie Cobbs 1585373f88edSGarrett Wollman struct ifmultiaddr * 1586373f88edSGarrett Wollman ifmaof_ifpforaddr(sa, ifp) 1587373f88edSGarrett Wollman struct sockaddr *sa; 1588373f88edSGarrett Wollman struct ifnet *ifp; 1589373f88edSGarrett Wollman { 1590373f88edSGarrett Wollman struct ifmultiaddr *ifma; 1591373f88edSGarrett Wollman 15926817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 1593373f88edSGarrett Wollman if (equal(ifma->ifma_addr, sa)) 1594373f88edSGarrett Wollman break; 1595373f88edSGarrett Wollman 1596373f88edSGarrett Wollman return ifma; 1597373f88edSGarrett Wollman } 1598373f88edSGarrett Wollman 1599602d513cSGarrett Wollman SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 16002c37256eSGarrett Wollman SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 1601