xref: /freebsd/sys/net/if.c (revision fbd24c5ed637a1750fabcb16f6e52a663a3b397b)
1c398230bSWarner Losh /*-
2df8bae1dSRodney W. Grimes  * Copyright (c) 1980, 1986, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
14df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
15df8bae1dSRodney W. Grimes  *    without specific prior written permission.
16df8bae1dSRodney W. Grimes  *
17df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
28df8bae1dSRodney W. Grimes  *
2966afbd68SRuslan Ermilov  *	@(#)if.c	8.5 (Berkeley) 1/9/95
30c3aac50fSPeter Wemm  * $FreeBSD$
31df8bae1dSRodney W. Grimes  */
32df8bae1dSRodney W. Grimes 
335591b823SEivind Eklund #include "opt_compat.h"
34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h"
350d0f9d1eSYoshinobu Inoue #include "opt_inet.h"
36e70cd263SRobert Watson #include "opt_mac.h"
37a9771948SGleb Smirnoff #include "opt_carp.h"
385591b823SEivind Eklund 
39df8bae1dSRodney W. Grimes #include <sys/param.h>
404dcf2bbbSBrooks Davis #include <sys/types.h>
41f13ad206SJonathan Lemon #include <sys/conf.h>
42e70cd263SRobert Watson #include <sys/mac.h>
434d1d4912SBruce Evans #include <sys/malloc.h>
444dcf2bbbSBrooks Davis #include <sys/sbuf.h>
45d2b4566aSJonathan Lemon #include <sys/bus.h>
46df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
47df8bae1dSRodney W. Grimes #include <sys/systm.h>
48df8bae1dSRodney W. Grimes #include <sys/proc.h>
49df8bae1dSRodney W. Grimes #include <sys/socket.h>
50df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
51df8bae1dSRodney W. Grimes #include <sys/protosw.h>
52df8bae1dSRodney W. Grimes #include <sys/kernel.h>
5351a53488SBruce Evans #include <sys/sockio.h>
54963e4c2aSGarrett Wollman #include <sys/syslog.h>
55602d513cSGarrett Wollman #include <sys/sysctl.h>
56af5e59bfSRobert Watson #include <sys/taskqueue.h>
5731b1bfe1SHajimu UMEMOTO #include <sys/domain.h>
5891421ba2SRobert Watson #include <sys/jail.h>
59fa882e87SBrooks Davis #include <machine/stdarg.h>
60df8bae1dSRodney W. Grimes 
61df8bae1dSRodney W. Grimes #include <net/if.h>
62b106252cSBill Paul #include <net/if_arp.h>
63f889d2efSBrooks Davis #include <net/if_clone.h>
64df8bae1dSRodney W. Grimes #include <net/if_dl.h>
6566ce51ceSArchie Cobbs #include <net/if_types.h>
6630aad87dSBrooks Davis #include <net/if_var.h>
679448326fSPoul-Henning Kamp #include <net/radix.h>
685500d3beSWarner Losh #include <net/route.h>
69df8bae1dSRodney W. Grimes 
700d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6)
7182cd038dSYoshinobu Inoue /*XXX*/
7282cd038dSYoshinobu Inoue #include <netinet/in.h>
730d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h>
743411310dSYoshinobu Inoue #ifdef INET6
75978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h>
76978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h>
773411310dSYoshinobu Inoue #endif
7882cd038dSYoshinobu Inoue #endif
79c0933269SPeter Wemm #ifdef INET
80c0933269SPeter Wemm #include <netinet/if_ether.h>
81c0933269SPeter Wemm #endif
82a9771948SGleb Smirnoff #ifdef DEV_CARP
83a9771948SGleb Smirnoff #include <netinet/ip_carp.h>
84a9771948SGleb Smirnoff #endif
8582cd038dSYoshinobu Inoue 
865515c2e7SGleb Smirnoff SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
875515c2e7SGleb Smirnoff SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
885515c2e7SGleb Smirnoff 
895515c2e7SGleb Smirnoff /* Log link state change events */
905515c2e7SGleb Smirnoff static int log_link_state_change = 1;
915515c2e7SGleb Smirnoff 
925515c2e7SGleb Smirnoff SYSCTL_INT(_net_link, OID_AUTO, log_link_state_change, CTLFLAG_RW,
935515c2e7SGleb Smirnoff 	&log_link_state_change, 0,
945515c2e7SGleb Smirnoff 	"log interface link state change events");
955515c2e7SGleb Smirnoff 
961c7899c7SGleb Smirnoff void	(*ng_ether_link_state_p)(struct ifnet *ifp, int state);
971c7899c7SGleb Smirnoff 
984cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
994cb655c0SMax Laier 
10031b1bfe1SHajimu UMEMOTO static void	if_attachdomain(void *);
10131b1bfe1SHajimu UMEMOTO static void	if_attachdomain1(struct ifnet *);
1020b59d917SJonathan Lemon static int	ifconf(u_long, caddr_t);
103f9132cebSJonathan Lemon static void	if_grow(void);
104f9132cebSJonathan Lemon static void	if_init(void *);
105f9132cebSJonathan Lemon static void	if_check(void *);
106ffb5a104SJonathan Lemon static int	if_findindex(struct ifnet *);
10702b199f1SMax Laier static void	if_qflush(struct ifaltq *);
1088614fb12SMax Laier static void	if_route(struct ifnet *, int flag, int fam);
1090b59d917SJonathan Lemon static void	if_slowtimo(void *);
1108614fb12SMax Laier static void	if_unroute(struct ifnet *, int flag, int fam);
1118071913dSRuslan Ermilov static void	link_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
1120b59d917SJonathan Lemon static int	if_rtdel(struct radix_node *, void *);
113f13ad206SJonathan Lemon static int	ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *);
114af5e59bfSRobert Watson static void	if_start_deferred(void *context, int pending);
11582cd038dSYoshinobu Inoue #ifdef INET6
11682cd038dSYoshinobu Inoue /*
11782cd038dSYoshinobu Inoue  * XXX: declare here to avoid to include many inet6 related files..
11882cd038dSYoshinobu Inoue  * should be more generalized?
11982cd038dSYoshinobu Inoue  */
120929ddbbbSAlfred Perlstein extern void	nd6_setmtu(struct ifnet *);
12182cd038dSYoshinobu Inoue #endif
12282cd038dSYoshinobu Inoue 
1230b59d917SJonathan Lemon int	if_index = 0;
124f9132cebSJonathan Lemon struct	ifindex_entry *ifindex_table = NULL;
1250b59d917SJonathan Lemon int	ifqmaxlen = IFQ_MAXLEN;
1260b59d917SJonathan Lemon struct	ifnethead ifnet;	/* depend on static init XXX */
127b30a244cSJeffrey Hsu struct	mtx ifnet_lock;
1280b59d917SJonathan Lemon 
129f9132cebSJonathan Lemon static int	if_indexlim = 8;
130ad3b9257SJohn-Mark Gurney static struct	knlist ifklist;
131f9132cebSJonathan Lemon 
1329a2a57a1SJonathan Lemon static void	filt_netdetach(struct knote *kn);
1339a2a57a1SJonathan Lemon static int	filt_netdev(struct knote *kn, long hint);
1349a2a57a1SJonathan Lemon 
1359a2a57a1SJonathan Lemon static struct filterops netdev_filtops =
1369a2a57a1SJonathan Lemon     { 1, NULL, filt_netdetach, filt_netdev };
1379a2a57a1SJonathan Lemon 
1380b59d917SJonathan Lemon /*
1390b59d917SJonathan Lemon  * System initialization
1400b59d917SJonathan Lemon  */
141f9132cebSJonathan Lemon SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL)
142f9132cebSJonathan Lemon SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL)
1430b59d917SJonathan Lemon 
1440b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
1450b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
14630aad87dSBrooks Davis 
147f13ad206SJonathan Lemon static d_open_t		netopen;
148f13ad206SJonathan Lemon static d_close_t	netclose;
149f13ad206SJonathan Lemon static d_ioctl_t	netioctl;
1509a2a57a1SJonathan Lemon static d_kqfilter_t	netkqfilter;
151f13ad206SJonathan Lemon 
152f13ad206SJonathan Lemon static struct cdevsw net_cdevsw = {
153dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
154dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1557ac40f5fSPoul-Henning Kamp 	.d_open =	netopen,
1567ac40f5fSPoul-Henning Kamp 	.d_close =	netclose,
1577ac40f5fSPoul-Henning Kamp 	.d_ioctl =	netioctl,
1587ac40f5fSPoul-Henning Kamp 	.d_name =	"net",
1597ac40f5fSPoul-Henning Kamp 	.d_kqfilter =	netkqfilter,
160f13ad206SJonathan Lemon };
161f13ad206SJonathan Lemon 
162f13ad206SJonathan Lemon static int
16389c9c53dSPoul-Henning Kamp netopen(struct cdev *dev, int flag, int mode, struct thread *td)
164f13ad206SJonathan Lemon {
165f13ad206SJonathan Lemon 	return (0);
166f13ad206SJonathan Lemon }
167f13ad206SJonathan Lemon 
168f13ad206SJonathan Lemon static int
16989c9c53dSPoul-Henning Kamp netclose(struct cdev *dev, int flags, int fmt, struct thread *td)
170f13ad206SJonathan Lemon {
171f13ad206SJonathan Lemon 	return (0);
172f13ad206SJonathan Lemon }
173f13ad206SJonathan Lemon 
174f13ad206SJonathan Lemon static int
17589c9c53dSPoul-Henning Kamp netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
176f13ad206SJonathan Lemon {
177f13ad206SJonathan Lemon 	struct ifnet *ifp;
178f13ad206SJonathan Lemon 	int error, idx;
179f13ad206SJonathan Lemon 
180f13ad206SJonathan Lemon 	/* only support interface specific ioctls */
181f13ad206SJonathan Lemon 	if (IOCGROUP(cmd) != 'i')
182f13ad206SJonathan Lemon 		return (EOPNOTSUPP);
183f13ad206SJonathan Lemon 	idx = minor(dev);
184f13ad206SJonathan Lemon 	if (idx == 0) {
185f13ad206SJonathan Lemon 		/*
186f13ad206SJonathan Lemon 		 * special network device, not interface.
187f13ad206SJonathan Lemon 		 */
188f13ad206SJonathan Lemon 		if (cmd == SIOCGIFCONF)
189f13ad206SJonathan Lemon 			return (ifconf(cmd, data));	/* XXX remove cmd */
190f13ad206SJonathan Lemon 		return (EOPNOTSUPP);
191f13ad206SJonathan Lemon 	}
192f13ad206SJonathan Lemon 
193f13ad206SJonathan Lemon 	ifp = ifnet_byindex(idx);
194f13ad206SJonathan Lemon 	if (ifp == NULL)
195f13ad206SJonathan Lemon 		return (ENXIO);
196f13ad206SJonathan Lemon 
197f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
198f13ad206SJonathan Lemon 	if (error == ENOIOCTL)
199f13ad206SJonathan Lemon 		error = EOPNOTSUPP;
200f13ad206SJonathan Lemon 	return (error);
201f13ad206SJonathan Lemon }
202f13ad206SJonathan Lemon 
2039a2a57a1SJonathan Lemon static int
20489c9c53dSPoul-Henning Kamp netkqfilter(struct cdev *dev, struct knote *kn)
2059a2a57a1SJonathan Lemon {
206ad3b9257SJohn-Mark Gurney 	struct knlist *klist;
2079a2a57a1SJonathan Lemon 	struct ifnet *ifp;
2089a2a57a1SJonathan Lemon 	int idx;
2099a2a57a1SJonathan Lemon 
210ad3b9257SJohn-Mark Gurney 	switch (kn->kn_filter) {
211ad3b9257SJohn-Mark Gurney 	case EVFILT_NETDEV:
212ad3b9257SJohn-Mark Gurney 		kn->kn_fop = &netdev_filtops;
213ad3b9257SJohn-Mark Gurney 		break;
214ad3b9257SJohn-Mark Gurney 	default:
215ad3b9257SJohn-Mark Gurney 		return (1);
216ad3b9257SJohn-Mark Gurney 	}
217ad3b9257SJohn-Mark Gurney 
2189a2a57a1SJonathan Lemon 	idx = minor(dev);
2199a2a57a1SJonathan Lemon 	if (idx == 0) {
2209a2a57a1SJonathan Lemon 		klist = &ifklist;
2219a2a57a1SJonathan Lemon 	} else {
2229a2a57a1SJonathan Lemon 		ifp = ifnet_byindex(idx);
2239a2a57a1SJonathan Lemon 		if (ifp == NULL)
2249a2a57a1SJonathan Lemon 			return (1);
2259a2a57a1SJonathan Lemon 		klist = &ifp->if_klist;
2269a2a57a1SJonathan Lemon 	}
2279a2a57a1SJonathan Lemon 
2289a2a57a1SJonathan Lemon 	kn->kn_hook = (caddr_t)klist;
2299a2a57a1SJonathan Lemon 
230ad3b9257SJohn-Mark Gurney 	knlist_add(klist, kn, 0);
2319a2a57a1SJonathan Lemon 
2329a2a57a1SJonathan Lemon 	return (0);
2339a2a57a1SJonathan Lemon }
2349a2a57a1SJonathan Lemon 
2359a2a57a1SJonathan Lemon static void
2369a2a57a1SJonathan Lemon filt_netdetach(struct knote *kn)
2379a2a57a1SJonathan Lemon {
238ad3b9257SJohn-Mark Gurney 	struct knlist *klist = (struct knlist *)kn->kn_hook;
2399a2a57a1SJonathan Lemon 
240ad3b9257SJohn-Mark Gurney 	knlist_remove(klist, kn, 0);
2419a2a57a1SJonathan Lemon }
2429a2a57a1SJonathan Lemon 
2439a2a57a1SJonathan Lemon static int
2449a2a57a1SJonathan Lemon filt_netdev(struct knote *kn, long hint)
2459a2a57a1SJonathan Lemon {
246ad3b9257SJohn-Mark Gurney 	struct knlist *klist = (struct knlist *)kn->kn_hook;
2479a2a57a1SJonathan Lemon 
2489a2a57a1SJonathan Lemon 	/*
2499a2a57a1SJonathan Lemon 	 * Currently NOTE_EXIT is abused to indicate device detach.
2509a2a57a1SJonathan Lemon 	 */
2519a2a57a1SJonathan Lemon 	if (hint == NOTE_EXIT) {
2529a2a57a1SJonathan Lemon 		kn->kn_data = NOTE_LINKINV;
2539a2a57a1SJonathan Lemon 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
254ad3b9257SJohn-Mark Gurney 		knlist_remove_inevent(klist, kn);
2559a2a57a1SJonathan Lemon 		return (1);
2569a2a57a1SJonathan Lemon 	}
257ad3b9257SJohn-Mark Gurney 	if (hint != 0)
2589a2a57a1SJonathan Lemon 		kn->kn_data = hint;			/* current status */
2599a2a57a1SJonathan Lemon 	if (kn->kn_sfflags & hint)
2609a2a57a1SJonathan Lemon 		kn->kn_fflags |= hint;
2619a2a57a1SJonathan Lemon 	return (kn->kn_fflags != 0);
2629a2a57a1SJonathan Lemon }
2639a2a57a1SJonathan Lemon 
264df8bae1dSRodney W. Grimes /*
265df8bae1dSRodney W. Grimes  * Network interface utility routines.
266df8bae1dSRodney W. Grimes  *
267df8bae1dSRodney W. Grimes  * Routines with ifa_ifwith* names take sockaddr *'s as
268df8bae1dSRodney W. Grimes  * parameters.
269df8bae1dSRodney W. Grimes  */
2702b14f991SJulian Elischer /* ARGSUSED*/
271f9132cebSJonathan Lemon static void
27272fd1b6aSDag-Erling Smørgrav if_init(void *dummy __unused)
273f9132cebSJonathan Lemon {
274f9132cebSJonathan Lemon 
275b30a244cSJeffrey Hsu 	IFNET_LOCK_INIT();
276f9132cebSJonathan Lemon 	TAILQ_INIT(&ifnet);
277ad3b9257SJohn-Mark Gurney 	knlist_init(&ifklist, NULL);
278f9132cebSJonathan Lemon 	if_grow();				/* create initial table */
279f13ad206SJonathan Lemon 	ifdev_byindex(0) = make_dev(&net_cdevsw, 0,
280f13ad206SJonathan Lemon 	    UID_ROOT, GID_WHEEL, 0600, "network");
281f889d2efSBrooks Davis 	if_clone_init();
282f9132cebSJonathan Lemon }
283f9132cebSJonathan Lemon 
284f9132cebSJonathan Lemon static void
285f9132cebSJonathan Lemon if_grow(void)
286f9132cebSJonathan Lemon {
287f9132cebSJonathan Lemon 	u_int n;
288f9132cebSJonathan Lemon 	struct ifindex_entry *e;
289f9132cebSJonathan Lemon 
290f9132cebSJonathan Lemon 	if_indexlim <<= 1;
291f9132cebSJonathan Lemon 	n = if_indexlim * sizeof(*e);
292a163d034SWarner Losh 	e = malloc(n, M_IFADDR, M_WAITOK | M_ZERO);
293f9132cebSJonathan Lemon 	if (ifindex_table != NULL) {
294f9132cebSJonathan Lemon 		memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2);
295f9132cebSJonathan Lemon 		free((caddr_t)ifindex_table, M_IFADDR);
296f9132cebSJonathan Lemon 	}
297f9132cebSJonathan Lemon 	ifindex_table = e;
298f9132cebSJonathan Lemon }
299f9132cebSJonathan Lemon 
300f9132cebSJonathan Lemon /* ARGSUSED*/
301f9132cebSJonathan Lemon static void
30272fd1b6aSDag-Erling Smørgrav if_check(void *dummy __unused)
303df8bae1dSRodney W. Grimes {
3048ba5bdaeSPeter Wemm 	struct ifnet *ifp;
3058ba5bdaeSPeter Wemm 	int s;
306df8bae1dSRodney W. Grimes 
3078ba5bdaeSPeter Wemm 	s = splimp();
308b30a244cSJeffrey Hsu 	IFNET_RLOCK();	/* could sleep on rare error; mostly okay XXX */
309fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
310e0ea20bcSPoul-Henning Kamp 		if (ifp->if_snd.ifq_maxlen == 0) {
31113fb40dfSBrooks Davis 			if_printf(ifp, "XXX: driver didn't set ifq_maxlen\n");
312df8bae1dSRodney W. Grimes 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
313e0ea20bcSPoul-Henning Kamp 		}
3145e980e22SJohn Baldwin 		if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) {
31513fb40dfSBrooks Davis 			if_printf(ifp,
31613fb40dfSBrooks Davis 			    "XXX: driver didn't initialize queue mtx\n");
3176008862bSJohn Baldwin 			mtx_init(&ifp->if_snd.ifq_mtx, "unknown",
3186008862bSJohn Baldwin 			    MTX_NETWORK_LOCK, MTX_DEF);
319df5e1987SJonathan Lemon 		}
320df5e1987SJonathan Lemon 	}
321b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
3228ba5bdaeSPeter Wemm 	splx(s);
323df8bae1dSRodney W. Grimes 	if_slowtimo(0);
324df8bae1dSRodney W. Grimes }
325df8bae1dSRodney W. Grimes 
326ffb5a104SJonathan Lemon static int
327ffb5a104SJonathan Lemon if_findindex(struct ifnet *ifp)
328ffb5a104SJonathan Lemon {
329ffb5a104SJonathan Lemon 	int i, unit;
330ffb5a104SJonathan Lemon 	char eaddr[18], devname[32];
331d2b4566aSJonathan Lemon 	const char *name, *p;
332ffb5a104SJonathan Lemon 
333ffb5a104SJonathan Lemon 	switch (ifp->if_type) {
334ffb5a104SJonathan Lemon 	case IFT_ETHER:			/* these types use struct arpcom */
335ffb5a104SJonathan Lemon 	case IFT_FDDI:
336ffb5a104SJonathan Lemon 	case IFT_XETHER:
337ffb5a104SJonathan Lemon 	case IFT_ISO88025:
338ffb5a104SJonathan Lemon 	case IFT_L2VLAN:
3398bbfdc98SRobert Watson 		snprintf(eaddr, 18, "%6D", IFP2AC(ifp)->ac_enaddr, ":");
340ffb5a104SJonathan Lemon 		break;
341ffb5a104SJonathan Lemon 	default:
342ffb5a104SJonathan Lemon 		eaddr[0] = '\0';
343ffb5a104SJonathan Lemon 		break;
344ffb5a104SJonathan Lemon 	}
3459bf40edeSBrooks Davis 	strlcpy(devname, ifp->if_xname, sizeof(devname));
346ffb5a104SJonathan Lemon 	name = net_cdevsw.d_name;
347ffb5a104SJonathan Lemon 	i = 0;
348ffb5a104SJonathan Lemon 	while ((resource_find_dev(&i, name, &unit, NULL, NULL)) == 0) {
349ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "ether", &p) == 0)
350ffb5a104SJonathan Lemon 			if (strcmp(p, eaddr) == 0)
351ffb5a104SJonathan Lemon 				goto found;
352ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "dev", &p) == 0)
353ffb5a104SJonathan Lemon 			if (strcmp(p, devname) == 0)
354ffb5a104SJonathan Lemon 				goto found;
355ffb5a104SJonathan Lemon 	}
356ffb5a104SJonathan Lemon 	unit = 0;
357ffb5a104SJonathan Lemon found:
358ffb5a104SJonathan Lemon 	if (unit != 0) {
359ffb5a104SJonathan Lemon 		if (ifaddr_byindex(unit) == NULL)
360ffb5a104SJonathan Lemon 			return (unit);
361ffb5a104SJonathan Lemon 		printf("%s%d in use, cannot hardwire it to %s.\n",
362ffb5a104SJonathan Lemon 		    name, unit, devname);
363ffb5a104SJonathan Lemon 	}
364ffb5a104SJonathan Lemon 	for (unit = 1; ; unit++) {
36505153c61SBill Fenner 		if (unit <= if_index && ifaddr_byindex(unit) != NULL)
366ffb5a104SJonathan Lemon 			continue;
367ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "ether", &p) == 0 ||
368ffb5a104SJonathan Lemon 		    resource_string_value(name, unit, "dev", &p) == 0)
369ffb5a104SJonathan Lemon 			continue;
370ffb5a104SJonathan Lemon 		break;
371ffb5a104SJonathan Lemon 	}
372ffb5a104SJonathan Lemon 	return (unit);
373ffb5a104SJonathan Lemon }
374ffb5a104SJonathan Lemon 
375df8bae1dSRodney W. Grimes /*
376df8bae1dSRodney W. Grimes  * Attach an interface to the
377df8bae1dSRodney W. Grimes  * list of "active" interfaces.
378df8bae1dSRodney W. Grimes  */
379df8bae1dSRodney W. Grimes void
38072fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp)
381df8bae1dSRodney W. Grimes {
382df8bae1dSRodney W. Grimes 	unsigned socksize, ifasize;
3831ce9bf88SPoul-Henning Kamp 	int namelen, masklen;
38472fd1b6aSDag-Erling Smørgrav 	struct sockaddr_dl *sdl;
38572fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
386df8bae1dSRodney W. Grimes 
387af5e59bfSRobert Watson 	TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp);
388234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK_INIT(ifp);
389234a35c7SHajimu UMEMOTO 	ifp->if_afdata_initialized = 0;
390b30a244cSJeffrey Hsu 	IFNET_WLOCK();
39129412182SGarrett Wollman 	TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
392b30a244cSJeffrey Hsu 	IFNET_WUNLOCK();
39359562606SGarrett Wollman 	/*
39459562606SGarrett Wollman 	 * XXX -
39559562606SGarrett Wollman 	 * The old code would work if the interface passed a pre-existing
39659562606SGarrett Wollman 	 * chain of ifaddrs to this code.  We don't trust our callers to
39759562606SGarrett Wollman 	 * properly initialize the tailq, however, so we no longer allow
39859562606SGarrett Wollman 	 * this unlikely case.
39959562606SGarrett Wollman 	 */
40059562606SGarrett Wollman 	TAILQ_INIT(&ifp->if_addrhead);
40182cd038dSYoshinobu Inoue 	TAILQ_INIT(&ifp->if_prefixhead);
4026817526dSPoul-Henning Kamp 	TAILQ_INIT(&ifp->if_multiaddrs);
403ad3b9257SJohn-Mark Gurney 	knlist_init(&ifp->if_klist, NULL);
40498b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
405bc9d2991SBrooks Davis 	ifp->if_data.ifi_epoch = time_uptime;
406e70cd263SRobert Watson 
407e70cd263SRobert Watson #ifdef MAC
408e70cd263SRobert Watson 	mac_init_ifnet(ifp);
409e70cd263SRobert Watson 	mac_create_ifnet(ifp);
410e70cd263SRobert Watson #endif
411e70cd263SRobert Watson 
412ffb5a104SJonathan Lemon 	ifp->if_index = if_findindex(ifp);
41305153c61SBill Fenner 	if (ifp->if_index > if_index)
41405153c61SBill Fenner 		if_index = ifp->if_index;
415f9132cebSJonathan Lemon 	if (if_index >= if_indexlim)
416f9132cebSJonathan Lemon 		if_grow();
4179e734b44SBrooks Davis 	ifp->if_data.ifi_datalen = sizeof(struct if_data);
41882cd038dSYoshinobu Inoue 
419ffb5a104SJonathan Lemon 	ifnet_byindex(ifp->if_index) = ifp;
42012b8b80eSRuslan Ermilov 	ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw,
42112b8b80eSRuslan Ermilov 	    unit2minor(ifp->if_index),
4229bf40edeSBrooks Davis 	    UID_ROOT, GID_WHEEL, 0600, "%s/%s",
4239bf40edeSBrooks Davis 	    net_cdevsw.d_name, ifp->if_xname);
424ffb5a104SJonathan Lemon 	make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d",
425ffb5a104SJonathan Lemon 	    net_cdevsw.d_name, ifp->if_index);
426f13ad206SJonathan Lemon 
4279bf40edeSBrooks Davis 	mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF);
428df5e1987SJonathan Lemon 
429df8bae1dSRodney W. Grimes 	/*
430df8bae1dSRodney W. Grimes 	 * create a Link Level name for this device
431df8bae1dSRodney W. Grimes 	 */
4329bf40edeSBrooks Davis 	namelen = strlen(ifp->if_xname);
43336c19a57SBrooks Davis 	/*
43436c19a57SBrooks Davis 	 * Always save enough space for any possiable name so we can do
43536c19a57SBrooks Davis 	 * a rename in place later.
43636c19a57SBrooks Davis 	 */
43736c19a57SBrooks Davis 	masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ;
438df8bae1dSRodney W. Grimes 	socksize = masklen + ifp->if_addrlen;
439df8bae1dSRodney W. Grimes 	if (socksize < sizeof(*sdl))
440df8bae1dSRodney W. Grimes 		socksize = sizeof(*sdl);
441ccb82468SBrooks Davis 	socksize = roundup2(socksize, sizeof(long));
442df8bae1dSRodney W. Grimes 	ifasize = sizeof(*ifa) + 2 * socksize;
443a8773564SBrooks Davis 	ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO);
44419fc74fbSJeffrey Hsu 	IFA_LOCK_INIT(ifa);
445df8bae1dSRodney W. Grimes 	sdl = (struct sockaddr_dl *)(ifa + 1);
446df8bae1dSRodney W. Grimes 	sdl->sdl_len = socksize;
447df8bae1dSRodney W. Grimes 	sdl->sdl_family = AF_LINK;
4489bf40edeSBrooks Davis 	bcopy(ifp->if_xname, sdl->sdl_data, namelen);
4491ce9bf88SPoul-Henning Kamp 	sdl->sdl_nlen = namelen;
450df8bae1dSRodney W. Grimes 	sdl->sdl_index = ifp->if_index;
451df8bae1dSRodney W. Grimes 	sdl->sdl_type = ifp->if_type;
452ffb5a104SJonathan Lemon 	ifaddr_byindex(ifp->if_index) = ifa;
453df8bae1dSRodney W. Grimes 	ifa->ifa_ifp = ifp;
454df8bae1dSRodney W. Grimes 	ifa->ifa_rtrequest = link_rtrequest;
455df8bae1dSRodney W. Grimes 	ifa->ifa_addr = (struct sockaddr *)sdl;
456df8bae1dSRodney W. Grimes 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
457df8bae1dSRodney W. Grimes 	ifa->ifa_netmask = (struct sockaddr *)sdl;
458df8bae1dSRodney W. Grimes 	sdl->sdl_len = masklen;
459df8bae1dSRodney W. Grimes 	while (namelen != 0)
460df8bae1dSRodney W. Grimes 		sdl->sdl_data[--namelen] = 0xff;
46119fc74fbSJeffrey Hsu 	ifa->ifa_refcnt = 1;
46259562606SGarrett Wollman 	TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
4636237419dSRobert Watson 	ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */
46402b199f1SMax Laier 	ifp->if_snd.altq_type = 0;
46502b199f1SMax Laier 	ifp->if_snd.altq_disc = NULL;
46602b199f1SMax Laier 	ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE;
46702b199f1SMax Laier 	ifp->if_snd.altq_tbr  = NULL;
46802b199f1SMax Laier 	ifp->if_snd.altq_ifp  = ifp;
4697b6edd04SRuslan Ermilov 
47069fb23b7SMax Laier 	if (domain_init_status >= 2)
47131b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
47231b1bfe1SHajimu UMEMOTO 
47325a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
47425a4adceSMax Laier 
4757b6edd04SRuslan Ermilov 	/* Announce the interface. */
4767b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
477df8bae1dSRodney W. Grimes }
4786182fdbdSPeter Wemm 
47931b1bfe1SHajimu UMEMOTO static void
48072fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy)
48131b1bfe1SHajimu UMEMOTO {
48231b1bfe1SHajimu UMEMOTO 	struct ifnet *ifp;
48331b1bfe1SHajimu UMEMOTO 	int s;
48431b1bfe1SHajimu UMEMOTO 
48531b1bfe1SHajimu UMEMOTO 	s = splnet();
4869046571fSLuigi Rizzo 	TAILQ_FOREACH(ifp, &ifnet, if_link)
48731b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
48831b1bfe1SHajimu UMEMOTO 	splx(s);
48931b1bfe1SHajimu UMEMOTO }
49069fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND,
49131b1bfe1SHajimu UMEMOTO     if_attachdomain, NULL);
49231b1bfe1SHajimu UMEMOTO 
49331b1bfe1SHajimu UMEMOTO static void
49472fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp)
49531b1bfe1SHajimu UMEMOTO {
49631b1bfe1SHajimu UMEMOTO 	struct domain *dp;
49731b1bfe1SHajimu UMEMOTO 	int s;
49831b1bfe1SHajimu UMEMOTO 
49931b1bfe1SHajimu UMEMOTO 	s = splnet();
50031b1bfe1SHajimu UMEMOTO 
501234a35c7SHajimu UMEMOTO 	/*
502234a35c7SHajimu UMEMOTO 	 * Since dp->dom_ifattach calls malloc() with M_WAITOK, we
503234a35c7SHajimu UMEMOTO 	 * cannot lock ifp->if_afdata initialization, entirely.
504234a35c7SHajimu UMEMOTO 	 */
505234a35c7SHajimu UMEMOTO 	if (IF_AFDATA_TRYLOCK(ifp) == 0) {
506234a35c7SHajimu UMEMOTO 		splx(s);
507234a35c7SHajimu UMEMOTO 		return;
508234a35c7SHajimu UMEMOTO 	}
50969fb23b7SMax Laier 	if (ifp->if_afdata_initialized >= domain_init_status) {
510234a35c7SHajimu UMEMOTO 		IF_AFDATA_UNLOCK(ifp);
511234a35c7SHajimu UMEMOTO 		splx(s);
5126237419dSRobert Watson 		printf("if_attachdomain called more than once on %s\n",
5136237419dSRobert Watson 		    ifp->if_xname);
514234a35c7SHajimu UMEMOTO 		return;
515234a35c7SHajimu UMEMOTO 	}
51669fb23b7SMax Laier 	ifp->if_afdata_initialized = domain_init_status;
517234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
518234a35c7SHajimu UMEMOTO 
51931b1bfe1SHajimu UMEMOTO 	/* address family dependent data region */
52031b1bfe1SHajimu UMEMOTO 	bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
52131b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
52231b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifattach)
52331b1bfe1SHajimu UMEMOTO 			ifp->if_afdata[dp->dom_family] =
52431b1bfe1SHajimu UMEMOTO 			    (*dp->dom_ifattach)(ifp);
52531b1bfe1SHajimu UMEMOTO 	}
52631b1bfe1SHajimu UMEMOTO 
52731b1bfe1SHajimu UMEMOTO 	splx(s);
52831b1bfe1SHajimu UMEMOTO }
52931b1bfe1SHajimu UMEMOTO 
5306182fdbdSPeter Wemm /*
5316182fdbdSPeter Wemm  * Detach an interface, removing it from the
5326182fdbdSPeter Wemm  * list of "active" interfaces.
5336182fdbdSPeter Wemm  */
5346182fdbdSPeter Wemm void
53572fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp)
5366182fdbdSPeter Wemm {
537212bd869SHajimu UMEMOTO 	struct ifaddr *ifa, *next;
5385500d3beSWarner Losh 	struct radix_node_head	*rnh;
5395500d3beSWarner Losh 	int s;
5405500d3beSWarner Losh 	int i;
54131b1bfe1SHajimu UMEMOTO 	struct domain *dp;
5423f35d515SPeter Pentchev  	struct ifnet *iter;
5433f35d515SPeter Pentchev  	int found;
5446182fdbdSPeter Wemm 
54525a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
546a9771948SGleb Smirnoff #ifdef DEV_CARP
547a9771948SGleb Smirnoff 	/* Maybe hook to the generalized departure handler above?!? */
548a9771948SGleb Smirnoff 	if (ifp->if_carp)
549a9771948SGleb Smirnoff 		carp_ifdetach(ifp);
550a9771948SGleb Smirnoff #endif
551a9771948SGleb Smirnoff 
5526182fdbdSPeter Wemm 	/*
5536182fdbdSPeter Wemm 	 * Remove routes and flush queues.
5546182fdbdSPeter Wemm 	 */
5555500d3beSWarner Losh 	s = splnet();
5566182fdbdSPeter Wemm 	if_down(ifp);
55702b199f1SMax Laier #ifdef ALTQ
55802b199f1SMax Laier 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
55902b199f1SMax Laier 		altq_disable(&ifp->if_snd);
56002b199f1SMax Laier 	if (ALTQ_IS_ATTACHED(&ifp->if_snd))
56102b199f1SMax Laier 		altq_detach(&ifp->if_snd);
56202b199f1SMax Laier #endif
5636182fdbdSPeter Wemm 
564212bd869SHajimu UMEMOTO 	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = next) {
565212bd869SHajimu UMEMOTO 		next = TAILQ_NEXT(ifa, ifa_link);
566212bd869SHajimu UMEMOTO 
567212bd869SHajimu UMEMOTO 		if (ifa->ifa_addr->sa_family == AF_LINK)
568212bd869SHajimu UMEMOTO 			continue;
5690d0f9d1eSYoshinobu Inoue #ifdef INET
570aa6be122SWarner Losh 		/* XXX: Ugly!! ad hoc just for INET */
571aa6be122SWarner Losh 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
572aa6be122SWarner Losh 			struct ifaliasreq ifr;
573aa6be122SWarner Losh 
574aa6be122SWarner Losh 			bzero(&ifr, sizeof(ifr));
575aa6be122SWarner Losh 			ifr.ifra_addr = *ifa->ifa_addr;
576aa6be122SWarner Losh 			if (ifa->ifa_dstaddr)
577aa6be122SWarner Losh 				ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
578aa6be122SWarner Losh 			if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
579aa6be122SWarner Losh 			    NULL) == 0)
580aa6be122SWarner Losh 				continue;
581aa6be122SWarner Losh 		}
5820d0f9d1eSYoshinobu Inoue #endif /* INET */
5830d0f9d1eSYoshinobu Inoue #ifdef INET6
5840d0f9d1eSYoshinobu Inoue 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
58533841545SHajimu UMEMOTO 			in6_purgeaddr(ifa);
586978ee2edSJun-ichiro itojun Hagino 			/* ifp_addrhead is already updated */
5870d0f9d1eSYoshinobu Inoue 			continue;
5880d0f9d1eSYoshinobu Inoue 		}
5890d0f9d1eSYoshinobu Inoue #endif /* INET6 */
5906182fdbdSPeter Wemm 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
5916182fdbdSPeter Wemm 		IFAFREE(ifa);
5926182fdbdSPeter Wemm 	}
5936182fdbdSPeter Wemm 
59433841545SHajimu UMEMOTO #ifdef INET6
59533841545SHajimu UMEMOTO 	/*
59633841545SHajimu UMEMOTO 	 * Remove all IPv6 kernel structs related to ifp.  This should be done
59733841545SHajimu UMEMOTO 	 * before removing routing entries below, since IPv6 interface direct
59833841545SHajimu UMEMOTO 	 * routes are expected to be removed by the IPv6-specific kernel API.
59933841545SHajimu UMEMOTO 	 * Otherwise, the kernel will detect some inconsistency and bark it.
60033841545SHajimu UMEMOTO 	 */
60133841545SHajimu UMEMOTO 	in6_ifdetach(ifp);
60233841545SHajimu UMEMOTO #endif
603f4247b59SLuigi Rizzo 	/*
604f4247b59SLuigi Rizzo 	 * Remove address from ifindex_table[] and maybe decrement if_index.
605f4247b59SLuigi Rizzo 	 * Clean up all addresses.
606f4247b59SLuigi Rizzo 	 */
607b9907cd4SBrooks Davis 	ifnet_byindex(ifp->if_index) = NULL;
608f4247b59SLuigi Rizzo 	ifaddr_byindex(ifp->if_index) = NULL;
609f4247b59SLuigi Rizzo 	destroy_dev(ifdev_byindex(ifp->if_index));
610f4247b59SLuigi Rizzo 	ifdev_byindex(ifp->if_index) = NULL;
611f4247b59SLuigi Rizzo 
612f4247b59SLuigi Rizzo 	while (if_index > 0 && ifaddr_byindex(if_index) == NULL)
613f4247b59SLuigi Rizzo 		if_index--;
614f4247b59SLuigi Rizzo 
61533841545SHajimu UMEMOTO 
616212bd869SHajimu UMEMOTO 	/* We can now free link ifaddr. */
6173f35d515SPeter Pentchev 	if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
618212bd869SHajimu UMEMOTO 		ifa = TAILQ_FIRST(&ifp->if_addrhead);
619212bd869SHajimu UMEMOTO 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
620212bd869SHajimu UMEMOTO 		IFAFREE(ifa);
6213f35d515SPeter Pentchev 	}
622212bd869SHajimu UMEMOTO 
6235500d3beSWarner Losh 	/*
6245500d3beSWarner Losh 	 * Delete all remaining routes using this interface
6255500d3beSWarner Losh 	 * Unfortuneatly the only way to do this is to slog through
6265500d3beSWarner Losh 	 * the entire routing table looking for routes which point
6275500d3beSWarner Losh 	 * to this interface...oh well...
6285500d3beSWarner Losh 	 */
6295500d3beSWarner Losh 	for (i = 1; i <= AF_MAX; i++) {
6305500d3beSWarner Losh 		if ((rnh = rt_tables[i]) == NULL)
6315500d3beSWarner Losh 			continue;
632956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_LOCK(rnh);
6335500d3beSWarner Losh 		(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
634956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_UNLOCK(rnh);
6355500d3beSWarner Losh 	}
6365500d3beSWarner Losh 
6377b6edd04SRuslan Ermilov 	/* Announce that the interface is gone. */
6387b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
6397b6edd04SRuslan Ermilov 
640234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK(ifp);
64131b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
64231b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
64331b1bfe1SHajimu UMEMOTO 			(*dp->dom_ifdetach)(ifp,
64431b1bfe1SHajimu UMEMOTO 			    ifp->if_afdata[dp->dom_family]);
64531b1bfe1SHajimu UMEMOTO 	}
646234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
64731b1bfe1SHajimu UMEMOTO 
648e70cd263SRobert Watson #ifdef MAC
649e70cd263SRobert Watson 	mac_destroy_ifnet(ifp);
650e70cd263SRobert Watson #endif /* MAC */
651ad3b9257SJohn-Mark Gurney 	KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT);
652ad3b9257SJohn-Mark Gurney 	knlist_clear(&ifp->if_klist, 0);
653ad3b9257SJohn-Mark Gurney 	knlist_destroy(&ifp->if_klist);
654b30a244cSJeffrey Hsu 	IFNET_WLOCK();
6553f35d515SPeter Pentchev  	found = 0;
6563f35d515SPeter Pentchev  	TAILQ_FOREACH(iter, &ifnet, if_link)
6573f35d515SPeter Pentchev  		if (iter == ifp) {
6583f35d515SPeter Pentchev  			found = 1;
6593f35d515SPeter Pentchev  			break;
6603f35d515SPeter Pentchev  		}
6613f35d515SPeter Pentchev  	if (found)
6626182fdbdSPeter Wemm  		TAILQ_REMOVE(&ifnet, ifp, if_link);
663b30a244cSJeffrey Hsu 	IFNET_WUNLOCK();
664df5e1987SJonathan Lemon 	mtx_destroy(&ifp->if_snd.ifq_mtx);
665234a35c7SHajimu UMEMOTO 	IF_AFDATA_DESTROY(ifp);
6665500d3beSWarner Losh 	splx(s);
6675500d3beSWarner Losh }
6685500d3beSWarner Losh 
6695500d3beSWarner Losh /*
6705500d3beSWarner Losh  * Delete Routes for a Network Interface
6715500d3beSWarner Losh  *
6725500d3beSWarner Losh  * Called for each routing entry via the rnh->rnh_walktree() call above
6735500d3beSWarner Losh  * to delete all route entries referencing a detaching network interface.
6745500d3beSWarner Losh  *
6755500d3beSWarner Losh  * Arguments:
6765500d3beSWarner Losh  *	rn	pointer to node in the routing table
6775500d3beSWarner Losh  *	arg	argument passed to rnh->rnh_walktree() - detaching interface
6785500d3beSWarner Losh  *
6795500d3beSWarner Losh  * Returns:
6805500d3beSWarner Losh  *	0	successful
6815500d3beSWarner Losh  *	errno	failed - reason indicated
6825500d3beSWarner Losh  *
6835500d3beSWarner Losh  */
6845500d3beSWarner Losh static int
68572fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg)
6865500d3beSWarner Losh {
6875500d3beSWarner Losh 	struct rtentry	*rt = (struct rtentry *)rn;
6885500d3beSWarner Losh 	struct ifnet	*ifp = arg;
6895500d3beSWarner Losh 	int		err;
6905500d3beSWarner Losh 
6915500d3beSWarner Losh 	if (rt->rt_ifp == ifp) {
6925500d3beSWarner Losh 
6935500d3beSWarner Losh 		/*
6945500d3beSWarner Losh 		 * Protect (sorta) against walktree recursion problems
6955500d3beSWarner Losh 		 * with cloned routes
6965500d3beSWarner Losh 		 */
6975500d3beSWarner Losh 		if ((rt->rt_flags & RTF_UP) == 0)
6985500d3beSWarner Losh 			return (0);
6995500d3beSWarner Losh 
7005500d3beSWarner Losh 		err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
7015500d3beSWarner Losh 				rt_mask(rt), rt->rt_flags,
7025500d3beSWarner Losh 				(struct rtentry **) NULL);
7035500d3beSWarner Losh 		if (err) {
7045500d3beSWarner Losh 			log(LOG_WARNING, "if_rtdel: error %d\n", err);
7055500d3beSWarner Losh 		}
7065500d3beSWarner Losh 	}
7075500d3beSWarner Losh 
7085500d3beSWarner Losh 	return (0);
7096182fdbdSPeter Wemm }
7106182fdbdSPeter Wemm 
711d1dd20beSSam Leffler #define	equal(a1, a2)	(bcmp((a1), (a2), ((a1))->sa_len) == 0)
71219fc74fbSJeffrey Hsu 
71330aad87dSBrooks Davis /*
714df8bae1dSRodney W. Grimes  * Locate an interface based on a complete address.
715df8bae1dSRodney W. Grimes  */
716df8bae1dSRodney W. Grimes /*ARGSUSED*/
717df8bae1dSRodney W. Grimes struct ifaddr *
71872fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr)
719df8bae1dSRodney W. Grimes {
7200b59d917SJonathan Lemon 	struct ifnet *ifp;
7210b59d917SJonathan Lemon 	struct ifaddr *ifa;
722df8bae1dSRodney W. Grimes 
723b30a244cSJeffrey Hsu 	IFNET_RLOCK();
724fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link)
72537d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
726df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
727df8bae1dSRodney W. Grimes 				continue;
728df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr))
7290b59d917SJonathan Lemon 				goto done;
73082cd038dSYoshinobu Inoue 			/* IP6 doesn't have broadcast */
7310b59d917SJonathan Lemon 			if ((ifp->if_flags & IFF_BROADCAST) &&
7320b59d917SJonathan Lemon 			    ifa->ifa_broadaddr &&
73382cd038dSYoshinobu Inoue 			    ifa->ifa_broadaddr->sa_len != 0 &&
734df8bae1dSRodney W. Grimes 			    equal(ifa->ifa_broadaddr, addr))
7350b59d917SJonathan Lemon 				goto done;
7360b59d917SJonathan Lemon 		}
7370b59d917SJonathan Lemon 	ifa = NULL;
7380b59d917SJonathan Lemon done:
739b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
740df8bae1dSRodney W. Grimes 	return (ifa);
741df8bae1dSRodney W. Grimes }
7420b59d917SJonathan Lemon 
743df8bae1dSRodney W. Grimes /*
744df8bae1dSRodney W. Grimes  * Locate the point to point interface with a given destination address.
745df8bae1dSRodney W. Grimes  */
746df8bae1dSRodney W. Grimes /*ARGSUSED*/
747df8bae1dSRodney W. Grimes struct ifaddr *
74872fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr)
749df8bae1dSRodney W. Grimes {
7500b59d917SJonathan Lemon 	struct ifnet *ifp;
7510b59d917SJonathan Lemon 	struct ifaddr *ifa;
752df8bae1dSRodney W. Grimes 
753b30a244cSJeffrey Hsu 	IFNET_RLOCK();
7540b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
7550b59d917SJonathan Lemon 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
7560b59d917SJonathan Lemon 			continue;
75737d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
758df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
759df8bae1dSRodney W. Grimes 				continue;
76055088a1cSDavid Greenman 			if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
7610b59d917SJonathan Lemon 				goto done;
762df8bae1dSRodney W. Grimes 		}
7630b59d917SJonathan Lemon 	}
7640b59d917SJonathan Lemon 	ifa = NULL;
7650b59d917SJonathan Lemon done:
766b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
7670b59d917SJonathan Lemon 	return (ifa);
768df8bae1dSRodney W. Grimes }
769df8bae1dSRodney W. Grimes 
770df8bae1dSRodney W. Grimes /*
771df8bae1dSRodney W. Grimes  * Find an interface on a specific network.  If many, choice
772df8bae1dSRodney W. Grimes  * is most specific found.
773df8bae1dSRodney W. Grimes  */
774df8bae1dSRodney W. Grimes struct ifaddr *
77572fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr)
776df8bae1dSRodney W. Grimes {
77772fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
77872fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
779df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
780df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
781df8bae1dSRodney W. Grimes 	char *addr_data = addr->sa_data, *cplim;
782df8bae1dSRodney W. Grimes 
7837e2a6151SJulian Elischer 	/*
7847e2a6151SJulian Elischer 	 * AF_LINK addresses can be looked up directly by their index number,
7857e2a6151SJulian Elischer 	 * so do that if we can.
7867e2a6151SJulian Elischer 	 */
787df8bae1dSRodney W. Grimes 	if (af == AF_LINK) {
788d1dd20beSSam Leffler 	    struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
789df8bae1dSRodney W. Grimes 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
790f9132cebSJonathan Lemon 		return (ifaddr_byindex(sdl->sdl_index));
791df8bae1dSRodney W. Grimes 	}
7927e2a6151SJulian Elischer 
7937e2a6151SJulian Elischer 	/*
7947e2a6151SJulian Elischer 	 * Scan though each interface, looking for ones that have
7957e2a6151SJulian Elischer 	 * addresses in this address family.
7967e2a6151SJulian Elischer 	 */
797b30a244cSJeffrey Hsu 	IFNET_RLOCK();
798fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
79937d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
80072fd1b6aSDag-Erling Smørgrav 			char *cp, *cp2, *cp3;
801df8bae1dSRodney W. Grimes 
802523a02aaSDavid Greenman 			if (ifa->ifa_addr->sa_family != af)
803df8bae1dSRodney W. Grimes next:				continue;
804c61cd599SHajimu UMEMOTO 			if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) {
8057e2a6151SJulian Elischer 				/*
8067e2a6151SJulian Elischer 				 * This is a bit broken as it doesn't
8077e2a6151SJulian Elischer 				 * take into account that the remote end may
8087e2a6151SJulian Elischer 				 * be a single node in the network we are
8097e2a6151SJulian Elischer 				 * looking for.
8107e2a6151SJulian Elischer 				 * The trouble is that we don't know the
8117e2a6151SJulian Elischer 				 * netmask for the remote end.
8127e2a6151SJulian Elischer 				 */
813fcd6781aSGarrett Wollman 				if (ifa->ifa_dstaddr != 0
814fcd6781aSGarrett Wollman 				    && equal(addr, ifa->ifa_dstaddr))
8150b59d917SJonathan Lemon 					goto done;
8163740e2adSDavid Greenman 			} else {
8177e2a6151SJulian Elischer 				/*
8187ed8f465SJulian Elischer 				 * if we have a special address handler,
8197ed8f465SJulian Elischer 				 * then use it instead of the generic one.
8207ed8f465SJulian Elischer 				 */
8217ed8f465SJulian Elischer 				if (ifa->ifa_claim_addr) {
8220b59d917SJonathan Lemon 					if ((*ifa->ifa_claim_addr)(ifa, addr))
8230b59d917SJonathan Lemon 						goto done;
8247ed8f465SJulian Elischer 					continue;
8257ed8f465SJulian Elischer 				}
8267ed8f465SJulian Elischer 
8277ed8f465SJulian Elischer 				/*
8287e2a6151SJulian Elischer 				 * Scan all the bits in the ifa's address.
8297e2a6151SJulian Elischer 				 * If a bit dissagrees with what we are
8307e2a6151SJulian Elischer 				 * looking for, mask it with the netmask
8317e2a6151SJulian Elischer 				 * to see if it really matters.
8327e2a6151SJulian Elischer 				 * (A byte at a time)
8337e2a6151SJulian Elischer 				 */
834523a02aaSDavid Greenman 				if (ifa->ifa_netmask == 0)
835523a02aaSDavid Greenman 					continue;
836df8bae1dSRodney W. Grimes 				cp = addr_data;
837df8bae1dSRodney W. Grimes 				cp2 = ifa->ifa_addr->sa_data;
838df8bae1dSRodney W. Grimes 				cp3 = ifa->ifa_netmask->sa_data;
8397e2a6151SJulian Elischer 				cplim = ifa->ifa_netmask->sa_len
8407e2a6151SJulian Elischer 					+ (char *)ifa->ifa_netmask;
841df8bae1dSRodney W. Grimes 				while (cp3 < cplim)
842df8bae1dSRodney W. Grimes 					if ((*cp++ ^ *cp2++) & *cp3++)
8437e2a6151SJulian Elischer 						goto next; /* next address! */
8447e2a6151SJulian Elischer 				/*
8457e2a6151SJulian Elischer 				 * If the netmask of what we just found
8467e2a6151SJulian Elischer 				 * is more specific than what we had before
8477e2a6151SJulian Elischer 				 * (if we had one) then remember the new one
8487e2a6151SJulian Elischer 				 * before continuing to search
8497e2a6151SJulian Elischer 				 * for an even better one.
8507e2a6151SJulian Elischer 				 */
851df8bae1dSRodney W. Grimes 				if (ifa_maybe == 0 ||
852df8bae1dSRodney W. Grimes 				    rn_refines((caddr_t)ifa->ifa_netmask,
853df8bae1dSRodney W. Grimes 				    (caddr_t)ifa_maybe->ifa_netmask))
854df8bae1dSRodney W. Grimes 					ifa_maybe = ifa;
855df8bae1dSRodney W. Grimes 			}
856b2af64fdSDavid Greenman 		}
857b2af64fdSDavid Greenman 	}
8580b59d917SJonathan Lemon 	ifa = ifa_maybe;
8590b59d917SJonathan Lemon done:
860b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
8610b59d917SJonathan Lemon 	return (ifa);
862df8bae1dSRodney W. Grimes }
863df8bae1dSRodney W. Grimes 
864df8bae1dSRodney W. Grimes /*
865df8bae1dSRodney W. Grimes  * Find an interface address specific to an interface best matching
866df8bae1dSRodney W. Grimes  * a given address.
867df8bae1dSRodney W. Grimes  */
868df8bae1dSRodney W. Grimes struct ifaddr *
86972fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
870df8bae1dSRodney W. Grimes {
87172fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
87272fd1b6aSDag-Erling Smørgrav 	char *cp, *cp2, *cp3;
87372fd1b6aSDag-Erling Smørgrav 	char *cplim;
874df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = 0;
875df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
876df8bae1dSRodney W. Grimes 
877df8bae1dSRodney W. Grimes 	if (af >= AF_MAX)
878df8bae1dSRodney W. Grimes 		return (0);
87937d40066SPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
880df8bae1dSRodney W. Grimes 		if (ifa->ifa_addr->sa_family != af)
881df8bae1dSRodney W. Grimes 			continue;
882381dd1d2SJulian Elischer 		if (ifa_maybe == 0)
883df8bae1dSRodney W. Grimes 			ifa_maybe = ifa;
884df8bae1dSRodney W. Grimes 		if (ifa->ifa_netmask == 0) {
885df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr) ||
886df8bae1dSRodney W. Grimes 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
8872defe5cdSJonathan Lemon 				goto done;
888df8bae1dSRodney W. Grimes 			continue;
889df8bae1dSRodney W. Grimes 		}
890b2af64fdSDavid Greenman 		if (ifp->if_flags & IFF_POINTOPOINT) {
891b2af64fdSDavid Greenman 			if (equal(addr, ifa->ifa_dstaddr))
892a8637146SJonathan Lemon 				goto done;
8933740e2adSDavid Greenman 		} else {
894df8bae1dSRodney W. Grimes 			cp = addr->sa_data;
895df8bae1dSRodney W. Grimes 			cp2 = ifa->ifa_addr->sa_data;
896df8bae1dSRodney W. Grimes 			cp3 = ifa->ifa_netmask->sa_data;
897df8bae1dSRodney W. Grimes 			cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
898df8bae1dSRodney W. Grimes 			for (; cp3 < cplim; cp3++)
899df8bae1dSRodney W. Grimes 				if ((*cp++ ^ *cp2++) & *cp3)
900df8bae1dSRodney W. Grimes 					break;
901df8bae1dSRodney W. Grimes 			if (cp3 == cplim)
9022defe5cdSJonathan Lemon 				goto done;
903df8bae1dSRodney W. Grimes 		}
904b2af64fdSDavid Greenman 	}
905f9132cebSJonathan Lemon 	ifa = ifa_maybe;
906f9132cebSJonathan Lemon done:
907f9132cebSJonathan Lemon 	return (ifa);
908df8bae1dSRodney W. Grimes }
909df8bae1dSRodney W. Grimes 
910df8bae1dSRodney W. Grimes #include <net/route.h>
911df8bae1dSRodney W. Grimes 
912df8bae1dSRodney W. Grimes /*
913df8bae1dSRodney W. Grimes  * Default action when installing a route with a Link Level gateway.
914df8bae1dSRodney W. Grimes  * Lookup an appropriate real ifa to point to.
915df8bae1dSRodney W. Grimes  * This should be moved to /sys/net/link.c eventually.
916df8bae1dSRodney W. Grimes  */
9173bda9f9bSPoul-Henning Kamp static void
91872fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
919df8bae1dSRodney W. Grimes {
92072fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa, *oifa;
921df8bae1dSRodney W. Grimes 	struct sockaddr *dst;
922df8bae1dSRodney W. Grimes 	struct ifnet *ifp;
923df8bae1dSRodney W. Grimes 
924d1dd20beSSam Leffler 	RT_LOCK_ASSERT(rt);
925d1dd20beSSam Leffler 
926df8bae1dSRodney W. Grimes 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
927df8bae1dSRodney W. Grimes 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
928df8bae1dSRodney W. Grimes 		return;
9299448326fSPoul-Henning Kamp 	ifa = ifaof_ifpforaddr(dst, ifp);
9309448326fSPoul-Henning Kamp 	if (ifa) {
93119fc74fbSJeffrey Hsu 		IFAREF(ifa);		/* XXX */
932d1dd20beSSam Leffler 		oifa = rt->rt_ifa;
933df8bae1dSRodney W. Grimes 		rt->rt_ifa = ifa;
934d1dd20beSSam Leffler 		IFAFREE(oifa);
935df8bae1dSRodney W. Grimes 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
9368071913dSRuslan Ermilov 			ifa->ifa_rtrequest(cmd, rt, info);
937df8bae1dSRodney W. Grimes 	}
938df8bae1dSRodney W. Grimes }
939df8bae1dSRodney W. Grimes 
940df8bae1dSRodney W. Grimes /*
941df8bae1dSRodney W. Grimes  * Mark an interface down and notify protocols of
942df8bae1dSRodney W. Grimes  * the transition.
943df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
944df8bae1dSRodney W. Grimes  */
9458614fb12SMax Laier static void
94672fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam)
947df8bae1dSRodney W. Grimes {
94872fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
949df8bae1dSRodney W. Grimes 
950e8c2601dSPoul-Henning Kamp 	ifp->if_flags &= ~flag;
95198b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
952e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
953e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
954df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
955df8bae1dSRodney W. Grimes 	if_qflush(&ifp->if_snd);
956a9771948SGleb Smirnoff #ifdef DEV_CARP
957a9771948SGleb Smirnoff 	if (ifp->if_carp)
958a9771948SGleb Smirnoff 		carp_carpdev_state(ifp->if_carp);
959a9771948SGleb Smirnoff #endif
960df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
961df8bae1dSRodney W. Grimes }
962df8bae1dSRodney W. Grimes 
963df8bae1dSRodney W. Grimes /*
964df8bae1dSRodney W. Grimes  * Mark an interface up and notify protocols of
965df8bae1dSRodney W. Grimes  * the transition.
966df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
967df8bae1dSRodney W. Grimes  */
9688614fb12SMax Laier static void
96972fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam)
970df8bae1dSRodney W. Grimes {
97172fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
972df8bae1dSRodney W. Grimes 
973e8c2601dSPoul-Henning Kamp 	ifp->if_flags |= flag;
97498b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
975e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
976e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
977df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFUP, ifa->ifa_addr);
978a9771948SGleb Smirnoff #ifdef DEV_CARP
979a9771948SGleb Smirnoff 	if (ifp->if_carp)
980a9771948SGleb Smirnoff 		carp_carpdev_state(ifp->if_carp);
981a9771948SGleb Smirnoff #endif
982df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
98382cd038dSYoshinobu Inoue #ifdef INET6
98482cd038dSYoshinobu Inoue 	in6_if_up(ifp);
98582cd038dSYoshinobu Inoue #endif
986df8bae1dSRodney W. Grimes }
987df8bae1dSRodney W. Grimes 
98894f5c9cfSSam Leffler void	(*vlan_link_state_p)(struct ifnet *, int);	/* XXX: private from if_vlan */
98994f5c9cfSSam Leffler 
99094f5c9cfSSam Leffler /*
99194f5c9cfSSam Leffler  * Handle a change in the interface link state.
99294f5c9cfSSam Leffler  */
99394f5c9cfSSam Leffler void
99494f5c9cfSSam Leffler if_link_state_change(struct ifnet *ifp, int link_state)
99594f5c9cfSSam Leffler {
99694f5c9cfSSam Leffler 	int link;
99794f5c9cfSSam Leffler 
9984d96314fSGleb Smirnoff 	/* Return if state hasn't changed. */
9994d96314fSGleb Smirnoff 	if (ifp->if_link_state == link_state)
10004d96314fSGleb Smirnoff 		return;
10014d96314fSGleb Smirnoff 
100294f5c9cfSSam Leffler 	ifp->if_link_state = link_state;
10034d96314fSGleb Smirnoff 
10044d96314fSGleb Smirnoff 	/* Notify that the link state has changed. */
100594f5c9cfSSam Leffler 	rt_ifmsg(ifp);
100694f5c9cfSSam Leffler 	if (link_state == LINK_STATE_UP)
100794f5c9cfSSam Leffler 		link = NOTE_LINKUP;
100894f5c9cfSSam Leffler 	else if (link_state == LINK_STATE_DOWN)
100994f5c9cfSSam Leffler 		link = NOTE_LINKDOWN;
101094f5c9cfSSam Leffler 	else
101194f5c9cfSSam Leffler 		link = NOTE_LINKINV;
101294f5c9cfSSam Leffler 	KNOTE_UNLOCKED(&ifp->if_klist, link);
101394f5c9cfSSam Leffler 	if (ifp->if_nvlans != 0)
101494f5c9cfSSam Leffler 		(*vlan_link_state_p)(ifp, link);
10151c7899c7SGleb Smirnoff 
10161c7899c7SGleb Smirnoff 	if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) &&
10171c7899c7SGleb Smirnoff 	    IFP2AC(ifp)->ac_netgraph != NULL)
10181c7899c7SGleb Smirnoff 		(*ng_ether_link_state_p)(ifp, link_state);
10194d96314fSGleb Smirnoff #ifdef DEV_CARP
10204d96314fSGleb Smirnoff 	if (ifp->if_carp)
10214d96314fSGleb Smirnoff 		carp_carpdev_state(ifp->if_carp);
10224d96314fSGleb Smirnoff #endif
10235515c2e7SGleb Smirnoff 	if (log_link_state_change)
10248b02df24SGleb Smirnoff 		log(LOG_NOTICE, "%s: link state changed to %s\n", ifp->if_xname,
10258b02df24SGleb Smirnoff 		    (link_state == LINK_STATE_UP) ? "UP" : "DOWN" );
102694f5c9cfSSam Leffler }
102794f5c9cfSSam Leffler 
1028df8bae1dSRodney W. Grimes /*
1029e8c2601dSPoul-Henning Kamp  * Mark an interface down and notify protocols of
1030e8c2601dSPoul-Henning Kamp  * the transition.
1031e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
1032e8c2601dSPoul-Henning Kamp  */
1033e8c2601dSPoul-Henning Kamp void
103472fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp)
1035e8c2601dSPoul-Henning Kamp {
1036e8c2601dSPoul-Henning Kamp 
1037e8c2601dSPoul-Henning Kamp 	if_unroute(ifp, IFF_UP, AF_UNSPEC);
1038e8c2601dSPoul-Henning Kamp }
1039e8c2601dSPoul-Henning Kamp 
1040e8c2601dSPoul-Henning Kamp /*
1041e8c2601dSPoul-Henning Kamp  * Mark an interface up and notify protocols of
1042e8c2601dSPoul-Henning Kamp  * the transition.
1043e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
1044e8c2601dSPoul-Henning Kamp  */
1045e8c2601dSPoul-Henning Kamp void
104672fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp)
1047e8c2601dSPoul-Henning Kamp {
1048e8c2601dSPoul-Henning Kamp 
1049e8c2601dSPoul-Henning Kamp 	if_route(ifp, IFF_UP, AF_UNSPEC);
1050e8c2601dSPoul-Henning Kamp }
1051e8c2601dSPoul-Henning Kamp 
1052e8c2601dSPoul-Henning Kamp /*
1053df8bae1dSRodney W. Grimes  * Flush an interface queue.
1054df8bae1dSRodney W. Grimes  */
10553bda9f9bSPoul-Henning Kamp static void
105602b199f1SMax Laier if_qflush(struct ifaltq *ifq)
1057df8bae1dSRodney W. Grimes {
105872fd1b6aSDag-Erling Smørgrav 	struct mbuf *m, *n;
1059df8bae1dSRodney W. Grimes 
10607b21048cSMax Laier 	IFQ_LOCK(ifq);
106102b199f1SMax Laier #ifdef ALTQ
106202b199f1SMax Laier 	if (ALTQ_IS_ENABLED(ifq))
106302b199f1SMax Laier 		ALTQ_PURGE(ifq);
106402b199f1SMax Laier #endif
1065df8bae1dSRodney W. Grimes 	n = ifq->ifq_head;
10669448326fSPoul-Henning Kamp 	while ((m = n) != 0) {
1067df8bae1dSRodney W. Grimes 		n = m->m_act;
1068df8bae1dSRodney W. Grimes 		m_freem(m);
1069df8bae1dSRodney W. Grimes 	}
1070df8bae1dSRodney W. Grimes 	ifq->ifq_head = 0;
1071df8bae1dSRodney W. Grimes 	ifq->ifq_tail = 0;
1072df8bae1dSRodney W. Grimes 	ifq->ifq_len = 0;
10737b21048cSMax Laier 	IFQ_UNLOCK(ifq);
1074df8bae1dSRodney W. Grimes }
1075df8bae1dSRodney W. Grimes 
1076df8bae1dSRodney W. Grimes /*
1077df8bae1dSRodney W. Grimes  * Handle interface watchdog timer routines.  Called
1078df8bae1dSRodney W. Grimes  * from softclock, we decrement timers (if set) and
1079df8bae1dSRodney W. Grimes  * call the appropriate interface routine on expiration.
1080af5e59bfSRobert Watson  *
1081af5e59bfSRobert Watson  * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called
1082af5e59bfSRobert Watson  * holding Giant.  If we switch to an MPSAFE callout, we likely need to grab
1083af5e59bfSRobert Watson  * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface.
1084df8bae1dSRodney W. Grimes  */
10853bda9f9bSPoul-Henning Kamp static void
108672fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg)
1087df8bae1dSRodney W. Grimes {
108872fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
1089df8bae1dSRodney W. Grimes 	int s = splimp();
1090df8bae1dSRodney W. Grimes 
1091b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1092fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1093df8bae1dSRodney W. Grimes 		if (ifp->if_timer == 0 || --ifp->if_timer)
1094df8bae1dSRodney W. Grimes 			continue;
1095df8bae1dSRodney W. Grimes 		if (ifp->if_watchdog)
10964a5f1499SDavid Greenman 			(*ifp->if_watchdog)(ifp);
1097df8bae1dSRodney W. Grimes 	}
1098b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1099df8bae1dSRodney W. Grimes 	splx(s);
1100df8bae1dSRodney W. Grimes 	timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
1101df8bae1dSRodney W. Grimes }
1102df8bae1dSRodney W. Grimes 
1103df8bae1dSRodney W. Grimes /*
1104df8bae1dSRodney W. Grimes  * Map interface name to
1105df8bae1dSRodney W. Grimes  * interface structure pointer.
1106df8bae1dSRodney W. Grimes  */
1107df8bae1dSRodney W. Grimes struct ifnet *
110830aad87dSBrooks Davis ifunit(const char *name)
1109df8bae1dSRodney W. Grimes {
11108b7805e4SBoris Popov 	struct ifnet *ifp;
1111df8bae1dSRodney W. Grimes 
1112b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1113fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
111436c19a57SBrooks Davis 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
1115df8bae1dSRodney W. Grimes 			break;
1116df8bae1dSRodney W. Grimes 	}
1117b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1118df8bae1dSRodney W. Grimes 	return (ifp);
1119df8bae1dSRodney W. Grimes }
1120df8bae1dSRodney W. Grimes 
112182cd038dSYoshinobu Inoue /*
1122f13ad206SJonathan Lemon  * Hardware specific interface ioctls.
1123df8bae1dSRodney W. Grimes  */
1124f13ad206SJonathan Lemon static int
1125f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
1126df8bae1dSRodney W. Grimes {
1127f13ad206SJonathan Lemon 	struct ifreq *ifr;
1128413dd0baSPoul-Henning Kamp 	struct ifstat *ifs;
1129f13ad206SJonathan Lemon 	int error = 0;
113062f76486SMaxim Sobolev 	int new_flags;
113136c19a57SBrooks Davis 	size_t namelen, onamelen;
113236c19a57SBrooks Davis 	char new_name[IFNAMSIZ];
113336c19a57SBrooks Davis 	struct ifaddr *ifa;
113436c19a57SBrooks Davis 	struct sockaddr_dl *sdl;
1135df8bae1dSRodney W. Grimes 
1136df8bae1dSRodney W. Grimes 	ifr = (struct ifreq *)data;
113730aad87dSBrooks Davis 	switch (cmd) {
1138de593450SJonathan Lemon 	case SIOCGIFINDEX:
1139de593450SJonathan Lemon 		ifr->ifr_index = ifp->if_index;
1140de593450SJonathan Lemon 		break;
1141de593450SJonathan Lemon 
1142df8bae1dSRodney W. Grimes 	case SIOCGIFFLAGS:
114362f76486SMaxim Sobolev 		ifr->ifr_flags = ifp->if_flags & 0xffff;
114462f76486SMaxim Sobolev 		ifr->ifr_flagshigh = ifp->if_flags >> 16;
1145df8bae1dSRodney W. Grimes 		break;
1146df8bae1dSRodney W. Grimes 
1147016da741SJonathan Lemon 	case SIOCGIFCAP:
1148016da741SJonathan Lemon 		ifr->ifr_reqcap = ifp->if_capabilities;
1149016da741SJonathan Lemon 		ifr->ifr_curcap = ifp->if_capenable;
1150016da741SJonathan Lemon 		break;
1151016da741SJonathan Lemon 
11528f293a63SRobert Watson #ifdef MAC
11538f293a63SRobert Watson 	case SIOCGIFMAC:
115431566c96SJohn Baldwin 		error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp);
11558f293a63SRobert Watson 		break;
11568f293a63SRobert Watson #endif
11578f293a63SRobert Watson 
1158df8bae1dSRodney W. Grimes 	case SIOCGIFMETRIC:
1159df8bae1dSRodney W. Grimes 		ifr->ifr_metric = ifp->if_metric;
1160df8bae1dSRodney W. Grimes 		break;
1161df8bae1dSRodney W. Grimes 
1162a7028af7SDavid Greenman 	case SIOCGIFMTU:
1163a7028af7SDavid Greenman 		ifr->ifr_mtu = ifp->if_mtu;
1164a7028af7SDavid Greenman 		break;
1165a7028af7SDavid Greenman 
1166074c4a4eSGarrett Wollman 	case SIOCGIFPHYS:
1167074c4a4eSGarrett Wollman 		ifr->ifr_phys = ifp->if_physical;
1168074c4a4eSGarrett Wollman 		break;
1169074c4a4eSGarrett Wollman 
1170df8bae1dSRodney W. Grimes 	case SIOCSIFFLAGS:
117144731cabSJohn Baldwin 		error = suser(td);
11729448326fSPoul-Henning Kamp 		if (error)
1173df8bae1dSRodney W. Grimes 			return (error);
117462f76486SMaxim Sobolev 		new_flags = (ifr->ifr_flags & 0xffff) |
117562f76486SMaxim Sobolev 		    (ifr->ifr_flagshigh << 16);
1176cf4b9371SPoul-Henning Kamp 		if (ifp->if_flags & IFF_SMART) {
1177cf4b9371SPoul-Henning Kamp 			/* Smart drivers twiddle their own routes */
11782f55ead7SPoul-Henning Kamp 		} else if (ifp->if_flags & IFF_UP &&
117962f76486SMaxim Sobolev 		    (new_flags & IFF_UP) == 0) {
1180df8bae1dSRodney W. Grimes 			int s = splimp();
1181df8bae1dSRodney W. Grimes 			if_down(ifp);
1182df8bae1dSRodney W. Grimes 			splx(s);
118362f76486SMaxim Sobolev 		} else if (new_flags & IFF_UP &&
1184cf4b9371SPoul-Henning Kamp 		    (ifp->if_flags & IFF_UP) == 0) {
1185df8bae1dSRodney W. Grimes 			int s = splimp();
1186df8bae1dSRodney W. Grimes 			if_up(ifp);
1187df8bae1dSRodney W. Grimes 			splx(s);
1188df8bae1dSRodney W. Grimes 		}
1189df8bae1dSRodney W. Grimes 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
119062f76486SMaxim Sobolev 			(new_flags &~ IFF_CANTCHANGE);
1191ffb079beSMaxim Sobolev 		if (new_flags & IFF_PPROMISC) {
1192ffb079beSMaxim Sobolev 			/* Permanently promiscuous mode requested */
1193ffb079beSMaxim Sobolev 			ifp->if_flags |= IFF_PROMISC;
1194ffb079beSMaxim Sobolev 		} else if (ifp->if_pcount == 0) {
1195ffb079beSMaxim Sobolev 			ifp->if_flags &= ~IFF_PROMISC;
1196ffb079beSMaxim Sobolev 		}
119731302ebfSRobert Watson 		if (ifp->if_ioctl) {
119831302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1199df8bae1dSRodney W. Grimes 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
120031302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
120131302ebfSRobert Watson 		}
120298b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1203df8bae1dSRodney W. Grimes 		break;
1204df8bae1dSRodney W. Grimes 
1205016da741SJonathan Lemon 	case SIOCSIFCAP:
120644731cabSJohn Baldwin 		error = suser(td);
1207016da741SJonathan Lemon 		if (error)
1208016da741SJonathan Lemon 			return (error);
1209efb4018bSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1210efb4018bSYaroslav Tykhiy 			return (EOPNOTSUPP);
1211016da741SJonathan Lemon 		if (ifr->ifr_reqcap & ~ifp->if_capabilities)
1212016da741SJonathan Lemon 			return (EINVAL);
121331302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1214efb4018bSYaroslav Tykhiy 		error = (*ifp->if_ioctl)(ifp, cmd, data);
121531302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1216efb4018bSYaroslav Tykhiy 		if (error == 0)
1217efb4018bSYaroslav Tykhiy 			getmicrotime(&ifp->if_lastchange);
1218016da741SJonathan Lemon 		break;
1219016da741SJonathan Lemon 
12208f293a63SRobert Watson #ifdef MAC
12218f293a63SRobert Watson 	case SIOCSIFMAC:
122231566c96SJohn Baldwin 		error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp);
12238f293a63SRobert Watson 		break;
12248f293a63SRobert Watson #endif
12258f293a63SRobert Watson 
122636c19a57SBrooks Davis 	case SIOCSIFNAME:
122736c19a57SBrooks Davis 		error = suser(td);
1228bc1470f1SBrooks Davis 		if (error != 0)
122936c19a57SBrooks Davis 			return (error);
123036c19a57SBrooks Davis 		error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL);
1231bc1470f1SBrooks Davis 		if (error != 0)
123236c19a57SBrooks Davis 			return (error);
1233bc1470f1SBrooks Davis 		if (new_name[0] == '\0')
1234bc1470f1SBrooks Davis 			return (EINVAL);
123536c19a57SBrooks Davis 		if (ifunit(new_name) != NULL)
123636c19a57SBrooks Davis 			return (EEXIST);
123736c19a57SBrooks Davis 
123825a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
123936c19a57SBrooks Davis 		/* Announce the departure of the interface. */
124036c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
124136c19a57SBrooks Davis 
124271672bb6SBrooks Davis 		log(LOG_INFO, "%s: changing name to '%s'\n",
124371672bb6SBrooks Davis 		    ifp->if_xname, new_name);
124471672bb6SBrooks Davis 
124536c19a57SBrooks Davis 		strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
12469b98ee2cSLuigi Rizzo 		ifa = ifaddr_byindex(ifp->if_index);
124736c19a57SBrooks Davis 		IFA_LOCK(ifa);
124836c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
124936c19a57SBrooks Davis 		namelen = strlen(new_name);
125036c19a57SBrooks Davis 		onamelen = sdl->sdl_nlen;
125136c19a57SBrooks Davis 		/*
125236c19a57SBrooks Davis 		 * Move the address if needed.  This is safe because we
125336c19a57SBrooks Davis 		 * allocate space for a name of length IFNAMSIZ when we
125436c19a57SBrooks Davis 		 * create this in if_attach().
125536c19a57SBrooks Davis 		 */
125636c19a57SBrooks Davis 		if (namelen != onamelen) {
125736c19a57SBrooks Davis 			bcopy(sdl->sdl_data + onamelen,
125836c19a57SBrooks Davis 			    sdl->sdl_data + namelen, sdl->sdl_alen);
125936c19a57SBrooks Davis 		}
126036c19a57SBrooks Davis 		bcopy(new_name, sdl->sdl_data, namelen);
126136c19a57SBrooks Davis 		sdl->sdl_nlen = namelen;
126236c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_netmask;
126336c19a57SBrooks Davis 		bzero(sdl->sdl_data, onamelen);
126436c19a57SBrooks Davis 		while (namelen != 0)
126536c19a57SBrooks Davis 			sdl->sdl_data[--namelen] = 0xff;
126636c19a57SBrooks Davis 		IFA_UNLOCK(ifa);
126736c19a57SBrooks Davis 
126825a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
126936c19a57SBrooks Davis 		/* Announce the return of the interface. */
127036c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
127136c19a57SBrooks Davis 		break;
127236c19a57SBrooks Davis 
1273df8bae1dSRodney W. Grimes 	case SIOCSIFMETRIC:
127444731cabSJohn Baldwin 		error = suser(td);
12759448326fSPoul-Henning Kamp 		if (error)
1276df8bae1dSRodney W. Grimes 			return (error);
1277df8bae1dSRodney W. Grimes 		ifp->if_metric = ifr->ifr_metric;
127898b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1279df8bae1dSRodney W. Grimes 		break;
1280df8bae1dSRodney W. Grimes 
1281074c4a4eSGarrett Wollman 	case SIOCSIFPHYS:
128244731cabSJohn Baldwin 		error = suser(td);
1283e39a0280SGary Palmer 		if (error)
1284913e410eSYaroslav Tykhiy 			return (error);
1285913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1286913e410eSYaroslav Tykhiy 			return (EOPNOTSUPP);
128731302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1288e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
128931302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1290e39a0280SGary Palmer 		if (error == 0)
129198b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1292913e410eSYaroslav Tykhiy 		break;
1293074c4a4eSGarrett Wollman 
1294a7028af7SDavid Greenman 	case SIOCSIFMTU:
129582cd038dSYoshinobu Inoue 	{
129682cd038dSYoshinobu Inoue 		u_long oldmtu = ifp->if_mtu;
129782cd038dSYoshinobu Inoue 
129844731cabSJohn Baldwin 		error = suser(td);
12999448326fSPoul-Henning Kamp 		if (error)
1300a7028af7SDavid Greenman 			return (error);
1301aab3beeeSBrian Somers 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
130275ee03cbSDavid Greenman 			return (EINVAL);
1303f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1304f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
130531302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1306e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
130731302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
130848f71763SRuslan Ermilov 		if (error == 0) {
130998b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
131048f71763SRuslan Ermilov 			rt_ifmsg(ifp);
131148f71763SRuslan Ermilov 		}
131282cd038dSYoshinobu Inoue 		/*
131382cd038dSYoshinobu Inoue 		 * If the link MTU changed, do network layer specific procedure.
131482cd038dSYoshinobu Inoue 		 */
131582cd038dSYoshinobu Inoue 		if (ifp->if_mtu != oldmtu) {
131682cd038dSYoshinobu Inoue #ifdef INET6
131782cd038dSYoshinobu Inoue 			nd6_setmtu(ifp);
131882cd038dSYoshinobu Inoue #endif
131982cd038dSYoshinobu Inoue 		}
1320f13ad206SJonathan Lemon 		break;
132182cd038dSYoshinobu Inoue 	}
1322a7028af7SDavid Greenman 
1323df8bae1dSRodney W. Grimes 	case SIOCADDMULTI:
1324df8bae1dSRodney W. Grimes 	case SIOCDELMULTI:
132544731cabSJohn Baldwin 		error = suser(td);
13269448326fSPoul-Henning Kamp 		if (error)
1327df8bae1dSRodney W. Grimes 			return (error);
1328477180fbSGarrett Wollman 
1329477180fbSGarrett Wollman 		/* Don't allow group membership on non-multicast interfaces. */
1330477180fbSGarrett Wollman 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
1331f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
1332477180fbSGarrett Wollman 
1333477180fbSGarrett Wollman 		/* Don't let users screw up protocols' entries. */
1334477180fbSGarrett Wollman 		if (ifr->ifr_addr.sa_family != AF_LINK)
1335f13ad206SJonathan Lemon 			return (EINVAL);
1336477180fbSGarrett Wollman 
1337477180fbSGarrett Wollman 		if (cmd == SIOCADDMULTI) {
1338477180fbSGarrett Wollman 			struct ifmultiaddr *ifma;
1339477180fbSGarrett Wollman 			error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
1340477180fbSGarrett Wollman 		} else {
1341477180fbSGarrett Wollman 			error = if_delmulti(ifp, &ifr->ifr_addr);
1342477180fbSGarrett Wollman 		}
1343e39a0280SGary Palmer 		if (error == 0)
134498b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1345f13ad206SJonathan Lemon 		break;
1346df8bae1dSRodney W. Grimes 
134741b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR:
134841b3e8e5SJun-ichiro itojun Hagino 	case SIOCDIFPHYADDR:
134941b3e8e5SJun-ichiro itojun Hagino #ifdef INET6
135041b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR_IN6:
135141b3e8e5SJun-ichiro itojun Hagino #endif
135233841545SHajimu UMEMOTO 	case SIOCSLIFPHYADDR:
1353a912e453SPeter Wemm 	case SIOCSIFMEDIA:
1354d7189ec6SJoerg Wunsch 	case SIOCSIFGENERIC:
135544731cabSJohn Baldwin 		error = suser(td);
1356a912e453SPeter Wemm 		if (error)
1357a912e453SPeter Wemm 			return (error);
1358f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1359a912e453SPeter Wemm 			return (EOPNOTSUPP);
136031302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1361a912e453SPeter Wemm 		error = (*ifp->if_ioctl)(ifp, cmd, data);
136231302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1363a912e453SPeter Wemm 		if (error == 0)
136498b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1365f13ad206SJonathan Lemon 		break;
1366a912e453SPeter Wemm 
1367413dd0baSPoul-Henning Kamp 	case SIOCGIFSTATUS:
1368413dd0baSPoul-Henning Kamp 		ifs = (struct ifstat *)data;
1369413dd0baSPoul-Henning Kamp 		ifs->ascii[0] = '\0';
1370413dd0baSPoul-Henning Kamp 
137133841545SHajimu UMEMOTO 	case SIOCGIFPSRCADDR:
137233841545SHajimu UMEMOTO 	case SIOCGIFPDSTADDR:
137333841545SHajimu UMEMOTO 	case SIOCGLIFPHYADDR:
1374a912e453SPeter Wemm 	case SIOCGIFMEDIA:
1375d7189ec6SJoerg Wunsch 	case SIOCGIFGENERIC:
1376913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1377a912e453SPeter Wemm 			return (EOPNOTSUPP);
137831302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1379f13ad206SJonathan Lemon 		error = (*ifp->if_ioctl)(ifp, cmd, data);
138031302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1381f13ad206SJonathan Lemon 		break;
1382a912e453SPeter Wemm 
1383b106252cSBill Paul 	case SIOCSIFLLADDR:
138444731cabSJohn Baldwin 		error = suser(td);
1385b106252cSBill Paul 		if (error)
1386b106252cSBill Paul 			return (error);
1387f13ad206SJonathan Lemon 		error = if_setlladdr(ifp,
138866ce51ceSArchie Cobbs 		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
1389f13ad206SJonathan Lemon 		break;
139066ce51ceSArchie Cobbs 
1391df8bae1dSRodney W. Grimes 	default:
1392f13ad206SJonathan Lemon 		error = ENOIOCTL;
1393f13ad206SJonathan Lemon 		break;
1394f13ad206SJonathan Lemon 	}
1395f13ad206SJonathan Lemon 	return (error);
1396f13ad206SJonathan Lemon }
1397f13ad206SJonathan Lemon 
1398f13ad206SJonathan Lemon /*
1399f13ad206SJonathan Lemon  * Interface ioctls.
1400f13ad206SJonathan Lemon  */
1401f13ad206SJonathan Lemon int
140272fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
1403f13ad206SJonathan Lemon {
1404f13ad206SJonathan Lemon 	struct ifnet *ifp;
1405f13ad206SJonathan Lemon 	struct ifreq *ifr;
1406f13ad206SJonathan Lemon 	int error;
140762f76486SMaxim Sobolev 	int oif_flags;
1408f13ad206SJonathan Lemon 
1409f13ad206SJonathan Lemon 	switch (cmd) {
1410f13ad206SJonathan Lemon 	case SIOCGIFCONF:
1411f13ad206SJonathan Lemon 	case OSIOCGIFCONF:
1412f13ad206SJonathan Lemon 		return (ifconf(cmd, data));
1413f13ad206SJonathan Lemon 	}
1414f13ad206SJonathan Lemon 	ifr = (struct ifreq *)data;
1415f13ad206SJonathan Lemon 
1416f13ad206SJonathan Lemon 	switch (cmd) {
1417f13ad206SJonathan Lemon 	case SIOCIFCREATE:
1418f13ad206SJonathan Lemon 	case SIOCIFDESTROY:
141944731cabSJohn Baldwin 		if ((error = suser(td)) != 0)
1420f13ad206SJonathan Lemon 			return (error);
1421f13ad206SJonathan Lemon 		return ((cmd == SIOCIFCREATE) ?
1422f13ad206SJonathan Lemon 			if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) :
1423f13ad206SJonathan Lemon 			if_clone_destroy(ifr->ifr_name));
1424f13ad206SJonathan Lemon 
1425f13ad206SJonathan Lemon 	case SIOCIFGCLONERS:
1426f13ad206SJonathan Lemon 		return (if_clone_list((struct if_clonereq *)data));
1427f13ad206SJonathan Lemon 	}
1428f13ad206SJonathan Lemon 
1429f13ad206SJonathan Lemon 	ifp = ifunit(ifr->ifr_name);
1430f13ad206SJonathan Lemon 	if (ifp == 0)
1431f13ad206SJonathan Lemon 		return (ENXIO);
1432f13ad206SJonathan Lemon 
1433f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
1434f13ad206SJonathan Lemon 	if (error != ENOIOCTL)
1435f13ad206SJonathan Lemon 		return (error);
1436f13ad206SJonathan Lemon 
143782cd038dSYoshinobu Inoue 	oif_flags = ifp->if_flags;
1438df8bae1dSRodney W. Grimes 	if (so->so_proto == 0)
1439df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1440df8bae1dSRodney W. Grimes #ifndef COMPAT_43
144182cd038dSYoshinobu Inoue 	error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
14422c37256eSGarrett Wollman 								 data,
1443b40ce416SJulian Elischer 								 ifp, td));
1444df8bae1dSRodney W. Grimes #else
1445df8bae1dSRodney W. Grimes 	{
1446df8bae1dSRodney W. Grimes 		int ocmd = cmd;
1447df8bae1dSRodney W. Grimes 
1448df8bae1dSRodney W. Grimes 		switch (cmd) {
1449df8bae1dSRodney W. Grimes 
1450df8bae1dSRodney W. Grimes 		case SIOCSIFDSTADDR:
1451df8bae1dSRodney W. Grimes 		case SIOCSIFADDR:
1452df8bae1dSRodney W. Grimes 		case SIOCSIFBRDADDR:
1453df8bae1dSRodney W. Grimes 		case SIOCSIFNETMASK:
1454df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN
1455df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_family == 0 &&
1456df8bae1dSRodney W. Grimes 			    ifr->ifr_addr.sa_len < 16) {
1457df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
1458df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1459df8bae1dSRodney W. Grimes 			}
1460df8bae1dSRodney W. Grimes #else
1461df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_len == 0)
1462df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1463df8bae1dSRodney W. Grimes #endif
1464df8bae1dSRodney W. Grimes 			break;
1465df8bae1dSRodney W. Grimes 
1466df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1467df8bae1dSRodney W. Grimes 			cmd = SIOCGIFADDR;
1468df8bae1dSRodney W. Grimes 			break;
1469df8bae1dSRodney W. Grimes 
1470df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1471df8bae1dSRodney W. Grimes 			cmd = SIOCGIFDSTADDR;
1472df8bae1dSRodney W. Grimes 			break;
1473df8bae1dSRodney W. Grimes 
1474df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1475df8bae1dSRodney W. Grimes 			cmd = SIOCGIFBRDADDR;
1476df8bae1dSRodney W. Grimes 			break;
1477df8bae1dSRodney W. Grimes 
1478df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1479df8bae1dSRodney W. Grimes 			cmd = SIOCGIFNETMASK;
1480df8bae1dSRodney W. Grimes 		}
14812c37256eSGarrett Wollman 		error =  ((*so->so_proto->pr_usrreqs->pru_control)(so,
14822c37256eSGarrett Wollman 								   cmd,
14832c37256eSGarrett Wollman 								   data,
1484b40ce416SJulian Elischer 								   ifp, td));
1485df8bae1dSRodney W. Grimes 		switch (ocmd) {
1486df8bae1dSRodney W. Grimes 
1487df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1488df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1489df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1490df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1491df8bae1dSRodney W. Grimes 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
149282cd038dSYoshinobu Inoue 
149382cd038dSYoshinobu Inoue 		}
149482cd038dSYoshinobu Inoue 	}
149582cd038dSYoshinobu Inoue #endif /* COMPAT_43 */
149682cd038dSYoshinobu Inoue 
149782cd038dSYoshinobu Inoue 	if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
149882cd038dSYoshinobu Inoue #ifdef INET6
149988ff5695SSUZUKI Shinsuke 		DELAY(100);/* XXX: temporary workaround for fxp issue*/
150082cd038dSYoshinobu Inoue 		if (ifp->if_flags & IFF_UP) {
150182cd038dSYoshinobu Inoue 			int s = splimp();
150282cd038dSYoshinobu Inoue 			in6_if_up(ifp);
150382cd038dSYoshinobu Inoue 			splx(s);
150482cd038dSYoshinobu Inoue 		}
150582cd038dSYoshinobu Inoue #endif
1506df8bae1dSRodney W. Grimes 	}
1507df8bae1dSRodney W. Grimes 	return (error);
1508df8bae1dSRodney W. Grimes }
1509df8bae1dSRodney W. Grimes 
1510df8bae1dSRodney W. Grimes /*
1511963e4c2aSGarrett Wollman  * Set/clear promiscuous mode on interface ifp based on the truth value
1512963e4c2aSGarrett Wollman  * of pswitch.  The calls are reference counted so that only the first
1513963e4c2aSGarrett Wollman  * "on" request actually has an effect, as does the final "off" request.
1514963e4c2aSGarrett Wollman  * Results are undefined if the "off" and "on" requests are not matched.
1515963e4c2aSGarrett Wollman  */
1516963e4c2aSGarrett Wollman int
151772fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch)
1518963e4c2aSGarrett Wollman {
1519963e4c2aSGarrett Wollman 	struct ifreq ifr;
15204a26224cSGarrett Wollman 	int error;
15214f3c11a6SBill Fenner 	int oldflags, oldpcount;
1522963e4c2aSGarrett Wollman 
15234f3c11a6SBill Fenner 	oldpcount = ifp->if_pcount;
15242c514a31SBrian Somers 	oldflags = ifp->if_flags;
1525ffb079beSMaxim Sobolev 	if (ifp->if_flags & IFF_PPROMISC) {
1526ffb079beSMaxim Sobolev 		/* Do nothing if device is in permanently promiscuous mode */
1527ffb079beSMaxim Sobolev 		ifp->if_pcount += pswitch ? 1 : -1;
1528ffb079beSMaxim Sobolev 		return (0);
1529ffb079beSMaxim Sobolev 	}
1530963e4c2aSGarrett Wollman 	if (pswitch) {
1531963e4c2aSGarrett Wollman 		/*
1532963e4c2aSGarrett Wollman 		 * If the device is not configured up, we cannot put it in
1533963e4c2aSGarrett Wollman 		 * promiscuous mode.
1534963e4c2aSGarrett Wollman 		 */
1535963e4c2aSGarrett Wollman 		if ((ifp->if_flags & IFF_UP) == 0)
1536963e4c2aSGarrett Wollman 			return (ENETDOWN);
1537963e4c2aSGarrett Wollman 		if (ifp->if_pcount++ != 0)
1538963e4c2aSGarrett Wollman 			return (0);
1539963e4c2aSGarrett Wollman 		ifp->if_flags |= IFF_PROMISC;
1540963e4c2aSGarrett Wollman 	} else {
1541963e4c2aSGarrett Wollman 		if (--ifp->if_pcount > 0)
1542963e4c2aSGarrett Wollman 			return (0);
1543963e4c2aSGarrett Wollman 		ifp->if_flags &= ~IFF_PROMISC;
1544963e4c2aSGarrett Wollman 	}
154562f76486SMaxim Sobolev 	ifr.ifr_flags = ifp->if_flags & 0xffff;
154662f76486SMaxim Sobolev 	ifr.ifr_flagshigh = ifp->if_flags >> 16;
154731302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
15484a26224cSGarrett Wollman 	error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
154931302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
15504f3c11a6SBill Fenner 	if (error == 0) {
15519bf40edeSBrooks Davis 		log(LOG_INFO, "%s: promiscuous mode %s\n",
15529bf40edeSBrooks Davis 		    ifp->if_xname,
15534f3c11a6SBill Fenner 		    (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
15544a26224cSGarrett Wollman 		rt_ifmsg(ifp);
15554f3c11a6SBill Fenner 	} else {
15564f3c11a6SBill Fenner 		ifp->if_pcount = oldpcount;
15572c514a31SBrian Somers 		ifp->if_flags = oldflags;
15584f3c11a6SBill Fenner 	}
15594a26224cSGarrett Wollman 	return error;
1560963e4c2aSGarrett Wollman }
1561963e4c2aSGarrett Wollman 
1562963e4c2aSGarrett Wollman /*
1563df8bae1dSRodney W. Grimes  * Return interface configuration
1564df8bae1dSRodney W. Grimes  * of system.  List may be used
1565df8bae1dSRodney W. Grimes  * in later ioctl's (above) to get
1566df8bae1dSRodney W. Grimes  * other information.
1567df8bae1dSRodney W. Grimes  */
1568df8bae1dSRodney W. Grimes /*ARGSUSED*/
15693bda9f9bSPoul-Henning Kamp static int
157072fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data)
1571df8bae1dSRodney W. Grimes {
15720b59d917SJonathan Lemon 	struct ifconf *ifc = (struct ifconf *)data;
15730b59d917SJonathan Lemon 	struct ifnet *ifp;
15740b59d917SJonathan Lemon 	struct ifaddr *ifa;
15754dcf2bbbSBrooks Davis 	struct ifreq ifr;
15764dcf2bbbSBrooks Davis 	struct sbuf *sb;
15774dcf2bbbSBrooks Davis 	int error, full = 0, valid_len, max_len;
1578df8bae1dSRodney W. Grimes 
15794dcf2bbbSBrooks Davis 	/* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */
15804dcf2bbbSBrooks Davis 	max_len = MAXPHYS - 1;
15814dcf2bbbSBrooks Davis 
1582b0b4b28bSXin LI 	/* Prevent hostile input from being able to crash the system */
1583b0b4b28bSXin LI 	if (ifc->ifc_len <= 0)
1584b0b4b28bSXin LI 		return (EINVAL);
1585b0b4b28bSXin LI 
15864dcf2bbbSBrooks Davis again:
15874dcf2bbbSBrooks Davis 	if (ifc->ifc_len <= max_len) {
15884dcf2bbbSBrooks Davis 		max_len = ifc->ifc_len;
15894dcf2bbbSBrooks Davis 		full = 1;
15904dcf2bbbSBrooks Davis 	}
15914dcf2bbbSBrooks Davis 	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
15924dcf2bbbSBrooks Davis 	max_len = 0;
15934dcf2bbbSBrooks Davis 	valid_len = 0;
15944dcf2bbbSBrooks Davis 
1595b30a244cSJeffrey Hsu 	IFNET_RLOCK();		/* could sleep XXX */
15960b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
15979bf40edeSBrooks Davis 		int addrs;
15982624cf89SGarrett Wollman 
1599fbd24c5eSColin Percival 		/*
1600fbd24c5eSColin Percival 		 * Zero the ifr_name buffer to make sure we don't
1601fbd24c5eSColin Percival 		 * disclose the contents of the stack.
1602fbd24c5eSColin Percival 		 */
1603fbd24c5eSColin Percival 		memset(ifr.ifr_name, 0, sizeof(ifr.ifr_name));
1604fbd24c5eSColin Percival 
16059bf40edeSBrooks Davis 		if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name))
16064dcf2bbbSBrooks Davis 		    >= sizeof(ifr.ifr_name))
16074dcf2bbbSBrooks Davis 			return (ENAMETOOLONG);
16082624cf89SGarrett Wollman 
160975c13541SPoul-Henning Kamp 		addrs = 0;
16102defe5cdSJonathan Lemon 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
16112defe5cdSJonathan Lemon 			struct sockaddr *sa = ifa->ifa_addr;
16122defe5cdSJonathan Lemon 
1613a854ed98SJohn Baldwin 			if (jailed(curthread->td_ucred) &&
1614a854ed98SJohn Baldwin 			    prison_if(curthread->td_ucred, sa))
161575c13541SPoul-Henning Kamp 				continue;
161675c13541SPoul-Henning Kamp 			addrs++;
1617df8bae1dSRodney W. Grimes #ifdef COMPAT_43
1618df8bae1dSRodney W. Grimes 			if (cmd == OSIOCGIFCONF) {
1619df8bae1dSRodney W. Grimes 				struct osockaddr *osa =
1620df8bae1dSRodney W. Grimes 					 (struct osockaddr *)&ifr.ifr_addr;
1621df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
1622df8bae1dSRodney W. Grimes 				osa->sa_family = sa->sa_family;
16234dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
16244dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1625df8bae1dSRodney W. Grimes 			} else
1626df8bae1dSRodney W. Grimes #endif
1627df8bae1dSRodney W. Grimes 			if (sa->sa_len <= sizeof(*sa)) {
1628df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
16294dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
16304dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1631df8bae1dSRodney W. Grimes 			} else {
16324dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr,
16334dcf2bbbSBrooks Davis 				    offsetof(struct ifreq, ifr_addr));
16344dcf2bbbSBrooks Davis 				max_len += offsetof(struct ifreq, ifr_addr);
16354dcf2bbbSBrooks Davis 				sbuf_bcat(sb, sa, sa->sa_len);
16364dcf2bbbSBrooks Davis 				max_len += sa->sa_len;
1637df8bae1dSRodney W. Grimes 			}
16384dcf2bbbSBrooks Davis 
16394dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
16404dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
1641df8bae1dSRodney W. Grimes 		}
16424dcf2bbbSBrooks Davis 		if (addrs == 0) {
164375c13541SPoul-Henning Kamp 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
16444dcf2bbbSBrooks Davis 			sbuf_bcat(sb, &ifr, sizeof(ifr));
16454dcf2bbbSBrooks Davis 			max_len += sizeof(ifr);
16464dcf2bbbSBrooks Davis 
16474dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
16484dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
164975c13541SPoul-Henning Kamp 		}
1650df8bae1dSRodney W. Grimes 	}
1651b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
16524dcf2bbbSBrooks Davis 
16534dcf2bbbSBrooks Davis 	/*
16544dcf2bbbSBrooks Davis 	 * If we didn't allocate enough space (uncommon), try again.  If
16554dcf2bbbSBrooks Davis 	 * we have already allocated as much space as we are allowed,
16564dcf2bbbSBrooks Davis 	 * return what we've got.
16574dcf2bbbSBrooks Davis 	 */
16584dcf2bbbSBrooks Davis 	if (valid_len != max_len && !full) {
16594dcf2bbbSBrooks Davis 		sbuf_delete(sb);
16604dcf2bbbSBrooks Davis 		goto again;
16614dcf2bbbSBrooks Davis 	}
16624dcf2bbbSBrooks Davis 
16634dcf2bbbSBrooks Davis 	ifc->ifc_len = valid_len;
16645ed8cedcSBrian Feldman 	sbuf_finish(sb);
16654dcf2bbbSBrooks Davis 	error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len);
16664dcf2bbbSBrooks Davis 	sbuf_delete(sb);
1667df8bae1dSRodney W. Grimes 	return (error);
1668df8bae1dSRodney W. Grimes }
1669df8bae1dSRodney W. Grimes 
16701158dfb7SGarrett Wollman /*
16718b25904eSGleb Smirnoff  * Just like ifpromisc(), but for all-multicast-reception mode.
16721158dfb7SGarrett Wollman  */
16731158dfb7SGarrett Wollman int
167472fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch)
16751158dfb7SGarrett Wollman {
16761158dfb7SGarrett Wollman 	int error = 0;
16771158dfb7SGarrett Wollman 	int s = splimp();
1678ee0a4f7eSSUZUKI Shinsuke 	struct ifreq ifr;
16791158dfb7SGarrett Wollman 
16801158dfb7SGarrett Wollman 	if (onswitch) {
16811158dfb7SGarrett Wollman 		if (ifp->if_amcount++ == 0) {
16821158dfb7SGarrett Wollman 			ifp->if_flags |= IFF_ALLMULTI;
168362f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
168462f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
168531302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1686ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
168731302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
16881158dfb7SGarrett Wollman 		}
16891158dfb7SGarrett Wollman 	} else {
16901158dfb7SGarrett Wollman 		if (ifp->if_amcount > 1) {
16911158dfb7SGarrett Wollman 			ifp->if_amcount--;
16921158dfb7SGarrett Wollman 		} else {
16931158dfb7SGarrett Wollman 			ifp->if_amcount = 0;
16941158dfb7SGarrett Wollman 			ifp->if_flags &= ~IFF_ALLMULTI;
169562f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;;
169662f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
169731302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1698ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
169931302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
17001158dfb7SGarrett Wollman 		}
17011158dfb7SGarrett Wollman 	}
17021158dfb7SGarrett Wollman 	splx(s);
17034a26224cSGarrett Wollman 
17044a26224cSGarrett Wollman 	if (error == 0)
17054a26224cSGarrett Wollman 		rt_ifmsg(ifp);
17061158dfb7SGarrett Wollman 	return error;
17071158dfb7SGarrett Wollman }
17081158dfb7SGarrett Wollman 
17091158dfb7SGarrett Wollman /*
17101158dfb7SGarrett Wollman  * Add a multicast listenership to the interface in question.
17111158dfb7SGarrett Wollman  * The link layer provides a routine which converts
17121158dfb7SGarrett Wollman  */
17131158dfb7SGarrett Wollman int
171472fd1b6aSDag-Erling Smørgrav if_addmulti(struct ifnet *ifp, struct sockaddr *sa, struct ifmultiaddr **retifma)
17151158dfb7SGarrett Wollman {
17161158dfb7SGarrett Wollman 	struct sockaddr *llsa, *dupsa;
17171158dfb7SGarrett Wollman 	int error, s;
17181158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
17191158dfb7SGarrett Wollman 
172057af7922SJulian Elischer 	/*
172157af7922SJulian Elischer 	 * If the matching multicast address already exists
172257af7922SJulian Elischer 	 * then don't add a new one, just add a reference
172357af7922SJulian Elischer 	 */
17246817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
172557af7922SJulian Elischer 		if (equal(sa, ifma->ifma_addr)) {
17261158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
172757af7922SJulian Elischer 			if (retifma)
172857af7922SJulian Elischer 				*retifma = ifma;
17291158dfb7SGarrett Wollman 			return 0;
17301158dfb7SGarrett Wollman 		}
173157af7922SJulian Elischer 	}
17321158dfb7SGarrett Wollman 
17331158dfb7SGarrett Wollman 	/*
17341158dfb7SGarrett Wollman 	 * Give the link layer a chance to accept/reject it, and also
17351158dfb7SGarrett Wollman 	 * find out which AF_LINK address this maps to, if it isn't one
17361158dfb7SGarrett Wollman 	 * already.
17371158dfb7SGarrett Wollman 	 */
17381158dfb7SGarrett Wollman 	if (ifp->if_resolvemulti) {
17391158dfb7SGarrett Wollman 		error = ifp->if_resolvemulti(ifp, &llsa, sa);
17401158dfb7SGarrett Wollman 		if (error) return error;
17411158dfb7SGarrett Wollman 	} else {
17421158dfb7SGarrett Wollman 		llsa = 0;
17431158dfb7SGarrett Wollman 	}
17441158dfb7SGarrett Wollman 
1745a163d034SWarner Losh 	MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
1746a163d034SWarner Losh 	MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
17471158dfb7SGarrett Wollman 	bcopy(sa, dupsa, sa->sa_len);
17481158dfb7SGarrett Wollman 
17491158dfb7SGarrett Wollman 	ifma->ifma_addr = dupsa;
17501158dfb7SGarrett Wollman 	ifma->ifma_lladdr = llsa;
17511158dfb7SGarrett Wollman 	ifma->ifma_ifp = ifp;
17521158dfb7SGarrett Wollman 	ifma->ifma_refcount = 1;
1753d4d22970SGleb Smirnoff 	ifma->ifma_protospec = NULL;
1754477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
1755373f88edSGarrett Wollman 
17561158dfb7SGarrett Wollman 	/*
17571158dfb7SGarrett Wollman 	 * Some network interfaces can scan the address list at
17581158dfb7SGarrett Wollman 	 * interrupt time; lock them out.
17591158dfb7SGarrett Wollman 	 */
17601158dfb7SGarrett Wollman 	s = splimp();
17616817526dSPoul-Henning Kamp 	TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
17621158dfb7SGarrett Wollman 	splx(s);
176313990766SJonathan Mini 	if (retifma != NULL)
1764373f88edSGarrett Wollman 		*retifma = ifma;
17651158dfb7SGarrett Wollman 
17661158dfb7SGarrett Wollman 	if (llsa != 0) {
17676817526dSPoul-Henning Kamp 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
17681158dfb7SGarrett Wollman 			if (equal(ifma->ifma_addr, llsa))
17691158dfb7SGarrett Wollman 				break;
17701158dfb7SGarrett Wollman 		}
17711158dfb7SGarrett Wollman 		if (ifma) {
17721158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
17731158dfb7SGarrett Wollman 		} else {
17741158dfb7SGarrett Wollman 			MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
1775a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1776477180fbSGarrett Wollman 			MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
1777a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1778477180fbSGarrett Wollman 			bcopy(llsa, dupsa, llsa->sa_len);
1779477180fbSGarrett Wollman 			ifma->ifma_addr = dupsa;
178089eaef50SHajimu UMEMOTO 			ifma->ifma_lladdr = NULL;
17811158dfb7SGarrett Wollman 			ifma->ifma_ifp = ifp;
17821158dfb7SGarrett Wollman 			ifma->ifma_refcount = 1;
1783d4d22970SGleb Smirnoff 			ifma->ifma_protospec = NULL;
17841158dfb7SGarrett Wollman 			s = splimp();
17856817526dSPoul-Henning Kamp 			TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
17861158dfb7SGarrett Wollman 			splx(s);
17871158dfb7SGarrett Wollman 		}
178857af7922SJulian Elischer 	}
17891158dfb7SGarrett Wollman 	/*
17901158dfb7SGarrett Wollman 	 * We are certain we have added something, so call down to the
17911158dfb7SGarrett Wollman 	 * interface to let them know about it.
17921158dfb7SGarrett Wollman 	 */
17931158dfb7SGarrett Wollman 	s = splimp();
179431302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
17951158dfb7SGarrett Wollman 	ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
179631302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
17971158dfb7SGarrett Wollman 	splx(s);
17981158dfb7SGarrett Wollman 
17991158dfb7SGarrett Wollman 	return 0;
18001158dfb7SGarrett Wollman }
18011158dfb7SGarrett Wollman 
18021158dfb7SGarrett Wollman /*
18031158dfb7SGarrett Wollman  * Remove a reference to a multicast address on this interface.  Yell
18041158dfb7SGarrett Wollman  * if the request does not match an existing membership.
18051158dfb7SGarrett Wollman  */
18061158dfb7SGarrett Wollman int
180772fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
18081158dfb7SGarrett Wollman {
18091158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
18101158dfb7SGarrett Wollman 	int s;
18111158dfb7SGarrett Wollman 
18126817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
18131158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
18141158dfb7SGarrett Wollman 			break;
18151158dfb7SGarrett Wollman 	if (ifma == 0)
18161158dfb7SGarrett Wollman 		return ENOENT;
18171158dfb7SGarrett Wollman 
18181158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
18191158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
18201158dfb7SGarrett Wollman 		return 0;
18211158dfb7SGarrett Wollman 	}
18221158dfb7SGarrett Wollman 
1823477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_DELMADDR, ifma);
18241158dfb7SGarrett Wollman 	sa = ifma->ifma_lladdr;
18251158dfb7SGarrett Wollman 	s = splimp();
18266817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
1827ccb7cc8dSYaroslav Tykhiy 	/*
1828ccb7cc8dSYaroslav Tykhiy 	 * Make sure the interface driver is notified
1829ccb7cc8dSYaroslav Tykhiy 	 * in the case of a link layer mcast group being left.
1830ccb7cc8dSYaroslav Tykhiy 	 */
183131302ebfSRobert Watson 	if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) {
183231302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1833ccb7cc8dSYaroslav Tykhiy 		ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
183431302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
183531302ebfSRobert Watson 	}
18361158dfb7SGarrett Wollman 	splx(s);
18371158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
18381158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
18391158dfb7SGarrett Wollman 	if (sa == 0)
18401158dfb7SGarrett Wollman 		return 0;
18411158dfb7SGarrett Wollman 
18421158dfb7SGarrett Wollman 	/*
18431158dfb7SGarrett Wollman 	 * Now look for the link-layer address which corresponds to
18441158dfb7SGarrett Wollman 	 * this network address.  It had been squirreled away in
18451158dfb7SGarrett Wollman 	 * ifma->ifma_lladdr for this purpose (so we don't have
18461158dfb7SGarrett Wollman 	 * to call ifp->if_resolvemulti() again), and we saved that
18471158dfb7SGarrett Wollman 	 * value in sa above.  If some nasty deleted the
18481158dfb7SGarrett Wollman 	 * link-layer address out from underneath us, we can deal because
18491158dfb7SGarrett Wollman 	 * the address we stored was is not the same as the one which was
18501158dfb7SGarrett Wollman 	 * in the record for the link-layer address.  (So we don't complain
18511158dfb7SGarrett Wollman 	 * in that case.)
18521158dfb7SGarrett Wollman 	 */
18536817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
18541158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
18551158dfb7SGarrett Wollman 			break;
18561158dfb7SGarrett Wollman 	if (ifma == 0)
18571158dfb7SGarrett Wollman 		return 0;
18581158dfb7SGarrett Wollman 
18591158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
18601158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
18611158dfb7SGarrett Wollman 		return 0;
18621158dfb7SGarrett Wollman 	}
18631158dfb7SGarrett Wollman 
18641158dfb7SGarrett Wollman 	s = splimp();
18656817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
186631302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
1867c7323482SBill Paul 	ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
186831302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
18691158dfb7SGarrett Wollman 	splx(s);
18701158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
18711158dfb7SGarrett Wollman 	free(sa, M_IFMADDR);
18721158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
18731158dfb7SGarrett Wollman 
18741158dfb7SGarrett Wollman 	return 0;
18751158dfb7SGarrett Wollman }
18761158dfb7SGarrett Wollman 
187766ce51ceSArchie Cobbs /*
187866ce51ceSArchie Cobbs  * Set the link layer address on an interface.
187966ce51ceSArchie Cobbs  *
188066ce51ceSArchie Cobbs  * At this time we only support certain types of interfaces,
188166ce51ceSArchie Cobbs  * and we don't allow the length of the address to change.
188266ce51ceSArchie Cobbs  */
188366ce51ceSArchie Cobbs int
188466ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
188566ce51ceSArchie Cobbs {
188666ce51ceSArchie Cobbs 	struct sockaddr_dl *sdl;
188766ce51ceSArchie Cobbs 	struct ifaddr *ifa;
1888d637e989SPeter Wemm 	struct ifreq ifr;
188966ce51ceSArchie Cobbs 
1890f9132cebSJonathan Lemon 	ifa = ifaddr_byindex(ifp->if_index);
189166ce51ceSArchie Cobbs 	if (ifa == NULL)
189266ce51ceSArchie Cobbs 		return (EINVAL);
189366ce51ceSArchie Cobbs 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
189466ce51ceSArchie Cobbs 	if (sdl == NULL)
189566ce51ceSArchie Cobbs 		return (EINVAL);
189666ce51ceSArchie Cobbs 	if (len != sdl->sdl_alen)	/* don't allow length to change */
189766ce51ceSArchie Cobbs 		return (EINVAL);
189866ce51ceSArchie Cobbs 	switch (ifp->if_type) {
189966ce51ceSArchie Cobbs 	case IFT_ETHER:			/* these types use struct arpcom */
190066ce51ceSArchie Cobbs 	case IFT_FDDI:
190166ce51ceSArchie Cobbs 	case IFT_XETHER:
190266ce51ceSArchie Cobbs 	case IFT_ISO88025:
1903b7bffa71SYaroslav Tykhiy 	case IFT_L2VLAN:
19043fefbff0SLuigi Rizzo 		bcopy(lladdr, IFP2AC(ifp)->ac_enaddr, len);
19059046571fSLuigi Rizzo 		/*
19069046571fSLuigi Rizzo 		 * XXX We also need to store the lladdr in LLADDR(sdl),
19079046571fSLuigi Rizzo 		 * which is done below. This is a pain because we must
19089046571fSLuigi Rizzo 		 * remember to keep the info in sync.
19099046571fSLuigi Rizzo 		 */
19106cdcc159SMax Khon 		/* FALLTHROUGH */
19116cdcc159SMax Khon 	case IFT_ARCNET:
191266ce51ceSArchie Cobbs 		bcopy(lladdr, LLADDR(sdl), len);
191366ce51ceSArchie Cobbs 		break;
191466ce51ceSArchie Cobbs 	default:
191566ce51ceSArchie Cobbs 		return (ENODEV);
191666ce51ceSArchie Cobbs 	}
191766ce51ceSArchie Cobbs 	/*
191866ce51ceSArchie Cobbs 	 * If the interface is already up, we need
191966ce51ceSArchie Cobbs 	 * to re-init it in order to reprogram its
192066ce51ceSArchie Cobbs 	 * address filter.
192166ce51ceSArchie Cobbs 	 */
192266ce51ceSArchie Cobbs 	if ((ifp->if_flags & IFF_UP) != 0) {
192331302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
192466ce51ceSArchie Cobbs 		ifp->if_flags &= ~IFF_UP;
192562f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
192662f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1927ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
192866ce51ceSArchie Cobbs 		ifp->if_flags |= IFF_UP;
192962f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
193062f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1931ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
193231302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1933b2c08f43SLuigi Rizzo #ifdef INET
1934b2c08f43SLuigi Rizzo 		/*
1935b2c08f43SLuigi Rizzo 		 * Also send gratuitous ARPs to notify other nodes about
1936b2c08f43SLuigi Rizzo 		 * the address change.
1937b2c08f43SLuigi Rizzo 		 */
1938b2c08f43SLuigi Rizzo 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1939b2c08f43SLuigi Rizzo 			if (ifa->ifa_addr != NULL &&
1940b2c08f43SLuigi Rizzo 			    ifa->ifa_addr->sa_family == AF_INET)
1941c0933269SPeter Wemm 				arp_ifinit(ifp, ifa);
1942b2c08f43SLuigi Rizzo 		}
1943b2c08f43SLuigi Rizzo #endif
194466ce51ceSArchie Cobbs 	}
194566ce51ceSArchie Cobbs 	return (0);
194666ce51ceSArchie Cobbs }
194766ce51ceSArchie Cobbs 
1948373f88edSGarrett Wollman struct ifmultiaddr *
194972fd1b6aSDag-Erling Smørgrav ifmaof_ifpforaddr(struct sockaddr *sa, struct ifnet *ifp)
1950373f88edSGarrett Wollman {
1951373f88edSGarrett Wollman 	struct ifmultiaddr *ifma;
1952373f88edSGarrett Wollman 
19536817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
1954373f88edSGarrett Wollman 		if (equal(ifma->ifma_addr, sa))
1955373f88edSGarrett Wollman 			break;
1956373f88edSGarrett Wollman 
1957373f88edSGarrett Wollman 	return ifma;
1958373f88edSGarrett Wollman }
1959373f88edSGarrett Wollman 
19609bf40edeSBrooks Davis /*
19619bf40edeSBrooks Davis  * The name argument must be a pointer to storage which will last as
19629bf40edeSBrooks Davis  * long as the interface does.  For physical devices, the result of
19639bf40edeSBrooks Davis  * device_get_name(dev) is a good choice and for pseudo-devices a
19649bf40edeSBrooks Davis  * static string works well.
19659bf40edeSBrooks Davis  */
19669bf40edeSBrooks Davis void
19679bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit)
19689bf40edeSBrooks Davis {
19699bf40edeSBrooks Davis 	ifp->if_dname = name;
19709bf40edeSBrooks Davis 	ifp->if_dunit = unit;
19719bf40edeSBrooks Davis 	if (unit != IF_DUNIT_NONE)
19729bf40edeSBrooks Davis 		snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit);
19739bf40edeSBrooks Davis 	else
19749bf40edeSBrooks Davis 		strlcpy(ifp->if_xname, name, IFNAMSIZ);
19759bf40edeSBrooks Davis }
19769bf40edeSBrooks Davis 
1977fa882e87SBrooks Davis int
1978fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...)
1979fa882e87SBrooks Davis {
1980fa882e87SBrooks Davis 	va_list ap;
1981fa882e87SBrooks Davis 	int retval;
1982fa882e87SBrooks Davis 
19839bf40edeSBrooks Davis 	retval = printf("%s: ", ifp->if_xname);
1984fa882e87SBrooks Davis 	va_start(ap, fmt);
1985fa882e87SBrooks Davis 	retval += vprintf(fmt, ap);
1986fa882e87SBrooks Davis 	va_end(ap);
1987fa882e87SBrooks Davis 	return (retval);
1988fa882e87SBrooks Davis }
1989fa882e87SBrooks Davis 
1990af5e59bfSRobert Watson /*
1991af5e59bfSRobert Watson  * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot
1992af5e59bfSRobert Watson  * be called without Giant.  However, we often can't acquire the Giant lock
1993af5e59bfSRobert Watson  * at those points; instead, we run it via a task queue that holds Giant via
1994af5e59bfSRobert Watson  * if_start_deferred.
1995af5e59bfSRobert Watson  *
1996af5e59bfSRobert Watson  * XXXRW: We need to make sure that the ifnet isn't fully detached until any
1997af5e59bfSRobert Watson  * outstanding if_start_deferred() tasks that will run after the free.  This
1998af5e59bfSRobert Watson  * probably means waiting in if_detach().
1999af5e59bfSRobert Watson  */
2000af5e59bfSRobert Watson void
2001af5e59bfSRobert Watson if_start(struct ifnet *ifp)
2002af5e59bfSRobert Watson {
2003af5e59bfSRobert Watson 
2004af5e59bfSRobert Watson 	NET_ASSERT_GIANT();
2005af5e59bfSRobert Watson 
2006af5e59bfSRobert Watson 	if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) {
2007af5e59bfSRobert Watson 		if (mtx_owned(&Giant))
2008af5e59bfSRobert Watson 			(*(ifp)->if_start)(ifp);
2009af5e59bfSRobert Watson 		else
2010af5e59bfSRobert Watson 			taskqueue_enqueue(taskqueue_swi_giant,
2011af5e59bfSRobert Watson 			    &ifp->if_starttask);
2012af5e59bfSRobert Watson 	} else
2013af5e59bfSRobert Watson 		(*(ifp)->if_start)(ifp);
2014af5e59bfSRobert Watson }
2015af5e59bfSRobert Watson 
2016af5e59bfSRobert Watson static void
2017af5e59bfSRobert Watson if_start_deferred(void *context, int pending)
2018af5e59bfSRobert Watson {
2019af5e59bfSRobert Watson 	struct ifnet *ifp;
2020af5e59bfSRobert Watson 
2021af5e59bfSRobert Watson 	/*
2022af5e59bfSRobert Watson 	 * This code must be entered with Giant, and should never run if
2023af5e59bfSRobert Watson 	 * we're not running with debug.mpsafenet.
2024af5e59bfSRobert Watson 	 */
2025af5e59bfSRobert Watson 	KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet"));
2026af5e59bfSRobert Watson 	GIANT_REQUIRED;
2027af5e59bfSRobert Watson 
2028af5e59bfSRobert Watson 	ifp = (struct ifnet *)context;
2029af5e59bfSRobert Watson 	(ifp->if_start)(ifp);
2030af5e59bfSRobert Watson }
2031af5e59bfSRobert Watson 
20320b762445SRobert Watson int
20330b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
20340b762445SRobert Watson {
20350b762445SRobert Watson 	int active = 0;
20360b762445SRobert Watson 
20370b762445SRobert Watson 	IF_LOCK(ifq);
20380b762445SRobert Watson 	if (_IF_QFULL(ifq)) {
20390b762445SRobert Watson 		_IF_DROP(ifq);
20400b762445SRobert Watson 		IF_UNLOCK(ifq);
20410b762445SRobert Watson 		m_freem(m);
20420b762445SRobert Watson 		return (0);
20430b762445SRobert Watson 	}
20440b762445SRobert Watson 	if (ifp != NULL) {
20450b762445SRobert Watson 		ifp->if_obytes += m->m_pkthdr.len + adjust;
20460b762445SRobert Watson 		if (m->m_flags & (M_BCAST|M_MCAST))
20470b762445SRobert Watson 			ifp->if_omcasts++;
20480b762445SRobert Watson 		active = ifp->if_flags & IFF_OACTIVE;
20490b762445SRobert Watson 	}
20500b762445SRobert Watson 	_IF_ENQUEUE(ifq, m);
20510b762445SRobert Watson 	IF_UNLOCK(ifq);
20520b762445SRobert Watson 	if (ifp != NULL && !active)
20530b762445SRobert Watson 		if_start(ifp);
20540b762445SRobert Watson 	return (1);
20550b762445SRobert Watson }
2056