aboutsummaryrefslogtreecommitdiffstats
path: root/net/6lowpan/iphc.c
diff options
context:
space:
mode:
authorMartin Townsend <mtownsend1973@gmail.com>2014-10-13 06:00:56 -0400
committerMarcel Holtmann <marcel@holtmann.org>2014-10-25 01:56:25 -0400
commit11e3ff7072789ad4585870cbdde1be10c45f1cc4 (patch)
tree0a8e62cbf7eaeb33ac5931f9cea2321abf730ce5 /net/6lowpan/iphc.c
parent4456c50d23d44352f4174a9a0cb75313d3150907 (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.c47
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,
174static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr, 174static 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);