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