Bluetooth: Track LE initiator and responder address information
authorJohan Hedberg <johan.hedberg@intel.com>
Fri, 28 Feb 2014 10:54:16 +0000 (12:54 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Fri, 28 Feb 2014 15:53:07 +0000 (07:53 -0800)
For SMP we need the local and remote addresses (and their types) that
were used to establish the connection. These may be different from the
Identity Addresses or even the current RPA. To guarantee that we have
this information available and it is correct track these values
separately from the very beginning of the connection.

For outgoing connections we set the values as soon as we get a
successful command status for HCI_LE_Create_Connection (for which the
patch adds a command status handler function) and for incoming
connections as soon as we get a LE Connection Complete HCI event.

Signed-off-by: Johan Hedberg <johan.hedberg@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci_core.h
net/bluetooth/hci_event.c

index 0c63a7e..edf1946 100644 (file)
@@ -332,6 +332,10 @@ struct hci_conn {
        __u8            dst_type;
        bdaddr_t        src;
        __u8            src_type;
+       bdaddr_t        init_addr;
+       __u8            init_addr_type;
+       bdaddr_t        resp_addr;
+       __u8            resp_addr_type;
        __u16           handle;
        __u16           state;
        __u8            mode;
index e3d7151..3ae8ae1 100644 (file)
@@ -1641,6 +1641,47 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
        amp_write_remote_assoc(hdev, cp->phy_handle);
 }
 
+static void hci_cs_le_create_conn(struct hci_dev *hdev, u8 status)
+{
+       struct hci_cp_le_create_conn *cp;
+       struct hci_conn *conn;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       /* All connection failure handling is taken care of by the
+        * hci_le_conn_failed function which is triggered by the HCI
+        * request completion callbacks used for connecting.
+        */
+       if (status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_LE_CREATE_CONN);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, LE_LINK, &cp->peer_addr);
+       if (!conn)
+               goto unlock;
+
+       /* Store the initiator and responder address information which
+        * is needed for SMP. These values will not change during the
+        * lifetime of the connection.
+        */
+       conn->init_addr_type = cp->own_address_type;
+       if (cp->own_address_type == ADDR_LE_DEV_RANDOM)
+               bacpy(&conn->init_addr, &hdev->random_addr);
+       else
+               bacpy(&conn->init_addr, &hdev->bdaddr);
+
+       conn->resp_addr_type = cp->peer_addr_type;
+       bacpy(&conn->resp_addr, &cp->peer_addr);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -2532,6 +2573,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_accept_phylink(hdev, ev->status);
                break;
 
+       case HCI_OP_LE_CREATE_CONN:
+               hci_cs_le_create_conn(hdev, ev->status);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -3716,6 +3761,39 @@ static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                        conn->out = true;
                        conn->link_mode |= HCI_LM_MASTER;
                }
+
+               /* If we didn't have a hci_conn object previously
+                * but we're in master role this must be something
+                * initiated using a white list. Since white list based
+                * connections are not "first class citizens" we don't
+                * have full tracking of them. Therefore, we go ahead
+                * with a "best effort" approach of determining the
+                * initiator address based on the HCI_PRIVACY flag.
+                */
+               if (conn->out) {
+                       conn->resp_addr_type = ev->bdaddr_type;
+                       bacpy(&conn->resp_addr, &ev->bdaddr);
+                       if (test_bit(HCI_PRIVACY, &hdev->dev_flags)) {
+                               conn->init_addr_type = ADDR_LE_DEV_RANDOM;
+                               bacpy(&conn->init_addr, &hdev->rpa);
+                       } else {
+                               hci_copy_identity_address(hdev,
+                                                         &conn->init_addr,
+                                                         &conn->init_addr_type);
+                       }
+               } else {
+                       /* Set the responder (our side) address type based on
+                        * the advertising address type.
+                        */
+                       conn->resp_addr_type = hdev->adv_addr_type;
+                       if (hdev->adv_addr_type == ADDR_LE_DEV_RANDOM)
+                               bacpy(&conn->resp_addr, &hdev->random_addr);
+                       else
+                               bacpy(&conn->resp_addr, &hdev->bdaddr);
+
+                       conn->init_addr_type = ev->bdaddr_type;
+                       bacpy(&conn->init_addr, &ev->bdaddr);
+               }
        }
 
        /* Ensure that the hci_conn contains the identity address type