diff options
Diffstat (limited to 'net/core/dev.c')
| -rw-r--r-- | net/core/dev.c | 35 |
1 files changed, 25 insertions, 10 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 9abc503b19b7..fb8b0546485b 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
| @@ -2283,8 +2283,8 @@ EXPORT_SYMBOL(skb_checksum_help); | |||
| 2283 | 2283 | ||
| 2284 | __be16 skb_network_protocol(struct sk_buff *skb, int *depth) | 2284 | __be16 skb_network_protocol(struct sk_buff *skb, int *depth) |
| 2285 | { | 2285 | { |
| 2286 | unsigned int vlan_depth = skb->mac_len; | ||
| 2286 | __be16 type = skb->protocol; | 2287 | __be16 type = skb->protocol; |
| 2287 | int vlan_depth = skb->mac_len; | ||
| 2288 | 2288 | ||
| 2289 | /* Tunnel gso handlers can set protocol to ethernet. */ | 2289 | /* Tunnel gso handlers can set protocol to ethernet. */ |
| 2290 | if (type == htons(ETH_P_TEB)) { | 2290 | if (type == htons(ETH_P_TEB)) { |
| @@ -2297,15 +2297,30 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth) | |||
| 2297 | type = eth->h_proto; | 2297 | type = eth->h_proto; |
| 2298 | } | 2298 | } |
| 2299 | 2299 | ||
| 2300 | while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { | 2300 | /* if skb->protocol is 802.1Q/AD then the header should already be |
| 2301 | struct vlan_hdr *vh; | 2301 | * present at mac_len - VLAN_HLEN (if mac_len > 0), or at |
| 2302 | 2302 | * ETH_HLEN otherwise | |
| 2303 | if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN))) | 2303 | */ |
| 2304 | return 0; | 2304 | if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) { |
| 2305 | 2305 | if (vlan_depth) { | |
| 2306 | vh = (struct vlan_hdr *)(skb->data + vlan_depth); | 2306 | if (unlikely(WARN_ON(vlan_depth < VLAN_HLEN))) |
| 2307 | type = vh->h_vlan_encapsulated_proto; | 2307 | return 0; |
| 2308 | vlan_depth += VLAN_HLEN; | 2308 | vlan_depth -= VLAN_HLEN; |
| 2309 | } else { | ||
| 2310 | vlan_depth = ETH_HLEN; | ||
| 2311 | } | ||
| 2312 | do { | ||
| 2313 | struct vlan_hdr *vh; | ||
| 2314 | |||
| 2315 | if (unlikely(!pskb_may_pull(skb, | ||
| 2316 | vlan_depth + VLAN_HLEN))) | ||
| 2317 | return 0; | ||
| 2318 | |||
| 2319 | vh = (struct vlan_hdr *)(skb->data + vlan_depth); | ||
| 2320 | type = vh->h_vlan_encapsulated_proto; | ||
| 2321 | vlan_depth += VLAN_HLEN; | ||
| 2322 | } while (type == htons(ETH_P_8021Q) || | ||
| 2323 | type == htons(ETH_P_8021AD)); | ||
| 2309 | } | 2324 | } |
| 2310 | 2325 | ||
| 2311 | *depth = vlan_depth; | 2326 | *depth = vlan_depth; |
