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/06/05 11:52:02 UTC

[15/43] incubator-mynewt-core git commit: BLE Host - Rearrange some SM code.

BLE Host - Rearrange some SM code.


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

Branch: refs/heads/develop
Commit: e673cace077b789bf1a54680f940bab630951203
Parents: ac11583
Author: Christopher Collins <cc...@apache.org>
Authored: Tue May 31 10:39:45 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Sun Jun 5 19:09:54 2016 +0800

----------------------------------------------------------------------
 apps/bleprph/src/main.c         |    1 +
 apps/bletiny/src/cmd.c          |    1 +
 net/nimble/host/src/ble_sm.c    | 1164 +++++++++++++++++-----------------
 net/nimble/host/src/ble_sm_sc.c |    4 -
 4 files changed, 586 insertions(+), 584 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e673cace/apps/bleprph/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bleprph/src/main.c b/apps/bleprph/src/main.c
index 8f8acac..e44e58a 100755
--- a/apps/bleprph/src/main.c
+++ b/apps/bleprph/src/main.c
@@ -38,6 +38,7 @@
 #include "host/ble_gap.h"
 #include "host/ble_gatt.h"
 #include "host/ble_l2cap.h"
+#include "host/ble_sm.h"
 #include "controller/ble_ll.h"
 
 #include "bleprph.h"

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e673cace/apps/bletiny/src/cmd.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/cmd.c b/apps/bletiny/src/cmd.c
index 27971dc..d74deba 100644
--- a/apps/bletiny/src/cmd.c
+++ b/apps/bletiny/src/cmd.c
@@ -27,6 +27,7 @@
 #include "nimble/hci_common.h"
 #include "host/ble_gap.h"
 #include "host/ble_hs_adv.h"
+#include "host/ble_sm.h"
 #include "host/ble_eddystone.h"
 #include "../src/ble_l2cap_priv.h"
 #include "../src/ble_hs_priv.h"

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e673cace/net/nimble/host/src/ble_sm.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_sm.c b/net/nimble/host/src/ble_sm.c
index 21a42e2..0dbbdf6 100644
--- a/net/nimble/host/src/ble_sm.c
+++ b/net/nimble/host/src/ble_sm.c
@@ -133,7 +133,7 @@ static struct os_mempool ble_sm_proc_pool;
 /* Maintains the list of active security manager procedures. */
 static struct ble_sm_proc_list ble_sm_procs;
 
-static void ble_sm_check_key_exchange(struct ble_sm_proc *proc);
+static void ble_sm_pair_cfg(struct ble_sm_proc *proc);
 
 
 /*****************************************************************************
@@ -789,7 +789,7 @@ ble_sm_process_result(uint16_t conn_handle, struct ble_sm_result *res)
 }
 
 /*****************************************************************************
- * $hci                                                                      *
+ * $enc                                                                      *
  *****************************************************************************/
 
 static int
@@ -843,6 +843,58 @@ ble_sm_enc_restore_go(struct ble_sm_proc *proc,
     res->app_status = ble_sm_start_encrypt_tx(cmd);
 }
 
+void
+ble_sm_rx_encryption_change(struct hci_encrypt_change *evt)
+{
+    struct ble_sm_result res;
+    struct ble_sm_proc *proc;
+    struct ble_sm_proc *prev;
+    int enc_enabled = 0;
+    int do_key_exchange = 0;
+
+    memset(&res, 0, sizeof res);
+
+    ble_hs_lock();
+    proc = ble_sm_proc_find(evt->connection_handle, BLE_SM_PROC_STATE_NONE, -1,
+                            &prev);
+    if (proc == NULL) {
+        res.app_status = BLE_HS_ENOENT;
+    } else if (proc->state == BLE_SM_PROC_STATE_ENC_START) {
+        enc_enabled = evt->encryption_enabled & 0x01; /* LE bit. */
+        do_key_exchange = proc->flags & BLE_SM_PROC_F_KEY_EXCHANGE;
+        res.app_status = 0;
+    } else if (proc->state == BLE_SM_PROC_STATE_ENC_RESTORE) {
+        enc_enabled = evt->encryption_enabled & 0x01; /* LE bit. */
+        do_key_exchange = 0;
+        res.app_status = 0;
+    } else {
+        proc = NULL;
+        res.app_status = BLE_HS_ENOENT;
+    }
+
+    if (proc != NULL) {
+        if (do_key_exchange && enc_enabled) {
+            proc->state = BLE_SM_PROC_STATE_KEY_EXCH;
+
+            /* The responder sends its keys first. */
+            if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
+                res.execute = 1;
+            }
+        } else {
+            proc->state = BLE_SM_PROC_STATE_NONE;
+            res.enc_cb = 1;
+        }
+    }
+
+    ble_hs_unlock();
+
+    ble_sm_process_result(evt->connection_handle, &res);
+}
+
+/*****************************************************************************
+ * $ltk                                                                      *
+ *****************************************************************************/
+
 static int
 ble_sm_lt_key_req_reply_tx(uint16_t conn_handle, uint8_t *ltk)
 {
@@ -952,6 +1004,103 @@ ble_sm_ltk_restore_go(struct ble_sm_proc *proc,
     }
 }
 
