xref: /freebsd/sys/net/if.c (revision 274579831b61fccd5ce849350430e5167d0024f0)
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>
40*27457983SMark Johnston #include <sys/capsicum.h>
41f13ad206SJonathan Lemon #include <sys/conf.h>
42e2e050c8SConrad Meyer #include <sys/eventhandler.h>
434d1d4912SBruce Evans #include <sys/malloc.h>
447687707dSAndrew Gallatin #include <sys/domainset.h>
454dcf2bbbSBrooks Davis #include <sys/sbuf.h>
46d2b4566aSJonathan Lemon #include <sys/bus.h>
47d7c5a620SMatt Macy #include <sys/epoch.h>
48df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
49df8bae1dSRodney W. Grimes #include <sys/systm.h>
50acd3428bSRobert Watson #include <sys/priv.h>
51df8bae1dSRodney W. Grimes #include <sys/proc.h>
52df8bae1dSRodney W. Grimes #include <sys/socket.h>
53df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
54df8bae1dSRodney W. Grimes #include <sys/protosw.h>
55df8bae1dSRodney W. Grimes #include <sys/kernel.h>
56653735c4SBjoern A. Zeeb #include <sys/lock.h>
5727d37320SRobert Watson #include <sys/refcount.h>
5821ca7b57SMarko Zec #include <sys/module.h>
59653735c4SBjoern A. Zeeb #include <sys/rwlock.h>
6051a53488SBruce Evans #include <sys/sockio.h>
61963e4c2aSGarrett Wollman #include <sys/syslog.h>
62602d513cSGarrett Wollman #include <sys/sysctl.h>
6386d2ef16SBrooks Davis #include <sys/sysent.h>
64af5e59bfSRobert Watson #include <sys/taskqueue.h>
6531b1bfe1SHajimu UMEMOTO #include <sys/domain.h>
6691421ba2SRobert Watson #include <sys/jail.h>
6735fd7bc0SBjoern A. Zeeb #include <sys/priv.h>
6835fd7bc0SBjoern A. Zeeb 
69fa882e87SBrooks Davis #include <machine/stdarg.h>
706e6b3f7cSQing Li #include <vm/uma.h>
71df8bae1dSRodney W. Grimes 
7262d76917SMarcel Moolenaar #include <net/bpf.h>
7362d76917SMarcel Moolenaar #include <net/ethernet.h>
74df8bae1dSRodney W. Grimes #include <net/if.h>
755a97c9d4SBjoern A. Zeeb #include <net/if_arp.h>
76f889d2efSBrooks Davis #include <net/if_clone.h>
77df8bae1dSRodney W. Grimes #include <net/if_dl.h>
7866ce51ceSArchie Cobbs #include <net/if_types.h>
7930aad87dSBrooks Davis #include <net/if_var.h>
8062d76917SMarcel Moolenaar #include <net/if_media.h>
8162d76917SMarcel Moolenaar #include <net/if_vlan_var.h>
829448326fSPoul-Henning Kamp #include <net/radix.h>
835500d3beSWarner Losh #include <net/route.h>
84e1c05fd2SAlexander V. Chernikov #include <net/route/route_ctl.h>
854b79449eSBjoern A. Zeeb #include <net/vnet.h>
86df8bae1dSRodney W. Grimes 
870d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6)
88209579aeSRick Macklem #include <net/ethernet.h>
8982cd038dSYoshinobu Inoue #include <netinet/in.h>
900d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h>
913c914c54SAndre Oppermann #include <netinet/ip.h>
929963e8a5SWill Andrews #include <netinet/ip_carp.h>
933c914c54SAndre Oppermann #ifdef INET
947790c8c1SConrad Meyer #include <net/debugnet.h>
953c914c54SAndre Oppermann #include <netinet/if_ether.h>
963c914c54SAndre Oppermann #endif /* INET */
973411310dSYoshinobu Inoue #ifdef INET6
98978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h>
99978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h>
1003c914c54SAndre Oppermann #endif /* INET6 */
1013c914c54SAndre Oppermann #endif /* INET || INET6 */
10282cd038dSYoshinobu Inoue 
103aed55708SRobert Watson #include <security/mac/mac_framework.h>
104aed55708SRobert Watson 
1058708f1bdSBrooks Davis /*
1068708f1bdSBrooks Davis  * Consumers of struct ifreq such as tcpdump assume no pad between ifr_name
1078708f1bdSBrooks Davis  * and ifr_ifru when it is used in SIOCGIFCONF.
1088708f1bdSBrooks Davis  */
1098708f1bdSBrooks Davis _Static_assert(sizeof(((struct ifreq *)0)->ifr_name) ==
1108708f1bdSBrooks Davis     offsetof(struct ifreq, ifr_ifru), "gap between ifr_name and ifr_ifru");
1118708f1bdSBrooks Davis 
112d71e30deSMatt Macy __read_mostly epoch_t net_epoch_preempt;
1139af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32
1149af74f3dSSergey Kandaurov #include <sys/mount.h>
1159af74f3dSSergey Kandaurov #include <compat/freebsd32/freebsd32.h>
11686d2ef16SBrooks Davis 
11786d2ef16SBrooks Davis struct ifreq_buffer32 {
11886d2ef16SBrooks Davis 	uint32_t	length;		/* (size_t) */
11986d2ef16SBrooks Davis 	uint32_t	buffer;		/* (void *) */
12086d2ef16SBrooks Davis };
12186d2ef16SBrooks Davis 
12286d2ef16SBrooks Davis /*
12386d2ef16SBrooks Davis  * Interface request structure used for socket
12486d2ef16SBrooks Davis  * ioctl's.  All interface ioctl's must have parameter
12586d2ef16SBrooks Davis  * definitions which begin with ifr_name.  The
12686d2ef16SBrooks Davis  * remainder may be interface specific.
12786d2ef16SBrooks Davis  */
12886d2ef16SBrooks Davis struct ifreq32 {
12986d2ef16SBrooks Davis 	char	ifr_name[IFNAMSIZ];		/* if name, e.g. "en0" */
13086d2ef16SBrooks Davis 	union {
13186d2ef16SBrooks Davis 		struct sockaddr	ifru_addr;
13286d2ef16SBrooks Davis 		struct sockaddr	ifru_dstaddr;
13386d2ef16SBrooks Davis 		struct sockaddr	ifru_broadaddr;
13486d2ef16SBrooks Davis 		struct ifreq_buffer32 ifru_buffer;
13586d2ef16SBrooks Davis 		short		ifru_flags[2];
13686d2ef16SBrooks Davis 		short		ifru_index;
13786d2ef16SBrooks Davis 		int		ifru_jid;
13886d2ef16SBrooks Davis 		int		ifru_metric;
13986d2ef16SBrooks Davis 		int		ifru_mtu;
14086d2ef16SBrooks Davis 		int		ifru_phys;
14186d2ef16SBrooks Davis 		int		ifru_media;
14286d2ef16SBrooks Davis 		uint32_t	ifru_data;
14386d2ef16SBrooks Davis 		int		ifru_cap[2];
14486d2ef16SBrooks Davis 		u_int		ifru_fib;
14586d2ef16SBrooks Davis 		u_char		ifru_vlan_pcp;
14686d2ef16SBrooks Davis 	} ifr_ifru;
14786d2ef16SBrooks Davis };
14886d2ef16SBrooks Davis CTASSERT(sizeof(struct ifreq) == sizeof(struct ifreq32));
14986d2ef16SBrooks Davis CTASSERT(__offsetof(struct ifreq, ifr_ifru) ==
15086d2ef16SBrooks Davis     __offsetof(struct ifreq32, ifr_ifru));
151756181b8SBrooks Davis 
152756181b8SBrooks Davis struct ifgroupreq32 {
153756181b8SBrooks Davis 	char	ifgr_name[IFNAMSIZ];
154756181b8SBrooks Davis 	u_int	ifgr_len;
155756181b8SBrooks Davis 	union {
156756181b8SBrooks Davis 		char		ifgru_group[IFNAMSIZ];
157756181b8SBrooks Davis 		uint32_t	ifgru_groups;
158756181b8SBrooks Davis 	} ifgr_ifgru;
159756181b8SBrooks Davis };
1603edb7f4eSBrooks Davis 
1613edb7f4eSBrooks Davis struct ifmediareq32 {
1623edb7f4eSBrooks Davis 	char		ifm_name[IFNAMSIZ];
1633edb7f4eSBrooks Davis 	int		ifm_current;
1643edb7f4eSBrooks Davis 	int		ifm_mask;
1653edb7f4eSBrooks Davis 	int		ifm_status;
1663edb7f4eSBrooks Davis 	int		ifm_active;
1673edb7f4eSBrooks Davis 	int		ifm_count;
1683edb7f4eSBrooks Davis 	uint32_t	ifm_ulist;	/* (int *) */
1693edb7f4eSBrooks Davis };
1703edb7f4eSBrooks Davis #define	SIOCGIFMEDIA32	_IOC_NEWTYPE(SIOCGIFMEDIA, struct ifmediareq32)
1713edb7f4eSBrooks Davis #define	SIOCGIFXMEDIA32	_IOC_NEWTYPE(SIOCGIFXMEDIA, struct ifmediareq32)
1723edb7f4eSBrooks Davis 
173756181b8SBrooks Davis #define	_CASE_IOC_IFGROUPREQ_32(cmd)				\
174bc6f170eSBrooks Davis     _IOC_NEWTYPE((cmd), struct ifgroupreq32): case
1753edb7f4eSBrooks Davis #else /* !COMPAT_FREEBSD32 */
176756181b8SBrooks Davis #define _CASE_IOC_IFGROUPREQ_32(cmd)
1773edb7f4eSBrooks Davis #endif /* !COMPAT_FREEBSD32 */
178756181b8SBrooks Davis 
179756181b8SBrooks Davis #define CASE_IOC_IFGROUPREQ(cmd)	\
180756181b8SBrooks Davis     _CASE_IOC_IFGROUPREQ_32(cmd)	\
181bc6f170eSBrooks Davis     (cmd)
1829af74f3dSSergey Kandaurov 
18386d2ef16SBrooks Davis union ifreq_union {
18486d2ef16SBrooks Davis 	struct ifreq	ifr;
18586d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
18686d2ef16SBrooks Davis 	struct ifreq32	ifr32;
18786d2ef16SBrooks Davis #endif
18886d2ef16SBrooks Davis };
18986d2ef16SBrooks Davis 
190756181b8SBrooks Davis union ifgroupreq_union {
191756181b8SBrooks Davis 	struct ifgroupreq ifgr;
192756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32
193756181b8SBrooks Davis 	struct ifgroupreq32 ifgr32;
194756181b8SBrooks Davis #endif
195756181b8SBrooks Davis };
196756181b8SBrooks Davis 
1977029da5cSPawel Biernacki SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
1987029da5cSPawel Biernacki     "Link layers");
1997029da5cSPawel Biernacki SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW | CTLFLAG_MPSAFE, 0,
2007029da5cSPawel Biernacki     "Generic link-management");
2015515c2e7SGleb Smirnoff 
202f88910cdSMatthew D Fleming SYSCTL_INT(_net_link, OID_AUTO, ifqmaxlen, CTLFLAG_RDTUN,
203e50d35e6SMaxim Sobolev     &ifqmaxlen, 0, "max send queue size");
204e50d35e6SMaxim Sobolev 
2055515c2e7SGleb Smirnoff /* Log link state change events */
2065515c2e7SGleb Smirnoff static int log_link_state_change = 1;
2075515c2e7SGleb Smirnoff 
2085515c2e7SGleb Smirnoff SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW,
2095515c2e7SGleb Smirnoff 	&log_link_state_change, 0,
2105515c2e7SGleb Smirnoff 	"log interface link state change events");
2115515c2e7SGleb Smirnoff 
2126d07c157SNick Hibma /* Log promiscuous mode change events */
2136d07c157SNick Hibma static int log_promisc_mode_change = 1;
2146d07c157SNick Hibma 
215dbd2ee46SNick Hibma SYSCTL_INT(_net_link, OID_AUTO, log_promisc_mode_change, CTLFLAG_RDTUN,
2166d07c157SNick Hibma 	&log_promisc_mode_change, 1,
2176d07c157SNick Hibma 	"log promiscuous mode change events");
2186d07c157SNick Hibma 
219215940b3SXin LI /* Interface description */
220215940b3SXin LI static unsigned int ifdescr_maxlen = 1024;
221215940b3SXin LI SYSCTL_UINT(_net, OID_AUTO, ifdescr_maxlen, CTLFLAG_RW,
222215940b3SXin LI 	&ifdescr_maxlen, 0,
223215940b3SXin LI 	"administrative maximum length for interface description");
224215940b3SXin LI 
225d745c852SEd Schouten static MALLOC_DEFINE(M_IFDESCR, "ifdescr", "ifnet descriptions");
226215940b3SXin LI 
227215940b3SXin LI /* global sx for non-critical path ifdescr */
228215940b3SXin LI static struct sx ifdescr_sx;
229215940b3SXin LI SX_SYSINIT(ifdescr_sx, &ifdescr_sx, "ifnet descr");
230215940b3SXin LI 
2311c7899c7SGleb Smirnoff void	(*ng_ether_link_state_p)(struct ifnet *ifp, int state);
232d6e82913SSteven Hartland void	(*lagg_linkstate_p)(struct ifnet *ifp, int state);
2339963e8a5SWill Andrews /* These are external hooks for CARP. */
23454bfbd51SWill Andrews void	(*carp_linkstate_p)(struct ifnet *ifp);
235f08535f8SGleb Smirnoff void	(*carp_demote_adj_p)(int, char *);
23624421c1cSGleb Smirnoff int	(*carp_master_p)(struct ifaddr *);
2379963e8a5SWill Andrews #if defined(INET) || defined(INET6)
23808b68b0eSGleb Smirnoff int	(*carp_forus_p)(struct ifnet *ifp, u_char *dhost);
2399963e8a5SWill Andrews int	(*carp_output_p)(struct ifnet *ifp, struct mbuf *m,
24047e8d432SGleb Smirnoff     const struct sockaddr *sa);
24108b68b0eSGleb Smirnoff int	(*carp_ioctl_p)(struct ifreq *, u_long, struct thread *);
24208b68b0eSGleb Smirnoff int	(*carp_attach_p)(struct ifaddr *, int);
243338e227aSLuiz Otavio O Souza void	(*carp_detach_p)(struct ifaddr *, bool);
2449963e8a5SWill Andrews #endif
2459963e8a5SWill Andrews #ifdef INET
24608b68b0eSGleb Smirnoff int	(*carp_iamatch_p)(struct ifaddr *, uint8_t **);
2479963e8a5SWill Andrews #endif
2489963e8a5SWill Andrews #ifdef INET6
2499963e8a5SWill Andrews struct ifaddr *(*carp_iamatch6_p)(struct ifnet *ifp, struct in6_addr *taddr6);
2509963e8a5SWill Andrews caddr_t	(*carp_macmatch6_p)(struct ifnet *ifp, struct mbuf *m,
2519963e8a5SWill Andrews     const struct in6_addr *taddr);
2529963e8a5SWill Andrews #endif
2531c7899c7SGleb Smirnoff 
2544cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
2554cb655c0SMax Laier 
256ec002feeSBruce M Simpson /*
257ec002feeSBruce M Simpson  * XXX: Style; these should be sorted alphabetically, and unprototyped
258ec002feeSBruce M Simpson  * static functions should be prototyped. Currently they are sorted by
259ec002feeSBruce M Simpson  * declaration order.
260ec002feeSBruce M Simpson  */
26131b1bfe1SHajimu UMEMOTO static void	if_attachdomain(void *);
26231b1bfe1SHajimu UMEMOTO static void	if_attachdomain1(struct ifnet *);
2630b59d917SJonathan Lemon static int	ifconf(u_long, caddr_t);
2644f6c66ccSMatt Macy static void	*if_grow(void);
265b57d9721SAndrey V. Elsukov static void	if_input_default(struct ifnet *, struct mbuf *);
2664fb3a820SAlexander V. Chernikov static int	if_requestencap_default(struct ifnet *, struct if_encap_req *);
2678614fb12SMax Laier static void	if_route(struct ifnet *, int flag, int fam);
2681a3b6859SYaroslav Tykhiy static int	if_setflag(struct ifnet *, int, int, int *, int);
269db7f0b97SKip Macy static int	if_transmit(struct ifnet *ifp, struct mbuf *m);
2708614fb12SMax Laier static void	if_unroute(struct ifnet *, int flag, int fam);
271ec002feeSBruce M Simpson static int	if_delmulti_locked(struct ifnet *, struct ifmultiaddr *, int);
27268a3482fSGleb Smirnoff static void	do_link_state_change(void *, int);
2730dad3f0eSMax Laier static int	if_getgroup(struct ifgroupreq *, struct ifnet *);
2740dad3f0eSMax Laier static int	if_getgroupmembers(struct ifgroupreq *);
2758623f9fdSMax Laier static void	if_delgroups(struct ifnet *);
276c92a456bSHiroki Sato static void	if_attach_internal(struct ifnet *, int, struct if_clone *);
277f501e6f1SBjoern A. Zeeb static int	if_detach_internal(struct ifnet *, int, struct if_clone **);
2780839aa5cSGleb Smirnoff static void	if_siocaddmulti(void *, int);
279a779388fSKristof Provost static void	if_link_ifnet(struct ifnet *);
280a779388fSKristof Provost static bool	if_unlink_ifnet(struct ifnet *, bool);
281ad4e9116SBjoern A. Zeeb #ifdef VIMAGE
282c7bab2a7SKyle Evans static int	if_vmove(struct ifnet *, struct vnet *);
283ad4e9116SBjoern A. Zeeb #endif
284db7f0b97SKip Macy 
28582cd038dSYoshinobu Inoue #ifdef INET6
28682cd038dSYoshinobu Inoue /*
28782cd038dSYoshinobu Inoue  * XXX: declare here to avoid to include many inet6 related files..
28882cd038dSYoshinobu Inoue  * should be more generalized?
28982cd038dSYoshinobu Inoue  */
290929ddbbbSAlfred Perlstein extern void	nd6_setmtu(struct ifnet *);
29182cd038dSYoshinobu Inoue #endif
29282cd038dSYoshinobu Inoue 
293ef91a976SAndrey V. Elsukov /* ipsec helper hooks */
294ef91a976SAndrey V. Elsukov VNET_DEFINE(struct hhook_head *, ipsec_hhh_in[HHOOK_IPSEC_COUNT]);
295ef91a976SAndrey V. Elsukov VNET_DEFINE(struct hhook_head *, ipsec_hhh_out[HHOOK_IPSEC_COUNT]);
296ef91a976SAndrey V. Elsukov 
29782cea7e6SBjoern A. Zeeb VNET_DEFINE(int, if_index);
29882cea7e6SBjoern A. Zeeb int	ifqmaxlen = IFQ_MAXLEN;
299eddfbb76SRobert Watson VNET_DEFINE(struct ifnethead, ifnet);	/* depend on static init XXX */
300eddfbb76SRobert Watson VNET_DEFINE(struct ifgrouphead, ifg_head);
30182cea7e6SBjoern A. Zeeb 
3025f901c92SAndrew Turner VNET_DEFINE_STATIC(int, if_indexlim) = 8;
303eddfbb76SRobert Watson 
30477dfcdc4SRobert Watson /* Table of ifnet by index. */
305e6abef09SGleb Smirnoff VNET_DEFINE(struct ifnet **, ifindex_table);
306eddfbb76SRobert Watson 
3071e77c105SRobert Watson #define	V_if_indexlim		VNET(if_indexlim)
3081e77c105SRobert Watson #define	V_ifindex_table		VNET(ifindex_table)
30944e33a07SMarko Zec 
31077dfcdc4SRobert Watson /*
31177dfcdc4SRobert Watson  * The global network interface list (V_ifnet) and related state (such as
312a60100fdSKristof Provost  * if_index, if_indexlim, and ifindex_table) are protected by an sxlock.
313a60100fdSKristof Provost  * This may be acquired to stabilise the list, or we may rely on NET_EPOCH.
31477dfcdc4SRobert Watson  */
31577dfcdc4SRobert Watson struct sx ifnet_sxlock;
3164ea05db8SGleb Smirnoff SX_SYSINIT_FLAGS(ifnet_sx, &ifnet_sxlock, "ifnet_sx", SX_RECURSE);
31777dfcdc4SRobert Watson 
318e133271fSKristof Provost struct sx ifnet_detach_sxlock;
3196d2a10d9SKristof Provost SX_SYSINIT_FLAGS(ifnet_detach, &ifnet_detach_sxlock, "ifnet_detach_sx",
3206d2a10d9SKristof Provost     SX_RECURSE);
321e133271fSKristof Provost 
322ed2dabfcSRobert Watson /*
323ed2dabfcSRobert Watson  * The allocation of network interfaces is a rather non-atomic affair; we
324ed2dabfcSRobert Watson  * need to select an index before we are ready to expose the interface for
325ed2dabfcSRobert Watson  * use, so will use this pointer value to indicate reservation.
326ed2dabfcSRobert Watson  */
327ed2dabfcSRobert Watson #define	IFNET_HOLD	(void *)(uintptr_t)(-1)
328ed2dabfcSRobert Watson 
32910108cb6SBjoern A. Zeeb #ifdef VIMAGE
33010108cb6SBjoern A. Zeeb #define	VNET_IS_SHUTTING_DOWN(_vnet)					\
33110108cb6SBjoern A. Zeeb     ((_vnet)->vnet_shutdown && (_vnet)->vnet_state < SI_SUB_VNET_DONE)
33210108cb6SBjoern A. Zeeb #endif
33310108cb6SBjoern A. Zeeb 
334fc74a9f9SBrooks Davis static	if_com_alloc_t *if_com_alloc[256];
335fc74a9f9SBrooks Davis static	if_com_free_t *if_com_free[256];
3360b59d917SJonathan Lemon 
337d745c852SEd Schouten static MALLOC_DEFINE(M_IFNET, "ifnet", "interface internals");
3380b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
3390b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
34030aad87dSBrooks Davis 
34121ca7b57SMarko Zec struct ifnet *
342d24c444cSKip Macy ifnet_byindex(u_short idx)
343d24c444cSKip Macy {
344d24c444cSKip Macy 	struct ifnet *ifp;
345d24c444cSKip Macy 
346270b83b9SHans Petter Selasky 	if (__predict_false(idx > V_if_index))
347270b83b9SHans Petter Selasky 		return (NULL);
348270b83b9SHans Petter Selasky 
349270b83b9SHans Petter Selasky 	ifp = *(struct ifnet * const volatile *)(V_ifindex_table + idx);
350270b83b9SHans Petter Selasky 	return (__predict_false(ifp == IFNET_HOLD) ? NULL : ifp);
35102f4879dSRobert Watson }
35202f4879dSRobert Watson 
35327d37320SRobert Watson struct ifnet *
35427d37320SRobert Watson ifnet_byindex_ref(u_short idx)
35527d37320SRobert Watson {
35627d37320SRobert Watson 	struct ifnet *ifp;
35727d37320SRobert Watson 
358b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
359b8a6e03fSGleb Smirnoff 
360270b83b9SHans Petter Selasky 	ifp = ifnet_byindex(idx);
361b8a6e03fSGleb Smirnoff 	if (ifp == NULL || (ifp->if_flags & IFF_DYING))
36227d37320SRobert Watson 		return (NULL);
3637563019bSAlexander V. Chernikov 	if (!if_try_ref(ifp))
3647563019bSAlexander V. Chernikov 		return (NULL);
36527d37320SRobert Watson 	return (ifp);
36627d37320SRobert Watson }
36727d37320SRobert Watson 
36861f6986bSRobert Watson /*
36961f6986bSRobert Watson  * Allocate an ifindex array entry; return 0 on success or an error on
37061f6986bSRobert Watson  * failure.
37161f6986bSRobert Watson  */
372f4507b71SGleb Smirnoff static u_short
3734f6c66ccSMatt Macy ifindex_alloc(void **old)
37461f6986bSRobert Watson {
37561f6986bSRobert Watson 	u_short idx;
37661f6986bSRobert Watson 
37761f6986bSRobert Watson 	IFNET_WLOCK_ASSERT();
37861f6986bSRobert Watson 	/*
379ed2dabfcSRobert Watson 	 * Try to find an empty slot below V_if_index.  If we fail, take the
38061f6986bSRobert Watson 	 * next slot.
38161f6986bSRobert Watson 	 */
38261f6986bSRobert Watson 	for (idx = 1; idx <= V_if_index; idx++) {
383e6abef09SGleb Smirnoff 		if (V_ifindex_table[idx] == NULL)
38461f6986bSRobert Watson 			break;
38561f6986bSRobert Watson 	}
38661f6986bSRobert Watson 
38761f6986bSRobert Watson 	/* Catch if_index overflow. */
3885f3b301aSJohn Baldwin 	if (idx >= V_if_indexlim) {
3894f6c66ccSMatt Macy 		*old = if_grow();
3904f6c66ccSMatt Macy 		return (USHRT_MAX);
3915f3b301aSJohn Baldwin 	}
39261f6986bSRobert Watson 	if (idx > V_if_index)
39361f6986bSRobert Watson 		V_if_index = idx;
394f4507b71SGleb Smirnoff 	return (idx);
39561f6986bSRobert Watson }
39661f6986bSRobert Watson 
397e0c14af9SMarko Zec static void
398ed2dabfcSRobert Watson ifindex_free_locked(u_short idx)
399ed2dabfcSRobert Watson {
400ed2dabfcSRobert Watson 
401ed2dabfcSRobert Watson 	IFNET_WLOCK_ASSERT();
402ed2dabfcSRobert Watson 
403e6abef09SGleb Smirnoff 	V_ifindex_table[idx] = NULL;
404ed2dabfcSRobert Watson 	while (V_if_index > 0 &&
405e6abef09SGleb Smirnoff 	    V_ifindex_table[V_if_index] == NULL)
406ed2dabfcSRobert Watson 		V_if_index--;
407ed2dabfcSRobert Watson }
408ed2dabfcSRobert Watson 
409ed2dabfcSRobert Watson static void
410ed2dabfcSRobert Watson ifindex_free(u_short idx)
411ed2dabfcSRobert Watson {
412ed2dabfcSRobert Watson 
413ed2dabfcSRobert Watson 	IFNET_WLOCK();
414ed2dabfcSRobert Watson 	ifindex_free_locked(idx);
415ed2dabfcSRobert Watson 	IFNET_WUNLOCK();
416ed2dabfcSRobert Watson }
417ed2dabfcSRobert Watson 
418ed2dabfcSRobert Watson static void
41977dfcdc4SRobert Watson ifnet_setbyindex(u_short idx, struct ifnet *ifp)
42077dfcdc4SRobert Watson {
42177dfcdc4SRobert Watson 
4224f6c66ccSMatt Macy 	V_ifindex_table[idx] = ifp;
42377dfcdc4SRobert Watson }
42477dfcdc4SRobert Watson 
42502f4879dSRobert Watson struct ifaddr *
42602f4879dSRobert Watson ifaddr_byindex(u_short idx)
42702f4879dSRobert Watson {
42822a93840SMarko Zec 	struct ifnet *ifp;
42922a93840SMarko Zec 	struct ifaddr *ifa = NULL;
43002f4879dSRobert Watson 
431b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
432b8a6e03fSGleb Smirnoff 
433270b83b9SHans Petter Selasky 	ifp = ifnet_byindex(idx);
43422a93840SMarko Zec 	if (ifp != NULL && (ifa = ifp->if_addr) != NULL)
4358c0fec80SRobert Watson 		ifa_ref(ifa);
43602f4879dSRobert Watson 	return (ifa);
43702f4879dSRobert Watson }
43802f4879dSRobert Watson 
439df8bae1dSRodney W. Grimes /*
440df8bae1dSRodney W. Grimes  * Network interface utility routines.
441df8bae1dSRodney W. Grimes  *
442df8bae1dSRodney W. Grimes  * Routines with ifa_ifwith* names take sockaddr *'s as
443df8bae1dSRodney W. Grimes  * parameters.
444df8bae1dSRodney W. Grimes  */
445a45cbf12SBrooks Davis 
446f9132cebSJonathan Lemon static void
447d0728d71SRobert Watson vnet_if_init(const void *unused __unused)
4481ed81b73SMarko Zec {
4494f6c66ccSMatt Macy 	void *old;
45044e33a07SMarko Zec 
4514f6c66ccSMatt Macy 	CK_STAILQ_INIT(&V_ifnet);
4524f6c66ccSMatt Macy 	CK_STAILQ_INIT(&V_ifg_head);
4535f3b301aSJohn Baldwin 	IFNET_WLOCK();
4544f6c66ccSMatt Macy 	old = if_grow();				/* create initial table */
4555f3b301aSJohn Baldwin 	IFNET_WUNLOCK();
4564f6c66ccSMatt Macy 	epoch_wait_preempt(net_epoch_preempt);
4574f6c66ccSMatt Macy 	free(old, M_IFNET);
458d0728d71SRobert Watson 	vnet_if_clone_init();
459f9132cebSJonathan Lemon }
4605f3b301aSJohn Baldwin VNET_SYSINIT(vnet_if_init, SI_SUB_INIT_IF, SI_ORDER_SECOND, vnet_if_init,
461d0728d71SRobert Watson     NULL);
462d0728d71SRobert Watson 
463bc29160dSMarko Zec #ifdef VIMAGE
464d0728d71SRobert Watson static void
465d0728d71SRobert Watson vnet_if_uninit(const void *unused __unused)
466bc29160dSMarko Zec {
467bc29160dSMarko Zec 
4684f6c66ccSMatt Macy 	VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifnet), ("%s:%d tailq &V_ifnet=%p "
4690028e524SBjoern A. Zeeb 	    "not empty", __func__, __LINE__, &V_ifnet));
4704f6c66ccSMatt Macy 	VNET_ASSERT(CK_STAILQ_EMPTY(&V_ifg_head), ("%s:%d tailq &V_ifg_head=%p "
4710028e524SBjoern A. Zeeb 	    "not empty", __func__, __LINE__, &V_ifg_head));
472bc29160dSMarko Zec 
473bc29160dSMarko Zec 	free((caddr_t)V_ifindex_table, M_IFNET);
474bc29160dSMarko Zec }
475d0728d71SRobert Watson VNET_SYSUNINIT(vnet_if_uninit, SI_SUB_INIT_IF, SI_ORDER_FIRST,
476d0728d71SRobert Watson     vnet_if_uninit, NULL);
477bca0e1d2SKristof Provost #endif
478ad4e9116SBjoern A. Zeeb 
479ad4e9116SBjoern A. Zeeb static void
480a779388fSKristof Provost if_link_ifnet(struct ifnet *ifp)
481a779388fSKristof Provost {
482a779388fSKristof Provost 
483a779388fSKristof Provost 	IFNET_WLOCK();
484a779388fSKristof Provost 	CK_STAILQ_INSERT_TAIL(&V_ifnet, ifp, if_link);
485a779388fSKristof Provost #ifdef VIMAGE
486a779388fSKristof Provost 	curvnet->vnet_ifcnt++;
487a779388fSKristof Provost #endif
488a779388fSKristof Provost 	IFNET_WUNLOCK();
489a779388fSKristof Provost }
490a779388fSKristof Provost 
491a779388fSKristof Provost static bool
492a779388fSKristof Provost if_unlink_ifnet(struct ifnet *ifp, bool vmove)
493a779388fSKristof Provost {
494a779388fSKristof Provost 	struct ifnet *iter;
495a779388fSKristof Provost 	int found = 0;
496a779388fSKristof Provost 
497a779388fSKristof Provost 	IFNET_WLOCK();
498a779388fSKristof Provost 	CK_STAILQ_FOREACH(iter, &V_ifnet, if_link)
499a779388fSKristof Provost 		if (iter == ifp) {
500a779388fSKristof Provost 			CK_STAILQ_REMOVE(&V_ifnet, ifp, ifnet, if_link);
501a779388fSKristof Provost 			if (!vmove)
502a779388fSKristof Provost 				ifp->if_flags |= IFF_DYING;
503a779388fSKristof Provost 			found = 1;
504a779388fSKristof Provost 			break;
505a779388fSKristof Provost 		}
506a779388fSKristof Provost #ifdef VIMAGE
507a779388fSKristof Provost 	curvnet->vnet_ifcnt--;
508a779388fSKristof Provost #endif
509a779388fSKristof Provost 	IFNET_WUNLOCK();
510a779388fSKristof Provost 
511a779388fSKristof Provost 	return (found);
512a779388fSKristof Provost }
513a779388fSKristof Provost 
514bca0e1d2SKristof Provost #ifdef VIMAGE
515a779388fSKristof Provost static void
516ad4e9116SBjoern A. Zeeb vnet_if_return(const void *unused __unused)
517ad4e9116SBjoern A. Zeeb {
518ad4e9116SBjoern A. Zeeb 	struct ifnet *ifp, *nifp;
519a779388fSKristof Provost 	struct ifnet **pending;
520a779388fSKristof Provost 	int found, i;
521a779388fSKristof Provost 
522a779388fSKristof Provost 	i = 0;
523a779388fSKristof Provost 
524a779388fSKristof Provost 	/*
525a779388fSKristof Provost 	 * We need to protect our access to the V_ifnet tailq. Ordinarily we'd
526a779388fSKristof Provost 	 * enter NET_EPOCH, but that's not possible, because if_vmove() calls
527a779388fSKristof Provost 	 * if_detach_internal(), which waits for NET_EPOCH callbacks to
528a779388fSKristof Provost 	 * complete. We can't do that from within NET_EPOCH.
529a779388fSKristof Provost 	 *
530a779388fSKristof Provost 	 * However, we can also use the IFNET_xLOCK, which is the V_ifnet
531a779388fSKristof Provost 	 * read/write lock. We cannot hold the lock as we call if_vmove()
532a779388fSKristof Provost 	 * though, as that presents LOR w.r.t ifnet_sx, in_multi_sx and iflib
533a779388fSKristof Provost 	 * ctx lock.
534a779388fSKristof Provost 	 */
535a779388fSKristof Provost 	IFNET_WLOCK();
536a779388fSKristof Provost 
537a779388fSKristof Provost 	pending = malloc(sizeof(struct ifnet *) * curvnet->vnet_ifcnt,
538a779388fSKristof Provost 	    M_IFNET, M_WAITOK | M_ZERO);
539ad4e9116SBjoern A. Zeeb 
540ad4e9116SBjoern A. Zeeb 	/* Return all inherited interfaces to their parent vnets. */
5414f6c66ccSMatt Macy 	CK_STAILQ_FOREACH_SAFE(ifp, &V_ifnet, if_link, nifp) {
542a779388fSKristof Provost 		if (ifp->if_home_vnet != ifp->if_vnet) {
543a779388fSKristof Provost 			found = if_unlink_ifnet(ifp, true);
544a779388fSKristof Provost 			MPASS(found);
545a779388fSKristof Provost 
546a779388fSKristof Provost 			pending[i++] = ifp;
547ad4e9116SBjoern A. Zeeb 		}
548ad4e9116SBjoern A. Zeeb 	}
549a779388fSKristof Provost 	IFNET_WUNLOCK();
550a779388fSKristof Provost 
551a779388fSKristof Provost 	for (int j = 0; j < i; j++) {
552a779388fSKristof Provost 		if_vmove(pending[j], pending[j]->if_home_vnet);
553a779388fSKristof Provost 	}
554a779388fSKristof Provost 
555a779388fSKristof Provost 	free(pending, M_IFNET);
556a779388fSKristof Provost }
557ad4e9116SBjoern A. Zeeb VNET_SYSUNINIT(vnet_if_return, SI_SUB_VNET_DONE, SI_ORDER_ANY,
558ad4e9116SBjoern A. Zeeb     vnet_if_return, NULL);
559bc29160dSMarko Zec #endif
560bc29160dSMarko Zec 
5614f6c66ccSMatt Macy static void *
562f9132cebSJonathan Lemon if_grow(void)
563f9132cebSJonathan Lemon {
5645f3b301aSJohn Baldwin 	int oldlim;
565f9132cebSJonathan Lemon 	u_int n;
566e6abef09SGleb Smirnoff 	struct ifnet **e;
5674f6c66ccSMatt Macy 	void *old;
568f9132cebSJonathan Lemon 
5694f6c66ccSMatt Macy 	old = NULL;
5705f3b301aSJohn Baldwin 	IFNET_WLOCK_ASSERT();
5715f3b301aSJohn Baldwin 	oldlim = V_if_indexlim;
5725f3b301aSJohn Baldwin 	IFNET_WUNLOCK();
5735f3b301aSJohn Baldwin 	n = (oldlim << 1) * sizeof(*e);
574fc74a9f9SBrooks Davis 	e = malloc(n, M_IFNET, M_WAITOK | M_ZERO);
5755f3b301aSJohn Baldwin 	IFNET_WLOCK();
5765f3b301aSJohn Baldwin 	if (V_if_indexlim != oldlim) {
5775f3b301aSJohn Baldwin 		free(e, M_IFNET);
5784f6c66ccSMatt Macy 		return (NULL);
5795f3b301aSJohn Baldwin 	}
580603724d3SBjoern A. Zeeb 	if (V_ifindex_table != NULL) {
581603724d3SBjoern A. Zeeb 		memcpy((caddr_t)e, (caddr_t)V_ifindex_table, n/2);
5824f6c66ccSMatt Macy 		old = V_ifindex_table;
583f9132cebSJonathan Lemon 	}
5845f3b301aSJohn Baldwin 	V_if_indexlim <<= 1;
585603724d3SBjoern A. Zeeb 	V_ifindex_table = e;
5864f6c66ccSMatt Macy 	return (old);
587f9132cebSJonathan Lemon }
588f9132cebSJonathan Lemon 
589df8bae1dSRodney W. Grimes /*
590a45cbf12SBrooks Davis  * Allocate a struct ifnet and an index for an interface.  A layer 2
591a45cbf12SBrooks Davis  * common structure will also be allocated if an allocation routine is
592a45cbf12SBrooks Davis  * registered for the passed type.
593fc74a9f9SBrooks Davis  */
594fc74a9f9SBrooks Davis struct ifnet *
5957687707dSAndrew Gallatin if_alloc_domain(u_char type, int numa_domain)
596fc74a9f9SBrooks Davis {
597fc74a9f9SBrooks Davis 	struct ifnet *ifp;
59861f6986bSRobert Watson 	u_short idx;
5994f6c66ccSMatt Macy 	void *old;
600fc74a9f9SBrooks Davis 
6017687707dSAndrew Gallatin 	KASSERT(numa_domain <= IF_NODOM, ("numa_domain too large"));
6027687707dSAndrew Gallatin 	if (numa_domain == IF_NODOM)
6037687707dSAndrew Gallatin 		ifp = malloc(sizeof(struct ifnet), M_IFNET,
6047687707dSAndrew Gallatin 		    M_WAITOK | M_ZERO);
6057687707dSAndrew Gallatin 	else
6067687707dSAndrew Gallatin 		ifp = malloc_domainset(sizeof(struct ifnet), M_IFNET,
6077687707dSAndrew Gallatin 		    DOMAINSET_PREF(numa_domain), M_WAITOK | M_ZERO);
6084f6c66ccSMatt Macy  restart:
60961f6986bSRobert Watson 	IFNET_WLOCK();
6104f6c66ccSMatt Macy 	idx = ifindex_alloc(&old);
6114f6c66ccSMatt Macy 	if (__predict_false(idx == USHRT_MAX)) {
6124f6c66ccSMatt Macy 		IFNET_WUNLOCK();
6134f6c66ccSMatt Macy 		epoch_wait_preempt(net_epoch_preempt);
6144f6c66ccSMatt Macy 		free(old, M_IFNET);
6154f6c66ccSMatt Macy 		goto restart;
6164f6c66ccSMatt Macy 	}
6174f6c66ccSMatt Macy 	ifnet_setbyindex(idx, IFNET_HOLD);
61861f6986bSRobert Watson 	IFNET_WUNLOCK();
61961f6986bSRobert Watson 	ifp->if_index = idx;
620fc74a9f9SBrooks Davis 	ifp->if_type = type;
62127d37320SRobert Watson 	ifp->if_alloctype = type;
6227687707dSAndrew Gallatin 	ifp->if_numa_domain = numa_domain;
623a29c7aebSBjoern A. Zeeb #ifdef VIMAGE
624a29c7aebSBjoern A. Zeeb 	ifp->if_vnet = curvnet;
625a29c7aebSBjoern A. Zeeb #endif
626fc74a9f9SBrooks Davis 	if (if_com_alloc[type] != NULL) {
627fc74a9f9SBrooks Davis 		ifp->if_l2com = if_com_alloc[type](type, ifp);
62828ef2db4SBrooks Davis 		if (ifp->if_l2com == NULL) {
629fc74a9f9SBrooks Davis 			free(ifp, M_IFNET);
630ed2dabfcSRobert Watson 			ifindex_free(idx);
63128ef2db4SBrooks Davis 			return (NULL);
63228ef2db4SBrooks Davis 		}
633fc74a9f9SBrooks Davis 	}
63427d37320SRobert Watson 
63527d37320SRobert Watson 	IF_ADDR_LOCK_INIT(ifp);
636d6f157eaSRobert Watson 	TASK_INIT(&ifp->if_linktask, 0, do_link_state_change, ifp);
6370839aa5cSGleb Smirnoff 	TASK_INIT(&ifp->if_addmultitask, 0, if_siocaddmulti, ifp);
638d6f157eaSRobert Watson 	ifp->if_afdata_initialized = 0;
639e0c14af9SMarko Zec 	IF_AFDATA_LOCK_INIT(ifp);
640d7c5a620SMatt Macy 	CK_STAILQ_INIT(&ifp->if_addrhead);
641d7c5a620SMatt Macy 	CK_STAILQ_INIT(&ifp->if_multiaddrs);
6424f6c66ccSMatt Macy 	CK_STAILQ_INIT(&ifp->if_groups);
643d6f157eaSRobert Watson #ifdef MAC
644d6f157eaSRobert Watson 	mac_ifnet_init(ifp);
645d6f157eaSRobert Watson #endif
646d659538fSSam Leffler 	ifq_init(&ifp->if_snd, ifp);
647d6f157eaSRobert Watson 
64827d37320SRobert Watson 	refcount_init(&ifp->if_refcount, 1);	/* Index reference. */
649112f50ffSGleb Smirnoff 	for (int i = 0; i < IFCOUNTERS; i++)
650112f50ffSGleb Smirnoff 		ifp->if_counters[i] = counter_u64_alloc(M_WAITOK);
65161dc4344SAndrey V. Elsukov 	ifp->if_get_counter = if_get_counter_default;
652f1379734SKonstantin Belousov 	ifp->if_pcp = IFNET_PCP_NONE;
65361dc4344SAndrey V. Elsukov 	ifnet_setbyindex(ifp->if_index, ifp);
654fc74a9f9SBrooks Davis 	return (ifp);
655fc74a9f9SBrooks Davis }
656fc74a9f9SBrooks Davis 
6577687707dSAndrew Gallatin struct ifnet *
6587687707dSAndrew Gallatin if_alloc_dev(u_char type, device_t dev)
6597687707dSAndrew Gallatin {
6607687707dSAndrew Gallatin 	int numa_domain;
6617687707dSAndrew Gallatin 
6627687707dSAndrew Gallatin 	if (dev == NULL || bus_get_domain(dev, &numa_domain) != 0)
6637687707dSAndrew Gallatin 		return (if_alloc_domain(type, IF_NODOM));
6647687707dSAndrew Gallatin 	return (if_alloc_domain(type, numa_domain));
6657687707dSAndrew Gallatin }
6667687707dSAndrew Gallatin 
6677687707dSAndrew Gallatin struct ifnet *
6687687707dSAndrew Gallatin if_alloc(u_char type)
6697687707dSAndrew Gallatin {
6707687707dSAndrew Gallatin 
6717687707dSAndrew Gallatin 	return (if_alloc_domain(type, IF_NODOM));
6727687707dSAndrew Gallatin }
673a45cbf12SBrooks Davis /*
6744c506522SGleb Smirnoff  * Do the actual work of freeing a struct ifnet, and layer 2 common
6754c506522SGleb Smirnoff  * structure.  This call is made when the last reference to an
676242a8e72SRobert Watson  * interface is released.
677a45cbf12SBrooks Davis  */
678242a8e72SRobert Watson static void
679242a8e72SRobert Watson if_free_internal(struct ifnet *ifp)
680fc74a9f9SBrooks Davis {
681fc74a9f9SBrooks Davis 
682242a8e72SRobert Watson 	KASSERT((ifp->if_flags & IFF_DYING),
683242a8e72SRobert Watson 	    ("if_free_internal: interface not dying"));
684fc74a9f9SBrooks Davis 
68527d37320SRobert Watson 	if (if_com_free[ifp->if_alloctype] != NULL)
68627d37320SRobert Watson 		if_com_free[ifp->if_alloctype](ifp->if_l2com,
68727d37320SRobert Watson 		    ifp->if_alloctype);
688fc74a9f9SBrooks Davis 
689d6f157eaSRobert Watson #ifdef MAC
690d6f157eaSRobert Watson 	mac_ifnet_destroy(ifp);
691d6f157eaSRobert Watson #endif /* MAC */
692d6f157eaSRobert Watson 	IF_AFDATA_DESTROY(ifp);
69302f4879dSRobert Watson 	IF_ADDR_LOCK_DESTROY(ifp);
694d659538fSSam Leffler 	ifq_delete(&ifp->if_snd);
695112f50ffSGleb Smirnoff 
696112f50ffSGleb Smirnoff 	for (int i = 0; i < IFCOUNTERS; i++)
697112f50ffSGleb Smirnoff 		counter_u64_free(ifp->if_counters[i]);
698112f50ffSGleb Smirnoff 
69985107355SAndrey V. Elsukov 	free(ifp->if_description, M_IFDESCR);
70085107355SAndrey V. Elsukov 	free(ifp->if_hw_addr, M_IFADDR);
701fc74a9f9SBrooks Davis 	free(ifp, M_IFNET);
702c0c9ea90SSam Leffler }
703fc74a9f9SBrooks Davis 
7044f6c66ccSMatt Macy static void
7054f6c66ccSMatt Macy if_destroy(epoch_context_t ctx)
7064f6c66ccSMatt Macy {
7074f6c66ccSMatt Macy 	struct ifnet *ifp;
7084f6c66ccSMatt Macy 
7094f6c66ccSMatt Macy 	ifp = __containerof(ctx, struct ifnet, if_epoch_ctx);
7104f6c66ccSMatt Macy 	if_free_internal(ifp);
7114f6c66ccSMatt Macy }
7124f6c66ccSMatt Macy 
713242a8e72SRobert Watson /*
714f26fa169SBrooks Davis  * Deregister an interface and free the associated storage.
715242a8e72SRobert Watson  */
716242a8e72SRobert Watson void
717f26fa169SBrooks Davis if_free(struct ifnet *ifp)
718242a8e72SRobert Watson {
719242a8e72SRobert Watson 
720242a8e72SRobert Watson 	ifp->if_flags |= IFF_DYING;			/* XXX: Locking */
7214c506522SGleb Smirnoff 
722719fb725SCraig Rodrigues 	CURVNET_SET_QUIET(ifp->if_vnet);
7234c506522SGleb Smirnoff 	IFNET_WLOCK();
724270b83b9SHans Petter Selasky 	KASSERT(ifp == ifnet_byindex(ifp->if_index),
7254c506522SGleb Smirnoff 	    ("%s: freeing unallocated ifnet", ifp->if_xname));
7264c506522SGleb Smirnoff 
7274c506522SGleb Smirnoff 	ifindex_free_locked(ifp->if_index);
7284c506522SGleb Smirnoff 	IFNET_WUNLOCK();
7294c506522SGleb Smirnoff 
730719fb725SCraig Rodrigues 	if (refcount_release(&ifp->if_refcount))
7312a4bd982SGleb Smirnoff 		NET_EPOCH_CALL(if_destroy, &ifp->if_epoch_ctx);
732719fb725SCraig Rodrigues 	CURVNET_RESTORE();
733242a8e72SRobert Watson }
734242a8e72SRobert Watson 
735242a8e72SRobert Watson /*
736242a8e72SRobert Watson  * Interfaces to keep an ifnet type-stable despite the possibility of the
737242a8e72SRobert Watson  * driver calling if_free().  If there are additional references, we defer
738242a8e72SRobert Watson  * freeing the underlying data structure.
739242a8e72SRobert Watson  */
740db7f0b97SKip Macy void
74127d37320SRobert Watson if_ref(struct ifnet *ifp)
74227d37320SRobert Watson {
7437563019bSAlexander V. Chernikov 	u_int old;
74427d37320SRobert Watson 
74527d37320SRobert Watson 	/* We don't assert the ifnet list lock here, but arguably should. */
7467563019bSAlexander V. Chernikov 	old = refcount_acquire(&ifp->if_refcount);
7477563019bSAlexander V. Chernikov 	KASSERT(old > 0, ("%s: ifp %p has 0 refs", __func__, ifp));
7487563019bSAlexander V. Chernikov }
7497563019bSAlexander V. Chernikov 
7507563019bSAlexander V. Chernikov bool
7517563019bSAlexander V. Chernikov if_try_ref(struct ifnet *ifp)
7527563019bSAlexander V. Chernikov {
7537563019bSAlexander V. Chernikov 	NET_EPOCH_ASSERT();
7547563019bSAlexander V. Chernikov 	return (refcount_acquire_if_not_zero(&ifp->if_refcount));
75527d37320SRobert Watson }
75627d37320SRobert Watson 
75727d37320SRobert Watson void
75827d37320SRobert Watson if_rele(struct ifnet *ifp)
75927d37320SRobert Watson {
76027d37320SRobert Watson 
761242a8e72SRobert Watson 	if (!refcount_release(&ifp->if_refcount))
762242a8e72SRobert Watson 		return;
7632a4bd982SGleb Smirnoff 	NET_EPOCH_CALL(if_destroy, &ifp->if_epoch_ctx);
76427d37320SRobert Watson }
76527d37320SRobert Watson 
76627d37320SRobert Watson void
767d659538fSSam Leffler ifq_init(struct ifaltq *ifq, struct ifnet *ifp)
768db7f0b97SKip Macy {
769db7f0b97SKip Macy 
770db7f0b97SKip Macy 	mtx_init(&ifq->ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF);
771db7f0b97SKip Macy 
772db7f0b97SKip Macy 	if (ifq->ifq_maxlen == 0)
773db7f0b97SKip Macy 		ifq->ifq_maxlen = ifqmaxlen;
774db7f0b97SKip Macy 
775db7f0b97SKip Macy 	ifq->altq_type = 0;
776db7f0b97SKip Macy 	ifq->altq_disc = NULL;
777db7f0b97SKip Macy 	ifq->altq_flags &= ALTQF_CANTCHANGE;
778db7f0b97SKip Macy 	ifq->altq_tbr  = NULL;
779db7f0b97SKip Macy 	ifq->altq_ifp  = ifp;
780db7f0b97SKip Macy }
781db7f0b97SKip Macy 
782db7f0b97SKip Macy void
783d659538fSSam Leffler ifq_delete(struct ifaltq *ifq)
784db7f0b97SKip Macy {
785db7f0b97SKip Macy 	mtx_destroy(&ifq->ifq_mtx);
786db7f0b97SKip Macy }
787db7f0b97SKip Macy 
788fc74a9f9SBrooks Davis /*
789a4641f4eSPedro F. Giffuni  * Perform generic interface initialization tasks and attach the interface
790e0c14af9SMarko Zec  * to the list of "active" interfaces.  If vmove flag is set on entry
791e0c14af9SMarko Zec  * to if_attach_internal(), perform only a limited subset of initialization
792e0c14af9SMarko Zec  * tasks, given that we are moving from one vnet to another an ifnet which
793e0c14af9SMarko Zec  * has already been fully initialized.
794a45cbf12SBrooks Davis  *
795c92a456bSHiroki Sato  * Note that if_detach_internal() removes group membership unconditionally
796c92a456bSHiroki Sato  * even when vmove flag is set, and if_attach_internal() adds only IFG_ALL.
797c92a456bSHiroki Sato  * Thus, when if_vmove() is applied to a cloned interface, group membership
798c92a456bSHiroki Sato  * is lost while a cloned one always joins a group whose name is
799c92a456bSHiroki Sato  * ifc->ifc_name.  To recover this after if_detach_internal() and
800c92a456bSHiroki Sato  * if_attach_internal(), the cloner should be specified to
801c92a456bSHiroki Sato  * if_attach_internal() via ifc.  If it is non-NULL, if_attach_internal()
802c92a456bSHiroki Sato  * attempts to join a group whose name is ifc->ifc_name.
803c92a456bSHiroki Sato  *
804a45cbf12SBrooks Davis  * XXX:
805a45cbf12SBrooks Davis  *  - The decision to return void and thus require this function to
806a45cbf12SBrooks Davis  *    succeed is questionable.
807a45cbf12SBrooks Davis  *  - We should probably do more sanity checking.  For instance we don't
808a45cbf12SBrooks Davis  *    do anything to insure if_xname is unique or non-empty.
809df8bae1dSRodney W. Grimes  */
810df8bae1dSRodney W. Grimes void
81172fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp)
812df8bae1dSRodney W. Grimes {
813e0c14af9SMarko Zec 
814c92a456bSHiroki Sato 	if_attach_internal(ifp, 0, NULL);
815e0c14af9SMarko Zec }
816e0c14af9SMarko Zec 
8179fd573c3SHans Petter Selasky /*
8189fd573c3SHans Petter Selasky  * Compute the least common TSO limit.
8199fd573c3SHans Petter Selasky  */
8209fd573c3SHans Petter Selasky void
8219fd573c3SHans Petter Selasky if_hw_tsomax_common(if_t ifp, struct ifnet_hw_tsomax *pmax)
8229fd573c3SHans Petter Selasky {
8239fd573c3SHans Petter Selasky 	/*
8249fd573c3SHans Petter Selasky 	 * 1) If there is no limit currently, take the limit from
8259fd573c3SHans Petter Selasky 	 * the network adapter.
8269fd573c3SHans Petter Selasky 	 *
8279fd573c3SHans Petter Selasky 	 * 2) If the network adapter has a limit below the current
8289fd573c3SHans Petter Selasky 	 * limit, apply it.
8299fd573c3SHans Petter Selasky 	 */
8309fd573c3SHans Petter Selasky 	if (pmax->tsomaxbytes == 0 || (ifp->if_hw_tsomax != 0 &&
8319fd573c3SHans Petter Selasky 	    ifp->if_hw_tsomax < pmax->tsomaxbytes)) {
8329fd573c3SHans Petter Selasky 		pmax->tsomaxbytes = ifp->if_hw_tsomax;
8339fd573c3SHans Petter Selasky 	}
8349fd573c3SHans Petter Selasky 	if (pmax->tsomaxsegcount == 0 || (ifp->if_hw_tsomaxsegcount != 0 &&
8359fd573c3SHans Petter Selasky 	    ifp->if_hw_tsomaxsegcount < pmax->tsomaxsegcount)) {
8369fd573c3SHans Petter Selasky 		pmax->tsomaxsegcount = ifp->if_hw_tsomaxsegcount;
8379fd573c3SHans Petter Selasky 	}
8389fd573c3SHans Petter Selasky 	if (pmax->tsomaxsegsize == 0 || (ifp->if_hw_tsomaxsegsize != 0 &&
8399fd573c3SHans Petter Selasky 	    ifp->if_hw_tsomaxsegsize < pmax->tsomaxsegsize)) {
8409fd573c3SHans Petter Selasky 		pmax->tsomaxsegsize = ifp->if_hw_tsomaxsegsize;
8419fd573c3SHans Petter Selasky 	}
8429fd573c3SHans Petter Selasky }
8439fd573c3SHans Petter Selasky 
8449fd573c3SHans Petter Selasky /*
8459fd573c3SHans Petter Selasky  * Update TSO limit of a network adapter.
8469fd573c3SHans Petter Selasky  *
8479fd573c3SHans Petter Selasky  * Returns zero if no change. Else non-zero.
8489fd573c3SHans Petter Selasky  */
8499fd573c3SHans Petter Selasky int
8509fd573c3SHans Petter Selasky if_hw_tsomax_update(if_t ifp, struct ifnet_hw_tsomax *pmax)
8519fd573c3SHans Petter Selasky {
8529fd573c3SHans Petter Selasky 	int retval = 0;
8539fd573c3SHans Petter Selasky 	if (ifp->if_hw_tsomax != pmax->tsomaxbytes) {
8549fd573c3SHans Petter Selasky 		ifp->if_hw_tsomax = pmax->tsomaxbytes;
8559fd573c3SHans Petter Selasky 		retval++;
8569fd573c3SHans Petter Selasky 	}
8579fd573c3SHans Petter Selasky 	if (ifp->if_hw_tsomaxsegsize != pmax->tsomaxsegsize) {
8589fd573c3SHans Petter Selasky 		ifp->if_hw_tsomaxsegsize = pmax->tsomaxsegsize;
8599fd573c3SHans Petter Selasky 		retval++;
8609fd573c3SHans Petter Selasky 	}
8619fd573c3SHans Petter Selasky 	if (ifp->if_hw_tsomaxsegcount != pmax->tsomaxsegcount) {
8629fd573c3SHans Petter Selasky 		ifp->if_hw_tsomaxsegcount = pmax->tsomaxsegcount;
8639fd573c3SHans Petter Selasky 		retval++;
8649fd573c3SHans Petter Selasky 	}
8659fd573c3SHans Petter Selasky 	return (retval);
8669fd573c3SHans Petter Selasky }
8679fd573c3SHans Petter Selasky 
868e0c14af9SMarko Zec static void
869c92a456bSHiroki Sato if_attach_internal(struct ifnet *ifp, int vmove, struct if_clone *ifc)
870e0c14af9SMarko Zec {
871df8bae1dSRodney W. Grimes 	unsigned socksize, ifasize;
8721ce9bf88SPoul-Henning Kamp 	int namelen, masklen;
87372fd1b6aSDag-Erling Smørgrav 	struct sockaddr_dl *sdl;
87472fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
875df8bae1dSRodney W. Grimes 
876fc74a9f9SBrooks Davis 	if (ifp->if_index == 0 || ifp != ifnet_byindex(ifp->if_index))
877fc74a9f9SBrooks Davis 		panic ("%s: BUG: if_attach called without if_alloc'd input()\n",
878fc74a9f9SBrooks Davis 		    ifp->if_xname);
879fc74a9f9SBrooks Davis 
880f6dfe47aSMarko Zec #ifdef VIMAGE
881f6dfe47aSMarko Zec 	ifp->if_vnet = curvnet;
882bc29160dSMarko Zec 	if (ifp->if_home_vnet == NULL)
883bc29160dSMarko Zec 		ifp->if_home_vnet = curvnet;
884f6dfe47aSMarko Zec #endif
885f6dfe47aSMarko Zec 
8860dad3f0eSMax Laier 	if_addgroup(ifp, IFG_ALL);
8870dad3f0eSMax Laier 
888c92a456bSHiroki Sato 	/* Restore group membership for cloned interfaces. */
889c92a456bSHiroki Sato 	if (vmove && ifc != NULL)
890c92a456bSHiroki Sato 		if_clone_addgroup(ifp, ifc);
891c92a456bSHiroki Sato 
89298b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
893e6485f73SGleb Smirnoff 	ifp->if_epoch = time_uptime;
894d6f157eaSRobert Watson 
8957cc5b47fSKip Macy 	KASSERT((ifp->if_transmit == NULL && ifp->if_qflush == NULL) ||
8967cc5b47fSKip Macy 	    (ifp->if_transmit != NULL && ifp->if_qflush != NULL),
8977cc5b47fSKip Macy 	    ("transmit and qflush must both either be set or both be NULL"));
8987cc5b47fSKip Macy 	if (ifp->if_transmit == NULL) {
899db7f0b97SKip Macy 		ifp->if_transmit = if_transmit;
900db7f0b97SKip Macy 		ifp->if_qflush = if_qflush;
9017cc5b47fSKip Macy 	}
902b57d9721SAndrey V. Elsukov 	if (ifp->if_input == NULL)
903b57d9721SAndrey V. Elsukov 		ifp->if_input = if_input_default;
9047cc5b47fSKip Macy 
9054fb3a820SAlexander V. Chernikov 	if (ifp->if_requestencap == NULL)
9064fb3a820SAlexander V. Chernikov 		ifp->if_requestencap = if_requestencap_default;
9074fb3a820SAlexander V. Chernikov 
908e0c14af9SMarko Zec 	if (!vmove) {
909e70cd263SRobert Watson #ifdef MAC
91030d239bcSRobert Watson 		mac_ifnet_create(ifp);
911e70cd263SRobert Watson #endif
912e70cd263SRobert Watson 
913df8bae1dSRodney W. Grimes 		/*
914e0c14af9SMarko Zec 		 * Create a Link Level name for this device.
915df8bae1dSRodney W. Grimes 		 */
9169bf40edeSBrooks Davis 		namelen = strlen(ifp->if_xname);
91736c19a57SBrooks Davis 		/*
918e0c14af9SMarko Zec 		 * Always save enough space for any possiable name so we
919e0c14af9SMarko Zec 		 * can do a rename in place later.
92036c19a57SBrooks Davis 		 */
92136c19a57SBrooks Davis 		masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ;
922df8bae1dSRodney W. Grimes 		socksize = masklen + ifp->if_addrlen;
923df8bae1dSRodney W. Grimes 		if (socksize < sizeof(*sdl))
924df8bae1dSRodney W. Grimes 			socksize = sizeof(*sdl);
925ccb82468SBrooks Davis 		socksize = roundup2(socksize, sizeof(long));
926df8bae1dSRodney W. Grimes 		ifasize = sizeof(*ifa) + 2 * socksize;
92746758960SGleb Smirnoff 		ifa = ifa_alloc(ifasize, M_WAITOK);
928df8bae1dSRodney W. Grimes 		sdl = (struct sockaddr_dl *)(ifa + 1);
929df8bae1dSRodney W. Grimes 		sdl->sdl_len = socksize;
930df8bae1dSRodney W. Grimes 		sdl->sdl_family = AF_LINK;
9319bf40edeSBrooks Davis 		bcopy(ifp->if_xname, sdl->sdl_data, namelen);
9321ce9bf88SPoul-Henning Kamp 		sdl->sdl_nlen = namelen;
933df8bae1dSRodney W. Grimes 		sdl->sdl_index = ifp->if_index;
934df8bae1dSRodney W. Grimes 		sdl->sdl_type = ifp->if_type;
9354a0d6638SRuslan Ermilov 		ifp->if_addr = ifa;
936df8bae1dSRodney W. Grimes 		ifa->ifa_ifp = ifp;
937df8bae1dSRodney W. Grimes 		ifa->ifa_addr = (struct sockaddr *)sdl;
938df8bae1dSRodney W. Grimes 		sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
939df8bae1dSRodney W. Grimes 		ifa->ifa_netmask = (struct sockaddr *)sdl;
940df8bae1dSRodney W. Grimes 		sdl->sdl_len = masklen;
941df8bae1dSRodney W. Grimes 		while (namelen != 0)
942df8bae1dSRodney W. Grimes 			sdl->sdl_data[--namelen] = 0xff;
943d7c5a620SMatt Macy 		CK_STAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
944e0c14af9SMarko Zec 		/* Reliably crash if used uninitialized. */
945e0c14af9SMarko Zec 		ifp->if_broadcastaddr = NULL;
94672f31000SHans Petter Selasky 
947ddae5750SRavi Pokala 		if (ifp->if_type == IFT_ETHER) {
948ddae5750SRavi Pokala 			ifp->if_hw_addr = malloc(ifp->if_addrlen, M_IFADDR,
949ddae5750SRavi Pokala 			    M_WAITOK | M_ZERO);
950ddae5750SRavi Pokala 		}
951ddae5750SRavi Pokala 
95272f31000SHans Petter Selasky #if defined(INET) || defined(INET6)
9539fd573c3SHans Petter Selasky 		/* Use defaults for TSO, if nothing is set */
9549fd573c3SHans Petter Selasky 		if (ifp->if_hw_tsomax == 0 &&
9559fd573c3SHans Petter Selasky 		    ifp->if_hw_tsomaxsegcount == 0 &&
9569fd573c3SHans Petter Selasky 		    ifp->if_hw_tsomaxsegsize == 0) {
9579fd573c3SHans Petter Selasky 			/*
9589fd573c3SHans Petter Selasky 			 * The TSO defaults needs to be such that an
9599fd573c3SHans Petter Selasky 			 * NFS mbuf list of 35 mbufs totalling just
9609fd573c3SHans Petter Selasky 			 * below 64K works and that a chain of mbufs
9619fd573c3SHans Petter Selasky 			 * can be defragged into at most 32 segments:
9629fd573c3SHans Petter Selasky 			 */
9639fd573c3SHans Petter Selasky 			ifp->if_hw_tsomax = min(IP_MAXPACKET, (32 * MCLBYTES) -
96472f31000SHans Petter Selasky 			    (ETHER_HDR_LEN + ETHER_VLAN_ENCAP_LEN));
9659fd573c3SHans Petter Selasky 			ifp->if_hw_tsomaxsegcount = 35;
9669fd573c3SHans Petter Selasky 			ifp->if_hw_tsomaxsegsize = 2048;	/* 2K */
9679fd573c3SHans Petter Selasky 
9689fd573c3SHans Petter Selasky 			/* XXX some drivers set IFCAP_TSO after ethernet attach */
9699fd573c3SHans Petter Selasky 			if (ifp->if_capabilities & IFCAP_TSO) {
9709fd573c3SHans Petter Selasky 				if_printf(ifp, "Using defaults for TSO: %u/%u/%u\n",
9719fd573c3SHans Petter Selasky 				    ifp->if_hw_tsomax,
9729fd573c3SHans Petter Selasky 				    ifp->if_hw_tsomaxsegcount,
9739fd573c3SHans Petter Selasky 				    ifp->if_hw_tsomaxsegsize);
9749fd573c3SHans Petter Selasky 			}
9759fd573c3SHans Petter Selasky 		}
97672f31000SHans Petter Selasky #endif
977e0c14af9SMarko Zec 	}
97852db6805SMarko Zec #ifdef VIMAGE
97952db6805SMarko Zec 	else {
98052db6805SMarko Zec 		/*
98152db6805SMarko Zec 		 * Update the interface index in the link layer address
98252db6805SMarko Zec 		 * of the interface.
98352db6805SMarko Zec 		 */
98452db6805SMarko Zec 		for (ifa = ifp->if_addr; ifa != NULL;
985d7c5a620SMatt Macy 		    ifa = CK_STAILQ_NEXT(ifa, ifa_link)) {
98652db6805SMarko Zec 			if (ifa->ifa_addr->sa_family == AF_LINK) {
98752db6805SMarko Zec 				sdl = (struct sockaddr_dl *)ifa->ifa_addr;
98852db6805SMarko Zec 				sdl->sdl_index = ifp->if_index;
98952db6805SMarko Zec 			}
99052db6805SMarko Zec 		}
99152db6805SMarko Zec 	}
99252db6805SMarko Zec #endif
993d94ccb09SBrooks Davis 
994a779388fSKristof Provost 	if_link_ifnet(ifp);
995457f48e6SGleb Smirnoff 
99669fb23b7SMax Laier 	if (domain_init_status >= 2)
99731b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
99831b1bfe1SHajimu UMEMOTO 
99925a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
100021ca7b57SMarko Zec 	if (IS_DEFAULT_VNET(curvnet))
1001f3b90d48SAndrew Thompson 		devctl_notify("IFNET", ifp->if_xname, "ATTACH", NULL);
100225a4adceSMax Laier 
10037b6edd04SRuslan Ermilov 	/* Announce the interface. */
10047b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
1005df8bae1dSRodney W. Grimes }
10066182fdbdSPeter Wemm 
100731b1bfe1SHajimu UMEMOTO static void
1008f2d19f98SMatt Macy if_epochalloc(void *dummy __unused)
1009f2d19f98SMatt Macy {
1010f2d19f98SMatt Macy 
1011dd902d01SGleb Smirnoff 	net_epoch_preempt = epoch_alloc("Net preemptible", EPOCH_PREEMPT);
1012f2d19f98SMatt Macy }
10137993a104SConrad Meyer SYSINIT(ifepochalloc, SI_SUB_EPOCH, SI_ORDER_ANY, if_epochalloc, NULL);
1014f2d19f98SMatt Macy 
1015f2d19f98SMatt Macy static void
101672fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy)
101731b1bfe1SHajimu UMEMOTO {
101831b1bfe1SHajimu UMEMOTO 	struct ifnet *ifp;
101931b1bfe1SHajimu UMEMOTO 
10204f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link)
102131b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
102231b1bfe1SHajimu UMEMOTO }
102369fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND,
102431b1bfe1SHajimu UMEMOTO     if_attachdomain, NULL);
102531b1bfe1SHajimu UMEMOTO 
102631b1bfe1SHajimu UMEMOTO static void
102772fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp)
102831b1bfe1SHajimu UMEMOTO {
102931b1bfe1SHajimu UMEMOTO 	struct domain *dp;
103031b1bfe1SHajimu UMEMOTO 
1031234a35c7SHajimu UMEMOTO 	/*
1032234a35c7SHajimu UMEMOTO 	 * Since dp->dom_ifattach calls malloc() with M_WAITOK, we
1033234a35c7SHajimu UMEMOTO 	 * cannot lock ifp->if_afdata initialization, entirely.
1034234a35c7SHajimu UMEMOTO 	 */
1035c169d9feSBjoern A. Zeeb 	IF_AFDATA_LOCK(ifp);
103669fb23b7SMax Laier 	if (ifp->if_afdata_initialized >= domain_init_status) {
1037234a35c7SHajimu UMEMOTO 		IF_AFDATA_UNLOCK(ifp);
1038813ee737SAndre Oppermann 		log(LOG_WARNING, "%s called more than once on %s\n",
1039813ee737SAndre Oppermann 		    __func__, ifp->if_xname);
1040234a35c7SHajimu UMEMOTO 		return;
1041234a35c7SHajimu UMEMOTO 	}
104269fb23b7SMax Laier 	ifp->if_afdata_initialized = domain_init_status;
1043234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
1044234a35c7SHajimu UMEMOTO 
104531b1bfe1SHajimu UMEMOTO 	/* address family dependent data region */
104631b1bfe1SHajimu UMEMOTO 	bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
104731b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
104831b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifattach)
104931b1bfe1SHajimu UMEMOTO 			ifp->if_afdata[dp->dom_family] =
105031b1bfe1SHajimu UMEMOTO 			    (*dp->dom_ifattach)(ifp);
105131b1bfe1SHajimu UMEMOTO 	}
105231b1bfe1SHajimu UMEMOTO }
105331b1bfe1SHajimu UMEMOTO 
10546182fdbdSPeter Wemm /*
1055ec002feeSBruce M Simpson  * Remove any unicast or broadcast network addresses from an interface.
105645778b37SPeter Edwards  */
105745778b37SPeter Edwards void
105845778b37SPeter Edwards if_purgeaddrs(struct ifnet *ifp)
105945778b37SPeter Edwards {
106088d57e9eSHans Petter Selasky 	struct ifaddr *ifa;
106145778b37SPeter Edwards 
106288d57e9eSHans Petter Selasky 	while (1) {
1063a68cc388SGleb Smirnoff 		struct epoch_tracker et;
1064a68cc388SGleb Smirnoff 
1065a68cc388SGleb Smirnoff 		NET_EPOCH_ENTER(et);
106688d57e9eSHans Petter Selasky 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
106788d57e9eSHans Petter Selasky 			if (ifa->ifa_addr->sa_family != AF_LINK)
106888d57e9eSHans Petter Selasky 				break;
106988d57e9eSHans Petter Selasky 		}
1070a68cc388SGleb Smirnoff 		NET_EPOCH_EXIT(et);
107188d57e9eSHans Petter Selasky 
107288d57e9eSHans Petter Selasky 		if (ifa == NULL)
107388d57e9eSHans Petter Selasky 			break;
107445778b37SPeter Edwards #ifdef INET
107545778b37SPeter Edwards 		/* XXX: Ugly!! ad hoc just for INET */
10764b97d7afSYaroslav Tykhiy 		if (ifa->ifa_addr->sa_family == AF_INET) {
107745778b37SPeter Edwards 			struct ifaliasreq ifr;
107845778b37SPeter Edwards 
107945778b37SPeter Edwards 			bzero(&ifr, sizeof(ifr));
108045778b37SPeter Edwards 			ifr.ifra_addr = *ifa->ifa_addr;
108145778b37SPeter Edwards 			if (ifa->ifa_dstaddr)
108245778b37SPeter Edwards 				ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
108345778b37SPeter Edwards 			if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
108445778b37SPeter Edwards 			    NULL) == 0)
108545778b37SPeter Edwards 				continue;
108645778b37SPeter Edwards 		}
108745778b37SPeter Edwards #endif /* INET */
108845778b37SPeter Edwards #ifdef INET6
10894b97d7afSYaroslav Tykhiy 		if (ifa->ifa_addr->sa_family == AF_INET6) {
1090f9e0752eSAlexander V. Chernikov 			in6_purgeifaddr((struct in6_ifaddr *)ifa);
109145778b37SPeter Edwards 			/* ifp_addrhead is already updated */
109245778b37SPeter Edwards 			continue;
109345778b37SPeter Edwards 		}
109445778b37SPeter Edwards #endif /* INET6 */
1095f22d78c0SBjoern A. Zeeb 		IF_ADDR_WLOCK(ifp);
1096d7c5a620SMatt Macy 		CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link);
1097f22d78c0SBjoern A. Zeeb 		IF_ADDR_WUNLOCK(ifp);
10981099f828SRobert Watson 		ifa_free(ifa);
109945778b37SPeter Edwards 	}
110045778b37SPeter Edwards }
110145778b37SPeter Edwards 
110245778b37SPeter Edwards /*
110393ec7edcSShteryana Shopova  * Remove any multicast network addresses from an interface when an ifnet
110493ec7edcSShteryana Shopova  * is going away.
1105ec002feeSBruce M Simpson  */
110693ec7edcSShteryana Shopova static void
1107ec002feeSBruce M Simpson if_purgemaddrs(struct ifnet *ifp)
1108ec002feeSBruce M Simpson {
1109ec002feeSBruce M Simpson 	struct ifmultiaddr *ifma;
1110ec002feeSBruce M Simpson 
1111137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
1112d7c5a620SMatt Macy 	while (!CK_STAILQ_EMPTY(&ifp->if_multiaddrs)) {
1113d7c5a620SMatt Macy 		ifma = CK_STAILQ_FIRST(&ifp->if_multiaddrs);
1114d7c5a620SMatt Macy 		CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
1115ec002feeSBruce M Simpson 		if_delmulti_locked(ifp, ifma, 1);
1116f3e1324bSStephen Hurd 	}
1117137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
1118ec002feeSBruce M Simpson }
1119ec002feeSBruce M Simpson 
1120ec002feeSBruce M Simpson /*
1121e0c14af9SMarko Zec  * Detach an interface, removing it from the list of "active" interfaces.
1122e0c14af9SMarko Zec  * If vmove flag is set on entry to if_detach_internal(), perform only a
1123e0c14af9SMarko Zec  * limited subset of cleanup tasks, given that we are moving an ifnet from
1124e0c14af9SMarko Zec  * one vnet to another, where it must be fully operational.
1125b1c53bc9SRobert Watson  *
1126b1c53bc9SRobert Watson  * XXXRW: There are some significant questions about event ordering, and
1127b1c53bc9SRobert Watson  * how to prevent things from starting to use the interface during detach.
11286182fdbdSPeter Wemm  */
11296182fdbdSPeter Wemm void
113072fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp)
11316182fdbdSPeter Wemm {
1132a779388fSKristof Provost 	bool found;
1133e0c14af9SMarko Zec 
1134719fb725SCraig Rodrigues 	CURVNET_SET_QUIET(ifp->if_vnet);
1135a779388fSKristof Provost 	found = if_unlink_ifnet(ifp, false);
1136e133271fSKristof Provost 	if (found) {
11376d2a10d9SKristof Provost 		sx_xlock(&ifnet_detach_sxlock);
1138c92a456bSHiroki Sato 		if_detach_internal(ifp, 0, NULL);
11396d2a10d9SKristof Provost 		sx_xunlock(&ifnet_detach_sxlock);
1140e133271fSKristof Provost 	}
1141719fb725SCraig Rodrigues 	CURVNET_RESTORE();
1142e0c14af9SMarko Zec }
1143e0c14af9SMarko Zec 
114489856f7eSBjoern A. Zeeb /*
114589856f7eSBjoern A. Zeeb  * The vmove flag, if set, indicates that we are called from a callpath
114689856f7eSBjoern A. Zeeb  * that is moving an interface to a different vnet instance.
114789856f7eSBjoern A. Zeeb  *
114889856f7eSBjoern A. Zeeb  * The shutdown flag, if set, indicates that we are called in the
114989856f7eSBjoern A. Zeeb  * process of shutting down a vnet instance.  Currently only the
115089856f7eSBjoern A. Zeeb  * vnet_if_return SYSUNINIT function sets it.  Note: we can be called
115189856f7eSBjoern A. Zeeb  * on a vnet instance shutdown without this flag being set, e.g., when
115289856f7eSBjoern A. Zeeb  * the cloned interfaces are destoyed as first thing of teardown.
115389856f7eSBjoern A. Zeeb  */
1154f501e6f1SBjoern A. Zeeb static int
1155c92a456bSHiroki Sato if_detach_internal(struct ifnet *ifp, int vmove, struct if_clone **ifcp)
1156e0c14af9SMarko Zec {
115745778b37SPeter Edwards 	struct ifaddr *ifa;
11584bdf0b6aSAlexander V. Chernikov 	int i;
115931b1bfe1SHajimu UMEMOTO 	struct domain *dp;
1160d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE
1161204e2f30SHans Petter Selasky 	bool shutdown;
1162457f48e6SGleb Smirnoff 
116310108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet);
1164d3f6f80fSBjoern A. Zeeb #endif
11656182fdbdSPeter Wemm 
116689856f7eSBjoern A. Zeeb 	/*
116789856f7eSBjoern A. Zeeb 	 * At this point we know the interface still was on the ifnet list
116889856f7eSBjoern A. Zeeb 	 * and we removed it so we are in a stable state.
116989856f7eSBjoern A. Zeeb 	 */
11704f6c66ccSMatt Macy 	epoch_wait_preempt(net_epoch_preempt);
11710dbdf041SHans Petter Selasky 
11720dbdf041SHans Petter Selasky 	/*
11730dbdf041SHans Petter Selasky 	 * Ensure all pending EPOCH(9) callbacks have been executed. This
11740dbdf041SHans Petter Selasky 	 * fixes issues about late destruction of multicast options
11750dbdf041SHans Petter Selasky 	 * which lead to leave group calls, which in turn access the
11760dbdf041SHans Petter Selasky 	 * belonging ifnet structure:
11770dbdf041SHans Petter Selasky 	 */
11780dbdf041SHans Petter Selasky 	epoch_drain_callbacks(net_epoch_preempt);
11790dbdf041SHans Petter Selasky 
118089856f7eSBjoern A. Zeeb 	/*
118189856f7eSBjoern A. Zeeb 	 * In any case (destroy or vmove) detach us from the groups
118289856f7eSBjoern A. Zeeb 	 * and remove/wait for pending events on the taskq.
118389856f7eSBjoern A. Zeeb 	 * XXX-BZ in theory an interface could still enqueue a taskq change?
118489856f7eSBjoern A. Zeeb 	 */
118589856f7eSBjoern A. Zeeb 	if_delgroups(ifp);
118689856f7eSBjoern A. Zeeb 
118789856f7eSBjoern A. Zeeb 	taskqueue_drain(taskqueue_swi, &ifp->if_linktask);
11880839aa5cSGleb Smirnoff 	taskqueue_drain(taskqueue_swi, &ifp->if_addmultitask);
118989856f7eSBjoern A. Zeeb 
119089856f7eSBjoern A. Zeeb 	/*
119189856f7eSBjoern A. Zeeb 	 * Check if this is a cloned interface or not. Must do even if
119289856f7eSBjoern A. Zeeb 	 * shutting down as a if_vmove_reclaim() would move the ifp and
119389856f7eSBjoern A. Zeeb 	 * the if_clone_addgroup() will have a corrupted string overwise
119489856f7eSBjoern A. Zeeb 	 * from a gibberish pointer.
119589856f7eSBjoern A. Zeeb 	 */
1196c92a456bSHiroki Sato 	if (vmove && ifcp != NULL)
1197c92a456bSHiroki Sato 		*ifcp = if_clone_findifc(ifp);
1198c92a456bSHiroki Sato 
119989856f7eSBjoern A. Zeeb 	if_down(ifp);
120089856f7eSBjoern A. Zeeb 
1201d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE
120268a3482fSGleb Smirnoff 	/*
120389856f7eSBjoern A. Zeeb 	 * On VNET shutdown abort here as the stack teardown will do all
120489856f7eSBjoern A. Zeeb 	 * the work top-down for us.
120568a3482fSGleb Smirnoff 	 */
120689856f7eSBjoern A. Zeeb 	if (shutdown) {
120725c6ab1bSKristof Provost 		/* Give interface users the chance to clean up. */
120825c6ab1bSKristof Provost 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
120925c6ab1bSKristof Provost 
121089856f7eSBjoern A. Zeeb 		/*
121189856f7eSBjoern A. Zeeb 		 * In case of a vmove we are done here without error.
121289856f7eSBjoern A. Zeeb 		 * If we would signal an error it would lead to the same
121389856f7eSBjoern A. Zeeb 		 * abort as if we did not find the ifnet anymore.
121489856f7eSBjoern A. Zeeb 		 * if_detach() calls us in void context and does not care
121589856f7eSBjoern A. Zeeb 		 * about an early abort notification, so life is splendid :)
121689856f7eSBjoern A. Zeeb 		 */
121789856f7eSBjoern A. Zeeb 		goto finish_vnet_shutdown;
121889856f7eSBjoern A. Zeeb 	}
1219d3f6f80fSBjoern A. Zeeb #endif
122089856f7eSBjoern A. Zeeb 
122189856f7eSBjoern A. Zeeb 	/*
122289856f7eSBjoern A. Zeeb 	 * At this point we are not tearing down a VNET and are either
122389856f7eSBjoern A. Zeeb 	 * going to destroy or vmove the interface and have to cleanup
122489856f7eSBjoern A. Zeeb 	 * accordingly.
122589856f7eSBjoern A. Zeeb 	 */
122668a3482fSGleb Smirnoff 
12276182fdbdSPeter Wemm 	/*
12286182fdbdSPeter Wemm 	 * Remove routes and flush queues.
12296182fdbdSPeter Wemm 	 */
123002b199f1SMax Laier #ifdef ALTQ
123102b199f1SMax Laier 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
123202b199f1SMax Laier 		altq_disable(&ifp->if_snd);
123302b199f1SMax Laier 	if (ALTQ_IS_ATTACHED(&ifp->if_snd))
123402b199f1SMax Laier 		altq_detach(&ifp->if_snd);
123502b199f1SMax Laier #endif
12366182fdbdSPeter Wemm 
123745778b37SPeter Edwards 	if_purgeaddrs(ifp);
12386182fdbdSPeter Wemm 
1239b1c53bc9SRobert Watson #ifdef INET
1240b1c53bc9SRobert Watson 	in_ifdetach(ifp);
1241b1c53bc9SRobert Watson #endif
1242b1c53bc9SRobert Watson 
124333841545SHajimu UMEMOTO #ifdef INET6
124433841545SHajimu UMEMOTO 	/*
124533841545SHajimu UMEMOTO 	 * Remove all IPv6 kernel structs related to ifp.  This should be done
124633841545SHajimu UMEMOTO 	 * before removing routing entries below, since IPv6 interface direct
124733841545SHajimu UMEMOTO 	 * routes are expected to be removed by the IPv6-specific kernel API.
124833841545SHajimu UMEMOTO 	 * Otherwise, the kernel will detect some inconsistency and bark it.
124933841545SHajimu UMEMOTO 	 */
125033841545SHajimu UMEMOTO 	in6_ifdetach(ifp);
125133841545SHajimu UMEMOTO #endif
1252ec002feeSBruce M Simpson 	if_purgemaddrs(ifp);
1253ec002feeSBruce M Simpson 
1254af371fc6SRoger Pau Monné 	/* Announce that the interface is gone. */
1255af371fc6SRoger Pau Monné 	rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
1256af371fc6SRoger Pau Monné 	EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
1257af371fc6SRoger Pau Monné 	if (IS_DEFAULT_VNET(curvnet))
1258af371fc6SRoger Pau Monné 		devctl_notify("IFNET", ifp->if_xname, "DETACH", NULL);
1259af371fc6SRoger Pau Monné 
1260e0c14af9SMarko Zec 	if (!vmove) {
1261f4247b59SLuigi Rizzo 		/*
1262111c6b61SRobert Watson 		 * Prevent further calls into the device driver via ifnet.
1263111c6b61SRobert Watson 		 */
1264111c6b61SRobert Watson 		if_dead(ifp);
1265111c6b61SRobert Watson 
1266111c6b61SRobert Watson 		/*
1267f4247b59SLuigi Rizzo 		 * Clean up all addresses.
1268f4247b59SLuigi Rizzo 		 */
1269d117fd80SBjoern A. Zeeb 		IF_ADDR_WLOCK(ifp);
1270d7c5a620SMatt Macy 		if (!CK_STAILQ_EMPTY(&ifp->if_addrhead)) {
1271d7c5a620SMatt Macy 			ifa = CK_STAILQ_FIRST(&ifp->if_addrhead);
1272d7c5a620SMatt Macy 			CK_STAILQ_REMOVE(&ifp->if_addrhead, ifa, ifaddr, ifa_link);
1273d117fd80SBjoern A. Zeeb 			IF_ADDR_WUNLOCK(ifp);
12741099f828SRobert Watson 			ifa_free(ifa);
1275d117fd80SBjoern A. Zeeb 		} else
1276d117fd80SBjoern A. Zeeb 			IF_ADDR_WUNLOCK(ifp);
1277e0c14af9SMarko Zec 	}
1278212bd869SHajimu UMEMOTO 
12794bdf0b6aSAlexander V. Chernikov 	rt_flushifroutes(ifp);
12807b6edd04SRuslan Ermilov 
1281d3f6f80fSBjoern A. Zeeb #ifdef VIMAGE
128289856f7eSBjoern A. Zeeb finish_vnet_shutdown:
1283d3f6f80fSBjoern A. Zeeb #endif
1284d8c13659SBjoern A. Zeeb 	/*
1285d8c13659SBjoern A. Zeeb 	 * We cannot hold the lock over dom_ifdetach calls as they might
1286d8c13659SBjoern A. Zeeb 	 * sleep, for example trying to drain a callout, thus open up the
1287d8c13659SBjoern A. Zeeb 	 * theoretical race with re-attaching.
1288d8c13659SBjoern A. Zeeb 	 */
1289234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK(ifp);
1290d8c13659SBjoern A. Zeeb 	i = ifp->if_afdata_initialized;
1291d8c13659SBjoern A. Zeeb 	ifp->if_afdata_initialized = 0;
1292d8c13659SBjoern A. Zeeb 	IF_AFDATA_UNLOCK(ifp);
1293d8c13659SBjoern A. Zeeb 	for (dp = domains; i > 0 && dp; dp = dp->dom_next) {
12942d5ad99aSBjoern A. Zeeb 		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family]) {
129531b1bfe1SHajimu UMEMOTO 			(*dp->dom_ifdetach)(ifp,
129631b1bfe1SHajimu UMEMOTO 			    ifp->if_afdata[dp->dom_family]);
12972d5ad99aSBjoern A. Zeeb 			ifp->if_afdata[dp->dom_family] = NULL;
12982d5ad99aSBjoern A. Zeeb 		}
129931b1bfe1SHajimu UMEMOTO 	}
1300f501e6f1SBjoern A. Zeeb 
1301f501e6f1SBjoern A. Zeeb 	return (0);
13025500d3beSWarner Losh }
13035500d3beSWarner Losh 
1304e0c14af9SMarko Zec #ifdef VIMAGE
1305e0c14af9SMarko Zec /*
1306e0c14af9SMarko Zec  * if_vmove() performs a limited version of if_detach() in current
1307e0c14af9SMarko Zec  * vnet and if_attach()es the ifnet to the vnet specified as 2nd arg.
1308e0c14af9SMarko Zec  * An attempt is made to shrink if_index in current vnet, find an
1309e0c14af9SMarko Zec  * unused if_index in target vnet and calls if_grow() if necessary,
1310e0c14af9SMarko Zec  * and finally find an unused if_xname for the target vnet.
1311e0c14af9SMarko Zec  */
1312c7bab2a7SKyle Evans static int
1313e0c14af9SMarko Zec if_vmove(struct ifnet *ifp, struct vnet *new_vnet)
1314e0c14af9SMarko Zec {
1315c92a456bSHiroki Sato 	struct if_clone *ifc;
13163232273fSBjoern A. Zeeb #ifdef DEV_BPF
131705fc4164SBjoern A. Zeeb 	u_int bif_dlt, bif_hdrlen;
13183232273fSBjoern A. Zeeb #endif
13194f6c66ccSMatt Macy 	void *old;
1320f501e6f1SBjoern A. Zeeb 	int rc;
1321e0c14af9SMarko Zec 
13223232273fSBjoern A. Zeeb #ifdef DEV_BPF
1323e0c14af9SMarko Zec  	/*
132405fc4164SBjoern A. Zeeb 	 * if_detach_internal() will call the eventhandler to notify
132505fc4164SBjoern A. Zeeb 	 * interface departure.  That will detach if_bpf.  We need to
132605fc4164SBjoern A. Zeeb 	 * safe the dlt and hdrlen so we can re-attach it later.
132705fc4164SBjoern A. Zeeb 	 */
132805fc4164SBjoern A. Zeeb 	bpf_get_bp_params(ifp->if_bpf, &bif_dlt, &bif_hdrlen);
13293232273fSBjoern A. Zeeb #endif
133005fc4164SBjoern A. Zeeb 
133105fc4164SBjoern A. Zeeb 	/*
1332e0c14af9SMarko Zec 	 * Detach from current vnet, but preserve LLADDR info, do not
1333e0c14af9SMarko Zec 	 * mark as dead etc. so that the ifnet can be reattached later.
1334f501e6f1SBjoern A. Zeeb 	 * If we cannot find it, we lost the race to someone else.
1335e0c14af9SMarko Zec 	 */
1336f501e6f1SBjoern A. Zeeb 	rc = if_detach_internal(ifp, 1, &ifc);
1337f501e6f1SBjoern A. Zeeb 	if (rc != 0)
1338c7bab2a7SKyle Evans 		return (rc);
1339e0c14af9SMarko Zec 
1340e0c14af9SMarko Zec 	/*
134177dfcdc4SRobert Watson 	 * Unlink the ifnet from ifindex_table[] in current vnet, and shrink
134277dfcdc4SRobert Watson 	 * the if_index for that vnet if possible.
134377dfcdc4SRobert Watson 	 *
134477dfcdc4SRobert Watson 	 * NOTE: IFNET_WLOCK/IFNET_WUNLOCK() are assumed to be unvirtualized,
134577dfcdc4SRobert Watson 	 * or we'd lock on one vnet and unlock on another.
1346e0c14af9SMarko Zec 	 */
1347e0c14af9SMarko Zec 	IFNET_WLOCK();
1348ed2dabfcSRobert Watson 	ifindex_free_locked(ifp->if_index);
1349d3c351c5SMarko Zec 	IFNET_WUNLOCK();
1350d3c351c5SMarko Zec 
1351d3c351c5SMarko Zec 	/*
1352d3c351c5SMarko Zec 	 * Perform interface-specific reassignment tasks, if provided by
1353d3c351c5SMarko Zec 	 * the driver.
1354d3c351c5SMarko Zec 	 */
1355d3c351c5SMarko Zec 	if (ifp->if_reassign != NULL)
1356d3c351c5SMarko Zec 		ifp->if_reassign(ifp, new_vnet, NULL);
1357e0c14af9SMarko Zec 
1358e0c14af9SMarko Zec 	/*
1359e0c14af9SMarko Zec 	 * Switch to the context of the target vnet.
1360e0c14af9SMarko Zec 	 */
1361e0c14af9SMarko Zec 	CURVNET_SET_QUIET(new_vnet);
13624f6c66ccSMatt Macy  restart:
1363d3c351c5SMarko Zec 	IFNET_WLOCK();
13644f6c66ccSMatt Macy 	ifp->if_index = ifindex_alloc(&old);
13654f6c66ccSMatt Macy 	if (__predict_false(ifp->if_index == USHRT_MAX)) {
13664f6c66ccSMatt Macy 		IFNET_WUNLOCK();
13674f6c66ccSMatt Macy 		epoch_wait_preempt(net_epoch_preempt);
13684f6c66ccSMatt Macy 		free(old, M_IFNET);
13694f6c66ccSMatt Macy 		goto restart;
13704f6c66ccSMatt Macy 	}
13714f6c66ccSMatt Macy 	ifnet_setbyindex(ifp->if_index, ifp);
1372e0c14af9SMarko Zec 	IFNET_WUNLOCK();
1373e0c14af9SMarko Zec 
1374c92a456bSHiroki Sato 	if_attach_internal(ifp, 1, ifc);
1375e0c14af9SMarko Zec 
13763232273fSBjoern A. Zeeb #ifdef DEV_BPF
137705fc4164SBjoern A. Zeeb 	if (ifp->if_bpf == NULL)
137805fc4164SBjoern A. Zeeb 		bpfattach(ifp, bif_dlt, bif_hdrlen);
13793232273fSBjoern A. Zeeb #endif
138005fc4164SBjoern A. Zeeb 
1381e0c14af9SMarko Zec 	CURVNET_RESTORE();
1382c7bab2a7SKyle Evans 	return (0);
1383e0c14af9SMarko Zec }
1384be31e5e7SBjoern A. Zeeb 
1385be31e5e7SBjoern A. Zeeb /*
1386be31e5e7SBjoern A. Zeeb  * Move an ifnet to or from another child prison/vnet, specified by the jail id.
1387be31e5e7SBjoern A. Zeeb  */
1388be31e5e7SBjoern A. Zeeb static int
1389be31e5e7SBjoern A. Zeeb if_vmove_loan(struct thread *td, struct ifnet *ifp, char *ifname, int jid)
1390be31e5e7SBjoern A. Zeeb {
1391be31e5e7SBjoern A. Zeeb 	struct prison *pr;
1392be31e5e7SBjoern A. Zeeb 	struct ifnet *difp;
1393c7bab2a7SKyle Evans 	int error;
1394a779388fSKristof Provost 	bool found;
139510108cb6SBjoern A. Zeeb 	bool shutdown;
1396be31e5e7SBjoern A. Zeeb 
1397be31e5e7SBjoern A. Zeeb 	/* Try to find the prison within our visibility. */
1398be31e5e7SBjoern A. Zeeb 	sx_slock(&allprison_lock);
1399be31e5e7SBjoern A. Zeeb 	pr = prison_find_child(td->td_ucred->cr_prison, jid);
1400be31e5e7SBjoern A. Zeeb 	sx_sunlock(&allprison_lock);
1401be31e5e7SBjoern A. Zeeb 	if (pr == NULL)
1402be31e5e7SBjoern A. Zeeb 		return (ENXIO);
1403be31e5e7SBjoern A. Zeeb 	prison_hold_locked(pr);
1404be31e5e7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
1405be31e5e7SBjoern A. Zeeb 
1406be31e5e7SBjoern A. Zeeb 	/* Do not try to move the iface from and to the same prison. */
1407be31e5e7SBjoern A. Zeeb 	if (pr->pr_vnet == ifp->if_vnet) {
1408be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1409be31e5e7SBjoern A. Zeeb 		return (EEXIST);
1410be31e5e7SBjoern A. Zeeb 	}
1411be31e5e7SBjoern A. Zeeb 
1412be31e5e7SBjoern A. Zeeb 	/* Make sure the named iface does not exists in the dst. prison/vnet. */
1413be31e5e7SBjoern A. Zeeb 	/* XXX Lock interfaces to avoid races. */
14149abb4862SMarko Zec 	CURVNET_SET_QUIET(pr->pr_vnet);
1415be31e5e7SBjoern A. Zeeb 	difp = ifunit(ifname);
1416be31e5e7SBjoern A. Zeeb 	if (difp != NULL) {
141789856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
1418be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1419be31e5e7SBjoern A. Zeeb 		return (EEXIST);
1420be31e5e7SBjoern A. Zeeb 	}
1421be31e5e7SBjoern A. Zeeb 
142289856f7eSBjoern A. Zeeb 	/* Make sure the VNET is stable. */
142310108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet);
142410108cb6SBjoern A. Zeeb 	if (shutdown) {
142589856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
142689856f7eSBjoern A. Zeeb 		prison_free(pr);
142789856f7eSBjoern A. Zeeb 		return (EBUSY);
142889856f7eSBjoern A. Zeeb 	}
142989856f7eSBjoern A. Zeeb 	CURVNET_RESTORE();
143089856f7eSBjoern A. Zeeb 
1431a779388fSKristof Provost 	found = if_unlink_ifnet(ifp, true);
1432a779388fSKristof Provost 	MPASS(found);
1433a779388fSKristof Provost 
1434be31e5e7SBjoern A. Zeeb 	/* Move the interface into the child jail/vnet. */
1435c7bab2a7SKyle Evans 	error = if_vmove(ifp, pr->pr_vnet);
1436be31e5e7SBjoern A. Zeeb 
1437c7bab2a7SKyle Evans 	/* Report the new if_xname back to the userland on success. */
1438c7bab2a7SKyle Evans 	if (error == 0)
1439be31e5e7SBjoern A. Zeeb 		sprintf(ifname, "%s", ifp->if_xname);
1440be31e5e7SBjoern A. Zeeb 
1441be31e5e7SBjoern A. Zeeb 	prison_free(pr);
1442c7bab2a7SKyle Evans 	return (error);
1443be31e5e7SBjoern A. Zeeb }
1444be31e5e7SBjoern A. Zeeb 
1445be31e5e7SBjoern A. Zeeb static int
1446be31e5e7SBjoern A. Zeeb if_vmove_reclaim(struct thread *td, char *ifname, int jid)
1447be31e5e7SBjoern A. Zeeb {
1448be31e5e7SBjoern A. Zeeb 	struct prison *pr;
1449be31e5e7SBjoern A. Zeeb 	struct vnet *vnet_dst;
1450be31e5e7SBjoern A. Zeeb 	struct ifnet *ifp;
1451a779388fSKristof Provost 	int error, found;
145210108cb6SBjoern A. Zeeb  	bool shutdown;
1453be31e5e7SBjoern A. Zeeb 
1454be31e5e7SBjoern A. Zeeb 	/* Try to find the prison within our visibility. */
1455be31e5e7SBjoern A. Zeeb 	sx_slock(&allprison_lock);
1456be31e5e7SBjoern A. Zeeb 	pr = prison_find_child(td->td_ucred->cr_prison, jid);
1457be31e5e7SBjoern A. Zeeb 	sx_sunlock(&allprison_lock);
1458be31e5e7SBjoern A. Zeeb 	if (pr == NULL)
1459be31e5e7SBjoern A. Zeeb 		return (ENXIO);
1460be31e5e7SBjoern A. Zeeb 	prison_hold_locked(pr);
1461be31e5e7SBjoern A. Zeeb 	mtx_unlock(&pr->pr_mtx);
1462be31e5e7SBjoern A. Zeeb 
1463be31e5e7SBjoern A. Zeeb 	/* Make sure the named iface exists in the source prison/vnet. */
1464be31e5e7SBjoern A. Zeeb 	CURVNET_SET(pr->pr_vnet);
1465be31e5e7SBjoern A. Zeeb 	ifp = ifunit(ifname);		/* XXX Lock to avoid races. */
1466be31e5e7SBjoern A. Zeeb 	if (ifp == NULL) {
1467be31e5e7SBjoern A. Zeeb 		CURVNET_RESTORE();
1468be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1469be31e5e7SBjoern A. Zeeb 		return (ENXIO);
1470be31e5e7SBjoern A. Zeeb 	}
1471be31e5e7SBjoern A. Zeeb 
1472be31e5e7SBjoern A. Zeeb 	/* Do not try to move the iface from and to the same prison. */
1473be31e5e7SBjoern A. Zeeb 	vnet_dst = TD_TO_VNET(td);
1474be31e5e7SBjoern A. Zeeb 	if (vnet_dst == ifp->if_vnet) {
1475be31e5e7SBjoern A. Zeeb 		CURVNET_RESTORE();
1476be31e5e7SBjoern A. Zeeb 		prison_free(pr);
1477be31e5e7SBjoern A. Zeeb 		return (EEXIST);
1478be31e5e7SBjoern A. Zeeb 	}
1479be31e5e7SBjoern A. Zeeb 
148089856f7eSBjoern A. Zeeb 	/* Make sure the VNET is stable. */
148110108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(ifp->if_vnet);
148210108cb6SBjoern A. Zeeb 	if (shutdown) {
148389856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
148489856f7eSBjoern A. Zeeb 		prison_free(pr);
148589856f7eSBjoern A. Zeeb 		return (EBUSY);
148689856f7eSBjoern A. Zeeb 	}
148789856f7eSBjoern A. Zeeb 
1488be31e5e7SBjoern A. Zeeb 	/* Get interface back from child jail/vnet. */
1489a779388fSKristof Provost 	found = if_unlink_ifnet(ifp, true);
1490a779388fSKristof Provost 	MPASS(found);
1491c7bab2a7SKyle Evans 	error = if_vmove(ifp, vnet_dst);
1492be31e5e7SBjoern A. Zeeb 	CURVNET_RESTORE();
1493be31e5e7SBjoern A. Zeeb 
1494c7bab2a7SKyle Evans 	/* Report the new if_xname back to the userland on success. */
1495c7bab2a7SKyle Evans 	if (error == 0)
1496be31e5e7SBjoern A. Zeeb 		sprintf(ifname, "%s", ifp->if_xname);
1497be31e5e7SBjoern A. Zeeb 
1498be31e5e7SBjoern A. Zeeb 	prison_free(pr);
1499c7bab2a7SKyle Evans 	return (error);
1500be31e5e7SBjoern A. Zeeb }
1501e0c14af9SMarko Zec #endif /* VIMAGE */
1502e0c14af9SMarko Zec 
15035500d3beSWarner Losh /*
15040dad3f0eSMax Laier  * Add a group to an interface
15050dad3f0eSMax Laier  */
15060dad3f0eSMax Laier int
15070dad3f0eSMax Laier if_addgroup(struct ifnet *ifp, const char *groupname)
15080dad3f0eSMax Laier {
15090dad3f0eSMax Laier 	struct ifg_list		*ifgl;
15100dad3f0eSMax Laier 	struct ifg_group	*ifg = NULL;
15110dad3f0eSMax Laier 	struct ifg_member	*ifgm;
1512d6d3f01eSGleb Smirnoff 	int 			 new = 0;
15130dad3f0eSMax Laier 
15140dad3f0eSMax Laier 	if (groupname[0] && groupname[strlen(groupname) - 1] >= '0' &&
15150dad3f0eSMax Laier 	    groupname[strlen(groupname) - 1] <= '9')
15160dad3f0eSMax Laier 		return (EINVAL);
15170dad3f0eSMax Laier 
15180dad3f0eSMax Laier 	IFNET_WLOCK();
15194f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
15200dad3f0eSMax Laier 		if (!strcmp(ifgl->ifgl_group->ifg_group, groupname)) {
15210dad3f0eSMax Laier 			IFNET_WUNLOCK();
15220dad3f0eSMax Laier 			return (EEXIST);
15230dad3f0eSMax Laier 		}
15240dad3f0eSMax Laier 
15253f197b13SMark Johnston 	if ((ifgl = malloc(sizeof(*ifgl), M_TEMP, M_NOWAIT)) == NULL) {
15260dad3f0eSMax Laier 	    	IFNET_WUNLOCK();
15270dad3f0eSMax Laier 		return (ENOMEM);
15280dad3f0eSMax Laier 	}
15290dad3f0eSMax Laier 
15303f197b13SMark Johnston 	if ((ifgm = malloc(sizeof(*ifgm), M_TEMP, M_NOWAIT)) == NULL) {
15310dad3f0eSMax Laier 		free(ifgl, M_TEMP);
15320dad3f0eSMax Laier 		IFNET_WUNLOCK();
15330dad3f0eSMax Laier 		return (ENOMEM);
15340dad3f0eSMax Laier 	}
15350dad3f0eSMax Laier 
15364f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
15370dad3f0eSMax Laier 		if (!strcmp(ifg->ifg_group, groupname))
15380dad3f0eSMax Laier 			break;
15390dad3f0eSMax Laier 
15400dad3f0eSMax Laier 	if (ifg == NULL) {
15413f197b13SMark Johnston 		if ((ifg = malloc(sizeof(*ifg), M_TEMP, M_NOWAIT)) == NULL) {
15420dad3f0eSMax Laier 			free(ifgl, M_TEMP);
15430dad3f0eSMax Laier 			free(ifgm, M_TEMP);
15440dad3f0eSMax Laier 			IFNET_WUNLOCK();
15450dad3f0eSMax Laier 			return (ENOMEM);
15460dad3f0eSMax Laier 		}
15470dad3f0eSMax Laier 		strlcpy(ifg->ifg_group, groupname, sizeof(ifg->ifg_group));
15480dad3f0eSMax Laier 		ifg->ifg_refcnt = 0;
15494f6c66ccSMatt Macy 		CK_STAILQ_INIT(&ifg->ifg_members);
15504f6c66ccSMatt Macy 		CK_STAILQ_INSERT_TAIL(&V_ifg_head, ifg, ifg_next);
1551d6d3f01eSGleb Smirnoff 		new = 1;
15520dad3f0eSMax Laier 	}
15530dad3f0eSMax Laier 
15540dad3f0eSMax Laier 	ifg->ifg_refcnt++;
15550dad3f0eSMax Laier 	ifgl->ifgl_group = ifg;
15560dad3f0eSMax Laier 	ifgm->ifgm_ifp = ifp;
15570dad3f0eSMax Laier 
1558137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
15594f6c66ccSMatt Macy 	CK_STAILQ_INSERT_TAIL(&ifg->ifg_members, ifgm, ifgm_next);
15604f6c66ccSMatt Macy 	CK_STAILQ_INSERT_TAIL(&ifp->if_groups, ifgl, ifgl_next);
1561137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
15620dad3f0eSMax Laier 
15630dad3f0eSMax Laier 	IFNET_WUNLOCK();
15640dad3f0eSMax Laier 
1565d6d3f01eSGleb Smirnoff 	if (new)
1566d6d3f01eSGleb Smirnoff 		EVENTHANDLER_INVOKE(group_attach_event, ifg);
15670dad3f0eSMax Laier 	EVENTHANDLER_INVOKE(group_change_event, groupname);
15680dad3f0eSMax Laier 
15690dad3f0eSMax Laier 	return (0);
15700dad3f0eSMax Laier }
15710dad3f0eSMax Laier 
15720dad3f0eSMax Laier /*
15733f197b13SMark Johnston  * Helper function to remove a group out of an interface.  Expects the global
15743f197b13SMark Johnston  * ifnet lock to be write-locked, and drops it before returning.
15750dad3f0eSMax Laier  */
15763f197b13SMark Johnston static void
15773f197b13SMark Johnston _if_delgroup_locked(struct ifnet *ifp, struct ifg_list *ifgl,
15783f197b13SMark Johnston     const char *groupname)
15790dad3f0eSMax Laier {
15800dad3f0eSMax Laier 	struct ifg_member *ifgm;
15813f197b13SMark Johnston 	bool freeifgl;
15820dad3f0eSMax Laier 
15833f197b13SMark Johnston 	IFNET_WLOCK_ASSERT();
15840dad3f0eSMax Laier 
1585137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
15864f6c66ccSMatt Macy 	CK_STAILQ_REMOVE(&ifp->if_groups, ifgl, ifg_list, ifgl_next);
1587137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
15880dad3f0eSMax Laier 
15893f197b13SMark Johnston 	CK_STAILQ_FOREACH(ifgm, &ifgl->ifgl_group->ifg_members, ifgm_next) {
15903f197b13SMark Johnston 		if (ifgm->ifgm_ifp == ifp) {
15913f197b13SMark Johnston 			CK_STAILQ_REMOVE(&ifgl->ifgl_group->ifg_members, ifgm,
15923f197b13SMark Johnston 			    ifg_member, ifgm_next);
15930dad3f0eSMax Laier 			break;
15943f197b13SMark Johnston 		}
15953f197b13SMark Johnston 	}
15960dad3f0eSMax Laier 
15970dad3f0eSMax Laier 	if (--ifgl->ifgl_group->ifg_refcnt == 0) {
15983f197b13SMark Johnston 		CK_STAILQ_REMOVE(&V_ifg_head, ifgl->ifgl_group, ifg_group,
15993f197b13SMark Johnston 		    ifg_next);
16003f197b13SMark Johnston 		freeifgl = true;
16013f197b13SMark Johnston 	} else {
16023f197b13SMark Johnston 		freeifgl = false;
16034f6c66ccSMatt Macy 	}
16040dad3f0eSMax Laier 	IFNET_WUNLOCK();
16050dad3f0eSMax Laier 
16064f6c66ccSMatt Macy 	epoch_wait_preempt(net_epoch_preempt);
16074f6c66ccSMatt Macy 	if (freeifgl) {
16084f6c66ccSMatt Macy 		EVENTHANDLER_INVOKE(group_detach_event, ifgl->ifgl_group);
16094f6c66ccSMatt Macy 		free(ifgl->ifgl_group, M_TEMP);
16104f6c66ccSMatt Macy 	}
16114f6c66ccSMatt Macy 	free(ifgm, M_TEMP);
16120dad3f0eSMax Laier 	free(ifgl, M_TEMP);
16130dad3f0eSMax Laier 
16140dad3f0eSMax Laier 	EVENTHANDLER_INVOKE(group_change_event, groupname);
16153f197b13SMark Johnston }
16163f197b13SMark Johnston 
16173f197b13SMark Johnston /*
16183f197b13SMark Johnston  * Remove a group from an interface
16193f197b13SMark Johnston  */
16203f197b13SMark Johnston int
16213f197b13SMark Johnston if_delgroup(struct ifnet *ifp, const char *groupname)
16223f197b13SMark Johnston {
16233f197b13SMark Johnston 	struct ifg_list *ifgl;
16243f197b13SMark Johnston 
16253f197b13SMark Johnston 	IFNET_WLOCK();
16263f197b13SMark Johnston 	CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
16273f197b13SMark Johnston 		if (strcmp(ifgl->ifgl_group->ifg_group, groupname) == 0)
16283f197b13SMark Johnston 			break;
16293f197b13SMark Johnston 	if (ifgl == NULL) {
16303f197b13SMark Johnston 		IFNET_WUNLOCK();
16313f197b13SMark Johnston 		return (ENOENT);
16323f197b13SMark Johnston 	}
16333f197b13SMark Johnston 
16343f197b13SMark Johnston 	_if_delgroup_locked(ifp, ifgl, groupname);
16350dad3f0eSMax Laier 
16360dad3f0eSMax Laier 	return (0);
16370dad3f0eSMax Laier }
16380dad3f0eSMax Laier 
16390dad3f0eSMax Laier /*
16408623f9fdSMax Laier  * Remove an interface from all groups
16418623f9fdSMax Laier  */
16428623f9fdSMax Laier static void
16438623f9fdSMax Laier if_delgroups(struct ifnet *ifp)
16448623f9fdSMax Laier {
16458623f9fdSMax Laier 	struct ifg_list *ifgl;
16468623f9fdSMax Laier 	char groupname[IFNAMSIZ];
16478623f9fdSMax Laier 
16488623f9fdSMax Laier 	IFNET_WLOCK();
16493f197b13SMark Johnston 	while ((ifgl = CK_STAILQ_FIRST(&ifp->if_groups)) != NULL) {
16508623f9fdSMax Laier 		strlcpy(groupname, ifgl->ifgl_group->ifg_group, IFNAMSIZ);
16513f197b13SMark Johnston 		_if_delgroup_locked(ifp, ifgl, groupname);
16528623f9fdSMax Laier 		IFNET_WLOCK();
16538623f9fdSMax Laier 	}
16548623f9fdSMax Laier 	IFNET_WUNLOCK();
16558623f9fdSMax Laier }
16568623f9fdSMax Laier 
1657756181b8SBrooks Davis static char *
1658756181b8SBrooks Davis ifgr_group_get(void *ifgrp)
1659756181b8SBrooks Davis {
1660756181b8SBrooks Davis 	union ifgroupreq_union *ifgrup;
1661756181b8SBrooks Davis 
1662756181b8SBrooks Davis 	ifgrup = ifgrp;
1663756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32
1664756181b8SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
1665756181b8SBrooks Davis 		return (&ifgrup->ifgr32.ifgr_ifgru.ifgru_group[0]);
1666756181b8SBrooks Davis #endif
1667756181b8SBrooks Davis 	return (&ifgrup->ifgr.ifgr_ifgru.ifgru_group[0]);
1668756181b8SBrooks Davis }
1669756181b8SBrooks Davis 
1670756181b8SBrooks Davis static struct ifg_req *
1671756181b8SBrooks Davis ifgr_groups_get(void *ifgrp)
1672756181b8SBrooks Davis {
1673756181b8SBrooks Davis 	union ifgroupreq_union *ifgrup;
1674756181b8SBrooks Davis 
1675756181b8SBrooks Davis 	ifgrup = ifgrp;
1676756181b8SBrooks Davis #ifdef COMPAT_FREEBSD32
1677756181b8SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
1678756181b8SBrooks Davis 		return ((struct ifg_req *)(uintptr_t)
1679756181b8SBrooks Davis 		    ifgrup->ifgr32.ifgr_ifgru.ifgru_groups);
1680756181b8SBrooks Davis #endif
1681756181b8SBrooks Davis 	return (ifgrup->ifgr.ifgr_ifgru.ifgru_groups);
1682756181b8SBrooks Davis }
1683756181b8SBrooks Davis 
16848623f9fdSMax Laier /*
1685756181b8SBrooks Davis  * Stores all groups from an interface in memory pointed to by ifgr.
16860dad3f0eSMax Laier  */
16870dad3f0eSMax Laier static int
1688756181b8SBrooks Davis if_getgroup(struct ifgroupreq *ifgr, struct ifnet *ifp)
16890dad3f0eSMax Laier {
16900dad3f0eSMax Laier 	int			 len, error;
16910dad3f0eSMax Laier 	struct ifg_list		*ifgl;
16920dad3f0eSMax Laier 	struct ifg_req		 ifgrq, *ifgp;
16930dad3f0eSMax Laier 
1694b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
1695b8a6e03fSGleb Smirnoff 
16960dad3f0eSMax Laier 	if (ifgr->ifgr_len == 0) {
16974f6c66ccSMatt Macy 		CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next)
16980dad3f0eSMax Laier 			ifgr->ifgr_len += sizeof(struct ifg_req);
16990dad3f0eSMax Laier 		return (0);
17000dad3f0eSMax Laier 	}
17010dad3f0eSMax Laier 
17020dad3f0eSMax Laier 	len = ifgr->ifgr_len;
1703756181b8SBrooks Davis 	ifgp = ifgr_groups_get(ifgr);
17040dad3f0eSMax Laier 	/* XXX: wire */
17054f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifgl, &ifp->if_groups, ifgl_next) {
1706b8a6e03fSGleb Smirnoff 		if (len < sizeof(ifgrq))
17070dad3f0eSMax Laier 			return (EINVAL);
17080dad3f0eSMax Laier 		bzero(&ifgrq, sizeof ifgrq);
17090dad3f0eSMax Laier 		strlcpy(ifgrq.ifgrq_group, ifgl->ifgl_group->ifg_group,
17100dad3f0eSMax Laier 		    sizeof(ifgrq.ifgrq_group));
1711b8a6e03fSGleb Smirnoff 		if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req))))
17120dad3f0eSMax Laier 			return (error);
17130dad3f0eSMax Laier 		len -= sizeof(ifgrq);
17140dad3f0eSMax Laier 		ifgp++;
17150dad3f0eSMax Laier 	}
17160dad3f0eSMax Laier 
17170dad3f0eSMax Laier 	return (0);
17180dad3f0eSMax Laier }
17190dad3f0eSMax Laier 
17200dad3f0eSMax Laier /*
1721756181b8SBrooks Davis  * Stores all members of a group in memory pointed to by igfr
17220dad3f0eSMax Laier  */
17230dad3f0eSMax Laier static int
1724756181b8SBrooks Davis if_getgroupmembers(struct ifgroupreq *ifgr)
17250dad3f0eSMax Laier {
17260dad3f0eSMax Laier 	struct ifg_group	*ifg;
17270dad3f0eSMax Laier 	struct ifg_member	*ifgm;
17280dad3f0eSMax Laier 	struct ifg_req		 ifgrq, *ifgp;
17290dad3f0eSMax Laier 	int			 len, error;
17300dad3f0eSMax Laier 
17310dad3f0eSMax Laier 	IFNET_RLOCK();
17324f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifg, &V_ifg_head, ifg_next)
17333f197b13SMark Johnston 		if (strcmp(ifg->ifg_group, ifgr->ifgr_name) == 0)
17340dad3f0eSMax Laier 			break;
17350dad3f0eSMax Laier 	if (ifg == NULL) {
17360dad3f0eSMax Laier 		IFNET_RUNLOCK();
17370dad3f0eSMax Laier 		return (ENOENT);
17380dad3f0eSMax Laier 	}
17390dad3f0eSMax Laier 
17400dad3f0eSMax Laier 	if (ifgr->ifgr_len == 0) {
17414f6c66ccSMatt Macy 		CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next)
17420dad3f0eSMax Laier 			ifgr->ifgr_len += sizeof(ifgrq);
17430dad3f0eSMax Laier 		IFNET_RUNLOCK();
17440dad3f0eSMax Laier 		return (0);
17450dad3f0eSMax Laier 	}
17460dad3f0eSMax Laier 
17470dad3f0eSMax Laier 	len = ifgr->ifgr_len;
1748756181b8SBrooks Davis 	ifgp = ifgr_groups_get(ifgr);
17494f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifgm, &ifg->ifg_members, ifgm_next) {
17500dad3f0eSMax Laier 		if (len < sizeof(ifgrq)) {
17510dad3f0eSMax Laier 			IFNET_RUNLOCK();
17520dad3f0eSMax Laier 			return (EINVAL);
17530dad3f0eSMax Laier 		}
17540dad3f0eSMax Laier 		bzero(&ifgrq, sizeof ifgrq);
17550dad3f0eSMax Laier 		strlcpy(ifgrq.ifgrq_member, ifgm->ifgm_ifp->if_xname,
17560dad3f0eSMax Laier 		    sizeof(ifgrq.ifgrq_member));
17570dad3f0eSMax Laier 		if ((error = copyout(&ifgrq, ifgp, sizeof(struct ifg_req)))) {
17580dad3f0eSMax Laier 			IFNET_RUNLOCK();
17590dad3f0eSMax Laier 			return (error);
17600dad3f0eSMax Laier 		}
17610dad3f0eSMax Laier 		len -= sizeof(ifgrq);
17620dad3f0eSMax Laier 		ifgp++;
17630dad3f0eSMax Laier 	}
17640dad3f0eSMax Laier 	IFNET_RUNLOCK();
17650dad3f0eSMax Laier 
17660dad3f0eSMax Laier 	return (0);
17670dad3f0eSMax Laier }
17680dad3f0eSMax Laier 
17690dad3f0eSMax Laier /*
1770112f50ffSGleb Smirnoff  * Return counter values from counter(9)s stored in ifnet.
1771e6485f73SGleb Smirnoff  */
1772e6485f73SGleb Smirnoff uint64_t
17731b7fb1d9SGleb Smirnoff if_get_counter_default(struct ifnet *ifp, ift_counter cnt)
1774e6485f73SGleb Smirnoff {
1775e6485f73SGleb Smirnoff 
1776112f50ffSGleb Smirnoff 	KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt));
1777112f50ffSGleb Smirnoff 
1778112f50ffSGleb Smirnoff 	return (counter_u64_fetch(ifp->if_counters[cnt]));
1779e6485f73SGleb Smirnoff }
1780e6485f73SGleb Smirnoff 
1781e6485f73SGleb Smirnoff /*
17820b7b006cSGleb Smirnoff  * Increase an ifnet counter. Usually used for counters shared
17830b7b006cSGleb Smirnoff  * between the stack and a driver, but function supports them all.
17840b7b006cSGleb Smirnoff  */
17850b7b006cSGleb Smirnoff void
17861b7fb1d9SGleb Smirnoff if_inc_counter(struct ifnet *ifp, ift_counter cnt, int64_t inc)
17870b7b006cSGleb Smirnoff {
17880b7b006cSGleb Smirnoff 
1789112f50ffSGleb Smirnoff 	KASSERT(cnt < IFCOUNTERS, ("%s: invalid cnt %d", __func__, cnt));
1790112f50ffSGleb Smirnoff 
1791112f50ffSGleb Smirnoff 	counter_u64_add(ifp->if_counters[cnt], inc);
17920b7b006cSGleb Smirnoff }
17930b7b006cSGleb Smirnoff 
17940b7b006cSGleb Smirnoff /*
1795e6485f73SGleb Smirnoff  * Copy data from ifnet to userland API structure if_data.
1796e6485f73SGleb Smirnoff  */
1797e6485f73SGleb Smirnoff void
1798e6485f73SGleb Smirnoff if_data_copy(struct ifnet *ifp, struct if_data *ifd)
1799e6485f73SGleb Smirnoff {
1800e6485f73SGleb Smirnoff 
1801e6485f73SGleb Smirnoff 	ifd->ifi_type = ifp->if_type;
1802e6485f73SGleb Smirnoff 	ifd->ifi_physical = 0;
1803e6485f73SGleb Smirnoff 	ifd->ifi_addrlen = ifp->if_addrlen;
1804e6485f73SGleb Smirnoff 	ifd->ifi_hdrlen = ifp->if_hdrlen;
1805e6485f73SGleb Smirnoff 	ifd->ifi_link_state = ifp->if_link_state;
1806e6485f73SGleb Smirnoff 	ifd->ifi_vhid = 0;
1807e6485f73SGleb Smirnoff 	ifd->ifi_datalen = sizeof(struct if_data);
1808e6485f73SGleb Smirnoff 	ifd->ifi_mtu = ifp->if_mtu;
1809e6485f73SGleb Smirnoff 	ifd->ifi_metric = ifp->if_metric;
1810e6485f73SGleb Smirnoff 	ifd->ifi_baudrate = ifp->if_baudrate;
1811e6485f73SGleb Smirnoff 	ifd->ifi_hwassist = ifp->if_hwassist;
1812e6485f73SGleb Smirnoff 	ifd->ifi_epoch = ifp->if_epoch;
1813e6485f73SGleb Smirnoff 	ifd->ifi_lastchange = ifp->if_lastchange;
1814e6485f73SGleb Smirnoff 
1815e6485f73SGleb Smirnoff 	ifd->ifi_ipackets = ifp->if_get_counter(ifp, IFCOUNTER_IPACKETS);
1816e6485f73SGleb Smirnoff 	ifd->ifi_ierrors = ifp->if_get_counter(ifp, IFCOUNTER_IERRORS);
1817e6485f73SGleb Smirnoff 	ifd->ifi_opackets = ifp->if_get_counter(ifp, IFCOUNTER_OPACKETS);
1818e6485f73SGleb Smirnoff 	ifd->ifi_oerrors = ifp->if_get_counter(ifp, IFCOUNTER_OERRORS);
1819e6485f73SGleb Smirnoff 	ifd->ifi_collisions = ifp->if_get_counter(ifp, IFCOUNTER_COLLISIONS);
1820e6485f73SGleb Smirnoff 	ifd->ifi_ibytes = ifp->if_get_counter(ifp, IFCOUNTER_IBYTES);
1821e6485f73SGleb Smirnoff 	ifd->ifi_obytes = ifp->if_get_counter(ifp, IFCOUNTER_OBYTES);
1822e6485f73SGleb Smirnoff 	ifd->ifi_imcasts = ifp->if_get_counter(ifp, IFCOUNTER_IMCASTS);
1823e6485f73SGleb Smirnoff 	ifd->ifi_omcasts = ifp->if_get_counter(ifp, IFCOUNTER_OMCASTS);
1824e6485f73SGleb Smirnoff 	ifd->ifi_iqdrops = ifp->if_get_counter(ifp, IFCOUNTER_IQDROPS);
1825e6485f73SGleb Smirnoff 	ifd->ifi_oqdrops = ifp->if_get_counter(ifp, IFCOUNTER_OQDROPS);
1826e6485f73SGleb Smirnoff 	ifd->ifi_noproto = ifp->if_get_counter(ifp, IFCOUNTER_NOPROTO);
1827e6485f73SGleb Smirnoff }
1828e6485f73SGleb Smirnoff 
1829e6485f73SGleb Smirnoff /*
1830e8aa8bddSGleb Smirnoff  * Initialization, destruction and refcounting functions for ifaddrs.
18311099f828SRobert Watson  */
183246758960SGleb Smirnoff struct ifaddr *
183346758960SGleb Smirnoff ifa_alloc(size_t size, int flags)
18341099f828SRobert Watson {
183546758960SGleb Smirnoff 	struct ifaddr *ifa;
183646758960SGleb Smirnoff 
183746758960SGleb Smirnoff 	KASSERT(size >= sizeof(struct ifaddr),
183846758960SGleb Smirnoff 	    ("%s: invalid size %zu", __func__, size));
183946758960SGleb Smirnoff 
184046758960SGleb Smirnoff 	ifa = malloc(size, M_IFADDR, M_ZERO | flags);
184146758960SGleb Smirnoff 	if (ifa == NULL)
184246758960SGleb Smirnoff 		return (NULL);
18431099f828SRobert Watson 
18447caf4ab7SGleb Smirnoff 	if ((ifa->ifa_opackets = counter_u64_alloc(flags)) == NULL)
18457caf4ab7SGleb Smirnoff 		goto fail;
18467caf4ab7SGleb Smirnoff 	if ((ifa->ifa_ipackets = counter_u64_alloc(flags)) == NULL)
18477caf4ab7SGleb Smirnoff 		goto fail;
18487caf4ab7SGleb Smirnoff 	if ((ifa->ifa_obytes = counter_u64_alloc(flags)) == NULL)
18497caf4ab7SGleb Smirnoff 		goto fail;
18507caf4ab7SGleb Smirnoff 	if ((ifa->ifa_ibytes = counter_u64_alloc(flags)) == NULL)
18517caf4ab7SGleb Smirnoff 		goto fail;
18527caf4ab7SGleb Smirnoff 
18531099f828SRobert Watson 	refcount_init(&ifa->ifa_refcnt, 1);
185446758960SGleb Smirnoff 
185546758960SGleb Smirnoff 	return (ifa);
18567caf4ab7SGleb Smirnoff 
18577caf4ab7SGleb Smirnoff fail:
18587caf4ab7SGleb Smirnoff 	/* free(NULL) is okay */
18597caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_opackets);
18607caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ipackets);
18617caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_obytes);
18627caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ibytes);
18637caf4ab7SGleb Smirnoff 	free(ifa, M_IFADDR);
18647caf4ab7SGleb Smirnoff 
18657caf4ab7SGleb Smirnoff 	return (NULL);
18661099f828SRobert Watson }
18671099f828SRobert Watson 
18681099f828SRobert Watson void
18691099f828SRobert Watson ifa_ref(struct ifaddr *ifa)
18701099f828SRobert Watson {
1871600eade2SAlexander V. Chernikov 	u_int old;
18721099f828SRobert Watson 
1873600eade2SAlexander V. Chernikov 	old = refcount_acquire(&ifa->ifa_refcnt);
1874600eade2SAlexander V. Chernikov 	KASSERT(old > 0, ("%s: ifa %p has 0 refs", __func__, ifa));
1875600eade2SAlexander V. Chernikov }
1876600eade2SAlexander V. Chernikov 
1877600eade2SAlexander V. Chernikov int
1878600eade2SAlexander V. Chernikov ifa_try_ref(struct ifaddr *ifa)
1879600eade2SAlexander V. Chernikov {
1880600eade2SAlexander V. Chernikov 
1881600eade2SAlexander V. Chernikov 	NET_EPOCH_ASSERT();
1882600eade2SAlexander V. Chernikov 	return (refcount_acquire_if_not_zero(&ifa->ifa_refcnt));
18831099f828SRobert Watson }
18841099f828SRobert Watson 
1885d7c5a620SMatt Macy static void
1886d7c5a620SMatt Macy ifa_destroy(epoch_context_t ctx)
18871099f828SRobert Watson {
1888d7c5a620SMatt Macy 	struct ifaddr *ifa;
18891099f828SRobert Watson 
1890d7c5a620SMatt Macy 	ifa = __containerof(ctx, struct ifaddr, ifa_epoch_ctx);
18917caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_opackets);
18927caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ipackets);
18937caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_obytes);
18947caf4ab7SGleb Smirnoff 	counter_u64_free(ifa->ifa_ibytes);
18951099f828SRobert Watson 	free(ifa, M_IFADDR);
18961099f828SRobert Watson }
1897d7c5a620SMatt Macy 
1898d7c5a620SMatt Macy void
1899d7c5a620SMatt Macy ifa_free(struct ifaddr *ifa)
1900d7c5a620SMatt Macy {
1901d7c5a620SMatt Macy 
1902d7c5a620SMatt Macy 	if (refcount_release(&ifa->ifa_refcnt))
19032a4bd982SGleb Smirnoff 		NET_EPOCH_CALL(ifa_destroy, &ifa->ifa_epoch_ctx);
19041099f828SRobert Watson }
19051099f828SRobert Watson 
19061099f828SRobert Watson /*
190740d8a302SBruce M Simpson  * XXX: Because sockaddr_dl has deeper structure than the sockaddr
190840d8a302SBruce M Simpson  * structs used to represent other address families, it is necessary
190940d8a302SBruce M Simpson  * to perform a different comparison.
191040d8a302SBruce M Simpson  */
191140d8a302SBruce M Simpson 
191240d8a302SBruce M Simpson #define	sa_dl_equal(a1, a2)	\
1913441f9243SAlexander V. Chernikov 	((((const struct sockaddr_dl *)(a1))->sdl_len ==		\
1914441f9243SAlexander V. Chernikov 	 ((const struct sockaddr_dl *)(a2))->sdl_len) &&		\
1915441f9243SAlexander V. Chernikov 	 (bcmp(CLLADDR((const struct sockaddr_dl *)(a1)),		\
1916441f9243SAlexander V. Chernikov 	       CLLADDR((const struct sockaddr_dl *)(a2)),		\
1917441f9243SAlexander V. Chernikov 	       ((const struct sockaddr_dl *)(a1))->sdl_alen) == 0))
191819fc74fbSJeffrey Hsu 
191930aad87dSBrooks Davis /*
1920df8bae1dSRodney W. Grimes  * Locate an interface based on a complete address.
1921df8bae1dSRodney W. Grimes  */
1922df8bae1dSRodney W. Grimes /*ARGSUSED*/
19234f6c66ccSMatt Macy struct ifaddr *
19244f6c66ccSMatt Macy ifa_ifwithaddr(const struct sockaddr *addr)
1925df8bae1dSRodney W. Grimes {
19260b59d917SJonathan Lemon 	struct ifnet *ifp;
19270b59d917SJonathan Lemon 	struct ifaddr *ifa;
1928df8bae1dSRodney W. Grimes 
1929b8a6e03fSGleb Smirnoff 	NET_EPOCH_ASSERT();
1930b8a6e03fSGleb Smirnoff 
19314f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
1932d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1933df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
1934df8bae1dSRodney W. Grimes 				continue;
1935ab5ed8a5SRobert Watson 			if (sa_equal(addr, ifa->ifa_addr)) {
19360b59d917SJonathan Lemon 				goto done;
1937ab5ed8a5SRobert Watson 			}
193882cd038dSYoshinobu Inoue 			/* IP6 doesn't have broadcast */
19390b59d917SJonathan Lemon 			if ((ifp->if_flags & IFF_BROADCAST) &&
19400b59d917SJonathan Lemon 			    ifa->ifa_broadaddr &&
194182cd038dSYoshinobu Inoue 			    ifa->ifa_broadaddr->sa_len != 0 &&
1942ab5ed8a5SRobert Watson 			    sa_equal(ifa->ifa_broadaddr, addr)) {
19430b59d917SJonathan Lemon 				goto done;
19440b59d917SJonathan Lemon 			}
1945ab5ed8a5SRobert Watson 		}
1946ab5ed8a5SRobert Watson 	}
19470b59d917SJonathan Lemon 	ifa = NULL;
19480b59d917SJonathan Lemon done:
1949df8bae1dSRodney W. Grimes 	return (ifa);
1950df8bae1dSRodney W. Grimes }
19510b59d917SJonathan Lemon 
19528896f83aSRobert Watson int
1953441f9243SAlexander V. Chernikov ifa_ifwithaddr_check(const struct sockaddr *addr)
19548896f83aSRobert Watson {
1955a68cc388SGleb Smirnoff 	struct epoch_tracker et;
19564f6c66ccSMatt Macy 	int rc;
19578896f83aSRobert Watson 
1958a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
19594f6c66ccSMatt Macy 	rc = (ifa_ifwithaddr(addr) != NULL);
1960a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
19614f6c66ccSMatt Macy 	return (rc);
19628896f83aSRobert Watson }
19638896f83aSRobert Watson 
1964df8bae1dSRodney W. Grimes /*
1965773725a2SAndre Oppermann  * Locate an interface based on the broadcast address.
1966773725a2SAndre Oppermann  */
1967773725a2SAndre Oppermann /* ARGSUSED */
1968773725a2SAndre Oppermann struct ifaddr *
1969441f9243SAlexander V. Chernikov ifa_ifwithbroadaddr(const struct sockaddr *addr, int fibnum)
1970773725a2SAndre Oppermann {
1971773725a2SAndre Oppermann 	struct ifnet *ifp;
1972773725a2SAndre Oppermann 	struct ifaddr *ifa;
1973773725a2SAndre Oppermann 
197497168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
19754f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
19764f8585e0SAlan Somers 		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
19774f8585e0SAlan Somers 			continue;
1978d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1979773725a2SAndre Oppermann 			if (ifa->ifa_addr->sa_family != addr->sa_family)
1980773725a2SAndre Oppermann 				continue;
1981773725a2SAndre Oppermann 			if ((ifp->if_flags & IFF_BROADCAST) &&
1982773725a2SAndre Oppermann 			    ifa->ifa_broadaddr &&
1983773725a2SAndre Oppermann 			    ifa->ifa_broadaddr->sa_len != 0 &&
1984ab5ed8a5SRobert Watson 			    sa_equal(ifa->ifa_broadaddr, addr)) {
1985773725a2SAndre Oppermann 				goto done;
1986773725a2SAndre Oppermann 			}
1987ab5ed8a5SRobert Watson 		}
1988ab5ed8a5SRobert Watson 	}
1989773725a2SAndre Oppermann 	ifa = NULL;
1990773725a2SAndre Oppermann done:
1991773725a2SAndre Oppermann 	return (ifa);
1992773725a2SAndre Oppermann }
1993773725a2SAndre Oppermann 
1994773725a2SAndre Oppermann /*
1995df8bae1dSRodney W. Grimes  * Locate the point to point interface with a given destination address.
1996df8bae1dSRodney W. Grimes  */
1997df8bae1dSRodney W. Grimes /*ARGSUSED*/
1998df8bae1dSRodney W. Grimes struct ifaddr *
1999441f9243SAlexander V. Chernikov ifa_ifwithdstaddr(const struct sockaddr *addr, int fibnum)
2000df8bae1dSRodney W. Grimes {
20010b59d917SJonathan Lemon 	struct ifnet *ifp;
20020b59d917SJonathan Lemon 	struct ifaddr *ifa;
2003df8bae1dSRodney W. Grimes 
200497168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
20054f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
20060b59d917SJonathan Lemon 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
20070b59d917SJonathan Lemon 			continue;
20082f308a34SAlan Somers 		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
20090cfee0c2SAlan Somers 			continue;
2010d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2011df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
2012df8bae1dSRodney W. Grimes 				continue;
2013f0c04221SBjoern A. Zeeb 			if (ifa->ifa_dstaddr != NULL &&
2014ab5ed8a5SRobert Watson 			    sa_equal(addr, ifa->ifa_dstaddr)) {
20150b59d917SJonathan Lemon 				goto done;
2016df8bae1dSRodney W. Grimes 			}
20170b59d917SJonathan Lemon 		}
2018ab5ed8a5SRobert Watson 	}
20190b59d917SJonathan Lemon 	ifa = NULL;
20200b59d917SJonathan Lemon done:
20210b59d917SJonathan Lemon 	return (ifa);
2022df8bae1dSRodney W. Grimes }
2023df8bae1dSRodney W. Grimes 
2024df8bae1dSRodney W. Grimes /*
2025df8bae1dSRodney W. Grimes  * Find an interface on a specific network.  If many, choice
2026df8bae1dSRodney W. Grimes  * is most specific found.
2027df8bae1dSRodney W. Grimes  */
2028df8bae1dSRodney W. Grimes struct ifaddr *
2029441f9243SAlexander V. Chernikov ifa_ifwithnet(const struct sockaddr *addr, int ignore_ptp, int fibnum)
2030df8bae1dSRodney W. Grimes {
203172fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
203272fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
20338c0fec80SRobert Watson 	struct ifaddr *ifa_maybe = NULL;
2034df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
2035441f9243SAlexander V. Chernikov 	const char *addr_data = addr->sa_data, *cplim;
2036df8bae1dSRodney W. Grimes 
203797168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
20387e2a6151SJulian Elischer 	/*
20397e2a6151SJulian Elischer 	 * AF_LINK addresses can be looked up directly by their index number,
20407e2a6151SJulian Elischer 	 * so do that if we can.
20417e2a6151SJulian Elischer 	 */
2042df8bae1dSRodney W. Grimes 	if (af == AF_LINK) {
2043441f9243SAlexander V. Chernikov 	    const struct sockaddr_dl *sdl = (const struct sockaddr_dl *)addr;
2044603724d3SBjoern A. Zeeb 	    if (sdl->sdl_index && sdl->sdl_index <= V_if_index)
2045f9132cebSJonathan Lemon 		return (ifaddr_byindex(sdl->sdl_index));
2046df8bae1dSRodney W. Grimes 	}
20477e2a6151SJulian Elischer 
20487e2a6151SJulian Elischer 	/*
20498c0fec80SRobert Watson 	 * Scan though each interface, looking for ones that have addresses
205021ee61a6SGleb Smirnoff 	 * in this address family and the requested fib.
20517e2a6151SJulian Elischer 	 */
20524f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
20532f308a34SAlan Somers 		if ((fibnum != RT_ALL_FIBS) && (ifp->if_fib != fibnum))
20540cfee0c2SAlan Somers 			continue;
2055d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2056441f9243SAlexander V. Chernikov 			const char *cp, *cp2, *cp3;
2057df8bae1dSRodney W. Grimes 
2058523a02aaSDavid Greenman 			if (ifa->ifa_addr->sa_family != af)
2059df8bae1dSRodney W. Grimes next:				continue;
20600ed6142bSQing Li 			if (af == AF_INET &&
20610ed6142bSQing Li 			    ifp->if_flags & IFF_POINTOPOINT && !ignore_ptp) {
20627e2a6151SJulian Elischer 				/*
20637e2a6151SJulian Elischer 				 * This is a bit broken as it doesn't
20647e2a6151SJulian Elischer 				 * take into account that the remote end may
20657e2a6151SJulian Elischer 				 * be a single node in the network we are
20667e2a6151SJulian Elischer 				 * looking for.
20677e2a6151SJulian Elischer 				 * The trouble is that we don't know the
20687e2a6151SJulian Elischer 				 * netmask for the remote end.
20697e2a6151SJulian Elischer 				 */
2070f0c04221SBjoern A. Zeeb 				if (ifa->ifa_dstaddr != NULL &&
2071ab5ed8a5SRobert Watson 				    sa_equal(addr, ifa->ifa_dstaddr)) {
20720b59d917SJonathan Lemon 					goto done;
2073ab5ed8a5SRobert Watson 				}
20743740e2adSDavid Greenman 			} else {
20757e2a6151SJulian Elischer 				/*
20767e2a6151SJulian Elischer 				 * Scan all the bits in the ifa's address.
20777e2a6151SJulian Elischer 				 * If a bit dissagrees with what we are
20787e2a6151SJulian Elischer 				 * looking for, mask it with the netmask
20797e2a6151SJulian Elischer 				 * to see if it really matters.
20807e2a6151SJulian Elischer 				 * (A byte at a time)
20817e2a6151SJulian Elischer 				 */
2082523a02aaSDavid Greenman 				if (ifa->ifa_netmask == 0)
2083523a02aaSDavid Greenman 					continue;
2084df8bae1dSRodney W. Grimes 				cp = addr_data;
2085df8bae1dSRodney W. Grimes 				cp2 = ifa->ifa_addr->sa_data;
2086df8bae1dSRodney W. Grimes 				cp3 = ifa->ifa_netmask->sa_data;
20877e2a6151SJulian Elischer 				cplim = ifa->ifa_netmask->sa_len
20887e2a6151SJulian Elischer 					+ (char *)ifa->ifa_netmask;
2089df8bae1dSRodney W. Grimes 				while (cp3 < cplim)
2090df8bae1dSRodney W. Grimes 					if ((*cp++ ^ *cp2++) & *cp3++)
20917e2a6151SJulian Elischer 						goto next; /* next address! */
20927e2a6151SJulian Elischer 				/*
20937e2a6151SJulian Elischer 				 * If the netmask of what we just found
20947e2a6151SJulian Elischer 				 * is more specific than what we had before
209524421c1cSGleb Smirnoff 				 * (if we had one), or if the virtual status
209624421c1cSGleb Smirnoff 				 * of new prefix is better than of the old one,
209724421c1cSGleb Smirnoff 				 * then remember the new one before continuing
209824421c1cSGleb Smirnoff 				 * to search for an even better one.
20997e2a6151SJulian Elischer 				 */
21008c0fec80SRobert Watson 				if (ifa_maybe == NULL ||
210124421c1cSGleb Smirnoff 				    ifa_preferred(ifa_maybe, ifa) ||
2102df8bae1dSRodney W. Grimes 				    rn_refines((caddr_t)ifa->ifa_netmask,
21038c0fec80SRobert Watson 				    (caddr_t)ifa_maybe->ifa_netmask)) {
2104df8bae1dSRodney W. Grimes 					ifa_maybe = ifa;
21058c0fec80SRobert Watson 				}
2106df8bae1dSRodney W. Grimes 			}
2107b2af64fdSDavid Greenman 		}
2108b2af64fdSDavid Greenman 	}
21090b59d917SJonathan Lemon 	ifa = ifa_maybe;
21108c0fec80SRobert Watson 	ifa_maybe = NULL;
21110b59d917SJonathan Lemon done:
21120b59d917SJonathan Lemon 	return (ifa);
2113df8bae1dSRodney W. Grimes }
2114df8bae1dSRodney W. Grimes 
2115df8bae1dSRodney W. Grimes /*
2116df8bae1dSRodney W. Grimes  * Find an interface address specific to an interface best matching
2117df8bae1dSRodney W. Grimes  * a given address.
2118df8bae1dSRodney W. Grimes  */
2119df8bae1dSRodney W. Grimes struct ifaddr *
2120441f9243SAlexander V. Chernikov ifaof_ifpforaddr(const struct sockaddr *addr, struct ifnet *ifp)
2121df8bae1dSRodney W. Grimes {
212272fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
2123441f9243SAlexander V. Chernikov 	const char *cp, *cp2, *cp3;
212472fd1b6aSDag-Erling Smørgrav 	char *cplim;
21258c0fec80SRobert Watson 	struct ifaddr *ifa_maybe = NULL;
2126df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
2127df8bae1dSRodney W. Grimes 
2128df8bae1dSRodney W. Grimes 	if (af >= AF_MAX)
2129cd292f12SBjoern A. Zeeb 		return (NULL);
21306573d758SMatt Macy 
213197168be8SGleb Smirnoff 	NET_EPOCH_ASSERT();
2132d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
2133df8bae1dSRodney W. Grimes 		if (ifa->ifa_addr->sa_family != af)
2134df8bae1dSRodney W. Grimes 			continue;
21358c0fec80SRobert Watson 		if (ifa_maybe == NULL)
2136df8bae1dSRodney W. Grimes 			ifa_maybe = ifa;
2137df8bae1dSRodney W. Grimes 		if (ifa->ifa_netmask == 0) {
2138d8d5b10eSRobert Watson 			if (sa_equal(addr, ifa->ifa_addr) ||
2139d8d5b10eSRobert Watson 			    (ifa->ifa_dstaddr &&
2140d8d5b10eSRobert Watson 			    sa_equal(addr, ifa->ifa_dstaddr)))
21412defe5cdSJonathan Lemon 				goto done;
2142df8bae1dSRodney W. Grimes 			continue;
2143df8bae1dSRodney W. Grimes 		}
2144b2af64fdSDavid Greenman 		if (ifp->if_flags & IFF_POINTOPOINT) {
2145d8d5b10eSRobert Watson 			if (sa_equal(addr, ifa->ifa_dstaddr))
2146a8637146SJonathan Lemon 				goto done;
21473740e2adSDavid Greenman 		} else {
2148df8bae1dSRodney W. Grimes 			cp = addr->sa_data;
2149df8bae1dSRodney W. Grimes 			cp2 = ifa->ifa_addr->sa_data;
2150df8bae1dSRodney W. Grimes 			cp3 = ifa->ifa_netmask->sa_data;
2151df8bae1dSRodney W. Grimes 			cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
2152df8bae1dSRodney W. Grimes 			for (; cp3 < cplim; cp3++)
2153df8bae1dSRodney W. Grimes 				if ((*cp++ ^ *cp2++) & *cp3)
2154df8bae1dSRodney W. Grimes 					break;
2155df8bae1dSRodney W. Grimes 			if (cp3 == cplim)
21562defe5cdSJonathan Lemon 				goto done;
2157df8bae1dSRodney W. Grimes 		}
2158b2af64fdSDavid Greenman 	}
2159f9132cebSJonathan Lemon 	ifa = ifa_maybe;
2160f9132cebSJonathan Lemon done:
2161f9132cebSJonathan Lemon 	return (ifa);
2162df8bae1dSRodney W. Grimes }
2163df8bae1dSRodney W. Grimes 
216424421c1cSGleb Smirnoff /*
216524421c1cSGleb Smirnoff  * See whether new ifa is better than current one:
216624421c1cSGleb Smirnoff  * 1) A non-virtual one is preferred over virtual.
216724421c1cSGleb Smirnoff  * 2) A virtual in master state preferred over any other state.
216824421c1cSGleb Smirnoff  *
216924421c1cSGleb Smirnoff  * Used in several address selecting functions.
217024421c1cSGleb Smirnoff  */
217124421c1cSGleb Smirnoff int
217224421c1cSGleb Smirnoff ifa_preferred(struct ifaddr *cur, struct ifaddr *next)
217324421c1cSGleb Smirnoff {
217424421c1cSGleb Smirnoff 
217524421c1cSGleb Smirnoff 	return (cur->ifa_carp && (!next->ifa_carp ||
217624421c1cSGleb Smirnoff 	    ((*carp_master_p)(next) && !(*carp_master_p)(cur))));
217724421c1cSGleb Smirnoff }
217824421c1cSGleb Smirnoff 
217995fbe4d0SAlexander V. Chernikov struct sockaddr_dl *
218095fbe4d0SAlexander V. Chernikov link_alloc_sdl(size_t size, int flags)
218195fbe4d0SAlexander V. Chernikov {
218295fbe4d0SAlexander V. Chernikov 
218395fbe4d0SAlexander V. Chernikov 	return (malloc(size, M_TEMP, flags));
218495fbe4d0SAlexander V. Chernikov }
218595fbe4d0SAlexander V. Chernikov 
218695fbe4d0SAlexander V. Chernikov void
218795fbe4d0SAlexander V. Chernikov link_free_sdl(struct sockaddr *sa)
218895fbe4d0SAlexander V. Chernikov {
218995fbe4d0SAlexander V. Chernikov 	free(sa, M_TEMP);
219095fbe4d0SAlexander V. Chernikov }
219195fbe4d0SAlexander V. Chernikov 
219295fbe4d0SAlexander V. Chernikov /*
219395fbe4d0SAlexander V. Chernikov  * Fills in given sdl with interface basic info.
219495fbe4d0SAlexander V. Chernikov  * Returns pointer to filled sdl.
219595fbe4d0SAlexander V. Chernikov  */
219695fbe4d0SAlexander V. Chernikov struct sockaddr_dl *
219795fbe4d0SAlexander V. Chernikov link_init_sdl(struct ifnet *ifp, struct sockaddr *paddr, u_char iftype)
219895fbe4d0SAlexander V. Chernikov {
219995fbe4d0SAlexander V. Chernikov 	struct sockaddr_dl *sdl;
220095fbe4d0SAlexander V. Chernikov 
220195fbe4d0SAlexander V. Chernikov 	sdl = (struct sockaddr_dl *)paddr;
220295fbe4d0SAlexander V. Chernikov 	memset(sdl, 0, sizeof(struct sockaddr_dl));
220395fbe4d0SAlexander V. Chernikov 	sdl->sdl_len = sizeof(struct sockaddr_dl);
220495fbe4d0SAlexander V. Chernikov 	sdl->sdl_family = AF_LINK;
220595fbe4d0SAlexander V. Chernikov 	sdl->sdl_index = ifp->if_index;
220695fbe4d0SAlexander V. Chernikov 	sdl->sdl_type = iftype;
220795fbe4d0SAlexander V. Chernikov 
220895fbe4d0SAlexander V. Chernikov 	return (sdl);
220995fbe4d0SAlexander V. Chernikov }
221095fbe4d0SAlexander V. Chernikov 
2211df8bae1dSRodney W. Grimes /*
2212df8bae1dSRodney W. Grimes  * Mark an interface down and notify protocols of
2213df8bae1dSRodney W. Grimes  * the transition.
2214df8bae1dSRodney W. Grimes  */
22158614fb12SMax Laier static void
221672fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam)
2217df8bae1dSRodney W. Grimes {
221872fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
2219df8bae1dSRodney W. Grimes 
2220292ee7beSRobert Watson 	KASSERT(flag == IFF_UP, ("if_unroute: flag != IFF_UP"));
2221292ee7beSRobert Watson 
2222e8c2601dSPoul-Henning Kamp 	ifp->if_flags &= ~flag;
222398b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
2224d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
2225e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
2226df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
2227db7f0b97SKip Macy 	ifp->if_qflush(ifp);
2228db7f0b97SKip Macy 
2229a9771948SGleb Smirnoff 	if (ifp->if_carp)
223054bfbd51SWill Andrews 		(*carp_linkstate_p)(ifp);
2231df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
2232df8bae1dSRodney W. Grimes }
2233df8bae1dSRodney W. Grimes 
2234df8bae1dSRodney W. Grimes /*
2235df8bae1dSRodney W. Grimes  * Mark an interface up and notify protocols of
2236df8bae1dSRodney W. Grimes  * the transition.
2237df8bae1dSRodney W. Grimes  */
22388614fb12SMax Laier static void
223972fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam)
2240df8bae1dSRodney W. Grimes {
224172fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
2242df8bae1dSRodney W. Grimes 
2243292ee7beSRobert Watson 	KASSERT(flag == IFF_UP, ("if_route: flag != IFF_UP"));
2244292ee7beSRobert Watson 
2245e8c2601dSPoul-Henning Kamp 	ifp->if_flags |= flag;
224698b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
2247d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
2248e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
2249df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFUP, ifa->ifa_addr);
2250a9771948SGleb Smirnoff 	if (ifp->if_carp)
225154bfbd51SWill Andrews 		(*carp_linkstate_p)(ifp);
2252df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
225382cd038dSYoshinobu Inoue #ifdef INET6
225482cd038dSYoshinobu Inoue 	in6_if_up(ifp);
225582cd038dSYoshinobu Inoue #endif
2256df8bae1dSRodney W. Grimes }
2257df8bae1dSRodney W. Grimes 
2258a6fffd6cSBrooks Davis void	(*vlan_link_state_p)(struct ifnet *);	/* XXX: private from if_vlan */
225975ee267cSGleb Smirnoff void	(*vlan_trunk_cap_p)(struct ifnet *);		/* XXX: private from if_vlan */
2260e4cd31ddSJeff Roberson struct ifnet *(*vlan_trunkdev_p)(struct ifnet *);
2261e4cd31ddSJeff Roberson struct	ifnet *(*vlan_devat_p)(struct ifnet *, uint16_t);
2262e4cd31ddSJeff Roberson int	(*vlan_tag_p)(struct ifnet *, uint16_t *);
226332d2623aSNavdeep Parhar int	(*vlan_pcp_p)(struct ifnet *, uint16_t *);
2264e4cd31ddSJeff Roberson int	(*vlan_setcookie_p)(struct ifnet *, void *);
2265e4cd31ddSJeff Roberson void	*(*vlan_cookie_p)(struct ifnet *);
226694f5c9cfSSam Leffler 
226794f5c9cfSSam Leffler /*
226868a3482fSGleb Smirnoff  * Handle a change in the interface link state. To avoid LORs
226968a3482fSGleb Smirnoff  * between driver lock and upper layer locks, as well as possible
227068a3482fSGleb Smirnoff  * recursions, we post event to taskqueue, and all job
227168a3482fSGleb Smirnoff  * is done in static do_link_state_change().
227294f5c9cfSSam Leffler  */
227394f5c9cfSSam Leffler void
2274d6e82913SSteven Hartland if_link_state_change(struct ifnet *ifp, int link_state)
227594f5c9cfSSam Leffler {
2276d6e82913SSteven Hartland 	/* Return if state hasn't changed. */
2277d6e82913SSteven Hartland 	if (ifp->if_link_state == link_state)
22784d96314fSGleb Smirnoff 		return;
22794d96314fSGleb Smirnoff 
228094f5c9cfSSam Leffler 	ifp->if_link_state = link_state;
22814d96314fSGleb Smirnoff 
2282b8a6e03fSGleb Smirnoff 	/* XXXGL: reference ifp? */
228368a3482fSGleb Smirnoff 	taskqueue_enqueue(taskqueue_swi, &ifp->if_linktask);
228468a3482fSGleb Smirnoff }
228568a3482fSGleb Smirnoff 
228668a3482fSGleb Smirnoff static void
228768a3482fSGleb Smirnoff do_link_state_change(void *arg, int pending)
228868a3482fSGleb Smirnoff {
2289b8a6e03fSGleb Smirnoff 	struct ifnet *ifp;
2290b8a6e03fSGleb Smirnoff 	int link_state;
229168a3482fSGleb Smirnoff 
2292b8a6e03fSGleb Smirnoff 	ifp = arg;
2293b8a6e03fSGleb Smirnoff 	link_state = ifp->if_link_state;
2294b8a6e03fSGleb Smirnoff 
2295b8a6e03fSGleb Smirnoff 	CURVNET_SET(ifp->if_vnet);
229694f5c9cfSSam Leffler 	rt_ifmsg(ifp);
229775ee267cSGleb Smirnoff 	if (ifp->if_vlantrunk != NULL)
2298a6fffd6cSBrooks Davis 		(*vlan_link_state_p)(ifp);
22991c7899c7SGleb Smirnoff 
23001c7899c7SGleb Smirnoff 	if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) &&
2301833e8dc5SGleb Smirnoff 	    ifp->if_l2com != NULL)
23021c7899c7SGleb Smirnoff 		(*ng_ether_link_state_p)(ifp, link_state);
23034d96314fSGleb Smirnoff 	if (ifp->if_carp)
230454bfbd51SWill Andrews 		(*carp_linkstate_p)(ifp);
2305ddf32010SAndrew Thompson 	if (ifp->if_bridge)
23065c30b378SMatt Macy 		ifp->if_bridge_linkstate(ifp);
2307ddf32010SAndrew Thompson 	if (ifp->if_lagg)
2308d6e82913SSteven Hartland 		(*lagg_linkstate_p)(ifp, link_state);
23098f867517SAndrew Thompson 
231021ca7b57SMarko Zec 	if (IS_DEFAULT_VNET(curvnet))
23119d80a330SBrooks Davis 		devctl_notify("IFNET", ifp->if_xname,
231221ca7b57SMarko Zec 		    (link_state == LINK_STATE_UP) ? "LINK_UP" : "LINK_DOWN",
231321ca7b57SMarko Zec 		    NULL);
231468a3482fSGleb Smirnoff 	if (pending > 1)
231568a3482fSGleb Smirnoff 		if_printf(ifp, "%d link states coalesced\n", pending);
23165515c2e7SGleb Smirnoff 	if (log_link_state_change)
231720f8d7bcSDag-Erling Smørgrav 		if_printf(ifp, "link state changed to %s\n",
23188b02df24SGleb Smirnoff 		    (link_state == LINK_STATE_UP) ? "UP" : "DOWN" );
2319368bf0c2SSepherosa Ziehau 	EVENTHANDLER_INVOKE(ifnet_link_event, ifp, link_state);
23208b615593SMarko Zec 	CURVNET_RESTORE();
232194f5c9cfSSam Leffler }
232294f5c9cfSSam Leffler 
2323df8bae1dSRodney W. Grimes /*
2324e8c2601dSPoul-Henning Kamp  * Mark an interface down and notify protocols of
2325e8c2601dSPoul-Henning Kamp  * the transition.
2326e8c2601dSPoul-Henning Kamp  */
2327e8c2601dSPoul-Henning Kamp void
232872fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp)
2329e8c2601dSPoul-Henning Kamp {
2330e8c2601dSPoul-Henning Kamp 
233192a6859bSDexuan Cui 	EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_DOWN);
2332e8c2601dSPoul-Henning Kamp 	if_unroute(ifp, IFF_UP, AF_UNSPEC);
2333e8c2601dSPoul-Henning Kamp }
2334e8c2601dSPoul-Henning Kamp 
2335e8c2601dSPoul-Henning Kamp /*
2336e8c2601dSPoul-Henning Kamp  * Mark an interface up and notify protocols of
2337e8c2601dSPoul-Henning Kamp  * the transition.
2338e8c2601dSPoul-Henning Kamp  */
2339e8c2601dSPoul-Henning Kamp void
234072fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp)
2341e8c2601dSPoul-Henning Kamp {
2342e8c2601dSPoul-Henning Kamp 
2343e8c2601dSPoul-Henning Kamp 	if_route(ifp, IFF_UP, AF_UNSPEC);
234492a6859bSDexuan Cui 	EVENTHANDLER_INVOKE(ifnet_event, ifp, IFNET_EVENT_UP);
2345e8c2601dSPoul-Henning Kamp }
2346e8c2601dSPoul-Henning Kamp 
2347e8c2601dSPoul-Henning Kamp /*
2348df8bae1dSRodney W. Grimes  * Flush an interface queue.
2349df8bae1dSRodney W. Grimes  */
23507cc5b47fSKip Macy void
2351db7f0b97SKip Macy if_qflush(struct ifnet *ifp)
2352df8bae1dSRodney W. Grimes {
235372fd1b6aSDag-Erling Smørgrav 	struct mbuf *m, *n;
2354db7f0b97SKip Macy 	struct ifaltq *ifq;
2355df8bae1dSRodney W. Grimes 
2356db7f0b97SKip Macy 	ifq = &ifp->if_snd;
23577b21048cSMax Laier 	IFQ_LOCK(ifq);
235802b199f1SMax Laier #ifdef ALTQ
235902b199f1SMax Laier 	if (ALTQ_IS_ENABLED(ifq))
236002b199f1SMax Laier 		ALTQ_PURGE(ifq);
236102b199f1SMax Laier #endif
2362df8bae1dSRodney W. Grimes 	n = ifq->ifq_head;
2363155d72c4SPedro F. Giffuni 	while ((m = n) != NULL) {
2364c29a3321SKevin Lo 		n = m->m_nextpkt;
2365df8bae1dSRodney W. Grimes 		m_freem(m);
2366df8bae1dSRodney W. Grimes 	}
2367df8bae1dSRodney W. Grimes 	ifq->ifq_head = 0;
2368df8bae1dSRodney W. Grimes 	ifq->ifq_tail = 0;
2369df8bae1dSRodney W. Grimes 	ifq->ifq_len = 0;
23707b21048cSMax Laier 	IFQ_UNLOCK(ifq);
2371df8bae1dSRodney W. Grimes }
2372df8bae1dSRodney W. Grimes 
2373df8bae1dSRodney W. Grimes /*
23746064c5d3SRobert Watson  * Map interface name to interface structure pointer, with or without
23756064c5d3SRobert Watson  * returning a reference.
2376df8bae1dSRodney W. Grimes  */
2377df8bae1dSRodney W. Grimes struct ifnet *
23786064c5d3SRobert Watson ifunit_ref(const char *name)
23796064c5d3SRobert Watson {
2380a68cc388SGleb Smirnoff 	struct epoch_tracker et;
23816064c5d3SRobert Watson 	struct ifnet *ifp;
23826064c5d3SRobert Watson 
2383a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
23844f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
23858bd015a1SRobert Watson 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0 &&
23868bd015a1SRobert Watson 		    !(ifp->if_flags & IFF_DYING))
23876064c5d3SRobert Watson 			break;
23886064c5d3SRobert Watson 	}
23896064c5d3SRobert Watson 	if (ifp != NULL)
23906064c5d3SRobert Watson 		if_ref(ifp);
2391a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
23926064c5d3SRobert Watson 	return (ifp);
23936064c5d3SRobert Watson }
23946064c5d3SRobert Watson 
23956064c5d3SRobert Watson struct ifnet *
239630aad87dSBrooks Davis ifunit(const char *name)
2397df8bae1dSRodney W. Grimes {
2398a68cc388SGleb Smirnoff 	struct epoch_tracker et;
23998b7805e4SBoris Popov 	struct ifnet *ifp;
2400df8bae1dSRodney W. Grimes 
2401a68cc388SGleb Smirnoff 	NET_EPOCH_ENTER(et);
24024f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
240336c19a57SBrooks Davis 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
2404df8bae1dSRodney W. Grimes 			break;
2405df8bae1dSRodney W. Grimes 	}
2406a68cc388SGleb Smirnoff 	NET_EPOCH_EXIT(et);
2407df8bae1dSRodney W. Grimes 	return (ifp);
2408df8bae1dSRodney W. Grimes }
2409df8bae1dSRodney W. Grimes 
24108ad798aeSBrooks Davis void *
24118a4a4a43SBrooks Davis ifr_buffer_get_buffer(void *data)
241286d2ef16SBrooks Davis {
241386d2ef16SBrooks Davis 	union ifreq_union *ifrup;
241486d2ef16SBrooks Davis 
241586d2ef16SBrooks Davis 	ifrup = data;
241686d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24178a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
241886d2ef16SBrooks Davis 		return ((void *)(uintptr_t)
241986d2ef16SBrooks Davis 		    ifrup->ifr32.ifr_ifru.ifru_buffer.buffer);
242086d2ef16SBrooks Davis #endif
242186d2ef16SBrooks Davis 	return (ifrup->ifr.ifr_ifru.ifru_buffer.buffer);
242286d2ef16SBrooks Davis }
242386d2ef16SBrooks Davis 
242486d2ef16SBrooks Davis static void
24258a4a4a43SBrooks Davis ifr_buffer_set_buffer_null(void *data)
242686d2ef16SBrooks Davis {
242786d2ef16SBrooks Davis 	union ifreq_union *ifrup;
242886d2ef16SBrooks Davis 
242986d2ef16SBrooks Davis 	ifrup = data;
243086d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24318a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
243286d2ef16SBrooks Davis 		ifrup->ifr32.ifr_ifru.ifru_buffer.buffer = 0;
243386d2ef16SBrooks Davis 	else
243486d2ef16SBrooks Davis #endif
243586d2ef16SBrooks Davis 		ifrup->ifr.ifr_ifru.ifru_buffer.buffer = NULL;
243686d2ef16SBrooks Davis }
243786d2ef16SBrooks Davis 
24388ad798aeSBrooks Davis size_t
24398a4a4a43SBrooks Davis ifr_buffer_get_length(void *data)
244086d2ef16SBrooks Davis {
244186d2ef16SBrooks Davis 	union ifreq_union *ifrup;
244286d2ef16SBrooks Davis 
244386d2ef16SBrooks Davis 	ifrup = data;
244486d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24458a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
244686d2ef16SBrooks Davis 		return (ifrup->ifr32.ifr_ifru.ifru_buffer.length);
244786d2ef16SBrooks Davis #endif
244886d2ef16SBrooks Davis 	return (ifrup->ifr.ifr_ifru.ifru_buffer.length);
244986d2ef16SBrooks Davis }
245086d2ef16SBrooks Davis 
245186d2ef16SBrooks Davis static void
24528a4a4a43SBrooks Davis ifr_buffer_set_length(void *data, size_t len)
245386d2ef16SBrooks Davis {
245486d2ef16SBrooks Davis 	union ifreq_union *ifrup;
245586d2ef16SBrooks Davis 
245686d2ef16SBrooks Davis 	ifrup = data;
245786d2ef16SBrooks Davis #ifdef COMPAT_FREEBSD32
24588a4a4a43SBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
245986d2ef16SBrooks Davis 		ifrup->ifr32.ifr_ifru.ifru_buffer.length = len;
246086d2ef16SBrooks Davis 	else
246186d2ef16SBrooks Davis #endif
246286d2ef16SBrooks Davis 		ifrup->ifr.ifr_ifru.ifru_buffer.length = len;
246386d2ef16SBrooks Davis }
246486d2ef16SBrooks Davis 
2465541d96aaSBrooks Davis void *
2466541d96aaSBrooks Davis ifr_data_get_ptr(void *ifrp)
2467541d96aaSBrooks Davis {
2468541d96aaSBrooks Davis 	union ifreq_union *ifrup;
2469541d96aaSBrooks Davis 
2470541d96aaSBrooks Davis 	ifrup = ifrp;
2471541d96aaSBrooks Davis #ifdef COMPAT_FREEBSD32
2472541d96aaSBrooks Davis 	if (SV_CURPROC_FLAG(SV_ILP32))
2473541d96aaSBrooks Davis 		return ((void *)(uintptr_t)
2474541d96aaSBrooks Davis 		    ifrup->ifr32.ifr_ifru.ifru_data);
2475541d96aaSBrooks Davis #endif
2476541d96aaSBrooks Davis 		return (ifrup->ifr.ifr_ifru.ifru_data);
2477541d96aaSBrooks Davis }
2478541d96aaSBrooks Davis 
247982cd038dSYoshinobu Inoue /*
2480f13ad206SJonathan Lemon  * Hardware specific interface ioctls.
2481df8bae1dSRodney W. Grimes  */
24821687b1abSMichael Tuexen int
2483f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
2484df8bae1dSRodney W. Grimes {
2485f13ad206SJonathan Lemon 	struct ifreq *ifr;
2486cc5bb78bSSepherosa Ziehau 	int error = 0, do_ifup = 0;
2487292ee7beSRobert Watson 	int new_flags, temp_flags;
248836c19a57SBrooks Davis 	size_t namelen, onamelen;
2489215940b3SXin LI 	size_t descrlen;
2490215940b3SXin LI 	char *descrbuf, *odescrbuf;
249136c19a57SBrooks Davis 	char new_name[IFNAMSIZ];
249236c19a57SBrooks Davis 	struct ifaddr *ifa;
249336c19a57SBrooks Davis 	struct sockaddr_dl *sdl;
2494df8bae1dSRodney W. Grimes 
2495df8bae1dSRodney W. Grimes 	ifr = (struct ifreq *)data;
249630aad87dSBrooks Davis 	switch (cmd) {
2497de593450SJonathan Lemon 	case SIOCGIFINDEX:
2498de593450SJonathan Lemon 		ifr->ifr_index = ifp->if_index;
2499de593450SJonathan Lemon 		break;
2500de593450SJonathan Lemon 
2501df8bae1dSRodney W. Grimes 	case SIOCGIFFLAGS:
2502292ee7beSRobert Watson 		temp_flags = ifp->if_flags | ifp->if_drv_flags;
2503292ee7beSRobert Watson 		ifr->ifr_flags = temp_flags & 0xffff;
2504292ee7beSRobert Watson 		ifr->ifr_flagshigh = temp_flags >> 16;
2505df8bae1dSRodney W. Grimes 		break;
2506df8bae1dSRodney W. Grimes 
2507016da741SJonathan Lemon 	case SIOCGIFCAP:
2508016da741SJonathan Lemon 		ifr->ifr_reqcap = ifp->if_capabilities;
2509016da741SJonathan Lemon 		ifr->ifr_curcap = ifp->if_capenable;
2510016da741SJonathan Lemon 		break;
2511016da741SJonathan Lemon 
2512c1aedfcbSEd Maste 	case SIOCGIFDATA:
2513c1aedfcbSEd Maste 	{
2514c1aedfcbSEd Maste 		struct if_data ifd;
2515c1aedfcbSEd Maste 
2516c1aedfcbSEd Maste 		/* Ensure uninitialised padding is not leaked. */
2517c1aedfcbSEd Maste 		memset(&ifd, 0, sizeof(ifd));
2518c1aedfcbSEd Maste 
2519c1aedfcbSEd Maste 		if_data_copy(ifp, &ifd);
2520c1aedfcbSEd Maste 		error = copyout(&ifd, ifr_data_get_ptr(ifr), sizeof(ifd));
2521c1aedfcbSEd Maste 		break;
2522c1aedfcbSEd Maste 	}
2523c1aedfcbSEd Maste 
25248f293a63SRobert Watson #ifdef MAC
25258f293a63SRobert Watson 	case SIOCGIFMAC:
252630d239bcSRobert Watson 		error = mac_ifnet_ioctl_get(td->td_ucred, ifr, ifp);
25278f293a63SRobert Watson 		break;
25288f293a63SRobert Watson #endif
25298f293a63SRobert Watson 
2530df8bae1dSRodney W. Grimes 	case SIOCGIFMETRIC:
2531df8bae1dSRodney W. Grimes 		ifr->ifr_metric = ifp->if_metric;
2532df8bae1dSRodney W. Grimes 		break;
2533df8bae1dSRodney W. Grimes 
2534a7028af7SDavid Greenman 	case SIOCGIFMTU:
2535a7028af7SDavid Greenman 		ifr->ifr_mtu = ifp->if_mtu;
2536a7028af7SDavid Greenman 		break;
2537a7028af7SDavid Greenman 
2538074c4a4eSGarrett Wollman 	case SIOCGIFPHYS:
2539e6485f73SGleb Smirnoff 		/* XXXGL: did this ever worked? */
2540e6485f73SGleb Smirnoff 		ifr->ifr_phys = 0;
2541074c4a4eSGarrett Wollman 		break;
2542074c4a4eSGarrett Wollman 
2543215940b3SXin LI 	case SIOCGIFDESCR:
2544215940b3SXin LI 		error = 0;
2545215940b3SXin LI 		sx_slock(&ifdescr_sx);
254657d84848SXin LI 		if (ifp->if_description == NULL)
2547215940b3SXin LI 			error = ENOMSG;
254857d84848SXin LI 		else {
2549215940b3SXin LI 			/* space for terminating nul */
2550215940b3SXin LI 			descrlen = strlen(ifp->if_description) + 1;
25518a4a4a43SBrooks Davis 			if (ifr_buffer_get_length(ifr) < descrlen)
25528a4a4a43SBrooks Davis 				ifr_buffer_set_buffer_null(ifr);
2553215940b3SXin LI 			else
2554215940b3SXin LI 				error = copyout(ifp->if_description,
25558a4a4a43SBrooks Davis 				    ifr_buffer_get_buffer(ifr), descrlen);
25568a4a4a43SBrooks Davis 			ifr_buffer_set_length(ifr, descrlen);
2557215940b3SXin LI 		}
2558215940b3SXin LI 		sx_sunlock(&ifdescr_sx);
2559215940b3SXin LI 		break;
2560215940b3SXin LI 
2561215940b3SXin LI 	case SIOCSIFDESCR:
2562215940b3SXin LI 		error = priv_check(td, PRIV_NET_SETIFDESCR);
2563215940b3SXin LI 		if (error)
2564215940b3SXin LI 			return (error);
2565215940b3SXin LI 
2566215940b3SXin LI 		/*
2567215940b3SXin LI 		 * Copy only (length-1) bytes to make sure that
2568215940b3SXin LI 		 * if_description is always nul terminated.  The
2569215940b3SXin LI 		 * length parameter is supposed to count the
2570215940b3SXin LI 		 * terminating nul in.
2571215940b3SXin LI 		 */
25728a4a4a43SBrooks Davis 		if (ifr_buffer_get_length(ifr) > ifdescr_maxlen)
2573215940b3SXin LI 			return (ENAMETOOLONG);
25748a4a4a43SBrooks Davis 		else if (ifr_buffer_get_length(ifr) == 0)
2575215940b3SXin LI 			descrbuf = NULL;
2576215940b3SXin LI 		else {
25778a4a4a43SBrooks Davis 			descrbuf = malloc(ifr_buffer_get_length(ifr),
257886d2ef16SBrooks Davis 			    M_IFDESCR, M_WAITOK | M_ZERO);
25798a4a4a43SBrooks Davis 			error = copyin(ifr_buffer_get_buffer(ifr), descrbuf,
25808a4a4a43SBrooks Davis 			    ifr_buffer_get_length(ifr) - 1);
2581215940b3SXin LI 			if (error) {
2582215940b3SXin LI 				free(descrbuf, M_IFDESCR);
2583215940b3SXin LI 				break;
2584215940b3SXin LI 			}
2585215940b3SXin LI 		}
2586215940b3SXin LI 
2587215940b3SXin LI 		sx_xlock(&ifdescr_sx);
2588215940b3SXin LI 		odescrbuf = ifp->if_description;
2589215940b3SXin LI 		ifp->if_description = descrbuf;
2590215940b3SXin LI 		sx_xunlock(&ifdescr_sx);
2591215940b3SXin LI 
2592215940b3SXin LI 		getmicrotime(&ifp->if_lastchange);
2593215940b3SXin LI 		free(odescrbuf, M_IFDESCR);
2594215940b3SXin LI 		break;
2595215940b3SXin LI 
259635fd7bc0SBjoern A. Zeeb 	case SIOCGIFFIB:
259735fd7bc0SBjoern A. Zeeb 		ifr->ifr_fib = ifp->if_fib;
259835fd7bc0SBjoern A. Zeeb 		break;
259935fd7bc0SBjoern A. Zeeb 
260035fd7bc0SBjoern A. Zeeb 	case SIOCSIFFIB:
260135fd7bc0SBjoern A. Zeeb 		error = priv_check(td, PRIV_NET_SETIFFIB);
260235fd7bc0SBjoern A. Zeeb 		if (error)
260335fd7bc0SBjoern A. Zeeb 			return (error);
260435fd7bc0SBjoern A. Zeeb 		if (ifr->ifr_fib >= rt_numfibs)
260535fd7bc0SBjoern A. Zeeb 			return (EINVAL);
260635fd7bc0SBjoern A. Zeeb 
260735fd7bc0SBjoern A. Zeeb 		ifp->if_fib = ifr->ifr_fib;
260835fd7bc0SBjoern A. Zeeb 		break;
260935fd7bc0SBjoern A. Zeeb 
2610df8bae1dSRodney W. Grimes 	case SIOCSIFFLAGS:
2611acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFFLAGS);
26129448326fSPoul-Henning Kamp 		if (error)
2613df8bae1dSRodney W. Grimes 			return (error);
2614292ee7beSRobert Watson 		/*
2615292ee7beSRobert Watson 		 * Currently, no driver owned flags pass the IFF_CANTCHANGE
2616292ee7beSRobert Watson 		 * check, so we don't need special handling here yet.
2617292ee7beSRobert Watson 		 */
261862f76486SMaxim Sobolev 		new_flags = (ifr->ifr_flags & 0xffff) |
261962f76486SMaxim Sobolev 		    (ifr->ifr_flagshigh << 16);
2620af50ea38SGleb Smirnoff 		if (ifp->if_flags & IFF_UP &&
262162f76486SMaxim Sobolev 		    (new_flags & IFF_UP) == 0) {
2622df8bae1dSRodney W. Grimes 			if_down(ifp);
262362f76486SMaxim Sobolev 		} else if (new_flags & IFF_UP &&
2624cf4b9371SPoul-Henning Kamp 		    (ifp->if_flags & IFF_UP) == 0) {
2625cc5bb78bSSepherosa Ziehau 			do_ifup = 1;
2626df8bae1dSRodney W. Grimes 		}
26277aebc5e8SYaroslav Tykhiy 		/* See if permanently promiscuous mode bit is about to flip */
26287aebc5e8SYaroslav Tykhiy 		if ((ifp->if_flags ^ new_flags) & IFF_PPROMISC) {
26297aebc5e8SYaroslav Tykhiy 			if (new_flags & IFF_PPROMISC)
26307aebc5e8SYaroslav Tykhiy 				ifp->if_flags |= IFF_PROMISC;
26317aebc5e8SYaroslav Tykhiy 			else if (ifp->if_pcount == 0)
26327aebc5e8SYaroslav Tykhiy 				ifp->if_flags &= ~IFF_PROMISC;
26336d07c157SNick Hibma 			if (log_promisc_mode_change)
263420f8d7bcSDag-Erling Smørgrav                                 if_printf(ifp, "permanently promiscuous mode %s\n",
26356d07c157SNick Hibma                                     ((new_flags & IFF_PPROMISC) ?
26366d07c157SNick Hibma                                      "enabled" : "disabled"));
26377aebc5e8SYaroslav Tykhiy 		}
2638df8bae1dSRodney W. Grimes 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
263962f76486SMaxim Sobolev 			(new_flags &~ IFF_CANTCHANGE);
264031302ebfSRobert Watson 		if (ifp->if_ioctl) {
2641df8bae1dSRodney W. Grimes 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
264231302ebfSRobert Watson 		}
2643cc5bb78bSSepherosa Ziehau 		if (do_ifup)
2644cc5bb78bSSepherosa Ziehau 			if_up(ifp);
264598b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
2646df8bae1dSRodney W. Grimes 		break;
2647df8bae1dSRodney W. Grimes 
2648016da741SJonathan Lemon 	case SIOCSIFCAP:
2649acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFCAP);
2650016da741SJonathan Lemon 		if (error)
2651016da741SJonathan Lemon 			return (error);
2652efb4018bSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
2653efb4018bSYaroslav Tykhiy 			return (EOPNOTSUPP);
2654016da741SJonathan Lemon 		if (ifr->ifr_reqcap & ~ifp->if_capabilities)
2655016da741SJonathan Lemon 			return (EINVAL);
2656efb4018bSYaroslav Tykhiy 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2657efb4018bSYaroslav Tykhiy 		if (error == 0)
2658efb4018bSYaroslav Tykhiy 			getmicrotime(&ifp->if_lastchange);
2659016da741SJonathan Lemon 		break;
2660016da741SJonathan Lemon 
26618f293a63SRobert Watson #ifdef MAC
26628f293a63SRobert Watson 	case SIOCSIFMAC:
266330d239bcSRobert Watson 		error = mac_ifnet_ioctl_set(td->td_ucred, ifr, ifp);
26648f293a63SRobert Watson 		break;
26658f293a63SRobert Watson #endif
26668f293a63SRobert Watson 
266736c19a57SBrooks Davis 	case SIOCSIFNAME:
2668acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFNAME);
2669acd3428bSRobert Watson 		if (error)
267036c19a57SBrooks Davis 			return (error);
2671541d96aaSBrooks Davis 		error = copyinstr(ifr_data_get_ptr(ifr), new_name, IFNAMSIZ,
2672541d96aaSBrooks Davis 		    NULL);
2673bc1470f1SBrooks Davis 		if (error != 0)
267436c19a57SBrooks Davis 			return (error);
2675bc1470f1SBrooks Davis 		if (new_name[0] == '\0')
2676bc1470f1SBrooks Davis 			return (EINVAL);
26771ef3d54dSDon Lewis 		if (new_name[IFNAMSIZ-1] != '\0') {
26781ef3d54dSDon Lewis 			new_name[IFNAMSIZ-1] = '\0';
26791ef3d54dSDon Lewis 			if (strlen(new_name) == IFNAMSIZ-1)
26801ef3d54dSDon Lewis 				return (EINVAL);
26811ef3d54dSDon Lewis 		}
268240b1c921SKyle Evans 		if (strcmp(new_name, ifp->if_xname) == 0)
268340b1c921SKyle Evans 			break;
268436c19a57SBrooks Davis 		if (ifunit(new_name) != NULL)
268536c19a57SBrooks Davis 			return (EEXIST);
268636c19a57SBrooks Davis 
26875428776eSJohn Baldwin 		/*
26885428776eSJohn Baldwin 		 * XXX: Locking.  Nothing else seems to lock if_flags,
26895428776eSJohn Baldwin 		 * and there are numerous other races with the
26905428776eSJohn Baldwin 		 * ifunit() checks not being atomic with namespace
26915428776eSJohn Baldwin 		 * changes (renames, vmoves, if_attach, etc).
26925428776eSJohn Baldwin 		 */
26935428776eSJohn Baldwin 		ifp->if_flags |= IFF_RENAMING;
26945428776eSJohn Baldwin 
269536c19a57SBrooks Davis 		/* Announce the departure of the interface. */
269636c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
269752023244SMax Laier 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
269836c19a57SBrooks Davis 
269920f8d7bcSDag-Erling Smørgrav 		if_printf(ifp, "changing name to '%s'\n", new_name);
270071672bb6SBrooks Davis 
270167420bdaSGleb Smirnoff 		IF_ADDR_WLOCK(ifp);
270236c19a57SBrooks Davis 		strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
27034a0d6638SRuslan Ermilov 		ifa = ifp->if_addr;
270436c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
270536c19a57SBrooks Davis 		namelen = strlen(new_name);
270636c19a57SBrooks Davis 		onamelen = sdl->sdl_nlen;
270736c19a57SBrooks Davis 		/*
270836c19a57SBrooks Davis 		 * Move the address if needed.  This is safe because we
270936c19a57SBrooks Davis 		 * allocate space for a name of length IFNAMSIZ when we
271036c19a57SBrooks Davis 		 * create this in if_attach().
271136c19a57SBrooks Davis 		 */
271236c19a57SBrooks Davis 		if (namelen != onamelen) {
271336c19a57SBrooks Davis 			bcopy(sdl->sdl_data + onamelen,
271436c19a57SBrooks Davis 			    sdl->sdl_data + namelen, sdl->sdl_alen);
271536c19a57SBrooks Davis 		}
271636c19a57SBrooks Davis 		bcopy(new_name, sdl->sdl_data, namelen);
271736c19a57SBrooks Davis 		sdl->sdl_nlen = namelen;
271836c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_netmask;
271936c19a57SBrooks Davis 		bzero(sdl->sdl_data, onamelen);
272036c19a57SBrooks Davis 		while (namelen != 0)
272136c19a57SBrooks Davis 			sdl->sdl_data[--namelen] = 0xff;
272267420bdaSGleb Smirnoff 		IF_ADDR_WUNLOCK(ifp);
272336c19a57SBrooks Davis 
272425a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
272536c19a57SBrooks Davis 		/* Announce the return of the interface. */
272636c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
27275428776eSJohn Baldwin 
27285428776eSJohn Baldwin 		ifp->if_flags &= ~IFF_RENAMING;
272936c19a57SBrooks Davis 		break;
273036c19a57SBrooks Davis 
2731679e1390SJamie Gritton #ifdef VIMAGE
2732679e1390SJamie Gritton 	case SIOCSIFVNET:
2733679e1390SJamie Gritton 		error = priv_check(td, PRIV_NET_SETIFVNET);
2734679e1390SJamie Gritton 		if (error)
2735679e1390SJamie Gritton 			return (error);
2736be31e5e7SBjoern A. Zeeb 		error = if_vmove_loan(td, ifp, ifr->ifr_name, ifr->ifr_jid);
2737679e1390SJamie Gritton 		break;
2738679e1390SJamie Gritton #endif
2739679e1390SJamie Gritton 
2740df8bae1dSRodney W. Grimes 	case SIOCSIFMETRIC:
2741acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFMETRIC);
27429448326fSPoul-Henning Kamp 		if (error)
2743df8bae1dSRodney W. Grimes 			return (error);
2744df8bae1dSRodney W. Grimes 		ifp->if_metric = ifr->ifr_metric;
274598b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
2746df8bae1dSRodney W. Grimes 		break;
2747df8bae1dSRodney W. Grimes 
2748074c4a4eSGarrett Wollman 	case SIOCSIFPHYS:
2749acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFPHYS);
2750e39a0280SGary Palmer 		if (error)
2751913e410eSYaroslav Tykhiy 			return (error);
2752913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
2753913e410eSYaroslav Tykhiy 			return (EOPNOTSUPP);
2754e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2755e39a0280SGary Palmer 		if (error == 0)
275698b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
2757913e410eSYaroslav Tykhiy 		break;
2758074c4a4eSGarrett Wollman 
2759a7028af7SDavid Greenman 	case SIOCSIFMTU:
276082cd038dSYoshinobu Inoue 	{
276182cd038dSYoshinobu Inoue 		u_long oldmtu = ifp->if_mtu;
276282cd038dSYoshinobu Inoue 
2763acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETIFMTU);
27649448326fSPoul-Henning Kamp 		if (error)
2765a7028af7SDavid Greenman 			return (error);
2766aab3beeeSBrian Somers 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
276775ee03cbSDavid Greenman 			return (EINVAL);
2768f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
2769f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
2770e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
277148f71763SRuslan Ermilov 		if (error == 0) {
277298b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
277348f71763SRuslan Ermilov 			rt_ifmsg(ifp);
2774e5054602SMark Johnston #ifdef INET
27757790c8c1SConrad Meyer 			DEBUGNET_NOTIFY_MTU(ifp);
2776e5054602SMark Johnston #endif
277748f71763SRuslan Ermilov 		}
277882cd038dSYoshinobu Inoue 		/*
277982cd038dSYoshinobu Inoue 		 * If the link MTU changed, do network layer specific procedure.
278082cd038dSYoshinobu Inoue 		 */
278182cd038dSYoshinobu Inoue 		if (ifp->if_mtu != oldmtu) {
278282cd038dSYoshinobu Inoue #ifdef INET6
278382cd038dSYoshinobu Inoue 			nd6_setmtu(ifp);
278482cd038dSYoshinobu Inoue #endif
27857f948f12SAlexander V. Chernikov 			rt_updatemtu(ifp);
278682cd038dSYoshinobu Inoue 		}
2787f13ad206SJonathan Lemon 		break;
278882cd038dSYoshinobu Inoue 	}
2789a7028af7SDavid Greenman 
2790df8bae1dSRodney W. Grimes 	case SIOCADDMULTI:
2791df8bae1dSRodney W. Grimes 	case SIOCDELMULTI:
2792acd3428bSRobert Watson 		if (cmd == SIOCADDMULTI)
2793acd3428bSRobert Watson 			error = priv_check(td, PRIV_NET_ADDMULTI);
2794acd3428bSRobert Watson 		else
2795acd3428bSRobert Watson 			error = priv_check(td, PRIV_NET_DELMULTI);
27969448326fSPoul-Henning Kamp 		if (error)
2797df8bae1dSRodney W. Grimes 			return (error);
2798477180fbSGarrett Wollman 
2799477180fbSGarrett Wollman 		/* Don't allow group membership on non-multicast interfaces. */
2800477180fbSGarrett Wollman 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
2801f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
2802477180fbSGarrett Wollman 
2803477180fbSGarrett Wollman 		/* Don't let users screw up protocols' entries. */
2804477180fbSGarrett Wollman 		if (ifr->ifr_addr.sa_family != AF_LINK)
2805f13ad206SJonathan Lemon 			return (EINVAL);
2806477180fbSGarrett Wollman 
2807477180fbSGarrett Wollman 		if (cmd == SIOCADDMULTI) {
2808a68cc388SGleb Smirnoff 			struct epoch_tracker et;
2809477180fbSGarrett Wollman 			struct ifmultiaddr *ifma;
2810ec002feeSBruce M Simpson 
2811ec002feeSBruce M Simpson 			/*
2812ec002feeSBruce M Simpson 			 * Userland is only permitted to join groups once
2813ec002feeSBruce M Simpson 			 * via the if_addmulti() KPI, because it cannot hold
2814ec002feeSBruce M Simpson 			 * struct ifmultiaddr * between calls. It may also
2815ec002feeSBruce M Simpson 			 * lose a race while we check if the membership
2816ec002feeSBruce M Simpson 			 * already exists.
2817ec002feeSBruce M Simpson 			 */
2818a68cc388SGleb Smirnoff 			NET_EPOCH_ENTER(et);
2819ec002feeSBruce M Simpson 			ifma = if_findmulti(ifp, &ifr->ifr_addr);
2820a68cc388SGleb Smirnoff 			NET_EPOCH_EXIT(et);
2821ec002feeSBruce M Simpson 			if (ifma != NULL)
2822ec002feeSBruce M Simpson 				error = EADDRINUSE;
2823ec002feeSBruce M Simpson 			else
2824477180fbSGarrett Wollman 				error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
2825477180fbSGarrett Wollman 		} else {
2826477180fbSGarrett Wollman 			error = if_delmulti(ifp, &ifr->ifr_addr);
2827477180fbSGarrett Wollman 		}
2828e39a0280SGary Palmer 		if (error == 0)
282998b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
2830f13ad206SJonathan Lemon 		break;
2831df8bae1dSRodney W. Grimes 
283241b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR:
283341b3e8e5SJun-ichiro itojun Hagino 	case SIOCDIFPHYADDR:
283441b3e8e5SJun-ichiro itojun Hagino #ifdef INET6
283541b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR_IN6:
283641b3e8e5SJun-ichiro itojun Hagino #endif
2837a912e453SPeter Wemm 	case SIOCSIFMEDIA:
2838d7189ec6SJoerg Wunsch 	case SIOCSIFGENERIC:
2839acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_HWIOCTL);
2840a912e453SPeter Wemm 		if (error)
2841a912e453SPeter Wemm 			return (error);
2842f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
2843a912e453SPeter Wemm 			return (EOPNOTSUPP);
2844a912e453SPeter Wemm 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2845a912e453SPeter Wemm 		if (error == 0)
284698b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
2847f13ad206SJonathan Lemon 		break;
2848a912e453SPeter Wemm 
2849413dd0baSPoul-Henning Kamp 	case SIOCGIFSTATUS:
285033841545SHajimu UMEMOTO 	case SIOCGIFPSRCADDR:
285133841545SHajimu UMEMOTO 	case SIOCGIFPDSTADDR:
2852a912e453SPeter Wemm 	case SIOCGIFMEDIA:
2853eb7e25b2SEric Joyner 	case SIOCGIFXMEDIA:
2854d7189ec6SJoerg Wunsch 	case SIOCGIFGENERIC:
28550f3af041SSepherosa Ziehau 	case SIOCGIFRSSKEY:
28560f3af041SSepherosa Ziehau 	case SIOCGIFRSSHASH:
2857247cf566SKonstantin Belousov 	case SIOCGIFDOWNREASON:
2858913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
2859a912e453SPeter Wemm 			return (EOPNOTSUPP);
2860f13ad206SJonathan Lemon 		error = (*ifp->if_ioctl)(ifp, cmd, data);
2861f13ad206SJonathan Lemon 		break;
2862a912e453SPeter Wemm 
2863b106252cSBill Paul 	case SIOCSIFLLADDR:
2864acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_SETLLADDR);
2865b106252cSBill Paul 		if (error)
2866b106252cSBill Paul 			return (error);
2867f13ad206SJonathan Lemon 		error = if_setlladdr(ifp,
286866ce51ceSArchie Cobbs 		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
2869f13ad206SJonathan Lemon 		break;
287066ce51ceSArchie Cobbs 
2871ddae5750SRavi Pokala 	case SIOCGHWADDR:
2872ddae5750SRavi Pokala 		error = if_gethwaddr(ifp, ifr);
2873ddae5750SRavi Pokala 		break;
2874ddae5750SRavi Pokala 
2875bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCAIFGROUP):
2876acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_ADDIFGROUP);
28770dad3f0eSMax Laier 		if (error)
28780dad3f0eSMax Laier 			return (error);
2879756181b8SBrooks Davis 		if ((error = if_addgroup(ifp,
2880756181b8SBrooks Davis 		    ifgr_group_get((struct ifgroupreq *)data))))
28810dad3f0eSMax Laier 			return (error);
28820dad3f0eSMax Laier 		break;
28830dad3f0eSMax Laier 
2884bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCGIFGROUP):
2885b8a6e03fSGleb Smirnoff 	{
2886b8a6e03fSGleb Smirnoff 		struct epoch_tracker et;
2887b8a6e03fSGleb Smirnoff 
2888b8a6e03fSGleb Smirnoff 		NET_EPOCH_ENTER(et);
2889b8a6e03fSGleb Smirnoff 		error = if_getgroup((struct ifgroupreq *)data, ifp);
2890b8a6e03fSGleb Smirnoff 		NET_EPOCH_EXIT(et);
2891756181b8SBrooks Davis 		break;
2892b8a6e03fSGleb Smirnoff 	}
28930dad3f0eSMax Laier 
2894bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCDIFGROUP):
2895acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_DELIFGROUP);
28960dad3f0eSMax Laier 		if (error)
28970dad3f0eSMax Laier 			return (error);
2898756181b8SBrooks Davis 		if ((error = if_delgroup(ifp,
2899756181b8SBrooks Davis 		    ifgr_group_get((struct ifgroupreq *)data))))
29000dad3f0eSMax Laier 			return (error);
29010dad3f0eSMax Laier 		break;
29020dad3f0eSMax Laier 
2903df8bae1dSRodney W. Grimes 	default:
2904f13ad206SJonathan Lemon 		error = ENOIOCTL;
2905f13ad206SJonathan Lemon 		break;
2906f13ad206SJonathan Lemon 	}
2907f13ad206SJonathan Lemon 	return (error);
2908f13ad206SJonathan Lemon }
2909f13ad206SJonathan Lemon 
29109af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32
29119af74f3dSSergey Kandaurov struct ifconf32 {
29129af74f3dSSergey Kandaurov 	int32_t	ifc_len;
29139af74f3dSSergey Kandaurov 	union {
29149af74f3dSSergey Kandaurov 		uint32_t	ifcu_buf;
29159af74f3dSSergey Kandaurov 		uint32_t	ifcu_req;
29169af74f3dSSergey Kandaurov 	} ifc_ifcu;
29179af74f3dSSergey Kandaurov };
29189af74f3dSSergey Kandaurov #define	SIOCGIFCONF32	_IOWR('i', 36, struct ifconf32)
29199af74f3dSSergey Kandaurov #endif
29209af74f3dSSergey Kandaurov 
29213edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
29223edb7f4eSBrooks Davis static void
29233edb7f4eSBrooks Davis ifmr_init(struct ifmediareq *ifmr, caddr_t data)
29243edb7f4eSBrooks Davis {
29253edb7f4eSBrooks Davis 	struct ifmediareq32 *ifmr32;
29263edb7f4eSBrooks Davis 
29273edb7f4eSBrooks Davis 	ifmr32 = (struct ifmediareq32 *)data;
29283edb7f4eSBrooks Davis 	memcpy(ifmr->ifm_name, ifmr32->ifm_name,
29293edb7f4eSBrooks Davis 	    sizeof(ifmr->ifm_name));
29303edb7f4eSBrooks Davis 	ifmr->ifm_current = ifmr32->ifm_current;
29313edb7f4eSBrooks Davis 	ifmr->ifm_mask = ifmr32->ifm_mask;
29323edb7f4eSBrooks Davis 	ifmr->ifm_status = ifmr32->ifm_status;
29333edb7f4eSBrooks Davis 	ifmr->ifm_active = ifmr32->ifm_active;
29343edb7f4eSBrooks Davis 	ifmr->ifm_count = ifmr32->ifm_count;
29353edb7f4eSBrooks Davis 	ifmr->ifm_ulist = (int *)(uintptr_t)ifmr32->ifm_ulist;
29363edb7f4eSBrooks Davis }
29373edb7f4eSBrooks Davis 
29383edb7f4eSBrooks Davis static void
29393edb7f4eSBrooks Davis ifmr_update(const struct ifmediareq *ifmr, caddr_t data)
29403edb7f4eSBrooks Davis {
29413edb7f4eSBrooks Davis 	struct ifmediareq32 *ifmr32;
29423edb7f4eSBrooks Davis 
29433edb7f4eSBrooks Davis 	ifmr32 = (struct ifmediareq32 *)data;
29443edb7f4eSBrooks Davis 	ifmr32->ifm_current = ifmr->ifm_current;
29453edb7f4eSBrooks Davis 	ifmr32->ifm_mask = ifmr->ifm_mask;
29463edb7f4eSBrooks Davis 	ifmr32->ifm_status = ifmr->ifm_status;
29473edb7f4eSBrooks Davis 	ifmr32->ifm_active = ifmr->ifm_active;
29483edb7f4eSBrooks Davis 	ifmr32->ifm_count = ifmr->ifm_count;
29493edb7f4eSBrooks Davis }
29503edb7f4eSBrooks Davis #endif
29513edb7f4eSBrooks Davis 
2952f13ad206SJonathan Lemon /*
2953f13ad206SJonathan Lemon  * Interface ioctls.
2954f13ad206SJonathan Lemon  */
2955f13ad206SJonathan Lemon int
295672fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
2957f13ad206SJonathan Lemon {
29583edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
2959f6cb0deaSMatt Macy 	caddr_t saved_data = NULL;
29603edb7f4eSBrooks Davis 	struct ifmediareq ifmr;
2961b8a6e03fSGleb Smirnoff 	struct ifmediareq *ifmrp = NULL;
29622da19677SSean Bruno #endif
2963f13ad206SJonathan Lemon 	struct ifnet *ifp;
2964f13ad206SJonathan Lemon 	struct ifreq *ifr;
2965f13ad206SJonathan Lemon 	int error;
296662f76486SMaxim Sobolev 	int oif_flags;
296710108cb6SBjoern A. Zeeb #ifdef VIMAGE
296810108cb6SBjoern A. Zeeb 	bool shutdown;
296910108cb6SBjoern A. Zeeb #endif
2970f13ad206SJonathan Lemon 
2971*27457983SMark Johnston 	/*
2972*27457983SMark Johnston 	 * Interface ioctls access a global namespace.  There is currently no
2973*27457983SMark Johnston 	 * capability-based representation for interfaces, so the configuration
2974*27457983SMark Johnston 	 * interface is simply unaccessible from capability mode.  If necessary,
2975*27457983SMark Johnston 	 * select ioctls may be permitted here.
2976*27457983SMark Johnston 	 */
2977*27457983SMark Johnston 	if (IN_CAPABILITY_MODE(td))
2978*27457983SMark Johnston 		return (ECAPMODE);
2979*27457983SMark Johnston 
29801fb51a12SBjoern A. Zeeb 	CURVNET_SET(so->so_vnet);
298189856f7eSBjoern A. Zeeb #ifdef VIMAGE
298289856f7eSBjoern A. Zeeb 	/* Make sure the VNET is stable. */
298310108cb6SBjoern A. Zeeb 	shutdown = VNET_IS_SHUTTING_DOWN(so->so_vnet);
298410108cb6SBjoern A. Zeeb 	if (shutdown) {
298589856f7eSBjoern A. Zeeb 		CURVNET_RESTORE();
298689856f7eSBjoern A. Zeeb 		return (EBUSY);
298789856f7eSBjoern A. Zeeb 	}
298889856f7eSBjoern A. Zeeb #endif
298989856f7eSBjoern A. Zeeb 
2990f13ad206SJonathan Lemon 	switch (cmd) {
2991f13ad206SJonathan Lemon 	case SIOCGIFCONF:
29921fb51a12SBjoern A. Zeeb 		error = ifconf(cmd, data);
2993b8a6e03fSGleb Smirnoff 		goto out_noref;
29949af74f3dSSergey Kandaurov 
29959af74f3dSSergey Kandaurov #ifdef COMPAT_FREEBSD32
29969af74f3dSSergey Kandaurov 	case SIOCGIFCONF32:
29979af74f3dSSergey Kandaurov 		{
29989af74f3dSSergey Kandaurov 			struct ifconf32 *ifc32;
29999af74f3dSSergey Kandaurov 			struct ifconf ifc;
30009af74f3dSSergey Kandaurov 
30019af74f3dSSergey Kandaurov 			ifc32 = (struct ifconf32 *)data;
30029af74f3dSSergey Kandaurov 			ifc.ifc_len = ifc32->ifc_len;
30039af74f3dSSergey Kandaurov 			ifc.ifc_buf = PTRIN(ifc32->ifc_buf);
30049af74f3dSSergey Kandaurov 
30051fb51a12SBjoern A. Zeeb 			error = ifconf(SIOCGIFCONF, (void *)&ifc);
300623519598SSergey Kandaurov 			if (error == 0)
300723519598SSergey Kandaurov 				ifc32->ifc_len = ifc.ifc_len;
3008b8a6e03fSGleb Smirnoff 			goto out_noref;
30099af74f3dSSergey Kandaurov 		}
30109af74f3dSSergey Kandaurov #endif
3011f13ad206SJonathan Lemon 	}
3012f13ad206SJonathan Lemon 
30133edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
30143edb7f4eSBrooks Davis 	switch (cmd) {
30153edb7f4eSBrooks Davis 	case SIOCGIFMEDIA32:
30163edb7f4eSBrooks Davis 	case SIOCGIFXMEDIA32:
30173edb7f4eSBrooks Davis 		ifmrp = &ifmr;
30183edb7f4eSBrooks Davis 		ifmr_init(ifmrp, data);
30193edb7f4eSBrooks Davis 		cmd = _IOC_NEWTYPE(cmd, struct ifmediareq);
30203edb7f4eSBrooks Davis 		saved_data = data;
30213edb7f4eSBrooks Davis 		data = (caddr_t)ifmrp;
30223edb7f4eSBrooks Davis 	}
30233edb7f4eSBrooks Davis #endif
30243edb7f4eSBrooks Davis 
30253edb7f4eSBrooks Davis 	ifr = (struct ifreq *)data;
3026f13ad206SJonathan Lemon 	switch (cmd) {
3027feb08d06SMarko Zec #ifdef VIMAGE
3028679e1390SJamie Gritton 	case SIOCSIFRVNET:
3029679e1390SJamie Gritton 		error = priv_check(td, PRIV_NET_SETIFVNET);
30301fb51a12SBjoern A. Zeeb 		if (error == 0)
30311fb51a12SBjoern A. Zeeb 			error = if_vmove_reclaim(td, ifr->ifr_name,
30321fb51a12SBjoern A. Zeeb 			    ifr->ifr_jid);
30333edb7f4eSBrooks Davis 		goto out_noref;
3034feb08d06SMarko Zec #endif
3035f13ad206SJonathan Lemon 	case SIOCIFCREATE:
30366b7330e2SSam Leffler 	case SIOCIFCREATE2:
3037acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_IFCREATE);
30381fb51a12SBjoern A. Zeeb 		if (error == 0)
30391fb51a12SBjoern A. Zeeb 			error = if_clone_create(ifr->ifr_name,
3040541d96aaSBrooks Davis 			    sizeof(ifr->ifr_name), cmd == SIOCIFCREATE2 ?
3041541d96aaSBrooks Davis 			    ifr_data_get_ptr(ifr) : NULL);
30423edb7f4eSBrooks Davis 		goto out_noref;
3043f13ad206SJonathan Lemon 	case SIOCIFDESTROY:
3044acd3428bSRobert Watson 		error = priv_check(td, PRIV_NET_IFDESTROY);
3045e133271fSKristof Provost 
3046e133271fSKristof Provost 		if (error == 0) {
30476d2a10d9SKristof Provost 			sx_xlock(&ifnet_detach_sxlock);
30481fb51a12SBjoern A. Zeeb 			error = if_clone_destroy(ifr->ifr_name);
30496d2a10d9SKristof Provost 			sx_xunlock(&ifnet_detach_sxlock);
3050e133271fSKristof Provost 		}
30513edb7f4eSBrooks Davis 		goto out_noref;
3052f13ad206SJonathan Lemon 
3053f13ad206SJonathan Lemon 	case SIOCIFGCLONERS:
30541fb51a12SBjoern A. Zeeb 		error = if_clone_list((struct if_clonereq *)data);
30553edb7f4eSBrooks Davis 		goto out_noref;
30563edb7f4eSBrooks Davis 
3057bc6f170eSBrooks Davis 	case CASE_IOC_IFGROUPREQ(SIOCGIFGMEMB):
30581fb51a12SBjoern A. Zeeb 		error = if_getgroupmembers((struct ifgroupreq *)data);
30593edb7f4eSBrooks Davis 		goto out_noref;
30603edb7f4eSBrooks Davis 
306108b68b0eSGleb Smirnoff #if defined(INET) || defined(INET6)
306208b68b0eSGleb Smirnoff 	case SIOCSVH:
306308b68b0eSGleb Smirnoff 	case SIOCGVH:
306408b68b0eSGleb Smirnoff 		if (carp_ioctl_p == NULL)
306508b68b0eSGleb Smirnoff 			error = EPROTONOSUPPORT;
306608b68b0eSGleb Smirnoff 		else
306708b68b0eSGleb Smirnoff 			error = (*carp_ioctl_p)(ifr, cmd, td);
30683edb7f4eSBrooks Davis 		goto out_noref;
306908b68b0eSGleb Smirnoff #endif
3070f13ad206SJonathan Lemon 	}
3071f13ad206SJonathan Lemon 
30726064c5d3SRobert Watson 	ifp = ifunit_ref(ifr->ifr_name);
30731fb51a12SBjoern A. Zeeb 	if (ifp == NULL) {
30743edb7f4eSBrooks Davis 		error = ENXIO;
30753edb7f4eSBrooks Davis 		goto out_noref;
30761fb51a12SBjoern A. Zeeb 	}
3077f13ad206SJonathan Lemon 
3078f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
30793edb7f4eSBrooks Davis 	if (error != ENOIOCTL)
30803edb7f4eSBrooks Davis 		goto out_ref;
3081f13ad206SJonathan Lemon 
308282cd038dSYoshinobu Inoue 	oif_flags = ifp->if_flags;
30836064c5d3SRobert Watson 	if (so->so_proto == NULL) {
30843edb7f4eSBrooks Davis 		error = EOPNOTSUPP;
30853edb7f4eSBrooks Davis 		goto out_ref;
30866064c5d3SRobert Watson 	}
30871a05c762SDag-Erling Smørgrav 
30881a05c762SDag-Erling Smørgrav 	/*
30891a05c762SDag-Erling Smørgrav 	 * Pass the request on to the socket control method, and if the
30901a05c762SDag-Erling Smørgrav 	 * latter returns EOPNOTSUPP, directly to the interface.
30911a05c762SDag-Erling Smørgrav 	 *
30921a05c762SDag-Erling Smørgrav 	 * Make an exception for the legacy SIOCSIF* requests.  Drivers
30931a05c762SDag-Erling Smørgrav 	 * trust SIOCSIFADDR et al to come from an already privileged
30941a05c762SDag-Erling Smørgrav 	 * layer, and do not perform any credentials checks or input
30951a05c762SDag-Erling Smørgrav 	 * validation.
30961a05c762SDag-Erling Smørgrav 	 */
30975fb009bdSGleb Smirnoff 	error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd, data,
3098b40ce416SJulian Elischer 	    ifp, td));
30991a05c762SDag-Erling Smørgrav 	if (error == EOPNOTSUPP && ifp != NULL && ifp->if_ioctl != NULL &&
31001a05c762SDag-Erling Smørgrav 	    cmd != SIOCSIFADDR && cmd != SIOCSIFBRDADDR &&
31011a05c762SDag-Erling Smørgrav 	    cmd != SIOCSIFDSTADDR && cmd != SIOCSIFNETMASK)
3102bc3977f1SJamie Gritton 		error = (*ifp->if_ioctl)(ifp, cmd, data);
310382cd038dSYoshinobu Inoue 
310482cd038dSYoshinobu Inoue 	if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
310582cd038dSYoshinobu Inoue #ifdef INET6
3106c9b652e3SAndre Oppermann 		if (ifp->if_flags & IFF_UP)
310782cd038dSYoshinobu Inoue 			in6_if_up(ifp);
310882cd038dSYoshinobu Inoue #endif
3109df8bae1dSRodney W. Grimes 	}
31103edb7f4eSBrooks Davis 
31113edb7f4eSBrooks Davis out_ref:
31126064c5d3SRobert Watson 	if_rele(ifp);
31133edb7f4eSBrooks Davis out_noref:
31143edb7f4eSBrooks Davis #ifdef COMPAT_FREEBSD32
31153edb7f4eSBrooks Davis 	if (ifmrp != NULL) {
31163edb7f4eSBrooks Davis 		KASSERT((cmd == SIOCGIFMEDIA || cmd == SIOCGIFXMEDIA),
31173edb7f4eSBrooks Davis 		    ("ifmrp non-NULL, but cmd is not an ifmedia req 0x%lx",
31183edb7f4eSBrooks Davis 		     cmd));
31193edb7f4eSBrooks Davis 		data = saved_data;
31203edb7f4eSBrooks Davis 		ifmr_update(ifmrp, data);
31213edb7f4eSBrooks Davis 	}
31223edb7f4eSBrooks Davis #endif
31231fb51a12SBjoern A. Zeeb 	CURVNET_RESTORE();
3124df8bae1dSRodney W. Grimes 	return (error);
3125df8bae1dSRodney W. Grimes }
3126df8bae1dSRodney W. Grimes 
3127df8bae1dSRodney W. Grimes /*
3128292ee7beSRobert Watson  * The code common to handling reference counted flags,
31291a3b6859SYaroslav Tykhiy  * e.g., in ifpromisc() and if_allmulti().
3130b5c8bd59SYaroslav Tykhiy  * The "pflag" argument can specify a permanent mode flag to check,
31311a3b6859SYaroslav Tykhiy  * such as IFF_PPROMISC for promiscuous mode; should be 0 if none.
3132292ee7beSRobert Watson  *
3133292ee7beSRobert Watson  * Only to be used on stack-owned flags, not driver-owned flags.
31341a3b6859SYaroslav Tykhiy  */
31351a3b6859SYaroslav Tykhiy static int
31361a3b6859SYaroslav Tykhiy if_setflag(struct ifnet *ifp, int flag, int pflag, int *refcount, int onswitch)
31371a3b6859SYaroslav Tykhiy {
31381a3b6859SYaroslav Tykhiy 	struct ifreq ifr;
31391a3b6859SYaroslav Tykhiy 	int error;
31401a3b6859SYaroslav Tykhiy 	int oldflags, oldcount;
31411a3b6859SYaroslav Tykhiy 
31421a3b6859SYaroslav Tykhiy 	/* Sanity checks to catch programming errors */
3143b5c8bd59SYaroslav Tykhiy 	KASSERT((flag & (IFF_DRV_OACTIVE|IFF_DRV_RUNNING)) == 0,
3144b5c8bd59SYaroslav Tykhiy 	    ("%s: setting driver-owned flag %d", __func__, flag));
3145b5c8bd59SYaroslav Tykhiy 
3146b5c8bd59SYaroslav Tykhiy 	if (onswitch)
3147b5c8bd59SYaroslav Tykhiy 		KASSERT(*refcount >= 0,
3148b5c8bd59SYaroslav Tykhiy 		    ("%s: increment negative refcount %d for flag %d",
3149b5c8bd59SYaroslav Tykhiy 		    __func__, *refcount, flag));
3150b5c8bd59SYaroslav Tykhiy 	else
3151b5c8bd59SYaroslav Tykhiy 		KASSERT(*refcount > 0,
3152b5c8bd59SYaroslav Tykhiy 		    ("%s: decrement non-positive refcount %d for flag %d",
3153b5c8bd59SYaroslav Tykhiy 		    __func__, *refcount, flag));
31541a3b6859SYaroslav Tykhiy 
31551a3b6859SYaroslav Tykhiy 	/* In case this mode is permanent, just touch refcount */
31561a3b6859SYaroslav Tykhiy 	if (ifp->if_flags & pflag) {
31571a3b6859SYaroslav Tykhiy 		*refcount += onswitch ? 1 : -1;
31581a3b6859SYaroslav Tykhiy 		return (0);
31591a3b6859SYaroslav Tykhiy 	}
31601a3b6859SYaroslav Tykhiy 
31611a3b6859SYaroslav Tykhiy 	/* Save ifnet parameters for if_ioctl() may fail */
31621a3b6859SYaroslav Tykhiy 	oldcount = *refcount;
31631a3b6859SYaroslav Tykhiy 	oldflags = ifp->if_flags;
31641a3b6859SYaroslav Tykhiy 
31651a3b6859SYaroslav Tykhiy 	/*
31661a3b6859SYaroslav Tykhiy 	 * See if we aren't the only and touching refcount is enough.
31671a3b6859SYaroslav Tykhiy 	 * Actually toggle interface flag if we are the first or last.
31681a3b6859SYaroslav Tykhiy 	 */
31691a3b6859SYaroslav Tykhiy 	if (onswitch) {
31701a3b6859SYaroslav Tykhiy 		if ((*refcount)++)
31711a3b6859SYaroslav Tykhiy 			return (0);
31721a3b6859SYaroslav Tykhiy 		ifp->if_flags |= flag;
31731a3b6859SYaroslav Tykhiy 	} else {
31741a3b6859SYaroslav Tykhiy 		if (--(*refcount))
31751a3b6859SYaroslav Tykhiy 			return (0);
31761a3b6859SYaroslav Tykhiy 		ifp->if_flags &= ~flag;
31771a3b6859SYaroslav Tykhiy 	}
31781a3b6859SYaroslav Tykhiy 
31791a3b6859SYaroslav Tykhiy 	/* Call down the driver since we've changed interface flags */
31801a3b6859SYaroslav Tykhiy 	if (ifp->if_ioctl == NULL) {
31811a3b6859SYaroslav Tykhiy 		error = EOPNOTSUPP;
31821a3b6859SYaroslav Tykhiy 		goto recover;
31831a3b6859SYaroslav Tykhiy 	}
31841a3b6859SYaroslav Tykhiy 	ifr.ifr_flags = ifp->if_flags & 0xffff;
31851a3b6859SYaroslav Tykhiy 	ifr.ifr_flagshigh = ifp->if_flags >> 16;
31861a3b6859SYaroslav Tykhiy 	error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
31871a3b6859SYaroslav Tykhiy 	if (error)
31881a3b6859SYaroslav Tykhiy 		goto recover;
31891a3b6859SYaroslav Tykhiy 	/* Notify userland that interface flags have changed */
31901a3b6859SYaroslav Tykhiy 	rt_ifmsg(ifp);
31911a3b6859SYaroslav Tykhiy 	return (0);
31921a3b6859SYaroslav Tykhiy 
31931a3b6859SYaroslav Tykhiy recover:
31941a3b6859SYaroslav Tykhiy 	/* Recover after driver error */
31951a3b6859SYaroslav Tykhiy 	*refcount = oldcount;
31961a3b6859SYaroslav Tykhiy 	ifp->if_flags = oldflags;
31971a3b6859SYaroslav Tykhiy 	return (error);
31981a3b6859SYaroslav Tykhiy }
31991a3b6859SYaroslav Tykhiy 
32001a3b6859SYaroslav Tykhiy /*
3201963e4c2aSGarrett Wollman  * Set/clear promiscuous mode on interface ifp based on the truth value
3202963e4c2aSGarrett Wollman  * of pswitch.  The calls are reference counted so that only the first
3203963e4c2aSGarrett Wollman  * "on" request actually has an effect, as does the final "off" request.
3204963e4c2aSGarrett Wollman  * Results are undefined if the "off" and "on" requests are not matched.
3205963e4c2aSGarrett Wollman  */
3206963e4c2aSGarrett Wollman int
320772fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch)
3208963e4c2aSGarrett Wollman {
32094a26224cSGarrett Wollman 	int error;
32101a3b6859SYaroslav Tykhiy 	int oldflags = ifp->if_flags;
3211963e4c2aSGarrett Wollman 
32121a3b6859SYaroslav Tykhiy 	error = if_setflag(ifp, IFF_PROMISC, IFF_PPROMISC,
32131a3b6859SYaroslav Tykhiy 			   &ifp->if_pcount, pswitch);
32141a3b6859SYaroslav Tykhiy 	/* If promiscuous mode status has changed, log a message */
32156d07c157SNick Hibma 	if (error == 0 && ((ifp->if_flags ^ oldflags) & IFF_PROMISC) &&
32166d07c157SNick Hibma             log_promisc_mode_change)
321720f8d7bcSDag-Erling Smørgrav 		if_printf(ifp, "promiscuous mode %s\n",
32184f3c11a6SBill Fenner 		    (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
32191a3b6859SYaroslav Tykhiy 	return (error);
3220963e4c2aSGarrett Wollman }
3221963e4c2aSGarrett Wollman 
3222963e4c2aSGarrett Wollman /*
3223df8bae1dSRodney W. Grimes  * Return interface configuration
3224df8bae1dSRodney W. Grimes  * of system.  List may be used
3225df8bae1dSRodney W. Grimes  * in later ioctl's (above) to get
3226df8bae1dSRodney W. Grimes  * other information.
3227df8bae1dSRodney W. Grimes  */
3228df8bae1dSRodney W. Grimes /*ARGSUSED*/
32293bda9f9bSPoul-Henning Kamp static int
323072fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data)
3231df8bae1dSRodney W. Grimes {
32320b59d917SJonathan Lemon 	struct ifconf *ifc = (struct ifconf *)data;
32330b59d917SJonathan Lemon 	struct ifnet *ifp;
32340b59d917SJonathan Lemon 	struct ifaddr *ifa;
32354dcf2bbbSBrooks Davis 	struct ifreq ifr;
32364dcf2bbbSBrooks Davis 	struct sbuf *sb;
32374dcf2bbbSBrooks Davis 	int error, full = 0, valid_len, max_len;
3238df8bae1dSRodney W. Grimes 
3239cd853791SKonstantin Belousov 	/* Limit initial buffer size to maxphys to avoid DoS from userspace. */
3240cd853791SKonstantin Belousov 	max_len = maxphys - 1;
32414dcf2bbbSBrooks Davis 
3242b0b4b28bSXin LI 	/* Prevent hostile input from being able to crash the system */
3243b0b4b28bSXin LI 	if (ifc->ifc_len <= 0)
3244b0b4b28bSXin LI 		return (EINVAL);
3245b0b4b28bSXin LI 
32464dcf2bbbSBrooks Davis again:
32474dcf2bbbSBrooks Davis 	if (ifc->ifc_len <= max_len) {
32484dcf2bbbSBrooks Davis 		max_len = ifc->ifc_len;
32494dcf2bbbSBrooks Davis 		full = 1;
32504dcf2bbbSBrooks Davis 	}
32514dcf2bbbSBrooks Davis 	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
32524dcf2bbbSBrooks Davis 	max_len = 0;
32534dcf2bbbSBrooks Davis 	valid_len = 0;
32544dcf2bbbSBrooks Davis 
325577dfcdc4SRobert Watson 	IFNET_RLOCK();
32564f6c66ccSMatt Macy 	CK_STAILQ_FOREACH(ifp, &V_ifnet, if_link) {
3257a68cc388SGleb Smirnoff 		struct epoch_tracker et;
32589bf40edeSBrooks Davis 		int addrs;
32592624cf89SGarrett Wollman 
3260fbd24c5eSColin Percival 		/*
32612443045fSBrooks Davis 		 * Zero the ifr to make sure we don't disclose the contents
32622443045fSBrooks Davis 		 * of the stack.
3263fbd24c5eSColin Percival 		 */
32642443045fSBrooks Davis 		memset(&ifr, 0, sizeof(ifr));
3265fbd24c5eSColin Percival 
32669bf40edeSBrooks Davis 		if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name))
326762313e4cSSam Leffler 		    >= sizeof(ifr.ifr_name)) {
326862313e4cSSam Leffler 			sbuf_delete(sb);
326962313e4cSSam Leffler 			IFNET_RUNLOCK();
32704dcf2bbbSBrooks Davis 			return (ENAMETOOLONG);
327162313e4cSSam Leffler 		}
32722624cf89SGarrett Wollman 
327375c13541SPoul-Henning Kamp 		addrs = 0;
3274a68cc388SGleb Smirnoff 		NET_EPOCH_ENTER(et);
3275d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
32762defe5cdSJonathan Lemon 			struct sockaddr *sa = ifa->ifa_addr;
32772defe5cdSJonathan Lemon 
3278b89e82ddSJamie Gritton 			if (prison_if(curthread->td_ucred, sa) != 0)
327975c13541SPoul-Henning Kamp 				continue;
328075c13541SPoul-Henning Kamp 			addrs++;
3281df8bae1dSRodney W. Grimes 			if (sa->sa_len <= sizeof(*sa)) {
3282e7fdc72eSBrooks Davis 				if (sa->sa_len < sizeof(*sa)) {
3283e7fdc72eSBrooks Davis 					memset(&ifr.ifr_ifru.ifru_addr, 0,
3284e7fdc72eSBrooks Davis 					    sizeof(ifr.ifr_ifru.ifru_addr));
3285e7fdc72eSBrooks Davis 					memcpy(&ifr.ifr_ifru.ifru_addr, sa,
3286e7fdc72eSBrooks Davis 					    sa->sa_len);
3287e7fdc72eSBrooks Davis 				} else
3288e7fdc72eSBrooks Davis 					ifr.ifr_ifru.ifru_addr = *sa;
32894dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
32904dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
3291df8bae1dSRodney W. Grimes 			} else {
32924dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr,
32934dcf2bbbSBrooks Davis 				    offsetof(struct ifreq, ifr_addr));
32944dcf2bbbSBrooks Davis 				max_len += offsetof(struct ifreq, ifr_addr);
32954dcf2bbbSBrooks Davis 				sbuf_bcat(sb, sa, sa->sa_len);
32964dcf2bbbSBrooks Davis 				max_len += sa->sa_len;
3297df8bae1dSRodney W. Grimes 			}
32984dcf2bbbSBrooks Davis 
32994d369413SMatthew D Fleming 			if (sbuf_error(sb) == 0)
33004dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
3301df8bae1dSRodney W. Grimes 		}
3302a68cc388SGleb Smirnoff 		NET_EPOCH_EXIT(et);
33034dcf2bbbSBrooks Davis 		if (addrs == 0) {
33044dcf2bbbSBrooks Davis 			sbuf_bcat(sb, &ifr, sizeof(ifr));
33054dcf2bbbSBrooks Davis 			max_len += sizeof(ifr);
33064dcf2bbbSBrooks Davis 
33074d369413SMatthew D Fleming 			if (sbuf_error(sb) == 0)
33084dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
330975c13541SPoul-Henning Kamp 		}
3310df8bae1dSRodney W. Grimes 	}
3311b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
33124dcf2bbbSBrooks Davis 
33134dcf2bbbSBrooks Davis 	/*
33144dcf2bbbSBrooks Davis 	 * If we didn't allocate enough space (uncommon), try again.  If
33154dcf2bbbSBrooks Davis 	 * we have already allocated as much space as we are allowed,
33164dcf2bbbSBrooks Davis 	 * return what we've got.
33174dcf2bbbSBrooks Davis 	 */
33184dcf2bbbSBrooks Davis 	if (valid_len != max_len && !full) {
33194dcf2bbbSBrooks Davis 		sbuf_delete(sb);
33204dcf2bbbSBrooks Davis 		goto again;
33214dcf2bbbSBrooks Davis 	}
33224dcf2bbbSBrooks Davis 
33234dcf2bbbSBrooks Davis 	ifc->ifc_len = valid_len;
33245ed8cedcSBrian Feldman 	sbuf_finish(sb);
33254dcf2bbbSBrooks Davis 	error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len);
33264dcf2bbbSBrooks Davis 	sbuf_delete(sb);
3327df8bae1dSRodney W. Grimes 	return (error);
3328df8bae1dSRodney W. Grimes }
3329df8bae1dSRodney W. Grimes 
33301158dfb7SGarrett Wollman /*
33318b25904eSGleb Smirnoff  * Just like ifpromisc(), but for all-multicast-reception mode.
33321158dfb7SGarrett Wollman  */
33331158dfb7SGarrett Wollman int
333472fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch)
33351158dfb7SGarrett Wollman {
33361158dfb7SGarrett Wollman 
33371a3b6859SYaroslav Tykhiy 	return (if_setflag(ifp, IFF_ALLMULTI, 0, &ifp->if_amcount, onswitch));
33381158dfb7SGarrett Wollman }
33391158dfb7SGarrett Wollman 
33405896d124SBruce M Simpson struct ifmultiaddr *
3341441f9243SAlexander V. Chernikov if_findmulti(struct ifnet *ifp, const struct sockaddr *sa)
33421158dfb7SGarrett Wollman {
33431158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
33441158dfb7SGarrett Wollman 
3345c3b31afdSRobert Watson 	IF_ADDR_LOCK_ASSERT(ifp);
3346c3b31afdSRobert Watson 
3347d7c5a620SMatt Macy 	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
334840d8a302SBruce M Simpson 		if (sa->sa_family == AF_LINK) {
334940d8a302SBruce M Simpson 			if (sa_dl_equal(ifma->ifma_addr, sa))
335040d8a302SBruce M Simpson 				break;
335140d8a302SBruce M Simpson 		} else {
3352c3b31afdSRobert Watson 			if (sa_equal(ifma->ifma_addr, sa))
3353c3b31afdSRobert Watson 				break;
33541158dfb7SGarrett Wollman 		}
335540d8a302SBruce M Simpson 	}
3356c3b31afdSRobert Watson 
3357c3b31afdSRobert Watson 	return ifma;
335857af7922SJulian Elischer }
33591158dfb7SGarrett Wollman 
33601158dfb7SGarrett Wollman /*
3361c3b31afdSRobert Watson  * Allocate a new ifmultiaddr and initialize based on passed arguments.  We
3362c3b31afdSRobert Watson  * make copies of passed sockaddrs.  The ifmultiaddr will not be added to
3363c3b31afdSRobert Watson  * the ifnet multicast address list here, so the caller must do that and
3364c3b31afdSRobert Watson  * other setup work (such as notifying the device driver).  The reference
3365c3b31afdSRobert Watson  * count is initialized to 1.
33661158dfb7SGarrett Wollman  */
3367c3b31afdSRobert Watson static struct ifmultiaddr *
3368c3b31afdSRobert Watson if_allocmulti(struct ifnet *ifp, struct sockaddr *sa, struct sockaddr *llsa,
3369c3b31afdSRobert Watson     int mflags)
3370c3b31afdSRobert Watson {
3371c3b31afdSRobert Watson 	struct ifmultiaddr *ifma;
3372c3b31afdSRobert Watson 	struct sockaddr *dupsa;
3373c3b31afdSRobert Watson 
33741ede983cSDag-Erling Smørgrav 	ifma = malloc(sizeof *ifma, M_IFMADDR, mflags |
3375c3b31afdSRobert Watson 	    M_ZERO);
3376c3b31afdSRobert Watson 	if (ifma == NULL)
3377c3b31afdSRobert Watson 		return (NULL);
3378c3b31afdSRobert Watson 
33791ede983cSDag-Erling Smørgrav 	dupsa = malloc(sa->sa_len, M_IFMADDR, mflags);
3380c3b31afdSRobert Watson 	if (dupsa == NULL) {
33811ede983cSDag-Erling Smørgrav 		free(ifma, M_IFMADDR);
3382c3b31afdSRobert Watson 		return (NULL);
33831158dfb7SGarrett Wollman 	}
33841158dfb7SGarrett Wollman 	bcopy(sa, dupsa, sa->sa_len);
33851158dfb7SGarrett Wollman 	ifma->ifma_addr = dupsa;
3386c3b31afdSRobert Watson 
33871158dfb7SGarrett Wollman 	ifma->ifma_ifp = ifp;
33881158dfb7SGarrett Wollman 	ifma->ifma_refcount = 1;
3389d4d22970SGleb Smirnoff 	ifma->ifma_protospec = NULL;
3390c3b31afdSRobert Watson 
3391c3b31afdSRobert Watson 	if (llsa == NULL) {
3392c3b31afdSRobert Watson 		ifma->ifma_lladdr = NULL;
3393c3b31afdSRobert Watson 		return (ifma);
3394c3b31afdSRobert Watson 	}
3395c3b31afdSRobert Watson 
33961ede983cSDag-Erling Smørgrav 	dupsa = malloc(llsa->sa_len, M_IFMADDR, mflags);
3397c3b31afdSRobert Watson 	if (dupsa == NULL) {
33981ede983cSDag-Erling Smørgrav 		free(ifma->ifma_addr, M_IFMADDR);
33991ede983cSDag-Erling Smørgrav 		free(ifma, M_IFMADDR);
3400c3b31afdSRobert Watson 		return (NULL);
3401c3b31afdSRobert Watson 	}
3402c3b31afdSRobert Watson 	bcopy(llsa, dupsa, llsa->sa_len);
3403c3b31afdSRobert Watson 	ifma->ifma_lladdr = dupsa;
3404c3b31afdSRobert Watson 
3405c3b31afdSRobert Watson 	return (ifma);
3406c3b31afdSRobert Watson }
3407373f88edSGarrett Wollman 
34081158dfb7SGarrett Wollman /*
3409c3b31afdSRobert Watson  * if_freemulti: free ifmultiaddr structure and possibly attached related
3410c3b31afdSRobert Watson  * addresses.  The caller is responsible for implementing reference
3411c3b31afdSRobert Watson  * counting, notifying the driver, handling routing messages, and releasing
3412c3b31afdSRobert Watson  * any dependent link layer state.
34131158dfb7SGarrett Wollman  */
3414b6f6f880SMatt Macy #ifdef MCAST_VERBOSE
3415b6f6f880SMatt Macy extern void kdb_backtrace(void);
3416b6f6f880SMatt Macy #endif
3417d7c5a620SMatt Macy static void
3418d7c5a620SMatt Macy if_freemulti_internal(struct ifmultiaddr *ifma)
3419c3b31afdSRobert Watson {
3420c3b31afdSRobert Watson 
3421ec002feeSBruce M Simpson 	KASSERT(ifma->ifma_refcount == 0, ("if_freemulti: refcount %d",
3422c3b31afdSRobert Watson 	    ifma->ifma_refcount));
3423c3b31afdSRobert Watson 
3424c3b31afdSRobert Watson 	if (ifma->ifma_lladdr != NULL)
34251ede983cSDag-Erling Smørgrav 		free(ifma->ifma_lladdr, M_IFMADDR);
3426b6f6f880SMatt Macy #ifdef MCAST_VERBOSE
3427b6f6f880SMatt Macy 	kdb_backtrace();
3428b6f6f880SMatt Macy 	printf("%s freeing ifma: %p\n", __func__, ifma);
3429b6f6f880SMatt Macy #endif
34301ede983cSDag-Erling Smørgrav 	free(ifma->ifma_addr, M_IFMADDR);
34311ede983cSDag-Erling Smørgrav 	free(ifma, M_IFMADDR);
3432c3b31afdSRobert Watson }
3433c3b31afdSRobert Watson 
3434d7c5a620SMatt Macy static void
3435d7c5a620SMatt Macy if_destroymulti(epoch_context_t ctx)
3436d7c5a620SMatt Macy {
3437d7c5a620SMatt Macy 	struct ifmultiaddr *ifma;
3438d7c5a620SMatt Macy 
3439d7c5a620SMatt Macy 	ifma = __containerof(ctx, struct ifmultiaddr, ifma_epoch_ctx);
3440d7c5a620SMatt Macy 	if_freemulti_internal(ifma);
3441d7c5a620SMatt Macy }
3442d7c5a620SMatt Macy 
3443d7c5a620SMatt Macy void
3444d7c5a620SMatt Macy if_freemulti(struct ifmultiaddr *ifma)
3445d7c5a620SMatt Macy {
3446d7c5a620SMatt Macy 	KASSERT(ifma->ifma_refcount == 0, ("if_freemulti_epoch: refcount %d",
3447d7c5a620SMatt Macy 	    ifma->ifma_refcount));
3448d7c5a620SMatt Macy 
34492a4bd982SGleb Smirnoff 	NET_EPOCH_CALL(if_destroymulti, &ifma->ifma_epoch_ctx);
3450d7c5a620SMatt Macy }
3451d7c5a620SMatt Macy 
3452c3b31afdSRobert Watson /*
3453c3b31afdSRobert Watson  * Register an additional multicast address with a network interface.
3454c3b31afdSRobert Watson  *
3455c3b31afdSRobert Watson  * - If the address is already present, bump the reference count on the
3456c3b31afdSRobert Watson  *   address and return.
3457c3b31afdSRobert Watson  * - If the address is not link-layer, look up a link layer address.
3458c3b31afdSRobert Watson  * - Allocate address structures for one or both addresses, and attach to the
3459c3b31afdSRobert Watson  *   multicast address list on the interface.  If automatically adding a link
3460c3b31afdSRobert Watson  *   layer address, the protocol address will own a reference to the link
3461c3b31afdSRobert Watson  *   layer address, to be freed when it is freed.
3462c3b31afdSRobert Watson  * - Notify the network device driver of an addition to the multicast address
3463c3b31afdSRobert Watson  *   list.
3464c3b31afdSRobert Watson  *
3465c3b31afdSRobert Watson  * 'sa' points to caller-owned memory with the desired multicast address.
3466c3b31afdSRobert Watson  *
3467c3b31afdSRobert Watson  * 'retifma' will be used to return a pointer to the resulting multicast
3468c3b31afdSRobert Watson  * address reference, if desired.
3469c3b31afdSRobert Watson  */
3470c3b31afdSRobert Watson int
3471c3b31afdSRobert Watson if_addmulti(struct ifnet *ifp, struct sockaddr *sa,
3472c3b31afdSRobert Watson     struct ifmultiaddr **retifma)
3473c3b31afdSRobert Watson {
3474c3b31afdSRobert Watson 	struct ifmultiaddr *ifma, *ll_ifma;
3475c3b31afdSRobert Watson 	struct sockaddr *llsa;
347695fbe4d0SAlexander V. Chernikov 	struct sockaddr_dl sdl;
3477c3b31afdSRobert Watson 	int error;
3478c3b31afdSRobert Watson 
3479f3e1324bSStephen Hurd #ifdef INET
3480f3e1324bSStephen Hurd 	IN_MULTI_LIST_UNLOCK_ASSERT();
3481f3e1324bSStephen Hurd #endif
3482f3e1324bSStephen Hurd #ifdef INET6
3483f3e1324bSStephen Hurd 	IN6_MULTI_LIST_UNLOCK_ASSERT();
3484f3e1324bSStephen Hurd #endif
3485c3b31afdSRobert Watson 	/*
3486c3b31afdSRobert Watson 	 * If the address is already present, return a new reference to it;
3487c3b31afdSRobert Watson 	 * otherwise, allocate storage and set up a new address.
3488c3b31afdSRobert Watson 	 */
3489137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
3490c3b31afdSRobert Watson 	ifma = if_findmulti(ifp, sa);
3491c3b31afdSRobert Watson 	if (ifma != NULL) {
3492c3b31afdSRobert Watson 		ifma->ifma_refcount++;
3493c3b31afdSRobert Watson 		if (retifma != NULL)
3494c3b31afdSRobert Watson 			*retifma = ifma;
3495137f91e8SJohn Baldwin 		IF_ADDR_WUNLOCK(ifp);
3496c3b31afdSRobert Watson 		return (0);
3497c3b31afdSRobert Watson 	}
3498c3b31afdSRobert Watson 
3499c3b31afdSRobert Watson 	/*
3500c3b31afdSRobert Watson 	 * The address isn't already present; resolve the protocol address
3501c3b31afdSRobert Watson 	 * into a link layer address, and then look that up, bump its
350295fbe4d0SAlexander V. Chernikov 	 * refcount or allocate an ifma for that also.
350395fbe4d0SAlexander V. Chernikov 	 * Most link layer resolving functions returns address data which
350495fbe4d0SAlexander V. Chernikov 	 * fits inside default sockaddr_dl structure. However callback
350595fbe4d0SAlexander V. Chernikov 	 * can allocate another sockaddr structure, in that case we need to
350695fbe4d0SAlexander V. Chernikov 	 * free it later.
3507c3b31afdSRobert Watson 	 */
3508c3b31afdSRobert Watson 	llsa = NULL;
3509c3b31afdSRobert Watson 	ll_ifma = NULL;
3510c3b31afdSRobert Watson 	if (ifp->if_resolvemulti != NULL) {
351195fbe4d0SAlexander V. Chernikov 		/* Provide called function with buffer size information */
351295fbe4d0SAlexander V. Chernikov 		sdl.sdl_len = sizeof(sdl);
351395fbe4d0SAlexander V. Chernikov 		llsa = (struct sockaddr *)&sdl;
3514c3b31afdSRobert Watson 		error = ifp->if_resolvemulti(ifp, &llsa, sa);
3515c3b31afdSRobert Watson 		if (error)
3516c3b31afdSRobert Watson 			goto unlock_out;
3517c3b31afdSRobert Watson 	}
3518c3b31afdSRobert Watson 
3519c3b31afdSRobert Watson 	/*
3520c3b31afdSRobert Watson 	 * Allocate the new address.  Don't hook it up yet, as we may also
3521c3b31afdSRobert Watson 	 * need to allocate a link layer multicast address.
3522c3b31afdSRobert Watson 	 */
3523c3b31afdSRobert Watson 	ifma = if_allocmulti(ifp, sa, llsa, M_NOWAIT);
3524c3b31afdSRobert Watson 	if (ifma == NULL) {
3525c3b31afdSRobert Watson 		error = ENOMEM;
3526c3b31afdSRobert Watson 		goto free_llsa_out;
3527c3b31afdSRobert Watson 	}
3528c3b31afdSRobert Watson 
3529c3b31afdSRobert Watson 	/*
3530c3b31afdSRobert Watson 	 * If a link layer address is found, we'll need to see if it's
3531c3b31afdSRobert Watson 	 * already present in the address list, or allocate is as well.
3532c3b31afdSRobert Watson 	 * When this block finishes, the link layer address will be on the
3533c3b31afdSRobert Watson 	 * list.
3534c3b31afdSRobert Watson 	 */
3535c3b31afdSRobert Watson 	if (llsa != NULL) {
3536c3b31afdSRobert Watson 		ll_ifma = if_findmulti(ifp, llsa);
3537c3b31afdSRobert Watson 		if (ll_ifma == NULL) {
3538c3b31afdSRobert Watson 			ll_ifma = if_allocmulti(ifp, llsa, NULL, M_NOWAIT);
3539c3b31afdSRobert Watson 			if (ll_ifma == NULL) {
3540ec002feeSBruce M Simpson 				--ifma->ifma_refcount;
3541c3b31afdSRobert Watson 				if_freemulti(ifma);
3542c3b31afdSRobert Watson 				error = ENOMEM;
3543c3b31afdSRobert Watson 				goto free_llsa_out;
3544c3b31afdSRobert Watson 			}
3545f9be0386SMatt Macy 			ll_ifma->ifma_flags |= IFMA_F_ENQUEUED;
3546d7c5a620SMatt Macy 			CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ll_ifma,
3547c3b31afdSRobert Watson 			    ifma_link);
3548c3b31afdSRobert Watson 		} else
3549c3b31afdSRobert Watson 			ll_ifma->ifma_refcount++;
3550ec002feeSBruce M Simpson 		ifma->ifma_llifma = ll_ifma;
3551c3b31afdSRobert Watson 	}
3552c3b31afdSRobert Watson 
3553c3b31afdSRobert Watson 	/*
3554c3b31afdSRobert Watson 	 * We now have a new multicast address, ifma, and possibly a new or
3555c3b31afdSRobert Watson 	 * referenced link layer address.  Add the primary address to the
3556c3b31afdSRobert Watson 	 * ifnet address list.
3557c3b31afdSRobert Watson 	 */
3558f9be0386SMatt Macy 	ifma->ifma_flags |= IFMA_F_ENQUEUED;
3559d7c5a620SMatt Macy 	CK_STAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
3560c3b31afdSRobert Watson 
356113990766SJonathan Mini 	if (retifma != NULL)
3562373f88edSGarrett Wollman 		*retifma = ifma;
35631158dfb7SGarrett Wollman 
3564c3b31afdSRobert Watson 	/*
3565c3b31afdSRobert Watson 	 * Must generate the message while holding the lock so that 'ifma'
3566c3b31afdSRobert Watson 	 * pointer is still valid.
3567c3b31afdSRobert Watson 	 */
3568c3b31afdSRobert Watson 	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
3569137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
3570c3b31afdSRobert Watson 
35711158dfb7SGarrett Wollman 	/*
35721158dfb7SGarrett Wollman 	 * We are certain we have added something, so call down to the
35731158dfb7SGarrett Wollman 	 * interface to let them know about it.
35741158dfb7SGarrett Wollman 	 */
35752432c31cSRobert Watson 	if (ifp->if_ioctl != NULL) {
35760839aa5cSGleb Smirnoff 		if (THREAD_CAN_SLEEP())
35771a3b6859SYaroslav Tykhiy 			(void )(*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
35780839aa5cSGleb Smirnoff 		else
35790839aa5cSGleb Smirnoff 			taskqueue_enqueue(taskqueue_swi, &ifp->if_addmultitask);
35801a3b6859SYaroslav Tykhiy 	}
35811158dfb7SGarrett Wollman 
358295fbe4d0SAlexander V. Chernikov 	if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
358395fbe4d0SAlexander V. Chernikov 		link_free_sdl(llsa);
3584c3b31afdSRobert Watson 
3585c3b31afdSRobert Watson 	return (0);
3586c3b31afdSRobert Watson 
3587c3b31afdSRobert Watson free_llsa_out:
358895fbe4d0SAlexander V. Chernikov 	if ((llsa != NULL) && (llsa != (struct sockaddr *)&sdl))
358995fbe4d0SAlexander V. Chernikov 		link_free_sdl(llsa);
3590c3b31afdSRobert Watson 
3591c3b31afdSRobert Watson unlock_out:
3592137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
3593c3b31afdSRobert Watson 	return (error);
35941158dfb7SGarrett Wollman }
35951158dfb7SGarrett Wollman 
35960839aa5cSGleb Smirnoff static void
35970839aa5cSGleb Smirnoff if_siocaddmulti(void *arg, int pending)
35980839aa5cSGleb Smirnoff {
35990839aa5cSGleb Smirnoff 	struct ifnet *ifp;
36000839aa5cSGleb Smirnoff 
36010839aa5cSGleb Smirnoff 	ifp = arg;
36020839aa5cSGleb Smirnoff #ifdef DIAGNOSTIC
36030839aa5cSGleb Smirnoff 	if (pending > 1)
36040839aa5cSGleb Smirnoff 		if_printf(ifp, "%d SIOCADDMULTI coalesced\n", pending);
36050839aa5cSGleb Smirnoff #endif
36069352fab6SGleb Smirnoff 	CURVNET_SET(ifp->if_vnet);
36070839aa5cSGleb Smirnoff 	(void )(*ifp->if_ioctl)(ifp, SIOCADDMULTI, 0);
36089352fab6SGleb Smirnoff 	CURVNET_RESTORE();
36090839aa5cSGleb Smirnoff }
36100839aa5cSGleb Smirnoff 
36111158dfb7SGarrett Wollman /*
3612ec002feeSBruce M Simpson  * Delete a multicast group membership by network-layer group address.
3613ec002feeSBruce M Simpson  *
3614ec002feeSBruce M Simpson  * Returns ENOENT if the entry could not be found. If ifp no longer
3615ec002feeSBruce M Simpson  * exists, results are undefined. This entry point should only be used
3616ec002feeSBruce M Simpson  * from subsystems which do appropriate locking to hold ifp for the
3617ec002feeSBruce M Simpson  * duration of the call.
3618ec002feeSBruce M Simpson  * Network-layer protocol domains must use if_delmulti_ifma().
36191158dfb7SGarrett Wollman  */
36201158dfb7SGarrett Wollman int
362172fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
36221158dfb7SGarrett Wollman {
3623ec002feeSBruce M Simpson 	struct ifmultiaddr *ifma;
3624ec002feeSBruce M Simpson 	int lastref;
3625ec002feeSBruce M Simpson 
3626416a1d1eSGleb Smirnoff 	KASSERT(ifp, ("%s: NULL ifp", __func__));
36271158dfb7SGarrett Wollman 
3628137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
3629ec002feeSBruce M Simpson 	lastref = 0;
3630c3b31afdSRobert Watson 	ifma = if_findmulti(ifp, sa);
3631ec002feeSBruce M Simpson 	if (ifma != NULL)
3632ec002feeSBruce M Simpson 		lastref = if_delmulti_locked(ifp, ifma, 0);
3633137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
3634c3b31afdSRobert Watson 
3635ec002feeSBruce M Simpson 	if (ifma == NULL)
3636ec002feeSBruce M Simpson 		return (ENOENT);
3637ec002feeSBruce M Simpson 
3638ec002feeSBruce M Simpson 	if (lastref && ifp->if_ioctl != NULL) {
36391a3b6859SYaroslav Tykhiy 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
364031302ebfSRobert Watson 	}
36411158dfb7SGarrett Wollman 
3642ec002feeSBruce M Simpson 	return (0);
3643ec002feeSBruce M Simpson }
3644ec002feeSBruce M Simpson 
3645ec002feeSBruce M Simpson /*
364693ec7edcSShteryana Shopova  * Delete all multicast group membership for an interface.
364793ec7edcSShteryana Shopova  * Should be used to quickly flush all multicast filters.
364893ec7edcSShteryana Shopova  */
364993ec7edcSShteryana Shopova void
365093ec7edcSShteryana Shopova if_delallmulti(struct ifnet *ifp)
365193ec7edcSShteryana Shopova {
365293ec7edcSShteryana Shopova 	struct ifmultiaddr *ifma;
365393ec7edcSShteryana Shopova 	struct ifmultiaddr *next;
365493ec7edcSShteryana Shopova 
3655137f91e8SJohn Baldwin 	IF_ADDR_WLOCK(ifp);
3656d7c5a620SMatt Macy 	CK_STAILQ_FOREACH_SAFE(ifma, &ifp->if_multiaddrs, ifma_link, next)
365793ec7edcSShteryana Shopova 		if_delmulti_locked(ifp, ifma, 0);
3658137f91e8SJohn Baldwin 	IF_ADDR_WUNLOCK(ifp);
365993ec7edcSShteryana Shopova }
366093ec7edcSShteryana Shopova 
3661b6f6f880SMatt Macy void
3662b6f6f880SMatt Macy if_delmulti_ifma(struct ifmultiaddr *ifma)
3663b6f6f880SMatt Macy {
3664b6f6f880SMatt Macy 	if_delmulti_ifma_flags(ifma, 0);
3665b6f6f880SMatt Macy }
3666b6f6f880SMatt Macy 
366793ec7edcSShteryana Shopova /*
3668ec002feeSBruce M Simpson  * Delete a multicast group membership by group membership pointer.
3669ec002feeSBruce M Simpson  * Network-layer protocol domains must use this routine.
3670ec002feeSBruce M Simpson  *
3671e5adda3dSRobert Watson  * It is safe to call this routine if the ifp disappeared.
3672ec002feeSBruce M Simpson  */
3673ec002feeSBruce M Simpson void
3674b6f6f880SMatt Macy if_delmulti_ifma_flags(struct ifmultiaddr *ifma, int flags)
3675ec002feeSBruce M Simpson {
3676ec002feeSBruce M Simpson 	struct ifnet *ifp;
3677ec002feeSBruce M Simpson 	int lastref;
3678b6f6f880SMatt Macy 	MCDPRINTF("%s freeing ifma: %p\n", __func__, ifma);
3679f3e1324bSStephen Hurd #ifdef INET
3680f3e1324bSStephen Hurd 	IN_MULTI_LIST_UNLOCK_ASSERT();
3681f3e1324bSStephen Hurd #endif
3682ec002feeSBruce M Simpson 	ifp = ifma->ifma_ifp;
3683ec002feeSBruce M Simpson #ifdef DIAGNOSTIC
3684ec002feeSBruce M Simpson 	if (ifp == NULL) {
3685ec002feeSBruce M Simpson 		printf("%s: ifma_ifp seems to be detached\n", __func__);
3686ec002feeSBruce M Simpson 	} else {
3687e9dc46ccSGleb Smirnoff 		struct epoch_tracker et;
3688ec002feeSBruce M Simpson 		struct ifnet *oifp;
3689ec002feeSBruce M Simpson 
3690e9dc46ccSGleb Smirnoff 		NET_EPOCH_ENTER(et);
36914f6c66ccSMatt Macy 		CK_STAILQ_FOREACH(oifp, &V_ifnet, if_link)
3692ec002feeSBruce M Simpson 			if (ifp == oifp)
3693ec002feeSBruce M Simpson 				break;
3694e9dc46ccSGleb Smirnoff 		NET_EPOCH_EXIT(et);
36951ebec5faSMatt Macy 		if (ifp != oifp)
3696ec002feeSBruce M Simpson 			ifp = NULL;
3697ec002feeSBruce M Simpson 	}
3698ec002feeSBruce M Simpson #endif
3699ec002feeSBruce M Simpson 	/*
3700ec002feeSBruce M Simpson 	 * If and only if the ifnet instance exists: Acquire the address lock.
3701ec002feeSBruce M Simpson 	 */
3702ec002feeSBruce M Simpson 	if (ifp != NULL)
3703137f91e8SJohn Baldwin 		IF_ADDR_WLOCK(ifp);
3704ec002feeSBruce M Simpson 
3705b6f6f880SMatt Macy 	lastref = if_delmulti_locked(ifp, ifma, flags);
3706ec002feeSBruce M Simpson 
3707ec002feeSBruce M Simpson 	if (ifp != NULL) {
3708ec002feeSBruce M Simpson 		/*
3709ec002feeSBruce M Simpson 		 * If and only if the ifnet instance exists:
3710ec002feeSBruce M Simpson 		 *  Release the address lock.
3711ec002feeSBruce M Simpson 		 *  If the group was left: update the hardware hash filter.
3712ec002feeSBruce M Simpson 		 */
3713137f91e8SJohn Baldwin 		IF_ADDR_WUNLOCK(ifp);
3714ec002feeSBruce M Simpson 		if (lastref && ifp->if_ioctl != NULL) {
3715ec002feeSBruce M Simpson 			(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, 0);
3716ec002feeSBruce M Simpson 		}
3717ec002feeSBruce M Simpson 	}
3718ec002feeSBruce M Simpson }
3719ec002feeSBruce M Simpson 
3720ec002feeSBruce M Simpson /*
3721ec002feeSBruce M Simpson  * Perform deletion of network-layer and/or link-layer multicast address.
3722ec002feeSBruce M Simpson  *
3723ec002feeSBruce M Simpson  * Return 0 if the reference count was decremented.
3724ec002feeSBruce M Simpson  * Return 1 if the final reference was released, indicating that the
3725ec002feeSBruce M Simpson  * hardware hash filter should be reprogrammed.
3726ec002feeSBruce M Simpson  */
3727ec002feeSBruce M Simpson static int
3728ec002feeSBruce M Simpson if_delmulti_locked(struct ifnet *ifp, struct ifmultiaddr *ifma, int detaching)
3729ec002feeSBruce M Simpson {
3730ec002feeSBruce M Simpson 	struct ifmultiaddr *ll_ifma;
3731ec002feeSBruce M Simpson 
3732ec002feeSBruce M Simpson 	if (ifp != NULL && ifma->ifma_ifp != NULL) {
3733ec002feeSBruce M Simpson 		KASSERT(ifma->ifma_ifp == ifp,
3734ec002feeSBruce M Simpson 		    ("%s: inconsistent ifp %p", __func__, ifp));
3735137f91e8SJohn Baldwin 		IF_ADDR_WLOCK_ASSERT(ifp);
3736ec002feeSBruce M Simpson 	}
3737ec002feeSBruce M Simpson 
3738ec002feeSBruce M Simpson 	ifp = ifma->ifma_ifp;
3739b6f6f880SMatt Macy 	MCDPRINTF("%s freeing %p from %s \n", __func__, ifma, ifp ? ifp->if_xname : "");
3740ec002feeSBruce M Simpson 
3741ec002feeSBruce M Simpson 	/*
3742ec002feeSBruce M Simpson 	 * If the ifnet is detaching, null out references to ifnet,
3743ec002feeSBruce M Simpson 	 * so that upper protocol layers will notice, and not attempt
374475ae0c01SBruce M Simpson 	 * to obtain locks for an ifnet which no longer exists. The
374575ae0c01SBruce M Simpson 	 * routing socket announcement must happen before the ifnet
374675ae0c01SBruce M Simpson 	 * instance is detached from the system.
3747ec002feeSBruce M Simpson 	 */
3748ec002feeSBruce M Simpson 	if (detaching) {
3749ec002feeSBruce M Simpson #ifdef DIAGNOSTIC
3750ec002feeSBruce M Simpson 		printf("%s: detaching ifnet instance %p\n", __func__, ifp);
3751ec002feeSBruce M Simpson #endif
375275ae0c01SBruce M Simpson 		/*
375375ae0c01SBruce M Simpson 		 * ifp may already be nulled out if we are being reentered
375475ae0c01SBruce M Simpson 		 * to delete the ll_ifma.
375575ae0c01SBruce M Simpson 		 */
375675ae0c01SBruce M Simpson 		if (ifp != NULL) {
375775ae0c01SBruce M Simpson 			rt_newmaddrmsg(RTM_DELMADDR, ifma);
3758ec002feeSBruce M Simpson 			ifma->ifma_ifp = NULL;
3759ec002feeSBruce M Simpson 		}
376075ae0c01SBruce M Simpson 	}
3761ec002feeSBruce M Simpson 
3762ec002feeSBruce M Simpson 	if (--ifma->ifma_refcount > 0)
37631158dfb7SGarrett Wollman 		return 0;
3764ec002feeSBruce M Simpson 
3765f9be0386SMatt Macy 	if (ifp != NULL && detaching == 0 && (ifma->ifma_flags & IFMA_F_ENQUEUED)) {
3766d7c5a620SMatt Macy 		CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifmultiaddr, ifma_link);
3767f9be0386SMatt Macy 		ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
3768f9be0386SMatt Macy 	}
3769ec002feeSBruce M Simpson 	/*
3770ec002feeSBruce M Simpson 	 * If this ifma is a network-layer ifma, a link-layer ifma may
3771ec002feeSBruce M Simpson 	 * have been associated with it. Release it first if so.
3772ec002feeSBruce M Simpson 	 */
3773ec002feeSBruce M Simpson 	ll_ifma = ifma->ifma_llifma;
3774ec002feeSBruce M Simpson 	if (ll_ifma != NULL) {
3775ec002feeSBruce M Simpson 		KASSERT(ifma->ifma_lladdr != NULL,
3776ec002feeSBruce M Simpson 		    ("%s: llifma w/o lladdr", __func__));
3777ec002feeSBruce M Simpson 		if (detaching)
3778ec002feeSBruce M Simpson 			ll_ifma->ifma_ifp = NULL;	/* XXX */
3779ec002feeSBruce M Simpson 		if (--ll_ifma->ifma_refcount == 0) {
3780ec002feeSBruce M Simpson 			if (ifp != NULL) {
3781f9be0386SMatt Macy 				if (ll_ifma->ifma_flags & IFMA_F_ENQUEUED) {
3782d7c5a620SMatt Macy 					CK_STAILQ_REMOVE(&ifp->if_multiaddrs, ll_ifma, ifmultiaddr,
3783ec002feeSBruce M Simpson 						ifma_link);
378477ad07b6SMatt Macy 					ll_ifma->ifma_flags &= ~IFMA_F_ENQUEUED;
3785f9be0386SMatt Macy 				}
3786ec002feeSBruce M Simpson 			}
3787ec002feeSBruce M Simpson 			if_freemulti(ll_ifma);
3788ec002feeSBruce M Simpson 		}
3789ec002feeSBruce M Simpson 	}
3790b6f6f880SMatt Macy #ifdef INVARIANTS
3791b6f6f880SMatt Macy 	if (ifp) {
3792b6f6f880SMatt Macy 		struct ifmultiaddr *ifmatmp;
3793ec002feeSBruce M Simpson 
3794d7c5a620SMatt Macy 		CK_STAILQ_FOREACH(ifmatmp, &ifp->if_multiaddrs, ifma_link)
3795b6f6f880SMatt Macy 			MPASS(ifma != ifmatmp);
3796b6f6f880SMatt Macy 	}
3797b6f6f880SMatt Macy #endif
3798ec002feeSBruce M Simpson 	if_freemulti(ifma);
3799ec002feeSBruce M Simpson 	/*
3800ec002feeSBruce M Simpson 	 * The last reference to this instance of struct ifmultiaddr
3801ec002feeSBruce M Simpson 	 * was released; the hardware should be notified of this change.
3802ec002feeSBruce M Simpson 	 */
3803ec002feeSBruce M Simpson 	return 1;
38041158dfb7SGarrett Wollman }
38051158dfb7SGarrett Wollman 
380666ce51ceSArchie Cobbs /*
380766ce51ceSArchie Cobbs  * Set the link layer address on an interface.
380866ce51ceSArchie Cobbs  *
380966ce51ceSArchie Cobbs  * At this time we only support certain types of interfaces,
381066ce51ceSArchie Cobbs  * and we don't allow the length of the address to change.
3811bb3d23fdSAlexander V. Chernikov  *
3812bb3d23fdSAlexander V. Chernikov  * Set noinline to be dtrace-friendly
381366ce51ceSArchie Cobbs  */
3814bb3d23fdSAlexander V. Chernikov __noinline int
381566ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
381666ce51ceSArchie Cobbs {
381766ce51ceSArchie Cobbs 	struct sockaddr_dl *sdl;
381866ce51ceSArchie Cobbs 	struct ifaddr *ifa;
3819d637e989SPeter Wemm 	struct ifreq ifr;
382066ce51ceSArchie Cobbs 
38214a0d6638SRuslan Ermilov 	ifa = ifp->if_addr;
38221e80e4f2SGleb Smirnoff 	if (ifa == NULL)
38231e80e4f2SGleb Smirnoff 		return (EINVAL);
38244f6c66ccSMatt Macy 
382566ce51ceSArchie Cobbs 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
38261e80e4f2SGleb Smirnoff 	if (sdl == NULL)
38271e80e4f2SGleb Smirnoff 		return (EINVAL);
38281e80e4f2SGleb Smirnoff 
38291e80e4f2SGleb Smirnoff 	if (len != sdl->sdl_alen)	/* don't allow length to change */
38301e80e4f2SGleb Smirnoff 		return (EINVAL);
38311e80e4f2SGleb Smirnoff 
383266ce51ceSArchie Cobbs 	switch (ifp->if_type) {
3833d09ed26fSRuslan Ermilov 	case IFT_ETHER:
383466ce51ceSArchie Cobbs 	case IFT_XETHER:
3835b7bffa71SYaroslav Tykhiy 	case IFT_L2VLAN:
38368f867517SAndrew Thompson 	case IFT_BRIDGE:
3837b47888ceSAndrew Thompson 	case IFT_IEEE8023ADLAG:
383866ce51ceSArchie Cobbs 		bcopy(lladdr, LLADDR(sdl), len);
383966ce51ceSArchie Cobbs 		break;
384066ce51ceSArchie Cobbs 	default:
38411e80e4f2SGleb Smirnoff 		return (ENODEV);
384266ce51ceSArchie Cobbs 	}
38433baaf297SRobert Watson 
384466ce51ceSArchie Cobbs 	/*
384566ce51ceSArchie Cobbs 	 * If the interface is already up, we need
384666ce51ceSArchie Cobbs 	 * to re-init it in order to reprogram its
384766ce51ceSArchie Cobbs 	 * address filter.
384866ce51ceSArchie Cobbs 	 */
384966ce51ceSArchie Cobbs 	if ((ifp->if_flags & IFF_UP) != 0) {
38501a3b6859SYaroslav Tykhiy 		if (ifp->if_ioctl) {
385166ce51ceSArchie Cobbs 			ifp->if_flags &= ~IFF_UP;
385262f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
385362f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
3854ee0a4f7eSSUZUKI Shinsuke 			(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
385566ce51ceSArchie Cobbs 			ifp->if_flags |= IFF_UP;
385662f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
385762f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
3858ee0a4f7eSSUZUKI Shinsuke 			(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
38591a3b6859SYaroslav Tykhiy 		}
386066ce51ceSArchie Cobbs 	}
38618ad43f2dSAlexander V. Chernikov 	EVENTHANDLER_INVOKE(iflladdr_event, ifp);
38621e80e4f2SGleb Smirnoff 
386391d6c9b9SMatt Macy 	return (0);
386466ce51ceSArchie Cobbs }
386566ce51ceSArchie Cobbs 
38669bf40edeSBrooks Davis /*
38674fb3a820SAlexander V. Chernikov  * Compat function for handling basic encapsulation requests.
38684fb3a820SAlexander V. Chernikov  * Not converted stacks (FDDI, IB, ..) supports traditional
38694fb3a820SAlexander V. Chernikov  * output model: ARP (and other similar L2 protocols) are handled
38704fb3a820SAlexander V. Chernikov  * inside output routine, arpresolve/nd6_resolve() returns MAC
38714fb3a820SAlexander V. Chernikov  * address instead of full prepend.
38724fb3a820SAlexander V. Chernikov  *
38734fb3a820SAlexander V. Chernikov  * This function creates calculated header==MAC for IPv4/IPv6 and
38744fb3a820SAlexander V. Chernikov  * returns EAFNOSUPPORT (which is then handled in ARP code) for other
38754fb3a820SAlexander V. Chernikov  * address families.
38764fb3a820SAlexander V. Chernikov  */
38774fb3a820SAlexander V. Chernikov static int
38784fb3a820SAlexander V. Chernikov if_requestencap_default(struct ifnet *ifp, struct if_encap_req *req)
38794fb3a820SAlexander V. Chernikov {
38804fb3a820SAlexander V. Chernikov 
38814fb3a820SAlexander V. Chernikov 	if (req->rtype != IFENCAP_LL)
38824fb3a820SAlexander V. Chernikov 		return (EOPNOTSUPP);
38834fb3a820SAlexander V. Chernikov 
38844fb3a820SAlexander V. Chernikov 	if (req->bufsize < req->lladdr_len)
38854fb3a820SAlexander V. Chernikov 		return (ENOMEM);
38864fb3a820SAlexander V. Chernikov 
38874fb3a820SAlexander V. Chernikov 	switch (req->family) {
38884fb3a820SAlexander V. Chernikov 	case AF_INET:
38894fb3a820SAlexander V. Chernikov 	case AF_INET6:
38904fb3a820SAlexander V. Chernikov 		break;
38914fb3a820SAlexander V. Chernikov 	default:
38924fb3a820SAlexander V. Chernikov 		return (EAFNOSUPPORT);
38934fb3a820SAlexander V. Chernikov 	}
38944fb3a820SAlexander V. Chernikov 
38954fb3a820SAlexander V. Chernikov 	/* Copy lladdr to storage as is */
38964fb3a820SAlexander V. Chernikov 	memmove(req->buf, req->lladdr, req->lladdr_len);
38974fb3a820SAlexander V. Chernikov 	req->bufsize = req->lladdr_len;
38984fb3a820SAlexander V. Chernikov 	req->lladdr_off = 0;
38994fb3a820SAlexander V. Chernikov 
39004fb3a820SAlexander V. Chernikov 	return (0);
39014fb3a820SAlexander V. Chernikov }
39024fb3a820SAlexander V. Chernikov 
39034fb3a820SAlexander V. Chernikov /*
390498a8fdf6SAndrey V. Elsukov  * Tunnel interfaces can nest, also they may cause infinite recursion
390598a8fdf6SAndrey V. Elsukov  * calls when misconfigured. We'll prevent this by detecting loops.
390698a8fdf6SAndrey V. Elsukov  * High nesting level may cause stack exhaustion. We'll prevent this
390798a8fdf6SAndrey V. Elsukov  * by introducing upper limit.
390898a8fdf6SAndrey V. Elsukov  *
390998a8fdf6SAndrey V. Elsukov  * Return 0, if tunnel nesting count is equal or less than limit.
391098a8fdf6SAndrey V. Elsukov  */
391198a8fdf6SAndrey V. Elsukov int
391298a8fdf6SAndrey V. Elsukov if_tunnel_check_nesting(struct ifnet *ifp, struct mbuf *m, uint32_t cookie,
391398a8fdf6SAndrey V. Elsukov     int limit)
391498a8fdf6SAndrey V. Elsukov {
391598a8fdf6SAndrey V. Elsukov 	struct m_tag *mtag;
391698a8fdf6SAndrey V. Elsukov 	int count;
391798a8fdf6SAndrey V. Elsukov 
391898a8fdf6SAndrey V. Elsukov 	count = 1;
391998a8fdf6SAndrey V. Elsukov 	mtag = NULL;
392098a8fdf6SAndrey V. Elsukov 	while ((mtag = m_tag_locate(m, cookie, 0, mtag)) != NULL) {
392198a8fdf6SAndrey V. Elsukov 		if (*(struct ifnet **)(mtag + 1) == ifp) {
392298a8fdf6SAndrey V. Elsukov 			log(LOG_NOTICE, "%s: loop detected\n", if_name(ifp));
392398a8fdf6SAndrey V. Elsukov 			return (EIO);
392498a8fdf6SAndrey V. Elsukov 		}
392598a8fdf6SAndrey V. Elsukov 		count++;
392698a8fdf6SAndrey V. Elsukov 	}
392798a8fdf6SAndrey V. Elsukov 	if (count > limit) {
392898a8fdf6SAndrey V. Elsukov 		log(LOG_NOTICE,
392998a8fdf6SAndrey V. Elsukov 		    "%s: if_output recursively called too many times(%d)\n",
393098a8fdf6SAndrey V. Elsukov 		    if_name(ifp), count);
393198a8fdf6SAndrey V. Elsukov 		return (EIO);
393298a8fdf6SAndrey V. Elsukov 	}
393398a8fdf6SAndrey V. Elsukov 	mtag = m_tag_alloc(cookie, 0, sizeof(struct ifnet *), M_NOWAIT);
393498a8fdf6SAndrey V. Elsukov 	if (mtag == NULL)
393598a8fdf6SAndrey V. Elsukov 		return (ENOMEM);
393698a8fdf6SAndrey V. Elsukov 	*(struct ifnet **)(mtag + 1) = ifp;
393798a8fdf6SAndrey V. Elsukov 	m_tag_prepend(m, mtag);
393898a8fdf6SAndrey V. Elsukov 	return (0);
393998a8fdf6SAndrey V. Elsukov }
394098a8fdf6SAndrey V. Elsukov 
394198a8fdf6SAndrey V. Elsukov /*
3942ddae5750SRavi Pokala  * Get the link layer address that was read from the hardware at attach.
3943ddae5750SRavi Pokala  *
3944ddae5750SRavi Pokala  * This is only set by Ethernet NICs (IFT_ETHER), but laggX interfaces re-type
3945ddae5750SRavi Pokala  * their component interfaces as IFT_IEEE8023ADLAG.
3946ddae5750SRavi Pokala  */
3947ddae5750SRavi Pokala int
3948ddae5750SRavi Pokala if_gethwaddr(struct ifnet *ifp, struct ifreq *ifr)
3949ddae5750SRavi Pokala {
3950ddae5750SRavi Pokala 
3951ddae5750SRavi Pokala 	if (ifp->if_hw_addr == NULL)
3952ddae5750SRavi Pokala 		return (ENODEV);
3953ddae5750SRavi Pokala 
3954ddae5750SRavi Pokala 	switch (ifp->if_type) {
3955ddae5750SRavi Pokala 	case IFT_ETHER:
3956ddae5750SRavi Pokala 	case IFT_IEEE8023ADLAG:
3957ddae5750SRavi Pokala 		bcopy(ifp->if_hw_addr, ifr->ifr_addr.sa_data, ifp->if_addrlen);
3958ddae5750SRavi Pokala 		return (0);
3959ddae5750SRavi Pokala 	default:
3960ddae5750SRavi Pokala 		return (ENODEV);
3961ddae5750SRavi Pokala 	}
3962ddae5750SRavi Pokala }
3963ddae5750SRavi Pokala 
3964ddae5750SRavi Pokala /*
39659bf40edeSBrooks Davis  * The name argument must be a pointer to storage which will last as
39669bf40edeSBrooks Davis  * long as the interface does.  For physical devices, the result of
39679bf40edeSBrooks Davis  * device_get_name(dev) is a good choice and for pseudo-devices a
39689bf40edeSBrooks Davis  * static string works well.
39699bf40edeSBrooks Davis  */
39709bf40edeSBrooks Davis void
39719bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit)
39729bf40edeSBrooks Davis {
39739bf40edeSBrooks Davis 	ifp->if_dname = name;
39749bf40edeSBrooks Davis 	ifp->if_dunit = unit;
39759bf40edeSBrooks Davis 	if (unit != IF_DUNIT_NONE)
39769bf40edeSBrooks Davis 		snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit);
39779bf40edeSBrooks Davis 	else
39789bf40edeSBrooks Davis 		strlcpy(ifp->if_xname, name, IFNAMSIZ);
39799bf40edeSBrooks Davis }
39809bf40edeSBrooks Davis 
398125bfa448SAdrian Chadd static int
398225bfa448SAdrian Chadd if_vlog(struct ifnet *ifp, int pri, const char *fmt, va_list ap)
398325bfa448SAdrian Chadd {
398425bfa448SAdrian Chadd 	char if_fmt[256];
398525bfa448SAdrian Chadd 
398625bfa448SAdrian Chadd 	snprintf(if_fmt, sizeof(if_fmt), "%s: %s", ifp->if_xname, fmt);
398725bfa448SAdrian Chadd 	vlog(pri, if_fmt, ap);
398825bfa448SAdrian Chadd 	return (0);
398925bfa448SAdrian Chadd }
399025bfa448SAdrian Chadd 
399125bfa448SAdrian Chadd 
3992fa882e87SBrooks Davis int
3993fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char *fmt, ...)
3994fa882e87SBrooks Davis {
3995fa882e87SBrooks Davis 	va_list ap;
3996fa882e87SBrooks Davis 
3997fa882e87SBrooks Davis 	va_start(ap, fmt);
399825bfa448SAdrian Chadd 	if_vlog(ifp, LOG_INFO, fmt, ap);
399925bfa448SAdrian Chadd 	va_end(ap);
400025bfa448SAdrian Chadd 	return (0);
400125bfa448SAdrian Chadd }
400225bfa448SAdrian Chadd 
400325bfa448SAdrian Chadd int
400425bfa448SAdrian Chadd if_log(struct ifnet *ifp, int pri, const char *fmt, ...)
400525bfa448SAdrian Chadd {
400625bfa448SAdrian Chadd 	va_list ap;
400725bfa448SAdrian Chadd 
400825bfa448SAdrian Chadd 	va_start(ap, fmt);
400925bfa448SAdrian Chadd 	if_vlog(ifp, pri, fmt, ap);
4010fa882e87SBrooks Davis 	va_end(ap);
401120f8d7bcSDag-Erling Smørgrav 	return (0);
4012fa882e87SBrooks Davis }
4013fa882e87SBrooks Davis 
4014af5e59bfSRobert Watson void
4015af5e59bfSRobert Watson if_start(struct ifnet *ifp)
4016af5e59bfSRobert Watson {
4017af5e59bfSRobert Watson 
4018af5e59bfSRobert Watson 	(*(ifp)->if_start)(ifp);
4019af5e59bfSRobert Watson }
4020af5e59bfSRobert Watson 
4021db7f0b97SKip Macy /*
4022db7f0b97SKip Macy  * Backwards compatibility interface for drivers
4023db7f0b97SKip Macy  * that have not implemented it
4024db7f0b97SKip Macy  */
4025db7f0b97SKip Macy static int
4026db7f0b97SKip Macy if_transmit(struct ifnet *ifp, struct mbuf *m)
4027db7f0b97SKip Macy {
4028db7f0b97SKip Macy 	int error;
4029db7f0b97SKip Macy 
4030db7f0b97SKip Macy 	IFQ_HANDOFF(ifp, m, error);
4031db7f0b97SKip Macy 	return (error);
4032db7f0b97SKip Macy }
4033db7f0b97SKip Macy 
4034b57d9721SAndrey V. Elsukov static void
4035b57d9721SAndrey V. Elsukov if_input_default(struct ifnet *ifp __unused, struct mbuf *m)
4036b57d9721SAndrey V. Elsukov {
4037b57d9721SAndrey V. Elsukov 
4038b57d9721SAndrey V. Elsukov 	m_freem(m);
4039b57d9721SAndrey V. Elsukov }
4040b57d9721SAndrey V. Elsukov 
40410b762445SRobert Watson int
40420b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
40430b762445SRobert Watson {
40440b762445SRobert Watson 	int active = 0;
40450b762445SRobert Watson 
40460b762445SRobert Watson 	IF_LOCK(ifq);
40470b762445SRobert Watson 	if (_IF_QFULL(ifq)) {
40480b762445SRobert Watson 		IF_UNLOCK(ifq);
4049112f50ffSGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OQDROPS, 1);
40500b762445SRobert Watson 		m_freem(m);
40510b762445SRobert Watson 		return (0);
40520b762445SRobert Watson 	}
40530b762445SRobert Watson 	if (ifp != NULL) {
4054112f50ffSGleb Smirnoff 		if_inc_counter(ifp, IFCOUNTER_OBYTES, m->m_pkthdr.len + adjust);
40550b762445SRobert Watson 		if (m->m_flags & (M_BCAST|M_MCAST))
4056112f50ffSGleb Smirnoff 			if_inc_counter(ifp, IFCOUNTER_OMCASTS, 1);
4057292ee7beSRobert Watson 		active = ifp->if_drv_flags & IFF_DRV_OACTIVE;
40580b762445SRobert Watson 	}
40590b762445SRobert Watson 	_IF_ENQUEUE(ifq, m);
40600b762445SRobert Watson 	IF_UNLOCK(ifq);
40610b762445SRobert Watson 	if (ifp != NULL && !active)
4062e5adda3dSRobert Watson 		(*(ifp)->if_start)(ifp);
40630b762445SRobert Watson 	return (1);
40640b762445SRobert Watson }
4065fc74a9f9SBrooks Davis 
4066fc74a9f9SBrooks Davis void
4067fc74a9f9SBrooks Davis if_register_com_alloc(u_char type,
4068fc74a9f9SBrooks Davis     if_com_alloc_t *a, if_com_free_t *f)
4069fc74a9f9SBrooks Davis {
4070fc74a9f9SBrooks Davis 
4071fc74a9f9SBrooks Davis 	KASSERT(if_com_alloc[type] == NULL,
4072fc74a9f9SBrooks Davis 	    ("if_register_com_alloc: %d already registered", type));
4073fc74a9f9SBrooks Davis 	KASSERT(if_com_free[type] == NULL,
4074fc74a9f9SBrooks Davis 	    ("if_register_com_alloc: %d free already registered", type));
4075fc74a9f9SBrooks Davis 
4076fc74a9f9SBrooks Davis 	if_com_alloc[type] = a;
4077fc74a9f9SBrooks Davis 	if_com_free[type] = f;
4078fc74a9f9SBrooks Davis }
4079fc74a9f9SBrooks Davis 
4080fc74a9f9SBrooks Davis void
4081fc74a9f9SBrooks Davis if_deregister_com_alloc(u_char type)
4082fc74a9f9SBrooks Davis {
4083fc74a9f9SBrooks Davis 
4084affcaf78SMax Khon 	KASSERT(if_com_alloc[type] != NULL,
4085fc74a9f9SBrooks Davis 	    ("if_deregister_com_alloc: %d not registered", type));
4086affcaf78SMax Khon 	KASSERT(if_com_free[type] != NULL,
4087fc74a9f9SBrooks Davis 	    ("if_deregister_com_alloc: %d free not registered", type));
4088092f3f08STai-hwa Liang 
4089092f3f08STai-hwa Liang 	/*
4090092f3f08STai-hwa Liang 	 * Ensure all pending EPOCH(9) callbacks have been executed. This
4091092f3f08STai-hwa Liang 	 * fixes issues about late invocation of if_destroy(), which leads
4092092f3f08STai-hwa Liang 	 * to memory leak from if_com_alloc[type] allocated if_l2com.
4093092f3f08STai-hwa Liang 	 */
4094092f3f08STai-hwa Liang 	epoch_drain_callbacks(net_epoch_preempt);
4095092f3f08STai-hwa Liang 
4096fc74a9f9SBrooks Davis 	if_com_alloc[type] = NULL;
4097fc74a9f9SBrooks Davis 	if_com_free[type] = NULL;
4098fc74a9f9SBrooks Davis }
409962d76917SMarcel Moolenaar 
410062d76917SMarcel Moolenaar /* API for driver access to network stack owned ifnet.*/
410162d76917SMarcel Moolenaar uint64_t
410209a8241fSGleb Smirnoff if_setbaudrate(struct ifnet *ifp, uint64_t baudrate)
410362d76917SMarcel Moolenaar {
410462d76917SMarcel Moolenaar 	uint64_t oldbrate;
410562d76917SMarcel Moolenaar 
410662d76917SMarcel Moolenaar 	oldbrate = ifp->if_baudrate;
410762d76917SMarcel Moolenaar 	ifp->if_baudrate = baudrate;
410862d76917SMarcel Moolenaar 	return (oldbrate);
410962d76917SMarcel Moolenaar }
411062d76917SMarcel Moolenaar 
411162d76917SMarcel Moolenaar uint64_t
411262d76917SMarcel Moolenaar if_getbaudrate(if_t ifp)
411362d76917SMarcel Moolenaar {
411462d76917SMarcel Moolenaar 
411562d76917SMarcel Moolenaar 	return (((struct ifnet *)ifp)->if_baudrate);
411662d76917SMarcel Moolenaar }
411762d76917SMarcel Moolenaar 
411862d76917SMarcel Moolenaar int
411962d76917SMarcel Moolenaar if_setcapabilities(if_t ifp, int capabilities)
412062d76917SMarcel Moolenaar {
412162d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capabilities = capabilities;
412262d76917SMarcel Moolenaar 	return (0);
412362d76917SMarcel Moolenaar }
412462d76917SMarcel Moolenaar 
412562d76917SMarcel Moolenaar int
412662d76917SMarcel Moolenaar if_setcapabilitiesbit(if_t ifp, int setbit, int clearbit)
412762d76917SMarcel Moolenaar {
412862d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capabilities |= setbit;
412962d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capabilities &= ~clearbit;
413062d76917SMarcel Moolenaar 
413162d76917SMarcel Moolenaar 	return (0);
413262d76917SMarcel Moolenaar }
413362d76917SMarcel Moolenaar 
413462d76917SMarcel Moolenaar int
413562d76917SMarcel Moolenaar if_getcapabilities(if_t ifp)
413662d76917SMarcel Moolenaar {
413762d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_capabilities;
413862d76917SMarcel Moolenaar }
413962d76917SMarcel Moolenaar 
414062d76917SMarcel Moolenaar int
414162d76917SMarcel Moolenaar if_setcapenable(if_t ifp, int capabilities)
414262d76917SMarcel Moolenaar {
414362d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capenable = capabilities;
414462d76917SMarcel Moolenaar 	return (0);
414562d76917SMarcel Moolenaar }
414662d76917SMarcel Moolenaar 
414762d76917SMarcel Moolenaar int
414862d76917SMarcel Moolenaar if_setcapenablebit(if_t ifp, int setcap, int clearcap)
414962d76917SMarcel Moolenaar {
415062d76917SMarcel Moolenaar 	if(setcap)
415162d76917SMarcel Moolenaar 		((struct ifnet *)ifp)->if_capenable |= setcap;
415262d76917SMarcel Moolenaar 	if(clearcap)
415362d76917SMarcel Moolenaar 		((struct ifnet *)ifp)->if_capenable &= ~clearcap;
415462d76917SMarcel Moolenaar 
415562d76917SMarcel Moolenaar 	return (0);
415662d76917SMarcel Moolenaar }
415762d76917SMarcel Moolenaar 
415862d76917SMarcel Moolenaar const char *
415962d76917SMarcel Moolenaar if_getdname(if_t ifp)
416062d76917SMarcel Moolenaar {
416162d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_dname;
416262d76917SMarcel Moolenaar }
416362d76917SMarcel Moolenaar 
416462d76917SMarcel Moolenaar int
416562d76917SMarcel Moolenaar if_togglecapenable(if_t ifp, int togglecap)
416662d76917SMarcel Moolenaar {
416762d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_capenable ^= togglecap;
416862d76917SMarcel Moolenaar 	return (0);
416962d76917SMarcel Moolenaar }
417062d76917SMarcel Moolenaar 
417162d76917SMarcel Moolenaar int
417262d76917SMarcel Moolenaar if_getcapenable(if_t ifp)
417362d76917SMarcel Moolenaar {
417462d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_capenable;
417562d76917SMarcel Moolenaar }
417662d76917SMarcel Moolenaar 
417762d76917SMarcel Moolenaar /*
417862d76917SMarcel Moolenaar  * This is largely undesirable because it ties ifnet to a device, but does
417962d76917SMarcel Moolenaar  * provide flexiblity for an embedded product vendor. Should be used with
418062d76917SMarcel Moolenaar  * the understanding that it violates the interface boundaries, and should be
418162d76917SMarcel Moolenaar  * a last resort only.
418262d76917SMarcel Moolenaar  */
418362d76917SMarcel Moolenaar int
418462d76917SMarcel Moolenaar if_setdev(if_t ifp, void *dev)
418562d76917SMarcel Moolenaar {
418662d76917SMarcel Moolenaar 	return (0);
418762d76917SMarcel Moolenaar }
418862d76917SMarcel Moolenaar 
418962d76917SMarcel Moolenaar int
419062d76917SMarcel Moolenaar if_setdrvflagbits(if_t ifp, int set_flags, int clear_flags)
419162d76917SMarcel Moolenaar {
419262d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_drv_flags |= set_flags;
419362d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_drv_flags &= ~clear_flags;
419462d76917SMarcel Moolenaar 
419562d76917SMarcel Moolenaar 	return (0);
419662d76917SMarcel Moolenaar }
419762d76917SMarcel Moolenaar 
419862d76917SMarcel Moolenaar int
419962d76917SMarcel Moolenaar if_getdrvflags(if_t ifp)
420062d76917SMarcel Moolenaar {
420162d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_drv_flags;
420262d76917SMarcel Moolenaar }
420362d76917SMarcel Moolenaar 
420462d76917SMarcel Moolenaar int
420562d76917SMarcel Moolenaar if_setdrvflags(if_t ifp, int flags)
420662d76917SMarcel Moolenaar {
420762d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_drv_flags = flags;
420862d76917SMarcel Moolenaar 	return (0);
420962d76917SMarcel Moolenaar }
421062d76917SMarcel Moolenaar 
421162d76917SMarcel Moolenaar int
421262d76917SMarcel Moolenaar if_setflags(if_t ifp, int flags)
421362d76917SMarcel Moolenaar {
4214e87c4940SGleb Smirnoff 
4215e87c4940SGleb Smirnoff 	ifp->if_flags = flags;
421662d76917SMarcel Moolenaar 	return (0);
421762d76917SMarcel Moolenaar }
421862d76917SMarcel Moolenaar 
421962d76917SMarcel Moolenaar int
422062d76917SMarcel Moolenaar if_setflagbits(if_t ifp, int set, int clear)
422162d76917SMarcel Moolenaar {
422262d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_flags |= set;
422362d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_flags &= ~clear;
422462d76917SMarcel Moolenaar 
422562d76917SMarcel Moolenaar 	return (0);
422662d76917SMarcel Moolenaar }
422762d76917SMarcel Moolenaar 
422862d76917SMarcel Moolenaar int
422962d76917SMarcel Moolenaar if_getflags(if_t ifp)
423062d76917SMarcel Moolenaar {
423162d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_flags;
423262d76917SMarcel Moolenaar }
423362d76917SMarcel Moolenaar 
423462d76917SMarcel Moolenaar int
423562d76917SMarcel Moolenaar if_clearhwassist(if_t ifp)
423662d76917SMarcel Moolenaar {
423762d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist = 0;
423862d76917SMarcel Moolenaar 	return (0);
423962d76917SMarcel Moolenaar }
424062d76917SMarcel Moolenaar 
424162d76917SMarcel Moolenaar int
424262d76917SMarcel Moolenaar if_sethwassistbits(if_t ifp, int toset, int toclear)
424362d76917SMarcel Moolenaar {
424462d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist |= toset;
424562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist &= ~toclear;
424662d76917SMarcel Moolenaar 
424762d76917SMarcel Moolenaar 	return (0);
424862d76917SMarcel Moolenaar }
424962d76917SMarcel Moolenaar 
425062d76917SMarcel Moolenaar int
425162d76917SMarcel Moolenaar if_sethwassist(if_t ifp, int hwassist_bit)
425262d76917SMarcel Moolenaar {
425362d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_hwassist = hwassist_bit;
425462d76917SMarcel Moolenaar 	return (0);
425562d76917SMarcel Moolenaar }
425662d76917SMarcel Moolenaar 
425762d76917SMarcel Moolenaar int
425862d76917SMarcel Moolenaar if_gethwassist(if_t ifp)
425962d76917SMarcel Moolenaar {
426062d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_hwassist;
426162d76917SMarcel Moolenaar }
426262d76917SMarcel Moolenaar 
426362d76917SMarcel Moolenaar int
426462d76917SMarcel Moolenaar if_setmtu(if_t ifp, int mtu)
426562d76917SMarcel Moolenaar {
426662d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_mtu = mtu;
426762d76917SMarcel Moolenaar 	return (0);
426862d76917SMarcel Moolenaar }
426962d76917SMarcel Moolenaar 
427062d76917SMarcel Moolenaar int
427162d76917SMarcel Moolenaar if_getmtu(if_t ifp)
427262d76917SMarcel Moolenaar {
427362d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_mtu;
427462d76917SMarcel Moolenaar }
427562d76917SMarcel Moolenaar 
427662d76917SMarcel Moolenaar int
42771a75e3b2SAlexander V. Chernikov if_getmtu_family(if_t ifp, int family)
42781a75e3b2SAlexander V. Chernikov {
42791a75e3b2SAlexander V. Chernikov 	struct domain *dp;
42801a75e3b2SAlexander V. Chernikov 
42811a75e3b2SAlexander V. Chernikov 	for (dp = domains; dp; dp = dp->dom_next) {
42821a75e3b2SAlexander V. Chernikov 		if (dp->dom_family == family && dp->dom_ifmtu != NULL)
42831a75e3b2SAlexander V. Chernikov 			return (dp->dom_ifmtu((struct ifnet *)ifp));
42841a75e3b2SAlexander V. Chernikov 	}
42851a75e3b2SAlexander V. Chernikov 
42861a75e3b2SAlexander V. Chernikov 	return (((struct ifnet *)ifp)->if_mtu);
42871a75e3b2SAlexander V. Chernikov }
42881a75e3b2SAlexander V. Chernikov 
4289826857c8SGleb Smirnoff /*
4290826857c8SGleb Smirnoff  * Methods for drivers to access interface unicast and multicast
4291826857c8SGleb Smirnoff  * link level addresses.  Driver shall not know 'struct ifaddr' neither
4292826857c8SGleb Smirnoff  * 'struct ifmultiaddr'.
4293826857c8SGleb Smirnoff  */
4294826857c8SGleb Smirnoff u_int
4295fb3fc771SGleb Smirnoff if_lladdr_count(if_t ifp)
4296fb3fc771SGleb Smirnoff {
4297fb3fc771SGleb Smirnoff 	struct epoch_tracker et;
4298fb3fc771SGleb Smirnoff 	struct ifaddr *ifa;
4299fb3fc771SGleb Smirnoff 	u_int count;
4300fb3fc771SGleb Smirnoff 
4301fb3fc771SGleb Smirnoff 	count = 0;
4302fb3fc771SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4303fb3fc771SGleb Smirnoff 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
4304fb3fc771SGleb Smirnoff 		if (ifa->ifa_addr->sa_family == AF_LINK)
4305fb3fc771SGleb Smirnoff 			count++;
4306fb3fc771SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4307fb3fc771SGleb Smirnoff 
4308fb3fc771SGleb Smirnoff 	return (count);
4309fb3fc771SGleb Smirnoff }
4310fb3fc771SGleb Smirnoff 
4311fb3fc771SGleb Smirnoff u_int
4312826857c8SGleb Smirnoff if_foreach_lladdr(if_t ifp, iflladdr_cb_t cb, void *cb_arg)
4313826857c8SGleb Smirnoff {
4314826857c8SGleb Smirnoff 	struct epoch_tracker et;
4315826857c8SGleb Smirnoff 	struct ifaddr *ifa;
4316826857c8SGleb Smirnoff 	u_int count;
4317826857c8SGleb Smirnoff 
4318826857c8SGleb Smirnoff 	MPASS(cb);
4319826857c8SGleb Smirnoff 
4320826857c8SGleb Smirnoff 	count = 0;
4321826857c8SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4322826857c8SGleb Smirnoff 	CK_STAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
4323826857c8SGleb Smirnoff 		if (ifa->ifa_addr->sa_family != AF_LINK)
4324826857c8SGleb Smirnoff 			continue;
4325826857c8SGleb Smirnoff 		count += (*cb)(cb_arg, (struct sockaddr_dl *)ifa->ifa_addr,
4326826857c8SGleb Smirnoff 		    count);
4327826857c8SGleb Smirnoff 	}
4328826857c8SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4329826857c8SGleb Smirnoff 
4330826857c8SGleb Smirnoff 	return (count);
4331826857c8SGleb Smirnoff }
4332826857c8SGleb Smirnoff 
4333826857c8SGleb Smirnoff u_int
4334fb3fc771SGleb Smirnoff if_llmaddr_count(if_t ifp)
4335fb3fc771SGleb Smirnoff {
4336fb3fc771SGleb Smirnoff 	struct epoch_tracker et;
4337fb3fc771SGleb Smirnoff 	struct ifmultiaddr *ifma;
4338fb3fc771SGleb Smirnoff 	int count;
4339fb3fc771SGleb Smirnoff 
4340fb3fc771SGleb Smirnoff 	count = 0;
4341fb3fc771SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4342fb3fc771SGleb Smirnoff 	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
4343fb3fc771SGleb Smirnoff 		if (ifma->ifma_addr->sa_family == AF_LINK)
4344fb3fc771SGleb Smirnoff 			count++;
4345fb3fc771SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4346fb3fc771SGleb Smirnoff 
4347fb3fc771SGleb Smirnoff 	return (count);
4348fb3fc771SGleb Smirnoff }
4349fb3fc771SGleb Smirnoff 
4350fb3fc771SGleb Smirnoff u_int
4351826857c8SGleb Smirnoff if_foreach_llmaddr(if_t ifp, iflladdr_cb_t cb, void *cb_arg)
4352826857c8SGleb Smirnoff {
4353826857c8SGleb Smirnoff 	struct epoch_tracker et;
4354826857c8SGleb Smirnoff 	struct ifmultiaddr *ifma;
4355826857c8SGleb Smirnoff 	u_int count;
4356826857c8SGleb Smirnoff 
4357826857c8SGleb Smirnoff 	MPASS(cb);
4358826857c8SGleb Smirnoff 
4359826857c8SGleb Smirnoff 	count = 0;
4360826857c8SGleb Smirnoff 	NET_EPOCH_ENTER(et);
4361826857c8SGleb Smirnoff 	CK_STAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
4362826857c8SGleb Smirnoff 		if (ifma->ifma_addr->sa_family != AF_LINK)
4363826857c8SGleb Smirnoff 			continue;
4364826857c8SGleb Smirnoff 		count += (*cb)(cb_arg, (struct sockaddr_dl *)ifma->ifma_addr,
4365826857c8SGleb Smirnoff 		    count);
4366826857c8SGleb Smirnoff 	}
4367826857c8SGleb Smirnoff 	NET_EPOCH_EXIT(et);
4368826857c8SGleb Smirnoff 
4369826857c8SGleb Smirnoff 	return (count);
4370826857c8SGleb Smirnoff }
4371826857c8SGleb Smirnoff 
43721a75e3b2SAlexander V. Chernikov int
437362d76917SMarcel Moolenaar if_setsoftc(if_t ifp, void *softc)
437462d76917SMarcel Moolenaar {
437562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_softc = softc;
437662d76917SMarcel Moolenaar 	return (0);
437762d76917SMarcel Moolenaar }
437862d76917SMarcel Moolenaar 
437962d76917SMarcel Moolenaar void *
438062d76917SMarcel Moolenaar if_getsoftc(if_t ifp)
438162d76917SMarcel Moolenaar {
438262d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_softc;
438362d76917SMarcel Moolenaar }
438462d76917SMarcel Moolenaar 
438562d76917SMarcel Moolenaar void
438662d76917SMarcel Moolenaar if_setrcvif(struct mbuf *m, if_t ifp)
438762d76917SMarcel Moolenaar {
4388fb3bc596SJohn Baldwin 
4389fb3bc596SJohn Baldwin 	MPASS((m->m_pkthdr.csum_flags & CSUM_SND_TAG) == 0);
439062d76917SMarcel Moolenaar 	m->m_pkthdr.rcvif = (struct ifnet *)ifp;
439162d76917SMarcel Moolenaar }
439262d76917SMarcel Moolenaar 
439362d76917SMarcel Moolenaar void
439462d76917SMarcel Moolenaar if_setvtag(struct mbuf *m, uint16_t tag)
439562d76917SMarcel Moolenaar {
439662d76917SMarcel Moolenaar 	m->m_pkthdr.ether_vtag = tag;
439762d76917SMarcel Moolenaar }
439862d76917SMarcel Moolenaar 
439962d76917SMarcel Moolenaar uint16_t
440062d76917SMarcel Moolenaar if_getvtag(struct mbuf *m)
440162d76917SMarcel Moolenaar {
440262d76917SMarcel Moolenaar 
440362d76917SMarcel Moolenaar 	return (m->m_pkthdr.ether_vtag);
440462d76917SMarcel Moolenaar }
440562d76917SMarcel Moolenaar 
440662d76917SMarcel Moolenaar int
440762d76917SMarcel Moolenaar if_sendq_empty(if_t ifp)
440862d76917SMarcel Moolenaar {
440962d76917SMarcel Moolenaar 	return IFQ_DRV_IS_EMPTY(&((struct ifnet *)ifp)->if_snd);
441062d76917SMarcel Moolenaar }
441162d76917SMarcel Moolenaar 
441262d76917SMarcel Moolenaar struct ifaddr *
441362d76917SMarcel Moolenaar if_getifaddr(if_t ifp)
441462d76917SMarcel Moolenaar {
441562d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_addr;
441662d76917SMarcel Moolenaar }
441762d76917SMarcel Moolenaar 
441862d76917SMarcel Moolenaar int
441962d76917SMarcel Moolenaar if_getamcount(if_t ifp)
442062d76917SMarcel Moolenaar {
442162d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_amcount;
442262d76917SMarcel Moolenaar }
442362d76917SMarcel Moolenaar 
442462d76917SMarcel Moolenaar int
442562d76917SMarcel Moolenaar if_setsendqready(if_t ifp)
442662d76917SMarcel Moolenaar {
442762d76917SMarcel Moolenaar 	IFQ_SET_READY(&((struct ifnet *)ifp)->if_snd);
442862d76917SMarcel Moolenaar 	return (0);
442962d76917SMarcel Moolenaar }
443062d76917SMarcel Moolenaar 
443162d76917SMarcel Moolenaar int
443262d76917SMarcel Moolenaar if_setsendqlen(if_t ifp, int tx_desc_count)
443362d76917SMarcel Moolenaar {
443462d76917SMarcel Moolenaar 	IFQ_SET_MAXLEN(&((struct ifnet *)ifp)->if_snd, tx_desc_count);
443562d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_snd.ifq_drv_maxlen = tx_desc_count;
443662d76917SMarcel Moolenaar 
443762d76917SMarcel Moolenaar 	return (0);
443862d76917SMarcel Moolenaar }
443962d76917SMarcel Moolenaar 
444062d76917SMarcel Moolenaar int
444162d76917SMarcel Moolenaar if_vlantrunkinuse(if_t ifp)
444262d76917SMarcel Moolenaar {
444362d76917SMarcel Moolenaar 	return ((struct ifnet *)ifp)->if_vlantrunk != NULL?1:0;
444462d76917SMarcel Moolenaar }
444562d76917SMarcel Moolenaar 
444662d76917SMarcel Moolenaar int
444762d76917SMarcel Moolenaar if_input(if_t ifp, struct mbuf* sendmp)
444862d76917SMarcel Moolenaar {
444962d76917SMarcel Moolenaar 	(*((struct ifnet *)ifp)->if_input)((struct ifnet *)ifp, sendmp);
445062d76917SMarcel Moolenaar 	return (0);
445162d76917SMarcel Moolenaar 
445262d76917SMarcel Moolenaar }
445362d76917SMarcel Moolenaar 
445462d76917SMarcel Moolenaar struct mbuf *
445562d76917SMarcel Moolenaar if_dequeue(if_t ifp)
445662d76917SMarcel Moolenaar {
445762d76917SMarcel Moolenaar 	struct mbuf *m;
445862d76917SMarcel Moolenaar 	IFQ_DRV_DEQUEUE(&((struct ifnet *)ifp)->if_snd, m);
445962d76917SMarcel Moolenaar 
446062d76917SMarcel Moolenaar 	return (m);
446162d76917SMarcel Moolenaar }
446262d76917SMarcel Moolenaar 
446362d76917SMarcel Moolenaar int
446462d76917SMarcel Moolenaar if_sendq_prepend(if_t ifp, struct mbuf *m)
446562d76917SMarcel Moolenaar {
446662d76917SMarcel Moolenaar 	IFQ_DRV_PREPEND(&((struct ifnet *)ifp)->if_snd, m);
446762d76917SMarcel Moolenaar 	return (0);
446862d76917SMarcel Moolenaar }
446962d76917SMarcel Moolenaar 
447062d76917SMarcel Moolenaar int
447162d76917SMarcel Moolenaar if_setifheaderlen(if_t ifp, int len)
447262d76917SMarcel Moolenaar {
4473e6485f73SGleb Smirnoff 	((struct ifnet *)ifp)->if_hdrlen = len;
447462d76917SMarcel Moolenaar 	return (0);
447562d76917SMarcel Moolenaar }
447662d76917SMarcel Moolenaar 
447762d76917SMarcel Moolenaar caddr_t
447862d76917SMarcel Moolenaar if_getlladdr(if_t ifp)
447962d76917SMarcel Moolenaar {
448062d76917SMarcel Moolenaar 	return (IF_LLADDR((struct ifnet *)ifp));
448162d76917SMarcel Moolenaar }
448262d76917SMarcel Moolenaar 
448362d76917SMarcel Moolenaar void *
448462d76917SMarcel Moolenaar if_gethandle(u_char type)
448562d76917SMarcel Moolenaar {
448662d76917SMarcel Moolenaar 	return (if_alloc(type));
448762d76917SMarcel Moolenaar }
448862d76917SMarcel Moolenaar 
448962d76917SMarcel Moolenaar void
449062d76917SMarcel Moolenaar if_bpfmtap(if_t ifh, struct mbuf *m)
449162d76917SMarcel Moolenaar {
449262d76917SMarcel Moolenaar 	struct ifnet *ifp = (struct ifnet *)ifh;
449362d76917SMarcel Moolenaar 
449462d76917SMarcel Moolenaar 	BPF_MTAP(ifp, m);
449562d76917SMarcel Moolenaar }
449662d76917SMarcel Moolenaar 
449762d76917SMarcel Moolenaar void
449862d76917SMarcel Moolenaar if_etherbpfmtap(if_t ifh, struct mbuf *m)
449962d76917SMarcel Moolenaar {
450062d76917SMarcel Moolenaar 	struct ifnet *ifp = (struct ifnet *)ifh;
450162d76917SMarcel Moolenaar 
450262d76917SMarcel Moolenaar 	ETHER_BPF_MTAP(ifp, m);
450362d76917SMarcel Moolenaar }
450462d76917SMarcel Moolenaar 
450562d76917SMarcel Moolenaar void
450662d76917SMarcel Moolenaar if_vlancap(if_t ifh)
450762d76917SMarcel Moolenaar {
450862d76917SMarcel Moolenaar 	struct ifnet *ifp = (struct ifnet *)ifh;
450962d76917SMarcel Moolenaar 	VLAN_CAPABILITIES(ifp);
451062d76917SMarcel Moolenaar }
451162d76917SMarcel Moolenaar 
4512d0b2cad1SStephen J. Kiernan int
4513d0b2cad1SStephen J. Kiernan if_sethwtsomax(if_t ifp, u_int if_hw_tsomax)
4514d0b2cad1SStephen J. Kiernan {
4515d0b2cad1SStephen J. Kiernan 
4516d0b2cad1SStephen J. Kiernan 	((struct ifnet *)ifp)->if_hw_tsomax = if_hw_tsomax;
4517d0b2cad1SStephen J. Kiernan         return (0);
4518d0b2cad1SStephen J. Kiernan }
4519d0b2cad1SStephen J. Kiernan 
4520d0b2cad1SStephen J. Kiernan int
4521d0b2cad1SStephen J. Kiernan if_sethwtsomaxsegcount(if_t ifp, u_int if_hw_tsomaxsegcount)
4522d0b2cad1SStephen J. Kiernan {
4523d0b2cad1SStephen J. Kiernan 
4524d0b2cad1SStephen J. Kiernan 	((struct ifnet *)ifp)->if_hw_tsomaxsegcount = if_hw_tsomaxsegcount;
4525d0b2cad1SStephen J. Kiernan         return (0);
4526d0b2cad1SStephen J. Kiernan }
4527d0b2cad1SStephen J. Kiernan 
4528d0b2cad1SStephen J. Kiernan int
4529d0b2cad1SStephen J. Kiernan if_sethwtsomaxsegsize(if_t ifp, u_int if_hw_tsomaxsegsize)
4530d0b2cad1SStephen J. Kiernan {
4531d0b2cad1SStephen J. Kiernan 
4532d0b2cad1SStephen J. Kiernan 	((struct ifnet *)ifp)->if_hw_tsomaxsegsize = if_hw_tsomaxsegsize;
4533d0b2cad1SStephen J. Kiernan         return (0);
4534d0b2cad1SStephen J. Kiernan }
4535d0b2cad1SStephen J. Kiernan 
4536d0b2cad1SStephen J. Kiernan u_int
4537d0b2cad1SStephen J. Kiernan if_gethwtsomax(if_t ifp)
4538d0b2cad1SStephen J. Kiernan {
4539d0b2cad1SStephen J. Kiernan 
4540d0b2cad1SStephen J. Kiernan 	return (((struct ifnet *)ifp)->if_hw_tsomax);
4541d0b2cad1SStephen J. Kiernan }
4542d0b2cad1SStephen J. Kiernan 
4543d0b2cad1SStephen J. Kiernan u_int
4544d0b2cad1SStephen J. Kiernan if_gethwtsomaxsegcount(if_t ifp)
4545d0b2cad1SStephen J. Kiernan {
4546d0b2cad1SStephen J. Kiernan 
4547d0b2cad1SStephen J. Kiernan 	return (((struct ifnet *)ifp)->if_hw_tsomaxsegcount);
4548d0b2cad1SStephen J. Kiernan }
4549d0b2cad1SStephen J. Kiernan 
4550d0b2cad1SStephen J. Kiernan u_int
4551d0b2cad1SStephen J. Kiernan if_gethwtsomaxsegsize(if_t ifp)
4552d0b2cad1SStephen J. Kiernan {
4553d0b2cad1SStephen J. Kiernan 
4554d0b2cad1SStephen J. Kiernan 	return (((struct ifnet *)ifp)->if_hw_tsomaxsegsize);
4555d0b2cad1SStephen J. Kiernan }
4556d0b2cad1SStephen J. Kiernan 
455762d76917SMarcel Moolenaar void
455862d76917SMarcel Moolenaar if_setinitfn(if_t ifp, void (*init_fn)(void *))
455962d76917SMarcel Moolenaar {
456062d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_init = init_fn;
456162d76917SMarcel Moolenaar }
456262d76917SMarcel Moolenaar 
456362d76917SMarcel Moolenaar void
456409a8241fSGleb Smirnoff if_setioctlfn(if_t ifp, int (*ioctl_fn)(if_t, u_long, caddr_t))
456562d76917SMarcel Moolenaar {
456662d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_ioctl = (void *)ioctl_fn;
456762d76917SMarcel Moolenaar }
456862d76917SMarcel Moolenaar 
456962d76917SMarcel Moolenaar void
457009a8241fSGleb Smirnoff if_setstartfn(if_t ifp, void (*start_fn)(if_t))
457162d76917SMarcel Moolenaar {
457262d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_start = (void *)start_fn;
457362d76917SMarcel Moolenaar }
457462d76917SMarcel Moolenaar 
457562d76917SMarcel Moolenaar void
457662d76917SMarcel Moolenaar if_settransmitfn(if_t ifp, if_transmit_fn_t start_fn)
457762d76917SMarcel Moolenaar {
457862d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_transmit = start_fn;
457962d76917SMarcel Moolenaar }
458062d76917SMarcel Moolenaar 
458162d76917SMarcel Moolenaar void if_setqflushfn(if_t ifp, if_qflush_fn_t flush_fn)
458262d76917SMarcel Moolenaar {
458362d76917SMarcel Moolenaar 	((struct ifnet *)ifp)->if_qflush = flush_fn;
458462d76917SMarcel Moolenaar 
458562d76917SMarcel Moolenaar }
458662d76917SMarcel Moolenaar 
458735853c2cSGleb Smirnoff void
458835853c2cSGleb Smirnoff if_setgetcounterfn(if_t ifp, if_get_counter_t fn)
458935853c2cSGleb Smirnoff {
459035853c2cSGleb Smirnoff 
459135853c2cSGleb Smirnoff 	ifp->if_get_counter = fn;
459235853c2cSGleb Smirnoff }
459335853c2cSGleb Smirnoff 
459462d76917SMarcel Moolenaar /* Revisit these - These are inline functions originally. */
459562d76917SMarcel Moolenaar int
459662d76917SMarcel Moolenaar drbr_inuse_drv(if_t ifh, struct buf_ring *br)
459762d76917SMarcel Moolenaar {
4598966ab68dSDimitry Andric 	return drbr_inuse(ifh, br);
459962d76917SMarcel Moolenaar }
460062d76917SMarcel Moolenaar 
460162d76917SMarcel Moolenaar struct mbuf*
460262d76917SMarcel Moolenaar drbr_dequeue_drv(if_t ifh, struct buf_ring *br)
460362d76917SMarcel Moolenaar {
460462d76917SMarcel Moolenaar 	return drbr_dequeue(ifh, br);
460562d76917SMarcel Moolenaar }
460662d76917SMarcel Moolenaar 
460762d76917SMarcel Moolenaar int
460862d76917SMarcel Moolenaar drbr_needs_enqueue_drv(if_t ifh, struct buf_ring *br)
460962d76917SMarcel Moolenaar {
461062d76917SMarcel Moolenaar 	return drbr_needs_enqueue(ifh, br);
461162d76917SMarcel Moolenaar }
461262d76917SMarcel Moolenaar 
461362d76917SMarcel Moolenaar int
461462d76917SMarcel Moolenaar drbr_enqueue_drv(if_t ifh, struct buf_ring *br, struct mbuf *m)
461562d76917SMarcel Moolenaar {
461662d76917SMarcel Moolenaar 	return drbr_enqueue(ifh, br, m);
461762d76917SMarcel Moolenaar 
461862d76917SMarcel Moolenaar }
4619