aboutsummaryrefslogtreecommitdiffstats
path: root/net/bridge
diff options
context:
space:
mode:
Diffstat (limited to 'net/bridge')
-rw-r--r--net/bridge/br_fdb.c10
-rw-r--r--net/bridge/br_private.h6
-rw-r--r--net/bridge/br_vlan.c19
3 files changed, 34 insertions, 1 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c
index 96ab1d1748d0..b4005f5b28f4 100644
--- a/net/bridge/br_fdb.c
+++ b/net/bridge/br_fdb.c
@@ -114,12 +114,20 @@ void br_fdb_changeaddr(struct net_bridge_port *p, const unsigned char *newaddr)
114 if (op != p && 114 if (op != p &&
115 ether_addr_equal(op->dev->dev_addr, 115 ether_addr_equal(op->dev->dev_addr,
116 f->addr.addr) && 116 f->addr.addr) &&
117 nbp_vlan_find(op, vid)) { 117 (!vid || nbp_vlan_find(op, vid))) {
118 f->dst = op; 118 f->dst = op;
119 goto skip_delete; 119 goto skip_delete;
120 } 120 }
121 } 121 }
122 122
123 /* maybe bridge device has same hw addr? */
124 if (ether_addr_equal(br->dev->dev_addr,
125 f->addr.addr) &&
126 (!vid || br_vlan_find(br, vid))) {
127 f->dst = NULL;
128 goto skip_delete;
129 }
130
123 /* delete old one */ 131 /* delete old one */
124 fdb_delete(br, f); 132 fdb_delete(br, f);
125skip_delete: 133skip_delete:
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 939a59e15036..f91e1d9c8e92 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -585,6 +585,7 @@ struct sk_buff *br_handle_vlan(struct net_bridge *br,
585int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags); 585int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags);
586int br_vlan_delete(struct net_bridge *br, u16 vid); 586int br_vlan_delete(struct net_bridge *br, u16 vid);
587void br_vlan_flush(struct net_bridge *br); 587void br_vlan_flush(struct net_bridge *br);
588bool br_vlan_find(struct net_bridge *br, u16 vid);
588int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); 589int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val);
589int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); 590int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags);
590int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); 591int nbp_vlan_delete(struct net_bridge_port *port, u16 vid);
@@ -666,6 +667,11 @@ static inline void br_vlan_flush(struct net_bridge *br)
666{ 667{
667} 668}
668 669
670static inline bool br_vlan_find(struct net_bridge *br, u16 vid)
671{
672 return false;
673}
674
669static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) 675static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags)
670{ 676{
671 return -EOPNOTSUPP; 677 return -EOPNOTSUPP;
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index 4ca4d0a0151c..233ec1c6e9db 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -295,6 +295,25 @@ void br_vlan_flush(struct net_bridge *br)
295 __vlan_flush(pv); 295 __vlan_flush(pv);
296} 296}
297 297
298bool br_vlan_find(struct net_bridge *br, u16 vid)
299{
300 struct net_port_vlans *pv;
301 bool found = false;
302
303 rcu_read_lock();
304 pv = rcu_dereference(br->vlan_info);
305
306 if (!pv)
307 goto out;
308
309 if (test_bit(vid, pv->vlan_bitmap))
310 found = true;
311
312out:
313 rcu_read_unlock();
314 return found;
315}
316
298int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) 317int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val)
299{ 318{
300 if (!rtnl_trylock()) 319 if (!rtnl_trylock())