diff options
Diffstat (limited to 'net/bridge/br_vlan.c')
-rw-r--r-- | net/bridge/br_vlan.c | 125 |
1 files changed, 67 insertions, 58 deletions
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 | } |