Bluetooth: controller: Fix race in create connection cancel

Fix race conditional when create connection cancel is called
and actually a connection did get setup while initiator is
being stopped.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2021-03-16 11:48:07 +05:30 committed by Carles Cufí
commit 77cfd3cf52
4 changed files with 27 additions and 3 deletions

View file

@ -59,6 +59,7 @@ struct lll_conn {
union { union {
struct { struct {
uint8_t initiated:1; uint8_t initiated:1;
uint8_t cancelled:1;
} master; } master;
#if defined(CONFIG_BT_PERIPHERAL) #if defined(CONFIG_BT_PERIPHERAL)
struct { struct {

View file

@ -12,7 +12,7 @@ struct lll_scan {
* check ull_conn_setup how it access the connection LLL * check ull_conn_setup how it access the connection LLL
* context. * context.
*/ */
struct lll_conn *conn; struct lll_conn *volatile conn;
uint8_t adv_addr[BDADDR_SIZE]; uint8_t adv_addr[BDADDR_SIZE];
uint32_t conn_win_offset_us; uint32_t conn_win_offset_us;

View file

@ -140,7 +140,9 @@ static int prepare_cb(struct lll_prepare_param *p)
/* Check if stopped (on connection establishment race between LLL and /* Check if stopped (on connection establishment race between LLL and
* ULL. * ULL.
*/ */
if (unlikely(lll->conn && lll->conn->master.initiated)) { if (unlikely(lll->conn &&
(lll->conn->master.initiated ||
lll->conn->master.cancelled))) {
int err; int err;
err = lll_hfclock_off(); 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 (0) {
#if defined(CONFIG_BT_CENTRAL) #if defined(CONFIG_BT_CENTRAL)
/* Initiator */ /* Initiator */
} else if (lll->conn && } else if (lll->conn && !lll->conn->master.cancelled &&
isr_scan_init_check(lll, pdu_adv_rx, rl_idx)) { isr_scan_init_check(lll, pdu_adv_rx, rl_idx)) {
struct lll_conn *lll_conn; struct lll_conn *lll_conn;
struct node_rx_ftr *ftr; struct node_rx_ftr *ftr;

View file

@ -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->data_chan_use = 0;
conn_lll->role = 0; conn_lll->role = 0;
conn_lll->master.initiated = 0; conn_lll->master.initiated = 0;
conn_lll->master.cancelled = 0;
/* FIXME: END: Move to ULL? */ /* FIXME: END: Move to ULL? */
#if defined(CONFIG_BT_CTLR_CONN_META) #if defined(CONFIG_BT_CTLR_CONN_META)
memset(&conn_lll->conn_meta, 0, sizeof(conn_lll->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; scan_lll = &scan->lll;
} }
/* Check if initiator active */
conn_lll = scan_lll->conn; conn_lll = scan_lll->conn;
if (!conn_lll) { 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; return BT_HCI_ERR_CMD_DISALLOWED;
} }