diff --git a/subsys/bluetooth/controller/ll_sw/lll_conn.h b/subsys/bluetooth/controller/ll_sw/lll_conn.h index 7fb326e5bd6..0564c61b893 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_conn.h +++ b/subsys/bluetooth/controller/ll_sw/lll_conn.h @@ -59,6 +59,7 @@ struct lll_conn { union { struct { uint8_t initiated:1; + uint8_t cancelled:1; } master; #if defined(CONFIG_BT_PERIPHERAL) struct { diff --git a/subsys/bluetooth/controller/ll_sw/lll_scan.h b/subsys/bluetooth/controller/ll_sw/lll_scan.h index 972d3332295..767e9b19370 100644 --- a/subsys/bluetooth/controller/ll_sw/lll_scan.h +++ b/subsys/bluetooth/controller/ll_sw/lll_scan.h @@ -12,7 +12,7 @@ struct lll_scan { * check ull_conn_setup how it access the connection LLL * context. */ - struct lll_conn *conn; + struct lll_conn *volatile conn; uint8_t adv_addr[BDADDR_SIZE]; uint32_t conn_win_offset_us; diff --git a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c index 33f46bedf64..f7a7507c58f 100644 --- a/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c +++ b/subsys/bluetooth/controller/ll_sw/nordic/lll/lll_scan.c @@ -140,7 +140,9 @@ static int prepare_cb(struct lll_prepare_param *p) /* Check if stopped (on connection establishment race between LLL and * ULL. */ - if (unlikely(lll->conn && lll->conn->master.initiated)) { + if (unlikely(lll->conn && + (lll->conn->master.initiated || + lll->conn->master.cancelled))) { int err; err = lll_hfclock_off(); @@ -779,7 +781,7 @@ static inline int isr_rx_pdu(struct lll_scan *lll, struct pdu_adv *pdu_adv_rx, if (0) { #if defined(CONFIG_BT_CENTRAL) /* Initiator */ - } else if (lll->conn && + } else if (lll->conn && !lll->conn->master.cancelled && isr_scan_init_check(lll, pdu_adv_rx, rl_idx)) { struct lll_conn *lll_conn; struct node_rx_ftr *ftr; diff --git a/subsys/bluetooth/controller/ll_sw/ull_master.c b/subsys/bluetooth/controller/ll_sw/ull_master.c index 550ed3d994d..e34c4e74741 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_master.c +++ b/subsys/bluetooth/controller/ll_sw/ull_master.c @@ -222,6 +222,7 @@ uint8_t ll_create_connection(uint16_t scan_interval, uint16_t scan_window, conn_lll->data_chan_use = 0; conn_lll->role = 0; conn_lll->master.initiated = 0; + conn_lll->master.cancelled = 0; /* FIXME: END: Move to ULL? */ #if defined(CONFIG_BT_CTLR_CONN_META) memset(&conn_lll->conn_meta, 0, sizeof(conn_lll->conn_meta)); @@ -428,8 +429,28 @@ uint8_t ll_connect_disable(void **rx) scan_lll = &scan->lll; } + /* Check if initiator active */ conn_lll = scan_lll->conn; if (!conn_lll) { + /* Scanning not associated with initiation of a connection or + * connection setup already complete (was set to NULL in + * ull_master_setup), but HCI event not processed by host. + */ + return BT_HCI_ERR_CMD_DISALLOWED; + } + + /* Indicate to LLL that a cancellation is requested */ + conn_lll->master.cancelled = 1U; + cpu_dmb(); + + /* Check if connection was established under race condition, i.e. + * before the cancelled flag was set. + */ + conn_lll = scan_lll->conn; + if (!conn_lll) { + /* Connection setup completed on race condition with cancelled + * flag, before it was set. + */ return BT_HCI_ERR_CMD_DISALLOWED; }