The following patch fixes these problems in MLDv2: 1) Add/remove "delete" records for sending change reports when addition of a filter results in that filter transitioning to/from inactive. [same as recent IPv4 IGMPv3 fix] 2) Remove 2 redundant "group_type" checks (can't be IPV6_ADDR_ANY within that loop, so checks are always true) 3) change an is_in() "return 0" to "return type == MLD2_MODE_IS_INCLUDE". It should always be "0" to get here, but it improves code locality to not assume it, and if some race allowed otherwise, doing the check would return the correct result.
+-DLS [in-line for viewing, attached for applying] Signed-off-by: David L Stevens <[EMAIL PROTECTED]> diff -ruNp linux-2.6.15.1/net/ipv6/mcast.c linux-2.6.15.1MC1/net/ipv6/mcast.c --- linux-2.6.15.1/net/ipv6/mcast.c 2006-01-14 22:16:02.000000000 -0800 +++ linux-2.6.15.1MC1/net/ipv6/mcast.c 2006-01-19 13:56:07.000000000 -0800 @@ -1253,8 +1253,7 @@ int igmp6_event_query(struct sk_buff *sk } } else { for (ma = idev->mc_list; ma; ma=ma->next) { - if (group_type != IPV6_ADDR_ANY && - !ipv6_addr_equal(group, &ma->mca_addr)) + if (!ipv6_addr_equal(group, &ma->mca_addr)) continue; spin_lock_bh(&ma->mca_lock); if (ma->mca_flags & MAF_TIMER_RUNNING) { @@ -1269,11 +1268,10 @@ int igmp6_event_query(struct sk_buff *sk ma->mca_flags &= ~MAF_GSQUERY; } if (!(ma->mca_flags & MAF_GSQUERY) || - mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs)) + mld_marksources(ma, ntohs(mlh2->nsrcs), mlh2->srcs)) igmp6_group_queried(ma, max_delay); spin_unlock_bh(&ma->mca_lock); - if (group_type != IPV6_ADDR_ANY) - break; + break; } } read_unlock_bh(&idev->lock); @@ -1352,7 +1350,7 @@ static int is_in(struct ifmcaddr6 *pmc, * in all filters */ if (psf->sf_count[MCAST_INCLUDE]) - return 0; + return type == MLD2_MODE_IS_INCLUDE; return pmc->mca_sfcount[MCAST_EXCLUDE] == psf->sf_count[MCAST_EXCLUDE]; } @@ -1967,7 +1965,7 @@ static void sf_markstate(struct ifmcaddr static int sf_setstate(struct ifmcaddr6 *pmc) { - struct ip6_sf_list *psf; + struct ip6_sf_list *psf, *dpsf; int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE]; int qrv = pmc->idev->mc_qrv; int new_in, rv; @@ -1979,8 +1977,48 @@ static int sf_setstate(struct ifmcaddr6 !psf->sf_count[MCAST_INCLUDE]; } else new_in = psf->sf_count[MCAST_INCLUDE] != 0; - if (new_in != psf->sf_oldin) { - psf->sf_crcount = qrv; + if (new_in) { + if (!psf->sf_oldin) { + struct ip6_sf_list *prev = 0; + + for (dpsf=pmc->mca_tomb; dpsf; + dpsf=dpsf->sf_next) { + if (ipv6_addr_equal(&dpsf->sf_addr, + &psf->sf_addr)) + break; + prev = dpsf; + } + if (dpsf) { + if (prev) + prev->sf_next = dpsf->sf_next; + else + pmc->mca_tomb = dpsf->sf_next; + kfree(dpsf); + } + psf->sf_crcount = qrv; + rv++; + } + } else if (psf->sf_oldin) { + psf->sf_crcount = 0; + /* + * add or update "delete" records if an active filter + * is now inactive + */ + for (dpsf=pmc->mca_tomb; dpsf; dpsf=dpsf->sf_next) + if (ipv6_addr_equal(&dpsf->sf_addr, + &psf->sf_addr)) + break; + if (!dpsf) { + dpsf = (struct ip6_sf_list *) + kmalloc(sizeof(*dpsf), GFP_ATOMIC); + if (!dpsf) + continue; + *dpsf = *psf; + /* pmc->mca_lock held by callers */ + dpsf->sf_next = pmc->mca_tomb; + pmc->mca_tomb = dpsf; + } + dpsf->sf_crcount = qrv; rv++; } }
mc1.patch
Description: Binary data