2015-10-13 11:42:54

by Alexander Aring

[permalink] [raw]
Subject: [PATCH bluetooth-next 1/6] mac802154: llsec: use kzfree

This patch will use kzfree instead kfree for security related
information which can be offered by acccident.

Signed-off-by: Alexander Aring <[email protected]>
---
net/mac802154/llsec.c | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/net/mac802154/llsec.c b/net/mac802154/llsec.c
index 7799d3c..a13d02b 100644
--- a/net/mac802154/llsec.c
+++ b/net/mac802154/llsec.c
@@ -55,7 +55,7 @@ void mac802154_llsec_destroy(struct mac802154_llsec *sec)

msl = container_of(sl, struct mac802154_llsec_seclevel, level);
list_del(&sl->list);
- kfree(msl);
+ kzfree(msl);
}

list_for_each_entry_safe(dev, dn, &sec->table.devices, list) {
@@ -72,7 +72,7 @@ void mac802154_llsec_destroy(struct mac802154_llsec *sec)
mkey = container_of(key->key, struct mac802154_llsec_key, key);
list_del(&key->list);
llsec_key_put(mkey);
- kfree(key);
+ kzfree(key);
}
}

@@ -161,7 +161,7 @@ err_tfm:
if (key->tfm[i])
crypto_free_aead(key->tfm[i]);

- kfree(key);
+ kzfree(key);
return NULL;
}

@@ -176,7 +176,7 @@ static void llsec_key_release(struct kref *ref)
crypto_free_aead(key->tfm[i]);

crypto_free_blkcipher(key->tfm0);
- kfree(key);
+ kzfree(key);
}

static struct mac802154_llsec_key*
@@ -267,7 +267,7 @@ int mac802154_llsec_key_add(struct mac802154_llsec *sec,
return 0;

fail:
- kfree(new);
+ kzfree(new);
return -ENOMEM;
}

@@ -347,10 +347,10 @@ static void llsec_dev_free(struct mac802154_llsec_device *dev)
devkey);

list_del(&pos->list);
- kfree(devkey);
+ kzfree(devkey);
}

- kfree(dev);
+ kzfree(dev);
}

