1 /*	$OpenBSD: if_vlan.c,v 1.46 2004/03/27 23:41:04 deraadt 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 extern int ifqmaxlen;
83 u_long vlan_tagmask;
84 
85 #define TAG_HASH_SIZE	32
86 #define TAG_HASH(tag)	(tag & vlan_tagmask)
87 LIST_HEAD(, ifvlan)	*vlan_tagh;
88 
89 void	vlan_start (struct ifnet *ifp);
90 int	vlan_ioctl (struct ifnet *ifp, u_long cmd, caddr_t addr);
91 int	vlan_setmulti (struct ifnet *ifp);
92 int	vlan_unconfig (struct ifnet *ifp);
93 int	vlan_config (struct ifvlan *, struct ifnet *, u_int16_t);
94 void	vlanattach (int count);
95 int	vlan_set_promisc (struct ifnet *ifp);
96 int	vlan_ether_addmulti(struct ifvlan *, struct ifreq *);
97 int	vlan_ether_delmulti(struct ifvlan *, struct ifreq *);
98 void	vlan_ether_purgemulti(struct ifvlan *);
99 int	vlan_clone_create(struct if_clone *, int);
100 int	vlan_clone_destroy(struct ifnet *);
101 
102 struct if_clone vlan_cloner =
103     IF_CLONE_INITIALIZER("vlan", vlan_clone_create, vlan_clone_destroy);
104 
105 /* ARGSUSED */
106 void
vlanattach(int count)107 vlanattach(int count)
108 {
109 	vlan_tagh = hashinit(TAG_HASH_SIZE, M_DEVBUF, M_NOWAIT, &vlan_tagmask);
110 	if (vlan_tagh == NULL)
111 		panic("vlanattach: hashinit");
112 
113 	if_clone_attach(&vlan_cloner);
114 }
115 
116 int
vlan_clone_create(struct if_clone * ifc,int unit)117 vlan_clone_create(struct if_clone *ifc, int unit)
118 {
119 	struct ifvlan *ifv;
120 	struct ifnet *ifp;
121 
122 	ifv = malloc(sizeof(*ifv), M_DEVBUF, M_NOWAIT);
123 	if (!ifv)
124 		return (ENOMEM);
125 	bzero(ifv, sizeof(*ifv));
126 
127 	LIST_INIT(&ifv->vlan_mc_listhead);
128 	ifp = &ifv->ifv_if;
129 	ifp->if_softc = ifv;
130 	snprintf(ifp->if_xname, sizeof ifp->if_xname, "%s%d", ifc->ifc_name,
131 	    unit);
132 	/* NB: flags are not set here */
133 	/* NB: mtu is not set here */
134 
135 	ifp->if_start = vlan_start;
136 	ifp->if_ioctl = vlan_ioctl;
137 	ifp->if_output = ether_output;
138 	IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
139 	IFQ_SET_READY(&ifp->if_snd);
140 	if_attach(ifp);
141 	ether_ifattach(ifp);
142 
143 	/* Now undo some of the damage... */
144 	ifp->if_type = IFT_8021_VLAN;
145 	ifp->if_hdrlen = EVL_ENCAPLEN;
146 
147 	return (0);
148 }
149 
150 int
vlan_clone_destroy(struct ifnet * ifp)151 vlan_clone_destroy(struct ifnet *ifp)
152 {
153 	struct ifvlan *ifv = ifp->if_softc;
154 
155 	vlan_unconfig(ifp);
156 #if NBPFILTER > 0
157 	bpfdetach(ifp);
158 #endif
159 	ether_ifdetach(ifp);
160 	if_detach(ifp);
161 
162 	free(ifv, M_DEVBUF);
163 	return (0);
164 }
165 
166 void
vlan_start(struct ifnet * ifp)167 vlan_start(struct ifnet *ifp)
168 {
169 	struct ifvlan *ifv;
170 	struct ifnet *p;
171 	struct mbuf *m, *m0;
172 	int error;
173 
174 	ifv = ifp->if_softc;
175 	p = ifv->ifv_p;
176 
177 	ifp->if_flags |= IFF_OACTIVE;
178 	for (;;) {
179 		IFQ_DEQUEUE(&ifp->if_snd, m);
180 		if (m == NULL)
181 			break;
182 
183 		if ((p->if_flags & (IFF_UP|IFF_RUNNING)) !=
184 		    (IFF_UP|IFF_RUNNING)) {
185 			IF_DROP(&p->if_snd);
186 				/* XXX stats */
187 			ifp->if_oerrors++;
188 			m_freem(m);
189 			continue;
190 		}
191 
192 #if NBPFILTER > 0
193 		if (ifp->if_bpf)
194 			bpf_mtap(ifp->if_bpf, m);
195 #endif
196 
197 		/*
198 		 * If the IFCAP_VLAN_HWTAGGING capability is set on the parent,
199 		 * it can do VLAN tag insertion itself and doesn't require us
200 	 	 * to create a special header for it. In this case, we just pass
201 		 * the packet along. However, we need some way to tell the
202 		 * interface where the packet came from so that it knows how
203 		 * to find the VLAN tag to use, so we set the rcvif in the
204 		 * mbuf header to our ifnet.
205 		 *
206 		 * Note: we also set the M_PROTO1 flag in the mbuf to let
207 		 * the parent driver know that the rcvif pointer is really
208 		 * valid. We need to do this because sometimes mbufs will
209 		 * be allocated by other parts of the system that contain
210 		 * garbage in the rcvif pointer. Using the M_PROTO1 flag
211 		 * lets the driver perform a proper sanity check and avoid
212 		 * following potentially bogus rcvif pointers off into
213 		 * never-never land.
214 		 */
215 		if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) {
216 			m->m_pkthdr.rcvif = ifp;
217 			m->m_flags |= M_PROTO1;
218 		} else {
219 			struct ether_vlan_header evh;
220 
221 			m_copydata(m, 0, sizeof(struct ether_header),
222 			    (caddr_t)&evh);
223 			evh.evl_proto = evh.evl_encap_proto;
224 			evh.evl_encap_proto = htons(ETHERTYPE_8021Q);
225 			evh.evl_tag = htons(ifv->ifv_tag);
226 			m_adj(m, sizeof(struct ether_header));
227 
228 			m0 = m_prepend(m, sizeof(struct ether_vlan_header),
229 			    M_DONTWAIT);
230 			if (m0 == NULL) {
231 				ifp->if_ierrors++;
232 				continue;
233 			}
234 
235 			/* m_prepend() doesn't adjust m_pkthdr.len */
236 			if (m0->m_flags & M_PKTHDR)
237 				m0->m_pkthdr.len +=
238 				    sizeof(struct ether_vlan_header);
239 
240 			m_copyback(m0, 0, sizeof(struct ether_vlan_header),
241 			    &evh);
242 
243 			m = m0;
244 		}
245 
246 		/*
247 		 * Send it, precisely as ether_output() would have.
248 		 * We are already running at splimp.
249 		 */
250 		p->if_obytes += m->m_pkthdr.len;
251 		if (m->m_flags & M_MCAST)
252 			p->if_omcasts++;
253 		IFQ_ENQUEUE(&p->if_snd, m, NULL, error);
254 		if (error) {
255 			/* mbuf is already freed */
256 			ifp->if_oerrors++;
257 			continue;
258 		}
259 
260 		ifp->if_opackets++;
261 		if ((p->if_flags & IFF_OACTIVE) == 0)
262 			p->if_start(p);
263 	}
264 	ifp->if_flags &= ~IFF_OACTIVE;
265 
266 	return;
267 }
268 
269 int
vlan_input_tag(struct mbuf * m,u_int16_t t)270 vlan_input_tag(struct mbuf *m, u_int16_t t)
271 {
272 	struct ifvlan *ifv;
273 	struct ether_vlan_header vh;
274 
275 	t = EVL_VLANOFTAG(t);
276 	LIST_FOREACH(ifv, &vlan_tagh[TAG_HASH(t)], ifv_list) {
277 		if (m->m_pkthdr.rcvif == ifv->ifv_p && t == ifv->ifv_tag)
278 			break;
279 	}
280 
281 	if (ifv == NULL) {
282 		if (m->m_pkthdr.len < sizeof(struct ether_header)) {
283 			m_freem(m);
284 			return (-1);
285 		}
286 		m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&vh);
287 		vh.evl_proto = vh.evl_encap_proto;
288 		vh.evl_tag = htons(t);
289 		vh.evl_encap_proto = htons(ETHERTYPE_8021Q);
290 		m_adj(m, sizeof(struct ether_header));
291 		m = m_prepend(m, sizeof(struct ether_vlan_header), M_DONTWAIT);
292 		if (m == NULL)
293 			return (-1);
294 		m->m_pkthdr.len += sizeof(struct ether_vlan_header);
295 		if (m->m_len < sizeof(struct ether_vlan_header) &&
296 		    (m = m_pullup(m, sizeof(struct ether_vlan_header))) == NULL)
297 			return (-1);
298 		m_copyback(m, 0, sizeof(struct ether_vlan_header), &vh);
299 		ether_input_mbuf(m->m_pkthdr.rcvif, m);
300 		return (-1);
301 	}
302 
303 	if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
304 	    (IFF_UP|IFF_RUNNING)) {
305 		m_freem(m);
306 		return (-1);
307 	}
308 
309 	/*
310 	 * Having found a valid vlan interface corresponding to
311 	 * the given source interface and vlan tag, run the
312 	 * the real packet through ether_input().
313 	 */
314 	m->m_pkthdr.rcvif = &ifv->ifv_if;
315 
316 #if NBPFILTER > 0
317 	if (ifv->ifv_if.if_bpf) {
318 		/*
319 		 * Do the usual BPF fakery.  Note that we don't support
320 		 * promiscuous mode here, since it would require the
321 		 * drivers to know about VLANs and we're not ready for
322 		 * that yet.
323 		 */
324 		bpf_mtap(ifv->ifv_if.if_bpf, m);
325 	}
326 #endif
327 	ifv->ifv_if.if_ipackets++;
328 	ether_input_mbuf(&ifv->ifv_if, m);
329 	return 0;
330 }
331 
332 int
vlan_input(eh,m)333 vlan_input(eh, m)
334 	struct ether_header *eh;
335 	struct mbuf *m;
336 {
337 	struct ifvlan *ifv;
338 	u_int tag;
339 	struct ifnet *ifp = m->m_pkthdr.rcvif;
340 
341 	if (m->m_len < EVL_ENCAPLEN &&
342 	    (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
343 		ifp->if_ierrors++;
344 		return (0);
345 	}
346 
347 	tag = EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *)));
348 
349 	LIST_FOREACH(ifv, &vlan_tagh[TAG_HASH(tag)], ifv_list) {
350 		if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag)
351 			break;
352 	}
353 
354 	if (ifv == NULL || (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
355 	    (IFF_UP|IFF_RUNNING)) {
356 		m_freem(m);
357 		return -1;	/* so ether_input can take note */
358 	}
359 
360 	/*
361 	 * Having found a valid vlan interface corresponding to
362 	 * the given source interface and vlan tag, remove the
363 	 * encapsulation, and run the real packet through
364 	 * ether_input() a second time (it had better be
365 	 * reentrant!).
366 	 */
367 	m->m_pkthdr.rcvif = &ifv->ifv_if;
368 	eh->ether_type = mtod(m, u_int16_t *)[1];
369 	m->m_len -= EVL_ENCAPLEN;
370 	m->m_data += EVL_ENCAPLEN;
371 	m->m_pkthdr.len -= EVL_ENCAPLEN;
372 
373 #if NBPFILTER > 0
374 	if (ifv->ifv_if.if_bpf) {
375 		/*
376 		 * Do the usual BPF fakery.  Note that we don't support
377 		 * promiscuous mode here, since it would require the
378 		 * drivers to know about VLANs and we're not ready for
379 		 * that yet.
380 		 */
381 		struct mbuf m0;
382 
383 		m0.m_flags = 0;
384 		m0.m_next = m;
385 		m0.m_len = sizeof(struct ether_header);
386 		m0.m_data = (char *)eh;
387 		bpf_mtap(ifv->ifv_if.if_bpf, &m0);
388 	}
389 #endif
390 	ifv->ifv_if.if_ipackets++;
391 	ether_input(&ifv->ifv_if, eh, m);
392 
393 	return 0;
394 }
395 
396 int
vlan_config(struct ifvlan * ifv,struct ifnet * p,u_int16_t tag)397 vlan_config(struct ifvlan *ifv, struct ifnet *p, u_int16_t tag)
398 {
399 	struct ifaddr *ifa1, *ifa2;
400 	struct sockaddr_dl *sdl1, *sdl2;
401 	int s;
402 
403 	if (p->if_type != IFT_ETHER)
404 		return EPROTONOSUPPORT;
405 	if (ifv->ifv_p)
406 		return EBUSY;
407 	ifv->ifv_p = p;
408 
409 	if (p->if_capabilities & IFCAP_VLAN_MTU)
410 		ifv->ifv_if.if_mtu = p->if_mtu;
411 	else {
412 		/*
413 		 * This will be incompatible with strict
414 		 * 802.1Q implementations
415 		 */
416 		ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN;
417 #ifdef DIAGNOSTIC
418 		printf("%s: initialized with non-standard mtu %lu (parent %s)\n",
419 		    ifv->ifv_if.if_xname, ifv->ifv_if.if_mtu,
420 		    ifv->ifv_p->if_xname);
421 #endif
422 	}
423 
424 	ifv->ifv_if.if_flags = p->if_flags &
425 	    (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
426 
427 	/*
428 	 * Inherit the if_type from the parent.  This allows us to
429 	 * participate in bridges of that type.
430 	 */
431 	ifv->ifv_if.if_type = p->if_type;
432 
433 	/*
434 	 * Inherit baudrate from the parent.  An SNMP agent would use this
435 	 * information.
436 	 */
437 	ifv->ifv_if.if_baudrate = p->if_baudrate;
438 
439 	/*
440 	 * If the parent interface can do hardware-assisted
441 	 * VLAN encapsulation, then propagate its hardware-
442 	 * assisted checksumming flags.
443 	 *
444 	 * If the card cannot handle hardware tagging, it cannot
445 	 * possibly compute the correct checksums for tagged packets.
446 	 *
447 	 * This brings up another possibility, do cards exist which
448 	 * have all of these capabilities but cannot utilize them together?
449 	 */
450 	if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
451 		ifv->ifv_if.if_capabilities = p->if_capabilities &
452 		    (IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4|
453 		    IFCAP_CSUM_UDPv4);
454 		/* (IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6); */
455 
456 	/*
457 	 * Set up our ``Ethernet address'' to reflect the underlying
458 	 * physical interface's.
459 	 */
460 	ifa1 = ifnet_addrs[ifv->ifv_if.if_index];
461 	ifa2 = ifnet_addrs[p->if_index];
462 	sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
463 	sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
464 	sdl1->sdl_type = IFT_ETHER;
465 	sdl1->sdl_alen = ETHER_ADDR_LEN;
466 	bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
467 	bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
468 
469 	ifv->ifv_tag = tag;
470 	s = splnet();
471 	LIST_INSERT_HEAD(&vlan_tagh[TAG_HASH(tag)], ifv, ifv_list);
472 	splx(s);
473 
474 	return 0;
475 }
476 
477 int
vlan_unconfig(struct ifnet * ifp)478 vlan_unconfig(struct ifnet *ifp)
479 {
480 	struct ifaddr *ifa;
481 	struct sockaddr_dl *sdl;
482 	struct ifvlan *ifv;
483 	struct ifnet *p;
484 	struct ifreq *ifr, *ifr_p;
485 	int s;
486 
487 	ifv = ifp->if_softc;
488 	p = ifv->ifv_p;
489 	ifr = (struct ifreq *)&ifp->if_data;
490 	ifr_p = (struct ifreq *)&ifv->ifv_p->if_data;
491 
492 	if (p == NULL)
493 		return 0;
494 
495 	s = splnet();
496 	LIST_REMOVE(ifv, ifv_list);
497 	splx(s);
498 
499 	/*
500  	 * Since the interface is being unconfigured, we need to
501 	 * empty the list of multicast groups that we may have joined
502 	 * while we were alive and remove them from the parent's list
503 	 * as well.
504 	 */
505 	vlan_ether_purgemulti(ifv);
506 
507 	/* Disconnect from parent. */
508 	ifv->ifv_p = NULL;
509 	ifv->ifv_if.if_mtu = ETHERMTU;
510 
511 	/* Clear our MAC address. */
512 	ifa = ifnet_addrs[ifv->ifv_if.if_index];
513 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
514 	sdl->sdl_type = IFT_ETHER;
515 	sdl->sdl_alen = ETHER_ADDR_LEN;
516 	bzero(LLADDR(sdl), ETHER_ADDR_LEN);
517 	bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
518 
519 	return 0;
520 }
521 
522 int
vlan_set_promisc(struct ifnet * ifp)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
vlan_ioctl(struct ifnet * ifp,u_long cmd,caddr_t data)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 = splimp();
612 			vlan_unconfig(ifp);
613 			if_down(ifp);
614 			ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
615 			splx(s);
616 			break;
617 		}
618 		if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
619 			error = EINVAL;		 /* check for valid tag */
620 			break;
621 		}
622 		pr = ifunit(vlr.vlr_parent);
623 		if (pr == NULL) {
624 			error = ENOENT;
625 			break;
626 		}
627 		error = vlan_config(ifv, pr, vlr.vlr_tag);
628 		if (error)
629 			break;
630 		ifp->if_flags |= IFF_RUNNING;
631 
632 		/* Update promiscuous mode, if necessary. */
633 		vlan_set_promisc(ifp);
634 		break;
635 
636 	case SIOCGETVLAN:
637 		bzero(&vlr, sizeof vlr);
638 		if (ifv->ifv_p) {
639 			snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
640 			    "%s", ifv->ifv_p->if_xname);
641 			vlr.vlr_tag = ifv->ifv_tag;
642 		}
643 		error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
644 		break;
645 
646 	case SIOCSIFFLAGS:
647 		/*
648 		 * For promiscuous mode, we enable promiscuous mode on
649 		 * the parent if we need promiscuous on the VLAN interface.
650 		 */
651 		if (ifv->ifv_p != NULL)
652 			error = vlan_set_promisc(ifp);
653 		break;
654 	case SIOCADDMULTI:
655 		error = (ifv->ifv_p != NULL) ?
656 		    vlan_ether_addmulti(ifv, ifr) : EINVAL;
657 		break;
658 
659 	case SIOCDELMULTI:
660 		error = (ifv->ifv_p != NULL) ?
661 		    vlan_ether_delmulti(ifv, ifr) : EINVAL;
662 		break;
663 	default:
664 		error = EINVAL;
665 	}
666 	return error;
667 }
668 
669 
670 int
vlan_ether_addmulti(struct ifvlan * ifv,struct ifreq * ifr)671 vlan_ether_addmulti(struct ifvlan *ifv, struct ifreq *ifr)
672 {
673 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
674 	struct vlan_mc_entry *mc;
675 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
676 	int error;
677 
678 	/* XXX: sa_len is too small for such comparison
679 	if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr_storage))
680 		return (EINVAL);
681 	*/
682 
683 	error = ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
684 	if (error != ENETRESET)
685 		return (error);
686 
687 	/*
688 	 * This is new multicast address.  We have to tell parent
689 	 * about it.  Also, remember this multicast address so that
690 	 * we can delete them on unconfigure.
691 	 */
692 	MALLOC(mc, struct vlan_mc_entry *, sizeof(struct vlan_mc_entry),
693 	    M_DEVBUF, M_NOWAIT);
694 	if (mc == NULL) {
695 		error = ENOMEM;
696 		goto alloc_failed;
697 	}
698 
699 	/*
700 	 * As ether_addmulti() returns ENETRESET, following two
701 	 * statement shouldn't fail.
702 	 */
703 	(void)ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi);
704 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, mc->mc_enm);
705 	memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
706 	LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
707 
708 	error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr);
709 	if (error != 0)
710 		goto ioctl_failed;
711 
712 	return (error);
713 
714  ioctl_failed:
715 	LIST_REMOVE(mc, mc_entries);
716 	FREE(mc, M_DEVBUF);
717  alloc_failed:
718 	(void)ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
719 
720 	return (error);
721 }
722 
723 int
vlan_ether_delmulti(struct ifvlan * ifv,struct ifreq * ifr)724 vlan_ether_delmulti(struct ifvlan *ifv, struct ifreq *ifr)
725 {
726 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
727 	struct ether_multi *enm;
728 	struct vlan_mc_entry *mc;
729 	u_int8_t addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
730 	int error;
731 
732 	/*
733 	 * Find a key to lookup vlan_mc_entry.  We have to do this
734 	 * before calling ether_delmulti for obvious reason.
735 	 */
736 	if ((error = ether_multiaddr(&ifr->ifr_addr, addrlo, addrhi)) != 0)
737 		return (error);
738 	ETHER_LOOKUP_MULTI(addrlo, addrhi, &ifv->ifv_ac, enm);
739 
740 	error = ether_delmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
741 	if (error != ENETRESET)
742 		return (error);
743 
744 	/* We no longer use this multicast address.  Tell parent so. */
745 	error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
746 	if (error == 0) {
747 		/* And forget about this address. */
748 		for (mc = LIST_FIRST(&ifv->vlan_mc_listhead); mc != NULL;
749 		    mc = LIST_NEXT(mc, mc_entries)) {
750 			if (mc->mc_enm == enm) {
751 				LIST_REMOVE(mc, mc_entries);
752 				FREE(mc, M_DEVBUF);
753 				break;
754 			}
755 		}
756 		KASSERT(mc != NULL);
757 	} else
758 		(void)ether_addmulti(ifr, (struct arpcom *)&ifv->ifv_ac);
759 	return (error);
760 }
761 
762 /*
763  * Delete any multicast address we have asked to add from parent
764  * interface.  Called when the vlan is being unconfigured.
765  */
766 void
vlan_ether_purgemulti(struct ifvlan * ifv)767 vlan_ether_purgemulti(struct ifvlan *ifv)
768 {
769 	struct ifnet *ifp = ifv->ifv_p;		/* Parent. */
770 	struct vlan_mc_entry *mc;
771 	union {
772 		struct ifreq ifreq;
773 		struct {
774 			char ifr_name[IFNAMSIZ];
775 			struct sockaddr_storage ifr_ss;
776 		} ifreq_storage;
777 	} ifreq;
778 	struct ifreq *ifr = &ifreq.ifreq;
779 
780 	memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
781 	while ((mc = LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
782 		memcpy(&ifr->ifr_addr, &mc->mc_addr, mc->mc_addr.ss_len);
783 		(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
784 		LIST_REMOVE(mc, mc_entries);
785 		FREE(mc, M_DEVBUF);
786 	}
787 }
788