Bluetooth: Unify remote OOB data functions
[cascardo/linux.git] / net / bluetooth / hci_core.c
index c9495fb..967fbfe 100644 (file)
@@ -274,15 +274,13 @@ static const struct file_operations inquiry_cache_fops = {
 static int link_keys_show(struct seq_file *f, void *ptr)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *p, *n;
+       struct link_key *key;
 
-       hci_dev_lock(hdev);
-       list_for_each_safe(p, n, &hdev->link_keys) {
-               struct link_key *key = list_entry(p, struct link_key, list);
+       rcu_read_lock();
+       list_for_each_entry_rcu(key, &hdev->link_keys, list)
                seq_printf(f, "%pMR %u %*phN %u\n", &key->bdaddr, key->type,
                           HCI_LINK_KEY_SIZE, key->val, key->pin_len);
-       }
-       hci_dev_unlock(hdev);
+       rcu_read_unlock();
 
        return 0;
 }
@@ -408,6 +406,49 @@ static const struct file_operations force_sc_support_fops = {
        .llseek         = default_llseek,
 };
 
+static ssize_t force_lesc_support_read(struct file *file, char __user *user_buf,
+                                      size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[3];
+
+       buf[0] = test_bit(HCI_FORCE_LESC, &hdev->dbg_flags) ? 'Y': 'N';
+       buf[1] = '\n';
+       buf[2] = '\0';
+       return simple_read_from_buffer(user_buf, count, ppos, buf, 2);
+}
+
+static ssize_t force_lesc_support_write(struct file *file,
+                                       const char __user *user_buf,
+                                       size_t count, loff_t *ppos)
+{
+       struct hci_dev *hdev = file->private_data;
+       char buf[32];
+       size_t buf_size = min(count, (sizeof(buf)-1));
+       bool enable;
+
+       if (copy_from_user(buf, user_buf, buf_size))
+               return -EFAULT;
+
+       buf[buf_size] = '\0';
+       if (strtobool(buf, &enable))
+               return -EINVAL;
+
+       if (enable == test_bit(HCI_FORCE_LESC, &hdev->dbg_flags))
+               return -EALREADY;
+
+       change_bit(HCI_FORCE_LESC, &hdev->dbg_flags);
+
+       return count;
+}
+
+static const struct file_operations force_lesc_support_fops = {
+       .open           = simple_open,
+       .read           = force_lesc_support_read,
+       .write          = force_lesc_support_write,
+       .llseek         = default_llseek,
+};
+
 static ssize_t sc_only_mode_read(struct file *file, char __user *user_buf,
                                 size_t count, loff_t *ppos)
 {
@@ -748,16 +789,15 @@ static const struct file_operations white_list_fops = {
 static int identity_resolving_keys_show(struct seq_file *f, void *ptr)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *p, *n;
+       struct smp_irk *irk;
 
-       hci_dev_lock(hdev);
-       list_for_each_safe(p, n, &hdev->identity_resolving_keys) {
-               struct smp_irk *irk = list_entry(p, struct smp_irk, list);
+       rcu_read_lock();
+       list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
                seq_printf(f, "%pMR (type %u) %*phN %pMR\n",
                           &irk->bdaddr, irk->addr_type,
                           16, irk->val, &irk->rpa);
        }
-       hci_dev_unlock(hdev);
+       rcu_read_unlock();
 
        return 0;
 }
@@ -1129,6 +1169,7 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
        err = hci_req_run(&req, hci_req_sync_complete);
        if (err < 0) {
                remove_wait_queue(&hdev->req_wait_q, &wait);
+               set_current_state(TASK_RUNNING);
                return ERR_PTR(err);
        }
 
@@ -1197,6 +1238,7 @@ static int __hci_req_sync(struct hci_dev *hdev,
                hdev->req_status = 0;
 
                remove_wait_queue(&hdev->req_wait_q, &wait);
+               set_current_state(TASK_RUNNING);
 
                /* ENODATA means the HCI request command queue is empty.
                 * This can happen when a request with conditionals doesn't
@@ -1735,9 +1777,7 @@ static void hci_init4_req(struct hci_request *req, unsigned long opt)
                hci_req_add(req, HCI_OP_READ_SYNC_TRAIN_PARAMS, 0, NULL);
 
        /* Enable Secure Connections if supported and configured */
-       if ((lmp_sc_capable(hdev) ||
-            test_bit(HCI_FORCE_SC, &hdev->dbg_flags)) &&
-           test_bit(HCI_SC_ENABLED, &hdev->dev_flags)) {
+       if (bredr_sc_enabled(hdev)) {
                u8 support = 0x01;
                hci_req_add(req, HCI_OP_WRITE_SC_SUPPORT,
                            sizeof(support), &support);
@@ -1820,6 +1860,10 @@ static int __hci_init(struct hci_dev *hdev)
                                    hdev, &force_sc_support_fops);
                debugfs_create_file("sc_only_mode", 0444, hdev->debugfs,
                                    hdev, &sc_only_mode_fops);
+               if (lmp_le_capable(hdev))
+                       debugfs_create_file("force_lesc_support", 0644,
+                                           hdev->debugfs, hdev,
+                                           &force_lesc_support_fops);
        }
 
        if (lmp_sniff_capable(hdev)) {
@@ -2562,6 +2606,11 @@ static int hci_dev_do_close(struct hci_dev *hdev)
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
                cancel_delayed_work_sync(&hdev->rpa_expired);
 
+       /* Avoid potential lockdep warnings from the *_flush() calls by
+        * ensuring the workqueue is empty up front.
+        */
+       drain_workqueue(hdev->workqueue);
+
        hci_dev_lock(hdev);
        hci_inquiry_cache_flush(hdev);
        hci_pend_le_actions_clear(hdev);
@@ -2685,6 +2734,11 @@ int hci_dev_reset(__u16 dev)
        skb_queue_purge(&hdev->rx_q);
        skb_queue_purge(&hdev->cmd_q);
 
+       /* Avoid potential lockdep warnings from the *_flush() calls by
+        * ensuring the workqueue is empty up front.
+        */
+       drain_workqueue(hdev->workqueue);
+
        hci_dev_lock(hdev);
        hci_inquiry_cache_flush(hdev);
        hci_conn_hash_flush(hdev);
@@ -3090,15 +3144,11 @@ void hci_uuids_clear(struct hci_dev *hdev)
 
 void hci_link_keys_clear(struct hci_dev *hdev)
 {
-       struct list_head *p, *n;
-
-       list_for_each_safe(p, n, &hdev->link_keys) {
-               struct link_key *key;
-
-               key = list_entry(p, struct link_key, list);
+       struct link_key *key;
 
-               list_del(p);
-               kfree(key);
+       list_for_each_entry_rcu(key, &hdev->link_keys, list) {
+               list_del_rcu(&key->list);
+               kfree_rcu(key, rcu);
        }
 }
 
@@ -3114,11 +3164,11 @@ void hci_smp_ltks_clear(struct hci_dev *hdev)
 
 void hci_smp_irks_clear(struct hci_dev *hdev)
 {
-       struct smp_irk *k, *tmp;
+       struct smp_irk *k;
 
-       list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) {
-               list_del(&k->list);
-               kfree(k);
+       list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) {
+               list_del_rcu(&k->list);
+               kfree_rcu(k, rcu);
        }
 }
 
@@ -3126,9 +3176,14 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct link_key *k;
 
-       list_for_each_entry(k, &hdev->link_keys, list)
-               if (bacmp(bdaddr, &k->bdaddr) == 0)
+       rcu_read_lock();
+       list_for_each_entry_rcu(k, &hdev->link_keys, list) {
+               if (bacmp(bdaddr, &k->bdaddr) == 0) {
+                       rcu_read_unlock();
                        return k;
+               }
+       }
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -3152,6 +3207,10 @@ static bool hci_persistent_key(struct hci_dev *hdev, struct hci_conn *conn,
        if (!conn)
                return true;
 
+       /* BR/EDR key derived using SC from an LE link */
+       if (conn->type == LE_LINK)
+               return true;
+
        /* Neither local nor remote side had no-bonding as requirement */
        if (conn->auth_type > 0x01 && conn->remote_auth > 0x01)
                return true;
@@ -3177,37 +3236,25 @@ static u8 ltk_role(u8 type)
        return HCI_ROLE_SLAVE;
 }
 
-struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
-                            u8 role)
+struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
+                            u8 addr_type, u8 role)
 {
        struct smp_ltk *k;
 
        rcu_read_lock();
        list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
-               if (k->ediv != ediv || k->rand != rand)
+               if (addr_type != k->bdaddr_type || bacmp(bdaddr, &k->bdaddr))
                        continue;
 
-               if (ltk_role(k->type) != role)
-                       continue;
-
-               rcu_read_unlock();
-               return k;
-       }
-       rcu_read_unlock();
-
-       return NULL;
-}
-
-struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                                    u8 addr_type, u8 role)
-{
-       struct smp_ltk *k;
+               if (smp_ltk_is_sc(k)) {
+                       if (k->type == SMP_LTK_P256_DEBUG &&
+                           !test_bit(HCI_KEEP_DEBUG_KEYS, &hdev->dev_flags))
+                               continue;
+                       rcu_read_unlock();
+                       return k;
+               }
 
-       rcu_read_lock();
-       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
-               if (addr_type == k->bdaddr_type &&
-                   bacmp(bdaddr, &k->bdaddr) == 0 &&
-                   ltk_role(k->type) == role) {
+               if (ltk_role(k->type) == role) {
                        rcu_read_unlock();
                        return k;
                }
@@ -3221,17 +3268,22 @@ struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
 {
        struct smp_irk *irk;
 
-       list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
-               if (!bacmp(&irk->rpa, rpa))
+       rcu_read_lock();
+       list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
+               if (!bacmp(&irk->rpa, rpa)) {
+                       rcu_read_unlock();
                        return irk;
+               }
        }
 
-       list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+       list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
                if (smp_irk_matches(hdev, irk->val, rpa)) {
                        bacpy(&irk->rpa, rpa);
+                       rcu_read_unlock();
                        return irk;
                }
        }
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -3245,11 +3297,15 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
        if (addr_type == ADDR_LE_DEV_RANDOM && (bdaddr->b[5] & 0xc0) != 0xc0)
                return NULL;
 
-       list_for_each_entry(irk, &hdev->identity_resolving_keys, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
                if (addr_type == irk->addr_type &&
-                   bacmp(bdaddr, &irk->bdaddr) == 0)
+                   bacmp(bdaddr, &irk->bdaddr) == 0) {
+                       rcu_read_unlock();
                        return irk;
+               }
        }
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -3270,7 +3326,7 @@ struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
                key = kzalloc(sizeof(*key), GFP_KERNEL);
                if (!key)
                        return NULL;
