Subject: kern/18102: Network interfaces do not receive VLAN-tagged packet with VLAN id 0.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <haya@ilink.sony.co.jp>
List: netbsd-bugs
Date: 08/29/2002 18:56:18
>Number: 18102
>Category: kern
>Synopsis: Network i/f does not receive VLAN-tagged packet w/ VLAN id 0.
>Confidential: no
>Severity: non-critical
>Priority: medium
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Thu Aug 29 02:57:00 PDT 2002
>Closed-Date:
>Last-Modified:
>Originator: HAYAKAWA Koichi
>Release: NetBSD 1.6E
>Organization:
>Environment:
System: NetBSD trangie 1.6E NetBSD 1.6E (TRANGIE) #20: Tue Aug 20 19:00:22 JST 2002 haya@trangie:/home/haya/src/NetBSD/syssrc/sys/arch/i386/compile/TRANGIE i386
Architecture: i386
Machine: i386
>Description:
All VLAN-tagged packets with VLAN id 0 are not received by
NetBSD kernel.
IEEE 802.1D spec says a packet which VLAN tag ID is 0 should
be treated as an untagged packet when it is received.
>How-To-Repeat:
1. make NetBSD kernel with pseudodevice vlan enabled.
2. enable a network interface which has vlan capability.
3. send VLAN-tagged packets w/ VLAN id 0 to the network interface.
4. NetBSD wont receive VLAN-tagged packets w/ VLAN id 0.
>Fix:
This patch would fix this problem.
--
Index: sys/net/if_ethersubr.c
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_ethersubr.c,v
retrieving revision 1.98
diff -c -r1.98 if_ethersubr.c
*** sys/net/if_ethersubr.c 2002/08/26 01:39:39 1.98
--- sys/net/if_ethersubr.c 2002/08/27 11:38:15
***************
*** 762,798 ****
* see if the device performed the decapsulation and
* provided us with the tag.
*/
! if (ec->ec_nvlans &&
! (n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN)) != NULL) {
#if NVLAN > 0
/*
! * vlan_input() will either recursively call ether_input()
! * or drop the packet.
*/
- vlan_input(ifp, m);
#else
m_freem(m);
- #endif
return;
}
/*
* Handle protocols that expect to have the Ethernet header
* (and possibly FCS) intact.
*/
switch (etype) {
- #if NVLAN > 0
- case ETHERTYPE_VLAN:
- /*
- * vlan_input() will either recursively call ether_input()
- * or drop the packet.
- */
- if (((struct ethercom *)ifp)->ec_nvlans != 0)
- vlan_input(ifp, m);
- else
- m_freem(m);
- return;
- #endif /* NVLAN > 0 */
#if NPPPOE > 0
case ETHERTYPE_PPPOEDISC:
case ETHERTYPE_PPPOE:
--- 762,846 ----
* see if the device performed the decapsulation and
* provided us with the tag.
*/
! if ((n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN)) != NULL) {
#if NVLAN > 0
+ u_int tag;
+
+ /* m contains a normal ethernet frame, the tag is in m_aux */
+ tag = EVL_VLANOFTAG(*mtod(n, int *));
+ m_aux_delete(m, n);
+
+ if (tag != 0) {
+ /* VLAN-tagged frame (IEEE 802.1D 3.18) */
+ if (ec->ec_nvlans > 0) {
+ vlan_input(ifp, m, tag);
+ } else {
+ m_freem(m);
+ }
+ return;
+ }
/*
! * priority-tagged frame (IEEE 802.1D 3.8) must be
! * treated same as non-tagged frame.
*/
#else
m_freem(m);
return;
+ #endif
}
+ if (etype == ETHERTYPE_VLAN) {
+ #if NVLAN > 0
+ u_int tag;
+ struct ether_vlan_header *evl;
+
+ if (m->m_len < sizeof(struct ether_vlan_header) &&
+ (m = m_pullup(m,
+ sizeof(struct ether_vlan_header))) == NULL) {
+ printf("%s: no memory for VLAN header, "
+ "dropping packet.\n", ifp->if_xname);
+ return;
+ }
+ evl = mtod(m, struct ether_vlan_header *);
+ KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
+
+ tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
+
+ /* Find a VLAN-tagged frame but no VLAN if */
+ if (tag != 0 && ec->ec_nvlans == 0) {
+ m_freem(m);
+ return;
+ }
+
+ /*
+ * Restore the original ethertype. We'll remove
+ * the encapsulation.
+ */
+ etype = evl->evl_encap_proto = evl->evl_proto;
+
+ memmove(mtod(m, caddr_t) + ETHER_VLAN_ENCAP_LEN,
+ mtod(m, caddr_t), sizeof(struct ether_header));
+ m_adj(m, ETHER_VLAN_ENCAP_LEN);
+
+ if (tag != 0) {
+ /* VLAN-tagged frame (IEEE 802.1D 3.18) */
+ vlan_input(ifp, m, tag);
+ return;
+ }
+ /*
+ * priority-tagged frame (IEEE 802.1D 3.8) must be
+ * treated same as non-tagged frame.
+ */
+ #else
+ m_freem(m);
+ #endif /* NVLAN > 0 */
+ }
+
/*
* Handle protocols that expect to have the Ethernet header
* (and possibly FCS) intact.
*/
switch (etype) {
#if NPPPOE > 0
case ETHERTYPE_PPPOEDISC:
case ETHERTYPE_PPPOE:
Index: sys/net/if_vlan.c
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_vlan.c,v
retrieving revision 1.34
diff -c -r1.34 if_vlan.c
*** sys/net/if_vlan.c 2002/06/11 06:00:57 1.34
--- sys/net/if_vlan.c 2002/08/27 11:38:16
***************
*** 812,882 ****
* the parent's input routine.
*/
void
! vlan_input(struct ifnet *ifp, struct mbuf *m)
{
struct ifvlan *ifv;
- u_int tag;
- struct mbuf *n;
! n = m_aux_find(m, AF_LINK, ETHERTYPE_VLAN);
! if (n) {
! /* m contains a normal ethernet frame, the tag is in m_aux */
! tag = *mtod(n, int *);
! m_aux_delete(m, n);
! for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
! ifv = LIST_NEXT(ifv, ifv_list))
! if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
! break;
! } else {
! switch (ifp->if_type) {
! case IFT_ETHER:
! {
! struct ether_vlan_header *evl;
!
! if (m->m_len < sizeof(struct ether_vlan_header) &&
! (m = m_pullup(m,
! sizeof(struct ether_vlan_header))) == NULL) {
! printf("%s: no memory for VLAN header, "
! "dropping packet.\n", ifp->if_xname);
! return;
! }
! evl = mtod(m, struct ether_vlan_header *);
! KASSERT(ntohs(evl->evl_encap_proto) == ETHERTYPE_VLAN);
!
! tag = EVL_VLANOFTAG(ntohs(evl->evl_tag));
!
! /*
! * Restore the original ethertype. We'll remove
! * the encapsulation after we've found the vlan
! * interface corresponding to the tag.
! */
! evl->evl_encap_proto = evl->evl_proto;
break;
- }
-
- default:
- tag = (u_int) -1; /* XXX GCC */
- #ifdef DIAGNOSTIC
- panic("vlan_input: impossible");
- #endif
- }
-
- for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
- ifv = LIST_NEXT(ifv, ifv_list))
- if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
- break;
-
-
- /*
- * Now, remove the encapsulation header. The original
- * header has already been fixed up above.
- */
- if (ifv) {
- memmove(mtod(m, caddr_t) + ifv->ifv_encaplen,
- mtod(m, caddr_t), sizeof(struct ether_header));
- m_adj(m, ifv->ifv_encaplen);
- }
- }
if (ifv == NULL ||
(ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
--- 812,825 ----
* the parent's input routine.
*/
void
! vlan_input(struct ifnet *ifp, struct mbuf *m, u_int tag)
{
struct ifvlan *ifv;
! for (ifv = LIST_FIRST(&ifv_list); ifv != NULL;
! ifv = LIST_NEXT(ifv, ifv_list))
! if (ifp == ifv->ifv_p && tag == ifv->ifv_tag)
break;
if (ifv == NULL ||
(ifv->ifv_if.if_flags & (IFF_UP|IFF_RUNNING)) !=
Index: sys/net/if_vlanvar.h
===================================================================
RCS file: /cvsroot/syssrc/sys/net/if_vlanvar.h,v
retrieving revision 1.4
diff -c -r1.4 if_vlanvar.h
*** sys/net/if_vlanvar.h 2000/10/03 23:50:52 1.4
--- sys/net/if_vlanvar.h 2002/08/27 11:38:16
***************
*** 91,97 ****
#define SIOCGETVLAN SIOCGIFGENERIC
#ifdef _KERNEL
! void vlan_input(struct ifnet *, struct mbuf *);
void vlan_ifdetach(struct ifnet *);
#endif /* _KERNEL */
--- 91,97 ----
#define SIOCGETVLAN SIOCGIFGENERIC
#ifdef _KERNEL
! void vlan_input(struct ifnet *, struct mbuf *, u_int);
void vlan_ifdetach(struct ifnet *);
#endif /* _KERNEL */
--
>Release-Note:
>Audit-Trail:
>Unformatted: