Bluetooth: controller: legacy: 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 <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2019-10-21 19:43:09 +05:30 committed by Anas Nashif
commit 3805290055
2 changed files with 91 additions and 41 deletions

View file

@ -2766,7 +2766,30 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
if (nack) {
break;
}
#endif /* CONFIG_BT_CTLR_FAST_ENC */
/* enqueue the enc req */
*rx_enqueue = 1U;
/* Start Enc Req to be scheduled by LL api */
_radio.conn_curr->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(&_radio.conn_curr->llcp_enc.rand[0],
&pdu_data_rx->llctrl.enc_req.rand[0],
sizeof(_radio.conn_curr->llcp_enc.rand));
_radio.conn_curr->llcp_enc.ediv[0] =
pdu_data_rx->llctrl.enc_req.ediv[0];
_radio.conn_curr->llcp_enc.ediv[1] =
pdu_data_rx->llctrl.enc_req.ediv[1];
/* Enc rsp to be scheduled in master prepare */
_radio.conn_curr->llcp.encryption.state = LLCP_ENC_STATE_INIT;
#endif /* !CONFIG_BT_CTLR_FAST_ENC */
/* Enc Setup requested */
_radio.conn_curr->llcp_type = LLCP_ENCRYPTION;
_radio.conn_curr->llcp_ack--;
/* things from master stored for session key calculation */
memcpy(&_radio.conn_curr->llcp.encryption.skd[0],
@ -2782,9 +2805,6 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
*/
_radio.conn_curr->procedure_expire =
_radio.conn_curr->procedure_reload;
/* enqueue the enc req */
*rx_enqueue = 1U;
break;
case PDU_DATA_LLCTRL_TYPE_ENC_RSP:
@ -2806,18 +2826,16 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
case PDU_DATA_LLCTRL_TYPE_START_ENC_REQ:
if (_radio.conn_curr->role ||
((_radio.conn_curr->llcp_req !=
_radio.conn_curr->llcp_ack) &&
(_radio.conn_curr->llcp_type != LLCP_ENCRYPTION)) ||
(_radio.conn_curr->llcp_req ==
_radio.conn_curr->llcp_ack) ||
(_radio.conn_curr->llcp_type != LLCP_ENCRYPTION) ||
!pdu_len_cmp(PDU_DATA_LLCTRL_TYPE_START_ENC_REQ,
pdu_data_rx->len)) {
goto isr_rx_conn_unknown_rsp_send;
}
/* start enc rsp to be scheduled in master prepare */
_radio.conn_curr->llcp.encryption.initiate = 0U;
_radio.conn_curr->llcp_type = LLCP_ENCRYPTION;
_radio.conn_curr->llcp_ack--;
_radio.conn_curr->llcp.encryption.state = LLCP_ENC_STATE_INPROG;
break;
case PDU_DATA_LLCTRL_TYPE_START_ENC_RSP:
@ -2835,7 +2853,8 @@ isr_rx_conn_pkt_ctrl(struct radio_pdu_node_rx *node_rx,
}
/* start enc rsp to be scheduled in slave prepare */
_radio.conn_curr->llcp.encryption.initiate = 0U;
_radio.conn_curr->llcp.encryption.state =
LLCP_ENC_STATE_INPROG;
_radio.conn_curr->llcp_type = LLCP_ENCRYPTION;
_radio.conn_curr->llcp_ack--;
#else /* CONFIG_BT_CTLR_FAST_ENC */
@ -7671,7 +7690,54 @@ 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) {
if (conn->llcp.encryption.state) {
#if !defined(CONFIG_BT_CTLR_FAST_ENC) && defined(CONFIG_BT_PERIPHERAL)
if (conn->role &&
(conn->llcp.encryption.state == LLCP_ENC_STATE_INIT)) {
struct radio_pdu_node_rx *node_rx;
struct pdu_data *pdu_ctrl_rx;
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;
}
/* Prepare the rx packet structure */
node_rx = packet_rx_reserve_get(2);
LL_ASSERT(node_rx);
node_rx->hdr.handle = conn->handle;
node_rx->hdr.type = NODE_RX_TYPE_DC_PDU;
/* prepare enc req structure */
pdu_ctrl_rx = (void *)node_rx->pdu_data;
pdu_ctrl_rx->ll_id = PDU_DATA_LLID_CTRL;
pdu_ctrl_rx->len =
offsetof(struct pdu_data_llctrl, enc_req) +
sizeof(struct pdu_data_llctrl_enc_req);
pdu_ctrl_rx->llctrl.opcode =
PDU_DATA_LLCTRL_TYPE_ENC_REQ;
memcpy(&pdu_ctrl_rx->llctrl.enc_req.rand[0],
&conn->llcp_enc.rand[0],
sizeof(pdu_ctrl_rx->llctrl.enc_req.rand));
pdu_ctrl_rx->llctrl.enc_req.ediv[0] =
conn->llcp_enc.ediv[0];
pdu_ctrl_rx->llctrl.enc_req.ediv[1] =
conn->llcp_enc.ediv[1];
/* enqueue enc req structure into rx queue */
packet_rx_enqueue();
/* Wait for LTK reply */
conn->llcp.encryption.state = LLCP_ENC_STATE_LTK_WAIT;
}
#endif /* !CONFIG_BT_CTLR_FAST_ENC && CONFIG_BT_PERIPHERAL */
return;
}
@ -7719,7 +7785,7 @@ static inline void event_enc_prep(struct connection *conn)
#if defined(CONFIG_BT_CTLR_FAST_ENC)
else {
#else /* !CONFIG_BT_CTLR_FAST_ENC */
else if (!conn->pause_tx || conn->refresh) {
else if (!conn->enc_rx) {
#endif /* !CONFIG_BT_CTLR_FAST_ENC */
/* place the reject ind packet as next in tx queue */
@ -7728,22 +7794,6 @@ static inline void event_enc_prep(struct connection *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(node_tx, &_radio.pkt_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,
@ -9912,7 +9962,7 @@ static bool is_enc_req_pause_tx(struct connection *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--;
@ -12279,15 +12329,13 @@ u8_t ll_start_enc_req_send(u16_t handle, u8_t error_code,
if (error_code) {
if (conn->refresh == 0) {
if (conn->llcp_req != conn->llcp_ack) {
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) {
@ -12299,7 +12347,8 @@ u8_t ll_start_enc_req_send(u16_t handle, u8_t error_code,
conn->llcp_terminate.req++;
}
} else {
if (conn->llcp_req != conn->llcp_ack) {
if ((conn->llcp_req == conn->llcp_ack) ||
(conn->llcp_type != LLCP_ENCRYPTION)) {
return BT_HCI_ERR_CMD_DISALLOWED;
}
@ -12307,10 +12356,7 @@ u8_t ll_start_enc_req_send(u16_t handle, u8_t error_code,
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;

View file

@ -159,7 +159,11 @@ struct connection {
#if defined(CONFIG_BT_CTLR_LE_ENC)
struct {
u8_t initiate:1;
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;