-               list_add(&key->list, &hdev->link_keys);
+               list_add_rcu(&key->list, &hdev->link_keys);
        }
 
        BT_DBG("%s key for %pMR type %u", hdev->name, bdaddr, type);
@@ -3308,7 +3364,7 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
        struct smp_ltk *key, *old_key;
        u8 role = ltk_role(type);
 
-       old_key = hci_find_ltk_by_addr(hdev, bdaddr, addr_type, role);
+       old_key = hci_find_ltk(hdev, bdaddr, addr_type, role);
        if (old_key)
                key = old_key;
        else {
@@ -3344,7 +3400,7 @@ struct smp_irk *hci_add_irk(struct hci_dev *hdev, bdaddr_t *bdaddr,
                bacpy(&irk->bdaddr, bdaddr);
                irk->addr_type = addr_type;
 
-               list_add(&irk->list, &hdev->identity_resolving_keys);
+               list_add_rcu(&irk->list, &hdev->identity_resolving_keys);
        }
 
        memcpy(irk->val, val, 16);
@@ -3363,8 +3419,8 @@ int hci_remove_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 
        BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
-       list_del(&key->list);
-       kfree(key);
+       list_del_rcu(&key->list);
+       kfree_rcu(key, rcu);
 
        return 0;
 }
@@ -3390,16 +3446,16 @@ int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
 
 void hci_remove_irk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 addr_type)
 {
-       struct smp_irk *k, *tmp;
+       struct smp_irk *k;
 
-       list_for_each_entry_safe(k, tmp, &hdev->identity_resolving_keys, list) {
+       list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) {
                if (bacmp(bdaddr, &k->bdaddr) || k->addr_type != addr_type)
                        continue;
 
                BT_DBG("%s removing %pMR", hdev->name, bdaddr);
 
-               list_del(&k->list);
-               kfree(k);
+               list_del_rcu(&k->list);
+               kfree_rcu(k, rcu);
        }
 }
 
