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_UNKNOWN_ADV_IDENTIFIER;
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 /* TODO: active_to_start feature port */
808 sync->ull.ticks_active_to_start = 0U;
809 sync->ull.ticks_prepare_to_start =
810 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
811 sync->ull.ticks_preempt_to_start =
812 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US);
813 sync->ull.ticks_slot = HAL_TICKER_US_TO_TICKS_CEIL(time_us);
814
815 ticks_slot_offset = MAX(sync->ull.ticks_active_to_start,
816 sync->ull.ticks_prepare_to_start);
817 if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
818 ticks_slot_overhead = ticks_slot_offset;
819 } else {
820 ticks_slot_overhead = 0U;
821 }
822
823 return ticks_slot_overhead;
824 }
825
ull_adv_sync_start(struct ll_adv_set * adv,struct ll_adv_sync_set * sync,uint32_t ticks_anchor,uint32_t ticks_slot_overhead)826 uint32_t ull_adv_sync_start(struct ll_adv_set *adv,
827 struct ll_adv_sync_set *sync,
828 uint32_t ticks_anchor,
829 uint32_t ticks_slot_overhead)
830 {
831 uint32_t volatile ret_cb;
832 uint32_t interval_us;
833 uint8_t sync_handle;
834 uint32_t ret;
835
836 interval_us = (uint32_t)sync->interval * PERIODIC_INT_UNIT_US;
837
838 sync_handle = sync_handle_get(sync);
839
840 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
841 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
842 if (sync->lll.iso) {
843 ll_adv_sync_ticker_ext[sync_handle].expire_info_id =
844 TICKER_ID_ADV_ISO_BASE + sync->lll.iso->handle;
845 } else {
846 ll_adv_sync_ticker_ext[sync_handle].expire_info_id = TICKER_NULL;
847 }
848
849 ll_adv_sync_ticker_ext[sync_handle].ext_timeout_func = ticker_cb;
850
851 ret_cb = TICKER_STATUS_BUSY;
852 ret = ticker_start_ext(
853 #else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
854
855 ret_cb = TICKER_STATUS_BUSY;
856 ret = ticker_start(
857 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
858 TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_THREAD,
859 (TICKER_ID_ADV_SYNC_BASE + sync_handle),
860 ticks_anchor, 0U,
861 HAL_TICKER_US_TO_TICKS(interval_us),
862 HAL_TICKER_REMAINDER(interval_us), TICKER_NULL_LAZY,
863 (sync->ull.ticks_slot + ticks_slot_overhead),
864 ticker_cb, sync,
865 ull_ticker_status_give, (void *)&ret_cb
866 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
867 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
868 ,
869 &ll_adv_sync_ticker_ext[sync_handle]
870 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
871 );
872 ret = ull_ticker_status_take(ret, &ret_cb);
873
874 return ret;
875 }
876
ull_adv_sync_time_update(struct ll_adv_sync_set * sync,struct pdu_adv * pdu)877 uint8_t ull_adv_sync_time_update(struct ll_adv_sync_set *sync,
878 struct pdu_adv *pdu)
879 {
880 uint32_t time_ticks;
881 uint32_t time_us;
882
883 time_us = sync_time_get(sync, pdu);
884 time_ticks = HAL_TICKER_US_TO_TICKS(time_us);
885
886 #if !defined(CONFIG_BT_CTLR_JIT_SCHEDULING)
887 uint32_t volatile ret_cb;
888 uint32_t ticks_minus;
889 uint32_t ticks_plus;
890 uint32_t ret;
891
892 if (sync->ull.ticks_slot > time_ticks) {
893 ticks_minus = sync->ull.ticks_slot - time_ticks;
894 ticks_plus = 0U;
895 } else if (sync->ull.ticks_slot < time_ticks) {
896 ticks_minus = 0U;
897 ticks_plus = time_ticks - sync->ull.ticks_slot;
898 } else {
899 return BT_HCI_ERR_SUCCESS;
900 }
901
902 ret_cb = TICKER_STATUS_BUSY;
903 ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
904 TICKER_USER_ID_THREAD,
905 (TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync)),
906 0, 0, ticks_plus, ticks_minus, 0, 0,
907 ull_ticker_status_give, (void *)&ret_cb);
908 ret = ull_ticker_status_take(ret, &ret_cb);
909 if (ret != TICKER_STATUS_SUCCESS) {
910 return BT_HCI_ERR_CMD_DISALLOWED;
911 }
912 #endif /* !CONFIG_BT_CTLR_JIT_SCHEDULING */
913
914 sync->ull.ticks_slot = time_ticks;
915
916 return BT_HCI_ERR_SUCCESS;
917 }
918
ull_adv_sync_chm_update(void)919 uint8_t ull_adv_sync_chm_update(void)
920 {
921 uint8_t handle;
922
923 handle = CONFIG_BT_CTLR_ADV_SYNC_SET;
924 while (handle--) {
925 (void)sync_chm_update(handle);
926 }
927
928 /* TODO: Should failure due to Channel Map Update being already in
929 * progress be returned to caller?
930 */
931 return 0;
932 }
933
ull_adv_sync_chm_complete(struct node_rx_pdu * rx)934 void ull_adv_sync_chm_complete(struct node_rx_pdu *rx)
935 {
936 struct lll_adv_sync *lll_sync;
937 struct pdu_adv *pdu_prev;
938 struct ll_adv_set *adv;
939 struct pdu_adv *pdu;
940 uint8_t ter_idx;
941 uint8_t err;
942
943 /* Allocate next Sync PDU */
944 pdu_prev = NULL;
945 pdu = NULL;
946 lll_sync = rx->rx_ftr.param;
947 adv = HDR_LLL2ULL(lll_sync->adv);
948 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
949 &pdu_prev, &pdu, NULL, NULL, &ter_idx);
950 LL_ASSERT(!err);
951
952 err = ull_adv_sync_remove_from_acad(lll_sync, pdu_prev, pdu,
953 PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND);
954 LL_ASSERT(!err);
955
956 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
957 }
958
ull_adv_sync_info_fill(struct ll_adv_sync_set * sync,struct pdu_adv_sync_info * si)959 void ull_adv_sync_info_fill(struct ll_adv_sync_set *sync,
960 struct pdu_adv_sync_info *si)
961 {
962 struct lll_adv_sync *lll_sync;
963
964 /* NOTE: sync offset and offset unit filled by secondary prepare.
965 *
966 * If sync_info is part of ADV PDU the offs_adjust field
967 * is always set to 0.
968 */
969 PDU_ADV_SYNC_INFO_OFFS_SET(si, 0U, OFFS_UNIT_VALUE_30_US, 0U);
970
971 /* Fill the interval, access address and CRC init */
972 si->interval = sys_cpu_to_le16(sync->interval);
973 lll_sync = &sync->lll;
974 (void)memcpy(&si->aa, lll_sync->access_addr, sizeof(si->aa));
975 (void)memcpy(si->crc_init, lll_sync->crc_init, sizeof(si->crc_init));
976
977 /* NOTE: Filled by secondary prepare */
978 si->evt_cntr = 0U;
979 }
980
981 #if !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
ull_adv_sync_offset_get(struct ll_adv_set * adv)982 void ull_adv_sync_offset_get(struct ll_adv_set *adv)
983 {
984 static memq_link_t link;
985 static struct mayfly mfy = {0, 0, &link, NULL, mfy_sync_offset_get};
986 uint32_t ret;
987
988 mfy.param = adv;
989 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_ULL_LOW, 1,
990 &mfy);
991 LL_ASSERT(!ret);
992 }
993 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
994
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)995 void ull_adv_sync_pdu_init(struct pdu_adv *pdu, uint8_t ext_hdr_flags,
996 uint8_t phy_s, uint8_t phy_flags,
997 struct pdu_cte_info *cte_info)
998 {
999 struct pdu_adv_com_ext_adv *com_hdr;
1000 struct pdu_adv_ext_hdr *ext_hdr;
1001 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1002 struct pdu_adv_aux_ptr *aux_ptr;
1003 uint32_t cte_len_us;
1004 #endif
1005 uint8_t *dptr;
1006 uint8_t len;
1007
1008 pdu->type = PDU_ADV_TYPE_AUX_SYNC_IND;
1009 pdu->rfu = 0U;
1010 pdu->chan_sel = 0U;
1011
1012 pdu->tx_addr = 0U;
1013 pdu->rx_addr = 0U;
1014
1015 com_hdr = &pdu->adv_ext_ind;
1016 /* Non-connectable and Non-scannable adv mode */
1017 com_hdr->adv_mode = 0U;
1018
1019 ext_hdr = &com_hdr->ext_hdr;
1020 *(uint8_t *)ext_hdr = ext_hdr_flags;
1021 dptr = ext_hdr->data;
1022
1023 LL_ASSERT(!(ext_hdr_flags & (ULL_ADV_PDU_HDR_FIELD_ADVA | ULL_ADV_PDU_HDR_FIELD_TARGETA |
1024 #if !defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1025 ULL_ADV_PDU_HDR_FIELD_ADI |
1026 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1027 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO)));
1028
1029 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1030 if (IS_ENABLED(CONFIG_BT_CTLR_DF_ADV_CTE_TX) &&
1031 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_CTE_INFO)) {
1032 (void)memcpy(dptr, cte_info, sizeof(*cte_info));
1033 cte_len_us = CTE_LEN_US(cte_info->time);
1034 dptr += sizeof(struct pdu_cte_info);
1035 } else {
1036 cte_len_us = 0U;
1037 }
1038 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
1039 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT) &&
1040 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_ADI)) {
1041 dptr += sizeof(struct pdu_adv_adi);
1042 }
1043 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1044 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) &&
1045 (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR)) {
1046 aux_ptr = (void *)dptr;
1047 dptr += sizeof(struct pdu_adv_aux_ptr);
1048 }
1049 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
1050 if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_TX_POWER) {
1051 dptr += sizeof(uint8_t);
1052 }
1053
1054 /* Calc tertiary PDU len */
1055 len = ull_adv_aux_hdr_len_calc(com_hdr, &dptr);
1056 ull_adv_aux_hdr_len_fill(com_hdr, len);
1057
1058 pdu->len = len;
1059
1060 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
1061 /* Fill aux offset in aux pointer field */
1062 if (ext_hdr_flags & ULL_ADV_PDU_HDR_FIELD_AUX_PTR) {
1063 uint32_t offs_us;
1064
1065 offs_us = PDU_AC_US(pdu->len, phy_s, phy_flags) +
1066 EVENT_SYNC_B2B_MAFS_US;
1067 offs_us += cte_len_us;
1068 ull_adv_aux_ptr_fill(aux_ptr, offs_us, phy_s);
1069 }
1070 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
1071 }
1072
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)1073 uint8_t ull_adv_sync_pdu_alloc(struct ll_adv_set *adv,
1074 enum ull_adv_pdu_extra_data_flag extra_data_flag,
1075 struct pdu_adv **ter_pdu_prev, struct pdu_adv **ter_pdu_new,
1076 void **extra_data_prev, void **extra_data_new, uint8_t *ter_idx)
1077 {
1078 struct pdu_adv *pdu_prev, *pdu_new;
1079 struct lll_adv_sync *lll_sync;
1080 void *ed_prev;
1081 #if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
1082 void *ed_new;
1083 #endif
1084
1085 lll_sync = adv->lll.sync;
1086 if (!lll_sync) {
1087 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
1088 }
1089
1090 /* Get reference to previous periodic advertising PDU data */
1091 pdu_prev = lll_adv_sync_data_peek(lll_sync, &ed_prev);
1092
1093 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1094 /* Get reference to new periodic advertising PDU data buffer */
1095 if (extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_ALWAYS ||
1096 (extra_data_flag == ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST && ed_prev)) {
1097 /* If there was an extra data in past PDU data or it is required
1098 * by the hdr_add_fields then allocate memory for it.
1099 */
1100 pdu_new = lll_adv_sync_data_alloc(lll_sync, &ed_new,
1101 ter_idx);
1102 if (!pdu_new) {
1103 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1104 }
1105 } else {
1106 ed_new = NULL;
1107 #else
1108 {
1109 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1110 pdu_new = lll_adv_sync_data_alloc(lll_sync, NULL, ter_idx);
1111 if (!pdu_new) {
1112 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1113 }
1114 }
1115
1116 #if defined(CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY)
1117 if (extra_data_prev) {
1118 *extra_data_prev = ed_prev;
1119 }
1120 if (extra_data_new) {
1121 *extra_data_new = ed_new;
1122 }
1123 #endif /* CONFIG_BT_CTLR_ADV_EXT_PDU_EXTRA_DATA_MEMORY */
1124
1125 *ter_pdu_prev = pdu_prev;
1126 *ter_pdu_new = pdu_new;
1127
1128 return 0;
1129 }
1130
1131 uint8_t ull_adv_sync_duplicate(const struct pdu_adv *pdu_prev, struct pdu_adv *pdu_new)
1132 {
1133 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1134 /* Duplicate chain PDUs */
1135 return ull_adv_sync_duplicate_chain(pdu_prev, pdu_new);
1136 #else
1137 ull_adv_sync_copy_pdu(pdu_prev, pdu_new);
1138
1139 return 0U;
1140 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1141 }
1142
1143 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK) || defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX) || \
1144 defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1145 static void ull_adv_sync_add_to_header(struct pdu_adv *pdu,
1146 const struct pdu_adv_ext_hdr *fields,
1147 uint8_t *ad_overflow, uint8_t *overflow_len)
1148 {
1149 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1150 uint8_t delta = 0U;
1151 uint8_t *dptr;
1152
1153 if (overflow_len) {
1154 *overflow_len = 0U;
1155 }
1156
1157 /* AdvA, TargetA and SyncInfo is RFU for periodic advertising */
1158 if (fields->cte_info && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.cte_info == 0U)) {
1159 delta += sizeof(struct pdu_cte_info);
1160 }
1161 if (fields->adi && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.adi == 0U)) {
1162 delta += sizeof(struct pdu_adv_adi);
1163 }
1164 if (fields->aux_ptr && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.aux_ptr == 0U)) {
1165 delta += sizeof(struct pdu_adv_aux_ptr);
1166 }
1167 if (fields->tx_pwr && (hdr->ext_hdr_len == 0U || hdr->ext_hdr.tx_pwr == 0U)) {
1168 delta += 1U;
1169 }
1170
1171 if (delta == 0U) {
1172 /* No new fields to add */
1173 return;
1174 }
1175
1176 if (hdr->ext_hdr_len == 0) {
1177 /* Add one byte for the header flags */
1178 delta++;
1179 }
1180
1181 /* Push back any adv data - overflow will be returned via ad_overflow */
1182 if (pdu->len > hdr->ext_hdr_len + 1U) {
1183 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - delta) {
1184 LL_ASSERT(ad_overflow);
1185 LL_ASSERT(overflow_len);
1186 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1187 *overflow_len = delta - (PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len);
1188 memcpy(ad_overflow,
1189 pdu->payload + PDU_AC_EXT_PAYLOAD_SIZE_MAX - *overflow_len,
1190 *overflow_len);
1191 pdu->len -= *overflow_len;
1192 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1193 }
1194 dptr = pdu->payload + hdr->ext_hdr_len + 1U;
1195 memmove(dptr + delta,
1196 dptr, pdu->len - hdr->ext_hdr_len - 1U);
1197 }
1198
1199 pdu->len += delta;
1200
1201 if (hdr->ext_hdr_len == 0U) {
1202 /* No extended header present, adding one */
1203 memcpy(&hdr->ext_hdr, fields, sizeof(struct pdu_adv_ext_hdr));
1204 hdr->ext_hdr_len = delta;
1205 } else {
1206 /* Go to end of current extended header and push back fields/ACAD in reverse */
1207 dptr = hdr->ext_hdr.data;
1208
1209 /* AdvA and TargetA is RFU for periodic advertising */
1210
1211 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1212 if (hdr->ext_hdr.cte_info) {
1213 dptr += sizeof(struct pdu_cte_info);
1214 }
1215 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1216
1217 if (hdr->ext_hdr.adi) {
1218 dptr += sizeof(struct pdu_adv_adi);
1219 }
1220
1221 if (hdr->ext_hdr.aux_ptr) {
1222 dptr += sizeof(struct pdu_adv_aux_ptr);
1223 }
1224
1225 /* SyncInfo is RFU for periodic advertising */
1226
1227 if (hdr->ext_hdr.tx_pwr) {
1228 dptr++;
1229 }
1230
1231 /* Push back ACAD if any */
1232 if ((dptr - hdr->ext_hdr_adv_data) < hdr->ext_hdr_len) {
1233 uint8_t acad_len = hdr->ext_hdr_len - (dptr - hdr->ext_hdr_adv_data);
1234
1235 memmove(dptr + delta, dptr, acad_len);
1236 }
1237
1238 /* Set new header size now before starting to decrement delta */
1239 hdr->ext_hdr_len += delta;
1240
1241 /* Now push back or add fields as needed */
1242
1243 if (hdr->ext_hdr.tx_pwr) {
1244 dptr--;
1245 *(dptr + delta) = *dptr;
1246 } else if (fields->tx_pwr) {
1247 hdr->ext_hdr.tx_pwr = 1U;
1248 delta -= 1U;
1249 }
1250
1251 if (hdr->ext_hdr.aux_ptr) {
1252 dptr -= sizeof(struct pdu_adv_aux_ptr);
1253 memmove(dptr + delta, dptr, sizeof(struct pdu_adv_aux_ptr));
1254 } else if (fields->aux_ptr) {
1255 hdr->ext_hdr.aux_ptr = 1U;
1256 delta -= sizeof(struct pdu_adv_aux_ptr);
1257 }
1258
1259 if (hdr->ext_hdr.adi) {
1260 dptr -= sizeof(struct pdu_adv_adi);
1261 memmove(dptr + delta, dptr, sizeof(struct pdu_adv_adi));
1262 } else if (fields->adi) {
1263 hdr->ext_hdr.adi = 1U;
1264 delta -= sizeof(struct pdu_adv_adi);
1265 }
1266
1267 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1268 if (hdr->ext_hdr.cte_info) {
1269 dptr -= sizeof(struct pdu_cte_info);
1270 memmove(dptr + delta, dptr, sizeof(struct pdu_cte_info));
1271 } else if (fields->cte_info) {
1272 hdr->ext_hdr.cte_info = 1U;
1273 delta -= sizeof(struct pdu_cte_info);
1274 }
1275 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1276 }
1277 }
1278
1279 static void ull_adv_sync_remove_from_header(struct pdu_adv *pdu,
1280 const struct pdu_adv_ext_hdr *fields,
1281 bool acad)
1282 {
1283 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1284 uint8_t orig_hdr_len = hdr->ext_hdr_len;
1285 uint8_t *dptr;
1286
1287 if (orig_hdr_len == 0U) {
1288 return;
1289 }
1290
1291 dptr = hdr->ext_hdr.data;
1292
1293 /* AdvA and TargetA is RFU for periodic advertising */
1294
1295 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1296 if (hdr->ext_hdr.cte_info) {
1297 if (fields->cte_info) {
1298 memmove(dptr, dptr + sizeof(struct pdu_cte_info),
1299 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1300 hdr->ext_hdr.cte_info = 0U;
1301 hdr->ext_hdr_len -= sizeof(struct pdu_cte_info);
1302 } else {
1303 dptr += sizeof(struct pdu_cte_info);
1304 }
1305 }
1306 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1307
1308 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1309 if (hdr->ext_hdr.adi) {
1310 if (fields->adi) {
1311 memmove(dptr, dptr + sizeof(struct pdu_adv_adi),
1312 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1313 hdr->ext_hdr.adi = 0U;
1314 hdr->ext_hdr_len -= sizeof(struct pdu_adv_adi);
1315 } else {
1316 dptr += sizeof(struct pdu_adv_adi);
1317 }
1318 }
1319 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1320
1321 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1322 if (hdr->ext_hdr.aux_ptr) {
1323 if (fields->aux_ptr) {
1324 memmove(dptr, dptr + sizeof(struct pdu_adv_aux_ptr),
1325 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1326 hdr->ext_hdr.aux_ptr = 0U;
1327 hdr->ext_hdr_len -= sizeof(struct pdu_adv_aux_ptr);
1328 } else {
1329 dptr += sizeof(struct pdu_adv_aux_ptr);
1330 }
1331 }
1332 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1333
1334 /* SyncInfo is RFU for periodic advertising */
1335
1336 if (hdr->ext_hdr.tx_pwr) {
1337 if (fields->tx_pwr) {
1338 memmove(dptr, dptr + 1U,
1339 hdr->ext_hdr_len - (hdr->ext_hdr.data - dptr));
1340 hdr->ext_hdr.tx_pwr = 0U;
1341 hdr->ext_hdr_len -= 1U;
1342 } else {
1343 dptr++;
1344 }
1345 }
1346
1347 /* ACAD is the remainder of the header, if any left */
1348 if (acad) {
1349 /* Drop any ACAD */
1350 hdr->ext_hdr_len = dptr - hdr->ext_hdr_adv_data;
1351 }
1352
1353 if (hdr->ext_hdr_len == 1U) {
1354 /* Only flags left in header, remove it completely */
1355 hdr->ext_hdr_len = 0U;
1356 }
1357
1358 if (orig_hdr_len != hdr->ext_hdr_len) {
1359 /* Move adv data if any */
1360 if (pdu->len > orig_hdr_len + 1U) {
1361 memmove(hdr->ext_hdr_adv_data + hdr->ext_hdr_len,
1362 hdr->ext_hdr_adv_data + orig_hdr_len,
1363 pdu->len - orig_hdr_len - 1U);
1364 }
1365
1366 /* Update total PDU len */
1367 pdu->len -= orig_hdr_len - hdr->ext_hdr_len;
1368 }
1369
1370 }
1371 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK || CONFIG_BT_CTLR_DF_ADV_CTE_TX || \
1372 * CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT
1373 */
1374
1375 static void ull_adv_sync_copy_pdu_header(struct pdu_adv *target_pdu,
1376 const struct pdu_adv *source_pdu,
1377 const struct pdu_adv_ext_hdr *skip_fields,
1378 bool skip_acad)
1379 {
1380 const struct pdu_adv_com_ext_adv *source_hdr = &source_pdu->adv_ext_ind;
1381 struct pdu_adv_com_ext_adv *target_hdr = &target_pdu->adv_ext_ind;
1382 const uint8_t *source_dptr;
1383 uint8_t *target_dptr;
1384
1385 LL_ASSERT(target_pdu != source_pdu);
1386
1387 /* Initialize PDU header */
1388 target_pdu->type = source_pdu->type;
1389 target_pdu->rfu = 0U;
1390 target_pdu->chan_sel = 0U;
1391 target_pdu->tx_addr = 0U;
1392 target_pdu->rx_addr = 0U;
1393 target_hdr->adv_mode = source_hdr->adv_mode;
1394
1395 /* Copy extended header */
1396 if (source_hdr->ext_hdr_len == 0U) {
1397 /* No extended header present */
1398 target_hdr->ext_hdr_len = 0U;
1399 } else if (!skip_fields && !skip_acad) {
1400 /* Copy entire extended header */
1401 memcpy(target_hdr, source_hdr, source_hdr->ext_hdr_len + 1U);
1402 } else {
1403 /* Copy field by field */
1404
1405 source_dptr = source_hdr->ext_hdr.data;
1406 target_dptr = target_hdr->ext_hdr.data;
1407
1408 /* Initialize extended header flags to all 0 */
1409 target_hdr->ext_hdr_adv_data[0U] = 0U;
1410
1411 /* AdvA and TargetA is RFU for periodic advertising */
1412
1413 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1414 if (source_hdr->ext_hdr.cte_info) {
1415 if (!skip_fields->cte_info) {
1416 memcpy(target_dptr, source_dptr, sizeof(struct pdu_cte_info));
1417 target_dptr += sizeof(struct pdu_cte_info);
1418 target_hdr->ext_hdr.cte_info = 1U;
1419 }
1420 source_dptr += sizeof(struct pdu_cte_info);
1421 }
1422 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1423
1424 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1425 if (source_hdr->ext_hdr.adi) {
1426 if (!skip_fields->adi) {
1427 memcpy(target_dptr, source_dptr, sizeof(struct pdu_adv_adi));
1428 target_dptr += sizeof(struct pdu_adv_adi);
1429 target_hdr->ext_hdr.adi = 1U;
1430 }
1431 source_dptr += sizeof(struct pdu_adv_adi);
1432 }
1433 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1434
1435 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1436 if (source_hdr->ext_hdr.aux_ptr) {
1437 if (!skip_fields->aux_ptr) {
1438 memcpy(target_dptr, source_dptr, sizeof(struct pdu_adv_aux_ptr));
1439 target_dptr += sizeof(struct pdu_adv_aux_ptr);
1440 target_hdr->ext_hdr.aux_ptr = 1U;
1441 }
1442 source_dptr += sizeof(struct pdu_adv_aux_ptr);
1443 }
1444 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1445
1446 /* SyncInfo is RFU for periodic advertising */
1447
1448 if (source_hdr->ext_hdr.tx_pwr) {
1449 if (!skip_fields->tx_pwr) {
1450 *target_dptr = *source_dptr;
1451 target_dptr++;
1452 target_hdr->ext_hdr.tx_pwr = 1U;
1453 }
1454 source_dptr++;
1455 }
1456
1457 /* ACAD is the remainder of the header, if any left */
1458 if ((source_dptr - source_hdr->ext_hdr_adv_data) < source_hdr->ext_hdr_len &&
1459 !skip_acad) {
1460 uint8_t acad_len = source_hdr->ext_hdr_len -
1461 (source_dptr - source_hdr->ext_hdr_adv_data);
1462
1463 memcpy(target_dptr, source_dptr, acad_len);
1464 target_dptr += acad_len;
1465 }
1466
1467 if (target_dptr == target_hdr->ext_hdr.data) {
1468 /* Nothing copied, do not include extended header */
1469 target_hdr->ext_hdr_len = 0U;
1470 } else {
1471 target_hdr->ext_hdr_len = target_dptr - target_hdr->ext_hdr_adv_data;
1472 }
1473 }
1474
1475 target_pdu->len = target_hdr->ext_hdr_len + 1U;
1476 }
1477
1478 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1479 static void ull_adv_sync_update_pdu_adi(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu,
1480 uint16_t did)
1481 {
1482 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1483 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1484 struct pdu_adv_adi *adi;
1485 uint8_t *dptr;
1486
1487 if (hdr->ext_hdr_len == 0U || hdr->ext_hdr.adi == 0U) {
1488 /* No ADI field present, nothing to do */
1489 return;
1490 }
1491
1492 /* Find ADI in extended header */
1493 dptr = hdr->ext_hdr.data;
1494
1495 /* AdvA and TargetA is RFU for periodic advertising */
1496
1497 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1498 if (hdr->ext_hdr.cte_info) {
1499 dptr += sizeof(struct pdu_cte_info);
1500 }
1501 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1502
1503 adi = (struct pdu_adv_adi *)dptr;
1504
1505 PDU_ADV_ADI_DID_SID_SET(adi, did, adv->sid);
1506 }
1507 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1508
1509 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1510 static void ull_adv_sync_add_aux_ptr(struct pdu_adv *pdu, uint8_t *ad_overflow,
1511 uint8_t *overflow_len)
1512 {
1513 struct pdu_adv_ext_hdr fields = { 0U };
1514
1515 fields.aux_ptr = 1U;
1516 ull_adv_sync_add_to_header(pdu, &fields, ad_overflow, overflow_len);
1517 }
1518
1519 static void ull_adv_sync_update_aux_ptr(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu)
1520 {
1521 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1522 struct pdu_adv_aux_ptr *aux_ptr;
1523 struct ll_adv_set *adv;
1524 uint32_t offs_us;
1525 uint8_t *dptr;
1526 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1527 struct pdu_cte_info *cte_info = NULL;
1528 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1529
1530 if (!hdr->ext_hdr_len || !hdr->ext_hdr.aux_ptr) {
1531 /* Nothing to update */
1532 return;
1533 }
1534
1535 /* Find AuxPtr */
1536 dptr = hdr->ext_hdr.data;
1537
1538 /* AdvA and TargetA is RFU for periodic advertising */
1539
1540 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1541 if (hdr->ext_hdr.cte_info) {
1542 cte_info = (struct pdu_cte_info *)dptr;
1543 dptr += sizeof(struct pdu_cte_info);
1544 }
1545 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1546
1547 if (hdr->ext_hdr.adi) {
1548 dptr += sizeof(struct pdu_adv_adi);
1549 }
1550
1551 /* Now at AuxPtr */
1552 aux_ptr = (struct pdu_adv_aux_ptr *)dptr;
1553
1554 /* Calculate and set offset */
1555 adv = HDR_LLL2ULL(lll_sync->adv);
1556 offs_us = PDU_AC_US(pdu->len, adv->lll.phy_s, adv->lll.phy_flags) + EVENT_SYNC_B2B_MAFS_US;
1557
1558 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1559 /* Add CTE time if relevant */
1560 if (cte_info) {
1561 offs_us += CTE_LEN_US(cte_info->time);
1562 }
1563 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1564
1565 ull_adv_aux_ptr_fill(aux_ptr, offs_us, adv->lll.phy_s);
1566 }
1567 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1568
1569 static uint8_t ull_adv_sync_append_ad_data(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu,
1570 const uint8_t *ad, uint8_t ad_len, uint8_t max_ad_len)
1571 {
1572 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1573 uint8_t ad_overflow[sizeof(struct pdu_adv_aux_ptr) + 1U];
1574 uint8_t overflow_len = 0U;
1575 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1576
1577 while (ad_len) {
1578 uint8_t pdu_ad_len;
1579 uint8_t *dptr;
1580 uint8_t ext_hdr_len;
1581 uint8_t pdu_add_len = ad_len;
1582
1583 ext_hdr_len = pdu->adv_ext_ind.ext_hdr_len + 1U;
1584 pdu_ad_len = pdu->len - ext_hdr_len;
1585
1586 /* Check if the adv data exceeds the configured maximum */
1587 /* FIXME - this check should include the entire chain */
1588 if (pdu_ad_len + ad_len > CONFIG_BT_CTLR_ADV_DATA_LEN_MAX) {
1589 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1590 }
1591
1592 /* Only allow up to max_ad_len adv data per PDU */
1593 if (pdu_ad_len + ad_len > max_ad_len ||
1594 PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len < ad_len) {
1595 #if !defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1596 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1597 #else
1598 /* Will fragment into chain PDU */
1599
1600 /* Add aux_ptr to existing PDU */
1601 ull_adv_sync_add_aux_ptr(pdu, ad_overflow, &overflow_len);
1602
1603 pdu_add_len = MAX(0U, MIN(max_ad_len - pdu_ad_len,
1604 PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len));
1605 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1606 }
1607
1608 dptr = pdu->payload + pdu->len;
1609
1610 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1611 if (pdu_add_len && overflow_len) {
1612 /* Overflow from previous PDU in chain, add this first */
1613 memcpy(dptr, ad, overflow_len);
1614 pdu->len += overflow_len;
1615 dptr += overflow_len;
1616 overflow_len = 0U;
1617 }
1618 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1619
1620 if (pdu_add_len) {
1621 memcpy(dptr, ad, pdu_add_len);
1622 pdu->len += pdu_add_len;
1623 ad_len -= pdu_add_len;
1624 ad += pdu_add_len;
1625 }
1626 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1627 if (ad_len) {
1628 struct pdu_adv_ext_hdr skip_fields = { 0U };
1629 struct pdu_adv *pdu_chain;
1630
1631 /* Fill the aux offset in superior PDU */
1632 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
1633
1634 /* Allocate new PDU */
1635 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
1636 if (!pdu_chain) {
1637 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1638 }
1639
1640 /* Copy header, removing AuxPtr, CTEInfo and ACAD */
1641 skip_fields.aux_ptr = 1U;
1642 skip_fields.cte_info = 1U;
1643 ull_adv_sync_copy_pdu_header(pdu_chain, pdu, &skip_fields, true);
1644
1645 /* Chain the PDU */
1646 lll_adv_pdu_linked_append(pdu_chain, pdu);
1647
1648 pdu = pdu_chain;
1649 }
1650 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1651 }
1652
1653 return 0U;
1654 }
1655
1656 static void ull_adv_sync_copy_pdu(const struct pdu_adv *pdu_prev,
1657 struct pdu_adv *pdu)
1658 {
1659 if (pdu == pdu_prev) {
1660 return;
1661 }
1662
1663 /* Initialize PDU header */
1664 pdu->type = pdu_prev->type;
1665 pdu->rfu = 0U;
1666 pdu->chan_sel = 0U;
1667 pdu->tx_addr = 0U;
1668 pdu->rx_addr = 0U;
1669 pdu->len = pdu_prev->len;
1670
1671 /* Copy PDU payload */
1672 memcpy(pdu->payload, pdu_prev->payload, pdu_prev->len);
1673 }
1674
1675 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1676 static uint8_t ull_adv_sync_duplicate_chain(const struct pdu_adv *pdu_prev,
1677 struct pdu_adv *pdu)
1678 {
1679 /* If pdu_prev == pdu we are done */
1680 if (pdu == pdu_prev) {
1681 return 0U;
1682 }
1683
1684 /* Copy existing PDU chain */
1685 while (pdu_prev) {
1686 struct pdu_adv *pdu_chain;
1687
1688 ull_adv_sync_copy_pdu(pdu_prev, pdu);
1689
1690 pdu_prev = lll_adv_pdu_linked_next_get(pdu_prev);
1691 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
1692 if (pdu_prev && !pdu_chain) {
1693 /* Get a new chain PDU */
1694 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
1695 if (!pdu_chain) {
1696 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
1697 }
1698
1699 /* Link the chain PDU to parent PDU */
1700 lll_adv_pdu_linked_append(pdu_chain, pdu);
1701 pdu = pdu_chain;
1702 }
1703 }
1704
1705 return 0U;
1706 }
1707 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1708
1709 static uint8_t ull_adv_sync_ad_add(struct lll_adv_sync *lll_sync,
1710 struct pdu_adv *ter_pdu_prev,
1711 struct pdu_adv *ter_pdu,
1712 const uint8_t *ad, uint8_t ad_len)
1713 {
1714 uint8_t pdu_ad_max_len = PDU_AC_EXT_AD_DATA_LEN_MAX;
1715 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1716 uint8_t err;
1717
1718 err = ull_adv_sync_duplicate_chain(ter_pdu_prev, ter_pdu);
1719 if (err) {
1720 return err;
1721 }
1722
1723 /* Find end of current advertising data */
1724 while (lll_adv_pdu_linked_next_get(ter_pdu)) {
1725 ter_pdu = lll_adv_pdu_linked_next_get(ter_pdu);
1726 ter_pdu_prev = lll_adv_pdu_linked_next_get(ter_pdu_prev);
1727
1728 /* Use the full PDU payload for AUX_CHAIN_IND */
1729 pdu_ad_max_len = PDU_AC_EXT_PAYLOAD_SIZE_MAX;
1730
1731 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1732 /* Detect end of current advertising data */
1733 if (ter_pdu->len < PDU_AC_EXT_PAYLOAD_SIZE_MAX) {
1734 break;
1735 }
1736 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1737 }
1738 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1739 /* Initialize PDU header */
1740 ter_pdu->type = ter_pdu_prev->type;
1741 ter_pdu->rfu = 0U;
1742 ter_pdu->chan_sel = 0U;
1743 ter_pdu->tx_addr = 0U;
1744 ter_pdu->rx_addr = 0U;
1745 ter_pdu->len = ter_pdu_prev->len;
1746
1747 /* Copy PDU payload */
1748 memcpy(ter_pdu->payload, ter_pdu_prev->payload, ter_pdu_prev->len);
1749 #endif /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1750
1751 /* At end of copied chain, append new adv data */
1752 return ull_adv_sync_append_ad_data(lll_sync, ter_pdu, ad, ad_len, pdu_ad_max_len);
1753 }
1754
1755 static uint8_t ull_adv_sync_ad_replace(struct lll_adv_sync *lll_sync,
1756 struct pdu_adv *ter_pdu_prev,
1757 struct pdu_adv *ter_pdu,
1758 const uint8_t *ad, uint8_t ad_len)
1759 {
1760 struct pdu_adv_ext_hdr skip_fields = { 0U };
1761
1762 skip_fields.aux_ptr = 1U;
1763
1764 /* FIXME - below ignores any configured CTE count */
1765 if (ter_pdu_prev == ter_pdu) {
1766 /* Remove adv data and any AuxPtr */
1767 ter_pdu->len = ter_pdu_prev->adv_ext_ind.ext_hdr_len + 1U;
1768 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1769 ull_adv_sync_remove_from_header(ter_pdu, &skip_fields, false);
1770 /* Delete any existing PDU chain */
1771 if (lll_adv_pdu_linked_next_get(ter_pdu)) {
1772 lll_adv_pdu_linked_release_all(lll_adv_pdu_linked_next_get(ter_pdu));
1773 lll_adv_pdu_linked_append(NULL, ter_pdu);
1774 }
1775 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1776 } else {
1777 /* Copy header (only), removing any prior presence of Aux Ptr */
1778 ull_adv_sync_copy_pdu_header(ter_pdu, ter_pdu_prev, &skip_fields, false);
1779 }
1780
1781 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1782 /* New adv data - update ADI if present */
1783 if (ter_pdu->adv_ext_ind.ext_hdr_len && ter_pdu->adv_ext_ind.ext_hdr.adi) {
1784 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1785 uint16_t did;
1786
1787 /* The DID for a specific SID shall be unique */
1788 did = sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid));
1789 ull_adv_sync_update_pdu_adi(lll_sync, ter_pdu, did);
1790 }
1791 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1792
1793 /* Set advertising data (without copying any existing adv data) */
1794 return ull_adv_sync_append_ad_data(lll_sync, ter_pdu, ad, ad_len,
1795 PDU_AC_EXT_AD_DATA_LEN_MAX);
1796 }
1797
1798 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
1799 static uint8_t ull_adv_sync_update_adi(struct lll_adv_sync *lll_sync,
1800 struct pdu_adv *ter_pdu_prev,
1801 struct pdu_adv *ter_pdu)
1802 {
1803 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1804 uint16_t did;
1805
1806 /* The DID for a specific SID shall be unique */
1807 did = sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid));
1808
1809 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1810 uint8_t err;
1811
1812 err = ull_adv_sync_duplicate_chain(ter_pdu_prev, ter_pdu);
1813 if (err) {
1814 return err;
1815 }
1816
1817 /* Loop through chain and set new ADI for all */
1818 while (ter_pdu) {
1819 ull_adv_sync_update_pdu_adi(lll_sync, ter_pdu, did);
1820 ter_pdu = lll_adv_pdu_linked_next_get(ter_pdu);
1821 }
1822 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1823 /* Initialize PDU header */
1824 ter_pdu->type = ter_pdu_prev->type;
1825 ter_pdu->rfu = 0U;
1826 ter_pdu->chan_sel = 0U;
1827 ter_pdu->tx_addr = 0U;
1828 ter_pdu->rx_addr = 0U;
1829 ter_pdu->len = ter_pdu_prev->len;
1830
1831 /* Copy PDU payload */
1832 memcpy(ter_pdu->payload, ter_pdu_prev->payload, ter_pdu_prev->len);
1833
1834 /* Set new ADI */
1835 ull_adv_sync_update_pdu_adi(lll_sync, ter_pdu, did);
1836 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK*/
1837 return 0U;
1838 }
1839
1840 static uint8_t ull_adv_sync_add_adi(struct lll_adv_sync *lll_sync,
1841 struct pdu_adv *pdu_prev,
1842 struct pdu_adv *pdu)
1843 {
1844 struct ll_adv_set *adv = HDR_LLL2ULL(lll_sync->adv);
1845 struct pdu_adv_ext_hdr add_fields = { 0U };
1846 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1847 uint8_t ad_overflow[sizeof(struct pdu_adv_adi)*MAX_FRAG_COUNT];
1848 uint8_t total_overflow_len;
1849 struct pdu_adv *last_pdu;
1850 uint8_t overflow_len;
1851 uint8_t err;
1852 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1853 uint16_t did;
1854
1855 add_fields.adi = 1U;
1856
1857 /* The DID for a specific SID shall be unique */
1858 did = sys_cpu_to_le16(ull_adv_aux_did_next_unique_get(adv->sid));
1859
1860 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1861 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
1862 if (err) {
1863 return err;
1864 }
1865
1866 total_overflow_len = 0U;
1867 /* Loop through chain and add ADI for all */
1868 while (pdu) {
1869 last_pdu = pdu;
1870
1871 /* We should always have enough available overflow space to fit an ADI */
1872 LL_ASSERT(total_overflow_len + sizeof(struct pdu_adv_adi) <= sizeof(ad_overflow));
1873
1874 ull_adv_sync_add_to_header(pdu, &add_fields,
1875 &ad_overflow[total_overflow_len], &overflow_len);
1876 total_overflow_len += overflow_len;
1877 ull_adv_sync_update_pdu_adi(lll_sync, pdu, did);
1878 pdu = lll_adv_pdu_linked_next_get(pdu);
1879 if (pdu) {
1880 uint8_t ad_overflow_tmp[sizeof(struct pdu_adv_adi)*MAX_FRAG_COUNT];
1881 uint8_t overflow_tmp_len = 0U;
1882 uint8_t pdu_avail = PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len;
1883 uint8_t pdu_needed = total_overflow_len;
1884 uint8_t *dptr;
1885
1886 if (!pdu->adv_ext_ind.ext_hdr.adi) {
1887 pdu_needed += sizeof(struct pdu_adv_adi);
1888 }
1889 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
1890 /* Make room for flags as well */
1891 pdu_needed++;
1892 }
1893
1894 if (total_overflow_len > 0U) {
1895 if (pdu_avail < pdu_needed) {
1896 /* Make room by removing last part of adv data */
1897 overflow_tmp_len = pdu_needed - pdu_avail;
1898 memcpy(ad_overflow_tmp,
1899 pdu->payload + (pdu->len - overflow_tmp_len),
1900 overflow_tmp_len);
1901 pdu->len -= overflow_tmp_len;
1902 }
1903
1904 /* Prepend overflow from last PDU */
1905 dptr = pdu->payload + pdu->adv_ext_ind.ext_hdr_len + 1U;
1906 memmove(dptr + total_overflow_len, dptr,
1907 pdu->len - pdu->adv_ext_ind.ext_hdr_len - 1U +
1908 total_overflow_len);
1909 pdu->len += total_overflow_len;
1910 memcpy(dptr, ad_overflow, total_overflow_len);
1911
1912 /* Carry forward overflow from this PDU */
1913 total_overflow_len = overflow_tmp_len;
1914 if (overflow_tmp_len) {
1915 memcpy(ad_overflow, ad_overflow_tmp, overflow_tmp_len);
1916 }
1917 }
1918 }
1919 }
1920
1921 /* Push any remaining overflow on to last PDU */
1922 ull_adv_sync_append_ad_data(lll_sync, pdu, ad_overflow, total_overflow_len,
1923 PDU_AC_EXT_PAYLOAD_SIZE_MAX);
1924
1925 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1926
1927 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - sizeof(struct pdu_adv_adi)) {
1928 /* No room for ADI */
1929 return BT_HCI_ERR_PACKET_TOO_LONG;
1930 }
1931
1932 /* Initialize PDU header */
1933 pdu->type = pdu_prev->type;
1934 pdu->rfu = 0U;
1935 pdu->chan_sel = 0U;
1936 pdu->tx_addr = 0U;
1937 pdu->rx_addr = 0U;
1938 pdu->len = pdu_prev->len;
1939
1940 /* Copy PDU payload */
1941 memcpy(pdu->payload, pdu_prev->payload, pdu_prev->len);
1942
1943 /* Add and set new ADI */
1944 ull_adv_sync_add_to_header(pdu, &add_fields, NULL, NULL);
1945 ull_adv_sync_update_pdu_adi(lll_sync, pdu, did);
1946 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1947 return 0U;
1948 }
1949
1950 static uint8_t ull_adv_sync_remove_adi(struct lll_adv_sync *lll_sync,
1951 struct pdu_adv *pdu_prev,
1952 struct pdu_adv *pdu)
1953 {
1954 struct pdu_adv_ext_hdr remove_fields = { 0U };
1955 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1956 uint8_t err;
1957 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1958
1959 remove_fields.adi = 1U;
1960
1961 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
1962 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
1963 if (err) {
1964 return err;
1965 }
1966
1967 /* Loop through chain and remove ADI for all */
1968 while (pdu) {
1969 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
1970 if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
1971 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
1972 }
1973 pdu = lll_adv_pdu_linked_next_get(pdu);
1974 }
1975 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1976 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
1977 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
1978
1979 return 0U;
1980 }
1981 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
1982
1983 uint8_t *ull_adv_sync_get_acad(struct pdu_adv *pdu, uint8_t *acad_len)
1984 {
1985 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
1986 uint8_t *dptr;
1987
1988 /* Skip to ACAD */
1989 dptr = hdr->ext_hdr.data;
1990
1991 /* AdvA and TargetA is RFU for periodic advertising */
1992
1993 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
1994 if (hdr->ext_hdr.cte_info) {
1995 dptr += sizeof(struct pdu_cte_info);
1996 }
1997 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
1998
1999 #if defined(CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT)
2000 if (hdr->ext_hdr.adi) {
2001 dptr += sizeof(struct pdu_adv_adi);
2002 }
2003 #endif /* CONFIG_BT_CTLR_ADV_PERIODIC_ADI_SUPPORT */
2004
2005 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2006 if (hdr->ext_hdr.aux_ptr) {
2007 dptr += sizeof(struct pdu_adv_aux_ptr);
2008 }
2009 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2010
2011 /* SyncInfo is RFU for periodic advertising */
2012
2013 if (hdr->ext_hdr.tx_pwr) {
2014 dptr++;
2015 }
2016
2017 /* ACAD is the remainder of the header, if any left */
2018 if ((dptr - hdr->ext_hdr_adv_data) < hdr->ext_hdr_len) {
2019 *acad_len = hdr->ext_hdr_len - (dptr - hdr->ext_hdr_adv_data);
2020 } else {
2021 *acad_len = 0U;
2022 }
2023
2024 return dptr;
2025 }
2026
2027 uint8_t ull_adv_sync_remove_from_acad(struct lll_adv_sync *lll_sync,
2028 struct pdu_adv *pdu_prev,
2029 struct pdu_adv *pdu,
2030 uint8_t ad_type)
2031 {
2032 uint8_t acad_len;
2033 uint8_t ad_len;
2034 uint8_t *acad;
2035 uint8_t len;
2036 uint8_t *ad;
2037 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2038 uint8_t err;
2039
2040 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2041 if (err) {
2042 return err;
2043 }
2044 #else
2045 ull_adv_sync_copy_pdu(pdu_prev, pdu);
2046 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2047
2048 acad = ull_adv_sync_get_acad(pdu, &acad_len);
2049
2050 if (acad_len == 0U) {
2051 return 0U;
2052 }
2053
2054 /* Find the relevant entry */
2055 len = acad_len;
2056 ad = acad;
2057 do {
2058 ad_len = ad[PDU_ADV_DATA_HEADER_LEN_OFFSET];
2059 if (ad_len && (ad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] == ad_type)) {
2060 break;
2061 }
2062
2063 ad_len += 1U;
2064
2065 LL_ASSERT(ad_len <= len);
2066
2067 ad += ad_len;
2068 len -= ad_len;
2069 } while (len);
2070
2071 if (len == 0U) {
2072 /* Entry is not present */
2073 return 0U;
2074 }
2075
2076 /* Remove entry by moving the rest of the PDU content forward */
2077 ad_len += 1U;
2078 (void)memmove(ad, ad + ad_len, pdu->len - ((ad + ad_len) - pdu->payload));
2079
2080 /* Adjust lengths */
2081 pdu->len -= ad_len;
2082 pdu->adv_ext_ind.ext_hdr_len -= ad_len;
2083
2084 return 0U;
2085 }
2086
2087 uint8_t ull_adv_sync_add_to_acad(struct lll_adv_sync *lll_sync,
2088 struct pdu_adv *pdu_prev,
2089 struct pdu_adv *pdu,
2090 const uint8_t *new_ad,
2091 uint8_t new_ad_len)
2092 {
2093 uint8_t ad_len;
2094 uint8_t delta;
2095 uint8_t *dptr;
2096 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2097 uint8_t err;
2098
2099 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2100 if (err) {
2101 return err;
2102 }
2103 #else
2104 ull_adv_sync_copy_pdu(pdu_prev, pdu);
2105 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2106
2107 delta = new_ad_len;
2108 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
2109 /* Add one byte for the header flags */
2110 delta++;
2111 }
2112
2113 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - delta) {
2114 return BT_HCI_ERR_PACKET_TOO_LONG;
2115 }
2116
2117 dptr = pdu->payload + pdu->adv_ext_ind.ext_hdr_len + 1U;
2118
2119 /* Make room in ACAD by moving any advertising data back */
2120 ad_len = pdu->len - pdu->adv_ext_ind.ext_hdr_len - 1U;
2121 if (ad_len) {
2122 (void)memmove(dptr + delta, dptr, ad_len);
2123 }
2124
2125 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
2126 /* Set all extended header flags to 0 */
2127 *dptr = 0U;
2128 dptr++;
2129 }
2130
2131 /* Copy in ACAD data */
2132 memcpy(dptr, new_ad, new_ad_len);
2133
2134 /* Adjust lengths */
2135 pdu->len += delta;
2136 pdu->adv_ext_ind.ext_hdr_len += delta;
2137
2138 return 0U;
2139 }
2140
2141 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
2142 static void ull_adv_sync_update_pdu_cteinfo(struct lll_adv_sync *lll_sync, struct pdu_adv *pdu,
2143 const struct pdu_cte_info *cte_info)
2144 {
2145 struct pdu_adv_com_ext_adv *hdr = &pdu->adv_ext_ind;
2146 uint8_t *dptr;
2147
2148 if (hdr->ext_hdr_len == 0U || hdr->ext_hdr.cte_info == 0U) {
2149 /* No CTEInfo field present, nothing to do */
2150 return;
2151 }
2152
2153 /* Find CTEInfo in extended header */
2154 dptr = hdr->ext_hdr.data;
2155
2156 /* AdvA and TargetA is RFU for periodic advertising */
2157
2158 /* Copy supplied data into extended header */
2159 memcpy(dptr, (uint8_t *)cte_info, sizeof(struct pdu_cte_info));
2160 }
2161
2162 uint8_t ull_adv_sync_add_cteinfo(struct lll_adv_sync *lll_sync,
2163 struct pdu_adv *pdu_prev,
2164 struct pdu_adv *pdu,
2165 const struct pdu_cte_info *cte_info,
2166 uint8_t cte_count)
2167 {
2168 struct pdu_adv_ext_hdr add_fields = { 0U };
2169 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2170 uint8_t ad_overflow[sizeof(struct pdu_cte_info)*MAX_FRAG_COUNT];
2171 uint8_t total_overflow_len;
2172 struct pdu_adv *last_pdu = pdu;
2173 uint8_t overflow_len;
2174 uint8_t err;
2175 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2176
2177 add_fields.cte_info = 1U;
2178
2179 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2180 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2181 if (err) {
2182 return err;
2183 }
2184
2185 total_overflow_len = 0U;
2186 /* Loop through chain and add CTEInfo for PDUs up to cte_count */
2187 while (pdu && cte_count) {
2188 last_pdu = pdu;
2189
2190 /* We should always have enough available overflow space to fit CTEInfo */
2191 LL_ASSERT(total_overflow_len + sizeof(struct pdu_cte_info) <= sizeof(ad_overflow));
2192
2193 ull_adv_sync_add_to_header(pdu, &add_fields,
2194 &ad_overflow[total_overflow_len], &overflow_len);
2195 total_overflow_len += overflow_len;
2196 ull_adv_sync_update_pdu_cteinfo(lll_sync, pdu, cte_info);
2197 cte_count--;
2198
2199 /* Update AuxPtr if present */
2200 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
2201
2202 pdu = lll_adv_pdu_linked_next_get(pdu);
2203 if (pdu) {
2204 uint8_t ad_overflow_tmp[sizeof(struct pdu_cte_info)*MAX_FRAG_COUNT];
2205 uint8_t overflow_tmp_len = 0U;
2206 uint8_t pdu_avail = PDU_AC_EXT_PAYLOAD_SIZE_MAX - pdu->len;
2207 uint8_t pdu_needed = total_overflow_len;
2208 uint8_t *dptr;
2209
2210 if (!pdu->adv_ext_ind.ext_hdr.cte_info) {
2211 pdu_needed += sizeof(struct pdu_cte_info);
2212 }
2213 if (pdu->adv_ext_ind.ext_hdr_len == 0U) {
2214 /* Make room for flags as well */
2215 pdu_needed++;
2216 }
2217
2218 if (total_overflow_len > 0U) {
2219 if (pdu_avail < pdu_needed) {
2220 /* Make room by removing last part of adv data */
2221 overflow_tmp_len = pdu_needed - pdu_avail;
2222 memcpy(ad_overflow_tmp,
2223 pdu->payload + (pdu->len - overflow_tmp_len),
2224 overflow_tmp_len);
2225 pdu->len -= overflow_tmp_len;
2226 }
2227
2228 /* Prepend overflow from last PDU */
2229 dptr = pdu->payload + pdu->adv_ext_ind.ext_hdr_len + 1U;
2230 memmove(dptr + total_overflow_len, dptr,
2231 pdu->len - pdu->adv_ext_ind.ext_hdr_len - 1U +
2232 total_overflow_len);
2233 pdu->len += total_overflow_len;
2234 memcpy(dptr, ad_overflow, total_overflow_len);
2235
2236 /* Carry forward overflow from this PDU */
2237 total_overflow_len = overflow_tmp_len;
2238 if (overflow_tmp_len) {
2239 memcpy(ad_overflow, ad_overflow_tmp, overflow_tmp_len);
2240 }
2241 }
2242
2243 }
2244 }
2245
2246 pdu = last_pdu;
2247
2248 /* Push any remaining overflow on to last PDU */
2249 ull_adv_sync_append_ad_data(lll_sync, pdu, ad_overflow, total_overflow_len,
2250 PDU_AC_EXT_PAYLOAD_SIZE_MAX);
2251
2252 #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1)
2253 /* Add PDUs up to cte_count if needed */
2254 while (cte_count) {
2255 struct pdu_adv_ext_hdr skip_fields = { 0U };
2256 struct pdu_adv *pdu_chain;
2257
2258 skip_fields.adi = 1U;
2259 skip_fields.aux_ptr = 1U;
2260 skip_fields.tx_pwr = 1U;
2261
2262 /* Get a new chain PDU */
2263 pdu_chain = lll_adv_pdu_alloc_pdu_adv();
2264 if (!pdu_chain) {
2265 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
2266 }
2267
2268 /* Link the chain PDU to parent PDU */
2269 lll_adv_pdu_linked_append(pdu_chain, pdu);
2270
2271 /* Copy header to new PDU, skipping all fields except CTEInfo */
2272 ull_adv_sync_copy_pdu_header(pdu_chain, pdu, &skip_fields, true);
2273
2274 /* Add and set aux_ptr to existing PDU */
2275 ull_adv_sync_add_aux_ptr(pdu, ad_overflow, &overflow_len);
2276 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
2277
2278 if (overflow_len) {
2279 ull_adv_sync_append_ad_data(lll_sync, pdu_chain, ad_overflow, overflow_len,
2280 PDU_AC_EXT_PAYLOAD_SIZE_MAX);
2281 }
2282
2283 pdu = pdu_chain;
2284 cte_count--;
2285 }
2286 #endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
2287
2288 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2289
2290 if (pdu->len > PDU_AC_EXT_PAYLOAD_SIZE_MAX - sizeof(struct pdu_cte_info)) {
2291 /* No room for CTEInfo */
2292 return BT_HCI_ERR_PACKET_TOO_LONG;
2293 }
2294
2295 /* Initialize PDU header */
2296 pdu->type = pdu_prev->type;
2297 pdu->rfu = 0U;
2298 pdu->chan_sel = 0U;
2299 pdu->tx_addr = 0U;
2300 pdu->rx_addr = 0U;
2301 pdu->len = pdu_prev->len;
2302
2303 /* Copy PDU payload */
2304 memcpy(pdu->payload, pdu_prev->payload, pdu_prev->len);
2305
2306 /* Add and set CTEInfo */
2307 ull_adv_sync_add_to_header(pdu, &add_fields, NULL, NULL);
2308 ull_adv_sync_update_pdu_cteinfo(lll_sync, pdu, cte_info);
2309 #endif /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2310 return 0U;
2311 }
2312
2313 uint8_t ull_adv_sync_remove_cteinfo(struct lll_adv_sync *lll_sync,
2314 struct pdu_adv *pdu_prev,
2315 struct pdu_adv *pdu)
2316 {
2317 struct pdu_adv_ext_hdr remove_fields = { 0U };
2318 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2319 uint8_t err;
2320 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2321
2322 remove_fields.cte_info = 1U;
2323
2324 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK)
2325 err = ull_adv_sync_duplicate_chain(pdu_prev, pdu);
2326 if (err) {
2327 return err;
2328 }
2329
2330 /* Loop through chain and remove CTEInfo for all */
2331 while (pdu) {
2332 struct pdu_adv *pdu_chain;
2333
2334 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
2335
2336 if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
2337 ull_adv_sync_update_aux_ptr(lll_sync, pdu);
2338 }
2339
2340 pdu_chain = lll_adv_pdu_linked_next_get(pdu);
2341 #if (CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1)
2342 /* If the next PDU in the chain contains no adv data, any remaining PDUs
2343 * in the chain are only present for CTE purposes
2344 */
2345 if (pdu_chain && pdu_chain->len == pdu_chain->adv_ext_ind.ext_hdr_len + 1U) {
2346 /* Remove AuxPtr and clean up remaining PDUs in chain */
2347 remove_fields.aux_ptr = 1U;
2348 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
2349 lll_adv_pdu_linked_release_all(pdu_chain);
2350 lll_adv_pdu_linked_append(NULL, pdu);
2351 pdu_chain = NULL;
2352 }
2353 #endif /* CONFIG_BT_CTLR_DF_PER_ADV_CTE_NUM_MAX > 1 */
2354 pdu = pdu_chain;
2355 }
2356 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2357 ull_adv_sync_remove_from_header(pdu, &remove_fields, false);
2358 #endif /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_LINK */
2359
2360 return 0U;
2361 }
2362 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
2363
2364 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
2365 /* @brief Set or clear fields in extended advertising header and store
2366 * extra_data if requested.
2367 *
2368 * @param[in] extra_data_prev Pointer to previous content of extra_data.
2369 * @param[in] hdr_add_fields Flag with information which fields add.
2370 * @param[in] hdr_rem_fields Flag with information which fields remove.
2371 * @param[in] data Pointer to data to be stored in extra_data.
2372 * Content depends on the data depends on
2373 * @p hdr_add_fields.
2374 *
2375 * @Note
2376 * @p hdr_data content depends on the flag provided by @p hdr_add_fields:
2377 * - ULL_ADV_PDU_HDR_FIELD_CTE_INFO:
2378 * # @p hdr_data points to single byte with CTEInfo field
2379 *
2380 * @return Zero in case of success, other value in case of failure.
2381 * @p data depends on the flag provided by @p hdr_add_fields.
2382 *
2383 * @return Zero in case of success, other value in case of failure.
2384 */
2385 void ull_adv_sync_extra_data_set_clear(void *extra_data_prev,
2386 void *extra_data_new,
2387 uint16_t hdr_add_fields,
2388 uint16_t hdr_rem_fields,
2389 void *data)
2390 {
2391 /* Currently only CTE enable requires extra_data. Due to that fact
2392 * CTE additional data are just copied to extra_data memory.
2393 */
2394 if (hdr_add_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) {
2395 (void)memcpy(extra_data_new, data, sizeof(struct lll_df_adv_cfg));
2396 } else if (!(hdr_rem_fields & ULL_ADV_PDU_HDR_FIELD_CTE_INFO) ||
2397 extra_data_prev) {
2398 (void)memmove(extra_data_new, extra_data_prev,
2399 sizeof(struct lll_df_adv_cfg));
2400 }
2401 }
2402 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
2403
2404 static int init_reset(void)
2405 {
2406 /* Initialize adv sync pool. */
2407 mem_init(ll_adv_sync_pool, sizeof(struct ll_adv_sync_set),
2408 sizeof(ll_adv_sync_pool) / sizeof(struct ll_adv_sync_set),
2409 &adv_sync_free);
2410
2411 return 0;
2412 }
2413
2414 static uint8_t adv_type_check(struct ll_adv_set *adv)
2415 {
2416 struct pdu_adv_com_ext_adv *pri_com_hdr;
2417 struct pdu_adv_ext_hdr *pri_hdr;
2418 struct pdu_adv *pri_pdu;
2419
2420 pri_pdu = lll_adv_data_latest_peek(&adv->lll);
2421 if (pri_pdu->type != PDU_ADV_TYPE_EXT_IND) {
2422 return BT_HCI_ERR_INVALID_PARAM;
2423 }
2424
2425 pri_com_hdr = (void *)&pri_pdu->adv_ext_ind;
2426 if (pri_com_hdr->adv_mode != 0U) {
2427 return BT_HCI_ERR_INVALID_PARAM;
2428 }
2429
2430 pri_hdr = (void *)pri_com_hdr->ext_hdr_adv_data;
2431 if (pri_hdr->aux_ptr) {
2432 struct pdu_adv_com_ext_adv *sec_com_hdr;
2433 struct pdu_adv_ext_hdr *sec_hdr;
2434 struct pdu_adv *sec_pdu;
2435
2436 sec_pdu = lll_adv_aux_data_latest_peek(adv->lll.aux);
2437 sec_com_hdr = (void *)&sec_pdu->adv_ext_ind;
2438 sec_hdr = (void *)sec_com_hdr->ext_hdr_adv_data;
2439 if (!pri_hdr->adv_addr && !sec_hdr->adv_addr) {
2440 return BT_HCI_ERR_INVALID_PARAM;
2441 }
2442 } else if (!pri_hdr->adv_addr) {
2443 return BT_HCI_ERR_INVALID_PARAM;
2444 }
2445
2446 return 0;
2447 }
2448
2449 static inline struct ll_adv_sync_set *sync_acquire(void)
2450 {
2451 return mem_acquire(&adv_sync_free);
2452 }
2453
2454 static inline void sync_release(struct ll_adv_sync_set *sync)
2455 {
2456 mem_release(sync, &adv_sync_free);
2457 }
2458
2459 static inline uint16_t sync_handle_get(const struct ll_adv_sync_set *sync)
2460 {
2461 return mem_index_get(sync, ll_adv_sync_pool,
2462 sizeof(struct ll_adv_sync_set));
2463 }
2464
2465 static uint32_t sync_time_get(const struct ll_adv_sync_set *sync,
2466 const struct pdu_adv *pdu)
2467 {
2468 uint8_t len;
2469
2470 /* Calculate the PDU Tx Time and hence the radio event length,
2471 * Always use maximum length for common extended header format so that
2472 * ACAD could be update when periodic advertising is active and the
2473 * time reservation need not be updated every time avoiding overlapping
2474 * with other active states/roles.
2475 */
2476 len = pdu->len - pdu->adv_ext_ind.ext_hdr_len -
2477 PDU_AC_EXT_HEADER_SIZE_MIN + PDU_AC_EXT_HEADER_SIZE_MAX;
2478
2479 return ull_adv_sync_time_get(sync, len);
2480 }
2481
2482 static uint8_t sync_stop(struct ll_adv_sync_set *sync)
2483 {
2484 uint8_t sync_handle;
2485 int err;
2486
2487 sync_handle = sync_handle_get(sync);
2488
2489 err = ull_ticker_stop_with_mark(TICKER_ID_ADV_SYNC_BASE + sync_handle,
2490 sync, &sync->lll);
2491 LL_ASSERT_INFO2(err == 0 || err == -EALREADY, sync_handle, err);
2492 if (err) {
2493 return BT_HCI_ERR_CMD_DISALLOWED;
2494 }
2495
2496 return 0;
2497 }
2498
2499 static inline uint8_t sync_remove(struct ll_adv_sync_set *sync,
2500 struct ll_adv_set *adv, uint8_t enable)
2501 {
2502 uint8_t pri_idx;
2503 uint8_t sec_idx;
2504 uint8_t err;
2505
2506 /* Remove sync_info from auxiliary PDU */
2507 err = ull_adv_aux_hdr_set_clear(adv, 0U,
2508 ULL_ADV_PDU_HDR_FIELD_SYNC_INFO, NULL,
2509 &pri_idx, &sec_idx);
2510 if (err) {
2511 return err;
2512 }
2513
2514 lll_adv_aux_data_enqueue(adv->lll.aux, sec_idx);
2515 lll_adv_data_enqueue(&adv->lll, pri_idx);
2516
2517 if (sync->is_started) {
2518 /* TODO: we removed sync info, but if sync_stop() fails, what do
2519 * we do?
2520 */
2521 err = sync_stop(sync);
2522 if (err) {
2523 return err;
2524 }
2525
2526 sync->is_started = 0U;
2527
2528 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2529 if (adv->lll.aux) {
2530 /* notify the auxiliary set */
2531 ull_adv_sync_started_stopped(HDR_LLL2ULL(adv->lll.aux));
2532 }
2533 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2534 }
2535
2536 if (!enable) {
2537 sync->is_enabled = 0U;
2538 }
2539
2540 return 0U;
2541 }
2542
2543 static uint8_t sync_chm_update(uint8_t handle)
2544 {
2545 struct pdu_adv_sync_chm_upd_ind *chm_upd_ind;
2546 uint8_t ad[sizeof(*chm_upd_ind) + 2U];
2547 struct lll_adv_sync *lll_sync;
2548 struct pdu_adv *pdu_prev;
2549 struct ll_adv_set *adv;
2550 struct pdu_adv *pdu;
2551 uint16_t instant;
2552 uint8_t chm_last;
2553 uint8_t ter_idx;
2554 uint8_t err;
2555
2556 /* Check for valid advertising instance */
2557 adv = ull_adv_is_created_get(handle);
2558 if (!adv) {
2559 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
2560 }
2561
2562 /* Check for valid periodic advertising */
2563 lll_sync = adv->lll.sync;
2564 if (!lll_sync) {
2565 return BT_HCI_ERR_UNKNOWN_ADV_IDENTIFIER;
2566 }
2567
2568 /* Fail if already in progress */
2569 if (lll_sync->chm_last != lll_sync->chm_first) {
2570 return BT_HCI_ERR_CMD_DISALLOWED;
2571 }
2572
2573 /* Allocate next Sync PDU */
2574 err = ull_adv_sync_pdu_alloc(adv, ULL_ADV_PDU_EXTRA_DATA_ALLOC_IF_EXIST,
2575 &pdu_prev, &pdu, NULL, NULL, &ter_idx);
2576 if (err) {
2577 return err;
2578 }
2579
2580 /* Populate the AD data length and opcode */
2581 ad[PDU_ADV_DATA_HEADER_LEN_OFFSET] = sizeof(*chm_upd_ind) + 1U;
2582 ad[PDU_ADV_DATA_HEADER_TYPE_OFFSET] = PDU_ADV_DATA_TYPE_CHANNEL_MAP_UPDATE_IND;
2583
2584 /* Populate the Channel Map Indication structure */
2585 chm_upd_ind = (void *)&ad[PDU_ADV_DATA_HEADER_DATA_OFFSET];
2586 (void)ull_chan_map_get(chm_upd_ind->chm);
2587 instant = lll_sync->event_counter + 6U;
2588 chm_upd_ind->instant = sys_cpu_to_le16(instant);
2589
2590 /* Try to add channel map update indication to ACAD */
2591 err = ull_adv_sync_add_to_acad(lll_sync, pdu_prev, pdu, ad, sizeof(*chm_upd_ind) + 2U);
2592 if (err) {
2593 return err;
2594 }
2595
2596 /* Update the LLL to reflect the Channel Map and Instant to use */
2597 chm_last = lll_sync->chm_last + 1U;
2598 if (chm_last == DOUBLE_BUFFER_SIZE) {
2599 chm_last = 0U;
2600 }
2601 lll_sync->chm[chm_last].data_chan_count =
2602 ull_chan_map_get(lll_sync->chm[chm_last].data_chan_map);
2603 lll_sync->chm_instant = instant;
2604
2605 /* Commit the Channel Map Indication in the ACAD field of Periodic
2606 * Advertising
2607 */
2608 lll_adv_sync_data_enqueue(lll_sync, ter_idx);
2609
2610 /* Initiate the Channel Map Indication */
2611 lll_sync->chm_last = chm_last;
2612
2613 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2614 struct ll_adv_sync_set *sync = HDR_LLL2ULL(lll_sync);
2615
2616 if (!sync->is_started) {
2617 /* Sync not started yet, apply new channel map now */
2618 lll_sync->chm_first = lll_sync->chm_last;
2619 }
2620 #endif /* CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2621
2622 return 0;
2623 }
2624
2625 #if defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2626 void ull_adv_sync_lll_syncinfo_fill(struct pdu_adv *pdu, struct lll_adv_aux *lll_aux)
2627 {
2628 struct lll_adv_sync *lll_sync;
2629 struct pdu_adv_sync_info *si;
2630 uint8_t chm_first;
2631
2632 lll_sync = lll_aux->adv->sync;
2633
2634 si = sync_info_get(pdu);
2635 sync_info_offset_fill(si, lll_sync->us_adv_sync_pdu_offset);
2636 si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare +
2637 lll_sync->sync_lazy;
2638
2639 /* Fill the correct channel map to use if at or past the instant */
2640 if (lll_sync->chm_first != lll_sync->chm_last) {
2641 uint16_t instant_latency;
2642
2643 instant_latency = (si->evt_cntr - lll_sync->chm_instant) &
2644 EVENT_INSTANT_MAX;
2645 if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) {
2646 chm_first = lll_sync->chm_last;
2647 } else {
2648 chm_first = lll_sync->chm_first;
2649 }
2650 } else {
2651 chm_first = lll_sync->chm_first;
2652 }
2653 (void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map,
2654 sizeof(si->sca_chm));
2655 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
2656 ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
2657 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |=
2658 ((lll_clock_sca_local_get() <<
2659 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) &
2660 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK);
2661 }
2662
2663 static void sync_info_offset_fill(struct pdu_adv_sync_info *si, uint32_t offs)
2664 {
2665 uint8_t offs_adjust = 0U;
2666
2667 if (offs >= OFFS_ADJUST_US) {
2668 offs -= OFFS_ADJUST_US;
2669 offs_adjust = 1U;
2670 }
2671
2672 offs = offs / OFFS_UNIT_30_US;
2673 if (!!(offs >> OFFS_UNIT_BITS)) {
2674 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US),
2675 OFFS_UNIT_VALUE_300_US, offs_adjust);
2676 } else {
2677 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs, OFFS_UNIT_VALUE_30_US, offs_adjust);
2678 }
2679 }
2680
2681 #else /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2682 static void mfy_sync_offset_get(void *param)
2683 {
2684 struct ll_adv_set *adv = param;
2685 struct lll_adv_sync *lll_sync;
2686 struct ll_adv_sync_set *sync;
2687 struct pdu_adv_sync_info *si;
2688 uint32_t sync_remainder_us;
2689 uint32_t aux_remainder_us;
2690 uint32_t ticks_to_expire;
2691 uint32_t ticks_current;
2692 struct pdu_adv *pdu;
2693 uint32_t remainder;
2694 uint8_t chm_first;
2695 uint8_t ticker_id;
2696 uint16_t lazy;
2697 uint8_t retry;
2698 uint8_t id;
2699
2700 lll_sync = adv->lll.sync;
2701 sync = HDR_LLL2ULL(lll_sync);
2702 ticker_id = TICKER_ID_ADV_SYNC_BASE + sync_handle_get(sync);
2703
2704 id = TICKER_NULL;
2705 ticks_to_expire = 0U;
2706 ticks_current = 0U;
2707 retry = 4U;
2708 do {
2709 uint32_t volatile ret_cb;
2710 uint32_t ticks_previous;
2711 uint32_t ret;
2712 bool success;
2713
2714 ticks_previous = ticks_current;
2715
2716 ret_cb = TICKER_STATUS_BUSY;
2717 ret = ticker_next_slot_get_ext(TICKER_INSTANCE_ID_CTLR,
2718 TICKER_USER_ID_ULL_LOW,
2719 &id, &ticks_current,
2720 &ticks_to_expire, &remainder,
2721 &lazy, NULL, NULL,
2722 ticker_op_cb, (void *)&ret_cb);
2723 if (ret == TICKER_STATUS_BUSY) {
2724 while (ret_cb == TICKER_STATUS_BUSY) {
2725 ticker_job_sched(TICKER_INSTANCE_ID_CTLR,
2726 TICKER_USER_ID_ULL_LOW);
2727 }
2728 }
2729
2730 success = (ret_cb == TICKER_STATUS_SUCCESS);
2731 LL_ASSERT(success);
2732
2733 LL_ASSERT((ticks_current == ticks_previous) || retry--);
2734
2735 LL_ASSERT(id != TICKER_NULL);
2736 } while (id != ticker_id);
2737
2738 /* Reduced a tick for negative remainder and return positive remainder
2739 * value.
2740 */
2741 hal_ticker_remove_jitter(&ticks_to_expire, &remainder);
2742 sync_remainder_us = remainder;
2743
2744 /* Add a tick for negative remainder and return positive remainder
2745 * value.
2746 */
2747 remainder = sync->aux_remainder;
2748 hal_ticker_add_jitter(&ticks_to_expire, &remainder);
2749 aux_remainder_us = remainder;
2750
2751 pdu = lll_adv_aux_data_latest_peek(adv->lll.aux);
2752 si = sync_info_get(pdu);
2753 sync_info_offset_fill(si, ticks_to_expire, sync_remainder_us,
2754 aux_remainder_us);
2755 si->evt_cntr = lll_sync->event_counter + lll_sync->latency_prepare +
2756 lazy;
2757
2758 /* Fill the correct channel map to use if at or past the instant */
2759 if (lll_sync->chm_first != lll_sync->chm_last) {
2760 uint16_t instant_latency;
2761
2762 instant_latency = (si->evt_cntr - lll_sync->chm_instant) &
2763 EVENT_INSTANT_MAX;
2764 if (instant_latency <= EVENT_INSTANT_LATENCY_MAX) {
2765 chm_first = lll_sync->chm_last;
2766 } else {
2767 chm_first = lll_sync->chm_first;
2768 }
2769 } else {
2770 chm_first = lll_sync->chm_first;
2771 }
2772 (void)memcpy(si->sca_chm, lll_sync->chm[chm_first].data_chan_map,
2773 sizeof(si->sca_chm));
2774 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] &=
2775 ~PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK;
2776 si->sca_chm[PDU_SYNC_INFO_SCA_CHM_SCA_BYTE_OFFSET] |=
2777 ((lll_clock_sca_local_get() <<
2778 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_POS) &
2779 PDU_SYNC_INFO_SCA_CHM_SCA_BIT_MASK);
2780 }
2781
2782 static void sync_info_offset_fill(struct pdu_adv_sync_info *si,
2783 uint32_t ticks_offset,
2784 uint32_t remainder_us,
2785 uint32_t start_us)
2786 {
2787 uint8_t offs_adjust = 0U;
2788 uint32_t offs;
2789
2790 offs = HAL_TICKER_TICKS_TO_US(ticks_offset) + remainder_us - start_us;
2791
2792 if (offs >= OFFS_ADJUST_US) {
2793 offs -= OFFS_ADJUST_US;
2794 offs_adjust = 1U;
2795 }
2796
2797 offs = offs / OFFS_UNIT_30_US;
2798 if (!!(offs >> OFFS_UNIT_BITS)) {
2799 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs / (OFFS_UNIT_300_US / OFFS_UNIT_30_US),
2800 OFFS_UNIT_VALUE_300_US, offs_adjust);
2801 } else {
2802 PDU_ADV_SYNC_INFO_OFFS_SET(si, offs, OFFS_UNIT_VALUE_30_US, offs_adjust);
2803 }
2804 }
2805
2806 static void ticker_op_cb(uint32_t status, void *param)
2807 {
2808 *((uint32_t volatile *)param) = status;
2809 }
2810 #endif /* !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2811
2812 static struct pdu_adv_sync_info *sync_info_get(struct pdu_adv *pdu)
2813 {
2814 struct pdu_adv_com_ext_adv *p;
2815 struct pdu_adv_ext_hdr *h;
2816 uint8_t *ptr;
2817
2818 p = (void *)&pdu->adv_ext_ind;
2819 h = (void *)p->ext_hdr_adv_data;
2820 ptr = h->data;
2821
2822 /* traverse through adv_addr, if present */
2823 if (h->adv_addr) {
2824 ptr += BDADDR_SIZE;
2825 }
2826
2827 /* traverse through tgt_addr, if present */
2828 if (h->tgt_addr) {
2829 ptr += BDADDR_SIZE;
2830 }
2831
2832 /* No CTEInfo flag in primary and secondary channel PDU */
2833
2834 /* traverse through adi, if present */
2835 if (h->adi) {
2836 ptr += sizeof(struct pdu_adv_adi);
2837 }
2838
2839 /* traverse through aux ptr, if present */
2840 if (h->aux_ptr) {
2841 ptr += sizeof(struct pdu_adv_aux_ptr);
2842 }
2843
2844 /* return pointer offset to sync_info */
2845 return (void *)ptr;
2846 }
2847
2848 static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
2849 uint32_t remainder, uint16_t lazy, uint8_t force,
2850 void *param)
2851 {
2852 static memq_link_t link;
2853 static struct mayfly mfy = {0, 0, &link, NULL, lll_adv_sync_prepare};
2854 static struct lll_prepare_param p;
2855 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2856 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2857 struct ticker_ext_context *context = param;
2858 struct ll_adv_sync_set *sync = context->context;
2859 #else /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2860 struct ll_adv_sync_set *sync = param;
2861 #endif /* !CONFIG_BT_CTLR_ADV_ISO || !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2862 struct lll_adv_sync *lll;
2863 uint32_t ret;
2864 uint8_t ref;
2865
2866 DEBUG_RADIO_PREPARE_A(1);
2867
2868 lll = &sync->lll;
2869
2870 /* Increment prepare reference count */
2871 ref = ull_ref_inc(&sync->ull);
2872 LL_ASSERT(ref);
2873
2874 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2875 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2876 if (lll->iso) {
2877 struct lll_adv_iso *lll_iso = lll->iso;
2878
2879 LL_ASSERT(context->other_expire_info);
2880
2881 /* Check: No need for remainder in this case? */
2882 lll_iso->ticks_sync_pdu_offset = context->other_expire_info->ticks_to_expire;
2883 lll_iso->iso_lazy = context->other_expire_info->lazy;
2884 }
2885 #endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2886
2887 /* Append timing parameters */
2888 p.ticks_at_expire = ticks_at_expire;
2889 p.remainder = remainder;
2890 p.lazy = lazy;
2891 p.force = force;
2892 p.param = lll;
2893 mfy.param = &p;
2894
2895 /* Kick LLL prepare */
2896 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
2897 TICKER_USER_ID_LLL, 0, &mfy);
2898 LL_ASSERT(!ret);
2899
2900 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2901 !defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2902 if (lll->iso) {
2903 ull_adv_iso_offset_get(sync);
2904 }
2905 #endif /* CONFIG_BT_CTLR_ADV_ISO && !CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2906
2907 DEBUG_RADIO_PREPARE_A(1);
2908 }
2909
2910 #if defined(CONFIG_BT_CTLR_ADV_ISO) && \
2911 defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
2912 static void ticker_update_op_cb(uint32_t status, void *param)
2913 {
2914 LL_ASSERT(status == TICKER_STATUS_SUCCESS ||
2915 param == ull_disable_mark_get());
2916 }
2917 #endif /* !CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
2918