From 7dd5fbee26fc548e94bc708af992e1ce55a29ac1 Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Wed, 1 Nov 2017 14:18:25 +0100 Subject: [PATCH] Bluetooth: controller: Fix MIC error due to parallel Enc Proc Fix to disallow initiating LE Start Encryption while another procedure is in progress. Similarly, disallow initiating another procedure while Encryption procedure is in progress. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/ll_sw/ctrl.c | 214 ++++++++++-------- .../controller/ll_sw/ctrl_internal.h | 1 + 2 files changed, 116 insertions(+), 99 deletions(-) diff --git a/subsys/bluetooth/controller/ll_sw/ctrl.c b/subsys/bluetooth/controller/ll_sw/ctrl.c index 6b912243ab0..1bfe0228da8 100644 --- a/subsys/bluetooth/controller/ll_sw/ctrl.c +++ b/subsys/bluetooth/controller/ll_sw/ctrl.c @@ -2470,10 +2470,12 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *radio_pdu_node_rx, break; case PDU_DATA_LLCTRL_TYPE_START_ENC_REQ: - LL_ASSERT(_radio.conn_curr->llcp_req == - _radio.conn_curr->llcp_ack); + LL_ASSERT((_radio.conn_curr->llcp_req == + _radio.conn_curr->llcp_ack) || + (_radio.conn_curr->llcp_type == LLCP_ENCRYPTION)); /* start enc rsp to be scheduled in master prepare */ + _radio.conn_curr->llcp.encryption.initiate = 0; _radio.conn_curr->llcp_type = LLCP_ENCRYPTION; _radio.conn_curr->llcp_ack--; break; @@ -2481,10 +2483,13 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *radio_pdu_node_rx, case PDU_DATA_LLCTRL_TYPE_START_ENC_RSP: if (_radio.role == ROLE_SLAVE) { #if !defined(CONFIG_BT_CTLR_FAST_ENC) - LL_ASSERT(_radio.conn_curr->llcp_req == - _radio.conn_curr->llcp_ack); + LL_ASSERT((_radio.conn_curr->llcp_req == + _radio.conn_curr->llcp_ack) || + (_radio.conn_curr->llcp_type == + LLCP_ENCRYPTION)); /* start enc rsp to be scheduled in slave prepare */ + _radio.conn_curr->llcp.encryption.initiate = 0; _radio.conn_curr->llcp_type = LLCP_ENCRYPTION; _radio.conn_curr->llcp_ack--; #else /* CONFIG_BT_CTLR_FAST_ENC */ @@ -6675,21 +6680,89 @@ static inline void event_enc_reject_prep(struct connection *conn, static inline void event_enc_prep(struct connection *conn) { struct radio_pdu_node_tx *node_tx; + struct pdu_data *pdu_ctrl_tx; + + if (conn->llcp.encryption.initiate) { + return; + } node_tx = mem_acquire(&_radio.pkt_tx_ctrl_free); - if (node_tx) { - struct pdu_data *pdu_ctrl_tx = - (struct pdu_data *)node_tx->pdu_data; + if (!node_tx) { + return; + } + + pdu_ctrl_tx = (void *)node_tx->pdu_data; + + /* master sends encrypted enc start rsp in control priority */ + if (!conn->role) { + /* calc the Session Key */ + ecb_encrypt(&conn->llcp.encryption.ltk[0], + &conn->llcp.encryption.skd[0], + NULL, &conn->ccm_rx.key[0]); + + /* copy the Session Key */ + memcpy(&conn->ccm_tx.key[0], &conn->ccm_rx.key[0], + sizeof(conn->ccm_tx.key)); + + /* copy the IV */ + memcpy(&conn->ccm_tx.iv[0], &conn->ccm_rx.iv[0], + sizeof(conn->ccm_tx.iv)); + + /* initialise counter */ + conn->ccm_rx.counter = 0; + conn->ccm_tx.counter = 0; + + /* set direction: slave to master = 0, + * master to slave = 1 + */ + conn->ccm_rx.direction = 0; + conn->ccm_tx.direction = 1; + + /* enable receive encryption */ + conn->enc_rx = 1; + + /* send enc start resp */ + start_enc_rsp_send(conn, pdu_ctrl_tx); + } + + /* slave send reject ind or start enc req at control priority */ + +#if defined(CONFIG_BT_CTLR_FAST_ENC) + else { +#else /* !CONFIG_BT_CTLR_FAST_ENC */ + else if (!conn->pause_tx || conn->refresh) { +#endif /* !CONFIG_BT_CTLR_FAST_ENC */ + + /* place the reject ind packet as next in tx queue */ + if (conn->llcp.encryption.error_code) { + event_enc_reject_prep(conn, pdu_ctrl_tx); + } + /* 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(node_tx, &_radio.pkt_tx_ctrl_free); + + return; + } +#endif /* !CONFIG_BT_CTLR_FAST_ENC */ - /* master sends encrypted enc start rsp in control priority */ - if (!conn->role) { /* calc the Session Key */ ecb_encrypt(&conn->llcp.encryption.ltk[0], - &conn->llcp.encryption.skd[0], - NULL, &conn->ccm_rx.key[0]); + &conn->llcp.encryption.skd[0], NULL, + &conn->ccm_rx.key[0]); /* copy the Session Key */ - memcpy(&conn->ccm_tx.key[0], &conn->ccm_rx.key[0], + memcpy(&conn->ccm_tx.key[0], + &conn->ccm_rx.key[0], sizeof(conn->ccm_tx.key)); /* copy the IV */ @@ -6703,102 +6776,38 @@ static inline void event_enc_prep(struct connection *conn) /* set direction: slave to master = 0, * master to slave = 1 */ - conn->ccm_rx.direction = 0; - conn->ccm_tx.direction = 1; + conn->ccm_rx.direction = 1; + conn->ccm_tx.direction = 0; - /* enable receive encryption */ + /* enable receive encryption (transmit turned + * on when start enc resp from master is + * received) + */ conn->enc_rx = 1; - /* send enc start resp */ - start_enc_rsp_send(conn, pdu_ctrl_tx); + /* prepare the start enc req */ + pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL; + pdu_ctrl_tx->len = offsetof(struct pdu_data_llctrl, + ctrldata); + pdu_ctrl_tx->payload.llctrl.opcode = + PDU_DATA_LLCTRL_TYPE_START_ENC_REQ; } - /* slave send reject ind or start enc req at control priority */ - -#if defined(CONFIG_BT_CTLR_FAST_ENC) - else { -#else /* !CONFIG_BT_CTLR_FAST_ENC */ - else if (!conn->pause_tx || conn->refresh) { -#endif /* !CONFIG_BT_CTLR_FAST_ENC */ - - /* place the reject ind packet as next in tx queue */ - if (conn->llcp.encryption.error_code) { - event_enc_reject_prep(conn, pdu_ctrl_tx); - } - /* place the start enc req packet as next in tx queue */ - else { - #if !defined(CONFIG_BT_CTLR_FAST_ENC) - u8_t err; + } else { + start_enc_rsp_send(_radio.conn_curr, pdu_ctrl_tx); - /* 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(node_tx, - &_radio.pkt_tx_ctrl_free); - - return; - } + /* resume data packet rx and tx */ + _radio.conn_curr->pause_rx = 0; + _radio.conn_curr->pause_tx = 0; #endif /* !CONFIG_BT_CTLR_FAST_ENC */ - /* calc the Session Key */ - ecb_encrypt(&conn->llcp.encryption.ltk[0], - &conn->llcp.encryption.skd[0], NULL, - &conn->ccm_rx.key[0]); - - /* copy the Session Key */ - memcpy(&conn->ccm_tx.key[0], - &conn->ccm_rx.key[0], - sizeof(conn->ccm_tx.key)); - - /* copy the IV */ - memcpy(&conn->ccm_tx.iv[0], &conn->ccm_rx.iv[0], - sizeof(conn->ccm_tx.iv)); - - /* initialise counter */ - conn->ccm_rx.counter = 0; - conn->ccm_tx.counter = 0; - - /* set direction: slave to master = 0, - * master to slave = 1 - */ - conn->ccm_rx.direction = 1; - conn->ccm_tx.direction = 0; - - /* enable receive encryption (transmit turned - * on when start enc resp from master is - * received) - */ - conn->enc_rx = 1; - - /* prepare the start enc req */ - pdu_ctrl_tx->ll_id = PDU_DATA_LLID_CTRL; - pdu_ctrl_tx->len = - offsetof(struct pdu_data_llctrl, - ctrldata); - pdu_ctrl_tx->payload.llctrl.opcode = - PDU_DATA_LLCTRL_TYPE_START_ENC_REQ; - } - -#if !defined(CONFIG_BT_CTLR_FAST_ENC) - } else { - start_enc_rsp_send(_radio.conn_curr, pdu_ctrl_tx); - - /* resume data packet rx and tx */ - _radio.conn_curr->pause_rx = 0; - _radio.conn_curr->pause_tx = 0; -#endif /* !CONFIG_BT_CTLR_FAST_ENC */ - - } - - ctrl_tx_enqueue(conn, node_tx); - - /* procedure request acked */ - conn->llcp_ack = conn->llcp_req; } + + ctrl_tx_enqueue(conn, node_tx); + + /* procedure request acked */ + conn->llcp_ack = conn->llcp_req; } #endif /* CONFIG_BT_CTLR_LE_ENC */ @@ -10481,7 +10490,7 @@ u32_t ll_enc_req_send(u16_t handle, u8_t *rand, u8_t *ediv, u8_t *ltk) struct radio_pdu_node_tx *node_tx; conn = connection_get(handle); - if (!conn) { + if (!conn || (conn->llcp_req != conn->llcp_ack)) { return 1; } @@ -10534,6 +10543,11 @@ u32_t ll_enc_req_send(u16_t handle, u8_t *rand, u8_t *ediv, u8_t *ltk) return 1; } + conn->llcp.encryption.initiate = 1; + + conn->llcp_type = LLCP_ENCRYPTION; + conn->llcp_req++; + return 0; } @@ -10557,6 +10571,7 @@ u32_t ll_start_enc_req_send(u16_t handle, u8_t error_code, } conn->llcp.encryption.error_code = error_code; + conn->llcp.encryption.initiate = 0; conn->llcp_type = LLCP_ENCRYPTION; conn->llcp_req++; @@ -10579,6 +10594,7 @@ u32_t ll_start_enc_req_send(u16_t handle, u8_t error_code, } conn->llcp.encryption.error_code = 0; + conn->llcp.encryption.initiate = 0; conn->llcp_type = LLCP_ENCRYPTION; conn->llcp_req++; diff --git a/subsys/bluetooth/controller/ll_sw/ctrl_internal.h b/subsys/bluetooth/controller/ll_sw/ctrl_internal.h index cf2b192c336..b4af3795dc4 100644 --- a/subsys/bluetooth/controller/ll_sw/ctrl_internal.h +++ b/subsys/bluetooth/controller/ll_sw/ctrl_internal.h @@ -165,6 +165,7 @@ struct connection { #endif /* CONFIG_BT_CTLR_PHY */ struct { + u8_t initiate; u8_t error_code; u8_t rand[8]; u8_t ediv[2];