|
|
@@ -2283,8 +2283,8 @@ EXPORT_SYMBOL(skb_checksum_help);
|
|
|
|
|
|
__be16 skb_network_protocol(struct sk_buff *skb, int *depth)
|
|
|
{
|
|
|
+ unsigned int vlan_depth = skb->mac_len;
|
|
|
__be16 type = skb->protocol;
|
|
|
- int vlan_depth = skb->mac_len;
|
|
|
|
|
|
/* Tunnel gso handlers can set protocol to ethernet. */
|
|
|
if (type == htons(ETH_P_TEB)) {
|
|
|
@@ -2297,15 +2297,30 @@ __be16 skb_network_protocol(struct sk_buff *skb, int *depth)
|
|
|
type = eth->h_proto;
|
|
|
}
|
|
|
|
|
|
- while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
|
|
|
- struct vlan_hdr *vh;
|
|
|
-
|
|
|
- if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
|
|
|
- return 0;
|
|
|
-
|
|
|
- vh = (struct vlan_hdr *)(skb->data + vlan_depth);
|
|
|
- type = vh->h_vlan_encapsulated_proto;
|
|
|
- vlan_depth += VLAN_HLEN;
|
|
|
+ /* if skb->protocol is 802.1Q/AD then the header should already be
|
|
|
+ * present at mac_len - VLAN_HLEN (if mac_len > 0), or at
|
|
|
+ * ETH_HLEN otherwise
|
|
|
+ */
|
|
|
+ if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
|
|
|
+ if (vlan_depth) {
|
|
|
+ if (unlikely(WARN_ON(vlan_depth < VLAN_HLEN)))
|
|
|
+ return 0;
|
|
|
+ vlan_depth -= VLAN_HLEN;
|
|
|
+ } else {
|
|
|
+ vlan_depth = ETH_HLEN;
|
|
|
+ }
|
|
|
+ do {
|
|
|
+ struct vlan_hdr *vh;
|
|
|
+
|
|
|
+ if (unlikely(!pskb_may_pull(skb,
|
|
|
+ vlan_depth + VLAN_HLEN)))
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ vh = (struct vlan_hdr *)(skb->data + vlan_depth);
|
|
|
+ type = vh->h_vlan_encapsulated_proto;
|
|
|
+ vlan_depth += VLAN_HLEN;
|
|
|
+ } while (type == htons(ETH_P_8021Q) ||
|
|
|
+ type == htons(ETH_P_8021AD));
|
|
|
}
|
|
|
|
|
|
*depth = vlan_depth;
|