You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2016/05/17 02:47:34 UTC

[1/4] incubator-mynewt-core git commit: BLE Host - Add bonded flag to SM proc.

Repository: incubator-mynewt-core
Updated Branches:
  refs/heads/develop 4d5aa14f6 -> 26eef9af3


BLE Host - Add bonded flag to SM proc.

This is needed so that the host/app/someone can determine if the
persisted client characteristic configuration should be restored upon
receiving an encryption-change HCI event.


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/28327e94
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/28327e94
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/28327e94

Branch: refs/heads/develop
Commit: 28327e946faebd02fee3913e175c01df2cbd7bac
Parents: aeb46ab
Author: Christopher Collins <cc...@apache.org>
Authored: Mon May 16 13:06:04 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Mon May 16 19:47:00 2016 -0700

----------------------------------------------------------------------
 net/nimble/host/include/host/ble_gap.h | 1 +
 net/nimble/host/src/ble_l2cap_sm.c     | 7 +++++++
 2 files changed, 8 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/28327e94/net/nimble/host/include/host/ble_gap.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_gap.h b/net/nimble/host/include/host/ble_gap.h
index ef9a478..d3fc26d 100644
--- a/net/nimble/host/include/host/ble_gap.h
+++ b/net/nimble/host/include/host/ble_gap.h
@@ -105,6 +105,7 @@ struct ble_gap_sec_state {
     uint8_t pair_alg;
     unsigned enc_enabled:1;
     unsigned authenticated:1;
+    unsigned bonded:1;
 };
 
 struct ble_gap_conn_desc {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/28327e94/net/nimble/host/src/ble_l2cap_sm.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm.c b/net/nimble/host/src/ble_l2cap_sm.c
index a8fe98f..9703519 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -65,6 +65,7 @@
 #define BLE_L2CAP_SM_PROC_F_RX_CONFIRM          0x04
 #define BLE_L2CAP_SM_PROC_F_AUTHENTICATED       0x08
 #define BLE_L2CAP_SM_PROC_F_KEY_EXCHANGE        0x10
+#define BLE_L2CAP_SM_PROC_F_BONDED              0x20
 
 #define BLE_L2CAP_SM_KE_F_ENC_INFO              0x01
 #define BLE_L2CAP_SM_KE_F_MASTER_IDEN           0x02
@@ -393,6 +394,7 @@ ble_l2cap_sm_sec_state(struct ble_l2cap_sm_proc *proc,
     out_sec_state->enc_enabled = enc_enabled;
     out_sec_state->authenticated =
             (proc->flags & BLE_L2CAP_SM_PROC_F_AUTHENTICATED) ? 1 : 0;
+    out_sec_state->bonded = (proc->flags & BLE_L2CAP_SM_PROC_F_BONDED) ? 1 : 0;
 }
 
 static void
@@ -1331,6 +1333,10 @@ ble_l2cap_sm_rx_key_exchange(uint16_t conn_handle, uint8_t op,
         rc = BLE_HS_ENOENT;
     }
 
+    if (rc == 0 && sm_end) {
+        proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
+    }
+
     ble_hs_unlock();
 
     /* a successful ending of the link */
@@ -1665,6 +1671,7 @@ ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
         if (proc != NULL) {
             proc->conn_handle = evt->connection_handle;
             proc->state = BLE_L2CAP_SM_PROC_STATE_LTK;
+            proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
             ble_l2cap_sm_insert(proc);
         }
     } else if (proc->state == BLE_L2CAP_SM_PROC_STATE_LTK) {


[2/4] incubator-mynewt-core git commit: BLE Host - Rename sec procs to match spec language

Posted by cc...@apache.org.
BLE Host - Rename sec procs to match spec language


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/aeb46aba
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/aeb46aba
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/aeb46aba

Branch: refs/heads/develop
Commit: aeb46abade038e6b62b0b7603455e8e8eda01bac
Parents: 4d5aa14
Author: Christopher Collins <cc...@apache.org>
Authored: Mon May 16 13:03:26 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Mon May 16 19:47:00 2016 -0700

----------------------------------------------------------------------
 net/nimble/host/src/ble_gap.c           |  5 ++---
 net/nimble/host/src/ble_l2cap_sm.c      | 19 ++++++++++---------
 net/nimble/host/src/ble_l2cap_sm_priv.h |  4 ++--
 3 files changed, 14 insertions(+), 14 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aeb46aba/net/nimble/host/src/ble_gap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap.c b/net/nimble/host/src/ble_gap.c
index 14c921a..b43535c 100644
--- a/net/nimble/host/src/ble_gap.c
+++ b/net/nimble/host/src/ble_gap.c
@@ -816,7 +816,6 @@ ble_gap_rx_conn_complete(struct hci_le_conn_complete *evt)
     }
 
     /* We verified that there is a free connection when the procedure began. */
-    /* XXX: Revisit this; ensure this is guaranteed. */
     conn = ble_hs_conn_alloc();
     BLE_HS_DBG_ASSERT(conn != NULL);
 
@@ -1989,7 +1988,7 @@ ble_gap_security_initiate(uint16_t conn_handle)
         return BLE_HS_EROLE;
     }
 
-    rc = ble_l2cap_sm_initiate(conn_handle);
+    rc = ble_l2cap_sm_pair_initiate(conn_handle);
     return rc;
 }
 
@@ -2012,7 +2011,7 @@ ble_gap_encryption_initiate(uint16_t conn_handle,
         return BLE_HS_EROLE;
     }
 
-    rc = ble_l2cap_sm_sec_initiate(conn_handle, ltk, ediv, rand_val, auth);
+    rc = ble_l2cap_sm_enc_initiate(conn_handle, ltk, ediv, rand_val, auth);
     return rc;
 }
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aeb46aba/net/nimble/host/src/ble_l2cap_sm.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm.c b/net/nimble/host/src/ble_l2cap_sm.c
index 81b5996..a8fe98f 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -1348,7 +1348,6 @@ ble_l2cap_sm_rx_key_exchange(uint16_t conn_handle, uint8_t op,
     return rc;
 }
 
-
 /*****************************************************************************
  * $rx                                                                       *
  *****************************************************************************/
@@ -1806,15 +1805,16 @@ ble_l2cap_sm_heartbeat(void)
     }
 }
 
+/**
+ * Initiates the pairing procedure for the specified connection.
+ */
 int
-ble_l2cap_sm_initiate(uint16_t conn_handle)
+ble_l2cap_sm_pair_initiate(uint16_t conn_handle)
 {
     struct ble_l2cap_sm_proc *proc;
     int rc;
 
-    /* Make sure a pairing operation for this connection is not already in
-     * progress.
-     */
+    /* Make sure a procedure isn't already in progress for this connection. */
     ble_hs_lock();
     proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
                                   -1, NULL);
