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>
此提交包含在:
Martin Townsend
2014-10-13 11:00:56 +01:00
提交者 Marcel Holtmann
父節點 4456c50d23
當前提交 11e3ff7072
共有 2 個檔案被更改,包括 25 行新增26 行删除

查看文件

@@ -174,30 +174,22 @@ static int uncompress_context_based_src_addr(struct sk_buff *skb,
static int skb_deliver(struct sk_buff *skb, struct ipv6hdr *hdr,
struct net_device *dev, skb_delivery_cb deliver_skb)
{
struct sk_buff *new;
int stat;
new = skb_copy_expand(skb, sizeof(struct ipv6hdr), skb_tailroom(skb),
GFP_ATOMIC);
kfree_skb(skb);
skb_push(skb, sizeof(struct ipv6hdr));
skb_reset_network_header(skb);
skb_copy_to_linear_data(skb, hdr, sizeof(struct ipv6hdr));
if (!new)
return -ENOMEM;
skb_push(new, sizeof(struct ipv6hdr));
skb_reset_network_header(new);
skb_copy_to_linear_data(new, hdr, sizeof(struct ipv6hdr));
new->protocol = htons(ETH_P_IPV6);
new->pkt_type = PACKET_HOST;
new->dev = dev;
skb->protocol = htons(ETH_P_IPV6);
skb->pkt_type = PACKET_HOST;
skb->dev = dev;
raw_dump_table(__func__, "raw skb data dump before receiving",
new->data, new->len);
skb->data, skb->len);
stat = deliver_skb(new, dev);
stat = deliver_skb(skb, dev);
kfree_skb(new);
consume_skb(skb);
return stat;
}
@@ -460,7 +452,7 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
/* UDP data uncompression */
if (iphc0 & LOWPAN_IPHC_NH_C) {
struct udphdr uh;
struct sk_buff *new;
const int needed = sizeof(struct udphdr) + sizeof(hdr);
if (uncompress_udp_header(skb, &uh))
goto drop;
@@ -468,14 +460,11 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
/* replace the compressed UDP head by the uncompressed UDP
* header
*/
new = skb_copy_expand(skb, sizeof(struct udphdr),
skb_tailroom(skb), GFP_ATOMIC);
kfree_skb(skb);
if (!new)
return -ENOMEM;
skb = new;
err = skb_cow(skb, needed);
if (unlikely(err)) {
kfree_skb(skb);
return err;
}
skb_push(skb, sizeof(struct udphdr));
skb_reset_transport_header(skb);
@@ -485,6 +474,12 @@ int lowpan_process_data(struct sk_buff *skb, struct net_device *dev,
(u8 *)&uh, sizeof(uh));
hdr.nexthdr = UIP_PROTO_UDP;
} else {
err = skb_cow(skb, sizeof(hdr));
if (unlikely(err)) {
kfree_skb(skb);
return err;
}
}
hdr.payload_len = htons(skb->len);