History

bridge: Fix inabillity to retrieve vlan tags when tx offload is disabled

Bridge vlan code (br_vlan_get_tag()) assumes that all frames have vlan_tci if they are tagged, but if vlan tx offload is manually disabled on bridge device and frames are sent from vlan device on the bridge device, the tags are embedded in skb->data and they break this assumption. Extract embedded vlan tags and move them to vlan_tci at ingress.

Toshiaki Makita committed 12 years ago

Commit 12464bb1 parent a39ee442 files · +15 −3Browse files

Unified · Split

2 files
  1. net/bridge/br_device.c +3 −3
  2. net/bridge/br_vlan.c +12 −0
net/bridge/br_device.c+3−3
@@ -49,14 +49,14 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev) · 48 unmodified lines
49 brstats->tx_bytes += skb->len;49 brstats->tx_bytes += skb->len;
50 u64_stats_update_end(&brstats->syncp);50 u64_stats_update_end(&brstats->syncp);
51 51
52 if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
53 goto out;
54
55 BR_INPUT_SKB_CB(skb)->brdev = dev;52 BR_INPUT_SKB_CB(skb)->brdev = dev;
56 53
57 skb_reset_mac_header(skb);54 skb_reset_mac_header(skb);
58 skb_pull(skb, ETH_HLEN);55 skb_pull(skb, ETH_HLEN);
59 56
57 if (!br_allowed_ingress(br, br_get_vlan_info(br), skb, &vid))
58 goto out;
59
60 if (is_broadcast_ether_addr(dest))60 if (is_broadcast_ether_addr(dest))
61 br_flood_deliver(br, skb, false);61 br_flood_deliver(br, skb, false);
62 else if (is_multicast_ether_addr(dest)) {62 else if (is_multicast_ether_addr(dest)) {
net/bridge/br_vlan.c+12−0
@@ -174,6 +174,18 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v, · 173 unmodified lines
174 if (!v)174 if (!v)
175 return false;175 return false;
176 176
177 /* If vlan tx offload is disabled on bridge device and frame was
178 * sent from vlan device on the bridge device, it does not have
179 * HW accelerated vlan tag.
180 */
181 if (unlikely(!vlan_tx_tag_present(skb) &&
182 (skb->protocol == htons(ETH_P_8021Q) ||
183 skb->protocol == htons(ETH_P_8021AD)))) {
184 skb = vlan_untag(skb);
185 if (unlikely(!skb))
186 return false;
187 }
188
177 err = br_vlan_get_tag(skb, vid);189 err = br_vlan_get_tag(skb, vid);
178 if (!*vid) {190 if (!*vid) {
179 u16 pvid = br_get_pvid(v);191 u16 pvid = br_get_pvid(v);