mirror of
https://github.com/torvalds/linux.git
synced 2026-09-12 04:23:03 +02:00
ipv6: mcast: fix delay calculation in igmp6_join_group()
When joining a multicast group, if a report work is already pending
(e.g. scheduled by a query or a previous join), igmp6_join_group()
cancels the delayed work and recalculates the delay:
if (cancel_delayed_work(&ma->mca_work)) {
refcount_dec(&ma->mca_refcnt);
delay = ma->mca_work.timer.expires - jiffies;
}
Unlike igmp6_group_queried(), igmp6_join_group() did not check
if delay >= interval. This leads to two issues:
1. If the timer has already expired (timer.expires <= jiffies), the
stale expiry is reused by mod_delayed_work(), causing the second
unsolicited report to fire on the very next tick without a
randomized delay.
2. If the timer was originally armed by a query with a large
maximum response delay, delay could exceed
unsolicited_report_interval(ma->idev).
Fix this by initializing delay to unsolicited_report_interval(ma->idev)
and re-randomizing it with get_random_u32_below(interval) when
delay >= interval, mirroring the logic in igmp6_group_queried().
Fixes: 2d9a93b490 ("mld: convert from timer to delayed work")
Signed-off-by: Eric Dumazet <edumazet@google.com>
Cc: Taehee Yoo <ap420073@gmail.com>
Reviewed-by: Ido Schimmel <idosch@nvidia.com>
Fixes: 1da177e4c3 ("Linux-2.6.12-rc2")
Link: https://patch.msgid.link/20260828084531.1826790-4-edumazet@google.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
c073d1b070
commit
75fa9caeb8
|
|
@ -2639,7 +2639,7 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc)
|
|||
|
||||
static void igmp6_join_group(struct ifmcaddr6 *ma)
|
||||
{
|
||||
unsigned long delay;
|
||||
unsigned long delay, interval;
|
||||
|
||||
mc_assert_locked(ma->idev);
|
||||
|
||||
|
|
@ -2648,13 +2648,17 @@ static void igmp6_join_group(struct ifmcaddr6 *ma)
|
|||
|
||||
igmp6_send(&ma->mca_addr, ma->idev->dev, ICMPV6_MGM_REPORT);
|
||||
|
||||
delay = get_random_u32_below(unsolicited_report_interval(ma->idev));
|
||||
interval = unsolicited_report_interval(ma->idev);
|
||||
delay = interval;
|
||||
|
||||
if (cancel_delayed_work(&ma->mca_work)) {
|
||||
refcount_dec(&ma->mca_refcnt);
|
||||
delay = ma->mca_work.timer.expires - jiffies;
|
||||
}
|
||||
|
||||
if (delay >= interval)
|
||||
delay = get_random_u32_below(interval);
|
||||
|
||||
if (!mod_delayed_work(mld_wq, &ma->mca_work, delay))
|
||||
refcount_inc(&ma->mca_refcnt);
|
||||
WRITE_ONCE(ma->mca_flags, ma->mca_flags |
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user