diff options
author | William San Filippo <wills@runtime.io> | 2016-04-25 20:06:00 -0700 |
---|---|---|
committer | William San Filippo <wills@runtime.io> | 2016-04-25 20:11:39 -0700 |
commit | 470262a29a9bccfbffbd27b83c139cc109e5c2af (patch) | |
tree | 0b94cf4ecefd7d17590eee58f2210db87955a537 /net | |
parent | 4ad86e91ab5be6693aa13668e7f9f6ef50d72f4c (diff) |
MYNEWT-99: implement encryption pause procedure
This allows keys to be changed on an already encrypted connection.
The code was tested on a bmd300, nrf52dk and also a nrf51. The
nrf51 with encryption enabled was disconnecting and/or getting
MIC failures with large frames; was working fine for small
frames. We are investigating similar issues on the nrf51 so I
do not necessarily believe these to be encryption related which
is why I am committing the changes.
Diffstat (limited to 'net')
-rw-r--r-- | net/nimble/controller/include/controller/ble_ll_conn.h | 3 | ||||
-rw-r--r-- | net/nimble/controller/include/controller/ble_ll_ctrl.h | 4 | ||||
-rw-r--r-- | net/nimble/controller/src/ble_ll_conn.c | 101 | ||||
-rw-r--r-- | net/nimble/controller/src/ble_ll_conn_hci.c | 8 | ||||
-rw-r--r-- | net/nimble/controller/src/ble_ll_ctrl.c | 138 | ||||
-rw-r--r-- | net/nimble/controller/src/ble_ll_hci_ev.c | 27 | ||||
-rw-r--r-- | net/nimble/host/include/host/host_hci.h | 1 | ||||
-rw-r--r-- | net/nimble/host/src/host_dbg.c | 25 | ||||
-rw-r--r-- | net/nimble/host/src/host_hci_cmd.c | 38 | ||||
-rw-r--r-- | net/nimble/include/nimble/hci_common.h | 1 |
10 files changed, 255 insertions, 91 deletions
diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h index f9937aa2..36079c8d 100644 --- a/net/nimble/controller/include/controller/ble_ll_conn.h +++ b/net/nimble/controller/include/controller/ble_ll_conn.h @@ -67,6 +67,7 @@ enum conn_enc_state { CONN_ENC_S_ENC_RSP_WAIT, CONN_ENC_S_START_ENC_REQ_WAIT, CONN_ENC_S_START_ENC_RSP_WAIT, + CONN_ENC_S_PAUSE_ENC_RSP_WAIT, CONN_ENC_S_LTK_REQ_WAIT, CONN_ENC_S_LTK_NEG_REPLY }; @@ -108,6 +109,7 @@ union ble_ll_conn_sm_flags { uint32_t conn_req_txd:1; uint32_t send_ltk_req:1; uint32_t encrypted:1; + uint32_t encrypt_chg_sent; } cfbit; uint32_t conn_flags; } __attribute__((packed)); @@ -255,6 +257,7 @@ struct ble_ll_conn_sm #define CONN_F_LAST_TXD_MD(csm) ((csm)->csmflags.cfbit.last_txd_md) #define CONN_F_CONN_REQ_TXD(csm) ((csm)->csmflags.cfbit.conn_req_txd) #define CONN_F_ENCRYPTED(csm) ((csm)->csmflags.cfbit.encrypted) +#define CONN_F_ENC_CHANGE_SENT(csm) ((csm)->csmflags.cfbit.encrypt_chg_sent) /* Role */ #define CONN_IS_MASTER(csm) (csm->conn_role == BLE_LL_CONN_ROLE_MASTER) diff --git a/net/nimble/controller/include/controller/ble_ll_ctrl.h b/net/nimble/controller/include/controller/ble_ll_ctrl.h index 4a9b1df4..a5cd99bd 100644 --- a/net/nimble/controller/include/controller/ble_ll_ctrl.h +++ b/net/nimble/controller/include/controller/ble_ll_ctrl.h @@ -139,9 +139,6 @@ struct ble_ll_enc_rsp */ #define BLE_LL_CTRL_FEATURE_LEN (8) -/* LL control pause enc req and pause enc rsp have no data */ -#define BLE_LL_CTRL_PAUSE_ENC_LEN (0) - /* * LL control version ind * -> version (1 byte): @@ -237,7 +234,6 @@ int ble_ll_ctrl_start_enc_send(struct ble_ll_conn_sm *connsm, uint8_t opcode); int ble_ll_ctrl_enc_allowed_pdu(struct os_mbuf_pkthdr *pkthdr); int ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm); int ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu); -int ble_ll_ctrl_is_start_enc_req(struct os_mbuf *txpdu); void ble_ll_hci_ev_datalen_chg(struct ble_ll_conn_sm *connsm); void ble_ll_hci_ev_rem_conn_parm_req(struct ble_ll_conn_sm *connsm, diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c index da9acb49..05b2c6cf 100644 --- a/net/nimble/controller/src/ble_ll_conn.c +++ b/net/nimble/controller/src/ble_ll_conn.c @@ -609,6 +609,16 @@ ble_ll_conn_start_rx_encrypt(void *arg) } static void +ble_ll_conn_start_rx_unencrypt(void *arg) +{ + struct ble_ll_conn_sm *connsm; + + connsm = (struct ble_ll_conn_sm *)arg; + CONN_F_ENCRYPTED(connsm) = 0; + ble_phy_encrypt_disable(); +} + +static void ble_ll_conn_txend_encrypt(void *arg) { struct ble_ll_conn_sm *connsm; @@ -620,6 +630,17 @@ ble_ll_conn_txend_encrypt(void *arg) } static void +ble_ll_conn_rxend_unencrypt(void *arg) +{ + struct ble_ll_conn_sm *connsm; + + connsm = (struct ble_ll_conn_sm *)arg; + CONN_F_ENCRYPTED(connsm) = 0; + ble_ll_conn_current_sm_over(); + ble_ll_event_send(&connsm->conn_ev_end); +} + +static void ble_ll_conn_continue_rx_encrypt(void *arg) { struct ble_ll_conn_sm *connsm; @@ -953,14 +974,34 @@ conn_tx_pdu: } #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION - if (ble_ll_ctrl_is_start_enc_rsp(m)) { + int is_ctrl; + uint8_t llid; + uint8_t opcode; + + llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; + if (llid == BLE_LL_LLID_CTRL) { + is_ctrl = 1; + opcode = m->om_data[0]; + } else { + is_ctrl = 0; + } + + if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_RSP)) { + /* + * Both master and slave send the START_ENC_RSP encrypted and receive + * encrypted + */ CONN_F_ENCRYPTED(connsm) = 1; connsm->enc_data.tx_encrypted = 1; ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, connsm->enc_data.iv, connsm->enc_data.enc_block.cipher_text, CONN_IS_MASTER(connsm)); - } else if (ble_ll_ctrl_is_start_enc_req(m)) { + } else if (is_ctrl && (opcode == BLE_LL_CTRL_START_ENC_REQ)) { + /* + * Only the slave sends this and it gets sent unencrypted but + * we receive encrypted + */ CONN_F_ENCRYPTED(connsm) = 0; connsm->enc_data.enc_state = CONN_ENC_S_START_ENC_RSP_WAIT; connsm->enc_data.tx_encrypted = 0; @@ -970,6 +1011,29 @@ conn_tx_pdu: } else { txend_func = ble_ll_conn_txend_encrypt; } + } else if (is_ctrl && (opcode == BLE_LL_CTRL_PAUSE_ENC_RSP)) { + /* + * The slave sends the PAUSE_ENC_RSP encrypted. The master sends + * it unencrypted (note that link was already set unencrypted). + */ + if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + CONN_F_ENCRYPTED(connsm) = 1; + connsm->enc_data.tx_encrypted = 1; + ble_phy_encrypt_enable(connsm->enc_data.tx_pkt_cntr, + connsm->enc_data.iv, + connsm->enc_data.enc_block.cipher_text, + CONN_IS_MASTER(connsm)); + if (txend_func == NULL) { + txend_func = ble_ll_conn_start_rx_unencrypt; + } else { + txend_func = ble_ll_conn_rxend_unencrypt; + } + } else { + CONN_F_ENCRYPTED(connsm) = 0; + connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; + connsm->enc_data.tx_encrypted = 0; + ble_phy_encrypt_disable(); + } } else { /* If encrypted set packet counter */ if (CONN_F_ENCRYPTED(connsm)) { @@ -1043,8 +1107,8 @@ ble_ll_conn_event_start_cb(struct ble_ll_sched_item *sch) ble_ll_state_set(BLE_LL_STATE_CONNECTION); /* Log connection event start */ - ble_ll_log(BLE_LL_LOG_ID_CONN_EV_START, connsm->data_chan_index, - connsm->conn_handle, connsm->ce_end_time); + ble_ll_log(BLE_LL_LOG_ID_CONN_EV_START, (uint8_t)connsm->conn_handle, + (uint16_t)connsm->ce_end_time, connsm->csmflags.conn_flags); /* Set channel */ ble_phy_setchan(connsm->data_chan_index, connsm->access_addr, @@ -2208,7 +2272,6 @@ ble_ll_conn_rx_data_pdu(struct os_mbuf *rxpdu, struct ble_mbuf_hdr *hdr) */ if (BLE_MBUF_HDR_MIC_FAILURE(hdr)) { STATS_INC(ble_ll_conn_stats, mic_failures); - /* Control procedure has timed out. Kill the connection */ ble_ll_conn_timeout(connsm, BLE_ERR_CONN_TERM_MIC); goto conn_rx_data_pdu_end; } @@ -2267,6 +2330,7 @@ int ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa) { int rc; + int is_ctrl; uint8_t hdr_byte; uint8_t hdr_sn; uint8_t hdr_nesn; @@ -2274,6 +2338,7 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa) uint8_t conn_nesn; uint8_t reply; uint8_t rem_bytes; + uint8_t opcode; uint32_t ticks; struct os_mbuf *txpdu; struct ble_ll_conn_sm *connsm; @@ -2443,7 +2508,14 @@ ble_ll_conn_rx_isr_end(struct os_mbuf *rxpdu, uint32_t aa) /* Should we continue connection event? */ /* If this is a TERMINATE_IND, we have to reply */ chk_rx_terminate_ind: - if (ble_ll_ctrl_is_terminate_ind(rxpdu->om_data[0],rxpdu->om_data[2])) { + is_ctrl = 0; + if ((hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) { + is_ctrl = 1; + opcode = rxpdu->om_data[2]; + } + + /* If we received a terminate IND, we must set some flags */ + if (is_ctrl && (opcode == BLE_LL_CTRL_TERMINATE_IND)) { connsm->csmflags.cfbit.terminate_ind_rxd = 1; connsm->rxd_disconnect_reason = rxpdu->om_data[3]; reply = 1; @@ -2452,6 +2524,11 @@ chk_rx_terminate_ind: } else { /* A slave always replies */ reply = 1; +#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION + if (is_ctrl && (opcode == BLE_LL_CTRL_PAUSE_ENC_RSP)) { + connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; + } +#endif } } @@ -2463,6 +2540,8 @@ chk_rx_terminate_ind: * terminate timer will expire within two packet times. If it will, * no use sending the terminate ind. We need to get an ACK for the * terminate ind (master and/or slave) so that is why it is two packets. + * + * XXX: should we just skip this check? */ if (IS_PENDING_CTRL_PROC(connsm, BLE_LL_CTRL_PROC_TERMINATE)) { ticks = BLE_TX_DUR_USECS_M(0) + @@ -2535,12 +2614,15 @@ ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, lifo = 0; #if defined(BLE_LL_CFG_FEAT_LE_ENCRYPTION) if (connsm->enc_data.enc_state > CONN_ENC_S_ENCRYPTED) { + uint8_t llid; + /* * If this is one of the following types we need to insert it at * head of queue. */ ble_hdr = BLE_MBUF_HDR_PTR(om); - if ((ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK) == BLE_LL_LLID_CTRL) { + llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; + if (llid == BLE_LL_LLID_CTRL) { switch (om->om_data[0]) { case BLE_LL_CTRL_TERMINATE_IND: case BLE_LL_CTRL_REJECT_IND: @@ -2549,6 +2631,11 @@ ble_ll_conn_enqueue_pkt(struct ble_ll_conn_sm *connsm, struct os_mbuf *om, case BLE_LL_CTRL_START_ENC_RSP: lifo = 1; break; + case BLE_LL_CTRL_PAUSE_ENC_RSP: + if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + lifo = 1; + } + break; default: break; } diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c index 28028665..791fe4ab 100644 --- a/net/nimble/controller/src/ble_ll_conn_hci.c +++ b/net/nimble/controller/src/ble_ll_conn_hci.c @@ -936,8 +936,14 @@ ble_ll_conn_hci_le_start_encrypt(uint8_t *cmdbuf) rc = BLE_ERR_UNK_CONN_ID; } else if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { rc = BLE_ERR_UNSPECIFIED; + } else if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { + /* + * The specification does not say what to do here but the host should + * not be telling us to start encryption while we are in the process + * of honoring a previous start encrypt. + */ + rc = BLE_ERR_CMD_DISALLOWED; } else { - /* XXX: implement pause procedure */ /* Start the control procedure */ connsm->enc_data.host_rand_num = le64toh(cmdbuf + 2); connsm->enc_data.enc_div = le16toh(cmdbuf + 10); diff --git a/net/nimble/controller/src/ble_ll_ctrl.c b/net/nimble/controller/src/ble_ll_ctrl.c index 63b4c98c..e72e0f91 100644 --- a/net/nimble/controller/src/ble_ll_ctrl.c +++ b/net/nimble/controller/src/ble_ll_ctrl.c @@ -367,6 +367,19 @@ ble_ll_calc_session_key(struct ble_ll_conn_sm *connsm) #endif } +/** + * Called to determine if this is a control PDU we are allowed to send. This + * is called when a link is being encrypted, as only certain control PDU's + * area lowed to be sent. + * + * XXX: the current code may actually allow some control pdu's to be sent + * in states where they shouldnt. I dont expect those states to occur so I + * dont try to check for them but we could do more... + * + * @param pkthdr + * + * @return int + */ int ble_ll_ctrl_enc_allowed_pdu(struct os_mbuf_pkthdr *pkthdr) { @@ -390,6 +403,8 @@ ble_ll_ctrl_enc_allowed_pdu(struct os_mbuf_pkthdr *pkthdr) case BLE_LL_CTRL_START_ENC_REQ: case BLE_LL_CTRL_ENC_REQ: case BLE_LL_CTRL_ENC_RSP: + case BLE_LL_CTRL_PAUSE_ENC_REQ: + case BLE_LL_CTRL_PAUSE_ENC_RSP: case BLE_LL_CTRL_TERMINATE_IND: allowed = 1; break; @@ -423,28 +438,6 @@ ble_ll_ctrl_is_start_enc_rsp(struct os_mbuf *txpdu) return is_start_enc_rsp; } -int -ble_ll_ctrl_is_start_enc_req(struct os_mbuf *txpdu) -{ - int is_start_enc_req; - uint8_t opcode; - uint8_t llid; - struct ble_mbuf_hdr *ble_hdr; - - is_start_enc_req = 0; - ble_hdr = BLE_MBUF_HDR_PTR(txpdu); - - llid = ble_hdr->txinfo.hdr_byte & BLE_LL_DATA_HDR_LLID_MASK; - if (llid == BLE_LL_LLID_CTRL) { - opcode = txpdu->om_data[0]; - if (opcode == BLE_LL_CTRL_START_ENC_REQ) { - is_start_enc_req = 1; - } - } - - return is_start_enc_req; -} - /** * Called to create and send a LL_START_ENC_REQ or LL_START_ENC_RSP * @@ -532,6 +525,11 @@ ble_ll_ctrl_rx_enc_rsp(struct ble_ll_conn_sm *connsm, uint8_t *dptr) { /* Calculate session key now that we have received the ENC_RSP */ if (connsm->cur_ctrl_proc == BLE_LL_CTRL_PROC_ENCRYPT) { + /* In case we were already encrypted we need to reset packet counters */ + connsm->enc_data.rx_pkt_cntr = 0; + connsm->enc_data.tx_pkt_cntr = 0; + connsm->enc_data.tx_encrypted = 0; + swap_buf(connsm->enc_data.enc_block.plain_text, dptr, 8); memcpy(connsm->enc_data.iv + 4, dptr + 8, 4); ble_ll_calc_session_key(connsm); @@ -568,6 +566,11 @@ ble_ll_ctrl_rx_enc_req(struct ble_ll_conn_sm *connsm, uint8_t *dptr, return BLE_ERR_MAX; } + /* In case we were already encrypted we need to reset packet counters */ + connsm->enc_data.rx_pkt_cntr = 0; + connsm->enc_data.tx_pkt_cntr = 0; + connsm->enc_data.tx_encrypted = 0; + /* Extract information from request */ connsm->enc_data.host_rand_num = le64toh(dptr); connsm->enc_data.enc_div = le16toh(dptr + 8); @@ -612,6 +615,46 @@ ble_ll_ctrl_rx_start_enc_req(struct ble_ll_conn_sm *connsm) return rc; } +static uint8_t +ble_ll_ctrl_rx_pause_enc_req(struct ble_ll_conn_sm *connsm) +{ + int rc; + + /* + * The spec does not say what to do here, but if we receive a pause + * encryption request and we are not encrypted, what do we do? We + * ignore it... + */ + rc = BLE_ERR_MAX; + if ((connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) && + (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED)) { + rc = BLE_LL_CTRL_PAUSE_ENC_RSP; + } + + return rc; +} + +/** + * Called when a LL control pdu with opcode PAUSE_ENC_RSP is received. + * + * + * @param connsm + * + * @return uint8_t + */ +static uint8_t +ble_ll_ctrl_rx_pause_enc_rsp(struct ble_ll_conn_sm *connsm) +{ + int rc; + + rc = BLE_ERR_MAX; + if (connsm->conn_role == BLE_LL_CONN_ROLE_MASTER) { + rc = BLE_LL_CTRL_PAUSE_ENC_RSP; + } + + return rc; +} + /** * Called when we have received a LL_CTRL_START_ENC_RSP. * @@ -1238,8 +1281,13 @@ ble_ll_ctrl_proc_init(struct ble_ll_conn_sm *connsm, int ctrl_proc) #if defined(BLE_LL_CFG_FEAT_LE_ENCRYPTION) /* XXX: deal with already encrypted connection.*/ case BLE_LL_CTRL_PROC_ENCRYPT: - opcode = BLE_LL_CTRL_ENC_REQ; - ble_ll_ctrl_enc_req_make(connsm, ctrdata); + /* If we are already encrypted we do pause procedure */ + if (connsm->enc_data.enc_state == CONN_ENC_S_ENCRYPTED) { + opcode = BLE_LL_CTRL_PAUSE_ENC_REQ; + } else { + opcode = BLE_LL_CTRL_ENC_REQ; + ble_ll_ctrl_enc_req_make(connsm, ctrdata); + } break; #endif default: @@ -1427,6 +1475,8 @@ ble_ll_ctrl_chk_proc_start(struct ble_ll_conn_sm *connsm) * NOTE: this function uses the received PDU for the response in some cases. If * the received PDU is not used it needs to be freed here. * + * XXX: may want to check, for both master and slave, whether the control + * pdu should be received by that role. Might make for less code... * Context: Link Layer * * @param om @@ -1443,6 +1493,9 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) uint8_t *dptr; uint8_t *rspbuf; uint8_t *rspdata; +#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION + int restart_encryption; +#endif /* XXX: where do we validate length received and packet header length? * do this in LL task when received. Someplace!!! What I mean @@ -1477,13 +1530,17 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) */ --len; + ble_ll_log(BLE_LL_LOG_ID_LL_CTRL_RX, opcode, len, 0); + /* opcode must be good */ if ((opcode >= BLE_LL_CTRL_OPCODES) || (len != g_ble_ll_ctrl_pkt_lengths[opcode])) { goto rx_malformed_ctrl; } - ble_ll_log(BLE_LL_LOG_ID_LL_CTRL_RX, opcode, len, 0); +#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION + restart_encryption = 0; +#endif /* Check if the feature is supported. */ switch (opcode) { @@ -1529,7 +1586,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) } /* Process opcode */ - rsp_opcode = 255; + rsp_opcode = BLE_ERR_MAX; switch (opcode) { case BLE_LL_CTRL_CONN_UPDATE_REQ: rsp_opcode = ble_ll_ctrl_rx_conn_update(connsm, dptr, rspbuf); @@ -1589,7 +1646,7 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) case BLE_LL_CTRL_SLAVE_FEATURE_REQ: rsp_opcode = ble_ll_ctrl_rx_feature_req(connsm, dptr, rspbuf, opcode); break; -#if defined(BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION case BLE_LL_CTRL_ENC_REQ: rsp_opcode = ble_ll_ctrl_rx_enc_req(connsm, dptr, rspdata); break; @@ -1599,13 +1656,17 @@ ble_ll_ctrl_rx_pdu(struct ble_ll_conn_sm *connsm, struct os_mbuf *om) case BLE_LL_CTRL_START_ENC_REQ: rsp_opcode = ble_ll_ctrl_rx_start_enc_req(connsm); break; - case BLE_LL_CTRL_START_ENC_RSP: rsp_opcode = ble_ll_ctrl_rx_start_enc_rsp(connsm); break; - case BLE_LL_CTRL_PAUSE_ENC_REQ: - /* XXX: implement */ + rsp_opcode = ble_ll_ctrl_rx_pause_enc_req(connsm); + break; + case BLE_LL_CTRL_PAUSE_ENC_RSP: + rsp_opcode = ble_ll_ctrl_rx_pause_enc_rsp(connsm); + if (rsp_opcode == BLE_LL_CTRL_PAUSE_ENC_RSP) { + restart_encryption = 1; + } break; #endif case BLE_LL_CTRL_PING_REQ: @@ -1643,6 +1704,13 @@ ll_ctrl_send_rsp: } len = g_ble_ll_ctrl_pkt_lengths[rsp_opcode] + 1; ble_ll_conn_enqueue_pkt(connsm, om, BLE_LL_LLID_CTRL, len); +#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION + if (restart_encryption) { + /* XXX: what happens if this fails? Meaning we cant allocate + mbuf? */ + ble_ll_ctrl_proc_init(connsm, BLE_LL_CTRL_PROC_ENCRYPT); + } +#endif } return 0; @@ -1732,11 +1800,13 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) #endif break; case BLE_LL_CTRL_REJECT_IND: -#if defined (BLE_LL_CFG_FEAT_LE_ENCRYPTION) +#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION connsm->enc_data.enc_state = CONN_ENC_S_UNENCRYPTED; #endif break; #if defined (BLE_LL_CFG_FEAT_LE_ENCRYPTION) + case BLE_LL_CTRL_PAUSE_ENC_REQ: + /* note: fall-through intentional */ case BLE_LL_CTRL_ENC_REQ: connsm->enc_data.enc_state = CONN_ENC_S_ENC_RSP_WAIT; break; @@ -1745,11 +1815,15 @@ ble_ll_ctrl_tx_done(struct os_mbuf *txpdu, struct ble_ll_conn_sm *connsm) connsm->csmflags.cfbit.send_ltk_req = 1; break; case BLE_LL_CTRL_START_ENC_RSP: - /* We are encrypted */ if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { connsm->enc_data.enc_state = CONN_ENC_S_ENCRYPTED; } break; + case BLE_LL_CTRL_PAUSE_ENC_RSP: + if (connsm->conn_role == BLE_LL_CONN_ROLE_SLAVE) { + connsm->enc_data.enc_state = CONN_ENC_S_PAUSE_ENC_RSP_WAIT; + } + break; #endif default: break; diff --git a/net/nimble/controller/src/ble_ll_hci_ev.c b/net/nimble/controller/src/ble_ll_hci_ev.c index d35d59b2..ed0f1ba5 100644 --- a/net/nimble/controller/src/ble_ll_hci_ev.c +++ b/net/nimble/controller/src/ble_ll_hci_ev.c @@ -114,23 +114,36 @@ ble_ll_hci_ev_conn_update(struct ble_ll_conn_sm *connsm, uint8_t status) void ble_ll_hci_ev_encrypt_chg(struct ble_ll_conn_sm *connsm, uint8_t status) { + uint8_t evcode; uint8_t *evbuf; + uint8_t evlen; - if (ble_ll_hci_is_event_enabled(BLE_HCI_EVCODE_ENCRYPT_CHG)) { + if (CONN_F_ENC_CHANGE_SENT(connsm) == 0) { + evcode = BLE_HCI_EVCODE_ENCRYPT_CHG; + evlen = BLE_HCI_EVENT_ENCRYPT_CHG_LEN; + } else { + evcode = BLE_HCI_EVCODE_ENC_KEY_REFRESH; + evlen = BLE_HCI_EVENT_ENC_KEY_REFRESH_LEN; + } + + if (ble_ll_hci_is_event_enabled(evcode)) { evbuf = os_memblock_get(&g_hci_cmd_pool); if (evbuf) { - evbuf[0] = BLE_HCI_EVCODE_ENCRYPT_CHG; - evbuf[1] = BLE_HCI_EVENT_ENCRYPT_CHG_LEN; + evbuf[0] = evcode; + evbuf[1] = evlen; evbuf[2] = status; htole16(evbuf + 3, connsm->conn_handle); - if (status == BLE_ERR_SUCCESS) { - evbuf[5] = 0x01; - } else { - evbuf[5] = 0; + if (evcode == BLE_HCI_EVCODE_ENCRYPT_CHG) { + if (status == BLE_ERR_SUCCESS) { + evbuf[5] = 0x01; + } else { + evbuf[5] = 0; + } } ble_ll_hci_event_send(evbuf); } } + CONN_F_ENC_CHANGE_SENT(connsm) = 1; } /** diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h index e8fab80c..c7d12228 100644 --- a/net/nimble/host/include/host/host_hci.h +++ b/net/nimble/host/include/host/host_hci.h @@ -78,7 +78,6 @@ int host_hci_cmd_build_le_conn_update(struct hci_conn_update *hcu, int host_hci_cmd_le_conn_update(struct hci_conn_update *hcu); void host_hci_cmd_build_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr, uint8_t *dst, int dst_len); -int host_hci_cmd_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr); int host_hci_cmd_le_lt_key_req_neg_reply(uint16_t handle); void host_hci_cmd_build_le_conn_param_reply(struct hci_conn_param_reply *hcr, uint8_t *dst, int dst_len); diff --git a/net/nimble/host/src/host_dbg.c b/net/nimble/host/src/host_dbg.c index d9e8af61..f8c9a431 100644 --- a/net/nimble/host/src/host_dbg.c +++ b/net/nimble/host/src/host_dbg.c @@ -164,7 +164,7 @@ host_hci_dbg_disconn_comp_disp(uint8_t *evdata, uint8_t len) } /** - * Display an encryption change event. + * Display an encryption change event or encryption key refresh event * * @param evdata * @param len @@ -178,6 +178,7 @@ host_hci_dbg_encrypt_chg_disp(uint8_t *evdata, uint8_t len) status = evdata[0]; handle = le16toh(evdata + 1); + /* Ignore reason if status is not success */ if (status != BLE_ERR_SUCCESS) { enabled = 0; @@ -189,6 +190,25 @@ host_hci_dbg_encrypt_chg_disp(uint8_t *evdata, uint8_t len) } /** + * Display an encryption encryption key refresh event + * + * @param evdata + * @param len + */ +static void +host_hci_dbg_encrypt_refresh_disp(uint8_t *evdata, uint8_t len) +{ + uint8_t status; + uint16_t handle; + + status = evdata[0]; + handle = le16toh(evdata + 1); + + BLE_HS_LOG(DEBUG, "Encrypt key refresh: status=%u handle=%u\n", + status, handle); +} + +/** * Display a version information event * * @param evdata @@ -403,6 +423,9 @@ host_hci_dbg_event_disp(uint8_t *evbuf) case BLE_HCI_EVCODE_DISCONN_CMP: host_hci_dbg_disconn_comp_disp(evdata, len); break; + case BLE_HCI_EVCODE_ENC_KEY_REFRESH: + host_hci_dbg_encrypt_refresh_disp(evdata, len); + break; case BLE_HCI_EVCODE_ENCRYPT_CHG: host_hci_dbg_encrypt_chg_disp(evdata, len); break; diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/host_hci_cmd.c index 8a923ae4..16d6536f 100644 --- a/net/nimble/host/src/host_hci_cmd.c +++ b/net/nimble/host/src/host_hci_cmd.c @@ -809,32 +809,6 @@ host_hci_cmd_build_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr, host_hci_cmd_body_le_lt_key_req_reply(hkr, dst); } -/** - * Sends the long-term key (LTK) to the controller. - * - * Note: This function expects the 128-bit key to be in little-endian byte - * order. - * - * OGF = 0x08 (LE) - * OCF = 0x001a - * - * @param key - * @param pt - * - * @return int - */ -int -host_hci_cmd_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr) -{ - uint8_t cmd[BLE_HCI_LT_KEY_REQ_REPLY_LEN]; - int rc; - - host_hci_cmd_body_le_lt_key_req_reply(hkr, cmd); - rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY, - sizeof cmd, cmd); - return rc; -} - static void host_hci_cmd_body_le_conn_param_reply(struct hci_conn_param_reply *hcr, uint8_t *dst) @@ -863,18 +837,6 @@ host_hci_cmd_build_le_conn_param_reply(struct hci_conn_param_reply *hcr, } int -host_hci_cmd_le_lt_key_req_neg_reply(uint16_t handle) -{ - uint8_t cmd[sizeof(uint16_t)]; - int rc; - - htole16(cmd, handle); - rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY, - sizeof(uint16_t), cmd); - return rc; -} - -int host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr) { uint8_t cmd[BLE_HCI_CONN_PARAM_REPLY_LEN]; diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h index 50d61422..e5c3e2ca 100644 --- a/net/nimble/include/nimble/hci_common.h +++ b/net/nimble/include/nimble/hci_common.h @@ -452,6 +452,7 @@ /* Event encryption change (code=0x08) */ #define BLE_HCI_EVENT_ENCRYPT_CHG_LEN (4) +#define BLE_HCI_EVENT_ENC_KEY_REFRESH_LEN (3) /* Event command complete */ #define BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN (5) |