1 /*
2 * Copyright (c) 2016-2019 Nordic Semiconductor ASA
3 * Copyright (c) 2016 Vinayak Kariappa Chettimada
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #include <zephyr.h>
9 #include <soc.h>
10 #include <bluetooth/hci.h>
11
12 #include "hal/cpu.h"
13 #include "hal/ccm.h"
14 #include "hal/radio.h"
15 #include "hal/ticker.h"
16
17 #include "util/util.h"
18 #include "util/mem.h"
19 #include "util/memq.h"
20 #include "util/mayfly.h"
21
22 #include "ticker/ticker.h"
23
24 #include "pdu.h"
25
26 #include "lll.h"
27 #include "lll/lll_vendor.h"
28 #include "lll/lll_adv_types.h"
29 #include "lll_adv.h"
30 #include "lll/lll_adv_pdu.h"
31 #include "lll_scan.h"
32 #include "lll/lll_df_types.h"
33 #include "lll_conn.h"
34 #include "lll_filter.h"
35
36 #include "ull_adv_types.h"
37 #include "ull_scan_types.h"
38 #include "ull_filter.h"
39
40 #include "ull_internal.h"
41 #include "ull_adv_internal.h"
42 #include "ull_scan_internal.h"
43 #include "ull_sched_internal.h"
44
45 #include "ll.h"
46
47 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
48 #define LOG_MODULE_NAME bt_ctlr_ull_scan
49 #include "common/log.h"
50 #include "hal/debug.h"
51
52 static int init_reset(void);
53 static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
54 uint32_t remainder, uint16_t lazy, uint8_t force,
55 void *param);
56 static uint8_t disable(uint8_t handle);
57
58 #if defined(CONFIG_BT_CTLR_ADV_EXT)
59 static uint8_t is_scan_update(uint8_t handle, uint16_t duration,
60 uint16_t period, struct ll_scan_set **scan,
61 struct node_rx_pdu **node_rx_scan_term);
62 static uint8_t duration_period_setup(struct ll_scan_set *scan,
63 uint16_t duration, uint16_t period,
64 struct node_rx_pdu **node_rx_scan_term);
65 static uint8_t duration_period_update(struct ll_scan_set *scan,
66 uint8_t is_update);
67 static void ticker_stop_ext_op_cb(uint32_t status, void *param);
68 static void ext_disable(void *param);
69 static void ext_disabled_cb(void *param);
70 #endif /* CONFIG_BT_CTLR_ADV_EXT */
71
72 static struct ll_scan_set ll_scan[BT_CTLR_SCAN_SET];
73
ll_scan_params_set(uint8_t type,uint16_t interval,uint16_t window,uint8_t own_addr_type,uint8_t filter_policy)74 uint8_t ll_scan_params_set(uint8_t type, uint16_t interval, uint16_t window,
75 uint8_t own_addr_type, uint8_t filter_policy)
76 {
77 struct ll_scan_set *scan;
78 struct lll_scan *lll;
79
80 scan = ull_scan_is_disabled_get(SCAN_HANDLE_1M);
81 if (!scan) {
82 return BT_HCI_ERR_CMD_DISALLOWED;
83 }
84
85 #if defined(CONFIG_BT_CTLR_ADV_EXT)
86 uint8_t phy;
87
88 phy = type >> 1;
89 if (phy & BT_HCI_LE_EXT_SCAN_PHY_CODED) {
90 struct ll_scan_set *scan_coded;
91
92 if (!IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) {
93 return BT_HCI_ERR_CMD_DISALLOWED;
94 }
95
96 scan_coded = ull_scan_is_disabled_get(SCAN_HANDLE_PHY_CODED);
97 if (!scan_coded) {
98 return BT_HCI_ERR_CMD_DISALLOWED;
99 }
100
101 scan = scan_coded;
102 }
103
104 lll = &scan->lll;
105
106 /* NOTE: Pass invalid interval value to not start scanning using this
107 * scan instance.
108 */
109 if (!interval) {
110 /* Set PHY to 0 to not start scanning on this instance */
111 lll->phy = 0U;
112
113 return 0;
114 }
115
116 lll->phy = phy;
117
118 #else /* !CONFIG_BT_CTLR_ADV_EXT */
119 lll = &scan->lll;
120 #endif /* !CONFIG_BT_CTLR_ADV_EXT */
121
122 scan->own_addr_type = own_addr_type;
123
124 ull_scan_params_set(lll, type, interval, window, filter_policy);
125
126 return 0;
127 }
128
129 #if defined(CONFIG_BT_CTLR_ADV_EXT)
ll_scan_enable(uint8_t enable,uint16_t duration,uint16_t period)130 uint8_t ll_scan_enable(uint8_t enable, uint16_t duration, uint16_t period)
131 {
132 struct node_rx_pdu *node_rx_scan_term = NULL;
133 uint8_t is_update_coded = 0U;
134 uint8_t is_update_1m = 0U;
135 #else /* !CONFIG_BT_CTLR_ADV_EXT */
136 uint8_t ll_scan_enable(uint8_t enable)
137 {
138 #endif /* !CONFIG_BT_CTLR_ADV_EXT */
139 struct ll_scan_set *scan_coded = NULL;
140 uint8_t own_addr_type = 0U;
141 uint8_t is_coded_phy = 0U;
142 struct ll_scan_set *scan;
143 uint8_t err;
144
145 if (!enable) {
146 err = disable(SCAN_HANDLE_1M);
147
148 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) &&
149 IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED)) {
150 uint8_t err_coded;
151
152 err_coded = disable(SCAN_HANDLE_PHY_CODED);
153 if (!err_coded) {
154 err = 0U;
155 }
156 }
157
158 return err;
159 }
160
161 scan = ull_scan_is_disabled_get(SCAN_HANDLE_1M);
162 if (!scan) {
163 #if defined(CONFIG_BT_CTLR_ADV_EXT)
164 is_update_1m = is_scan_update(SCAN_HANDLE_1M, duration, period,
165 &scan, &node_rx_scan_term);
166 if (!is_update_1m)
167 #endif /* CONFIG_BT_CTLR_ADV_EXT */
168 {
169 return BT_HCI_ERR_CMD_DISALLOWED;
170 }
171 }
172
173 #if defined(CONFIG_BT_CTLR_ADV_EXT) && defined(CONFIG_BT_CTLR_PHY_CODED)
174 scan_coded = ull_scan_is_disabled_get(SCAN_HANDLE_PHY_CODED);
175 if (!scan_coded) {
176 is_update_coded = is_scan_update(SCAN_HANDLE_PHY_CODED,
177 duration, period, &scan_coded,
178 &node_rx_scan_term);
179 if (!is_update_coded) {
180 return BT_HCI_ERR_CMD_DISALLOWED;
181 }
182 }
183
184 own_addr_type = scan_coded->own_addr_type;
185 is_coded_phy = (scan_coded->lll.phy &
186 BT_HCI_LE_EXT_SCAN_PHY_CODED);
187 #endif /* CONFIG_BT_CTLR_ADV_EXT && CONFIG_BT_CTLR_PHY_CODED */
188
189 if ((is_coded_phy && (own_addr_type & 0x1)) ||
190 (!is_coded_phy && (scan->own_addr_type & 0x1))) {
191 if (!mem_nz(ll_addr_get(BT_ADDR_LE_RANDOM), BDADDR_SIZE)) {
192 return BT_HCI_ERR_INVALID_PARAM;
193 }
194 }
195
196 #if defined(CONFIG_BT_CTLR_ADV_EXT)
197 #if defined(CONFIG_BT_CTLR_PHY_CODED)
198 if (!is_coded_phy || (scan->lll.phy & PHY_1M))
199 #endif /* CONFIG_BT_CTLR_PHY_CODED */
200 {
201 err = duration_period_setup(scan, duration, period,
202 &node_rx_scan_term);
203 if (err) {
204 return err;
205 }
206 }
207
208 if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) &&
209 is_coded_phy) {
210 err = duration_period_setup(scan_coded, duration, period,
211 &node_rx_scan_term);
212 if (err) {
213 return err;
214 }
215 }
216 #endif /* CONFIG_BT_CTLR_ADV_EXT */
217
218 #if defined(CONFIG_BT_CTLR_PRIVACY)
219 struct lll_scan *lll;
220
221 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) && is_coded_phy) {
222 lll = &scan_coded->lll;
223
224 /* TODO: Privacy support in Advertising Extensions */
225 } else {
226 lll = &scan->lll;
227 own_addr_type = scan->own_addr_type;
228 }
229
230 ull_filter_scan_update(lll->filter_policy);
231
232 lll->rl_idx = FILTER_IDX_NONE;
233 lll->rpa_gen = 0;
234
235 if ((lll->type & 0x1) &&
236 (own_addr_type == BT_ADDR_LE_PUBLIC_ID ||
237 own_addr_type == BT_ADDR_LE_RANDOM_ID)) {
238 /* Generate RPAs if required */
239 ull_filter_rpa_update(false);
240 lll->rpa_gen = 1;
241 }
242 #endif /* CONFIG_BT_CTLR_PRIVACY */
243
244 #if defined(CONFIG_BT_CTLR_ADV_EXT)
245 #if defined(CONFIG_BT_CTLR_PHY_CODED)
246 if (!is_coded_phy || (scan->lll.phy & PHY_1M))
247 #endif /* CONFIG_BT_CTLR_PHY_CODED */
248 {
249 err = duration_period_update(scan, is_update_1m);
250 if (err) {
251 return err;
252 } else if (is_update_1m) {
253 return 0;
254 }
255 }
256
257 if (IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) &&
258 is_coded_phy) {
259 err = duration_period_update(scan_coded, is_update_coded);
260 if (err) {
261 return err;
262 } else if (is_update_coded) {
263 return 0;
264 }
265 }
266
267 #if defined(CONFIG_BT_CTLR_PHY_CODED)
268 if (!is_coded_phy || (scan->lll.phy & PHY_1M))
269 #endif /* CONFIG_BT_CTLR_PHY_CODED */
270 #endif /* CONFIG_BT_CTLR_ADV_EXT */
271 {
272 err = ull_scan_enable(scan);
273 if (err) {
274 return err;
275 }
276 }
277
278 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT) &&
279 IS_ENABLED(CONFIG_BT_CTLR_PHY_CODED) &&
280 is_coded_phy) {
281 err = ull_scan_enable(scan_coded);
282 if (err) {
283 return err;
284 }
285 }
286
287 return 0;
288 }
289
290 int ull_scan_init(void)
291 {
292 int err;
293
294 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT)) {
295 err = ull_scan_aux_init();
296 if (err) {
297 return err;
298 }
299 }
300
301 err = init_reset();
302 if (err) {
303 return err;
304 }
305
306 return 0;
307 }
308
309 int ull_scan_reset(void)
310 {
311 uint8_t handle;
312 int err;
313
314 for (handle = 0U; handle < BT_CTLR_SCAN_SET; handle++) {
315 (void)disable(handle);
316 }
317
318 if (IS_ENABLED(CONFIG_BT_CTLR_ADV_EXT)) {
319 err = ull_scan_aux_reset();
320 if (err) {
321 return err;
322 }
323 }
324
325 err = init_reset();
326 if (err) {
327 return err;
328 }
329
330 return 0;
331 }
332
333 void ull_scan_params_set(struct lll_scan *lll, uint8_t type, uint16_t interval,
334 uint16_t window, uint8_t filter_policy)
335 {
336 /* type value:
337 * 0000b - legacy 1M passive
338 * 0001b - legacy 1M active
339 * 0010b - Ext. 1M passive
340 * 0011b - Ext. 1M active
341 * 0100b - invalid
342 * 0101b - invalid
343 * 0110b - invalid
344 * 0111b - invalid
345 * 1000b - Ext. Coded passive
346 * 1001b - Ext. Coded active
347 */
348 lll->type = type;
349 lll->filter_policy = filter_policy;
350 lll->interval = interval;
351 lll->ticks_window = HAL_TICKER_US_TO_TICKS((uint64_t)window *
352 SCAN_INT_UNIT_US);
353 }
354
355 uint8_t ull_scan_enable(struct ll_scan_set *scan)
356 {
357 struct lll_scan *lll = &scan->lll;
358 uint32_t ticks_slot_overhead;
359 uint32_t volatile ret_cb;
360 uint32_t ticks_interval;
361 uint32_t ticks_anchor;
362 uint32_t ret;
363
364 lll->init_addr_type = scan->own_addr_type;
365 (void)ll_addr_read(lll->init_addr_type, lll->init_addr);
366 lll->chan = 0U;
367 lll->is_stop = 0U;
368
369 ull_hdr_init(&scan->ull);
370 lll_hdr_init(lll, scan);
371
372 ticks_interval = HAL_TICKER_US_TO_TICKS((uint64_t)lll->interval *
373 SCAN_INT_UNIT_US);
374
375 /* TODO: active_to_start feature port */
376 scan->ull.ticks_active_to_start = 0U;
377 scan->ull.ticks_prepare_to_start =
378 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
379 scan->ull.ticks_preempt_to_start =
380 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_PREEMPT_MIN_US);
381 if ((lll->ticks_window +
382 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US)) <
383 (ticks_interval -
384 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US))) {
385 scan->ull.ticks_slot =
386 (lll->ticks_window +
387 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US));
388 } else {
389 if (IS_ENABLED(CONFIG_BT_CTLR_SCAN_UNRESERVED)) {
390 scan->ull.ticks_slot = 0U;
391 } else {
392 scan->ull.ticks_slot = ticks_interval -
393 HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_XTAL_US);
394 }
395
396 lll->ticks_window = 0U;
397 }
398
399 if (IS_ENABLED(CONFIG_BT_CTLR_LOW_LAT)) {
400 ticks_slot_overhead = MAX(scan->ull.ticks_active_to_start,
401 scan->ull.ticks_prepare_to_start);
402 } else {
403 ticks_slot_overhead = 0U;
404 }
405
406 ticks_anchor = ticker_ticks_now_get();
407
408 #if defined(CONFIG_BT_CENTRAL) && defined(CONFIG_BT_CTLR_SCHED_ADVANCED)
409 if (!lll->conn) {
410 uint32_t ticks_ref = 0U;
411 uint32_t offset_us = 0U;
412
413 ull_sched_after_mstr_slot_get(TICKER_USER_ID_THREAD,
414 (scan->ull.ticks_slot +
415 ticks_slot_overhead),
416 &ticks_ref, &offset_us);
417
418 /* Use the ticks_ref as scanner's anchor if a free time space
419 * after any central role is available (indicated by a non-zero
420 * offset_us value).
421 */
422 if (offset_us) {
423 ticks_anchor = ticks_ref +
424 HAL_TICKER_US_TO_TICKS(offset_us);
425 }
426 }
427 #endif /* CONFIG_BT_CENTRAL && CONFIG_BT_CTLR_SCHED_ADVANCED */
428
429 uint8_t handle = ull_scan_handle_get(scan);
430
431 ret_cb = TICKER_STATUS_BUSY;
432 ret = ticker_start(TICKER_INSTANCE_ID_CTLR,
433 TICKER_USER_ID_THREAD, TICKER_ID_SCAN_BASE + handle,
434 ticks_anchor, 0, ticks_interval,
435 HAL_TICKER_REMAINDER((uint64_t)lll->interval *
436 SCAN_INT_UNIT_US),
437 TICKER_NULL_LAZY,
438 (scan->ull.ticks_slot + ticks_slot_overhead),
439 ticker_cb, scan,
440 ull_ticker_status_give, (void *)&ret_cb);
441 ret = ull_ticker_status_take(ret, &ret_cb);
442 if (ret != TICKER_STATUS_SUCCESS) {
443 return BT_HCI_ERR_CMD_DISALLOWED;
444 }
445
446 scan->is_enabled = 1U;
447
448 #if defined(CONFIG_BT_CTLR_PRIVACY)
449 #if defined(CONFIG_BT_BROADCASTER)
450 if (!ull_adv_is_enabled_get(0))
451 #endif
452 {
453 ull_filter_adv_scan_state_cb(BIT(1));
454 }
455 #endif
456
457 return 0;
458 }
459
460 uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan)
461 {
462 int err;
463
464 err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_BASE + handle,
465 scan, &scan->lll);
466 LL_ASSERT(err == 0 || err == -EALREADY);
467 if (err) {
468 return BT_HCI_ERR_CMD_DISALLOWED;
469 }
470
471 return 0;
472 }
473
474 #if defined(CONFIG_BT_CTLR_ADV_EXT)
475 void ull_scan_done(struct node_rx_event_done *done)
476 {
477 struct node_rx_hdr *rx_hdr;
478 struct ll_scan_set *scan;
479 struct lll_scan *lll;
480 uint8_t handle;
481 uint32_t ret;
482
483 /* Get reference to ULL context */
484 scan = CONTAINER_OF(done->param, struct ll_scan_set, ull);
485 lll = &scan->lll;
486
487 if (likely(scan->duration_lazy || !lll->duration_reload ||
488 lll->duration_expire)) {
489 return;
490 }
491
492 rx_hdr = (void *)scan->node_rx_scan_term;
493 if (!rx_hdr) {
494 /* Prevent generation if another scan instance already did so.
495 */
496 return;
497 }
498
499 handle = ull_scan_handle_get(scan);
500 LL_ASSERT(handle < BT_CTLR_SCAN_SET);
501
502 #if defined(CONFIG_BT_CTLR_PHY_CODED)
503 /* Reset the singular node rx buffer, so that it does not get used if
504 * ull_scan_done get called by the other scan instance.
505 */
506 struct ll_scan_set *scan_other;
507
508 if (handle == SCAN_HANDLE_1M) {
509 scan_other = ull_scan_set_get(SCAN_HANDLE_PHY_CODED);
510 } else {
511 scan_other = ull_scan_set_get(SCAN_HANDLE_1M);
512 }
513 scan_other->node_rx_scan_term = NULL;
514 #endif /* CONFIG_BT_CTLR_PHY_CODED */
515
516 rx_hdr->type = NODE_RX_TYPE_EXT_SCAN_TERMINATE;
517 rx_hdr->handle = handle;
518
519 ret = ticker_stop(TICKER_INSTANCE_ID_CTLR, TICKER_USER_ID_ULL_HIGH,
520 (TICKER_ID_SCAN_BASE + handle), ticker_stop_ext_op_cb,
521 scan);
522
523 LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
524 (ret == TICKER_STATUS_BUSY));
525 }
526
527 void ull_scan_term_dequeue(uint8_t handle)
528 {
529 struct ll_scan_set *scan;
530
531 scan = ull_scan_set_get(handle);
532 LL_ASSERT(scan);
533
534 scan->is_enabled = 0U;
535
536 #if defined(CONFIG_BT_CTLR_PHY_CODED)
537 if (handle == SCAN_HANDLE_1M) {
538 struct ll_scan_set *scan_coded;
539
540 scan_coded = ull_scan_set_get(SCAN_HANDLE_PHY_CODED);
541 if (scan_coded->lll.phy & PHY_CODED) {
542 uint8_t err;
543
544 err = disable(SCAN_HANDLE_PHY_CODED);
545 LL_ASSERT(!err);
546 }
547 } else {
548 struct ll_scan_set *scan_1m;
549
550 scan_1m = ull_scan_set_get(SCAN_HANDLE_1M);
551 if (scan_1m->lll.phy & PHY_1M) {
552 uint8_t err;
553
554 err = disable(SCAN_HANDLE_1M);
555 LL_ASSERT(!err);
556 }
557 }
558 #endif /* CONFIG_BT_CTLR_PHY_CODED */
559 }
560 #endif /* CONFIG_BT_CTLR_ADV_EXT */
561
562 struct ll_scan_set *ull_scan_set_get(uint8_t handle)
563 {
564 if (handle >= BT_CTLR_SCAN_SET) {
565 return NULL;
566 }
567
568 return &ll_scan[handle];
569 }
570
571 uint8_t ull_scan_handle_get(struct ll_scan_set *scan)
572 {
573 return ((uint8_t *)scan - (uint8_t *)ll_scan) / sizeof(*scan);
574 }
575
576 uint8_t ull_scan_lll_handle_get(struct lll_scan *lll)
577 {
578 return ull_scan_handle_get((void *)lll->hdr.parent);
579 }
580
581 struct ll_scan_set *ull_scan_is_valid_get(struct ll_scan_set *scan)
582 {
583 if (((uint8_t *)scan < (uint8_t *)ll_scan) ||
584 ((uint8_t *)scan > ((uint8_t *)ll_scan +
585 (sizeof(struct ll_scan_set) *
586 (BT_CTLR_SCAN_SET - 1))))) {
587 return NULL;
588 }
589
590 return scan;
591 }
592
593 struct ll_scan_set *ull_scan_is_enabled_get(uint8_t handle)
594 {
595 struct ll_scan_set *scan;
596
597 scan = ull_scan_set_get(handle);
598 if (!scan || !scan->is_enabled) {
599 return NULL;
600 }
601
602 return scan;
603 }
604
605 struct ll_scan_set *ull_scan_is_disabled_get(uint8_t handle)
606 {
607 struct ll_scan_set *scan;
608
609 scan = ull_scan_set_get(handle);
610 if (!scan || scan->is_enabled) {
611 return NULL;
612 }
613
614 return scan;
615 }
616
617 uint32_t ull_scan_is_enabled(uint8_t handle)
618 {
619 struct ll_scan_set *scan;
620
621 scan = ull_scan_is_enabled_get(handle);
622 if (!scan) {
623 #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
624 scan = ull_scan_set_get(handle);
625
626 return scan->per_scan.sync ? ULL_SCAN_IS_SYNC : 0U;
627 #else
628 return 0U;
629 #endif
630 }
631
632 return (((uint32_t)scan->is_enabled << scan->lll.type) |
633 #if defined(CONFIG_BT_CENTRAL)
634 (scan->lll.conn ? ULL_SCAN_IS_INITIATOR : 0U) |
635 #endif
636 #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC)
637 (scan->per_scan.sync ? ULL_SCAN_IS_SYNC : 0U) |
638 #endif
639 0U);
640 }
641
642 uint32_t ull_scan_filter_pol_get(uint8_t handle)
643 {
644 struct ll_scan_set *scan;
645
646 scan = ull_scan_is_enabled_get(handle);
647 if (!scan) {
648 return 0;
649 }
650
651 return scan->lll.filter_policy;
652 }
653
654 static int init_reset(void)
655 {
656 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL) && \
657 !defined(CONFIG_BT_CTLR_ADV_EXT)
658 ll_scan[0].lll.tx_pwr_lvl = RADIO_TXP_DEFAULT;
659 #endif /* CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL && !CONFIG_BT_CTLR_ADV_EXT */
660
661 return 0;
662 }
663
664 static void ticker_cb(uint32_t ticks_at_expire, uint32_t ticks_drift,
665 uint32_t remainder, uint16_t lazy, uint8_t force,
666 void *param)
667 {
668 static memq_link_t link;
669 static struct mayfly mfy = {0, 0, &link, NULL, lll_scan_prepare};
670 static struct lll_prepare_param p;
671 struct ll_scan_set *scan;
672 struct lll_scan *lll;
673 uint32_t ret;
674 uint8_t ref;
675
676 DEBUG_RADIO_PREPARE_O(1);
677
678 scan = param;
679 lll = &scan->lll;
680
681 /* Increment prepare reference count */
682 ref = ull_ref_inc(&scan->ull);
683 LL_ASSERT(ref);
684
685 /* Append timing parameters */
686 p.ticks_at_expire = ticks_at_expire;
687 p.remainder = remainder;
688 p.lazy = lazy;
689 p.param = lll;
690 p.force = force;
691 mfy.param = &p;
692
693 /* Kick LLL prepare */
694 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH, TICKER_USER_ID_LLL,
695 0, &mfy);
696 LL_ASSERT(!ret);
697
698 #if defined(CONFIG_BT_CTLR_ADV_EXT)
699 if (lll->duration_expire) {
700 uint16_t elapsed;
701
702 elapsed = lazy + 1;
703 if (lll->duration_expire > elapsed) {
704 lll->duration_expire -= elapsed;
705 } else {
706 if (scan->duration_lazy) {
707 uint8_t handle;
708 uint16_t duration_lazy;
709
710 duration_lazy = lll->duration_expire +
711 scan->duration_lazy - elapsed;
712
713 handle = ull_scan_handle_get(scan);
714 LL_ASSERT(handle < BT_CTLR_SCAN_SET);
715
716 ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
717 TICKER_USER_ID_ULL_HIGH,
718 (TICKER_ID_SCAN_BASE +
719 handle), 0, 0, 0, 0,
720 duration_lazy, 0,
721 NULL, NULL);
722 LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
723 (ret == TICKER_STATUS_BUSY));
724 }
725
726 lll->duration_expire = 0U;
727 }
728 } else if (lll->duration_reload && lazy) {
729 uint8_t handle;
730
731 handle = ull_scan_handle_get(scan);
732 LL_ASSERT(handle < BT_CTLR_SCAN_SET);
733
734 lll->duration_expire = lll->duration_reload;
735 ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
736 TICKER_USER_ID_ULL_HIGH,
737 (TICKER_ID_SCAN_BASE + handle),
738 0, 0, 0, 0, 1, 1, NULL, NULL);
739 LL_ASSERT((ret == TICKER_STATUS_SUCCESS) ||
740 (ret == TICKER_STATUS_BUSY));
741 }
742 #endif /* CONFIG_BT_CTLR_ADV_EXT */
743
744 DEBUG_RADIO_PREPARE_O(1);
745 }
746
747 #if defined(CONFIG_BT_CTLR_ADV_EXT)
748 static uint8_t is_scan_update(uint8_t handle, uint16_t duration,
749 uint16_t period, struct ll_scan_set **scan,
750 struct node_rx_pdu **node_rx_scan_term)
751 {
752 *scan = ull_scan_set_get(handle);
753 *node_rx_scan_term = (void *)(*scan)->node_rx_scan_term;
754 return duration && period && (*scan)->lll.duration_reload &&
755 (*scan)->duration_lazy;
756 }
757
758 static uint8_t duration_period_setup(struct ll_scan_set *scan,
759 uint16_t duration, uint16_t period,
760 struct node_rx_pdu **node_rx_scan_term)
761 {
762 struct lll_scan *lll;
763
764 lll = &scan->lll;
765 if (duration) {
766 lll->duration_reload =
767 ULL_SCAN_DURATION_TO_EVENTS(duration,
768 scan->lll.interval);
769 if (period) {
770 if (IS_ENABLED(CONFIG_BT_CTLR_PARAM_CHECK) &&
771 (duration >= ULL_SCAN_PERIOD_TO_DURATION(period))) {
772 return BT_HCI_ERR_INVALID_PARAM;
773 }
774
775 scan->duration_lazy =
776 ULL_SCAN_PERIOD_TO_EVENTS(period,
777 scan->lll.interval);
778 scan->duration_lazy -= lll->duration_reload;
779 scan->node_rx_scan_term = NULL;
780 } else {
781 struct node_rx_pdu *node_rx;
782 void *link_scan_term;
783
784 scan->duration_lazy = 0U;
785
786 if (*node_rx_scan_term) {
787 scan->node_rx_scan_term =
788 (void *)*node_rx_scan_term;
789
790 return 0;
791 }
792
793 /* The alloc here used for ext scan termination event */
794 link_scan_term = ll_rx_link_alloc();
795 if (!link_scan_term) {
796 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
797 }
798
799 node_rx = ll_rx_alloc();
800 if (!node_rx) {
801 ll_rx_link_release(link_scan_term);
802
803 return BT_HCI_ERR_MEM_CAPACITY_EXCEEDED;
804 }
805
806 node_rx->hdr.link = (void *)link_scan_term;
807 scan->node_rx_scan_term = (void *)node_rx;
808 *node_rx_scan_term = node_rx;
809 }
810 } else {
811 lll->duration_reload = 0U;
812 scan->duration_lazy = 0U;
813 scan->node_rx_scan_term = NULL;
814 }
815
816 return 0;
817 }
818
819 static uint8_t duration_period_update(struct ll_scan_set *scan,
820 uint8_t is_update)
821 {
822 if (is_update) {
823 uint32_t volatile ret_cb;
824 uint32_t ret;
825
826 scan->lll.duration_expire = 0U;
827
828 ret_cb = TICKER_STATUS_BUSY;
829 ret = ticker_update(TICKER_INSTANCE_ID_CTLR,
830 TICKER_USER_ID_THREAD,
831 (TICKER_ID_SCAN_BASE +
832 ull_scan_handle_get(scan)),
833 0, 0, 0, 0, 1, 1,
834 ull_ticker_status_give, (void *)&ret_cb);
835 ret = ull_ticker_status_take(ret, &ret_cb);
836 if (ret != TICKER_STATUS_SUCCESS) {
837 return BT_HCI_ERR_CMD_DISALLOWED;
838 }
839
840 return 0;
841 } else {
842 scan->lll.duration_expire = scan->lll.duration_reload;
843 }
844
845 return 0;
846 }
847
848 static void ticker_stop_ext_op_cb(uint32_t status, void *param)
849 {
850 static memq_link_t link;
851 static struct mayfly mfy = {0, 0, &link, NULL, ext_disable};
852 uint32_t ret;
853
854 /* Ignore if race between thread and ULL */
855 if (status != TICKER_STATUS_SUCCESS) {
856 /* TODO: detect race */
857
858 return;
859 }
860
861 /* Check if any pending LLL events that need to be aborted */
862 mfy.param = param;
863 ret = mayfly_enqueue(TICKER_USER_ID_ULL_LOW,
864 TICKER_USER_ID_ULL_HIGH, 0, &mfy);
865 LL_ASSERT(!ret);
866 }
867
868 static void ext_disable(void *param)
869 {
870 struct ll_scan_set *scan;
871 struct ull_hdr *hdr;
872
873 /* Check ref count to determine if any pending LLL events in pipeline */
874 scan = param;
875 hdr = &scan->ull;
876 if (ull_ref_get(hdr)) {
877 static memq_link_t link;
878 static struct mayfly mfy = {0, 0, &link, NULL, lll_disable};
879 uint32_t ret;
880
881 mfy.param = &scan->lll;
882
883 /* Setup disabled callback to be called when ref count
884 * returns to zero.
885 */
886 LL_ASSERT(!hdr->disabled_cb);
887 hdr->disabled_param = mfy.param;
888 hdr->disabled_cb = ext_disabled_cb;
889
890 /* Trigger LLL disable */
891 ret = mayfly_enqueue(TICKER_USER_ID_ULL_HIGH,
892 TICKER_USER_ID_LLL, 0, &mfy);
893 LL_ASSERT(!ret);
894 } else {
895 /* No pending LLL events */
896 ext_disabled_cb(&scan->lll);
897 }
898 }
899
900 static void ext_disabled_cb(void *param)
901 {
902 struct node_rx_hdr *rx_hdr;
903 struct ll_scan_set *scan;
904 struct lll_scan *lll;
905
906 /* Under race condition, if a connection has been established then
907 * node_rx is already utilized to send terminate event on connection
908 */
909 lll = (void *)param;
910 scan = HDR_LLL2ULL(lll);
911 rx_hdr = (void *)scan->node_rx_scan_term;
912 if (!rx_hdr) {
913 return;
914 }
915
916 /* NOTE: parameters are already populated on disable,
917 * just enqueue here
918 */
919 ll_rx_put(rx_hdr->link, rx_hdr);
920 ll_rx_sched();
921 }
922 #endif /* CONFIG_BT_CTLR_ADV_EXT */
923
924 static uint8_t disable(uint8_t handle)
925 {
926 struct ll_scan_set *scan;
927 uint8_t ret;
928
929 scan = ull_scan_is_enabled_get(handle);
930 if (!scan) {
931 return BT_HCI_ERR_CMD_DISALLOWED;
932 }
933
934 #if defined(CONFIG_BT_CENTRAL)
935 if (scan->lll.conn) {
936 return BT_HCI_ERR_CMD_DISALLOWED;
937 }
938 #endif
939
940 ret = ull_scan_disable(handle, scan);
941 if (ret) {
942 return ret;
943 }
944
945 scan->is_enabled = 0U;
946
947 #if defined(CONFIG_BT_CTLR_ADV_EXT)
948 if (scan->node_rx_scan_term) {
949 struct node_rx_pdu *node_rx_scan_term =
950 (void *)scan->node_rx_scan_term;
951
952 scan->node_rx_scan_term = NULL;
953
954 ll_rx_link_release(node_rx_scan_term->hdr.link);
955 ll_rx_release(node_rx_scan_term);
956 }
957 #endif /* CONFIG_BT_CTLR_ADV_EXT */
958
959 #if defined(CONFIG_BT_CTLR_PRIVACY)
960 #if defined(CONFIG_BT_BROADCASTER)
961 if (!ull_adv_is_enabled_get(0))
962 #endif
963 {
964 ull_filter_adv_scan_state_cb(0);
965 }
966 #endif
967
968 return 0;
969 }
970