Subject: kern/32643: re(4) has problems with HW VLAN tagging
To: None <kern-bug-people@netbsd.org, gnats-admin@netbsd.org,>
From: Pavel Cahyna <pcah8322@artax.karlin.mff.cuni.cz>
List: netbsd-bugs
Date: 01/26/2006 22:00:01
>Number:         32643
>Category:       kern
>Synopsis:       re(4) has problems with HW VLAN tagging
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Thu Jan 26 22:00:01 +0000 2006
>Originator:     Pavel Cahyna
>Release:        NetBSD 3.0
>Organization:
>Environment:
System: NetBSD beta.imc.cas.cz 3.0 NetBSD 3.0 (GENERIC-RLPHY) #3: Thu Jan 26 16:18:14 CET 2006 cahyna@beta.imc.cas.cz:/usr/src/sys/arch/i386/compile/GENERIC-RLPHY i386
Architecture: i386
Machine: i386
>Description:
I configured a VLAN device on this re NIC:

re0 at pci1 dev 3 function 0: RealTek 8169S Single-chip Gigabit Ethernet
re0: interrupting at irq 5
re0: Ethernet address 00:01:6c:34:87:14
re0: using 256 tx descriptors
ukphy0 at re0 phy 7: Generic IEEE 802.3u media interface
ukphy0: RTL8169S/8110S 1000BASE-T media interface (OUI 0x00e04c, model 0x0011), rev. 0
ukphy0: 10baseT, 10baseT-FDX, 100baseTX, 100baseTX-FDX, 1000baseT, 1000baseT-FDX, auto

The tagged VLAN itself is working fine. But packets going to the untagged
VLAN are often incorrectly tagged with the tag of the tagged VLAN. This
breaks communication over the untagged VLAN. After a reset of the device
with ifconfig re0 down up, it gets better, but after several minutes of
using both VLANs, the problem is back.
>How-To-Repeat:
ifconfig re0 inet xxx
ifconfig vlan0 create; ifconfig vlan0 vlan 4 vlanif re0
ifconfig vlan0 inet 192.168.1.1
now watch the ethernet segment with tcpdump -e on another machine and
observe that some packets with source address xxx are sent with a VLAN
tag.
>Fix:
OpenBSD has a similar HW VLAN tagging code, but it has been always
commented out. Maybe it is a hardware bug? Until a better fix is found, I
propose the following, which disables HW VLAN tagging and works for me.
(NB VLANs in OpenBSD on re do not work - they forgot to disable tag
stripping on input. This problem is corrected in the following diff.
Otherwise the diff is taken from OpenBSD.)

Index: rtl8169.c
===================================================================
RCS file: /cvsroot/src/sys/dev/ic/rtl8169.c,v
retrieving revision 1.14.2.4
diff -u -r1.14.2.4 rtl8169.c
--- rtl8169.c	18 Aug 2005 20:40:38 -0000	1.14.2.4
+++ rtl8169.c	26 Jan 2006 21:05:22 -0000
@@ -745,8 +745,10 @@
 	ifp->if_mtu = ETHERMTU;
 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
 	ifp->if_ioctl = re_ioctl;
-	sc->ethercom.ec_capabilities |=
-	    ETHERCAP_VLAN_MTU | ETHERCAP_VLAN_HWTAGGING;
+	sc->ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
+#ifdef RE_VLAN
+	sc->ethercom.ec_capabilities |= ETHERCAP_VLAN_HWTAGGING;
+#endif
 	ifp->if_start = re_start;
 	ifp->if_stop = re_stop;
 	ifp->if_capabilities |=
@@ -1269,11 +1271,13 @@
 				m->m_pkthdr.csum_flags |= M_CSUM_TCP_UDP_BAD;
 		}
 
+#ifdef RE_VLAN
 		if (rxvlan & RTK_RDESC_VLANCTL_TAG) {
 			VLAN_INPUT_TAG(ifp, m,
 			     be16toh(rxvlan & RTK_RDESC_VLANCTL_DATA),
 			     continue);
 		}
+#endif
 #if NBPFILTER > 0
 		if (ifp->if_bpf)
 			bpf_mtap(ifp->if_bpf, m);
@@ -1511,7 +1515,9 @@
 {
 	bus_dmamap_t		map;
 	int			error, i, startidx, curidx;
+#ifdef RE_VLAN
 	struct m_tag		*mtag;
+#endif
 	struct rtk_desc		*d;
 	u_int32_t		cmdstat, rtk_flags;
 	struct rtk_txq		*txq;
@@ -1625,11 +1631,13 @@
 	 * transmission attempt.
 	 */
 
+#ifdef RE_VLAN
 	if ((mtag = VLAN_OUTPUT_TAG(&sc->ethercom, m)) != NULL) {
 		sc->rtk_ldata.rtk_tx_list[startidx].rtk_vlanctl =
 		    htole32(htons(VLAN_TAG_VALUE(mtag)) |
 		    RTK_TDESC_VLANCTL_TAG);
 	}
+#endif
 
 	/* Transfer ownership of packet to the chip. */
 
@@ -1781,7 +1789,10 @@
 		reg |= (0x1 << 14) | RTK_CPLUSCMD_PCI_MRW;;
 
 	if (1)  {/* not for 8169S ? */
-		reg |= RTK_CPLUSCMD_VLANSTRIP |
+		reg |= 
+#ifdef RE_VLAN
+		    RTK_CPLUSCMD_VLANSTRIP |
+#endif
 		    (ifp->if_capenable &
 		    (IFCAP_CSUM_IPv4 | IFCAP_CSUM_TCPv4 | IFCAP_CSUM_UDPv4) ?
 		    RTK_CPLUSCMD_RXCSUM_ENB : 0);