Skip to content

Commit

Permalink
6lowpan: Use skb_cow in IPHC decompression.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Alexander Aring <[email protected]>
Acked-by: Jukka Rissanen <[email protected]>
Signed-off-by: Marcel Holtmann <[email protected]>
  • Loading branch information
martintownsend authored and holtmann committed Oct 25, 2014
1 parent 4456c50 commit 11e3ff7
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 26 deletions.
47 changes: 21 additions & 26 deletions net/6lowpan/iphc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

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));
skb_push(skb, sizeof(struct ipv6hdr));
skb_reset_network_header(skb);
skb_copy_to_linear_data(skb, 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;
}
Expand Down Expand Up @@ -460,22 +452,19 @@ 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;

/* 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);
Expand All @@ -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);
Expand Down
4 changes: 4 additions & 0 deletions net/bluetooth/6lowpan.c
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,10 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
if (dev->type != ARPHRD_6LOWPAN)
goto drop;

skb = skb_share_check(skb, GFP_ATOMIC);
if (!skb)
goto drop;

/* check that it's our buffer */
if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
/* Copy the packet so that the IPv6 header is
Expand Down

0 comments on commit 11e3ff7

Please sign in to comment.