From 5c2ebd3ad60c2784d14934e28ed5434fbd0651bf Mon Sep 17 00:00:00 2001 From: Olivier BLANC Date: Fri, 14 Mar 2025 19:55:55 +0100 Subject: [PATCH] igmp: apply net.inet.igmp.default_version to existing interfaces IGMP requires hosts to use the lowest version they have seen on the network. When net.inet.igmp.default_version is changed, we do not change IGMP version used by interface even if the interface use an higher version than V_igmp_default_version. So we could send IGMPv3 even if the user has requested IGMPv2 or IGMPv1 via the sysctl. Change IGMP version for each interface when V_igmp_default_version is smaller than the version used by the interface. Pull Request: https://github.com/freebsd/freebsd-src/pull/1615 Differential Revision: https://reviews.freebsd.org/D50071 --- sys/netinet/igmp.c | 35 +++++++++++++++++++++++------------ 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/sys/netinet/igmp.c b/sys/netinet/igmp.c index 5caa957cdda..6fe5e32c2e6 100644 --- a/sys/netinet/igmp.c +++ b/sys/netinet/igmp.c @@ -404,32 +404,43 @@ out: static int sysctl_igmp_default_version(SYSCTL_HANDLER_ARGS) { + struct epoch_tracker et; int error; int new; + struct igmp_ifsoftc *igi; error = sysctl_wire_old_buffer(req, sizeof(int)); if (error) return (error); - IGMP_LOCK(); - new = V_igmp_default_version; error = sysctl_handle_int(oidp, &new, 0, req); if (error || !req->newptr) - goto out_locked; + return (error); - if (new < IGMP_VERSION_1 || new > IGMP_VERSION_3) { - error = EINVAL; - goto out_locked; + if (new < IGMP_VERSION_1 || new > IGMP_VERSION_3) + return (EINVAL); + + IN_MULTI_LIST_LOCK(); + IGMP_LOCK(); + NET_EPOCH_ENTER(et); + + if (V_igmp_default_version != new) { + CTR2(KTR_IGMPV3, "change igmp_default_version from %d to %d", + V_igmp_default_version, new); + + V_igmp_default_version = new; + + LIST_FOREACH(igi, &V_igi_head, igi_link) { + if (igi->igi_version > V_igmp_default_version){ + igmp_set_version(igi, V_igmp_default_version); + } + } } - CTR2(KTR_IGMPV3, "change igmp_default_version from %d to %d", - V_igmp_default_version, new); - - V_igmp_default_version = new; - -out_locked: + NET_EPOCH_EXIT(et); + IN_MULTI_LIST_UNLOCK(); IGMP_UNLOCK(); return (error); }