xref: /freebsd/sys/net/if.c (revision 7563019bc69301a382abefbac3b0fea1d876410e)
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>
40f13ad206SJonathan Lemon #include <sys/conf.h>
41e2e050c8SConrad Meyer #include <sys/eventhandler.h>
424d1d4912SBruce Evans #include <sys/malloc.h>
437687707dSAndrew Gallatin #include <sys/domainset.h>
444dcf2bbbSBrooks Davis #include <sys/sbuf.h>
45d2b4566aSJonathan Lemon #include <sys/bus.h>
46d7c5a620SMatt Macy #include <sys/epoch.h>
47df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
48df8bae1dSRodney W. Grimes #include <sys/systm.h>
49acd3428bSRobert Watson #include <sys/priv.h>
50df8bae1dSRodney W. Grimes #include <sys/proc.h>
51df8bae1dSRodney W. Grimes #include <sys/socket.h>
52df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
53df8bae1dSRodney W. Grimes #include <sys/protosw.h>
54df8bae1dSRodney W. Grimes #include <sys/kernel.h>
55653735c4SBjoern A. Zeeb #include <sys/lock.h>
5627d37320SRobert Watson #include <sys/refcount.h>
5721ca7b57SMarko Zec #include <sys/module.h>
58653735c4SBjoern A. Zeeb #include <sys/rwlock.h>
5951a53488SBruce Evans #include <sys/sockio.h>
60963e4c2aSGarrett Wollman #include <sys/syslog.h>
61602d513cSGarrett Wollman #include <sys/sysctl.h>
6286d2ef16SBrooks Davis #include <sys/sysent.h>
63af5e59bfSRobert Watson #include <sys/taskqueue.h>
6431b1bfe1SHajimu UMEMOTO #include <sys/domain.h>
6591421ba2SRobert Watson #include <sys/jail.h>
6635fd7bc0SBjoern A. Zeeb #include <sys/priv.h>
6735fd7bc0SBjoern A. Zeeb 
68fa882e87SBrooks Davis #include <machine/stdarg.h>
696e6b3f7cSQing Li #include <vm/uma.h>
70df8bae1dSRodney W. Grimes 
7162d76917SMarcel Moolenaar #include <net/bpf.h>
7262d76917SMarcel Moolenaar #include <net/ethernet.h>
73df8bae1dSRodney W. Grimes #include <net/if.h>
745a97c9d4SBjoern A. Zeeb #include <net/if_arp.h>
75f889d2efSBrooks Davis #include <net/if_clone.h>
76df8bae1dSRodney W. Grimes #include <net/if_dl.h>
7766ce51ceSArchie Cobbs #include <net/if_types.h>
7830aad87dSBrooks Davis #include <net/if_var.h>
7962d76917SMarcel Moolenaar #include <net/if_media.h>
8062d76917SMarcel Moolenaar #include <net/if_vlan_var.h>
819448326fSPoul-Henning Kamp #include <net/radix.h>
825500d3beSWarner Losh #include <net/route.h>
83e1c05fd2SAlexander V. Chernikov #include <net/route/route_ctl.h>
844b79449eSBjoern A. Zeeb #include <net/vnet.h>
85df8bae1dSRodney W. Grimes 
860d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6)
87209579aeSRick Macklem #include <net/ethernet.h>
8882cd038dSYoshinobu Inoue #include <netinet/in.h>
890d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h>
903c914c54SAndre Oppermann #include <netinet/ip.h>
919963e8a5SWill Andrews #include <netinet/ip_carp.h>
923c914c54SAndre Oppermann #ifdef INET
937790c8c1SConrad Meyer #include <net/debugnet.h>
943c914c54SAndre Oppermann #include <netinet/if_ether.h>
953c914c54SAndre Oppermann #endif /* INET */
963411310dSYoshinobu Inoue #ifdef INET6
97978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h>
98978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h>
993c914c54SAndre Oppermann #endif /* INET6 */
1003c914c54SAndre Oppermann #endif /* INET || INET6 */
10182cd038dSYoshinobu Inoue 
102aed55708SRobert Watson #include <security/mac/mac_framework.h>
103aed55708SRobert Watson 
1048708f1bdSBrooks Davis /*
1058708f1bdSBrooks Davis  * Consumers of struct ifreq such as tcpdump assume no pad between ifr_name
1068708f1bdSBrooks Davis  * and ifr_ifru when it is used in SIOCGIFCONF.
1078708f1bdSBrooks Davis  */
1088708f1bdSBrooks Davis _Static_assert(sizeof(((struct ifreq *)0)->ifr_name) ==
1098708f1bdSBrooks Davis     offsetof(struct ifreq, ifr_ifru), "gap between ifr_name and ifr_ifru");
1108708f1bdSBrooks Davis 
111d71e30deSMatt Macy __read_mostly epoch_t net_epoch_preempt;
1129af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32
1139af74f3dSSergey Kandaurov #include <sys/mount.h>
1149af74f3dSSergey Kandaurov #include <compat/freebsd32/freebsd32.h>
11586d2ef16SBrooks Davis 
11686d2ef16SBrooks Davis struct ifreq_buffer32 {
11786d2ef16SBrooks Davis 	uint32_t	length;		/* (size_t) */
11886d2ef16SBrooks Davis 	uint32_t	buffer;		/* (void *) */
11986d2ef16SBrooks Davis };
12086d2ef16SBrooks Davis 
12186d2ef16SBrooks Davis /*
12286d2ef16SBrooks Davis  * Interface request structure used for socket
12386d2ef16SBrooks Davis  * ioctl's.  All interface ioctl's must have parameter
12486d2ef16SBrooks Davis  * definitions which begin with ifr_name.  The
12586d2ef16SBrooks Davis  * remainder may be interface specific.
12686d2ef16SBrooks Davis  */
12786d2ef16SBrooks Davis struct ifreq32 {
12886d2ef16SBrooks Davis 	char	ifr_name[IFNAMSIZ];		/* if name, e.g. "en0" */
12986d2ef16SBrooks Davis 	union {
13086d2ef16SBrooks Davis 		struct sockaddr	ifru_addr;
13186d2ef16SBrooks Davis 		struct sockaddr	ifru_dstaddr;
13286d2ef16SBrooks Davis 		struct sockaddr	ifru_broadaddr;
13386d2ef16SBrooks Davis 		struct ifreq_buffer32 ifru_buffer;
13486d2ef16SBrooks Davis 		short		ifru_flags[2];
13586d2ef16SBrooks Davis 		short		ifru_index;
13686d2ef16SBrooks Davis 		int		ifru_jid;
13786d2ef16SBrooks Davis 		int		ifru_metric;
13886d2ef16SBrooks Davis 		int		ifru_mtu;
13986d2ef16SBrooks Davis 		int		ifru_phys;
14086d2ef16SBrooks Davis 		int		ifru_media;
14186d2ef16SBrooks Davis 		uint32_t	ifru_data;
14286d2ef16SBrooks Davis 		int		ifru_cap[2];
14386d2ef16SBrooks Davis 		u_int		ifru_fib;
14486d2ef16SBrooks Davis 		u_char		ifru_vlan_pcp;
14586d2ef16SBrooks Davis 	} ifr_ifru;
14686d2ef16SBrooks Davis };
14786d2ef16SBrooks Davis CTASSERT(sizeof(struct ifreq) == sizeof(struct ifreq32));
14886d2ef16SBrooks Davis CTASSERT(__offsetof(struct ifreq, ifr_ifru) ==
14986d2ef16SBrooks Davis     __offsetof(struct ifreq32, ifr_ifru));
150756181b8SBrooks Davis 
151756181b8SBrooks Davis struct ifgroupreq32 {
152756181b8SBrooks Davis 	char	ifgr_name[IFNAMSIZ];
153756181b8SBrooks Davis 	u_int	ifgr_len;
154756181b8SBrooks Davis 	union {
155756181b8SBrooks Davis 		char		ifgru_group[IFNAMSIZ];
156756181b8SBrooks Davis 		uint32_t	ifgru_groups;
157756181b8SBrooks Davis 	} ifgr_ifgru;
158756181b8SBrooks Davis };
1593edb7f4eSBrooks Davis 
1603edb7f4eSBrooks Davis struct ifmediareq32 {
1613edb7f4eSBrooks Davis 	char		ifm_name[IFNAMSIZ];
1623edb7f4eSBrooks Davis 	int		ifm_current;
1633edb7f4eSBrooks Davis 	int		ifm_mask;
1643edb7f4eSBrooks Davis 	int		ifm_status;
1653edb7f4eSBrooks Davis 	int		ifm_active;
1663edb7f4eSBrooks Davis 	int		ifm_count;
1673edb7f4eSBrooks Davis 	uint32_t	ifm_ulist;	/* (int *) */
1683edb7f4eSBrooks Davis };
1693edb7f4eSBrooks Davis #define	SIOCGIFMEDIA32	_IOC_NEWTYPE(SIOCGIFMEDIA, struct ifmediareq32)
1703edb7f4eSBrooks Davis #define	SIOCGIFXMEDIA32	_IOC_NEWTYPE(SIOCGIFXMEDIA, struct ifmediareq32)
1713edb7f4eSBrooks Davis 
172756181b8SBrooks Davis #define	_CASE_IOC_IFGROUPREQ_32(cmd)				\
173bc6f170eSBrooks Davis     _IOC_NEWTYPE((cmd), struct ifgroupreq32): case
1743edb7f4eSBrooks Davis #else /* !COMPAT_FREEBSD32 */
175756181b8SBrooks Davis #define _CASE_IOC_IFGROUPREQ_32(cmd)
1763edb7f4eSBrooks Davis #endif /* !COMPAT_FREEBSD32 */
177756181b8SBrooks Davis 
178756181b8SBrooks Davis #define CASE_IOC_IFGROUPREQ(cmd)	\
179756181b8SBrooks Davis     _CASE_IOC_IFGROUPREQ_32(cmd)	\
180bc6f170eSBrooks Davis     (cmd)
1819af74f3dSSergey Kandaurov 
18286d2ef16SBrooks Davis union ifreq_union {
18386d2ef16SBrooks Davis 	struct ifreq	ifr;
18486d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
18586d2ef16SBrooks Davis 	struct ifreq32	ifr32;
18686d2ef16SBrooks Davis #endif
18786d2ef16SBrooks Davis };
18886d2ef16SBrooks Davis 
189756181b8SBrooks Davis union ifgroupreq_union {
190756181b8SBrooks Davis 	struct ifgroupreq ifgr;
191756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32
192756181b8SBrooks Davis 	struct ifgroupreq32 ifgr32;
193756181b8SBrooks Davis #endif
194756181b8SBrooks Davis };
195756181b8SBrooks Davis 
1967029da5cSPawel Biernacki SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1977029da5cSPawel Biernacki     "Link layers");
1987029da5cSPawel Biernacki SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1997029da5cSPawel Biernacki     "Generic link-management");
2005515c2e7SGleb Smirnoff 
201f88910cdSMatthew D Fleming SYSCTL_INT(_net_link, OID_AUTO, ifqmaxlen, CTLFLAG_RDTUN,
202e50d35e6SMaxim Sobolev     &ifqmaxlen, 0, "max send queue size");
203e50d35e6SMaxim Sobolev 
2045515c2e7SGleb Smirnoff /* Log link state change events */
2055515c2e7SGleb Smirnoff static int log_link_state_change = 1;
2065515c2e7SGleb Smirnoff 
2075515c2e7SGleb Smirnoff SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW,
2085515c2e7SGleb Smirnoff 	&log_link_state_change, 0,
2095515c2e7SGleb Smirnoff 	"log interface link state change events");
2105515c2e7SGleb Smirnoff 
2116d07c157SNick Hibma /* Log promiscuous mode change events */
2126d07c157SNick Hibma static int log_promisc_mode_change = 1;
2136d07c157SNick Hibma 
214dbd2ee46SNick Hibma SYSCTL_INT(_net_link, OID_AUTO, log_promisc_mode_change, CTLFLAG_RDTUN,
2156d07c157SNick Hibma 	&log_promisc_mode_change, 1,
2166d07c157SNick Hibma 	"log promiscuous mode change events");
2176d07c157SNick Hibma 
218215940b3SXin LI /* Interface description */
219215940b3SXin LI static unsigned int ifdescr_maxlen = 1024;
220215940b3SXin LI SYSCTL_UINT(_net, OID_AUTO, ifdescr_maxlen, CTLFLAG_RW,
221215940b3SXin LI 	&ifdescr_maxlen, 0,
222215940b3SXin LI 	"administrative maximum length for interface description");
223215940b3SXin LI 
224d745c852SEd Schouten static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions");
225215940b3SXin LI 
226215940b3SXin LI /* global sx for non-critical path ifdescr */
227215940b3SXin LI static struct sx ifdescr_sx;
228215940b3SXin LI SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr");
229215940b3SXin LI 
2301c7899c7SGleb Smirnoff void	(*ng_ether_link_state_p)(struct ifnet *ifp, int state);
231d6e82913SSteven Hartland void	(*lagg_linkstate_p)(struct ifnet *ifp, int state);
2329963e8a5SWill Andrews /* These are external hooks for CARP. */
23354bfbd51SWill Andrews void	(*carp_linkstate_p)(struct ifnet *ifp);
234f08535f8SGleb Smirnoff void	(*carp_demote_adj_p)(int, char *);
23524421c1cSGleb Smirnoff int	(*carp_master_p)(struct ifaddr *);
2369963e8a5SWill Andrews #if defined(INET) || defined(INET6)
23708b68b0eSGleb Smirnoff int	(*carp_forus_p)(struct ifnet *ifp, u_char *dhost);
2389963e8a5SWill Andrews int	(*carp_output_p)(struct ifnet *ifp, struct mbuf *m,
23947e8d432SGleb Smirnoff     const struct sockaddr *sa);
24008b68b0eSGleb Smirnoff int	(*carp_ioctl_p)(struct ifreq *, u_long, struct thread *);
24108b68b0eSGleb Smirnoff int	(*carp_attach_p)(struct ifaddr *, int);
242338e227aSLuiz Otavio O Souza void	(*carp_detach_p)(struct ifaddr *, bool);
2439963e8a5SWill Andrews #endif
2449963e8a5SWill Andrews #ifdef INET
24508b68b0eSGleb Smirnoff int	(*carp_iamatch_p)(struct ifaddr *, uint8_t **);
2469963e8a5SWill Andrews #endif
2479963e8a5SWill Andrews #ifdef INET6
2489963e8a5SWill Andrews struct ifaddr *(*carp_iamatch6_p)(struct ifnet *ifp, struct in6_addr *taddr6);
2499963e8a5SWill Andrews caddr_t	(*carp_macmatch6_p)(struct ifnet *ifp, struct mbuf *m,
2509963e8a5SWill Andrews     const struct in6_addr *taddr);
2519963e8a5SWill Andrews #endif
2521c7899c7SGleb Smirnoff 
2534cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
2544cb655c0SMax Laier 
255ec002feeSBruce M Simpson /*
256ec002feeSBruce M Simpson  * XXX: Style; these should be sorted alphabetically, and unprototyped
257ec002feeSBruce M Simpson  * static functions should be prototyped. Currently they are sorted by
258ec002feeSBruce M Simpson  * declaration order.
259ec002feeSBruce M Simpson  */
26031b1bfe1SHajimu UMEMOTO static void	if_attachdomain(void *);
26131b1bfe1SHajimu UMEMOTO static void	if_attachdomain1(struct ifnet *);
2620b59d917SJonathan Lemon static int	ifconf(u_long, caddr_t);
2634f6c66ccSMatt Macy static void	*if_grow(void);
264b57d9721SAndrey V. Elsukov static void	if_input_default(struct ifnet *, struct mbuf *);
2654fb3a820SAlexander V. Chernikov static int	if_requestencap_default(struct ifnet *, struct if_encap_req *);
2668614fb12SMax Laier static void	if_route(struct ifnet *, int flag, int fam);
2671a3b6859SYaroslav Tykhiy static int	if_setflag(struct ifnet *, int, int, int *, int);
268db7f0b97SKip Macy static int	if_transmit(struct ifnet *ifp, struct mbuf *m);
2698614fb12SMax Laier static void	if_unroute(struct ifnet *, int flag, int fam);
270ec002feeSBruce M Simpson static int	if_delmulti_locked(struct ifnet *, struct ifmultiaddr *, int);
27168a3482fSGleb Smirnoff static void	do_link_state_change(void *, int);
2720dad3f0eSMax Laier static int	if_getgroup(struct ifgroupreq *, struct ifnet *);
2730dad3f0eSMax Laier static int	if_getgroupmembers(struct ifgroupreq *);
2748623f9fdSMax Laier static void	if_delgroups(struct ifnet *);
275c92a456bSHiroki Sato static void	if_attach_internal(struct ifnet *, int, struct if_clone *);
276f501e6f1SBjoern A. Zeeb static int	if_detach_internal(struct ifnet *, int, struct if_clone **);
2770839aa5cSGleb Smirnoff static void	if_siocaddmulti(void *, int);
278a779388fSKristof Provost static void	if_link_ifnet(struct ifnet *);
279a779388fSKristof Provost static bool	if_unlink_ifnet(struct ifnet *, bool);
280ad4e9116SBjoern A. Zeeb #ifdef VIMAGE
281c7bab2a7SKyle Evans static int	if_vmove(struct ifnet *, struct vnet *);
282ad4e9116SBjoern A. Zeeb #endif
283db7f0b97SKip Macy 
28482cd038dSYoshinobu Inoue #ifdef INET6
28582cd038dSYoshinobu Inoue /*
28682cd038dSYoshinobu Inoue  * XXX: declare here to avoid to include many inet6 related files..
28782cd038dSYoshinobu Inoue  * should be more generalized?
28882cd038dSYoshinobu Inoue  */
289929ddbbbSAlfred Perlstein extern void	nd6_setmtu(struct ifnet *);
29082cd038dSYoshinobu Inoue #endif
29182cd038dSYoshinobu Inoue 
292ef91a976SAndrey V. Elsukov /* ipsec helper hooks */
293ef91a976SAndrey V. Elsukov VNET_DEFINE(struct hhook_head *, ipsec_hhh_in[HHOOK_IPSEC_COUNT]);
294ef91a976SAndrey V. Elsukov VNET_DEFINE(struct hhook_head *, ipsec_hhh_out[HHOOK_IPSEC_COUNT]);
295ef91a976SAndrey V. Elsukov 
29682cea7e6SBjoern A. Zeeb VNET_DEFINE(int, if_index);
29782cea7e6SBjoern A. Zeeb int	ifqmaxlen = IFQ_MAXLEN;
298eddfbb76SRobert Watson VNET_DEFINE(struct ifnethead, ifnet);	/* depend on static init XXX */
299eddfbb76SRobert Watson VNET_DEFINE(struct ifgrouphead, ifg_head);
30082cea7e6SBjoern A. Zeeb 
3015f901c92SAndrew Turner VNET_DEFINE_STATIC(int, if_indexlim) = 8;
302eddfbb76SRobert Watson 
30377dfcdc4SRobert Watson /* Table of ifnet by index. */
304e6abef09SGleb Smirnoff VNET_DEFINE(struct ifnet **, ifindex_table);
305eddfbb76SRobert Watson 
3061e77c105SRobert Watson #define	V_if_indexlim		VNET(if_indexlim)
3071e77c105SRobert Watson #define	V_ifindex_table		VNET(ifindex_table)
30844e33a07SMarko Zec 
30977dfcdc4SRobert Watson /*
31077dfcdc4SRobert Watson  * The global network interface list (V_ifnet) and related state (such as
311a60100fdSKristof Provost  * if_index, if_indexlim, and ifindex_table) are protected by an sxlock.
312a60100fdSKristof Provost  * This may be acquired to stabilise the list, or we may rely on NET_EPOCH.
31377dfcdc4SRobert Watson  */
31477dfcdc4SRobert Watson struct sx ifnet_sxlock;
3154ea05db8SGleb Smirnoff SX_SYSINIT_FLAGS(ifnet_sx, &ifnet_sxlock, "ifnet_sx", SX_RECURSE);
31677dfcdc4SRobert Watson 
317e133271fSKristof Provost struct sx ifnet_detach_sxlock;
3186d2a10d9SKristof Provost SX_SYSINIT_FLAGS(ifnet_detach, &ifnet_detach_sxlock, "ifnet_detach_sx",
3196d2a10d9SKristof Provost     SX_RECURSE);
320e133271fSKristof Provost 
321ed2dabfcSRobert Watson /*
322ed2dabfcSRobert Watson  * The allocation of network interfaces is a rather non-atomic affair; we
323ed2dabfcSRobert Watson  * need to select an index before we are ready to expose the interface for
324ed2dabfcSRobert Watson  * use, so will use this pointer value to indicate reservation.
325ed2dabfcSRobert Watson  */
326ed2dabfcSRobert Watson #define	IFNET_HOLD	(void *)(uintptr_t)(-1)
327ed2dabfcSRobert Watson 
32810108cb6SBjoern A. Zeeb #ifdef VIMAGE
32910108cb6SBjoern A. Zeeb #define	VNET_IS_SHUTTING_DOWN(_vnet)					\
33010108cb6SBjoern A. Zeeb     ((_vnet)->vnet_shutdown && (_vnet)->vnet_state < SI_SUB_VNET_DONE)
33110108cb6SBjoern A. Zeeb #endif
33210108cb6SBjoern A. Zeeb 
333fc74a9f9SBrooks Davis static	if_com_alloc_t *if_com_alloc[256];
334fc74a9f9SBrooks Davis static	if_com_free_t *if_com_free[256];
3350b59d917SJonathan Lemon 
336d745c852SEd Schouten static MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals");
3370b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
3380b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
33930aad87dSBrooks Davis 
34021ca7b57SMarko Zec struct ifnet *
341d24c444cSKip Macy ifnet_byindex(u_short idx)
342d24c444cSKip Macy {
343d24c444cSKip Macy 	struct ifnet *ifp;
344d24c444cSKip Macy 
345270b83b9SHans Petter Selasky 	if (__predict_false(idx > V_if_index))
346270b83b9SHans Petter Selasky 		return (NULL);
347270b83b9SHans Petter Selasky 
348270b83b9SHans Petter Selasky 	ifp = *(struct ifnet * const volatile *)(V_ifindex_table + idx);
349270b83b9SHans Petter Selasky 	return (__predict_false(ifp == IFNET_HOLD) ? NULL : ifp);
35002f4879dSRobert Watson }
35102f4879dSRobert Watson 
35227d37320SRobert Watson struct ifnet *
35327d37320SRobert Watson ifnet_byindex_ref(u_short idx)
35427d37320SRobert Watson {
35527d37320SRobert Watson 	struct ifnet *ifp;
35627d37320SRobert Watson 
357b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
358b8a6e03fSGleb Smirnoff 
359270b83b9SHans Petter Selasky 	ifp = ifnet_byindex(idx);
360b8a6e03fSGleb Smirnoff 	if (ifp == NULL || (ifp->if_flags & IFF_DYING))
36127d37320SRobert Watson 		return (NULL);
362*7563019bSAlexander V. Chernikov 	if (!if_try_ref(ifp))
363*7563019bSAlexander V. Chernikov 		return (NULL);
36427d37320SRobert Watson 	return (ifp);
36527d37320SRobert Watson }
36627d37320SRobert Watson 
36761f6986bSRobert Watson /*
36861f6986bSRobert Watson  * Allocate an ifindex array entry; return 0 on success or an error on
36961f6986bSRobert Watson  * failure.
37061f6986bSRobert Watson  */
371f4507b71SGleb Smirnoff static u_short
3724f6c66ccSMatt Macy ifindex_alloc(void **old)
37361f6986bSRobert Watson {
37461f6986bSRobert Watson 	u_short idx;
37561f6986bSRobert Watson 
37661f6986bSRobert Watson 	IFNET_WLOCK_ASSERT();
37761f6986bSRobert Watson 	/*
378ed2dabfcSRobert Watson 	 * Try to find an empty slot below V_if_index.  If we fail, take the
37961f6986bSRobert Watson 	 * next slot.
38061f6986bSRobert Watson 	 */
38161f6986bSRobert Watson 	for (idx = 1; idx <= V_if_index; idx++) {
382e6abef09SGleb Smirnoff 		if (V_ifindex_table[idx] == NULL)
38361f6986bSRobert Watson 			break;
38461f6986bSRobert Watson 	}
38561f6986bSRobert Watson 
38661f6986bSRobert Watson 	/* Catch if_index overflow. */
3875f3b301aSJohn Baldwin 	if (idx >= V_if_indexlim) {
3884f6c66ccSMatt Macy 		*old = if_grow();
3894f6c66ccSMatt Macy 		return (USHRT_MAX);
3905f3b301aSJohn Baldwin 	}
39161f6986bSRobert Watson 	if (idx > V_if_index)
39261f6986bSRobert Watson 		V_if_index = idx;
393f4507b71SGleb Smirnoff 	return (idx);
39461f6986bSRobert Watson }
39561f6986bSRobert Watson 
396e0c14af9SMarko Zec static void
397ed2dabfcSRobert Watson ifindex_free_locked(u_short idx)
398ed2dabfcSRobert Watson {
399ed2dabfcSRobert Watson 
400ed2dabfcSRobert Watson 	IFNET_WLOCK_ASSERT();
401ed2dabfcSRobert Watson 
402e6abef09SGleb Smirnoff 	V_ifindex_table[idx] = NULL;
403ed2dabfcSRobert Watson 	while (V_if_index > 0 &&
404e6abef09SGleb Smirnoff 	    V_ifindex_table[V_if_index] == NULL)
405ed2dabfcSRobert Watson 		V_if_index--;
406ed2dabfcSRobert Watson }
407ed2dabfcSRobert Watson 
408ed2dabfcSRobert Watson static void
409ed2dabfcSRobert Watson ifindex_free(u_short idx)
410ed2dabfcSRobert Watson {
411ed2dabfcSRobert Watson 
412ed2dabfcSRobert Watson 	IFNET_WLOCK();
413ed2dabfcSRobert Watson 	ifindex_free_locked(idx);
414ed2dabfcSRobert Watson 	IFNET_WUNLOCK();
415ed2dabfcSRobert Watson }
416ed2dabfcSRobert Watson 
417ed2dabfcSRobert Watson static void
41877dfcdc4SRobert Watson ifnet_setbyindex(u_short idx, struct ifnet *ifp)
41977dfcdc4SRobert Watson {
42077dfcdc4SRobert Watson 
4214f6c66ccSMatt Macy 	V_ifindex_table[idx] = ifp;
42277dfcdc4SRobert Watson }
42377dfcdc4SRobert Watson 
42402f4879dSRobert Watson struct ifaddr *
42502f4879dSRobert Watson ifaddr_byindex(u_short idx)
42602f4879dSRobert Watson {
42722a93840SMarko Zec 	struct ifnet *ifp;
42822a93840SMarko Zec 	struct ifaddr *ifa = NULL;
42902f4879dSRobert Watson 
430b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
431b8a6e03fSGleb Smirnoff 
432270b83b9SHans Petter Selasky 	ifp = ifnet_byindex(idx);
43322a93840SMarko Zec 	if (ifp != NULL && (ifa = ifp->if_addr) != NULL)
4348c0fec80SRobert Watson 		ifa_ref(ifa);
43502f4879dSRobert Watson 	return (ifa);
43602f4879dSRobert Watson }
43702f4879dSRobert Watson 
438df8bae1dSRodney W. Grimes /*
439df8bae1dSRodney W. Grimes  * Network interface utility routines.
440df8bae1dSRodney W. Grimes  *
441df8bae1dSRodney W. Grimes  * Routines with ifa_ifwith* names take sockaddr *'s as
442df8bae1dSRodney W. Grimes  * parameters.
443df8bae1dSRodney W. Grimes  */
444a45cbf12SBrooks Davis 
445f9132cebSJonathan Lemon static void
446d0728d71SRobert Watson vnet_if_init(const void *unused __unused)
4471ed81b73SMarko Zec {
4484f6c66ccSMatt Macy 	void *old;
44944e33a07SMarko Zec 
4504f6c66ccSMatt Macy 	CK_STAILQ_INIT(&V_ifnet);
4514f6c66ccSMatt Macy 	CK_STAILQ_INIT(&V_ifg_head);
4525f3b301aSJohn Baldwin 	IFNET_WLOCK();
4534f6c66ccSMatt Macy 	old = if_grow();				/* create initial table */
4545f3b301aSJohn Baldwin 	IFNET_WUNLOCK();
4554f6c66ccSMatt Macy 	epoch_wait_preempt(net_epoch_preempt);
4564f6c66ccSMatt Macy 	free(old, M_IFNET);
457d0728d71SRobert Watson 	vnet_if_clone_init();
458f9132cebSJonathan Lemon }
4595f3b301aSJohn Baldwin VNET_SYSINIT(vnet_if_init, SI_SUB_INIT_IF, SI_ORDER_SECOND, vnet_if_init,
460d0728d71SRobert Watson     NULL);
461d0728d71SRobert Watson 
462bc29160dSMarko Zec #ifdef VIMAGE
463d0728d71SRobert Watson static void
464d0728d71SRobert Watson vnet_if_uninit(const void *unused __unused)
465bc29160dSMarko Zec {
466bc29160dSMarko Zec 
4674f6c66ccSMatt Macy 	VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifnet), ("%s:%d tailq &V_ifnet=%p "
4680028e524SBjoern A. Zeeb 	    "not empty", __func__, __LINE__, &V_ifnet));
4694f6c66ccSMatt Macy 	VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifg_head), ("%s:%d tailq &V_ifg_head=%p "
4700028e524SBjoern A. Zeeb 	    "not empty", __func__, __LINE__, &V_ifg_head));
471bc29160dSMarko Zec 
472bc29160dSMarko Zec 	free((caddr_t)V_ifindex_table, M_IFNET);
473bc29160dSMarko Zec }
474d0728d71SRobert Watson VNET_SYSUNINIT(vnet_if_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST,
475d0728d71SRobert Watson     vnet_if_uninit, NULL);
476bca0e1d2SKristof Provost #endif
477ad4e9116SBjoern A. Zeeb 
478ad4e9116SBjoern A. Zeeb static void
479a779388fSKristof Provost if_link_ifnet(struct ifnet *ifp)
480a779388fSKristof Provost {
481a779388fSKristof Provost 
482a779388fSKristof Provost 	IFNET_WLOCK();
483a779388fSKristof Provost 	CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link);
484a779388fSKristof Provost #ifdef VIMAGE
485a779388fSKristof Provost 	curvnet->vnet_ifcnt++;
486a779388fSKristof Provost #endif
487a779388fSKristof Provost 	IFNET_WUNLOCK();
488a779388fSKristof Provost }
489a779388fSKristof Provost 
490a779388fSKristof Provost static bool
491a779388fSKristof Provost if_unlink_ifnet(struct ifnet *ifp, bool vmove)
492a779388fSKristof Provost {
493a779388fSKristof Provost 	struct ifnet *iter;
494a779388fSKristof Provost 	int found = 0;
495a779388fSKristof Provost 
496a779388fSKristof Provost 	IFNET_WLOCK();
497a779388fSKristof Provost 	CK_STAILQ_FOREACH(iter, &V_ifnet, if_link)
498a779388fSKristof Provost 		if (iter == ifp) {
499a779388fSKristof Provost 			CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link);
500a779388fSKristof Provost 			if (!vmove)
501a779388fSKristof Provost 				ifp->if_flags |= IFF_DYING;
502a779388fSKristof Provost 			found = 1;
503a779388fSKristof Provost 			break;
504a779388fSKristof Provost 		}
505a779388fSKristof Provost #ifdef VIMAGE
506a779388fSKristof Provost 	curvnet->vnet_ifcnt--;
507a779388fSKristof Provost #endif
508a779388fSKristof Provost 	IFNET_WUNLOCK();
509a779388fSKristof Provost 
510a779388fSKristof Provost 	return (found);
511a779388fSKristof Provost }
512a779388fSKristof Provost 
513bca0e1d2SKristof Provost #ifdef VIMAGE
514a779388fSKristof Provost static void
515ad4e9116SBjoern A. Zeeb vnet_if_return(const void *unused __unused)
516ad4e9116SBjoern A. Zeeb {
517ad4e9116SBjoern A. Zeeb 	struct ifnet *ifp, *nifp;
518a779388fSKristof Provost 	struct ifnet **pending;
519a779388fSKristof Provost 	int found, i;
520a779388fSKristof Provost 
521a779388fSKristof Provost 	i = 0;
522a779388fSKristof Provost 
523a779388fSKristof Provost 	/*
524a779388fSKristof Provost 	 * We need to protect our access to the V_ifnet tailq. Ordinarily we'd
525a779388fSKristof Provost 	 * enter NET_EPOCH, but that's not possible, because if_vmove() calls
526a779388fSKristof Provost 	 * if_detach_internal(), which waits for NET_EPOCH callbacks to
527a779388fSKristof Provost 	 * complete. We can't do that from within NET_EPOCH.
528a779388fSKristof Provost 	 *
529a779388fSKristof Provost 	 * However, we can also use the IFNET_xLOCK, which is the V_ifnet
530a779388fSKristof Provost 	 * read/write lock. We cannot hold the lock as we call if_vmove()
531a779388fSKristof Provost 	 * though, as that presents LOR w.r.t ifnet_sx, in_multi_sx and iflib
532a779388fSKristof Provost 	 * ctx lock.
533a779388fSKristof Provost 	 */
534a779388fSKristof Provost 	IFNET_WLOCK();
535a779388fSKristof Provost 
536a779388fSKristof Provost 	pending = malloc(sizeof(struct ifnet *) * curvnet->vnet_ifcnt,
537a779388fSKristof Provost 	    M_IFNET, M_WAITOK | M_ZERO);
538ad4e9116SBjoern A. Zeeb 
539ad4e9116SBjoern A. Zeeb 	/* Return all inherited interfaces to their parent vnets. */
5404f6c66ccSMatt Macy 	CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) {
541a779388fSKristof Provost 		if (ifp->if_home_vnet != ifp->if_vnet) {
542a779388fSKristof Provost 			found = if_unlink_ifnet(ifp, true);
543a779388fSKristof Provost 			MPASS(found);
544a779388fSKristof Provost 
545a779388fSKristof Provost 			pending[i++] = ifp;
546ad4e9116SBjoern A. Zeeb 		}
547ad4e9116SBjoern A. Zeeb 	}
548a779388fSKristof Provost 	IFNET_WUNLOCK();
549a779388fSKristof Provost 
550a779388fSKristof Provost 	for (int j = 0; j < i; j++) {
551a779388fSKristof Provost 		if_vmove(pending[j], pending[j]->if_home_vnet);
552a779388fSKristof Provost 	}
553a779388fSKristof Provost 
554a779388fSKristof Provost 	free(pending, M_IFNET);
555a779388fSKristof Provost }
556ad4e9116SBjoern A. Zeeb VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY,
557ad4e9116SBjoern A. Zeeb     vnet_if_return, NULL);
558bc29160dSMarko Zec #endif
559bc29160dSMarko Zec 
5604f6c66ccSMatt Macy static void *
561f9132cebSJonathan Lemon if_grow(void)
562f9132cebSJonathan Lemon {
5635f3b301aSJohn Baldwin 	int oldlim;
564f9132cebSJonathan Lemon 	u_int n;
565e6abef09SGleb Smirnoff 	struct ifnet **e;
5664f6c66ccSMatt Macy 	void *old;
567f9132cebSJonathan Lemon 
5684f6c66ccSMatt Macy 	old = NULL;
5695f3b301aSJohn Baldwin 	IFNET_WLOCK_ASSERT();
5705f3b301aSJohn Baldwin 	oldlim = V_if_indexlim;
5715f3b301aSJohn Baldwin 	IFNET_WUNLOCK();
5725f3b301aSJohn Baldwin 	n = (oldlim << 1) * sizeof(*e);
573fc74a9f9SBrooks Davis 	e = malloc(n, M_IFNET, M_WAITOK | M_ZERO);
5745f3b301aSJohn Baldwin 	IFNET_WLOCK();
5755f3b301aSJohn Baldwin 	if (V_if_indexlim != oldlim) {
5765f3b301aSJohn Baldwin 		free(e, M_IFNET);
5774f6c66ccSMatt Macy 		return (NULL);
5785f3b301aSJohn Baldwin 	}
579603724d3SBjoern A. Zeeb 	if (V_ifindex_table != NULL) {
580603724d3SBjoern A. Zeeb 		memcpy((caddr_t)e, (caddr_t)V_ifindex_table, n/2);
5814f6c66ccSMatt Macy 		old = V_ifindex_table;
582f9132cebSJonathan Lemon 	}
5835f3b301aSJohn Baldwin 	V_if_indexlim <<= 1;
584603724d3SBjoern A. Zeeb 	V_ifindex_table = e;
5854f6c66ccSMatt Macy 	return (old);
586f9132cebSJonathan Lemon }
587f9132cebSJonathan Lemon 
588df8bae1dSRodney W. Grimes /*
589a45cbf12SBrooks Davis  * Allocate a struct ifnet and an index for an interface.  A layer 2
590a45cbf12SBrooks Davis  * common structure will also be allocated if an allocation routine is
591a45cbf12SBrooks Davis  * registered for the passed type.
592fc74a9f9SBrooks Davis  */
593fc74a9f9SBrooks Davis struct ifnet *
5947687707dSAndrew Gallatin if_alloc_domain(u_char type, int numa_domain)
595fc74a9f9SBrooks Davis {
596fc74a9f9SBrooks Davis 	struct ifnet *ifp;
59761f6986bSRobert Watson 	u_short idx;
5984f6c66ccSMatt Macy 	void *old;
599fc74a9f9SBrooks Davis 
6007687707dSAndrew Gallatin 	KASSERT(numa_domain <= IF_NODOM, ("numa_domain too large"));
6017687707dSAndrew Gallatin 	if (numa_domain == IF_NODOM)
6027687707dSAndrew Gallatin 		ifp = malloc(sizeof(struct ifnet), M_IFNET,
6037687707dSAndrew Gallatin 		    M_WAITOK | M_ZERO);
6047687707dSAndrew Gallatin 	else
6057687707dSAndrew Gallatin 		ifp = malloc_domainset(sizeof(struct ifnet), M_IFNET,
6067687707dSAndrew Gallatin 		    DOMAINSET_PREF(numa_domain), M_WAITOK | M_ZERO);
6074f6c66ccSMatt Macy  restart:
60861f6986bSRobert Watson 	IFNET_WLOCK();
6094f6c66ccSMatt Macy 	idx = ifindex_alloc(&old);
6104f6c66ccSMatt Macy 	if (__predict_false(idx == USHRT_MAX)) {
6114f6c66ccSMatt Macy 		IFNET_WUNLOCK();
6124f6c66ccSMatt Macy 		epoch_wait_preempt(net_epoch_preempt);
6134f6c66ccSMatt Macy 		free(old, M_IFNET);
6144f6c66ccSMatt Macy 		goto restart;
6154f6c66ccSMatt Macy 	}
6164f6c66ccSMatt Macy 	ifnet_setbyindex(idx, IFNET_HOLD);
61761f6986bSRobert Watson 	IFNET_WUNLOCK();
61861f6986bSRobert Watson 	ifp->if_index = idx;
619fc74a9f9SBrooks Davis 	ifp->if_type = type;
62027d37320SRobert Watson 	ifp->if_alloctype = type;
6217687707dSAndrew Gallatin 	ifp->if_numa_domain = numa_domain;
622a29c7aebSBjoern A. Zeeb #ifdef VIMAGE
623a29c7aebSBjoern A. Zeeb 	ifp->if_vnet = curvnet;
624a29c7aebSBjoern A. Zeeb #endif
625fc74a9f9SBrooks Davis 	if (if_com_alloc[type] != NULL) {
626fc74a9f9SBrooks Davis 		ifp->if_l2com = if_com_alloc[type](type, ifp);
62728ef2db4SBrooks Davis 		if (ifp->if_l2com == NULL) {
628fc74a9f9SBrooks Davis 			free(ifp, M_IFNET);
629ed2dabfcSRobert Watson 			ifindex_free(idx);
63028ef2db4SBrooks Davis 			return (NULL);
63128ef2db4SBrooks Davis 		}
632fc74a9f9SBrooks Davis 	}
63327d37320SRobert Watson 
63427d37320SRobert Watson 	IF_ADDR_LOCK_INIT(ifp);
635d6f157eaSRobert Watson 	TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp);
6360839aa5cSGleb Smirnoff 	TASK_INIT(&ifp->if_addmultitask, 0, if_siocaddmulti, ifp);
637d6f157eaSRobert Watson 	ifp->if_afdata_initialized = 0;
638e0c14af9SMarko Zec 	IF_AFDATA_LOCK_INIT(ifp);
639d7c5a620SMatt Macy 	CK_STAILQ_INIT(&ifp->if_addrhead);
640d7c5a620SMatt Macy 	CK_STAILQ_INIT(&ifp->if_multiaddrs);
6414f6c66ccSMatt Macy 	CK_STAILQ_INIT(&ifp->if_groups);
642d6f157eaSRobert Watson #ifdef MAC
643d6f157eaSRobert Watson 	mac_ifnet_init(ifp);
644d6f157eaSRobert Watson #endif
645d659538fSSam Leffler 	ifq_init(&ifp->if_snd, ifp);
646d6f157eaSRobert Watson 
64727d37320SRobert Watson 	refcount_init(&ifp->if_refcount, 1);	/* Index reference. */
648112f50ffSGleb Smirnoff 	for (int i = 0; i < IFCOUNTERS; i++)
649112f50ffSGleb Smirnoff 		ifp->if_counters[i] = counter_u64_alloc(M_WAITOK);
65061dc4344SAndrey V. Elsukov 	ifp->if_get_counter = if_get_counter_default;
651f1379734SKonstantin Belousov 	ifp->if_pcp = IFNET_PCP_NONE;
65261dc4344SAndrey V. Elsukov 	ifnet_setbyindex(ifp->if_index, ifp);
653fc74a9f9SBrooks Davis 	return (ifp);
654fc74a9f9SBrooks Davis }
655fc74a9f9SBrooks Davis 
6567687707dSAndrew Gallatin struct ifnet *
6577687707dSAndrew Gallatin if_alloc_dev(u_char type, device_t dev)
6587687707dSAndrew Gallatin {
6597687707dSAndrew Gallatin 	int numa_domain;
6607687707dSAndrew Gallatin 
6617687707dSAndrew Gallatin 	if (dev == NULL || bus_get_domain(dev, &numa_domain) != 0)
6627687707dSAndrew Gallatin 		return (if_alloc_domain(type, IF_NODOM));
6637687707dSAndrew Gallatin 	return (if_alloc_domain(type, numa_domain));
6647687707dSAndrew Gallatin }
6657687707dSAndrew Gallatin 
6667687707dSAndrew Gallatin struct ifnet *
6677687707dSAndrew Gallatin if_alloc(u_char type)
6687687707dSAndrew Gallatin {
6697687707dSAndrew Gallatin 
6707687707dSAndrew Gallatin 	return (if_alloc_domain(type, IF_NODOM));
6717687707dSAndrew Gallatin }
672a45cbf12SBrooks Davis /*
6734c506522SGleb Smirnoff  * Do the actual work of freeing a struct ifnet, and layer 2 common
6744c506522SGleb Smirnoff  * structure.  This call is made when the last reference to an
675242a8e72SRobert Watson  * interface is released.
676a45cbf12SBrooks Davis  */
677242a8e72SRobert Watson static void
678242a8e72SRobert Watson if_free_internal(struct ifnet *ifp)
679fc74a9f9SBrooks Davis {
680fc74a9f9SBrooks Davis 
681242a8e72SRobert Watson 	KASSERT((ifp->if_flags & IFF_DYING),
682242a8e72SRobert Watson 	    ("if_free_internal: interface not dying"));
683fc74a9f9SBrooks Davis 
68427d37320SRobert Watson 	if (if_com_free[ifp->if_alloctype] != NULL)
68527d37320SRobert Watson 		if_com_free[ifp->if_alloctype](ifp->if_l2com,
68627d37320SRobert Watson 		    ifp->if_alloctype);
687fc74a9f9SBrooks Davis 
688d6f157eaSRobert Watson #ifdef MAC
689d6f157eaSRobert Watson 	mac_ifnet_destroy(ifp);
690d6f157eaSRobert Watson #endif /* MAC */
691d6f157eaSRobert Watson 	IF_AFDATA_DESTROY(ifp);
69202f4879dSRobert Watson 	IF_ADDR_LOCK_DESTROY(ifp);
693d659538fSSam Leffler 	ifq_delete(&ifp->if_snd);
694112f50ffSGleb Smirnoff 
695112f50ffSGleb Smirnoff 	for (int i = 0; i < IFCOUNTERS; i++)
696112f50ffSGleb Smirnoff 		counter_u64_free(ifp->if_counters[i]);
697112f50ffSGleb Smirnoff 
69885107355SAndrey V. Elsukov 	free(ifp->if_description, M_IFDESCR);
69985107355SAndrey V. Elsukov 	free(ifp->if_hw_addr, M_IFADDR);
700fc74a9f9SBrooks Davis 	free(ifp, M_IFNET);
701c0c9ea90SSam Leffler }
702fc74a9f9SBrooks Davis 
7034f6c66ccSMatt Macy static void
7044f6c66ccSMatt Macy if_destroy(epoch_context_t ctx)
7054f6c66ccSMatt Macy {
7064f6c66ccSMatt Macy 	struct ifnet *ifp;
7074f6c66ccSMatt Macy 
7084f6c66ccSMatt Macy 	ifp = __containerof(ctx, struct ifnet, if_epoch_ctx);
7094f6c66ccSMatt Macy 	if_free_internal(ifp);
7104f6c66ccSMatt Macy }
7114f6c66ccSMatt Macy 
712242a8e72SRobert Watson /*
713f26fa169SBrooks Davis  * Deregister an interface and free the associated storage.
714242a8e72SRobert Watson  */
715242a8e72SRobert Watson void
716f26fa169SBrooks Davis if_free(struct ifnet *ifp)
717242a8e72SRobert Watson {
718242a8e72SRobert Watson 
719242a8e72SRobert Watson 	ifp->if_flags |= IFF_DYING;			/* XXX: Locking */
7204c506522SGleb Smirnoff 
721719fb725SCraig Rodrigues 	CURVNET_SET_QUIET(ifp->if_vnet);
7224c506522SGleb Smirnoff 	IFNET_WLOCK();
723270b83b9SHans Petter Selasky 	KASSERT(ifp == ifnet_byindex(ifp->if_index),
7244c506522SGleb Smirnoff 	    ("%s: freeing unallocated ifnet", ifp->if_xname));
7254c506522SGleb Smirnoff 
7264c506522SGleb Smirnoff 	ifindex_free_locked(ifp->if_index);
7274c506522SGleb Smirnoff 	IFNET_WUNLOCK();
7284c506522SGleb Smirnoff 
729719fb725SCraig Rodrigues 	if (refcount_release(&ifp->if_refcount))
7302a4bd982SGleb Smirnoff 		NET_EPOCH_CALL(if_destroy, &ifp->if_epoch_ctx);
731719fb725SCraig Rodrigues 	CURVNET_RESTORE();
732242a8e72SRobert Watson }
733242a8e72SRobert Watson 
734242a8e72SRobert Watson /*
735242a8e72SRobert Watson  * Interfaces to keep an ifnet type-stable despite the possibility of the
736242a8e72SRobert Watson  * driver calling if_free().  If there are additional references, we defer
737242a8e72SRobert Watson  * freeing the underlying data structure.
738242a8e72SRobert Watson  */
739db7f0b97SKip Macy void
74027d37320SRobert Watson if_ref(struct ifnet *ifp)
74127d37320SRobert Watson {
742*7563019bSAlexander V. Chernikov 	u_int old;
74327d37320SRobert Watson 
74427d37320SRobert Watson 	/* We don't assert the ifnet list lock here, but arguably should. */
745*7563019bSAlexander V. Chernikov 	old = refcount_acquire(&ifp->if_refcount);
746*7563019bSAlexander V. Chernikov 	KASSERT(old > 0, ("%s: ifp %p has 0 refs", __func__, ifp));
747*7563019bSAlexander V. Chernikov }
748*7563019bSAlexander V. Chernikov 
749*7563019bSAlexander V. Chernikov bool
750*7563019bSAlexander V. Chernikov if_try_ref(struct ifnet *ifp)
751*7563019bSAlexander V. Chernikov {
752*7563019bSAlexander V. Chernikov 	NET_EPOCH_ASSERT();
753*7563019bSAlexander V. Chernikov 	return (refcount_acquire_if_not_zero(&ifp->if_refcount));
75427d37320SRobert Watson }
75527d37320SRobert Watson 
75627d37320SRobert Watson void
75727d37320SRobert Watson if_rele(struct ifnet *ifp)
75827d37320SRobert Watson {
75927d37320SRobert Watson 
760242a8e72SRobert Watson 	if (!refcount_release(&ifp->if_refcount))
761242a8e72SRobert Watson 		return;
7622a4bd982SGleb Smirnoff 	NET_EPOCH_CALL(if_destroy, &ifp->if_epoch_ctx);
76327d37320SRobert Watson }
76427d37320SRobert Watson 
76527d37320SRobert Watson void
766d659538fSSam Leffler ifq_init(struct ifaltq *ifq, struct ifnet *ifp)
767db7f0b97SKip Macy {
768db7f0b97SKip Macy 
769db7f0b97SKip Macy 	mtx_init(&ifq->ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF);
770db7f0b97SKip Macy 
771db7f0b97SKip Macy 	if (ifq->ifq_maxlen == 0)
772db7f0b97SKip Macy 		ifq->ifq_maxlen = ifqmaxlen;
773db7f0b97SKip Macy 
774db7f0b97SKip Macy 	ifq->altq_type = 0;
775db7f0b97SKip Macy 	ifq->altq_disc = NULL;
776db7f0b97SKip Macy 	ifq->altq_flags &= ALTQF_CANTCHANGE;
777db7f0b97SKip Macy 	ifq->altq_tbr  = NULL;
778db7f0b97SKip Macy 	ifq->altq_ifp  = ifp;
779db7f0b97SKip Macy }
780db7f0b97SKip Macy 
781db7f0b97SKip Macy void
782d659538fSSam Leffler ifq_delete(struct ifaltq *ifq)
783db7f0b97SKip Macy {
784db7f0b97SKip Macy 	mtx_destroy(&ifq->ifq_mtx);
785db7f0b97SKip Macy }
786db7f0b97SKip Macy 
787fc74a9f9SBrooks Davis /*
788a4641f4eSPedro F. Giffuni  * Perform generic interface initialization tasks and attach the interface
789e0c14af9SMarko Zec  * to the list of "active" interfaces.  If vmove flag is set on entry
790e0c14af9SMarko Zec  * to if_attach_internal(), perform only a limited subset of initialization
791e0c14af9SMarko Zec  * tasks, given that we are moving from one vnet to another an ifnet which
792e0c14af9SMarko Zec  * has already been fully initialized.
793a45cbf12SBrooks Davis  *
794c92a456bSHiroki Sato  * Note that if_detach_internal() removes group membership unconditionally
795c92a456bSHiroki Sato  * even when vmove flag is set, and if_attach_internal() adds only IFG_ALL.
796c92a456bSHiroki Sato  * Thus, when if_vmove() is applied to a cloned interface, group membership
797c92a456bSHiroki Sato  * is lost while a cloned one always joins a group whose name is
798c92a456bSHiroki Sato  * ifc->ifc_name.  To recover this after if_detach_internal() and
799c92a456bSHiroki Sato  * if_attach_internal(), the cloner should be specified to
800c92a456bSHiroki Sato  * if_attach_internal() via ifc.  If it is non-NULL, if_attach_internal()
801c92a456bSHiroki Sato  * attempts to join a group whose name is ifc->ifc_name.
802c92a456bSHiroki Sato  *
803a45cbf12SBrooks Davis  * XXX:
804a45cbf12SBrooks Davis  *  - The decision to return void and thus require this function to
805a45cbf12SBrooks Davis  *    succeed is questionable.
806a45cbf12SBrooks Davis  *  - We should probably do more sanity checking.  For instance we don't
807a45cbf12SBrooks Davis  *    do anything to insure if_xname is unique or non-empty.
808df8bae1dSRodney W. Grimes  */
809df8bae1dSRodney W. Grimes void
81072fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp)
811df8bae1dSRodney W. Grimes {
812e0c14af9SMarko Zec 
813c92a456bSHiroki Sato 	if_attach_internal(ifp, 0, NULL);
814e0c14af9SMarko Zec }
815e0c14af9SMarko Zec 
8169fd573c3SHans Petter Selasky /*
8179fd573c3SHans Petter Selasky  * Compute the least common TSO limit.
8189fd573c3SHans Petter Selasky  */
8199fd573c3SHans Petter Selasky void
8209fd573c3SHans Petter Selasky if_hw_tsomax_common(if_t ifp, struct ifnet_hw_tsomax *pmax)
8219fd573c3SHans Petter Selasky {
8229fd573c3SHans Petter Selasky 	/*
8239fd573c3SHans Petter Selasky 	 * 1) If there is no limit currently, take the limit from
8249fd573c3SHans Petter Selasky 	 * the network adapter.
8259fd573c3SHans Petter Selasky 	 *
8269fd573c3SHans Petter Selasky 	 * 2) If the network adapter has a limit below the current
8279fd573c3SHans Petter Selasky 	 * limit, apply it.
8289fd573c3SHans Petter Selasky 	 */
8299fd573c3SHans Petter Selasky 	if (pmax->tsomaxbytes == 0 || (ifp->if_hw_tsomax != 0 &&
8309fd573c3SHans Petter Selasky 	    ifp->if_hw_tsomax < pmax->tsomaxbytes)) {
8319fd573c3SHans Petter Selasky 		pmax->tsomaxbytes = ifp->if_hw_tsomax;
8329fd573c3SHans Petter Selasky 	}
8339fd573c3SHans Petter Selasky 	if (pmax->tsomaxsegcount == 0 || (ifp->if_hw_tsomaxsegcount != 0 &&
8349fd573c3SHans Petter Selasky 	    ifp->if_hw_tsomaxsegcount < pmax->tsomaxsegcount)) {
8359fd573c3SHans Petter Selasky 		pmax->tsomaxsegcount = ifp->if_hw_tsomaxsegcount;
8369fd573c3SHans Petter Selasky 	}
8379fd573c3SHans Petter Selasky 	if (pmax->tsomaxsegsize == 0 || (ifp->if_hw_tsomaxsegsize != 0 &&
8389fd573c3SHans Petter Selasky 	    ifp->if_hw_tsomaxsegsize < pmax->tsomaxsegsize)) {
8399fd573c3SHans Petter Selasky 		pmax->tsomaxsegsize = ifp->if_hw_tsomaxsegsize;
8409fd573c3SHans Petter Selasky 	}
8419fd573c3SHans Petter Selasky }
8429fd573c3SHans Petter Selasky 
8439fd573c3SHans Petter Selasky /*
8449fd573c3SHans Petter Selasky  * Update TSO limit of a network adapter.
8459fd573c3SHans Petter Selasky  *
8469fd573c3SHans Petter Selasky  * Returns zero if no change. Else non-zero.
8479fd573c3SHans Petter Selasky  */
8489fd573c3SHans Petter Selasky int
8499fd573c3SHans Petter Selasky if_hw_tsomax_update(if_t ifp, struct ifnet_hw_tsomax *pmax)
8509fd573c3SHans Petter Selasky {
8519fd573c3SHans Petter Selasky 	int retval = 0;
8529fd573c3SHans Petter Selasky 	if (ifp->if_hw_tsomax != pmax->tsomaxbytes) {
8539fd573c3SHans Petter Selasky 		ifp->if_hw_tsomax = pmax->tsomaxbytes;
8549fd573c3SHans Petter Selasky 		retval++;
8559fd573c3SHans Petter Selasky 	}
8569fd573c3SHans Petter Selasky 	if (ifp->if_hw_tsomaxsegsize != pmax->tsomaxsegsize) {
8579fd573c3SHans Petter Selasky 		ifp->if_hw_tsomaxsegsize = pmax->tsomaxsegsize;
8589fd573c3SHans Petter Selasky 		retval++;
8599fd573c3SHans Petter Selasky 	}
8609fd573c3SHans Petter Selasky 	if (ifp->if_hw_tsomaxsegcount != pmax->tsomaxsegcount) {
8619fd573c3SHans Petter Selasky 		ifp->if_hw_tsomaxsegcount = pmax->tsomaxsegcount;
8629fd573c3SHans Petter Selasky 		retval++;
8639fd573c3SHans Petter Selasky 	}
8649fd573c3SHans Petter Selasky 	return (retval);
8659fd573c3SHans Petter Selasky }
8669fd573c3SHans Petter Selasky 
867e0c14af9SMarko Zec static void
868c92a456bSHiroki Sato if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
869e0c14af9SMarko Zec {
870df8bae1dSRodney W. Grimes 	unsigned socksize, ifasize;
8711ce9bf88SPoul-Henning Kamp 	int namelen, masklen;
87272fd1b6aSDag-Erling Smørgrav 	struct sockaddr_dl *sdl;
87372fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
874df8bae1dSRodney W. Grimes 
875fc74a9f9SBrooks Davis 	if (ifp->if_index == 0 || ifp != ifnet_byindex(ifp->if_index))
876fc74a9f9SBrooks Davis 		panic ("%s: BUG: if_attach called without if_alloc'd input()\n",
877fc74a9f9SBrooks Davis 		    ifp->if_xname);
878fc74a9f9SBrooks Davis 
879f6dfe47aSMarko Zec #ifdef VIMAGE
880f6dfe47aSMarko Zec 	ifp->if_vnet = curvnet;
881bc29160dSMarko Zec 	if (ifp->if_home_vnet == NULL)
882bc29160dSMarko Zec 		ifp->if_home_vnet = curvnet;
883f6dfe47aSMarko Zec #endif
884f6dfe47aSMarko Zec 
8850dad3f0eSMax Laier 	if_addgroup(ifp, IFG_ALL);
8860dad3f0eSMax Laier 
887c92a456bSHiroki Sato 	/* Restore group membership for cloned interfaces. */
888c92a456bSHiroki Sato 	if (vmove && ifc != NULL)
889c92a456bSHiroki Sato 		if_clone_addgroup(ifp, ifc);
890c92a456bSHiroki Sato 
89198b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
892e6485f73SGleb Smirnoff 	ifp->if_epoch = time_uptime;
893d6f157eaSRobert Watson 
8947cc5b47fSKip Macy 	KASSERT((ifp->if_transmit == NULL && ifp->if_qflush == NULL) ||
8957cc5b47fSKip Macy 	    (ifp->if_transmit != NULL && ifp->if_qflush != NULL),
8967cc5b47fSKip Macy 	    ("transmit and qflush must both either be set or both be NULL"));
8977cc5b47fSKip Macy 	if (ifp->if_transmit == NULL) {
898db7f0b97SKip Macy 		ifp->if_transmit = if_transmit;
899db7f0b97SKip Macy 		ifp->if_qflush = if_qflush;
9007cc5b47fSKip Macy 	}
901b57d9721SAndrey V. Elsukov 	if (ifp->if_input == NULL)
902b57d9721SAndrey V. Elsukov 		ifp->if_input = if_input_default;
9037cc5b47fSKip Macy 
9044fb3a820SAlexander V. Chernikov 	if (ifp->if_requestencap == NULL)
9054fb3a820SAlexander V. Chernikov 		ifp->if_requestencap = if_requestencap_default;
9064fb3a820SAlexander V. Chernikov 
907e0c14af9SMarko Zec 	if (!vmove) {
908e70cd263SRobert Watson #ifdef MAC
90930d239bcSRobert Watson 		mac_ifnet_create(ifp);
910e70cd263SRobert Watson #endif
911e70cd263SRobert Watson 
912df8bae1dSRodney W. Grimes 		/*
913e0c14af9SMarko Zec 		 * Create a Link Level name for this device.
914df8bae1dSRodney W. Grimes 		 */
9159bf40edeSBrooks Davis 		namelen = strlen(ifp->if_xname);
91636c19a57SBrooks Davis 		/*
917e0c14af9SMarko Zec 		 * Always save enough space for any possiable name so we
918e0c14af9SMarko Zec 		 * can do a rename in place later.
91936c19a57SBrooks Davis 		 */
92036c19a57SBrooks Davis 		masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ;
921df8bae1dSRodney W. Grimes 		socksize = masklen + ifp->if_addrlen;
922df8bae1dSRodney W. Grimes 		if (socksize < sizeof(*sdl))
923df8bae1dSRodney W. Grimes 			socksize = sizeof(*sdl);
924ccb82468SBrooks Davis 		socksize = roundup2(socksize, sizeof(long));
925df8bae1dSRodney W. Grimes 		ifasize = sizeof(*ifa) + 2 * socksize;
92646758960SGleb Smirnoff 		ifa = ifa_alloc(ifasize, M_WAITOK);
927df8bae1dSRodney W. Grimes 		sdl = (struct sockaddr_dl *)(ifa + 1);
928df8bae1dSRodney W. Grimes 		sdl->sdl_len = socksize;
929df8bae1dSRodney W. Grimes 		sdl->sdl_family = AF_LINK;
9309bf40edeSBrooks Davis 		bcopy(ifp->if_xname, sdl->sdl_data, namelen);
9311ce9bf88SPoul-Henning Kamp 		sdl->sdl_nlen = namelen;
932df8bae1dSRodney W. Grimes 		sdl->sdl_index = ifp->if_index;
933df8bae1dSRodney W. Grimes 		sdl->sdl_type = ifp->if_type;
9344a0d6638SRuslan Ermilov 		ifp->if_addr = ifa;
935df8bae1dSRodney W. Grimes 		ifa->ifa_ifp = ifp;
936df8bae1dSRodney W. Grimes 		ifa->ifa_addr = (struct sockaddr *)sdl;
937df8bae1dSRodney W. Grimes 		sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
938df8bae1dSRodney W. Grimes 		ifa->ifa_netmask = (struct sockaddr *)sdl;
939df8bae1dSRodney W. Grimes 		sdl->sdl_len = masklen;
940df8bae1dSRodney W. Grimes 		while (namelen != 0)
941df8bae1dSRodney W. Grimes 			sdl->sdl_data[--namelen] = 0xff;
942d7c5a620SMatt Macy 		CK_STAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
943e0c14af9SMarko Zec 		/* Reliably crash if used uninitialized. */
944e0c14af9SMarko Zec 		ifp->if_broadcastaddr = NULL;
94572f31000SHans Petter Selasky 
946ddae5750SRavi Pokala 		if (ifp->if_type == IFT_ETHER) {
947ddae5750SRavi Pokala 			ifp->if_hw_addr = malloc(ifp->if_addrlen, M_IFADDR,
948ddae5750SRavi Pokala 			    M_WAITOK | M_ZERO);
949ddae5750SRavi Pokala 		}
950ddae5750SRavi Pokala 
95172f31000SHans Petter Selasky #if defined(INET) || defined(INET6)
9529fd573c3SHans Petter Selasky 		/* Use defaults for TSO, if nothing is set */
9539fd573c3SHans Petter Selasky 		if (ifp->if_hw_tsomax == 0 &&
9549fd573c3SHans Petter Selasky 		    ifp->if_hw_tsomaxsegcount == 0 &&
9559fd573c3SHans Petter Selasky 		    ifp->if_hw_tsomaxsegsize == 0) {
9569fd573c3SHans Petter Selasky 			/*
9579fd573c3SHans Petter Selasky 			 * The TSO defaults needs to be such that an
9589fd573c3SHans Petter Selasky 			 * NFS mbuf list of 35 mbufs totalling just
9599fd573c3SHans Petter Selasky 			 * below 64K works and that a chain of mbufs
9609fd573c3SHans Petter Selasky 			 * can be defragged into at most 32 segments:
9619fd573c3SHans Petter Selasky 			 */
9629fd573c3SHans Petter Selasky 			ifp->if_hw_tsomax = min(IP_MAXPACKET, (32 * MCLBYTES) -
96372f31000SHans Petter Selasky 			    (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
9649fd573c3SHans Petter Selasky 			ifp->if_hw_tsomaxsegcount = 35;
9659fd573c3SHans Petter Selasky 			ifp->if_hw_tsomaxsegsize = 2048;	/* 2K */
9669fd573c3SHans Petter Selasky 
9679fd573c3SHans Petter Selasky 			/* XXX some drivers set IFCAP_TSO after ethernet attach */
9689fd573c3SHans Petter Selasky 			if (ifp->if_capabilities & IFCAP_TSO) {
9699fd573c3SHans Petter Selasky 				if_printf(ifp, "Using defaults for TSO: %u/%u/%u\n",
9709fd573c3SHans Petter Selasky 				    ifp->if_hw_tsomax,
9719fd573c3SHans Petter Selasky 				    ifp->if_hw_tsomaxsegcount,
9729fd573c3SHans Petter Selasky 				    ifp->if_hw_tsomaxsegsize);
9739fd573c3SHans Petter Selasky 			}
9749fd573c3SHans Petter Selasky 		}
97572f31000SHans Petter Selasky #endif
976e0c14af9SMarko Zec 	}
97752db6805SMarko Zec #ifdef VIMAGE
97852db6805SMarko Zec 	else {
97952db6805SMarko Zec 		/*
98052db6805SMarko Zec 		 * Update the interface index in the link layer address
98152db6805SMarko Zec 		 * of the interface.
98252db6805SMarko Zec 		 */
98352db6805SMarko Zec 		for (ifa = ifp->if_addr; ifa != NULL;
984d7c5a620SMatt Macy 		    ifa = CK_STAILQ_NEXT(ifa, ifa_link)) {
98552db6805SMarko Zec 			if (ifa->ifa_addr->sa_family == AF_LINK) {
98652db6805SMarko Zec 				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
98752db6805SMarko Zec 				sdl->sdl_index = ifp->if_index;
98852db6805SMarko Zec 			}
98952db6805SMarko Zec 		}
99052db6805SMarko Zec 	}
99152db6805SMarko Zec #endif
992d94ccb09SBrooks Davis 
993a779388fSKristof Provost 	if_link_ifnet(ifp);
994457f48e6SGleb Smirnoff 
99569fb23b7SMax Laier 	if (domain_init_status >= 2)
99631b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
99731b1bfe1SHajimu UMEMOTO 
99825a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
99921ca7b57SMarko Zec 	if (IS_DEFAULT_VNET(curvnet))
1000f3b90d48SAndrew Thompson 		devctl_notify("IFNET", ifp->if_xname, "ATTACH", NULL);
100125a4adceSMax Laier 
10027b6edd04SRuslan Ermilov 	/* Announce the interface. */
10037b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
1004df8bae1dSRodney W. Grimes }
10056182fdbdSPeter Wemm 
100631b1bfe1SHajimu UMEMOTO static void
1007f2d19f98SMatt Macy if_epochalloc(void *dummy __unused)
1008f2d19f98SMatt Macy {
1009f2d19f98SMatt Macy 
1010dd902d01SGleb Smirnoff 	net_epoch_preempt = epoch_alloc("Net preemptible", EPOCH_PREEMPT);
1011f2d19f98SMatt Macy }
10127993a104SConrad Meyer SYSINIT(ifepochalloc, SI_SUB_EPOCH, SI_ORDER_ANY, if_epochalloc, NULL);
1013f2d19f98SMatt Macy 
1014f2d19f98SMatt Macy static void
101572fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy)
101631b1bfe1SHajimu UMEMOTO {
101731b1bfe1SHajimu UMEMOTO 	struct ifnet *ifp;
101831b1bfe1SHajimu UMEMOTO 
10194f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link)
102031b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
102131b1bfe1SHajimu UMEMOTO }
102269fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND,
102331b1bfe1SHajimu UMEMOTO     if_attachdomain, NULL);
102431b1bfe1SHajimu UMEMOTO 
102531b1bfe1SHajimu UMEMOTO static void
102672fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp)
102731b1bfe1SHajimu UMEMOTO {
102831b1bfe1SHajimu UMEMOTO 	struct domain *dp;
102931b1bfe1SHajimu UMEMOTO 
1030234a35c7SHajimu UMEMOTO 	/*
1031234a35c7SHajimu UMEMOTO 	 * Since dp->dom_ifattach calls malloc() with M_WAITOK, we
1032234a35c7SHajimu UMEMOTO 	 * cannot lock ifp->if_afdata initialization, entirely.
1033234a35c7SHajimu UMEMOTO 	 */
1034c169d9feSBjoern A. Zeeb 	IF_AFDATA_LOCK(ifp);
103569fb23b7SMax Laier 	if (ifp->if_afdata_initialized >= domain_init_status) {
1036234a35c7SHajimu UMEMOTO 		IF_AFDATA_UNLOCK(ifp);
1037813ee737SAndre Oppermann 		log(LOG_WARNING, "%s called more than once on %s\n",
1038813ee737SAndre Oppermann 		    __func__, ifp->if_xname);
1039234a35c7SHajimu UMEMOTO 		return;
1040234a35c7SHajimu UMEMOTO 	}
104169fb23b7SMax Laier 	ifp->if_afdata_initialized = domain_init_status;
1042234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
1043234a35c7SHajimu UMEMOTO 
104431b1bfe1SHajimu UMEMOTO 	/* address family dependent data region */
104531b1bfe1SHajimu UMEMOTO 	bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
104631b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
104731b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifattach)
104831b1bfe1SHajimu UMEMOTO 			ifp->if_afdata[dp->dom_family] =
104931b1bfe1SHajimu UMEMOTO 			    (*dp->dom_ifattach)(ifp);
105031b1bfe1SHajimu UMEMOTO 	}
105131b1bfe1SHajimu UMEMOTO }
105231b1bfe1SHajimu UMEMOTO 
10536182fdbdSPeter Wemm /*
1054ec002feeSBruce M Simpson  * Remove any unicast or broadcast network addresses from an interface.
105545778b37SPeter Edwards  */
105645778b37SPeter Edwards void
105745778b37SPeter Edwards if_purgeaddrs(struct ifnet *ifp)
105845778b37SPeter Edwards {
105988d57e9eSHans Petter Selasky 	struct ifaddr *ifa;
106045778b37SPeter Edwards 
106188d57e9eSHans Petter Selasky 	while (1) {
1062a68cc388SGleb Smirnoff 		struct epoch_tracker et;
1063a68cc388SGleb Smirnoff 
1064a68cc388SGleb Smirnoff 		NET_EPOCH_ENTER(et);
106588d57e9eSHans Petter Selasky 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
106688d57e9eSHans Petter Selasky 			if (ifa->ifa_addr->sa_family != AF_LINK)
106788d57e9eSHans Petter Selasky 				break;
106888d57e9eSHans Petter Selasky 		}
1069a68cc388SGleb Smirnoff 		NET_EPOCH_EXIT(et);
107088d57e9eSHans Petter Selasky 
107188d57e9eSHans Petter Selasky 		if (ifa == NULL)
107288d57e9eSHans Petter Selasky 			break;
107345778b37SPeter Edwards #ifdef INET
107445778b37SPeter Edwards 		/* XXX: Ugly!! ad hoc just for INET */
10754b97d7afSYaroslav Tykhiy 		if (ifa->ifa_addr->sa_family == AF_INET) {
107645778b37SPeter Edwards 			struct ifaliasreq ifr;
107745778b37SPeter Edwards 
107845778b37SPeter Edwards 			bzero(&ifr, sizeof(ifr));
107945778b37SPeter Edwards 			ifr.ifra_addr = *ifa->ifa_addr;
108045778b37SPeter Edwards 			if (ifa->ifa_dstaddr)
108145778b37SPeter Edwards 				ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
108245778b37SPeter Edwards 			if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
108345778b37SPeter Edwards 			    NULL) == 0)
108445778b37SPeter Edwards 				continue;
108545778b37SPeter Edwards 		}
108645778b37SPeter Edwards #endif /* INET */
108745778b37SPeter Edwards #ifdef INET6
10884b97d7afSYaroslav Tykhiy 		if (ifa->ifa_addr->sa_family == AF_INET6) {
1089f9e0752eSAlexander V. Chernikov 			in6_purgeifaddr((struct in6_ifaddr *)ifa);
109045778b37SPeter Edwards 			/* ifp_addrhead is already updated */
109145778b37SPeter Edwards 			continue;
109245778b37SPeter Edwards 		}
109345778b37SPeter Edwards #endif /* INET6 */
1094f22d78c0SBjoern A. Zeeb 		IF_ADDR_WLOCK(ifp);
1095d7c5a620SMatt Macy 		CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link);
1096f22d78c0SBjoern A. Zeeb 		IF_ADDR_WUNLOCK(ifp);
10971099f828SRobert Watson 		ifa_free(ifa);
109845778b37SPeter Edwards 	}
109945778b37SPeter Edwards }
110045778b37SPeter Edwards 
110145778b37SPeter Edwards /*
110293ec7edcSShteryana Shopova  * Remove any multicast network addresses from an interface when an ifnet
110393ec7edcSShteryana Shopova  * is going away.
1104ec002feeSBruce M Simpson  */
110593ec7edcSShteryana Shopova static void
1106ec002feeSBruce M Simpson if_purgemaddrs(struct ifnet *ifp)
1107ec002feeSBruce M Simpson {
1108ec002feeSBruce M Simpson 	struct ifmultiaddr *ifma;
1109ec002feeSBruce M Simpson 
1110137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
1111d7c5a620SMatt Macy 	while (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) {
1112d7c5a620SMatt Macy 		ifma = CK_STAILQ_FIRST(&ifp->if_multiaddrs);
1113d7c5a620SMatt Macy 		CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
1114ec002feeSBruce M Simpson 		if_delmulti_locked(ifp, ifma, 1);
1115f3e1324bSStephen Hurd 	}
1116137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
1117ec002feeSBruce M Simpson }
1118ec002feeSBruce M Simpson 
1119ec002feeSBruce M Simpson /*
1120e0c14af9SMarko Zec  * Detach an interface, removing it from the list of "active" interfaces.
1121e0c14af9SMarko Zec  * If vmove flag is set on entry to if_detach_internal(), perform only a
1122e0c14af9SMarko Zec  * limited subset of cleanup tasks, given that we are moving an ifnet from
1123e0c14af9SMarko Zec  * one vnet to another, where it must be fully operational.
1124b1c53bc9SRobert Watson  *
1125b1c53bc9SRobert Watson  * XXXRW: There are some significant questions about event ordering, and
1126b1c53bc9SRobert Watson  * how to prevent things from starting to use the interface during detach.
11276182fdbdSPeter Wemm  */
11286182fdbdSPeter Wemm void
112972fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp)
11306182fdbdSPeter Wemm {
1131a779388fSKristof Provost 	bool found;
1132e0c14af9SMarko Zec 
1133719fb725SCraig Rodrigues 	CURVNET_SET_QUIET(ifp->if_vnet);
1134a779388fSKristof Provost 	found = if_unlink_ifnet(ifp, false);
1135e133271fSKristof Provost 	if (found) {
11366d2a10d9SKristof Provost 		sx_xlock(&ifnet_detach_sxlock);
1137c92a456bSHiroki Sato 		if_detach_internal(ifp, 0, NULL);
11386d2a10d9SKristof Provost 		sx_xunlock(&ifnet_detach_sxlock);
1139e133271fSKristof Provost 	}
1140719fb725SCraig Rodrigues 	CURVNET_RESTORE();
1141e0c14af9SMarko Zec }
1142e0c14af9SMarko Zec 
114389856f7eSBjoern A. Zeeb /*
114489856f7eSBjoern A. Zeeb  * The vmove flag, if set, indicates that we are called from a callpath
114589856f7eSBjoern A. Zeeb  * that is moving an interface to a different vnet instance.
114689856f7eSBjoern A. Zeeb  *
114789856f7eSBjoern A. Zeeb  * The shutdown flag, if set, indicates that we are called in the
114889856f7eSBjoern A. Zeeb  * process of shutting down a vnet instance.  Currently only the
114989856f7eSBjoern A. Zeeb  * vnet_if_return SYSUNINIT function sets it.  Note: we can be called
115089856f7eSBjoern A. Zeeb  * on a vnet instance shutdown without this flag being set, e.g., when
115189856f7eSBjoern A. Zeeb  * the cloned interfaces are destoyed as first thing of teardown.
115289856f7eSBjoern A. Zeeb  */
1153f501e6f1SBjoern A. Zeeb static int
1154c92a456bSHiroki Sato if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
1155e0c14af9SMarko Zec {
115645778b37SPeter Edwards 	struct ifaddr *ifa;
11574bdf0b6aSAlexander V. Chernikov 	int i;
115831b1bfe1SHajimu UMEMOTO 	struct domain *dp;
1159d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE
1160204e2f30SHans Petter Selasky 	bool shutdown;
1161457f48e6SGleb Smirnoff 
116210108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet);
1163d3f6f80fSBjoern A. Zeeb #endif
11646182fdbdSPeter Wemm 
116589856f7eSBjoern A. Zeeb 	/*
116689856f7eSBjoern A. Zeeb 	 * At this point we know the interface still was on the ifnet list
116789856f7eSBjoern A. Zeeb 	 * and we removed it so we are in a stable state.
116889856f7eSBjoern A. Zeeb 	 */
11694f6c66ccSMatt Macy 	epoch_wait_preempt(net_epoch_preempt);
11700dbdf041SHans Petter Selasky 
11710dbdf041SHans Petter Selasky 	/*
11720dbdf041SHans Petter Selasky 	 * Ensure all pending EPOCH(9) callbacks have been executed. This
11730dbdf041SHans Petter Selasky 	 * fixes issues about late destruction of multicast options
11740dbdf041SHans Petter Selasky 	 * which lead to leave group calls, which in turn access the
11750dbdf041SHans Petter Selasky 	 * belonging ifnet structure:
11760dbdf041SHans Petter Selasky 	 */
11770dbdf041SHans Petter Selasky 	epoch_drain_callbacks(net_epoch_preempt);
11780dbdf041SHans Petter Selasky 
117989856f7eSBjoern A. Zeeb 	/*
118089856f7eSBjoern A. Zeeb 	 * In any case (destroy or vmove) detach us from the groups
118189856f7eSBjoern A. Zeeb 	 * and remove/wait for pending events on the taskq.
118289856f7eSBjoern A. Zeeb 	 * XXX-BZ in theory an interface could still enqueue a taskq change?
118389856f7eSBjoern A. Zeeb 	 */
118489856f7eSBjoern A. Zeeb 	if_delgroups(ifp);
118589856f7eSBjoern A. Zeeb 
118689856f7eSBjoern A. Zeeb 	taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
11870839aa5cSGleb Smirnoff 	taskqueue_drain(taskqueue_swi, &ifp->if_addmultitask);
118889856f7eSBjoern A. Zeeb 
118989856f7eSBjoern A. Zeeb 	/*
119089856f7eSBjoern A. Zeeb 	 * Check if this is a cloned interface or not. Must do even if
119189856f7eSBjoern A. Zeeb 	 * shutting down as a if_vmove_reclaim() would move the ifp and
119289856f7eSBjoern A. Zeeb 	 * the if_clone_addgroup() will have a corrupted string overwise
119389856f7eSBjoern A. Zeeb 	 * from a gibberish pointer.
119489856f7eSBjoern A. Zeeb 	 */
1195c92a456bSHiroki Sato 	if (vmove && ifcp != NULL)
1196c92a456bSHiroki Sato 		*ifcp = if_clone_findifc(ifp);
1197c92a456bSHiroki Sato 
119889856f7eSBjoern A. Zeeb 	if_down(ifp);
119989856f7eSBjoern A. Zeeb 
1200d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE
120168a3482fSGleb Smirnoff 	/*
120289856f7eSBjoern A. Zeeb 	 * On VNET shutdown abort here as the stack teardown will do all
120389856f7eSBjoern A. Zeeb 	 * the work top-down for us.
120468a3482fSGleb Smirnoff 	 */
120589856f7eSBjoern A. Zeeb 	if (shutdown) {
120625c6ab1bSKristof Provost 		/* Give interface users the chance to clean up. */
120725c6ab1bSKristof Provost 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
120825c6ab1bSKristof Provost 
120989856f7eSBjoern A. Zeeb 		/*
121089856f7eSBjoern A. Zeeb 		 * In case of a vmove we are done here without error.
121189856f7eSBjoern A. Zeeb 		 * If we would signal an error it would lead to the same
121289856f7eSBjoern A. Zeeb 		 * abort as if we did not find the ifnet anymore.
121389856f7eSBjoern A. Zeeb 		 * if_detach() calls us in void context and does not care
121489856f7eSBjoern A. Zeeb 		 * about an early abort notification, so life is splendid :)
121589856f7eSBjoern A. Zeeb 		 */
121689856f7eSBjoern A. Zeeb 		goto finish_vnet_shutdown;
121789856f7eSBjoern A. Zeeb 	}
1218d3f6f80fSBjoern A. Zeeb #endif
121989856f7eSBjoern A. Zeeb 
122089856f7eSBjoern A. Zeeb 	/*
122189856f7eSBjoern A. Zeeb 	 * At this point we are not tearing down a VNET and are either
122289856f7eSBjoern A. Zeeb 	 * going to destroy or vmove the interface and have to cleanup
122389856f7eSBjoern A. Zeeb 	 * accordingly.
122489856f7eSBjoern A. Zeeb 	 */
122568a3482fSGleb Smirnoff 
12266182fdbdSPeter Wemm 	/*
12276182fdbdSPeter Wemm 	 * Remove routes and flush queues.
12286182fdbdSPeter Wemm 	 */
122902b199f1SMax Laier #ifdef ALTQ
123002b199f1SMax Laier 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
123102b199f1SMax Laier 		altq_disable(&ifp->if_snd);
123202b199f1SMax Laier 	if (ALTQ_IS_ATTACHED(&ifp->if_snd))
123302b199f1SMax Laier 		altq_detach(&ifp->if_snd);
123402b199f1SMax Laier #endif
12356182fdbdSPeter Wemm 
123645778b37SPeter Edwards 	if_purgeaddrs(ifp);
12376182fdbdSPeter Wemm 
1238b1c53bc9SRobert Watson #ifdef INET
1239b1c53bc9SRobert Watson 	in_ifdetach(ifp);
1240b1c53bc9SRobert Watson #endif
1241b1c53bc9SRobert Watson 
124233841545SHajimu UMEMOTO #ifdef INET6
124333841545SHajimu UMEMOTO 	/*
124433841545SHajimu UMEMOTO 	 * Remove all IPv6 kernel structs related to ifp.  This should be done
124533841545SHajimu UMEMOTO 	 * before removing routing entries below, since IPv6 interface direct
124633841545SHajimu UMEMOTO 	 * routes are expected to be removed by the IPv6-specific kernel API.
124733841545SHajimu UMEMOTO 	 * Otherwise, the kernel will detect some inconsistency and bark it.
124833841545SHajimu UMEMOTO 	 */
124933841545SHajimu UMEMOTO 	in6_ifdetach(ifp);
125033841545SHajimu UMEMOTO #endif
1251ec002feeSBruce M Simpson 	if_purgemaddrs(ifp);
1252ec002feeSBruce M Simpson 
1253af371fc6SRoger Pau Monné 	/* Announce that the interface is gone. */
1254af371fc6SRoger Pau Monné 	rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
1255af371fc6SRoger Pau Monné 	EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
1256af371fc6SRoger Pau Monné 	if (IS_DEFAULT_VNET(curvnet))
1257af371fc6SRoger Pau Monné 		devctl_notify("IFNET", ifp->if_xname, "DETACH", NULL);
1258af371fc6SRoger Pau Monné 
1259e0c14af9SMarko Zec 	if (!vmove) {
1260f4247b59SLuigi Rizzo 		/*
1261111c6b61SRobert Watson 		 * Prevent further calls into the device driver via ifnet.
1262111c6b61SRobert Watson 		 */
1263111c6b61SRobert Watson 		if_dead(ifp);
1264111c6b61SRobert Watson 
1265111c6b61SRobert Watson 		/*
1266f4247b59SLuigi Rizzo 		 * Clean up all addresses.
1267f4247b59SLuigi Rizzo 		 */
1268d117fd80SBjoern A. Zeeb 		IF_ADDR_WLOCK(ifp);
1269d7c5a620SMatt Macy 		if (!CK_STAILQ_EMPTY(&ifp->if_addrhead)) {
1270d7c5a620SMatt Macy 			ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
1271d7c5a620SMatt Macy 			CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link);
1272d117fd80SBjoern A. Zeeb 			IF_ADDR_WUNLOCK(ifp);
12731099f828SRobert Watson 			ifa_free(ifa);
1274d117fd80SBjoern A. Zeeb 		} else
1275d117fd80SBjoern A. Zeeb 			IF_ADDR_WUNLOCK(ifp);
1276e0c14af9SMarko Zec 	}
1277212bd869SHajimu UMEMOTO 
12784bdf0b6aSAlexander V. Chernikov 	rt_flushifroutes(ifp);
12797b6edd04SRuslan Ermilov 
1280d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE
128189856f7eSBjoern A. Zeeb finish_vnet_shutdown:
1282d3f6f80fSBjoern A. Zeeb #endif
1283d8c13659SBjoern A. Zeeb 	/*
1284d8c13659SBjoern A. Zeeb 	 * We cannot hold the lock over dom_ifdetach calls as they might
1285d8c13659SBjoern A. Zeeb 	 * sleep, for example trying to drain a callout, thus open up the
1286d8c13659SBjoern A. Zeeb 	 * theoretical race with re-attaching.
1287d8c13659SBjoern A. Zeeb 	 */
1288234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK(ifp);
1289d8c13659SBjoern A. Zeeb 	i = ifp->if_afdata_initialized;
1290d8c13659SBjoern A. Zeeb 	ifp->if_afdata_initialized = 0;
1291d8c13659SBjoern A. Zeeb 	IF_AFDATA_UNLOCK(ifp);
1292d8c13659SBjoern A. Zeeb 	for (dp = domains; i > 0 && dp; dp = dp->dom_next) {
12932d5ad99aSBjoern A. Zeeb 		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) {
129431b1bfe1SHajimu UMEMOTO 			(*dp->dom_ifdetach)(ifp,
129531b1bfe1SHajimu UMEMOTO 			    ifp->if_afdata[dp->dom_family]);
12962d5ad99aSBjoern A. Zeeb 			ifp->if_afdata[dp->dom_family] = NULL;
12972d5ad99aSBjoern A. Zeeb 		}
129831b1bfe1SHajimu UMEMOTO 	}
1299f501e6f1SBjoern A. Zeeb 
1300f501e6f1SBjoern A. Zeeb 	return (0);
13015500d3beSWarner Losh }
13025500d3beSWarner Losh 
1303e0c14af9SMarko Zec #ifdef VIMAGE
1304e0c14af9SMarko Zec /*
1305e0c14af9SMarko Zec  * if_vmove() performs a limited version of if_detach() in current
1306e0c14af9SMarko Zec  * vnet and if_attach()es the ifnet to the vnet specified as 2nd arg.
1307e0c14af9SMarko Zec  * An attempt is made to shrink if_index in current vnet, find an
1308e0c14af9SMarko Zec  * unused if_index in target vnet and calls if_grow() if necessary,
1309e0c14af9SMarko Zec  * and finally find an unused if_xname for the target vnet.
1310e0c14af9SMarko Zec  */
1311c7bab2a7SKyle Evans static int
1312e0c14af9SMarko Zec if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
1313e0c14af9SMarko Zec {
1314c92a456bSHiroki Sato 	struct if_clone *ifc;
13153232273fSBjoern A. Zeeb #ifdef DEV_BPF
131605fc4164SBjoern A. Zeeb 	u_int bif_dlt, bif_hdrlen;
13173232273fSBjoern A. Zeeb #endif
13184f6c66ccSMatt Macy 	void *old;
1319f501e6f1SBjoern A. Zeeb 	int rc;
1320e0c14af9SMarko Zec 
13213232273fSBjoern A. Zeeb #ifdef DEV_BPF
1322e0c14af9SMarko Zec  	/*
132305fc4164SBjoern A. Zeeb 	 * if_detach_internal() will call the eventhandler to notify
132405fc4164SBjoern A. Zeeb 	 * interface departure.  That will detach if_bpf.  We need to
132505fc4164SBjoern A. Zeeb 	 * safe the dlt and hdrlen so we can re-attach it later.
132605fc4164SBjoern A. Zeeb 	 */
132705fc4164SBjoern A. Zeeb 	bpf_get_bp_params(ifp->if_bpf, &bif_dlt, &bif_hdrlen);
13283232273fSBjoern A. Zeeb #endif
132905fc4164SBjoern A. Zeeb 
133005fc4164SBjoern A. Zeeb 	/*
1331e0c14af9SMarko Zec 	 * Detach from current vnet, but preserve LLADDR info, do not
1332e0c14af9SMarko Zec 	 * mark as dead etc. so that the ifnet can be reattached later.
1333f501e6f1SBjoern A. Zeeb 	 * If we cannot find it, we lost the race to someone else.
1334e0c14af9SMarko Zec 	 */
1335f501e6f1SBjoern A. Zeeb 	rc = if_detach_internal(ifp, 1, &ifc);
1336f501e6f1SBjoern A. Zeeb 	if (rc != 0)
1337c7bab2a7SKyle Evans 		return (rc);
1338e0c14af9SMarko Zec 
1339e0c14af9SMarko Zec 	/*
134077dfcdc4SRobert Watson 	 * Unlink the ifnet from ifindex_table[] in current vnet, and shrink
134177dfcdc4SRobert Watson 	 * the if_index for that vnet if possible.
134277dfcdc4SRobert Watson 	 *
134377dfcdc4SRobert Watson 	 * NOTE: IFNET_WLOCK/IFNET_WUNLOCK() are assumed to be unvirtualized,
134477dfcdc4SRobert Watson 	 * or we'd lock on one vnet and unlock on another.
1345e0c14af9SMarko Zec 	 */
1346e0c14af9SMarko Zec 	IFNET_WLOCK();
1347ed2dabfcSRobert Watson 	ifindex_free_locked(ifp->if_index);
1348d3c351c5SMarko Zec 	IFNET_WUNLOCK();
1349d3c351c5SMarko Zec 
1350d3c351c5SMarko Zec 	/*
1351d3c351c5SMarko Zec 	 * Perform interface-specific reassignment tasks, if provided by
1352d3c351c5SMarko Zec 	 * the driver.
1353d3c351c5SMarko Zec 	 */
1354d3c351c5SMarko Zec 	if (ifp->if_reassign != NULL)
1355d3c351c5SMarko Zec 		ifp->if_reassign(ifp, new_vnet, NULL);
1356e0c14af9SMarko Zec 
1357e0c14af9SMarko Zec 	/*
1358e0c14af9SMarko Zec 	 * Switch to the context of the target vnet.
1359e0c14af9SMarko Zec 	 */
1360e0c14af9SMarko Zec 	CURVNET_SET_QUIET(new_vnet);
13614f6c66ccSMatt Macy  restart:
1362d3c351c5SMarko Zec 	IFNET_WLOCK();
13634f6c66ccSMatt Macy 	ifp->if_index = ifindex_alloc(&old);
13644f6c66ccSMatt Macy 	if (__predict_false(ifp->if_index == USHRT_MAX)) {
13654f6c66ccSMatt Macy 		IFNET_WUNLOCK();
13664f6c66ccSMatt Macy 		epoch_wait_preempt(net_epoch_preempt);
13674f6c66ccSMatt Macy 		free(old, M_IFNET);
13684f6c66ccSMatt Macy 		goto restart;
13694f6c66ccSMatt Macy 	}
13704f6c66ccSMatt Macy 	ifnet_setbyindex(ifp->if_index, ifp);
1371e0c14af9SMarko Zec 	IFNET_WUNLOCK();
1372e0c14af9SMarko Zec 
1373c92a456bSHiroki Sato 	if_attach_internal(ifp, 1, ifc);
1374e0c14af9SMarko Zec 
13753232273fSBjoern A. Zeeb #ifdef DEV_BPF
137605fc4164SBjoern A. Zeeb 	if (ifp->if_bpf == NULL)
137705fc4164SBjoern A. Zeeb 		bpfattach(ifp, bif_dlt, bif_hdrlen);
13783232273fSBjoern A. Zeeb #endif
137905fc4164SBjoern A. Zeeb 
1380e0c14af9SMarko Zec 	CURVNET_RESTORE();
1381c7bab2a7SKyle Evans 	return (0);
1382e0c14af9SMarko Zec }
1383be31e5e7SBjoern A. Zeeb 
1384be31e5e7SBjoern A. Zeeb /*
1385be31e5e7SBjoern A. Zeeb  * Move an ifnet to or from another child prison/vnet, specified by the jail id.
1386be31e5e7SBjoern A. Zeeb  */
1387be31e5e7SBjoern A. Zeeb static int
1388be31e5e7SBjoern A. Zeeb if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
1389be31e5e7SBjoern A. Zeeb {
1390be31e5e7SBjoern A. Zeeb 	struct prison *pr;
1391be31e5e7SBjoern A. Zeeb 	struct ifnet *difp;
1392c7bab2a7SKyle Evans 	int error;
1393a779388fSKristof Provost 	bool found;
139410108cb6SBjoern A. Zeeb 	bool shutdown;
1395be31e5e7SBjoern A. Zeeb 
1396be31e5e7SBjoern A. Zeeb 	/* Try to find the prison within our visibility. */
1397be31e5e7SBjoern A. Zeeb 	sx_slock(&allprison_lock);
1398be31e5e7SBjoern A. Zeeb 	pr = prison_find_child(td->td_ucred->cr_prison, jid);
1399be31e5e7SBjoern A. Zeeb 	sx_sunlock(&allprison_lock);
1400be31e5e7SBjoern A. Zeeb 	if (pr == NULL)
1401be31e5e7SBjoern A. Zeeb 		return (ENXIO);
1402be31e5e7SBjoern A. Zeeb 	prison_hold_locked(pr);
1403be31e5e7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
1404be31e5e7SBjoern A. Zeeb 
1405be31e5e7SBjoern A. Zeeb 	/* Do not try to move the iface from and to the same prison. */
1406be31e5e7SBjoern A. Zeeb 	if (pr->pr_vnet == ifp->if_vnet) {
1407be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1408be31e5e7SBjoern A. Zeeb 		return (EEXIST);
1409be31e5e7SBjoern A. Zeeb 	}
1410be31e5e7SBjoern A. Zeeb 
1411be31e5e7SBjoern A. Zeeb 	/* Make sure the named iface does not exists in the dst. prison/vnet. */
1412be31e5e7SBjoern A. Zeeb 	/* XXX Lock interfaces to avoid races. */
14139abb4862SMarko Zec 	CURVNET_SET_QUIET(pr->pr_vnet);
1414be31e5e7SBjoern A. Zeeb 	difp = ifunit(ifname);
1415be31e5e7SBjoern A. Zeeb 	if (difp != NULL) {
141689856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
1417be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1418be31e5e7SBjoern A. Zeeb 		return (EEXIST);
1419be31e5e7SBjoern A. Zeeb 	}
1420be31e5e7SBjoern A. Zeeb 
142189856f7eSBjoern A. Zeeb 	/* Make sure the VNET is stable. */
142210108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet);
142310108cb6SBjoern A. Zeeb 	if (shutdown) {
142489856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
142589856f7eSBjoern A. Zeeb 		prison_free(pr);
142689856f7eSBjoern A. Zeeb 		return (EBUSY);
142789856f7eSBjoern A. Zeeb 	}
142889856f7eSBjoern A. Zeeb 	CURVNET_RESTORE();
142989856f7eSBjoern A. Zeeb 
1430a779388fSKristof Provost 	found = if_unlink_ifnet(ifp, true);
1431a779388fSKristof Provost 	MPASS(found);
1432a779388fSKristof Provost 
1433be31e5e7SBjoern A. Zeeb 	/* Move the interface into the child jail/vnet. */
1434c7bab2a7SKyle Evans 	error = if_vmove(ifp, pr->pr_vnet);
1435be31e5e7SBjoern A. Zeeb 
1436c7bab2a7SKyle Evans 	/* Report the new if_xname back to the userland on success. */
1437c7bab2a7SKyle Evans 	if (error == 0)
1438be31e5e7SBjoern A. Zeeb 		sprintf(ifname, "%s", ifp->if_xname);
1439be31e5e7SBjoern A. Zeeb 
1440be31e5e7SBjoern A. Zeeb 	prison_free(pr);
1441c7bab2a7SKyle Evans 	return (error);
1442be31e5e7SBjoern A. Zeeb }
1443be31e5e7SBjoern A. Zeeb 
1444be31e5e7SBjoern A. Zeeb static int
1445be31e5e7SBjoern A. Zeeb if_vmove_reclaim(struct thread *td, char *ifname, int jid)
1446be31e5e7SBjoern A. Zeeb {
1447be31e5e7SBjoern A. Zeeb 	struct prison *pr;
1448be31e5e7SBjoern A. Zeeb 	struct vnet *vnet_dst;
1449be31e5e7SBjoern A. Zeeb 	struct ifnet *ifp;
1450a779388fSKristof Provost 	int error, found;
145110108cb6SBjoern A. Zeeb  	bool shutdown;
1452be31e5e7SBjoern A. Zeeb 
1453be31e5e7SBjoern A. Zeeb 	/* Try to find the prison within our visibility. */
1454be31e5e7SBjoern A. Zeeb 	sx_slock(&allprison_lock);
1455be31e5e7SBjoern A. Zeeb 	pr = prison_find_child(td->td_ucred->cr_prison, jid);
1456be31e5e7SBjoern A. Zeeb 	sx_sunlock(&allprison_lock);
1457be31e5e7SBjoern A. Zeeb 	if (pr == NULL)
1458be31e5e7SBjoern A. Zeeb 		return (ENXIO);
1459be31e5e7SBjoern A. Zeeb 	prison_hold_locked(pr);
1460be31e5e7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
1461be31e5e7SBjoern A. Zeeb 
1462be31e5e7SBjoern A. Zeeb 	/* Make sure the named iface exists in the source prison/vnet. */
1463be31e5e7SBjoern A. Zeeb 	CURVNET_SET(pr->pr_vnet);
1464be31e5e7SBjoern A. Zeeb 	ifp = ifunit(ifname);		/* XXX Lock to avoid races. */
1465be31e5e7SBjoern A. Zeeb 	if (ifp == NULL) {
1466be31e5e7SBjoern A. Zeeb 		CURVNET_RESTORE();
1467be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1468be31e5e7SBjoern A. Zeeb 		return (ENXIO);
1469be31e5e7SBjoern A. Zeeb 	}
1470be31e5e7SBjoern A. Zeeb 
1471be31e5e7SBjoern A. Zeeb 	/* Do not try to move the iface from and to the same prison. */
1472be31e5e7SBjoern A. Zeeb 	vnet_dst = TD_TO_VNET(td);
1473be31e5e7SBjoern A. Zeeb 	if (vnet_dst == ifp->if_vnet) {
1474be31e5e7SBjoern A. Zeeb 		CURVNET_RESTORE();
1475be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1476be31e5e7SBjoern A. Zeeb 		return (EEXIST);
1477be31e5e7SBjoern A. Zeeb 	}
1478be31e5e7SBjoern A. Zeeb 
147989856f7eSBjoern A. Zeeb 	/* Make sure the VNET is stable. */
148010108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet);
148110108cb6SBjoern A. Zeeb 	if (shutdown) {
148289856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
148389856f7eSBjoern A. Zeeb 		prison_free(pr);
148489856f7eSBjoern A. Zeeb 		return (EBUSY);
148589856f7eSBjoern A. Zeeb 	}
148689856f7eSBjoern A. Zeeb 
1487be31e5e7SBjoern A. Zeeb 	/* Get interface back from child jail/vnet. */
1488a779388fSKristof Provost 	found = if_unlink_ifnet(ifp, true);
1489a779388fSKristof Provost 	MPASS(found);
1490c7bab2a7SKyle Evans 	error = if_vmove(ifp, vnet_dst);
1491be31e5e7SBjoern A. Zeeb 	CURVNET_RESTORE();
1492be31e5e7SBjoern A. Zeeb 
1493c7bab2a7SKyle Evans 	/* Report the new if_xname back to the userland on success. */
1494c7bab2a7SKyle Evans 	if (error == 0)
1495be31e5e7SBjoern A. Zeeb 		sprintf(ifname, "%s", ifp->if_xname);
1496be31e5e7SBjoern A. Zeeb 
1497be31e5e7SBjoern A. Zeeb 	prison_free(pr);
1498c7bab2a7SKyle Evans 	return (error);
1499be31e5e7SBjoern A. Zeeb }
1500e0c14af9SMarko Zec #endif /* VIMAGE */
1501e0c14af9SMarko Zec 
15025500d3beSWarner Losh /*
15030dad3f0eSMax Laier  * Add a group to an interface
15040dad3f0eSMax Laier  */
15050dad3f0eSMax Laier int
15060dad3f0eSMax Laier if_addgroup(struct ifnet *ifp, const char *groupname)
15070dad3f0eSMax Laier {
15080dad3f0eSMax Laier 	struct ifg_list		*ifgl;
15090dad3f0eSMax Laier 	struct ifg_group	*ifg = NULL;
15100dad3f0eSMax Laier 	struct ifg_member	*ifgm;
1511d6d3f01eSGleb Smirnoff 	int 			 new = 0;
15120dad3f0eSMax Laier 
15130dad3f0eSMax Laier 	if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' &&
15140dad3f0eSMax Laier 	    groupname[strlen(groupname) - 1] <= '9')
15150dad3f0eSMax Laier 		return (EINVAL);
15160dad3f0eSMax Laier 
15170dad3f0eSMax Laier 	IFNET_WLOCK();
15184f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
15190dad3f0eSMax Laier 		if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) {
15200dad3f0eSMax Laier 			IFNET_WUNLOCK();
15210dad3f0eSMax Laier 			return (EEXIST);
15220dad3f0eSMax Laier 		}
15230dad3f0eSMax Laier 
15243f197b13SMark Johnston 	if ((ifgl = malloc(sizeof(*ifgl), M_TEMP, M_NOWAIT)) == NULL) {
15250dad3f0eSMax Laier 	    	IFNET_WUNLOCK();
15260dad3f0eSMax Laier 		return (ENOMEM);
15270dad3f0eSMax Laier 	}
15280dad3f0eSMax Laier 
15293f197b13SMark Johnston 	if ((ifgm = malloc(sizeof(*ifgm), M_TEMP, M_NOWAIT)) == NULL) {
15300dad3f0eSMax Laier 		free(ifgl, M_TEMP);
15310dad3f0eSMax Laier 		IFNET_WUNLOCK();
15320dad3f0eSMax Laier 		return (ENOMEM);
15330dad3f0eSMax Laier 	}
15340dad3f0eSMax Laier 
15354f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
15360dad3f0eSMax Laier 		if (!strcmp(ifg->ifg_group, groupname))
15370dad3f0eSMax Laier 			break;
15380dad3f0eSMax Laier 
15390dad3f0eSMax Laier 	if (ifg == NULL) {
15403f197b13SMark Johnston 		if ((ifg = malloc(sizeof(*ifg), M_TEMP, M_NOWAIT)) == NULL) {
15410dad3f0eSMax Laier 			free(ifgl, M_TEMP);
15420dad3f0eSMax Laier 			free(ifgm, M_TEMP);
15430dad3f0eSMax Laier 			IFNET_WUNLOCK();
15440dad3f0eSMax Laier 			return (ENOMEM);
15450dad3f0eSMax Laier 		}
15460dad3f0eSMax Laier 		strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
15470dad3f0eSMax Laier 		ifg->ifg_refcnt = 0;
15484f6c66ccSMatt Macy 		CK_STAILQ_INIT(&ifg->ifg_members);
15494f6c66ccSMatt Macy 		CK_STAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next);
1550d6d3f01eSGleb Smirnoff 		new = 1;
15510dad3f0eSMax Laier 	}
15520dad3f0eSMax Laier 
15530dad3f0eSMax Laier 	ifg->ifg_refcnt++;
15540dad3f0eSMax Laier 	ifgl->ifgl_group = ifg;
15550dad3f0eSMax Laier 	ifgm->ifgm_ifp = ifp;
15560dad3f0eSMax Laier 
1557137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
15584f6c66ccSMatt Macy 	CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
15594f6c66ccSMatt Macy 	CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
1560137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
15610dad3f0eSMax Laier 
15620dad3f0eSMax Laier 	IFNET_WUNLOCK();
15630dad3f0eSMax Laier 
1564d6d3f01eSGleb Smirnoff 	if (new)
1565d6d3f01eSGleb Smirnoff 		EVENTHANDLER_INVOKE(group_attach_event, ifg);
15660dad3f0eSMax Laier 	EVENTHANDLER_INVOKE(group_change_event, groupname);
15670dad3f0eSMax Laier 
15680dad3f0eSMax Laier 	return (0);
15690dad3f0eSMax Laier }
15700dad3f0eSMax Laier 
15710dad3f0eSMax Laier /*
15723f197b13SMark Johnston  * Helper function to remove a group out of an interface.  Expects the global
15733f197b13SMark Johnston  * ifnet lock to be write-locked, and drops it before returning.
15740dad3f0eSMax Laier  */
15753f197b13SMark Johnston static void
15763f197b13SMark Johnston _if_delgroup_locked(struct ifnet *ifp, struct ifg_list *ifgl,
15773f197b13SMark Johnston     const char *groupname)
15780dad3f0eSMax Laier {
15790dad3f0eSMax Laier 	struct ifg_member *ifgm;
15803f197b13SMark Johnston 	bool freeifgl;
15810dad3f0eSMax Laier 
15823f197b13SMark Johnston 	IFNET_WLOCK_ASSERT();
15830dad3f0eSMax Laier 
1584137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
15854f6c66ccSMatt Macy 	CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next);
1586137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
15870dad3f0eSMax Laier 
15883f197b13SMark Johnston 	CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) {
15893f197b13SMark Johnston 		if (ifgm->ifgm_ifp == ifp) {
15903f197b13SMark Johnston 			CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm,
15913f197b13SMark Johnston 			    ifg_member, ifgm_next);
15920dad3f0eSMax Laier 			break;
15933f197b13SMark Johnston 		}
15943f197b13SMark Johnston 	}
15950dad3f0eSMax Laier 
15960dad3f0eSMax Laier 	if (--ifgl->ifgl_group->ifg_refcnt == 0) {
15973f197b13SMark Johnston 		CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group,
15983f197b13SMark Johnston 		    ifg_next);
15993f197b13SMark Johnston 		freeifgl = true;
16003f197b13SMark Johnston 	} else {
16013f197b13SMark Johnston 		freeifgl = false;
16024f6c66ccSMatt Macy 	}
16030dad3f0eSMax Laier 	IFNET_WUNLOCK();
16040dad3f0eSMax Laier 
16054f6c66ccSMatt Macy 	epoch_wait_preempt(net_epoch_preempt);
16064f6c66ccSMatt Macy 	if (freeifgl) {
16074f6c66ccSMatt Macy 		EVENTHANDLER_INVOKE(group_detach_event, ifgl->ifgl_group);
16084f6c66ccSMatt Macy 		free(ifgl->ifgl_group, M_TEMP);
16094f6c66ccSMatt Macy 	}
16104f6c66ccSMatt Macy 	free(ifgm, M_TEMP);
16110dad3f0eSMax Laier 	free(ifgl, M_TEMP);
16120dad3f0eSMax Laier 
16130dad3f0eSMax Laier 	EVENTHANDLER_INVOKE(group_change_event, groupname);
16143f197b13SMark Johnston }
16153f197b13SMark Johnston 
16163f197b13SMark Johnston /*
16173f197b13SMark Johnston  * Remove a group from an interface
16183f197b13SMark Johnston  */
16193f197b13SMark Johnston int
16203f197b13SMark Johnston if_delgroup(struct ifnet *ifp, const char *groupname)
16213f197b13SMark Johnston {
16223f197b13SMark Johnston 	struct ifg_list *ifgl;
16233f197b13SMark Johnston 
16243f197b13SMark Johnston 	IFNET_WLOCK();
16253f197b13SMark Johnston 	CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
16263f197b13SMark Johnston 		if (strcmp(ifgl->ifgl_group->ifg_group, groupname) == 0)
16273f197b13SMark Johnston 			break;
16283f197b13SMark Johnston 	if (ifgl == NULL) {
16293f197b13SMark Johnston 		IFNET_WUNLOCK();
16303f197b13SMark Johnston 		return (ENOENT);
16313f197b13SMark Johnston 	}
16323f197b13SMark Johnston 
16333f197b13SMark Johnston 	_if_delgroup_locked(ifp, ifgl, groupname);
16340dad3f0eSMax Laier 
16350dad3f0eSMax Laier 	return (0);
16360dad3f0eSMax Laier }
16370dad3f0eSMax Laier 
16380dad3f0eSMax Laier /*
16398623f9fdSMax Laier  * Remove an interface from all groups
16408623f9fdSMax Laier  */
16418623f9fdSMax Laier static void
16428623f9fdSMax Laier if_delgroups(struct ifnet *ifp)
16438623f9fdSMax Laier {
16448623f9fdSMax Laier 	struct ifg_list *ifgl;
16458623f9fdSMax Laier 	char groupname[IFNAMSIZ];
16468623f9fdSMax Laier 
16478623f9fdSMax Laier 	IFNET_WLOCK();
16483f197b13SMark Johnston 	while ((ifgl = CK_STAILQ_FIRST(&ifp->if_groups)) != NULL) {
16498623f9fdSMax Laier 		strlcpy(groupname, ifgl->ifgl_group->ifg_group, IFNAMSIZ);
16503f197b13SMark Johnston 		_if_delgroup_locked(ifp, ifgl, groupname);
16518623f9fdSMax Laier 		IFNET_WLOCK();
16528623f9fdSMax Laier 	}
16538623f9fdSMax Laier 	IFNET_WUNLOCK();
16548623f9fdSMax Laier }
16558623f9fdSMax Laier 
1656756181b8SBrooks Davis static char *
1657756181b8SBrooks Davis ifgr_group_get(void *ifgrp)
1658756181b8SBrooks Davis {
1659756181b8SBrooks Davis 	union ifgroupreq_union *ifgrup;
1660756181b8SBrooks Davis 
1661756181b8SBrooks Davis 	ifgrup = ifgrp;
1662756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32
1663756181b8SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
1664756181b8SBrooks Davis 		return (&ifgrup->ifgr32.ifgr_ifgru.ifgru_group[0]);
1665756181b8SBrooks Davis #endif
1666756181b8SBrooks Davis 	return (&ifgrup->ifgr.ifgr_ifgru.ifgru_group[0]);
1667756181b8SBrooks Davis }
1668756181b8SBrooks Davis 
1669756181b8SBrooks Davis static struct ifg_req *
1670756181b8SBrooks Davis ifgr_groups_get(void *ifgrp)
1671756181b8SBrooks Davis {
1672756181b8SBrooks Davis 	union ifgroupreq_union *ifgrup;
1673756181b8SBrooks Davis 
1674756181b8SBrooks Davis 	ifgrup = ifgrp;
1675756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32
1676756181b8SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
1677756181b8SBrooks Davis 		return ((struct ifg_req *)(uintptr_t)
1678756181b8SBrooks Davis 		    ifgrup->ifgr32.ifgr_ifgru.ifgru_groups);
1679756181b8SBrooks Davis #endif
1680756181b8SBrooks Davis 	return (ifgrup->ifgr.ifgr_ifgru.ifgru_groups);
1681756181b8SBrooks Davis }
1682756181b8SBrooks Davis 
16838623f9fdSMax Laier /*
1684756181b8SBrooks Davis  * Stores all groups from an interface in memory pointed to by ifgr.
16850dad3f0eSMax Laier  */
16860dad3f0eSMax Laier static int
1687756181b8SBrooks Davis if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp)
16880dad3f0eSMax Laier {
16890dad3f0eSMax Laier 	int			 len, error;
16900dad3f0eSMax Laier 	struct ifg_list		*ifgl;
16910dad3f0eSMax Laier 	struct ifg_req		 ifgrq, *ifgp;
16920dad3f0eSMax Laier 
1693b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
1694b8a6e03fSGleb Smirnoff 
16950dad3f0eSMax Laier 	if (ifgr->ifgr_len == 0) {
16964f6c66ccSMatt Macy 		CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
16970dad3f0eSMax Laier 			ifgr->ifgr_len += sizeof(struct ifg_req);
16980dad3f0eSMax Laier 		return (0);
16990dad3f0eSMax Laier 	}
17000dad3f0eSMax Laier 
17010dad3f0eSMax Laier 	len = ifgr->ifgr_len;
1702756181b8SBrooks Davis 	ifgp = ifgr_groups_get(ifgr);
17030dad3f0eSMax Laier 	/* XXX: wire */
17044f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
1705b8a6e03fSGleb Smirnoff 		if (len < sizeof(ifgrq))
17060dad3f0eSMax Laier 			return (EINVAL);
17070dad3f0eSMax Laier 		bzero(&ifgrq, sizeof ifgrq);
17080dad3f0eSMax Laier 		strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
17090dad3f0eSMax Laier 		    sizeof(ifgrq.ifgrq_group));
1710b8a6e03fSGleb Smirnoff 		if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req))))
17110dad3f0eSMax Laier 			return (error);
17120dad3f0eSMax Laier 		len -= sizeof(ifgrq);
17130dad3f0eSMax Laier 		ifgp++;
17140dad3f0eSMax Laier 	}
17150dad3f0eSMax Laier 
17160dad3f0eSMax Laier 	return (0);
17170dad3f0eSMax Laier }
17180dad3f0eSMax Laier 
17190dad3f0eSMax Laier /*
1720756181b8SBrooks Davis  * Stores all members of a group in memory pointed to by igfr
17210dad3f0eSMax Laier  */
17220dad3f0eSMax Laier static int
1723756181b8SBrooks Davis if_getgroupmembers(struct ifgroupreq *ifgr)
17240dad3f0eSMax Laier {
17250dad3f0eSMax Laier 	struct ifg_group	*ifg;
17260dad3f0eSMax Laier 	struct ifg_member	*ifgm;
17270dad3f0eSMax Laier 	struct ifg_req		 ifgrq, *ifgp;
17280dad3f0eSMax Laier 	int			 len, error;
17290dad3f0eSMax Laier 
17300dad3f0eSMax Laier 	IFNET_RLOCK();
17314f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
17323f197b13SMark Johnston 		if (strcmp(ifg->ifg_group, ifgr->ifgr_name) == 0)
17330dad3f0eSMax Laier 			break;
17340dad3f0eSMax Laier 	if (ifg == NULL) {
17350dad3f0eSMax Laier 		IFNET_RUNLOCK();
17360dad3f0eSMax Laier 		return (ENOENT);
17370dad3f0eSMax Laier 	}
17380dad3f0eSMax Laier 
17390dad3f0eSMax Laier 	if (ifgr->ifgr_len == 0) {
17404f6c66ccSMatt Macy 		CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
17410dad3f0eSMax Laier 			ifgr->ifgr_len += sizeof(ifgrq);
17420dad3f0eSMax Laier 		IFNET_RUNLOCK();
17430dad3f0eSMax Laier 		return (0);
17440dad3f0eSMax Laier 	}
17450dad3f0eSMax Laier 
17460dad3f0eSMax Laier 	len = ifgr->ifgr_len;
1747756181b8SBrooks Davis 	ifgp = ifgr_groups_get(ifgr);
17484f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
17490dad3f0eSMax Laier 		if (len < sizeof(ifgrq)) {
17500dad3f0eSMax Laier 			IFNET_RUNLOCK();
17510dad3f0eSMax Laier 			return (EINVAL);
17520dad3f0eSMax Laier 		}
17530dad3f0eSMax Laier 		bzero(&ifgrq, sizeof ifgrq);
17540dad3f0eSMax Laier 		strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname,
17550dad3f0eSMax Laier 		    sizeof(ifgrq.ifgrq_member));
17560dad3f0eSMax Laier 		if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) {
17570dad3f0eSMax Laier 			IFNET_RUNLOCK();
17580dad3f0eSMax Laier 			return (error);
17590dad3f0eSMax Laier 		}
17600dad3f0eSMax Laier 		len -= sizeof(ifgrq);
17610dad3f0eSMax Laier 		ifgp++;
17620dad3f0eSMax Laier 	}
17630dad3f0eSMax Laier 	IFNET_RUNLOCK();
17640dad3f0eSMax Laier 
17650dad3f0eSMax Laier 	return (0);
17660dad3f0eSMax Laier }
17670dad3f0eSMax Laier 
17680dad3f0eSMax Laier /*
1769112f50ffSGleb Smirnoff  * Return counter values from counter(9)s stored in ifnet.
1770e6485f73SGleb Smirnoff  */
1771e6485f73SGleb Smirnoff uint64_t
17721b7fb1d9SGleb Smirnoff if_get_counter_default(struct ifnet *ifp, ift_counter cnt)
1773e6485f73SGleb Smirnoff {
1774e6485f73SGleb Smirnoff 
1775112f50ffSGleb Smirnoff 	KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt));
1776112f50ffSGleb Smirnoff 
1777112f50ffSGleb Smirnoff 	return (counter_u64_fetch(ifp->if_counters[cnt]));
1778e6485f73SGleb Smirnoff }
1779e6485f73SGleb Smirnoff 
1780e6485f73SGleb Smirnoff /*
17810b7b006cSGleb Smirnoff  * Increase an ifnet counter. Usually used for counters shared
17820b7b006cSGleb Smirnoff  * between the stack and a driver, but function supports them all.
17830b7b006cSGleb Smirnoff  */
17840b7b006cSGleb Smirnoff void
17851b7fb1d9SGleb Smirnoff if_inc_counter(struct ifnet *ifp, ift_counter cnt, int64_t inc)
17860b7b006cSGleb Smirnoff {
17870b7b006cSGleb Smirnoff 
1788112f50ffSGleb Smirnoff 	KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt));
1789112f50ffSGleb Smirnoff 
1790112f50ffSGleb Smirnoff 	counter_u64_add(ifp->if_counters[cnt], inc);
17910b7b006cSGleb Smirnoff }
17920b7b006cSGleb Smirnoff 
17930b7b006cSGleb Smirnoff /*
1794e6485f73SGleb Smirnoff  * Copy data from ifnet to userland API structure if_data.
1795e6485f73SGleb Smirnoff  */
1796e6485f73SGleb Smirnoff void
1797e6485f73SGleb Smirnoff if_data_copy(struct ifnet *ifp, struct if_data *ifd)
1798e6485f73SGleb Smirnoff {
1799e6485f73SGleb Smirnoff 
1800e6485f73SGleb Smirnoff 	ifd->ifi_type = ifp->if_type;
1801e6485f73SGleb Smirnoff 	ifd->ifi_physical = 0;
1802e6485f73SGleb Smirnoff 	ifd->ifi_addrlen = ifp->if_addrlen;
1803e6485f73SGleb Smirnoff 	ifd->ifi_hdrlen = ifp->if_hdrlen;
1804e6485f73SGleb Smirnoff 	ifd->ifi_link_state = ifp->if_link_state;
1805e6485f73SGleb Smirnoff 	ifd->ifi_vhid = 0;
1806e6485f73SGleb Smirnoff 	ifd->ifi_datalen = sizeof(struct if_data);
1807e6485f73SGleb Smirnoff 	ifd->ifi_mtu = ifp->if_mtu;
1808e6485f73SGleb Smirnoff 	ifd->ifi_metric = ifp->if_metric;
1809e6485f73SGleb Smirnoff 	ifd->ifi_baudrate = ifp->if_baudrate;
1810e6485f73SGleb Smirnoff 	ifd->ifi_hwassist = ifp->if_hwassist;
1811e6485f73SGleb Smirnoff 	ifd->ifi_epoch = ifp->if_epoch;
1812e6485f73SGleb Smirnoff 	ifd->ifi_lastchange = ifp->if_lastchange;
1813e6485f73SGleb Smirnoff 
1814e6485f73SGleb Smirnoff 	ifd->ifi_ipackets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS);
1815e6485f73SGleb Smirnoff 	ifd->ifi_ierrors = ifp->if_get_counter(ifp, IFCOUNTER_IERRORS);
1816e6485f73SGleb Smirnoff 	ifd->ifi_opackets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS);
1817e6485f73SGleb Smirnoff 	ifd->ifi_oerrors = ifp->if_get_counter(ifp, IFCOUNTER_OERRORS);
1818e6485f73SGleb Smirnoff 	ifd->ifi_collisions = ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS);
1819e6485f73SGleb Smirnoff 	ifd->ifi_ibytes = ifp->if_get_counter(ifp, IFCOUNTER_IBYTES);
1820e6485f73SGleb Smirnoff 	ifd->ifi_obytes = ifp->if_get_counter(ifp, IFCOUNTER_OBYTES);
1821e6485f73SGleb Smirnoff 	ifd->ifi_imcasts = ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS);
1822e6485f73SGleb Smirnoff 	ifd->ifi_omcasts = ifp->if_get_counter(ifp, IFCOUNTER_OMCASTS);
1823e6485f73SGleb Smirnoff 	ifd->ifi_iqdrops = ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS);
1824e6485f73SGleb Smirnoff 	ifd->ifi_oqdrops = ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS);
1825e6485f73SGleb Smirnoff 	ifd->ifi_noproto = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO);
1826e6485f73SGleb Smirnoff }
1827e6485f73SGleb Smirnoff 
1828e6485f73SGleb Smirnoff /*
1829e8aa8bddSGleb Smirnoff  * Initialization, destruction and refcounting functions for ifaddrs.
18301099f828SRobert Watson  */
183146758960SGleb Smirnoff struct ifaddr *
183246758960SGleb Smirnoff ifa_alloc(size_t size, int flags)
18331099f828SRobert Watson {
183446758960SGleb Smirnoff 	struct ifaddr *ifa;
183546758960SGleb Smirnoff 
183646758960SGleb Smirnoff 	KASSERT(size >= sizeof(struct ifaddr),
183746758960SGleb Smirnoff 	    ("%s: invalid size %zu", __func__, size));
183846758960SGleb Smirnoff 
183946758960SGleb Smirnoff 	ifa = malloc(size, M_IFADDR, M_ZERO | flags);
184046758960SGleb Smirnoff 	if (ifa == NULL)
184146758960SGleb Smirnoff 		return (NULL);
18421099f828SRobert Watson 
18437caf4ab7SGleb Smirnoff 	if ((ifa->ifa_opackets = counter_u64_alloc(flags)) == NULL)
18447caf4ab7SGleb Smirnoff 		goto fail;
18457caf4ab7SGleb Smirnoff 	if ((ifa->ifa_ipackets = counter_u64_alloc(flags)) == NULL)
18467caf4ab7SGleb Smirnoff 		goto fail;
18477caf4ab7SGleb Smirnoff 	if ((ifa->ifa_obytes = counter_u64_alloc(flags)) == NULL)
18487caf4ab7SGleb Smirnoff 		goto fail;
18497caf4ab7SGleb Smirnoff 	if ((ifa->ifa_ibytes = counter_u64_alloc(flags)) == NULL)
18507caf4ab7SGleb Smirnoff 		goto fail;
18517caf4ab7SGleb Smirnoff 
18521099f828SRobert Watson 	refcount_init(&ifa->ifa_refcnt, 1);
185346758960SGleb Smirnoff 
185446758960SGleb Smirnoff 	return (ifa);
18557caf4ab7SGleb Smirnoff 
18567caf4ab7SGleb Smirnoff fail:
18577caf4ab7SGleb Smirnoff 	/* free(NULL) is okay */
18587caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_opackets);
18597caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ipackets);
18607caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_obytes);
18617caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ibytes);
18627caf4ab7SGleb Smirnoff 	free(ifa, M_IFADDR);
18637caf4ab7SGleb Smirnoff 
18647caf4ab7SGleb Smirnoff 	return (NULL);
18651099f828SRobert Watson }
18661099f828SRobert Watson 
18671099f828SRobert Watson void
18681099f828SRobert Watson ifa_ref(struct ifaddr *ifa)
18691099f828SRobert Watson {
1870600eade2SAlexander V. Chernikov 	u_int old;
18711099f828SRobert Watson 
1872600eade2SAlexander V. Chernikov 	old = refcount_acquire(&ifa->ifa_refcnt);
1873600eade2SAlexander V. Chernikov 	KASSERT(old > 0, ("%s: ifa %p has 0 refs", __func__, ifa));
1874600eade2SAlexander V. Chernikov }
1875600eade2SAlexander V. Chernikov 
1876600eade2SAlexander V. Chernikov int
1877600eade2SAlexander V. Chernikov ifa_try_ref(struct ifaddr *ifa)
1878600eade2SAlexander V. Chernikov {
1879600eade2SAlexander V. Chernikov 
1880600eade2SAlexander V. Chernikov 	NET_EPOCH_ASSERT();
1881600eade2SAlexander V. Chernikov 	return (refcount_acquire_if_not_zero(&ifa->ifa_refcnt));
18821099f828SRobert Watson }
18831099f828SRobert Watson 
1884d7c5a620SMatt Macy static void
1885d7c5a620SMatt Macy ifa_destroy(epoch_context_t ctx)
18861099f828SRobert Watson {
1887d7c5a620SMatt Macy 	struct ifaddr *ifa;
18881099f828SRobert Watson 
1889d7c5a620SMatt Macy 	ifa = __containerof(ctx, struct ifaddr, ifa_epoch_ctx);
18907caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_opackets);
18917caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ipackets);
18927caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_obytes);
18937caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ibytes);
18941099f828SRobert Watson 	free(ifa, M_IFADDR);
18951099f828SRobert Watson }
1896d7c5a620SMatt Macy 
1897d7c5a620SMatt Macy void
1898d7c5a620SMatt Macy ifa_free(struct ifaddr *ifa)
1899d7c5a620SMatt Macy {
1900d7c5a620SMatt Macy 
1901d7c5a620SMatt Macy 	if (refcount_release(&ifa->ifa_refcnt))
19022a4bd982SGleb Smirnoff 		NET_EPOCH_CALL(ifa_destroy, &ifa->ifa_epoch_ctx);
19031099f828SRobert Watson }
19041099f828SRobert Watson 
19051099f828SRobert Watson /*
190640d8a302SBruce M Simpson  * XXX: Because sockaddr_dl has deeper structure than the sockaddr
190740d8a302SBruce M Simpson  * structs used to represent other address families, it is necessary
190840d8a302SBruce M Simpson  * to perform a different comparison.
190940d8a302SBruce M Simpson  */
191040d8a302SBruce M Simpson 
191140d8a302SBruce M Simpson #define	sa_dl_equal(a1, a2)	\
1912441f9243SAlexander V. Chernikov 	((((const struct sockaddr_dl *)(a1))->sdl_len ==		\
1913441f9243SAlexander V. Chernikov 	 ((const struct sockaddr_dl *)(a2))->sdl_len) &&		\
1914441f9243SAlexander V. Chernikov 	 (bcmp(CLLADDR((const struct sockaddr_dl *)(a1)),		\
1915441f9243SAlexander V. Chernikov 	       CLLADDR((const struct sockaddr_dl *)(a2)),		\
1916441f9243SAlexander V. Chernikov 	       ((const struct sockaddr_dl *)(a1))->sdl_alen) == 0))
191719fc74fbSJeffrey Hsu 
191830aad87dSBrooks Davis /*
1919df8bae1dSRodney W. Grimes  * Locate an interface based on a complete address.
1920df8bae1dSRodney W. Grimes  */
1921df8bae1dSRodney W. Grimes /*ARGSUSED*/
19224f6c66ccSMatt Macy struct ifaddr *
19234f6c66ccSMatt Macy ifa_ifwithaddr(const struct sockaddr *addr)
1924df8bae1dSRodney W. Grimes {
19250b59d917SJonathan Lemon 	struct ifnet *ifp;
19260b59d917SJonathan Lemon 	struct ifaddr *ifa;
1927df8bae1dSRodney W. Grimes 
1928b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
1929b8a6e03fSGleb Smirnoff 
19304f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1931d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1932df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
1933df8bae1dSRodney W. Grimes 				continue;
1934ab5ed8a5SRobert Watson 			if (sa_equal(addr, ifa->ifa_addr)) {
19350b59d917SJonathan Lemon 				goto done;
1936ab5ed8a5SRobert Watson 			}
193782cd038dSYoshinobu Inoue 			/* IP6 doesn't have broadcast */
19380b59d917SJonathan Lemon 			if ((ifp->if_flags & IFF_BROADCAST) &&
19390b59d917SJonathan Lemon 			    ifa->ifa_broadaddr &&
194082cd038dSYoshinobu Inoue 			    ifa->ifa_broadaddr->sa_len != 0 &&
1941ab5ed8a5SRobert Watson 			    sa_equal(ifa->ifa_broadaddr, addr)) {
19420b59d917SJonathan Lemon 				goto done;
19430b59d917SJonathan Lemon 			}
1944ab5ed8a5SRobert Watson 		}
1945ab5ed8a5SRobert Watson 	}
19460b59d917SJonathan Lemon 	ifa = NULL;
19470b59d917SJonathan Lemon done:
1948df8bae1dSRodney W. Grimes 	return (ifa);
1949df8bae1dSRodney W. Grimes }
19500b59d917SJonathan Lemon 
19518896f83aSRobert Watson int
1952441f9243SAlexander V. Chernikov ifa_ifwithaddr_check(const struct sockaddr *addr)
19538896f83aSRobert Watson {
1954a68cc388SGleb Smirnoff 	struct epoch_tracker et;
19554f6c66ccSMatt Macy 	int rc;
19568896f83aSRobert Watson 
1957a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
19584f6c66ccSMatt Macy 	rc = (ifa_ifwithaddr(addr) != NULL);
1959a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
19604f6c66ccSMatt Macy 	return (rc);
19618896f83aSRobert Watson }
19628896f83aSRobert Watson 
1963df8bae1dSRodney W. Grimes /*
1964773725a2SAndre Oppermann  * Locate an interface based on the broadcast address.
1965773725a2SAndre Oppermann  */
1966773725a2SAndre Oppermann /* ARGSUSED */
1967773725a2SAndre Oppermann struct ifaddr *
1968441f9243SAlexander V. Chernikov ifa_ifwithbroadaddr(const struct sockaddr *addr, int fibnum)
1969773725a2SAndre Oppermann {
1970773725a2SAndre Oppermann 	struct ifnet *ifp;
1971773725a2SAndre Oppermann 	struct ifaddr *ifa;
1972773725a2SAndre Oppermann 
197397168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
19744f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
19754f8585e0SAlan Somers 		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
19764f8585e0SAlan Somers 			continue;
1977d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1978773725a2SAndre Oppermann 			if (ifa->ifa_addr->sa_family != addr->sa_family)
1979773725a2SAndre Oppermann 				continue;
1980773725a2SAndre Oppermann 			if ((ifp->if_flags & IFF_BROADCAST) &&
1981773725a2SAndre Oppermann 			    ifa->ifa_broadaddr &&
1982773725a2SAndre Oppermann 			    ifa->ifa_broadaddr->sa_len != 0 &&
1983ab5ed8a5SRobert Watson 			    sa_equal(ifa->ifa_broadaddr, addr)) {
1984773725a2SAndre Oppermann 				goto done;
1985773725a2SAndre Oppermann 			}
1986ab5ed8a5SRobert Watson 		}
1987ab5ed8a5SRobert Watson 	}
1988773725a2SAndre Oppermann 	ifa = NULL;
1989773725a2SAndre Oppermann done:
1990773725a2SAndre Oppermann 	return (ifa);
1991773725a2SAndre Oppermann }
1992773725a2SAndre Oppermann 
1993773725a2SAndre Oppermann /*
1994df8bae1dSRodney W. Grimes  * Locate the point to point interface with a given destination address.
1995df8bae1dSRodney W. Grimes  */
1996df8bae1dSRodney W. Grimes /*ARGSUSED*/
1997df8bae1dSRodney W. Grimes struct ifaddr *
1998441f9243SAlexander V. Chernikov ifa_ifwithdstaddr(const struct sockaddr *addr, int fibnum)
1999df8bae1dSRodney W. Grimes {
20000b59d917SJonathan Lemon 	struct ifnet *ifp;
20010b59d917SJonathan Lemon 	struct ifaddr *ifa;
2002df8bae1dSRodney W. Grimes 
200397168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
20044f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
20050b59d917SJonathan Lemon 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
20060b59d917SJonathan Lemon 			continue;
20072f308a34SAlan Somers 		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
20080cfee0c2SAlan Somers 			continue;
2009d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2010df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
2011df8bae1dSRodney W. Grimes 				continue;
2012f0c04221SBjoern A. Zeeb 			if (ifa->ifa_dstaddr != NULL &&
2013ab5ed8a5SRobert Watson 			    sa_equal(addr, ifa->ifa_dstaddr)) {
20140b59d917SJonathan Lemon 				goto done;
2015df8bae1dSRodney W. Grimes 			}
20160b59d917SJonathan Lemon 		}
2017ab5ed8a5SRobert Watson 	}
20180b59d917SJonathan Lemon 	ifa = NULL;
20190b59d917SJonathan Lemon done:
20200b59d917SJonathan Lemon 	return (ifa);
2021df8bae1dSRodney W. Grimes }
2022df8bae1dSRodney W. Grimes 
2023df8bae1dSRodney W. Grimes /*
2024df8bae1dSRodney W. Grimes  * Find an interface on a specific network.  If many, choice
2025df8bae1dSRodney W. Grimes  * is most specific found.
2026df8bae1dSRodney W. Grimes  */
2027df8bae1dSRodney W. Grimes struct ifaddr *
2028441f9243SAlexander V. Chernikov ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum)
2029df8bae1dSRodney W. Grimes {
203072fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
203172fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
20328c0fec80SRobert Watson 	struct ifaddr *ifa_maybe = NULL;
2033df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
2034441f9243SAlexander V. Chernikov 	const char *addr_data = addr->sa_data, *cplim;
2035df8bae1dSRodney W. Grimes 
203697168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
20377e2a6151SJulian Elischer 	/*
20387e2a6151SJulian Elischer 	 * AF_LINK addresses can be looked up directly by their index number,
20397e2a6151SJulian Elischer 	 * so do that if we can.
20407e2a6151SJulian Elischer 	 */
2041df8bae1dSRodney W. Grimes 	if (af == AF_LINK) {
2042441f9243SAlexander V. Chernikov 	    const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)addr;
2043603724d3SBjoern A. Zeeb 	    if (sdl->sdl_index && sdl->sdl_index <= V_if_index)
2044f9132cebSJonathan Lemon 		return (ifaddr_byindex(sdl->sdl_index));
2045df8bae1dSRodney W. Grimes 	}
20467e2a6151SJulian Elischer 
20477e2a6151SJulian Elischer 	/*
20488c0fec80SRobert Watson 	 * Scan though each interface, looking for ones that have addresses
204921ee61a6SGleb Smirnoff 	 * in this address family and the requested fib.
20507e2a6151SJulian Elischer 	 */
20514f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
20522f308a34SAlan Somers 		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
20530cfee0c2SAlan Somers 			continue;
2054d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2055441f9243SAlexander V. Chernikov 			const char *cp, *cp2, *cp3;
2056df8bae1dSRodney W. Grimes 
2057523a02aaSDavid Greenman 			if (ifa->ifa_addr->sa_family != af)
2058df8bae1dSRodney W. Grimes next:				continue;
20590ed6142bSQing Li 			if (af == AF_INET &&
20600ed6142bSQing Li 			    ifp->if_flags & IFF_POINTOPOINT && !ignore_ptp) {
20617e2a6151SJulian Elischer 				/*
20627e2a6151SJulian Elischer 				 * This is a bit broken as it doesn't
20637e2a6151SJulian Elischer 				 * take into account that the remote end may
20647e2a6151SJulian Elischer 				 * be a single node in the network we are
20657e2a6151SJulian Elischer 				 * looking for.
20667e2a6151SJulian Elischer 				 * The trouble is that we don't know the
20677e2a6151SJulian Elischer 				 * netmask for the remote end.
20687e2a6151SJulian Elischer 				 */
2069f0c04221SBjoern A. Zeeb 				if (ifa->ifa_dstaddr != NULL &&
2070ab5ed8a5SRobert Watson 				    sa_equal(addr, ifa->ifa_dstaddr)) {
20710b59d917SJonathan Lemon 					goto done;
2072ab5ed8a5SRobert Watson 				}
20733740e2adSDavid Greenman 			} else {
20747e2a6151SJulian Elischer 				/*
20757e2a6151SJulian Elischer 				 * Scan all the bits in the ifa's address.
20767e2a6151SJulian Elischer 				 * If a bit dissagrees with what we are
20777e2a6151SJulian Elischer 				 * looking for, mask it with the netmask
20787e2a6151SJulian Elischer 				 * to see if it really matters.
20797e2a6151SJulian Elischer 				 * (A byte at a time)
20807e2a6151SJulian Elischer 				 */
2081523a02aaSDavid Greenman 				if (ifa->ifa_netmask == 0)
2082523a02aaSDavid Greenman 					continue;
2083df8bae1dSRodney W. Grimes 				cp = addr_data;
2084df8bae1dSRodney W. Grimes 				cp2 = ifa->ifa_addr->sa_data;
2085df8bae1dSRodney W. Grimes 				cp3 = ifa->ifa_netmask->sa_data;
20867e2a6151SJulian Elischer 				cplim = ifa->ifa_netmask->sa_len
20877e2a6151SJulian Elischer 					+ (char *)ifa->ifa_netmask;
2088df8bae1dSRodney W. Grimes 				while (cp3 < cplim)
2089df8bae1dSRodney W. Grimes 					if ((*cp++ ^ *cp2++) & *cp3++)
20907e2a6151SJulian Elischer 						goto next; /* next address! */
20917e2a6151SJulian Elischer 				/*
20927e2a6151SJulian Elischer 				 * If the netmask of what we just found
20937e2a6151SJulian Elischer 				 * is more specific than what we had before
209424421c1cSGleb Smirnoff 				 * (if we had one), or if the virtual status
209524421c1cSGleb Smirnoff 				 * of new prefix is better than of the old one,
209624421c1cSGleb Smirnoff 				 * then remember the new one before continuing
209724421c1cSGleb Smirnoff 				 * to search for an even better one.
20987e2a6151SJulian Elischer 				 */
20998c0fec80SRobert Watson 				if (ifa_maybe == NULL ||
210024421c1cSGleb Smirnoff 				    ifa_preferred(ifa_maybe, ifa) ||
2101df8bae1dSRodney W. Grimes 				    rn_refines((caddr_t)ifa->ifa_netmask,
21028c0fec80SRobert Watson 				    (caddr_t)ifa_maybe->ifa_netmask)) {
2103df8bae1dSRodney W. Grimes 					ifa_maybe = ifa;
21048c0fec80SRobert Watson 				}
2105df8bae1dSRodney W. Grimes 			}
2106b2af64fdSDavid Greenman 		}
2107b2af64fdSDavid Greenman 	}
21080b59d917SJonathan Lemon 	ifa = ifa_maybe;
21098c0fec80SRobert Watson 	ifa_maybe = NULL;
21100b59d917SJonathan Lemon done:
21110b59d917SJonathan Lemon 	return (ifa);
2112df8bae1dSRodney W. Grimes }
2113df8bae1dSRodney W. Grimes 
2114df8bae1dSRodney W. Grimes /*
2115df8bae1dSRodney W. Grimes  * Find an interface address specific to an interface best matching
2116df8bae1dSRodney W. Grimes  * a given address.
2117df8bae1dSRodney W. Grimes  */
2118df8bae1dSRodney W. Grimes struct ifaddr *
2119441f9243SAlexander V. Chernikov ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
2120df8bae1dSRodney W. Grimes {
212172fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
2122441f9243SAlexander V. Chernikov 	const char *cp, *cp2, *cp3;
212372fd1b6aSDag-Erling Smørgrav 	char *cplim;
21248c0fec80SRobert Watson 	struct ifaddr *ifa_maybe = NULL;
2125df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
2126df8bae1dSRodney W. Grimes 
2127df8bae1dSRodney W. Grimes 	if (af >= AF_MAX)
2128cd292f12SBjoern A. Zeeb 		return (NULL);
21296573d758SMatt Macy 
213097168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
2131d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2132df8bae1dSRodney W. Grimes 		if (ifa->ifa_addr->sa_family != af)
2133df8bae1dSRodney W. Grimes 			continue;
21348c0fec80SRobert Watson 		if (ifa_maybe == NULL)
2135df8bae1dSRodney W. Grimes 			ifa_maybe = ifa;
2136df8bae1dSRodney W. Grimes 		if (ifa->ifa_netmask == 0) {
2137d8d5b10eSRobert Watson 			if (sa_equal(addr, ifa->ifa_addr) ||
2138d8d5b10eSRobert Watson 			    (ifa->ifa_dstaddr &&
2139d8d5b10eSRobert Watson 			    sa_equal(addr, ifa->ifa_dstaddr)))
21402defe5cdSJonathan Lemon 				goto done;
2141df8bae1dSRodney W. Grimes 			continue;
2142df8bae1dSRodney W. Grimes 		}
2143b2af64fdSDavid Greenman 		if (ifp->if_flags & IFF_POINTOPOINT) {
2144d8d5b10eSRobert Watson 			if (sa_equal(addr, ifa->ifa_dstaddr))
2145a8637146SJonathan Lemon 				goto done;
21463740e2adSDavid Greenman 		} else {
2147df8bae1dSRodney W. Grimes 			cp = addr->sa_data;
2148df8bae1dSRodney W. Grimes 			cp2 = ifa->ifa_addr->sa_data;
2149df8bae1dSRodney W. Grimes 			cp3 = ifa->ifa_netmask->sa_data;
2150df8bae1dSRodney W. Grimes 			cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
2151df8bae1dSRodney W. Grimes 			for (; cp3 < cplim; cp3++)
2152df8bae1dSRodney W. Grimes 				if ((*cp++ ^ *cp2++) & *cp3)
2153df8bae1dSRodney W. Grimes 					break;
2154df8bae1dSRodney W. Grimes 			if (cp3 == cplim)
21552defe5cdSJonathan Lemon 				goto done;
2156df8bae1dSRodney W. Grimes 		}
2157b2af64fdSDavid Greenman 	}
2158f9132cebSJonathan Lemon 	ifa = ifa_maybe;
2159f9132cebSJonathan Lemon done:
2160f9132cebSJonathan Lemon 	return (ifa);
2161df8bae1dSRodney W. Grimes }
2162df8bae1dSRodney W. Grimes 
216324421c1cSGleb Smirnoff /*
216424421c1cSGleb Smirnoff  * See whether new ifa is better than current one:
216524421c1cSGleb Smirnoff  * 1) A non-virtual one is preferred over virtual.
216624421c1cSGleb Smirnoff  * 2) A virtual in master state preferred over any other state.
216724421c1cSGleb Smirnoff  *
216824421c1cSGleb Smirnoff  * Used in several address selecting functions.
216924421c1cSGleb Smirnoff  */
217024421c1cSGleb Smirnoff int
217124421c1cSGleb Smirnoff ifa_preferred(struct ifaddr *cur, struct ifaddr *next)
217224421c1cSGleb Smirnoff {
217324421c1cSGleb Smirnoff 
217424421c1cSGleb Smirnoff 	return (cur->ifa_carp && (!next->ifa_carp ||
217524421c1cSGleb Smirnoff 	    ((*carp_master_p)(next) && !(*carp_master_p)(cur))));
217624421c1cSGleb Smirnoff }
217724421c1cSGleb Smirnoff 
217895fbe4d0SAlexander V. Chernikov struct sockaddr_dl *
217995fbe4d0SAlexander V. Chernikov link_alloc_sdl(size_t size, int flags)
218095fbe4d0SAlexander V. Chernikov {
218195fbe4d0SAlexander V. Chernikov 
218295fbe4d0SAlexander V. Chernikov 	return (malloc(size, M_TEMP, flags));
218395fbe4d0SAlexander V. Chernikov }
218495fbe4d0SAlexander V. Chernikov 
218595fbe4d0SAlexander V. Chernikov void
218695fbe4d0SAlexander V. Chernikov link_free_sdl(struct sockaddr *sa)
218795fbe4d0SAlexander V. Chernikov {
218895fbe4d0SAlexander V. Chernikov 	free(sa, M_TEMP);
218995fbe4d0SAlexander V. Chernikov }
219095fbe4d0SAlexander V. Chernikov 
219195fbe4d0SAlexander V. Chernikov /*
219295fbe4d0SAlexander V. Chernikov  * Fills in given sdl with interface basic info.
219395fbe4d0SAlexander V. Chernikov  * Returns pointer to filled sdl.
219495fbe4d0SAlexander V. Chernikov  */
219595fbe4d0SAlexander V. Chernikov struct sockaddr_dl *
219695fbe4d0SAlexander V. Chernikov link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype)
219795fbe4d0SAlexander V. Chernikov {
219895fbe4d0SAlexander V. Chernikov 	struct sockaddr_dl *sdl;
219995fbe4d0SAlexander V. Chernikov 
220095fbe4d0SAlexander V. Chernikov 	sdl = (struct sockaddr_dl *)paddr;
220195fbe4d0SAlexander V. Chernikov 	memset(sdl, 0, sizeof(struct sockaddr_dl));
220295fbe4d0SAlexander V. Chernikov 	sdl->sdl_len = sizeof(struct sockaddr_dl);
220395fbe4d0SAlexander V. Chernikov 	sdl->sdl_family = AF_LINK;
220495fbe4d0SAlexander V. Chernikov 	sdl->sdl_index = ifp->if_index;
220595fbe4d0SAlexander V. Chernikov 	sdl->sdl_type = iftype;
220695fbe4d0SAlexander V. Chernikov 
220795fbe4d0SAlexander V. Chernikov 	return (sdl);
220895fbe4d0SAlexander V. Chernikov }
220995fbe4d0SAlexander V. Chernikov 
2210df8bae1dSRodney W. Grimes /*
2211df8bae1dSRodney W. Grimes  * Mark an interface down and notify protocols of
2212df8bae1dSRodney W. Grimes  * the transition.
2213df8bae1dSRodney W. Grimes  */
22148614fb12SMax Laier static void
221572fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam)
2216df8bae1dSRodney W. Grimes {
221772fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
2218df8bae1dSRodney W. Grimes 
2219292ee7beSRobert Watson 	KASSERT(flag == IFF_UP, ("if_unroute: flag != IFF_UP"));
2220292ee7beSRobert Watson 
2221e8c2601dSPoul-Henning Kamp 	ifp->if_flags &= ~flag;
222298b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
2223d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
2224e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
2225df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
2226db7f0b97SKip Macy 	ifp->if_qflush(ifp);
2227db7f0b97SKip Macy 
2228a9771948SGleb Smirnoff 	if (ifp->if_carp)
222954bfbd51SWill Andrews 		(*carp_linkstate_p)(ifp);
2230df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
2231df8bae1dSRodney W. Grimes }
2232df8bae1dSRodney W. Grimes 
2233df8bae1dSRodney W. Grimes /*
2234df8bae1dSRodney W. Grimes  * Mark an interface up and notify protocols of
2235df8bae1dSRodney W. Grimes  * the transition.
2236df8bae1dSRodney W. Grimes  */
22378614fb12SMax Laier static void
223872fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam)
2239df8bae1dSRodney W. Grimes {
224072fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
2241df8bae1dSRodney W. Grimes 
2242292ee7beSRobert Watson 	KASSERT(flag == IFF_UP, ("if_route: flag != IFF_UP"));
2243292ee7beSRobert Watson 
2244e8c2601dSPoul-Henning Kamp 	ifp->if_flags |= flag;
224598b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
2246d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
2247e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
2248df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFUP, ifa->ifa_addr);
2249a9771948SGleb Smirnoff 	if (ifp->if_carp)
225054bfbd51SWill Andrews 		(*carp_linkstate_p)(ifp);
2251df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
225282cd038dSYoshinobu Inoue #ifdef INET6
225382cd038dSYoshinobu Inoue 	in6_if_up(ifp);
225482cd038dSYoshinobu Inoue #endif
2255df8bae1dSRodney W. Grimes }
2256df8bae1dSRodney W. Grimes 
2257a6fffd6cSBrooks Davis void	(*vlan_link_state_p)(struct ifnet *);	/* XXX: private from if_vlan */
225875ee267cSGleb Smirnoff void	(*vlan_trunk_cap_p)(struct ifnet *);		/* XXX: private from if_vlan */
2259e4cd31ddSJeff Roberson struct ifnet *(*vlan_trunkdev_p)(struct ifnet *);
2260e4cd31ddSJeff Roberson struct	ifnet *(*vlan_devat_p)(struct ifnet *, uint16_t);
2261e4cd31ddSJeff Roberson int	(*vlan_tag_p)(struct ifnet *, uint16_t *);
226232d2623aSNavdeep Parhar int	(*vlan_pcp_p)(struct ifnet *, uint16_t *);
2263e4cd31ddSJeff Roberson int	(*vlan_setcookie_p)(struct ifnet *, void *);
2264e4cd31ddSJeff Roberson void	*(*vlan_cookie_p)(struct ifnet *);
226594f5c9cfSSam Leffler 
226694f5c9cfSSam Leffler /*
226768a3482fSGleb Smirnoff  * Handle a change in the interface link state. To avoid LORs
226868a3482fSGleb Smirnoff  * between driver lock and upper layer locks, as well as possible
226968a3482fSGleb Smirnoff  * recursions, we post event to taskqueue, and all job
227068a3482fSGleb Smirnoff  * is done in static do_link_state_change().
227194f5c9cfSSam Leffler  */
227294f5c9cfSSam Leffler void
2273d6e82913SSteven Hartland if_link_state_change(struct ifnet *ifp, int link_state)
227494f5c9cfSSam Leffler {
2275d6e82913SSteven Hartland 	/* Return if state hasn't changed. */
2276d6e82913SSteven Hartland 	if (ifp->if_link_state == link_state)
22774d96314fSGleb Smirnoff 		return;
22784d96314fSGleb Smirnoff 
227994f5c9cfSSam Leffler 	ifp->if_link_state = link_state;
22804d96314fSGleb Smirnoff 
2281b8a6e03fSGleb Smirnoff 	/* XXXGL: reference ifp? */
228268a3482fSGleb Smirnoff 	taskqueue_enqueue(taskqueue_swi, &ifp->if_linktask);
228368a3482fSGleb Smirnoff }
228468a3482fSGleb Smirnoff 
228568a3482fSGleb Smirnoff static void
228668a3482fSGleb Smirnoff do_link_state_change(void *arg, int pending)
228768a3482fSGleb Smirnoff {
2288b8a6e03fSGleb Smirnoff 	struct ifnet *ifp;
2289b8a6e03fSGleb Smirnoff 	int link_state;
229068a3482fSGleb Smirnoff 
2291b8a6e03fSGleb Smirnoff 	ifp = arg;
2292b8a6e03fSGleb Smirnoff 	link_state = ifp->if_link_state;
2293b8a6e03fSGleb Smirnoff 
2294b8a6e03fSGleb Smirnoff 	CURVNET_SET(ifp->if_vnet);
229594f5c9cfSSam Leffler 	rt_ifmsg(ifp);
229675ee267cSGleb Smirnoff 	if (ifp->if_vlantrunk != NULL)
2297a6fffd6cSBrooks Davis 		(*vlan_link_state_p)(ifp);
22981c7899c7SGleb Smirnoff 
22991c7899c7SGleb Smirnoff 	if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) &&
2300833e8dc5SGleb Smirnoff 	    ifp->if_l2com != NULL)
23011c7899c7SGleb Smirnoff 		(*ng_ether_link_state_p)(ifp, link_state);
23024d96314fSGleb Smirnoff 	if (ifp->if_carp)
230354bfbd51SWill Andrews 		(*carp_linkstate_p)(ifp);
2304ddf32010SAndrew Thompson 	if (ifp->if_bridge)
23055c30b378SMatt Macy 		ifp->if_bridge_linkstate(ifp);
2306ddf32010SAndrew Thompson 	if (ifp->if_lagg)
2307d6e82913SSteven Hartland 		(*lagg_linkstate_p)(ifp, link_state);
23088f867517SAndrew Thompson 
230921ca7b57SMarko Zec 	if (IS_DEFAULT_VNET(curvnet))
23109d80a330SBrooks Davis 		devctl_notify("IFNET", ifp->if_xname,
231121ca7b57SMarko Zec 		    (link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN",
231221ca7b57SMarko Zec 		    NULL);
231368a3482fSGleb Smirnoff 	if (pending > 1)
231468a3482fSGleb Smirnoff 		if_printf(ifp, "%d link states coalesced\n", pending);
23155515c2e7SGleb Smirnoff 	if (log_link_state_change)
231620f8d7bcSDag-Erling Smørgrav 		if_printf(ifp, "link state changed to %s\n",
23178b02df24SGleb Smirnoff 		    (link_state == LINK_STATE_UP) ? "UP" : "DOWN" );
2318368bf0c2SSepherosa Ziehau 	EVENTHANDLER_INVOKE(ifnet_link_event, ifp, link_state);
23198b615593SMarko Zec 	CURVNET_RESTORE();
232094f5c9cfSSam Leffler }
232194f5c9cfSSam Leffler 
2322df8bae1dSRodney W. Grimes /*
2323e8c2601dSPoul-Henning Kamp  * Mark an interface down and notify protocols of
2324e8c2601dSPoul-Henning Kamp  * the transition.
2325e8c2601dSPoul-Henning Kamp  */
2326e8c2601dSPoul-Henning Kamp void
232772fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp)
2328e8c2601dSPoul-Henning Kamp {
2329e8c2601dSPoul-Henning Kamp 
233092a6859bSDexuan Cui 	EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_DOWN);
2331e8c2601dSPoul-Henning Kamp 	if_unroute(ifp, IFF_UP, AF_UNSPEC);
2332e8c2601dSPoul-Henning Kamp }
2333e8c2601dSPoul-Henning Kamp 
2334e8c2601dSPoul-Henning Kamp /*
2335e8c2601dSPoul-Henning Kamp  * Mark an interface up and notify protocols of
2336e8c2601dSPoul-Henning Kamp  * the transition.
2337e8c2601dSPoul-Henning Kamp  */
2338e8c2601dSPoul-Henning Kamp void
233972fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp)
2340e8c2601dSPoul-Henning Kamp {
2341e8c2601dSPoul-Henning Kamp 
2342e8c2601dSPoul-Henning Kamp 	if_route(ifp, IFF_UP, AF_UNSPEC);
234392a6859bSDexuan Cui 	EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_UP);
2344e8c2601dSPoul-Henning Kamp }
2345e8c2601dSPoul-Henning Kamp 
2346e8c2601dSPoul-Henning Kamp /*
2347df8bae1dSRodney W. Grimes  * Flush an interface queue.
2348df8bae1dSRodney W. Grimes  */
23497cc5b47fSKip Macy void
2350db7f0b97SKip Macy if_qflush(struct ifnet *ifp)
2351df8bae1dSRodney W. Grimes {
235272fd1b6aSDag-Erling Smørgrav 	struct mbuf *m, *n;
2353db7f0b97SKip Macy 	struct ifaltq *ifq;
2354df8bae1dSRodney W. Grimes 
2355db7f0b97SKip Macy 	ifq = &ifp->if_snd;
23567b21048cSMax Laier 	IFQ_LOCK(ifq);
235702b199f1SMax Laier #ifdef ALTQ
235802b199f1SMax Laier 	if (ALTQ_IS_ENABLED(ifq))
235902b199f1SMax Laier 		ALTQ_PURGE(ifq);
236002b199f1SMax Laier #endif
2361df8bae1dSRodney W. Grimes 	n = ifq->ifq_head;
2362155d72c4SPedro F. Giffuni 	while ((m = n) != NULL) {
2363c29a3321SKevin Lo 		n = m->m_nextpkt;
2364df8bae1dSRodney W. Grimes 		m_freem(m);
2365df8bae1dSRodney W. Grimes 	}
2366df8bae1dSRodney W. Grimes 	ifq->ifq_head = 0;
2367df8bae1dSRodney W. Grimes 	ifq->ifq_tail = 0;
2368df8bae1dSRodney W. Grimes 	ifq->ifq_len = 0;
23697b21048cSMax Laier 	IFQ_UNLOCK(ifq);
2370df8bae1dSRodney W. Grimes }
2371df8bae1dSRodney W. Grimes 
2372df8bae1dSRodney W. Grimes /*
23736064c5d3SRobert Watson  * Map interface name to interface structure pointer, with or without
23746064c5d3SRobert Watson  * returning a reference.
2375df8bae1dSRodney W. Grimes  */
2376df8bae1dSRodney W. Grimes struct ifnet *
23776064c5d3SRobert Watson ifunit_ref(const char *name)
23786064c5d3SRobert Watson {
2379a68cc388SGleb Smirnoff 	struct epoch_tracker et;
23806064c5d3SRobert Watson 	struct ifnet *ifp;
23816064c5d3SRobert Watson 
2382a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
23834f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
23848bd015a1SRobert Watson 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0 &&
23858bd015a1SRobert Watson 		    !(ifp->if_flags & IFF_DYING))
23866064c5d3SRobert Watson 			break;
23876064c5d3SRobert Watson 	}
23886064c5d3SRobert Watson 	if (ifp != NULL)
23896064c5d3SRobert Watson 		if_ref(ifp);
2390a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
23916064c5d3SRobert Watson 	return (ifp);
23926064c5d3SRobert Watson }
23936064c5d3SRobert Watson 
23946064c5d3SRobert Watson struct ifnet *
239530aad87dSBrooks Davis ifunit(const char *name)
2396df8bae1dSRodney W. Grimes {
2397a68cc388SGleb Smirnoff 	struct epoch_tracker et;
23988b7805e4SBoris Popov 	struct ifnet *ifp;
2399df8bae1dSRodney W. Grimes 
2400a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
24014f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
240236c19a57SBrooks Davis 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
2403df8bae1dSRodney W. Grimes 			break;
2404df8bae1dSRodney W. Grimes 	}
2405a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
2406df8bae1dSRodney W. Grimes 	return (ifp);
2407df8bae1dSRodney W. Grimes }
2408df8bae1dSRodney W. Grimes 
24098ad798aeSBrooks Davis void *
24108a4a4a43SBrooks Davis ifr_buffer_get_buffer(void *data)
241186d2ef16SBrooks Davis {
241286d2ef16SBrooks Davis 	union ifreq_union *ifrup;
241386d2ef16SBrooks Davis 
241486d2ef16SBrooks Davis 	ifrup = data;
241586d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24168a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
241786d2ef16SBrooks Davis 		return ((void *)(uintptr_t)
241886d2ef16SBrooks Davis 		    ifrup->ifr32.ifr_ifru.ifru_buffer.buffer);
241986d2ef16SBrooks Davis #endif
242086d2ef16SBrooks Davis 	return (ifrup->ifr.ifr_ifru.ifru_buffer.buffer);
242186d2ef16SBrooks Davis }
242286d2ef16SBrooks Davis 
242386d2ef16SBrooks Davis static void
24248a4a4a43SBrooks Davis ifr_buffer_set_buffer_null(void *data)
242586d2ef16SBrooks Davis {
242686d2ef16SBrooks Davis 	union ifreq_union *ifrup;
242786d2ef16SBrooks Davis 
242886d2ef16SBrooks Davis 	ifrup = data;
242986d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24308a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
243186d2ef16SBrooks Davis 		ifrup->ifr32.ifr_ifru.ifru_buffer.buffer = 0;
243286d2ef16SBrooks Davis 	else
243386d2ef16SBrooks Davis #endif
243486d2ef16SBrooks Davis 		ifrup->ifr.ifr_ifru.ifru_buffer.buffer = NULL;
243586d2ef16SBrooks Davis }
243686d2ef16SBrooks Davis 
24378ad798aeSBrooks Davis size_t
24388a4a4a43SBrooks Davis ifr_buffer_get_length(void *data)
243986d2ef16SBrooks Davis {
244086d2ef16SBrooks Davis 	union ifreq_union *ifrup;
244186d2ef16SBrooks Davis 
244286d2ef16SBrooks Davis 	ifrup = data;
244386d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24448a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
244586d2ef16SBrooks Davis 		return (ifrup->ifr32.ifr_ifru.ifru_buffer.length);
244686d2ef16SBrooks Davis #endif
244786d2ef16SBrooks Davis 	return (ifrup->ifr.ifr_ifru.ifru_buffer.length);
244886d2ef16SBrooks Davis }
244986d2ef16SBrooks Davis 
245086d2ef16SBrooks Davis static void
24518a4a4a43SBrooks Davis ifr_buffer_set_length(void *data, size_t len)
245286d2ef16SBrooks Davis {
245386d2ef16SBrooks Davis 	union ifreq_union *ifrup;
245486d2ef16SBrooks Davis 
245586d2ef16SBrooks Davis 	ifrup = data;
245686d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24578a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
245886d2ef16SBrooks Davis 		ifrup->ifr32.ifr_ifru.ifru_buffer.length = len;
245986d2ef16SBrooks Davis 	else
246086d2ef16SBrooks Davis #endif
246186d2ef16SBrooks Davis 		ifrup->ifr.ifr_ifru.ifru_buffer.length = len;
246286d2ef16SBrooks Davis }
246386d2ef16SBrooks Davis 
2464541d96aaSBrooks Davis void *
2465541d96aaSBrooks Davis ifr_data_get_ptr(void *ifrp)
2466541d96aaSBrooks Davis {
2467541d96aaSBrooks Davis 	union ifreq_union *ifrup;
2468541d96aaSBrooks Davis 
2469541d96aaSBrooks Davis 	ifrup = ifrp;
2470541d96aaSBrooks Davis #ifdef COMPAT_FREEBSD32
2471541d96aaSBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
2472541d96aaSBrooks Davis 		return ((void *)(uintptr_t)
2473541d96aaSBrooks Davis 		    ifrup->ifr32.ifr_ifru.ifru_data);
2474541d96aaSBrooks Davis #endif
2475541d96aaSBrooks Davis 		return (ifrup->ifr.ifr_ifru.ifru_data);
2476541d96aaSBrooks Davis }
2477541d96aaSBrooks Davis 
247882cd038dSYoshinobu Inoue /*
2479f13ad206SJonathan Lemon  * Hardware specific interface ioctls.
2480df8bae1dSRodney W. Grimes  */
24811687b1abSMichael Tuexen int
2482f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
2483df8bae1dSRodney W. Grimes {
2484f13ad206SJonathan Lemon 	struct ifreq *ifr;
2485cc5bb78bSSepherosa Ziehau 	int error = 0, do_ifup = 0;
2486292ee7beSRobert Watson 	int new_flags, temp_flags;
248736c19a57SBrooks Davis 	size_t namelen, onamelen;
2488215940b3SXin LI 	size_t descrlen;
2489215940b3SXin LI 	char *descrbuf, *odescrbuf;
249036c19a57SBrooks Davis 	char new_name[IFNAMSIZ];
249136c19a57SBrooks Davis 	struct ifaddr *ifa;
249236c19a57SBrooks Davis 	struct sockaddr_dl *sdl;
2493df8bae1dSRodney W. Grimes 
2494df8bae1dSRodney W. Grimes 	ifr = (struct ifreq *)data;
249530aad87dSBrooks Davis 	switch (cmd) {
2496de593450SJonathan Lemon 	case SIOCGIFINDEX:
2497de593450SJonathan Lemon 		ifr->ifr_index = ifp->if_index;
2498de593450SJonathan Lemon 		break;
2499de593450SJonathan Lemon 
2500df8bae1dSRodney W. Grimes 	case SIOCGIFFLAGS:
2501292ee7beSRobert Watson 		temp_flags = ifp->if_flags | ifp->if_drv_flags;
2502292ee7beSRobert Watson 		ifr->ifr_flags = temp_flags & 0xffff;
2503292ee7beSRobert Watson 		ifr->ifr_flagshigh = temp_flags >> 16;
2504df8bae1dSRodney W. Grimes 		break;
2505df8bae1dSRodney W. Grimes 
2506016da741SJonathan Lemon 	case SIOCGIFCAP:
2507016da741SJonathan Lemon 		ifr->ifr_reqcap = ifp->if_capabilities;
2508016da741SJonathan Lemon 		ifr->ifr_curcap = ifp->if_capenable;
2509016da741SJonathan Lemon 		break;
2510016da741SJonathan Lemon 
2511c1aedfcbSEd Maste 	case SIOCGIFDATA:
2512c1aedfcbSEd Maste 	{
2513c1aedfcbSEd Maste 		struct if_data ifd;
2514c1aedfcbSEd Maste 
2515c1aedfcbSEd Maste 		/* Ensure uninitialised padding is not leaked. */
2516c1aedfcbSEd Maste 		memset(&ifd, 0, sizeof(ifd));
2517c1aedfcbSEd Maste 
2518c1aedfcbSEd Maste 		if_data_copy(ifp, &ifd);
2519c1aedfcbSEd Maste 		error = copyout(&ifd, ifr_data_get_ptr(ifr), sizeof(ifd));
2520c1aedfcbSEd Maste 		break;
2521c1aedfcbSEd Maste 	}
2522c1aedfcbSEd Maste 
25238f293a63SRobert Watson #ifdef MAC
25248f293a63SRobert Watson 	case SIOCGIFMAC:
252530d239bcSRobert Watson 		error = mac_ifnet_ioctl_get(td->td_ucred, ifr, ifp);
25268f293a63SRobert Watson 		break;
25278f293a63SRobert Watson #endif
25288f293a63SRobert Watson 
2529df8bae1dSRodney W. Grimes 	case SIOCGIFMETRIC:
2530df8bae1dSRodney W. Grimes 		ifr->ifr_metric = ifp->if_metric;
2531df8bae1dSRodney W. Grimes 		break;
2532df8bae1dSRodney W. Grimes 
2533a7028af7SDavid Greenman 	case SIOCGIFMTU:
2534a7028af7SDavid Greenman 		ifr->ifr_mtu = ifp->if_mtu;
2535a7028af7SDavid Greenman 		break;
2536a7028af7SDavid Greenman 
2537074c4a4eSGarrett Wollman 	case SIOCGIFPHYS:
2538e6485f73SGleb Smirnoff 		/* XXXGL: did this ever worked? */
2539e6485f73SGleb Smirnoff 		ifr->ifr_phys = 0;
2540074c4a4eSGarrett Wollman 		break;
2541074c4a4eSGarrett Wollman 
2542215940b3SXin LI 	case SIOCGIFDESCR:
2543215940b3SXin LI 		error = 0;
2544215940b3SXin LI 		sx_slock(&ifdescr_sx);
254557d84848SXin LI 		if (ifp->if_description == NULL)
2546215940b3SXin LI 			error = ENOMSG;
254757d84848SXin LI 		else {
2548215940b3SXin LI 			/* space for terminating nul */
2549215940b3SXin LI 			descrlen = strlen(ifp->if_description) + 1;
25508a4a4a43SBrooks Davis 			if (ifr_buffer_get_length(ifr) < descrlen)
25518a4a4a43SBrooks Davis 				ifr_buffer_set_buffer_null(ifr);
2552215940b3SXin LI 			else
2553215940b3SXin LI 				error = copyout(ifp->if_description,
25548a4a4a43SBrooks Davis 				    ifr_buffer_get_buffer(ifr), descrlen);
25558a4a4a43SBrooks Davis 			ifr_buffer_set_length(ifr, descrlen);
2556215940b3SXin LI 		}
2557215940b3SXin LI 		sx_sunlock(&ifdescr_sx);
2558215940b3SXin LI 		break;
2559215940b3SXin LI 
2560215940b3SXin LI 	case SIOCSIFDESCR:
2561215940b3SXin LI 		error = priv_check(td, PRIV_NET_SETIFDESCR);
2562215940b3SXin LI 		if (error)
2563215940b3SXin LI 			return (error);
2564215940b3SXin LI 
2565215940b3SXin LI 		/*
2566215940b3SXin LI 		 * Copy only (length-1) bytes to make sure that
2567215940b3SXin LI 		 * if_description is always nul terminated.  The
2568215940b3SXin LI 		 * length parameter is supposed to count the
2569215940b3SXin LI 		 * terminating nul in.
2570215940b3SXin LI 		 */
25718a4a4a43SBrooks Davis 		if (ifr_buffer_get_length(ifr) > ifdescr_maxlen)
2572215940b3SXin LI 			return (ENAMETOOLONG);
25738a4a4a43SBrooks Davis 		else if (ifr_buffer_get_length(ifr) == 0)
2574215940b3SXin LI 			descrbuf = NULL;
2575215940b3SXin LI 		else {
25768a4a4a43SBrooks Davis 			descrbuf = malloc(ifr_buffer_get_length(ifr),
257786d2ef16SBrooks Davis 			    M_IFDESCR, M_WAITOK | M_ZERO);
25788a4a4a43SBrooks Davis 			error = copyin(ifr_buffer_get_buffer(ifr), descrbuf,
25798a4a4a43SBrooks Davis 			    ifr_buffer_get_length(ifr) - 1);
2580215940b3SXin LI 			if (error) {
2581215940b3SXin LI 				free(descrbuf, M_IFDESCR);
2582215940b3SXin LI 				break;
2583215940b3SXin LI 			}
2584215940b3SXin LI 		}
2585215940b3SXin LI 
2586215940b3SXin LI 		sx_xlock(&ifdescr_sx);
2587215940b3SXin LI 		odescrbuf = ifp->if_description;
2588215940b3SXin LI 		ifp->if_description = descrbuf;
2589215940b3SXin LI 		sx_xunlock(&ifdescr_sx);
2590215940b3SXin LI 
2591215940b3SXin LI 		getmicrotime(&ifp->if_lastchange);
2592215940b3SXin LI 		free(odescrbuf, M_IFDESCR);
2593215940b3SXin LI 		break;
2594215940b3SXin LI 
259535fd7bc0SBjoern A. Zeeb 	case SIOCGIFFIB:
259635fd7bc0SBjoern A. Zeeb 		ifr->ifr_fib = ifp->if_fib;
259735fd7bc0SBjoern A. Zeeb 		break;
259835fd7bc0SBjoern A. Zeeb 
259935fd7bc0SBjoern A. Zeeb 	case SIOCSIFFIB:
260035fd7bc0SBjoern A. Zeeb 		error = priv_check(td, PRIV_NET_SETIFFIB);
260135fd7bc0SBjoern A. Zeeb 		if (error)
260235fd7bc0SBjoern A. Zeeb 			return (error);
260335fd7bc0SBjoern A. Zeeb 		if (ifr->ifr_fib >= rt_numfibs)
260435fd7bc0SBjoern A. Zeeb 			return (EINVAL);
260535fd7bc0SBjoern A. Zeeb 
260635fd7bc0SBjoern A. Zeeb 		ifp->if_fib = ifr->ifr_fib;
260735fd7bc0SBjoern A. Zeeb 		break;
260835fd7bc0SBjoern A. Zeeb 
2609df8bae1dSRodney W. Grimes 	case SIOCSIFFLAGS:
2610acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFFLAGS);
26119448326fSPoul-Henning Kamp 		if (error)
2612df8bae1dSRodney W. Grimes 			return (error);
2613292ee7beSRobert Watson 		/*
2614292ee7beSRobert Watson 		 * Currently, no driver owned flags pass the IFF_CANTCHANGE
2615292ee7beSRobert Watson 		 * check, so we don't need special handling here yet.
2616292ee7beSRobert Watson 		 */
261762f76486SMaxim Sobolev 		new_flags = (ifr->ifr_flags & 0xffff) |
261862f76486SMaxim Sobolev 		    (ifr->ifr_flagshigh << 16);
2619af50ea38SGleb Smirnoff 		if (ifp->if_flags & IFF_UP &&
262062f76486SMaxim Sobolev 		    (new_flags & IFF_UP) == 0) {
2621df8bae1dSRodney W. Grimes 			if_down(ifp);
262262f76486SMaxim Sobolev 		} else if (new_flags & IFF_UP &&
2623cf4b9371SPoul-Henning Kamp 		    (ifp->if_flags & IFF_UP) == 0) {
2624cc5bb78bSSepherosa Ziehau 			do_ifup = 1;
2625df8bae1dSRodney W. Grimes 		}
26267aebc5e8SYaroslav Tykhiy 		/* See if permanently promiscuous mode bit is about to flip */
26277aebc5e8SYaroslav Tykhiy 		if ((ifp->if_flags ^ new_flags) & IFF_PPROMISC) {
26287aebc5e8SYaroslav Tykhiy 			if (new_flags & IFF_PPROMISC)
26297aebc5e8SYaroslav Tykhiy 				ifp->if_flags |= IFF_PROMISC;
26307aebc5e8SYaroslav Tykhiy 			else if (ifp->if_pcount == 0)
26317aebc5e8SYaroslav Tykhiy 				ifp->if_flags &= ~IFF_PROMISC;
26326d07c157SNick Hibma 			if (log_promisc_mode_change)
263320f8d7bcSDag-Erling Smørgrav                                 if_printf(ifp, "permanently promiscuous mode %s\n",
26346d07c157SNick Hibma                                     ((new_flags & IFF_PPROMISC) ?
26356d07c157SNick Hibma                                      "enabled" : "disabled"));
26367aebc5e8SYaroslav Tykhiy 		}
2637df8bae1dSRodney W. Grimes 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
263862f76486SMaxim Sobolev 			(new_flags &~ IFF_CANTCHANGE);
263931302ebfSRobert Watson 		if (ifp->if_ioctl) {
2640df8bae1dSRodney W. Grimes 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
264131302ebfSRobert Watson 		}
2642cc5bb78bSSepherosa Ziehau 		if (do_ifup)
2643cc5bb78bSSepherosa Ziehau 			if_up(ifp);
264498b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
2645df8bae1dSRodney W. Grimes 		break;
2646df8bae1dSRodney W. Grimes 
2647016da741SJonathan Lemon 	case SIOCSIFCAP:
2648acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFCAP);
2649016da741SJonathan Lemon 		if (error)
2650016da741SJonathan Lemon 			return (error);
2651efb4018bSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
2652efb4018bSYaroslav Tykhiy 			return (EOPNOTSUPP);
2653016da741SJonathan Lemon 		if (ifr->ifr_reqcap & ~ifp->if_capabilities)
2654016da741SJonathan Lemon 			return (EINVAL);
2655efb4018bSYaroslav Tykhiy 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2656efb4018bSYaroslav Tykhiy 		if (error == 0)
2657efb4018bSYaroslav Tykhiy 			getmicrotime(&ifp->if_lastchange);
2658016da741SJonathan Lemon 		break;
2659016da741SJonathan Lemon 
26608f293a63SRobert Watson #ifdef MAC
26618f293a63SRobert Watson 	case SIOCSIFMAC:
266230d239bcSRobert Watson 		error = mac_ifnet_ioctl_set(td->td_ucred, ifr, ifp);
26638f293a63SRobert Watson 		break;
26648f293a63SRobert Watson #endif
26658f293a63SRobert Watson 
266636c19a57SBrooks Davis 	case SIOCSIFNAME:
2667acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFNAME);
2668acd3428bSRobert Watson 		if (error)
266936c19a57SBrooks Davis 			return (error);
2670541d96aaSBrooks Davis 		error = copyinstr(ifr_data_get_ptr(ifr), new_name, IFNAMSIZ,
2671541d96aaSBrooks Davis 		    NULL);
2672bc1470f1SBrooks Davis 		if (error != 0)
267336c19a57SBrooks Davis 			return (error);
2674bc1470f1SBrooks Davis 		if (new_name[0] == '\0')
2675bc1470f1SBrooks Davis 			return (EINVAL);
26761ef3d54dSDon Lewis 		if (new_name[IFNAMSIZ-1] != '\0') {
26771ef3d54dSDon Lewis 			new_name[IFNAMSIZ-1] = '\0';
26781ef3d54dSDon Lewis 			if (strlen(new_name) == IFNAMSIZ-1)
26791ef3d54dSDon Lewis 				return (EINVAL);
26801ef3d54dSDon Lewis 		}
268140b1c921SKyle Evans 		if (strcmp(new_name, ifp->if_xname) == 0)
268240b1c921SKyle Evans 			break;
268336c19a57SBrooks Davis 		if (ifunit(new_name) != NULL)
268436c19a57SBrooks Davis 			return (EEXIST);
268536c19a57SBrooks Davis 
26865428776eSJohn Baldwin 		/*
26875428776eSJohn Baldwin 		 * XXX: Locking.  Nothing else seems to lock if_flags,
26885428776eSJohn Baldwin 		 * and there are numerous other races with the
26895428776eSJohn Baldwin 		 * ifunit() checks not being atomic with namespace
26905428776eSJohn Baldwin 		 * changes (renames, vmoves, if_attach, etc).
26915428776eSJohn Baldwin 		 */
26925428776eSJohn Baldwin 		ifp->if_flags |= IFF_RENAMING;
26935428776eSJohn Baldwin 
269436c19a57SBrooks Davis 		/* Announce the departure of the interface. */
269536c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
269652023244SMax Laier 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
269736c19a57SBrooks Davis 
269820f8d7bcSDag-Erling Smørgrav 		if_printf(ifp, "changing name to '%s'\n", new_name);
269971672bb6SBrooks Davis 
270067420bdaSGleb Smirnoff 		IF_ADDR_WLOCK(ifp);
270136c19a57SBrooks Davis 		strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
27024a0d6638SRuslan Ermilov 		ifa = ifp->if_addr;
270336c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
270436c19a57SBrooks Davis 		namelen = strlen(new_name);
270536c19a57SBrooks Davis 		onamelen = sdl->sdl_nlen;
270636c19a57SBrooks Davis 		/*
270736c19a57SBrooks Davis 		 * Move the address if needed.  This is safe because we
270836c19a57SBrooks Davis 		 * allocate space for a name of length IFNAMSIZ when we
270936c19a57SBrooks Davis 		 * create this in if_attach().
271036c19a57SBrooks Davis 		 */
271136c19a57SBrooks Davis 		if (namelen != onamelen) {
271236c19a57SBrooks Davis 			bcopy(sdl->sdl_data + onamelen,
271336c19a57SBrooks Davis 			    sdl->sdl_data + namelen, sdl->sdl_alen);
271436c19a57SBrooks Davis 		}
271536c19a57SBrooks Davis 		bcopy(new_name, sdl->sdl_data, namelen);
271636c19a57SBrooks Davis 		sdl->sdl_nlen = namelen;
271736c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_netmask;
271836c19a57SBrooks Davis 		bzero(sdl->sdl_data, onamelen);
271936c19a57SBrooks Davis 		while (namelen != 0)
272036c19a57SBrooks Davis 			sdl->sdl_data[--namelen] = 0xff;
272167420bdaSGleb Smirnoff 		IF_ADDR_WUNLOCK(ifp);
272236c19a57SBrooks Davis 
272325a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
272436c19a57SBrooks Davis 		/* Announce the return of the interface. */
272536c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
27265428776eSJohn Baldwin 
27275428776eSJohn Baldwin 		ifp->if_flags &= ~IFF_RENAMING;
272836c19a57SBrooks Davis 		break;
272936c19a57SBrooks Davis 
2730679e1390SJamie Gritton #ifdef VIMAGE
2731679e1390SJamie Gritton 	case SIOCSIFVNET:
2732679e1390SJamie Gritton 		error = priv_check(td, PRIV_NET_SETIFVNET);
2733679e1390SJamie Gritton 		if (error)
2734679e1390SJamie Gritton 			return (error);
2735be31e5e7SBjoern A. Zeeb 		error = if_vmove_loan(td, ifp, ifr->ifr_name, ifr->ifr_jid);
2736679e1390SJamie Gritton 		break;
2737679e1390SJamie Gritton #endif
2738679e1390SJamie Gritton 
2739df8bae1dSRodney W. Grimes 	case SIOCSIFMETRIC:
2740acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFMETRIC);
27419448326fSPoul-Henning Kamp 		if (error)
2742df8bae1dSRodney W. Grimes 			return (error);
2743df8bae1dSRodney W. Grimes 		ifp->if_metric = ifr->ifr_metric;
274498b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
2745df8bae1dSRodney W. Grimes 		break;
2746df8bae1dSRodney W. Grimes 
2747074c4a4eSGarrett Wollman 	case SIOCSIFPHYS:
2748acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFPHYS);
2749e39a0280SGary Palmer 		if (error)
2750913e410eSYaroslav Tykhiy 			return (error);
2751913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
2752913e410eSYaroslav Tykhiy 			return (EOPNOTSUPP);
2753e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2754e39a0280SGary Palmer 		if (error == 0)
275598b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
2756913e410eSYaroslav Tykhiy 		break;
2757074c4a4eSGarrett Wollman 
2758a7028af7SDavid Greenman 	case SIOCSIFMTU:
275982cd038dSYoshinobu Inoue 	{
276082cd038dSYoshinobu Inoue 		u_long oldmtu = ifp->if_mtu;
276182cd038dSYoshinobu Inoue 
2762acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFMTU);
27639448326fSPoul-Henning Kamp 		if (error)
2764a7028af7SDavid Greenman 			return (error);
2765aab3beeeSBrian Somers 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
276675ee03cbSDavid Greenman 			return (EINVAL);
2767f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
2768f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
2769e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
277048f71763SRuslan Ermilov 		if (error == 0) {
277198b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
277248f71763SRuslan Ermilov 			rt_ifmsg(ifp);
2773e5054602SMark Johnston #ifdef INET
27747790c8c1SConrad Meyer 			DEBUGNET_NOTIFY_MTU(ifp);
2775e5054602SMark Johnston #endif
277648f71763SRuslan Ermilov 		}
277782cd038dSYoshinobu Inoue 		/*
277882cd038dSYoshinobu Inoue 		 * If the link MTU changed, do network layer specific procedure.
277982cd038dSYoshinobu Inoue 		 */
278082cd038dSYoshinobu Inoue 		if (ifp->if_mtu != oldmtu) {
278182cd038dSYoshinobu Inoue #ifdef INET6
278282cd038dSYoshinobu Inoue 			nd6_setmtu(ifp);
278382cd038dSYoshinobu Inoue #endif
27847f948f12SAlexander V. Chernikov 			rt_updatemtu(ifp);
278582cd038dSYoshinobu Inoue 		}
2786f13ad206SJonathan Lemon 		break;
278782cd038dSYoshinobu Inoue 	}
2788a7028af7SDavid Greenman 
2789df8bae1dSRodney W. Grimes 	case SIOCADDMULTI:
2790df8bae1dSRodney W. Grimes 	case SIOCDELMULTI:
2791acd3428bSRobert Watson 		if (cmd == SIOCADDMULTI)
2792acd3428bSRobert Watson 			error = priv_check(td, PRIV_NET_ADDMULTI);
2793acd3428bSRobert Watson 		else
2794acd3428bSRobert Watson 			error = priv_check(td, PRIV_NET_DELMULTI);
27959448326fSPoul-Henning Kamp 		if (error)
2796df8bae1dSRodney W. Grimes 			return (error);
2797477180fbSGarrett Wollman 
2798477180fbSGarrett Wollman 		/* Don't allow group membership on non-multicast interfaces. */
2799477180fbSGarrett Wollman 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
2800f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
2801477180fbSGarrett Wollman 
2802477180fbSGarrett Wollman 		/* Don't let users screw up protocols' entries. */
2803477180fbSGarrett Wollman 		if (ifr->ifr_addr.sa_family != AF_LINK)
2804f13ad206SJonathan Lemon 			return (EINVAL);
2805477180fbSGarrett Wollman 
2806477180fbSGarrett Wollman 		if (cmd == SIOCADDMULTI) {
2807a68cc388SGleb Smirnoff 			struct epoch_tracker et;
2808477180fbSGarrett Wollman 			struct ifmultiaddr *ifma;
2809ec002feeSBruce M Simpson 
2810ec002feeSBruce M Simpson 			/*
2811ec002feeSBruce M Simpson 			 * Userland is only permitted to join groups once
2812ec002feeSBruce M Simpson 			 * via the if_addmulti() KPI, because it cannot hold
2813ec002feeSBruce M Simpson 			 * struct ifmultiaddr * between calls. It may also
2814ec002feeSBruce M Simpson 			 * lose a race while we check if the membership
2815ec002feeSBruce M Simpson 			 * already exists.
2816ec002feeSBruce M Simpson 			 */
2817a68cc388SGleb Smirnoff 			NET_EPOCH_ENTER(et);
2818ec002feeSBruce M Simpson 			ifma = if_findmulti(ifp, &ifr->ifr_addr);
2819a68cc388SGleb Smirnoff 			NET_EPOCH_EXIT(et);
2820ec002feeSBruce M Simpson 			if (ifma != NULL)
2821ec002feeSBruce M Simpson 				error = EADDRINUSE;
2822ec002feeSBruce M Simpson 			else
2823477180fbSGarrett Wollman 				error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
2824477180fbSGarrett Wollman 		} else {
2825477180fbSGarrett Wollman 			error = if_delmulti(ifp, &ifr->ifr_addr);
2826477180fbSGarrett Wollman 		}
2827e39a0280SGary Palmer 		if (error == 0)
282898b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
2829f13ad206SJonathan Lemon 		break;
2830df8bae1dSRodney W. Grimes 
283141b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR:
283241b3e8e5SJun-ichiro itojun Hagino 	case SIOCDIFPHYADDR:
283341b3e8e5SJun-ichiro itojun Hagino #ifdef INET6
283441b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR_IN6:
283541b3e8e5SJun-ichiro itojun Hagino #endif
2836a912e453SPeter Wemm 	case SIOCSIFMEDIA:
2837d7189ec6SJoerg Wunsch 	case SIOCSIFGENERIC:
2838acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_HWIOCTL);
2839a912e453SPeter Wemm 		if (error)
2840a912e453SPeter Wemm 			return (error);
2841f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
2842a912e453SPeter Wemm 			return (EOPNOTSUPP);
2843a912e453SPeter Wemm 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2844a912e453SPeter Wemm 		if (error == 0)
284598b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
2846f13ad206SJonathan Lemon 		break;
2847a912e453SPeter Wemm 
2848413dd0baSPoul-Henning Kamp 	case SIOCGIFSTATUS:
284933841545SHajimu UMEMOTO 	case SIOCGIFPSRCADDR:
285033841545SHajimu UMEMOTO 	case SIOCGIFPDSTADDR:
2851a912e453SPeter Wemm 	case SIOCGIFMEDIA:
2852eb7e25b2SEric Joyner 	case SIOCGIFXMEDIA:
2853d7189ec6SJoerg Wunsch 	case SIOCGIFGENERIC:
28540f3af041SSepherosa Ziehau 	case SIOCGIFRSSKEY:
28550f3af041SSepherosa Ziehau 	case SIOCGIFRSSHASH:
2856247cf566SKonstantin Belousov 	case SIOCGIFDOWNREASON:
2857913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
2858a912e453SPeter Wemm 			return (EOPNOTSUPP);
2859f13ad206SJonathan Lemon 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2860f13ad206SJonathan Lemon 		break;
2861a912e453SPeter Wemm 
2862b106252cSBill Paul 	case SIOCSIFLLADDR:
2863acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETLLADDR);
2864b106252cSBill Paul 		if (error)
2865b106252cSBill Paul 			return (error);
2866f13ad206SJonathan Lemon 		error = if_setlladdr(ifp,
286766ce51ceSArchie Cobbs 		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
2868f13ad206SJonathan Lemon 		break;
286966ce51ceSArchie Cobbs 
2870ddae5750SRavi Pokala 	case SIOCGHWADDR:
2871ddae5750SRavi Pokala 		error = if_gethwaddr(ifp, ifr);
2872ddae5750SRavi Pokala 		break;
2873ddae5750SRavi Pokala 
2874bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCAIFGROUP):
2875acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_ADDIFGROUP);
28760dad3f0eSMax Laier 		if (error)
28770dad3f0eSMax Laier 			return (error);
2878756181b8SBrooks Davis 		if ((error = if_addgroup(ifp,
2879756181b8SBrooks Davis 		    ifgr_group_get((struct ifgroupreq *)data))))
28800dad3f0eSMax Laier 			return (error);
28810dad3f0eSMax Laier 		break;
28820dad3f0eSMax Laier 
2883bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCGIFGROUP):
2884b8a6e03fSGleb Smirnoff 	{
2885b8a6e03fSGleb Smirnoff 		struct epoch_tracker et;
2886b8a6e03fSGleb Smirnoff 
2887b8a6e03fSGleb Smirnoff 		NET_EPOCH_ENTER(et);
2888b8a6e03fSGleb Smirnoff 		error = if_getgroup((struct ifgroupreq *)data, ifp);
2889b8a6e03fSGleb Smirnoff 		NET_EPOCH_EXIT(et);
2890756181b8SBrooks Davis 		break;
2891b8a6e03fSGleb Smirnoff 	}
28920dad3f0eSMax Laier 
2893bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCDIFGROUP):
2894acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_DELIFGROUP);
28950dad3f0eSMax Laier 		if (error)
28960dad3f0eSMax Laier 			return (error);
2897756181b8SBrooks Davis 		if ((error = if_delgroup(ifp,
2898756181b8SBrooks Davis 		    ifgr_group_get((struct ifgroupreq *)data))))
28990dad3f0eSMax Laier 			return (error);
29000dad3f0eSMax Laier 		break;
29010dad3f0eSMax Laier 
2902df8bae1dSRodney W. Grimes 	default:
2903f13ad206SJonathan Lemon 		error = ENOIOCTL;
2904f13ad206SJonathan Lemon 		break;
2905f13ad206SJonathan Lemon 	}
2906f13ad206SJonathan Lemon 	return (error);
2907f13ad206SJonathan Lemon }
2908f13ad206SJonathan Lemon 
29099af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32
29109af74f3dSSergey Kandaurov struct ifconf32 {
29119af74f3dSSergey Kandaurov 	int32_t	ifc_len;
29129af74f3dSSergey Kandaurov 	union {
29139af74f3dSSergey Kandaurov 		uint32_t	ifcu_buf;
29149af74f3dSSergey Kandaurov 		uint32_t	ifcu_req;
29159af74f3dSSergey Kandaurov 	} ifc_ifcu;
29169af74f3dSSergey Kandaurov };
29179af74f3dSSergey Kandaurov #define	SIOCGIFCONF32	_IOWR('i', 36, struct ifconf32)
29189af74f3dSSergey Kandaurov #endif
29199af74f3dSSergey Kandaurov 
29203edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
29213edb7f4eSBrooks Davis static void
29223edb7f4eSBrooks Davis ifmr_init(struct ifmediareq *ifmr, caddr_t data)
29233edb7f4eSBrooks Davis {
29243edb7f4eSBrooks Davis 	struct ifmediareq32 *ifmr32;
29253edb7f4eSBrooks Davis 
29263edb7f4eSBrooks Davis 	ifmr32 = (struct ifmediareq32 *)data;
29273edb7f4eSBrooks Davis 	memcpy(ifmr->ifm_name, ifmr32->ifm_name,
29283edb7f4eSBrooks Davis 	    sizeof(ifmr->ifm_name));
29293edb7f4eSBrooks Davis 	ifmr->ifm_current = ifmr32->ifm_current;
29303edb7f4eSBrooks Davis 	ifmr->ifm_mask = ifmr32->ifm_mask;
29313edb7f4eSBrooks Davis 	ifmr->ifm_status = ifmr32->ifm_status;
29323edb7f4eSBrooks Davis 	ifmr->ifm_active = ifmr32->ifm_active;
29333edb7f4eSBrooks Davis 	ifmr->ifm_count = ifmr32->ifm_count;
29343edb7f4eSBrooks Davis 	ifmr->ifm_ulist = (int *)(uintptr_t)ifmr32->ifm_ulist;
29353edb7f4eSBrooks Davis }
29363edb7f4eSBrooks Davis 
29373edb7f4eSBrooks Davis static void
29383edb7f4eSBrooks Davis ifmr_update(const struct ifmediareq *ifmr, caddr_t data)
29393edb7f4eSBrooks Davis {
29403edb7f4eSBrooks Davis 	struct ifmediareq32 *ifmr32;
29413edb7f4eSBrooks Davis 
29423edb7f4eSBrooks Davis 	ifmr32 = (struct ifmediareq32 *)data;
29433edb7f4eSBrooks Davis 	ifmr32->ifm_current = ifmr->ifm_current;
29443edb7f4eSBrooks Davis 	ifmr32->ifm_mask = ifmr->ifm_mask;
29453edb7f4eSBrooks Davis 	ifmr32->ifm_status = ifmr->ifm_status;
29463edb7f4eSBrooks Davis 	ifmr32->ifm_active = ifmr->ifm_active;
29473edb7f4eSBrooks Davis 	ifmr32->ifm_count = ifmr->ifm_count;
29483edb7f4eSBrooks Davis }
29493edb7f4eSBrooks Davis #endif
29503edb7f4eSBrooks Davis 
2951f13ad206SJonathan Lemon /*
2952f13ad206SJonathan Lemon  * Interface ioctls.
2953f13ad206SJonathan Lemon  */
2954f13ad206SJonathan Lemon int
295572fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
2956f13ad206SJonathan Lemon {
29573edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
2958f6cb0deaSMatt Macy 	caddr_t saved_data = NULL;
29593edb7f4eSBrooks Davis 	struct ifmediareq ifmr;
2960b8a6e03fSGleb Smirnoff 	struct ifmediareq *ifmrp = NULL;
29612da19677SSean Bruno #endif
2962f13ad206SJonathan Lemon 	struct ifnet *ifp;
2963f13ad206SJonathan Lemon 	struct ifreq *ifr;
2964f13ad206SJonathan Lemon 	int error;
296562f76486SMaxim Sobolev 	int oif_flags;
296610108cb6SBjoern A. Zeeb #ifdef VIMAGE
296710108cb6SBjoern A. Zeeb 	bool shutdown;
296810108cb6SBjoern A. Zeeb #endif
2969f13ad206SJonathan Lemon 
29701fb51a12SBjoern A. Zeeb 	CURVNET_SET(so->so_vnet);
297189856f7eSBjoern A. Zeeb #ifdef VIMAGE
297289856f7eSBjoern A. Zeeb 	/* Make sure the VNET is stable. */
297310108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(so->so_vnet);
297410108cb6SBjoern A. Zeeb 	if (shutdown) {
297589856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
297689856f7eSBjoern A. Zeeb 		return (EBUSY);
297789856f7eSBjoern A. Zeeb 	}
297889856f7eSBjoern A. Zeeb #endif
297989856f7eSBjoern A. Zeeb 
2980f13ad206SJonathan Lemon 	switch (cmd) {
2981f13ad206SJonathan Lemon 	case SIOCGIFCONF:
29821fb51a12SBjoern A. Zeeb 		error = ifconf(cmd, data);
2983b8a6e03fSGleb Smirnoff 		goto out_noref;
29849af74f3dSSergey Kandaurov 
29859af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32
29869af74f3dSSergey Kandaurov 	case SIOCGIFCONF32:
29879af74f3dSSergey Kandaurov 		{
29889af74f3dSSergey Kandaurov 			struct ifconf32 *ifc32;
29899af74f3dSSergey Kandaurov 			struct ifconf ifc;
29909af74f3dSSergey Kandaurov 
29919af74f3dSSergey Kandaurov 			ifc32 = (struct ifconf32 *)data;
29929af74f3dSSergey Kandaurov 			ifc.ifc_len = ifc32->ifc_len;
29939af74f3dSSergey Kandaurov 			ifc.ifc_buf = PTRIN(ifc32->ifc_buf);
29949af74f3dSSergey Kandaurov 
29951fb51a12SBjoern A. Zeeb 			error = ifconf(SIOCGIFCONF, (void *)&ifc);
299623519598SSergey Kandaurov 			if (error == 0)
299723519598SSergey Kandaurov 				ifc32->ifc_len = ifc.ifc_len;
2998b8a6e03fSGleb Smirnoff 			goto out_noref;
29999af74f3dSSergey Kandaurov 		}
30009af74f3dSSergey Kandaurov #endif
3001f13ad206SJonathan Lemon 	}
3002f13ad206SJonathan Lemon 
30033edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
30043edb7f4eSBrooks Davis 	switch (cmd) {
30053edb7f4eSBrooks Davis 	case SIOCGIFMEDIA32:
30063edb7f4eSBrooks Davis 	case SIOCGIFXMEDIA32:
30073edb7f4eSBrooks Davis 		ifmrp = &ifmr;
30083edb7f4eSBrooks Davis 		ifmr_init(ifmrp, data);
30093edb7f4eSBrooks Davis 		cmd = _IOC_NEWTYPE(cmd, struct ifmediareq);
30103edb7f4eSBrooks Davis 		saved_data = data;
30113edb7f4eSBrooks Davis 		data = (caddr_t)ifmrp;
30123edb7f4eSBrooks Davis 	}
30133edb7f4eSBrooks Davis #endif
30143edb7f4eSBrooks Davis 
30153edb7f4eSBrooks Davis 	ifr = (struct ifreq *)data;
3016f13ad206SJonathan Lemon 	switch (cmd) {
3017feb08d06SMarko Zec #ifdef VIMAGE
3018679e1390SJamie Gritton 	case SIOCSIFRVNET:
3019679e1390SJamie Gritton 		error = priv_check(td, PRIV_NET_SETIFVNET);
30201fb51a12SBjoern A. Zeeb 		if (error == 0)
30211fb51a12SBjoern A. Zeeb 			error = if_vmove_reclaim(td, ifr->ifr_name,
30221fb51a12SBjoern A. Zeeb 			    ifr->ifr_jid);
30233edb7f4eSBrooks Davis 		goto out_noref;
3024feb08d06SMarko Zec #endif
3025f13ad206SJonathan Lemon 	case SIOCIFCREATE:
30266b7330e2SSam Leffler 	case SIOCIFCREATE2:
3027acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_IFCREATE);
30281fb51a12SBjoern A. Zeeb 		if (error == 0)
30291fb51a12SBjoern A. Zeeb 			error = if_clone_create(ifr->ifr_name,
3030541d96aaSBrooks Davis 			    sizeof(ifr->ifr_name), cmd == SIOCIFCREATE2 ?
3031541d96aaSBrooks Davis 			    ifr_data_get_ptr(ifr) : NULL);
30323edb7f4eSBrooks Davis 		goto out_noref;
3033f13ad206SJonathan Lemon 	case SIOCIFDESTROY:
3034acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_IFDESTROY);
3035e133271fSKristof Provost 
3036e133271fSKristof Provost 		if (error == 0) {
30376d2a10d9SKristof Provost 			sx_xlock(&ifnet_detach_sxlock);
30381fb51a12SBjoern A. Zeeb 			error = if_clone_destroy(ifr->ifr_name);
30396d2a10d9SKristof Provost 			sx_xunlock(&ifnet_detach_sxlock);
3040e133271fSKristof Provost 		}
30413edb7f4eSBrooks Davis 		goto out_noref;
3042f13ad206SJonathan Lemon 
3043f13ad206SJonathan Lemon 	case SIOCIFGCLONERS:
30441fb51a12SBjoern A. Zeeb 		error = if_clone_list((struct if_clonereq *)data);
30453edb7f4eSBrooks Davis 		goto out_noref;
30463edb7f4eSBrooks Davis 
3047bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCGIFGMEMB):
30481fb51a12SBjoern A. Zeeb 		error = if_getgroupmembers((struct ifgroupreq *)data);
30493edb7f4eSBrooks Davis 		goto out_noref;
30503edb7f4eSBrooks Davis 
305108b68b0eSGleb Smirnoff #if defined(INET) || defined(INET6)
305208b68b0eSGleb Smirnoff 	case SIOCSVH:
305308b68b0eSGleb Smirnoff 	case SIOCGVH:
305408b68b0eSGleb Smirnoff 		if (carp_ioctl_p == NULL)
305508b68b0eSGleb Smirnoff 			error = EPROTONOSUPPORT;
305608b68b0eSGleb Smirnoff 		else
305708b68b0eSGleb Smirnoff 			error = (*carp_ioctl_p)(ifr, cmd, td);
30583edb7f4eSBrooks Davis 		goto out_noref;
305908b68b0eSGleb Smirnoff #endif
3060f13ad206SJonathan Lemon 	}
3061f13ad206SJonathan Lemon 
30626064c5d3SRobert Watson 	ifp = ifunit_ref(ifr->ifr_name);
30631fb51a12SBjoern A. Zeeb 	if (ifp == NULL) {
30643edb7f4eSBrooks Davis 		error = ENXIO;
30653edb7f4eSBrooks Davis 		goto out_noref;
30661fb51a12SBjoern A. Zeeb 	}
3067f13ad206SJonathan Lemon 
3068f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
30693edb7f4eSBrooks Davis 	if (error != ENOIOCTL)
30703edb7f4eSBrooks Davis 		goto out_ref;
3071f13ad206SJonathan Lemon 
307282cd038dSYoshinobu Inoue 	oif_flags = ifp->if_flags;
30736064c5d3SRobert Watson 	if (so->so_proto == NULL) {
30743edb7f4eSBrooks Davis 		error = EOPNOTSUPP;
30753edb7f4eSBrooks Davis 		goto out_ref;
30766064c5d3SRobert Watson 	}
30771a05c762SDag-Erling Smørgrav 
30781a05c762SDag-Erling Smørgrav 	/*
30791a05c762SDag-Erling Smørgrav 	 * Pass the request on to the socket control method, and if the
30801a05c762SDag-Erling Smørgrav 	 * latter returns EOPNOTSUPP, directly to the interface.
30811a05c762SDag-Erling Smørgrav 	 *
30821a05c762SDag-Erling Smørgrav 	 * Make an exception for the legacy SIOCSIF* requests.  Drivers
30831a05c762SDag-Erling Smørgrav 	 * trust SIOCSIFADDR et al to come from an already privileged
30841a05c762SDag-Erling Smørgrav 	 * layer, and do not perform any credentials checks or input
30851a05c762SDag-Erling Smørgrav 	 * validation.
30861a05c762SDag-Erling Smørgrav 	 */
30875fb009bdSGleb Smirnoff 	error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data,
3088b40ce416SJulian Elischer 	    ifp, td));
30891a05c762SDag-Erling Smørgrav 	if (error == EOPNOTSUPP && ifp != NULL && ifp->if_ioctl != NULL &&
30901a05c762SDag-Erling Smørgrav 	    cmd != SIOCSIFADDR && cmd != SIOCSIFBRDADDR &&
30911a05c762SDag-Erling Smørgrav 	    cmd != SIOCSIFDSTADDR && cmd != SIOCSIFNETMASK)
3092bc3977f1SJamie Gritton 		error = (*ifp->if_ioctl)(ifp, cmd, data);
309382cd038dSYoshinobu Inoue 
309482cd038dSYoshinobu Inoue 	if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
309582cd038dSYoshinobu Inoue #ifdef INET6
3096c9b652e3SAndre Oppermann 		if (ifp->if_flags & IFF_UP)
309782cd038dSYoshinobu Inoue 			in6_if_up(ifp);
309882cd038dSYoshinobu Inoue #endif
3099df8bae1dSRodney W. Grimes 	}
31003edb7f4eSBrooks Davis 
31013edb7f4eSBrooks Davis out_ref:
31026064c5d3SRobert Watson 	if_rele(ifp);
31033edb7f4eSBrooks Davis out_noref:
31043edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
31053edb7f4eSBrooks Davis 	if (ifmrp != NULL) {
31063edb7f4eSBrooks Davis 		KASSERT((cmd == SIOCGIFMEDIA || cmd == SIOCGIFXMEDIA),
31073edb7f4eSBrooks Davis 		    ("ifmrp non-NULL, but cmd is not an ifmedia req 0x%lx",
31083edb7f4eSBrooks Davis 		     cmd));
31093edb7f4eSBrooks Davis 		data = saved_data;
31103edb7f4eSBrooks Davis 		ifmr_update(ifmrp, data);
31113edb7f4eSBrooks Davis 	}
31123edb7f4eSBrooks Davis #endif
31131fb51a12SBjoern A. Zeeb 	CURVNET_RESTORE();
3114df8bae1dSRodney W. Grimes 	return (error);
3115df8bae1dSRodney W. Grimes }
3116df8bae1dSRodney W. Grimes 
3117df8bae1dSRodney W. Grimes /*
3118292ee7beSRobert Watson  * The code common to handling reference counted flags,
31191a3b6859SYaroslav Tykhiy  * e.g., in ifpromisc() and if_allmulti().
3120b5c8bd59SYaroslav Tykhiy  * The "pflag" argument can specify a permanent mode flag to check,
31211a3b6859SYaroslav Tykhiy  * such as IFF_PPROMISC for promiscuous mode; should be 0 if none.
3122292ee7beSRobert Watson  *
3123292ee7beSRobert Watson  * Only to be used on stack-owned flags, not driver-owned flags.
31241a3b6859SYaroslav Tykhiy  */
31251a3b6859SYaroslav Tykhiy static int
31261a3b6859SYaroslav Tykhiy if_setflag(struct ifnet *ifp, int flag, int pflag, int *refcount, int onswitch)
31271a3b6859SYaroslav Tykhiy {
31281a3b6859SYaroslav Tykhiy 	struct ifreq ifr;
31291a3b6859SYaroslav Tykhiy 	int error;
31301a3b6859SYaroslav Tykhiy 	int oldflags, oldcount;
31311a3b6859SYaroslav Tykhiy 
31321a3b6859SYaroslav Tykhiy 	/* Sanity checks to catch programming errors */
3133b5c8bd59SYaroslav Tykhiy 	KASSERT((flag & (IFF_DRV_OACTIVE|IFF_DRV_RUNNING)) == 0,
3134b5c8bd59SYaroslav Tykhiy 	    ("%s: setting driver-owned flag %d", __func__, flag));
3135b5c8bd59SYaroslav Tykhiy 
3136b5c8bd59SYaroslav Tykhiy 	if (onswitch)
3137b5c8bd59SYaroslav Tykhiy 		KASSERT(*refcount >= 0,
3138b5c8bd59SYaroslav Tykhiy 		    ("%s: increment negative refcount %d for flag %d",
3139b5c8bd59SYaroslav Tykhiy 		    __func__, *refcount, flag));
3140b5c8bd59SYaroslav Tykhiy 	else
3141b5c8bd59SYaroslav Tykhiy 		KASSERT(*refcount > 0,
3142b5c8bd59SYaroslav Tykhiy 		    ("%s: decrement non-positive refcount %d for flag %d",
3143b5c8bd59SYaroslav Tykhiy 		    __func__, *refcount, flag));
31441a3b6859SYaroslav Tykhiy 
31451a3b6859SYaroslav Tykhiy 	/* In case this mode is permanent, just touch refcount */
31461a3b6859SYaroslav Tykhiy 	if (ifp->if_flags & pflag) {
31471a3b6859SYaroslav Tykhiy 		*refcount += onswitch ? 1 : -1;
31481a3b6859SYaroslav Tykhiy 		return (0);
31491a3b6859SYaroslav Tykhiy 	}
31501a3b6859SYaroslav Tykhiy 
31511a3b6859SYaroslav Tykhiy 	/* Save ifnet parameters for if_ioctl() may fail */
31521a3b6859SYaroslav Tykhiy 	oldcount = *refcount;
31531a3b6859SYaroslav Tykhiy 	oldflags = ifp->if_flags;
31541a3b6859SYaroslav Tykhiy 
31551a3b6859SYaroslav Tykhiy 	/*
31561a3b6859SYaroslav Tykhiy 	 * See if we aren't the only and touching refcount is enough.
31571a3b6859SYaroslav Tykhiy 	 * Actually toggle interface flag if we are the first or last.
31581a3b6859SYaroslav Tykhiy 	 */
31591a3b6859SYaroslav Tykhiy 	if (onswitch) {
31601a3b6859SYaroslav Tykhiy 		if ((*refcount)++)
31611a3b6859SYaroslav Tykhiy 			return (0);
31621a3b6859SYaroslav Tykhiy 		ifp->if_flags |= flag;
31631a3b6859SYaroslav Tykhiy 	} else {
31641a3b6859SYaroslav Tykhiy 		if (--(*refcount))
31651a3b6859SYaroslav Tykhiy 			return (0);
31661a3b6859SYaroslav Tykhiy 		ifp->if_flags &= ~flag;
31671a3b6859SYaroslav Tykhiy 	}
31681a3b6859SYaroslav Tykhiy 
31691a3b6859SYaroslav Tykhiy 	/* Call down the driver since we've changed interface flags */
31701a3b6859SYaroslav Tykhiy 	if (ifp->if_ioctl == NULL) {
31711a3b6859SYaroslav Tykhiy 		error = EOPNOTSUPP;
31721a3b6859SYaroslav Tykhiy 		goto recover;
31731a3b6859SYaroslav Tykhiy 	}
31741a3b6859SYaroslav Tykhiy 	ifr.ifr_flags = ifp->if_flags & 0xffff;
31751a3b6859SYaroslav Tykhiy 	ifr.ifr_flagshigh = ifp->if_flags >> 16;
31761a3b6859SYaroslav Tykhiy 	error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
31771a3b6859SYaroslav Tykhiy 	if (error)
31781a3b6859SYaroslav Tykhiy 		goto recover;
31791a3b6859SYaroslav Tykhiy 	/* Notify userland that interface flags have changed */
31801a3b6859SYaroslav Tykhiy 	rt_ifmsg(ifp);
31811a3b6859SYaroslav Tykhiy 	return (0);
31821a3b6859SYaroslav Tykhiy 
31831a3b6859SYaroslav Tykhiy recover:
31841a3b6859SYaroslav Tykhiy 	/* Recover after driver error */
31851a3b6859SYaroslav Tykhiy 	*refcount = oldcount;
31861a3b6859SYaroslav Tykhiy 	ifp->if_flags = oldflags;
31871a3b6859SYaroslav Tykhiy 	return (error);
31881a3b6859SYaroslav Tykhiy }
31891a3b6859SYaroslav Tykhiy 
31901a3b6859SYaroslav Tykhiy /*
3191963e4c2aSGarrett Wollman  * Set/clear promiscuous mode on interface ifp based on the truth value
3192963e4c2aSGarrett Wollman  * of pswitch.  The calls are reference counted so that only the first
3193963e4c2aSGarrett Wollman  * "on" request actually has an effect, as does the final "off" request.
3194963e4c2aSGarrett Wollman  * Results are undefined if the "off" and "on" requests are not matched.
3195963e4c2aSGarrett Wollman  */
3196963e4c2aSGarrett Wollman int
319772fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch)
3198963e4c2aSGarrett Wollman {
31994a26224cSGarrett Wollman 	int error;
32001a3b6859SYaroslav Tykhiy 	int oldflags = ifp->if_flags;
3201963e4c2aSGarrett Wollman 
32021a3b6859SYaroslav Tykhiy 	error = if_setflag(ifp, IFF_PROMISC, IFF_PPROMISC,
32031a3b6859SYaroslav Tykhiy 			   &ifp->if_pcount, pswitch);
32041a3b6859SYaroslav Tykhiy 	/* If promiscuous mode status has changed, log a message */
32056d07c157SNick Hibma 	if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC) &&
32066d07c157SNick Hibma             log_promisc_mode_change)
320720f8d7bcSDag-Erling Smørgrav 		if_printf(ifp, "promiscuous mode %s\n",
32084f3c11a6SBill Fenner 		    (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
32091a3b6859SYaroslav Tykhiy 	return (error);
3210963e4c2aSGarrett Wollman }
3211963e4c2aSGarrett Wollman 
3212963e4c2aSGarrett Wollman /*
3213df8bae1dSRodney W. Grimes  * Return interface configuration
3214df8bae1dSRodney W. Grimes  * of system.  List may be used
3215df8bae1dSRodney W. Grimes  * in later ioctl's (above) to get
3216df8bae1dSRodney W. Grimes  * other information.
3217df8bae1dSRodney W. Grimes  */
3218df8bae1dSRodney W. Grimes /*ARGSUSED*/
32193bda9f9bSPoul-Henning Kamp static int
322072fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data)
3221df8bae1dSRodney W. Grimes {
32220b59d917SJonathan Lemon 	struct ifconf *ifc = (struct ifconf *)data;
32230b59d917SJonathan Lemon 	struct ifnet *ifp;
32240b59d917SJonathan Lemon 	struct ifaddr *ifa;
32254dcf2bbbSBrooks Davis 	struct ifreq ifr;
32264dcf2bbbSBrooks Davis 	struct sbuf *sb;
32274dcf2bbbSBrooks Davis 	int error, full = 0, valid_len, max_len;
3228df8bae1dSRodney W. Grimes 
3229cd853791SKonstantin Belousov 	/* Limit initial buffer size to maxphys to avoid DoS from userspace. */
3230cd853791SKonstantin Belousov 	max_len = maxphys - 1;
32314dcf2bbbSBrooks Davis 
3232b0b4b28bSXin LI 	/* Prevent hostile input from being able to crash the system */
3233b0b4b28bSXin LI 	if (ifc->ifc_len <= 0)
3234b0b4b28bSXin LI 		return (EINVAL);
3235b0b4b28bSXin LI 
32364dcf2bbbSBrooks Davis again:
32374dcf2bbbSBrooks Davis 	if (ifc->ifc_len <= max_len) {
32384dcf2bbbSBrooks Davis 		max_len = ifc->ifc_len;
32394dcf2bbbSBrooks Davis 		full = 1;
32404dcf2bbbSBrooks Davis 	}
32414dcf2bbbSBrooks Davis 	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
32424dcf2bbbSBrooks Davis 	max_len = 0;
32434dcf2bbbSBrooks Davis 	valid_len = 0;
32444dcf2bbbSBrooks Davis 
324577dfcdc4SRobert Watson 	IFNET_RLOCK();
32464f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
3247a68cc388SGleb Smirnoff 		struct epoch_tracker et;
32489bf40edeSBrooks Davis 		int addrs;
32492624cf89SGarrett Wollman 
3250fbd24c5eSColin Percival 		/*
32512443045fSBrooks Davis 		 * Zero the ifr to make sure we don't disclose the contents
32522443045fSBrooks Davis 		 * of the stack.
3253fbd24c5eSColin Percival 		 */
32542443045fSBrooks Davis 		memset(&ifr, 0, sizeof(ifr));
3255fbd24c5eSColin Percival 
32569bf40edeSBrooks Davis 		if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name))
325762313e4cSSam Leffler 		    >= sizeof(ifr.ifr_name)) {
325862313e4cSSam Leffler 			sbuf_delete(sb);
325962313e4cSSam Leffler 			IFNET_RUNLOCK();
32604dcf2bbbSBrooks Davis 			return (ENAMETOOLONG);
326162313e4cSSam Leffler 		}
32622624cf89SGarrett Wollman 
326375c13541SPoul-Henning Kamp 		addrs = 0;
3264a68cc388SGleb Smirnoff 		NET_EPOCH_ENTER(et);
3265d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
32662defe5cdSJonathan Lemon 			struct sockaddr *sa = ifa->ifa_addr;
32672defe5cdSJonathan Lemon 
3268b89e82ddSJamie Gritton 			if (prison_if(curthread->td_ucred, sa) != 0)
326975c13541SPoul-Henning Kamp 				continue;
327075c13541SPoul-Henning Kamp 			addrs++;
3271df8bae1dSRodney W. Grimes 			if (sa->sa_len <= sizeof(*sa)) {
3272e7fdc72eSBrooks Davis 				if (sa->sa_len < sizeof(*sa)) {
3273e7fdc72eSBrooks Davis 					memset(&ifr.ifr_ifru.ifru_addr, 0,
3274e7fdc72eSBrooks Davis 					    sizeof(ifr.ifr_ifru.ifru_addr));
3275e7fdc72eSBrooks Davis 					memcpy(&ifr.ifr_ifru.ifru_addr, sa,
3276e7fdc72eSBrooks Davis 					    sa->sa_len);
3277e7fdc72eSBrooks Davis 				} else
3278e7fdc72eSBrooks Davis 					ifr.ifr_ifru.ifru_addr = *sa;
32794dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
32804dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
3281df8bae1dSRodney W. Grimes 			} else {
32824dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr,
32834dcf2bbbSBrooks Davis 				    offsetof(struct ifreq, ifr_addr));
32844dcf2bbbSBrooks Davis 				max_len += offsetof(struct ifreq, ifr_addr);
32854dcf2bbbSBrooks Davis 				sbuf_bcat(sb, sa, sa->sa_len);
32864dcf2bbbSBrooks Davis 				max_len += sa->sa_len;
3287df8bae1dSRodney W. Grimes 			}
32884dcf2bbbSBrooks Davis 
32894d369413SMatthew D Fleming 			if (sbuf_error(sb) == 0)
32904dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
3291df8bae1dSRodney W. Grimes 		}
3292a68cc388SGleb Smirnoff 		NET_EPOCH_EXIT(et);
32934dcf2bbbSBrooks Davis 		if (addrs == 0) {
32944dcf2bbbSBrooks Davis 			sbuf_bcat(sb, &ifr, sizeof(ifr));
32954dcf2bbbSBrooks Davis 			max_len += sizeof(ifr);
32964dcf2bbbSBrooks Davis 
32974d369413SMatthew D Fleming 			if (sbuf_error(sb) == 0)
32984dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
329975c13541SPoul-Henning Kamp 		}
3300df8bae1dSRodney W. Grimes 	}
3301b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
33024dcf2bbbSBrooks Davis 
33034dcf2bbbSBrooks Davis 	/*
33044dcf2bbbSBrooks Davis 	 * If we didn't allocate enough space (uncommon), try again.  If
33054dcf2bbbSBrooks Davis 	 * we have already allocated as much space as we are allowed,
33064dcf2bbbSBrooks Davis 	 * return what we've got.
33074dcf2bbbSBrooks Davis 	 */
33084dcf2bbbSBrooks Davis 	if (valid_len != max_len && !full) {
33094dcf2bbbSBrooks Davis 		sbuf_delete(sb);
33104dcf2bbbSBrooks Davis 		goto again;
33114dcf2bbbSBrooks Davis 	}
33124dcf2bbbSBrooks Davis 
33134dcf2bbbSBrooks Davis 	ifc->ifc_len = valid_len;
33145ed8cedcSBrian Feldman 	sbuf_finish(sb);
33154dcf2bbbSBrooks Davis 	error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len);
33164dcf2bbbSBrooks Davis 	sbuf_delete(sb);
3317df8bae1dSRodney W. Grimes 	return (error);
3318df8bae1dSRodney W. Grimes }
3319df8bae1dSRodney W. Grimes 
33201158dfb7SGarrett Wollman /*
33218b25904eSGleb Smirnoff  * Just like ifpromisc(), but for all-multicast-reception mode.
33221158dfb7SGarrett Wollman  */
33231158dfb7SGarrett Wollman int
332472fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch)
33251158dfb7SGarrett Wollman {
33261158dfb7SGarrett Wollman 
33271a3b6859SYaroslav Tykhiy 	return (if_setflag(ifp, IFF_ALLMULTI, 0, &ifp->if_amcount, onswitch));
33281158dfb7SGarrett Wollman }
33291158dfb7SGarrett Wollman 
33305896d124SBruce M Simpson struct ifmultiaddr *
3331441f9243SAlexander V. Chernikov if_findmulti(struct ifnet *ifp, const struct sockaddr *sa)
33321158dfb7SGarrett Wollman {
33331158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
33341158dfb7SGarrett Wollman 
3335c3b31afdSRobert Watson 	IF_ADDR_LOCK_ASSERT(ifp);
3336c3b31afdSRobert Watson 
3337d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
333840d8a302SBruce M Simpson 		if (sa->sa_family == AF_LINK) {
333940d8a302SBruce M Simpson 			if (sa_dl_equal(ifma->ifma_addr, sa))
334040d8a302SBruce M Simpson 				break;
334140d8a302SBruce M Simpson 		} else {
3342c3b31afdSRobert Watson 			if (sa_equal(ifma->ifma_addr, sa))
3343c3b31afdSRobert Watson 				break;
33441158dfb7SGarrett Wollman 		}
334540d8a302SBruce M Simpson 	}
3346c3b31afdSRobert Watson 
3347c3b31afdSRobert Watson 	return ifma;
334857af7922SJulian Elischer }
33491158dfb7SGarrett Wollman 
33501158dfb7SGarrett Wollman /*
3351c3b31afdSRobert Watson  * Allocate a new ifmultiaddr and initialize based on passed arguments.  We
3352c3b31afdSRobert Watson  * make copies of passed sockaddrs.  The ifmultiaddr will not be added to
3353c3b31afdSRobert Watson  * the ifnet multicast address list here, so the caller must do that and
3354c3b31afdSRobert Watson  * other setup work (such as notifying the device driver).  The reference
3355c3b31afdSRobert Watson  * count is initialized to 1.
33561158dfb7SGarrett Wollman  */
3357c3b31afdSRobert Watson static struct ifmultiaddr *
3358c3b31afdSRobert Watson if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa,
3359c3b31afdSRobert Watson     int mflags)
3360c3b31afdSRobert Watson {
3361c3b31afdSRobert Watson 	struct ifmultiaddr *ifma;
3362c3b31afdSRobert Watson 	struct sockaddr *dupsa;
3363c3b31afdSRobert Watson 
33641ede983cSDag-Erling Smørgrav 	ifma = malloc(sizeof *ifma, M_IFMADDR, mflags |
3365c3b31afdSRobert Watson 	    M_ZERO);
3366c3b31afdSRobert Watson 	if (ifma == NULL)
3367c3b31afdSRobert Watson 		return (NULL);
3368c3b31afdSRobert Watson 
33691ede983cSDag-Erling Smørgrav 	dupsa = malloc(sa->sa_len, M_IFMADDR, mflags);
3370c3b31afdSRobert Watson 	if (dupsa == NULL) {
33711ede983cSDag-Erling Smørgrav 		free(ifma, M_IFMADDR);
3372c3b31afdSRobert Watson 		return (NULL);
33731158dfb7SGarrett Wollman 	}
33741158dfb7SGarrett Wollman 	bcopy(sa, dupsa, sa->sa_len);
33751158dfb7SGarrett Wollman 	ifma->ifma_addr = dupsa;
3376c3b31afdSRobert Watson 
33771158dfb7SGarrett Wollman 	ifma->ifma_ifp = ifp;
33781158dfb7SGarrett Wollman 	ifma->ifma_refcount = 1;
3379d4d22970SGleb Smirnoff 	ifma->ifma_protospec = NULL;
3380c3b31afdSRobert Watson 
3381c3b31afdSRobert Watson 	if (llsa == NULL) {
3382c3b31afdSRobert Watson 		ifma->ifma_lladdr = NULL;
3383c3b31afdSRobert Watson 		return (ifma);
3384c3b31afdSRobert Watson 	}
3385c3b31afdSRobert Watson 
33861ede983cSDag-Erling Smørgrav 	dupsa = malloc(llsa->sa_len, M_IFMADDR, mflags);
3387c3b31afdSRobert Watson 	if (dupsa == NULL) {
33881ede983cSDag-Erling Smørgrav 		free(ifma->ifma_addr, M_IFMADDR);
33891ede983cSDag-Erling Smørgrav 		free(ifma, M_IFMADDR);
3390c3b31afdSRobert Watson 		return (NULL);
3391c3b31afdSRobert Watson 	}
3392c3b31afdSRobert Watson 	bcopy(llsa, dupsa, llsa->sa_len);
3393c3b31afdSRobert Watson 	ifma->ifma_lladdr = dupsa;
3394c3b31afdSRobert Watson 
3395c3b31afdSRobert Watson 	return (ifma);
3396c3b31afdSRobert Watson }
3397373f88edSGarrett Wollman 
33981158dfb7SGarrett Wollman /*
3399c3b31afdSRobert Watson  * if_freemulti: free ifmultiaddr structure and possibly attached related
3400c3b31afdSRobert Watson  * addresses.  The caller is responsible for implementing reference
3401c3b31afdSRobert Watson  * counting, notifying the driver, handling routing messages, and releasing
3402c3b31afdSRobert Watson  * any dependent link layer state.
34031158dfb7SGarrett Wollman  */
3404b6f6f880SMatt Macy #ifdef MCAST_VERBOSE
3405b6f6f880SMatt Macy extern void kdb_backtrace(void);
3406b6f6f880SMatt Macy #endif
3407d7c5a620SMatt Macy static void
3408d7c5a620SMatt Macy if_freemulti_internal(struct ifmultiaddr *ifma)
3409c3b31afdSRobert Watson {
3410c3b31afdSRobert Watson 
3411ec002feeSBruce M Simpson 	KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d",
3412c3b31afdSRobert Watson 	    ifma->ifma_refcount));
3413c3b31afdSRobert Watson 
3414c3b31afdSRobert Watson 	if (ifma->ifma_lladdr != NULL)
34151ede983cSDag-Erling Smørgrav 		free(ifma->ifma_lladdr, M_IFMADDR);
3416b6f6f880SMatt Macy #ifdef MCAST_VERBOSE
3417b6f6f880SMatt Macy 	kdb_backtrace();
3418b6f6f880SMatt Macy 	printf("%s freeing ifma: %p\n", __func__, ifma);
3419b6f6f880SMatt Macy #endif
34201ede983cSDag-Erling Smørgrav 	free(ifma->ifma_addr, M_IFMADDR);
34211ede983cSDag-Erling Smørgrav 	free(ifma, M_IFMADDR);
3422c3b31afdSRobert Watson }
3423c3b31afdSRobert Watson 
3424d7c5a620SMatt Macy static void
3425d7c5a620SMatt Macy if_destroymulti(epoch_context_t ctx)
3426d7c5a620SMatt Macy {
3427d7c5a620SMatt Macy 	struct ifmultiaddr *ifma;
3428d7c5a620SMatt Macy 
3429d7c5a620SMatt Macy 	ifma = __containerof(ctx, struct ifmultiaddr, ifma_epoch_ctx);
3430d7c5a620SMatt Macy 	if_freemulti_internal(ifma);
3431d7c5a620SMatt Macy }
3432d7c5a620SMatt Macy 
3433d7c5a620SMatt Macy void
3434d7c5a620SMatt Macy if_freemulti(struct ifmultiaddr *ifma)
3435d7c5a620SMatt Macy {
3436d7c5a620SMatt Macy 	KASSERT(ifma->ifma_refcount == 0, ("if_freemulti_epoch: refcount %d",
3437d7c5a620SMatt Macy 	    ifma->ifma_refcount));
3438d7c5a620SMatt Macy 
34392a4bd982SGleb Smirnoff 	NET_EPOCH_CALL(if_destroymulti, &ifma->ifma_epoch_ctx);
3440d7c5a620SMatt Macy }
3441d7c5a620SMatt Macy 
3442c3b31afdSRobert Watson /*
3443c3b31afdSRobert Watson  * Register an additional multicast address with a network interface.
3444c3b31afdSRobert Watson  *
3445c3b31afdSRobert Watson  * - If the address is already present, bump the reference count on the
3446c3b31afdSRobert Watson  *   address and return.
3447c3b31afdSRobert Watson  * - If the address is not link-layer, look up a link layer address.
3448c3b31afdSRobert Watson  * - Allocate address structures for one or both addresses, and attach to the
3449c3b31afdSRobert Watson  *   multicast address list on the interface.  If automatically adding a link
3450c3b31afdSRobert Watson  *   layer address, the protocol address will own a reference to the link
3451c3b31afdSRobert Watson  *   layer address, to be freed when it is freed.
3452c3b31afdSRobert Watson  * - Notify the network device driver of an addition to the multicast address
3453c3b31afdSRobert Watson  *   list.
3454c3b31afdSRobert Watson  *
3455c3b31afdSRobert Watson  * 'sa' points to caller-owned memory with the desired multicast address.
3456c3b31afdSRobert Watson  *
3457c3b31afdSRobert Watson  * 'retifma' will be used to return a pointer to the resulting multicast
3458c3b31afdSRobert Watson  * address reference, if desired.
3459c3b31afdSRobert Watson  */
3460c3b31afdSRobert Watson int
3461c3b31afdSRobert Watson if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
3462c3b31afdSRobert Watson     struct ifmultiaddr **retifma)
3463c3b31afdSRobert Watson {
3464c3b31afdSRobert Watson 	struct ifmultiaddr *ifma, *ll_ifma;
3465c3b31afdSRobert Watson 	struct sockaddr *llsa;
346695fbe4d0SAlexander V. Chernikov 	struct sockaddr_dl sdl;
3467c3b31afdSRobert Watson 	int error;
3468c3b31afdSRobert Watson 
3469f3e1324bSStephen Hurd #ifdef INET
3470f3e1324bSStephen Hurd 	IN_MULTI_LIST_UNLOCK_ASSERT();
3471f3e1324bSStephen Hurd #endif
3472f3e1324bSStephen Hurd #ifdef INET6
3473f3e1324bSStephen Hurd 	IN6_MULTI_LIST_UNLOCK_ASSERT();
3474f3e1324bSStephen Hurd #endif
3475c3b31afdSRobert Watson 	/*
3476c3b31afdSRobert Watson 	 * If the address is already present, return a new reference to it;
3477c3b31afdSRobert Watson 	 * otherwise, allocate storage and set up a new address.
3478c3b31afdSRobert Watson 	 */
3479137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
3480c3b31afdSRobert Watson 	ifma = if_findmulti(ifp, sa);
3481c3b31afdSRobert Watson 	if (ifma != NULL) {
3482c3b31afdSRobert Watson 		ifma->ifma_refcount++;
3483c3b31afdSRobert Watson 		if (retifma != NULL)
3484c3b31afdSRobert Watson 			*retifma = ifma;
3485137f91e8SJohn Baldwin 		IF_ADDR_WUNLOCK(ifp);
3486c3b31afdSRobert Watson 		return (0);
3487c3b31afdSRobert Watson 	}
3488c3b31afdSRobert Watson 
3489c3b31afdSRobert Watson 	/*
3490c3b31afdSRobert Watson 	 * The address isn't already present; resolve the protocol address
3491c3b31afdSRobert Watson 	 * into a link layer address, and then look that up, bump its
349295fbe4d0SAlexander V. Chernikov 	 * refcount or allocate an ifma for that also.
349395fbe4d0SAlexander V. Chernikov 	 * Most link layer resolving functions returns address data which
349495fbe4d0SAlexander V. Chernikov 	 * fits inside default sockaddr_dl structure. However callback
349595fbe4d0SAlexander V. Chernikov 	 * can allocate another sockaddr structure, in that case we need to
349695fbe4d0SAlexander V. Chernikov 	 * free it later.
3497c3b31afdSRobert Watson 	 */
3498c3b31afdSRobert Watson 	llsa = NULL;
3499c3b31afdSRobert Watson 	ll_ifma = NULL;
3500c3b31afdSRobert Watson 	if (ifp->if_resolvemulti != NULL) {
350195fbe4d0SAlexander V. Chernikov 		/* Provide called function with buffer size information */
350295fbe4d0SAlexander V. Chernikov 		sdl.sdl_len = sizeof(sdl);
350395fbe4d0SAlexander V. Chernikov 		llsa = (struct sockaddr *)&sdl;
3504c3b31afdSRobert Watson 		error = ifp->if_resolvemulti(ifp, &llsa, sa);
3505c3b31afdSRobert Watson 		if (error)
3506c3b31afdSRobert Watson 			goto unlock_out;
3507c3b31afdSRobert Watson 	}
3508c3b31afdSRobert Watson 
3509c3b31afdSRobert Watson 	/*
3510c3b31afdSRobert Watson 	 * Allocate the new address.  Don't hook it up yet, as we may also
3511c3b31afdSRobert Watson 	 * need to allocate a link layer multicast address.
3512c3b31afdSRobert Watson 	 */
3513c3b31afdSRobert Watson 	ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT);
3514c3b31afdSRobert Watson 	if (ifma == NULL) {
3515c3b31afdSRobert Watson 		error = ENOMEM;
3516c3b31afdSRobert Watson 		goto free_llsa_out;
3517c3b31afdSRobert Watson 	}
3518c3b31afdSRobert Watson 
3519c3b31afdSRobert Watson 	/*
3520c3b31afdSRobert Watson 	 * If a link layer address is found, we'll need to see if it's
3521c3b31afdSRobert Watson 	 * already present in the address list, or allocate is as well.
3522c3b31afdSRobert Watson 	 * When this block finishes, the link layer address will be on the
3523c3b31afdSRobert Watson 	 * list.
3524c3b31afdSRobert Watson 	 */
3525c3b31afdSRobert Watson 	if (llsa != NULL) {
3526c3b31afdSRobert Watson 		ll_ifma = if_findmulti(ifp, llsa);
3527c3b31afdSRobert Watson 		if (ll_ifma == NULL) {
3528c3b31afdSRobert Watson 			ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT);
3529c3b31afdSRobert Watson 			if (ll_ifma == NULL) {
3530ec002feeSBruce M Simpson 				--ifma->ifma_refcount;
3531c3b31afdSRobert Watson 				if_freemulti(ifma);
3532c3b31afdSRobert Watson 				error = ENOMEM;
3533c3b31afdSRobert Watson 				goto free_llsa_out;
3534c3b31afdSRobert Watson 			}
3535f9be0386SMatt Macy 			ll_ifma->ifma_flags |= IFMA_F_ENQUEUED;
3536d7c5a620SMatt Macy 			CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma,
3537c3b31afdSRobert Watson 			    ifma_link);
3538c3b31afdSRobert Watson 		} else
3539c3b31afdSRobert Watson 			ll_ifma->ifma_refcount++;
3540ec002feeSBruce M Simpson 		ifma->ifma_llifma = ll_ifma;
3541c3b31afdSRobert Watson 	}
3542c3b31afdSRobert Watson 
3543c3b31afdSRobert Watson 	/*
3544c3b31afdSRobert Watson 	 * We now have a new multicast address, ifma, and possibly a new or
3545c3b31afdSRobert Watson 	 * referenced link layer address.  Add the primary address to the
3546c3b31afdSRobert Watson 	 * ifnet address list.
3547c3b31afdSRobert Watson 	 */
3548f9be0386SMatt Macy 	ifma->ifma_flags |= IFMA_F_ENQUEUED;
3549d7c5a620SMatt Macy 	CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
3550c3b31afdSRobert Watson 
355113990766SJonathan Mini 	if (retifma != NULL)
3552373f88edSGarrett Wollman 		*retifma = ifma;
35531158dfb7SGarrett Wollman 
3554c3b31afdSRobert Watson 	/*
3555c3b31afdSRobert Watson 	 * Must generate the message while holding the lock so that 'ifma'
3556c3b31afdSRobert Watson 	 * pointer is still valid.
3557c3b31afdSRobert Watson 	 */
3558c3b31afdSRobert Watson 	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
3559137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
3560c3b31afdSRobert Watson 
35611158dfb7SGarrett Wollman 	/*
35621158dfb7SGarrett Wollman 	 * We are certain we have added something, so call down to the
35631158dfb7SGarrett Wollman 	 * interface to let them know about it.
35641158dfb7SGarrett Wollman 	 */
35652432c31cSRobert Watson 	if (ifp->if_ioctl != NULL) {
35660839aa5cSGleb Smirnoff 		if (THREAD_CAN_SLEEP())
35671a3b6859SYaroslav Tykhiy 			(void )(*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
35680839aa5cSGleb Smirnoff 		else
35690839aa5cSGleb Smirnoff 			taskqueue_enqueue(taskqueue_swi, &ifp->if_addmultitask);
35701a3b6859SYaroslav Tykhiy 	}
35711158dfb7SGarrett Wollman 
357295fbe4d0SAlexander V. Chernikov 	if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
357395fbe4d0SAlexander V. Chernikov 		link_free_sdl(llsa);
3574c3b31afdSRobert Watson 
3575c3b31afdSRobert Watson 	return (0);
3576c3b31afdSRobert Watson 
3577c3b31afdSRobert Watson free_llsa_out:
357895fbe4d0SAlexander V. Chernikov 	if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
357995fbe4d0SAlexander V. Chernikov 		link_free_sdl(llsa);
3580c3b31afdSRobert Watson 
3581c3b31afdSRobert Watson unlock_out:
3582137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
3583c3b31afdSRobert Watson 	return (error);
35841158dfb7SGarrett Wollman }
35851158dfb7SGarrett Wollman 
35860839aa5cSGleb Smirnoff static void
35870839aa5cSGleb Smirnoff if_siocaddmulti(void *arg, int pending)
35880839aa5cSGleb Smirnoff {
35890839aa5cSGleb Smirnoff 	struct ifnet *ifp;
35900839aa5cSGleb Smirnoff 
35910839aa5cSGleb Smirnoff 	ifp = arg;
35920839aa5cSGleb Smirnoff #ifdef DIAGNOSTIC
35930839aa5cSGleb Smirnoff 	if (pending > 1)
35940839aa5cSGleb Smirnoff 		if_printf(ifp, "%d SIOCADDMULTI coalesced\n", pending);
35950839aa5cSGleb Smirnoff #endif
35969352fab6SGleb Smirnoff 	CURVNET_SET(ifp->if_vnet);
35970839aa5cSGleb Smirnoff 	(void )(*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
35989352fab6SGleb Smirnoff 	CURVNET_RESTORE();
35990839aa5cSGleb Smirnoff }
36000839aa5cSGleb Smirnoff 
36011158dfb7SGarrett Wollman /*
3602ec002feeSBruce M Simpson  * Delete a multicast group membership by network-layer group address.
3603ec002feeSBruce M Simpson  *
3604ec002feeSBruce M Simpson  * Returns ENOENT if the entry could not be found. If ifp no longer
3605ec002feeSBruce M Simpson  * exists, results are undefined. This entry point should only be used
3606ec002feeSBruce M Simpson  * from subsystems which do appropriate locking to hold ifp for the
3607ec002feeSBruce M Simpson  * duration of the call.
3608ec002feeSBruce M Simpson  * Network-layer protocol domains must use if_delmulti_ifma().
36091158dfb7SGarrett Wollman  */
36101158dfb7SGarrett Wollman int
361172fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
36121158dfb7SGarrett Wollman {
3613ec002feeSBruce M Simpson 	struct ifmultiaddr *ifma;
3614ec002feeSBruce M Simpson 	int lastref;
3615ec002feeSBruce M Simpson 
3616416a1d1eSGleb Smirnoff 	KASSERT(ifp, ("%s: NULL ifp", __func__));
36171158dfb7SGarrett Wollman 
3618137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
3619ec002feeSBruce M Simpson 	lastref = 0;
3620c3b31afdSRobert Watson 	ifma = if_findmulti(ifp, sa);
3621ec002feeSBruce M Simpson 	if (ifma != NULL)
3622ec002feeSBruce M Simpson 		lastref = if_delmulti_locked(ifp, ifma, 0);
3623137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
3624c3b31afdSRobert Watson 
3625ec002feeSBruce M Simpson 	if (ifma == NULL)
3626ec002feeSBruce M Simpson 		return (ENOENT);
3627ec002feeSBruce M Simpson 
3628ec002feeSBruce M Simpson 	if (lastref && ifp->if_ioctl != NULL) {
36291a3b6859SYaroslav Tykhiy 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
363031302ebfSRobert Watson 	}
36311158dfb7SGarrett Wollman 
3632ec002feeSBruce M Simpson 	return (0);
3633ec002feeSBruce M Simpson }
3634ec002feeSBruce M Simpson 
3635ec002feeSBruce M Simpson /*
363693ec7edcSShteryana Shopova  * Delete all multicast group membership for an interface.
363793ec7edcSShteryana Shopova  * Should be used to quickly flush all multicast filters.
363893ec7edcSShteryana Shopova  */
363993ec7edcSShteryana Shopova void
364093ec7edcSShteryana Shopova if_delallmulti(struct ifnet *ifp)
364193ec7edcSShteryana Shopova {
364293ec7edcSShteryana Shopova 	struct ifmultiaddr *ifma;
364393ec7edcSShteryana Shopova 	struct ifmultiaddr *next;
364493ec7edcSShteryana Shopova 
3645137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
3646d7c5a620SMatt Macy 	CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
364793ec7edcSShteryana Shopova 		if_delmulti_locked(ifp, ifma, 0);
3648137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
364993ec7edcSShteryana Shopova }
365093ec7edcSShteryana Shopova 
3651b6f6f880SMatt Macy void
3652b6f6f880SMatt Macy if_delmulti_ifma(struct ifmultiaddr *ifma)
3653b6f6f880SMatt Macy {
3654b6f6f880SMatt Macy 	if_delmulti_ifma_flags(ifma, 0);
3655b6f6f880SMatt Macy }
3656b6f6f880SMatt Macy 
365793ec7edcSShteryana Shopova /*
3658ec002feeSBruce M Simpson  * Delete a multicast group membership by group membership pointer.
3659ec002feeSBruce M Simpson  * Network-layer protocol domains must use this routine.
3660ec002feeSBruce M Simpson  *
3661e5adda3dSRobert Watson  * It is safe to call this routine if the ifp disappeared.
3662ec002feeSBruce M Simpson  */
3663ec002feeSBruce M Simpson void
3664b6f6f880SMatt Macy if_delmulti_ifma_flags(struct ifmultiaddr *ifma, int flags)
3665ec002feeSBruce M Simpson {
3666ec002feeSBruce M Simpson 	struct ifnet *ifp;
3667ec002feeSBruce M Simpson 	int lastref;
3668b6f6f880SMatt Macy 	MCDPRINTF("%s freeing ifma: %p\n", __func__, ifma);
3669f3e1324bSStephen Hurd #ifdef INET
3670f3e1324bSStephen Hurd 	IN_MULTI_LIST_UNLOCK_ASSERT();
3671f3e1324bSStephen Hurd #endif
3672ec002feeSBruce M Simpson 	ifp = ifma->ifma_ifp;
3673ec002feeSBruce M Simpson #ifdef DIAGNOSTIC
3674ec002feeSBruce M Simpson 	if (ifp == NULL) {
3675ec002feeSBruce M Simpson 		printf("%s: ifma_ifp seems to be detached\n", __func__);
3676ec002feeSBruce M Simpson 	} else {
3677e9dc46ccSGleb Smirnoff 		struct epoch_tracker et;
3678ec002feeSBruce M Simpson 		struct ifnet *oifp;
3679ec002feeSBruce M Simpson 
3680e9dc46ccSGleb Smirnoff 		NET_EPOCH_ENTER(et);
36814f6c66ccSMatt Macy 		CK_STAILQ_FOREACH(oifp, &V_ifnet, if_link)
3682ec002feeSBruce M Simpson 			if (ifp == oifp)
3683ec002feeSBruce M Simpson 				break;
3684e9dc46ccSGleb Smirnoff 		NET_EPOCH_EXIT(et);
36851ebec5faSMatt Macy 		if (ifp != oifp)
3686ec002feeSBruce M Simpson 			ifp = NULL;
3687ec002feeSBruce M Simpson 	}
3688ec002feeSBruce M Simpson #endif
3689ec002feeSBruce M Simpson 	/*
3690ec002feeSBruce M Simpson 	 * If and only if the ifnet instance exists: Acquire the address lock.
3691ec002feeSBruce M Simpson 	 */
3692ec002feeSBruce M Simpson 	if (ifp != NULL)
3693137f91e8SJohn Baldwin 		IF_ADDR_WLOCK(ifp);
3694ec002feeSBruce M Simpson 
3695b6f6f880SMatt Macy 	lastref = if_delmulti_locked(ifp, ifma, flags);
3696ec002feeSBruce M Simpson 
3697ec002feeSBruce M Simpson 	if (ifp != NULL) {
3698ec002feeSBruce M Simpson 		/*
3699ec002feeSBruce M Simpson 		 * If and only if the ifnet instance exists:
3700ec002feeSBruce M Simpson 		 *  Release the address lock.
3701ec002feeSBruce M Simpson 		 *  If the group was left: update the hardware hash filter.
3702ec002feeSBruce M Simpson 		 */
3703137f91e8SJohn Baldwin 		IF_ADDR_WUNLOCK(ifp);
3704ec002feeSBruce M Simpson 		if (lastref && ifp->if_ioctl != NULL) {
3705ec002feeSBruce M Simpson 			(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
3706ec002feeSBruce M Simpson 		}
3707ec002feeSBruce M Simpson 	}
3708ec002feeSBruce M Simpson }
3709ec002feeSBruce M Simpson 
3710ec002feeSBruce M Simpson /*
3711ec002feeSBruce M Simpson  * Perform deletion of network-layer and/or link-layer multicast address.
3712ec002feeSBruce M Simpson  *
3713ec002feeSBruce M Simpson  * Return 0 if the reference count was decremented.
3714ec002feeSBruce M Simpson  * Return 1 if the final reference was released, indicating that the
3715ec002feeSBruce M Simpson  * hardware hash filter should be reprogrammed.
3716ec002feeSBruce M Simpson  */
3717ec002feeSBruce M Simpson static int
3718ec002feeSBruce M Simpson if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
3719ec002feeSBruce M Simpson {
3720ec002feeSBruce M Simpson 	struct ifmultiaddr *ll_ifma;
3721ec002feeSBruce M Simpson 
3722ec002feeSBruce M Simpson 	if (ifp != NULL && ifma->ifma_ifp != NULL) {
3723ec002feeSBruce M Simpson 		KASSERT(ifma->ifma_ifp == ifp,
3724ec002feeSBruce M Simpson 		    ("%s: inconsistent ifp %p", __func__, ifp));
3725137f91e8SJohn Baldwin 		IF_ADDR_WLOCK_ASSERT(ifp);
3726ec002feeSBruce M Simpson 	}
3727ec002feeSBruce M Simpson 
3728ec002feeSBruce M Simpson 	ifp = ifma->ifma_ifp;
3729b6f6f880SMatt Macy 	MCDPRINTF("%s freeing %p from %s \n", __func__, ifma, ifp ? ifp->if_xname : "");
3730ec002feeSBruce M Simpson 
3731ec002feeSBruce M Simpson 	/*
3732ec002feeSBruce M Simpson 	 * If the ifnet is detaching, null out references to ifnet,
3733ec002feeSBruce M Simpson 	 * so that upper protocol layers will notice, and not attempt
373475ae0c01SBruce M Simpson 	 * to obtain locks for an ifnet which no longer exists. The
373575ae0c01SBruce M Simpson 	 * routing socket announcement must happen before the ifnet
373675ae0c01SBruce M Simpson 	 * instance is detached from the system.
3737ec002feeSBruce M Simpson 	 */
3738ec002feeSBruce M Simpson 	if (detaching) {
3739ec002feeSBruce M Simpson #ifdef DIAGNOSTIC
3740ec002feeSBruce M Simpson 		printf("%s: detaching ifnet instance %p\n", __func__, ifp);
3741ec002feeSBruce M Simpson #endif
374275ae0c01SBruce M Simpson 		/*
374375ae0c01SBruce M Simpson 		 * ifp may already be nulled out if we are being reentered
374475ae0c01SBruce M Simpson 		 * to delete the ll_ifma.
374575ae0c01SBruce M Simpson 		 */
374675ae0c01SBruce M Simpson 		if (ifp != NULL) {
374775ae0c01SBruce M Simpson 			rt_newmaddrmsg(RTM_DELMADDR, ifma);
3748ec002feeSBruce M Simpson 			ifma->ifma_ifp = NULL;
3749ec002feeSBruce M Simpson 		}
375075ae0c01SBruce M Simpson 	}
3751ec002feeSBruce M Simpson 
3752ec002feeSBruce M Simpson 	if (--ifma->ifma_refcount > 0)
37531158dfb7SGarrett Wollman 		return 0;
3754ec002feeSBruce M Simpson 
3755f9be0386SMatt Macy 	if (ifp != NULL && detaching == 0 && (ifma->ifma_flags & IFMA_F_ENQUEUED)) {
3756d7c5a620SMatt Macy 		CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
3757f9be0386SMatt Macy 		ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
3758f9be0386SMatt Macy 	}
3759ec002feeSBruce M Simpson 	/*
3760ec002feeSBruce M Simpson 	 * If this ifma is a network-layer ifma, a link-layer ifma may
3761ec002feeSBruce M Simpson 	 * have been associated with it. Release it first if so.
3762ec002feeSBruce M Simpson 	 */
3763ec002feeSBruce M Simpson 	ll_ifma = ifma->ifma_llifma;
3764ec002feeSBruce M Simpson 	if (ll_ifma != NULL) {
3765ec002feeSBruce M Simpson 		KASSERT(ifma->ifma_lladdr != NULL,
3766ec002feeSBruce M Simpson 		    ("%s: llifma w/o lladdr", __func__));
3767ec002feeSBruce M Simpson 		if (detaching)
3768ec002feeSBruce M Simpson 			ll_ifma->ifma_ifp = NULL;	/* XXX */
3769ec002feeSBruce M Simpson 		if (--ll_ifma->ifma_refcount == 0) {
3770ec002feeSBruce M Simpson 			if (ifp != NULL) {
3771f9be0386SMatt Macy 				if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
3772d7c5a620SMatt Macy 					CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr,
3773ec002feeSBruce M Simpson 						ifma_link);
377477ad07b6SMatt Macy 					ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
3775f9be0386SMatt Macy 				}
3776ec002feeSBruce M Simpson 			}
3777ec002feeSBruce M Simpson 			if_freemulti(ll_ifma);
3778ec002feeSBruce M Simpson 		}
3779ec002feeSBruce M Simpson 	}
3780b6f6f880SMatt Macy #ifdef INVARIANTS
3781b6f6f880SMatt Macy 	if (ifp) {
3782b6f6f880SMatt Macy 		struct ifmultiaddr *ifmatmp;
3783ec002feeSBruce M Simpson 
3784d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link)
3785b6f6f880SMatt Macy 			MPASS(ifma != ifmatmp);
3786b6f6f880SMatt Macy 	}
3787b6f6f880SMatt Macy #endif
3788ec002feeSBruce M Simpson 	if_freemulti(ifma);
3789ec002feeSBruce M Simpson 	/*
3790ec002feeSBruce M Simpson 	 * The last reference to this instance of struct ifmultiaddr
3791ec002feeSBruce M Simpson 	 * was released; the hardware should be notified of this change.
3792ec002feeSBruce M Simpson 	 */
3793ec002feeSBruce M Simpson 	return 1;
37941158dfb7SGarrett Wollman }
37951158dfb7SGarrett Wollman 
379666ce51ceSArchie Cobbs /*
379766ce51ceSArchie Cobbs  * Set the link layer address on an interface.
379866ce51ceSArchie Cobbs  *
379966ce51ceSArchie Cobbs  * At this time we only support certain types of interfaces,
380066ce51ceSArchie Cobbs  * and we don't allow the length of the address to change.
3801bb3d23fdSAlexander V. Chernikov  *
3802bb3d23fdSAlexander V. Chernikov  * Set noinline to be dtrace-friendly
380366ce51ceSArchie Cobbs  */
3804bb3d23fdSAlexander V. Chernikov __noinline int
380566ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
380666ce51ceSArchie Cobbs {
380766ce51ceSArchie Cobbs 	struct sockaddr_dl *sdl;
380866ce51ceSArchie Cobbs 	struct ifaddr *ifa;
3809d637e989SPeter Wemm 	struct ifreq ifr;
381066ce51ceSArchie Cobbs 
38114a0d6638SRuslan Ermilov 	ifa = ifp->if_addr;
38121e80e4f2SGleb Smirnoff 	if (ifa == NULL)
38131e80e4f2SGleb Smirnoff 		return (EINVAL);
38144f6c66ccSMatt Macy 
381566ce51ceSArchie Cobbs 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
38161e80e4f2SGleb Smirnoff 	if (sdl == NULL)
38171e80e4f2SGleb Smirnoff 		return (EINVAL);
38181e80e4f2SGleb Smirnoff 
38191e80e4f2SGleb Smirnoff 	if (len != sdl->sdl_alen)	/* don't allow length to change */
38201e80e4f2SGleb Smirnoff 		return (EINVAL);
38211e80e4f2SGleb Smirnoff 
382266ce51ceSArchie Cobbs 	switch (ifp->if_type) {
3823d09ed26fSRuslan Ermilov 	case IFT_ETHER:
382466ce51ceSArchie Cobbs 	case IFT_XETHER:
3825b7bffa71SYaroslav Tykhiy 	case IFT_L2VLAN:
38268f867517SAndrew Thompson 	case IFT_BRIDGE:
3827b47888ceSAndrew Thompson 	case IFT_IEEE8023ADLAG:
382866ce51ceSArchie Cobbs 		bcopy(lladdr, LLADDR(sdl), len);
382966ce51ceSArchie Cobbs 		break;
383066ce51ceSArchie Cobbs 	default:
38311e80e4f2SGleb Smirnoff 		return (ENODEV);
383266ce51ceSArchie Cobbs 	}
38333baaf297SRobert Watson 
383466ce51ceSArchie Cobbs 	/*
383566ce51ceSArchie Cobbs 	 * If the interface is already up, we need
383666ce51ceSArchie Cobbs 	 * to re-init it in order to reprogram its
383766ce51ceSArchie Cobbs 	 * address filter.
383866ce51ceSArchie Cobbs 	 */
383966ce51ceSArchie Cobbs 	if ((ifp->if_flags & IFF_UP) != 0) {
38401a3b6859SYaroslav Tykhiy 		if (ifp->if_ioctl) {
384166ce51ceSArchie Cobbs 			ifp->if_flags &= ~IFF_UP;
384262f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
384362f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
3844ee0a4f7eSSUZUKI Shinsuke 			(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
384566ce51ceSArchie Cobbs 			ifp->if_flags |= IFF_UP;
384662f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
384762f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
3848ee0a4f7eSSUZUKI Shinsuke 			(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
38491a3b6859SYaroslav Tykhiy 		}
385066ce51ceSArchie Cobbs 	}
38518ad43f2dSAlexander V. Chernikov 	EVENTHANDLER_INVOKE(iflladdr_event, ifp);
38521e80e4f2SGleb Smirnoff 
385391d6c9b9SMatt Macy 	return (0);
385466ce51ceSArchie Cobbs }
385566ce51ceSArchie Cobbs 
38569bf40edeSBrooks Davis /*
38574fb3a820SAlexander V. Chernikov  * Compat function for handling basic encapsulation requests.
38584fb3a820SAlexander V. Chernikov  * Not converted stacks (FDDI, IB, ..) supports traditional
38594fb3a820SAlexander V. Chernikov  * output model: ARP (and other similar L2 protocols) are handled
38604fb3a820SAlexander V. Chernikov  * inside output routine, arpresolve/nd6_resolve() returns MAC
38614fb3a820SAlexander V. Chernikov  * address instead of full prepend.
38624fb3a820SAlexander V. Chernikov  *
38634fb3a820SAlexander V. Chernikov  * This function creates calculated header==MAC for IPv4/IPv6 and
38644fb3a820SAlexander V. Chernikov  * returns EAFNOSUPPORT (which is then handled in ARP code) for other
38654fb3a820SAlexander V. Chernikov  * address families.
38664fb3a820SAlexander V. Chernikov  */
38674fb3a820SAlexander V. Chernikov static int
38684fb3a820SAlexander V. Chernikov if_requestencap_default(struct ifnet *ifp, struct if_encap_req *req)
38694fb3a820SAlexander V. Chernikov {
38704fb3a820SAlexander V. Chernikov 
38714fb3a820SAlexander V. Chernikov 	if (req->rtype != IFENCAP_LL)
38724fb3a820SAlexander V. Chernikov 		return (EOPNOTSUPP);
38734fb3a820SAlexander V. Chernikov 
38744fb3a820SAlexander V. Chernikov 	if (req->bufsize < req->lladdr_len)
38754fb3a820SAlexander V. Chernikov 		return (ENOMEM);
38764fb3a820SAlexander V. Chernikov 
38774fb3a820SAlexander V. Chernikov 	switch (req->family) {
38784fb3a820SAlexander V. Chernikov 	case AF_INET:
38794fb3a820SAlexander V. Chernikov 	case AF_INET6:
38804fb3a820SAlexander V. Chernikov 		break;
38814fb3a820SAlexander V. Chernikov 	default:
38824fb3a820SAlexander V. Chernikov 		return (EAFNOSUPPORT);
38834fb3a820SAlexander V. Chernikov 	}
38844fb3a820SAlexander V. Chernikov 
38854fb3a820SAlexander V. Chernikov 	/* Copy lladdr to storage as is */
38864fb3a820SAlexander V. Chernikov 	memmove(req->buf, req->lladdr, req->lladdr_len);
38874fb3a820SAlexander V. Chernikov 	req->bufsize = req->lladdr_len;
38884fb3a820SAlexander V. Chernikov 	req->lladdr_off = 0;
38894fb3a820SAlexander V. Chernikov 
38904fb3a820SAlexander V. Chernikov 	return (0);
38914fb3a820SAlexander V. Chernikov }
38924fb3a820SAlexander V. Chernikov 
38934fb3a820SAlexander V. Chernikov /*
389498a8fdf6SAndrey V. Elsukov  * Tunnel interfaces can nest, also they may cause infinite recursion
389598a8fdf6SAndrey V. Elsukov  * calls when misconfigured. We'll prevent this by detecting loops.
389698a8fdf6SAndrey V. Elsukov  * High nesting level may cause stack exhaustion. We'll prevent this
389798a8fdf6SAndrey V. Elsukov  * by introducing upper limit.
389898a8fdf6SAndrey V. Elsukov  *
389998a8fdf6SAndrey V. Elsukov  * Return 0, if tunnel nesting count is equal or less than limit.
390098a8fdf6SAndrey V. Elsukov  */
390198a8fdf6SAndrey V. Elsukov int
390298a8fdf6SAndrey V. Elsukov if_tunnel_check_nesting(struct ifnet *ifp, struct mbuf *m, uint32_t cookie,
390398a8fdf6SAndrey V. Elsukov     int limit)
390498a8fdf6SAndrey V. Elsukov {
390598a8fdf6SAndrey V. Elsukov 	struct m_tag *mtag;
390698a8fdf6SAndrey V. Elsukov 	int count;
390798a8fdf6SAndrey V. Elsukov 
390898a8fdf6SAndrey V. Elsukov 	count = 1;
390998a8fdf6SAndrey V. Elsukov 	mtag = NULL;
391098a8fdf6SAndrey V. Elsukov 	while ((mtag = m_tag_locate(m, cookie, 0, mtag)) != NULL) {
391198a8fdf6SAndrey V. Elsukov 		if (*(struct ifnet **)(mtag + 1) == ifp) {
391298a8fdf6SAndrey V. Elsukov 			log(LOG_NOTICE, "%s: loop detected\n", if_name(ifp));
391398a8fdf6SAndrey V. Elsukov 			return (EIO);
391498a8fdf6SAndrey V. Elsukov 		}
391598a8fdf6SAndrey V. Elsukov 		count++;
391698a8fdf6SAndrey V. Elsukov 	}
391798a8fdf6SAndrey V. Elsukov 	if (count > limit) {
391898a8fdf6SAndrey V. Elsukov 		log(LOG_NOTICE,
391998a8fdf6SAndrey V. Elsukov 		    "%s: if_output recursively called too many times(%d)\n",
392098a8fdf6SAndrey V. Elsukov 		    if_name(ifp), count);
392198a8fdf6SAndrey V. Elsukov 		return (EIO);
392298a8fdf6SAndrey V. Elsukov 	}
392398a8fdf6SAndrey V. Elsukov 	mtag = m_tag_alloc(cookie, 0, sizeof(struct ifnet *), M_NOWAIT);
392498a8fdf6SAndrey V. Elsukov 	if (mtag == NULL)
392598a8fdf6SAndrey V. Elsukov 		return (ENOMEM);
392698a8fdf6SAndrey V. Elsukov 	*(struct ifnet **)(mtag + 1) = ifp;
392798a8fdf6SAndrey V. Elsukov 	m_tag_prepend(m, mtag);
392898a8fdf6SAndrey V. Elsukov 	return (0);
392998a8fdf6SAndrey V. Elsukov }
393098a8fdf6SAndrey V. Elsukov 
393198a8fdf6SAndrey V. Elsukov /*
3932ddae5750SRavi Pokala  * Get the link layer address that was read from the hardware at attach.
3933ddae5750SRavi Pokala  *
3934ddae5750SRavi Pokala  * This is only set by Ethernet NICs (IFT_ETHER), but laggX interfaces re-type
3935ddae5750SRavi Pokala  * their component interfaces as IFT_IEEE8023ADLAG.
3936ddae5750SRavi Pokala  */
3937ddae5750SRavi Pokala int
3938ddae5750SRavi Pokala if_gethwaddr(struct ifnet *ifp, struct ifreq *ifr)
3939ddae5750SRavi Pokala {
3940ddae5750SRavi Pokala 
3941ddae5750SRavi Pokala 	if (ifp->if_hw_addr == NULL)
3942ddae5750SRavi Pokala 		return (ENODEV);
3943ddae5750SRavi Pokala 
3944ddae5750SRavi Pokala 	switch (ifp->if_type) {
3945ddae5750SRavi Pokala 	case IFT_ETHER:
3946ddae5750SRavi Pokala 	case IFT_IEEE8023ADLAG:
3947ddae5750SRavi Pokala 		bcopy(ifp->if_hw_addr, ifr->ifr_addr.sa_data, ifp->if_addrlen);
3948ddae5750SRavi Pokala 		return (0);
3949ddae5750SRavi Pokala 	default:
3950ddae5750SRavi Pokala 		return (ENODEV);
3951ddae5750SRavi Pokala 	}
3952ddae5750SRavi Pokala }
3953ddae5750SRavi Pokala 
3954ddae5750SRavi Pokala /*
39559bf40edeSBrooks Davis  * The name argument must be a pointer to storage which will last as
39569bf40edeSBrooks Davis  * long as the interface does.  For physical devices, the result of
39579bf40edeSBrooks Davis  * device_get_name(dev) is a good choice and for pseudo-devices a
39589bf40edeSBrooks Davis  * static string works well.
39599bf40edeSBrooks Davis  */
39609bf40edeSBrooks Davis void
39619bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit)
39629bf40edeSBrooks Davis {
39639bf40edeSBrooks Davis 	ifp->if_dname = name;
39649bf40edeSBrooks Davis 	ifp->if_dunit = unit;
39659bf40edeSBrooks Davis 	if (unit != IF_DUNIT_NONE)
39669bf40edeSBrooks Davis 		snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit);
39679bf40edeSBrooks Davis 	else
39689bf40edeSBrooks Davis 		strlcpy(ifp->if_xname, name, IFNAMSIZ);
39699bf40edeSBrooks Davis }
39709bf40edeSBrooks Davis 
3971fa882e87SBrooks Davis int
3972fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char *fmt, ...)
3973fa882e87SBrooks Davis {
397420f8d7bcSDag-Erling Smørgrav 	char if_fmt[256];
3975fa882e87SBrooks Davis 	va_list ap;
3976fa882e87SBrooks Davis 
397720f8d7bcSDag-Erling Smørgrav 	snprintf(if_fmt, sizeof(if_fmt), "%s: %s", ifp->if_xname, fmt);
3978fa882e87SBrooks Davis 	va_start(ap, fmt);
397920f8d7bcSDag-Erling Smørgrav 	vlog(LOG_INFO, if_fmt, ap);
3980fa882e87SBrooks Davis 	va_end(ap);
398120f8d7bcSDag-Erling Smørgrav 	return (0);
3982fa882e87SBrooks Davis }
3983fa882e87SBrooks Davis 
3984af5e59bfSRobert Watson void
3985af5e59bfSRobert Watson if_start(struct ifnet *ifp)
3986af5e59bfSRobert Watson {
3987af5e59bfSRobert Watson 
3988af5e59bfSRobert Watson 	(*(ifp)->if_start)(ifp);
3989af5e59bfSRobert Watson }
3990af5e59bfSRobert Watson 
3991db7f0b97SKip Macy /*
3992db7f0b97SKip Macy  * Backwards compatibility interface for drivers
3993db7f0b97SKip Macy  * that have not implemented it
3994db7f0b97SKip Macy  */
3995db7f0b97SKip Macy static int
3996db7f0b97SKip Macy if_transmit(struct ifnet *ifp, struct mbuf *m)
3997db7f0b97SKip Macy {
3998db7f0b97SKip Macy 	int error;
3999db7f0b97SKip Macy 
4000db7f0b97SKip Macy 	IFQ_HANDOFF(ifp, m, error);
4001db7f0b97SKip Macy 	return (error);
4002db7f0b97SKip Macy }
4003db7f0b97SKip Macy 
4004b57d9721SAndrey V. Elsukov static void
4005b57d9721SAndrey V. Elsukov if_input_default(struct ifnet *ifp __unused, struct mbuf *m)
4006b57d9721SAndrey V. Elsukov {
4007b57d9721SAndrey V. Elsukov 
4008b57d9721SAndrey V. Elsukov 	m_freem(m);
4009b57d9721SAndrey V. Elsukov }
4010b57d9721SAndrey V. Elsukov 
40110b762445SRobert Watson int
40120b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
40130b762445SRobert Watson {
40140b762445SRobert Watson 	int active = 0;
40150b762445SRobert Watson 
40160b762445SRobert Watson 	IF_LOCK(ifq);
40170b762445SRobert Watson 	if (_IF_QFULL(ifq)) {
40180b762445SRobert Watson 		IF_UNLOCK(ifq);
4019112f50ffSGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
40200b762445SRobert Watson 		m_freem(m);
40210b762445SRobert Watson 		return (0);
40220b762445SRobert Watson 	}
40230b762445SRobert Watson 	if (ifp != NULL) {
4024112f50ffSGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len + adjust);
40250b762445SRobert Watson 		if (m->m_flags & (M_BCAST|M_MCAST))
4026112f50ffSGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
4027292ee7beSRobert Watson 		active = ifp->if_drv_flags & IFF_DRV_OACTIVE;
40280b762445SRobert Watson 	}
40290b762445SRobert Watson 	_IF_ENQUEUE(ifq, m);
40300b762445SRobert Watson 	IF_UNLOCK(ifq);
40310b762445SRobert Watson 	if (ifp != NULL && !active)
4032e5adda3dSRobert Watson 		(*(ifp)->if_start)(ifp);
40330b762445SRobert Watson 	return (1);
40340b762445SRobert Watson }
4035fc74a9f9SBrooks Davis 
4036fc74a9f9SBrooks Davis void
4037fc74a9f9SBrooks Davis if_register_com_alloc(u_char type,
4038fc74a9f9SBrooks Davis     if_com_alloc_t *a, if_com_free_t *f)
4039fc74a9f9SBrooks Davis {
4040fc74a9f9SBrooks Davis 
4041fc74a9f9SBrooks Davis 	KASSERT(if_com_alloc[type] == NULL,
4042fc74a9f9SBrooks Davis 	    ("if_register_com_alloc: %d already registered", type));
4043fc74a9f9SBrooks Davis 	KASSERT(if_com_free[type] == NULL,
4044fc74a9f9SBrooks Davis 	    ("if_register_com_alloc: %d free already registered", type));
4045fc74a9f9SBrooks Davis 
4046fc74a9f9SBrooks Davis 	if_com_alloc[type] = a;
4047fc74a9f9SBrooks Davis 	if_com_free[type] = f;
4048fc74a9f9SBrooks Davis }
4049fc74a9f9SBrooks Davis 
4050fc74a9f9SBrooks Davis void
4051fc74a9f9SBrooks Davis if_deregister_com_alloc(u_char type)
4052fc74a9f9SBrooks Davis {
4053fc74a9f9SBrooks Davis 
4054affcaf78SMax Khon 	KASSERT(if_com_alloc[type] != NULL,
4055fc74a9f9SBrooks Davis 	    ("if_deregister_com_alloc: %d not registered", type));
4056affcaf78SMax Khon 	KASSERT(if_com_free[type] != NULL,
4057fc74a9f9SBrooks Davis 	    ("if_deregister_com_alloc: %d free not registered", type));
4058fc74a9f9SBrooks Davis 	if_com_alloc[type] = NULL;
4059fc74a9f9SBrooks Davis 	if_com_free[type] = NULL;
4060fc74a9f9SBrooks Davis }
406162d76917SMarcel Moolenaar 
406262d76917SMarcel Moolenaar /* API for driver access to network stack owned ifnet.*/
406362d76917SMarcel Moolenaar uint64_t
406409a8241fSGleb Smirnoff if_setbaudrate(struct ifnet *ifp, uint64_t baudrate)
406562d76917SMarcel Moolenaar {
406662d76917SMarcel Moolenaar 	uint64_t oldbrate;
406762d76917SMarcel Moolenaar 
406862d76917SMarcel Moolenaar 	oldbrate = ifp->if_baudrate;
406962d76917SMarcel Moolenaar 	ifp->if_baudrate = baudrate;
407062d76917SMarcel Moolenaar 	return (oldbrate);
407162d76917SMarcel Moolenaar }
407262d76917SMarcel Moolenaar 
407362d76917SMarcel Moolenaar uint64_t
407462d76917SMarcel Moolenaar if_getbaudrate(if_t ifp)
407562d76917SMarcel Moolenaar {
407662d76917SMarcel Moolenaar 
407762d76917SMarcel Moolenaar 	return (((struct ifnet *)ifp)->if_baudrate);
407862d76917SMarcel Moolenaar }
407962d76917SMarcel Moolenaar 
408062d76917SMarcel Moolenaar int
408162d76917SMarcel Moolenaar if_setcapabilities(if_t ifp, int capabilities)
408262d76917SMarcel Moolenaar {
408362d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capabilities = capabilities;
408462d76917SMarcel Moolenaar 	return (0);
408562d76917SMarcel Moolenaar }
408662d76917SMarcel Moolenaar 
408762d76917SMarcel Moolenaar int
408862d76917SMarcel Moolenaar if_setcapabilitiesbit(if_t ifp, int setbit, int clearbit)
408962d76917SMarcel Moolenaar {
409062d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capabilities |= setbit;
409162d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capabilities &= ~clearbit;
409262d76917SMarcel Moolenaar 
409362d76917SMarcel Moolenaar 	return (0);
409462d76917SMarcel Moolenaar }
409562d76917SMarcel Moolenaar 
409662d76917SMarcel Moolenaar int
409762d76917SMarcel Moolenaar if_getcapabilities(if_t ifp)
409862d76917SMarcel Moolenaar {
409962d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_capabilities;
410062d76917SMarcel Moolenaar }
410162d76917SMarcel Moolenaar 
410262d76917SMarcel Moolenaar int
410362d76917SMarcel Moolenaar if_setcapenable(if_t ifp, int capabilities)
410462d76917SMarcel Moolenaar {
410562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capenable = capabilities;
410662d76917SMarcel Moolenaar 	return (0);
410762d76917SMarcel Moolenaar }
410862d76917SMarcel Moolenaar 
410962d76917SMarcel Moolenaar int
411062d76917SMarcel Moolenaar if_setcapenablebit(if_t ifp, int setcap, int clearcap)
411162d76917SMarcel Moolenaar {
411262d76917SMarcel Moolenaar 	if(setcap)
411362d76917SMarcel Moolenaar 		((struct ifnet *)ifp)->if_capenable |= setcap;
411462d76917SMarcel Moolenaar 	if(clearcap)
411562d76917SMarcel Moolenaar 		((struct ifnet *)ifp)->if_capenable &= ~clearcap;
411662d76917SMarcel Moolenaar 
411762d76917SMarcel Moolenaar 	return (0);
411862d76917SMarcel Moolenaar }
411962d76917SMarcel Moolenaar 
412062d76917SMarcel Moolenaar const char *
412162d76917SMarcel Moolenaar if_getdname(if_t ifp)
412262d76917SMarcel Moolenaar {
412362d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_dname;
412462d76917SMarcel Moolenaar }
412562d76917SMarcel Moolenaar 
412662d76917SMarcel Moolenaar int
412762d76917SMarcel Moolenaar if_togglecapenable(if_t ifp, int togglecap)
412862d76917SMarcel Moolenaar {
412962d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capenable ^= togglecap;
413062d76917SMarcel Moolenaar 	return (0);
413162d76917SMarcel Moolenaar }
413262d76917SMarcel Moolenaar 
413362d76917SMarcel Moolenaar int
413462d76917SMarcel Moolenaar if_getcapenable(if_t ifp)
413562d76917SMarcel Moolenaar {
413662d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_capenable;
413762d76917SMarcel Moolenaar }
413862d76917SMarcel Moolenaar 
413962d76917SMarcel Moolenaar /*
414062d76917SMarcel Moolenaar  * This is largely undesirable because it ties ifnet to a device, but does
414162d76917SMarcel Moolenaar  * provide flexiblity for an embedded product vendor. Should be used with
414262d76917SMarcel Moolenaar  * the understanding that it violates the interface boundaries, and should be
414362d76917SMarcel Moolenaar  * a last resort only.
414462d76917SMarcel Moolenaar  */
414562d76917SMarcel Moolenaar int
414662d76917SMarcel Moolenaar if_setdev(if_t ifp, void *dev)
414762d76917SMarcel Moolenaar {
414862d76917SMarcel Moolenaar 	return (0);
414962d76917SMarcel Moolenaar }
415062d76917SMarcel Moolenaar 
415162d76917SMarcel Moolenaar int
415262d76917SMarcel Moolenaar if_setdrvflagbits(if_t ifp, int set_flags, int clear_flags)
415362d76917SMarcel Moolenaar {
415462d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_drv_flags |= set_flags;
415562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_drv_flags &= ~clear_flags;
415662d76917SMarcel Moolenaar 
415762d76917SMarcel Moolenaar 	return (0);
415862d76917SMarcel Moolenaar }
415962d76917SMarcel Moolenaar 
416062d76917SMarcel Moolenaar int
416162d76917SMarcel Moolenaar if_getdrvflags(if_t ifp)
416262d76917SMarcel Moolenaar {
416362d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_drv_flags;
416462d76917SMarcel Moolenaar }
416562d76917SMarcel Moolenaar 
416662d76917SMarcel Moolenaar int
416762d76917SMarcel Moolenaar if_setdrvflags(if_t ifp, int flags)
416862d76917SMarcel Moolenaar {
416962d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_drv_flags = flags;
417062d76917SMarcel Moolenaar 	return (0);
417162d76917SMarcel Moolenaar }
417262d76917SMarcel Moolenaar 
417362d76917SMarcel Moolenaar int
417462d76917SMarcel Moolenaar if_setflags(if_t ifp, int flags)
417562d76917SMarcel Moolenaar {
4176e87c4940SGleb Smirnoff 
4177e87c4940SGleb Smirnoff 	ifp->if_flags = flags;
417862d76917SMarcel Moolenaar 	return (0);
417962d76917SMarcel Moolenaar }
418062d76917SMarcel Moolenaar 
418162d76917SMarcel Moolenaar int
418262d76917SMarcel Moolenaar if_setflagbits(if_t ifp, int set, int clear)
418362d76917SMarcel Moolenaar {
418462d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_flags |= set;
418562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_flags &= ~clear;
418662d76917SMarcel Moolenaar 
418762d76917SMarcel Moolenaar 	return (0);
418862d76917SMarcel Moolenaar }
418962d76917SMarcel Moolenaar 
419062d76917SMarcel Moolenaar int
419162d76917SMarcel Moolenaar if_getflags(if_t ifp)
419262d76917SMarcel Moolenaar {
419362d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_flags;
419462d76917SMarcel Moolenaar }
419562d76917SMarcel Moolenaar 
419662d76917SMarcel Moolenaar int
419762d76917SMarcel Moolenaar if_clearhwassist(if_t ifp)
419862d76917SMarcel Moolenaar {
419962d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist = 0;
420062d76917SMarcel Moolenaar 	return (0);
420162d76917SMarcel Moolenaar }
420262d76917SMarcel Moolenaar 
420362d76917SMarcel Moolenaar int
420462d76917SMarcel Moolenaar if_sethwassistbits(if_t ifp, int toset, int toclear)
420562d76917SMarcel Moolenaar {
420662d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist |= toset;
420762d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist &= ~toclear;
420862d76917SMarcel Moolenaar 
420962d76917SMarcel Moolenaar 	return (0);
421062d76917SMarcel Moolenaar }
421162d76917SMarcel Moolenaar 
421262d76917SMarcel Moolenaar int
421362d76917SMarcel Moolenaar if_sethwassist(if_t ifp, int hwassist_bit)
421462d76917SMarcel Moolenaar {
421562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist = hwassist_bit;
421662d76917SMarcel Moolenaar 	return (0);
421762d76917SMarcel Moolenaar }
421862d76917SMarcel Moolenaar 
421962d76917SMarcel Moolenaar int
422062d76917SMarcel Moolenaar if_gethwassist(if_t ifp)
422162d76917SMarcel Moolenaar {
422262d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_hwassist;
422362d76917SMarcel Moolenaar }
422462d76917SMarcel Moolenaar 
422562d76917SMarcel Moolenaar int
422662d76917SMarcel Moolenaar if_setmtu(if_t ifp, int mtu)
422762d76917SMarcel Moolenaar {
422862d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_mtu = mtu;
422962d76917SMarcel Moolenaar 	return (0);
423062d76917SMarcel Moolenaar }
423162d76917SMarcel Moolenaar 
423262d76917SMarcel Moolenaar int
423362d76917SMarcel Moolenaar if_getmtu(if_t ifp)
423462d76917SMarcel Moolenaar {
423562d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_mtu;
423662d76917SMarcel Moolenaar }
423762d76917SMarcel Moolenaar 
423862d76917SMarcel Moolenaar int
42391a75e3b2SAlexander V. Chernikov if_getmtu_family(if_t ifp, int family)
42401a75e3b2SAlexander V. Chernikov {
42411a75e3b2SAlexander V. Chernikov 	struct domain *dp;
42421a75e3b2SAlexander V. Chernikov 
42431a75e3b2SAlexander V. Chernikov 	for (dp = domains; dp; dp = dp->dom_next) {
42441a75e3b2SAlexander V. Chernikov 		if (dp->dom_family == family && dp->dom_ifmtu != NULL)
42451a75e3b2SAlexander V. Chernikov 			return (dp->dom_ifmtu((struct ifnet *)ifp));
42461a75e3b2SAlexander V. Chernikov 	}
42471a75e3b2SAlexander V. Chernikov 
42481a75e3b2SAlexander V. Chernikov 	return (((struct ifnet *)ifp)->if_mtu);
42491a75e3b2SAlexander V. Chernikov }
42501a75e3b2SAlexander V. Chernikov 
4251826857c8SGleb Smirnoff /*
4252826857c8SGleb Smirnoff  * Methods for drivers to access interface unicast and multicast
4253826857c8SGleb Smirnoff  * link level addresses.  Driver shall not know 'struct ifaddr' neither
4254826857c8SGleb Smirnoff  * 'struct ifmultiaddr'.
4255826857c8SGleb Smirnoff  */
4256826857c8SGleb Smirnoff u_int
4257fb3fc771SGleb Smirnoff if_lladdr_count(if_t ifp)
4258fb3fc771SGleb Smirnoff {
4259fb3fc771SGleb Smirnoff 	struct epoch_tracker et;
4260fb3fc771SGleb Smirnoff 	struct ifaddr *ifa;
4261fb3fc771SGleb Smirnoff 	u_int count;
4262fb3fc771SGleb Smirnoff 
4263fb3fc771SGleb Smirnoff 	count = 0;
4264fb3fc771SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4265fb3fc771SGleb Smirnoff 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
4266fb3fc771SGleb Smirnoff 		if (ifa->ifa_addr->sa_family == AF_LINK)
4267fb3fc771SGleb Smirnoff 			count++;
4268fb3fc771SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4269fb3fc771SGleb Smirnoff 
4270fb3fc771SGleb Smirnoff 	return (count);
4271fb3fc771SGleb Smirnoff }
4272fb3fc771SGleb Smirnoff 
4273fb3fc771SGleb Smirnoff u_int
4274826857c8SGleb Smirnoff if_foreach_lladdr(if_t ifp, iflladdr_cb_t cb, void *cb_arg)
4275826857c8SGleb Smirnoff {
4276826857c8SGleb Smirnoff 	struct epoch_tracker et;
4277826857c8SGleb Smirnoff 	struct ifaddr *ifa;
4278826857c8SGleb Smirnoff 	u_int count;
4279826857c8SGleb Smirnoff 
4280826857c8SGleb Smirnoff 	MPASS(cb);
4281826857c8SGleb Smirnoff 
4282826857c8SGleb Smirnoff 	count = 0;
4283826857c8SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4284826857c8SGleb Smirnoff 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
4285826857c8SGleb Smirnoff 		if (ifa->ifa_addr->sa_family != AF_LINK)
4286826857c8SGleb Smirnoff 			continue;
4287826857c8SGleb Smirnoff 		count += (*cb)(cb_arg, (struct sockaddr_dl *)ifa->ifa_addr,
4288826857c8SGleb Smirnoff 		    count);
4289826857c8SGleb Smirnoff 	}
4290826857c8SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4291826857c8SGleb Smirnoff 
4292826857c8SGleb Smirnoff 	return (count);
4293826857c8SGleb Smirnoff }
4294826857c8SGleb Smirnoff 
4295826857c8SGleb Smirnoff u_int
4296fb3fc771SGleb Smirnoff if_llmaddr_count(if_t ifp)
4297fb3fc771SGleb Smirnoff {
4298fb3fc771SGleb Smirnoff 	struct epoch_tracker et;
4299fb3fc771SGleb Smirnoff 	struct ifmultiaddr *ifma;
4300fb3fc771SGleb Smirnoff 	int count;
4301fb3fc771SGleb Smirnoff 
4302fb3fc771SGleb Smirnoff 	count = 0;
4303fb3fc771SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4304fb3fc771SGleb Smirnoff 	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
4305fb3fc771SGleb Smirnoff 		if (ifma->ifma_addr->sa_family == AF_LINK)
4306fb3fc771SGleb Smirnoff 			count++;
4307fb3fc771SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4308fb3fc771SGleb Smirnoff 
4309fb3fc771SGleb Smirnoff 	return (count);
4310fb3fc771SGleb Smirnoff }
4311fb3fc771SGleb Smirnoff 
4312fb3fc771SGleb Smirnoff u_int
4313826857c8SGleb Smirnoff if_foreach_llmaddr(if_t ifp, iflladdr_cb_t cb, void *cb_arg)
4314826857c8SGleb Smirnoff {
4315826857c8SGleb Smirnoff 	struct epoch_tracker et;
4316826857c8SGleb Smirnoff 	struct ifmultiaddr *ifma;
4317826857c8SGleb Smirnoff 	u_int count;
4318826857c8SGleb Smirnoff 
4319826857c8SGleb Smirnoff 	MPASS(cb);
4320826857c8SGleb Smirnoff 
4321826857c8SGleb Smirnoff 	count = 0;
4322826857c8SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4323826857c8SGleb Smirnoff 	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
4324826857c8SGleb Smirnoff 		if (ifma->ifma_addr->sa_family != AF_LINK)
4325826857c8SGleb Smirnoff 			continue;
4326826857c8SGleb Smirnoff 		count += (*cb)(cb_arg, (struct sockaddr_dl *)ifma->ifma_addr,
4327826857c8SGleb Smirnoff 		    count);
4328826857c8SGleb Smirnoff 	}
4329826857c8SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4330826857c8SGleb Smirnoff 
4331826857c8SGleb Smirnoff 	return (count);
4332826857c8SGleb Smirnoff }
4333826857c8SGleb Smirnoff 
43341a75e3b2SAlexander V. Chernikov int
433562d76917SMarcel Moolenaar if_setsoftc(if_t ifp, void *softc)
433662d76917SMarcel Moolenaar {
433762d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_softc = softc;
433862d76917SMarcel Moolenaar 	return (0);
433962d76917SMarcel Moolenaar }
434062d76917SMarcel Moolenaar 
434162d76917SMarcel Moolenaar void *
434262d76917SMarcel Moolenaar if_getsoftc(if_t ifp)
434362d76917SMarcel Moolenaar {
434462d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_softc;
434562d76917SMarcel Moolenaar }
434662d76917SMarcel Moolenaar 
434762d76917SMarcel Moolenaar void
434862d76917SMarcel Moolenaar if_setrcvif(struct mbuf *m, if_t ifp)
434962d76917SMarcel Moolenaar {
4350fb3bc596SJohn Baldwin 
4351fb3bc596SJohn Baldwin 	MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
435262d76917SMarcel Moolenaar 	m->m_pkthdr.rcvif = (struct ifnet *)ifp;
435362d76917SMarcel Moolenaar }
435462d76917SMarcel Moolenaar 
435562d76917SMarcel Moolenaar void
435662d76917SMarcel Moolenaar if_setvtag(struct mbuf *m, uint16_t tag)
435762d76917SMarcel Moolenaar {
435862d76917SMarcel Moolenaar 	m->m_pkthdr.ether_vtag = tag;
435962d76917SMarcel Moolenaar }
436062d76917SMarcel Moolenaar 
436162d76917SMarcel Moolenaar uint16_t
436262d76917SMarcel Moolenaar if_getvtag(struct mbuf *m)
436362d76917SMarcel Moolenaar {
436462d76917SMarcel Moolenaar 
436562d76917SMarcel Moolenaar 	return (m->m_pkthdr.ether_vtag);
436662d76917SMarcel Moolenaar }
436762d76917SMarcel Moolenaar 
436862d76917SMarcel Moolenaar int
436962d76917SMarcel Moolenaar if_sendq_empty(if_t ifp)
437062d76917SMarcel Moolenaar {
437162d76917SMarcel Moolenaar 	return IFQ_DRV_IS_EMPTY(&((struct ifnet *)ifp)->if_snd);
437262d76917SMarcel Moolenaar }
437362d76917SMarcel Moolenaar 
437462d76917SMarcel Moolenaar struct ifaddr *
437562d76917SMarcel Moolenaar if_getifaddr(if_t ifp)
437662d76917SMarcel Moolenaar {
437762d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_addr;
437862d76917SMarcel Moolenaar }
437962d76917SMarcel Moolenaar 
438062d76917SMarcel Moolenaar int
438162d76917SMarcel Moolenaar if_getamcount(if_t ifp)
438262d76917SMarcel Moolenaar {
438362d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_amcount;
438462d76917SMarcel Moolenaar }
438562d76917SMarcel Moolenaar 
438662d76917SMarcel Moolenaar int
438762d76917SMarcel Moolenaar if_setsendqready(if_t ifp)
438862d76917SMarcel Moolenaar {
438962d76917SMarcel Moolenaar 	IFQ_SET_READY(&((struct ifnet *)ifp)->if_snd);
439062d76917SMarcel Moolenaar 	return (0);
439162d76917SMarcel Moolenaar }
439262d76917SMarcel Moolenaar 
439362d76917SMarcel Moolenaar int
439462d76917SMarcel Moolenaar if_setsendqlen(if_t ifp, int tx_desc_count)
439562d76917SMarcel Moolenaar {
439662d76917SMarcel Moolenaar 	IFQ_SET_MAXLEN(&((struct ifnet *)ifp)->if_snd, tx_desc_count);
439762d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_snd.ifq_drv_maxlen = tx_desc_count;
439862d76917SMarcel Moolenaar 
439962d76917SMarcel Moolenaar 	return (0);
440062d76917SMarcel Moolenaar }
440162d76917SMarcel Moolenaar 
440262d76917SMarcel Moolenaar int
440362d76917SMarcel Moolenaar if_vlantrunkinuse(if_t ifp)
440462d76917SMarcel Moolenaar {
440562d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_vlantrunk != NULL?1:0;
440662d76917SMarcel Moolenaar }
440762d76917SMarcel Moolenaar 
440862d76917SMarcel Moolenaar int
440962d76917SMarcel Moolenaar if_input(if_t ifp, struct mbuf* sendmp)
441062d76917SMarcel Moolenaar {
441162d76917SMarcel Moolenaar 	(*((struct ifnet *)ifp)->if_input)((struct ifnet *)ifp, sendmp);
441262d76917SMarcel Moolenaar 	return (0);
441362d76917SMarcel Moolenaar 
441462d76917SMarcel Moolenaar }
441562d76917SMarcel Moolenaar 
441662d76917SMarcel Moolenaar struct mbuf *
441762d76917SMarcel Moolenaar if_dequeue(if_t ifp)
441862d76917SMarcel Moolenaar {
441962d76917SMarcel Moolenaar 	struct mbuf *m;
442062d76917SMarcel Moolenaar 	IFQ_DRV_DEQUEUE(&((struct ifnet *)ifp)->if_snd, m);
442162d76917SMarcel Moolenaar 
442262d76917SMarcel Moolenaar 	return (m);
442362d76917SMarcel Moolenaar }
442462d76917SMarcel Moolenaar 
442562d76917SMarcel Moolenaar int
442662d76917SMarcel Moolenaar if_sendq_prepend(if_t ifp, struct mbuf *m)
442762d76917SMarcel Moolenaar {
442862d76917SMarcel Moolenaar 	IFQ_DRV_PREPEND(&((struct ifnet *)ifp)->if_snd, m);
442962d76917SMarcel Moolenaar 	return (0);
443062d76917SMarcel Moolenaar }
443162d76917SMarcel Moolenaar 
443262d76917SMarcel Moolenaar int
443362d76917SMarcel Moolenaar if_setifheaderlen(if_t ifp, int len)
443462d76917SMarcel Moolenaar {
4435e6485f73SGleb Smirnoff 	((struct ifnet *)ifp)->if_hdrlen = len;
443662d76917SMarcel Moolenaar 	return (0);
443762d76917SMarcel Moolenaar }
443862d76917SMarcel Moolenaar 
443962d76917SMarcel Moolenaar caddr_t
444062d76917SMarcel Moolenaar if_getlladdr(if_t ifp)
444162d76917SMarcel Moolenaar {
444262d76917SMarcel Moolenaar 	return (IF_LLADDR((struct ifnet *)ifp));
444362d76917SMarcel Moolenaar }
444462d76917SMarcel Moolenaar 
444562d76917SMarcel Moolenaar void *
444662d76917SMarcel Moolenaar if_gethandle(u_char type)
444762d76917SMarcel Moolenaar {
444862d76917SMarcel Moolenaar 	return (if_alloc(type));
444962d76917SMarcel Moolenaar }
445062d76917SMarcel Moolenaar 
445162d76917SMarcel Moolenaar void
445262d76917SMarcel Moolenaar if_bpfmtap(if_t ifh, struct mbuf *m)
445362d76917SMarcel Moolenaar {
445462d76917SMarcel Moolenaar 	struct ifnet *ifp = (struct ifnet *)ifh;
445562d76917SMarcel Moolenaar 
445662d76917SMarcel Moolenaar 	BPF_MTAP(ifp, m);
445762d76917SMarcel Moolenaar }
445862d76917SMarcel Moolenaar 
445962d76917SMarcel Moolenaar void
446062d76917SMarcel Moolenaar if_etherbpfmtap(if_t ifh, struct mbuf *m)
446162d76917SMarcel Moolenaar {
446262d76917SMarcel Moolenaar 	struct ifnet *ifp = (struct ifnet *)ifh;
446362d76917SMarcel Moolenaar 
446462d76917SMarcel Moolenaar 	ETHER_BPF_MTAP(ifp, m);
446562d76917SMarcel Moolenaar }
446662d76917SMarcel Moolenaar 
446762d76917SMarcel Moolenaar void
446862d76917SMarcel Moolenaar if_vlancap(if_t ifh)
446962d76917SMarcel Moolenaar {
447062d76917SMarcel Moolenaar 	struct ifnet *ifp = (struct ifnet *)ifh;
447162d76917SMarcel Moolenaar 	VLAN_CAPABILITIES(ifp);
447262d76917SMarcel Moolenaar }
447362d76917SMarcel Moolenaar 
4474d0b2cad1SStephen J. Kiernan int
4475d0b2cad1SStephen J. Kiernan if_sethwtsomax(if_t ifp, u_int if_hw_tsomax)
4476d0b2cad1SStephen J. Kiernan {
4477d0b2cad1SStephen J. Kiernan 
4478d0b2cad1SStephen J. Kiernan 	((struct ifnet *)ifp)->if_hw_tsomax = if_hw_tsomax;
4479d0b2cad1SStephen J. Kiernan         return (0);
4480d0b2cad1SStephen J. Kiernan }
4481d0b2cad1SStephen J. Kiernan 
4482d0b2cad1SStephen J. Kiernan int
4483d0b2cad1SStephen J. Kiernan if_sethwtsomaxsegcount(if_t ifp, u_int if_hw_tsomaxsegcount)
4484d0b2cad1SStephen J. Kiernan {
4485d0b2cad1SStephen J. Kiernan 
4486d0b2cad1SStephen J. Kiernan 	((struct ifnet *)ifp)->if_hw_tsomaxsegcount = if_hw_tsomaxsegcount;
4487d0b2cad1SStephen J. Kiernan         return (0);
4488d0b2cad1SStephen J. Kiernan }
4489d0b2cad1SStephen J. Kiernan 
4490d0b2cad1SStephen J. Kiernan int
4491d0b2cad1SStephen J. Kiernan if_sethwtsomaxsegsize(if_t ifp, u_int if_hw_tsomaxsegsize)
4492d0b2cad1SStephen J. Kiernan {
4493d0b2cad1SStephen J. Kiernan 
4494d0b2cad1SStephen J. Kiernan 	((struct ifnet *)ifp)->if_hw_tsomaxsegsize = if_hw_tsomaxsegsize;
4495d0b2cad1SStephen J. Kiernan         return (0);
4496d0b2cad1SStephen J. Kiernan }
4497d0b2cad1SStephen J. Kiernan 
4498d0b2cad1SStephen J. Kiernan u_int
4499d0b2cad1SStephen J. Kiernan if_gethwtsomax(if_t ifp)
4500d0b2cad1SStephen J. Kiernan {
4501d0b2cad1SStephen J. Kiernan 
4502d0b2cad1SStephen J. Kiernan 	return (((struct ifnet *)ifp)->if_hw_tsomax);
4503d0b2cad1SStephen J. Kiernan }
4504d0b2cad1SStephen J. Kiernan 
4505d0b2cad1SStephen J. Kiernan u_int
4506d0b2cad1SStephen J. Kiernan if_gethwtsomaxsegcount(if_t ifp)
4507d0b2cad1SStephen J. Kiernan {
4508d0b2cad1SStephen J. Kiernan 
4509d0b2cad1SStephen J. Kiernan 	return (((struct ifnet *)ifp)->if_hw_tsomaxsegcount);
4510d0b2cad1SStephen J. Kiernan }
4511d0b2cad1SStephen J. Kiernan 
4512d0b2cad1SStephen J. Kiernan u_int
4513d0b2cad1SStephen J. Kiernan if_gethwtsomaxsegsize(if_t ifp)
4514d0b2cad1SStephen J. Kiernan {
4515d0b2cad1SStephen J. Kiernan 
4516d0b2cad1SStephen J. Kiernan 	return (((struct ifnet *)ifp)->if_hw_tsomaxsegsize);
4517d0b2cad1SStephen J. Kiernan }
4518d0b2cad1SStephen J. Kiernan 
451962d76917SMarcel Moolenaar void
452062d76917SMarcel Moolenaar if_setinitfn(if_t ifp, void (*init_fn)(void *))
452162d76917SMarcel Moolenaar {
452262d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_init = init_fn;
452362d76917SMarcel Moolenaar }
452462d76917SMarcel Moolenaar 
452562d76917SMarcel Moolenaar void
452609a8241fSGleb Smirnoff if_setioctlfn(if_t ifp, int (*ioctl_fn)(if_t, u_long, caddr_t))
452762d76917SMarcel Moolenaar {
452862d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_ioctl = (void *)ioctl_fn;
452962d76917SMarcel Moolenaar }
453062d76917SMarcel Moolenaar 
453162d76917SMarcel Moolenaar void
453209a8241fSGleb Smirnoff if_setstartfn(if_t ifp, void (*start_fn)(if_t))
453362d76917SMarcel Moolenaar {
453462d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_start = (void *)start_fn;
453562d76917SMarcel Moolenaar }
453662d76917SMarcel Moolenaar 
453762d76917SMarcel Moolenaar void
453862d76917SMarcel Moolenaar if_settransmitfn(if_t ifp, if_transmit_fn_t start_fn)
453962d76917SMarcel Moolenaar {
454062d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_transmit = start_fn;
454162d76917SMarcel Moolenaar }
454262d76917SMarcel Moolenaar 
454362d76917SMarcel Moolenaar void if_setqflushfn(if_t ifp, if_qflush_fn_t flush_fn)
454462d76917SMarcel Moolenaar {
454562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_qflush = flush_fn;
454662d76917SMarcel Moolenaar 
454762d76917SMarcel Moolenaar }
454862d76917SMarcel Moolenaar 
454935853c2cSGleb Smirnoff void
455035853c2cSGleb Smirnoff if_setgetcounterfn(if_t ifp, if_get_counter_t fn)
455135853c2cSGleb Smirnoff {
455235853c2cSGleb Smirnoff 
455335853c2cSGleb Smirnoff 	ifp->if_get_counter = fn;
455435853c2cSGleb Smirnoff }
455535853c2cSGleb Smirnoff 
455662d76917SMarcel Moolenaar /* Revisit these - These are inline functions originally. */
455762d76917SMarcel Moolenaar int
455862d76917SMarcel Moolenaar drbr_inuse_drv(if_t ifh, struct buf_ring *br)
455962d76917SMarcel Moolenaar {
4560966ab68dSDimitry Andric 	return drbr_inuse(ifh, br);
456162d76917SMarcel Moolenaar }
456262d76917SMarcel Moolenaar 
456362d76917SMarcel Moolenaar struct mbuf*
456462d76917SMarcel Moolenaar drbr_dequeue_drv(if_t ifh, struct buf_ring *br)
456562d76917SMarcel Moolenaar {
456662d76917SMarcel Moolenaar 	return drbr_dequeue(ifh, br);
456762d76917SMarcel Moolenaar }
456862d76917SMarcel Moolenaar 
456962d76917SMarcel Moolenaar int
457062d76917SMarcel Moolenaar drbr_needs_enqueue_drv(if_t ifh, struct buf_ring *br)
457162d76917SMarcel Moolenaar {
457262d76917SMarcel Moolenaar 	return drbr_needs_enqueue(ifh, br);
457362d76917SMarcel Moolenaar }
457462d76917SMarcel Moolenaar 
457562d76917SMarcel Moolenaar int
457662d76917SMarcel Moolenaar drbr_enqueue_drv(if_t ifh, struct buf_ring *br, struct mbuf *m)
457762d76917SMarcel Moolenaar {
457862d76917SMarcel Moolenaar 	return drbr_enqueue(ifh, br, m);
457962d76917SMarcel Moolenaar 
458062d76917SMarcel Moolenaar }
4581