From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-pj1-f41.google.com (mail-pj1-f41.google.com [209.85.216.41]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 648A7275AEB for ; Fri, 1 May 2026 17:32:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.41 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777656726; cv=none; b=kPC+qwgIGtPqdZiwvXqPI/uLzmoktwotaIeSiL5NteLnEN+FedpU5bIiYRioFWGm2sFtHLd0TpUB/lUbX8FlW4dLRqpw2SUk+qIjSEbxYhJE5DOrM3i/em2eLmfgL6ePQsFE7mb8Cr6pCVrJ21Cmr8fWDzfUD3TW8oeaBGK3lUA= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1777656726; c=relaxed/simple; bh=ZVHW1z1PIb5ePVtbyq08NJ8dexrkCXfgDVaSH/sbAuc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=KFKTstKNYNYHG/aQH/CKZ4sRPUtIWXcjl0zoT2nW+MC9igS/dsOyj5zufAQ2XzZV01TnlwjO4JZY3vHhItj96lU4zBrgwOdB+Am1x1THxKRfLB0hIemQ1LxM8gq+9yNkMpPRaSfwoG5ZWL8USUhY9d3xju3s//lrorGaTEGuKtc= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=JGrGYmJE; arc=none smtp.client-ip=209.85.216.41 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="JGrGYmJE" Received: by mail-pj1-f41.google.com with SMTP id 98e67ed59e1d1-356337f058aso1404180a91.2 for ; Fri, 01 May 2026 10:32:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777656725; x=1778261525; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=qnFHFq0X3do40vbZFzPcxUaeVD7TkwqS7ui8TNvbysY=; b=JGrGYmJEHwHwqVz+YnEY8AHy3bKQ8xR4yG/DZL9J+kRWe6V73eS9bKg4sVa7/WA13V I4myyj61W8TPC3tpk1Abh5PHxEtkle5YW2nQviTUPPMChMHEZA4uh2mzjVcbPq7jCMl6 rUtVFHE+s87e/NumPxUsANYU+kZhnE++8IGLM/fbzu4DAcVo3fCv7Py1xM+JwdLU3Gmk r1ILSaCmwVsQGqLWmscE4I5L5nMkK6HNg3EV6ZtGrudOyJZQDFlbYSNOGJgDiIKOyxul 1M1CHgQYngHXBTKe9KCmiZaI6CM+hbz1AyCHPUaElElSTzubsibXLAo0OXHHjJdhEP+W ioCw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777656725; x=1778261525; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=qnFHFq0X3do40vbZFzPcxUaeVD7TkwqS7ui8TNvbysY=; b=qdYyImZrTivCzapcwBE+GmZZrDr2RDFdf641r+ZAvyNBLFibTSlTg5DSai4CpqigqK pikZDF0oxYnWqTrkmNJaYvgluhBn30v7f8AmaXSOPYgcnsot4OclB1xyVEQdSHcFia0a HNi/DCZV0M4GSmQBCMQDN560C8yf3WyRHlWHkO+3fX8sAm8DFaE8E26NBIeHKr6DTElx W4h+BtyFDDRnm7Kfl6JIt0+fUyc9Hmr/At0Ra4uRjWkdnb7LJ+6jNqD9vaUwzP2QBIbq 88rKh4MQJIPkpvpRoEe9IM1rU/+vtEFt6/ogp7TCR5dsT7SclffJ2UqFTfqoBel2BL2g j52Q== X-Forwarded-Encrypted: i=1; AFNElJ/0V2L3mAxi3wFSwjRh9XQZOHRSbPzk3HZN4IadzPvwyvdCa08X7q0YT4nCsFQkgwj0cDfEvCrP4eqdpeTKMGQ=@vger.kernel.org X-Gm-Message-State: AOJu0Yy8GsH7636YEKCTWDXmDErLWb8aCJbrmXGWjVq3A1LjyforiZh7 tJsbWv5651zyPEN+59Zgk9GqTSKvISJqoVWZxaeNvBQPDTLhY19e+gYF X-Gm-Gg: AeBDietC5fsjvAI8YHKagAFblm1op08tADl8DhZWo43ruW6Gs1Ttx2aWrVduHgnG1k3 oyCpvYM97TDTKRIL7naUgK9GJqUnvysQVuHpIHJSg6EyaGM7tKnIP59Us7rYPQWJE2aB9AQpZJS Ass5UppmfudZovIHetbZCZ0fgWZiL5QkB+JPBhj+YeldKjLIJ6e5sHrnZxxG7SkB7uoM5adeZvL AEYosswMRwl3isfYnBfWYIb143rMLeV5G9Jq1IdZfPi/23eqLOevo0EjVHwhu3Fi5utnIe5qPmV sGmrlHkvS6UwXhFJCYJmFyU9xTS75PQ1mSdMQ6RjkMB6oaSeqNiv7w3iD9A0x2MFgYN9xAW/hPa qo1SQOvCqnw35QaCZP3U906qr2nubxqjQsxPVm1L7ywcJ45dzgZG62JVbgrmrE6ZNNdUngmnWak Mn7C6VA6kI+9AyXUP2uYZrMjCR2WAZK6merEz1uETXWwI6VVVdxw== X-Received: by 2002:a17:90b:518e:b0:35f:b5df:449 with SMTP id 98e67ed59e1d1-3650cec16c5mr137991a91.21.1777656724709; Fri, 01 May 2026 10:32:04 -0700 (PDT) Received: from DESKTOP-82PPU4A.localdomain ([202.8.116.84]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-364ebec73aasm2908906a91.2.2026.05.01.10.31.57 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 01 May 2026 10:32:04 -0700 (PDT) From: Ujjal Roy To: "David S . Miller" , Eric Dumazet , Jakub Kicinski , Paolo Abeni , Simon Horman , Nikolay Aleksandrov , Ido Schimmel , David Ahern , Shuah Khan , Andy Roulin , Yong Wang , Petr Machata Cc: Ujjal Roy , bridge@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-kselftest@vger.kernel.org Subject: [PATCH net-next v5 3/5] ipv4: igmp: encode multicast exponential fields Date: Fri, 1 May 2026 17:31:27 +0000 Message-ID: <20260501173130.3486-4-royujjal@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20260501173130.3486-1-royujjal@gmail.com> References: <20260501173130.3486-1-royujjal@gmail.com> Precedence: bulk X-Mailing-List: linux-kselftest@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit In IGMP, MRC and QQIC fields are not correctly encoded when generating query packets. Since the receiver of the query interprets these fields using the IGMPv3 floating- point decoding logic, any value that exceeds the linear threshold is incorrectly parsed as an exponential value, leading to an incorrect interval calculation. Encode and assign the corresponding protocol fields during query generation. Introduce the logic to dynamically calculate the exponent and mantissa using bit-scan (fls). This ensures MRC and QQIC fields (8-bit) are properly encoded when transmitting query packets with intervals that exceed their respective linear threshold value of 128 (for MRT/QQI). RFC3376: for both MRC and QQIC, values >= 128 represent the same floating-point encoding as follows: 0 1 2 3 4 5 6 7 +-+-+-+-+-+-+-+-+ |1| exp | mant | +-+-+-+-+-+-+-+-+ Reviewed-by: Ido Schimmel Signed-off-by: Ujjal Roy --- include/linux/igmp.h | 87 +++++++++++++++++++++++++++++++++++++++ net/bridge/br_multicast.c | 14 +++---- 2 files changed, 93 insertions(+), 8 deletions(-) diff --git a/include/linux/igmp.h b/include/linux/igmp.h index 0e095c9f234e..3a2d35a9f307 100644 --- a/include/linux/igmp.h +++ b/include/linux/igmp.h @@ -109,6 +109,93 @@ struct ip_mc_list { /* IGMPv3 floating-point exponential field min threshold */ #define IGMPV3_EXP_MIN_THRESHOLD 128 +/* IGMPv3 FP max threshold (mant = 0xF, exp = 7) -> 31744 */ +#define IGMPV3_EXP_MAX_THRESHOLD 31744 + +/* V3 exponential field encoding */ + +/* IGMPv3 MRC/QQIC 8-bit exponential field encode + * + * RFC3376, 4.1.1 & 4.1.7. defines only the decoding formula: + * MRT/QQI = (mant | 0x10) << (exp + 3) + * + * but does NOT define the encoding procedure. To derive exponent: + * + * For any value of mantissa and exponent, the decoding formula + * indicates that the "hidden bit" (0x10) is shifted 4 bits left + * to sit above the 4-bit mantissa. The RFC again shifts this + * entire block left by (exp + 3) to reconstruct the value. + * So, 'hidden bit' is the MSB which is shifted by (4 + exp + 3). + * + * Total left shift of the 'hidden bit' = 4 + (exp + 3) = exp + 7. + * This is the MSB at the 0-based bit position: (exp + 7). + * Since fls() is 1-based, fls(value) - 1 = exp + 7. + * + * Therefore: + * exp = fls(value) - 8 + * mant = (value >> (exp + 3)) & 0x0F + * + * Final encoding formula: + * 0x80 | (exp << 4) | mant + * + * Example (value = 3200): + * 0 1 + * 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * |0 0 0 0 1 1 0 0 1 0 0 0 0 0 0 0| (value = 3200) + * | ^-^-mant^ ^..(exp+3)..^| exp = 4, mant = 9 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * Encoded: + * 0x80 | (4 << 4) | 9 = 0xC9 + */ +static inline u8 igmpv3_exp_field_encode(unsigned long value) +{ + u8 mc_exp, mc_man; + + /* MRC/QQIC < 128 is literal */ + if (value < IGMPV3_EXP_MIN_THRESHOLD) + return value; + + /* Saturate at max representable (mant = 0xF, exp = 7) -> 31744 */ + if (value >= IGMPV3_EXP_MAX_THRESHOLD) + return 0xFF; + + mc_exp = fls(value) - 8; + mc_man = (value >> (mc_exp + 3)) & 0x0F; + + return 0x80 | (mc_exp << 4) | mc_man; +} + +/* Calculate Maximum Response Code from Max Resp Time + * + * RFC3376, relevant sections: + * - 4.1.1. Maximum Response Code + * - 8.3. Query Response Interval + * + * MRC represents the encoded form of Max Resp Time (MRT); once + * decoded, the resulting value is in units of 0.1 seconds (100 ms). + */ +static inline u8 igmpv3_mrc(unsigned long mrt) +{ + return igmpv3_exp_field_encode(mrt); +} + +/* Calculate Querier's Query Interval Code from Querier's Query Interval + * + * RFC3376, relevant sections: + * - 4.1.7. QQIC (Querier's Query Interval Code) + * - 8.2. Query Interval + * - 8.12. Older Version Querier Present Timeout + * (the [Query Interval] in the last Query received) + * + * QQIC represents the encoded form of Querier's Query Interval (QQI); + * once decoded, the resulting value is in units of seconds. + */ +static inline u8 igmpv3_qqic(unsigned long qi) +{ + return igmpv3_exp_field_encode(qi); +} /* V3 exponential field decoding */ diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 1438c023db62..27010744d7ae 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c @@ -934,12 +934,12 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brm size_t pkt_size, igmp_hdr_size; unsigned long now = jiffies; struct igmpv3_query *ihv3; + unsigned long lmqt, mrt; void *csum_start = NULL; __sum16 *csum = NULL; struct sk_buff *skb; struct igmphdr *ih; struct ethhdr *eth; - unsigned long lmqt; struct iphdr *iph; u16 lmqt_srcs = 0; @@ -1004,15 +1004,15 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brm skb_put(skb, 24); skb_set_transport_header(skb, skb->len); + mrt = group ? brmctx->multicast_last_member_interval : + brmctx->multicast_query_response_interval; *igmp_type = IGMP_HOST_MEMBERSHIP_QUERY; switch (brmctx->multicast_igmp_version) { case 2: ih = igmp_hdr(skb); ih->type = IGMP_HOST_MEMBERSHIP_QUERY; - ih->code = (group ? brmctx->multicast_last_member_interval : - brmctx->multicast_query_response_interval) / - (HZ / IGMP_TIMER_SCALE); + ih->code = mrt / (HZ / IGMP_TIMER_SCALE); ih->group = group; ih->csum = 0; csum = &ih->csum; @@ -1021,11 +1021,9 @@ static struct sk_buff *br_ip4_multicast_alloc_query(struct net_bridge_mcast *brm case 3: ihv3 = igmpv3_query_hdr(skb); ihv3->type = IGMP_HOST_MEMBERSHIP_QUERY; - ihv3->code = (group ? brmctx->multicast_last_member_interval : - brmctx->multicast_query_response_interval) / - (HZ / IGMP_TIMER_SCALE); + ihv3->code = igmpv3_mrc(mrt / (HZ / IGMP_TIMER_SCALE)); ihv3->group = group; - ihv3->qqic = brmctx->multicast_query_interval / HZ; + ihv3->qqic = igmpv3_qqic(brmctx->multicast_query_interval / HZ); ihv3->nsrcs = htons(lmqt_srcs); ihv3->resv = 0; ihv3->suppress = sflag; -- 2.43.0