Skip to content

Commit 1868987

Browse files
patstewcarlescufi
authored andcommitted
Bluetooth: userchan: Support TCP fragmentation of HCI packets
Keep reading from the HCI socket when a packet is incomplete. The other end may not write entire packets, or TCP could fragment in the middle of a packet. Also fix a potential infinite loop by advancing to the next packet before any continue statements. Signed-off-by: Patrick Stewart <[email protected]>
1 parent 74378f3 commit 1868987

File tree

1 file changed

+48
-25
lines changed

1 file changed

+48
-25
lines changed

drivers/bluetooth/hci/userchan.c

Lines changed: 48 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -89,16 +89,18 @@ static struct net_buf *get_rx(const uint8_t *buf)
8989
}
9090

9191
/**
92-
* @brief Decode the length of an HCI H4 packet
92+
* @brief Decode the length of an HCI H4 packet and check it's complete
9393
* @details Decodes packet length according to Bluetooth spec v5.4 Vol 4 Part E
9494
* @param buf Pointer to a HCI packet buffer
95-
* @return Length of the HCI packet in bytes, zero if no valid packet found.
95+
* @param buf_len Bytes available in the buffer
96+
* @return Length of the complete HCI packet in bytes, -1 if cannot find an HCI
97+
* packet, 0 if more data required.
9698
*/
97-
static uint16_t packet_len(const uint8_t *buf)
99+
static int32_t hci_packet_complete(const uint8_t *buf, uint16_t buf_len)
98100
{
99101
uint16_t payload_len = 0;
100-
uint8_t header_len = 0;
101102
const uint8_t type = buf[0];
103+
uint8_t header_len = sizeof(type);
102104
const uint8_t *hdr = &buf[sizeof(type)];
103105

104106
switch (type) {
@@ -107,48 +109,53 @@ static uint16_t packet_len(const uint8_t *buf)
107109

108110
/* Parameter Total Length */
109111
payload_len = cmd->param_len;
110-
header_len = BT_HCI_CMD_HDR_SIZE;
112+
header_len += BT_HCI_CMD_HDR_SIZE;
111113
break;
112114
}
113115
case BT_HCI_H4_ACL: {
114116
const struct bt_hci_acl_hdr *acl = (const struct bt_hci_acl_hdr *)hdr;
115117

116118
/* Data Total Length */
117119
payload_len = sys_le16_to_cpu(acl->len);
118-
header_len = BT_HCI_ACL_HDR_SIZE;
120+
header_len += BT_HCI_ACL_HDR_SIZE;
119121
break;
120122
}
121123
case BT_HCI_H4_SCO: {
122124
const struct bt_hci_sco_hdr *sco = (const struct bt_hci_sco_hdr *)hdr;
123125

124126
/* Data_Total_Length */
125127
payload_len = sco->len;
126-
header_len = BT_HCI_SCO_HDR_SIZE;
128+
header_len += BT_HCI_SCO_HDR_SIZE;
127129
break;
128130
}
129131
case BT_HCI_H4_EVT: {
130132
const struct bt_hci_evt_hdr *evt = (const struct bt_hci_evt_hdr *)hdr;
131133

132134
/* Parameter Total Length */
133135
payload_len = evt->len;
134-
header_len = BT_HCI_EVT_HDR_SIZE;
136+
header_len += BT_HCI_EVT_HDR_SIZE;
135137
break;
136138
}
137139
case BT_HCI_H4_ISO: {
138140
const struct bt_hci_iso_hdr *iso = (const struct bt_hci_iso_hdr *)hdr;
139141

140142
/* ISO_Data_Load_Length parameter */
141143
payload_len = bt_iso_hdr_len(sys_le16_to_cpu(iso->len));
142-
header_len = BT_HCI_ISO_HDR_SIZE;
144+
header_len += BT_HCI_ISO_HDR_SIZE;
143145
break;
144146
}
145147
/* If no valid packet type found */
146148
default:
147149
LOG_WRN("Unknown packet type 0x%02x", type);
150+
return -1;
151+
}
152+
153+
/* Request more data */
154+
if (buf_len < header_len || buf_len - header_len < payload_len) {
148155
return 0;
149156
}
150157

