--- zzzz-none-000/linux-3.10.107/net/bridge/br_mdb.c 2017-06-27 09:49:32.000000000 +0000 +++ vr9-7490-729/linux-3.10.107/net/bridge/br_mdb.c 2021-11-10 11:53:56.000000000 +0000 @@ -5,10 +5,12 @@ #include #include #include +#include #include #include #if IS_ENABLED(CONFIG_IPV6) #include +#include #endif #include "br_private.h" @@ -61,7 +63,8 @@ for (i = 0; i < mdb->max; i++) { struct net_bridge_mdb_entry *mp; - struct net_bridge_port_group *p, **pp; + struct net_bridge_port_group *p; + struct net_bridge_port_group __rcu **pp; struct net_bridge_port *port; hlist_for_each_entry_rcu(mp, &mdb->mhash[i], hlist[mdb->ver]) { @@ -253,7 +256,7 @@ return false; #if IS_ENABLED(CONFIG_IPV6) } else if (entry->addr.proto == htons(ETH_P_IPV6)) { - if (!ipv6_is_transient_multicast(&entry->addr.u.ip6)) + if (ipv6_addr_is_ll_all_nodes(&entry->addr.u.ip6)) return false; #endif } else @@ -375,6 +378,10 @@ else ip.u.ip6 = entry->addr.u.ip6; #endif + if (is_vlan_dev(dev)) + ip.vid = vlan_dev_vlan_id(dev); + else + ip.vid = 0; spin_lock_bh(&br->multicast_lock); ret = br_mdb_add_group(br, p, &ip, entry->state); @@ -402,29 +409,42 @@ return err; } -static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) +static int __br_mdb_del(struct net *net, struct net_bridge *br, struct br_mdb_entry *entry) { struct net_bridge_mdb_htable *mdb; struct net_bridge_mdb_entry *mp; struct net_bridge_port_group *p; struct net_bridge_port_group __rcu **pp; + struct net_device *dev; struct br_ip ip; int err = -EINVAL; if (!netif_running(br->dev) || br->multicast_disabled) return -EINVAL; - if (timer_pending(&br->multicast_querier_timer)) - return -EBUSY; + dev = __dev_get_by_index(net, entry->ifindex); + if (!dev) + return -ENODEV; memset(&ip, 0, sizeof(ip)); ip.proto = entry->addr.proto; - if (ip.proto == htons(ETH_P_IP)) + if (ip.proto == htons(ETH_P_IP)) { + if (timer_pending(&br->ip4_other_query.timer)) + return -EBUSY; + ip.u.ip4 = entry->addr.u.ip4; #if IS_ENABLED(CONFIG_IPV6) - else + } else { + if (timer_pending(&br->ip6_other_query.timer)) + return -EBUSY; + ip.u.ip6 = entry->addr.u.ip6; #endif + } + if (is_vlan_dev(dev)) + ip.vid = vlan_dev_vlan_id(dev); + else + ip.vid = 0; spin_lock_bh(&br->multicast_lock); mdb = mlock_dereference(br->mdb, br); @@ -443,9 +463,7 @@ goto unlock; rcu_assign_pointer(*pp, p->next); - hlist_del_init(&p->mglist); - del_timer(&p->timer); - call_rcu_bh(&p->rcu, br_multicast_free_pg); + br_multicast_delete_pg(p); err = 0; if (!mp->ports && !mp->mglist && @@ -461,6 +479,7 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh) { + struct net *net = sock_net(skb->sk); struct net_device *dev; struct br_mdb_entry *entry; struct net_bridge *br; @@ -472,7 +491,7 @@ br = netdev_priv(dev); - err = __br_mdb_del(br, entry); + err = __br_mdb_del(net, br, entry); if (!err) __br_mdb_notify(dev, entry, RTM_DELMDB); return err;