xref: /freebsd/sys/net/if.c (revision 1c7899c74e68cca6dbfddbed437d11001c0c3722)
1c398230bSWarner Losh /*-
2df8bae1dSRodney W. Grimes  * Copyright (c) 1980, 1986, 1993
3df8bae1dSRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4df8bae1dSRodney W. Grimes  *
5df8bae1dSRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
6df8bae1dSRodney W. Grimes  * modification, are permitted provided that the following conditions
7df8bae1dSRodney W. Grimes  * are met:
8df8bae1dSRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
9df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
10df8bae1dSRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
11df8bae1dSRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
12df8bae1dSRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
13df8bae1dSRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
14df8bae1dSRodney W. Grimes  *    may be used to endorse or promote products derived from this software
15df8bae1dSRodney W. Grimes  *    without specific prior written permission.
16df8bae1dSRodney W. Grimes  *
17df8bae1dSRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
18df8bae1dSRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19df8bae1dSRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20df8bae1dSRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
21df8bae1dSRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22df8bae1dSRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23df8bae1dSRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24df8bae1dSRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25df8bae1dSRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26df8bae1dSRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27df8bae1dSRodney W. Grimes  * SUCH DAMAGE.
28df8bae1dSRodney W. Grimes  *
2966afbd68SRuslan Ermilov  *	@(#)if.c	8.5 (Berkeley) 1/9/95
30c3aac50fSPeter Wemm  * $FreeBSD$
31df8bae1dSRodney W. Grimes  */
32df8bae1dSRodney W. Grimes 
335591b823SEivind Eklund #include "opt_compat.h"
34cfa1ca9dSYoshinobu Inoue #include "opt_inet6.h"
350d0f9d1eSYoshinobu Inoue #include "opt_inet.h"
36e70cd263SRobert Watson #include "opt_mac.h"
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 
821c7899c7SGleb Smirnoff void	(*ng_ether_link_state_p)(struct ifnet *ifp, int state);
831c7899c7SGleb Smirnoff 
844cb655c0SMax Laier struct mbuf *(*tbr_dequeue_ptr)(struct ifaltq *, int) = NULL;
854cb655c0SMax Laier 
8631b1bfe1SHajimu UMEMOTO static void	if_attachdomain(void *);
8731b1bfe1SHajimu UMEMOTO static void	if_attachdomain1(struct ifnet *);
880b59d917SJonathan Lemon static int	ifconf(u_long, caddr_t);
89f9132cebSJonathan Lemon static void	if_grow(void);
90f9132cebSJonathan Lemon static void	if_init(void *);
91f9132cebSJonathan Lemon static void	if_check(void *);
92ffb5a104SJonathan Lemon static int	if_findindex(struct ifnet *);
9302b199f1SMax Laier static void	if_qflush(struct ifaltq *);
948614fb12SMax Laier static void	if_route(struct ifnet *, int flag, int fam);
950b59d917SJonathan Lemon static void	if_slowtimo(void *);
968614fb12SMax Laier static void	if_unroute(struct ifnet *, int flag, int fam);
978071913dSRuslan Ermilov static void	link_rtrequest(int, struct rtentry *, struct rt_addrinfo *);
980b59d917SJonathan Lemon static int	if_rtdel(struct radix_node *, void *);
99f13ad206SJonathan Lemon static int	ifhwioctl(u_long, struct ifnet *, caddr_t, struct thread *);
100af5e59bfSRobert Watson static void	if_start_deferred(void *context, int pending);
10182cd038dSYoshinobu Inoue #ifdef INET6
10282cd038dSYoshinobu Inoue /*
10382cd038dSYoshinobu Inoue  * XXX: declare here to avoid to include many inet6 related files..
10482cd038dSYoshinobu Inoue  * should be more generalized?
10582cd038dSYoshinobu Inoue  */
106929ddbbbSAlfred Perlstein extern void	nd6_setmtu(struct ifnet *);
10782cd038dSYoshinobu Inoue #endif
10882cd038dSYoshinobu Inoue 
1090b59d917SJonathan Lemon int	if_index = 0;
110f9132cebSJonathan Lemon struct	ifindex_entry *ifindex_table = NULL;
1110b59d917SJonathan Lemon int	ifqmaxlen = IFQ_MAXLEN;
1120b59d917SJonathan Lemon struct	ifnethead ifnet;	/* depend on static init XXX */
113b30a244cSJeffrey Hsu struct	mtx ifnet_lock;
1140b59d917SJonathan Lemon 
115f9132cebSJonathan Lemon static int	if_indexlim = 8;
116ad3b9257SJohn-Mark Gurney static struct	knlist ifklist;
117f9132cebSJonathan Lemon 
1189a2a57a1SJonathan Lemon static void	filt_netdetach(struct knote *kn);
1199a2a57a1SJonathan Lemon static int	filt_netdev(struct knote *kn, long hint);
1209a2a57a1SJonathan Lemon 
1219a2a57a1SJonathan Lemon static struct filterops netdev_filtops =
1229a2a57a1SJonathan Lemon     { 1, NULL, filt_netdetach, filt_netdev };
1239a2a57a1SJonathan Lemon 
1240b59d917SJonathan Lemon /*
1250b59d917SJonathan Lemon  * System initialization
1260b59d917SJonathan Lemon  */
127f9132cebSJonathan Lemon SYSINIT(interfaces, SI_SUB_INIT_IF, SI_ORDER_FIRST, if_init, NULL)
128f9132cebSJonathan Lemon SYSINIT(interface_check, SI_SUB_PROTO_IF, SI_ORDER_FIRST, if_check, NULL)
1290b59d917SJonathan Lemon 
1300b59d917SJonathan Lemon MALLOC_DEFINE(M_IFADDR, "ifaddr", "interface address");
1310b59d917SJonathan Lemon MALLOC_DEFINE(M_IFMADDR, "ether_multi", "link-level multicast address");
13230aad87dSBrooks Davis 
133f13ad206SJonathan Lemon static d_open_t		netopen;
134f13ad206SJonathan Lemon static d_close_t	netclose;
135f13ad206SJonathan Lemon static d_ioctl_t	netioctl;
1369a2a57a1SJonathan Lemon static d_kqfilter_t	netkqfilter;
137f13ad206SJonathan Lemon 
138f13ad206SJonathan Lemon static struct cdevsw net_cdevsw = {
139dc08ffecSPoul-Henning Kamp 	.d_version =	D_VERSION,
140dc08ffecSPoul-Henning Kamp 	.d_flags =	D_NEEDGIANT,
1417ac40f5fSPoul-Henning Kamp 	.d_open =	netopen,
1427ac40f5fSPoul-Henning Kamp 	.d_close =	netclose,
1437ac40f5fSPoul-Henning Kamp 	.d_ioctl =	netioctl,
1447ac40f5fSPoul-Henning Kamp 	.d_name =	"net",
1457ac40f5fSPoul-Henning Kamp 	.d_kqfilter =	netkqfilter,
146f13ad206SJonathan Lemon };
147f13ad206SJonathan Lemon 
148f13ad206SJonathan Lemon static int
14989c9c53dSPoul-Henning Kamp netopen(struct cdev *dev, int flag, int mode, struct thread *td)
150f13ad206SJonathan Lemon {
151f13ad206SJonathan Lemon 	return (0);
152f13ad206SJonathan Lemon }
153f13ad206SJonathan Lemon 
154f13ad206SJonathan Lemon static int
15589c9c53dSPoul-Henning Kamp netclose(struct cdev *dev, int flags, int fmt, struct thread *td)
156f13ad206SJonathan Lemon {
157f13ad206SJonathan Lemon 	return (0);
158f13ad206SJonathan Lemon }
159f13ad206SJonathan Lemon 
160f13ad206SJonathan Lemon static int
16189c9c53dSPoul-Henning Kamp netioctl(struct cdev *dev, u_long cmd, caddr_t data, int flag, struct thread *td)
162f13ad206SJonathan Lemon {
163f13ad206SJonathan Lemon 	struct ifnet *ifp;
164f13ad206SJonathan Lemon 	int error, idx;
165f13ad206SJonathan Lemon 
166f13ad206SJonathan Lemon 	/* only support interface specific ioctls */
167f13ad206SJonathan Lemon 	if (IOCGROUP(cmd) != 'i')
168f13ad206SJonathan Lemon 		return (EOPNOTSUPP);
169f13ad206SJonathan Lemon 	idx = minor(dev);
170f13ad206SJonathan Lemon 	if (idx == 0) {
171f13ad206SJonathan Lemon 		/*
172f13ad206SJonathan Lemon 		 * special network device, not interface.
173f13ad206SJonathan Lemon 		 */
174f13ad206SJonathan Lemon 		if (cmd == SIOCGIFCONF)
175f13ad206SJonathan Lemon 			return (ifconf(cmd, data));	/* XXX remove cmd */
176f13ad206SJonathan Lemon 		return (EOPNOTSUPP);
177f13ad206SJonathan Lemon 	}
178f13ad206SJonathan Lemon 
179f13ad206SJonathan Lemon 	ifp = ifnet_byindex(idx);
180f13ad206SJonathan Lemon 	if (ifp == NULL)
181f13ad206SJonathan Lemon 		return (ENXIO);
182f13ad206SJonathan Lemon 
183f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
184f13ad206SJonathan Lemon 	if (error == ENOIOCTL)
185f13ad206SJonathan Lemon 		error = EOPNOTSUPP;
186f13ad206SJonathan Lemon 	return (error);
187f13ad206SJonathan Lemon }
188f13ad206SJonathan Lemon 
1899a2a57a1SJonathan Lemon static int
19089c9c53dSPoul-Henning Kamp netkqfilter(struct cdev *dev, struct knote *kn)
1919a2a57a1SJonathan Lemon {
192ad3b9257SJohn-Mark Gurney 	struct knlist *klist;
1939a2a57a1SJonathan Lemon 	struct ifnet *ifp;
1949a2a57a1SJonathan Lemon 	int idx;
1959a2a57a1SJonathan Lemon 
196ad3b9257SJohn-Mark Gurney 	switch (kn->kn_filter) {
197ad3b9257SJohn-Mark Gurney 	case EVFILT_NETDEV:
198ad3b9257SJohn-Mark Gurney 		kn->kn_fop = &netdev_filtops;
199ad3b9257SJohn-Mark Gurney 		break;
200ad3b9257SJohn-Mark Gurney 	default:
201ad3b9257SJohn-Mark Gurney 		return (1);
202ad3b9257SJohn-Mark Gurney 	}
203ad3b9257SJohn-Mark Gurney 
2049a2a57a1SJonathan Lemon 	idx = minor(dev);
2059a2a57a1SJonathan Lemon 	if (idx == 0) {
2069a2a57a1SJonathan Lemon 		klist = &ifklist;
2079a2a57a1SJonathan Lemon 	} else {
2089a2a57a1SJonathan Lemon 		ifp = ifnet_byindex(idx);
2099a2a57a1SJonathan Lemon 		if (ifp == NULL)
2109a2a57a1SJonathan Lemon 			return (1);
2119a2a57a1SJonathan Lemon 		klist = &ifp->if_klist;
2129a2a57a1SJonathan Lemon 	}
2139a2a57a1SJonathan Lemon 
2149a2a57a1SJonathan Lemon 	kn->kn_hook = (caddr_t)klist;
2159a2a57a1SJonathan Lemon 
216ad3b9257SJohn-Mark Gurney 	knlist_add(klist, kn, 0);
2179a2a57a1SJonathan Lemon 
2189a2a57a1SJonathan Lemon 	return (0);
2199a2a57a1SJonathan Lemon }
2209a2a57a1SJonathan Lemon 
2219a2a57a1SJonathan Lemon static void
2229a2a57a1SJonathan Lemon filt_netdetach(struct knote *kn)
2239a2a57a1SJonathan Lemon {
224ad3b9257SJohn-Mark Gurney 	struct knlist *klist = (struct knlist *)kn->kn_hook;
2259a2a57a1SJonathan Lemon 
226ad3b9257SJohn-Mark Gurney 	knlist_remove(klist, kn, 0);
2279a2a57a1SJonathan Lemon }
2289a2a57a1SJonathan Lemon 
2299a2a57a1SJonathan Lemon static int
2309a2a57a1SJonathan Lemon filt_netdev(struct knote *kn, long hint)
2319a2a57a1SJonathan Lemon {
232ad3b9257SJohn-Mark Gurney 	struct knlist *klist = (struct knlist *)kn->kn_hook;
2339a2a57a1SJonathan Lemon 
2349a2a57a1SJonathan Lemon 	/*
2359a2a57a1SJonathan Lemon 	 * Currently NOTE_EXIT is abused to indicate device detach.
2369a2a57a1SJonathan Lemon 	 */
2379a2a57a1SJonathan Lemon 	if (hint == NOTE_EXIT) {
2389a2a57a1SJonathan Lemon 		kn->kn_data = NOTE_LINKINV;
2399a2a57a1SJonathan Lemon 		kn->kn_flags |= (EV_EOF | EV_ONESHOT);
240ad3b9257SJohn-Mark Gurney 		knlist_remove_inevent(klist, kn);
2419a2a57a1SJonathan Lemon 		return (1);
2429a2a57a1SJonathan Lemon 	}
243ad3b9257SJohn-Mark Gurney 	if (hint != 0)
2449a2a57a1SJonathan Lemon 		kn->kn_data = hint;			/* current status */
2459a2a57a1SJonathan Lemon 	if (kn->kn_sfflags & hint)
2469a2a57a1SJonathan Lemon 		kn->kn_fflags |= hint;
2479a2a57a1SJonathan Lemon 	return (kn->kn_fflags != 0);
2489a2a57a1SJonathan Lemon }
2499a2a57a1SJonathan Lemon 
250df8bae1dSRodney W. Grimes /*
251df8bae1dSRodney W. Grimes  * Network interface utility routines.
252df8bae1dSRodney W. Grimes  *
253df8bae1dSRodney W. Grimes  * Routines with ifa_ifwith* names take sockaddr *'s as
254df8bae1dSRodney W. Grimes  * parameters.
255df8bae1dSRodney W. Grimes  */
2562b14f991SJulian Elischer /* ARGSUSED*/
257f9132cebSJonathan Lemon static void
25872fd1b6aSDag-Erling Smørgrav if_init(void *dummy __unused)
259f9132cebSJonathan Lemon {
260f9132cebSJonathan Lemon 
261b30a244cSJeffrey Hsu 	IFNET_LOCK_INIT();
262f9132cebSJonathan Lemon 	TAILQ_INIT(&ifnet);
263ad3b9257SJohn-Mark Gurney 	knlist_init(&ifklist, NULL);
264f9132cebSJonathan Lemon 	if_grow();				/* create initial table */
265f13ad206SJonathan Lemon 	ifdev_byindex(0) = make_dev(&net_cdevsw, 0,
266f13ad206SJonathan Lemon 	    UID_ROOT, GID_WHEEL, 0600, "network");
267f889d2efSBrooks Davis 	if_clone_init();
268f9132cebSJonathan Lemon }
269f9132cebSJonathan Lemon 
270f9132cebSJonathan Lemon static void
271f9132cebSJonathan Lemon if_grow(void)
272f9132cebSJonathan Lemon {
273f9132cebSJonathan Lemon 	u_int n;
274f9132cebSJonathan Lemon 	struct ifindex_entry *e;
275f9132cebSJonathan Lemon 
276f9132cebSJonathan Lemon 	if_indexlim <<= 1;
277f9132cebSJonathan Lemon 	n = if_indexlim * sizeof(*e);
278a163d034SWarner Losh 	e = malloc(n, M_IFADDR, M_WAITOK | M_ZERO);
279f9132cebSJonathan Lemon 	if (ifindex_table != NULL) {
280f9132cebSJonathan Lemon 		memcpy((caddr_t)e, (caddr_t)ifindex_table, n/2);
281f9132cebSJonathan Lemon 		free((caddr_t)ifindex_table, M_IFADDR);
282f9132cebSJonathan Lemon 	}
283f9132cebSJonathan Lemon 	ifindex_table = e;
284f9132cebSJonathan Lemon }
285f9132cebSJonathan Lemon 
286f9132cebSJonathan Lemon /* ARGSUSED*/
287f9132cebSJonathan Lemon static void
28872fd1b6aSDag-Erling Smørgrav if_check(void *dummy __unused)
289df8bae1dSRodney W. Grimes {
2908ba5bdaeSPeter Wemm 	struct ifnet *ifp;
2918ba5bdaeSPeter Wemm 	int s;
292df8bae1dSRodney W. Grimes 
2938ba5bdaeSPeter Wemm 	s = splimp();
294b30a244cSJeffrey Hsu 	IFNET_RLOCK();	/* could sleep on rare error; mostly okay XXX */
295fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
296e0ea20bcSPoul-Henning Kamp 		if (ifp->if_snd.ifq_maxlen == 0) {
29713fb40dfSBrooks Davis 			if_printf(ifp, "XXX: driver didn't set ifq_maxlen\n");
298df8bae1dSRodney W. Grimes 			ifp->if_snd.ifq_maxlen = ifqmaxlen;
299e0ea20bcSPoul-Henning Kamp 		}
3005e980e22SJohn Baldwin 		if (!mtx_initialized(&ifp->if_snd.ifq_mtx)) {
30113fb40dfSBrooks Davis 			if_printf(ifp,
30213fb40dfSBrooks Davis 			    "XXX: driver didn't initialize queue mtx\n");
3036008862bSJohn Baldwin 			mtx_init(&ifp->if_snd.ifq_mtx, "unknown",
3046008862bSJohn Baldwin 			    MTX_NETWORK_LOCK, MTX_DEF);
305df5e1987SJonathan Lemon 		}
306df5e1987SJonathan Lemon 	}
307b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
3088ba5bdaeSPeter Wemm 	splx(s);
309df8bae1dSRodney W. Grimes 	if_slowtimo(0);
310df8bae1dSRodney W. Grimes }
311df8bae1dSRodney W. Grimes 
312ffb5a104SJonathan Lemon static int
313ffb5a104SJonathan Lemon if_findindex(struct ifnet *ifp)
314ffb5a104SJonathan Lemon {
315ffb5a104SJonathan Lemon 	int i, unit;
316ffb5a104SJonathan Lemon 	char eaddr[18], devname[32];
317d2b4566aSJonathan Lemon 	const char *name, *p;
318ffb5a104SJonathan Lemon 
319ffb5a104SJonathan Lemon 	switch (ifp->if_type) {
320ffb5a104SJonathan Lemon 	case IFT_ETHER:			/* these types use struct arpcom */
321ffb5a104SJonathan Lemon 	case IFT_FDDI:
322ffb5a104SJonathan Lemon 	case IFT_XETHER:
323ffb5a104SJonathan Lemon 	case IFT_ISO88025:
324ffb5a104SJonathan Lemon 	case IFT_L2VLAN:
3258bbfdc98SRobert Watson 		snprintf(eaddr, 18, "%6D", IFP2AC(ifp)->ac_enaddr, ":");
326ffb5a104SJonathan Lemon 		break;
327ffb5a104SJonathan Lemon 	default:
328ffb5a104SJonathan Lemon 		eaddr[0] = '\0';
329ffb5a104SJonathan Lemon 		break;
330ffb5a104SJonathan Lemon 	}
3319bf40edeSBrooks Davis 	strlcpy(devname, ifp->if_xname, sizeof(devname));
332ffb5a104SJonathan Lemon 	name = net_cdevsw.d_name;
333ffb5a104SJonathan Lemon 	i = 0;
334ffb5a104SJonathan Lemon 	while ((resource_find_dev(&i, name, &unit, NULL, NULL)) == 0) {
335ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "ether", &p) == 0)
336ffb5a104SJonathan Lemon 			if (strcmp(p, eaddr) == 0)
337ffb5a104SJonathan Lemon 				goto found;
338ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "dev", &p) == 0)
339ffb5a104SJonathan Lemon 			if (strcmp(p, devname) == 0)
340ffb5a104SJonathan Lemon 				goto found;
341ffb5a104SJonathan Lemon 	}
342ffb5a104SJonathan Lemon 	unit = 0;
343ffb5a104SJonathan Lemon found:
344ffb5a104SJonathan Lemon 	if (unit != 0) {
345ffb5a104SJonathan Lemon 		if (ifaddr_byindex(unit) == NULL)
346ffb5a104SJonathan Lemon 			return (unit);
347ffb5a104SJonathan Lemon 		printf("%s%d in use, cannot hardwire it to %s.\n",
348ffb5a104SJonathan Lemon 		    name, unit, devname);
349ffb5a104SJonathan Lemon 	}
350ffb5a104SJonathan Lemon 	for (unit = 1; ; unit++) {
35105153c61SBill Fenner 		if (unit <= if_index && ifaddr_byindex(unit) != NULL)
352ffb5a104SJonathan Lemon 			continue;
353ffb5a104SJonathan Lemon 		if (resource_string_value(name, unit, "ether", &p) == 0 ||
354ffb5a104SJonathan Lemon 		    resource_string_value(name, unit, "dev", &p) == 0)
355ffb5a104SJonathan Lemon 			continue;
356ffb5a104SJonathan Lemon 		break;
357ffb5a104SJonathan Lemon 	}
358ffb5a104SJonathan Lemon 	return (unit);
359ffb5a104SJonathan Lemon }
360ffb5a104SJonathan Lemon 
361df8bae1dSRodney W. Grimes /*
362df8bae1dSRodney W. Grimes  * Attach an interface to the
363df8bae1dSRodney W. Grimes  * list of "active" interfaces.
364df8bae1dSRodney W. Grimes  */
365df8bae1dSRodney W. Grimes void
36672fd1b6aSDag-Erling Smørgrav if_attach(struct ifnet *ifp)
367df8bae1dSRodney W. Grimes {
368df8bae1dSRodney W. Grimes 	unsigned socksize, ifasize;
3691ce9bf88SPoul-Henning Kamp 	int namelen, masklen;
37072fd1b6aSDag-Erling Smørgrav 	struct sockaddr_dl *sdl;
37172fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
372df8bae1dSRodney W. Grimes 
373af5e59bfSRobert Watson 	TASK_INIT(&ifp->if_starttask, 0, if_start_deferred, ifp);
374234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK_INIT(ifp);
375234a35c7SHajimu UMEMOTO 	ifp->if_afdata_initialized = 0;
376b30a244cSJeffrey Hsu 	IFNET_WLOCK();
37729412182SGarrett Wollman 	TAILQ_INSERT_TAIL(&ifnet, ifp, if_link);
378b30a244cSJeffrey Hsu 	IFNET_WUNLOCK();
37959562606SGarrett Wollman 	/*
38059562606SGarrett Wollman 	 * XXX -
38159562606SGarrett Wollman 	 * The old code would work if the interface passed a pre-existing
38259562606SGarrett Wollman 	 * chain of ifaddrs to this code.  We don't trust our callers to
38359562606SGarrett Wollman 	 * properly initialize the tailq, however, so we no longer allow
38459562606SGarrett Wollman 	 * this unlikely case.
38559562606SGarrett Wollman 	 */
38659562606SGarrett Wollman 	TAILQ_INIT(&ifp->if_addrhead);
38782cd038dSYoshinobu Inoue 	TAILQ_INIT(&ifp->if_prefixhead);
3886817526dSPoul-Henning Kamp 	TAILQ_INIT(&ifp->if_multiaddrs);
389ad3b9257SJohn-Mark Gurney 	knlist_init(&ifp->if_klist, NULL);
39098b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
39155287f2aSBrooks Davis 	ifp->if_data.ifi_epoch = time_second;
392e70cd263SRobert Watson 
393e70cd263SRobert Watson #ifdef MAC
394e70cd263SRobert Watson 	mac_init_ifnet(ifp);
395e70cd263SRobert Watson 	mac_create_ifnet(ifp);
396e70cd263SRobert Watson #endif
397e70cd263SRobert Watson 
398ffb5a104SJonathan Lemon 	ifp->if_index = if_findindex(ifp);
39905153c61SBill Fenner 	if (ifp->if_index > if_index)
40005153c61SBill Fenner 		if_index = ifp->if_index;
401f9132cebSJonathan Lemon 	if (if_index >= if_indexlim)
402f9132cebSJonathan Lemon 		if_grow();
4039e734b44SBrooks Davis 	ifp->if_data.ifi_datalen = sizeof(struct if_data);
40482cd038dSYoshinobu Inoue 
405ffb5a104SJonathan Lemon 	ifnet_byindex(ifp->if_index) = ifp;
40612b8b80eSRuslan Ermilov 	ifdev_byindex(ifp->if_index) = make_dev(&net_cdevsw,
40712b8b80eSRuslan Ermilov 	    unit2minor(ifp->if_index),
4089bf40edeSBrooks Davis 	    UID_ROOT, GID_WHEEL, 0600, "%s/%s",
4099bf40edeSBrooks Davis 	    net_cdevsw.d_name, ifp->if_xname);
410ffb5a104SJonathan Lemon 	make_dev_alias(ifdev_byindex(ifp->if_index), "%s%d",
411ffb5a104SJonathan Lemon 	    net_cdevsw.d_name, ifp->if_index);
412f13ad206SJonathan Lemon 
4139bf40edeSBrooks Davis 	mtx_init(&ifp->if_snd.ifq_mtx, ifp->if_xname, "if send queue", MTX_DEF);
414df5e1987SJonathan Lemon 
415df8bae1dSRodney W. Grimes 	/*
416df8bae1dSRodney W. Grimes 	 * create a Link Level name for this device
417df8bae1dSRodney W. Grimes 	 */
4189bf40edeSBrooks Davis 	namelen = strlen(ifp->if_xname);
41936c19a57SBrooks Davis 	/*
42036c19a57SBrooks Davis 	 * Always save enough space for any possiable name so we can do
42136c19a57SBrooks Davis 	 * a rename in place later.
42236c19a57SBrooks Davis 	 */
42336c19a57SBrooks Davis 	masklen = offsetof(struct sockaddr_dl, sdl_data[0]) + IFNAMSIZ;
424df8bae1dSRodney W. Grimes 	socksize = masklen + ifp->if_addrlen;
425df8bae1dSRodney W. Grimes 	if (socksize < sizeof(*sdl))
426df8bae1dSRodney W. Grimes 		socksize = sizeof(*sdl);
427ccb82468SBrooks Davis 	socksize = roundup2(socksize, sizeof(long));
428df8bae1dSRodney W. Grimes 	ifasize = sizeof(*ifa) + 2 * socksize;
429a8773564SBrooks Davis 	ifa = malloc(ifasize, M_IFADDR, M_WAITOK | M_ZERO);
43019fc74fbSJeffrey Hsu 	IFA_LOCK_INIT(ifa);
431df8bae1dSRodney W. Grimes 	sdl = (struct sockaddr_dl *)(ifa + 1);
432df8bae1dSRodney W. Grimes 	sdl->sdl_len = socksize;
433df8bae1dSRodney W. Grimes 	sdl->sdl_family = AF_LINK;
4349bf40edeSBrooks Davis 	bcopy(ifp->if_xname, sdl->sdl_data, namelen);
4351ce9bf88SPoul-Henning Kamp 	sdl->sdl_nlen = namelen;
436df8bae1dSRodney W. Grimes 	sdl->sdl_index = ifp->if_index;
437df8bae1dSRodney W. Grimes 	sdl->sdl_type = ifp->if_type;
438ffb5a104SJonathan Lemon 	ifaddr_byindex(ifp->if_index) = ifa;
439df8bae1dSRodney W. Grimes 	ifa->ifa_ifp = ifp;
440df8bae1dSRodney W. Grimes 	ifa->ifa_rtrequest = link_rtrequest;
441df8bae1dSRodney W. Grimes 	ifa->ifa_addr = (struct sockaddr *)sdl;
442df8bae1dSRodney W. Grimes 	sdl = (struct sockaddr_dl *)(socksize + (caddr_t)sdl);
443df8bae1dSRodney W. Grimes 	ifa->ifa_netmask = (struct sockaddr *)sdl;
444df8bae1dSRodney W. Grimes 	sdl->sdl_len = masklen;
445df8bae1dSRodney W. Grimes 	while (namelen != 0)
446df8bae1dSRodney W. Grimes 		sdl->sdl_data[--namelen] = 0xff;
44719fc74fbSJeffrey Hsu 	ifa->ifa_refcnt = 1;
44859562606SGarrett Wollman 	TAILQ_INSERT_HEAD(&ifp->if_addrhead, ifa, ifa_link);
4496237419dSRobert Watson 	ifp->if_broadcastaddr = NULL; /* reliably crash if used uninitialized */
45002b199f1SMax Laier 	ifp->if_snd.altq_type = 0;
45102b199f1SMax Laier 	ifp->if_snd.altq_disc = NULL;
45202b199f1SMax Laier 	ifp->if_snd.altq_flags &= ALTQF_CANTCHANGE;
45302b199f1SMax Laier 	ifp->if_snd.altq_tbr  = NULL;
45402b199f1SMax Laier 	ifp->if_snd.altq_ifp  = ifp;
4557b6edd04SRuslan Ermilov 
45669fb23b7SMax Laier 	if (domain_init_status >= 2)
45731b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
45831b1bfe1SHajimu UMEMOTO 
45925a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
46025a4adceSMax Laier 
4617b6edd04SRuslan Ermilov 	/* Announce the interface. */
4627b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
463df8bae1dSRodney W. Grimes }
4646182fdbdSPeter Wemm 
46531b1bfe1SHajimu UMEMOTO static void
46672fd1b6aSDag-Erling Smørgrav if_attachdomain(void *dummy)
46731b1bfe1SHajimu UMEMOTO {
46831b1bfe1SHajimu UMEMOTO 	struct ifnet *ifp;
46931b1bfe1SHajimu UMEMOTO 	int s;
47031b1bfe1SHajimu UMEMOTO 
47131b1bfe1SHajimu UMEMOTO 	s = splnet();
4729046571fSLuigi Rizzo 	TAILQ_FOREACH(ifp, &ifnet, if_link)
47331b1bfe1SHajimu UMEMOTO 		if_attachdomain1(ifp);
47431b1bfe1SHajimu UMEMOTO 	splx(s);
47531b1bfe1SHajimu UMEMOTO }
47669fb23b7SMax Laier SYSINIT(domainifattach, SI_SUB_PROTO_IFATTACHDOMAIN, SI_ORDER_SECOND,
47731b1bfe1SHajimu UMEMOTO     if_attachdomain, NULL);
47831b1bfe1SHajimu UMEMOTO 
47931b1bfe1SHajimu UMEMOTO static void
48072fd1b6aSDag-Erling Smørgrav if_attachdomain1(struct ifnet *ifp)
48131b1bfe1SHajimu UMEMOTO {
48231b1bfe1SHajimu UMEMOTO 	struct domain *dp;
48331b1bfe1SHajimu UMEMOTO 	int s;
48431b1bfe1SHajimu UMEMOTO 
48531b1bfe1SHajimu UMEMOTO 	s = splnet();
48631b1bfe1SHajimu UMEMOTO 
487234a35c7SHajimu UMEMOTO 	/*
488234a35c7SHajimu UMEMOTO 	 * Since dp->dom_ifattach calls malloc() with M_WAITOK, we
489234a35c7SHajimu UMEMOTO 	 * cannot lock ifp->if_afdata initialization, entirely.
490234a35c7SHajimu UMEMOTO 	 */
491234a35c7SHajimu UMEMOTO 	if (IF_AFDATA_TRYLOCK(ifp) == 0) {
492234a35c7SHajimu UMEMOTO 		splx(s);
493234a35c7SHajimu UMEMOTO 		return;
494234a35c7SHajimu UMEMOTO 	}
49569fb23b7SMax Laier 	if (ifp->if_afdata_initialized >= domain_init_status) {
496234a35c7SHajimu UMEMOTO 		IF_AFDATA_UNLOCK(ifp);
497234a35c7SHajimu UMEMOTO 		splx(s);
4986237419dSRobert Watson 		printf("if_attachdomain called more than once on %s\n",
4996237419dSRobert Watson 		    ifp->if_xname);
500234a35c7SHajimu UMEMOTO 		return;
501234a35c7SHajimu UMEMOTO 	}
50269fb23b7SMax Laier 	ifp->if_afdata_initialized = domain_init_status;
503234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
504234a35c7SHajimu UMEMOTO 
50531b1bfe1SHajimu UMEMOTO 	/* address family dependent data region */
50631b1bfe1SHajimu UMEMOTO 	bzero(ifp->if_afdata, sizeof(ifp->if_afdata));
50731b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
50831b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifattach)
50931b1bfe1SHajimu UMEMOTO 			ifp->if_afdata[dp->dom_family] =
51031b1bfe1SHajimu UMEMOTO 			    (*dp->dom_ifattach)(ifp);
51131b1bfe1SHajimu UMEMOTO 	}
51231b1bfe1SHajimu UMEMOTO 
51331b1bfe1SHajimu UMEMOTO 	splx(s);
51431b1bfe1SHajimu UMEMOTO }
51531b1bfe1SHajimu UMEMOTO 
5166182fdbdSPeter Wemm /*
5176182fdbdSPeter Wemm  * Detach an interface, removing it from the
5186182fdbdSPeter Wemm  * list of "active" interfaces.
5196182fdbdSPeter Wemm  */
5206182fdbdSPeter Wemm void
52172fd1b6aSDag-Erling Smørgrav if_detach(struct ifnet *ifp)
5226182fdbdSPeter Wemm {
523212bd869SHajimu UMEMOTO 	struct ifaddr *ifa, *next;
5245500d3beSWarner Losh 	struct radix_node_head	*rnh;
5255500d3beSWarner Losh 	int s;
5265500d3beSWarner Losh 	int i;
52731b1bfe1SHajimu UMEMOTO 	struct domain *dp;
5283f35d515SPeter Pentchev  	struct ifnet *iter;
5293f35d515SPeter Pentchev  	int found;
5306182fdbdSPeter Wemm 
53125a4adceSMax Laier 	EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
5326182fdbdSPeter Wemm 	/*
5336182fdbdSPeter Wemm 	 * Remove routes and flush queues.
5346182fdbdSPeter Wemm 	 */
5355500d3beSWarner Losh 	s = splnet();
5366182fdbdSPeter Wemm 	if_down(ifp);
53702b199f1SMax Laier #ifdef ALTQ
53802b199f1SMax Laier 	if (ALTQ_IS_ENABLED(&ifp->if_snd))
53902b199f1SMax Laier 		altq_disable(&ifp->if_snd);
54002b199f1SMax Laier 	if (ALTQ_IS_ATTACHED(&ifp->if_snd))
54102b199f1SMax Laier 		altq_detach(&ifp->if_snd);
54202b199f1SMax Laier #endif
5436182fdbdSPeter Wemm 
544212bd869SHajimu UMEMOTO 	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa; ifa = next) {
545212bd869SHajimu UMEMOTO 		next = TAILQ_NEXT(ifa, ifa_link);
546212bd869SHajimu UMEMOTO 
547212bd869SHajimu UMEMOTO 		if (ifa->ifa_addr->sa_family == AF_LINK)
548212bd869SHajimu UMEMOTO 			continue;
5490d0f9d1eSYoshinobu Inoue #ifdef INET
550aa6be122SWarner Losh 		/* XXX: Ugly!! ad hoc just for INET */
551aa6be122SWarner Losh 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET) {
552aa6be122SWarner Losh 			struct ifaliasreq ifr;
553aa6be122SWarner Losh 
554aa6be122SWarner Losh 			bzero(&ifr, sizeof(ifr));
555aa6be122SWarner Losh 			ifr.ifra_addr = *ifa->ifa_addr;
556aa6be122SWarner Losh 			if (ifa->ifa_dstaddr)
557aa6be122SWarner Losh 				ifr.ifra_broadaddr = *ifa->ifa_dstaddr;
558aa6be122SWarner Losh 			if (in_control(NULL, SIOCDIFADDR, (caddr_t)&ifr, ifp,
559aa6be122SWarner Losh 			    NULL) == 0)
560aa6be122SWarner Losh 				continue;
561aa6be122SWarner Losh 		}
5620d0f9d1eSYoshinobu Inoue #endif /* INET */
5630d0f9d1eSYoshinobu Inoue #ifdef INET6
5640d0f9d1eSYoshinobu Inoue 		if (ifa->ifa_addr && ifa->ifa_addr->sa_family == AF_INET6) {
56533841545SHajimu UMEMOTO 			in6_purgeaddr(ifa);
566978ee2edSJun-ichiro itojun Hagino 			/* ifp_addrhead is already updated */
5670d0f9d1eSYoshinobu Inoue 			continue;
5680d0f9d1eSYoshinobu Inoue 		}
5690d0f9d1eSYoshinobu Inoue #endif /* INET6 */
5706182fdbdSPeter Wemm 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
5716182fdbdSPeter Wemm 		IFAFREE(ifa);
5726182fdbdSPeter Wemm 	}
5736182fdbdSPeter Wemm 
57433841545SHajimu UMEMOTO #ifdef INET6
57533841545SHajimu UMEMOTO 	/*
57633841545SHajimu UMEMOTO 	 * Remove all IPv6 kernel structs related to ifp.  This should be done
57733841545SHajimu UMEMOTO 	 * before removing routing entries below, since IPv6 interface direct
57833841545SHajimu UMEMOTO 	 * routes are expected to be removed by the IPv6-specific kernel API.
57933841545SHajimu UMEMOTO 	 * Otherwise, the kernel will detect some inconsistency and bark it.
58033841545SHajimu UMEMOTO 	 */
58133841545SHajimu UMEMOTO 	in6_ifdetach(ifp);
58233841545SHajimu UMEMOTO #endif
583f4247b59SLuigi Rizzo 	/*
584f4247b59SLuigi Rizzo 	 * Remove address from ifindex_table[] and maybe decrement if_index.
585f4247b59SLuigi Rizzo 	 * Clean up all addresses.
586f4247b59SLuigi Rizzo 	 */
587b9907cd4SBrooks Davis 	ifnet_byindex(ifp->if_index) = NULL;
588f4247b59SLuigi Rizzo 	ifaddr_byindex(ifp->if_index) = NULL;
589f4247b59SLuigi Rizzo 	destroy_dev(ifdev_byindex(ifp->if_index));
590f4247b59SLuigi Rizzo 	ifdev_byindex(ifp->if_index) = NULL;
591f4247b59SLuigi Rizzo 
592f4247b59SLuigi Rizzo 	while (if_index > 0 && ifaddr_byindex(if_index) == NULL)
593f4247b59SLuigi Rizzo 		if_index--;
594f4247b59SLuigi Rizzo 
59533841545SHajimu UMEMOTO 
596212bd869SHajimu UMEMOTO 	/* We can now free link ifaddr. */
5973f35d515SPeter Pentchev 	if (!TAILQ_EMPTY(&ifp->if_addrhead)) {
598212bd869SHajimu UMEMOTO 		ifa = TAILQ_FIRST(&ifp->if_addrhead);
599212bd869SHajimu UMEMOTO 		TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
600212bd869SHajimu UMEMOTO 		IFAFREE(ifa);
6013f35d515SPeter Pentchev 	}
602212bd869SHajimu UMEMOTO 
6035500d3beSWarner Losh 	/*
6045500d3beSWarner Losh 	 * Delete all remaining routes using this interface
6055500d3beSWarner Losh 	 * Unfortuneatly the only way to do this is to slog through
6065500d3beSWarner Losh 	 * the entire routing table looking for routes which point
6075500d3beSWarner Losh 	 * to this interface...oh well...
6085500d3beSWarner Losh 	 */
6095500d3beSWarner Losh 	for (i = 1; i <= AF_MAX; i++) {
6105500d3beSWarner Losh 		if ((rnh = rt_tables[i]) == NULL)
6115500d3beSWarner Losh 			continue;
612956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_LOCK(rnh);
6135500d3beSWarner Losh 		(void) rnh->rnh_walktree(rnh, if_rtdel, ifp);
614956b0b65SJeffrey Hsu 		RADIX_NODE_HEAD_UNLOCK(rnh);
6155500d3beSWarner Losh 	}
6165500d3beSWarner Losh 
6177b6edd04SRuslan Ermilov 	/* Announce that the interface is gone. */
6187b6edd04SRuslan Ermilov 	rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
6197b6edd04SRuslan Ermilov 
620234a35c7SHajimu UMEMOTO 	IF_AFDATA_LOCK(ifp);
62131b1bfe1SHajimu UMEMOTO 	for (dp = domains; dp; dp = dp->dom_next) {
62231b1bfe1SHajimu UMEMOTO 		if (dp->dom_ifdetach && ifp->if_afdata[dp->dom_family])
62331b1bfe1SHajimu UMEMOTO 			(*dp->dom_ifdetach)(ifp,
62431b1bfe1SHajimu UMEMOTO 			    ifp->if_afdata[dp->dom_family]);
62531b1bfe1SHajimu UMEMOTO 	}
626234a35c7SHajimu UMEMOTO 	IF_AFDATA_UNLOCK(ifp);
62731b1bfe1SHajimu UMEMOTO 
628e70cd263SRobert Watson #ifdef MAC
629e70cd263SRobert Watson 	mac_destroy_ifnet(ifp);
630e70cd263SRobert Watson #endif /* MAC */
631ad3b9257SJohn-Mark Gurney 	KNOTE_UNLOCKED(&ifp->if_klist, NOTE_EXIT);
632ad3b9257SJohn-Mark Gurney 	knlist_clear(&ifp->if_klist, 0);
633ad3b9257SJohn-Mark Gurney 	knlist_destroy(&ifp->if_klist);
634b30a244cSJeffrey Hsu 	IFNET_WLOCK();
6353f35d515SPeter Pentchev  	found = 0;
6363f35d515SPeter Pentchev  	TAILQ_FOREACH(iter, &ifnet, if_link)
6373f35d515SPeter Pentchev  		if (iter == ifp) {
6383f35d515SPeter Pentchev  			found = 1;
6393f35d515SPeter Pentchev  			break;
6403f35d515SPeter Pentchev  		}
6413f35d515SPeter Pentchev  	if (found)
6426182fdbdSPeter Wemm  		TAILQ_REMOVE(&ifnet, ifp, if_link);
643b30a244cSJeffrey Hsu 	IFNET_WUNLOCK();
644df5e1987SJonathan Lemon 	mtx_destroy(&ifp->if_snd.ifq_mtx);
645234a35c7SHajimu UMEMOTO 	IF_AFDATA_DESTROY(ifp);
6465500d3beSWarner Losh 	splx(s);
6475500d3beSWarner Losh }
6485500d3beSWarner Losh 
6495500d3beSWarner Losh /*
6505500d3beSWarner Losh  * Delete Routes for a Network Interface
6515500d3beSWarner Losh  *
6525500d3beSWarner Losh  * Called for each routing entry via the rnh->rnh_walktree() call above
6535500d3beSWarner Losh  * to delete all route entries referencing a detaching network interface.
6545500d3beSWarner Losh  *
6555500d3beSWarner Losh  * Arguments:
6565500d3beSWarner Losh  *	rn	pointer to node in the routing table
6575500d3beSWarner Losh  *	arg	argument passed to rnh->rnh_walktree() - detaching interface
6585500d3beSWarner Losh  *
6595500d3beSWarner Losh  * Returns:
6605500d3beSWarner Losh  *	0	successful
6615500d3beSWarner Losh  *	errno	failed - reason indicated
6625500d3beSWarner Losh  *
6635500d3beSWarner Losh  */
6645500d3beSWarner Losh static int
66572fd1b6aSDag-Erling Smørgrav if_rtdel(struct radix_node *rn, void *arg)
6665500d3beSWarner Losh {
6675500d3beSWarner Losh 	struct rtentry	*rt = (struct rtentry *)rn;
6685500d3beSWarner Losh 	struct ifnet	*ifp = arg;
6695500d3beSWarner Losh 	int		err;
6705500d3beSWarner Losh 
6715500d3beSWarner Losh 	if (rt->rt_ifp == ifp) {
6725500d3beSWarner Losh 
6735500d3beSWarner Losh 		/*
6745500d3beSWarner Losh 		 * Protect (sorta) against walktree recursion problems
6755500d3beSWarner Losh 		 * with cloned routes
6765500d3beSWarner Losh 		 */
6775500d3beSWarner Losh 		if ((rt->rt_flags & RTF_UP) == 0)
6785500d3beSWarner Losh 			return (0);
6795500d3beSWarner Losh 
6805500d3beSWarner Losh 		err = rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway,
6815500d3beSWarner Losh 				rt_mask(rt), rt->rt_flags,
6825500d3beSWarner Losh 				(struct rtentry **) NULL);
6835500d3beSWarner Losh 		if (err) {
6845500d3beSWarner Losh 			log(LOG_WARNING, "if_rtdel: error %d\n", err);
6855500d3beSWarner Losh 		}
6865500d3beSWarner Losh 	}
6875500d3beSWarner Losh 
6885500d3beSWarner Losh 	return (0);
6896182fdbdSPeter Wemm }
6906182fdbdSPeter Wemm 
691d1dd20beSSam Leffler #define	equal(a1, a2)	(bcmp((a1), (a2), ((a1))->sa_len) == 0)
69219fc74fbSJeffrey Hsu 
69330aad87dSBrooks Davis /*
694df8bae1dSRodney W. Grimes  * Locate an interface based on a complete address.
695df8bae1dSRodney W. Grimes  */
696df8bae1dSRodney W. Grimes /*ARGSUSED*/
697df8bae1dSRodney W. Grimes struct ifaddr *
69872fd1b6aSDag-Erling Smørgrav ifa_ifwithaddr(struct sockaddr *addr)
699df8bae1dSRodney W. Grimes {
7000b59d917SJonathan Lemon 	struct ifnet *ifp;
7010b59d917SJonathan Lemon 	struct ifaddr *ifa;
702df8bae1dSRodney W. Grimes 
703b30a244cSJeffrey Hsu 	IFNET_RLOCK();
704fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link)
70537d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
706df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
707df8bae1dSRodney W. Grimes 				continue;
708df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr))
7090b59d917SJonathan Lemon 				goto done;
71082cd038dSYoshinobu Inoue 			/* IP6 doesn't have broadcast */
7110b59d917SJonathan Lemon 			if ((ifp->if_flags & IFF_BROADCAST) &&
7120b59d917SJonathan Lemon 			    ifa->ifa_broadaddr &&
71382cd038dSYoshinobu Inoue 			    ifa->ifa_broadaddr->sa_len != 0 &&
714df8bae1dSRodney W. Grimes 			    equal(ifa->ifa_broadaddr, addr))
7150b59d917SJonathan Lemon 				goto done;
7160b59d917SJonathan Lemon 		}
7170b59d917SJonathan Lemon 	ifa = NULL;
7180b59d917SJonathan Lemon done:
719b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
720df8bae1dSRodney W. Grimes 	return (ifa);
721df8bae1dSRodney W. Grimes }
7220b59d917SJonathan Lemon 
723df8bae1dSRodney W. Grimes /*
724df8bae1dSRodney W. Grimes  * Locate the point to point interface with a given destination address.
725df8bae1dSRodney W. Grimes  */
726df8bae1dSRodney W. Grimes /*ARGSUSED*/
727df8bae1dSRodney W. Grimes struct ifaddr *
72872fd1b6aSDag-Erling Smørgrav ifa_ifwithdstaddr(struct sockaddr *addr)
729df8bae1dSRodney W. Grimes {
7300b59d917SJonathan Lemon 	struct ifnet *ifp;
7310b59d917SJonathan Lemon 	struct ifaddr *ifa;
732df8bae1dSRodney W. Grimes 
733b30a244cSJeffrey Hsu 	IFNET_RLOCK();
7340b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
7350b59d917SJonathan Lemon 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
7360b59d917SJonathan Lemon 			continue;
73737d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
738df8bae1dSRodney W. Grimes 			if (ifa->ifa_addr->sa_family != addr->sa_family)
739df8bae1dSRodney W. Grimes 				continue;
74055088a1cSDavid Greenman 			if (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr))
7410b59d917SJonathan Lemon 				goto done;
742df8bae1dSRodney W. Grimes 		}
7430b59d917SJonathan Lemon 	}
7440b59d917SJonathan Lemon 	ifa = NULL;
7450b59d917SJonathan Lemon done:
746b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
7470b59d917SJonathan Lemon 	return (ifa);
748df8bae1dSRodney W. Grimes }
749df8bae1dSRodney W. Grimes 
750df8bae1dSRodney W. Grimes /*
751df8bae1dSRodney W. Grimes  * Find an interface on a specific network.  If many, choice
752df8bae1dSRodney W. Grimes  * is most specific found.
753df8bae1dSRodney W. Grimes  */
754df8bae1dSRodney W. Grimes struct ifaddr *
75572fd1b6aSDag-Erling Smørgrav ifa_ifwithnet(struct sockaddr *addr)
756df8bae1dSRodney W. Grimes {
75772fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
75872fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
759df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = (struct ifaddr *) 0;
760df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
761df8bae1dSRodney W. Grimes 	char *addr_data = addr->sa_data, *cplim;
762df8bae1dSRodney W. Grimes 
7637e2a6151SJulian Elischer 	/*
7647e2a6151SJulian Elischer 	 * AF_LINK addresses can be looked up directly by their index number,
7657e2a6151SJulian Elischer 	 * so do that if we can.
7667e2a6151SJulian Elischer 	 */
767df8bae1dSRodney W. Grimes 	if (af == AF_LINK) {
768d1dd20beSSam Leffler 	    struct sockaddr_dl *sdl = (struct sockaddr_dl *)addr;
769df8bae1dSRodney W. Grimes 	    if (sdl->sdl_index && sdl->sdl_index <= if_index)
770f9132cebSJonathan Lemon 		return (ifaddr_byindex(sdl->sdl_index));
771df8bae1dSRodney W. Grimes 	}
7727e2a6151SJulian Elischer 
7737e2a6151SJulian Elischer 	/*
7747e2a6151SJulian Elischer 	 * Scan though each interface, looking for ones that have
7757e2a6151SJulian Elischer 	 * addresses in this address family.
7767e2a6151SJulian Elischer 	 */
777b30a244cSJeffrey Hsu 	IFNET_RLOCK();
778fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
77937d40066SPoul-Henning Kamp 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
78072fd1b6aSDag-Erling Smørgrav 			char *cp, *cp2, *cp3;
781df8bae1dSRodney W. Grimes 
782523a02aaSDavid Greenman 			if (ifa->ifa_addr->sa_family != af)
783df8bae1dSRodney W. Grimes next:				continue;
784c61cd599SHajimu UMEMOTO 			if (af == AF_INET && ifp->if_flags & IFF_POINTOPOINT) {
7857e2a6151SJulian Elischer 				/*
7867e2a6151SJulian Elischer 				 * This is a bit broken as it doesn't
7877e2a6151SJulian Elischer 				 * take into account that the remote end may
7887e2a6151SJulian Elischer 				 * be a single node in the network we are
7897e2a6151SJulian Elischer 				 * looking for.
7907e2a6151SJulian Elischer 				 * The trouble is that we don't know the
7917e2a6151SJulian Elischer 				 * netmask for the remote end.
7927e2a6151SJulian Elischer 				 */
793fcd6781aSGarrett Wollman 				if (ifa->ifa_dstaddr != 0
794fcd6781aSGarrett Wollman 				    && equal(addr, ifa->ifa_dstaddr))
7950b59d917SJonathan Lemon 					goto done;
7963740e2adSDavid Greenman 			} else {
7977e2a6151SJulian Elischer 				/*
7987ed8f465SJulian Elischer 				 * if we have a special address handler,
7997ed8f465SJulian Elischer 				 * then use it instead of the generic one.
8007ed8f465SJulian Elischer 				 */
8017ed8f465SJulian Elischer 				if (ifa->ifa_claim_addr) {
8020b59d917SJonathan Lemon 					if ((*ifa->ifa_claim_addr)(ifa, addr))
8030b59d917SJonathan Lemon 						goto done;
8047ed8f465SJulian Elischer 					continue;
8057ed8f465SJulian Elischer 				}
8067ed8f465SJulian Elischer 
8077ed8f465SJulian Elischer 				/*
8087e2a6151SJulian Elischer 				 * Scan all the bits in the ifa's address.
8097e2a6151SJulian Elischer 				 * If a bit dissagrees with what we are
8107e2a6151SJulian Elischer 				 * looking for, mask it with the netmask
8117e2a6151SJulian Elischer 				 * to see if it really matters.
8127e2a6151SJulian Elischer 				 * (A byte at a time)
8137e2a6151SJulian Elischer 				 */
814523a02aaSDavid Greenman 				if (ifa->ifa_netmask == 0)
815523a02aaSDavid Greenman 					continue;
816df8bae1dSRodney W. Grimes 				cp = addr_data;
817df8bae1dSRodney W. Grimes 				cp2 = ifa->ifa_addr->sa_data;
818df8bae1dSRodney W. Grimes 				cp3 = ifa->ifa_netmask->sa_data;
8197e2a6151SJulian Elischer 				cplim = ifa->ifa_netmask->sa_len
8207e2a6151SJulian Elischer 					+ (char *)ifa->ifa_netmask;
821df8bae1dSRodney W. Grimes 				while (cp3 < cplim)
822df8bae1dSRodney W. Grimes 					if ((*cp++ ^ *cp2++) & *cp3++)
8237e2a6151SJulian Elischer 						goto next; /* next address! */
8247e2a6151SJulian Elischer 				/*
8257e2a6151SJulian Elischer 				 * If the netmask of what we just found
8267e2a6151SJulian Elischer 				 * is more specific than what we had before
8277e2a6151SJulian Elischer 				 * (if we had one) then remember the new one
8287e2a6151SJulian Elischer 				 * before continuing to search
8297e2a6151SJulian Elischer 				 * for an even better one.
8307e2a6151SJulian Elischer 				 */
831df8bae1dSRodney W. Grimes 				if (ifa_maybe == 0 ||
832df8bae1dSRodney W. Grimes 				    rn_refines((caddr_t)ifa->ifa_netmask,
833df8bae1dSRodney W. Grimes 				    (caddr_t)ifa_maybe->ifa_netmask))
834df8bae1dSRodney W. Grimes 					ifa_maybe = ifa;
835df8bae1dSRodney W. Grimes 			}
836b2af64fdSDavid Greenman 		}
837b2af64fdSDavid Greenman 	}
8380b59d917SJonathan Lemon 	ifa = ifa_maybe;
8390b59d917SJonathan Lemon done:
840b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
8410b59d917SJonathan Lemon 	return (ifa);
842df8bae1dSRodney W. Grimes }
843df8bae1dSRodney W. Grimes 
844df8bae1dSRodney W. Grimes /*
845df8bae1dSRodney W. Grimes  * Find an interface address specific to an interface best matching
846df8bae1dSRodney W. Grimes  * a given address.
847df8bae1dSRodney W. Grimes  */
848df8bae1dSRodney W. Grimes struct ifaddr *
84972fd1b6aSDag-Erling Smørgrav ifaof_ifpforaddr(struct sockaddr *addr, struct ifnet *ifp)
850df8bae1dSRodney W. Grimes {
85172fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
85272fd1b6aSDag-Erling Smørgrav 	char *cp, *cp2, *cp3;
85372fd1b6aSDag-Erling Smørgrav 	char *cplim;
854df8bae1dSRodney W. Grimes 	struct ifaddr *ifa_maybe = 0;
855df8bae1dSRodney W. Grimes 	u_int af = addr->sa_family;
856df8bae1dSRodney W. Grimes 
857df8bae1dSRodney W. Grimes 	if (af >= AF_MAX)
858df8bae1dSRodney W. Grimes 		return (0);
85937d40066SPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
860df8bae1dSRodney W. Grimes 		if (ifa->ifa_addr->sa_family != af)
861df8bae1dSRodney W. Grimes 			continue;
862381dd1d2SJulian Elischer 		if (ifa_maybe == 0)
863df8bae1dSRodney W. Grimes 			ifa_maybe = ifa;
864df8bae1dSRodney W. Grimes 		if (ifa->ifa_netmask == 0) {
865df8bae1dSRodney W. Grimes 			if (equal(addr, ifa->ifa_addr) ||
866df8bae1dSRodney W. Grimes 			    (ifa->ifa_dstaddr && equal(addr, ifa->ifa_dstaddr)))
8672defe5cdSJonathan Lemon 				goto done;
868df8bae1dSRodney W. Grimes 			continue;
869df8bae1dSRodney W. Grimes 		}
870b2af64fdSDavid Greenman 		if (ifp->if_flags & IFF_POINTOPOINT) {
871b2af64fdSDavid Greenman 			if (equal(addr, ifa->ifa_dstaddr))
872a8637146SJonathan Lemon 				goto done;
8733740e2adSDavid Greenman 		} else {
874df8bae1dSRodney W. Grimes 			cp = addr->sa_data;
875df8bae1dSRodney W. Grimes 			cp2 = ifa->ifa_addr->sa_data;
876df8bae1dSRodney W. Grimes 			cp3 = ifa->ifa_netmask->sa_data;
877df8bae1dSRodney W. Grimes 			cplim = ifa->ifa_netmask->sa_len + (char *)ifa->ifa_netmask;
878df8bae1dSRodney W. Grimes 			for (; cp3 < cplim; cp3++)
879df8bae1dSRodney W. Grimes 				if ((*cp++ ^ *cp2++) & *cp3)
880df8bae1dSRodney W. Grimes 					break;
881df8bae1dSRodney W. Grimes 			if (cp3 == cplim)
8822defe5cdSJonathan Lemon 				goto done;
883df8bae1dSRodney W. Grimes 		}
884b2af64fdSDavid Greenman 	}
885f9132cebSJonathan Lemon 	ifa = ifa_maybe;
886f9132cebSJonathan Lemon done:
887f9132cebSJonathan Lemon 	return (ifa);
888df8bae1dSRodney W. Grimes }
889df8bae1dSRodney W. Grimes 
890df8bae1dSRodney W. Grimes #include <net/route.h>
891df8bae1dSRodney W. Grimes 
892df8bae1dSRodney W. Grimes /*
893df8bae1dSRodney W. Grimes  * Default action when installing a route with a Link Level gateway.
894df8bae1dSRodney W. Grimes  * Lookup an appropriate real ifa to point to.
895df8bae1dSRodney W. Grimes  * This should be moved to /sys/net/link.c eventually.
896df8bae1dSRodney W. Grimes  */
8973bda9f9bSPoul-Henning Kamp static void
89872fd1b6aSDag-Erling Smørgrav link_rtrequest(int cmd, struct rtentry *rt, struct rt_addrinfo *info)
899df8bae1dSRodney W. Grimes {
90072fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa, *oifa;
901df8bae1dSRodney W. Grimes 	struct sockaddr *dst;
902df8bae1dSRodney W. Grimes 	struct ifnet *ifp;
903df8bae1dSRodney W. Grimes 
904d1dd20beSSam Leffler 	RT_LOCK_ASSERT(rt);
905d1dd20beSSam Leffler 
906df8bae1dSRodney W. Grimes 	if (cmd != RTM_ADD || ((ifa = rt->rt_ifa) == 0) ||
907df8bae1dSRodney W. Grimes 	    ((ifp = ifa->ifa_ifp) == 0) || ((dst = rt_key(rt)) == 0))
908df8bae1dSRodney W. Grimes 		return;
9099448326fSPoul-Henning Kamp 	ifa = ifaof_ifpforaddr(dst, ifp);
9109448326fSPoul-Henning Kamp 	if (ifa) {
91119fc74fbSJeffrey Hsu 		IFAREF(ifa);		/* XXX */
912d1dd20beSSam Leffler 		oifa = rt->rt_ifa;
913df8bae1dSRodney W. Grimes 		rt->rt_ifa = ifa;
914d1dd20beSSam Leffler 		IFAFREE(oifa);
915df8bae1dSRodney W. Grimes 		if (ifa->ifa_rtrequest && ifa->ifa_rtrequest != link_rtrequest)
9168071913dSRuslan Ermilov 			ifa->ifa_rtrequest(cmd, rt, info);
917df8bae1dSRodney W. Grimes 	}
918df8bae1dSRodney W. Grimes }
919df8bae1dSRodney W. Grimes 
920df8bae1dSRodney W. Grimes /*
921df8bae1dSRodney W. Grimes  * Mark an interface down and notify protocols of
922df8bae1dSRodney W. Grimes  * the transition.
923df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
924df8bae1dSRodney W. Grimes  */
9258614fb12SMax Laier static void
92672fd1b6aSDag-Erling Smørgrav if_unroute(struct ifnet *ifp, int flag, int fam)
927df8bae1dSRodney W. Grimes {
92872fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
929df8bae1dSRodney W. Grimes 
930e8c2601dSPoul-Henning Kamp 	ifp->if_flags &= ~flag;
93198b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
932e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
933e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
934df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFDOWN, ifa->ifa_addr);
935df8bae1dSRodney W. Grimes 	if_qflush(&ifp->if_snd);
936df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
937df8bae1dSRodney W. Grimes }
938df8bae1dSRodney W. Grimes 
939df8bae1dSRodney W. Grimes /*
940df8bae1dSRodney W. Grimes  * Mark an interface up and notify protocols of
941df8bae1dSRodney W. Grimes  * the transition.
942df8bae1dSRodney W. Grimes  * NOTE: must be called at splnet or eqivalent.
943df8bae1dSRodney W. Grimes  */
9448614fb12SMax Laier static void
94572fd1b6aSDag-Erling Smørgrav if_route(struct ifnet *ifp, int flag, int fam)
946df8bae1dSRodney W. Grimes {
94772fd1b6aSDag-Erling Smørgrav 	struct ifaddr *ifa;
948df8bae1dSRodney W. Grimes 
949e8c2601dSPoul-Henning Kamp 	ifp->if_flags |= flag;
95098b9590eSPoul-Henning Kamp 	getmicrotime(&ifp->if_lastchange);
951e8c2601dSPoul-Henning Kamp 	TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
952e8c2601dSPoul-Henning Kamp 		if (fam == PF_UNSPEC || (fam == ifa->ifa_addr->sa_family))
953df8bae1dSRodney W. Grimes 			pfctlinput(PRC_IFUP, ifa->ifa_addr);
954df8bae1dSRodney W. Grimes 	rt_ifmsg(ifp);
95582cd038dSYoshinobu Inoue #ifdef INET6
95682cd038dSYoshinobu Inoue 	in6_if_up(ifp);
95782cd038dSYoshinobu Inoue #endif
958df8bae1dSRodney W. Grimes }
959df8bae1dSRodney W. Grimes 
96094f5c9cfSSam Leffler void	(*vlan_link_state_p)(struct ifnet *, int);	/* XXX: private from if_vlan */
96194f5c9cfSSam Leffler 
96294f5c9cfSSam Leffler /*
96394f5c9cfSSam Leffler  * Handle a change in the interface link state.
96494f5c9cfSSam Leffler  */
96594f5c9cfSSam Leffler void
96694f5c9cfSSam Leffler if_link_state_change(struct ifnet *ifp, int link_state)
96794f5c9cfSSam Leffler {
96894f5c9cfSSam Leffler 	int link;
96994f5c9cfSSam Leffler 
97094f5c9cfSSam Leffler 	/* Notify that the link state has changed. */
97194f5c9cfSSam Leffler 	if (ifp->if_link_state != link_state) {
97294f5c9cfSSam Leffler 		ifp->if_link_state = link_state;
97394f5c9cfSSam Leffler 		rt_ifmsg(ifp);
97494f5c9cfSSam Leffler 		if (link_state == LINK_STATE_UP)
97594f5c9cfSSam Leffler 			link = NOTE_LINKUP;
97694f5c9cfSSam Leffler 		else if (link_state == LINK_STATE_DOWN)
97794f5c9cfSSam Leffler 			link = NOTE_LINKDOWN;
97894f5c9cfSSam Leffler 		else
97994f5c9cfSSam Leffler 			link = NOTE_LINKINV;
98094f5c9cfSSam Leffler 		KNOTE_UNLOCKED(&ifp->if_klist, link);
98194f5c9cfSSam Leffler 		if (ifp->if_nvlans != 0)
98294f5c9cfSSam Leffler 			(*vlan_link_state_p)(ifp, link);
9831c7899c7SGleb Smirnoff 
9841c7899c7SGleb Smirnoff 		if ((ifp->if_type == IFT_ETHER || ifp->if_type == IFT_L2VLAN) &&
9851c7899c7SGleb Smirnoff 		    IFP2AC(ifp)->ac_netgraph != NULL)
9861c7899c7SGleb Smirnoff 			(*ng_ether_link_state_p)(ifp, link_state);
98794f5c9cfSSam Leffler 	}
98894f5c9cfSSam Leffler }
98994f5c9cfSSam Leffler 
990df8bae1dSRodney W. Grimes /*
991e8c2601dSPoul-Henning Kamp  * Mark an interface down and notify protocols of
992e8c2601dSPoul-Henning Kamp  * the transition.
993e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
994e8c2601dSPoul-Henning Kamp  */
995e8c2601dSPoul-Henning Kamp void
99672fd1b6aSDag-Erling Smørgrav if_down(struct ifnet *ifp)
997e8c2601dSPoul-Henning Kamp {
998e8c2601dSPoul-Henning Kamp 
999e8c2601dSPoul-Henning Kamp 	if_unroute(ifp, IFF_UP, AF_UNSPEC);
1000e8c2601dSPoul-Henning Kamp }
1001e8c2601dSPoul-Henning Kamp 
1002e8c2601dSPoul-Henning Kamp /*
1003e8c2601dSPoul-Henning Kamp  * Mark an interface up and notify protocols of
1004e8c2601dSPoul-Henning Kamp  * the transition.
1005e8c2601dSPoul-Henning Kamp  * NOTE: must be called at splnet or eqivalent.
1006e8c2601dSPoul-Henning Kamp  */
1007e8c2601dSPoul-Henning Kamp void
100872fd1b6aSDag-Erling Smørgrav if_up(struct ifnet *ifp)
1009e8c2601dSPoul-Henning Kamp {
1010e8c2601dSPoul-Henning Kamp 
1011e8c2601dSPoul-Henning Kamp 	if_route(ifp, IFF_UP, AF_UNSPEC);
1012e8c2601dSPoul-Henning Kamp }
1013e8c2601dSPoul-Henning Kamp 
1014e8c2601dSPoul-Henning Kamp /*
1015df8bae1dSRodney W. Grimes  * Flush an interface queue.
1016df8bae1dSRodney W. Grimes  */
10173bda9f9bSPoul-Henning Kamp static void
101802b199f1SMax Laier if_qflush(struct ifaltq *ifq)
1019df8bae1dSRodney W. Grimes {
102072fd1b6aSDag-Erling Smørgrav 	struct mbuf *m, *n;
1021df8bae1dSRodney W. Grimes 
10227b21048cSMax Laier 	IFQ_LOCK(ifq);
102302b199f1SMax Laier #ifdef ALTQ
102402b199f1SMax Laier 	if (ALTQ_IS_ENABLED(ifq))
102502b199f1SMax Laier 		ALTQ_PURGE(ifq);
102602b199f1SMax Laier #endif
1027df8bae1dSRodney W. Grimes 	n = ifq->ifq_head;
10289448326fSPoul-Henning Kamp 	while ((m = n) != 0) {
1029df8bae1dSRodney W. Grimes 		n = m->m_act;
1030df8bae1dSRodney W. Grimes 		m_freem(m);
1031df8bae1dSRodney W. Grimes 	}
1032df8bae1dSRodney W. Grimes 	ifq->ifq_head = 0;
1033df8bae1dSRodney W. Grimes 	ifq->ifq_tail = 0;
1034df8bae1dSRodney W. Grimes 	ifq->ifq_len = 0;
10357b21048cSMax Laier 	IFQ_UNLOCK(ifq);
1036df8bae1dSRodney W. Grimes }
1037df8bae1dSRodney W. Grimes 
1038df8bae1dSRodney W. Grimes /*
1039df8bae1dSRodney W. Grimes  * Handle interface watchdog timer routines.  Called
1040df8bae1dSRodney W. Grimes  * from softclock, we decrement timers (if set) and
1041df8bae1dSRodney W. Grimes  * call the appropriate interface routine on expiration.
1042af5e59bfSRobert Watson  *
1043af5e59bfSRobert Watson  * XXXRW: Note that because timeouts run with Giant, if_watchdog() is called
1044af5e59bfSRobert Watson  * holding Giant.  If we switch to an MPSAFE callout, we likely need to grab
1045af5e59bfSRobert Watson  * Giant before entering if_watchdog() on an IFF_NEEDSGIANT interface.
1046df8bae1dSRodney W. Grimes  */
10473bda9f9bSPoul-Henning Kamp static void
104872fd1b6aSDag-Erling Smørgrav if_slowtimo(void *arg)
1049df8bae1dSRodney W. Grimes {
105072fd1b6aSDag-Erling Smørgrav 	struct ifnet *ifp;
1051df8bae1dSRodney W. Grimes 	int s = splimp();
1052df8bae1dSRodney W. Grimes 
1053b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1054fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
1055df8bae1dSRodney W. Grimes 		if (ifp->if_timer == 0 || --ifp->if_timer)
1056df8bae1dSRodney W. Grimes 			continue;
1057df8bae1dSRodney W. Grimes 		if (ifp->if_watchdog)
10584a5f1499SDavid Greenman 			(*ifp->if_watchdog)(ifp);
1059df8bae1dSRodney W. Grimes 	}
1060b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1061df8bae1dSRodney W. Grimes 	splx(s);
1062df8bae1dSRodney W. Grimes 	timeout(if_slowtimo, (void *)0, hz / IFNET_SLOWHZ);
1063df8bae1dSRodney W. Grimes }
1064df8bae1dSRodney W. Grimes 
1065df8bae1dSRodney W. Grimes /*
1066df8bae1dSRodney W. Grimes  * Map interface name to
1067df8bae1dSRodney W. Grimes  * interface structure pointer.
1068df8bae1dSRodney W. Grimes  */
1069df8bae1dSRodney W. Grimes struct ifnet *
107030aad87dSBrooks Davis ifunit(const char *name)
1071df8bae1dSRodney W. Grimes {
10728b7805e4SBoris Popov 	struct ifnet *ifp;
1073df8bae1dSRodney W. Grimes 
1074b30a244cSJeffrey Hsu 	IFNET_RLOCK();
1075fc2ffbe6SPoul-Henning Kamp 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
107636c19a57SBrooks Davis 		if (strncmp(name, ifp->if_xname, IFNAMSIZ) == 0)
1077df8bae1dSRodney W. Grimes 			break;
1078df8bae1dSRodney W. Grimes 	}
1079b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
1080df8bae1dSRodney W. Grimes 	return (ifp);
1081df8bae1dSRodney W. Grimes }
1082df8bae1dSRodney W. Grimes 
108382cd038dSYoshinobu Inoue /*
1084f13ad206SJonathan Lemon  * Hardware specific interface ioctls.
1085df8bae1dSRodney W. Grimes  */
1086f13ad206SJonathan Lemon static int
1087f13ad206SJonathan Lemon ifhwioctl(u_long cmd, struct ifnet *ifp, caddr_t data, struct thread *td)
1088df8bae1dSRodney W. Grimes {
1089f13ad206SJonathan Lemon 	struct ifreq *ifr;
1090413dd0baSPoul-Henning Kamp 	struct ifstat *ifs;
1091f13ad206SJonathan Lemon 	int error = 0;
109262f76486SMaxim Sobolev 	int new_flags;
109336c19a57SBrooks Davis 	size_t namelen, onamelen;
109436c19a57SBrooks Davis 	char new_name[IFNAMSIZ];
109536c19a57SBrooks Davis 	struct ifaddr *ifa;
109636c19a57SBrooks Davis 	struct sockaddr_dl *sdl;
1097df8bae1dSRodney W. Grimes 
1098df8bae1dSRodney W. Grimes 	ifr = (struct ifreq *)data;
109930aad87dSBrooks Davis 	switch (cmd) {
1100de593450SJonathan Lemon 	case SIOCGIFINDEX:
1101de593450SJonathan Lemon 		ifr->ifr_index = ifp->if_index;
1102de593450SJonathan Lemon 		break;
1103de593450SJonathan Lemon 
1104df8bae1dSRodney W. Grimes 	case SIOCGIFFLAGS:
110562f76486SMaxim Sobolev 		ifr->ifr_flags = ifp->if_flags & 0xffff;
110662f76486SMaxim Sobolev 		ifr->ifr_flagshigh = ifp->if_flags >> 16;
1107df8bae1dSRodney W. Grimes 		break;
1108df8bae1dSRodney W. Grimes 
1109016da741SJonathan Lemon 	case SIOCGIFCAP:
1110016da741SJonathan Lemon 		ifr->ifr_reqcap = ifp->if_capabilities;
1111016da741SJonathan Lemon 		ifr->ifr_curcap = ifp->if_capenable;
1112016da741SJonathan Lemon 		break;
1113016da741SJonathan Lemon 
11148f293a63SRobert Watson #ifdef MAC
11158f293a63SRobert Watson 	case SIOCGIFMAC:
111631566c96SJohn Baldwin 		error = mac_ioctl_ifnet_get(td->td_ucred, ifr, ifp);
11178f293a63SRobert Watson 		break;
11188f293a63SRobert Watson #endif
11198f293a63SRobert Watson 
1120df8bae1dSRodney W. Grimes 	case SIOCGIFMETRIC:
1121df8bae1dSRodney W. Grimes 		ifr->ifr_metric = ifp->if_metric;
1122df8bae1dSRodney W. Grimes 		break;
1123df8bae1dSRodney W. Grimes 
1124a7028af7SDavid Greenman 	case SIOCGIFMTU:
1125a7028af7SDavid Greenman 		ifr->ifr_mtu = ifp->if_mtu;
1126a7028af7SDavid Greenman 		break;
1127a7028af7SDavid Greenman 
1128074c4a4eSGarrett Wollman 	case SIOCGIFPHYS:
1129074c4a4eSGarrett Wollman 		ifr->ifr_phys = ifp->if_physical;
1130074c4a4eSGarrett Wollman 		break;
1131074c4a4eSGarrett Wollman 
1132df8bae1dSRodney W. Grimes 	case SIOCSIFFLAGS:
113344731cabSJohn Baldwin 		error = suser(td);
11349448326fSPoul-Henning Kamp 		if (error)
1135df8bae1dSRodney W. Grimes 			return (error);
113662f76486SMaxim Sobolev 		new_flags = (ifr->ifr_flags & 0xffff) |
113762f76486SMaxim Sobolev 		    (ifr->ifr_flagshigh << 16);
1138cf4b9371SPoul-Henning Kamp 		if (ifp->if_flags & IFF_SMART) {
1139cf4b9371SPoul-Henning Kamp 			/* Smart drivers twiddle their own routes */
11402f55ead7SPoul-Henning Kamp 		} else if (ifp->if_flags & IFF_UP &&
114162f76486SMaxim Sobolev 		    (new_flags & IFF_UP) == 0) {
1142df8bae1dSRodney W. Grimes 			int s = splimp();
1143df8bae1dSRodney W. Grimes 			if_down(ifp);
1144df8bae1dSRodney W. Grimes 			splx(s);
114562f76486SMaxim Sobolev 		} else if (new_flags & IFF_UP &&
1146cf4b9371SPoul-Henning Kamp 		    (ifp->if_flags & IFF_UP) == 0) {
1147df8bae1dSRodney W. Grimes 			int s = splimp();
1148df8bae1dSRodney W. Grimes 			if_up(ifp);
1149df8bae1dSRodney W. Grimes 			splx(s);
1150df8bae1dSRodney W. Grimes 		}
1151df8bae1dSRodney W. Grimes 		ifp->if_flags = (ifp->if_flags & IFF_CANTCHANGE) |
115262f76486SMaxim Sobolev 			(new_flags &~ IFF_CANTCHANGE);
1153ffb079beSMaxim Sobolev 		if (new_flags & IFF_PPROMISC) {
1154ffb079beSMaxim Sobolev 			/* Permanently promiscuous mode requested */
1155ffb079beSMaxim Sobolev 			ifp->if_flags |= IFF_PROMISC;
1156ffb079beSMaxim Sobolev 		} else if (ifp->if_pcount == 0) {
1157ffb079beSMaxim Sobolev 			ifp->if_flags &= ~IFF_PROMISC;
1158ffb079beSMaxim Sobolev 		}
115931302ebfSRobert Watson 		if (ifp->if_ioctl) {
116031302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1161df8bae1dSRodney W. Grimes 			(void) (*ifp->if_ioctl)(ifp, cmd, data);
116231302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
116331302ebfSRobert Watson 		}
116498b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1165df8bae1dSRodney W. Grimes 		break;
1166df8bae1dSRodney W. Grimes 
1167016da741SJonathan Lemon 	case SIOCSIFCAP:
116844731cabSJohn Baldwin 		error = suser(td);
1169016da741SJonathan Lemon 		if (error)
1170016da741SJonathan Lemon 			return (error);
1171efb4018bSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1172efb4018bSYaroslav Tykhiy 			return (EOPNOTSUPP);
1173016da741SJonathan Lemon 		if (ifr->ifr_reqcap & ~ifp->if_capabilities)
1174016da741SJonathan Lemon 			return (EINVAL);
117531302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1176efb4018bSYaroslav Tykhiy 		error = (*ifp->if_ioctl)(ifp, cmd, data);
117731302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1178efb4018bSYaroslav Tykhiy 		if (error == 0)
1179efb4018bSYaroslav Tykhiy 			getmicrotime(&ifp->if_lastchange);
1180016da741SJonathan Lemon 		break;
1181016da741SJonathan Lemon 
11828f293a63SRobert Watson #ifdef MAC
11838f293a63SRobert Watson 	case SIOCSIFMAC:
118431566c96SJohn Baldwin 		error = mac_ioctl_ifnet_set(td->td_ucred, ifr, ifp);
11858f293a63SRobert Watson 		break;
11868f293a63SRobert Watson #endif
11878f293a63SRobert Watson 
118836c19a57SBrooks Davis 	case SIOCSIFNAME:
118936c19a57SBrooks Davis 		error = suser(td);
1190bc1470f1SBrooks Davis 		if (error != 0)
119136c19a57SBrooks Davis 			return (error);
119236c19a57SBrooks Davis 		error = copyinstr(ifr->ifr_data, new_name, IFNAMSIZ, NULL);
1193bc1470f1SBrooks Davis 		if (error != 0)
119436c19a57SBrooks Davis 			return (error);
1195bc1470f1SBrooks Davis 		if (new_name[0] == '\0')
1196bc1470f1SBrooks Davis 			return (EINVAL);
119736c19a57SBrooks Davis 		if (ifunit(new_name) != NULL)
119836c19a57SBrooks Davis 			return (EEXIST);
119936c19a57SBrooks Davis 
120025a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_departure_event, ifp);
120136c19a57SBrooks Davis 		/* Announce the departure of the interface. */
120236c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_DEPARTURE);
120336c19a57SBrooks Davis 
120471672bb6SBrooks Davis 		log(LOG_INFO, "%s: changing name to '%s'\n",
120571672bb6SBrooks Davis 		    ifp->if_xname, new_name);
120671672bb6SBrooks Davis 
120736c19a57SBrooks Davis 		strlcpy(ifp->if_xname, new_name, sizeof(ifp->if_xname));
12089b98ee2cSLuigi Rizzo 		ifa = ifaddr_byindex(ifp->if_index);
120936c19a57SBrooks Davis 		IFA_LOCK(ifa);
121036c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_addr;
121136c19a57SBrooks Davis 		namelen = strlen(new_name);
121236c19a57SBrooks Davis 		onamelen = sdl->sdl_nlen;
121336c19a57SBrooks Davis 		/*
121436c19a57SBrooks Davis 		 * Move the address if needed.  This is safe because we
121536c19a57SBrooks Davis 		 * allocate space for a name of length IFNAMSIZ when we
121636c19a57SBrooks Davis 		 * create this in if_attach().
121736c19a57SBrooks Davis 		 */
121836c19a57SBrooks Davis 		if (namelen != onamelen) {
121936c19a57SBrooks Davis 			bcopy(sdl->sdl_data + onamelen,
122036c19a57SBrooks Davis 			    sdl->sdl_data + namelen, sdl->sdl_alen);
122136c19a57SBrooks Davis 		}
122236c19a57SBrooks Davis 		bcopy(new_name, sdl->sdl_data, namelen);
122336c19a57SBrooks Davis 		sdl->sdl_nlen = namelen;
122436c19a57SBrooks Davis 		sdl = (struct sockaddr_dl *)ifa->ifa_netmask;
122536c19a57SBrooks Davis 		bzero(sdl->sdl_data, onamelen);
122636c19a57SBrooks Davis 		while (namelen != 0)
122736c19a57SBrooks Davis 			sdl->sdl_data[--namelen] = 0xff;
122836c19a57SBrooks Davis 		IFA_UNLOCK(ifa);
122936c19a57SBrooks Davis 
123025a4adceSMax Laier 		EVENTHANDLER_INVOKE(ifnet_arrival_event, ifp);
123136c19a57SBrooks Davis 		/* Announce the return of the interface. */
123236c19a57SBrooks Davis 		rt_ifannouncemsg(ifp, IFAN_ARRIVAL);
123336c19a57SBrooks Davis 		break;
123436c19a57SBrooks Davis 
1235df8bae1dSRodney W. Grimes 	case SIOCSIFMETRIC:
123644731cabSJohn Baldwin 		error = suser(td);
12379448326fSPoul-Henning Kamp 		if (error)
1238df8bae1dSRodney W. Grimes 			return (error);
1239df8bae1dSRodney W. Grimes 		ifp->if_metric = ifr->ifr_metric;
124098b9590eSPoul-Henning Kamp 		getmicrotime(&ifp->if_lastchange);
1241df8bae1dSRodney W. Grimes 		break;
1242df8bae1dSRodney W. Grimes 
1243074c4a4eSGarrett Wollman 	case SIOCSIFPHYS:
124444731cabSJohn Baldwin 		error = suser(td);
1245e39a0280SGary Palmer 		if (error)
1246913e410eSYaroslav Tykhiy 			return (error);
1247913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1248913e410eSYaroslav Tykhiy 			return (EOPNOTSUPP);
124931302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1250e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
125131302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1252e39a0280SGary Palmer 		if (error == 0)
125398b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1254913e410eSYaroslav Tykhiy 		break;
1255074c4a4eSGarrett Wollman 
1256a7028af7SDavid Greenman 	case SIOCSIFMTU:
125782cd038dSYoshinobu Inoue 	{
125882cd038dSYoshinobu Inoue 		u_long oldmtu = ifp->if_mtu;
125982cd038dSYoshinobu Inoue 
126044731cabSJohn Baldwin 		error = suser(td);
12619448326fSPoul-Henning Kamp 		if (error)
1262a7028af7SDavid Greenman 			return (error);
1263aab3beeeSBrian Somers 		if (ifr->ifr_mtu < IF_MINMTU || ifr->ifr_mtu > IF_MAXMTU)
126475ee03cbSDavid Greenman 			return (EINVAL);
1265f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1266f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
126731302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1268e39a0280SGary Palmer 		error = (*ifp->if_ioctl)(ifp, cmd, data);
126931302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
127048f71763SRuslan Ermilov 		if (error == 0) {
127198b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
127248f71763SRuslan Ermilov 			rt_ifmsg(ifp);
127348f71763SRuslan Ermilov 		}
127482cd038dSYoshinobu Inoue 		/*
127582cd038dSYoshinobu Inoue 		 * If the link MTU changed, do network layer specific procedure.
127682cd038dSYoshinobu Inoue 		 */
127782cd038dSYoshinobu Inoue 		if (ifp->if_mtu != oldmtu) {
127882cd038dSYoshinobu Inoue #ifdef INET6
127982cd038dSYoshinobu Inoue 			nd6_setmtu(ifp);
128082cd038dSYoshinobu Inoue #endif
128182cd038dSYoshinobu Inoue 		}
1282f13ad206SJonathan Lemon 		break;
128382cd038dSYoshinobu Inoue 	}
1284a7028af7SDavid Greenman 
1285df8bae1dSRodney W. Grimes 	case SIOCADDMULTI:
1286df8bae1dSRodney W. Grimes 	case SIOCDELMULTI:
128744731cabSJohn Baldwin 		error = suser(td);
12889448326fSPoul-Henning Kamp 		if (error)
1289df8bae1dSRodney W. Grimes 			return (error);
1290477180fbSGarrett Wollman 
1291477180fbSGarrett Wollman 		/* Don't allow group membership on non-multicast interfaces. */
1292477180fbSGarrett Wollman 		if ((ifp->if_flags & IFF_MULTICAST) == 0)
1293f13ad206SJonathan Lemon 			return (EOPNOTSUPP);
1294477180fbSGarrett Wollman 
1295477180fbSGarrett Wollman 		/* Don't let users screw up protocols' entries. */
1296477180fbSGarrett Wollman 		if (ifr->ifr_addr.sa_family != AF_LINK)
1297f13ad206SJonathan Lemon 			return (EINVAL);
1298477180fbSGarrett Wollman 
1299477180fbSGarrett Wollman 		if (cmd == SIOCADDMULTI) {
1300477180fbSGarrett Wollman 			struct ifmultiaddr *ifma;
1301477180fbSGarrett Wollman 			error = if_addmulti(ifp, &ifr->ifr_addr, &ifma);
1302477180fbSGarrett Wollman 		} else {
1303477180fbSGarrett Wollman 			error = if_delmulti(ifp, &ifr->ifr_addr);
1304477180fbSGarrett Wollman 		}
1305e39a0280SGary Palmer 		if (error == 0)
130698b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1307f13ad206SJonathan Lemon 		break;
1308df8bae1dSRodney W. Grimes 
130941b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR:
131041b3e8e5SJun-ichiro itojun Hagino 	case SIOCDIFPHYADDR:
131141b3e8e5SJun-ichiro itojun Hagino #ifdef INET6
131241b3e8e5SJun-ichiro itojun Hagino 	case SIOCSIFPHYADDR_IN6:
131341b3e8e5SJun-ichiro itojun Hagino #endif
131433841545SHajimu UMEMOTO 	case SIOCSLIFPHYADDR:
1315a912e453SPeter Wemm 	case SIOCSIFMEDIA:
1316d7189ec6SJoerg Wunsch 	case SIOCSIFGENERIC:
131744731cabSJohn Baldwin 		error = suser(td);
1318a912e453SPeter Wemm 		if (error)
1319a912e453SPeter Wemm 			return (error);
1320f13ad206SJonathan Lemon 		if (ifp->if_ioctl == NULL)
1321a912e453SPeter Wemm 			return (EOPNOTSUPP);
132231302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1323a912e453SPeter Wemm 		error = (*ifp->if_ioctl)(ifp, cmd, data);
132431302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1325a912e453SPeter Wemm 		if (error == 0)
132698b9590eSPoul-Henning Kamp 			getmicrotime(&ifp->if_lastchange);
1327f13ad206SJonathan Lemon 		break;
1328a912e453SPeter Wemm 
1329413dd0baSPoul-Henning Kamp 	case SIOCGIFSTATUS:
1330413dd0baSPoul-Henning Kamp 		ifs = (struct ifstat *)data;
1331413dd0baSPoul-Henning Kamp 		ifs->ascii[0] = '\0';
1332413dd0baSPoul-Henning Kamp 
133333841545SHajimu UMEMOTO 	case SIOCGIFPSRCADDR:
133433841545SHajimu UMEMOTO 	case SIOCGIFPDSTADDR:
133533841545SHajimu UMEMOTO 	case SIOCGLIFPHYADDR:
1336a912e453SPeter Wemm 	case SIOCGIFMEDIA:
1337d7189ec6SJoerg Wunsch 	case SIOCGIFGENERIC:
1338913e410eSYaroslav Tykhiy 		if (ifp->if_ioctl == NULL)
1339a912e453SPeter Wemm 			return (EOPNOTSUPP);
134031302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1341f13ad206SJonathan Lemon 		error = (*ifp->if_ioctl)(ifp, cmd, data);
134231302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1343f13ad206SJonathan Lemon 		break;
1344a912e453SPeter Wemm 
1345b106252cSBill Paul 	case SIOCSIFLLADDR:
134644731cabSJohn Baldwin 		error = suser(td);
1347b106252cSBill Paul 		if (error)
1348b106252cSBill Paul 			return (error);
1349f13ad206SJonathan Lemon 		error = if_setlladdr(ifp,
135066ce51ceSArchie Cobbs 		    ifr->ifr_addr.sa_data, ifr->ifr_addr.sa_len);
1351f13ad206SJonathan Lemon 		break;
135266ce51ceSArchie Cobbs 
1353df8bae1dSRodney W. Grimes 	default:
1354f13ad206SJonathan Lemon 		error = ENOIOCTL;
1355f13ad206SJonathan Lemon 		break;
1356f13ad206SJonathan Lemon 	}
1357f13ad206SJonathan Lemon 	return (error);
1358f13ad206SJonathan Lemon }
1359f13ad206SJonathan Lemon 
1360f13ad206SJonathan Lemon /*
1361f13ad206SJonathan Lemon  * Interface ioctls.
1362f13ad206SJonathan Lemon  */
1363f13ad206SJonathan Lemon int
136472fd1b6aSDag-Erling Smørgrav ifioctl(struct socket *so, u_long cmd, caddr_t data, struct thread *td)
1365f13ad206SJonathan Lemon {
1366f13ad206SJonathan Lemon 	struct ifnet *ifp;
1367f13ad206SJonathan Lemon 	struct ifreq *ifr;
1368f13ad206SJonathan Lemon 	int error;
136962f76486SMaxim Sobolev 	int oif_flags;
1370f13ad206SJonathan Lemon 
1371f13ad206SJonathan Lemon 	switch (cmd) {
1372f13ad206SJonathan Lemon 	case SIOCGIFCONF:
1373f13ad206SJonathan Lemon 	case OSIOCGIFCONF:
1374f13ad206SJonathan Lemon 		return (ifconf(cmd, data));
1375f13ad206SJonathan Lemon 	}
1376f13ad206SJonathan Lemon 	ifr = (struct ifreq *)data;
1377f13ad206SJonathan Lemon 
1378f13ad206SJonathan Lemon 	switch (cmd) {
1379f13ad206SJonathan Lemon 	case SIOCIFCREATE:
1380f13ad206SJonathan Lemon 	case SIOCIFDESTROY:
138144731cabSJohn Baldwin 		if ((error = suser(td)) != 0)
1382f13ad206SJonathan Lemon 			return (error);
1383f13ad206SJonathan Lemon 		return ((cmd == SIOCIFCREATE) ?
1384f13ad206SJonathan Lemon 			if_clone_create(ifr->ifr_name, sizeof(ifr->ifr_name)) :
1385f13ad206SJonathan Lemon 			if_clone_destroy(ifr->ifr_name));
1386f13ad206SJonathan Lemon 
1387f13ad206SJonathan Lemon 	case SIOCIFGCLONERS:
1388f13ad206SJonathan Lemon 		return (if_clone_list((struct if_clonereq *)data));
1389f13ad206SJonathan Lemon 	}
1390f13ad206SJonathan Lemon 
1391f13ad206SJonathan Lemon 	ifp = ifunit(ifr->ifr_name);
1392f13ad206SJonathan Lemon 	if (ifp == 0)
1393f13ad206SJonathan Lemon 		return (ENXIO);
1394f13ad206SJonathan Lemon 
1395f13ad206SJonathan Lemon 	error = ifhwioctl(cmd, ifp, data, td);
1396f13ad206SJonathan Lemon 	if (error != ENOIOCTL)
1397f13ad206SJonathan Lemon 		return (error);
1398f13ad206SJonathan Lemon 
139982cd038dSYoshinobu Inoue 	oif_flags = ifp->if_flags;
1400df8bae1dSRodney W. Grimes 	if (so->so_proto == 0)
1401df8bae1dSRodney W. Grimes 		return (EOPNOTSUPP);
1402df8bae1dSRodney W. Grimes #ifndef COMPAT_43
140382cd038dSYoshinobu Inoue 	error = ((*so->so_proto->pr_usrreqs->pru_control)(so, cmd,
14042c37256eSGarrett Wollman 								 data,
1405b40ce416SJulian Elischer 								 ifp, td));
1406df8bae1dSRodney W. Grimes #else
1407df8bae1dSRodney W. Grimes 	{
1408df8bae1dSRodney W. Grimes 		int ocmd = cmd;
1409df8bae1dSRodney W. Grimes 
1410df8bae1dSRodney W. Grimes 		switch (cmd) {
1411df8bae1dSRodney W. Grimes 
1412df8bae1dSRodney W. Grimes 		case SIOCSIFDSTADDR:
1413df8bae1dSRodney W. Grimes 		case SIOCSIFADDR:
1414df8bae1dSRodney W. Grimes 		case SIOCSIFBRDADDR:
1415df8bae1dSRodney W. Grimes 		case SIOCSIFNETMASK:
1416df8bae1dSRodney W. Grimes #if BYTE_ORDER != BIG_ENDIAN
1417df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_family == 0 &&
1418df8bae1dSRodney W. Grimes 			    ifr->ifr_addr.sa_len < 16) {
1419df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_family = ifr->ifr_addr.sa_len;
1420df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1421df8bae1dSRodney W. Grimes 			}
1422df8bae1dSRodney W. Grimes #else
1423df8bae1dSRodney W. Grimes 			if (ifr->ifr_addr.sa_len == 0)
1424df8bae1dSRodney W. Grimes 				ifr->ifr_addr.sa_len = 16;
1425df8bae1dSRodney W. Grimes #endif
1426df8bae1dSRodney W. Grimes 			break;
1427df8bae1dSRodney W. Grimes 
1428df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1429df8bae1dSRodney W. Grimes 			cmd = SIOCGIFADDR;
1430df8bae1dSRodney W. Grimes 			break;
1431df8bae1dSRodney W. Grimes 
1432df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1433df8bae1dSRodney W. Grimes 			cmd = SIOCGIFDSTADDR;
1434df8bae1dSRodney W. Grimes 			break;
1435df8bae1dSRodney W. Grimes 
1436df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1437df8bae1dSRodney W. Grimes 			cmd = SIOCGIFBRDADDR;
1438df8bae1dSRodney W. Grimes 			break;
1439df8bae1dSRodney W. Grimes 
1440df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1441df8bae1dSRodney W. Grimes 			cmd = SIOCGIFNETMASK;
1442df8bae1dSRodney W. Grimes 		}
14432c37256eSGarrett Wollman 		error =  ((*so->so_proto->pr_usrreqs->pru_control)(so,
14442c37256eSGarrett Wollman 								   cmd,
14452c37256eSGarrett Wollman 								   data,
1446b40ce416SJulian Elischer 								   ifp, td));
1447df8bae1dSRodney W. Grimes 		switch (ocmd) {
1448df8bae1dSRodney W. Grimes 
1449df8bae1dSRodney W. Grimes 		case OSIOCGIFADDR:
1450df8bae1dSRodney W. Grimes 		case OSIOCGIFDSTADDR:
1451df8bae1dSRodney W. Grimes 		case OSIOCGIFBRDADDR:
1452df8bae1dSRodney W. Grimes 		case OSIOCGIFNETMASK:
1453df8bae1dSRodney W. Grimes 			*(u_short *)&ifr->ifr_addr = ifr->ifr_addr.sa_family;
145482cd038dSYoshinobu Inoue 
145582cd038dSYoshinobu Inoue 		}
145682cd038dSYoshinobu Inoue 	}
145782cd038dSYoshinobu Inoue #endif /* COMPAT_43 */
145882cd038dSYoshinobu Inoue 
145982cd038dSYoshinobu Inoue 	if ((oif_flags ^ ifp->if_flags) & IFF_UP) {
146082cd038dSYoshinobu Inoue #ifdef INET6
146188ff5695SSUZUKI Shinsuke 		DELAY(100);/* XXX: temporary workaround for fxp issue*/
146282cd038dSYoshinobu Inoue 		if (ifp->if_flags & IFF_UP) {
146382cd038dSYoshinobu Inoue 			int s = splimp();
146482cd038dSYoshinobu Inoue 			in6_if_up(ifp);
146582cd038dSYoshinobu Inoue 			splx(s);
146682cd038dSYoshinobu Inoue 		}
146782cd038dSYoshinobu Inoue #endif
1468df8bae1dSRodney W. Grimes 	}
1469df8bae1dSRodney W. Grimes 	return (error);
1470df8bae1dSRodney W. Grimes }
1471df8bae1dSRodney W. Grimes 
1472df8bae1dSRodney W. Grimes /*
1473963e4c2aSGarrett Wollman  * Set/clear promiscuous mode on interface ifp based on the truth value
1474963e4c2aSGarrett Wollman  * of pswitch.  The calls are reference counted so that only the first
1475963e4c2aSGarrett Wollman  * "on" request actually has an effect, as does the final "off" request.
1476963e4c2aSGarrett Wollman  * Results are undefined if the "off" and "on" requests are not matched.
1477963e4c2aSGarrett Wollman  */
1478963e4c2aSGarrett Wollman int
147972fd1b6aSDag-Erling Smørgrav ifpromisc(struct ifnet *ifp, int pswitch)
1480963e4c2aSGarrett Wollman {
1481963e4c2aSGarrett Wollman 	struct ifreq ifr;
14824a26224cSGarrett Wollman 	int error;
14834f3c11a6SBill Fenner 	int oldflags, oldpcount;
1484963e4c2aSGarrett Wollman 
14854f3c11a6SBill Fenner 	oldpcount = ifp->if_pcount;
14862c514a31SBrian Somers 	oldflags = ifp->if_flags;
1487ffb079beSMaxim Sobolev 	if (ifp->if_flags & IFF_PPROMISC) {
1488ffb079beSMaxim Sobolev 		/* Do nothing if device is in permanently promiscuous mode */
1489ffb079beSMaxim Sobolev 		ifp->if_pcount += pswitch ? 1 : -1;
1490ffb079beSMaxim Sobolev 		return (0);
1491ffb079beSMaxim Sobolev 	}
1492963e4c2aSGarrett Wollman 	if (pswitch) {
1493963e4c2aSGarrett Wollman 		/*
1494963e4c2aSGarrett Wollman 		 * If the device is not configured up, we cannot put it in
1495963e4c2aSGarrett Wollman 		 * promiscuous mode.
1496963e4c2aSGarrett Wollman 		 */
1497963e4c2aSGarrett Wollman 		if ((ifp->if_flags & IFF_UP) == 0)
1498963e4c2aSGarrett Wollman 			return (ENETDOWN);
1499963e4c2aSGarrett Wollman 		if (ifp->if_pcount++ != 0)
1500963e4c2aSGarrett Wollman 			return (0);
1501963e4c2aSGarrett Wollman 		ifp->if_flags |= IFF_PROMISC;
1502963e4c2aSGarrett Wollman 	} else {
1503963e4c2aSGarrett Wollman 		if (--ifp->if_pcount > 0)
1504963e4c2aSGarrett Wollman 			return (0);
1505963e4c2aSGarrett Wollman 		ifp->if_flags &= ~IFF_PROMISC;
1506963e4c2aSGarrett Wollman 	}
150762f76486SMaxim Sobolev 	ifr.ifr_flags = ifp->if_flags & 0xffff;
150862f76486SMaxim Sobolev 	ifr.ifr_flagshigh = ifp->if_flags >> 16;
150931302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
15104a26224cSGarrett Wollman 	error = (*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
151131302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
15124f3c11a6SBill Fenner 	if (error == 0) {
15139bf40edeSBrooks Davis 		log(LOG_INFO, "%s: promiscuous mode %s\n",
15149bf40edeSBrooks Davis 		    ifp->if_xname,
15154f3c11a6SBill Fenner 		    (ifp->if_flags & IFF_PROMISC) ? "enabled" : "disabled");
15164a26224cSGarrett Wollman 		rt_ifmsg(ifp);
15174f3c11a6SBill Fenner 	} else {
15184f3c11a6SBill Fenner 		ifp->if_pcount = oldpcount;
15192c514a31SBrian Somers 		ifp->if_flags = oldflags;
15204f3c11a6SBill Fenner 	}
15214a26224cSGarrett Wollman 	return error;
1522963e4c2aSGarrett Wollman }
1523963e4c2aSGarrett Wollman 
1524963e4c2aSGarrett Wollman /*
1525df8bae1dSRodney W. Grimes  * Return interface configuration
1526df8bae1dSRodney W. Grimes  * of system.  List may be used
1527df8bae1dSRodney W. Grimes  * in later ioctl's (above) to get
1528df8bae1dSRodney W. Grimes  * other information.
1529df8bae1dSRodney W. Grimes  */
1530df8bae1dSRodney W. Grimes /*ARGSUSED*/
15313bda9f9bSPoul-Henning Kamp static int
153272fd1b6aSDag-Erling Smørgrav ifconf(u_long cmd, caddr_t data)
1533df8bae1dSRodney W. Grimes {
15340b59d917SJonathan Lemon 	struct ifconf *ifc = (struct ifconf *)data;
15350b59d917SJonathan Lemon 	struct ifnet *ifp;
15360b59d917SJonathan Lemon 	struct ifaddr *ifa;
15374dcf2bbbSBrooks Davis 	struct ifreq ifr;
15384dcf2bbbSBrooks Davis 	struct sbuf *sb;
15394dcf2bbbSBrooks Davis 	int error, full = 0, valid_len, max_len;
1540df8bae1dSRodney W. Grimes 
15414dcf2bbbSBrooks Davis 	/* Limit initial buffer size to MAXPHYS to avoid DoS from userspace. */
15424dcf2bbbSBrooks Davis 	max_len = MAXPHYS - 1;
15434dcf2bbbSBrooks Davis 
15444dcf2bbbSBrooks Davis again:
15454dcf2bbbSBrooks Davis 	if (ifc->ifc_len <= max_len) {
15464dcf2bbbSBrooks Davis 		max_len = ifc->ifc_len;
15474dcf2bbbSBrooks Davis 		full = 1;
15484dcf2bbbSBrooks Davis 	}
15494dcf2bbbSBrooks Davis 	sb = sbuf_new(NULL, NULL, max_len + 1, SBUF_FIXEDLEN);
15504dcf2bbbSBrooks Davis 	max_len = 0;
15514dcf2bbbSBrooks Davis 	valid_len = 0;
15524dcf2bbbSBrooks Davis 
1553b30a244cSJeffrey Hsu 	IFNET_RLOCK();		/* could sleep XXX */
15540b59d917SJonathan Lemon 	TAILQ_FOREACH(ifp, &ifnet, if_link) {
15559bf40edeSBrooks Davis 		int addrs;
15562624cf89SGarrett Wollman 
15579bf40edeSBrooks Davis 		if (strlcpy(ifr.ifr_name, ifp->if_xname, sizeof(ifr.ifr_name))
15584dcf2bbbSBrooks Davis 		    >= sizeof(ifr.ifr_name))
15594dcf2bbbSBrooks Davis 			return (ENAMETOOLONG);
15602624cf89SGarrett Wollman 
156175c13541SPoul-Henning Kamp 		addrs = 0;
15622defe5cdSJonathan Lemon 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
15632defe5cdSJonathan Lemon 			struct sockaddr *sa = ifa->ifa_addr;
15642defe5cdSJonathan Lemon 
1565a854ed98SJohn Baldwin 			if (jailed(curthread->td_ucred) &&
1566a854ed98SJohn Baldwin 			    prison_if(curthread->td_ucred, sa))
156775c13541SPoul-Henning Kamp 				continue;
156875c13541SPoul-Henning Kamp 			addrs++;
1569df8bae1dSRodney W. Grimes #ifdef COMPAT_43
1570df8bae1dSRodney W. Grimes 			if (cmd == OSIOCGIFCONF) {
1571df8bae1dSRodney W. Grimes 				struct osockaddr *osa =
1572df8bae1dSRodney W. Grimes 					 (struct osockaddr *)&ifr.ifr_addr;
1573df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
1574df8bae1dSRodney W. Grimes 				osa->sa_family = sa->sa_family;
15754dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
15764dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1577df8bae1dSRodney W. Grimes 			} else
1578df8bae1dSRodney W. Grimes #endif
1579df8bae1dSRodney W. Grimes 			if (sa->sa_len <= sizeof(*sa)) {
1580df8bae1dSRodney W. Grimes 				ifr.ifr_addr = *sa;
15814dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr, sizeof(ifr));
15824dcf2bbbSBrooks Davis 				max_len += sizeof(ifr);
1583df8bae1dSRodney W. Grimes 			} else {
15844dcf2bbbSBrooks Davis 				sbuf_bcat(sb, &ifr,
15854dcf2bbbSBrooks Davis 				    offsetof(struct ifreq, ifr_addr));
15864dcf2bbbSBrooks Davis 				max_len += offsetof(struct ifreq, ifr_addr);
15874dcf2bbbSBrooks Davis 				sbuf_bcat(sb, sa, sa->sa_len);
15884dcf2bbbSBrooks Davis 				max_len += sa->sa_len;
1589df8bae1dSRodney W. Grimes 			}
15904dcf2bbbSBrooks Davis 
15914dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
15924dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
1593df8bae1dSRodney W. Grimes 		}
15944dcf2bbbSBrooks Davis 		if (addrs == 0) {
159575c13541SPoul-Henning Kamp 			bzero((caddr_t)&ifr.ifr_addr, sizeof(ifr.ifr_addr));
15964dcf2bbbSBrooks Davis 			sbuf_bcat(sb, &ifr, sizeof(ifr));
15974dcf2bbbSBrooks Davis 			max_len += sizeof(ifr);
15984dcf2bbbSBrooks Davis 
15994dcf2bbbSBrooks Davis 			if (!sbuf_overflowed(sb))
16004dcf2bbbSBrooks Davis 				valid_len = sbuf_len(sb);
160175c13541SPoul-Henning Kamp 		}
1602df8bae1dSRodney W. Grimes 	}
1603b30a244cSJeffrey Hsu 	IFNET_RUNLOCK();
16044dcf2bbbSBrooks Davis 
16054dcf2bbbSBrooks Davis 	/*
16064dcf2bbbSBrooks Davis 	 * If we didn't allocate enough space (uncommon), try again.  If
16074dcf2bbbSBrooks Davis 	 * we have already allocated as much space as we are allowed,
16084dcf2bbbSBrooks Davis 	 * return what we've got.
16094dcf2bbbSBrooks Davis 	 */
16104dcf2bbbSBrooks Davis 	if (valid_len != max_len && !full) {
16114dcf2bbbSBrooks Davis 		sbuf_delete(sb);
16124dcf2bbbSBrooks Davis 		goto again;
16134dcf2bbbSBrooks Davis 	}
16144dcf2bbbSBrooks Davis 
16154dcf2bbbSBrooks Davis 	ifc->ifc_len = valid_len;
16165ed8cedcSBrian Feldman 	sbuf_finish(sb);
16174dcf2bbbSBrooks Davis 	error = copyout(sbuf_data(sb), ifc->ifc_req, ifc->ifc_len);
16184dcf2bbbSBrooks Davis 	sbuf_delete(sb);
1619df8bae1dSRodney W. Grimes 	return (error);
1620df8bae1dSRodney W. Grimes }
1621df8bae1dSRodney W. Grimes 
16221158dfb7SGarrett Wollman /*
16231158dfb7SGarrett Wollman  * Just like if_promisc(), but for all-multicast-reception mode.
16241158dfb7SGarrett Wollman  */
16251158dfb7SGarrett Wollman int
162672fd1b6aSDag-Erling Smørgrav if_allmulti(struct ifnet *ifp, int onswitch)
16271158dfb7SGarrett Wollman {
16281158dfb7SGarrett Wollman 	int error = 0;
16291158dfb7SGarrett Wollman 	int s = splimp();
1630ee0a4f7eSSUZUKI Shinsuke 	struct ifreq ifr;
16311158dfb7SGarrett Wollman 
16321158dfb7SGarrett Wollman 	if (onswitch) {
16331158dfb7SGarrett Wollman 		if (ifp->if_amcount++ == 0) {
16341158dfb7SGarrett Wollman 			ifp->if_flags |= IFF_ALLMULTI;
163562f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;
163662f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
163731302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1638ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
163931302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
16401158dfb7SGarrett Wollman 		}
16411158dfb7SGarrett Wollman 	} else {
16421158dfb7SGarrett Wollman 		if (ifp->if_amcount > 1) {
16431158dfb7SGarrett Wollman 			ifp->if_amcount--;
16441158dfb7SGarrett Wollman 		} else {
16451158dfb7SGarrett Wollman 			ifp->if_amcount = 0;
16461158dfb7SGarrett Wollman 			ifp->if_flags &= ~IFF_ALLMULTI;
164762f76486SMaxim Sobolev 			ifr.ifr_flags = ifp->if_flags & 0xffff;;
164862f76486SMaxim Sobolev 			ifr.ifr_flagshigh = ifp->if_flags >> 16;
164931302ebfSRobert Watson 			IFF_LOCKGIANT(ifp);
1650ee0a4f7eSSUZUKI Shinsuke 			error = ifp->if_ioctl(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
165131302ebfSRobert Watson 			IFF_UNLOCKGIANT(ifp);
16521158dfb7SGarrett Wollman 		}
16531158dfb7SGarrett Wollman 	}
16541158dfb7SGarrett Wollman 	splx(s);
16554a26224cSGarrett Wollman 
16564a26224cSGarrett Wollman 	if (error == 0)
16574a26224cSGarrett Wollman 		rt_ifmsg(ifp);
16581158dfb7SGarrett Wollman 	return error;
16591158dfb7SGarrett Wollman }
16601158dfb7SGarrett Wollman 
16611158dfb7SGarrett Wollman /*
16621158dfb7SGarrett Wollman  * Add a multicast listenership to the interface in question.
16631158dfb7SGarrett Wollman  * The link layer provides a routine which converts
16641158dfb7SGarrett Wollman  */
16651158dfb7SGarrett Wollman int
166672fd1b6aSDag-Erling Smørgrav if_addmulti(struct ifnet *ifp, struct sockaddr *sa, struct ifmultiaddr **retifma)
16671158dfb7SGarrett Wollman {
16681158dfb7SGarrett Wollman 	struct sockaddr *llsa, *dupsa;
16691158dfb7SGarrett Wollman 	int error, s;
16701158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
16711158dfb7SGarrett Wollman 
167257af7922SJulian Elischer 	/*
167357af7922SJulian Elischer 	 * If the matching multicast address already exists
167457af7922SJulian Elischer 	 * then don't add a new one, just add a reference
167557af7922SJulian Elischer 	 */
16766817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
167757af7922SJulian Elischer 		if (equal(sa, ifma->ifma_addr)) {
16781158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
167957af7922SJulian Elischer 			if (retifma)
168057af7922SJulian Elischer 				*retifma = ifma;
16811158dfb7SGarrett Wollman 			return 0;
16821158dfb7SGarrett Wollman 		}
168357af7922SJulian Elischer 	}
16841158dfb7SGarrett Wollman 
16851158dfb7SGarrett Wollman 	/*
16861158dfb7SGarrett Wollman 	 * Give the link layer a chance to accept/reject it, and also
16871158dfb7SGarrett Wollman 	 * find out which AF_LINK address this maps to, if it isn't one
16881158dfb7SGarrett Wollman 	 * already.
16891158dfb7SGarrett Wollman 	 */
16901158dfb7SGarrett Wollman 	if (ifp->if_resolvemulti) {
16911158dfb7SGarrett Wollman 		error = ifp->if_resolvemulti(ifp, &llsa, sa);
16921158dfb7SGarrett Wollman 		if (error) return error;
16931158dfb7SGarrett Wollman 	} else {
16941158dfb7SGarrett Wollman 		llsa = 0;
16951158dfb7SGarrett Wollman 	}
16961158dfb7SGarrett Wollman 
1697a163d034SWarner Losh 	MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma, M_IFMADDR, M_WAITOK);
1698a163d034SWarner Losh 	MALLOC(dupsa, struct sockaddr *, sa->sa_len, M_IFMADDR, M_WAITOK);
16991158dfb7SGarrett Wollman 	bcopy(sa, dupsa, sa->sa_len);
17001158dfb7SGarrett Wollman 
17011158dfb7SGarrett Wollman 	ifma->ifma_addr = dupsa;
17021158dfb7SGarrett Wollman 	ifma->ifma_lladdr = llsa;
17031158dfb7SGarrett Wollman 	ifma->ifma_ifp = ifp;
17041158dfb7SGarrett Wollman 	ifma->ifma_refcount = 1;
1705373f88edSGarrett Wollman 	ifma->ifma_protospec = 0;
1706477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_NEWMADDR, ifma);
1707373f88edSGarrett Wollman 
17081158dfb7SGarrett Wollman 	/*
17091158dfb7SGarrett Wollman 	 * Some network interfaces can scan the address list at
17101158dfb7SGarrett Wollman 	 * interrupt time; lock them out.
17111158dfb7SGarrett Wollman 	 */
17121158dfb7SGarrett Wollman 	s = splimp();
17136817526dSPoul-Henning Kamp 	TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
17141158dfb7SGarrett Wollman 	splx(s);
171513990766SJonathan Mini 	if (retifma != NULL)
1716373f88edSGarrett Wollman 		*retifma = ifma;
17171158dfb7SGarrett Wollman 
17181158dfb7SGarrett Wollman 	if (llsa != 0) {
17196817526dSPoul-Henning Kamp 		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
17201158dfb7SGarrett Wollman 			if (equal(ifma->ifma_addr, llsa))
17211158dfb7SGarrett Wollman 				break;
17221158dfb7SGarrett Wollman 		}
17231158dfb7SGarrett Wollman 		if (ifma) {
17241158dfb7SGarrett Wollman 			ifma->ifma_refcount++;
17251158dfb7SGarrett Wollman 		} else {
17261158dfb7SGarrett Wollman 			MALLOC(ifma, struct ifmultiaddr *, sizeof *ifma,
1727a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1728477180fbSGarrett Wollman 			MALLOC(dupsa, struct sockaddr *, llsa->sa_len,
1729a163d034SWarner Losh 			       M_IFMADDR, M_WAITOK);
1730477180fbSGarrett Wollman 			bcopy(llsa, dupsa, llsa->sa_len);
1731477180fbSGarrett Wollman 			ifma->ifma_addr = dupsa;
173289eaef50SHajimu UMEMOTO 			ifma->ifma_lladdr = NULL;
17331158dfb7SGarrett Wollman 			ifma->ifma_ifp = ifp;
17341158dfb7SGarrett Wollman 			ifma->ifma_refcount = 1;
173589eaef50SHajimu UMEMOTO 			ifma->ifma_protospec = 0;
17361158dfb7SGarrett Wollman 			s = splimp();
17376817526dSPoul-Henning Kamp 			TAILQ_INSERT_HEAD(&ifp->if_multiaddrs, ifma, ifma_link);
17381158dfb7SGarrett Wollman 			splx(s);
17391158dfb7SGarrett Wollman 		}
174057af7922SJulian Elischer 	}
17411158dfb7SGarrett Wollman 	/*
17421158dfb7SGarrett Wollman 	 * We are certain we have added something, so call down to the
17431158dfb7SGarrett Wollman 	 * interface to let them know about it.
17441158dfb7SGarrett Wollman 	 */
17451158dfb7SGarrett Wollman 	s = splimp();
174631302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
17471158dfb7SGarrett Wollman 	ifp->if_ioctl(ifp, SIOCADDMULTI, 0);
174831302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
17491158dfb7SGarrett Wollman 	splx(s);
17501158dfb7SGarrett Wollman 
17511158dfb7SGarrett Wollman 	return 0;
17521158dfb7SGarrett Wollman }
17531158dfb7SGarrett Wollman 
17541158dfb7SGarrett Wollman /*
17551158dfb7SGarrett Wollman  * Remove a reference to a multicast address on this interface.  Yell
17561158dfb7SGarrett Wollman  * if the request does not match an existing membership.
17571158dfb7SGarrett Wollman  */
17581158dfb7SGarrett Wollman int
175972fd1b6aSDag-Erling Smørgrav if_delmulti(struct ifnet *ifp, struct sockaddr *sa)
17601158dfb7SGarrett Wollman {
17611158dfb7SGarrett Wollman 	struct ifmultiaddr *ifma;
17621158dfb7SGarrett Wollman 	int s;
17631158dfb7SGarrett Wollman 
17646817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
17651158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
17661158dfb7SGarrett Wollman 			break;
17671158dfb7SGarrett Wollman 	if (ifma == 0)
17681158dfb7SGarrett Wollman 		return ENOENT;
17691158dfb7SGarrett Wollman 
17701158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
17711158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
17721158dfb7SGarrett Wollman 		return 0;
17731158dfb7SGarrett Wollman 	}
17741158dfb7SGarrett Wollman 
1775477180fbSGarrett Wollman 	rt_newmaddrmsg(RTM_DELMADDR, ifma);
17761158dfb7SGarrett Wollman 	sa = ifma->ifma_lladdr;
17771158dfb7SGarrett Wollman 	s = splimp();
17786817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
1779ccb7cc8dSYaroslav Tykhiy 	/*
1780ccb7cc8dSYaroslav Tykhiy 	 * Make sure the interface driver is notified
1781ccb7cc8dSYaroslav Tykhiy 	 * in the case of a link layer mcast group being left.
1782ccb7cc8dSYaroslav Tykhiy 	 */
178331302ebfSRobert Watson 	if (ifma->ifma_addr->sa_family == AF_LINK && sa == 0) {
178431302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
1785ccb7cc8dSYaroslav Tykhiy 		ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
178631302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
178731302ebfSRobert Watson 	}
17881158dfb7SGarrett Wollman 	splx(s);
17891158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
17901158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
17911158dfb7SGarrett Wollman 	if (sa == 0)
17921158dfb7SGarrett Wollman 		return 0;
17931158dfb7SGarrett Wollman 
17941158dfb7SGarrett Wollman 	/*
17951158dfb7SGarrett Wollman 	 * Now look for the link-layer address which corresponds to
17961158dfb7SGarrett Wollman 	 * this network address.  It had been squirreled away in
17971158dfb7SGarrett Wollman 	 * ifma->ifma_lladdr for this purpose (so we don't have
17981158dfb7SGarrett Wollman 	 * to call ifp->if_resolvemulti() again), and we saved that
17991158dfb7SGarrett Wollman 	 * value in sa above.  If some nasty deleted the
18001158dfb7SGarrett Wollman 	 * link-layer address out from underneath us, we can deal because
18011158dfb7SGarrett Wollman 	 * the address we stored was is not the same as the one which was
18021158dfb7SGarrett Wollman 	 * in the record for the link-layer address.  (So we don't complain
18031158dfb7SGarrett Wollman 	 * in that case.)
18041158dfb7SGarrett Wollman 	 */
18056817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
18061158dfb7SGarrett Wollman 		if (equal(sa, ifma->ifma_addr))
18071158dfb7SGarrett Wollman 			break;
18081158dfb7SGarrett Wollman 	if (ifma == 0)
18091158dfb7SGarrett Wollman 		return 0;
18101158dfb7SGarrett Wollman 
18111158dfb7SGarrett Wollman 	if (ifma->ifma_refcount > 1) {
18121158dfb7SGarrett Wollman 		ifma->ifma_refcount--;
18131158dfb7SGarrett Wollman 		return 0;
18141158dfb7SGarrett Wollman 	}
18151158dfb7SGarrett Wollman 
18161158dfb7SGarrett Wollman 	s = splimp();
18176817526dSPoul-Henning Kamp 	TAILQ_REMOVE(&ifp->if_multiaddrs, ifma, ifma_link);
181831302ebfSRobert Watson 	IFF_LOCKGIANT(ifp);
1819c7323482SBill Paul 	ifp->if_ioctl(ifp, SIOCDELMULTI, 0);
182031302ebfSRobert Watson 	IFF_UNLOCKGIANT(ifp);
18211158dfb7SGarrett Wollman 	splx(s);
18221158dfb7SGarrett Wollman 	free(ifma->ifma_addr, M_IFMADDR);
18231158dfb7SGarrett Wollman 	free(sa, M_IFMADDR);
18241158dfb7SGarrett Wollman 	free(ifma, M_IFMADDR);
18251158dfb7SGarrett Wollman 
18261158dfb7SGarrett Wollman 	return 0;
18271158dfb7SGarrett Wollman }
18281158dfb7SGarrett Wollman 
182966ce51ceSArchie Cobbs /*
183066ce51ceSArchie Cobbs  * Set the link layer address on an interface.
183166ce51ceSArchie Cobbs  *
183266ce51ceSArchie Cobbs  * At this time we only support certain types of interfaces,
183366ce51ceSArchie Cobbs  * and we don't allow the length of the address to change.
183466ce51ceSArchie Cobbs  */
183566ce51ceSArchie Cobbs int
183666ce51ceSArchie Cobbs if_setlladdr(struct ifnet *ifp, const u_char *lladdr, int len)
183766ce51ceSArchie Cobbs {
183866ce51ceSArchie Cobbs 	struct sockaddr_dl *sdl;
183966ce51ceSArchie Cobbs 	struct ifaddr *ifa;
1840d637e989SPeter Wemm 	struct ifreq ifr;
184166ce51ceSArchie Cobbs 
1842f9132cebSJonathan Lemon 	ifa = ifaddr_byindex(ifp->if_index);
184366ce51ceSArchie Cobbs 	if (ifa == NULL)
184466ce51ceSArchie Cobbs 		return (EINVAL);
184566ce51ceSArchie Cobbs 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
184666ce51ceSArchie Cobbs 	if (sdl == NULL)
184766ce51ceSArchie Cobbs 		return (EINVAL);
184866ce51ceSArchie Cobbs 	if (len != sdl->sdl_alen)	/* don't allow length to change */
184966ce51ceSArchie Cobbs 		return (EINVAL);
185066ce51ceSArchie Cobbs 	switch (ifp->if_type) {
185166ce51ceSArchie Cobbs 	case IFT_ETHER:			/* these types use struct arpcom */
185266ce51ceSArchie Cobbs 	case IFT_FDDI:
185366ce51ceSArchie Cobbs 	case IFT_XETHER:
185466ce51ceSArchie Cobbs 	case IFT_ISO88025:
1855b7bffa71SYaroslav Tykhiy 	case IFT_L2VLAN:
18563fefbff0SLuigi Rizzo 		bcopy(lladdr, IFP2AC(ifp)->ac_enaddr, len);
18579046571fSLuigi Rizzo 		/*
18589046571fSLuigi Rizzo 		 * XXX We also need to store the lladdr in LLADDR(sdl),
18599046571fSLuigi Rizzo 		 * which is done below. This is a pain because we must
18609046571fSLuigi Rizzo 		 * remember to keep the info in sync.
18619046571fSLuigi Rizzo 		 */
18626cdcc159SMax Khon 		/* FALLTHROUGH */
18636cdcc159SMax Khon 	case IFT_ARCNET:
186466ce51ceSArchie Cobbs 		bcopy(lladdr, LLADDR(sdl), len);
186566ce51ceSArchie Cobbs 		break;
186666ce51ceSArchie Cobbs 	default:
186766ce51ceSArchie Cobbs 		return (ENODEV);
186866ce51ceSArchie Cobbs 	}
186966ce51ceSArchie Cobbs 	/*
187066ce51ceSArchie Cobbs 	 * If the interface is already up, we need
187166ce51ceSArchie Cobbs 	 * to re-init it in order to reprogram its
187266ce51ceSArchie Cobbs 	 * address filter.
187366ce51ceSArchie Cobbs 	 */
187466ce51ceSArchie Cobbs 	if ((ifp->if_flags & IFF_UP) != 0) {
187531302ebfSRobert Watson 		IFF_LOCKGIANT(ifp);
187666ce51ceSArchie Cobbs 		ifp->if_flags &= ~IFF_UP;
187762f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
187862f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1879ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
188066ce51ceSArchie Cobbs 		ifp->if_flags |= IFF_UP;
188162f76486SMaxim Sobolev 		ifr.ifr_flags = ifp->if_flags & 0xffff;
188262f76486SMaxim Sobolev 		ifr.ifr_flagshigh = ifp->if_flags >> 16;
1883ee0a4f7eSSUZUKI Shinsuke 		(*ifp->if_ioctl)(ifp, SIOCSIFFLAGS, (caddr_t)&ifr);
188431302ebfSRobert Watson 		IFF_UNLOCKGIANT(ifp);
1885b2c08f43SLuigi Rizzo #ifdef INET
1886b2c08f43SLuigi Rizzo 		/*
1887b2c08f43SLuigi Rizzo 		 * Also send gratuitous ARPs to notify other nodes about
1888b2c08f43SLuigi Rizzo 		 * the address change.
1889b2c08f43SLuigi Rizzo 		 */
1890b2c08f43SLuigi Rizzo 		TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
1891b2c08f43SLuigi Rizzo 			if (ifa->ifa_addr != NULL &&
1892b2c08f43SLuigi Rizzo 			    ifa->ifa_addr->sa_family == AF_INET)
1893c0933269SPeter Wemm 				arp_ifinit(ifp, ifa);
1894b2c08f43SLuigi Rizzo 		}
1895b2c08f43SLuigi Rizzo #endif
189666ce51ceSArchie Cobbs 	}
189766ce51ceSArchie Cobbs 	return (0);
189866ce51ceSArchie Cobbs }
189966ce51ceSArchie Cobbs 
1900373f88edSGarrett Wollman struct ifmultiaddr *
190172fd1b6aSDag-Erling Smørgrav ifmaof_ifpforaddr(struct sockaddr *sa, struct ifnet *ifp)
1902373f88edSGarrett Wollman {
1903373f88edSGarrett Wollman 	struct ifmultiaddr *ifma;
1904373f88edSGarrett Wollman 
19056817526dSPoul-Henning Kamp 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link)
1906373f88edSGarrett Wollman 		if (equal(ifma->ifma_addr, sa))
1907373f88edSGarrett Wollman 			break;
1908373f88edSGarrett Wollman 
1909373f88edSGarrett Wollman 	return ifma;
1910373f88edSGarrett Wollman }
1911373f88edSGarrett Wollman 
19129bf40edeSBrooks Davis /*
19139bf40edeSBrooks Davis  * The name argument must be a pointer to storage which will last as
19149bf40edeSBrooks Davis  * long as the interface does.  For physical devices, the result of
19159bf40edeSBrooks Davis  * device_get_name(dev) is a good choice and for pseudo-devices a
19169bf40edeSBrooks Davis  * static string works well.
19179bf40edeSBrooks Davis  */
19189bf40edeSBrooks Davis void
19199bf40edeSBrooks Davis if_initname(struct ifnet *ifp, const char *name, int unit)
19209bf40edeSBrooks Davis {
19219bf40edeSBrooks Davis 	ifp->if_dname = name;
19229bf40edeSBrooks Davis 	ifp->if_dunit = unit;
19239bf40edeSBrooks Davis 	if (unit != IF_DUNIT_NONE)
19249bf40edeSBrooks Davis 		snprintf(ifp->if_xname, IFNAMSIZ, "%s%d", name, unit);
19259bf40edeSBrooks Davis 	else
19269bf40edeSBrooks Davis 		strlcpy(ifp->if_xname, name, IFNAMSIZ);
19279bf40edeSBrooks Davis }
19289bf40edeSBrooks Davis 
1929fa882e87SBrooks Davis int
1930fa882e87SBrooks Davis if_printf(struct ifnet *ifp, const char * fmt, ...)
1931fa882e87SBrooks Davis {
1932fa882e87SBrooks Davis 	va_list ap;
1933fa882e87SBrooks Davis 	int retval;
1934fa882e87SBrooks Davis 
19359bf40edeSBrooks Davis 	retval = printf("%s: ", ifp->if_xname);
1936fa882e87SBrooks Davis 	va_start(ap, fmt);
1937fa882e87SBrooks Davis 	retval += vprintf(fmt, ap);
1938fa882e87SBrooks Davis 	va_end(ap);
1939fa882e87SBrooks Davis 	return (retval);
1940fa882e87SBrooks Davis }
1941fa882e87SBrooks Davis 
1942af5e59bfSRobert Watson /*
1943af5e59bfSRobert Watson  * When an interface is marked IFF_NEEDSGIANT, its if_start() routine cannot
1944af5e59bfSRobert Watson  * be called without Giant.  However, we often can't acquire the Giant lock
1945af5e59bfSRobert Watson  * at those points; instead, we run it via a task queue that holds Giant via
1946af5e59bfSRobert Watson  * if_start_deferred.
1947af5e59bfSRobert Watson  *
1948af5e59bfSRobert Watson  * XXXRW: We need to make sure that the ifnet isn't fully detached until any
1949af5e59bfSRobert Watson  * outstanding if_start_deferred() tasks that will run after the free.  This
1950af5e59bfSRobert Watson  * probably means waiting in if_detach().
1951af5e59bfSRobert Watson  */
1952af5e59bfSRobert Watson void
1953af5e59bfSRobert Watson if_start(struct ifnet *ifp)
1954af5e59bfSRobert Watson {
1955af5e59bfSRobert Watson 
1956af5e59bfSRobert Watson 	NET_ASSERT_GIANT();
1957af5e59bfSRobert Watson 
1958af5e59bfSRobert Watson 	if ((ifp->if_flags & IFF_NEEDSGIANT) != 0 && debug_mpsafenet != 0) {
1959af5e59bfSRobert Watson 		if (mtx_owned(&Giant))
1960af5e59bfSRobert Watson 			(*(ifp)->if_start)(ifp);
1961af5e59bfSRobert Watson 		else
1962af5e59bfSRobert Watson 			taskqueue_enqueue(taskqueue_swi_giant,
1963af5e59bfSRobert Watson 			    &ifp->if_starttask);
1964af5e59bfSRobert Watson 	} else
1965af5e59bfSRobert Watson 		(*(ifp)->if_start)(ifp);
1966af5e59bfSRobert Watson }
1967af5e59bfSRobert Watson 
1968af5e59bfSRobert Watson static void
1969af5e59bfSRobert Watson if_start_deferred(void *context, int pending)
1970af5e59bfSRobert Watson {
1971af5e59bfSRobert Watson 	struct ifnet *ifp;
1972af5e59bfSRobert Watson 
1973af5e59bfSRobert Watson 	/*
1974af5e59bfSRobert Watson 	 * This code must be entered with Giant, and should never run if
1975af5e59bfSRobert Watson 	 * we're not running with debug.mpsafenet.
1976af5e59bfSRobert Watson 	 */
1977af5e59bfSRobert Watson 	KASSERT(debug_mpsafenet != 0, ("if_start_deferred: debug.mpsafenet"));
1978af5e59bfSRobert Watson 	GIANT_REQUIRED;
1979af5e59bfSRobert Watson 
1980af5e59bfSRobert Watson 	ifp = (struct ifnet *)context;
1981af5e59bfSRobert Watson 	(ifp->if_start)(ifp);
1982af5e59bfSRobert Watson }
1983af5e59bfSRobert Watson 
19840b762445SRobert Watson int
19850b762445SRobert Watson if_handoff(struct ifqueue *ifq, struct mbuf *m, struct ifnet *ifp, int adjust)
19860b762445SRobert Watson {
19870b762445SRobert Watson 	int active = 0;
19880b762445SRobert Watson 
19890b762445SRobert Watson 	IF_LOCK(ifq);
19900b762445SRobert Watson 	if (_IF_QFULL(ifq)) {
19910b762445SRobert Watson 		_IF_DROP(ifq);
19920b762445SRobert Watson 		IF_UNLOCK(ifq);
19930b762445SRobert Watson 		m_freem(m);
19940b762445SRobert Watson 		return (0);
19950b762445SRobert Watson 	}
19960b762445SRobert Watson 	if (ifp != NULL) {
19970b762445SRobert Watson 		ifp->if_obytes += m->m_pkthdr.len + adjust;
19980b762445SRobert Watson 		if (m->m_flags & (M_BCAST|M_MCAST))
19990b762445SRobert Watson 			ifp->if_omcasts++;
20000b762445SRobert Watson 		active = ifp->if_flags & IFF_OACTIVE;
20010b762445SRobert Watson 	}
20020b762445SRobert Watson 	_IF_ENQUEUE(ifq, m);
20030b762445SRobert Watson 	IF_UNLOCK(ifq);
20040b762445SRobert Watson 	if (ifp != NULL && !active)
20050b762445SRobert Watson 		if_start(ifp);
20060b762445SRobert Watson 	return (1);
20070b762445SRobert Watson }
20080b762445SRobert Watson 
2009602d513cSGarrett Wollman SYSCTL_NODE(_net, PF_LINK, link, CTLFLAG_RW, 0, "Link layers");
20102c37256eSGarrett Wollman SYSCTL_NODE(_net_link, 0, generic, CTLFLAG_RW, 0, "Generic link-management");
2011