diff options
author | Martin Townsend <mtownsend1973@gmail.com> | 2014-10-13 06:00:56 -0400 |
---|---|---|
committer | Marcel Holtmann <marcel@holtmann.org> | 2014-10-25 01:56:25 -0400 |
commit | 11e3ff7072789ad4585870cbdde1be10c45f1cc4 (patch) | |
tree | 0a8e62cbf7eaeb33ac5931f9cea2321abf730ce5 /net/6lowpan/iphc.c | |
parent | 4456c50d23d44352f4174a9a0cb75313d3150907 (diff) |
6lowpan: Use skb_cow in IPHC decompression.
Currently there are potentially 2 skb_copy_expand calls in IPHC
decompression. This patch replaces this with one call to
skb_cow which will check to see if there is enough headroom
first to ensure it's only done if necessary and will handle
alignment issues for cache.
As skb_cow uses pskb_expand_head we ensure the skb isn't shared from
bluetooth and ieee802.15.4 code that use the IPHC decompression.
Signed-off-by: Martin Townsend <martin.townsend@xsilon.com>
Acked-by: Alexander Aring <alex.aring@gmail.com>
Acked-by: Jukka Rissanen <jukka.rissanen@linux.intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Diffstat (limited to 'net/6lowpan/iphc.c')
-rw-r--r-- | net/6lowpan/iphc.c | 47 |
1 files changed, 21 insertions, 26 deletions
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c index 142eef55c9e2..747b3ccfc4f8 100644 --- a/net/6lowpan/iphc.c +++ b/net/6lowpan/iphc.c | |||
@@ -174,30 +174,22 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb, | |||
174 | static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, | 174 | static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, |
175 | struct net_device *dev, skb_delivery_cb deliver_skb) | 175 | struct net_device *dev, skb_delivery_cb deliver_skb) |
176 | { | 176 | { |
177 | struct sk_buff *new; | ||
178 | int stat; | 177 | int stat; |
179 | 178 | ||
180 | new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb), | 179 | skb_push(skb, sizeof(struct ipv6hdr)); |
181 | GFP_ATOMIC); | 180 | skb_reset_network_header(skb); |
182 | kfree_skb(skb); | 181 | skb_copy_to_linear_data(skb, hdr, sizeof(struct ipv6hdr)); |
183 | |||
184 | if (!new) | ||
185 | return -ENOMEM; | ||
186 | |||
187 | skb_push(new, sizeof(struct ipv6hdr)); | ||
188 | skb_reset_network_header(new); | ||
189 | skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr)); | ||
190 | 182 | ||
191 | new->protocol = htons(ETH_P_IPV6); | 183 | skb->protocol = htons(ETH_P_IPV6); |
192 | new->pkt_type = PACKET_HOST; | 184 | skb->pkt_type = PACKET_HOST; |
193 | new->dev = dev; | 185 | skb->dev = dev; |
194 | 186 | ||
195 | raw_dump_table(__func__, "raw skb data dump before receiving", | 187 | raw_dump_table(__func__, "raw skb data dump before receiving", |
196 | new->data, new->len); | 188 | skb->data, skb->len); |
197 | 189 | ||
198 | stat = deliver_skb(new, dev); | 190 | stat = deliver_skb(skb, dev); |
199 | 191 | ||
200 | kfree_skb(new); | 192 | consume_skb(skb); |
201 | 193 | ||
202 | return stat; | 194 | return stat; |
203 | } | 195 | } |
@@ -460,7 +452,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
460 | /* UDP data uncompression */ | 452 | /* UDP data uncompression */ |
461 | if (iphc0 & LOWPAN_IPHC_NH_C) { | 453 | if (iphc0 & LOWPAN_IPHC_NH_C) { |
462 | struct udphdr uh; | 454 | struct udphdr uh; |
463 | struct sk_buff *new; | 455 | const int needed = sizeof(struct udphdr) + sizeof(hdr); |
464 | 456 | ||
465 | if (uncompress_udp_header(skb, &uh)) | 457 | if (uncompress_udp_header(skb, &uh)) |
466 | goto drop; | 458 | goto drop; |
@@ -468,14 +460,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
468 | /* replace the compressed UDP head by the uncompressed UDP | 460 | /* replace the compressed UDP head by the uncompressed UDP |
469 | * header | 461 | * header |
470 | */ | 462 | */ |
471 | new = skb_copy_expand(skb, sizeof(struct udphdr), | 463 | err = skb_cow(skb, needed); |
472 | skb_tailroom(skb), GFP_ATOMIC); | 464 | if (unlikely(err)) { |
473 | kfree_skb(skb); | 465 | kfree_skb(skb); |
474 | 466 | return err; | |
475 | if (!new) | 467 | } |
476 | return -ENOMEM; | ||
477 | |||
478 | skb = new; | ||
479 | 468 | ||
480 | skb_push(skb, sizeof(struct udphdr)); | 469 | skb_push(skb, sizeof(struct udphdr)); |
481 | skb_reset_transport_header(skb); | 470 | skb_reset_transport_header(skb); |
@@ -485,6 +474,12 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev, | |||
485 | (u8 *)&uh, sizeof(uh)); | 474 | (u8 *)&uh, sizeof(uh)); |
486 | 475 | ||
487 | hdr.nexthdr = UIP_PROTO_UDP; | 476 | hdr.nexthdr = UIP_PROTO_UDP; |
477 | } else { | ||
478 | err = skb_cow(skb, sizeof(hdr)); | ||
479 | if (unlikely(err)) { | ||
480 | kfree_skb(skb); | ||
481 | return err; | ||
482 | } | ||
488 | } | 483 | } |
489 | 484 | ||
490 | hdr.payload_len = htons(skb->len); | 485 | hdr.payload_len = htons(skb->len); |