| Summary: | Bug in Hardware VLAN Tag Support | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | csg <csg> | ||||
| Component: | kern | Assignee: | Garrett Wollman <wollman> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | CC: | ajk | ||||
| Priority: | Normal | ||||||
| Version: | 3.3-STABLE | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
Responsible Changed From-To: freebsd-bugs->wollman Over to maintainer. I incorrectly removed the check for reporting an error condition
if the vlan interface wasn't IFF_UP. Here's a corrected patch:
Index: pci/if_ti.c
===================================================================
RCS file: /usr/local/share/cvs/FreeBSD/src/sys/pci/if_ti.c,v
retrieving revision 1.24
diff -u -r1.24 if_ti.c
--- if_ti.c 1999/09/23 03:32:54 1.24
+++ if_ti.c 1999/12/05 22:28:44
@@ -1887,7 +1887,8 @@
* to vlan_input() instead of ether_input().
*/
if (have_tag) {
- vlan_input_tag(eh, m, vlan_tag);
+ if (vlan_input_tag(eh, m, vlan_tag) < 0)
+ ifp->if_data.ifi_noproto++;
have_tag = vlan_tag = 0;
continue;
}
Index: net/if_vlan.c
===================================================================
RCS file: /usr/local/share/cvs/FreeBSD/src/sys/net/if_vlan.c,v
retrieving revision 1.10
diff -u -r1.10 if_vlan.c
--- if_vlan.c 1999/09/25 12:05:57 1.10
+++ if_vlan.c 1999/12/12 22:48:27
@@ -272,7 +272,7 @@
return;
}
-void
+int
vlan_input_tag(struct ether_header *eh, struct mbuf *m, u_int16_t t)
{
int i;
@@ -285,9 +285,8 @@
}
if (i >= NVLAN || (ifv->ifv_if.if_flags & IFF_UP) == 0) {
- m_freem(m);
- ifv->ifv_p->if_data.ifi_noproto++;
- return;
+ m_free(m);
+ return -1; /* So the parent can take note */
}
/*
@@ -312,7 +311,7 @@
}
ifv->ifv_if.if_ipackets++;
ether_input(&ifv->ifv_if, eh, m);
- return;
+ return 0;
}
int
Index: net/if_vlan_var.h
===================================================================
RCS file: /usr/local/share/cvs/FreeBSD/src/sys/net/if_vlan_var.h,v
retrieving revision 1.3
diff -u -r1.3 if_vlan_var.h
--- if_vlan_var.h 1999/08/28 00:48:24 1.3
+++ if_vlan_var.h 1999/12/05 22:19:22
@@ -85,7 +85,7 @@
/* shared with if_ethersubr.c: */
extern u_int vlan_proto;
extern int vlan_input(struct ether_header *eh, struct mbuf *m);
-extern void vlan_input_tag(struct ether_header *eh,
+extern int vlan_input_tag(struct ether_header *eh,
struct mbuf *m, u_int16_t t);
#endif
State Changed From-To: open->closed Fixes (including update) merged to both branches, thanks. |
sys/net/if_vlan.c contains support for ethernet hardware that support tagged VLANs in hardware. Currently (AFAIK) only the "ti" driver written by Bill Paul has support for these features. Apparently, when the ethernet driver detects a tagged frame from the hardware, it passes the frame, along with the tag to vlan_input_tag() instead of the normal vlan_input() call from inside ether_input(). The problem arrises in an attempt to log errors on the parent device. vlan_input_tag() walks the list of vlan devices, looking for a matching and tries to log the error on the parent device if appropriately. Unfortunatly, the current code incorrectly assumes that all vlans are configured, and/or associated with a parent device. If you receive a frame for a VLAN that's not in the list, you walk off the end of the list. Boom. Fix: This patch modifies vlan_input_tag to return -1 in the event of an error so the parent device can maintain its counters for us. - BEGIN PATCH ----------------------------------------------------------------- -void +int vlan_input_tag(struct ether_header *eh, struct mbuf *m, u_int16_t t) { int i; @@ -284,10 +284,9 @@ break; } - if (i >= NVLAN || (ifv->ifv_if.if_flags & IFF_UP) == 0) { - m_freem(m); - ifv->ifv_p->if_data.ifi_noproto++; - return; + if (i >= NVLAN) { + m_free(m); + return -1; /* So the parent can take note */ } /* @@ -312,7 +311,7 @@ } ifv->ifv_if.if_ipackets++; ether_input(&ifv->ifv_if, eh, m); - return; + return 0; } int - END PATCH ---------------------------------------------------------------------lJHzUWqIJi0iZr8JQrJiKzouPv2kkUJpo2YHwTRSNP5XJrQU Content-Type: text/plain; name="file.diff" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="file.diff" Index: pci/if_ti.c =================================================================== RCS file: /usr/local/share/cvs/FreeBSD/src/sys/pci/if_ti.c,v retrieving revision 1.24 diff -u -r1.24 if_ti.c --- if_ti.c 1999/09/23 03:32:54 1.24 +++ if_ti.c 1999/12/05 22:28:44 @@ -1887,7 +1887,8 @@ * to vlan_input() instead of ether_input(). */ if (have_tag) { - vlan_input_tag(eh, m, vlan_tag); + if (vlan_input_tag(eh, m, vlan_tag) < 0) + ifp->if_data.ifi_noproto++; have_tag = vlan_tag = 0; continue; } Index: if_vlan.c =================================================================== RCS file: /usr/local/share/cvs/FreeBSD/src/sys/net/if_vlan.c,v retrieving revision 1.10 diff -u -r1.10 if_vlan.c --- if_vlan.c 1999/09/25 12:05:57 1.10 +++ if_vlan.c 1999/12/06 00:17:05 @@ -272,7 +272,7 @@ return; } How-To-Repeat: 1. Setup a host with multiple VLAN's on an 802.1Q trunk to the machine, with a ti0 ethernet interface. 2. Configure some but not all of the vlan interfaces: # ifconfig <parent-device> up # ifconfig vlan0 vlandev <parent-device> vlan <tag-number 1> # ifconfig vlan1 vlandev <parent-device> vlan <tag-number 2> 3. Wait for traffic on an as-of-yet unconfigured vlan number. 4. Watch your machine crashdump..