Commit fa09ae66 authored by Luiz Augusto von Dentz's avatar Luiz Augusto von Dentz Committed by Marcel Holtmann

6lowpan: Use netdev addr_len to determine lladdr len

This allow technologies such as Bluetooth to use its native lladdr which
is eui48 instead of eui64 which was expected by functions like
lowpan_header_decompress and lowpan_header_compress.
Signed-off-by: default avatarLuiz Augusto von Dentz <luiz.von.dentz@intel.com>
Reviewed-by: default avatarStefan Schmidt <stefan@osg.samsung.com>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent 8a7a4b47
...@@ -198,6 +198,25 @@ static inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr, ...@@ -198,6 +198,25 @@ static inline void lowpan_iphc_uncompress_eui64_lladdr(struct in6_addr *ipaddr,
ipaddr->s6_addr[8] ^= 0x02; ipaddr->s6_addr[8] ^= 0x02;
} }
static inline void lowpan_iphc_uncompress_eui48_lladdr(struct in6_addr *ipaddr,
const void *lladdr)
{
/* fe:80::XXXX:XXff:feXX:XXXX
* \_________________/
* hwaddr
*/
ipaddr->s6_addr[0] = 0xFE;
ipaddr->s6_addr[1] = 0x80;
memcpy(&ipaddr->s6_addr[8], lladdr, 3);
ipaddr->s6_addr[11] = 0xFF;
ipaddr->s6_addr[12] = 0xFE;
memcpy(&ipaddr->s6_addr[13], lladdr + 3, 3);
/* second bit-flip (Universe/Local)
* is done according RFC2464
*/
ipaddr->s6_addr[8] ^= 0x02;
}
#ifdef DEBUG #ifdef DEBUG
/* print data in line */ /* print data in line */
static inline void raw_dump_inline(const char *caller, char *msg, static inline void raw_dump_inline(const char *caller, char *msg,
......
...@@ -278,6 +278,23 @@ lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev, ...@@ -278,6 +278,23 @@ lowpan_iphc_ctx_get_by_mcast_addr(const struct net_device *dev,
return ret; return ret;
} }
static void lowpan_iphc_uncompress_lladdr(const struct net_device *dev,
struct in6_addr *ipaddr,
const void *lladdr)
{
switch (dev->addr_len) {
case ETH_ALEN:
lowpan_iphc_uncompress_eui48_lladdr(ipaddr, lladdr);
break;
case EUI64_ADDR_LEN:
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr);
break;
default:
WARN_ON_ONCE(1);
break;
}
}
/* Uncompress address function for source and /* Uncompress address function for source and
* destination address(non-multicast). * destination address(non-multicast).
* *
...@@ -320,7 +337,7 @@ static int lowpan_iphc_uncompress_addr(struct sk_buff *skb, ...@@ -320,7 +337,7 @@ static int lowpan_iphc_uncompress_addr(struct sk_buff *skb,
lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
break; break;
default: default:
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr);
break; break;
} }
break; break;
...@@ -381,7 +398,7 @@ static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb, ...@@ -381,7 +398,7 @@ static int lowpan_iphc_uncompress_ctx_addr(struct sk_buff *skb,
lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr); lowpan_iphc_uncompress_802154_lladdr(ipaddr, lladdr);
break; break;
default: default:
lowpan_iphc_uncompress_eui64_lladdr(ipaddr, lladdr); lowpan_iphc_uncompress_lladdr(dev, ipaddr, lladdr);
break; break;
} }
ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen); ipv6_addr_prefix_copy(ipaddr, &ctx->pfx, ctx->plen);
...@@ -810,6 +827,21 @@ lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr, ...@@ -810,6 +827,21 @@ lowpan_iphc_compress_ctx_802154_lladdr(const struct in6_addr *ipaddr,
return lladdr_compress; return lladdr_compress;
} }
static bool lowpan_iphc_addr_equal(const struct net_device *dev,
const struct lowpan_iphc_ctx *ctx,
const struct in6_addr *ipaddr,
const void *lladdr)
{
struct in6_addr tmp = {};
lowpan_iphc_uncompress_lladdr(dev, &tmp, lladdr);
if (ctx)
ipv6_addr_prefix_copy(&tmp, &ctx->pfx, ctx->plen);
return ipv6_addr_equal(&tmp, ipaddr);
}
static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
const struct in6_addr *ipaddr, const struct in6_addr *ipaddr,
const struct lowpan_iphc_ctx *ctx, const struct lowpan_iphc_ctx *ctx,
...@@ -827,13 +859,7 @@ static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev, ...@@ -827,13 +859,7 @@ static u8 lowpan_compress_ctx_addr(u8 **hc_ptr, const struct net_device *dev,
} }
break; break;
default: default:
/* check for SAM/DAM = 11 */ if (lowpan_iphc_addr_equal(dev, ctx, ipaddr, lladdr)) {
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; dam = LOWPAN_IPHC_DAM_11;
goto out; goto out;
} }
...@@ -929,11 +955,12 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev, ...@@ -929,11 +955,12 @@ static u8 lowpan_compress_addr_64(u8 **hc_ptr, const struct net_device *dev,
} }
break; break;
default: default:
if (is_addr_mac_addr_based(ipaddr, lladdr)) { if (lowpan_iphc_addr_equal(dev, NULL, ipaddr, lladdr)) {
dam = LOWPAN_IPHC_DAM_11; /* 0-bits */ dam = LOWPAN_IPHC_DAM_11;
pr_debug("address compression 0 bits\n"); pr_debug("address compression 0 bits\n");
goto out; goto out;
} }
break; break;
} }
......
...@@ -64,7 +64,7 @@ struct lowpan_peer { ...@@ -64,7 +64,7 @@ struct lowpan_peer {
struct l2cap_chan *chan; struct l2cap_chan *chan;
/* peer addresses in various formats */ /* peer addresses in various formats */
unsigned char eui64_addr[EUI64_ADDR_LEN]; unsigned char lladdr[ETH_ALEN];
struct in6_addr peer_addr; struct in6_addr peer_addr;
}; };
...@@ -80,8 +80,6 @@ struct lowpan_btle_dev { ...@@ -80,8 +80,6 @@ struct lowpan_btle_dev {
struct delayed_work notify_peers; struct delayed_work notify_peers;
}; };
static void set_addr(u8 *eui, u8 *addr, u8 addr_type);
static inline struct lowpan_btle_dev * static inline struct lowpan_btle_dev *
lowpan_btle_dev(const struct net_device *netdev) lowpan_btle_dev(const struct net_device *netdev)
{ {
...@@ -277,7 +275,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev, ...@@ -277,7 +275,6 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
const u8 *saddr; const u8 *saddr;
struct lowpan_btle_dev *dev; struct lowpan_btle_dev *dev;
struct lowpan_peer *peer; struct lowpan_peer *peer;
unsigned char eui64_daddr[EUI64_ADDR_LEN];
dev = lowpan_btle_dev(netdev); dev = lowpan_btle_dev(netdev);
...@@ -287,10 +284,9 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev, ...@@ -287,10 +284,9 @@ static int iphc_decompress(struct sk_buff *skb, struct net_device *netdev,
if (!peer) if (!peer)
return -EINVAL; return -EINVAL;
saddr = peer->eui64_addr; saddr = peer->lladdr;
set_addr(&eui64_daddr[0], chan->src.b, chan->src_type);
return lowpan_header_decompress(skb, netdev, &eui64_daddr, saddr); return lowpan_header_decompress(skb, netdev, netdev->dev_addr, saddr);
} }
static int recv_pkt(struct sk_buff *skb, struct net_device *dev, static int recv_pkt(struct sk_buff *skb, struct net_device *dev,
...@@ -477,7 +473,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev, ...@@ -477,7 +473,7 @@ static int setup_header(struct sk_buff *skb, struct net_device *netdev,
} }
} }
daddr = peer->eui64_addr; daddr = peer->lladdr;
*peer_addr = addr; *peer_addr = addr;
*peer_addr_type = addr_type; *peer_addr_type = addr_type;
lowpan_cb(skb)->chan = peer->chan; lowpan_cb(skb)->chan = peer->chan;
...@@ -663,27 +659,6 @@ static struct device_type bt_type = { ...@@ -663,27 +659,6 @@ static struct device_type bt_type = {
.name = "bluetooth", .name = "bluetooth",
}; };
static void set_addr(u8 *eui, u8 *addr, u8 addr_type)
{
/* addr is the BT address in little-endian format */
eui[0] = addr[5];
eui[1] = addr[4];
eui[2] = addr[3];
eui[3] = 0xFF;
eui[4] = 0xFE;
eui[5] = addr[2];
eui[6] = addr[1];
eui[7] = addr[0];
/* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */
if (addr_type == BDADDR_LE_PUBLIC)
eui[0] &= ~0x02;
else
eui[0] |= 0x02;
BT_DBG("type %d addr %*phC", addr_type, 8, eui);
}
static void ifup(struct net_device *netdev) static void ifup(struct net_device *netdev)
{ {
int err; int err;
...@@ -762,14 +737,9 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan, ...@@ -762,14 +737,9 @@ static struct l2cap_chan *add_peer_chan(struct l2cap_chan *chan,
peer->chan = chan; peer->chan = chan;
memset(&peer->peer_addr, 0, sizeof(struct in6_addr)); memset(&peer->peer_addr, 0, sizeof(struct in6_addr));
/* RFC 2464 ch. 5 */ baswap((void *)peer->lladdr, &chan->dst);
peer->peer_addr.s6_addr[0] = 0xFE;
peer->peer_addr.s6_addr[1] = 0x80;
set_addr((u8 *)&peer->peer_addr.s6_addr + 8, chan->dst.b,
chan->dst_type);
memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, lowpan_iphc_uncompress_eui48_lladdr(&peer->peer_addr, peer->lladdr);
EUI64_ADDR_LEN);
/* IPv6 address needs to have the U/L bit set properly so toggle /* IPv6 address needs to have the U/L bit set properly so toggle
* it back here. * it back here.
......
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