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:51:51 UTC
[04/43] incubator-mynewt-core git commit: BLE Host - Rearrange SM.
BLE Host - Rearrange SM.
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/023769e4
Tree: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/tree/023769e4
Diff: http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/diff/023769e4
Branch: refs/heads/develop
Commit: 023769e4765672e064aa22d76e804a2aab028f33
Parents: b843792
Author: Christopher Collins <cc...@apache.org>
Authored: Fri May 27 10:27:41 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Sun Jun 5 19:07:51 2016 +0800
----------------------------------------------------------------------
net/nimble/host/pkg.yml | 1 +
net/nimble/host/src/ble_l2cap_sm.c | 1505 +++++++++------------
net/nimble/host/src/ble_l2cap_sm_cmd.c | 1 +
net/nimble/host/src/ble_l2cap_sm_priv.h | 78 +-
net/nimble/host/src/ble_sm_lgcy.c | 171 ++-
net/nimble/host/src/ble_sm_sc.c | 359 +++++
net/nimble/host/src/test/ble_l2cap_sm_test.c | 63 +-
7 files changed, 1256 insertions(+), 922 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/023769e4/net/nimble/host/pkg.yml
----------------------------------------------------------------------
diff --git a/net/nimble/host/pkg.yml b/net/nimble/host/pkg.yml
index a4be5ba..0cea14f 100644
--- a/net/nimble/host/pkg.yml
+++ b/net/nimble/host/pkg.yml
@@ -42,4 +42,5 @@ pkg.cflags.SELFTEST:
- -DPHONY_TRANSPORT=1
- -DPHONY_HCI_ACKS=1
- -DNIMBLE_OPT_SM=1
+ - -DNIMBLE_OPT_SM_SC=1
pkg.cflags.TEST: -DBLE_HS_DEBUG
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/023769e4/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 fd70b57..16c671b 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -50,7 +50,6 @@
#if NIMBLE_OPT(SM)
-
/** Procedure timeout; 30 seconds. */
#define BLE_L2CAP_SM_TIMEOUT_OS_TICKS (30 * OS_TICKS_PER_SEC)
@@ -67,8 +66,6 @@ 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 ble_l2cap_sm_rx_public_key;
-static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_dhkey_check;
static ble_l2cap_sm_rx_fn * const ble_l2cap_sm_dispatch[] = {
[BLE_L2CAP_SM_OP_PAIR_REQ] = ble_l2cap_sm_rx_pair_req,
@@ -82,14 +79,56 @@ static ble_l2cap_sm_rx_fn * const ble_l2cap_sm_dispatch[] = {
[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_sec_req,
- [BLE_L2CAP_SM_OP_PAIR_PUBLIC_KEY] = ble_l2cap_sm_rx_public_key,
- [BLE_L2CAP_SM_OP_PAIR_DHKEY_CHECK] = ble_l2cap_sm_rx_dhkey_check,
[BLE_L2CAP_SM_OP_PAIR_KEYPRESS_NOTIFY] = ble_l2cap_sm_rx_noop,
+#if NIMBLE_OPT_SM_SC
+ [BLE_L2CAP_SM_OP_PAIR_PUBLIC_KEY] = ble_sm_sc_rx_public_key,
+ [BLE_L2CAP_SM_OP_PAIR_DHKEY_CHECK] = ble_sm_sc_rx_dhkey_check,
+#else
+ [BLE_L2CAP_SM_OP_PAIR_PUBLIC_KEY] = ble_l2cap_sm_rx_noop,
+ [BLE_L2CAP_SM_OP_PAIR_DHKEY_CHECK] = ble_l2cap_sm_rx_noop,
+#endif
+};
+
+typedef void ble_l2cap_sm_state_fn(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res,
+ void *arg);
+
+static ble_l2cap_sm_state_fn ble_l2cap_sm_pair_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_confirm_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_random_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_ltk_start_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_ltk_restore_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_enc_start_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_enc_restore_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_key_exch_go;
+static ble_l2cap_sm_state_fn ble_l2cap_sm_sec_req_go;
+
+static ble_l2cap_sm_state_fn * const
+ble_l2cap_sm_state_dispatch[BLE_L2CAP_SM_PROC_STATE_CNT] = {
+ [BLE_L2CAP_SM_PROC_STATE_PAIR] = ble_l2cap_sm_pair_go,
+ [BLE_L2CAP_SM_PROC_STATE_CONFIRM] = ble_l2cap_sm_confirm_go,
+ [BLE_L2CAP_SM_PROC_STATE_RANDOM] = ble_l2cap_sm_random_go,
+ [BLE_L2CAP_SM_PROC_STATE_LTK_START] = ble_l2cap_sm_ltk_start_go,
+ [BLE_L2CAP_SM_PROC_STATE_LTK_RESTORE] = ble_l2cap_sm_ltk_restore_go,
+ [BLE_L2CAP_SM_PROC_STATE_ENC_START] = ble_l2cap_sm_enc_start_go,
+ [BLE_L2CAP_SM_PROC_STATE_ENC_RESTORE] = ble_l2cap_sm_enc_restore_go,
+ [BLE_L2CAP_SM_PROC_STATE_KEY_EXCH] = ble_l2cap_sm_key_exch_go,
+ [BLE_L2CAP_SM_PROC_STATE_SEC_REQ] = ble_l2cap_sm_sec_req_go,
+#if NIMBLE_OPT_SM_SC
+ [BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY] = ble_sm_sc_public_key_go,
+ [BLE_L2CAP_SM_PROC_STATE_DHKEY_CHECK] = ble_sm_sc_dhkey_check_go,
+#else
+ [BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY] = NULL,
+ [BLE_L2CAP_SM_PROC_STATE_DHKEY_CHECK] = NULL,
+#endif
};
static void *ble_l2cap_sm_proc_mem;
static struct os_mempool ble_l2cap_sm_proc_pool;
+static void *ble_l2cap_sm_key_mem;
+static struct os_mempool ble_l2cap_sm_key_pool;
+
/* Maintains the list of active security manager procedures. */
static struct ble_l2cap_sm_proc_list ble_l2cap_sm_procs;
@@ -323,7 +362,7 @@ ble_l2cap_sm_gen_csrk(struct ble_l2cap_sm_proc *proc, uint8_t *csrk)
return 0;
}
-static int
+int
ble_l2cap_sm_gen_pub_priv(struct ble_l2cap_sm_proc *proc,
uint8_t *pub, uint8_t *priv)
{
@@ -366,6 +405,38 @@ ble_l2cap_sm_dispatch_get(uint8_t op)
}
/**
+ * Allocates a key entry.
+ *
+ * @return An entry on success; null on failure.
+ */
+static struct ble_l2cap_sm_keys *
+ble_l2cap_sm_keys_alloc(void)
+{
+ struct ble_l2cap_sm_keys *keys;
+
+ keys = os_memblock_get(&ble_l2cap_sm_key_pool);
+ if (keys != NULL) {
+ memset(keys, 0, sizeof *keys);
+ }
+
+ return keys;
+}
+
+/**
+ * Frees the specified keys entry. No-state if passed a null pointer.
+ */
+static void
+ble_l2cap_sm_keys_free(struct ble_l2cap_sm_keys *keys)
+{
+ int rc;
+
+ if (keys != NULL) {
+ rc = os_memblock_put(&ble_l2cap_sm_key_pool, keys);
+ BLE_HS_DBG_ASSERT_EVAL(rc == 0);
+ }
+}
+
+/**
* Allocates a proc entry.
*
* @return An entry on success; null on failure.
@@ -394,6 +465,9 @@ ble_l2cap_sm_proc_free(struct ble_l2cap_sm_proc *proc)
if (proc != NULL) {
ble_l2cap_sm_dbg_assert_not_inserted(proc);
+ ble_l2cap_sm_keys_free(proc->our_keys);
+ ble_l2cap_sm_keys_free(proc->peer_keys);
+
rc = os_memblock_put(&ble_l2cap_sm_proc_pool, proc);
BLE_HS_DBG_ASSERT_EVAL(rc == 0);
}
@@ -459,17 +533,19 @@ ble_l2cap_sm_fill_store_value(uint8_t peer_addr_type, uint8_t *peer_addr,
}
static void
-ble_l2cap_sm_key_exchange_events(struct ble_l2cap_sm_proc *proc)
+ble_l2cap_sm_key_exchange_events(uint16_t conn_handle,
+ struct ble_l2cap_sm_keys *our_keys,
+ struct ble_l2cap_sm_keys *peer_keys,
+ int authenticated)
{
struct ble_store_value_sec value_sec;
struct ble_hs_conn *conn;
uint8_t peer_addr[8];
uint8_t peer_addr_type;
- int authenticated;
ble_hs_lock();
- conn = ble_hs_conn_find(proc->conn_handle);
+ conn = ble_hs_conn_find(conn_handle);
BLE_HS_DBG_ASSERT(conn != NULL);
/* if we got an identity address, use that for key storage */
@@ -482,14 +558,12 @@ ble_l2cap_sm_key_exchange_events(struct ble_l2cap_sm_proc *proc)
}
ble_hs_unlock();
- authenticated = !!(proc->flags & BLE_L2CAP_SM_PROC_F_AUTHENTICATED);
-
ble_l2cap_sm_fill_store_value(peer_addr_type, peer_addr, authenticated,
- &proc->our_keys, &value_sec);
+ our_keys, &value_sec);
ble_store_write_slv_sec(&value_sec);
ble_l2cap_sm_fill_store_value(peer_addr_type, peer_addr, authenticated,
- &proc->peer_keys, &value_sec);
+ peer_keys, &value_sec);
ble_store_write_mst_sec(&value_sec);
}
@@ -541,7 +615,7 @@ ble_l2cap_sm_proc_matches(struct ble_l2cap_sm_proc *proc, uint16_t conn_handle,
* @return The matching proc entry on success;
* null on failure.
*/
-static struct ble_l2cap_sm_proc *
+struct ble_l2cap_sm_proc *
ble_l2cap_sm_proc_find(uint16_t conn_handle, uint8_t state, int is_initiator,
struct ble_l2cap_sm_proc **out_prev)
{
@@ -634,32 +708,87 @@ ble_l2cap_sm_build_authreq(void)
}
static int
-ble_l2cap_sm_initiator_txes_confirm(struct ble_l2cap_sm_proc *proc)
+ble_l2cap_sm_passkey_action(struct ble_l2cap_sm_proc *proc)
{
- BLE_HS_DBG_ASSERT(proc->flags & BLE_L2CAP_SM_PROC_F_SC);
+ if (proc->flags & BLE_L2CAP_SM_PROC_F_SC) {
+ return ble_sm_sc_passkey_action(proc);
+ } else {
+ return ble_sm_lgcy_passkey_action(proc);
+ }
+}
- /* Initiator does not send a confirm when pairing algorithm is any of:
- * o just works
- * o numeric comparison
- * (vol. 3, part H, 2.3.5.6.2)
- */
- return proc->pair_alg != BLE_L2CAP_SM_PAIR_ALG_JW &&
- proc->pair_alg != BLE_L2CAP_SM_PAIR_ALG_NUM_CMP;
+void
+ble_l2cap_sm_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res,
+ void *arg)
+{
+ ble_l2cap_sm_state_fn *cb;
+
+ while (1) {
+ BLE_HS_DBG_ASSERT(proc->state < BLE_L2CAP_SM_PROC_STATE_CNT);
+ cb = ble_l2cap_sm_state_dispatch[proc->state];
+ BLE_HS_DBG_ASSERT(cb != NULL);
+
+ memset(res, 0, sizeof *res);
+
+ cb(proc, res, arg);
+ if (res->app_status != 0 ||
+ proc->state == BLE_L2CAP_SM_PROC_STATE_NONE) {
+
+ break;
+ }
+ if (!res->do_tx) {
+ break;
+ }
+
+ arg = NULL;
+ }
+
+ if (res->app_status == 0) {
+ ble_l2cap_sm_proc_set_timer(proc);
+ }
}
-static int
-ble_l2cap_sm_responder_verifies_random(struct ble_l2cap_sm_proc *proc)
+void
+ble_l2cap_sm_process_result(uint16_t conn_handle,
+ struct ble_l2cap_sm_result *res)
{
- BLE_HS_DBG_ASSERT(proc->flags & BLE_L2CAP_SM_PROC_F_SC);
+ struct ble_l2cap_sm_proc *prev;
+ struct ble_l2cap_sm_proc *proc;
+ int rm;
- /* Responder does not verify the initiator's random number when pairing
- * algorithm is any of:
- * o just works
- * o numeric comparison
- * (vol. 3, part H, 2.3.5.6.2)
- */
- return proc->pair_alg != BLE_L2CAP_SM_PAIR_ALG_JW &&
- proc->pair_alg != BLE_L2CAP_SM_PAIR_ALG_NUM_CMP;
+ ble_hs_lock();
+ proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
+ -1, &prev);
+
+ if (proc != NULL) {
+ rm = res->app_status != 0 ||
+ proc->state == BLE_L2CAP_SM_PROC_STATE_NONE;
+
+ if (rm) {
+ ble_l2cap_sm_proc_remove(proc, prev);
+ }
+
+ if (res->app_status != 0 && res->sm_err != 0) {
+ ble_l2cap_sm_pair_fail_tx(conn_handle, res->sm_err);
+ }
+ }
+
+ ble_hs_unlock();
+
+ if (proc == NULL) {
+ return;
+ }
+
+ if (res->do_cb) {
+ BLE_HS_DBG_ASSERT(rm);
+ ble_l2cap_sm_gap_event(proc, res->app_status,
+ res->app_status == 0);
+ }
+
+ if (rm) {
+ ble_l2cap_sm_proc_free(proc);
+ }
}
/*****************************************************************************
@@ -667,19 +796,12 @@ ble_l2cap_sm_responder_verifies_random(struct ble_l2cap_sm_proc *proc)
*****************************************************************************/
static int
-ble_l2cap_sm_start_encrypt_tx(uint16_t conn_handle, uint16_t ediv,
- uint64_t rand_num, uint8_t *ltk)
+ble_l2cap_sm_start_encrypt_tx(struct hci_start_encrypt *cmd)
{
- struct hci_start_encrypt cmd;
uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_LE_START_ENCRYPT_LEN];
int rc;
- cmd.connection_handle = conn_handle;
- cmd.encrypted_diversifier = ediv;
- cmd.random_number = rand_num;
- memcpy(cmd.long_term_key, ltk, sizeof cmd.long_term_key);
-
- host_hci_cmd_build_le_start_encrypt(&cmd, buf, sizeof buf);
+ host_hci_cmd_build_le_start_encrypt(cmd, buf, sizeof buf);
rc = ble_hci_cmd_tx_empty_ack(buf);
if (rc != 0) {
return rc;
@@ -688,6 +810,40 @@ ble_l2cap_sm_start_encrypt_tx(uint16_t conn_handle, uint16_t ediv,
return 0;
}
+static void
+ble_l2cap_sm_enc_start_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
+{
+ struct hci_start_encrypt *cmd;
+ int rc;
+
+ BLE_HS_DBG_ASSERT(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR);
+
+ cmd = arg;
+ BLE_HS_DBG_ASSERT(cmd != NULL);
+
+ rc = ble_l2cap_sm_start_encrypt_tx(cmd);
+ if (rc != 0) {
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ res->app_status = rc;
+ res->do_cb = 1;
+ }
+}
+
+static void
+ble_l2cap_sm_enc_restore_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
+{
+ struct hci_start_encrypt *cmd;
+
+ BLE_HS_DBG_ASSERT(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR);
+
+ cmd = arg;
+ BLE_HS_DBG_ASSERT(cmd != NULL);
+
+ res->app_status = ble_l2cap_sm_start_encrypt_tx(cmd);
+}
+
static int
ble_l2cap_sm_lt_key_req_reply_tx(uint16_t conn_handle, uint8_t *ltk)
{
@@ -744,85 +900,57 @@ ble_l2cap_sm_lt_key_req_neg_reply_tx(uint16_t conn_handle)
return 0;
}
-static int
-ble_l2cap_sm_lt_key_req_stk_handle(struct ble_l2cap_sm_proc *proc,
- struct hci_le_lt_key_req *evt)
+static void
+ble_l2cap_sm_ltk_start_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
{
- int rc;
+ BLE_HS_DBG_ASSERT(!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR));
- rc = ble_l2cap_sm_lt_key_req_reply_tx(proc->conn_handle, proc->ltk);
- if (rc != 0) {
- return rc;
+ res->app_status = ble_l2cap_sm_lt_key_req_reply_tx(proc->conn_handle,
+ proc->ltk);
+ if (res->app_status == 0) {
+ proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_START;
+ } else {
+ res->do_cb = 1;
}
-
- proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE;
-
- return 0;
}
-/*****************************************************************************
- * $dhkey check *
- *****************************************************************************/
-
-static int
-ble_l2cap_sm_dhkey_check_go(struct ble_l2cap_sm_proc *proc)
+static void
+ble_l2cap_sm_ltk_restore_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res,
+ void *arg)
{
- struct ble_l2cap_sm_dhkey_check cmd;
- int rc;
-
- rc = ble_l2cap_sm_alg_f6(NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL,
- cmd.value);
- if (rc != 0) {
- return rc;
- }
-
- rc = ble_l2cap_sm_dhkey_check_tx(proc->conn_handle, &cmd);
- if (rc != 0) {
- return rc;
- }
+ struct ble_store_value_sec *value_sec;
- ble_l2cap_sm_proc_set_timer(proc);
-
- return 0;
-}
+ BLE_HS_DBG_ASSERT(!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR));
-static int
-ble_l2cap_sm_dhkey_check_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_dhkey_check *cmd,
- uint8_t *out_sm_status)
-{
- uint8_t exp_value[16];
- int rc;
+ value_sec = arg;
- rc = ble_l2cap_sm_alg_f6(NULL, NULL, NULL, NULL, NULL, 0, NULL, 0, NULL,
- exp_value);
- if (rc != 0) {
- return rc;
- }
- if (memcmp(cmd->value, exp_value, 16) != 0) {
- /* Random number mismatch. */
- *out_sm_status = BLE_L2CAP_SM_ERR_DHKEY;
- return BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_DHKEY);
- }
+ if (value_sec != NULL) {
+ /* Store provided a key; send it to the controller. */
+ res->app_status = ble_l2cap_sm_lt_key_req_reply_tx(
+ proc->conn_handle, value_sec->ltk);
- if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE;
- rc = ble_l2cap_sm_start_encrypt_tx(proc->conn_handle, 0, 0,
- proc->ltk);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ if (res->app_status == 0) {
+ if (value_sec->authenticated) {
+ proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
+ }
+ } else {
+ /* Notify the app if it provided a key and the procedure failed. */
+ res->do_cb = 1;
}
} else {
- rc = ble_l2cap_sm_dhkey_check_go(proc);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
- }
- proc->state = BLE_L2CAP_SM_PROC_STATE_LTK;
+ /* Application does not have the requested key in its database. Send a
+ * negative reply to the controller.
+ */
+ ble_l2cap_sm_lt_key_req_neg_reply_tx(proc->conn_handle);
+ res->app_status = BLE_HS_ENOENT;
}
- return 0;
+
+ if (res->app_status == 0) {
+ proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_RESTORE;
+ }
}
/*****************************************************************************
@@ -849,191 +977,35 @@ ble_l2cap_sm_their_pair_rand(struct ble_l2cap_sm_proc *proc)
}
}
-static int
-ble_l2cap_sm_random_go(struct ble_l2cap_sm_proc *proc)
+static void
+ble_l2cap_sm_random_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
{
- struct ble_l2cap_sm_pair_random cmd;
- int rc;
-
- memcpy(cmd.value, ble_l2cap_sm_our_pair_rand(proc), 16);
- rc = ble_l2cap_sm_pair_random_tx(proc->conn_handle, &cmd);
- if (rc != 0) {
- return rc;
+ if (proc->flags & BLE_L2CAP_SM_PROC_F_SC) {
+ ble_sm_sc_random_go(proc, res);
+ } else {
+ ble_sm_lgcy_random_go(proc, res);
}
-
- ble_l2cap_sm_proc_set_timer(proc);
-
- return 0;
}
-static int
+static void
ble_l2cap_sm_random_handle(struct ble_l2cap_sm_proc *proc,
struct ble_l2cap_sm_pair_random *cmd,
- uint8_t *out_sm_status)
+ struct ble_l2cap_sm_result *res)
{
- uint8_t confirm_val[16];
- int do_verify;
- int rc;
-
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_SC)) {
- rc = ble_sm_lgcy_random_handle(proc, cmd, out_sm_status);
- if (rc == 0) {
- switch (proc->state) {
- case BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE:
- rc = ble_l2cap_sm_start_encrypt_tx(proc->conn_handle, 0, 0,
- proc->ltk);
- break;
-
- case BLE_L2CAP_SM_PROC_STATE_RANDOM:
- rc = ble_l2cap_sm_random_go(proc);
- if (rc == 0) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_LTK; // XXX
- }
- break;
-
- default:
- BLE_HS_DBG_ASSERT(0);
- rc = BLE_HS_EUNKNOWN;
- break;
- }
- }
- return rc;
- } else {
- /* SC. */
- if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- do_verify = 1;
- } else {
- do_verify = ble_l2cap_sm_responder_verifies_random(proc);
- }
-
- if (do_verify) {
- rc = ble_l2cap_sm_alg_f4(proc->pub_key_our.x,
- proc->pub_key_their.x,
- ble_l2cap_sm_our_pair_rand(proc), 0,
- confirm_val);
- }
- }
-
- if (do_verify) {
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
- }
-
- if (memcmp(proc->confirm_their, confirm_val, 16) != 0) {
- /* Random number mismatch. */
- *out_sm_status = BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH;
- return BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH);
- }
- }
-
memcpy(ble_l2cap_sm_their_pair_rand(proc), cmd->value, 16);
- /* Calculate the mac key and ltk. */
- rc = ble_l2cap_sm_alg_f5(NULL, NULL, NULL, 0, NULL, 0, NULL,
- proc->mackey, proc->ltk);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
- }
-
- if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_DHKEY_CHECK;
- rc = ble_l2cap_sm_dhkey_check_go(proc);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
- }
+ if (proc->flags & BLE_L2CAP_SM_PROC_F_SC) {
+ ble_sm_sc_random_handle(proc, res);
} else {
- rc = ble_l2cap_sm_random_go(proc);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
- }
- proc->state = BLE_L2CAP_SM_PROC_STATE_DHKEY_CHECK;
+ ble_sm_lgcy_random_handle(proc, res);
}
-
- *out_sm_status = 0;
- return 0;
}
/*****************************************************************************
* $confirm *
*****************************************************************************/
-/**
- * Create some shortened names for the passkey actions so that the table is
- * easier to read.
- */
-#define PKACT_NONE BLE_GAP_PKACT_NONE
-#define PKACT_OOB BLE_GAP_PKACT_OOB
-#define PKACT_INPUT BLE_GAP_PKACT_INPUT
-#define PKACT_DISP BLE_GAP_PKACT_DISP
-
-/* This is the initiator passkey action action dpeneding on the io
- * capabilties of both parties
- */
-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},
-};
-
-/* 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},
-};
-
-static int
-ble_l2cap_sm_passkey_action(struct ble_l2cap_sm_proc *proc)
-{
- int action;
-
- if (proc->pair_req.oob_data_flag && proc->pair_rsp.oob_data_flag) {
- action = BLE_GAP_PKACT_OOB;
- } else if (!(proc->pair_req.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_MITM) ||
- !(proc->pair_rsp.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_MITM)) {
-
- action = BLE_GAP_PKACT_NONE;
- } else if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- action = initiator_pkact[proc->pair_req.io_cap][proc->pair_rsp.io_cap];
- } else {
- action = responder_pkact[proc->pair_req.io_cap][proc->pair_rsp.io_cap];
- }
-
- switch (action) {
- case BLE_GAP_PKACT_NONE:
- proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_JW;
- break;
-
- case BLE_GAP_PKACT_OOB:
- proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_OOB;
- proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
- break;
-
- case BLE_GAP_PKACT_INPUT:
- case BLE_GAP_PKACT_DISP:
- proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_PASSKEY;
- proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
- break;
-
- default:
- BLE_HS_DBG_ASSERT(0);
- break;
- }
-
- return action;
-}
-
static int
ble_l2cap_sm_confirm_prepare_args_lgcy(struct ble_l2cap_sm_proc *proc,
uint8_t *k, uint8_t *preq, uint8_t *pres,
@@ -1127,143 +1099,61 @@ ble_l2cap_sm_confirm_prepare_args_lgcy(struct ble_l2cap_sm_proc *proc,
return 0;
}
-static int
-ble_l2cap_sm_confirm_go(struct ble_l2cap_sm_proc *proc)
+static void
+ble_l2cap_sm_confirm_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
{
- struct ble_l2cap_sm_pair_confirm cmd;
- int rc;
-
if (!(proc->flags & BLE_L2CAP_SM_PROC_F_SC)) {
- /* Legacy. */
- rc = ble_sm_lgcy_confirm_go(proc);
- return rc;
+ ble_sm_lgcy_confirm_go(proc, res);
} else {
- /* Secure connections. */
- rc = ble_l2cap_sm_alg_f4(proc->pub_key_our.x, proc->pub_key_their.x,
- ble_l2cap_sm_our_pair_rand(proc), 0,
- cmd.value);
- if (rc != 0) {
- return rc;
- }
-
- rc = ble_l2cap_sm_pair_confirm_tx(proc->conn_handle, &cmd);
- if (rc != 0) {
- return rc;
- }
-
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_RANDOM;
- }
+ ble_sm_sc_confirm_go(proc, res);
}
-
- ble_l2cap_sm_proc_set_timer(proc);
-
- return 0;
}
-static int
+static void
ble_l2cap_sm_confirm_handle(struct ble_l2cap_sm_proc *proc,
struct ble_l2cap_sm_pair_confirm *cmd,
- uint8_t *out_sm_status)
+ struct ble_l2cap_sm_result *res)
{
- int rc;
-
memcpy(proc->confirm_their, cmd->value, 16);
if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- rc = ble_l2cap_sm_random_go(proc);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
- }
proc->state = BLE_L2CAP_SM_PROC_STATE_RANDOM;
+ ble_l2cap_sm_go(proc, res, NULL);
+ if (res->app_status != 0) {
+ return;
+ }
} else {
proc->flags |= BLE_L2CAP_SM_PROC_F_RX_CONFIRM;
if (ble_l2cap_sm_passkey_action(proc) == BLE_GAP_PKACT_NONE ||
proc->flags & BLE_L2CAP_SM_PROC_F_TK_VALID) {
- rc = ble_l2cap_sm_confirm_go(proc);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ ble_l2cap_sm_go(proc, res, NULL);
+ if (res->app_status != 0) {
+ return;
}
- proc->state = BLE_L2CAP_SM_PROC_STATE_RANDOM;
}
}
-
- return 0;
}
/*****************************************************************************
- * $public key *
+ * $pair *
*****************************************************************************/
-static int
-ble_l2cap_sm_public_key_go(struct ble_l2cap_sm_proc *proc)
+static uint8_t
+ble_l2cap_sm_state_after_pair(struct ble_l2cap_sm_proc *proc)
{
- int initiator_txes;
- int is_initiator;
- int rc;
-
- rc = ble_l2cap_sm_gen_pub_priv(proc, proc->pub_key_our.x,
- proc->priv_key_our);
- if (rc != 0) {
- return rc;
- }
-
- rc = ble_l2cap_sm_public_key_tx(proc->conn_handle, &proc->pub_key_our);
- if (rc != 0) {
- return rc;
- }
-
- proc->state = BLE_L2CAP_SM_PROC_STATE_CONFIRM;
-
- initiator_txes = ble_l2cap_sm_initiator_txes_confirm(proc);
- is_initiator = proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR;
- if ((initiator_txes && is_initiator) ||
- (!initiator_txes && !is_initiator)) {
-
- rc = ble_l2cap_sm_confirm_go(proc);
- if (rc != 0) {
- return rc;
- }
- }
-
- return 0;
-}
-
-static int
-ble_l2cap_sm_public_key_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_public_key *cmd)
-{
- int rc;
-
- proc->pub_key_their = *cmd;
-
- if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_CONFIRM;
-
- if (ble_l2cap_sm_initiator_txes_confirm(proc)) {
- rc = ble_l2cap_sm_confirm_go(proc);
- if (rc != 0) {
- return rc;
- }
- }
+ if (proc->flags & BLE_L2CAP_SM_PROC_F_SC) {
+ return BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY;
} else {
- proc->state = BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY;
- ble_l2cap_sm_public_key_go(proc);
+ return BLE_L2CAP_SM_PROC_STATE_CONFIRM;
}
-
- return 0;
}
-/*****************************************************************************
- * $pair *
- *****************************************************************************/
-
-static int
-ble_l2cap_sm_pair_go(struct ble_l2cap_sm_proc *proc)
+static void
+ble_l2cap_sm_pair_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
{
struct ble_l2cap_sm_pair_cmd cmd;
int is_req;
@@ -1291,7 +1181,7 @@ ble_l2cap_sm_pair_go(struct ble_l2cap_sm_proc *proc)
rc = ble_l2cap_sm_pair_cmd_tx(proc->conn_handle, is_req, &cmd);
if (rc != 0) {
- return rc;
+ goto err;
}
if (is_req) {
@@ -1302,118 +1192,85 @@ ble_l2cap_sm_pair_go(struct ble_l2cap_sm_proc *proc)
rc = ble_l2cap_sm_gen_pair_rand(ble_l2cap_sm_our_pair_rand(proc));
if (rc != 0) {
- return rc;
+ goto err;
}
- ble_l2cap_sm_proc_set_timer(proc);
+ return;
- return 0;
+err:
+ res->app_status = rc;
+
+ if (is_req) {
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ }
}
-static int
+static void
ble_l2cap_sm_pair_req_handle(struct ble_l2cap_sm_proc *proc,
struct ble_l2cap_sm_pair_cmd *req,
- uint8_t *out_sm_status,
- uint8_t *passkey_action)
+ struct ble_l2cap_sm_result *res)
{
struct ble_hs_conn *conn;
- int rc;
proc->pair_req = *req;
conn = ble_hs_conn_find(proc->conn_handle);
if (conn == NULL) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return BLE_HS_ENOTCONN;
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ res->app_status = BLE_HS_ENOTCONN;
+ return;
}
if (conn->bhc_flags & BLE_HS_CONN_F_MASTER) {
- *out_sm_status = BLE_L2CAP_SM_ERR_CMD_NOT_SUPP;
- return BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CMD_NOT_SUPP);
+ res->sm_err = BLE_L2CAP_SM_ERR_CMD_NOT_SUPP;
+ res->app_status = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CMD_NOT_SUPP);
+ return;
}
if (!ble_l2cap_sm_pair_cmd_is_valid(req)) {
- *out_sm_status = BLE_L2CAP_SM_ERR_INVAL;
- return BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_INVAL);
+ res->sm_err = BLE_L2CAP_SM_ERR_INVAL;
+ res->app_status = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_INVAL);
+ return;
}
- rc = ble_l2cap_sm_pair_go(proc);
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ ble_l2cap_sm_go(proc, res, NULL);
+ if (res->app_status != 0) {
+ return;
}
ble_l2cap_sm_check_key_exchange(proc);
-
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_SC)) {
- /* Legacy. */
- proc->state = BLE_L2CAP_SM_PROC_STATE_CONFIRM;
- *passkey_action = ble_l2cap_sm_passkey_action(proc);
- } else {
- /* SC. */
- proc->state = BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY;
- *passkey_action = 0; // XXX
- }
-
- return 0;
+ proc->state = ble_l2cap_sm_state_after_pair(proc);
}
-static int
+static void
ble_l2cap_sm_pair_rsp_handle(struct ble_l2cap_sm_proc *proc,
struct ble_l2cap_sm_pair_cmd *rsp,
- uint8_t *out_sm_status,
- uint8_t *passkey_action)
+ uint8_t passkey_action,
+ struct ble_l2cap_sm_result *res)
{
- int rc;
-
proc->pair_rsp = *rsp;
if (!ble_l2cap_sm_pair_cmd_is_valid(rsp)) {
- *out_sm_status = BLE_L2CAP_SM_ERR_INVAL;
- return BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_INVAL);
+ res->sm_err = BLE_L2CAP_SM_ERR_INVAL;
+ res->app_status = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_INVAL);
+ return;
}
ble_l2cap_sm_check_key_exchange(proc);
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_SC)) {
- /* Legacy. */
- proc->state = BLE_L2CAP_SM_PROC_STATE_CONFIRM;
- } else {
- /* SC. */
- proc->state = BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY;
- }
/* If there is no passkey action to take, proceed to next state. */
- *passkey_action = ble_l2cap_sm_passkey_action(proc);
- if (*passkey_action == BLE_GAP_PKACT_NONE) {
- switch (proc->state) {
- case BLE_L2CAP_SM_PROC_STATE_CONFIRM:
- rc = ble_l2cap_sm_confirm_go(proc);
- break;
-
- case BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY:
- rc = ble_l2cap_sm_public_key_go(proc);
- break;
-
- default:
- BLE_HS_DBG_ASSERT(0);
- rc = BLE_HS_EUNKNOWN;
- break;
- }
-
- if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
- }
+ if (passkey_action == BLE_GAP_PKACT_NONE) {
+ proc->state = ble_l2cap_sm_state_after_pair(proc);
+ ble_l2cap_sm_go(proc, res, NULL);
}
-
- return 0;
}
/*****************************************************************************
* $security request *
*****************************************************************************/
-static int
-ble_l2cap_sm_sec_req_go(struct ble_l2cap_sm_proc *proc)
+static void
+ble_l2cap_sm_sec_req_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
{
struct ble_l2cap_sm_sec_req cmd;
int rc;
@@ -1421,12 +1278,9 @@ ble_l2cap_sm_sec_req_go(struct ble_l2cap_sm_proc *proc)
cmd.authreq = ble_l2cap_sm_build_authreq();
rc = ble_l2cap_sm_sec_req_tx(proc->conn_handle, &cmd);
if (rc != 0) {
- return rc;
+ res->app_status = rc;
+ return;
}
-
- ble_l2cap_sm_proc_set_timer(proc);
-
- return 0;
}
/*****************************************************************************
@@ -1479,8 +1333,8 @@ ble_l2cap_sm_enc_info_handle(struct ble_l2cap_sm_proc *proc,
proc->rx_key_flags &= ~BLE_L2CAP_SM_KE_F_ENC_INFO;
/* Save until completion. */
- proc->peer_keys.ltk_valid = 1;
- memcpy(proc->peer_keys.ltk, info->ltk_le, 16);
+ proc->peer_keys->ltk_valid = 1;
+ memcpy(proc->peer_keys->ltk, info->ltk_le, 16);
}
static void
@@ -1489,9 +1343,9 @@ ble_l2cap_sm_master_iden_handle(struct ble_l2cap_sm_proc *proc,
{
proc->rx_key_flags &= ~BLE_L2CAP_SM_KE_F_MASTER_IDEN;
/* Save until completion. */
- proc->peer_keys.ediv_rand_valid = 1;
- proc->peer_keys.ediv = info->ediv;
- proc->peer_keys.rand_val = info->rand_val;
+ proc->peer_keys->ediv_rand_valid = 1;
+ proc->peer_keys->ediv = info->ediv;
+ proc->peer_keys->rand_val = info->rand_val;
}
static void
@@ -1501,8 +1355,8 @@ ble_l2cap_sm_iden_info_handle(struct ble_l2cap_sm_proc *proc,
proc->rx_key_flags &= ~BLE_L2CAP_SM_KE_F_IDEN_INFO;
/* Save until completion. */
- proc->peer_keys.irk_valid = 1;
- memcpy(proc->peer_keys.irk, info->irk_le, 16);
+ proc->peer_keys->irk_valid = 1;
+ memcpy(proc->peer_keys->irk, info->irk_le, 16);
}
static void
@@ -1512,9 +1366,9 @@ ble_l2cap_sm_iden_addr_handle(struct ble_l2cap_sm_proc *proc,
proc->rx_key_flags &= ~BLE_L2CAP_SM_KE_F_ADDR_INFO;
/* Save until completion. */
- proc->peer_keys.addr_valid = 1;
- proc->peer_keys.addr_type = info->addr_type;
- memcpy(proc->peer_keys.addr, info->bd_addr_le, 6);
+ proc->peer_keys->addr_valid = 1;
+ proc->peer_keys->addr_type = info->addr_type;
+ memcpy(proc->peer_keys->addr, info->bd_addr_le, 6);
}
static void
@@ -1524,13 +1378,13 @@ ble_l2cap_sm_signing_info_handle(struct ble_l2cap_sm_proc *proc,
proc->rx_key_flags &= ~BLE_L2CAP_SM_KE_F_SIGN_INFO;
/* save until completion */
- proc->peer_keys.csrk_valid = 1;
- memcpy(proc->peer_keys.csrk, info->sig_key_le, 16);
+ proc->peer_keys->csrk_valid = 1;
+ memcpy(proc->peer_keys->csrk, info->sig_key_le, 16);
}
-static int
-ble_l2cap_sm_key_exchange_go(struct ble_l2cap_sm_proc *proc,
- uint8_t *sm_status)
+static void
+ble_l2cap_sm_key_exch_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg)
{
struct ble_l2cap_sm_signing_info sign_info;
struct ble_l2cap_sm_master_iden master_iden;
@@ -1540,44 +1394,49 @@ ble_l2cap_sm_key_exchange_go(struct ble_l2cap_sm_proc *proc,
uint8_t our_key_dist;
int rc;
- /* There are no appropriate error codes for key distribution failures. */
- *sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
-
if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
our_key_dist = proc->pair_rsp.init_key_dist;
} else {
our_key_dist = proc->pair_rsp.resp_key_dist;
}
+ if (our_key_dist == 0) {
+ return;
+ }
+
+ BLE_HS_DBG_ASSERT(proc->our_keys == NULL);
+ proc->our_keys = ble_l2cap_sm_keys_alloc();
+ BLE_HS_DBG_ASSERT(proc->our_keys != NULL);
+
if (our_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_ENC) {
/* Send encryption information. */
rc = ble_l2cap_sm_gen_ltk(proc, enc_info.ltk_le);
if (rc != 0) {
- return rc;
+ goto err;
}
rc = ble_l2cap_sm_enc_info_tx(proc->conn_handle, &enc_info);
if (rc != 0) {
- return rc;
+ goto err;
}
- proc->our_keys.ltk_valid = 1;
- memcpy(proc->our_keys.ltk, enc_info.ltk_le, 16);
+ proc->our_keys->ltk_valid = 1;
+ memcpy(proc->our_keys->ltk, enc_info.ltk_le, 16);
/* Send master identification. */
rc = ble_l2cap_sm_gen_ediv(&master_iden.ediv);
if (rc != 0) {
- return rc;
+ goto err;
}
rc = ble_l2cap_sm_gen_start_rand(&master_iden.rand_val);
if (rc != 0) {
- return rc;
+ goto err;
}
rc = ble_l2cap_sm_master_iden_tx(proc->conn_handle, &master_iden);
if (rc != 0) {
- return rc;
+ goto err;
}
- proc->our_keys.ediv_rand_valid = 1;
- proc->our_keys.rand_val = master_iden.rand_val;
- proc->our_keys.ediv = master_iden.ediv;
+ proc->our_keys->ediv_rand_valid = 1;
+ proc->our_keys->rand_val = master_iden.rand_val;
+ proc->our_keys->ediv = master_iden.ediv;
}
if (our_key_dist & BLE_L2CAP_SM_PAIR_KEY_DIST_ID) {
@@ -1588,16 +1447,16 @@ ble_l2cap_sm_key_exchange_go(struct ble_l2cap_sm_proc *proc,
rc = ble_l2cap_sm_iden_info_tx(proc->conn_handle, &iden_info);
if (rc != 0) {
- *sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ goto err;
}
+ proc->our_keys->irk_valid = 1;
+ memcpy(proc->our_keys->irk, iden_info.irk_le, 16);
bls_hs_priv_copy_local_identity_addr(iden_addr_info.bd_addr_le,
&iden_addr_info.addr_type);
rc = ble_l2cap_sm_iden_addr_tx(proc->conn_handle, &iden_addr_info);
if (rc != 0) {
- *sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ goto err;
}
/* copy data to pass to application */
@@ -1613,23 +1472,27 @@ ble_l2cap_sm_key_exchange_go(struct ble_l2cap_sm_proc *proc,
/* Send signing information. */
rc = ble_l2cap_sm_gen_csrk(proc, sign_info.sig_key_le);
if (rc != 0) {
- return rc;
+ goto err;
}
rc = ble_l2cap_sm_signing_info_tx(proc->conn_handle, &sign_info);
if (rc != 0) {
- return rc;
+ goto err;
}
- proc->our_keys.csrk_valid = 1;
- memcpy(proc->our_keys.csrk, sign_info.sig_key_le, 16);
+ proc->our_keys->csrk_valid = 1;
+ memcpy(proc->our_keys->csrk, sign_info.sig_key_le, 16);
}
- /* XXX: Send remainining key information. */
- return 0;
+ return;
+
+err:
+ res->app_status = rc;
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ res->do_cb = 1;
}
static int
ble_l2cap_sm_rx_key_exchange(uint16_t conn_handle, uint8_t op,
- struct os_mbuf **om)
+ struct os_mbuf **om)
{
union {
struct ble_l2cap_sm_enc_info enc_info;
@@ -1639,11 +1502,13 @@ ble_l2cap_sm_rx_key_exchange(uint16_t conn_handle, uint8_t op,
struct ble_l2cap_sm_signing_info signing_info;
} u;
int rc;
- int sm_end = 0;
int base_len;
+ struct ble_l2cap_sm_result res;
+ struct ble_l2cap_sm_keys *peer_keys;
+ struct ble_l2cap_sm_keys *our_keys;
struct ble_l2cap_sm_proc *proc;
struct ble_l2cap_sm_proc *prev;
- uint8_t sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ int authenticated;
switch (op) {
case BLE_L2CAP_SM_OP_ENC_INFO:
@@ -1704,6 +1569,11 @@ ble_l2cap_sm_rx_key_exchange(uint16_t conn_handle, uint8_t op,
proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_KEY_EXCH,
-1, &prev);
if (proc != NULL) {
+ if (proc->peer_keys == NULL) {
+ proc->peer_keys = ble_l2cap_sm_keys_alloc();
+ BLE_HS_DBG_ASSERT(proc->peer_keys != NULL);
+ }
+
switch (op) {
case BLE_L2CAP_SM_OP_ENC_INFO:
ble_l2cap_sm_enc_info_handle(proc, &u.enc_info);
@@ -1729,41 +1599,44 @@ ble_l2cap_sm_rx_key_exchange(uint16_t conn_handle, uint8_t op,
BLE_HS_LOG(DEBUG, "op=%d rx_key_flags=0x%02x\n",
op, proc->rx_key_flags);
- /* did we finish RX keys */
- rc = 0;
if (!proc->rx_key_flags) {
if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- /* time for us to send our keys */
- rc = ble_l2cap_sm_key_exchange_go(proc, &sm_status);
+ ble_l2cap_sm_go(proc, &res, NULL);
}
- sm_end = 1;
- }
- if (rc != 0 || sm_end) {
- ble_l2cap_sm_proc_remove(proc, prev);
+ /* The SM procedure is complete. */
+ proc->state = BLE_L2CAP_SM_PROC_STATE_NONE;
+
+ if (res.app_status == 0) {
+ proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
+ }
}
} else {
- rc = BLE_HS_ENOENT;
+ res.app_status = BLE_HS_ENOENT;
}
- if (rc == 0 && sm_end) {
- proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
+ if (proc->flags & BLE_L2CAP_SM_PROC_F_BONDED) {
+ our_keys = proc->our_keys;
+ peer_keys = proc->peer_keys;
+ authenticated = proc->flags & BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
+
+ proc->our_keys = NULL;
+ proc->peer_keys = NULL;
+ } else {
+ our_keys = NULL;
+ peer_keys = NULL;
}
ble_hs_unlock();
- if (rc == 0) {
- if (sm_end) {
- ble_l2cap_sm_gap_event(proc, 0, 1);
- ble_l2cap_sm_key_exchange_events(proc);
- ble_l2cap_sm_proc_free(proc);
- }
- } else {
- ble_l2cap_sm_gap_event(proc, sm_status, 0);
- ble_l2cap_sm_proc_free(proc);
+ if (our_keys != NULL && peer_keys != NULL) {
+ ble_l2cap_sm_key_exchange_events(conn_handle, our_keys, peer_keys,
+ authenticated);
}
- return rc;
+ ble_l2cap_sm_process_result(conn_handle, &res);
+
+ return res.app_status;
}
/*****************************************************************************
@@ -1775,9 +1648,9 @@ ble_l2cap_sm_rx_pair_req(uint16_t conn_handle, uint8_t op,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_cmd req;
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
struct ble_l2cap_sm_proc *prev;
- uint8_t sm_status = 0;
uint8_t passkey_action = BLE_GAP_PKACT_NONE;
int rc;
@@ -1810,34 +1683,29 @@ ble_l2cap_sm_rx_pair_req(uint16_t conn_handle, uint8_t op,
ble_l2cap_sm_proc_free(proc);
}
+ memset(&res, 0, sizeof res);
+
proc = ble_l2cap_sm_proc_alloc();
- if (proc == NULL) {
- rc = BLE_HS_ENOMEM;
- } else {
+ if (proc != NULL) {
proc->conn_handle = conn_handle;
proc->state = BLE_L2CAP_SM_PROC_STATE_PAIR;
- rc = ble_l2cap_sm_pair_req_handle(proc, &req, &sm_status,
- &passkey_action);
- if (rc == 0) {
- ble_l2cap_sm_insert(proc);
- }
- }
+ ble_l2cap_sm_insert(proc);
- if (rc != 0) {
- ble_l2cap_sm_pair_fail_tx(proc->conn_handle, sm_status);
+ ble_l2cap_sm_pair_req_handle(proc, &req, &res);
+ if (res.app_status == 0) {
+ passkey_action = ble_l2cap_sm_passkey_action(proc);
+ }
}
ble_hs_unlock();
- if (rc == 0) {
- if (passkey_action != BLE_GAP_PKACT_NONE) {
- ble_gap_passkey_event(conn_handle, passkey_action);
- }
- } else {
- ble_l2cap_sm_proc_free(proc);
+ if (res.app_status == 0 && passkey_action != BLE_GAP_PKACT_NONE) {
+ ble_gap_passkey_event(conn_handle, passkey_action);
}
- return rc;
+ ble_l2cap_sm_process_result(conn_handle, &res);
+
+ return res.app_status;
}
static int
@@ -1845,9 +1713,9 @@ ble_l2cap_sm_rx_pair_rsp(uint16_t conn_handle, uint8_t op,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_cmd rsp;
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
struct ble_l2cap_sm_proc *prev;
- uint8_t sm_status = 0;
int rc;
uint8_t passkey_action = BLE_GAP_PKACT_NONE;
@@ -1868,24 +1736,25 @@ ble_l2cap_sm_rx_pair_rsp(uint16_t conn_handle, uint8_t op,
proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_PAIR, 1,
&prev);
if (proc != NULL) {
- rc = ble_l2cap_sm_pair_rsp_handle(proc, &rsp, &sm_status,
- &passkey_action);
- if (rc != 0) {
- ble_l2cap_sm_proc_remove(proc, prev);
- ble_l2cap_sm_pair_fail_tx(conn_handle, sm_status);
- }
+ passkey_action = ble_l2cap_sm_passkey_action(proc);
+
+ memset(&res, 0, sizeof res);
+ ble_l2cap_sm_pair_rsp_handle(proc, &rsp, passkey_action, &res);
}
ble_hs_unlock();
- if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- ble_l2cap_sm_proc_free(proc);
- } else if (passkey_action != BLE_GAP_PKACT_NONE) {
+ if (proc == NULL) {
+ return BLE_HS_ENOENT;
+ }
+
+ if (passkey_action != BLE_GAP_PKACT_NONE) {
ble_gap_passkey_event(conn_handle, passkey_action);
}
- return rc;
+ ble_l2cap_sm_process_result(conn_handle, &res);
+
+ return res.app_status;
}
static int
@@ -1893,14 +1762,13 @@ ble_l2cap_sm_rx_pair_confirm(uint16_t conn_handle, uint8_t op,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_confirm cmd;
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
struct ble_l2cap_sm_proc *prev;
- uint8_t sm_status;
- int rc;
- rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_CONFIRM_SZ);
- if (rc != 0) {
- return rc;
+ res.app_status = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_CONFIRM_SZ);
+ if (res.app_status != 0) {
+ return res.app_status;
}
ble_l2cap_sm_pair_confirm_parse((*om)->om_data, (*om)->om_len, &cmd);
@@ -1911,20 +1779,18 @@ ble_l2cap_sm_rx_pair_confirm(uint16_t conn_handle, uint8_t op,
proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_CONFIRM,
-1, &prev);
if (proc != NULL) {
- rc = ble_l2cap_sm_confirm_handle(proc, &cmd, &sm_status);
- if (rc != 0) {
- ble_l2cap_sm_proc_remove(proc, prev);
- ble_l2cap_sm_pair_fail_tx(conn_handle, sm_status);
- }
+ memset(&res, 0, sizeof res);
+ ble_l2cap_sm_confirm_handle(proc, &cmd, &res);
}
ble_hs_unlock();
- if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- ble_l2cap_sm_proc_free(proc);
+ if (proc == NULL) {
+ return BLE_HS_ENOENT;
}
- return rc;
+ ble_l2cap_sm_process_result(conn_handle, &res);
+
+ return res.app_status;
}
static int
@@ -1932,13 +1798,11 @@ ble_l2cap_sm_rx_pair_random(uint16_t conn_handle, uint8_t op,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_random cmd;
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
struct ble_l2cap_sm_proc *prev;
- uint8_t sm_status;
int rc;
- sm_status = 0; /* Silence gcc warning. */
-
rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_RANDOM_SZ);
if (rc != 0) {
return rc;
@@ -1952,20 +1816,18 @@ ble_l2cap_sm_rx_pair_random(uint16_t conn_handle, uint8_t op,
proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_RANDOM,
-1, &prev);
if (proc != NULL) {
- rc = ble_l2cap_sm_random_handle(proc, &cmd, &sm_status);
- if (rc != 0) {
- ble_l2cap_sm_proc_remove(proc, prev);
- ble_l2cap_sm_pair_fail_tx(conn_handle, sm_status);
- }
+ memset(&res, 0, sizeof res);
+ ble_l2cap_sm_random_handle(proc, &cmd, &res);
}
ble_hs_unlock();
- if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- ble_l2cap_sm_proc_free(proc);
+ if (proc == NULL) {
+ return BLE_HS_ENOENT;
}
- return rc;
+ ble_l2cap_sm_process_result(conn_handle, &res);
+
+ return res.app_status;
}
static int
@@ -1973,8 +1835,7 @@ ble_l2cap_sm_rx_pair_fail(uint16_t conn_handle, uint8_t op,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_fail cmd;
- struct ble_l2cap_sm_proc *proc;
- struct ble_l2cap_sm_proc *prev;
+ struct ble_l2cap_sm_result res;
int rc;
rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_FAIL_SZ);
@@ -1986,32 +1847,18 @@ ble_l2cap_sm_rx_pair_fail(uint16_t conn_handle, uint8_t op,
BLE_HS_LOG(DEBUG, "rxed sm fail cmd; reason=%d\n", cmd.reason);
- ble_hs_lock();
- proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
- -1, &prev);
- if (proc != NULL) {
- ble_l2cap_sm_proc_remove(proc, prev);
- }
- ble_hs_unlock();
-
- if (proc == NULL) {
- return BLE_HS_ENOENT;
- }
-
- ble_l2cap_sm_gap_event(proc, BLE_HS_SM_THEM_ERR(cmd.reason), 0);
- ble_l2cap_sm_proc_free(proc);
+ memset(&res, 0, sizeof res);
+ res.app_status = BLE_HS_SM_THEM_ERR(cmd.reason),
+ ble_l2cap_sm_process_result(conn_handle, &res);
return 0;
}
static int
-ble_l2cap_sm_lt_key_req_ltk_handle(struct hci_le_lt_key_req *evt)
+ble_l2cap_sm_retrieve_ltk(struct hci_le_lt_key_req *evt,
+ struct ble_store_value_sec *value_sec)
{
- struct ble_store_value_sec value_sec;
struct ble_store_key_sec key_sec;
- struct ble_l2cap_sm_proc *proc;
- struct ble_l2cap_sm_proc *prev;
- int store_rc;
int rc;
/* Tell application to look up LTK by ediv/rand pair. */
@@ -2021,145 +1868,27 @@ ble_l2cap_sm_lt_key_req_ltk_handle(struct hci_le_lt_key_req *evt)
key_sec.ediv = evt->encrypted_diversifier;
key_sec.rand_num = evt->random_number;
key_sec.ediv_rand_present = 1;
- store_rc = ble_store_read_slv_sec(&key_sec, &value_sec);
- if (store_rc == 0) {
- /* Store provided a key; send it to the controller. */
- rc = ble_l2cap_sm_lt_key_req_reply_tx(evt->connection_handle,
- value_sec.ltk);
- } else {
- /* Application does not have the requested key in its database. Send a
- * negative reply to the controller.
- */
- rc = ble_l2cap_sm_lt_key_req_neg_reply_tx(evt->connection_handle);
- }
-
- ble_hs_lock();
- proc = ble_l2cap_sm_proc_find(evt->connection_handle,
- BLE_L2CAP_SM_PROC_STATE_LTK, 0,
- &prev);
- if (proc == NULL) {
- rc = BLE_HS_EUNKNOWN;
- } else if (store_rc == 0 && rc == 0) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE;
- if (value_sec.authenticated) {
- proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
- }
- } else {
- ble_l2cap_sm_proc_remove(proc, prev);
- }
- ble_hs_unlock();
-
- /* Notify the app if it provided a key and the procedure failed. */
- if (store_rc == 0 && rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- }
-
- /* The procedure is aborted if the app didn't provide a key or if there was
- * a failure.
- */
- if (store_rc != 0 || rc != 0) {
- ble_l2cap_sm_proc_free(proc);
- }
-
- return rc;
-}
-
-static int
-ble_l2cap_sm_rx_public_key(uint16_t conn_handle, uint8_t op,
- struct os_mbuf **om)
-{
- struct ble_l2cap_sm_public_key cmd;
- struct ble_l2cap_sm_proc *proc;
- struct ble_l2cap_sm_proc *prev;
- int rc;
-
- rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PUBLIC_KEY_SZ);
- if (rc != 0) {
- return rc;
- }
-
- ble_l2cap_sm_public_key_parse((*om)->om_data, (*om)->om_len, &cmd);
-
- BLE_HS_LOG(DEBUG, "rxed sm public key cmd\n");
-
- ble_hs_lock();
- proc = ble_l2cap_sm_proc_find(conn_handle,
- BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY,
- -1, &prev);
- if (proc != NULL) {
- rc = ble_l2cap_sm_public_key_handle(proc, &cmd);
- if (rc != 0) {
- ble_l2cap_sm_proc_remove(proc, prev);
- ble_l2cap_sm_pair_fail_tx(conn_handle,
- BLE_L2CAP_SM_ERR_UNSPECIFIED);
- }
- }
- ble_hs_unlock();
-
- if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- ble_l2cap_sm_proc_free(proc);
- }
-
- return rc;
-}
-
-static int
-ble_l2cap_sm_rx_dhkey_check(uint16_t conn_handle, uint8_t op,
- struct os_mbuf **om)
-{
- struct ble_l2cap_sm_dhkey_check cmd;
- struct ble_l2cap_sm_proc *proc;
- struct ble_l2cap_sm_proc *prev;
- uint8_t sm_status;
- int rc;
-
- rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_DHKEY_CHECK_SZ);
- if (rc != 0) {
- return rc;
- }
-
- rc = ble_l2cap_sm_dhkey_check_parse((*om)->om_data, (*om)->om_len, &cmd);
- if (rc != 0) {
- return rc;
- }
-
- BLE_HS_LOG(DEBUG, "rxed sm dhkey check cmd\n");
-
- ble_hs_lock();
- proc = ble_l2cap_sm_proc_find(conn_handle,
- BLE_L2CAP_SM_PROC_STATE_DHKEY_CHECK,
- -1, &prev);
- if (proc != NULL) {
- rc = ble_l2cap_sm_dhkey_check_handle(proc, &cmd, &sm_status);
- if (rc != 0) {
- ble_l2cap_sm_proc_remove(proc, prev);
- ble_l2cap_sm_pair_fail_tx(conn_handle, sm_status);
- }
- }
- ble_hs_unlock();
-
- if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- ble_l2cap_sm_proc_free(proc);
- }
+ rc = ble_store_read_slv_sec(&key_sec, value_sec);
return rc;
}
int
ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
{
+ struct ble_store_value_sec value_sec;
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
- struct ble_l2cap_sm_proc *prev;
+ void *arg;
+ int store_rc;
int bonding;
- int rc;
- rc = 0; /* Silence spurious gcc warning. */
+ memset(&res, 0, sizeof res);
+ arg = NULL;
ble_hs_lock();
proc = ble_l2cap_sm_proc_find(evt->connection_handle,
- BLE_L2CAP_SM_PROC_STATE_NONE, 0, &prev);
+ BLE_L2CAP_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
@@ -2169,9 +1898,11 @@ ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
/* XXX: Ensure we are the master. */
bonding = 1;
proc = ble_l2cap_sm_proc_alloc();
- if (proc != NULL) {
+ if (proc == NULL) {
+ res.app_status = BLE_HS_ENOMEM;
+ } else {
proc->conn_handle = evt->connection_handle;
- proc->state = BLE_L2CAP_SM_PROC_STATE_LTK;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_LTK_RESTORE;
proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
ble_l2cap_sm_insert(proc);
}
@@ -2180,83 +1911,95 @@ ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
* sending a security request.
*/
bonding = 1;
- proc->state = BLE_L2CAP_SM_PROC_STATE_LTK;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_LTK_RESTORE;
proc->flags |= BLE_L2CAP_SM_PROC_F_BONDED;
- } else if (proc->state == BLE_L2CAP_SM_PROC_STATE_LTK) {
+ } else if (proc->state == BLE_L2CAP_SM_PROC_STATE_LTK_START) {
/* Short-term key pairing just completed. Send the short term key to
* the controller.
*/
bonding = 0;
- rc = ble_l2cap_sm_lt_key_req_stk_handle(proc, evt);
} else {
/* The request is unexpected. Quietly ignore it. */
- bonding = 0;
- rc = 0;
- }
-
- if (proc != NULL) {
- ble_l2cap_sm_proc_set_timer(proc);
+ proc = NULL;
}
ble_hs_unlock();
+ if (proc == NULL) {
+ return res.app_status;
+ }
+
if (bonding) {
- if (proc == NULL) {
- rc = BLE_HS_ENOMEM;
- } else {
- rc = ble_l2cap_sm_lt_key_req_ltk_handle(evt);
+ store_rc = ble_l2cap_sm_retrieve_ltk(evt, &value_sec);
+ if (store_rc == 0) {
+ arg = &value_sec;
}
- } else if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- ble_l2cap_sm_proc_free(proc);
}
- return rc;
+ if (res.app_status == 0) {
+ ble_hs_lock();
+
+ proc = ble_l2cap_sm_proc_find(evt->connection_handle,
+ BLE_L2CAP_SM_PROC_STATE_NONE, 0, NULL);
+ if (proc != NULL) {
+ ble_l2cap_sm_go(proc, &res, arg);
+ }
+
+ ble_hs_unlock();
+ }
+
+ ble_l2cap_sm_process_result(evt->connection_handle, &res);
+
+ return 0;
}
void
ble_l2cap_sm_rx_encryption_change(struct hci_encrypt_change *evt)
{
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
struct ble_l2cap_sm_proc *prev;
int enc_enabled = 0;
int do_key_exchange = 0;
- int rc;
- uint8_t sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- int complete;
+
+ memset(&res, 0, sizeof res);
ble_hs_lock();
proc = ble_l2cap_sm_proc_find(evt->connection_handle,
- BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE, -1,
+ BLE_L2CAP_SM_PROC_STATE_NONE, -1,
&prev);
if (proc == NULL) {
- rc = BLE_HS_ENOENT;
- } else {
+ res.app_status = BLE_HS_ENOENT;
+ } else if (proc->state == BLE_L2CAP_SM_PROC_STATE_ENC_START) {
enc_enabled = evt->encryption_enabled & 0x01; /* LE bit. */
- do_key_exchange = (proc->flags & BLE_L2CAP_SM_PROC_F_KEY_EXCHANGE);
- rc = 0;
+ do_key_exchange = proc->flags & BLE_L2CAP_SM_PROC_F_KEY_EXCHANGE;
+ res.app_status = 0;
+ } else if (proc->state == BLE_L2CAP_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 (do_key_exchange && enc_enabled) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_KEY_EXCH;
+ if (proc != NULL) {
+ if (do_key_exchange && enc_enabled) {
+ proc->state = BLE_L2CAP_SM_PROC_STATE_KEY_EXCH;
- /* The responder sends its keys first. */
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
- rc = ble_l2cap_sm_key_exchange_go(proc, &sm_status);
+ /* The responder sends its keys first. */
+ if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
+ ble_l2cap_sm_go(proc, &res, NULL);
+ }
+ } else {
+ proc->state = BLE_L2CAP_SM_PROC_STATE_NONE;
+ res.do_cb = 1;
}
}
- complete = proc != NULL && (rc != 0 || !do_key_exchange || !enc_enabled);
- if (complete) {
- ble_l2cap_sm_proc_remove(proc, prev);
- }
-
ble_hs_unlock();
- if (complete) {
- ble_l2cap_sm_gap_event(proc, BLE_HS_HCI_ERR(evt->status), enc_enabled);
- ble_l2cap_sm_proc_free(proc);
- }
+ ble_l2cap_sm_process_result(evt->connection_handle, &res);
}
static int
@@ -2396,45 +2139,46 @@ ble_l2cap_sm_heartbeat(void)
int
ble_l2cap_sm_pair_initiate(uint16_t conn_handle)
{
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
- int rc;
/* 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);
if (proc != NULL) {
- rc = BLE_HS_EALREADY;
- goto done;
- }
+ res.app_status = BLE_HS_EALREADY;
- 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_PAIR;
- proc->flags |= BLE_L2CAP_SM_PROC_F_INITIATOR;
+ /* Set pointer to null so that existing entry doesn't get freed. */
+ proc = NULL;
+ } else {
+ proc = ble_l2cap_sm_proc_alloc();
+ if (proc == NULL) {
+ res.app_status = BLE_HS_ENOMEM;
+ } else {
+ proc->conn_handle = conn_handle;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_PAIR;
+ proc->flags |= BLE_L2CAP_SM_PROC_F_INITIATOR;
+ ble_l2cap_sm_insert(proc);
- rc = ble_l2cap_sm_pair_go(proc);
- if (rc != 0) {
- ble_l2cap_sm_proc_free(proc);
- goto done;
+ ble_l2cap_sm_go(proc, &res, NULL);
+ }
}
- ble_l2cap_sm_insert(proc);
-
-done:
ble_hs_unlock();
- return rc;
+
+ if (proc != NULL) {
+ ble_l2cap_sm_process_result(conn_handle, &res);
+ }
+
+ return res.app_status;
}
int
ble_l2cap_sm_slave_initiate(uint16_t conn_handle)
{
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
- int rc;
ble_hs_lock();
@@ -2442,29 +2186,30 @@ ble_l2cap_sm_slave_initiate(uint16_t conn_handle)
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;
- }
+ res.app_status = BLE_HS_EALREADY;
- 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;
+ /* Set pointer to null so that existing entry doesn't get freed. */
+ proc = NULL;
+ } else {
+ proc = ble_l2cap_sm_proc_alloc();
+ if (proc == NULL) {
+ res.app_status = BLE_HS_ENOMEM;
+ } else {
+ proc->conn_handle = conn_handle;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_SEC_REQ;
+ ble_l2cap_sm_insert(proc);
- rc = ble_l2cap_sm_sec_req_go(proc);
- if (rc != 0) {
- ble_l2cap_sm_proc_free(proc);
- goto done;
+ ble_l2cap_sm_go(proc, &res, NULL);
+ }
}
- ble_l2cap_sm_insert(proc);
-
-done:
ble_hs_unlock();
- return rc;
+
+ if (proc != NULL) {
+ ble_l2cap_sm_process_result(conn_handle, &res);
+ }
+
+ return res.app_status;
}
/**
@@ -2477,43 +2222,47 @@ ble_l2cap_sm_enc_initiate(uint16_t conn_handle,
uint64_t rand_val,
int auth)
{
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
- int rc;
+ struct hci_start_encrypt cmd;
+
+ memset(&res, 0, sizeof res);
/* 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);
if (proc != NULL) {
- rc = BLE_HS_EALREADY;
- goto sec_initiate_done;
- }
-
- proc = ble_l2cap_sm_proc_alloc();
- if (proc == NULL) {
- rc = BLE_HS_ENOMEM;
- goto sec_initiate_done;
- }
- proc->conn_handle = conn_handle;
- proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE;
- proc->flags |= BLE_L2CAP_SM_PROC_F_INITIATOR;
+ res.app_status = BLE_HS_EALREADY;
- /* use the authenticated state of the key provided */
- if (auth) {
- proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
- }
+ /* Set pointer to null so that existing entry doesn't get freed. */
+ proc = NULL;
+ } else {
+ proc = ble_l2cap_sm_proc_alloc();
+ if (proc == NULL) {
+ res.app_status = BLE_HS_ENOMEM;
+ } else {
+ proc->conn_handle = conn_handle;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_RESTORE;
+ proc->flags |= BLE_L2CAP_SM_PROC_F_INITIATOR;
+ if (auth) {
+ proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
+ }
+ ble_l2cap_sm_insert(proc);
- rc = ble_l2cap_sm_start_encrypt_tx(proc->conn_handle, ediv, rand_val, ltk);
- if (rc != 0) {
- ble_l2cap_sm_proc_free(proc);
- goto sec_initiate_done;
+ cmd.connection_handle = conn_handle;
+ cmd.encrypted_diversifier = ediv;
+ cmd.random_number = rand_val;
+ memcpy(cmd.long_term_key, ltk, sizeof cmd.long_term_key);
+ ble_l2cap_sm_go(proc, &res, &cmd);
+ }
}
+
+ ble_hs_unlock();
- ble_l2cap_sm_insert(proc);
+ ble_l2cap_sm_process_result(conn_handle, &res);
-sec_initiate_done:
- ble_hs_unlock();
- return rc;
+ return res.app_status;
}
struct ble_l2cap_chan *
@@ -2537,10 +2286,11 @@ ble_l2cap_sm_create_chan(void)
int
ble_l2cap_sm_set_tk(uint16_t conn_handle, struct ble_l2cap_sm_passkey *pkey)
{
+ struct ble_l2cap_sm_result res;
struct ble_l2cap_sm_proc *proc;
struct ble_l2cap_sm_proc *prev;
- int rc = 0;
- int sm_error = 0;
+
+ memset(&res, 0, sizeof res);
ble_hs_lock();
@@ -2548,19 +2298,19 @@ ble_l2cap_sm_set_tk(uint16_t conn_handle, struct ble_l2cap_sm_passkey *pkey)
-1, &prev);
if (proc == NULL) {
- rc = BLE_HS_ENOENT;
+ res.app_status = BLE_HS_ENOENT;
goto set_tk_return;
}
/* Do we already have a valid TK? */
if (proc->flags & BLE_L2CAP_SM_PROC_F_TK_VALID) {
- rc = BLE_HS_EALREADY;
+ res.app_status = BLE_HS_EALREADY;
goto set_tk_return;
}
/* Is the response of the right type? Must match what we asked for. */
if (pkey->action != ble_l2cap_sm_passkey_action(proc)) {
- rc = BLE_HS_EINVAL;
+ res.app_status = BLE_HS_EINVAL;
goto set_tk_return;
}
@@ -2568,14 +2318,14 @@ ble_l2cap_sm_set_tk(uint16_t conn_handle, struct ble_l2cap_sm_passkey *pkey)
switch (pkey->action) {
case BLE_GAP_PKACT_OOB:
memcpy(proc->tk, pkey->oob, 16);
- sm_error = BLE_L2CAP_SM_ERR_OOB;
+ res.sm_err = BLE_L2CAP_SM_ERR_OOB;
break;
case BLE_GAP_PKACT_INPUT:
case BLE_GAP_PKACT_DISP:
- sm_error = BLE_L2CAP_SM_ERR_PASSKEY;
+ res.sm_err = BLE_L2CAP_SM_ERR_PASSKEY;
if (pkey->passkey > 999999) {
- rc = BLE_HS_EINVAL;
+ res.app_status = BLE_HS_EINVAL;
goto set_tk_return;
}
memset(proc->tk, 0, 16);
@@ -2586,71 +2336,49 @@ ble_l2cap_sm_set_tk(uint16_t conn_handle, struct ble_l2cap_sm_passkey *pkey)
break;
default:
- sm_error = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- rc = BLE_HS_EINVAL;
+ res.sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ res.app_status = BLE_HS_EINVAL;
goto set_tk_return;
}
proc->flags |= BLE_L2CAP_SM_PROC_F_TK_VALID;
- rc = 0;
/* If we are the initiator, its time to send the confirm. If we are the
- * responder, we check whether or not we received the confirm yet. All of
- * this has to be in the confirmed state.
+ * responder, we check whether or not we received the confirm yet.
*/
- if (proc->state == BLE_L2CAP_SM_PROC_STATE_CONFIRM) {
- if (proc->flags & (BLE_L2CAP_SM_PROC_F_INITIATOR |
- BLE_L2CAP_SM_PROC_F_RX_CONFIRM)) {
-
- rc = ble_l2cap_sm_confirm_go(proc);
- if (rc != 0) {
- goto set_tk_return;
- }
+ if (proc->flags & (BLE_L2CAP_SM_PROC_F_INITIATOR |
+ BLE_L2CAP_SM_PROC_F_RX_CONFIRM)) {
- /* Only the responder changes state here. */
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
- proc->state = BLE_L2CAP_SM_PROC_STATE_RANDOM;
- }
+ ble_l2cap_sm_go(proc, &res, NULL);
+ if (res.app_status != 0) {
+ goto set_tk_return;
}
}
set_tk_return:
- if (proc != NULL && rc != 0) {
- ble_l2cap_sm_proc_remove(proc, prev);
- ble_l2cap_sm_pair_fail_tx(conn_handle, sm_error);
- }
-
ble_hs_unlock();
- if (proc != NULL && rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- ble_l2cap_sm_proc_free(proc);
- }
-
- return rc;
+ ble_l2cap_sm_process_result(conn_handle, &res);
+ return res.app_status;
}
void
ble_l2cap_sm_connection_broken(uint16_t conn_handle)
{
- struct ble_l2cap_sm_proc *proc;
- struct ble_l2cap_sm_proc *prev;
+ struct ble_l2cap_sm_result res;
- ble_hs_lock();
- proc = ble_l2cap_sm_proc_find(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
- -1, &prev);
- if (proc != NULL) {
- /* Free the affected procedure object and notify the application of the
- * failure.
- */
- ble_l2cap_sm_proc_remove(proc, prev);
- }
- ble_hs_unlock();
+ memset(&res, 0, sizeof res);
+ res.app_status = BLE_HS_ENOTCONN;
+ res.do_cb = 1;
- if (proc != NULL) {
- ble_l2cap_sm_gap_event(proc, BLE_HS_ENOTCONN, 0);
- ble_l2cap_sm_proc_free(proc);
- }
+ ble_l2cap_sm_process_result(conn_handle, &res);
+}
+
+static void
+ble_l2cap_sm_free_mem(void)
+{
+ free(ble_l2cap_sm_proc_mem);
+ free(ble_l2cap_sm_key_mem);
}
int
@@ -2658,7 +2386,7 @@ ble_l2cap_sm_init(void)
{
int rc;
- free(ble_l2cap_sm_proc_mem);
+ ble_l2cap_sm_free_mem();
STAILQ_INIT(&ble_l2cap_sm_procs);
@@ -2670,7 +2398,6 @@ ble_l2cap_sm_init(void)
rc = BLE_HS_ENOMEM;
goto err;
}
-
rc = os_mempool_init(&ble_l2cap_sm_proc_pool,
ble_hs_cfg.max_l2cap_sm_procs,
sizeof (struct ble_l2cap_sm_proc),
@@ -2679,12 +2406,28 @@ ble_l2cap_sm_init(void)
if (rc != 0) {
goto err;
}
+
+ ble_l2cap_sm_key_mem = malloc(
+ OS_MEMPOOL_BYTES(ble_hs_cfg.max_l2cap_sm_procs * 2,
+ sizeof (struct ble_l2cap_sm_keys)));
+ if (ble_l2cap_sm_key_mem == NULL) {
+ rc = BLE_HS_ENOMEM;
+ goto err;
+ }
+ rc = os_mempool_init(&ble_l2cap_sm_key_pool,
+ ble_hs_cfg.max_l2cap_sm_procs * 2,
+ sizeof (struct ble_l2cap_sm_keys),
+ ble_l2cap_sm_key_mem,
+ "ble_l2cap_sm_key_pool");
+ if (rc != 0) {
+ goto err;
+ }
}
return 0;
err:
- free(ble_l2cap_sm_proc_mem);
+ ble_l2cap_sm_free_mem();
return rc;
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/023769e4/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 c776208..d199423 100644
--- a/net/nimble/host/src/ble_l2cap_sm_cmd.c
+++ b/net/nimble/host/src/ble_l2cap_sm_cmd.c
@@ -287,6 +287,7 @@ ble_l2cap_sm_pair_fail_write(void *payload, int len,
u8ptr[1] = cmd->reason;
}
+/* XXX: Should not require locked. */
int
ble_l2cap_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason)
{
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/023769e4/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 f02556c..dfcb3eb 100644
--- a/net/nimble/host/src/ble_l2cap_sm_priv.h
+++ b/net/nimble/host/src/ble_l2cap_sm_priv.h
@@ -20,10 +20,13 @@
#ifndef H_BLE_L2CAP_SM_
#define H_BLE_L2CAP_SM_
+#include <inttypes.h>
+#include "os/queue.h"
#include "nimble/nimble_opt.h"
struct ble_gap_sec_state;
struct hci_le_lt_key_req;
+struct hci_encrypt_change;
#define BLE_L2CAP_SM_MTU 65
@@ -185,13 +188,15 @@ struct ble_l2cap_sm_dhkey_check {
#define BLE_L2CAP_SM_PROC_STATE_PAIR 0
#define BLE_L2CAP_SM_PROC_STATE_CONFIRM 1
#define BLE_L2CAP_SM_PROC_STATE_RANDOM 2
-#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_SEC_REQ 6
-#define BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY 7
-#define BLE_L2CAP_SM_PROC_STATE_DHKEY_CHECK 8
-#define BLE_L2CAP_SM_PROC_STATE_CNT 9
+#define BLE_L2CAP_SM_PROC_STATE_LTK_START 3
+#define BLE_L2CAP_SM_PROC_STATE_LTK_RESTORE 4
+#define BLE_L2CAP_SM_PROC_STATE_ENC_START 5
+#define BLE_L2CAP_SM_PROC_STATE_ENC_RESTORE 6
+#define BLE_L2CAP_SM_PROC_STATE_KEY_EXCH 7
+#define BLE_L2CAP_SM_PROC_STATE_SEC_REQ 8
+#define BLE_L2CAP_SM_PROC_STATE_PUBLIC_KEY 9
+#define BLE_L2CAP_SM_PROC_STATE_DHKEY_CHECK 10
+#define BLE_L2CAP_SM_PROC_STATE_CNT 11
#define BLE_L2CAP_SM_PROC_F_INITIATOR 0x01
#define BLE_L2CAP_SM_PROC_F_TK_VALID 0x02
@@ -247,9 +252,18 @@ struct ble_l2cap_sm_proc {
uint8_t ltk[16];
uint8_t mackey[16];
- /* this may be temporary, but we keep the keys here for now */
- struct ble_l2cap_sm_keys our_keys;
- struct ble_l2cap_sm_keys peer_keys;
+ uint16_t ediv;
+ uint64_t rand_num;
+
+ struct ble_l2cap_sm_keys *our_keys;
+ struct ble_l2cap_sm_keys *peer_keys;
+};
+
+struct ble_l2cap_sm_result {
+ int app_status;
+ uint8_t sm_err;
+ unsigned do_tx:1;
+ unsigned do_cb:1;
};
#ifdef BLE_HS_DEBUG
@@ -351,12 +365,48 @@ int ble_l2cap_sm_dhkey_check_tx(uint16_t conn_handle,
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);
+int ble_sm_lgcy_next_state(struct ble_l2cap_sm_proc *proc);
+int ble_sm_lgcy_passkey_action(struct ble_l2cap_sm_proc *proc);
+void ble_sm_lgcy_confirm_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res);
+void ble_sm_lgcy_random_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res);
+void ble_sm_lgcy_random_handle(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res);
+
+int ble_sm_sc_next_state(struct ble_l2cap_sm_proc *proc);
+int ble_sm_sc_passkey_action(struct ble_l2cap_sm_proc *proc);
+void ble_sm_sc_confirm_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res);
+void ble_sm_sc_random_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res);
+void ble_sm_sc_random_handle(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res);
+void ble_sm_sc_public_key_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res,
+ void *arg);
+void ble_sm_sc_public_key_handle(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_public_key *cmd,
+ struct ble_l2cap_sm_result *res);
+int ble_sm_sc_rx_public_key(uint16_t conn_handle, uint8_t op,
+ struct os_mbuf **om);
+void ble_sm_sc_dhkey_check_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res, void *arg);
+int ble_sm_sc_rx_dhkey_check(uint16_t conn_handle, uint8_t op,
+ struct os_mbuf **om);
+
+struct ble_l2cap_sm_proc *
+ble_l2cap_sm_proc_find(uint16_t conn_handle, uint8_t state, int is_initiator,
+ struct ble_l2cap_sm_proc **out_prev);
+int ble_l2cap_sm_gen_pub_priv(struct ble_l2cap_sm_proc *proc,
+ uint8_t *pub, uint8_t *priv);
uint8_t *ble_l2cap_sm_our_pair_rand(struct ble_l2cap_sm_proc *proc);
uint8_t *ble_l2cap_sm_their_pair_rand(struct ble_l2cap_sm_proc *proc);
-int ble_sm_lgcy_confirm_go(struct ble_l2cap_sm_proc *proc);
-int ble_sm_lgcy_random_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_pair_random *cmd,
- uint8_t *out_sm_status);
+void ble_l2cap_sm_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res,
+ void *arg);
+void ble_l2cap_sm_process_result(uint16_t conn_handle,
+ struct ble_l2cap_sm_result *res);
void ble_l2cap_sm_heartbeat(void);
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/023769e4/net/nimble/host/src/ble_sm_lgcy.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_sm_lgcy.c b/net/nimble/host/src/ble_sm_lgcy.c
index 32d2c7f..01a09bd 100644
--- a/net/nimble/host/src/ble_sm_lgcy.c
+++ b/net/nimble/host/src/ble_sm_lgcy.c
@@ -24,6 +24,81 @@
#include "nimble/nimble_opt.h"
#include "ble_hs_priv.h"
+/**
+ * Create some shortened names for the passkey actions so that the table is
+ * easier to read.
+ */
+#define PKACT_NONE BLE_GAP_PKACT_NONE
+#define PKACT_OOB BLE_GAP_PKACT_OOB
+#define PKACT_INPUT BLE_GAP_PKACT_INPUT
+#define PKACT_DISP BLE_GAP_PKACT_DISP
+
+/* This is the initiator passkey action action dpeneding on the io
+ * capabilties of both parties
+ */
+static const uint8_t ble_sm_lgcy_init_pka[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},
+};
+
+/* This is the initiator passkey action action depending on the io
+ * capabilities of both parties */
+static const uint8_t ble_sm_lgcy_resp_pka[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},
+};
+
+int
+ble_sm_lgcy_passkey_action(struct ble_l2cap_sm_proc *proc)
+{
+ int action;
+
+ if (proc->pair_req.oob_data_flag && proc->pair_rsp.oob_data_flag) {
+ action = BLE_GAP_PKACT_OOB;
+ } else if (!(proc->pair_req.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_MITM) ||
+ !(proc->pair_rsp.authreq & BLE_L2CAP_SM_PAIR_AUTHREQ_MITM)) {
+
+ action = BLE_GAP_PKACT_NONE;
+ } else if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
+ action = ble_sm_lgcy_init_pka[proc->pair_req.io_cap]
+ [proc->pair_rsp.io_cap];
+ } else {
+ action = ble_sm_lgcy_resp_pka[proc->pair_req.io_cap]
+ [proc->pair_rsp.io_cap];
+ }
+
+ switch (action) {
+ case BLE_GAP_PKACT_NONE:
+ proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_JW;
+ break;
+
+ case BLE_GAP_PKACT_OOB:
+ proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_OOB;
+ proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
+ break;
+
+ case BLE_GAP_PKACT_INPUT:
+ case BLE_GAP_PKACT_DISP:
+ proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_PASSKEY;
+ proc->flags |= BLE_L2CAP_SM_PROC_F_AUTHENTICATED;
+ break;
+
+ default:
+ BLE_HS_DBG_ASSERT(0);
+ break;
+ }
+
+ return action;
+}
+
static int
ble_sm_lgcy_confirm_prepare_args(struct ble_l2cap_sm_proc *proc,
uint8_t *k, uint8_t *preq, uint8_t *pres,
@@ -68,8 +143,9 @@ ble_sm_lgcy_confirm_prepare_args(struct ble_l2cap_sm_proc *proc,
return 0;
}
-int
-ble_sm_lgcy_confirm_go(struct ble_l2cap_sm_proc *proc)
+void
+ble_sm_lgcy_confirm_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res)
{
struct ble_l2cap_sm_pair_confirm cmd;
uint8_t preq[BLE_L2CAP_SM_HDR_SZ + BLE_L2CAP_SM_PAIR_CMD_SZ];
@@ -81,24 +157,35 @@ ble_sm_lgcy_confirm_go(struct ble_l2cap_sm_proc *proc)
uint8_t rat;
int rc;
+ res->do_tx = 0;
+
rc = ble_sm_lgcy_confirm_prepare_args(proc, k, preq, pres,
&iat, &rat, ia, ra);
if (rc != 0) {
- return rc;
+ goto err;
}
rc = ble_l2cap_sm_alg_c1(k, ble_l2cap_sm_our_pair_rand(proc),
preq, pres, iat, rat, ia, ra, cmd.value);
if (rc != 0) {
- return rc;
+ goto err;
}
rc = ble_l2cap_sm_pair_confirm_tx(proc->conn_handle, &cmd);
if (rc != 0) {
- return rc;
+ goto err;
}
- return 0;
+ if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
+ proc->state = BLE_L2CAP_SM_PROC_STATE_RANDOM;
+ }
+
+ return;
+
+err:
+ res->app_status = rc;
+ res->do_cb = 1;
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
}
static int
@@ -117,11 +204,33 @@ ble_l2cap_sm_gen_stk(struct ble_l2cap_sm_proc *proc)
return 0;
}
-int
+void
+ble_sm_lgcy_random_go(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_result *res)
+{
+ struct ble_l2cap_sm_pair_random cmd;
+ int rc;
+
+ memcpy(cmd.value, ble_l2cap_sm_our_pair_rand(proc), 16);
+
+ rc = ble_l2cap_sm_pair_random_tx(proc->conn_handle, &cmd);
+ if (rc != 0) {
+ res->app_status = rc;
+ res->do_cb = 1;
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return;
+ }
+
+ if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
+ proc->state = BLE_L2CAP_SM_PROC_STATE_LTK_START;
+ }
+}
+
+void
ble_sm_lgcy_random_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_pair_random *cmd,
- uint8_t *out_sm_status)
+ struct ble_l2cap_sm_result *res)
{
+ struct hci_start_encrypt enc_cmd;
uint8_t preq[BLE_L2CAP_SM_HDR_SZ + BLE_L2CAP_SM_PAIR_CMD_SZ];
uint8_t pres[BLE_L2CAP_SM_HDR_SZ + BLE_L2CAP_SM_PAIR_CMD_SZ];
uint8_t confirm_val[16];
@@ -135,30 +244,36 @@ ble_sm_lgcy_random_handle(struct ble_l2cap_sm_proc *proc,
rc = ble_sm_lgcy_confirm_prepare_args(proc, k, preq, pres,
&iat, &rat, ia, ra);
if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ res->app_status = rc;
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ res->do_cb = 1;
+ return;
}
- rc = ble_l2cap_sm_alg_c1(k, cmd->value, preq, pres, iat, rat,
- ia, ra, confirm_val);
+ rc = ble_l2cap_sm_alg_c1(k, ble_l2cap_sm_their_pair_rand(proc), preq, pres,
+ iat, rat, ia, ra, confirm_val);
if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ res->app_status = rc;
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ res->do_cb = 1;
+ return;
}
if (memcmp(proc->confirm_their, confirm_val, 16) != 0) {
/* Random number mismatch. */
- *out_sm_status = BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH;
- return BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH);
+ res->app_status = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH);
+ res->sm_err = BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH;
+ res->do_cb = 1;
+ return;
}
- memcpy(ble_l2cap_sm_their_pair_rand(proc), cmd->value, 16);
-
/* Generate the key. */
rc = ble_l2cap_sm_gen_stk(proc);
if (rc != 0) {
- *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
- return rc;
+ res->app_status = rc;
+ res->sm_err = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ res->do_cb = 1;
+ return;
}
if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
@@ -166,9 +281,15 @@ ble_sm_lgcy_random_handle(struct ble_l2cap_sm_proc *proc,
* short-term key generation, we always set ediv and rand to 0.
* (Vol. 3, part H, 2.4.4.1).
*/
- proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_START;
+ enc_cmd.connection_handle = proc->conn_handle;
+ enc_cmd.encrypted_diversifier = 0;
+ enc_cmd.random_number = 0;
+ memcpy(enc_cmd.long_term_key, proc->ltk,
+ sizeof enc_cmd.long_term_key);
+ ble_l2cap_sm_go(proc, res, &enc_cmd);
+ } else {
+ /* We are the repsonder; send the random response. */
+ ble_l2cap_sm_go(proc, res, NULL);
}
-
- *out_sm_status = 0;
- return 0;
}