+static int
+ble_sm_retrieve_ltk(struct hci_le_lt_key_req *evt,
+                    struct ble_store_value_sec *value_sec)
+{
+    struct ble_store_key_sec key_sec;
+    int rc;
+
+    /* Tell applicaiton to look up LTK by ediv/rand pair. */
+    /* XXX: Also filter by peer address? */
+    memset(&key_sec, 0, sizeof key_sec);
+    key_sec.peer_addr_type = BLE_STORE_ADDR_TYPE_NONE;
+    key_sec.ediv = evt->encrypted_diversifier;
+    key_sec.rand_num = evt->random_number;
+    key_sec.ediv_rand_present = 1;
+
+    rc = ble_store_read_slv_sec(&key_sec, value_sec);
+    return rc;
+}
+
+int
+ble_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
+{
+    struct ble_store_value_sec value_sec;
+    struct ble_sm_result res;
+    struct ble_sm_proc *proc;
+    int store_rc;
+    int bonding;
+
+    memset(&res, 0, sizeof res);
+
+    ble_hs_lock();
+    proc = ble_sm_proc_find(evt->connection_handle,
+                                  BLE_SM_PROC_STATE_NONE, 0, NULL);
+    if (proc == NULL) {
+        /* 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.
+         */
+        /* XXX: Ensure we are the master. */
+        bonding = 1;
+        proc = ble_sm_proc_alloc();
+        if (proc == NULL) {
+            res.app_status = BLE_HS_ENOMEM;
+        } else {
+            proc->conn_handle = evt->connection_handle;
+            proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
+            proc->flags |= BLE_SM_PROC_F_BONDED;
+            ble_sm_insert(proc);
+        }
+    } else if (proc->state == BLE_SM_PROC_STATE_SEC_REQ) {
+        /* Same as above, except we solicited the encryption procedure by
+         * sending a security request.
+         */
+        bonding = 1;
+        proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
+        proc->flags |= BLE_SM_PROC_F_BONDED;
+    } else if (proc->state == BLE_SM_PROC_STATE_LTK_START) {
+        /* Short-term key pairing just completed.  Send the short term key to
+         * the controller.
+         */
+        bonding = 0;
+    } else {
+        /* The request is unexpected.  Quietly ignore it. */
+        proc = NULL;
+    }
+
+    ble_hs_unlock();
+
+    if (proc == NULL) {
+        return res.app_status;
+    }
+
+    if (bonding) {
+        store_rc = ble_sm_retrieve_ltk(evt, &value_sec);
+        if (store_rc == 0) {
+            res.state_arg = &value_sec;
+        }
+    }
+
+    if (res.app_status == 0) {
+        ble_hs_lock();
+
+        proc = ble_sm_proc_find(evt->connection_handle,
+                                      BLE_SM_PROC_STATE_NONE, 0, NULL);
+        if (proc != NULL) {
+            res.execute = 1;
+        }
+
+        ble_hs_unlock();
+    }
+
+    ble_sm_process_result(evt->connection_handle, &res);
+
+    return 0;
+}
+
 /*****************************************************************************
  * $random                                                                   *
  *****************************************************************************/
@@ -987,6 +1136,42 @@ ble_sm_random_go(struct ble_sm_proc *proc,
     }
 }
 
+static void
+ble_sm_rx_pair_random(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                      struct ble_sm_result *res)
+{
+    struct ble_sm_pair_random cmd;
+    struct ble_sm_proc *proc;
+    struct ble_sm_proc *prev;
+
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_RANDOM_SZ);
+    if (res->app_status != 0) {
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+        res->enc_cb = 1;
+        return;
+    }
+
+    ble_sm_pair_random_parse((*om)->om_data, (*om)->om_len, &cmd);
+
+    BLE_HS_LOG(DEBUG, "rxed sm random cmd\n");
+
+    ble_hs_lock();
+    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_RANDOM,
+                                  -1, &prev);
+    if (proc == NULL) {
+        res->app_status = BLE_HS_ENOENT;
+    } else {
+        memcpy(ble_sm_their_pair_rand(proc), cmd.value, 16);
+
+        if (proc->flags & BLE_SM_PROC_F_SC) {
+            ble_sm_sc_rx_pair_random(proc, res);
+        } else {
+            ble_sm_lgcy_rx_pair_random(proc, res);
+        }
+    }
+    ble_hs_unlock();
+}
+
 /*****************************************************************************
  * $confirm                                                                  *
  *****************************************************************************/
@@ -1003,6 +1188,51 @@ ble_sm_confirm_go(struct ble_sm_proc *proc,
     }
 }
 
+static void
+ble_sm_rx_pair_confirm(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                       struct ble_sm_result *res)
+{
+    struct ble_sm_pair_confirm cmd;
+    struct ble_sm_proc *proc;
+    struct ble_sm_proc *prev;
+    uint8_t passkey_action;
+
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CONFIRM_SZ);
+    if (res->app_status != 0) {
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+        res->enc_cb = 1;
+        return;
+    }
+
+    ble_sm_pair_confirm_parse((*om)->om_data, (*om)->om_len, &cmd);
+
+    BLE_HS_LOG(DEBUG, "rxed sm confirm cmd\n");
+
+    ble_hs_lock();
+    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_CONFIRM,
+                                  -1, &prev);
+    if (proc == NULL) {
+        res->app_status = BLE_HS_ENOENT;
+    } else {
+        memcpy(proc->confirm_their, cmd.value, 16);
+
+        if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
+            proc->state = BLE_SM_PROC_STATE_RANDOM;
+            res->execute = 1;
+        } else {
+            proc->flags |= BLE_SM_PROC_F_RX_CONFIRM;
+
+            passkey_action = ble_sm_passkey_action(proc);
+            if (passkey_action == BLE_SM_PKACT_NONE ||
+                proc->flags & BLE_SM_PROC_F_TK_VALID) {
+
+                res->execute = 1;
+            }
+        }
+    }
+    ble_hs_unlock();
+}
+
 /*****************************************************************************
  * $pair                                                                     *
  *****************************************************************************/
@@ -1018,33 +1248,72 @@ ble_sm_state_after_pair(struct ble_sm_proc *proc)
 }
 
 static void
