From 624f93a28a4e7bb3b322df957334ef18ba9f8fb7 Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Tue, 8 Sep 2026 22:39:13 +0200 Subject: [PATCH] igmp: mask the port number before shifting by it The RTL tag carries a 4-bit port number for received frames, and the two places that turn it into a mask bit take the whole byte: entry.pmask |= (1L << (IGMP_I->rtl_tag.pmask >> 8)); The comment beside it already says only the low four bits count, but nothing takes them. rtl837x_stp.c:424 does the same extraction and does mask: stp_scratch = ((uint8_t)HTONS(STP_I->rtl_tag.pmask)) & 0x0f; With a count above 15 the result is not a bit at all. SDCC narrows the 1L to 16 bits and emits the shift as a djnz loop, so a count of 200 spins the loop 200 times and leaves zero behind: the join adds no port and the leave clears none, neither saying anything. It also spends those iterations inside packet handling. Mask to four bits and shift a uint16_t, which is the width the surrounding code works in. Six bytes of BANK1. Worth saying that this does not make snooping work on its own. struct igmp_pkt has no vlan_tag field while struct eth_in describes the same frame with one, so every IP and IGMP field below rtl_tag is read four bytes early. --- rtl837x_igmp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rtl837x_igmp.c b/rtl837x_igmp.c index da029036..0a749f99 100644 --- a/rtl837x_igmp.c +++ b/rtl837x_igmp.c @@ -295,7 +295,7 @@ void igmp_packet_handler(void) __banked entry.pmask |= ((uint16_t)sfr_data[3]) << 2; } // Update (found) entry with portmask from trapped Packet - entry.pmask |= (1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count + entry.pmask |= ((uint16_t)1) << ((IGMP_I->rtl_tag.pmask >> 8) & 0x0f); // Swap bytes from network order, only 4 LSB count // print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n'); } else if (IGMP_I->igmp_rtype == 0x3){ // Leave group if (sfr_data[2] & 0x10) { @@ -312,7 +312,7 @@ void igmp_packet_handler(void) __banked write_char('\n'); #endif // Remove portmask of IGMP packet from entry - entry.pmask &= ~(1L << (IGMP_I->rtl_tag.pmask >> 8)); // Swap bytes from network order, only 4 LSB count + entry.pmask &= ~(((uint16_t)1) << ((IGMP_I->rtl_tag.pmask >> 8) & 0x0f)); // Swap bytes from network order, only 4 LSB count // print_string("\nPort-Mask: "); print_short(entry.pmask); write_char('\n'); } else { print_string("IGMP Entry already deleted\n");