@@ -1845,8 +1845,11 @@ done:
     return rc;
 }
 
+/**
+ * Initiates the encryption procedure for the specified connection.
+ */
 int
-ble_l2cap_sm_sec_initiate(uint16_t conn_handle,
+ble_l2cap_sm_enc_initiate(uint16_t conn_handle,
                           uint8_t *ltk,
                           uint16_t ediv,
                           uint64_t rand_val,
@@ -1855,9 +1858,7 @@ ble_l2cap_sm_sec_initiate(uint16_t conn_handle,
     struct ble_l2cap_sm_proc *proc;
     int rc;
 
-    /* Make sure a pairing operation for this connection is not already in
-     * progress.
-     */
+    /* Make sure a procedure isn't already in progress for this connection. */
     ble_hs_lock();
     proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
                                   -1, NULL);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/aeb46aba/net/nimble/host/src/ble_l2cap_sm_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm_priv.h b/net/nimble/host/src/ble_l2cap_sm_priv.h
index 0ed311d..5838ba5 100644
--- a/net/nimble/host/src/ble_l2cap_sm_priv.h
+++ b/net/nimble/host/src/ble_l2cap_sm_priv.h
@@ -211,8 +211,8 @@ void ble_l2cap_sm_rx_encryption_change(struct hci_encrypt_change *evt);
 int ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt);
 
 void ble_l2cap_sm_heartbeat(void);
-int ble_l2cap_sm_initiate(uint16_t conn_handle);
-int ble_l2cap_sm_sec_initiate(uint16_t conn_handle, uint8_t *ltk,
+int ble_l2cap_sm_pair_initiate(uint16_t conn_handle);
+int ble_l2cap_sm_enc_initiate(uint16_t conn_handle, uint8_t *ltk,
                           uint16_t ediv, uint64_t rand_val, int auth);
 int ble_l2cap_sm_init(void);
 


[3/4] incubator-mynewt-core git commit: BLE Host - rx slave security request.

Posted by cc...@apache.org.
BLE Host - rx slave security request.


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/91e81018
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/91e81018
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/91e81018

Branch: refs/heads/develop
Commit: 91e810186b882750a0f3fc48be7ad6b659e934e4
Parents: 28327e9
Author: Christopher Collins <cc...@apache.org>
Authored: Mon May 16 16:33:06 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Mon May 16 19:47:01 2016 -0700

----------------------------------------------------------------------
 net/nimble/host/src/ble_l2cap_sm.c           | 56 ++++++++++++++++-
 net/nimble/host/src/ble_l2cap_sm_cmd.c       | 46 ++++++++++++++
 net/nimble/host/src/ble_l2cap_sm_priv.h      | 17 +++++
 net/nimble/host/src/test/ble_hs_test_util.c  |  8 +++
 net/nimble/host/src/test/ble_hs_test_util.h  |  1 +
 net/nimble/host/src/test/ble_l2cap_sm_test.c | 76 +++++++++++++++++++++++
 6 files changed, 203 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/91e81018/net/nimble/host/src/ble_l2cap_sm.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm.c b/net/nimble/host/src/ble_l2cap_sm.c
index 9703519..05adfca 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -114,6 +114,7 @@ static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_pair_confirm;
 static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_pair_random;
 static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_pair_fail;
 static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_key_exchange;
+static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_sec_req;
 
 static ble_l2cap_sm_rx_fn * const ble_l2cap_sm_dispatch[] = {
    [BLE_L2CAP_SM_OP_PAIR_REQ] = ble_l2cap_sm_rx_pair_req,
@@ -126,7 +127,7 @@ static ble_l2cap_sm_rx_fn * const ble_l2cap_sm_dispatch[] = {
    [BLE_L2CAP_SM_OP_IDENTITY_INFO] = ble_l2cap_sm_rx_key_exchange,
    [BLE_L2CAP_SM_OP_IDENTITY_ADDR_INFO] = ble_l2cap_sm_rx_key_exchange,
    [BLE_L2CAP_SM_OP_SIGN_INFO] = ble_l2cap_sm_rx_key_exchange,
-   [BLE_L2CAP_SM_OP_SEC_REQ] = ble_l2cap_sm_rx_noop,
+   [BLE_L2CAP_SM_OP_SEC_REQ] = ble_l2cap_sm_rx_sec_req,
    [BLE_L2CAP_SM_OP_PAIR_PUBLIC_KEY] = ble_l2cap_sm_rx_noop,
    [BLE_L2CAP_SM_OP_PAIR_DHKEY_CHECK] = ble_l2cap_sm_rx_noop,
    [BLE_L2CAP_SM_OP_PAIR_KEYPRESS_NOTIFY] = ble_l2cap_sm_rx_noop,
@@ -1757,6 +1758,59 @@ ble_l2cap_sm_rx_encryption_change(struct hci_encrypt_change *evt)
 }
 
 static int
+ble_l2cap_sm_rx_sec_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om)
+{
+    struct ble_l2cap_sm_sec_req cmd;
+    struct ble_l2cap_sm_proc *proc;
+    struct ble_hs_conn *conn;
+    int rc;
+
+    rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_SEC_REQ_SZ);
+    if (rc != 0) {
+        return rc;
+    }
+
+    ble_l2cap_sm_sec_req_parse((*om)->om_data, (*om)->om_len, &cmd);
+
+    BLE_HS_LOG(DEBUG, "rxed sm sec req; authreq=%d\n", cmd.authreq);
+
+    ble_hs_lock();
+
+    /* Only handle the security request if a procedure isn't already in
+     * progress for this connection.
+     */
+    proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
+                                  -1, NULL);
+    if (proc != NULL) {
+        rc = BLE_HS_EALREADY;
+    } else {
+        conn = ble_hs_conn_find(conn_handle);
+        if (conn == NULL) {
+            rc = BLE_HS_ENOTCONN;
+        } else if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
+            rc = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CMD_NOT_SUPP);
+            ble_l2cap_sm_pair_fail_tx(conn_handle,
+                                      BLE_L2CAP_SM_ERR_CMD_NOT_SUPP);
+        } else {
+            rc = 0;
+        }
+    }
+
+    ble_hs_unlock();
+
+    if (rc == 0) {
+        /* XXX: Ask app / someone if there is a persisted LTK such that:
+         *     o It corresponds to this peer.
+         *     o It meets the specified authreq criteria.
+         * For now, assume we don't have an appropriate LTK; initiate pairing.
+         */
+        rc = ble_l2cap_sm_pair_initiate(conn_handle);
+    }
+
+    return rc;
+}
+
+static int
 ble_l2cap_sm_rx(uint16_t conn_handle, struct os_mbuf **om)
 {
     ble_l2cap_sm_rx_fn *rx_cb;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/91e81018/net/nimble/host/src/ble_l2cap_sm_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm_cmd.c b/net/nimble/host/src/ble_l2cap_sm_cmd.c
index 62149e6..14c5093 100644
--- a/net/nimble/host/src/ble_l2cap_sm_cmd.c
+++ b/net/nimble/host/src/ble_l2cap_sm_cmd.c
@@ -471,4 +471,50 @@ done:
     return rc;
 }
 
