Subject: kern/33216: taggged VLAN packets are seen when they should not
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Pavel Cahyna <pcah8322@artax.karlin.mff.cuni.cz>
List: netbsd-bugs
Date: 04/07/2006 20:35:00
>Number:         33216
>Category:       kern
>Synopsis:       taggged VLAN packets are seen when they should not
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Apr 07 20:35:00 +0000 2006
>Originator:     Pavel Cahyna
>Release:        NetBSD 3.0_RC5
>Organization:
>Environment:
System: NetBSD beta 3.0_RC5 NetBSD 3.0_RC5 (EV56) #3: Mon Dec 12 20:28:20 CET 2005 pavel@beta:/usr/src/sys/arch/alpha/compile/EV56 alpha
Architecture: alpha
Machine: alpha
>Description:
When no VLAN is enabled on an interface which supports HW VLAN tag
insertion and removal, and tagged frames are received, they are
threated as untagged. If a VLAN is enabled, those frames (with a
different VLAN id) are dropped, as they should.
>How-To-Repeat:
Host A has a NIC with HW vlan tagging support.
HostB# ifconfig vlan0 create
HostB# ifconfig vlan0 vlan 4 vlanif fxp0
HostB# ping6 ff02::1%vlan0
PING6(56=40+8+8 bytes) fe80::<HostB>%fxp0 --> ff02::1%fxp0
16 bytes from fe80::<HostB>%vlan0, icmp_seq=0 hlim=64 time=0.151 ms
16 bytes from fe80::<HostA>%fxp0, icmp_seq=0 hlim=64 time=0.504 ms(DUP!)

HostA# ifconfig vlan0 create
HostA# ifconfig vlan0 vlan 5 vlanif gsip0
HostA# ifconfig vlan0 up
HostB# ping6 ff02::1%vlan0
PING6(56=40+8+8 bytes) fe80::<HostB>%fxp0 --> ff02::1%fxp0
16 bytes from fe80::<HostB>%vlan0, icmp_seq=0 hlim=64 time=0.152 ms

(note: no duplicate.)

sys/net/if_ethersubr.c has this code:
	if (ec->ec_nvlans && m_tag_find(m, PACKET_TAG_VLAN, NULL) != 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;
	}

which lets the tagged frames pass as untagged if ec->ec_nvlans == 0.
>Fix:
(untested) remove the ec->ec_nvlans check, like this:
	if (m_tag_find(m, PACKET_TAG_VLAN, NULL) != NULL) {
#if NVLAN > 0
	if (ec->ec_nvlans)
		/*
		 * vlan_input() will either recursively call ether_input()
		 * or drop the packet.
		 */
		vlan_input(ifp, m);
	else
		m_freem(m);
#else
		m_freem(m);
#endif
		return;
	}