Commit ce2463b2 authored by Alexander Aring's avatar Alexander Aring Committed by David S. Miller

6lowpan: lowpan_uncompress_addr with address_mode

This patch drops the pre and postcount calculation from the
lowpan_uncompress_addr function.We use instead a switch/case
over address_mode value. The original implementation has several
bugs in this function and it was hard to decrypt how it works.
To make it maintainable and fix these bugs this patch basically
reimplements lowpan_uncompress_addr from scratch.

A list of bugs we found in the current implementation:

1) Properly support uncompression of short-address based IPv6 addresses
   (instead of basically copying garbage)

2) Fix use and uncompression of long-addresses based IPv6 addresses

3) Add missing ff:fe00 in the case of SAM/DAM = 2 and M = 0
Signed-off-by: default avatarAlexander Aring <alex.aring@gmail.com>
Reviewed-by: default avatarWerner Almesberger <werner@almesberger.net>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 84c2e7bc
...@@ -67,30 +67,6 @@ static const u8 lowpan_ttl_values[] = {0, 1, 64, 255}; ...@@ -67,30 +67,6 @@ static const u8 lowpan_ttl_values[] = {0, 1, 64, 255};
static LIST_HEAD(lowpan_devices); static LIST_HEAD(lowpan_devices);
/*
* Uncompression of linklocal:
* 0 -> 16 bytes from packet
* 1 -> 2 bytes from prefix - bunch of zeroes and 8 from packet
* 2 -> 2 bytes from prefix - zeroes + 2 from packet
* 3 -> 2 bytes from prefix - infer 8 bytes from lladdr
*
* NOTE: => the uncompress function does change 0xf to 0x10
* NOTE: 0x00 => no-autoconfig => unspecified
*/
static const u8 lowpan_unc_llconf[] = {0x0f, 0x28, 0x22, 0x20};
/*
* Uncompression of ctx-based:
* 0 -> 0 bits from packet [unspecified / reserved]
* 1 -> 8 bytes from prefix - bunch of zeroes and 8 from packet
* 2 -> 8 bytes from prefix - zeroes + 2 from packet
* 3 -> 8 bytes from prefix - infer 8 bytes from lladdr
*/
static const u8 lowpan_unc_ctxconf[] = {0x00, 0x88, 0x82, 0x80};
/* Link local prefix */
static const u8 lowpan_llprefix[] = {0xfe, 0x80};
/* private device info */ /* private device info */
struct lowpan_dev_info { struct lowpan_dev_info {
struct net_device *real_dev; /* real WPAN device ptr */ struct net_device *real_dev; /* real WPAN device ptr */
...@@ -182,51 +158,86 @@ lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr, ...@@ -182,51 +158,86 @@ lowpan_compress_addr_64(u8 **hc06_ptr, u8 shift, const struct in6_addr *ipaddr,
return rol8(val, shift); return rol8(val, shift);
} }
static void
lowpan_uip_ds6_set_addr_iid(struct in6_addr *ipaddr, unsigned char *lladdr)
{
memcpy(&ipaddr->s6_addr[8], lladdr, IEEE802154_ADDR_LEN);
/* second bit-flip (Universe/Local) is done according RFC2464 */
ipaddr->s6_addr[8] ^= 0x02;
}
/* /*
* Uncompress addresses based on a prefix and a postfix with zeroes in * Uncompress address function for source and
* between. If the postfix is zero in length it will use the link address * destination address(non-multicast).
* to configure the IP address (autoconf style). *
* pref_post_count takes a byte where the first nibble specify prefix count * address_mode is sam value or dam value.
* and the second postfix count (NOTE: 15/0xf => 16 bytes copy).
*/ */
static int static int
lowpan_uncompress_addr(struct sk_buff *skb, struct in6_addr *ipaddr, lowpan_uncompress_addr(struct sk_buff *skb,
u8 const *prefix, u8 pref_post_count, unsigned char *lladdr) struct in6_addr *ipaddr,
const u8 address_mode,
const struct ieee802154_addr *lladdr)
{ {
u8 prefcount = pref_post_count >> 4; bool fail;
u8 postcount = pref_post_count & 0x0f;
switch (address_mode) {
/* full nibble 15 => 16 */ case LOWPAN_IPHC_ADDR_00:
prefcount = (prefcount == 15 ? 16 : prefcount); /* for global link addresses */
postcount = (postcount == 15 ? 16 : postcount); fail = lowpan_fetch_skb(skb, ipaddr->s6_addr, 16);
break;
if (lladdr) case LOWPAN_IPHC_ADDR_01:
lowpan_raw_dump_inline(__func__, "linklocal address", /* fe:80::XXXX:XXXX:XXXX:XXXX */
lladdr, IEEE802154_ADDR_LEN); ipaddr->s6_addr[0] = 0xFE;
if (prefcount > 0) ipaddr->s6_addr[1] = 0x80;
memcpy(ipaddr, prefix, prefcount); fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[8], 8);
break;
if (postcount > 0) { case LOWPAN_IPHC_ADDR_02:
memcpy(&ipaddr->s6_addr[16 - postcount], skb->data, postcount); /* fe:80::ff:fe00:XXXX */
skb_pull(skb, postcount); ipaddr->s6_addr[0] = 0xFE;
} else if (prefcount > 0) { ipaddr->s6_addr[1] = 0x80;
if (lladdr == NULL) ipaddr->s6_addr[11] = 0xFF;
ipaddr->s6_addr[12] = 0xFE;
fail = lowpan_fetch_skb(skb, &ipaddr->s6_addr[14], 2);
break;
case LOWPAN_IPHC_ADDR_03:
fail = false;
switch (lladdr->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->hwaddr,
IEEE802154_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(lladdr->short_addr);
break;
default:
pr_debug("Invalid addr_type set\n");
return -EINVAL; return -EINVAL;
}
break;
default:
pr_debug("Invalid address mode value: 0x%x\n", address_mode);
return -EINVAL;
}
/* no IID based configuration if no prefix and no data */ if (fail) {
lowpan_uip_ds6_set_addr_iid(ipaddr, lladdr); pr_debug("Failed to fetch skb data\n");
return -EIO;
} }
pr_debug("uncompressing %d + %d => ", prefcount, postcount); lowpan_raw_dump_inline(NULL, "Reconstructed ipv6 addr is:\n",
lowpan_raw_dump_inline(NULL, NULL, ipaddr->s6_addr, 16); ipaddr->s6_addr, 16);
return 0; return 0;
} }
...@@ -775,7 +786,7 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -775,7 +786,7 @@ lowpan_process_data(struct sk_buff *skb)
{ {
struct ipv6hdr hdr = {}; struct ipv6hdr hdr = {};
u8 tmp, iphc0, iphc1, num_context = 0; u8 tmp, iphc0, iphc1, num_context = 0;
u8 *_saddr, *_daddr; const struct ieee802154_addr *_saddr, *_daddr;
int err; int err;
lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data, lowpan_raw_dump_table(__func__, "raw skb data dump", skb->data,
...@@ -878,8 +889,8 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -878,8 +889,8 @@ lowpan_process_data(struct sk_buff *skb)
if (lowpan_fetch_skb_u8(skb, &iphc1)) if (lowpan_fetch_skb_u8(skb, &iphc1))
goto drop; goto drop;
_saddr = mac_cb(skb)->sa.hwaddr; _saddr = &mac_cb(skb)->sa;
_daddr = mac_cb(skb)->da.hwaddr; _daddr = &mac_cb(skb)->da;
pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1); pr_debug("iphc0 = %02x, iphc1 = %02x\n", iphc0, iphc1);
...@@ -961,8 +972,7 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -961,8 +972,7 @@ lowpan_process_data(struct sk_buff *skb)
/* Source address uncompression */ /* Source address uncompression */
pr_debug("source address stateless compression\n"); pr_debug("source address stateless compression\n");
err = lowpan_uncompress_addr(skb, &hdr.saddr, lowpan_llprefix, err = lowpan_uncompress_addr(skb, &hdr.saddr, tmp, _saddr);
lowpan_unc_llconf[tmp], skb->data);
if (err) if (err)
goto drop; goto drop;
...@@ -982,8 +992,7 @@ lowpan_process_data(struct sk_buff *skb) ...@@ -982,8 +992,7 @@ lowpan_process_data(struct sk_buff *skb)
} }
} else { } else {
pr_debug("dest: stateless compression\n"); pr_debug("dest: stateless compression\n");
err = lowpan_uncompress_addr(skb, &hdr.daddr, lowpan_llprefix, err = lowpan_uncompress_addr(skb, &hdr.daddr, tmp, _daddr);
lowpan_unc_llconf[tmp], skb->data);
if (err) if (err)
goto drop; goto drop;
} }
......
...@@ -193,10 +193,12 @@ ...@@ -193,10 +193,12 @@
/* Values of fields within the IPHC encoding second byte */ /* Values of fields within the IPHC encoding second byte */
#define LOWPAN_IPHC_CID 0x80 #define LOWPAN_IPHC_CID 0x80
#define LOWPAN_IPHC_ADDR_00 0x00
#define LOWPAN_IPHC_ADDR_01 0x01
#define LOWPAN_IPHC_ADDR_02 0x02
#define LOWPAN_IPHC_ADDR_03 0x03
#define LOWPAN_IPHC_SAC 0x40 #define LOWPAN_IPHC_SAC 0x40
#define LOWPAN_IPHC_SAM_00 0x00
#define LOWPAN_IPHC_SAM_01 0x10
#define LOWPAN_IPHC_SAM_10 0x20
#define LOWPAN_IPHC_SAM 0x30 #define LOWPAN_IPHC_SAM 0x30
#define LOWPAN_IPHC_SAM_BIT 4 #define LOWPAN_IPHC_SAM_BIT 4
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment