diff options
| author | Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp> | 2015-01-29 06:37:07 -0500 |
|---|---|---|
| committer | David S. Miller <davem@davemloft.net> | 2015-01-30 21:03:47 -0500 |
| commit | d4bcef3fbe887ff93b58da4fcf6df1eee416e8fa (patch) | |
| tree | cf4ad1600694c60733d7696727d7112acbc6e85c /net/core/dev.c | |
| parent | cfbf654efc6d78dc9812e030673b86f235bf677d (diff) | |
net: Fix vlan_get_protocol for stacked vlan
vlan_get_protocol() could not get network protocol if a skb has a 802.1ad
vlan tag or multiple vlans, which caused incorrect checksum calculation
in several drivers.
Fix vlan_get_protocol() to retrieve network protocol instead of incorrect
vlan protocol.
As the logic is the same as skb_network_protocol(), create a common helper
function __vlan_get_protocol() and call it from existing functions.
Signed-off-by: Toshiaki Makita <makita.toshiaki@lab.ntt.co.jp>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 31 |
1 files changed, 1 insertions, 30 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 171420e75b03..c87a2264a02b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2352,7 +2352,6 @@ EXPORT_SYMBOL(skb_checksum_help); | |||
| 2352 | 2352 | ||
| 2353 | __be16 skb_network_protocol(struct sk_buff *skb, int *depth) | 2353 | __be16 skb_network_protocol(struct sk_buff *skb, int *depth) |
| 2354 | { | 2354 | { |
| 2355 | unsigned int vlan_depth = skb->mac_len; | ||
| 2356 | __be16 type = skb->protocol; | 2355 | __be16 type = skb->protocol; |
| 2357 | 2356 | ||
| 2358 | /* Tunnel gso handlers can set protocol to ethernet. */ | 2357 | /* Tunnel gso handlers can set protocol to ethernet. */ |
| @@ -2366,35 +2365,7 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) | |||
| 2366 | type = eth->h_proto; | 2365 | type = eth->h_proto; |
| 2367 | } | 2366 | } |
| 2368 | 2367 | ||
| 2369 | /* if skb->protocol is 802.1Q/AD then the header should already be | 2368 | return __vlan_get_protocol(skb, type, depth); |
| 2370 | * present at mac_len - VLAN_HLEN (if mac_len > 0), or at | ||
| 2371 | * ETH_HLEN otherwise | ||
| 2372 | */ | ||
| 2373 | if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { | ||
| 2374 | if (vlan_depth) { | ||
| 2375 | if (WARN_ON(vlan_depth < VLAN_HLEN)) | ||
| 2376 | return 0; | ||
| 2377 | vlan_depth -= VLAN_HLEN; | ||
| 2378 | } else { | ||
| 2379 | vlan_depth = ETH_HLEN; | ||
| 2380 | } | ||
| 2381 | do { | ||
| 2382 | struct vlan_hdr *vh; | ||
| 2383 | |||
| 2384 | if (unlikely(!pskb_may_pull(skb, | ||
| 2385 | vlan_depth + VLAN_HLEN))) | ||
| 2386 | return 0; | ||
| 2387 | |||
| 2388 | vh = (struct vlan_hdr *)(skb->data + vlan_depth); | ||
| 2389 | type = vh->h_vlan_encapsulated_proto; | ||
| 2390 | vlan_depth += VLAN_HLEN; | ||
| 2391 | } while (type == htons(ETH_P_8021Q) || | ||
| 2392 | type == htons(ETH_P_8021AD)); | ||
| 2393 | } | ||
| 2394 | |||
| 2395 | *depth = vlan_depth; | ||
| 2396 | |||
| 2397 | return type; | ||
| 2398 | } | 2369 | } |
| 2399 | 2370 | ||
| 2400 | /** | 2371 | /** |