int mac802154_llsec_dev_add(struct mac802154_llsec *sec,
@@ -681,7 +681,7 @@ llsec_do_encrypt_auth(struct sk_buff *skb, const struct mac802154_llsec *sec,

rc = crypto_aead_encrypt(req);

- kfree(req);
+ kzfree(req);

return rc;
}
@@ -881,7 +881,7 @@ llsec_do_decrypt_auth(struct sk_buff *skb, const struct mac802154_llsec *sec,

rc = crypto_aead_decrypt(req);

- kfree(req);
+ kzfree(req);
skb_trim(skb, skb->len - authlen);

return rc;
@@ -921,7 +921,7 @@ llsec_update_devkey_record(struct mac802154_llsec_device *dev,
if (!devkey)
list_add_rcu(&next->devkey.list, &dev->dev.keys);
else
- kfree(next);
+ kzfree(next);

spin_unlock_bh(&dev->lock);
}
--
2.6.1



2015-10-20 08:04:03

by Marcel Holtmann

[permalink] [raw]
Subject: Re: [PATCH bluetooth-next 1/6] mac802154: llsec: use kzfree

Hi Alex,

> This patch will use kzfree instead kfree for security related
> information which can be offered by acccident.
>
> Signed-off-by: Alexander Aring <[email protected]>
> ---
> net/mac802154/llsec.c | 20 ++++++++++----------
> 1 file changed, 10 insertions(+), 10 deletions(-)

all 6 patches have been applied to bluetooth-next tree.

Regards

Marcel


2015-10-16 12:44:11

by Jukka Rissanen

[permalink] [raw]
Subject: Re: [PATCH bluetooth-next 6/6] 6lowpan: remove lowpan_fetch_skb_u8

Hi Alex,


Acked-by: Jukka Rissanen <[email protected]>


On ti, 2015-10-13 at 13:42 +0200, Alexander Aring wrote:
> This patch removes the lowpan_fetch_skb_u8 function for getting the iphc
> bytes. Instead we using the generic which has a len parameter to tell
> the amount of bytes to fetch.
>
> Signed-off-by: Alexander Aring <[email protected]>
> ---
> include/net/6lowpan.h | 27 ++++++++++++++-------------
> net/6lowpan/iphc.c | 4 ++--
> 2 files changed, 16 insertions(+), 15 deletions(-)
>
> diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
> index ac30ad3..4afdbb3 100644
> --- a/include/net/6lowpan.h
> +++ b/include/net/6lowpan.h
> @@ -287,19 +287,20 @@ static inline void raw_dump_inline(const char *caller, char *msg,
> const unsigned char *buf, int len) { }
> #endif
>
> -static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
> -{
> - if (unlikely(!pskb_may_pull(skb, 1)))
> - return -EINVAL;
> -
> - *val = skb->data[0];
> - skb_pull(skb, 1);
> -
> - return 0;
> -}
> -
> -static inline bool lowpan_fetch_skb(struct sk_buff *skb,
> - void *data, const unsigned int len)
> +/**
> + * lowpan_fetch_skb - getting inline data from 6LoWPAN header
> + *
> + * This function will pull data from sk buffer and put it into data to
> + * remove the 6LoWPAN inline data. This function returns true if the
> + * sk buffer is too small to pull the amount of data which is specified
> + * by len.
> + *
> + * @skb: the buffer where the inline data should be pulled from.
> + * @data: destination buffer for the inline data.
> + * @len: amount of data which should be pulled in bytes.
> + */
> +static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data,
> + unsigned int len)
> {
> if (unlikely(!pskb_may_pull(skb, len)))
> return true;
> diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
> index 8f967d3..87d8f1f 100644
> --- a/net/6lowpan/iphc.c
> +++ b/net/6lowpan/iphc.c
> @@ -265,8 +265,8 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
> raw_dump_table(__func__, "raw skb data dump uncompressed",
> skb->data, skb->len);
>
> - if (lowpan_fetch_skb_u8(skb, &iphc0) ||
> - lowpan_fetch_skb_u8(skb, &iphc1))
> + if (lowpan_fetch_skb(skb, &iphc0, sizeof(iphc0)) ||
> + lowpan_fetch_skb(skb, &iphc1, sizeof(iphc1)))
> return -EINVAL;
>
> /* another if the CID flag is set */


Cheers,
Jukka



2015-10-16 12:43:26

by Jukka Rissanen

[permalink] [raw]
Subject: Re: [PATCH bluetooth-next 5/6] 6lowpan: cleanup lowpan_header_decompress

Hi Alex,

On ti, 2015-10-13 at 13:42 +0200, Alexander Aring wrote:
> This patch changes the lowpan_header_decompress function by removing
> inklayer related information from parameters. This is currently for

small typo above "inklayer" -> "linklayer"

Other than that ack from me.


Acked-by: Jukka Rissanen <[email protected]>


> supporting short and extended address for iphc handling in 802154.
> We don't support short address handling anyway right now, but there
> exists already code for handling short addresses in
> lowpan_header_decompress.
>
> The address parameters are also changed to a void pointer, so 6LoWPAN
> linklayer specific code can put complex structures as these parameters
> and cast it again inside the generic code by evaluating linklayer type
> before. The order is also changed by destination address at first and
> then source address, which is the same like all others functions where
> destination is always the first, memcpy, dev_hard_header,
> lowpan_header_compress, etc.
>
> This patch also moves the fetching of iphc values from 6LoWPAN linklayer
> specific code into the generic branch.
>
> Signed-off-by: Alexander Aring <[email protected]>
> ---
> include/net/6lowpan.h | 24 +++++++---
> include/net/mac802154.h | 10 ++++
> net/6lowpan/iphc.c | 113 +++++++++++++++++++++++++++-----------------
> net/6lowpan/nhc.c | 3 +-
> net/6lowpan/nhc.h | 3 +-
> net/bluetooth/6lowpan.c | 20 +-------
> net/ieee802154/6lowpan/rx.c | 26 +---------
> 7 files changed, 103 insertions(+), 96 deletions(-)
>
> diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
> index 6f1e0bd..ac30ad3 100644
> --- a/include/net/6lowpan.h
> +++ b/include/net/6lowpan.h
> @@ -319,12 +319,24 @@ static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,
>
> void lowpan_netdev_setup(struct net_device *dev, enum lowpan_lltypes lltype);
>
> -int
> -lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
> - const u8 *saddr, const u8 saddr_type,
> - const u8 saddr_len, const u8 *daddr,
> - const u8 daddr_type, const u8 daddr_len,
> - u8 iphc0, u8 iphc1);
> +/**
> + * lowpan_header_decompress - replace 6LoWPAN header with IPv6 header
> + *
> + * This function replaces the IPHC 6LoWPAN header which should be pointed at
> + * skb->data and skb_network_header, with the IPv6 header.
> + * It would be nice that the caller have the necessary headroom of IPv6 header
> + * and greatest Transport layer header, this would reduce the overhead for
> + * reallocate headroom.
> + *
> + * @skb: the buffer which should be manipulate.
> + * @dev: the lowpan net device pointer.
> + * @daddr: destination lladdr of mac header which is used for compression
> + * methods.
> + * @saddr: source lladdr of mac header which is used for compression
> + * methods.
> + */
> +int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
> + const void *daddr, const void *saddr);
>
> /**
> * lowpan_header_compress - replace IPv6 header with 6LoWPAN header
> diff --git a/include/net/mac802154.h b/include/net/mac802154.h
> index 5718765..da574bb 100644
> --- a/include/net/mac802154.h
> +++ b/include/net/mac802154.h
> @@ -277,6 +277,16 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src)
> }
>
> /**
> + * ieee802154_le16_to_be16 - copies and convert le16 to be16
> + * @be16_dst: be16 destination pointer
> + * @le16_src: le16 source pointer
> + */
> +static inline void ieee802154_le16_to_be16(void *be16_dst, const void *le16_src)
> +{
> + __put_unaligned_memmove16(swab16p(le16_src), be16_dst);
> +}
> +
> +/**
> * ieee802154_alloc_hw - Allocate a new hardware device
> *
> * This must be called once for each hardware device. The returned pointer
> diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
> index 4e4af8c..8f967d3 100644
> --- a/net/6lowpan/iphc.c
> +++ b/net/6lowpan/iphc.c
> @@ -49,21 +49,71 @@
> #include <linux/bitops.h>
> #include <linux/if_arp.h>
> #include <linux/netdevice.h>
> +
> #include <net/6lowpan.h>
> #include <net/ipv6.h>
> -#include <net/af_ieee802154.h>
> +
> +/* special link-layer handling */
> +#include <net/mac802154.h>
>
> #include "nhc.h"
>
> +static inline void iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
> + const void *lladdr)
> +{
> + /* fe:80::XXXX:XXXX:XXXX:XXXX
> + * \_________________/
> + * hwaddr
> + */
> + ipaddr->s6_addr[0] = 0xFE;
> + ipaddr->s6_addr[1] = 0x80;
> + memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN);
> + /* second bit-flip (Universe/Local)
> + * is done according RFC2464
> + */
> + ipaddr->s6_addr[8] ^= 0x02;
> +}
> +
> +static inline void iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
> + const void *lladdr)
> +{
> + const struct ieee802154_addr *addr = lladdr;
> + u8 eui64[EUI64_ADDR_LEN] = { };
> +
> + switch (addr->mode) {
> + case IEEE802154_ADDR_LONG:
> + ieee802154_le64_to_be64(eui64, &addr->extended_addr);
> + iphc_uncompress_eui64_lladdr(ipaddr, eui64);
> + break;
> + case IEEE802154_ADDR_SHORT:
> + /* fe:80::ff:fe00:XXXX
> + * \__/
> + * short_addr
> + *
> + * Universe/Local bit is zero.
> + */
> + ipaddr->s6_addr[0] = 0xFE;
> + ipaddr->s6_addr[1] = 0x80;
> + ipaddr->s6_addr[11] = 0xFF;
> + ipaddr->s6_addr[12] = 0xFE;
> + ieee802154_le16_to_be16(&ipaddr->s6_addr16[7],
> + &addr->short_addr);
> + break;
> + default:
> + /* should never handled and filtered by 802154 6lowpan */
> + WARN_ON_ONCE(1);
> + break;
> + }
> +}
> +
> /* Uncompress address function for source and
> * destination address(non-multicast).
> *
> * address_mode is sam value or dam value.
> */
> -static int uncompress_addr(struct sk_buff *skb,
> - struct in6_addr *ipaddr, const u8 address_mode,
> - const u8 *lladdr, const u8 addr_type,
> - const u8 addr_len)
> +static int uncompress_addr(struct sk_buff *skb, const struct net_device *dev,
> + struct in6_addr *ipaddr, u8 address_mode,
> + const void *lladdr)
> {
> bool fail;
>
> @@ -88,36 +138,13 @@ static int uncompress_addr(struct sk_buff *skb,
> break;
> case LOWPAN_IPHC_ADDR_03:
> fail = false;
> - switch (addr_type) {
> - case IEEE802154_ADDR_LONG:
> - /* fe:80::XXXX:XXXX:XXXX:XXXX
> - * \_________________/
> - * hwaddr
> - */
> - ipaddr->s6_addr[0] = 0xFE;
> - ipaddr->s6_addr[1] = 0x80;
> - memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
> - /* second bit-flip (Universe/Local)
> - * is done according RFC2464
> - */
> - ipaddr->s6_addr[8] ^= 0x02;
> - break;
> - case IEEE802154_ADDR_SHORT:
> - /* fe:80::ff:fe00:XXXX
> - * \__/
> - * short_addr
> - *
> - * Universe/Local bit is zero.
> - */
> - ipaddr->s6_addr[0] = 0xFE;
> - ipaddr->s6_addr[1] = 0x80;
> - ipaddr->s6_addr[11] = 0xFF;
> - ipaddr->s6_addr[12] = 0xFE;
> - ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
> + switch (lowpan_priv(dev)->lltype) {
> + case LOWPAN_LLTYPE_IEEE802154:
> + iphc_uncompress_802154_lladdr(ipaddr, lladdr);
> break;
> default:
> - pr_debug("Invalid addr_type set\n");
> - return -EINVAL;
> + iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
> + break;
> }
> break;
> default:
> @@ -228,20 +255,20 @@ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
> /* TTL uncompression values */
> static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };
>
> -int
> -lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
> - const u8 *saddr, const u8 saddr_type,
> - const u8 saddr_len, const u8 *daddr,
> - const u8 daddr_type, const u8 daddr_len,
> - u8 iphc0, u8 iphc1)
> +int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
> + const void *daddr, const void *saddr)
> {
> struct ipv6hdr hdr = {};
> - u8 tmp, num_context = 0;
> + u8 iphc0, iphc1, tmp, num_context = 0;
> int err;
>
> raw_dump_table(__func__, "raw skb data dump uncompressed",
> skb->data, skb->len);
>
> + if (lowpan_fetch_skb_u8(skb, &iphc0) ||
> + lowpan_fetch_skb_u8(skb, &iphc1))
> + return -EINVAL;
> +
> /* another if the CID flag is set */
> if (iphc1 & LOWPAN_IPHC_CID) {
> pr_debug("CID flag is set, increase header with one\n");
> @@ -323,8 +350,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
> } else {
> /* Source address uncompression */
> pr_debug("source address stateless compression\n");
> - err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
> - saddr_type, saddr_len);
> + err = uncompress_addr(skb, dev, &hdr.saddr, tmp, saddr);
> }
>
> /* Check on error of previous branch */
> @@ -347,8 +373,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
> return -EINVAL;
> }
> } else {
> - err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
> - daddr_type, daddr_len);
> + err = uncompress_addr(skb, dev, &hdr.daddr, tmp, daddr);
> pr_debug("dest: stateless compression mode %d dest %pI6c\n",
> tmp, &hdr.daddr);
> if (err)
> diff --git a/net/6lowpan/nhc.c b/net/6lowpan/nhc.c
> index fd20fc5..589224e 100644
> --- a/net/6lowpan/nhc.c
> +++ b/net/6lowpan/nhc.c
> @@ -157,7 +157,8 @@ out:
> return ret;
> }
>
> -int lowpan_nhc_do_uncompression(struct sk_buff *skb, struct net_device *dev,
> +int lowpan_nhc_do_uncompression(struct sk_buff *skb,
> + const struct net_device *dev,
> struct ipv6hdr *hdr)
> {
> struct lowpan_nhc *nhc;
> diff --git a/net/6lowpan/nhc.h b/net/6lowpan/nhc.h
> index c249f17..e3a5644 100644
> --- a/net/6lowpan/nhc.h
> +++ b/net/6lowpan/nhc.h
> @@ -119,7 +119,8 @@ int lowpan_nhc_do_compression(struct sk_buff *skb, const struct ipv6hdr *hdr,
> * @dev: netdevice for print logging information.
> * @hdr: ipv6hdr for setting nexthdr value.
> */
> -int lowpan_nhc_do_uncompression(struct sk_buff *skb, struct net_device *dev,
> +int lowpan_nhc_do_uncompression(struct sk_buff *skb,
> + const struct net_device *dev,
> struct ipv6hdr *hdr);
>
> /**
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index e2b66f3..4057d6e 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -21,8 +21,6 @@
> #include <net/ip6_route.h>
> #include <net/addrconf.h>
>
> -#include <net/af_ieee802154.h> /* to get the address type */
> -
> #include <net/bluetooth/bluetooth.h>
> #include <net/bluetooth/hci_core.h>
> #include <net/bluetooth/l2cap.h>
> @@ -272,7 +270,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
> struct l2cap_chan *chan)
> {
> const u8 *saddr, *daddr;
> - u8 iphc0, iphc1;
> struct lowpan_dev *dev;
> struct lowpan_peer *peer;
>
> @@ -287,22 +284,7 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
> saddr = peer->eui64_addr;
> daddr = dev->netdev->dev_addr;
>
> - /* at least two bytes will be used for the encoding */
> - if (skb->len < 2)
> - return -EINVAL;
> -
> - if (lowpan_fetch_skb_u8(skb, &iphc0))
> - return -EINVAL;
> -
> - if (lowpan_fetch_skb_u8(skb, &iphc1))
> - return -EINVAL;
> -
> - return lowpan_header_decompress(skb, netdev,
> - saddr, IEEE802154_ADDR_LONG,
> - EUI64_ADDR_LEN, daddr,
> - IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
> - iphc0, iphc1);
> -
> + return lowpan_header_decompress(skb, netdev, daddr, saddr);
> }
>
> static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
> diff --git a/net/ieee802154/6lowpan/rx.c b/net/ieee802154/6lowpan/rx.c
> index 65d55e0..403f171 100644
> --- a/net/ieee802154/6lowpan/rx.c
> +++ b/net/ieee802154/6lowpan/rx.c
> @@ -90,36 +90,12 @@ static lowpan_rx_result lowpan_rx_h_frag(struct sk_buff *skb)
>
> int lowpan_iphc_decompress(struct sk_buff *skb)
> {
> - struct ieee802154_addr_sa sa, da;
> struct ieee802154_hdr hdr;
> - u8 iphc0, iphc1;
> - void *sap, *dap;
>
> if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
> return -EINVAL;
>
> - raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
> -
> - if (lowpan_fetch_skb_u8(skb, &iphc0) ||
> - lowpan_fetch_skb_u8(skb, &iphc1))
> - return -EINVAL;
> -
> - ieee802154_addr_to_sa(&sa, &hdr.source);
> - ieee802154_addr_to_sa(&da, &hdr.dest);
> -
> - if (sa.addr_type == IEEE802154_ADDR_SHORT)
> - sap = &sa.short_addr;
> - else
> - sap = &sa.hwaddr;
> -
> - if (da.addr_type == IEEE802154_ADDR_SHORT)
> - dap = &da.short_addr;
> - else
> - dap = &da.hwaddr;
> -
> - return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
> - IEEE802154_ADDR_LEN, dap, da.addr_type,
> - IEEE802154_ADDR_LEN, iphc0, iphc1);
> + return lowpan_header_decompress(skb, skb->dev, &hdr.dest, &hdr.source);
> }
>
> static lowpan_rx_result lowpan_rx_h_iphc(struct sk_buff *skb)


Cheers,
Jukka



2015-10-16 12:41:51

by Jukka Rissanen

[permalink] [raw]
Subject: Re: [PATCH bluetooth-next 4/6] 6lowpan: cleanup lowpan_header_compress

Hi Alex,

Acked-by: Jukka Rissanen <[email protected]>


On ti, 2015-10-13 at 13:42 +0200, Alexander Aring wrote:
> This patch changes the lowpan_header_compress function by removing
> unused parameters like "len" and drop static value parameters of
> protocol type. Instead we really check the protocol type inside inside
> the skb structure. Also we drop the use of IEEE802154_ADDR_LEN which is
> link-layer specific. Instead we using EUI64_ADDR_LEN which should always
> the default case for now.
>
> Signed-off-by: Alexander Aring <[email protected]>
> ---
> include/net/6lowpan.h | 30 +++++++++++++++++++++++-------
> net/6lowpan/iphc.c | 17 +++++++----------
> net/bluetooth/6lowpan.c | 3 +--
> net/ieee802154/6lowpan/tx.c | 2 +-
> 4 files changed, 32 insertions(+), 20 deletions(-)
>
> diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
> index aa5a823..6f1e0bd 100644
> --- a/include/net/6lowpan.h
> +++ b/include/net/6lowpan.h
> @@ -258,7 +258,7 @@ struct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb)
> #ifdef DEBUG
> /* print data in line */
> static inline void raw_dump_inline(const char *caller, char *msg,
> - unsigned char *buf, int len)
> + const unsigned char *buf, int len)
> {
> if (msg)
> pr_debug("%s():%s: ", caller, msg);
> @@ -273,7 +273,7 @@ static inline void raw_dump_inline(const char *caller, char *msg,
> * ...
> */
> static inline void raw_dump_table(const char *caller, char *msg,
> - unsigned char *buf, int len)
> + const unsigned char *buf, int len)
> {
> if (msg)
> pr_debug("%s():%s:\n", caller, msg);
> @@ -282,9 +282,9 @@ static inline void raw_dump_table(const char *caller, char *msg,
> }
> #else
> static inline void raw_dump_table(const char *caller, char *msg,
> - unsigned char *buf, int len) { }
> + const unsigned char *buf, int len) { }
> static inline void raw_dump_inline(const char *caller, char *msg,
> - unsigned char *buf, int len) { }
> + const unsigned char *buf, int len) { }
> #endif
>
> static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
> @@ -325,8 +325,24 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
> const u8 saddr_len, const u8 *daddr,
> const u8 daddr_type, const u8 daddr_len,
> u8 iphc0, u8 iphc1);
> -int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
> - unsigned short type, const void *_daddr,
> - const void *_saddr, unsigned int len);
> +
> +/**
> + * lowpan_header_compress - replace IPv6 header with 6LoWPAN header
> + *
> + * This function replaces the IPv6 header which should be pointed at
> + * skb->data and skb_network_header, with the IPHC 6LoWPAN header.
> + * The caller need to be sure that the sk buffer is not shared and at have
> + * at least a headroom which is smaller or equal LOWPAN_IPHC_MAX_HEADER_LEN,
> + * which is the IPHC "more bytes than IPv6 header" at worst case.
> + *
> + * @skb: the buffer which should be manipulate.
> + * @dev: the lowpan net device pointer.
> + * @daddr: destination lladdr of mac header which is used for compression
> + * methods.
> + * @saddr: source lladdr of mac header which is used for compression
> + * methods.
> + */
> +int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
> + const void *daddr, const void *saddr);
>
> #endif /* __6LOWPAN_H__ */
> diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
> index dd5f27d..4e4af8c 100644
> --- a/net/6lowpan/iphc.c
> +++ b/net/6lowpan/iphc.c
> @@ -423,16 +423,15 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
> return rol8(val, shift);
> }
>
> -int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
> - unsigned short type, const void *_daddr,
> - const void *_saddr, unsigned int len)
> +int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
> + const void *daddr, const void *saddr)
> {
> u8 tmp, iphc0, iphc1, *hc_ptr;
> struct ipv6hdr *hdr;
> u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {};
> int ret, addr_type;
>
> - if (type != ETH_P_IPV6)
> + if (skb->protocol != htons(ETH_P_IPV6))
> return -EINVAL;
>
> hdr = ipv6_hdr(skb);
> @@ -456,10 +455,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
>
> /* TODO: context lookup */
>
> - raw_dump_inline(__func__, "saddr",
> - (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
> - raw_dump_inline(__func__, "daddr",
> - (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
> + raw_dump_inline(__func__, "saddr", saddr, EUI64_ADDR_LEN);
> + raw_dump_inline(__func__, "daddr", daddr, EUI64_ADDR_LEN);
>
> raw_dump_table(__func__, "sending raw skb network uncompressed packet",
> skb->data, skb->len);
> @@ -544,7 +541,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
> if (addr_type & IPV6_ADDR_LINKLOCAL) {
> iphc1 |= lowpan_compress_addr_64(&hc_ptr,
> LOWPAN_IPHC_SAM_BIT,
> - &hdr->saddr, _saddr);
> + &hdr->saddr, saddr);
> pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
> &hdr->saddr, iphc1);
> } else {
> @@ -589,7 +586,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
> if (addr_type & IPV6_ADDR_LINKLOCAL) {
> /* TODO: context lookup */
> iphc1 |= lowpan_compress_addr_64(&hc_ptr,
> - LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
> + LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
> pr_debug("dest address unicast link-local %pI6c "
> "iphc1 0x%02x\n", &hdr->daddr, iphc1);
> } else {
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index 665bf38..e2b66f3 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -489,8 +489,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
> status = 1;
> }
>
> - lowpan_header_compress(skb, netdev, ETH_P_IPV6, daddr,
> - dev->netdev->dev_addr, skb->len);
> + lowpan_header_compress(skb, netdev, daddr, dev->netdev->dev_addr);
>
> err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
> if (err < 0)
> diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
> index 62a21f6..2a5b2c2 100644
> --- a/net/ieee802154/6lowpan/tx.c
> +++ b/net/ieee802154/6lowpan/tx.c
> @@ -218,7 +218,7 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
> saddr = &info.saddr.u.extended_addr;
>
> *dgram_size = skb->len;
> - lowpan_header_compress(skb, ldev, ETH_P_IPV6, daddr, saddr, skb->len);
> + lowpan_header_compress(skb, ldev, daddr, saddr);
> /* dgram_offset = (saved bytes after compression) + lowpan header len */
> *dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb);
>


Cheers,
Jukka



2015-10-16 12:40:54

by Jukka Rissanen

[permalink] [raw]
Subject: Re: [PATCH bluetooth-next 3/6] 6lowpan: introduce LOWPAN_IPHC_MAX_HC_BUF_LEN

Hi Alex,

Acked-by: Jukka Rissanen <[email protected]>


On ti, 2015-10-13 at 13:42 +0200, Alexander Aring wrote:
> This patch introduces the LOWPAN_IPHC_MAX_HC_BUF_LEN define which
> represent the worst-case supported IPHC buffer length. It's used to
> allocate the stack buffer space for creating the IPHC header.
>
> Signed-off-by: Alexander Aring <[email protected]>
> ---
> include/net/6lowpan.h | 8 ++++++++
> net/6lowpan/iphc.c | 2 +-
> 2 files changed, 9 insertions(+), 1 deletion(-)
>
> diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
> index 07db532..aa5a823 100644
> --- a/include/net/6lowpan.h
> +++ b/include/net/6lowpan.h
> @@ -64,12 +64,20 @@
> #define EUI64_ADDR_LEN 8
>
> #define LOWPAN_NHC_MAX_ID_LEN 1
> +/* Maximum next header compression length which we currently support inclusive
> + * possible inline data.
> + */
> +#define LOWPAN_NHC_MAX_HDR_LEN (sizeof(struct udphdr))
> /* Max IPHC Header len without IPv6 hdr specific inline data.
> * Useful for getting the "extra" bytes we need at worst case compression.
> *
> * LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN
> */
> #define LOWPAN_IPHC_MAX_HEADER_LEN (2 + 1 + LOWPAN_NHC_MAX_ID_LEN)
> +/* Maximum worst case IPHC header buffer size */
> +#define LOWPAN_IPHC_MAX_HC_BUF_LEN (sizeof(struct ipv6hdr) + \
> + LOWPAN_IPHC_MAX_HEADER_LEN + \
> + LOWPAN_NHC_MAX_HDR_LEN)
>
> /*
> * ipv6 address based on mac
> diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
> index 78c8a49..dd5f27d 100644
> --- a/net/6lowpan/iphc.c
> +++ b/net/6lowpan/iphc.c
> @@ -429,7 +429,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
> {
> u8 tmp, iphc0, iphc1, *hc_ptr;
> struct ipv6hdr *hdr;
> - u8 head[100] = {};
> + u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {};
> int ret, addr_type;
>
> if (type != ETH_P_IPV6)


Cheers,
Jukka



2015-10-16 12:38:22

by Jukka Rissanen

[permalink] [raw]
Subject: Re: [PATCH bluetooth-next 2/6] bluetooth: 6lowpan: use lowpan dispatch helpers

Hi Alex,

the fixes in this patchset are fine and I verified with real hw that
everything works ok. The fix in this patch did not fix the skb poison
overwritten problem I am seeing and that needs more investigation.


Acked-by: Jukka Rissanen <[email protected]>


Cheers,
Jukka



On ti, 2015-10-13 at 13:42 +0200, Alexander Aring wrote:
> This patch adds a check if the dataroom of skb contains a dispatch value
> by checking if skb->len != 0. This patch also change the dispatch
> evaluation by the recently introduced helpers for checking the common
> 6LoWPAN dispatch values for IPv6 and IPHC header.
>
> There was also a forgotten else branch which should drop the packet if
> no matching dispatch is available.
>
> Signed-off-by: Alexander Aring <[email protected]>
> ---
> Jukka,
>
> there seems something wrong or I don't get it. There is a skb_share_check but
> inside the lowpan_is_iphc branch there is a skb_clone again. From my
> understanding skb_share_check will check if the skb (structure) is used
> somewhere else by looking at some refcounts, if yes then clone it.
>
> So after that the skb is always a clone, which means the skb (structure only)
> is not used somewhere else. Also IPHC will manipulate the skb (buffer) as well,
> so we need somewhere to be sure that the buffer isn't shared. There exists a
> function "skb_unshare" which is identically like skb_share_check just for the
> buffer.
>
> It could be that you ensure that the buffer is not shared somewhere else. Anyway
> I think the solution with checking the "refcounts" is a very low cost operation.
>
> btw:
> In case of IPv6 dispatch this is something else, because we move pointers there
> only (adjust skb->headroom with skb->data), not manipulate the buffer, so clone
> is enough there.
>
> net/bluetooth/6lowpan.c | 57 +++++++++++++++++++++++--------------------------
> 1 file changed, 27 insertions(+), 30 deletions(-)
>
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index db73b8a..665bf38 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -314,15 +314,17 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
> if (!netif_running(dev))
> goto drop;
>
> - if (dev->type != ARPHRD_6LOWPAN)
> + if (dev->type != ARPHRD_6LOWPAN || !skb->len)
> goto drop;
>
> + skb_reset_network_header(skb);
> +
> skb = skb_share_check(skb, GFP_ATOMIC);
> if (!skb)
> goto drop;
>
> /* check that it's our buffer */
> - if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
> + if (lowpan_is_ipv6(*skb_network_header(skb))) {
> /* Copy the packet so that the IPv6 header is
> * properly aligned.
> */
> @@ -334,7 +336,6 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
> local_skb->protocol = htons(ETH_P_IPV6);
> local_skb->pkt_type = PACKET_HOST;
>
> - skb_reset_network_header(local_skb);
> skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
>
> if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
> @@ -347,38 +348,34 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
>
> consume_skb(local_skb);
> consume_skb(skb);
> - } else {
> - switch (skb->data[0] & 0xe0) {
> - case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
> - local_skb = skb_clone(skb, GFP_ATOMIC);
> - if (!local_skb)
> - goto drop;
> + } else if (lowpan_is_iphc(*skb_network_header(skb))) {
> + local_skb = skb_clone(skb, GFP_ATOMIC);
> + if (!local_skb)
> + goto drop;
>
> - ret = iphc_decompress(local_skb, dev, chan);
> - if (ret < 0) {
> - kfree_skb(local_skb);
> - goto drop;
> - }
> + ret = iphc_decompress(local_skb, dev, chan);
> + if (ret < 0) {
> + kfree_skb(local_skb);
> + goto drop;
> + }
>
> - local_skb->protocol = htons(ETH_P_IPV6);
> - local_skb->pkt_type = PACKET_HOST;
> - local_skb->dev = dev;
> + local_skb->protocol = htons(ETH_P_IPV6);
> + local_skb->pkt_type = PACKET_HOST;
> + local_skb->dev = dev;
>
> - if (give_skb_to_upper(local_skb, dev)
> - != NET_RX_SUCCESS) {
> - kfree_skb(local_skb);
> - goto drop;
> - }
> + if (give_skb_to_upper(local_skb, dev)
> + != NET_RX_SUCCESS) {
> + kfree_skb(local_skb);
> + goto drop;
> + }
>
> - dev->stats.rx_bytes += skb->len;
> - dev->stats.rx_packets++;
> + dev->stats.rx_bytes += skb->len;
> + dev->stats.rx_packets++;
>
> - consume_skb(local_skb);
> - consume_skb(skb);
> - break;
> - default:
> - break;
> - }
> + consume_skb(local_skb);
> + consume_skb(skb);
> + } else {
> + goto drop;
> }
>
> return NET_RX_SUCCESS;



2015-10-13 13:02:43

by Jukka Rissanen

[permalink] [raw]
Subject: Re: [PATCH bluetooth-next 2/6] bluetooth: 6lowpan: use lowpan dispatch helpers

Hi Alex,

On ti, 2015-10-13 at 13:42 +0200, Alexander Aring wrote:
> This patch adds a check if the dataroom of skb contains a dispatch value
> by checking if skb->len != 0. This patch also change the dispatch
> evaluation by the recently introduced helpers for checking the common
> 6LoWPAN dispatch values for IPv6 and IPHC header.
>
> There was also a forgotten else branch which should drop the packet if
> no matching dispatch is available.
>
> Signed-off-by: Alexander Aring <[email protected]>
> ---
> Jukka,
>
> there seems something wrong or I don't get it. There is a skb_share_check but
> inside the lowpan_is_iphc branch there is a skb_clone again. From my
> understanding skb_share_check will check if the skb (structure) is used
> somewhere else by looking at some refcounts, if yes then clone it.
>
> So after that the skb is always a clone, which means the skb (structure only)
> is not used somewhere else. Also IPHC will manipulate the skb (buffer) as well,
> so we need somewhere to be sure that the buffer isn't shared. There exists a
> function "skb_unshare" which is identically like skb_share_check just for the
> buffer.
>
> It could be that you ensure that the buffer is not shared somewhere else. Anyway
> I think the solution with checking the "refcounts" is a very low cost operation.

I just got a kernel log http://ix.io/lng about some skb issue so this
could be related, I am investigating it.

>
> btw:
> In case of IPv6 dispatch this is something else, because we move pointers there
> only (adjust skb->headroom with skb->data), not manipulate the buffer, so clone
> is enough there.
>
> net/bluetooth/6lowpan.c | 57 +++++++++++++++++++++++--------------------------
> 1 file changed, 27 insertions(+), 30 deletions(-)
>
> diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
> index db73b8a..665bf38 100644
> --- a/net/bluetooth/6lowpan.c
> +++ b/net/bluetooth/6lowpan.c
> @@ -314,15 +314,17 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
> if (!netif_running(dev))
> goto drop;
>
> - if (dev->type != ARPHRD_6LOWPAN)
> + if (dev->type != ARPHRD_6LOWPAN || !skb->len)
> goto drop;
>
> + skb_reset_network_header(skb);
> +
> skb = skb_share_check(skb, GFP_ATOMIC);
> if (!skb)
> goto drop;
>
> /* check that it's our buffer */
> - if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
> + if (lowpan_is_ipv6(*skb_network_header(skb))) {
> /* Copy the packet so that the IPv6 header is
> * properly aligned.
> */
> @@ -334,7 +336,6 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
> local_skb->protocol = htons(ETH_P_IPV6);
> local_skb->pkt_type = PACKET_HOST;
>
> - skb_reset_network_header(local_skb);
> skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));
>
> if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
> @@ -347,38 +348,34 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
>
> consume_skb(local_skb);
> consume_skb(skb);
> - } else {
> - switch (skb->data[0] & 0xe0) {
> - case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
> - local_skb = skb_clone(skb, GFP_ATOMIC);
> - if (!local_skb)
> - goto drop;
> + } else if (lowpan_is_iphc(*skb_network_header(skb))) {
> + local_skb = skb_clone(skb, GFP_ATOMIC);
> + if (!local_skb)
> + goto drop;
>
> - ret = iphc_decompress(local_skb, dev, chan);
> - if (ret < 0) {
> - kfree_skb(local_skb);
> - goto drop;
> - }
> + ret = iphc_decompress(local_skb, dev, chan);
> + if (ret < 0) {
> + kfree_skb(local_skb);
> + goto drop;
> + }
>
> - local_skb->protocol = htons(ETH_P_IPV6);
> - local_skb->pkt_type = PACKET_HOST;
> - local_skb->dev = dev;
> + local_skb->protocol = htons(ETH_P_IPV6);
> + local_skb->pkt_type = PACKET_HOST;
> + local_skb->dev = dev;
>
> - if (give_skb_to_upper(local_skb, dev)
> - != NET_RX_SUCCESS) {
> - kfree_skb(local_skb);
> - goto drop;
> - }
> + if (give_skb_to_upper(local_skb, dev)
> + != NET_RX_SUCCESS) {
> + kfree_skb(local_skb);
> + goto drop;
> + }
>
> - dev->stats.rx_bytes += skb->len;
> - dev->stats.rx_packets++;
> + dev->stats.rx_bytes += skb->len;
> + dev->stats.rx_packets++;
>
> - consume_skb(local_skb);
> - consume_skb(skb);
> - break;
> - default:
> - break;
> - }
> + consume_skb(local_skb);
> + consume_skb(skb);
> + } else {
> + goto drop;
> }
>
> return NET_RX_SUCCESS;


Cheers,
Jukka



2015-10-13 11:42:59

by Alexander Aring

[permalink] [raw]
Subject: [PATCH bluetooth-next 6/6] 6lowpan: remove lowpan_fetch_skb_u8

This patch removes the lowpan_fetch_skb_u8 function for getting the iphc
bytes. Instead we using the generic which has a len parameter to tell
the amount of bytes to fetch.

Signed-off-by: Alexander Aring <[email protected]>
---
include/net/6lowpan.h | 27 ++++++++++++++-------------
net/6lowpan/iphc.c | 4 ++--
2 files changed, 16 insertions(+), 15 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index ac30ad3..4afdbb3 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -287,19 +287,20 @@ static inline void raw_dump_inline(const char *caller, char *msg,
const unsigned char *buf, int len) { }
#endif

-static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
-{
- if (unlikely(!pskb_may_pull(skb, 1)))
- return -EINVAL;
-
- *val = skb->data[0];
- skb_pull(skb, 1);
-
- return 0;
-}
-
-static inline bool lowpan_fetch_skb(struct sk_buff *skb,
- void *data, const unsigned int len)
+/**
+ * lowpan_fetch_skb - getting inline data from 6LoWPAN header
+ *
+ * This function will pull data from sk buffer and put it into data to
+ * remove the 6LoWPAN inline data. This function returns true if the
+ * sk buffer is too small to pull the amount of data which is specified
+ * by len.
+ *
+ * @skb: the buffer where the inline data should be pulled from.
+ * @data: destination buffer for the inline data.
+ * @len: amount of data which should be pulled in bytes.
+ */
+static inline bool lowpan_fetch_skb(struct sk_buff *skb, void *data,
+ unsigned int len)
{
if (unlikely(!pskb_may_pull(skb, len)))
return true;
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 8f967d3..87d8f1f 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -265,8 +265,8 @@ int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
raw_dump_table(__func__, "raw skb data dump uncompressed",
skb->data, skb->len);

- if (lowpan_fetch_skb_u8(skb, &iphc0) ||
- lowpan_fetch_skb_u8(skb, &iphc1))
+ if (lowpan_fetch_skb(skb, &iphc0, sizeof(iphc0)) ||
+ lowpan_fetch_skb(skb, &iphc1, sizeof(iphc1)))
return -EINVAL;

/* another if the CID flag is set */
--
2.6.1


2015-10-13 11:42:58

by Alexander Aring

[permalink] [raw]
Subject: [PATCH bluetooth-next 5/6] 6lowpan: cleanup lowpan_header_decompress

This patch changes the lowpan_header_decompress function by removing
inklayer related information from parameters. This is currently for
supporting short and extended address for iphc handling in 802154.
We don't support short address handling anyway right now, but there
exists already code for handling short addresses in
lowpan_header_decompress.

The address parameters are also changed to a void pointer, so 6LoWPAN
linklayer specific code can put complex structures as these parameters
and cast it again inside the generic code by evaluating linklayer type
before. The order is also changed by destination address at first and
then source address, which is the same like all others functions where
destination is always the first, memcpy, dev_hard_header,
lowpan_header_compress, etc.

This patch also moves the fetching of iphc values from 6LoWPAN linklayer
specific code into the generic branch.

Signed-off-by: Alexander Aring <[email protected]>
---
include/net/6lowpan.h | 24 +++++++---
include/net/mac802154.h | 10 ++++
net/6lowpan/iphc.c | 113 +++++++++++++++++++++++++++-----------------
net/6lowpan/nhc.c | 3 +-
net/6lowpan/nhc.h | 3 +-
net/bluetooth/6lowpan.c | 20 +-------
net/ieee802154/6lowpan/rx.c | 26 +---------
7 files changed, 103 insertions(+), 96 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 6f1e0bd..ac30ad3 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -319,12 +319,24 @@ static inline void lowpan_push_hc_data(u8 **hc_ptr, const void *data,

void lowpan_netdev_setup(struct net_device *dev, enum lowpan_lltypes lltype);

-int
-lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
- const u8 *saddr, const u8 saddr_type,
- const u8 saddr_len, const u8 *daddr,
- const u8 daddr_type, const u8 daddr_len,
- u8 iphc0, u8 iphc1);
+/**
+ * lowpan_header_decompress - replace 6LoWPAN header with IPv6 header
+ *
+ * This function replaces the IPHC 6LoWPAN header which should be pointed at
+ * skb->data and skb_network_header, with the IPv6 header.
+ * It would be nice that the caller have the necessary headroom of IPv6 header
+ * and greatest Transport layer header, this would reduce the overhead for
+ * reallocate headroom.
+ *
+ * @skb: the buffer which should be manipulate.
+ * @dev: the lowpan net device pointer.
+ * @daddr: destination lladdr of mac header which is used for compression
+ * methods.
+ * @saddr: source lladdr of mac header which is used for compression
+ * methods.
+ */
+int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
+ const void *daddr, const void *saddr);

/**
* lowpan_header_compress - replace IPv6 header with 6LoWPAN header
diff --git a/include/net/mac802154.h b/include/net/mac802154.h
index 5718765..da574bb 100644
--- a/include/net/mac802154.h
+++ b/include/net/mac802154.h
@@ -277,6 +277,16 @@ static inline void ieee802154_le64_to_be64(void *be64_dst, const void *le64_src)
}

/**
+ * ieee802154_le16_to_be16 - copies and convert le16 to be16
+ * @be16_dst: be16 destination pointer
+ * @le16_src: le16 source pointer
+ */
+static inline void ieee802154_le16_to_be16(void *be16_dst, const void *le16_src)
+{
+ __put_unaligned_memmove16(swab16p(le16_src), be16_dst);
+}
+
+/**
* ieee802154_alloc_hw - Allocate a new hardware device
*
* This must be called once for each hardware device. The returned pointer
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 4e4af8c..8f967d3 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -49,21 +49,71 @@
#include <linux/bitops.h>
#include <linux/if_arp.h>
#include <linux/netdevice.h>
+
#include <net/6lowpan.h>
#include <net/ipv6.h>
-#include <net/af_ieee802154.h>
+
+/* special link-layer handling */
+#include <net/mac802154.h>

#include "nhc.h"

+static inline void iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
+ const void *lladdr)
+{
+ /* fe:80::XXXX:XXXX:XXXX:XXXX
+ * \_________________/
+ * hwaddr
+ */
+ ipaddr->s6_addr[0] = 0xFE;
+ ipaddr->s6_addr[1] = 0x80;
+ memcpy(&ipaddr->s6_addr[8], lladdr, EUI64_ADDR_LEN);
+ /* second bit-flip (Universe/Local)
+ * is done according RFC2464
+ */
+ ipaddr->s6_addr[8] ^= 0x02;
+}
+
+static inline void iphc_uncompress_802154_lladdr(struct in6_addr *ipaddr,
+ const void *lladdr)
+{
+ const struct ieee802154_addr *addr = lladdr;
+ u8 eui64[EUI64_ADDR_LEN] = { };
+
+ switch (addr->mode) {
+ case IEEE802154_ADDR_LONG:
+ ieee802154_le64_to_be64(eui64, &addr->extended_addr);
+ iphc_uncompress_eui64_lladdr(ipaddr, eui64);
+ break;
+ case IEEE802154_ADDR_SHORT:
+ /* fe:80::ff:fe00:XXXX
+ * \__/
+ * short_addr
+ *
+ * Universe/Local bit is zero.
+ */
+ ipaddr->s6_addr[0] = 0xFE;
+ ipaddr->s6_addr[1] = 0x80;
+ ipaddr->s6_addr[11] = 0xFF;
+ ipaddr->s6_addr[12] = 0xFE;
+ ieee802154_le16_to_be16(&ipaddr->s6_addr16[7],
+ &addr->short_addr);
+ break;
+ default:
+ /* should never handled and filtered by 802154 6lowpan */
+ WARN_ON_ONCE(1);
+ break;
+ }
+}
+
/* Uncompress address function for source and
* destination address(non-multicast).
*
* address_mode is sam value or dam value.
*/
-static int uncompress_addr(struct sk_buff *skb,
- struct in6_addr *ipaddr, const u8 address_mode,
- const u8 *lladdr, const u8 addr_type,
- const u8 addr_len)
+static int uncompress_addr(struct sk_buff *skb, const struct net_device *dev,
+ struct in6_addr *ipaddr, u8 address_mode,
+ const void *lladdr)
{
bool fail;

@@ -88,36 +138,13 @@ static int uncompress_addr(struct sk_buff *skb,
break;
case LOWPAN_IPHC_ADDR_03:
fail = false;
- switch (addr_type) {
- case IEEE802154_ADDR_LONG:
- /* fe:80::XXXX:XXXX:XXXX:XXXX
- * \_________________/
- * hwaddr
- */
- ipaddr->s6_addr[0] = 0xFE;
- ipaddr->s6_addr[1] = 0x80;
- memcpy(&ipaddr->s6_addr[8], lladdr, addr_len);
- /* second bit-flip (Universe/Local)
- * is done according RFC2464
- */
- ipaddr->s6_addr[8] ^= 0x02;
- break;
- case IEEE802154_ADDR_SHORT:
- /* fe:80::ff:fe00:XXXX
- * \__/
- * short_addr
- *
- * Universe/Local bit is zero.
- */
- ipaddr->s6_addr[0] = 0xFE;
- ipaddr->s6_addr[1] = 0x80;
- ipaddr->s6_addr[11] = 0xFF;
- ipaddr->s6_addr[12] = 0xFE;
- ipaddr->s6_addr16[7] = htons(*((u16 *)lladdr));
+ switch (lowpan_priv(dev)->lltype) {
+ case LOWPAN_LLTYPE_IEEE802154:
+ iphc_uncompress_802154_lladdr(ipaddr, lladdr);
break;
default:
- pr_debug("Invalid addr_type set\n");
- return -EINVAL;
+ iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
+ break;
}
break;
default:
@@ -228,20 +255,20 @@ static int lowpan_uncompress_multicast_daddr(struct sk_buff *skb,
/* TTL uncompression values */
static const u8 lowpan_ttl_values[] = { 0, 1, 64, 255 };

-int
-lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
- const u8 *saddr, const u8 saddr_type,
- const u8 saddr_len, const u8 *daddr,
- const u8 daddr_type, const u8 daddr_len,
- u8 iphc0, u8 iphc1)
+int lowpan_header_decompress(struct sk_buff *skb, const struct net_device *dev,
+ const void *daddr, const void *saddr)
{
struct ipv6hdr hdr = {};
- u8 tmp, num_context = 0;
+ u8 iphc0, iphc1, tmp, num_context = 0;
int err;

raw_dump_table(__func__, "raw skb data dump uncompressed",
skb->data, skb->len);

+ if (lowpan_fetch_skb_u8(skb, &iphc0) ||
+ lowpan_fetch_skb_u8(skb, &iphc1))
+ return -EINVAL;
+
/* another if the CID flag is set */
if (iphc1 & LOWPAN_IPHC_CID) {
pr_debug("CID flag is set, increase header with one\n");
@@ -323,8 +350,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
} else {
/* Source address uncompression */
pr_debug("source address stateless compression\n");
- err = uncompress_addr(skb, &hdr.saddr, tmp, saddr,
- saddr_type, saddr_len);
+ err = uncompress_addr(skb, dev, &hdr.saddr, tmp, saddr);
}

/* Check on error of previous branch */
@@ -347,8 +373,7 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
return -EINVAL;
}
} else {
- err = uncompress_addr(skb, &hdr.daddr, tmp, daddr,
- daddr_type, daddr_len);
+ err = uncompress_addr(skb, dev, &hdr.daddr, tmp, daddr);
pr_debug("dest: stateless compression mode %d dest %pI6c\n",
tmp, &hdr.daddr);
if (err)
diff --git a/net/6lowpan/nhc.c b/net/6lowpan/nhc.c
index fd20fc5..589224e 100644
--- a/net/6lowpan/nhc.c
+++ b/net/6lowpan/nhc.c
@@ -157,7 +157,8 @@ out:
return ret;
}

-int lowpan_nhc_do_uncompression(struct sk_buff *skb, struct net_device *dev,
+int lowpan_nhc_do_uncompression(struct sk_buff *skb,
+ const struct net_device *dev,
struct ipv6hdr *hdr)
{
struct lowpan_nhc *nhc;
diff --git a/net/6lowpan/nhc.h b/net/6lowpan/nhc.h
index c249f17..e3a5644 100644
--- a/net/6lowpan/nhc.h
+++ b/net/6lowpan/nhc.h
@@ -119,7 +119,8 @@ int lowpan_nhc_do_compression(struct sk_buff *skb, const struct ipv6hdr *hdr,
* @dev: netdevice for print logging information.
* @hdr: ipv6hdr for setting nexthdr value.
*/
-int lowpan_nhc_do_uncompression(struct sk_buff *skb, struct net_device *dev,
+int lowpan_nhc_do_uncompression(struct sk_buff *skb,
+ const struct net_device *dev,
struct ipv6hdr *hdr);

/**
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index e2b66f3..4057d6e 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -21,8 +21,6 @@
#include <net/ip6_route.h>
#include <net/addrconf.h>

-#include <net/af_ieee802154.h> /* to get the address type */
-
#include <net/bluetooth/bluetooth.h>
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
@@ -272,7 +270,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
struct l2cap_chan *chan)
{
const u8 *saddr, *daddr;
- u8 iphc0, iphc1;
struct lowpan_dev *dev;
struct lowpan_peer *peer;

@@ -287,22 +284,7 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
saddr = peer->eui64_addr;
daddr = dev->netdev->dev_addr;

- /* at least two bytes will be used for the encoding */
- if (skb->len < 2)
- return -EINVAL;
-
- if (lowpan_fetch_skb_u8(skb, &iphc0))
- return -EINVAL;
-
- if (lowpan_fetch_skb_u8(skb, &iphc1))
- return -EINVAL;
-
- return lowpan_header_decompress(skb, netdev,
- saddr, IEEE802154_ADDR_LONG,
- EUI64_ADDR_LEN, daddr,
- IEEE802154_ADDR_LONG, EUI64_ADDR_LEN,
- iphc0, iphc1);
-
+ return lowpan_header_decompress(skb, netdev, daddr, saddr);
}

static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
diff --git a/net/ieee802154/6lowpan/rx.c b/net/ieee802154/6lowpan/rx.c
index 65d55e0..403f171 100644
--- a/net/ieee802154/6lowpan/rx.c
+++ b/net/ieee802154/6lowpan/rx.c
@@ -90,36 +90,12 @@ static lowpan_rx_result lowpan_rx_h_frag(struct sk_buff *skb)

int lowpan_iphc_decompress(struct sk_buff *skb)
{
- struct ieee802154_addr_sa sa, da;
struct ieee802154_hdr hdr;
- u8 iphc0, iphc1;
- void *sap, *dap;

if (ieee802154_hdr_peek_addrs(skb, &hdr) < 0)
return -EINVAL;

- raw_dump_table(__func__, "raw skb data dump", skb->data, skb->len);
-
- if (lowpan_fetch_skb_u8(skb, &iphc0) ||
- lowpan_fetch_skb_u8(skb, &iphc1))
- return -EINVAL;
-
- ieee802154_addr_to_sa(&sa, &hdr.source);
- ieee802154_addr_to_sa(&da, &hdr.dest);
-
- if (sa.addr_type == IEEE802154_ADDR_SHORT)
- sap = &sa.short_addr;
- else
- sap = &sa.hwaddr;
-
- if (da.addr_type == IEEE802154_ADDR_SHORT)
- dap = &da.short_addr;
- else
- dap = &da.hwaddr;
-
- return lowpan_header_decompress(skb, skb->dev, sap, sa.addr_type,
- IEEE802154_ADDR_LEN, dap, da.addr_type,
- IEEE802154_ADDR_LEN, iphc0, iphc1);
+ return lowpan_header_decompress(skb, skb->dev, &hdr.dest, &hdr.source);
}

static lowpan_rx_result lowpan_rx_h_iphc(struct sk_buff *skb)
--
2.6.1


2015-10-13 11:42:57

by Alexander Aring

[permalink] [raw]
Subject: [PATCH bluetooth-next 4/6] 6lowpan: cleanup lowpan_header_compress

This patch changes the lowpan_header_compress function by removing
unused parameters like "len" and drop static value parameters of
protocol type. Instead we really check the protocol type inside inside
the skb structure. Also we drop the use of IEEE802154_ADDR_LEN which is
link-layer specific. Instead we using EUI64_ADDR_LEN which should always
the default case for now.

Signed-off-by: Alexander Aring <[email protected]>
---
include/net/6lowpan.h | 30 +++++++++++++++++++++++-------
net/6lowpan/iphc.c | 17 +++++++----------
net/bluetooth/6lowpan.c | 3 +--
net/ieee802154/6lowpan/tx.c | 2 +-
4 files changed, 32 insertions(+), 20 deletions(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index aa5a823..6f1e0bd 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -258,7 +258,7 @@ struct lowpan_802154_cb *lowpan_802154_cb(const struct sk_buff *skb)
#ifdef DEBUG
/* print data in line */
static inline void raw_dump_inline(const char *caller, char *msg,
- unsigned char *buf, int len)
+ const unsigned char *buf, int len)
{
if (msg)
pr_debug("%s():%s: ", caller, msg);
@@ -273,7 +273,7 @@ static inline void raw_dump_inline(const char *caller, char *msg,
* ...
*/
static inline void raw_dump_table(const char *caller, char *msg,
- unsigned char *buf, int len)
+ const unsigned char *buf, int len)
{
if (msg)
pr_debug("%s():%s:\n", caller, msg);
@@ -282,9 +282,9 @@ static inline void raw_dump_table(const char *caller, char *msg,
}
#else
static inline void raw_dump_table(const char *caller, char *msg,
- unsigned char *buf, int len) { }
+ const unsigned char *buf, int len) { }
static inline void raw_dump_inline(const char *caller, char *msg,
- unsigned char *buf, int len) { }
+ const unsigned char *buf, int len) { }
#endif

static inline int lowpan_fetch_skb_u8(struct sk_buff *skb, u8 *val)
@@ -325,8 +325,24 @@ lowpan_header_decompress(struct sk_buff *skb, struct net_device *dev,
const u8 saddr_len, const u8 *daddr,
const u8 daddr_type, const u8 daddr_len,
u8 iphc0, u8 iphc1);
-int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *_daddr,
- const void *_saddr, unsigned int len);
+
+/**
+ * lowpan_header_compress - replace IPv6 header with 6LoWPAN header
+ *
+ * This function replaces the IPv6 header which should be pointed at
+ * skb->data and skb_network_header, with the IPHC 6LoWPAN header.
+ * The caller need to be sure that the sk buffer is not shared and at have
+ * at least a headroom which is smaller or equal LOWPAN_IPHC_MAX_HEADER_LEN,
+ * which is the IPHC "more bytes than IPv6 header" at worst case.
+ *
+ * @skb: the buffer which should be manipulate.
+ * @dev: the lowpan net device pointer.
+ * @daddr: destination lladdr of mac header which is used for compression
+ * methods.
+ * @saddr: source lladdr of mac header which is used for compression
+ * methods.
+ */
+int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
+ const void *daddr, const void *saddr);

#endif /* __6LOWPAN_H__ */
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index dd5f27d..4e4af8c 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -423,16 +423,15 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, u8 shift,
return rol8(val, shift);
}

-int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
- unsigned short type, const void *_daddr,
- const void *_saddr, unsigned int len)
+int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
+ const void *daddr, const void *saddr)
{
u8 tmp, iphc0, iphc1, *hc_ptr;
struct ipv6hdr *hdr;
u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {};
int ret, addr_type;

- if (type != ETH_P_IPV6)
+ if (skb->protocol != htons(ETH_P_IPV6))
return -EINVAL;

hdr = ipv6_hdr(skb);
@@ -456,10 +455,8 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,

/* TODO: context lookup */

- raw_dump_inline(__func__, "saddr",
- (unsigned char *)_saddr, IEEE802154_ADDR_LEN);
- raw_dump_inline(__func__, "daddr",
- (unsigned char *)_daddr, IEEE802154_ADDR_LEN);
+ raw_dump_inline(__func__, "saddr", saddr, EUI64_ADDR_LEN);
+ raw_dump_inline(__func__, "daddr", daddr, EUI64_ADDR_LEN);

raw_dump_table(__func__, "sending raw skb network uncompressed packet",
skb->data, skb->len);
@@ -544,7 +541,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
if (addr_type & IPV6_ADDR_LINKLOCAL) {
iphc1 |= lowpan_compress_addr_64(&hc_ptr,
LOWPAN_IPHC_SAM_BIT,
- &hdr->saddr, _saddr);
+ &hdr->saddr, saddr);
pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
&hdr->saddr, iphc1);
} else {
@@ -589,7 +586,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
if (addr_type & IPV6_ADDR_LINKLOCAL) {
/* TODO: context lookup */
iphc1 |= lowpan_compress_addr_64(&hc_ptr,
- LOWPAN_IPHC_DAM_BIT, &hdr->daddr, _daddr);
+ LOWPAN_IPHC_DAM_BIT, &hdr->daddr, daddr);
pr_debug("dest address unicast link-local %pI6c "
"iphc1 0x%02x\n", &hdr->daddr, iphc1);
} else {
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index 665bf38..e2b66f3 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -489,8 +489,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
status = 1;
}

