Bluetooth: Unify remote OOB data functions
[cascardo/linux.git] / net / bluetooth / hci_core.c
index cb05d7f..967fbfe 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;
 }
@@ -433,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)
 {
@@ -773,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;
 }
@@ -803,17 +818,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 +1043,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 +1163,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 +1230,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 +1251,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);
@@ -1755,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);
@@ -1811,10 +1831,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,
@@ -1840,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)) {
@@ -1893,8 +1917,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 +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);
@@ -2707,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);
@@ -3112,35 +3144,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 +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;
 }
@@ -3174,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;
@@ -3199,34 +3236,30 @@ 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;
 
-       list_for_each_entry(k, &hdev->long_term_keys, list) {
-               if (k->ediv != ediv || k->rand != rand)
-                       continue;
-
-               if (ltk_role(k->type) != role)
+       rcu_read_lock();
+       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
+               if (addr_type != k->bdaddr_type || bacmp(bdaddr, &k->bdaddr))
                        continue;
 
-               return k;
-       }
-
-       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;
+               }
 
-       list_for_each_entry(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;
+               }
+       }
+       rcu_read_unlock();
 
        return NULL;
 }
@@ -3235,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;
 }
@@ -3259,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;
 }
@@ -3284,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);
@@ -3322,14 +3364,14 @@ 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 {
                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 +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);
@@ -3377,25 +3419,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 +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);
        }
 }
 
@@ -3475,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;
 
@@ -3489,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);
 
@@ -4244,6 +4270,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 +4521,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 +4590,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 +4610,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 +4705,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 +4727,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);
        }
 }