Changeset View
Changeset View
Standalone View
Standalone View
head/sys/netinet6/mld6.c
Show First 20 Lines • Show All 118 Lines • ▼ Show 20 Lines | |||||
static char * mld_rec_type_to_str(const int); | static char * mld_rec_type_to_str(const int); | ||||
#endif | #endif | ||||
static void mld_set_version(struct mld_ifsoftc *, const int); | static void mld_set_version(struct mld_ifsoftc *, const int); | ||||
static void mld_slowtimo_vnet(void); | static void mld_slowtimo_vnet(void); | ||||
static int mld_v1_input_query(struct ifnet *, const struct ip6_hdr *, | static int mld_v1_input_query(struct ifnet *, const struct ip6_hdr *, | ||||
/*const*/ struct mld_hdr *); | /*const*/ struct mld_hdr *); | ||||
static int mld_v1_input_report(struct ifnet *, const struct ip6_hdr *, | static int mld_v1_input_report(struct ifnet *, const struct ip6_hdr *, | ||||
/*const*/ struct mld_hdr *); | /*const*/ struct mld_hdr *); | ||||
static void mld_v1_process_group_timer(struct mld_ifsoftc *, | static void mld_v1_process_group_timer(struct in6_multi_head *, | ||||
struct in6_multi *); | struct in6_multi *); | ||||
static void mld_v1_process_querier_timers(struct mld_ifsoftc *); | static void mld_v1_process_querier_timers(struct mld_ifsoftc *); | ||||
static int mld_v1_transmit_report(struct in6_multi *, const int); | static int mld_v1_transmit_report(struct in6_multi *, const int); | ||||
static void mld_v1_update_group(struct in6_multi *, const int); | static void mld_v1_update_group(struct in6_multi *, const int); | ||||
static void mld_v2_cancel_link_timers(struct mld_ifsoftc *); | static void mld_v2_cancel_link_timers(struct mld_ifsoftc *); | ||||
static void mld_v2_dispatch_general_query(struct mld_ifsoftc *); | static void mld_v2_dispatch_general_query(struct mld_ifsoftc *); | ||||
static struct mbuf * | static struct mbuf * | ||||
mld_v2_encap_report(struct ifnet *, struct mbuf *); | mld_v2_encap_report(struct ifnet *, struct mbuf *); | ||||
static int mld_v2_enqueue_filter_change(struct mbufq *, | static int mld_v2_enqueue_filter_change(struct mbufq *, | ||||
struct in6_multi *); | struct in6_multi *); | ||||
static int mld_v2_enqueue_group_record(struct mbufq *, | static int mld_v2_enqueue_group_record(struct mbufq *, | ||||
struct in6_multi *, const int, const int, const int, | struct in6_multi *, const int, const int, const int, | ||||
const int); | const int); | ||||
static int mld_v2_input_query(struct ifnet *, const struct ip6_hdr *, | static int mld_v2_input_query(struct ifnet *, const struct ip6_hdr *, | ||||
struct mbuf *, const int, const int); | struct mbuf *, const int, const int); | ||||
static int mld_v2_merge_state_changes(struct in6_multi *, | static int mld_v2_merge_state_changes(struct in6_multi *, | ||||
struct mbufq *); | struct mbufq *); | ||||
static void mld_v2_process_group_timers(struct mld_ifsoftc *, | static void mld_v2_process_group_timers(struct in6_multi_head *, | ||||
struct mbufq *, struct mbufq *, | struct mbufq *, struct mbufq *, | ||||
struct in6_multi *, const int); | struct in6_multi *, const int); | ||||
static int mld_v2_process_group_query(struct in6_multi *, | static int mld_v2_process_group_query(struct in6_multi *, | ||||
struct mld_ifsoftc *mli, int, struct mbuf *, const int); | struct mld_ifsoftc *mli, int, struct mbuf *, const int); | ||||
static int sysctl_mld_gsr(SYSCTL_HANDLER_ARGS); | static int sysctl_mld_gsr(SYSCTL_HANDLER_ARGS); | ||||
static int sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS); | static int sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS); | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 218 Lines • ▼ Show 20 Lines | sysctl_mld_ifinfo(SYSCTL_HANDLER_ARGS) | ||||
if (namelen != 1) | if (namelen != 1) | ||||
return (EINVAL); | return (EINVAL); | ||||
error = sysctl_wire_old_buffer(req, sizeof(struct mld_ifinfo)); | error = sysctl_wire_old_buffer(req, sizeof(struct mld_ifinfo)); | ||||
if (error) | if (error) | ||||
return (error); | return (error); | ||||
IN6_MULTI_LOCK(); | IN6_MULTI_LOCK(); | ||||
IN6_MULTI_LIST_LOCK(); | |||||
MLD_LOCK(); | MLD_LOCK(); | ||||
if (name[0] <= 0 || name[0] > V_if_index) { | if (name[0] <= 0 || name[0] > V_if_index) { | ||||
error = ENOENT; | error = ENOENT; | ||||
goto out_locked; | goto out_locked; | ||||
} | } | ||||
error = ENOENT; | error = ENOENT; | ||||
Show All 16 Lines | if (ifp == mli->mli_ifp) { | ||||
info.mli_uri = mli->mli_uri; | info.mli_uri = mli->mli_uri; | ||||
error = SYSCTL_OUT(req, &info, sizeof(info)); | error = SYSCTL_OUT(req, &info, sizeof(info)); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
out_locked: | out_locked: | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_LIST_UNLOCK(); | |||||
IN6_MULTI_UNLOCK(); | IN6_MULTI_UNLOCK(); | ||||
return (error); | return (error); | ||||
} | } | ||||
/* | /* | ||||
* Dispatch an entire queue of pending packet chains. | * Dispatch an entire queue of pending packet chains. | ||||
* VIMAGE: Assumes the vnet pointer has been set. | * VIMAGE: Assumes the vnet pointer has been set. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 83 Lines • ▼ Show 20 Lines | mli_alloc_locked(/*const*/ struct ifnet *ifp) | ||||
mli->mli_ifp = ifp; | mli->mli_ifp = ifp; | ||||
mli->mli_version = MLD_VERSION_2; | mli->mli_version = MLD_VERSION_2; | ||||
mli->mli_flags = 0; | mli->mli_flags = 0; | ||||
mli->mli_rv = MLD_RV_INIT; | mli->mli_rv = MLD_RV_INIT; | ||||
mli->mli_qi = MLD_QI_INIT; | mli->mli_qi = MLD_QI_INIT; | ||||
mli->mli_qri = MLD_QRI_INIT; | mli->mli_qri = MLD_QRI_INIT; | ||||
mli->mli_uri = MLD_URI_INIT; | mli->mli_uri = MLD_URI_INIT; | ||||
SLIST_INIT(&mli->mli_relinmhead); | |||||
mbufq_init(&mli->mli_gq, MLD_MAX_RESPONSE_PACKETS); | mbufq_init(&mli->mli_gq, MLD_MAX_RESPONSE_PACKETS); | ||||
LIST_INSERT_HEAD(&V_mli_head, mli, mli_link); | LIST_INSERT_HEAD(&V_mli_head, mli, mli_link); | ||||
CTR2(KTR_MLD, "allocate mld_ifsoftc for ifp %p(%s)", | CTR2(KTR_MLD, "allocate mld_ifsoftc for ifp %p(%s)", | ||||
ifp, if_name(ifp)); | ifp, if_name(ifp)); | ||||
out: | out: | ||||
Show All 11 Lines | |||||
* Must take IF_ADDR_LOCK() to cover if_multiaddrs iterator. | * Must take IF_ADDR_LOCK() to cover if_multiaddrs iterator. | ||||
* XXX This routine is also bitten by unlocked ifma_protospec access. | * XXX This routine is also bitten by unlocked ifma_protospec access. | ||||
*/ | */ | ||||
void | void | ||||
mld_ifdetach(struct ifnet *ifp) | mld_ifdetach(struct ifnet *ifp) | ||||
{ | { | ||||
struct mld_ifsoftc *mli; | struct mld_ifsoftc *mli; | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct in6_multi *inm, *tinm; | struct in6_multi *inm; | ||||
struct in6_multi_head inmh; | |||||
CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp, | CTR3(KTR_MLD, "%s: called for ifp %p(%s)", __func__, ifp, | ||||
if_name(ifp)); | if_name(ifp)); | ||||
IN6_MULTI_LOCK_ASSERT(); | SLIST_INIT(&inmh); | ||||
IN6_MULTI_LIST_LOCK_ASSERT(); | |||||
MLD_LOCK(); | MLD_LOCK(); | ||||
mli = MLD_IFINFO(ifp); | mli = MLD_IFINFO(ifp); | ||||
if (mli->mli_version == MLD_VERSION_2) { | if (mli->mli_version == MLD_VERSION_2) { | ||||
IF_ADDR_RLOCK(ifp); | IF_ADDR_RLOCK(ifp); | ||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | ||||
if (ifma->ifma_addr->sa_family != AF_INET6 || | if (ifma->ifma_addr->sa_family != AF_INET6 || | ||||
ifma->ifma_protospec == NULL) | ifma->ifma_protospec == NULL) | ||||
continue; | continue; | ||||
inm = (struct in6_multi *)ifma->ifma_protospec; | inm = (struct in6_multi *)ifma->ifma_protospec; | ||||
if (inm->in6m_state == MLD_LEAVING_MEMBER) { | if (inm->in6m_state == MLD_LEAVING_MEMBER) { | ||||
SLIST_INSERT_HEAD(&mli->mli_relinmhead, | in6m_rele_locked(&inmh, inm); | ||||
inm, in6m_nrele); | ifma->ifma_protospec = NULL; | ||||
} | } | ||||
in6m_clear_recorded(inm); | in6m_clear_recorded(inm); | ||||
} | } | ||||
IF_ADDR_RUNLOCK(ifp); | IF_ADDR_RUNLOCK(ifp); | ||||
SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, in6m_nrele, | |||||
tinm) { | |||||
SLIST_REMOVE_HEAD(&mli->mli_relinmhead, in6m_nrele); | |||||
in6m_release_locked(inm); | |||||
} | } | ||||
} | |||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
in6m_release_list_deferred(&inmh); | |||||
} | } | ||||
/* | /* | ||||
* Hook for domifdetach. | * Hook for domifdetach. | ||||
* Runs after link-layer cleanup; free MLD state. | * Runs after link-layer cleanup; free MLD state. | ||||
* | * | ||||
* SMPng: Normally called with IF_AFDATA_LOCK held. | * SMPng: Normally called with IF_AFDATA_LOCK held. | ||||
*/ | */ | ||||
Show All 23 Lines | LIST_FOREACH_SAFE(mli, &V_mli_head, mli_link, tmli) { | ||||
if (mli->mli_ifp == ifp) { | if (mli->mli_ifp == ifp) { | ||||
/* | /* | ||||
* Free deferred General Query responses. | * Free deferred General Query responses. | ||||
*/ | */ | ||||
mbufq_drain(&mli->mli_gq); | mbufq_drain(&mli->mli_gq); | ||||
LIST_REMOVE(mli, mli_link); | LIST_REMOVE(mli, mli_link); | ||||
KASSERT(SLIST_EMPTY(&mli->mli_relinmhead), | |||||
("%s: there are dangling in_multi references", | |||||
__func__)); | |||||
free(mli, M_MLD); | free(mli, M_MLD); | ||||
return; | return; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Process a received MLDv1 general or address-specific query. | * Process a received MLDv1 general or address-specific query. | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | #endif | ||||
} else { | } else { | ||||
/* | /* | ||||
* Embed scope ID of receiving interface in MLD query for | * Embed scope ID of receiving interface in MLD query for | ||||
* lookup whilst we don't hold other locks. | * lookup whilst we don't hold other locks. | ||||
*/ | */ | ||||
in6_setscope(&mld->mld_addr, ifp, NULL); | in6_setscope(&mld->mld_addr, ifp, NULL); | ||||
} | } | ||||
IN6_MULTI_LOCK(); | IN6_MULTI_LIST_LOCK(); | ||||
MLD_LOCK(); | MLD_LOCK(); | ||||
/* | /* | ||||
* Switch to MLDv1 host compatibility mode. | * Switch to MLDv1 host compatibility mode. | ||||
*/ | */ | ||||
mli = MLD_IFINFO(ifp); | mli = MLD_IFINFO(ifp); | ||||
KASSERT(mli != NULL, ("%s: no mld_ifsoftc for ifp %p", __func__, ifp)); | KASSERT(mli != NULL, ("%s: no mld_ifsoftc for ifp %p", __func__, ifp)); | ||||
mld_set_version(mli, MLD_VERSION_1); | mld_set_version(mli, MLD_VERSION_1); | ||||
Show All 31 Lines | if (inm != NULL) { | ||||
mld_v1_update_group(inm, timer); | mld_v1_update_group(inm, timer); | ||||
} | } | ||||
/* XXX Clear embedded scope ID as userland won't expect it. */ | /* XXX Clear embedded scope ID as userland won't expect it. */ | ||||
in6_clearscope(&mld->mld_addr); | in6_clearscope(&mld->mld_addr); | ||||
} | } | ||||
IF_ADDR_RUNLOCK(ifp); | IF_ADDR_RUNLOCK(ifp); | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Update the report timer on a group in response to an MLDv1 query. | * Update the report timer on a group in response to an MLDv1 query. | ||||
* | * | ||||
* If we are becoming the reporting member for this group, start the timer. | * If we are becoming the reporting member for this group, start the timer. | ||||
Show All 14 Lines | |||||
#ifdef KTR | #ifdef KTR | ||||
char ip6tbuf[INET6_ADDRSTRLEN]; | char ip6tbuf[INET6_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
CTR4(KTR_MLD, "%s: %s/%s timer=%d", __func__, | CTR4(KTR_MLD, "%s: %s/%s timer=%d", __func__, | ||||
ip6_sprintf(ip6tbuf, &inm->in6m_addr), | ip6_sprintf(ip6tbuf, &inm->in6m_addr), | ||||
if_name(inm->in6m_ifp), timer); | if_name(inm->in6m_ifp), timer); | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
switch (inm->in6m_state) { | switch (inm->in6m_state) { | ||||
case MLD_NOT_MEMBER: | case MLD_NOT_MEMBER: | ||||
case MLD_SILENT_MEMBER: | case MLD_SILENT_MEMBER: | ||||
break; | break; | ||||
case MLD_REPORTING_MEMBER: | case MLD_REPORTING_MEMBER: | ||||
if (inm->in6m_timer != 0 && | if (inm->in6m_timer != 0 && | ||||
inm->in6m_timer <= timer) { | inm->in6m_timer <= timer) { | ||||
▲ Show 20 Lines • Show All 106 Lines • ▼ Show 20 Lines | if (IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) { | ||||
/* | /* | ||||
* Embed scope ID of receiving interface in MLD query for | * Embed scope ID of receiving interface in MLD query for | ||||
* lookup whilst we don't hold other locks (due to KAME | * lookup whilst we don't hold other locks (due to KAME | ||||
* locking lameness). We own this mbuf chain just now. | * locking lameness). We own this mbuf chain just now. | ||||
*/ | */ | ||||
in6_setscope(&mld->mld_addr, ifp, NULL); | in6_setscope(&mld->mld_addr, ifp, NULL); | ||||
} | } | ||||
IN6_MULTI_LOCK(); | IN6_MULTI_LIST_LOCK(); | ||||
MLD_LOCK(); | MLD_LOCK(); | ||||
mli = MLD_IFINFO(ifp); | mli = MLD_IFINFO(ifp); | ||||
KASSERT(mli != NULL, ("%s: no mld_ifsoftc for ifp %p", __func__, ifp)); | KASSERT(mli != NULL, ("%s: no mld_ifsoftc for ifp %p", __func__, ifp)); | ||||
/* | /* | ||||
* Discard the v2 query if we're in Compatibility Mode. | * Discard the v2 query if we're in Compatibility Mode. | ||||
* The RFC is pretty clear that hosts need to stay in MLDv1 mode | * The RFC is pretty clear that hosts need to stay in MLDv1 mode | ||||
▲ Show 20 Lines • Show All 66 Lines • ▼ Show 20 Lines | if (is_general_query) { | ||||
/* XXX Clear embedded scope ID as userland won't expect it. */ | /* XXX Clear embedded scope ID as userland won't expect it. */ | ||||
in6_clearscope(&mld->mld_addr); | in6_clearscope(&mld->mld_addr); | ||||
IF_ADDR_RUNLOCK(ifp); | IF_ADDR_RUNLOCK(ifp); | ||||
} | } | ||||
out_locked: | out_locked: | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
* Process a received MLDv2 group-specific or group-and-source-specific | * Process a received MLDv2 group-specific or group-and-source-specific | ||||
* query. | * query. | ||||
* Return <0 if any error occurred. Currently this is ignored. | * Return <0 if any error occurred. Currently this is ignored. | ||||
*/ | */ | ||||
static int | static int | ||||
mld_v2_process_group_query(struct in6_multi *inm, struct mld_ifsoftc *mli, | mld_v2_process_group_query(struct in6_multi *inm, struct mld_ifsoftc *mli, | ||||
int timer, struct mbuf *m0, const int off) | int timer, struct mbuf *m0, const int off) | ||||
{ | { | ||||
struct mldv2_query *mld; | struct mldv2_query *mld; | ||||
int retval; | int retval; | ||||
uint16_t nsrc; | uint16_t nsrc; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
retval = 0; | retval = 0; | ||||
mld = (struct mldv2_query *)(mtod(m0, uint8_t *) + off); | mld = (struct mldv2_query *)(mtod(m0, uint8_t *) + off); | ||||
switch (inm->in6m_state) { | switch (inm->in6m_state) { | ||||
case MLD_NOT_MEMBER: | case MLD_NOT_MEMBER: | ||||
case MLD_SILENT_MEMBER: | case MLD_SILENT_MEMBER: | ||||
▲ Show 20 Lines • Show All 168 Lines • ▼ Show 20 Lines | #endif | ||||
/* | /* | ||||
* Embed scope ID of receiving interface in MLD query for lookup | * Embed scope ID of receiving interface in MLD query for lookup | ||||
* whilst we don't hold other locks (due to KAME locking lameness). | * whilst we don't hold other locks (due to KAME locking lameness). | ||||
*/ | */ | ||||
if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) | if (!IN6_IS_ADDR_UNSPECIFIED(&mld->mld_addr)) | ||||
in6_setscope(&mld->mld_addr, ifp, NULL); | in6_setscope(&mld->mld_addr, ifp, NULL); | ||||
IN6_MULTI_LOCK(); | IN6_MULTI_LIST_LOCK(); | ||||
MLD_LOCK(); | MLD_LOCK(); | ||||
IF_ADDR_RLOCK(ifp); | IF_ADDR_RLOCK(ifp); | ||||
/* | /* | ||||
* MLDv1 report suppression. | * MLDv1 report suppression. | ||||
* If we are a member of this group, and our membership should be | * If we are a member of this group, and our membership should be | ||||
* reported, and our group timer is pending or about to be reset, | * reported, and our group timer is pending or about to be reset, | ||||
* stop our group timer by transitioning to the 'lazy' state. | * stop our group timer by transitioning to the 'lazy' state. | ||||
Show All 35 Lines | if (inm != NULL) { | ||||
case MLD_LEAVING_MEMBER: | case MLD_LEAVING_MEMBER: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
out_locked: | out_locked: | ||||
IF_ADDR_RUNLOCK(ifp); | IF_ADDR_RUNLOCK(ifp); | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
/* XXX Clear embedded scope ID as userland won't expect it. */ | /* XXX Clear embedded scope ID as userland won't expect it. */ | ||||
in6_clearscope(&mld->mld_addr); | in6_clearscope(&mld->mld_addr); | ||||
return (0); | return (0); | ||||
} | } | ||||
/* | /* | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
mld_fasttimo_vnet(void) | mld_fasttimo_vnet(void) | ||||
{ | { | ||||
struct mbufq scq; /* State-change packets */ | struct mbufq scq; /* State-change packets */ | ||||
struct mbufq qrq; /* Query response packets */ | struct mbufq qrq; /* Query response packets */ | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct mld_ifsoftc *mli; | struct mld_ifsoftc *mli; | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct in6_multi *inm, *tinm; | struct in6_multi *inm, *tinm; | ||||
struct in6_multi_head inmh; | |||||
int uri_fasthz; | int uri_fasthz; | ||||
uri_fasthz = 0; | uri_fasthz = 0; | ||||
/* | /* | ||||
* Quick check to see if any work needs to be done, in order to | * Quick check to see if any work needs to be done, in order to | ||||
* minimize the overhead of fasttimo processing. | * minimize the overhead of fasttimo processing. | ||||
* SMPng: XXX Unlocked reads. | * SMPng: XXX Unlocked reads. | ||||
*/ | */ | ||||
if (!V_current_state_timers_running6 && | if (!V_current_state_timers_running6 && | ||||
!V_interface_timers_running6 && | !V_interface_timers_running6 && | ||||
!V_state_change_timers_running6) | !V_state_change_timers_running6) | ||||
return; | return; | ||||
IN6_MULTI_LOCK(); | SLIST_INIT(&inmh); | ||||
IN6_MULTI_LIST_LOCK(); | |||||
MLD_LOCK(); | MLD_LOCK(); | ||||
/* | /* | ||||
* MLDv2 General Query response timer processing. | * MLDv2 General Query response timer processing. | ||||
*/ | */ | ||||
if (V_interface_timers_running6) { | if (V_interface_timers_running6) { | ||||
CTR1(KTR_MLD, "%s: interface timers running", __func__); | CTR1(KTR_MLD, "%s: interface timers running", __func__); | ||||
Show All 35 Lines | LIST_FOREACH(mli, &V_mli_head, mli_link) { | ||||
IF_ADDR_RLOCK(ifp); | IF_ADDR_RLOCK(ifp); | ||||
TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | ||||
if (ifma->ifma_addr->sa_family != AF_INET6 || | if (ifma->ifma_addr->sa_family != AF_INET6 || | ||||
ifma->ifma_protospec == NULL) | ifma->ifma_protospec == NULL) | ||||
continue; | continue; | ||||
inm = (struct in6_multi *)ifma->ifma_protospec; | inm = (struct in6_multi *)ifma->ifma_protospec; | ||||
switch (mli->mli_version) { | switch (mli->mli_version) { | ||||
case MLD_VERSION_1: | case MLD_VERSION_1: | ||||
mld_v1_process_group_timer(mli, inm); | mld_v1_process_group_timer(&inmh, inm); | ||||
break; | break; | ||||
case MLD_VERSION_2: | case MLD_VERSION_2: | ||||
mld_v2_process_group_timers(mli, &qrq, | mld_v2_process_group_timers(&inmh, &qrq, | ||||
&scq, inm, uri_fasthz); | &scq, inm, uri_fasthz); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
IF_ADDR_RUNLOCK(ifp); | IF_ADDR_RUNLOCK(ifp); | ||||
switch (mli->mli_version) { | switch (mli->mli_version) { | ||||
case MLD_VERSION_1: | case MLD_VERSION_1: | ||||
/* | /* | ||||
* Transmit reports for this lifecycle. This | * Transmit reports for this lifecycle. This | ||||
* is done while not holding IF_ADDR_LOCK | * is done while not holding IF_ADDR_LOCK | ||||
* since this can call | * since this can call | ||||
* in6ifa_ifpforlinklocal() which locks | * in6ifa_ifpforlinklocal() which locks | ||||
* IF_ADDR_LOCK internally as well as | * IF_ADDR_LOCK internally as well as | ||||
* ip6_output() to transmit a packet. | * ip6_output() to transmit a packet. | ||||
*/ | */ | ||||
SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, | SLIST_FOREACH_SAFE(inm, &inmh, in6m_nrele, tinm) { | ||||
in6m_nrele, tinm) { | SLIST_REMOVE_HEAD(&inmh, | ||||
SLIST_REMOVE_HEAD(&mli->mli_relinmhead, | |||||
in6m_nrele); | in6m_nrele); | ||||
(void)mld_v1_transmit_report(inm, | (void)mld_v1_transmit_report(inm, | ||||
MLD_LISTENER_REPORT); | MLD_LISTENER_REPORT); | ||||
} | } | ||||
break; | break; | ||||
case MLD_VERSION_2: | case MLD_VERSION_2: | ||||
mld_dispatch_queue(&qrq, 0); | mld_dispatch_queue(&qrq, 0); | ||||
mld_dispatch_queue(&scq, 0); | mld_dispatch_queue(&scq, 0); | ||||
/* | /* | ||||
* Free the in_multi reference(s) for | * Free the in_multi reference(s) for | ||||
* this lifecycle. | * this lifecycle. | ||||
*/ | */ | ||||
SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, | in6m_release_list_deferred(&inmh); | ||||
in6m_nrele, tinm) { | |||||
SLIST_REMOVE_HEAD(&mli->mli_relinmhead, | |||||
in6m_nrele); | |||||
in6m_release_locked(inm); | |||||
} | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
out_locked: | out_locked: | ||||
MLD_UNLOCK(); | MLD_UNLOCK(); | ||||
IN6_MULTI_UNLOCK(); | IN6_MULTI_LIST_UNLOCK(); | ||||
} | } | ||||
/* | /* | ||||
* Update host report group timer. | * Update host report group timer. | ||||
* Will update the global pending timer flags. | * Will update the global pending timer flags. | ||||
*/ | */ | ||||
static void | static void | ||||
mld_v1_process_group_timer(struct mld_ifsoftc *mli, struct in6_multi *inm) | mld_v1_process_group_timer(struct in6_multi_head *inmh, struct in6_multi *inm) | ||||
{ | { | ||||
int report_timer_expired; | int report_timer_expired; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
if (inm->in6m_timer == 0) { | if (inm->in6m_timer == 0) { | ||||
report_timer_expired = 0; | report_timer_expired = 0; | ||||
} else if (--inm->in6m_timer == 0) { | } else if (--inm->in6m_timer == 0) { | ||||
report_timer_expired = 1; | report_timer_expired = 1; | ||||
} else { | } else { | ||||
V_current_state_timers_running6 = 1; | V_current_state_timers_running6 = 1; | ||||
return; | return; | ||||
} | } | ||||
switch (inm->in6m_state) { | switch (inm->in6m_state) { | ||||
case MLD_NOT_MEMBER: | case MLD_NOT_MEMBER: | ||||
case MLD_SILENT_MEMBER: | case MLD_SILENT_MEMBER: | ||||
case MLD_IDLE_MEMBER: | case MLD_IDLE_MEMBER: | ||||
case MLD_LAZY_MEMBER: | case MLD_LAZY_MEMBER: | ||||
case MLD_SLEEPING_MEMBER: | case MLD_SLEEPING_MEMBER: | ||||
case MLD_AWAKENING_MEMBER: | case MLD_AWAKENING_MEMBER: | ||||
break; | break; | ||||
case MLD_REPORTING_MEMBER: | case MLD_REPORTING_MEMBER: | ||||
if (report_timer_expired) { | if (report_timer_expired) { | ||||
inm->in6m_state = MLD_IDLE_MEMBER; | inm->in6m_state = MLD_IDLE_MEMBER; | ||||
SLIST_INSERT_HEAD(&mli->mli_relinmhead, inm, | in6m_rele_locked(inmh, inm); | ||||
in6m_nrele); | |||||
} | } | ||||
break; | break; | ||||
case MLD_G_QUERY_PENDING_MEMBER: | case MLD_G_QUERY_PENDING_MEMBER: | ||||
case MLD_SG_QUERY_PENDING_MEMBER: | case MLD_SG_QUERY_PENDING_MEMBER: | ||||
case MLD_LEAVING_MEMBER: | case MLD_LEAVING_MEMBER: | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Update a group's timers for MLDv2. | * Update a group's timers for MLDv2. | ||||
* Will update the global pending timer flags. | * Will update the global pending timer flags. | ||||
* Note: Unlocked read from mli. | * Note: Unlocked read from mli. | ||||
*/ | */ | ||||
static void | static void | ||||
mld_v2_process_group_timers(struct mld_ifsoftc *mli, | mld_v2_process_group_timers(struct in6_multi_head *inmh, | ||||
struct mbufq *qrq, struct mbufq *scq, | struct mbufq *qrq, struct mbufq *scq, | ||||
struct in6_multi *inm, const int uri_fasthz) | struct in6_multi *inm, const int uri_fasthz) | ||||
{ | { | ||||
int query_response_timer_expired; | int query_response_timer_expired; | ||||
int state_change_retransmit_timer_expired; | int state_change_retransmit_timer_expired; | ||||
#ifdef KTR | #ifdef KTR | ||||
char ip6tbuf[INET6_ADDRSTRLEN]; | char ip6tbuf[INET6_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
query_response_timer_expired = 0; | query_response_timer_expired = 0; | ||||
state_change_retransmit_timer_expired = 0; | state_change_retransmit_timer_expired = 0; | ||||
/* | /* | ||||
* During a transition from compatibility mode back to MLDv2, | * During a transition from compatibility mode back to MLDv2, | ||||
* a group record in REPORTING state may still have its group | * a group record in REPORTING state may still have its group | ||||
▲ Show 20 Lines • Show All 81 Lines • ▼ Show 20 Lines | if (state_change_retransmit_timer_expired) { | ||||
* we release MLD's reference to it. | * we release MLD's reference to it. | ||||
* This release must be deferred using a SLIST, | * This release must be deferred using a SLIST, | ||||
* as we are called from a loop which traverses | * as we are called from a loop which traverses | ||||
* the in_ifmultiaddr TAILQ. | * the in_ifmultiaddr TAILQ. | ||||
*/ | */ | ||||
if (inm->in6m_state == MLD_LEAVING_MEMBER && | if (inm->in6m_state == MLD_LEAVING_MEMBER && | ||||
inm->in6m_scrv == 0) { | inm->in6m_scrv == 0) { | ||||
inm->in6m_state = MLD_NOT_MEMBER; | inm->in6m_state = MLD_NOT_MEMBER; | ||||
SLIST_INSERT_HEAD(&mli->mli_relinmhead, | in6m_rele_locked(inmh, inm); | ||||
inm, in6m_nrele); | |||||
} | } | ||||
} | } | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* Switch to a different version on the given interface, | * Switch to a different version on the given interface, | ||||
Show All 29 Lines | |||||
* Cancel pending MLDv2 timers for the given link and all groups | * Cancel pending MLDv2 timers for the given link and all groups | ||||
* joined on it; state-change, general-query, and group-query timers. | * joined on it; state-change, general-query, and group-query timers. | ||||
*/ | */ | ||||
static void | static void | ||||
mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) | mld_v2_cancel_link_timers(struct mld_ifsoftc *mli) | ||||
{ | { | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct in6_multi *inm, *tinm; | struct in6_multi *inm; | ||||
struct in6_multi_head inmh; | |||||
CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__, | CTR3(KTR_MLD, "%s: cancel v2 timers on ifp %p(%s)", __func__, | ||||
mli->mli_ifp, if_name(mli->mli_ifp)); | mli->mli_ifp, if_name(mli->mli_ifp)); | ||||
IN6_MULTI_LOCK_ASSERT(); | SLIST_INIT(&inmh); | ||||
IN6_MULTI_LIST_LOCK_ASSERT(); | |||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
/* | /* | ||||
* Fast-track this potentially expensive operation | * Fast-track this potentially expensive operation | ||||
* by checking all the global 'timer pending' flags. | * by checking all the global 'timer pending' flags. | ||||
*/ | */ | ||||
if (!V_interface_timers_running6 && | if (!V_interface_timers_running6 && | ||||
!V_state_change_timers_running6 && | !V_state_change_timers_running6 && | ||||
Show All 18 Lines | TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) { | ||||
case MLD_AWAKENING_MEMBER: | case MLD_AWAKENING_MEMBER: | ||||
break; | break; | ||||
case MLD_LEAVING_MEMBER: | case MLD_LEAVING_MEMBER: | ||||
/* | /* | ||||
* If we are leaving the group and switching | * If we are leaving the group and switching | ||||
* version, we need to release the final | * version, we need to release the final | ||||
* reference held for issuing the INCLUDE {}. | * reference held for issuing the INCLUDE {}. | ||||
*/ | */ | ||||
SLIST_INSERT_HEAD(&mli->mli_relinmhead, inm, | in6m_rele_locked(&inmh, inm); | ||||
in6m_nrele); | ifma->ifma_protospec = NULL; | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case MLD_G_QUERY_PENDING_MEMBER: | case MLD_G_QUERY_PENDING_MEMBER: | ||||
case MLD_SG_QUERY_PENDING_MEMBER: | case MLD_SG_QUERY_PENDING_MEMBER: | ||||
in6m_clear_recorded(inm); | in6m_clear_recorded(inm); | ||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | ||||
case MLD_REPORTING_MEMBER: | case MLD_REPORTING_MEMBER: | ||||
inm->in6m_sctimer = 0; | inm->in6m_sctimer = 0; | ||||
inm->in6m_timer = 0; | inm->in6m_timer = 0; | ||||
inm->in6m_state = MLD_REPORTING_MEMBER; | inm->in6m_state = MLD_REPORTING_MEMBER; | ||||
/* | /* | ||||
* Free any pending MLDv2 state-change records. | * Free any pending MLDv2 state-change records. | ||||
*/ | */ | ||||
mbufq_drain(&inm->in6m_scq); | mbufq_drain(&inm->in6m_scq); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
IF_ADDR_RUNLOCK(ifp); | IF_ADDR_RUNLOCK(ifp); | ||||
SLIST_FOREACH_SAFE(inm, &mli->mli_relinmhead, in6m_nrele, tinm) { | in6m_release_list_deferred(&inmh); | ||||
SLIST_REMOVE_HEAD(&mli->mli_relinmhead, in6m_nrele); | |||||
in6m_release_locked(inm); | |||||
} | } | ||||
} | |||||
/* | /* | ||||
* Global slowtimo handler. | * Global slowtimo handler. | ||||
* VIMAGE: Timeout handlers are expected to service all vimages. | * VIMAGE: Timeout handlers are expected to service all vimages. | ||||
*/ | */ | ||||
void | void | ||||
mld_slowtimo(void) | mld_slowtimo(void) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 54 Lines • ▼ Show 20 Lines | |||||
mld_v1_transmit_report(struct in6_multi *in6m, const int type) | mld_v1_transmit_report(struct in6_multi *in6m, const int type) | ||||
{ | { | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct in6_ifaddr *ia; | struct in6_ifaddr *ia; | ||||
struct ip6_hdr *ip6; | struct ip6_hdr *ip6; | ||||
struct mbuf *mh, *md; | struct mbuf *mh, *md; | ||||
struct mld_hdr *mld; | struct mld_hdr *mld; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
ifp = in6m->in6m_ifp; | ifp = in6m->in6m_ifp; | ||||
ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); | ia = in6ifa_ifpforlinklocal(ifp, IN6_IFF_NOTREADY|IN6_IFF_ANYCAST); | ||||
/* ia may be NULL if link-local address is tentative. */ | /* ia may be NULL if link-local address is tentative. */ | ||||
mh = m_gethdr(M_NOWAIT, MT_DATA); | mh = m_gethdr(M_NOWAIT, MT_DATA); | ||||
if (mh == NULL) { | if (mh == NULL) { | ||||
▲ Show 20 Lines • Show All 74 Lines • ▼ Show 20 Lines | |||||
*/ | */ | ||||
int | int | ||||
mld_change_state(struct in6_multi *inm, const int delay) | mld_change_state(struct in6_multi *inm, const int delay) | ||||
{ | { | ||||
struct mld_ifsoftc *mli; | struct mld_ifsoftc *mli; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
int error; | int error; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
error = 0; | error = 0; | ||||
/* | /* | ||||
* Try to detect if the upper layer just asked us to change state | * Try to detect if the upper layer just asked us to change state | ||||
* for an interface which has now gone away. | * for an interface which has now gone away. | ||||
*/ | */ | ||||
KASSERT(inm->in6m_ifma != NULL, ("%s: no ifma", __func__)); | KASSERT(inm->in6m_ifma != NULL, ("%s: no ifma", __func__)); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | CTR4(KTR_MLD, "%s: initial join %s on ifp %p(%s)", | ||||
__func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr), | __func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr), | ||||
inm->in6m_ifp, if_name(inm->in6m_ifp)); | inm->in6m_ifp, if_name(inm->in6m_ifp)); | ||||
error = 0; | error = 0; | ||||
syncstates = 1; | syncstates = 1; | ||||
ifp = inm->in6m_ifp; | ifp = inm->in6m_ifp; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
KASSERT(mli && mli->mli_ifp == ifp, ("%s: inconsistent ifp", __func__)); | KASSERT(mli && mli->mli_ifp == ifp, ("%s: inconsistent ifp", __func__)); | ||||
/* | /* | ||||
* Groups joined on loopback or marked as 'not reported', | * Groups joined on loopback or marked as 'not reported', | ||||
* enter the MLD_SILENT_MEMBER state and | * enter the MLD_SILENT_MEMBER state and | ||||
* are never reported in any protocol exchanges. | * are never reported in any protocol exchanges. | ||||
Show All 13 Lines | "%s: not kicking state machine for silent group", __func__); | ||||
/* | /* | ||||
* Deal with overlapping in_multi lifecycle. | * Deal with overlapping in_multi lifecycle. | ||||
* If this group was LEAVING, then make sure | * If this group was LEAVING, then make sure | ||||
* we drop the reference we picked up to keep the | * we drop the reference we picked up to keep the | ||||
* group around for the final INCLUDE {} enqueue. | * group around for the final INCLUDE {} enqueue. | ||||
*/ | */ | ||||
if (mli->mli_version == MLD_VERSION_2 && | if (mli->mli_version == MLD_VERSION_2 && | ||||
inm->in6m_state == MLD_LEAVING_MEMBER) | inm->in6m_state == MLD_LEAVING_MEMBER) | ||||
in6m_release_locked(inm); | in6m_release_deferred(inm); | ||||
inm->in6m_state = MLD_REPORTING_MEMBER; | inm->in6m_state = MLD_REPORTING_MEMBER; | ||||
switch (mli->mli_version) { | switch (mli->mli_version) { | ||||
case MLD_VERSION_1: | case MLD_VERSION_1: | ||||
/* | /* | ||||
* If a delay was provided, only use it if | * If a delay was provided, only use it if | ||||
* it is greater than the delay normally | * it is greater than the delay normally | ||||
▲ Show 20 Lines • Show All 96 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
CTR4(KTR_MLD, "%s: state change for %s on ifp %p(%s)", | CTR4(KTR_MLD, "%s: state change for %s on ifp %p(%s)", | ||||
__func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr), | __func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr), | ||||
inm->in6m_ifp, if_name(inm->in6m_ifp)); | inm->in6m_ifp, if_name(inm->in6m_ifp)); | ||||
ifp = inm->in6m_ifp; | ifp = inm->in6m_ifp; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
KASSERT(mli && mli->mli_ifp == ifp, | KASSERT(mli && mli->mli_ifp == ifp, | ||||
("%s: inconsistent ifp", __func__)); | ("%s: inconsistent ifp", __func__)); | ||||
if ((ifp->if_flags & IFF_LOOPBACK) || | if ((ifp->if_flags & IFF_LOOPBACK) || | ||||
(mli->mli_flags & MLIF_SILENT) || | (mli->mli_flags & MLIF_SILENT) || | ||||
!mld_is_addr_reported(&inm->in6m_addr) || | !mld_is_addr_reported(&inm->in6m_addr) || | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
#endif | #endif | ||||
syncstates = 1; | syncstates = 1; | ||||
CTR4(KTR_MLD, "%s: final leave %s on ifp %p(%s)", | CTR4(KTR_MLD, "%s: final leave %s on ifp %p(%s)", | ||||
__func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr), | __func__, ip6_sprintf(ip6tbuf, &inm->in6m_addr), | ||||
inm->in6m_ifp, if_name(inm->in6m_ifp)); | inm->in6m_ifp, if_name(inm->in6m_ifp)); | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
switch (inm->in6m_state) { | switch (inm->in6m_state) { | ||||
case MLD_NOT_MEMBER: | case MLD_NOT_MEMBER: | ||||
case MLD_SILENT_MEMBER: | case MLD_SILENT_MEMBER: | ||||
case MLD_LEAVING_MEMBER: | case MLD_LEAVING_MEMBER: | ||||
/* Already leaving or left; do nothing. */ | /* Already leaving or left; do nothing. */ | ||||
CTR1(KTR_MLD, | CTR1(KTR_MLD, | ||||
▲ Show 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | mld_v2_enqueue_group_record(struct mbufq *mq, struct in6_multi *inm, | ||||
int record_has_sources; | int record_has_sources; | ||||
int now; | int now; | ||||
int type; | int type; | ||||
uint8_t mode; | uint8_t mode; | ||||
#ifdef KTR | #ifdef KTR | ||||
char ip6tbuf[INET6_ADDRSTRLEN]; | char ip6tbuf[INET6_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
ifp = inm->in6m_ifp; | ifp = inm->in6m_ifp; | ||||
is_filter_list_change = 0; | is_filter_list_change = 0; | ||||
m = NULL; | m = NULL; | ||||
m0 = NULL; | m0 = NULL; | ||||
m0srcs = 0; | m0srcs = 0; | ||||
msrcs = 0; | msrcs = 0; | ||||
nbytes = 0; | nbytes = 0; | ||||
▲ Show 20 Lines • Show All 366 Lines • ▼ Show 20 Lines | mld_v2_enqueue_filter_change(struct mbufq *mq, struct in6_multi *inm) | ||||
int m0srcs, nbytes, npbytes, off, rsrcs, schanged; | int m0srcs, nbytes, npbytes, off, rsrcs, schanged; | ||||
int nallow, nblock; | int nallow, nblock; | ||||
uint8_t mode, now, then; | uint8_t mode, now, then; | ||||
rectype_t crt, drt, nrt; | rectype_t crt, drt, nrt; | ||||
#ifdef KTR | #ifdef KTR | ||||
char ip6tbuf[INET6_ADDRSTRLEN]; | char ip6tbuf[INET6_ADDRSTRLEN]; | ||||
#endif | #endif | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
if (inm->in6m_nsrc == 0 || | if (inm->in6m_nsrc == 0 || | ||||
(inm->in6m_st[0].iss_asm > 0 && inm->in6m_st[1].iss_asm > 0)) | (inm->in6m_st[0].iss_asm > 0 && inm->in6m_st[1].iss_asm > 0)) | ||||
return (0); | return (0); | ||||
ifp = inm->in6m_ifp; /* interface */ | ifp = inm->in6m_ifp; /* interface */ | ||||
mode = inm->in6m_st[1].iss_fmode; /* filter mode at t1 */ | mode = inm->in6m_st[1].iss_fmode; /* filter mode at t1 */ | ||||
crt = REC_NONE; /* current group record type */ | crt = REC_NONE; /* current group record type */ | ||||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Lines | mld_v2_merge_state_changes(struct in6_multi *inm, struct mbufq *scq) | ||||
struct mbuf *mt; /* last state-change in packet */ | struct mbuf *mt; /* last state-change in packet */ | ||||
int docopy, domerge; | int docopy, domerge; | ||||
u_int recslen; | u_int recslen; | ||||
docopy = 0; | docopy = 0; | ||||
domerge = 0; | domerge = 0; | ||||
recslen = 0; | recslen = 0; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
/* | /* | ||||
* If there are further pending retransmissions, make a writable | * If there are further pending retransmissions, make a writable | ||||
* copy of each queued state-change message before merging. | * copy of each queued state-change message before merging. | ||||
*/ | */ | ||||
if (inm->in6m_scrv > 0) | if (inm->in6m_scrv > 0) | ||||
docopy = 1; | docopy = 1; | ||||
▲ Show 20 Lines • Show All 82 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
mld_v2_dispatch_general_query(struct mld_ifsoftc *mli) | mld_v2_dispatch_general_query(struct mld_ifsoftc *mli) | ||||
{ | { | ||||
struct ifmultiaddr *ifma; | struct ifmultiaddr *ifma; | ||||
struct ifnet *ifp; | struct ifnet *ifp; | ||||
struct in6_multi *inm; | struct in6_multi *inm; | ||||
int retval; | int retval; | ||||
IN6_MULTI_LOCK_ASSERT(); | IN6_MULTI_LIST_LOCK_ASSERT(); | ||||
MLD_LOCK_ASSERT(); | MLD_LOCK_ASSERT(); | ||||
KASSERT(mli->mli_version == MLD_VERSION_2, | KASSERT(mli->mli_version == MLD_VERSION_2, | ||||
("%s: called when version %d", __func__, mli->mli_version)); | ("%s: called when version %d", __func__, mli->mli_version)); | ||||
/* | /* | ||||
* Check that there are some packets queued. If so, send them first. | * Check that there are some packets queued. If so, send them first. | ||||
* For large number of groups the reply to general query can take | * For large number of groups the reply to general query can take | ||||
▲ Show 20 Lines • Show All 328 Lines • Show Last 20 Lines |