1 /*
2 * Copyright (c) 2020 Demant
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <zephyr/sys/byteorder.h>
9
10 #include <zephyr/bluetooth/hci_types.h>
11 #include <zephyr/bluetooth/conn.h>
12
13 #include "util/util.h"
14 #include "util/memq.h"
15 #include "util/mayfly.h"
16 #include "util/dbuf.h"
17
18 #include "hal/ccm.h"
19 #include "hal/ticker.h"
20
21 #include "ticker/ticker.h"
22
23 #include "pdu_df.h"
24 #include "lll/pdu_vendor.h"
25 #include "pdu.h"
26
27 #include "lll.h"
28 #include "lll_clock.h"
29 #include "lll/lll_vendor.h"
30 #include "lll/lll_df_types.h"
31 #include "lll_conn.h"
32 #include "lll_conn_iso.h"
33 #include "lll_peripheral_iso.h"
34
35
36 #include "ll_sw/ull_tx_queue.h"
37
38 #include "ull_conn_types.h"
39
40 #include "isoal.h"
41 #include "ull_iso_types.h"
42 #include "ull_conn_iso_types.h"
43
44 #include "ull_llcp.h"
45
46 #include "ull_internal.h"
47 #include "ull_conn_internal.h"
48 #include "ull_conn_iso_internal.h"
49 #include "ull_llcp_internal.h"
50
51 #include "hal/debug.h"
52
53 #define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
54 #include <zephyr/logging/log.h>
55 LOG_MODULE_REGISTER(bt_ctlr_ull_peripheral_iso);
56
ll_cis_get_acl_awaiting_reply(uint16_t handle,uint8_t * error)57 static struct ll_conn *ll_cis_get_acl_awaiting_reply(uint16_t handle, uint8_t *error)
58 {
59 struct ll_conn *acl_conn = NULL;
60
61 if (!IS_CIS_HANDLE(handle) || ll_conn_iso_stream_get(handle)->group == NULL) {
62 LOG_ERR("Unknown CIS handle %u", handle);
63 *error = BT_HCI_ERR_UNKNOWN_CONN_ID;
64 return NULL;
65 }
66
67 for (int h = 0; h < CONFIG_BT_MAX_CONN; h++) {
68 /* Handle h in valid range, hence conn will be non-NULL */
69 struct ll_conn *conn = ll_conn_get(h);
70 uint16_t cis_handle = ull_cp_cc_ongoing_handle(conn);
71
72 if (handle == cis_handle) {
73 /* ACL connection found */
74 acl_conn = conn;
75 break;
76 }
77 }
78
79 if (!acl_conn) {
80 LOG_ERR("No connection found for handle %u", handle);
81 *error = BT_HCI_ERR_CMD_DISALLOWED;
82 return NULL;
83 }
84
85 if (acl_conn->lll.role == BT_CONN_ROLE_CENTRAL) {
86 LOG_ERR("Not allowed for central");
87 *error = BT_HCI_ERR_CMD_DISALLOWED;
88 return NULL;
89 }
90
91 if (!ull_cp_cc_awaiting_reply(acl_conn)) {
92 LOG_ERR("Not allowed in current procedure state");
93 *error = BT_HCI_ERR_CMD_DISALLOWED;
94 return NULL;
95 }
96
97 return acl_conn;
98 }
99
ll_cis_accept(uint16_t handle)100 uint8_t ll_cis_accept(uint16_t handle)
101 {
102 uint8_t status = BT_HCI_ERR_SUCCESS;
103 struct ll_conn *conn = ll_cis_get_acl_awaiting_reply(handle, &status);
104
105 if (conn) {
106 uint32_t cis_offset_min;
107
108 if (IS_ENABLED(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START) ||
109 !IS_ENABLED(CONFIG_BT_CTLR_CIS_ACCEPT_MIN_OFFSET_STRICT)) {
110 /* Early start allows offset down to spec defined minimum */
111 cis_offset_min = CIS_MIN_OFFSET_MIN;
112 } else {
113 cis_offset_min = HAL_TICKER_TICKS_TO_US(conn->ull.ticks_slot) +
114 (EVENT_TICKER_RES_MARGIN_US << 1U);
115
116 if (!IS_ENABLED(CONFIG_BT_CTLR_EVENT_OVERHEAD_RESERVE_MAX)) {
117 cis_offset_min += EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
118 }
119 }
120
121 /* Accept request */
122 ull_cp_cc_accept(conn, cis_offset_min);
123 }
124
125 return status;
126 }
127
ll_cis_reject(uint16_t handle,uint8_t reason)128 uint8_t ll_cis_reject(uint16_t handle, uint8_t reason)
129 {
130 uint8_t status = BT_HCI_ERR_SUCCESS;
131 struct ll_conn *acl_conn = ll_cis_get_acl_awaiting_reply(handle, &status);
132
133 if (acl_conn) {
134 /* Reject request */
135 ull_cp_cc_reject(acl_conn, reason);
136 }
137
138 return status;
139 }
140
ull_peripheral_iso_init(void)141 int ull_peripheral_iso_init(void)
142 {
143 return 0;
144 }
145
ull_peripheral_iso_reset(void)146 int ull_peripheral_iso_reset(void)
147 {
148 return 0;
149 }
150
151 /* Use this function to release CIS/CIG resources on an aborted CIS setup
152 * ie if CIS setup is 'cancelled' after call to ull_peripheral_iso_acquire()
153 * because of a rejection of the CIS request
154 */
ull_peripheral_iso_release(uint16_t cis_handle)155 void ull_peripheral_iso_release(uint16_t cis_handle)
156 {
157 struct ll_conn_iso_stream *cis;
158 struct ll_conn_iso_group *cig;
159
160 cis = ll_conn_iso_stream_get(cis_handle);
161 LL_ASSERT(cis);
162
163 cig = cis->group;
164
165 ll_conn_iso_stream_release(cis);
166 cig->lll.num_cis--;
167
168 if (!cig->lll.num_cis) {
169 ll_conn_iso_group_release(cig);
170 }
171 }
172
ull_peripheral_iso_acquire(struct ll_conn * acl,struct pdu_data_llctrl_cis_req * req,uint16_t * cis_handle)173 uint8_t ull_peripheral_iso_acquire(struct ll_conn *acl,
174 struct pdu_data_llctrl_cis_req *req,
175 uint16_t *cis_handle)
176 {
177 struct ll_conn_iso_group *cig;
178 struct ll_conn_iso_stream *cis;
179 uint32_t iso_interval_us;
180 uint16_t handle;
181
182 /* Get CIG by id */
183 cig = ll_conn_iso_group_get_by_id(req->cig_id);
184 if (!cig) {
185 /* CIG does not exist - create it */
186 cig = ll_conn_iso_group_acquire();
187 if (!cig) {
188 /* No space for new CIG */
189 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
190 }
191
192 memset(&cig->lll, 0, sizeof(cig->lll));
193
194 cig->iso_interval = sys_le16_to_cpu(req->iso_interval);
195 iso_interval_us = cig->iso_interval * CONN_INT_UNIT_US;
196 cig->lll.iso_interval_us = iso_interval_us;
197
198 cig->cig_id = req->cig_id;
199 cig->lll.handle = LLL_HANDLE_INVALID;
200 cig->lll.role = acl->lll.role;
201 cig->lll.resume_cis = LLL_HANDLE_INVALID;
202
203 /* Calculate CIG default maximum window widening. NOTE: This calculation
204 * does not take into account that leading CIS with NSE>=3 must reduce
205 * the maximum window widening to one sub-interval. This must be applied
206 * in LLL (BT Core 5.3, Vol 6, Part B, section 4.2.4).
207 */
208 cig->lll.window_widening_max_us = (iso_interval_us >> 1) -
209 EVENT_IFS_US;
210 cig->lll.window_widening_periodic_us_frac =
211 DIV_ROUND_UP(((lll_clock_ppm_local_get() +
212 lll_clock_ppm_get(acl->periph.sca)) *
213 EVENT_US_TO_US_FRAC(iso_interval_us)), USEC_PER_SEC);
214
215 lll_hdr_init(&cig->lll, cig);
216 }
217
218 if (cig->lll.num_cis == CONFIG_BT_CTLR_CONN_ISO_STREAMS_PER_GROUP) {
219 /* No space in CIG for new CIS */
220 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
221 }
222
223 for (handle = LL_CIS_HANDLE_BASE; handle <= LL_CIS_HANDLE_LAST;
224 handle++) {
225 cis = ll_iso_stream_connected_get(handle);
226 if (cis && cis->group && cis->cis_id == req->cis_id) {
227 /* CIS ID already in use */
228 return BT_HCI_ERR_INVALID_LL_PARAM;
229 }
230 }
231
232 /* Acquire new CIS */
233 cis = ll_conn_iso_stream_acquire();
234 if (cis == NULL) {
235 if (!cig->lll.num_cis) {
236 /* No CIS's in CIG, so this was just allocated
237 * so release as we can't use it
238 */
239 ll_conn_iso_group_release(cig);
240 }
241 /* No space for new CIS */
242 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
243 }
244
245 /* Read 20-bit SDU intervals (mask away RFU bits) */
246 cig->c_sdu_interval = sys_get_le24(req->c_sdu_interval) & 0x0FFFFF;
247 cig->p_sdu_interval = sys_get_le24(req->p_sdu_interval) & 0x0FFFFF;
248
249 cis->cis_id = req->cis_id;
250 cis->framed = (req->c_max_sdu_packed[1] & BIT(7)) >> 7;
251 cis->established = 0;
252 cis->group = cig;
253 cis->teardown = 0;
254 cis->released_cb = NULL;
255 cis->c_max_sdu = (uint16_t)(req->c_max_sdu_packed[1] & 0x0F) << 8 |
256 req->c_max_sdu_packed[0];
257 cis->p_max_sdu = (uint16_t)(req->p_max_sdu[1] & 0x0F) << 8 |
258 req->p_max_sdu[0];
259
260 cis->lll.active = 0U;
261
262 #if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
263 cis->lll.prepared = 0U;
264 #endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
265
266 cis->lll.handle = LLL_HANDLE_INVALID;
267 cis->lll.acl_handle = acl->lll.handle;
268 cis->lll.sub_interval = sys_get_le24(req->sub_interval);
269 cis->lll.nse = req->nse;
270
271 cis->lll.rx.phy = req->c_phy;
272 cis->lll.rx.phy_flags = PHY_FLAGS_S8;
273 cis->lll.rx.bn = req->c_bn;
274 cis->lll.rx.ft = req->c_ft;
275 cis->lll.rx.max_pdu = sys_le16_to_cpu(req->c_max_pdu);
276
277 cis->lll.tx.phy = req->p_phy;
278 cis->lll.tx.phy_flags = PHY_FLAGS_S8;
279 cis->lll.tx.bn = req->p_bn;
280 cis->lll.tx.ft = req->p_ft;
281 cis->lll.tx.max_pdu = sys_le16_to_cpu(req->p_max_pdu);
282
283 if (!cis->lll.link_tx_free) {
284 cis->lll.link_tx_free = &cis->lll.link_tx;
285 }
286
287 memq_init(cis->lll.link_tx_free, &cis->lll.memq_tx.head,
288 &cis->lll.memq_tx.tail);
289 cis->lll.link_tx_free = NULL;
290
291 *cis_handle = ll_conn_iso_stream_handle_get(cis);
292 cig->lll.num_cis++;
293
294 return 0;
295 }
296
ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind * ind,uint8_t cig_id,uint16_t cis_handle,uint16_t * conn_event_count)297 uint8_t ull_peripheral_iso_setup(struct pdu_data_llctrl_cis_ind *ind,
298 uint8_t cig_id, uint16_t cis_handle,
299 uint16_t *conn_event_count)
300 {
301 struct ll_conn_iso_stream *cis = NULL;
302 struct ll_conn_iso_group *cig;
303 struct ll_conn *conn;
304 uint32_t cis_offset;
305
306 /* Get CIG by id */
307 cig = ll_conn_iso_group_get_by_id(cig_id);
308 if (!cig) {
309 return BT_HCI_ERR_UNSPECIFIED;
310 }
311
312 cig->lll.handle = ll_conn_iso_group_handle_get(cig);
313 cig->sync_delay = sys_get_le24(ind->cig_sync_delay);
314
315 cis = ll_conn_iso_stream_get(cis_handle);
316 if (!cis) {
317 return BT_HCI_ERR_UNSPECIFIED;
318 }
319
320 conn = ll_conn_get(cis->lll.acl_handle);
321 LL_ASSERT(conn != NULL);
322
323 cis_offset = sys_get_le24(ind->cis_offset);
324
325 #if defined(CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START)
326 if (cig->state != CIG_STATE_ACTIVE) {
327 /* This is the first CIS. Make sure we can make the anchorpoint, otherwise
328 * we need to move up the instant up by one connection interval.
329 */
330 if (cis_offset < EVENT_OVERHEAD_START_US) {
331 /* Start one connection event earlier */
332 (*conn_event_count)--;
333 }
334 }
335 #endif /* CONFIG_BT_CTLR_PERIPHERAL_ISO_EARLY_CIG_START */
336
337 cis->sync_delay = sys_get_le24(ind->cis_sync_delay);
338 cis->offset = cis_offset;
339 memcpy(cis->lll.access_addr, ind->aa, sizeof(ind->aa));
340 #if defined(CONFIG_BT_CTLR_ISOAL_PSN_IGNORE)
341 cis->pkt_seq_num = 0U;
342 #endif /* CONFIG_BT_CTLR_ISOAL_PSN_IGNORE */
343 /* It is intentional to initialize to the 39 bit maximum value and rollover to 0 in the
344 * prepare function, the event counter is pre-incremented in prepare function for the
345 * current ISO event.
346 */
347 cis->lll.event_count_prepare = LLL_CONN_ISO_EVENT_COUNT_MAX;
348 cis->lll.event_count = LLL_CONN_ISO_EVENT_COUNT_MAX;
349 cis->lll.next_subevent = 0U;
350 cis->lll.tifs_us = conn->lll.tifs_cis_us;
351 cis->lll.sn = 0U;
352 cis->lll.nesn = 0U;
353 cis->lll.cie = 0U;
354 cis->lll.npi = 0U;
355 cis->lll.flush = LLL_CIS_FLUSH_NONE;
356 cis->lll.datapath_ready_rx = 0U;
357 cis->lll.tx.payload_count = 0U;
358 cis->lll.rx.payload_count = 0U;
359 cis->lll.rx.bn_curr = 1U;
360 cis->lll.tx.bn_curr = 1U;
361
362 return 0;
363 }
364
ticker_op_cb(uint32_t status,void * param)365 static void ticker_op_cb(uint32_t status, void *param)
366 {
367 ARG_UNUSED(param);
368
369 LL_ASSERT(status == TICKER_STATUS_SUCCESS);
370 }
371
ull_peripheral_iso_update_ticker(struct ll_conn_iso_group * cig,uint32_t ticks_at_expire,uint32_t iso_interval_us_frac)372 void ull_peripheral_iso_update_ticker(struct ll_conn_iso_group *cig,
373 uint32_t ticks_at_expire,
374 uint32_t iso_interval_us_frac)
375 {
376
377 /* stop/start with new updated timings */
378 uint8_t ticker_id_cig = TICKER_ID_CONN_ISO_BASE + ll_conn_iso_group_handle_get(cig);
379 uint32_t ticker_status = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH,
380 ticker_id_cig, ticker_op_cb, NULL);
381 LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
382 (ticker_status == TICKER_STATUS_BUSY));
383
384 ticker_status = ticker_start(TICKER_INSTANCE_ID_CTLR,
385 TICKER_USER_ID_ULL_HIGH,
386 ticker_id_cig,
387 ticks_at_expire,
388 EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac),
389 EVENT_US_FRAC_TO_TICKS(iso_interval_us_frac),
390 EVENT_US_FRAC_TO_REMAINDER(iso_interval_us_frac),
391 TICKER_NULL_LAZY,
392 0,
393 ull_conn_iso_ticker_cb, cig,
394 ticker_op_cb, NULL);
395
396 LL_ASSERT((ticker_status == TICKER_STATUS_SUCCESS) ||
397 (ticker_status == TICKER_STATUS_BUSY));
398
399 }
400
ull_peripheral_iso_update_peer_sca(struct ll_conn * acl)401 void ull_peripheral_iso_update_peer_sca(struct ll_conn *acl)
402 {
403 uint8_t cig_handle;
404
405 /* Find CIG associated with ACL conn */
406 for (cig_handle = 0; cig_handle < CONFIG_BT_CTLR_CONN_ISO_GROUPS; cig_handle++) {
407 /* Go through all ACL affiliated CIGs and update peer SCA */
408 struct ll_conn_iso_stream *cis;
409 struct ll_conn_iso_group *cig;
410
411 cig = ll_conn_iso_group_get(cig_handle);
412 if (!cig || !cig->lll.num_cis) {
413 continue;
414 }
415 cis = ll_conn_iso_stream_get_by_group(cig, NULL);
416 LL_ASSERT(cis);
417
418 uint16_t cis_handle = cis->lll.handle;
419
420 cis = ll_iso_stream_connected_get(cis_handle);
421 if (!cis) {
422 continue;
423 }
424
425 if (cis->lll.acl_handle == acl->lll.handle) {
426 cig->sca_update = acl->periph.sca + 1;
427 }
428 }
429 }
430