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 "ull_conn_internal.h"
47
48 #include "isoal.h"
49 #include "ull_iso_types.h"
50 #include "lll_conn_iso.h"
51 #include "ull_conn_iso_types.h"
52 #include "ull_llcp.h"
53
54 #include "ll.h"
55
56 #include "hal/debug.h"
57
58 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
59 /* First PDU contains up to PDU_AC_EXT_AD_DATA_LEN_MAX, next ones PDU_AC_EXT_PAYLOAD_SIZE_MAX */
60 #define PAYLOAD_BASED_FRAG_COUNT \
61 1U + DIV_ROUND_UP(MAX(0U, CONFIG_BT_CTLR_ADV_DATA_LEN_MAX - PDU_AC_EXT_AD_DATA_LEN_MAX), \
62 PDU_AC_EXT_PAYLOAD_SIZE_MAX)
63 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
64 #define MAX_FRAG_COUNT MAX(PAYLOAD_BASED_FRAG_COUNT, CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX)
65 #else
66 #define MAX_FRAG_COUNT PAYLOAD_BASED_FRAG_COUNT
67 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
68 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
69
70 static int init_reset(void);
71 static void ull_adv_sync_copy_pdu(const struct pdu_adv *pdu_prev,
72 struct pdu_adv *pdu);
73 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
74 static uint8_t ull_adv_sync_duplicate_chain(const struct pdu_adv *pdu_prev,
75 struct pdu_adv *pdu);
76 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
77 static uint8_t ull_adv_sync_ad_add(struct lll_adv_sync *lll_sync,
78 struct pdu_adv *ter_pdu_prev,
79 struct pdu_adv *ter_pdu,
80 const uint8_t *ad, uint8_t ad_len);
81 static uint8_t ull_adv_sync_ad_replace(struct lll_adv_sync *lll_sync,
82 struct pdu_adv *ter_pdu_prev,
83 struct pdu_adv *ter_pdu,
84 const uint8_t *ad, uint8_t ad_len);
85 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
86 static uint8_t ull_adv_sync_update_adi(struct lll_adv_sync *lll_sync,
87 struct pdu_adv *ter_pdu_prev,
88 struct pdu_adv *ter_pdu);
89 static uint8_t ull_adv_sync_add_adi(struct lll_adv_sync *lll_sync,
90 struct pdu_adv *pdu_prev,
91 struct pdu_adv *pdu);
92 static uint8_t ull_adv_sync_remove_adi(struct lll_adv_sync *lll_sync,
93 struct pdu_adv *pdu_prev,
94 struct pdu_adv *pdu);
95 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
96 static uint8_t adv_type_check(struct ll_adv_set *adv);
97 static inline struct ll_adv_sync_set *sync_acquire(void);
98 static inline void sync_release(struct ll_adv_sync_set *sync);
99 static inline uint16_t sync_handle_get(const struct ll_adv_sync_set *sync);
100 static uint32_t sync_time_get(const struct ll_adv_sync_set *sync,
101 const struct pdu_adv *pdu);
102 static inline uint8_t sync_remove(struct ll_adv_sync_set *sync,
103 struct ll_adv_set *adv, uint8_t enable);
104 static uint8_t sync_chm_update(uint8_t handle);
105
106 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
107 static void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs);
108
109 #else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
110 static void mfy_sync_offset_get(void *param);
111 static void sync_info_offset_fill(struct pdu_adv_sync_info *si,
112 uint32_t ticks_offset,
113 uint32_t remainder_us,
114 uint32_t start_us);
115 static void ticker_op_cb(uint32_t status, void *param);
116 #endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
117
118 static struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu);
119 static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
120 uint32_t remainder, uint16_t lazy, uint8_t force,
121 void *param);
122
123 #if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
124 static void ticker_update_op_cb(uint32_t status, void *param);
125
126 static struct ticker_ext ll_adv_sync_ticker_ext[CONFIG_BT_CTLR_ADV_SYNC_SET];
127 #endif /* !CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
128
129 static struct ll_adv_sync_set ll_adv_sync_pool[CONFIG_BT_CTLR_ADV_SYNC_SET];
130 static void *adv_sync_free;
131
ll_adv_sync_param_set(uint8_t handle,uint16_t interval,uint16_t flags)132 uint8_t ll_adv_sync_param_set(uint8_t handle, uint16_t interval, uint16_t flags)
133 {
134 void *extra_data_prev, *extra_data;
135 struct pdu_adv *pdu_prev, *pdu;
136 struct lll_adv_sync *lll_sync;
137 struct ll_adv_sync_set *sync;
138 struct ll_adv_set *adv;
139 uint8_t err, ter_idx;
140
141 adv = ull_adv_is_created_get(handle);
142 if (!adv) {
143 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
144 }
145
146 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) {
147 err = adv_type_check(adv);
148 if (err) {
149 return err;
150 }
151 }
152
153 lll_sync = adv->lll.sync;
154 if (!lll_sync) {
155 struct pdu_adv *ter_pdu;
156 struct lll_adv *lll;
157 uint8_t chm_last;
158
159 sync = sync_acquire();
160 if (!sync) {
161 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
162 }
163
164 lll = &adv->lll;
165 lll_sync = &sync->lll;
166 lll->sync = lll_sync;
167 lll_sync->adv = lll;
168
169 lll_adv_data_reset(&lll_sync->data);
170 err = lll_adv_sync_data_init(&lll_sync->data);
171 if (err) {
172 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
173 }
174
175 /* NOTE: ull_hdr_init(&sync->ull); is done on start */
176 lll_hdr_init(lll_sync, sync);
177
178 err = util_aa_le32(lll_sync->access_addr);
179 LL_ASSERT(!err);
180
181 lll_sync->data_chan_id = lll_chan_id(lll_sync->access_addr);
182 chm_last = lll_sync->chm_first;
183 lll_sync->chm_last = chm_last;
184 lll_sync->chm[chm_last].data_chan_count =
185 ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map);
186
187 lll_csrand_get(lll_sync->crc_init, sizeof(lll_sync->crc_init));
188
189 lll_sync->latency_prepare = 0;
190 lll_sync->latency_event = 0;
191 lll_sync->event_counter = 0;
192
193 #if defined(CONFIG_BT_CTLR_ADV_PDU_LINK)
194 lll_sync->data_chan_counter = 0U;
195 #endif /* CONFIG_BT_CTLR_ADV_PDU_LINK */
196
197 sync->is_enabled = 0U;
198 sync->is_started = 0U;
199
200 ter_pdu = lll_adv_sync_data_peek(lll_sync, NULL);
201 ull_adv_sync_pdu_init(ter_pdu, 0U, 0U, 0U, NULL);
202 } else {
203 sync = HDR_LLL2ULL(lll_sync);
204 }
205
206 /* Periodic Advertising is already started */
207 if (sync->is_started) {
208 return BT_HCI_ERR_CMD_DISALLOWED;
209 }
210
211 sync->interval = interval;
212
213 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST, &pdu_prev, &pdu,
214 &extra_data_prev, &extra_data, &ter_idx);
215 if (err) {
216 return err;
217 }
218
219 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
220 if (extra_data) {
221 ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data,
222 0U, 0U, NULL);
223 }
224 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
225
226 /* FIXME - handle flags (i.e. adding TxPower if specified) */
227 err = ull_adv_sync_duplicate(pdu_prev, pdu);
228 if (err) {
229 return err;
230 }
231
232 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
233
234 sync->is_data_cmplt = 1U;
235
236 return 0;
237 }
238
239 #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)240 void ull_adv_sync_iso_created(struct ll_adv_sync_set *sync)
241 {
242 if (sync->lll.iso && sync->is_started) {
243 uint8_t iso_handle = sync->lll.iso->handle;
244 uint8_t handle = sync_handle_get(sync);
245
246 ticker_update_ext(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
247 (TICKER_ID_ADV_SYNC_BASE + handle), 0, 0, 0, 0, 0, 0,
248 ticker_update_op_cb, sync, 0, TICKER_ID_ADV_ISO_BASE + iso_handle);
249 }
250 }
251 #endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
252
ll_adv_sync_ad_data_set(uint8_t handle,uint8_t op,uint8_t len,uint8_t const * const data)253 uint8_t ll_adv_sync_ad_data_set(uint8_t handle, uint8_t op, uint8_t len,
254 uint8_t const *const data)
255 {
256 void *extra_data_prev, *extra_data;
257 struct pdu_adv *pdu_prev, *pdu;
258 struct lll_adv_sync *lll_sync;
259 struct ll_adv_sync_set *sync;
260 struct ll_adv_set *adv;
261 uint8_t ter_idx;
262 uint8_t err;
263
264 /* Check for valid advertising set */
265 adv = ull_adv_is_created_get(handle);
266 if (!adv) {
267 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
268 }
269
270 /* Check for advertising set type */
271 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) {
272 err = adv_type_check(adv);
273 if (err) {
274 return err;
275 }
276 }
277
278 /* Check if periodic advertising is associated with advertising set */
279 lll_sync = adv->lll.sync;
280 if (!lll_sync) {
281 return BT_HCI_ERR_CMD_DISALLOWED;
282 }
283
284 sync = HDR_LLL2ULL(lll_sync);
285
286 /* Reject setting fragment when periodic advertising is enabled */
287 if (sync->is_enabled && (op <= BT_HCI_LE_EXT_ADV_OP_LAST_FRAG)) {
288 return BT_HCI_ERR_CMD_DISALLOWED;
289 }
290
291 /* Reject intermediate op before first op */
292 if (sync->is_data_cmplt &&
293 ((op == BT_HCI_LE_EXT_ADV_OP_INTERM_FRAG) ||
294 (op == BT_HCI_LE_EXT_ADV_OP_LAST_FRAG))) {
295 return BT_HCI_ERR_CMD_DISALLOWED;
296 }
297
298 /* Reject unchanged op before complete status */
299 if (!sync->is_data_cmplt &&
300 (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA)) {
301 return BT_HCI_ERR_CMD_DISALLOWED;
302 }
303
304 /* Reject len > 191 bytes if chain PDUs unsupported */
305 if (!IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) &&
306 (len > PDU_AC_EXT_AD_DATA_LEN_MAX)) {
307 return BT_HCI_ERR_CMD_DISALLOWED;
308 }
309
310 /* Allocate new PDU buffer at latest double buffer index */
311 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
312 &pdu_prev, &pdu, &extra_data_prev,
313 &extra_data, &ter_idx);
314 if (err) {
315 return err;
316 }
317
318 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
319 if (extra_data) {
320 ull_adv_sync_extra_data_set_clear(extra_data_prev, extra_data,
321 0U, 0U, NULL);
322 }
323 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
324
325 if (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA) {
326 /* Only update ADI */
327 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
328 err = ull_adv_sync_update_adi(lll_sync, pdu_prev, pdu);
329 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
330 } else if (op == BT_HCI_LE_EXT_ADV_OP_FIRST_FRAG ||
331 op == BT_HCI_LE_EXT_ADV_OP_COMPLETE_DATA) {
332 err = ull_adv_sync_ad_replace(lll_sync, pdu_prev, pdu, data, len);
333 } else {
334 err = ull_adv_sync_ad_add(lll_sync, pdu_prev, pdu, data, len);
335 }
336 if (err) {
337 return err;
338 }
339
340 /* Parameter validation, if operation is 0x04 (unchanged data)
341 * - periodic advertising is disabled, or
342 * - periodic advertising contains no data, or
343 * - Advertising Data Length is not zero
344 */
345 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK) &&
346 (op == BT_HCI_LE_EXT_ADV_OP_UNCHANGED_DATA) &&
347 ((!sync->is_enabled) ||
348 (pdu->len == pdu->adv_ext_ind.ext_hdr_len + 1U) ||
349 (len != 0U))) {
350 /* NOTE: latest PDU was not consumed by LLL and as
351 * ull_adv_sync_pdu_alloc() has reverted back the double buffer
352 * with the first PDU, and returned the latest PDU as the new
353 * PDU, we need to enqueue back the new PDU which is in fact
354 * the latest PDU.
355 */
356 if (pdu_prev == pdu) {
357 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
358 }
359
360 return BT_HCI_ERR_INVALID_PARAM;
361 }
362
363 /* Update time reservation if Periodic Advertising events are active */
364 if (sync->is_started) {
365 err = ull_adv_sync_time_update(sync, pdu);
366 if (err) {
367 return err;
368 }
369 }
370
371 /* Commit the updated Periodic Advertising Data */
372 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
373
374 /* Check if Periodic Advertising Data is complete */
375 sync->is_data_cmplt = (op >= BT_HCI_LE_EXT_ADV_OP_LAST_FRAG);
376
377 return 0;
378 }
379
ll_adv_sync_enable(uint8_t handle,uint8_t enable)380 uint8_t ll_adv_sync_enable(uint8_t handle, uint8_t enable)
381 {
382 struct pdu_adv *ter_pdu = NULL;
383 struct lll_adv_sync *lll_sync;
384 struct ll_adv_sync_set *sync;
385 uint8_t sync_got_enabled;
386 struct ll_adv_set *adv;
387 uint8_t ter_idx;
388 uint8_t err;
389
390 /* Check for valid advertising set */
391 adv = ull_adv_is_created_get(handle);
392 if (!adv) {
393 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
394 }
395
396 /* Check if periodic advertising is associated with advertising set */
397 lll_sync = adv->lll.sync;
398 if (!lll_sync) {
399 return BT_HCI_ERR_CMD_DISALLOWED;
400 }
401
402 /* Check for invalid enable bit fields */
403 if ((enable > (BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE |
404 BT_HCI_LE_SET_PER_ADV_ENABLE_ADI)) ||
405 (!IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
406 (enable > BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE))) {
407 return BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL;
408 }
409
410 sync = HDR_LLL2ULL(lll_sync);
411
412 /* Handle periodic advertising being disable */
413 if (!(enable & BT_HCI_LE_SET_PER_ADV_ENABLE_ENABLE)) {
414 if (!sync->is_enabled) {
415 return BT_HCI_ERR_CMD_DISALLOWED;
416 }
417
418 if (!sync->is_started) {
419 sync->is_enabled = 0U;
420
421 return 0;
422 }
423
424 err = sync_remove(sync, adv, 0U);
425 return err;
426 }
427
428 /* Check for advertising set type */
429 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK)) {
430 err = adv_type_check(adv);
431 if (err) {
432 return BT_HCI_ERR_CMD_DISALLOWED;
433 }
434 }
435
436 /* Check for periodic data being complete */
437 if (!sync->is_data_cmplt) {
438 return BT_HCI_ERR_CMD_DISALLOWED;
439 }
440
441 /* TODO: Check packet too long */
442
443 /* Check for already enabled periodic advertising set */
444 sync_got_enabled = 0U;
445 if (sync->is_enabled) {
446 /* TODO: Enabling an already enabled advertising changes its
447 * random address.
448 */
449 } else {
450 sync_got_enabled = 1U;
451 }
452
453 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
454 /* Add/Remove ADI */
455 {
456 void *extra_data_prev, *extra_data;
457 struct pdu_adv *pdu_prev, *pdu;
458
459 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
460 &pdu_prev, &pdu, &extra_data_prev,
461 &extra_data, &ter_idx);
462 if (err) {
463 return err;
464 }
465
466 /* Use PDU to calculate time reservation */
467 ter_pdu = pdu;
468
469 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
470 if (extra_data) {
471 ull_adv_sync_extra_data_set_clear(extra_data_prev,
472 extra_data, 0U, 0U,
473 NULL);
474 }
475 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
476
477 if (enable & BT_HCI_LE_SET_PER_ADV_ENABLE_ADI) {
478 ull_adv_sync_add_adi(lll_sync, pdu_prev, pdu);
479 } else {
480 ull_adv_sync_remove_adi(lll_sync, pdu_prev, pdu);
481 }
482 }
483 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
484
485 /* Start Periodic Advertising events if Extended Advertising events are
486 * active.
487 */
488 if (adv->is_enabled && !sync->is_started) {
489 struct pdu_adv_sync_info *sync_info;
490 uint8_t value[1 + sizeof(sync_info)];
491 uint32_t ticks_slot_overhead_aux;
492 uint32_t ticks_slot_overhead;
493 struct lll_adv_aux *lll_aux;
494 struct ll_adv_aux_set *aux;
495 uint32_t ticks_anchor_sync;
496 uint32_t ticks_anchor_aux;
497 uint8_t pri_idx, sec_idx;
498 uint32_t ret;
499
500 lll_aux = adv->lll.aux;
501
502 /* Add sync_info into auxiliary PDU */
503 err = ull_adv_aux_hdr_set_clear(adv,
504 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO,
505 0U, value, &pri_idx, &sec_idx);
506 if (err) {
507 return err;
508 }
509
510 /* First byte in the length-value encoded parameter is size of
511 * sync_info structure, followed by pointer to sync_info in the
512 * PDU.
513 */
514 (void)memcpy(&sync_info, &value[1], sizeof(sync_info));
515 ull_adv_sync_info_fill(sync, sync_info);
516
517 /* Calculate the ticks_slot and return slot overhead */
518 ticks_slot_overhead = ull_adv_sync_evt_init(adv, sync, ter_pdu);
519
520 /* If Auxiliary PDU already active, find and schedule Periodic
521 * advertising follow it.
522 */
523 if (lll_aux) {
524 /* Auxiliary set already active (due to other fields
525 * being already present or being started prior).
526 */
527 aux = NULL;
528 ticks_anchor_aux = 0U; /* unused in this path */
529 ticks_slot_overhead_aux = 0U; /* unused in this path */
530
531 /* Find the anchor after the group of active auxiliary
532 * sets such that Periodic Advertising events are placed
533 * in non-overlapping timeline when auxiliary and
534 * Periodic Advertising have similar event interval.
535 */
536 ticks_anchor_sync = ticker_ticks_now_get() +
537 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
538
539 #if defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
540 err = ull_sched_adv_aux_sync_free_anchor_get(sync->ull.ticks_slot,
541 &ticks_anchor_sync);
542 if (!err) {
543 ticks_anchor_sync += HAL_TICKER_US_TO_TICKS(
544 MAX(EVENT_MAFS_US,
545 EVENT_OVERHEAD_START_US) -
546 EVENT_OVERHEAD_START_US +
547 (EVENT_TICKER_RES_MARGIN_US << 1));
548 }
549 #endif /* CONFIG_BT_CTLR_SCHED_ADVANCED */
550
551 } else {
552 /* Auxiliary set will be started due to inclusion of
553 * sync info field.
554 */
555 lll_aux = adv->lll.aux;
556 aux = HDR_LLL2ULL(lll_aux);
557 ticks_anchor_aux = ticker_ticks_now_get() +
558 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
559 ticks_slot_overhead_aux =
560 ull_adv_aux_evt_init(aux, &ticks_anchor_aux);
561
562 #if !defined(CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET) || \
563 (CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET == 0)
564 ticks_anchor_sync = ticks_anchor_aux +
565 ticks_slot_overhead_aux + aux->ull.ticks_slot +
566 HAL_TICKER_US_TO_TICKS(
567 MAX(EVENT_MAFS_US,
568 EVENT_OVERHEAD_START_US) -
569 EVENT_OVERHEAD_START_US +
570 (EVENT_TICKER_RES_MARGIN_US << 1));
571
572 #else /* CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET */
573 ticks_anchor_sync = ticks_anchor_aux +
574 HAL_TICKER_US_TO_TICKS(
575 CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET);
576
577 #endif /* CONFIG_BT_CTLR_ADV_AUX_SYNC_OFFSET */
578 }
579
580 ret = ull_adv_sync_start(adv, sync, ticks_anchor_sync,
581 ticks_slot_overhead);
582 if (ret) {
583 sync_remove(sync, adv, 1U);
584
585 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
586 }
587
588 sync->is_started = 1U;
589
590 lll_adv_aux_data_enqueue(lll_aux, sec_idx);
591 lll_adv_data_enqueue(&adv->lll, pri_idx);
592
593 if (aux) {
594 /* Keep aux interval equal or higher than primary PDU
595 * interval.
596 */
597 aux->interval = adv->interval +
598 (HAL_TICKER_TICKS_TO_US(
599 ULL_ADV_RANDOM_DELAY) /
600 ADV_INT_UNIT_US);
601
602 ret = ull_adv_aux_start(aux, ticks_anchor_aux,
603 ticks_slot_overhead_aux);
604 if (ret) {
605 sync_remove(sync, adv, 1U);
606
607 return BT_HCI_ERR_INSUFFICIENT_RESOURCES;
608 }
609
610 aux->is_started = 1U;
611
612 } else if (IS_ENABLED(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)) {
613 /* notify the auxiliary set */
614 ull_adv_sync_started_stopped(HDR_LLL2ULL(lll_aux));
615 }
616 }
617
618 /* Commit the Periodic Advertising data if ADI supported and has been
619 * updated.
620 */
621 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)) {
622 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
623 }
624
625 if (sync_got_enabled) {
626 sync->is_enabled = sync_got_enabled;
627 }
628
629 return 0;
630 }
631
632 #if defined(CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER)
633 /* @brief Link Layer interface function corresponding to HCI LE Periodic
634 * Advertising Set Info Transfer command.
635 *
636 * @param[in] conn_handle Connection_Handle identifying the connected device
637 * Range: 0x0000 to 0x0EFF.
638 * @param[in] service_data Service_Data value provided by the Host for use by the
639 * Host of the peer device.
640 * @param[in] adv_handle Advertising_Handle identifying the advertising
641 * set. Range: 0x00 to 0xEF.
642 *
643 * @return HCI error codes as documented in Bluetooth Core Specification v5.4.
644 */
ll_adv_sync_set_info_transfer(uint16_t conn_handle,uint16_t service_data,uint8_t adv_handle)645 uint8_t ll_adv_sync_set_info_transfer(uint16_t conn_handle, uint16_t service_data,
646 uint8_t adv_handle)
647 {
648 struct ll_adv_sync_set *sync;
649 struct ll_adv_set *adv;
650 struct ll_conn *conn;
651
652 conn = ll_connected_get(conn_handle);
653 if (!conn) {
654 return BT_HCI_ERR_UNKNOWN_CONN_ID;
655 }
656
657 /* Verify that adv_handle is valid and periodic advertising is enabled */
658 adv = ull_adv_is_created_get(adv_handle);
659 if (!adv) {
660 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
661 }
662
663 if (!adv->lll.sync) {
664 return BT_HCI_ERR_CMD_DISALLOWED;
665 }
666
667 sync = HDR_LLL2ULL(adv->lll.sync);
668 if (!sync->is_enabled) {
669 return BT_HCI_ERR_CMD_DISALLOWED;
670 }
671
672 /* Call llcp to start LLCP_PERIODIC_SYNC_IND */
673 return ull_cp_periodic_sync(conn, NULL, sync, service_data);
674 }
675 #endif /* CONFIG_BT_CTLR_SYNC_TRANSFER_SENDER */
676
ull_adv_sync_init(void)677 int ull_adv_sync_init(void)
678 {
679 int err;
680
681 err = init_reset();
682 if (err) {
683 return err;
684 }
685
686 return 0;
687 }
688
ull_adv_sync_reset(void)689 int ull_adv_sync_reset(void)
690 {
691 struct lll_adv_sync *lll_sync;
692 struct ll_adv_sync_set *sync;
693 struct ll_adv_set *adv;
694 uint8_t handle;
695 int err;
696
697 for (handle = 0U; handle < BT_CTLR_ADV_SET; handle++) {
698 adv = ull_adv_is_created_get(handle);
699 if (!adv) {
700 continue;
701 }
702
703 lll_sync = adv->lll.sync;
704 if (!lll_sync) {
705 continue;
706 }
707
708 sync = HDR_LLL2ULL(lll_sync);
709
710 if (!sync->is_started) {
711 sync->is_enabled = 0U;
712
713 continue;
714 }
715
716 err = sync_remove(sync, adv, 0U);
717 if (err) {
718 return err;
719 }
720 }
721
722 return 0;
723 }
724
ull_adv_sync_reset_finalize(void)725 int ull_adv_sync_reset_finalize(void)
726 {
727 int err;
728
729 err = init_reset();
730 if (err) {
731 return err;
732 }
733
734 return 0;
735 }
736
ull_adv_sync_get(uint8_t handle)737 struct ll_adv_sync_set *ull_adv_sync_get(uint8_t handle)
738 {
739 if (handle >= CONFIG_BT_CTLR_ADV_SYNC_SET) {
740 return NULL;
741 }
742
743 return &ll_adv_sync_pool[handle];
744 }
745
ull_adv_sync_handle_get(const struct ll_adv_sync_set * sync)746 uint16_t ull_adv_sync_handle_get(const struct ll_adv_sync_set *sync)
747 {
748 return sync_handle_get(sync);
749 }
750
ull_adv_sync_lll_handle_get(const struct lll_adv_sync * lll)751 uint16_t ull_adv_sync_lll_handle_get(const struct lll_adv_sync *lll)
752 {
753 return sync_handle_get((void *)lll->hdr.parent);
754 }
755
ull_adv_sync_release(struct ll_adv_sync_set * sync)756 void ull_adv_sync_release(struct ll_adv_sync_set *sync)
757 {
758 lll_adv_sync_data_release(&sync->lll);
759 sync_release(sync);
760 }
761
ull_adv_sync_time_get(const struct ll_adv_sync_set * sync,uint8_t pdu_len)762 uint32_t ull_adv_sync_time_get(const struct ll_adv_sync_set *sync,
763 uint8_t pdu_len)
764 {
765 const struct lll_adv_sync *lll_sync = &sync->lll;
766 const struct lll_adv *lll = lll_sync->adv;
767 uint32_t time_us;
768
769 /* NOTE: 16-bit values are sufficient for minimum radio event time
770 * reservation, 32-bit are used here so that reservations for
771 * whole back-to-back chaining of PDUs can be accommodated where
772 * the required microseconds could overflow 16-bits, example,
773 * back-to-back chained Coded PHY PDUs.
774 */
775
776 time_us = PDU_AC_US(pdu_len, lll->phy_s, lll->phy_flags) +
777 EVENT_OVERHEAD_START_US + EVENT_OVERHEAD_END_US;
778
779 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
780 struct ll_adv_set *adv = HDR_LLL2ULL(lll);
781 struct lll_df_adv_cfg *df_cfg = adv->df_cfg;
782
783 if (df_cfg && df_cfg->is_enabled) {
784 time_us += CTE_LEN_US(df_cfg->cte_length);
785 }
786 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
787
788 return time_us;
789 }
790
ull_adv_sync_evt_init(struct ll_adv_set * adv,struct ll_adv_sync_set * sync,struct pdu_adv * pdu)791 uint32_t ull_adv_sync_evt_init(struct ll_adv_set *adv,
792 struct ll_adv_sync_set *sync,
793 struct pdu_adv *pdu)
794 {
795 uint32_t ticks_slot_overhead;
796 uint32_t ticks_slot_offset;
797 uint32_t time_us;
798
799 ull_hdr_init(&sync->ull);
800
801 if (!pdu) {
802 pdu = lll_adv_sync_data_peek(&sync->lll, NULL);
803 }
804
805 time_us = sync_time_get(sync, pdu);
806
807 sync->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL(time_us);
808
809 ticks_slot_offset = HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
810 if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
811 ticks_slot_overhead = ticks_slot_offset;
812 } else {
813 ticks_slot_overhead = 0U;
814 }
815
816 return ticks_slot_overhead;
817 }
818
ull_adv_sync_start(struct ll_adv_set * adv,struct ll_adv_sync_set * sync,uint32_t ticks_anchor,uint32_t ticks_slot_overhead)819 uint32_t ull_adv_sync_start(struct ll_adv_set *adv,
820 struct ll_adv_sync_set *sync,
821 uint32_t ticks_anchor,
822 uint32_t ticks_slot_overhead)
823 {
824 uint32_t volatile ret_cb;
825 uint32_t interval_us;
826 uint8_t sync_handle;
827 uint32_t ret;
828
829 interval_us = (uint32_t)sync->interval * PERIODIC_INT_UNIT_US;
830
831 sync_handle = sync_handle_get(sync);
832
833 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
834 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
835 if (sync->lll.iso) {
836 ll_adv_sync_ticker_ext[sync_handle].expire_info_id =
837 TICKER_ID_ADV_ISO_BASE + sync->lll.iso->handle;
838 } else {
839 ll_adv_sync_ticker_ext[sync_handle].expire_info_id = TICKER_NULL;
840 }
841
842 ll_adv_sync_ticker_ext[sync_handle].ext_timeout_func = ticker_cb;
843
844 ret_cb = TICKER_STATUS_BUSY;
845 ret = ticker_start_ext(
846 #else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
847
848 ret_cb = TICKER_STATUS_BUSY;
849 ret = ticker_start(
850 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
851 TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
852 (TICKER_ID_ADV_SYNC_BASE + sync_handle),
853 ticks_anchor, 0U,
854 HAL_TICKER_US_TO_TICKS(interval_us),
855 HAL_TICKER_REMAINDER(interval_us), TICKER_NULL_LAZY,
856 (sync->ull.ticks_slot + ticks_slot_overhead),
857 ticker_cb, sync,
858 ull_ticker_status_give, (void *)&ret_cb
859 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
860 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
861 ,
862 &ll_adv_sync_ticker_ext[sync_handle]
863 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
864 );
865 ret = ull_ticker_status_take(ret, &ret_cb);
866
867 return ret;
868 }
869
ull_adv_sync_time_update(struct ll_adv_sync_set * sync,struct pdu_adv * pdu)870 uint8_t ull_adv_sync_time_update(struct ll_adv_sync_set *sync,
871 struct pdu_adv *pdu)
872 {
873 uint32_t time_ticks;
874 uint32_t time_us;
875
876 time_us = sync_time_get(sync, pdu);
877 time_ticks = HAL_TICKER_US_TO_TICKS(time_us);
878
879 #if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
880 uint32_t volatile ret_cb;
881 uint32_t ticks_minus;
882 uint32_t ticks_plus;
883 uint32_t ret;
884
885 if (sync->ull.ticks_slot > time_ticks) {
886 ticks_minus = sync->ull.ticks_slot - time_ticks;
887 ticks_plus = 0U;
888 } else if (sync->ull.ticks_slot < time_ticks) {
889 ticks_minus = 0U;
890 ticks_plus = time_ticks - sync->ull.ticks_slot;
891 } else {
892 return BT_HCI_ERR_SUCCESS;
893 }
894
895 ret_cb = TICKER_STATUS_BUSY;
896 ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
897 TICKER_USER_ID_THREAD,
898 (TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync)),
899 0, 0, ticks_plus, ticks_minus, 0, 0,
900 ull_ticker_status_give, (void *)&ret_cb);
901 ret = ull_ticker_status_take(ret, &ret_cb);
902 if (ret != TICKER_STATUS_SUCCESS) {
903 return BT_HCI_ERR_CMD_DISALLOWED;
904 }
905 #endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
906
907 sync->ull.ticks_slot = time_ticks;
908
909 return BT_HCI_ERR_SUCCESS;
910 }
911
ull_adv_sync_chm_update(void)912 uint8_t ull_adv_sync_chm_update(void)
913 {
914 uint8_t handle;
915
916 handle = CONFIG_BT_CTLR_ADV_SYNC_SET;
917 while (handle--) {
918 (void)sync_chm_update(handle);
919 }
920
921 /* TODO: Should failure due to Channel Map Update being already in
922 * progress be returned to caller?
923 */
924 return 0;
925 }
926
ull_adv_sync_chm_complete(struct node_rx_pdu * rx)927 void ull_adv_sync_chm_complete(struct node_rx_pdu *rx)
928 {
929 struct lll_adv_sync *lll_sync;
930 struct pdu_adv *pdu_prev;
931 struct ll_adv_set *adv;
932 struct pdu_adv *pdu;
933 uint8_t ter_idx;
934 uint8_t err;
935
936 /* Allocate next Sync PDU */
937 pdu_prev = NULL;
938 pdu = NULL;
939 lll_sync = rx->rx_ftr.param;
940 adv = HDR_LLL2ULL(lll_sync->adv);
941 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
942 &pdu_prev, &pdu, NULL, NULL, &ter_idx);
943 LL_ASSERT(!err);
944
945 err = ull_adv_sync_remove_from_acad(lll_sync, pdu_prev, pdu,
946 PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND);
947 LL_ASSERT(!err);
948
949 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
950 }
951
ull_adv_sync_info_fill(struct ll_adv_sync_set * sync,struct pdu_adv_sync_info * si)952 void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync,
953 struct pdu_adv_sync_info *si)
954 {
955 struct lll_adv_sync *lll_sync;
956
957 /* NOTE: sync offset and offset unit filled by secondary prepare.
958 *
959 * If sync_info is part of ADV PDU the offs_adjust field
960 * is always set to 0.
961 */
962 PDU_ADV_SYNC_INFO_OFFS_SET(si, 0U, OFFS_UNIT_VALUE_30_US, 0U);
963
964 /* Fill the interval, access address and CRC init */
965 si->interval = sys_cpu_to_le16(sync->interval);
966 lll_sync = &sync->lll;
967 (void)memcpy(&si->aa, lll_sync->access_addr, sizeof(si->aa));
968 (void)memcpy(si->crc_init, lll_sync->crc_init, sizeof(si->crc_init));
969
970 /* NOTE: Filled by secondary prepare */
971 si->evt_cntr = 0U;
972 }
973
974 #if !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
ull_adv_sync_offset_get(struct ll_adv_set * adv)975 void ull_adv_sync_offset_get(struct ll_adv_set *adv)
976 {
977 static memq_link_t link;
978 static struct mayfly mfy = {0, 0, &link, NULL, mfy_sync_offset_get};
979 uint32_t ret;
980
981 mfy.param = adv;
982 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1,
983 &mfy);
984 LL_ASSERT(!ret);
985 }
986 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
987
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)988 void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags,
989 uint8_t phy_s, uint8_t phy_flags,
990 struct pdu_cte_info *cte_info)
991 {
992 struct pdu_adv_com_ext_adv *com_hdr;
993 struct pdu_adv_ext_hdr *ext_hdr;
994 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
995 struct pdu_adv_aux_ptr *aux_ptr;
996 uint32_t cte_len_us;
997 #endif
998 uint8_t *dptr;
999 uint8_t len;
1000
1001 pdu->type = PDU_ADV_TYPE_AUX_SYNC_IND;
1002 pdu->rfu = 0U;
1003 pdu->chan_sel = 0U;
1004
1005 pdu->tx_addr = 0U;
1006 pdu->rx_addr = 0U;
1007
1008 com_hdr = &pdu->adv_ext_ind;
1009 /* Non-connectable and Non-scannable adv mode */
1010 com_hdr->adv_mode = 0U;
1011
1012 ext_hdr = &com_hdr->ext_hdr;
1013 *(uint8_t *)ext_hdr = ext_hdr_flags;
1014 dptr = ext_hdr->data;
1015
1016 LL_ASSERT(!(ext_hdr_flags & (ULL_ADV_PDU_HDR_FIELD_ADVA | ULL_ADV_PDU_HDR_FIELD_TARGETA |
1017 #if !defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1018 ULL_ADV_PDU_HDR_FIELD_ADI |
1019 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1020 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO)));
1021
1022 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1023 if (IS_ENABLED(CONFIG_BT_CTLR_DF_ADV_CTE_TX) &&
1024 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_CTE_INFO)) {
1025 (void)memcpy(dptr, cte_info, sizeof(*cte_info));
1026 cte_len_us = CTE_LEN_US(cte_info->time);
1027 dptr += sizeof(struct pdu_cte_info);
1028 } else {
1029 cte_len_us = 0U;
1030 }
1031 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
1032 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
1033 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_ADI)) {
1034 dptr += sizeof(struct pdu_adv_adi);
1035 }
1036 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1037 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) &&
1038 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR)) {
1039 aux_ptr = (void *)dptr;
1040 dptr += sizeof(struct pdu_adv_aux_ptr);
1041 }
1042 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
1043 if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_TX_POWER) {
1044 dptr += sizeof(uint8_t);
1045 }
1046
1047 /* Calc tertiary PDU len */
1048 len = ull_adv_aux_hdr_len_calc(com_hdr, &dptr);
1049 ull_adv_aux_hdr_len_fill(com_hdr, len);
1050
1051 pdu->len = len;
1052
1053 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1054 /* Fill aux offset in aux pointer field */
1055 if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) {
1056 uint32_t offs_us;
1057
1058 offs_us = PDU_AC_US(pdu->len, phy_s, phy_flags) +
1059 EVENT_SYNC_B2B_MAFS_US;
1060 offs_us += cte_len_us;
1061 ull_adv_aux_ptr_fill(aux_ptr, offs_us, phy_s);
1062 }
1063 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
1064 }
1065
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)1066 uint8_t ull_adv_sync_pdu_alloc(struct ll_adv_set *adv,
1067 enum ull_adv_pdu_extra_data_flag extra_data_flag,
1068 struct pdu_adv **ter_pdu_prev, struct pdu_adv **ter_pdu_new,
1069 void **extra_data_prev, void **extra_data_new, uint8_t *ter_idx)
1070 {
1071 struct pdu_adv *pdu_prev, *pdu_new;
1072 struct lll_adv_sync *lll_sync;
1073 void *ed_prev;
1074 #if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
1075 void *ed_new;
1076 #endif
1077
1078 lll_sync = adv->lll.sync;
1079 if (!lll_sync) {
1080 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
1081 }
1082
1083 /* Get reference to previous periodic advertising PDU data */
1084 pdu_prev = lll_adv_sync_data_peek(lll_sync, &ed_prev);
1085
1086 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1087 /* Get reference to new periodic advertising PDU data buffer */
1088 if (extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS ||
1089 (extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST && ed_prev)) {
1090 /* If there was an extra data in past PDU data or it is required
1091 * by the hdr_add_fields then allocate memory for it.
1092 */
1093 pdu_new = lll_adv_sync_data_alloc(lll_sync, &ed_new,
1094 ter_idx);
1095 if (!pdu_new) {
1096 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1097 }
1098 } else {
1099 ed_new = NULL;
1100 #else
1101 {
1102 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1103 pdu_new = lll_adv_sync_data_alloc(lll_sync, NULL, ter_idx);
1104 if (!pdu_new) {
1105 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1106 }
1107 }
1108
1109 #if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
1110 if (extra_data_prev) {
1111 *extra_data_prev = ed_prev;
1112 }
1113 if (extra_data_new) {
1114 *extra_data_new = ed_new;
1115 }
1116 #endif /* CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY */
1117
1118 *ter_pdu_prev = pdu_prev;
1119 *ter_pdu_new = pdu_new;
1120
1121 return 0;
1122 }
1123
1124 uint8_t ull_adv_sync_duplicate(const struct pdu_adv *pdu_prev, struct pdu_adv *pdu_new)
1125 {
1126 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1127 /* Duplicate chain PDUs */
1128 return ull_adv_sync_duplicate_chain(pdu_prev, pdu_new);
1129 #else
1130 ull_adv_sync_copy_pdu(pdu_prev, pdu_new);
1131
1132 return 0U;
1133 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1134 }
1135
1136 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) || defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) || \
1137 defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1138 static void ull_adv_sync_add_to_header(struct pdu_adv *pdu,
1139 const struct pdu_adv_ext_hdr *fields,
1140 uint8_t *ad_overflow, uint8_t *overflow_len)
1141 {
1142 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1143 uint8_t delta = 0U;
1144 uint8_t *dptr;
1145
1146 if (overflow_len) {
1147 *overflow_len = 0U;
1148 }
1149
1150 /* AdvA, TargetA and SyncInfo is RFU for periodic advertising */
1151 if (fields->cte_info && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.cte_info == 0U)) {
1152 delta += sizeof(struct pdu_cte_info);
1153 }
1154 if (fields->adi && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.adi == 0U)) {
1155 delta += sizeof(struct pdu_adv_adi);
1156 }
1157 if (fields->aux_ptr && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.aux_ptr == 0U)) {
1158 delta += sizeof(struct pdu_adv_aux_ptr);
1159 }
1160 if (fields->tx_pwr && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.tx_pwr == 0U)) {
1161 delta += 1U;
1162 }
1163
1164 if (delta == 0U) {
1165 /* No new fields to add */
1166 return;
1167 }
1168
1169 if (hdr->ext_hdr_len == 0) {
1170 /* Add one byte for the header flags */
1171 delta++;
1172 }
1173
1174 /* Push back any adv data - overflow will be returned via ad_overflow */
1175 if (pdu->len > hdr->ext_hdr_len + 1U) {
1176 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - delta) {
1177 LL_ASSERT(ad_overflow);
1178 LL_ASSERT(overflow_len);
1179 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1180 *overflow_len = delta - (PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len);
1181 memcpy(ad_overflow,
1182 pdu->payload + PDU_AC_EXT_PAYLOAD_SIZE_MAX - *overflow_len,
1183 *overflow_len);
1184 pdu->len -= *overflow_len;
1185 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1186 }
1187 dptr = pdu->payload + hdr->ext_hdr_len + 1U;
1188 memmove(dptr + delta,
1189 dptr, pdu->len - hdr->ext_hdr_len - 1U);
1190 }
1191
1192 pdu->len += delta;
1193
1194 if (hdr->ext_hdr_len == 0U) {
1195 /* No extended header present, adding one */
1196 memcpy(&hdr->ext_hdr, fields, sizeof(struct pdu_adv_ext_hdr));
1197 hdr->ext_hdr_len = delta;
1198 } else {
1199 /* Go to end of current extended header and push back fields/ACAD in reverse */
1200 dptr = hdr->ext_hdr.data;
1201
1202 /* AdvA and TargetA is RFU for periodic advertising */
1203
1204 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1205 if (hdr->ext_hdr.cte_info) {
1206 dptr += sizeof(struct pdu_cte_info);
1207 }
1208 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1209
1210 if (hdr->ext_hdr.adi) {
1211 dptr += sizeof(struct pdu_adv_adi);
1212 }
1213
1214 if (hdr->ext_hdr.aux_ptr) {
1215 dptr += sizeof(struct pdu_adv_aux_ptr);
1216 }
1217
1218 /* SyncInfo is RFU for periodic advertising */
1219
1220 if (hdr->ext_hdr.tx_pwr) {
1221 dptr++;
1222 }
1223
1224 /* Push back ACAD if any */
1225 if ((dptr - hdr->ext_hdr_adv_data) < hdr->ext_hdr_len) {
1226 uint8_t acad_len = hdr->ext_hdr_len - (dptr - hdr->ext_hdr_adv_data);
1227
1228 memmove(dptr + delta, dptr, acad_len);
1229 }
1230
1231 /* Set new header size now before starting to decrement delta */
1232 hdr->ext_hdr_len += delta;
1233
1234 /* Now push back or add fields as needed */
1235
1236 if (hdr->ext_hdr.tx_pwr) {
1237 dptr--;
1238 *(dptr + delta) = *dptr;
1239 } else if (fields->tx_pwr) {
1240 hdr->ext_hdr.tx_pwr = 1U;
1241 delta -= 1U;
1242 }
1243
1244 if (hdr->ext_hdr.aux_ptr) {
1245 dptr -= sizeof(struct pdu_adv_aux_ptr);
1246 memmove(dptr + delta, dptr, sizeof(struct pdu_adv_aux_ptr));
1247 } else if (fields->aux_ptr) {
1248 hdr->ext_hdr.aux_ptr = 1U;
1249 delta -= sizeof(struct pdu_adv_aux_ptr);
1250 }
1251
1252 if (hdr->ext_hdr.adi) {
1253 dptr -= sizeof(struct pdu_adv_adi);
1254 memmove(dptr + delta, dptr, sizeof(struct pdu_adv_adi));
1255 } else if (fields->adi) {
1256 hdr->ext_hdr.adi = 1U;
1257 delta -= sizeof(struct pdu_adv_adi);
1258 }
1259
1260 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1261 if (hdr->ext_hdr.cte_info) {
1262 dptr -= sizeof(struct pdu_cte_info);
1263 memmove(dptr + delta, dptr, sizeof(struct pdu_cte_info));
1264 } else if (fields->cte_info) {
1265 hdr->ext_hdr.cte_info = 1U;
1266 delta -= sizeof(struct pdu_cte_info);
1267 }
1268 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1269 }
1270 }
1271
1272 static void ull_adv_sync_remove_from_header(struct pdu_adv *pdu,
1273 const struct pdu_adv_ext_hdr *fields,
1274 bool acad)
1275 {
1276 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1277 uint8_t orig_hdr_len = hdr->ext_hdr_len;
1278 uint8_t *dptr;
1279
1280 if (orig_hdr_len == 0U) {
1281 return;
1282 }
1283
1284 dptr = hdr->ext_hdr.data;
1285
1286 /* AdvA and TargetA is RFU for periodic advertising */
1287
1288 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1289 if (hdr->ext_hdr.cte_info) {
1290 if (fields->cte_info) {
1291 memmove(dptr, dptr + sizeof(struct pdu_cte_info),
1292 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1293 hdr->ext_hdr.cte_info = 0U;
1294 hdr->ext_hdr_len -= sizeof(struct pdu_cte_info);
1295 } else {
1296 dptr += sizeof(struct pdu_cte_info);
1297 }
1298 }
1299 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1300
1301 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1302 if (hdr->ext_hdr.adi) {
1303 if (fields->adi) {
1304 memmove(dptr, dptr + sizeof(struct pdu_adv_adi),
1305 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1306 hdr->ext_hdr.adi = 0U;
1307 hdr->ext_hdr_len -= sizeof(struct pdu_adv_adi);
1308 } else {
1309 dptr += sizeof(struct pdu_adv_adi);
1310 }
1311 }
1312 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1313
1314 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1315 if (hdr->ext_hdr.aux_ptr) {
1316 if (fields->aux_ptr) {
1317 memmove(dptr, dptr + sizeof(struct pdu_adv_aux_ptr),
1318 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1319 hdr->ext_hdr.aux_ptr = 0U;
1320 hdr->ext_hdr_len -= sizeof(struct pdu_adv_aux_ptr);
1321 } else {
1322 dptr += sizeof(struct pdu_adv_aux_ptr);
1323 }
1324 }
1325 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1326
1327 /* SyncInfo is RFU for periodic advertising */
1328
1329 if (hdr->ext_hdr.tx_pwr) {
1330 if (fields->tx_pwr) {
1331 memmove(dptr, dptr + 1U,
1332 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1333 hdr->ext_hdr.tx_pwr = 0U;
1334 hdr->ext_hdr_len -= 1U;
1335 } else {
1336 dptr++;
1337 }
1338 }
1339
1340 /* ACAD is the remainder of the header, if any left */
1341 if (acad) {
1342 /* Drop any ACAD */
1343 hdr->ext_hdr_len = dptr - hdr->ext_hdr_adv_data;
1344 }
1345
1346 if (hdr->ext_hdr_len == 1U) {
1347 /* Only flags left in header, remove it completely */
1348 hdr->ext_hdr_len = 0U;
1349 }
1350
1351 if (orig_hdr_len != hdr->ext_hdr_len) {
1352 /* Move adv data if any */
1353 if (pdu->len > orig_hdr_len + 1U) {
1354 memmove(hdr->ext_hdr_adv_data + hdr->ext_hdr_len,
1355 hdr->ext_hdr_adv_data + orig_hdr_len,
1356 pdu->len - orig_hdr_len - 1U);
1357 }
1358
1359 /* Update total PDU len */
1360 pdu->len -= orig_hdr_len - hdr->ext_hdr_len;
1361 }
1362
1363 }
1364 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK || CONFIG_BT_CTLR_DF_ADV_CTE_TX || \
1365 * CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT
1366 */
1367
1368 static void ull_adv_sync_copy_pdu_header(struct pdu_adv *target_pdu,
1369 const struct pdu_adv *source_pdu,
1370 const struct pdu_adv_ext_hdr *skip_fields,
1371 bool skip_acad)
1372 {
1373 const struct pdu_adv_com_ext_adv *source_hdr = &source_pdu->adv_ext_ind;
1374 struct pdu_adv_com_ext_adv *target_hdr = &target_pdu->adv_ext_ind;
1375 const uint8_t *source_dptr;
1376 uint8_t *target_dptr;
1377
1378 LL_ASSERT(target_pdu != source_pdu);
1379
1380 /* Initialize PDU header */
1381 target_pdu->type = source_pdu->type;
1382 target_pdu->rfu = 0U;
1383 target_pdu->chan_sel = 0U;
1384 target_pdu->tx_addr = 0U;
1385 target_pdu->rx_addr = 0U;
1386 target_hdr->adv_mode = source_hdr->adv_mode;
1387
1388 /* Copy extended header */
1389 if (source_hdr->ext_hdr_len == 0U) {
1390 /* No extended header present */
1391 target_hdr->ext_hdr_len = 0U;
1392 } else if (!skip_fields && !skip_acad) {
1393 /* Copy entire extended header */
1394 memcpy(target_hdr, source_hdr, source_hdr->ext_hdr_len + 1U);
1395 } else {
1396 /* Copy field by field */
1397 source_dptr = source_hdr->ext_hdr.data;
1398 target_dptr = target_hdr->ext_hdr.data;
1399
1400 /* Initialize extended header flags to all 0 */
1401 target_hdr->ext_hdr_adv_data[0U] = 0U;
1402
1403 /* AdvA and TargetA is RFU for periodic advertising */
1404
1405 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1406 if (source_hdr->ext_hdr.cte_info) {
1407 if (!skip_fields || !skip_fields->cte_info) {
1408 memcpy(target_dptr, source_dptr, sizeof(struct pdu_cte_info));
1409 target_dptr += sizeof(struct pdu_cte_info);
1410 target_hdr->ext_hdr.cte_info = 1U;
1411 }
1412 source_dptr += sizeof(struct pdu_cte_info);
1413 }
1414 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1415
1416 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1417 if (source_hdr->ext_hdr.adi) {
1418 if (!skip_fields || !skip_fields->adi) {
1419 memcpy(target_dptr, source_dptr, sizeof(struct pdu_adv_adi));
1420 target_dptr += sizeof(struct pdu_adv_adi);
1421 target_hdr->ext_hdr.adi = 1U;
1422 }
1423 source_dptr += sizeof(struct pdu_adv_adi);
1424 }
1425 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1426
1427 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1428 if (source_hdr->ext_hdr.aux_ptr) {
1429 if (!skip_fields || !skip_fields->aux_ptr) {
1430 memcpy(target_dptr, source_dptr, sizeof(struct pdu_adv_aux_ptr));
1431 target_dptr += sizeof(struct pdu_adv_aux_ptr);
1432 target_hdr->ext_hdr.aux_ptr = 1U;
1433 }
1434 source_dptr += sizeof(struct pdu_adv_aux_ptr);
1435 }
1436 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1437
1438 /* SyncInfo is RFU for periodic advertising */
1439
1440 if (source_hdr->ext_hdr.tx_pwr) {
1441 if (!skip_fields || !skip_fields->tx_pwr) {
1442 *target_dptr = *source_dptr;
1443 target_dptr++;
1444 target_hdr->ext_hdr.tx_pwr = 1U;
1445 }
1446 source_dptr++;
1447 }
1448
1449 /* ACAD is the remainder of the header, if any left */
1450 if ((source_dptr - source_hdr->ext_hdr_adv_data) < source_hdr->ext_hdr_len &&
1451 !skip_acad) {
1452 uint8_t acad_len = source_hdr->ext_hdr_len -
1453 (source_dptr - source_hdr->ext_hdr_adv_data);
1454
1455 memcpy(target_dptr, source_dptr, acad_len);
1456 target_dptr += acad_len;
1457 }
1458
1459 if (target_dptr == target_hdr->ext_hdr.data) {
1460 /* Nothing copied, do not include extended header */
1461 target_hdr->ext_hdr_len = 0U;
1462 } else {
1463 target_hdr->ext_hdr_len = target_dptr - target_hdr->ext_hdr_adv_data;
1464 }
1465 }
1466
1467 target_pdu->len = target_hdr->ext_hdr_len + 1U;
1468 }
1469
1470 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1471 static void ull_adv_sync_update_pdu_adi(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu,
1472 uint16_t did)
1473 {
1474 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1475 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1476 struct pdu_adv_adi *adi;
1477 uint8_t *dptr;
1478
1479 if (hdr->ext_hdr_len == 0U || hdr->ext_hdr.adi == 0U) {
1480 /* No ADI field present, nothing to do */
1481 return;
1482 }
1483
1484 /* Find ADI in extended header */
1485 dptr = hdr->ext_hdr.data;
1486
1487 /* AdvA and TargetA is RFU for periodic advertising */
1488
1489 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1490 if (hdr->ext_hdr.cte_info) {
1491 dptr += sizeof(struct pdu_cte_info);
1492 }
1493 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1494
1495 adi = (struct pdu_adv_adi *)dptr;
1496
1497 PDU_ADV_ADI_DID_SID_SET(adi, did, adv->sid);
1498 }
1499 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1500
1501 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1502 static void ull_adv_sync_add_aux_ptr(struct pdu_adv *pdu, uint8_t *ad_overflow,
1503 uint8_t *overflow_len)
1504 {
1505 struct pdu_adv_ext_hdr fields = { 0U };
1506
1507 fields.aux_ptr = 1U;
1508 ull_adv_sync_add_to_header(pdu, &fields, ad_overflow, overflow_len);
1509 }
1510
1511 static void ull_adv_sync_update_aux_ptr(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu)
1512 {
1513 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1514 struct pdu_adv_aux_ptr *aux_ptr;
1515 struct ll_adv_set *adv;
1516 uint32_t offs_us;
1517 uint8_t *dptr;
1518 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1519 struct pdu_cte_info *cte_info = NULL;
1520 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1521
1522 if (!hdr->ext_hdr_len || !hdr->ext_hdr.aux_ptr) {
1523 /* Nothing to update */
1524 return;
1525 }
1526
1527 /* Find AuxPtr */
1528 dptr = hdr->ext_hdr.data;
1529
1530 /* AdvA and TargetA is RFU for periodic advertising */
1531
1532 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1533 if (hdr->ext_hdr.cte_info) {
1534 cte_info = (struct pdu_cte_info *)dptr;
1535 dptr += sizeof(struct pdu_cte_info);
1536 }
1537 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1538
1539 if (hdr->ext_hdr.adi) {
1540 dptr += sizeof(struct pdu_adv_adi);
1541 }
1542
1543 /* Now at AuxPtr */
1544 aux_ptr = (struct pdu_adv_aux_ptr *)dptr;
1545
1546 /* Calculate and set offset */
1547 adv = HDR_LLL2ULL(lll_sync->adv);
1548 offs_us = PDU_AC_US(pdu->len, adv->lll.phy_s, adv->lll.phy_flags) + EVENT_SYNC_B2B_MAFS_US;
1549
1550 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1551 /* Add CTE time if relevant */
1552 if (cte_info) {
1553 offs_us += CTE_LEN_US(cte_info->time);
1554 }
1555 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1556
1557 ull_adv_aux_ptr_fill(aux_ptr, offs_us, adv->lll.phy_s);
1558 }
1559 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1560
1561 static uint8_t ull_adv_sync_append_ad_data(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu,
1562 const uint8_t *ad, uint8_t ad_len, uint8_t max_ad_len)
1563 {
1564 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1565 uint8_t ad_overflow[sizeof(struct pdu_adv_aux_ptr) + 1U];
1566 uint8_t overflow_len = 0U;
1567 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1568
1569 while (ad_len) {
1570 uint8_t pdu_ad_len;
1571 uint8_t *dptr;
1572 uint8_t ext_hdr_len;
1573 uint8_t pdu_add_len = ad_len;
1574
1575 ext_hdr_len = pdu->adv_ext_ind.ext_hdr_len + 1U;
1576 pdu_ad_len = pdu->len - ext_hdr_len;
1577
1578 /* Check if the adv data exceeds the configured maximum */
1579 /* FIXME - this check should include the entire chain */
1580 if (pdu_ad_len + ad_len > CONFIG_BT_CTLR_ADV_DATA_LEN_MAX) {
1581 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1582 }
1583
1584 /* Only allow up to max_ad_len adv data per PDU */
1585 if (pdu_ad_len + ad_len > max_ad_len ||
1586 PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len < ad_len) {
1587 #if !defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1588 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1589 #else
1590 /* Will fragment into chain PDU */
1591
1592 /* Add aux_ptr to existing PDU */
1593 ull_adv_sync_add_aux_ptr(pdu, ad_overflow, &overflow_len);
1594
1595 pdu_add_len = MAX(0U, MIN(max_ad_len - pdu_ad_len,
1596 PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len));
1597 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1598 }
1599
1600 dptr = pdu->payload + pdu->len;
1601
1602 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1603 if (pdu_add_len && overflow_len) {
1604 /* Overflow from previous PDU in chain, add this first */
1605 memcpy(dptr, ad, overflow_len);
1606 pdu->len += overflow_len;
1607 dptr += overflow_len;
1608 overflow_len = 0U;
1609 }
1610 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1611
1612 if (pdu_add_len) {
1613 memcpy(dptr, ad, pdu_add_len);
1614 pdu->len += pdu_add_len;
1615 ad_len -= pdu_add_len;
1616 ad += pdu_add_len;
1617 }
1618 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1619 if (ad_len) {
1620 struct pdu_adv_ext_hdr skip_fields = { 0U };
1621 struct pdu_adv *pdu_chain;
1622
1623 /* Fill the aux offset in superior PDU */
1624 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
1625
1626 /* Allocate new PDU */
1627 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
1628 if (!pdu_chain) {
1629 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1630 }
1631
1632 /* Copy header, removing AuxPtr, CTEInfo and ACAD */
1633 skip_fields.aux_ptr = 1U;
1634 skip_fields.cte_info = 1U;
1635 ull_adv_sync_copy_pdu_header(pdu_chain, pdu, &skip_fields, true);
1636
1637 /* Chain the PDU */
1638 lll_adv_pdu_linked_append(pdu_chain, pdu);
1639
1640 pdu = pdu_chain;
1641 }
1642 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1643 }
1644
1645 return 0U;
1646 }
1647
1648 static void ull_adv_sync_copy_pdu(const struct pdu_adv *pdu_prev,
1649 struct pdu_adv *pdu)
1650 {
1651 if (pdu == pdu_prev) {
1652 return;
1653 }
1654
1655 /* Initialize PDU header */
1656 pdu->type = pdu_prev->type;
1657 pdu->rfu = 0U;
1658 pdu->chan_sel = 0U;
1659 pdu->tx_addr = 0U;
1660 pdu->rx_addr = 0U;
1661 pdu->len = pdu_prev->len;
1662
1663 /* Copy PDU payload */
1664 memcpy(pdu->payload, pdu_prev->payload, pdu_prev->len);
1665 }
1666
1667 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1668 static uint8_t ull_adv_sync_duplicate_chain(const struct pdu_adv *pdu_prev,
1669 struct pdu_adv *pdu)
1670 {
1671 /* If pdu_prev == pdu we are done */
1672 if (pdu == pdu_prev) {
1673 return 0U;
1674 }
1675
1676 /* Copy existing PDU chain */
1677 while (pdu_prev) {
1678 struct pdu_adv *pdu_chain;
1679
1680 ull_adv_sync_copy_pdu(pdu_prev, pdu);
1681
1682 pdu_prev = lll_adv_pdu_linked_next_get(pdu_prev);
1683 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
1684 if (pdu_prev && !pdu_chain) {
1685 /* Get a new chain PDU */
1686 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
1687 if (!pdu_chain) {
1688 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1689 }
1690
1691 /* Link the chain PDU to parent PDU */
1692 lll_adv_pdu_linked_append(pdu_chain, pdu);
1693 pdu = pdu_chain;
1694 }
1695 }
1696
1697 return 0U;
1698 }
1699 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1700
1701 static uint8_t ull_adv_sync_ad_add(struct lll_adv_sync *lll_sync,
1702 struct pdu_adv *ter_pdu_prev,
1703 struct pdu_adv *ter_pdu,
1704 const uint8_t *ad, uint8_t ad_len)
1705 {
1706 uint8_t pdu_ad_max_len = PDU_AC_EXT_AD_DATA_LEN_MAX;
1707 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1708 uint8_t err;
1709
1710 err = ull_adv_sync_duplicate_chain(ter_pdu_prev, ter_pdu);
1711 if (err) {
1712 return err;
1713 }
1714
1715 /* Find end of current advertising data */
1716 while (lll_adv_pdu_linked_next_get(ter_pdu)) {
1717 ter_pdu = lll_adv_pdu_linked_next_get(ter_pdu);
1718 ter_pdu_prev = lll_adv_pdu_linked_next_get(ter_pdu_prev);
1719
1720 /* Use the full PDU payload for AUX_CHAIN_IND */
1721 pdu_ad_max_len = PDU_AC_EXT_PAYLOAD_SIZE_MAX;
1722
1723 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1724 /* Detect end of current advertising data */
1725 if (ter_pdu->len < PDU_AC_EXT_PAYLOAD_SIZE_MAX) {
1726 break;
1727 }
1728 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1729 }
1730 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1731 /* Initialize PDU header */
1732 ter_pdu->type = ter_pdu_prev->type;
1733 ter_pdu->rfu = 0U;
1734 ter_pdu->chan_sel = 0U;
1735 ter_pdu->tx_addr = 0U;
1736 ter_pdu->rx_addr = 0U;
1737 ter_pdu->len = ter_pdu_prev->len;
1738
1739 /* Copy PDU payload */
1740 memcpy(ter_pdu->payload, ter_pdu_prev->payload, ter_pdu_prev->len);
1741 #endif /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1742
1743 /* At end of copied chain, append new adv data */
1744 return ull_adv_sync_append_ad_data(lll_sync, ter_pdu, ad, ad_len, pdu_ad_max_len);
1745 }
1746
1747 static uint8_t ull_adv_sync_ad_replace(struct lll_adv_sync *lll_sync,
1748 struct pdu_adv *ter_pdu_prev,
1749 struct pdu_adv *ter_pdu,
1750 const uint8_t *ad, uint8_t ad_len)
1751 {
1752 struct pdu_adv_ext_hdr skip_fields = { 0U };
1753
1754 skip_fields.aux_ptr = 1U;
1755
1756 /* FIXME - below ignores any configured CTE count */
1757 if (ter_pdu_prev == ter_pdu) {
1758 /* Remove adv data and any AuxPtr */
1759 ter_pdu->len = ter_pdu_prev->adv_ext_ind.ext_hdr_len + 1U;
1760 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1761 ull_adv_sync_remove_from_header(ter_pdu, &skip_fields, false);
1762 /* Delete any existing PDU chain */
1763 if (lll_adv_pdu_linked_next_get(ter_pdu)) {
1764 lll_adv_pdu_linked_release_all(lll_adv_pdu_linked_next_get(ter_pdu));
1765 lll_adv_pdu_linked_append(NULL, ter_pdu);
1766 }
1767 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1768 } else {
1769 /* Copy header (only), removing any prior presence of Aux Ptr */
1770 ull_adv_sync_copy_pdu_header(ter_pdu, ter_pdu_prev, &skip_fields, false);
1771 }
1772
1773 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1774 /* New adv data - update ADI if present */
1775 if (ter_pdu->adv_ext_ind.ext_hdr_len && ter_pdu->adv_ext_ind.ext_hdr.adi) {
1776 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1777 uint16_t did;
1778
1779 /* The DID for a specific SID shall be unique */
1780 did = sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid));
1781 ull_adv_sync_update_pdu_adi(lll_sync, ter_pdu, did);
1782 }
1783 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1784
1785 /* Set advertising data (without copying any existing adv data) */
1786 return ull_adv_sync_append_ad_data(lll_sync, ter_pdu, ad, ad_len,
1787 PDU_AC_EXT_AD_DATA_LEN_MAX);
1788 }
1789
1790 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1791 static uint8_t ull_adv_sync_update_adi(struct lll_adv_sync *lll_sync,
1792 struct pdu_adv *ter_pdu_prev,
1793 struct pdu_adv *ter_pdu)
1794 {
1795 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1796 uint16_t did;
1797
1798 /* The DID for a specific SID shall be unique */
1799 did = sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid));
1800
1801 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1802 uint8_t err;
1803
1804 err = ull_adv_sync_duplicate_chain(ter_pdu_prev, ter_pdu);
1805 if (err) {
1806 return err;
1807 }
1808
1809 /* Loop through chain and set new ADI for all */
1810 while (ter_pdu) {
1811 ull_adv_sync_update_pdu_adi(lll_sync, ter_pdu, did);
1812 ter_pdu = lll_adv_pdu_linked_next_get(ter_pdu);
1813 }
1814 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1815 /* Initialize PDU header */
1816 ter_pdu->type = ter_pdu_prev->type;
1817 ter_pdu->rfu = 0U;
1818 ter_pdu->chan_sel = 0U;
1819 ter_pdu->tx_addr = 0U;
1820 ter_pdu->rx_addr = 0U;
1821 ter_pdu->len = ter_pdu_prev->len;
1822
1823 /* Copy PDU payload */
1824 memcpy(ter_pdu->payload, ter_pdu_prev->payload, ter_pdu_prev->len);
1825
1826 /* Set new ADI */
1827 ull_adv_sync_update_pdu_adi(lll_sync, ter_pdu, did);
1828 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK*/
1829 return 0U;
1830 }
1831
1832 static uint8_t ull_adv_sync_add_adi(struct lll_adv_sync *lll_sync,
1833 struct pdu_adv *pdu_prev,
1834 struct pdu_adv *pdu)
1835 {
1836 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1837 struct pdu_adv_ext_hdr add_fields = { 0U };
1838 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1839 uint8_t ad_overflow[sizeof(struct pdu_adv_adi)*MAX_FRAG_COUNT];
1840 uint8_t total_overflow_len;
1841 struct pdu_adv *last_pdu;
1842 uint8_t overflow_len;
1843 uint8_t err;
1844 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1845 uint16_t did;
1846
1847 add_fields.adi = 1U;
1848
1849 /* The DID for a specific SID shall be unique */
1850 did = sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid));
1851
1852 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1853 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
1854 if (err) {
1855 return err;
1856 }
1857
1858 total_overflow_len = 0U;
1859 /* Loop through chain and add ADI for all */
1860 while (pdu) {
1861 last_pdu = pdu;
1862
1863 /* We should always have enough available overflow space to fit an ADI */
1864 LL_ASSERT(total_overflow_len + sizeof(struct pdu_adv_adi) <= sizeof(ad_overflow));
1865
1866 ull_adv_sync_add_to_header(pdu, &add_fields,
1867 &ad_overflow[total_overflow_len], &overflow_len);
1868 total_overflow_len += overflow_len;
1869 ull_adv_sync_update_pdu_adi(lll_sync, pdu, did);
1870 pdu = lll_adv_pdu_linked_next_get(pdu);
1871 if (pdu) {
1872 uint8_t ad_overflow_tmp[sizeof(struct pdu_adv_adi)*MAX_FRAG_COUNT];
1873 uint8_t overflow_tmp_len = 0U;
1874 uint8_t pdu_avail = PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len;
1875 uint8_t pdu_needed = total_overflow_len;
1876 uint8_t *dptr;
1877
1878 if (!pdu->adv_ext_ind.ext_hdr.adi) {
1879 pdu_needed += sizeof(struct pdu_adv_adi);
1880 }
1881 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
1882 /* Make room for flags as well */
1883 pdu_needed++;
1884 }
1885
1886 if (total_overflow_len > 0U) {
1887 if (pdu_avail < pdu_needed) {
1888 /* Make room by removing last part of adv data */
1889 overflow_tmp_len = pdu_needed - pdu_avail;
1890 memcpy(ad_overflow_tmp,
1891 pdu->payload + (pdu->len - overflow_tmp_len),
1892 overflow_tmp_len);
1893 pdu->len -= overflow_tmp_len;
1894 }
1895
1896 /* Prepend overflow from last PDU */
1897 dptr = pdu->payload + pdu->adv_ext_ind.ext_hdr_len + 1U;
1898 memmove(dptr + total_overflow_len, dptr,
1899 pdu->len - pdu->adv_ext_ind.ext_hdr_len - 1U +
1900 total_overflow_len);
1901 pdu->len += total_overflow_len;
1902 memcpy(dptr, ad_overflow, total_overflow_len);
1903
1904 /* Carry forward overflow from this PDU */
1905 total_overflow_len = overflow_tmp_len;
1906 if (overflow_tmp_len) {
1907 memcpy(ad_overflow, ad_overflow_tmp, overflow_tmp_len);
1908 }
1909 }
1910 }
1911 }
1912
1913 /* Push any remaining overflow on to last PDU */
1914 ull_adv_sync_append_ad_data(lll_sync, pdu, ad_overflow, total_overflow_len,
1915 PDU_AC_EXT_PAYLOAD_SIZE_MAX);
1916
1917 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1918
1919 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - sizeof(struct pdu_adv_adi)) {
1920 /* No room for ADI */
1921 return BT_HCI_ERR_PACKET_TOO_LONG;
1922 }
1923
1924 /* Initialize PDU header */
1925 pdu->type = pdu_prev->type;
1926 pdu->rfu = 0U;
1927 pdu->chan_sel = 0U;
1928 pdu->tx_addr = 0U;
1929 pdu->rx_addr = 0U;
1930 pdu->len = pdu_prev->len;
1931
1932 /* Copy PDU payload */
1933 memcpy(pdu->payload, pdu_prev->payload, pdu_prev->len);
1934
1935 /* Add and set new ADI */
1936 ull_adv_sync_add_to_header(pdu, &add_fields, NULL, NULL);
1937 ull_adv_sync_update_pdu_adi(lll_sync, pdu, did);
1938 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1939 return 0U;
1940 }
1941
1942 static uint8_t ull_adv_sync_remove_adi(struct lll_adv_sync *lll_sync,
1943 struct pdu_adv *pdu_prev,
1944 struct pdu_adv *pdu)
1945 {
1946 struct pdu_adv_ext_hdr remove_fields = { 0U };
1947 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1948 uint8_t err;
1949 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1950
1951 remove_fields.adi = 1U;
1952
1953 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1954 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
1955 if (err) {
1956 return err;
1957 }
1958
1959 /* Loop through chain and remove ADI for all */
1960 while (pdu) {
1961 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
1962 if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
1963 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
1964 }
1965 pdu = lll_adv_pdu_linked_next_get(pdu);
1966 }
1967 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1968 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
1969 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1970
1971 return 0U;
1972 }
1973 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1974
1975 uint8_t *ull_adv_sync_get_acad(struct pdu_adv *pdu, uint8_t *acad_len)
1976 {
1977 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1978 uint8_t *dptr;
1979
1980 /* Skip to ACAD */
1981 dptr = hdr->ext_hdr.data;
1982
1983 /* AdvA and TargetA is RFU for periodic advertising */
1984
1985 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1986 if (hdr->ext_hdr.cte_info) {
1987 dptr += sizeof(struct pdu_cte_info);
1988 }
1989 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1990
1991 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1992 if (hdr->ext_hdr.adi) {
1993 dptr += sizeof(struct pdu_adv_adi);
1994 }
1995 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1996
1997 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1998 if (hdr->ext_hdr.aux_ptr) {
1999 dptr += sizeof(struct pdu_adv_aux_ptr);
2000 }
2001 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2002
2003 /* SyncInfo is RFU for periodic advertising */
2004
2005 if (hdr->ext_hdr.tx_pwr) {
2006 dptr++;
2007 }
2008
2009 /* ACAD is the remainder of the header, if any left */
2010 if ((dptr - hdr->ext_hdr_adv_data) < hdr->ext_hdr_len) {
2011 *acad_len = hdr->ext_hdr_len - (dptr - hdr->ext_hdr_adv_data);
2012 } else {
2013 *acad_len = 0U;
2014 }
2015
2016 return dptr;
2017 }
2018
2019 uint8_t ull_adv_sync_remove_from_acad(struct lll_adv_sync *lll_sync,
2020 struct pdu_adv *pdu_prev,
2021 struct pdu_adv *pdu,
2022 uint8_t ad_type)
2023 {
2024 uint8_t acad_len;
2025 uint8_t ad_len;
2026 uint8_t *acad;
2027 uint8_t len;
2028 uint8_t *ad;
2029 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2030 uint8_t err;
2031
2032 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2033 if (err) {
2034 return err;
2035 }
2036 #else
2037 ull_adv_sync_copy_pdu(pdu_prev, pdu);
2038 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2039
2040 acad = ull_adv_sync_get_acad(pdu, &acad_len);
2041
2042 if (acad_len == 0U) {
2043 return 0U;
2044 }
2045
2046 /* Find the relevant entry */
2047 len = acad_len;
2048 ad = acad;
2049 do {
2050 ad_len = ad[PDU_ADV_DATA_HEADER_LEN_OFFSET];
2051 if (ad_len && (ad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] == ad_type)) {
2052 break;
2053 }
2054
2055 ad_len += 1U;
2056
2057 LL_ASSERT(ad_len <= len);
2058
2059 ad += ad_len;
2060 len -= ad_len;
2061 } while (len);
2062
2063 if (len == 0U) {
2064 /* Entry is not present */
2065 return 0U;
2066 }
2067
2068 /* Remove entry by moving the rest of the PDU content forward */
2069 ad_len += 1U;
2070 (void)memmove(ad, ad + ad_len, pdu->len - ((ad + ad_len) - pdu->payload));
2071
2072 /* Adjust lengths */
2073 pdu->len -= ad_len;
2074 pdu->adv_ext_ind.ext_hdr_len -= ad_len;
2075
2076 return 0U;
2077 }
2078
2079 uint8_t ull_adv_sync_add_to_acad(struct lll_adv_sync *lll_sync,
2080 struct pdu_adv *pdu_prev,
2081 struct pdu_adv *pdu,
2082 const uint8_t *new_ad,
2083 uint8_t new_ad_len)
2084 {
2085 uint8_t ad_len;
2086 uint8_t delta;
2087 uint8_t *dptr;
2088 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2089 uint8_t err;
2090
2091 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2092 if (err) {
2093 return err;
2094 }
2095 #else
2096 ull_adv_sync_copy_pdu(pdu_prev, pdu);
2097 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2098
2099 delta = new_ad_len;
2100 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
2101 /* Add one byte for the header flags */
2102 delta++;
2103 }
2104
2105 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - delta) {
2106 return BT_HCI_ERR_PACKET_TOO_LONG;
2107 }
2108
2109 dptr = pdu->payload + pdu->adv_ext_ind.ext_hdr_len + 1U;
2110
2111 /* Make room in ACAD by moving any advertising data back */
2112 ad_len = pdu->len - pdu->adv_ext_ind.ext_hdr_len - 1U;
2113 if (ad_len) {
2114 (void)memmove(dptr + delta, dptr, ad_len);
2115 }
2116
2117 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
2118 /* Set all extended header flags to 0 */
2119 *dptr = 0U;
2120 dptr++;
2121 }
2122
2123 /* Copy in ACAD data */
2124 memcpy(dptr, new_ad, new_ad_len);
2125
2126 /* Adjust lengths */
2127 pdu->len += delta;
2128 pdu->adv_ext_ind.ext_hdr_len += delta;
2129
2130 return 0U;
2131 }
2132
2133 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
2134 static void ull_adv_sync_update_pdu_cteinfo(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu,
2135 const struct pdu_cte_info *cte_info)
2136 {
2137 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
2138 uint8_t *dptr;
2139
2140 if (hdr->ext_hdr_len == 0U || hdr->ext_hdr.cte_info == 0U) {
2141 /* No CTEInfo field present, nothing to do */
2142 return;
2143 }
2144
2145 /* Find CTEInfo in extended header */
2146 dptr = hdr->ext_hdr.data;
2147
2148 /* AdvA and TargetA is RFU for periodic advertising */
2149
2150 /* Copy supplied data into extended header */
2151 memcpy(dptr, (uint8_t *)cte_info, sizeof(struct pdu_cte_info));
2152 }
2153
2154 uint8_t ull_adv_sync_add_cteinfo(struct lll_adv_sync *lll_sync,
2155 struct pdu_adv *pdu_prev,
2156 struct pdu_adv *pdu,
2157 const struct pdu_cte_info *cte_info,
2158 uint8_t cte_count)
2159 {
2160 struct pdu_adv_ext_hdr add_fields = { 0U };
2161 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2162 uint8_t ad_overflow[sizeof(struct pdu_cte_info)*MAX_FRAG_COUNT];
2163 uint8_t total_overflow_len;
2164 struct pdu_adv *last_pdu = pdu;
2165 uint8_t overflow_len;
2166 uint8_t err;
2167 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2168
2169 add_fields.cte_info = 1U;
2170
2171 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2172 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2173 if (err) {
2174 return err;
2175 }
2176
2177 total_overflow_len = 0U;
2178 /* Loop through chain and add CTEInfo for PDUs up to cte_count */
2179 while (pdu && cte_count) {
2180 last_pdu = pdu;
2181
2182 /* We should always have enough available overflow space to fit CTEInfo */
2183 LL_ASSERT(total_overflow_len + sizeof(struct pdu_cte_info) <= sizeof(ad_overflow));
2184
2185 ull_adv_sync_add_to_header(pdu, &add_fields,
2186 &ad_overflow[total_overflow_len], &overflow_len);
2187 total_overflow_len += overflow_len;
2188 ull_adv_sync_update_pdu_cteinfo(lll_sync, pdu, cte_info);
2189 cte_count--;
2190
2191 /* Update AuxPtr if present */
2192 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
2193
2194 pdu = lll_adv_pdu_linked_next_get(pdu);
2195 if (pdu) {
2196 uint8_t ad_overflow_tmp[sizeof(struct pdu_cte_info)*MAX_FRAG_COUNT];
2197 uint8_t overflow_tmp_len = 0U;
2198 uint8_t pdu_avail = PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len;
2199 uint8_t pdu_needed = total_overflow_len;
2200 uint8_t *dptr;
2201
2202 if (!pdu->adv_ext_ind.ext_hdr.cte_info) {
2203 pdu_needed += sizeof(struct pdu_cte_info);
2204 }
2205 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
2206 /* Make room for flags as well */
2207 pdu_needed++;
2208 }
2209
2210 if (total_overflow_len > 0U) {
2211 if (pdu_avail < pdu_needed) {
2212 /* Make room by removing last part of adv data */
2213 overflow_tmp_len = pdu_needed - pdu_avail;
2214 memcpy(ad_overflow_tmp,
2215 pdu->payload + (pdu->len - overflow_tmp_len),
2216 overflow_tmp_len);
2217 pdu->len -= overflow_tmp_len;
2218 }
2219
2220 /* Prepend overflow from last PDU */
2221 dptr = pdu->payload + pdu->adv_ext_ind.ext_hdr_len + 1U;
2222 memmove(dptr + total_overflow_len, dptr,
2223 pdu->len - pdu->adv_ext_ind.ext_hdr_len - 1U +
2224 total_overflow_len);
2225 pdu->len += total_overflow_len;
2226 memcpy(dptr, ad_overflow, total_overflow_len);
2227
2228 /* Carry forward overflow from this PDU */
2229 total_overflow_len = overflow_tmp_len;
2230 if (overflow_tmp_len) {
2231 memcpy(ad_overflow, ad_overflow_tmp, overflow_tmp_len);
2232 }
2233 }
2234
2235 }
2236 }
2237
2238 pdu = last_pdu;
2239
2240 /* Push any remaining overflow on to last PDU */
2241 ull_adv_sync_append_ad_data(lll_sync, pdu, ad_overflow, total_overflow_len,
2242 PDU_AC_EXT_PAYLOAD_SIZE_MAX);
2243
2244 #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1)
2245 /* Add PDUs up to cte_count if needed */
2246 while (cte_count) {
2247 struct pdu_adv_ext_hdr skip_fields = { 0U };
2248 struct pdu_adv *pdu_chain;
2249
2250 skip_fields.adi = 1U;
2251 skip_fields.aux_ptr = 1U;
2252 skip_fields.tx_pwr = 1U;
2253
2254 /* Get a new chain PDU */
2255 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
2256 if (!pdu_chain) {
2257 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
2258 }
2259
2260 /* Link the chain PDU to parent PDU */
2261 lll_adv_pdu_linked_append(pdu_chain, pdu);
2262
2263 /* Copy header to new PDU, skipping all fields except CTEInfo */
2264 ull_adv_sync_copy_pdu_header(pdu_chain, pdu, &skip_fields, true);
2265
2266 /* Add and set aux_ptr to existing PDU */
2267 ull_adv_sync_add_aux_ptr(pdu, ad_overflow, &overflow_len);
2268 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
2269
2270 if (overflow_len) {
2271 ull_adv_sync_append_ad_data(lll_sync, pdu_chain, ad_overflow, overflow_len,
2272 PDU_AC_EXT_PAYLOAD_SIZE_MAX);
2273 }
2274
2275 pdu = pdu_chain;
2276 cte_count--;
2277 }
2278 #endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
2279
2280 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2281
2282 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - sizeof(struct pdu_cte_info)) {
2283 /* No room for CTEInfo */
2284 return BT_HCI_ERR_PACKET_TOO_LONG;
2285 }
2286
2287 /* Initialize PDU header */
2288 pdu->type = pdu_prev->type;
2289 pdu->rfu = 0U;
2290 pdu->chan_sel = 0U;
2291 pdu->tx_addr = 0U;
2292 pdu->rx_addr = 0U;
2293 pdu->len = pdu_prev->len;
2294
2295 /* Copy PDU payload */
2296 memcpy(pdu->payload, pdu_prev->payload, pdu_prev->len);
2297
2298 /* Add and set CTEInfo */
2299 ull_adv_sync_add_to_header(pdu, &add_fields, NULL, NULL);
2300 ull_adv_sync_update_pdu_cteinfo(lll_sync, pdu, cte_info);
2301 #endif /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2302 return 0U;
2303 }
2304
2305 uint8_t ull_adv_sync_remove_cteinfo(struct lll_adv_sync *lll_sync,
2306 struct pdu_adv *pdu_prev,
2307 struct pdu_adv *pdu)
2308 {
2309 struct pdu_adv_ext_hdr remove_fields = { 0U };
2310 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2311 uint8_t err;
2312 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2313
2314 remove_fields.cte_info = 1U;
2315
2316 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2317 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2318 if (err) {
2319 return err;
2320 }
2321
2322 /* Loop through chain and remove CTEInfo for all */
2323 while (pdu) {
2324 struct pdu_adv *pdu_chain;
2325
2326 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
2327
2328 if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
2329 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
2330 }
2331
2332 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
2333 #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1)
2334 /* If the next PDU in the chain contains no adv data, any remaining PDUs
2335 * in the chain are only present for CTE purposes
2336 */
2337 if (pdu_chain && pdu_chain->len == pdu_chain->adv_ext_ind.ext_hdr_len + 1U) {
2338 /* Remove AuxPtr and clean up remaining PDUs in chain */
2339 remove_fields.aux_ptr = 1U;
2340 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
2341 lll_adv_pdu_linked_release_all(pdu_chain);
2342 lll_adv_pdu_linked_append(NULL, pdu);
2343 pdu_chain = NULL;
2344 }
2345 #endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
2346 pdu = pdu_chain;
2347 }
2348 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2349 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
2350 #endif /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2351
2352 return 0U;
2353 }
2354 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
2355
2356 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
2357 /* @brief Set or clear fields in extended advertising header and store
2358 * extra_data if requested.
2359 *
2360 * @param[in] extra_data_prev Pointer to previous content of extra_data.
2361 * @param[in] hdr_add_fields Flag with information which fields add.
2362 * @param[in] hdr_rem_fields Flag with information which fields remove.
2363 * @param[in] data Pointer to data to be stored in extra_data.
2364 * Content depends on the data depends on
2365 * @p hdr_add_fields.
2366 *
2367 * @Note
2368 * @p hdr_data content depends on the flag provided by @p hdr_add_fields:
2369 * - ULL_ADV_PDU_HDR_FIELD_CTE_INFO:
2370 * # @p hdr_data points to single byte with CTEInfo field
2371 *
2372 * @return Zero in case of success, other value in case of failure.
2373 * @p data depends on the flag provided by @p hdr_add_fields.
2374 *
2375 * @return Zero in case of success, other value in case of failure.
2376 */
2377 void ull_adv_sync_extra_data_set_clear(void *extra_data_prev,
2378 void *extra_data_new,
2379 uint16_t hdr_add_fields,
2380 uint16_t hdr_rem_fields,
2381 void *data)
2382 {
2383 /* Currently only CTE enable requires extra_data. Due to that fact
2384 * CTE additional data are just copied to extra_data memory.
2385 */
2386 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
2387 (void)memcpy(extra_data_new, data, sizeof(struct lll_df_adv_cfg));
2388 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) ||
2389 extra_data_prev) {
2390 (void)memmove(extra_data_new, extra_data_prev,
2391 sizeof(struct lll_df_adv_cfg));
2392 }
2393 }
2394 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
2395
2396 static int init_reset(void)
2397 {
2398 /* Initialize adv sync pool. */
2399 mem_init(ll_adv_sync_pool, sizeof(struct ll_adv_sync_set),
2400 sizeof(ll_adv_sync_pool) / sizeof(struct ll_adv_sync_set),
2401 &adv_sync_free);
2402
2403 return 0;
2404 }
2405
2406 static uint8_t adv_type_check(struct ll_adv_set *adv)
2407 {
2408 struct pdu_adv_com_ext_adv *pri_com_hdr;
2409 struct pdu_adv_ext_hdr *pri_hdr;
2410 struct pdu_adv *pri_pdu;
2411
2412 pri_pdu = lll_adv_data_latest_peek(&adv->lll);
2413 if (pri_pdu->type != PDU_ADV_TYPE_EXT_IND) {
2414 return BT_HCI_ERR_INVALID_PARAM;
2415 }
2416
2417 pri_com_hdr = (void *)&pri_pdu->adv_ext_ind;
2418 if (pri_com_hdr->adv_mode != 0U) {
2419 return BT_HCI_ERR_INVALID_PARAM;
2420 }
2421
2422 pri_hdr = (void *)pri_com_hdr->ext_hdr_adv_data;
2423 if (pri_hdr->aux_ptr) {
2424 struct pdu_adv_com_ext_adv *sec_com_hdr;
2425 struct pdu_adv_ext_hdr *sec_hdr;
2426 struct pdu_adv *sec_pdu;
2427
2428 sec_pdu = lll_adv_aux_data_latest_peek(adv->lll.aux);
2429 sec_com_hdr = (void *)&sec_pdu->adv_ext_ind;
2430 sec_hdr = (void *)sec_com_hdr->ext_hdr_adv_data;
2431 if (!pri_hdr->adv_addr && !sec_hdr->adv_addr) {
2432 return BT_HCI_ERR_INVALID_PARAM;
2433 }
2434 } else if (!pri_hdr->adv_addr) {
2435 return BT_HCI_ERR_INVALID_PARAM;
2436 }
2437
2438 return 0;
2439 }
2440
2441 static inline struct ll_adv_sync_set *sync_acquire(void)
2442 {
2443 return mem_acquire(&adv_sync_free);
2444 }
2445
2446 static inline void sync_release(struct ll_adv_sync_set *sync)
2447 {
2448 mem_release(sync, &adv_sync_free);
2449 }
2450
2451 static inline uint16_t sync_handle_get(const struct ll_adv_sync_set *sync)
2452 {
2453 return mem_index_get(sync, ll_adv_sync_pool,
2454 sizeof(struct ll_adv_sync_set));
2455 }
2456
2457 static uint32_t sync_time_get(const struct ll_adv_sync_set *sync,
2458 const struct pdu_adv *pdu)
2459 {
2460 uint8_t len;
2461
2462 /* Calculate the PDU Tx Time and hence the radio event length,
2463 * Always use maximum length for common extended header format so that
2464 * ACAD could be update when periodic advertising is active and the
2465 * time reservation need not be updated every time avoiding overlapping
2466 * with other active states/roles.
2467 */
2468 len = pdu->len - pdu->adv_ext_ind.ext_hdr_len -
2469 PDU_AC_EXT_HEADER_SIZE_MIN + PDU_AC_EXT_HEADER_SIZE_MAX;
2470
2471 return ull_adv_sync_time_get(sync, len);
2472 }
2473
2474 static uint8_t sync_stop(struct ll_adv_sync_set *sync)
2475 {
2476 uint8_t sync_handle;
2477 int err;
2478
2479 sync_handle = sync_handle_get(sync);
2480
2481 err = ull_ticker_stop_with_mark(TICKER_ID_ADV_SYNC_BASE + sync_handle,
2482 sync, &sync->lll);
2483 LL_ASSERT_INFO2(err == 0 || err == -EALREADY, sync_handle, err);
2484 if (err) {
2485 return BT_HCI_ERR_CMD_DISALLOWED;
2486 }
2487
2488 return 0;
2489 }
2490
2491 static inline uint8_t sync_remove(struct ll_adv_sync_set *sync,
2492 struct ll_adv_set *adv, uint8_t enable)
2493 {
2494 uint8_t pri_idx;
2495 uint8_t sec_idx;
2496 uint8_t err;
2497
2498 /* Remove sync_info from auxiliary PDU */
2499 err = ull_adv_aux_hdr_set_clear(adv, 0U,
2500 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO, NULL,
2501 &pri_idx, &sec_idx);
2502 if (err) {
2503 return err;
2504 }
2505
2506 lll_adv_aux_data_enqueue(adv->lll.aux, sec_idx);
2507 lll_adv_data_enqueue(&adv->lll, pri_idx);
2508
2509 if (sync->is_started) {
2510 /* TODO: we removed sync info, but if sync_stop() fails, what do
2511 * we do?
2512 */
2513 err = sync_stop(sync);
2514 if (err) {
2515 return err;
2516 }
2517
2518 sync->is_started = 0U;
2519
2520 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2521 if (adv->lll.aux) {
2522 /* notify the auxiliary set */
2523 ull_adv_sync_started_stopped(HDR_LLL2ULL(adv->lll.aux));
2524 }
2525 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2526 }
2527
2528 if (!enable) {
2529 sync->is_enabled = 0U;
2530 }
2531
2532 return 0U;
2533 }
2534
2535 static uint8_t sync_chm_update(uint8_t handle)
2536 {
2537 struct pdu_adv_sync_chm_upd_ind *chm_upd_ind;
2538 uint8_t ad[sizeof(*chm_upd_ind) + 2U];
2539 struct lll_adv_sync *lll_sync;
2540 struct pdu_adv *pdu_prev;
2541 struct ll_adv_set *adv;
2542 struct pdu_adv *pdu;
2543 uint16_t instant;
2544 uint8_t chm_last;
2545 uint8_t ter_idx;
2546 uint8_t err;
2547
2548 /* Check for valid advertising instance */
2549 adv = ull_adv_is_created_get(handle);
2550 if (!adv) {
2551 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
2552 }
2553
2554 /* Check for valid periodic advertising */
2555 lll_sync = adv->lll.sync;
2556 if (!lll_sync) {
2557 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
2558 }
2559
2560 /* Fail if already in progress */
2561 if (lll_sync->chm_last != lll_sync->chm_first) {
2562 return BT_HCI_ERR_CMD_DISALLOWED;
2563 }
2564
2565 /* Allocate next Sync PDU */
2566 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
2567 &pdu_prev, &pdu, NULL, NULL, &ter_idx);
2568 if (err) {
2569 return err;
2570 }
2571
2572 /* Populate the AD data length and opcode */
2573 ad[PDU_ADV_DATA_HEADER_LEN_OFFSET] = sizeof(*chm_upd_ind) + 1U;
2574 ad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] = PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND;
2575
2576 /* Populate the Channel Map Indication structure */
2577 chm_upd_ind = (void *)&ad[PDU_ADV_DATA_HEADER_DATA_OFFSET];
2578 (void)ull_chan_map_get(chm_upd_ind->chm);
2579 instant = lll_sync->event_counter + 6U;
2580 chm_upd_ind->instant = sys_cpu_to_le16(instant);
2581
2582 /* Try to add channel map update indication to ACAD */
2583 err = ull_adv_sync_add_to_acad(lll_sync, pdu_prev, pdu, ad, sizeof(*chm_upd_ind) + 2U);
2584 if (err) {
2585 return err;
2586 }
2587
2588 /* Update the LLL to reflect the Channel Map and Instant to use */
2589 chm_last = lll_sync->chm_last + 1U;
2590 if (chm_last == DOUBLE_BUFFER_SIZE) {
2591 chm_last = 0U;
2592 }
2593 lll_sync->chm[chm_last].data_chan_count =
2594 ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map);
2595 lll_sync->chm_instant = instant;
2596
2597 /* Commit the Channel Map Indication in the ACAD field of Periodic
2598 * Advertising
2599 */
2600 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
2601
2602 /* Initiate the Channel Map Indication */
2603 lll_sync->chm_last = chm_last;
2604
2605 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2606 struct ll_adv_sync_set *sync = HDR_LLL2ULL(lll_sync);
2607
2608 if (!sync->is_started) {
2609 /* Sync not started yet, apply new channel map now */
2610 lll_sync->chm_first = lll_sync->chm_last;
2611 }
2612 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2613
2614 return 0;
2615 }
2616
2617 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2618 void ull_adv_sync_lll_syncinfo_fill(struct pdu_adv *pdu, struct lll_adv_aux *lll_aux)
2619 {
2620 struct lll_adv_sync *lll_sync;
2621 struct pdu_adv_sync_info *si;
2622 uint8_t chm_first;
2623
2624 lll_sync = lll_aux->adv->sync;
2625
2626 si = sync_info_get(pdu);
2627 sync_info_offset_fill(si, lll_sync->us_adv_sync_pdu_offset);
2628 si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare +
2629 lll_sync->sync_lazy;
2630
2631 /* Fill the correct channel map to use if at or past the instant */
2632 if (lll_sync->chm_first != lll_sync->chm_last) {
2633 uint16_t instant_latency;
2634
2635 instant_latency = (si->evt_cntr - lll_sync->chm_instant) &
2636 EVENT_INSTANT_MAX;
2637 if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) {
2638 chm_first = lll_sync->chm_last;
2639 } else {
2640 chm_first = lll_sync->chm_first;
2641 }
2642 } else {
2643 chm_first = lll_sync->chm_first;
2644 }
2645 (void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map,
2646 sizeof(si->sca_chm));
2647 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
2648 ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
2649 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |=
2650 ((lll_clock_sca_local_get() <<
2651 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) &
2652 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK);
2653 }
2654
2655 static void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs)
2656 {
2657 uint8_t offs_adjust = 0U;
2658
2659 if (offs >= OFFS_ADJUST_US) {
2660 offs -= OFFS_ADJUST_US;
2661 offs_adjust = 1U;
2662 }
2663
2664 offs = offs / OFFS_UNIT_30_US;
2665 if (!!(offs >> OFFS_UNIT_BITS)) {
2666 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US),
2667 OFFS_UNIT_VALUE_300_US, offs_adjust);
2668 } else {
2669 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs, OFFS_UNIT_VALUE_30_US, offs_adjust);
2670 }
2671 }
2672
2673 #else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2674 static void mfy_sync_offset_get(void *param)
2675 {
2676 struct ll_adv_set *adv = param;
2677 struct lll_adv_sync *lll_sync;
2678 struct ll_adv_sync_set *sync;
2679 struct pdu_adv_sync_info *si;
2680 uint32_t sync_remainder_us;
2681 uint32_t aux_remainder_us;
2682 uint32_t ticks_to_expire;
2683 uint32_t ticks_current;
2684 struct pdu_adv *pdu;
2685 uint32_t remainder = 0U;
2686 uint8_t chm_first;
2687 uint8_t ticker_id;
2688 uint16_t lazy;
2689 uint8_t retry;
2690 uint8_t id;
2691
2692 lll_sync = adv->lll.sync;
2693 sync = HDR_LLL2ULL(lll_sync);
2694 ticker_id = TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync);
2695
2696 id = TICKER_NULL;
2697 ticks_to_expire = 0U;
2698 ticks_current = 0U;
2699 retry = 4U;
2700 do {
2701 uint32_t volatile ret_cb;
2702 uint32_t ticks_previous;
2703 uint32_t ret;
2704 bool success;
2705
2706 ticks_previous = ticks_current;
2707
2708 ret_cb = TICKER_STATUS_BUSY;
2709 ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR,
2710 TICKER_USER_ID_ULL_LOW,
2711 &id, &ticks_current,
2712 &ticks_to_expire, &remainder,
2713 &lazy, NULL, NULL,
2714 ticker_op_cb, (void *)&ret_cb);
2715 if (ret == TICKER_STATUS_BUSY) {
2716 while (ret_cb == TICKER_STATUS_BUSY) {
2717 ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
2718 TICKER_USER_ID_ULL_LOW);
2719 }
2720 }
2721
2722 success = (ret_cb == TICKER_STATUS_SUCCESS);
2723 LL_ASSERT(success);
2724
2725 LL_ASSERT((ticks_current == ticks_previous) || retry--);
2726
2727 LL_ASSERT(id != TICKER_NULL);
2728 } while (id != ticker_id);
2729
2730 /* Reduced a tick for negative remainder and return positive remainder
2731 * value.
2732 */
2733 hal_ticker_remove_jitter(&ticks_to_expire, &remainder);
2734 sync_remainder_us = remainder;
2735
2736 /* Add a tick for negative remainder and return positive remainder
2737 * value.
2738 */
2739 remainder = sync->aux_remainder;
2740 hal_ticker_add_jitter(&ticks_to_expire, &remainder);
2741 aux_remainder_us = remainder;
2742
2743 pdu = lll_adv_aux_data_latest_peek(adv->lll.aux);
2744 si = sync_info_get(pdu);
2745 sync_info_offset_fill(si, ticks_to_expire, sync_remainder_us,
2746 aux_remainder_us);
2747 si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare +
2748 lazy;
2749
2750 /* Fill the correct channel map to use if at or past the instant */
2751 if (lll_sync->chm_first != lll_sync->chm_last) {
2752 uint16_t instant_latency;
2753
2754 instant_latency = (si->evt_cntr - lll_sync->chm_instant) &
2755 EVENT_INSTANT_MAX;
2756 if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) {
2757 chm_first = lll_sync->chm_last;
2758 } else {
2759 chm_first = lll_sync->chm_first;
2760 }
2761 } else {
2762 chm_first = lll_sync->chm_first;
2763 }
2764 (void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map,
2765 sizeof(si->sca_chm));
2766 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
2767 ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
2768 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |=
2769 ((lll_clock_sca_local_get() <<
2770 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) &
2771 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK);
2772 }
2773
2774 static void sync_info_offset_fill(struct pdu_adv_sync_info *si,
2775 uint32_t ticks_offset,
2776 uint32_t remainder_us,
2777 uint32_t start_us)
2778 {
2779 uint8_t offs_adjust = 0U;
2780 uint32_t offs;
2781
2782 offs = HAL_TICKER_TICKS_TO_US(ticks_offset) + remainder_us - start_us;
2783
2784 if (offs >= OFFS_ADJUST_US) {
2785 offs -= OFFS_ADJUST_US;
2786 offs_adjust = 1U;
2787 }
2788
2789 offs = offs / OFFS_UNIT_30_US;
2790 if (!!(offs >> OFFS_UNIT_BITS)) {
2791 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US),
2792 OFFS_UNIT_VALUE_300_US, offs_adjust);
2793 } else {
2794 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs, OFFS_UNIT_VALUE_30_US, offs_adjust);
2795 }
2796 }
2797
2798 static void ticker_op_cb(uint32_t status, void *param)
2799 {
2800 *((uint32_t volatile *)param) = status;
2801 }
2802 #endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2803
2804 static struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu)
2805 {
2806 struct pdu_adv_com_ext_adv *p;
2807 struct pdu_adv_ext_hdr *h;
2808 uint8_t *ptr;
2809
2810 p = (void *)&pdu->adv_ext_ind;
2811 h = (void *)p->ext_hdr_adv_data;
2812 ptr = h->data;
2813
2814 /* traverse through adv_addr, if present */
2815 if (h->adv_addr) {
2816 ptr += BDADDR_SIZE;
2817 }
2818
2819 /* traverse through tgt_addr, if present */
2820 if (h->tgt_addr) {
2821 ptr += BDADDR_SIZE;
2822 }
2823
2824 /* No CTEInfo flag in primary and secondary channel PDU */
2825
2826 /* traverse through adi, if present */
2827 if (h->adi) {
2828 ptr += sizeof(struct pdu_adv_adi);
2829 }
2830
2831 /* traverse through aux ptr, if present */
2832 if (h->aux_ptr) {
2833 ptr += sizeof(struct pdu_adv_aux_ptr);
2834 }
2835
2836 /* return pointer offset to sync_info */
2837 return (void *)ptr;
2838 }
2839
2840 static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
2841 uint32_t remainder, uint16_t lazy, uint8_t force,
2842 void *param)
2843 {
2844 static memq_link_t link;
2845 static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_sync_prepare};
2846 static struct lll_prepare_param p;
2847 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2848 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2849 struct ticker_ext_context *context = param;
2850 struct ll_adv_sync_set *sync = context->context;
2851 #else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2852 struct ll_adv_sync_set *sync = param;
2853 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2854 struct lll_adv_sync *lll;
2855 uint32_t ret;
2856 uint8_t ref;
2857
2858 DEBUG_RADIO_PREPARE_A(1);
2859
2860 lll = &sync->lll;
2861
2862 /* Increment prepare reference count */
2863 ref = ull_ref_inc(&sync->ull);
2864 LL_ASSERT(ref);
2865
2866 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2867 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2868 if (lll->iso) {
2869 struct lll_adv_iso *lll_iso = lll->iso;
2870
2871 LL_ASSERT(context->other_expire_info);
2872
2873 /* Check: No need for remainder in this case? */
2874 lll_iso->ticks_sync_pdu_offset = context->other_expire_info->ticks_to_expire;
2875 lll_iso->iso_lazy = context->other_expire_info->lazy;
2876 }
2877 #endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2878
2879 /* Append timing parameters */
2880 p.ticks_at_expire = ticks_at_expire;
2881 p.remainder = remainder;
2882 p.lazy = lazy;
2883 p.force = force;
2884 p.param = lll;
2885 mfy.param = &p;
2886
2887 /* Kick LLL prepare */
2888 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
2889 TICKER_USER_ID_LLL, 0, &mfy);
2890 LL_ASSERT(!ret);
2891
2892 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2893 !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2894 if (lll->iso) {
2895 ull_adv_iso_offset_get(sync);
2896 }
2897 #endif /* CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2898
2899 DEBUG_RADIO_PREPARE_A(1);
2900 }
2901
2902 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2903 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2904 static void ticker_update_op_cb(uint32_t status, void *param)
2905 {
2906 LL_ASSERT(status == TICKER_STATUS_SUCCESS ||
2907 param == ull_disable_mark_get());
2908 }
2909 #endif /* !CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2910