diff options
author | Mark Johnston <markj@FreeBSD.org> | 2019-05-16 13:04:26 +0000 |
---|---|---|
committer | Mark Johnston <markj@FreeBSD.org> | 2019-05-16 13:04:26 +0000 |
commit | f00876fb601ad1bae791830cfa7a7079a4fc0d79 (patch) | |
tree | 35b78a6844943532251c5339b1755bdcf362b95f | |
parent | 0ddfdc60f80c93c8a2df986e246c92cfdd011bf0 (diff) | |
download | src-f00876fb601ad1bae791830cfa7a7079a4fc0d79.tar.gz src-f00876fb601ad1bae791830cfa7a7079a4fc0d79.zip |
Notes
-rw-r--r-- | sys/netinet/in_mcast.c | 60 | ||||
-rw-r--r-- | sys/netinet6/in6_mcast.c | 23 |
2 files changed, 59 insertions, 24 deletions
diff --git a/sys/netinet/in_mcast.c b/sys/netinet/in_mcast.c index f07c2aa7bc32..2980c1a463ca 100644 --- a/sys/netinet/in_mcast.c +++ b/sys/netinet/in_mcast.c @@ -1534,7 +1534,6 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) /* * Check if we are actually a member of this group. */ - IN_MULTI_LOCK(); imo = inp_findmoptions(inp); idx = imo_match_group(imo, ifp, &gsa->sa); if (idx == -1 || imo->imo_mfilters == NULL) { @@ -1594,13 +1593,14 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ + IN_MULTI_LOCK(); CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); IN_MULTI_LIST_LOCK(); error = inm_merge(inm, imf); if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -1609,6 +1609,9 @@ inp_block_unblock_source(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); +out_in_multi_locked: + + IN_MULTI_UNLOCK(); out_imf_rollback: if (error) imf_rollback(imf); @@ -1619,7 +1622,6 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); - IN_MULTI_UNLOCK(); return (error); } @@ -1678,10 +1680,10 @@ inp_findmoptions(struct inpcb *inp) static void inp_gcmoptions(struct ip_moptions *imo) { - struct in_mfilter *imf; + struct in_mfilter *imf; struct in_multi *inm; struct ifnet *ifp; - size_t idx, nmships; + size_t idx, nmships; nmships = imo->imo_num_memberships; for (idx = 0; idx < nmships; ++idx) { @@ -2140,12 +2142,12 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR2(KTR_IGMPV3, "%s: unknown sopt_name %d", __func__, sopt->sopt_name); return (EOPNOTSUPP); + break; } if (ifp == NULL || (ifp->if_flags & IFF_MULTICAST) == 0) return (EADDRNOTAVAIL); - IN_MULTI_LOCK(); imo = inp_findmoptions(inp); idx = imo_match_group(imo, ifp, &gsa->sa); if (idx == -1) { @@ -2270,6 +2272,10 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); + IN_MULTI_LOCK(); + if (is_new) { error = in_joingroup_locked(ifp, &gsa->sin.sin_addr, imf, &inm); @@ -2280,8 +2286,6 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) goto out_imo_free; } inm_acquire(inm); - KASSERT(imo->imo_membership[idx] == NULL, - ("%s: imo_membership already allocated", __func__)); imo->imo_membership[idx] = inm; } else { CTR1(KTR_IGMPV3, "%s: merge inm state", __func__); @@ -2291,7 +2295,7 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); error = igmp_change_state(inm); @@ -2299,11 +2303,16 @@ inp_join_group(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); - goto out_imf_rollback; + goto out_in_multi_locked; } } -out_imf_rollback: +out_in_multi_locked: + + IN_MULTI_UNLOCK(); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); if (error) { imf_rollback(imf); if (is_new) @@ -2328,7 +2337,6 @@ out_imo_free: out_inp_locked: INP_WUNLOCK(inp); - IN_MULTI_UNLOCK(); return (error); } @@ -2455,7 +2463,6 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Find the membership in the membership array. */ - IN_MULTI_LOCK(); imo = inp_findmoptions(inp); idx = imo_match_group(imo, ifp, &gsa->sa); if (idx == -1) { @@ -2503,6 +2510,9 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at IGMP layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); + IN_MULTI_LOCK(); if (is_final) { /* @@ -2518,7 +2528,7 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2530,7 +2540,13 @@ inp_leave_group(struct inpcb *inp, struct sockopt *sopt) } } -out_imf_rollback: +out_in_multi_locked: + + IN_MULTI_UNLOCK(); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); + if (error) imf_rollback(imf); else @@ -2541,7 +2557,7 @@ out_imf_rollback: if (is_final) { /* Remove the gap in the membership and filter array. */ KASSERT(RB_EMPTY(&imf->imf_sources), - ("%s: imf_sources (%p %p %zu) not empty", __func__, imf, imo, idx)); + ("%s: imf_sources not empty", __func__)); for (++idx; idx < imo->imo_num_memberships; ++idx) { imo->imo_membership[idx - 1] = imo->imo_membership[idx]; imo->imo_mfilters[idx - 1] = imo->imo_mfilters[idx]; @@ -2553,7 +2569,6 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); - IN_MULTI_UNLOCK(); return (error); } @@ -2631,6 +2646,8 @@ inp_set_multicast_if(struct inpcb *inp, struct sockopt *sopt) /* * Atomically set source filters on a socket for an IPv4 multicast group. + * + * SMPng: NOTE: Potentially calls malloc(M_WAITOK) with Giant held. */ static int inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) @@ -2677,7 +2694,6 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) * Take the INP write lock. * Check if this socket is a member of this group. */ - IN_MULTI_LOCK(); imo = inp_findmoptions(inp); idx = imo_match_group(imo, ifp, &gsa->sa); if (idx == -1 || imo->imo_mfilters == NULL) { @@ -2762,6 +2778,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) goto out_imf_rollback; INP_WLOCK_ASSERT(inp); + IN_MULTI_LOCK(); /* * Begin state merge transaction at IGMP layer. @@ -2772,7 +2789,7 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) { CTR1(KTR_IGMPV3, "%s: failed to merge inm state", __func__); IN_MULTI_LIST_UNLOCK(); - goto out_imf_rollback; + goto out_in_multi_locked; } CTR1(KTR_IGMPV3, "%s: doing igmp downcall", __func__); @@ -2781,6 +2798,10 @@ inp_set_source_filters(struct inpcb *inp, struct sockopt *sopt) if (error) CTR1(KTR_IGMPV3, "%s: failed igmp downcall", __func__); +out_in_multi_locked: + + IN_MULTI_UNLOCK(); + out_imf_rollback: if (error) imf_rollback(imf); @@ -2791,7 +2812,6 @@ out_imf_rollback: out_inp_locked: INP_WUNLOCK(inp); - IN_MULTI_UNLOCK(); return (error); } diff --git a/sys/netinet6/in6_mcast.c b/sys/netinet6/in6_mcast.c index c0e6d2dcb650..5557a7c76564 100644 --- a/sys/netinet6/in6_mcast.c +++ b/sys/netinet6/in6_mcast.c @@ -2052,7 +2052,6 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) */ (void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL); - IN6_MULTI_LOCK(); imo = in6p_findmoptions(inp); idx = im6o_match_group(imo, ifp, &gsa->sa); if (idx == -1) { @@ -2172,6 +2171,10 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); + IN6_MULTI_LOCK(); + if (is_new) { error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf, &inm, 0); @@ -2201,6 +2204,10 @@ in6p_join_group(struct inpcb *inp, struct sockopt *sopt) IN6_MULTI_LIST_UNLOCK(); } + IN6_MULTI_UNLOCK(); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); if (error) { im6f_rollback(imf); if (is_new) @@ -2225,7 +2232,6 @@ out_im6o_free: out_in6p_locked: INP_WUNLOCK(inp); - IN6_MULTI_UNLOCK(); in6m_release_list_deferred(&inmh); return (error); } @@ -2375,7 +2381,6 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Find the membership in the membership array. */ - IN6_MULTI_LOCK(); imo = in6p_findmoptions(inp); idx = im6o_match_group(imo, ifp, &gsa->sa); if (idx == -1) { @@ -2424,6 +2429,10 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) /* * Begin state merge transaction at MLD layer. */ + in_pcbref(inp); + INP_WUNLOCK(inp); + IN6_MULTI_LOCK(); + if (is_final) { /* * Give up the multicast address record to which @@ -2447,6 +2456,11 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) IN6_MULTI_LIST_UNLOCK(); } + IN6_MULTI_UNLOCK(); + INP_WLOCK(inp); + if (in_pcbrele_wlocked(inp)) + return (ENXIO); + if (error) im6f_rollback(imf); else @@ -2469,7 +2483,6 @@ in6p_leave_group(struct inpcb *inp, struct sockopt *sopt) out_in6p_locked: INP_WUNLOCK(inp); - IN6_MULTI_UNLOCK(); return (error); } @@ -2515,6 +2528,8 @@ in6p_set_multicast_if(struct inpcb *inp, struct sockopt *sopt) /* * Atomically set source filters on a socket for an IPv6 multicast group. + * + * SMPng: NOTE: Potentially calls malloc(M_WAITOK) with Giant held. */ static int in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) |