-ble_sm_pair_go(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
+ble_sm_pair_cfg(struct ble_sm_proc *proc)
 {
-    struct ble_sm_pair_cmd cmd;
-    int is_req;
-    int rc;
-
-    is_req = proc->flags & BLE_SM_PROC_F_INITIATOR;
+    uint8_t rx_key_dist;
 
-    cmd.io_cap = ble_hs_cfg.sm_io_cap;
-    cmd.oob_data_flag = ble_hs_cfg.sm_oob_data_flag;
-    cmd.authreq = ble_sm_build_authreq();
-    cmd.max_enc_key_size = 16;
+    if (proc->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_BOND &&
+        proc->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_BOND &&
+        proc->pair_rsp.init_key_dist                      &&
+        proc->pair_rsp.resp_key_dist) {
 
-    if (is_req) {
-        cmd.init_key_dist = ble_hs_cfg.sm_our_key_dist;
-        cmd.resp_key_dist = ble_hs_cfg.sm_their_key_dist;
-    } else {
-        /* The response's key distribution flags field is the intersection of
-         * the peer's preferences and our capabilities.
-         */
-        cmd.init_key_dist = proc->pair_req.init_key_dist &
-                            ble_hs_cfg.sm_their_key_dist;
-        cmd.resp_key_dist = proc->pair_req.resp_key_dist &
-                            ble_hs_cfg.sm_our_key_dist;
+        proc->flags |= BLE_SM_PROC_F_KEY_EXCHANGE;
     }
 
-    rc = ble_sm_pair_cmd_tx(proc->conn_handle, is_req, &cmd);
+    if (proc->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC &&
+        proc->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC) {
+
+        proc->flags |= BLE_SM_PROC_F_SC;
+    }
+
+    if (proc->flags & BLE_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_SM_PAIR_KEY_DIST_ENC) {
+        proc->rx_key_flags |= BLE_SM_KE_F_ENC_INFO |
+                              BLE_SM_KE_F_MASTER_ID;
+    }
+    if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
+        proc->rx_key_flags |= BLE_SM_KE_F_ID_INFO |
+                              BLE_SM_KE_F_ADDR_INFO;
+    }
+    if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
+        proc->rx_key_flags |= BLE_SM_KE_F_SIGN_INFO;
+    }
+}
+
+static void
+ble_sm_pair_go(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
+{
+    struct ble_sm_pair_cmd cmd;
+    int is_req;
+    int rc;
+
+    is_req = proc->flags & BLE_SM_PROC_F_INITIATOR;
+
+    cmd.io_cap = ble_hs_cfg.sm_io_cap;
+    cmd.oob_data_flag = ble_hs_cfg.sm_oob_data_flag;
+    cmd.authreq = ble_sm_build_authreq();
+    cmd.max_enc_key_size = 16;
+
+    if (is_req) {
+        cmd.init_key_dist = ble_hs_cfg.sm_our_key_dist;
+        cmd.resp_key_dist = ble_hs_cfg.sm_their_key_dist;
+    } else {
+        /* The response's key distribution flags field is the intersection of
+         * the peer's preferences and our capabilities.
+         */
+        cmd.init_key_dist = proc->pair_req.init_key_dist &
+                            ble_hs_cfg.sm_their_key_dist;
+        cmd.resp_key_dist = proc->pair_req.resp_key_dist &
+                            ble_hs_cfg.sm_our_key_dist;
+    }
+
+    rc = ble_sm_pair_cmd_tx(proc->conn_handle, is_req, &cmd);
     if (rc != 0) {
         goto err;
     }
@@ -1054,7 +1323,7 @@ ble_sm_pair_go(struct ble_sm_proc *proc, struct ble_sm_result *res, void *arg)
     } else {
         proc->pair_rsp = cmd;
 
-        ble_sm_check_key_exchange(proc);
+        ble_sm_pair_cfg(proc);
         proc->state = ble_sm_state_after_pair(proc);
         res->passkey_action = ble_sm_passkey_action(proc);
     }
@@ -1074,6 +1343,112 @@ err:
     }
 }
 
+static void
+ble_sm_rx_pair_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                   struct ble_sm_result *res)
+{
+    struct ble_sm_pair_cmd req;
+    struct ble_sm_proc *proc;
+    struct ble_sm_proc *prev;
+    struct ble_hs_conn *conn;
+
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
+    if (res->app_status != 0) {
+        return;
+    }
+
+    ble_sm_pair_cmd_parse((*om)->om_data, (*om)->om_len, &req);
+
+    BLE_HS_LOG(DEBUG, "rxed sm pair req; io_cap=0x%02x oob_data_flag=%d "
+                      "authreq=0x%02x max_enc_key_size=%d "
+                      "init_key_dist=0x%02x resp_key_dist=0x%02x\n",
+               req.io_cap, req.oob_data_flag, req.authreq,
+               req.max_enc_key_size, req.init_key_dist, req.resp_key_dist);
+
+    ble_hs_lock();
+
+    /* XXX: Check connection state; reject if not appropriate. */
+    /* XXX: Ensure enough time has passed since the previous failed pairing
+     * attempt.
+     */
+    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev);
+    if (proc != NULL) {
+        /* Pairing already in progress; abort old procedure and start new. */
+        /* XXX: Check the spec on this. */
+        ble_sm_proc_remove(proc, prev);
+        ble_sm_proc_free(proc);
+    }
+
+    proc = ble_sm_proc_alloc();
+    if (proc != NULL) {
+        proc->conn_handle = conn_handle;
+        proc->state = BLE_SM_PROC_STATE_PAIR;
+        ble_sm_insert(proc);
+
+        proc->pair_req = req;
+
+        conn = ble_hs_conn_find(proc->conn_handle);
+        if (conn == NULL) {
+            res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+            res->app_status = BLE_HS_ENOTCONN;
+        } else if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) {
+            res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
+            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
+        } else if (!ble_sm_pair_cmd_is_valid(&req)) {
+            res->sm_err = BLE_SM_ERR_INVAL;
+            res->app_status =  BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
+        } else {
+            res->execute = 1;
+        }
+    }
+
+    ble_hs_unlock();
+}
+
+static void
+ble_sm_rx_pair_rsp(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                   struct ble_sm_result *res)
+{
+    struct ble_sm_pair_cmd rsp;
+    struct ble_sm_proc *proc;
+    struct ble_sm_proc *prev;
+
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
+    if (res->app_status != 0) {
+        res->enc_cb = 1;
+        return;
+    }
+
+    ble_sm_pair_cmd_parse((*om)->om_data, (*om)->om_len, &rsp);
+
+    BLE_HS_LOG(DEBUG, "rxed sm pair rsp; io_cap=0x%02x oob_data_flag=%d "
+                      "authreq=0x%02x max_enc_key_size=%d "
+                      "init_key_dist=0x%02x resp_key_dist=0x%02x\n",
+               rsp.io_cap, rsp.oob_data_flag, rsp.authreq,
+               rsp.max_enc_key_size, rsp.init_key_dist, rsp.resp_key_dist);
+
+    ble_hs_lock();
+    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PAIR, 1,
+                                  &prev);
+    if (proc != NULL) {
+        proc->pair_rsp = rsp;
+        if (!ble_sm_pair_cmd_is_valid(&rsp)) {
+            res->sm_err = BLE_SM_ERR_INVAL;
+            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
+        } else {
+            ble_sm_pair_cfg(proc);
+
+            res->passkey_action = ble_sm_passkey_action(proc);
+            if (res->passkey_action == BLE_SM_PKACT_NONE) {
+                proc->state = ble_sm_state_after_pair(proc);
+                res->execute = 1;
+            }
+        }
+    }
+
+    ble_hs_unlock();
+}
+
 /*****************************************************************************
  * $security request                                                         *
  *****************************************************************************/
