diff options
Diffstat (limited to 'net/bluetooth')
-rw-r--r-- | net/bluetooth/hci_core.c | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index 7ba1ca12c1d..4885914449f 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -1057,6 +1057,42 @@ static int hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn, return 0; } +struct link_key *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, u8 rand[8]) +{ + struct link_key *k; + + list_for_each_entry(k, &hdev->link_keys, list) { + struct key_master_id *id; + + if (k->type != HCI_LK_SMP_LTK) + continue; + + if (k->dlen != sizeof(*id)) + continue; + + id = (void *) &k->data; + if (id->ediv == ediv && + (memcmp(rand, id->rand, sizeof(id->rand)) == 0)) + return k; + } + + return NULL; +} +EXPORT_SYMBOL(hci_find_ltk); + +struct link_key *hci_find_link_key_type(struct hci_dev *hdev, + bdaddr_t *bdaddr, u8 type) +{ + struct link_key *k; + + list_for_each_entry(k, &hdev->link_keys, list) + if (k->type == type && bacmp(bdaddr, &k->bdaddr) == 0) + return k; + + return NULL; +} +EXPORT_SYMBOL(hci_find_link_key_type); + int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, bdaddr_t *bdaddr, u8 *val, u8 type, u8 pin_len) { @@ -1112,6 +1148,43 @@ int hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn, int new_key, return 0; } +int hci_add_ltk(struct hci_dev *hdev, int new_key, bdaddr_t *bdaddr, + __le16 ediv, u8 rand[8], u8 ltk[16]) +{ + struct link_key *key, *old_key; + struct key_master_id *id; + u8 old_key_type; + + BT_DBG("%s addr %s", hdev->name, batostr(bdaddr)); + + old_key = hci_find_link_key_type(hdev, bdaddr, HCI_LK_SMP_LTK); + if (old_key) { + key = old_key; + old_key_type = old_key->type; + } else { + key = kzalloc(sizeof(*key) + sizeof(*id), GFP_ATOMIC); + if (!key) + return -ENOMEM; + list_add(&key->list, &hdev->link_keys); + old_key_type = 0xff; + } + + key->dlen = sizeof(*id); + + bacpy(&key->bdaddr, bdaddr); + memcpy(key->val, ltk, sizeof(key->val)); + key->type = HCI_LK_SMP_LTK; + + id = (void *) &key->data; + id->ediv = ediv; + memcpy(id->rand, rand, sizeof(id->rand)); + + if (new_key) + mgmt_new_key(hdev->id, key, old_key_type); + + return 0; +} + int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr) { struct link_key *key; |