Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet6/in6_mcast.c
Show First 20 Lines • Show All 2,046 Lines • ▼ Show 20 Lines | in6p_join_group(struct inpcb *inp, struct sockopt *sopt) | ||||
/* | /* | ||||
* Always set the scope zone ID on memberships created from userland. | * Always set the scope zone ID on memberships created from userland. | ||||
* Use the passed-in ifp to do this. | * Use the passed-in ifp to do this. | ||||
* XXX The in6_setscope() return value is meaningless. | * XXX The in6_setscope() return value is meaningless. | ||||
* XXX SCOPE6_LOCK() is taken by in6_setscope(). | * XXX SCOPE6_LOCK() is taken by in6_setscope(). | ||||
*/ | */ | ||||
(void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL); | (void)in6_setscope(&gsa->sin6.sin6_addr, ifp, NULL); | ||||
IN6_MULTI_LOCK(); | |||||
imo = in6p_findmoptions(inp); | imo = in6p_findmoptions(inp); | ||||
idx = im6o_match_group(imo, ifp, &gsa->sa); | idx = im6o_match_group(imo, ifp, &gsa->sa); | ||||
if (idx == -1) { | if (idx == -1) { | ||||
is_new = 1; | is_new = 1; | ||||
} else { | } else { | ||||
inm = imo->im6o_membership[idx]; | inm = imo->im6o_membership[idx]; | ||||
imf = &imo->im6o_mfilters[idx]; | imf = &imo->im6o_mfilters[idx]; | ||||
if (ssa->ss.ss_family != AF_UNSPEC) { | if (ssa->ss.ss_family != AF_UNSPEC) { | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | if (is_new) { | ||||
CTR1(KTR_MLD, "%s: new join w/o source", __func__); | CTR1(KTR_MLD, "%s: new join w/o source", __func__); | ||||
im6f_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); | im6f_init(imf, MCAST_UNDEFINED, MCAST_EXCLUDE); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Begin state merge transaction at MLD layer. | * Begin state merge transaction at MLD layer. | ||||
*/ | */ | ||||
in_pcbref(inp); | |||||
INP_WUNLOCK(inp); | |||||
IN6_MULTI_LOCK(); | |||||
if (is_new) { | if (is_new) { | ||||
error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf, | error = in6_joingroup_locked(ifp, &gsa->sin6.sin6_addr, imf, | ||||
&inm, 0); | &inm, 0); | ||||
if (error) { | if (error) { | ||||
IN6_MULTI_UNLOCK(); | IN6_MULTI_UNLOCK(); | ||||
goto out_im6o_free; | goto out_im6o_free; | ||||
} | } | ||||
/* | /* | ||||
Show All 13 Lines | else { | ||||
error = mld_change_state(inm, 0); | error = mld_change_state(inm, 0); | ||||
if (error) | if (error) | ||||
CTR1(KTR_MLD, "%s: failed mld downcall", | CTR1(KTR_MLD, "%s: failed mld downcall", | ||||
__func__); | __func__); | ||||
} | } | ||||
IN6_MULTI_LIST_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
} | } | ||||
IN6_MULTI_UNLOCK(); | |||||
INP_WLOCK(inp); | |||||
if (in_pcbrele_wlocked(inp)) | |||||
return (ENXIO); | |||||
if (error) { | if (error) { | ||||
im6f_rollback(imf); | im6f_rollback(imf); | ||||
if (is_new) | if (is_new) | ||||
im6f_purge(imf); | im6f_purge(imf); | ||||
else | else | ||||
im6f_reap(imf); | im6f_reap(imf); | ||||
} else { | } else { | ||||
im6f_commit(imf); | im6f_commit(imf); | ||||
} | } | ||||
out_im6o_free: | out_im6o_free: | ||||
if (error && is_new) { | if (error && is_new) { | ||||
inm = imo->im6o_membership[idx]; | inm = imo->im6o_membership[idx]; | ||||
if (inm != NULL) { | if (inm != NULL) { | ||||
IN6_MULTI_LIST_LOCK(); | IN6_MULTI_LIST_LOCK(); | ||||
in6m_rele_locked(&inmh, inm); | in6m_rele_locked(&inmh, inm); | ||||
IN6_MULTI_LIST_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
} | } | ||||
imo->im6o_membership[idx] = NULL; | imo->im6o_membership[idx] = NULL; | ||||
--imo->im6o_num_memberships; | --imo->im6o_num_memberships; | ||||
} | } | ||||
out_in6p_locked: | out_in6p_locked: | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
IN6_MULTI_UNLOCK(); | |||||
in6m_release_list_deferred(&inmh); | in6m_release_list_deferred(&inmh); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Leave an IPv6 multicast group on an inpcb, possibly with a source. | * Leave an IPv6 multicast group on an inpcb, possibly with a source. | ||||
*/ | */ | ||||
static int | static int | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | #endif | ||||
} | } | ||||
CTR2(KTR_MLD, "%s: ifp = %p", __func__, ifp); | CTR2(KTR_MLD, "%s: ifp = %p", __func__, ifp); | ||||
KASSERT(ifp != NULL, ("%s: ifp did not resolve", __func__)); | KASSERT(ifp != NULL, ("%s: ifp did not resolve", __func__)); | ||||
/* | /* | ||||
* Find the membership in the membership array. | * Find the membership in the membership array. | ||||
*/ | */ | ||||
IN6_MULTI_LOCK(); | |||||
imo = in6p_findmoptions(inp); | imo = in6p_findmoptions(inp); | ||||
idx = im6o_match_group(imo, ifp, &gsa->sa); | idx = im6o_match_group(imo, ifp, &gsa->sa); | ||||
if (idx == -1) { | if (idx == -1) { | ||||
error = EADDRNOTAVAIL; | error = EADDRNOTAVAIL; | ||||
goto out_in6p_locked; | goto out_in6p_locked; | ||||
} | } | ||||
inm = imo->im6o_membership[idx]; | inm = imo->im6o_membership[idx]; | ||||
imf = &imo->im6o_mfilters[idx]; | imf = &imo->im6o_mfilters[idx]; | ||||
Show All 32 Lines | if (error) { | ||||
__func__); | __func__); | ||||
goto out_in6p_locked; | goto out_in6p_locked; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Begin state merge transaction at MLD layer. | * Begin state merge transaction at MLD layer. | ||||
*/ | */ | ||||
in_pcbref(inp); | |||||
INP_WUNLOCK(inp); | |||||
IN6_MULTI_LOCK(); | |||||
if (is_final) { | if (is_final) { | ||||
/* | /* | ||||
* Give up the multicast address record to which | * Give up the multicast address record to which | ||||
* the membership points. | * the membership points. | ||||
*/ | */ | ||||
(void)in6_leavegroup_locked(inm, imf); | (void)in6_leavegroup_locked(inm, imf); | ||||
} else { | } else { | ||||
CTR1(KTR_MLD, "%s: merge inm state", __func__); | CTR1(KTR_MLD, "%s: merge inm state", __func__); | ||||
IN6_MULTI_LIST_LOCK(); | IN6_MULTI_LIST_LOCK(); | ||||
error = in6m_merge(inm, imf); | error = in6m_merge(inm, imf); | ||||
if (error) | if (error) | ||||
CTR1(KTR_MLD, "%s: failed to merge inm state", | CTR1(KTR_MLD, "%s: failed to merge inm state", | ||||
__func__); | __func__); | ||||
else { | else { | ||||
CTR1(KTR_MLD, "%s: doing mld downcall", __func__); | CTR1(KTR_MLD, "%s: doing mld downcall", __func__); | ||||
error = mld_change_state(inm, 0); | error = mld_change_state(inm, 0); | ||||
if (error) | if (error) | ||||
CTR1(KTR_MLD, "%s: failed mld downcall", | CTR1(KTR_MLD, "%s: failed mld downcall", | ||||
__func__); | __func__); | ||||
} | } | ||||
IN6_MULTI_LIST_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
} | } | ||||
IN6_MULTI_UNLOCK(); | |||||
INP_WLOCK(inp); | |||||
if (in_pcbrele_wlocked(inp)) | |||||
return (ENXIO); | |||||
if (error) | if (error) | ||||
im6f_rollback(imf); | im6f_rollback(imf); | ||||
else | else | ||||
im6f_commit(imf); | im6f_commit(imf); | ||||
im6f_reap(imf); | im6f_reap(imf); | ||||
if (is_final) { | if (is_final) { | ||||
/* Remove the gap in the membership array. */ | /* Remove the gap in the membership array. */ | ||||
KASSERT(RB_EMPTY(&imf->im6f_sources), | KASSERT(RB_EMPTY(&imf->im6f_sources), | ||||
("%s: im6f_sources not empty", __func__)); | ("%s: im6f_sources not empty", __func__)); | ||||
for (++idx; idx < imo->im6o_num_memberships; ++idx) { | for (++idx; idx < imo->im6o_num_memberships; ++idx) { | ||||
imo->im6o_membership[idx - 1] = imo->im6o_membership[idx]; | imo->im6o_membership[idx - 1] = imo->im6o_membership[idx]; | ||||
imo->im6o_mfilters[idx - 1] = imo->im6o_mfilters[idx]; | imo->im6o_mfilters[idx - 1] = imo->im6o_mfilters[idx]; | ||||
} | } | ||||
im6f_init(&imo->im6o_mfilters[idx - 1], MCAST_UNDEFINED, | im6f_init(&imo->im6o_mfilters[idx - 1], MCAST_UNDEFINED, | ||||
MCAST_EXCLUDE); | MCAST_EXCLUDE); | ||||
imo->im6o_num_memberships--; | imo->im6o_num_memberships--; | ||||
} | } | ||||
out_in6p_locked: | out_in6p_locked: | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
IN6_MULTI_UNLOCK(); | |||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Select the interface for transmitting IPv6 multicast datagrams. | * Select the interface for transmitting IPv6 multicast datagrams. | ||||
* | * | ||||
* Either an instance of struct in6_addr or an instance of struct ipv6_mreqn | * Either an instance of struct in6_addr or an instance of struct ipv6_mreqn | ||||
* may be passed to this socket option. An address of in6addr_any or an | * may be passed to this socket option. An address of in6addr_any or an | ||||
Show All 29 Lines | in6p_set_multicast_if(struct inpcb *inp, struct sockopt *sopt) | ||||
imo->im6o_multicast_ifp = ifp; | imo->im6o_multicast_ifp = ifp; | ||||
INP_WUNLOCK(inp); | INP_WUNLOCK(inp); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Atomically set source filters on a socket for an IPv6 multicast group. | * Atomically set source filters on a socket for an IPv6 multicast group. | ||||
* | |||||
* SMPng: NOTE: Potentially calls malloc(M_WAITOK) with Giant held. | |||||
*/ | */ | ||||
static int | static int | ||||
in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) | in6p_set_source_filters(struct inpcb *inp, struct sockopt *sopt) | ||||
{ | { | ||||
struct __msfilterreq msfr; | struct __msfilterreq msfr; | ||||
sockunion_t *gsa; | sockunion_t *gsa; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct in6_mfilter *imf; | struct in6_mfilter *imf; | ||||
▲ Show 20 Lines • Show All 459 Lines • Show Last 20 Lines |