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