diff options
Diffstat (limited to 'net/bridge')
-rw-r--r-- | net/bridge/br_fdb.c | 4 | ||||
-rw-r--r-- | net/bridge/br_mdb.c | 2 | ||||
-rw-r--r-- | net/bridge/br_multicast.c | 38 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 2 | ||||
-rw-r--r-- | net/bridge/br_private.h | 5 | ||||
-rw-r--r-- | net/bridge/br_stp_if.c | 2 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 125 |
7 files changed, 99 insertions, 79 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index ffd5874f2592..33e8f23acddd 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -700,7 +700,7 @@ int br_fdb_add(struct ndmsg *ndm, struct nlattr *tb[], | |||
700 | 700 | ||
701 | vid = nla_get_u16(tb[NDA_VLAN]); | 701 | vid = nla_get_u16(tb[NDA_VLAN]); |
702 | 702 | ||
703 | if (vid >= VLAN_N_VID) { | 703 | if (!vid || vid >= VLAN_VID_MASK) { |
704 | pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n", | 704 | pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n", |
705 | vid); | 705 | vid); |
706 | return -EINVAL; | 706 | return -EINVAL; |
@@ -794,7 +794,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], | |||
794 | 794 | ||
795 | vid = nla_get_u16(tb[NDA_VLAN]); | 795 | vid = nla_get_u16(tb[NDA_VLAN]); |
796 | 796 | ||
797 | if (vid >= VLAN_N_VID) { | 797 | if (!vid || vid >= VLAN_VID_MASK) { |
798 | pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n", | 798 | pr_info("bridge: RTM_NEWNEIGH with invalid vlan id %d\n", |
799 | vid); | 799 | vid); |
800 | return -EINVAL; | 800 | return -EINVAL; |
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c index 85a09bb5ca51..b7b1914dfa25 100644 --- a/net/bridge/br_mdb.c +++ b/net/bridge/br_mdb.c | |||
@@ -453,7 +453,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry) | |||
453 | call_rcu_bh(&p->rcu, br_multicast_free_pg); | 453 | call_rcu_bh(&p->rcu, br_multicast_free_pg); |
454 | err = 0; | 454 | err = 0; |
455 | 455 | ||
456 | if (!mp->ports && !mp->mglist && mp->timer_armed && | 456 | if (!mp->ports && !mp->mglist && |
457 | netif_running(br->dev)) | 457 | netif_running(br->dev)) |
458 | mod_timer(&mp->timer, jiffies); | 458 | mod_timer(&mp->timer, jiffies); |
459 | break; | 459 | break; |
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c index 005d876dd86c..0513ef3ce667 100644 --- a/net/bridge/br_multicast.c +++ b/net/bridge/br_multicast.c | |||
@@ -272,7 +272,7 @@ static void br_multicast_del_pg(struct net_bridge *br, | |||
272 | del_timer(&p->timer); | 272 | del_timer(&p->timer); |
273 | call_rcu_bh(&p->rcu, br_multicast_free_pg); | 273 | call_rcu_bh(&p->rcu, br_multicast_free_pg); |
274 | 274 | ||
275 | if (!mp->ports && !mp->mglist && mp->timer_armed && | 275 | if (!mp->ports && !mp->mglist && |
276 | netif_running(br->dev)) | 276 | netif_running(br->dev)) |
277 | mod_timer(&mp->timer, jiffies); | 277 | mod_timer(&mp->timer, jiffies); |
278 | 278 | ||
@@ -620,7 +620,6 @@ rehash: | |||
620 | 620 | ||
621 | mp->br = br; | 621 | mp->br = br; |
622 | mp->addr = *group; | 622 | mp->addr = *group; |
623 | |||
624 | setup_timer(&mp->timer, br_multicast_group_expired, | 623 | setup_timer(&mp->timer, br_multicast_group_expired, |
625 | (unsigned long)mp); | 624 | (unsigned long)mp); |
626 | 625 | ||
@@ -660,6 +659,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
660 | struct net_bridge_mdb_entry *mp; | 659 | struct net_bridge_mdb_entry *mp; |
661 | struct net_bridge_port_group *p; | 660 | struct net_bridge_port_group *p; |
662 | struct net_bridge_port_group __rcu **pp; | 661 | struct net_bridge_port_group __rcu **pp; |
662 | unsigned long now = jiffies; | ||
663 | int err; | 663 | int err; |
664 | 664 | ||
665 | spin_lock(&br->multicast_lock); | 665 | spin_lock(&br->multicast_lock); |
@@ -674,6 +674,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
674 | 674 | ||
675 | if (!port) { | 675 | if (!port) { |
676 | mp->mglist = true; | 676 | mp->mglist = true; |
677 | mod_timer(&mp->timer, now + br->multicast_membership_interval); | ||
677 | goto out; | 678 | goto out; |
678 | } | 679 | } |
679 | 680 | ||
@@ -681,7 +682,7 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
681 | (p = mlock_dereference(*pp, br)) != NULL; | 682 | (p = mlock_dereference(*pp, br)) != NULL; |
682 | pp = &p->next) { | 683 | pp = &p->next) { |
683 | if (p->port == port) | 684 | if (p->port == port) |
684 | goto out; | 685 | goto found; |
685 | if ((unsigned long)p->port < (unsigned long)port) | 686 | if ((unsigned long)p->port < (unsigned long)port) |
686 | break; | 687 | break; |
687 | } | 688 | } |
@@ -692,6 +693,8 @@ static int br_multicast_add_group(struct net_bridge *br, | |||
692 | rcu_assign_pointer(*pp, p); | 693 | rcu_assign_pointer(*pp, p); |
693 | br_mdb_notify(br->dev, port, group, RTM_NEWMDB); | 694 | br_mdb_notify(br->dev, port, group, RTM_NEWMDB); |
694 | 695 | ||
696 | found: | ||
697 | mod_timer(&p->timer, now + br->multicast_membership_interval); | ||
695 | out: | 698 | out: |
696 | err = 0; | 699 | err = 0; |
697 | 700 | ||
@@ -1191,9 +1194,6 @@ static int br_ip4_multicast_query(struct net_bridge *br, | |||
1191 | if (!mp) | 1194 | if (!mp) |
1192 | goto out; | 1195 | goto out; |
1193 | 1196 | ||
1194 | mod_timer(&mp->timer, now + br->multicast_membership_interval); | ||
1195 | mp->timer_armed = true; | ||
1196 | |||
1197 | max_delay *= br->multicast_last_member_count; | 1197 | max_delay *= br->multicast_last_member_count; |
1198 | 1198 | ||
1199 | if (mp->mglist && | 1199 | if (mp->mglist && |
@@ -1270,9 +1270,6 @@ static int br_ip6_multicast_query(struct net_bridge *br, | |||
1270 | if (!mp) | 1270 | if (!mp) |
1271 | goto out; | 1271 | goto out; |
1272 | 1272 | ||
1273 | mod_timer(&mp->timer, now + br->multicast_membership_interval); | ||
1274 | mp->timer_armed = true; | ||
1275 | |||
1276 | max_delay *= br->multicast_last_member_count; | 1273 | max_delay *= br->multicast_last_member_count; |
1277 | if (mp->mglist && | 1274 | if (mp->mglist && |
1278 | (timer_pending(&mp->timer) ? | 1275 | (timer_pending(&mp->timer) ? |
@@ -1358,7 +1355,7 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1358 | call_rcu_bh(&p->rcu, br_multicast_free_pg); | 1355 | call_rcu_bh(&p->rcu, br_multicast_free_pg); |
1359 | br_mdb_notify(br->dev, port, group, RTM_DELMDB); | 1356 | br_mdb_notify(br->dev, port, group, RTM_DELMDB); |
1360 | 1357 | ||
1361 | if (!mp->ports && !mp->mglist && mp->timer_armed && | 1358 | if (!mp->ports && !mp->mglist && |
1362 | netif_running(br->dev)) | 1359 | netif_running(br->dev)) |
1363 | mod_timer(&mp->timer, jiffies); | 1360 | mod_timer(&mp->timer, jiffies); |
1364 | } | 1361 | } |
@@ -1370,12 +1367,30 @@ static void br_multicast_leave_group(struct net_bridge *br, | |||
1370 | br->multicast_last_member_interval; | 1367 | br->multicast_last_member_interval; |
1371 | 1368 | ||
1372 | if (!port) { | 1369 | if (!port) { |
1373 | if (mp->mglist && mp->timer_armed && | 1370 | if (mp->mglist && |
1374 | (timer_pending(&mp->timer) ? | 1371 | (timer_pending(&mp->timer) ? |
1375 | time_after(mp->timer.expires, time) : | 1372 | time_after(mp->timer.expires, time) : |
1376 | try_to_del_timer_sync(&mp->timer) >= 0)) { | 1373 | try_to_del_timer_sync(&mp->timer) >= 0)) { |
1377 | mod_timer(&mp->timer, time); | 1374 | mod_timer(&mp->timer, time); |
1378 | } | 1375 | } |
1376 | |||
1377 | goto out; | ||
1378 | } | ||
1379 | |||
1380 | for (p = mlock_dereference(mp->ports, br); | ||
1381 | p != NULL; | ||
1382 | p = mlock_dereference(p->next, br)) { | ||
1383 | if (p->port != port) | ||
1384 | continue; | ||
1385 | |||
1386 | if (!hlist_unhashed(&p->mglist) && | ||
1387 | (timer_pending(&p->timer) ? | ||
1388 | time_after(p->timer.expires, time) : | ||
1389 | try_to_del_timer_sync(&p->timer) >= 0)) { | ||
1390 | mod_timer(&p->timer, time); | ||
1391 | } | ||
1392 | |||
1393 | break; | ||
1379 | } | 1394 | } |
1380 | out: | 1395 | out: |
1381 | spin_unlock(&br->multicast_lock); | 1396 | spin_unlock(&br->multicast_lock); |
@@ -1798,7 +1813,6 @@ void br_multicast_stop(struct net_bridge *br) | |||
1798 | hlist_for_each_entry_safe(mp, n, &mdb->mhash[i], | 1813 | hlist_for_each_entry_safe(mp, n, &mdb->mhash[i], |
1799 | hlist[ver]) { | 1814 | hlist[ver]) { |
1800 | del_timer(&mp->timer); | 1815 | del_timer(&mp->timer); |
1801 | mp->timer_armed = false; | ||
1802 | call_rcu_bh(&mp->rcu, br_multicast_free_group); | 1816 | call_rcu_bh(&mp->rcu, br_multicast_free_group); |
1803 | } | 1817 | } |
1804 | } | 1818 | } |
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c index e74ddc1c29a8..f75d92e4f96b 100644 --- a/net/bridge/br_netlink.c +++ b/net/bridge/br_netlink.c | |||
@@ -243,7 +243,7 @@ static int br_afspec(struct net_bridge *br, | |||
243 | 243 | ||
244 | vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); | 244 | vinfo = nla_data(tb[IFLA_BRIDGE_VLAN_INFO]); |
245 | 245 | ||
246 | if (vinfo->vid >= VLAN_N_VID) | 246 | if (!vinfo->vid || vinfo->vid >= VLAN_VID_MASK) |
247 | return -EINVAL; | 247 | return -EINVAL; |
248 | 248 | ||
249 | switch (cmd) { | 249 | switch (cmd) { |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 767c4dad8504..d1ca6d956633 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -126,7 +126,6 @@ struct net_bridge_mdb_entry | |||
126 | struct timer_list timer; | 126 | struct timer_list timer; |
127 | struct br_ip addr; | 127 | struct br_ip addr; |
128 | bool mglist; | 128 | bool mglist; |
129 | bool timer_armed; | ||
130 | }; | 129 | }; |
131 | 130 | ||
132 | struct net_bridge_mdb_htable | 131 | struct net_bridge_mdb_htable |
@@ -624,9 +623,7 @@ static inline u16 br_get_pvid(const struct net_port_vlans *v) | |||
624 | * vid wasn't set | 623 | * vid wasn't set |
625 | */ | 624 | */ |
626 | smp_rmb(); | 625 | smp_rmb(); |
627 | return (v->pvid & VLAN_TAG_PRESENT) ? | 626 | return v->pvid ?: VLAN_N_VID; |
628 | (v->pvid & ~VLAN_TAG_PRESENT) : | ||
629 | VLAN_N_VID; | ||
630 | } | 627 | } |
631 | 628 | ||
632 | #else | 629 | #else |
diff --git a/net/bridge/br_stp_if.c b/net/bridge/br_stp_if.c index 108084a04671..656a6f3e40de 100644 --- a/net/bridge/br_stp_if.c +++ b/net/bridge/br_stp_if.c | |||
@@ -134,7 +134,7 @@ static void br_stp_start(struct net_bridge *br) | |||
134 | 134 | ||
135 | if (br->bridge_forward_delay < BR_MIN_FORWARD_DELAY) | 135 | if (br->bridge_forward_delay < BR_MIN_FORWARD_DELAY) |
136 | __br_set_forward_delay(br, BR_MIN_FORWARD_DELAY); | 136 | __br_set_forward_delay(br, BR_MIN_FORWARD_DELAY); |
137 | else if (br->bridge_forward_delay < BR_MAX_FORWARD_DELAY) | 137 | else if (br->bridge_forward_delay > BR_MAX_FORWARD_DELAY) |
138 | __br_set_forward_delay(br, BR_MAX_FORWARD_DELAY); | 138 | __br_set_forward_delay(br, BR_MAX_FORWARD_DELAY); |
139 | 139 | ||
140 | if (r == 0) { | 140 | if (r == 0) { |
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c index 9a9ffe7e4019..53f0990eab58 100644 --- a/net/bridge/br_vlan.c +++ b/net/bridge/br_vlan.c | |||
@@ -45,37 +45,34 @@ static int __vlan_add(struct net_port_vlans *v, u16 vid, u16 flags) | |||
45 | return 0; | 45 | return 0; |
46 | } | 46 | } |
47 | 47 | ||
48 | if (vid) { | 48 | if (v->port_idx) { |
49 | if (v->port_idx) { | 49 | p = v->parent.port; |
50 | p = v->parent.port; | 50 | br = p->br; |
51 | br = p->br; | 51 | dev = p->dev; |
52 | dev = p->dev; | 52 | } else { |
53 | } else { | 53 | br = v->parent.br; |
54 | br = v->parent.br; | 54 | dev = br->dev; |
55 | dev = br->dev; | 55 | } |
56 | } | 56 | ops = dev->netdev_ops; |
57 | ops = dev->netdev_ops; | 57 | |
58 | 58 | if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { | |
59 | if (p && (dev->features & NETIF_F_HW_VLAN_CTAG_FILTER)) { | 59 | /* Add VLAN to the device filter if it is supported. |
60 | /* Add VLAN to the device filter if it is supported. | 60 | * Stricly speaking, this is not necessary now, since |
61 | * Stricly speaking, this is not necessary now, since | 61 | * devices are made promiscuous by the bridge, but if |
62 | * devices are made promiscuous by the bridge, but if | 62 | * that ever changes this code will allow tagged |
63 | * that ever changes this code will allow tagged | 63 | * traffic to enter the bridge. |
64 | * traffic to enter the bridge. | 64 | */ |
65 | */ | 65 | err = ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), |
66 | err = ops->ndo_vlan_rx_add_vid(dev, htons(ETH_P_8021Q), | 66 | vid); |
67 | vid); | 67 | if (err) |
68 | if (err) | 68 | return err; |
69 | return err; | 69 | } |
70 | } | ||
71 | |||
72 | err = br_fdb_insert(br, p, dev->dev_addr, vid); | ||
73 | if (err) { | ||
74 | br_err(br, "failed insert local address into bridge " | ||
75 | "forwarding table\n"); | ||
76 | goto out_filt; | ||
77 | } | ||
78 | 70 | ||
71 | err = br_fdb_insert(br, p, dev->dev_addr, vid); | ||
72 | if (err) { | ||
73 | br_err(br, "failed insert local address into bridge " | ||
74 | "forwarding table\n"); | ||
75 | goto out_filt; | ||
79 | } | 76 | } |
80 | 77 | ||
81 | set_bit(vid, v->vlan_bitmap); | 78 | set_bit(vid, v->vlan_bitmap); |
@@ -98,7 +95,7 @@ static int __vlan_del(struct net_port_vlans *v, u16 vid) | |||
98 | __vlan_delete_pvid(v, vid); | 95 | __vlan_delete_pvid(v, vid); |
99 | clear_bit(vid, v->untagged_bitmap); | 96 | clear_bit(vid, v->untagged_bitmap); |
100 | 97 | ||
101 | if (v->port_idx && vid) { | 98 | if (v->port_idx) { |
102 | struct net_device *dev = v->parent.port->dev; | 99 | struct net_device *dev = v->parent.port->dev; |
103 | const struct net_device_ops *ops = dev->netdev_ops; | 100 | const struct net_device_ops *ops = dev->netdev_ops; |
104 | 101 | ||
@@ -192,6 +189,8 @@ out: | |||
192 | bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, | 189 | bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, |
193 | struct sk_buff *skb, u16 *vid) | 190 | struct sk_buff *skb, u16 *vid) |
194 | { | 191 | { |
192 | int err; | ||
193 | |||
195 | /* If VLAN filtering is disabled on the bridge, all packets are | 194 | /* If VLAN filtering is disabled on the bridge, all packets are |
196 | * permitted. | 195 | * permitted. |
197 | */ | 196 | */ |
@@ -204,20 +203,32 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, | |||
204 | if (!v) | 203 | if (!v) |
205 | return false; | 204 | return false; |
206 | 205 | ||
207 | if (br_vlan_get_tag(skb, vid)) { | 206 | err = br_vlan_get_tag(skb, vid); |
207 | if (!*vid) { | ||
208 | u16 pvid = br_get_pvid(v); | 208 | u16 pvid = br_get_pvid(v); |
209 | 209 | ||
210 | /* Frame did not have a tag. See if pvid is set | 210 | /* Frame had a tag with VID 0 or did not have a tag. |
211 | * on this port. That tells us which vlan untagged | 211 | * See if pvid is set on this port. That tells us which |
212 | * traffic belongs to. | 212 | * vlan untagged or priority-tagged traffic belongs to. |
213 | */ | 213 | */ |
214 | if (pvid == VLAN_N_VID) | 214 | if (pvid == VLAN_N_VID) |
215 | return false; | 215 | return false; |
216 | 216 | ||
217 | /* PVID is set on this port. Any untagged ingress | 217 | /* PVID is set on this port. Any untagged or priority-tagged |
218 | * frame is considered to belong to this vlan. | 218 | * ingress frame is considered to belong to this vlan. |
219 | */ | 219 | */ |
220 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid); | 220 | *vid = pvid; |
221 | if (likely(err)) | ||
222 | /* Untagged Frame. */ | ||
223 | __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), pvid); | ||
224 | else | ||
225 | /* Priority-tagged Frame. | ||
226 | * At this point, We know that skb->vlan_tci had | ||
227 | * VLAN_TAG_PRESENT bit and its VID field was 0x000. | ||
228 | * We update only VID field and preserve PCP field. | ||
229 | */ | ||
230 | skb->vlan_tci |= pvid; | ||
231 | |||
221 | return true; | 232 | return true; |
222 | } | 233 | } |
223 | 234 | ||
@@ -248,7 +259,9 @@ bool br_allowed_egress(struct net_bridge *br, | |||
248 | return false; | 259 | return false; |
249 | } | 260 | } |
250 | 261 | ||
251 | /* Must be protected by RTNL */ | 262 | /* Must be protected by RTNL. |
263 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
264 | */ | ||
252 | int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags) | 265 | int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags) |
253 | { | 266 | { |
254 | struct net_port_vlans *pv = NULL; | 267 | struct net_port_vlans *pv = NULL; |
@@ -278,7 +291,9 @@ out: | |||
278 | return err; | 291 | return err; |
279 | } | 292 | } |
280 | 293 | ||
281 | /* Must be protected by RTNL */ | 294 | /* Must be protected by RTNL. |
295 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
296 | */ | ||
282 | int br_vlan_delete(struct net_bridge *br, u16 vid) | 297 | int br_vlan_delete(struct net_bridge *br, u16 vid) |
283 | { | 298 | { |
284 | struct net_port_vlans *pv; | 299 | struct net_port_vlans *pv; |
@@ -289,14 +304,9 @@ int br_vlan_delete(struct net_bridge *br, u16 vid) | |||
289 | if (!pv) | 304 | if (!pv) |
290 | return -EINVAL; | 305 | return -EINVAL; |
291 | 306 | ||
292 | if (vid) { | 307 | spin_lock_bh(&br->hash_lock); |
293 | /* If the VID !=0 remove fdb for this vid. VID 0 is special | 308 | fdb_delete_by_addr(br, br->dev->dev_addr, vid); |
294 | * in that it's the default and is always there in the fdb. | 309 | spin_unlock_bh(&br->hash_lock); |
295 | */ | ||
296 | spin_lock_bh(&br->hash_lock); | ||
297 | fdb_delete_by_addr(br, br->dev->dev_addr, vid); | ||
298 | spin_unlock_bh(&br->hash_lock); | ||
299 | } | ||
300 | 310 | ||
301 | __vlan_del(pv, vid); | 311 | __vlan_del(pv, vid); |
302 | return 0; | 312 | return 0; |
@@ -329,7 +339,9 @@ unlock: | |||
329 | return 0; | 339 | return 0; |
330 | } | 340 | } |
331 | 341 | ||
332 | /* Must be protected by RTNL */ | 342 | /* Must be protected by RTNL. |
343 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
344 | */ | ||
333 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) | 345 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) |
334 | { | 346 | { |
335 | struct net_port_vlans *pv = NULL; | 347 | struct net_port_vlans *pv = NULL; |
@@ -363,7 +375,9 @@ clean_up: | |||
363 | return err; | 375 | return err; |
364 | } | 376 | } |
365 | 377 | ||
366 | /* Must be protected by RTNL */ | 378 | /* Must be protected by RTNL. |
379 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
380 | */ | ||
367 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) | 381 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) |
368 | { | 382 | { |
369 | struct net_port_vlans *pv; | 383 | struct net_port_vlans *pv; |
@@ -374,14 +388,9 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) | |||
374 | if (!pv) | 388 | if (!pv) |
375 | return -EINVAL; | 389 | return -EINVAL; |
376 | 390 | ||
377 | if (vid) { | 391 | spin_lock_bh(&port->br->hash_lock); |
378 | /* If the VID !=0 remove fdb for this vid. VID 0 is special | 392 | fdb_delete_by_addr(port->br, port->dev->dev_addr, vid); |
379 | * in that it's the default and is always there in the fdb. | 393 | spin_unlock_bh(&port->br->hash_lock); |
380 | */ | ||
381 | spin_lock_bh(&port->br->hash_lock); | ||
382 | fdb_delete_by_addr(port->br, port->dev->dev_addr, vid); | ||
383 | spin_unlock_bh(&port->br->hash_lock); | ||
384 | } | ||
385 | 394 | ||
386 | return __vlan_del(pv, vid); | 395 | return __vlan_del(pv, vid); |
387 | } | 396 | } |