summaryrefslogtreecommitdiffstats
path: root/sys/net/if_vlan.c
diff options
context:
space:
mode:
authorbms <bms@FreeBSD.org>2004-07-04 18:32:54 +0000
committerbms <bms@FreeBSD.org>2004-07-04 18:32:54 +0000
commitf58c85659673b7c072819abbd7c5a27785b5c2fb (patch)
treee8809577df2cf1ec4c8a69af3bbffc5f613c62fc /sys/net/if_vlan.c
parent423979003aba4f7f09234e090a743183e3957b0f (diff)
downloadFreeBSD-src-f58c85659673b7c072819abbd7c5a27785b5c2fb.zip
FreeBSD-src-f58c85659673b7c072819abbd7c5a27785b5c2fb.tar.gz
Workaround a locking problem in vlan(4). vlan_setmulti() may be called
with sleepable locks held from further up in the network stack, and attempts to allocate memory to hold multicast group membership information with M_WAITOK. This panic was triggered specifically when an exiting routing daemon process closes its raw sockets after joining multicast groups on them. While we're here, comment some possible locking badness. PR: kern/48560
Diffstat (limited to 'sys/net/if_vlan.c')
-rw-r--r--sys/net/if_vlan.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/sys/net/if_vlan.c b/sys/net/if_vlan.c
index a981dd5..da9b280 100644
--- a/sys/net/if_vlan.c
+++ b/sys/net/if_vlan.c
@@ -144,6 +144,9 @@ struct if_clone vlan_cloner = IFC_CLONE_INITIALIZER(VLANNAME, NULL, IF_MAXUNIT,
* traffic that it doesn't really want, which ends up being discarded
* later by the upper protocol layers. Unfortunately, there's no way
* to avoid this: there really is only one physical interface.
+ *
+ * XXX: There is a possible race here if more than one thread is
+ * modifying the multicast state of the vlan interface at the same time.
*/
static int
vlan_setmulti(struct ifnet *ifp)
@@ -155,6 +158,8 @@ vlan_setmulti(struct ifnet *ifp)
struct sockaddr_dl sdl;
int error;
+ /*VLAN_LOCK_ASSERT();*/
+
/* Find the parent. */
sc = ifp->if_softc;
ifp_p = sc->ifv_p;
@@ -188,7 +193,9 @@ vlan_setmulti(struct ifnet *ifp)
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
if (ifma->ifma_addr->sa_family != AF_LINK)
continue;
- mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_WAITOK);
+ mc = malloc(sizeof(struct vlan_mc_entry), M_VLAN, M_NOWAIT);
+ if (mc == NULL)
+ return (ENOMEM);
bcopy(LLADDR((struct sockaddr_dl *)ifma->ifma_addr),
(char *)&mc->mc_addr, ETHER_ADDR_LEN);
SLIST_INSERT_HEAD(&sc->vlan_mc_listhead, mc, mc_entries);
@@ -716,7 +723,7 @@ vlan_config(struct ifvlan *ifv, struct ifnet *p)
* Configure multicast addresses that may already be
* joined on the vlan device.
*/
- (void)vlan_setmulti(&ifv->ifv_if);
+ (void)vlan_setmulti(&ifv->ifv_if); /* XXX: VLAN lock held */
return (0);
}
@@ -981,7 +988,9 @@ vlan_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
case SIOCADDMULTI:
case SIOCDELMULTI:
+ /*VLAN_LOCK();*/
error = vlan_setmulti(ifp);
+ /*VLAN_UNLOCK();*/
break;
default:
error = EINVAL;
OpenPOWER on IntegriCloud