if_vlan.c revision 129539
1/*
2 * Copyright 1998 Massachusetts Institute of Technology
3 *
4 * Permission to use, copy, modify, and distribute this software and
5 * its documentation for any purpose and without fee is hereby
6 * granted, provided that both the above copyright notice and this
7 * permission notice appear in all copies, that both the above
8 * copyright notice and this permission notice appear in all
9 * supporting documentation, and that the name of M.I.T. not be used
10 * in advertising or publicity pertaining to distribution of the
11 * software without specific, written prior permission.  M.I.T. makes
12 * no representations about the suitability of this software for any
13 * purpose.  It is provided "as is" without express or implied
14 * warranty.
15 *
16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $FreeBSD: head/sys/net/if_vlan.c 129539 2004-05-21 08:43:38Z ru $
30 */
31
32/*
33 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
34 * Might be extended some day to also handle IEEE 802.1p priority
35 * tagging.  This is sort of sneaky in the implementation, since
36 * we need to pretend to be enough of an Ethernet implementation
37 * to make arp work.  The way we do this is by telling everyone
38 * that we are an Ethernet, and then catch the packets that
39 * ether_output() left on our output queue when it calls
40 * if_start(), rewrite them for use by the real outgoing interface,
41 * and ask it to send them.
42 */
43
44#include "opt_inet.h"
45
46#include <sys/param.h>
47#include <sys/kernel.h>
48#include <sys/malloc.h>
49#include <sys/mbuf.h>
50#include <sys/module.h>
51#include <sys/queue.h>
52#include <sys/socket.h>
53#include <sys/sockio.h>
54#include <sys/sysctl.h>
55#include <sys/systm.h>
56
57#include <net/bpf.h>
58#include <net/ethernet.h>
59#include <net/if.h>
60#include <net/if_arp.h>
61#include <net/if_dl.h>
62#include <net/if_types.h>
63#include <net/if_vlan_var.h>
64#include <net/route.h>
65
66#ifdef INET
67#include <netinet/in.h>
68#include <netinet/if_ether.h>
69#endif
70
71#define VLANNAME	"vlan"
72
73struct vlan_mc_entry {
74	struct ether_addr		mc_addr;
75	SLIST_ENTRY(vlan_mc_entry)	mc_entries;
76};
77
78struct	ifvlan {
79	struct	arpcom ifv_ac;	/* make this an interface */
80	struct	ifnet *ifv_p;	/* parent inteface of this vlan */
81	struct	ifv_linkmib {
82		int	ifvm_parent;
83		int	ifvm_encaplen;	/* encapsulation length */
84		int	ifvm_mtufudge;	/* MTU fudged by this much */
85		int	ifvm_mintu;	/* min transmission unit */
86		u_int16_t ifvm_proto; /* encapsulation ethertype */
87		u_int16_t ifvm_tag; /* tag to apply on packets leaving if */
88	}	ifv_mib;
89	SLIST_HEAD(__vlan_mchead, vlan_mc_entry)	vlan_mc_listhead;
90	LIST_ENTRY(ifvlan) ifv_list;
91	int	ifv_flags;
92};
93#define	ifv_if	ifv_ac.ac_if
94#define	ifv_tag	ifv_mib.ifvm_tag
95#define	ifv_encaplen	ifv_mib.ifvm_encaplen
96#define	ifv_mtufudge	ifv_mib.ifvm_mtufudge
97#define	ifv_mintu	ifv_mib.ifvm_mintu
98
99#define	IFVF_PROMISC	0x01		/* promiscuous mode enabled */
100
101SYSCTL_DECL(_net_link);
102SYSCTL_NODE(_net_link, IFT_L2VLAN, vlan, CTLFLAG_RW, 0, "IEEE 802.1Q VLAN");
103SYSCTL_NODE(_net_link_vlan, PF_LINK, link, CTLFLAG_RW, 0, "for consistency");
104
105static MALLOC_DEFINE(M_VLAN, VLANNAME, "802.1Q Virtual LAN Interface");
106static LIST_HEAD(, ifvlan) ifv_list;
107
108/*
109 * Locking: one lock is used to guard both the ifv_list and modification
110 * to vlan data structures.  We are rather conservative here; probably
111 * more than necessary.
112 */
113static struct mtx ifv_mtx;
114#define	VLAN_LOCK_INIT()	mtx_init(&ifv_mtx, VLANNAME, NULL, MTX_DEF)
115#define	VLAN_LOCK_DESTROY()	mtx_destroy(&ifv_mtx)
116#define	VLAN_LOCK_ASSERT()	mtx_assert(&ifv_mtx, MA_OWNED)
117#define	VLAN_LOCK()	mtx_lock(&ifv_mtx)
118#define	VLAN_UNLOCK()	mtx_unlock(&ifv_mtx)
119
120static	int vlan_clone_create(struct if_clone *, int);
121static	void vlan_clone_destroy(struct ifnet *);
122static	void vlan_start(struct ifnet *ifp);
123static	void vlan_ifinit(void *foo);
124static	void vlan_input(struct ifnet *ifp, struct mbuf *m);
125static	int vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
126static	int vlan_setmulti(struct ifnet *ifp);
127static	int vlan_unconfig(struct ifnet *ifp);
128static	int vlan_config(struct ifvlan *ifv, struct ifnet *p);
129static	void vlan_link_state(struct ifnet *ifp, int link);
130
131struct if_clone vlan_cloner = IF_CLONE_INITIALIZER(VLANNAME,
132    vlan_clone_create, vlan_clone_destroy, 0, IF_MAXUNIT);
133
134/*
135 * Program our multicast filter. What we're actually doing is
136 * programming the multicast filter of the parent. This has the
137 * side effect of causing the parent interface to receive multicast
138 * traffic that it doesn't really want, which ends up being discarded
139 * later by the upper protocol layers. Unfortunately, there's no way
140 * to avoid this: there really is only one physical interface.
141 */
142static int
143vlan_setmulti(struct ifnet *ifp)
144{
145	struct ifnet		*ifp_p;
146	struct ifmultiaddr	*ifma, *rifma = NULL;
147	struct ifvlan		*sc;
148	struct vlan_mc_entry	*mc = NULL;
149	struct sockaddr_dl	sdl;
150	int			error;
151
152	/* Find the parent. */
153	sc = ifp->if_softc;
154	ifp_p = sc->ifv_p;
155
156	/*
157	 * If we don't have a parent, just remember the membership for
158	 * when we do.
159	 */
160	if (ifp_p == NULL)
161		return(0);
162
163	bzero((char *)&sdl, sizeof sdl);
164	sdl.sdl_len = sizeof sdl;
165	sdl.sdl_family = AF_LINK;
166	sdl.sdl_index = ifp_p->if_index;
167	sdl.sdl_type = IFT_ETHER;
168	sdl.sdl_alen = ETHER_ADDR_LEN;
169
170	/* First, remove any existing filter entries. */
171	while(SLIST_FIRST(&sc->vlan_mc_listhead) != NULL) {
172		mc = SLIST_FIRST(&sc->vlan_mc_listhead);
173		bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
174		error = if_delmulti(ifp_p, (struct sockaddr *)&sdl);
175		if (error)
176			return(error);
177		SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
178		free(mc, M_VLAN);
179	}
180
181	/* Now program new ones. */
182	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
183		if (ifma->ifma_addr->sa_family != AF_LINK)
184			continue;
185		mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_WAITOK);
186		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
187		    (char *)&mc->mc_addr, ETHER_ADDR_LEN);
188		SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
189		bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
190		    LLADDR(&sdl), ETHER_ADDR_LEN);
191		error = if_addmulti(ifp_p, (struct sockaddr *)&sdl, &rifma);
192		if (error)
193			return(error);
194	}
195
196	return(0);
197}
198
199/*
200 * VLAN support can be loaded as a module.  The only place in the
201 * system that's intimately aware of this is ether_input.  We hook
202 * into this code through vlan_input_p which is defined there and
203 * set here.  Noone else in the system should be aware of this so
204 * we use an explicit reference here.
205 *
206 * NB: Noone should ever need to check if vlan_input_p is null or
207 *     not.  This is because interfaces have a count of the number
208 *     of active vlans (if_nvlans) and this should never be bumped
209 *     except by vlan_config--which is in this module so therefore
210 *     the module must be loaded and vlan_input_p must be non-NULL.
211 */
212extern	void (*vlan_input_p)(struct ifnet *, struct mbuf *);
213
214/* For MII eyes only... */
215extern	void (*vlan_link_state_p)(struct ifnet *, int);
216
217static int
218vlan_modevent(module_t mod, int type, void *data)
219{
220
221	switch (type) {
222	case MOD_LOAD:
223		LIST_INIT(&ifv_list);
224		VLAN_LOCK_INIT();
225		vlan_input_p = vlan_input;
226		vlan_link_state_p = vlan_link_state;
227		if_clone_attach(&vlan_cloner);
228		break;
229	case MOD_UNLOAD:
230		if_clone_detach(&vlan_cloner);
231		vlan_input_p = NULL;
232		vlan_link_state_p = NULL;
233		while (!LIST_EMPTY(&ifv_list))
234			vlan_clone_destroy(&LIST_FIRST(&ifv_list)->ifv_if);
235		VLAN_LOCK_DESTROY();
236		break;
237	}
238	return 0;
239}
240
241static moduledata_t vlan_mod = {
242	"if_vlan",
243	vlan_modevent,
244	0
245};
246
247DECLARE_MODULE(if_vlan, vlan_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
248MODULE_DEPEND(if_vlan, miibus, 1, 1, 1);
249
250static int
251vlan_clone_create(struct if_clone *ifc, int unit)
252{
253	struct ifvlan *ifv;
254	struct ifnet *ifp;
255
256	ifv = malloc(sizeof(struct ifvlan), M_VLAN, M_WAITOK | M_ZERO);
257	ifp = &ifv->ifv_if;
258	SLIST_INIT(&ifv->vlan_mc_listhead);
259
260	ifp->if_softc = ifv;
261	if_initname(ifp, ifc->ifc_name, unit);
262	/* NB: flags are not set here */
263	ifp->if_linkmib = &ifv->ifv_mib;
264	ifp->if_linkmiblen = sizeof ifv->ifv_mib;
265	/* NB: mtu is not set here */
266
267	ifp->if_init = vlan_ifinit;
268	ifp->if_start = vlan_start;
269	ifp->if_ioctl = vlan_ioctl;
270	ifp->if_snd.ifq_maxlen = ifqmaxlen;
271	ether_ifattach(ifp, ifv->ifv_ac.ac_enaddr);
272	/* Now undo some of the damage... */
273	ifp->if_baudrate = 0;
274	ifp->if_type = IFT_L2VLAN;
275	ifp->if_hdrlen = ETHER_VLAN_ENCAP_LEN;
276
277	VLAN_LOCK();
278	LIST_INSERT_HEAD(&ifv_list, ifv, ifv_list);
279	VLAN_UNLOCK();
280
281	return (0);
282}
283
284static void
285vlan_clone_destroy(struct ifnet *ifp)
286{
287	struct ifvlan *ifv = ifp->if_softc;
288
289	VLAN_LOCK();
290	LIST_REMOVE(ifv, ifv_list);
291	vlan_unconfig(ifp);
292	VLAN_UNLOCK();
293
294	ether_ifdetach(ifp);
295
296	free(ifv, M_VLAN);
297}
298
299static void
300vlan_ifinit(void *foo)
301{
302	return;
303}
304
305static void
306vlan_start(struct ifnet *ifp)
307{
308	struct ifvlan *ifv;
309	struct ifnet *p;
310	struct ether_vlan_header *evl;
311	struct mbuf *m;
312
313	ifv = ifp->if_softc;
314	p = ifv->ifv_p;
315
316	ifp->if_flags |= IFF_OACTIVE;
317	for (;;) {
318		IF_DEQUEUE(&ifp->if_snd, m);
319		if (m == 0)
320			break;
321		BPF_MTAP(ifp, m);
322
323		/*
324		 * Do not run parent's if_start() if the parent is not up,
325		 * or parent's driver will cause a system crash.
326		 */
327		if ((p->if_flags & (IFF_UP | IFF_RUNNING)) !=
328					(IFF_UP | IFF_RUNNING)) {
329			m_freem(m);
330			ifp->if_collisions++;
331			continue;
332		}
333
334		/*
335		 * If underlying interface can do VLAN tag insertion itself,
336		 * just pass the packet along. However, we need some way to
337		 * tell the interface where the packet came from so that it
338		 * knows how to find the VLAN tag to use, so we attach a
339		 * packet tag that holds it.
340		 */
341		if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) {
342			struct m_tag *mtag = m_tag_alloc(MTAG_VLAN,
343							 MTAG_VLAN_TAG,
344							 sizeof (u_int),
345							 M_NOWAIT);
346			if (mtag == NULL) {
347				ifp->if_oerrors++;
348				m_freem(m);
349				continue;
350			}
351			*(u_int*)(mtag+1) = ifv->ifv_tag;
352			m_tag_prepend(m, mtag);
353		} else {
354			M_PREPEND(m, ifv->ifv_encaplen, M_DONTWAIT);
355			if (m == NULL) {
356				if_printf(ifp, "unable to prepend VLAN header");
357				ifp->if_oerrors++;
358				continue;
359			}
360			/* M_PREPEND takes care of m_len, m_pkthdr.len for us */
361
362			if (m->m_len < sizeof(*evl)) {
363				m = m_pullup(m, sizeof(*evl));
364				if (m == NULL) {
365					if_printf(ifp,
366					    "cannot pullup VLAN header");
367					ifp->if_oerrors++;
368					continue;
369				}
370			}
371
372			/*
373			 * Transform the Ethernet header into an Ethernet header
374			 * with 802.1Q encapsulation.
375			 */
376			bcopy(mtod(m, char *) + ifv->ifv_encaplen,
377			      mtod(m, char *), ETHER_HDR_LEN);
378			evl = mtod(m, struct ether_vlan_header *);
379			evl->evl_proto = evl->evl_encap_proto;
380			evl->evl_encap_proto = htons(ETHERTYPE_VLAN);
381			evl->evl_tag = htons(ifv->ifv_tag);
382#ifdef DEBUG
383			printf("vlan_start: %*D\n", (int)sizeof *evl,
384			    (unsigned char *)evl, ":");
385#endif
386		}
387
388		/*
389		 * Send it, precisely as ether_output() would have.
390		 * We are already running at splimp.
391		 */
392		if (IF_HANDOFF(&p->if_snd, m, p))
393			ifp->if_opackets++;
394		else
395			ifp->if_oerrors++;
396	}
397	ifp->if_flags &= ~IFF_OACTIVE;
398
399	return;
400}
401
402static void
403vlan_input(struct ifnet *ifp, struct mbuf *m)
404{
405	struct ether_vlan_header *evl;
406	struct ifvlan *ifv;
407	struct m_tag *mtag;
408	u_int tag;
409
410	mtag = m_tag_locate(m, MTAG_VLAN, MTAG_VLAN_TAG, NULL);
411	if (mtag != NULL) {
412		/*
413		 * Packet is tagged, m contains a normal
414		 * Ethernet frame; the tag is stored out-of-band.
415		 */
416		tag = EVL_VLANOFTAG(VLAN_TAG_VALUE(mtag));
417		m_tag_delete(m, mtag);
418	} else {
419		switch (ifp->if_type) {
420		case IFT_ETHER:
421			if (m->m_len < sizeof (*evl) &&
422			    (m = m_pullup(m, sizeof (*evl))) == NULL) {
423				if_printf(ifp, "cannot pullup VLAN header\n");
424				return;
425			}
426			evl = mtod(m, struct ether_vlan_header *);
427			KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN,
428				("vlan_input: bad encapsulated protocols (%u)",
429				 ntohs(evl->evl_encap_proto)));
430
431			tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
432
433			/*
434			 * Restore the original ethertype.  We'll remove
435			 * the encapsulation after we've found the vlan
436			 * interface corresponding to the tag.
437			 */
438			evl->evl_encap_proto = evl->evl_proto;
439			break;
440		default:
441			tag = (u_int) -1;
442#ifdef DIAGNOSTIC
443			panic("vlan_input: unsupported if type %u", ifp->if_type);
444#endif
445			break;
446		}
447	}
448
449	VLAN_LOCK();
450	LIST_FOREACH(ifv, &ifv_list, ifv_list)
451		if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
452			break;
453
454	if (ifv == NULL || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
455		VLAN_UNLOCK();
456		m_freem(m);
457		ifp->if_noproto++;
458		return;
459	}
460	VLAN_UNLOCK();		/* XXX extend below? */
461
462	if (mtag == NULL) {
463		/*
464		 * Packet had an in-line encapsulation header;
465		 * remove it.  The original header has already
466		 * been fixed up above.
467		 */
468		bcopy(mtod(m, caddr_t),
469		      mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN,
470		      ETHER_HDR_LEN);
471		m_adj(m, ETHER_VLAN_ENCAP_LEN);
472	}
473
474	m->m_pkthdr.rcvif = &ifv->ifv_if;
475	ifv->ifv_if.if_ipackets++;
476
477	/* Pass it back through the parent's input routine. */
478	(*ifp->if_input)(&ifv->ifv_if, m);
479}
480
481static int
482vlan_config(struct ifvlan *ifv, struct ifnet *p)
483{
484	struct ifaddr *ifa1, *ifa2;
485	struct sockaddr_dl *sdl1, *sdl2;
486
487	VLAN_LOCK_ASSERT();
488
489	if (p->if_data.ifi_type != IFT_ETHER)
490		return EPROTONOSUPPORT;
491	if (ifv->ifv_p)
492		return EBUSY;
493
494	ifv->ifv_encaplen = ETHER_VLAN_ENCAP_LEN;
495	ifv->ifv_mintu = ETHERMIN;
496	ifv->ifv_flags = 0;
497
498	/*
499	 * If the parent supports the VLAN_MTU capability,
500	 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
501	 * enable it.
502	 */
503	p->if_nvlans++;
504	if (p->if_nvlans == 1 && (p->if_capabilities & IFCAP_VLAN_MTU) != 0) {
505		/*
506		 * Enable Tx/Rx of VLAN-sized frames.
507		 */
508		p->if_capenable |= IFCAP_VLAN_MTU;
509		if (p->if_flags & IFF_UP) {
510			struct ifreq ifr;
511			int error;
512
513			ifr.ifr_flags = p->if_flags;
514			error = (*p->if_ioctl)(p, SIOCSIFFLAGS,
515			    (caddr_t) &ifr);
516			if (error) {
517				p->if_nvlans--;
518				if (p->if_nvlans == 0)
519					p->if_capenable &= ~IFCAP_VLAN_MTU;
520				return (error);
521			}
522		}
523		ifv->ifv_mtufudge = 0;
524	} else if ((p->if_capabilities & IFCAP_VLAN_MTU) == 0) {
525		/*
526		 * Fudge the MTU by the encapsulation size.  This
527		 * makes us incompatible with strictly compliant
528		 * 802.1Q implementations, but allows us to use
529		 * the feature with other NetBSD implementations,
530		 * which might still be useful.
531		 */
532		ifv->ifv_mtufudge = ifv->ifv_encaplen;
533	}
534
535	ifv->ifv_p = p;
536	ifv->ifv_if.if_mtu = p->if_mtu - ifv->ifv_mtufudge;
537	/*
538	 * Copy only a selected subset of flags from the parent.
539	 * Other flags are none of our business.
540	 */
541	ifv->ifv_if.if_flags = (p->if_flags &
542	    (IFF_BROADCAST | IFF_MULTICAST | IFF_SIMPLEX | IFF_POINTOPOINT));
543	ifv->ifv_if.if_link_state = p->if_link_state;
544
545	/*
546	 * If the parent interface can do hardware-assisted
547	 * VLAN encapsulation, then propagate its hardware-
548	 * assisted checksumming flags.
549	 */
550	if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
551		ifv->ifv_if.if_capabilities |= p->if_capabilities & IFCAP_HWCSUM;
552
553	/*
554	 * Set up our ``Ethernet address'' to reflect the underlying
555	 * physical interface's.
556	 */
557	ifa1 = ifaddr_byindex(ifv->ifv_if.if_index);
558	ifa2 = ifaddr_byindex(p->if_index);
559	sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
560	sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
561	sdl1->sdl_type = IFT_ETHER;
562	sdl1->sdl_alen = ETHER_ADDR_LEN;
563	bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
564	bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
565
566	/*
567	 * Configure multicast addresses that may already be
568	 * joined on the vlan device.
569	 */
570	(void)vlan_setmulti(&ifv->ifv_if);
571
572	return 0;
573}
574
575static int
576vlan_unconfig(struct ifnet *ifp)
577{
578	struct ifaddr *ifa;
579	struct sockaddr_dl *sdl;
580	struct vlan_mc_entry *mc;
581	struct ifvlan *ifv;
582	struct ifnet *p;
583	int error;
584
585	VLAN_LOCK_ASSERT();
586
587	ifv = ifp->if_softc;
588	p = ifv->ifv_p;
589
590	if (p) {
591		struct sockaddr_dl sdl;
592
593		/*
594		 * Since the interface is being unconfigured, we need to
595		 * empty the list of multicast groups that we may have joined
596		 * while we were alive from the parent's list.
597		 */
598		bzero((char *)&sdl, sizeof sdl);
599		sdl.sdl_len = sizeof sdl;
600		sdl.sdl_family = AF_LINK;
601		sdl.sdl_index = p->if_index;
602		sdl.sdl_type = IFT_ETHER;
603		sdl.sdl_alen = ETHER_ADDR_LEN;
604
605		while(SLIST_FIRST(&ifv->vlan_mc_listhead) != NULL) {
606			mc = SLIST_FIRST(&ifv->vlan_mc_listhead);
607			bcopy((char *)&mc->mc_addr, LLADDR(&sdl), ETHER_ADDR_LEN);
608			error = if_delmulti(p, (struct sockaddr *)&sdl);
609			if (error)
610				return(error);
611			SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
612			free(mc, M_VLAN);
613		}
614
615		p->if_nvlans--;
616		if (p->if_nvlans == 0) {
617			/*
618			 * Disable Tx/Rx of VLAN-sized frames.
619			 */
620			p->if_capenable &= ~IFCAP_VLAN_MTU;
621			if (p->if_flags & IFF_UP) {
622				struct ifreq ifr;
623
624				ifr.ifr_flags = p->if_flags;
625				(*p->if_ioctl)(p, SIOCSIFFLAGS, (caddr_t) &ifr);
626			}
627		}
628	}
629
630	/* Disconnect from parent. */
631	ifv->ifv_p = NULL;
632	ifv->ifv_if.if_mtu = ETHERMTU;		/* XXX why not 0? */
633	ifv->ifv_flags = 0;
634	ifv->ifv_if.if_link_state = LINK_STATE_UNKNOWN;
635
636	/* Clear our MAC address. */
637	ifa = ifaddr_byindex(ifv->ifv_if.if_index);
638	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
639	sdl->sdl_type = IFT_ETHER;
640	sdl->sdl_alen = ETHER_ADDR_LEN;
641	bzero(LLADDR(sdl), ETHER_ADDR_LEN);
642	bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
643
644	return 0;
645}
646
647static int
648vlan_set_promisc(struct ifnet *ifp)
649{
650	struct ifvlan *ifv = ifp->if_softc;
651	int error = 0;
652
653	if ((ifp->if_flags & IFF_PROMISC) != 0) {
654		if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
655			error = ifpromisc(ifv->ifv_p, 1);
656			if (error == 0)
657				ifv->ifv_flags |= IFVF_PROMISC;
658		}
659	} else {
660		if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
661			error = ifpromisc(ifv->ifv_p, 0);
662			if (error == 0)
663				ifv->ifv_flags &= ~IFVF_PROMISC;
664		}
665	}
666
667	return (error);
668}
669
670/* Inform all vlans that their parent has changed link state */
671static void
672vlan_link_state(struct ifnet *ifp, int link)
673{
674	struct ifvlan *ifv;
675
676	VLAN_LOCK();
677	LIST_FOREACH(ifv, &ifv_list, ifv_list) {
678		if (ifv->ifv_p == ifp) {
679			ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state;
680			rt_ifmsg(&(ifv->ifv_if));
681			KNOTE(&ifp->if_klist, link);
682		}
683	}
684	VLAN_UNLOCK();
685}
686
687static int
688vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
689{
690	struct ifaddr *ifa;
691	struct ifnet *p;
692	struct ifreq *ifr;
693	struct ifvlan *ifv;
694	struct vlanreq vlr;
695	int error = 0;
696
697	ifr = (struct ifreq *)data;
698	ifa = (struct ifaddr *)data;
699	ifv = ifp->if_softc;
700
701	switch (cmd) {
702	case SIOCSIFADDR:
703		ifp->if_flags |= IFF_UP;
704
705		switch (ifa->ifa_addr->sa_family) {
706#ifdef INET
707		case AF_INET:
708			arp_ifinit(&ifv->ifv_if, ifa);
709			break;
710#endif
711		default:
712			break;
713		}
714		break;
715
716	case SIOCGIFADDR:
717		{
718			struct sockaddr *sa;
719
720			sa = (struct sockaddr *) &ifr->ifr_data;
721			bcopy(IFP2AC(ifp)->ac_enaddr,
722			      (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
723		}
724		break;
725
726	case SIOCGIFMEDIA:
727		VLAN_LOCK();
728		if (ifv->ifv_p != NULL) {
729			error = (*ifv->ifv_p->if_ioctl)(ifv->ifv_p,
730					SIOCGIFMEDIA, data);
731			VLAN_UNLOCK();
732			/* Limit the result to the parent's current config. */
733			if (error == 0) {
734				struct ifmediareq *ifmr;
735
736				ifmr = (struct ifmediareq *) data;
737				if (ifmr->ifm_count >= 1 && ifmr->ifm_ulist) {
738					ifmr->ifm_count = 1;
739					error = copyout(&ifmr->ifm_current,
740						ifmr->ifm_ulist,
741						sizeof(int));
742				}
743			}
744		} else {
745			VLAN_UNLOCK();
746			error = EINVAL;
747		}
748		break;
749
750	case SIOCSIFMEDIA:
751		error = EINVAL;
752		break;
753
754	case SIOCSIFMTU:
755		/*
756		 * Set the interface MTU.
757		 */
758		VLAN_LOCK();
759		if (ifv->ifv_p != NULL) {
760			if (ifr->ifr_mtu >
761			     (ifv->ifv_p->if_mtu - ifv->ifv_mtufudge) ||
762			    ifr->ifr_mtu <
763			     (ifv->ifv_mintu - ifv->ifv_mtufudge))
764				error = EINVAL;
765			else
766				ifp->if_mtu = ifr->ifr_mtu;
767		} else
768			error = EINVAL;
769		VLAN_UNLOCK();
770		break;
771
772	case SIOCSETVLAN:
773		error = copyin(ifr->ifr_data, &vlr, sizeof vlr);
774		if (error)
775			break;
776		if (vlr.vlr_parent[0] == '\0') {
777			VLAN_LOCK();
778			vlan_unconfig(ifp);
779			if (ifp->if_flags & IFF_UP)
780				if_down(ifp);
781			ifp->if_flags &= ~IFF_RUNNING;
782			VLAN_UNLOCK();
783			break;
784		}
785		p = ifunit(vlr.vlr_parent);
786		if (p == 0) {
787			error = ENOENT;
788			break;
789		}
790		/*
791		 * Don't let the caller set up a VLAN tag with
792		 * anything except VLID bits.
793		 */
794		if (vlr.vlr_tag & ~EVL_VLID_MASK) {
795			error = EINVAL;
796			break;
797		}
798		VLAN_LOCK();
799		error = vlan_config(ifv, p);
800		if (error) {
801			VLAN_UNLOCK();
802			break;
803		}
804		ifv->ifv_tag = vlr.vlr_tag;
805		ifp->if_flags |= IFF_RUNNING;
806		VLAN_UNLOCK();
807
808		/* Update promiscuous mode, if necessary. */
809		vlan_set_promisc(ifp);
810		break;
811
812	case SIOCGETVLAN:
813		bzero(&vlr, sizeof vlr);
814		VLAN_LOCK();
815		if (ifv->ifv_p) {
816			strlcpy(vlr.vlr_parent, ifv->ifv_p->if_xname,
817			    sizeof(vlr.vlr_parent));
818			vlr.vlr_tag = ifv->ifv_tag;
819		}
820		VLAN_UNLOCK();
821		error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
822		break;
823
824	case SIOCSIFFLAGS:
825		/*
826		 * For promiscuous mode, we enable promiscuous mode on
827		 * the parent if we need promiscuous on the VLAN interface.
828		 */
829		if (ifv->ifv_p != NULL)
830			error = vlan_set_promisc(ifp);
831		break;
832
833	case SIOCADDMULTI:
834	case SIOCDELMULTI:
835		error = vlan_setmulti(ifp);
836		break;
837	default:
838		error = EINVAL;
839	}
840	return error;
841}
842