Skip to content

Commit 96422f2

Browse files
jfischer-nodkalowsk
authored andcommitted
usb: device: fix Bluetooth buffer handling
In both implementation, when comparing received data length take into account that the buffer obtained from bt_buf_get_tx() stores the type at the top. The buffer types are H:4 and in the TX path we need to check for BT_HCI_H4_* types not BT_BUF_*. In the legacy implementation, the hci_acl_pkt_len() function obtains the length from the USB transaction buffer, which does not contain a buffer type at the top. In the new implementation, partially revert the changes and restore hci_pkt_get_len(), this will be required for any further changes anyway. Fixes commit f85d63a ("Bluetooth: Remove USB H4 mode support"). Signed-off-by: Johann Fischer <[email protected]>
1 parent d25b1d1 commit 96422f2

File tree

2 files changed

+49
-19
lines changed

2 files changed

+49
-19
lines changed

subsys/usb/device/class/bluetooth.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -154,20 +154,20 @@ static void hci_tx_thread(void *p1, void *p2, void *p3)
154154

155155
type = net_buf_pull_u8(buf);
156156
switch (type) {
157-
case BT_BUF_EVT:
157+
case BT_HCI_H4_EVT:
158158
usb_transfer_sync(
159159
bluetooth_ep_data[HCI_INT_EP_IDX].ep_addr,
160160
buf->data, buf->len,
161161
USB_TRANS_WRITE | USB_TRANS_NO_ZLP);
162162
break;
163-
case BT_BUF_ACL_IN:
163+
case BT_HCI_H4_ACL:
164164
usb_transfer_sync(
165165
bluetooth_ep_data[HCI_IN_EP_IDX].ep_addr,
166166
buf->data, buf->len,
167167
USB_TRANS_WRITE);
168168
break;
169169
default:
170-
LOG_ERR("Unknown type %u", type);
170+
LOG_ERR("Unsupported type %u", type);
171171
break;
172172
}
173173

@@ -200,11 +200,11 @@ static uint16_t hci_acl_pkt_len(const uint8_t *data, size_t data_len)
200200
struct bt_hci_acl_hdr *acl_hdr;
201201
size_t hdr_len = sizeof(*acl_hdr);
202202

203-
if (data_len - 1 < hdr_len) {
203+
if (data_len < hdr_len) {
204204
return 0;
205205
}
206206

207-
acl_hdr = (struct bt_hci_acl_hdr *)(data + 1);
207+
acl_hdr = (struct bt_hci_acl_hdr *)data;
208208

209209
return sys_le16_to_cpu(acl_hdr->len) + hdr_len;
210210
}
@@ -250,7 +250,7 @@ static void acl_read_cb(uint8_t ep, int size, void *priv)
250250
LOG_DBG("len %u, chunk %u", buf->len, size);
251251
}
252252

253-
if (buf != NULL && pkt_len == buf->len) {
253+
if (buf != NULL && pkt_len == buf->len - 1) {
254254
k_fifo_put(&rx_queue, buf);
255255
LOG_DBG("put");
256256
buf = NULL;

subsys/usb/device_next/class/bt_hci.c

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -210,14 +210,14 @@ static void bt_hci_tx_thread(void *p1, void *p2, void *p3)
210210
type = net_buf_pull_u8(bt_buf);
211211

212212
switch (type) {
213-
case BT_BUF_EVT:
213+
case BT_HCI_H4_EVT:
214214
ep = bt_hci_get_int_in(c_data);
215215
break;
216-
case BT_BUF_ACL_IN:
216+
case BT_HCI_H4_ACL:
217217
ep = bt_hci_get_bulk_in(c_data);
218218
break;
219219
default:
220-
LOG_ERR("Unknown type %u", type);
220+
LOG_ERR("Unsupported type %u", type);
221221
continue;
222222
}
223223

@@ -273,19 +273,43 @@ static int bt_hci_acl_out_start(struct usbd_class_data *const c_data)
273273
return ret;
274274
}
275275

276-
static uint16_t hci_acl_pkt_len(struct net_buf *const buf)
276+
static uint16_t hci_pkt_get_len(const uint8_t h4_type,
277+
const uint8_t *data, const size_t size)
277278
{
278-
struct bt_hci_acl_hdr *acl_hdr;
279-
size_t hdr_len;
279+
size_t hdr_len = 0;
280+
uint16_t len = 0;
280281

281-
hdr_len = sizeof(*acl_hdr);
282-
if (buf->len - 1 < hdr_len) {
283-
return 0;
282+
switch (h4_type) {
283+
case BT_HCI_H4_CMD: {
284+
struct bt_hci_cmd_hdr *cmd_hdr;
285+
286+
hdr_len = sizeof(*cmd_hdr);
287+
cmd_hdr = (struct bt_hci_cmd_hdr *)data;
288+
len = cmd_hdr->param_len + hdr_len;
289+
break;
290+
}
291+
case BT_HCI_H4_ACL: {
292+
struct bt_hci_acl_hdr *acl_hdr;
293+
294+
hdr_len = sizeof(*acl_hdr);
295+
acl_hdr = (struct bt_hci_acl_hdr *)data;
296+
len = sys_le16_to_cpu(acl_hdr->len) + hdr_len;
297+
break;
284298
}
299+
case BT_HCI_H4_ISO: {
300+
struct bt_hci_iso_hdr *iso_hdr;
285301

286-
acl_hdr = (struct bt_hci_acl_hdr *)(buf->data + 1);
302+
hdr_len = sizeof(*iso_hdr);
303+
iso_hdr = (struct bt_hci_iso_hdr *)data;
304+
len = bt_iso_hdr_len(sys_le16_to_cpu(iso_hdr->len)) + hdr_len;
305+
break;
306+
}
307+
default:
308+
LOG_ERR("Unknown H4 buffer type");
309+
return 0;
310+
}
287311

288-
return sys_le16_to_cpu(acl_hdr->len) + hdr_len;
312+
return (size < hdr_len) ? 0 : len;
289313
}
290314

291315
static int bt_hci_acl_out_cb(struct usbd_class_data *const c_data,
@@ -305,7 +329,9 @@ static int bt_hci_acl_out_cb(struct usbd_class_data *const c_data,
305329
goto restart_out_transfer;
306330
}
307331

308-
hci_data->acl_len = hci_acl_pkt_len(hci_data->acl_buf);
332+
hci_data->acl_len = hci_pkt_get_len(BT_HCI_H4_ACL,
333+
buf->data,
334+
buf->len);
309335

310336
LOG_DBG("acl_len %u, chunk %u", hci_data->acl_len, buf->len);
311337

@@ -330,7 +356,11 @@ static int bt_hci_acl_out_cb(struct usbd_class_data *const c_data,
330356
LOG_INF("len %u, chunk %u", hci_data->acl_buf->len, buf->len);
331357
}
332358

333-
if (hci_data->acl_buf != NULL && hci_data->acl_len == hci_data->acl_buf->len) {
359+
/*
360+
* The buffer obtained from bt_buf_get_tx() stores the type at the top.
361+
* Take this into account when comparing received data length.
362+
*/
363+
if (hci_data->acl_buf != NULL && hci_data->acl_len == hci_data->acl_buf->len - 1) {
334364
k_fifo_put(&bt_hci_rx_queue, hci_data->acl_buf);
335365
hci_data->acl_buf = NULL;
336366
hci_data->acl_len = 0;

0 commit comments

Comments
 (0)