diff --git a/sys/netinet/ip_mroute.c b/sys/netinet/ip_mroute.c --- a/sys/netinet/ip_mroute.c +++ b/sys/netinet/ip_mroute.c @@ -317,7 +317,7 @@ static int del_bw_upcall(struct bw_upcall *); static int del_mfc(struct mfcctl2 *); static int del_vif(vifi_t); -static int del_vif_locked(vifi_t, struct ifnet **); +static int del_vif_locked(vifi_t, struct ifnet **, struct ifnet **); static void expire_bw_upcalls_send(void *); static void expire_mfc(struct mfc *); static void expire_upcalls(void *); @@ -618,7 +618,7 @@ { vifi_t vifi; u_long i, vifi_cnt = 0; - struct ifnet *free_ptr; + struct ifnet *free_ptr, *multi_leave; MRW_WLOCK(); @@ -635,6 +635,7 @@ * 3. Expire any matching multicast forwarding cache entries. * 4. Free vif state. This should disable ALLMULTI on the interface. */ +restart: for (vifi = 0; vifi < V_numvifs; vifi++) { if (V_viftable[vifi].v_ifp != ifp) continue; @@ -647,9 +648,15 @@ } } } - del_vif_locked(vifi, &free_ptr); + del_vif_locked(vifi, &multi_leave, &free_ptr); if (free_ptr != NULL) vifi_cnt++; + if (multi_leave) { + MRW_WUNLOCK(); + if_allmulti(multi_leave, 0); + MRW_WLOCK(); + goto restart; + } } MRW_WUNLOCK(); @@ -998,11 +1005,12 @@ * Delete a vif from the vif table */ static int -del_vif_locked(vifi_t vifi, struct ifnet **ifp_free) +del_vif_locked(vifi_t vifi, struct ifnet **ifp_multi_leave, struct ifnet **ifp_free) { struct vif *vifp; *ifp_free = NULL; + *ifp_multi_leave = NULL; MRW_WLOCK_ASSERT(); @@ -1015,7 +1023,7 @@ } if (!(vifp->v_flags & (VIFF_TUNNEL | VIFF_REGISTER))) - if_allmulti(vifp->v_ifp, 0); + *ifp_multi_leave = vifp->v_ifp; if (vifp->v_flags & VIFF_REGISTER) { V_reg_vif_num = VIFI_INVALID; @@ -1045,14 +1053,17 @@ del_vif(vifi_t vifi) { int cc; - struct ifnet *free_ptr; + struct ifnet *free_ptr, *multi_leave; MRW_WLOCK(); - cc = del_vif_locked(vifi, &free_ptr); + cc = del_vif_locked(vifi, &multi_leave, &free_ptr); MRW_WUNLOCK(); - if (free_ptr) + if (multi_leave) + if_allmulti(multi_leave, 0); + if (free_ptr) { if_free(free_ptr); + } return cc; }