xref: /openbsd-src/sys/net/if_vlan.c (revision 3a3fbb3f2e2521ab7c4a56b7ff7462ebd9095ec5)
1 /*	$OpenBSD: if_vlan.c,v 1.29 2001/12/11 05:13:37 jason 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 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 
96 /*
97  * Program our multicast filter. What we're actually doing is
98  * programming the multicast filter of the parent. This has the
99  * side effect of causing the parent interface to receive multicast
100  * traffic that it doesn't really want, which ends up being discarded
101  * later by the upper protocol layers. Unfortunately, there's no way
102  * to avoid this: there really is only one physical interface.
103  */
104 
105 int vlan_setmulti(struct ifnet *ifp)
106 {
107 	struct ifreq		*ifr_p;
108 	struct ether_multi	*enm;
109 	struct ether_multistep	step;
110 	struct ifvlan		*sc;
111 	struct vlan_mc_entry	*mc = NULL;
112 	int			error;
113 
114 	/* Find the parent. */
115 	sc = ifp->if_softc;
116 	ifr_p = (struct ifreq *)&sc->ifv_p->if_data;
117 
118 	/* First, remove any existing filter entries. */
119 	while (!SLIST_EMPTY(&sc->vlan_mc_listhead)) {
120 		mc = SLIST_FIRST(&sc->vlan_mc_listhead);
121 		error = ether_delmulti(ifr_p, &sc->ifv_ac);
122 		if (error)
123 			return(error);
124 		SLIST_REMOVE_HEAD(&sc->vlan_mc_listhead, mc_entries);
125 		free(mc, M_DEVBUF);
126 	}
127 
128 	/* Now program new ones. */
129 	ETHER_FIRST_MULTI(step, &sc->ifv_ac, enm);
130 	while (enm != NULL) {
131 		mc = malloc(sizeof(struct vlan_mc_entry), M_DEVBUF, M_NOWAIT);
132 		bcopy(enm->enm_addrlo,
133 		    (void *) &mc->mc_addr, ETHER_ADDR_LEN);
134 		SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
135 		error = ether_addmulti(ifr_p, &sc->ifv_ac);
136 		if (error)
137 			return(error);
138 		ETHER_NEXT_MULTI(step, enm);
139 	}
140 
141 	return(0);
142 }
143 
144 void
145 vlanattach(int count)
146 {
147 	struct ifnet *ifp;
148 	int i;
149 
150 	MALLOC(ifv_softc, struct ifvlan *, count * sizeof(struct ifvlan),
151 	    M_DEVBUF, M_NOWAIT);
152 	if (ifv_softc == NULL)
153 		panic("vlanattach: MALLOC failed");
154 	nifvlan = count;
155 	bzero(ifv_softc, nifvlan * sizeof(struct ifvlan));
156 
157 	for (i = 0; i < nifvlan; i++) {
158 		ifp = &ifv_softc[i].ifv_if;
159 		ifp->if_softc = &ifv_softc[i];
160 		sprintf(ifp->if_xname, "vlan%d", i);
161 		/* NB: flags are not set here */
162 		/* NB: mtu is not set here */
163 
164 		ifp->if_start = vlan_start;
165 		ifp->if_ioctl = vlan_ioctl;
166 		ifp->if_output = ether_output;
167 		IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
168 		IFQ_SET_READY(&ifp->if_snd);
169 		if_attach(ifp);
170 		ether_ifattach(ifp);
171 
172 		/* Now undo some of the damage... */
173 		ifp->if_type = IFT_8021_VLAN;
174 		ifp->if_hdrlen = EVL_ENCAPLEN;
175 	}
176 }
177 
178 void
179 vlan_start(struct ifnet *ifp)
180 {
181 	struct ifvlan *ifv;
182 	struct ifnet *p;
183 	struct ether_vlan_header *evl;
184 	struct mbuf *m, *m0;
185 	int error;
186 	ALTQ_DECL(struct altq_pktattr pktattr;)
187 
188 	ifv = ifp->if_softc;
189 	p = ifv->ifv_p;
190 
191 	ifp->if_flags |= IFF_OACTIVE;
192 	for (;;) {
193 		IFQ_DEQUEUE(&ifp->if_snd, m);
194 		if (m == NULL)
195 			break;
196 
197 		if ((p->if_flags & (IFF_UP|IFF_RUNNING)) !=
198 		    (IFF_UP|IFF_RUNNING)) {
199 			IF_DROP(&p->if_snd);
200 				/* XXX stats */
201 			ifp->if_oerrors++;
202 			m_freem(m);
203 			continue;
204 		}
205 
206 #ifdef ALTQ
207 		/*
208 		 * If ALTQ is enabled on the parent interface, do
209 		 * classification; the queueing discipline might
210 		 * not require classification, but might require
211 		 * the address family/header pointer in the pktattr.
212 		 */
213 		if (ALTQ_IS_ENABLED(&p->if_snd)) {
214 			switch (p->if_type) {
215 			case IFT_ETHER:
216 				altq_etherclassify(&p->if_snd, m, &pktattr);
217 				break;
218 #ifdef DIAGNOSTIC
219 			default:
220 				panic("vlan_start: impossible (altq)");
221 #endif
222 			}
223 		}
224 #endif /* ALTQ */
225 
226 #if NBPFILTER > 0
227 		if (ifp->if_bpf)
228 			bpf_mtap(ifp->if_bpf, m);
229 #endif
230 
231 		/*
232 		 * If the IFCAP_VLAN_HWTAGGING capability is set on the parent,
233 		 * it can do VLAN tag insertion itself and doesn't require us
234 	 	 * to create a special header for it. In this case, we just pass
235 		 * the packet along. However, we need some way to tell the
236 		 * interface where the packet came from so that it knows how
237 		 * to find the VLAN tag to use, so we set the rcvif in the
238 		 * mbuf header to our ifnet.
239 		 *
240 		 * Note: we also set the M_PROTO1 flag in the mbuf to let
241 		 * the parent driver know that the rcvif pointer is really
242 		 * valid. We need to do this because sometimes mbufs will
243 		 * be allocated by other parts of the system that contain
244 		 * garbage in the rcvif pointer. Using the M_PROTO1 flag
245 		 * lets the driver perform a proper sanity check and avoid
246 		 * following potentially bogus rcvif pointers off into
247 		 * never-never land.
248 		 */
249 		if (p->if_capabilities & IFCAP_VLAN_HWTAGGING) {
250 			m->m_pkthdr.rcvif = ifp;
251 			m->m_flags |= M_PROTO1;
252 		} else {
253 			if (m->m_len < sizeof(struct ether_header) &&
254 			    (m = m_pullup(m, sizeof(struct ether_header)))
255 			    == NULL) {
256 				ifp->if_ierrors++;
257 				continue;
258 			}
259 
260 			if (m->m_flags & M_PKTHDR) {
261 				MGETHDR(m0, MT_DATA, M_DONTWAIT);
262 			} else {
263 				MGET(m0, MT_DATA, M_DONTWAIT);
264 			}
265 
266 			if (m0 == NULL) {
267 				ifp->if_ierrors++;
268 				m_freem(m);
269 				continue;
270 			}
271 
272 			if (m0->m_flags & M_PKTHDR)
273 				M_MOVE_PKTHDR(m0, m);
274 
275 			m0->m_flags &= ~M_PROTO1;
276 			m0->m_next = m;
277 			m0->m_len = sizeof(struct ether_vlan_header);
278 
279 			evl = mtod(m0, struct ether_vlan_header *);
280 			bcopy(mtod(m, char *),
281 			    evl, sizeof(struct ether_header));
282 			evl->evl_proto = evl->evl_encap_proto;
283 			evl->evl_encap_proto = htons(ETHERTYPE_8021Q);
284 			evl->evl_tag = htons(ifv->ifv_tag);
285 
286 			m->m_len -= sizeof(struct ether_header);
287 			m->m_data += sizeof(struct ether_header);
288 
289 			m = m0;
290 		}
291 
292 		/*
293 		 * Send it, precisely as ether_output() would have.
294 		 * We are already running at splimp.
295 		 */
296 		p->if_obytes += m->m_pkthdr.len;
297 		if (m->m_flags & M_MCAST)
298 			p->if_omcasts++;
299 		IFQ_ENQUEUE(&p->if_snd, m, &pktattr, error);
300 		if (error) {
301 			/* mbuf is already freed */
302 			ifp->if_oerrors++;
303 			continue;
304 		}
305 
306 		ifp->if_opackets++;
307 		if ((p->if_flags & IFF_OACTIVE) == 0)
308 			p->if_start(p);
309 	}
310 	ifp->if_flags &= ~IFF_OACTIVE;
311 
312 	return;
313 }
314 
315 int
316 vlan_input_tag(struct mbuf *m, u_int16_t t)
317 {
318 	int i;
319 	struct ifvlan *ifv;
320 	struct ether_vlan_header vh;
321 
322 	for (i = 0; i < nifvlan; i++) {
323 		ifv = &ifv_softc[i];
324 		if (m->m_pkthdr.rcvif == ifv->ifv_p && t == ifv->ifv_tag)
325 			break;
326 	}
327 
328 	if (i >= nifvlan) {
329 		if (m->m_pkthdr.len < sizeof(struct ether_header))
330 			return (-1);
331 		m_copydata(m, 0, sizeof(struct ether_header), (caddr_t)&vh);
332 		vh.evl_proto = vh.evl_encap_proto;
333 		vh.evl_tag = htons(t);
334 		vh.evl_encap_proto = htons(ETHERTYPE_8021Q);
335 		M_PREPEND(m, EVL_ENCAPLEN, M_DONTWAIT);
336 		if (m == NULL)
337 			return (-1);
338 		m_copyback(m, 0, sizeof(struct ether_vlan_header), (caddr_t)&vh);
339 		ether_input_mbuf(m->m_pkthdr.rcvif, m);
340 		return (-1);
341 	}
342 
343 	if ((ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
344 	    (IFF_UP|IFF_RUNNING)) {
345 		m_freem(m);
346 		return (-1);
347 	}
348 
349 	/*
350 	 * Having found a valid vlan interface corresponding to
351 	 * the given source interface and vlan tag, run the
352 	 * the real packet through ether_input().
353 	 */
354 	m->m_pkthdr.rcvif = &ifv->ifv_if;
355 
356 #if NBPFILTER > 0
357 	if (ifv->ifv_if.if_bpf) {
358 		/*
359 		 * Do the usual BPF fakery.  Note that we don't support
360 		 * promiscuous mode here, since it would require the
361 		 * drivers to know about VLANs and we're not ready for
362 		 * that yet.
363 		 */
364 		bpf_mtap(ifv->ifv_if.if_bpf, m);
365 	}
366 #endif
367 	ifv->ifv_if.if_ipackets++;
368 	ether_input_mbuf(&ifv->ifv_if, m);
369 	return 0;
370 }
371 
372 int
373 vlan_input(eh, m)
374 	struct ether_header *eh;
375 	struct mbuf *m;
376 {
377 	int i;
378 	struct ifvlan *ifv;
379 	u_int tag;
380 
381 	if (m->m_len < EVL_ENCAPLEN &&
382 	    (m = m_pullup(m, EVL_ENCAPLEN)) == NULL) {
383 		m->m_pkthdr.rcvif->if_ierrors++;
384 		return (0);
385 	}
386 
387 	tag = EVL_VLANOFTAG(ntohs(*mtod(m, u_int16_t *)));
388 
389 	for (i = 0; i < nifvlan; i++) {
390 		ifv = &ifv_softc[i];
391 		if (m->m_pkthdr.rcvif == ifv->ifv_p && tag == ifv->ifv_tag)
392 			break;
393 	}
394 
395 	if (i >= nifvlan || (ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
396 	    (IFF_UP|IFF_RUNNING)) {
397 		m_freem(m);
398 		return -1;	/* so ether_input can take note */
399 	}
400 
401 	/*
402 	 * Having found a valid vlan interface corresponding to
403 	 * the given source interface and vlan tag, remove the
404 	 * encapsulation, and run the real packet through
405 	 * ether_input() a second time (it had better be
406 	 * reentrant!).
407 	 */
408 	m->m_pkthdr.rcvif = &ifv->ifv_if;
409 	eh->ether_type = mtod(m, u_int16_t *)[1];
410 	m->m_len -= EVL_ENCAPLEN;
411 	m->m_data += EVL_ENCAPLEN;
412 	m->m_pkthdr.len -= EVL_ENCAPLEN;
413 
414 #if NBPFILTER > 0
415 	if (ifv->ifv_if.if_bpf) {
416 		/*
417 		 * Do the usual BPF fakery.  Note that we don't support
418 		 * promiscuous mode here, since it would require the
419 		 * drivers to know about VLANs and we're not ready for
420 		 * that yet.
421 		 */
422 		struct mbuf m0;
423 		m0.m_next = m;
424 		m0.m_len = sizeof(struct ether_header);
425 		m0.m_data = (char *)eh;
426 		bpf_mtap(ifv->ifv_if.if_bpf, &m0);
427 	}
428 #endif
429 	ifv->ifv_if.if_ipackets++;
430 	ether_input(&ifv->ifv_if, eh, m);
431 
432 	return 0;
433 }
434 
435 int
436 vlan_config(struct ifvlan *ifv, struct ifnet *p)
437 {
438 	struct ifaddr *ifa1, *ifa2;
439 	struct sockaddr_dl *sdl1, *sdl2;
440 
441 	if (p->if_type != IFT_ETHER)
442 		return EPROTONOSUPPORT;
443 	if (ifv->ifv_p)
444 		return EBUSY;
445 	ifv->ifv_p = p;
446 
447 	if (p->if_capabilities & IFCAP_VLAN_MTU)
448 		ifv->ifv_if.if_mtu = p->if_mtu;
449 	else {
450 		/*
451 		 * This will be incompatible with strict
452 		 * 802.1Q implementations
453 		 */
454 		ifv->ifv_if.if_mtu = p->if_mtu - EVL_ENCAPLEN;
455 #ifdef DIAGNOSTIC
456 		printf("%s: initialized with non-standard mtu %d (parent %s)\n",
457 		    ifv->ifv_if.if_xname, ifv->ifv_if.if_mtu,
458 		    ifv->ifv_p->if_xname);
459 #endif
460 	}
461 
462 	ifv->ifv_if.if_flags = p->if_flags &
463 	    (IFF_UP | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
464 
465 	/*
466 	 * Inherit the if_type from the parent.  This allows us to
467 	 * participate in bridges of that type.
468 	 */
469 	ifv->ifv_if.if_type = p->if_type;
470 
471 	/*
472 	 * Inherit baudrate from the parent.  An SNMP agent would use this
473 	 * information.
474 	 */
475 	ifv->ifv_if.if_baudrate = p->if_baudrate;
476 
477 	/*
478 	 * If the parent interface can do hardware-assisted
479 	 * VLAN encapsulation, then propagate its hardware-
480 	 * assisted checksumming flags.
481 	 *
482 	 * If the card cannot handle hardware tagging, it cannot
483 	 * possibly compute the correct checksums for tagged packets.
484 	 *
485 	 * This brings up another possibility, do cards exist which
486 	 * have all of these capabilities but cannot utilize them together?
487 	 */
488 	if (p->if_capabilities & IFCAP_VLAN_HWTAGGING)
489 		ifv->ifv_if.if_capabilities = p->if_capabilities &
490 		    (IFCAP_CSUM_IPv4|IFCAP_CSUM_TCPv4|
491 		    IFCAP_CSUM_UDPv4);
492 		/* (IFCAP_CSUM_TCPv6|IFCAP_CSUM_UDPv6); */
493 
494 	/*
495 	 * Set up our ``Ethernet address'' to reflect the underlying
496 	 * physical interface's.
497 	 */
498 	ifa1 = ifnet_addrs[ifv->ifv_if.if_index];
499 	ifa2 = ifnet_addrs[p->if_index];
500 	sdl1 = (struct sockaddr_dl *)ifa1->ifa_addr;
501 	sdl2 = (struct sockaddr_dl *)ifa2->ifa_addr;
502 	sdl1->sdl_type = IFT_ETHER;
503 	sdl1->sdl_alen = ETHER_ADDR_LEN;
504 	bcopy(LLADDR(sdl2), LLADDR(sdl1), ETHER_ADDR_LEN);
505 	bcopy(LLADDR(sdl2), ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
506 	return 0;
507 }
508 
509 int
510 vlan_unconfig(struct ifnet *ifp)
511 {
512 	struct ifaddr *ifa;
513 	struct sockaddr_dl *sdl;
514 	struct ifvlan *ifv;
515 	struct ifnet *p;
516 	struct ifreq *ifr, *ifr_p;
517 	struct vlan_mc_entry *mc;
518 	int error;
519 
520 	ifv = ifp->if_softc;
521 	p = ifv->ifv_p;
522 	ifr = (struct ifreq *)&ifp->if_data;
523 	ifr_p = (struct ifreq *)&ifv->ifv_p->if_data;
524 
525 	/*
526  	 * Since the interface is being unconfigured, we need to
527 	 * empty the list of multicast groups that we may have joined
528 	 * while we were alive and remove them from the parent's list
529 	 * as well.
530 	 */
531 	while (!SLIST_EMPTY(&ifv->vlan_mc_listhead)) {
532 		mc = SLIST_FIRST(&ifv->vlan_mc_listhead);
533 		error = ether_delmulti(ifr_p, &ifv->ifv_ac);
534 		error = ether_delmulti(ifr, &ifv->ifv_ac);
535 		if (error)
536 			return(error);
537 		SLIST_REMOVE_HEAD(&ifv->vlan_mc_listhead, mc_entries);
538 		free(mc, M_DEVBUF);
539 	}
540 
541 	/* Disconnect from parent. */
542 	ifv->ifv_p = NULL;
543 	ifv->ifv_if.if_mtu = ETHERMTU;
544 
545 	/* Clear our MAC address. */
546 	ifa = ifnet_addrs[ifv->ifv_if.if_index];
547 	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
548 	sdl->sdl_type = IFT_ETHER;
549 	sdl->sdl_alen = ETHER_ADDR_LEN;
550 	bzero(LLADDR(sdl), ETHER_ADDR_LEN);
551 	bzero(ifv->ifv_ac.ac_enaddr, ETHER_ADDR_LEN);
552 
553 	return 0;
554 }
555 
556 int
557 vlan_set_promisc(struct ifnet *ifp)
558 {
559 	struct ifvlan *ifv = ifp->if_softc;
560 	int error = 0;
561 
562 	if ((ifp->if_flags & IFF_PROMISC) != 0) {
563 		if ((ifv->ifv_flags & IFVF_PROMISC) == 0) {
564 			error = ifpromisc(ifv->ifv_p, 1);
565 			if (error == 0)
566 				ifv->ifv_flags |= IFVF_PROMISC;
567 		}
568 	} else {
569 		if ((ifv->ifv_flags & IFVF_PROMISC) != 0) {
570 			error = ifpromisc(ifv->ifv_p, 0);
571 			if (error == 0)
572 				ifv->ifv_flags &= ~IFVF_PROMISC;
573 		}
574 	}
575 
576 	return (0);
577 }
578 
579 int
580 vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
581 {
582 	struct proc *p = curproc;	/* XXX */
583 	struct ifaddr *ifa;
584 	struct ifnet *pr;
585 	struct ifreq *ifr;
586 	struct ifvlan *ifv;
587 	struct vlanreq vlr;
588 	int error = 0, p_mtu = 0;
589 
590 	ifr = (struct ifreq *)data;
591 	ifa = (struct ifaddr *)data;
592 	ifv = ifp->if_softc;
593 
594 	switch (cmd) {
595 	case SIOCSIFADDR:
596 		if (ifv->ifv_p != NULL) {
597 			ifp->if_flags |= IFF_UP;
598 
599 			switch (ifa->ifa_addr->sa_family) {
600 #ifdef INET
601 			case AF_INET:
602 				arp_ifinit(&ifv->ifv_ac, ifa);
603 				break;
604 #endif
605 			default:
606 				break;
607 			}
608 		} else {
609 			error = EINVAL;
610 		}
611 		break;
612 
613 	case SIOCGIFADDR:
614 		{
615 			struct sockaddr *sa;
616 
617 			sa = (struct sockaddr *) &ifr->ifr_data;
618 			bcopy(((struct arpcom *)ifp->if_softc)->ac_enaddr,
619 			    (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
620 		}
621 		break;
622 
623 	case SIOCSIFMTU:
624 		if (ifv->ifv_p != NULL) {
625 			if (ifv->ifv_p->if_capabilities & IFCAP_VLAN_MTU)
626 				p_mtu = ifv->ifv_p->if_mtu;
627 			else
628 				p_mtu = ifv->ifv_p->if_mtu - EVL_ENCAPLEN;
629 
630 			if (ifr->ifr_mtu > p_mtu || ifr->ifr_mtu < ETHERMIN)
631 				error = EINVAL;
632 			else
633 				ifp->if_mtu = ifr->ifr_mtu;
634 		} else
635 			error = EINVAL;
636 
637 		break;
638 
639 	case SIOCSETVLAN:
640 		if ((error = suser(p->p_ucred, &p->p_acflag)) != 0)
641 			break;
642 		if ((error = copyin(ifr->ifr_data, &vlr, sizeof vlr)))
643 			break;
644 		if (vlr.vlr_parent[0] == '\0') {
645 			vlan_unconfig(ifp);
646 			if_down(ifp);
647 			ifp->if_flags &= ~(IFF_UP|IFF_RUNNING);
648 			break;
649 		}
650 		if (vlr.vlr_tag != EVL_VLANOFTAG(vlr.vlr_tag)) {
651 			error = EINVAL;		 /* check for valid tag */
652 			break;
653 		}
654 		pr = ifunit(vlr.vlr_parent);
655 		if (pr == NULL) {
656 			error = ENOENT;
657 			break;
658 		}
659 		error = vlan_config(ifv, pr);
660 		if (error)
661 			break;
662 		ifv->ifv_tag = vlr.vlr_tag;
663 		ifp->if_flags |= IFF_RUNNING;
664 
665 		/* Update promiscuous mode, if necessary. */
666 		vlan_set_promisc(ifp);
667 		break;
668 
669 	case SIOCGETVLAN:
670 		bzero(&vlr, sizeof vlr);
671 		if (ifv->ifv_p) {
672 			snprintf(vlr.vlr_parent, sizeof(vlr.vlr_parent),
673 			    "%s", ifv->ifv_p->if_xname);
674 			vlr.vlr_tag = ifv->ifv_tag;
675 		}
676 		error = copyout(&vlr, ifr->ifr_data, sizeof vlr);
677 		break;
678 
679 	case SIOCSIFFLAGS:
680 		/*
681 		 * For promiscuous mode, we enable promiscuous mode on
682 		 * the parent if we need promiscuous on the VLAN interface.
683 		 */
684 		if (ifv->ifv_p != NULL)
685 			error = vlan_set_promisc(ifp);
686 		break;
687 	case SIOCADDMULTI:
688 	case SIOCDELMULTI:
689 		if (ifv->ifv_p != NULL) {
690 			error = vlan_setmulti(ifp);
691 		} else {
692 			error = EINVAL;
693 		}
694 		break;
695 	default:
696 		error = EINVAL;
697 	}
698 	return error;
699 }
700