+void
+ble_l2cap_sm_sec_req_parse(void *payload, int len,
+                           struct ble_l2cap_sm_sec_req *cmd)
+{
+    uint8_t *u8ptr;
+
+    BLE_HS_DBG_ASSERT(len >= BLE_L2CAP_SM_SEC_REQ_SZ);
+
+    u8ptr = payload;
+    cmd->authreq = *u8ptr;
+}
+
+void
+ble_l2cap_sm_sec_req_write(void *payload, int len,
+                           struct ble_l2cap_sm_sec_req *cmd)
+{
+    uint8_t *u8ptr;
+
+    BLE_HS_DBG_ASSERT(len >= BLE_L2CAP_SM_HDR_SZ + BLE_L2CAP_SM_SEC_REQ_SZ);
+
+    u8ptr = payload;
+
+    u8ptr[0] = BLE_L2CAP_SM_OP_SEC_REQ;
+    u8ptr[1] = cmd->authreq;
+}
+
+int
+ble_l2cap_sm_sec_req_tx(uint16_t conn_handle, struct ble_l2cap_sm_sec_req *cmd)
+{
+    struct os_mbuf *txom;
+    int rc;
+
+    rc = ble_l2cap_sm_init_req(BLE_L2CAP_SM_SEC_REQ_SZ, &txom);
+    if (rc != 0) {
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+
+    ble_l2cap_sm_sec_req_write(txom->om_data, txom->om_len, cmd);
+    rc = ble_l2cap_sm_tx(conn_handle, txom);
+    txom = NULL;
+
+done:
+    os_mbuf_free_chain(txom);
+    return rc;
+}
 #endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/91e81018/net/nimble/host/src/ble_l2cap_sm_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm_priv.h b/net/nimble/host/src/ble_l2cap_sm_priv.h
index 5838ba5..99070dc 100644
--- a/net/nimble/host/src/ble_l2cap_sm_priv.h
+++ b/net/nimble/host/src/ble_l2cap_sm_priv.h
@@ -141,6 +141,17 @@ struct ble_l2cap_sm_signing_info {
     uint8_t sig_key_le[16];
 };
 
+/**
+ * | Parameter                          | Size (octets)     |
+ * +------------------------------------+-------------------+
+ * | (Code=0x0B)                        | 1                 |
+ * | authreq                            | 1                 |
+ */
+#define BLE_L2CAP_SM_SEC_REQ_SZ         1
+struct ble_l2cap_sm_sec_req {
+    uint8_t authreq;
+};
+
 
 #if NIMBLE_OPT_SM
 
@@ -206,6 +217,12 @@ void ble_l2cap_sm_signing_info_parse(void *payload, int len,
                                      struct ble_l2cap_sm_signing_info *cmd);
 int ble_l2cap_sm_signing_info_tx(uint16_t conn_handle,
                                  struct ble_l2cap_sm_signing_info *cmd);
+void ble_l2cap_sm_sec_req_parse(void *payload, int len,
+                                struct ble_l2cap_sm_sec_req *cmd);
+void ble_l2cap_sm_sec_req_write(void *payload, int len,
+                                struct ble_l2cap_sm_sec_req *cmd);
+int ble_l2cap_sm_sec_req_tx(uint16_t conn_handle,
+                            struct ble_l2cap_sm_sec_req *cmd);
 
 void ble_l2cap_sm_rx_encryption_change(struct hci_encrypt_change *evt);
 int ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/91e81018/net/nimble/host/src/test/ble_hs_test_util.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test_util.c b/net/nimble/host/src/test/ble_hs_test_util.c
index d0b8c0b..bfb4696 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.c
+++ b/net/nimble/host/src/test/ble_hs_test_util.c
@@ -117,6 +117,14 @@ ble_hs_test_util_prev_tx_queue_sz(void)
     return cnt;
 }
 