- lowpan_header_compress(skb, netdev, ETH_P_IPV6, daddr,
- dev->netdev->dev_addr, skb->len);
+ lowpan_header_compress(skb, netdev, daddr, dev->netdev->dev_addr);

err = dev_hard_header(skb, netdev, ETH_P_IPV6, NULL, NULL, 0);
if (err < 0)
diff --git a/net/ieee802154/6lowpan/tx.c b/net/ieee802154/6lowpan/tx.c
index 62a21f6..2a5b2c2 100644
--- a/net/ieee802154/6lowpan/tx.c
+++ b/net/ieee802154/6lowpan/tx.c
@@ -218,7 +218,7 @@ static int lowpan_header(struct sk_buff *skb, struct net_device *ldev,
saddr = &info.saddr.u.extended_addr;

*dgram_size = skb->len;
- lowpan_header_compress(skb, ldev, ETH_P_IPV6, daddr, saddr, skb->len);
+ lowpan_header_compress(skb, ldev, daddr, saddr);
/* dgram_offset = (saved bytes after compression) + lowpan header len */
*dgram_offset = (*dgram_size - skb->len) + skb_network_header_len(skb);

--
2.6.1


2015-10-13 11:42:56

by Alexander Aring

[permalink] [raw]
Subject: [PATCH bluetooth-next 3/6] 6lowpan: introduce LOWPAN_IPHC_MAX_HC_BUF_LEN

This patch introduces the LOWPAN_IPHC_MAX_HC_BUF_LEN define which
represent the worst-case supported IPHC buffer length. It's used to
allocate the stack buffer space for creating the IPHC header.

Signed-off-by: Alexander Aring <[email protected]>
---
include/net/6lowpan.h | 8 ++++++++
net/6lowpan/iphc.c | 2 +-
2 files changed, 9 insertions(+), 1 deletion(-)

diff --git a/include/net/6lowpan.h b/include/net/6lowpan.h
index 07db532..aa5a823 100644
--- a/include/net/6lowpan.h
+++ b/include/net/6lowpan.h
@@ -64,12 +64,20 @@
#define EUI64_ADDR_LEN 8

#define LOWPAN_NHC_MAX_ID_LEN 1
+/* Maximum next header compression length which we currently support inclusive
+ * possible inline data.
+ */
+#define LOWPAN_NHC_MAX_HDR_LEN (sizeof(struct udphdr))
/* Max IPHC Header len without IPv6 hdr specific inline data.
* Useful for getting the "extra" bytes we need at worst case compression.
*
* LOWPAN_IPHC + CID + LOWPAN_NHC_MAX_ID_LEN
*/
#define LOWPAN_IPHC_MAX_HEADER_LEN (2 + 1 + LOWPAN_NHC_MAX_ID_LEN)
+/* Maximum worst case IPHC header buffer size */
+#define LOWPAN_IPHC_MAX_HC_BUF_LEN (sizeof(struct ipv6hdr) + \
+ LOWPAN_IPHC_MAX_HEADER_LEN + \
+ LOWPAN_NHC_MAX_HDR_LEN)

