From b6fb074d6ed81f9482e7013e0c98094a723521bb Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Tue, 29 Sep 2020 15:14:08 +0530 Subject: [PATCH] Bluetooth: controller: Connection termination race condition Add checks to abort connection radio event preparation and start, if the connection terminates with a race condition with new radio event being prepared or being in prepare pipeline. Signed-off-by: Vinayak Kariappa Chettimada --- .../controller/ll_sw/nordic/lll/lll_master.c | 14 ++++++++++++++ .../controller/ll_sw/nordic/lll/lll_slave.c | 14 ++++++++++++++ subsys/bluetooth/controller/ll_sw/ull_conn.c | 2 -- subsys/bluetooth/controller/ll_sw/ull_master.c | 11 ++++++++++- subsys/bluetooth/controller/ll_sw/ull_slave.c | 11 ++++++++++- 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_master.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_master.c index e2beed9977b..8ef8d7d0abd 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_master.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_master.c @@ -100,6 +100,20 @@ static int prepare_cb(struct lll_prepare_param *prepare_param) DEBUG_RADIO_START_M(1); + /* Check if stopped (on disconnection between prepare and pre-empt) + */ + if (unlikely(lll->handle == 0xFFFF)) { + int err; + + err = lll_hfclock_off(); + LL_ASSERT(err >= 0); + + lll_done(NULL); + + DEBUG_RADIO_START_M(0); + return 0; + } + /* Reset connection event global variables */ lll_conn_prepare_reset(); diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_slave.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_slave.c index 4843748561f..2c8ed2b77a2 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_slave.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_slave.c @@ -109,6 +109,20 @@ static int prepare_cb(struct lll_prepare_param *prepare_param) DEBUG_RADIO_START_S(1); + /* Check if stopped (on disconnection between prepare and pre-empt) + */ + if (unlikely(lll->handle == 0xFFFF)) { + int err; + + err = lll_hfclock_off(); + LL_ASSERT(err >= 0); + + lll_done(NULL); + + DEBUG_RADIO_START_S(0); + return 0; + } + /* Reset connection event global variables */ lll_conn_prepare_reset(); diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 641fb0f98ff..d4d60180ac7 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -815,8 +815,6 @@ int ull_conn_rx(memq_link_t *link, struct node_rx_pdu **rx) int ull_conn_llcp(struct ll_conn *conn, uint32_t ticks_at_expire, uint16_t lazy) { - LL_ASSERT(conn->lll.handle != 0xFFFF); - /* Check if no other procedure with instant is requested and not in * Encryption setup. */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_master.c b/subsys/bluetooth/controller/ll_sw/ull_master.c index 3be93653195..53abb17f5b6 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_master.c +++ b/subsys/bluetooth/controller/ll_sw/ull_master.c @@ -728,12 +728,21 @@ void ull_master_ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, uint16_t static memq_link_t link; static struct mayfly mfy = {0, 0, &link, NULL, lll_master_prepare}; static struct lll_prepare_param p; - struct ll_conn *conn = param; + struct ll_conn *conn; uint32_t err; uint8_t ref; DEBUG_RADIO_PREPARE_M(1); + conn = param; + + /* Check if stopping ticker (on disconnection, race with ticker expiry) + */ + if (unlikely(conn->lll.handle == 0xFFFF)) { + DEBUG_RADIO_PREPARE_M(0); + return; + } + /* If this is a must-expire callback, LLCP state machine does not need * to know. Will be called with lazy > 0 when scheduled in air. */ diff --git a/subsys/bluetooth/controller/ll_sw/ull_slave.c b/subsys/bluetooth/controller/ll_sw/ull_slave.c index 4b99f62ba62..16f21af6244 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_slave.c +++ b/subsys/bluetooth/controller/ll_sw/ull_slave.c @@ -375,12 +375,21 @@ void ull_slave_ticker_cb(uint32_t ticks_at_expire, uint32_t remainder, static memq_link_t link; static struct mayfly mfy = {0, 0, &link, NULL, lll_slave_prepare}; static struct lll_prepare_param p; - struct ll_conn *conn = param; + struct ll_conn *conn; uint32_t err; uint8_t ref; DEBUG_RADIO_PREPARE_S(1); + conn = param; + + /* Check if stopping ticker (on disconnection, race with ticker expiry) + */ + if (unlikely(conn->lll.handle == 0xFFFF)) { + DEBUG_RADIO_PREPARE_S(0); + return; + } + /* If this is a must-expire callback, LLCP state machine does not need * to know. Will be called with lazy > 0 when scheduled in air. */