+void
+ble_hs_test_util_prev_tx_queue_clear(void)
+{
+    while (!STAILQ_EMPTY(&ble_hs_test_util_prev_tx_queue)) {
+        ble_hs_test_util_prev_tx_dequeue();
+    }
+}
+
 void *
 ble_hs_test_util_get_first_hci_tx(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/91e81018/net/nimble/host/src/test/ble_hs_test_util.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_hs_test_util.h b/net/nimble/host/src/test/ble_hs_test_util.h
index baffffc..cd75452 100644
--- a/net/nimble/host/src/test/ble_hs_test_util.h
+++ b/net/nimble/host/src/test/ble_hs_test_util.h
@@ -38,6 +38,7 @@ void ble_hs_test_util_prev_tx_enqueue(struct os_mbuf *om);
 struct os_mbuf *ble_hs_test_util_prev_tx_dequeue(void);
 struct os_mbuf *ble_hs_test_util_prev_tx_dequeue_pullup(void);
 int ble_hs_test_util_prev_tx_queue_sz(void);
+void ble_hs_test_util_prev_tx_queue_clear(void);
 
 void ble_hs_test_util_set_ack_params(uint16_t opcode, uint8_t status,
                                      void *params, uint8_t params_len);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/91e81018/net/nimble/host/src/test/ble_l2cap_sm_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_l2cap_sm_test.c b/net/nimble/host/src/test/ble_l2cap_sm_test.c
index 43d9350..5e3dce9 100644
--- a/net/nimble/host/src/test/ble_l2cap_sm_test.c
+++ b/net/nimble/host/src/test/ble_l2cap_sm_test.c
@@ -248,6 +248,36 @@ ble_l2cap_sm_test_util_rx_random(uint16_t conn_handle,
     TEST_ASSERT_FATAL(rc == exp_status);
 }
 
+static void
+ble_l2cap_sm_test_util_rx_sec_req(uint16_t conn_handle,
+                                  struct ble_l2cap_sm_sec_req *cmd,
+                                  int exp_status)
+{
+    struct hci_data_hdr hci_hdr;
+    struct os_mbuf *om;
+    void *v;
+    int payload_len;
+    int rc;
+
+    hci_hdr = BLE_L2CAP_SM_TEST_UTIL_HCI_HDR(
+        2, BLE_HCI_PB_FIRST_FLUSH,
+        BLE_L2CAP_HDR_SZ + BLE_L2CAP_SM_HDR_SZ + BLE_L2CAP_SM_SEC_REQ_SZ);
+
+    om = ble_hs_misc_pkthdr();
+    TEST_ASSERT_FATAL(om != NULL);
+
+    payload_len = BLE_L2CAP_SM_HDR_SZ + BLE_L2CAP_SM_SEC_REQ_SZ;
+
+    v = os_mbuf_extend(om, payload_len);
+    TEST_ASSERT_FATAL(v != NULL);
+
+    ble_l2cap_sm_sec_req_write(v, payload_len, cmd);
+
+    rc = ble_hs_test_util_l2cap_rx_first_frag(conn_handle, BLE_L2CAP_CID_SM,
+                                              &hci_hdr, om);
+    TEST_ASSERT_FATAL(rc == exp_status);
+}
+
 static struct os_mbuf *
 ble_l2cap_sm_test_util_verify_tx_hdr(uint8_t sm_op, uint16_t payload_len)
 {
@@ -1638,6 +1668,51 @@ TEST_CASE(ble_l2cap_sm_test_case_conn_broken)
     TEST_ASSERT(!ble_l2cap_sm_test_sec_state.authenticated);
 }
 
+TEST_CASE(ble_l2cap_sm_test_case_peer_sec_req_inval)
+{
+    struct ble_l2cap_sm_pair_fail fail;
+    struct ble_l2cap_sm_sec_req sec_req;
+    struct ble_hs_conn *conn;
+    int rc;
+
+    ble_l2cap_sm_test_util_init();
+
+    ble_hs_test_util_create_conn(2, ((uint8_t[6]){1,2,3,5,6,7}),
+                                 ble_l2cap_sm_test_util_conn_cb,
+                                 NULL);
+
+    /* This test inspects and modifies the connection object without locking
+     * the host mutex.  It is not OK for real code to do this, but this test
+     * can assume the connection list is unchanging.
+     */
+    ble_hs_lock();
+    conn = ble_hs_conn_find(2);
+    TEST_ASSERT_FATAL(conn != NULL);
+    ble_hs_unlock();
+
+    /*** We are the slave; reject the security request. */
+    conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
+
+    sec_req.authreq = 0;
+    ble_l2cap_sm_test_util_rx_sec_req(
+        2, &sec_req, BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CMD_NOT_SUPP));
+
+    ble_hs_test_util_tx_all();
+
+    fail.reason = BLE_L2CAP_SM_ERR_CMD_NOT_SUPP;
+    ble_l2cap_sm_test_util_verify_tx_pair_fail(&fail);
+
+    /*** Pairing already in progress; ignore security request. */
+    rc = ble_l2cap_sm_pair_initiate(2);
+    TEST_ASSERT_FATAL(rc == 0);
+    ble_hs_test_util_tx_all();
+    ble_hs_test_util_prev_tx_queue_clear();
+
+    ble_l2cap_sm_test_util_rx_sec_req(2, &sec_req, BLE_HS_EALREADY);
+    ble_hs_test_util_tx_all();
+    TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0);
+}
+
 TEST_SUITE(ble_l2cap_sm_test_suite)
 {
     ble_l2cap_sm_test_case_peer_fail_inval();
@@ -1649,6 +1724,7 @@ TEST_SUITE(ble_l2cap_sm_test_suite)
     ble_l2cap_sm_test_case_peer_bonding_good();
     ble_l2cap_sm_test_case_peer_bonding_bad();
     ble_l2cap_sm_test_case_conn_broken();
+    ble_l2cap_sm_test_case_peer_sec_req_inval();
 }
 #endif
 


[4/4] incubator-mynewt-core git commit: BLE Host - tx slave security request.

Posted by cc...@apache.org.
BLE Host - tx slave security request.


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/26eef9af
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/26eef9af
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/26eef9af

Branch: refs/heads/develop
Commit: 26eef9af3409225c2da26830cc9da2fd2375754c
Parents: 91e8101
Author: Christopher Collins <cc...@apache.org>
Authored: Mon May 16 19:46:49 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Mon May 16 19:47:13 2016 -0700

----------------------------------------------------------------------
 net/nimble/host/src/ble_gap.c                |  11 +-
 net/nimble/host/src/ble_l2cap_sm.c           | 177 ++++++++++++------
 net/nimble/host/src/ble_l2cap_sm_priv.h      |   3 +
 net/nimble/host/src/test/ble_l2cap_sm_test.c | 218 ++++++++++++++++++++--
 4 files changed, 337 insertions(+), 72 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/26eef9af/net/nimble/host/src/ble_gap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap.c b/net/nimble/host/src/ble_gap.c
index b43535c..5dc3078 100644
--- a/net/nimble/host/src/ble_gap.c
+++ b/net/nimble/host/src/ble_gap.c
@@ -1984,11 +1984,16 @@ ble_gap_security_initiate(uint16_t conn_handle)
         return rc;
     }
 
