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