From 48e5d9482a0ef2c66f4866ef057425b34a7fddd5 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Mon, 21 Oct 2019 19:43:09 +0530 Subject: [PATCH] Bluetooth: controller: split: Fix the slow Enc Setup alternative Fix the implementation of slow encryption setup design alternative to send ENC_RSP PDU before sending REJECT_IND or REJECT_EXT_IND PDU. Fixes #19917. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ull_conn.c | 105 ++++++++++++------ .../controller/ll_sw/ull_conn_types.h | 6 +- subsys/bluetooth/controller/ll_sw/ull_slave.c | 26 ++--- 3 files changed, 89 insertions(+), 48 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn.c b/subsys/bluetooth/controller/ll_sw/ull_conn.c index 220a7f640c2..ba53fec4c84 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn.c +++ b/subsys/bluetooth/controller/ll_sw/ull_conn.c @@ -2012,7 +2012,7 @@ static bool is_enc_req_pause_tx(struct ll_conn *conn) } if (conn->llcp_req == conn->llcp_ack) { - conn->llcp.encryption.initiate = 1U; + conn->llcp.encryption.state = LLCP_ENC_STATE_INIT; conn->llcp_type = LLCP_ENCRYPTION; conn->llcp_ack -= 2U; @@ -2503,11 +2503,56 @@ static inline void event_enc_reject_prep(struct ll_conn *conn, static inline void event_enc_prep(struct ll_conn *conn) { + struct lll_conn *lll = &conn->lll; struct pdu_data *pdu_ctrl_tx; struct node_tx *tx; - struct lll_conn *lll; - if (conn->llcp.encryption.initiate) { + if (conn->llcp.encryption.state) { +#if !defined(CONFIG_BT_CTLR_FAST_ENC) + if (lll->role && + (conn->llcp.encryption.state == LLCP_ENC_STATE_INIT)) { + struct node_rx_pdu *rx; + struct pdu_data *pdu; + u8_t err; + + /* TODO BT Spec. text: may finalize the sending + * of additional data channel PDUs queued in the + * controller. + */ + err = enc_rsp_send(conn); + if (err) { + return; + } + + /* get a rx node for ULL->LL */ + rx = ll_pdu_rx_alloc(); + if (!rx) { + return; + } + + /* prepare enc req structure */ + rx->hdr.handle = conn->lll.handle; + rx->hdr.type = NODE_RX_TYPE_DC_PDU; + pdu = (void *)rx->pdu; + pdu->ll_id = PDU_DATA_LLID_CTRL; + pdu->len = offsetof(struct pdu_data_llctrl, enc_req) + + sizeof(struct pdu_data_llctrl_enc_req); + pdu->llctrl.opcode = PDU_DATA_LLCTRL_TYPE_ENC_REQ; + memcpy(&pdu->llctrl.enc_req.rand[0], + &conn->llcp_enc.rand[0], + sizeof(pdu->llctrl.enc_req.rand)); + pdu->llctrl.enc_req.ediv[0] = conn->llcp_enc.ediv[0]; + pdu->llctrl.enc_req.ediv[1] = conn->llcp_enc.ediv[1]; + + /* enqueue enc req structure into rx queue */ + ll_rx_put(rx->hdr.link, rx); + ll_rx_sched(); + + /* Wait for LTK reply */ + conn->llcp.encryption.state = LLCP_ENC_STATE_LTK_WAIT; + } +#endif /* !CONFIG_BT_CTLR_FAST_ENC */ + return; } @@ -2516,8 +2561,6 @@ static inline void event_enc_prep(struct ll_conn *conn) return; } - lll = &conn->lll; - pdu_ctrl_tx = (void *)tx->pdu; /* master sends encrypted enc start rsp in control priority */ @@ -2559,7 +2602,7 @@ static inline void event_enc_prep(struct ll_conn *conn) #if defined(CONFIG_BT_CTLR_FAST_ENC) else { #else /* !CONFIG_BT_CTLR_FAST_ENC */ - else if (!conn->llcp_enc.pause_tx || conn->llcp_enc.refresh) { + else if (!lll->enc_rx) { #endif /* !CONFIG_BT_CTLR_FAST_ENC */ /* place the reject ind packet as next in tx queue */ @@ -2570,22 +2613,6 @@ static inline void event_enc_prep(struct ll_conn *conn) } /* place the start enc req packet as next in tx queue */ else { - -#if !defined(CONFIG_BT_CTLR_FAST_ENC) - u8_t err; - - /* TODO BT Spec. text: may finalize the sending - * of additional data channel PDUs queued in the - * controller. - */ - err = enc_rsp_send(conn); - if (err) { - mem_release(tx, &mem_conn_tx_ctrl.free); - - return; - } -#endif /* !CONFIG_BT_CTLR_FAST_ENC */ - /* calc the Session Key */ ecb_encrypt(&conn->llcp_enc.ltk[0], &conn->llcp.encryption.skd[0], NULL, @@ -5146,8 +5173,28 @@ static inline int ctrl_rx(memq_link_t *link, struct node_rx_pdu **rx, if (nack) { break; } + + /* Start Enc Req to be scheduled by LL api */ + conn->llcp.encryption.state = LLCP_ENC_STATE_LTK_WAIT; +#else /* CONFIG_BT_CTLR_FAST_ENC */ + /* back up rand and ediv for deferred generation of Enc Req */ + memcpy(&conn->llcp_enc.rand[0], + &pdu_rx->llctrl.enc_req.rand[0], + sizeof(conn->llcp_enc.rand)); + conn->llcp_enc.ediv[0] = pdu_rx->llctrl.enc_req.ediv[0]; + conn->llcp_enc.ediv[1] = pdu_rx->llctrl.enc_req.ediv[1]; + + /* Enc rsp to be scheduled in master prepare */ + conn->llcp.encryption.state = LLCP_ENC_STATE_INIT; + + /* Mark for buffer for release */ + (*rx)->hdr.type = NODE_RX_TYPE_DC_PDU_RELEASE; #endif /* CONFIG_BT_CTLR_FAST_ENC */ + /* Enc Setup state machine active */ + conn->llcp_type = LLCP_ENCRYPTION; + conn->llcp_ack -= 2U; + /* things from master stored for session key calculation */ memcpy(&conn->llcp.encryption.skd[0], &pdu_rx->llctrl.enc_req.skdm[0], 8); @@ -5185,20 +5232,15 @@ static inline int ctrl_rx(memq_link_t *link, struct node_rx_pdu **rx, break; case PDU_DATA_LLCTRL_TYPE_START_ENC_REQ: - if (conn->lll.role || - ((conn->llcp_req != conn->llcp_ack) && - (conn->llcp_type != LLCP_ENCRYPTION)) || + if (conn->lll.role || (conn->llcp_req == conn->llcp_ack) || + (conn->llcp_type != LLCP_ENCRYPTION) || !pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_START_ENC_REQ, pdu_rx->len)) { goto ull_conn_rx_unknown_rsp_send; } /* start enc rsp to be scheduled in master prepare */ - conn->llcp.encryption.initiate = 0U; - if (conn->llcp_req == conn->llcp_ack) { - conn->llcp_type = LLCP_ENCRYPTION; - conn->llcp_ack -= 2U; - } + conn->llcp.encryption.state = LLCP_ENC_STATE_INPROG; /* Mark for buffer for release */ (*rx)->hdr.type = NODE_RX_TYPE_DC_PDU_RELEASE; @@ -5219,11 +5261,12 @@ static inline int ctrl_rx(memq_link_t *link, struct node_rx_pdu **rx, } /* start enc rsp to be scheduled in slave prepare */ - conn->llcp.encryption.initiate = 0U; + conn->llcp.encryption.state = LLCP_ENC_STATE_INPROG; if (conn->llcp_req == conn->llcp_ack) { conn->llcp_type = LLCP_ENCRYPTION; conn->llcp_ack -= 2U; } + #else /* CONFIG_BT_CTLR_FAST_ENC */ nack = start_enc_rsp_send(conn, NULL); if (nack) { diff --git a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h index b3366c66e0d..c9924d45f62 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_conn_types.h +++ b/subsys/bluetooth/controller/ll_sw/ull_conn_types.h @@ -119,7 +119,11 @@ struct ll_conn { #if defined(CONFIG_BT_CTLR_LE_ENC) struct { - u8_t initiate; + enum { + LLCP_ENC_STATE_INPROG, + LLCP_ENC_STATE_INIT, + LLCP_ENC_STATE_LTK_WAIT, + } state:2 __packed; u8_t error_code; u8_t skd[16]; } encryption; diff --git a/subsys/bluetooth/controller/ll_sw/ull_slave.c b/subsys/bluetooth/controller/ll_sw/ull_slave.c index eeabe7b7296..82cfd9450c1 100644 --- a/subsys/bluetooth/controller/ll_sw/ull_slave.c +++ b/subsys/bluetooth/controller/ll_sw/ull_slave.c @@ -386,7 +386,6 @@ u8_t ll_start_enc_req_send(u16_t handle, u8_t error_code, u8_t const *const ltk) { struct ll_conn *conn; - u8_t ret; conn = ll_connected_get(handle); if (!conn) { @@ -395,16 +394,13 @@ u8_t ll_start_enc_req_send(u16_t handle, u8_t error_code, if (error_code) { if (conn->llcp_enc.refresh == 0U) { - ret = ull_conn_llcp_req(conn); - if (ret) { - return ret; + if ((conn->llcp_req == conn->llcp_ack) || + (conn->llcp_type != LLCP_ENCRYPTION)) { + return BT_HCI_ERR_CMD_DISALLOWED; } conn->llcp.encryption.error_code = error_code; - conn->llcp.encryption.initiate = 0U; - - conn->llcp_type = LLCP_ENCRYPTION; - conn->llcp_req++; + conn->llcp.encryption.state = LLCP_ENC_STATE_INPROG; } else { if (conn->llcp_terminate.ack != conn->llcp_terminate.req) { @@ -416,18 +412,16 @@ u8_t ll_start_enc_req_send(u16_t handle, u8_t error_code, conn->llcp_terminate.req++; } } else { - ret = ull_conn_llcp_req(conn); - if (ret) { - return ret; + if ((conn->llcp_req == conn->llcp_ack) || + (conn->llcp_type != LLCP_ENCRYPTION)) { + return BT_HCI_ERR_CMD_DISALLOWED; } - memcpy(&conn->llcp_enc.ltk[0], ltk, sizeof(conn->llcp_enc.ltk)); + memcpy(&conn->llcp_enc.ltk[0], ltk, + sizeof(conn->llcp_enc.ltk)); conn->llcp.encryption.error_code = 0U; - conn->llcp.encryption.initiate = 0U; - - conn->llcp_type = LLCP_ENCRYPTION; - conn->llcp_req++; + conn->llcp.encryption.state = LLCP_ENC_STATE_INPROG; } return 0;