]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/blobdiff - net/bluetooth/hci_core.c
Bluetooth: Enable erroneous data reporting if WBS is supported
[mirror_ubuntu-jammy-kernel.git] / net / bluetooth / hci_core.c
index 9e19d5a3aac87086e0e10fc0785eeb64d59512eb..9ce98762559bc2f11971ac1fe12bf4a38d8b360d 100644 (file)
@@ -603,6 +603,9 @@ static int hci_init3_req(struct hci_request *req, unsigned long opt)
        if (hdev->commands[8] & 0x01)
                hci_req_add(req, HCI_OP_READ_PAGE_SCAN_ACTIVITY, 0, NULL);
 
+       if (hdev->commands[18] & 0x02)
+               hci_req_add(req, HCI_OP_READ_DEF_ERR_DATA_REPORTING, 0, NULL);
+
        /* Some older Broadcom based Bluetooth 1.2 controllers do not
         * support the Read Page Scan Type command. Check support for
         * this command in the bit mask of supported commands.
@@ -838,6 +841,26 @@ static int hci_init4_req(struct hci_request *req, unsigned long opt)
                            sizeof(support), &support);
        }
 
+       /* Set erroneous data reporting if supported to the wideband speech
+        * setting value
+        */
+       if (hdev->commands[18] & 0x04) {
+               bool enabled = hci_dev_test_flag(hdev,
+                                                HCI_WIDEBAND_SPEECH_ENABLED);
+
+               if (enabled !=
+                   (hdev->err_data_reporting == ERR_DATA_REPORTING_ENABLED)) {
+                       struct hci_cp_write_def_err_data_reporting cp;
+
+                       cp.err_data_reporting = enabled ?
+                                               ERR_DATA_REPORTING_ENABLED :
+                                               ERR_DATA_REPORTING_DISABLED;
+
+                       hci_req_add(req, HCI_OP_WRITE_DEF_ERR_DATA_REPORTING,
+                                   sizeof(cp), &cp);
+               }
+       }
+
        /* Set Suggested Default Data Length to maximum if supported */
        if (hdev->le_features[0] & HCI_LE_DATA_LEN_EXT) {
                struct hci_cp_le_write_def_data_len cp;
@@ -2285,7 +2308,7 @@ void hci_link_keys_clear(struct hci_dev *hdev)
 {
        struct link_key *key;
 
-       list_for_each_entry_rcu(key, &hdev->link_keys, list) {
+       list_for_each_entry(key, &hdev->link_keys, list) {
                list_del_rcu(&key->list);
                kfree_rcu(key, rcu);
        }
@@ -2295,7 +2318,7 @@ void hci_smp_ltks_clear(struct hci_dev *hdev)
 {
        struct smp_ltk *k;
 
-       list_for_each_entry_rcu(k, &hdev->long_term_keys, list) {
+       list_for_each_entry(k, &hdev->long_term_keys, list) {
                list_del_rcu(&k->list);
                kfree_rcu(k, rcu);
        }
@@ -2305,12 +2328,39 @@ void hci_smp_irks_clear(struct hci_dev *hdev)
 {
        struct smp_irk *k;
 
-       list_for_each_entry_rcu(k, &hdev->identity_resolving_keys, list) {
+       list_for_each_entry(k, &hdev->identity_resolving_keys, list) {
                list_del_rcu(&k->list);
                kfree_rcu(k, rcu);
        }
 }
 
+void hci_blocked_keys_clear(struct hci_dev *hdev)
+{
+       struct blocked_key *b;
+
+       list_for_each_entry(b, &hdev->blocked_keys, list) {
+               list_del_rcu(&b->list);
+               kfree_rcu(b, rcu);
+       }
+}
+
+bool hci_is_blocked_key(struct hci_dev *hdev, u8 type, u8 val[16])
+{
+       bool blocked = false;
+       struct blocked_key *b;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(b, &hdev->blocked_keys, list) {
+               if (b->type == type && !memcmp(b->val, val, sizeof(b->val))) {
+                       blocked = true;
+                       break;
+               }
+       }
+
+       rcu_read_unlock();
+       return blocked;
+}
+
 struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
 {
        struct link_key *k;
@@ -2319,6 +2369,16 @@ struct link_key *hci_find_link_key(struct hci_dev *hdev, bdaddr_t *bdaddr)
        list_for_each_entry_rcu(k, &hdev->link_keys, list) {
                if (bacmp(bdaddr, &k->bdaddr) == 0) {
                        rcu_read_unlock();
+
+                       if (hci_is_blocked_key(hdev,
+                                              HCI_BLOCKED_KEY_TYPE_LINKKEY,
+                                              k->val)) {
+                               bt_dev_warn_ratelimited(hdev,
+                                                       "Link key blocked for %pMR",
+                                                       &k->bdaddr);
+                               return NULL;
+                       }
+
                        return k;
                }
        }
@@ -2387,6 +2447,15 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
                if (smp_ltk_is_sc(k) || ltk_role(k->type) == role) {
                        rcu_read_unlock();
+
+                       if (hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_LTK,
+                                              k->val)) {
+                               bt_dev_warn_ratelimited(hdev,
+                                                       "LTK blocked for %pMR",
+                                                       &k->bdaddr);
+                               return NULL;
+                       }
+
                        return k;
                }
        }
@@ -2397,31 +2466,42 @@ struct smp_ltk *hci_find_ltk(struct hci_dev *hdev, bdaddr_t *bdaddr,
 
 struct smp_irk *hci_find_irk_by_rpa(struct hci_dev *hdev, bdaddr_t *rpa)
 {
+       struct smp_irk *irk_to_return = NULL;
        struct smp_irk *irk;
 
        rcu_read_lock();
        list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
                if (!bacmp(&irk->rpa, rpa)) {
-                       rcu_read_unlock();
-                       return irk;
+                       irk_to_return = irk;
+                       goto done;
                }
        }
 
        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;
+                       irk_to_return = irk;
+                       goto done;
                }
        }
+
+done:
+       if (irk_to_return && hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_IRK,
+                                               irk_to_return->val)) {
+               bt_dev_warn_ratelimited(hdev, "Identity key blocked for %pMR",
+                                       &irk_to_return->bdaddr);
+               irk_to_return = NULL;
+       }
+
        rcu_read_unlock();
 
-       return NULL;
+       return irk_to_return;
 }
 
 struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
                                     u8 addr_type)
 {
+       struct smp_irk *irk_to_return = NULL;
        struct smp_irk *irk;
 
        /* Identity Address must be public or static random */
@@ -2432,13 +2512,23 @@ struct smp_irk *hci_find_irk_by_addr(struct hci_dev *hdev, bdaddr_t *bdaddr,
        list_for_each_entry_rcu(irk, &hdev->identity_resolving_keys, list) {
                if (addr_type == irk->addr_type &&
                    bacmp(bdaddr, &irk->bdaddr) == 0) {
-                       rcu_read_unlock();
-                       return irk;
+                       irk_to_return = irk;
+                       goto done;
                }
        }
+
+done:
+
+       if (irk_to_return && hci_is_blocked_key(hdev, HCI_BLOCKED_KEY_TYPE_IRK,
+                                               irk_to_return->val)) {
+               bt_dev_warn_ratelimited(hdev, "Identity key blocked for %pMR",
+                                       &irk_to_return->bdaddr);
+               irk_to_return = NULL;
+       }
+
        rcu_read_unlock();
 
-       return NULL;
+       return irk_to_return;
 }
 
 struct link_key *hci_add_link_key(struct hci_dev *hdev, struct hci_conn *conn,
@@ -3244,6 +3334,7 @@ struct hci_dev *hci_alloc_dev(void)
        INIT_LIST_HEAD(&hdev->pend_le_reports);
        INIT_LIST_HEAD(&hdev->conn_hash.list);
        INIT_LIST_HEAD(&hdev->adv_instances);
+       INIT_LIST_HEAD(&hdev->blocked_keys);
 
        INIT_WORK(&hdev->rx_work, hci_rx_work);
        INIT_WORK(&hdev->cmd_work, hci_cmd_work);
@@ -3443,6 +3534,7 @@ void hci_unregister_dev(struct hci_dev *hdev)
        hci_bdaddr_list_clear(&hdev->le_resolv_list);
        hci_conn_params_clear_all(hdev);
        hci_discovery_filter_clear(hdev);
+       hci_blocked_keys_clear(hdev);
        hci_dev_unlock(hdev);
 
        hci_dev_put(hdev);
@@ -3496,7 +3588,8 @@ int hci_recv_frame(struct hci_dev *hdev, struct sk_buff *skb)
 
        if (hci_skb_pkt_type(skb) != HCI_EVENT_PKT &&
            hci_skb_pkt_type(skb) != HCI_ACLDATA_PKT &&
-           hci_skb_pkt_type(skb) != HCI_SCODATA_PKT) {
+           hci_skb_pkt_type(skb) != HCI_SCODATA_PKT &&
+           hci_skb_pkt_type(skb) != HCI_ISODATA_PKT) {
                kfree_skb(skb);
                return -EINVAL;
        }
@@ -4218,15 +4311,10 @@ static void hci_sched_le(struct hci_dev *hdev)
        if (!hci_conn_num(hdev, LE_LINK))
                return;
 
-       if (!hci_dev_test_flag(hdev, HCI_UNCONFIGURED)) {
-               /* LE tx timeout must be longer than maximum
-                * link supervision timeout (40.9 seconds) */
-               if (!hdev->le_cnt && hdev->le_pkts &&
-                   time_after(jiffies, hdev->le_last_tx + HZ * 45))
-                       hci_link_tx_to(hdev, LE_LINK);
-       }
-
        cnt = hdev->le_pkts ? hdev->le_cnt : hdev->acl_cnt;
+
+       __check_timeout(hdev, cnt);
+
        tmp = cnt;
        while (cnt && (chan = hci_chan_sent(hdev, LE_LINK, &quote))) {
                u32 priority = (skb_peek(&chan->data_q))->priority;
@@ -4322,13 +4410,16 @@ static void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_sco_hdr *hdr = (void *) skb->data;
        struct hci_conn *conn;
-       __u16 handle;
+       __u16 handle, flags;
 
        skb_pull(skb, HCI_SCO_HDR_SIZE);
 
        handle = __le16_to_cpu(hdr->handle);
+       flags  = hci_flags(handle);
+       handle = hci_handle(handle);
 
-       BT_DBG("%s len %d handle 0x%4.4x", hdev->name, skb->len, handle);
+       BT_DBG("%s len %d handle 0x%4.4x flags 0x%4.4x", hdev->name, skb->len,
+              handle, flags);
 
        hdev->stat.sco_rx++;
 
@@ -4479,6 +4570,7 @@ static void hci_rx_work(struct work_struct *work)
                        switch (hci_skb_pkt_type(skb)) {
                        case HCI_ACLDATA_PKT:
                        case HCI_SCODATA_PKT:
+                       case HCI_ISODATA_PKT:
                                kfree_skb(skb);
                                continue;
                        }