xref: /openbsd/sys/net/if_vlan.c (revision 91f110e0)
1 /*	$OpenBSD: if_vlan.c,v 1.102 2014/03/10 12:21:35 mpi Exp $	*/
2 
3 /*
4  * Copyright 1998 Massachusetts Institute of Technology
5  *
6  * Permission to use, copy, modify, and distribute this software and
7  * its documentation for any purpose and without fee is hereby
8  * granted, provided that both the above copyright notice and this
9  * permission notice appear in all copies, that both the above
10  * copyright notice and this permission notice appear in all
11  * supporting documentation, and that the name of M.I.T. not be used
12  * in advertising or publicity pertaining to distribution of the
13  * software without specific, written prior permission.  M.I.T. makes
14  * no representations about the suitability of this software for any
15  * purpose.  It is provided "as is" without express or implied
16  * warranty.
17  *
18  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
19  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
20  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
21  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
22  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
25  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
26  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  *
31  * $FreeBSD: src/sys/net/if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp $
32  */
33 
34 /*
35  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
36  * This is sort of sneaky in the implementation, since
37  * we need to pretend to be enough of an Ethernet implementation
38  * to make arp work.  The way we do this is by telling everyone
39  * that we are an Ethernet, and then catch the packets that
40  * ether_output() left on our output queue when it calls
41  * if_start(), rewrite them for use by the real outgoing interface,
42  * and ask it to send them.
43  *
44  * Some devices support 802.1Q tag insertion in firmware.  The
45  * vlan interface behavior changes when the IFCAP_VLAN_HWTAGGING
46  * capability is set on the parent.  In this case, vlan_start()
47  * will not modify the ethernet header.
48  */
49 
50 #include "vlan.h"
51 
52 #include <sys/param.h>
53 #include <sys/kernel.h>
54 #include <sys/malloc.h>
55 #include <sys/mbuf.h>
56 #include <sys/queue.h>
57 #include <sys/socket.h>
58 #include <sys/sockio.h>
59 #include <sys/systm.h>
60 
61 #include "bpfilter.h"
62 #if NBPFILTER > 0
63 #include <net/bpf.h>
64 #endif
65 
66 #include <net/if.h>
67 #include <net/if_dl.h>
68 #include <net/if_types.h>
69 
70 #ifdef INET
71 #include <netinet/in.h>
72 #include <netinet/if_ether.h>
73 #endif
74 
75 #include <net/if_vlan_var.h>
76 
77 u_long vlan_tagmask, svlan_tagmask;
78 
79 #define TAG_HASH_SIZE		32
80 #define TAG_HASH(tag)		(tag & vlan_tagmask)
81 LIST_HEAD(vlan_taghash, ifvlan)	*vlan_tagh, *svlan_tagh;
82 
83 void	vlan_start(struct ifnet *ifp);
84 int	vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
85 int	vlan_unconfig(struct ifnet *ifp, struct ifnet *newp);
86 int	vlan_config(struct ifvlan *, struct ifnet *, u_int16_t);
87 void	vlan_vlandev_state(void *);
88 void	vlanattach(int count);
89 int	vlan_set_promisc(struct ifnet *ifp);
90 int	vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
91 int	vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
92 void	vlan_ether_purgemulti(struct ifvlan *);
93 void	vlan_ether_resetmulti(struct ifvlan *, struct ifnet *);
94 int	vlan_clone_create(struct if_clone *, int);
95 int	vlan_clone_destroy(struct ifnet *);
96 void	vlan_ifdetach(void *);
97 
98 struct if_clone vlan_cloner =
99     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
100 struct if_clone svlan_cloner =
101     IF_CLONE_INITIALIZER("svlan", vlan_clone_create, vlan_clone_destroy);
102 
103 /* ARGSUSED */
104 void
105 vlanattach(int count)
106 {
107 	/* Normal VLAN */
108 	vlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT,
109 	    &vlan_tagmask);
110 	if (vlan_tagh == NULL)
111 		panic("vlanattach: hashinit");
112 	if_clone_attach(&vlan_cloner);
113 
114 	/* Service-VLAN for QinQ/802.1ad provider bridges */
115 	svlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT,
116 	    &svlan_tagmask);
117 	if (svlan_tagh == NULL)
118 		panic("vlanattach: hashinit");
119 	if_clone_attach(&svlan_cloner);
120 }
121 
122 int
123 vlan_clone_create(struct if_clone *ifc, int unit)
124 {
125 	struct ifvlan *ifv;
126 	struct ifnet *ifp;
127 
128 	ifv = malloc(sizeof(*ifv), M_DEVBUF, M_NOWAIT|M_ZERO);
129 	if (!ifv)
130 		return (ENOMEM);
131 
132 	LIST_INIT(&ifv->vlan_mc_listhead);
133 	ifp = &ifv->ifv_if;
134 	ifp->if_softc = ifv;
135 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
136 	    unit);
137 	/* NB: flags are not set here */
138 	/* NB: mtu is not set here */
139 
140 	/* Special handling for the IEEE 802.1ad QinQ variant */
141 	if (strcmp("svlan", ifc->ifc_name) == 0)
142 		ifv->ifv_type = ETHERTYPE_QINQ;
143 	else
144 		ifv->ifv_type = ETHERTYPE_VLAN;
145 
146 	ifp->if_start = vlan_start;
147 	ifp->if_ioctl = vlan_ioctl;
148 	IFQ_SET_MAXLEN(&ifp->if_snd, 1);
149 	IFQ_SET_READY(&ifp->if_snd);
150 	if_attach(ifp);
151 	ether_ifattach(ifp);
152 	/* Now undo some of the damage... */
153 	ifp->if_type = IFT_L2VLAN;
154 	ifp->if_hdrlen = EVL_ENCAPLEN;
155 
156 	return (0);
157 }
158 
159 int
160 vlan_clone_destroy(struct ifnet *ifp)
161 {
162 	struct ifvlan *ifv = ifp->if_softc;
163 
164 	vlan_unconfig(ifp, NULL);
165 	ether_ifdetach(ifp);
166 	if_detach(ifp);
167 
168 	free(ifv, M_DEVBUF);
169 	return (0);
170 }
171 
172 void
173 vlan_ifdetach(void *ptr)
174 {
175 	struct ifvlan *ifv = (struct ifvlan *)ptr;
176 
177 	vlan_clone_destroy(&ifv->ifv_if);
178 }
179 
180 void
181 vlan_start(struct ifnet *ifp)
182 {
183 	struct ifvlan *ifv;
184 	struct ifnet *p;
185 	struct mbuf *m;
186 	int error;
187 
188 	ifv = ifp->if_softc;
189 	p = ifv->ifv_p;
190 
191 	for (;;) {
192 		IFQ_DEQUEUE(&ifp->if_snd, m);
193 		if (m == NULL)
194 			break;
195 
196 		if ((p->if_flags & (IFF_UP|IFF_RUNNING)) !=
197 		    (IFF_UP|IFF_RUNNING)) {
198 			IF_DROP(&p->if_snd);
199 				/* XXX stats */
200 			ifp->if_oerrors++;
201 			m_freem(m);
202 			continue;
203 		}
204 
205 #if NBPFILTER > 0
206 		if (ifp->if_bpf)
207 			bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT);
208 #endif
209 
210 		/*
211 		 * If the IFCAP_VLAN_HWTAGGING capability is set on the parent,
212 		 * it can do VLAN tag insertion itself and doesn't require us
213 	 	 * to create a special header for it. In this case, we just pass
214 		 * the packet along.
215 		 */
216 		if ((p->if_capabilities & IFCAP_VLAN_HWTAGGING) &&
217 		    (ifv->ifv_type == ETHERTYPE_VLAN)) {
218 			m->m_pkthdr.ether_vtag = ifv->ifv_tag +
219 			    (m->m_pkthdr.pf.prio << EVL_PRIO_BITS);
220 			m->m_flags |= M_VLANTAG;
221 		} else {
222 			struct ether_vlan_header evh;
223 
224 			m_copydata(m, 0, ETHER_HDR_LEN, (caddr_t)&evh);
225 			evh.evl_proto = evh.evl_encap_proto;
226 			evh.evl_encap_proto = htons(ifv->ifv_type);
227 			evh.evl_tag = htons(ifv->ifv_tag +
228 			    (m->m_pkthdr.pf.prio << EVL_PRIO_BITS));
229 
230 			m_adj(m, ETHER_HDR_LEN);
231 			M_PREPEND(m, sizeof(evh), M_DONTWAIT);
232 			if (m == NULL) {
233 				ifp->if_oerrors++;
234 				continue;
235 			}
236 
237 			m_copyback(m, 0, sizeof(evh), &evh, M_NOWAIT);
238 		}
239 
240 		/*
241 		 * Send it, precisely as ether_output() would have.
242 		 * We are already running at splnet.
243 		 */
244 		IFQ_ENQUEUE(&p->if_snd, m, NULL, error);
245 		if (error) {
246 			/* mbuf is already freed */
247 			ifp->if_oerrors++;
248 			continue;
249 		}
250 		p->if_obytes += m->m_pkthdr.len;
251 		if (m->m_flags & M_MCAST)
252 			p->if_omcasts++;
253 
254 		ifp->if_opackets++;
255 		if_start(p);
256 	}
257 
258 	return;
259 }
260 
261 /*
262  * vlan_input() returns 0 if it has consumed the packet, 1 otherwise.
263  */
264 int
265 vlan_input(struct ether_header *eh, struct mbuf *m)
266 {
267 	struct ifvlan *ifv;
268 	struct ifnet *ifp = m->m_pkthdr.rcvif;
269 	struct vlan_taghash *tagh;
270 	u_int tag;
271 	u_int16_t etype;
272 
273 	if (m->m_flags & M_VLANTAG) {
274 		etype = ETHERTYPE_VLAN;
275 		tagh = vlan_tagh;
276 	} else {
277 		if (m->m_len < EVL_ENCAPLEN &&
278 		    (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
279 			ifp->if_ierrors++;
280 			return (0);
281 		}
282 
283 		etype = ntohs(eh->ether_type);
284 		tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
285 		m->m_pkthdr.ether_vtag = ntohs(*mtod(m, u_int16_t *));
286 	}
287 	/* From now on ether_vtag is fine */
288 	tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
289 	m->m_pkthdr.pf.prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
290 
291 	LIST_FOREACH(ifv, &tagh[TAG_HASH(tag)], ifv_list) {
292 		if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag &&
293 		    etype == ifv->ifv_type)
294 			break;
295 	}
296 	if (ifv == NULL)
297 		return (1);
298 
299 	if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
300 	    (IFF_UP|IFF_RUNNING)) {
301 		m_freem(m);
302 		return (0);
303 	}
304 
305 	/*
306 	 * Having found a valid vlan interface corresponding to
307 	 * the given source interface and vlan tag, remove the
308 	 * encapsulation, and run the real packet through
309 	 * ether_input() a second time (it had better be
310 	 * reentrant!).
311 	 */
312 	m->m_pkthdr.rcvif = &ifv->ifv_if;
313 	if (m->m_flags & M_VLANTAG) {
314 		m->m_flags &= ~M_VLANTAG;
315 	} else {
316 		eh->ether_type = mtod(m, u_int16_t *)[1];
317 		m->m_len -= EVL_ENCAPLEN;
318 		m->m_data += EVL_ENCAPLEN;
319 		m->m_pkthdr.len -= EVL_ENCAPLEN;
320 	}
321 
322 #if NBPFILTER > 0
323 	if (ifv->ifv_if.if_bpf)
324 		bpf_mtap_hdr(ifv->ifv_if.if_bpf, (char *)eh, ETHER_HDR_LEN,
325 		    m, BPF_DIRECTION_IN);
326 #endif
327 
328 	/*
329 	 * Drop promiscuously received packets if we are not in
330 	 * promiscuous mode.
331 	 */
332 	if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 &&
333 	    (ifp->if_flags & IFF_PROMISC) &&
334 	    (ifv->ifv_if.if_flags & IFF_PROMISC) == 0) {
335 		struct arpcom *ac = &ifv->ifv_ac;
336 		if (bcmp(ac->ac_enaddr, eh->ether_dhost, ETHER_ADDR_LEN)) {
337 			m_freem(m);
338 			return (0);
339 		}
340 	}
341 
342 	ifv->ifv_if.if_ipackets++;
343 	ether_input(&ifv->ifv_if, eh, m);
344 
345 	return (0);
346 }
347 
348 int
349 vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
350 {
351 	struct sockaddr_dl *sdl1, *sdl2;
352 	struct vlan_taghash *tagh;
353 	u_int flags;
354 	int s;
355 
356 	if (p->if_type != IFT_ETHER)
357 		return EPROTONOSUPPORT;
358 	if (ifv->ifv_p == p && ifv->ifv_tag == tag) /* noop */
359 		return (0);
360 
361 	/* Remember existing interface flags and reset the interface */
362 	flags = ifv->ifv_flags;
363 	vlan_unconfig(&ifv->ifv_if, p);
364 
365 	ifv->ifv_p = p;
366 
367 	if (p->if_capabilities & IFCAP_VLAN_MTU)
368 		ifv->ifv_if.if_mtu = p->if_mtu;
369 	else {
370 		/*
371 		 * This will be incompatible with strict
372 		 * 802.1Q implementations
373 		 */
374 		ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN;
375 #ifdef DIAGNOSTIC
376 		printf("%s: initialized with non-standard mtu %u (parent %s)\n",
377 		    ifv->ifv_if.if_xname, ifv->ifv_if.if_mtu,
378 		    ifv->ifv_p->if_xname);
379 #endif
380 	}
381 
382 	ifv->ifv_if.if_flags = p->if_flags &
383 	    (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
384 
385 	/* Reset promisc mode on the interface and its parent */
386 	if (flags & IFVF_PROMISC) {
387 		ifv->ifv_if.if_flags |= IFF_PROMISC;
388 		vlan_set_promisc(&ifv->ifv_if);
389 	}
390 
391 	/*
392 	 * Inherit the if_type from the parent.  This allows us to
393 	 * participate in bridges of that type.
394 	 */
395 	ifv->ifv_if.if_type = p->if_type;
396 
397 	/*
398 	 * Inherit baudrate from the parent.  An SNMP agent would use this
399 	 * information.
400 	 */
401 	ifv->ifv_if.if_baudrate = p->if_baudrate;
402 
403 	/*
404 	 * If the parent interface can do hardware-assisted
405 	 * VLAN encapsulation, then propagate its hardware-
406 	 * assisted checksumming flags.
407 	 *
408 	 * If the card cannot handle hardware tagging, it cannot
409 	 * possibly compute the correct checksums for tagged packets.
410 	 *
411 	 * This brings up another possibility, do cards exist which
412 	 * have all of these capabilities but cannot utilize them together?
413 	 */
414 	if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
415 		ifv->ifv_if.if_capabilities = p->if_capabilities &
416 		    IFCAP_CSUM_MASK;
417 
418 	/*
419 	 * Hardware VLAN tagging only works with the default VLAN
420 	 * ethernet type (0x8100).
421 	 */
422 	if (ifv->ifv_type != ETHERTYPE_VLAN)
423 		ifv->ifv_if.if_capabilities &= ~IFCAP_VLAN_HWTAGGING;
424 
425 	/*
426 	 * Set up our ``Ethernet address'' to reflect the underlying
427 	 * physical interface's.
428 	 */
429 	sdl1 = ifv->ifv_if.if_sadl;
430 	sdl2 = p->if_sadl;
431 	sdl1->sdl_type = IFT_ETHER;
432 	sdl1->sdl_alen = ETHER_ADDR_LEN;
433 	bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
434 	bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
435 
436 	ifv->ifv_tag = tag;
437 	s = splnet();
438 	tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
439 	LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list);
440 
441 	/* Register callback for physical link state changes */
442 	ifv->lh_cookie = hook_establish(p->if_linkstatehooks, 1,
443 	    vlan_vlandev_state, ifv);
444 
445 	/* Register callback if parent wants to unregister */
446 	ifv->dh_cookie = hook_establish(p->if_detachhooks, 0,
447 	    vlan_ifdetach, ifv);
448 
449 	vlan_vlandev_state(ifv);
450 	splx(s);
451 
452 	return 0;
453 }
454 
455 int
456 vlan_unconfig(struct ifnet *ifp, struct ifnet *newp)
457 {
458 	struct sockaddr_dl *sdl;
459 	struct ifvlan *ifv;
460 	struct ifnet *p;
461 	int s;
462 
463 	ifv = ifp->if_softc;
464 	p = ifv->ifv_p;
465 	if (p == NULL)
466 		return 0;
467 
468 	/* Unset promisc mode on the interface and its parent */
469 	if (ifv->ifv_flags & IFVF_PROMISC) {
470 		ifp->if_flags &= ~IFF_PROMISC;
471 		vlan_set_promisc(ifp);
472 	}
473 
474 	s = splnet();
475 	LIST_REMOVE(ifv, ifv_list);
476 	splx(s);
477 
478 	hook_disestablish(p->if_linkstatehooks, ifv->lh_cookie);
479 	hook_disestablish(p->if_detachhooks, ifv->dh_cookie);
480 	/* Reset link state */
481 	if (newp != NULL) {
482 		ifp->if_link_state = LINK_STATE_INVALID;
483 		if_link_state_change(ifp);
484 	}
485 
486 	/*
487  	 * Since the interface is being unconfigured, we need to
488 	 * empty the list of multicast groups that we may have joined
489 	 * while we were alive and remove them from the parent's list
490 	 * as well.
491 	 */
492 	vlan_ether_resetmulti(ifv, newp);
493 
494 	/* Disconnect from parent. */
495 	ifv->ifv_p = NULL;
496 	ifv->ifv_if.if_mtu = ETHERMTU;
497 	ifv->ifv_flags = 0;
498 
499 	/* Clear our MAC address. */
500 	sdl = ifv->ifv_if.if_sadl;
501 	sdl->sdl_type = IFT_ETHER;
502 	sdl->sdl_alen = ETHER_ADDR_LEN;
503 	bzero(LLADDR(sdl), ETHER_ADDR_LEN);
504 	bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
505 
506 	return 0;
507 }
508 
509 void
510 vlan_vlandev_state(void *v)
511 {
512 	struct ifvlan *ifv = v;
513 
514 	if (ifv->ifv_if.if_link_state == ifv->ifv_p->if_link_state)
515 		return;
516 
517 	ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state;
518 	ifv->ifv_if.if_baudrate = ifv->ifv_p->if_baudrate;
519 	if_link_state_change(&ifv->ifv_if);
520 }
521 
522 int
523 vlan_set_promisc(struct ifnet *ifp)
524 {
525 	struct ifvlan *ifv = ifp->if_softc;
526 	int error = 0;
527 
528 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
529 		if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
530 			error = ifpromisc(ifv->ifv_p, 1);
531 			if (error == 0)
532 				ifv->ifv_flags |= IFVF_PROMISC;
533 		}
534 	} else {
535 		if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
536 			error = ifpromisc(ifv->ifv_p, 0);
537 			if (error == 0)
538 				ifv->ifv_flags &= ~IFVF_PROMISC;
539 		}
540 	}
541 
542 	return (0);
543 }
544 
545 int
546 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
547 {
548 	struct proc *p = curproc;	/* XXX */
549 	struct ifaddr *ifa;
550 	struct ifnet *pr;
551 	struct ifreq *ifr;
552 	struct ifvlan *ifv;
553 	struct vlanreq vlr;
554 	int error = 0, p_mtu = 0, s;
555 
556 	ifr = (struct ifreq *)data;
557 	ifa = (struct ifaddr *)data;
558 	ifv = ifp->if_softc;
559 
560 	switch (cmd) {
561 	case SIOCSIFADDR:
562 		if (ifv->ifv_p != NULL) {
563 			ifp->if_flags |= IFF_UP;
564 
565 			switch (ifa->ifa_addr->sa_family) {
566 #ifdef INET
567 			case AF_INET:
568 				arp_ifinit(&ifv->ifv_ac, ifa);
569 				break;
570 #endif
571 			default:
572 				break;
573 			}
574 		} else {
575 			error = EINVAL;
576 		}
577 		break;
578 
579 	case SIOCGIFADDR:
580 		{
581 			struct sockaddr *sa;
582 
583 			sa = (struct sockaddr *) &ifr->ifr_data;
584 			bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
585 			    (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
586 		}
587 		break;
588 
589 	case SIOCSIFMTU:
590 		if (ifv->ifv_p != NULL) {
591 			if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU)
592 				p_mtu = ifv->ifv_p->if_mtu;
593 			else
594 				p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN;
595 
596 			if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN)
597 				error = EINVAL;
598 			else
599 				ifp->if_mtu = ifr->ifr_mtu;
600 		} else
601 			error = EINVAL;
602 
603 		break;
604 
605 	case SIOCSETVLAN:
606 		if ((error = suser(p, 0)) != 0)
607 			break;
608 		if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr)))
609 			break;
610 		if (vlr.vlr_parent[0] == '\0') {
611 			s = splnet();
612 			vlan_unconfig(ifp, NULL);
613 			if (ifp->if_flags & IFF_UP)
614 				if_down(ifp);
615 			ifp->if_flags &= ~IFF_RUNNING;
616 			splx(s);
617 			break;
618 		}
619 		pr = ifunit(vlr.vlr_parent);
620 		if (pr == NULL) {
621 			error = ENOENT;
622 			break;
623 		}
624 		/*
625 		 * Don't let the caller set up a VLAN tag with
626 		 * anything except VLID bits.
627 		 */
628 		if (vlr.vlr_tag & ~EVL_VLID_MASK) {
629 			error = EINVAL;
630 			break;
631 		}
632 		error = vlan_config(ifv, pr, vlr.vlr_tag);
633 		if (error)
634 			break;
635 		ifp->if_flags |= IFF_RUNNING;
636 
637 		/* Update promiscuous mode, if necessary. */
638 		vlan_set_promisc(ifp);
639 		break;
640 
641 	case SIOCGETVLAN:
642 		bzero(&vlr, sizeof vlr);
643 		if (ifv->ifv_p) {
644 			snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
645 			    "%s", ifv->ifv_p->if_xname);
646 			vlr.vlr_tag = ifv->ifv_tag;
647 		}
648 		error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
649 		break;
650 	case SIOCSIFFLAGS:
651 		/*
652 		 * For promiscuous mode, we enable promiscuous mode on
653 		 * the parent if we need promiscuous on the VLAN interface.
654 		 */
655 		if (ifv->ifv_p != NULL)
656 			error = vlan_set_promisc(ifp);
657 		break;
658 
659 	case SIOCADDMULTI:
660 		error = (ifv->ifv_p != NULL) ?
661 		    vlan_ether_addmulti(ifv, ifr) : EINVAL;
662 		break;
663 
664 	case SIOCDELMULTI:
665 		error = (ifv->ifv_p != NULL) ?
666 		    vlan_ether_delmulti(ifv, ifr) : EINVAL;
667 		break;
668 	default:
669 		error = ENOTTY;
670 	}
671 	return error;
672 }
673 
674 
675 int
676 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
677 {
678 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
679 	struct vlan_mc_entry *mc;
680 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
681 	int error;
682 
683 	/* XXX: sa_len is too small for such comparison
684 	if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage))
685 		return (EINVAL);
686 	*/
687 
688 	error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
689 	if (error != ENETRESET)
690 		return (error);
691 
692 	/*
693 	 * This is new multicast address.  We have to tell parent
694 	 * about it.  Also, remember this multicast address so that
695 	 * we can delete them on unconfigure.
696 	 */
697 	mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT);
698 	if (mc == NULL) {
699 		error = ENOMEM;
700 		goto alloc_failed;
701 	}
702 
703 	/*
704 	 * As ether_addmulti() returns ENETRESET, following two
705 	 * statement shouldn't fail.
706 	 */
707 	(void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
708 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm);
709 	memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
710 	LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
711 
712 	error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr);
713 	if (error != 0)
714 		goto ioctl_failed;
715 
716 	return (error);
717 
718  ioctl_failed:
719 	LIST_REMOVE(mc, mc_entries);
720 	free(mc, M_DEVBUF);
721  alloc_failed:
722 	(void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
723 
724 	return (error);
725 }
726 
727 int
728 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
729 {
730 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
731 	struct ether_multi *enm;
732 	struct vlan_mc_entry *mc;
733 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
734 	int error;
735 
736 	/*
737 	 * Find a key to lookup vlan_mc_entry.  We have to do this
738 	 * before calling ether_delmulti for obvious reason.
739 	 */
740 	if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
741 		return (error);
742 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm);
743 	if (enm == NULL)
744 		return (EINVAL);
745 
746 	LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries)
747 		if (mc->mc_enm == enm)
748 			break;
749 
750 	/* We won't delete entries we didn't add */
751 	if (mc == NULL)
752 		return (EINVAL);
753 
754 	error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
755 	if (error != ENETRESET)
756 		return (error);
757 
758 	/* We no longer use this multicast address.  Tell parent so. */
759 	error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
760 	if (error == 0) {
761 		/* And forget about this address. */
762 		LIST_REMOVE(mc, mc_entries);
763 		free(mc, M_DEVBUF);
764 	} else
765 		(void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
766 	return (error);
767 }
768 
769 /*
770  * Delete any multicast address we have asked to add from parent
771  * interface.  Called when the vlan is being unconfigured.
772  */
773 void
774 vlan_ether_purgemulti(struct ifvlan *ifv)
775 {
776 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
777 	struct vlan_mc_entry *mc;
778 	union {
779 		struct ifreq ifreq;
780 		struct {
781 			char ifr_name[IFNAMSIZ];
782 			struct sockaddr_storage ifr_ss;
783 		} ifreq_storage;
784 	} ifreq;
785 	struct ifreq *ifr = &ifreq.ifreq;
786 
787 	memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
788 	while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
789 		memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
790 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
791 		LIST_REMOVE(mc, mc_entries);
792 		free(mc, M_DEVBUF);
793 	}
794 }
795 
796 void
797 vlan_ether_resetmulti(struct ifvlan *ifv, struct ifnet *p)
798 {
799 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
800 	struct vlan_mc_entry *mc;
801 	union {
802 		struct ifreq ifreq;
803 		struct {
804 			char ifr_name[IFNAMSIZ];
805 			struct sockaddr_storage ifr_ss;
806 		} ifreq_storage;
807 	} ifreq;
808 	struct ifreq *ifr = &ifreq.ifreq;
809 
810 	if (p == NULL) {
811 		vlan_ether_purgemulti(ifv);
812 		return;
813 	} else if (ifp == p)
814 		return;
815 
816 	LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
817 		memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
818 
819 		/* Remove from the old parent */
820 		memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
821 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
822 
823 		/* Try to add to the new parent */
824 		memcpy(ifr->ifr_name, p->if_xname, IFNAMSIZ);
825 		(void)(*p->if_ioctl)(p, SIOCADDMULTI, (caddr_t)ifr);
826 	}
827 }
828