From 9fa18600eea54115d69d919906de78f835c1ecc7 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 11 Sep 2024 12:56:27 +0200 Subject: [PATCH] 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 3590bd648f8f ("Bluetooth: Controller: Fix missing invalid aux offset check"). Signed-off-by: Vinayak Kariappa Chettimada --- .../ll_sw/nordic/lll/lll_scan_aux.c | 4 +-- .../bluetooth/controller/ll_sw/ull_scan_aux.c | 33 ++++++++++--------- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c index eb97ab789fd..3c4c591d228 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan_aux.c @@ -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; } diff --git a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c index 0e4bbf0f2cd..864a8240d35 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c +++ b/subsys/bluetooth/controller/ll_sw/ull_scan_aux.c @@ -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);