xref: /openbsd-src/sys/net/if_vlan.c (revision 8500990981f885cbe5e6a4958549cacc238b5ae6)
1 /*	$OpenBSD: if_vlan.c,v 1.41 2003/08/15 20:32:19 tedu Exp $ */
2 /*
3  * Copyright 1998 Massachusetts Institute of Technology
4  *
5  * Permission to use, copy, modify, and distribute this software and
6  * its documentation for any purpose and without fee is hereby
7  * granted, provided that both the above copyright notice and this
8  * permission notice appear in all copies, that both the above
9  * copyright notice and this permission notice appear in all
10  * supporting documentation, and that the name of M.I.T. not be used
11  * in advertising or publicity pertaining to distribution of the
12  * software without specific, written prior permission.  M.I.T. makes
13  * no representations about the suitability of this software for any
14  * purpose.  It is provided "as is" without express or implied
15  * warranty.
16  *
17  * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''.  M.I.T. DISCLAIMS
18  * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
19  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
20  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
21  * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
27  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  *
30  * $FreeBSD: src/sys/net/if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp $
31  */
32 
33 /*
34  * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs.
35  * Might be extended some day to also handle IEEE 802.1p priority
36  * tagging.  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 and extraction in firmware.
45  * The vlan interface behavior changes when the IFCAP_VLAN_HWTAGGING
46  * capability is set on the parent.  In this case, vlan_start() will not
47  * modify the ethernet header.  On input, the parent can call vlan_input_tag()
48  * directly in order to supply us with an incoming mbuf and the vlan
49  * tag value that goes with it.
50  */
51 
52 #include "vlan.h"
53 
54 #include <sys/param.h>
55 #include <sys/kernel.h>
56 #include <sys/malloc.h>
57 #include <sys/mbuf.h>
58 #include <sys/queue.h>
59 #include <sys/socket.h>
60 #include <sys/sockio.h>
61 #include <sys/sysctl.h>
62 #include <sys/systm.h>
63 #include <sys/proc.h>
64 
65 #include "bpfilter.h"
66 #if NBPFILTER > 0
67 #include <net/bpf.h>
68 #endif
69 
70 #include <net/if.h>
71 #include <net/if_dl.h>
72 #include <net/if_types.h>
73 
74 #ifdef INET
75 #include <netinet/in.h>
76 #include <netinet/if_ether.h>
77 #endif
78 
79 #include <net/if_vlan_var.h>
80 
81 extern struct	ifaddr	**ifnet_addrs;
82 
83 struct ifvlan *ifv_softc;
84 int nifvlan;
85 
86 extern int ifqmaxlen;
87 
88 void	vlan_start (struct ifnet *ifp);
89 int	vlan_ioctl (struct ifnet *ifp, u_long cmd, caddr_t addr);
90 int	vlan_setmulti (struct ifnet *ifp);
91 int	vlan_unconfig (struct ifnet *ifp);
92 int	vlan_config (struct ifvlan *ifv, struct ifnet *p);
93 void	vlanattach (int count);
94 int	vlan_set_promisc (struct ifnet *ifp);
95 int	vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
96 int	vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
97 void	vlan_ether_purgemulti(struct ifvlan *);
98 
99 void
100 vlanattach(int count)
101 {
102 	struct ifnet *ifp;
103 	int i;
104 
105 	MALLOC(ifv_softc, struct ifvlan *, count * sizeof(struct ifvlan),
106 	    M_DEVBUF, M_NOWAIT);
107 	if (ifv_softc == NULL)
108 		panic("vlanattach: MALLOC failed");
109 	nifvlan = count;
110 	bzero(ifv_softc, nifvlan * sizeof(struct ifvlan));
111 
112 	for (i = 0; i < nifvlan; i++) {
113 		LIST_INIT(&ifv_softc[i].vlan_mc_listhead);
114 		ifp = &ifv_softc[i].ifv_if;
115 		ifp->if_softc = &ifv_softc[i];
116 		snprintf(ifp->if_xname, sizeof ifp->if_xname, "vlan%d", i);
117 		/* NB: flags are not set here */
118 		/* NB: mtu is not set here */
119 
120 		ifp->if_start = vlan_start;
121 		ifp->if_ioctl = vlan_ioctl;
122 		ifp->if_output = ether_output;
123 		IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
124 		IFQ_SET_READY(&ifp->if_snd);
125 		if_attach(ifp);
126 		ether_ifattach(ifp);
127 
128 		/* Now undo some of the damage... */
129 		ifp->if_type = IFT_8021_VLAN;
130 		ifp->if_hdrlen = EVL_ENCAPLEN;
131 	}
132 }
133 
134 void
135 vlan_start(struct ifnet *ifp)
136 {
137 	struct ifvlan *ifv;
138 	struct ifnet *p;
139 	struct mbuf *m, *m0;
140 	int error;
141 
142 	ifv = ifp->if_softc;
143 	p = ifv->ifv_p;
144 
145 	ifp->if_flags |= IFF_OACTIVE;
146 	for (;;) {
147 		IFQ_DEQUEUE(&ifp->if_snd, m);
148 		if (m == NULL)
149 			break;
150 
151 		if ((p->if_flags & (IFF_UP|IFF_RUNNING)) !=
152 		    (IFF_UP|IFF_RUNNING)) {
153 			IF_DROP(&p->if_snd);
154 				/* XXX stats */
155 			ifp->if_oerrors++;
156 			m_freem(m);
157 			continue;
158 		}
159 
160 #if NBPFILTER > 0
161 		if (ifp->if_bpf)
162 			bpf_mtap(ifp->if_bpf, m);
163 #endif
164 
165 		/*
166 		 * If the IFCAP_VLAN_HWTAGGING capability is set on the parent,
167 		 * it can do VLAN tag insertion itself and doesn't require us
168 	 	 * to create a special header for it. In this case, we just pass
169 		 * the packet along. However, we need some way to tell the
170 		 * interface where the packet came from so that it knows how
171 		 * to find the VLAN tag to use, so we set the rcvif in the
172 		 * mbuf header to our ifnet.
173 		 *
174 		 * Note: we also set the M_PROTO1 flag in the mbuf to let
175 		 * the parent driver know that the rcvif pointer is really
176 		 * valid. We need to do this because sometimes mbufs will
177 		 * be allocated by other parts of the system that contain
178 		 * garbage in the rcvif pointer. Using the M_PROTO1 flag
179 		 * lets the driver perform a proper sanity check and avoid
180 		 * following potentially bogus rcvif pointers off into
181 		 * never-never land.
182 		 */
183 		if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) {
184 			m->m_pkthdr.rcvif = ifp;
185 			m->m_flags |= M_PROTO1;
186 		} else {
187 			struct ether_vlan_header evh;
188 
189 			m_copydata(m, 0, sizeof(struct ether_header),
190 			    (caddr_t)&evh);
191 			evh.evl_proto = evh.evl_encap_proto;
192 			evh.evl_encap_proto = htons(ETHERTYPE_8021Q);
193 			evh.evl_tag = htons(ifv->ifv_tag);
194 			m_adj(m, sizeof(struct ether_header));
195 
196 			m0 = m_prepend(m, sizeof(struct ether_vlan_header),
197 			    M_DONTWAIT);
198 			if (m0 == NULL) {
199 				ifp->if_ierrors++;
200 				continue;
201 			}
202 
203 			/* m_prepend() doesn't adjust m_pkthdr.len */
204 			if (m0->m_flags & M_PKTHDR)
205 				m0->m_pkthdr.len +=
206 				    sizeof(struct ether_vlan_header);
207 
208 			m_copyback(m0, 0, sizeof(struct ether_vlan_header),
209 			    &evh);
210 
211 			m = m0;
212 		}
213 
214 		/*
215 		 * Send it, precisely as ether_output() would have.
216 		 * We are already running at splimp.
217 		 */
218 		p->if_obytes += m->m_pkthdr.len;
219 		if (m->m_flags & M_MCAST)
220 			p->if_omcasts++;
221 		IFQ_ENQUEUE(&p->if_snd, m, NULL, error);
222 		if (error) {
223 			/* mbuf is already freed */
224 			ifp->if_oerrors++;
225 			continue;
226 		}
227 
228 		ifp->if_opackets++;
229 		if ((p->if_flags & IFF_OACTIVE) == 0)
230 			p->if_start(p);
231 	}
232 	ifp->if_flags &= ~IFF_OACTIVE;
233 
234 	return;
235 }
236 
237 int
238 vlan_input_tag(struct mbuf *m, u_int16_t t)
239 {
240 	int i;
241 	struct ifvlan *ifv;
242 	struct ether_vlan_header vh;
243 
244 	t = EVL_VLANOFTAG(t);
245 	for (i = 0; i < nifvlan; i++) {
246 		ifv = &ifv_softc[i];
247 		if (m->m_pkthdr.rcvif == ifv->ifv_p && t == ifv->ifv_tag)
248 			break;
249 	}
250 
251 	if (i >= nifvlan) {
252 		if (m->m_pkthdr.len < sizeof(struct ether_header)) {
253 			m_freem(m);
254 			return (-1);
255 		}
256 		m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&vh);
257 		vh.evl_proto = vh.evl_encap_proto;
258 		vh.evl_tag = htons(t);
259 		vh.evl_encap_proto = htons(ETHERTYPE_8021Q);
260 		m_adj(m, sizeof(struct ether_header));
261 		m = m_prepend(m, sizeof(struct ether_vlan_header), M_DONTWAIT);
262 		if (m == NULL)
263 			return (-1);
264 		m->m_pkthdr.len += sizeof(struct ether_vlan_header);
265 		if (m->m_len < sizeof(struct ether_vlan_header) &&
266 		    (m = m_pullup(m, sizeof(struct ether_vlan_header))) == NULL)
267 			return (-1);
268 		m_copyback(m, 0, sizeof(struct ether_vlan_header), &vh);
269 		ether_input_mbuf(m->m_pkthdr.rcvif, m);
270 		return (-1);
271 	}
272 
273 	if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
274 	    (IFF_UP|IFF_RUNNING)) {
275 		m_freem(m);
276 		return (-1);
277 	}
278 
279 	/*
280 	 * Having found a valid vlan interface corresponding to
281 	 * the given source interface and vlan tag, run the
282 	 * the real packet through ether_input().
283 	 */
284 	m->m_pkthdr.rcvif = &ifv->ifv_if;
285 
286 #if NBPFILTER > 0
287 	if (ifv->ifv_if.if_bpf) {
288 		/*
289 		 * Do the usual BPF fakery.  Note that we don't support
290 		 * promiscuous mode here, since it would require the
291 		 * drivers to know about VLANs and we're not ready for
292 		 * that yet.
293 		 */
294 		bpf_mtap(ifv->ifv_if.if_bpf, m);
295 	}
296 #endif
297 	ifv->ifv_if.if_ipackets++;
298 	ether_input_mbuf(&ifv->ifv_if, m);
299 	return 0;
300 }
301 
302 int
303 vlan_input(eh, m)
304 	struct ether_header *eh;
305 	struct mbuf *m;
306 {
307 	int i;
308 	struct ifvlan *ifv;
309 	u_int tag;
310 	struct ifnet *ifp = m->m_pkthdr.rcvif;
311 
312 	if (m->m_len < EVL_ENCAPLEN &&
313 	    (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
314 		ifp->if_ierrors++;
315 		return (0);
316 	}
317 
318 	tag = EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *)));
319 
320 	for (i = 0; i < nifvlan; i++) {
321 		ifv = &ifv_softc[i];
322 		if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag)
323 			break;
324 	}
325 
326 	if (i >= nifvlan || (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
327 	    (IFF_UP|IFF_RUNNING)) {
328 		m_freem(m);
329 		return -1;	/* so ether_input can take note */
330 	}
331 
332 	/*
333 	 * Having found a valid vlan interface corresponding to
334 	 * the given source interface and vlan tag, remove the
335 	 * encapsulation, and run the real packet through
336 	 * ether_input() a second time (it had better be
337 	 * reentrant!).
338 	 */
339 	m->m_pkthdr.rcvif = &ifv->ifv_if;
340 	eh->ether_type = mtod(m, u_int16_t *)[1];
341 	m->m_len -= EVL_ENCAPLEN;
342 	m->m_data += EVL_ENCAPLEN;
343 	m->m_pkthdr.len -= EVL_ENCAPLEN;
344 
345 #if NBPFILTER > 0
346 	if (ifv->ifv_if.if_bpf) {
347 		/*
348 		 * Do the usual BPF fakery.  Note that we don't support
349 		 * promiscuous mode here, since it would require the
350 		 * drivers to know about VLANs and we're not ready for
351 		 * that yet.
352 		 */
353 		struct mbuf m0;
354 
355 		m0.m_flags = 0;
356 		m0.m_next = m;
357 		m0.m_len = sizeof(struct ether_header);
358 		m0.m_data = (char *)eh;
359 		bpf_mtap(ifv->ifv_if.if_bpf, &m0);
360 	}
361 #endif
362 	ifv->ifv_if.if_ipackets++;
363 	ether_input(&ifv->ifv_if, eh, m);
364 
365 	return 0;
366 }
367 
368 int
369 vlan_config(struct ifvlan *ifv, struct ifnet *p)
370 {
371 	struct ifaddr *ifa1, *ifa2;
372 	struct sockaddr_dl *sdl1, *sdl2;
373 
374 	if (p->if_type != IFT_ETHER)
375 		return EPROTONOSUPPORT;
376 	if (ifv->ifv_p)
377 		return EBUSY;
378 	ifv->ifv_p = p;
379 
380 	if (p->if_capabilities & IFCAP_VLAN_MTU)
381 		ifv->ifv_if.if_mtu = p->if_mtu;
382 	else {
383 		/*
384 		 * This will be incompatible with strict
385 		 * 802.1Q implementations
386 		 */
387 		ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN;
388 #ifdef DIAGNOSTIC
389 		printf("%s: initialized with non-standard mtu %lu (parent %s)\n",
390 		    ifv->ifv_if.if_xname, ifv->ifv_if.if_mtu,
391 		    ifv->ifv_p->if_xname);
392 #endif
393 	}
394 
395 	ifv->ifv_if.if_flags = p->if_flags &
396 	    (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
397 
398 	/*
399 	 * Inherit the if_type from the parent.  This allows us to
400 	 * participate in bridges of that type.
401 	 */
402 	ifv->ifv_if.if_type = p->if_type;
403 
404 	/*
405 	 * Inherit baudrate from the parent.  An SNMP agent would use this
406 	 * information.
407 	 */
408 	ifv->ifv_if.if_baudrate = p->if_baudrate;
409 
410 	/*
411 	 * If the parent interface can do hardware-assisted
412 	 * VLAN encapsulation, then propagate its hardware-
413 	 * assisted checksumming flags.
414 	 *
415 	 * If the card cannot handle hardware tagging, it cannot
416 	 * possibly compute the correct checksums for tagged packets.
417 	 *
418 	 * This brings up another possibility, do cards exist which
419 	 * have all of these capabilities but cannot utilize them together?
420 	 */
421 	if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
422 		ifv->ifv_if.if_capabilities = p->if_capabilities &
423 		    (IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4|
424 		    IFCAP_CSUM_UDPv4);
425 		/* (IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6); */
426 
427 	/*
428 	 * Set up our ``Ethernet address'' to reflect the underlying
429 	 * physical interface's.
430 	 */
431 	ifa1 = ifnet_addrs[ifv->ifv_if.if_index];
432 	ifa2 = ifnet_addrs[p->if_index];
433 	sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
434 	sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
435 	sdl1->sdl_type = IFT_ETHER;
436 	sdl1->sdl_alen = ETHER_ADDR_LEN;
437 	bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
438 	bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
439 	return 0;
440 }
441 
442 int
443 vlan_unconfig(struct ifnet *ifp)
444 {
445 	struct ifaddr *ifa;
446 	struct sockaddr_dl *sdl;
447 	struct ifvlan *ifv;
448 	struct ifnet *p;
449 	struct ifreq *ifr, *ifr_p;
450 
451 	ifv = ifp->if_softc;
452 	p = ifv->ifv_p;
453 	ifr = (struct ifreq *)&ifp->if_data;
454 	ifr_p = (struct ifreq *)&ifv->ifv_p->if_data;
455 
456 	if (p == NULL)
457 		return 0;
458 
459 	/*
460  	 * Since the interface is being unconfigured, we need to
461 	 * empty the list of multicast groups that we may have joined
462 	 * while we were alive and remove them from the parent's list
463 	 * as well.
464 	 */
465 	vlan_ether_purgemulti(ifv);
466 
467 	/* Disconnect from parent. */
468 	ifv->ifv_p = NULL;
469 	ifv->ifv_if.if_mtu = ETHERMTU;
470 
471 	/* Clear our MAC address. */
472 	ifa = ifnet_addrs[ifv->ifv_if.if_index];
473 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
474 	sdl->sdl_type = IFT_ETHER;
475 	sdl->sdl_alen = ETHER_ADDR_LEN;
476 	bzero(LLADDR(sdl), ETHER_ADDR_LEN);
477 	bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
478 
479 	return 0;
480 }
481 
482 int
483 vlan_set_promisc(struct ifnet *ifp)
484 {
485 	struct ifvlan *ifv = ifp->if_softc;
486 	int error = 0;
487 
488 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
489 		if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
490 			error = ifpromisc(ifv->ifv_p, 1);
491 			if (error == 0)
492 				ifv->ifv_flags |= IFVF_PROMISC;
493 		}
494 	} else {
495 		if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
496 			error = ifpromisc(ifv->ifv_p, 0);
497 			if (error == 0)
498 				ifv->ifv_flags &= ~IFVF_PROMISC;
499 		}
500 	}
501 
502 	return (0);
503 }
504 
505 int
506 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
507 {
508 	struct proc *p = curproc;	/* XXX */
509 	struct ifaddr *ifa;
510 	struct ifnet *pr;
511 	struct ifreq *ifr;
512 	struct ifvlan *ifv;
513 	struct vlanreq vlr;
514 	int error = 0, p_mtu = 0;
515 
516 	ifr = (struct ifreq *)data;
517 	ifa = (struct ifaddr *)data;
518 	ifv = ifp->if_softc;
519 
520 	switch (cmd) {
521 	case SIOCSIFADDR:
522 		if (ifv->ifv_p != NULL) {
523 			ifp->if_flags |= IFF_UP;
524 
525 			switch (ifa->ifa_addr->sa_family) {
526 #ifdef INET
527 			case AF_INET:
528 				arp_ifinit(&ifv->ifv_ac, ifa);
529 				break;
530 #endif
531 			default:
532 				break;
533 			}
534 		} else {
535 			error = EINVAL;
536 		}
537 		break;
538 
539 	case SIOCGIFADDR:
540 		{
541 			struct sockaddr *sa;
542 
543 			sa = (struct sockaddr *) &ifr->ifr_data;
544 			bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
545 			    (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
546 		}
547 		break;
548 
549 	case SIOCSIFMTU:
550 		if (ifv->ifv_p != NULL) {
551 			if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU)
552 				p_mtu = ifv->ifv_p->if_mtu;
553 			else
554 				p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN;
555 
556 			if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN)
557 				error = EINVAL;
558 			else
559 				ifp->if_mtu = ifr->ifr_mtu;
560 		} else
561 			error = EINVAL;
562 
563 		break;
564 
565 	case SIOCSETVLAN:
566 		if ((error = suser(p, 0)) != 0)
567 			break;
568 		if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr)))
569 			break;
570 		if (vlr.vlr_parent[0] == '\0') {
571 			vlan_unconfig(ifp);
572 			if_down(ifp);
573 			ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
574 			break;
575 		}
576 		if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
577 			error = EINVAL;		 /* check for valid tag */
578 			break;
579 		}
580 		pr = ifunit(vlr.vlr_parent);
581 		if (pr == NULL) {
582 			error = ENOENT;
583 			break;
584 		}
585 		error = vlan_config(ifv, pr);
586 		if (error)
587 			break;
588 		ifv->ifv_tag = vlr.vlr_tag;
589 		ifp->if_flags |= IFF_RUNNING;
590 
591 		/* Update promiscuous mode, if necessary. */
592 		vlan_set_promisc(ifp);
593 		break;
594 
595 	case SIOCGETVLAN:
596 		bzero(&vlr, sizeof vlr);
597 		if (ifv->ifv_p) {
598 			snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
599 			    "%s", ifv->ifv_p->if_xname);
600 			vlr.vlr_tag = ifv->ifv_tag;
601 		}
602 		error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
603 		break;
604 
605 	case SIOCSIFFLAGS:
606 		/*
607 		 * For promiscuous mode, we enable promiscuous mode on
608 		 * the parent if we need promiscuous on the VLAN interface.
609 		 */
610 		if (ifv->ifv_p != NULL)
611 			error = vlan_set_promisc(ifp);
612 		break;
613 	case SIOCADDMULTI:
614 		error = (ifv->ifv_p != NULL) ?
615 		    vlan_ether_addmulti(ifv, ifr) : EINVAL;
616 		break;
617 
618 	case SIOCDELMULTI:
619 		error = (ifv->ifv_p != NULL) ?
620 		    vlan_ether_delmulti(ifv, ifr) : EINVAL;
621 		break;
622 	default:
623 		error = EINVAL;
624 	}
625 	return error;
626 }
627 
628 
629 int
630 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
631 {
632 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
633 	struct vlan_mc_entry *mc;
634 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
635 	int error;
636 
637 	if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage))
638 		return (EINVAL);
639 
640 	error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
641 	if (error != ENETRESET)
642 		return (error);
643 
644 	/*
645 	 * This is new multicast address.  We have to tell parent
646 	 * about it.  Also, remember this multicast address so that
647 	 * we can delete them on unconfigure.
648 	 */
649 	MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry),
650 	    M_DEVBUF, M_NOWAIT);
651 	if (mc == NULL) {
652 		error = ENOMEM;
653 		goto alloc_failed;
654 	}
655 
656 	/*
657 	 * As ether_addmulti() returns ENETRESET, following two
658 	 * statement shouldn't fail.
659 	 */
660 	(void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
661 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm);
662 	memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
663 	LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
664 
665 	error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr);
666 	if (error != 0)
667 		goto ioctl_failed;
668 
669 	return (error);
670 
671  ioctl_failed:
672 	LIST_REMOVE(mc, mc_entries);
673 	FREE(mc, M_DEVBUF);
674  alloc_failed:
675 	(void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
676 
677 	return (error);
678 }
679 
680 int
681 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
682 {
683 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
684 	struct ether_multi *enm;
685 	struct vlan_mc_entry *mc;
686 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
687 	int error;
688 
689 	/*
690 	 * Find a key to lookup vlan_mc_entry.  We have to do this
691 	 * before calling ether_delmulti for obvious reason.
692 	 */
693 	if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
694 		return (error);
695 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm);
696 
697 	error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
698 	if (error != ENETRESET)
699 		return (error);
700 
701 	/* We no longer use this multicast address.  Tell parent so. */
702 	error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
703 	if (error == 0) {
704 		/* And forget about this address. */
705 		for (mc = LIST_FIRST(&ifv->vlan_mc_listhead); mc != NULL;
706 		    mc = LIST_NEXT(mc, mc_entries)) {
707 			if (mc->mc_enm == enm) {
708 				LIST_REMOVE(mc, mc_entries);
709 				FREE(mc, M_DEVBUF);
710 				break;
711 			}
712 		}
713 		KASSERT(mc != NULL);
714 	} else
715 		(void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
716 	return (error);
717 }
718 
719 /*
720  * Delete any multicast address we have asked to add from parent
721  * interface.  Called when the vlan is being unconfigured.
722  */
723 void
724 vlan_ether_purgemulti(struct ifvlan *ifv)
725 {
726 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
727 	struct vlan_mc_entry *mc;
728 	union {
729 		struct ifreq ifreq;
730 		struct {
731 			char ifr_name[IFNAMSIZ];
732 			struct sockaddr_storage ifr_ss;
733 		} ifreq_storage;
734 	} ifreq;
735 	struct ifreq *ifr = &ifreq.ifreq;
736 
737 	memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
738 	while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
739 		memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
740 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
741 		LIST_REMOVE(mc, mc_entries);
742 		FREE(mc, M_DEVBUF);
743 	}
744 }
745