@@ -3461,7 +3517,8 @@ void hci_remote_oob_data_clear(struct hci_dev *hdev)
 }
 
 int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                           u8 *hash, u8 *randomizer)
+                           u8 *hash192, u8 *rand192,
+                           u8 *hash256, u8 *rand256)
 {
        struct oob_data *data;
 
@@ -3475,38 +3532,21 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
                list_add(&data->list, &hdev->remote_oob_data);
        }
 
-       memcpy(data->hash192, hash, sizeof(data->hash192));
-       memcpy(data->randomizer192, randomizer, sizeof(data->randomizer192));
-
-       memset(data->hash256, 0, sizeof(data->hash256));
-       memset(data->randomizer256, 0, sizeof(data->randomizer256));
-
-       BT_DBG("%s for %pMR", hdev->name, bdaddr);
-
-       return 0;
-}
-
-int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                               u8 *hash192, u8 *randomizer192,
-                               u8 *hash256, u8 *randomizer256)
-{
-       struct oob_data *data;
-
-       data = hci_find_remote_oob_data(hdev, bdaddr);
-       if (!data) {
-               data = kmalloc(sizeof(*data), GFP_KERNEL);
-               if (!data)
-                       return -ENOMEM;
-
-               bacpy(&data->bdaddr, bdaddr);
-               list_add(&data->list, &hdev->remote_oob_data);
+       if (hash192 && rand192) {
+               memcpy(data->hash192, hash192, sizeof(data->hash192));
+               memcpy(data->rand192, rand192, sizeof(data->rand192));
+       } else {
+               memset(data->hash192, 0, sizeof(data->hash192));
+               memset(data->rand192, 0, sizeof(data->rand192));
        }
 
-       memcpy(data->hash192, hash192, sizeof(data->hash192));
-       memcpy(data->randomizer192, randomizer192, sizeof(data->randomizer192));
-
-       memcpy(data->hash256, hash256, sizeof(data->hash256));
-       memcpy(data->randomizer256, randomizer256, sizeof(data->randomizer256));
+       if (hash256 && rand256) {
+               memcpy(data->hash256, hash256, sizeof(data->hash256));
+               memcpy(data->rand256, rand256, sizeof(data->rand256));
+       } else {
+               memset(data->hash256, 0, sizeof(data->hash256));
+               memset(data->rand256, 0, sizeof(data->rand256));
+       }
 
        BT_DBG("%s for %pMR", hdev->name, bdaddr);