diff options
author | Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> | 2013-10-16 04:07:13 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2013-10-18 16:02:52 -0400 |
commit | 8adff41c3d259eb5e313b7b04669eee545925154 (patch) | |
tree | 0457c19489a9c482ff5c15fc16729673aa633dda | |
parent | 4b6c7879d84ad06a2ac5b964808ed599187a188d (diff) |
bridge: Don't use VID 0 and 4095 in vlan filtering
IEEE 802.1Q says that:
- VID 0 shall not be configured as a PVID, or configured in any Filtering
Database entry.
- VID 4095 shall not be configured as a PVID, or transmitted in a tag
header. This VID value may be used to indicate a wildcard match for the VID
in management operations or Filtering Database entries.
(See IEEE 802.1Q-2011 6.9.1 and Table 9-2)
Don't accept adding these VIDs in the vlan_filtering implementation.
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Reviewed-by: Vlad Yasevich <vyasevic@redhat.com>
Acked-by: Stephen Hemminger <stephen@networkplumber.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r-- | net/bridge/br_fdb.c | 4 | ||||
-rw-r--r-- | net/bridge/br_netlink.c | 2 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 97 |
3 files changed, 49 insertions, 54 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_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_vlan.c b/net/bridge/br_vlan.c index 9a9ffe7e4019..21b6d217872b 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 | ||
@@ -248,7 +245,9 @@ bool br_allowed_egress(struct net_bridge *br, | |||
248 | return false; | 245 | return false; |
249 | } | 246 | } |
250 | 247 | ||
251 | /* Must be protected by RTNL */ | 248 | /* Must be protected by RTNL. |
249 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
250 | */ | ||
252 | int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags) | 251 | int br_vlan_add(struct net_bridge *br, u16 vid, u16 flags) |
253 | { | 252 | { |
254 | struct net_port_vlans *pv = NULL; | 253 | struct net_port_vlans *pv = NULL; |
@@ -278,7 +277,9 @@ out: | |||
278 | return err; | 277 | return err; |
279 | } | 278 | } |
280 | 279 | ||
281 | /* Must be protected by RTNL */ | 280 | /* Must be protected by RTNL. |
281 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
282 | */ | ||
282 | int br_vlan_delete(struct net_bridge *br, u16 vid) | 283 | int br_vlan_delete(struct net_bridge *br, u16 vid) |
283 | { | 284 | { |
284 | struct net_port_vlans *pv; | 285 | struct net_port_vlans *pv; |
@@ -289,14 +290,9 @@ int br_vlan_delete(struct net_bridge *br, u16 vid) | |||
289 | if (!pv) | 290 | if (!pv) |
290 | return -EINVAL; | 291 | return -EINVAL; |
291 | 292 | ||
292 | if (vid) { | 293 | spin_lock_bh(&br->hash_lock); |
293 | /* If the VID !=0 remove fdb for this vid. VID 0 is special | 294 | fdb_delete_by_addr(br, br->dev->dev_addr, vid); |
294 | * in that it's the default and is always there in the fdb. | 295 | 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 | 296 | ||
301 | __vlan_del(pv, vid); | 297 | __vlan_del(pv, vid); |
302 | return 0; | 298 | return 0; |
@@ -329,7 +325,9 @@ unlock: | |||
329 | return 0; | 325 | return 0; |
330 | } | 326 | } |
331 | 327 | ||
332 | /* Must be protected by RTNL */ | 328 | /* Must be protected by RTNL. |
329 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
330 | */ | ||
333 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) | 331 | int nbp_vlan_add(struct net_bridge_port *port, u16 vid, u16 flags) |
334 | { | 332 | { |
335 | struct net_port_vlans *pv = NULL; | 333 | struct net_port_vlans *pv = NULL; |
@@ -363,7 +361,9 @@ clean_up: | |||
363 | return err; | 361 | return err; |
364 | } | 362 | } |
365 | 363 | ||
366 | /* Must be protected by RTNL */ | 364 | /* Must be protected by RTNL. |
365 | * Must be called with vid in range from 1 to 4094 inclusive. | ||
366 | */ | ||
367 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) | 367 | int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) |
368 | { | 368 | { |
369 | struct net_port_vlans *pv; | 369 | struct net_port_vlans *pv; |
@@ -374,14 +374,9 @@ int nbp_vlan_delete(struct net_bridge_port *port, u16 vid) | |||
374 | if (!pv) | 374 | if (!pv) |
375 | return -EINVAL; | 375 | return -EINVAL; |
376 | 376 | ||
377 | if (vid) { | 377 | spin_lock_bh(&port->br->hash_lock); |
378 | /* If the VID !=0 remove fdb for this vid. VID 0 is special | 378 | 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. | 379 | 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 | 380 | ||
386 | return __vlan_del(pv, vid); | 381 | return __vlan_del(pv, vid); |
387 | } | 382 | } |