mynewt-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From w...@apache.org
Subject [1/2] incubator-mynewt-core git commit: MYNEWT-99: implement encryption pause procedure
Date Tue, 26 Apr 2016 03:11:46 GMT
Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop 4f9a1f840 -> 470262a29


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.


Project: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/commit/470262a2
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/470262a2
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/470262a2

Branch: refs/heads/develop
Commit: 470262a29a9bccfbffbd27b83c139cc109e5c2af
Parents: 4ad86e9
Author: William San Filippo <wills@runtime.io>
Authored: Mon Apr 25 20:06:00 2016 -0700
Committer: William San Filippo <wills@runtime.io>
Committed: Mon Apr 25 20:11:39 2016 -0700

----------------------------------------------------------------------
 apps/bletest/src/bletest_hci.c                  |  48 ++++++-
 apps/bletest/src/bletest_priv.h                 |   4 +-
 apps/bletest/src/main.c                         |  20 ++-
 .../controller/include/controller/ble_ll_conn.h |   3 +
 .../controller/include/controller/ble_ll_ctrl.h |   4 -
 net/nimble/controller/src/ble_ll_conn.c         | 101 +++++++++++++-
 net/nimble/controller/src/ble_ll_conn_hci.c     |   8 +-
 net/nimble/controller/src/ble_ll_ctrl.c         | 138 ++++++++++++++-----
 net/nimble/controller/src/ble_ll_hci_ev.c       |  27 +++-
 net/nimble/host/include/host/host_hci.h         |   1 -
 net/nimble/host/src/host_dbg.c                  |  25 +++-
 net/nimble/host/src/host_hci_cmd.c              |  38 -----
 net/nimble/include/nimble/hci_common.h          |   1 +
 13 files changed, 319 insertions(+), 99 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/apps/bletest/src/bletest_hci.c
----------------------------------------------------------------------
diff --git a/apps/bletest/src/bletest_hci.c b/apps/bletest/src/bletest_hci.c
index 785edd9..b4dcd8b 100755
--- a/apps/bletest/src/bletest_hci.c
+++ b/apps/bletest/src/bletest_hci.c
@@ -41,6 +41,8 @@
 #include "../src/ble_hs_priv.h"
 #include "bletest_priv.h"
 
+extern uint16_t g_bletest_ltk_reply_handle;
+
 void
 bletest_send_conn_update(uint16_t handle)
 {
@@ -66,20 +68,58 @@ bletest_ltk_req_reply(uint16_t handle)
     g_bletest_ltk_reply_handle = handle;
 }
 
-void
+int
 bletest_send_ltk_req_neg_reply(uint16_t handle)
 {
-    host_hci_cmd_le_lt_key_req_neg_reply(handle);
+    int rc;
+    uint8_t *dst;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + sizeof(uint16_t)];
+    uint16_t ack_conn_handle;
+    uint8_t rsplen;
+
+    dst = buf;
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY,
+                       sizeof(uint16_t), dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    htole16(dst, handle);
+    rc = ble_hci_cmd_tx(buf, &ack_conn_handle, 2, &rsplen);
+    if (rc == 0) {
+        if (rsplen != 2) {
+            rc = -1;
+        }
+    }
+
+    return rc;
 }
 
-void
+int
 bletest_send_ltk_req_reply(uint16_t handle)
 {
     struct hci_lt_key_req_reply hkr;
+    uint16_t ack_conn_handle;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_LT_KEY_REQ_REPLY_LEN];
+    uint8_t ack_params_len;
+    int rc;
 
     hkr.conn_handle = handle;
     swap_buf(hkr.long_term_key, (uint8_t *)g_bletest_LTK, 16);
-    host_hci_cmd_le_lt_key_req_reply(&hkr);
+
+    host_hci_cmd_build_le_lt_key_req_reply(&hkr, buf, sizeof buf);
+    rc = ble_hci_cmd_tx(buf, &ack_conn_handle, sizeof ack_conn_handle,
+                        &ack_params_len);
+    if (rc != 0) {
+        return rc;
+    }
+    if (ack_params_len != BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN - 1) {
+        return -1;
+    }
+
+    ack_conn_handle = TOFROMLE16(ack_conn_handle);
+    if (ack_conn_handle != handle) {
+        return -1;
+    }
+    return 0;
 }
 #endif
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/apps/bletest/src/bletest_priv.h
----------------------------------------------------------------------
diff --git a/apps/bletest/src/bletest_priv.h b/apps/bletest/src/bletest_priv.h
index d44dcfe..db4d4b9 100644
--- a/apps/bletest/src/bletest_priv.h
+++ b/apps/bletest/src/bletest_priv.h
@@ -24,8 +24,8 @@ void bletest_send_conn_update(uint16_t handle);
 
 #ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
 void bletest_ltk_req_reply(uint16_t handle);
