aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/if_vlan.h60
-rw-r--r--net/core/dev.c31
2 files changed, 47 insertions, 44 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 515a35e2a48a..960e666c51e4 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -472,27 +472,59 @@ static inline int vlan_get_tag(const struct sk_buff *skb, u16 *vlan_tci)
472/** 472/**
473 * vlan_get_protocol - get protocol EtherType. 473 * vlan_get_protocol - get protocol EtherType.
474 * @skb: skbuff to query 474 * @skb: skbuff to query
475 * @type: first vlan protocol
476 * @depth: buffer to store length of eth and vlan tags in bytes
475 * 477 *
476 * Returns the EtherType of the packet, regardless of whether it is 478 * Returns the EtherType of the packet, regardless of whether it is
477 * vlan encapsulated (normal or hardware accelerated) or not. 479 * vlan encapsulated (normal or hardware accelerated) or not.
478 */ 480 */
479static inline __be16 vlan_get_protocol(const struct sk_buff *skb) 481static inline __be16 __vlan_get_protocol(struct sk_buff *skb, __be16 type,
482 int *depth)
480{ 483{
481 __be16 protocol = 0; 484 unsigned int vlan_depth = skb->mac_len;
482 485
483 if (vlan_tx_tag_present(skb) || 486 /* if type is 802.1Q/AD then the header should already be
484 skb->protocol != cpu_to_be16(ETH_P_8021Q)) 487 * present at mac_len - VLAN_HLEN (if mac_len > 0), or at
485 protocol = skb->protocol; 488 * ETH_HLEN otherwise
486 else { 489 */
487 __be16 proto, *protop; 490 if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
488 protop = skb_header_pointer(skb, offsetof(struct vlan_ethhdr, 491 if (vlan_depth) {
489 h_vlan_encapsulated_proto), 492 if (WARN_ON(vlan_depth < VLAN_HLEN))
490 sizeof(proto), &proto); 493 return 0;
491 if (likely(protop)) 494 vlan_depth -= VLAN_HLEN;
492 protocol = *protop; 495 } else {
496 vlan_depth = ETH_HLEN;
497 }
498 do {
499 struct vlan_hdr *vh;
500
501 if (unlikely(!pskb_may_pull(skb,
502 vlan_depth + VLAN_HLEN)))
503 return 0;
504
505 vh = (struct vlan_hdr *)(skb->data + vlan_depth);
506 type = vh->h_vlan_encapsulated_proto;
507 vlan_depth += VLAN_HLEN;
508 } while (type == htons(ETH_P_8021Q) ||
509 type == htons(ETH_P_8021AD));
493 } 510 }
494 511
495 return protocol; 512 if (depth)
513 *depth = vlan_depth;
514
515 return type;
516}
517
518/**
519 * vlan_get_protocol - get protocol EtherType.
520 * @skb: skbuff to query
521 *
522 * Returns the EtherType of the packet, regardless of whether it is
523 * vlan encapsulated (normal or hardware accelerated) or not.
524 */
525static inline __be16 vlan_get_protocol(struct sk_buff *skb)
526{
527 return __vlan_get_protocol(skb, skb->protocol, NULL);
496} 528}
497 529
498static inline void vlan_set_encap_proto(struct sk_buff *skb, 530static inline void vlan_set_encap_proto(struct sk_buff *skb,
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/**