mirror of
https://github.com/rd-stuffs/msm-4.14.git
synced 2025-02-20 11:45:48 +08:00
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: Luiz Augusto von Dentz <luiz.von.dentz@intel.com> Reviewed-by: Stefan Schmidt <stefan@osg.samsung.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
8a7a4b4767
commit
fa09ae661f
@ -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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
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,
|
|||||||
}
|
}
|
||||||
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 {
|
|||||||
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 {
|
|||||||
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,
|
|||||||
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,
|
|||||||
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,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 = {
|
|||||||
.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,
|
|||||||
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.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user