aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/if_vlan.h6
-rw-r--r--include/linux/skbuff.h1
-rw-r--r--net/8021q/vlan_core.c53
-rw-r--r--net/bridge/br_vlan.c2
-rw-r--r--net/core/dev.c2
-rw-r--r--net/core/skbuff.c53
6 files changed, 56 insertions, 61 deletions
diff --git a/include/linux/if_vlan.h b/include/linux/if_vlan.h
index 4967916fe4ac..d69f0577a319 100644
--- a/include/linux/if_vlan.h
+++ b/include/linux/if_vlan.h
@@ -187,7 +187,6 @@ vlan_dev_get_egress_qos_mask(struct net_device *dev, u32 skprio)
187} 187}
188 188
189extern bool vlan_do_receive(struct sk_buff **skb); 189extern bool vlan_do_receive(struct sk_buff **skb);
190extern struct sk_buff *vlan_untag(struct sk_buff *skb);
191 190
192extern int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid); 191extern int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid);
193extern void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid); 192extern void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid);
@@ -241,11 +240,6 @@ static inline bool vlan_do_receive(struct sk_buff **skb)
241 return false; 240 return false;
242} 241}
243 242
244static inline struct sk_buff *vlan_untag(struct sk_buff *skb)
245{
246 return skb;
247}
248
249static inline int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid) 243static inline int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid)
250{ 244{
251 return 0; 245 return 0;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 11c270551d25..abde271c18ae 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -2555,6 +2555,7 @@ int skb_shift(struct sk_buff *tgt, struct sk_buff *skb, int shiftlen);
2555void skb_scrub_packet(struct sk_buff *skb, bool xnet); 2555void skb_scrub_packet(struct sk_buff *skb, bool xnet);
2556unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); 2556unsigned int skb_gso_transport_seglen(const struct sk_buff *skb);
2557struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); 2557struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features);
2558struct sk_buff *skb_vlan_untag(struct sk_buff *skb);
2558 2559
2559struct skb_checksum_ops { 2560struct skb_checksum_ops {
2560 __wsum (*update)(const void *mem, int len, __wsum wsum); 2561 __wsum (*update)(const void *mem, int len, __wsum wsum);
diff --git a/net/8021q/vlan_core.c b/net/8021q/vlan_core.c
index 75d427763992..90cc2bdd4064 100644
--- a/net/8021q/vlan_core.c
+++ b/net/8021q/vlan_core.c
@@ -112,59 +112,6 @@ __be16 vlan_dev_vlan_proto(const struct net_device *dev)
112} 112}
113EXPORT_SYMBOL(vlan_dev_vlan_proto); 113EXPORT_SYMBOL(vlan_dev_vlan_proto);
114 114
115static struct sk_buff *vlan_reorder_header(struct sk_buff *skb)
116{
117 if (skb_cow(skb, skb_headroom(skb)) < 0) {
118 kfree_skb(skb);
119 return NULL;
120 }
121
122 memmove(skb->data - ETH_HLEN, skb->data - VLAN_ETH_HLEN, 2 * ETH_ALEN);
123 skb->mac_header += VLAN_HLEN;
124 return skb;
125}
126
127struct sk_buff *vlan_untag(struct sk_buff *skb)
128{
129 struct vlan_hdr *vhdr;
130 u16 vlan_tci;
131
132 if (unlikely(vlan_tx_tag_present(skb))) {
133 /* vlan_tci is already set-up so leave this for another time */
134 return skb;
135 }
136
137 skb = skb_share_check(skb, GFP_ATOMIC);
138 if (unlikely(!skb))
139 goto err_free;
140
141 if (unlikely(!pskb_may_pull(skb, VLAN_HLEN)))
142 goto err_free;
143
144 vhdr = (struct vlan_hdr *) skb->data;
145 vlan_tci = ntohs(vhdr->h_vlan_TCI);
146 __vlan_hwaccel_put_tag(skb, skb->protocol, vlan_tci);
147
148 skb_pull_rcsum(skb, VLAN_HLEN);
149 vlan_set_encap_proto(skb, vhdr);
150
151 skb = vlan_reorder_header(skb);
152 if (unlikely(!skb))
153 goto err_free;
154
155 skb_reset_network_header(skb);
156 skb_reset_transport_header(skb);
157 skb_reset_mac_len(skb);
158
159 return skb;
160
161err_free:
162 kfree_skb(skb);
163 return NULL;
164}
165EXPORT_SYMBOL(vlan_untag);
166
167
168/* 115/*
169 * vlan info and vid list 116 * vlan info and vid list
170 */ 117 */
diff --git a/net/bridge/br_vlan.c b/net/bridge/br_vlan.c
index febb0f87fa37..e1bcd653899b 100644
--- a/net/bridge/br_vlan.c
+++ b/net/bridge/br_vlan.c
@@ -181,7 +181,7 @@ bool br_allowed_ingress(struct net_bridge *br, struct net_port_vlans *v,
181 */ 181 */
182 if (unlikely(!vlan_tx_tag_present(skb) && 182 if (unlikely(!vlan_tx_tag_present(skb) &&
183 skb->protocol == proto)) { 183 skb->protocol == proto)) {
184 skb = vlan_untag(skb); 184 skb = skb_vlan_untag(skb);
185 if (unlikely(!skb)) 185 if (unlikely(!skb))
186 return false; 186 return false;
187 } 187 }
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}
3975EXPORT_SYMBOL_GPL(skb_gso_transport_seglen); 3976EXPORT_SYMBOL_GPL(skb_gso_transport_seglen);
3977
3978static 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
3990struct 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
4024err_free:
4025 kfree_skb(skb);
4026 return NULL;
4027}
4028EXPORT_SYMBOL(skb_vlan_untag);