diff options
Diffstat (limited to 'net/core')
-rw-r--r-- | net/core/dev.c | 2 | ||||
-rw-r--r-- | net/core/skbuff.c | 53 |
2 files changed, 54 insertions, 1 deletions
diff --git a/net/core/dev.c b/net/core/dev.c index 1c15b189c52b..b65a5051361f 100644 --- a/net/core/dev.c +++ b/net/core/dev.c | |||
@@ -3602,7 +3602,7 @@ another_round: | |||
3602 | 3602 | ||
3603 | if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || | 3603 | if (skb->protocol == cpu_to_be16(ETH_P_8021Q) || |
3604 | skb->protocol == cpu_to_be16(ETH_P_8021AD)) { | 3604 | skb->protocol == cpu_to_be16(ETH_P_8021AD)) { |
3605 | skb = vlan_untag(skb); | 3605 | skb = skb_vlan_untag(skb); |
3606 | if (unlikely(!skb)) | 3606 | if (unlikely(!skb)) |
3607 | goto unlock; | 3607 | goto unlock; |
3608 | } | 3608 | } |
diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 224506a6fa80..163b673f9e62 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c | |||
@@ -62,6 +62,7 @@ | |||
62 | #include <linux/scatterlist.h> | 62 | #include <linux/scatterlist.h> |
63 | #include <linux/errqueue.h> | 63 | #include <linux/errqueue.h> |
64 | #include <linux/prefetch.h> | 64 | #include <linux/prefetch.h> |
65 | #include <linux/if_vlan.h> | ||
65 | 66 | ||
66 | #include <net/protocol.h> | 67 | #include <net/protocol.h> |
67 | #include <net/dst.h> | 68 | #include <net/dst.h> |
@@ -3973,3 +3974,55 @@ unsigned int skb_gso_transport_seglen(const struct sk_buff *skb) | |||
3973 | return shinfo->gso_size; | 3974 | return shinfo->gso_size; |
3974 | } | 3975 | } |
3975 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); | 3976 | EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); |
3977 | |||
3978 | static struct sk_buff *skb_reorder_vlan_header(struct sk_buff *skb) | ||
3979 | { | ||
3980 | if (skb_cow(skb, skb_headroom(skb)) < 0) { | ||
3981 | kfree_skb(skb); | ||
3982 | return NULL; | ||
3983 | } | ||
3984 | |||
3985 | memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN); | ||
3986 | skb->mac_header += VLAN_HLEN; | ||
3987 | return skb; | ||
3988 | } | ||
3989 | |||
3990 | struct sk_buff *skb_vlan_untag(struct sk_buff *skb) | ||
3991 | { | ||
3992 | struct vlan_hdr *vhdr; | ||
3993 | u16 vlan_tci; | ||
3994 | |||
3995 | if (unlikely(vlan_tx_tag_present(skb))) { | ||
3996 | /* vlan_tci is already set-up so leave this for another time */ | ||
3997 | return skb; | ||
3998 | } | ||
3999 | |||
4000 | skb = skb_share_check(skb, GFP_ATOMIC); | ||
4001 | if (unlikely(!skb)) | ||
4002 | goto err_free; | ||
4003 | |||
4004 | if (unlikely(!pskb_may_pull(skb, VLAN_HLEN))) | ||
4005 | goto err_free; | ||
4006 | |||
4007 | vhdr = (struct vlan_hdr *)skb->data; | ||
4008 | vlan_tci = ntohs(vhdr->h_vlan_TCI); | ||
4009 | __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci); | ||
4010 | |||
4011 | skb_pull_rcsum(skb, VLAN_HLEN); | ||
4012 | vlan_set_encap_proto(skb, vhdr); | ||
4013 | |||
4014 | skb = skb_reorder_vlan_header(skb); | ||
4015 | if (unlikely(!skb)) | ||
4016 | goto err_free; | ||
4017 | |||
4018 | skb_reset_network_header(skb); | ||
4019 | skb_reset_transport_header(skb); | ||
4020 | skb_reset_mac_len(skb); | ||
4021 | |||
4022 | return skb; | ||
4023 | |||
4024 | err_free: | ||
4025 | kfree_skb(skb); | ||
4026 | return NULL; | ||
4027 | } | ||
4028 | EXPORT_SYMBOL(skb_vlan_untag); | ||