@@ -1093,49 +1468,82 @@ ble_sm_sec_req_go(struct ble_sm_proc *proc,
     }
 }
 
-/*****************************************************************************
- * $key exchange                                                             *
- *****************************************************************************/
-
 static void
-ble_sm_check_key_exchange(struct ble_sm_proc *proc)
+ble_sm_rx_sec_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                  struct ble_sm_result *res)
 {
-    uint8_t rx_key_dist;
-
-    if (proc->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_BOND &&
-        proc->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_BOND &&
-        proc->pair_rsp.init_key_dist                            &&
-        proc->pair_rsp.resp_key_dist) {
+    struct ble_sm_sec_req cmd;
+    struct ble_store_value_sec value_sec;
+    struct ble_store_key_sec key_sec;
+    struct ble_hs_conn *conn;
+    int authreq_mitm;
 
-        proc->flags |= BLE_SM_PROC_F_KEY_EXCHANGE;
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SEC_REQ_SZ);
+    if (res->app_status != 0) {
+        return;
     }
 
-    if (proc->pair_req.authreq & BLE_SM_PAIR_AUTHREQ_SC &&
-        proc->pair_rsp.authreq & BLE_SM_PAIR_AUTHREQ_SC) {
+    ble_sm_sec_req_parse((*om)->om_data, (*om)->om_len, &cmd);
 
-        proc->flags |= BLE_SM_PROC_F_SC;
-    }
+    /* XXX: Reject if:
+     *     o authreq-bonded flag not set?
+     *     o authreq-reserved flags set?
+     */
 
-    if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
-        rx_key_dist = proc->pair_rsp.resp_key_dist;
+    BLE_HS_LOG(DEBUG, "rxed sm sec req; authreq=%d\n", cmd.authreq);
+
+    ble_hs_lock();
+
+    conn = ble_hs_conn_find(conn_handle);
+    if (conn == NULL) {
+        res->app_status = BLE_HS_ENOTCONN;
+    } else if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
+        res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
+        res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
     } else {
-        rx_key_dist = proc->pair_rsp.init_key_dist;
+        /* We will be querying the SM database for a key corresponding to the
+         * sender; remember the sender's address while the connection list is
+         * locked.
+         */
+        memset(&key_sec, 0, sizeof key_sec);
+        key_sec.peer_addr_type = conn->bhc_addr_type;
+        memcpy(key_sec.peer_addr, conn->bhc_addr, 6);
     }
 
-    proc->rx_key_flags = 0;
-    if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_ENC) {
-        proc->rx_key_flags |= BLE_SM_KE_F_ENC_INFO |
-                              BLE_SM_KE_F_MASTER_ID;
-    }
-    if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_ID) {
-        proc->rx_key_flags |= BLE_SM_KE_F_ID_INFO |
-                              BLE_SM_KE_F_ADDR_INFO;
-    }
-    if (rx_key_dist & BLE_SM_PAIR_KEY_DIST_SIGN) {
-        proc->rx_key_flags |= BLE_SM_KE_F_SIGN_INFO;
+    ble_hs_unlock();
+
+    if (res->app_status == 0) {
+        /* Query database for an LTK corresponding to the sender.  We are the
+         * master, so retrieve a master key.
+         */
+        res->app_status = ble_store_read_mst_sec(&key_sec, &value_sec);
+        if (res->app_status == 0) {
+            /* Found a key corresponding to this peer.  Make sure it meets the
+             * requested minimum authreq.
+             */
+            authreq_mitm = cmd.authreq & BLE_SM_PAIR_AUTHREQ_MITM;
+            if ((!authreq_mitm && value_sec.authenticated) ||
+                (authreq_mitm && !value_sec.authenticated)) {
+
+                res->app_status = BLE_HS_EREJECT;
+            }
+        }
+
+        if (res->app_status == 0) {
+            res->app_status = ble_sm_enc_initiate(conn_handle, value_sec.ltk,
+                                                  value_sec.ediv,
+                                                  value_sec.rand_num,
+                                                  value_sec.authenticated);
+        } else {
+            res->app_status = ble_sm_pair_initiate(conn_handle);
+        }
     }
 }
 
+/*****************************************************************************
+ * $key exchange                                                             *
+ *****************************************************************************/
+
 static void
 ble_sm_key_exch_go(struct ble_sm_proc *proc,
                    struct ble_sm_result *res, void *arg)
