#define VLAN_ETH_DATA_LEN      1500    /* Max. octets in payload        */
 #define VLAN_ETH_FRAME_LEN     1518    /* Max. octets in frame sans FCS */
 
+#define VLAN_MAX_DEPTH 8               /* Max. number of nested VLAN tags parsed */
+
 /*
  *     struct vlan_hdr - vlan header
  *     @h_vlan_TCI: priority and VLAN ID
        }
 }
 
-/* A getter for the SKB protocol field which will handle VLAN tags consistently
- * whether VLAN acceleration is enabled or not.
- */
-static inline __be16 skb_protocol(const struct sk_buff *skb, bool skip_vlan)
-{
-       unsigned int offset = skb_mac_offset(skb) + sizeof(struct ethhdr);
-       __be16 proto = skb->protocol;
-
-       if (!skip_vlan)
-               /* VLAN acceleration strips the VLAN header from the skb and
-                * moves it to skb->vlan_proto
-                */
-               return skb_vlan_tag_present(skb) ? skb->vlan_proto : proto;
-
-       while (eth_type_vlan(proto)) {
-               struct vlan_hdr vhdr, *vh;
-
-               vh = skb_header_pointer(skb, offset, sizeof(vhdr), &vhdr);
-               if (!vh)
-                       break;
-
-               proto = vh->h_vlan_encapsulated_proto;
-               offset += sizeof(vhdr);
-       }
-
-       return proto;
-}
-
 static inline bool vlan_hw_offload_capable(netdev_features_t features,
                                           __be16 proto)
 {
  * Returns the EtherType of the packet, regardless of whether it is
  * vlan encapsulated (normal or hardware accelerated) or not.
  */
-static inline __be16 __vlan_get_protocol(struct sk_buff *skb, __be16 type,
+static inline __be16 __vlan_get_protocol(const struct sk_buff *skb, __be16 type,
                                         int *depth)
 {
-       unsigned int vlan_depth = skb->mac_len;
+       unsigned int vlan_depth = skb->mac_len, parse_depth = VLAN_MAX_DEPTH;
 
        /* if type is 802.1Q/AD then the header should already be
         * present at mac_len - VLAN_HLEN (if mac_len > 0), or at
                        vlan_depth = ETH_HLEN;
                }
                do {
-                       struct vlan_hdr *vh;
+                       struct vlan_hdr vhdr, *vh;
 
-                       if (unlikely(!pskb_may_pull(skb,
-                                                   vlan_depth + VLAN_HLEN)))
+                       vh = skb_header_pointer(skb, vlan_depth, sizeof(vhdr), &vhdr);
+                       if (unlikely(!vh || !--parse_depth))
                                return 0;
 
-                       vh = (struct vlan_hdr *)(skb->data + vlan_depth);
                        type = vh->h_vlan_encapsulated_proto;
                        vlan_depth += VLAN_HLEN;
                } while (eth_type_vlan(type));
  * Returns the EtherType of the packet, regardless of whether it is
  * vlan encapsulated (normal or hardware accelerated) or not.
  */
-static inline __be16 vlan_get_protocol(struct sk_buff *skb)
+static inline __be16 vlan_get_protocol(const struct sk_buff *skb)
 {
        return __vlan_get_protocol(skb, skb->protocol, NULL);
 }
 
+/* A getter for the SKB protocol field which will handle VLAN tags consistently
+ * whether VLAN acceleration is enabled or not.
+ */
+static inline __be16 skb_protocol(const struct sk_buff *skb, bool skip_vlan)
+{
+       if (!skip_vlan)
+               /* VLAN acceleration strips the VLAN header from the skb and
+                * moves it to skb->vlan_proto
+                */
+               return skb_vlan_tag_present(skb) ? skb->vlan_proto : skb->protocol;
+
+       return vlan_get_protocol(skb);
+}
+
 static inline void vlan_set_encap_proto(struct sk_buff *skb,
                                        struct vlan_hdr *vhdr)
 {