diff options
-rw-r--r-- | include/linux/if_vlan.h | 6 | ||||
-rw-r--r-- | include/linux/skbuff.h | 1 | ||||
-rw-r--r-- | net/8021q/vlan_core.c | 53 | ||||
-rw-r--r-- | net/bridge/br_vlan.c | 2 | ||||
-rw-r--r-- | net/core/dev.c | 2 | ||||
-rw-r--r-- | net/core/skbuff.c | 53 |
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 | ||
189 | extern bool vlan_do_receive(struct sk_buff **skb); | 189 | extern bool vlan_do_receive(struct sk_buff **skb); |
190 | extern struct sk_buff *vlan_untag(struct sk_buff *skb); | ||
191 | 190 | ||
192 | extern int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid); | 191 | extern int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid); |
193 | extern void vlan_vid_del(struct net_device *dev, __be16 proto, u16 vid); | 192 | extern 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 | ||
244 | static inline struct sk_buff *vlan_untag(struct sk_buff *skb) | ||
245 | { | ||
246 | return skb; | ||
247 | } | ||
248 | |||
249 | static inline int vlan_vid_add(struct net_device *dev, __be16 proto, u16 vid) | 243 | static 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); | |||
2555 | void skb_scrub_packet(struct sk_buff *skb, bool xnet); | 2555 | void skb_scrub_packet(struct sk_buff *skb, bool xnet); |
2556 | unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); | 2556 | unsigned int skb_gso_transport_seglen(const struct sk_buff *skb); |
2557 | struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); | 2557 | struct sk_buff *skb_segment(struct sk_buff *skb, netdev_features_t features); |
2558 | struct sk_buff *skb_vlan_untag(struct sk_buff *skb); | ||
2558 | 2559 | ||
2559 | struct skb_checksum_ops { | 2560 | struct 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 | } |
113 | EXPORT_SYMBOL(vlan_dev_vlan_proto); | 113 | EXPORT_SYMBOL(vlan_dev_vlan_proto); |
114 | 114 | ||
115 | static 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 | |||
127 | struct 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 | |||
161 | err_free: | ||
162 | kfree_skb(skb); | ||
163 | return NULL; | ||
164 | } | ||
165 | EXPORT_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 | } |
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); | ||