Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Bluetooth: Enumerate local supported codec and cache details

Move reading of supported local codecs into a separate init function,
query codecs capabilities and cache the data

Signed-off-by: Kiran K <kiran.k@intel.com>
Signed-off-by: Chethan T N <chethan.tumkur.narayan@intel.com>
Signed-off-by: Srivatsa Ravishankar <ravishankar.srivatsa@intel.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>

authored by

Kiran K and committed by
Luiz Augusto von Dentz
8961987f 49d8a560

+244 -5
+41
include/net/bluetooth/hci.h
··· 1308 1308 } __packed; 1309 1309 1310 1310 #define HCI_OP_READ_LOCAL_CODECS 0x100b 1311 + struct hci_std_codecs { 1312 + __u8 num; 1313 + __u8 codec[]; 1314 + } __packed; 1315 + 1316 + struct hci_vnd_codec { 1317 + /* company id */ 1318 + __le16 cid; 1319 + /* vendor codec id */ 1320 + __le16 vid; 1321 + } __packed; 1322 + 1323 + struct hci_vnd_codecs { 1324 + __u8 num; 1325 + struct hci_vnd_codec codec[]; 1326 + } __packed; 1327 + 1328 + struct hci_rp_read_local_supported_codecs { 1329 + __u8 status; 1330 + struct hci_std_codecs std_codecs; 1331 + struct hci_vnd_codecs vnd_codecs; 1332 + } __packed; 1311 1333 1312 1334 #define HCI_OP_READ_LOCAL_PAIRING_OPTS 0x100c 1313 1335 struct hci_rp_read_local_pairing_opts { 1314 1336 __u8 status; 1315 1337 __u8 pairing_opts; 1316 1338 __u8 max_key_size; 1339 + } __packed; 1340 + 1341 + #define HCI_OP_READ_LOCAL_CODEC_CAPS 0x100e 1342 + struct hci_op_read_local_codec_caps { 1343 + __u8 id; 1344 + __le16 cid; 1345 + __le16 vid; 1346 + __u8 transport; 1347 + __u8 direction; 1348 + } __packed; 1349 + 1350 + struct hci_codec_caps { 1351 + __u8 len; 1352 + __u8 data[]; 1353 + } __packed; 1354 + 1355 + struct hci_rp_read_local_codec_caps { 1356 + __u8 status; 1357 + __u8 num_caps; 1317 1358 } __packed; 1318 1359 1319 1360 #define HCI_OP_READ_PAGE_SCAN_ACTIVITY 0x0c1b
+17
include/net/bluetooth/hci_core.h
··· 131 131 u8 bdaddr_type; 132 132 }; 133 133 134 + struct codec_list { 135 + struct list_head list; 136 + u8 id; 137 + __u16 cid; 138 + __u16 vid; 139 + u8 transport; 140 + u8 num_caps; 141 + u32 len; 142 + struct hci_codec_caps caps[]; 143 + }; 144 + 134 145 struct bdaddr_list_with_irk { 135 146 struct list_head list; 136 147 bdaddr_t bdaddr; ··· 547 536 struct list_head pend_le_conns; 548 537 struct list_head pend_le_reports; 549 538 struct list_head blocked_keys; 539 + struct list_head local_codecs; 550 540 551 541 struct hci_dev_stats stat; 552 542 ··· 1881 1869 #define SCO_AIRMODE_MASK 0x0003 1882 1870 #define SCO_AIRMODE_CVSD 0x0000 1883 1871 #define SCO_AIRMODE_TRANSP 0x0003 1872 + 1873 + #define LOCAL_CODEC_ACL_MASK BIT(0) 1874 + #define LOCAL_CODEC_SCO_MASK BIT(1) 1875 + 1876 + #define TRANSPORT_TYPE_MAX 0x04 1884 1877 1885 1878 #endif /* __HCI_CORE_H */
+1 -1
net/bluetooth/Makefile
··· 14 14 15 15 bluetooth-y := af_bluetooth.o hci_core.o hci_conn.o hci_event.o mgmt.o \ 16 16 hci_sock.o hci_sysfs.o l2cap_core.o l2cap_sock.o smp.o lib.o \ 17 - ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o 17 + ecdh_helper.o hci_request.o mgmt_util.o mgmt_config.o hci_codec.o 18 18 19 19 bluetooth-$(CONFIG_BT_BREDR) += sco.o 20 20 bluetooth-$(CONFIG_BT_HS) += a2mp.o amp.o
+172
net/bluetooth/hci_codec.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + /* Copyright (C) 2021 Intel Corporation */ 4 + 5 + #include <net/bluetooth/bluetooth.h> 6 + #include <net/bluetooth/hci_core.h> 7 + #include "hci_codec.h" 8 + 9 + static int hci_codec_list_add(struct list_head *list, 10 + struct hci_op_read_local_codec_caps *sent, 11 + struct hci_rp_read_local_codec_caps *rp, 12 + void *caps, 13 + __u32 len) 14 + { 15 + struct codec_list *entry; 16 + 17 + entry = kzalloc(sizeof(*entry) + len, GFP_KERNEL); 18 + if (!entry) 19 + return -ENOMEM; 20 + 21 + entry->id = sent->id; 22 + if (sent->id == 0xFF) { 23 + entry->cid = __le16_to_cpu(sent->cid); 24 + entry->vid = __le16_to_cpu(sent->vid); 25 + } 26 + entry->transport = sent->transport; 27 + entry->len = len; 28 + entry->num_caps = rp->num_caps; 29 + if (rp->num_caps) 30 + memcpy(entry->caps, caps, len); 31 + list_add(&entry->list, list); 32 + 33 + return 0; 34 + } 35 + 36 + void hci_codec_list_clear(struct list_head *codec_list) 37 + { 38 + struct codec_list *c, *n; 39 + 40 + list_for_each_entry_safe(c, n, codec_list, list) { 41 + list_del(&c->list); 42 + kfree(c); 43 + } 44 + } 45 + 46 + static void hci_read_codec_capabilities(struct hci_dev *hdev, __u8 transport, 47 + struct hci_op_read_local_codec_caps 48 + *cmd) 49 + { 50 + __u8 i; 51 + 52 + for (i = 0; i < TRANSPORT_TYPE_MAX; i++) { 53 + if (transport & BIT(i)) { 54 + struct hci_rp_read_local_codec_caps *rp; 55 + struct hci_codec_caps *caps; 56 + struct sk_buff *skb; 57 + __u8 j; 58 + __u32 len; 59 + 60 + cmd->transport = i; 61 + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODEC_CAPS, 62 + sizeof(*cmd), cmd, 63 + HCI_CMD_TIMEOUT); 64 + if (IS_ERR(skb)) { 65 + bt_dev_err(hdev, "Failed to read codec capabilities (%ld)", 66 + PTR_ERR(skb)); 67 + continue; 68 + } 69 + 70 + if (skb->len < sizeof(*rp)) 71 + goto error; 72 + 73 + rp = (void *)skb->data; 74 + 75 + if (rp->status) 76 + goto error; 77 + 78 + if (!rp->num_caps) { 79 + len = 0; 80 + /* this codec doesn't have capabilities */ 81 + goto skip_caps_parse; 82 + } 83 + 84 + skb_pull(skb, sizeof(*rp)); 85 + 86 + for (j = 0, len = 0; j < rp->num_caps; j++) { 87 + caps = (void *)skb->data; 88 + if (skb->len < sizeof(*caps)) 89 + goto error; 90 + if (skb->len < caps->len) 91 + goto error; 92 + len += sizeof(caps->len) + caps->len; 93 + skb_pull(skb, sizeof(caps->len) + caps->len); 94 + } 95 + 96 + skip_caps_parse: 97 + hci_dev_lock(hdev); 98 + hci_codec_list_add(&hdev->local_codecs, cmd, rp, 99 + (__u8 *)rp + sizeof(*rp), len); 100 + hci_dev_unlock(hdev); 101 + error: 102 + kfree_skb(skb); 103 + } 104 + } 105 + } 106 + 107 + void hci_read_supported_codecs(struct hci_dev *hdev) 108 + { 109 + struct sk_buff *skb; 110 + struct hci_rp_read_local_supported_codecs *rp; 111 + struct hci_std_codecs *std_codecs; 112 + struct hci_vnd_codecs *vnd_codecs; 113 + struct hci_op_read_local_codec_caps caps; 114 + __u8 i; 115 + 116 + skb = __hci_cmd_sync(hdev, HCI_OP_READ_LOCAL_CODECS, 0, NULL, 117 + HCI_CMD_TIMEOUT); 118 + 119 + if (IS_ERR(skb)) { 120 + bt_dev_err(hdev, "Failed to read local supported codecs (%ld)", 121 + PTR_ERR(skb)); 122 + return; 123 + } 124 + 125 + if (skb->len < sizeof(*rp)) 126 + goto error; 127 + 128 + rp = (void *)skb->data; 129 + 130 + if (rp->status) 131 + goto error; 132 + 133 + skb_pull(skb, sizeof(rp->status)); 134 + 135 + std_codecs = (void *)skb->data; 136 + 137 + /* validate codecs length before accessing */ 138 + if (skb->len < flex_array_size(std_codecs, codec, std_codecs->num) 139 + + sizeof(std_codecs->num)) 140 + goto error; 141 + 142 + /* enumerate codec capabilities of standard codecs */ 143 + memset(&caps, 0, sizeof(caps)); 144 + for (i = 0; i < std_codecs->num; i++) { 145 + caps.id = std_codecs->codec[i]; 146 + caps.direction = 0x00; 147 + hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps); 148 + } 149 + 150 + skb_pull(skb, flex_array_size(std_codecs, codec, std_codecs->num) 151 + + sizeof(std_codecs->num)); 152 + 153 + vnd_codecs = (void *)skb->data; 154 + 155 + /* validate vendor codecs length before accessing */ 156 + if (skb->len < 157 + flex_array_size(vnd_codecs, codec, vnd_codecs->num) 158 + + sizeof(vnd_codecs->num)) 159 + goto error; 160 + 161 + /* enumerate vendor codec capabilities */ 162 + for (i = 0; i < vnd_codecs->num; i++) { 163 + caps.id = 0xFF; 164 + caps.cid = vnd_codecs->codec[i].cid; 165 + caps.vid = vnd_codecs->codec[i].vid; 166 + caps.direction = 0x00; 167 + hci_read_codec_capabilities(hdev, LOCAL_CODEC_ACL_MASK, &caps); 168 + } 169 + 170 + error: 171 + kfree_skb(skb); 172 + }
+6
net/bluetooth/hci_codec.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + 3 + /* Copyright (C) 2014 Intel Corporation */ 4 + 5 + void hci_read_supported_codecs(struct hci_dev *hdev); 6 + void hci_codec_list_clear(struct list_head *codec_list);
+7 -4
net/bluetooth/hci_core.c
··· 45 45 #include "leds.h" 46 46 #include "msft.h" 47 47 #include "aosp.h" 48 + #include "hci_codec.h" 48 49 49 50 static void hci_rx_work(struct work_struct *work); 50 51 static void hci_cmd_work(struct work_struct *work); ··· 839 838 if (hdev->commands[22] & 0x04) 840 839 hci_set_event_mask_page_2(req); 841 840 842 - /* Read local codec list if the HCI command is supported */ 843 - if (hdev->commands[29] & 0x20) 844 - hci_req_add(req, HCI_OP_READ_LOCAL_CODECS, 0, NULL); 845 - 846 841 /* Read local pairing options if the HCI command is supported */ 847 842 if (hdev->commands[41] & 0x08) 848 843 hci_req_add(req, HCI_OP_READ_LOCAL_PAIRING_OPTS, 0, NULL); ··· 933 936 err = __hci_req_sync(hdev, hci_init4_req, 0, HCI_INIT_TIMEOUT, NULL); 934 937 if (err < 0) 935 938 return err; 939 + 940 + /* Read local codec list if the HCI command is supported */ 941 + if (hdev->commands[29] & 0x20) 942 + hci_read_supported_codecs(hdev); 936 943 937 944 /* This function is only called when the controller is actually in 938 945 * configured state. When the controller is marked as unconfigured, ··· 1849 1848 memset(hdev->eir, 0, sizeof(hdev->eir)); 1850 1849 memset(hdev->dev_class, 0, sizeof(hdev->dev_class)); 1851 1850 bacpy(&hdev->random_addr, BDADDR_ANY); 1851 + hci_codec_list_clear(&hdev->local_codecs); 1852 1852 1853 1853 hci_req_sync_unlock(hdev); 1854 1854 ··· 3850 3848 INIT_LIST_HEAD(&hdev->adv_instances); 3851 3849 INIT_LIST_HEAD(&hdev->blocked_keys); 3852 3850 3851 + INIT_LIST_HEAD(&hdev->local_codecs); 3853 3852 INIT_WORK(&hdev->rx_work, hci_rx_work); 3854 3853 INIT_WORK(&hdev->cmd_work, hci_cmd_work); 3855 3854 INIT_WORK(&hdev->tx_work, hci_tx_work);