@@ -1330,580 +1738,141 @@ ble_sm_rx_master_id(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
         res->sm_err = BLE_SM_ERR_UNSPECIFIED;
     } else {
         proc->rx_key_flags &= ~BLE_SM_KE_F_MASTER_ID;
-        proc->peer_keys.ediv_rand_valid = 1;
-        proc->peer_keys.ediv = cmd.ediv;
-        proc->peer_keys.rand_val = cmd.rand_val;
-
-        ble_sm_key_rxed(proc, res);
-    }
-
-    ble_hs_unlock();
-}
-
-static void
-ble_sm_rx_id_info(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                  struct ble_sm_result *res)
-{
-    struct ble_sm_id_info cmd;
-    struct ble_sm_proc *proc;
-    struct ble_sm_proc *prev;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_INFO_SZ);
-    if (res->app_status != 0) {
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-        res->enc_cb = 1;
-        return;
-    }
-
-    ble_sm_id_info_parse((*om)->om_data, (*om)->om_len, &cmd);
-
-    ble_hs_lock();
-
-    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1,
-                            &prev);
-    if (proc == NULL) {
-        res->app_status = BLE_HS_ENOENT;
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-    } else {
-        proc->rx_key_flags &= ~BLE_SM_KE_F_ID_INFO;
-        proc->peer_keys.irk_valid = 1;
-        memcpy(proc->peer_keys.irk, cmd.irk, 16);
-
-        ble_sm_key_rxed(proc, res);
-    }
-
-    ble_hs_unlock();
-}
-
-static void
-ble_sm_rx_id_addr_info(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                       struct ble_sm_result *res)
-{
-    struct ble_sm_id_addr_info cmd;
-    struct ble_sm_proc *proc;
-    struct ble_sm_proc *prev;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_ADDR_INFO_SZ);
-    if (res->app_status != 0) {
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-        res->enc_cb = 1;
-        return;
-    }
-
-    ble_sm_iden_addr_parse((*om)->om_data, (*om)->om_len, &cmd);
-
-    ble_hs_lock();
-
-    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1,
-                            &prev);
-    if (proc == NULL) {
-        res->app_status = BLE_HS_ENOENT;
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-    } else {
-        proc->rx_key_flags &= ~BLE_SM_KE_F_ADDR_INFO;
-        proc->peer_keys.addr_valid = 1;
-        proc->peer_keys.addr_type = cmd.addr_type;
-        memcpy(proc->peer_keys.addr, cmd.bd_addr, 6);
-
-        ble_sm_key_rxed(proc, res);
-    }
-
-    ble_hs_unlock();
-}
-
-static void
-ble_sm_rx_sign_info(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                    struct ble_sm_result *res)
-{
-    struct ble_sm_sign_info cmd;
-    struct ble_sm_proc *proc;
-    struct ble_sm_proc *prev;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SIGN_INFO_SZ);
-    if (res->app_status != 0) {
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-        res->enc_cb = 1;
-        return;
-    }
-
-    ble_sm_sign_info_parse((*om)->om_data, (*om)->om_len, &cmd);
-
-    ble_hs_lock();
-
-    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1,
-                            &prev);
-    if (proc == NULL) {
-        res->app_status = BLE_HS_ENOENT;
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-    } else {
-        proc->rx_key_flags &= ~BLE_SM_KE_F_SIGN_INFO;
-        proc->peer_keys.csrk_valid = 1;
-        memcpy(proc->peer_keys.csrk, cmd.sig_key, 16);
-
-        ble_sm_key_rxed(proc, res);
-    }
-
-    ble_hs_unlock();
-}
-
-/*****************************************************************************
- * $rx                                                                       *
- *****************************************************************************/
-
-static void
-ble_sm_rx_pair_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                   struct ble_sm_result *res)
-{
-    struct ble_sm_pair_cmd req;
-    struct ble_sm_proc *proc;
-    struct ble_sm_proc *prev;
-    struct ble_hs_conn *conn;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
-    if (res->app_status != 0) {
-        return;
-    }
-
-    ble_sm_pair_cmd_parse((*om)->om_data, (*om)->om_len, &req);
-
-    BLE_HS_LOG(DEBUG, "rxed sm pair req; io_cap=0x%02x oob_data_flag=%d "
-                      "authreq=0x%02x max_enc_key_size=%d "
-                      "init_key_dist=0x%02x resp_key_dist=0x%02x\n",
-               req.io_cap, req.oob_data_flag, req.authreq,
-               req.max_enc_key_size, req.init_key_dist, req.resp_key_dist);
-
-    ble_hs_lock();
-
-    /* XXX: Check connection state; reject if not appropriate. */
-    /* XXX: Ensure enough time has passed since the previous failed pairing
-     * attempt.
-     */
-    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_NONE, -1, &prev);
-    if (proc != NULL) {
-        /* Pairing already in progress; abort old procedure and start new. */
-        /* XXX: Check the spec on this. */
-        ble_sm_proc_remove(proc, prev);
-        ble_sm_proc_free(proc);
-    }
-
-    proc = ble_sm_proc_alloc();
-    if (proc != NULL) {
-        proc->conn_handle = conn_handle;
-        proc->state = BLE_SM_PROC_STATE_PAIR;
-        ble_sm_insert(proc);
-
-        proc->pair_req = req;
-
-        conn = ble_hs_conn_find(proc->conn_handle);
-        if (conn == NULL) {
-            res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-            res->app_status = BLE_HS_ENOTCONN;
-        } else if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) {
-            res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
-            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
-        } else if (!ble_sm_pair_cmd_is_valid(&req)) {
-            res->sm_err = BLE_SM_ERR_INVAL;
-            res->app_status =  BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
-        } else {
-            res->execute = 1;
-        }
-    }
-
-    ble_hs_unlock();
-}
-
-static void
-ble_sm_rx_pair_rsp(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                   struct ble_sm_result *res)
-{
-    struct ble_sm_pair_cmd rsp;
-    struct ble_sm_proc *proc;
-    struct ble_sm_proc *prev;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CMD_SZ);
-    if (res->app_status != 0) {
-        res->enc_cb = 1;
-        return;
-    }
-
-    ble_sm_pair_cmd_parse((*om)->om_data, (*om)->om_len, &rsp);
-
-    BLE_HS_LOG(DEBUG, "rxed sm pair rsp; io_cap=0x%02x oob_data_flag=%d "
-                      "authreq=0x%02x max_enc_key_size=%d "
-                      "init_key_dist=0x%02x resp_key_dist=0x%02x\n",
-               rsp.io_cap, rsp.oob_data_flag, rsp.authreq,
-               rsp.max_enc_key_size, rsp.init_key_dist, rsp.resp_key_dist);
-
-    ble_hs_lock();
-    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PAIR, 1,
-                                  &prev);
-    if (proc != NULL) {
-        proc->pair_rsp = rsp;
-        if (!ble_sm_pair_cmd_is_valid(&rsp)) {
-            res->sm_err = BLE_SM_ERR_INVAL;
-            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_INVAL);
-        } else {
-            ble_sm_check_key_exchange(proc);
-
-            res->passkey_action = ble_sm_passkey_action(proc);
-            if (res->passkey_action == BLE_SM_PKACT_NONE) {
-                proc->state = ble_sm_state_after_pair(proc);
-                res->execute = 1;
-            }
-        }
-    }
-
-    ble_hs_unlock();
-}
-
-static void
-ble_sm_rx_pair_confirm(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                       struct ble_sm_result *res)
-{
-    struct ble_sm_pair_confirm cmd;
-    struct ble_sm_proc *proc;
-    struct ble_sm_proc *prev;
-    uint8_t passkey_action;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_CONFIRM_SZ);
-    if (res->app_status != 0) {
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-        res->enc_cb = 1;
-        return;
-    }
-
-    ble_sm_pair_confirm_parse((*om)->om_data, (*om)->om_len, &cmd);
-
-    BLE_HS_LOG(DEBUG, "rxed sm confirm cmd\n");
-
-    ble_hs_lock();
-    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_CONFIRM,
-                                  -1, &prev);
-    if (proc == NULL) {
-        res->app_status = BLE_HS_ENOENT;
-    } else {
-        memcpy(proc->confirm_their, cmd.value, 16);
-
-        if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
-            proc->state = BLE_SM_PROC_STATE_RANDOM;
-            res->execute = 1;
-        } else {
-            proc->flags |= BLE_SM_PROC_F_RX_CONFIRM;
-
-            passkey_action = ble_sm_passkey_action(proc);
-            if (passkey_action == BLE_SM_PKACT_NONE ||
-                proc->flags & BLE_SM_PROC_F_TK_VALID) {
-
-                res->execute = 1;
-            }
-        }
-    }
-    ble_hs_unlock();
-}
-
-static void
-ble_sm_rx_pair_random(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                      struct ble_sm_result *res)
-{
-    struct ble_sm_pair_random cmd;
-    struct ble_sm_proc *proc;
-    struct ble_sm_proc *prev;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_RANDOM_SZ);
-    if (res->app_status != 0) {
-        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
-        res->enc_cb = 1;
-        return;
-    }
-
-    ble_sm_pair_random_parse((*om)->om_data, (*om)->om_len, &cmd);
-
-    BLE_HS_LOG(DEBUG, "rxed sm random cmd\n");
-
-    ble_hs_lock();
-    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_RANDOM,
-                                  -1, &prev);
-    if (proc == NULL) {
-        res->app_status = BLE_HS_ENOENT;
-    } else {
-        memcpy(ble_sm_their_pair_rand(proc), cmd.value, 16);
-
-        if (proc->flags & BLE_SM_PROC_F_SC) {
-            ble_sm_sc_rx_pair_random(proc, res);
-        } else {
-            ble_sm_lgcy_rx_pair_random(proc, res);
-        }
-    }
-    ble_hs_unlock();
-}
-
-static void
-ble_sm_rx_pair_fail(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                    struct ble_sm_result *res)
-{
-    struct ble_sm_pair_fail cmd;
-
-    res->enc_cb = 1;
-
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_FAIL_SZ);
-    if (res->app_status == 0) {
-        ble_sm_pair_fail_parse((*om)->om_data, (*om)->om_len, &cmd);
-        BLE_HS_LOG(DEBUG, "rxed sm fail cmd; reason=%d\n", cmd.reason);
-
-        res->app_status = BLE_HS_SM_THEM_ERR(cmd.reason);
-    }
-}
-
-static int
-ble_sm_retrieve_ltk(struct hci_le_lt_key_req *evt,
-                    struct ble_store_value_sec *value_sec)
-{
-    struct ble_store_key_sec key_sec;
-    int rc;
-
-    /* Tell applicaiton to look up LTK by ediv/rand pair. */
-    /* XXX: Also filter by peer address? */
-    memset(&key_sec, 0, sizeof key_sec);
-    key_sec.peer_addr_type = BLE_STORE_ADDR_TYPE_NONE;
-    key_sec.ediv = evt->encrypted_diversifier;
-    key_sec.rand_num = evt->random_number;
-    key_sec.ediv_rand_present = 1;
-
-    rc = ble_store_read_slv_sec(&key_sec, value_sec);
-    return rc;
-}
-
-int
-ble_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
-{
-    struct ble_store_value_sec value_sec;
-    struct ble_sm_result res;
-    struct ble_sm_proc *proc;
-    int store_rc;
-    int bonding;
-
-    memset(&res, 0, sizeof res);
-
-    ble_hs_lock();
-    proc = ble_sm_proc_find(evt->connection_handle,
-                                  BLE_SM_PROC_STATE_NONE, 0, NULL);
-    if (proc == NULL) {
-        /* 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.
-         */
-        /* XXX: Ensure we are the master. */
-        bonding = 1;
-        proc = ble_sm_proc_alloc();
-        if (proc == NULL) {
-            res.app_status = BLE_HS_ENOMEM;
-        } else {
-            proc->conn_handle = evt->connection_handle;
-            proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
-            proc->flags |= BLE_SM_PROC_F_BONDED;
-            ble_sm_insert(proc);
-        }
-    } else if (proc->state == BLE_SM_PROC_STATE_SEC_REQ) {
-        /* Same as above, except we solicited the encryption procedure by
-         * sending a security request.
-         */
-        bonding = 1;
-        proc->state = BLE_SM_PROC_STATE_LTK_RESTORE;
-        proc->flags |= BLE_SM_PROC_F_BONDED;
-    } else if (proc->state == BLE_SM_PROC_STATE_LTK_START) {
-        /* Short-term key pairing just completed.  Send the short term key to
-         * the controller.
-         */
-        bonding = 0;
-    } else {
-        /* The request is unexpected.  Quietly ignore it. */
-        proc = NULL;
+        proc->peer_keys.ediv_rand_valid = 1;
+        proc->peer_keys.ediv = cmd.ediv;
+        proc->peer_keys.rand_val = cmd.rand_val;
+
+        ble_sm_key_rxed(proc, res);
     }
 
     ble_hs_unlock();
+}
 
