1 /*
2 * Copyright (c) 2017-2021 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr/kernel.h>
8 #include <soc.h>
9 #include <zephyr/bluetooth/hci_types.h>
10 #include <zephyr/sys/byteorder.h>
11
12 #include "hal/cpu.h"
13 #include "hal/ccm.h"
14 #include "hal/ticker.h"
15
16 #include "util/util.h"
17 #include "util/mem.h"
18 #include "util/memq.h"
19 #include "util/mayfly.h"
20 #include "util/dbuf.h"
21
22 #include "ticker/ticker.h"
23
24 #include "pdu_df.h"
25 #include "lll/pdu_vendor.h"
26 #include "pdu.h"
27
28 #include "lll.h"
29 #include "lll_clock.h"
30 #include "lll/lll_vendor.h"
31 #include "lll/lll_adv_types.h"
32 #include "lll_adv.h"
33 #include "lll/lll_adv_pdu.h"
34 #include "lll_adv_sync.h"
35 #include "lll/lll_df_types.h"
36 #include "lll_conn.h"
37 #include "lll_chan.h"
38
39 #include "ull_adv_types.h"
40
41 #include "ull_internal.h"
42 #include "ull_chan_internal.h"
43 #include "ull_sched_internal.h"
44 #include "ull_adv_internal.h"
45
46 #include "ll.h"
47
48 #include "hal/debug.h"
49
50 static int init_reset(void);
51 static uint8_t adv_type_check(struct ll_adv_set *adv);
52 static inline struct ll_adv_sync_set *sync_acquire(void);
53 static inline void sync_release(struct ll_adv_sync_set *sync);
54 static inline uint16_t sync_handle_get(const struct ll_adv_sync_set *sync);
55 static uint32_t sync_time_get(const struct ll_adv_sync_set *sync,
56 const struct pdu_adv *pdu);
57 static inline uint8_t sync_remove(struct ll_adv_sync_set *sync,
58 struct ll_adv_set *adv, uint8_t enable);
59 static uint8_t sync_chm_update(uint8_t handle);
60
61 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
62 static void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs);
63
64 #else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
65 static void mfy_sync_offset_get(void *param);
66 static void sync_info_offset_fill(struct pdu_adv_sync_info *si,
67 uint32_t ticks_offset,
68 uint32_t remainder_us,
69 uint32_t start_us);
70 static void ticker_op_cb(uint32_t status, void *param);
71 #endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
72
73 static struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu);
74 static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
75 uint32_t remainder, uint16_t lazy, uint8_t force,
76 void *param);
77
78 #if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
79 static void ticker_update_op_cb(uint32_t status, void *param);
80
81 static struct ticker_ext ll_adv_sync_ticker_ext[CONFIG_BT_CTLR_ADV_SYNC_SET];
82 #endif /* !CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
83
84 static struct ll_adv_sync_set ll_adv_sync_pool[CONFIG_BT_CTLR_ADV_SYNC_SET];
85 static void *adv_sync_free;
86
ll_adv_sync_param_set(uint8_t handle,uint16_t interval,uint16_t flags)87 uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
88 {
89 void *extra_data_prev, *extra_data;
90 struct pdu_adv *pdu_prev, *pdu;
91 struct lll_adv_sync *lll_sync;
92 struct ll_adv_sync_set *sync;
93 struct ll_adv_set *adv;
94 uint8_t err, ter_idx;
95
96 adv = ull_adv_is_created_get(handle);
97 if (!adv) {
98 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
99 }
100
101 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) {
102 uint8_t err;
103
104 err = adv_type_check(adv);
105 if (err) {
106 return err;
107 }
108 }
109
110 lll_sync = adv->lll.sync;
111 if (!lll_sync) {
112 struct pdu_adv *ter_pdu;
113 struct lll_adv *lll;
114 uint8_t chm_last;
115 int err;
116
117 sync = sync_acquire();
118 if (!sync) {
119 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
120 }
121
122 lll = &adv->lll;
123 lll_sync = &sync->lll;
124 lll->sync = lll_sync;
125 lll_sync->adv = lll;
126
127 lll_adv_data_reset(&lll_sync->data);
128 err = lll_adv_sync_data_init(&lll_sync->data);
129 if (err) {
130 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
131 }
132
133 /* NOTE: ull_hdr_init(&sync->ull); is done on start */
134 lll_hdr_init(lll_sync, sync);
135
136 err = util_aa_le32(lll_sync->access_addr);
137 LL_ASSERT(!err);
138
139 lll_sync->data_chan_id = lll_chan_id(lll_sync->access_addr);
140 chm_last = lll_sync->chm_first;
141 lll_sync->chm_last = chm_last;
142 lll_sync->chm[chm_last].data_chan_count =
143 ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map);
144
145 lll_csrand_get(lll_sync->crc_init, sizeof(lll_sync->crc_init));
146
147 lll_sync->latency_prepare = 0;
148 lll_sync->latency_event = 0;
149 lll_sync->event_counter = 0;
150
151 sync->is_enabled = 0U;
152 sync->is_started = 0U;
153
154 ter_pdu = lll_adv_sync_data_peek(lll_sync, NULL);
155 ull_adv_sync_pdu_init(ter_pdu, 0U, 0U, 0U, NULL);
156 } else {
157 sync = HDR_LLL2ULL(lll_sync);
158 }
159
160 /* Periodic Advertising is already started */
161 if (sync->is_started) {
162 return BT_HCI_ERR_CMD_DISALLOWED;
163 }
164
165 sync->interval = interval;
166
167 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST, &pdu_prev, &pdu,
168 &extra_data_prev, &extra_data, &ter_idx);
169 if (err) {
170 return err;
171 }
172
173 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
174 if (extra_data) {
175 ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data,
176 0U, 0U, NULL);
177 }
178 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
179
180 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
181 /* Duplicate chain PDUs */
182 do {
183 struct pdu_adv *pdu_chain;
184
185 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
186 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
187 0U, 0U, NULL);
188 if (err) {
189 return err;
190 }
191
192 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
193 pdu_prev = lll_adv_pdu_linked_next_get(pdu_prev);
194 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
195
196 /* Allocate new chain PDU if required */
197 if (pdu_prev) {
198 /* Prior PDU chain allocation valid */
199 if (pdu_chain) {
200 pdu = pdu_chain;
201
202 continue;
203 }
204
205 /* Get a new chain PDU */
206 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
207 if (!pdu_chain) {
208 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
209 }
210
211 /* Link the chain PDU to parent PDU */
212 lll_adv_pdu_linked_append(pdu_chain, pdu);
213
214 /* continue back to update the new PDU */
215 pdu = pdu_chain;
216 }
217 } while (pdu_prev);
218 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
219
220 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
221
222 sync->is_data_cmplt = 1U;
223
224 return 0;
225 }
226
227 #if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
ull_adv_iso_created(struct ll_adv_sync_set * sync)228 void ull_adv_iso_created(struct ll_adv_sync_set *sync)
229 {
230 if (sync->lll.iso && sync->is_started) {
231 uint8_t iso_handle = sync->lll.iso->handle;
232 uint8_t handle = sync_handle_get(sync);
233
234 ticker_update_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
235 (TICKER_ID_ADV_SYNC_BASE + handle), 0, 0, 0, 0, 0, 0,
236 ticker_update_op_cb, sync, 0, TICKER_ID_ADV_ISO_BASE + iso_handle);
237 }
238 }
239 #endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
240
ll_adv_sync_ad_data_set(uint8_t handle,uint8_t op,uint8_t len,uint8_t const * const data)241 uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len,
242 uint8_t const *const data)
243 {
244 uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
245 ULL_ADV_HDR_DATA_DATA_PTR_SIZE +
246 ULL_ADV_HDR_DATA_LEN_SIZE +
247 ULL_ADV_HDR_DATA_AUX_PTR_PTR_SIZE +
248 ULL_ADV_HDR_DATA_LEN_SIZE];
249 void *extra_data_prev, *extra_data;
250 struct pdu_adv *pdu_prev, *pdu;
251 struct lll_adv_sync *lll_sync;
252 struct ll_adv_sync_set *sync;
253 struct ll_adv_set *adv;
254 uint8_t *val_ptr;
255 uint8_t ter_idx;
256 uint8_t err;
257
258 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
259 uint8_t ad_len_overflow;
260 uint8_t ad_len_chain;
261 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
262
263 /* Check for valid advertising set */
264 adv = ull_adv_is_created_get(handle);
265 if (!adv) {
266 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
267 }
268
269 /* Check for advertising set type */
270 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) {
271 uint8_t err;
272
273 err = adv_type_check(adv);
274 if (err) {
275 return err;
276 }
277 }
278
279 /* Check if periodic advertising is associated with advertising set */
280 lll_sync = adv->lll.sync;
281 if (!lll_sync) {
282 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
283 }
284
285 sync = HDR_LLL2ULL(lll_sync);
286
287 /* Reject setting fragment when periodic advertising is enabled */
288 if (sync->is_enabled && (op <= BT_HCI_LE_EXT_ADV_OP_LAST_FRAG)) {
289 return BT_HCI_ERR_CMD_DISALLOWED;
290 }
291
292 /* Reject intermediate op before first op */
293 if (sync->is_data_cmplt &&
294 ((op == BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG) ||
295 (op == BT_HCI_LE_EXT_ADV_OP_LAST_FRAG))) {
296 return BT_HCI_ERR_CMD_DISALLOWED;
297 }
298
299 /* Reject unchanged op before complete status */
300 if (!sync->is_data_cmplt &&
301 (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA)) {
302 return BT_HCI_ERR_CMD_DISALLOWED;
303 }
304
305 /* Reject first, intermediate, last operation and len > 191 bytes if
306 * chain PDUs unsupported.
307 */
308 if (!IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) &&
309 ((op < BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA) ||
310 (len > PDU_AC_EXT_AD_DATA_LEN_MAX))) {
311 return BT_HCI_ERR_CMD_DISALLOWED;
312 }
313
314 /* Allocate new PDU buffer at latest double buffer index */
315 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
316 &pdu_prev, &pdu, &extra_data_prev,
317 &extra_data, &ter_idx);
318 if (err) {
319 return err;
320 }
321
322 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
323 if (extra_data) {
324 ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data,
325 0U, 0U, NULL);
326 }
327 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
328
329 /* Prepare the AD data as parameter to update in PDU */
330 /* Use length = 0 and NULL pointer to retain old data in the PDU.
331 * Use length = 0 and valid pointer of `data` (auto/local variable) to
332 * remove old data.
333 * User length > 0 and valid pointer of `data` (auto/local variable) to
334 * set new data.
335 */
336 val_ptr = hdr_data;
337 if (op == BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG ||
338 op == BT_HCI_LE_EXT_ADV_OP_LAST_FRAG ||
339 op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA) {
340 *val_ptr++ = 0U;
341 (void)memset((void *)val_ptr, 0U,
342 ULL_ADV_HDR_DATA_DATA_PTR_SIZE);
343 } else {
344 *val_ptr++ = len;
345 (void)memcpy(val_ptr, &data, sizeof(data));
346 }
347
348 if (!IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) ||
349 (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA)) {
350 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
351 ULL_ADV_PDU_HDR_FIELD_AD_DATA,
352 0U, hdr_data);
353 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
354 /* No AD data overflow */
355 ad_len_overflow = 0U;
356 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
357 } else if (!IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) ||
358 (op == BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG ||
359 op == BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA)) {
360 /* Add AD Data and remove any prior presence of Aux Ptr */
361 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
362 ULL_ADV_PDU_HDR_FIELD_AD_DATA,
363 ULL_ADV_PDU_HDR_FIELD_AUX_PTR,
364 hdr_data);
365 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
366 if (!err) {
367 /* Fragment into chain PDU if len > 191 bytes */
368 if (len > PDU_AC_EXT_AD_DATA_LEN_MAX) {
369 /* Prepare the AD data as parameter to update in
370 * PDU
371 */
372 val_ptr = hdr_data;
373 *val_ptr++ = PDU_AC_EXT_AD_DATA_LEN_MAX;
374 (void)memcpy(val_ptr, &data, sizeof(data));
375
376 /* Traverse to next set clear hdr data
377 * parameter, as aux ptr reference to be
378 * returned, hence second parameter will be for
379 * AD data field.
380 */
381 val_ptr += sizeof(data);
382
383 *val_ptr = PDU_AC_EXT_AD_DATA_LEN_MAX;
384 (void)memcpy(&val_ptr[ULL_ADV_HDR_DATA_DATA_PTR_OFFSET],
385 &data, sizeof(data));
386
387 /* Calculate the overflow chain PDU's AD data
388 * length
389 */
390 ad_len_overflow =
391 len - PDU_AC_EXT_AD_DATA_LEN_MAX;
392
393 /* No AD data in chain PDU besides the
394 * overflow
395 */
396 ad_len_chain = 0U;
397 } else {
398 struct pdu_adv *pdu_chain;
399
400 /* Remove/Release any previous chain PDU
401 * allocations
402 */
403 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
404 if (pdu_chain) {
405 lll_adv_pdu_linked_append(NULL, pdu);
406 lll_adv_pdu_linked_release_all(pdu_chain);
407 }
408
409 /* No AD data overflow */
410 ad_len_overflow = 0U;
411 }
412 }
413 } else {
414 struct pdu_adv *pdu_chain_prev;
415 struct pdu_adv *pdu_chain;
416 uint16_t ad_len_total;
417 uint8_t ad_len_prev;
418
419 /* Traverse to next set clear hdr data parameter */
420 val_ptr += sizeof(data);
421
422 /* Traverse to the last chain PDU */
423 ad_len_total = 0U;
424 pdu_chain_prev = pdu_prev;
425 pdu_chain = pdu;
426 do {
427 /* Prepare for aux ptr field reference to be returned, hence
428 * second parameter will be for AD data field.
429 */
430 *val_ptr = 0U;
431 (void)memset((void *)&val_ptr[ULL_ADV_HDR_DATA_DATA_PTR_OFFSET],
432 0U, ULL_ADV_HDR_DATA_DATA_PTR_SIZE);
433
434 pdu_prev = pdu_chain_prev;
435 pdu = pdu_chain;
436
437 /* Add Aux Ptr field if not already present */
438 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev,
439 pdu, (ULL_ADV_PDU_HDR_FIELD_AD_DATA |
440 ULL_ADV_PDU_HDR_FIELD_AUX_PTR),
441 0, hdr_data);
442 LL_ASSERT(!err || (err == BT_HCI_ERR_PACKET_TOO_LONG));
443
444 /* Get PDUs previous AD data length */
445 ad_len_prev =
446 hdr_data[ULL_ADV_HDR_DATA_AUX_PTR_PTR_OFFSET +
447 ULL_ADV_HDR_DATA_AUX_PTR_PTR_SIZE];
448
449 /* Check of max supported AD data len */
450 ad_len_total += ad_len_prev;
451 if ((ad_len_total + len) >
452 CONFIG_BT_CTLR_ADV_DATA_LEN_MAX) {
453 /* NOTE: latest PDU was not consumed by LLL and
454 * as ull_adv_sync_pdu_alloc() has reverted back
455 * the double buffer with the first PDU, and
456 * returned the latest PDU as the new PDU, we
457 * need to enqueue back the new PDU which is
458 * infact the latest PDU.
459 */
460 if (pdu_prev == pdu) {
461 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
462 }
463
464 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
465 }
466
467 pdu_chain_prev = lll_adv_pdu_linked_next_get(pdu_prev);
468 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
469 LL_ASSERT((pdu_chain_prev && pdu_chain) ||
470 (!pdu_chain_prev && !pdu_chain));
471 } while (pdu_chain_prev);
472
473 if (err == BT_HCI_ERR_PACKET_TOO_LONG) {
474 ad_len_overflow =
475 hdr_data[ULL_ADV_HDR_DATA_AUX_PTR_PTR_OFFSET +
476 ULL_ADV_HDR_DATA_AUX_PTR_PTR_SIZE +
477 ULL_ADV_HDR_DATA_DATA_PTR_OFFSET +
478 ULL_ADV_HDR_DATA_DATA_PTR_SIZE];
479
480 /* Prepare for aux ptr field reference to be returned,
481 * hence second parameter will be for AD data field.
482 * Fill it with reduced AD data length.
483 */
484 *val_ptr = ad_len_prev - ad_len_overflow;
485
486 /* AD data len in chain PDU */
487 ad_len_chain = len;
488
489 /* Proceed to add chain PDU */
490 err = 0U;
491 } else {
492 ad_len_overflow = 0U;
493 }
494 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
495 }
496 if (err) {
497 return err;
498 }
499
500 /* Parameter validation, if operation is 0x04 (unchanged data)
501 * - periodic advertising is disabled, or
502 * - periodic advertising contains no data, or
503 * - Advertising Data Length is not zero
504 */
505 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK) &&
506 (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA) &&
507 ((!sync->is_enabled) ||
508 (hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] == 0U) ||
509 (len != 0U))) {
510 /* NOTE: latest PDU was not consumed by LLL and as
511 * ull_adv_sync_pdu_alloc() has reverted back the double buffer
512 * with the first PDU, and returned the latest PDU as the new
513 * PDU, we need to enqueue back the new PDU which is infact
514 * the latest PDU.
515 */
516 if (pdu_prev == pdu) {
517 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
518 }
519
520 return BT_HCI_ERR_INVALID_PARAM;
521 }
522
523 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
524 if ((op == BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG) ||
525 (op == BT_HCI_LE_EXT_ADV_OP_LAST_FRAG) ||
526 ad_len_overflow) {
527 struct pdu_adv_com_ext_adv *com_hdr_chain;
528 struct pdu_adv_com_ext_adv *com_hdr;
529 struct pdu_adv_ext_hdr *hdr_chain;
530 struct pdu_adv_aux_ptr *aux_ptr;
531 struct pdu_adv *pdu_chain_prev;
532 struct pdu_adv_ext_hdr hdr;
533 struct pdu_adv *pdu_chain;
534 uint8_t *dptr_chain;
535 uint32_t offs_us;
536 uint16_t ter_len;
537 uint8_t *dptr;
538
539 /* Get reference to flags in superior PDU */
540 com_hdr = &pdu->adv_ext_ind;
541 if (com_hdr->ext_hdr_len) {
542 hdr = com_hdr->ext_hdr;
543 } else {
544 *(uint8_t *)&hdr = 0U;
545 }
546 dptr = com_hdr->ext_hdr.data;
547
548 /* Allocate new PDU */
549 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
550 LL_ASSERT(pdu_chain);
551
552 /* Populate the appended chain PDU */
553 pdu_chain->type = PDU_ADV_TYPE_AUX_CHAIN_IND;
554 pdu_chain->rfu = 0U;
555 pdu_chain->chan_sel = 0U;
556 pdu_chain->tx_addr = 0U;
557 pdu_chain->rx_addr = 0U;
558 pdu_chain->len = 0U;
559
560 com_hdr_chain = &pdu_chain->adv_ext_ind;
561 hdr_chain = (void *)&com_hdr_chain->ext_hdr_adv_data[0];
562 dptr_chain = (void *)hdr_chain;
563
564 /* Initialize Flags */
565 *dptr_chain = 0U;
566
567 /* No CTE Info.
568 * CTE count is given by HCI LE Set Connectionless CTE Transmit
569 * Parameters, hence it is not altered due to change on PDUs
570 * count in Periodic Advertising chain.
571 */
572
573 /* ADI flag, mandatory if superior PDU has it */
574 if (hdr.adi) {
575 hdr_chain->adi = 1U;
576 }
577
578 /* Proceed to next byte if any flags present */
579 if (*dptr_chain) {
580 dptr_chain++;
581 }
582
583 /* Start adding fields corresponding to flags here, if any */
584
585 /* No AdvA */
586 /* No TgtA */
587 /* No CTEInfo */
588
589 /* ADI flag */
590 if (hdr_chain->adi) {
591 (void)memcpy(dptr_chain, dptr,
592 sizeof(struct pdu_adv_adi));
593
594 dptr += sizeof(struct pdu_adv_adi);
595 dptr_chain += sizeof(struct pdu_adv_adi);
596 }
597
598 /* non-connectable non-scannable chain pdu */
599 com_hdr_chain->adv_mode = 0;
600
601 /* Calc current chain PDU len */
602 ter_len = ull_adv_aux_hdr_len_calc(com_hdr_chain, &dptr_chain);
603
604 /* Prefix overflowed data to chain PDU and reduce the AD data in
605 * in the current PDU.
606 */
607 if (ad_len_overflow) {
608 uint8_t *ad_overflow;
609
610 /* Copy overflowed AD data from previous PDU into
611 * new chain PDU
612 */
613 (void)memcpy(&ad_overflow,
614 &val_ptr[ULL_ADV_HDR_DATA_DATA_PTR_OFFSET],
615 sizeof(ad_overflow));
616 ad_overflow += *val_ptr;
617 (void)memcpy(dptr_chain, ad_overflow, ad_len_overflow);
618 dptr_chain += ad_len_overflow;
619
620 /* Reduce the AD data in the current PDU that will
621 * become the current parent PDU for the new chain PDU.
622 */
623 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
624 (ULL_ADV_PDU_HDR_FIELD_AD_DATA |
625 ULL_ADV_PDU_HDR_FIELD_AUX_PTR),
626 0, hdr_data);
627 if (err) {
628 /* NOTE: latest PDU was not consumed by LLL and
629 * as ull_adv_sync_pdu_alloc() has reverted back
630 * the double buffer with the first PDU, and
631 * returned the latest PDU as the new PDU, we
632 * need to enqueue back the new PDU which is
633 * infact the latest PDU.
634 */
635 if (pdu_prev == pdu) {
636 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
637 }
638
639 return err;
640 }
641
642 /* AD data len in chain PDU besides the overflow */
643 len = ad_len_chain;
644 }
645
646 /* Check AdvData overflow */
647 if ((ter_len + ad_len_overflow + len) >
648 PDU_AC_PAYLOAD_SIZE_MAX) {
649 /* NOTE: latest PDU was not consumed by LLL and
650 * as ull_adv_sync_pdu_alloc() has reverted back
651 * the double buffer with the first PDU, and
652 * returned the latest PDU as the new PDU, we
653 * need to enqueue back the new PDU which is
654 * infact the latest PDU.
655 */
656 if (pdu_prev == pdu) {
657 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
658 }
659
660 return BT_HCI_ERR_PACKET_TOO_LONG;
661 }
662
663 /* Fill the chain PDU length */
664 ull_adv_aux_hdr_len_fill(com_hdr_chain, ter_len);
665 pdu_chain->len = ter_len + ad_len_overflow + len;
666
667 /* Fill AD Data in chain PDU */
668 (void)memcpy(dptr_chain, data, len);
669
670 /* Get reference to aux ptr in superior PDU */
671 (void)memcpy(&aux_ptr,
672 &hdr_data[ULL_ADV_HDR_DATA_AUX_PTR_PTR_OFFSET],
673 sizeof(aux_ptr));
674
675 /* Fill the aux offset in the previous AUX_SYNC_IND PDU */
676 offs_us = PDU_AC_US(pdu->len, adv->lll.phy_s,
677 adv->lll.phy_flags) +
678 EVENT_SYNC_B2B_MAFS_US;
679 ull_adv_aux_ptr_fill(aux_ptr, offs_us, adv->lll.phy_s);
680
681 /* Remove/Release any previous chain PDUs */
682 pdu_chain_prev = lll_adv_pdu_linked_next_get(pdu);
683 if (pdu_chain_prev) {
684 lll_adv_pdu_linked_append(NULL, pdu);
685 lll_adv_pdu_linked_release_all(pdu_chain_prev);
686 }
687
688 /* Chain the PDU */
689 lll_adv_pdu_linked_append(pdu_chain, pdu);
690 }
691 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
692
693 /* Update time reservation if Periodic Advertising events are active */
694 if (sync->is_started) {
695 err = ull_adv_sync_time_update(sync, pdu);
696 if (err) {
697 return err;
698 }
699 }
700
701 /* Commit the updated Periodic Advertising Data */
702 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
703
704 /* Check if Periodic Advertising Data is complete */
705 sync->is_data_cmplt = (op >= BT_HCI_LE_EXT_ADV_OP_LAST_FRAG);
706
707 return 0;
708 }
709
ll_adv_sync_enable(uint8_t handle,uint8_t enable)710 uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
711 {
712 struct pdu_adv *ter_pdu = NULL;
713 struct lll_adv_sync *lll_sync;
714 struct ll_adv_sync_set *sync;
715 uint8_t sync_got_enabled;
716 struct ll_adv_set *adv;
717 uint8_t ter_idx;
718 uint8_t err;
719
720 /* Check for valid advertising set */
721 adv = ull_adv_is_created_get(handle);
722 if (!adv) {
723 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
724 }
725
726 /* Check if periodic advertising is associated with advertising set */
727 lll_sync = adv->lll.sync;
728 if (!lll_sync) {
729 return BT_HCI_ERR_CMD_DISALLOWED;
730 }
731
732 /* Check for invalid enable bit fields */
733 if ((enable > (BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE |
734 BT_HCI_LE_SET_PER_ADV_ENABLE_ADI)) ||
735 (!IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
736 (enable > BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE))) {
737 return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
738 }
739
740 sync = HDR_LLL2ULL(lll_sync);
741
742 /* Handle periodic advertising being disable */
743 if (!(enable & BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE)) {
744 if (!sync->is_enabled) {
745 return BT_HCI_ERR_CMD_DISALLOWED;
746 }
747
748 if (!sync->is_started) {
749 sync->is_enabled = 0U;
750
751 return 0;
752 }
753
754 err = sync_remove(sync, adv, 0U);
755 return err;
756 }
757
758 /* Check for advertising set type */
759 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) {
760 uint8_t err;
761
762 err = adv_type_check(adv);
763 if (err) {
764 return BT_HCI_ERR_CMD_DISALLOWED;
765 }
766 }
767
768 /* Check for periodic data being complete */
769 if (!sync->is_data_cmplt) {
770 return BT_HCI_ERR_CMD_DISALLOWED;
771 }
772
773 /* TODO: Check packet too long */
774
775 /* Check for already enabled periodic advertising set */
776 sync_got_enabled = 0U;
777 if (sync->is_enabled) {
778 /* TODO: Enabling an already enabled advertising changes its
779 * random address.
780 */
781 } else {
782 sync_got_enabled = 1U;
783 }
784
785 /* Add/Remove ADI */
786 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)) {
787 uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
788 ULL_ADV_HDR_DATA_ADI_PTR_SIZE] = {0, };
789 void *extra_data_prev, *extra_data;
790 struct pdu_adv *pdu_prev, *pdu;
791 uint16_t hdr_add_fields;
792 uint16_t hdr_rem_fields;
793
794 if (enable & BT_HCI_LE_SET_PER_ADV_ENABLE_ADI) {
795 hdr_add_fields = ULL_ADV_PDU_HDR_FIELD_ADI;
796 hdr_rem_fields = 0U;
797 } else {
798 hdr_add_fields = 0U;
799 hdr_rem_fields = ULL_ADV_PDU_HDR_FIELD_ADI;
800 }
801
802 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
803 &pdu_prev, &pdu, &extra_data_prev,
804 &extra_data, &ter_idx);
805 if (err) {
806 return err;
807 }
808
809 /* Use PDU to calculate time reservation */
810 ter_pdu = pdu;
811
812 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
813 if (extra_data) {
814 ull_adv_sync_extra_data_set_clear(extra_data_prev,
815 extra_data, 0U, 0U,
816 NULL);
817 }
818 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
819
820 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
821 /* Update ADI while duplicating chain PDUs */
822 do {
823 struct pdu_adv *pdu_chain;
824
825 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
826 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev,
827 pdu, hdr_add_fields,
828 hdr_rem_fields,
829 hdr_data);
830 if (err) {
831 return err;
832 }
833
834 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
835 pdu_prev = lll_adv_pdu_linked_next_get(pdu_prev);
836 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
837
838 /* Allocate new chain PDU if required */
839 if (pdu_prev) {
840 /* Prior PDU chain allocation valid */
841 if (pdu_chain) {
842 pdu = pdu_chain;
843
844 continue;
845 }
846
847 /* Get a new chain PDU */
848 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
849 if (!pdu_chain) {
850 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
851 }
852
853 /* Link the chain PDU to parent PDU */
854 lll_adv_pdu_linked_append(pdu_chain, pdu);
855
856 /* continue back to update the new PDU */
857 pdu = pdu_chain;
858 }
859 } while (pdu_prev);
860 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
861 }
862
863 /* Start Periodic Advertising events if Extended Advertising events are
864 * active.
865 */
866 if (adv->is_enabled && !sync->is_started) {
867 struct pdu_adv_sync_info *sync_info;
868 uint8_t value[1 + sizeof(sync_info)];
869 uint32_t ticks_slot_overhead_aux;
870 uint32_t ticks_slot_overhead;
871 struct lll_adv_aux *lll_aux;
872 struct ll_adv_aux_set *aux;
873 uint32_t ticks_anchor_sync;
874 uint32_t ticks_anchor_aux;
875 uint8_t pri_idx, sec_idx;
876 uint32_t ret;
877
878 lll_aux = adv->lll.aux;
879
880 /* Add sync_info into auxiliary PDU */
881 err = ull_adv_aux_hdr_set_clear(adv,
882 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO,
883 0U, value, &pri_idx, &sec_idx);
884 if (err) {
885 return err;
886 }
887
888 /* First byte in the length-value encoded parameter is size of
889 * sync_info structure, followed by pointer to sync_info in the
890 * PDU.
891 */
892 (void)memcpy(&sync_info, &value[1], sizeof(sync_info));
893 ull_adv_sync_info_fill(sync, sync_info);
894
895 /* Calculate the ticks_slot and return slot overhead */
896 ticks_slot_overhead = ull_adv_sync_evt_init(adv, sync, ter_pdu);
897
898 /* If Auxiliary PDU already active, find and schedule Periodic
899 * advertising follow it.
900 */
901 if (lll_aux) {
902 /* Auxiliary set already active (due to other fields
903 * being already present or being started prior).
904 */
905 aux = NULL;
906 ticks_anchor_aux = 0U; /* unused in this path */
907 ticks_slot_overhead_aux = 0U; /* unused in this path */
908
909 /* Find the anchor after the group of active auxiliary
910 * sets such that Periodic Advertising events are placed
911 * in non-overlapping timeline when auxiliary and
912 * Periodic Advertising have similar event interval.
913 */
914 ticks_anchor_sync = ticker_ticks_now_get() +
915 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
916
917 #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
918 err = ull_sched_adv_aux_sync_free_anchor_get(sync->ull.ticks_slot,
919 &ticks_anchor_sync);
920 if (!err) {
921 ticks_anchor_sync += HAL_TICKER_US_TO_TICKS(
922 MAX(EVENT_MAFS_US,
923 EVENT_OVERHEAD_START_US) -
924 EVENT_OVERHEAD_START_US +
925 (EVENT_TICKER_RES_MARGIN_US << 1));
926 }
927 #endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
928
929 } else {
930 /* Auxiliary set will be started due to inclusion of
931 * sync info field.
932 */
933 lll_aux = adv->lll.aux;
934 aux = HDR_LLL2ULL(lll_aux);
935 ticks_anchor_aux = ticker_ticks_now_get() +
936 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
937 ticks_slot_overhead_aux =
938 ull_adv_aux_evt_init(aux, &ticks_anchor_aux);
939
940 #if !defined(CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET) || \
941 (CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET == 0)
942 ticks_anchor_sync = ticks_anchor_aux +
943 ticks_slot_overhead_aux + aux->ull.ticks_slot +
944 HAL_TICKER_US_TO_TICKS(
945 MAX(EVENT_MAFS_US,
946 EVENT_OVERHEAD_START_US) -
947 EVENT_OVERHEAD_START_US +
948 (EVENT_TICKER_RES_MARGIN_US << 1));
949
950 #else /* CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET */
951 ticks_anchor_sync = ticks_anchor_aux +
952 HAL_TICKER_US_TO_TICKS(
953 CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET);
954
955 #endif /* CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET */
956 }
957
958 ret = ull_adv_sync_start(adv, sync, ticks_anchor_sync,
959 ticks_slot_overhead);
960 if (ret) {
961 sync_remove(sync, adv, 1U);
962
963 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
964 }
965
966 sync->is_started = 1U;
967
968 lll_adv_aux_data_enqueue(lll_aux, sec_idx);
969 lll_adv_data_enqueue(&adv->lll, pri_idx);
970
971 if (aux) {
972 /* Keep aux interval equal or higher than primary PDU
973 * interval.
974 */
975 aux->interval = adv->interval +
976 (HAL_TICKER_TICKS_TO_US(
977 ULL_ADV_RANDOM_DELAY) /
978 ADV_INT_UNIT_US);
979
980 ret = ull_adv_aux_start(aux, ticks_anchor_aux,
981 ticks_slot_overhead_aux);
982 if (ret) {
983 sync_remove(sync, adv, 1U);
984
985 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
986 }
987
988 aux->is_started = 1U;
989
990 } else if (IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) {
991 /* notify the auxiliary set */
992 ull_adv_sync_started_stopped(HDR_LLL2ULL(lll_aux));
993 }
994 }
995
996 /* Commit the Periodic Advertising data if ADI supported and has been
997 * updated.
998 */
999 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)) {
1000 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
1001 }
1002
1003 if (sync_got_enabled) {
1004 sync->is_enabled = sync_got_enabled;
1005 }
1006
1007 return 0;
1008 }
1009
ull_adv_sync_init(void)1010 int ull_adv_sync_init(void)
1011 {
1012 int err;
1013
1014 err = init_reset();
1015 if (err) {
1016 return err;
1017 }
1018
1019 return 0;
1020 }
1021
ull_adv_sync_reset(void)1022 int ull_adv_sync_reset(void)
1023 {
1024 struct lll_adv_sync *lll_sync;
1025 struct ll_adv_sync_set *sync;
1026 struct ll_adv_set *adv;
1027 uint8_t handle;
1028 int err;
1029
1030 for (handle = 0U; handle < BT_CTLR_ADV_SET; handle++) {
1031 adv = ull_adv_is_created_get(handle);
1032 if (!adv) {
1033 continue;
1034 }
1035
1036 lll_sync = adv->lll.sync;
1037 if (!lll_sync) {
1038 continue;
1039 }
1040
1041 sync = HDR_LLL2ULL(lll_sync);
1042
1043 if (!sync->is_started) {
1044 sync->is_enabled = 0U;
1045
1046 continue;
1047 }
1048
1049 err = sync_remove(sync, adv, 0U);
1050 if (err) {
1051 return err;
1052 }
1053 }
1054
1055 return 0;
1056 }
1057
ull_adv_sync_reset_finalize(void)1058 int ull_adv_sync_reset_finalize(void)
1059 {
1060 int err;
1061
1062 err = init_reset();
1063 if (err) {
1064 return err;
1065 }
1066
1067 return 0;
1068 }
1069
ull_adv_sync_get(uint8_t handle)1070 struct ll_adv_sync_set *ull_adv_sync_get(uint8_t handle)
1071 {
1072 if (handle >= CONFIG_BT_CTLR_ADV_SYNC_SET) {
1073 return NULL;
1074 }
1075
1076 return &ll_adv_sync_pool[handle];
1077 }
1078
ull_adv_sync_handle_get(const struct ll_adv_sync_set * sync)1079 uint16_t ull_adv_sync_handle_get(const struct ll_adv_sync_set *sync)
1080 {
1081 return sync_handle_get(sync);
1082 }
1083
ull_adv_sync_lll_handle_get(const struct lll_adv_sync * lll)1084 uint16_t ull_adv_sync_lll_handle_get(const struct lll_adv_sync *lll)
1085 {
1086 return sync_handle_get((void *)lll->hdr.parent);
1087 }
1088
ull_adv_sync_release(struct ll_adv_sync_set * sync)1089 void ull_adv_sync_release(struct ll_adv_sync_set *sync)
1090 {
1091 lll_adv_sync_data_release(&sync->lll);
1092 sync_release(sync);
1093 }
1094
ull_adv_sync_time_get(const struct ll_adv_sync_set * sync,uint8_t pdu_len)1095 uint32_t ull_adv_sync_time_get(const struct ll_adv_sync_set *sync,
1096 uint8_t pdu_len)
1097 {
1098 const struct lll_adv_sync *lll_sync = &sync->lll;
1099 const struct lll_adv *lll = lll_sync->adv;
1100 uint32_t time_us;
1101
1102 /* NOTE: 16-bit values are sufficient for minimum radio event time
1103 * reservation, 32-bit are used here so that reservations for
1104 * whole back-to-back chaining of PDUs can be accommodated where
1105 * the required microseconds could overflow 16-bits, example,
1106 * back-to-back chained Coded PHY PDUs.
1107 */
1108
1109 time_us = PDU_AC_US(pdu_len, lll->phy_s, lll->phy_flags) +
1110 EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
1111
1112 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1113 struct ll_adv_set *adv = HDR_LLL2ULL(lll);
1114 struct lll_df_adv_cfg *df_cfg = adv->df_cfg;
1115
1116 if (df_cfg && df_cfg->is_enabled) {
1117 time_us += CTE_LEN_US(df_cfg->cte_length);
1118 }
1119 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1120
1121 return time_us;
1122 }
1123
ull_adv_sync_evt_init(struct ll_adv_set * adv,struct ll_adv_sync_set * sync,struct pdu_adv * pdu)1124 uint32_t ull_adv_sync_evt_init(struct ll_adv_set *adv,
1125 struct ll_adv_sync_set *sync,
1126 struct pdu_adv *pdu)
1127 {
1128 uint32_t ticks_slot_overhead;
1129 uint32_t ticks_slot_offset;
1130 uint32_t time_us;
1131
1132 ull_hdr_init(&sync->ull);
1133
1134 if (!pdu) {
1135 pdu = lll_adv_sync_data_peek(&sync->lll, NULL);
1136 }
1137
1138 time_us = sync_time_get(sync, pdu);
1139
1140 /* TODO: active_to_start feature port */
1141 sync->ull.ticks_active_to_start = 0U;
1142 sync->ull.ticks_prepare_to_start =
1143 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
1144 sync->ull.ticks_preempt_to_start =
1145 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US);
1146 sync->ull.ticks_slot = HAL_TICKER_US_TO_TICKS(time_us);
1147
1148 ticks_slot_offset = MAX(sync->ull.ticks_active_to_start,
1149 sync->ull.ticks_prepare_to_start);
1150 if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
1151 ticks_slot_overhead = ticks_slot_offset;
1152 } else {
1153 ticks_slot_overhead = 0U;
1154 }
1155
1156 return ticks_slot_overhead;
1157 }
1158
ull_adv_sync_start(struct ll_adv_set * adv,struct ll_adv_sync_set * sync,uint32_t ticks_anchor,uint32_t ticks_slot_overhead)1159 uint32_t ull_adv_sync_start(struct ll_adv_set *adv,
1160 struct ll_adv_sync_set *sync,
1161 uint32_t ticks_anchor,
1162 uint32_t ticks_slot_overhead)
1163 {
1164 uint32_t volatile ret_cb;
1165 uint32_t interval_us;
1166 uint8_t sync_handle;
1167 uint32_t ret;
1168
1169 interval_us = (uint32_t)sync->interval * PERIODIC_INT_UNIT_US;
1170
1171 sync_handle = sync_handle_get(sync);
1172
1173 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
1174 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
1175 if (sync->lll.iso) {
1176 ll_adv_sync_ticker_ext[sync_handle].expire_info_id =
1177 TICKER_ID_ADV_ISO_BASE + sync->lll.iso->handle;
1178 } else {
1179 ll_adv_sync_ticker_ext[sync_handle].expire_info_id = TICKER_NULL;
1180 }
1181
1182 ll_adv_sync_ticker_ext[sync_handle].ext_timeout_func = ticker_cb;
1183
1184 ret_cb = TICKER_STATUS_BUSY;
1185 ret = ticker_start_ext(
1186 #else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
1187
1188 ret_cb = TICKER_STATUS_BUSY;
1189 ret = ticker_start(
1190 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
1191 TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
1192 (TICKER_ID_ADV_SYNC_BASE + sync_handle),
1193 ticks_anchor, 0U,
1194 HAL_TICKER_US_TO_TICKS(interval_us),
1195 HAL_TICKER_REMAINDER(interval_us), TICKER_NULL_LAZY,
1196 (sync->ull.ticks_slot + ticks_slot_overhead),
1197 ticker_cb, sync,
1198 ull_ticker_status_give, (void *)&ret_cb
1199 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
1200 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
1201 ,
1202 &ll_adv_sync_ticker_ext[sync_handle]
1203 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
1204 );
1205 ret = ull_ticker_status_take(ret, &ret_cb);
1206
1207 return ret;
1208 }
1209
ull_adv_sync_time_update(struct ll_adv_sync_set * sync,struct pdu_adv * pdu)1210 uint8_t ull_adv_sync_time_update(struct ll_adv_sync_set *sync,
1211 struct pdu_adv *pdu)
1212 {
1213 uint32_t volatile ret_cb;
1214 uint32_t ticks_minus;
1215 uint32_t ticks_plus;
1216 uint32_t time_ticks;
1217 uint32_t time_us;
1218 uint32_t ret;
1219
1220 time_us = sync_time_get(sync, pdu);
1221 time_ticks = HAL_TICKER_US_TO_TICKS(time_us);
1222 if (sync->ull.ticks_slot > time_ticks) {
1223 ticks_minus = sync->ull.ticks_slot - time_ticks;
1224 ticks_plus = 0U;
1225 } else if (sync->ull.ticks_slot < time_ticks) {
1226 ticks_minus = 0U;
1227 ticks_plus = time_ticks - sync->ull.ticks_slot;
1228 } else {
1229 return BT_HCI_ERR_SUCCESS;
1230 }
1231
1232 ret_cb = TICKER_STATUS_BUSY;
1233 ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
1234 TICKER_USER_ID_THREAD,
1235 (TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync)),
1236 0, 0, ticks_plus, ticks_minus, 0, 0,
1237 ull_ticker_status_give, (void *)&ret_cb);
1238 ret = ull_ticker_status_take(ret, &ret_cb);
1239 if (ret != TICKER_STATUS_SUCCESS) {
1240 return BT_HCI_ERR_CMD_DISALLOWED;
1241 }
1242
1243 sync->ull.ticks_slot = time_ticks;
1244
1245 return BT_HCI_ERR_SUCCESS;
1246 }
1247
ull_adv_sync_chm_update(void)1248 uint8_t ull_adv_sync_chm_update(void)
1249 {
1250 uint8_t handle;
1251
1252 handle = CONFIG_BT_CTLR_ADV_SYNC_SET;
1253 while (handle--) {
1254 (void)sync_chm_update(handle);
1255 }
1256
1257 /* TODO: Should failure due to Channel Map Update being already in
1258 * progress be returned to caller?
1259 */
1260 return 0;
1261 }
1262
ull_adv_sync_chm_complete(struct node_rx_hdr * rx)1263 void ull_adv_sync_chm_complete(struct node_rx_hdr *rx)
1264 {
1265 uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
1266 ULL_ADV_HDR_DATA_ACAD_PTR_SIZE];
1267 struct lll_adv_sync *lll_sync;
1268 struct pdu_adv *pdu_prev;
1269 struct ll_adv_set *adv;
1270 struct pdu_adv *pdu;
1271 uint8_t acad_len;
1272 uint8_t *others;
1273 uint8_t ter_idx;
1274 uint8_t ad_len;
1275 uint8_t *acad;
1276 uint8_t *ad;
1277 uint8_t len;
1278 uint8_t err;
1279
1280 /* Allocate next Sync PDU */
1281 pdu_prev = NULL;
1282 pdu = NULL;
1283 lll_sync = rx->rx_ftr.param;
1284 adv = HDR_LLL2ULL(lll_sync->adv);
1285 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
1286 &pdu_prev, &pdu, NULL, NULL, &ter_idx);
1287 LL_ASSERT(!err);
1288
1289 /* Get the size of current ACAD, first octet returns the old length and
1290 * followed by pointer to previous offset to ACAD in the PDU.
1291 */
1292 hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = 0U;
1293 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
1294 ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
1295 &hdr_data);
1296 LL_ASSERT(!err);
1297
1298 /* Dev assert if ACAD empty */
1299 LL_ASSERT(hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET]);
1300
1301 /* Find the Channel Map Update Indication */
1302 acad_len = hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET];
1303 len = acad_len;
1304 (void)memcpy(&acad, &hdr_data[ULL_ADV_HDR_DATA_ACAD_PTR_OFFSET],
1305 sizeof(acad));
1306 ad = acad;
1307 do {
1308 ad_len = ad[PDU_ADV_DATA_HEADER_LEN_OFFSET];
1309 if (ad_len &&
1310 (ad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] ==
1311 PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND)) {
1312 break;
1313 }
1314
1315 ad_len += 1U;
1316
1317 LL_ASSERT(ad_len <= len);
1318
1319 ad += ad_len;
1320 len -= ad_len;
1321 } while (len);
1322 LL_ASSERT(len);
1323
1324 /* Remove Channel Map Update Indication by moving other AD types that
1325 * are after it.
1326 */
1327 ad_len += 1U;
1328 others = ad + ad_len;
1329 acad_len -= ad_len;
1330 (void)memmove(ad, others, acad_len);
1331
1332 /* Adjust the next PDU for ACAD length, this is done by using the next
1333 * PDU to copy ACAD into same next PDU.
1334 */
1335 hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = acad_len;
1336 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu, pdu,
1337 ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
1338 &hdr_data);
1339 LL_ASSERT(!err);
1340
1341 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
1342 }
1343
ull_adv_sync_info_fill(struct ll_adv_sync_set * sync,struct pdu_adv_sync_info * si)1344 void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync,
1345 struct pdu_adv_sync_info *si)
1346 {
1347 struct lll_adv_sync *lll_sync;
1348
1349 /* NOTE: sync offset and offset unit filled by secondary prepare.
1350 *
1351 * If sync_info is part of ADV PDU the offs_adjust field
1352 * is always set to 0.
1353 */
1354 si->offs_units = OFFS_UNIT_VALUE_30_US;
1355 si->offs_adjust = 0U;
1356 si->offs = 0U;
1357
1358 /* Fill the interval, access address and CRC init */
1359 si->interval = sys_cpu_to_le16(sync->interval);
1360 lll_sync = &sync->lll;
1361 (void)memcpy(&si->aa, lll_sync->access_addr, sizeof(si->aa));
1362 (void)memcpy(si->crc_init, lll_sync->crc_init, sizeof(si->crc_init));
1363
1364 /* NOTE: Filled by secondary prepare */
1365 si->evt_cntr = 0U;
1366 }
1367
1368 #if !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
ull_adv_sync_offset_get(struct ll_adv_set * adv)1369 void ull_adv_sync_offset_get(struct ll_adv_set *adv)
1370 {
1371 static memq_link_t link;
1372 static struct mayfly mfy = {0, 0, &link, NULL, mfy_sync_offset_get};
1373 uint32_t ret;
1374
1375 mfy.param = adv;
1376 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1,
1377 &mfy);
1378 LL_ASSERT(!ret);
1379 }
1380 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
1381
ull_adv_sync_pdu_init(struct pdu_adv * pdu,uint8_t ext_hdr_flags,uint8_t phy_s,uint8_t phy_flags,struct pdu_cte_info * cte_info)1382 void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags,
1383 uint8_t phy_s, uint8_t phy_flags,
1384 struct pdu_cte_info *cte_info)
1385 {
1386 struct pdu_adv_com_ext_adv *com_hdr;
1387 struct pdu_adv_ext_hdr *ext_hdr;
1388 struct pdu_adv_aux_ptr *aux_ptr;
1389 uint32_t cte_len_us;
1390 uint8_t *dptr;
1391 uint8_t len;
1392
1393 pdu->type = PDU_ADV_TYPE_AUX_SYNC_IND;
1394 pdu->rfu = 0U;
1395 pdu->chan_sel = 0U;
1396
1397 pdu->tx_addr = 0U;
1398 pdu->rx_addr = 0U;
1399
1400 com_hdr = &pdu->adv_ext_ind;
1401 /* Non-connectable and Non-scannable adv mode */
1402 com_hdr->adv_mode = 0U;
1403
1404 ext_hdr = &com_hdr->ext_hdr;
1405 *(uint8_t *)ext_hdr = ext_hdr_flags;
1406 dptr = ext_hdr->data;
1407
1408 LL_ASSERT(!(ext_hdr_flags & (ULL_ADV_PDU_HDR_FIELD_ADVA | ULL_ADV_PDU_HDR_FIELD_TARGETA |
1409 #if !defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1410 ULL_ADV_PDU_HDR_FIELD_ADI |
1411 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1412 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO)));
1413
1414 if (IS_ENABLED(CONFIG_BT_CTLR_DF_ADV_CTE_TX) &&
1415 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_CTE_INFO)) {
1416 (void)memcpy(dptr, cte_info, sizeof(*cte_info));
1417 cte_len_us = CTE_LEN_US(cte_info->time);
1418 dptr += sizeof(struct pdu_cte_info);
1419 } else {
1420 cte_len_us = 0U;
1421 }
1422 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
1423 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_ADI)) {
1424 dptr += sizeof(struct pdu_adv_adi);
1425 }
1426 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) &&
1427 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR)) {
1428 aux_ptr = (void *)dptr;
1429 dptr += sizeof(struct pdu_adv_aux_ptr);
1430 }
1431 if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_TX_POWER) {
1432 dptr += sizeof(uint8_t);
1433 }
1434
1435 /* Calc tertiary PDU len */
1436 len = ull_adv_aux_hdr_len_calc(com_hdr, &dptr);
1437 ull_adv_aux_hdr_len_fill(com_hdr, len);
1438
1439 pdu->len = len;
1440
1441 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1442 /* Fill aux offset in aux pointer field */
1443 if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) {
1444 uint32_t offs_us;
1445
1446 offs_us = PDU_AC_US(pdu->len, phy_s, phy_flags) +
1447 EVENT_SYNC_B2B_MAFS_US;
1448 offs_us += cte_len_us;
1449 ull_adv_aux_ptr_fill(aux_ptr, offs_us, phy_s);
1450 }
1451 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
1452 }
1453
ull_adv_sync_pdu_alloc(struct ll_adv_set * adv,enum ull_adv_pdu_extra_data_flag extra_data_flag,struct pdu_adv ** ter_pdu_prev,struct pdu_adv ** ter_pdu_new,void ** extra_data_prev,void ** extra_data_new,uint8_t * ter_idx)1454 uint8_t ull_adv_sync_pdu_alloc(struct ll_adv_set *adv,
1455 enum ull_adv_pdu_extra_data_flag extra_data_flag,
1456 struct pdu_adv **ter_pdu_prev, struct pdu_adv **ter_pdu_new,
1457 void **extra_data_prev, void **extra_data_new, uint8_t *ter_idx)
1458 {
1459 struct pdu_adv *pdu_prev, *pdu_new;
1460 struct lll_adv_sync *lll_sync;
1461 void *ed_prev;
1462 #if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
1463 void *ed_new;
1464 #endif
1465
1466 lll_sync = adv->lll.sync;
1467 if (!lll_sync) {
1468 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
1469 }
1470
1471 /* Get reference to previous periodic advertising PDU data */
1472 pdu_prev = lll_adv_sync_data_peek(lll_sync, &ed_prev);
1473
1474 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1475 /* Get reference to new periodic advertising PDU data buffer */
1476 if (extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS ||
1477 (extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST && ed_prev)) {
1478 /* If there was an extra data in past PDU data or it is required
1479 * by the hdr_add_fields then allocate memmory for it.
1480 */
1481 pdu_new = lll_adv_sync_data_alloc(lll_sync, &ed_new,
1482 ter_idx);
1483 if (!pdu_new) {
1484 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1485 }
1486 } else {
1487 ed_new = NULL;
1488 #else
1489 {
1490 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1491 pdu_new = lll_adv_sync_data_alloc(lll_sync, NULL, ter_idx);
1492 if (!pdu_new) {
1493 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1494 }
1495 }
1496
1497 #if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
1498 if (extra_data_prev) {
1499 *extra_data_prev = ed_prev;
1500 }
1501 if (extra_data_new) {
1502 *extra_data_new = ed_new;
1503 }
1504 #endif /* CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY */
1505
1506 *ter_pdu_prev = pdu_prev;
1507 *ter_pdu_new = pdu_new;
1508
1509 return 0;
1510 }
1511
1512 /* @brief Set or clear fields in extended advertising header and store
1513 * extra_data if requested.
1514 *
1515 * @param[in] lll_sync Reference to periodic advertising sync.
1516 * @param[in] ter_pdu_prev Pointer to previous PDU.
1517 * @param[in] ter_pdu_ Pointer to PDU to fill fields.
1518 * @param[in] hdr_add_fields Flag with information which fields add.
1519 * @param[in] hdr_rem_fields Flag with information which fields remove.
1520 * @param[in] hdr_data Pointer to data to be added to header. Content
1521 * depends on the value of @p hdr_add_fields.
1522 *
1523 * @Note
1524 * @p hdr_data content depends on the flag provided by @p hdr_add_fields:
1525 * - ULL_ADV_PDU_HDR_FIELD_CTE_INFO:
1526 * # @p hdr_data points to single byte with CTEInfo field
1527 * - ULL_ADV_PDU_HDR_FIELD_ADI:
1528 * # @p hdr_data points to memory where first byte is size of ADI structure,
1529 * following bytes are the pointer reference to the new ADI structure to be
1530 * updated in the PDU.
1531 * In return, the first byte returns the size of ADI structure, following
1532 * bytes returns the pointer reference to ADI structure offset inside the
1533 * updated current PDU.
1534 * - ULL_ADV_PDU_HDR_FIELD_AD_DATA:
1535 * # @p hdr_data points to memory where first byte
1536 * is size of advertising data, following byte is a pointer to actual
1537 * advertising data.
1538 * - ULL_ADV_PDU_HDR_FIELD_AUX_PTR:
1539 * # @p hdr_data points to memory where first byte is size of aux ptr
1540 * structure, following bytes are the pointer reference to the new aux ptr
1541 * structure to be updated in the PDU.
1542 * In return, the first byte returns the size of aux ptr structure,
1543 * following bytes returns the pointer reference to aux ptr structure offset
1544 * inside the updated current PDU.
1545 * - ULL_ADV_PDU_HDR_FIELD_ACAD:
1546 * # @p hdr_data points to memory where first byte is size of ACAD, second
1547 * byte is used to return offset to ACAD field.
1548 * # @p hdr_data memory returns previous ACAD length back in the first byte
1549 * and offset to new ACAD in the next PDU.
1550 *
1551 * @return Zero in case of success, other value in case of failure.
1552 */
1553 uint8_t ull_adv_sync_pdu_set_clear(struct lll_adv_sync *lll_sync,
1554 struct pdu_adv *ter_pdu_prev,
1555 struct pdu_adv *ter_pdu,
1556 uint16_t hdr_add_fields,
1557 uint16_t hdr_rem_fields,
1558 void *hdr_data)
1559 {
1560 struct pdu_adv_com_ext_adv *ter_com_hdr, *ter_com_hdr_prev;
1561 struct pdu_adv_ext_hdr ter_hdr = { 0 }, ter_hdr_prev = { 0 };
1562 struct pdu_adv_aux_ptr *aux_ptr, *aux_ptr_prev;
1563 uint8_t *ter_dptr, *ter_dptr_prev;
1564 struct pdu_adv_adi *adi;
1565 uint8_t acad_len_prev;
1566 uint8_t ter_len_prev;
1567 uint8_t hdr_buf_len;
1568 uint16_t ter_len;
1569 uint8_t *ad_data;
1570 uint8_t acad_len;
1571 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1572 uint8_t cte_info;
1573 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1574 uint8_t ad_len;
1575
1576 /* Get common pointers from reference to previous tertiary PDU data */
1577 ter_com_hdr_prev = (void *)&ter_pdu_prev->adv_ext_ind;
1578 if (ter_com_hdr_prev->ext_hdr_len != 0) {
1579 ter_hdr_prev = ter_com_hdr_prev->ext_hdr;
1580 }
1581 ter_dptr_prev = ter_com_hdr_prev->ext_hdr.data;
1582
1583 /* Set common fields in reference to new tertiary PDU data buffer */
1584 ter_pdu->type = ter_pdu_prev->type;
1585 ter_pdu->rfu = 0U;
1586 ter_pdu->chan_sel = 0U;
1587
1588 ter_pdu->tx_addr = ter_pdu_prev->tx_addr;
1589 ter_pdu->rx_addr = ter_pdu_prev->rx_addr;
1590
1591 /* Get common pointers from current tertiary PDU data.
1592 * It is possible that the current tertiary is the same as
1593 * previous one. It may happen if update periodic advertising
1594 * chain in place.
1595 */
1596 ter_com_hdr = (void *)&ter_pdu->adv_ext_ind;
1597 ter_com_hdr->adv_mode = ter_com_hdr_prev->adv_mode;
1598 ter_dptr = ter_com_hdr->ext_hdr.data;
1599
1600 /* No AdvA in AUX_SYNC_IND */
1601 /* No TargetA in AUX_SYNC_IND */
1602
1603 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1604 /* If requested add or update CTEInfo */
1605 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
1606 ter_hdr.cte_info = 1;
1607 cte_info = *(uint8_t *)hdr_data;
1608 hdr_data = (uint8_t *)hdr_data + 1;
1609 ter_dptr += sizeof(struct pdu_cte_info);
1610 /* If CTEInfo exists in prev and is not requested to be removed */
1611 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) &&
1612 ter_hdr_prev.cte_info) {
1613 ter_hdr.cte_info = 1;
1614 cte_info = 0U; /* value not used, will be read from prev PDU */
1615 ter_dptr += sizeof(struct pdu_cte_info);
1616 } else {
1617 cte_info = 0U; /* value not used */
1618 }
1619
1620 /* If CTEInfo exists in prev PDU */
1621 if (ter_hdr_prev.cte_info) {
1622 ter_dptr_prev += sizeof(struct pdu_cte_info);
1623 }
1624 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1625
1626 /* ADI */
1627 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_ADI) {
1628 ter_hdr.adi = 1U;
1629 /* return the size of ADI structure */
1630 *(uint8_t *)hdr_data = sizeof(struct pdu_adv_adi);
1631 hdr_data = (uint8_t *)hdr_data + sizeof(uint8_t);
1632 /* pick the reference to ADI param */
1633 (void)memcpy(&adi, hdr_data, sizeof(struct pdu_adv_adi *));
1634 /* return the pointer to ADI struct inside the PDU */
1635 (void)memcpy(hdr_data, &ter_dptr, sizeof(ter_dptr));
1636 hdr_data = (uint8_t *)hdr_data + sizeof(ter_dptr);
1637 ter_dptr += sizeof(struct pdu_adv_adi);
1638 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_ADI) &&
1639 ter_hdr_prev.adi) {
1640 ter_hdr.adi = 1U;
1641 adi = NULL;
1642 ter_dptr += sizeof(struct pdu_adv_adi);
1643 } else {
1644 adi = NULL;
1645 }
1646 if (ter_hdr_prev.adi) {
1647 ter_dptr_prev += sizeof(struct pdu_adv_adi);
1648 }
1649
1650 /* AuxPtr - will be added if AUX_CHAIN_IND is required */
1651 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) {
1652 ter_hdr.aux_ptr = 1;
1653 aux_ptr_prev = NULL;
1654 aux_ptr = (void *)ter_dptr;
1655
1656 /* return the size of aux pointer structure */
1657 *(uint8_t *)hdr_data = sizeof(struct pdu_adv_aux_ptr);
1658 hdr_data = (uint8_t *)hdr_data + sizeof(uint8_t);
1659
1660 /* return the pointer to aux pointer struct inside the PDU
1661 * buffer
1662 */
1663 (void)memcpy(hdr_data, &ter_dptr, sizeof(ter_dptr));
1664 hdr_data = (uint8_t *)hdr_data + sizeof(ter_dptr);
1665 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) &&
1666 ter_hdr_prev.aux_ptr) {
1667 ter_hdr.aux_ptr = 1;
1668 aux_ptr_prev = (void *)ter_dptr_prev;
1669 aux_ptr = (void *)ter_dptr;
1670 } else {
1671 aux_ptr_prev = NULL;
1672 aux_ptr = NULL;
1673 }
1674 if (ter_hdr_prev.aux_ptr) {
1675 ter_dptr_prev += sizeof(struct pdu_adv_aux_ptr);
1676 }
1677 if (ter_hdr.aux_ptr) {
1678 ter_dptr += sizeof(struct pdu_adv_aux_ptr);
1679 }
1680
1681 /* No SyncInfo in AUX_SYNC_IND */
1682
1683 /* Tx Power flag */
1684 if (ter_hdr_prev.tx_pwr) {
1685 ter_dptr_prev++;
1686
1687 ter_hdr.tx_pwr = 1;
1688 ter_dptr++;
1689 }
1690
1691 /* Calc previous ACAD len and update PDU len */
1692 ter_len_prev = ter_dptr_prev - (uint8_t *)ter_com_hdr_prev;
1693 hdr_buf_len = ter_com_hdr_prev->ext_hdr_len +
1694 PDU_AC_EXT_HEADER_SIZE_MIN;
1695 if (ter_len_prev <= hdr_buf_len) {
1696 /* There are some data, except ACAD, in extended header if ter_len_prev
1697 * equals to hdr_buf_len. There is ACAD if the size of ter_len_prev
1698 * is smaller than hdr_buf_len.
1699 */
1700 acad_len_prev = hdr_buf_len - ter_len_prev;
1701 ter_len_prev += acad_len_prev;
1702 ter_dptr_prev += acad_len_prev;
1703 } else {
1704 /* There are no data in extended header, all flags are zeros. */
1705 acad_len_prev = 0;
1706 /* NOTE: If no flags are set then extended header length will be
1707 * zero. Under this condition the current ter_len_prev
1708 * value will be greater than extended header length,
1709 * hence set ter_len_prev to size of the length/mode
1710 * field.
1711 */
1712 ter_len_prev = PDU_AC_EXT_HEADER_SIZE_MIN;
1713 ter_dptr_prev = (uint8_t *)ter_com_hdr_prev + ter_len_prev;
1714 }
1715
1716 /* Did we parse beyond PDU length? */
1717 if (ter_len_prev > ter_pdu_prev->len) {
1718 /* we should not encounter invalid length */
1719 return BT_HCI_ERR_UNSPECIFIED;
1720 }
1721
1722 /* Add/Retain/Remove ACAD */
1723 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_ACAD) {
1724 /* remember the new acad data len */
1725 acad_len = *(uint8_t *)hdr_data;
1726
1727 /* return prev ACAD length */
1728 *(uint8_t *)hdr_data = acad_len_prev;
1729 hdr_data = (uint8_t *)hdr_data + sizeof(acad_len);
1730
1731 /* return the pointer to ACAD offset */
1732 (void)memcpy(hdr_data, &ter_dptr, sizeof(ter_dptr));
1733 hdr_data = (uint8_t *)hdr_data + sizeof(ter_dptr);
1734
1735 /* unchanged acad */
1736 if (!acad_len) {
1737 acad_len = acad_len_prev;
1738 }
1739
1740 ter_dptr += acad_len;
1741 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_ACAD)) {
1742 acad_len = acad_len_prev;
1743 ter_dptr += acad_len_prev;
1744 } else {
1745 acad_len = 0U;
1746 }
1747
1748 /* Calc current tertiary PDU len so far without AD data added */
1749 ter_len = ull_adv_aux_hdr_len_calc(ter_com_hdr, &ter_dptr);
1750
1751 /* Get Adv data from function parameters */
1752 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_AD_DATA) {
1753 uint8_t ad_len_prev;
1754
1755 /* remember the new ad data len */
1756 ad_len = *(uint8_t *)hdr_data;
1757
1758 /* return prev ad data length */
1759 ad_len_prev = ter_pdu_prev->len - ter_len_prev;
1760 *(uint8_t *)hdr_data = ad_len_prev;
1761 hdr_data = (uint8_t *)hdr_data + sizeof(ad_len);
1762
1763 /* remember the reference to new ad data */
1764 (void)memcpy(&ad_data, hdr_data, sizeof(ad_data));
1765
1766 /* return the reference to prev ad data */
1767 (void)memcpy(hdr_data, &ter_dptr_prev, sizeof(ter_dptr_prev));
1768 hdr_data = (uint8_t *)hdr_data + sizeof(ter_dptr_prev);
1769
1770 /* unchanged data */
1771 if (!ad_len && !ad_data) {
1772 ad_len = ad_len_prev;
1773 ad_data = ter_dptr_prev;
1774 }
1775 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_AD_DATA)) {
1776 ad_len = ter_pdu_prev->len - ter_len_prev;
1777 ad_data = ter_dptr_prev;
1778 } else {
1779 ad_len = 0;
1780 ad_data = NULL;
1781 }
1782
1783 /* Check Max Advertising Data Length */
1784 if (ad_len > CONFIG_BT_CTLR_ADV_DATA_LEN_MAX) {
1785 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1786 }
1787
1788 /* Check AdvData overflow */
1789 if ((ter_len + ad_len) > PDU_AC_PAYLOAD_SIZE_MAX) {
1790 /* return excess length */
1791 *(uint8_t *)hdr_data = ter_len + ad_len -
1792 PDU_AC_PAYLOAD_SIZE_MAX;
1793
1794 /* Will use packet too long error to determine fragmenting
1795 * long data
1796 */
1797 return BT_HCI_ERR_PACKET_TOO_LONG;
1798 }
1799
1800 LL_ASSERT(ter_len <= (PDU_AC_EXT_HEADER_SIZE_MIN + PDU_AC_EXT_HEADER_SIZE_MAX));
1801
1802 /* set the tertiary extended header and PDU length */
1803 ull_adv_aux_hdr_len_fill(ter_com_hdr, ter_len);
1804 ter_pdu->len = ter_len + ad_len;
1805
1806 /* Start filling tertiary PDU payload based on flags from here
1807 * ==============================================================
1808 */
1809
1810 /* Fill AdvData in tertiary PDU */
1811 (void)memmove(ter_dptr, ad_data, ad_len);
1812
1813 /* Early exit if no flags set */
1814 if (!ter_com_hdr->ext_hdr_len) {
1815 return 0;
1816 }
1817
1818 /* Retain ACAD in tertiary PDU */
1819 ter_dptr_prev -= acad_len_prev;
1820 if (acad_len) {
1821 ter_dptr -= acad_len;
1822 (void)memmove(ter_dptr, ter_dptr_prev, acad_len_prev);
1823 }
1824
1825 /* Tx Power */
1826 if (ter_hdr.tx_pwr) {
1827 *--ter_dptr = *--ter_dptr_prev;
1828 }
1829
1830 /* No SyncInfo in AUX_SYNC_IND */
1831
1832 /* AuxPtr */
1833 if (ter_hdr_prev.aux_ptr) {
1834 ter_dptr_prev -= sizeof(struct pdu_adv_aux_ptr);
1835 }
1836 if (ter_hdr.aux_ptr) {
1837 ter_dptr -= sizeof(struct pdu_adv_aux_ptr);
1838 }
1839 if (aux_ptr_prev) {
1840 (void)memmove(ter_dptr, aux_ptr_prev, sizeof(*aux_ptr_prev));
1841 }
1842
1843 /* ADI */
1844 if (ter_hdr_prev.adi) {
1845 ter_dptr_prev -= sizeof(struct pdu_adv_adi);
1846 }
1847 if (ter_hdr.adi) {
1848 struct pdu_adv_adi *adi_pdu;
1849
1850 ter_dptr -= sizeof(struct pdu_adv_adi);
1851 adi_pdu = (void *)ter_dptr;
1852
1853 if (!adi) {
1854 struct ll_adv_set *adv;
1855
1856 adv = HDR_LLL2ULL(lll_sync->adv);
1857
1858 /* The DID for a specific SID shall be unique.
1859 */
1860 const uint16_t did =
1861 sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid));
1862 PDU_ADV_ADI_DID_SID_SET(adi_pdu, did, adv->sid);
1863 } else {
1864 adi_pdu->did_sid_packed[0] = adi->did_sid_packed[0];
1865 adi_pdu->did_sid_packed[1] = adi->did_sid_packed[1];
1866 }
1867 }
1868
1869 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1870 if (ter_hdr.cte_info) {
1871 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
1872 *--ter_dptr = cte_info;
1873 } else {
1874 *--ter_dptr = *--ter_dptr_prev;
1875 }
1876 }
1877 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1878
1879 /* No TargetA in AUX_SYNC_IND */
1880 /* No AdvA in AUX_SYNC_IND */
1881
1882 if (ter_com_hdr->ext_hdr_len != 0) {
1883 ter_com_hdr->ext_hdr = ter_hdr;
1884 }
1885
1886 return 0;
1887 }
1888
1889 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1890 /* @brief Set or clear fields in extended advertising header and store
1891 * extra_data if requested.
1892 *
1893 * @param[in] extra_data_prev Pointer to previous content of extra_data.
1894 * @param[in] hdr_add_fields Flag with information which fields add.
1895 * @param[in] hdr_rem_fields Flag with information which fields remove.
1896 * @param[in] data Pointer to data to be stored in extra_data.
1897 * Content depends on the data depends on
1898 * @p hdr_add_fields.
1899 *
1900 * @Note
1901 * @p data depends on the flag provided by @p hdr_add_fields.
1902 * Information about content of value may be found in description of
1903 * @ref ull_adv_sync_pdu_set_clear.
1904 *
1905 * @return Zero in case of success, other value in case of failure.
1906 */
1907 void ull_adv_sync_extra_data_set_clear(void *extra_data_prev,
1908 void *extra_data_new,
1909 uint16_t hdr_add_fields,
1910 uint16_t hdr_rem_fields,
1911 void *data)
1912 {
1913 /* Currently only CTE enable requires extra_data. Due to that fact
1914 * CTE additional data are just copied to extra_data memory.
1915 */
1916 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
1917 (void)memcpy(extra_data_new, data, sizeof(struct lll_df_adv_cfg));
1918 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) ||
1919 extra_data_prev) {
1920 (void)memmove(extra_data_new, extra_data_prev,
1921 sizeof(struct lll_df_adv_cfg));
1922 }
1923 }
1924 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1925
1926 static int init_reset(void)
1927 {
1928 /* Initialize adv sync pool. */
1929 mem_init(ll_adv_sync_pool, sizeof(struct ll_adv_sync_set),
1930 sizeof(ll_adv_sync_pool) / sizeof(struct ll_adv_sync_set),
1931 &adv_sync_free);
1932
1933 return 0;
1934 }
1935
1936 static uint8_t adv_type_check(struct ll_adv_set *adv)
1937 {
1938 struct pdu_adv_com_ext_adv *pri_com_hdr;
1939 struct pdu_adv_ext_hdr *pri_hdr;
1940 struct pdu_adv *pri_pdu;
1941
1942 pri_pdu = lll_adv_data_latest_peek(&adv->lll);
1943 if (pri_pdu->type != PDU_ADV_TYPE_EXT_IND) {
1944 return BT_HCI_ERR_INVALID_PARAM;
1945 }
1946
1947 pri_com_hdr = (void *)&pri_pdu->adv_ext_ind;
1948 if (pri_com_hdr->adv_mode != 0U) {
1949 return BT_HCI_ERR_INVALID_PARAM;
1950 }
1951
1952 pri_hdr = (void *)pri_com_hdr->ext_hdr_adv_data;
1953 if (pri_hdr->aux_ptr) {
1954 struct pdu_adv_com_ext_adv *sec_com_hdr;
1955 struct pdu_adv_ext_hdr *sec_hdr;
1956 struct pdu_adv *sec_pdu;
1957
1958 sec_pdu = lll_adv_aux_data_latest_peek(adv->lll.aux);
1959 sec_com_hdr = (void *)&sec_pdu->adv_ext_ind;
1960 sec_hdr = (void *)sec_com_hdr->ext_hdr_adv_data;
1961 if (!pri_hdr->adv_addr && !sec_hdr->adv_addr) {
1962 return BT_HCI_ERR_INVALID_PARAM;
1963 }
1964 } else if (!pri_hdr->adv_addr) {
1965 return BT_HCI_ERR_INVALID_PARAM;
1966 }
1967
1968 return 0;
1969 }
1970
1971 static inline struct ll_adv_sync_set *sync_acquire(void)
1972 {
1973 return mem_acquire(&adv_sync_free);
1974 }
1975
1976 static inline void sync_release(struct ll_adv_sync_set *sync)
1977 {
1978 mem_release(sync, &adv_sync_free);
1979 }
1980
1981 static inline uint16_t sync_handle_get(const struct ll_adv_sync_set *sync)
1982 {
1983 return mem_index_get(sync, ll_adv_sync_pool,
1984 sizeof(struct ll_adv_sync_set));
1985 }
1986
1987 static uint32_t sync_time_get(const struct ll_adv_sync_set *sync,
1988 const struct pdu_adv *pdu)
1989 {
1990 uint8_t len;
1991
1992 /* Calculate the PDU Tx Time and hence the radio event length,
1993 * Always use maximum length for common extended header format so that
1994 * ACAD could be update when periodic advertising is active and the
1995 * time reservation need not be updated everytime avoiding overlapping
1996 * with other active states/roles.
1997 */
1998 len = pdu->len - pdu->adv_ext_ind.ext_hdr_len -
1999 PDU_AC_EXT_HEADER_SIZE_MIN + PDU_AC_EXT_HEADER_SIZE_MAX;
2000
2001 return ull_adv_sync_time_get(sync, len);
2002 }
2003
2004 static uint8_t sync_stop(struct ll_adv_sync_set *sync)
2005 {
2006 uint8_t sync_handle;
2007 int err;
2008
2009 sync_handle = sync_handle_get(sync);
2010
2011 err = ull_ticker_stop_with_mark(TICKER_ID_ADV_SYNC_BASE + sync_handle,
2012 sync, &sync->lll);
2013 LL_ASSERT(err == 0 || err == -EALREADY);
2014 if (err) {
2015 return BT_HCI_ERR_CMD_DISALLOWED;
2016 }
2017
2018 return 0;
2019 }
2020
2021 static inline uint8_t sync_remove(struct ll_adv_sync_set *sync,
2022 struct ll_adv_set *adv, uint8_t enable)
2023 {
2024 uint8_t pri_idx;
2025 uint8_t sec_idx;
2026 uint8_t err;
2027
2028 /* Remove sync_info from auxiliary PDU */
2029 err = ull_adv_aux_hdr_set_clear(adv, 0U,
2030 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO, NULL,
2031 &pri_idx, &sec_idx);
2032 if (err) {
2033 return err;
2034 }
2035
2036 lll_adv_aux_data_enqueue(adv->lll.aux, sec_idx);
2037 lll_adv_data_enqueue(&adv->lll, pri_idx);
2038
2039 if (sync->is_started) {
2040 /* TODO: we removed sync info, but if sync_stop() fails, what do
2041 * we do?
2042 */
2043 err = sync_stop(sync);
2044 if (err) {
2045 return err;
2046 }
2047
2048 sync->is_started = 0U;
2049
2050 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2051 if (adv->lll.aux) {
2052 /* notify the auxiliary set */
2053 ull_adv_sync_started_stopped(HDR_LLL2ULL(adv->lll.aux));
2054 }
2055 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2056 }
2057
2058 if (!enable) {
2059 sync->is_enabled = 0U;
2060 }
2061
2062 return 0U;
2063 }
2064
2065 static uint8_t sync_chm_update(uint8_t handle)
2066 {
2067 uint8_t hdr_data[ULL_ADV_HDR_DATA_LEN_SIZE +
2068 ULL_ADV_HDR_DATA_ACAD_PTR_SIZE];
2069 struct pdu_adv_sync_chm_upd_ind *chm_upd_ind;
2070 struct lll_adv_sync *lll_sync;
2071 struct pdu_adv *pdu_prev;
2072 struct ll_adv_set *adv;
2073 uint8_t acad_len_prev;
2074 struct pdu_adv *pdu;
2075 uint16_t instant;
2076 uint8_t chm_last;
2077 uint8_t ter_idx;
2078 uint8_t *acad;
2079 uint8_t err;
2080
2081 /* Check for valid advertising instance */
2082 adv = ull_adv_is_created_get(handle);
2083 if (!adv) {
2084 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
2085 }
2086
2087 /* Check for valid periodic advertising */
2088 lll_sync = adv->lll.sync;
2089 if (!lll_sync) {
2090 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
2091 }
2092
2093 /* Fail if already in progress */
2094 if (lll_sync->chm_last != lll_sync->chm_first) {
2095 return BT_HCI_ERR_CMD_DISALLOWED;
2096 }
2097
2098 /* Allocate next Sync PDU */
2099 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
2100 &pdu_prev, &pdu, NULL, NULL, &ter_idx);
2101 if (err) {
2102 return err;
2103 }
2104
2105 /* Try to allocate ACAD for channel map update indication, previous
2106 * ACAD length with be returned back.
2107 */
2108 hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = 0U;
2109 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
2110 ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
2111 &hdr_data);
2112 if (err) {
2113 return err;
2114 }
2115
2116 /* Check if there are other ACAD data previously and append to end of
2117 * other ACAD already present.
2118 */
2119 acad_len_prev = hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET];
2120 hdr_data[ULL_ADV_HDR_DATA_LEN_OFFSET] = acad_len_prev +
2121 sizeof(*chm_upd_ind) +
2122 2U;
2123 err = ull_adv_sync_pdu_set_clear(lll_sync, pdu_prev, pdu,
2124 ULL_ADV_PDU_HDR_FIELD_ACAD, 0U,
2125 &hdr_data);
2126 if (err) {
2127 return err;
2128 }
2129
2130 /* Populate the AD data length and opcode */
2131 (void)memcpy(&acad, &hdr_data[ULL_ADV_HDR_DATA_ACAD_PTR_OFFSET],
2132 sizeof(acad));
2133 acad += acad_len_prev;
2134 acad[PDU_ADV_DATA_HEADER_LEN_OFFSET] = sizeof(*chm_upd_ind) + 1U;
2135 acad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] =
2136 PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND;
2137
2138 /* Populate the Channel Map Indication structure */
2139 chm_upd_ind = (void *)&acad[PDU_ADV_DATA_HEADER_DATA_OFFSET];
2140 (void)ull_chan_map_get(chm_upd_ind->chm);
2141 instant = lll_sync->event_counter + 6U;
2142 chm_upd_ind->instant = sys_cpu_to_le16(instant);
2143
2144 /* Update the LLL to reflect the Channel Map and Instant to use */
2145 chm_last = lll_sync->chm_last + 1;
2146 if (chm_last == DOUBLE_BUFFER_SIZE) {
2147 chm_last = 0U;
2148 }
2149 lll_sync->chm[chm_last].data_chan_count =
2150 ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map);
2151 lll_sync->chm_instant = instant;
2152
2153 /* Commit the Channel Map Indication in the ACAD field of Periodic
2154 * Advertising
2155 */
2156 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
2157
2158 /* Initiate the Channel Map Indication */
2159 lll_sync->chm_last = chm_last;
2160
2161 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2162 struct ll_adv_sync_set *sync = HDR_LLL2ULL(lll_sync);
2163
2164 if (!sync->is_started) {
2165 /* Sync not started yet, apply new channel map now */
2166 lll_sync->chm_first = lll_sync->chm_last;
2167 }
2168 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2169
2170 return 0;
2171 }
2172
2173 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2174 void ull_adv_sync_lll_syncinfo_fill(struct pdu_adv *pdu, struct lll_adv_aux *lll_aux)
2175 {
2176 struct lll_adv_sync *lll_sync;
2177 struct pdu_adv_sync_info *si;
2178 uint8_t chm_first;
2179
2180 lll_sync = lll_aux->adv->sync;
2181
2182 si = sync_info_get(pdu);
2183 sync_info_offset_fill(si, lll_sync->us_adv_sync_pdu_offset);
2184 si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare +
2185 lll_sync->sync_lazy;
2186
2187 /* Fill the correct channel map to use if at or past the instant */
2188 if (lll_sync->chm_first != lll_sync->chm_last) {
2189 uint16_t instant_latency;
2190
2191 instant_latency = (si->evt_cntr - lll_sync->chm_instant) &
2192 EVENT_INSTANT_MAX;
2193 if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) {
2194 chm_first = lll_sync->chm_last;
2195 } else {
2196 chm_first = lll_sync->chm_first;
2197 }
2198 } else {
2199 chm_first = lll_sync->chm_first;
2200 }
2201 (void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map,
2202 sizeof(si->sca_chm));
2203 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
2204 ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
2205 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |=
2206 ((lll_clock_sca_local_get() <<
2207 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) &
2208 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK);
2209 }
2210
2211 static void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs)
2212 {
2213 if (offs >= OFFS_ADJUST_US) {
2214 offs -= OFFS_ADJUST_US;
2215 si->offs_adjust = 1U;
2216 }
2217
2218 offs = offs / OFFS_UNIT_30_US;
2219 if (!!(offs >> OFFS_UNIT_BITS)) {
2220 si->offs = sys_cpu_to_le16(offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US));
2221 si->offs_units = OFFS_UNIT_VALUE_300_US;
2222 } else {
2223 si->offs = sys_cpu_to_le16(offs);
2224 si->offs_units = OFFS_UNIT_VALUE_30_US;
2225 }
2226 }
2227
2228 #else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2229 static void mfy_sync_offset_get(void *param)
2230 {
2231 struct ll_adv_set *adv = param;
2232 struct lll_adv_sync *lll_sync;
2233 struct ll_adv_sync_set *sync;
2234 struct pdu_adv_sync_info *si;
2235 uint32_t sync_remainder_us;
2236 uint32_t aux_remainder_us;
2237 uint32_t ticks_to_expire;
2238 uint32_t ticks_current;
2239 struct pdu_adv *pdu;
2240 uint32_t remainder;
2241 uint8_t chm_first;
2242 uint8_t ticker_id;
2243 uint16_t lazy;
2244 uint8_t retry;
2245 uint8_t id;
2246
2247 lll_sync = adv->lll.sync;
2248 sync = HDR_LLL2ULL(lll_sync);
2249 ticker_id = TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync);
2250
2251 id = TICKER_NULL;
2252 ticks_to_expire = 0U;
2253 ticks_current = 0U;
2254 retry = 4U;
2255 do {
2256 uint32_t volatile ret_cb;
2257 uint32_t ticks_previous;
2258 uint32_t ret;
2259 bool success;
2260
2261 ticks_previous = ticks_current;
2262
2263 ret_cb = TICKER_STATUS_BUSY;
2264 ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR,
2265 TICKER_USER_ID_ULL_LOW,
2266 &id, &ticks_current,
2267 &ticks_to_expire, &remainder,
2268 &lazy, NULL, NULL,
2269 ticker_op_cb, (void *)&ret_cb);
2270 if (ret == TICKER_STATUS_BUSY) {
2271 while (ret_cb == TICKER_STATUS_BUSY) {
2272 ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
2273 TICKER_USER_ID_ULL_LOW);
2274 }
2275 }
2276
2277 success = (ret_cb == TICKER_STATUS_SUCCESS);
2278 LL_ASSERT(success);
2279
2280 LL_ASSERT((ticks_current == ticks_previous) || retry--);
2281
2282 LL_ASSERT(id != TICKER_NULL);
2283 } while (id != ticker_id);
2284
2285 /* Reduced a tick for negative remainder and return positive remainder
2286 * value.
2287 */
2288 hal_ticker_remove_jitter(&ticks_to_expire, &remainder);
2289 sync_remainder_us = remainder;
2290
2291 /* Add a tick for negative remainder and return positive remainder
2292 * value.
2293 */
2294 remainder = sync->aux_remainder;
2295 hal_ticker_add_jitter(&ticks_to_expire, &remainder);
2296 aux_remainder_us = remainder;
2297
2298 pdu = lll_adv_aux_data_latest_peek(adv->lll.aux);
2299 si = sync_info_get(pdu);
2300 sync_info_offset_fill(si, ticks_to_expire, sync_remainder_us,
2301 aux_remainder_us);
2302 si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare +
2303 lazy;
2304
2305 /* Fill the correct channel map to use if at or past the instant */
2306 if (lll_sync->chm_first != lll_sync->chm_last) {
2307 uint16_t instant_latency;
2308
2309 instant_latency = (si->evt_cntr - lll_sync->chm_instant) &
2310 EVENT_INSTANT_MAX;
2311 if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) {
2312 chm_first = lll_sync->chm_last;
2313 } else {
2314 chm_first = lll_sync->chm_first;
2315 }
2316 } else {
2317 chm_first = lll_sync->chm_first;
2318 }
2319 (void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map,
2320 sizeof(si->sca_chm));
2321 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
2322 ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
2323 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |=
2324 ((lll_clock_sca_local_get() <<
2325 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) &
2326 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK);
2327 }
2328
2329 static void sync_info_offset_fill(struct pdu_adv_sync_info *si,
2330 uint32_t ticks_offset,
2331 uint32_t remainder_us,
2332 uint32_t start_us)
2333 {
2334 uint32_t offs;
2335
2336 offs = HAL_TICKER_TICKS_TO_US(ticks_offset) + remainder_us - start_us;
2337
2338 if (offs >= OFFS_ADJUST_US) {
2339 offs -= OFFS_ADJUST_US;
2340 si->offs_adjust = 1U;
2341 }
2342
2343 offs = offs / OFFS_UNIT_30_US;
2344 if (!!(offs >> OFFS_UNIT_BITS)) {
2345 si->offs = sys_cpu_to_le16(offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US));
2346 si->offs_units = OFFS_UNIT_VALUE_300_US;
2347 } else {
2348 si->offs = sys_cpu_to_le16(offs);
2349 si->offs_units = OFFS_UNIT_VALUE_30_US;
2350 }
2351 }
2352
2353 static void ticker_op_cb(uint32_t status, void *param)
2354 {
2355 *((uint32_t volatile *)param) = status;
2356 }
2357 #endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2358
2359 static struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu)
2360 {
2361 struct pdu_adv_com_ext_adv *p;
2362 struct pdu_adv_ext_hdr *h;
2363 uint8_t *ptr;
2364
2365 p = (void *)&pdu->adv_ext_ind;
2366 h = (void *)p->ext_hdr_adv_data;
2367 ptr = h->data;
2368
2369 /* traverse through adv_addr, if present */
2370 if (h->adv_addr) {
2371 ptr += BDADDR_SIZE;
2372 }
2373
2374 /* traverse through tgt_addr, if present */
2375 if (h->tgt_addr) {
2376 ptr += BDADDR_SIZE;
2377 }
2378
2379 /* No CTEInfo flag in primary and secondary channel PDU */
2380
2381 /* traverse through adi, if present */
2382 if (h->adi) {
2383 ptr += sizeof(struct pdu_adv_adi);
2384 }
2385
2386 /* traverse through aux ptr, if present */
2387 if (h->aux_ptr) {
2388 ptr += sizeof(struct pdu_adv_aux_ptr);
2389 }
2390
2391 /* return pointer offset to sync_info */
2392 return (void *)ptr;
2393 }
2394
2395 static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
2396 uint32_t remainder, uint16_t lazy, uint8_t force,
2397 void *param)
2398 {
2399 static memq_link_t link;
2400 static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_sync_prepare};
2401 static struct lll_prepare_param p;
2402 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2403 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2404 struct ticker_ext_context *context = param;
2405 struct ll_adv_sync_set *sync = context->context;
2406 #else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2407 struct ll_adv_sync_set *sync = param;
2408 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2409 struct lll_adv_sync *lll;
2410 uint32_t ret;
2411 uint8_t ref;
2412
2413 DEBUG_RADIO_PREPARE_A(1);
2414
2415 lll = &sync->lll;
2416
2417 /* Increment prepare reference count */
2418 ref = ull_ref_inc(&sync->ull);
2419 LL_ASSERT(ref);
2420
2421 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2422 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2423 if (lll->iso) {
2424 struct lll_adv_iso *lll_iso = lll->iso;
2425
2426 LL_ASSERT(context->other_expire_info);
2427
2428 /* Check: No need for remainder in this case? */
2429 lll_iso->ticks_sync_pdu_offset = context->other_expire_info->ticks_to_expire;
2430 lll_iso->iso_lazy = context->other_expire_info->lazy;
2431 }
2432 #endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2433
2434 /* Append timing parameters */
2435 p.ticks_at_expire = ticks_at_expire;
2436 p.remainder = remainder;
2437 p.lazy = lazy;
2438 p.force = force;
2439 p.param = lll;
2440 mfy.param = &p;
2441
2442 /* Kick LLL prepare */
2443 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
2444 TICKER_USER_ID_LLL, 0, &mfy);
2445 LL_ASSERT(!ret);
2446
2447 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2448 !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2449 if (lll->iso) {
2450 ull_adv_iso_offset_get(sync);
2451 }
2452 #endif /* CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2453
2454 DEBUG_RADIO_PREPARE_A(1);
2455 }
2456
2457 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2458 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2459 static void ticker_update_op_cb(uint32_t status, void *param)
2460 {
2461 LL_ASSERT(status == TICKER_STATUS_SUCCESS ||
2462 param == ull_disable_mark_get());
2463 }
2464 #endif /* !CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2465