Bluetooth: Controller: Fix to stop Extended Auxiliary Scan context

Fix any stray Extended Auxiliary PDU from being scanned
when disabling Extended Scanning.

Updated Extended Scan disable implementation to find any
active auxiliary scan context and stop them.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2021-12-13 07:04:53 +05:30 committed by Carles Cufí
parent ffeee6ce1f
commit a5fb434705
4 changed files with 115 additions and 10 deletions

View File

@ -355,13 +355,20 @@ void ull_scan_params_set(struct lll_scan *lll, uint8_t type, uint16_t interval,
uint8_t ull_scan_enable(struct ll_scan_set *scan)
{
struct lll_scan *lll = &scan->lll;
uint32_t ticks_slot_overhead;
uint32_t volatile ret_cb;
uint32_t ticks_interval;
uint32_t ticks_anchor;
struct lll_scan *lll;
uint32_t ret;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
/* Initialize extend scan stop request */
scan->is_stop = 0U;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
/* Initialize LLL scan context */
lll = &scan->lll;
lll->init_addr_type = scan->own_addr_type;
(void)ll_addr_read(lll->init_addr_type, lll->init_addr);
lll->chan = 0U;
@ -462,6 +469,12 @@ uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan)
{
int err;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
/* Request Extended Scan stop */
scan->is_stop = 1U;
cpu_dmb();
#endif /* CONFIG_BT_CTLR_ADV_EXT */
err = ull_ticker_stop_with_mark(TICKER_ID_SCAN_BASE + handle,
scan, &scan->lll);
LL_ASSERT(err == 0 || err == -EALREADY);
@ -469,6 +482,30 @@ uint8_t ull_scan_disable(uint8_t handle, struct ll_scan_set *scan)
return BT_HCI_ERR_CMD_DISALLOWED;
}
#if defined(CONFIG_BT_CTLR_ADV_EXT)
/* Find and stop associated auxiliary scan contexts */
for (uint8_t aux_handle = 0; aux_handle < CONFIG_BT_CTLR_SCAN_AUX_SET;
aux_handle++) {
struct lll_scan_aux *aux_scan_lll;
struct ll_scan_set *aux_scan;
struct ll_scan_aux_set *aux;
aux = ull_scan_aux_set_get(aux_handle);
aux_scan_lll = aux->parent;
if (!aux_scan_lll) {
continue;
}
aux_scan = HDR_LLL2ULL(aux_scan_lll);
if (aux_scan == scan) {
err = ull_scan_aux_stop(aux);
if (err && (err != -EALREADY)) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
}
}
#endif /* CONFIG_BT_CTLR_ADV_EXT */
return 0;
}

View File

@ -552,6 +552,14 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx)
/* Switching to ULL scheduling to receive auxiliary PDUs */
if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC) || lll) {
/* Do not ULL schedule if scan disable requested */
if (unlikely(scan->is_stop)) {
goto ull_scan_aux_rx_flush;
}
/* Remove auxiliary context association with scan context so
* that LLL can differentiate it to being ULL scheduling.
*/
lll->lll_aux = NULL;
} else {
struct ll_sync_set *sync;
@ -747,13 +755,36 @@ void ull_scan_aux_done(struct node_rx_event_done *done)
aux = HDR_LLL2ULL(sync->lll.lll_aux);
} else {
struct ll_scan_set *scan;
scan = HDR_LLL2ULL(aux->parent);
LL_ASSERT(ull_scan_is_valid_get(scan));
/* Auxiliary context will be flushed by ull_scan_aux_stop() */
if (unlikely(scan->is_stop)) {
return;
}
/* Setup the disabled callback to flush the auxiliary PDUs */
hdr = &aux->ull;
}
LL_ASSERT(!hdr->disabled_cb);
hdr->disabled_param = aux;
hdr->disabled_cb = done_disabled_cb;
if (ull_ref_get(hdr) == 0U) {
flush(aux);
} else {
LL_ASSERT(!hdr->disabled_cb);
hdr->disabled_param = aux;
hdr->disabled_cb = done_disabled_cb;
}
}
struct ll_scan_aux_set *ull_scan_aux_set_get(uint8_t handle)
{
if (handle >= CONFIG_BT_CTLR_SCAN_AUX_SET) {
return NULL;
}
return &ll_scan_aux_pool[handle];
}
uint8_t ull_scan_aux_lll_handle_get(struct lll_scan_aux *lll)
@ -856,7 +887,7 @@ void ull_scan_aux_release(memq_link_t *link, struct node_rx_hdr *rx)
scan = HDR_LLL2ULL(lll);
scan = ull_scan_is_valid_get(scan);
if (scan) {
is_stop = 0U;
is_stop = scan->is_stop;
} else {
struct lll_sync *sync_lll;
struct ll_sync_set *sync;
@ -926,15 +957,37 @@ int ull_scan_aux_stop(struct ll_scan_aux_set *aux)
/* Abort LLL event if ULL scheduling not used or already in prepare */
if (err == -EALREADY) {
ret = ull_disable(&aux->lll);
if (ret) {
return -EBUSY;
err = ull_disable(&aux->lll);
if (err) {
return err;
}
mfy.fp = flush;
} else if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC)) {
/* ULL scan auxiliary PDU reception scheduling stopped
* before prepare.
*/
mfy.fp = flush;
} else {
/* ULL scheduling stopped before prepare */
mfy.fp = aux_sync_incomplete;
struct ll_scan_set *scan;
struct lll_scan *lll;
lll = aux->parent;
scan = HDR_LLL2ULL(lll);
scan = ull_scan_is_valid_get(scan);
if (scan) {
/* ULL scan auxiliary PDU reception scheduling stopped
* before prepare.
*/
mfy.fp = flush;
} else {
/* ULL sync chain reception scheduling stopped before
* prepare.
*/
mfy.fp = aux_sync_incomplete;
}
}
/* Release auxiliary context in ULL execution context */
@ -963,6 +1016,16 @@ static inline struct ll_scan_aux_set *aux_acquire(void)
static inline void aux_release(struct ll_scan_aux_set *aux)
{
/* Debug check that parent was assigned when allocated for reception of
* auxiliary channel PDUs.
*/
LL_ASSERT(aux->parent);
/* Clear the parent so that when scan is being disabled then this
* auxiliary context shall not associate itself from being disable.
*/
aux->parent = NULL;
mem_release(aux, &scan_aux_free);
}

View File

@ -80,6 +80,9 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_hdr *rx);
/* Helper to clean up auxiliary channel scanning */
void ull_scan_aux_done(struct node_rx_event_done *done);
/* Return the scan aux set instance given the handle */
struct ll_scan_aux_set *ull_scan_aux_set_get(uint8_t handle);
/* Helper function to check and return if a valid aux scan context */
struct ll_scan_aux_set *ull_scan_aux_is_valid_get(struct ll_scan_aux_set *aux);

View File

@ -11,6 +11,8 @@ struct ll_scan_set {
#if defined(CONFIG_BT_CTLR_ADV_EXT)
uint16_t duration_lazy;
struct node_rx_hdr *node_rx_scan_term;
uint8_t is_stop:1;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
uint8_t is_enabled:1;