-    if (proc == NULL) {
-        return res.app_status;
-    }
+static void
+ble_sm_rx_id_info(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                  struct ble_sm_result *res)
+{
+    struct ble_sm_id_info cmd;
+    struct ble_sm_proc *proc;
+    struct ble_sm_proc *prev;
 
-    if (bonding) {
-        store_rc = ble_sm_retrieve_ltk(evt, &value_sec);
-        if (store_rc == 0) {
-            res.state_arg = &value_sec;
-        }
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_INFO_SZ);
+    if (res->app_status != 0) {
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+        res->enc_cb = 1;
+        return;
     }
 
-    if (res.app_status == 0) {
-        ble_hs_lock();
+    ble_sm_id_info_parse((*om)->om_data, (*om)->om_len, &cmd);
 
-        proc = ble_sm_proc_find(evt->connection_handle,
-                                      BLE_SM_PROC_STATE_NONE, 0, NULL);
-        if (proc != NULL) {
-            res.execute = 1;
-        }
+    ble_hs_lock();
 
-        ble_hs_unlock();
-    }
+    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1,
+                            &prev);
+    if (proc == NULL) {
+        res->app_status = BLE_HS_ENOENT;
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+    } else {
+        proc->rx_key_flags &= ~BLE_SM_KE_F_ID_INFO;
+        proc->peer_keys.irk_valid = 1;
+        memcpy(proc->peer_keys.irk, cmd.irk, 16);
 
-    ble_sm_process_result(evt->connection_handle, &res);
+        ble_sm_key_rxed(proc, res);
+    }
 
