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 20:52:04 UTC

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

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/master
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