Bluetooth: Convert link keys list to use RCU
[firefly-linux-kernel-4.4.55.git] / net / bluetooth / hci_core.c
index cb05d7f16a34acc0ca78958d3e5d612453f7d154..5c319a49a5a4ca8e510a28fe553b5c59c74c2a15 100644 (file)
@@ -200,31 +200,6 @@ static const struct file_operations blacklist_fops = {
        .release        = single_release,
 };
 
-static int whitelist_show(struct seq_file *f, void *p)
-{
-       struct hci_dev *hdev = f->private;
-       struct bdaddr_list *b;
-
-       hci_dev_lock(hdev);
-       list_for_each_entry(b, &hdev->whitelist, list)
-               seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
-       hci_dev_unlock(hdev);
-
-       return 0;
-}
-
-static int whitelist_open(struct inode *inode, struct file *file)
-{
-       return single_open(file, whitelist_show, inode->i_private);
-}
-
-static const struct file_operations whitelist_fops = {
-       .open           = whitelist_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
-};
-
 static int uuids_show(struct seq_file *f, void *p)
 {
        struct hci_dev *hdev = f->private;
@@ -299,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;
 }
@@ -773,16 +746,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;
 }
@@ -803,17 +775,15 @@ static const struct file_operations identity_resolving_keys_fops = {
 static int long_term_keys_show(struct seq_file *f, void *ptr)
 {
        struct hci_dev *hdev = f->private;
-       struct list_head *p, *n;
+       struct smp_ltk *ltk;
 
-       hci_dev_lock(hdev);
-       list_for_each_safe(p, n, &hdev->long_term_keys) {
-               struct smp_ltk *ltk = list_entry(p, struct smp_ltk, list);
+       rcu_read_lock();
+       list_for_each_entry_rcu(ltk, &hdev->long_term_keys, list)
                seq_printf(f, "%pMR (type %u) %u 0x%02x %u %.4x %.16llx %*phN\n",
                           &ltk->bdaddr, ltk->bdaddr_type, ltk->authenticated,
                           ltk->type, ltk->enc_size, __le16_to_cpu(ltk->ediv),
                           __le64_to_cpu(ltk->rand), 16, ltk->val);
-       }
-       hci_dev_unlock(hdev);
+       rcu_read_unlock();
 
        return 0;
 }
@@ -1030,10 +1000,13 @@ static int device_list_show(struct seq_file *f, void *ptr)
 {
        struct hci_dev *hdev = f->private;
        struct hci_conn_params *p;
+       struct bdaddr_list *b;
 
        hci_dev_lock(hdev);
+       list_for_each_entry(b, &hdev->whitelist, list)
+               seq_printf(f, "%pMR (type %u)\n", &b->bdaddr, b->bdaddr_type);
        list_for_each_entry(p, &hdev->le_conn_params, list) {
-               seq_printf(f, "%pMR %u %u\n", &p->addr, p->addr_type,
+               seq_printf(f, "%pMR (type %u) %u\n", &p->addr, p->addr_type,
                           p->auto_connect);
        }
        hci_dev_unlock(hdev);
@@ -1147,13 +1120,16 @@ struct sk_buff *__hci_cmd_sync_ev(struct hci_dev *hdev, u16 opcode, u32 plen,
 
        hdev->req_status = HCI_REQ_PEND;
 
-       err = hci_req_run(&req, hci_req_sync_complete);
-       if (err < 0)
-               return ERR_PTR(err);
-
        add_wait_queue(&hdev->req_wait_q, &wait);
        set_current_state(TASK_INTERRUPTIBLE);
 
+       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);
+       }
+
        schedule_timeout(timeout);
 
        remove_wait_queue(&hdev->req_wait_q, &wait);
@@ -1211,10 +1187,16 @@ static int __hci_req_sync(struct hci_dev *hdev,
 
        func(&req, opt);
 
+       add_wait_queue(&hdev->req_wait_q, &wait);
+       set_current_state(TASK_INTERRUPTIBLE);
+
        err = hci_req_run(&req, hci_req_sync_complete);
        if (err < 0) {
                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
                 * trigger any commands to be sent. This is normal behavior
@@ -1226,9 +1208,6 @@ static int __hci_req_sync(struct hci_dev *hdev,
                return err;
        }
 
-       add_wait_queue(&hdev->req_wait_q, &wait);
-       set_current_state(TASK_INTERRUPTIBLE);
-
        schedule_timeout(timeout);
 
        remove_wait_queue(&hdev->req_wait_q, &wait);
@@ -1811,10 +1790,10 @@ static int __hci_init(struct hci_dev *hdev)
                           &hdev->manufacturer);
        debugfs_create_u8("hci_version", 0444, hdev->debugfs, &hdev->hci_ver);
        debugfs_create_u16("hci_revision", 0444, hdev->debugfs, &hdev->hci_rev);
+       debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
+                           &device_list_fops);
        debugfs_create_file("blacklist", 0444, hdev->debugfs, hdev,
                            &blacklist_fops);
-       debugfs_create_file("whitelist", 0444, hdev->debugfs, hdev,
-                           &whitelist_fops);
        debugfs_create_file("uuids", 0444, hdev->debugfs, hdev, &uuids_fops);
 
        debugfs_create_file("conn_info_min_age", 0644, hdev->debugfs, hdev,
@@ -1893,8 +1872,6 @@ static int __hci_init(struct hci_dev *hdev)
                                    hdev, &adv_min_interval_fops);
                debugfs_create_file("adv_max_interval", 0644, hdev->debugfs,
                                    hdev, &adv_max_interval_fops);
-               debugfs_create_file("device_list", 0444, hdev->debugfs, hdev,
-                                   &device_list_fops);
                debugfs_create_u16("discov_interleaved_timeout", 0644,
                                   hdev->debugfs,
                                   &hdev->discov_interleaved_timeout);
@@ -2584,6 +2561,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);
@@ -2707,6 +2689,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);
@@ -3112,35 +3099,31 @@ 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);
        }
 }
 
 void hci_smp_ltks_clear(struct hci_dev *hdev)
 {
-       struct smp_ltk *k, *tmp;
+       struct smp_ltk *k;
 
-       list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
-               list_del(&k->list);
-               kfree(k);
+       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
+               list_del_rcu(&k->list);
+               kfree_rcu(k, rcu);
        }
 }
 
 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);
        }
 }
 