-    return 0;
+    ble_hs_unlock();
 }
 
-void
-ble_sm_rx_encryption_change(struct hci_encrypt_change *evt)
+static void
+ble_sm_rx_id_addr_info(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                       struct ble_sm_result *res)
 {
-    struct ble_sm_result res;
+    struct ble_sm_id_addr_info cmd;
     struct ble_sm_proc *proc;
     struct ble_sm_proc *prev;
-    int enc_enabled = 0;
-    int do_key_exchange = 0;
 
-    memset(&res, 0, sizeof res);
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_ID_ADDR_INFO_SZ);
+    if (res->app_status != 0) {
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+        res->enc_cb = 1;
+        return;
+    }
+
+    ble_sm_iden_addr_parse((*om)->om_data, (*om)->om_len, &cmd);
 
     ble_hs_lock();
-    proc = ble_sm_proc_find(evt->connection_handle, BLE_SM_PROC_STATE_NONE, -1,
+
+    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1,
                             &prev);
     if (proc == NULL) {
-        res.app_status = BLE_HS_ENOENT;
-    } else if (proc->state == BLE_SM_PROC_STATE_ENC_START) {
-        enc_enabled = evt->encryption_enabled & 0x01; /* LE bit. */
-        do_key_exchange = proc->flags & BLE_SM_PROC_F_KEY_EXCHANGE;
-        res.app_status = 0;
-    } else if (proc->state == BLE_SM_PROC_STATE_ENC_RESTORE) {
-        enc_enabled = evt->encryption_enabled & 0x01; /* LE bit. */
-        do_key_exchange = 0;
-        res.app_status = 0;
+        res->app_status = BLE_HS_ENOENT;
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
     } else {
-        proc = NULL;
-        res.app_status = BLE_HS_ENOENT;
-    }
-
-    if (proc != NULL) {
-        if (do_key_exchange && enc_enabled) {
-            proc->state = BLE_SM_PROC_STATE_KEY_EXCH;
+        proc->rx_key_flags &= ~BLE_SM_KE_F_ADDR_INFO;
+        proc->peer_keys.addr_valid = 1;
+        proc->peer_keys.addr_type = cmd.addr_type;
+        memcpy(proc->peer_keys.addr, cmd.bd_addr, 6);
 
-            /* The responder sends its keys first. */
-            if (!(proc->flags & BLE_SM_PROC_F_INITIATOR)) {
-                res.execute = 1;
-            }
-        } else {
-            proc->state = BLE_SM_PROC_STATE_NONE;
-            res.enc_cb = 1;
-        }
+        ble_sm_key_rxed(proc, res);
     }
 
     ble_hs_unlock();
-
-    ble_sm_process_result(evt->connection_handle, &res);
 }
 
 static void
-ble_sm_rx_sec_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
-                  struct ble_sm_result *res)
+ble_sm_rx_sign_info(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                    struct ble_sm_result *res)
 {
-    struct ble_sm_sec_req cmd;
-    struct ble_store_value_sec value_sec;
-    struct ble_store_key_sec key_sec;
-    struct ble_hs_conn *conn;
-    int authreq_mitm;
+    struct ble_sm_sign_info cmd;
+    struct ble_sm_proc *proc;
+    struct ble_sm_proc *prev;
 
-    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SEC_REQ_SZ);
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_SIGN_INFO_SZ);
     if (res->app_status != 0) {
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
+        res->enc_cb = 1;
         return;
     }
 
-    ble_sm_sec_req_parse((*om)->om_data, (*om)->om_len, &cmd);
-
-    /* XXX: Reject if:
-     *     o authreq-bonded flag not set?
-     *     o authreq-reserved flags set?
-     */
-
-    BLE_HS_LOG(DEBUG, "rxed sm sec req; authreq=%d\n", cmd.authreq);
+    ble_sm_sign_info_parse((*om)->om_data, (*om)->om_len, &cmd);
 
     ble_hs_lock();
 
