提交 62bbd5b3 编写于 作者: J Jukka Rissanen 提交者: Marcel Holtmann

Bluetooth: 6LoWPAN: Fix MAC address universal/local bit handling

The universal/local bit handling was incorrectly done in the code.

So when setting EUI address from BD address we do this:
- If BD address type is PUBLIC, then we clear the universal bit
  in EUI address. If the address type is RANDOM, then the universal
  bit is set (BT 6lowpan draft chapter 3.2.2)
- After this we invert the universal/local bit according to RFC 2464

When figuring out BD address we do the reverse:
- Take EUI address from stateless IPv6 address, invert the
  universal/local bit according to RFC 2464
- If universal bit is 1 in this modified EUI address, then address
  type is set to RANDOM, otherwise it is PUBLIC

Note that 6lowpan_iphc.[ch] does the final toggling of U/L bit
before sending or receiving the network packet.
Signed-off-by: NJukka Rissanen <jukka.rissanen@linux.intel.com>
Signed-off-by: NMarcel Holtmann <marcel@holtmann.org>
Cc: stable@vger.kernel.org
上级 7e3691e1
...@@ -420,12 +420,18 @@ static int conn_send(struct l2cap_conn *conn, ...@@ -420,12 +420,18 @@ static int conn_send(struct l2cap_conn *conn,
return 0; return 0;
} }
static void get_dest_bdaddr(struct in6_addr *ip6_daddr, static u8 get_addr_type_from_eui64(u8 byte)
bdaddr_t *addr, u8 *addr_type)
{ {
u8 *eui64; /* Is universal(0) or local(1) bit, */
if (byte & 0x02)
return ADDR_LE_DEV_RANDOM;
eui64 = ip6_daddr->s6_addr + 8; return ADDR_LE_DEV_PUBLIC;
}
static void copy_to_bdaddr(struct in6_addr *ip6_daddr, bdaddr_t *addr)
{
u8 *eui64 = ip6_daddr->s6_addr + 8;
addr->b[0] = eui64[7]; addr->b[0] = eui64[7];
addr->b[1] = eui64[6]; addr->b[1] = eui64[6];
...@@ -433,16 +439,19 @@ static void get_dest_bdaddr(struct in6_addr *ip6_daddr, ...@@ -433,16 +439,19 @@ static void get_dest_bdaddr(struct in6_addr *ip6_daddr,
addr->b[3] = eui64[2]; addr->b[3] = eui64[2];
addr->b[4] = eui64[1]; addr->b[4] = eui64[1];
addr->b[5] = eui64[0]; addr->b[5] = eui64[0];
}
addr->b[5] ^= 2; static void convert_dest_bdaddr(struct in6_addr *ip6_daddr,
bdaddr_t *addr, u8 *addr_type)
{
copy_to_bdaddr(ip6_daddr, addr);
/* Set universal/local bit to 0 */ /* We need to toggle the U/L bit that we got from IPv6 address
if (addr->b[5] & 1) { * so that we get the proper address and type of the BD address.
addr->b[5] &= ~1; */
*addr_type = ADDR_LE_DEV_PUBLIC; addr->b[5] ^= 0x02;
} else {
*addr_type = ADDR_LE_DEV_RANDOM; *addr_type = get_addr_type_from_eui64(addr->b[5]);
}
} }
static int header_create(struct sk_buff *skb, struct net_device *netdev, static int header_create(struct sk_buff *skb, struct net_device *netdev,
...@@ -473,9 +482,11 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev, ...@@ -473,9 +482,11 @@ static int header_create(struct sk_buff *skb, struct net_device *netdev,
/* Get destination BT device from skb. /* Get destination BT device from skb.
* If there is no such peer then discard the packet. * If there is no such peer then discard the packet.
*/ */
get_dest_bdaddr(&hdr->daddr, &addr, &addr_type); convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type);
BT_DBG("dest addr %pMR type %d", &addr, addr_type); BT_DBG("dest addr %pMR type %s IP %pI6c", &addr,
addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM",
&hdr->daddr);
read_lock_irqsave(&devices_lock, flags); read_lock_irqsave(&devices_lock, flags);
peer = peer_lookup_ba(dev, &addr, addr_type); peer = peer_lookup_ba(dev, &addr, addr_type);
...@@ -556,7 +567,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -556,7 +567,7 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
} else { } else {
unsigned long flags; unsigned long flags;
get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type);
eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8;
dev = lowpan_dev(netdev); dev = lowpan_dev(netdev);
...@@ -564,8 +575,10 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) ...@@ -564,8 +575,10 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev)
peer = peer_lookup_ba(dev, &addr, addr_type); peer = peer_lookup_ba(dev, &addr, addr_type);
read_unlock_irqrestore(&devices_lock, flags); read_unlock_irqrestore(&devices_lock, flags);
BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name, BT_DBG("xmit %s to %pMR type %s IP %pI6c peer %p",
&addr, &lowpan_cb(skb)->addr, peer); netdev->name, &addr,
addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM",
&lowpan_cb(skb)->addr, peer);
if (peer && peer->conn) if (peer && peer->conn)
err = send_pkt(peer->conn, netdev->dev_addr, err = send_pkt(peer->conn, netdev->dev_addr,
...@@ -620,13 +633,13 @@ static void set_addr(u8 *eui, u8 *addr, u8 addr_type) ...@@ -620,13 +633,13 @@ static void set_addr(u8 *eui, u8 *addr, u8 addr_type)
eui[6] = addr[1]; eui[6] = addr[1];
eui[7] = addr[0]; eui[7] = addr[0];
eui[0] ^= 2; /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */
/* Universal/local bit set, RFC 4291 */
if (addr_type == ADDR_LE_DEV_PUBLIC) if (addr_type == ADDR_LE_DEV_PUBLIC)
eui[0] |= 1; eui[0] &= ~0x02;
else else
eui[0] &= ~1; eui[0] |= 0x02;
BT_DBG("type %d addr %*phC", addr_type, 8, eui);
} }
static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr, static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr,
...@@ -634,7 +647,6 @@ static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr, ...@@ -634,7 +647,6 @@ static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr,
{ {
netdev->addr_assign_type = NET_ADDR_PERM; netdev->addr_assign_type = NET_ADDR_PERM;
set_addr(netdev->dev_addr, addr->b, addr_type); set_addr(netdev->dev_addr, addr->b, addr_type);
netdev->dev_addr[0] ^= 2;
} }
static void ifup(struct net_device *netdev) static void ifup(struct net_device *netdev)
...@@ -684,13 +696,6 @@ static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev) ...@@ -684,13 +696,6 @@ static int add_peer_conn(struct l2cap_conn *conn, struct lowpan_dev *dev)
memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8,
EUI64_ADDR_LEN); EUI64_ADDR_LEN);
peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local)
* is done according RFC2464
*/
raw_dump_inline(__func__, "peer IPv6 address",
(unsigned char *)&peer->peer_addr, 16);
raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8);
write_lock_irqsave(&devices_lock, flags); write_lock_irqsave(&devices_lock, flags);
INIT_LIST_HEAD(&peer->list); INIT_LIST_HEAD(&peer->list);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册