Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
[pandora-kernel.git] / net / bluetooth / hci_core.c
index b18db56..ec0bc3f 100644 (file)
@@ -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)");