summaryrefslogtreecommitdiffstats
path: root/sys/netinet/in.c
diff options
context:
space:
mode:
authorrwatson <rwatson@FreeBSD.org>2005-08-03 19:29:47 +0000
committerrwatson <rwatson@FreeBSD.org>2005-08-03 19:29:47 +0000
commit7504160c1e1a408af3d9f6b998e6e9ce49dcf158 (patch)
tree7da6aeba14225658b424b8a1f07d30e9523cbc3e /sys/netinet/in.c
parent405f9b654c12682dc78887f78db0d01ebe3acbdf (diff)
downloadFreeBSD-src-7504160c1e1a408af3d9f6b998e6e9ce49dcf158.zip
FreeBSD-src-7504160c1e1a408af3d9f6b998e6e9ce49dcf158.tar.gz
Introduce in_multi_mtx, which will protect IPv4-layer multicast address
lists, as well as accessor macros. For now, this is a recursive mutex due code sequences where IPv4 multicast calls into IGMP calls into ip_output(), which then tests for a multicast forwarding case. For support macros in in_var.h to check multicast address lists, assert that in_multi_mtx is held. Acquire in_multi_mtx around iteration over the IPv4 multicast address lists, such as in ip_input() and ip_output(). Acquire in_multi_mtx when manipulating the IPv4 layer multicast addresses, as well as over the manipulation of ifnet multicast address lists in order to keep the two layers in sync. Lock down accesses to IPv4 multicast addresses in IGMP, or assert the lock when performing IGMP join/leave events. Eliminate spl's associated with IPv4 multicast addresses, portions of IGMP that weren't previously expunged by IGMP locking. Add in_multi_mtx, igmp_mtx, and if_addr_mtx lock order to hard-coded lock order in WITNESS, in that order. Problem reported by: Ed Maste <emaste at phaedrus dot sandvine dot ca> MFC after: 10 days
Diffstat (limited to 'sys/netinet/in.c')
-rw-r--r--sys/netinet/in.c28
1 files changed, 18 insertions, 10 deletions
diff --git a/sys/netinet/in.c b/sys/netinet/in.c
index fcc1809..3f9d369 100644
--- a/sys/netinet/in.c
+++ b/sys/netinet/in.c
@@ -68,7 +68,16 @@ static int subnetsarelocal = 0;
SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
&subnetsarelocal, 0, "Treat all subnets as directly connected");
+/*
+ * The IPv4 multicast list (in_multihead and associated structures) are
+ * protected by the global in_multi_mtx. See in_var.h for more details. For
+ * now, in_multi_mtx is marked as recursible due to IGMP's calling back into
+ * ip_output() to send IGMP packets while holding the lock; this probably is
+ * not quite desirable.
+ */
struct in_multihead in_multihead; /* XXX BSS initialization */
+struct mtx in_multi_mtx;
+MTX_SYSINIT(in_multi_mtx, &in_multi_mtx, "in_multi_mtx", MTX_DEF | MTX_RECURSE);
extern struct inpcbinfo ripcbinfo;
extern struct inpcbinfo udbinfo;
@@ -949,8 +958,8 @@ in_addmulti(ap, ifp)
int error;
struct sockaddr_in sin;
struct ifmultiaddr *ifma;
- int s = splnet();
+ IN_MULTI_LOCK();
/*
* Call generic routine to add membership or increment
* refcount. It wants addresses in the form of a sockaddr,
@@ -962,7 +971,7 @@ in_addmulti(ap, ifp)
sin.sin_addr = *ap;
error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
if (error) {
- splx(s);
+ IN_MULTI_UNLOCK();
return 0;
}
@@ -971,16 +980,14 @@ in_addmulti(ap, ifp)
* a new record. Otherwise, we are done.
*/
if (ifma->ifma_protospec != NULL) {
- splx(s);
+ IN_MULTI_UNLOCK();
return ifma->ifma_protospec;
}
- /* XXX - if_addmulti uses M_WAITOK. Can this really be called
- at interrupt time? If so, need to fix if_addmulti. XXX */
inm = (struct in_multi *)malloc(sizeof(*inm), M_IPMADDR,
M_NOWAIT | M_ZERO);
if (inm == NULL) {
- splx(s);
+ IN_MULTI_UNLOCK();
return (NULL);
}
@@ -994,7 +1001,7 @@ in_addmulti(ap, ifp)
* Let IGMP know that we have joined a new IP multicast group.
*/
igmp_joingroup(inm);
- splx(s);
+ IN_MULTI_UNLOCK();
return (inm);
}
@@ -1005,10 +1012,11 @@ void
in_delmulti(inm)
register struct in_multi *inm;
{
- struct ifmultiaddr *ifma = inm->inm_ifma;
+ struct ifmultiaddr *ifma;
struct in_multi my_inm;
- int s = splnet();
+ IN_MULTI_LOCK();
+ ifma = inm->inm_ifma;
my_inm.inm_ifp = NULL ; /* don't send the leave msg */
if (ifma->ifma_refcount == 1) {
/*
@@ -1026,5 +1034,5 @@ in_delmulti(inm)
if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
if (my_inm.inm_ifp != NULL)
igmp_leavegroup(&my_inm);
- splx(s);
+ IN_MULTI_UNLOCK();
}
OpenPOWER on IntegriCloud