Bluetooth: Controller: Fix hang due to loop in node_rx list

Fix Controller hang due to infinite looping caused by
duplicate node_rx enqueued in auxiliary context.

When LLL scheduling is not applied due to invalid aux offset
then ULL scheduling too would skip setting up the reception
after similarly checking the validity of aux offset required
to schedule the reception of auxiliary PDU. This check in
ULL was after the received node_rx being enqueued into the
auxiliary context causing a loop in the list of node_rx.

Dequeue of a list with a loop of node_rx caused an infinite
loop execution in the Controller.

Regression introduced in commit 3590bd648f ("Bluetooth:
Controller: Fix missing invalid aux offset check").

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2024-09-11 12:56:27 +02:00 committed by Mahesh Mahadevan
parent 437bfa5b1a
commit 9fa18600ee
2 changed files with 20 additions and 17 deletions

View File

@ -124,8 +124,8 @@ uint8_t lll_scan_aux_setup(struct pdu_adv *pdu, uint8_t pdu_phy,
struct pdu_cte_info *cte_info;
struct node_rx_pdu *node_rx;
uint32_t window_widening_us;
uint32_t window_size_us;
struct node_rx_ftr *ftr;
uint16_t window_size_us;
uint32_t aux_offset_us;
uint32_t overhead_us;
uint8_t *pri_dptr;
@ -186,7 +186,7 @@ uint8_t lll_scan_aux_setup(struct pdu_adv *pdu, uint8_t pdu_phy,
/* Skip reception if invalid aux offset */
pdu_us = PDU_AC_US(pdu->len, pdu_phy, pdu_phy_flags_rx);
if (aux_offset_us < pdu_us) {
if (unlikely((aux_offset_us + window_size_us) < (pdu_us + EVENT_MAFS_US))) {
return 0U;
}

View File

@ -116,6 +116,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx)
struct pdu_adv_adi *adi;
struct node_rx_ftr *ftr;
uint32_t ready_delay_us;
uint16_t window_size_us;
uint32_t aux_offset_us;
uint32_t ticker_status;
struct lll_scan *lll;
@ -511,6 +512,22 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx)
goto ull_scan_aux_rx_flush;
}
/* Determine the window size */
if (aux_ptr->offs_units) {
window_size_us = OFFS_UNIT_300_US;
} else {
window_size_us = OFFS_UNIT_30_US;
}
/* Calculate received aux offset we need to have ULL schedule a reception */
aux_offset_us = (uint32_t)PDU_ADV_AUX_PTR_OFFSET_GET(aux_ptr) * window_size_us;
/* Skip reception if invalid aux offset */
pdu_us = PDU_AC_US(pdu->len, phy, ftr->phy_flags);
if (unlikely((aux_offset_us + window_size_us) < (pdu_us + EVENT_MAFS_US))) {
goto ull_scan_aux_rx_flush;
}
if (!aux) {
aux = aux_acquire();
if (!aux) {
@ -697,21 +714,6 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx)
aux->rx_head = rx;
}
/* Determine the window size */
if (aux_ptr->offs_units) {
lll_aux->window_size_us = OFFS_UNIT_300_US;
} else {
lll_aux->window_size_us = OFFS_UNIT_30_US;
}
aux_offset_us = (uint32_t)PDU_ADV_AUX_PTR_OFFSET_GET(aux_ptr) * lll_aux->window_size_us;
/* Skip reception if invalid aux offset */
pdu_us = PDU_AC_US(pdu->len, phy, ftr->phy_flags);
if (aux_offset_us < pdu_us) {
goto ull_scan_aux_rx_flush;
}
/* CA field contains the clock accuracy of the advertiser;
* 0 - 51 ppm to 500 ppm
* 1 - 0 ppm to 50 ppm
@ -722,6 +724,7 @@ void ull_scan_aux_setup(memq_link_t *link, struct node_rx_pdu *rx)
window_widening_us = SCA_DRIFT_500_PPM_US(aux_offset_us);
}
lll_aux->window_size_us = window_size_us;
lll_aux->window_size_us += ((EVENT_TICKER_RES_MARGIN_US + EVENT_JITTER_US +
window_widening_us) << 1);