Bluetooth: Add 'Already Paired' error for Pair Device command
authorJohan Hedberg <johan.hedberg@intel.com>
Tue, 10 Mar 2015 20:34:40 +0000 (22:34 +0200)
committerMarcel Holtmann <marcel@holtmann.org>
Tue, 10 Mar 2015 20:42:05 +0000 (21:42 +0100)
To make the behavior predictable when attempting to pair with a device
for which we already have a Link Key or Long Term Key, this patch adds a
new 'Already Paired' error which gets sent in such a scenario.

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

index afc641c..5cc5a19 100644 (file)
@@ -967,6 +967,8 @@ struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
 void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type);
 void hci_smp_irks_clear(struct hci_dev *hdev);
 
+bool hci_bdaddr_is_paired(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type);
+
 void hci_remote_oob_data_clear(struct hci_dev *hdev);
 struct oob_data *hci_find_remote_oob_data(struct hci_dev *hdev,
                                          bdaddr_t *bdaddr, u8 bdaddr_type);
index 0c737e4..5bf6af9 100644 (file)
@@ -43,6 +43,7 @@
 #define MGMT_STATUS_CANCELLED          0x10
 #define MGMT_STATUS_INVALID_INDEX      0x11
 #define MGMT_STATUS_RFKILLED           0x12
+#define MGMT_STATUS_ALREADY_PAIRED     0x13
 
 struct mgmt_hdr {
        __le16  opcode;
index bba4c34..a35d844 100644 (file)
@@ -2516,6 +2516,33 @@ void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type)
        }
 }
 
+bool hci_bdaddr_is_paired(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
+{
+       struct smp_ltk *k;
+       u8 addr_type;
+
+       if (type == BDADDR_BREDR) {
+               if (hci_find_link_key(hdev, bdaddr))
+                       return true;
+               return false;
+       }
+
+       /* Convert to HCI addr type which struct smp_ltk uses */
+       if (type == BDADDR_LE_PUBLIC)
+               addr_type = ADDR_LE_DEV_PUBLIC;
+       else
+               addr_type = ADDR_LE_DEV_RANDOM;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
+               if (k->bdaddr_type == addr_type && !bacmp(bdaddr, &k->bdaddr))
+                       return true;
+       }
+       rcu_read_unlock();
+
+       return false;
+}
+
 /* HCI command timer function */
 static void hci_cmd_timeout(struct work_struct *work)
 {
index 49b8e09..600636c 100644 (file)
@@ -3245,6 +3245,13 @@ static int pair_device(struct sock *sk, struct hci_dev *hdev, void *data,
                goto unlock;
        }
 
+       if (hci_bdaddr_is_paired(hdev, &cp->addr.bdaddr, cp->addr.type)) {
+               err = mgmt_cmd_complete(sk, hdev->id, MGMT_OP_PAIR_DEVICE,
+                                       MGMT_STATUS_ALREADY_PAIRED, &rp,
+                                       sizeof(rp));
+               goto unlock;
+       }
+
        sec_level = BT_SECURITY_MEDIUM;
        auth_type = HCI_AT_DEDICATED_BONDING;