-    conn = ble_hs_conn_find(conn_handle);
-    if (conn == NULL) {
-        res->app_status = BLE_HS_ENOTCONN;
-    } else if (!(conn->bhc_flags & BLE_HS_CONN_F_MASTER)) {
-        res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_CMD_NOT_SUPP);
-        res->sm_err = BLE_SM_ERR_CMD_NOT_SUPP;
+    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_KEY_EXCH, -1,
+                            &prev);
+    if (proc == NULL) {
+        res->app_status = BLE_HS_ENOENT;
+        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
     } else {
-        /* We will be querying the SM database for a key corresponding to the
-         * sender; remember the sender's address while the connection list is
-         * locked.
-         */
-        memset(&key_sec, 0, sizeof key_sec);
-        key_sec.peer_addr_type = conn->bhc_addr_type;
-        memcpy(key_sec.peer_addr, conn->bhc_addr, 6);
+        proc->rx_key_flags &= ~BLE_SM_KE_F_SIGN_INFO;
+        proc->peer_keys.csrk_valid = 1;
+        memcpy(proc->peer_keys.csrk, cmd.sig_key, 16);
+
+        ble_sm_key_rxed(proc, res);
     }
 
     ble_hs_unlock();
-
-    if (res->app_status == 0) {
-        /* Query database for an LTK corresponding to the sender.  We are the
-         * master, so retrieve a master key.
-         */
-        res->app_status = ble_store_read_mst_sec(&key_sec, &value_sec);
-        if (res->app_status == 0) {
-            /* Found a key corresponding to this peer.  Make sure it meets the
-             * requested minimum authreq.
-             */
-            authreq_mitm = cmd.authreq & BLE_SM_PAIR_AUTHREQ_MITM;
-            if ((!authreq_mitm && value_sec.authenticated) ||
-                (authreq_mitm && !value_sec.authenticated)) {
-
-                res->app_status = BLE_HS_EREJECT;
-            }
-        }
-
-        if (res->app_status == 0) {
-            res->app_status = ble_sm_enc_initiate(conn_handle, value_sec.ltk,
-                                                  value_sec.ediv,
-                                                  value_sec.rand_num,
-                                                  value_sec.authenticated);
-        } else {
-            res->app_status = ble_sm_pair_initiate(conn_handle);
-        }
-    }
 }
 
-static int
-ble_sm_rx(uint16_t conn_handle, struct os_mbuf **om)
-{
-    struct ble_sm_result res;
-    ble_sm_rx_fn *rx_cb;
-    uint8_t op;
-    int rc;
-
-    STATS_INC(ble_l2cap_stats, sm_rx);
-    BLE_HS_LOG(DEBUG, "L2CAP - rxed security manager msg: ");
-    ble_hs_misc_log_mbuf(*om);
-    BLE_HS_LOG(DEBUG, "\n");
+/*****************************************************************************
+ * $fail                                                                     *
+ *****************************************************************************/
 
-    rc = os_mbuf_copydata(*om, 0, 1, &op);
-    if (rc != 0) {
-        return BLE_HS_EBADDATA;
-    }
+static void
+ble_sm_rx_pair_fail(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
+                    struct ble_sm_result *res)
+{
+    struct ble_sm_pair_fail cmd;
 
-    /* Strip L2CAP SM header from the front of the mbuf. */
-    os_mbuf_adj(*om, 1);
+    res->enc_cb = 1;
 
-    rx_cb = ble_sm_dispatch_get(op);
-    if (rx_cb != NULL) {
-        memset(&res, 0, sizeof res);
+    res->app_status = ble_hs_misc_pullup_base(om, BLE_SM_PAIR_FAIL_SZ);
+    if (res->app_status == 0) {
+        ble_sm_pair_fail_parse((*om)->om_data, (*om)->om_len, &cmd);
+        BLE_HS_LOG(DEBUG, "rxed sm fail cmd; reason=%d\n", cmd.reason);
 
-        rx_cb(conn_handle, op, om, &res);
-        ble_sm_process_result(conn_handle, &res);
-        rc = res.app_status;
-    } else {
-        rc = BLE_HS_ENOTSUP;
+        res->app_status = BLE_HS_SM_THEM_ERR(cmd.reason);
     }
-
-    return rc;
 }
 
 /*****************************************************************************
@@ -2063,6 +2032,41 @@ ble_sm_enc_initiate(uint16_t conn_handle, uint8_t *ltk, uint16_t ediv,
     return res.app_status;
 }
 
+static int
+ble_sm_rx(uint16_t conn_handle, struct os_mbuf **om)
+{
+    struct ble_sm_result res;
+    ble_sm_rx_fn *rx_cb;
+    uint8_t op;
+    int rc;
+
+    STATS_INC(ble_l2cap_stats, sm_rx);
+    BLE_HS_LOG(DEBUG, "L2CAP - rxed security manager msg: ");
+    ble_hs_misc_log_mbuf(*om);
+    BLE_HS_LOG(DEBUG, "\n");
+
+    rc = os_mbuf_copydata(*om, 0, 1, &op);
+    if (rc != 0) {
+        return BLE_HS_EBADDATA;
+    }
+
+    /* Strip L2CAP SM header from the front of the mbuf. */
+    os_mbuf_adj(*om, 1);
+
+    rx_cb = ble_sm_dispatch_get(op);
+    if (rx_cb != NULL) {
+        memset(&res, 0, sizeof res);
+
+        rx_cb(conn_handle, op, om, &res);
+        ble_sm_process_result(conn_handle, &res);
+        rc = res.app_status;
+    } else {
+        rc = BLE_HS_ENOTSUP;
+    }
+
+    return rc;
+}
+
 struct ble_l2cap_chan *
 ble_sm_create_chan(void)
 {

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e673cace/net/nimble/host/src/ble_sm_sc.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_sm_sc.c b/net/nimble/host/src/ble_sm_sc.c
index 658f62f..b06703d 100644
--- a/net/nimble/host/src/ble_sm_sc.c
+++ b/net/nimble/host/src/ble_sm_sc.c
@@ -241,10 +241,6 @@ ble_sm_sc_rx_public_key(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
     ble_hs_unlock();
 }
 
-/*****************************************************************************
- * $dhkey check                                                              *
- *****************************************************************************/
-
 void
 ble_sm_sc_dhkey_check_go(struct ble_sm_proc *proc, struct ble_sm_result *res,
                          void *arg)