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 730b59d917SJonathan Lemon static int ifconf(u_long, caddr_t); 740b59d917SJonathan Lemon static void ifinit(void *); 750b59d917SJonathan Lemon static void if_qflush(struct ifqueue *); 760b59d917SJonathan Lemon static void if_slowtimo(void *); 770b59d917SJonathan Lemon static void link_rtrequest(int, struct rtentry *, struct sockaddr *); 780b59d917SJonathan Lemon static int if_rtdel(struct radix_node *, void *); 790b59d917SJonathan Lemon static struct if_clone *if_clone_lookup(const char *, int *); 800b59d917SJonathan Lemon static int if_clone_list(struct if_clonereq *); 8182cd038dSYoshinobu Inoue #ifdef INET6 8282cd038dSYoshinobu Inoue /* 8382cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 8482cd038dSYoshinobu Inoue * should be more generalized? 8582cd038dSYoshinobu Inoue */ 8682cd038dSYoshinobu Inoue extern void nd6_setmtu __P((struct ifnet *)); 8782cd038dSYoshinobu Inoue #endif 8882cd038dSYoshinobu Inoue 890b59d917SJonathan Lemon int if_index = 0; 900b59d917SJonathan Lemon struct ifaddr **ifnet_addrs; 910b59d917SJonathan Lemon struct ifnet **ifindex2ifnet = NULL; 920b59d917SJonathan Lemon int ifqmaxlen = IFQ_MAXLEN; 930b59d917SJonathan Lemon struct ifnethead ifnet; /* depend on static init XXX */ 9430aad87dSBrooks Davis int if_cloners_count; 950b59d917SJonathan Lemon LIST_HEAD(, if_clone) if_cloners = LIST_HEAD_INITIALIZER(if_cloners); 960b59d917SJonathan Lemon 970b59d917SJonathan Lemon /* 980b59d917SJonathan Lemon * System initialization 990b59d917SJonathan Lemon */ 1000b59d917SJonathan Lemon SYSINIT(interfaces, SI_SUB_PROTO_IF, SI_ORDER_FIRST, ifinit, NULL) 1010b59d917SJonathan Lemon 1020b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 1030b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 10430aad87dSBrooks Davis 105df8bae1dSRodney W. Grimes /* 106df8bae1dSRodney W. Grimes * Network interface utility routines. 107df8bae1dSRodney W. Grimes * 108df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 109df8bae1dSRodney W. Grimes * parameters. 110df8bae1dSRodney W. Grimes */ 1112b14f991SJulian Elischer /* ARGSUSED*/ 112df8bae1dSRodney W. Grimes void 11327501cb6SBruce Evans ifinit(dummy) 11427501cb6SBruce Evans void *dummy; 115df8bae1dSRodney W. Grimes { 1168ba5bdaeSPeter Wemm struct ifnet *ifp; 1178ba5bdaeSPeter Wemm int s; 118df8bae1dSRodney W. Grimes 1198ba5bdaeSPeter Wemm s = splimp(); 120fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 121e0ea20bcSPoul-Henning Kamp if (ifp->if_snd.ifq_maxlen == 0) { 122e0ea20bcSPoul-Henning Kamp printf("%s%d XXX: driver didn't set ifq_maxlen\n", 123e0ea20bcSPoul-Henning Kamp ifp->if_name, ifp->if_unit); 124df8bae1dSRodney W. Grimes ifp->if_snd.ifq_maxlen = ifqmaxlen; 125e0ea20bcSPoul-Henning Kamp } 1265e980e22SJohn Baldwin if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) { 127df5e1987SJonathan Lemon printf("%s%d XXX: driver didn't initialize queue mtx\n", 128df5e1987SJonathan Lemon ifp->if_name, ifp->if_unit); 129df5e1987SJonathan Lemon mtx_init(&ifp->if_snd.ifq_mtx, "unknown", MTX_DEF); 130df5e1987SJonathan Lemon } 131df5e1987SJonathan Lemon } 1328ba5bdaeSPeter Wemm splx(s); 133df8bae1dSRodney W. Grimes if_slowtimo(0); 134df8bae1dSRodney W. Grimes } 135df8bae1dSRodney W. Grimes 136df8bae1dSRodney W. Grimes /* 137df8bae1dSRodney W. Grimes * Attach an interface to the 138df8bae1dSRodney W. Grimes * list of "active" interfaces. 139df8bae1dSRodney W. Grimes */ 140df8bae1dSRodney W. Grimes void 141df8bae1dSRodney W. Grimes if_attach(ifp) 142df8bae1dSRodney W. Grimes struct ifnet *ifp; 143df8bae1dSRodney W. Grimes { 144df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 1451ce9bf88SPoul-Henning Kamp int namelen, masklen; 1461ce9bf88SPoul-Henning Kamp char workbuf[64]; 147df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl; 148df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 149df8bae1dSRodney W. Grimes static int if_indexlim = 8; 15029412182SGarrett Wollman static int inited; 151f23b4c91SGarrett Wollman 15229412182SGarrett Wollman if (!inited) { 15329412182SGarrett Wollman TAILQ_INIT(&ifnet); 15429412182SGarrett Wollman inited = 1; 15529412182SGarrett Wollman } 156df8bae1dSRodney W. Grimes 15729412182SGarrett Wollman TAILQ_INSERT_TAIL(&ifnet, ifp, if_link); 158df8bae1dSRodney W. Grimes ifp->if_index = ++if_index; 15959562606SGarrett Wollman /* 16059562606SGarrett Wollman * XXX - 16159562606SGarrett Wollman * The old code would work if the interface passed a pre-existing 16259562606SGarrett Wollman * chain of ifaddrs to this code. We don't trust our callers to 16359562606SGarrett Wollman * properly initialize the tailq, however, so we no longer allow 16459562606SGarrett Wollman * this unlikely case. 16559562606SGarrett Wollman */ 16659562606SGarrett Wollman TAILQ_INIT(&ifp->if_addrhead); 16782cd038dSYoshinobu Inoue TAILQ_INIT(&ifp->if_prefixhead); 1686817526dSPoul-Henning Kamp TAILQ_INIT(&ifp->if_multiaddrs); 16998b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 170df8bae1dSRodney W. Grimes if (ifnet_addrs == 0 || if_index >= if_indexlim) { 171df8bae1dSRodney W. Grimes unsigned n = (if_indexlim <<= 1) * sizeof(ifa); 1727cc0979fSDavid Malone caddr_t q = malloc(n, M_IFADDR, M_WAITOK | M_ZERO); 173df8bae1dSRodney W. Grimes if (ifnet_addrs) { 174df8bae1dSRodney W. Grimes bcopy((caddr_t)ifnet_addrs, (caddr_t)q, n/2); 175df8bae1dSRodney W. Grimes free((caddr_t)ifnet_addrs, M_IFADDR); 176df8bae1dSRodney W. Grimes } 17782cd038dSYoshinobu Inoue ifnet_addrs = (struct ifaddr **)q; 17882cd038dSYoshinobu Inoue 17982cd038dSYoshinobu Inoue /* grow ifindex2ifnet */ 18082cd038dSYoshinobu Inoue n = if_indexlim * sizeof(struct ifnet *); 1817cc0979fSDavid Malone q = malloc(n, M_IFADDR, M_WAITOK | M_ZERO); 18282cd038dSYoshinobu Inoue if (ifindex2ifnet) { 18382cd038dSYoshinobu Inoue bcopy((caddr_t)ifindex2ifnet, q, n/2); 18482cd038dSYoshinobu Inoue free((caddr_t)ifindex2ifnet, M_IFADDR); 185df8bae1dSRodney W. Grimes } 18682cd038dSYoshinobu Inoue ifindex2ifnet = (struct ifnet **)q; 18782cd038dSYoshinobu Inoue } 18882cd038dSYoshinobu Inoue 18982cd038dSYoshinobu Inoue ifindex2ifnet[if_index] = ifp; 19082cd038dSYoshinobu Inoue 191df5e1987SJonathan Lemon mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_name, MTX_DEF); 192df5e1987SJonathan Lemon 193df8bae1dSRodney W. Grimes /* 194df8bae1dSRodney W. Grimes * create a Link Level name for this device 195df8bae1dSRodney W. Grimes */ 1962127f260SArchie Cobbs namelen = snprintf(workbuf, sizeof(workbuf), 1972127f260SArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 198df8bae1dSRodney W. Grimes #define _offsetof(t, m) ((int)((caddr_t)&((t *)0)->m)) 1991ce9bf88SPoul-Henning Kamp masklen = _offsetof(struct sockaddr_dl, sdl_data[0]) + namelen; 200df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 201df8bae1dSRodney W. Grimes #define ROUNDUP(a) (1 + (((a) - 1) | (sizeof(long) - 1))) 202df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 203df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 2048a261b8fSDoug Rabson socksize = ROUNDUP(socksize); 205df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 2067cc0979fSDavid Malone ifa = (struct ifaddr *)malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO); 2079448326fSPoul-Henning Kamp if (ifa) { 208df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 209df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 210df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 2111ce9bf88SPoul-Henning Kamp bcopy(workbuf, sdl->sdl_data, namelen); 2121ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 213df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 214df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 215df8bae1dSRodney W. Grimes ifnet_addrs[if_index - 1] = ifa; 216df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 217df8bae1dSRodney W. Grimes ifa->ifa_rtrequest = link_rtrequest; 218df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 219df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 220df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 221df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 222df8bae1dSRodney W. Grimes while (namelen != 0) 223df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 22459562606SGarrett Wollman TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 225df8bae1dSRodney W. Grimes } 226df8bae1dSRodney W. Grimes } 2276182fdbdSPeter Wemm 2286182fdbdSPeter Wemm /* 2296182fdbdSPeter Wemm * Detach an interface, removing it from the 2306182fdbdSPeter Wemm * list of "active" interfaces. 2316182fdbdSPeter Wemm */ 2326182fdbdSPeter Wemm void 2336182fdbdSPeter Wemm if_detach(ifp) 2346182fdbdSPeter Wemm struct ifnet *ifp; 2356182fdbdSPeter Wemm { 2366182fdbdSPeter Wemm struct ifaddr *ifa; 2375500d3beSWarner Losh struct radix_node_head *rnh; 2385500d3beSWarner Losh int s; 2395500d3beSWarner Losh int i; 2406182fdbdSPeter Wemm 2416182fdbdSPeter Wemm /* 2426182fdbdSPeter Wemm * Remove routes and flush queues. 2436182fdbdSPeter Wemm */ 2445500d3beSWarner Losh s = splnet(); 2456182fdbdSPeter Wemm if_down(ifp); 2466182fdbdSPeter Wemm 2476182fdbdSPeter Wemm /* 2486182fdbdSPeter Wemm * Remove address from ifnet_addrs[] and maybe decrement if_index. 2496182fdbdSPeter Wemm * Clean up all addresses. 2506182fdbdSPeter Wemm */ 251aa6be122SWarner Losh ifnet_addrs[ifp->if_index - 1] = 0; 252aa6be122SWarner Losh while (if_index > 0 && ifnet_addrs[if_index - 1] == 0) 2536182fdbdSPeter Wemm if_index--; 2546182fdbdSPeter Wemm 2556182fdbdSPeter Wemm for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; 2566182fdbdSPeter Wemm ifa = TAILQ_FIRST(&ifp->if_addrhead)) { 2570d0f9d1eSYoshinobu Inoue #ifdef INET 258aa6be122SWarner Losh /* XXX: Ugly!! ad hoc just for INET */ 259aa6be122SWarner Losh if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) { 260aa6be122SWarner Losh struct ifaliasreq ifr; 261aa6be122SWarner Losh 262aa6be122SWarner Losh bzero(&ifr, sizeof(ifr)); 263aa6be122SWarner Losh ifr.ifra_addr = *ifa->ifa_addr; 264aa6be122SWarner Losh if (ifa->ifa_dstaddr) 265aa6be122SWarner Losh ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 266aa6be122SWarner Losh if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 267aa6be122SWarner Losh NULL) == 0) 268aa6be122SWarner Losh continue; 269aa6be122SWarner Losh } 2700d0f9d1eSYoshinobu Inoue #endif /* INET */ 2710d0f9d1eSYoshinobu Inoue #ifdef INET6 2720d0f9d1eSYoshinobu Inoue if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) { 27333841545SHajimu UMEMOTO in6_purgeaddr(ifa); 274978ee2edSJun-ichiro itojun Hagino /* ifp_addrhead is already updated */ 2750d0f9d1eSYoshinobu Inoue continue; 2760d0f9d1eSYoshinobu Inoue } 2770d0f9d1eSYoshinobu Inoue #endif /* INET6 */ 2786182fdbdSPeter Wemm TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link); 2796182fdbdSPeter Wemm IFAFREE(ifa); 2806182fdbdSPeter Wemm } 2816182fdbdSPeter Wemm 28233841545SHajimu UMEMOTO #ifdef INET6 28333841545SHajimu UMEMOTO /* 28433841545SHajimu UMEMOTO * Remove all IPv6 kernel structs related to ifp. This should be done 28533841545SHajimu UMEMOTO * before removing routing entries below, since IPv6 interface direct 28633841545SHajimu UMEMOTO * routes are expected to be removed by the IPv6-specific kernel API. 28733841545SHajimu UMEMOTO * Otherwise, the kernel will detect some inconsistency and bark it. 28833841545SHajimu UMEMOTO */ 28933841545SHajimu UMEMOTO in6_ifdetach(ifp); 29033841545SHajimu UMEMOTO #endif 29133841545SHajimu UMEMOTO 2925500d3beSWarner Losh /* 2935500d3beSWarner Losh * Delete all remaining routes using this interface 2945500d3beSWarner Losh * Unfortuneatly the only way to do this is to slog through 2955500d3beSWarner Losh * the entire routing table looking for routes which point 2965500d3beSWarner Losh * to this interface...oh well... 2975500d3beSWarner Losh */ 2985500d3beSWarner Losh for (i = 1; i <= AF_MAX; i++) { 2995500d3beSWarner Losh if ((rnh = rt_tables[i]) == NULL) 3005500d3beSWarner Losh continue; 3015500d3beSWarner Losh (void) rnh->rnh_walktree(rnh, if_rtdel, ifp); 3025500d3beSWarner Losh } 3035500d3beSWarner Losh 3046182fdbdSPeter Wemm TAILQ_REMOVE(&ifnet, ifp, if_link); 305df5e1987SJonathan Lemon mtx_destroy(&ifp->if_snd.ifq_mtx); 3065500d3beSWarner Losh splx(s); 3075500d3beSWarner Losh } 3085500d3beSWarner Losh 3095500d3beSWarner Losh /* 3105500d3beSWarner Losh * Delete Routes for a Network Interface 3115500d3beSWarner Losh * 3125500d3beSWarner Losh * Called for each routing entry via the rnh->rnh_walktree() call above 3135500d3beSWarner Losh * to delete all route entries referencing a detaching network interface. 3145500d3beSWarner Losh * 3155500d3beSWarner Losh * Arguments: 3165500d3beSWarner Losh * rn pointer to node in the routing table 3175500d3beSWarner Losh * arg argument passed to rnh->rnh_walktree() - detaching interface 3185500d3beSWarner Losh * 3195500d3beSWarner Losh * Returns: 3205500d3beSWarner Losh * 0 successful 3215500d3beSWarner Losh * errno failed - reason indicated 3225500d3beSWarner Losh * 3235500d3beSWarner Losh */ 3245500d3beSWarner Losh static int 3255500d3beSWarner Losh if_rtdel(rn, arg) 3265500d3beSWarner Losh struct radix_node *rn; 3275500d3beSWarner Losh void *arg; 3285500d3beSWarner Losh { 3295500d3beSWarner Losh struct rtentry *rt = (struct rtentry *)rn; 3305500d3beSWarner Losh struct ifnet *ifp = arg; 3315500d3beSWarner Losh int err; 3325500d3beSWarner Losh 3335500d3beSWarner Losh if (rt->rt_ifp == ifp) { 3345500d3beSWarner Losh 3355500d3beSWarner Losh /* 3365500d3beSWarner Losh * Protect (sorta) against walktree recursion problems 3375500d3beSWarner Losh * with cloned routes 3385500d3beSWarner Losh */ 3395500d3beSWarner Losh if ((rt->rt_flags & RTF_UP) == 0) 3405500d3beSWarner Losh return (0); 3415500d3beSWarner Losh 3425500d3beSWarner Losh err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, 3435500d3beSWarner Losh rt_mask(rt), rt->rt_flags, 3445500d3beSWarner Losh (struct rtentry **) NULL); 3455500d3beSWarner Losh if (err) { 3465500d3beSWarner Losh log(LOG_WARNING, "if_rtdel: error %d\n", err); 3475500d3beSWarner Losh } 3485500d3beSWarner Losh } 3495500d3beSWarner Losh 3505500d3beSWarner Losh return (0); 3516182fdbdSPeter Wemm } 3526182fdbdSPeter Wemm 353df8bae1dSRodney W. Grimes /* 35430aad87dSBrooks Davis * Create a clone network interface. 35530aad87dSBrooks Davis */ 35630aad87dSBrooks Davis int 35730aad87dSBrooks Davis if_clone_create(name, len) 35830aad87dSBrooks Davis char *name; 35930aad87dSBrooks Davis int len; 36030aad87dSBrooks Davis { 36130aad87dSBrooks Davis struct if_clone *ifc; 36230aad87dSBrooks Davis char *dp; 36330aad87dSBrooks Davis int wildcard; 36430aad87dSBrooks Davis int unit; 36530aad87dSBrooks Davis int err; 36630aad87dSBrooks Davis 36730aad87dSBrooks Davis ifc = if_clone_lookup(name, &unit); 36830aad87dSBrooks Davis if (ifc == NULL) 36930aad87dSBrooks Davis return (EINVAL); 37030aad87dSBrooks Davis 37130aad87dSBrooks Davis if (ifunit(name) != NULL) 37230aad87dSBrooks Davis return (EEXIST); 37330aad87dSBrooks Davis 37430aad87dSBrooks Davis wildcard = (unit < 0); 37530aad87dSBrooks Davis 37630aad87dSBrooks Davis err = (*ifc->ifc_create)(ifc, &unit); 37730aad87dSBrooks Davis if (err != 0) 37830aad87dSBrooks Davis return (err); 37930aad87dSBrooks Davis 38030aad87dSBrooks Davis /* In the wildcard case, we need to update the name. */ 38130aad87dSBrooks Davis if (wildcard) { 38230aad87dSBrooks Davis for (dp = name; *dp != '\0'; dp++); 38330aad87dSBrooks Davis if (snprintf(dp, len - (dp-name), "%d", unit) > 38430aad87dSBrooks Davis len - (dp-name) - 1) { 38530aad87dSBrooks Davis /* 38630aad87dSBrooks Davis * This can only be a programmer error and 38730aad87dSBrooks Davis * there's no straightforward way to recover if 38830aad87dSBrooks Davis * it happens. 38930aad87dSBrooks Davis */ 39030aad87dSBrooks Davis panic("if_clone_create(): interface name too long"); 39130aad87dSBrooks Davis } 39230aad87dSBrooks Davis 39330aad87dSBrooks Davis } 39430aad87dSBrooks Davis 39530aad87dSBrooks Davis return (0); 39630aad87dSBrooks Davis } 39730aad87dSBrooks Davis 39830aad87dSBrooks Davis /* 39930aad87dSBrooks Davis * Destroy a clone network interface. 40030aad87dSBrooks Davis */ 40130aad87dSBrooks Davis int 40230aad87dSBrooks Davis if_clone_destroy(name) 40330aad87dSBrooks Davis const char *name; 40430aad87dSBrooks Davis { 40530aad87dSBrooks Davis struct if_clone *ifc; 40630aad87dSBrooks Davis struct ifnet *ifp; 40730aad87dSBrooks Davis 40830aad87dSBrooks Davis ifc = if_clone_lookup(name, NULL); 40930aad87dSBrooks Davis if (ifc == NULL) 41030aad87dSBrooks Davis return (EINVAL); 41130aad87dSBrooks Davis 41230aad87dSBrooks Davis ifp = ifunit(name); 41330aad87dSBrooks Davis if (ifp == NULL) 41430aad87dSBrooks Davis return (ENXIO); 41530aad87dSBrooks Davis 41630aad87dSBrooks Davis if (ifc->ifc_destroy == NULL) 41730aad87dSBrooks Davis return (EOPNOTSUPP); 41830aad87dSBrooks Davis 41930aad87dSBrooks Davis (*ifc->ifc_destroy)(ifp); 42030aad87dSBrooks Davis return (0); 42130aad87dSBrooks Davis } 42230aad87dSBrooks Davis 42330aad87dSBrooks Davis /* 42430aad87dSBrooks Davis * Look up a network interface cloner. 42530aad87dSBrooks Davis */ 4260b59d917SJonathan Lemon static struct if_clone * 42730aad87dSBrooks Davis if_clone_lookup(name, unitp) 42830aad87dSBrooks Davis const char *name; 42930aad87dSBrooks Davis int *unitp; 43030aad87dSBrooks Davis { 43130aad87dSBrooks Davis struct if_clone *ifc; 43230aad87dSBrooks Davis const char *cp; 43330aad87dSBrooks Davis int i; 43430aad87dSBrooks Davis 43530aad87dSBrooks Davis for (ifc = LIST_FIRST(&if_cloners); ifc != NULL;) { 43630aad87dSBrooks Davis for (cp = name, i = 0; i < ifc->ifc_namelen; i++, cp++) { 43730aad87dSBrooks Davis if (ifc->ifc_name[i] != *cp) 43830aad87dSBrooks Davis goto next_ifc; 43930aad87dSBrooks Davis } 44030aad87dSBrooks Davis goto found_name; 44130aad87dSBrooks Davis next_ifc: 44230aad87dSBrooks Davis ifc = LIST_NEXT(ifc, ifc_list); 44330aad87dSBrooks Davis } 44430aad87dSBrooks Davis 44530aad87dSBrooks Davis /* No match. */ 44630aad87dSBrooks Davis return ((struct if_clone *)NULL); 44730aad87dSBrooks Davis 44830aad87dSBrooks Davis found_name: 44930aad87dSBrooks Davis if (*cp == '\0') { 45030aad87dSBrooks Davis i = -1; 45130aad87dSBrooks Davis } else { 45230aad87dSBrooks Davis for (i = 0; *cp != '\0'; cp++) { 45330aad87dSBrooks Davis if (*cp < '0' || *cp > '9') { 45430aad87dSBrooks Davis /* Bogus unit number. */ 45530aad87dSBrooks Davis return (NULL); 45630aad87dSBrooks Davis } 45730aad87dSBrooks Davis i = (i * 10) + (*cp - '0'); 45830aad87dSBrooks Davis } 45930aad87dSBrooks Davis } 46030aad87dSBrooks Davis 46130aad87dSBrooks Davis if (unitp != NULL) 46230aad87dSBrooks Davis *unitp = i; 46330aad87dSBrooks Davis return (ifc); 46430aad87dSBrooks Davis } 46530aad87dSBrooks Davis 46630aad87dSBrooks Davis /* 46730aad87dSBrooks Davis * Register a network interface cloner. 46830aad87dSBrooks Davis */ 46930aad87dSBrooks Davis void 47030aad87dSBrooks Davis if_clone_attach(ifc) 47130aad87dSBrooks Davis struct if_clone *ifc; 47230aad87dSBrooks Davis { 47330aad87dSBrooks Davis 47430aad87dSBrooks Davis LIST_INSERT_HEAD(&if_cloners, ifc, ifc_list); 47530aad87dSBrooks Davis if_cloners_count++; 47630aad87dSBrooks Davis } 47730aad87dSBrooks Davis 47830aad87dSBrooks Davis /* 47930aad87dSBrooks Davis * Unregister a network interface cloner. 48030aad87dSBrooks Davis */ 48130aad87dSBrooks Davis void 48230aad87dSBrooks Davis if_clone_detach(ifc) 48330aad87dSBrooks Davis struct if_clone *ifc; 48430aad87dSBrooks Davis { 48530aad87dSBrooks Davis 48630aad87dSBrooks Davis LIST_REMOVE(ifc, ifc_list); 48730aad87dSBrooks Davis if_cloners_count--; 48830aad87dSBrooks Davis } 48930aad87dSBrooks Davis 49030aad87dSBrooks Davis /* 49130aad87dSBrooks Davis * Provide list of interface cloners to userspace. 49230aad87dSBrooks Davis */ 4930b59d917SJonathan Lemon static int 49430aad87dSBrooks Davis if_clone_list(ifcr) 49530aad87dSBrooks Davis struct if_clonereq *ifcr; 49630aad87dSBrooks Davis { 49730aad87dSBrooks Davis char outbuf[IFNAMSIZ], *dst; 49830aad87dSBrooks Davis struct if_clone *ifc; 49930aad87dSBrooks Davis int count, error = 0; 50030aad87dSBrooks Davis 50130aad87dSBrooks Davis ifcr->ifcr_total = if_cloners_count; 50230aad87dSBrooks Davis if ((dst = ifcr->ifcr_buffer) == NULL) { 50330aad87dSBrooks Davis /* Just asking how many there are. */ 50430aad87dSBrooks Davis return (0); 50530aad87dSBrooks Davis } 50630aad87dSBrooks Davis 50730aad87dSBrooks Davis if (ifcr->ifcr_count < 0) 50830aad87dSBrooks Davis return (EINVAL); 50930aad87dSBrooks Davis 51030aad87dSBrooks Davis count = (if_cloners_count < ifcr->ifcr_count) ? 51130aad87dSBrooks Davis if_cloners_count : ifcr->ifcr_count; 51230aad87dSBrooks Davis 51330aad87dSBrooks Davis for (ifc = LIST_FIRST(&if_cloners); ifc != NULL && count != 0; 51430aad87dSBrooks Davis ifc = LIST_NEXT(ifc, ifc_list), count--, dst += IFNAMSIZ) { 51530aad87dSBrooks Davis strncpy(outbuf, ifc->ifc_name, IFNAMSIZ); 51630aad87dSBrooks Davis outbuf[IFNAMSIZ - 1] = '\0'; /* sanity */ 51730aad87dSBrooks Davis error = copyout(outbuf, dst, IFNAMSIZ); 51830aad87dSBrooks Davis if (error) 51930aad87dSBrooks Davis break; 52030aad87dSBrooks Davis } 52130aad87dSBrooks Davis 52230aad87dSBrooks Davis return (error); 52330aad87dSBrooks Davis } 52430aad87dSBrooks Davis 52530aad87dSBrooks Davis /* 526df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 527df8bae1dSRodney W. Grimes */ 528df8bae1dSRodney W. Grimes /*ARGSUSED*/ 529df8bae1dSRodney W. Grimes struct ifaddr * 530df8bae1dSRodney W. Grimes ifa_ifwithaddr(addr) 5310b59d917SJonathan Lemon struct sockaddr *addr; 532df8bae1dSRodney W. Grimes { 5330b59d917SJonathan Lemon struct ifnet *ifp; 5340b59d917SJonathan Lemon struct ifaddr *ifa; 535df8bae1dSRodney W. Grimes 536df8bae1dSRodney W. Grimes #define equal(a1, a2) \ 537df8bae1dSRodney W. Grimes (bcmp((caddr_t)(a1), (caddr_t)(a2), ((struct sockaddr *)(a1))->sa_len) == 0) 538fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) 53937d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 540df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 541df8bae1dSRodney W. Grimes continue; 542df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr)) 5430b59d917SJonathan Lemon goto done; 54482cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 5450b59d917SJonathan Lemon if ((ifp->if_flags & IFF_BROADCAST) && 5460b59d917SJonathan Lemon ifa->ifa_broadaddr && 54782cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 548df8bae1dSRodney W. Grimes equal(ifa->ifa_broadaddr, addr)) 5490b59d917SJonathan Lemon goto done; 5500b59d917SJonathan Lemon } 5510b59d917SJonathan Lemon ifa = NULL; 5520b59d917SJonathan Lemon done: 553df8bae1dSRodney W. Grimes return (ifa); 554df8bae1dSRodney W. Grimes } 5550b59d917SJonathan Lemon 556df8bae1dSRodney W. Grimes /* 557df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 558df8bae1dSRodney W. Grimes */ 559df8bae1dSRodney W. Grimes /*ARGSUSED*/ 560df8bae1dSRodney W. Grimes struct ifaddr * 561df8bae1dSRodney W. Grimes ifa_ifwithdstaddr(addr) 5620b59d917SJonathan Lemon struct sockaddr *addr; 563df8bae1dSRodney W. Grimes { 5640b59d917SJonathan Lemon struct ifnet *ifp; 5650b59d917SJonathan Lemon struct ifaddr *ifa; 566df8bae1dSRodney W. Grimes 5670b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 5680b59d917SJonathan Lemon if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 5690b59d917SJonathan Lemon continue; 57037d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 571df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 572df8bae1dSRodney W. Grimes continue; 57355088a1cSDavid Greenman if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)) 5740b59d917SJonathan Lemon goto done; 575df8bae1dSRodney W. Grimes } 5760b59d917SJonathan Lemon } 5770b59d917SJonathan Lemon ifa = NULL; 5780b59d917SJonathan Lemon done: 5790b59d917SJonathan Lemon return (ifa); 580df8bae1dSRodney W. Grimes } 581df8bae1dSRodney W. Grimes 582df8bae1dSRodney W. Grimes /* 583df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 584df8bae1dSRodney W. Grimes * is most specific found. 585df8bae1dSRodney W. Grimes */ 586df8bae1dSRodney W. Grimes struct ifaddr * 587df8bae1dSRodney W. Grimes ifa_ifwithnet(addr) 588df8bae1dSRodney W. Grimes struct sockaddr *addr; 589df8bae1dSRodney W. Grimes { 590df8bae1dSRodney W. Grimes register struct ifnet *ifp; 591df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 592df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = (struct ifaddr *) 0; 593df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 594df8bae1dSRodney W. Grimes char *addr_data = addr->sa_data, *cplim; 595df8bae1dSRodney W. Grimes 5967e2a6151SJulian Elischer /* 5977e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 5987e2a6151SJulian Elischer * so do that if we can. 5997e2a6151SJulian Elischer */ 600df8bae1dSRodney W. Grimes if (af == AF_LINK) { 601df8bae1dSRodney W. Grimes register struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr; 602df8bae1dSRodney W. Grimes if (sdl->sdl_index && sdl->sdl_index <= if_index) 603df8bae1dSRodney W. Grimes return (ifnet_addrs[sdl->sdl_index - 1]); 604df8bae1dSRodney W. Grimes } 6057e2a6151SJulian Elischer 6067e2a6151SJulian Elischer /* 6077e2a6151SJulian Elischer * Scan though each interface, looking for ones that have 6087e2a6151SJulian Elischer * addresses in this address family. 6097e2a6151SJulian Elischer */ 610fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 61137d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 612df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 613df8bae1dSRodney W. Grimes 614523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 615df8bae1dSRodney W. Grimes next: continue; 61682cd038dSYoshinobu Inoue if ( 61782cd038dSYoshinobu Inoue #ifdef INET6 /* XXX: for maching gif tunnel dst as routing entry gateway */ 61882cd038dSYoshinobu Inoue addr->sa_family != AF_INET6 && 61982cd038dSYoshinobu Inoue #endif 62082cd038dSYoshinobu Inoue ifp->if_flags & IFF_POINTOPOINT) { 6217e2a6151SJulian Elischer /* 6227e2a6151SJulian Elischer * This is a bit broken as it doesn't 6237e2a6151SJulian Elischer * take into account that the remote end may 6247e2a6151SJulian Elischer * be a single node in the network we are 6257e2a6151SJulian Elischer * looking for. 6267e2a6151SJulian Elischer * The trouble is that we don't know the 6277e2a6151SJulian Elischer * netmask for the remote end. 6287e2a6151SJulian Elischer */ 629fcd6781aSGarrett Wollman if (ifa->ifa_dstaddr != 0 630fcd6781aSGarrett Wollman && equal(addr, ifa->ifa_dstaddr)) 6310b59d917SJonathan Lemon goto done; 6323740e2adSDavid Greenman } else { 6337e2a6151SJulian Elischer /* 6347ed8f465SJulian Elischer * if we have a special address handler, 6357ed8f465SJulian Elischer * then use it instead of the generic one. 6367ed8f465SJulian Elischer */ 6377ed8f465SJulian Elischer if (ifa->ifa_claim_addr) { 6380b59d917SJonathan Lemon if ((*ifa->ifa_claim_addr)(ifa, addr)) 6390b59d917SJonathan Lemon goto done; 6407ed8f465SJulian Elischer continue; 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 } 6740b59d917SJonathan Lemon ifa = ifa_maybe; 6750b59d917SJonathan Lemon done: 6760b59d917SJonathan Lemon return (ifa); 677df8bae1dSRodney W. Grimes } 678df8bae1dSRodney W. Grimes 679df8bae1dSRodney W. Grimes /* 680df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 681df8bae1dSRodney W. Grimes * a given address. 682df8bae1dSRodney W. Grimes */ 683df8bae1dSRodney W. Grimes struct ifaddr * 684df8bae1dSRodney W. Grimes ifaof_ifpforaddr(addr, ifp) 685df8bae1dSRodney W. Grimes struct sockaddr *addr; 686df8bae1dSRodney W. Grimes register struct ifnet *ifp; 687df8bae1dSRodney W. Grimes { 688df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 689df8bae1dSRodney W. Grimes register char *cp, *cp2, *cp3; 690df8bae1dSRodney W. Grimes register char *cplim; 691df8bae1dSRodney W. Grimes struct ifaddr *ifa_maybe = 0; 692df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 693df8bae1dSRodney W. Grimes 694df8bae1dSRodney W. Grimes if (af >= AF_MAX) 695df8bae1dSRodney W. Grimes return (0); 69637d40066SPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 697df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 698df8bae1dSRodney W. Grimes continue; 699381dd1d2SJulian Elischer if (ifa_maybe == 0) 700df8bae1dSRodney W. Grimes ifa_maybe = ifa; 701df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 702df8bae1dSRodney W. Grimes if (equal(addr, ifa->ifa_addr) || 703df8bae1dSRodney W. Grimes (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))) 704df8bae1dSRodney W. Grimes return (ifa); 705df8bae1dSRodney W. Grimes continue; 706df8bae1dSRodney W. Grimes } 707b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 708b2af64fdSDavid Greenman if (equal(addr, ifa->ifa_dstaddr)) 709b2af64fdSDavid Greenman return (ifa); 7103740e2adSDavid Greenman } else { 711df8bae1dSRodney W. Grimes cp = addr->sa_data; 712df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 713df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 714df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 715df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 716df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 717df8bae1dSRodney W. Grimes break; 718df8bae1dSRodney W. Grimes if (cp3 == cplim) 719df8bae1dSRodney W. Grimes return (ifa); 720df8bae1dSRodney W. Grimes } 721b2af64fdSDavid Greenman } 722df8bae1dSRodney W. Grimes return (ifa_maybe); 723df8bae1dSRodney W. Grimes } 724df8bae1dSRodney W. Grimes 725df8bae1dSRodney W. Grimes #include <net/route.h> 726df8bae1dSRodney W. Grimes 727df8bae1dSRodney W. Grimes /* 728df8bae1dSRodney W. Grimes * Default action when installing a route with a Link Level gateway. 729df8bae1dSRodney W. Grimes * Lookup an appropriate real ifa to point to. 730df8bae1dSRodney W. Grimes * This should be moved to /sys/net/link.c eventually. 731df8bae1dSRodney W. Grimes */ 7323bda9f9bSPoul-Henning Kamp static void 733df8bae1dSRodney W. Grimes link_rtrequest(cmd, rt, sa) 734df8bae1dSRodney W. Grimes int cmd; 735df8bae1dSRodney W. Grimes register struct rtentry *rt; 736df8bae1dSRodney W. Grimes struct sockaddr *sa; 737df8bae1dSRodney W. Grimes { 738df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 739df8bae1dSRodney W. Grimes struct sockaddr *dst; 740df8bae1dSRodney W. Grimes struct ifnet *ifp; 741df8bae1dSRodney W. Grimes 742df8bae1dSRodney W. Grimes if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) || 743df8bae1dSRodney W. Grimes ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0)) 744df8bae1dSRodney W. Grimes return; 7459448326fSPoul-Henning Kamp ifa = ifaof_ifpforaddr(dst, ifp); 7469448326fSPoul-Henning Kamp if (ifa) { 747df8bae1dSRodney W. Grimes IFAFREE(rt->rt_ifa); 748df8bae1dSRodney W. Grimes rt->rt_ifa = ifa; 749df8bae1dSRodney W. Grimes ifa->ifa_refcnt++; 750df8bae1dSRodney W. Grimes if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest) 751df8bae1dSRodney W. Grimes ifa->ifa_rtrequest(cmd, rt, sa); 752df8bae1dSRodney W. Grimes } 753df8bae1dSRodney W. Grimes } 754df8bae1dSRodney W. Grimes 755df8bae1dSRodney W. Grimes /* 756df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 757df8bae1dSRodney W. Grimes * the transition. 758df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 759df8bae1dSRodney W. Grimes */ 760df8bae1dSRodney W. Grimes void 761e8c2601dSPoul-Henning Kamp if_unroute(ifp, flag, fam) 762df8bae1dSRodney W. Grimes register struct ifnet *ifp; 763e8c2601dSPoul-Henning Kamp int flag, fam; 764df8bae1dSRodney W. Grimes { 765df8bae1dSRodney W. Grimes register struct ifaddr *ifa; 766df8bae1dSRodney W. Grimes 767e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 76898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 769e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 770e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 771df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 772df8bae1dSRodney W. Grimes if_qflush(&ifp->if_snd); 773df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 774df8bae1dSRodney W. Grimes } 775df8bae1dSRodney W. Grimes 776df8bae1dSRodney W. Grimes /* 777df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 778df8bae1dSRodney W. Grimes * the transition. 779df8bae1dSRodney W. Grimes * NOTE: must be called at splnet or eqivalent. 780df8bae1dSRodney W. Grimes */ 781df8bae1dSRodney W. Grimes void 782e8c2601dSPoul-Henning Kamp if_route(ifp, flag, fam) 783df8bae1dSRodney W. Grimes register struct ifnet *ifp; 784e8c2601dSPoul-Henning Kamp int flag, fam; 785df8bae1dSRodney W. Grimes { 786176395b2SGarrett Wollman register struct ifaddr *ifa; 787df8bae1dSRodney W. Grimes 788e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 78998b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 790e8c2601dSPoul-Henning Kamp TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 791e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 792df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 793df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 79482cd038dSYoshinobu Inoue #ifdef INET6 79582cd038dSYoshinobu Inoue in6_if_up(ifp); 79682cd038dSYoshinobu Inoue #endif 797df8bae1dSRodney W. Grimes } 798df8bae1dSRodney W. Grimes 799df8bae1dSRodney W. Grimes /* 800e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 801e8c2601dSPoul-Henning Kamp * the transition. 802e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 803e8c2601dSPoul-Henning Kamp */ 804e8c2601dSPoul-Henning Kamp void 805e8c2601dSPoul-Henning Kamp if_down(ifp) 806e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 807e8c2601dSPoul-Henning Kamp { 808e8c2601dSPoul-Henning Kamp 809e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 810e8c2601dSPoul-Henning Kamp } 811e8c2601dSPoul-Henning Kamp 812e8c2601dSPoul-Henning Kamp /* 813e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 814e8c2601dSPoul-Henning Kamp * the transition. 815e8c2601dSPoul-Henning Kamp * NOTE: must be called at splnet or eqivalent. 816e8c2601dSPoul-Henning Kamp */ 817e8c2601dSPoul-Henning Kamp void 818e8c2601dSPoul-Henning Kamp if_up(ifp) 819e8c2601dSPoul-Henning Kamp register struct ifnet *ifp; 820e8c2601dSPoul-Henning Kamp { 821e8c2601dSPoul-Henning Kamp 822e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 823e8c2601dSPoul-Henning Kamp } 824e8c2601dSPoul-Henning Kamp 825e8c2601dSPoul-Henning Kamp /* 826df8bae1dSRodney W. Grimes * Flush an interface queue. 827df8bae1dSRodney W. Grimes */ 8283bda9f9bSPoul-Henning Kamp static void 829df8bae1dSRodney W. Grimes if_qflush(ifq) 830df8bae1dSRodney W. Grimes register struct ifqueue *ifq; 831df8bae1dSRodney W. Grimes { 832df8bae1dSRodney W. Grimes register struct mbuf *m, *n; 833df8bae1dSRodney W. Grimes 834df8bae1dSRodney W. Grimes n = ifq->ifq_head; 8359448326fSPoul-Henning Kamp while ((m = n) != 0) { 836df8bae1dSRodney W. Grimes n = m->m_act; 837df8bae1dSRodney W. Grimes m_freem(m); 838df8bae1dSRodney W. Grimes } 839df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 840df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 841df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 842df8bae1dSRodney W. Grimes } 843df8bae1dSRodney W. Grimes 844df8bae1dSRodney W. Grimes /* 845df8bae1dSRodney W. Grimes * Handle interface watchdog timer routines. Called 846df8bae1dSRodney W. Grimes * from softclock, we decrement timers (if set) and 847df8bae1dSRodney W. Grimes * call the appropriate interface routine on expiration. 848df8bae1dSRodney W. Grimes */ 8493bda9f9bSPoul-Henning Kamp static void 850df8bae1dSRodney W. Grimes if_slowtimo(arg) 851df8bae1dSRodney W. Grimes void *arg; 852df8bae1dSRodney W. Grimes { 853df8bae1dSRodney W. Grimes register struct ifnet *ifp; 854df8bae1dSRodney W. Grimes int s = splimp(); 855df8bae1dSRodney W. Grimes 856fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 857df8bae1dSRodney W. Grimes if (ifp->if_timer == 0 || --ifp->if_timer) 858df8bae1dSRodney W. Grimes continue; 859df8bae1dSRodney W. Grimes if (ifp->if_watchdog) 8604a5f1499SDavid Greenman (*ifp->if_watchdog)(ifp); 861df8bae1dSRodney W. Grimes } 862df8bae1dSRodney W. Grimes splx(s); 863df8bae1dSRodney W. Grimes timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ); 864df8bae1dSRodney W. Grimes } 865df8bae1dSRodney W. Grimes 866df8bae1dSRodney W. Grimes /* 867df8bae1dSRodney W. Grimes * Map interface name to 868df8bae1dSRodney W. Grimes * interface structure pointer. 869df8bae1dSRodney W. Grimes */ 870df8bae1dSRodney W. Grimes struct ifnet * 87130aad87dSBrooks Davis ifunit(const char *name) 872df8bae1dSRodney W. Grimes { 87301f0fef3SJulian Elischer char namebuf[IFNAMSIZ + 1]; 87430aad87dSBrooks Davis const char *cp; 8758b7805e4SBoris Popov struct ifnet *ifp; 876df8bae1dSRodney W. Grimes int unit; 8778b7805e4SBoris Popov unsigned len, m; 8788b7805e4SBoris Popov char c; 879df8bae1dSRodney W. Grimes 8808b7805e4SBoris Popov len = strlen(name); 8818b7805e4SBoris Popov if (len < 2 || len > IFNAMSIZ) 8828b7805e4SBoris Popov return NULL; 8838b7805e4SBoris Popov cp = name + len - 1; 8848b7805e4SBoris Popov c = *cp; 8858b7805e4SBoris Popov if (c < '0' || c > '9') 8868b7805e4SBoris Popov return NULL; /* trailing garbage */ 8878b7805e4SBoris Popov unit = 0; 8888b7805e4SBoris Popov m = 1; 8898b7805e4SBoris Popov do { 8908b7805e4SBoris Popov if (cp == name) 8918b7805e4SBoris Popov return NULL; /* no interface name */ 8928b7805e4SBoris Popov unit += (c - '0') * m; 8938b7805e4SBoris Popov if (unit > 1000000) 8948b7805e4SBoris Popov return NULL; /* number is unreasonable */ 8958b7805e4SBoris Popov m *= 10; 8968b7805e4SBoris Popov c = *--cp; 8978b7805e4SBoris Popov } while (c >= '0' && c <= '9'); 898df8bae1dSRodney W. Grimes len = cp - name + 1; 8998b7805e4SBoris Popov bcopy(name, namebuf, len); 9008b7805e4SBoris Popov namebuf[len] = '\0'; 90101f0fef3SJulian Elischer /* 90201f0fef3SJulian Elischer * Now search all the interfaces for this name/number 90301f0fef3SJulian Elischer */ 904fc2ffbe6SPoul-Henning Kamp TAILQ_FOREACH(ifp, &ifnet, if_link) { 9058b7805e4SBoris Popov if (strcmp(ifp->if_name, namebuf)) 906df8bae1dSRodney W. Grimes continue; 907df8bae1dSRodney W. Grimes if (unit == ifp->if_unit) 908df8bae1dSRodney W. Grimes break; 909df8bae1dSRodney W. Grimes } 910df8bae1dSRodney W. Grimes return (ifp); 911df8bae1dSRodney W. Grimes } 912df8bae1dSRodney W. Grimes 91382cd038dSYoshinobu Inoue 91482cd038dSYoshinobu Inoue /* 91582cd038dSYoshinobu Inoue * Map interface name in a sockaddr_dl to 91682cd038dSYoshinobu Inoue * interface structure pointer. 91782cd038dSYoshinobu Inoue */ 91882cd038dSYoshinobu Inoue struct ifnet * 91982cd038dSYoshinobu Inoue if_withname(sa) 92082cd038dSYoshinobu Inoue struct sockaddr *sa; 92182cd038dSYoshinobu Inoue { 92282cd038dSYoshinobu Inoue char ifname[IFNAMSIZ+1]; 92382cd038dSYoshinobu Inoue struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa; 92482cd038dSYoshinobu Inoue 92582cd038dSYoshinobu Inoue if ( (sa->sa_family != AF_LINK) || (sdl->sdl_nlen == 0) || 92682cd038dSYoshinobu Inoue (sdl->sdl_nlen > IFNAMSIZ) ) 92782cd038dSYoshinobu Inoue return NULL; 92882cd038dSYoshinobu Inoue 92982cd038dSYoshinobu Inoue /* 93082cd038dSYoshinobu Inoue * ifunit wants a null-terminated name. It may not be null-terminated 93182cd038dSYoshinobu Inoue * in the sockaddr. We don't want to change the caller's sockaddr, 93282cd038dSYoshinobu Inoue * and there might not be room to put the trailing null anyway, so we 93382cd038dSYoshinobu Inoue * make a local copy that we know we can null terminate safely. 93482cd038dSYoshinobu Inoue */ 93582cd038dSYoshinobu Inoue 93682cd038dSYoshinobu Inoue bcopy(sdl->sdl_data, ifname, sdl->sdl_nlen); 93782cd038dSYoshinobu Inoue ifname[sdl->sdl_nlen] = '\0'; 93882cd038dSYoshinobu Inoue return ifunit(ifname); 93982cd038dSYoshinobu Inoue } 94082cd038dSYoshinobu Inoue 94182cd038dSYoshinobu Inoue 942df8bae1dSRodney W. Grimes /* 943df8bae1dSRodney W. Grimes * Interface ioctls. 944df8bae1dSRodney W. Grimes */ 945df8bae1dSRodney W. Grimes int 946df8bae1dSRodney W. Grimes ifioctl(so, cmd, data, p) 947df8bae1dSRodney W. Grimes struct socket *so; 948ecbb00a2SDoug Rabson u_long cmd; 949df8bae1dSRodney W. Grimes caddr_t data; 950df8bae1dSRodney W. Grimes struct proc *p; 951df8bae1dSRodney W. Grimes { 952df8bae1dSRodney W. Grimes register struct ifnet *ifp; 953df8bae1dSRodney W. Grimes register struct ifreq *ifr; 954413dd0baSPoul-Henning Kamp struct ifstat *ifs; 955df8bae1dSRodney W. Grimes int error; 95682cd038dSYoshinobu Inoue short oif_flags; 957df8bae1dSRodney W. Grimes 958df8bae1dSRodney W. Grimes switch (cmd) { 959df8bae1dSRodney W. Grimes 960df8bae1dSRodney W. Grimes case SIOCGIFCONF: 961df8bae1dSRodney W. Grimes case OSIOCGIFCONF: 962df8bae1dSRodney W. Grimes return (ifconf(cmd, data)); 963df8bae1dSRodney W. Grimes } 964df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 96530aad87dSBrooks Davis 96630aad87dSBrooks Davis switch (cmd) { 96730aad87dSBrooks Davis case SIOCIFCREATE: 96830aad87dSBrooks Davis case SIOCIFDESTROY: 96930aad87dSBrooks Davis if ((error = suser(p)) != 0) 97030aad87dSBrooks Davis return (error); 97130aad87dSBrooks Davis return ((cmd == SIOCIFCREATE) ? 97230aad87dSBrooks Davis if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) : 97330aad87dSBrooks Davis if_clone_destroy(ifr->ifr_name)); 97430aad87dSBrooks Davis 97530aad87dSBrooks Davis case SIOCIFGCLONERS: 97630aad87dSBrooks Davis return (if_clone_list((struct if_clonereq *)data)); 97730aad87dSBrooks Davis } 97830aad87dSBrooks Davis 979df8bae1dSRodney W. Grimes ifp = ifunit(ifr->ifr_name); 980df8bae1dSRodney W. Grimes if (ifp == 0) 981df8bae1dSRodney W. Grimes return (ENXIO); 982df8bae1dSRodney W. Grimes switch (cmd) { 983df8bae1dSRodney W. Grimes 984df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 985df8bae1dSRodney W. Grimes ifr->ifr_flags = ifp->if_flags; 986df8bae1dSRodney W. Grimes break; 987df8bae1dSRodney W. Grimes 988df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 989df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 990df8bae1dSRodney W. Grimes break; 991df8bae1dSRodney W. Grimes 992a7028af7SDavid Greenman case SIOCGIFMTU: 993a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 994a7028af7SDavid Greenman break; 995a7028af7SDavid Greenman 996074c4a4eSGarrett Wollman case SIOCGIFPHYS: 997074c4a4eSGarrett Wollman ifr->ifr_phys = ifp->if_physical; 998074c4a4eSGarrett Wollman break; 999074c4a4eSGarrett Wollman 1000df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 1001f711d546SPoul-Henning Kamp error = suser(p); 10029448326fSPoul-Henning Kamp if (error) 1003df8bae1dSRodney W. Grimes return (error); 10044add131eSPoul-Henning Kamp ifr->ifr_prevflags = ifp->if_flags; 1005cf4b9371SPoul-Henning Kamp if (ifp->if_flags & IFF_SMART) { 1006cf4b9371SPoul-Henning Kamp /* Smart drivers twiddle their own routes */ 10072f55ead7SPoul-Henning Kamp } else if (ifp->if_flags & IFF_UP && 1008cf4b9371SPoul-Henning Kamp (ifr->ifr_flags & IFF_UP) == 0) { 1009df8bae1dSRodney W. Grimes int s = splimp(); 1010df8bae1dSRodney W. Grimes if_down(ifp); 1011df8bae1dSRodney W. Grimes splx(s); 1012cf4b9371SPoul-Henning Kamp } else if (ifr->ifr_flags & IFF_UP && 1013cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 1014df8bae1dSRodney W. Grimes int s = splimp(); 1015df8bae1dSRodney W. Grimes if_up(ifp); 1016df8bae1dSRodney W. Grimes splx(s); 1017df8bae1dSRodney W. Grimes } 1018df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 1019df8bae1dSRodney W. Grimes (ifr->ifr_flags &~ IFF_CANTCHANGE); 1020df8bae1dSRodney W. Grimes if (ifp->if_ioctl) 1021df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 102298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1023df8bae1dSRodney W. Grimes break; 1024df8bae1dSRodney W. Grimes 1025df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 1026f711d546SPoul-Henning Kamp error = suser(p); 10279448326fSPoul-Henning Kamp if (error) 1028df8bae1dSRodney W. Grimes return (error); 1029df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 103098b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1031df8bae1dSRodney W. Grimes break; 1032df8bae1dSRodney W. Grimes 1033074c4a4eSGarrett Wollman case SIOCSIFPHYS: 1034f711d546SPoul-Henning Kamp error = suser(p); 1035e39a0280SGary Palmer if (error) 1036e39a0280SGary Palmer return error; 1037e39a0280SGary Palmer if (!ifp->if_ioctl) 1038e39a0280SGary Palmer return EOPNOTSUPP; 1039e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 1040e39a0280SGary Palmer if (error == 0) 104198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1042e39a0280SGary Palmer return(error); 1043074c4a4eSGarrett Wollman 1044a7028af7SDavid Greenman case SIOCSIFMTU: 104582cd038dSYoshinobu Inoue { 104682cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 104782cd038dSYoshinobu Inoue 1048f711d546SPoul-Henning Kamp error = suser(p); 10499448326fSPoul-Henning Kamp if (error) 1050a7028af7SDavid Greenman return (error); 1051a7028af7SDavid Greenman if (ifp->if_ioctl == NULL) 1052a7028af7SDavid Greenman return (EOPNOTSUPP); 1053aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 105475ee03cbSDavid Greenman return (EINVAL); 1055e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 105648f71763SRuslan Ermilov if (error == 0) { 105798b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 105848f71763SRuslan Ermilov rt_ifmsg(ifp); 105948f71763SRuslan Ermilov } 106082cd038dSYoshinobu Inoue /* 106182cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 106282cd038dSYoshinobu Inoue */ 106382cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 106482cd038dSYoshinobu Inoue #ifdef INET6 106582cd038dSYoshinobu Inoue nd6_setmtu(ifp); 106682cd038dSYoshinobu Inoue #endif 106782cd038dSYoshinobu Inoue } 1068e39a0280SGary Palmer return (error); 106982cd038dSYoshinobu Inoue } 1070a7028af7SDavid Greenman 1071df8bae1dSRodney W. Grimes case SIOCADDMULTI: 1072df8bae1dSRodney W. Grimes case SIOCDELMULTI: 1073f711d546SPoul-Henning Kamp error = suser(p); 10749448326fSPoul-Henning Kamp if (error) 1075df8bae1dSRodney W. Grimes return (error); 1076477180fbSGarrett Wollman 1077477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 1078477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 1079477180fbSGarrett Wollman return EOPNOTSUPP; 1080477180fbSGarrett Wollman 1081477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 1082477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 1083477180fbSGarrett Wollman return EINVAL; 1084477180fbSGarrett Wollman 1085477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 1086477180fbSGarrett Wollman struct ifmultiaddr *ifma; 1087477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 1088477180fbSGarrett Wollman } else { 1089477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 1090477180fbSGarrett Wollman } 1091e39a0280SGary Palmer if (error == 0) 109298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1093477180fbSGarrett Wollman return error; 1094df8bae1dSRodney W. Grimes 109541b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 109641b3e8e5SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 109741b3e8e5SJun-ichiro itojun Hagino #ifdef INET6 109841b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 109941b3e8e5SJun-ichiro itojun Hagino #endif 110033841545SHajimu UMEMOTO case SIOCSLIFPHYADDR: 1101a912e453SPeter Wemm case SIOCSIFMEDIA: 1102d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 1103f711d546SPoul-Henning Kamp error = suser(p); 1104a912e453SPeter Wemm if (error) 1105a912e453SPeter Wemm return (error); 1106a912e453SPeter Wemm if (ifp->if_ioctl == 0) 1107a912e453SPeter Wemm return (EOPNOTSUPP); 1108a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 1109a912e453SPeter Wemm if (error == 0) 111098b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 1111a912e453SPeter Wemm return error; 1112a912e453SPeter Wemm 1113413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 1114413dd0baSPoul-Henning Kamp ifs = (struct ifstat *)data; 1115413dd0baSPoul-Henning Kamp ifs->ascii[0] = '\0'; 1116413dd0baSPoul-Henning Kamp 111733841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 111833841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 111933841545SHajimu UMEMOTO case SIOCGLIFPHYADDR: 1120a912e453SPeter Wemm case SIOCGIFMEDIA: 1121d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 1122a912e453SPeter Wemm if (ifp->if_ioctl == 0) 1123a912e453SPeter Wemm return (EOPNOTSUPP); 1124a912e453SPeter Wemm return ((*ifp->if_ioctl)(ifp, cmd, data)); 1125a912e453SPeter Wemm 1126b106252cSBill Paul case SIOCSIFLLADDR: 1127b106252cSBill Paul error = suser(p); 1128b106252cSBill Paul if (error) 1129b106252cSBill Paul return (error); 113066ce51ceSArchie Cobbs return if_setlladdr(ifp, 113166ce51ceSArchie Cobbs ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 113266ce51ceSArchie Cobbs 1133df8bae1dSRodney W. Grimes default: 113482cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 1135df8bae1dSRodney W. Grimes if (so->so_proto == 0) 1136df8bae1dSRodney W. Grimes return (EOPNOTSUPP); 1137df8bae1dSRodney W. Grimes #ifndef COMPAT_43 113882cd038dSYoshinobu Inoue error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, 11392c37256eSGarrett Wollman data, 1140bc6d9b80SJoerg Wunsch ifp, p)); 1141df8bae1dSRodney W. Grimes #else 1142df8bae1dSRodney W. Grimes { 1143df8bae1dSRodney W. Grimes int ocmd = cmd; 1144df8bae1dSRodney W. Grimes 1145df8bae1dSRodney W. Grimes switch (cmd) { 1146df8bae1dSRodney W. Grimes 1147df8bae1dSRodney W. Grimes case SIOCSIFDSTADDR: 1148df8bae1dSRodney W. Grimes case SIOCSIFADDR: 1149df8bae1dSRodney W. Grimes case SIOCSIFBRDADDR: 1150df8bae1dSRodney W. Grimes case SIOCSIFNETMASK: 1151df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN 1152df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_family == 0 && 1153df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len < 16) { 1154df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len; 1155df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1156df8bae1dSRodney W. Grimes } 1157df8bae1dSRodney W. Grimes #else 1158df8bae1dSRodney W. Grimes if (ifr->ifr_addr.sa_len == 0) 1159df8bae1dSRodney W. Grimes ifr->ifr_addr.sa_len = 16; 1160df8bae1dSRodney W. Grimes #endif 1161df8bae1dSRodney W. Grimes break; 1162df8bae1dSRodney W. Grimes 1163df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1164df8bae1dSRodney W. Grimes cmd = SIOCGIFADDR; 1165df8bae1dSRodney W. Grimes break; 1166df8bae1dSRodney W. Grimes 1167df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1168df8bae1dSRodney W. Grimes cmd = SIOCGIFDSTADDR; 1169df8bae1dSRodney W. Grimes break; 1170df8bae1dSRodney W. Grimes 1171df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1172df8bae1dSRodney W. Grimes cmd = SIOCGIFBRDADDR; 1173df8bae1dSRodney W. Grimes break; 1174df8bae1dSRodney W. Grimes 1175df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1176df8bae1dSRodney W. Grimes cmd = SIOCGIFNETMASK; 1177df8bae1dSRodney W. Grimes } 11782c37256eSGarrett Wollman error = ((*so->so_proto->pr_usrreqs->pru_control)(so, 11792c37256eSGarrett Wollman cmd, 11802c37256eSGarrett Wollman data, 1181a29f300eSGarrett Wollman ifp, p)); 1182df8bae1dSRodney W. Grimes switch (ocmd) { 1183df8bae1dSRodney W. Grimes 1184df8bae1dSRodney W. Grimes case OSIOCGIFADDR: 1185df8bae1dSRodney W. Grimes case OSIOCGIFDSTADDR: 1186df8bae1dSRodney W. Grimes case OSIOCGIFBRDADDR: 1187df8bae1dSRodney W. Grimes case OSIOCGIFNETMASK: 1188df8bae1dSRodney W. Grimes *(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family; 118982cd038dSYoshinobu Inoue 119082cd038dSYoshinobu Inoue } 119182cd038dSYoshinobu Inoue } 119282cd038dSYoshinobu Inoue #endif /* COMPAT_43 */ 119382cd038dSYoshinobu Inoue 119482cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 119582cd038dSYoshinobu Inoue #ifdef INET6 11963411310dSYoshinobu Inoue DELAY(100);/* XXX: temporal workaround for fxp issue*/ 119782cd038dSYoshinobu Inoue if (ifp->if_flags & IFF_UP) { 119882cd038dSYoshinobu Inoue int s = splimp(); 119982cd038dSYoshinobu Inoue in6_if_up(ifp); 120082cd038dSYoshinobu Inoue splx(s); 120182cd038dSYoshinobu Inoue } 120282cd038dSYoshinobu Inoue #endif 1203df8bae1dSRodney W. Grimes } 1204df8bae1dSRodney W. Grimes return (error); 1205df8bae1dSRodney W. Grimes 1206df8bae1dSRodney W. Grimes } 1207df8bae1dSRodney W. Grimes return (0); 1208df8bae1dSRodney W. Grimes } 1209df8bae1dSRodney W. Grimes 1210df8bae1dSRodney W. Grimes /* 1211963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 1212963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 1213963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 1214963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 1215963e4c2aSGarrett Wollman */ 1216963e4c2aSGarrett Wollman int 1217963e4c2aSGarrett Wollman ifpromisc(ifp, pswitch) 1218963e4c2aSGarrett Wollman struct ifnet *ifp; 1219963e4c2aSGarrett Wollman int pswitch; 1220963e4c2aSGarrett Wollman { 1221963e4c2aSGarrett Wollman struct ifreq ifr; 12224a26224cSGarrett Wollman int error; 12234f3c11a6SBill Fenner int oldflags, oldpcount; 1224963e4c2aSGarrett Wollman 12254f3c11a6SBill Fenner oldpcount = ifp->if_pcount; 12262c514a31SBrian Somers oldflags = ifp->if_flags; 1227963e4c2aSGarrett Wollman if (pswitch) { 1228963e4c2aSGarrett Wollman /* 1229963e4c2aSGarrett Wollman * If the device is not configured up, we cannot put it in 1230963e4c2aSGarrett Wollman * promiscuous mode. 1231963e4c2aSGarrett Wollman */ 1232963e4c2aSGarrett Wollman if ((ifp->if_flags & IFF_UP) == 0) 1233963e4c2aSGarrett Wollman return (ENETDOWN); 1234963e4c2aSGarrett Wollman if (ifp->if_pcount++ != 0) 1235963e4c2aSGarrett Wollman return (0); 1236963e4c2aSGarrett Wollman ifp->if_flags |= IFF_PROMISC; 1237963e4c2aSGarrett Wollman } else { 1238963e4c2aSGarrett Wollman if (--ifp->if_pcount > 0) 1239963e4c2aSGarrett Wollman return (0); 1240963e4c2aSGarrett Wollman ifp->if_flags &= ~IFF_PROMISC; 1241963e4c2aSGarrett Wollman } 1242963e4c2aSGarrett Wollman ifr.ifr_flags = ifp->if_flags; 12434a26224cSGarrett Wollman error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 12444f3c11a6SBill Fenner if (error == 0) { 12454f3c11a6SBill Fenner log(LOG_INFO, "%s%d: promiscuous mode %s\n", 12464f3c11a6SBill Fenner ifp->if_name, ifp->if_unit, 12474f3c11a6SBill Fenner (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 12484a26224cSGarrett Wollman rt_ifmsg(ifp); 12494f3c11a6SBill Fenner } else { 12504f3c11a6SBill Fenner ifp->if_pcount = oldpcount; 12512c514a31SBrian Somers ifp->if_flags = oldflags; 12524f3c11a6SBill Fenner } 12534a26224cSGarrett Wollman return error; 1254963e4c2aSGarrett Wollman } 1255963e4c2aSGarrett Wollman 1256963e4c2aSGarrett Wollman /* 1257df8bae1dSRodney W. Grimes * Return interface configuration 1258df8bae1dSRodney W. Grimes * of system. List may be used 1259df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 1260df8bae1dSRodney W. Grimes * other information. 1261df8bae1dSRodney W. Grimes */ 1262df8bae1dSRodney W. Grimes /*ARGSUSED*/ 12633bda9f9bSPoul-Henning Kamp static int 1264df8bae1dSRodney W. Grimes ifconf(cmd, data) 1265ecbb00a2SDoug Rabson u_long cmd; 1266df8bae1dSRodney W. Grimes caddr_t data; 1267df8bae1dSRodney W. Grimes { 12680b59d917SJonathan Lemon struct ifconf *ifc = (struct ifconf *)data; 12690b59d917SJonathan Lemon struct ifnet *ifp; 12700b59d917SJonathan Lemon struct ifaddr *ifa; 1271df8bae1dSRodney W. Grimes struct ifreq ifr, *ifrp; 1272df8bae1dSRodney W. Grimes int space = ifc->ifc_len, error = 0; 1273df8bae1dSRodney W. Grimes 1274df8bae1dSRodney W. Grimes ifrp = ifc->ifc_req; 12750b59d917SJonathan Lemon TAILQ_FOREACH(ifp, &ifnet, if_link) { 12761ce9bf88SPoul-Henning Kamp char workbuf[64]; 127775c13541SPoul-Henning Kamp int ifnlen, addrs; 12782624cf89SGarrett Wollman 12790b59d917SJonathan Lemon if (space > sizeof(ifr)) 12800b59d917SJonathan Lemon break; 12810b59d917SJonathan Lemon 12822127f260SArchie Cobbs ifnlen = snprintf(workbuf, sizeof(workbuf), 12832127f260SArchie Cobbs "%s%d", ifp->if_name, ifp->if_unit); 12841ce9bf88SPoul-Henning Kamp if(ifnlen + 1 > sizeof ifr.ifr_name) { 12852624cf89SGarrett Wollman error = ENAMETOOLONG; 1286b3f1e629SGuido van Rooij break; 12872624cf89SGarrett Wollman } else { 12881ce9bf88SPoul-Henning Kamp strcpy(ifr.ifr_name, workbuf); 12892624cf89SGarrett Wollman } 12902624cf89SGarrett Wollman 129175c13541SPoul-Henning Kamp addrs = 0; 129222f29826SPoul-Henning Kamp ifa = TAILQ_FIRST(&ifp->if_addrhead); 129359562606SGarrett Wollman for ( ; space > sizeof (ifr) && ifa; 129422f29826SPoul-Henning Kamp ifa = TAILQ_NEXT(ifa, ifa_link)) { 1295df8bae1dSRodney W. Grimes register struct sockaddr *sa = ifa->ifa_addr; 129691421ba2SRobert Watson if (jailed(curproc->p_ucred) && 129791421ba2SRobert Watson prison_if(curproc->p_ucred, sa)) 129875c13541SPoul-Henning Kamp continue; 129975c13541SPoul-Henning Kamp addrs++; 1300df8bae1dSRodney W. Grimes #ifdef COMPAT_43 1301df8bae1dSRodney W. Grimes if (cmd == OSIOCGIFCONF) { 1302df8bae1dSRodney W. Grimes struct osockaddr *osa = 1303df8bae1dSRodney W. Grimes (struct osockaddr *)&ifr.ifr_addr; 1304df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1305df8bae1dSRodney W. Grimes osa->sa_family = sa->sa_family; 1306df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1307df8bae1dSRodney W. Grimes sizeof (ifr)); 1308df8bae1dSRodney W. Grimes ifrp++; 1309df8bae1dSRodney W. Grimes } else 1310df8bae1dSRodney W. Grimes #endif 1311df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 1312df8bae1dSRodney W. Grimes ifr.ifr_addr = *sa; 1313df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1314df8bae1dSRodney W. Grimes sizeof (ifr)); 1315df8bae1dSRodney W. Grimes ifrp++; 1316df8bae1dSRodney W. Grimes } else { 1317d91a068eSGuido van Rooij if (space < sizeof (ifr) + sa->sa_len - 1318d91a068eSGuido van Rooij sizeof(*sa)) 1319b3f1e629SGuido van Rooij break; 1320df8bae1dSRodney W. Grimes space -= sa->sa_len - sizeof(*sa); 1321df8bae1dSRodney W. Grimes error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 1322df8bae1dSRodney W. Grimes sizeof (ifr.ifr_name)); 1323df8bae1dSRodney W. Grimes if (error == 0) 1324df8bae1dSRodney W. Grimes error = copyout((caddr_t)sa, 1325df8bae1dSRodney W. Grimes (caddr_t)&ifrp->ifr_addr, sa->sa_len); 1326df8bae1dSRodney W. Grimes ifrp = (struct ifreq *) 1327df8bae1dSRodney W. Grimes (sa->sa_len + (caddr_t)&ifrp->ifr_addr); 1328df8bae1dSRodney W. Grimes } 1329df8bae1dSRodney W. Grimes if (error) 1330df8bae1dSRodney W. Grimes break; 1331df8bae1dSRodney W. Grimes space -= sizeof (ifr); 1332df8bae1dSRodney W. Grimes } 1333b3f1e629SGuido van Rooij if (error) 1334b3f1e629SGuido van Rooij break; 133575c13541SPoul-Henning Kamp if (!addrs) { 133675c13541SPoul-Henning Kamp bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr)); 133775c13541SPoul-Henning Kamp error = copyout((caddr_t)&ifr, (caddr_t)ifrp, 133875c13541SPoul-Henning Kamp sizeof (ifr)); 133975c13541SPoul-Henning Kamp if (error) 134075c13541SPoul-Henning Kamp break; 1341b3f1e629SGuido van Rooij space -= sizeof (ifr); 1342b3f1e629SGuido van Rooij ifrp++; 134375c13541SPoul-Henning Kamp } 1344df8bae1dSRodney W. Grimes } 1345df8bae1dSRodney W. Grimes ifc->ifc_len -= space; 1346df8bae1dSRodney W. Grimes return (error); 1347df8bae1dSRodney W. Grimes } 1348df8bae1dSRodney W. Grimes 13491158dfb7SGarrett Wollman /* 13501158dfb7SGarrett Wollman * Just like if_promisc(), but for all-multicast-reception mode. 13511158dfb7SGarrett Wollman */ 13521158dfb7SGarrett Wollman int 13531158dfb7SGarrett Wollman if_allmulti(ifp, onswitch) 13541158dfb7SGarrett Wollman struct ifnet *ifp; 13551158dfb7SGarrett Wollman int onswitch; 13561158dfb7SGarrett Wollman { 13571158dfb7SGarrett Wollman int error = 0; 13581158dfb7SGarrett Wollman int s = splimp(); 13591158dfb7SGarrett Wollman 13601158dfb7SGarrett Wollman if (onswitch) { 13611158dfb7SGarrett Wollman if (ifp->if_amcount++ == 0) { 13621158dfb7SGarrett Wollman ifp->if_flags |= IFF_ALLMULTI; 13631158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 13641158dfb7SGarrett Wollman } 13651158dfb7SGarrett Wollman } else { 13661158dfb7SGarrett Wollman if (ifp->if_amcount > 1) { 13671158dfb7SGarrett Wollman ifp->if_amcount--; 13681158dfb7SGarrett Wollman } else { 13691158dfb7SGarrett Wollman ifp->if_amcount = 0; 13701158dfb7SGarrett Wollman ifp->if_flags &= ~IFF_ALLMULTI; 13711158dfb7SGarrett Wollman error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, 0); 13721158dfb7SGarrett Wollman } 13731158dfb7SGarrett Wollman } 13741158dfb7SGarrett Wollman splx(s); 13754a26224cSGarrett Wollman 13764a26224cSGarrett Wollman if (error == 0) 13774a26224cSGarrett Wollman rt_ifmsg(ifp); 13781158dfb7SGarrett Wollman return error; 13791158dfb7SGarrett Wollman } 13801158dfb7SGarrett Wollman 13811158dfb7SGarrett Wollman /* 13821158dfb7SGarrett Wollman * Add a multicast listenership to the interface in question. 13831158dfb7SGarrett Wollman * The link layer provides a routine which converts 13841158dfb7SGarrett Wollman */ 13851158dfb7SGarrett Wollman int 1386373f88edSGarrett Wollman if_addmulti(ifp, sa, retifma) 13871158dfb7SGarrett Wollman struct ifnet *ifp; /* interface to manipulate */ 13881158dfb7SGarrett Wollman struct sockaddr *sa; /* address to add */ 1389b2053118SGarrett Wollman struct ifmultiaddr **retifma; 13901158dfb7SGarrett Wollman { 13911158dfb7SGarrett Wollman struct sockaddr *llsa, *dupsa; 13921158dfb7SGarrett Wollman int error, s; 13931158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 13941158dfb7SGarrett Wollman 139557af7922SJulian Elischer /* 139657af7922SJulian Elischer * If the matching multicast address already exists 139757af7922SJulian Elischer * then don't add a new one, just add a reference 139857af7922SJulian Elischer */ 13996817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 140057af7922SJulian Elischer if (equal(sa, ifma->ifma_addr)) { 14011158dfb7SGarrett Wollman ifma->ifma_refcount++; 140257af7922SJulian Elischer if (retifma) 140357af7922SJulian Elischer *retifma = ifma; 14041158dfb7SGarrett Wollman return 0; 14051158dfb7SGarrett Wollman } 140657af7922SJulian Elischer } 14071158dfb7SGarrett Wollman 14081158dfb7SGarrett Wollman /* 14091158dfb7SGarrett Wollman * Give the link layer a chance to accept/reject it, and also 14101158dfb7SGarrett Wollman * find out which AF_LINK address this maps to, if it isn't one 14111158dfb7SGarrett Wollman * already. 14121158dfb7SGarrett Wollman */ 14131158dfb7SGarrett Wollman if (ifp->if_resolvemulti) { 14141158dfb7SGarrett Wollman error = ifp->if_resolvemulti(ifp, &llsa, sa); 14151158dfb7SGarrett Wollman if (error) return error; 14161158dfb7SGarrett Wollman } else { 14171158dfb7SGarrett Wollman llsa = 0; 14181158dfb7SGarrett Wollman } 14191158dfb7SGarrett Wollman 14201158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK); 14211158dfb7SGarrett Wollman MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK); 14221158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 14231158dfb7SGarrett Wollman 14241158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 14251158dfb7SGarrett Wollman ifma->ifma_lladdr = llsa; 14261158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 14271158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 1428373f88edSGarrett Wollman ifma->ifma_protospec = 0; 1429477180fbSGarrett Wollman rt_newmaddrmsg(RTM_NEWMADDR, ifma); 1430373f88edSGarrett Wollman 14311158dfb7SGarrett Wollman /* 14321158dfb7SGarrett Wollman * Some network interfaces can scan the address list at 14331158dfb7SGarrett Wollman * interrupt time; lock them out. 14341158dfb7SGarrett Wollman */ 14351158dfb7SGarrett Wollman s = splimp(); 14366817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 14371158dfb7SGarrett Wollman splx(s); 1438373f88edSGarrett Wollman *retifma = ifma; 14391158dfb7SGarrett Wollman 14401158dfb7SGarrett Wollman if (llsa != 0) { 14416817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 14421158dfb7SGarrett Wollman if (equal(ifma->ifma_addr, llsa)) 14431158dfb7SGarrett Wollman break; 14441158dfb7SGarrett Wollman } 14451158dfb7SGarrett Wollman if (ifma) { 14461158dfb7SGarrett Wollman ifma->ifma_refcount++; 14471158dfb7SGarrett Wollman } else { 14481158dfb7SGarrett Wollman MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, 14491158dfb7SGarrett Wollman M_IFMADDR, M_WAITOK); 1450477180fbSGarrett Wollman MALLOC(dupsa, struct sockaddr *, llsa->sa_len, 1451477180fbSGarrett Wollman M_IFMADDR, M_WAITOK); 1452477180fbSGarrett Wollman bcopy(llsa, dupsa, llsa->sa_len); 1453477180fbSGarrett Wollman ifma->ifma_addr = dupsa; 14541158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 14551158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 14561158dfb7SGarrett Wollman s = splimp(); 14576817526dSPoul-Henning Kamp TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 14581158dfb7SGarrett Wollman splx(s); 14591158dfb7SGarrett Wollman } 146057af7922SJulian Elischer } 14611158dfb7SGarrett Wollman /* 14621158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 14631158dfb7SGarrett Wollman * interface to let them know about it. 14641158dfb7SGarrett Wollman */ 14651158dfb7SGarrett Wollman s = splimp(); 14661158dfb7SGarrett Wollman ifp->if_ioctl(ifp, SIOCADDMULTI, 0); 14671158dfb7SGarrett Wollman splx(s); 14681158dfb7SGarrett Wollman 14691158dfb7SGarrett Wollman return 0; 14701158dfb7SGarrett Wollman } 14711158dfb7SGarrett Wollman 14721158dfb7SGarrett Wollman /* 14731158dfb7SGarrett Wollman * Remove a reference to a multicast address on this interface. Yell 14741158dfb7SGarrett Wollman * if the request does not match an existing membership. 14751158dfb7SGarrett Wollman */ 14761158dfb7SGarrett Wollman int 14771158dfb7SGarrett Wollman if_delmulti(ifp, sa) 14781158dfb7SGarrett Wollman struct ifnet *ifp; 14791158dfb7SGarrett Wollman struct sockaddr *sa; 14801158dfb7SGarrett Wollman { 14811158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 14821158dfb7SGarrett Wollman int s; 14831158dfb7SGarrett Wollman 14846817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 14851158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 14861158dfb7SGarrett Wollman break; 14871158dfb7SGarrett Wollman if (ifma == 0) 14881158dfb7SGarrett Wollman return ENOENT; 14891158dfb7SGarrett Wollman 14901158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 14911158dfb7SGarrett Wollman ifma->ifma_refcount--; 14921158dfb7SGarrett Wollman return 0; 14931158dfb7SGarrett Wollman } 14941158dfb7SGarrett Wollman 1495477180fbSGarrett Wollman rt_newmaddrmsg(RTM_DELMADDR, ifma); 14961158dfb7SGarrett Wollman sa = ifma->ifma_lladdr; 14971158dfb7SGarrett Wollman s = splimp(); 14986817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 1499ccb7cc8dSYaroslav Tykhiy /* 1500ccb7cc8dSYaroslav Tykhiy * Make sure the interface driver is notified 1501ccb7cc8dSYaroslav Tykhiy * in the case of a link layer mcast group being left. 1502ccb7cc8dSYaroslav Tykhiy */ 1503ccb7cc8dSYaroslav Tykhiy if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) 1504ccb7cc8dSYaroslav Tykhiy ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 15051158dfb7SGarrett Wollman splx(s); 15061158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 15071158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 15081158dfb7SGarrett Wollman if (sa == 0) 15091158dfb7SGarrett Wollman return 0; 15101158dfb7SGarrett Wollman 15111158dfb7SGarrett Wollman /* 15121158dfb7SGarrett Wollman * Now look for the link-layer address which corresponds to 15131158dfb7SGarrett Wollman * this network address. It had been squirreled away in 15141158dfb7SGarrett Wollman * ifma->ifma_lladdr for this purpose (so we don't have 15151158dfb7SGarrett Wollman * to call ifp->if_resolvemulti() again), and we saved that 15161158dfb7SGarrett Wollman * value in sa above. If some nasty deleted the 15171158dfb7SGarrett Wollman * link-layer address out from underneath us, we can deal because 15181158dfb7SGarrett Wollman * the address we stored was is not the same as the one which was 15191158dfb7SGarrett Wollman * in the record for the link-layer address. (So we don't complain 15201158dfb7SGarrett Wollman * in that case.) 15211158dfb7SGarrett Wollman */ 15226817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 15231158dfb7SGarrett Wollman if (equal(sa, ifma->ifma_addr)) 15241158dfb7SGarrett Wollman break; 15251158dfb7SGarrett Wollman if (ifma == 0) 15261158dfb7SGarrett Wollman return 0; 15271158dfb7SGarrett Wollman 15281158dfb7SGarrett Wollman if (ifma->ifma_refcount > 1) { 15291158dfb7SGarrett Wollman ifma->ifma_refcount--; 15301158dfb7SGarrett Wollman return 0; 15311158dfb7SGarrett Wollman } 15321158dfb7SGarrett Wollman 15331158dfb7SGarrett Wollman s = splimp(); 15346817526dSPoul-Henning Kamp TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link); 1535c7323482SBill Paul ifp->if_ioctl(ifp, SIOCDELMULTI, 0); 15361158dfb7SGarrett Wollman splx(s); 15371158dfb7SGarrett Wollman free(ifma->ifma_addr, M_IFMADDR); 15381158dfb7SGarrett Wollman free(sa, M_IFMADDR); 15391158dfb7SGarrett Wollman free(ifma, M_IFMADDR); 15401158dfb7SGarrett Wollman 15411158dfb7SGarrett Wollman return 0; 15421158dfb7SGarrett Wollman } 15431158dfb7SGarrett Wollman 154466ce51ceSArchie Cobbs /* 154566ce51ceSArchie Cobbs * Set the link layer address on an interface. 154666ce51ceSArchie Cobbs * 154766ce51ceSArchie Cobbs * At this time we only support certain types of interfaces, 154866ce51ceSArchie Cobbs * and we don't allow the length of the address to change. 154966ce51ceSArchie Cobbs */ 155066ce51ceSArchie Cobbs int 155166ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 155266ce51ceSArchie Cobbs { 155366ce51ceSArchie Cobbs struct sockaddr_dl *sdl; 155466ce51ceSArchie Cobbs struct ifaddr *ifa; 155566ce51ceSArchie Cobbs 155666ce51ceSArchie Cobbs ifa = ifnet_addrs[ifp->if_index - 1]; 155766ce51ceSArchie Cobbs if (ifa == NULL) 155866ce51ceSArchie Cobbs return (EINVAL); 155966ce51ceSArchie Cobbs sdl = (struct sockaddr_dl *)ifa->ifa_addr; 156066ce51ceSArchie Cobbs if (sdl == NULL) 156166ce51ceSArchie Cobbs return (EINVAL); 156266ce51ceSArchie Cobbs if (len != sdl->sdl_alen) /* don't allow length to change */ 156366ce51ceSArchie Cobbs return (EINVAL); 156466ce51ceSArchie Cobbs switch (ifp->if_type) { 156566ce51ceSArchie Cobbs case IFT_ETHER: /* these types use struct arpcom */ 156666ce51ceSArchie Cobbs case IFT_FDDI: 156766ce51ceSArchie Cobbs case IFT_XETHER: 156866ce51ceSArchie Cobbs case IFT_ISO88025: 1569b7bffa71SYaroslav Tykhiy case IFT_L2VLAN: 157066ce51ceSArchie Cobbs bcopy(lladdr, ((struct arpcom *)ifp->if_softc)->ac_enaddr, len); 157166ce51ceSArchie Cobbs bcopy(lladdr, LLADDR(sdl), len); 157266ce51ceSArchie Cobbs break; 157366ce51ceSArchie Cobbs default: 157466ce51ceSArchie Cobbs return (ENODEV); 157566ce51ceSArchie Cobbs } 157666ce51ceSArchie Cobbs /* 157766ce51ceSArchie Cobbs * If the interface is already up, we need 157866ce51ceSArchie Cobbs * to re-init it in order to reprogram its 157966ce51ceSArchie Cobbs * address filter. 158066ce51ceSArchie Cobbs */ 158166ce51ceSArchie Cobbs if ((ifp->if_flags & IFF_UP) != 0) { 158266ce51ceSArchie Cobbs ifp->if_flags &= ~IFF_UP; 158366ce51ceSArchie Cobbs (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL); 158466ce51ceSArchie Cobbs ifp->if_flags |= IFF_UP; 158566ce51ceSArchie Cobbs (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, NULL); 158666ce51ceSArchie Cobbs } 158766ce51ceSArchie Cobbs return (0); 158866ce51ceSArchie Cobbs } 158966ce51ceSArchie Cobbs 1590373f88edSGarrett Wollman struct ifmultiaddr * 1591373f88edSGarrett Wollman ifmaof_ifpforaddr(sa, ifp) 1592373f88edSGarrett Wollman struct sockaddr *sa; 1593373f88edSGarrett Wollman struct ifnet *ifp; 1594373f88edSGarrett Wollman { 1595373f88edSGarrett Wollman struct ifmultiaddr *ifma; 1596373f88edSGarrett Wollman 15976817526dSPoul-Henning Kamp TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 1598373f88edSGarrett Wollman if (equal(ifma->ifma_addr, sa)) 1599373f88edSGarrett Wollman break; 1600373f88edSGarrett Wollman 1601373f88edSGarrett Wollman return ifma; 1602373f88edSGarrett Wollman } 1603373f88edSGarrett Wollman 1604602d513cSGarrett Wollman SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers"); 16052c37256eSGarrett Wollman SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management"); 1606