-void bletest_send_ltk_req_neg_reply(uint16_t handle);
-void bletest_send_ltk_req_reply(uint16_t handle);
+int bletest_send_ltk_req_neg_reply(uint16_t handle);
+int bletest_send_ltk_req_reply(uint16_t handle);
 int bletest_hci_le_start_encrypt(struct hci_start_encrypt *cmd);
 int bletest_hci_le_encrypt(uint8_t *key, uint8_t *pt);
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/apps/bletest/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletest/src/main.c b/apps/bletest/src/main.c
index aa713ac..9510641 100755
--- a/apps/bletest/src/main.c
+++ b/apps/bletest/src/main.c
@@ -514,6 +514,20 @@ bletest_execute_initiator(void)
                     }
                 }
 #endif
+            } else if (g_bletest_state == 8) {
+#ifdef BLE_LL_CFG_FEAT_LE_ENCRYPTION
+                struct hci_start_encrypt hsle;
+                for (i = 0; i < g_bletest_current_conns; ++i) {
+                    if (ble_ll_conn_find_active_conn(i + 1)) {
+                        hsle.connection_handle = i + 1;
+                        hsle.encrypted_diversifier = g_bletest_EDIV;
+                        hsle.random_number = ~g_bletest_RAND;
+                        swap_buf(hsle.long_term_key, (uint8_t *)g_bletest_LTK,
+                                 16);
+                        bletest_hci_le_start_encrypt(&hsle);
+                    }
+                }
+#endif
             } else {
                 for (i = 0; i < g_bletest_current_conns; ++i) {
                     if (ble_ll_conn_find_active_conn(i + 1)) {
@@ -521,8 +535,10 @@ bletest_execute_initiator(void)
                     }
                 }
             }
-            if (g_bletest_state < 5) {
-                ++g_bletest_state;
+
+            ++g_bletest_state;
+            if (g_bletest_state > 9) {
+                g_bletest_state = 9;
             }
             g_next_os_time = os_time_get() + OS_TICKS_PER_SEC * 3;
         }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/controller/include/controller/ble_ll_conn.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_conn.h b/net/nimble/controller/include/controller/ble_ll_conn.h
index f9937aa..36079c8 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)

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/controller/include/controller/ble_ll_ctrl.h
----------------------------------------------------------------------
diff --git a/net/nimble/controller/include/controller/ble_ll_ctrl.h b/net/nimble/controller/include/controller/ble_ll_ctrl.h
index 4a9b1df..a5cd99b 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,

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/controller/src/ble_ll_conn.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn.c b/net/nimble/controller/src/ble_ll_conn.c
index da9acb4..05b2c6c 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;
             }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/controller/src/ble_ll_conn_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_conn_hci.c b/net/nimble/controller/src/ble_ll_conn_hci.c
index 2802866..791fe4a 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);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/controller/src/ble_ll_ctrl.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_ctrl.c b/net/nimble/controller/src/ble_ll_ctrl.c
index 63b4c98..e72e0f9 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;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/controller/src/ble_ll_hci_ev.c
----------------------------------------------------------------------
diff --git a/net/nimble/controller/src/ble_ll_hci_ev.c b/net/nimble/controller/src/ble_ll_hci_ev.c
index d35d59b..ed0f1ba 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;
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/host/include/host/host_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h
index e8fab80..c7d1222 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);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/host/src/host_dbg.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_dbg.c b/net/nimble/host/src/host_dbg.c
index d9e8af6..f8c9a43 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;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/host/src/host_hci_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/host_hci_cmd.c
index 8a923ae..16d6536 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];

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/470262a2/net/nimble/include/nimble/hci_common.h
----------------------------------------------------------------------
diff --git a/net/nimble/include/nimble/hci_common.h b/net/nimble/include/nimble/hci_common.h
index 50d6142..e5c3e2c 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)


Mime
View raw message