aboutsummaryrefslogtreecommitdiffstats
path: root/net/core
diff options
context:
space:
mode:
authorJiri Pirko <jiri@resnulli.us>2014-11-19 08:05:02 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-21 14:20:18 -0500
commit93515d53b133d66f01aec7b231fa3e40e3d2fd9a (patch)
tree6b3bc7c1e38c90eeacdbfb4ddce02d208ae66d63 /net/core
parente21951212f03b8d805795d8f71206853b2ab344d (diff)
net: move vlan pop/push functions into common code
So it can be used from out of openvswitch code. Did couple of cosmetic changes on the way, namely variable naming and adding support for 8021AD proto. Signed-off-by: Jiri Pirko <jiri@resnulli.us> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/core')
-rw-r--r--net/core/skbuff.c95
1 files changed, 95 insertions, 0 deletions
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index d11bbe0da355..c906c5f4bf69 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4163,6 +4163,101 @@ int skb_ensure_writable(struct sk_buff *skb, int write_len)
4163} 4163}
4164EXPORT_SYMBOL(skb_ensure_writable); 4164EXPORT_SYMBOL(skb_ensure_writable);
4165 4165
4166/* remove VLAN header from packet and update csum accordingly. */
4167static int __skb_vlan_pop(struct sk_buff *skb, u16 *vlan_tci)
4168{
4169 struct vlan_hdr *vhdr;
4170 unsigned int offset = skb->data - skb_mac_header(skb);
4171 int err;
4172
4173 __skb_push(skb, offset);
4174 err = skb_ensure_writable(skb, VLAN_ETH_HLEN);
4175 if (unlikely(err))
4176 goto pull;
4177
4178 skb_postpull_rcsum(skb, skb->data + (2 * ETH_ALEN), VLAN_HLEN);
4179
4180 vhdr = (struct vlan_hdr *)(skb->data + ETH_HLEN);
4181 *vlan_tci = ntohs(vhdr->h_vlan_TCI);
4182
4183 memmove(skb->data + VLAN_HLEN, skb->data, 2 * ETH_ALEN);
4184 __skb_pull(skb, VLAN_HLEN);
4185
4186 vlan_set_encap_proto(skb, vhdr);
4187 skb->mac_header += VLAN_HLEN;
4188
4189 if (skb_network_offset(skb) < ETH_HLEN)
4190 skb_set_network_header(skb, ETH_HLEN);
4191
4192 skb_reset_mac_len(skb);
4193pull:
4194 __skb_pull(skb, offset);
4195
4196 return err;
4197}
4198
4199int skb_vlan_pop(struct sk_buff *skb)
4200{
4201 u16 vlan_tci;
4202 __be16 vlan_proto;
4203 int err;
4204
4205 if (likely(vlan_tx_tag_present(skb))) {
4206 skb->vlan_tci = 0;
4207 } else {
4208 if (unlikely((skb->protocol != htons(ETH_P_8021Q) &&
4209 skb->protocol != htons(ETH_P_8021AD)) ||
4210 skb->len < VLAN_ETH_HLEN))
4211 return 0;
4212
4213 err = __skb_vlan_pop(skb, &vlan_tci);
4214 if (err)
4215 return err;
4216 }
4217 /* move next vlan tag to hw accel tag */
4218 if (likely((skb->protocol != htons(ETH_P_8021Q) &&
4219 skb->protocol != htons(ETH_P_8021AD)) ||
4220 skb->len < VLAN_ETH_HLEN))
4221 return 0;
4222
4223 vlan_proto = skb->protocol;
4224 err = __skb_vlan_pop(skb, &vlan_tci);
4225 if (unlikely(err))
4226 return err;
4227
4228 __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
4229 return 0;
4230}
4231EXPORT_SYMBOL(skb_vlan_pop);
4232
4233int skb_vlan_push(struct sk_buff *skb, __be16 vlan_proto, u16 vlan_tci)
4234{
4235 if (vlan_tx_tag_present(skb)) {
4236 unsigned int offset = skb->data - skb_mac_header(skb);
4237 int err;
4238
4239 /* __vlan_insert_tag expect skb->data pointing to mac header.
4240 * So change skb->data before calling it and change back to
4241 * original position later
4242 */
4243 __skb_push(skb, offset);
4244 err = __vlan_insert_tag(skb, skb->vlan_proto,
4245 vlan_tx_tag_get(skb));
4246 if (err)
4247 return err;
4248 skb->protocol = skb->vlan_proto;
4249 skb->mac_len += VLAN_HLEN;
4250 __skb_pull(skb, offset);
4251
4252 if (skb->ip_summed == CHECKSUM_COMPLETE)
4253 skb->csum = csum_add(skb->csum, csum_partial(skb->data
4254 + (2 * ETH_ALEN), VLAN_HLEN, 0));
4255 }
4256 __vlan_hwaccel_put_tag(skb, vlan_proto, vlan_tci);
4257 return 0;
4258}
4259EXPORT_SYMBOL(skb_vlan_push);
4260
4166/** 4261/**
4167 * alloc_skb_with_frags - allocate skb with page frags 4262 * alloc_skb_with_frags - allocate skb with page frags
4168 * 4263 *