-    if (!(conn_flags & BLE_HS_CONN_F_MASTER)) {
-        return BLE_HS_EROLE;
+    if (conn_flags & BLE_HS_CONN_F_MASTER) {
+        /* XXX: Search the security database for an LTK for this peer.  If one
+         * is found, perform the encryption procedure rather than the pairing
+         * procedure.
+         */
+        rc = ble_l2cap_sm_pair_initiate(conn_handle);
+    } else {
+        rc = ble_l2cap_sm_slave_initiate(conn_handle);
     }
 
-    rc = ble_l2cap_sm_pair_initiate(conn_handle);
     return rc;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/26eef9af/net/nimble/host/src/ble_l2cap_sm.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm.c b/net/nimble/host/src/ble_l2cap_sm.c
index 05adfca..198f4fa 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -58,7 +58,8 @@
 #define BLE_L2CAP_SM_PROC_STATE_LTK             3
 #define BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE      4
 #define BLE_L2CAP_SM_PROC_STATE_KEY_EXCH        5
-#define BLE_L2CAP_SM_PROC_STATE_CNT             6
+#define BLE_L2CAP_SM_PROC_STATE_SEC_REQ         6
+#define BLE_L2CAP_SM_PROC_STATE_CNT             7
 
 #define BLE_L2CAP_SM_PROC_F_INITIATOR           0x01
 #define BLE_L2CAP_SM_PROC_F_TK_VALID            0x02
@@ -144,6 +145,7 @@ static int ble_l2cap_sm_confirm_prepare_args(struct ble_l2cap_sm_proc *proc,
                                              uint8_t *pres, uint8_t *iat,
                                              uint8_t *rat, uint8_t *ia,
                                              uint8_t *ra);
+static void ble_l2cap_sm_check_key_exchange(struct ble_l2cap_sm_proc *proc);
 
 
 /*****************************************************************************
@@ -538,6 +540,15 @@ ble_l2cap_sm_rx_noop(uint16_t conn_handle, uint8_t op, struct os_mbuf **om)
     return BLE_HS_ENOTSUP;
 }
 
+uint8_t
+ble_l2cap_sm_build_authreq(void)
+{
+    return ble_hs_cfg.sm_bonding << 0  |
+           ble_hs_cfg.sm_mitm << 2     |
+           ble_hs_cfg.sm_sc << 3       |
+           ble_hs_cfg.sm_keypress << 4;
+}
+
 /*****************************************************************************
  * $hci                                                                      *
  *****************************************************************************/
@@ -765,22 +776,22 @@ ble_l2cap_sm_random_handle(struct ble_l2cap_sm_proc *proc,
  */
 static const uint8_t initiator_pkact[5 /*init*/ ][5 /*resp */] =
 {
-  {PKACT_NONE,    PKACT_NONE,   PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
-  {PKACT_NONE,    PKACT_NONE,   PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
-  {PKACT_DISP,    PKACT_DISP,   PKACT_INPUT, PKACT_NONE, PKACT_DISP},
-  {PKACT_NONE,    PKACT_NONE,   PKACT_NONE,  PKACT_NONE, PKACT_NONE},
-  {PKACT_DISP,    PKACT_DISP,   PKACT_DISP,  PKACT_NONE, PKACT_DISP},
+    {PKACT_NONE,    PKACT_NONE,   PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
+    {PKACT_NONE,    PKACT_NONE,   PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
+    {PKACT_DISP,    PKACT_DISP,   PKACT_INPUT, PKACT_NONE, PKACT_DISP},
+    {PKACT_NONE,    PKACT_NONE,   PKACT_NONE,  PKACT_NONE, PKACT_NONE},
+    {PKACT_DISP,    PKACT_DISP,   PKACT_DISP,  PKACT_NONE, PKACT_DISP},
 };
 
 /* This is the initiator passkey action action depending on the io
  * capabilities of both parties */
 static const uint8_t responder_pkact[5 /*init*/ ][5 /*resp */] =
 {
-  {PKACT_NONE,    PKACT_NONE,   PKACT_DISP,  PKACT_NONE, PKACT_DISP},
-  {PKACT_NONE,    PKACT_NONE,   PKACT_DISP,  PKACT_NONE, PKACT_DISP},
-  {PKACT_INPUT,   PKACT_INPUT,  PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
-  {PKACT_NONE,    PKACT_NONE,   PKACT_NONE,  PKACT_NONE, PKACT_NONE},
-  {PKACT_INPUT,   PKACT_INPUT,  PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
+    {PKACT_NONE,    PKACT_NONE,   PKACT_DISP,  PKACT_NONE, PKACT_DISP},
+    {PKACT_NONE,    PKACT_NONE,   PKACT_DISP,  PKACT_NONE, PKACT_DISP},
+    {PKACT_INPUT,   PKACT_INPUT,  PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
+    {PKACT_NONE,    PKACT_NONE,   PKACT_NONE,  PKACT_NONE, PKACT_NONE},
+    {PKACT_INPUT,   PKACT_INPUT,  PKACT_INPUT, PKACT_NONE, PKACT_INPUT},
 };
 
 static int
@@ -957,10 +968,7 @@ ble_l2cap_sm_pair_go(struct ble_l2cap_sm_proc *proc)
 
     cmd.io_cap = ble_hs_cfg.sm_io_cap;
     cmd.oob_data_flag = ble_hs_cfg.sm_oob_data_flag;
-    cmd.authreq = (ble_hs_cfg.sm_bonding << 0)  |
-                  (ble_hs_cfg.sm_mitm << 2)     |
-                  (ble_hs_cfg.sm_sc << 3)       |
-                  (ble_hs_cfg.sm_keypress << 4);
+    cmd.authreq = ble_l2cap_sm_build_authreq();
     cmd.max_enc_key_size = 16;
 
     if (is_req) {
@@ -992,39 +1000,6 @@ ble_l2cap_sm_pair_go(struct ble_l2cap_sm_proc *proc)
     return 0;
 }
 
-static void
-ble_l2cap_sm_check_key_exchange(struct ble_l2cap_sm_proc *proc)
-{
-    uint8_t rx_key_dist;
-
-    if (proc->pair_req.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_BOND &&
-        proc->pair_rsp.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_BOND &&
-        proc->pair_rsp.init_key_dist                            &&
-        proc->pair_rsp.resp_key_dist) {
-
-        proc->flags |= BLE_L2CAP_SM_PROC_F_KEY_EXCHANGE;
-    }
-
-    if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
-        rx_key_dist = proc->pair_rsp.resp_key_dist;
-    } else {
-        rx_key_dist = proc->pair_rsp.init_key_dist;
-    }
-
-    proc->rx_key_flags = 0;
-    if (rx_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_ENC) {
-        proc->rx_key_flags |= BLE_L2CAP_SM_KE_F_ENC_INFO |
-                              BLE_L2CAP_SM_KE_F_MASTER_IDEN;
-    }
-    if (rx_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_ID) {
-        proc->rx_key_flags |= BLE_L2CAP_SM_KE_F_IDEN_INFO |
-                              BLE_L2CAP_SM_KE_F_ADDR_INFO;
-    }
-    if (rx_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_SIGN) {
-        proc->rx_key_flags |= BLE_L2CAP_SM_KE_F_SIGN_INFO;
-    }
-}
-
 static int
 ble_l2cap_sm_pair_req_handle(struct ble_l2cap_sm_proc *proc,
                              struct ble_l2cap_sm_pair_cmd *req,
@@ -1098,10 +1073,64 @@ ble_l2cap_sm_pair_rsp_handle(struct ble_l2cap_sm_proc *proc,
 }
 
 /*****************************************************************************
+ * $security request                                                         *
+ *****************************************************************************/
+
+static int
+ble_l2cap_sm_sec_req_go(struct ble_l2cap_sm_proc *proc)
+{
+    struct ble_l2cap_sm_sec_req cmd;
+    int rc;
+
+    cmd.authreq = ble_l2cap_sm_build_authreq();
+    rc = ble_l2cap_sm_sec_req_tx(proc->conn_handle, &cmd);
+    if (rc != 0) {
+        return rc;
+    }
+
+    ble_l2cap_sm_proc_set_timer(proc);
+
+    return 0;
+}
+
+/*****************************************************************************
  * $key exchange                                                             *
  *****************************************************************************/
 
 static void
+ble_l2cap_sm_check_key_exchange(struct ble_l2cap_sm_proc *proc)
+{
+    uint8_t rx_key_dist;
+
+    if (proc->pair_req.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_BOND &&
+        proc->pair_rsp.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_BOND &&
+        proc->pair_rsp.init_key_dist                            &&
+        proc->pair_rsp.resp_key_dist) {
+
+        proc->flags |= BLE_L2CAP_SM_PROC_F_KEY_EXCHANGE;
+    }
+
+    if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
+        rx_key_dist = proc->pair_rsp.resp_key_dist;
+    } else {
+        rx_key_dist = proc->pair_rsp.init_key_dist;
+    }
+
+    proc->rx_key_flags = 0;
+    if (rx_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_ENC) {
+        proc->rx_key_flags |= BLE_L2CAP_SM_KE_F_ENC_INFO |
+                              BLE_L2CAP_SM_KE_F_MASTER_IDEN;
+    }
+    if (rx_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_ID) {
+        proc->rx_key_flags |= BLE_L2CAP_SM_KE_F_IDEN_INFO |
+                              BLE_L2CAP_SM_KE_F_ADDR_INFO;
+    }
+    if (rx_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_SIGN) {
+        proc->rx_key_flags |= BLE_L2CAP_SM_KE_F_SIGN_INFO;
+    }
+}
+
+static void
 ble_l2cap_sm_enc_info_handle(struct ble_l2cap_sm_proc *proc,
                              struct ble_l2cap_sm_enc_info *info)
 {
@@ -1662,10 +1691,10 @@ ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
     proc = ble_l2cap_sm_proc_find(evt->connection_handle,
                                   BLE_L2CAP_SM_PROC_STATE_NONE, 0, &prev);
     if (proc == NULL) {
-        /* The peer is attempting to restore a encrypted connection via
-         * bonding.  Create a proc entry to indicate that security
-         * establishment is in progress and execute the procedure after the
-         * mutex gets unlocked.
+        /* The peer is attempting to restore a encrypted connection via the
+         * encryption procedure (bonding).  Create a proc entry to indicate
+         * that security establishment is in progress and execute the procedure
+         * after the mutex gets unlocked.
          */
         bonding = 1;
         proc = ble_l2cap_sm_proc_alloc();
@@ -1675,6 +1704,13 @@ ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
             proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
             ble_l2cap_sm_insert(proc);
         }
+    } else if (proc->state == BLE_L2CAP_SM_PROC_STATE_SEC_REQ) {
+        /* Same as above, except we solicited the encryption procedure by
+         * sending a security request.
+         */
+        bonding = 1;
+        proc->state = BLE_L2CAP_SM_PROC_STATE_LTK;
+        proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
     } else if (proc->state == BLE_L2CAP_SM_PROC_STATE_LTK) {
         /* Short-term key pairing just completed.  Send the short term key to
          * the controller.
@@ -1906,6 +1942,43 @@ done:
     return rc;
 }
 
+int
+ble_l2cap_sm_slave_initiate(uint16_t conn_handle)
+{
+    struct ble_l2cap_sm_proc *proc;
+    int rc;
+
+    ble_hs_lock();
+
+    /* Make sure a procedure isn't already in progress for this connection. */
+    proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
+                                  -1, NULL);
+    if (proc != NULL) {
+        rc = BLE_HS_EALREADY;
+        goto done;
+    }
+
+    proc = ble_l2cap_sm_proc_alloc();
+    if (proc == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto done;
+    }
+    proc->conn_handle = conn_handle;
+    proc->state = BLE_L2CAP_SM_PROC_STATE_SEC_REQ;
+
+    rc = ble_l2cap_sm_sec_req_go(proc);
+    if (rc != 0) {
+        ble_l2cap_sm_proc_free(proc);
+        goto done;
+    }
+
+    ble_l2cap_sm_insert(proc);
+
+done:
+    ble_hs_unlock();
+    return rc;
+}
+
 /**
  * Initiates the encryption procedure for the specified connection.
  */

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/26eef9af/net/nimble/host/src/ble_l2cap_sm_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm_priv.h b/net/nimble/host/src/ble_l2cap_sm_priv.h
index 99070dc..09a4a53 100644
--- a/net/nimble/host/src/ble_l2cap_sm_priv.h
+++ b/net/nimble/host/src/ble_l2cap_sm_priv.h
@@ -163,6 +163,8 @@ void ble_l2cap_sm_dbg_set_next_ltk(uint8_t *next_ltk);
 int ble_l2cap_sm_dbg_num_procs(void);
 #endif
 
+uint8_t ble_l2cap_sm_build_authreq(void);
+
 struct ble_l2cap_chan *ble_l2cap_sm_create_chan(void);
 
 void ble_l2cap_sm_pair_cmd_parse(void *payload, int len,
@@ -229,6 +231,7 @@ int ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt);
 
 void ble_l2cap_sm_heartbeat(void);
 int ble_l2cap_sm_pair_initiate(uint16_t conn_handle);
+int ble_l2cap_sm_slave_initiate(uint16_t conn_handle);
 int ble_l2cap_sm_enc_initiate(uint16_t conn_handle, uint8_t *ltk,
                           uint16_t ediv, uint64_t rand_val, int auth);
 int ble_l2cap_sm_init(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/26eef9af/net/nimble/host/src/test/ble_l2cap_sm_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_l2cap_sm_test.c b/net/nimble/host/src/test/ble_l2cap_sm_test.c
index 5e3dce9..a775cd5 100644
--- a/net/nimble/host/src/test/ble_l2cap_sm_test.c
+++ b/net/nimble/host/src/test/ble_l2cap_sm_test.c
@@ -6,7 +6,7 @@
  * to you under the Apache License, Version 2.0 (the
  * "License"); you may not use this file except in compliance
  * with the License.  You may obtain a copy of the License at
- * 
+ *
  *  http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing,
@@ -41,6 +41,7 @@ struct ble_gap_ltk_params ble_l2cap_sm_test_ltk_params;
 struct ble_l2cap_sm_test_pair_params {
     uint8_t init_addr[6];
     uint8_t rsp_addr[6];
+    struct ble_l2cap_sm_sec_req sec_req;
     struct ble_l2cap_sm_pair_cmd pair_req;
     struct ble_l2cap_sm_pair_cmd pair_rsp;
     struct ble_l2cap_sm_pair_confirm confirm_req;
@@ -61,6 +62,7 @@ struct ble_l2cap_sm_test_pair_params {
     struct ble_l2cap_sm_passkey passkey;
     struct ble_l2cap_sm_pair_fail pair_fail;
 
+    unsigned has_sec_req:1;
     unsigned has_enc_info_req:1;
     unsigned has_enc_info_rsp:1;
     unsigned has_master_id_req:1;
@@ -834,6 +836,7 @@ ble_l2cap_sm_test_util_peer_lgcy_good(
     struct ble_l2cap_sm_test_pair_params *params)
 {
     struct ble_hs_conn *conn;
+    int rc;
 
     ble_l2cap_sm_test_util_init();
 
@@ -871,6 +874,11 @@ ble_l2cap_sm_test_util_peer_lgcy_good(
     TEST_ASSERT(!conn->bhc_sec_state.enc_enabled);
     TEST_ASSERT(ble_l2cap_sm_dbg_num_procs() == 0);
 
+    if (params->has_sec_req) {
+        rc = ble_l2cap_sm_slave_initiate(2);
+        TEST_ASSERT(rc == 0);
+    }
+
     /* Receive a pair request from the peer. */
     ble_l2cap_sm_test_util_rx_pair_req(2, &params->pair_req, 0);
     TEST_ASSERT(!conn->bhc_sec_state.enc_enabled);
@@ -1066,12 +1074,20 @@ TEST_CASE(ble_l2cap_sm_test_case_peer_lgcy_passkey_good)
     ble_l2cap_sm_test_util_peer_lgcy_good(&params);
 }
 
+/**
+ * @param send_enc_req          Whether this procedure is initiated by a slave
+ *                                  security request;
+ *                                  1: We send a security request at start.
+ *                                  0: No security request; peer initiates.
+ */
 static void
-ble_l2cap_sm_test_util_peer_bonding_good(uint8_t *ltk, int authenticated,
+ble_l2cap_sm_test_util_peer_bonding_good(int send_enc_req, uint8_t *ltk,
+                                         int authenticated,
                                          uint16_t ediv, uint64_t rand_num)
 {
     struct ble_l2cap_sm_test_ltk_info ltk_info;
     struct ble_hs_conn *conn;
+    int rc;
 
     ble_l2cap_sm_test_util_init();
 
@@ -1094,6 +1110,11 @@ ble_l2cap_sm_test_util_peer_bonding_good(uint8_t *ltk, int authenticated,
     TEST_ASSERT(!conn->bhc_sec_state.enc_enabled);
     TEST_ASSERT(ble_l2cap_sm_dbg_num_procs() == 0);
 
+    if (send_enc_req) {
+        rc = ble_l2cap_sm_slave_initiate(2);
+        TEST_ASSERT(rc == 0);
+    }
+
     /* Receive a long term key request from the controller. */
     ble_l2cap_sm_test_util_set_lt_key_req_reply_ack(0, 2);
     ble_l2cap_sm_test_util_rx_lt_key_req(2, rand_num, ediv);
@@ -1184,6 +1205,7 @@ TEST_CASE(ble_l2cap_sm_test_case_peer_bonding_good)
 {
     /* Unauthenticated. */
     ble_l2cap_sm_test_util_peer_bonding_good(
+        0,
         ((uint8_t[16]){ 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 }),
         0,
         0x1234,
@@ -1191,6 +1213,7 @@ TEST_CASE(ble_l2cap_sm_test_case_peer_bonding_good)
 
     /* Authenticated. */
     ble_l2cap_sm_test_util_peer_bonding_good(
+        0,
         ((uint8_t[16]){ 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 }),
         1,
         0x4325,
@@ -1510,9 +1533,15 @@ ble_l2cap_sm_test_util_us_lgcy_good(
     TEST_ASSERT(!conn->bhc_sec_state.enc_enabled);
     TEST_ASSERT(ble_l2cap_sm_dbg_num_procs() == 0);
 
-    /* Initiate the pairing procedure. */
-    rc = ble_hs_test_util_security_initiate(2, 0);
-    TEST_ASSERT_FATAL(rc == 0);
+    ble_hs_test_util_set_ack(
+        host_hci_opcode_join(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_START_ENCRYPT), 0);
+    if (params->has_sec_req) {
+        ble_l2cap_sm_test_util_rx_sec_req(2, &params->sec_req, 0);
+    } else {
+        /* Initiate the pairing procedure. */
+        rc = ble_gap_security_initiate(2);
+        TEST_ASSERT_FATAL(rc == 0);
+    }
 
     /* Ensure we sent the expected pair request. */
     ble_hs_test_util_tx_all();
@@ -1586,7 +1615,7 @@ TEST_CASE(ble_l2cap_sm_test_case_us_lgcy_jw_good)
     struct ble_l2cap_sm_test_pair_params params;
 
     params = (struct ble_l2cap_sm_test_pair_params) {
-        .init_addr = {0x06, 0x05, 0x04, 0x03, 0x02, 0x01}, 
+        .init_addr = {0x06, 0x05, 0x04, 0x03, 0x02, 0x01},
         .rsp_addr = {0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a},
         .pair_req = (struct ble_l2cap_sm_pair_cmd) {
             .io_cap = 3,
@@ -1672,7 +1701,6 @@ TEST_CASE(ble_l2cap_sm_test_case_peer_sec_req_inval)
 {
     struct ble_l2cap_sm_pair_fail fail;
     struct ble_l2cap_sm_sec_req sec_req;
-    struct ble_hs_conn *conn;
     int rc;
 
     ble_l2cap_sm_test_util_init();
@@ -1681,17 +1709,8 @@ TEST_CASE(ble_l2cap_sm_test_case_peer_sec_req_inval)
                                  ble_l2cap_sm_test_util_conn_cb,
                                  NULL);
 
-    /* This test inspects and modifies the connection object without locking
-     * the host mutex.  It is not OK for real code to do this, but this test
-     * can assume the connection list is unchanging.
-     */
-    ble_hs_lock();
-    conn = ble_hs_conn_find(2);
-    TEST_ASSERT_FATAL(conn != NULL);
-    ble_hs_unlock();
-
     /*** We are the slave; reject the security request. */
-    conn->bhc_flags &= ~BLE_HS_CONN_F_MASTER;
+    ble_hs_atomic_conn_set_flags(2, BLE_HS_CONN_F_MASTER, 0);
 
     sec_req.authreq = 0;
     ble_l2cap_sm_test_util_rx_sec_req(
@@ -1713,6 +1732,167 @@ TEST_CASE(ble_l2cap_sm_test_case_peer_sec_req_inval)
     TEST_ASSERT(ble_hs_test_util_prev_tx_queue_sz() == 0);
 }
 
+/**
+ * Master: us.
+ * Peer sends a security request.
+ * We respond by initiating the pairing procedure.
+ */
+TEST_CASE(ble_l2cap_sm_test_case_peer_sec_req_pair)
+{
+    struct ble_l2cap_sm_test_pair_params params;
+
+    params = (struct ble_l2cap_sm_test_pair_params) {
+        .init_addr = {0x06, 0x05, 0x04, 0x03, 0x02, 0x01},
+        .rsp_addr = {0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a},
+        .sec_req = (struct ble_l2cap_sm_sec_req) {
+            .authreq = 0,
+        },
+        .has_sec_req = 1,
+        .pair_req = (struct ble_l2cap_sm_pair_cmd) {
+            .io_cap = 3,
+            .oob_data_flag = 0,
+            .authreq = 0,
+            .max_enc_key_size = 16,
+            .init_key_dist = 0,
+            .resp_key_dist = 0,
+        },
+        .pair_rsp = (struct ble_l2cap_sm_pair_cmd) {
+            .io_cap = 3,
+            .oob_data_flag = 0,
+            .authreq = 0,
+            .max_enc_key_size = 16,
+            .init_key_dist = 0,
+            .resp_key_dist = 0,
+        },
+        .confirm_req = (struct ble_l2cap_sm_pair_confirm) {
+            .value = {
+                0x04, 0x4e, 0xaf, 0xce, 0x30, 0x79, 0x2c, 0x9e,
+                0xa2, 0xeb, 0x53, 0x6a, 0xdf, 0xf7, 0x99, 0xb2,
+            },
+        },
+        .confirm_rsp = (struct ble_l2cap_sm_pair_confirm) {
+            .value = {
+                0x04, 0x4e, 0xaf, 0xce, 0x30, 0x79, 0x2c, 0x9e,
+                0xa2, 0xeb, 0x53, 0x6a, 0xdf, 0xf7, 0x99, 0xb2,
+            },
+        },
+        .random_req = (struct ble_l2cap_sm_pair_random) {
+            .value = {
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            },
+        },
+        .random_rsp = (struct ble_l2cap_sm_pair_random) {
+            .value = {
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+            },
+        },
+        .pair_alg = BLE_L2CAP_SM_PAIR_ALG_JW,
+        .tk = { 0 },
+        .stk = {
+            0x2e, 0x2b, 0x34, 0xca, 0x59, 0xfa, 0x4c, 0x88,
+            0x3b, 0x2c, 0x8a, 0xef, 0xd4, 0x4b, 0xe9, 0x66,
+        },
+        .r = 0,
+        .ediv = 0,
+    };
+
+    ble_l2cap_sm_test_util_us_lgcy_good(&params);
+}
+
+/**
+ * Master: peer.
+ * We send a security request.
+ * We accept pairing request sent in response.
+ */
+TEST_CASE(ble_l2cap_sm_test_case_us_sec_req_pair)
+{
+    struct ble_l2cap_sm_test_pair_params params;
+
+    params = (struct ble_l2cap_sm_test_pair_params) {
+        .init_addr = {0xe1, 0xfc, 0xda, 0xf4, 0xb7, 0x6c},
+        .rsp_addr = {0x0c, 0x0b, 0x0a, 0x09, 0x08, 0x07},
+        .sec_req = (struct ble_l2cap_sm_sec_req) {
+            .authreq = 0x05,
+        },
+        .has_sec_req = 1,
+        .pair_req = (struct ble_l2cap_sm_pair_cmd) {
+            .io_cap = 0x04,
+            .oob_data_flag = 0,
+            .authreq = 0x05,
+            .max_enc_key_size = 16,
+            .init_key_dist = 0x07,
+            .resp_key_dist = 0x07,
+        },
+        .pair_rsp = (struct ble_l2cap_sm_pair_cmd) {
+            .io_cap = 0x02,
+            .oob_data_flag = 0,
+            .authreq = 0x05,
+            .max_enc_key_size = 16,
+            .init_key_dist = 0x01,
+            .resp_key_dist = 0x01,
+        },
+        .confirm_req = (struct ble_l2cap_sm_pair_confirm) {
+            .value = {
+                0x54, 0xed, 0x7c, 0x65, 0xc5, 0x3a, 0xee, 0x87,
+                0x8e, 0xf8, 0x04, 0xd8, 0x93, 0xb0, 0xfa, 0xa4,
+            },
+        },
+        .confirm_rsp = (struct ble_l2cap_sm_pair_confirm) {
+            .value = {
+                0xdf, 0x96, 0x88, 0x73, 0x49, 0x24, 0x3f, 0xe8,
+                0xb0, 0xaf, 0xb3, 0xf6, 0xc8, 0xf4, 0xe2, 0x36,
+            },
+        },
+        .random_req = (struct ble_l2cap_sm_pair_random) {
+            .value = {
+                0x4d, 0x2c, 0xf2, 0xb7, 0x11, 0x56, 0xbd, 0x4f,
+                0xfc, 0xde, 0xa9, 0x86, 0x4d, 0xfd, 0x77, 0x03,
+            },
+        },
+        .random_rsp = {
+            .value = {
+                0x12, 0x45, 0x65, 0x2c, 0x85, 0x56, 0x32, 0x8f,
+                0xf4, 0x7f, 0x44, 0xd0, 0x17, 0x35, 0x41, 0xed
+            },
+        },
+        .pair_alg = BLE_L2CAP_SM_PAIR_ALG_PASSKEY,
+        .authenticated = 1,
+        .tk = {
+            0x5a, 0x7f, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00,
+            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+        },
+        .stk = {
+            0x2b, 0x9c, 0x1e, 0x42, 0xa8, 0xcb, 0xab, 0xd1,
+            0x4b, 0xde, 0x50, 0x05, 0x50, 0xd9, 0x95, 0xc6
+        },
+        .r = 4107344270811490869,
+        .ediv = 61621,
+
+        .passkey = {
+            .action = BLE_GAP_PKACT_INPUT,
+            .passkey = 884570,
+        }
+    };
+    ble_l2cap_sm_test_util_peer_lgcy_good(&params);
+}
+
+/**
+ * Master: peer.
+ * We send a security request.
+ * We accept an encryption-changed event in response.
+ */
+TEST_CASE(ble_l2cap_sm_test_case_us_sec_req_enc)
+{
+    ble_l2cap_sm_test_util_peer_bonding_good(
+        1,
+        ((uint8_t[16]){ 2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17 }),
+        1,
+        0x4325,
+        0x543892375);
+}
+
 TEST_SUITE(ble_l2cap_sm_test_suite)
 {
     ble_l2cap_sm_test_case_peer_fail_inval();
@@ -1725,6 +1905,10 @@ TEST_SUITE(ble_l2cap_sm_test_suite)
     ble_l2cap_sm_test_case_peer_bonding_bad();
     ble_l2cap_sm_test_case_conn_broken();
     ble_l2cap_sm_test_case_peer_sec_req_inval();
+    ble_l2cap_sm_test_case_peer_sec_req_pair();
+    /* XXX: ble_l2cap_sm_test_case_peer_sec_req_enc(); */
+    ble_l2cap_sm_test_case_us_sec_req_pair();
+    ble_l2cap_sm_test_case_us_sec_req_enc();
 }
 #endif