sys/netinet/ip_mroute.c | 11 ++++++++---
sys/netinet/ip_mroute.h | 4 +++-
sys/netinet/raw_ip.c | 11 ++++++++---
3 files changed, 19 insertions(+), 7 deletions(-)
diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c
index 8cd0b2ac7449..0566048621ad 100644
--- a/sys/netinet/ip_mroute.c
+++ b/sys/netinet/ip_mroute.c
@@ -300,7 +300,7 @@ VNET_DEFINE_STATIC(struct ifnet *,
multicast_register_if);
static u_long X_ip_mcast_src(int);
static int X_ip_mforward(struct ip *, struct ifnet *, struct mbuf *,
struct ip_moptions *);
-static int X_ip_mrouter_done(void);
+static int X_ip_mrouter_done(void *);
static int X_ip_mrouter_get(struct socket *, struct sockopt *);
static int X_ip_mrouter_set(struct socket *, struct sockopt *);
static int X_legal_vif_num(int);
@@ -431,7 +431,7 @@ X_ip_mrouter_set(struct socket *so, struct
sockopt *sopt)
break;
case MRT_DONE:
- error = ip_mrouter_done();
+ error = ip_mrouter_done(NULL);
break;
case MRT_ADD_VIF:
@@ -734,7 +734,7 @@ ip_mrouter_init(struct socket *so, int version)
* Disable multicast forwarding.
*/
static int
-X_ip_mrouter_done(void)
+X_ip_mrouter_done(void *locked)
{
struct ifnet *ifp;
u_long i;
@@ -751,6 +751,11 @@ X_ip_mrouter_done(void)
atomic_subtract_int(&ip_mrouter_cnt, 1);
V_mrt_api_config = 0;
+ if (locked) {
+ struct epoch_tracker *mrouter_et = locked;
+ MROUTER_RUNLOCK_PARAM(mrouter_et);
+ }
+
MROUTER_WAIT();
/* Stop and drain task queue */
diff --git a/sys/netinet/ip_mroute.h b/sys/netinet/ip_mroute.h
index 65c5bdd3a025..016d026d184c 100644
--- a/sys/netinet/ip_mroute.h
+++ b/sys/netinet/ip_mroute.h
@@ -363,12 +363,14 @@ struct sockopt;
extern int (*ip_mrouter_set)(struct socket *, struct sockopt *);
extern int (*ip_mrouter_get)(struct socket *, struct sockopt *);
-extern int (*ip_mrouter_done)(void);
+extern int (*ip_mrouter_done)(void *);
extern int (*mrt_ioctl)(u_long, caddr_t, int);
#define MROUTER_RLOCK_TRACKER struct epoch_tracker mrouter_et
+#define MROUTER_RLOCK_PARAM_PTR &mrouter_et
#define MROUTER_RLOCK() epoch_enter_preempt(net_epoch_preempt,
&mrouter_et)
#define MROUTER_RUNLOCK() epoch_exit_preempt(net_epoch_preempt,
&mrouter_et)
+#define MROUTER_RUNLOCK_PARAM(param) epoch_exit_preempt(net_epoch_preempt,
param)
#define MROUTER_WAIT() epoch_wait_preempt(net_epoch_preempt)
#endif /* _KERNEL */
diff --git a/sys/netinet/raw_ip.c b/sys/netinet/raw_ip.c
index 7c495745806e..08ce848a63f7 100644
--- a/sys/netinet/raw_ip.c
+++ b/sys/netinet/raw_ip.c
@@ -119,7 +119,7 @@ VNET_DEFINE(struct socket *, ip_mrouter);
*/
int (*ip_mrouter_set)(struct socket *, struct sockopt *);
int (*ip_mrouter_get)(struct socket *, struct sockopt *);
-int (*ip_mrouter_done)(void);
+int (*ip_mrouter_done)(void *locked);
int (*ip_mforward)(struct ip *, struct ifnet *, struct mbuf *,
struct ip_moptions *);
int (*mrt_ioctl)(u_long, caddr_t, int);
@@ -879,18 +879,23 @@ static void
rip_detach(struct socket *so)
{
struct inpcb *inp;
+ MROUTER_RLOCK_TRACKER;
inp = sotoinpcb(so);
KASSERT(inp != NULL, ("rip_detach: inp == NULL"));
KASSERT(inp->inp_faddr.s_addr == INADDR_ANY,
("rip_detach: not closed"));
+ /* Disable mrouter first, lock released inside ip_mrouter_done */
+ MROUTER_RLOCK();
+ if (so == V_ip_mrouter && ip_mrouter_done)
+ ip_mrouter_done(MROUTER_RLOCK_PARAM_PTR);
+