@@ -3148,9 +3131,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;
 }
@@ -3204,15 +3192,18 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, __le16 ediv, __le64 rand,
 {
        struct smp_ltk *k;
 
-       list_for_each_entry(k, &hdev->long_term_keys, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
                if (k->ediv != ediv || k->rand != rand)
                        continue;
 
                if (ltk_role(k->type) != role)
                        continue;
 
+               rcu_read_unlock();
                return k;
        }
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -3222,11 +3213,16 @@ struct smp_ltk *hci_find_ltk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
 {
        struct smp_ltk *k;
 
-       list_for_each_entry(k, &hdev->long_term_keys, list)
+       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)
+                   ltk_role(k->type) == role) {
+                       rcu_read_unlock();
                        return k;
+               }
+       }
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -3235,17 +3231,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;
 }
@@ -3259,11 +3260,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;
 }
@@ -3284,7 +3289,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);
@@ -3329,7 +3334,7 @@ struct smp_ltk *hci_add_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
                key = kzalloc(sizeof(*key), GFP_KERNEL);
                if (!key)
                        return NULL;
-               list_add(&key->list, &hdev->long_term_keys);
+               list_add_rcu(&key->list, &hdev->long_term_keys);
        }
 
        bacpy(&key->bdaddr, bdaddr);
@@ -3358,7 +3363,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);
@@ -3377,25 +3382,25 @@ 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;
 }
 
 int hci_remove_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 bdaddr_type)
 {
-       struct smp_ltk *k, *tmp;
+       struct smp_ltk *k;
        int removed = 0;
 
-       list_for_each_entry_safe(k, tmp, &hdev->long_term_keys, list) {
+       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
                if (bacmp(bdaddr, &k->bdaddr) || k->bdaddr_type != bdaddr_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);
                removed++;
        }
 
@@ -3404,16 +3409,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);
        }
 }
 
@@ -3475,7 +3480,7 @@ 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 *hash, u8 *rand)
 {
        struct oob_data *data;
 
@@ -3490,10 +3495,10 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
        }
 
        memcpy(data->hash192, hash, sizeof(data->hash192));