/*
* ipv6 address based on mac
diff --git a/net/6lowpan/iphc.c b/net/6lowpan/iphc.c
index 78c8a49..dd5f27d 100644
--- a/net/6lowpan/iphc.c
+++ b/net/6lowpan/iphc.c
@@ -429,7 +429,7 @@ int lowpan_header_compress(struct sk_buff *skb, struct net_device *dev,
{
u8 tmp, iphc0, iphc1, *hc_ptr;
struct ipv6hdr *hdr;
- u8 head[100] = {};
+ u8 head[LOWPAN_IPHC_MAX_HC_BUF_LEN] = {};
int ret, addr_type;

if (type != ETH_P_IPV6)
--
2.6.1


2015-10-13 11:42:55

by Alexander Aring

[permalink] [raw]
Subject: [PATCH bluetooth-next 2/6] bluetooth: 6lowpan: use lowpan dispatch helpers

This patch adds a check if the dataroom of skb contains a dispatch value
by checking if skb->len != 0. This patch also change the dispatch
evaluation by the recently introduced helpers for checking the common
6LoWPAN dispatch values for IPv6 and IPHC header.

There was also a forgotten else branch which should drop the packet if
no matching dispatch is available.

Signed-off-by: Alexander Aring <[email protected]>
---
Jukka,

there seems something wrong or I don't get it. There is a skb_share_check but
inside the lowpan_is_iphc branch there is a skb_clone again. From my
understanding skb_share_check will check if the skb (structure) is used
somewhere else by looking at some refcounts, if yes then clone it.

So after that the skb is always a clone, which means the skb (structure only)
is not used somewhere else. Also IPHC will manipulate the skb (buffer) as well,
so we need somewhere to be sure that the buffer isn't shared. There exists a
function "skb_unshare" which is identically like skb_share_check just for the
buffer.

It could be that you ensure that the buffer is not shared somewhere else. Anyway
I think the solution with checking the "refcounts" is a very low cost operation.

btw:
In case of IPv6 dispatch this is something else, because we move pointers there
only (adjust skb->headroom with skb->data), not manipulate the buffer, so clone
is enough there.

net/bluetooth/6lowpan.c | 57 +++++++++++++++++++++++--------------------------
1 file changed, 27 insertions(+), 30 deletions(-)

diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c
index db73b8a..665bf38 100644
--- a/net/bluetooth/6lowpan.c
+++ b/net/bluetooth/6lowpan.c
@@ -314,15 +314,17 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
if (!netif_running(dev))
goto drop;

- if (dev->type != ARPHRD_6LOWPAN)
+ if (dev->type != ARPHRD_6LOWPAN || !skb->len)
goto drop;

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

/* check that it's our buffer */
- if (skb->data[0] == LOWPAN_DISPATCH_IPV6) {
+ if (lowpan_is_ipv6(*skb_network_header(skb))) {
/* Copy the packet so that the IPv6 header is
* properly aligned.
*/
@@ -334,7 +336,6 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
local_skb->protocol = htons(ETH_P_IPV6);
local_skb->pkt_type = PACKET_HOST;

- skb_reset_network_header(local_skb);
skb_set_transport_header(local_skb, sizeof(struct ipv6hdr));

if (give_skb_to_upper(local_skb, dev) != NET_RX_SUCCESS) {
@@ -347,38 +348,34 @@ static int recv_pkt(struct sk_buff *skb, struct net_device *dev,

consume_skb(local_skb);
consume_skb(skb);
- } else {
- switch (skb->data[0] & 0xe0) {
- case LOWPAN_DISPATCH_IPHC: /* ipv6 datagram */
- local_skb = skb_clone(skb, GFP_ATOMIC);
- if (!local_skb)
- goto drop;
+ } else if (lowpan_is_iphc(*skb_network_header(skb))) {
+ local_skb = skb_clone(skb, GFP_ATOMIC);
+ if (!local_skb)
+ goto drop;

- ret = iphc_decompress(local_skb, dev, chan);
- if (ret < 0) {
- kfree_skb(local_skb);
- goto drop;
- }
+ ret = iphc_decompress(local_skb, dev, chan);
+ if (ret < 0) {
+ kfree_skb(local_skb);
+ goto drop;
+ }

- local_skb->protocol = htons(ETH_P_IPV6);
- local_skb->pkt_type = PACKET_HOST;
- local_skb->dev = dev;
+ local_skb->protocol = htons(ETH_P_IPV6);
+ local_skb->pkt_type = PACKET_HOST;
+ local_skb->dev = dev;

- if (give_skb_to_upper(local_skb, dev)
- != NET_RX_SUCCESS) {
- kfree_skb(local_skb);
- goto drop;
- }
+ if (give_skb_to_upper(local_skb, dev)
+ != NET_RX_SUCCESS) {
+ kfree_skb(local_skb);
+ goto drop;
+ }

- dev->stats.rx_bytes += skb->len;
- dev->stats.rx_packets++;
+ dev->stats.rx_bytes += skb->len;
+ dev->stats.rx_packets++;

- consume_skb(local_skb);
- consume_skb(skb);
- break;
- default:
- break;
- }
+ consume_skb(local_skb);
+ consume_skb(skb);
+ } else {
+ goto drop;
}

return NET_RX_SUCCESS;
--
2.6.1