1c398230bSWarner Losh /*- 251369649SPedro F. Giffuni * SPDX-License-Identifier: BSD-3-Clause 351369649SPedro F. Giffuni * 4df8bae1dSRodney W. Grimes * Copyright (c) 1980, 1986, 1993 5df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 6df8bae1dSRodney W. Grimes * 7df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 8df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 9df8bae1dSRodney W. Grimes * are met: 10df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 12df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 13df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 14df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 15fbbd9655SWarner Losh * 3. Neither the name of the University nor the names of its contributors 16df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 17df8bae1dSRodney W. Grimes * without specific prior written permission. 18df8bae1dSRodney W. Grimes * 19df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29df8bae1dSRodney W. Grimes * SUCH DAMAGE. 30df8bae1dSRodney W. Grimes * 3166afbd68SRuslan Ermilov * @(#)if.c 8.5 (Berkeley) 1/9/95 32c3aac50fSPeter Wemm * $FreeBSD$ 33df8bae1dSRodney W. Grimes */ 34df8bae1dSRodney W. Grimes 353232273fSBjoern A. Zeeb #include "opt_bpf.h" 36cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h" 370d0f9d1eSYoshinobu Inoue #include "opt_inet.h" 385591b823SEivind Eklund 39df8bae1dSRodney W. Grimes #include <sys/param.h> 4027457983SMark Johnston #include <sys/capsicum.h> 41f13ad206SJonathan Lemon #include <sys/conf.h> 42e2e050c8SConrad Meyer #include <sys/eventhandler.h> 434d1d4912SBruce Evans #include <sys/malloc.h> 447687707dSAndrew Gallatin #include <sys/domainset.h> 454dcf2bbbSBrooks Davis #include <sys/sbuf.h> 46d2b4566aSJonathan Lemon #include <sys/bus.h> 47d7c5a620SMatt Macy #include <sys/epoch.h> 48df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 49df8bae1dSRodney W. Grimes #include <sys/systm.h> 50acd3428bSRobert Watson #include <sys/priv.h> 51df8bae1dSRodney W. Grimes #include <sys/proc.h> 52df8bae1dSRodney W. Grimes #include <sys/socket.h> 53df8bae1dSRodney W. Grimes #include <sys/socketvar.h> 54df8bae1dSRodney W. Grimes #include <sys/protosw.h> 55df8bae1dSRodney W. Grimes #include <sys/kernel.h> 56653735c4SBjoern A. Zeeb #include <sys/lock.h> 5727d37320SRobert Watson #include <sys/refcount.h> 5821ca7b57SMarko Zec #include <sys/module.h> 59653735c4SBjoern A. Zeeb #include <sys/rwlock.h> 6051a53488SBruce Evans #include <sys/sockio.h> 61963e4c2aSGarrett Wollman #include <sys/syslog.h> 62602d513cSGarrett Wollman #include <sys/sysctl.h> 6386d2ef16SBrooks Davis #include <sys/sysent.h> 64af5e59bfSRobert Watson #include <sys/taskqueue.h> 6531b1bfe1SHajimu UMEMOTO #include <sys/domain.h> 6691421ba2SRobert Watson #include <sys/jail.h> 6735fd7bc0SBjoern A. Zeeb #include <sys/priv.h> 6835fd7bc0SBjoern A. Zeeb 69fa882e87SBrooks Davis #include <machine/stdarg.h> 706e6b3f7cSQing Li #include <vm/uma.h> 71df8bae1dSRodney W. Grimes 7262d76917SMarcel Moolenaar #include <net/bpf.h> 7362d76917SMarcel Moolenaar #include <net/ethernet.h> 74df8bae1dSRodney W. Grimes #include <net/if.h> 755a97c9d4SBjoern A. Zeeb #include <net/if_arp.h> 76f889d2efSBrooks Davis #include <net/if_clone.h> 77df8bae1dSRodney W. Grimes #include <net/if_dl.h> 7866ce51ceSArchie Cobbs #include <net/if_types.h> 7930aad87dSBrooks Davis #include <net/if_var.h> 8062d76917SMarcel Moolenaar #include <net/if_media.h> 8162d76917SMarcel Moolenaar #include <net/if_vlan_var.h> 829448326fSPoul-Henning Kamp #include <net/radix.h> 835500d3beSWarner Losh #include <net/route.h> 84e1c05fd2SAlexander V. Chernikov #include <net/route/route_ctl.h> 854b79449eSBjoern A. Zeeb #include <net/vnet.h> 86df8bae1dSRodney W. Grimes 870d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6) 88209579aeSRick Macklem #include <net/ethernet.h> 8982cd038dSYoshinobu Inoue #include <netinet/in.h> 900d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h> 913c914c54SAndre Oppermann #include <netinet/ip.h> 929963e8a5SWill Andrews #include <netinet/ip_carp.h> 933c914c54SAndre Oppermann #ifdef INET 947790c8c1SConrad Meyer #include <net/debugnet.h> 953c914c54SAndre Oppermann #include <netinet/if_ether.h> 963c914c54SAndre Oppermann #endif /* INET */ 973411310dSYoshinobu Inoue #ifdef INET6 98978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h> 99978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h> 1003c914c54SAndre Oppermann #endif /* INET6 */ 1013c914c54SAndre Oppermann #endif /* INET || INET6 */ 10282cd038dSYoshinobu Inoue 103aed55708SRobert Watson #include <security/mac/mac_framework.h> 104aed55708SRobert Watson 1058708f1bdSBrooks Davis /* 1068708f1bdSBrooks Davis * Consumers of struct ifreq such as tcpdump assume no pad between ifr_name 1078708f1bdSBrooks Davis * and ifr_ifru when it is used in SIOCGIFCONF. 1088708f1bdSBrooks Davis */ 1098708f1bdSBrooks Davis _Static_assert(sizeof(((struct ifreq *)0)->ifr_name) == 1108708f1bdSBrooks Davis offsetof(struct ifreq, ifr_ifru), "gap between ifr_name and ifr_ifru"); 1118708f1bdSBrooks Davis 112d71e30deSMatt Macy __read_mostly epoch_t net_epoch_preempt; 1139af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32 1149af74f3dSSergey Kandaurov #include <sys/mount.h> 1159af74f3dSSergey Kandaurov #include <compat/freebsd32/freebsd32.h> 11686d2ef16SBrooks Davis 11786d2ef16SBrooks Davis struct ifreq_buffer32 { 11886d2ef16SBrooks Davis uint32_t length; /* (size_t) */ 11986d2ef16SBrooks Davis uint32_t buffer; /* (void *) */ 12086d2ef16SBrooks Davis }; 12186d2ef16SBrooks Davis 12286d2ef16SBrooks Davis /* 12386d2ef16SBrooks Davis * Interface request structure used for socket 12486d2ef16SBrooks Davis * ioctl's. All interface ioctl's must have parameter 12586d2ef16SBrooks Davis * definitions which begin with ifr_name. The 12686d2ef16SBrooks Davis * remainder may be interface specific. 12786d2ef16SBrooks Davis */ 12886d2ef16SBrooks Davis struct ifreq32 { 12986d2ef16SBrooks Davis char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */ 13086d2ef16SBrooks Davis union { 13186d2ef16SBrooks Davis struct sockaddr ifru_addr; 13286d2ef16SBrooks Davis struct sockaddr ifru_dstaddr; 13386d2ef16SBrooks Davis struct sockaddr ifru_broadaddr; 13486d2ef16SBrooks Davis struct ifreq_buffer32 ifru_buffer; 13586d2ef16SBrooks Davis short ifru_flags[2]; 13686d2ef16SBrooks Davis short ifru_index; 13786d2ef16SBrooks Davis int ifru_jid; 13886d2ef16SBrooks Davis int ifru_metric; 13986d2ef16SBrooks Davis int ifru_mtu; 14086d2ef16SBrooks Davis int ifru_phys; 14186d2ef16SBrooks Davis int ifru_media; 14286d2ef16SBrooks Davis uint32_t ifru_data; 14386d2ef16SBrooks Davis int ifru_cap[2]; 14486d2ef16SBrooks Davis u_int ifru_fib; 14586d2ef16SBrooks Davis u_char ifru_vlan_pcp; 14686d2ef16SBrooks Davis } ifr_ifru; 14786d2ef16SBrooks Davis }; 14886d2ef16SBrooks Davis CTASSERT(sizeof(struct ifreq) == sizeof(struct ifreq32)); 14986d2ef16SBrooks Davis CTASSERT(__offsetof(struct ifreq, ifr_ifru) == 15086d2ef16SBrooks Davis __offsetof(struct ifreq32, ifr_ifru)); 151756181b8SBrooks Davis 152*d61d98f4SJohn Baldwin struct ifdrv32 { 153*d61d98f4SJohn Baldwin char ifd_name[IFNAMSIZ]; 154*d61d98f4SJohn Baldwin uint32_t ifd_cmd; 155*d61d98f4SJohn Baldwin uint32_t ifd_len; 156*d61d98f4SJohn Baldwin uint32_t ifd_data; 157*d61d98f4SJohn Baldwin }; 158*d61d98f4SJohn Baldwin #define SIOCSDRVSPEC32 _IOC_NEWTYPE(SIOCSDRVSPEC, struct ifdrv32) 159*d61d98f4SJohn Baldwin #define SIOCGDRVSPEC32 _IOC_NEWTYPE(SIOCGDRVSPEC, struct ifdrv32) 160*d61d98f4SJohn Baldwin 161756181b8SBrooks Davis struct ifgroupreq32 { 162756181b8SBrooks Davis char ifgr_name[IFNAMSIZ]; 163756181b8SBrooks Davis u_int ifgr_len; 164756181b8SBrooks Davis union { 165756181b8SBrooks Davis char ifgru_group[IFNAMSIZ]; 166756181b8SBrooks Davis uint32_t ifgru_groups; 167756181b8SBrooks Davis } ifgr_ifgru; 168756181b8SBrooks Davis }; 1693edb7f4eSBrooks Davis 1703edb7f4eSBrooks Davis struct ifmediareq32 { 1713edb7f4eSBrooks Davis char ifm_name[IFNAMSIZ]; 1723edb7f4eSBrooks Davis int ifm_current; 1733edb7f4eSBrooks Davis int ifm_mask; 1743edb7f4eSBrooks Davis int ifm_status; 1753edb7f4eSBrooks Davis int ifm_active; 1763edb7f4eSBrooks Davis int ifm_count; 1773edb7f4eSBrooks Davis uint32_t ifm_ulist; /* (int *) */ 1783edb7f4eSBrooks Davis }; 1793edb7f4eSBrooks Davis #define SIOCGIFMEDIA32 _IOC_NEWTYPE(SIOCGIFMEDIA, struct ifmediareq32) 1803edb7f4eSBrooks Davis #define SIOCGIFXMEDIA32 _IOC_NEWTYPE(SIOCGIFXMEDIA, struct ifmediareq32) 1813edb7f4eSBrooks Davis 182756181b8SBrooks Davis #define _CASE_IOC_IFGROUPREQ_32(cmd) \ 183bc6f170eSBrooks Davis _IOC_NEWTYPE((cmd), struct ifgroupreq32): case 1843edb7f4eSBrooks Davis #else /* !COMPAT_FREEBSD32 */ 185756181b8SBrooks Davis #define _CASE_IOC_IFGROUPREQ_32(cmd) 1863edb7f4eSBrooks Davis #endif /* !COMPAT_FREEBSD32 */ 187756181b8SBrooks Davis 188756181b8SBrooks Davis #define CASE_IOC_IFGROUPREQ(cmd) \ 189756181b8SBrooks Davis _CASE_IOC_IFGROUPREQ_32(cmd) \ 190bc6f170eSBrooks Davis (cmd) 1919af74f3dSSergey Kandaurov 19286d2ef16SBrooks Davis union ifreq_union { 19386d2ef16SBrooks Davis struct ifreq ifr; 19486d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32 19586d2ef16SBrooks Davis struct ifreq32 ifr32; 19686d2ef16SBrooks Davis #endif 19786d2ef16SBrooks Davis }; 19886d2ef16SBrooks Davis 199756181b8SBrooks Davis union ifgroupreq_union { 200756181b8SBrooks Davis struct ifgroupreq ifgr; 201756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32 202756181b8SBrooks Davis struct ifgroupreq32 ifgr32; 203756181b8SBrooks Davis #endif 204756181b8SBrooks Davis }; 205756181b8SBrooks Davis 2067029da5cSPawel Biernacki SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 2077029da5cSPawel Biernacki "Link layers"); 2087029da5cSPawel Biernacki SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 2097029da5cSPawel Biernacki "Generic link-management"); 2105515c2e7SGleb Smirnoff 211f88910cdSMatthew D Fleming SYSCTL_INT(_net_link, OID_AUTO, ifqmaxlen, CTLFLAG_RDTUN, 212e50d35e6SMaxim Sobolev &ifqmaxlen, 0, "max send queue size"); 213e50d35e6SMaxim Sobolev 2145515c2e7SGleb Smirnoff /* Log link state change events */ 2155515c2e7SGleb Smirnoff static int log_link_state_change = 1; 2165515c2e7SGleb Smirnoff 2175515c2e7SGleb Smirnoff SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW, 2185515c2e7SGleb Smirnoff &log_link_state_change, 0, 2195515c2e7SGleb Smirnoff "log interface link state change events"); 2205515c2e7SGleb Smirnoff 2216d07c157SNick Hibma /* Log promiscuous mode change events */ 2226d07c157SNick Hibma static int log_promisc_mode_change = 1; 2236d07c157SNick Hibma 224dbd2ee46SNick Hibma SYSCTL_INT(_net_link, OID_AUTO, log_promisc_mode_change, CTLFLAG_RDTUN, 2256d07c157SNick Hibma &log_promisc_mode_change, 1, 2266d07c157SNick Hibma "log promiscuous mode change events"); 2276d07c157SNick Hibma 228215940b3SXin LI /* Interface description */ 229215940b3SXin LI static unsigned int ifdescr_maxlen = 1024; 230215940b3SXin LI SYSCTL_UINT(_net, OID_AUTO, ifdescr_maxlen, CTLFLAG_RW, 231215940b3SXin LI &ifdescr_maxlen, 0, 232215940b3SXin LI "administrative maximum length for interface description"); 233215940b3SXin LI 234d745c852SEd Schouten static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions"); 235215940b3SXin LI 236215940b3SXin LI /* global sx for non-critical path ifdescr */ 237215940b3SXin LI static struct sx ifdescr_sx; 238215940b3SXin LI SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr"); 239215940b3SXin LI 2401c7899c7SGleb Smirnoff void (*ng_ether_link_state_p)(struct ifnet *ifp, int state); 241d6e82913SSteven Hartland void (*lagg_linkstate_p)(struct ifnet *ifp, int state); 2429963e8a5SWill Andrews /* These are external hooks for CARP. */ 24354bfbd51SWill Andrews void (*carp_linkstate_p)(struct ifnet *ifp); 244f08535f8SGleb Smirnoff void (*carp_demote_adj_p)(int, char *); 24524421c1cSGleb Smirnoff int (*carp_master_p)(struct ifaddr *); 2469963e8a5SWill Andrews #if defined(INET) || defined(INET6) 24708b68b0eSGleb Smirnoff int (*carp_forus_p)(struct ifnet *ifp, u_char *dhost); 2489963e8a5SWill Andrews int (*carp_output_p)(struct ifnet *ifp, struct mbuf *m, 24947e8d432SGleb Smirnoff const struct sockaddr *sa); 25008b68b0eSGleb Smirnoff int (*carp_ioctl_p)(struct ifreq *, u_long, struct thread *); 25108b68b0eSGleb Smirnoff int (*carp_attach_p)(struct ifaddr *, int); 252338e227aSLuiz Otavio O Souza void (*carp_detach_p)(struct ifaddr *, bool); 2539963e8a5SWill Andrews #endif 2549963e8a5SWill Andrews #ifdef INET 25508b68b0eSGleb Smirnoff int (*carp_iamatch_p)(struct ifaddr *, uint8_t **); 2569963e8a5SWill Andrews #endif 2579963e8a5SWill Andrews #ifdef INET6 2589963e8a5SWill Andrews struct ifaddr *(*carp_iamatch6_p)(struct ifnet *ifp, struct in6_addr *taddr6); 2599963e8a5SWill Andrews caddr_t (*carp_macmatch6_p)(struct ifnet *ifp, struct mbuf *m, 2609963e8a5SWill Andrews const struct in6_addr *taddr); 2619963e8a5SWill Andrews #endif 2621c7899c7SGleb Smirnoff 2634cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL; 2644cb655c0SMax Laier 265ec002feeSBruce M Simpson /* 266ec002feeSBruce M Simpson * XXX: Style; these should be sorted alphabetically, and unprototyped 267ec002feeSBruce M Simpson * static functions should be prototyped. Currently they are sorted by 268ec002feeSBruce M Simpson * declaration order. 269ec002feeSBruce M Simpson */ 27031b1bfe1SHajimu UMEMOTO static void if_attachdomain(void *); 27131b1bfe1SHajimu UMEMOTO static void if_attachdomain1(struct ifnet *); 2720b59d917SJonathan Lemon static int ifconf(u_long, caddr_t); 2734f6c66ccSMatt Macy static void *if_grow(void); 274b57d9721SAndrey V. Elsukov static void if_input_default(struct ifnet *, struct mbuf *); 2754fb3a820SAlexander V. Chernikov static int if_requestencap_default(struct ifnet *, struct if_encap_req *); 2768614fb12SMax Laier static void if_route(struct ifnet *, int flag, int fam); 2771a3b6859SYaroslav Tykhiy static int if_setflag(struct ifnet *, int, int, int *, int); 278db7f0b97SKip Macy static int if_transmit(struct ifnet *ifp, struct mbuf *m); 2798614fb12SMax Laier static void if_unroute(struct ifnet *, int flag, int fam); 280ec002feeSBruce M Simpson static int if_delmulti_locked(struct ifnet *, struct ifmultiaddr *, int); 28168a3482fSGleb Smirnoff static void do_link_state_change(void *, int); 2820dad3f0eSMax Laier static int if_getgroup(struct ifgroupreq *, struct ifnet *); 2830dad3f0eSMax Laier static int if_getgroupmembers(struct ifgroupreq *); 2848623f9fdSMax Laier static void if_delgroups(struct ifnet *); 285c92a456bSHiroki Sato static void if_attach_internal(struct ifnet *, int, struct if_clone *); 286f501e6f1SBjoern A. Zeeb static int if_detach_internal(struct ifnet *, int, struct if_clone **); 2870839aa5cSGleb Smirnoff static void if_siocaddmulti(void *, int); 288a779388fSKristof Provost static void if_link_ifnet(struct ifnet *); 289a779388fSKristof Provost static bool if_unlink_ifnet(struct ifnet *, bool); 290ad4e9116SBjoern A. Zeeb #ifdef VIMAGE 291c7bab2a7SKyle Evans static int if_vmove(struct ifnet *, struct vnet *); 292ad4e9116SBjoern A. Zeeb #endif 293db7f0b97SKip Macy 29482cd038dSYoshinobu Inoue #ifdef INET6 29582cd038dSYoshinobu Inoue /* 29682cd038dSYoshinobu Inoue * XXX: declare here to avoid to include many inet6 related files.. 29782cd038dSYoshinobu Inoue * should be more generalized? 29882cd038dSYoshinobu Inoue */ 299929ddbbbSAlfred Perlstein extern void nd6_setmtu(struct ifnet *); 30082cd038dSYoshinobu Inoue #endif 30182cd038dSYoshinobu Inoue 302ef91a976SAndrey V. Elsukov /* ipsec helper hooks */ 303ef91a976SAndrey V. Elsukov VNET_DEFINE(struct hhook_head *, ipsec_hhh_in[HHOOK_IPSEC_COUNT]); 304ef91a976SAndrey V. Elsukov VNET_DEFINE(struct hhook_head *, ipsec_hhh_out[HHOOK_IPSEC_COUNT]); 305ef91a976SAndrey V. Elsukov 30682cea7e6SBjoern A. Zeeb VNET_DEFINE(int, if_index); 30782cea7e6SBjoern A. Zeeb int ifqmaxlen = IFQ_MAXLEN; 308eddfbb76SRobert Watson VNET_DEFINE(struct ifnethead, ifnet); /* depend on static init XXX */ 309eddfbb76SRobert Watson VNET_DEFINE(struct ifgrouphead, ifg_head); 31082cea7e6SBjoern A. Zeeb 3115f901c92SAndrew Turner VNET_DEFINE_STATIC(int, if_indexlim) = 8; 312eddfbb76SRobert Watson 31377dfcdc4SRobert Watson /* Table of ifnet by index. */ 314e6abef09SGleb Smirnoff VNET_DEFINE(struct ifnet **, ifindex_table); 315eddfbb76SRobert Watson 3161e77c105SRobert Watson #define V_if_indexlim VNET(if_indexlim) 3171e77c105SRobert Watson #define V_ifindex_table VNET(ifindex_table) 31844e33a07SMarko Zec 31977dfcdc4SRobert Watson /* 32077dfcdc4SRobert Watson * The global network interface list (V_ifnet) and related state (such as 321a60100fdSKristof Provost * if_index, if_indexlim, and ifindex_table) are protected by an sxlock. 322a60100fdSKristof Provost * This may be acquired to stabilise the list, or we may rely on NET_EPOCH. 32377dfcdc4SRobert Watson */ 32477dfcdc4SRobert Watson struct sx ifnet_sxlock; 3254ea05db8SGleb Smirnoff SX_SYSINIT_FLAGS(ifnet_sx, &ifnet_sxlock, "ifnet_sx", SX_RECURSE); 32677dfcdc4SRobert Watson 327e133271fSKristof Provost struct sx ifnet_detach_sxlock; 3286d2a10d9SKristof Provost SX_SYSINIT_FLAGS(ifnet_detach, &ifnet_detach_sxlock, "ifnet_detach_sx", 3296d2a10d9SKristof Provost SX_RECURSE); 330e133271fSKristof Provost 331ed2dabfcSRobert Watson /* 332ed2dabfcSRobert Watson * The allocation of network interfaces is a rather non-atomic affair; we 333ed2dabfcSRobert Watson * need to select an index before we are ready to expose the interface for 334ed2dabfcSRobert Watson * use, so will use this pointer value to indicate reservation. 335ed2dabfcSRobert Watson */ 336ed2dabfcSRobert Watson #define IFNET_HOLD (void *)(uintptr_t)(-1) 337ed2dabfcSRobert Watson 33810108cb6SBjoern A. Zeeb #ifdef VIMAGE 33910108cb6SBjoern A. Zeeb #define VNET_IS_SHUTTING_DOWN(_vnet) \ 34010108cb6SBjoern A. Zeeb ((_vnet)->vnet_shutdown && (_vnet)->vnet_state < SI_SUB_VNET_DONE) 34110108cb6SBjoern A. Zeeb #endif 34210108cb6SBjoern A. Zeeb 343fc74a9f9SBrooks Davis static if_com_alloc_t *if_com_alloc[256]; 344fc74a9f9SBrooks Davis static if_com_free_t *if_com_free[256]; 3450b59d917SJonathan Lemon 346d745c852SEd Schouten static MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals"); 3470b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address"); 3480b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address"); 34930aad87dSBrooks Davis 35021ca7b57SMarko Zec struct ifnet * 351d24c444cSKip Macy ifnet_byindex(u_short idx) 352d24c444cSKip Macy { 353d24c444cSKip Macy struct ifnet *ifp; 354d24c444cSKip Macy 355270b83b9SHans Petter Selasky if (__predict_false(idx > V_if_index)) 356270b83b9SHans Petter Selasky return (NULL); 357270b83b9SHans Petter Selasky 358270b83b9SHans Petter Selasky ifp = *(struct ifnet * const volatile *)(V_ifindex_table + idx); 359270b83b9SHans Petter Selasky return (__predict_false(ifp == IFNET_HOLD) ? NULL : ifp); 36002f4879dSRobert Watson } 36102f4879dSRobert Watson 36227d37320SRobert Watson struct ifnet * 36327d37320SRobert Watson ifnet_byindex_ref(u_short idx) 36427d37320SRobert Watson { 36527d37320SRobert Watson struct ifnet *ifp; 36627d37320SRobert Watson 367b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 368b8a6e03fSGleb Smirnoff 369270b83b9SHans Petter Selasky ifp = ifnet_byindex(idx); 370b8a6e03fSGleb Smirnoff if (ifp == NULL || (ifp->if_flags & IFF_DYING)) 37127d37320SRobert Watson return (NULL); 3727563019bSAlexander V. Chernikov if (!if_try_ref(ifp)) 3737563019bSAlexander V. Chernikov return (NULL); 37427d37320SRobert Watson return (ifp); 37527d37320SRobert Watson } 37627d37320SRobert Watson 37761f6986bSRobert Watson /* 37861f6986bSRobert Watson * Allocate an ifindex array entry; return 0 on success or an error on 37961f6986bSRobert Watson * failure. 38061f6986bSRobert Watson */ 381f4507b71SGleb Smirnoff static u_short 3824f6c66ccSMatt Macy ifindex_alloc(void **old) 38361f6986bSRobert Watson { 38461f6986bSRobert Watson u_short idx; 38561f6986bSRobert Watson 38661f6986bSRobert Watson IFNET_WLOCK_ASSERT(); 38761f6986bSRobert Watson /* 388ed2dabfcSRobert Watson * Try to find an empty slot below V_if_index. If we fail, take the 38961f6986bSRobert Watson * next slot. 39061f6986bSRobert Watson */ 39161f6986bSRobert Watson for (idx = 1; idx <= V_if_index; idx++) { 392e6abef09SGleb Smirnoff if (V_ifindex_table[idx] == NULL) 39361f6986bSRobert Watson break; 39461f6986bSRobert Watson } 39561f6986bSRobert Watson 39661f6986bSRobert Watson /* Catch if_index overflow. */ 3975f3b301aSJohn Baldwin if (idx >= V_if_indexlim) { 3984f6c66ccSMatt Macy *old = if_grow(); 3994f6c66ccSMatt Macy return (USHRT_MAX); 4005f3b301aSJohn Baldwin } 40161f6986bSRobert Watson if (idx > V_if_index) 40261f6986bSRobert Watson V_if_index = idx; 403f4507b71SGleb Smirnoff return (idx); 40461f6986bSRobert Watson } 40561f6986bSRobert Watson 406e0c14af9SMarko Zec static void 407ed2dabfcSRobert Watson ifindex_free_locked(u_short idx) 408ed2dabfcSRobert Watson { 409ed2dabfcSRobert Watson 410ed2dabfcSRobert Watson IFNET_WLOCK_ASSERT(); 411ed2dabfcSRobert Watson 412e6abef09SGleb Smirnoff V_ifindex_table[idx] = NULL; 413ed2dabfcSRobert Watson while (V_if_index > 0 && 414e6abef09SGleb Smirnoff V_ifindex_table[V_if_index] == NULL) 415ed2dabfcSRobert Watson V_if_index--; 416ed2dabfcSRobert Watson } 417ed2dabfcSRobert Watson 418ed2dabfcSRobert Watson static void 419ed2dabfcSRobert Watson ifindex_free(u_short idx) 420ed2dabfcSRobert Watson { 421ed2dabfcSRobert Watson 422ed2dabfcSRobert Watson IFNET_WLOCK(); 423ed2dabfcSRobert Watson ifindex_free_locked(idx); 424ed2dabfcSRobert Watson IFNET_WUNLOCK(); 425ed2dabfcSRobert Watson } 426ed2dabfcSRobert Watson 427ed2dabfcSRobert Watson static void 42877dfcdc4SRobert Watson ifnet_setbyindex(u_short idx, struct ifnet *ifp) 42977dfcdc4SRobert Watson { 43077dfcdc4SRobert Watson 4314f6c66ccSMatt Macy V_ifindex_table[idx] = ifp; 43277dfcdc4SRobert Watson } 43377dfcdc4SRobert Watson 43402f4879dSRobert Watson struct ifaddr * 43502f4879dSRobert Watson ifaddr_byindex(u_short idx) 43602f4879dSRobert Watson { 43722a93840SMarko Zec struct ifnet *ifp; 43822a93840SMarko Zec struct ifaddr *ifa = NULL; 43902f4879dSRobert Watson 440b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 441b8a6e03fSGleb Smirnoff 442270b83b9SHans Petter Selasky ifp = ifnet_byindex(idx); 44322a93840SMarko Zec if (ifp != NULL && (ifa = ifp->if_addr) != NULL) 4448c0fec80SRobert Watson ifa_ref(ifa); 44502f4879dSRobert Watson return (ifa); 44602f4879dSRobert Watson } 44702f4879dSRobert Watson 448df8bae1dSRodney W. Grimes /* 449df8bae1dSRodney W. Grimes * Network interface utility routines. 450df8bae1dSRodney W. Grimes * 451df8bae1dSRodney W. Grimes * Routines with ifa_ifwith* names take sockaddr *'s as 452df8bae1dSRodney W. Grimes * parameters. 453df8bae1dSRodney W. Grimes */ 454a45cbf12SBrooks Davis 455f9132cebSJonathan Lemon static void 456d0728d71SRobert Watson vnet_if_init(const void *unused __unused) 4571ed81b73SMarko Zec { 4584f6c66ccSMatt Macy void *old; 45944e33a07SMarko Zec 4604f6c66ccSMatt Macy CK_STAILQ_INIT(&V_ifnet); 4614f6c66ccSMatt Macy CK_STAILQ_INIT(&V_ifg_head); 4625f3b301aSJohn Baldwin IFNET_WLOCK(); 4634f6c66ccSMatt Macy old = if_grow(); /* create initial table */ 4645f3b301aSJohn Baldwin IFNET_WUNLOCK(); 4654f6c66ccSMatt Macy epoch_wait_preempt(net_epoch_preempt); 4664f6c66ccSMatt Macy free(old, M_IFNET); 467d0728d71SRobert Watson vnet_if_clone_init(); 468f9132cebSJonathan Lemon } 4695f3b301aSJohn Baldwin VNET_SYSINIT(vnet_if_init, SI_SUB_INIT_IF, SI_ORDER_SECOND, vnet_if_init, 470d0728d71SRobert Watson NULL); 471d0728d71SRobert Watson 472bc29160dSMarko Zec #ifdef VIMAGE 473d0728d71SRobert Watson static void 474d0728d71SRobert Watson vnet_if_uninit(const void *unused __unused) 475bc29160dSMarko Zec { 476bc29160dSMarko Zec 4774f6c66ccSMatt Macy VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifnet), ("%s:%d tailq &V_ifnet=%p " 4780028e524SBjoern A. Zeeb "not empty", __func__, __LINE__, &V_ifnet)); 4794f6c66ccSMatt Macy VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifg_head), ("%s:%d tailq &V_ifg_head=%p " 4800028e524SBjoern A. Zeeb "not empty", __func__, __LINE__, &V_ifg_head)); 481bc29160dSMarko Zec 482bc29160dSMarko Zec free((caddr_t)V_ifindex_table, M_IFNET); 483bc29160dSMarko Zec } 484d0728d71SRobert Watson VNET_SYSUNINIT(vnet_if_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST, 485d0728d71SRobert Watson vnet_if_uninit, NULL); 486bca0e1d2SKristof Provost #endif 487ad4e9116SBjoern A. Zeeb 488ad4e9116SBjoern A. Zeeb static void 489a779388fSKristof Provost if_link_ifnet(struct ifnet *ifp) 490a779388fSKristof Provost { 491a779388fSKristof Provost 492a779388fSKristof Provost IFNET_WLOCK(); 493a779388fSKristof Provost CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link); 494a779388fSKristof Provost #ifdef VIMAGE 495a779388fSKristof Provost curvnet->vnet_ifcnt++; 496a779388fSKristof Provost #endif 497a779388fSKristof Provost IFNET_WUNLOCK(); 498a779388fSKristof Provost } 499a779388fSKristof Provost 500a779388fSKristof Provost static bool 501a779388fSKristof Provost if_unlink_ifnet(struct ifnet *ifp, bool vmove) 502a779388fSKristof Provost { 503a779388fSKristof Provost struct ifnet *iter; 504a779388fSKristof Provost int found = 0; 505a779388fSKristof Provost 506a779388fSKristof Provost IFNET_WLOCK(); 507a779388fSKristof Provost CK_STAILQ_FOREACH(iter, &V_ifnet, if_link) 508a779388fSKristof Provost if (iter == ifp) { 509a779388fSKristof Provost CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link); 510a779388fSKristof Provost if (!vmove) 511a779388fSKristof Provost ifp->if_flags |= IFF_DYING; 512a779388fSKristof Provost found = 1; 513a779388fSKristof Provost break; 514a779388fSKristof Provost } 515a779388fSKristof Provost #ifdef VIMAGE 516a779388fSKristof Provost curvnet->vnet_ifcnt--; 517a779388fSKristof Provost #endif 518a779388fSKristof Provost IFNET_WUNLOCK(); 519a779388fSKristof Provost 520a779388fSKristof Provost return (found); 521a779388fSKristof Provost } 522a779388fSKristof Provost 523bca0e1d2SKristof Provost #ifdef VIMAGE 524a779388fSKristof Provost static void 525ad4e9116SBjoern A. Zeeb vnet_if_return(const void *unused __unused) 526ad4e9116SBjoern A. Zeeb { 527ad4e9116SBjoern A. Zeeb struct ifnet *ifp, *nifp; 528a779388fSKristof Provost struct ifnet **pending; 529a779388fSKristof Provost int found, i; 530a779388fSKristof Provost 531a779388fSKristof Provost i = 0; 532a779388fSKristof Provost 533a779388fSKristof Provost /* 534a779388fSKristof Provost * We need to protect our access to the V_ifnet tailq. Ordinarily we'd 535a779388fSKristof Provost * enter NET_EPOCH, but that's not possible, because if_vmove() calls 536a779388fSKristof Provost * if_detach_internal(), which waits for NET_EPOCH callbacks to 537a779388fSKristof Provost * complete. We can't do that from within NET_EPOCH. 538a779388fSKristof Provost * 539a779388fSKristof Provost * However, we can also use the IFNET_xLOCK, which is the V_ifnet 540a779388fSKristof Provost * read/write lock. We cannot hold the lock as we call if_vmove() 541a779388fSKristof Provost * though, as that presents LOR w.r.t ifnet_sx, in_multi_sx and iflib 542a779388fSKristof Provost * ctx lock. 543a779388fSKristof Provost */ 544a779388fSKristof Provost IFNET_WLOCK(); 545a779388fSKristof Provost 546a779388fSKristof Provost pending = malloc(sizeof(struct ifnet *) * curvnet->vnet_ifcnt, 547a779388fSKristof Provost M_IFNET, M_WAITOK | M_ZERO); 548ad4e9116SBjoern A. Zeeb 549ad4e9116SBjoern A. Zeeb /* Return all inherited interfaces to their parent vnets. */ 5504f6c66ccSMatt Macy CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) { 551a779388fSKristof Provost if (ifp->if_home_vnet != ifp->if_vnet) { 552a779388fSKristof Provost found = if_unlink_ifnet(ifp, true); 553a779388fSKristof Provost MPASS(found); 554a779388fSKristof Provost 555a779388fSKristof Provost pending[i++] = ifp; 556ad4e9116SBjoern A. Zeeb } 557ad4e9116SBjoern A. Zeeb } 558a779388fSKristof Provost IFNET_WUNLOCK(); 559a779388fSKristof Provost 560a779388fSKristof Provost for (int j = 0; j < i; j++) { 561a779388fSKristof Provost if_vmove(pending[j], pending[j]->if_home_vnet); 562a779388fSKristof Provost } 563a779388fSKristof Provost 564a779388fSKristof Provost free(pending, M_IFNET); 565a779388fSKristof Provost } 566ad4e9116SBjoern A. Zeeb VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY, 567ad4e9116SBjoern A. Zeeb vnet_if_return, NULL); 568bc29160dSMarko Zec #endif 569bc29160dSMarko Zec 5704f6c66ccSMatt Macy static void * 571f9132cebSJonathan Lemon if_grow(void) 572f9132cebSJonathan Lemon { 5735f3b301aSJohn Baldwin int oldlim; 574f9132cebSJonathan Lemon u_int n; 575e6abef09SGleb Smirnoff struct ifnet **e; 5764f6c66ccSMatt Macy void *old; 577f9132cebSJonathan Lemon 5784f6c66ccSMatt Macy old = NULL; 5795f3b301aSJohn Baldwin IFNET_WLOCK_ASSERT(); 5805f3b301aSJohn Baldwin oldlim = V_if_indexlim; 5815f3b301aSJohn Baldwin IFNET_WUNLOCK(); 5825f3b301aSJohn Baldwin n = (oldlim << 1) * sizeof(*e); 583fc74a9f9SBrooks Davis e = malloc(n, M_IFNET, M_WAITOK | M_ZERO); 5845f3b301aSJohn Baldwin IFNET_WLOCK(); 5855f3b301aSJohn Baldwin if (V_if_indexlim != oldlim) { 5865f3b301aSJohn Baldwin free(e, M_IFNET); 5874f6c66ccSMatt Macy return (NULL); 5885f3b301aSJohn Baldwin } 589603724d3SBjoern A. Zeeb if (V_ifindex_table != NULL) { 590603724d3SBjoern A. Zeeb memcpy((caddr_t)e, (caddr_t)V_ifindex_table, n/2); 5914f6c66ccSMatt Macy old = V_ifindex_table; 592f9132cebSJonathan Lemon } 5935f3b301aSJohn Baldwin V_if_indexlim <<= 1; 594603724d3SBjoern A. Zeeb V_ifindex_table = e; 5954f6c66ccSMatt Macy return (old); 596f9132cebSJonathan Lemon } 597f9132cebSJonathan Lemon 598df8bae1dSRodney W. Grimes /* 599a45cbf12SBrooks Davis * Allocate a struct ifnet and an index for an interface. A layer 2 600a45cbf12SBrooks Davis * common structure will also be allocated if an allocation routine is 601a45cbf12SBrooks Davis * registered for the passed type. 602fc74a9f9SBrooks Davis */ 603fc74a9f9SBrooks Davis struct ifnet * 6047687707dSAndrew Gallatin if_alloc_domain(u_char type, int numa_domain) 605fc74a9f9SBrooks Davis { 606fc74a9f9SBrooks Davis struct ifnet *ifp; 60761f6986bSRobert Watson u_short idx; 6084f6c66ccSMatt Macy void *old; 609fc74a9f9SBrooks Davis 6107687707dSAndrew Gallatin KASSERT(numa_domain <= IF_NODOM, ("numa_domain too large")); 6117687707dSAndrew Gallatin if (numa_domain == IF_NODOM) 6127687707dSAndrew Gallatin ifp = malloc(sizeof(struct ifnet), M_IFNET, 6137687707dSAndrew Gallatin M_WAITOK | M_ZERO); 6147687707dSAndrew Gallatin else 6157687707dSAndrew Gallatin ifp = malloc_domainset(sizeof(struct ifnet), M_IFNET, 6167687707dSAndrew Gallatin DOMAINSET_PREF(numa_domain), M_WAITOK | M_ZERO); 6174f6c66ccSMatt Macy restart: 61861f6986bSRobert Watson IFNET_WLOCK(); 6194f6c66ccSMatt Macy idx = ifindex_alloc(&old); 6204f6c66ccSMatt Macy if (__predict_false(idx == USHRT_MAX)) { 6214f6c66ccSMatt Macy IFNET_WUNLOCK(); 6224f6c66ccSMatt Macy epoch_wait_preempt(net_epoch_preempt); 6234f6c66ccSMatt Macy free(old, M_IFNET); 6244f6c66ccSMatt Macy goto restart; 6254f6c66ccSMatt Macy } 6264f6c66ccSMatt Macy ifnet_setbyindex(idx, IFNET_HOLD); 62761f6986bSRobert Watson IFNET_WUNLOCK(); 62861f6986bSRobert Watson ifp->if_index = idx; 629fc74a9f9SBrooks Davis ifp->if_type = type; 63027d37320SRobert Watson ifp->if_alloctype = type; 6317687707dSAndrew Gallatin ifp->if_numa_domain = numa_domain; 632a29c7aebSBjoern A. Zeeb #ifdef VIMAGE 633a29c7aebSBjoern A. Zeeb ifp->if_vnet = curvnet; 634a29c7aebSBjoern A. Zeeb #endif 635fc74a9f9SBrooks Davis if (if_com_alloc[type] != NULL) { 636fc74a9f9SBrooks Davis ifp->if_l2com = if_com_alloc[type](type, ifp); 63728ef2db4SBrooks Davis if (ifp->if_l2com == NULL) { 638fc74a9f9SBrooks Davis free(ifp, M_IFNET); 639ed2dabfcSRobert Watson ifindex_free(idx); 64028ef2db4SBrooks Davis return (NULL); 64128ef2db4SBrooks Davis } 642fc74a9f9SBrooks Davis } 64327d37320SRobert Watson 64427d37320SRobert Watson IF_ADDR_LOCK_INIT(ifp); 645d6f157eaSRobert Watson TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp); 6460839aa5cSGleb Smirnoff TASK_INIT(&ifp->if_addmultitask, 0, if_siocaddmulti, ifp); 647d6f157eaSRobert Watson ifp->if_afdata_initialized = 0; 648e0c14af9SMarko Zec IF_AFDATA_LOCK_INIT(ifp); 649d7c5a620SMatt Macy CK_STAILQ_INIT(&ifp->if_addrhead); 650d7c5a620SMatt Macy CK_STAILQ_INIT(&ifp->if_multiaddrs); 6514f6c66ccSMatt Macy CK_STAILQ_INIT(&ifp->if_groups); 652d6f157eaSRobert Watson #ifdef MAC 653d6f157eaSRobert Watson mac_ifnet_init(ifp); 654d6f157eaSRobert Watson #endif 655d659538fSSam Leffler ifq_init(&ifp->if_snd, ifp); 656d6f157eaSRobert Watson 65727d37320SRobert Watson refcount_init(&ifp->if_refcount, 1); /* Index reference. */ 658112f50ffSGleb Smirnoff for (int i = 0; i < IFCOUNTERS; i++) 659112f50ffSGleb Smirnoff ifp->if_counters[i] = counter_u64_alloc(M_WAITOK); 66061dc4344SAndrey V. Elsukov ifp->if_get_counter = if_get_counter_default; 661f1379734SKonstantin Belousov ifp->if_pcp = IFNET_PCP_NONE; 66261dc4344SAndrey V. Elsukov ifnet_setbyindex(ifp->if_index, ifp); 663fc74a9f9SBrooks Davis return (ifp); 664fc74a9f9SBrooks Davis } 665fc74a9f9SBrooks Davis 6667687707dSAndrew Gallatin struct ifnet * 6677687707dSAndrew Gallatin if_alloc_dev(u_char type, device_t dev) 6687687707dSAndrew Gallatin { 6697687707dSAndrew Gallatin int numa_domain; 6707687707dSAndrew Gallatin 6717687707dSAndrew Gallatin if (dev == NULL || bus_get_domain(dev, &numa_domain) != 0) 6727687707dSAndrew Gallatin return (if_alloc_domain(type, IF_NODOM)); 6737687707dSAndrew Gallatin return (if_alloc_domain(type, numa_domain)); 6747687707dSAndrew Gallatin } 6757687707dSAndrew Gallatin 6767687707dSAndrew Gallatin struct ifnet * 6777687707dSAndrew Gallatin if_alloc(u_char type) 6787687707dSAndrew Gallatin { 6797687707dSAndrew Gallatin 6807687707dSAndrew Gallatin return (if_alloc_domain(type, IF_NODOM)); 6817687707dSAndrew Gallatin } 682a45cbf12SBrooks Davis /* 6834c506522SGleb Smirnoff * Do the actual work of freeing a struct ifnet, and layer 2 common 6844c506522SGleb Smirnoff * structure. This call is made when the last reference to an 685242a8e72SRobert Watson * interface is released. 686a45cbf12SBrooks Davis */ 687242a8e72SRobert Watson static void 688242a8e72SRobert Watson if_free_internal(struct ifnet *ifp) 689fc74a9f9SBrooks Davis { 690fc74a9f9SBrooks Davis 691242a8e72SRobert Watson KASSERT((ifp->if_flags & IFF_DYING), 692242a8e72SRobert Watson ("if_free_internal: interface not dying")); 693fc74a9f9SBrooks Davis 69427d37320SRobert Watson if (if_com_free[ifp->if_alloctype] != NULL) 69527d37320SRobert Watson if_com_free[ifp->if_alloctype](ifp->if_l2com, 69627d37320SRobert Watson ifp->if_alloctype); 697fc74a9f9SBrooks Davis 698d6f157eaSRobert Watson #ifdef MAC 699d6f157eaSRobert Watson mac_ifnet_destroy(ifp); 700d6f157eaSRobert Watson #endif /* MAC */ 701d6f157eaSRobert Watson IF_AFDATA_DESTROY(ifp); 70202f4879dSRobert Watson IF_ADDR_LOCK_DESTROY(ifp); 703d659538fSSam Leffler ifq_delete(&ifp->if_snd); 704112f50ffSGleb Smirnoff 705112f50ffSGleb Smirnoff for (int i = 0; i < IFCOUNTERS; i++) 706112f50ffSGleb Smirnoff counter_u64_free(ifp->if_counters[i]); 707112f50ffSGleb Smirnoff 70885107355SAndrey V. Elsukov free(ifp->if_description, M_IFDESCR); 70985107355SAndrey V. Elsukov free(ifp->if_hw_addr, M_IFADDR); 710fc74a9f9SBrooks Davis free(ifp, M_IFNET); 711c0c9ea90SSam Leffler } 712fc74a9f9SBrooks Davis 7134f6c66ccSMatt Macy static void 7144f6c66ccSMatt Macy if_destroy(epoch_context_t ctx) 7154f6c66ccSMatt Macy { 7164f6c66ccSMatt Macy struct ifnet *ifp; 7174f6c66ccSMatt Macy 7184f6c66ccSMatt Macy ifp = __containerof(ctx, struct ifnet, if_epoch_ctx); 7194f6c66ccSMatt Macy if_free_internal(ifp); 7204f6c66ccSMatt Macy } 7214f6c66ccSMatt Macy 722242a8e72SRobert Watson /* 723f26fa169SBrooks Davis * Deregister an interface and free the associated storage. 724242a8e72SRobert Watson */ 725242a8e72SRobert Watson void 726f26fa169SBrooks Davis if_free(struct ifnet *ifp) 727242a8e72SRobert Watson { 728242a8e72SRobert Watson 729242a8e72SRobert Watson ifp->if_flags |= IFF_DYING; /* XXX: Locking */ 7304c506522SGleb Smirnoff 731719fb725SCraig Rodrigues CURVNET_SET_QUIET(ifp->if_vnet); 7324c506522SGleb Smirnoff IFNET_WLOCK(); 733270b83b9SHans Petter Selasky KASSERT(ifp == ifnet_byindex(ifp->if_index), 7344c506522SGleb Smirnoff ("%s: freeing unallocated ifnet", ifp->if_xname)); 7354c506522SGleb Smirnoff 7364c506522SGleb Smirnoff ifindex_free_locked(ifp->if_index); 7374c506522SGleb Smirnoff IFNET_WUNLOCK(); 7384c506522SGleb Smirnoff 739719fb725SCraig Rodrigues if (refcount_release(&ifp->if_refcount)) 7402a4bd982SGleb Smirnoff NET_EPOCH_CALL(if_destroy, &ifp->if_epoch_ctx); 741719fb725SCraig Rodrigues CURVNET_RESTORE(); 742242a8e72SRobert Watson } 743242a8e72SRobert Watson 744242a8e72SRobert Watson /* 745242a8e72SRobert Watson * Interfaces to keep an ifnet type-stable despite the possibility of the 746242a8e72SRobert Watson * driver calling if_free(). If there are additional references, we defer 747242a8e72SRobert Watson * freeing the underlying data structure. 748242a8e72SRobert Watson */ 749db7f0b97SKip Macy void 75027d37320SRobert Watson if_ref(struct ifnet *ifp) 75127d37320SRobert Watson { 7527563019bSAlexander V. Chernikov u_int old; 75327d37320SRobert Watson 75427d37320SRobert Watson /* We don't assert the ifnet list lock here, but arguably should. */ 7557563019bSAlexander V. Chernikov old = refcount_acquire(&ifp->if_refcount); 7567563019bSAlexander V. Chernikov KASSERT(old > 0, ("%s: ifp %p has 0 refs", __func__, ifp)); 7577563019bSAlexander V. Chernikov } 7587563019bSAlexander V. Chernikov 7597563019bSAlexander V. Chernikov bool 7607563019bSAlexander V. Chernikov if_try_ref(struct ifnet *ifp) 7617563019bSAlexander V. Chernikov { 7627563019bSAlexander V. Chernikov NET_EPOCH_ASSERT(); 7637563019bSAlexander V. Chernikov return (refcount_acquire_if_not_zero(&ifp->if_refcount)); 76427d37320SRobert Watson } 76527d37320SRobert Watson 76627d37320SRobert Watson void 76727d37320SRobert Watson if_rele(struct ifnet *ifp) 76827d37320SRobert Watson { 76927d37320SRobert Watson 770242a8e72SRobert Watson if (!refcount_release(&ifp->if_refcount)) 771242a8e72SRobert Watson return; 7722a4bd982SGleb Smirnoff NET_EPOCH_CALL(if_destroy, &ifp->if_epoch_ctx); 77327d37320SRobert Watson } 77427d37320SRobert Watson 77527d37320SRobert Watson void 776d659538fSSam Leffler ifq_init(struct ifaltq *ifq, struct ifnet *ifp) 777db7f0b97SKip Macy { 778db7f0b97SKip Macy 779db7f0b97SKip Macy mtx_init(&ifq->ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF); 780db7f0b97SKip Macy 781db7f0b97SKip Macy if (ifq->ifq_maxlen == 0) 782db7f0b97SKip Macy ifq->ifq_maxlen = ifqmaxlen; 783db7f0b97SKip Macy 784db7f0b97SKip Macy ifq->altq_type = 0; 785db7f0b97SKip Macy ifq->altq_disc = NULL; 786db7f0b97SKip Macy ifq->altq_flags &= ALTQF_CANTCHANGE; 787db7f0b97SKip Macy ifq->altq_tbr = NULL; 788db7f0b97SKip Macy ifq->altq_ifp = ifp; 789db7f0b97SKip Macy } 790db7f0b97SKip Macy 791db7f0b97SKip Macy void 792d659538fSSam Leffler ifq_delete(struct ifaltq *ifq) 793db7f0b97SKip Macy { 794db7f0b97SKip Macy mtx_destroy(&ifq->ifq_mtx); 795db7f0b97SKip Macy } 796db7f0b97SKip Macy 797fc74a9f9SBrooks Davis /* 798a4641f4eSPedro F. Giffuni * Perform generic interface initialization tasks and attach the interface 799e0c14af9SMarko Zec * to the list of "active" interfaces. If vmove flag is set on entry 800e0c14af9SMarko Zec * to if_attach_internal(), perform only a limited subset of initialization 801e0c14af9SMarko Zec * tasks, given that we are moving from one vnet to another an ifnet which 802e0c14af9SMarko Zec * has already been fully initialized. 803a45cbf12SBrooks Davis * 804c92a456bSHiroki Sato * Note that if_detach_internal() removes group membership unconditionally 805c92a456bSHiroki Sato * even when vmove flag is set, and if_attach_internal() adds only IFG_ALL. 806c92a456bSHiroki Sato * Thus, when if_vmove() is applied to a cloned interface, group membership 807c92a456bSHiroki Sato * is lost while a cloned one always joins a group whose name is 808c92a456bSHiroki Sato * ifc->ifc_name. To recover this after if_detach_internal() and 809c92a456bSHiroki Sato * if_attach_internal(), the cloner should be specified to 810c92a456bSHiroki Sato * if_attach_internal() via ifc. If it is non-NULL, if_attach_internal() 811c92a456bSHiroki Sato * attempts to join a group whose name is ifc->ifc_name. 812c92a456bSHiroki Sato * 813a45cbf12SBrooks Davis * XXX: 814a45cbf12SBrooks Davis * - The decision to return void and thus require this function to 815a45cbf12SBrooks Davis * succeed is questionable. 816a45cbf12SBrooks Davis * - We should probably do more sanity checking. For instance we don't 817a45cbf12SBrooks Davis * do anything to insure if_xname is unique or non-empty. 818df8bae1dSRodney W. Grimes */ 819df8bae1dSRodney W. Grimes void 82072fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp) 821df8bae1dSRodney W. Grimes { 822e0c14af9SMarko Zec 823c92a456bSHiroki Sato if_attach_internal(ifp, 0, NULL); 824e0c14af9SMarko Zec } 825e0c14af9SMarko Zec 8269fd573c3SHans Petter Selasky /* 8279fd573c3SHans Petter Selasky * Compute the least common TSO limit. 8289fd573c3SHans Petter Selasky */ 8299fd573c3SHans Petter Selasky void 8309fd573c3SHans Petter Selasky if_hw_tsomax_common(if_t ifp, struct ifnet_hw_tsomax *pmax) 8319fd573c3SHans Petter Selasky { 8329fd573c3SHans Petter Selasky /* 8339fd573c3SHans Petter Selasky * 1) If there is no limit currently, take the limit from 8349fd573c3SHans Petter Selasky * the network adapter. 8359fd573c3SHans Petter Selasky * 8369fd573c3SHans Petter Selasky * 2) If the network adapter has a limit below the current 8379fd573c3SHans Petter Selasky * limit, apply it. 8389fd573c3SHans Petter Selasky */ 8399fd573c3SHans Petter Selasky if (pmax->tsomaxbytes == 0 || (ifp->if_hw_tsomax != 0 && 8409fd573c3SHans Petter Selasky ifp->if_hw_tsomax < pmax->tsomaxbytes)) { 8419fd573c3SHans Petter Selasky pmax->tsomaxbytes = ifp->if_hw_tsomax; 8429fd573c3SHans Petter Selasky } 8439fd573c3SHans Petter Selasky if (pmax->tsomaxsegcount == 0 || (ifp->if_hw_tsomaxsegcount != 0 && 8449fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount < pmax->tsomaxsegcount)) { 8459fd573c3SHans Petter Selasky pmax->tsomaxsegcount = ifp->if_hw_tsomaxsegcount; 8469fd573c3SHans Petter Selasky } 8479fd573c3SHans Petter Selasky if (pmax->tsomaxsegsize == 0 || (ifp->if_hw_tsomaxsegsize != 0 && 8489fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize < pmax->tsomaxsegsize)) { 8499fd573c3SHans Petter Selasky pmax->tsomaxsegsize = ifp->if_hw_tsomaxsegsize; 8509fd573c3SHans Petter Selasky } 8519fd573c3SHans Petter Selasky } 8529fd573c3SHans Petter Selasky 8539fd573c3SHans Petter Selasky /* 8549fd573c3SHans Petter Selasky * Update TSO limit of a network adapter. 8559fd573c3SHans Petter Selasky * 8569fd573c3SHans Petter Selasky * Returns zero if no change. Else non-zero. 8579fd573c3SHans Petter Selasky */ 8589fd573c3SHans Petter Selasky int 8599fd573c3SHans Petter Selasky if_hw_tsomax_update(if_t ifp, struct ifnet_hw_tsomax *pmax) 8609fd573c3SHans Petter Selasky { 8619fd573c3SHans Petter Selasky int retval = 0; 8629fd573c3SHans Petter Selasky if (ifp->if_hw_tsomax != pmax->tsomaxbytes) { 8639fd573c3SHans Petter Selasky ifp->if_hw_tsomax = pmax->tsomaxbytes; 8649fd573c3SHans Petter Selasky retval++; 8659fd573c3SHans Petter Selasky } 8669fd573c3SHans Petter Selasky if (ifp->if_hw_tsomaxsegsize != pmax->tsomaxsegsize) { 8679fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize = pmax->tsomaxsegsize; 8689fd573c3SHans Petter Selasky retval++; 8699fd573c3SHans Petter Selasky } 8709fd573c3SHans Petter Selasky if (ifp->if_hw_tsomaxsegcount != pmax->tsomaxsegcount) { 8719fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount = pmax->tsomaxsegcount; 8729fd573c3SHans Petter Selasky retval++; 8739fd573c3SHans Petter Selasky } 8749fd573c3SHans Petter Selasky return (retval); 8759fd573c3SHans Petter Selasky } 8769fd573c3SHans Petter Selasky 877e0c14af9SMarko Zec static void 878c92a456bSHiroki Sato if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc) 879e0c14af9SMarko Zec { 880df8bae1dSRodney W. Grimes unsigned socksize, ifasize; 8811ce9bf88SPoul-Henning Kamp int namelen, masklen; 88272fd1b6aSDag-Erling Smørgrav struct sockaddr_dl *sdl; 88372fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 884df8bae1dSRodney W. Grimes 885fc74a9f9SBrooks Davis if (ifp->if_index == 0 || ifp != ifnet_byindex(ifp->if_index)) 886fc74a9f9SBrooks Davis panic ("%s: BUG: if_attach called without if_alloc'd input()\n", 887fc74a9f9SBrooks Davis ifp->if_xname); 888fc74a9f9SBrooks Davis 889f6dfe47aSMarko Zec #ifdef VIMAGE 890f6dfe47aSMarko Zec ifp->if_vnet = curvnet; 891bc29160dSMarko Zec if (ifp->if_home_vnet == NULL) 892bc29160dSMarko Zec ifp->if_home_vnet = curvnet; 893f6dfe47aSMarko Zec #endif 894f6dfe47aSMarko Zec 8950dad3f0eSMax Laier if_addgroup(ifp, IFG_ALL); 8960dad3f0eSMax Laier 897c92a456bSHiroki Sato /* Restore group membership for cloned interfaces. */ 898c92a456bSHiroki Sato if (vmove && ifc != NULL) 899c92a456bSHiroki Sato if_clone_addgroup(ifp, ifc); 900c92a456bSHiroki Sato 90198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 902e6485f73SGleb Smirnoff ifp->if_epoch = time_uptime; 903d6f157eaSRobert Watson 9047cc5b47fSKip Macy KASSERT((ifp->if_transmit == NULL && ifp->if_qflush == NULL) || 9057cc5b47fSKip Macy (ifp->if_transmit != NULL && ifp->if_qflush != NULL), 9067cc5b47fSKip Macy ("transmit and qflush must both either be set or both be NULL")); 9077cc5b47fSKip Macy if (ifp->if_transmit == NULL) { 908db7f0b97SKip Macy ifp->if_transmit = if_transmit; 909db7f0b97SKip Macy ifp->if_qflush = if_qflush; 9107cc5b47fSKip Macy } 911b57d9721SAndrey V. Elsukov if (ifp->if_input == NULL) 912b57d9721SAndrey V. Elsukov ifp->if_input = if_input_default; 9137cc5b47fSKip Macy 9144fb3a820SAlexander V. Chernikov if (ifp->if_requestencap == NULL) 9154fb3a820SAlexander V. Chernikov ifp->if_requestencap = if_requestencap_default; 9164fb3a820SAlexander V. Chernikov 917e0c14af9SMarko Zec if (!vmove) { 918e70cd263SRobert Watson #ifdef MAC 91930d239bcSRobert Watson mac_ifnet_create(ifp); 920e70cd263SRobert Watson #endif 921e70cd263SRobert Watson 922df8bae1dSRodney W. Grimes /* 923e0c14af9SMarko Zec * Create a Link Level name for this device. 924df8bae1dSRodney W. Grimes */ 9259bf40edeSBrooks Davis namelen = strlen(ifp->if_xname); 92636c19a57SBrooks Davis /* 927e0c14af9SMarko Zec * Always save enough space for any possiable name so we 928e0c14af9SMarko Zec * can do a rename in place later. 92936c19a57SBrooks Davis */ 93036c19a57SBrooks Davis masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ; 931df8bae1dSRodney W. Grimes socksize = masklen + ifp->if_addrlen; 932df8bae1dSRodney W. Grimes if (socksize < sizeof(*sdl)) 933df8bae1dSRodney W. Grimes socksize = sizeof(*sdl); 934ccb82468SBrooks Davis socksize = roundup2(socksize, sizeof(long)); 935df8bae1dSRodney W. Grimes ifasize = sizeof(*ifa) + 2 * socksize; 93646758960SGleb Smirnoff ifa = ifa_alloc(ifasize, M_WAITOK); 937df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(ifa + 1); 938df8bae1dSRodney W. Grimes sdl->sdl_len = socksize; 939df8bae1dSRodney W. Grimes sdl->sdl_family = AF_LINK; 9409bf40edeSBrooks Davis bcopy(ifp->if_xname, sdl->sdl_data, namelen); 9411ce9bf88SPoul-Henning Kamp sdl->sdl_nlen = namelen; 942df8bae1dSRodney W. Grimes sdl->sdl_index = ifp->if_index; 943df8bae1dSRodney W. Grimes sdl->sdl_type = ifp->if_type; 9444a0d6638SRuslan Ermilov ifp->if_addr = ifa; 945df8bae1dSRodney W. Grimes ifa->ifa_ifp = ifp; 946df8bae1dSRodney W. Grimes ifa->ifa_addr = (struct sockaddr *)sdl; 947df8bae1dSRodney W. Grimes sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl); 948df8bae1dSRodney W. Grimes ifa->ifa_netmask = (struct sockaddr *)sdl; 949df8bae1dSRodney W. Grimes sdl->sdl_len = masklen; 950df8bae1dSRodney W. Grimes while (namelen != 0) 951df8bae1dSRodney W. Grimes sdl->sdl_data[--namelen] = 0xff; 952d7c5a620SMatt Macy CK_STAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link); 953e0c14af9SMarko Zec /* Reliably crash if used uninitialized. */ 954e0c14af9SMarko Zec ifp->if_broadcastaddr = NULL; 95572f31000SHans Petter Selasky 956ddae5750SRavi Pokala if (ifp->if_type == IFT_ETHER) { 957ddae5750SRavi Pokala ifp->if_hw_addr = malloc(ifp->if_addrlen, M_IFADDR, 958ddae5750SRavi Pokala M_WAITOK | M_ZERO); 959ddae5750SRavi Pokala } 960ddae5750SRavi Pokala 96172f31000SHans Petter Selasky #if defined(INET) || defined(INET6) 9629fd573c3SHans Petter Selasky /* Use defaults for TSO, if nothing is set */ 9639fd573c3SHans Petter Selasky if (ifp->if_hw_tsomax == 0 && 9649fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount == 0 && 9659fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize == 0) { 9669fd573c3SHans Petter Selasky /* 9679fd573c3SHans Petter Selasky * The TSO defaults needs to be such that an 9689fd573c3SHans Petter Selasky * NFS mbuf list of 35 mbufs totalling just 9699fd573c3SHans Petter Selasky * below 64K works and that a chain of mbufs 9709fd573c3SHans Petter Selasky * can be defragged into at most 32 segments: 9719fd573c3SHans Petter Selasky */ 9729fd573c3SHans Petter Selasky ifp->if_hw_tsomax = min(IP_MAXPACKET, (32 * MCLBYTES) - 97372f31000SHans Petter Selasky (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN)); 9749fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount = 35; 9759fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize = 2048; /* 2K */ 9769fd573c3SHans Petter Selasky 9779fd573c3SHans Petter Selasky /* XXX some drivers set IFCAP_TSO after ethernet attach */ 9789fd573c3SHans Petter Selasky if (ifp->if_capabilities & IFCAP_TSO) { 9799fd573c3SHans Petter Selasky if_printf(ifp, "Using defaults for TSO: %u/%u/%u\n", 9809fd573c3SHans Petter Selasky ifp->if_hw_tsomax, 9819fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegcount, 9829fd573c3SHans Petter Selasky ifp->if_hw_tsomaxsegsize); 9839fd573c3SHans Petter Selasky } 9849fd573c3SHans Petter Selasky } 98572f31000SHans Petter Selasky #endif 986e0c14af9SMarko Zec } 98752db6805SMarko Zec #ifdef VIMAGE 98852db6805SMarko Zec else { 98952db6805SMarko Zec /* 99052db6805SMarko Zec * Update the interface index in the link layer address 99152db6805SMarko Zec * of the interface. 99252db6805SMarko Zec */ 99352db6805SMarko Zec for (ifa = ifp->if_addr; ifa != NULL; 994d7c5a620SMatt Macy ifa = CK_STAILQ_NEXT(ifa, ifa_link)) { 99552db6805SMarko Zec if (ifa->ifa_addr->sa_family == AF_LINK) { 99652db6805SMarko Zec sdl = (struct sockaddr_dl *)ifa->ifa_addr; 99752db6805SMarko Zec sdl->sdl_index = ifp->if_index; 99852db6805SMarko Zec } 99952db6805SMarko Zec } 100052db6805SMarko Zec } 100152db6805SMarko Zec #endif 1002d94ccb09SBrooks Davis 1003a779388fSKristof Provost if_link_ifnet(ifp); 1004457f48e6SGleb Smirnoff 100569fb23b7SMax Laier if (domain_init_status >= 2) 100631b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 100731b1bfe1SHajimu UMEMOTO 100825a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 100921ca7b57SMarko Zec if (IS_DEFAULT_VNET(curvnet)) 1010f3b90d48SAndrew Thompson devctl_notify("IFNET", ifp->if_xname, "ATTACH", NULL); 101125a4adceSMax Laier 10127b6edd04SRuslan Ermilov /* Announce the interface. */ 10137b6edd04SRuslan Ermilov rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 1014df8bae1dSRodney W. Grimes } 10156182fdbdSPeter Wemm 101631b1bfe1SHajimu UMEMOTO static void 1017f2d19f98SMatt Macy if_epochalloc(void *dummy __unused) 1018f2d19f98SMatt Macy { 1019f2d19f98SMatt Macy 1020dd902d01SGleb Smirnoff net_epoch_preempt = epoch_alloc("Net preemptible", EPOCH_PREEMPT); 1021f2d19f98SMatt Macy } 10227993a104SConrad Meyer SYSINIT(ifepochalloc, SI_SUB_EPOCH, SI_ORDER_ANY, if_epochalloc, NULL); 1023f2d19f98SMatt Macy 1024f2d19f98SMatt Macy static void 102572fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy) 102631b1bfe1SHajimu UMEMOTO { 102731b1bfe1SHajimu UMEMOTO struct ifnet *ifp; 102831b1bfe1SHajimu UMEMOTO 10294f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) 103031b1bfe1SHajimu UMEMOTO if_attachdomain1(ifp); 103131b1bfe1SHajimu UMEMOTO } 103269fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND, 103331b1bfe1SHajimu UMEMOTO if_attachdomain, NULL); 103431b1bfe1SHajimu UMEMOTO 103531b1bfe1SHajimu UMEMOTO static void 103672fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp) 103731b1bfe1SHajimu UMEMOTO { 103831b1bfe1SHajimu UMEMOTO struct domain *dp; 103931b1bfe1SHajimu UMEMOTO 1040234a35c7SHajimu UMEMOTO /* 1041234a35c7SHajimu UMEMOTO * Since dp->dom_ifattach calls malloc() with M_WAITOK, we 1042234a35c7SHajimu UMEMOTO * cannot lock ifp->if_afdata initialization, entirely. 1043234a35c7SHajimu UMEMOTO */ 1044c169d9feSBjoern A. Zeeb IF_AFDATA_LOCK(ifp); 104569fb23b7SMax Laier if (ifp->if_afdata_initialized >= domain_init_status) { 1046234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 1047813ee737SAndre Oppermann log(LOG_WARNING, "%s called more than once on %s\n", 1048813ee737SAndre Oppermann __func__, ifp->if_xname); 1049234a35c7SHajimu UMEMOTO return; 1050234a35c7SHajimu UMEMOTO } 105169fb23b7SMax Laier ifp->if_afdata_initialized = domain_init_status; 1052234a35c7SHajimu UMEMOTO IF_AFDATA_UNLOCK(ifp); 1053234a35c7SHajimu UMEMOTO 105431b1bfe1SHajimu UMEMOTO /* address family dependent data region */ 105531b1bfe1SHajimu UMEMOTO bzero(ifp->if_afdata, sizeof(ifp->if_afdata)); 105631b1bfe1SHajimu UMEMOTO for (dp = domains; dp; dp = dp->dom_next) { 105731b1bfe1SHajimu UMEMOTO if (dp->dom_ifattach) 105831b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family] = 105931b1bfe1SHajimu UMEMOTO (*dp->dom_ifattach)(ifp); 106031b1bfe1SHajimu UMEMOTO } 106131b1bfe1SHajimu UMEMOTO } 106231b1bfe1SHajimu UMEMOTO 10636182fdbdSPeter Wemm /* 1064ec002feeSBruce M Simpson * Remove any unicast or broadcast network addresses from an interface. 106545778b37SPeter Edwards */ 106645778b37SPeter Edwards void 106745778b37SPeter Edwards if_purgeaddrs(struct ifnet *ifp) 106845778b37SPeter Edwards { 106988d57e9eSHans Petter Selasky struct ifaddr *ifa; 107045778b37SPeter Edwards 107188d57e9eSHans Petter Selasky while (1) { 1072a68cc388SGleb Smirnoff struct epoch_tracker et; 1073a68cc388SGleb Smirnoff 1074a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 107588d57e9eSHans Petter Selasky CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 107688d57e9eSHans Petter Selasky if (ifa->ifa_addr->sa_family != AF_LINK) 107788d57e9eSHans Petter Selasky break; 107888d57e9eSHans Petter Selasky } 1079a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 108088d57e9eSHans Petter Selasky 108188d57e9eSHans Petter Selasky if (ifa == NULL) 108288d57e9eSHans Petter Selasky break; 108345778b37SPeter Edwards #ifdef INET 108445778b37SPeter Edwards /* XXX: Ugly!! ad hoc just for INET */ 10854b97d7afSYaroslav Tykhiy if (ifa->ifa_addr->sa_family == AF_INET) { 108645778b37SPeter Edwards struct ifaliasreq ifr; 108745778b37SPeter Edwards 108845778b37SPeter Edwards bzero(&ifr, sizeof(ifr)); 108945778b37SPeter Edwards ifr.ifra_addr = *ifa->ifa_addr; 109045778b37SPeter Edwards if (ifa->ifa_dstaddr) 109145778b37SPeter Edwards ifr.ifra_broadaddr = *ifa->ifa_dstaddr; 109245778b37SPeter Edwards if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp, 109345778b37SPeter Edwards NULL) == 0) 109445778b37SPeter Edwards continue; 109545778b37SPeter Edwards } 109645778b37SPeter Edwards #endif /* INET */ 109745778b37SPeter Edwards #ifdef INET6 10984b97d7afSYaroslav Tykhiy if (ifa->ifa_addr->sa_family == AF_INET6) { 1099f9e0752eSAlexander V. Chernikov in6_purgeifaddr((struct in6_ifaddr *)ifa); 110045778b37SPeter Edwards /* ifp_addrhead is already updated */ 110145778b37SPeter Edwards continue; 110245778b37SPeter Edwards } 110345778b37SPeter Edwards #endif /* INET6 */ 1104f22d78c0SBjoern A. Zeeb IF_ADDR_WLOCK(ifp); 1105d7c5a620SMatt Macy CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link); 1106f22d78c0SBjoern A. Zeeb IF_ADDR_WUNLOCK(ifp); 11071099f828SRobert Watson ifa_free(ifa); 110845778b37SPeter Edwards } 110945778b37SPeter Edwards } 111045778b37SPeter Edwards 111145778b37SPeter Edwards /* 111293ec7edcSShteryana Shopova * Remove any multicast network addresses from an interface when an ifnet 111393ec7edcSShteryana Shopova * is going away. 1114ec002feeSBruce M Simpson */ 111593ec7edcSShteryana Shopova static void 1116ec002feeSBruce M Simpson if_purgemaddrs(struct ifnet *ifp) 1117ec002feeSBruce M Simpson { 1118ec002feeSBruce M Simpson struct ifmultiaddr *ifma; 1119ec002feeSBruce M Simpson 1120137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 1121d7c5a620SMatt Macy while (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) { 1122d7c5a620SMatt Macy ifma = CK_STAILQ_FIRST(&ifp->if_multiaddrs); 1123d7c5a620SMatt Macy CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); 1124ec002feeSBruce M Simpson if_delmulti_locked(ifp, ifma, 1); 1125f3e1324bSStephen Hurd } 1126137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 1127ec002feeSBruce M Simpson } 1128ec002feeSBruce M Simpson 1129ec002feeSBruce M Simpson /* 1130e0c14af9SMarko Zec * Detach an interface, removing it from the list of "active" interfaces. 1131e0c14af9SMarko Zec * If vmove flag is set on entry to if_detach_internal(), perform only a 1132e0c14af9SMarko Zec * limited subset of cleanup tasks, given that we are moving an ifnet from 1133e0c14af9SMarko Zec * one vnet to another, where it must be fully operational. 1134b1c53bc9SRobert Watson * 1135b1c53bc9SRobert Watson * XXXRW: There are some significant questions about event ordering, and 1136b1c53bc9SRobert Watson * how to prevent things from starting to use the interface during detach. 11376182fdbdSPeter Wemm */ 11386182fdbdSPeter Wemm void 113972fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp) 11406182fdbdSPeter Wemm { 1141a779388fSKristof Provost bool found; 1142e0c14af9SMarko Zec 1143719fb725SCraig Rodrigues CURVNET_SET_QUIET(ifp->if_vnet); 1144a779388fSKristof Provost found = if_unlink_ifnet(ifp, false); 1145e133271fSKristof Provost if (found) { 11466d2a10d9SKristof Provost sx_xlock(&ifnet_detach_sxlock); 1147c92a456bSHiroki Sato if_detach_internal(ifp, 0, NULL); 11486d2a10d9SKristof Provost sx_xunlock(&ifnet_detach_sxlock); 1149e133271fSKristof Provost } 1150719fb725SCraig Rodrigues CURVNET_RESTORE(); 1151e0c14af9SMarko Zec } 1152e0c14af9SMarko Zec 115389856f7eSBjoern A. Zeeb /* 115489856f7eSBjoern A. Zeeb * The vmove flag, if set, indicates that we are called from a callpath 115589856f7eSBjoern A. Zeeb * that is moving an interface to a different vnet instance. 115689856f7eSBjoern A. Zeeb * 115789856f7eSBjoern A. Zeeb * The shutdown flag, if set, indicates that we are called in the 115889856f7eSBjoern A. Zeeb * process of shutting down a vnet instance. Currently only the 115989856f7eSBjoern A. Zeeb * vnet_if_return SYSUNINIT function sets it. Note: we can be called 116089856f7eSBjoern A. Zeeb * on a vnet instance shutdown without this flag being set, e.g., when 116189856f7eSBjoern A. Zeeb * the cloned interfaces are destoyed as first thing of teardown. 116289856f7eSBjoern A. Zeeb */ 1163f501e6f1SBjoern A. Zeeb static int 1164c92a456bSHiroki Sato if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp) 1165e0c14af9SMarko Zec { 116645778b37SPeter Edwards struct ifaddr *ifa; 11674bdf0b6aSAlexander V. Chernikov int i; 116831b1bfe1SHajimu UMEMOTO struct domain *dp; 1169d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE 1170204e2f30SHans Petter Selasky bool shutdown; 1171457f48e6SGleb Smirnoff 117210108cb6SBjoern A. Zeeb shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet); 1173d3f6f80fSBjoern A. Zeeb #endif 11746182fdbdSPeter Wemm 117589856f7eSBjoern A. Zeeb /* 117689856f7eSBjoern A. Zeeb * At this point we know the interface still was on the ifnet list 117789856f7eSBjoern A. Zeeb * and we removed it so we are in a stable state. 117889856f7eSBjoern A. Zeeb */ 11794f6c66ccSMatt Macy epoch_wait_preempt(net_epoch_preempt); 11800dbdf041SHans Petter Selasky 11810dbdf041SHans Petter Selasky /* 11820dbdf041SHans Petter Selasky * Ensure all pending EPOCH(9) callbacks have been executed. This 11830dbdf041SHans Petter Selasky * fixes issues about late destruction of multicast options 11840dbdf041SHans Petter Selasky * which lead to leave group calls, which in turn access the 11850dbdf041SHans Petter Selasky * belonging ifnet structure: 11860dbdf041SHans Petter Selasky */ 11870dbdf041SHans Petter Selasky epoch_drain_callbacks(net_epoch_preempt); 11880dbdf041SHans Petter Selasky 118989856f7eSBjoern A. Zeeb /* 119089856f7eSBjoern A. Zeeb * In any case (destroy or vmove) detach us from the groups 119189856f7eSBjoern A. Zeeb * and remove/wait for pending events on the taskq. 119289856f7eSBjoern A. Zeeb * XXX-BZ in theory an interface could still enqueue a taskq change? 119389856f7eSBjoern A. Zeeb */ 119489856f7eSBjoern A. Zeeb if_delgroups(ifp); 119589856f7eSBjoern A. Zeeb 119689856f7eSBjoern A. Zeeb taskqueue_drain(taskqueue_swi, &ifp->if_linktask); 11970839aa5cSGleb Smirnoff taskqueue_drain(taskqueue_swi, &ifp->if_addmultitask); 119889856f7eSBjoern A. Zeeb 119989856f7eSBjoern A. Zeeb /* 120089856f7eSBjoern A. Zeeb * Check if this is a cloned interface or not. Must do even if 120189856f7eSBjoern A. Zeeb * shutting down as a if_vmove_reclaim() would move the ifp and 120289856f7eSBjoern A. Zeeb * the if_clone_addgroup() will have a corrupted string overwise 120389856f7eSBjoern A. Zeeb * from a gibberish pointer. 120489856f7eSBjoern A. Zeeb */ 1205c92a456bSHiroki Sato if (vmove && ifcp != NULL) 1206c92a456bSHiroki Sato *ifcp = if_clone_findifc(ifp); 1207c92a456bSHiroki Sato 120889856f7eSBjoern A. Zeeb if_down(ifp); 120989856f7eSBjoern A. Zeeb 1210d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE 121168a3482fSGleb Smirnoff /* 121289856f7eSBjoern A. Zeeb * On VNET shutdown abort here as the stack teardown will do all 121389856f7eSBjoern A. Zeeb * the work top-down for us. 121468a3482fSGleb Smirnoff */ 121589856f7eSBjoern A. Zeeb if (shutdown) { 121625c6ab1bSKristof Provost /* Give interface users the chance to clean up. */ 121725c6ab1bSKristof Provost EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 121825c6ab1bSKristof Provost 121989856f7eSBjoern A. Zeeb /* 122089856f7eSBjoern A. Zeeb * In case of a vmove we are done here without error. 122189856f7eSBjoern A. Zeeb * If we would signal an error it would lead to the same 122289856f7eSBjoern A. Zeeb * abort as if we did not find the ifnet anymore. 122389856f7eSBjoern A. Zeeb * if_detach() calls us in void context and does not care 122489856f7eSBjoern A. Zeeb * about an early abort notification, so life is splendid :) 122589856f7eSBjoern A. Zeeb */ 122689856f7eSBjoern A. Zeeb goto finish_vnet_shutdown; 122789856f7eSBjoern A. Zeeb } 1228d3f6f80fSBjoern A. Zeeb #endif 122989856f7eSBjoern A. Zeeb 123089856f7eSBjoern A. Zeeb /* 123189856f7eSBjoern A. Zeeb * At this point we are not tearing down a VNET and are either 123289856f7eSBjoern A. Zeeb * going to destroy or vmove the interface and have to cleanup 123389856f7eSBjoern A. Zeeb * accordingly. 123489856f7eSBjoern A. Zeeb */ 123568a3482fSGleb Smirnoff 12366182fdbdSPeter Wemm /* 12376182fdbdSPeter Wemm * Remove routes and flush queues. 12386182fdbdSPeter Wemm */ 123902b199f1SMax Laier #ifdef ALTQ 124002b199f1SMax Laier if (ALTQ_IS_ENABLED(&ifp->if_snd)) 124102b199f1SMax Laier altq_disable(&ifp->if_snd); 124202b199f1SMax Laier if (ALTQ_IS_ATTACHED(&ifp->if_snd)) 124302b199f1SMax Laier altq_detach(&ifp->if_snd); 124402b199f1SMax Laier #endif 12456182fdbdSPeter Wemm 124645778b37SPeter Edwards if_purgeaddrs(ifp); 12476182fdbdSPeter Wemm 1248b1c53bc9SRobert Watson #ifdef INET 1249b1c53bc9SRobert Watson in_ifdetach(ifp); 1250b1c53bc9SRobert Watson #endif 1251b1c53bc9SRobert Watson 125233841545SHajimu UMEMOTO #ifdef INET6 125333841545SHajimu UMEMOTO /* 125433841545SHajimu UMEMOTO * Remove all IPv6 kernel structs related to ifp. This should be done 125533841545SHajimu UMEMOTO * before removing routing entries below, since IPv6 interface direct 125633841545SHajimu UMEMOTO * routes are expected to be removed by the IPv6-specific kernel API. 125733841545SHajimu UMEMOTO * Otherwise, the kernel will detect some inconsistency and bark it. 125833841545SHajimu UMEMOTO */ 125933841545SHajimu UMEMOTO in6_ifdetach(ifp); 126033841545SHajimu UMEMOTO #endif 1261ec002feeSBruce M Simpson if_purgemaddrs(ifp); 1262ec002feeSBruce M Simpson 1263af371fc6SRoger Pau Monné /* Announce that the interface is gone. */ 1264af371fc6SRoger Pau Monné rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 1265af371fc6SRoger Pau Monné EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 1266af371fc6SRoger Pau Monné if (IS_DEFAULT_VNET(curvnet)) 1267af371fc6SRoger Pau Monné devctl_notify("IFNET", ifp->if_xname, "DETACH", NULL); 1268af371fc6SRoger Pau Monné 1269e0c14af9SMarko Zec if (!vmove) { 1270f4247b59SLuigi Rizzo /* 1271111c6b61SRobert Watson * Prevent further calls into the device driver via ifnet. 1272111c6b61SRobert Watson */ 1273111c6b61SRobert Watson if_dead(ifp); 1274111c6b61SRobert Watson 1275111c6b61SRobert Watson /* 1276f4247b59SLuigi Rizzo * Clean up all addresses. 1277f4247b59SLuigi Rizzo */ 1278d117fd80SBjoern A. Zeeb IF_ADDR_WLOCK(ifp); 1279d7c5a620SMatt Macy if (!CK_STAILQ_EMPTY(&ifp->if_addrhead)) { 1280d7c5a620SMatt Macy ifa = CK_STAILQ_FIRST(&ifp->if_addrhead); 1281d7c5a620SMatt Macy CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link); 1282d117fd80SBjoern A. Zeeb IF_ADDR_WUNLOCK(ifp); 12831099f828SRobert Watson ifa_free(ifa); 1284d117fd80SBjoern A. Zeeb } else 1285d117fd80SBjoern A. Zeeb IF_ADDR_WUNLOCK(ifp); 1286e0c14af9SMarko Zec } 1287212bd869SHajimu UMEMOTO 12884bdf0b6aSAlexander V. Chernikov rt_flushifroutes(ifp); 12897b6edd04SRuslan Ermilov 1290d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE 129189856f7eSBjoern A. Zeeb finish_vnet_shutdown: 1292d3f6f80fSBjoern A. Zeeb #endif 1293d8c13659SBjoern A. Zeeb /* 1294d8c13659SBjoern A. Zeeb * We cannot hold the lock over dom_ifdetach calls as they might 1295d8c13659SBjoern A. Zeeb * sleep, for example trying to drain a callout, thus open up the 1296d8c13659SBjoern A. Zeeb * theoretical race with re-attaching. 1297d8c13659SBjoern A. Zeeb */ 1298234a35c7SHajimu UMEMOTO IF_AFDATA_LOCK(ifp); 1299d8c13659SBjoern A. Zeeb i = ifp->if_afdata_initialized; 1300d8c13659SBjoern A. Zeeb ifp->if_afdata_initialized = 0; 1301d8c13659SBjoern A. Zeeb IF_AFDATA_UNLOCK(ifp); 1302d8c13659SBjoern A. Zeeb for (dp = domains; i > 0 && dp; dp = dp->dom_next) { 13032d5ad99aSBjoern A. Zeeb if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) { 130431b1bfe1SHajimu UMEMOTO (*dp->dom_ifdetach)(ifp, 130531b1bfe1SHajimu UMEMOTO ifp->if_afdata[dp->dom_family]); 13062d5ad99aSBjoern A. Zeeb ifp->if_afdata[dp->dom_family] = NULL; 13072d5ad99aSBjoern A. Zeeb } 130831b1bfe1SHajimu UMEMOTO } 1309f501e6f1SBjoern A. Zeeb 1310f501e6f1SBjoern A. Zeeb return (0); 13115500d3beSWarner Losh } 13125500d3beSWarner Losh 1313e0c14af9SMarko Zec #ifdef VIMAGE 1314e0c14af9SMarko Zec /* 1315e0c14af9SMarko Zec * if_vmove() performs a limited version of if_detach() in current 1316e0c14af9SMarko Zec * vnet and if_attach()es the ifnet to the vnet specified as 2nd arg. 1317e0c14af9SMarko Zec * An attempt is made to shrink if_index in current vnet, find an 1318e0c14af9SMarko Zec * unused if_index in target vnet and calls if_grow() if necessary, 1319e0c14af9SMarko Zec * and finally find an unused if_xname for the target vnet. 1320e0c14af9SMarko Zec */ 1321c7bab2a7SKyle Evans static int 1322e0c14af9SMarko Zec if_vmove(struct ifnet *ifp, struct vnet *new_vnet) 1323e0c14af9SMarko Zec { 1324c92a456bSHiroki Sato struct if_clone *ifc; 13253232273fSBjoern A. Zeeb #ifdef DEV_BPF 132605fc4164SBjoern A. Zeeb u_int bif_dlt, bif_hdrlen; 13273232273fSBjoern A. Zeeb #endif 13284f6c66ccSMatt Macy void *old; 1329f501e6f1SBjoern A. Zeeb int rc; 1330e0c14af9SMarko Zec 13313232273fSBjoern A. Zeeb #ifdef DEV_BPF 1332e0c14af9SMarko Zec /* 133305fc4164SBjoern A. Zeeb * if_detach_internal() will call the eventhandler to notify 133405fc4164SBjoern A. Zeeb * interface departure. That will detach if_bpf. We need to 133505fc4164SBjoern A. Zeeb * safe the dlt and hdrlen so we can re-attach it later. 133605fc4164SBjoern A. Zeeb */ 133705fc4164SBjoern A. Zeeb bpf_get_bp_params(ifp->if_bpf, &bif_dlt, &bif_hdrlen); 13383232273fSBjoern A. Zeeb #endif 133905fc4164SBjoern A. Zeeb 134005fc4164SBjoern A. Zeeb /* 1341e0c14af9SMarko Zec * Detach from current vnet, but preserve LLADDR info, do not 1342e0c14af9SMarko Zec * mark as dead etc. so that the ifnet can be reattached later. 1343f501e6f1SBjoern A. Zeeb * If we cannot find it, we lost the race to someone else. 1344e0c14af9SMarko Zec */ 1345f501e6f1SBjoern A. Zeeb rc = if_detach_internal(ifp, 1, &ifc); 1346f501e6f1SBjoern A. Zeeb if (rc != 0) 1347c7bab2a7SKyle Evans return (rc); 1348e0c14af9SMarko Zec 1349e0c14af9SMarko Zec /* 135077dfcdc4SRobert Watson * Unlink the ifnet from ifindex_table[] in current vnet, and shrink 135177dfcdc4SRobert Watson * the if_index for that vnet if possible. 135277dfcdc4SRobert Watson * 135377dfcdc4SRobert Watson * NOTE: IFNET_WLOCK/IFNET_WUNLOCK() are assumed to be unvirtualized, 135477dfcdc4SRobert Watson * or we'd lock on one vnet and unlock on another. 1355e0c14af9SMarko Zec */ 1356e0c14af9SMarko Zec IFNET_WLOCK(); 1357ed2dabfcSRobert Watson ifindex_free_locked(ifp->if_index); 1358d3c351c5SMarko Zec IFNET_WUNLOCK(); 1359d3c351c5SMarko Zec 1360d3c351c5SMarko Zec /* 1361d3c351c5SMarko Zec * Perform interface-specific reassignment tasks, if provided by 1362d3c351c5SMarko Zec * the driver. 1363d3c351c5SMarko Zec */ 1364d3c351c5SMarko Zec if (ifp->if_reassign != NULL) 1365d3c351c5SMarko Zec ifp->if_reassign(ifp, new_vnet, NULL); 1366e0c14af9SMarko Zec 1367e0c14af9SMarko Zec /* 1368e0c14af9SMarko Zec * Switch to the context of the target vnet. 1369e0c14af9SMarko Zec */ 1370e0c14af9SMarko Zec CURVNET_SET_QUIET(new_vnet); 13714f6c66ccSMatt Macy restart: 1372d3c351c5SMarko Zec IFNET_WLOCK(); 13734f6c66ccSMatt Macy ifp->if_index = ifindex_alloc(&old); 13744f6c66ccSMatt Macy if (__predict_false(ifp->if_index == USHRT_MAX)) { 13754f6c66ccSMatt Macy IFNET_WUNLOCK(); 13764f6c66ccSMatt Macy epoch_wait_preempt(net_epoch_preempt); 13774f6c66ccSMatt Macy free(old, M_IFNET); 13784f6c66ccSMatt Macy goto restart; 13794f6c66ccSMatt Macy } 13804f6c66ccSMatt Macy ifnet_setbyindex(ifp->if_index, ifp); 1381e0c14af9SMarko Zec IFNET_WUNLOCK(); 1382e0c14af9SMarko Zec 1383c92a456bSHiroki Sato if_attach_internal(ifp, 1, ifc); 1384e0c14af9SMarko Zec 13853232273fSBjoern A. Zeeb #ifdef DEV_BPF 138605fc4164SBjoern A. Zeeb if (ifp->if_bpf == NULL) 138705fc4164SBjoern A. Zeeb bpfattach(ifp, bif_dlt, bif_hdrlen); 13883232273fSBjoern A. Zeeb #endif 138905fc4164SBjoern A. Zeeb 1390e0c14af9SMarko Zec CURVNET_RESTORE(); 1391c7bab2a7SKyle Evans return (0); 1392e0c14af9SMarko Zec } 1393be31e5e7SBjoern A. Zeeb 1394be31e5e7SBjoern A. Zeeb /* 1395be31e5e7SBjoern A. Zeeb * Move an ifnet to or from another child prison/vnet, specified by the jail id. 1396be31e5e7SBjoern A. Zeeb */ 1397be31e5e7SBjoern A. Zeeb static int 1398be31e5e7SBjoern A. Zeeb if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid) 1399be31e5e7SBjoern A. Zeeb { 1400be31e5e7SBjoern A. Zeeb struct prison *pr; 1401be31e5e7SBjoern A. Zeeb struct ifnet *difp; 1402c7bab2a7SKyle Evans int error; 1403a779388fSKristof Provost bool found; 140410108cb6SBjoern A. Zeeb bool shutdown; 1405be31e5e7SBjoern A. Zeeb 1406be31e5e7SBjoern A. Zeeb /* Try to find the prison within our visibility. */ 1407be31e5e7SBjoern A. Zeeb sx_slock(&allprison_lock); 1408be31e5e7SBjoern A. Zeeb pr = prison_find_child(td->td_ucred->cr_prison, jid); 1409be31e5e7SBjoern A. Zeeb sx_sunlock(&allprison_lock); 1410be31e5e7SBjoern A. Zeeb if (pr == NULL) 1411be31e5e7SBjoern A. Zeeb return (ENXIO); 1412be31e5e7SBjoern A. Zeeb prison_hold_locked(pr); 1413be31e5e7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 1414be31e5e7SBjoern A. Zeeb 1415be31e5e7SBjoern A. Zeeb /* Do not try to move the iface from and to the same prison. */ 1416be31e5e7SBjoern A. Zeeb if (pr->pr_vnet == ifp->if_vnet) { 1417be31e5e7SBjoern A. Zeeb prison_free(pr); 1418be31e5e7SBjoern A. Zeeb return (EEXIST); 1419be31e5e7SBjoern A. Zeeb } 1420be31e5e7SBjoern A. Zeeb 1421be31e5e7SBjoern A. Zeeb /* Make sure the named iface does not exists in the dst. prison/vnet. */ 1422be31e5e7SBjoern A. Zeeb /* XXX Lock interfaces to avoid races. */ 14239abb4862SMarko Zec CURVNET_SET_QUIET(pr->pr_vnet); 1424be31e5e7SBjoern A. Zeeb difp = ifunit(ifname); 1425be31e5e7SBjoern A. Zeeb if (difp != NULL) { 142689856f7eSBjoern A. Zeeb CURVNET_RESTORE(); 1427be31e5e7SBjoern A. Zeeb prison_free(pr); 1428be31e5e7SBjoern A. Zeeb return (EEXIST); 1429be31e5e7SBjoern A. Zeeb } 1430be31e5e7SBjoern A. Zeeb 143189856f7eSBjoern A. Zeeb /* Make sure the VNET is stable. */ 143210108cb6SBjoern A. Zeeb shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet); 143310108cb6SBjoern A. Zeeb if (shutdown) { 143489856f7eSBjoern A. Zeeb CURVNET_RESTORE(); 143589856f7eSBjoern A. Zeeb prison_free(pr); 143689856f7eSBjoern A. Zeeb return (EBUSY); 143789856f7eSBjoern A. Zeeb } 143889856f7eSBjoern A. Zeeb CURVNET_RESTORE(); 143989856f7eSBjoern A. Zeeb 1440a779388fSKristof Provost found = if_unlink_ifnet(ifp, true); 1441a779388fSKristof Provost MPASS(found); 1442a779388fSKristof Provost 1443be31e5e7SBjoern A. Zeeb /* Move the interface into the child jail/vnet. */ 1444c7bab2a7SKyle Evans error = if_vmove(ifp, pr->pr_vnet); 1445be31e5e7SBjoern A. Zeeb 1446c7bab2a7SKyle Evans /* Report the new if_xname back to the userland on success. */ 1447c7bab2a7SKyle Evans if (error == 0) 1448be31e5e7SBjoern A. Zeeb sprintf(ifname, "%s", ifp->if_xname); 1449be31e5e7SBjoern A. Zeeb 1450be31e5e7SBjoern A. Zeeb prison_free(pr); 1451c7bab2a7SKyle Evans return (error); 1452be31e5e7SBjoern A. Zeeb } 1453be31e5e7SBjoern A. Zeeb 1454be31e5e7SBjoern A. Zeeb static int 1455be31e5e7SBjoern A. Zeeb if_vmove_reclaim(struct thread *td, char *ifname, int jid) 1456be31e5e7SBjoern A. Zeeb { 1457be31e5e7SBjoern A. Zeeb struct prison *pr; 1458be31e5e7SBjoern A. Zeeb struct vnet *vnet_dst; 1459be31e5e7SBjoern A. Zeeb struct ifnet *ifp; 1460a779388fSKristof Provost int error, found; 146110108cb6SBjoern A. Zeeb bool shutdown; 1462be31e5e7SBjoern A. Zeeb 1463be31e5e7SBjoern A. Zeeb /* Try to find the prison within our visibility. */ 1464be31e5e7SBjoern A. Zeeb sx_slock(&allprison_lock); 1465be31e5e7SBjoern A. Zeeb pr = prison_find_child(td->td_ucred->cr_prison, jid); 1466be31e5e7SBjoern A. Zeeb sx_sunlock(&allprison_lock); 1467be31e5e7SBjoern A. Zeeb if (pr == NULL) 1468be31e5e7SBjoern A. Zeeb return (ENXIO); 1469be31e5e7SBjoern A. Zeeb prison_hold_locked(pr); 1470be31e5e7SBjoern A. Zeeb mtx_unlock(&pr->pr_mtx); 1471be31e5e7SBjoern A. Zeeb 1472be31e5e7SBjoern A. Zeeb /* Make sure the named iface exists in the source prison/vnet. */ 1473be31e5e7SBjoern A. Zeeb CURVNET_SET(pr->pr_vnet); 1474be31e5e7SBjoern A. Zeeb ifp = ifunit(ifname); /* XXX Lock to avoid races. */ 1475be31e5e7SBjoern A. Zeeb if (ifp == NULL) { 1476be31e5e7SBjoern A. Zeeb CURVNET_RESTORE(); 1477be31e5e7SBjoern A. Zeeb prison_free(pr); 1478be31e5e7SBjoern A. Zeeb return (ENXIO); 1479be31e5e7SBjoern A. Zeeb } 1480be31e5e7SBjoern A. Zeeb 1481be31e5e7SBjoern A. Zeeb /* Do not try to move the iface from and to the same prison. */ 1482be31e5e7SBjoern A. Zeeb vnet_dst = TD_TO_VNET(td); 1483be31e5e7SBjoern A. Zeeb if (vnet_dst == ifp->if_vnet) { 1484be31e5e7SBjoern A. Zeeb CURVNET_RESTORE(); 1485be31e5e7SBjoern A. Zeeb prison_free(pr); 1486be31e5e7SBjoern A. Zeeb return (EEXIST); 1487be31e5e7SBjoern A. Zeeb } 1488be31e5e7SBjoern A. Zeeb 148989856f7eSBjoern A. Zeeb /* Make sure the VNET is stable. */ 149010108cb6SBjoern A. Zeeb shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet); 149110108cb6SBjoern A. Zeeb if (shutdown) { 149289856f7eSBjoern A. Zeeb CURVNET_RESTORE(); 149389856f7eSBjoern A. Zeeb prison_free(pr); 149489856f7eSBjoern A. Zeeb return (EBUSY); 149589856f7eSBjoern A. Zeeb } 149689856f7eSBjoern A. Zeeb 1497be31e5e7SBjoern A. Zeeb /* Get interface back from child jail/vnet. */ 1498a779388fSKristof Provost found = if_unlink_ifnet(ifp, true); 1499a779388fSKristof Provost MPASS(found); 1500c7bab2a7SKyle Evans error = if_vmove(ifp, vnet_dst); 1501be31e5e7SBjoern A. Zeeb CURVNET_RESTORE(); 1502be31e5e7SBjoern A. Zeeb 1503c7bab2a7SKyle Evans /* Report the new if_xname back to the userland on success. */ 1504c7bab2a7SKyle Evans if (error == 0) 1505be31e5e7SBjoern A. Zeeb sprintf(ifname, "%s", ifp->if_xname); 1506be31e5e7SBjoern A. Zeeb 1507be31e5e7SBjoern A. Zeeb prison_free(pr); 1508c7bab2a7SKyle Evans return (error); 1509be31e5e7SBjoern A. Zeeb } 1510e0c14af9SMarko Zec #endif /* VIMAGE */ 1511e0c14af9SMarko Zec 15125500d3beSWarner Losh /* 15130dad3f0eSMax Laier * Add a group to an interface 15140dad3f0eSMax Laier */ 15150dad3f0eSMax Laier int 15160dad3f0eSMax Laier if_addgroup(struct ifnet *ifp, const char *groupname) 15170dad3f0eSMax Laier { 15180dad3f0eSMax Laier struct ifg_list *ifgl; 15190dad3f0eSMax Laier struct ifg_group *ifg = NULL; 15200dad3f0eSMax Laier struct ifg_member *ifgm; 1521d6d3f01eSGleb Smirnoff int new = 0; 15220dad3f0eSMax Laier 15230dad3f0eSMax Laier if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' && 15240dad3f0eSMax Laier groupname[strlen(groupname) - 1] <= '9') 15250dad3f0eSMax Laier return (EINVAL); 15260dad3f0eSMax Laier 15270dad3f0eSMax Laier IFNET_WLOCK(); 15284f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) 15290dad3f0eSMax Laier if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) { 15300dad3f0eSMax Laier IFNET_WUNLOCK(); 15310dad3f0eSMax Laier return (EEXIST); 15320dad3f0eSMax Laier } 15330dad3f0eSMax Laier 15343f197b13SMark Johnston if ((ifgl = malloc(sizeof(*ifgl), M_TEMP, M_NOWAIT)) == NULL) { 15350dad3f0eSMax Laier IFNET_WUNLOCK(); 15360dad3f0eSMax Laier return (ENOMEM); 15370dad3f0eSMax Laier } 15380dad3f0eSMax Laier 15393f197b13SMark Johnston if ((ifgm = malloc(sizeof(*ifgm), M_TEMP, M_NOWAIT)) == NULL) { 15400dad3f0eSMax Laier free(ifgl, M_TEMP); 15410dad3f0eSMax Laier IFNET_WUNLOCK(); 15420dad3f0eSMax Laier return (ENOMEM); 15430dad3f0eSMax Laier } 15440dad3f0eSMax Laier 15454f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) 15460dad3f0eSMax Laier if (!strcmp(ifg->ifg_group, groupname)) 15470dad3f0eSMax Laier break; 15480dad3f0eSMax Laier 15490dad3f0eSMax Laier if (ifg == NULL) { 15503f197b13SMark Johnston if ((ifg = malloc(sizeof(*ifg), M_TEMP, M_NOWAIT)) == NULL) { 15510dad3f0eSMax Laier free(ifgl, M_TEMP); 15520dad3f0eSMax Laier free(ifgm, M_TEMP); 15530dad3f0eSMax Laier IFNET_WUNLOCK(); 15540dad3f0eSMax Laier return (ENOMEM); 15550dad3f0eSMax Laier } 15560dad3f0eSMax Laier strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group)); 15570dad3f0eSMax Laier ifg->ifg_refcnt = 0; 15584f6c66ccSMatt Macy CK_STAILQ_INIT(&ifg->ifg_members); 15594f6c66ccSMatt Macy CK_STAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next); 1560d6d3f01eSGleb Smirnoff new = 1; 15610dad3f0eSMax Laier } 15620dad3f0eSMax Laier 15630dad3f0eSMax Laier ifg->ifg_refcnt++; 15640dad3f0eSMax Laier ifgl->ifgl_group = ifg; 15650dad3f0eSMax Laier ifgm->ifgm_ifp = ifp; 15660dad3f0eSMax Laier 1567137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 15684f6c66ccSMatt Macy CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next); 15694f6c66ccSMatt Macy CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next); 1570137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 15710dad3f0eSMax Laier 15720dad3f0eSMax Laier IFNET_WUNLOCK(); 15730dad3f0eSMax Laier 1574d6d3f01eSGleb Smirnoff if (new) 1575d6d3f01eSGleb Smirnoff EVENTHANDLER_INVOKE(group_attach_event, ifg); 15760dad3f0eSMax Laier EVENTHANDLER_INVOKE(group_change_event, groupname); 15770dad3f0eSMax Laier 15780dad3f0eSMax Laier return (0); 15790dad3f0eSMax Laier } 15800dad3f0eSMax Laier 15810dad3f0eSMax Laier /* 15823f197b13SMark Johnston * Helper function to remove a group out of an interface. Expects the global 15833f197b13SMark Johnston * ifnet lock to be write-locked, and drops it before returning. 15840dad3f0eSMax Laier */ 15853f197b13SMark Johnston static void 15863f197b13SMark Johnston _if_delgroup_locked(struct ifnet *ifp, struct ifg_list *ifgl, 15873f197b13SMark Johnston const char *groupname) 15880dad3f0eSMax Laier { 15890dad3f0eSMax Laier struct ifg_member *ifgm; 15903f197b13SMark Johnston bool freeifgl; 15910dad3f0eSMax Laier 15923f197b13SMark Johnston IFNET_WLOCK_ASSERT(); 15930dad3f0eSMax Laier 1594137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 15954f6c66ccSMatt Macy CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next); 1596137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 15970dad3f0eSMax Laier 15983f197b13SMark Johnston CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) { 15993f197b13SMark Johnston if (ifgm->ifgm_ifp == ifp) { 16003f197b13SMark Johnston CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm, 16013f197b13SMark Johnston ifg_member, ifgm_next); 16020dad3f0eSMax Laier break; 16033f197b13SMark Johnston } 16043f197b13SMark Johnston } 16050dad3f0eSMax Laier 16060dad3f0eSMax Laier if (--ifgl->ifgl_group->ifg_refcnt == 0) { 16073f197b13SMark Johnston CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group, 16083f197b13SMark Johnston ifg_next); 16093f197b13SMark Johnston freeifgl = true; 16103f197b13SMark Johnston } else { 16113f197b13SMark Johnston freeifgl = false; 16124f6c66ccSMatt Macy } 16130dad3f0eSMax Laier IFNET_WUNLOCK(); 16140dad3f0eSMax Laier 16154f6c66ccSMatt Macy epoch_wait_preempt(net_epoch_preempt); 16164f6c66ccSMatt Macy if (freeifgl) { 16174f6c66ccSMatt Macy EVENTHANDLER_INVOKE(group_detach_event, ifgl->ifgl_group); 16184f6c66ccSMatt Macy free(ifgl->ifgl_group, M_TEMP); 16194f6c66ccSMatt Macy } 16204f6c66ccSMatt Macy free(ifgm, M_TEMP); 16210dad3f0eSMax Laier free(ifgl, M_TEMP); 16220dad3f0eSMax Laier 16230dad3f0eSMax Laier EVENTHANDLER_INVOKE(group_change_event, groupname); 16243f197b13SMark Johnston } 16253f197b13SMark Johnston 16263f197b13SMark Johnston /* 16273f197b13SMark Johnston * Remove a group from an interface 16283f197b13SMark Johnston */ 16293f197b13SMark Johnston int 16303f197b13SMark Johnston if_delgroup(struct ifnet *ifp, const char *groupname) 16313f197b13SMark Johnston { 16323f197b13SMark Johnston struct ifg_list *ifgl; 16333f197b13SMark Johnston 16343f197b13SMark Johnston IFNET_WLOCK(); 16353f197b13SMark Johnston CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) 16363f197b13SMark Johnston if (strcmp(ifgl->ifgl_group->ifg_group, groupname) == 0) 16373f197b13SMark Johnston break; 16383f197b13SMark Johnston if (ifgl == NULL) { 16393f197b13SMark Johnston IFNET_WUNLOCK(); 16403f197b13SMark Johnston return (ENOENT); 16413f197b13SMark Johnston } 16423f197b13SMark Johnston 16433f197b13SMark Johnston _if_delgroup_locked(ifp, ifgl, groupname); 16440dad3f0eSMax Laier 16450dad3f0eSMax Laier return (0); 16460dad3f0eSMax Laier } 16470dad3f0eSMax Laier 16480dad3f0eSMax Laier /* 16498623f9fdSMax Laier * Remove an interface from all groups 16508623f9fdSMax Laier */ 16518623f9fdSMax Laier static void 16528623f9fdSMax Laier if_delgroups(struct ifnet *ifp) 16538623f9fdSMax Laier { 16548623f9fdSMax Laier struct ifg_list *ifgl; 16558623f9fdSMax Laier char groupname[IFNAMSIZ]; 16568623f9fdSMax Laier 16578623f9fdSMax Laier IFNET_WLOCK(); 16583f197b13SMark Johnston while ((ifgl = CK_STAILQ_FIRST(&ifp->if_groups)) != NULL) { 16598623f9fdSMax Laier strlcpy(groupname, ifgl->ifgl_group->ifg_group, IFNAMSIZ); 16603f197b13SMark Johnston _if_delgroup_locked(ifp, ifgl, groupname); 16618623f9fdSMax Laier IFNET_WLOCK(); 16628623f9fdSMax Laier } 16638623f9fdSMax Laier IFNET_WUNLOCK(); 16648623f9fdSMax Laier } 16658623f9fdSMax Laier 1666756181b8SBrooks Davis static char * 1667756181b8SBrooks Davis ifgr_group_get(void *ifgrp) 1668756181b8SBrooks Davis { 1669756181b8SBrooks Davis union ifgroupreq_union *ifgrup; 1670756181b8SBrooks Davis 1671756181b8SBrooks Davis ifgrup = ifgrp; 1672756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32 1673756181b8SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) 1674756181b8SBrooks Davis return (&ifgrup->ifgr32.ifgr_ifgru.ifgru_group[0]); 1675756181b8SBrooks Davis #endif 1676756181b8SBrooks Davis return (&ifgrup->ifgr.ifgr_ifgru.ifgru_group[0]); 1677756181b8SBrooks Davis } 1678756181b8SBrooks Davis 1679756181b8SBrooks Davis static struct ifg_req * 1680756181b8SBrooks Davis ifgr_groups_get(void *ifgrp) 1681756181b8SBrooks Davis { 1682756181b8SBrooks Davis union ifgroupreq_union *ifgrup; 1683756181b8SBrooks Davis 1684756181b8SBrooks Davis ifgrup = ifgrp; 1685756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32 1686756181b8SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) 1687756181b8SBrooks Davis return ((struct ifg_req *)(uintptr_t) 1688756181b8SBrooks Davis ifgrup->ifgr32.ifgr_ifgru.ifgru_groups); 1689756181b8SBrooks Davis #endif 1690756181b8SBrooks Davis return (ifgrup->ifgr.ifgr_ifgru.ifgru_groups); 1691756181b8SBrooks Davis } 1692756181b8SBrooks Davis 16938623f9fdSMax Laier /* 1694756181b8SBrooks Davis * Stores all groups from an interface in memory pointed to by ifgr. 16950dad3f0eSMax Laier */ 16960dad3f0eSMax Laier static int 1697756181b8SBrooks Davis if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp) 16980dad3f0eSMax Laier { 16990dad3f0eSMax Laier int len, error; 17000dad3f0eSMax Laier struct ifg_list *ifgl; 17010dad3f0eSMax Laier struct ifg_req ifgrq, *ifgp; 17020dad3f0eSMax Laier 1703b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 1704b8a6e03fSGleb Smirnoff 17050dad3f0eSMax Laier if (ifgr->ifgr_len == 0) { 17064f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) 17070dad3f0eSMax Laier ifgr->ifgr_len += sizeof(struct ifg_req); 17080dad3f0eSMax Laier return (0); 17090dad3f0eSMax Laier } 17100dad3f0eSMax Laier 17110dad3f0eSMax Laier len = ifgr->ifgr_len; 1712756181b8SBrooks Davis ifgp = ifgr_groups_get(ifgr); 17130dad3f0eSMax Laier /* XXX: wire */ 17144f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) { 1715b8a6e03fSGleb Smirnoff if (len < sizeof(ifgrq)) 17160dad3f0eSMax Laier return (EINVAL); 17170dad3f0eSMax Laier bzero(&ifgrq, sizeof ifgrq); 17180dad3f0eSMax Laier strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group, 17190dad3f0eSMax Laier sizeof(ifgrq.ifgrq_group)); 1720b8a6e03fSGleb Smirnoff if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) 17210dad3f0eSMax Laier return (error); 17220dad3f0eSMax Laier len -= sizeof(ifgrq); 17230dad3f0eSMax Laier ifgp++; 17240dad3f0eSMax Laier } 17250dad3f0eSMax Laier 17260dad3f0eSMax Laier return (0); 17270dad3f0eSMax Laier } 17280dad3f0eSMax Laier 17290dad3f0eSMax Laier /* 1730756181b8SBrooks Davis * Stores all members of a group in memory pointed to by igfr 17310dad3f0eSMax Laier */ 17320dad3f0eSMax Laier static int 1733756181b8SBrooks Davis if_getgroupmembers(struct ifgroupreq *ifgr) 17340dad3f0eSMax Laier { 17350dad3f0eSMax Laier struct ifg_group *ifg; 17360dad3f0eSMax Laier struct ifg_member *ifgm; 17370dad3f0eSMax Laier struct ifg_req ifgrq, *ifgp; 17380dad3f0eSMax Laier int len, error; 17390dad3f0eSMax Laier 17400dad3f0eSMax Laier IFNET_RLOCK(); 17414f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next) 17423f197b13SMark Johnston if (strcmp(ifg->ifg_group, ifgr->ifgr_name) == 0) 17430dad3f0eSMax Laier break; 17440dad3f0eSMax Laier if (ifg == NULL) { 17450dad3f0eSMax Laier IFNET_RUNLOCK(); 17460dad3f0eSMax Laier return (ENOENT); 17470dad3f0eSMax Laier } 17480dad3f0eSMax Laier 17490dad3f0eSMax Laier if (ifgr->ifgr_len == 0) { 17504f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) 17510dad3f0eSMax Laier ifgr->ifgr_len += sizeof(ifgrq); 17520dad3f0eSMax Laier IFNET_RUNLOCK(); 17530dad3f0eSMax Laier return (0); 17540dad3f0eSMax Laier } 17550dad3f0eSMax Laier 17560dad3f0eSMax Laier len = ifgr->ifgr_len; 1757756181b8SBrooks Davis ifgp = ifgr_groups_get(ifgr); 17584f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) { 17590dad3f0eSMax Laier if (len < sizeof(ifgrq)) { 17600dad3f0eSMax Laier IFNET_RUNLOCK(); 17610dad3f0eSMax Laier return (EINVAL); 17620dad3f0eSMax Laier } 17630dad3f0eSMax Laier bzero(&ifgrq, sizeof ifgrq); 17640dad3f0eSMax Laier strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname, 17650dad3f0eSMax Laier sizeof(ifgrq.ifgrq_member)); 17660dad3f0eSMax Laier if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) { 17670dad3f0eSMax Laier IFNET_RUNLOCK(); 17680dad3f0eSMax Laier return (error); 17690dad3f0eSMax Laier } 17700dad3f0eSMax Laier len -= sizeof(ifgrq); 17710dad3f0eSMax Laier ifgp++; 17720dad3f0eSMax Laier } 17730dad3f0eSMax Laier IFNET_RUNLOCK(); 17740dad3f0eSMax Laier 17750dad3f0eSMax Laier return (0); 17760dad3f0eSMax Laier } 17770dad3f0eSMax Laier 17780dad3f0eSMax Laier /* 1779112f50ffSGleb Smirnoff * Return counter values from counter(9)s stored in ifnet. 1780e6485f73SGleb Smirnoff */ 1781e6485f73SGleb Smirnoff uint64_t 17821b7fb1d9SGleb Smirnoff if_get_counter_default(struct ifnet *ifp, ift_counter cnt) 1783e6485f73SGleb Smirnoff { 1784e6485f73SGleb Smirnoff 1785112f50ffSGleb Smirnoff KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); 1786112f50ffSGleb Smirnoff 1787112f50ffSGleb Smirnoff return (counter_u64_fetch(ifp->if_counters[cnt])); 1788e6485f73SGleb Smirnoff } 1789e6485f73SGleb Smirnoff 1790e6485f73SGleb Smirnoff /* 17910b7b006cSGleb Smirnoff * Increase an ifnet counter. Usually used for counters shared 17920b7b006cSGleb Smirnoff * between the stack and a driver, but function supports them all. 17930b7b006cSGleb Smirnoff */ 17940b7b006cSGleb Smirnoff void 17951b7fb1d9SGleb Smirnoff if_inc_counter(struct ifnet *ifp, ift_counter cnt, int64_t inc) 17960b7b006cSGleb Smirnoff { 17970b7b006cSGleb Smirnoff 1798112f50ffSGleb Smirnoff KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt)); 1799112f50ffSGleb Smirnoff 1800112f50ffSGleb Smirnoff counter_u64_add(ifp->if_counters[cnt], inc); 18010b7b006cSGleb Smirnoff } 18020b7b006cSGleb Smirnoff 18030b7b006cSGleb Smirnoff /* 1804e6485f73SGleb Smirnoff * Copy data from ifnet to userland API structure if_data. 1805e6485f73SGleb Smirnoff */ 1806e6485f73SGleb Smirnoff void 1807e6485f73SGleb Smirnoff if_data_copy(struct ifnet *ifp, struct if_data *ifd) 1808e6485f73SGleb Smirnoff { 1809e6485f73SGleb Smirnoff 1810e6485f73SGleb Smirnoff ifd->ifi_type = ifp->if_type; 1811e6485f73SGleb Smirnoff ifd->ifi_physical = 0; 1812e6485f73SGleb Smirnoff ifd->ifi_addrlen = ifp->if_addrlen; 1813e6485f73SGleb Smirnoff ifd->ifi_hdrlen = ifp->if_hdrlen; 1814e6485f73SGleb Smirnoff ifd->ifi_link_state = ifp->if_link_state; 1815e6485f73SGleb Smirnoff ifd->ifi_vhid = 0; 1816e6485f73SGleb Smirnoff ifd->ifi_datalen = sizeof(struct if_data); 1817e6485f73SGleb Smirnoff ifd->ifi_mtu = ifp->if_mtu; 1818e6485f73SGleb Smirnoff ifd->ifi_metric = ifp->if_metric; 1819e6485f73SGleb Smirnoff ifd->ifi_baudrate = ifp->if_baudrate; 1820e6485f73SGleb Smirnoff ifd->ifi_hwassist = ifp->if_hwassist; 1821e6485f73SGleb Smirnoff ifd->ifi_epoch = ifp->if_epoch; 1822e6485f73SGleb Smirnoff ifd->ifi_lastchange = ifp->if_lastchange; 1823e6485f73SGleb Smirnoff 1824e6485f73SGleb Smirnoff ifd->ifi_ipackets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS); 1825e6485f73SGleb Smirnoff ifd->ifi_ierrors = ifp->if_get_counter(ifp, IFCOUNTER_IERRORS); 1826e6485f73SGleb Smirnoff ifd->ifi_opackets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS); 1827e6485f73SGleb Smirnoff ifd->ifi_oerrors = ifp->if_get_counter(ifp, IFCOUNTER_OERRORS); 1828e6485f73SGleb Smirnoff ifd->ifi_collisions = ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS); 1829e6485f73SGleb Smirnoff ifd->ifi_ibytes = ifp->if_get_counter(ifp, IFCOUNTER_IBYTES); 1830e6485f73SGleb Smirnoff ifd->ifi_obytes = ifp->if_get_counter(ifp, IFCOUNTER_OBYTES); 1831e6485f73SGleb Smirnoff ifd->ifi_imcasts = ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS); 1832e6485f73SGleb Smirnoff ifd->ifi_omcasts = ifp->if_get_counter(ifp, IFCOUNTER_OMCASTS); 1833e6485f73SGleb Smirnoff ifd->ifi_iqdrops = ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS); 1834e6485f73SGleb Smirnoff ifd->ifi_oqdrops = ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS); 1835e6485f73SGleb Smirnoff ifd->ifi_noproto = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO); 1836e6485f73SGleb Smirnoff } 1837e6485f73SGleb Smirnoff 1838e6485f73SGleb Smirnoff /* 1839e8aa8bddSGleb Smirnoff * Initialization, destruction and refcounting functions for ifaddrs. 18401099f828SRobert Watson */ 184146758960SGleb Smirnoff struct ifaddr * 184246758960SGleb Smirnoff ifa_alloc(size_t size, int flags) 18431099f828SRobert Watson { 184446758960SGleb Smirnoff struct ifaddr *ifa; 184546758960SGleb Smirnoff 184646758960SGleb Smirnoff KASSERT(size >= sizeof(struct ifaddr), 184746758960SGleb Smirnoff ("%s: invalid size %zu", __func__, size)); 184846758960SGleb Smirnoff 184946758960SGleb Smirnoff ifa = malloc(size, M_IFADDR, M_ZERO | flags); 185046758960SGleb Smirnoff if (ifa == NULL) 185146758960SGleb Smirnoff return (NULL); 18521099f828SRobert Watson 18537caf4ab7SGleb Smirnoff if ((ifa->ifa_opackets = counter_u64_alloc(flags)) == NULL) 18547caf4ab7SGleb Smirnoff goto fail; 18557caf4ab7SGleb Smirnoff if ((ifa->ifa_ipackets = counter_u64_alloc(flags)) == NULL) 18567caf4ab7SGleb Smirnoff goto fail; 18577caf4ab7SGleb Smirnoff if ((ifa->ifa_obytes = counter_u64_alloc(flags)) == NULL) 18587caf4ab7SGleb Smirnoff goto fail; 18597caf4ab7SGleb Smirnoff if ((ifa->ifa_ibytes = counter_u64_alloc(flags)) == NULL) 18607caf4ab7SGleb Smirnoff goto fail; 18617caf4ab7SGleb Smirnoff 18621099f828SRobert Watson refcount_init(&ifa->ifa_refcnt, 1); 186346758960SGleb Smirnoff 186446758960SGleb Smirnoff return (ifa); 18657caf4ab7SGleb Smirnoff 18667caf4ab7SGleb Smirnoff fail: 18677caf4ab7SGleb Smirnoff /* free(NULL) is okay */ 18687caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_opackets); 18697caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_ipackets); 18707caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_obytes); 18717caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_ibytes); 18727caf4ab7SGleb Smirnoff free(ifa, M_IFADDR); 18737caf4ab7SGleb Smirnoff 18747caf4ab7SGleb Smirnoff return (NULL); 18751099f828SRobert Watson } 18761099f828SRobert Watson 18771099f828SRobert Watson void 18781099f828SRobert Watson ifa_ref(struct ifaddr *ifa) 18791099f828SRobert Watson { 1880600eade2SAlexander V. Chernikov u_int old; 18811099f828SRobert Watson 1882600eade2SAlexander V. Chernikov old = refcount_acquire(&ifa->ifa_refcnt); 1883600eade2SAlexander V. Chernikov KASSERT(old > 0, ("%s: ifa %p has 0 refs", __func__, ifa)); 1884600eade2SAlexander V. Chernikov } 1885600eade2SAlexander V. Chernikov 1886600eade2SAlexander V. Chernikov int 1887600eade2SAlexander V. Chernikov ifa_try_ref(struct ifaddr *ifa) 1888600eade2SAlexander V. Chernikov { 1889600eade2SAlexander V. Chernikov 1890600eade2SAlexander V. Chernikov NET_EPOCH_ASSERT(); 1891600eade2SAlexander V. Chernikov return (refcount_acquire_if_not_zero(&ifa->ifa_refcnt)); 18921099f828SRobert Watson } 18931099f828SRobert Watson 1894d7c5a620SMatt Macy static void 1895d7c5a620SMatt Macy ifa_destroy(epoch_context_t ctx) 18961099f828SRobert Watson { 1897d7c5a620SMatt Macy struct ifaddr *ifa; 18981099f828SRobert Watson 1899d7c5a620SMatt Macy ifa = __containerof(ctx, struct ifaddr, ifa_epoch_ctx); 19007caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_opackets); 19017caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_ipackets); 19027caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_obytes); 19037caf4ab7SGleb Smirnoff counter_u64_free(ifa->ifa_ibytes); 19041099f828SRobert Watson free(ifa, M_IFADDR); 19051099f828SRobert Watson } 1906d7c5a620SMatt Macy 1907d7c5a620SMatt Macy void 1908d7c5a620SMatt Macy ifa_free(struct ifaddr *ifa) 1909d7c5a620SMatt Macy { 1910d7c5a620SMatt Macy 1911d7c5a620SMatt Macy if (refcount_release(&ifa->ifa_refcnt)) 19122a4bd982SGleb Smirnoff NET_EPOCH_CALL(ifa_destroy, &ifa->ifa_epoch_ctx); 19131099f828SRobert Watson } 19141099f828SRobert Watson 19151099f828SRobert Watson /* 191640d8a302SBruce M Simpson * XXX: Because sockaddr_dl has deeper structure than the sockaddr 191740d8a302SBruce M Simpson * structs used to represent other address families, it is necessary 191840d8a302SBruce M Simpson * to perform a different comparison. 191940d8a302SBruce M Simpson */ 192040d8a302SBruce M Simpson 192140d8a302SBruce M Simpson #define sa_dl_equal(a1, a2) \ 1922441f9243SAlexander V. Chernikov ((((const struct sockaddr_dl *)(a1))->sdl_len == \ 1923441f9243SAlexander V. Chernikov ((const struct sockaddr_dl *)(a2))->sdl_len) && \ 1924441f9243SAlexander V. Chernikov (bcmp(CLLADDR((const struct sockaddr_dl *)(a1)), \ 1925441f9243SAlexander V. Chernikov CLLADDR((const struct sockaddr_dl *)(a2)), \ 1926441f9243SAlexander V. Chernikov ((const struct sockaddr_dl *)(a1))->sdl_alen) == 0)) 192719fc74fbSJeffrey Hsu 192830aad87dSBrooks Davis /* 1929df8bae1dSRodney W. Grimes * Locate an interface based on a complete address. 1930df8bae1dSRodney W. Grimes */ 1931df8bae1dSRodney W. Grimes /*ARGSUSED*/ 19324f6c66ccSMatt Macy struct ifaddr * 19334f6c66ccSMatt Macy ifa_ifwithaddr(const struct sockaddr *addr) 1934df8bae1dSRodney W. Grimes { 19350b59d917SJonathan Lemon struct ifnet *ifp; 19360b59d917SJonathan Lemon struct ifaddr *ifa; 1937df8bae1dSRodney W. Grimes 1938b8a6e03fSGleb Smirnoff NET_EPOCH_ASSERT(); 1939b8a6e03fSGleb Smirnoff 19404f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 1941d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1942df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 1943df8bae1dSRodney W. Grimes continue; 1944ab5ed8a5SRobert Watson if (sa_equal(addr, ifa->ifa_addr)) { 19450b59d917SJonathan Lemon goto done; 1946ab5ed8a5SRobert Watson } 194782cd038dSYoshinobu Inoue /* IP6 doesn't have broadcast */ 19480b59d917SJonathan Lemon if ((ifp->if_flags & IFF_BROADCAST) && 19490b59d917SJonathan Lemon ifa->ifa_broadaddr && 195082cd038dSYoshinobu Inoue ifa->ifa_broadaddr->sa_len != 0 && 1951ab5ed8a5SRobert Watson sa_equal(ifa->ifa_broadaddr, addr)) { 19520b59d917SJonathan Lemon goto done; 19530b59d917SJonathan Lemon } 1954ab5ed8a5SRobert Watson } 1955ab5ed8a5SRobert Watson } 19560b59d917SJonathan Lemon ifa = NULL; 19570b59d917SJonathan Lemon done: 1958df8bae1dSRodney W. Grimes return (ifa); 1959df8bae1dSRodney W. Grimes } 19600b59d917SJonathan Lemon 19618896f83aSRobert Watson int 1962441f9243SAlexander V. Chernikov ifa_ifwithaddr_check(const struct sockaddr *addr) 19638896f83aSRobert Watson { 1964a68cc388SGleb Smirnoff struct epoch_tracker et; 19654f6c66ccSMatt Macy int rc; 19668896f83aSRobert Watson 1967a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 19684f6c66ccSMatt Macy rc = (ifa_ifwithaddr(addr) != NULL); 1969a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 19704f6c66ccSMatt Macy return (rc); 19718896f83aSRobert Watson } 19728896f83aSRobert Watson 1973df8bae1dSRodney W. Grimes /* 1974773725a2SAndre Oppermann * Locate an interface based on the broadcast address. 1975773725a2SAndre Oppermann */ 1976773725a2SAndre Oppermann /* ARGSUSED */ 1977773725a2SAndre Oppermann struct ifaddr * 1978441f9243SAlexander V. Chernikov ifa_ifwithbroadaddr(const struct sockaddr *addr, int fibnum) 1979773725a2SAndre Oppermann { 1980773725a2SAndre Oppermann struct ifnet *ifp; 1981773725a2SAndre Oppermann struct ifaddr *ifa; 1982773725a2SAndre Oppermann 198397168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 19844f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 19854f8585e0SAlan Somers if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum)) 19864f8585e0SAlan Somers continue; 1987d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 1988773725a2SAndre Oppermann if (ifa->ifa_addr->sa_family != addr->sa_family) 1989773725a2SAndre Oppermann continue; 1990773725a2SAndre Oppermann if ((ifp->if_flags & IFF_BROADCAST) && 1991773725a2SAndre Oppermann ifa->ifa_broadaddr && 1992773725a2SAndre Oppermann ifa->ifa_broadaddr->sa_len != 0 && 1993ab5ed8a5SRobert Watson sa_equal(ifa->ifa_broadaddr, addr)) { 1994773725a2SAndre Oppermann goto done; 1995773725a2SAndre Oppermann } 1996ab5ed8a5SRobert Watson } 1997ab5ed8a5SRobert Watson } 1998773725a2SAndre Oppermann ifa = NULL; 1999773725a2SAndre Oppermann done: 2000773725a2SAndre Oppermann return (ifa); 2001773725a2SAndre Oppermann } 2002773725a2SAndre Oppermann 2003773725a2SAndre Oppermann /* 2004df8bae1dSRodney W. Grimes * Locate the point to point interface with a given destination address. 2005df8bae1dSRodney W. Grimes */ 2006df8bae1dSRodney W. Grimes /*ARGSUSED*/ 2007df8bae1dSRodney W. Grimes struct ifaddr * 2008441f9243SAlexander V. Chernikov ifa_ifwithdstaddr(const struct sockaddr *addr, int fibnum) 2009df8bae1dSRodney W. Grimes { 20100b59d917SJonathan Lemon struct ifnet *ifp; 20110b59d917SJonathan Lemon struct ifaddr *ifa; 2012df8bae1dSRodney W. Grimes 201397168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 20144f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 20150b59d917SJonathan Lemon if ((ifp->if_flags & IFF_POINTOPOINT) == 0) 20160b59d917SJonathan Lemon continue; 20172f308a34SAlan Somers if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum)) 20180cfee0c2SAlan Somers continue; 2019d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 2020df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != addr->sa_family) 2021df8bae1dSRodney W. Grimes continue; 2022f0c04221SBjoern A. Zeeb if (ifa->ifa_dstaddr != NULL && 2023ab5ed8a5SRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) { 20240b59d917SJonathan Lemon goto done; 2025df8bae1dSRodney W. Grimes } 20260b59d917SJonathan Lemon } 2027ab5ed8a5SRobert Watson } 20280b59d917SJonathan Lemon ifa = NULL; 20290b59d917SJonathan Lemon done: 20300b59d917SJonathan Lemon return (ifa); 2031df8bae1dSRodney W. Grimes } 2032df8bae1dSRodney W. Grimes 2033df8bae1dSRodney W. Grimes /* 2034df8bae1dSRodney W. Grimes * Find an interface on a specific network. If many, choice 2035df8bae1dSRodney W. Grimes * is most specific found. 2036df8bae1dSRodney W. Grimes */ 2037df8bae1dSRodney W. Grimes struct ifaddr * 2038441f9243SAlexander V. Chernikov ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum) 2039df8bae1dSRodney W. Grimes { 204072fd1b6aSDag-Erling Smørgrav struct ifnet *ifp; 204172fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 20428c0fec80SRobert Watson struct ifaddr *ifa_maybe = NULL; 2043df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 2044441f9243SAlexander V. Chernikov const char *addr_data = addr->sa_data, *cplim; 2045df8bae1dSRodney W. Grimes 204697168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 20477e2a6151SJulian Elischer /* 20487e2a6151SJulian Elischer * AF_LINK addresses can be looked up directly by their index number, 20497e2a6151SJulian Elischer * so do that if we can. 20507e2a6151SJulian Elischer */ 2051df8bae1dSRodney W. Grimes if (af == AF_LINK) { 2052441f9243SAlexander V. Chernikov const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)addr; 2053603724d3SBjoern A. Zeeb if (sdl->sdl_index && sdl->sdl_index <= V_if_index) 2054f9132cebSJonathan Lemon return (ifaddr_byindex(sdl->sdl_index)); 2055df8bae1dSRodney W. Grimes } 20567e2a6151SJulian Elischer 20577e2a6151SJulian Elischer /* 20588c0fec80SRobert Watson * Scan though each interface, looking for ones that have addresses 205921ee61a6SGleb Smirnoff * in this address family and the requested fib. 20607e2a6151SJulian Elischer */ 20614f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 20622f308a34SAlan Somers if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum)) 20630cfee0c2SAlan Somers continue; 2064d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 2065441f9243SAlexander V. Chernikov const char *cp, *cp2, *cp3; 2066df8bae1dSRodney W. Grimes 2067523a02aaSDavid Greenman if (ifa->ifa_addr->sa_family != af) 2068df8bae1dSRodney W. Grimes next: continue; 20690ed6142bSQing Li if (af == AF_INET && 20700ed6142bSQing Li ifp->if_flags & IFF_POINTOPOINT && !ignore_ptp) { 20717e2a6151SJulian Elischer /* 20727e2a6151SJulian Elischer * This is a bit broken as it doesn't 20737e2a6151SJulian Elischer * take into account that the remote end may 20747e2a6151SJulian Elischer * be a single node in the network we are 20757e2a6151SJulian Elischer * looking for. 20767e2a6151SJulian Elischer * The trouble is that we don't know the 20777e2a6151SJulian Elischer * netmask for the remote end. 20787e2a6151SJulian Elischer */ 2079f0c04221SBjoern A. Zeeb if (ifa->ifa_dstaddr != NULL && 2080ab5ed8a5SRobert Watson sa_equal(addr, ifa->ifa_dstaddr)) { 20810b59d917SJonathan Lemon goto done; 2082ab5ed8a5SRobert Watson } 20833740e2adSDavid Greenman } else { 20847e2a6151SJulian Elischer /* 20857e2a6151SJulian Elischer * Scan all the bits in the ifa's address. 20867e2a6151SJulian Elischer * If a bit dissagrees with what we are 20877e2a6151SJulian Elischer * looking for, mask it with the netmask 20887e2a6151SJulian Elischer * to see if it really matters. 20897e2a6151SJulian Elischer * (A byte at a time) 20907e2a6151SJulian Elischer */ 2091523a02aaSDavid Greenman if (ifa->ifa_netmask == 0) 2092523a02aaSDavid Greenman continue; 2093df8bae1dSRodney W. Grimes cp = addr_data; 2094df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 2095df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 20967e2a6151SJulian Elischer cplim = ifa->ifa_netmask->sa_len 20977e2a6151SJulian Elischer + (char *)ifa->ifa_netmask; 2098df8bae1dSRodney W. Grimes while (cp3 < cplim) 2099df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3++) 21007e2a6151SJulian Elischer goto next; /* next address! */ 21017e2a6151SJulian Elischer /* 21027e2a6151SJulian Elischer * If the netmask of what we just found 21037e2a6151SJulian Elischer * is more specific than what we had before 210424421c1cSGleb Smirnoff * (if we had one), or if the virtual status 210524421c1cSGleb Smirnoff * of new prefix is better than of the old one, 210624421c1cSGleb Smirnoff * then remember the new one before continuing 210724421c1cSGleb Smirnoff * to search for an even better one. 21087e2a6151SJulian Elischer */ 21098c0fec80SRobert Watson if (ifa_maybe == NULL || 211024421c1cSGleb Smirnoff ifa_preferred(ifa_maybe, ifa) || 2111df8bae1dSRodney W. Grimes rn_refines((caddr_t)ifa->ifa_netmask, 21128c0fec80SRobert Watson (caddr_t)ifa_maybe->ifa_netmask)) { 2113df8bae1dSRodney W. Grimes ifa_maybe = ifa; 21148c0fec80SRobert Watson } 2115df8bae1dSRodney W. Grimes } 2116b2af64fdSDavid Greenman } 2117b2af64fdSDavid Greenman } 21180b59d917SJonathan Lemon ifa = ifa_maybe; 21198c0fec80SRobert Watson ifa_maybe = NULL; 21200b59d917SJonathan Lemon done: 21210b59d917SJonathan Lemon return (ifa); 2122df8bae1dSRodney W. Grimes } 2123df8bae1dSRodney W. Grimes 2124df8bae1dSRodney W. Grimes /* 2125df8bae1dSRodney W. Grimes * Find an interface address specific to an interface best matching 2126df8bae1dSRodney W. Grimes * a given address. 2127df8bae1dSRodney W. Grimes */ 2128df8bae1dSRodney W. Grimes struct ifaddr * 2129441f9243SAlexander V. Chernikov ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp) 2130df8bae1dSRodney W. Grimes { 213172fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 2132441f9243SAlexander V. Chernikov const char *cp, *cp2, *cp3; 213372fd1b6aSDag-Erling Smørgrav char *cplim; 21348c0fec80SRobert Watson struct ifaddr *ifa_maybe = NULL; 2135df8bae1dSRodney W. Grimes u_int af = addr->sa_family; 2136df8bae1dSRodney W. Grimes 2137df8bae1dSRodney W. Grimes if (af >= AF_MAX) 2138cd292f12SBjoern A. Zeeb return (NULL); 21396573d758SMatt Macy 214097168be8SGleb Smirnoff NET_EPOCH_ASSERT(); 2141d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 2142df8bae1dSRodney W. Grimes if (ifa->ifa_addr->sa_family != af) 2143df8bae1dSRodney W. Grimes continue; 21448c0fec80SRobert Watson if (ifa_maybe == NULL) 2145df8bae1dSRodney W. Grimes ifa_maybe = ifa; 2146df8bae1dSRodney W. Grimes if (ifa->ifa_netmask == 0) { 2147d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_addr) || 2148d8d5b10eSRobert Watson (ifa->ifa_dstaddr && 2149d8d5b10eSRobert Watson sa_equal(addr, ifa->ifa_dstaddr))) 21502defe5cdSJonathan Lemon goto done; 2151df8bae1dSRodney W. Grimes continue; 2152df8bae1dSRodney W. Grimes } 2153b2af64fdSDavid Greenman if (ifp->if_flags & IFF_POINTOPOINT) { 2154d8d5b10eSRobert Watson if (sa_equal(addr, ifa->ifa_dstaddr)) 2155a8637146SJonathan Lemon goto done; 21563740e2adSDavid Greenman } else { 2157df8bae1dSRodney W. Grimes cp = addr->sa_data; 2158df8bae1dSRodney W. Grimes cp2 = ifa->ifa_addr->sa_data; 2159df8bae1dSRodney W. Grimes cp3 = ifa->ifa_netmask->sa_data; 2160df8bae1dSRodney W. Grimes cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask; 2161df8bae1dSRodney W. Grimes for (; cp3 < cplim; cp3++) 2162df8bae1dSRodney W. Grimes if ((*cp++ ^ *cp2++) & *cp3) 2163df8bae1dSRodney W. Grimes break; 2164df8bae1dSRodney W. Grimes if (cp3 == cplim) 21652defe5cdSJonathan Lemon goto done; 2166df8bae1dSRodney W. Grimes } 2167b2af64fdSDavid Greenman } 2168f9132cebSJonathan Lemon ifa = ifa_maybe; 2169f9132cebSJonathan Lemon done: 2170f9132cebSJonathan Lemon return (ifa); 2171df8bae1dSRodney W. Grimes } 2172df8bae1dSRodney W. Grimes 217324421c1cSGleb Smirnoff /* 217424421c1cSGleb Smirnoff * See whether new ifa is better than current one: 217524421c1cSGleb Smirnoff * 1) A non-virtual one is preferred over virtual. 217624421c1cSGleb Smirnoff * 2) A virtual in master state preferred over any other state. 217724421c1cSGleb Smirnoff * 217824421c1cSGleb Smirnoff * Used in several address selecting functions. 217924421c1cSGleb Smirnoff */ 218024421c1cSGleb Smirnoff int 218124421c1cSGleb Smirnoff ifa_preferred(struct ifaddr *cur, struct ifaddr *next) 218224421c1cSGleb Smirnoff { 218324421c1cSGleb Smirnoff 218424421c1cSGleb Smirnoff return (cur->ifa_carp && (!next->ifa_carp || 218524421c1cSGleb Smirnoff ((*carp_master_p)(next) && !(*carp_master_p)(cur)))); 218624421c1cSGleb Smirnoff } 218724421c1cSGleb Smirnoff 218895fbe4d0SAlexander V. Chernikov struct sockaddr_dl * 218995fbe4d0SAlexander V. Chernikov link_alloc_sdl(size_t size, int flags) 219095fbe4d0SAlexander V. Chernikov { 219195fbe4d0SAlexander V. Chernikov 219295fbe4d0SAlexander V. Chernikov return (malloc(size, M_TEMP, flags)); 219395fbe4d0SAlexander V. Chernikov } 219495fbe4d0SAlexander V. Chernikov 219595fbe4d0SAlexander V. Chernikov void 219695fbe4d0SAlexander V. Chernikov link_free_sdl(struct sockaddr *sa) 219795fbe4d0SAlexander V. Chernikov { 219895fbe4d0SAlexander V. Chernikov free(sa, M_TEMP); 219995fbe4d0SAlexander V. Chernikov } 220095fbe4d0SAlexander V. Chernikov 220195fbe4d0SAlexander V. Chernikov /* 220295fbe4d0SAlexander V. Chernikov * Fills in given sdl with interface basic info. 220395fbe4d0SAlexander V. Chernikov * Returns pointer to filled sdl. 220495fbe4d0SAlexander V. Chernikov */ 220595fbe4d0SAlexander V. Chernikov struct sockaddr_dl * 220695fbe4d0SAlexander V. Chernikov link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype) 220795fbe4d0SAlexander V. Chernikov { 220895fbe4d0SAlexander V. Chernikov struct sockaddr_dl *sdl; 220995fbe4d0SAlexander V. Chernikov 221095fbe4d0SAlexander V. Chernikov sdl = (struct sockaddr_dl *)paddr; 221195fbe4d0SAlexander V. Chernikov memset(sdl, 0, sizeof(struct sockaddr_dl)); 221295fbe4d0SAlexander V. Chernikov sdl->sdl_len = sizeof(struct sockaddr_dl); 221395fbe4d0SAlexander V. Chernikov sdl->sdl_family = AF_LINK; 221495fbe4d0SAlexander V. Chernikov sdl->sdl_index = ifp->if_index; 221595fbe4d0SAlexander V. Chernikov sdl->sdl_type = iftype; 221695fbe4d0SAlexander V. Chernikov 221795fbe4d0SAlexander V. Chernikov return (sdl); 221895fbe4d0SAlexander V. Chernikov } 221995fbe4d0SAlexander V. Chernikov 2220df8bae1dSRodney W. Grimes /* 2221df8bae1dSRodney W. Grimes * Mark an interface down and notify protocols of 2222df8bae1dSRodney W. Grimes * the transition. 2223df8bae1dSRodney W. Grimes */ 22248614fb12SMax Laier static void 222572fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam) 2226df8bae1dSRodney W. Grimes { 222772fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 2228df8bae1dSRodney W. Grimes 2229292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_unroute: flag != IFF_UP")); 2230292ee7beSRobert Watson 2231e8c2601dSPoul-Henning Kamp ifp->if_flags &= ~flag; 223298b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 2233d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 2234e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 2235df8bae1dSRodney W. Grimes pfctlinput(PRC_IFDOWN, ifa->ifa_addr); 2236db7f0b97SKip Macy ifp->if_qflush(ifp); 2237db7f0b97SKip Macy 2238a9771948SGleb Smirnoff if (ifp->if_carp) 223954bfbd51SWill Andrews (*carp_linkstate_p)(ifp); 2240df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 2241df8bae1dSRodney W. Grimes } 2242df8bae1dSRodney W. Grimes 2243df8bae1dSRodney W. Grimes /* 2244df8bae1dSRodney W. Grimes * Mark an interface up and notify protocols of 2245df8bae1dSRodney W. Grimes * the transition. 2246df8bae1dSRodney W. Grimes */ 22478614fb12SMax Laier static void 224872fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam) 2249df8bae1dSRodney W. Grimes { 225072fd1b6aSDag-Erling Smørgrav struct ifaddr *ifa; 2251df8bae1dSRodney W. Grimes 2252292ee7beSRobert Watson KASSERT(flag == IFF_UP, ("if_route: flag != IFF_UP")); 2253292ee7beSRobert Watson 2254e8c2601dSPoul-Henning Kamp ifp->if_flags |= flag; 225598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 2256d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 2257e8c2601dSPoul-Henning Kamp if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family)) 2258df8bae1dSRodney W. Grimes pfctlinput(PRC_IFUP, ifa->ifa_addr); 2259a9771948SGleb Smirnoff if (ifp->if_carp) 226054bfbd51SWill Andrews (*carp_linkstate_p)(ifp); 2261df8bae1dSRodney W. Grimes rt_ifmsg(ifp); 226282cd038dSYoshinobu Inoue #ifdef INET6 226382cd038dSYoshinobu Inoue in6_if_up(ifp); 226482cd038dSYoshinobu Inoue #endif 2265df8bae1dSRodney W. Grimes } 2266df8bae1dSRodney W. Grimes 2267a6fffd6cSBrooks Davis void (*vlan_link_state_p)(struct ifnet *); /* XXX: private from if_vlan */ 226875ee267cSGleb Smirnoff void (*vlan_trunk_cap_p)(struct ifnet *); /* XXX: private from if_vlan */ 2269e4cd31ddSJeff Roberson struct ifnet *(*vlan_trunkdev_p)(struct ifnet *); 2270e4cd31ddSJeff Roberson struct ifnet *(*vlan_devat_p)(struct ifnet *, uint16_t); 2271e4cd31ddSJeff Roberson int (*vlan_tag_p)(struct ifnet *, uint16_t *); 227232d2623aSNavdeep Parhar int (*vlan_pcp_p)(struct ifnet *, uint16_t *); 2273e4cd31ddSJeff Roberson int (*vlan_setcookie_p)(struct ifnet *, void *); 2274e4cd31ddSJeff Roberson void *(*vlan_cookie_p)(struct ifnet *); 227594f5c9cfSSam Leffler 227694f5c9cfSSam Leffler /* 227768a3482fSGleb Smirnoff * Handle a change in the interface link state. To avoid LORs 227868a3482fSGleb Smirnoff * between driver lock and upper layer locks, as well as possible 227968a3482fSGleb Smirnoff * recursions, we post event to taskqueue, and all job 228068a3482fSGleb Smirnoff * is done in static do_link_state_change(). 228194f5c9cfSSam Leffler */ 228294f5c9cfSSam Leffler void 2283d6e82913SSteven Hartland if_link_state_change(struct ifnet *ifp, int link_state) 228494f5c9cfSSam Leffler { 2285d6e82913SSteven Hartland /* Return if state hasn't changed. */ 2286d6e82913SSteven Hartland if (ifp->if_link_state == link_state) 22874d96314fSGleb Smirnoff return; 22884d96314fSGleb Smirnoff 228994f5c9cfSSam Leffler ifp->if_link_state = link_state; 22904d96314fSGleb Smirnoff 2291b8a6e03fSGleb Smirnoff /* XXXGL: reference ifp? */ 229268a3482fSGleb Smirnoff taskqueue_enqueue(taskqueue_swi, &ifp->if_linktask); 229368a3482fSGleb Smirnoff } 229468a3482fSGleb Smirnoff 229568a3482fSGleb Smirnoff static void 229668a3482fSGleb Smirnoff do_link_state_change(void *arg, int pending) 229768a3482fSGleb Smirnoff { 2298b8a6e03fSGleb Smirnoff struct ifnet *ifp; 2299b8a6e03fSGleb Smirnoff int link_state; 230068a3482fSGleb Smirnoff 2301b8a6e03fSGleb Smirnoff ifp = arg; 2302b8a6e03fSGleb Smirnoff link_state = ifp->if_link_state; 2303b8a6e03fSGleb Smirnoff 2304b8a6e03fSGleb Smirnoff CURVNET_SET(ifp->if_vnet); 230594f5c9cfSSam Leffler rt_ifmsg(ifp); 230675ee267cSGleb Smirnoff if (ifp->if_vlantrunk != NULL) 2307a6fffd6cSBrooks Davis (*vlan_link_state_p)(ifp); 23081c7899c7SGleb Smirnoff 23091c7899c7SGleb Smirnoff if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) && 2310833e8dc5SGleb Smirnoff ifp->if_l2com != NULL) 23111c7899c7SGleb Smirnoff (*ng_ether_link_state_p)(ifp, link_state); 23124d96314fSGleb Smirnoff if (ifp->if_carp) 231354bfbd51SWill Andrews (*carp_linkstate_p)(ifp); 2314ddf32010SAndrew Thompson if (ifp->if_bridge) 23155c30b378SMatt Macy ifp->if_bridge_linkstate(ifp); 2316ddf32010SAndrew Thompson if (ifp->if_lagg) 2317d6e82913SSteven Hartland (*lagg_linkstate_p)(ifp, link_state); 23188f867517SAndrew Thompson 231921ca7b57SMarko Zec if (IS_DEFAULT_VNET(curvnet)) 23209d80a330SBrooks Davis devctl_notify("IFNET", ifp->if_xname, 232121ca7b57SMarko Zec (link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN", 232221ca7b57SMarko Zec NULL); 232368a3482fSGleb Smirnoff if (pending > 1) 232468a3482fSGleb Smirnoff if_printf(ifp, "%d link states coalesced\n", pending); 23255515c2e7SGleb Smirnoff if (log_link_state_change) 232620f8d7bcSDag-Erling Smørgrav if_printf(ifp, "link state changed to %s\n", 23278b02df24SGleb Smirnoff (link_state == LINK_STATE_UP) ? "UP" : "DOWN" ); 2328368bf0c2SSepherosa Ziehau EVENTHANDLER_INVOKE(ifnet_link_event, ifp, link_state); 23298b615593SMarko Zec CURVNET_RESTORE(); 233094f5c9cfSSam Leffler } 233194f5c9cfSSam Leffler 2332df8bae1dSRodney W. Grimes /* 2333e8c2601dSPoul-Henning Kamp * Mark an interface down and notify protocols of 2334e8c2601dSPoul-Henning Kamp * the transition. 2335e8c2601dSPoul-Henning Kamp */ 2336e8c2601dSPoul-Henning Kamp void 233772fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp) 2338e8c2601dSPoul-Henning Kamp { 2339e8c2601dSPoul-Henning Kamp 234092a6859bSDexuan Cui EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_DOWN); 2341e8c2601dSPoul-Henning Kamp if_unroute(ifp, IFF_UP, AF_UNSPEC); 2342e8c2601dSPoul-Henning Kamp } 2343e8c2601dSPoul-Henning Kamp 2344e8c2601dSPoul-Henning Kamp /* 2345e8c2601dSPoul-Henning Kamp * Mark an interface up and notify protocols of 2346e8c2601dSPoul-Henning Kamp * the transition. 2347e8c2601dSPoul-Henning Kamp */ 2348e8c2601dSPoul-Henning Kamp void 234972fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp) 2350e8c2601dSPoul-Henning Kamp { 2351e8c2601dSPoul-Henning Kamp 2352e8c2601dSPoul-Henning Kamp if_route(ifp, IFF_UP, AF_UNSPEC); 235392a6859bSDexuan Cui EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_UP); 2354e8c2601dSPoul-Henning Kamp } 2355e8c2601dSPoul-Henning Kamp 2356e8c2601dSPoul-Henning Kamp /* 2357df8bae1dSRodney W. Grimes * Flush an interface queue. 2358df8bae1dSRodney W. Grimes */ 23597cc5b47fSKip Macy void 2360db7f0b97SKip Macy if_qflush(struct ifnet *ifp) 2361df8bae1dSRodney W. Grimes { 236272fd1b6aSDag-Erling Smørgrav struct mbuf *m, *n; 2363db7f0b97SKip Macy struct ifaltq *ifq; 2364df8bae1dSRodney W. Grimes 2365db7f0b97SKip Macy ifq = &ifp->if_snd; 23667b21048cSMax Laier IFQ_LOCK(ifq); 236702b199f1SMax Laier #ifdef ALTQ 236802b199f1SMax Laier if (ALTQ_IS_ENABLED(ifq)) 236902b199f1SMax Laier ALTQ_PURGE(ifq); 237002b199f1SMax Laier #endif 2371df8bae1dSRodney W. Grimes n = ifq->ifq_head; 2372155d72c4SPedro F. Giffuni while ((m = n) != NULL) { 2373c29a3321SKevin Lo n = m->m_nextpkt; 2374df8bae1dSRodney W. Grimes m_freem(m); 2375df8bae1dSRodney W. Grimes } 2376df8bae1dSRodney W. Grimes ifq->ifq_head = 0; 2377df8bae1dSRodney W. Grimes ifq->ifq_tail = 0; 2378df8bae1dSRodney W. Grimes ifq->ifq_len = 0; 23797b21048cSMax Laier IFQ_UNLOCK(ifq); 2380df8bae1dSRodney W. Grimes } 2381df8bae1dSRodney W. Grimes 2382df8bae1dSRodney W. Grimes /* 23836064c5d3SRobert Watson * Map interface name to interface structure pointer, with or without 23846064c5d3SRobert Watson * returning a reference. 2385df8bae1dSRodney W. Grimes */ 2386df8bae1dSRodney W. Grimes struct ifnet * 23876064c5d3SRobert Watson ifunit_ref(const char *name) 23886064c5d3SRobert Watson { 2389a68cc388SGleb Smirnoff struct epoch_tracker et; 23906064c5d3SRobert Watson struct ifnet *ifp; 23916064c5d3SRobert Watson 2392a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 23934f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 23948bd015a1SRobert Watson if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0 && 23958bd015a1SRobert Watson !(ifp->if_flags & IFF_DYING)) 23966064c5d3SRobert Watson break; 23976064c5d3SRobert Watson } 23986064c5d3SRobert Watson if (ifp != NULL) 23996064c5d3SRobert Watson if_ref(ifp); 2400a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 24016064c5d3SRobert Watson return (ifp); 24026064c5d3SRobert Watson } 24036064c5d3SRobert Watson 24046064c5d3SRobert Watson struct ifnet * 240530aad87dSBrooks Davis ifunit(const char *name) 2406df8bae1dSRodney W. Grimes { 2407a68cc388SGleb Smirnoff struct epoch_tracker et; 24088b7805e4SBoris Popov struct ifnet *ifp; 2409df8bae1dSRodney W. Grimes 2410a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 24114f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 241236c19a57SBrooks Davis if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0) 2413df8bae1dSRodney W. Grimes break; 2414df8bae1dSRodney W. Grimes } 2415a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 2416df8bae1dSRodney W. Grimes return (ifp); 2417df8bae1dSRodney W. Grimes } 2418df8bae1dSRodney W. Grimes 24198ad798aeSBrooks Davis void * 24208a4a4a43SBrooks Davis ifr_buffer_get_buffer(void *data) 242186d2ef16SBrooks Davis { 242286d2ef16SBrooks Davis union ifreq_union *ifrup; 242386d2ef16SBrooks Davis 242486d2ef16SBrooks Davis ifrup = data; 242586d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32 24268a4a4a43SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) 242786d2ef16SBrooks Davis return ((void *)(uintptr_t) 242886d2ef16SBrooks Davis ifrup->ifr32.ifr_ifru.ifru_buffer.buffer); 242986d2ef16SBrooks Davis #endif 243086d2ef16SBrooks Davis return (ifrup->ifr.ifr_ifru.ifru_buffer.buffer); 243186d2ef16SBrooks Davis } 243286d2ef16SBrooks Davis 243386d2ef16SBrooks Davis static void 24348a4a4a43SBrooks Davis ifr_buffer_set_buffer_null(void *data) 243586d2ef16SBrooks Davis { 243686d2ef16SBrooks Davis union ifreq_union *ifrup; 243786d2ef16SBrooks Davis 243886d2ef16SBrooks Davis ifrup = data; 243986d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32 24408a4a4a43SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) 244186d2ef16SBrooks Davis ifrup->ifr32.ifr_ifru.ifru_buffer.buffer = 0; 244286d2ef16SBrooks Davis else 244386d2ef16SBrooks Davis #endif 244486d2ef16SBrooks Davis ifrup->ifr.ifr_ifru.ifru_buffer.buffer = NULL; 244586d2ef16SBrooks Davis } 244686d2ef16SBrooks Davis 24478ad798aeSBrooks Davis size_t 24488a4a4a43SBrooks Davis ifr_buffer_get_length(void *data) 244986d2ef16SBrooks Davis { 245086d2ef16SBrooks Davis union ifreq_union *ifrup; 245186d2ef16SBrooks Davis 245286d2ef16SBrooks Davis ifrup = data; 245386d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32 24548a4a4a43SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) 245586d2ef16SBrooks Davis return (ifrup->ifr32.ifr_ifru.ifru_buffer.length); 245686d2ef16SBrooks Davis #endif 245786d2ef16SBrooks Davis return (ifrup->ifr.ifr_ifru.ifru_buffer.length); 245886d2ef16SBrooks Davis } 245986d2ef16SBrooks Davis 246086d2ef16SBrooks Davis static void 24618a4a4a43SBrooks Davis ifr_buffer_set_length(void *data, size_t len) 246286d2ef16SBrooks Davis { 246386d2ef16SBrooks Davis union ifreq_union *ifrup; 246486d2ef16SBrooks Davis 246586d2ef16SBrooks Davis ifrup = data; 246686d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32 24678a4a4a43SBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) 246886d2ef16SBrooks Davis ifrup->ifr32.ifr_ifru.ifru_buffer.length = len; 246986d2ef16SBrooks Davis else 247086d2ef16SBrooks Davis #endif 247186d2ef16SBrooks Davis ifrup->ifr.ifr_ifru.ifru_buffer.length = len; 247286d2ef16SBrooks Davis } 247386d2ef16SBrooks Davis 2474541d96aaSBrooks Davis void * 2475541d96aaSBrooks Davis ifr_data_get_ptr(void *ifrp) 2476541d96aaSBrooks Davis { 2477541d96aaSBrooks Davis union ifreq_union *ifrup; 2478541d96aaSBrooks Davis 2479541d96aaSBrooks Davis ifrup = ifrp; 2480541d96aaSBrooks Davis #ifdef COMPAT_FREEBSD32 2481541d96aaSBrooks Davis if (SV_CURPROC_FLAG(SV_ILP32)) 2482541d96aaSBrooks Davis return ((void *)(uintptr_t) 2483541d96aaSBrooks Davis ifrup->ifr32.ifr_ifru.ifru_data); 2484541d96aaSBrooks Davis #endif 2485541d96aaSBrooks Davis return (ifrup->ifr.ifr_ifru.ifru_data); 2486541d96aaSBrooks Davis } 2487541d96aaSBrooks Davis 248882cd038dSYoshinobu Inoue /* 2489f13ad206SJonathan Lemon * Hardware specific interface ioctls. 2490df8bae1dSRodney W. Grimes */ 24911687b1abSMichael Tuexen int 2492f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td) 2493df8bae1dSRodney W. Grimes { 2494f13ad206SJonathan Lemon struct ifreq *ifr; 2495cc5bb78bSSepherosa Ziehau int error = 0, do_ifup = 0; 2496292ee7beSRobert Watson int new_flags, temp_flags; 249736c19a57SBrooks Davis size_t namelen, onamelen; 2498215940b3SXin LI size_t descrlen; 2499215940b3SXin LI char *descrbuf, *odescrbuf; 250036c19a57SBrooks Davis char new_name[IFNAMSIZ]; 250136c19a57SBrooks Davis struct ifaddr *ifa; 250236c19a57SBrooks Davis struct sockaddr_dl *sdl; 2503df8bae1dSRodney W. Grimes 2504df8bae1dSRodney W. Grimes ifr = (struct ifreq *)data; 250530aad87dSBrooks Davis switch (cmd) { 2506de593450SJonathan Lemon case SIOCGIFINDEX: 2507de593450SJonathan Lemon ifr->ifr_index = ifp->if_index; 2508de593450SJonathan Lemon break; 2509de593450SJonathan Lemon 2510df8bae1dSRodney W. Grimes case SIOCGIFFLAGS: 2511292ee7beSRobert Watson temp_flags = ifp->if_flags | ifp->if_drv_flags; 2512292ee7beSRobert Watson ifr->ifr_flags = temp_flags & 0xffff; 2513292ee7beSRobert Watson ifr->ifr_flagshigh = temp_flags >> 16; 2514df8bae1dSRodney W. Grimes break; 2515df8bae1dSRodney W. Grimes 2516016da741SJonathan Lemon case SIOCGIFCAP: 2517016da741SJonathan Lemon ifr->ifr_reqcap = ifp->if_capabilities; 2518016da741SJonathan Lemon ifr->ifr_curcap = ifp->if_capenable; 2519016da741SJonathan Lemon break; 2520016da741SJonathan Lemon 2521c1aedfcbSEd Maste case SIOCGIFDATA: 2522c1aedfcbSEd Maste { 2523c1aedfcbSEd Maste struct if_data ifd; 2524c1aedfcbSEd Maste 2525c1aedfcbSEd Maste /* Ensure uninitialised padding is not leaked. */ 2526c1aedfcbSEd Maste memset(&ifd, 0, sizeof(ifd)); 2527c1aedfcbSEd Maste 2528c1aedfcbSEd Maste if_data_copy(ifp, &ifd); 2529c1aedfcbSEd Maste error = copyout(&ifd, ifr_data_get_ptr(ifr), sizeof(ifd)); 2530c1aedfcbSEd Maste break; 2531c1aedfcbSEd Maste } 2532c1aedfcbSEd Maste 25338f293a63SRobert Watson #ifdef MAC 25348f293a63SRobert Watson case SIOCGIFMAC: 253530d239bcSRobert Watson error = mac_ifnet_ioctl_get(td->td_ucred, ifr, ifp); 25368f293a63SRobert Watson break; 25378f293a63SRobert Watson #endif 25388f293a63SRobert Watson 2539df8bae1dSRodney W. Grimes case SIOCGIFMETRIC: 2540df8bae1dSRodney W. Grimes ifr->ifr_metric = ifp->if_metric; 2541df8bae1dSRodney W. Grimes break; 2542df8bae1dSRodney W. Grimes 2543a7028af7SDavid Greenman case SIOCGIFMTU: 2544a7028af7SDavid Greenman ifr->ifr_mtu = ifp->if_mtu; 2545a7028af7SDavid Greenman break; 2546a7028af7SDavid Greenman 2547074c4a4eSGarrett Wollman case SIOCGIFPHYS: 2548e6485f73SGleb Smirnoff /* XXXGL: did this ever worked? */ 2549e6485f73SGleb Smirnoff ifr->ifr_phys = 0; 2550074c4a4eSGarrett Wollman break; 2551074c4a4eSGarrett Wollman 2552215940b3SXin LI case SIOCGIFDESCR: 2553215940b3SXin LI error = 0; 2554215940b3SXin LI sx_slock(&ifdescr_sx); 255557d84848SXin LI if (ifp->if_description == NULL) 2556215940b3SXin LI error = ENOMSG; 255757d84848SXin LI else { 2558215940b3SXin LI /* space for terminating nul */ 2559215940b3SXin LI descrlen = strlen(ifp->if_description) + 1; 25608a4a4a43SBrooks Davis if (ifr_buffer_get_length(ifr) < descrlen) 25618a4a4a43SBrooks Davis ifr_buffer_set_buffer_null(ifr); 2562215940b3SXin LI else 2563215940b3SXin LI error = copyout(ifp->if_description, 25648a4a4a43SBrooks Davis ifr_buffer_get_buffer(ifr), descrlen); 25658a4a4a43SBrooks Davis ifr_buffer_set_length(ifr, descrlen); 2566215940b3SXin LI } 2567215940b3SXin LI sx_sunlock(&ifdescr_sx); 2568215940b3SXin LI break; 2569215940b3SXin LI 2570215940b3SXin LI case SIOCSIFDESCR: 2571215940b3SXin LI error = priv_check(td, PRIV_NET_SETIFDESCR); 2572215940b3SXin LI if (error) 2573215940b3SXin LI return (error); 2574215940b3SXin LI 2575215940b3SXin LI /* 2576215940b3SXin LI * Copy only (length-1) bytes to make sure that 2577215940b3SXin LI * if_description is always nul terminated. The 2578215940b3SXin LI * length parameter is supposed to count the 2579215940b3SXin LI * terminating nul in. 2580215940b3SXin LI */ 25818a4a4a43SBrooks Davis if (ifr_buffer_get_length(ifr) > ifdescr_maxlen) 2582215940b3SXin LI return (ENAMETOOLONG); 25838a4a4a43SBrooks Davis else if (ifr_buffer_get_length(ifr) == 0) 2584215940b3SXin LI descrbuf = NULL; 2585215940b3SXin LI else { 25868a4a4a43SBrooks Davis descrbuf = malloc(ifr_buffer_get_length(ifr), 258786d2ef16SBrooks Davis M_IFDESCR, M_WAITOK | M_ZERO); 25888a4a4a43SBrooks Davis error = copyin(ifr_buffer_get_buffer(ifr), descrbuf, 25898a4a4a43SBrooks Davis ifr_buffer_get_length(ifr) - 1); 2590215940b3SXin LI if (error) { 2591215940b3SXin LI free(descrbuf, M_IFDESCR); 2592215940b3SXin LI break; 2593215940b3SXin LI } 2594215940b3SXin LI } 2595215940b3SXin LI 2596215940b3SXin LI sx_xlock(&ifdescr_sx); 2597215940b3SXin LI odescrbuf = ifp->if_description; 2598215940b3SXin LI ifp->if_description = descrbuf; 2599215940b3SXin LI sx_xunlock(&ifdescr_sx); 2600215940b3SXin LI 2601215940b3SXin LI getmicrotime(&ifp->if_lastchange); 2602215940b3SXin LI free(odescrbuf, M_IFDESCR); 2603215940b3SXin LI break; 2604215940b3SXin LI 260535fd7bc0SBjoern A. Zeeb case SIOCGIFFIB: 260635fd7bc0SBjoern A. Zeeb ifr->ifr_fib = ifp->if_fib; 260735fd7bc0SBjoern A. Zeeb break; 260835fd7bc0SBjoern A. Zeeb 260935fd7bc0SBjoern A. Zeeb case SIOCSIFFIB: 261035fd7bc0SBjoern A. Zeeb error = priv_check(td, PRIV_NET_SETIFFIB); 261135fd7bc0SBjoern A. Zeeb if (error) 261235fd7bc0SBjoern A. Zeeb return (error); 261335fd7bc0SBjoern A. Zeeb if (ifr->ifr_fib >= rt_numfibs) 261435fd7bc0SBjoern A. Zeeb return (EINVAL); 261535fd7bc0SBjoern A. Zeeb 261635fd7bc0SBjoern A. Zeeb ifp->if_fib = ifr->ifr_fib; 261735fd7bc0SBjoern A. Zeeb break; 261835fd7bc0SBjoern A. Zeeb 2619df8bae1dSRodney W. Grimes case SIOCSIFFLAGS: 2620acd3428bSRobert Watson error = priv_check(td, PRIV_NET_SETIFFLAGS); 26219448326fSPoul-Henning Kamp if (error) 2622df8bae1dSRodney W. Grimes return (error); 2623292ee7beSRobert Watson /* 2624292ee7beSRobert Watson * Currently, no driver owned flags pass the IFF_CANTCHANGE 2625292ee7beSRobert Watson * check, so we don't need special handling here yet. 2626292ee7beSRobert Watson */ 262762f76486SMaxim Sobolev new_flags = (ifr->ifr_flags & 0xffff) | 262862f76486SMaxim Sobolev (ifr->ifr_flagshigh << 16); 2629af50ea38SGleb Smirnoff if (ifp->if_flags & IFF_UP && 263062f76486SMaxim Sobolev (new_flags & IFF_UP) == 0) { 2631df8bae1dSRodney W. Grimes if_down(ifp); 263262f76486SMaxim Sobolev } else if (new_flags & IFF_UP && 2633cf4b9371SPoul-Henning Kamp (ifp->if_flags & IFF_UP) == 0) { 2634cc5bb78bSSepherosa Ziehau do_ifup = 1; 2635df8bae1dSRodney W. Grimes } 26367aebc5e8SYaroslav Tykhiy /* See if permanently promiscuous mode bit is about to flip */ 26377aebc5e8SYaroslav Tykhiy if ((ifp->if_flags ^ new_flags) & IFF_PPROMISC) { 26387aebc5e8SYaroslav Tykhiy if (new_flags & IFF_PPROMISC) 26397aebc5e8SYaroslav Tykhiy ifp->if_flags |= IFF_PROMISC; 26407aebc5e8SYaroslav Tykhiy else if (ifp->if_pcount == 0) 26417aebc5e8SYaroslav Tykhiy ifp->if_flags &= ~IFF_PROMISC; 26426d07c157SNick Hibma if (log_promisc_mode_change) 264320f8d7bcSDag-Erling Smørgrav if_printf(ifp, "permanently promiscuous mode %s\n", 26446d07c157SNick Hibma ((new_flags & IFF_PPROMISC) ? 26456d07c157SNick Hibma "enabled" : "disabled")); 26467aebc5e8SYaroslav Tykhiy } 2647df8bae1dSRodney W. Grimes ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) | 264862f76486SMaxim Sobolev (new_flags &~ IFF_CANTCHANGE); 264931302ebfSRobert Watson if (ifp->if_ioctl) { 2650df8bae1dSRodney W. Grimes (void) (*ifp->if_ioctl)(ifp, cmd, data); 265131302ebfSRobert Watson } 2652cc5bb78bSSepherosa Ziehau if (do_ifup) 2653cc5bb78bSSepherosa Ziehau if_up(ifp); 265498b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 2655df8bae1dSRodney W. Grimes break; 2656df8bae1dSRodney W. Grimes 2657016da741SJonathan Lemon case SIOCSIFCAP: 2658acd3428bSRobert Watson error = priv_check(td, PRIV_NET_SETIFCAP); 2659016da741SJonathan Lemon if (error) 2660016da741SJonathan Lemon return (error); 2661efb4018bSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 2662efb4018bSYaroslav Tykhiy return (EOPNOTSUPP); 2663016da741SJonathan Lemon if (ifr->ifr_reqcap & ~ifp->if_capabilities) 2664016da741SJonathan Lemon return (EINVAL); 2665efb4018bSYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, cmd, data); 2666efb4018bSYaroslav Tykhiy if (error == 0) 2667efb4018bSYaroslav Tykhiy getmicrotime(&ifp->if_lastchange); 2668016da741SJonathan Lemon break; 2669016da741SJonathan Lemon 26708f293a63SRobert Watson #ifdef MAC 26718f293a63SRobert Watson case SIOCSIFMAC: 267230d239bcSRobert Watson error = mac_ifnet_ioctl_set(td->td_ucred, ifr, ifp); 26738f293a63SRobert Watson break; 26748f293a63SRobert Watson #endif 26758f293a63SRobert Watson 267636c19a57SBrooks Davis case SIOCSIFNAME: 2677acd3428bSRobert Watson error = priv_check(td, PRIV_NET_SETIFNAME); 2678acd3428bSRobert Watson if (error) 267936c19a57SBrooks Davis return (error); 2680541d96aaSBrooks Davis error = copyinstr(ifr_data_get_ptr(ifr), new_name, IFNAMSIZ, 2681541d96aaSBrooks Davis NULL); 2682bc1470f1SBrooks Davis if (error != 0) 268336c19a57SBrooks Davis return (error); 2684bc1470f1SBrooks Davis if (new_name[0] == '\0') 2685bc1470f1SBrooks Davis return (EINVAL); 26861ef3d54dSDon Lewis if (new_name[IFNAMSIZ-1] != '\0') { 26871ef3d54dSDon Lewis new_name[IFNAMSIZ-1] = '\0'; 26881ef3d54dSDon Lewis if (strlen(new_name) == IFNAMSIZ-1) 26891ef3d54dSDon Lewis return (EINVAL); 26901ef3d54dSDon Lewis } 269140b1c921SKyle Evans if (strcmp(new_name, ifp->if_xname) == 0) 269240b1c921SKyle Evans break; 269336c19a57SBrooks Davis if (ifunit(new_name) != NULL) 269436c19a57SBrooks Davis return (EEXIST); 269536c19a57SBrooks Davis 26965428776eSJohn Baldwin /* 26975428776eSJohn Baldwin * XXX: Locking. Nothing else seems to lock if_flags, 26985428776eSJohn Baldwin * and there are numerous other races with the 26995428776eSJohn Baldwin * ifunit() checks not being atomic with namespace 27005428776eSJohn Baldwin * changes (renames, vmoves, if_attach, etc). 27015428776eSJohn Baldwin */ 27025428776eSJohn Baldwin ifp->if_flags |= IFF_RENAMING; 27035428776eSJohn Baldwin 270436c19a57SBrooks Davis /* Announce the departure of the interface. */ 270536c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_DEPARTURE); 270652023244SMax Laier EVENTHANDLER_INVOKE(ifnet_departure_event, ifp); 270736c19a57SBrooks Davis 270820f8d7bcSDag-Erling Smørgrav if_printf(ifp, "changing name to '%s'\n", new_name); 270971672bb6SBrooks Davis 271067420bdaSGleb Smirnoff IF_ADDR_WLOCK(ifp); 271136c19a57SBrooks Davis strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname)); 27124a0d6638SRuslan Ermilov ifa = ifp->if_addr; 271336c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_addr; 271436c19a57SBrooks Davis namelen = strlen(new_name); 271536c19a57SBrooks Davis onamelen = sdl->sdl_nlen; 271636c19a57SBrooks Davis /* 271736c19a57SBrooks Davis * Move the address if needed. This is safe because we 271836c19a57SBrooks Davis * allocate space for a name of length IFNAMSIZ when we 271936c19a57SBrooks Davis * create this in if_attach(). 272036c19a57SBrooks Davis */ 272136c19a57SBrooks Davis if (namelen != onamelen) { 272236c19a57SBrooks Davis bcopy(sdl->sdl_data + onamelen, 272336c19a57SBrooks Davis sdl->sdl_data + namelen, sdl->sdl_alen); 272436c19a57SBrooks Davis } 272536c19a57SBrooks Davis bcopy(new_name, sdl->sdl_data, namelen); 272636c19a57SBrooks Davis sdl->sdl_nlen = namelen; 272736c19a57SBrooks Davis sdl = (struct sockaddr_dl *)ifa->ifa_netmask; 272836c19a57SBrooks Davis bzero(sdl->sdl_data, onamelen); 272936c19a57SBrooks Davis while (namelen != 0) 273036c19a57SBrooks Davis sdl->sdl_data[--namelen] = 0xff; 273167420bdaSGleb Smirnoff IF_ADDR_WUNLOCK(ifp); 273236c19a57SBrooks Davis 273325a4adceSMax Laier EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp); 273436c19a57SBrooks Davis /* Announce the return of the interface. */ 273536c19a57SBrooks Davis rt_ifannouncemsg(ifp, IFAN_ARRIVAL); 27365428776eSJohn Baldwin 27375428776eSJohn Baldwin ifp->if_flags &= ~IFF_RENAMING; 273836c19a57SBrooks Davis break; 273936c19a57SBrooks Davis 2740679e1390SJamie Gritton #ifdef VIMAGE 2741679e1390SJamie Gritton case SIOCSIFVNET: 2742679e1390SJamie Gritton error = priv_check(td, PRIV_NET_SETIFVNET); 2743679e1390SJamie Gritton if (error) 2744679e1390SJamie Gritton return (error); 2745be31e5e7SBjoern A. Zeeb error = if_vmove_loan(td, ifp, ifr->ifr_name, ifr->ifr_jid); 2746679e1390SJamie Gritton break; 2747679e1390SJamie Gritton #endif 2748679e1390SJamie Gritton 2749df8bae1dSRodney W. Grimes case SIOCSIFMETRIC: 2750acd3428bSRobert Watson error = priv_check(td, PRIV_NET_SETIFMETRIC); 27519448326fSPoul-Henning Kamp if (error) 2752df8bae1dSRodney W. Grimes return (error); 2753df8bae1dSRodney W. Grimes ifp->if_metric = ifr->ifr_metric; 275498b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 2755df8bae1dSRodney W. Grimes break; 2756df8bae1dSRodney W. Grimes 2757074c4a4eSGarrett Wollman case SIOCSIFPHYS: 2758acd3428bSRobert Watson error = priv_check(td, PRIV_NET_SETIFPHYS); 2759e39a0280SGary Palmer if (error) 2760913e410eSYaroslav Tykhiy return (error); 2761913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 2762913e410eSYaroslav Tykhiy return (EOPNOTSUPP); 2763e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 2764e39a0280SGary Palmer if (error == 0) 276598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 2766913e410eSYaroslav Tykhiy break; 2767074c4a4eSGarrett Wollman 2768a7028af7SDavid Greenman case SIOCSIFMTU: 276982cd038dSYoshinobu Inoue { 277082cd038dSYoshinobu Inoue u_long oldmtu = ifp->if_mtu; 277182cd038dSYoshinobu Inoue 2772acd3428bSRobert Watson error = priv_check(td, PRIV_NET_SETIFMTU); 27739448326fSPoul-Henning Kamp if (error) 2774a7028af7SDavid Greenman return (error); 2775aab3beeeSBrian Somers if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU) 277675ee03cbSDavid Greenman return (EINVAL); 2777f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 2778f13ad206SJonathan Lemon return (EOPNOTSUPP); 2779e39a0280SGary Palmer error = (*ifp->if_ioctl)(ifp, cmd, data); 278048f71763SRuslan Ermilov if (error == 0) { 278198b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 278248f71763SRuslan Ermilov rt_ifmsg(ifp); 2783e5054602SMark Johnston #ifdef INET 27847790c8c1SConrad Meyer DEBUGNET_NOTIFY_MTU(ifp); 2785e5054602SMark Johnston #endif 278648f71763SRuslan Ermilov } 278782cd038dSYoshinobu Inoue /* 278882cd038dSYoshinobu Inoue * If the link MTU changed, do network layer specific procedure. 278982cd038dSYoshinobu Inoue */ 279082cd038dSYoshinobu Inoue if (ifp->if_mtu != oldmtu) { 279182cd038dSYoshinobu Inoue #ifdef INET6 279282cd038dSYoshinobu Inoue nd6_setmtu(ifp); 279382cd038dSYoshinobu Inoue #endif 27947f948f12SAlexander V. Chernikov rt_updatemtu(ifp); 279582cd038dSYoshinobu Inoue } 2796f13ad206SJonathan Lemon break; 279782cd038dSYoshinobu Inoue } 2798a7028af7SDavid Greenman 2799df8bae1dSRodney W. Grimes case SIOCADDMULTI: 2800df8bae1dSRodney W. Grimes case SIOCDELMULTI: 2801acd3428bSRobert Watson if (cmd == SIOCADDMULTI) 2802acd3428bSRobert Watson error = priv_check(td, PRIV_NET_ADDMULTI); 2803acd3428bSRobert Watson else 2804acd3428bSRobert Watson error = priv_check(td, PRIV_NET_DELMULTI); 28059448326fSPoul-Henning Kamp if (error) 2806df8bae1dSRodney W. Grimes return (error); 2807477180fbSGarrett Wollman 2808477180fbSGarrett Wollman /* Don't allow group membership on non-multicast interfaces. */ 2809477180fbSGarrett Wollman if ((ifp->if_flags & IFF_MULTICAST) == 0) 2810f13ad206SJonathan Lemon return (EOPNOTSUPP); 2811477180fbSGarrett Wollman 2812477180fbSGarrett Wollman /* Don't let users screw up protocols' entries. */ 2813477180fbSGarrett Wollman if (ifr->ifr_addr.sa_family != AF_LINK) 2814f13ad206SJonathan Lemon return (EINVAL); 2815477180fbSGarrett Wollman 2816477180fbSGarrett Wollman if (cmd == SIOCADDMULTI) { 2817a68cc388SGleb Smirnoff struct epoch_tracker et; 2818477180fbSGarrett Wollman struct ifmultiaddr *ifma; 2819ec002feeSBruce M Simpson 2820ec002feeSBruce M Simpson /* 2821ec002feeSBruce M Simpson * Userland is only permitted to join groups once 2822ec002feeSBruce M Simpson * via the if_addmulti() KPI, because it cannot hold 2823ec002feeSBruce M Simpson * struct ifmultiaddr * between calls. It may also 2824ec002feeSBruce M Simpson * lose a race while we check if the membership 2825ec002feeSBruce M Simpson * already exists. 2826ec002feeSBruce M Simpson */ 2827a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 2828ec002feeSBruce M Simpson ifma = if_findmulti(ifp, &ifr->ifr_addr); 2829a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 2830ec002feeSBruce M Simpson if (ifma != NULL) 2831ec002feeSBruce M Simpson error = EADDRINUSE; 2832ec002feeSBruce M Simpson else 2833477180fbSGarrett Wollman error = if_addmulti(ifp, &ifr->ifr_addr, &ifma); 2834477180fbSGarrett Wollman } else { 2835477180fbSGarrett Wollman error = if_delmulti(ifp, &ifr->ifr_addr); 2836477180fbSGarrett Wollman } 2837e39a0280SGary Palmer if (error == 0) 283898b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 2839f13ad206SJonathan Lemon break; 2840df8bae1dSRodney W. Grimes 284141b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR: 284241b3e8e5SJun-ichiro itojun Hagino case SIOCDIFPHYADDR: 284341b3e8e5SJun-ichiro itojun Hagino #ifdef INET6 284441b3e8e5SJun-ichiro itojun Hagino case SIOCSIFPHYADDR_IN6: 284541b3e8e5SJun-ichiro itojun Hagino #endif 2846a912e453SPeter Wemm case SIOCSIFMEDIA: 2847d7189ec6SJoerg Wunsch case SIOCSIFGENERIC: 2848acd3428bSRobert Watson error = priv_check(td, PRIV_NET_HWIOCTL); 2849a912e453SPeter Wemm if (error) 2850a912e453SPeter Wemm return (error); 2851f13ad206SJonathan Lemon if (ifp->if_ioctl == NULL) 2852a912e453SPeter Wemm return (EOPNOTSUPP); 2853a912e453SPeter Wemm error = (*ifp->if_ioctl)(ifp, cmd, data); 2854a912e453SPeter Wemm if (error == 0) 285598b9590eSPoul-Henning Kamp getmicrotime(&ifp->if_lastchange); 2856f13ad206SJonathan Lemon break; 2857a912e453SPeter Wemm 2858413dd0baSPoul-Henning Kamp case SIOCGIFSTATUS: 285933841545SHajimu UMEMOTO case SIOCGIFPSRCADDR: 286033841545SHajimu UMEMOTO case SIOCGIFPDSTADDR: 2861a912e453SPeter Wemm case SIOCGIFMEDIA: 2862eb7e25b2SEric Joyner case SIOCGIFXMEDIA: 2863d7189ec6SJoerg Wunsch case SIOCGIFGENERIC: 28640f3af041SSepherosa Ziehau case SIOCGIFRSSKEY: 28650f3af041SSepherosa Ziehau case SIOCGIFRSSHASH: 2866247cf566SKonstantin Belousov case SIOCGIFDOWNREASON: 2867913e410eSYaroslav Tykhiy if (ifp->if_ioctl == NULL) 2868a912e453SPeter Wemm return (EOPNOTSUPP); 2869f13ad206SJonathan Lemon error = (*ifp->if_ioctl)(ifp, cmd, data); 2870f13ad206SJonathan Lemon break; 2871a912e453SPeter Wemm 2872b106252cSBill Paul case SIOCSIFLLADDR: 2873acd3428bSRobert Watson error = priv_check(td, PRIV_NET_SETLLADDR); 2874b106252cSBill Paul if (error) 2875b106252cSBill Paul return (error); 2876f13ad206SJonathan Lemon error = if_setlladdr(ifp, 287766ce51ceSArchie Cobbs ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len); 2878f13ad206SJonathan Lemon break; 287966ce51ceSArchie Cobbs 2880ddae5750SRavi Pokala case SIOCGHWADDR: 2881ddae5750SRavi Pokala error = if_gethwaddr(ifp, ifr); 2882ddae5750SRavi Pokala break; 2883ddae5750SRavi Pokala 2884bc6f170eSBrooks Davis case CASE_IOC_IFGROUPREQ(SIOCAIFGROUP): 2885acd3428bSRobert Watson error = priv_check(td, PRIV_NET_ADDIFGROUP); 28860dad3f0eSMax Laier if (error) 28870dad3f0eSMax Laier return (error); 2888756181b8SBrooks Davis if ((error = if_addgroup(ifp, 2889756181b8SBrooks Davis ifgr_group_get((struct ifgroupreq *)data)))) 28900dad3f0eSMax Laier return (error); 28910dad3f0eSMax Laier break; 28920dad3f0eSMax Laier 2893bc6f170eSBrooks Davis case CASE_IOC_IFGROUPREQ(SIOCGIFGROUP): 2894b8a6e03fSGleb Smirnoff { 2895b8a6e03fSGleb Smirnoff struct epoch_tracker et; 2896b8a6e03fSGleb Smirnoff 2897b8a6e03fSGleb Smirnoff NET_EPOCH_ENTER(et); 2898b8a6e03fSGleb Smirnoff error = if_getgroup((struct ifgroupreq *)data, ifp); 2899b8a6e03fSGleb Smirnoff NET_EPOCH_EXIT(et); 2900756181b8SBrooks Davis break; 2901b8a6e03fSGleb Smirnoff } 29020dad3f0eSMax Laier 2903bc6f170eSBrooks Davis case CASE_IOC_IFGROUPREQ(SIOCDIFGROUP): 2904acd3428bSRobert Watson error = priv_check(td, PRIV_NET_DELIFGROUP); 29050dad3f0eSMax Laier if (error) 29060dad3f0eSMax Laier return (error); 2907756181b8SBrooks Davis if ((error = if_delgroup(ifp, 2908756181b8SBrooks Davis ifgr_group_get((struct ifgroupreq *)data)))) 29090dad3f0eSMax Laier return (error); 29100dad3f0eSMax Laier break; 29110dad3f0eSMax Laier 2912df8bae1dSRodney W. Grimes default: 2913f13ad206SJonathan Lemon error = ENOIOCTL; 2914f13ad206SJonathan Lemon break; 2915f13ad206SJonathan Lemon } 2916f13ad206SJonathan Lemon return (error); 2917f13ad206SJonathan Lemon } 2918f13ad206SJonathan Lemon 29199af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32 29209af74f3dSSergey Kandaurov struct ifconf32 { 29219af74f3dSSergey Kandaurov int32_t ifc_len; 29229af74f3dSSergey Kandaurov union { 29239af74f3dSSergey Kandaurov uint32_t ifcu_buf; 29249af74f3dSSergey Kandaurov uint32_t ifcu_req; 29259af74f3dSSergey Kandaurov } ifc_ifcu; 29269af74f3dSSergey Kandaurov }; 29279af74f3dSSergey Kandaurov #define SIOCGIFCONF32 _IOWR('i', 36, struct ifconf32) 29289af74f3dSSergey Kandaurov #endif 2929f13ad206SJonathan Lemon /* 2930f13ad206SJonathan Lemon * Interface ioctls. 2931f13ad206SJonathan Lemon */ 2932f13ad206SJonathan Lemon int 293372fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td) 2934f13ad206SJonathan Lemon { 29353edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32 2936d17e0940SJohn Baldwin union { 2937d17e0940SJohn Baldwin struct ifconf ifc; 2938*d61d98f4SJohn Baldwin struct ifdrv ifd; 29393edb7f4eSBrooks Davis struct ifmediareq ifmr; 2940d17e0940SJohn Baldwin } thunk; 2941d17e0940SJohn Baldwin caddr_t saved_data; 2942d17e0940SJohn Baldwin u_long saved_cmd; 2943d17e0940SJohn Baldwin struct ifconf32 *ifc32; 2944*d61d98f4SJohn Baldwin struct ifdrv32 *ifd32; 2945d17e0940SJohn Baldwin struct ifmediareq32 *ifmr32; 29462da19677SSean Bruno #endif 2947f13ad206SJonathan Lemon struct ifnet *ifp; 2948f13ad206SJonathan Lemon struct ifreq *ifr; 2949f13ad206SJonathan Lemon int error; 295062f76486SMaxim Sobolev int oif_flags; 295110108cb6SBjoern A. Zeeb #ifdef VIMAGE 295210108cb6SBjoern A. Zeeb bool shutdown; 295310108cb6SBjoern A. Zeeb #endif 2954f13ad206SJonathan Lemon 29551fb51a12SBjoern A. Zeeb CURVNET_SET(so->so_vnet); 295689856f7eSBjoern A. Zeeb #ifdef VIMAGE 295789856f7eSBjoern A. Zeeb /* Make sure the VNET is stable. */ 295810108cb6SBjoern A. Zeeb shutdown = VNET_IS_SHUTTING_DOWN(so->so_vnet); 295910108cb6SBjoern A. Zeeb if (shutdown) { 296089856f7eSBjoern A. Zeeb CURVNET_RESTORE(); 296189856f7eSBjoern A. Zeeb return (EBUSY); 296289856f7eSBjoern A. Zeeb } 296389856f7eSBjoern A. Zeeb #endif 296489856f7eSBjoern A. Zeeb 2965d17e0940SJohn Baldwin #ifdef COMPAT_FREEBSD32 2966d17e0940SJohn Baldwin saved_cmd = cmd; 2967d17e0940SJohn Baldwin saved_data = data; 2968d17e0940SJohn Baldwin switch (cmd) { 2969d17e0940SJohn Baldwin case SIOCGIFCONF32: 2970d17e0940SJohn Baldwin ifc32 = (struct ifconf32 *)data; 2971d17e0940SJohn Baldwin thunk.ifc.ifc_len = ifc32->ifc_len; 2972d17e0940SJohn Baldwin thunk.ifc.ifc_buf = PTRIN(ifc32->ifc_buf); 2973d17e0940SJohn Baldwin data = (caddr_t)&thunk.ifc; 2974d17e0940SJohn Baldwin cmd = SIOCGIFCONF; 2975d17e0940SJohn Baldwin break; 2976*d61d98f4SJohn Baldwin case SIOCGDRVSPEC32: 2977*d61d98f4SJohn Baldwin case SIOCSDRVSPEC32: 2978*d61d98f4SJohn Baldwin ifd32 = (struct ifdrv32 *)data; 2979*d61d98f4SJohn Baldwin memcpy(thunk.ifd.ifd_name, ifd32->ifd_name, 2980*d61d98f4SJohn Baldwin sizeof(thunk.ifd.ifd_name)); 2981*d61d98f4SJohn Baldwin thunk.ifd.ifd_cmd = ifd32->ifd_cmd; 2982*d61d98f4SJohn Baldwin thunk.ifd.ifd_len = ifd32->ifd_len; 2983*d61d98f4SJohn Baldwin thunk.ifd.ifd_data = PTRIN(ifd32->ifd_data); 2984*d61d98f4SJohn Baldwin data = (caddr_t)&thunk.ifd; 2985*d61d98f4SJohn Baldwin cmd = _IOC_NEWTYPE(cmd, struct ifdrv); 2986*d61d98f4SJohn Baldwin break; 2987d17e0940SJohn Baldwin case SIOCGIFMEDIA32: 2988d17e0940SJohn Baldwin case SIOCGIFXMEDIA32: 2989d17e0940SJohn Baldwin ifmr32 = (struct ifmediareq32 *)data; 2990d17e0940SJohn Baldwin memcpy(thunk.ifmr.ifm_name, ifmr32->ifm_name, 2991d17e0940SJohn Baldwin sizeof(thunk.ifmr.ifm_name)); 2992d17e0940SJohn Baldwin thunk.ifmr.ifm_current = ifmr32->ifm_current; 2993d17e0940SJohn Baldwin thunk.ifmr.ifm_mask = ifmr32->ifm_mask; 2994d17e0940SJohn Baldwin thunk.ifmr.ifm_status = ifmr32->ifm_status; 2995d17e0940SJohn Baldwin thunk.ifmr.ifm_active = ifmr32->ifm_active; 2996d17e0940SJohn Baldwin thunk.ifmr.ifm_count = ifmr32->ifm_count; 2997d17e0940SJohn Baldwin thunk.ifmr.ifm_ulist = PTRIN(ifmr32->ifm_ulist); 2998d17e0940SJohn Baldwin data = (caddr_t)&thunk.ifmr; 2999d17e0940SJohn Baldwin cmd = _IOC_NEWTYPE(cmd, struct ifmediareq); 3000d17e0940SJohn Baldwin break; 3001d17e0940SJohn Baldwin } 3002d17e0940SJohn Baldwin #endif 3003d17e0940SJohn Baldwin 3004f13ad206SJonathan Lemon switch (cmd) { 3005f13ad206SJonathan Lemon case SIOCGIFCONF: 30061fb51a12SBjoern A. Zeeb error = ifconf(cmd, data); 3007b8a6e03fSGleb Smirnoff goto out_noref; 30089af74f3dSSergey Kandaurov } 30093edb7f4eSBrooks Davis 30103edb7f4eSBrooks Davis ifr = (struct ifreq *)data; 3011f13ad206SJonathan Lemon switch (cmd) { 3012feb08d06SMarko Zec #ifdef VIMAGE 3013679e1390SJamie Gritton case SIOCSIFRVNET: 3014679e1390SJamie Gritton error = priv_check(td, PRIV_NET_SETIFVNET); 30151fb51a12SBjoern A. Zeeb if (error == 0) 30161fb51a12SBjoern A. Zeeb error = if_vmove_reclaim(td, ifr->ifr_name, 30171fb51a12SBjoern A. Zeeb ifr->ifr_jid); 30183edb7f4eSBrooks Davis goto out_noref; 3019feb08d06SMarko Zec #endif 3020f13ad206SJonathan Lemon case SIOCIFCREATE: 30216b7330e2SSam Leffler case SIOCIFCREATE2: 3022acd3428bSRobert Watson error = priv_check(td, PRIV_NET_IFCREATE); 30231fb51a12SBjoern A. Zeeb if (error == 0) 30241fb51a12SBjoern A. Zeeb error = if_clone_create(ifr->ifr_name, 3025541d96aaSBrooks Davis sizeof(ifr->ifr_name), cmd == SIOCIFCREATE2 ? 3026541d96aaSBrooks Davis ifr_data_get_ptr(ifr) : NULL); 30273edb7f4eSBrooks Davis goto out_noref; 3028f13ad206SJonathan Lemon case SIOCIFDESTROY: 3029acd3428bSRobert Watson error = priv_check(td, PRIV_NET_IFDESTROY); 3030e133271fSKristof Provost 3031e133271fSKristof Provost if (error == 0) { 30326d2a10d9SKristof Provost sx_xlock(&ifnet_detach_sxlock); 30331fb51a12SBjoern A. Zeeb error = if_clone_destroy(ifr->ifr_name); 30346d2a10d9SKristof Provost sx_xunlock(&ifnet_detach_sxlock); 3035e133271fSKristof Provost } 30363edb7f4eSBrooks Davis goto out_noref; 3037f13ad206SJonathan Lemon 3038f13ad206SJonathan Lemon case SIOCIFGCLONERS: 30391fb51a12SBjoern A. Zeeb error = if_clone_list((struct if_clonereq *)data); 30403edb7f4eSBrooks Davis goto out_noref; 30413edb7f4eSBrooks Davis 3042bc6f170eSBrooks Davis case CASE_IOC_IFGROUPREQ(SIOCGIFGMEMB): 30431fb51a12SBjoern A. Zeeb error = if_getgroupmembers((struct ifgroupreq *)data); 30443edb7f4eSBrooks Davis goto out_noref; 30453edb7f4eSBrooks Davis 304608b68b0eSGleb Smirnoff #if defined(INET) || defined(INET6) 304708b68b0eSGleb Smirnoff case SIOCSVH: 304808b68b0eSGleb Smirnoff case SIOCGVH: 304908b68b0eSGleb Smirnoff if (carp_ioctl_p == NULL) 305008b68b0eSGleb Smirnoff error = EPROTONOSUPPORT; 305108b68b0eSGleb Smirnoff else 305208b68b0eSGleb Smirnoff error = (*carp_ioctl_p)(ifr, cmd, td); 30533edb7f4eSBrooks Davis goto out_noref; 305408b68b0eSGleb Smirnoff #endif 3055f13ad206SJonathan Lemon } 3056f13ad206SJonathan Lemon 30576064c5d3SRobert Watson ifp = ifunit_ref(ifr->ifr_name); 30581fb51a12SBjoern A. Zeeb if (ifp == NULL) { 30593edb7f4eSBrooks Davis error = ENXIO; 30603edb7f4eSBrooks Davis goto out_noref; 30611fb51a12SBjoern A. Zeeb } 3062f13ad206SJonathan Lemon 3063f13ad206SJonathan Lemon error = ifhwioctl(cmd, ifp, data, td); 30643edb7f4eSBrooks Davis if (error != ENOIOCTL) 30653edb7f4eSBrooks Davis goto out_ref; 3066f13ad206SJonathan Lemon 306782cd038dSYoshinobu Inoue oif_flags = ifp->if_flags; 30686064c5d3SRobert Watson if (so->so_proto == NULL) { 30693edb7f4eSBrooks Davis error = EOPNOTSUPP; 30703edb7f4eSBrooks Davis goto out_ref; 30716064c5d3SRobert Watson } 30721a05c762SDag-Erling Smørgrav 30731a05c762SDag-Erling Smørgrav /* 30741a05c762SDag-Erling Smørgrav * Pass the request on to the socket control method, and if the 30751a05c762SDag-Erling Smørgrav * latter returns EOPNOTSUPP, directly to the interface. 30761a05c762SDag-Erling Smørgrav * 30771a05c762SDag-Erling Smørgrav * Make an exception for the legacy SIOCSIF* requests. Drivers 30781a05c762SDag-Erling Smørgrav * trust SIOCSIFADDR et al to come from an already privileged 30791a05c762SDag-Erling Smørgrav * layer, and do not perform any credentials checks or input 30801a05c762SDag-Erling Smørgrav * validation. 30811a05c762SDag-Erling Smørgrav */ 30825fb009bdSGleb Smirnoff error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data, 3083b40ce416SJulian Elischer ifp, td)); 30841a05c762SDag-Erling Smørgrav if (error == EOPNOTSUPP && ifp != NULL && ifp->if_ioctl != NULL && 30851a05c762SDag-Erling Smørgrav cmd != SIOCSIFADDR && cmd != SIOCSIFBRDADDR && 30861a05c762SDag-Erling Smørgrav cmd != SIOCSIFDSTADDR && cmd != SIOCSIFNETMASK) 3087bc3977f1SJamie Gritton error = (*ifp->if_ioctl)(ifp, cmd, data); 308882cd038dSYoshinobu Inoue 308982cd038dSYoshinobu Inoue if ((oif_flags ^ ifp->if_flags) & IFF_UP) { 309082cd038dSYoshinobu Inoue #ifdef INET6 3091c9b652e3SAndre Oppermann if (ifp->if_flags & IFF_UP) 309282cd038dSYoshinobu Inoue in6_if_up(ifp); 309382cd038dSYoshinobu Inoue #endif 3094df8bae1dSRodney W. Grimes } 30953edb7f4eSBrooks Davis 30963edb7f4eSBrooks Davis out_ref: 30976064c5d3SRobert Watson if_rele(ifp); 30983edb7f4eSBrooks Davis out_noref: 3099d17e0940SJohn Baldwin CURVNET_RESTORE(); 31003edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32 3101d17e0940SJohn Baldwin if (error != 0) 3102d17e0940SJohn Baldwin return (error); 3103d17e0940SJohn Baldwin switch (saved_cmd) { 3104d17e0940SJohn Baldwin case SIOCGIFCONF32: 3105d17e0940SJohn Baldwin ifc32->ifc_len = thunk.ifc.ifc_len; 3106d17e0940SJohn Baldwin break; 3107*d61d98f4SJohn Baldwin case SIOCGDRVSPEC32: 3108*d61d98f4SJohn Baldwin /* 3109*d61d98f4SJohn Baldwin * SIOCGDRVSPEC is IOWR, but nothing actually touches 3110*d61d98f4SJohn Baldwin * the struct so just assert that ifd_len (the only 3111*d61d98f4SJohn Baldwin * field it might make sense to update) hasn't 3112*d61d98f4SJohn Baldwin * changed. 3113*d61d98f4SJohn Baldwin */ 3114*d61d98f4SJohn Baldwin KASSERT(thunk.ifd.ifd_len == ifd32->ifd_len, 3115*d61d98f4SJohn Baldwin ("ifd_len was updated %u -> %zu", ifd32->ifd_len, 3116*d61d98f4SJohn Baldwin thunk.ifd.ifd_len)); 3117*d61d98f4SJohn Baldwin break; 3118d17e0940SJohn Baldwin case SIOCGIFMEDIA32: 3119d17e0940SJohn Baldwin case SIOCGIFXMEDIA32: 3120d17e0940SJohn Baldwin ifmr32->ifm_current = thunk.ifmr.ifm_current; 3121d17e0940SJohn Baldwin ifmr32->ifm_mask = thunk.ifmr.ifm_mask; 3122d17e0940SJohn Baldwin ifmr32->ifm_status = thunk.ifmr.ifm_status; 3123d17e0940SJohn Baldwin ifmr32->ifm_active = thunk.ifmr.ifm_active; 3124d17e0940SJohn Baldwin ifmr32->ifm_count = thunk.ifmr.ifm_count; 3125d17e0940SJohn Baldwin break; 31263edb7f4eSBrooks Davis } 31273edb7f4eSBrooks Davis #endif 3128df8bae1dSRodney W. Grimes return (error); 3129df8bae1dSRodney W. Grimes } 3130df8bae1dSRodney W. Grimes 3131df8bae1dSRodney W. Grimes /* 3132292ee7beSRobert Watson * The code common to handling reference counted flags, 31331a3b6859SYaroslav Tykhiy * e.g., in ifpromisc() and if_allmulti(). 3134b5c8bd59SYaroslav Tykhiy * The "pflag" argument can specify a permanent mode flag to check, 31351a3b6859SYaroslav Tykhiy * such as IFF_PPROMISC for promiscuous mode; should be 0 if none. 3136292ee7beSRobert Watson * 3137292ee7beSRobert Watson * Only to be used on stack-owned flags, not driver-owned flags. 31381a3b6859SYaroslav Tykhiy */ 31391a3b6859SYaroslav Tykhiy static int 31401a3b6859SYaroslav Tykhiy if_setflag(struct ifnet *ifp, int flag, int pflag, int *refcount, int onswitch) 31411a3b6859SYaroslav Tykhiy { 31421a3b6859SYaroslav Tykhiy struct ifreq ifr; 31431a3b6859SYaroslav Tykhiy int error; 31441a3b6859SYaroslav Tykhiy int oldflags, oldcount; 31451a3b6859SYaroslav Tykhiy 31461a3b6859SYaroslav Tykhiy /* Sanity checks to catch programming errors */ 3147b5c8bd59SYaroslav Tykhiy KASSERT((flag & (IFF_DRV_OACTIVE|IFF_DRV_RUNNING)) == 0, 3148b5c8bd59SYaroslav Tykhiy ("%s: setting driver-owned flag %d", __func__, flag)); 3149b5c8bd59SYaroslav Tykhiy 3150b5c8bd59SYaroslav Tykhiy if (onswitch) 3151b5c8bd59SYaroslav Tykhiy KASSERT(*refcount >= 0, 3152b5c8bd59SYaroslav Tykhiy ("%s: increment negative refcount %d for flag %d", 3153b5c8bd59SYaroslav Tykhiy __func__, *refcount, flag)); 3154b5c8bd59SYaroslav Tykhiy else 3155b5c8bd59SYaroslav Tykhiy KASSERT(*refcount > 0, 3156b5c8bd59SYaroslav Tykhiy ("%s: decrement non-positive refcount %d for flag %d", 3157b5c8bd59SYaroslav Tykhiy __func__, *refcount, flag)); 31581a3b6859SYaroslav Tykhiy 31591a3b6859SYaroslav Tykhiy /* In case this mode is permanent, just touch refcount */ 31601a3b6859SYaroslav Tykhiy if (ifp->if_flags & pflag) { 31611a3b6859SYaroslav Tykhiy *refcount += onswitch ? 1 : -1; 31621a3b6859SYaroslav Tykhiy return (0); 31631a3b6859SYaroslav Tykhiy } 31641a3b6859SYaroslav Tykhiy 31651a3b6859SYaroslav Tykhiy /* Save ifnet parameters for if_ioctl() may fail */ 31661a3b6859SYaroslav Tykhiy oldcount = *refcount; 31671a3b6859SYaroslav Tykhiy oldflags = ifp->if_flags; 31681a3b6859SYaroslav Tykhiy 31691a3b6859SYaroslav Tykhiy /* 31701a3b6859SYaroslav Tykhiy * See if we aren't the only and touching refcount is enough. 31711a3b6859SYaroslav Tykhiy * Actually toggle interface flag if we are the first or last. 31721a3b6859SYaroslav Tykhiy */ 31731a3b6859SYaroslav Tykhiy if (onswitch) { 31741a3b6859SYaroslav Tykhiy if ((*refcount)++) 31751a3b6859SYaroslav Tykhiy return (0); 31761a3b6859SYaroslav Tykhiy ifp->if_flags |= flag; 31771a3b6859SYaroslav Tykhiy } else { 31781a3b6859SYaroslav Tykhiy if (--(*refcount)) 31791a3b6859SYaroslav Tykhiy return (0); 31801a3b6859SYaroslav Tykhiy ifp->if_flags &= ~flag; 31811a3b6859SYaroslav Tykhiy } 31821a3b6859SYaroslav Tykhiy 31831a3b6859SYaroslav Tykhiy /* Call down the driver since we've changed interface flags */ 31841a3b6859SYaroslav Tykhiy if (ifp->if_ioctl == NULL) { 31851a3b6859SYaroslav Tykhiy error = EOPNOTSUPP; 31861a3b6859SYaroslav Tykhiy goto recover; 31871a3b6859SYaroslav Tykhiy } 31881a3b6859SYaroslav Tykhiy ifr.ifr_flags = ifp->if_flags & 0xffff; 31891a3b6859SYaroslav Tykhiy ifr.ifr_flagshigh = ifp->if_flags >> 16; 31901a3b6859SYaroslav Tykhiy error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 31911a3b6859SYaroslav Tykhiy if (error) 31921a3b6859SYaroslav Tykhiy goto recover; 31931a3b6859SYaroslav Tykhiy /* Notify userland that interface flags have changed */ 31941a3b6859SYaroslav Tykhiy rt_ifmsg(ifp); 31951a3b6859SYaroslav Tykhiy return (0); 31961a3b6859SYaroslav Tykhiy 31971a3b6859SYaroslav Tykhiy recover: 31981a3b6859SYaroslav Tykhiy /* Recover after driver error */ 31991a3b6859SYaroslav Tykhiy *refcount = oldcount; 32001a3b6859SYaroslav Tykhiy ifp->if_flags = oldflags; 32011a3b6859SYaroslav Tykhiy return (error); 32021a3b6859SYaroslav Tykhiy } 32031a3b6859SYaroslav Tykhiy 32041a3b6859SYaroslav Tykhiy /* 3205963e4c2aSGarrett Wollman * Set/clear promiscuous mode on interface ifp based on the truth value 3206963e4c2aSGarrett Wollman * of pswitch. The calls are reference counted so that only the first 3207963e4c2aSGarrett Wollman * "on" request actually has an effect, as does the final "off" request. 3208963e4c2aSGarrett Wollman * Results are undefined if the "off" and "on" requests are not matched. 3209963e4c2aSGarrett Wollman */ 3210963e4c2aSGarrett Wollman int 321172fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch) 3212963e4c2aSGarrett Wollman { 32134a26224cSGarrett Wollman int error; 32141a3b6859SYaroslav Tykhiy int oldflags = ifp->if_flags; 3215963e4c2aSGarrett Wollman 32161a3b6859SYaroslav Tykhiy error = if_setflag(ifp, IFF_PROMISC, IFF_PPROMISC, 32171a3b6859SYaroslav Tykhiy &ifp->if_pcount, pswitch); 32181a3b6859SYaroslav Tykhiy /* If promiscuous mode status has changed, log a message */ 32196d07c157SNick Hibma if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC) && 32206d07c157SNick Hibma log_promisc_mode_change) 322120f8d7bcSDag-Erling Smørgrav if_printf(ifp, "promiscuous mode %s\n", 32224f3c11a6SBill Fenner (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled"); 32231a3b6859SYaroslav Tykhiy return (error); 3224963e4c2aSGarrett Wollman } 3225963e4c2aSGarrett Wollman 3226963e4c2aSGarrett Wollman /* 3227df8bae1dSRodney W. Grimes * Return interface configuration 3228df8bae1dSRodney W. Grimes * of system. List may be used 3229df8bae1dSRodney W. Grimes * in later ioctl's (above) to get 3230df8bae1dSRodney W. Grimes * other information. 3231df8bae1dSRodney W. Grimes */ 3232df8bae1dSRodney W. Grimes /*ARGSUSED*/ 32333bda9f9bSPoul-Henning Kamp static int 323472fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data) 3235df8bae1dSRodney W. Grimes { 32360b59d917SJonathan Lemon struct ifconf *ifc = (struct ifconf *)data; 32370b59d917SJonathan Lemon struct ifnet *ifp; 32380b59d917SJonathan Lemon struct ifaddr *ifa; 32394dcf2bbbSBrooks Davis struct ifreq ifr; 32404dcf2bbbSBrooks Davis struct sbuf *sb; 32414dcf2bbbSBrooks Davis int error, full = 0, valid_len, max_len; 3242df8bae1dSRodney W. Grimes 3243cd853791SKonstantin Belousov /* Limit initial buffer size to maxphys to avoid DoS from userspace. */ 3244cd853791SKonstantin Belousov max_len = maxphys - 1; 32454dcf2bbbSBrooks Davis 3246b0b4b28bSXin LI /* Prevent hostile input from being able to crash the system */ 3247b0b4b28bSXin LI if (ifc->ifc_len <= 0) 3248b0b4b28bSXin LI return (EINVAL); 3249b0b4b28bSXin LI 32504dcf2bbbSBrooks Davis again: 32514dcf2bbbSBrooks Davis if (ifc->ifc_len <= max_len) { 32524dcf2bbbSBrooks Davis max_len = ifc->ifc_len; 32534dcf2bbbSBrooks Davis full = 1; 32544dcf2bbbSBrooks Davis } 32554dcf2bbbSBrooks Davis sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN); 32564dcf2bbbSBrooks Davis max_len = 0; 32574dcf2bbbSBrooks Davis valid_len = 0; 32584dcf2bbbSBrooks Davis 325977dfcdc4SRobert Watson IFNET_RLOCK(); 32604f6c66ccSMatt Macy CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) { 3261a68cc388SGleb Smirnoff struct epoch_tracker et; 32629bf40edeSBrooks Davis int addrs; 32632624cf89SGarrett Wollman 3264fbd24c5eSColin Percival /* 32652443045fSBrooks Davis * Zero the ifr to make sure we don't disclose the contents 32662443045fSBrooks Davis * of the stack. 3267fbd24c5eSColin Percival */ 32682443045fSBrooks Davis memset(&ifr, 0, sizeof(ifr)); 3269fbd24c5eSColin Percival 32709bf40edeSBrooks Davis if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name)) 327162313e4cSSam Leffler >= sizeof(ifr.ifr_name)) { 327262313e4cSSam Leffler sbuf_delete(sb); 327362313e4cSSam Leffler IFNET_RUNLOCK(); 32744dcf2bbbSBrooks Davis return (ENAMETOOLONG); 327562313e4cSSam Leffler } 32762624cf89SGarrett Wollman 327775c13541SPoul-Henning Kamp addrs = 0; 3278a68cc388SGleb Smirnoff NET_EPOCH_ENTER(et); 3279d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 32802defe5cdSJonathan Lemon struct sockaddr *sa = ifa->ifa_addr; 32812defe5cdSJonathan Lemon 3282b89e82ddSJamie Gritton if (prison_if(curthread->td_ucred, sa) != 0) 328375c13541SPoul-Henning Kamp continue; 328475c13541SPoul-Henning Kamp addrs++; 3285df8bae1dSRodney W. Grimes if (sa->sa_len <= sizeof(*sa)) { 3286e7fdc72eSBrooks Davis if (sa->sa_len < sizeof(*sa)) { 3287e7fdc72eSBrooks Davis memset(&ifr.ifr_ifru.ifru_addr, 0, 3288e7fdc72eSBrooks Davis sizeof(ifr.ifr_ifru.ifru_addr)); 3289e7fdc72eSBrooks Davis memcpy(&ifr.ifr_ifru.ifru_addr, sa, 3290e7fdc72eSBrooks Davis sa->sa_len); 3291e7fdc72eSBrooks Davis } else 3292e7fdc72eSBrooks Davis ifr.ifr_ifru.ifru_addr = *sa; 32934dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 32944dcf2bbbSBrooks Davis max_len += sizeof(ifr); 3295df8bae1dSRodney W. Grimes } else { 32964dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, 32974dcf2bbbSBrooks Davis offsetof(struct ifreq, ifr_addr)); 32984dcf2bbbSBrooks Davis max_len += offsetof(struct ifreq, ifr_addr); 32994dcf2bbbSBrooks Davis sbuf_bcat(sb, sa, sa->sa_len); 33004dcf2bbbSBrooks Davis max_len += sa->sa_len; 3301df8bae1dSRodney W. Grimes } 33024dcf2bbbSBrooks Davis 33034d369413SMatthew D Fleming if (sbuf_error(sb) == 0) 33044dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 3305df8bae1dSRodney W. Grimes } 3306a68cc388SGleb Smirnoff NET_EPOCH_EXIT(et); 33074dcf2bbbSBrooks Davis if (addrs == 0) { 33084dcf2bbbSBrooks Davis sbuf_bcat(sb, &ifr, sizeof(ifr)); 33094dcf2bbbSBrooks Davis max_len += sizeof(ifr); 33104dcf2bbbSBrooks Davis 33114d369413SMatthew D Fleming if (sbuf_error(sb) == 0) 33124dcf2bbbSBrooks Davis valid_len = sbuf_len(sb); 331375c13541SPoul-Henning Kamp } 3314df8bae1dSRodney W. Grimes } 3315b30a244cSJeffrey Hsu IFNET_RUNLOCK(); 33164dcf2bbbSBrooks Davis 33174dcf2bbbSBrooks Davis /* 33184dcf2bbbSBrooks Davis * If we didn't allocate enough space (uncommon), try again. If 33194dcf2bbbSBrooks Davis * we have already allocated as much space as we are allowed, 33204dcf2bbbSBrooks Davis * return what we've got. 33214dcf2bbbSBrooks Davis */ 33224dcf2bbbSBrooks Davis if (valid_len != max_len && !full) { 33234dcf2bbbSBrooks Davis sbuf_delete(sb); 33244dcf2bbbSBrooks Davis goto again; 33254dcf2bbbSBrooks Davis } 33264dcf2bbbSBrooks Davis 33274dcf2bbbSBrooks Davis ifc->ifc_len = valid_len; 33285ed8cedcSBrian Feldman sbuf_finish(sb); 33294dcf2bbbSBrooks Davis error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len); 33304dcf2bbbSBrooks Davis sbuf_delete(sb); 3331df8bae1dSRodney W. Grimes return (error); 3332df8bae1dSRodney W. Grimes } 3333df8bae1dSRodney W. Grimes 33341158dfb7SGarrett Wollman /* 33358b25904eSGleb Smirnoff * Just like ifpromisc(), but for all-multicast-reception mode. 33361158dfb7SGarrett Wollman */ 33371158dfb7SGarrett Wollman int 333872fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch) 33391158dfb7SGarrett Wollman { 33401158dfb7SGarrett Wollman 33411a3b6859SYaroslav Tykhiy return (if_setflag(ifp, IFF_ALLMULTI, 0, &ifp->if_amcount, onswitch)); 33421158dfb7SGarrett Wollman } 33431158dfb7SGarrett Wollman 33445896d124SBruce M Simpson struct ifmultiaddr * 3345441f9243SAlexander V. Chernikov if_findmulti(struct ifnet *ifp, const struct sockaddr *sa) 33461158dfb7SGarrett Wollman { 33471158dfb7SGarrett Wollman struct ifmultiaddr *ifma; 33481158dfb7SGarrett Wollman 3349c3b31afdSRobert Watson IF_ADDR_LOCK_ASSERT(ifp); 3350c3b31afdSRobert Watson 3351d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 335240d8a302SBruce M Simpson if (sa->sa_family == AF_LINK) { 335340d8a302SBruce M Simpson if (sa_dl_equal(ifma->ifma_addr, sa)) 335440d8a302SBruce M Simpson break; 335540d8a302SBruce M Simpson } else { 3356c3b31afdSRobert Watson if (sa_equal(ifma->ifma_addr, sa)) 3357c3b31afdSRobert Watson break; 33581158dfb7SGarrett Wollman } 335940d8a302SBruce M Simpson } 3360c3b31afdSRobert Watson 3361c3b31afdSRobert Watson return ifma; 336257af7922SJulian Elischer } 33631158dfb7SGarrett Wollman 33641158dfb7SGarrett Wollman /* 3365c3b31afdSRobert Watson * Allocate a new ifmultiaddr and initialize based on passed arguments. We 3366c3b31afdSRobert Watson * make copies of passed sockaddrs. The ifmultiaddr will not be added to 3367c3b31afdSRobert Watson * the ifnet multicast address list here, so the caller must do that and 3368c3b31afdSRobert Watson * other setup work (such as notifying the device driver). The reference 3369c3b31afdSRobert Watson * count is initialized to 1. 33701158dfb7SGarrett Wollman */ 3371c3b31afdSRobert Watson static struct ifmultiaddr * 3372c3b31afdSRobert Watson if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa, 3373c3b31afdSRobert Watson int mflags) 3374c3b31afdSRobert Watson { 3375c3b31afdSRobert Watson struct ifmultiaddr *ifma; 3376c3b31afdSRobert Watson struct sockaddr *dupsa; 3377c3b31afdSRobert Watson 33781ede983cSDag-Erling Smørgrav ifma = malloc(sizeof *ifma, M_IFMADDR, mflags | 3379c3b31afdSRobert Watson M_ZERO); 3380c3b31afdSRobert Watson if (ifma == NULL) 3381c3b31afdSRobert Watson return (NULL); 3382c3b31afdSRobert Watson 33831ede983cSDag-Erling Smørgrav dupsa = malloc(sa->sa_len, M_IFMADDR, mflags); 3384c3b31afdSRobert Watson if (dupsa == NULL) { 33851ede983cSDag-Erling Smørgrav free(ifma, M_IFMADDR); 3386c3b31afdSRobert Watson return (NULL); 33871158dfb7SGarrett Wollman } 33881158dfb7SGarrett Wollman bcopy(sa, dupsa, sa->sa_len); 33891158dfb7SGarrett Wollman ifma->ifma_addr = dupsa; 3390c3b31afdSRobert Watson 33911158dfb7SGarrett Wollman ifma->ifma_ifp = ifp; 33921158dfb7SGarrett Wollman ifma->ifma_refcount = 1; 3393d4d22970SGleb Smirnoff ifma->ifma_protospec = NULL; 3394c3b31afdSRobert Watson 3395c3b31afdSRobert Watson if (llsa == NULL) { 3396c3b31afdSRobert Watson ifma->ifma_lladdr = NULL; 3397c3b31afdSRobert Watson return (ifma); 3398c3b31afdSRobert Watson } 3399c3b31afdSRobert Watson 34001ede983cSDag-Erling Smørgrav dupsa = malloc(llsa->sa_len, M_IFMADDR, mflags); 3401c3b31afdSRobert Watson if (dupsa == NULL) { 34021ede983cSDag-Erling Smørgrav free(ifma->ifma_addr, M_IFMADDR); 34031ede983cSDag-Erling Smørgrav free(ifma, M_IFMADDR); 3404c3b31afdSRobert Watson return (NULL); 3405c3b31afdSRobert Watson } 3406c3b31afdSRobert Watson bcopy(llsa, dupsa, llsa->sa_len); 3407c3b31afdSRobert Watson ifma->ifma_lladdr = dupsa; 3408c3b31afdSRobert Watson 3409c3b31afdSRobert Watson return (ifma); 3410c3b31afdSRobert Watson } 3411373f88edSGarrett Wollman 34121158dfb7SGarrett Wollman /* 3413c3b31afdSRobert Watson * if_freemulti: free ifmultiaddr structure and possibly attached related 3414c3b31afdSRobert Watson * addresses. The caller is responsible for implementing reference 3415c3b31afdSRobert Watson * counting, notifying the driver, handling routing messages, and releasing 3416c3b31afdSRobert Watson * any dependent link layer state. 34171158dfb7SGarrett Wollman */ 3418b6f6f880SMatt Macy #ifdef MCAST_VERBOSE 3419b6f6f880SMatt Macy extern void kdb_backtrace(void); 3420b6f6f880SMatt Macy #endif 3421d7c5a620SMatt Macy static void 3422d7c5a620SMatt Macy if_freemulti_internal(struct ifmultiaddr *ifma) 3423c3b31afdSRobert Watson { 3424c3b31afdSRobert Watson 3425ec002feeSBruce M Simpson KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d", 3426c3b31afdSRobert Watson ifma->ifma_refcount)); 3427c3b31afdSRobert Watson 3428c3b31afdSRobert Watson if (ifma->ifma_lladdr != NULL) 34291ede983cSDag-Erling Smørgrav free(ifma->ifma_lladdr, M_IFMADDR); 3430b6f6f880SMatt Macy #ifdef MCAST_VERBOSE 3431b6f6f880SMatt Macy kdb_backtrace(); 3432b6f6f880SMatt Macy printf("%s freeing ifma: %p\n", __func__, ifma); 3433b6f6f880SMatt Macy #endif 34341ede983cSDag-Erling Smørgrav free(ifma->ifma_addr, M_IFMADDR); 34351ede983cSDag-Erling Smørgrav free(ifma, M_IFMADDR); 3436c3b31afdSRobert Watson } 3437c3b31afdSRobert Watson 3438d7c5a620SMatt Macy static void 3439d7c5a620SMatt Macy if_destroymulti(epoch_context_t ctx) 3440d7c5a620SMatt Macy { 3441d7c5a620SMatt Macy struct ifmultiaddr *ifma; 3442d7c5a620SMatt Macy 3443d7c5a620SMatt Macy ifma = __containerof(ctx, struct ifmultiaddr, ifma_epoch_ctx); 3444d7c5a620SMatt Macy if_freemulti_internal(ifma); 3445d7c5a620SMatt Macy } 3446d7c5a620SMatt Macy 3447d7c5a620SMatt Macy void 3448d7c5a620SMatt Macy if_freemulti(struct ifmultiaddr *ifma) 3449d7c5a620SMatt Macy { 3450d7c5a620SMatt Macy KASSERT(ifma->ifma_refcount == 0, ("if_freemulti_epoch: refcount %d", 3451d7c5a620SMatt Macy ifma->ifma_refcount)); 3452d7c5a620SMatt Macy 34532a4bd982SGleb Smirnoff NET_EPOCH_CALL(if_destroymulti, &ifma->ifma_epoch_ctx); 3454d7c5a620SMatt Macy } 3455d7c5a620SMatt Macy 3456c3b31afdSRobert Watson /* 3457c3b31afdSRobert Watson * Register an additional multicast address with a network interface. 3458c3b31afdSRobert Watson * 3459c3b31afdSRobert Watson * - If the address is already present, bump the reference count on the 3460c3b31afdSRobert Watson * address and return. 3461c3b31afdSRobert Watson * - If the address is not link-layer, look up a link layer address. 3462c3b31afdSRobert Watson * - Allocate address structures for one or both addresses, and attach to the 3463c3b31afdSRobert Watson * multicast address list on the interface. If automatically adding a link 3464c3b31afdSRobert Watson * layer address, the protocol address will own a reference to the link 3465c3b31afdSRobert Watson * layer address, to be freed when it is freed. 3466c3b31afdSRobert Watson * - Notify the network device driver of an addition to the multicast address 3467c3b31afdSRobert Watson * list. 3468c3b31afdSRobert Watson * 3469c3b31afdSRobert Watson * 'sa' points to caller-owned memory with the desired multicast address. 3470c3b31afdSRobert Watson * 3471c3b31afdSRobert Watson * 'retifma' will be used to return a pointer to the resulting multicast 3472c3b31afdSRobert Watson * address reference, if desired. 3473c3b31afdSRobert Watson */ 3474c3b31afdSRobert Watson int 3475c3b31afdSRobert Watson if_addmulti(struct ifnet *ifp, struct sockaddr *sa, 3476c3b31afdSRobert Watson struct ifmultiaddr **retifma) 3477c3b31afdSRobert Watson { 3478c3b31afdSRobert Watson struct ifmultiaddr *ifma, *ll_ifma; 3479c3b31afdSRobert Watson struct sockaddr *llsa; 348095fbe4d0SAlexander V. Chernikov struct sockaddr_dl sdl; 3481c3b31afdSRobert Watson int error; 3482c3b31afdSRobert Watson 3483f3e1324bSStephen Hurd #ifdef INET 3484f3e1324bSStephen Hurd IN_MULTI_LIST_UNLOCK_ASSERT(); 3485f3e1324bSStephen Hurd #endif 3486f3e1324bSStephen Hurd #ifdef INET6 3487f3e1324bSStephen Hurd IN6_MULTI_LIST_UNLOCK_ASSERT(); 3488f3e1324bSStephen Hurd #endif 3489c3b31afdSRobert Watson /* 3490c3b31afdSRobert Watson * If the address is already present, return a new reference to it; 3491c3b31afdSRobert Watson * otherwise, allocate storage and set up a new address. 3492c3b31afdSRobert Watson */ 3493137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 3494c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 3495c3b31afdSRobert Watson if (ifma != NULL) { 3496c3b31afdSRobert Watson ifma->ifma_refcount++; 3497c3b31afdSRobert Watson if (retifma != NULL) 3498c3b31afdSRobert Watson *retifma = ifma; 3499137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 3500c3b31afdSRobert Watson return (0); 3501c3b31afdSRobert Watson } 3502c3b31afdSRobert Watson 3503c3b31afdSRobert Watson /* 3504c3b31afdSRobert Watson * The address isn't already present; resolve the protocol address 3505c3b31afdSRobert Watson * into a link layer address, and then look that up, bump its 350695fbe4d0SAlexander V. Chernikov * refcount or allocate an ifma for that also. 350795fbe4d0SAlexander V. Chernikov * Most link layer resolving functions returns address data which 350895fbe4d0SAlexander V. Chernikov * fits inside default sockaddr_dl structure. However callback 350995fbe4d0SAlexander V. Chernikov * can allocate another sockaddr structure, in that case we need to 351095fbe4d0SAlexander V. Chernikov * free it later. 3511c3b31afdSRobert Watson */ 3512c3b31afdSRobert Watson llsa = NULL; 3513c3b31afdSRobert Watson ll_ifma = NULL; 3514c3b31afdSRobert Watson if (ifp->if_resolvemulti != NULL) { 351595fbe4d0SAlexander V. Chernikov /* Provide called function with buffer size information */ 351695fbe4d0SAlexander V. Chernikov sdl.sdl_len = sizeof(sdl); 351795fbe4d0SAlexander V. Chernikov llsa = (struct sockaddr *)&sdl; 3518c3b31afdSRobert Watson error = ifp->if_resolvemulti(ifp, &llsa, sa); 3519c3b31afdSRobert Watson if (error) 3520c3b31afdSRobert Watson goto unlock_out; 3521c3b31afdSRobert Watson } 3522c3b31afdSRobert Watson 3523c3b31afdSRobert Watson /* 3524c3b31afdSRobert Watson * Allocate the new address. Don't hook it up yet, as we may also 3525c3b31afdSRobert Watson * need to allocate a link layer multicast address. 3526c3b31afdSRobert Watson */ 3527c3b31afdSRobert Watson ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT); 3528c3b31afdSRobert Watson if (ifma == NULL) { 3529c3b31afdSRobert Watson error = ENOMEM; 3530c3b31afdSRobert Watson goto free_llsa_out; 3531c3b31afdSRobert Watson } 3532c3b31afdSRobert Watson 3533c3b31afdSRobert Watson /* 3534c3b31afdSRobert Watson * If a link layer address is found, we'll need to see if it's 3535c3b31afdSRobert Watson * already present in the address list, or allocate is as well. 3536c3b31afdSRobert Watson * When this block finishes, the link layer address will be on the 3537c3b31afdSRobert Watson * list. 3538c3b31afdSRobert Watson */ 3539c3b31afdSRobert Watson if (llsa != NULL) { 3540c3b31afdSRobert Watson ll_ifma = if_findmulti(ifp, llsa); 3541c3b31afdSRobert Watson if (ll_ifma == NULL) { 3542c3b31afdSRobert Watson ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT); 3543c3b31afdSRobert Watson if (ll_ifma == NULL) { 3544ec002feeSBruce M Simpson --ifma->ifma_refcount; 3545c3b31afdSRobert Watson if_freemulti(ifma); 3546c3b31afdSRobert Watson error = ENOMEM; 3547c3b31afdSRobert Watson goto free_llsa_out; 3548c3b31afdSRobert Watson } 3549f9be0386SMatt Macy ll_ifma->ifma_flags |= IFMA_F_ENQUEUED; 3550d7c5a620SMatt Macy CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma, 3551c3b31afdSRobert Watson ifma_link); 3552c3b31afdSRobert Watson } else 3553c3b31afdSRobert Watson ll_ifma->ifma_refcount++; 3554ec002feeSBruce M Simpson ifma->ifma_llifma = ll_ifma; 3555c3b31afdSRobert Watson } 3556c3b31afdSRobert Watson 3557c3b31afdSRobert Watson /* 3558c3b31afdSRobert Watson * We now have a new multicast address, ifma, and possibly a new or 3559c3b31afdSRobert Watson * referenced link layer address. Add the primary address to the 3560c3b31afdSRobert Watson * ifnet address list. 3561c3b31afdSRobert Watson */ 3562f9be0386SMatt Macy ifma->ifma_flags |= IFMA_F_ENQUEUED; 3563d7c5a620SMatt Macy CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link); 3564c3b31afdSRobert Watson 356513990766SJonathan Mini if (retifma != NULL) 3566373f88edSGarrett Wollman *retifma = ifma; 35671158dfb7SGarrett Wollman 3568c3b31afdSRobert Watson /* 3569c3b31afdSRobert Watson * Must generate the message while holding the lock so that 'ifma' 3570c3b31afdSRobert Watson * pointer is still valid. 3571c3b31afdSRobert Watson */ 3572c3b31afdSRobert Watson rt_newmaddrmsg(RTM_NEWMADDR, ifma); 3573137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 3574c3b31afdSRobert Watson 35751158dfb7SGarrett Wollman /* 35761158dfb7SGarrett Wollman * We are certain we have added something, so call down to the 35771158dfb7SGarrett Wollman * interface to let them know about it. 35781158dfb7SGarrett Wollman */ 35792432c31cSRobert Watson if (ifp->if_ioctl != NULL) { 35800839aa5cSGleb Smirnoff if (THREAD_CAN_SLEEP()) 35811a3b6859SYaroslav Tykhiy (void )(*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0); 35820839aa5cSGleb Smirnoff else 35830839aa5cSGleb Smirnoff taskqueue_enqueue(taskqueue_swi, &ifp->if_addmultitask); 35841a3b6859SYaroslav Tykhiy } 35851158dfb7SGarrett Wollman 358695fbe4d0SAlexander V. Chernikov if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl)) 358795fbe4d0SAlexander V. Chernikov link_free_sdl(llsa); 3588c3b31afdSRobert Watson 3589c3b31afdSRobert Watson return (0); 3590c3b31afdSRobert Watson 3591c3b31afdSRobert Watson free_llsa_out: 359295fbe4d0SAlexander V. Chernikov if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl)) 359395fbe4d0SAlexander V. Chernikov link_free_sdl(llsa); 3594c3b31afdSRobert Watson 3595c3b31afdSRobert Watson unlock_out: 3596137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 3597c3b31afdSRobert Watson return (error); 35981158dfb7SGarrett Wollman } 35991158dfb7SGarrett Wollman 36000839aa5cSGleb Smirnoff static void 36010839aa5cSGleb Smirnoff if_siocaddmulti(void *arg, int pending) 36020839aa5cSGleb Smirnoff { 36030839aa5cSGleb Smirnoff struct ifnet *ifp; 36040839aa5cSGleb Smirnoff 36050839aa5cSGleb Smirnoff ifp = arg; 36060839aa5cSGleb Smirnoff #ifdef DIAGNOSTIC 36070839aa5cSGleb Smirnoff if (pending > 1) 36080839aa5cSGleb Smirnoff if_printf(ifp, "%d SIOCADDMULTI coalesced\n", pending); 36090839aa5cSGleb Smirnoff #endif 36109352fab6SGleb Smirnoff CURVNET_SET(ifp->if_vnet); 36110839aa5cSGleb Smirnoff (void )(*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0); 36129352fab6SGleb Smirnoff CURVNET_RESTORE(); 36130839aa5cSGleb Smirnoff } 36140839aa5cSGleb Smirnoff 36151158dfb7SGarrett Wollman /* 3616ec002feeSBruce M Simpson * Delete a multicast group membership by network-layer group address. 3617ec002feeSBruce M Simpson * 3618ec002feeSBruce M Simpson * Returns ENOENT if the entry could not be found. If ifp no longer 3619ec002feeSBruce M Simpson * exists, results are undefined. This entry point should only be used 3620ec002feeSBruce M Simpson * from subsystems which do appropriate locking to hold ifp for the 3621ec002feeSBruce M Simpson * duration of the call. 3622ec002feeSBruce M Simpson * Network-layer protocol domains must use if_delmulti_ifma(). 36231158dfb7SGarrett Wollman */ 36241158dfb7SGarrett Wollman int 362572fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa) 36261158dfb7SGarrett Wollman { 3627ec002feeSBruce M Simpson struct ifmultiaddr *ifma; 3628ec002feeSBruce M Simpson int lastref; 3629ec002feeSBruce M Simpson 3630416a1d1eSGleb Smirnoff KASSERT(ifp, ("%s: NULL ifp", __func__)); 36311158dfb7SGarrett Wollman 3632137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 3633ec002feeSBruce M Simpson lastref = 0; 3634c3b31afdSRobert Watson ifma = if_findmulti(ifp, sa); 3635ec002feeSBruce M Simpson if (ifma != NULL) 3636ec002feeSBruce M Simpson lastref = if_delmulti_locked(ifp, ifma, 0); 3637137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 3638c3b31afdSRobert Watson 3639ec002feeSBruce M Simpson if (ifma == NULL) 3640ec002feeSBruce M Simpson return (ENOENT); 3641ec002feeSBruce M Simpson 3642ec002feeSBruce M Simpson if (lastref && ifp->if_ioctl != NULL) { 36431a3b6859SYaroslav Tykhiy (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0); 364431302ebfSRobert Watson } 36451158dfb7SGarrett Wollman 3646ec002feeSBruce M Simpson return (0); 3647ec002feeSBruce M Simpson } 3648ec002feeSBruce M Simpson 3649ec002feeSBruce M Simpson /* 365093ec7edcSShteryana Shopova * Delete all multicast group membership for an interface. 365193ec7edcSShteryana Shopova * Should be used to quickly flush all multicast filters. 365293ec7edcSShteryana Shopova */ 365393ec7edcSShteryana Shopova void 365493ec7edcSShteryana Shopova if_delallmulti(struct ifnet *ifp) 365593ec7edcSShteryana Shopova { 365693ec7edcSShteryana Shopova struct ifmultiaddr *ifma; 365793ec7edcSShteryana Shopova struct ifmultiaddr *next; 365893ec7edcSShteryana Shopova 3659137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 3660d7c5a620SMatt Macy CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next) 366193ec7edcSShteryana Shopova if_delmulti_locked(ifp, ifma, 0); 3662137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 366393ec7edcSShteryana Shopova } 366493ec7edcSShteryana Shopova 3665b6f6f880SMatt Macy void 3666b6f6f880SMatt Macy if_delmulti_ifma(struct ifmultiaddr *ifma) 3667b6f6f880SMatt Macy { 3668b6f6f880SMatt Macy if_delmulti_ifma_flags(ifma, 0); 3669b6f6f880SMatt Macy } 3670b6f6f880SMatt Macy 367193ec7edcSShteryana Shopova /* 3672ec002feeSBruce M Simpson * Delete a multicast group membership by group membership pointer. 3673ec002feeSBruce M Simpson * Network-layer protocol domains must use this routine. 3674ec002feeSBruce M Simpson * 3675e5adda3dSRobert Watson * It is safe to call this routine if the ifp disappeared. 3676ec002feeSBruce M Simpson */ 3677ec002feeSBruce M Simpson void 3678b6f6f880SMatt Macy if_delmulti_ifma_flags(struct ifmultiaddr *ifma, int flags) 3679ec002feeSBruce M Simpson { 3680ec002feeSBruce M Simpson struct ifnet *ifp; 3681ec002feeSBruce M Simpson int lastref; 3682b6f6f880SMatt Macy MCDPRINTF("%s freeing ifma: %p\n", __func__, ifma); 3683f3e1324bSStephen Hurd #ifdef INET 3684f3e1324bSStephen Hurd IN_MULTI_LIST_UNLOCK_ASSERT(); 3685f3e1324bSStephen Hurd #endif 3686ec002feeSBruce M Simpson ifp = ifma->ifma_ifp; 3687ec002feeSBruce M Simpson #ifdef DIAGNOSTIC 3688ec002feeSBruce M Simpson if (ifp == NULL) { 3689ec002feeSBruce M Simpson printf("%s: ifma_ifp seems to be detached\n", __func__); 3690ec002feeSBruce M Simpson } else { 3691e9dc46ccSGleb Smirnoff struct epoch_tracker et; 3692ec002feeSBruce M Simpson struct ifnet *oifp; 3693ec002feeSBruce M Simpson 3694e9dc46ccSGleb Smirnoff NET_EPOCH_ENTER(et); 36954f6c66ccSMatt Macy CK_STAILQ_FOREACH(oifp, &V_ifnet, if_link) 3696ec002feeSBruce M Simpson if (ifp == oifp) 3697ec002feeSBruce M Simpson break; 3698e9dc46ccSGleb Smirnoff NET_EPOCH_EXIT(et); 36991ebec5faSMatt Macy if (ifp != oifp) 3700ec002feeSBruce M Simpson ifp = NULL; 3701ec002feeSBruce M Simpson } 3702ec002feeSBruce M Simpson #endif 3703ec002feeSBruce M Simpson /* 3704ec002feeSBruce M Simpson * If and only if the ifnet instance exists: Acquire the address lock. 3705ec002feeSBruce M Simpson */ 3706ec002feeSBruce M Simpson if (ifp != NULL) 3707137f91e8SJohn Baldwin IF_ADDR_WLOCK(ifp); 3708ec002feeSBruce M Simpson 3709b6f6f880SMatt Macy lastref = if_delmulti_locked(ifp, ifma, flags); 3710ec002feeSBruce M Simpson 3711ec002feeSBruce M Simpson if (ifp != NULL) { 3712ec002feeSBruce M Simpson /* 3713ec002feeSBruce M Simpson * If and only if the ifnet instance exists: 3714ec002feeSBruce M Simpson * Release the address lock. 3715ec002feeSBruce M Simpson * If the group was left: update the hardware hash filter. 3716ec002feeSBruce M Simpson */ 3717137f91e8SJohn Baldwin IF_ADDR_WUNLOCK(ifp); 3718ec002feeSBruce M Simpson if (lastref && ifp->if_ioctl != NULL) { 3719ec002feeSBruce M Simpson (void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0); 3720ec002feeSBruce M Simpson } 3721ec002feeSBruce M Simpson } 3722ec002feeSBruce M Simpson } 3723ec002feeSBruce M Simpson 3724ec002feeSBruce M Simpson /* 3725ec002feeSBruce M Simpson * Perform deletion of network-layer and/or link-layer multicast address. 3726ec002feeSBruce M Simpson * 3727ec002feeSBruce M Simpson * Return 0 if the reference count was decremented. 3728ec002feeSBruce M Simpson * Return 1 if the final reference was released, indicating that the 3729ec002feeSBruce M Simpson * hardware hash filter should be reprogrammed. 3730ec002feeSBruce M Simpson */ 3731ec002feeSBruce M Simpson static int 3732ec002feeSBruce M Simpson if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching) 3733ec002feeSBruce M Simpson { 3734ec002feeSBruce M Simpson struct ifmultiaddr *ll_ifma; 3735ec002feeSBruce M Simpson 3736ec002feeSBruce M Simpson if (ifp != NULL && ifma->ifma_ifp != NULL) { 3737ec002feeSBruce M Simpson KASSERT(ifma->ifma_ifp == ifp, 3738ec002feeSBruce M Simpson ("%s: inconsistent ifp %p", __func__, ifp)); 3739137f91e8SJohn Baldwin IF_ADDR_WLOCK_ASSERT(ifp); 3740ec002feeSBruce M Simpson } 3741ec002feeSBruce M Simpson 3742ec002feeSBruce M Simpson ifp = ifma->ifma_ifp; 3743b6f6f880SMatt Macy MCDPRINTF("%s freeing %p from %s \n", __func__, ifma, ifp ? ifp->if_xname : ""); 3744ec002feeSBruce M Simpson 3745ec002feeSBruce M Simpson /* 3746ec002feeSBruce M Simpson * If the ifnet is detaching, null out references to ifnet, 3747ec002feeSBruce M Simpson * so that upper protocol layers will notice, and not attempt 374875ae0c01SBruce M Simpson * to obtain locks for an ifnet which no longer exists. The 374975ae0c01SBruce M Simpson * routing socket announcement must happen before the ifnet 375075ae0c01SBruce M Simpson * instance is detached from the system. 3751ec002feeSBruce M Simpson */ 3752ec002feeSBruce M Simpson if (detaching) { 3753ec002feeSBruce M Simpson #ifdef DIAGNOSTIC 3754ec002feeSBruce M Simpson printf("%s: detaching ifnet instance %p\n", __func__, ifp); 3755ec002feeSBruce M Simpson #endif 375675ae0c01SBruce M Simpson /* 375775ae0c01SBruce M Simpson * ifp may already be nulled out if we are being reentered 375875ae0c01SBruce M Simpson * to delete the ll_ifma. 375975ae0c01SBruce M Simpson */ 376075ae0c01SBruce M Simpson if (ifp != NULL) { 376175ae0c01SBruce M Simpson rt_newmaddrmsg(RTM_DELMADDR, ifma); 3762ec002feeSBruce M Simpson ifma->ifma_ifp = NULL; 3763ec002feeSBruce M Simpson } 376475ae0c01SBruce M Simpson } 3765ec002feeSBruce M Simpson 3766ec002feeSBruce M Simpson if (--ifma->ifma_refcount > 0) 37671158dfb7SGarrett Wollman return 0; 3768ec002feeSBruce M Simpson 3769f9be0386SMatt Macy if (ifp != NULL && detaching == 0 && (ifma->ifma_flags & IFMA_F_ENQUEUED)) { 3770d7c5a620SMatt Macy CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link); 3771f9be0386SMatt Macy ifma->ifma_flags &= ~IFMA_F_ENQUEUED; 3772f9be0386SMatt Macy } 3773ec002feeSBruce M Simpson /* 3774ec002feeSBruce M Simpson * If this ifma is a network-layer ifma, a link-layer ifma may 3775ec002feeSBruce M Simpson * have been associated with it. Release it first if so. 3776ec002feeSBruce M Simpson */ 3777ec002feeSBruce M Simpson ll_ifma = ifma->ifma_llifma; 3778ec002feeSBruce M Simpson if (ll_ifma != NULL) { 3779ec002feeSBruce M Simpson KASSERT(ifma->ifma_lladdr != NULL, 3780ec002feeSBruce M Simpson ("%s: llifma w/o lladdr", __func__)); 3781ec002feeSBruce M Simpson if (detaching) 3782ec002feeSBruce M Simpson ll_ifma->ifma_ifp = NULL; /* XXX */ 3783ec002feeSBruce M Simpson if (--ll_ifma->ifma_refcount == 0) { 3784ec002feeSBruce M Simpson if (ifp != NULL) { 3785f9be0386SMatt Macy if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) { 3786d7c5a620SMatt Macy CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr, 3787ec002feeSBruce M Simpson ifma_link); 378877ad07b6SMatt Macy ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED; 3789f9be0386SMatt Macy } 3790ec002feeSBruce M Simpson } 3791ec002feeSBruce M Simpson if_freemulti(ll_ifma); 3792ec002feeSBruce M Simpson } 3793ec002feeSBruce M Simpson } 3794b6f6f880SMatt Macy #ifdef INVARIANTS 3795b6f6f880SMatt Macy if (ifp) { 3796b6f6f880SMatt Macy struct ifmultiaddr *ifmatmp; 3797ec002feeSBruce M Simpson 3798d7c5a620SMatt Macy CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link) 3799b6f6f880SMatt Macy MPASS(ifma != ifmatmp); 3800b6f6f880SMatt Macy } 3801b6f6f880SMatt Macy #endif 3802ec002feeSBruce M Simpson if_freemulti(ifma); 3803ec002feeSBruce M Simpson /* 3804ec002feeSBruce M Simpson * The last reference to this instance of struct ifmultiaddr 3805ec002feeSBruce M Simpson * was released; the hardware should be notified of this change. 3806ec002feeSBruce M Simpson */ 3807ec002feeSBruce M Simpson return 1; 38081158dfb7SGarrett Wollman } 38091158dfb7SGarrett Wollman 381066ce51ceSArchie Cobbs /* 381166ce51ceSArchie Cobbs * Set the link layer address on an interface. 381266ce51ceSArchie Cobbs * 381366ce51ceSArchie Cobbs * At this time we only support certain types of interfaces, 381466ce51ceSArchie Cobbs * and we don't allow the length of the address to change. 3815bb3d23fdSAlexander V. Chernikov * 3816bb3d23fdSAlexander V. Chernikov * Set noinline to be dtrace-friendly 381766ce51ceSArchie Cobbs */ 3818bb3d23fdSAlexander V. Chernikov __noinline int 381966ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len) 382066ce51ceSArchie Cobbs { 382166ce51ceSArchie Cobbs struct sockaddr_dl *sdl; 382266ce51ceSArchie Cobbs struct ifaddr *ifa; 3823d637e989SPeter Wemm struct ifreq ifr; 382466ce51ceSArchie Cobbs 38254a0d6638SRuslan Ermilov ifa = ifp->if_addr; 38261e80e4f2SGleb Smirnoff if (ifa == NULL) 38271e80e4f2SGleb Smirnoff return (EINVAL); 38284f6c66ccSMatt Macy 382966ce51ceSArchie Cobbs sdl = (struct sockaddr_dl *)ifa->ifa_addr; 38301e80e4f2SGleb Smirnoff if (sdl == NULL) 38311e80e4f2SGleb Smirnoff return (EINVAL); 38321e80e4f2SGleb Smirnoff 38331e80e4f2SGleb Smirnoff if (len != sdl->sdl_alen) /* don't allow length to change */ 38341e80e4f2SGleb Smirnoff return (EINVAL); 38351e80e4f2SGleb Smirnoff 383666ce51ceSArchie Cobbs switch (ifp->if_type) { 3837d09ed26fSRuslan Ermilov case IFT_ETHER: 383866ce51ceSArchie Cobbs case IFT_XETHER: 3839b7bffa71SYaroslav Tykhiy case IFT_L2VLAN: 38408f867517SAndrew Thompson case IFT_BRIDGE: 3841b47888ceSAndrew Thompson case IFT_IEEE8023ADLAG: 384266ce51ceSArchie Cobbs bcopy(lladdr, LLADDR(sdl), len); 384366ce51ceSArchie Cobbs break; 384466ce51ceSArchie Cobbs default: 38451e80e4f2SGleb Smirnoff return (ENODEV); 384666ce51ceSArchie Cobbs } 38473baaf297SRobert Watson 384866ce51ceSArchie Cobbs /* 384966ce51ceSArchie Cobbs * If the interface is already up, we need 385066ce51ceSArchie Cobbs * to re-init it in order to reprogram its 385166ce51ceSArchie Cobbs * address filter. 385266ce51ceSArchie Cobbs */ 385366ce51ceSArchie Cobbs if ((ifp->if_flags & IFF_UP) != 0) { 38541a3b6859SYaroslav Tykhiy if (ifp->if_ioctl) { 385566ce51ceSArchie Cobbs ifp->if_flags &= ~IFF_UP; 385662f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 385762f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 3858ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 385966ce51ceSArchie Cobbs ifp->if_flags |= IFF_UP; 386062f76486SMaxim Sobolev ifr.ifr_flags = ifp->if_flags & 0xffff; 386162f76486SMaxim Sobolev ifr.ifr_flagshigh = ifp->if_flags >> 16; 3862ee0a4f7eSSUZUKI Shinsuke (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr); 38631a3b6859SYaroslav Tykhiy } 386466ce51ceSArchie Cobbs } 38658ad43f2dSAlexander V. Chernikov EVENTHANDLER_INVOKE(iflladdr_event, ifp); 38661e80e4f2SGleb Smirnoff 386791d6c9b9SMatt Macy return (0); 386866ce51ceSArchie Cobbs } 386966ce51ceSArchie Cobbs 38709bf40edeSBrooks Davis /* 38714fb3a820SAlexander V. Chernikov * Compat function for handling basic encapsulation requests. 38724fb3a820SAlexander V. Chernikov * Not converted stacks (FDDI, IB, ..) supports traditional 38734fb3a820SAlexander V. Chernikov * output model: ARP (and other similar L2 protocols) are handled 38744fb3a820SAlexander V. Chernikov * inside output routine, arpresolve/nd6_resolve() returns MAC 38754fb3a820SAlexander V. Chernikov * address instead of full prepend. 38764fb3a820SAlexander V. Chernikov * 38774fb3a820SAlexander V. Chernikov * This function creates calculated header==MAC for IPv4/IPv6 and 38784fb3a820SAlexander V. Chernikov * returns EAFNOSUPPORT (which is then handled in ARP code) for other 38794fb3a820SAlexander V. Chernikov * address families. 38804fb3a820SAlexander V. Chernikov */ 38814fb3a820SAlexander V. Chernikov static int 38824fb3a820SAlexander V. Chernikov if_requestencap_default(struct ifnet *ifp, struct if_encap_req *req) 38834fb3a820SAlexander V. Chernikov { 38844fb3a820SAlexander V. Chernikov 38854fb3a820SAlexander V. Chernikov if (req->rtype != IFENCAP_LL) 38864fb3a820SAlexander V. Chernikov return (EOPNOTSUPP); 38874fb3a820SAlexander V. Chernikov 38884fb3a820SAlexander V. Chernikov if (req->bufsize < req->lladdr_len) 38894fb3a820SAlexander V. Chernikov return (ENOMEM); 38904fb3a820SAlexander V. Chernikov 38914fb3a820SAlexander V. Chernikov switch (req->family) { 38924fb3a820SAlexander V. Chernikov case AF_INET: 38934fb3a820SAlexander V. Chernikov case AF_INET6: 38944fb3a820SAlexander V. Chernikov break; 38954fb3a820SAlexander V. Chernikov default: 38964fb3a820SAlexander V. Chernikov return (EAFNOSUPPORT); 38974fb3a820SAlexander V. Chernikov } 38984fb3a820SAlexander V. Chernikov 38994fb3a820SAlexander V. Chernikov /* Copy lladdr to storage as is */ 39004fb3a820SAlexander V. Chernikov memmove(req->buf, req->lladdr, req->lladdr_len); 39014fb3a820SAlexander V. Chernikov req->bufsize = req->lladdr_len; 39024fb3a820SAlexander V. Chernikov req->lladdr_off = 0; 39034fb3a820SAlexander V. Chernikov 39044fb3a820SAlexander V. Chernikov return (0); 39054fb3a820SAlexander V. Chernikov } 39064fb3a820SAlexander V. Chernikov 39074fb3a820SAlexander V. Chernikov /* 390898a8fdf6SAndrey V. Elsukov * Tunnel interfaces can nest, also they may cause infinite recursion 390998a8fdf6SAndrey V. Elsukov * calls when misconfigured. We'll prevent this by detecting loops. 391098a8fdf6SAndrey V. Elsukov * High nesting level may cause stack exhaustion. We'll prevent this 391198a8fdf6SAndrey V. Elsukov * by introducing upper limit. 391298a8fdf6SAndrey V. Elsukov * 391398a8fdf6SAndrey V. Elsukov * Return 0, if tunnel nesting count is equal or less than limit. 391498a8fdf6SAndrey V. Elsukov */ 391598a8fdf6SAndrey V. Elsukov int 391698a8fdf6SAndrey V. Elsukov if_tunnel_check_nesting(struct ifnet *ifp, struct mbuf *m, uint32_t cookie, 391798a8fdf6SAndrey V. Elsukov int limit) 391898a8fdf6SAndrey V. Elsukov { 391998a8fdf6SAndrey V. Elsukov struct m_tag *mtag; 392098a8fdf6SAndrey V. Elsukov int count; 392198a8fdf6SAndrey V. Elsukov 392298a8fdf6SAndrey V. Elsukov count = 1; 392398a8fdf6SAndrey V. Elsukov mtag = NULL; 392498a8fdf6SAndrey V. Elsukov while ((mtag = m_tag_locate(m, cookie, 0, mtag)) != NULL) { 392598a8fdf6SAndrey V. Elsukov if (*(struct ifnet **)(mtag + 1) == ifp) { 392698a8fdf6SAndrey V. Elsukov log(LOG_NOTICE, "%s: loop detected\n", if_name(ifp)); 392798a8fdf6SAndrey V. Elsukov return (EIO); 392898a8fdf6SAndrey V. Elsukov } 392998a8fdf6SAndrey V. Elsukov count++; 393098a8fdf6SAndrey V. Elsukov } 393198a8fdf6SAndrey V. Elsukov if (count > limit) { 393298a8fdf6SAndrey V. Elsukov log(LOG_NOTICE, 393398a8fdf6SAndrey V. Elsukov "%s: if_output recursively called too many times(%d)\n", 393498a8fdf6SAndrey V. Elsukov if_name(ifp), count); 393598a8fdf6SAndrey V. Elsukov return (EIO); 393698a8fdf6SAndrey V. Elsukov } 393798a8fdf6SAndrey V. Elsukov mtag = m_tag_alloc(cookie, 0, sizeof(struct ifnet *), M_NOWAIT); 393898a8fdf6SAndrey V. Elsukov if (mtag == NULL) 393998a8fdf6SAndrey V. Elsukov return (ENOMEM); 394098a8fdf6SAndrey V. Elsukov *(struct ifnet **)(mtag + 1) = ifp; 394198a8fdf6SAndrey V. Elsukov m_tag_prepend(m, mtag); 394298a8fdf6SAndrey V. Elsukov return (0); 394398a8fdf6SAndrey V. Elsukov } 394498a8fdf6SAndrey V. Elsukov 394598a8fdf6SAndrey V. Elsukov /* 3946ddae5750SRavi Pokala * Get the link layer address that was read from the hardware at attach. 3947ddae5750SRavi Pokala * 3948ddae5750SRavi Pokala * This is only set by Ethernet NICs (IFT_ETHER), but laggX interfaces re-type 3949ddae5750SRavi Pokala * their component interfaces as IFT_IEEE8023ADLAG. 3950ddae5750SRavi Pokala */ 3951ddae5750SRavi Pokala int 3952ddae5750SRavi Pokala if_gethwaddr(struct ifnet *ifp, struct ifreq *ifr) 3953ddae5750SRavi Pokala { 3954ddae5750SRavi Pokala 3955ddae5750SRavi Pokala if (ifp->if_hw_addr == NULL) 3956ddae5750SRavi Pokala return (ENODEV); 3957ddae5750SRavi Pokala 3958ddae5750SRavi Pokala switch (ifp->if_type) { 3959ddae5750SRavi Pokala case IFT_ETHER: 3960ddae5750SRavi Pokala case IFT_IEEE8023ADLAG: 3961ddae5750SRavi Pokala bcopy(ifp->if_hw_addr, ifr->ifr_addr.sa_data, ifp->if_addrlen); 3962ddae5750SRavi Pokala return (0); 3963ddae5750SRavi Pokala default: 3964ddae5750SRavi Pokala return (ENODEV); 3965ddae5750SRavi Pokala } 3966ddae5750SRavi Pokala } 3967ddae5750SRavi Pokala 3968ddae5750SRavi Pokala /* 39699bf40edeSBrooks Davis * The name argument must be a pointer to storage which will last as 39709bf40edeSBrooks Davis * long as the interface does. For physical devices, the result of 39719bf40edeSBrooks Davis * device_get_name(dev) is a good choice and for pseudo-devices a 39729bf40edeSBrooks Davis * static string works well. 39739bf40edeSBrooks Davis */ 39749bf40edeSBrooks Davis void 39759bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit) 39769bf40edeSBrooks Davis { 39779bf40edeSBrooks Davis ifp->if_dname = name; 39789bf40edeSBrooks Davis ifp->if_dunit = unit; 39799bf40edeSBrooks Davis if (unit != IF_DUNIT_NONE) 39809bf40edeSBrooks Davis snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit); 39819bf40edeSBrooks Davis else 39829bf40edeSBrooks Davis strlcpy(ifp->if_xname, name, IFNAMSIZ); 39839bf40edeSBrooks Davis } 39849bf40edeSBrooks Davis 398525bfa448SAdrian Chadd static int 398625bfa448SAdrian Chadd if_vlog(struct ifnet *ifp, int pri, const char *fmt, va_list ap) 398725bfa448SAdrian Chadd { 398825bfa448SAdrian Chadd char if_fmt[256]; 398925bfa448SAdrian Chadd 399025bfa448SAdrian Chadd snprintf(if_fmt, sizeof(if_fmt), "%s: %s", ifp->if_xname, fmt); 399125bfa448SAdrian Chadd vlog(pri, if_fmt, ap); 399225bfa448SAdrian Chadd return (0); 399325bfa448SAdrian Chadd } 399425bfa448SAdrian Chadd 399525bfa448SAdrian Chadd 3996fa882e87SBrooks Davis int 3997fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char *fmt, ...) 3998fa882e87SBrooks Davis { 3999fa882e87SBrooks Davis va_list ap; 4000fa882e87SBrooks Davis 4001fa882e87SBrooks Davis va_start(ap, fmt); 400225bfa448SAdrian Chadd if_vlog(ifp, LOG_INFO, fmt, ap); 400325bfa448SAdrian Chadd va_end(ap); 400425bfa448SAdrian Chadd return (0); 400525bfa448SAdrian Chadd } 400625bfa448SAdrian Chadd 400725bfa448SAdrian Chadd int 400825bfa448SAdrian Chadd if_log(struct ifnet *ifp, int pri, const char *fmt, ...) 400925bfa448SAdrian Chadd { 401025bfa448SAdrian Chadd va_list ap; 401125bfa448SAdrian Chadd 401225bfa448SAdrian Chadd va_start(ap, fmt); 401325bfa448SAdrian Chadd if_vlog(ifp, pri, fmt, ap); 4014fa882e87SBrooks Davis va_end(ap); 401520f8d7bcSDag-Erling Smørgrav return (0); 4016fa882e87SBrooks Davis } 4017fa882e87SBrooks Davis 4018af5e59bfSRobert Watson void 4019af5e59bfSRobert Watson if_start(struct ifnet *ifp) 4020af5e59bfSRobert Watson { 4021af5e59bfSRobert Watson 4022af5e59bfSRobert Watson (*(ifp)->if_start)(ifp); 4023af5e59bfSRobert Watson } 4024af5e59bfSRobert Watson 4025db7f0b97SKip Macy /* 4026db7f0b97SKip Macy * Backwards compatibility interface for drivers 4027db7f0b97SKip Macy * that have not implemented it 4028db7f0b97SKip Macy */ 4029db7f0b97SKip Macy static int 4030db7f0b97SKip Macy if_transmit(struct ifnet *ifp, struct mbuf *m) 4031db7f0b97SKip Macy { 4032db7f0b97SKip Macy int error; 4033db7f0b97SKip Macy 4034db7f0b97SKip Macy IFQ_HANDOFF(ifp, m, error); 4035db7f0b97SKip Macy return (error); 4036db7f0b97SKip Macy } 4037db7f0b97SKip Macy 4038b57d9721SAndrey V. Elsukov static void 4039b57d9721SAndrey V. Elsukov if_input_default(struct ifnet *ifp __unused, struct mbuf *m) 4040b57d9721SAndrey V. Elsukov { 4041b57d9721SAndrey V. Elsukov 4042b57d9721SAndrey V. Elsukov m_freem(m); 4043b57d9721SAndrey V. Elsukov } 4044b57d9721SAndrey V. Elsukov 40450b762445SRobert Watson int 40460b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust) 40470b762445SRobert Watson { 40480b762445SRobert Watson int active = 0; 40490b762445SRobert Watson 40500b762445SRobert Watson IF_LOCK(ifq); 40510b762445SRobert Watson if (_IF_QFULL(ifq)) { 40520b762445SRobert Watson IF_UNLOCK(ifq); 4053112f50ffSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1); 40540b762445SRobert Watson m_freem(m); 40550b762445SRobert Watson return (0); 40560b762445SRobert Watson } 40570b762445SRobert Watson if (ifp != NULL) { 4058112f50ffSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len + adjust); 40590b762445SRobert Watson if (m->m_flags & (M_BCAST|M_MCAST)) 4060112f50ffSGleb Smirnoff if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1); 4061292ee7beSRobert Watson active = ifp->if_drv_flags & IFF_DRV_OACTIVE; 40620b762445SRobert Watson } 40630b762445SRobert Watson _IF_ENQUEUE(ifq, m); 40640b762445SRobert Watson IF_UNLOCK(ifq); 40650b762445SRobert Watson if (ifp != NULL && !active) 4066e5adda3dSRobert Watson (*(ifp)->if_start)(ifp); 40670b762445SRobert Watson return (1); 40680b762445SRobert Watson } 4069fc74a9f9SBrooks Davis 4070fc74a9f9SBrooks Davis void 4071fc74a9f9SBrooks Davis if_register_com_alloc(u_char type, 4072fc74a9f9SBrooks Davis if_com_alloc_t *a, if_com_free_t *f) 4073fc74a9f9SBrooks Davis { 4074fc74a9f9SBrooks Davis 4075fc74a9f9SBrooks Davis KASSERT(if_com_alloc[type] == NULL, 4076fc74a9f9SBrooks Davis ("if_register_com_alloc: %d already registered", type)); 4077fc74a9f9SBrooks Davis KASSERT(if_com_free[type] == NULL, 4078fc74a9f9SBrooks Davis ("if_register_com_alloc: %d free already registered", type)); 4079fc74a9f9SBrooks Davis 4080fc74a9f9SBrooks Davis if_com_alloc[type] = a; 4081fc74a9f9SBrooks Davis if_com_free[type] = f; 4082fc74a9f9SBrooks Davis } 4083fc74a9f9SBrooks Davis 4084fc74a9f9SBrooks Davis void 4085fc74a9f9SBrooks Davis if_deregister_com_alloc(u_char type) 4086fc74a9f9SBrooks Davis { 4087fc74a9f9SBrooks Davis 4088affcaf78SMax Khon KASSERT(if_com_alloc[type] != NULL, 4089fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d not registered", type)); 4090affcaf78SMax Khon KASSERT(if_com_free[type] != NULL, 4091fc74a9f9SBrooks Davis ("if_deregister_com_alloc: %d free not registered", type)); 4092092f3f08STai-hwa Liang 4093092f3f08STai-hwa Liang /* 4094092f3f08STai-hwa Liang * Ensure all pending EPOCH(9) callbacks have been executed. This 4095092f3f08STai-hwa Liang * fixes issues about late invocation of if_destroy(), which leads 4096092f3f08STai-hwa Liang * to memory leak from if_com_alloc[type] allocated if_l2com. 4097092f3f08STai-hwa Liang */ 4098092f3f08STai-hwa Liang epoch_drain_callbacks(net_epoch_preempt); 4099092f3f08STai-hwa Liang 4100fc74a9f9SBrooks Davis if_com_alloc[type] = NULL; 4101fc74a9f9SBrooks Davis if_com_free[type] = NULL; 4102fc74a9f9SBrooks Davis } 410362d76917SMarcel Moolenaar 410462d76917SMarcel Moolenaar /* API for driver access to network stack owned ifnet.*/ 410562d76917SMarcel Moolenaar uint64_t 410609a8241fSGleb Smirnoff if_setbaudrate(struct ifnet *ifp, uint64_t baudrate) 410762d76917SMarcel Moolenaar { 410862d76917SMarcel Moolenaar uint64_t oldbrate; 410962d76917SMarcel Moolenaar 411062d76917SMarcel Moolenaar oldbrate = ifp->if_baudrate; 411162d76917SMarcel Moolenaar ifp->if_baudrate = baudrate; 411262d76917SMarcel Moolenaar return (oldbrate); 411362d76917SMarcel Moolenaar } 411462d76917SMarcel Moolenaar 411562d76917SMarcel Moolenaar uint64_t 411662d76917SMarcel Moolenaar if_getbaudrate(if_t ifp) 411762d76917SMarcel Moolenaar { 411862d76917SMarcel Moolenaar 411962d76917SMarcel Moolenaar return (((struct ifnet *)ifp)->if_baudrate); 412062d76917SMarcel Moolenaar } 412162d76917SMarcel Moolenaar 412262d76917SMarcel Moolenaar int 412362d76917SMarcel Moolenaar if_setcapabilities(if_t ifp, int capabilities) 412462d76917SMarcel Moolenaar { 412562d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_capabilities = capabilities; 412662d76917SMarcel Moolenaar return (0); 412762d76917SMarcel Moolenaar } 412862d76917SMarcel Moolenaar 412962d76917SMarcel Moolenaar int 413062d76917SMarcel Moolenaar if_setcapabilitiesbit(if_t ifp, int setbit, int clearbit) 413162d76917SMarcel Moolenaar { 413262d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_capabilities |= setbit; 413362d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_capabilities &= ~clearbit; 413462d76917SMarcel Moolenaar 413562d76917SMarcel Moolenaar return (0); 413662d76917SMarcel Moolenaar } 413762d76917SMarcel Moolenaar 413862d76917SMarcel Moolenaar int 413962d76917SMarcel Moolenaar if_getcapabilities(if_t ifp) 414062d76917SMarcel Moolenaar { 414162d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_capabilities; 414262d76917SMarcel Moolenaar } 414362d76917SMarcel Moolenaar 414462d76917SMarcel Moolenaar int 414562d76917SMarcel Moolenaar if_setcapenable(if_t ifp, int capabilities) 414662d76917SMarcel Moolenaar { 414762d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_capenable = capabilities; 414862d76917SMarcel Moolenaar return (0); 414962d76917SMarcel Moolenaar } 415062d76917SMarcel Moolenaar 415162d76917SMarcel Moolenaar int 415262d76917SMarcel Moolenaar if_setcapenablebit(if_t ifp, int setcap, int clearcap) 415362d76917SMarcel Moolenaar { 415462d76917SMarcel Moolenaar if(setcap) 415562d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_capenable |= setcap; 415662d76917SMarcel Moolenaar if(clearcap) 415762d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_capenable &= ~clearcap; 415862d76917SMarcel Moolenaar 415962d76917SMarcel Moolenaar return (0); 416062d76917SMarcel Moolenaar } 416162d76917SMarcel Moolenaar 416262d76917SMarcel Moolenaar const char * 416362d76917SMarcel Moolenaar if_getdname(if_t ifp) 416462d76917SMarcel Moolenaar { 416562d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_dname; 416662d76917SMarcel Moolenaar } 416762d76917SMarcel Moolenaar 416862d76917SMarcel Moolenaar int 416962d76917SMarcel Moolenaar if_togglecapenable(if_t ifp, int togglecap) 417062d76917SMarcel Moolenaar { 417162d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_capenable ^= togglecap; 417262d76917SMarcel Moolenaar return (0); 417362d76917SMarcel Moolenaar } 417462d76917SMarcel Moolenaar 417562d76917SMarcel Moolenaar int 417662d76917SMarcel Moolenaar if_getcapenable(if_t ifp) 417762d76917SMarcel Moolenaar { 417862d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_capenable; 417962d76917SMarcel Moolenaar } 418062d76917SMarcel Moolenaar 418162d76917SMarcel Moolenaar /* 418262d76917SMarcel Moolenaar * This is largely undesirable because it ties ifnet to a device, but does 418362d76917SMarcel Moolenaar * provide flexiblity for an embedded product vendor. Should be used with 418462d76917SMarcel Moolenaar * the understanding that it violates the interface boundaries, and should be 418562d76917SMarcel Moolenaar * a last resort only. 418662d76917SMarcel Moolenaar */ 418762d76917SMarcel Moolenaar int 418862d76917SMarcel Moolenaar if_setdev(if_t ifp, void *dev) 418962d76917SMarcel Moolenaar { 419062d76917SMarcel Moolenaar return (0); 419162d76917SMarcel Moolenaar } 419262d76917SMarcel Moolenaar 419362d76917SMarcel Moolenaar int 419462d76917SMarcel Moolenaar if_setdrvflagbits(if_t ifp, int set_flags, int clear_flags) 419562d76917SMarcel Moolenaar { 419662d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_drv_flags |= set_flags; 419762d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_drv_flags &= ~clear_flags; 419862d76917SMarcel Moolenaar 419962d76917SMarcel Moolenaar return (0); 420062d76917SMarcel Moolenaar } 420162d76917SMarcel Moolenaar 420262d76917SMarcel Moolenaar int 420362d76917SMarcel Moolenaar if_getdrvflags(if_t ifp) 420462d76917SMarcel Moolenaar { 420562d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_drv_flags; 420662d76917SMarcel Moolenaar } 420762d76917SMarcel Moolenaar 420862d76917SMarcel Moolenaar int 420962d76917SMarcel Moolenaar if_setdrvflags(if_t ifp, int flags) 421062d76917SMarcel Moolenaar { 421162d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_drv_flags = flags; 421262d76917SMarcel Moolenaar return (0); 421362d76917SMarcel Moolenaar } 421462d76917SMarcel Moolenaar 421562d76917SMarcel Moolenaar int 421662d76917SMarcel Moolenaar if_setflags(if_t ifp, int flags) 421762d76917SMarcel Moolenaar { 4218e87c4940SGleb Smirnoff 4219e87c4940SGleb Smirnoff ifp->if_flags = flags; 422062d76917SMarcel Moolenaar return (0); 422162d76917SMarcel Moolenaar } 422262d76917SMarcel Moolenaar 422362d76917SMarcel Moolenaar int 422462d76917SMarcel Moolenaar if_setflagbits(if_t ifp, int set, int clear) 422562d76917SMarcel Moolenaar { 422662d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_flags |= set; 422762d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_flags &= ~clear; 422862d76917SMarcel Moolenaar 422962d76917SMarcel Moolenaar return (0); 423062d76917SMarcel Moolenaar } 423162d76917SMarcel Moolenaar 423262d76917SMarcel Moolenaar int 423362d76917SMarcel Moolenaar if_getflags(if_t ifp) 423462d76917SMarcel Moolenaar { 423562d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_flags; 423662d76917SMarcel Moolenaar } 423762d76917SMarcel Moolenaar 423862d76917SMarcel Moolenaar int 423962d76917SMarcel Moolenaar if_clearhwassist(if_t ifp) 424062d76917SMarcel Moolenaar { 424162d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_hwassist = 0; 424262d76917SMarcel Moolenaar return (0); 424362d76917SMarcel Moolenaar } 424462d76917SMarcel Moolenaar 424562d76917SMarcel Moolenaar int 424662d76917SMarcel Moolenaar if_sethwassistbits(if_t ifp, int toset, int toclear) 424762d76917SMarcel Moolenaar { 424862d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_hwassist |= toset; 424962d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_hwassist &= ~toclear; 425062d76917SMarcel Moolenaar 425162d76917SMarcel Moolenaar return (0); 425262d76917SMarcel Moolenaar } 425362d76917SMarcel Moolenaar 425462d76917SMarcel Moolenaar int 425562d76917SMarcel Moolenaar if_sethwassist(if_t ifp, int hwassist_bit) 425662d76917SMarcel Moolenaar { 425762d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_hwassist = hwassist_bit; 425862d76917SMarcel Moolenaar return (0); 425962d76917SMarcel Moolenaar } 426062d76917SMarcel Moolenaar 426162d76917SMarcel Moolenaar int 426262d76917SMarcel Moolenaar if_gethwassist(if_t ifp) 426362d76917SMarcel Moolenaar { 426462d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_hwassist; 426562d76917SMarcel Moolenaar } 426662d76917SMarcel Moolenaar 426762d76917SMarcel Moolenaar int 426862d76917SMarcel Moolenaar if_setmtu(if_t ifp, int mtu) 426962d76917SMarcel Moolenaar { 427062d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_mtu = mtu; 427162d76917SMarcel Moolenaar return (0); 427262d76917SMarcel Moolenaar } 427362d76917SMarcel Moolenaar 427462d76917SMarcel Moolenaar int 427562d76917SMarcel Moolenaar if_getmtu(if_t ifp) 427662d76917SMarcel Moolenaar { 427762d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_mtu; 427862d76917SMarcel Moolenaar } 427962d76917SMarcel Moolenaar 428062d76917SMarcel Moolenaar int 42811a75e3b2SAlexander V. Chernikov if_getmtu_family(if_t ifp, int family) 42821a75e3b2SAlexander V. Chernikov { 42831a75e3b2SAlexander V. Chernikov struct domain *dp; 42841a75e3b2SAlexander V. Chernikov 42851a75e3b2SAlexander V. Chernikov for (dp = domains; dp; dp = dp->dom_next) { 42861a75e3b2SAlexander V. Chernikov if (dp->dom_family == family && dp->dom_ifmtu != NULL) 42871a75e3b2SAlexander V. Chernikov return (dp->dom_ifmtu((struct ifnet *)ifp)); 42881a75e3b2SAlexander V. Chernikov } 42891a75e3b2SAlexander V. Chernikov 42901a75e3b2SAlexander V. Chernikov return (((struct ifnet *)ifp)->if_mtu); 42911a75e3b2SAlexander V. Chernikov } 42921a75e3b2SAlexander V. Chernikov 4293826857c8SGleb Smirnoff /* 4294826857c8SGleb Smirnoff * Methods for drivers to access interface unicast and multicast 4295826857c8SGleb Smirnoff * link level addresses. Driver shall not know 'struct ifaddr' neither 4296826857c8SGleb Smirnoff * 'struct ifmultiaddr'. 4297826857c8SGleb Smirnoff */ 4298826857c8SGleb Smirnoff u_int 4299fb3fc771SGleb Smirnoff if_lladdr_count(if_t ifp) 4300fb3fc771SGleb Smirnoff { 4301fb3fc771SGleb Smirnoff struct epoch_tracker et; 4302fb3fc771SGleb Smirnoff struct ifaddr *ifa; 4303fb3fc771SGleb Smirnoff u_int count; 4304fb3fc771SGleb Smirnoff 4305fb3fc771SGleb Smirnoff count = 0; 4306fb3fc771SGleb Smirnoff NET_EPOCH_ENTER(et); 4307fb3fc771SGleb Smirnoff CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) 4308fb3fc771SGleb Smirnoff if (ifa->ifa_addr->sa_family == AF_LINK) 4309fb3fc771SGleb Smirnoff count++; 4310fb3fc771SGleb Smirnoff NET_EPOCH_EXIT(et); 4311fb3fc771SGleb Smirnoff 4312fb3fc771SGleb Smirnoff return (count); 4313fb3fc771SGleb Smirnoff } 4314fb3fc771SGleb Smirnoff 4315fb3fc771SGleb Smirnoff u_int 4316826857c8SGleb Smirnoff if_foreach_lladdr(if_t ifp, iflladdr_cb_t cb, void *cb_arg) 4317826857c8SGleb Smirnoff { 4318826857c8SGleb Smirnoff struct epoch_tracker et; 4319826857c8SGleb Smirnoff struct ifaddr *ifa; 4320826857c8SGleb Smirnoff u_int count; 4321826857c8SGleb Smirnoff 4322826857c8SGleb Smirnoff MPASS(cb); 4323826857c8SGleb Smirnoff 4324826857c8SGleb Smirnoff count = 0; 4325826857c8SGleb Smirnoff NET_EPOCH_ENTER(et); 4326826857c8SGleb Smirnoff CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { 4327826857c8SGleb Smirnoff if (ifa->ifa_addr->sa_family != AF_LINK) 4328826857c8SGleb Smirnoff continue; 4329826857c8SGleb Smirnoff count += (*cb)(cb_arg, (struct sockaddr_dl *)ifa->ifa_addr, 4330826857c8SGleb Smirnoff count); 4331826857c8SGleb Smirnoff } 4332826857c8SGleb Smirnoff NET_EPOCH_EXIT(et); 4333826857c8SGleb Smirnoff 4334826857c8SGleb Smirnoff return (count); 4335826857c8SGleb Smirnoff } 4336826857c8SGleb Smirnoff 4337826857c8SGleb Smirnoff u_int 4338fb3fc771SGleb Smirnoff if_llmaddr_count(if_t ifp) 4339fb3fc771SGleb Smirnoff { 4340fb3fc771SGleb Smirnoff struct epoch_tracker et; 4341fb3fc771SGleb Smirnoff struct ifmultiaddr *ifma; 4342fb3fc771SGleb Smirnoff int count; 4343fb3fc771SGleb Smirnoff 4344fb3fc771SGleb Smirnoff count = 0; 4345fb3fc771SGleb Smirnoff NET_EPOCH_ENTER(et); 4346fb3fc771SGleb Smirnoff CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) 4347fb3fc771SGleb Smirnoff if (ifma->ifma_addr->sa_family == AF_LINK) 4348fb3fc771SGleb Smirnoff count++; 4349fb3fc771SGleb Smirnoff NET_EPOCH_EXIT(et); 4350fb3fc771SGleb Smirnoff 4351fb3fc771SGleb Smirnoff return (count); 4352fb3fc771SGleb Smirnoff } 4353fb3fc771SGleb Smirnoff 4354fb3fc771SGleb Smirnoff u_int 4355826857c8SGleb Smirnoff if_foreach_llmaddr(if_t ifp, iflladdr_cb_t cb, void *cb_arg) 4356826857c8SGleb Smirnoff { 4357826857c8SGleb Smirnoff struct epoch_tracker et; 4358826857c8SGleb Smirnoff struct ifmultiaddr *ifma; 4359826857c8SGleb Smirnoff u_int count; 4360826857c8SGleb Smirnoff 4361826857c8SGleb Smirnoff MPASS(cb); 4362826857c8SGleb Smirnoff 4363826857c8SGleb Smirnoff count = 0; 4364826857c8SGleb Smirnoff NET_EPOCH_ENTER(et); 4365826857c8SGleb Smirnoff CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { 4366826857c8SGleb Smirnoff if (ifma->ifma_addr->sa_family != AF_LINK) 4367826857c8SGleb Smirnoff continue; 4368826857c8SGleb Smirnoff count += (*cb)(cb_arg, (struct sockaddr_dl *)ifma->ifma_addr, 4369826857c8SGleb Smirnoff count); 4370826857c8SGleb Smirnoff } 4371826857c8SGleb Smirnoff NET_EPOCH_EXIT(et); 4372826857c8SGleb Smirnoff 4373826857c8SGleb Smirnoff return (count); 4374826857c8SGleb Smirnoff } 4375826857c8SGleb Smirnoff 43761a75e3b2SAlexander V. Chernikov int 437762d76917SMarcel Moolenaar if_setsoftc(if_t ifp, void *softc) 437862d76917SMarcel Moolenaar { 437962d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_softc = softc; 438062d76917SMarcel Moolenaar return (0); 438162d76917SMarcel Moolenaar } 438262d76917SMarcel Moolenaar 438362d76917SMarcel Moolenaar void * 438462d76917SMarcel Moolenaar if_getsoftc(if_t ifp) 438562d76917SMarcel Moolenaar { 438662d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_softc; 438762d76917SMarcel Moolenaar } 438862d76917SMarcel Moolenaar 438962d76917SMarcel Moolenaar void 439062d76917SMarcel Moolenaar if_setrcvif(struct mbuf *m, if_t ifp) 439162d76917SMarcel Moolenaar { 4392fb3bc596SJohn Baldwin 4393fb3bc596SJohn Baldwin MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0); 439462d76917SMarcel Moolenaar m->m_pkthdr.rcvif = (struct ifnet *)ifp; 439562d76917SMarcel Moolenaar } 439662d76917SMarcel Moolenaar 439762d76917SMarcel Moolenaar void 439862d76917SMarcel Moolenaar if_setvtag(struct mbuf *m, uint16_t tag) 439962d76917SMarcel Moolenaar { 440062d76917SMarcel Moolenaar m->m_pkthdr.ether_vtag = tag; 440162d76917SMarcel Moolenaar } 440262d76917SMarcel Moolenaar 440362d76917SMarcel Moolenaar uint16_t 440462d76917SMarcel Moolenaar if_getvtag(struct mbuf *m) 440562d76917SMarcel Moolenaar { 440662d76917SMarcel Moolenaar 440762d76917SMarcel Moolenaar return (m->m_pkthdr.ether_vtag); 440862d76917SMarcel Moolenaar } 440962d76917SMarcel Moolenaar 441062d76917SMarcel Moolenaar int 441162d76917SMarcel Moolenaar if_sendq_empty(if_t ifp) 441262d76917SMarcel Moolenaar { 441362d76917SMarcel Moolenaar return IFQ_DRV_IS_EMPTY(&((struct ifnet *)ifp)->if_snd); 441462d76917SMarcel Moolenaar } 441562d76917SMarcel Moolenaar 441662d76917SMarcel Moolenaar struct ifaddr * 441762d76917SMarcel Moolenaar if_getifaddr(if_t ifp) 441862d76917SMarcel Moolenaar { 441962d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_addr; 442062d76917SMarcel Moolenaar } 442162d76917SMarcel Moolenaar 442262d76917SMarcel Moolenaar int 442362d76917SMarcel Moolenaar if_getamcount(if_t ifp) 442462d76917SMarcel Moolenaar { 442562d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_amcount; 442662d76917SMarcel Moolenaar } 442762d76917SMarcel Moolenaar 442862d76917SMarcel Moolenaar int 442962d76917SMarcel Moolenaar if_setsendqready(if_t ifp) 443062d76917SMarcel Moolenaar { 443162d76917SMarcel Moolenaar IFQ_SET_READY(&((struct ifnet *)ifp)->if_snd); 443262d76917SMarcel Moolenaar return (0); 443362d76917SMarcel Moolenaar } 443462d76917SMarcel Moolenaar 443562d76917SMarcel Moolenaar int 443662d76917SMarcel Moolenaar if_setsendqlen(if_t ifp, int tx_desc_count) 443762d76917SMarcel Moolenaar { 443862d76917SMarcel Moolenaar IFQ_SET_MAXLEN(&((struct ifnet *)ifp)->if_snd, tx_desc_count); 443962d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_snd.ifq_drv_maxlen = tx_desc_count; 444062d76917SMarcel Moolenaar 444162d76917SMarcel Moolenaar return (0); 444262d76917SMarcel Moolenaar } 444362d76917SMarcel Moolenaar 444462d76917SMarcel Moolenaar int 444562d76917SMarcel Moolenaar if_vlantrunkinuse(if_t ifp) 444662d76917SMarcel Moolenaar { 444762d76917SMarcel Moolenaar return ((struct ifnet *)ifp)->if_vlantrunk != NULL?1:0; 444862d76917SMarcel Moolenaar } 444962d76917SMarcel Moolenaar 445062d76917SMarcel Moolenaar int 445162d76917SMarcel Moolenaar if_input(if_t ifp, struct mbuf* sendmp) 445262d76917SMarcel Moolenaar { 445362d76917SMarcel Moolenaar (*((struct ifnet *)ifp)->if_input)((struct ifnet *)ifp, sendmp); 445462d76917SMarcel Moolenaar return (0); 445562d76917SMarcel Moolenaar 445662d76917SMarcel Moolenaar } 445762d76917SMarcel Moolenaar 445862d76917SMarcel Moolenaar struct mbuf * 445962d76917SMarcel Moolenaar if_dequeue(if_t ifp) 446062d76917SMarcel Moolenaar { 446162d76917SMarcel Moolenaar struct mbuf *m; 446262d76917SMarcel Moolenaar IFQ_DRV_DEQUEUE(&((struct ifnet *)ifp)->if_snd, m); 446362d76917SMarcel Moolenaar 446462d76917SMarcel Moolenaar return (m); 446562d76917SMarcel Moolenaar } 446662d76917SMarcel Moolenaar 446762d76917SMarcel Moolenaar int 446862d76917SMarcel Moolenaar if_sendq_prepend(if_t ifp, struct mbuf *m) 446962d76917SMarcel Moolenaar { 447062d76917SMarcel Moolenaar IFQ_DRV_PREPEND(&((struct ifnet *)ifp)->if_snd, m); 447162d76917SMarcel Moolenaar return (0); 447262d76917SMarcel Moolenaar } 447362d76917SMarcel Moolenaar 447462d76917SMarcel Moolenaar int 447562d76917SMarcel Moolenaar if_setifheaderlen(if_t ifp, int len) 447662d76917SMarcel Moolenaar { 4477e6485f73SGleb Smirnoff ((struct ifnet *)ifp)->if_hdrlen = len; 447862d76917SMarcel Moolenaar return (0); 447962d76917SMarcel Moolenaar } 448062d76917SMarcel Moolenaar 448162d76917SMarcel Moolenaar caddr_t 448262d76917SMarcel Moolenaar if_getlladdr(if_t ifp) 448362d76917SMarcel Moolenaar { 448462d76917SMarcel Moolenaar return (IF_LLADDR((struct ifnet *)ifp)); 448562d76917SMarcel Moolenaar } 448662d76917SMarcel Moolenaar 448762d76917SMarcel Moolenaar void * 448862d76917SMarcel Moolenaar if_gethandle(u_char type) 448962d76917SMarcel Moolenaar { 449062d76917SMarcel Moolenaar return (if_alloc(type)); 449162d76917SMarcel Moolenaar } 449262d76917SMarcel Moolenaar 449362d76917SMarcel Moolenaar void 449462d76917SMarcel Moolenaar if_bpfmtap(if_t ifh, struct mbuf *m) 449562d76917SMarcel Moolenaar { 449662d76917SMarcel Moolenaar struct ifnet *ifp = (struct ifnet *)ifh; 449762d76917SMarcel Moolenaar 449862d76917SMarcel Moolenaar BPF_MTAP(ifp, m); 449962d76917SMarcel Moolenaar } 450062d76917SMarcel Moolenaar 450162d76917SMarcel Moolenaar void 450262d76917SMarcel Moolenaar if_etherbpfmtap(if_t ifh, struct mbuf *m) 450362d76917SMarcel Moolenaar { 450462d76917SMarcel Moolenaar struct ifnet *ifp = (struct ifnet *)ifh; 450562d76917SMarcel Moolenaar 450662d76917SMarcel Moolenaar ETHER_BPF_MTAP(ifp, m); 450762d76917SMarcel Moolenaar } 450862d76917SMarcel Moolenaar 450962d76917SMarcel Moolenaar void 451062d76917SMarcel Moolenaar if_vlancap(if_t ifh) 451162d76917SMarcel Moolenaar { 451262d76917SMarcel Moolenaar struct ifnet *ifp = (struct ifnet *)ifh; 451362d76917SMarcel Moolenaar VLAN_CAPABILITIES(ifp); 451462d76917SMarcel Moolenaar } 451562d76917SMarcel Moolenaar 4516d0b2cad1SStephen J. Kiernan int 4517d0b2cad1SStephen J. Kiernan if_sethwtsomax(if_t ifp, u_int if_hw_tsomax) 4518d0b2cad1SStephen J. Kiernan { 4519d0b2cad1SStephen J. Kiernan 4520d0b2cad1SStephen J. Kiernan ((struct ifnet *)ifp)->if_hw_tsomax = if_hw_tsomax; 4521d0b2cad1SStephen J. Kiernan return (0); 4522d0b2cad1SStephen J. Kiernan } 4523d0b2cad1SStephen J. Kiernan 4524d0b2cad1SStephen J. Kiernan int 4525d0b2cad1SStephen J. Kiernan if_sethwtsomaxsegcount(if_t ifp, u_int if_hw_tsomaxsegcount) 4526d0b2cad1SStephen J. Kiernan { 4527d0b2cad1SStephen J. Kiernan 4528d0b2cad1SStephen J. Kiernan ((struct ifnet *)ifp)->if_hw_tsomaxsegcount = if_hw_tsomaxsegcount; 4529d0b2cad1SStephen J. Kiernan return (0); 4530d0b2cad1SStephen J. Kiernan } 4531d0b2cad1SStephen J. Kiernan 4532d0b2cad1SStephen J. Kiernan int 4533d0b2cad1SStephen J. Kiernan if_sethwtsomaxsegsize(if_t ifp, u_int if_hw_tsomaxsegsize) 4534d0b2cad1SStephen J. Kiernan { 4535d0b2cad1SStephen J. Kiernan 4536d0b2cad1SStephen J. Kiernan ((struct ifnet *)ifp)->if_hw_tsomaxsegsize = if_hw_tsomaxsegsize; 4537d0b2cad1SStephen J. Kiernan return (0); 4538d0b2cad1SStephen J. Kiernan } 4539d0b2cad1SStephen J. Kiernan 4540d0b2cad1SStephen J. Kiernan u_int 4541d0b2cad1SStephen J. Kiernan if_gethwtsomax(if_t ifp) 4542d0b2cad1SStephen J. Kiernan { 4543d0b2cad1SStephen J. Kiernan 4544d0b2cad1SStephen J. Kiernan return (((struct ifnet *)ifp)->if_hw_tsomax); 4545d0b2cad1SStephen J. Kiernan } 4546d0b2cad1SStephen J. Kiernan 4547d0b2cad1SStephen J. Kiernan u_int 4548d0b2cad1SStephen J. Kiernan if_gethwtsomaxsegcount(if_t ifp) 4549d0b2cad1SStephen J. Kiernan { 4550d0b2cad1SStephen J. Kiernan 4551d0b2cad1SStephen J. Kiernan return (((struct ifnet *)ifp)->if_hw_tsomaxsegcount); 4552d0b2cad1SStephen J. Kiernan } 4553d0b2cad1SStephen J. Kiernan 4554d0b2cad1SStephen J. Kiernan u_int 4555d0b2cad1SStephen J. Kiernan if_gethwtsomaxsegsize(if_t ifp) 4556d0b2cad1SStephen J. Kiernan { 4557d0b2cad1SStephen J. Kiernan 4558d0b2cad1SStephen J. Kiernan return (((struct ifnet *)ifp)->if_hw_tsomaxsegsize); 4559d0b2cad1SStephen J. Kiernan } 4560d0b2cad1SStephen J. Kiernan 456162d76917SMarcel Moolenaar void 456262d76917SMarcel Moolenaar if_setinitfn(if_t ifp, void (*init_fn)(void *)) 456362d76917SMarcel Moolenaar { 456462d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_init = init_fn; 456562d76917SMarcel Moolenaar } 456662d76917SMarcel Moolenaar 456762d76917SMarcel Moolenaar void 456809a8241fSGleb Smirnoff if_setioctlfn(if_t ifp, int (*ioctl_fn)(if_t, u_long, caddr_t)) 456962d76917SMarcel Moolenaar { 457062d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_ioctl = (void *)ioctl_fn; 457162d76917SMarcel Moolenaar } 457262d76917SMarcel Moolenaar 457362d76917SMarcel Moolenaar void 457409a8241fSGleb Smirnoff if_setstartfn(if_t ifp, void (*start_fn)(if_t)) 457562d76917SMarcel Moolenaar { 457662d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_start = (void *)start_fn; 457762d76917SMarcel Moolenaar } 457862d76917SMarcel Moolenaar 457962d76917SMarcel Moolenaar void 458062d76917SMarcel Moolenaar if_settransmitfn(if_t ifp, if_transmit_fn_t start_fn) 458162d76917SMarcel Moolenaar { 458262d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_transmit = start_fn; 458362d76917SMarcel Moolenaar } 458462d76917SMarcel Moolenaar 458562d76917SMarcel Moolenaar void if_setqflushfn(if_t ifp, if_qflush_fn_t flush_fn) 458662d76917SMarcel Moolenaar { 458762d76917SMarcel Moolenaar ((struct ifnet *)ifp)->if_qflush = flush_fn; 458862d76917SMarcel Moolenaar 458962d76917SMarcel Moolenaar } 459062d76917SMarcel Moolenaar 459135853c2cSGleb Smirnoff void 459235853c2cSGleb Smirnoff if_setgetcounterfn(if_t ifp, if_get_counter_t fn) 459335853c2cSGleb Smirnoff { 459435853c2cSGleb Smirnoff 459535853c2cSGleb Smirnoff ifp->if_get_counter = fn; 459635853c2cSGleb Smirnoff } 459735853c2cSGleb Smirnoff 459862d76917SMarcel Moolenaar /* Revisit these - These are inline functions originally. */ 459962d76917SMarcel Moolenaar int 460062d76917SMarcel Moolenaar drbr_inuse_drv(if_t ifh, struct buf_ring *br) 460162d76917SMarcel Moolenaar { 4602966ab68dSDimitry Andric return drbr_inuse(ifh, br); 460362d76917SMarcel Moolenaar } 460462d76917SMarcel Moolenaar 460562d76917SMarcel Moolenaar struct mbuf* 460662d76917SMarcel Moolenaar drbr_dequeue_drv(if_t ifh, struct buf_ring *br) 460762d76917SMarcel Moolenaar { 460862d76917SMarcel Moolenaar return drbr_dequeue(ifh, br); 460962d76917SMarcel Moolenaar } 461062d76917SMarcel Moolenaar 461162d76917SMarcel Moolenaar int 461262d76917SMarcel Moolenaar drbr_needs_enqueue_drv(if_t ifh, struct buf_ring *br) 461362d76917SMarcel Moolenaar { 461462d76917SMarcel Moolenaar return drbr_needs_enqueue(ifh, br); 461562d76917SMarcel Moolenaar } 461662d76917SMarcel Moolenaar 461762d76917SMarcel Moolenaar int 461862d76917SMarcel Moolenaar drbr_enqueue_drv(if_t ifh, struct buf_ring *br, struct mbuf *m) 461962d76917SMarcel Moolenaar { 462062d76917SMarcel Moolenaar return drbr_enqueue(ifh, br, m); 462162d76917SMarcel Moolenaar 462262d76917SMarcel Moolenaar } 4623