summaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
authorWilliam San Filippo <wills@runtime.io>2016-04-25 20:06:00 -0700
committerWilliam San Filippo <wills@runtime.io>2016-04-25 20:11:39 -0700
commit470262a29a9bccfbffbd27b83c139cc109e5c2af (patch)
tree0b94cf4ecefd7d17590eee58f2210db87955a537 /net
parent4ad86e91ab5be6693aa13668e7f9f6ef50d72f4c (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.h3
-rw-r--r--net/nimble/controller/include/controller/ble_ll_ctrl.h4
-rw-r--r--net/nimble/controller/src/ble_ll_conn.c101
-rw-r--r--net/nimble/controller/src/ble_ll_conn_hci.c8
-rw-r--r--net/nimble/controller/src/ble_ll_ctrl.c138
-rw-r--r--net/nimble/controller/src/ble_ll_hci_ev.c27
-rw-r--r--net/nimble/host/include/host/host_hci.h1
-rw-r--r--net/nimble/host/src/host_dbg.c25
-rw-r--r--net/nimble/host/src/host_hci_cmd.c38
-rw-r--r--net/nimble/include/nimble/hci_common.h1
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)