X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=net%2Fbluetooth%2Fhci_core.c;h=ec0bc3f60f2eea4216471746fdbea09c51b3fbcb;hb=25009a1ae1171eda6bff44b7e44eb0e076713811;hp=b18db5628275f93bc27b213cc1b4dbcc5ba0526c;hpb=df2cbe40753dc36af294c30209ed909869aca6cf;p=~andy%2Flinux diff --git a/net/bluetooth/hci_core.c b/net/bluetooth/hci_core.c index b18db562827..ec0bc3f60f2 100644 --- a/net/bluetooth/hci_core.c +++ b/net/bluetooth/hci_core.c @@ -60,8 +60,6 @@ static void hci_tx_task(unsigned long arg); static DEFINE_RWLOCK(hci_task_lock); -static int enable_smp; - /* HCI device list */ LIST_HEAD(hci_dev_list); DEFINE_RWLOCK(hci_dev_list_lock); @@ -148,7 +146,7 @@ static int __hci_request(struct hci_dev *hdev, void (*req)(struct hci_dev *hdev, switch (hdev->req_status) { case HCI_REQ_DONE: - err = -bt_err(hdev->req_result); + err = -bt_to_errno(hdev->req_result); break; case HCI_REQ_CANCELED: @@ -542,7 +540,7 @@ int hci_dev_open(__u16 dev) ret = __hci_request(hdev, hci_init_req, 0, msecs_to_jiffies(HCI_INIT_TIMEOUT)); - if (lmp_le_capable(hdev)) + if (lmp_host_le_capable(hdev)) ret = __hci_request(hdev, hci_le_init_req, 0, msecs_to_jiffies(HCI_INIT_TIMEOUT)); @@ -1059,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) { @@ -1114,6 +1148,44 @@ 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, + u8 key_size, __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; + key->pin_len = key_size; + + 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; @@ -1246,7 +1318,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) if (bacmp(bdaddr, BDADDR_ANY) == 0) return -EBADF; - hci_dev_lock(hdev); + hci_dev_lock_bh(hdev); if (hci_blacklist_lookup(hdev, bdaddr)) { err = -EEXIST; @@ -1266,7 +1338,7 @@ int hci_blacklist_add(struct hci_dev *hdev, bdaddr_t *bdaddr) err = 0; err: - hci_dev_unlock(hdev); + hci_dev_unlock_bh(hdev); return err; } @@ -1275,7 +1347,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) struct bdaddr_list *entry; int err = 0; - hci_dev_lock(hdev); + hci_dev_lock_bh(hdev); if (bacmp(bdaddr, BDADDR_ANY) == 0) { hci_blacklist_clear(hdev); @@ -1292,7 +1364,7 @@ int hci_blacklist_del(struct hci_dev *hdev, bdaddr_t *bdaddr) kfree(entry); done: - hci_dev_unlock(hdev); + hci_dev_unlock_bh(hdev); return err; } @@ -1368,14 +1440,6 @@ int hci_add_adv_entry(struct hci_dev *hdev, return 0; } -static struct crypto_blkcipher *alloc_cypher(void) -{ - if (enable_smp) - return crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); - - return ERR_PTR(-ENOTSUPP); -} - /* Register HCI device */ int hci_register_dev(struct hci_dev *hdev) { @@ -1460,7 +1524,7 @@ int hci_register_dev(struct hci_dev *hdev) if (!hdev->workqueue) goto nomem; - hdev->tfm = alloc_cypher(); + hdev->tfm = crypto_alloc_blkcipher("ecb(aes)", 0, CRYPTO_ALG_ASYNC); if (IS_ERR(hdev->tfm)) BT_INFO("Failed to load transform for ecb(aes): %ld", PTR_ERR(hdev->tfm)); @@ -2352,6 +2416,3 @@ static void hci_cmd_task(unsigned long arg) } } } - -module_param(enable_smp, bool, 0644); -MODULE_PARM_DESC(enable_smp, "Enable SMP support (LE only)");