1 /*
2 * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 /*
7 * Licensed to the Apache Software Foundation (ASF) under one
8 * or more contributor license agreements. See the NOTICE file
9 * distributed with this work for additional information
10 * regarding copyright ownership. The ASF licenses this file
11 * to you under the Apache License, Version 2.0 (the
12 * "License"); you may not use this file except in compliance
13 * with the License. You may obtain a copy of the License at
14 *
15 * http://www.apache.org/licenses/LICENSE-2.0
16 *
17 * Unless required by applicable law or agreed to in writing,
18 * software distributed under the License is distributed on an
19 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
20 * KIND, either express or implied. See the License for the
21 * specific language governing permissions and limitations
22 * under the License.
23 */
24
25 #include <assert.h>
26 #include <stdint.h>
27 #include <string.h>
28 #include <os/os.h>
29 #include <os/os_mbuf.h>
30 #include "common/hci_driver_h4.h"
31
32 #ifndef min
33 #define min(a, b) ((a) < (b) ? (a) : (b))
34 #endif
35
36 #ifndef max
37 #define max(a, b) ((a) > (b) ? (a) : (b))
38 #endif
39
40 #define HCI_H4_SM_W4_PKT_TYPE 0
41 #define HCI_H4_SM_W4_HEADER 1
42 #define HCI_H4_SM_W4_PAYLOAD 2
43 #define HCI_H4_SM_COMPLETED 3
44
45 struct hci_h4_input_buffer {
46 const uint8_t *buf;
47 uint16_t len;
48 };
49
50 static int
hci_h4_frame_start(struct hci_h4_sm * rxs,uint8_t pkt_type)51 hci_h4_frame_start(struct hci_h4_sm *rxs, uint8_t pkt_type)
52 {
53 rxs->pkt_type = pkt_type;
54 rxs->len = 0;
55 rxs->exp_len = 0;
56
57 switch (rxs->pkt_type) {
58 case HCI_H4_CMD:
59 rxs->min_len = 3;
60 break;
61 case HCI_H4_ACL:
62 case HCI_H4_ISO:
63 rxs->min_len = 4;
64 break;
65 case HCI_H4_EVT:
66 rxs->min_len = 2;
67 break;
68 default:
69 /* !TODO: Sync loss. Need to wait for reset. */
70 return -1;
71 }
72
73 return 0;
74 }
75
76 static int
hci_h4_ib_consume(struct hci_h4_input_buffer * ib,uint16_t len)77 hci_h4_ib_consume(struct hci_h4_input_buffer *ib, uint16_t len)
78 {
79 assert(ib->len >= len);
80
81 ib->buf += len;
82 ib->len -= len;
83
84 return len;
85 }
86
87 static int
hci_h4_ib_pull_min_len(struct hci_h4_sm * rxs,struct hci_h4_input_buffer * ib)88 hci_h4_ib_pull_min_len(struct hci_h4_sm *rxs,
89 struct hci_h4_input_buffer *ib)
90 {
91 uint16_t len;
92
93 len = min(ib->len, rxs->min_len - rxs->len);
94 memcpy(&rxs->hdr[rxs->len], ib->buf, len);
95
96 rxs->len += len;
97 hci_h4_ib_consume(ib, len);
98
99
100 return rxs->len != rxs->min_len;
101 }
102
103 static int
hci_h4_sm_w4_header(struct hci_h4_sm * h4sm,struct hci_h4_input_buffer * ib)104 hci_h4_sm_w4_header(struct hci_h4_sm *h4sm, struct hci_h4_input_buffer *ib)
105 {
106 int rc;
107
108 rc = hci_h4_ib_pull_min_len(h4sm, ib);
109 if (rc) {
110 /* need more data */
111 return 1;
112 }
113
114 switch (h4sm->pkt_type) {
115 case HCI_H4_CMD:
116 assert(h4sm->allocs && h4sm->allocs->cmd);
117 h4sm->buf = h4sm->allocs->cmd();
118 if (!h4sm->buf) {
119 return -1;
120 }
121
122 memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
123 h4sm->exp_len = h4sm->hdr[2] + 3;
124
125 break;
126 case HCI_H4_ACL:
127 assert(h4sm->allocs && h4sm->allocs->acl);
128 h4sm->om = h4sm->allocs->acl();
129 if (!h4sm->om) {
130 return -1;
131 }
132
133 os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len);
134 h4sm->exp_len = get_le16(&h4sm->hdr[2]) + 4;
135 break;
136 #if !CONFIG_BT_CONTROLLER_ENABLED
137 case HCI_H4_EVT:
138 if (h4sm->hdr[0] == BLE_HCI_EVCODE_LE_META) {
139 /* For LE Meta event we need 3 bytes to parse header */
140 h4sm->min_len = 3;
141 rc = hci_h4_ib_pull_min_len(h4sm, ib);
142 if (rc) {
143 /* need more data */
144 return 1;
145 }
146 }
147
148 assert(h4sm->allocs && h4sm->allocs->evt);
149
150 /* We can drop legacy advertising events if there's no free buffer in
151 * discardable pool.
152 */
153 if (h4sm->hdr[2] == BLE_HCI_LE_SUBEV_ADV_RPT) {
154 h4sm->buf = h4sm->allocs->evt(1);
155 } else {
156 h4sm->buf = h4sm->allocs->evt(0);
157 if (!h4sm->buf) {
158 return -1;
159 }
160 }
161
162 if (h4sm->buf) {
163 memcpy(h4sm->buf, h4sm->hdr, h4sm->len);
164 }
165
166 h4sm->exp_len = h4sm->hdr[1] + 2;
167 break;
168 #endif // !CONFIG_BT_CONTROLLER_ENABLED
169 case HCI_H4_ISO:
170 assert(h4sm->allocs && h4sm->allocs->iso);
171 h4sm->om = h4sm->allocs->iso();
172 if (!h4sm->om) {
173 return -1;
174 }
175
176 os_mbuf_append(h4sm->om, h4sm->hdr, h4sm->len);
177 h4sm->exp_len = (get_le16(&h4sm->hdr[2]) & 0x7fff) + 4;
178 break;
179 default:
180 assert(0);
181 break;
182 }
183
184 return 0;
185 }
186
187 static int
hci_h4_sm_w4_payload(struct hci_h4_sm * h4sm,struct hci_h4_input_buffer * ib)188 hci_h4_sm_w4_payload(struct hci_h4_sm *h4sm,
189 struct hci_h4_input_buffer *ib)
190 {
191 uint16_t mbuf_len;
192 uint16_t len;
193 int rc;
194
195 len = min(ib->len, h4sm->exp_len - h4sm->len);
196
197
198 switch (h4sm->pkt_type) {
199 case HCI_H4_CMD:
200 case HCI_H4_EVT:
201 if (h4sm->buf) {
202 memcpy(&h4sm->buf[h4sm->len], ib->buf, len);
203 }
204 break;
205 case HCI_H4_ACL:
206 case HCI_H4_ISO:
207 assert(h4sm->om);
208
209 mbuf_len = OS_MBUF_PKTLEN(h4sm->om);
210 rc = os_mbuf_append(h4sm->om, ib->buf, len);
211 if (rc) {
212 /* Some data may already be appended so need to adjust h4sm only by
213 * the size of appended data.
214 */
215 len = OS_MBUF_PKTLEN(h4sm->om) - mbuf_len;
216 h4sm->len += len;
217 hci_h4_ib_consume(ib, len);
218
219 return -1;
220 }
221 break;
222 default:
223 assert(0);
224 break;
225 }
226
227 h4sm->len += len;
228 hci_h4_ib_consume(ib, len);
229
230 /* return 1 if need more data */
231 return h4sm->len != h4sm->exp_len;
232 }
233
234 static void
hci_h4_sm_completed(struct hci_h4_sm * h4sm)235 hci_h4_sm_completed(struct hci_h4_sm *h4sm)
236 {
237 int rc;
238
239 switch (h4sm->pkt_type) {
240 #if CONFIG_BT_CONTROLLER_ENABLED
241 case HCI_H4_CMD:
242 if (h4sm->buf) {
243 assert(h4sm->frame_cb);
244 rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf);
245 assert(rc == 0);
246 h4sm->buf = NULL;
247 }
248 break;
249 case HCI_H4_ACL:
250 case HCI_H4_ISO:
251 if (h4sm->om) {
252 assert(h4sm->frame_cb);
253 rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om);
254 assert(rc == 0);
255 h4sm->om = NULL;
256 }
257 break;
258 #else
259 case HCI_H4_CMD:
260 case HCI_H4_EVT:
261 if (h4sm->buf) {
262 assert(h4sm->frame_cb);
263 rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->buf);
264 if (rc != 0) {
265 ble_transport_free(h4sm->buf);
266 }
267 h4sm->buf = NULL;
268 }
269 break;
270 case HCI_H4_ACL:
271 case HCI_H4_ISO:
272 if (h4sm->om) {
273 assert(h4sm->frame_cb);
274 rc = h4sm->frame_cb(h4sm->pkt_type, h4sm->om);
275 if (rc != 0) {
276 os_mbuf_free_chain(h4sm->om);
277 }
278 h4sm->om = NULL;
279 }
280 break;
281 #endif // CONFIG_BT_CONTROLLER_ENABLED
282 default:
283 assert(0);
284 break;
285 }
286 }
287
288 int
hci_h4_sm_rx(struct hci_h4_sm * h4sm,const uint8_t * buf,uint16_t len)289 hci_h4_sm_rx(struct hci_h4_sm *h4sm, const uint8_t *buf, uint16_t len)
290 {
291 struct hci_h4_input_buffer ib = {
292 .buf = buf,
293 .len = len,
294 };
295
296 int rc = 0;
297 while (ib.len && (rc >= 0)) {
298 rc = 0;
299 switch (h4sm->state) {
300 case HCI_H4_SM_W4_PKT_TYPE:
301 if (hci_h4_frame_start(h4sm, ib.buf[0]) < 0) {
302 return -1;
303 }
304
305 hci_h4_ib_consume(&ib, 1);
306 h4sm->state = HCI_H4_SM_W4_HEADER;
307 /* no break */
308 case HCI_H4_SM_W4_HEADER:
309 rc = hci_h4_sm_w4_header(h4sm, &ib);
310 assert(rc >= 0);
311 if (rc) {
312 break;
313 }
314 h4sm->state = HCI_H4_SM_W4_PAYLOAD;
315 /* no break */
316 case HCI_H4_SM_W4_PAYLOAD:
317 rc = hci_h4_sm_w4_payload(h4sm, &ib);
318 assert(rc >= 0);
319 if (rc) {
320 break;
321 }
322 h4sm->state = HCI_H4_SM_COMPLETED;
323 /* no break */
324 case HCI_H4_SM_COMPLETED:
325 hci_h4_sm_completed(h4sm);
326 h4sm->state = HCI_H4_SM_W4_PKT_TYPE;
327 break;
328 default:
329 return -1;
330 }
331 }
332
333 /* Calculate consumed bytes
334 *
335 * Note: we should always consume some bytes unless there is an oom error.
336 * It's also possible that we have an oom error but already consumed some
337 * data, in such case just return success and error will be returned on next
338 * pass.
339 */
340 len = len - ib.len;
341 if (len == 0) {
342 assert(rc < 0);
343 return -1;
344 }
345
346 return len;
347 }
348
349 void
hci_h4_sm_init(struct hci_h4_sm * h4sm,const struct hci_h4_allocators * allocs,hci_h4_frame_cb * frame_cb)350 hci_h4_sm_init(struct hci_h4_sm *h4sm, const struct hci_h4_allocators *allocs,
351 hci_h4_frame_cb *frame_cb)
352 {
353 memset(h4sm, 0, sizeof(*h4sm));
354 h4sm->allocs = allocs;
355 h4sm->frame_cb = frame_cb;
356 }
357