Bluetooth: Add definitions and track LE resolve list modification
authorAnkit Navik <ankit.p.navik@intel.com>
Fri, 17 Aug 2018 01:59:19 +0000 (07:29 +0530)
committerMarcel Holtmann <marcel@holtmann.org>
Thu, 27 Sep 2018 10:38:52 +0000 (12:38 +0200)
Add the definitions for adding entries to the LE resolve list and
removing entries from the LE resolve list. When the LE resolve list
gets changed via HCI commands make sure that the internal storage of
the resolve list entries gets updated.

Signed-off-by: Ankit Navik <ankit.p.navik@intel.com>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c

index cdd9f1fe7cfa903ea79f54ac0b17b1d946d81d92..c36dc1e20556aa2eb5924cc6978f4dee4757ac48 100644 (file)
@@ -1517,6 +1517,20 @@ struct hci_cp_le_write_def_data_len {
        __le16  tx_time;
 } __packed;
 
+#define HCI_OP_LE_ADD_TO_RESOLV_LIST   0x2027
+struct hci_cp_le_add_to_resolv_list {
+       __u8     bdaddr_type;
+       bdaddr_t bdaddr;
+       __u8     peer_irk[16];
+       __u8     local_irk[16];
+} __packed;
+
+#define HCI_OP_LE_DEL_FROM_RESOLV_LIST 0x2028
+struct hci_cp_le_del_from_resolv_list {
+       __u8     bdaddr_type;
+       bdaddr_t bdaddr;
+} __packed;
+
 #define HCI_OP_LE_CLEAR_RESOLV_LIST    0x2029
 
 #define HCI_OP_LE_READ_RESOLV_LIST_SIZE        0x202a
index 0db1b9b428b7d22b87ee50bed3491a672a6a76cb..9b0f821b2d3a2e8a413d23166faa59e21ab5956e 100644 (file)
@@ -103,6 +103,14 @@ struct bdaddr_list {
        u8 bdaddr_type;
 };
 
+struct bdaddr_list_with_irk {
+       struct list_head list;
+       bdaddr_t bdaddr;
+       u8 bdaddr_type;
+       u8 peer_irk[16];
+       u8 local_irk[16];
+};
+
 struct bt_uuid {
        struct list_head list;
        u8 uuid[16];
@@ -1058,8 +1066,15 @@ int hci_inquiry(void __user *arg);
 
 struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *list,
                                           bdaddr_t *bdaddr, u8 type);
+struct bdaddr_list_with_irk *hci_bdaddr_list_lookup_with_irk(
+                                   struct list_head *list, bdaddr_t *bdaddr,
+                                   u8 type);
 int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type);
+int hci_bdaddr_list_add_with_irk(struct list_head *list, bdaddr_t *bdaddr,
+                                       u8 type, u8 *peer_irk, u8 *local_irk);
 int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type);
+int hci_bdaddr_list_del_with_irk(struct list_head *list, bdaddr_t *bdaddr,
+                                                               u8 type);
 void hci_bdaddr_list_clear(struct list_head *list);
 
 struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
index 74b29c7d841c66192b8d697c845b24d2c2a5b820..0f1a8820d75c8a95dad3a71a3486a5e26b78a179 100644 (file)
@@ -2839,6 +2839,20 @@ struct bdaddr_list *hci_bdaddr_list_lookup(struct list_head *bdaddr_list,
        return NULL;
 }
 
+struct bdaddr_list_with_irk *hci_bdaddr_list_lookup_with_irk(
+                               struct list_head *bdaddr_list, bdaddr_t *bdaddr,
+                               u8 type)
+{
+       struct bdaddr_list_with_irk *b;
+
+       list_for_each_entry(b, bdaddr_list, list) {
+               if (!bacmp(&b->bdaddr, bdaddr) && b->bdaddr_type == type)
+                       return b;
+       }
+
+       return NULL;
+}
+
 void hci_bdaddr_list_clear(struct list_head *bdaddr_list)
 {
        struct bdaddr_list *b, *n;
@@ -2871,6 +2885,35 @@ int hci_bdaddr_list_add(struct list_head *list, bdaddr_t *bdaddr, u8 type)
        return 0;
 }
 
