You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by ma...@apache.org on 2016/04/28 02:14:08 UTC
[09/50] [abbrv] incubator-mynewt-core git commit: ble host - major
changes.
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e32f9f9f/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 d53124f..a2e5785 100644
--- a/net/nimble/host/src/ble_l2cap_sm.c
+++ b/net/nimble/host/src/ble_l2cap_sm.c
@@ -26,18 +26,14 @@
#if NIMBLE_OPT_SM
-#define BLE_L2CAP_SM_PROC_OP_NONE ((uint8_t)-1)
-
-#define BLE_L2CAP_SM_PROC_OP_PAIR 0
-#define BLE_L2CAP_SM_PROC_OP_CONFIRM 1
-#define BLE_L2CAP_SM_PROC_OP_RANDOM 2
-#define BLE_L2CAP_SM_PROC_OP_FAIL 3
-#define BLE_L2CAP_SM_PROC_OP_LTK 4
-#define BLE_L2CAP_SM_PROC_OP_LTK_TXED 5
-#define BLE_L2CAP_SM_PROC_OP_ENC_CHANGE 6
-#define BLE_L2CAP_SM_PROC_OP_START_ENCRYPT 7
-#define BLE_L2CAP_SM_PROC_OP_START_ENCRYPT_TXED 8
-#define BLE_L2CAP_SM_PROC_OP_CNT 9
+#define BLE_L2CAP_SM_PROC_STATE_NONE ((uint8_t)-1)
+
+#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_CNT 5
#define BLE_L2CAP_SM_PROC_F_INITIATOR 0x01
@@ -47,10 +43,14 @@
typedef uint16_t ble_l2cap_sm_proc_flags;
struct ble_l2cap_sm_proc {
- struct ble_fsm_proc fsm_proc;
+ STAILQ_ENTRY(ble_l2cap_sm_proc) next;
+
uint32_t exp_os_ticks;
ble_l2cap_sm_proc_flags flags;
+ uint16_t conn_handle;
uint8_t pair_alg;
+ uint8_t state;
+
/* XXX: Minimum security requirements. */
@@ -66,25 +66,13 @@ struct ble_l2cap_sm_proc {
struct {
uint8_t key[16];
- uint8_t handle;
} hci;
-
- struct {
- uint8_t reason;
- } fail;
};
};
-/** Used for extracting proc entries from the fsm list. */
-struct ble_l2cap_sm_extract_arg {
- uint16_t conn_handle;
- uint8_t op;
- int8_t initiator; /* 0=no, 1=yes, -1=don't-care. */
-};
-
-typedef int ble_l2cap_sm_kick_fn(struct ble_l2cap_sm_proc *proc);
+STAILQ_HEAD(ble_l2cap_sm_proc_list, ble_l2cap_sm_proc);
-typedef int ble_l2cap_sm_rx_fn(uint16_t conn_handle, uint8_t op,
+typedef int ble_l2cap_sm_rx_fn(uint16_t conn_handle, uint8_t state,
struct os_mbuf **om);
static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_noop;
@@ -94,13 +82,6 @@ static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_pair_confirm;
static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_pair_random;
static ble_l2cap_sm_rx_fn ble_l2cap_sm_rx_pair_fail;
-static ble_l2cap_sm_kick_fn ble_l2cap_sm_pair_kick;
-static ble_l2cap_sm_kick_fn ble_l2cap_sm_confirm_kick;
-static ble_l2cap_sm_kick_fn ble_l2cap_sm_random_kick;
-static ble_l2cap_sm_kick_fn ble_l2cap_sm_fail_kick;
-static ble_l2cap_sm_kick_fn ble_l2cap_sm_lt_key_req_kick;
-static ble_l2cap_sm_kick_fn ble_l2cap_sm_start_encrypt_kick;
-
static ble_l2cap_sm_rx_fn * const ble_l2cap_sm_dispatch[] = {
[BLE_L2CAP_SM_OP_PAIR_REQ] = ble_l2cap_sm_rx_pair_req,
[BLE_L2CAP_SM_OP_PAIR_RSP] = ble_l2cap_sm_rx_pair_rsp,
@@ -118,31 +99,24 @@ static ble_l2cap_sm_rx_fn * const ble_l2cap_sm_dispatch[] = {
[BLE_L2CAP_SM_OP_PAIR_KEYPRESS_NOTIFY] = ble_l2cap_sm_rx_noop,
};
-static ble_l2cap_sm_kick_fn * const
-ble_l2cap_sm_kick[BLE_L2CAP_SM_PROC_OP_CNT] = {
- [BLE_L2CAP_SM_PROC_OP_PAIR] = ble_l2cap_sm_pair_kick,
- [BLE_L2CAP_SM_PROC_OP_CONFIRM] = ble_l2cap_sm_confirm_kick,
- [BLE_L2CAP_SM_PROC_OP_RANDOM] = ble_l2cap_sm_random_kick,
- [BLE_L2CAP_SM_PROC_OP_FAIL] = ble_l2cap_sm_fail_kick,
- [BLE_L2CAP_SM_PROC_OP_LTK] = ble_l2cap_sm_lt_key_req_kick,
- [BLE_L2CAP_SM_PROC_OP_START_ENCRYPT] = ble_l2cap_sm_start_encrypt_kick,
-};
-
-static void ble_l2cap_sm_rx_lt_key_req_reply_ack(struct ble_hci_ack *ack,
- void *arg);
-static void ble_l2cap_sm_rx_start_encrypt_ack(struct ble_hci_ack *ack,
- void *arg);
-
static void *ble_l2cap_sm_proc_mem;
static struct os_mempool ble_l2cap_sm_proc_pool;
-static struct ble_fsm ble_l2cap_sm_fsm;
+/* Maintains the list of active security manager procedures. */
+static struct ble_l2cap_sm_proc_list ble_l2cap_sm_procs;
+
+static int ble_l2cap_sm_confirm_prepare_args(struct ble_l2cap_sm_proc *proc,
+ uint8_t *k, uint8_t *preq,
+ uint8_t *pres, uint8_t *iat,
+ uint8_t *rat, uint8_t *ia,
+ uint8_t *ra);
/*****************************************************************************
* $debug *
*****************************************************************************/
#ifdef BLE_HS_DEBUG
+
static uint8_t ble_l2cap_sm_dbg_next_pair_rand[16];
static uint8_t ble_l2cap_sm_dbg_next_pair_rand_set;
static uint16_t ble_l2cap_sm_dbg_next_ediv;
@@ -175,135 +149,122 @@ ble_l2cap_sm_dbg_set_next_start_rand(uint64_t next_start_rand)
int
ble_l2cap_sm_dbg_num_procs(void)
{
- struct ble_fsm_proc *proc;
+ struct ble_l2cap_sm_proc *proc;
int cnt;
- ble_fsm_lock(&ble_l2cap_sm_fsm);
-
cnt = 0;
- STAILQ_FOREACH(proc, &ble_l2cap_sm_fsm.procs, next) {
+ STAILQ_FOREACH(proc, &ble_l2cap_sm_procs, next) {
cnt++;
}
- ble_fsm_unlock(&ble_l2cap_sm_fsm);
-
return cnt;
}
#endif
/*****************************************************************************
- * $mutex *
- *****************************************************************************/
-
-int
-ble_l2cap_sm_locked_by_cur_task(void)
-{
- return ble_fsm_locked_by_cur_task(&ble_l2cap_sm_fsm);
-}
-
-/*****************************************************************************
* $misc *
*****************************************************************************/
-static void
+static int
ble_l2cap_sm_gen_pair_rand(uint8_t *pair_rand)
{
+ int rc;
+
#ifdef BLE_HS_DEBUG
if (ble_l2cap_sm_dbg_next_pair_rand_set) {
ble_l2cap_sm_dbg_next_pair_rand_set = 0;
memcpy(pair_rand, ble_l2cap_sm_dbg_next_pair_rand,
sizeof ble_l2cap_sm_dbg_next_pair_rand);
- return;
+ return 0;
}
#endif
- /* XXX: Generate random value rather than zeros. */
- memset(pair_rand, 0, 16);
+ rc = ble_hci_util_rand(pair_rand, 16);
+ if (rc != 0) {
+ return rc;
+ }
+
+ return 0;
}
-static uint16_t
-ble_l2cap_sm_gen_ediv(void)
+static int
+ble_l2cap_sm_gen_ediv(uint16_t *ediv)
{
+ int rc;
+
#ifdef BLE_HS_DEBUG
if (ble_l2cap_sm_dbg_next_ediv_set) {
ble_l2cap_sm_dbg_next_ediv_set = 0;
- return ble_l2cap_sm_dbg_next_ediv;
+ *ediv = ble_l2cap_sm_dbg_next_ediv;
+ return 0;
}
#endif
- /* XXX: Generate random value rather than zero. */
+ rc = ble_hci_util_rand(ediv, sizeof *ediv);
+ if (rc != 0) {
+ return rc;
+ }
+
return 0;
}
-static uint64_t
-ble_l2cap_sm_gen_start_rand(void)
+static int
+ble_l2cap_sm_gen_start_rand(uint64_t *start_rand)
{
+ int rc;
+
#ifdef BLE_HS_DEBUG
if (ble_l2cap_sm_dbg_next_start_rand_set) {
ble_l2cap_sm_dbg_next_start_rand_set = 0;
- return ble_l2cap_sm_dbg_next_start_rand;
+ *start_rand = ble_l2cap_sm_dbg_next_start_rand;
+ return 0;
}
#endif
- /* XXX: Generate random value rather than zeros. */
+ rc = ble_hci_util_rand(start_rand, sizeof *start_rand);
+ if (rc != 0) {
+ return rc;
+ }
+
return 0;
}
static int
-ble_l2cap_sm_proc_kick(struct ble_fsm_proc *proc)
+ble_l2cap_sm_gen_key(struct ble_l2cap_sm_proc *proc)
{
- struct ble_l2cap_sm_proc *sm_proc;
- ble_l2cap_sm_kick_fn *kick_cb;
+ uint8_t key[16];
int rc;
- BLE_HS_DBG_ASSERT(proc->op < BLE_L2CAP_SM_PROC_OP_CNT);
- kick_cb = ble_l2cap_sm_kick[proc->op];
- BLE_HS_DBG_ASSERT(kick_cb != NULL);
+ rc = ble_l2cap_sm_alg_s1(proc->phase_1_2.tk, proc->phase_1_2.rand_our,
+ proc->phase_1_2.rand_their, key);
+ if (rc != 0) {
+ return rc;
+ }
- /* Set a timeout of 30 seconds. */
- sm_proc = (struct ble_l2cap_sm_proc *)proc;
+ memcpy(proc->hci.key, key, sizeof key);
- sm_proc->exp_os_ticks = os_time_get() + BLE_L2CAP_SM_TIMEOUT_OS_TICKS;
- rc = kick_cb(sm_proc);
+ return 0;
+}
- return rc;
+static void
+ble_l2cap_sm_proc_set_timer(struct ble_l2cap_sm_proc *proc)
+{
+ /* Set a timeout of 30 seconds. */
+ proc->exp_os_ticks = os_time_get() + BLE_L2CAP_SM_TIMEOUT_OS_TICKS;
}
/**
* Lock restrictions: None.
*/
static ble_l2cap_sm_rx_fn *
-ble_l2cap_sm_dispatch_get(uint8_t op)
+ble_l2cap_sm_dispatch_get(uint8_t state)
{
- if (op > sizeof ble_l2cap_sm_dispatch / sizeof ble_l2cap_sm_dispatch[0]) {
+ if (state > sizeof ble_l2cap_sm_dispatch / sizeof ble_l2cap_sm_dispatch[0]) {
return NULL;
}
- return ble_l2cap_sm_dispatch[op];
-}
-
-/* Indicates the handle of the specified proc's unserviced HCI reservation, if
- * any. If there is no such handle associated with the proc,
- * BLE_HCI_SCHED_HANDLE_NONE is returned.
- *
- * Lock restrictions: None.
- *
- * @param proc The proc object to query.
- *
- * @return The HCI handle, or BLE_HCI_SCHED_HANDLE_NONE.
- */
-static uint8_t
-ble_l2cap_sm_proc_outstanding_hci_handle(struct ble_l2cap_sm_proc *proc)
-{
- switch (proc->fsm_proc.op) {
- case BLE_L2CAP_SM_PROC_OP_LTK:
- case BLE_L2CAP_SM_PROC_OP_START_ENCRYPT_TXED:
- return proc->hci.handle;
-
- default:
- return BLE_HCI_SCHED_HANDLE_NONE;
- }
+ return ble_l2cap_sm_dispatch[state];
}
/**
@@ -327,269 +288,336 @@ ble_l2cap_sm_proc_alloc(void)
}
/**
- * Frees the specified proc entry. No-op if passed a null pointer.
+ * Frees the specified proc entry. No-state if passed a null pointer.
*
* Lock restrictions: None.
*/
static void
-ble_l2cap_sm_proc_free(struct ble_fsm_proc *proc)
+ble_l2cap_sm_proc_free(struct ble_l2cap_sm_proc *proc)
{
- struct ble_l2cap_sm_proc *sm_proc;
- uint8_t hci_handle;
int rc;
if (proc != NULL) {
- sm_proc = (struct ble_l2cap_sm_proc *)proc;
-
- /* If this proc has an unserviced HCI reservation, cancel it before
- * freeing the proc.
- */
- hci_handle = ble_l2cap_sm_proc_outstanding_hci_handle(sm_proc);
- if (hci_handle != BLE_HCI_SCHED_HANDLE_NONE) {
- rc = ble_hci_sched_cancel(hci_handle);
- BLE_HS_DBG_ASSERT_EVAL(rc == 0);
- }
-
rc = os_memblock_put(&ble_l2cap_sm_proc_pool, proc);
BLE_HS_DBG_ASSERT_EVAL(rc == 0);
}
}
-/**
- * Lock restrictions: None.
- */
-static int
-ble_l2cap_sm_proc_new(uint16_t conn_handle, uint8_t op,
- struct ble_l2cap_sm_proc **out_proc)
+static void
+ble_l2cap_sm_proc_insert(struct ble_l2cap_sm_proc *proc)
{
- *out_proc = ble_l2cap_sm_proc_alloc();
- if (*out_proc == NULL) {
- return BLE_HS_ENOMEM;
- }
-
- memset(*out_proc, 0, sizeof **out_proc);
- (*out_proc)->fsm_proc.op = op;
- (*out_proc)->fsm_proc.conn_handle = conn_handle;
- (*out_proc)->fsm_proc.tx_time = os_time_get();
+ ble_hs_lock();
+ STAILQ_INSERT_HEAD(&ble_l2cap_sm_procs, proc, next);
+ ble_hs_unlock();
+}
- return 0;
+static void
+ble_l2cap_sm_sec_params(struct ble_l2cap_sm_proc *proc,
+ struct ble_gap_sec_params *out_sec_params,
+ int enc_enabled)
+{
+ out_sec_params->pair_alg = proc->pair_alg;
+ out_sec_params->enc_enabled = enc_enabled;
+ out_sec_params->auth_enabled = 0; // XXX
}
-/**
- * Extraction callback used for removing all pairing procedures that have timed
- * out.
- */
-static int
-ble_l2cap_sm_proc_extract_expired_cb(struct ble_fsm_proc *proc, void *unused)
+static void
+ble_l2cap_sm_gap_event(struct ble_l2cap_sm_proc *proc, int status,
+ int enc_enabled)
{
- uint32_t now;
- int32_t diff;
+ struct ble_gap_sec_params sec_params;
- now = os_time_get();
- diff = now - ((struct ble_l2cap_sm_proc *)proc)->exp_os_ticks;
- if (diff >= 0) {
- return BLE_FSM_EXTRACT_EMOVE_CONTINUE;
+ ble_l2cap_sm_sec_params(proc, &sec_params, enc_enabled);
+ ble_gap_security_event(proc->conn_handle, status, &sec_params);
+}
+
+static void
+ble_l2cap_sm_process_status(struct ble_l2cap_sm_proc *proc, int status,
+ uint8_t sm_status, int call_cb, int tx_fail)
+{
+ if (status == 0) {
+ ble_l2cap_sm_proc_insert(proc);
} else {
- return BLE_FSM_EXTRACT_EKEEP_CONTINUE;
+ if (tx_fail) {
+ ble_l2cap_sm_pair_fail_tx(proc->conn_handle, sm_status);
+ }
+ if (call_cb) {
+ ble_l2cap_sm_gap_event(proc, status, 0);
+ }
+ ble_l2cap_sm_proc_free(proc);
}
}
static int
-ble_l2cap_sm_proc_extract_cb(struct ble_fsm_proc *proc, void *arg)
+ble_l2cap_sm_proc_matches(struct ble_l2cap_sm_proc *proc, uint16_t conn_handle,
+ uint8_t state, int is_initiator)
{
- struct ble_l2cap_sm_extract_arg *extarg;
- struct ble_l2cap_sm_proc *sm_proc;
int proc_is_initiator;
- extarg = arg;
- sm_proc = (struct ble_l2cap_sm_proc *)proc;
-
- if (extarg->conn_handle != proc->conn_handle) {
- return BLE_FSM_EXTRACT_EKEEP_CONTINUE;
+ if (conn_handle != proc->conn_handle) {
+ return 0;
}
- if (extarg->op != BLE_L2CAP_SM_PROC_OP_NONE && extarg->op != proc->op) {
- return BLE_FSM_EXTRACT_EKEEP_CONTINUE;
+ if (state != BLE_L2CAP_SM_PROC_STATE_NONE && state != proc->state) {
+ return 0;
}
- proc_is_initiator = !!(sm_proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR);
- if (extarg->initiator != -1 && extarg->initiator != proc_is_initiator) {
- return BLE_FSM_EXTRACT_EKEEP_CONTINUE;
+ proc_is_initiator = !!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR);
+ if (is_initiator != -1 && is_initiator != proc_is_initiator) {
+ return 0;
}
- return BLE_FSM_EXTRACT_EMOVE_STOP;
+ return 1;
}
/**
- * Searches the main proc list for an "expecting" entry whose connection handle
- * and op code match those specified. If a matching entry is found, it is
- * removed from the list and returned.
- *
- * Lock restrictions:
- * o Caller unlocks l2cap_sm.
+ * Searches the main proc list for an entry whose connection handle and state code
+ * match those specified. If a matching entry is found, it is removed from the
+ * list and returned.
*
* @param conn_handle The connection handle to match against.
- * @param op The op code to match against.
- * @param identifier The identifier to match against.
+ * @param state The state code to match against.
+ * @param is_initiator
*
* @return The matching proc entry on success;
* null on failure.
*/
static struct ble_l2cap_sm_proc *
-ble_l2cap_sm_proc_extract(struct ble_l2cap_sm_extract_arg *arg)
+ble_l2cap_sm_proc_extract(uint16_t conn_handle, uint8_t state,
+ int is_initiator)
{
struct ble_l2cap_sm_proc *proc;
- int rc;
-
- rc = ble_fsm_proc_extract(&ble_l2cap_sm_fsm,
- (struct ble_fsm_proc **)&proc,
- ble_l2cap_sm_proc_extract_cb, arg);
+ struct ble_l2cap_sm_proc *prev;
+
+ ble_hs_lock();
+
+ prev = NULL;
+ STAILQ_FOREACH(proc, &ble_l2cap_sm_procs, next) {
+ if (ble_l2cap_sm_proc_matches(proc, conn_handle, state, is_initiator)) {
+ if (prev == NULL) {
+ STAILQ_REMOVE_HEAD(&ble_l2cap_sm_procs, next);
+ } else {
+ STAILQ_REMOVE_AFTER(&ble_l2cap_sm_procs, prev, next);
+ }
+ break;
+ }
- if (rc != 0) {
- proc = NULL;
+ prev = proc;
}
+ ble_hs_unlock();
+
return proc;
}
-/**
- * Sets the specified proc entry's "pending" flag (i.e., indicates that the
- * L2CAP sm procedure is stalled until it transmits its next request).
- *
- * Lock restrictions: None.
- */
static void
-ble_l2cap_sm_proc_set_pending(struct ble_l2cap_sm_proc *proc)
+ble_l2cap_sm_extract_expired(struct ble_l2cap_sm_proc_list *dst_list)
{
- ble_fsm_proc_set_pending(&proc->fsm_proc);
- ble_hs_kick_l2cap_sm();
-}
+ struct ble_l2cap_sm_proc *proc;
+ struct ble_l2cap_sm_proc *prev;
+ struct ble_l2cap_sm_proc *next;
+ uint32_t now;
+ int32_t time_diff;
-static void
-ble_l2cap_sm_set_fail_state(struct ble_l2cap_sm_proc *proc,
- uint8_t fail_reason)
-{
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_FAIL;
- proc->fail.reason = fail_reason;
- ble_l2cap_sm_proc_set_pending(proc);
+ now = os_time_get();
+ STAILQ_INIT(dst_list);
+
+ ble_hs_lock();
+
+ prev = NULL;
+ proc = STAILQ_FIRST(&ble_l2cap_sm_procs);
+ while (proc != NULL) {
+ next = STAILQ_NEXT(proc, next);
+
+ time_diff = now - proc->exp_os_ticks;
+ if (time_diff >= 0) {
+ if (prev == NULL) {
+ STAILQ_REMOVE_HEAD(&ble_l2cap_sm_procs, next);
+ } else {
+ STAILQ_REMOVE_AFTER(&ble_l2cap_sm_procs, prev, next);
+ }
+ STAILQ_INSERT_TAIL(dst_list, proc, next);
+ }
+
+ prev = proc;
+ proc = next;
+ }
+
+ ble_hs_unlock();
}
-/**
- * Lock restrictions: None.
- */
static int
-ble_l2cap_sm_rx_noop(uint16_t conn_handle, uint8_t op, struct os_mbuf **om)
+ble_l2cap_sm_rx_noop(uint16_t conn_handle, uint8_t state, struct os_mbuf **om)
{
- return 0;
+ return BLE_HS_ENOTSUP;
}
+/*****************************************************************************
+ * $hci *
+ *****************************************************************************/
+
static int
-ble_l2cap_sm_request_tk(struct ble_l2cap_sm_proc *proc)
+ble_l2cap_sm_start_encrypt_tx(uint16_t conn_handle, uint8_t *ltk)
{
- if (proc->pair_alg == BLE_L2CAP_SM_PAIR_ALG_JW) {
- ble_l2cap_sm_proc_set_pending(proc);
- } else {
- /* XXX: Ask application for TK. */
+ struct hci_start_encrypt cmd;
+ uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_LE_START_ENCRYPT_LEN];
+ int rc;
+
+ rc = ble_l2cap_sm_gen_ediv(&cmd.encrypted_diversifier);
+ if (rc != 0) {
+ return rc;
}
- return 0;
-}
-static void
-ble_l2cap_sm_sec_params(struct ble_l2cap_sm_proc *proc,
- struct ble_gap_sec_params *out_sec_params,
- int enc_enabled)
-{
- out_sec_params->pair_alg = proc->pair_alg;
- out_sec_params->enc_enabled = enc_enabled;
- out_sec_params->auth_enabled = 0; // XXX
-}
+ rc = ble_l2cap_sm_gen_start_rand(&cmd.random_number);
+ if (rc != 0) {
+ return rc;
+ }
-static void
-ble_l2cap_sm_gap_event(struct ble_l2cap_sm_proc *proc, int status,
- int enc_enabled)
-{
- struct ble_gap_sec_params sec_params;
+ cmd.connection_handle = conn_handle;
+ memcpy(cmd.long_term_key, ltk, sizeof cmd.long_term_key);
- ble_l2cap_sm_sec_params(proc, &sec_params, enc_enabled);
- ble_gap_security_event(proc->fsm_proc.conn_handle, status, &sec_params);
-}
+ host_hci_cmd_build_le_start_encrypt(&cmd, buf, sizeof buf);
+ rc = ble_hci_tx_cmd_empty_ack(buf);
+ if (rc != 0) {
+ return rc;
+ }
-/*****************************************************************************
- * $pair *
- *****************************************************************************/
+ return 0;
+}
static int
-ble_l2cap_sm_pair_req_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_pair_cmd *req)
+ble_l2cap_sm_lt_key_req_reply_tx(uint16_t conn_handle, uint8_t *ltk)
{
- proc->phase_1_2.pair_req = *req;
- ble_l2cap_sm_proc_set_pending(proc);
+ struct hci_lt_key_req_reply cmd;
+ uint16_t ack_conn_handle;
+ uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_LT_KEY_REQ_REPLY_LEN];
+ uint8_t ack_params_len;
+ int rc;
+
+ cmd.conn_handle = conn_handle;
+ memcpy(cmd.long_term_key, ltk, 16);
+
+ host_hci_cmd_build_le_lt_key_req_reply(&cmd, buf, sizeof buf);
+ rc = ble_hci_tx_cmd(buf, &ack_conn_handle, sizeof ack_conn_handle,
+ &ack_params_len);
+ if (rc != 0) {
+ return rc;
+ }
+ if (ack_params_len != BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN - 1) {
+ return BLE_HS_ECONTROLLER;
+ }
+
+ ack_conn_handle = TOFROMLE16(ack_conn_handle);
+ if (ack_conn_handle != conn_handle) {
+ return BLE_HS_ECONTROLLER;
+ }
return 0;
}
static int
-ble_l2cap_sm_pair_rsp_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_pair_cmd *rsp)
+ble_l2cap_sm_lt_key_req_handle(struct ble_l2cap_sm_proc *proc,
+ struct hci_le_lt_key_req *evt,
+ uint8_t *out_sm_status)
{
int rc;
- proc->phase_1_2.pair_rsp = *rsp;
+ rc = ble_l2cap_sm_lt_key_req_reply_tx(proc->conn_handle, proc->hci.key);
+ if (rc != 0) {
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
+ }
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_CONFIRM;
- proc->fsm_proc.flags &= ~BLE_FSM_PROC_F_EXPECTING;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE;
- /* XXX: Assume legacy "Just Works" for now. */
- proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_JW;
+ return 0;
+}
- rc = ble_l2cap_sm_request_tk(proc);
+/*****************************************************************************
+ * $random *
+ *****************************************************************************/
+
+static int
+ble_l2cap_sm_random_go(struct ble_l2cap_sm_proc *proc)
+{
+ struct ble_l2cap_sm_pair_random cmd;
+ int rc;
+
+ memcpy(cmd.value, proc->phase_1_2.rand_our, 16);
+ rc = ble_l2cap_sm_pair_random_tx(proc->conn_handle, &cmd);
if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, rc);
return rc;
}
+ ble_l2cap_sm_proc_set_timer(proc);
+
return 0;
}
static int
-ble_l2cap_sm_pair_kick(struct ble_l2cap_sm_proc *proc)
+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_pair_cmd cmd;
- int is_req;
+ 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];
+ uint8_t k[16];
+ uint8_t ia[6];
+ uint8_t ra[6];
+ uint8_t iat;
+ uint8_t rat;
int rc;
- is_req = proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR;
+ /* Verify peer's random value. */
+ rc = ble_l2cap_sm_confirm_prepare_args(proc, k, preq, pres, &iat, &rat,
+ ia, ra);
+ if (rc != 0) {
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
+ }
- cmd.io_cap = ble_hs_cfg.sm_io_cap;
- cmd.oob_data_flag = ble_hs_cfg.sm_oob_data_flag;
- cmd.authreq = (ble_hs_cfg.sm_bonding << 0) |
- (ble_hs_cfg.sm_mitm << 2) |
- (ble_hs_cfg.sm_sc << 3) |
- (ble_hs_cfg.sm_keypress << 4);
- cmd.max_enc_key_size = 16;
+ rc = ble_l2cap_sm_alg_c1(k, cmd->value, preq, pres, iat, rat,
+ ia, ra, confirm_val);
+ if (rc != 0) {
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
+ }
- 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 {
- cmd.init_key_dist = ble_hs_cfg.sm_their_key_dist;
- cmd.resp_key_dist = ble_hs_cfg.sm_our_key_dist;
+ if (memcmp(proc->phase_1_2.confirm_their, confirm_val, 16) != 0) {
+ /* Random number mismatch. */
+ rc = BLE_HS_SM_US_ERR(BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH);
+ *out_sm_status = BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH;
+ return rc;
}
- rc = ble_l2cap_sm_pair_cmd_tx(proc->fsm_proc.conn_handle, is_req, &cmd);
+ memcpy(proc->phase_1_2.rand_their, cmd->value, 16);
+
+ /* Generate the key. */
+ rc = ble_l2cap_sm_gen_key(proc);
if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_UNSPECIFIED);
- return BLE_HS_EAGAIN;
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
}
- if (is_req) {
- proc->phase_1_2.pair_req = cmd;
+ if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
+ /* Send the start-encrypt HCI command to the controller. */
+ rc = ble_l2cap_sm_start_encrypt_tx(proc->conn_handle, proc->hci.key);
+ if (rc != 0) {
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
+ }
+ proc->state = BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE;
} else {
- proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_JW;
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_CONFIRM;
- proc->phase_1_2.pair_rsp = cmd;
+ 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_LTK;
}
+ *out_sm_status = 0;
return 0;
}
@@ -605,8 +633,7 @@ ble_l2cap_sm_confirm_prepare_args(struct ble_l2cap_sm_proc *proc,
{
struct ble_hs_conn *conn;
- ble_hs_conn_lock();
- conn = ble_hs_conn_find(proc->fsm_proc.conn_handle);
+ conn = ble_hs_conn_find(proc->conn_handle);
if (conn != NULL) {
if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
*iat = BLE_ADDR_TYPE_PUBLIC; /* XXX: Support random addresses. */
@@ -622,7 +649,6 @@ ble_l2cap_sm_confirm_prepare_args(struct ble_l2cap_sm_proc *proc,
memcpy(ia, conn->bhc_addr, 6);
}
}
- ble_hs_conn_unlock();
if (conn == NULL) {
return BLE_HS_ENOTCONN;
@@ -642,7 +668,7 @@ ble_l2cap_sm_confirm_prepare_args(struct ble_l2cap_sm_proc *proc,
}
static int
-ble_l2cap_sm_confirm_kick(struct ble_l2cap_sm_proc *proc)
+ble_l2cap_sm_confirm_go(struct ble_l2cap_sm_proc *proc)
{
struct ble_l2cap_sm_pair_confirm cmd;
uint8_t preq[BLE_L2CAP_SM_HDR_SZ + BLE_L2CAP_SM_PAIR_CMD_SZ];
@@ -654,271 +680,150 @@ ble_l2cap_sm_confirm_kick(struct ble_l2cap_sm_proc *proc)
uint8_t rat;
int rc;
- ble_l2cap_sm_gen_pair_rand(proc->phase_1_2.rand_our);
+ rc = ble_l2cap_sm_gen_pair_rand(proc->phase_1_2.rand_our);
+ if (rc != 0) {
+ return rc;
+ }
rc = ble_l2cap_sm_confirm_prepare_args(proc, k, preq, pres, &iat, &rat,
ia, ra);
if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_UNSPECIFIED);
- return BLE_HS_EAGAIN;
+ return rc;
}
rc = ble_l2cap_sm_alg_c1(k, proc->phase_1_2.rand_our, preq, pres, iat, rat,
ia, ra, cmd.value);
if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_UNSPECIFIED);
- return BLE_HS_EAGAIN;
+ return rc;
}
- rc = ble_l2cap_sm_pair_confirm_tx(proc->fsm_proc.conn_handle, &cmd);
+ rc = ble_l2cap_sm_pair_confirm_tx(proc->conn_handle, &cmd);
if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_UNSPECIFIED);
- return BLE_HS_EAGAIN;
+ return rc;
}
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_RANDOM;
- }
+ ble_l2cap_sm_proc_set_timer(proc);
return 0;
}
static int
ble_l2cap_sm_confirm_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_pair_confirm *cmd)
+ struct ble_l2cap_sm_pair_confirm *cmd,
+ uint8_t *out_sm_status)
{
int rc;
memcpy(proc->phase_1_2.confirm_their, cmd->value, 16);
if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_RANDOM;
- ble_l2cap_sm_proc_set_pending(proc);
+ rc = ble_l2cap_sm_random_go(proc);
+ if (rc != 0) {
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
+ }
} else {
- rc = ble_l2cap_sm_request_tk(proc);
+ /* XXX: If MITM is used, request TK from application. */
+
+ rc = ble_l2cap_sm_confirm_go(proc);
if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, rc);
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
return rc;
}
}
+ proc->state = BLE_L2CAP_SM_PROC_STATE_RANDOM;
+
return 0;
}
/*****************************************************************************
- * $random *
+ * $pair *
*****************************************************************************/
static int
-ble_l2cap_sm_random_kick(struct ble_l2cap_sm_proc *proc)
+ble_l2cap_sm_pair_go(struct ble_l2cap_sm_proc *proc)
{
- struct ble_l2cap_sm_pair_random cmd;
- uint8_t key[16];
+ struct ble_l2cap_sm_pair_cmd cmd;
+ int is_req;
int rc;
- memcpy(cmd.value, proc->phase_1_2.rand_our, 16);
- rc = ble_l2cap_sm_pair_random_tx(proc->fsm_proc.conn_handle, &cmd);
- if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_UNSPECIFIED);
- return BLE_HS_EAGAIN;
- }
-
- if (!(proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR)) {
- /* Generate the key. */
- rc = ble_l2cap_sm_alg_s1(proc->phase_1_2.tk, proc->phase_1_2.rand_our,
- proc->phase_1_2.rand_their, key);
- if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- return rc;
- }
- memcpy(proc->hci.key, key, sizeof key);
-
- proc->hci.handle = BLE_HCI_SCHED_HANDLE_NONE;
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_LTK;
- }
-
- return 0;
-}
+ is_req = proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR;
-static int
-ble_l2cap_sm_random_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_pair_random *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];
- uint8_t key[16];
- uint8_t k[16];
- uint8_t ia[6];
- uint8_t ra[6];
- uint8_t iat;
- uint8_t rat;
- int rc;
+ cmd.io_cap = ble_hs_cfg.sm_io_cap;
+ cmd.oob_data_flag = ble_hs_cfg.sm_oob_data_flag;
+ cmd.authreq = (ble_hs_cfg.sm_bonding << 0) |
+ (ble_hs_cfg.sm_mitm << 2) |
+ (ble_hs_cfg.sm_sc << 3) |
+ (ble_hs_cfg.sm_keypress << 4);
+ cmd.max_enc_key_size = 16;
- /* Verify peer's random value. */
- rc = ble_l2cap_sm_confirm_prepare_args(proc, k, preq, pres, &iat, &rat,
- ia, ra);
- if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_UNSPECIFIED);
- return 0;
+ 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 {
+ cmd.init_key_dist = ble_hs_cfg.sm_their_key_dist;
+ cmd.resp_key_dist = ble_hs_cfg.sm_our_key_dist;
}
- rc = ble_l2cap_sm_alg_c1(k, cmd->value, preq, pres, iat, rat,
- ia, ra, confirm_val);
+ rc = ble_l2cap_sm_pair_cmd_tx(proc->conn_handle, is_req, &cmd);
if (rc != 0) {
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_UNSPECIFIED);
- return 0;
+ return rc;
}
- if (memcmp(proc->phase_1_2.confirm_their, confirm_val, 16) != 0) {
- /* Random number mismatch. */
- ble_l2cap_sm_set_fail_state(proc, BLE_L2CAP_SM_ERR_CONFIRM_MISMATCH);
- return 0;
+ if (is_req) {
+ proc->phase_1_2.pair_req = cmd;
+ } else {
+ proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_JW;
+ proc->phase_1_2.pair_rsp = cmd;
}
- memcpy(proc->phase_1_2.rand_their, cmd->value, 16);
-
- if (proc->flags & BLE_L2CAP_SM_PROC_F_INITIATOR) {
- /* Generate the key. */
- rc = ble_l2cap_sm_alg_s1(proc->phase_1_2.tk, proc->phase_1_2.rand_our,
- proc->phase_1_2.rand_their, key);
- if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- return rc;
- }
- memcpy(proc->hci.key, key, sizeof key);
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_START_ENCRYPT;
- }
- ble_l2cap_sm_proc_set_pending(proc);
+ ble_l2cap_sm_proc_set_timer(proc);
return 0;
}
-/*****************************************************************************
- * $fail *
- *****************************************************************************/
-
-static int
-ble_l2cap_sm_fail_kick(struct ble_l2cap_sm_proc *proc)
-{
- struct ble_l2cap_sm_pair_fail cmd;
-
- cmd.reason = proc->fail.reason;
- ble_l2cap_sm_pair_fail_tx(proc->fsm_proc.conn_handle, &cmd);
-
- /* Notify application of failure. */
- ble_l2cap_sm_gap_event(proc, BLE_HS_SM_US_ERR(cmd.reason), 0);
-
- return BLE_HS_EDONE;
-}
-
static int
-ble_l2cap_sm_fail_handle(struct ble_l2cap_sm_proc *proc,
- struct ble_l2cap_sm_pair_fail *cmd)
-{
- ble_l2cap_sm_gap_event(proc, BLE_HS_SM_THEM_ERR(cmd->reason), 0);
-
- /* Procedure should now be terminated (return nonzero). */
- return 1;
-}
-
-/*****************************************************************************
- * $hci *
- *****************************************************************************/
-
-static int
-ble_l2cap_sm_lt_key_req_reply_tx(void *arg)
+ble_l2cap_sm_pair_req_handle(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_pair_cmd *req,
+ uint8_t *out_sm_status)
{
- struct hci_lt_key_req_reply cmd;
- struct ble_l2cap_sm_proc *proc;
int rc;
- proc = arg;
-
- BLE_HS_DBG_ASSERT(proc->fsm_proc.op == BLE_L2CAP_SM_PROC_OP_LTK_TXED);
-
- /* Indicate that the HCI reservation has been serviced. If there is a
- * failure, we shouldn't try to cancel the reservation.
- */
- proc->hci.handle = BLE_HCI_SCHED_HANDLE_NONE;
-
- cmd.conn_handle = proc->fsm_proc.conn_handle;
- memcpy(cmd.long_term_key, proc->hci.key, 16);
-
- ble_hci_sched_set_ack_cb(ble_l2cap_sm_rx_lt_key_req_reply_ack, proc);
-
- rc = host_hci_cmd_le_lt_key_req_reply(&cmd);
- return rc;
-}
-
-static int
-ble_l2cap_sm_lt_key_req_kick(struct ble_l2cap_sm_proc *proc)
-{
- int rc;
+ proc->phase_1_2.pair_req = *req;
- rc = ble_hci_sched_enqueue(ble_l2cap_sm_lt_key_req_reply_tx, proc,
- &proc->hci.handle);
+ rc = ble_l2cap_sm_pair_go(proc);
if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- return BLE_HS_EDONE;
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
}
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_LTK_TXED;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_CONFIRM;
return 0;
}
static int
-ble_l2cap_sm_lt_key_req_handle(struct ble_l2cap_sm_proc *proc,
- struct hci_le_lt_key_req *evt)
-{
- ble_l2cap_sm_proc_set_pending(proc);
- return 0;
-}
-
-static int
-ble_l2cap_sm_start_encrypt_tx(void *arg)
+ble_l2cap_sm_pair_rsp_handle(struct ble_l2cap_sm_proc *proc,
+ struct ble_l2cap_sm_pair_cmd *rsp,
+ uint8_t *out_sm_status)
{
- struct ble_l2cap_sm_proc *proc;
- struct hci_start_encrypt cmd;
int rc;
- proc = arg;
-
- BLE_HS_DBG_ASSERT(proc->fsm_proc.op ==
- BLE_L2CAP_SM_PROC_OP_START_ENCRYPT_TXED);
-
- /* Indicate that the HCI reservation has been serviced. If there is a
- * failure, we shouldn't try to cancel the reservation.
- */
- proc->hci.handle = BLE_HCI_SCHED_HANDLE_NONE;
-
- cmd.connection_handle = proc->fsm_proc.conn_handle;
- cmd.encrypted_diversifier = ble_l2cap_sm_gen_ediv();
- cmd.random_number = ble_l2cap_sm_gen_start_rand();
- memcpy(cmd.long_term_key, proc->hci.key, sizeof cmd.long_term_key);
-
- ble_hci_sched_set_ack_cb(ble_l2cap_sm_rx_start_encrypt_ack, proc);
+ proc->phase_1_2.pair_rsp = *rsp;
- rc = host_hci_cmd_le_start_encrypt(&cmd);
- return rc;
-}
+ /* XXX: Assume legacy "Just Works" for now. */
+ proc->pair_alg = BLE_L2CAP_SM_PAIR_ALG_JW;
-static int
-ble_l2cap_sm_start_encrypt_kick(struct ble_l2cap_sm_proc *proc)
-{
- int rc;
+ /* XXX: If MITM is used, request TK from application. */
- rc = ble_hci_sched_enqueue(ble_l2cap_sm_start_encrypt_tx, proc,
- &proc->hci.handle);
+ proc->state = BLE_L2CAP_SM_PROC_STATE_CONFIRM;
+ rc = ble_l2cap_sm_confirm_go(proc);
if (rc != 0) {
- ble_l2cap_sm_gap_event(proc, rc, 0);
- return BLE_HS_EDONE;
+ *out_sm_status = BLE_L2CAP_SM_ERR_UNSPECIFIED;
+ return rc;
}
- proc->hci.handle = BLE_HCI_SCHED_HANDLE_NONE;
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_START_ENCRYPT_TXED;
-
return 0;
}
@@ -927,10 +832,12 @@ ble_l2cap_sm_start_encrypt_kick(struct ble_l2cap_sm_proc *proc)
*****************************************************************************/
static int
-ble_l2cap_sm_rx_pair_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om)
+ble_l2cap_sm_rx_pair_req(uint16_t conn_handle, uint8_t state,
+ struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_cmd req;
struct ble_l2cap_sm_proc *proc;
+ uint8_t sm_status;
int rc;
rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_CMD_SZ);
@@ -948,36 +855,34 @@ ble_l2cap_sm_rx_pair_req(uint16_t conn_handle, uint8_t op, struct os_mbuf **om)
/* XXX: Check connection state; reject if not appropriate. */
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_NONE,
- .initiator = -1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
+ -1);
if (proc != NULL) {
/* Pairing already in progress; abort old procedure and start new. */
/* XXX: Check the spec on this. */
- ble_l2cap_sm_proc_free(&proc->fsm_proc);
+ ble_l2cap_sm_proc_free(proc);
}
- rc = ble_l2cap_sm_proc_new(conn_handle, BLE_L2CAP_SM_PROC_OP_PAIR,
- &proc);
- if (rc != 0) {
- return rc;
+ proc = ble_l2cap_sm_proc_alloc();
+ if (proc == NULL) {
+ return BLE_HS_ENOMEM;
}
+ proc->conn_handle = conn_handle;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_PAIR;
- rc = ble_l2cap_sm_pair_req_handle(proc, &req);
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
+ rc = ble_l2cap_sm_pair_req_handle(proc, &req, &sm_status);
+ ble_l2cap_sm_process_status(proc, rc, sm_status, 1, 1);
return rc;
}
static int
-ble_l2cap_sm_rx_pair_rsp(uint16_t conn_handle, uint8_t op, struct os_mbuf **om)
+ble_l2cap_sm_rx_pair_rsp(uint16_t conn_handle, uint8_t state,
+ struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_cmd rsp;
struct ble_l2cap_sm_proc *proc;
+ uint8_t sm_status;
int rc;
rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_CMD_SZ);
@@ -993,29 +898,25 @@ ble_l2cap_sm_rx_pair_rsp(uint16_t conn_handle, uint8_t op, struct os_mbuf **om)
rsp.io_cap, rsp.oob_data_flag, rsp.authreq,
rsp.max_enc_key_size, rsp.init_key_dist, rsp.resp_key_dist);
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_PAIR,
- .initiator = 1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(conn_handle, BLE_L2CAP_SM_PROC_STATE_PAIR,
+ 1);
if (proc == NULL) {
return BLE_HS_ENOTCONN;
}
- rc = ble_l2cap_sm_pair_rsp_handle(proc, &rsp);
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
+ rc = ble_l2cap_sm_pair_rsp_handle(proc, &rsp, &sm_status);
+ ble_l2cap_sm_process_status(proc, rc, sm_status, 1, 1);
return 0;
}
static int
-ble_l2cap_sm_rx_pair_confirm(uint16_t conn_handle, uint8_t op,
+ble_l2cap_sm_rx_pair_confirm(uint16_t conn_handle, uint8_t state,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_confirm cmd;
struct ble_l2cap_sm_proc *proc;
+ uint8_t sm_status;
int rc;
rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_CONFIRM_SZ);
@@ -1027,29 +928,25 @@ ble_l2cap_sm_rx_pair_confirm(uint16_t conn_handle, uint8_t op,
BLE_HS_LOG(DEBUG, "rxed sm confirm cmd\n");
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_CONFIRM,
- .initiator = -1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(conn_handle,
+ BLE_L2CAP_SM_PROC_STATE_CONFIRM, -1);
if (proc == NULL) {
return BLE_HS_ENOTCONN;
}
- rc = ble_l2cap_sm_confirm_handle(proc, &cmd);
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
+ rc = ble_l2cap_sm_confirm_handle(proc, &cmd, &sm_status);
+ ble_l2cap_sm_process_status(proc, rc, sm_status, 1, 1);
return 0;
}
static int
-ble_l2cap_sm_rx_pair_random(uint16_t conn_handle, uint8_t op,
+ble_l2cap_sm_rx_pair_random(uint16_t conn_handle, uint8_t state,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_random cmd;
struct ble_l2cap_sm_proc *proc;
+ uint8_t sm_status;
int rc;
rc = ble_hs_misc_pullup_base(om, BLE_L2CAP_SM_PAIR_RANDOM_SZ);
@@ -1061,25 +958,20 @@ ble_l2cap_sm_rx_pair_random(uint16_t conn_handle, uint8_t op,
BLE_HS_LOG(DEBUG, "rxed sm random cmd\n");
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_RANDOM,
- .initiator = -1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(conn_handle,
+ BLE_L2CAP_SM_PROC_STATE_RANDOM, -1);
if (proc == NULL) {
return BLE_HS_ENOTCONN;
}
- rc = ble_l2cap_sm_random_handle(proc, &cmd);
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
+ rc = ble_l2cap_sm_random_handle(proc, &cmd, &sm_status);
+ ble_l2cap_sm_process_status(proc, rc, sm_status, 1, 1);
return 0;
}
static int
-ble_l2cap_sm_rx_pair_fail(uint16_t conn_handle, uint8_t op,
+ble_l2cap_sm_rx_pair_fail(uint16_t conn_handle, uint8_t state,
struct os_mbuf **om)
{
struct ble_l2cap_sm_pair_fail cmd;
@@ -1095,19 +987,13 @@ 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);
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_NONE,
- .initiator = -1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
+ -1);
if (proc == NULL) {
return BLE_HS_ENOTCONN;
}
- rc = ble_l2cap_sm_fail_handle(proc, &cmd);
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
+ ble_l2cap_sm_process_status(proc, BLE_HS_SM_THEM_ERR(cmd.reason), 0, 1, 0);
return 0;
}
@@ -1116,129 +1002,38 @@ int
ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt)
{
struct ble_l2cap_sm_proc *proc;
+ uint8_t sm_status;
int rc;
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = evt->connection_handle,
- .op = BLE_L2CAP_SM_PROC_OP_LTK,
- .initiator = 0,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(evt->connection_handle,
+ BLE_L2CAP_SM_PROC_STATE_LTK, 0);
if (proc == NULL) {
return BLE_HS_ENOTCONN;
}
- rc = ble_l2cap_sm_lt_key_req_handle(proc, evt);
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
+ rc = ble_l2cap_sm_lt_key_req_handle(proc, evt, &sm_status);
+ ble_l2cap_sm_process_status(proc, rc, sm_status, 1, 1);
return 0;
}
-static void
-ble_l2cap_sm_rx_lt_key_req_reply_ack(struct ble_hci_ack *ack, void *arg)
-{
- struct ble_l2cap_sm_proc *proc;
- uint16_t conn_handle;
- int rc;
-
- proc = arg;
-
- BLE_HS_DBG_ASSERT(proc->fsm_proc.op == BLE_L2CAP_SM_PROC_OP_LTK_TXED);
-
- /* Extract the procedure from the state machine while we mess with it. */
- ble_fsm_lock(&ble_l2cap_sm_fsm);
- STAILQ_REMOVE(&ble_l2cap_sm_fsm.procs, &proc->fsm_proc, ble_fsm_proc,
- next);
- ble_fsm_unlock(&ble_l2cap_sm_fsm);
-
- if (ack->bha_status != 0) {
- rc = ack->bha_status;
- goto done;
- }
-
- if (ack->bha_params_len != BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN) {
- /* Controller sent something weird; treat this as a failure. */
- rc = BLE_HS_ECONTROLLER;
- goto done;
- }
-
- conn_handle = le16toh(ack->bha_params + 1);
- if (conn_handle != proc->fsm_proc.conn_handle) {
- /* Controller sent something weird; treat this as a failure. */
- rc = BLE_HS_ECONTROLLER;
- goto done;
- }
-
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_ENC_CHANGE;
- rc = 0;
-
-done:
- if (rc != 0) {
- /* Report the failure to the application. */
- ble_l2cap_sm_gap_event(proc, rc, 0);
- }
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
-}
-
-static void
-ble_l2cap_sm_rx_start_encrypt_ack(struct ble_hci_ack *ack, void *arg)
-{
- struct ble_l2cap_sm_proc *proc;
- int rc;
-
- proc = arg;
-
- BLE_HS_DBG_ASSERT(proc->fsm_proc.op ==
- BLE_L2CAP_SM_PROC_OP_START_ENCRYPT_TXED);
-
- /* Extract the procedure from the state machine while we mess with it. */
- ble_fsm_lock(&ble_l2cap_sm_fsm);
- STAILQ_REMOVE(&ble_l2cap_sm_fsm.procs, &proc->fsm_proc, ble_fsm_proc,
- next);
- ble_fsm_unlock(&ble_l2cap_sm_fsm);
-
- if (ack->bha_status != 0) {
- rc = ack->bha_status;
- goto done;
- }
-
- proc->fsm_proc.op = BLE_L2CAP_SM_PROC_OP_ENC_CHANGE;
- rc = 0;
-
-done:
- if (rc != 0) {
- /* Report the failure to the application. */
- ble_l2cap_sm_gap_event(proc, rc, 0);
- }
- ble_fsm_process_rx_status(&ble_l2cap_sm_fsm, &proc->fsm_proc, rc);
-}
-
void
ble_l2cap_sm_rx_encryption_change(struct hci_encrypt_change *evt)
{
struct ble_l2cap_sm_proc *proc;
+ int enc_enabled;
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = evt->connection_handle,
- .op = BLE_L2CAP_SM_PROC_OP_ENC_CHANGE,
- .initiator = -1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(evt->connection_handle,
+ BLE_L2CAP_SM_PROC_STATE_ENC_CHANGE, -1);
if (proc == NULL) {
return;
}
- if (evt->status != 0) {
- ble_l2cap_sm_gap_event(proc, BLE_HS_HCI_ERR(evt->status), 0);
- } else {
- ble_l2cap_sm_gap_event(proc, 0,
- evt->encryption_enabled & 0x01 /* LE bit. */);
- }
+ enc_enabled = evt->encryption_enabled & 0x01; /* LE bit. */
+ ble_l2cap_sm_gap_event(proc, BLE_HS_HCI_ERR(evt->status), enc_enabled);
/* The pairing procedure is now complete. */
- ble_l2cap_sm_proc_free(&proc->fsm_proc);
+ ble_l2cap_sm_proc_free(proc);
}
/**
@@ -1257,11 +1052,10 @@ ble_l2cap_sm_rx(uint16_t conn_handle, struct os_mbuf **om)
ble_hs_misc_log_mbuf(*om);
BLE_HS_LOG(DEBUG, "\n");
- rc = ble_hs_misc_pullup_base(om, 1);
+ rc = os_mbuf_copydata(*om, 0, 1, &op);
if (rc != 0) {
return BLE_HS_EBADDATA;
}
- op = *(*om)->om_data;
/* Strip L2CAP SM header from the front of the mbuf. */
os_mbuf_adj(*om, 1);
@@ -1283,25 +1077,22 @@ ble_l2cap_sm_rx(uint16_t conn_handle, struct os_mbuf **om)
void
ble_l2cap_sm_heartbeat(void)
{
- struct ble_fsm_proc_list exp_list;
+ struct ble_l2cap_sm_proc_list exp_list;
struct ble_l2cap_sm_proc *proc;
- struct ble_fsm_proc *fsm_proc;
/* Remove all timed out procedures and insert them into a temporary
* list.
*/
- ble_fsm_proc_extract_list(&ble_l2cap_sm_fsm, &exp_list,
- ble_l2cap_sm_proc_extract_expired_cb, NULL);
+ ble_l2cap_sm_extract_expired(&exp_list);
/* Notify application of each failure and free the corresponding procedure
* object.
*/
- while ((fsm_proc = STAILQ_FIRST(&exp_list)) != NULL) {
- proc = (struct ble_l2cap_sm_proc *)fsm_proc;
+ while ((proc = STAILQ_FIRST(&exp_list)) != NULL) {
ble_l2cap_sm_gap_event(proc, BLE_HS_ETIMEOUT, 0);
STAILQ_REMOVE_HEAD(&exp_list, next);
- ble_l2cap_sm_proc_free(&proc->fsm_proc);
+ ble_l2cap_sm_proc_free(proc);
}
}
@@ -1314,28 +1105,24 @@ ble_l2cap_sm_initiate(uint16_t conn_handle)
/* Make sure a pairing operation for this connection is not already in
* progress.
*/
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_NONE,
- .initiator = -1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
+ -1);
if (proc != NULL) {
return BLE_HS_EALREADY;
}
- rc = ble_l2cap_sm_proc_new(conn_handle, BLE_L2CAP_SM_PROC_OP_PAIR,
- &proc);
- if (rc != 0) {
- return rc;
+ proc = ble_l2cap_sm_proc_alloc();
+ if (proc == NULL) {
+ return BLE_HS_ENOMEM;
}
-
+ proc->conn_handle = conn_handle;
+ proc->state = BLE_L2CAP_SM_PROC_STATE_PAIR;
proc->flags |= BLE_L2CAP_SM_PROC_F_INITIATOR;
- STAILQ_INSERT_TAIL(&ble_l2cap_sm_fsm.procs, &proc->fsm_proc, next);
- ble_l2cap_sm_proc_set_pending(proc);
- return 0;
+ rc = ble_l2cap_sm_pair_go(proc);
+ ble_l2cap_sm_process_status(proc, rc, 0, 0, 0);
+
+ return rc;
}
/**
@@ -1364,20 +1151,15 @@ ble_l2cap_sm_set_tk(uint16_t conn_handle, uint8_t *tk)
{
struct ble_l2cap_sm_proc *proc;
- proc = ble_l2cap_sm_proc_extract(
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_CONFIRM,
- .initiator = -1,
- }
- );
+ proc = ble_l2cap_sm_proc_extract(conn_handle,
+ BLE_L2CAP_SM_PROC_STATE_CONFIRM, -1);
if (proc == NULL) {
return BLE_HS_ENOENT;
}
memcpy(proc->phase_1_2.tk, tk, 16);
- ble_l2cap_sm_proc_set_pending(proc);
+ /* XXX: Proceed with pairing; send confirm command. */
return 0;
}
@@ -1385,43 +1167,19 @@ ble_l2cap_sm_set_tk(uint16_t conn_handle, uint8_t *tk)
void
ble_l2cap_sm_connection_broken(uint16_t conn_handle)
{
- struct ble_fsm_proc_list list;
struct ble_l2cap_sm_proc *proc;
- struct ble_fsm_proc *fsm_proc;
-
- /* Extract all procs associated with the broken connection and insert them
- * into the temporary list.
- */
- ble_fsm_proc_extract_list(
- &ble_l2cap_sm_fsm, &list, ble_l2cap_sm_proc_extract_cb,
- &(struct ble_l2cap_sm_extract_arg) {
- .conn_handle = conn_handle,
- .op = BLE_L2CAP_SM_PROC_OP_NONE,
- .initiator = -1,
- }
- );
-
- /* Free each affected procedure object. There is no need to notify the
- * application, as it has already been notified of the connection failure.
- */
- while ((fsm_proc = STAILQ_FIRST(&list)) != NULL) {
- proc = (struct ble_l2cap_sm_proc *)fsm_proc;
- STAILQ_REMOVE_HEAD(&list, next);
- ble_l2cap_sm_proc_free(&proc->fsm_proc);
+ proc = ble_l2cap_sm_proc_extract(conn_handle, BLE_L2CAP_SM_PROC_STATE_NONE,
+ -1);
+ if (proc != NULL) {
+ /* Free thw affected procedure object. There is no need to notify the
+ * application, as it has already been notified of the connection
+ * failure.
+ */
+ ble_l2cap_sm_proc_free(proc);
}
}
-/**
- * Lock restrictions:
- * o Caller unlocks ble_hs_conn.
- */
-void
-ble_l2cap_sm_wakeup(void)
-{
- ble_fsm_wakeup(&ble_l2cap_sm_fsm);
-}
-
int
ble_l2cap_sm_init(void)
{
@@ -1429,11 +1187,7 @@ ble_l2cap_sm_init(void)
free(ble_l2cap_sm_proc_mem);
- rc = ble_fsm_new(&ble_l2cap_sm_fsm, ble_l2cap_sm_proc_kick,
- ble_l2cap_sm_proc_free);
- if (rc != 0) {
- goto err;
- }
+ STAILQ_INIT(&ble_l2cap_sm_procs);
if (ble_hs_cfg.max_l2cap_sm_procs > 0) {
ble_l2cap_sm_proc_mem = malloc(
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e32f9f9f/net/nimble/host/src/ble_l2cap_sm.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_l2cap_sm.h b/net/nimble/host/src/ble_l2cap_sm.h
index e56f1df..9ecbeaf 100644
--- a/net/nimble/host/src/ble_l2cap_sm.h
+++ b/net/nimble/host/src/ble_l2cap_sm.h
@@ -90,8 +90,6 @@ void ble_l2cap_sm_dbg_set_next_start_rand(uint64_t next_start_rand);
int ble_l2cap_sm_dbg_num_procs(void);
#endif
-int ble_l2cap_sm_locked_by_cur_task(void);
-
struct ble_l2cap_chan *ble_l2cap_sm_create_chan(void);
void ble_l2cap_sm_pair_cmd_parse(void *payload, int len,
@@ -116,8 +114,7 @@ void ble_l2cap_sm_pair_fail_parse(void *payload, int len,
struct ble_l2cap_sm_pair_fail *cmd);
void ble_l2cap_sm_pair_fail_write(void *payload, int len,
struct ble_l2cap_sm_pair_fail *cmd);
-int ble_l2cap_sm_pair_fail_tx(uint16_t conn_handle,
- struct ble_l2cap_sm_pair_fail *cmd);
+int ble_l2cap_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason);
int ble_l2cap_sm_alg_s1(uint8_t *k, uint8_t *r1, uint8_t *r2, uint8_t *out);
int ble_l2cap_sm_alg_c1(uint8_t *k, uint8_t *r,
@@ -131,7 +128,6 @@ int ble_l2cap_sm_rx_lt_key_req(struct hci_le_lt_key_req *evt);
void ble_l2cap_sm_heartbeat(void);
int ble_l2cap_sm_initiate(uint16_t conn_handle);
-void ble_l2cap_sm_wakeup(void);
int ble_l2cap_sm_init(void);
#else
@@ -141,8 +137,6 @@ int ble_l2cap_sm_init(void);
#define ble_l2cap_sm_dbg_num_procs() 0
#endif
-#define ble_l2cap_sm_locked_by_cur_task() 0
-
#define ble_l2cap_sm_create_chan() NULL
#define ble_l2cap_sm_pair_cmd_tx(conn_handle, is_req, cmd) BLE_HS_ENOTSUP
@@ -160,7 +154,6 @@ int ble_l2cap_sm_init(void);
#define ble_l2cap_sm_connection_broken(conn_handle)
#define ble_l2cap_sm_heartbeat()
-#define ble_l2cap_sm_wakeup()
#define ble_l2cap_sm_init() 0
#endif
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e32f9f9f/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 dac8558..843b1e5 100644
--- a/net/nimble/host/src/ble_l2cap_sm_cmd.c
+++ b/net/nimble/host/src/ble_l2cap_sm_cmd.c
@@ -35,7 +35,7 @@ ble_l2cap_sm_tx(uint16_t conn_handle, struct os_mbuf *txom)
STATS_INC(ble_l2cap_stats, sm_tx);
- ble_hs_conn_lock();
+ ble_hs_lock();
rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SM,
&conn, &chan);
@@ -46,7 +46,7 @@ ble_l2cap_sm_tx(uint16_t conn_handle, struct os_mbuf *txom)
rc = ble_l2cap_tx(conn, chan, txom);
}
- ble_hs_conn_unlock();
+ ble_hs_unlock();
return rc;
}
@@ -257,19 +257,22 @@ ble_l2cap_sm_pair_fail_write(void *payload, int len,
}
int
-ble_l2cap_sm_pair_fail_tx(uint16_t conn_handle,
- struct ble_l2cap_sm_pair_fail *cmd)
+ble_l2cap_sm_pair_fail_tx(uint16_t conn_handle, uint8_t reason)
{
+ struct ble_l2cap_sm_pair_fail cmd;
struct os_mbuf *txom;
int rc;
+ BLE_HS_DBG_ASSERT(reason > 0 && reason < BLE_L2CAP_SM_ERR_MAX_PLUS_1);
+
rc = ble_l2cap_sm_init_req(BLE_L2CAP_SM_PAIR_FAIL_SZ, &txom);
if (rc != 0) {
rc = BLE_HS_ENOMEM;
goto done;
}
- ble_l2cap_sm_pair_fail_write(txom->om_data, txom->om_len, cmd);
+ cmd.reason = reason;
+ ble_l2cap_sm_pair_fail_write(txom->om_data, txom->om_len, &cmd);
rc = ble_l2cap_sm_tx(conn_handle, txom);
txom = NULL;
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e32f9f9f/net/nimble/host/src/host_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci.c b/net/nimble/host/src/host_hci.c
index a52d8b6..31eb108 100644
--- a/net/nimble/host/src/host_hci.c
+++ b/net/nimble/host/src/host_hci.c
@@ -31,11 +31,11 @@
_Static_assert(sizeof (struct hci_data_hdr) == BLE_HCI_DATA_HDR_SZ,
"struct hci_data_hdr must be 4 bytes");
+#define BLE_HCI_TIMEOUT (OS_TICKS_PER_SEC)
+
typedef int host_hci_event_fn(uint8_t event_code, uint8_t *data, int len);
static host_hci_event_fn host_hci_rx_disconn_complete;
static host_hci_event_fn host_hci_rx_encrypt_change;
-static host_hci_event_fn host_hci_rx_cmd_complete;
-static host_hci_event_fn host_hci_rx_cmd_status;
static host_hci_event_fn host_hci_rx_num_completed_pkts;
static host_hci_event_fn host_hci_rx_le_meta;
@@ -58,13 +58,8 @@ struct host_hci_stats
uint32_t unknown_events_rxd;
};
-/** The opcode of the current unacked HCI command; 0 if none. */
-uint16_t host_hci_outstanding_opcode;
-
#define HOST_HCI_TIMEOUT 50 /* Milliseconds. */
-static struct os_callout_func host_hci_timer;
-
/** Dispatch table for incoming HCI events. Sorted by event code field. */
struct host_hci_event_dispatch_entry {
uint8_t hed_event_code;
@@ -74,8 +69,6 @@ struct host_hci_event_dispatch_entry {
static const struct host_hci_event_dispatch_entry host_hci_event_dispatch[] = {
{ BLE_HCI_EVCODE_DISCONN_CMP, host_hci_rx_disconn_complete },
{ BLE_HCI_EVCODE_ENCRYPT_CHG, host_hci_rx_encrypt_change },
- { BLE_HCI_EVCODE_COMMAND_COMPLETE, host_hci_rx_cmd_complete },
- { BLE_HCI_EVCODE_COMMAND_STATUS, host_hci_rx_cmd_status },
{ BLE_HCI_EVCODE_NUM_COMP_PKTS, host_hci_rx_num_completed_pkts },
{ BLE_HCI_EVCODE_LE_META, host_hci_rx_le_meta },
};
@@ -101,6 +94,24 @@ static const struct host_hci_le_event_dispatch_entry
#define HOST_HCI_LE_EVENT_DISPATCH_SZ \
(sizeof host_hci_le_event_dispatch / sizeof host_hci_le_event_dispatch[0])
+uint16_t
+host_hci_opcode_join(uint8_t ogf, uint16_t ocf)
+{
+ return (ogf << 10) | ocf;
+}
+
+uint16_t
+host_hci_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc)
+{
+ BLE_HS_DBG_ASSERT(handle <= 0x0fff);
+ BLE_HS_DBG_ASSERT(pb <= 0x03);
+ BLE_HS_DBG_ASSERT(bc <= 0x03);
+
+ return (handle << 0) |
+ (pb << 12) |
+ (bc << 14);
+}
+
static const struct host_hci_event_dispatch_entry *
host_hci_dispatch_entry_find(uint8_t event_code)
{
@@ -133,39 +144,6 @@ host_hci_le_dispatch_entry_find(uint8_t event_code)
return NULL;
}
-void
-host_hci_timer_set(void)
-{
- int rc;
-
- rc = os_callout_reset(&host_hci_timer.cf_c,
- HOST_HCI_TIMEOUT * OS_TICKS_PER_SEC / 1000);
- BLE_HS_DBG_ASSERT_EVAL(rc == 0);
-}
-
-static void
-host_hci_timer_stop(void)
-{
- os_callout_stop(&host_hci_timer.cf_c);
-}
-
-static void
-host_hci_timer_exp(void *arg)
-{
- struct ble_hci_ack ack;
-
- BLE_HS_DBG_ASSERT(host_hci_outstanding_opcode != 0);
-
- ack.bha_opcode = host_hci_outstanding_opcode;
- ack.bha_status = BLE_HS_ETIMEOUT;
- ack.bha_params = NULL;
- ack.bha_params_len = 0;
-
- host_hci_outstanding_opcode = 0;
- ble_hci_sched_rx_ack(&ack);
-}
-
-
static int
host_hci_rx_disconn_complete(uint8_t event_code, uint8_t *data, int len)
{
@@ -203,12 +181,13 @@ host_hci_rx_encrypt_change(uint8_t event_code, uint8_t *data, int len)
}
static int
-host_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len)
+host_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len,
+ struct ble_hci_ack *out_ack)
{
- struct ble_hci_ack ack;
uint16_t opcode;
- uint8_t num_pkts;
uint8_t *params;
+ uint8_t params_len;
+ uint8_t num_pkts;
if (len < BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN) {
/* XXX: Increment stat. */
@@ -222,37 +201,33 @@ host_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len)
/* XXX: Process num_pkts field. */
(void)num_pkts;
- if (opcode != BLE_HCI_OPCODE_NOP &&
- opcode != host_hci_outstanding_opcode) {
+ out_ack->bha_opcode = opcode;
- STATS_INC(ble_hs_stats, hci_invalid_ack);
- return BLE_HS_ENOENT;
- }
-
- if (opcode == host_hci_outstanding_opcode) {
- /* Mark the outstanding command as acked. */
- host_hci_outstanding_opcode = 0;
- host_hci_timer_stop();
+ params_len = len - BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN;
+ if (params_len > 0) {
+ out_ack->bha_status = BLE_HS_HCI_ERR(params[0]);
+ } else if (opcode == BLE_HCI_OPCODE_NOP) {
+ out_ack->bha_status = 0;
+ } else {
+ out_ack->bha_status = BLE_HS_ECONTROLLER;
}
- ack.bha_opcode = opcode;
- ack.bha_params = params;
- ack.bha_params_len = len - BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN;
- if (ack.bha_params_len > 0) {
- ack.bha_status = BLE_HS_HCI_ERR(params[0]);
+ /* Don't include the status byte in the parameters blob. */
+ if (params_len > 1) {
+ out_ack->bha_params = params + 1;
+ out_ack->bha_params_len = params_len - 1;
} else {
- ack.bha_status = BLE_HS_ECONTROLLER;
+ out_ack->bha_params = NULL;
+ out_ack->bha_params_len = 0;
}
- ble_hci_sched_rx_ack(&ack);
-
return 0;
}
static int
-host_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len)
+host_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len,
+ struct ble_hci_ack *out_ack)
{
- struct ble_hci_ack ack;
uint16_t opcode;
uint8_t num_pkts;
uint8_t status;
@@ -269,26 +244,10 @@ host_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len)
/* XXX: Process num_pkts field. */
(void)num_pkts;
- /* XXX: This check might be overaggressive for the command status event. */
- if (opcode != BLE_HCI_OPCODE_NOP &&
- opcode != host_hci_outstanding_opcode) {
-
- STATS_INC(ble_hs_stats, hci_invalid_ack);
- return BLE_HS_ENOENT;
- }
-
- if (opcode == host_hci_outstanding_opcode) {
- /* Mark the outstanding command as acked. */
- host_hci_outstanding_opcode = 0;
- host_hci_timer_stop();
- }
-
- ack.bha_opcode = opcode;
- ack.bha_params = NULL;
- ack.bha_params_len = 0;
- ack.bha_status = BLE_HS_HCI_ERR(status);
-
- ble_hci_sched_rx_ack(&ack);
+ out_ack->bha_opcode = opcode;
+ out_ack->bha_params = NULL;
+ out_ack->bha_params_len = 0;
+ out_ack->bha_status = BLE_HS_HCI_ERR(status);
return 0;
}
@@ -318,7 +277,9 @@ host_hci_rx_num_completed_pkts(uint8_t event_code, uint8_t *data, int len)
handle = le16toh(data + off + 2 * i);
num_pkts = le16toh(data + off + 2 * num_handles + 2 * i);
- ble_hs_conn_rx_num_completed_pkts(handle, num_pkts);
+ /* XXX: Do something with these values. */
+ (void)handle;
+ (void)num_pkts;
}
return 0;
@@ -596,7 +557,7 @@ host_hci_event_rx(uint8_t *data)
int rc;
/* Count events received */
- STATS_INC(ble_hs_stats, hci_cmd);
+ STATS_INC(ble_hs_stats, hci_event);
/* Display to console */
host_hci_dbg_event_disp(data);
@@ -637,28 +598,197 @@ host_hci_os_event_proc(struct os_event *ev)
return rc;
}
+static uint8_t *ble_hci_ack_ev;
+static struct os_sem ble_hci_sem;
+
+#if PHONY_HCI_ACKS
+static ble_hci_phony_ack_fn *ble_hci_phony_ack_cb;
+#endif
+
+#if PHONY_HCI_ACKS
+void
+ble_hci_set_phony_ack_cb(ble_hci_phony_ack_fn *cb)
+{
+ ble_hci_phony_ack_cb = cb;
+}
+#endif
+
/* XXX: For now, put this here */
int
ble_hci_transport_ctlr_event_send(uint8_t *hci_ev)
{
- os_error_t err;
struct os_event *ev;
+ os_error_t err;
+ int enqueue;
BLE_HS_DBG_ASSERT(hci_ev != NULL);
- /* Get an event structure off the queue */
- ev = (struct os_event *)os_memblock_get(&g_hci_os_event_pool);
- if (!ev) {
- err = os_memblock_put(&g_hci_cmd_pool, hci_ev);
- BLE_HS_DBG_ASSERT_EVAL(err == OS_OK);
- return -1;
+ switch (hci_ev[0]) {
+ case BLE_HCI_EVCODE_COMMAND_COMPLETE:
+ case BLE_HCI_EVCODE_COMMAND_STATUS:
+ if (hci_ev[3] == 0 && hci_ev[4] == 0) {
+ enqueue = 1;
+ } else {
+ if (ble_hci_ack_ev != NULL) {
+ /* The controller sent two acks. Free the first one. */
+ BLE_HS_DBG_ASSERT(0);
+
+ err = os_memblock_put(&g_hci_cmd_pool, ble_hci_ack_ev);
+ BLE_HS_DBG_ASSERT_EVAL(err == OS_OK);
+ }
+
+ ble_hci_ack_ev = hci_ev;
+ os_sem_release(&ble_hci_sem);
+ enqueue = 0;
+ }
+ break;
+
+ default:
+ enqueue = 1;
+ break;
}
- /* Fill out the event and post to Link Layer */
- ev->ev_queued = 0;
- ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_EVENT;
- ev->ev_arg = hci_ev;
- os_eventq_put(&ble_hs_evq, ev);
+ if (enqueue) {
+ /* Get an event structure off the queue */
+ ev = (struct os_event *)os_memblock_get(&g_hci_os_event_pool);
+ if (!ev) {
+ err = os_memblock_put(&g_hci_cmd_pool, hci_ev);
+ BLE_HS_DBG_ASSERT_EVAL(err == OS_OK);
+ return -1;
+ }
+
+ /* Fill out the event and post to host task. */
+ ev->ev_queued = 0;
+ ev->ev_type = BLE_HOST_HCI_EVENT_CTLR_EVENT;
+ ev->ev_arg = hci_ev;
+ ble_hs_event_enqueue(ev);
+ }
+
+ return 0;
+}
+
+static int
+ble_hci_process_ack(uint8_t *params_buf, uint8_t params_buf_len,
+ struct ble_hci_ack *out_ack)
+{
+ uint8_t event_code;
+ uint8_t param_len;
+ uint8_t event_len;
+ int rc;
+
+ BLE_HS_DBG_ASSERT(ble_hci_ack_ev != NULL);
+
+ /* Count events received */
+ STATS_INC(ble_hs_stats, hci_event);
+
+ /* Display to console */
+ host_hci_dbg_event_disp(ble_hci_ack_ev);
+
+ event_code = ble_hci_ack_ev[0];
+ param_len = ble_hci_ack_ev[1];
+ event_len = param_len + 2;
+
+ /* Clear ack fields up front to silence spurious gcc warnings. */
+ memset(out_ack, 0, sizeof *out_ack);
+
+ switch (event_code) {
+ case BLE_HCI_EVCODE_COMMAND_COMPLETE:
+ rc = host_hci_rx_cmd_complete(event_code, ble_hci_ack_ev, event_len,
+ out_ack);
+ break;
+
+ case BLE_HCI_EVCODE_COMMAND_STATUS:
+ rc = host_hci_rx_cmd_status(event_code, ble_hci_ack_ev, event_len,
+ out_ack);
+ break;
+
+ default:
+ BLE_HS_DBG_ASSERT(0);
+ rc = BLE_HS_EUNKNOWN;
+ break;
+ }
+
+ if (rc == 0) {
+ if (params_buf == NULL) {
+ out_ack->bha_params_len = 0;
+ } else {
+ if (out_ack->bha_params_len > params_buf_len) {
+ out_ack->bha_params_len = params_buf_len;
+ rc = BLE_HS_EMSGSIZE;
+ }
+ memcpy(params_buf, out_ack->bha_params, out_ack->bha_params_len);
+ }
+ out_ack->bha_params = params_buf;
+ }
+
+ os_memblock_put(&g_hci_cmd_pool, ble_hci_ack_ev);
+ ble_hci_ack_ev = NULL;
+
+ return rc;
+}
+
+static int
+ble_hci_wait_for_ack(void)
+{
+ int rc;
+
+#if PHONY_HCI_ACKS
+ if (ble_hci_phony_ack_cb == NULL) {
+ rc = BLE_HS_ETIMEOUT;
+ } else {
+ BLE_HS_DBG_ASSERT(ble_hci_ack_ev == NULL);
+ ble_hci_ack_ev = os_memblock_get(&g_hci_cmd_pool);
+ if (ble_hci_ack_ev == NULL) {
+ rc = BLE_HS_ENOMEM;
+ } else {
+ rc = ble_hci_phony_ack_cb(ble_hci_ack_ev, 260);
+ }
+ }
+#else
+ rc = os_sem_pend(&ble_hci_sem, BLE_HCI_TIMEOUT);
+#endif
+
+ return rc;
+}
+
+int
+ble_hci_tx_cmd(void *cmd, void *evt_buf, uint8_t evt_buf_len,
+ uint8_t *out_evt_buf_len)
+{
+ struct ble_hci_ack ack;
+ int rc;
+
+ rc = host_hci_cmd_send_buf(cmd);
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = ble_hci_wait_for_ack();
+ if (rc != 0) {
+ return rc;
+ }
+
+ rc = ble_hci_process_ack(evt_buf, evt_buf_len, &ack);
+ if (rc != 0) {
+ return rc;
+ }
+
+ if (out_evt_buf_len != NULL) {
+ *out_evt_buf_len = ack.bha_params_len;
+ }
+
+ return ack.bha_status;
+}
+
+int
+ble_hci_tx_cmd_empty_ack(void *cmd)
+{
+ int rc;
+
+ rc = ble_hci_tx_cmd(cmd, NULL, 0, NULL);
+ if (rc != 0) {
+ return rc;
+ }
return 0;
}
@@ -717,7 +847,7 @@ host_hci_data_rx(struct os_mbuf *om)
} else {
handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc);
- ble_hs_conn_lock();
+ ble_hs_lock();
conn = ble_hs_conn_find(handle);
if (conn == NULL) {
@@ -727,7 +857,7 @@ host_hci_data_rx(struct os_mbuf *om)
om = NULL;
}
- ble_hs_conn_unlock();
+ ble_hs_unlock();
}
}
@@ -746,24 +876,6 @@ host_hci_data_rx(struct os_mbuf *om)
return rc;
}
-uint16_t
-host_hci_opcode_join(uint8_t ogf, uint16_t ocf)
-{
- return (ogf << 10) | ocf;
-}
-
-uint16_t
-host_hci_handle_pb_bc_join(uint16_t handle, uint8_t pb, uint8_t bc)
-{
- BLE_HS_DBG_ASSERT(handle <= 0x0fff);
- BLE_HS_DBG_ASSERT(pb <= 0x03);
- BLE_HS_DBG_ASSERT(bc <= 0x03);
-
- return (handle << 0) |
- (pb << 12) |
- (bc << 14);
-}
-
static struct os_mbuf *
host_hci_data_hdr_prepend(struct os_mbuf *om, uint16_t handle, uint8_t pb_flag)
{
@@ -820,8 +932,8 @@ host_hci_data_tx(struct ble_hs_conn *connection, struct os_mbuf *om)
void
host_hci_init(void)
{
- host_hci_outstanding_opcode = 0;
+ int rc;
- os_callout_func_init(&host_hci_timer, &ble_hs_evq,
- host_hci_timer_exp, NULL);
+ rc = os_sem_init(&ble_hci_sem, 0);
+ BLE_HS_DBG_ASSERT_EVAL(rc == 0);
}
http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/e32f9f9f/net/nimble/host/src/host_hci_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/host_hci_cmd.c b/net/nimble/host/src/host_hci_cmd.c
index dd7e14d..180571d 100644
--- a/net/nimble/host/src/host_hci_cmd.c
+++ b/net/nimble/host/src/host_hci_cmd.c
@@ -63,9 +63,6 @@ host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata)
uint8_t *cmd;
uint16_t opcode;
- /* Don't allow multiple commands "in flight." */
- BLE_HS_DBG_ASSERT(host_hci_outstanding_opcode == 0);
-
rc = -1;
cmd = os_memblock_get(&g_hci_cmd_pool);
if (cmd) {
@@ -78,15 +75,11 @@ host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata)
rc = host_hci_cmd_transport(cmd);
BLE_HS_LOG(DEBUG, "host_hci_cmd_send: ogf=0x%02x ocf=0x%02x len=%d\n",
ogf, ocf, len);
- if (rc == 0) {
- host_hci_outstanding_opcode = opcode;
- }
+ ble_hs_misc_log_flat_buf(cmd, len + BLE_HCI_CMD_HDR_LEN);
+ BLE_HS_LOG(DEBUG, "\n");
}
- /* Cancel ack callback if transmission failed. */
- if (rc != 0) {
- ble_hci_sched_set_ack_cb(NULL, NULL);
- } else {
+ if (rc == 0) {
STATS_INC(ble_hs_stats, hci_cmd);
}
@@ -463,13 +456,34 @@ host_hci_cmd_rd_bd_addr(void)
return rc;
}
+static void
+host_hci_cmd_body_set_event_mask(uint64_t event_mask, uint8_t *dst)
+{
+ htole64(dst, event_mask);
+}
+
+void
+host_hci_cmd_build_set_event_mask(uint64_t event_mask,
+ uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(
+ dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_EVENT_MASK_LEN);
+
+ host_hci_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND,
+ BLE_HCI_OCF_CB_SET_EVENT_MASK,
+ BLE_HCI_SET_EVENT_MASK_LEN, dst);
+ dst += BLE_HCI_CMD_HDR_LEN;
+
+ host_hci_cmd_body_set_event_mask(event_mask, dst);
+}
+
int
host_hci_cmd_set_event_mask(uint64_t event_mask)
{
int rc;
uint8_t cmd[BLE_HCI_SET_EVENT_MASK_LEN];
- htole64(cmd, event_mask);
+ host_hci_cmd_body_set_event_mask(event_mask, cmd);
rc = host_hci_cmd_send(BLE_HCI_OGF_CTLR_BASEBAND,
BLE_HCI_OCF_CB_SET_EVENT_MASK,
BLE_HCI_SET_EVENT_MASK_LEN,
@@ -524,13 +538,35 @@ host_hci_cmd_rd_rem_version(uint16_t handle)
return rc;
}
+static void
+host_hci_cmd_body_le_set_event_mask(uint64_t event_mask, uint8_t *dst)
+{
+ htole64(dst, event_mask);
+}
+
+void
+host_hci_cmd_build_le_set_event_mask(uint64_t event_mask,
+ uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(
+ dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_LE_EVENT_MASK_LEN);
+
+ host_hci_write_hdr(BLE_HCI_OGF_LE,
+ BLE_HCI_OCF_LE_SET_EVENT_MASK,
+ BLE_HCI_SET_LE_EVENT_MASK_LEN, dst);
+ dst += BLE_HCI_CMD_HDR_LEN;
+
+ host_hci_cmd_body_le_set_event_mask(event_mask, dst);
+}
+
int
host_hci_cmd_le_set_event_mask(uint64_t event_mask)
{
+ uint8_t cmd[BLE_HCI_SET_LE_EVENT_MASK_LEN];
+
int rc;
- uint8_t cmd[sizeof(uint64_t)];
- htole64(cmd, event_mask);
+ host_hci_cmd_body_le_set_event_mask(event_mask, cmd);
rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_SET_EVENT_MASK, sizeof(uint64_t),
cmd);
@@ -545,6 +581,21 @@ host_hci_cmd_le_set_event_mask(uint64_t event_mask)
*
* @return int
*/
+void
+host_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+ host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_BUF_SIZE, 0, dst);
+}
+
+/**
+ * LE Read buffer size
+ *
+ * OGF = 0x08 (LE)
+ * OCF = 0x0002
+ *
+ * @return int
+ */
int
host_hci_cmd_le_read_buffer_size(void)
{
@@ -642,6 +693,17 @@ host_hci_cmd_le_write_sugg_datalen(uint16_t txoctets, uint16_t txtime)
/**
* OGF=LE, OCF=0x0003
*/
+void
+host_hci_cmd_build_le_read_loc_supp_feat(uint8_t *dst, uint8_t dst_len)
+{
+ BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+ host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT,
+ 0, dst);
+}
+
+/**
+ * OGF=LE, OCF=0x0003
+ */
int
host_hci_cmd_le_read_loc_supp_feat(void)
{
@@ -668,7 +730,7 @@ host_hci_cmd_le_read_rem_used_feat(uint16_t handle)
}
static void
-host_hci_cmd_le_body_set_adv_enable(uint8_t enable, uint8_t *dst)
+host_hci_cmd_body_le_set_adv_enable(uint8_t enable, uint8_t *dst)
{
dst[0] = enable;
}
@@ -684,7 +746,7 @@ host_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst,
BLE_HCI_SET_ADV_ENABLE_LEN, dst);
dst += BLE_HCI_CMD_HDR_LEN;
- host_hci_cmd_le_body_set_adv_enable(enable, dst);
+ host_hci_cmd_body_le_set_adv_enable(enable, dst);
}
int
@@ -693,7 +755,7 @@ host_hci_cmd_le_set_adv_enable(uint8_t enable)
int rc;
uint8_t cmd[BLE_HCI_SET_ADV_ENABLE_LEN];
- host_hci_cmd_le_body_set_adv_enable(enable, cmd);
+ host_hci_cmd_body_le_set_adv_enable(enable, cmd);
rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_SET_ADV_ENABLE,
BLE_HCI_SET_ADV_ENABLE_LEN, cmd);
@@ -936,7 +998,7 @@ host_hci_cmd_le_create_connection(struct hci_create_conn *hcc)
}
void
-host_hci_cmd_le_build_clear_whitelist(uint8_t *dst, int dst_len)
+host_hci_cmd_build_le_clear_whitelist(uint8_t *dst, int dst_len)
{
BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLEAR_WHITE_LIST,
@@ -1031,6 +1093,14 @@ host_hci_cmd_le_rmv_from_whitelist(uint8_t *addr, uint8_t addr_type)
return rc;
}
+void
+host_hci_cmd_build_reset(uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+ host_hci_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET,
+ 0, dst);
+}
+
/**
* Reset the controller and link manager.
*
@@ -1143,6 +1213,42 @@ host_hci_cmd_le_conn_update(struct hci_conn_update *hcu)
return 0;
}
+static void
+host_hci_cmd_body_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr,
+ uint8_t *dst)
+{
+ htole16(dst + 0, hkr->conn_handle);
+ memcpy(dst + 2, hkr->long_term_key, sizeof hkr->long_term_key);
+}
+
+/**
+ * Sends the long-term key (LTK) to the controller.
+ *
+ * Note: This function expects the 128-bit key to be in little-endian byte
+ * order.
+ *
+ * OGF = 0x08 (LE)
+ * OCF = 0x001a
+ *
+ * @param key
+ * @param pt
+ *
+ * @return int
+ */
+void
+host_hci_cmd_build_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr,
+ uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(
+ dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_LT_KEY_REQ_REPLY_LEN);
+
+ host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY,
+ BLE_HCI_LT_KEY_REQ_REPLY_LEN, dst);
+ dst += BLE_HCI_CMD_HDR_LEN;
+
+ host_hci_cmd_body_le_lt_key_req_reply(hkr, dst);
+}
+
/**
* Sends the long-term key (LTK) to the controller.
*
@@ -1163,14 +1269,39 @@ host_hci_cmd_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr)
uint8_t cmd[BLE_HCI_LT_KEY_REQ_REPLY_LEN];
int rc;
- htole16(cmd + 0, hkr->conn_handle);
- memcpy(cmd + 2, hkr->long_term_key, sizeof hkr->long_term_key);
-
+ host_hci_cmd_body_le_lt_key_req_reply(hkr, cmd);
rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_LT_KEY_REQ_REPLY,
sizeof cmd, cmd);
return rc;
}
+static void
+host_hci_cmd_body_le_conn_param_reply(struct hci_conn_param_reply *hcr,
+ uint8_t *dst)
+{
+ htole16(dst + 0, hcr->handle);
+ htole16(dst + 2, hcr->conn_itvl_min);
+ htole16(dst + 4, hcr->conn_itvl_max);
+ htole16(dst + 6, hcr->conn_latency);
+ htole16(dst + 8, hcr->supervision_timeout);
+ htole16(dst + 10, hcr->min_ce_len);
+ htole16(dst + 12, hcr->max_ce_len);
+}
+
+void
+host_hci_cmd_build_le_conn_param_reply(struct hci_conn_param_reply *hcr,
+ uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(
+ dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_PARAM_REPLY_LEN);
+
+ host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_RR,
+ BLE_HCI_CONN_PARAM_REPLY_LEN, dst);
+ dst += BLE_HCI_CMD_HDR_LEN;
+
+ host_hci_cmd_body_le_conn_param_reply(hcr, dst);
+}
+
int
host_hci_cmd_le_lt_key_req_neg_reply(uint16_t handle)
{
@@ -1202,14 +1333,36 @@ host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr)
return rc;
}
+static void
+host_hci_cmd_body_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn,
+ uint8_t *dst)
+{
+ htole16(dst + 0, hcn->handle);
+ dst[2] = hcn->reason;
+}
+
+
+void
+host_hci_cmd_build_le_conn_param_neg_reply(
+ struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(
+ dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_PARAM_NEG_REPLY_LEN);
+
+ host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR,
+ BLE_HCI_CONN_PARAM_NEG_REPLY_LEN, dst);
+ dst += BLE_HCI_CMD_HDR_LEN;
+
+ host_hci_cmd_body_le_conn_param_neg_reply(hcn, dst);
+}
+
int
host_hci_cmd_le_conn_param_neg_reply(struct hci_conn_param_neg_reply *hcn)
{
uint8_t cmd[BLE_HCI_CONN_PARAM_NEG_REPLY_LEN];
int rc;
- htole16(cmd + 0, hcn->handle);
- cmd[2] = hcn->reason;
+ host_hci_cmd_body_le_conn_param_neg_reply(hcn, cmd);
rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR,
BLE_HCI_CONN_PARAM_NEG_REPLY_LEN, cmd);
@@ -1284,12 +1437,50 @@ host_hci_cmd_le_encrypt(uint8_t *key, uint8_t *pt)
*
* @return int
*/
+void
+host_hci_cmd_build_le_rand(uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+ host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RAND, 0, dst);
+}
+
+/**
+ * Get random data
+ *
+ * OGF = 0x08 (LE)
+ * OCF = 0x0018
+ *
+ * @return int
+ */
int
host_hci_cmd_le_rand(void)
{
return host_hci_le_cmd_send(BLE_HCI_OCF_LE_RAND, 0, NULL);
}
+static void
+host_hci_cmd_body_le_start_encrypt(struct hci_start_encrypt *cmd, uint8_t *dst)
+{
+ htole16(dst + 0, cmd->connection_handle);
+ htole64(dst + 2, cmd->random_number);
+ htole16(dst + 10, cmd->encrypted_diversifier);
+ memcpy(dst + 12, cmd->long_term_key, sizeof cmd->long_term_key);
+}
+
+void
+host_hci_cmd_build_le_start_encrypt(struct hci_start_encrypt *cmd,
+ uint8_t *dst, int dst_len)
+{
+ BLE_HS_DBG_ASSERT(
+ dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_LE_START_ENCRYPT_LEN);
+
+ host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_START_ENCRYPT,
+ BLE_HCI_LE_START_ENCRYPT_LEN, dst);
+ dst += BLE_HCI_CMD_HDR_LEN;
+
+ host_hci_cmd_body_le_start_encrypt(cmd, dst);
+}
+
/**
* Enables encryption on a connection.
*
@@ -1303,10 +1494,7 @@ host_hci_cmd_le_start_encrypt(struct hci_start_encrypt *cmd)
{
uint8_t buf[BLE_HCI_LE_START_ENCRYPT_LEN];
- htole16(buf + 0, cmd->connection_handle);
- htole64(buf + 2, cmd->random_number);
- htole16(buf + 10, cmd->encrypted_diversifier);
- memcpy(buf + 12, cmd->long_term_key, sizeof cmd->long_term_key);
+ host_hci_cmd_body_le_start_encrypt(cmd, buf);
return host_hci_le_cmd_send(BLE_HCI_OCF_LE_START_ENCRYPT, sizeof buf, buf);
}