VLAN related panics in 3.2
Hello,
Attached is a patch which fixes bugs in the VLAN multicast handling code.
It should apply against 3.2-stable and -current. I think this patch will
address the errors/panic seen in bug number 3007.
Problems fixed:
- Memory corruption in (leading to panic) when vlans and ipv6 are enabled.
The system was copying a struct sockaddr (when recording what multicast
addresses are in use so it can free them later) into a malloc'd space that
was only big enough for an ethernet address. Changed the target variable to
hold a struct sockaddr_storage which is guaranteed to be large enough.
- Multicast lists would not be purged correctly at interface
deconfiguration time. When passing the multicast address that should be
removed to the parent interface, an incomplete length would be passed for
non-ipv4 multicast addresses. Similar problems to the first bug.
- Multicast list initialised incorrectly every time the vlan interface's
if_start method is called. This causes a memory leak for every multicast
address registered and incorrect reference counts on the parent interface -
so a multicast address may never be removed from the parent's multicast
filters. Moved this initialisation to occur at interface creation time.
- Multicast addresses would never be registered on the parent interfaces.
The NetBSD codebase (where the most recent vlan changes were ported from)
handle SIOCADDMULTI in its ether_ioctl function and uses this to register
multicast addresses on the parent. On OpenBSD the parent's if_ioctl must be
called directly.
Regards,
Chris
--
Christopher Pascoe
IT Infrastructure Manager
School of Information Technology and Electrical Engineering
The University of Queensland Brisbane QLD 4072 Australia
Index: sys/net/if_vlan_var.h
===================================================================
RCS file:
/cvs/src/sys/net/if_vlan_var.h,v
retrieving revision 1.8
diff -u -r1.8
if_vlan_var.h
--- sys/net/if_vlan_var.h 12 Jun 2002 01:42:29 -0000 1.8
+++
sys/net/if_vlan_var.h 30 Jan 2003 10:14:16 -0000
@@ -42,7 +42,7 @@
union {
struct ether_multi *mcu_enm;
} mc_u;
- struct ether_addr mc_addr;
+ struct
sockaddr_storage mc_addr;
};
struct ifvlan {
Index: sys/net/if_vlan.c
===================================================================
RCS file:
/cvs/src/sys/net/if_vlan.c,v
retrieving revision 1.32
diff -u -r1.32 if_vlan.c
--- sys/net/if_vlan.c 12 Jun 2002 01:42:29 -0000 1.32
+++ sys/net/if_vlan.c 30
Jan 2003 10:14:29 -0000
@@ -110,6 +110,7 @@
bzero(ifv_softc, nifvlan *
sizeof(struct ifvlan));
for (i = 0; i < nifvlan; i++) {
+
LIST_INIT(&ifv_softc[i].vlan_mc_listhead);
ifp = &ifv_softc[i].ifv_if;
ifp->if_softc = &ifv_softc[i];
sprintf(ifp->if_xname, "vlan%d", i);
@@
-141,7 +142,6 @@
ifv = ifp->if_softc;
p = ifv->ifv_p;
-
LIST_INIT(&ifv->vlan_mc_listhead);
ifp->if_flags |= IFF_OACTIVE;
for
(;;) {
@@ -640,6 +640,7 @@
int
vlan_ether_addmulti(struct ifvlan *ifv,
struct ifreq *ifr)
{
+ struct ifnet *ifp = ifv->ifv_p; /* Parent. */
struct vlan_mc_entry *mc;
u_int8_t addrlo[ETHER_ADDR_LEN],
addrhi[ETHER_ADDR_LEN];
int error;
@@ -672,10 +673,10 @@
memcpy(&mc->mc_addr, &ifr->ifr_addr, ifr->ifr_addr.sa_len);
LIST_INSERT_HEAD(&ifv->vlan_mc_listhead, mc, mc_entries);
- error =
ether_ioctl(ifv->ifv_p, &ifv->ifv_ac, SIOCADDMULTI,
- (caddr_t)ifr);
+
error = (*ifp->if_ioctl)(ifp, SIOCADDMULTI, (caddr_t)ifr);
if (error != 0)
goto ioctl_failed;
+
return (error);
ioctl_failed:
@@ -683,12 +684,14 @@
FREE(mc, M_DEVBUF);
alloc_failed:
(void)ether_delmulti(ifr, (struct arpcom
*)&ifv->ifv_ac);
+
return (error);
}
int
vlan_ether_delmulti(struct
ifvlan *ifv, struct ifreq *ifr)
{
+ struct ifnet *ifp = ifv->ifv_p; /*
Parent. */
struct ether_multi *enm;
struct vlan_mc_entry *mc;
u_int8_t
addrlo[ETHER_ADDR_LEN], addrhi[ETHER_ADDR_LEN];
@@ -707,8 +710,7 @@
return
(error);
/* We no longer use this multicast address. Tell parent so. */
-
error = ether_ioctl(ifv->ifv_p, &ifv->ifv_ac, SIOCDELMULTI,
-
(caddr_t)ifr);
+ error = (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)ifr);
if (error == 0) {
/* And forget about this address. */
for (mc =
LIST_FIRST(&ifv->vlan_mc_listhead); mc != NULL;
@@ -745,7 +747,7 @@
memcpy(ifr->ifr_name, ifp->if_xname, IFNAMSIZ);
while ((mc =
LIST_FIRST(&ifv->vlan_mc_listhead)) != NULL) {
- memcpy(&ifr->ifr_addr,
&mc->mc_addr, ETHER_ADDR_LEN);
+ memcpy(&ifr->ifr_addr, &mc->mc_addr,
mc->mc_addr.ss_len);
(void)(*ifp->if_ioctl)(ifp, SIOCDELMULTI,
(caddr_t)ifr);
LIST_REMOVE(mc, mc_entries);
FREE(mc, M_DEVBUF);
Received on Thu Jan 30 05:35:04 2003
This archive was generated by hypermail 2.1.8
: Wed Aug 23 2006 - 13:29:48 EDT
|