151-
return sizeof(type) + header_len + payload_len;
158+
return (int32_t)header_len + payload_len;
152159
}
153160

154161
static bool uc_ready(void)
@@ -166,6 +173,8 @@ static void rx_thread(void *p1, void *p2, void *p3)
166173

167174
LOG_DBG("started");
168175

176+
uint16_t frame_size = 0;
177+
169178
while (1) {
170179
static uint8_t frame[512];
171180
struct net_buf *buf;
@@ -181,7 +190,7 @@ static void rx_thread(void *p1, void *p2, void *p3)
181190

182191
LOG_DBG("calling read()");
183192

184-
len = read(uc_fd, frame, sizeof(frame));
193+
len = read(uc_fd, frame + frame_size, sizeof(frame) - frame_size);
185194
if (len < 0) {
186195
if (errno == EINTR) {
187196
k_yield();
@@ -194,46 +203,60 @@ static void rx_thread(void *p1, void *p2, void *p3)
194203
return;
195204
}
196205

197-
while (len > 0) {
206+
frame_size += len;
198207

208+
while (frame_size > 0) {
209+
const uint8_t *buf_add;
199210
const uint8_t packet_type = frame_start[0];
200-
const uint16_t decoded_len = packet_len(frame_start);
211+
const int32_t decoded_len = hci_packet_complete(frame_start, frame_size);
201212

202-
if (decoded_len == 0) {
213+
if (decoded_len == -1) {
203214
LOG_ERR("HCI Packet type is invalid, length could not be decoded");
215+
frame_size = 0; /* Drop buffer */
204216
break;
205217
}
206218

207-
if (decoded_len > len) {
208-
LOG_ERR("Decoded HCI packet length (%d bytes) is greater "
209-
"than buffer length (%d bytes)", decoded_len, len);
219+
if (decoded_len == 0) {
220+
if (frame_size == sizeof(frame)) {
221+
LOG_ERR("HCI Packet (%d bytes) is too big for frame (%d "
222+
"bytes)",
223+
decoded_len, sizeof(frame));
224+
frame_size = 0; /* Drop buffer */
225+
break;
226+
}
227+
if (frame_start != frame) {
228+
memmove(frame, frame_start, frame_size);
229+
}
230+
/* Read more */
210231
break;
211232
}
212233

234+
buf_add = frame_start + sizeof(packet_type);
235+
buf_add_len = decoded_len - sizeof(packet_type);
236+
213237
buf = get_rx(frame_start);
238+
239+
frame_size -= decoded_len;
240+
frame_start += decoded_len;
241+
214242
if (!buf) {
215243
LOG_DBG("Discard adv report due to insufficient buf");
216-
goto next;
244+
continue;
217245
}
218246

219247
buf_tailroom = net_buf_tailroom(buf);
220-
buf_add_len = decoded_len - sizeof(packet_type);
221248
if (buf_tailroom < buf_add_len) {
222249
LOG_ERR("Not enough space in buffer %zu/%zu",
223250
buf_add_len, buf_tailroom);
224251
net_buf_unref(buf);
225-
goto next;
252+
continue;
226253
}
227254

228-
net_buf_add_mem(buf, frame_start + sizeof(packet_type), buf_add_len);
255+
net_buf_add_mem(buf, buf_add, buf_add_len);
229256

230257
LOG_DBG("Calling bt_recv(%p)", buf);
231258

232259
bt_recv(buf);
233-
234-
next:
235-
len -= decoded_len;
236-
frame_start += decoded_len;
237260
}
238261

239262
k_yield();

0 commit comments

Comments
 (0)