6lowpan: add support for 802.15.4 short addr handling

This patch adds necessary handling for use the short address for
802.15.4 6lowpan. It contains support for IPHC address compression
and new matching algorithmn to decide which link layer address will be
used for 802.15.4 frame.

Reviewed-by: Stefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: Alexander Aring <aar@pengutronix.de>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Alexander Aring
2016-06-15 21:20:27 +02:00
committed by David S. Miller
parent cfce94653d
commit eab560e582
2 changed files with 195 additions and 85 deletions

View File

@@ -761,22 +761,75 @@ static const u8 lowpan_iphc_dam_to_sam_value[] = {
[LOWPAN_IPHC_DAM_11] = LOWPAN_IPHC_SAM_11,
};
static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct in6_addr *ipaddr,
static inline bool
lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr,
const struct lowpan_iphc_ctx *ctx,
const void *lladdr)
{
const struct ieee802154_addr *addr = lladdr;
unsigned char extended_addr[EUI64_ADDR_LEN];
bool lladdr_compress = false;
struct in6_addr tmp = {};
switch (addr->mode) {
case IEEE802154_ADDR_LONG:
ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
/* check for SAM/DAM = 11 */
memcpy(&tmp.s6_addr[8], &extended_addr, EUI64_ADDR_LEN);
/* second bit-flip (Universe/Local) is done according RFC2464 */
tmp.s6_addr[8] ^= 0x02;
/* context information are always used */
ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
if (ipv6_addr_equal(&tmp, ipaddr))
lladdr_compress = true;
break;
case IEEE802154_ADDR_SHORT:
tmp.s6_addr[11] = 0xFF;
tmp.s6_addr[12] = 0xFE;
ieee802154_le16_to_be16(&tmp.s6_addr16[7],
&addr->short_addr);
/* context information are always used */
ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
if (ipv6_addr_equal(&tmp, ipaddr))
lladdr_compress = true;
break;
default:
/* should never handled and filtered by 802154 6lowpan */
WARN_ON_ONCE(1);
break;
}
return lladdr_compress;
}
static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
const struct in6_addr *ipaddr,
const struct lowpan_iphc_ctx *ctx,
const unsigned char *lladdr, bool sam)
{
struct in6_addr tmp = {};
u8 dam;
/* check for SAM/DAM = 11 */
memcpy(&tmp.s6_addr[8], lladdr, 8);
/* second bit-flip (Universe/Local) is done according RFC2464 */
tmp.s6_addr[8] ^= 0x02;
/* context information are always used */
ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
if (ipv6_addr_equal(&tmp, ipaddr)) {
dam = LOWPAN_IPHC_DAM_11;
goto out;
switch (lowpan_dev(dev)->lltype) {
case LOWPAN_LLTYPE_IEEE802154:
if (lowpan_iphc_compress_ctx_802154_lladdr(ipaddr, ctx,
lladdr)) {
dam = LOWPAN_IPHC_DAM_11;
goto out;
}
break;
default:
/* check for SAM/DAM = 11 */
memcpy(&tmp.s6_addr[8], lladdr, EUI64_ADDR_LEN);
/* second bit-flip (Universe/Local) is done according RFC2464 */
tmp.s6_addr[8] ^= 0x02;
/* context information are always used */
ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
if (ipv6_addr_equal(&tmp, ipaddr)) {
dam = LOWPAN_IPHC_DAM_11;
goto out;
}
break;
}
memset(&tmp, 0, sizeof(tmp));
@@ -813,28 +866,85 @@ out:
return dam;
}
static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct in6_addr *ipaddr,
static inline bool
lowpan_iphc_compress_802154_lladdr(const struct in6_addr *ipaddr,
const void *lladdr)
{
const struct ieee802154_addr *addr = lladdr;
unsigned char extended_addr[EUI64_ADDR_LEN];
bool lladdr_compress = false;
struct in6_addr tmp = {};
switch (addr->mode) {
case IEEE802154_ADDR_LONG:
ieee802154_le64_to_be64(&extended_addr, &addr->extended_addr);
if (is_addr_mac_addr_based(ipaddr, extended_addr))
lladdr_compress = true;
break;
case IEEE802154_ADDR_SHORT:
/* fe:80::ff:fe00:XXXX
* \__/
* short_addr
*
* Universe/Local bit is zero.
*/
tmp.s6_addr[0] = 0xFE;
tmp.s6_addr[1] = 0x80;
tmp.s6_addr[11] = 0xFF;
tmp.s6_addr[12] = 0xFE;
ieee802154_le16_to_be16(&tmp.s6_addr16[7],
&addr->short_addr);
if (ipv6_addr_equal(&tmp, ipaddr))
lladdr_compress = true;
break;
default:
/* should never handled and filtered by 802154 6lowpan */
WARN_ON_ONCE(1);
break;
}
return lladdr_compress;
}
static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
const struct in6_addr *ipaddr,
const unsigned char *lladdr, bool sam)
{
u8 dam = LOWPAN_IPHC_DAM_00;
u8 dam = LOWPAN_IPHC_DAM_01;
if (is_addr_mac_addr_based(ipaddr, lladdr)) {
dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
pr_debug("address compression 0 bits\n");
} else if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
switch (lowpan_dev(dev)->lltype) {
case LOWPAN_LLTYPE_IEEE802154:
if (lowpan_iphc_compress_802154_lladdr(ipaddr, lladdr)) {
dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
pr_debug("address compression 0 bits\n");
goto out;
}
break;
default:
if (is_addr_mac_addr_based(ipaddr, lladdr)) {
dam = LOWPAN_IPHC_DAM_11; /* 0-bits */
pr_debug("address compression 0 bits\n");
goto out;
}
break;
}
if (lowpan_is_iid_16_bit_compressable(ipaddr)) {
/* compress IID to 16 bits xxxx::XXXX */
lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[7], 2);
dam = LOWPAN_IPHC_DAM_10; /* 16-bits */
raw_dump_inline(NULL, "Compressed ipv6 addr is (16 bits)",
*hc_ptr - 2, 2);
} else {
/* do not compress IID => xxxx::IID */
lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
dam = LOWPAN_IPHC_DAM_01; /* 64-bits */
raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
*hc_ptr - 8, 8);
goto out;
}
/* do not compress IID => xxxx::IID */
lowpan_push_hc_data(hc_ptr, &ipaddr->s6_addr16[4], 8);
raw_dump_inline(NULL, "Compressed ipv6 addr is (64 bits)",
*hc_ptr - 8, 8);
out:
if (sam)
return lowpan_iphc_dam_to_sam_value[dam];
else
@@ -1013,9 +1123,6 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
iphc0 = LOWPAN_DISPATCH_IPHC;
iphc1 = 0;
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);
@@ -1088,14 +1195,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
iphc1 |= LOWPAN_IPHC_SAC;
} else {
if (sci) {
iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->saddr,
iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
&hdr->saddr,
&sci_entry, saddr,
true);
iphc1 |= LOWPAN_IPHC_SAC;
} else {
if (ipv6_saddr_type & IPV6_ADDR_LINKLOCAL &&
lowpan_is_linklocal_zero_padded(hdr->saddr)) {
iphc1 |= lowpan_compress_addr_64(&hc_ptr,
iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
&hdr->saddr,
saddr, true);
pr_debug("source address unicast link-local %pI6c iphc1 0x%02x\n",
@@ -1123,14 +1231,15 @@ int lowpan_header_compress(struct sk_buff *skb, const struct net_device *dev,
}
} else {
if (dci) {
iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, &hdr->daddr,
iphc1 |= lowpan_compress_ctx_addr(&hc_ptr, dev,
&hdr->daddr,
&dci_entry, daddr,
false);
iphc1 |= LOWPAN_IPHC_DAC;
} else {
if (ipv6_daddr_type & IPV6_ADDR_LINKLOCAL &&
lowpan_is_linklocal_zero_padded(hdr->daddr)) {
iphc1 |= lowpan_compress_addr_64(&hc_ptr,
iphc1 |= lowpan_compress_addr_64(&hc_ptr, dev,
&hdr->daddr,
daddr, false);
pr_debug("dest address unicast link-local %pI6c iphc1 0x%02x\n",