Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 11e3ff70 authored by Martin Townsend's avatar Martin Townsend Committed by Marcel Holtmann
Browse files

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: default avatarMartin Townsend <martin.townsend@xsilon.com>
Acked-by: default avatarAlexander Aring <alex.aring@gmail.com>
Acked-by: default avatarJukka Rissanen <jukka.rissanen@linux.intel.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 4456c50d
Loading
Loading
Loading
Loading
+21 −26
Original line number Diff line number Diff line
@@ -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;
}
@@ -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);
		err = skb_cow(skb, needed);
		if (unlikely(err)) {
			kfree_skb(skb);

		if (!new)
			return -ENOMEM;

		skb = new;
			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);
+4 −0
Original line number Diff line number Diff line
@@ -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