+int hci_bdaddr_list_add_with_irk(struct list_head *list, bdaddr_t *bdaddr,
+                                       u8 type, u8 *peer_irk, u8 *local_irk)
+{
+       struct bdaddr_list_with_irk *entry;
+
+       if (!bacmp(bdaddr, BDADDR_ANY))
+               return -EBADF;
+
+       if (hci_bdaddr_list_lookup(list, bdaddr, type))
+               return -EEXIST;
+
+       entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+       if (!entry)
+               return -ENOMEM;
+
+       bacpy(&entry->bdaddr, bdaddr);
+       entry->bdaddr_type = type;
+
+       if (peer_irk)
+               memcpy(entry->peer_irk, peer_irk, 16);
+
+       if (local_irk)
+               memcpy(entry->local_irk, local_irk, 16);
+
+       list_add(&entry->list, list);
+
+       return 0;
+}
+
 int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type)
 {
        struct bdaddr_list *entry;
@@ -2890,6 +2933,26 @@ int hci_bdaddr_list_del(struct list_head *list, bdaddr_t *bdaddr, u8 type)
        return 0;
 }
 
+int hci_bdaddr_list_del_with_irk(struct list_head *list, bdaddr_t *bdaddr,
+                                                       u8 type)
+{
+       struct bdaddr_list_with_irk *entry;
+
+       if (!bacmp(bdaddr, BDADDR_ANY)) {
+               hci_bdaddr_list_clear(list);
+               return 0;
+       }
+
+       entry = hci_bdaddr_list_lookup_with_irk(list, bdaddr, type);
+       if (!entry)
+               return -ENOENT;
+
+       list_del(&entry->list);
+       kfree(entry);
+
+       return 0;
+}
+
 /* This function requires the caller holds hdev->lock */
 struct hci_conn_params *hci_conn_params_lookup(struct hci_dev *hdev,
                                               bdaddr_t *addr, u8 addr_type)
index f12555f23a49a025563a6f11f174a0be71556a75..f47f8fad757ac97db775ad05fb3db3ce6285d336 100644 (file)
@@ -1454,6 +1454,45 @@ static void hci_cc_le_write_def_data_len(struct hci_dev *hdev,
        hdev->le_def_tx_time = le16_to_cpu(sent->tx_time);
 }
 
+static void hci_cc_le_add_to_resolv_list(struct hci_dev *hdev,
+                                        struct sk_buff *skb)
+{
+       struct hci_cp_le_add_to_resolv_list *sent;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_ADD_TO_RESOLV_LIST);
+       if (!sent)
+               return;
+
+       hci_bdaddr_list_add_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
+                               sent->bdaddr_type, sent->peer_irk,
+                               sent->local_irk);
+}
+
+static void hci_cc_le_del_from_resolv_list(struct hci_dev *hdev,
+                                         struct sk_buff *skb)
+{
+       struct hci_cp_le_del_from_resolv_list *sent;
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       if (status)
+               return;
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_DEL_FROM_RESOLV_LIST);
+       if (!sent)
+               return;
+
+       hci_bdaddr_list_del_with_irk(&hdev->le_resolv_list, &sent->bdaddr,
+                           sent->bdaddr_type);
+}
+
 static void hci_cc_le_clear_resolv_list(struct hci_dev *hdev,
                                       struct sk_buff *skb)
 {
@@ -3279,6 +3318,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb,
                hci_cc_le_write_def_data_len(hdev, skb);
                break;
 
+       case HCI_OP_LE_ADD_TO_RESOLV_LIST:
+               hci_cc_le_add_to_resolv_list(hdev, skb);
+               break;
+
+       case HCI_OP_LE_DEL_FROM_RESOLV_LIST:
+               hci_cc_le_del_from_resolv_list(hdev, skb);
+               break;
+
        case HCI_OP_LE_CLEAR_RESOLV_LIST:
                hci_cc_le_clear_resolv_list(hdev, skb);
                break;