xref: /openbsd-src/sys/net/if_vlan.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: if_vlan.c,v 1.108 2014/07/12 18:44:22 tedu 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 int	vlan_output(struct ifnet *, struct mbuf *, struct sockaddr *,
84 	    struct rtentry *);
85 void	vlan_start(struct ifnet *ifp);
86 int	vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t addr);
87 int	vlan_unconfig(struct ifnet *ifp, struct ifnet *newp);
88 int	vlan_config(struct ifvlan *, struct ifnet *, u_int16_t);
89 void	vlan_vlandev_state(void *);
90 void	vlanattach(int count);
91 int	vlan_set_promisc(struct ifnet *ifp);
92 int	vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
93 int	vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
94 void	vlan_ether_purgemulti(struct ifvlan *);
95 void	vlan_ether_resetmulti(struct ifvlan *, struct ifnet *);
96 int	vlan_clone_create(struct if_clone *, int);
97 int	vlan_clone_destroy(struct ifnet *);
98 void	vlan_ifdetach(void *);
99 
100 struct if_clone vlan_cloner =
101     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
102 struct if_clone svlan_cloner =
103     IF_CLONE_INITIALIZER("svlan", vlan_clone_create, vlan_clone_destroy);
104 
105 /* ARGSUSED */
106 void
107 vlanattach(int count)
108 {
109 	/* Normal VLAN */
110 	vlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT,
111 	    &vlan_tagmask);
112 	if (vlan_tagh == NULL)
113 		panic("vlanattach: hashinit");
114 	if_clone_attach(&vlan_cloner);
115 
116 	/* Service-VLAN for QinQ/802.1ad provider bridges */
117 	svlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT,
118 	    &svlan_tagmask);
119 	if (svlan_tagh == NULL)
120 		panic("vlanattach: hashinit");
121 	if_clone_attach(&svlan_cloner);
122 }
123 
124 int
125 vlan_clone_create(struct if_clone *ifc, int unit)
126 {
127 	struct ifvlan	*ifv;
128 	struct ifnet	*ifp;
129 
130 	if ((ifv = malloc(sizeof(*ifv), M_DEVBUF, M_NOWAIT|M_ZERO)) == NULL)
131 		return (ENOMEM);
132 
133 	LIST_INIT(&ifv->vlan_mc_listhead);
134 	ifp = &ifv->ifv_if;
135 	ifp->if_softc = ifv;
136 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
137 	    unit);
138 	/* NB: flags are not set here */
139 	/* NB: mtu is not set here */
140 
141 	/* Special handling for the IEEE 802.1ad QinQ variant */
142 	if (strcmp("svlan", ifc->ifc_name) == 0)
143 		ifv->ifv_type = ETHERTYPE_QINQ;
144 	else
145 		ifv->ifv_type = ETHERTYPE_VLAN;
146 
147 	ifp->if_start = vlan_start;
148 	ifp->if_ioctl = vlan_ioctl;
149 	IFQ_SET_MAXLEN(&ifp->if_snd, 1);
150 	IFQ_SET_READY(&ifp->if_snd);
151 	if_attach(ifp);
152 	ether_ifattach(ifp);
153 	ifp->if_hdrlen = EVL_ENCAPLEN;
154 	ifp->if_output = vlan_output;
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 	free(ifv, M_DEVBUF, 0);
168 	return (0);
169 }
170 
171 void
172 vlan_ifdetach(void *ptr)
173 {
174 	struct ifvlan	*ifv = ptr;
175 	vlan_clone_destroy(&ifv->ifv_if);
176 }
177 
178 int
179 vlan_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
180     struct rtentry *rt)
181 {
182 	/*
183 	 * we have to use a custom output function because ether_output
184 	 * can't figure out ifp is a vlan in a reasonable way
185 	 */
186 	m->m_flags |= M_VLANTAG;
187 	return (ether_output(ifp, m, dst, rt));
188 }
189 
190 void
191 vlan_start(struct ifnet *ifp)
192 {
193 	struct ifvlan	*ifv;
194 	struct ifnet	*p;
195 	struct mbuf	*m;
196 	int		 error;
197 
198 	ifv = ifp->if_softc;
199 	p = ifv->ifv_p;
200 
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 			ifp->if_oerrors++;
210 			m_freem(m);
211 			continue;
212 		}
213 
214 #if NBPFILTER > 0
215 		if (ifp->if_bpf)
216 			bpf_mtap_stripvlan(ifp->if_bpf, m, BPF_DIRECTION_OUT);
217 #endif
218 
219 		/*
220 		 * Send it, precisely as ether_output() would have.
221 		 * We are already running at splnet.
222 		 */
223 		IFQ_ENQUEUE(&p->if_snd, m, NULL, error);
224 		if (error) {
225 			/* mbuf is already freed */
226 			ifp->if_oerrors++;
227 			continue;
228 		}
229 		p->if_obytes += m->m_pkthdr.len;
230 		if (m->m_flags & M_MCAST)
231 			p->if_omcasts++;
232 
233 		ifp->if_opackets++;
234 		if_start(p);
235 	}
236 }
237 
238 /*
239  * vlan_input() returns 0 if it has consumed the packet, 1 otherwise.
240  */
241 int
242 vlan_input(struct ether_header *eh, struct mbuf *m)
243 {
244 	struct ifvlan		*ifv;
245 	struct ifnet		*ifp = m->m_pkthdr.rcvif;
246 	struct vlan_taghash	*tagh;
247 	u_int			 tag;
248 	u_int16_t		 etype;
249 
250 	if (m->m_flags & M_VLANTAG) {
251 		etype = ETHERTYPE_VLAN;
252 		tagh = vlan_tagh;
253 	} else {
254 		if (m->m_len < EVL_ENCAPLEN &&
255 		    (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
256 			ifp->if_ierrors++;
257 			return (0);
258 		}
259 
260 		etype = ntohs(eh->ether_type);
261 		tagh = etype == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
262 		m->m_pkthdr.ether_vtag = ntohs(*mtod(m, u_int16_t *));
263 	}
264 	/* From now on ether_vtag is fine */
265 	tag = EVL_VLANOFTAG(m->m_pkthdr.ether_vtag);
266 	m->m_pkthdr.pf.prio = EVL_PRIOFTAG(m->m_pkthdr.ether_vtag);
267 
268 	LIST_FOREACH(ifv, &tagh[TAG_HASH(tag)], ifv_list) {
269 		if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag &&
270 		    etype == ifv->ifv_type)
271 			break;
272 	}
273 	if (ifv == NULL)
274 		return (1);
275 
276 	if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
277 	    (IFF_UP|IFF_RUNNING)) {
278 		m_freem(m);
279 		return (0);
280 	}
281 
282 	/*
283 	 * Having found a valid vlan interface corresponding to
284 	 * the given source interface and vlan tag, remove the
285 	 * encapsulation, and run the real packet through
286 	 * ether_input() a second time (it had better be
287 	 * reentrant!).
288 	 */
289 	m->m_pkthdr.rcvif = &ifv->ifv_if;
290 	if (m->m_flags & M_VLANTAG) {
291 		m->m_flags &= ~M_VLANTAG;
292 	} else {
293 		eh->ether_type = mtod(m, u_int16_t *)[1];
294 		m->m_len -= EVL_ENCAPLEN;
295 		m->m_data += EVL_ENCAPLEN;
296 		m->m_pkthdr.len -= EVL_ENCAPLEN;
297 	}
298 
299 #if NBPFILTER > 0
300 	if (ifv->ifv_if.if_bpf)
301 		bpf_mtap_hdr(ifv->ifv_if.if_bpf, (char *)eh, ETHER_HDR_LEN, m,
302 		    BPF_DIRECTION_IN, NULL);
303 #endif
304 
305 	/*
306 	 * Drop promiscuously received packets if we are not in
307 	 * promiscuous mode.
308 	 */
309 	if ((m->m_flags & (M_BCAST|M_MCAST)) == 0 &&
310 	    (ifp->if_flags & IFF_PROMISC) &&
311 	    (ifv->ifv_if.if_flags & IFF_PROMISC) == 0) {
312 		if (bcmp(&ifv->ifv_ac.ac_enaddr, eh->ether_dhost,
313 		    ETHER_ADDR_LEN)) {
314 			m_freem(m);
315 			return (0);
316 		}
317 	}
318 
319 	ifv->ifv_if.if_ipackets++;
320 	ether_input(&ifv->ifv_if, eh, m);
321 
322 	return (0);
323 }
324 
325 int
326 vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
327 {
328 	struct sockaddr_dl	*sdl1, *sdl2;
329 	struct vlan_taghash	*tagh;
330 	u_int			 flags;
331 	int			 s;
332 
333 	if (p->if_type != IFT_ETHER)
334 		return EPROTONOSUPPORT;
335 	if (ifv->ifv_p == p && ifv->ifv_tag == tag) /* noop */
336 		return (0);
337 
338 	/* Remember existing interface flags and reset the interface */
339 	flags = ifv->ifv_flags;
340 	vlan_unconfig(&ifv->ifv_if, p);
341 	ifv->ifv_p = p;
342 	ifv->ifv_if.if_baudrate = p->if_baudrate;
343 
344 	if (p->if_capabilities & IFCAP_VLAN_MTU)
345 		ifv->ifv_if.if_mtu = p->if_mtu;
346 	else
347 		ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN;
348 
349 	ifv->ifv_if.if_flags = p->if_flags &
350 	    (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
351 
352 	/* Reset promisc mode on the interface and its parent */
353 	if (flags & IFVF_PROMISC) {
354 		ifv->ifv_if.if_flags |= IFF_PROMISC;
355 		vlan_set_promisc(&ifv->ifv_if);
356 	}
357 
358 	/*
359 	 * If the parent interface can do hardware-assisted
360 	 * VLAN encapsulation, then propagate its hardware-
361 	 * assisted checksumming flags.
362 	 *
363 	 * If the card cannot handle hardware tagging, it cannot
364 	 * possibly compute the correct checksums for tagged packets.
365 	 */
366 	if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
367 		ifv->ifv_if.if_capabilities = p->if_capabilities &
368 		    IFCAP_CSUM_MASK;
369 
370 	/*
371 	 * Hardware VLAN tagging only works with the default VLAN
372 	 * ethernet type (0x8100).
373 	 */
374 	if (ifv->ifv_type != ETHERTYPE_VLAN)
375 		ifv->ifv_if.if_capabilities &= ~IFCAP_VLAN_HWTAGGING;
376 
377 	/*
378 	 * Set up our ``Ethernet address'' to reflect the underlying
379 	 * physical interface's.
380 	 */
381 	sdl1 = ifv->ifv_if.if_sadl;
382 	sdl2 = p->if_sadl;
383 	sdl1->sdl_type = IFT_ETHER;
384 	sdl1->sdl_alen = ETHER_ADDR_LEN;
385 	bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
386 	bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
387 
388 	ifv->ifv_tag = tag;
389 	s = splnet();
390 	tagh = ifv->ifv_type == ETHERTYPE_QINQ ? svlan_tagh : vlan_tagh;
391 	LIST_INSERT_HEAD(&tagh[TAG_HASH(tag)], ifv, ifv_list);
392 
393 	/* Register callback for physical link state changes */
394 	ifv->lh_cookie = hook_establish(p->if_linkstatehooks, 1,
395 	    vlan_vlandev_state, ifv);
396 
397 	/* Register callback if parent wants to unregister */
398 	ifv->dh_cookie = hook_establish(p->if_detachhooks, 0,
399 	    vlan_ifdetach, ifv);
400 
401 	vlan_vlandev_state(ifv);
402 	splx(s);
403 
404 	return (0);
405 }
406 
407 int
408 vlan_unconfig(struct ifnet *ifp, struct ifnet *newp)
409 {
410 	struct sockaddr_dl	*sdl;
411 	struct ifvlan		*ifv;
412 	struct ifnet		*p;
413 	int			 s;
414 
415 	ifv = ifp->if_softc;
416 	if ((p = ifv->ifv_p) == NULL)
417 		return 0;
418 
419 	/* Unset promisc mode on the interface and its parent */
420 	if (ifv->ifv_flags & IFVF_PROMISC) {
421 		ifp->if_flags &= ~IFF_PROMISC;
422 		vlan_set_promisc(ifp);
423 	}
424 
425 	s = splnet();
426 	LIST_REMOVE(ifv, ifv_list);
427 	splx(s);
428 
429 	hook_disestablish(p->if_linkstatehooks, ifv->lh_cookie);
430 	hook_disestablish(p->if_detachhooks, ifv->dh_cookie);
431 	/* Reset link state */
432 	if (newp != NULL) {
433 		ifp->if_link_state = LINK_STATE_INVALID;
434 		if_link_state_change(ifp);
435 	}
436 
437 	/*
438  	 * Since the interface is being unconfigured, we need to
439 	 * empty the list of multicast groups that we may have joined
440 	 * while we were alive and remove them from the parent's list
441 	 * as well.
442 	 */
443 	vlan_ether_resetmulti(ifv, newp);
444 
445 	/* Disconnect from parent. */
446 	ifv->ifv_p = NULL;
447 	ifv->ifv_if.if_mtu = ETHERMTU;
448 	ifv->ifv_flags = 0;
449 
450 	/* Clear our MAC address. */
451 	sdl = ifv->ifv_if.if_sadl;
452 	sdl->sdl_type = IFT_ETHER;
453 	sdl->sdl_alen = ETHER_ADDR_LEN;
454 	bzero(LLADDR(sdl), ETHER_ADDR_LEN);
455 	bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
456 
457 	return (0);
458 }
459 
460 void
461 vlan_vlandev_state(void *v)
462 {
463 	struct ifvlan	*ifv = v;
464 
465 	if (ifv->ifv_if.if_link_state == ifv->ifv_p->if_link_state)
466 		return;
467 
468 	ifv->ifv_if.if_link_state = ifv->ifv_p->if_link_state;
469 	ifv->ifv_if.if_baudrate = ifv->ifv_p->if_baudrate;
470 	if_link_state_change(&ifv->ifv_if);
471 }
472 
473 int
474 vlan_set_promisc(struct ifnet *ifp)
475 {
476 	struct ifvlan	*ifv = ifp->if_softc;
477 	int		 error = 0;
478 
479 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
480 		if ((ifv->ifv_flags & IFVF_PROMISC) == 0)
481 			if ((error = ifpromisc(ifv->ifv_p, 1)) == 0)
482 				ifv->ifv_flags |= IFVF_PROMISC;
483 	} else {
484 		if ((ifv->ifv_flags & IFVF_PROMISC) != 0)
485 			if ((error = ifpromisc(ifv->ifv_p, 0)) == 0)
486 				ifv->ifv_flags &= ~IFVF_PROMISC;
487 	}
488 	return (0);
489 }
490 
491 int
492 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
493 {
494 	struct proc	*p = curproc;	/* XXX */
495 	struct ifaddr	*ifa;
496 	struct ifnet	*pr;
497 	struct ifreq	*ifr;
498 	struct ifvlan	*ifv;
499 	struct vlanreq	 vlr;
500 	int		 error = 0, p_mtu = 0, s;
501 
502 	ifr = (struct ifreq *)data;
503 	ifa = (struct ifaddr *)data;
504 	ifv = ifp->if_softc;
505 
506 	switch (cmd) {
507 	case SIOCSIFADDR:
508 		if (ifv->ifv_p != NULL) {
509 			ifp->if_flags |= IFF_UP;
510 #ifdef INET
511 			if (ifa->ifa_addr->sa_family == AF_INET)
512 				arp_ifinit(&ifv->ifv_ac, ifa);
513 #endif
514 		} else
515 			error = EINVAL;
516 		break;
517 
518 	case SIOCGIFADDR:
519 		{
520 			struct sockaddr	*sa;
521 
522 			sa = (struct sockaddr *)&ifr->ifr_data;
523 			bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
524 			    (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
525 		}
526 		break;
527 
528 	case SIOCSIFMTU:
529 		if (ifv->ifv_p != NULL) {
530 			if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU)
531 				p_mtu = ifv->ifv_p->if_mtu;
532 			else
533 				p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN;
534 
535 			if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN)
536 				error = EINVAL;
537 			else
538 				ifp->if_mtu = ifr->ifr_mtu;
539 		} else
540 			error = EINVAL;
541 
542 		break;
543 
544 	case SIOCSETVLAN:
545 		if ((error = suser(p, 0)) != 0)
546 			break;
547 		if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr)))
548 			break;
549 		if (vlr.vlr_parent[0] == '\0') {
550 			s = splnet();
551 			vlan_unconfig(ifp, NULL);
552 			if (ifp->if_flags & IFF_UP)
553 				if_down(ifp);
554 			ifp->if_flags &= ~IFF_RUNNING;
555 			splx(s);
556 			break;
557 		}
558 		pr = ifunit(vlr.vlr_parent);
559 		if (pr == NULL) {
560 			error = ENOENT;
561 			break;
562 		}
563 		/*
564 		 * Don't let the caller set up a VLAN tag with
565 		 * anything except VLID bits.
566 		 */
567 		if (vlr.vlr_tag & ~EVL_VLID_MASK) {
568 			error = EINVAL;
569 			break;
570 		}
571 		error = vlan_config(ifv, pr, vlr.vlr_tag);
572 		if (error)
573 			break;
574 		ifp->if_flags |= IFF_RUNNING;
575 
576 		/* Update promiscuous mode, if necessary. */
577 		vlan_set_promisc(ifp);
578 		break;
579 
580 	case SIOCGETVLAN:
581 		bzero(&vlr, sizeof vlr);
582 		if (ifv->ifv_p) {
583 			snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
584 			    "%s", ifv->ifv_p->if_xname);
585 			vlr.vlr_tag = ifv->ifv_tag;
586 		}
587 		error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
588 		break;
589 	case SIOCSIFFLAGS:
590 		/*
591 		 * For promiscuous mode, we enable promiscuous mode on
592 		 * the parent if we need promiscuous on the VLAN interface.
593 		 */
594 		if (ifv->ifv_p != NULL)
595 			error = vlan_set_promisc(ifp);
596 		break;
597 
598 	case SIOCADDMULTI:
599 		error = (ifv->ifv_p != NULL) ?
600 		    vlan_ether_addmulti(ifv, ifr) : EINVAL;
601 		break;
602 
603 	case SIOCDELMULTI:
604 		error = (ifv->ifv_p != NULL) ?
605 		    vlan_ether_delmulti(ifv, ifr) : EINVAL;
606 		break;
607 	default:
608 		error = ENOTTY;
609 	}
610 	return error;
611 }
612 
613 
614 int
615 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
616 {
617 	struct ifnet		*ifp = ifv->ifv_p;
618 	struct vlan_mc_entry	*mc;
619 	u_int8_t		 addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
620 	int			 error;
621 
622 	error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
623 	if (error != ENETRESET)
624 		return (error);
625 
626 	/*
627 	 * This is new multicast address.  We have to tell parent
628 	 * about it.  Also, remember this multicast address so that
629 	 * we can delete them on unconfigure.
630 	 */
631 	if ((mc = malloc(sizeof(*mc), M_DEVBUF, M_NOWAIT)) == NULL) {
632 		error = ENOMEM;
633 		goto alloc_failed;
634 	}
635 
636 	/*
637 	 * As ether_addmulti() returns ENETRESET, following two
638 	 * statement shouldn't fail.
639 	 */
640 	(void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
641 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm);
642 	memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
643 	LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
644 
645 	if ((error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr)) != 0)
646 		goto ioctl_failed;
647 
648 	return (error);
649 
650  ioctl_failed:
651 	LIST_REMOVE(mc, mc_entries);
652 	free(mc, M_DEVBUF, 0);
653  alloc_failed:
654 	(void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
655 
656 	return (error);
657 }
658 
659 int
660 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
661 {
662 	struct ifnet		*ifp = ifv->ifv_p;
663 	struct ether_multi	*enm;
664 	struct vlan_mc_entry	*mc;
665 	u_int8_t		 addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
666 	int			 error;
667 
668 	/*
669 	 * Find a key to lookup vlan_mc_entry.  We have to do this
670 	 * before calling ether_delmulti for obvious reason.
671 	 */
672 	if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
673 		return (error);
674 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm);
675 	if (enm == NULL)
676 		return (EINVAL);
677 
678 	LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries)
679 		if (mc->mc_enm == enm)
680 			break;
681 
682 	/* We won't delete entries we didn't add */
683 	if (mc == NULL)
684 		return (EINVAL);
685 
686 	if ((error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac)) != 0)
687 		return (error);
688 
689 	/* We no longer use this multicast address.  Tell parent so. */
690 	if ((error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr)) != 0) {
691 		/* And forget about this address. */
692 		LIST_REMOVE(mc, mc_entries);
693 		free(mc, M_DEVBUF, 0);
694 	} else
695 		(void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
696 	return (error);
697 }
698 
699 /*
700  * Delete any multicast address we have asked to add from parent
701  * interface.  Called when the vlan is being unconfigured.
702  */
703 void
704 vlan_ether_purgemulti(struct ifvlan *ifv)
705 {
706 	struct ifnet		*ifp = ifv->ifv_p;
707 	struct vlan_mc_entry	*mc;
708 	union {
709 		struct ifreq ifreq;
710 		struct {
711 			char			ifr_name[IFNAMSIZ];
712 			struct sockaddr_storage	ifr_ss;
713 		} ifreq_storage;
714 	} ifreq;
715 	struct ifreq	*ifr = &ifreq.ifreq;
716 
717 	memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
718 	while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
719 		memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
720 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
721 		LIST_REMOVE(mc, mc_entries);
722 		free(mc, M_DEVBUF, 0);
723 	}
724 }
725 
726 void
727 vlan_ether_resetmulti(struct ifvlan *ifv, struct ifnet *p)
728 {
729 	struct ifnet		*ifp = ifv->ifv_p;
730 	struct vlan_mc_entry	*mc;
731 	union {
732 		struct ifreq ifreq;
733 		struct {
734 			char			ifr_name[IFNAMSIZ];
735 			struct sockaddr_storage	ifr_ss;
736 		} ifreq_storage;
737 	} ifreq;
738 	struct ifreq	*ifr = &ifreq.ifreq;
739 
740 	if (p == NULL) {
741 		vlan_ether_purgemulti(ifv);
742 		return;
743 	} else if (ifp == p)
744 		return;
745 
746 	LIST_FOREACH(mc, &ifv->vlan_mc_listhead, mc_entries) {
747 		memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
748 
749 		/* Remove from the old parent */
750 		memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
751 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
752 
753 		/* Try to add to the new parent */
754 		memcpy(ifr->ifr_name, p->if_xname, IFNAMSIZ);
755 		(void)(*p->if_ioctl)(p, SIOCADDMULTI, (caddr_t)ifr);
756 	}
757 }
758