xref: /freebsd/sys/net/if.c (revision 69fb23b73dc7148de0f5b9857f80abeee6ac0cb0)
1df8bae1dSRodney W. Grimes /*
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"
375591b823SEivind Eklund 
38df8bae1dSRodney W. Grimes #include <sys/param.h>
394dcf2bbbSBrooks Davis #include <sys/types.h>
40f13ad206SJonathan Lemon #include <sys/conf.h>
41e70cd263SRobert Watson #include <sys/mac.h>
424d1d4912SBruce Evans #include <sys/malloc.h>
434dcf2bbbSBrooks Davis #include <sys/sbuf.h>
44d2b4566aSJonathan Lemon #include <sys/bus.h>
45df8bae1dSRodney W. Grimes #include <sys/mbuf.h>
46df8bae1dSRodney W. Grimes #include <sys/systm.h>
47df8bae1dSRodney W. Grimes #include <sys/proc.h>
48df8bae1dSRodney W. Grimes #include <sys/socket.h>
49df8bae1dSRodney W. Grimes #include <sys/socketvar.h>
50df8bae1dSRodney W. Grimes #include <sys/protosw.h>
51df8bae1dSRodney W. Grimes #include <sys/kernel.h>
5251a53488SBruce Evans #include <sys/sockio.h>
53963e4c2aSGarrett Wollman #include <sys/syslog.h>
54602d513cSGarrett Wollman #include <sys/sysctl.h>
55af5e59bfSRobert Watson #include <sys/taskqueue.h>
5631b1bfe1SHajimu UMEMOTO #include <sys/domain.h>
5791421ba2SRobert Watson #include <sys/jail.h>
58fa882e87SBrooks Davis #include <machine/stdarg.h>
59df8bae1dSRodney W. Grimes 
60df8bae1dSRodney W. Grimes #include <net/if.h>
61b106252cSBill Paul #include <net/if_arp.h>
62f889d2efSBrooks Davis #include <net/if_clone.h>
63df8bae1dSRodney W. Grimes #include <net/if_dl.h>
6466ce51ceSArchie Cobbs #include <net/if_types.h>
6530aad87dSBrooks Davis #include <net/if_var.h>
669448326fSPoul-Henning Kamp #include <net/radix.h>
675500d3beSWarner Losh #include <net/route.h>
68df8bae1dSRodney W. Grimes 
690d0f9d1eSYoshinobu Inoue #if defined(INET) || defined(INET6)
7082cd038dSYoshinobu Inoue /*XXX*/
7182cd038dSYoshinobu Inoue #include <netinet/in.h>
720d0f9d1eSYoshinobu Inoue #include <netinet/in_var.h>
733411310dSYoshinobu Inoue #ifdef INET6
74978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_var.h>
75978ee2edSJun-ichiro itojun Hagino #include <netinet6/in6_ifattach.h>
763411310dSYoshinobu Inoue #endif
7782cd038dSYoshinobu Inoue #endif
78c0933269SPeter Wemm #ifdef INET
79c0933269SPeter Wemm #include <netinet/if_ether.h>
80c0933269SPeter Wemm #endif
8182cd038dSYoshinobu Inoue 
824cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
834cb655c0SMax Laier 
8431b1bfe1SHajimu UMEMOTO static void	if_attachdomain(void *);
8531b1bfe1SHajimu UMEMOTO static void	if_attachdomain1(struct ifnet *);
860b59d917SJonathan Lemon static int	ifconf(u_long, caddr_t);
87f9132cebSJonathan Lemon static void	if_grow(void);
88f9132cebSJonathan Lemon static void	if_init(void *);
89f9132cebSJonathan Lemon static void	if_check(void *);
90ffb5a104SJonathan Lemon static int	if_findindex(struct ifnet *);
9102b199f1SMax Laier static void	if_qflush(struct ifaltq *);
928614fb12SMax Laier static void	if_route(struct ifnet *, int flag, int fam);
930b59d917SJonathan Lemon static void	if_slowtimo(void *);
948614fb12SMax Laier static void	if_unroute(struct ifnet *, int flag, int fam);
958071913dSRuslan Ermilov static void	link_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
960b59d917SJonathan Lemon static int	if_rtdel(struct radix_node *, void *);
97f13ad206SJonathan Lemon static int	ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *);
98af5e59bfSRobert Watson static void	if_start_deferred(void *context, int pending);
9982cd038dSYoshinobu Inoue #ifdef INET6
10082cd038dSYoshinobu Inoue /*
10182cd038dSYoshinobu Inoue  * XXX: declare here to avoid to include many inet6 related files..
10282cd038dSYoshinobu Inoue  * should be more generalized?
10382cd038dSYoshinobu Inoue  */
104929ddbbbSAlfred Perlstein extern void	nd6_setmtu(struct ifnet *);
10582cd038dSYoshinobu Inoue #endif
10682cd038dSYoshinobu Inoue 
1070b59d917SJonathan Lemon int	if_index = 0;
108f9132cebSJonathan Lemon struct	ifindex_entry *ifindex_table = NULL;
1090b59d917SJonathan Lemon int	ifqmaxlen = IFQ_MAXLEN;
1100b59d917SJonathan Lemon struct	ifnethead ifnet;	/* depend on static init XXX */
111b30a244cSJeffrey Hsu struct	mtx ifnet_lock;
1120b59d917SJonathan Lemon 
113f9132cebSJonathan Lemon static int	if_indexlim = 8;
114ad3b9257SJohn-Mark Gurney static struct	knlist ifklist;
115f9132cebSJonathan Lemon 
1169a2a57a1SJonathan Lemon static void	filt_netdetach(struct knote *kn);
1179a2a57a1SJonathan Lemon static int	filt_netdev(struct knote *kn, long hint);
1189a2a57a1SJonathan Lemon 
1199a2a57a1SJonathan Lemon static struct filterops netdev_filtops =
1209a2a57a1SJonathan Lemon     { 1, NULL, filt_netdetach, filt_netdev };
1219a2a57a1SJonathan Lemon 
1220b59d917SJonathan Lemon /*
1230b59d917SJonathan Lemon  * System initialization
1240b59d917SJonathan Lemon  */
125f9132cebSJonathan Lemon SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL)
126f9132cebSJonathan Lemon SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL)
1270b59d917SJonathan Lemon 
1280b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
1290b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
13030aad87dSBrooks Davis 
131f13ad206SJonathan Lemon static d_open_t		netopen;
132f13ad206SJonathan Lemon static d_close_t	netclose;
133f13ad206SJonathan Lemon static d_ioctl_t	netioctl;
1349a2a57a1SJonathan Lemon static d_kqfilter_t	netkqfilter;
135f13ad206SJonathan Lemon 
136f13ad206SJonathan Lemon static struct cdevsw net_cdevsw = {
137dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
138dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1397ac40f5fSPoul-Henning Kamp 	.d_open =	netopen,
1407ac40f5fSPoul-Henning Kamp 	.d_close =	netclose,
1417ac40f5fSPoul-Henning Kamp 	.d_ioctl =	netioctl,
1427ac40f5fSPoul-Henning Kamp 	.d_name =	"net",
1437ac40f5fSPoul-Henning Kamp 	.d_kqfilter =	netkqfilter,
144f13ad206SJonathan Lemon };
145f13ad206SJonathan Lemon 
146f13ad206SJonathan Lemon static int
14789c9c53dSPoul-Henning Kamp netopen(struct cdev *dev, int flag, int mode, struct thread *td)
148f13ad206SJonathan Lemon {
149f13ad206SJonathan Lemon 	return (0);
150f13ad206SJonathan Lemon }
151f13ad206SJonathan Lemon 
152f13ad206SJonathan Lemon static int
15389c9c53dSPoul-Henning Kamp netclose(struct cdev *dev, int flags, int fmt, struct thread *td)
154f13ad206SJonathan Lemon {
155f13ad206SJonathan Lemon 	return (0);
156f13ad206SJonathan Lemon }
157f13ad206SJonathan Lemon 
158f13ad206SJonathan Lemon static int
15989c9c53dSPoul-Henning Kamp netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
160f13ad206SJonathan Lemon {
161f13ad206SJonathan Lemon 	struct ifnet *ifp;
162f13ad206SJonathan Lemon 	int error, idx;
163f13ad206SJonathan Lemon 
164f13ad206SJonathan Lemon 	/* only support interface specific ioctls */
165f13ad206SJonathan Lemon 	if (IOCGROUP(cmd) != 'i')
166f13ad206SJonathan Lemon 		return (EOPNOTSUPP);
167f13ad206SJonathan Lemon 	idx = minor(dev);
168f13ad206SJonathan Lemon 	if (idx == 0) {
169f13ad206SJonathan Lemon 		/*
170f13ad206SJonathan Lemon 		 * special network device, not interface.
171f13ad206SJonathan Lemon 		 */
172f13ad206SJonathan Lemon 		if (cmd == SIOCGIFCONF)
173f13ad206SJonathan Lemon 			return (ifconf(cmd, data));	/* XXX remove cmd */
174f13ad206SJonathan Lemon 		return (EOPNOTSUPP);
175f13ad206SJonathan Lemon 	}
176f13ad206SJonathan Lemon 
177f13ad206SJonathan Lemon 	ifp = ifnet_byindex(idx);
178f13ad206SJonathan Lemon 	if (ifp == NULL)
179f13ad206SJonathan Lemon 		return (ENXIO);
180f13ad206SJonathan Lemon 
181f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
182f13ad206SJonathan Lemon 	if (error == ENOIOCTL)
183f13ad206SJonathan Lemon 		error = EOPNOTSUPP;
184f13ad206SJonathan Lemon 	return (error);
185f13ad206SJonathan Lemon }
186f13ad206SJonathan Lemon 
1879a2a57a1SJonathan Lemon static int
18889c9c53dSPoul-Henning Kamp netkqfilter(struct cdev *dev, struct knote *kn)
1899a2a57a1SJonathan Lemon {
190ad3b9257SJohn-Mark Gurney 	struct knlist *klist;
1919a2a57a1SJonathan Lemon 	struct ifnet *ifp;
1929a2a57a1SJonathan Lemon 	int idx;
1939a2a57a1SJonathan Lemon 
194ad3b9257SJohn-Mark Gurney 	switch (kn->kn_filter) {
195ad3b9257SJohn-Mark Gurney 	case EVFILT_NETDEV:
196ad3b9257SJohn-Mark Gurney 		kn->kn_fop = &netdev_filtops;
197ad3b9257SJohn-Mark Gurney 		break;
198ad3b9257SJohn-Mark Gurney 	default:
199ad3b9257SJohn-Mark Gurney 		return (1);
200ad3b9257SJohn-Mark Gurney 	}
201ad3b9257SJohn-Mark Gurney 
2029a2a57a1SJonathan Lemon 	idx = minor(dev);
2039a2a57a1SJonathan Lemon 	if (idx == 0) {
2049a2a57a1SJonathan Lemon 		klist = &ifklist;
2059a2a57a1SJonathan Lemon 	} else {
2069a2a57a1SJonathan Lemon 		ifp = ifnet_byindex(idx);
2079a2a57a1SJonathan Lemon 		if (ifp == NULL)
2089a2a57a1SJonathan Lemon 			return (1);
2099a2a57a1SJonathan Lemon 		klist = &ifp->if_klist;
2109a2a57a1SJonathan Lemon 	}
2119a2a57a1SJonathan Lemon 
2129a2a57a1SJonathan Lemon 	kn->kn_hook = (caddr_t)klist;
2139a2a57a1SJonathan Lemon 
214ad3b9257SJohn-Mark Gurney 	knlist_add(klist, kn, 0);
2159a2a57a1SJonathan Lemon 
2169a2a57a1SJonathan Lemon 	return (0);
2179a2a57a1SJonathan Lemon }
2189a2a57a1SJonathan Lemon 
2199a2a57a1SJonathan Lemon static void
2209a2a57a1SJonathan Lemon filt_netdetach(struct knote *kn)
2219a2a57a1SJonathan Lemon {
222ad3b9257SJohn-Mark Gurney 	struct knlist *klist = (struct knlist *)kn->kn_hook;
2239a2a57a1SJonathan Lemon 
224ad3b9257SJohn-Mark Gurney 	knlist_remove(klist, kn, 0);
2259a2a57a1SJonathan Lemon }
2269a2a57a1SJonathan Lemon 
2279a2a57a1SJonathan Lemon static int
2289a2a57a1SJonathan Lemon filt_netdev(struct knote *kn, long hint)
2299a2a57a1SJonathan Lemon {
230ad3b9257SJohn-Mark Gurney 	struct knlist *klist = (struct knlist *)kn->kn_hook;
2319a2a57a1SJonathan Lemon 
2329a2a57a1SJonathan Lemon 	/*
2339a2a57a1SJonathan Lemon 	 * Currently NOTE_EXIT is abused to indicate device detach.
2349a2a57a1SJonathan Lemon 	 */
2359a2a57a1SJonathan Lemon 	if (hint == NOTE_EXIT) {
2369a2a57a1SJonathan Lemon 		kn->kn_data = NOTE_LINKINV;
2379a2a57a1SJonathan Lemon 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
238ad3b9257SJohn-Mark Gurney 		knlist_remove_inevent(klist, kn);
2399a2a57a1SJonathan Lemon 		return (1);
2409a2a57a1SJonathan Lemon 	}
241ad3b9257SJohn-Mark Gurney 	if (hint != 0)
2429a2a57a1SJonathan Lemon 		kn->kn_data = hint;			/* current status */
2439a2a57a1SJonathan Lemon 	if (kn->kn_sfflags & hint)
2449a2a57a1SJonathan Lemon 		kn->kn_fflags |= hint;
2459a2a57a1SJonathan Lemon 	return (kn->kn_fflags != 0);
2469a2a57a1SJonathan Lemon }
2479a2a57a1SJonathan Lemon 
248df8bae1dSRodney W. Grimes /*
249df8bae1dSRodney W. Grimes  * Network interface utility routines.
250df8bae1dSRodney W. Grimes  *
251df8bae1dSRodney W. Grimes  * Routines with ifa_ifwith* names take sockaddr *'s as
252df8bae1dSRodney W. Grimes  * parameters.
253df8bae1dSRodney W. Grimes  */
2542b14f991SJulian Elischer /* ARGSUSED*/
255f9132cebSJonathan Lemon static void
25672fd1b6aSDag-Erling Smørgrav if_init(void *dummy __unused)
257f9132cebSJonathan Lemon {
258f9132cebSJonathan Lemon 
259b30a244cSJeffrey Hsu 	IFNET_LOCK_INIT();
260f9132cebSJonathan Lemon 	TAILQ_INIT(&ifnet);
261ad3b9257SJohn-Mark Gurney 	knlist_init(&ifklist, NULL);
262f9132cebSJonathan Lemon 	if_grow();				/* create initial table */
263f13ad206SJonathan Lemon 	ifdev_byindex(0) = make_dev(&net_cdevsw, 0,
264f13ad206SJonathan Lemon 	    UID_ROOT, GID_WHEEL, 0600, "network");
265f889d2efSBrooks Davis 	if_clone_init();
266f9132cebSJonathan Lemon }
267f9132cebSJonathan Lemon 
268f9132cebSJonathan Lemon static void
269f9132cebSJonathan Lemon if_grow(void)
270f9132cebSJonathan Lemon {
271f9132cebSJonathan Lemon 	u_int n;
272f9132cebSJonathan Lemon 	struct ifindex_entry *e;
273f9132cebSJonathan Lemon 
274f9132cebSJonathan Lemon 	if_indexlim <<= 1;
275f9132cebSJonathan Lemon 	n = if_indexlim * sizeof(*e);
276a163d034SWarner Losh 	e = malloc(n, M_IFADDR, M_WAITOK | M_ZERO);
277f9132cebSJonathan Lemon 	if (ifindex_table != NULL) {
278f9132cebSJonathan Lemon 		memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2);
279f9132cebSJonathan Lemon 		free((caddr_t)ifindex_table, M_IFADDR);
280f9132cebSJonathan Lemon 	}
281f9132cebSJonathan Lemon 	ifindex_table = e;
282f9132cebSJonathan Lemon }
283f9132cebSJonathan Lemon 
284f9132cebSJonathan Lemon /* ARGSUSED*/
285f9132cebSJonathan Lemon static void
28672fd1b6aSDag-Erling Smørgrav if_check(void *dummy __unused)
287df8bae1dSRodney W. Grimes {
2888ba5bdaeSPeter Wemm 	struct ifnet *ifp;
2898ba5bdaeSPeter Wemm 	int s;
290df8bae1dSRodney W. Grimes 
2918ba5bdaeSPeter Wemm 	s = splimp();
292b30a244cSJeffrey Hsu 	IFNET_RLOCK();	/* could sleep on rare error; mostly okay XXX */
293fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
294e0ea20bcSPoul-Henning Kamp 		if (ifp->if_snd.ifq_maxlen == 0) {
29513fb40dfSBrooks Davis 			if_printf(ifp, "XXX: driver didn't set ifq_maxlen\n");
296df8bae1dSRodney W. Grimes 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
297e0ea20bcSPoul-Henning Kamp 		}
2985e980e22SJohn Baldwin 		if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) {
29913fb40dfSBrooks Davis 			if_printf(ifp,
30013fb40dfSBrooks Davis 			    "XXX: driver didn't initialize queue mtx\n");
3016008862bSJohn Baldwin 			mtx_init(&ifp->if_snd.ifq_mtx, "unknown",
3026008862bSJohn Baldwin 			    MTX_NETWORK_LOCK, MTX_DEF);
303df5e1987SJonathan Lemon 		}
304df5e1987SJonathan Lemon 	}
305b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
3068ba5bdaeSPeter Wemm 	splx(s);
307df8bae1dSRodney W. Grimes 	if_slowtimo(0);
308df8bae1dSRodney W. Grimes }
309df8bae1dSRodney W. Grimes 
310ffb5a104SJonathan Lemon static int
311ffb5a104SJonathan Lemon if_findindex(struct ifnet *ifp)
312ffb5a104SJonathan Lemon {
313ffb5a104SJonathan Lemon 	int i, unit;
314ffb5a104SJonathan Lemon 	char eaddr[18], devname[32];
315d2b4566aSJonathan Lemon 	const char *name, *p;
316ffb5a104SJonathan Lemon 
317ffb5a104SJonathan Lemon 	switch (ifp->if_type) {
318ffb5a104SJonathan Lemon 	case IFT_ETHER:			/* these types use struct arpcom */
319ffb5a104SJonathan Lemon 	case IFT_FDDI:
320ffb5a104SJonathan Lemon 	case IFT_XETHER:
321ffb5a104SJonathan Lemon 	case IFT_ISO88025:
322ffb5a104SJonathan Lemon 	case IFT_L2VLAN:
3238bbfdc98SRobert Watson 		snprintf(eaddr, 18, "%6D", IFP2AC(ifp)->ac_enaddr, ":");
324ffb5a104SJonathan Lemon 		break;
325ffb5a104SJonathan Lemon 	default:
326ffb5a104SJonathan Lemon 		eaddr[0] = '\0';
327ffb5a104SJonathan Lemon 		break;
328ffb5a104SJonathan Lemon 	}
3299bf40edeSBrooks Davis 	strlcpy(devname, ifp->if_xname, sizeof(devname));
330ffb5a104SJonathan Lemon 	name = net_cdevsw.d_name;
331ffb5a104SJonathan Lemon 	i = 0;
332ffb5a104SJonathan Lemon 	while ((resource_find_dev(&i, name, &unit, NULL, NULL)) == 0) {
333ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "ether", &p) == 0)
334ffb5a104SJonathan Lemon 			if (strcmp(p, eaddr) == 0)
335ffb5a104SJonathan Lemon 				goto found;
336ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "dev", &p) == 0)
337ffb5a104SJonathan Lemon 			if (strcmp(p, devname) == 0)
338ffb5a104SJonathan Lemon 				goto found;
339ffb5a104SJonathan Lemon 	}
340ffb5a104SJonathan Lemon 	unit = 0;
341ffb5a104SJonathan Lemon found:
342ffb5a104SJonathan Lemon 	if (unit != 0) {
343ffb5a104SJonathan Lemon 		if (ifaddr_byindex(unit) == NULL)
344ffb5a104SJonathan Lemon 			return (unit);
345ffb5a104SJonathan Lemon 		printf("%s%d in use, cannot hardwire it to %s.\n",
346ffb5a104SJonathan Lemon 		    name, unit, devname);
347ffb5a104SJonathan Lemon 	}
348ffb5a104SJonathan Lemon 	for (unit = 1; ; unit++) {
34905153c61SBill Fenner 		if (unit <= if_index && ifaddr_byindex(unit) != NULL)
350ffb5a104SJonathan Lemon 			continue;
351ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "ether", &p) == 0 ||
352ffb5a104SJonathan Lemon 		    resource_string_value(name, unit, "dev", &p) == 0)
353ffb5a104SJonathan Lemon 			continue;
354ffb5a104SJonathan Lemon 		break;
355ffb5a104SJonathan Lemon 	}
356ffb5a104SJonathan Lemon 	return (unit);
357ffb5a104SJonathan Lemon }
358ffb5a104SJonathan Lemon 
359df8bae1dSRodney W. Grimes /*
360df8bae1dSRodney W. Grimes  * Attach an interface to the
361df8bae1dSRodney W. Grimes  * list of "active" interfaces.
362df8bae1dSRodney W. Grimes  */
363df8bae1dSRodney W. Grimes void
36472fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp)
365df8bae1dSRodney W. Grimes {
366df8bae1dSRodney W. Grimes 	unsigned socksize, ifasize;
3671ce9bf88SPoul-Henning Kamp 	int namelen, masklen;
36872fd1b6aSDag-Erling Smørgrav 	struct sockaddr_dl *sdl;
36972fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
370df8bae1dSRodney W. Grimes 
371af5e59bfSRobert Watson 	TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp);
372234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK_INIT(ifp);
373234a35c7SHajimu UMEMOTO 	ifp->if_afdata_initialized = 0;
374b30a244cSJeffrey Hsu 	IFNET_WLOCK();
37529412182SGarrett Wollman 	TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
376b30a244cSJeffrey Hsu 	IFNET_WUNLOCK();
37759562606SGarrett Wollman 	/*
37859562606SGarrett Wollman 	 * XXX -
37959562606SGarrett Wollman 	 * The old code would work if the interface passed a pre-existing
38059562606SGarrett Wollman 	 * chain of ifaddrs to this code.  We don't trust our callers to
38159562606SGarrett Wollman 	 * properly initialize the tailq, however, so we no longer allow
38259562606SGarrett Wollman 	 * this unlikely case.
38359562606SGarrett Wollman 	 */
38459562606SGarrett Wollman 	TAILQ_INIT(&ifp->if_addrhead);
38582cd038dSYoshinobu Inoue 	TAILQ_INIT(&ifp->if_prefixhead);
3866817526dSPoul-Henning Kamp 	TAILQ_INIT(&ifp->if_multiaddrs);
387ad3b9257SJohn-Mark Gurney 	knlist_init(&ifp->if_klist, NULL);
38898b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
38955287f2aSBrooks Davis 	ifp->if_data.ifi_epoch = time_second;
390e70cd263SRobert Watson 
391e70cd263SRobert Watson #ifdef MAC
392e70cd263SRobert Watson 	mac_init_ifnet(ifp);
393e70cd263SRobert Watson 	mac_create_ifnet(ifp);
394e70cd263SRobert Watson #endif
395e70cd263SRobert Watson 
396ffb5a104SJonathan Lemon 	ifp->if_index = if_findindex(ifp);
39705153c61SBill Fenner 	if (ifp->if_index > if_index)
39805153c61SBill Fenner 		if_index = ifp->if_index;
399f9132cebSJonathan Lemon 	if (if_index >= if_indexlim)
400f9132cebSJonathan Lemon 		if_grow();
4019e734b44SBrooks Davis 	ifp->if_data.ifi_datalen = sizeof(struct if_data);
40282cd038dSYoshinobu Inoue 
403ffb5a104SJonathan Lemon 	ifnet_byindex(ifp->if_index) = ifp;
40412b8b80eSRuslan Ermilov 	ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw,
40512b8b80eSRuslan Ermilov 	    unit2minor(ifp->if_index),
4069bf40edeSBrooks Davis 	    UID_ROOT, GID_WHEEL, 0600, "%s/%s",
4079bf40edeSBrooks Davis 	    net_cdevsw.d_name, ifp->if_xname);
408ffb5a104SJonathan Lemon 	make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d",
409ffb5a104SJonathan Lemon 	    net_cdevsw.d_name, ifp->if_index);
410f13ad206SJonathan Lemon 
4119bf40edeSBrooks Davis 	mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF);
412df5e1987SJonathan Lemon 
413df8bae1dSRodney W. Grimes 	/*
414df8bae1dSRodney W. Grimes 	 * create a Link Level name for this device
415df8bae1dSRodney W. Grimes 	 */
4169bf40edeSBrooks Davis 	namelen = strlen(ifp->if_xname);
41736c19a57SBrooks Davis 	/*
41836c19a57SBrooks Davis 	 * Always save enough space for any possiable name so we can do
41936c19a57SBrooks Davis 	 * a rename in place later.
42036c19a57SBrooks Davis 	 */
42136c19a57SBrooks Davis 	masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ;
422df8bae1dSRodney W. Grimes 	socksize = masklen + ifp->if_addrlen;
423df8bae1dSRodney W. Grimes 	if (socksize < sizeof(*sdl))
424df8bae1dSRodney W. Grimes 		socksize = sizeof(*sdl);
425ccb82468SBrooks Davis 	socksize = roundup2(socksize, sizeof(long));
426df8bae1dSRodney W. Grimes 	ifasize = sizeof(*ifa) + 2 * socksize;
427a8773564SBrooks Davis 	ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO);
42819fc74fbSJeffrey Hsu 	IFA_LOCK_INIT(ifa);
429df8bae1dSRodney W. Grimes 	sdl = (struct sockaddr_dl *)(ifa + 1);
430df8bae1dSRodney W. Grimes 	sdl->sdl_len = socksize;
431df8bae1dSRodney W. Grimes 	sdl->sdl_family = AF_LINK;
4329bf40edeSBrooks Davis 	bcopy(ifp->if_xname, sdl->sdl_data, namelen);
4331ce9bf88SPoul-Henning Kamp 	sdl->sdl_nlen = namelen;
434df8bae1dSRodney W. Grimes 	sdl->sdl_index = ifp->if_index;
435df8bae1dSRodney W. Grimes 	sdl->sdl_type = ifp->if_type;
436ffb5a104SJonathan Lemon 	ifaddr_byindex(ifp->if_index) = ifa;
437df8bae1dSRodney W. Grimes 	ifa->ifa_ifp = ifp;
438df8bae1dSRodney W. Grimes 	ifa->ifa_rtrequest = link_rtrequest;
439df8bae1dSRodney W. Grimes 	ifa->ifa_addr = (struct sockaddr *)sdl;
440df8bae1dSRodney W. Grimes 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
441df8bae1dSRodney W. Grimes 	ifa->ifa_netmask = (struct sockaddr *)sdl;
442df8bae1dSRodney W. Grimes 	sdl->sdl_len = masklen;
443df8bae1dSRodney W. Grimes 	while (namelen != 0)
444df8bae1dSRodney W. Grimes 		sdl->sdl_data[--namelen] = 0xff;
44519fc74fbSJeffrey Hsu 	ifa->ifa_refcnt = 1;
44659562606SGarrett Wollman 	TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
4476237419dSRobert Watson 	ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */
44802b199f1SMax Laier 	ifp->if_snd.altq_type = 0;
44902b199f1SMax Laier 	ifp->if_snd.altq_disc = NULL;
45002b199f1SMax Laier 	ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE;
45102b199f1SMax Laier 	ifp->if_snd.altq_tbr  = NULL;
45202b199f1SMax Laier 	ifp->if_snd.altq_ifp  = ifp;
4537b6edd04SRuslan Ermilov 
45469fb23b7SMax Laier 	if (domain_init_status >= 2)
45531b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
45631b1bfe1SHajimu UMEMOTO 
45725a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
45825a4adceSMax Laier 
4597b6edd04SRuslan Ermilov 	/* Announce the interface. */
4607b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
461df8bae1dSRodney W. Grimes }
4626182fdbdSPeter Wemm 
46331b1bfe1SHajimu UMEMOTO static void
46472fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy)
46531b1bfe1SHajimu UMEMOTO {
46631b1bfe1SHajimu UMEMOTO 	struct ifnet *ifp;
46731b1bfe1SHajimu UMEMOTO 	int s;
46831b1bfe1SHajimu UMEMOTO 
46931b1bfe1SHajimu UMEMOTO 	s = splnet();
4709046571fSLuigi Rizzo 	TAILQ_FOREACH(ifp, &ifnet, if_link)
47131b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
47231b1bfe1SHajimu UMEMOTO 	splx(s);
47331b1bfe1SHajimu UMEMOTO }
47469fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND,
47531b1bfe1SHajimu UMEMOTO     if_attachdomain, NULL);
47631b1bfe1SHajimu UMEMOTO 
47731b1bfe1SHajimu UMEMOTO static void
47872fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp)
47931b1bfe1SHajimu UMEMOTO {
48031b1bfe1SHajimu UMEMOTO 	struct domain *dp;
48131b1bfe1SHajimu UMEMOTO 	int s;
48231b1bfe1SHajimu UMEMOTO 
48331b1bfe1SHajimu UMEMOTO 	s = splnet();
48431b1bfe1SHajimu UMEMOTO 
485234a35c7SHajimu UMEMOTO 	/*
486234a35c7SHajimu UMEMOTO 	 * Since dp->dom_ifattach calls malloc() with M_WAITOK, we
487234a35c7SHajimu UMEMOTO 	 * cannot lock ifp->if_afdata initialization, entirely.
488234a35c7SHajimu UMEMOTO 	 */
489234a35c7SHajimu UMEMOTO 	if (IF_AFDATA_TRYLOCK(ifp) == 0) {
490234a35c7SHajimu UMEMOTO 		splx(s);
491234a35c7SHajimu UMEMOTO 		return;
492234a35c7SHajimu UMEMOTO 	}
49369fb23b7SMax Laier 	if (ifp->if_afdata_initialized >= domain_init_status) {
494234a35c7SHajimu UMEMOTO 		IF_AFDATA_UNLOCK(ifp);
495234a35c7SHajimu UMEMOTO 		splx(s);
4966237419dSRobert Watson 		printf("if_attachdomain called more than once on %s\n",
4976237419dSRobert Watson 		    ifp->if_xname);
498234a35c7SHajimu UMEMOTO 		return;
499234a35c7SHajimu UMEMOTO 	}
50069fb23b7SMax Laier 	ifp->if_afdata_initialized = domain_init_status;
501234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
502234a35c7SHajimu UMEMOTO 
50331b1bfe1SHajimu UMEMOTO 	/* address family dependent data region */
50431b1bfe1SHajimu UMEMOTO 	bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
50531b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
50631b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifattach)
50731b1bfe1SHajimu UMEMOTO 			ifp->if_afdata[dp->dom_family] =
50831b1bfe1SHajimu UMEMOTO 			    (*dp->dom_ifattach)(ifp);
50931b1bfe1SHajimu UMEMOTO 	}
51031b1bfe1SHajimu UMEMOTO 
51131b1bfe1SHajimu UMEMOTO 	splx(s);
51231b1bfe1SHajimu UMEMOTO }
51331b1bfe1SHajimu UMEMOTO 
5146182fdbdSPeter Wemm /*
5156182fdbdSPeter Wemm  * Detach an interface, removing it from the
5166182fdbdSPeter Wemm  * list of "active" interfaces.
5176182fdbdSPeter Wemm  */
5186182fdbdSPeter Wemm void
51972fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp)
5206182fdbdSPeter Wemm {
521212bd869SHajimu UMEMOTO 	struct ifaddr *ifa, *next;
5225500d3beSWarner Losh 	struct radix_node_head	*rnh;
5235500d3beSWarner Losh 	int s;
5245500d3beSWarner Losh 	int i;
52531b1bfe1SHajimu UMEMOTO 	struct domain *dp;
5263f35d515SPeter Pentchev  	struct ifnet *iter;
5273f35d515SPeter Pentchev  	int found;
5286182fdbdSPeter Wemm 
52925a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
5306182fdbdSPeter Wemm 	/*
5316182fdbdSPeter Wemm 	 * Remove routes and flush queues.
5326182fdbdSPeter Wemm 	 */
5335500d3beSWarner Losh 	s = splnet();
5346182fdbdSPeter Wemm 	if_down(ifp);
53502b199f1SMax Laier #ifdef ALTQ
53602b199f1SMax Laier 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
53702b199f1SMax Laier 		altq_disable(&ifp->if_snd);
53802b199f1SMax Laier 	if (ALTQ_IS_ATTACHED(&ifp->if_snd))
53902b199f1SMax Laier 		altq_detach(&ifp->if_snd);
54002b199f1SMax Laier #endif
5416182fdbdSPeter Wemm 
542212bd869SHajimu UMEMOTO 	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = next) {
543212bd869SHajimu UMEMOTO 		next = TAILQ_NEXT(ifa, ifa_link);
544212bd869SHajimu UMEMOTO 
545212bd869SHajimu UMEMOTO 		if (ifa->ifa_addr->sa_family == AF_LINK)
546212bd869SHajimu UMEMOTO 			continue;
5470d0f9d1eSYoshinobu Inoue #ifdef INET
548aa6be122SWarner Losh 		/* XXX: Ugly!! ad hoc just for INET */
549aa6be122SWarner Losh 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
550aa6be122SWarner Losh 			struct ifaliasreq ifr;
551aa6be122SWarner Losh 
552aa6be122SWarner Losh 			bzero(&ifr, sizeof(ifr));
553aa6be122SWarner Losh 			ifr.ifra_addr = *ifa->ifa_addr;
554aa6be122SWarner Losh 			if (ifa->ifa_dstaddr)
555aa6be122SWarner Losh 				ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
556aa6be122SWarner Losh 			if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
557aa6be122SWarner Losh 			    NULL) == 0)
558aa6be122SWarner Losh 				continue;
559aa6be122SWarner Losh 		}
5600d0f9d1eSYoshinobu Inoue #endif /* INET */
5610d0f9d1eSYoshinobu Inoue #ifdef INET6
5620d0f9d1eSYoshinobu Inoue 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
56333841545SHajimu UMEMOTO 			in6_purgeaddr(ifa);
564978ee2edSJun-ichiro itojun Hagino 			/* ifp_addrhead is already updated */
5650d0f9d1eSYoshinobu Inoue 			continue;
5660d0f9d1eSYoshinobu Inoue 		}
5670d0f9d1eSYoshinobu Inoue #endif /* INET6 */
5686182fdbdSPeter Wemm 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
5696182fdbdSPeter Wemm 		IFAFREE(ifa);
5706182fdbdSPeter Wemm 	}
5716182fdbdSPeter Wemm 
57233841545SHajimu UMEMOTO #ifdef INET6
57333841545SHajimu UMEMOTO 	/*
57433841545SHajimu UMEMOTO 	 * Remove all IPv6 kernel structs related to ifp.  This should be done
57533841545SHajimu UMEMOTO 	 * before removing routing entries below, since IPv6 interface direct
57633841545SHajimu UMEMOTO 	 * routes are expected to be removed by the IPv6-specific kernel API.
57733841545SHajimu UMEMOTO 	 * Otherwise, the kernel will detect some inconsistency and bark it.
57833841545SHajimu UMEMOTO 	 */
57933841545SHajimu UMEMOTO 	in6_ifdetach(ifp);
58033841545SHajimu UMEMOTO #endif
581f4247b59SLuigi Rizzo 	/*
582f4247b59SLuigi Rizzo 	 * Remove address from ifindex_table[] and maybe decrement if_index.
583f4247b59SLuigi Rizzo 	 * Clean up all addresses.
584f4247b59SLuigi Rizzo 	 */
585b9907cd4SBrooks Davis 	ifnet_byindex(ifp->if_index) = NULL;
586f4247b59SLuigi Rizzo 	ifaddr_byindex(ifp->if_index) = NULL;
587f4247b59SLuigi Rizzo 	destroy_dev(ifdev_byindex(ifp->if_index));
588f4247b59SLuigi Rizzo 	ifdev_byindex(ifp->if_index) = NULL;
589f4247b59SLuigi Rizzo 
590f4247b59SLuigi Rizzo 	while (if_index > 0 && ifaddr_byindex(if_index) == NULL)
591f4247b59SLuigi Rizzo 		if_index--;
592f4247b59SLuigi Rizzo 
59333841545SHajimu UMEMOTO 
594212bd869SHajimu UMEMOTO 	/* We can now free link ifaddr. */
5953f35d515SPeter Pentchev 	if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
596212bd869SHajimu UMEMOTO 		ifa = TAILQ_FIRST(&ifp->if_addrhead);
597212bd869SHajimu UMEMOTO 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
598212bd869SHajimu UMEMOTO 		IFAFREE(ifa);
5993f35d515SPeter Pentchev 	}
600212bd869SHajimu UMEMOTO 
6015500d3beSWarner Losh 	/*
6025500d3beSWarner Losh 	 * Delete all remaining routes using this interface
6035500d3beSWarner Losh 	 * Unfortuneatly the only way to do this is to slog through
6045500d3beSWarner Losh 	 * the entire routing table looking for routes which point
6055500d3beSWarner Losh 	 * to this interface...oh well...
6065500d3beSWarner Losh 	 */
6075500d3beSWarner Losh 	for (i = 1; i <= AF_MAX; i++) {
6085500d3beSWarner Losh 		if ((rnh = rt_tables[i]) == NULL)
6095500d3beSWarner Losh 			continue;
610956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_LOCK(rnh);
6115500d3beSWarner Losh 		(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
612956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_UNLOCK(rnh);
6135500d3beSWarner Losh 	}
6145500d3beSWarner Losh 
6157b6edd04SRuslan Ermilov 	/* Announce that the interface is gone. */
6167b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
6177b6edd04SRuslan Ermilov 
618234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK(ifp);
61931b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
62031b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
62131b1bfe1SHajimu UMEMOTO 			(*dp->dom_ifdetach)(ifp,
62231b1bfe1SHajimu UMEMOTO 			    ifp->if_afdata[dp->dom_family]);
62331b1bfe1SHajimu UMEMOTO 	}
624234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
62531b1bfe1SHajimu UMEMOTO 
626e70cd263SRobert Watson #ifdef MAC
627e70cd263SRobert Watson 	mac_destroy_ifnet(ifp);
628e70cd263SRobert Watson #endif /* MAC */
629ad3b9257SJohn-Mark Gurney 	KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT);
630ad3b9257SJohn-Mark Gurney 	knlist_clear(&ifp->if_klist, 0);
631ad3b9257SJohn-Mark Gurney 	knlist_destroy(&ifp->if_klist);
632b30a244cSJeffrey Hsu 	IFNET_WLOCK();
6333f35d515SPeter Pentchev  	found = 0;
6343f35d515SPeter Pentchev  	TAILQ_FOREACH(iter, &ifnet, if_link)
6353f35d515SPeter Pentchev  		if (iter == ifp) {
6363f35d515SPeter Pentchev  			found = 1;
6373f35d515SPeter Pentchev  			break;
6383f35d515SPeter Pentchev  		}
6393f35d515SPeter Pentchev  	if (found)
6406182fdbdSPeter Wemm  		TAILQ_REMOVE(&ifnet, ifp, if_link);
641b30a244cSJeffrey Hsu 	IFNET_WUNLOCK();
642df5e1987SJonathan Lemon 	mtx_destroy(&ifp->if_snd.ifq_mtx);
643234a35c7SHajimu UMEMOTO 	IF_AFDATA_DESTROY(ifp);
6445500d3beSWarner Losh 	splx(s);
6455500d3beSWarner Losh }
6465500d3beSWarner Losh 
6475500d3beSWarner Losh /*
6485500d3beSWarner Losh  * Delete Routes for a Network Interface
6495500d3beSWarner Losh  *
6505500d3beSWarner Losh  * Called for each routing entry via the rnh->rnh_walktree() call above
6515500d3beSWarner Losh  * to delete all route entries referencing a detaching network interface.
6525500d3beSWarner Losh  *
6535500d3beSWarner Losh  * Arguments:
6545500d3beSWarner Losh  *	rn	pointer to node in the routing table
6555500d3beSWarner Losh  *	arg	argument passed to rnh->rnh_walktree() - detaching interface
6565500d3beSWarner Losh  *
6575500d3beSWarner Losh  * Returns:
6585500d3beSWarner Losh  *	0	successful
6595500d3beSWarner Losh  *	errno	failed - reason indicated
6605500d3beSWarner Losh  *
6615500d3beSWarner Losh  */
6625500d3beSWarner Losh static int
66372fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg)
6645500d3beSWarner Losh {
6655500d3beSWarner Losh 	struct rtentry	*rt = (struct rtentry *)rn;
6665500d3beSWarner Losh 	struct ifnet	*ifp = arg;
6675500d3beSWarner Losh 	int		err;
6685500d3beSWarner Losh 
6695500d3beSWarner Losh 	if (rt->rt_ifp == ifp) {
6705500d3beSWarner Losh 
6715500d3beSWarner Losh 		/*
6725500d3beSWarner Losh 		 * Protect (sorta) against walktree recursion problems
6735500d3beSWarner Losh 		 * with cloned routes
6745500d3beSWarner Losh 		 */
6755500d3beSWarner Losh 		if ((rt->rt_flags & RTF_UP) == 0)
6765500d3beSWarner Losh 			return (0);
6775500d3beSWarner Losh 
6785500d3beSWarner Losh 		err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
6795500d3beSWarner Losh 				rt_mask(rt), rt->rt_flags,
6805500d3beSWarner Losh 				(struct rtentry **) NULL);
6815500d3beSWarner Losh 		if (err) {
6825500d3beSWarner Losh 			log(LOG_WARNING, "if_rtdel: error %d\n", err);
6835500d3beSWarner Losh 		}
6845500d3beSWarner Losh 	}
6855500d3beSWarner Losh 
6865500d3beSWarner Losh 	return (0);
6876182fdbdSPeter Wemm }
6886182fdbdSPeter Wemm 
689d1dd20beSSam Leffler #define	equal(a1, a2)	(bcmp((a1), (a2), ((a1))->sa_len) == 0)
69019fc74fbSJeffrey Hsu 
69130aad87dSBrooks Davis /*
692df8bae1dSRodney W. Grimes  * Locate an interface based on a complete address.
693df8bae1dSRodney W. Grimes  */
694df8bae1dSRodney W. Grimes /*ARGSUSED*/
695df8bae1dSRodney W. Grimes struct ifaddr *
69672fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr)
697df8bae1dSRodney W. Grimes {
6980b59d917SJonathan Lemon 	struct ifnet *ifp;
6990b59d917SJonathan Lemon 	struct ifaddr *ifa;
700df8bae1dSRodney W. Grimes 
701b30a244cSJeffrey Hsu 	IFNET_RLOCK();
702fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link)
70337d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
704df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
705df8bae1dSRodney W. Grimes 				continue;
706df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr))
7070b59d917SJonathan Lemon 				goto done;
70882cd038dSYoshinobu Inoue 			/* IP6 doesn't have broadcast */
7090b59d917SJonathan Lemon 			if ((ifp->if_flags & IFF_BROADCAST) &&
7100b59d917SJonathan Lemon 			    ifa->ifa_broadaddr &&
71182cd038dSYoshinobu Inoue 			    ifa->ifa_broadaddr->sa_len != 0 &&
712df8bae1dSRodney W. Grimes 			    equal(ifa->ifa_broadaddr, addr))
7130b59d917SJonathan Lemon 				goto done;
7140b59d917SJonathan Lemon 		}
7150b59d917SJonathan Lemon 	ifa = NULL;
7160b59d917SJonathan Lemon done:
717b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
718df8bae1dSRodney W. Grimes 	return (ifa);
719df8bae1dSRodney W. Grimes }
7200b59d917SJonathan Lemon 
721df8bae1dSRodney W. Grimes /*
722df8bae1dSRodney W. Grimes  * Locate the point to point interface with a given destination address.
723df8bae1dSRodney W. Grimes  */
724df8bae1dSRodney W. Grimes /*ARGSUSED*/
725df8bae1dSRodney W. Grimes struct ifaddr *
72672fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr)
727df8bae1dSRodney W. Grimes {
7280b59d917SJonathan Lemon 	struct ifnet *ifp;
7290b59d917SJonathan Lemon 	struct ifaddr *ifa;
730df8bae1dSRodney W. Grimes 
731b30a244cSJeffrey Hsu 	IFNET_RLOCK();
7320b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
7330b59d917SJonathan Lemon 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
7340b59d917SJonathan Lemon 			continue;
73537d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
736df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
737df8bae1dSRodney W. Grimes 				continue;
73855088a1cSDavid Greenman 			if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
7390b59d917SJonathan Lemon 				goto done;
740df8bae1dSRodney W. Grimes 		}
7410b59d917SJonathan Lemon 	}
7420b59d917SJonathan Lemon 	ifa = NULL;
7430b59d917SJonathan Lemon done:
744b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
7450b59d917SJonathan Lemon 	return (ifa);
746df8bae1dSRodney W. Grimes }
747df8bae1dSRodney W. Grimes 
748df8bae1dSRodney W. Grimes /*
749df8bae1dSRodney W. Grimes  * Find an interface on a specific network.  If many, choice
750df8bae1dSRodney W. Grimes  * is most specific found.
751df8bae1dSRodney W. Grimes  */
752df8bae1dSRodney W. Grimes struct ifaddr *
75372fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr)
754df8bae1dSRodney W. Grimes {
75572fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
75672fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
757df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
758df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
759df8bae1dSRodney W. Grimes 	char *addr_data = addr->sa_data, *cplim;
760df8bae1dSRodney W. Grimes 
7617e2a6151SJulian Elischer 	/*
7627e2a6151SJulian Elischer 	 * AF_LINK addresses can be looked up directly by their index number,
7637e2a6151SJulian Elischer 	 * so do that if we can.
7647e2a6151SJulian Elischer 	 */
765df8bae1dSRodney W. Grimes 	if (af == AF_LINK) {
766d1dd20beSSam Leffler 	    struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
767df8bae1dSRodney W. Grimes 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
768f9132cebSJonathan Lemon 		return (ifaddr_byindex(sdl->sdl_index));
769df8bae1dSRodney W. Grimes 	}
7707e2a6151SJulian Elischer 
7717e2a6151SJulian Elischer 	/*
7727e2a6151SJulian Elischer 	 * Scan though each interface, looking for ones that have
7737e2a6151SJulian Elischer 	 * addresses in this address family.
7747e2a6151SJulian Elischer 	 */
775b30a244cSJeffrey Hsu 	IFNET_RLOCK();
776fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
77737d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
77872fd1b6aSDag-Erling Smørgrav 			char *cp, *cp2, *cp3;
779df8bae1dSRodney W. Grimes 
780523a02aaSDavid Greenman 			if (ifa->ifa_addr->sa_family != af)
781df8bae1dSRodney W. Grimes next:				continue;
782c61cd599SHajimu UMEMOTO 			if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) {
7837e2a6151SJulian Elischer 				/*
7847e2a6151SJulian Elischer 				 * This is a bit broken as it doesn't
7857e2a6151SJulian Elischer 				 * take into account that the remote end may
7867e2a6151SJulian Elischer 				 * be a single node in the network we are
7877e2a6151SJulian Elischer 				 * looking for.
7887e2a6151SJulian Elischer 				 * The trouble is that we don't know the
7897e2a6151SJulian Elischer 				 * netmask for the remote end.
7907e2a6151SJulian Elischer 				 */
791fcd6781aSGarrett Wollman 				if (ifa->ifa_dstaddr != 0
792fcd6781aSGarrett Wollman 				    && equal(addr, ifa->ifa_dstaddr))
7930b59d917SJonathan Lemon 					goto done;
7943740e2adSDavid Greenman 			} else {
7957e2a6151SJulian Elischer 				/*
7967ed8f465SJulian Elischer 				 * if we have a special address handler,
7977ed8f465SJulian Elischer 				 * then use it instead of the generic one.
7987ed8f465SJulian Elischer 				 */
7997ed8f465SJulian Elischer 				if (ifa->ifa_claim_addr) {
8000b59d917SJonathan Lemon 					if ((*ifa->ifa_claim_addr)(ifa, addr))
8010b59d917SJonathan Lemon 						goto done;
8027ed8f465SJulian Elischer 					continue;
8037ed8f465SJulian Elischer 				}
8047ed8f465SJulian Elischer 
8057ed8f465SJulian Elischer 				/*
8067e2a6151SJulian Elischer 				 * Scan all the bits in the ifa's address.
8077e2a6151SJulian Elischer 				 * If a bit dissagrees with what we are
8087e2a6151SJulian Elischer 				 * looking for, mask it with the netmask
8097e2a6151SJulian Elischer 				 * to see if it really matters.
8107e2a6151SJulian Elischer 				 * (A byte at a time)
8117e2a6151SJulian Elischer 				 */
812523a02aaSDavid Greenman 				if (ifa->ifa_netmask == 0)
813523a02aaSDavid Greenman 					continue;
814df8bae1dSRodney W. Grimes 				cp = addr_data;
815df8bae1dSRodney W. Grimes 				cp2 = ifa->ifa_addr->sa_data;
816df8bae1dSRodney W. Grimes 				cp3 = ifa->ifa_netmask->sa_data;
8177e2a6151SJulian Elischer 				cplim = ifa->ifa_netmask->sa_len
8187e2a6151SJulian Elischer 					+ (char *)ifa->ifa_netmask;
819df8bae1dSRodney W. Grimes 				while (cp3 < cplim)
820df8bae1dSRodney W. Grimes 					if ((*cp++ ^ *cp2++) & *cp3++)
8217e2a6151SJulian Elischer 						goto next; /* next address! */
8227e2a6151SJulian Elischer 				/*
8237e2a6151SJulian Elischer 				 * If the netmask of what we just found
8247e2a6151SJulian Elischer 				 * is more specific than what we had before
8257e2a6151SJulian Elischer 				 * (if we had one) then remember the new one
8267e2a6151SJulian Elischer 				 * before continuing to search
8277e2a6151SJulian Elischer 				 * for an even better one.
8287e2a6151SJulian Elischer 				 */
829df8bae1dSRodney W. Grimes 				if (ifa_maybe == 0 ||
830df8bae1dSRodney W. Grimes 				    rn_refines((caddr_t)ifa->ifa_netmask,
831df8bae1dSRodney W. Grimes 				    (caddr_t)ifa_maybe->ifa_netmask))
832df8bae1dSRodney W. Grimes 					ifa_maybe = ifa;
833df8bae1dSRodney W. Grimes 			}
834b2af64fdSDavid Greenman 		}
835b2af64fdSDavid Greenman 	}
8360b59d917SJonathan Lemon 	ifa = ifa_maybe;
8370b59d917SJonathan Lemon done:
838b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
8390b59d917SJonathan Lemon 	return (ifa);
840df8bae1dSRodney W. Grimes }
841df8bae1dSRodney W. Grimes 
842df8bae1dSRodney W. Grimes /*
843df8bae1dSRodney W. Grimes  * Find an interface address specific to an interface best matching
844df8bae1dSRodney W. Grimes  * a given address.
845df8bae1dSRodney W. Grimes  */
846df8bae1dSRodney W. Grimes struct ifaddr *
84772fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
848df8bae1dSRodney W. Grimes {
84972fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
85072fd1b6aSDag-Erling Smørgrav 	char *cp, *cp2, *cp3;
85172fd1b6aSDag-Erling Smørgrav 	char *cplim;
852df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = 0;
853df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
854df8bae1dSRodney W. Grimes 
855df8bae1dSRodney W. Grimes 	if (af >= AF_MAX)
856df8bae1dSRodney W. Grimes 		return (0);
85737d40066SPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
858df8bae1dSRodney W. Grimes 		if (ifa->ifa_addr->sa_family != af)
859df8bae1dSRodney W. Grimes 			continue;
860381dd1d2SJulian Elischer 		if (ifa_maybe == 0)
861df8bae1dSRodney W. Grimes 			ifa_maybe = ifa;
862df8bae1dSRodney W. Grimes 		if (ifa->ifa_netmask == 0) {
863df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr) ||
864df8bae1dSRodney W. Grimes 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
8652defe5cdSJonathan Lemon 				goto done;
866df8bae1dSRodney W. Grimes 			continue;
867df8bae1dSRodney W. Grimes 		}
868b2af64fdSDavid Greenman 		if (ifp->if_flags & IFF_POINTOPOINT) {
869b2af64fdSDavid Greenman 			if (equal(addr, ifa->ifa_dstaddr))
870a8637146SJonathan Lemon 				goto done;
8713740e2adSDavid Greenman 		} else {
872df8bae1dSRodney W. Grimes 			cp = addr->sa_data;
873df8bae1dSRodney W. Grimes 			cp2 = ifa->ifa_addr->sa_data;
874df8bae1dSRodney W. Grimes 			cp3 = ifa->ifa_netmask->sa_data;
875df8bae1dSRodney W. Grimes 			cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
876df8bae1dSRodney W. Grimes 			for (; cp3 < cplim; cp3++)
877df8bae1dSRodney W. Grimes 				if ((*cp++ ^ *cp2++) & *cp3)
878df8bae1dSRodney W. Grimes 					break;
879df8bae1dSRodney W. Grimes 			if (cp3 == cplim)
8802defe5cdSJonathan Lemon 				goto done;
881df8bae1dSRodney W. Grimes 		}
882b2af64fdSDavid Greenman 	}
883f9132cebSJonathan Lemon 	ifa = ifa_maybe;
884f9132cebSJonathan Lemon done:
885f9132cebSJonathan Lemon 	return (ifa);
886df8bae1dSRodney W. Grimes }
887df8bae1dSRodney W. Grimes 
888df8bae1dSRodney W. Grimes #include <net/route.h>
889df8bae1dSRodney W. Grimes 
890df8bae1dSRodney W. Grimes /*
891df8bae1dSRodney W. Grimes  * Default action when installing a route with a Link Level gateway.
892df8bae1dSRodney W. Grimes  * Lookup an appropriate real ifa to point to.
893df8bae1dSRodney W. Grimes  * This should be moved to /sys/net/link.c eventually.
894df8bae1dSRodney W. Grimes  */
8953bda9f9bSPoul-Henning Kamp static void
89672fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
897df8bae1dSRodney W. Grimes {
89872fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa, *oifa;
899df8bae1dSRodney W. Grimes 	struct sockaddr *dst;
900df8bae1dSRodney W. Grimes 	struct ifnet *ifp;
901df8bae1dSRodney W. Grimes 
902d1dd20beSSam Leffler 	RT_LOCK_ASSERT(rt);
903d1dd20beSSam Leffler 
904df8bae1dSRodney W. Grimes 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
905df8bae1dSRodney W. Grimes 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
906df8bae1dSRodney W. Grimes 		return;
9079448326fSPoul-Henning Kamp 	ifa = ifaof_ifpforaddr(dst, ifp);
9089448326fSPoul-Henning Kamp 	if (ifa) {
90919fc74fbSJeffrey Hsu 		IFAREF(ifa);		/* XXX */
910d1dd20beSSam Leffler 		oifa = rt->rt_ifa;
911df8bae1dSRodney W. Grimes 		rt->rt_ifa = ifa;
912d1dd20beSSam Leffler 		IFAFREE(oifa);
913df8bae1dSRodney W. Grimes 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
9148071913dSRuslan Ermilov 			ifa->ifa_rtrequest(cmd, rt, info);
915df8bae1dSRodney W. Grimes 	}
916df8bae1dSRodney W. Grimes }
917df8bae1dSRodney W. Grimes 
918df8bae1dSRodney W. Grimes /*
919df8bae1dSRodney W. Grimes  * Mark an interface down and notify protocols of
920df8bae1dSRodney W. Grimes  * the transition.
921df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
922df8bae1dSRodney W. Grimes  */
9238614fb12SMax Laier static void
92472fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam)
925df8bae1dSRodney W. Grimes {
92672fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
927df8bae1dSRodney W. Grimes 
928e8c2601dSPoul-Henning Kamp 	ifp->if_flags &= ~flag;
92998b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
930e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
931e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
932df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
933df8bae1dSRodney W. Grimes 	if_qflush(&ifp->if_snd);
934df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
935df8bae1dSRodney W. Grimes }
936df8bae1dSRodney W. Grimes 
937df8bae1dSRodney W. Grimes /*
938df8bae1dSRodney W. Grimes  * Mark an interface up and notify protocols of
939df8bae1dSRodney W. Grimes  * the transition.
940df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
941df8bae1dSRodney W. Grimes  */
9428614fb12SMax Laier static void
94372fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam)
944df8bae1dSRodney W. Grimes {
94572fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
946df8bae1dSRodney W. Grimes 
947e8c2601dSPoul-Henning Kamp 	ifp->if_flags |= flag;
94898b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
949e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
950e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
951df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFUP, ifa->ifa_addr);
952df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
95382cd038dSYoshinobu Inoue #ifdef INET6
95482cd038dSYoshinobu Inoue 	in6_if_up(ifp);
95582cd038dSYoshinobu Inoue #endif
956df8bae1dSRodney W. Grimes }
957df8bae1dSRodney W. Grimes 
958df8bae1dSRodney W. Grimes /*
959e8c2601dSPoul-Henning Kamp  * Mark an interface down and notify protocols of
960e8c2601dSPoul-Henning Kamp  * the transition.
961e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
962e8c2601dSPoul-Henning Kamp  */
963e8c2601dSPoul-Henning Kamp void
96472fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp)
965e8c2601dSPoul-Henning Kamp {
966e8c2601dSPoul-Henning Kamp 
967e8c2601dSPoul-Henning Kamp 	if_unroute(ifp, IFF_UP, AF_UNSPEC);
968e8c2601dSPoul-Henning Kamp }
969e8c2601dSPoul-Henning Kamp 
970e8c2601dSPoul-Henning Kamp /*
971e8c2601dSPoul-Henning Kamp  * Mark an interface up and notify protocols of
972e8c2601dSPoul-Henning Kamp  * the transition.
973e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
974e8c2601dSPoul-Henning Kamp  */
975e8c2601dSPoul-Henning Kamp void
97672fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp)
977e8c2601dSPoul-Henning Kamp {
978e8c2601dSPoul-Henning Kamp 
979e8c2601dSPoul-Henning Kamp 	if_route(ifp, IFF_UP, AF_UNSPEC);
980e8c2601dSPoul-Henning Kamp }
981e8c2601dSPoul-Henning Kamp 
982e8c2601dSPoul-Henning Kamp /*
983df8bae1dSRodney W. Grimes  * Flush an interface queue.
984df8bae1dSRodney W. Grimes  */
9853bda9f9bSPoul-Henning Kamp static void
98602b199f1SMax Laier if_qflush(struct ifaltq *ifq)
987df8bae1dSRodney W. Grimes {
98872fd1b6aSDag-Erling Smørgrav 	struct mbuf *m, *n;
989df8bae1dSRodney W. Grimes 
9907b21048cSMax Laier 	IFQ_LOCK(ifq);
99102b199f1SMax Laier #ifdef ALTQ
99202b199f1SMax Laier 	if (ALTQ_IS_ENABLED(ifq))
99302b199f1SMax Laier 		ALTQ_PURGE(ifq);
99402b199f1SMax Laier #endif
995df8bae1dSRodney W. Grimes 	n = ifq->ifq_head;
9969448326fSPoul-Henning Kamp 	while ((m = n) != 0) {
997df8bae1dSRodney W. Grimes 		n = m->m_act;
998df8bae1dSRodney W. Grimes 		m_freem(m);
999df8bae1dSRodney W. Grimes 	}
1000df8bae1dSRodney W. Grimes 	ifq->ifq_head = 0;
1001df8bae1dSRodney W. Grimes 	ifq->ifq_tail = 0;
1002df8bae1dSRodney W. Grimes 	ifq->ifq_len = 0;
10037b21048cSMax Laier 	IFQ_UNLOCK(ifq);
1004df8bae1dSRodney W. Grimes }
1005df8bae1dSRodney W. Grimes 
1006df8bae1dSRodney W. Grimes /*
1007df8bae1dSRodney W. Grimes  * Handle interface watchdog timer routines.  Called
1008df8bae1dSRodney W. Grimes  * from softclock, we decrement timers (if set) and
1009df8bae1dSRodney W. Grimes  * call the appropriate interface routine on expiration.
1010af5e59bfSRobert Watson  *
1011af5e59bfSRobert Watson  * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called
1012af5e59bfSRobert Watson  * holding Giant.  If we switch to an MPSAFE callout, we likely need to grab
1013af5e59bfSRobert Watson  * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface.
1014df8bae1dSRodney W. Grimes  */
10153bda9f9bSPoul-Henning Kamp static void
101672fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg)
1017df8bae1dSRodney W. Grimes {
101872fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
1019df8bae1dSRodney W. Grimes 	int s = splimp();
1020df8bae1dSRodney W. Grimes 
1021b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1022fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1023df8bae1dSRodney W. Grimes 		if (ifp->if_timer == 0 || --ifp->if_timer)
1024df8bae1dSRodney W. Grimes 			continue;
1025df8bae1dSRodney W. Grimes 		if (ifp->if_watchdog)
10264a5f1499SDavid Greenman 			(*ifp->if_watchdog)(ifp);
1027df8bae1dSRodney W. Grimes 	}
1028b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1029df8bae1dSRodney W. Grimes 	splx(s);
1030df8bae1dSRodney W. Grimes 	timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
1031df8bae1dSRodney W. Grimes }
1032df8bae1dSRodney W. Grimes 
1033df8bae1dSRodney W. Grimes /*
1034df8bae1dSRodney W. Grimes  * Map interface name to
1035df8bae1dSRodney W. Grimes  * interface structure pointer.
1036df8bae1dSRodney W. Grimes  */
1037df8bae1dSRodney W. Grimes struct ifnet *
103830aad87dSBrooks Davis ifunit(const char *name)
1039df8bae1dSRodney W. Grimes {
10408b7805e4SBoris Popov 	struct ifnet *ifp;
1041df8bae1dSRodney W. Grimes 
1042b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1043fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
104436c19a57SBrooks Davis 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
1045df8bae1dSRodney W. Grimes 			break;
1046df8bae1dSRodney W. Grimes 	}
1047b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1048df8bae1dSRodney W. Grimes 	return (ifp);
1049df8bae1dSRodney W. Grimes }
1050df8bae1dSRodney W. Grimes 
105182cd038dSYoshinobu Inoue /*
1052f13ad206SJonathan Lemon  * Hardware specific interface ioctls.
1053df8bae1dSRodney W. Grimes  */
1054f13ad206SJonathan Lemon static int
1055f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
1056df8bae1dSRodney W. Grimes {
1057f13ad206SJonathan Lemon 	struct ifreq *ifr;
1058413dd0baSPoul-Henning Kamp 	struct ifstat *ifs;
1059f13ad206SJonathan Lemon 	int error = 0;
106062f76486SMaxim Sobolev 	int new_flags;
106136c19a57SBrooks Davis 	size_t namelen, onamelen;
106236c19a57SBrooks Davis 	char new_name[IFNAMSIZ];
106336c19a57SBrooks Davis 	struct ifaddr *ifa;
106436c19a57SBrooks Davis 	struct sockaddr_dl *sdl;
1065df8bae1dSRodney W. Grimes 
1066df8bae1dSRodney W. Grimes 	ifr = (struct ifreq *)data;
106730aad87dSBrooks Davis 	switch (cmd) {
1068de593450SJonathan Lemon 	case SIOCGIFINDEX:
1069de593450SJonathan Lemon 		ifr->ifr_index = ifp->if_index;
1070de593450SJonathan Lemon 		break;
1071de593450SJonathan Lemon 
1072df8bae1dSRodney W. Grimes 	case SIOCGIFFLAGS:
107362f76486SMaxim Sobolev 		ifr->ifr_flags = ifp->if_flags & 0xffff;
107462f76486SMaxim Sobolev 		ifr->ifr_flagshigh = ifp->if_flags >> 16;
1075df8bae1dSRodney W. Grimes 		break;
1076df8bae1dSRodney W. Grimes 
1077016da741SJonathan Lemon 	case SIOCGIFCAP:
1078016da741SJonathan Lemon 		ifr->ifr_reqcap = ifp->if_capabilities;
1079016da741SJonathan Lemon 		ifr->ifr_curcap = ifp->if_capenable;
1080016da741SJonathan Lemon 		break;
1081016da741SJonathan Lemon 
10828f293a63SRobert Watson #ifdef MAC
10838f293a63SRobert Watson 	case SIOCGIFMAC:
108431566c96SJohn Baldwin 		error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp);
10858f293a63SRobert Watson 		break;
10868f293a63SRobert Watson #endif
10878f293a63SRobert Watson 
1088df8bae1dSRodney W. Grimes 	case SIOCGIFMETRIC:
1089df8bae1dSRodney W. Grimes 		ifr->ifr_metric = ifp->if_metric;
1090df8bae1dSRodney W. Grimes 		break;
1091df8bae1dSRodney W. Grimes 
1092a7028af7SDavid Greenman 	case SIOCGIFMTU:
1093a7028af7SDavid Greenman 		ifr->ifr_mtu = ifp->if_mtu;
1094a7028af7SDavid Greenman 		break;
1095a7028af7SDavid Greenman 
1096074c4a4eSGarrett Wollman 	case SIOCGIFPHYS:
1097074c4a4eSGarrett Wollman 		ifr->ifr_phys = ifp->if_physical;
1098074c4a4eSGarrett Wollman 		break;
1099074c4a4eSGarrett Wollman 
1100df8bae1dSRodney W. Grimes 	case SIOCSIFFLAGS:
110144731cabSJohn Baldwin 		error = suser(td);
11029448326fSPoul-Henning Kamp 		if (error)
1103df8bae1dSRodney W. Grimes 			return (error);
110462f76486SMaxim Sobolev 		new_flags = (ifr->ifr_flags & 0xffff) |
110562f76486SMaxim Sobolev 		    (ifr->ifr_flagshigh << 16);
1106cf4b9371SPoul-Henning Kamp 		if (ifp->if_flags & IFF_SMART) {
1107cf4b9371SPoul-Henning Kamp 			/* Smart drivers twiddle their own routes */
11082f55ead7SPoul-Henning Kamp 		} else if (ifp->if_flags & IFF_UP &&
110962f76486SMaxim Sobolev 		    (new_flags & IFF_UP) == 0) {
1110df8bae1dSRodney W. Grimes 			int s = splimp();
1111df8bae1dSRodney W. Grimes 			if_down(ifp);
1112df8bae1dSRodney W. Grimes 			splx(s);
111362f76486SMaxim Sobolev 		} else if (new_flags & IFF_UP &&
1114cf4b9371SPoul-Henning Kamp 		    (ifp->if_flags & IFF_UP) == 0) {
1115df8bae1dSRodney W. Grimes 			int s = splimp();
1116df8bae1dSRodney W. Grimes 			if_up(ifp);
1117df8bae1dSRodney W. Grimes 			splx(s);
1118df8bae1dSRodney W. Grimes 		}
1119df8bae1dSRodney W. Grimes 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
112062f76486SMaxim Sobolev 			(new_flags &~ IFF_CANTCHANGE);
1121ffb079beSMaxim Sobolev 		if (new_flags & IFF_PPROMISC) {
1122ffb079beSMaxim Sobolev 			/* Permanently promiscuous mode requested */
1123ffb079beSMaxim Sobolev 			ifp->if_flags |= IFF_PROMISC;
1124ffb079beSMaxim Sobolev 		} else if (ifp->if_pcount == 0) {
1125ffb079beSMaxim Sobolev 			ifp->if_flags &= ~IFF_PROMISC;
1126ffb079beSMaxim Sobolev 		}
112731302ebfSRobert Watson 		if (ifp->if_ioctl) {
112831302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1129df8bae1dSRodney W. Grimes 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
113031302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
113131302ebfSRobert Watson 		}
113298b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1133df8bae1dSRodney W. Grimes 		break;
1134df8bae1dSRodney W. Grimes 
1135016da741SJonathan Lemon 	case SIOCSIFCAP:
113644731cabSJohn Baldwin 		error = suser(td);
1137016da741SJonathan Lemon 		if (error)
1138016da741SJonathan Lemon 			return (error);
1139efb4018bSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1140efb4018bSYaroslav Tykhiy 			return (EOPNOTSUPP);
1141016da741SJonathan Lemon 		if (ifr->ifr_reqcap & ~ifp->if_capabilities)
1142016da741SJonathan Lemon 			return (EINVAL);
114331302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1144efb4018bSYaroslav Tykhiy 		error = (*ifp->if_ioctl)(ifp, cmd, data);
114531302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1146efb4018bSYaroslav Tykhiy 		if (error == 0)
1147efb4018bSYaroslav Tykhiy 			getmicrotime(&ifp->if_lastchange);
1148016da741SJonathan Lemon 		break;
1149016da741SJonathan Lemon 
11508f293a63SRobert Watson #ifdef MAC
11518f293a63SRobert Watson 	case SIOCSIFMAC:
115231566c96SJohn Baldwin 		error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp);
11538f293a63SRobert Watson 		break;
11548f293a63SRobert Watson #endif
11558f293a63SRobert Watson 
115636c19a57SBrooks Davis 	case SIOCSIFNAME:
115736c19a57SBrooks Davis 		error = suser(td);
1158bc1470f1SBrooks Davis 		if (error != 0)
115936c19a57SBrooks Davis 			return (error);
116036c19a57SBrooks Davis 		error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL);
1161bc1470f1SBrooks Davis 		if (error != 0)
116236c19a57SBrooks Davis 			return (error);
1163bc1470f1SBrooks Davis 		if (new_name[0] == '\0')
1164bc1470f1SBrooks Davis 			return (EINVAL);
116536c19a57SBrooks Davis 		if (ifunit(new_name) != NULL)
116636c19a57SBrooks Davis 			return (EEXIST);
116736c19a57SBrooks Davis 
116825a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
116936c19a57SBrooks Davis 		/* Announce the departure of the interface. */
117036c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
117136c19a57SBrooks Davis 
117271672bb6SBrooks Davis 		log(LOG_INFO, "%s: changing name to '%s'\n",
117371672bb6SBrooks Davis 		    ifp->if_xname, new_name);
117471672bb6SBrooks Davis 
117536c19a57SBrooks Davis 		strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
11769b98ee2cSLuigi Rizzo 		ifa = ifaddr_byindex(ifp->if_index);
117736c19a57SBrooks Davis 		IFA_LOCK(ifa);
117836c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
117936c19a57SBrooks Davis 		namelen = strlen(new_name);
118036c19a57SBrooks Davis 		onamelen = sdl->sdl_nlen;
118136c19a57SBrooks Davis 		/*
118236c19a57SBrooks Davis 		 * Move the address if needed.  This is safe because we
118336c19a57SBrooks Davis 		 * allocate space for a name of length IFNAMSIZ when we
118436c19a57SBrooks Davis 		 * create this in if_attach().
118536c19a57SBrooks Davis 		 */
118636c19a57SBrooks Davis 		if (namelen != onamelen) {
118736c19a57SBrooks Davis 			bcopy(sdl->sdl_data + onamelen,
118836c19a57SBrooks Davis 			    sdl->sdl_data + namelen, sdl->sdl_alen);
118936c19a57SBrooks Davis 		}
119036c19a57SBrooks Davis 		bcopy(new_name, sdl->sdl_data, namelen);
119136c19a57SBrooks Davis 		sdl->sdl_nlen = namelen;
119236c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_netmask;
119336c19a57SBrooks Davis 		bzero(sdl->sdl_data, onamelen);
119436c19a57SBrooks Davis 		while (namelen != 0)
119536c19a57SBrooks Davis 			sdl->sdl_data[--namelen] = 0xff;
119636c19a57SBrooks Davis 		IFA_UNLOCK(ifa);
119736c19a57SBrooks Davis 
119825a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
119936c19a57SBrooks Davis 		/* Announce the return of the interface. */
120036c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
120136c19a57SBrooks Davis 		break;
120236c19a57SBrooks Davis 
1203df8bae1dSRodney W. Grimes 	case SIOCSIFMETRIC:
120444731cabSJohn Baldwin 		error = suser(td);
12059448326fSPoul-Henning Kamp 		if (error)
1206df8bae1dSRodney W. Grimes 			return (error);
1207df8bae1dSRodney W. Grimes 		ifp->if_metric = ifr->ifr_metric;
120898b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1209df8bae1dSRodney W. Grimes 		break;
1210df8bae1dSRodney W. Grimes 
1211074c4a4eSGarrett Wollman 	case SIOCSIFPHYS:
121244731cabSJohn Baldwin 		error = suser(td);
1213e39a0280SGary Palmer 		if (error)
1214913e410eSYaroslav Tykhiy 			return (error);
1215913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1216913e410eSYaroslav Tykhiy 			return (EOPNOTSUPP);
121731302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1218e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
121931302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1220e39a0280SGary Palmer 		if (error == 0)
122198b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1222913e410eSYaroslav Tykhiy 		break;
1223074c4a4eSGarrett Wollman 
1224a7028af7SDavid Greenman 	case SIOCSIFMTU:
122582cd038dSYoshinobu Inoue 	{
122682cd038dSYoshinobu Inoue 		u_long oldmtu = ifp->if_mtu;
122782cd038dSYoshinobu Inoue 
122844731cabSJohn Baldwin 		error = suser(td);
12299448326fSPoul-Henning Kamp 		if (error)
1230a7028af7SDavid Greenman 			return (error);
1231aab3beeeSBrian Somers 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
123275ee03cbSDavid Greenman 			return (EINVAL);
1233f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1234f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
123531302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1236e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
123731302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
123848f71763SRuslan Ermilov 		if (error == 0) {
123998b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
124048f71763SRuslan Ermilov 			rt_ifmsg(ifp);
124148f71763SRuslan Ermilov 		}
124282cd038dSYoshinobu Inoue 		/*
124382cd038dSYoshinobu Inoue 		 * If the link MTU changed, do network layer specific procedure.
124482cd038dSYoshinobu Inoue 		 */
124582cd038dSYoshinobu Inoue 		if (ifp->if_mtu != oldmtu) {
124682cd038dSYoshinobu Inoue #ifdef INET6
124782cd038dSYoshinobu Inoue 			nd6_setmtu(ifp);
124882cd038dSYoshinobu Inoue #endif
124982cd038dSYoshinobu Inoue 		}
1250f13ad206SJonathan Lemon 		break;
125182cd038dSYoshinobu Inoue 	}
1252a7028af7SDavid Greenman 
1253df8bae1dSRodney W. Grimes 	case SIOCADDMULTI:
1254df8bae1dSRodney W. Grimes 	case SIOCDELMULTI:
125544731cabSJohn Baldwin 		error = suser(td);
12569448326fSPoul-Henning Kamp 		if (error)
1257df8bae1dSRodney W. Grimes 			return (error);
1258477180fbSGarrett Wollman 
1259477180fbSGarrett Wollman 		/* Don't allow group membership on non-multicast interfaces. */
1260477180fbSGarrett Wollman 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
1261f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
1262477180fbSGarrett Wollman 
1263477180fbSGarrett Wollman 		/* Don't let users screw up protocols' entries. */
1264477180fbSGarrett Wollman 		if (ifr->ifr_addr.sa_family != AF_LINK)
1265f13ad206SJonathan Lemon 			return (EINVAL);
1266477180fbSGarrett Wollman 
1267477180fbSGarrett Wollman 		if (cmd == SIOCADDMULTI) {
1268477180fbSGarrett Wollman 			struct ifmultiaddr *ifma;
1269477180fbSGarrett Wollman 			error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
1270477180fbSGarrett Wollman 		} else {
1271477180fbSGarrett Wollman 			error = if_delmulti(ifp, &ifr->ifr_addr);
1272477180fbSGarrett Wollman 		}
1273e39a0280SGary Palmer 		if (error == 0)
127498b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1275f13ad206SJonathan Lemon 		break;
1276df8bae1dSRodney W. Grimes 
127741b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR:
127841b3e8e5SJun-ichiro itojun Hagino 	case SIOCDIFPHYADDR:
127941b3e8e5SJun-ichiro itojun Hagino #ifdef INET6
128041b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR_IN6:
128141b3e8e5SJun-ichiro itojun Hagino #endif
128233841545SHajimu UMEMOTO 	case SIOCSLIFPHYADDR:
1283a912e453SPeter Wemm 	case SIOCSIFMEDIA:
1284d7189ec6SJoerg Wunsch 	case SIOCSIFGENERIC:
128544731cabSJohn Baldwin 		error = suser(td);
1286a912e453SPeter Wemm 		if (error)
1287a912e453SPeter Wemm 			return (error);
1288f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1289a912e453SPeter Wemm 			return (EOPNOTSUPP);
129031302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1291a912e453SPeter Wemm 		error = (*ifp->if_ioctl)(ifp, cmd, data);
129231302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1293a912e453SPeter Wemm 		if (error == 0)
129498b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1295f13ad206SJonathan Lemon 		break;
1296a912e453SPeter Wemm 
1297413dd0baSPoul-Henning Kamp 	case SIOCGIFSTATUS:
1298413dd0baSPoul-Henning Kamp 		ifs = (struct ifstat *)data;
1299413dd0baSPoul-Henning Kamp 		ifs->ascii[0] = '\0';
1300413dd0baSPoul-Henning Kamp 
130133841545SHajimu UMEMOTO 	case SIOCGIFPSRCADDR:
130233841545SHajimu UMEMOTO 	case SIOCGIFPDSTADDR:
130333841545SHajimu UMEMOTO 	case SIOCGLIFPHYADDR:
1304a912e453SPeter Wemm 	case SIOCGIFMEDIA:
1305d7189ec6SJoerg Wunsch 	case SIOCGIFGENERIC:
1306913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1307a912e453SPeter Wemm 			return (EOPNOTSUPP);
130831302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1309f13ad206SJonathan Lemon 		error = (*ifp->if_ioctl)(ifp, cmd, data);
131031302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1311f13ad206SJonathan Lemon 		break;
1312a912e453SPeter Wemm 
1313b106252cSBill Paul 	case SIOCSIFLLADDR:
131444731cabSJohn Baldwin 		error = suser(td);
1315b106252cSBill Paul 		if (error)
1316b106252cSBill Paul 			return (error);
1317f13ad206SJonathan Lemon 		error = if_setlladdr(ifp,
131866ce51ceSArchie Cobbs 		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
1319f13ad206SJonathan Lemon 		break;
132066ce51ceSArchie Cobbs 
1321df8bae1dSRodney W. Grimes 	default:
1322f13ad206SJonathan Lemon 		error = ENOIOCTL;
1323f13ad206SJonathan Lemon 		break;
1324f13ad206SJonathan Lemon 	}
1325f13ad206SJonathan Lemon 	return (error);
1326f13ad206SJonathan Lemon }
1327f13ad206SJonathan Lemon 
1328f13ad206SJonathan Lemon /*
1329f13ad206SJonathan Lemon  * Interface ioctls.
1330f13ad206SJonathan Lemon  */
1331f13ad206SJonathan Lemon int
133272fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
1333f13ad206SJonathan Lemon {
1334f13ad206SJonathan Lemon 	struct ifnet *ifp;
1335f13ad206SJonathan Lemon 	struct ifreq *ifr;
1336f13ad206SJonathan Lemon 	int error;
133762f76486SMaxim Sobolev 	int oif_flags;
1338f13ad206SJonathan Lemon 
1339f13ad206SJonathan Lemon 	switch (cmd) {
1340f13ad206SJonathan Lemon 	case SIOCGIFCONF:
1341f13ad206SJonathan Lemon 	case OSIOCGIFCONF:
1342f13ad206SJonathan Lemon 		return (ifconf(cmd, data));
1343f13ad206SJonathan Lemon 	}
1344f13ad206SJonathan Lemon 	ifr = (struct ifreq *)data;
1345f13ad206SJonathan Lemon 
1346f13ad206SJonathan Lemon 	switch (cmd) {
1347f13ad206SJonathan Lemon 	case SIOCIFCREATE:
1348f13ad206SJonathan Lemon 	case SIOCIFDESTROY:
134944731cabSJohn Baldwin 		if ((error = suser(td)) != 0)
1350f13ad206SJonathan Lemon 			return (error);
1351f13ad206SJonathan Lemon 		return ((cmd == SIOCIFCREATE) ?
1352f13ad206SJonathan Lemon 			if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) :
1353f13ad206SJonathan Lemon 			if_clone_destroy(ifr->ifr_name));
1354f13ad206SJonathan Lemon 
1355f13ad206SJonathan Lemon 	case SIOCIFGCLONERS:
1356f13ad206SJonathan Lemon 		return (if_clone_list((struct if_clonereq *)data));
1357f13ad206SJonathan Lemon 	}
1358f13ad206SJonathan Lemon 
1359f13ad206SJonathan Lemon 	ifp = ifunit(ifr->ifr_name);
1360f13ad206SJonathan Lemon 	if (ifp == 0)
1361f13ad206SJonathan Lemon 		return (ENXIO);
1362f13ad206SJonathan Lemon 
1363f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
1364f13ad206SJonathan Lemon 	if (error != ENOIOCTL)
1365f13ad206SJonathan Lemon 		return (error);
1366f13ad206SJonathan Lemon 
136782cd038dSYoshinobu Inoue 	oif_flags = ifp->if_flags;
1368df8bae1dSRodney W. Grimes 	if (so->so_proto == 0)
1369df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1370df8bae1dSRodney W. Grimes #ifndef COMPAT_43
137182cd038dSYoshinobu Inoue 	error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
13722c37256eSGarrett Wollman 								 data,
1373b40ce416SJulian Elischer 								 ifp, td));
1374df8bae1dSRodney W. Grimes #else
1375df8bae1dSRodney W. Grimes 	{
1376df8bae1dSRodney W. Grimes 		int ocmd = cmd;
1377df8bae1dSRodney W. Grimes 
1378df8bae1dSRodney W. Grimes 		switch (cmd) {
1379df8bae1dSRodney W. Grimes 
1380df8bae1dSRodney W. Grimes 		case SIOCSIFDSTADDR:
1381df8bae1dSRodney W. Grimes 		case SIOCSIFADDR:
1382df8bae1dSRodney W. Grimes 		case SIOCSIFBRDADDR:
1383df8bae1dSRodney W. Grimes 		case SIOCSIFNETMASK:
1384df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN
1385df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_family == 0 &&
1386df8bae1dSRodney W. Grimes 			    ifr->ifr_addr.sa_len < 16) {
1387df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
1388df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1389df8bae1dSRodney W. Grimes 			}
1390df8bae1dSRodney W. Grimes #else
1391df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_len == 0)
1392df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1393df8bae1dSRodney W. Grimes #endif
1394df8bae1dSRodney W. Grimes 			break;
1395df8bae1dSRodney W. Grimes 
1396df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1397df8bae1dSRodney W. Grimes 			cmd = SIOCGIFADDR;
1398df8bae1dSRodney W. Grimes 			break;
1399df8bae1dSRodney W. Grimes 
1400df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1401df8bae1dSRodney W. Grimes 			cmd = SIOCGIFDSTADDR;
1402df8bae1dSRodney W. Grimes 			break;
1403df8bae1dSRodney W. Grimes 
1404df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1405df8bae1dSRodney W. Grimes 			cmd = SIOCGIFBRDADDR;
1406df8bae1dSRodney W. Grimes 			break;
1407df8bae1dSRodney W. Grimes 
1408df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1409df8bae1dSRodney W. Grimes 			cmd = SIOCGIFNETMASK;
1410df8bae1dSRodney W. Grimes 		}
14112c37256eSGarrett Wollman 		error =  ((*so->so_proto->pr_usrreqs->pru_control)(so,
14122c37256eSGarrett Wollman 								   cmd,
14132c37256eSGarrett Wollman 								   data,
1414b40ce416SJulian Elischer 								   ifp, td));
1415df8bae1dSRodney W. Grimes 		switch (ocmd) {
1416df8bae1dSRodney W. Grimes 
1417df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1418df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1419df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1420df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1421df8bae1dSRodney W. Grimes 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
142282cd038dSYoshinobu Inoue 
142382cd038dSYoshinobu Inoue 		}
142482cd038dSYoshinobu Inoue 	}
142582cd038dSYoshinobu Inoue #endif /* COMPAT_43 */
142682cd038dSYoshinobu Inoue 
142782cd038dSYoshinobu Inoue 	if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
142882cd038dSYoshinobu Inoue #ifdef INET6
142988ff5695SSUZUKI Shinsuke 		DELAY(100);/* XXX: temporary workaround for fxp issue*/
143082cd038dSYoshinobu Inoue 		if (ifp->if_flags & IFF_UP) {
143182cd038dSYoshinobu Inoue 			int s = splimp();
143282cd038dSYoshinobu Inoue 			in6_if_up(ifp);
143382cd038dSYoshinobu Inoue 			splx(s);
143482cd038dSYoshinobu Inoue 		}
143582cd038dSYoshinobu Inoue #endif
1436df8bae1dSRodney W. Grimes 	}
1437df8bae1dSRodney W. Grimes 	return (error);
1438df8bae1dSRodney W. Grimes }
1439df8bae1dSRodney W. Grimes 
1440df8bae1dSRodney W. Grimes /*
1441963e4c2aSGarrett Wollman  * Set/clear promiscuous mode on interface ifp based on the truth value
1442963e4c2aSGarrett Wollman  * of pswitch.  The calls are reference counted so that only the first
1443963e4c2aSGarrett Wollman  * "on" request actually has an effect, as does the final "off" request.
1444963e4c2aSGarrett Wollman  * Results are undefined if the "off" and "on" requests are not matched.
1445963e4c2aSGarrett Wollman  */
1446963e4c2aSGarrett Wollman int
144772fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch)
1448963e4c2aSGarrett Wollman {
1449963e4c2aSGarrett Wollman 	struct ifreq ifr;
14504a26224cSGarrett Wollman 	int error;
14514f3c11a6SBill Fenner 	int oldflags, oldpcount;
1452963e4c2aSGarrett Wollman 
14534f3c11a6SBill Fenner 	oldpcount = ifp->if_pcount;
14542c514a31SBrian Somers 	oldflags = ifp->if_flags;
1455ffb079beSMaxim Sobolev 	if (ifp->if_flags & IFF_PPROMISC) {
1456ffb079beSMaxim Sobolev 		/* Do nothing if device is in permanently promiscuous mode */
1457ffb079beSMaxim Sobolev 		ifp->if_pcount += pswitch ? 1 : -1;
1458ffb079beSMaxim Sobolev 		return (0);
1459ffb079beSMaxim Sobolev 	}
1460963e4c2aSGarrett Wollman 	if (pswitch) {
1461963e4c2aSGarrett Wollman 		/*
1462963e4c2aSGarrett Wollman 		 * If the device is not configured up, we cannot put it in
1463963e4c2aSGarrett Wollman 		 * promiscuous mode.
1464963e4c2aSGarrett Wollman 		 */
1465963e4c2aSGarrett Wollman 		if ((ifp->if_flags & IFF_UP) == 0)
1466963e4c2aSGarrett Wollman 			return (ENETDOWN);
1467963e4c2aSGarrett Wollman 		if (ifp->if_pcount++ != 0)
1468963e4c2aSGarrett Wollman 			return (0);
1469963e4c2aSGarrett Wollman 		ifp->if_flags |= IFF_PROMISC;
1470963e4c2aSGarrett Wollman 	} else {
1471963e4c2aSGarrett Wollman 		if (--ifp->if_pcount > 0)
1472963e4c2aSGarrett Wollman 			return (0);
1473963e4c2aSGarrett Wollman 		ifp->if_flags &= ~IFF_PROMISC;
1474963e4c2aSGarrett Wollman 	}
147562f76486SMaxim Sobolev 	ifr.ifr_flags = ifp->if_flags & 0xffff;
147662f76486SMaxim Sobolev 	ifr.ifr_flagshigh = ifp->if_flags >> 16;
147731302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
14784a26224cSGarrett Wollman 	error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
147931302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
14804f3c11a6SBill Fenner 	if (error == 0) {
14819bf40edeSBrooks Davis 		log(LOG_INFO, "%s: promiscuous mode %s\n",
14829bf40edeSBrooks Davis 		    ifp->if_xname,
14834f3c11a6SBill Fenner 		    (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
14844a26224cSGarrett Wollman 		rt_ifmsg(ifp);
14854f3c11a6SBill Fenner 	} else {
14864f3c11a6SBill Fenner 		ifp->if_pcount = oldpcount;
14872c514a31SBrian Somers 		ifp->if_flags = oldflags;
14884f3c11a6SBill Fenner 	}
14894a26224cSGarrett Wollman 	return error;
1490963e4c2aSGarrett Wollman }
1491963e4c2aSGarrett Wollman 
1492963e4c2aSGarrett Wollman /*
1493df8bae1dSRodney W. Grimes  * Return interface configuration
1494df8bae1dSRodney W. Grimes  * of system.  List may be used
1495df8bae1dSRodney W. Grimes  * in later ioctl's (above) to get
1496df8bae1dSRodney W. Grimes  * other information.
1497df8bae1dSRodney W. Grimes  */
1498df8bae1dSRodney W. Grimes /*ARGSUSED*/
14993bda9f9bSPoul-Henning Kamp static int
150072fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data)
1501df8bae1dSRodney W. Grimes {
15020b59d917SJonathan Lemon 	struct ifconf *ifc = (struct ifconf *)data;
15030b59d917SJonathan Lemon 	struct ifnet *ifp;
15040b59d917SJonathan Lemon 	struct ifaddr *ifa;
15054dcf2bbbSBrooks Davis 	struct ifreq ifr;
15064dcf2bbbSBrooks Davis 	struct sbuf *sb;
15074dcf2bbbSBrooks Davis 	int error, full = 0, valid_len, max_len;
1508df8bae1dSRodney W. Grimes 
15094dcf2bbbSBrooks Davis 	/* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */
15104dcf2bbbSBrooks Davis 	max_len = MAXPHYS - 1;
15114dcf2bbbSBrooks Davis 
15124dcf2bbbSBrooks Davis again:
15134dcf2bbbSBrooks Davis 	if (ifc->ifc_len <= max_len) {
15144dcf2bbbSBrooks Davis 		max_len = ifc->ifc_len;
15154dcf2bbbSBrooks Davis 		full = 1;
15164dcf2bbbSBrooks Davis 	}
15174dcf2bbbSBrooks Davis 	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
15184dcf2bbbSBrooks Davis 	max_len = 0;
15194dcf2bbbSBrooks Davis 	valid_len = 0;
15204dcf2bbbSBrooks Davis 
1521b30a244cSJeffrey Hsu 	IFNET_RLOCK();		/* could sleep XXX */
15220b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
15239bf40edeSBrooks Davis 		int addrs;
15242624cf89SGarrett Wollman 
15259bf40edeSBrooks Davis 		if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name))
15264dcf2bbbSBrooks Davis 		    >= sizeof(ifr.ifr_name))
15274dcf2bbbSBrooks Davis 			return (ENAMETOOLONG);
15282624cf89SGarrett Wollman 
152975c13541SPoul-Henning Kamp 		addrs = 0;
15302defe5cdSJonathan Lemon 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
15312defe5cdSJonathan Lemon 			struct sockaddr *sa = ifa->ifa_addr;
15322defe5cdSJonathan Lemon 
1533a854ed98SJohn Baldwin 			if (jailed(curthread->td_ucred) &&
1534a854ed98SJohn Baldwin 			    prison_if(curthread->td_ucred, sa))
153575c13541SPoul-Henning Kamp 				continue;
153675c13541SPoul-Henning Kamp 			addrs++;
1537df8bae1dSRodney W. Grimes #ifdef COMPAT_43
1538df8bae1dSRodney W. Grimes 			if (cmd == OSIOCGIFCONF) {
1539df8bae1dSRodney W. Grimes 				struct osockaddr *osa =
1540df8bae1dSRodney W. Grimes 					 (struct osockaddr *)&ifr.ifr_addr;
1541df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
1542df8bae1dSRodney W. Grimes 				osa->sa_family = sa->sa_family;
15434dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
15444dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1545df8bae1dSRodney W. Grimes 			} else
1546df8bae1dSRodney W. Grimes #endif
1547df8bae1dSRodney W. Grimes 			if (sa->sa_len <= sizeof(*sa)) {
1548df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
15494dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
15504dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1551df8bae1dSRodney W. Grimes 			} else {
15524dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr,
15534dcf2bbbSBrooks Davis 				    offsetof(struct ifreq, ifr_addr));
15544dcf2bbbSBrooks Davis 				max_len += offsetof(struct ifreq, ifr_addr);
15554dcf2bbbSBrooks Davis 				sbuf_bcat(sb, sa, sa->sa_len);
15564dcf2bbbSBrooks Davis 				max_len += sa->sa_len;
1557df8bae1dSRodney W. Grimes 			}
15584dcf2bbbSBrooks Davis 
15594dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
15604dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
1561df8bae1dSRodney W. Grimes 		}
15624dcf2bbbSBrooks Davis 		if (addrs == 0) {
156375c13541SPoul-Henning Kamp 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
15644dcf2bbbSBrooks Davis 			sbuf_bcat(sb, &ifr, sizeof(ifr));
15654dcf2bbbSBrooks Davis 			max_len += sizeof(ifr);
15664dcf2bbbSBrooks Davis 
15674dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
15684dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
156975c13541SPoul-Henning Kamp 		}
1570df8bae1dSRodney W. Grimes 	}
1571b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
15724dcf2bbbSBrooks Davis 
15734dcf2bbbSBrooks Davis 	/*
15744dcf2bbbSBrooks Davis 	 * If we didn't allocate enough space (uncommon), try again.  If
15754dcf2bbbSBrooks Davis 	 * we have already allocated as much space as we are allowed,
15764dcf2bbbSBrooks Davis 	 * return what we've got.
15774dcf2bbbSBrooks Davis 	 */
15784dcf2bbbSBrooks Davis 	if (valid_len != max_len && !full) {
15794dcf2bbbSBrooks Davis 		sbuf_delete(sb);
15804dcf2bbbSBrooks Davis 		goto again;
15814dcf2bbbSBrooks Davis 	}
15824dcf2bbbSBrooks Davis 
15834dcf2bbbSBrooks Davis 	ifc->ifc_len = valid_len;
15845ed8cedcSBrian Feldman 	sbuf_finish(sb);
15854dcf2bbbSBrooks Davis 	error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len);
15864dcf2bbbSBrooks Davis 	sbuf_delete(sb);
1587df8bae1dSRodney W. Grimes 	return (error);
1588df8bae1dSRodney W. Grimes }
1589df8bae1dSRodney W. Grimes 
15901158dfb7SGarrett Wollman /*
15911158dfb7SGarrett Wollman  * Just like if_promisc(), but for all-multicast-reception mode.
15921158dfb7SGarrett Wollman  */
15931158dfb7SGarrett Wollman int
159472fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch)
15951158dfb7SGarrett Wollman {
15961158dfb7SGarrett Wollman 	int error = 0;
15971158dfb7SGarrett Wollman 	int s = splimp();
1598ee0a4f7eSSUZUKI Shinsuke 	struct ifreq ifr;
15991158dfb7SGarrett Wollman 
16001158dfb7SGarrett Wollman 	if (onswitch) {
16011158dfb7SGarrett Wollman 		if (ifp->if_amcount++ == 0) {
16021158dfb7SGarrett Wollman 			ifp->if_flags |= IFF_ALLMULTI;
160362f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
160462f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
160531302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1606ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
160731302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
16081158dfb7SGarrett Wollman 		}
16091158dfb7SGarrett Wollman 	} else {
16101158dfb7SGarrett Wollman 		if (ifp->if_amcount > 1) {
16111158dfb7SGarrett Wollman 			ifp->if_amcount--;
16121158dfb7SGarrett Wollman 		} else {
16131158dfb7SGarrett Wollman 			ifp->if_amcount = 0;
16141158dfb7SGarrett Wollman 			ifp->if_flags &= ~IFF_ALLMULTI;
161562f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;;
161662f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
161731302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1618ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
161931302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
16201158dfb7SGarrett Wollman 		}
16211158dfb7SGarrett Wollman 	}
16221158dfb7SGarrett Wollman 	splx(s);
16234a26224cSGarrett Wollman 
16244a26224cSGarrett Wollman 	if (error == 0)
16254a26224cSGarrett Wollman 		rt_ifmsg(ifp);
16261158dfb7SGarrett Wollman 	return error;
16271158dfb7SGarrett Wollman }
16281158dfb7SGarrett Wollman 
16291158dfb7SGarrett Wollman /*
16301158dfb7SGarrett Wollman  * Add a multicast listenership to the interface in question.
16311158dfb7SGarrett Wollman  * The link layer provides a routine which converts
16321158dfb7SGarrett Wollman  */
16331158dfb7SGarrett Wollman int
163472fd1b6aSDag-Erling Smørgrav if_addmulti(struct ifnet *ifp, struct sockaddr *sa, struct ifmultiaddr **retifma)
16351158dfb7SGarrett Wollman {
16361158dfb7SGarrett Wollman 	struct sockaddr *llsa, *dupsa;
16371158dfb7SGarrett Wollman 	int error, s;
16381158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
16391158dfb7SGarrett Wollman 
164057af7922SJulian Elischer 	/*
164157af7922SJulian Elischer 	 * If the matching multicast address already exists
164257af7922SJulian Elischer 	 * then don't add a new one, just add a reference
164357af7922SJulian Elischer 	 */
16446817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
164557af7922SJulian Elischer 		if (equal(sa, ifma->ifma_addr)) {
16461158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
164757af7922SJulian Elischer 			if (retifma)
164857af7922SJulian Elischer 				*retifma = ifma;
16491158dfb7SGarrett Wollman 			return 0;
16501158dfb7SGarrett Wollman 		}
165157af7922SJulian Elischer 	}
16521158dfb7SGarrett Wollman 
16531158dfb7SGarrett Wollman 	/*
16541158dfb7SGarrett Wollman 	 * Give the link layer a chance to accept/reject it, and also
16551158dfb7SGarrett Wollman 	 * find out which AF_LINK address this maps to, if it isn't one
16561158dfb7SGarrett Wollman 	 * already.
16571158dfb7SGarrett Wollman 	 */
16581158dfb7SGarrett Wollman 	if (ifp->if_resolvemulti) {
16591158dfb7SGarrett Wollman 		error = ifp->if_resolvemulti(ifp, &llsa, sa);
16601158dfb7SGarrett Wollman 		if (error) return error;
16611158dfb7SGarrett Wollman 	} else {
16621158dfb7SGarrett Wollman 		llsa = 0;
16631158dfb7SGarrett Wollman 	}
16641158dfb7SGarrett Wollman 
1665a163d034SWarner Losh 	MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
1666a163d034SWarner Losh 	MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
16671158dfb7SGarrett Wollman 	bcopy(sa, dupsa, sa->sa_len);
16681158dfb7SGarrett Wollman 
16691158dfb7SGarrett Wollman 	ifma->ifma_addr = dupsa;
16701158dfb7SGarrett Wollman 	ifma->ifma_lladdr = llsa;
16711158dfb7SGarrett Wollman 	ifma->ifma_ifp = ifp;
16721158dfb7SGarrett Wollman 	ifma->ifma_refcount = 1;
1673373f88edSGarrett Wollman 	ifma->ifma_protospec = 0;
1674477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
1675373f88edSGarrett Wollman 
16761158dfb7SGarrett Wollman 	/*
16771158dfb7SGarrett Wollman 	 * Some network interfaces can scan the address list at
16781158dfb7SGarrett Wollman 	 * interrupt time; lock them out.
16791158dfb7SGarrett Wollman 	 */
16801158dfb7SGarrett Wollman 	s = splimp();
16816817526dSPoul-Henning Kamp 	TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
16821158dfb7SGarrett Wollman 	splx(s);
168313990766SJonathan Mini 	if (retifma != NULL)
1684373f88edSGarrett Wollman 		*retifma = ifma;
16851158dfb7SGarrett Wollman 
16861158dfb7SGarrett Wollman 	if (llsa != 0) {
16876817526dSPoul-Henning Kamp 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
16881158dfb7SGarrett Wollman 			if (equal(ifma->ifma_addr, llsa))
16891158dfb7SGarrett Wollman 				break;
16901158dfb7SGarrett Wollman 		}
16911158dfb7SGarrett Wollman 		if (ifma) {
16921158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
16931158dfb7SGarrett Wollman 		} else {
16941158dfb7SGarrett Wollman 			MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
1695a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1696477180fbSGarrett Wollman 			MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
1697a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1698477180fbSGarrett Wollman 			bcopy(llsa, dupsa, llsa->sa_len);
1699477180fbSGarrett Wollman 			ifma->ifma_addr = dupsa;
170089eaef50SHajimu UMEMOTO 			ifma->ifma_lladdr = NULL;
17011158dfb7SGarrett Wollman 			ifma->ifma_ifp = ifp;
17021158dfb7SGarrett Wollman 			ifma->ifma_refcount = 1;
170389eaef50SHajimu UMEMOTO 			ifma->ifma_protospec = 0;
17041158dfb7SGarrett Wollman 			s = splimp();
17056817526dSPoul-Henning Kamp 			TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
17061158dfb7SGarrett Wollman 			splx(s);
17071158dfb7SGarrett Wollman 		}
170857af7922SJulian Elischer 	}
17091158dfb7SGarrett Wollman 	/*
17101158dfb7SGarrett Wollman 	 * We are certain we have added something, so call down to the
17111158dfb7SGarrett Wollman 	 * interface to let them know about it.
17121158dfb7SGarrett Wollman 	 */
17131158dfb7SGarrett Wollman 	s = splimp();
171431302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
17151158dfb7SGarrett Wollman 	ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
171631302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
17171158dfb7SGarrett Wollman 	splx(s);
17181158dfb7SGarrett Wollman 
17191158dfb7SGarrett Wollman 	return 0;
17201158dfb7SGarrett Wollman }
17211158dfb7SGarrett Wollman 
17221158dfb7SGarrett Wollman /*
17231158dfb7SGarrett Wollman  * Remove a reference to a multicast address on this interface.  Yell
17241158dfb7SGarrett Wollman  * if the request does not match an existing membership.
17251158dfb7SGarrett Wollman  */
17261158dfb7SGarrett Wollman int
172772fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
17281158dfb7SGarrett Wollman {
17291158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
17301158dfb7SGarrett Wollman 	int s;
17311158dfb7SGarrett Wollman 
17326817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
17331158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
17341158dfb7SGarrett Wollman 			break;
17351158dfb7SGarrett Wollman 	if (ifma == 0)
17361158dfb7SGarrett Wollman 		return ENOENT;
17371158dfb7SGarrett Wollman 
17381158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
17391158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
17401158dfb7SGarrett Wollman 		return 0;
17411158dfb7SGarrett Wollman 	}
17421158dfb7SGarrett Wollman 
1743477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_DELMADDR, ifma);
17441158dfb7SGarrett Wollman 	sa = ifma->ifma_lladdr;
17451158dfb7SGarrett Wollman 	s = splimp();
17466817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
1747ccb7cc8dSYaroslav Tykhiy 	/*
1748ccb7cc8dSYaroslav Tykhiy 	 * Make sure the interface driver is notified
1749ccb7cc8dSYaroslav Tykhiy 	 * in the case of a link layer mcast group being left.
1750ccb7cc8dSYaroslav Tykhiy 	 */
175131302ebfSRobert Watson 	if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) {
175231302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1753ccb7cc8dSYaroslav Tykhiy 		ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
175431302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
175531302ebfSRobert Watson 	}
17561158dfb7SGarrett Wollman 	splx(s);
17571158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
17581158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
17591158dfb7SGarrett Wollman 	if (sa == 0)
17601158dfb7SGarrett Wollman 		return 0;
17611158dfb7SGarrett Wollman 
17621158dfb7SGarrett Wollman 	/*
17631158dfb7SGarrett Wollman 	 * Now look for the link-layer address which corresponds to
17641158dfb7SGarrett Wollman 	 * this network address.  It had been squirreled away in
17651158dfb7SGarrett Wollman 	 * ifma->ifma_lladdr for this purpose (so we don't have
17661158dfb7SGarrett Wollman 	 * to call ifp->if_resolvemulti() again), and we saved that
17671158dfb7SGarrett Wollman 	 * value in sa above.  If some nasty deleted the
17681158dfb7SGarrett Wollman 	 * link-layer address out from underneath us, we can deal because
17691158dfb7SGarrett Wollman 	 * the address we stored was is not the same as the one which was
17701158dfb7SGarrett Wollman 	 * in the record for the link-layer address.  (So we don't complain
17711158dfb7SGarrett Wollman 	 * in that case.)
17721158dfb7SGarrett Wollman 	 */
17736817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
17741158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
17751158dfb7SGarrett Wollman 			break;
17761158dfb7SGarrett Wollman 	if (ifma == 0)
17771158dfb7SGarrett Wollman 		return 0;
17781158dfb7SGarrett Wollman 
17791158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
17801158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
17811158dfb7SGarrett Wollman 		return 0;
17821158dfb7SGarrett Wollman 	}
17831158dfb7SGarrett Wollman 
17841158dfb7SGarrett Wollman 	s = splimp();
17856817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
178631302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
1787c7323482SBill Paul 	ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
178831302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
17891158dfb7SGarrett Wollman 	splx(s);
17901158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
17911158dfb7SGarrett Wollman 	free(sa, M_IFMADDR);
17921158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
17931158dfb7SGarrett Wollman 
17941158dfb7SGarrett Wollman 	return 0;
17951158dfb7SGarrett Wollman }
17961158dfb7SGarrett Wollman 
179766ce51ceSArchie Cobbs /*
179866ce51ceSArchie Cobbs  * Set the link layer address on an interface.
179966ce51ceSArchie Cobbs  *
180066ce51ceSArchie Cobbs  * At this time we only support certain types of interfaces,
180166ce51ceSArchie Cobbs  * and we don't allow the length of the address to change.
180266ce51ceSArchie Cobbs  */
180366ce51ceSArchie Cobbs int
180466ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
180566ce51ceSArchie Cobbs {
180666ce51ceSArchie Cobbs 	struct sockaddr_dl *sdl;
180766ce51ceSArchie Cobbs 	struct ifaddr *ifa;
1808d637e989SPeter Wemm 	struct ifreq ifr;
180966ce51ceSArchie Cobbs 
1810f9132cebSJonathan Lemon 	ifa = ifaddr_byindex(ifp->if_index);
181166ce51ceSArchie Cobbs 	if (ifa == NULL)
181266ce51ceSArchie Cobbs 		return (EINVAL);
181366ce51ceSArchie Cobbs 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
181466ce51ceSArchie Cobbs 	if (sdl == NULL)
181566ce51ceSArchie Cobbs 		return (EINVAL);
181666ce51ceSArchie Cobbs 	if (len != sdl->sdl_alen)	/* don't allow length to change */
181766ce51ceSArchie Cobbs 		return (EINVAL);
181866ce51ceSArchie Cobbs 	switch (ifp->if_type) {
181966ce51ceSArchie Cobbs 	case IFT_ETHER:			/* these types use struct arpcom */
182066ce51ceSArchie Cobbs 	case IFT_FDDI:
182166ce51ceSArchie Cobbs 	case IFT_XETHER:
182266ce51ceSArchie Cobbs 	case IFT_ISO88025:
1823b7bffa71SYaroslav Tykhiy 	case IFT_L2VLAN:
18243fefbff0SLuigi Rizzo 		bcopy(lladdr, IFP2AC(ifp)->ac_enaddr, len);
18259046571fSLuigi Rizzo 		/*
18269046571fSLuigi Rizzo 		 * XXX We also need to store the lladdr in LLADDR(sdl),
18279046571fSLuigi Rizzo 		 * which is done below. This is a pain because we must
18289046571fSLuigi Rizzo 		 * remember to keep the info in sync.
18299046571fSLuigi Rizzo 		 */
18306cdcc159SMax Khon 		/* FALLTHROUGH */
18316cdcc159SMax Khon 	case IFT_ARCNET:
183266ce51ceSArchie Cobbs 		bcopy(lladdr, LLADDR(sdl), len);
183366ce51ceSArchie Cobbs 		break;
183466ce51ceSArchie Cobbs 	default:
183566ce51ceSArchie Cobbs 		return (ENODEV);
183666ce51ceSArchie Cobbs 	}
183766ce51ceSArchie Cobbs 	/*
183866ce51ceSArchie Cobbs 	 * If the interface is already up, we need
183966ce51ceSArchie Cobbs 	 * to re-init it in order to reprogram its
184066ce51ceSArchie Cobbs 	 * address filter.
184166ce51ceSArchie Cobbs 	 */
184266ce51ceSArchie Cobbs 	if ((ifp->if_flags & IFF_UP) != 0) {
184331302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
184466ce51ceSArchie Cobbs 		ifp->if_flags &= ~IFF_UP;
184562f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
184662f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1847ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
184866ce51ceSArchie Cobbs 		ifp->if_flags |= IFF_UP;
184962f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
185062f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1851ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
185231302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1853b2c08f43SLuigi Rizzo #ifdef INET
1854b2c08f43SLuigi Rizzo 		/*
1855b2c08f43SLuigi Rizzo 		 * Also send gratuitous ARPs to notify other nodes about
1856b2c08f43SLuigi Rizzo 		 * the address change.
1857b2c08f43SLuigi Rizzo 		 */
1858b2c08f43SLuigi Rizzo 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1859b2c08f43SLuigi Rizzo 			if (ifa->ifa_addr != NULL &&
1860b2c08f43SLuigi Rizzo 			    ifa->ifa_addr->sa_family == AF_INET)
1861c0933269SPeter Wemm 				arp_ifinit(ifp, ifa);
1862b2c08f43SLuigi Rizzo 		}
1863b2c08f43SLuigi Rizzo #endif
186466ce51ceSArchie Cobbs 	}
186566ce51ceSArchie Cobbs 	return (0);
186666ce51ceSArchie Cobbs }
186766ce51ceSArchie Cobbs 
1868373f88edSGarrett Wollman struct ifmultiaddr *
186972fd1b6aSDag-Erling Smørgrav ifmaof_ifpforaddr(struct sockaddr *sa, struct ifnet *ifp)
1870373f88edSGarrett Wollman {
1871373f88edSGarrett Wollman 	struct ifmultiaddr *ifma;
1872373f88edSGarrett Wollman 
18736817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
1874373f88edSGarrett Wollman 		if (equal(ifma->ifma_addr, sa))
1875373f88edSGarrett Wollman 			break;
1876373f88edSGarrett Wollman 
1877373f88edSGarrett Wollman 	return ifma;
1878373f88edSGarrett Wollman }
1879373f88edSGarrett Wollman 
18809bf40edeSBrooks Davis /*
18819bf40edeSBrooks Davis  * The name argument must be a pointer to storage which will last as
18829bf40edeSBrooks Davis  * long as the interface does.  For physical devices, the result of
18839bf40edeSBrooks Davis  * device_get_name(dev) is a good choice and for pseudo-devices a
18849bf40edeSBrooks Davis  * static string works well.
18859bf40edeSBrooks Davis  */
18869bf40edeSBrooks Davis void
18879bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit)
18889bf40edeSBrooks Davis {
18899bf40edeSBrooks Davis 	ifp->if_dname = name;
18909bf40edeSBrooks Davis 	ifp->if_dunit = unit;
18919bf40edeSBrooks Davis 	if (unit != IF_DUNIT_NONE)
18929bf40edeSBrooks Davis 		snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit);
18939bf40edeSBrooks Davis 	else
18949bf40edeSBrooks Davis 		strlcpy(ifp->if_xname, name, IFNAMSIZ);
18959bf40edeSBrooks Davis }
18969bf40edeSBrooks Davis 
1897fa882e87SBrooks Davis int
1898fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...)
1899fa882e87SBrooks Davis {
1900fa882e87SBrooks Davis 	va_list ap;
1901fa882e87SBrooks Davis 	int retval;
1902fa882e87SBrooks Davis 
19039bf40edeSBrooks Davis 	retval = printf("%s: ", ifp->if_xname);
1904fa882e87SBrooks Davis 	va_start(ap, fmt);
1905fa882e87SBrooks Davis 	retval += vprintf(fmt, ap);
1906fa882e87SBrooks Davis 	va_end(ap);
1907fa882e87SBrooks Davis 	return (retval);
1908fa882e87SBrooks Davis }
1909fa882e87SBrooks Davis 
1910af5e59bfSRobert Watson /*
1911af5e59bfSRobert Watson  * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot
1912af5e59bfSRobert Watson  * be called without Giant.  However, we often can't acquire the Giant lock
1913af5e59bfSRobert Watson  * at those points; instead, we run it via a task queue that holds Giant via
1914af5e59bfSRobert Watson  * if_start_deferred.
1915af5e59bfSRobert Watson  *
1916af5e59bfSRobert Watson  * XXXRW: We need to make sure that the ifnet isn't fully detached until any
1917af5e59bfSRobert Watson  * outstanding if_start_deferred() tasks that will run after the free.  This
1918af5e59bfSRobert Watson  * probably means waiting in if_detach().
1919af5e59bfSRobert Watson  */
1920af5e59bfSRobert Watson void
1921af5e59bfSRobert Watson if_start(struct ifnet *ifp)
1922af5e59bfSRobert Watson {
1923af5e59bfSRobert Watson 
1924af5e59bfSRobert Watson 	NET_ASSERT_GIANT();
1925af5e59bfSRobert Watson 
1926af5e59bfSRobert Watson 	if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) {
1927af5e59bfSRobert Watson 		if (mtx_owned(&Giant))
1928af5e59bfSRobert Watson 			(*(ifp)->if_start)(ifp);
1929af5e59bfSRobert Watson 		else
1930af5e59bfSRobert Watson 			taskqueue_enqueue(taskqueue_swi_giant,
1931af5e59bfSRobert Watson 			    &ifp->if_starttask);
1932af5e59bfSRobert Watson 	} else
1933af5e59bfSRobert Watson 		(*(ifp)->if_start)(ifp);
1934af5e59bfSRobert Watson }
1935af5e59bfSRobert Watson 
1936af5e59bfSRobert Watson static void
1937af5e59bfSRobert Watson if_start_deferred(void *context, int pending)
1938af5e59bfSRobert Watson {
1939af5e59bfSRobert Watson 	struct ifnet *ifp;
1940af5e59bfSRobert Watson 
1941af5e59bfSRobert Watson 	/*
1942af5e59bfSRobert Watson 	 * This code must be entered with Giant, and should never run if
1943af5e59bfSRobert Watson 	 * we're not running with debug.mpsafenet.
1944af5e59bfSRobert Watson 	 */
1945af5e59bfSRobert Watson 	KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet"));
1946af5e59bfSRobert Watson 	GIANT_REQUIRED;
1947af5e59bfSRobert Watson 
1948af5e59bfSRobert Watson 	ifp = (struct ifnet *)context;
1949af5e59bfSRobert Watson 	(ifp->if_start)(ifp);
1950af5e59bfSRobert Watson }
1951af5e59bfSRobert Watson 
19520b762445SRobert Watson int
19530b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
19540b762445SRobert Watson {
19550b762445SRobert Watson 	int active = 0;
19560b762445SRobert Watson 
19570b762445SRobert Watson 	IF_LOCK(ifq);
19580b762445SRobert Watson 	if (_IF_QFULL(ifq)) {
19590b762445SRobert Watson 		_IF_DROP(ifq);
19600b762445SRobert Watson 		IF_UNLOCK(ifq);
19610b762445SRobert Watson 		m_freem(m);
19620b762445SRobert Watson 		return (0);
19630b762445SRobert Watson 	}
19640b762445SRobert Watson 	if (ifp != NULL) {
19650b762445SRobert Watson 		ifp->if_obytes += m->m_pkthdr.len + adjust;
19660b762445SRobert Watson 		if (m->m_flags & (M_BCAST|M_MCAST))
19670b762445SRobert Watson 			ifp->if_omcasts++;
19680b762445SRobert Watson 		active = ifp->if_flags & IFF_OACTIVE;
19690b762445SRobert Watson 	}
19700b762445SRobert Watson 	_IF_ENQUEUE(ifq, m);
19710b762445SRobert Watson 	IF_UNLOCK(ifq);
19720b762445SRobert Watson 	if (ifp != NULL && !active)
19730b762445SRobert Watson 		if_start(ifp);
19740b762445SRobert Watson 	return (1);
19750b762445SRobert Watson }
19760b762445SRobert Watson 
1977602d513cSGarrett Wollman SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
19782c37256eSGarrett Wollman SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
1979