Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

r8152: allow userland to disable multicast

The rtl8152 driver does not disable multicasting when userspace asks
it to. For example:
$ ifconfig eth0 -multicast -allmulti
$ tcpdump -p -i eth0 # will still capture multicast frames

Fix by clearing the device multicast filter table when multicast and
allmulti are both unset.

Tested as follows:
- Set multicast on eth0 network interface
- verify that multicast packets are coming in:
$ tcpdump -p -i eth0
- Clear multicast and allmulti on eth0 network interface
- verify that no more multicast packets are coming in:
$ tcpdump -p -i eth0

Signed-off-by: Sven van Ashbrook <svenva@chromium.org>
Acked-by: Hayes Wang <hayeswang@realtek.com>
Link: https://lore.kernel.org/r/20220830045923.net-next.v1.1.I4fee0ac057083d4f848caf0fa3a9fd466fc374a0@changeid
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Sven van Ashbrook and committed by
Jakub Kicinski
7305b78a f029c781

+12 -8
+12 -8
drivers/net/usb/r8152.c
··· 2727 2727 ocp_data |= RCR_AM | RCR_AAP; 2728 2728 mc_filter[1] = 0xffffffff; 2729 2729 mc_filter[0] = 0xffffffff; 2730 - } else if ((netdev_mc_count(netdev) > multicast_filter_limit) || 2731 - (netdev->flags & IFF_ALLMULTI)) { 2730 + } else if ((netdev->flags & IFF_MULTICAST && 2731 + netdev_mc_count(netdev) > multicast_filter_limit) || 2732 + (netdev->flags & IFF_ALLMULTI)) { 2732 2733 /* Too many to filter perfectly -- accept all multicasts. */ 2733 2734 ocp_data |= RCR_AM; 2734 2735 mc_filter[1] = 0xffffffff; 2735 2736 mc_filter[0] = 0xffffffff; 2736 2737 } else { 2737 - struct netdev_hw_addr *ha; 2738 - 2739 2738 mc_filter[1] = 0; 2740 2739 mc_filter[0] = 0; 2741 - netdev_for_each_mc_addr(ha, netdev) { 2742 - int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; 2743 2740 2744 - mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); 2745 - ocp_data |= RCR_AM; 2741 + if (netdev->flags & IFF_MULTICAST) { 2742 + struct netdev_hw_addr *ha; 2743 + 2744 + netdev_for_each_mc_addr(ha, netdev) { 2745 + int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26; 2746 + 2747 + mc_filter[bit_nr >> 5] |= 1 << (bit_nr & 31); 2748 + ocp_data |= RCR_AM; 2749 + } 2746 2750 } 2747 2751 } 2748 2752