diff options
| author | Jukka Rissanen <jukka.rissanen@linux.intel.com> | 2014-05-27 04:33:22 -0400 |
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2014-05-31 00:28:21 -0400 |
| commit | 62bbd5b35994eaf30519f126765d7f6af9cd3526 (patch) | |
| tree | a72047de0469280af9320c477367e3788b2dc4a3 /net | |
| parent | 7e3691e13ab51f3491e996e2edaf99b173621288 (diff) | |
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: Jukka Rissanen <jukka.rissanen@linux.intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
Cc: stable@vger.kernel.org
Diffstat (limited to 'net')
| -rw-r--r-- | net/bluetooth/6lowpan.c | 65 |
1 files changed, 35 insertions, 30 deletions
diff --git a/net/bluetooth/6lowpan.c b/net/bluetooth/6lowpan.c index adb3ea04adaa..d906016f3c6b 100644 --- a/net/bluetooth/6lowpan.c +++ b/net/bluetooth/6lowpan.c | |||
| @@ -420,12 +420,18 @@ static int conn_send(struct l2cap_conn *conn, | |||
| 420 | return 0; | 420 | return 0; |
| 421 | } | 421 | } |
| 422 | 422 | ||
| 423 | static void get_dest_bdaddr(struct in6_addr *ip6_daddr, | 423 | static u8 get_addr_type_from_eui64(u8 byte) |
| 424 | bdaddr_t *addr, u8 *addr_type) | ||
| 425 | { | 424 | { |
| 426 | u8 *eui64; | 425 | /* Is universal(0) or local(1) bit, */ |
| 426 | if (byte & 0x02) | ||
| 427 | return ADDR_LE_DEV_RANDOM; | ||
| 427 | 428 | ||
| 428 | eui64 = ip6_daddr->s6_addr + 8; | 429 | return ADDR_LE_DEV_PUBLIC; |
| 430 | } | ||
| 431 | |||
| 432 | static void copy_to_bdaddr(struct in6_addr *ip6_daddr, bdaddr_t *addr) | ||
| 433 | { | ||
| 434 | u8 *eui64 = ip6_daddr->s6_addr + 8; | ||
| 429 | 435 | ||
| 430 | addr->b[0] = eui64[7]; | 436 | addr->b[0] = eui64[7]; |
| 431 | addr->b[1] = eui64[6]; | 437 | addr->b[1] = eui64[6]; |
| @@ -433,16 +439,19 @@ static void get_dest_bdaddr(struct in6_addr *ip6_daddr, | |||
| 433 | addr->b[3] = eui64[2]; | 439 | addr->b[3] = eui64[2]; |
| 434 | addr->b[4] = eui64[1]; | 440 | addr->b[4] = eui64[1]; |
| 435 | addr->b[5] = eui64[0]; | 441 | addr->b[5] = eui64[0]; |
| 442 | } | ||
| 436 | 443 | ||
| 437 | addr->b[5] ^= 2; | 444 | static void convert_dest_bdaddr(struct in6_addr *ip6_daddr, |
| 445 | bdaddr_t *addr, u8 *addr_type) | ||
| 446 | { | ||
| 447 | copy_to_bdaddr(ip6_daddr, addr); | ||
| 438 | 448 | ||
| 439 | /* Set universal/local bit to 0 */ | 449 | /* We need to toggle the U/L bit that we got from IPv6 address |
| 440 | if (addr->b[5] & 1) { | 450 | * so that we get the proper address and type of the BD address. |
| 441 | addr->b[5] &= ~1; | 451 | */ |
| 442 | *addr_type = ADDR_LE_DEV_PUBLIC; | 452 | addr->b[5] ^= 0x02; |
| 443 | } else { | 453 | |
| 444 | *addr_type = ADDR_LE_DEV_RANDOM; | 454 | *addr_type = get_addr_type_from_eui64(addr->b[5]); |
| 445 | } | ||
| 446 | } | 455 | } |
| 447 | 456 | ||
| 448 | static int header_create(struct sk_buff *skb, struct net_device *netdev, | 457 | 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 | /* Get destination BT device from skb. | 482 | /* Get destination BT device from skb. |
| 474 | * If there is no such peer then discard the packet. | 483 | * If there is no such peer then discard the packet. |
| 475 | */ | 484 | */ |
| 476 | get_dest_bdaddr(&hdr->daddr, &addr, &addr_type); | 485 | convert_dest_bdaddr(&hdr->daddr, &addr, &addr_type); |
| 477 | 486 | ||
| 478 | BT_DBG("dest addr %pMR type %d", &addr, addr_type); | 487 | BT_DBG("dest addr %pMR type %s IP %pI6c", &addr, |
| 488 | addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", | ||
| 489 | &hdr->daddr); | ||
| 479 | 490 | ||
| 480 | read_lock_irqsave(&devices_lock, flags); | 491 | read_lock_irqsave(&devices_lock, flags); |
| 481 | peer = peer_lookup_ba(dev, &addr, addr_type); | 492 | 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 | } else { | 567 | } else { |
| 557 | unsigned long flags; | 568 | unsigned long flags; |
| 558 | 569 | ||
| 559 | get_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); | 570 | convert_dest_bdaddr(&lowpan_cb(skb)->addr, &addr, &addr_type); |
| 560 | eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; | 571 | eui64_addr = lowpan_cb(skb)->addr.s6_addr + 8; |
| 561 | dev = lowpan_dev(netdev); | 572 | dev = lowpan_dev(netdev); |
| 562 | 573 | ||
| @@ -564,8 +575,10 @@ static netdev_tx_t bt_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
| 564 | peer = peer_lookup_ba(dev, &addr, addr_type); | 575 | peer = peer_lookup_ba(dev, &addr, addr_type); |
| 565 | read_unlock_irqrestore(&devices_lock, flags); | 576 | read_unlock_irqrestore(&devices_lock, flags); |
| 566 | 577 | ||
| 567 | BT_DBG("xmit from %s to %pMR (%pI6c) peer %p", netdev->name, | 578 | BT_DBG("xmit %s to %pMR type %s IP %pI6c peer %p", |
| 568 | &addr, &lowpan_cb(skb)->addr, peer); | 579 | netdev->name, &addr, |
| 580 | addr_type == ADDR_LE_DEV_PUBLIC ? "PUBLIC" : "RANDOM", | ||
| 581 | &lowpan_cb(skb)->addr, peer); | ||
| 569 | 582 | ||
| 570 | if (peer && peer->conn) | 583 | if (peer && peer->conn) |
| 571 | err = send_pkt(peer->conn, netdev->dev_addr, | 584 | err = send_pkt(peer->conn, netdev->dev_addr, |
| @@ -620,13 +633,13 @@ static void set_addr(u8 *eui, u8 *addr, u8 addr_type) | |||
| 620 | eui[6] = addr[1]; | 633 | eui[6] = addr[1]; |
| 621 | eui[7] = addr[0]; | 634 | eui[7] = addr[0]; |
| 622 | 635 | ||
| 623 | eui[0] ^= 2; | 636 | /* Universal/local bit set, BT 6lowpan draft ch. 3.2.1 */ |
| 624 | |||
| 625 | /* Universal/local bit set, RFC 4291 */ | ||
| 626 | if (addr_type == ADDR_LE_DEV_PUBLIC) | 637 | if (addr_type == ADDR_LE_DEV_PUBLIC) |
| 627 | eui[0] |= 1; | 638 | eui[0] &= ~0x02; |
| 628 | else | 639 | else |
| 629 | eui[0] &= ~1; | 640 | eui[0] |= 0x02; |
| 641 | |||
| 642 | BT_DBG("type %d addr %*phC", addr_type, 8, eui); | ||
| 630 | } | 643 | } |
| 631 | 644 | ||
| 632 | static void set_dev_addr(struct net_device *netdev, bdaddr_t *addr, | 645 | 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 | { | 647 | { |
| 635 | netdev->addr_assign_type = NET_ADDR_PERM; | 648 | netdev->addr_assign_type = NET_ADDR_PERM; |
| 636 | set_addr(netdev->dev_addr, addr->b, addr_type); | 649 | set_addr(netdev->dev_addr, addr->b, addr_type); |
| 637 | netdev->dev_addr[0] ^= 2; | ||
| 638 | } | 650 | } |
| 639 | 651 | ||
| 640 | static void ifup(struct net_device *netdev) | 652 | 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 | 696 | ||
| 685 | memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, | 697 | memcpy(&peer->eui64_addr, (u8 *)&peer->peer_addr.s6_addr + 8, |
| 686 | EUI64_ADDR_LEN); | 698 | EUI64_ADDR_LEN); |
| 687 | peer->eui64_addr[0] ^= 2; /* second bit-flip (Universe/Local) | ||
| 688 | * is done according RFC2464 | ||
| 689 | */ | ||
| 690 | |||
| 691 | raw_dump_inline(__func__, "peer IPv6 address", | ||
| 692 | (unsigned char *)&peer->peer_addr, 16); | ||
| 693 | raw_dump_inline(__func__, "peer EUI64 address", peer->eui64_addr, 8); | ||
| 694 | 699 | ||
| 695 | write_lock_irqsave(&devices_lock, flags); | 700 | write_lock_irqsave(&devices_lock, flags); |
| 696 | INIT_LIST_HEAD(&peer->list); | 701 | INIT_LIST_HEAD(&peer->list); |
