cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

br_multicast_eht.c (22467B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2// Copyright (c) 2020, Nikolay Aleksandrov <nikolay@nvidia.com>
      3#include <linux/err.h>
      4#include <linux/export.h>
      5#include <linux/if_ether.h>
      6#include <linux/igmp.h>
      7#include <linux/in.h>
      8#include <linux/jhash.h>
      9#include <linux/kernel.h>
     10#include <linux/log2.h>
     11#include <linux/netdevice.h>
     12#include <linux/netfilter_bridge.h>
     13#include <linux/random.h>
     14#include <linux/rculist.h>
     15#include <linux/skbuff.h>
     16#include <linux/slab.h>
     17#include <linux/timer.h>
     18#include <linux/inetdevice.h>
     19#include <linux/mroute.h>
     20#include <net/ip.h>
     21#include <net/switchdev.h>
     22#if IS_ENABLED(CONFIG_IPV6)
     23#include <linux/icmpv6.h>
     24#include <net/ipv6.h>
     25#include <net/mld.h>
     26#include <net/ip6_checksum.h>
     27#include <net/addrconf.h>
     28#endif
     29
     30#include "br_private.h"
     31#include "br_private_mcast_eht.h"
     32
     33static bool br_multicast_del_eht_set_entry(struct net_bridge_port_group *pg,
     34					   union net_bridge_eht_addr *src_addr,
     35					   union net_bridge_eht_addr *h_addr);
     36static void br_multicast_create_eht_set_entry(const struct net_bridge_mcast *brmctx,
     37					      struct net_bridge_port_group *pg,
     38					      union net_bridge_eht_addr *src_addr,
     39					      union net_bridge_eht_addr *h_addr,
     40					      int filter_mode,
     41					      bool allow_zero_src);
     42
     43static struct net_bridge_group_eht_host *
     44br_multicast_eht_host_lookup(struct net_bridge_port_group *pg,
     45			     union net_bridge_eht_addr *h_addr)
     46{
     47	struct rb_node *node = pg->eht_host_tree.rb_node;
     48
     49	while (node) {
     50		struct net_bridge_group_eht_host *this;
     51		int result;
     52
     53		this = rb_entry(node, struct net_bridge_group_eht_host,
     54				rb_node);
     55		result = memcmp(h_addr, &this->h_addr, sizeof(*h_addr));
     56		if (result < 0)
     57			node = node->rb_left;
     58		else if (result > 0)
     59			node = node->rb_right;
     60		else
     61			return this;
     62	}
     63
     64	return NULL;
     65}
     66
     67static int br_multicast_eht_host_filter_mode(struct net_bridge_port_group *pg,
     68					     union net_bridge_eht_addr *h_addr)
     69{
     70	struct net_bridge_group_eht_host *eht_host;
     71
     72	eht_host = br_multicast_eht_host_lookup(pg, h_addr);
     73	if (!eht_host)
     74		return MCAST_INCLUDE;
     75
     76	return eht_host->filter_mode;
     77}
     78
     79static struct net_bridge_group_eht_set_entry *
     80br_multicast_eht_set_entry_lookup(struct net_bridge_group_eht_set *eht_set,
     81				  union net_bridge_eht_addr *h_addr)
     82{
     83	struct rb_node *node = eht_set->entry_tree.rb_node;
     84
     85	while (node) {
     86		struct net_bridge_group_eht_set_entry *this;
     87		int result;
     88
     89		this = rb_entry(node, struct net_bridge_group_eht_set_entry,
     90				rb_node);
     91		result = memcmp(h_addr, &this->h_addr, sizeof(*h_addr));
     92		if (result < 0)
     93			node = node->rb_left;
     94		else if (result > 0)
     95			node = node->rb_right;
     96		else
     97			return this;
     98	}
     99
    100	return NULL;
    101}
    102
    103static struct net_bridge_group_eht_set *
    104br_multicast_eht_set_lookup(struct net_bridge_port_group *pg,
    105			    union net_bridge_eht_addr *src_addr)
    106{
    107	struct rb_node *node = pg->eht_set_tree.rb_node;
    108
    109	while (node) {
    110		struct net_bridge_group_eht_set *this;
    111		int result;
    112
    113		this = rb_entry(node, struct net_bridge_group_eht_set,
    114				rb_node);
    115		result = memcmp(src_addr, &this->src_addr, sizeof(*src_addr));
    116		if (result < 0)
    117			node = node->rb_left;
    118		else if (result > 0)
    119			node = node->rb_right;
    120		else
    121			return this;
    122	}
    123
    124	return NULL;
    125}
    126
    127static void __eht_destroy_host(struct net_bridge_group_eht_host *eht_host)
    128{
    129	WARN_ON(!hlist_empty(&eht_host->set_entries));
    130
    131	br_multicast_eht_hosts_dec(eht_host->pg);
    132
    133	rb_erase(&eht_host->rb_node, &eht_host->pg->eht_host_tree);
    134	RB_CLEAR_NODE(&eht_host->rb_node);
    135	kfree(eht_host);
    136}
    137
    138static void br_multicast_destroy_eht_set_entry(struct net_bridge_mcast_gc *gc)
    139{
    140	struct net_bridge_group_eht_set_entry *set_h;
    141
    142	set_h = container_of(gc, struct net_bridge_group_eht_set_entry, mcast_gc);
    143	WARN_ON(!RB_EMPTY_NODE(&set_h->rb_node));
    144
    145	del_timer_sync(&set_h->timer);
    146	kfree(set_h);
    147}
    148
    149static void br_multicast_destroy_eht_set(struct net_bridge_mcast_gc *gc)
    150{
    151	struct net_bridge_group_eht_set *eht_set;
    152
    153	eht_set = container_of(gc, struct net_bridge_group_eht_set, mcast_gc);
    154	WARN_ON(!RB_EMPTY_NODE(&eht_set->rb_node));
    155	WARN_ON(!RB_EMPTY_ROOT(&eht_set->entry_tree));
    156
    157	del_timer_sync(&eht_set->timer);
    158	kfree(eht_set);
    159}
    160
    161static void __eht_del_set_entry(struct net_bridge_group_eht_set_entry *set_h)
    162{
    163	struct net_bridge_group_eht_host *eht_host = set_h->h_parent;
    164	union net_bridge_eht_addr zero_addr;
    165
    166	rb_erase(&set_h->rb_node, &set_h->eht_set->entry_tree);
    167	RB_CLEAR_NODE(&set_h->rb_node);
    168	hlist_del_init(&set_h->host_list);
    169	memset(&zero_addr, 0, sizeof(zero_addr));
    170	if (memcmp(&set_h->h_addr, &zero_addr, sizeof(zero_addr)))
    171		eht_host->num_entries--;
    172	hlist_add_head(&set_h->mcast_gc.gc_node, &set_h->br->mcast_gc_list);
    173	queue_work(system_long_wq, &set_h->br->mcast_gc_work);
    174
    175	if (hlist_empty(&eht_host->set_entries))
    176		__eht_destroy_host(eht_host);
    177}
    178
    179static void br_multicast_del_eht_set(struct net_bridge_group_eht_set *eht_set)
    180{
    181	struct net_bridge_group_eht_set_entry *set_h;
    182	struct rb_node *node;
    183
    184	while ((node = rb_first(&eht_set->entry_tree))) {
    185		set_h = rb_entry(node, struct net_bridge_group_eht_set_entry,
    186				 rb_node);
    187		__eht_del_set_entry(set_h);
    188	}
    189
    190	rb_erase(&eht_set->rb_node, &eht_set->pg->eht_set_tree);
    191	RB_CLEAR_NODE(&eht_set->rb_node);
    192	hlist_add_head(&eht_set->mcast_gc.gc_node, &eht_set->br->mcast_gc_list);
    193	queue_work(system_long_wq, &eht_set->br->mcast_gc_work);
    194}
    195
    196void br_multicast_eht_clean_sets(struct net_bridge_port_group *pg)
    197{
    198	struct net_bridge_group_eht_set *eht_set;
    199	struct rb_node *node;
    200
    201	while ((node = rb_first(&pg->eht_set_tree))) {
    202		eht_set = rb_entry(node, struct net_bridge_group_eht_set,
    203				   rb_node);
    204		br_multicast_del_eht_set(eht_set);
    205	}
    206}
    207
    208static void br_multicast_eht_set_entry_expired(struct timer_list *t)
    209{
    210	struct net_bridge_group_eht_set_entry *set_h = from_timer(set_h, t, timer);
    211	struct net_bridge *br = set_h->br;
    212
    213	spin_lock(&br->multicast_lock);
    214	if (RB_EMPTY_NODE(&set_h->rb_node) || timer_pending(&set_h->timer))
    215		goto out;
    216
    217	br_multicast_del_eht_set_entry(set_h->eht_set->pg,
    218				       &set_h->eht_set->src_addr,
    219				       &set_h->h_addr);
    220out:
    221	spin_unlock(&br->multicast_lock);
    222}
    223
    224static void br_multicast_eht_set_expired(struct timer_list *t)
    225{
    226	struct net_bridge_group_eht_set *eht_set = from_timer(eht_set, t,
    227							      timer);
    228	struct net_bridge *br = eht_set->br;
    229
    230	spin_lock(&br->multicast_lock);
    231	if (RB_EMPTY_NODE(&eht_set->rb_node) || timer_pending(&eht_set->timer))
    232		goto out;
    233
    234	br_multicast_del_eht_set(eht_set);
    235out:
    236	spin_unlock(&br->multicast_lock);
    237}
    238
    239static struct net_bridge_group_eht_host *
    240__eht_lookup_create_host(struct net_bridge_port_group *pg,
    241			 union net_bridge_eht_addr *h_addr,
    242			 unsigned char filter_mode)
    243{
    244	struct rb_node **link = &pg->eht_host_tree.rb_node, *parent = NULL;
    245	struct net_bridge_group_eht_host *eht_host;
    246
    247	while (*link) {
    248		struct net_bridge_group_eht_host *this;
    249		int result;
    250
    251		this = rb_entry(*link, struct net_bridge_group_eht_host,
    252				rb_node);
    253		result = memcmp(h_addr, &this->h_addr, sizeof(*h_addr));
    254		parent = *link;
    255		if (result < 0)
    256			link = &((*link)->rb_left);
    257		else if (result > 0)
    258			link = &((*link)->rb_right);
    259		else
    260			return this;
    261	}
    262
    263	if (br_multicast_eht_hosts_over_limit(pg))
    264		return NULL;
    265
    266	eht_host = kzalloc(sizeof(*eht_host), GFP_ATOMIC);
    267	if (!eht_host)
    268		return NULL;
    269
    270	memcpy(&eht_host->h_addr, h_addr, sizeof(*h_addr));
    271	INIT_HLIST_HEAD(&eht_host->set_entries);
    272	eht_host->pg = pg;
    273	eht_host->filter_mode = filter_mode;
    274
    275	rb_link_node(&eht_host->rb_node, parent, link);
    276	rb_insert_color(&eht_host->rb_node, &pg->eht_host_tree);
    277
    278	br_multicast_eht_hosts_inc(pg);
    279
    280	return eht_host;
    281}
    282
    283static struct net_bridge_group_eht_set_entry *
    284__eht_lookup_create_set_entry(struct net_bridge *br,
    285			      struct net_bridge_group_eht_set *eht_set,
    286			      struct net_bridge_group_eht_host *eht_host,
    287			      bool allow_zero_src)
    288{
    289	struct rb_node **link = &eht_set->entry_tree.rb_node, *parent = NULL;
    290	struct net_bridge_group_eht_set_entry *set_h;
    291
    292	while (*link) {
    293		struct net_bridge_group_eht_set_entry *this;
    294		int result;
    295
    296		this = rb_entry(*link, struct net_bridge_group_eht_set_entry,
    297				rb_node);
    298		result = memcmp(&eht_host->h_addr, &this->h_addr,
    299				sizeof(union net_bridge_eht_addr));
    300		parent = *link;
    301		if (result < 0)
    302			link = &((*link)->rb_left);
    303		else if (result > 0)
    304			link = &((*link)->rb_right);
    305		else
    306			return this;
    307	}
    308
    309	/* always allow auto-created zero entry */
    310	if (!allow_zero_src && eht_host->num_entries >= PG_SRC_ENT_LIMIT)
    311		return NULL;
    312
    313	set_h = kzalloc(sizeof(*set_h), GFP_ATOMIC);
    314	if (!set_h)
    315		return NULL;
    316
    317	memcpy(&set_h->h_addr, &eht_host->h_addr,
    318	       sizeof(union net_bridge_eht_addr));
    319	set_h->mcast_gc.destroy = br_multicast_destroy_eht_set_entry;
    320	set_h->eht_set = eht_set;
    321	set_h->h_parent = eht_host;
    322	set_h->br = br;
    323	timer_setup(&set_h->timer, br_multicast_eht_set_entry_expired, 0);
    324
    325	hlist_add_head(&set_h->host_list, &eht_host->set_entries);
    326	rb_link_node(&set_h->rb_node, parent, link);
    327	rb_insert_color(&set_h->rb_node, &eht_set->entry_tree);
    328	/* we must not count the auto-created zero entry otherwise we won't be
    329	 * able to track the full list of PG_SRC_ENT_LIMIT entries
    330	 */
    331	if (!allow_zero_src)
    332		eht_host->num_entries++;
    333
    334	return set_h;
    335}
    336
    337static struct net_bridge_group_eht_set *
    338__eht_lookup_create_set(struct net_bridge_port_group *pg,
    339			union net_bridge_eht_addr *src_addr)
    340{
    341	struct rb_node **link = &pg->eht_set_tree.rb_node, *parent = NULL;
    342	struct net_bridge_group_eht_set *eht_set;
    343
    344	while (*link) {
    345		struct net_bridge_group_eht_set *this;
    346		int result;
    347
    348		this = rb_entry(*link, struct net_bridge_group_eht_set,
    349				rb_node);
    350		result = memcmp(src_addr, &this->src_addr, sizeof(*src_addr));
    351		parent = *link;
    352		if (result < 0)
    353			link = &((*link)->rb_left);
    354		else if (result > 0)
    355			link = &((*link)->rb_right);
    356		else
    357			return this;
    358	}
    359
    360	eht_set = kzalloc(sizeof(*eht_set), GFP_ATOMIC);
    361	if (!eht_set)
    362		return NULL;
    363
    364	memcpy(&eht_set->src_addr, src_addr, sizeof(*src_addr));
    365	eht_set->mcast_gc.destroy = br_multicast_destroy_eht_set;
    366	eht_set->pg = pg;
    367	eht_set->br = pg->key.port->br;
    368	eht_set->entry_tree = RB_ROOT;
    369	timer_setup(&eht_set->timer, br_multicast_eht_set_expired, 0);
    370
    371	rb_link_node(&eht_set->rb_node, parent, link);
    372	rb_insert_color(&eht_set->rb_node, &pg->eht_set_tree);
    373
    374	return eht_set;
    375}
    376
    377static void br_multicast_ip_src_to_eht_addr(const struct br_ip *src,
    378					    union net_bridge_eht_addr *dest)
    379{
    380	switch (src->proto) {
    381	case htons(ETH_P_IP):
    382		dest->ip4 = src->src.ip4;
    383		break;
    384#if IS_ENABLED(CONFIG_IPV6)
    385	case htons(ETH_P_IPV6):
    386		memcpy(&dest->ip6, &src->src.ip6, sizeof(struct in6_addr));
    387		break;
    388#endif
    389	}
    390}
    391
    392static void br_eht_convert_host_filter_mode(const struct net_bridge_mcast *brmctx,
    393					    struct net_bridge_port_group *pg,
    394					    union net_bridge_eht_addr *h_addr,
    395					    int filter_mode)
    396{
    397	struct net_bridge_group_eht_host *eht_host;
    398	union net_bridge_eht_addr zero_addr;
    399
    400	eht_host = br_multicast_eht_host_lookup(pg, h_addr);
    401	if (eht_host)
    402		eht_host->filter_mode = filter_mode;
    403
    404	memset(&zero_addr, 0, sizeof(zero_addr));
    405	switch (filter_mode) {
    406	case MCAST_INCLUDE:
    407		br_multicast_del_eht_set_entry(pg, &zero_addr, h_addr);
    408		break;
    409	case MCAST_EXCLUDE:
    410		br_multicast_create_eht_set_entry(brmctx, pg, &zero_addr,
    411						  h_addr, MCAST_EXCLUDE,
    412						  true);
    413		break;
    414	}
    415}
    416
    417static void br_multicast_create_eht_set_entry(const struct net_bridge_mcast *brmctx,
    418					      struct net_bridge_port_group *pg,
    419					      union net_bridge_eht_addr *src_addr,
    420					      union net_bridge_eht_addr *h_addr,
    421					      int filter_mode,
    422					      bool allow_zero_src)
    423{
    424	struct net_bridge_group_eht_set_entry *set_h;
    425	struct net_bridge_group_eht_host *eht_host;
    426	struct net_bridge *br = pg->key.port->br;
    427	struct net_bridge_group_eht_set *eht_set;
    428	union net_bridge_eht_addr zero_addr;
    429
    430	memset(&zero_addr, 0, sizeof(zero_addr));
    431	if (!allow_zero_src && !memcmp(src_addr, &zero_addr, sizeof(zero_addr)))
    432		return;
    433
    434	eht_set = __eht_lookup_create_set(pg, src_addr);
    435	if (!eht_set)
    436		return;
    437
    438	eht_host = __eht_lookup_create_host(pg, h_addr, filter_mode);
    439	if (!eht_host)
    440		goto fail_host;
    441
    442	set_h = __eht_lookup_create_set_entry(br, eht_set, eht_host,
    443					      allow_zero_src);
    444	if (!set_h)
    445		goto fail_set_entry;
    446
    447	mod_timer(&set_h->timer, jiffies + br_multicast_gmi(brmctx));
    448	mod_timer(&eht_set->timer, jiffies + br_multicast_gmi(brmctx));
    449
    450	return;
    451
    452fail_set_entry:
    453	if (hlist_empty(&eht_host->set_entries))
    454		__eht_destroy_host(eht_host);
    455fail_host:
    456	if (RB_EMPTY_ROOT(&eht_set->entry_tree))
    457		br_multicast_del_eht_set(eht_set);
    458}
    459
    460static bool br_multicast_del_eht_set_entry(struct net_bridge_port_group *pg,
    461					   union net_bridge_eht_addr *src_addr,
    462					   union net_bridge_eht_addr *h_addr)
    463{
    464	struct net_bridge_group_eht_set_entry *set_h;
    465	struct net_bridge_group_eht_set *eht_set;
    466	bool set_deleted = false;
    467
    468	eht_set = br_multicast_eht_set_lookup(pg, src_addr);
    469	if (!eht_set)
    470		goto out;
    471
    472	set_h = br_multicast_eht_set_entry_lookup(eht_set, h_addr);
    473	if (!set_h)
    474		goto out;
    475
    476	__eht_del_set_entry(set_h);
    477
    478	if (RB_EMPTY_ROOT(&eht_set->entry_tree)) {
    479		br_multicast_del_eht_set(eht_set);
    480		set_deleted = true;
    481	}
    482
    483out:
    484	return set_deleted;
    485}
    486
    487static void br_multicast_del_eht_host(struct net_bridge_port_group *pg,
    488				      union net_bridge_eht_addr *h_addr)
    489{
    490	struct net_bridge_group_eht_set_entry *set_h;
    491	struct net_bridge_group_eht_host *eht_host;
    492	struct hlist_node *tmp;
    493
    494	eht_host = br_multicast_eht_host_lookup(pg, h_addr);
    495	if (!eht_host)
    496		return;
    497
    498	hlist_for_each_entry_safe(set_h, tmp, &eht_host->set_entries, host_list)
    499		br_multicast_del_eht_set_entry(set_h->eht_set->pg,
    500					       &set_h->eht_set->src_addr,
    501					       &set_h->h_addr);
    502}
    503
    504/* create new set entries from reports */
    505static void __eht_create_set_entries(const struct net_bridge_mcast *brmctx,
    506				     struct net_bridge_port_group *pg,
    507				     union net_bridge_eht_addr *h_addr,
    508				     void *srcs,
    509				     u32 nsrcs,
    510				     size_t addr_size,
    511				     int filter_mode)
    512{
    513	union net_bridge_eht_addr eht_src_addr;
    514	u32 src_idx;
    515
    516	memset(&eht_src_addr, 0, sizeof(eht_src_addr));
    517	for (src_idx = 0; src_idx < nsrcs; src_idx++) {
    518		memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size);
    519		br_multicast_create_eht_set_entry(brmctx, pg, &eht_src_addr,
    520						  h_addr, filter_mode,
    521						  false);
    522	}
    523}
    524
    525/* delete existing set entries and their (S,G) entries if they were the last */
    526static bool __eht_del_set_entries(struct net_bridge_port_group *pg,
    527				  union net_bridge_eht_addr *h_addr,
    528				  void *srcs,
    529				  u32 nsrcs,
    530				  size_t addr_size)
    531{
    532	union net_bridge_eht_addr eht_src_addr;
    533	struct net_bridge_group_src *src_ent;
    534	bool changed = false;
    535	struct br_ip src_ip;
    536	u32 src_idx;
    537
    538	memset(&eht_src_addr, 0, sizeof(eht_src_addr));
    539	memset(&src_ip, 0, sizeof(src_ip));
    540	src_ip.proto = pg->key.addr.proto;
    541	for (src_idx = 0; src_idx < nsrcs; src_idx++) {
    542		memcpy(&eht_src_addr, srcs + (src_idx * addr_size), addr_size);
    543		if (!br_multicast_del_eht_set_entry(pg, &eht_src_addr, h_addr))
    544			continue;
    545		memcpy(&src_ip, srcs + (src_idx * addr_size), addr_size);
    546		src_ent = br_multicast_find_group_src(pg, &src_ip);
    547		if (!src_ent)
    548			continue;
    549		br_multicast_del_group_src(src_ent, true);
    550		changed = true;
    551	}
    552
    553	return changed;
    554}
    555
    556static bool br_multicast_eht_allow(const struct net_bridge_mcast *brmctx,
    557				   struct net_bridge_port_group *pg,
    558				   union net_bridge_eht_addr *h_addr,
    559				   void *srcs,
    560				   u32 nsrcs,
    561				   size_t addr_size)
    562{
    563	bool changed = false;
    564
    565	switch (br_multicast_eht_host_filter_mode(pg, h_addr)) {
    566	case MCAST_INCLUDE:
    567		__eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs,
    568					 addr_size, MCAST_INCLUDE);
    569		break;
    570	case MCAST_EXCLUDE:
    571		changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs,
    572						addr_size);
    573		break;
    574	}
    575
    576	return changed;
    577}
    578
    579static bool br_multicast_eht_block(const struct net_bridge_mcast *brmctx,
    580				   struct net_bridge_port_group *pg,
    581				   union net_bridge_eht_addr *h_addr,
    582				   void *srcs,
    583				   u32 nsrcs,
    584				   size_t addr_size)
    585{
    586	bool changed = false;
    587
    588	switch (br_multicast_eht_host_filter_mode(pg, h_addr)) {
    589	case MCAST_INCLUDE:
    590		changed = __eht_del_set_entries(pg, h_addr, srcs, nsrcs,
    591						addr_size);
    592		break;
    593	case MCAST_EXCLUDE:
    594		__eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
    595					 MCAST_EXCLUDE);
    596		break;
    597	}
    598
    599	return changed;
    600}
    601
    602/* flush_entries is true when changing mode */
    603static bool __eht_inc_exc(const struct net_bridge_mcast *brmctx,
    604			  struct net_bridge_port_group *pg,
    605			  union net_bridge_eht_addr *h_addr,
    606			  void *srcs,
    607			  u32 nsrcs,
    608			  size_t addr_size,
    609			  unsigned char filter_mode,
    610			  bool to_report)
    611{
    612	bool changed = false, flush_entries = to_report;
    613	union net_bridge_eht_addr eht_src_addr;
    614
    615	if (br_multicast_eht_host_filter_mode(pg, h_addr) != filter_mode)
    616		flush_entries = true;
    617
    618	memset(&eht_src_addr, 0, sizeof(eht_src_addr));
    619	/* if we're changing mode del host and its entries */
    620	if (flush_entries)
    621		br_multicast_del_eht_host(pg, h_addr);
    622	__eht_create_set_entries(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
    623				 filter_mode);
    624	/* we can be missing sets only if we've deleted some entries */
    625	if (flush_entries) {
    626		struct net_bridge_group_eht_set *eht_set;
    627		struct net_bridge_group_src *src_ent;
    628		struct hlist_node *tmp;
    629
    630		hlist_for_each_entry_safe(src_ent, tmp, &pg->src_list, node) {
    631			br_multicast_ip_src_to_eht_addr(&src_ent->addr,
    632							&eht_src_addr);
    633			if (!br_multicast_eht_set_lookup(pg, &eht_src_addr)) {
    634				br_multicast_del_group_src(src_ent, true);
    635				changed = true;
    636				continue;
    637			}
    638			/* this is an optimization for TO_INCLUDE where we lower
    639			 * the set's timeout to LMQT to catch timeout hosts:
    640			 * - host A (timing out): set entries X, Y
    641			 * - host B: set entry Z (new from current TO_INCLUDE)
    642			 *           sends BLOCK Z after LMQT but host A's EHT
    643			 *           entries still exist (unless lowered to LMQT
    644			 *           so they can timeout with the S,Gs)
    645			 * => we wait another LMQT, when we can just delete the
    646			 *    group immediately
    647			 */
    648			if (!(src_ent->flags & BR_SGRP_F_SEND) ||
    649			    filter_mode != MCAST_INCLUDE ||
    650			    !to_report)
    651				continue;
    652			eht_set = br_multicast_eht_set_lookup(pg,
    653							      &eht_src_addr);
    654			if (!eht_set)
    655				continue;
    656			mod_timer(&eht_set->timer, jiffies + br_multicast_lmqt(brmctx));
    657		}
    658	}
    659
    660	return changed;
    661}
    662
    663static bool br_multicast_eht_inc(const struct net_bridge_mcast *brmctx,
    664				 struct net_bridge_port_group *pg,
    665				 union net_bridge_eht_addr *h_addr,
    666				 void *srcs,
    667				 u32 nsrcs,
    668				 size_t addr_size,
    669				 bool to_report)
    670{
    671	bool changed;
    672
    673	changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
    674				MCAST_INCLUDE, to_report);
    675	br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_INCLUDE);
    676
    677	return changed;
    678}
    679
    680static bool br_multicast_eht_exc(const struct net_bridge_mcast *brmctx,
    681				 struct net_bridge_port_group *pg,
    682				 union net_bridge_eht_addr *h_addr,
    683				 void *srcs,
    684				 u32 nsrcs,
    685				 size_t addr_size,
    686				 bool to_report)
    687{
    688	bool changed;
    689
    690	changed = __eht_inc_exc(brmctx, pg, h_addr, srcs, nsrcs, addr_size,
    691				MCAST_EXCLUDE, to_report);
    692	br_eht_convert_host_filter_mode(brmctx, pg, h_addr, MCAST_EXCLUDE);
    693
    694	return changed;
    695}
    696
    697static bool __eht_ip4_handle(const struct net_bridge_mcast *brmctx,
    698			     struct net_bridge_port_group *pg,
    699			     union net_bridge_eht_addr *h_addr,
    700			     void *srcs,
    701			     u32 nsrcs,
    702			     int grec_type)
    703{
    704	bool changed = false, to_report = false;
    705
    706	switch (grec_type) {
    707	case IGMPV3_ALLOW_NEW_SOURCES:
    708		br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs,
    709				       sizeof(__be32));
    710		break;
    711	case IGMPV3_BLOCK_OLD_SOURCES:
    712		changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs,
    713						 sizeof(__be32));
    714		break;
    715	case IGMPV3_CHANGE_TO_INCLUDE:
    716		to_report = true;
    717		fallthrough;
    718	case IGMPV3_MODE_IS_INCLUDE:
    719		changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs,
    720					       sizeof(__be32), to_report);
    721		break;
    722	case IGMPV3_CHANGE_TO_EXCLUDE:
    723		to_report = true;
    724		fallthrough;
    725	case IGMPV3_MODE_IS_EXCLUDE:
    726		changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs,
    727					       sizeof(__be32), to_report);
    728		break;
    729	}
    730
    731	return changed;
    732}
    733
    734#if IS_ENABLED(CONFIG_IPV6)
    735static bool __eht_ip6_handle(const struct net_bridge_mcast *brmctx,
    736			     struct net_bridge_port_group *pg,
    737			     union net_bridge_eht_addr *h_addr,
    738			     void *srcs,
    739			     u32 nsrcs,
    740			     int grec_type)
    741{
    742	bool changed = false, to_report = false;
    743
    744	switch (grec_type) {
    745	case MLD2_ALLOW_NEW_SOURCES:
    746		br_multicast_eht_allow(brmctx, pg, h_addr, srcs, nsrcs,
    747				       sizeof(struct in6_addr));
    748		break;
    749	case MLD2_BLOCK_OLD_SOURCES:
    750		changed = br_multicast_eht_block(brmctx, pg, h_addr, srcs, nsrcs,
    751						 sizeof(struct in6_addr));
    752		break;
    753	case MLD2_CHANGE_TO_INCLUDE:
    754		to_report = true;
    755		fallthrough;
    756	case MLD2_MODE_IS_INCLUDE:
    757		changed = br_multicast_eht_inc(brmctx, pg, h_addr, srcs, nsrcs,
    758					       sizeof(struct in6_addr),
    759					       to_report);
    760		break;
    761	case MLD2_CHANGE_TO_EXCLUDE:
    762		to_report = true;
    763		fallthrough;
    764	case MLD2_MODE_IS_EXCLUDE:
    765		changed = br_multicast_eht_exc(brmctx, pg, h_addr, srcs, nsrcs,
    766					       sizeof(struct in6_addr),
    767					       to_report);
    768		break;
    769	}
    770
    771	return changed;
    772}
    773#endif
    774
    775/* true means an entry was deleted */
    776bool br_multicast_eht_handle(const struct net_bridge_mcast *brmctx,
    777			     struct net_bridge_port_group *pg,
    778			     void *h_addr,
    779			     void *srcs,
    780			     u32 nsrcs,
    781			     size_t addr_size,
    782			     int grec_type)
    783{
    784	bool eht_enabled = !!(pg->key.port->flags & BR_MULTICAST_FAST_LEAVE);
    785	union net_bridge_eht_addr eht_host_addr;
    786	bool changed = false;
    787
    788	if (!eht_enabled)
    789		goto out;
    790
    791	memset(&eht_host_addr, 0, sizeof(eht_host_addr));
    792	memcpy(&eht_host_addr, h_addr, addr_size);
    793	if (addr_size == sizeof(__be32))
    794		changed = __eht_ip4_handle(brmctx, pg, &eht_host_addr, srcs,
    795					   nsrcs, grec_type);
    796#if IS_ENABLED(CONFIG_IPV6)
    797	else
    798		changed = __eht_ip6_handle(brmctx, pg, &eht_host_addr, srcs,
    799					   nsrcs, grec_type);
    800#endif
    801
    802out:
    803	return changed;
    804}
    805
    806int br_multicast_eht_set_hosts_limit(struct net_bridge_port *p,
    807				     u32 eht_hosts_limit)
    808{
    809	struct net_bridge *br = p->br;
    810
    811	if (!eht_hosts_limit)
    812		return -EINVAL;
    813
    814	spin_lock_bh(&br->multicast_lock);
    815	p->multicast_eht_hosts_limit = eht_hosts_limit;
    816	spin_unlock_bh(&br->multicast_lock);
    817
    818	return 0;
    819}