-       memcpy(data->randomizer192, randomizer, sizeof(data->randomizer192));
+       memcpy(data->rand192, rand, sizeof(data->rand192));
 
        memset(data->hash256, 0, sizeof(data->hash256));
-       memset(data->randomizer256, 0, sizeof(data->randomizer256));
+       memset(data->rand256, 0, sizeof(data->rand256));
 
        BT_DBG("%s for %pMR", hdev->name, bdaddr);
 
@@ -3501,8 +3506,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
 }
 
 int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
-                               u8 *hash192, u8 *randomizer192,
-                               u8 *hash256, u8 *randomizer256)
+                               u8 *hash192, u8 *rand192,
+                               u8 *hash256, u8 *rand256)
 {
        struct oob_data *data;
 
@@ -3517,10 +3522,10 @@ int hci_add_remote_oob_ext_data(struct hci_dev *hdev, bdaddr_t *bdaddr,
        }
 
        memcpy(data->hash192, hash192, sizeof(data->hash192));
-       memcpy(data->randomizer192, randomizer192, sizeof(data->randomizer192));
+       memcpy(data->rand192, rand192, sizeof(data->rand192));
 
        memcpy(data->hash256, hash256, sizeof(data->hash256));
-       memcpy(data->randomizer256, randomizer256, sizeof(data->randomizer256));
+       memcpy(data->rand256, rand256, sizeof(data->rand256));
 
        BT_DBG("%s for %pMR", hdev->name, bdaddr);
 
@@ -4244,6 +4249,24 @@ int hci_resume_dev(struct hci_dev *hdev)
 }
 EXPORT_SYMBOL(hci_resume_dev);
 
+/* Reset HCI device */
+int hci_reset_dev(struct hci_dev *hdev)
+{
+       const u8 hw_err[] = { HCI_EV_HARDWARE_ERROR, 0x01, 0x00 };
+       struct sk_buff *skb;
+
+       skb = bt_skb_alloc(3, GFP_ATOMIC);
+       if (!skb)
+               return -ENOMEM;
+
+       bt_cb(skb)->pkt_type = HCI_EVENT_PKT;
+       memcpy(skb_put(skb, 3), hw_err, 3);
+
+       /* Send Hardware Error to upper stack */
+       return hci_recv_frame(hdev, skb);
+}
+EXPORT_SYMBOL(hci_reset_dev);
+
 /* Receive frame from HCI drivers */
 int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
 {
@@ -4477,7 +4500,7 @@ int hci_req_run(struct hci_request *req, hci_req_complete_t complete)
 
        BT_DBG("length %u", skb_queue_len(&req->cmd_q));
 
-       /* If an error occured during request building, remove all HCI
+       /* If an error occurred during request building, remove all HCI
         * commands queued on the HCI request queue.
         */
        if (req->err) {
@@ -4546,7 +4569,7 @@ int hci_send_cmd(struct hci_dev *hdev, __u16 opcode, __u32 plen,
                return -ENOMEM;
        }
 
-       /* Stand-alone HCI commands must be flaged as
+       /* Stand-alone HCI commands must be flagged as
         * single-command requests.
         */
        bt_cb(skb)->req.start = true;
@@ -4566,7 +4589,7 @@ void hci_req_add_ev(struct hci_request *req, u16 opcode, u32 plen,
 
        BT_DBG("%s opcode 0x%4.4x plen %d", hdev->name, opcode, plen);
 
-       /* If an error occured during request building, there is no point in
+       /* If an error occurred during request building, there is no point in
         * queueing the HCI command. We can simply return.
         */
        if (req->err)
@@ -4661,8 +4684,12 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
 
                skb_shinfo(skb)->frag_list = NULL;
 
-               /* Queue all fragments atomically */
-               spin_lock(&queue->lock);
+               /* Queue all fragments atomically. We need to use spin_lock_bh
+                * here because of 6LoWPAN links, as there this function is
+                * called from softirq and using normal spin lock could cause
+                * deadlocks.
+                */
+               spin_lock_bh(&queue->lock);
 
                __skb_queue_tail(queue, skb);
 
@@ -4679,7 +4706,7 @@ static void hci_queue_acl(struct hci_chan *chan, struct sk_buff_head *queue,
                        __skb_queue_tail(queue, skb);
                } while (list);
 
-               spin_unlock(&queue->lock);
+               spin_unlock_bh(&queue->lock);
        }
 }