xref: /freebsd/sys/net/if.c (revision 0b762445b9fb99f380a8295ffbc0afc172e94a75)
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);
447322dcb8dSMax Khon 	ifp->if_broadcastaddr = 0; /* 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 
45431b1bfe1SHajimu UMEMOTO 	if (domains)
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 }
47431b1bfe1SHajimu UMEMOTO SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_FIRST,
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 	}
493234a35c7SHajimu UMEMOTO 	if (ifp->if_afdata_initialized) {
494234a35c7SHajimu UMEMOTO 		IF_AFDATA_UNLOCK(ifp);
495234a35c7SHajimu UMEMOTO 		splx(s);
496234a35c7SHajimu UMEMOTO 		return;
497234a35c7SHajimu UMEMOTO 	}
498234a35c7SHajimu UMEMOTO 	ifp->if_afdata_initialized = 1;
499234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
500234a35c7SHajimu UMEMOTO 
50131b1bfe1SHajimu UMEMOTO 	/* address family dependent data region */
50231b1bfe1SHajimu UMEMOTO 	bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
50331b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
50431b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifattach)
50531b1bfe1SHajimu UMEMOTO 			ifp->if_afdata[dp->dom_family] =
50631b1bfe1SHajimu UMEMOTO 			    (*dp->dom_ifattach)(ifp);
50731b1bfe1SHajimu UMEMOTO 	}
50831b1bfe1SHajimu UMEMOTO 
50931b1bfe1SHajimu UMEMOTO 	splx(s);
51031b1bfe1SHajimu UMEMOTO }
51131b1bfe1SHajimu UMEMOTO 
5126182fdbdSPeter Wemm /*
5136182fdbdSPeter Wemm  * Detach an interface, removing it from the
5146182fdbdSPeter Wemm  * list of "active" interfaces.
5156182fdbdSPeter Wemm  */
5166182fdbdSPeter Wemm void
51772fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp)
5186182fdbdSPeter Wemm {
519212bd869SHajimu UMEMOTO 	struct ifaddr *ifa, *next;
5205500d3beSWarner Losh 	struct radix_node_head	*rnh;
5215500d3beSWarner Losh 	int s;
5225500d3beSWarner Losh 	int i;
52331b1bfe1SHajimu UMEMOTO 	struct domain *dp;
5243f35d515SPeter Pentchev  	struct ifnet *iter;
5253f35d515SPeter Pentchev  	int found;
5266182fdbdSPeter Wemm 
52725a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
5286182fdbdSPeter Wemm 	/*
5296182fdbdSPeter Wemm 	 * Remove routes and flush queues.
5306182fdbdSPeter Wemm 	 */
5315500d3beSWarner Losh 	s = splnet();
5326182fdbdSPeter Wemm 	if_down(ifp);
53302b199f1SMax Laier #ifdef ALTQ
53402b199f1SMax Laier 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
53502b199f1SMax Laier 		altq_disable(&ifp->if_snd);
53602b199f1SMax Laier 	if (ALTQ_IS_ATTACHED(&ifp->if_snd))
53702b199f1SMax Laier 		altq_detach(&ifp->if_snd);
53802b199f1SMax Laier #endif
5396182fdbdSPeter Wemm 
540212bd869SHajimu UMEMOTO 	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = next) {
541212bd869SHajimu UMEMOTO 		next = TAILQ_NEXT(ifa, ifa_link);
542212bd869SHajimu UMEMOTO 
543212bd869SHajimu UMEMOTO 		if (ifa->ifa_addr->sa_family == AF_LINK)
544212bd869SHajimu UMEMOTO 			continue;
5450d0f9d1eSYoshinobu Inoue #ifdef INET
546aa6be122SWarner Losh 		/* XXX: Ugly!! ad hoc just for INET */
547aa6be122SWarner Losh 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
548aa6be122SWarner Losh 			struct ifaliasreq ifr;
549aa6be122SWarner Losh 
550aa6be122SWarner Losh 			bzero(&ifr, sizeof(ifr));
551aa6be122SWarner Losh 			ifr.ifra_addr = *ifa->ifa_addr;
552aa6be122SWarner Losh 			if (ifa->ifa_dstaddr)
553aa6be122SWarner Losh 				ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
554aa6be122SWarner Losh 			if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
555aa6be122SWarner Losh 			    NULL) == 0)
556aa6be122SWarner Losh 				continue;
557aa6be122SWarner Losh 		}
5580d0f9d1eSYoshinobu Inoue #endif /* INET */
5590d0f9d1eSYoshinobu Inoue #ifdef INET6
5600d0f9d1eSYoshinobu Inoue 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
56133841545SHajimu UMEMOTO 			in6_purgeaddr(ifa);
562978ee2edSJun-ichiro itojun Hagino 			/* ifp_addrhead is already updated */
5630d0f9d1eSYoshinobu Inoue 			continue;
5640d0f9d1eSYoshinobu Inoue 		}
5650d0f9d1eSYoshinobu Inoue #endif /* INET6 */
5666182fdbdSPeter Wemm 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
5676182fdbdSPeter Wemm 		IFAFREE(ifa);
5686182fdbdSPeter Wemm 	}
5696182fdbdSPeter Wemm 
57033841545SHajimu UMEMOTO #ifdef INET6
57133841545SHajimu UMEMOTO 	/*
57233841545SHajimu UMEMOTO 	 * Remove all IPv6 kernel structs related to ifp.  This should be done
57333841545SHajimu UMEMOTO 	 * before removing routing entries below, since IPv6 interface direct
57433841545SHajimu UMEMOTO 	 * routes are expected to be removed by the IPv6-specific kernel API.
57533841545SHajimu UMEMOTO 	 * Otherwise, the kernel will detect some inconsistency and bark it.
57633841545SHajimu UMEMOTO 	 */
57733841545SHajimu UMEMOTO 	in6_ifdetach(ifp);
57833841545SHajimu UMEMOTO #endif
579f4247b59SLuigi Rizzo 	/*
580f4247b59SLuigi Rizzo 	 * Remove address from ifindex_table[] and maybe decrement if_index.
581f4247b59SLuigi Rizzo 	 * Clean up all addresses.
582f4247b59SLuigi Rizzo 	 */
583b9907cd4SBrooks Davis 	ifnet_byindex(ifp->if_index) = NULL;
584f4247b59SLuigi Rizzo 	ifaddr_byindex(ifp->if_index) = NULL;
585f4247b59SLuigi Rizzo 	destroy_dev(ifdev_byindex(ifp->if_index));
586f4247b59SLuigi Rizzo 	ifdev_byindex(ifp->if_index) = NULL;
587f4247b59SLuigi Rizzo 
588f4247b59SLuigi Rizzo 	while (if_index > 0 && ifaddr_byindex(if_index) == NULL)
589f4247b59SLuigi Rizzo 		if_index--;
590f4247b59SLuigi Rizzo 
59133841545SHajimu UMEMOTO 
592212bd869SHajimu UMEMOTO 	/* We can now free link ifaddr. */
5933f35d515SPeter Pentchev 	if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
594212bd869SHajimu UMEMOTO 		ifa = TAILQ_FIRST(&ifp->if_addrhead);
595212bd869SHajimu UMEMOTO 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
596212bd869SHajimu UMEMOTO 		IFAFREE(ifa);
5973f35d515SPeter Pentchev 	}
598212bd869SHajimu UMEMOTO 
5995500d3beSWarner Losh 	/*
6005500d3beSWarner Losh 	 * Delete all remaining routes using this interface
6015500d3beSWarner Losh 	 * Unfortuneatly the only way to do this is to slog through
6025500d3beSWarner Losh 	 * the entire routing table looking for routes which point
6035500d3beSWarner Losh 	 * to this interface...oh well...
6045500d3beSWarner Losh 	 */
6055500d3beSWarner Losh 	for (i = 1; i <= AF_MAX; i++) {
6065500d3beSWarner Losh 		if ((rnh = rt_tables[i]) == NULL)
6075500d3beSWarner Losh 			continue;
608956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_LOCK(rnh);
6095500d3beSWarner Losh 		(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
610956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_UNLOCK(rnh);
6115500d3beSWarner Losh 	}
6125500d3beSWarner Losh 
6137b6edd04SRuslan Ermilov 	/* Announce that the interface is gone. */
6147b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
6157b6edd04SRuslan Ermilov 
616234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK(ifp);
61731b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
61831b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
61931b1bfe1SHajimu UMEMOTO 			(*dp->dom_ifdetach)(ifp,
62031b1bfe1SHajimu UMEMOTO 			    ifp->if_afdata[dp->dom_family]);
62131b1bfe1SHajimu UMEMOTO 	}
622234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
62331b1bfe1SHajimu UMEMOTO 
624e70cd263SRobert Watson #ifdef MAC
625e70cd263SRobert Watson 	mac_destroy_ifnet(ifp);
626e70cd263SRobert Watson #endif /* MAC */
627ad3b9257SJohn-Mark Gurney 	KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT);
628ad3b9257SJohn-Mark Gurney 	knlist_clear(&ifp->if_klist, 0);
629ad3b9257SJohn-Mark Gurney 	knlist_destroy(&ifp->if_klist);
630b30a244cSJeffrey Hsu 	IFNET_WLOCK();
6313f35d515SPeter Pentchev  	found = 0;
6323f35d515SPeter Pentchev  	TAILQ_FOREACH(iter, &ifnet, if_link)
6333f35d515SPeter Pentchev  		if (iter == ifp) {
6343f35d515SPeter Pentchev  			found = 1;
6353f35d515SPeter Pentchev  			break;
6363f35d515SPeter Pentchev  		}
6373f35d515SPeter Pentchev  	if (found)
6386182fdbdSPeter Wemm  		TAILQ_REMOVE(&ifnet, ifp, if_link);
639b30a244cSJeffrey Hsu 	IFNET_WUNLOCK();
640df5e1987SJonathan Lemon 	mtx_destroy(&ifp->if_snd.ifq_mtx);
641234a35c7SHajimu UMEMOTO 	IF_AFDATA_DESTROY(ifp);
6425500d3beSWarner Losh 	splx(s);
6435500d3beSWarner Losh }
6445500d3beSWarner Losh 
6455500d3beSWarner Losh /*
6465500d3beSWarner Losh  * Delete Routes for a Network Interface
6475500d3beSWarner Losh  *
6485500d3beSWarner Losh  * Called for each routing entry via the rnh->rnh_walktree() call above
6495500d3beSWarner Losh  * to delete all route entries referencing a detaching network interface.
6505500d3beSWarner Losh  *
6515500d3beSWarner Losh  * Arguments:
6525500d3beSWarner Losh  *	rn	pointer to node in the routing table
6535500d3beSWarner Losh  *	arg	argument passed to rnh->rnh_walktree() - detaching interface
6545500d3beSWarner Losh  *
6555500d3beSWarner Losh  * Returns:
6565500d3beSWarner Losh  *	0	successful
6575500d3beSWarner Losh  *	errno	failed - reason indicated
6585500d3beSWarner Losh  *
6595500d3beSWarner Losh  */
6605500d3beSWarner Losh static int
66172fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg)
6625500d3beSWarner Losh {
6635500d3beSWarner Losh 	struct rtentry	*rt = (struct rtentry *)rn;
6645500d3beSWarner Losh 	struct ifnet	*ifp = arg;
6655500d3beSWarner Losh 	int		err;
6665500d3beSWarner Losh 
6675500d3beSWarner Losh 	if (rt->rt_ifp == ifp) {
6685500d3beSWarner Losh 
6695500d3beSWarner Losh 		/*
6705500d3beSWarner Losh 		 * Protect (sorta) against walktree recursion problems
6715500d3beSWarner Losh 		 * with cloned routes
6725500d3beSWarner Losh 		 */
6735500d3beSWarner Losh 		if ((rt->rt_flags & RTF_UP) == 0)
6745500d3beSWarner Losh 			return (0);
6755500d3beSWarner Losh 
6765500d3beSWarner Losh 		err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
6775500d3beSWarner Losh 				rt_mask(rt), rt->rt_flags,
6785500d3beSWarner Losh 				(struct rtentry **) NULL);
6795500d3beSWarner Losh 		if (err) {
6805500d3beSWarner Losh 			log(LOG_WARNING, "if_rtdel: error %d\n", err);
6815500d3beSWarner Losh 		}
6825500d3beSWarner Losh 	}
6835500d3beSWarner Losh 
6845500d3beSWarner Losh 	return (0);
6856182fdbdSPeter Wemm }
6866182fdbdSPeter Wemm 
687d1dd20beSSam Leffler #define	equal(a1, a2)	(bcmp((a1), (a2), ((a1))->sa_len) == 0)
68819fc74fbSJeffrey Hsu 
68930aad87dSBrooks Davis /*
690df8bae1dSRodney W. Grimes  * Locate an interface based on a complete address.
691df8bae1dSRodney W. Grimes  */
692df8bae1dSRodney W. Grimes /*ARGSUSED*/
693df8bae1dSRodney W. Grimes struct ifaddr *
69472fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr)
695df8bae1dSRodney W. Grimes {
6960b59d917SJonathan Lemon 	struct ifnet *ifp;
6970b59d917SJonathan Lemon 	struct ifaddr *ifa;
698df8bae1dSRodney W. Grimes 
699b30a244cSJeffrey Hsu 	IFNET_RLOCK();
700fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link)
70137d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
702df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
703df8bae1dSRodney W. Grimes 				continue;
704df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr))
7050b59d917SJonathan Lemon 				goto done;
70682cd038dSYoshinobu Inoue 			/* IP6 doesn't have broadcast */
7070b59d917SJonathan Lemon 			if ((ifp->if_flags & IFF_BROADCAST) &&
7080b59d917SJonathan Lemon 			    ifa->ifa_broadaddr &&
70982cd038dSYoshinobu Inoue 			    ifa->ifa_broadaddr->sa_len != 0 &&
710df8bae1dSRodney W. Grimes 			    equal(ifa->ifa_broadaddr, addr))
7110b59d917SJonathan Lemon 				goto done;
7120b59d917SJonathan Lemon 		}
7130b59d917SJonathan Lemon 	ifa = NULL;
7140b59d917SJonathan Lemon done:
715b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
716df8bae1dSRodney W. Grimes 	return (ifa);
717df8bae1dSRodney W. Grimes }
7180b59d917SJonathan Lemon 
719df8bae1dSRodney W. Grimes /*
720df8bae1dSRodney W. Grimes  * Locate the point to point interface with a given destination address.
721df8bae1dSRodney W. Grimes  */
722df8bae1dSRodney W. Grimes /*ARGSUSED*/
723df8bae1dSRodney W. Grimes struct ifaddr *
72472fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr)
725df8bae1dSRodney W. Grimes {
7260b59d917SJonathan Lemon 	struct ifnet *ifp;
7270b59d917SJonathan Lemon 	struct ifaddr *ifa;
728df8bae1dSRodney W. Grimes 
729b30a244cSJeffrey Hsu 	IFNET_RLOCK();
7300b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
7310b59d917SJonathan Lemon 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
7320b59d917SJonathan Lemon 			continue;
73337d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
734df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
735df8bae1dSRodney W. Grimes 				continue;
73655088a1cSDavid Greenman 			if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
7370b59d917SJonathan Lemon 				goto done;
738df8bae1dSRodney W. Grimes 		}
7390b59d917SJonathan Lemon 	}
7400b59d917SJonathan Lemon 	ifa = NULL;
7410b59d917SJonathan Lemon done:
742b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
7430b59d917SJonathan Lemon 	return (ifa);
744df8bae1dSRodney W. Grimes }
745df8bae1dSRodney W. Grimes 
746df8bae1dSRodney W. Grimes /*
747df8bae1dSRodney W. Grimes  * Find an interface on a specific network.  If many, choice
748df8bae1dSRodney W. Grimes  * is most specific found.
749df8bae1dSRodney W. Grimes  */
750df8bae1dSRodney W. Grimes struct ifaddr *
75172fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr)
752df8bae1dSRodney W. Grimes {
75372fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
75472fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
755df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
756df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
757df8bae1dSRodney W. Grimes 	char *addr_data = addr->sa_data, *cplim;
758df8bae1dSRodney W. Grimes 
7597e2a6151SJulian Elischer 	/*
7607e2a6151SJulian Elischer 	 * AF_LINK addresses can be looked up directly by their index number,
7617e2a6151SJulian Elischer 	 * so do that if we can.
7627e2a6151SJulian Elischer 	 */
763df8bae1dSRodney W. Grimes 	if (af == AF_LINK) {
764d1dd20beSSam Leffler 	    struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
765df8bae1dSRodney W. Grimes 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
766f9132cebSJonathan Lemon 		return (ifaddr_byindex(sdl->sdl_index));
767df8bae1dSRodney W. Grimes 	}
7687e2a6151SJulian Elischer 
7697e2a6151SJulian Elischer 	/*
7707e2a6151SJulian Elischer 	 * Scan though each interface, looking for ones that have
7717e2a6151SJulian Elischer 	 * addresses in this address family.
7727e2a6151SJulian Elischer 	 */
773b30a244cSJeffrey Hsu 	IFNET_RLOCK();
774fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
77537d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
77672fd1b6aSDag-Erling Smørgrav 			char *cp, *cp2, *cp3;
777df8bae1dSRodney W. Grimes 
778523a02aaSDavid Greenman 			if (ifa->ifa_addr->sa_family != af)
779df8bae1dSRodney W. Grimes next:				continue;
780c61cd599SHajimu UMEMOTO 			if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) {
7817e2a6151SJulian Elischer 				/*
7827e2a6151SJulian Elischer 				 * This is a bit broken as it doesn't
7837e2a6151SJulian Elischer 				 * take into account that the remote end may
7847e2a6151SJulian Elischer 				 * be a single node in the network we are
7857e2a6151SJulian Elischer 				 * looking for.
7867e2a6151SJulian Elischer 				 * The trouble is that we don't know the
7877e2a6151SJulian Elischer 				 * netmask for the remote end.
7887e2a6151SJulian Elischer 				 */
789fcd6781aSGarrett Wollman 				if (ifa->ifa_dstaddr != 0
790fcd6781aSGarrett Wollman 				    && equal(addr, ifa->ifa_dstaddr))
7910b59d917SJonathan Lemon 					goto done;
7923740e2adSDavid Greenman 			} else {
7937e2a6151SJulian Elischer 				/*
7947ed8f465SJulian Elischer 				 * if we have a special address handler,
7957ed8f465SJulian Elischer 				 * then use it instead of the generic one.
7967ed8f465SJulian Elischer 				 */
7977ed8f465SJulian Elischer 				if (ifa->ifa_claim_addr) {
7980b59d917SJonathan Lemon 					if ((*ifa->ifa_claim_addr)(ifa, addr))
7990b59d917SJonathan Lemon 						goto done;
8007ed8f465SJulian Elischer 					continue;
8017ed8f465SJulian Elischer 				}
8027ed8f465SJulian Elischer 
8037ed8f465SJulian Elischer 				/*
8047e2a6151SJulian Elischer 				 * Scan all the bits in the ifa's address.
8057e2a6151SJulian Elischer 				 * If a bit dissagrees with what we are
8067e2a6151SJulian Elischer 				 * looking for, mask it with the netmask
8077e2a6151SJulian Elischer 				 * to see if it really matters.
8087e2a6151SJulian Elischer 				 * (A byte at a time)
8097e2a6151SJulian Elischer 				 */
810523a02aaSDavid Greenman 				if (ifa->ifa_netmask == 0)
811523a02aaSDavid Greenman 					continue;
812df8bae1dSRodney W. Grimes 				cp = addr_data;
813df8bae1dSRodney W. Grimes 				cp2 = ifa->ifa_addr->sa_data;
814df8bae1dSRodney W. Grimes 				cp3 = ifa->ifa_netmask->sa_data;
8157e2a6151SJulian Elischer 				cplim = ifa->ifa_netmask->sa_len
8167e2a6151SJulian Elischer 					+ (char *)ifa->ifa_netmask;
817df8bae1dSRodney W. Grimes 				while (cp3 < cplim)
818df8bae1dSRodney W. Grimes 					if ((*cp++ ^ *cp2++) & *cp3++)
8197e2a6151SJulian Elischer 						goto next; /* next address! */
8207e2a6151SJulian Elischer 				/*
8217e2a6151SJulian Elischer 				 * If the netmask of what we just found
8227e2a6151SJulian Elischer 				 * is more specific than what we had before
8237e2a6151SJulian Elischer 				 * (if we had one) then remember the new one
8247e2a6151SJulian Elischer 				 * before continuing to search
8257e2a6151SJulian Elischer 				 * for an even better one.
8267e2a6151SJulian Elischer 				 */
827df8bae1dSRodney W. Grimes 				if (ifa_maybe == 0 ||
828df8bae1dSRodney W. Grimes 				    rn_refines((caddr_t)ifa->ifa_netmask,
829df8bae1dSRodney W. Grimes 				    (caddr_t)ifa_maybe->ifa_netmask))
830df8bae1dSRodney W. Grimes 					ifa_maybe = ifa;
831df8bae1dSRodney W. Grimes 			}
832b2af64fdSDavid Greenman 		}
833b2af64fdSDavid Greenman 	}
8340b59d917SJonathan Lemon 	ifa = ifa_maybe;
8350b59d917SJonathan Lemon done:
836b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
8370b59d917SJonathan Lemon 	return (ifa);
838df8bae1dSRodney W. Grimes }
839df8bae1dSRodney W. Grimes 
840df8bae1dSRodney W. Grimes /*
841df8bae1dSRodney W. Grimes  * Find an interface address specific to an interface best matching
842df8bae1dSRodney W. Grimes  * a given address.
843df8bae1dSRodney W. Grimes  */
844df8bae1dSRodney W. Grimes struct ifaddr *
84572fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
846df8bae1dSRodney W. Grimes {
84772fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
84872fd1b6aSDag-Erling Smørgrav 	char *cp, *cp2, *cp3;
84972fd1b6aSDag-Erling Smørgrav 	char *cplim;
850df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = 0;
851df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
852df8bae1dSRodney W. Grimes 
853df8bae1dSRodney W. Grimes 	if (af >= AF_MAX)
854df8bae1dSRodney W. Grimes 		return (0);
85537d40066SPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
856df8bae1dSRodney W. Grimes 		if (ifa->ifa_addr->sa_family != af)
857df8bae1dSRodney W. Grimes 			continue;
858381dd1d2SJulian Elischer 		if (ifa_maybe == 0)
859df8bae1dSRodney W. Grimes 			ifa_maybe = ifa;
860df8bae1dSRodney W. Grimes 		if (ifa->ifa_netmask == 0) {
861df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr) ||
862df8bae1dSRodney W. Grimes 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
8632defe5cdSJonathan Lemon 				goto done;
864df8bae1dSRodney W. Grimes 			continue;
865df8bae1dSRodney W. Grimes 		}
866b2af64fdSDavid Greenman 		if (ifp->if_flags & IFF_POINTOPOINT) {
867b2af64fdSDavid Greenman 			if (equal(addr, ifa->ifa_dstaddr))
868a8637146SJonathan Lemon 				goto done;
8693740e2adSDavid Greenman 		} else {
870df8bae1dSRodney W. Grimes 			cp = addr->sa_data;
871df8bae1dSRodney W. Grimes 			cp2 = ifa->ifa_addr->sa_data;
872df8bae1dSRodney W. Grimes 			cp3 = ifa->ifa_netmask->sa_data;
873df8bae1dSRodney W. Grimes 			cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
874df8bae1dSRodney W. Grimes 			for (; cp3 < cplim; cp3++)
875df8bae1dSRodney W. Grimes 				if ((*cp++ ^ *cp2++) & *cp3)
876df8bae1dSRodney W. Grimes 					break;
877df8bae1dSRodney W. Grimes 			if (cp3 == cplim)
8782defe5cdSJonathan Lemon 				goto done;
879df8bae1dSRodney W. Grimes 		}
880b2af64fdSDavid Greenman 	}
881f9132cebSJonathan Lemon 	ifa = ifa_maybe;
882f9132cebSJonathan Lemon done:
883f9132cebSJonathan Lemon 	return (ifa);
884df8bae1dSRodney W. Grimes }
885df8bae1dSRodney W. Grimes 
886df8bae1dSRodney W. Grimes #include <net/route.h>
887df8bae1dSRodney W. Grimes 
888df8bae1dSRodney W. Grimes /*
889df8bae1dSRodney W. Grimes  * Default action when installing a route with a Link Level gateway.
890df8bae1dSRodney W. Grimes  * Lookup an appropriate real ifa to point to.
891df8bae1dSRodney W. Grimes  * This should be moved to /sys/net/link.c eventually.
892df8bae1dSRodney W. Grimes  */
8933bda9f9bSPoul-Henning Kamp static void
89472fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
895df8bae1dSRodney W. Grimes {
89672fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa, *oifa;
897df8bae1dSRodney W. Grimes 	struct sockaddr *dst;
898df8bae1dSRodney W. Grimes 	struct ifnet *ifp;
899df8bae1dSRodney W. Grimes 
900d1dd20beSSam Leffler 	RT_LOCK_ASSERT(rt);
901d1dd20beSSam Leffler 
902df8bae1dSRodney W. Grimes 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
903df8bae1dSRodney W. Grimes 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
904df8bae1dSRodney W. Grimes 		return;
9059448326fSPoul-Henning Kamp 	ifa = ifaof_ifpforaddr(dst, ifp);
9069448326fSPoul-Henning Kamp 	if (ifa) {
90719fc74fbSJeffrey Hsu 		IFAREF(ifa);		/* XXX */
908d1dd20beSSam Leffler 		oifa = rt->rt_ifa;
909df8bae1dSRodney W. Grimes 		rt->rt_ifa = ifa;
910d1dd20beSSam Leffler 		IFAFREE(oifa);
911df8bae1dSRodney W. Grimes 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
9128071913dSRuslan Ermilov 			ifa->ifa_rtrequest(cmd, rt, info);
913df8bae1dSRodney W. Grimes 	}
914df8bae1dSRodney W. Grimes }
915df8bae1dSRodney W. Grimes 
916df8bae1dSRodney W. Grimes /*
917df8bae1dSRodney W. Grimes  * Mark an interface down and notify protocols of
918df8bae1dSRodney W. Grimes  * the transition.
919df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
920df8bae1dSRodney W. Grimes  */
9218614fb12SMax Laier static void
92272fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam)
923df8bae1dSRodney W. Grimes {
92472fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
925df8bae1dSRodney W. Grimes 
926e8c2601dSPoul-Henning Kamp 	ifp->if_flags &= ~flag;
92798b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
928e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
929e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
930df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
931df8bae1dSRodney W. Grimes 	if_qflush(&ifp->if_snd);
932df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
933df8bae1dSRodney W. Grimes }
934df8bae1dSRodney W. Grimes 
935df8bae1dSRodney W. Grimes /*
936df8bae1dSRodney W. Grimes  * Mark an interface up and notify protocols of
937df8bae1dSRodney W. Grimes  * the transition.
938df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
939df8bae1dSRodney W. Grimes  */
9408614fb12SMax Laier static void
94172fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam)
942df8bae1dSRodney W. Grimes {
94372fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
944df8bae1dSRodney W. Grimes 
945e8c2601dSPoul-Henning Kamp 	ifp->if_flags |= flag;
94698b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
947e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
948e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
949df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFUP, ifa->ifa_addr);
950df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
95182cd038dSYoshinobu Inoue #ifdef INET6
95282cd038dSYoshinobu Inoue 	in6_if_up(ifp);
95382cd038dSYoshinobu Inoue #endif
954df8bae1dSRodney W. Grimes }
955df8bae1dSRodney W. Grimes 
956df8bae1dSRodney W. Grimes /*
957e8c2601dSPoul-Henning Kamp  * Mark an interface down and notify protocols of
958e8c2601dSPoul-Henning Kamp  * the transition.
959e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
960e8c2601dSPoul-Henning Kamp  */
961e8c2601dSPoul-Henning Kamp void
96272fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp)
963e8c2601dSPoul-Henning Kamp {
964e8c2601dSPoul-Henning Kamp 
965e8c2601dSPoul-Henning Kamp 	if_unroute(ifp, IFF_UP, AF_UNSPEC);
966e8c2601dSPoul-Henning Kamp }
967e8c2601dSPoul-Henning Kamp 
968e8c2601dSPoul-Henning Kamp /*
969e8c2601dSPoul-Henning Kamp  * Mark an interface up and notify protocols of
970e8c2601dSPoul-Henning Kamp  * the transition.
971e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
972e8c2601dSPoul-Henning Kamp  */
973e8c2601dSPoul-Henning Kamp void
97472fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp)
975e8c2601dSPoul-Henning Kamp {
976e8c2601dSPoul-Henning Kamp 
977e8c2601dSPoul-Henning Kamp 	if_route(ifp, IFF_UP, AF_UNSPEC);
978e8c2601dSPoul-Henning Kamp }
979e8c2601dSPoul-Henning Kamp 
980e8c2601dSPoul-Henning Kamp /*
981df8bae1dSRodney W. Grimes  * Flush an interface queue.
982df8bae1dSRodney W. Grimes  */
9833bda9f9bSPoul-Henning Kamp static void
98402b199f1SMax Laier if_qflush(struct ifaltq *ifq)
985df8bae1dSRodney W. Grimes {
98672fd1b6aSDag-Erling Smørgrav 	struct mbuf *m, *n;
987df8bae1dSRodney W. Grimes 
9887b21048cSMax Laier 	IFQ_LOCK(ifq);
98902b199f1SMax Laier #ifdef ALTQ
99002b199f1SMax Laier 	if (ALTQ_IS_ENABLED(ifq))
99102b199f1SMax Laier 		ALTQ_PURGE(ifq);
99202b199f1SMax Laier #endif
993df8bae1dSRodney W. Grimes 	n = ifq->ifq_head;
9949448326fSPoul-Henning Kamp 	while ((m = n) != 0) {
995df8bae1dSRodney W. Grimes 		n = m->m_act;
996df8bae1dSRodney W. Grimes 		m_freem(m);
997df8bae1dSRodney W. Grimes 	}
998df8bae1dSRodney W. Grimes 	ifq->ifq_head = 0;
999df8bae1dSRodney W. Grimes 	ifq->ifq_tail = 0;
1000df8bae1dSRodney W. Grimes 	ifq->ifq_len = 0;
10017b21048cSMax Laier 	IFQ_UNLOCK(ifq);
1002df8bae1dSRodney W. Grimes }
1003df8bae1dSRodney W. Grimes 
1004df8bae1dSRodney W. Grimes /*
1005df8bae1dSRodney W. Grimes  * Handle interface watchdog timer routines.  Called
1006df8bae1dSRodney W. Grimes  * from softclock, we decrement timers (if set) and
1007df8bae1dSRodney W. Grimes  * call the appropriate interface routine on expiration.
1008af5e59bfSRobert Watson  *
1009af5e59bfSRobert Watson  * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called
1010af5e59bfSRobert Watson  * holding Giant.  If we switch to an MPSAFE callout, we likely need to grab
1011af5e59bfSRobert Watson  * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface.
1012df8bae1dSRodney W. Grimes  */
10133bda9f9bSPoul-Henning Kamp static void
101472fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg)
1015df8bae1dSRodney W. Grimes {
101672fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
1017df8bae1dSRodney W. Grimes 	int s = splimp();
1018df8bae1dSRodney W. Grimes 
1019b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1020fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1021df8bae1dSRodney W. Grimes 		if (ifp->if_timer == 0 || --ifp->if_timer)
1022df8bae1dSRodney W. Grimes 			continue;
1023df8bae1dSRodney W. Grimes 		if (ifp->if_watchdog)
10244a5f1499SDavid Greenman 			(*ifp->if_watchdog)(ifp);
1025df8bae1dSRodney W. Grimes 	}
1026b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1027df8bae1dSRodney W. Grimes 	splx(s);
1028df8bae1dSRodney W. Grimes 	timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
1029df8bae1dSRodney W. Grimes }
1030df8bae1dSRodney W. Grimes 
1031df8bae1dSRodney W. Grimes /*
1032df8bae1dSRodney W. Grimes  * Map interface name to
1033df8bae1dSRodney W. Grimes  * interface structure pointer.
1034df8bae1dSRodney W. Grimes  */
1035df8bae1dSRodney W. Grimes struct ifnet *
103630aad87dSBrooks Davis ifunit(const char *name)
1037df8bae1dSRodney W. Grimes {
10388b7805e4SBoris Popov 	struct ifnet *ifp;
1039df8bae1dSRodney W. Grimes 
1040b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1041fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
104236c19a57SBrooks Davis 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
1043df8bae1dSRodney W. Grimes 			break;
1044df8bae1dSRodney W. Grimes 	}
1045b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1046df8bae1dSRodney W. Grimes 	return (ifp);
1047df8bae1dSRodney W. Grimes }
1048df8bae1dSRodney W. Grimes 
104982cd038dSYoshinobu Inoue /*
1050f13ad206SJonathan Lemon  * Hardware specific interface ioctls.
1051df8bae1dSRodney W. Grimes  */
1052f13ad206SJonathan Lemon static int
1053f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
1054df8bae1dSRodney W. Grimes {
1055f13ad206SJonathan Lemon 	struct ifreq *ifr;
1056413dd0baSPoul-Henning Kamp 	struct ifstat *ifs;
1057f13ad206SJonathan Lemon 	int error = 0;
105862f76486SMaxim Sobolev 	int new_flags;
105936c19a57SBrooks Davis 	size_t namelen, onamelen;
106036c19a57SBrooks Davis 	char new_name[IFNAMSIZ];
106136c19a57SBrooks Davis 	struct ifaddr *ifa;
106236c19a57SBrooks Davis 	struct sockaddr_dl *sdl;
1063df8bae1dSRodney W. Grimes 
1064df8bae1dSRodney W. Grimes 	ifr = (struct ifreq *)data;
106530aad87dSBrooks Davis 	switch (cmd) {
1066de593450SJonathan Lemon 	case SIOCGIFINDEX:
1067de593450SJonathan Lemon 		ifr->ifr_index = ifp->if_index;
1068de593450SJonathan Lemon 		break;
1069de593450SJonathan Lemon 
1070df8bae1dSRodney W. Grimes 	case SIOCGIFFLAGS:
107162f76486SMaxim Sobolev 		ifr->ifr_flags = ifp->if_flags & 0xffff;
107262f76486SMaxim Sobolev 		ifr->ifr_flagshigh = ifp->if_flags >> 16;
1073df8bae1dSRodney W. Grimes 		break;
1074df8bae1dSRodney W. Grimes 
1075016da741SJonathan Lemon 	case SIOCGIFCAP:
1076016da741SJonathan Lemon 		ifr->ifr_reqcap = ifp->if_capabilities;
1077016da741SJonathan Lemon 		ifr->ifr_curcap = ifp->if_capenable;
1078016da741SJonathan Lemon 		break;
1079016da741SJonathan Lemon 
10808f293a63SRobert Watson #ifdef MAC
10818f293a63SRobert Watson 	case SIOCGIFMAC:
108231566c96SJohn Baldwin 		error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp);
10838f293a63SRobert Watson 		break;
10848f293a63SRobert Watson #endif
10858f293a63SRobert Watson 
1086df8bae1dSRodney W. Grimes 	case SIOCGIFMETRIC:
1087df8bae1dSRodney W. Grimes 		ifr->ifr_metric = ifp->if_metric;
1088df8bae1dSRodney W. Grimes 		break;
1089df8bae1dSRodney W. Grimes 
1090a7028af7SDavid Greenman 	case SIOCGIFMTU:
1091a7028af7SDavid Greenman 		ifr->ifr_mtu = ifp->if_mtu;
1092a7028af7SDavid Greenman 		break;
1093a7028af7SDavid Greenman 
1094074c4a4eSGarrett Wollman 	case SIOCGIFPHYS:
1095074c4a4eSGarrett Wollman 		ifr->ifr_phys = ifp->if_physical;
1096074c4a4eSGarrett Wollman 		break;
1097074c4a4eSGarrett Wollman 
1098df8bae1dSRodney W. Grimes 	case SIOCSIFFLAGS:
109944731cabSJohn Baldwin 		error = suser(td);
11009448326fSPoul-Henning Kamp 		if (error)
1101df8bae1dSRodney W. Grimes 			return (error);
110262f76486SMaxim Sobolev 		new_flags = (ifr->ifr_flags & 0xffff) |
110362f76486SMaxim Sobolev 		    (ifr->ifr_flagshigh << 16);
1104cf4b9371SPoul-Henning Kamp 		if (ifp->if_flags & IFF_SMART) {
1105cf4b9371SPoul-Henning Kamp 			/* Smart drivers twiddle their own routes */
11062f55ead7SPoul-Henning Kamp 		} else if (ifp->if_flags & IFF_UP &&
110762f76486SMaxim Sobolev 		    (new_flags & IFF_UP) == 0) {
1108df8bae1dSRodney W. Grimes 			int s = splimp();
1109df8bae1dSRodney W. Grimes 			if_down(ifp);
1110df8bae1dSRodney W. Grimes 			splx(s);
111162f76486SMaxim Sobolev 		} else if (new_flags & IFF_UP &&
1112cf4b9371SPoul-Henning Kamp 		    (ifp->if_flags & IFF_UP) == 0) {
1113df8bae1dSRodney W. Grimes 			int s = splimp();
1114df8bae1dSRodney W. Grimes 			if_up(ifp);
1115df8bae1dSRodney W. Grimes 			splx(s);
1116df8bae1dSRodney W. Grimes 		}
1117df8bae1dSRodney W. Grimes 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
111862f76486SMaxim Sobolev 			(new_flags &~ IFF_CANTCHANGE);
1119ffb079beSMaxim Sobolev 		if (new_flags & IFF_PPROMISC) {
1120ffb079beSMaxim Sobolev 			/* Permanently promiscuous mode requested */
1121ffb079beSMaxim Sobolev 			ifp->if_flags |= IFF_PROMISC;
1122ffb079beSMaxim Sobolev 		} else if (ifp->if_pcount == 0) {
1123ffb079beSMaxim Sobolev 			ifp->if_flags &= ~IFF_PROMISC;
1124ffb079beSMaxim Sobolev 		}
112531302ebfSRobert Watson 		if (ifp->if_ioctl) {
112631302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1127df8bae1dSRodney W. Grimes 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
112831302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
112931302ebfSRobert Watson 		}
113098b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1131df8bae1dSRodney W. Grimes 		break;
1132df8bae1dSRodney W. Grimes 
1133016da741SJonathan Lemon 	case SIOCSIFCAP:
113444731cabSJohn Baldwin 		error = suser(td);
1135016da741SJonathan Lemon 		if (error)
1136016da741SJonathan Lemon 			return (error);
1137efb4018bSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1138efb4018bSYaroslav Tykhiy 			return (EOPNOTSUPP);
1139016da741SJonathan Lemon 		if (ifr->ifr_reqcap & ~ifp->if_capabilities)
1140016da741SJonathan Lemon 			return (EINVAL);
114131302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1142efb4018bSYaroslav Tykhiy 		error = (*ifp->if_ioctl)(ifp, cmd, data);
114331302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1144efb4018bSYaroslav Tykhiy 		if (error == 0)
1145efb4018bSYaroslav Tykhiy 			getmicrotime(&ifp->if_lastchange);
1146016da741SJonathan Lemon 		break;
1147016da741SJonathan Lemon 
11488f293a63SRobert Watson #ifdef MAC
11498f293a63SRobert Watson 	case SIOCSIFMAC:
115031566c96SJohn Baldwin 		error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp);
11518f293a63SRobert Watson 		break;
11528f293a63SRobert Watson #endif
11538f293a63SRobert Watson 
115436c19a57SBrooks Davis 	case SIOCSIFNAME:
115536c19a57SBrooks Davis 		error = suser(td);
1156bc1470f1SBrooks Davis 		if (error != 0)
115736c19a57SBrooks Davis 			return (error);
115836c19a57SBrooks Davis 		error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL);
1159bc1470f1SBrooks Davis 		if (error != 0)
116036c19a57SBrooks Davis 			return (error);
1161bc1470f1SBrooks Davis 		if (new_name[0] == '\0')
1162bc1470f1SBrooks Davis 			return (EINVAL);
116336c19a57SBrooks Davis 		if (ifunit(new_name) != NULL)
116436c19a57SBrooks Davis 			return (EEXIST);
116536c19a57SBrooks Davis 
116625a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
116736c19a57SBrooks Davis 		/* Announce the departure of the interface. */
116836c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
116936c19a57SBrooks Davis 
117071672bb6SBrooks Davis 		log(LOG_INFO, "%s: changing name to '%s'\n",
117171672bb6SBrooks Davis 		    ifp->if_xname, new_name);
117271672bb6SBrooks Davis 
117336c19a57SBrooks Davis 		strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
11749b98ee2cSLuigi Rizzo 		ifa = ifaddr_byindex(ifp->if_index);
117536c19a57SBrooks Davis 		IFA_LOCK(ifa);
117636c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
117736c19a57SBrooks Davis 		namelen = strlen(new_name);
117836c19a57SBrooks Davis 		onamelen = sdl->sdl_nlen;
117936c19a57SBrooks Davis 		/*
118036c19a57SBrooks Davis 		 * Move the address if needed.  This is safe because we
118136c19a57SBrooks Davis 		 * allocate space for a name of length IFNAMSIZ when we
118236c19a57SBrooks Davis 		 * create this in if_attach().
118336c19a57SBrooks Davis 		 */
118436c19a57SBrooks Davis 		if (namelen != onamelen) {
118536c19a57SBrooks Davis 			bcopy(sdl->sdl_data + onamelen,
118636c19a57SBrooks Davis 			    sdl->sdl_data + namelen, sdl->sdl_alen);
118736c19a57SBrooks Davis 		}
118836c19a57SBrooks Davis 		bcopy(new_name, sdl->sdl_data, namelen);
118936c19a57SBrooks Davis 		sdl->sdl_nlen = namelen;
119036c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_netmask;
119136c19a57SBrooks Davis 		bzero(sdl->sdl_data, onamelen);
119236c19a57SBrooks Davis 		while (namelen != 0)
119336c19a57SBrooks Davis 			sdl->sdl_data[--namelen] = 0xff;
119436c19a57SBrooks Davis 		IFA_UNLOCK(ifa);
119536c19a57SBrooks Davis 
119625a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
119736c19a57SBrooks Davis 		/* Announce the return of the interface. */
119836c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
119936c19a57SBrooks Davis 		break;
120036c19a57SBrooks Davis 
1201df8bae1dSRodney W. Grimes 	case SIOCSIFMETRIC:
120244731cabSJohn Baldwin 		error = suser(td);
12039448326fSPoul-Henning Kamp 		if (error)
1204df8bae1dSRodney W. Grimes 			return (error);
1205df8bae1dSRodney W. Grimes 		ifp->if_metric = ifr->ifr_metric;
120698b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1207df8bae1dSRodney W. Grimes 		break;
1208df8bae1dSRodney W. Grimes 
1209074c4a4eSGarrett Wollman 	case SIOCSIFPHYS:
121044731cabSJohn Baldwin 		error = suser(td);
1211e39a0280SGary Palmer 		if (error)
1212913e410eSYaroslav Tykhiy 			return (error);
1213913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1214913e410eSYaroslav Tykhiy 			return (EOPNOTSUPP);
121531302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1216e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
121731302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1218e39a0280SGary Palmer 		if (error == 0)
121998b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1220913e410eSYaroslav Tykhiy 		break;
1221074c4a4eSGarrett Wollman 
1222a7028af7SDavid Greenman 	case SIOCSIFMTU:
122382cd038dSYoshinobu Inoue 	{
122482cd038dSYoshinobu Inoue 		u_long oldmtu = ifp->if_mtu;
122582cd038dSYoshinobu Inoue 
122644731cabSJohn Baldwin 		error = suser(td);
12279448326fSPoul-Henning Kamp 		if (error)
1228a7028af7SDavid Greenman 			return (error);
1229aab3beeeSBrian Somers 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
123075ee03cbSDavid Greenman 			return (EINVAL);
1231f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1232f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
123331302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1234e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
123531302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
123648f71763SRuslan Ermilov 		if (error == 0) {
123798b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
123848f71763SRuslan Ermilov 			rt_ifmsg(ifp);
123948f71763SRuslan Ermilov 		}
124082cd038dSYoshinobu Inoue 		/*
124182cd038dSYoshinobu Inoue 		 * If the link MTU changed, do network layer specific procedure.
124282cd038dSYoshinobu Inoue 		 */
124382cd038dSYoshinobu Inoue 		if (ifp->if_mtu != oldmtu) {
124482cd038dSYoshinobu Inoue #ifdef INET6
124582cd038dSYoshinobu Inoue 			nd6_setmtu(ifp);
124682cd038dSYoshinobu Inoue #endif
124782cd038dSYoshinobu Inoue 		}
1248f13ad206SJonathan Lemon 		break;
124982cd038dSYoshinobu Inoue 	}
1250a7028af7SDavid Greenman 
1251df8bae1dSRodney W. Grimes 	case SIOCADDMULTI:
1252df8bae1dSRodney W. Grimes 	case SIOCDELMULTI:
125344731cabSJohn Baldwin 		error = suser(td);
12549448326fSPoul-Henning Kamp 		if (error)
1255df8bae1dSRodney W. Grimes 			return (error);
1256477180fbSGarrett Wollman 
1257477180fbSGarrett Wollman 		/* Don't allow group membership on non-multicast interfaces. */
1258477180fbSGarrett Wollman 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
1259f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
1260477180fbSGarrett Wollman 
1261477180fbSGarrett Wollman 		/* Don't let users screw up protocols' entries. */
1262477180fbSGarrett Wollman 		if (ifr->ifr_addr.sa_family != AF_LINK)
1263f13ad206SJonathan Lemon 			return (EINVAL);
1264477180fbSGarrett Wollman 
1265477180fbSGarrett Wollman 		if (cmd == SIOCADDMULTI) {
1266477180fbSGarrett Wollman 			struct ifmultiaddr *ifma;
1267477180fbSGarrett Wollman 			error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
1268477180fbSGarrett Wollman 		} else {
1269477180fbSGarrett Wollman 			error = if_delmulti(ifp, &ifr->ifr_addr);
1270477180fbSGarrett Wollman 		}
1271e39a0280SGary Palmer 		if (error == 0)
127298b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1273f13ad206SJonathan Lemon 		break;
1274df8bae1dSRodney W. Grimes 
127541b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR:
127641b3e8e5SJun-ichiro itojun Hagino 	case SIOCDIFPHYADDR:
127741b3e8e5SJun-ichiro itojun Hagino #ifdef INET6
127841b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR_IN6:
127941b3e8e5SJun-ichiro itojun Hagino #endif
128033841545SHajimu UMEMOTO 	case SIOCSLIFPHYADDR:
1281a912e453SPeter Wemm 	case SIOCSIFMEDIA:
1282d7189ec6SJoerg Wunsch 	case SIOCSIFGENERIC:
128344731cabSJohn Baldwin 		error = suser(td);
1284a912e453SPeter Wemm 		if (error)
1285a912e453SPeter Wemm 			return (error);
1286f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1287a912e453SPeter Wemm 			return (EOPNOTSUPP);
128831302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1289a912e453SPeter Wemm 		error = (*ifp->if_ioctl)(ifp, cmd, data);
129031302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1291a912e453SPeter Wemm 		if (error == 0)
129298b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1293f13ad206SJonathan Lemon 		break;
1294a912e453SPeter Wemm 
1295413dd0baSPoul-Henning Kamp 	case SIOCGIFSTATUS:
1296413dd0baSPoul-Henning Kamp 		ifs = (struct ifstat *)data;
1297413dd0baSPoul-Henning Kamp 		ifs->ascii[0] = '\0';
1298413dd0baSPoul-Henning Kamp 
129933841545SHajimu UMEMOTO 	case SIOCGIFPSRCADDR:
130033841545SHajimu UMEMOTO 	case SIOCGIFPDSTADDR:
130133841545SHajimu UMEMOTO 	case SIOCGLIFPHYADDR:
1302a912e453SPeter Wemm 	case SIOCGIFMEDIA:
1303d7189ec6SJoerg Wunsch 	case SIOCGIFGENERIC:
1304913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1305a912e453SPeter Wemm 			return (EOPNOTSUPP);
130631302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1307f13ad206SJonathan Lemon 		error = (*ifp->if_ioctl)(ifp, cmd, data);
130831302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1309f13ad206SJonathan Lemon 		break;
1310a912e453SPeter Wemm 
1311b106252cSBill Paul 	case SIOCSIFLLADDR:
131244731cabSJohn Baldwin 		error = suser(td);
1313b106252cSBill Paul 		if (error)
1314b106252cSBill Paul 			return (error);
1315f13ad206SJonathan Lemon 		error = if_setlladdr(ifp,
131666ce51ceSArchie Cobbs 		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
1317f13ad206SJonathan Lemon 		break;
131866ce51ceSArchie Cobbs 
1319df8bae1dSRodney W. Grimes 	default:
1320f13ad206SJonathan Lemon 		error = ENOIOCTL;
1321f13ad206SJonathan Lemon 		break;
1322f13ad206SJonathan Lemon 	}
1323f13ad206SJonathan Lemon 	return (error);
1324f13ad206SJonathan Lemon }
1325f13ad206SJonathan Lemon 
1326f13ad206SJonathan Lemon /*
1327f13ad206SJonathan Lemon  * Interface ioctls.
1328f13ad206SJonathan Lemon  */
1329f13ad206SJonathan Lemon int
133072fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
1331f13ad206SJonathan Lemon {
1332f13ad206SJonathan Lemon 	struct ifnet *ifp;
1333f13ad206SJonathan Lemon 	struct ifreq *ifr;
1334f13ad206SJonathan Lemon 	int error;
133562f76486SMaxim Sobolev 	int oif_flags;
1336f13ad206SJonathan Lemon 
1337f13ad206SJonathan Lemon 	switch (cmd) {
1338f13ad206SJonathan Lemon 	case SIOCGIFCONF:
1339f13ad206SJonathan Lemon 	case OSIOCGIFCONF:
1340f13ad206SJonathan Lemon 		return (ifconf(cmd, data));
1341f13ad206SJonathan Lemon 	}
1342f13ad206SJonathan Lemon 	ifr = (struct ifreq *)data;
1343f13ad206SJonathan Lemon 
1344f13ad206SJonathan Lemon 	switch (cmd) {
1345f13ad206SJonathan Lemon 	case SIOCIFCREATE:
1346f13ad206SJonathan Lemon 	case SIOCIFDESTROY:
134744731cabSJohn Baldwin 		if ((error = suser(td)) != 0)
1348f13ad206SJonathan Lemon 			return (error);
1349f13ad206SJonathan Lemon 		return ((cmd == SIOCIFCREATE) ?
1350f13ad206SJonathan Lemon 			if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) :
1351f13ad206SJonathan Lemon 			if_clone_destroy(ifr->ifr_name));
1352f13ad206SJonathan Lemon 
1353f13ad206SJonathan Lemon 	case SIOCIFGCLONERS:
1354f13ad206SJonathan Lemon 		return (if_clone_list((struct if_clonereq *)data));
1355f13ad206SJonathan Lemon 	}
1356f13ad206SJonathan Lemon 
1357f13ad206SJonathan Lemon 	ifp = ifunit(ifr->ifr_name);
1358f13ad206SJonathan Lemon 	if (ifp == 0)
1359f13ad206SJonathan Lemon 		return (ENXIO);
1360f13ad206SJonathan Lemon 
1361f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
1362f13ad206SJonathan Lemon 	if (error != ENOIOCTL)
1363f13ad206SJonathan Lemon 		return (error);
1364f13ad206SJonathan Lemon 
136582cd038dSYoshinobu Inoue 	oif_flags = ifp->if_flags;
1366df8bae1dSRodney W. Grimes 	if (so->so_proto == 0)
1367df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1368df8bae1dSRodney W. Grimes #ifndef COMPAT_43
136982cd038dSYoshinobu Inoue 	error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
13702c37256eSGarrett Wollman 								 data,
1371b40ce416SJulian Elischer 								 ifp, td));
1372df8bae1dSRodney W. Grimes #else
1373df8bae1dSRodney W. Grimes 	{
1374df8bae1dSRodney W. Grimes 		int ocmd = cmd;
1375df8bae1dSRodney W. Grimes 
1376df8bae1dSRodney W. Grimes 		switch (cmd) {
1377df8bae1dSRodney W. Grimes 
1378df8bae1dSRodney W. Grimes 		case SIOCSIFDSTADDR:
1379df8bae1dSRodney W. Grimes 		case SIOCSIFADDR:
1380df8bae1dSRodney W. Grimes 		case SIOCSIFBRDADDR:
1381df8bae1dSRodney W. Grimes 		case SIOCSIFNETMASK:
1382df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN
1383df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_family == 0 &&
1384df8bae1dSRodney W. Grimes 			    ifr->ifr_addr.sa_len < 16) {
1385df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
1386df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1387df8bae1dSRodney W. Grimes 			}
1388df8bae1dSRodney W. Grimes #else
1389df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_len == 0)
1390df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1391df8bae1dSRodney W. Grimes #endif
1392df8bae1dSRodney W. Grimes 			break;
1393df8bae1dSRodney W. Grimes 
1394df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1395df8bae1dSRodney W. Grimes 			cmd = SIOCGIFADDR;
1396df8bae1dSRodney W. Grimes 			break;
1397df8bae1dSRodney W. Grimes 
1398df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1399df8bae1dSRodney W. Grimes 			cmd = SIOCGIFDSTADDR;
1400df8bae1dSRodney W. Grimes 			break;
1401df8bae1dSRodney W. Grimes 
1402df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1403df8bae1dSRodney W. Grimes 			cmd = SIOCGIFBRDADDR;
1404df8bae1dSRodney W. Grimes 			break;
1405df8bae1dSRodney W. Grimes 
1406df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1407df8bae1dSRodney W. Grimes 			cmd = SIOCGIFNETMASK;
1408df8bae1dSRodney W. Grimes 		}
14092c37256eSGarrett Wollman 		error =  ((*so->so_proto->pr_usrreqs->pru_control)(so,
14102c37256eSGarrett Wollman 								   cmd,
14112c37256eSGarrett Wollman 								   data,
1412b40ce416SJulian Elischer 								   ifp, td));
1413df8bae1dSRodney W. Grimes 		switch (ocmd) {
1414df8bae1dSRodney W. Grimes 
1415df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1416df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1417df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1418df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1419df8bae1dSRodney W. Grimes 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
142082cd038dSYoshinobu Inoue 
142182cd038dSYoshinobu Inoue 		}
142282cd038dSYoshinobu Inoue 	}
142382cd038dSYoshinobu Inoue #endif /* COMPAT_43 */
142482cd038dSYoshinobu Inoue 
142582cd038dSYoshinobu Inoue 	if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
142682cd038dSYoshinobu Inoue #ifdef INET6
142788ff5695SSUZUKI Shinsuke 		DELAY(100);/* XXX: temporary workaround for fxp issue*/
142882cd038dSYoshinobu Inoue 		if (ifp->if_flags & IFF_UP) {
142982cd038dSYoshinobu Inoue 			int s = splimp();
143082cd038dSYoshinobu Inoue 			in6_if_up(ifp);
143182cd038dSYoshinobu Inoue 			splx(s);
143282cd038dSYoshinobu Inoue 		}
143382cd038dSYoshinobu Inoue #endif
1434df8bae1dSRodney W. Grimes 	}
1435df8bae1dSRodney W. Grimes 	return (error);
1436df8bae1dSRodney W. Grimes }
1437df8bae1dSRodney W. Grimes 
1438df8bae1dSRodney W. Grimes /*
1439963e4c2aSGarrett Wollman  * Set/clear promiscuous mode on interface ifp based on the truth value
1440963e4c2aSGarrett Wollman  * of pswitch.  The calls are reference counted so that only the first
1441963e4c2aSGarrett Wollman  * "on" request actually has an effect, as does the final "off" request.
1442963e4c2aSGarrett Wollman  * Results are undefined if the "off" and "on" requests are not matched.
1443963e4c2aSGarrett Wollman  */
1444963e4c2aSGarrett Wollman int
144572fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch)
1446963e4c2aSGarrett Wollman {
1447963e4c2aSGarrett Wollman 	struct ifreq ifr;
14484a26224cSGarrett Wollman 	int error;
14494f3c11a6SBill Fenner 	int oldflags, oldpcount;
1450963e4c2aSGarrett Wollman 
14514f3c11a6SBill Fenner 	oldpcount = ifp->if_pcount;
14522c514a31SBrian Somers 	oldflags = ifp->if_flags;
1453ffb079beSMaxim Sobolev 	if (ifp->if_flags & IFF_PPROMISC) {
1454ffb079beSMaxim Sobolev 		/* Do nothing if device is in permanently promiscuous mode */
1455ffb079beSMaxim Sobolev 		ifp->if_pcount += pswitch ? 1 : -1;
1456ffb079beSMaxim Sobolev 		return (0);
1457ffb079beSMaxim Sobolev 	}
1458963e4c2aSGarrett Wollman 	if (pswitch) {
1459963e4c2aSGarrett Wollman 		/*
1460963e4c2aSGarrett Wollman 		 * If the device is not configured up, we cannot put it in
1461963e4c2aSGarrett Wollman 		 * promiscuous mode.
1462963e4c2aSGarrett Wollman 		 */
1463963e4c2aSGarrett Wollman 		if ((ifp->if_flags & IFF_UP) == 0)
1464963e4c2aSGarrett Wollman 			return (ENETDOWN);
1465963e4c2aSGarrett Wollman 		if (ifp->if_pcount++ != 0)
1466963e4c2aSGarrett Wollman 			return (0);
1467963e4c2aSGarrett Wollman 		ifp->if_flags |= IFF_PROMISC;
1468963e4c2aSGarrett Wollman 	} else {
1469963e4c2aSGarrett Wollman 		if (--ifp->if_pcount > 0)
1470963e4c2aSGarrett Wollman 			return (0);
1471963e4c2aSGarrett Wollman 		ifp->if_flags &= ~IFF_PROMISC;
1472963e4c2aSGarrett Wollman 	}
147362f76486SMaxim Sobolev 	ifr.ifr_flags = ifp->if_flags & 0xffff;
147462f76486SMaxim Sobolev 	ifr.ifr_flagshigh = ifp->if_flags >> 16;
147531302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
14764a26224cSGarrett Wollman 	error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
147731302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
14784f3c11a6SBill Fenner 	if (error == 0) {
14799bf40edeSBrooks Davis 		log(LOG_INFO, "%s: promiscuous mode %s\n",
14809bf40edeSBrooks Davis 		    ifp->if_xname,
14814f3c11a6SBill Fenner 		    (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
14824a26224cSGarrett Wollman 		rt_ifmsg(ifp);
14834f3c11a6SBill Fenner 	} else {
14844f3c11a6SBill Fenner 		ifp->if_pcount = oldpcount;
14852c514a31SBrian Somers 		ifp->if_flags = oldflags;
14864f3c11a6SBill Fenner 	}
14874a26224cSGarrett Wollman 	return error;
1488963e4c2aSGarrett Wollman }
1489963e4c2aSGarrett Wollman 
1490963e4c2aSGarrett Wollman /*
1491df8bae1dSRodney W. Grimes  * Return interface configuration
1492df8bae1dSRodney W. Grimes  * of system.  List may be used
1493df8bae1dSRodney W. Grimes  * in later ioctl's (above) to get
1494df8bae1dSRodney W. Grimes  * other information.
1495df8bae1dSRodney W. Grimes  */
1496df8bae1dSRodney W. Grimes /*ARGSUSED*/
14973bda9f9bSPoul-Henning Kamp static int
149872fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data)
1499df8bae1dSRodney W. Grimes {
15000b59d917SJonathan Lemon 	struct ifconf *ifc = (struct ifconf *)data;
15010b59d917SJonathan Lemon 	struct ifnet *ifp;
15020b59d917SJonathan Lemon 	struct ifaddr *ifa;
15034dcf2bbbSBrooks Davis 	struct ifreq ifr;
15044dcf2bbbSBrooks Davis 	struct sbuf *sb;
15054dcf2bbbSBrooks Davis 	int error, full = 0, valid_len, max_len;
1506df8bae1dSRodney W. Grimes 
15074dcf2bbbSBrooks Davis 	/* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */
15084dcf2bbbSBrooks Davis 	max_len = MAXPHYS - 1;
15094dcf2bbbSBrooks Davis 
15104dcf2bbbSBrooks Davis again:
15114dcf2bbbSBrooks Davis 	if (ifc->ifc_len <= max_len) {
15124dcf2bbbSBrooks Davis 		max_len = ifc->ifc_len;
15134dcf2bbbSBrooks Davis 		full = 1;
15144dcf2bbbSBrooks Davis 	}
15154dcf2bbbSBrooks Davis 	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
15164dcf2bbbSBrooks Davis 	max_len = 0;
15174dcf2bbbSBrooks Davis 	valid_len = 0;
15184dcf2bbbSBrooks Davis 
1519b30a244cSJeffrey Hsu 	IFNET_RLOCK();		/* could sleep XXX */
15200b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
15219bf40edeSBrooks Davis 		int addrs;
15222624cf89SGarrett Wollman 
15239bf40edeSBrooks Davis 		if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name))
15244dcf2bbbSBrooks Davis 		    >= sizeof(ifr.ifr_name))
15254dcf2bbbSBrooks Davis 			return (ENAMETOOLONG);
15262624cf89SGarrett Wollman 
152775c13541SPoul-Henning Kamp 		addrs = 0;
15282defe5cdSJonathan Lemon 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
15292defe5cdSJonathan Lemon 			struct sockaddr *sa = ifa->ifa_addr;
15302defe5cdSJonathan Lemon 
1531a854ed98SJohn Baldwin 			if (jailed(curthread->td_ucred) &&
1532a854ed98SJohn Baldwin 			    prison_if(curthread->td_ucred, sa))
153375c13541SPoul-Henning Kamp 				continue;
153475c13541SPoul-Henning Kamp 			addrs++;
1535df8bae1dSRodney W. Grimes #ifdef COMPAT_43
1536df8bae1dSRodney W. Grimes 			if (cmd == OSIOCGIFCONF) {
1537df8bae1dSRodney W. Grimes 				struct osockaddr *osa =
1538df8bae1dSRodney W. Grimes 					 (struct osockaddr *)&ifr.ifr_addr;
1539df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
1540df8bae1dSRodney W. Grimes 				osa->sa_family = sa->sa_family;
15414dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
15424dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1543df8bae1dSRodney W. Grimes 			} else
1544df8bae1dSRodney W. Grimes #endif
1545df8bae1dSRodney W. Grimes 			if (sa->sa_len <= sizeof(*sa)) {
1546df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
15474dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
15484dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1549df8bae1dSRodney W. Grimes 			} else {
15504dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr,
15514dcf2bbbSBrooks Davis 				    offsetof(struct ifreq, ifr_addr));
15524dcf2bbbSBrooks Davis 				max_len += offsetof(struct ifreq, ifr_addr);
15534dcf2bbbSBrooks Davis 				sbuf_bcat(sb, sa, sa->sa_len);
15544dcf2bbbSBrooks Davis 				max_len += sa->sa_len;
1555df8bae1dSRodney W. Grimes 			}
15564dcf2bbbSBrooks Davis 
15574dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
15584dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
1559df8bae1dSRodney W. Grimes 		}
15604dcf2bbbSBrooks Davis 		if (addrs == 0) {
156175c13541SPoul-Henning Kamp 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
15624dcf2bbbSBrooks Davis 			sbuf_bcat(sb, &ifr, sizeof(ifr));
15634dcf2bbbSBrooks Davis 			max_len += sizeof(ifr);
15644dcf2bbbSBrooks Davis 
15654dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
15664dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
156775c13541SPoul-Henning Kamp 		}
1568df8bae1dSRodney W. Grimes 	}
1569b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
15704dcf2bbbSBrooks Davis 
15714dcf2bbbSBrooks Davis 	/*
15724dcf2bbbSBrooks Davis 	 * If we didn't allocate enough space (uncommon), try again.  If
15734dcf2bbbSBrooks Davis 	 * we have already allocated as much space as we are allowed,
15744dcf2bbbSBrooks Davis 	 * return what we've got.
15754dcf2bbbSBrooks Davis 	 */
15764dcf2bbbSBrooks Davis 	if (valid_len != max_len && !full) {
15774dcf2bbbSBrooks Davis 		sbuf_delete(sb);
15784dcf2bbbSBrooks Davis 		goto again;
15794dcf2bbbSBrooks Davis 	}
15804dcf2bbbSBrooks Davis 
15814dcf2bbbSBrooks Davis 	ifc->ifc_len = valid_len;
15825ed8cedcSBrian Feldman 	sbuf_finish(sb);
15834dcf2bbbSBrooks Davis 	error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len);
15844dcf2bbbSBrooks Davis 	sbuf_delete(sb);
1585df8bae1dSRodney W. Grimes 	return (error);
1586df8bae1dSRodney W. Grimes }
1587df8bae1dSRodney W. Grimes 
15881158dfb7SGarrett Wollman /*
15891158dfb7SGarrett Wollman  * Just like if_promisc(), but for all-multicast-reception mode.
15901158dfb7SGarrett Wollman  */
15911158dfb7SGarrett Wollman int
159272fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch)
15931158dfb7SGarrett Wollman {
15941158dfb7SGarrett Wollman 	int error = 0;
15951158dfb7SGarrett Wollman 	int s = splimp();
1596ee0a4f7eSSUZUKI Shinsuke 	struct ifreq ifr;
15971158dfb7SGarrett Wollman 
15981158dfb7SGarrett Wollman 	if (onswitch) {
15991158dfb7SGarrett Wollman 		if (ifp->if_amcount++ == 0) {
16001158dfb7SGarrett Wollman 			ifp->if_flags |= IFF_ALLMULTI;
160162f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
160262f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
160331302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1604ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
160531302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
16061158dfb7SGarrett Wollman 		}
16071158dfb7SGarrett Wollman 	} else {
16081158dfb7SGarrett Wollman 		if (ifp->if_amcount > 1) {
16091158dfb7SGarrett Wollman 			ifp->if_amcount--;
16101158dfb7SGarrett Wollman 		} else {
16111158dfb7SGarrett Wollman 			ifp->if_amcount = 0;
16121158dfb7SGarrett Wollman 			ifp->if_flags &= ~IFF_ALLMULTI;
161362f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;;
161462f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
161531302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1616ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
161731302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
16181158dfb7SGarrett Wollman 		}
16191158dfb7SGarrett Wollman 	}
16201158dfb7SGarrett Wollman 	splx(s);
16214a26224cSGarrett Wollman 
16224a26224cSGarrett Wollman 	if (error == 0)
16234a26224cSGarrett Wollman 		rt_ifmsg(ifp);
16241158dfb7SGarrett Wollman 	return error;
16251158dfb7SGarrett Wollman }
16261158dfb7SGarrett Wollman 
16271158dfb7SGarrett Wollman /*
16281158dfb7SGarrett Wollman  * Add a multicast listenership to the interface in question.
16291158dfb7SGarrett Wollman  * The link layer provides a routine which converts
16301158dfb7SGarrett Wollman  */
16311158dfb7SGarrett Wollman int
163272fd1b6aSDag-Erling Smørgrav if_addmulti(struct ifnet *ifp, struct sockaddr *sa, struct ifmultiaddr **retifma)
16331158dfb7SGarrett Wollman {
16341158dfb7SGarrett Wollman 	struct sockaddr *llsa, *dupsa;
16351158dfb7SGarrett Wollman 	int error, s;
16361158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
16371158dfb7SGarrett Wollman 
163857af7922SJulian Elischer 	/*
163957af7922SJulian Elischer 	 * If the matching multicast address already exists
164057af7922SJulian Elischer 	 * then don't add a new one, just add a reference
164157af7922SJulian Elischer 	 */
16426817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
164357af7922SJulian Elischer 		if (equal(sa, ifma->ifma_addr)) {
16441158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
164557af7922SJulian Elischer 			if (retifma)
164657af7922SJulian Elischer 				*retifma = ifma;
16471158dfb7SGarrett Wollman 			return 0;
16481158dfb7SGarrett Wollman 		}
164957af7922SJulian Elischer 	}
16501158dfb7SGarrett Wollman 
16511158dfb7SGarrett Wollman 	/*
16521158dfb7SGarrett Wollman 	 * Give the link layer a chance to accept/reject it, and also
16531158dfb7SGarrett Wollman 	 * find out which AF_LINK address this maps to, if it isn't one
16541158dfb7SGarrett Wollman 	 * already.
16551158dfb7SGarrett Wollman 	 */
16561158dfb7SGarrett Wollman 	if (ifp->if_resolvemulti) {
16571158dfb7SGarrett Wollman 		error = ifp->if_resolvemulti(ifp, &llsa, sa);
16581158dfb7SGarrett Wollman 		if (error) return error;
16591158dfb7SGarrett Wollman 	} else {
16601158dfb7SGarrett Wollman 		llsa = 0;
16611158dfb7SGarrett Wollman 	}
16621158dfb7SGarrett Wollman 
1663a163d034SWarner Losh 	MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
1664a163d034SWarner Losh 	MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
16651158dfb7SGarrett Wollman 	bcopy(sa, dupsa, sa->sa_len);
16661158dfb7SGarrett Wollman 
16671158dfb7SGarrett Wollman 	ifma->ifma_addr = dupsa;
16681158dfb7SGarrett Wollman 	ifma->ifma_lladdr = llsa;
16691158dfb7SGarrett Wollman 	ifma->ifma_ifp = ifp;
16701158dfb7SGarrett Wollman 	ifma->ifma_refcount = 1;
1671373f88edSGarrett Wollman 	ifma->ifma_protospec = 0;
1672477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
1673373f88edSGarrett Wollman 
16741158dfb7SGarrett Wollman 	/*
16751158dfb7SGarrett Wollman 	 * Some network interfaces can scan the address list at
16761158dfb7SGarrett Wollman 	 * interrupt time; lock them out.
16771158dfb7SGarrett Wollman 	 */
16781158dfb7SGarrett Wollman 	s = splimp();
16796817526dSPoul-Henning Kamp 	TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
16801158dfb7SGarrett Wollman 	splx(s);
168113990766SJonathan Mini 	if (retifma != NULL)
1682373f88edSGarrett Wollman 		*retifma = ifma;
16831158dfb7SGarrett Wollman 
16841158dfb7SGarrett Wollman 	if (llsa != 0) {
16856817526dSPoul-Henning Kamp 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
16861158dfb7SGarrett Wollman 			if (equal(ifma->ifma_addr, llsa))
16871158dfb7SGarrett Wollman 				break;
16881158dfb7SGarrett Wollman 		}
16891158dfb7SGarrett Wollman 		if (ifma) {
16901158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
16911158dfb7SGarrett Wollman 		} else {
16921158dfb7SGarrett Wollman 			MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
1693a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1694477180fbSGarrett Wollman 			MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
1695a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1696477180fbSGarrett Wollman 			bcopy(llsa, dupsa, llsa->sa_len);
1697477180fbSGarrett Wollman 			ifma->ifma_addr = dupsa;
169889eaef50SHajimu UMEMOTO 			ifma->ifma_lladdr = NULL;
16991158dfb7SGarrett Wollman 			ifma->ifma_ifp = ifp;
17001158dfb7SGarrett Wollman 			ifma->ifma_refcount = 1;
170189eaef50SHajimu UMEMOTO 			ifma->ifma_protospec = 0;
17021158dfb7SGarrett Wollman 			s = splimp();
17036817526dSPoul-Henning Kamp 			TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
17041158dfb7SGarrett Wollman 			splx(s);
17051158dfb7SGarrett Wollman 		}
170657af7922SJulian Elischer 	}
17071158dfb7SGarrett Wollman 	/*
17081158dfb7SGarrett Wollman 	 * We are certain we have added something, so call down to the
17091158dfb7SGarrett Wollman 	 * interface to let them know about it.
17101158dfb7SGarrett Wollman 	 */
17111158dfb7SGarrett Wollman 	s = splimp();
171231302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
17131158dfb7SGarrett Wollman 	ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
171431302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
17151158dfb7SGarrett Wollman 	splx(s);
17161158dfb7SGarrett Wollman 
17171158dfb7SGarrett Wollman 	return 0;
17181158dfb7SGarrett Wollman }
17191158dfb7SGarrett Wollman 
17201158dfb7SGarrett Wollman /*
17211158dfb7SGarrett Wollman  * Remove a reference to a multicast address on this interface.  Yell
17221158dfb7SGarrett Wollman  * if the request does not match an existing membership.
17231158dfb7SGarrett Wollman  */
17241158dfb7SGarrett Wollman int
172572fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
17261158dfb7SGarrett Wollman {
17271158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
17281158dfb7SGarrett Wollman 	int s;
17291158dfb7SGarrett Wollman 
17306817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
17311158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
17321158dfb7SGarrett Wollman 			break;
17331158dfb7SGarrett Wollman 	if (ifma == 0)
17341158dfb7SGarrett Wollman 		return ENOENT;
17351158dfb7SGarrett Wollman 
17361158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
17371158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
17381158dfb7SGarrett Wollman 		return 0;
17391158dfb7SGarrett Wollman 	}
17401158dfb7SGarrett Wollman 
1741477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_DELMADDR, ifma);
17421158dfb7SGarrett Wollman 	sa = ifma->ifma_lladdr;
17431158dfb7SGarrett Wollman 	s = splimp();
17446817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
1745ccb7cc8dSYaroslav Tykhiy 	/*
1746ccb7cc8dSYaroslav Tykhiy 	 * Make sure the interface driver is notified
1747ccb7cc8dSYaroslav Tykhiy 	 * in the case of a link layer mcast group being left.
1748ccb7cc8dSYaroslav Tykhiy 	 */
174931302ebfSRobert Watson 	if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) {
175031302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1751ccb7cc8dSYaroslav Tykhiy 		ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
175231302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
175331302ebfSRobert Watson 	}
17541158dfb7SGarrett Wollman 	splx(s);
17551158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
17561158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
17571158dfb7SGarrett Wollman 	if (sa == 0)
17581158dfb7SGarrett Wollman 		return 0;
17591158dfb7SGarrett Wollman 
17601158dfb7SGarrett Wollman 	/*
17611158dfb7SGarrett Wollman 	 * Now look for the link-layer address which corresponds to
17621158dfb7SGarrett Wollman 	 * this network address.  It had been squirreled away in
17631158dfb7SGarrett Wollman 	 * ifma->ifma_lladdr for this purpose (so we don't have
17641158dfb7SGarrett Wollman 	 * to call ifp->if_resolvemulti() again), and we saved that
17651158dfb7SGarrett Wollman 	 * value in sa above.  If some nasty deleted the
17661158dfb7SGarrett Wollman 	 * link-layer address out from underneath us, we can deal because
17671158dfb7SGarrett Wollman 	 * the address we stored was is not the same as the one which was
17681158dfb7SGarrett Wollman 	 * in the record for the link-layer address.  (So we don't complain
17691158dfb7SGarrett Wollman 	 * in that case.)
17701158dfb7SGarrett Wollman 	 */
17716817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
17721158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
17731158dfb7SGarrett Wollman 			break;
17741158dfb7SGarrett Wollman 	if (ifma == 0)
17751158dfb7SGarrett Wollman 		return 0;
17761158dfb7SGarrett Wollman 
17771158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
17781158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
17791158dfb7SGarrett Wollman 		return 0;
17801158dfb7SGarrett Wollman 	}
17811158dfb7SGarrett Wollman 
17821158dfb7SGarrett Wollman 	s = splimp();
17836817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
178431302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
1785c7323482SBill Paul 	ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
178631302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
17871158dfb7SGarrett Wollman 	splx(s);
17881158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
17891158dfb7SGarrett Wollman 	free(sa, M_IFMADDR);
17901158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
17911158dfb7SGarrett Wollman 
17921158dfb7SGarrett Wollman 	return 0;
17931158dfb7SGarrett Wollman }
17941158dfb7SGarrett Wollman 
179566ce51ceSArchie Cobbs /*
179666ce51ceSArchie Cobbs  * Set the link layer address on an interface.
179766ce51ceSArchie Cobbs  *
179866ce51ceSArchie Cobbs  * At this time we only support certain types of interfaces,
179966ce51ceSArchie Cobbs  * and we don't allow the length of the address to change.
180066ce51ceSArchie Cobbs  */
180166ce51ceSArchie Cobbs int
180266ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
180366ce51ceSArchie Cobbs {
180466ce51ceSArchie Cobbs 	struct sockaddr_dl *sdl;
180566ce51ceSArchie Cobbs 	struct ifaddr *ifa;
1806d637e989SPeter Wemm 	struct ifreq ifr;
180766ce51ceSArchie Cobbs 
1808f9132cebSJonathan Lemon 	ifa = ifaddr_byindex(ifp->if_index);
180966ce51ceSArchie Cobbs 	if (ifa == NULL)
181066ce51ceSArchie Cobbs 		return (EINVAL);
181166ce51ceSArchie Cobbs 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
181266ce51ceSArchie Cobbs 	if (sdl == NULL)
181366ce51ceSArchie Cobbs 		return (EINVAL);
181466ce51ceSArchie Cobbs 	if (len != sdl->sdl_alen)	/* don't allow length to change */
181566ce51ceSArchie Cobbs 		return (EINVAL);
181666ce51ceSArchie Cobbs 	switch (ifp->if_type) {
181766ce51ceSArchie Cobbs 	case IFT_ETHER:			/* these types use struct arpcom */
181866ce51ceSArchie Cobbs 	case IFT_FDDI:
181966ce51ceSArchie Cobbs 	case IFT_XETHER:
182066ce51ceSArchie Cobbs 	case IFT_ISO88025:
1821b7bffa71SYaroslav Tykhiy 	case IFT_L2VLAN:
18223fefbff0SLuigi Rizzo 		bcopy(lladdr, IFP2AC(ifp)->ac_enaddr, len);
18239046571fSLuigi Rizzo 		/*
18249046571fSLuigi Rizzo 		 * XXX We also need to store the lladdr in LLADDR(sdl),
18259046571fSLuigi Rizzo 		 * which is done below. This is a pain because we must
18269046571fSLuigi Rizzo 		 * remember to keep the info in sync.
18279046571fSLuigi Rizzo 		 */
18286cdcc159SMax Khon 		/* FALLTHROUGH */
18296cdcc159SMax Khon 	case IFT_ARCNET:
183066ce51ceSArchie Cobbs 		bcopy(lladdr, LLADDR(sdl), len);
183166ce51ceSArchie Cobbs 		break;
183266ce51ceSArchie Cobbs 	default:
183366ce51ceSArchie Cobbs 		return (ENODEV);
183466ce51ceSArchie Cobbs 	}
183566ce51ceSArchie Cobbs 	/*
183666ce51ceSArchie Cobbs 	 * If the interface is already up, we need
183766ce51ceSArchie Cobbs 	 * to re-init it in order to reprogram its
183866ce51ceSArchie Cobbs 	 * address filter.
183966ce51ceSArchie Cobbs 	 */
184066ce51ceSArchie Cobbs 	if ((ifp->if_flags & IFF_UP) != 0) {
184131302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
184266ce51ceSArchie Cobbs 		ifp->if_flags &= ~IFF_UP;
184362f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
184462f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1845ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
184666ce51ceSArchie Cobbs 		ifp->if_flags |= IFF_UP;
184762f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
184862f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1849ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
185031302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1851b2c08f43SLuigi Rizzo #ifdef INET
1852b2c08f43SLuigi Rizzo 		/*
1853b2c08f43SLuigi Rizzo 		 * Also send gratuitous ARPs to notify other nodes about
1854b2c08f43SLuigi Rizzo 		 * the address change.
1855b2c08f43SLuigi Rizzo 		 */
1856b2c08f43SLuigi Rizzo 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1857b2c08f43SLuigi Rizzo 			if (ifa->ifa_addr != NULL &&
1858b2c08f43SLuigi Rizzo 			    ifa->ifa_addr->sa_family == AF_INET)
1859c0933269SPeter Wemm 				arp_ifinit(ifp, ifa);
1860b2c08f43SLuigi Rizzo 		}
1861b2c08f43SLuigi Rizzo #endif
186266ce51ceSArchie Cobbs 	}
186366ce51ceSArchie Cobbs 	return (0);
186466ce51ceSArchie Cobbs }
186566ce51ceSArchie Cobbs 
1866373f88edSGarrett Wollman struct ifmultiaddr *
186772fd1b6aSDag-Erling Smørgrav ifmaof_ifpforaddr(struct sockaddr *sa, struct ifnet *ifp)
1868373f88edSGarrett Wollman {
1869373f88edSGarrett Wollman 	struct ifmultiaddr *ifma;
1870373f88edSGarrett Wollman 
18716817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
1872373f88edSGarrett Wollman 		if (equal(ifma->ifma_addr, sa))
1873373f88edSGarrett Wollman 			break;
1874373f88edSGarrett Wollman 
1875373f88edSGarrett Wollman 	return ifma;
1876373f88edSGarrett Wollman }
1877373f88edSGarrett Wollman 
18789bf40edeSBrooks Davis /*
18799bf40edeSBrooks Davis  * The name argument must be a pointer to storage which will last as
18809bf40edeSBrooks Davis  * long as the interface does.  For physical devices, the result of
18819bf40edeSBrooks Davis  * device_get_name(dev) is a good choice and for pseudo-devices a
18829bf40edeSBrooks Davis  * static string works well.
18839bf40edeSBrooks Davis  */
18849bf40edeSBrooks Davis void
18859bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit)
18869bf40edeSBrooks Davis {
18879bf40edeSBrooks Davis 	ifp->if_dname = name;
18889bf40edeSBrooks Davis 	ifp->if_dunit = unit;
18899bf40edeSBrooks Davis 	if (unit != IF_DUNIT_NONE)
18909bf40edeSBrooks Davis 		snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit);
18919bf40edeSBrooks Davis 	else
18929bf40edeSBrooks Davis 		strlcpy(ifp->if_xname, name, IFNAMSIZ);
18939bf40edeSBrooks Davis }
18949bf40edeSBrooks Davis 
1895fa882e87SBrooks Davis int
1896fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...)
1897fa882e87SBrooks Davis {
1898fa882e87SBrooks Davis 	va_list ap;
1899fa882e87SBrooks Davis 	int retval;
1900fa882e87SBrooks Davis 
19019bf40edeSBrooks Davis 	retval = printf("%s: ", ifp->if_xname);
1902fa882e87SBrooks Davis 	va_start(ap, fmt);
1903fa882e87SBrooks Davis 	retval += vprintf(fmt, ap);
1904fa882e87SBrooks Davis 	va_end(ap);
1905fa882e87SBrooks Davis 	return (retval);
1906fa882e87SBrooks Davis }
1907fa882e87SBrooks Davis 
1908af5e59bfSRobert Watson /*
1909af5e59bfSRobert Watson  * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot
1910af5e59bfSRobert Watson  * be called without Giant.  However, we often can't acquire the Giant lock
1911af5e59bfSRobert Watson  * at those points; instead, we run it via a task queue that holds Giant via
1912af5e59bfSRobert Watson  * if_start_deferred.
1913af5e59bfSRobert Watson  *
1914af5e59bfSRobert Watson  * XXXRW: We need to make sure that the ifnet isn't fully detached until any
1915af5e59bfSRobert Watson  * outstanding if_start_deferred() tasks that will run after the free.  This
1916af5e59bfSRobert Watson  * probably means waiting in if_detach().
1917af5e59bfSRobert Watson  */
1918af5e59bfSRobert Watson void
1919af5e59bfSRobert Watson if_start(struct ifnet *ifp)
1920af5e59bfSRobert Watson {
1921af5e59bfSRobert Watson 
1922af5e59bfSRobert Watson 	NET_ASSERT_GIANT();
1923af5e59bfSRobert Watson 
1924af5e59bfSRobert Watson         if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) {
1925af5e59bfSRobert Watson                 if (mtx_owned(&Giant))
1926af5e59bfSRobert Watson                         (*(ifp)->if_start)(ifp);
1927af5e59bfSRobert Watson                 else
1928af5e59bfSRobert Watson 			taskqueue_enqueue(taskqueue_swi_giant,
1929af5e59bfSRobert Watson 			    &ifp->if_starttask);
1930af5e59bfSRobert Watson         } else
1931af5e59bfSRobert Watson                 (*(ifp)->if_start)(ifp);
1932af5e59bfSRobert Watson }
1933af5e59bfSRobert Watson 
1934af5e59bfSRobert Watson static void
1935af5e59bfSRobert Watson if_start_deferred(void *context, int pending)
1936af5e59bfSRobert Watson {
1937af5e59bfSRobert Watson 	struct ifnet *ifp;
1938af5e59bfSRobert Watson 
1939af5e59bfSRobert Watson 	/*
1940af5e59bfSRobert Watson 	 * This code must be entered with Giant, and should never run if
1941af5e59bfSRobert Watson 	 * we're not running with debug.mpsafenet.
1942af5e59bfSRobert Watson 	 */
1943af5e59bfSRobert Watson 	KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet"));
1944af5e59bfSRobert Watson 	GIANT_REQUIRED;
1945af5e59bfSRobert Watson 
1946af5e59bfSRobert Watson 	ifp = (struct ifnet *)context;
1947af5e59bfSRobert Watson 	(ifp->if_start)(ifp);
1948af5e59bfSRobert Watson }
1949af5e59bfSRobert Watson 
19500b762445SRobert Watson int
19510b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
19520b762445SRobert Watson {
19530b762445SRobert Watson 	int active = 0;
19540b762445SRobert Watson 
19550b762445SRobert Watson 	IF_LOCK(ifq);
19560b762445SRobert Watson 	if (_IF_QFULL(ifq)) {
19570b762445SRobert Watson 		_IF_DROP(ifq);
19580b762445SRobert Watson 		IF_UNLOCK(ifq);
19590b762445SRobert Watson 		m_freem(m);
19600b762445SRobert Watson 		return (0);
19610b762445SRobert Watson 	}
19620b762445SRobert Watson 	if (ifp != NULL) {
19630b762445SRobert Watson 		ifp->if_obytes += m->m_pkthdr.len + adjust;
19640b762445SRobert Watson 		if (m->m_flags & (M_BCAST|M_MCAST))
19650b762445SRobert Watson 			ifp->if_omcasts++;
19660b762445SRobert Watson 		active = ifp->if_flags & IFF_OACTIVE;
19670b762445SRobert Watson 	}
19680b762445SRobert Watson 	_IF_ENQUEUE(ifq, m);
19690b762445SRobert Watson 	IF_UNLOCK(ifq);
19700b762445SRobert Watson 	if (ifp != NULL && !active)
19710b762445SRobert Watson 		if_start(ifp);
19720b762445SRobert Watson 	return (1);
19730b762445SRobert Watson }
19740b762445SRobert Watson 
1975602d513cSGarrett Wollman SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
19762c37256eSGarrett Wollman SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
1977