1 /* $NetBSD: if_vlan.c,v 1.62 2008/12/17 20:51:37 cegger Exp $ */
4 * Copyright (c) 2000, 2001 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran, and by Jason R. Thorpe of Zembu Labs, Inc.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright 1998 Massachusetts Institute of Technology
35 * Permission to use, copy, modify, and distribute this software and
36 * its documentation for any purpose and without fee is hereby
37 * granted, provided that both the above copyright notice and this
38 * permission notice appear in all copies, that both the above
39 * copyright notice and this permission notice appear in all
40 * supporting documentation, and that the name of M.I.T. not be used
41 * in advertising or publicity pertaining to distribution of the
42 * software without specific, written prior permission. M.I.T. makes
43 * no representations about the suitability of this software for any
44 * purpose. It is provided "as is" without express or implied
47 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS
48 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE,
49 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
50 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT
51 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
52 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
53 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
54 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
55 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
56 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
57 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
60 * from FreeBSD: if_vlan.c,v 1.16 2000/03/26 15:21:40 charnier Exp
61 * via OpenBSD: if_vlan.c,v 1.4 2000/05/15 19:15:00 chris Exp
65 * if_vlan.c - pseudo-device driver for IEEE 802.1Q virtual LANs. Might be
66 * extended some day to also handle IEEE 802.1P priority tagging. This is
67 * sort of sneaky in the implementation, since we need to pretend to be
68 * enough of an Ethernet implementation to make ARP work. The way we do
69 * this is by telling everyone that we are an Ethernet interface, and then
70 * catch the packets that ether_output() left on our output queue when it
71 * calls if_start(), rewrite them for use by the real outgoing interface,
72 * and ask it to send them.
76 * - Need some way to notify vlan interfaces when the parent
77 * interface changes MTU.
80 #include <sys/cdefs.h>
81 __KERNEL_RCSID(0, "$NetBSD: if_vlan.c,v 1.62 2008/12/17 20:51:37 cegger Exp $");
86 #include <sys/param.h>
87 #include <sys/kernel.h>
89 #include <sys/queue.h>
90 #include <sys/socket.h>
91 #include <sys/sockio.h>
92 #include <sys/systm.h>
94 #include <sys/kauth.h>
100 #include <net/if_dl.h>
101 #include <net/if_types.h>
102 #include <net/if_ether.h>
103 #include <net/if_vlanvar.h>
106 #include <netinet/in.h>
107 #include <netinet/if_inarp.h>
110 struct vlan_mc_entry
{
111 LIST_ENTRY(vlan_mc_entry
) mc_entries
;
113 * A key to identify this entry. The mc_addr below can't be
114 * used since multiple sockaddr may mapped into the same
115 * ether_multi (e.g., AF_UNSPEC).
118 struct ether_multi
*mcu_enm
;
120 struct sockaddr_storage mc_addr
;
123 #define mc_enm mc_u.mcu_enm
127 struct ethercom ifvu_ec
;
129 struct ifnet
*ifv_p
; /* parent interface of this vlan */
131 const struct vlan_multisw
*ifvm_msw
;
132 int ifvm_encaplen
; /* encapsulation length */
133 int ifvm_mtufudge
; /* MTU fudged by this much */
134 int ifvm_mintu
; /* min transmission unit */
135 uint16_t ifvm_proto
; /* encapsulation ethertype */
136 uint16_t ifvm_tag
; /* tag to apply on packets */
138 LIST_HEAD(__vlan_mchead
, vlan_mc_entry
) ifv_mc_listhead
;
139 LIST_ENTRY(ifvlan
) ifv_list
;
143 #define IFVF_PROMISC 0x01 /* promiscuous mode enabled */
145 #define ifv_ec ifv_u.ifvu_ec
147 #define ifv_if ifv_ec.ec_if
149 #define ifv_msw ifv_mib.ifvm_msw
150 #define ifv_encaplen ifv_mib.ifvm_encaplen
151 #define ifv_mtufudge ifv_mib.ifvm_mtufudge
152 #define ifv_mintu ifv_mib.ifvm_mintu
153 #define ifv_tag ifv_mib.ifvm_tag
155 struct vlan_multisw
{
156 int (*vmsw_addmulti
)(struct ifvlan
*, struct ifreq
*);
157 int (*vmsw_delmulti
)(struct ifvlan
*, struct ifreq
*);
158 void (*vmsw_purgemulti
)(struct ifvlan
*);
161 static int vlan_ether_addmulti(struct ifvlan
*, struct ifreq
*);
162 static int vlan_ether_delmulti(struct ifvlan
*, struct ifreq
*);
163 static void vlan_ether_purgemulti(struct ifvlan
*);
165 const struct vlan_multisw vlan_ether_multisw
= {
168 vlan_ether_purgemulti
,
171 static int vlan_clone_create(struct if_clone
*, int);
172 static int vlan_clone_destroy(struct ifnet
*);
173 static int vlan_config(struct ifvlan
*, struct ifnet
*);
174 static int vlan_ioctl(struct ifnet
*, u_long
, void *);
175 static void vlan_start(struct ifnet
*);
176 static void vlan_unconfig(struct ifnet
*);
178 void vlanattach(int);
180 /* XXX This should be a hash table with the tag as the basis of the key. */
181 static LIST_HEAD(, ifvlan
) ifv_list
;
183 struct if_clone vlan_cloner
=
184 IF_CLONE_INITIALIZER("vlan", vlan_clone_create
, vlan_clone_destroy
);
186 /* Used to pad ethernet frames with < ETHER_MIN_LEN bytes */
187 static char vlan_zero_pad_buff
[ETHER_MIN_LEN
];
193 LIST_INIT(&ifv_list
);
194 if_clone_attach(&vlan_cloner
);
198 vlan_reset_linkname(struct ifnet
*ifp
)
202 * We start out with a "802.1Q VLAN" type and zero-length
203 * addresses. When we attach to a parent interface, we
204 * inherit its type, address length, address, and data link
208 ifp
->if_type
= IFT_L2VLAN
;
210 ifp
->if_dlt
= DLT_NULL
;
215 vlan_clone_create(struct if_clone
*ifc
, int unit
)
221 ifv
= malloc(sizeof(struct ifvlan
), M_DEVBUF
, M_WAITOK
|M_ZERO
);
223 LIST_INIT(&ifv
->ifv_mc_listhead
);
226 LIST_INSERT_HEAD(&ifv_list
, ifv
, ifv_list
);
229 if_initname(ifp
, ifc
->ifc_name
, unit
);
231 ifp
->if_flags
= IFF_BROADCAST
| IFF_SIMPLEX
| IFF_MULTICAST
;
232 ifp
->if_start
= vlan_start
;
233 ifp
->if_ioctl
= vlan_ioctl
;
234 IFQ_SET_READY(&ifp
->if_snd
);
237 vlan_reset_linkname(ifp
);
243 vlan_clone_destroy(struct ifnet
*ifp
)
245 struct ifvlan
*ifv
= ifp
->if_softc
;
249 LIST_REMOVE(ifv
, ifv_list
);
260 * Configure a VLAN interface. Must be called at splnet().
263 vlan_config(struct ifvlan
*ifv
, struct ifnet
*p
)
265 struct ifnet
*ifp
= &ifv
->ifv_if
;
268 if (ifv
->ifv_p
!= NULL
)
271 switch (p
->if_type
) {
274 struct ethercom
*ec
= (void *) p
;
276 ifv
->ifv_msw
= &vlan_ether_multisw
;
277 ifv
->ifv_encaplen
= ETHER_VLAN_ENCAP_LEN
;
278 ifv
->ifv_mintu
= ETHERMIN
;
281 * If the parent supports the VLAN_MTU capability,
282 * i.e. can Tx/Rx larger than ETHER_MAX_LEN frames,
285 if (ec
->ec_nvlans
++ == 0 &&
286 (ec
->ec_capabilities
& ETHERCAP_VLAN_MTU
) != 0) {
288 * Enable Tx/Rx of VLAN-sized frames.
290 ec
->ec_capenable
|= ETHERCAP_VLAN_MTU
;
291 if (p
->if_flags
& IFF_UP
) {
294 ifr
.ifr_flags
= p
->if_flags
;
295 error
= (*p
->if_ioctl
)(p
, SIOCSIFFLAGS
,
298 if (ec
->ec_nvlans
-- == 1)
304 ifv
->ifv_mtufudge
= 0;
305 } else if ((ec
->ec_capabilities
& ETHERCAP_VLAN_MTU
) == 0) {
307 * Fudge the MTU by the encapsulation size. This
308 * makes us incompatible with strictly compliant
309 * 802.1Q implementations, but allows us to use
310 * the feature with other NetBSD implementations,
311 * which might still be useful.
313 ifv
->ifv_mtufudge
= ifv
->ifv_encaplen
;
317 * If the parent interface can do hardware-assisted
318 * VLAN encapsulation, then propagate its hardware-
319 * assisted checksumming flags and tcp segmentation
322 if (ec
->ec_capabilities
& ETHERCAP_VLAN_HWTAGGING
)
323 ifp
->if_capabilities
= p
->if_capabilities
&
325 IFCAP_CSUM_IPv4_Tx
|IFCAP_CSUM_IPv4_Rx
|
326 IFCAP_CSUM_TCPv4_Tx
|IFCAP_CSUM_TCPv4_Rx
|
327 IFCAP_CSUM_UDPv4_Tx
|IFCAP_CSUM_UDPv4_Rx
|
328 IFCAP_CSUM_TCPv6_Tx
|IFCAP_CSUM_TCPv6_Rx
|
329 IFCAP_CSUM_UDPv6_Tx
|IFCAP_CSUM_UDPv6_Rx
);
332 * We inherit the parent's Ethernet address.
334 ether_ifattach(ifp
, CLLADDR(p
->if_sadl
));
335 ifp
->if_hdrlen
= sizeof(struct ether_vlan_header
); /* XXX? */
340 return (EPROTONOSUPPORT
);
344 ifv
->ifv_if
.if_mtu
= p
->if_mtu
- ifv
->ifv_mtufudge
;
345 ifv
->ifv_if
.if_flags
= p
->if_flags
&
346 (IFF_UP
| IFF_BROADCAST
| IFF_SIMPLEX
| IFF_MULTICAST
);
349 * Inherit the if_type from the parent. This allows us
350 * to participate in bridges of that type.
352 ifv
->ifv_if
.if_type
= p
->if_type
;
358 * Unconfigure a VLAN interface. Must be called at splnet().
361 vlan_unconfig(struct ifnet
*ifp
)
363 struct ifvlan
*ifv
= ifp
->if_softc
;
365 if (ifv
->ifv_p
== NULL
)
369 * Since the interface is being unconfigured, we need to empty the
370 * list of multicast groups that we may have joined while we were
371 * alive and remove them from the parent's list also.
373 (*ifv
->ifv_msw
->vmsw_purgemulti
)(ifv
);
375 /* Disconnect from parent. */
376 switch (ifv
->ifv_p
->if_type
) {
379 struct ethercom
*ec
= (void *) ifv
->ifv_p
;
381 if (ec
->ec_nvlans
-- == 1) {
383 * Disable Tx/Rx of VLAN-sized frames.
385 ec
->ec_capenable
&= ~ETHERCAP_VLAN_MTU
;
386 if (ifv
->ifv_p
->if_flags
& IFF_UP
) {
389 ifr
.ifr_flags
= ifv
->ifv_p
->if_flags
;
390 (void) (*ifv
->ifv_p
->if_ioctl
)(ifv
->ifv_p
,
391 SIOCSIFFLAGS
, (void *) &ifr
);
396 vlan_reset_linkname(ifp
);
402 panic("vlan_unconfig: impossible");
407 ifv
->ifv_if
.if_mtu
= 0;
411 ifp
->if_flags
&= ~(IFF_UP
|IFF_RUNNING
);
412 ifp
->if_capabilities
= 0;
416 * Called when a parent interface is detaching; destroy any VLAN
417 * configuration for the parent interface.
420 vlan_ifdetach(struct ifnet
*p
)
427 for (ifv
= LIST_FIRST(&ifv_list
); ifv
!= NULL
;
428 ifv
= LIST_NEXT(ifv
, ifv_list
)) {
430 vlan_unconfig(&ifv
->ifv_if
);
437 vlan_set_promisc(struct ifnet
*ifp
)
439 struct ifvlan
*ifv
= ifp
->if_softc
;
442 if ((ifp
->if_flags
& IFF_PROMISC
) != 0) {
443 if ((ifv
->ifv_flags
& IFVF_PROMISC
) == 0) {
444 error
= ifpromisc(ifv
->ifv_p
, 1);
446 ifv
->ifv_flags
|= IFVF_PROMISC
;
449 if ((ifv
->ifv_flags
& IFVF_PROMISC
) != 0) {
450 error
= ifpromisc(ifv
->ifv_p
, 0);
452 ifv
->ifv_flags
&= ~IFVF_PROMISC
;
460 vlan_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
462 struct lwp
*l
= curlwp
; /* XXX */
463 struct ifvlan
*ifv
= ifp
->if_softc
;
464 struct ifaddr
*ifa
= (struct ifaddr
*) data
;
465 struct ifreq
*ifr
= (struct ifreq
*) data
;
467 struct ifcapreq
*ifcr
;
475 if (ifv
->ifv_p
!= NULL
) {
476 ifp
->if_flags
|= IFF_UP
;
478 switch (ifa
->ifa_addr
->sa_family
) {
481 arp_ifinit(ifp
, ifa
);
493 if (ifv
->ifv_p
== NULL
)
496 ifr
->ifr_mtu
> (ifv
->ifv_p
->if_mtu
- ifv
->ifv_mtufudge
) ||
497 ifr
->ifr_mtu
< (ifv
->ifv_mintu
- ifv
->ifv_mtufudge
))
499 else if ((error
= ifioctl_common(ifp
, cmd
, data
)) == ENETRESET
)
504 if ((error
= kauth_authorize_network(l
->l_cred
,
505 KAUTH_NETWORK_INTERFACE
,
506 KAUTH_REQ_NETWORK_INTERFACE_SETPRIV
, ifp
, (void *)cmd
,
509 if ((error
= copyin(ifr
->ifr_data
, &vlr
, sizeof(vlr
))) != 0)
511 if (vlr
.vlr_parent
[0] == '\0') {
515 if (vlr
.vlr_tag
!= EVL_VLANOFTAG(vlr
.vlr_tag
)) {
516 error
= EINVAL
; /* check for valid tag */
519 if ((pr
= ifunit(vlr
.vlr_parent
)) == 0) {
523 if ((error
= vlan_config(ifv
, pr
)) != 0)
525 ifv
->ifv_tag
= vlr
.vlr_tag
;
526 ifp
->if_flags
|= IFF_RUNNING
;
528 /* Update promiscuous mode, if necessary. */
529 vlan_set_promisc(ifp
);
533 memset(&vlr
, 0, sizeof(vlr
));
534 if (ifv
->ifv_p
!= NULL
) {
535 snprintf(vlr
.vlr_parent
, sizeof(vlr
.vlr_parent
), "%s",
536 ifv
->ifv_p
->if_xname
);
537 vlr
.vlr_tag
= ifv
->ifv_tag
;
539 error
= copyout(&vlr
, ifr
->ifr_data
, sizeof(vlr
));
543 if ((error
= ifioctl_common(ifp
, cmd
, data
)) != 0)
546 * For promiscuous mode, we enable promiscuous mode on
547 * the parent if we need promiscuous on the VLAN interface.
549 if (ifv
->ifv_p
!= NULL
)
550 error
= vlan_set_promisc(ifp
);
554 error
= (ifv
->ifv_p
!= NULL
) ?
555 (*ifv
->ifv_msw
->vmsw_addmulti
)(ifv
, ifr
) : EINVAL
;
559 error
= (ifv
->ifv_p
!= NULL
) ?
560 (*ifv
->ifv_msw
->vmsw_delmulti
)(ifv
, ifr
) : EINVAL
;
565 /* make sure caps are enabled on parent */
566 if ((ifv
->ifv_p
->if_capenable
& ifcr
->ifcr_capenable
) !=
567 ifcr
->ifcr_capenable
) {
571 if ((error
= ifioctl_common(ifp
, cmd
, data
)) == ENETRESET
)
575 error
= ether_ioctl(ifp
, cmd
, data
);
584 vlan_ether_addmulti(struct ifvlan
*ifv
, struct ifreq
*ifr
)
586 const struct sockaddr
*sa
= ifreq_getaddr(SIOCADDMULTI
, ifr
);
587 struct vlan_mc_entry
*mc
;
588 uint8_t addrlo
[ETHER_ADDR_LEN
], addrhi
[ETHER_ADDR_LEN
];
591 if (sa
->sa_len
> sizeof(struct sockaddr_storage
))
594 error
= ether_addmulti(sa
, &ifv
->ifv_ec
);
595 if (error
!= ENETRESET
)
599 * This is new multicast address. We have to tell parent
600 * about it. Also, remember this multicast address so that
601 * we can delete them on unconfigure.
603 mc
= malloc(sizeof(struct vlan_mc_entry
), M_DEVBUF
, M_NOWAIT
);
610 * As ether_addmulti() returns ENETRESET, following two
611 * statement shouldn't fail.
613 (void)ether_multiaddr(sa
, addrlo
, addrhi
);
614 ETHER_LOOKUP_MULTI(addrlo
, addrhi
, &ifv
->ifv_ec
, mc
->mc_enm
);
615 memcpy(&mc
->mc_addr
, sa
, sa
->sa_len
);
616 LIST_INSERT_HEAD(&ifv
->ifv_mc_listhead
, mc
, mc_entries
);
618 error
= (*ifv
->ifv_p
->if_ioctl
)(ifv
->ifv_p
, SIOCADDMULTI
,
625 LIST_REMOVE(mc
, mc_entries
);
628 (void)ether_delmulti(sa
, &ifv
->ifv_ec
);
633 vlan_ether_delmulti(struct ifvlan
*ifv
, struct ifreq
*ifr
)
635 const struct sockaddr
*sa
= ifreq_getaddr(SIOCDELMULTI
, ifr
);
636 struct ether_multi
*enm
;
637 struct vlan_mc_entry
*mc
;
638 uint8_t addrlo
[ETHER_ADDR_LEN
], addrhi
[ETHER_ADDR_LEN
];
642 * Find a key to lookup vlan_mc_entry. We have to do this
643 * before calling ether_delmulti for obvious reason.
645 if ((error
= ether_multiaddr(sa
, addrlo
, addrhi
)) != 0)
647 ETHER_LOOKUP_MULTI(addrlo
, addrhi
, &ifv
->ifv_ec
, enm
);
649 error
= ether_delmulti(sa
, &ifv
->ifv_ec
);
650 if (error
!= ENETRESET
)
653 /* We no longer use this multicast address. Tell parent so. */
654 error
= (*ifv
->ifv_p
->if_ioctl
)(ifv
->ifv_p
, SIOCDELMULTI
,
657 /* And forget about this address. */
658 for (mc
= LIST_FIRST(&ifv
->ifv_mc_listhead
); mc
!= NULL
;
659 mc
= LIST_NEXT(mc
, mc_entries
)) {
660 if (mc
->mc_enm
== enm
) {
661 LIST_REMOVE(mc
, mc_entries
);
668 (void)ether_addmulti(sa
, &ifv
->ifv_ec
);
673 * Delete any multicast address we have asked to add from parent
674 * interface. Called when the vlan is being unconfigured.
677 vlan_ether_purgemulti(struct ifvlan
*ifv
)
679 struct ifnet
*ifp
= ifv
->ifv_p
; /* Parent. */
680 struct vlan_mc_entry
*mc
;
684 char ifr_name
[IFNAMSIZ
];
685 struct sockaddr_storage ifr_ss
;
688 struct ifreq
*ifr
= &ifreq
.ifreq
;
690 memcpy(ifr
->ifr_name
, ifp
->if_xname
, IFNAMSIZ
);
691 while ((mc
= LIST_FIRST(&ifv
->ifv_mc_listhead
)) != NULL
) {
692 ifreq_setaddr(SIOCDELMULTI
, ifr
,
693 (const struct sockaddr
*)&mc
->mc_addr
);
694 (void)(*ifp
->if_ioctl
)(ifp
, SIOCDELMULTI
, (void *)ifr
);
695 LIST_REMOVE(mc
, mc_entries
);
701 vlan_start(struct ifnet
*ifp
)
703 struct ifvlan
*ifv
= ifp
->if_softc
;
704 struct ifnet
*p
= ifv
->ifv_p
;
705 struct ethercom
*ec
= (void *) ifv
->ifv_p
;
708 ALTQ_DECL(struct altq_pktattr pktattr
;)
710 ifp
->if_flags
|= IFF_OACTIVE
;
713 IFQ_DEQUEUE(&ifp
->if_snd
, m
);
719 * If ALTQ is enabled on the parent interface, do
720 * classification; the queueing discipline might
721 * not require classification, but might require
722 * the address family/header pointer in the pktattr.
724 if (ALTQ_IS_ENABLED(&p
->if_snd
)) {
725 switch (p
->if_type
) {
727 altq_etherclassify(&p
->if_snd
, m
, &pktattr
);
731 panic("vlan_start: impossible (altq)");
739 bpf_mtap(ifp
->if_bpf
, m
);
742 * If the parent can insert the tag itself, just mark
743 * the tag in the mbuf header.
745 if (ec
->ec_capabilities
& ETHERCAP_VLAN_HWTAGGING
) {
748 mtag
= m_tag_get(PACKET_TAG_VLAN
, sizeof(u_int
),
755 *(u_int
*)(mtag
+ 1) = ifv
->ifv_tag
;
756 m_tag_prepend(m
, mtag
);
759 * insert the tag ourselves
761 M_PREPEND(m
, ifv
->ifv_encaplen
, M_DONTWAIT
);
763 printf("%s: unable to prepend encap header",
764 ifv
->ifv_p
->if_xname
);
769 switch (p
->if_type
) {
772 struct ether_vlan_header
*evl
;
774 if (m
->m_len
< sizeof(struct ether_vlan_header
))
776 sizeof(struct ether_vlan_header
));
778 printf("%s: unable to pullup encap "
779 "header", ifv
->ifv_p
->if_xname
);
785 * Transform the Ethernet header into an
786 * Ethernet header with 802.1Q encapsulation.
788 memmove(mtod(m
, void *),
789 mtod(m
, char *) + ifv
->ifv_encaplen
,
790 sizeof(struct ether_header
));
791 evl
= mtod(m
, struct ether_vlan_header
*);
792 evl
->evl_proto
= evl
->evl_encap_proto
;
793 evl
->evl_encap_proto
= htons(ETHERTYPE_VLAN
);
794 evl
->evl_tag
= htons(ifv
->ifv_tag
);
797 * To cater for VLAN-aware layer 2 ethernet
798 * switches which may need to strip the tag
799 * before forwarding the packet, make sure
800 * the packet+tag is at least 68 bytes long.
801 * This is necessary because our parent will
802 * only pad to 64 bytes (ETHER_MIN_LEN) and
803 * some switches will not pad by themselves
804 * after deleting a tag.
806 if (m
->m_pkthdr
.len
<
807 (ETHER_MIN_LEN
+ ETHER_VLAN_ENCAP_LEN
)) {
808 m_copyback(m
, m
->m_pkthdr
.len
,
810 ETHER_VLAN_ENCAP_LEN
) -
819 panic("vlan_start: impossible");
825 * Send it, precisely as the parent's output routine
826 * would have. We are already running at splnet.
828 IFQ_ENQUEUE(&p
->if_snd
, m
, &pktattr
, error
);
830 /* mbuf is already freed */
836 if ((p
->if_flags
& (IFF_RUNNING
|IFF_OACTIVE
)) == IFF_RUNNING
)
840 ifp
->if_flags
&= ~IFF_OACTIVE
;
844 * Given an Ethernet frame, find a valid vlan interface corresponding to the
845 * given source interface and tag, then run the real packet through the
846 * parent's input routine.
849 vlan_input(struct ifnet
*ifp
, struct mbuf
*m
)
855 mtag
= m_tag_find(m
, PACKET_TAG_VLAN
, NULL
);
857 /* m contains a normal ethernet frame, the tag is in mtag */
858 tag
= EVL_VLANOFTAG(*(u_int
*)(mtag
+ 1));
859 m_tag_delete(m
, mtag
);
861 switch (ifp
->if_type
) {
864 struct ether_vlan_header
*evl
;
866 if (m
->m_len
< sizeof(struct ether_vlan_header
) &&
868 sizeof(struct ether_vlan_header
))) == NULL
) {
869 printf("%s: no memory for VLAN header, "
870 "dropping packet.\n", ifp
->if_xname
);
873 evl
= mtod(m
, struct ether_vlan_header
*);
874 KASSERT(ntohs(evl
->evl_encap_proto
) == ETHERTYPE_VLAN
);
876 tag
= EVL_VLANOFTAG(ntohs(evl
->evl_tag
));
879 * Restore the original ethertype. We'll remove
880 * the encapsulation after we've found the vlan
881 * interface corresponding to the tag.
883 evl
->evl_encap_proto
= evl
->evl_proto
;
888 tag
= (u_int
) -1; /* XXX GCC */
890 panic("vlan_input: impossible");
895 for (ifv
= LIST_FIRST(&ifv_list
); ifv
!= NULL
;
896 ifv
= LIST_NEXT(ifv
, ifv_list
))
897 if (ifp
== ifv
->ifv_p
&& tag
== ifv
->ifv_tag
)
901 (ifv
->ifv_if
.if_flags
& (IFF_UP
|IFF_RUNNING
)) !=
902 (IFF_UP
|IFF_RUNNING
)) {
909 * Now, remove the encapsulation header. The original
910 * header has already been fixed up above.
913 memmove(mtod(m
, char *) + ifv
->ifv_encaplen
,
914 mtod(m
, void *), sizeof(struct ether_header
));
915 m_adj(m
, ifv
->ifv_encaplen
);
918 m
->m_pkthdr
.rcvif
= &ifv
->ifv_if
;
919 ifv
->ifv_if
.if_ipackets
++;
922 if (ifv
->ifv_if
.if_bpf
)
923 bpf_mtap(ifv
->ifv_if
.if_bpf
, m
);
926 /* Pass it back through the parent's input routine. */
927 (*ifp
->if_input
)(&ifv
->ifv_if
, m
);