diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_fdb.c | 10 | ||||
-rw-r--r-- | net/bridge/br_private.h | 6 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 19 |
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); |
125 | skip_delete: | 133 | skip_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, | |||
585 | int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags); | 585 | int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags); |
586 | int br_vlan_delete(struct net_bridge *br, u16 vid); | 586 | int br_vlan_delete(struct net_bridge *br, u16 vid); |
587 | void br_vlan_flush(struct net_bridge *br); | 587 | void br_vlan_flush(struct net_bridge *br); |
588 | bool br_vlan_find(struct net_bridge *br, u16 vid); | ||
588 | int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); | 589 | int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val); |
589 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); | 590 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags); |
590 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid); | 591 | int 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 | ||
670 | static inline bool br_vlan_find(struct net_bridge *br, u16 vid) | ||
671 | { | ||
672 | return false; | ||
673 | } | ||
674 | |||
669 | static inline int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) | 675 | static 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 | ||
298 | bool 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 | |||
312 | out: | ||
313 | rcu_read_unlock(); | ||
314 | return found; | ||
315 | } | ||
316 | |||
298 | int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) | 317 | int br_vlan_filter_toggle(struct net_bridge *br, unsigned long val) |
299 | { | 318 | { |
300 | if (!rtnl_trylock()) | 319 | if (!rtnl_trylock()) |