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/04/12 04:02:12 UTC

[2/2] incubator-mynewt-core git commit: ble host - Use blocking HCI tx in GAP procedures.

ble host - Use blocking HCI tx in GAP procedures.

Prior to this change, all HCI exchanges were performed asynchronously
(non-blocking).  The transmits were non-blocking because all HCI
activity was performed in a single task (ble_hs).  With this change,
whenever possible, HCI transmits are done in the application task, which
blocks until the ble_hs task completes the transmit and receives the
acknowledgement (or times out).

This simplifies the GAP code, as it allows us to remove much of the FSM
machinery that was required before.  In addition, it simplifies the API
provided to the application by collapsing several failure scenarios into
a single function return.


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

Branch: refs/heads/develop
Commit: 199d3941d221940638e695d567204231e0aa8390
Parents: b4d4680
Author: Christopher Collins <cc...@apache.org>
Authored: Wed Apr 6 20:45:00 2016 -0700
Committer: Christopher Collins <cc...@apache.org>
Committed: Mon Apr 11 18:58:57 2016 -0700

----------------------------------------------------------------------
 apps/bletiny/src/main.c                      |   9 +-
 net/nimble/host/include/host/ble_gap.h       |   8 +-
 net/nimble/host/include/host/host_hci.h      |  30 +
 net/nimble/host/pkg.yml                      |   1 +
 net/nimble/host/src/ble_gap.c                | 928 ++++++----------------
 net/nimble/host/src/ble_gap_priv.h           |   1 -
 net/nimble/host/src/ble_hci_block.c          | 132 ++-
 net/nimble/host/src/ble_hci_sched.c          |   2 +-
 net/nimble/host/src/ble_hci_sched.h          |   1 -
 net/nimble/host/src/ble_hs_priv.h            |  18 +-
 net/nimble/host/src/ble_ibeacon.c            |  11 +-
 net/nimble/host/src/host_hci_cmd.c           | 548 +++++++++++--
 net/nimble/host/src/test/ble_att_svr_test.c  |   1 -
 net/nimble/host/src/test/ble_gap_test.c      | 638 +++++----------
 net/nimble/host/src/test/ble_hs_adv_test.c   |  76 +-
 net/nimble/host/src/test/ble_hs_conn_test.c  |  74 +-
 net/nimble/host/src/test/ble_hs_test.c       |   7 +-
 net/nimble/host/src/test/ble_hs_test_util.c  | 411 ++++++++--
 net/nimble/host/src/test/ble_hs_test_util.h  |  32 +-
 net/nimble/host/src/test/ble_l2cap_sm_test.c |   4 -
 net/nimble/host/src/test/ble_l2cap_test.c    |  11 +-
 net/nimble/host/src/test/ble_os_test.c       |  38 +-
 22 files changed, 1478 insertions(+), 1503 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/apps/bletiny/src/main.c
----------------------------------------------------------------------
diff --git a/apps/bletiny/src/main.c b/apps/bletiny/src/main.c
index 0740052..20efe2f 100755
--- a/apps/bletiny/src/main.c
+++ b/apps/bletiny/src/main.c
@@ -952,12 +952,6 @@ bletiny_on_l2cap_update(int status, void *arg)
 }
 
 static void
-bletiny_on_wl_set(int status, void *arg)
-{
-    console_printf("white list set status=%d\n", status);
-}
-
-static void
 bletiny_on_scan(int event, int status, struct ble_gap_disc_desc *desc,
                  void *arg)
 {
@@ -1223,8 +1217,7 @@ bletiny_wl_set(struct ble_gap_white_entry *white_list, int white_list_count)
 {
     int rc;
 
-    rc = ble_gap_wl_set(white_list, white_list_count, bletiny_on_wl_set,
-                        NULL);
+    rc = ble_gap_wl_set(white_list, white_list_count);
     return rc;
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/include/host/ble_gap.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/ble_gap.h b/net/nimble/host/include/host/ble_gap.h
index a72f0f1..321a17d 100644
--- a/net/nimble/host/include/host/ble_gap.h
+++ b/net/nimble/host/include/host/ble_gap.h
@@ -95,10 +95,8 @@ struct hci_adv_params;
 #define BLE_GAP_EVENT_TERM_FAILURE          5
 #define BLE_GAP_EVENT_DISC_SUCCESS          6
 #define BLE_GAP_EVENT_DISC_FINISHED         7
-#define BLE_GAP_EVENT_ADV                   8
-#define BLE_GAP_EVENT_ADV_STOP              9
-#define BLE_GAP_EVENT_ADV_FINISHED          10
-#define BLE_GAP_EVENT_SECURITY              11
+#define BLE_GAP_EVENT_ADV_FINISHED          8
+#define BLE_GAP_EVENT_SECURITY              9
 
 struct ble_gap_conn_desc {
     uint8_t peer_addr[6];
@@ -195,7 +193,7 @@ int ble_gap_conn_initiate(int addr_type, uint8_t *addr,
 int ble_gap_terminate(uint16_t handle);
 int ble_gap_cancel(void);
 int ble_gap_wl_set(struct ble_gap_white_entry *white_list,
-                   uint8_t white_list_count, ble_gap_wl_fn *cb, void *cb_arg);
+                   uint8_t white_list_count);
 int ble_gap_update_params(uint16_t conn_handle,
                           struct ble_gap_upd_params *params);
 int ble_gap_security_initiate(uint16_t conn_handle);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/include/host/host_hci.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/include/host/host_hci.h b/net/nimble/host/include/host/host_hci.h
index 0991e72..9caaf3a 100644
--- a/net/nimble/host/include/host/host_hci.h
+++ b/net/nimble/host/include/host/host_hci.h
@@ -27,8 +27,12 @@ struct os_mbuf;
 int host_hci_os_event_proc(struct os_event *ev);
 int host_hci_event_rx(uint8_t *data);
 uint16_t host_hci_opcode_join(uint8_t ogf, uint16_t ocf);
+void host_hci_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len, void *buf);
 int host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata);
+int host_hci_cmd_send_buf(void *cmddata);
 int host_hci_cmd_set_event_mask(uint64_t event_mask);
+void host_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason,
+                                   uint8_t *dst, int dst_len);
 int host_hci_cmd_disconnect(uint16_t handle, uint8_t reason);
 int host_hci_cmd_rd_rem_version(uint16_t handle);
 int host_hci_cmd_rd_local_version(void);
@@ -38,28 +42,54 @@ int host_hci_cmd_rd_bd_addr(void);
 int host_hci_cmd_read_rssi(uint16_t handle);
 int host_hci_cmd_le_set_host_chan_class(uint8_t *new_chan_map);
 int host_hci_cmd_le_rd_chanmap(uint16_t handle);
+int host_hci_cmd_build_le_set_scan_rsp_data(uint8_t *data, uint8_t len,
+                                            uint8_t *dst, int dst_len);
 int host_hci_cmd_le_set_scan_rsp_data(uint8_t *data, uint8_t len);
+int host_hci_cmd_build_le_set_adv_data(uint8_t *data, uint8_t len,
+                                       uint8_t *dst, int dst_len);
 int host_hci_cmd_le_set_adv_data(uint8_t *data, uint8_t len);
+int host_hci_cmd_build_le_set_adv_params(struct hci_adv_params *adv,
+                                         uint8_t *dst, int dst_len);
 int host_hci_cmd_le_set_adv_params(struct hci_adv_params *adv);
 int host_hci_cmd_le_set_rand_addr(uint8_t *addr);
 int host_hci_cmd_le_set_event_mask(uint64_t event_mask);
 int host_hci_cmd_le_read_buffer_size(void);
 int host_hci_cmd_le_read_loc_supp_feat(void);
 int host_hci_cmd_le_read_rem_used_feat(uint16_t handle);
+void host_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst,
+                                          int dst_len);
 int host_hci_cmd_le_set_adv_enable(uint8_t enable);
+int host_hci_cmd_build_le_set_scan_params(uint8_t scan_type,
+                                          uint16_t scan_itvl,
+                                          uint16_t scan_window,
+                                          uint8_t own_addr_type,
+                                          uint8_t filter_policy,
+                                          uint8_t *cmd, int cmd_len);
 int host_hci_cmd_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl, 
                                     uint16_t scan_window,
                                     uint8_t own_addr_type,
                                     uint8_t filter_policy);
+void host_hci_cmd_build_le_set_scan_enable(uint8_t enable,
+                                           uint8_t filter_dups,
+                                           uint8_t *dst, uint8_t dst_len);
 int host_hci_cmd_le_set_scan_enable(uint8_t enable, uint8_t filter_dups);
+int host_hci_cmd_build_le_create_connection(struct hci_create_conn *hcc,
+                                            uint8_t *cmd, int cmd_len);
 int 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);
 int host_hci_cmd_le_clear_whitelist(void);
 int host_hci_cmd_le_read_whitelist(void);
+int host_hci_cmd_build_le_add_to_whitelist(uint8_t *addr, uint8_t addr_type,
+                                           uint8_t *dst, int dst_len);
 int host_hci_cmd_le_add_to_whitelist(uint8_t *addr, uint8_t addr_type);
 int host_hci_cmd_le_rmv_from_whitelist(uint8_t *addr, uint8_t addr_type);
 int host_hci_cmd_reset(void);
+void host_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len);
 int host_hci_cmd_read_adv_pwr(void);
+void host_hci_cmd_build_le_create_conn_cancel(uint8_t *dst, int dst_len);
 int host_hci_cmd_le_create_conn_cancel(void);
+int host_hci_cmd_build_le_conn_update(struct hci_conn_update *hcu,
+                                      uint8_t *dst, int dst_len);
 int host_hci_cmd_le_conn_update(struct hci_conn_update *hcu);
 int host_hci_cmd_le_lt_key_req_reply(struct hci_lt_key_req_reply *hkr);
 int host_hci_cmd_le_conn_param_reply(struct hci_conn_param_reply *hcr);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/pkg.yml
----------------------------------------------------------------------
diff --git a/net/nimble/host/pkg.yml b/net/nimble/host/pkg.yml
index ef4cf2c..a4be5ba 100644
--- a/net/nimble/host/pkg.yml
+++ b/net/nimble/host/pkg.yml
@@ -40,5 +40,6 @@ pkg.req_apis:
 pkg.deps.SELFTEST: libs/console/stub
 pkg.cflags.SELFTEST:
     - -DPHONY_TRANSPORT=1
+    - -DPHONY_HCI_ACKS=1
     - -DNIMBLE_OPT_SM=1
 pkg.cflags.TEST: -DBLE_HS_DEBUG

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/ble_gap.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap.c b/net/nimble/host/src/ble_gap.c
index 1b05856..f4cac43 100644
--- a/net/nimble/host/src/ble_gap.c
+++ b/net/nimble/host/src/ble_gap.c
@@ -34,37 +34,24 @@
 
 #define BLE_GAP_OP_S_ADV                                1
 
-#define BLE_GAP_OP_W_SET                                1
-
 /** Discovery master states. */
-#define BLE_GAP_STATE_M_DISC_PARAMS                     0
-#define BLE_GAP_STATE_M_DISC_ENABLE                     1
-#define BLE_GAP_STATE_M_DISC_ACKED                      2
-#define BLE_GAP_STATE_M_DISC_DISABLE                    3
+#define BLE_GAP_STATE_M_DISC_PENDING                    0
+#define BLE_GAP_STATE_M_DISC_ACTIVE                     1
+#define BLE_GAP_STATE_M_DISC_DISABLE                    2
 
 /** Connect master states. */
-#define BLE_GAP_STATE_M_PENDING                         0
-#define BLE_GAP_STATE_M_UNACKED                         1
-#define BLE_GAP_STATE_M_ACKED                           2
-
-/** Slave states. */
-#define BLE_GAP_STATE_S_PARAMS                          0
-#define BLE_GAP_STATE_S_POWER                           1
-#define BLE_GAP_STATE_S_ADV_DATA                        2
-#define BLE_GAP_STATE_S_RSP_DATA                        3
-#define BLE_GAP_STATE_S_ENABLE                          4
-#define BLE_GAP_STATE_S_ADV                             5
-
-/** White list states. */
-#define BLE_GAP_STATE_W_CLEAR                           0
-#define BLE_GAP_STATE_W_ADD                             1
+#define BLE_GAP_STATE_M_CONN_PENDING                    0
+#define BLE_GAP_STATE_M_CONN_ACTIVE                     1
+
+/** Advertise slave states. */
+#define BLE_GAP_STATE_S_ADV_PENDING                     0
+#define BLE_GAP_STATE_S_ADV_ACTIVE                      1
 
 /** Connection update states. */
 #define BLE_GAP_STATE_U_UPDATE                          0
-#define BLE_GAP_STATE_U_UPDATE_ACKED                    1
-#define BLE_GAP_STATE_U_REPLY                           2
-#define BLE_GAP_STATE_U_REPLY_ACKED                     3
-#define BLE_GAP_STATE_U_NEG_REPLY                       4
+#define BLE_GAP_STATE_U_REPLY                           1
+#define BLE_GAP_STATE_U_REPLY_ACKED                     2
+#define BLE_GAP_STATE_U_NEG_REPLY                       3
 
 /**
  * The maximum amount of user data that can be put into the advertising data.
@@ -106,7 +93,6 @@ static const struct hci_adv_params ble_gap_adv_params_dflt = {
 static bssnz_t struct {
     uint8_t op;
     uint8_t state;
-    uint8_t hci_handle;
 
     unsigned exp_set:1;
     uint32_t exp_os_ticks;
@@ -140,7 +126,6 @@ static bssnz_t struct {
     uint8_t conn_mode;
     uint8_t state;
     uint8_t disc_mode;
-    uint8_t hci_handle;
     ble_gap_conn_fn *cb;
     void *cb_arg;
 
@@ -158,18 +143,6 @@ static bssnz_t struct {
     unsigned adv_pwr_lvl:1;
 } ble_gap_slave;
 
-static bssnz_t struct {
-    ble_gap_wl_fn *cb;
-    void *cb_arg;
-
-    struct ble_gap_white_entry *entries;
-    uint8_t op;
-    uint8_t state;
-    uint8_t count;
-    uint8_t cur;
-    uint8_t hci_handle;
-} ble_gap_wl;
-
 struct ble_gap_update_entry {
     SLIST_ENTRY(ble_gap_update_entry) next;
     struct ble_gap_upd_params params;
@@ -183,23 +156,8 @@ static SLIST_HEAD(, ble_gap_update_entry) ble_gap_update_entries;
 static void *ble_gap_update_mem;
 static struct os_mempool ble_gap_update_pool;
 
-static int ble_gap_adv_params_tx(void *arg);
-static int ble_gap_adv_power_tx(void *arg);
-static int ble_gap_adv_data_tx(void *arg);
-static int ble_gap_adv_rsp_data_tx(void *arg);
-static int ble_gap_adv_enable_tx(void *arg);
-static int ble_gap_wl_tx_add(void *arg);
 static int ble_gap_disc_tx_disable(void *arg);
 
-static ble_hci_sched_tx_fn * const ble_gap_dispatch_adv_und[] = {
-    [BLE_GAP_STATE_S_PARAMS]   = ble_gap_adv_params_tx,
-    [BLE_GAP_STATE_S_POWER]    = ble_gap_adv_power_tx,
-    [BLE_GAP_STATE_S_ADV_DATA] = ble_gap_adv_data_tx,
-    [BLE_GAP_STATE_S_RSP_DATA] = ble_gap_adv_rsp_data_tx,
-    [BLE_GAP_STATE_S_ENABLE]   = ble_gap_adv_enable_tx,
-    [BLE_GAP_STATE_S_ADV]      = NULL,
-};
-
 struct ble_gap_snapshot {
     struct ble_gap_conn_desc desc;
     ble_gap_conn_fn *cb;
@@ -320,15 +278,16 @@ ble_gap_log_update(struct ble_gap_update_entry *entry)
 }
 
 static void
-ble_gap_log_wl(void)
+ble_gap_log_wl(struct ble_gap_white_entry *white_list,
+               uint8_t white_list_count)
 {
     struct ble_gap_white_entry *entry;
     int i;
 
-    BLE_HS_LOG(INFO, "count=%d ", ble_gap_wl.count);
+    BLE_HS_LOG(INFO, "count=%d ", white_list_count);
 
-    for (i = 0; i < ble_gap_wl.count; i++) {
-        entry = ble_gap_wl.entries + i;
+    for (i = 0; i < white_list_count; i++) {
+        entry = white_list + i;
 
         BLE_HS_LOG(INFO, "entry-%d={addr_type=%d addr=", i, entry->addr_type);
         BLE_HS_LOG_ADDR(INFO, entry->addr);
@@ -421,6 +380,7 @@ ble_gap_find_snapshot(uint16_t handle, struct ble_gap_snapshot *snap)
 static void
 ble_gap_master_reset_state(void)
 {
+    ble_gap_master.state = BLE_GAP_STATE_NULL;
     ble_gap_master.op = BLE_GAP_OP_NULL;
 }
 
@@ -431,6 +391,7 @@ ble_gap_master_reset_state(void)
 static void
 ble_gap_slave_reset_state(void)
 {
+    ble_gap_slave.state = BLE_GAP_STATE_NULL;
     ble_gap_slave.op = BLE_GAP_OP_NULL;
 }
 
@@ -584,31 +545,6 @@ ble_gap_call_master_disc_cb(int event, int status, struct ble_hs_adv *adv,
 }
 
 /**
- * Lock restrictions: Caller must NOT lock ble_hs_conn mutex.
- */
-static void
-ble_gap_call_wl_cb(int status, int reset_state)
-{
-    ble_gap_wl_fn *cb;
-    void *cb_arg;
-
-    ble_gap_lock();
-
-    cb = ble_gap_wl.cb;
-    cb_arg = ble_gap_wl.cb_arg;
-
-    if (reset_state) {
-        ble_gap_wl.op = BLE_GAP_OP_NULL;
-    }
-
-    ble_gap_unlock();
-
-    if (cb != NULL) {
-        cb(status, cb_arg);
-    }
-}
-
-/**
  * Lock restrictions:
  *     o Caller locks gap.
  */
@@ -627,30 +563,19 @@ ble_gap_update_find(uint16_t conn_handle)
 }
 
 /**
- * Lock restrictions:
- *     o Caller unlocks gap.
+ * Lock restrictions: None.
  */
 static struct ble_gap_update_entry *
-ble_gap_update_entry_alloc(uint16_t conn_handle,
-                           struct ble_gap_upd_params *params, int state)
+ble_gap_update_entry_alloc(void)
 {
     struct ble_gap_update_entry *entry;
 
-#ifdef BLE_HS_DEBUG
-    ble_gap_lock();
-    BLE_HS_DBG_ASSERT(ble_gap_update_find(conn_handle) == NULL);
-    ble_gap_unlock();
-#endif
-
     entry = os_memblock_get(&ble_gap_update_pool);
     if (entry == NULL) {
         return NULL;
     }
 
     memset(entry, 0, sizeof *entry);
-    entry->conn_handle = conn_handle;
-    entry->params = *params;
-    entry->state = state;
 
     return entry;
 }
@@ -979,61 +904,12 @@ ble_gap_slave_set_op(uint8_t op)
 }
 
 /**
- * Lock restrictions:
- *     o Caller unlocks gap.
- */
-static int
-ble_gap_wl_set_op(uint8_t op)
-{
-    int rc;
-
-    ble_gap_lock();
-
-    if (ble_gap_wl_busy()) {
-        rc = BLE_HS_EBUSY;
-    } else {
-        ble_gap_wl.op = op;
-        rc = 0;
-    }
-
-    ble_gap_unlock();
-
-    return rc;
-}
-
-/**
  * Lock restrictions: None.
  */
 static int
 ble_gap_currently_advertising(void)
 {
-    return ble_gap_slave.op == BLE_GAP_OP_S_ADV &&
-           ble_gap_slave.state == BLE_GAP_STATE_S_ADV;
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static int
-ble_gap_master_enqueue(uint8_t state, int in_progress,
-                       ble_hci_sched_tx_fn *hci_tx_cb, void *cb_arg)
-{
-    int rc;
-
-    ble_hs_misc_assert_no_locks();
-
-    ble_gap_master.state = state;
-    rc = ble_hci_sched_enqueue(hci_tx_cb, cb_arg, &ble_gap_master.hci_handle);
-    if (rc != 0) {
-        if (in_progress) {
-            ble_gap_master_failed(rc);
-        } else {
-            ble_gap_master_reset_state();
-        }
-    }
-
-    return rc;
+    return ble_gap_slave.op == BLE_GAP_OP_S_ADV;
 }
 
 /**
@@ -1067,7 +943,7 @@ ble_gap_accept_master_conn(uint8_t addr_type, uint8_t *addr)
         break;
 
     case BLE_GAP_OP_M_CONN:
-        if (ble_gap_master.state != BLE_GAP_STATE_M_ACKED) {
+        if (ble_gap_master.state != BLE_GAP_STATE_M_CONN_ACTIVE) {
             rc = BLE_HS_ENOENT;
         } else if (ble_gap_master.conn.addr_type == BLE_GAP_ADDR_TYPE_WL ||
                    (addr_type == ble_gap_master.conn.addr_type &&
@@ -1169,7 +1045,7 @@ ble_gap_rx_adv_report(struct ble_hs_adv *adv)
     STATS_INC(ble_gap_stats, rx_adv_report);
 
     if (ble_gap_master.op      != BLE_GAP_OP_M_DISC ||
-        ble_gap_master.state   != BLE_GAP_STATE_M_DISC_ACKED) {
+        ble_gap_master.state   != BLE_GAP_STATE_M_DISC_ACTIVE) {
 
         return;
     }
@@ -1187,7 +1063,7 @@ ble_gap_rx_adv_report(struct ble_hs_adv *adv)
     }
 
     ble_gap_call_master_disc_cb(BLE_GAP_EVENT_DISC_SUCCESS, 0, adv,
-                                     &fields, 0);
+                                &fields, 0);
 }
 
 /**
@@ -1359,8 +1235,7 @@ void
 ble_gap_heartbeat(void)
 {
     int timer_expired;
-
-    ble_gap_lock();
+    int rc;
 
     if (ble_gap_master.op != BLE_GAP_OP_NULL &&
         ble_gap_master.exp_set &&
@@ -1374,14 +1249,15 @@ ble_gap_heartbeat(void)
         timer_expired = 0;
     }
 
-    ble_gap_unlock();
-
     if (timer_expired) {
         switch (ble_gap_master.op) {
         case BLE_GAP_OP_M_DISC:
             /* When a discovery procedure times out, it is not a failure. */
-            ble_gap_master_enqueue(BLE_GAP_STATE_M_DISC_DISABLE, 1,
-                                   ble_gap_disc_tx_disable, NULL);
+            ble_gap_master.state = BLE_GAP_STATE_M_DISC_DISABLE;
+            rc = ble_hci_sched_enqueue(ble_gap_disc_tx_disable, NULL, NULL);
+            if (rc != 0) {
+                ble_gap_master_failed(rc);
+            }
             break;
 
         default:
@@ -1396,34 +1272,20 @@ ble_gap_heartbeat(void)
  *****************************************************************************/
 
 /**
- * XXX: This should be static, as it requires the private gap mutex to be
- * locked.  Currently only called by gap code and test code.
- *
- * Lock restrictions:
- *     o Caller locks gap.
+ * Lock restrictions: None.
  */
-int
+static int
 ble_gap_wl_busy(void)
 {
 #if !NIMBLE_OPT_WHITELIST
     return BLE_HS_ENOTSUP;
 #endif
 
-    /* Check if application is currently setting the white list. */
-    if (ble_gap_wl.op != BLE_GAP_OP_NULL) {
-        return 1;
-    }
-
     /* Check if an auto or selective connection establishment procedure is in
      * progress.
      */
-    if (ble_gap_master.op == BLE_GAP_OP_M_CONN &&
-        ble_gap_master.conn.addr_type == BLE_GAP_ADDR_TYPE_WL) {
-
-        return 1;
-    }
-
-    return 0;
+    return ble_gap_master.op == BLE_GAP_OP_M_CONN &&
+           ble_gap_master.conn.addr_type == BLE_GAP_ADDR_TYPE_WL;
 }
 
 /**
@@ -1431,74 +1293,20 @@ ble_gap_wl_busy(void)
  *     o Caller unlocks all ble_hs mutexes.
  */
 static int
-ble_gap_wl_enqueue(uint8_t state, int in_progress,
-                   ble_hci_sched_tx_fn *hci_tx_cb, void *cb_arg)
+ble_gap_wl_tx_add(struct ble_gap_white_entry *entry)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CHG_WHITE_LIST_LEN];
     int rc;
 
-    ble_gap_wl.state = state;
-    rc = ble_hci_sched_enqueue(hci_tx_cb, cb_arg, &ble_gap_wl.hci_handle);
+    rc = host_hci_cmd_build_le_add_to_whitelist(entry->addr, entry->addr_type,
+                                                buf, sizeof buf);
     if (rc != 0) {
-        if (in_progress) {
-            ble_gap_call_wl_cb(rc, 1);
-        } else {
-            ble_gap_wl.op = BLE_GAP_OP_NULL;
-        }
-    }
-
-    return rc;
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static void
-ble_gap_wl_ack_add(struct ble_hci_ack *ack, void *arg)
-{
-    BLE_HS_DBG_ASSERT(ble_gap_wl.op == BLE_GAP_OP_W_SET);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.state == BLE_GAP_STATE_W_ADD);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_wl.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        ble_gap_call_wl_cb(ack->bha_status, 1);
-        return;
-    }
-
-    ble_gap_wl.cur++;
-    if (ble_gap_wl.cur < ble_gap_wl.count) {
-        ble_gap_wl_enqueue(BLE_GAP_STATE_W_ADD, 1, ble_gap_wl_tx_add, NULL);
-    } else {
-        /* Success. */
-        ble_gap_call_wl_cb(0, 1);
+        return rc;
     }
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static int
-ble_gap_wl_tx_add(void *arg)
-{
-    struct ble_gap_white_entry *white_entry;
-    int rc;
-
-    BLE_HS_DBG_ASSERT(ble_gap_wl.op == BLE_GAP_OP_W_SET);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.state == BLE_GAP_STATE_W_ADD);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.entries != NULL);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.cur < ble_gap_wl.count);
 
-    ble_hci_sched_set_ack_cb(ble_gap_wl_ack_add, NULL);
-
-    white_entry = ble_gap_wl.entries + ble_gap_wl.cur;
-    rc = host_hci_cmd_le_add_to_whitelist(white_entry->addr,
-                                          white_entry->addr_type);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
-        ble_gap_call_wl_cb(rc, 1);
-        return 1;
+        return rc;
     }
 
     return 0;
@@ -1508,41 +1316,16 @@ ble_gap_wl_tx_add(void *arg)
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_wl_ack_clear(struct ble_hci_ack *ack, void *arg)
-{
-    BLE_HS_DBG_ASSERT(ble_gap_wl.op == BLE_GAP_OP_W_SET);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.state == BLE_GAP_STATE_W_CLEAR);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_wl.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        ble_gap_call_wl_cb(ack->bha_status, 1);
-        return;
-    }
-
-    ble_gap_wl_enqueue(BLE_GAP_STATE_W_ADD, 1, ble_gap_wl_tx_add, NULL);
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
 static int
-ble_gap_wl_tx_clear(void *arg)
+ble_gap_wl_tx_clear(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
     int rc;
 
-    BLE_HS_DBG_ASSERT(ble_gap_wl.op == BLE_GAP_OP_W_SET);
-    BLE_HS_DBG_ASSERT(ble_gap_wl.state == BLE_GAP_STATE_W_CLEAR);
-
-    ble_hci_sched_set_ack_cb(ble_gap_wl_ack_clear, NULL);
-
-    rc = host_hci_cmd_le_clear_whitelist();
+    host_hci_cmd_le_build_clear_whitelist(buf, sizeof buf);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
-        ble_gap_call_wl_cb(rc, 1);
-        return 1;
+        return rc;
     }
 
     return 0;
@@ -1554,7 +1337,7 @@ ble_gap_wl_tx_clear(void *arg)
  */
 int
 ble_gap_wl_set(struct ble_gap_white_entry *white_list,
-               uint8_t white_list_count, ble_gap_wl_fn *cb, void *cb_arg)
+               uint8_t white_list_count)
 {
 #if !NIMBLE_OPT_WHITELIST
     return BLE_HS_ENOTSUP;
@@ -1565,7 +1348,7 @@ ble_gap_wl_set(struct ble_gap_white_entry *white_list,
 
     STATS_INC(ble_gap_stats, wl_set);
 
-    if (white_list_count <= 0) {
+    if (white_list_count == 0) {
         rc = BLE_HS_EINVAL;
         goto done;
     }
@@ -1579,27 +1362,27 @@ ble_gap_wl_set(struct ble_gap_white_entry *white_list,
         }
     }
 
-    rc = ble_gap_wl_set_op(BLE_GAP_OP_W_SET);
-    if (rc != 0) {
+    if (ble_gap_wl_busy()) {
+        rc = BLE_HS_EBUSY;
         goto done;
     }
 
-    ble_gap_wl.cb = cb;
-    ble_gap_wl.cb_arg = cb_arg;
-    ble_gap_wl.entries = white_list;
-    ble_gap_wl.count = white_list_count;
-    ble_gap_wl.cur = 0;
-
-    rc = ble_gap_wl_enqueue(BLE_GAP_STATE_W_CLEAR, 0,
-                            ble_gap_wl_tx_clear, NULL);
+    rc = ble_gap_wl_tx_clear();
     if (rc != 0) {
         goto done;
     }
 
+    for (i = 0; i < white_list_count; i++) {
+        rc = ble_gap_wl_tx_add(white_list + i);
+        if (rc != 0) {
+            goto done;
+        }
+    }
+
 done:
     if (rc == 0) {
         BLE_HS_LOG(INFO, "GAP procedure initiated: set whitelist; ");
-        ble_gap_log_wl();
+        ble_gap_log_wl(white_list, white_list_count);
         BLE_HS_LOG(INFO, "\n");
     } else {
         STATS_INC(ble_gap_stats, wl_set_fail);
@@ -1616,35 +1399,16 @@ done:
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_adv_ack_disable(struct ble_hci_ack *ack, void *arg)
-{
-    BLE_HS_DBG_ASSERT(ble_gap_slave.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_slave.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status == 0) {
-        /* Advertising should now be aborted. */
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV_FINISHED, 0, 1);
-    } else {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV_STOP, ack->bha_status, 0);
-    }
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
 static int
-ble_gap_adv_disable_tx(void *arg)
+ble_gap_adv_disable_tx(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_ENABLE_LEN];
     int rc;
 
-    ble_hci_sched_set_ack_cb(ble_gap_adv_ack_disable, NULL);
-    rc = host_hci_cmd_le_set_adv_enable(0);
-    if (rc != BLE_ERR_SUCCESS) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV_STOP, BLE_HS_HCI_ERR(rc), 0);
-        return 1;
+    host_hci_cmd_build_le_set_adv_enable(0, buf, sizeof buf);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
+    if (rc != 0) {
+        return rc;
     }
 
     return 0;
@@ -1671,12 +1435,13 @@ ble_gap_adv_stop(void)
         goto done;
     }
 
-    rc = ble_hci_sched_enqueue(ble_gap_adv_disable_tx, NULL,
-                               &ble_gap_slave.hci_handle);
+    rc = ble_gap_adv_disable_tx();
     if (rc != 0) {
         goto done;
     }
 
+    ble_gap_slave_reset_state();
+
 done:
     if (rc == 0) {
         BLE_HS_LOG(INFO, "GAP procedure initiated: stop advertising; ");
@@ -1723,84 +1488,23 @@ ble_gap_adv_itvls(uint8_t disc_mode, uint8_t conn_mode,
 }
 
 /**
- * Lock restrictions: None.
- */
-static ble_hci_sched_tx_fn *
-ble_gap_adv_get_dispatch(void)
-{
-    return ble_gap_dispatch_adv_und[ble_gap_slave.state];
-}
-
-static int
-ble_gap_adv_should_exec_state(void)
-{
-    switch (ble_gap_slave.state) {
-    case BLE_GAP_STATE_S_PARAMS:
-        return 1;
-
-    case BLE_GAP_STATE_S_POWER:
-        return ble_gap_slave.adv_pwr_lvl;
-
-    case BLE_GAP_STATE_S_ADV_DATA:
-        return ble_gap_slave.conn_mode != BLE_GAP_CONN_MODE_DIR;
-
-    case BLE_GAP_STATE_S_RSP_DATA:
-        return ble_gap_slave.conn_mode != BLE_GAP_CONN_MODE_DIR;
-
-    case BLE_GAP_STATE_S_ENABLE:
-        return 1;
-
-    case BLE_GAP_STATE_S_ADV:
-        return 1;
-
-    default:
-        BLE_HS_DBG_ASSERT(0);
-        return 1;
-    }
-}
-
-/**
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_adv_next_state(void)
+static int
+ble_gap_adv_enable_tx(void)
 {
-    ble_hci_sched_tx_fn *tx_fn;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_PARAM_LEN];
     int rc;
 
-    do {
-        ble_gap_slave.state++;
-    } while (!ble_gap_adv_should_exec_state());
+    host_hci_cmd_build_le_set_adv_enable(1, buf, sizeof buf);
 
-    tx_fn = ble_gap_adv_get_dispatch();
-    if (tx_fn != NULL) {
-        rc = ble_hci_sched_enqueue(tx_fn, NULL, &ble_gap_slave.hci_handle);
-        if (rc != 0) {
-            ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, rc, 1);
-        }
-    } else {
-        /* Procedure complete; indicate success to the application. */
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, 0, 0);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
+    if (rc != 0) {
+        return rc;
     }
-}
 
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static void
-ble_gap_adv_ack(struct ble_hci_ack *ack, void *arg)
-{
-    BLE_HS_DBG_ASSERT(ble_gap_slave.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_slave.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, ack->bha_status, 1);
-    } else {
-        ble_gap_adv_next_state();
-    }
+    return 0;
 }
 
 /**
@@ -1808,35 +1512,21 @@ ble_gap_adv_ack(struct ble_hci_ack *ack, void *arg)
  *     o Caller unlocks all ble_hs mutexes.
  */
 static int
-ble_gap_adv_enable_tx(void *arg)
+ble_gap_adv_rsp_data_tx(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_RSP_DATA_LEN];
     int rc;
 
-    ble_hci_sched_set_ack_cb(ble_gap_adv_ack, NULL);
-    rc = host_hci_cmd_le_set_adv_enable(1);
-    if (rc != BLE_ERR_SUCCESS) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, BLE_HS_HCI_ERR(rc), 1);
-        return 1;
+    rc = host_hci_cmd_build_le_set_scan_rsp_data(ble_gap_slave.rsp_data,
+                                                 ble_gap_slave.rsp_data_len,
+                                                 buf, sizeof buf);
+    if (rc != 0) {
+        return rc;
     }
 
-    return 0;
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static int
-ble_gap_adv_rsp_data_tx(void *arg)
-{
-    int rc;
-
-    ble_hci_sched_set_ack_cb(ble_gap_adv_ack, NULL);
-    rc = host_hci_cmd_le_set_scan_rsp_data(ble_gap_slave.rsp_data,
-                                           ble_gap_slave.rsp_data_len);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, BLE_HS_HCI_ERR(rc), 1);
-        return 1;
+        return rc;
     }
 
     return 0;
@@ -1847,14 +1537,13 @@ ble_gap_adv_rsp_data_tx(void *arg)
  *     o Caller unlocks all ble_hs mutexes.
  */
 static int
-ble_gap_adv_data_tx(void *arg)
+ble_gap_adv_data_tx(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_DATA_LEN];
     uint8_t adv_data_len;
     uint8_t flags;
     int rc;
 
-    BLE_HS_DBG_ASSERT(ble_gap_slave.op != BLE_GAP_OP_NULL);
-
     /* Calculate the value of the flags field from the discoverable mode. */
     flags = 0;
     switch (ble_gap_slave.disc_mode) {
@@ -1894,54 +1583,18 @@ ble_gap_adv_data_tx(void *arg)
         BLE_HS_DBG_ASSERT(rc == 0);
     }
 
-    ble_hci_sched_set_ack_cb(ble_gap_adv_ack, NULL);
-    rc = host_hci_cmd_le_set_adv_data(ble_gap_slave.adv_data,
-                                      adv_data_len);
+    rc = host_hci_cmd_build_le_set_adv_data(ble_gap_slave.adv_data,
+                                            adv_data_len, buf, sizeof buf);
     if (rc != 0) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, BLE_HS_HCI_ERR(rc), 1);
-        return 1;
-    }
-
-    return 0;
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static void
-ble_gap_adv_power_ack(struct ble_hci_ack *ack, void *arg)
-{
-    int8_t power_level;
-
-    BLE_HS_DBG_ASSERT(ble_gap_slave.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_slave.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, ack->bha_status, 1);
-        return;
-    }
-
-    if (ack->bha_params_len != BLE_HCI_ADV_CHAN_TXPWR_ACK_PARAM_LEN) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV,
-                              BLE_HS_ECONTROLLER, 1);
-        return;
+        return rc;
     }
 
-    power_level = ack->bha_params[1];
-    if (power_level < BLE_HCI_ADV_CHAN_TXPWR_MIN ||
-        power_level > BLE_HCI_ADV_CHAN_TXPWR_MAX) {
-
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV,
-                              BLE_HS_ECONTROLLER, 1);
-        return;
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
+    if (rc != 0) {
+        return rc;
     }
 
-    /* Save power level value so it can be put in the advertising data. */
-    ble_gap_slave.tx_pwr_lvl = power_level;
-
-    ble_gap_adv_next_state();
+    return 0;
 }
 
 /**
@@ -1949,17 +1602,28 @@ ble_gap_adv_power_ack(struct ble_hci_ack *ack, void *arg)
  *     o Caller unlocks all ble_hs mutexes.
  */
 static int
-ble_gap_adv_power_tx(void *arg)
+ble_gap_adv_power_tx(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
+    struct ble_hci_block_result result;
+    uint8_t tx_pwr;
     int rc;
 
-    ble_hci_sched_set_ack_cb(ble_gap_adv_power_ack, NULL);
-    rc = host_hci_cmd_read_adv_pwr();
+    host_hci_cmd_build_read_adv_pwr(buf, sizeof buf);
+    rc = ble_hci_block_tx(buf, &tx_pwr, 1, &result);
     if (rc != 0) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, BLE_HS_HCI_ERR(rc), 1);
-        return 1;
+        return rc;
+    }
+
+    if (result.evt_total_len != 1           ||
+        tx_pwr < BLE_HCI_ADV_CHAN_TXPWR_MIN ||
+        tx_pwr > BLE_HCI_ADV_CHAN_TXPWR_MAX) {
+
+        return BLE_HS_ECONTROLLER;
     }
 
+    ble_gap_slave.tx_pwr_lvl = tx_pwr;
+
     return 0;
 }
 
@@ -1968,8 +1632,9 @@ ble_gap_adv_power_tx(void *arg)
  *     o Caller unlocks all ble_hs mutexes.
  */
 static int
-ble_gap_adv_params_tx(void *arg)
+ble_gap_adv_params_tx(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_PARAM_LEN];
     struct hci_adv_params hap;
     int rc;
 
@@ -1994,11 +1659,14 @@ ble_gap_adv_params_tx(void *arg)
         break;
     }
 
-    ble_hci_sched_set_ack_cb(ble_gap_adv_ack, NULL);
-    rc = host_hci_cmd_le_set_adv_params(&hap);
+    rc = host_hci_cmd_build_le_set_adv_params(&hap, buf, sizeof buf);
     if (rc != 0) {
-        ble_gap_call_slave_cb(BLE_GAP_EVENT_ADV, BLE_HS_HCI_ERR(rc), 1);
-        return 1;
+        return rc;
+    }
+
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
+    if (rc != 0) {
+        return rc;
     }
 
     return 0;
@@ -2092,6 +1760,7 @@ ble_gap_adv_start(uint8_t discoverable_mode, uint8_t connectable_mode,
     if (rc != 0) {
         goto done;
     }
+    ble_gap_slave.state = BLE_GAP_STATE_S_ADV_PENDING;
 
     if (connectable_mode == BLE_GAP_CONN_MODE_DIR) {
         ble_gap_slave.dir_addr_type = peer_addr_type;
@@ -2114,13 +1783,37 @@ ble_gap_adv_start(uint8_t discoverable_mode, uint8_t connectable_mode,
                       &ble_gap_slave.adv_params.adv_itvl_min,
                       &ble_gap_slave.adv_params.adv_itvl_max);
 
-    rc = ble_hci_sched_enqueue(ble_gap_adv_params_tx, NULL,
-                               &ble_gap_slave.hci_handle);
+    rc = ble_gap_adv_params_tx();
     if (rc != 0) {
-        ble_gap_slave_reset_state();
         goto done;
     }
 
+    if (ble_gap_slave.adv_pwr_lvl) {
+        rc = ble_gap_adv_power_tx();
+        if (rc != 0) {
+            goto done;
+        }
+    }
+
+    if (ble_gap_slave.conn_mode != BLE_GAP_CONN_MODE_DIR) {
+        rc = ble_gap_adv_data_tx();
+        if (rc != 0) {
+            goto done;
+        }
+
+        rc = ble_gap_adv_rsp_data_tx();
+        if (rc != 0) {
+            goto done;
+        }
+    }
+
+    rc = ble_gap_adv_enable_tx();
+    if (rc != 0) {
+        goto done;
+    }
+
+    ble_gap_slave.state = BLE_GAP_STATE_S_ADV_ACTIVE;
+
 done:
     if (rc == 0) {
         BLE_HS_LOG(INFO, "GAP procedure initiated: advertise; ");
@@ -2128,6 +1821,9 @@ done:
         BLE_HS_LOG(INFO, "\n");
     } else {
         STATS_INC(ble_gap_stats, adv_start_fail);
+        if (rc != BLE_HS_EALREADY) {
+            ble_gap_slave_reset_state();
+        }
     }
 
     return rc;
@@ -2202,9 +1898,6 @@ ble_gap_disc_ack_disable(struct ble_hci_ack *ack, void *arg)
 {
     BLE_HS_DBG_ASSERT(ble_gap_master.op == BLE_GAP_OP_M_DISC);
     BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_DISC_DISABLE);
-    BLE_HS_DBG_ASSERT(ble_gap_master.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_master.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
 
     if (ack->bha_status != 0) {
         ble_gap_master_failed(ack->bha_status);
@@ -2241,38 +1934,15 @@ ble_gap_disc_tx_disable(void *arg)
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_disc_ack_enable(struct ble_hci_ack *ack, void *arg)
-{
-    BLE_HS_DBG_ASSERT(ble_gap_master.op == BLE_GAP_OP_M_DISC);
-    BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_DISC_ENABLE);
-    BLE_HS_DBG_ASSERT(ble_gap_master.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_master.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        ble_gap_master_failed(ack->bha_status);
-    } else {
-        ble_gap_master.state = BLE_GAP_STATE_M_DISC_ACKED;
-    }
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
 static int
-ble_gap_disc_tx_enable(void *arg)
+ble_gap_disc_tx_enable(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_ENABLE_LEN];
     int rc;
 
-    BLE_HS_DBG_ASSERT(ble_gap_master.op == BLE_GAP_OP_M_DISC);
-    BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_DISC_ENABLE);
-
-    ble_hci_sched_set_ack_cb(ble_gap_disc_ack_enable, NULL);
-    rc = host_hci_cmd_le_set_scan_enable(1, 0);
+    host_hci_cmd_build_le_set_scan_enable(1, 0, buf, sizeof buf);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
-        ble_gap_master_failed(rc);
         return rc;
     }
 
@@ -2283,45 +1953,26 @@ ble_gap_disc_tx_enable(void *arg)
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_disc_ack_params(struct ble_hci_ack *ack, void *arg)
-{
-    BLE_HS_DBG_ASSERT(ble_gap_master.op == BLE_GAP_OP_M_DISC);
-    BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_DISC_PARAMS);
-    BLE_HS_DBG_ASSERT(ble_gap_master.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_master.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        ble_gap_master_failed(ack->bha_status);
-        return;
-    }
-
-    ble_gap_master_enqueue(BLE_GAP_STATE_M_DISC_ENABLE, 1,
-                                ble_gap_disc_tx_enable, NULL);
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
 static int
-ble_gap_disc_tx_params(void *arg)
+ble_gap_disc_tx_params(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN];
     int rc;
 
     BLE_HS_DBG_ASSERT(ble_gap_master.op == BLE_GAP_OP_M_DISC);
-    BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_DISC_PARAMS);
+    BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_DISC_PENDING);
 
-    ble_hci_sched_set_ack_cb(ble_gap_disc_ack_params, NULL);
-    rc = host_hci_cmd_le_set_scan_params(
+    rc = host_hci_cmd_build_le_set_scan_params(
         ble_gap_master.disc.scan_type,
         BLE_GAP_SCAN_FAST_INTERVAL_MIN,
         BLE_GAP_SCAN_FAST_WINDOW,
         BLE_HCI_ADV_OWN_ADDR_PUBLIC,
-        ble_gap_master.disc.filter_policy);
+        ble_gap_master.disc.filter_policy,
+        buf, sizeof buf);
+    BLE_HS_DBG_ASSERT_EVAL(rc == 0);
+
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
-        ble_gap_master_failed(rc);
         return rc;
     }
 
@@ -2383,8 +2034,13 @@ ble_gap_disc(uint32_t duration_ms, uint8_t discovery_mode,
     ble_gap_master.disc.filter_policy = filter_policy;
     ble_gap_master.disc.cb = cb;
     ble_gap_master.disc.cb_arg = cb_arg;
-    rc = ble_gap_master_enqueue(BLE_GAP_STATE_M_DISC_PARAMS, 0,
-                                ble_gap_disc_tx_params, NULL);
+
+    rc = ble_gap_disc_tx_params();
+    if (rc != 0) {
+        goto done;
+    }
+
+    rc = ble_gap_disc_tx_enable();
     if (rc != 0) {
         goto done;
     }
@@ -2397,6 +2053,9 @@ done:
         ble_gap_log_disc();
         BLE_HS_LOG(INFO, "\n");
     } else {
+        if (rc != BLE_HS_EALREADY) {
+            ble_gap_master_reset_state();
+        }
         STATS_INC(ble_gap_stats, discover_fail);
     }
 
@@ -2414,22 +2073,6 @@ done:
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_conn_create_ack(struct ble_hci_ack *ack, void *arg)
-{
-    BLE_HS_DBG_ASSERT(ble_gap_master.op == BLE_GAP_OP_M_CONN);
-    BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_UNACKED);
-    BLE_HS_DBG_ASSERT(ble_gap_master.hci_handle == ack->bha_hci_handle);
-
-    ble_gap_master.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        ble_gap_master_failed(ack->bha_status);
-        return;
-    }
-
-    ble_gap_master.state = BLE_GAP_STATE_M_ACKED;
-}
 
 /**
  * Lock restrictions:
@@ -2438,11 +2081,11 @@ ble_gap_conn_create_ack(struct ble_hci_ack *ack, void *arg)
 static int
 ble_gap_conn_create_tx(void *arg)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CREATE_CONN_LEN];
     struct hci_create_conn hcc;
     int rc;
 
     BLE_HS_DBG_ASSERT(ble_gap_master.op == BLE_GAP_OP_M_CONN);
-    BLE_HS_DBG_ASSERT(ble_gap_master.state == BLE_GAP_STATE_M_PENDING);
 
     hcc.scan_itvl = ble_gap_master.conn.params.scan_itvl;
     hcc.scan_window = ble_gap_master.conn.params.scan_window;
@@ -2466,15 +2109,18 @@ ble_gap_conn_create_tx(void *arg)
     hcc.min_ce_len = ble_gap_master.conn.params.min_ce_len;
     hcc.max_ce_len = ble_gap_master.conn.params.max_ce_len;
 
-    ble_gap_master.state = BLE_GAP_STATE_M_UNACKED;
-    ble_hci_sched_set_ack_cb(ble_gap_conn_create_ack, NULL);
+    rc = host_hci_cmd_build_le_create_connection(&hcc, buf, sizeof buf);
+    if (rc != 0) {
+        return BLE_HS_EUNKNOWN;
+    }
 
-    rc = host_hci_cmd_le_create_connection(&hcc);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
-        ble_gap_master_failed(rc);
-        return 1;
+        return rc;
     }
 
+    ble_gap_master.state = BLE_GAP_STATE_M_CONN_ACTIVE;
+
     return 0;
 }
 
@@ -2520,6 +2166,7 @@ ble_gap_conn_initiate(int addr_type, uint8_t *addr,
     if (rc != 0) {
         goto done;
     }
+    ble_gap_master.state = BLE_GAP_STATE_M_CONN_PENDING;
 
     if (params == NULL) {
         ble_gap_master.conn.params = ble_gap_params_dflt;
@@ -2536,8 +2183,7 @@ ble_gap_conn_initiate(int addr_type, uint8_t *addr,
         memcpy(ble_gap_master.conn.addr, addr, BLE_DEV_ADDR_LEN);
     }
 
-    rc = ble_gap_master_enqueue(BLE_GAP_STATE_M_PENDING, 0,
-                                ble_gap_conn_create_tx, NULL);
+    rc = ble_gap_conn_create_tx(NULL);
     if (rc != 0) {
         goto done;
     }
@@ -2548,6 +2194,9 @@ done:
         ble_gap_log_conn();
         BLE_HS_LOG(INFO, "\n");
     } else {
+        if (rc != BLE_HS_EALREADY) {
+            ble_gap_master_reset_state();
+        }
         STATS_INC(ble_gap_stats, initiate_fail);
     }
 
@@ -2562,79 +2211,22 @@ done:
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_terminate_ack(struct ble_hci_ack *ack, void *arg)
-{
-    struct ble_gap_conn_ctxt ctxt;
-    struct ble_gap_snapshot snap;
-    uint16_t handle;
-    int rc;
-
-    if (ack->bha_status != 0) {
-        handle = (uintptr_t)arg;
-        rc = ble_gap_find_snapshot(handle, &snap);
-        if (rc == 0) {
-            STATS_INC(ble_gap_stats, terminate_fail);
-
-            memset(&ctxt, 0, sizeof ctxt);
-            ctxt.desc = &snap.desc;
-            ble_gap_call_conn_cb(BLE_GAP_EVENT_TERM_FAILURE, ack->bha_status,
-                                 &ctxt, snap.cb, snap.cb_arg);
-        }
-    }
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static int
-ble_gap_terminate_tx(void *arg)
-{
-    struct ble_gap_conn_ctxt ctxt;
-    struct ble_gap_snapshot snap;
-    uint16_t handle;
-    int status;
-    int rc;
-
-    handle = (uintptr_t)arg;
-
-    ble_hci_sched_set_ack_cb(ble_gap_terminate_ack, arg);
-
-    status = host_hci_cmd_disconnect(handle, BLE_ERR_REM_USER_CONN_TERM);
-    if (status != 0) {
-        rc = ble_gap_find_snapshot(handle, &snap);
-        if (rc == 0) {
-            STATS_INC(ble_gap_stats, terminate_fail);
-
-            memset(&ctxt, 0, sizeof ctxt);
-            ctxt.desc = &snap.desc;
-            ble_gap_call_conn_cb(BLE_GAP_EVENT_TERM_FAILURE, status, &ctxt,
-                                 snap.cb, snap.cb_arg);
-        }
-    }
-
-    return 0;
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
 int
 ble_gap_terminate(uint16_t conn_handle)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_DISCONNECT_CMD_LEN];
     int rc;
 
     STATS_INC(ble_gap_stats, terminate);
 
     if (!ble_hs_conn_exists(conn_handle)) {
-        rc = BLE_HS_ENOENT;
+        rc = BLE_HS_ENOTCONN;
         goto done;
     }
 
-    rc = ble_hci_sched_enqueue(ble_gap_terminate_tx,
-                               (void *)(uintptr_t)conn_handle, NULL);
+    host_hci_cmd_build_disconnect(conn_handle, BLE_ERR_REM_USER_CONN_TERM,
+                                  buf, sizeof buf);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
         goto done;
     }
@@ -2658,63 +2250,28 @@ done:
  * Lock restrictions:
  *     o Caller unlocks all ble_hs mutexes.
  */
-static void
-ble_gap_cancel_ack(struct ble_hci_ack *ack, void *arg)
-{
-    if (ack->bha_status != 0) {
-        STATS_INC(ble_gap_stats, cancel_fail);
-        ble_gap_call_master_conn_cb(BLE_GAP_EVENT_CANCEL, ack->bha_status, 0);
-    }
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static int
-ble_gap_cancel_tx(void *arg)
-{
-    int rc;
-
-    ble_hci_sched_set_ack_cb(ble_gap_cancel_ack, NULL);
-
-    rc = host_hci_cmd_le_create_conn_cancel();
-    if (rc != 0) {
-        STATS_INC(ble_gap_stats, cancel_fail);
-        ble_gap_call_master_conn_cb(BLE_GAP_EVENT_CANCEL, rc, 0);
-    }
-
-    return 0;
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
 int
 ble_gap_cancel(void)
 {
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
     int rc;
 
     STATS_INC(ble_gap_stats, cancel);
 
-    ble_gap_lock();
-
     if (!ble_gap_master_in_progress()) {
         rc = BLE_HS_ENOENT;
-    } else {
-        if (ble_gap_master.hci_handle != BLE_HCI_SCHED_HANDLE_NONE) {
-            ble_hci_sched_cancel(ble_gap_master.hci_handle);
-            ble_gap_master.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-        }
-
-        rc = ble_hci_sched_enqueue(ble_gap_cancel_tx, NULL, NULL);
+        goto done;
     }
 
-    ble_gap_unlock();
+    host_hci_cmd_build_le_create_conn_cancel(buf, sizeof buf);
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
+    if (rc != 0) {
+        goto done;
+    }
 
+done:
     if (rc == 0) {
-        BLE_HS_LOG(INFO, "GAP procedure initiated: cancel connetion\n");
+        BLE_HS_LOG(INFO, "GAP procedure initiated: cancel connection\n");
     } else {
         STATS_INC(ble_gap_stats, cancel_fail);
     }
@@ -2741,6 +2298,8 @@ ble_gap_param_neg_reply_ack(struct ble_hci_ack *ack, void *arg)
     BLE_HS_DBG_ASSERT(entry->state == BLE_GAP_STATE_U_NEG_REPLY);
     BLE_HS_DBG_ASSERT(entry->hci_handle == ack->bha_hci_handle);
 
+    entry->hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
+
     SLIST_REMOVE(&ble_gap_update_entries, entry,
                  ble_gap_update_entry, next);
 
@@ -2890,8 +2449,7 @@ ble_gap_rx_param_req(struct hci_le_conn_param_req *evt)
     peer_params.min_ce_len = 0;
     peer_params.max_ce_len = 0;
 
-    entry = ble_gap_update_entry_alloc(evt->connection_handle, &peer_params,
-                                       BLE_GAP_STATE_U_REPLY);
+    entry = ble_gap_update_entry_alloc();
     if (entry == NULL) {
         /* Out of memory; reject. */
         /* XXX: Our negative response should indicate which connection handle
@@ -2901,6 +2459,10 @@ ble_gap_rx_param_req(struct hci_le_conn_param_req *evt)
          */
         rc = BLE_ERR_MEM_CAPACITY;
     } else {
+        entry->state = BLE_GAP_STATE_U_REPLY;
+        entry->conn_handle = evt->connection_handle;
+        entry->params = peer_params;
+
         memset(&ctxt, 0, sizeof ctxt);
         ctxt.desc = &snap.desc;
         ctxt.update.self_params = &entry->params;
@@ -2936,51 +2498,15 @@ ble_gap_rx_param_req(struct hci_le_conn_param_req *evt)
 
 /**
  * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
- */
-static void
-ble_gap_update_ack(struct ble_hci_ack *ack, void *arg)
-{
-    struct ble_gap_update_entry *entry;
-
-    ble_gap_lock();
-
-    entry = arg;
-    BLE_HS_DBG_ASSERT(entry->state == BLE_GAP_STATE_U_UPDATE);
-    BLE_HS_DBG_ASSERT(entry->hci_handle == ack->bha_hci_handle);
-
-    ble_gap_master.hci_handle = BLE_HCI_SCHED_HANDLE_NONE;
-
-    if (ack->bha_status != 0) {
-        SLIST_REMOVE(&ble_gap_update_entries, entry,
-                     ble_gap_update_entry, next);
-    } else {
-        entry->state = BLE_GAP_STATE_U_UPDATE_ACKED;
-    }
-
-    ble_gap_unlock();
-
-    if (ack->bha_status != 0) {
-        ble_gap_update_failed(entry, ack->bha_status);
-    }
-}
-
-/**
- * Lock restrictions:
- *     o Caller unlocks all ble_hs mutexes.
+ *     o Caller locks gap.
  */
 static int
-ble_gap_update_tx(void *arg)
+ble_gap_update_tx(struct ble_gap_update_entry *entry)
 {
-    struct ble_gap_update_entry *entry;
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_UPDATE_LEN];
     struct hci_conn_update cmd;
     int rc;
 
-    ble_gap_lock();
-
-    entry = arg;
-    BLE_HS_DBG_ASSERT(entry->state == BLE_GAP_STATE_U_UPDATE);
-
     cmd.handle = entry->conn_handle;
     cmd.conn_itvl_min = entry->params.itvl_min;
     cmd.conn_itvl_max = entry->params.itvl_max;
@@ -2989,18 +2515,14 @@ ble_gap_update_tx(void *arg)
     cmd.min_ce_len = entry->params.min_ce_len;
     cmd.max_ce_len = entry->params.max_ce_len;
 
-    ble_hci_sched_set_ack_cb(ble_gap_update_ack, entry);
-
-    rc = host_hci_cmd_le_conn_update(&cmd);
+    rc = host_hci_cmd_build_le_conn_update(&cmd, buf, sizeof buf);
     if (rc != 0) {
-        SLIST_REMOVE(&ble_gap_update_entries, entry,
-                     ble_gap_update_entry, next);
+        return rc;
     }
 
-    ble_gap_unlock();
-
+    rc = ble_hci_block_tx(buf, NULL, 0, NULL);
     if (rc != 0) {
-        ble_gap_update_failed(entry, rc);
+        return rc;
     }
 
     return 0;
@@ -3023,32 +2545,30 @@ ble_gap_update_params(uint16_t conn_handle, struct ble_gap_upd_params *params)
 
     STATS_INC(ble_gap_stats, update);
 
+    ble_gap_lock();
+
     if (!ble_hs_conn_exists(conn_handle)) {
         rc = BLE_HS_ENOTCONN;
         goto done;
     }
 
-    ble_gap_lock();
     entry = ble_gap_update_find(conn_handle);
-    ble_gap_unlock();
-
     if (entry != NULL) {
         rc = BLE_HS_EALREADY;
         goto done;
     }
 
-    entry = ble_gap_update_entry_alloc(conn_handle, params,
-                                       BLE_GAP_STATE_U_UPDATE);
+    entry = ble_gap_update_entry_alloc();
     if (entry == NULL) {
         rc = BLE_HS_ENOMEM;
         goto done;
     }
 
+    entry->state = BLE_GAP_STATE_U_UPDATE;
     entry->conn_handle = conn_handle;
     entry->params = *params;
-    entry->state = BLE_GAP_STATE_U_UPDATE;
 
-    rc = ble_hci_sched_enqueue(ble_gap_update_tx, entry, &entry->hci_handle);
+    rc = ble_gap_update_tx(entry);
     if (rc != 0) {
         goto done;
     }
@@ -3058,14 +2578,13 @@ done:
         BLE_HS_LOG(INFO, "GAP procedure initiated: ");
         ble_gap_log_update(entry);
         BLE_HS_LOG(INFO, "\n");
-
-        ble_gap_lock();
         SLIST_INSERT_HEAD(&ble_gap_update_entries, entry, next);
-        ble_gap_unlock();
     } else {
         STATS_INC(ble_gap_stats, update_fail);
     }
 
+    ble_gap_unlock();
+
     return rc;
 }
 
@@ -3144,7 +2663,6 @@ ble_gap_init(void)
 
     memset(&ble_gap_master, 0, sizeof ble_gap_master);
     memset(&ble_gap_slave, 0, sizeof ble_gap_slave);
-    memset(&ble_gap_wl, 0, sizeof ble_gap_wl);
 
     free(ble_gap_update_mem);
     ble_gap_update_mem = malloc(

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/ble_gap_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_gap_priv.h b/net/nimble/host/src/ble_gap_priv.h
index 475652e..80aca2f 100644
--- a/net/nimble/host/src/ble_gap_priv.h
+++ b/net/nimble/host/src/ble_gap_priv.h
@@ -79,7 +79,6 @@ void ble_gap_security_event(uint16_t conn_handle, int status,
 int ble_gap_master_in_progress(void);
 int ble_gap_slave_in_progress(void);
 int ble_gap_update_in_progress(uint16_t conn_handle);
-int ble_gap_wl_busy(void);
 
 void ble_gap_heartbeat(void);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/ble_hci_block.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hci_block.c b/net/nimble/host/src/ble_hci_block.c
index f4d0d86..e8112c1 100644
--- a/net/nimble/host/src/ble_hci_block.c
+++ b/net/nimble/host/src/ble_hci_block.c
@@ -36,27 +36,40 @@ static struct os_mutex ble_hci_block_mutex;
 static struct os_sem ble_hci_block_sem;
 
 /** Global state corresponding to the current blocking operation. */
-static struct ble_hci_block_params *ble_hci_block_params;
+static void *ble_hci_block_cmd;
+static void *ble_hci_block_evt_buf;
+static uint8_t ble_hci_block_evt_buf_len;
 static struct ble_hci_block_result *ble_hci_block_result;
 static uint8_t ble_hci_block_handle;
 static int ble_hci_block_status;
 
 /**
+ * Used when the client passes a null result pointer (doesn't care about the
+ * event data).
+ */
+static struct ble_hci_block_result ble_hci_block_result_anon;
+
+#if PHONY_HCI_ACKS
+static uint8_t ble_hci_block_phony_ack_buf[256];
+static ble_hci_block_phony_ack_fn *ble_hci_block_phony_ack_cb;
+#endif
+
+/**
  * Copies the parameters from an acknowledgement into the application event
  * buffer.
  */
 static void
 ble_hci_block_copy_evt_data(void *src_data, uint8_t src_data_len)
 {
-    if (ble_hci_block_params->evt_buf_len > src_data_len) {
-        ble_hci_block_result->evt_buf_len = ble_hci_block_params->evt_buf_len;
+    if (ble_hci_block_evt_buf_len > src_data_len) {
+        ble_hci_block_result->evt_buf_len = ble_hci_block_evt_buf_len;
     } else {
         ble_hci_block_result->evt_buf_len = src_data_len;
     }
     ble_hci_block_result->evt_total_len = src_data_len;
 
     if (ble_hci_block_result->evt_buf_len > 0) {
-        memcpy(ble_hci_block_params->evt_buf, src_data,
+        memcpy(ble_hci_block_evt_buf, src_data,
                ble_hci_block_result->evt_buf_len);
     }
 }
@@ -67,10 +80,19 @@ ble_hci_block_copy_evt_data(void *src_data, uint8_t src_data_len)
 static void
 ble_hci_block_ack_cb(struct ble_hci_ack *ack, void *arg)
 {
+    uint8_t *ack_params;
+    uint8_t ack_params_len;
+
     BLE_HS_DBG_ASSERT(ack->bha_hci_handle == ble_hci_block_handle);
 
-    /* +1/-1 to ignore the status byte. */
-    ble_hci_block_copy_evt_data(ack->bha_params + 1, ack->bha_params_len - 1);
+    ack_params = ack->bha_params;
+    ack_params_len = ack->bha_params_len;
+    if (ack->bha_params_len > 0) {
+        /* +1/-1 to ignore the status byte. */
+        ack_params++;
+        ack_params_len--;
+    }
+    ble_hci_block_copy_evt_data(ack_params, ack_params_len);
     ble_hci_block_status = ack->bha_status;
 
     /* Wake the application task up now that the acknowledgement has been
@@ -86,16 +108,11 @@ ble_hci_block_ack_cb(struct ble_hci_ack *ack, void *arg)
 static int
 ble_hci_block_tx_cb(void *arg)
 {
-    uint16_t ocf;
-    uint8_t ogf;
     int rc;
 
     ble_hci_sched_set_ack_cb(ble_hci_block_ack_cb, NULL);
 
-    ogf = BLE_HCI_OGF(ble_hci_block_params->cmd_opcode);
-    ocf = BLE_HCI_OCF(ble_hci_block_params->cmd_opcode);
-    rc = host_hci_cmd_send(ogf, ocf, ble_hci_block_params->cmd_len,
-                           ble_hci_block_params->cmd_data);
+    rc = host_hci_cmd_send_buf(ble_hci_block_cmd);
     if (rc != 0) {
         os_sem_release(&ble_hci_block_sem);
         return rc;
@@ -104,11 +121,72 @@ ble_hci_block_tx_cb(void *arg)
     return 0;
 }
 
+#if PHONY_HCI_ACKS
+void
+ble_hci_block_set_phony_ack_cb(ble_hci_block_phony_ack_fn *cb)
+{
+    ble_hci_block_phony_ack_cb = cb;
+}
+#endif
+
+
+static int
+ble_hci_block_wait_for_ack(void)
+{
+#if PHONY_HCI_ACKS
+    int rc;
+
+    if (!os_started()) {
+        /* Force the pending HCI command to transmit. */
+        ble_hci_sched_wakeup();
+    }
+    if (ble_hci_block_phony_ack_cb == NULL) {
+        return BLE_HS_ETIMEOUT;
+    } else {
+        rc = ble_hci_block_phony_ack_cb(ble_hci_block_cmd,
+                                        ble_hci_block_phony_ack_buf,
+                                        sizeof ble_hci_block_phony_ack_buf);
+        if (rc == 0) {
+            rc = host_hci_event_rx(ble_hci_block_phony_ack_buf);
+            if (rc == 0) {
+                rc = ble_hci_block_status;
+            }
+        }
+
+        return rc;
+    }
+#else
+    int rc;
+
+    rc = os_sem_pend(&ble_hci_block_sem, BLE_HCI_BLOCK_TIMEOUT);
+    switch (rc) {
+    case 0:
+        rc = ble_hci_block_status;
+        break;
+
+    case OS_NOT_STARTED:
+        rc = BLE_HS_EOS;
+        break;
+
+    case OS_TIMEOUT:
+        rc = BLE_HS_ETIMEOUT;
+        break;
+
+    default:
+        BLE_HS_DBG_ASSERT(0);
+        rc = BLE_HS_EOS;
+        break;
+    }
+
+    return rc;
+#endif
+}
+
 /**
  * Performs a blocking HCI send.  Must not be called from the ble_hs task.
  */
 int
-ble_hci_block_tx(struct ble_hci_block_params *params,
+ble_hci_block_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len,
                  struct ble_hci_block_result *result)
 {
     int rc;
@@ -117,29 +195,21 @@ ble_hci_block_tx(struct ble_hci_block_params *params,
 
     os_mutex_pend(&ble_hci_block_mutex, OS_WAIT_FOREVER);
 
-    memset(result, 0, sizeof *result);
+    ble_hci_block_cmd = cmd;
+    ble_hci_block_evt_buf = evt_buf;
+    ble_hci_block_evt_buf_len = evt_buf_len;
 
-    ble_hci_block_params = params;
-    ble_hci_block_result = result;
+    if (result != NULL) {
+        ble_hci_block_result = result;
+    } else {
+        ble_hci_block_result = &ble_hci_block_result_anon;
+    }
+    memset(ble_hci_block_result, 0, sizeof *ble_hci_block_result);
 
     rc = ble_hci_sched_enqueue(ble_hci_block_tx_cb, NULL,
                                &ble_hci_block_handle);
     if (rc == 0) {
-        rc = os_sem_pend(&ble_hci_block_sem, BLE_HCI_BLOCK_TIMEOUT);
-        switch (rc) {
-        case 0:
-            rc = ble_hci_block_status;
-            break;
-
-        case OS_TIMEOUT:
-            rc = BLE_HS_ETIMEOUT;
-            break;
-
-        default:
-            BLE_HS_DBG_ASSERT(0);
-            rc = BLE_HS_EOS;
-            break;
-        }
+        rc = ble_hci_block_wait_for_ack();
     }
 
     os_mutex_release(&ble_hci_block_mutex);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/ble_hci_sched.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hci_sched.c b/net/nimble/host/src/ble_hci_sched.c
index 8b2f51a..068e986 100644
--- a/net/nimble/host/src/ble_hci_sched.c
+++ b/net/nimble/host/src/ble_hci_sched.c
@@ -357,7 +357,7 @@ ble_hci_sched_wakeup(void)
  * Lock restrictions:
  *     o Caller unlocks hci_sched.
  */
-void
+static void
 ble_hci_sched_transaction_complete(void)
 {
     struct ble_hci_sched_entry *entry;

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/ble_hci_sched.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hci_sched.h b/net/nimble/host/src/ble_hci_sched.h
index e25bee1..a53f06e 100644
--- a/net/nimble/host/src/ble_hci_sched.h
+++ b/net/nimble/host/src/ble_hci_sched.h
@@ -39,7 +39,6 @@ int ble_hci_sched_enqueue(ble_hci_sched_tx_fn *tx_cb, void *tx_cb_arg,
                           uint8_t *out_hci_handle);
 int ble_hci_sched_cancel(uint8_t handle);
 void ble_hci_sched_wakeup(void);
-void ble_hci_sched_transaction_complete(void);
 void ble_hci_sched_rx_ack(struct ble_hci_ack *ack);
 void ble_hci_sched_set_ack_cb(ble_hci_sched_ack_fn *cb, void *arg);
 ble_hci_sched_ack_fn *ble_hci_sched_get_ack_cb(void);

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/ble_hs_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_priv.h b/net/nimble/host/src/ble_hs_priv.h
index b76af74..c9a5f86 100644
--- a/net/nimble/host/src/ble_hs_priv.h
+++ b/net/nimble/host/src/ble_hs_priv.h
@@ -104,21 +104,19 @@ struct os_mbuf *ble_hs_misc_pkthdr(void);
 
 int ble_hs_misc_pullup_base(struct os_mbuf **om, int base_len);
 
-struct ble_hci_block_params {
-    uint16_t cmd_opcode;
-    uint8_t cmd_len;
-    void *cmd_data;
-
-    void *evt_buf;
-    uint8_t evt_buf_len;
-};
-
 struct ble_hci_block_result {
     uint8_t evt_buf_len;
     uint8_t evt_total_len;
 };
 
-int ble_hci_block_tx(struct ble_hci_block_params *params,
+#if PHONY_HCI_ACKS
+typedef int ble_hci_block_phony_ack_fn(void *cmd, uint8_t *ack,
+                                       int ack_buf_len);
+
+void ble_hci_block_set_phony_ack_cb(ble_hci_block_phony_ack_fn *cb);
+#endif
+
+int ble_hci_block_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len,
                      struct ble_hci_block_result *result);
 void ble_hci_block_init(void);
 

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/ble_ibeacon.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_ibeacon.c b/net/nimble/host/src/ble_ibeacon.c
index 92cf382..9f610d2 100644
--- a/net/nimble/host/src/ble_ibeacon.c
+++ b/net/nimble/host/src/ble_ibeacon.c
@@ -25,10 +25,10 @@
 int
 ble_ibeacon_set_adv_data(void *uuid128, uint16_t major, uint16_t minor)
 {
-    struct ble_hci_block_params params;
     struct ble_hci_block_result result;
     struct ble_hs_adv_fields fields;
     uint8_t buf[BLE_IBEACON_MFG_DATA_SIZE];
+    uint8_t hci_cmd[BLE_HCI_CMD_HDR_LEN];
     int rc;
 
     /** Company identifier (Apple). */
@@ -48,13 +48,10 @@ ble_ibeacon_set_adv_data(void *uuid128, uint16_t major, uint16_t minor)
 
     /** Last byte (tx power level) filled in after HCI exchange. */
 
-    memset(&params, 0, sizeof params);
-    params.cmd_opcode = host_hci_opcode_join(BLE_HCI_OGF_LE,
-                                             BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR);
-    params.evt_buf = buf + 24;
-    params.evt_buf_len = 1;
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR, 0,
+                       hci_cmd);
 
-    rc = ble_hci_block_tx(&params, &result);
+    rc = ble_hci_block_tx(hci_cmd, buf + 24, 1, &result);
     if (rc != 0) {
         return rc;
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/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 bb4f8d4..c56fdb1 100644
--- a/net/nimble/host/src/host_hci_cmd.c
+++ b/net/nimble/host/src/host_hci_cmd.c
@@ -43,6 +43,19 @@ host_hci_cmd_transport(uint8_t *cmdbuf)
 #endif
 }
 
+void
+host_hci_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len, void *buf)
+{
+    uint16_t opcode;
+    uint8_t *u8ptr;
+
+    u8ptr = buf;
+
+    opcode = (ogf << 10) | ocf;
+    htole16(u8ptr, opcode);
+    u8ptr[2] = len;
+}
+
 int
 host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata)
 {
@@ -80,6 +93,25 @@ host_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, void *cmddata)
     return rc;
 }
 
+int
+host_hci_cmd_send_buf(void *buf)
+{
+    uint16_t opcode;
+    uint8_t *u8ptr;
+    uint8_t len;
+    int rc;
+
+    u8ptr = buf;
+
+    opcode = le16toh(u8ptr + 0);
+    len = u8ptr[2];
+
+    rc = host_hci_cmd_send(BLE_HCI_OGF(opcode), BLE_HCI_OCF(opcode), len,
+                           u8ptr + BLE_HCI_CMD_HDR_LEN);
+    return rc;
+}
+
+
 /**
  * Send a LE command from the host to the controller.
  * 
@@ -98,32 +130,46 @@ host_hci_le_cmd_send(uint16_t ocf, uint8_t len, void *cmddata)
 }
 
 static int
+host_hci_cmd_body_le_whitelist_chg(uint8_t *addr, uint8_t addr_type,
+                                   uint8_t *dst)
+{
+    if (addr_type > BLE_ADDR_TYPE_RANDOM) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    dst[0] = addr_type;
+    memcpy(dst + 1, addr, BLE_DEV_ADDR_LEN);
+
+    return 0;
+}
+
+static int
 host_hci_cmd_le_whitelist_chg(uint8_t *addr, uint8_t addr_type, uint8_t ocf)
 {
-    int rc;
     uint8_t cmd[BLE_HCI_CHG_WHITE_LIST_LEN];
+    int rc;
 
-    if (addr_type <= BLE_ADDR_TYPE_RANDOM) {
-        cmd[0] = addr_type;
-        memcpy(cmd + 1, addr, BLE_DEV_ADDR_LEN);
-        rc = host_hci_le_cmd_send(ocf, BLE_HCI_CHG_WHITE_LIST_LEN, cmd);
-    } else {
-        rc = BLE_ERR_INV_HCI_CMD_PARMS;
+    rc = host_hci_cmd_body_le_whitelist_chg(addr, addr_type, cmd);
+    if (rc != 0) {
+        return rc;
     }
-    return rc;
+
+    rc = host_hci_le_cmd_send(ocf, BLE_HCI_CHG_WHITE_LIST_LEN, cmd);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
 }
 
-int
-host_hci_cmd_le_set_adv_params(struct hci_adv_params *adv)
+static int
+host_hci_cmd_body_le_set_adv_params(struct hci_adv_params *adv, uint8_t *dst)
 {
-    int rc;
     uint16_t itvl;
-    uint8_t cmd[BLE_HCI_SET_ADV_PARAM_LEN];
 
     BLE_HS_DBG_ASSERT(adv != NULL);
 
     /* Make sure parameters are valid */
-    rc = -1;
     if ((adv->adv_itvl_min > adv->adv_itvl_max) ||
         (adv->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) ||
         (adv->peer_addr_type > BLE_HCI_ADV_PEER_ADDR_MAX) ||
@@ -132,7 +178,7 @@ host_hci_cmd_le_set_adv_params(struct hci_adv_params *adv)
         (adv->adv_channel_map == 0) ||
         ((adv->adv_channel_map & 0xF8) != 0)) {
         /* These parameters are not valid */
-        return rc;
+        return -1;
     }
 
     /* Make sure interval is valid for advertising type. */
@@ -147,23 +193,88 @@ host_hci_cmd_le_set_adv_params(struct hci_adv_params *adv)
     if (adv->adv_type != BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
         if ((adv->adv_itvl_min < itvl) || 
             (adv->adv_itvl_min > BLE_HCI_ADV_ITVL_MAX)) {
-            return rc;
+            return -1;
         }
     }
 
-    htole16(cmd, adv->adv_itvl_min);
-    htole16(cmd + 2, adv->adv_itvl_max);
-    cmd[4] = adv->adv_type;
-    cmd[5] = adv->own_addr_type;
-    cmd[6] = adv->peer_addr_type;
-    memcpy(cmd + 7, adv->peer_addr, BLE_DEV_ADDR_LEN);
-    cmd[13] = adv->adv_channel_map;
-    cmd[14] = adv->adv_filter_policy;
+    htole16(dst, adv->adv_itvl_min);
+    htole16(dst + 2, adv->adv_itvl_max);
+    dst[4] = adv->adv_type;
+    dst[5] = adv->own_addr_type;
+    dst[6] = adv->peer_addr_type;
+    memcpy(dst + 7, adv->peer_addr, BLE_DEV_ADDR_LEN);
+    dst[13] = adv->adv_channel_map;
+    dst[14] = adv->adv_filter_policy;
+
+    return 0;
+}
+
+int
+host_hci_cmd_build_le_set_adv_params(struct hci_adv_params *adv, uint8_t *dst,
+                                     int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_PARAM_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_PARAMS,
+                       BLE_HCI_SET_ADV_PARAM_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    rc = host_hci_cmd_body_le_set_adv_params(adv, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+host_hci_cmd_le_set_adv_params(struct hci_adv_params *adv)
+{
+    int rc;
+    uint8_t cmd[BLE_HCI_SET_ADV_PARAM_LEN];
+
+    rc = host_hci_cmd_body_le_set_adv_params(adv, cmd);
+    if (rc != 0) {
+        return rc;
+    }
 
     rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_SET_ADV_PARAMS, 
                               BLE_HCI_SET_ADV_PARAM_LEN, cmd);
+    if (rc != 0) {
+        return rc;
+    }
 
-    return rc;
+    return 0;
+}
+
+/**
+ * Set advertising data
+ *  
+ * OGF = 0x08 (LE) 
+ * OCF = 0x0008
+ * 
+ * @param data 
+ * @param len 
+ * @param dst 
+ * 
+ * @return int 
+ */
+static int
+host_hci_cmd_body_le_set_adv_data(uint8_t *data, uint8_t len, uint8_t *dst)
+{
+    /* Check for valid parameters */
+    if (((data == NULL) && (len != 0)) || (len > BLE_HCI_MAX_ADV_DATA_LEN)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    memset(dst, 0, BLE_HCI_SET_ADV_DATA_LEN);
+    dst[0] = len;
+    memcpy(dst + 1, data, len);
+
+    return 0;
 }
 
 /**
@@ -174,27 +285,98 @@ host_hci_cmd_le_set_adv_params(struct hci_adv_params *adv)
  * 
  * @param data 
  * @param len 
+ * @param dst 
  * 
  * @return int 
  */
 int
-host_hci_cmd_le_set_adv_data(uint8_t *data, uint8_t len)
+host_hci_cmd_build_le_set_adv_data(uint8_t *data, uint8_t len, uint8_t *dst,
+                                   int dst_len)
 {
     int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_DATA_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_DATA,
+                       BLE_HCI_SET_ADV_DATA_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    rc = host_hci_cmd_body_le_set_adv_data(data, len, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+/**
+ * Set advertising data
+ *  
+ * OGF = 0x08 (LE) 
+ * OCF = 0x0008
+ * 
+ * @param data 
+ * @param len 
+ * 
+ * @return int 
+ */
+int
+host_hci_cmd_le_set_adv_data(uint8_t *data, uint8_t len)
+{
     uint8_t cmd[BLE_HCI_SET_ADV_DATA_LEN];
+    int rc;
 
-    /* Check for valid parameters */
-    if (((data == NULL) && (len != 0)) || (len > BLE_HCI_MAX_ADV_DATA_LEN)) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
+    rc = host_hci_cmd_body_le_set_adv_data(data, len, cmd);
+    if (rc != 0) {
+        return rc;
     }
 
-    memset(cmd, 0, BLE_HCI_SET_ADV_DATA_LEN);
-    cmd[0] = len;
-    memcpy(cmd + 1, data, len);
     rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_SET_ADV_DATA, 
                               BLE_HCI_SET_ADV_DATA_LEN, cmd);
+    if (rc != 0) {
+        return rc;
+    }
 
-    return rc;
+    return 0;
+}
+
+static int
+host_hci_cmd_body_le_set_scan_rsp_data(uint8_t *data, uint8_t len,
+                                       uint8_t *dst)
+{
+    /* Check for valid parameters */
+    if (((data == NULL) && (len != 0)) ||
+         (len > BLE_HCI_MAX_SCAN_RSP_DATA_LEN)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    memset(dst, 0, BLE_HCI_SET_SCAN_RSP_DATA_LEN);
+    dst[0] = len;
+    memcpy(dst + 1, data, len);
+
+    return 0;
+}
+
+int
+host_hci_cmd_build_le_set_scan_rsp_data(uint8_t *data, uint8_t len,
+                                        uint8_t *dst, int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_RSP_DATA_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA,
+                       BLE_HCI_SET_SCAN_RSP_DATA_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    rc = host_hci_cmd_body_le_set_scan_rsp_data(data, len, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
 }
 
 int
@@ -203,19 +385,18 @@ host_hci_cmd_le_set_scan_rsp_data(uint8_t *data, uint8_t len)
     int rc;
     uint8_t cmd[BLE_HCI_SET_SCAN_RSP_DATA_LEN];
 
-    /* Check for valid parameters */
-    if (((data == NULL) && (len != 0)) ||
-         (len > BLE_HCI_MAX_SCAN_RSP_DATA_LEN)) {
-        return BLE_ERR_INV_HCI_CMD_PARMS;
+    rc = host_hci_cmd_body_le_set_scan_rsp_data(data, len, cmd);
+    if (rc != 0) {
+        return rc;
     }
 
-    memset(cmd, 0, BLE_HCI_SET_SCAN_RSP_DATA_LEN);
-    cmd[0] = len;
-    memcpy(cmd + 1, data, len);
     rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_SET_SCAN_RSP_DATA, 
                               BLE_HCI_SET_SCAN_RSP_DATA_LEN, cmd);
+    if (rc != 0) {
+        return rc;
+    }
 
-    return rc;
+    return 0;
 }
 
 /**
@@ -296,14 +477,34 @@ host_hci_cmd_set_event_mask(uint64_t event_mask)
     return rc;
 }
 
+static void
+host_hci_cmd_body_disconnect(uint16_t handle, uint8_t reason, uint8_t *dst)
+{
+    htole16(dst + 0, handle);
+    dst[2] = reason;
+}
+
+void
+host_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason,
+                              uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_DISCONNECT_CMD_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD,
+                       BLE_HCI_DISCONNECT_CMD_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    host_hci_cmd_body_disconnect(handle, reason, dst);
+}
+
 int
 host_hci_cmd_disconnect(uint16_t handle, uint8_t reason)
 {
-    int rc;
     uint8_t cmd[BLE_HCI_DISCONNECT_CMD_LEN];
+    int rc;
 
-    htole16(cmd, handle);
-    cmd[2] = reason;
+    host_hci_cmd_body_disconnect(handle, reason, cmd);
     rc = host_hci_cmd_send(BLE_HCI_OGF_LINK_CTRL,
                            BLE_HCI_OCF_DISCONNECT_CMD,
                            BLE_HCI_DISCONNECT_CMD_LEN,
@@ -466,25 +667,43 @@ host_hci_cmd_le_read_rem_used_feat(uint16_t handle)
     return rc;
 }
 
+static void
+host_hci_cmd_le_body_set_adv_enable(uint8_t enable, uint8_t *dst)
+{
+    dst[0] = enable;
+}
+
+void
+host_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst,
+                                     int dst_len)
+{
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_ENABLE_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADV_ENABLE,
+                       BLE_HCI_SET_ADV_ENABLE_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    host_hci_cmd_le_body_set_adv_enable(enable, dst);
+}
+
 int
 host_hci_cmd_le_set_adv_enable(uint8_t enable)
 {
     int rc;
     uint8_t cmd[BLE_HCI_SET_ADV_ENABLE_LEN];
 
-    cmd[0] = enable;
+    host_hci_cmd_le_body_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);
 
     return rc;
 }
 
-int
-host_hci_cmd_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl, 
-                                uint16_t scan_window, uint8_t own_addr_type, 
-                                uint8_t filter_policy) {
-    int rc;
-    uint8_t cmd[BLE_HCI_SET_SCAN_PARAM_LEN];
+static int
+host_hci_cmd_body_le_set_scan_params(
+    uint8_t scan_type, uint16_t scan_itvl, uint16_t scan_window,
+    uint8_t own_addr_type, uint8_t filter_policy, uint8_t *dst) {
 
     /* Make sure parameters are valid */
     if ((scan_type != BLE_HCI_SCAN_TYPE_PASSIVE) && 
@@ -511,11 +730,54 @@ host_hci_cmd_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl,
         return BLE_ERR_INV_HCI_CMD_PARMS;
     }
 
-    cmd[0] = scan_type;
-    htole16(cmd + 1, scan_itvl);
-    htole16(cmd + 3, scan_window);
-    cmd[5] = own_addr_type;
-    cmd[6] = filter_policy;
+    dst[0] = scan_type;
+    htole16(dst + 1, scan_itvl);
+    htole16(dst + 3, scan_window);
+    dst[5] = own_addr_type;
+    dst[6] = filter_policy;
+
+    return 0;
+}
+
+int
+host_hci_cmd_build_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl,
+                                      uint16_t scan_window,
+                                      uint8_t own_addr_type,
+                                      uint8_t filter_policy,
+                                      uint8_t *cmd, int cmd_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        cmd_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_PARAMS,
+                       BLE_HCI_SET_SCAN_PARAM_LEN, cmd);
+    cmd += BLE_HCI_CMD_HDR_LEN;
+
+    rc = host_hci_cmd_body_le_set_scan_params(scan_type, scan_itvl,
+                                              scan_window, own_addr_type,
+                                              filter_policy, cmd);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+host_hci_cmd_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl, 
+                                uint16_t scan_window, uint8_t own_addr_type, 
+                                uint8_t filter_policy) {
+    int rc;
+    uint8_t cmd[BLE_HCI_SET_SCAN_PARAM_LEN];
+
+    rc = host_hci_cmd_body_le_set_scan_params(scan_type, scan_itvl,
+                                              scan_window, own_addr_type,
+                                              filter_policy, cmd);
+    if (rc != 0) {
+        return rc;
+    }
 
     rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_SET_SCAN_PARAMS, 
                               BLE_HCI_SET_SCAN_PARAM_LEN, cmd);
@@ -523,25 +785,45 @@ host_hci_cmd_le_set_scan_params(uint8_t scan_type, uint16_t scan_itvl,
     return rc;
 }
 
+static void
+host_hci_cmd_body_le_set_scan_enable(uint8_t enable, uint8_t filter_dups,
+                                     uint8_t *dst)
+{
+    dst[0] = enable;
+    dst[1] = filter_dups;
+}
+
+void
+host_hci_cmd_build_le_set_scan_enable(uint8_t enable, uint8_t filter_dups,
+                                      uint8_t *dst, uint8_t dst_len)
+{
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_ENABLE_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_ENABLE,
+                       BLE_HCI_SET_SCAN_ENABLE_LEN, dst);
+
+    host_hci_cmd_body_le_set_scan_enable(enable, filter_dups,
+                                         dst + BLE_HCI_CMD_HDR_LEN);
+}
+
 int
 host_hci_cmd_le_set_scan_enable(uint8_t enable, uint8_t filter_dups)
 {
     int rc;
     uint8_t cmd[BLE_HCI_SET_SCAN_ENABLE_LEN];
 
-    cmd[0] = enable;
-    cmd[1] = filter_dups;
+    host_hci_cmd_body_le_set_scan_enable(enable, filter_dups, cmd);
+
     rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_SET_SCAN_ENABLE, 
                               BLE_HCI_SET_SCAN_ENABLE_LEN, cmd);
     return rc;
 }
 
-int
-host_hci_cmd_le_create_connection(struct hci_create_conn *hcc)
+static int
+host_hci_cmd_body_le_create_connection(struct hci_create_conn *hcc,
+                                       uint8_t *cmd)
 {
-    int rc;
-    uint8_t cmd[BLE_HCI_CREATE_CONN_LEN];
-
     /* Check scan interval and scan window */
     if ((hcc->scan_itvl < BLE_HCI_SCAN_ITVL_MIN) ||
         (hcc->scan_itvl > BLE_HCI_SCAN_ITVL_MAX) ||
@@ -609,9 +891,56 @@ host_hci_cmd_le_create_connection(struct hci_create_conn *hcc)
     htole16(cmd + 21, hcc->min_ce_len);
     htole16(cmd + 23, hcc->max_ce_len);
 
+    return 0;
+}
+
+int
+host_hci_cmd_build_le_create_connection(struct hci_create_conn *hcc,
+                                        uint8_t *cmd, int cmd_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        cmd_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CREATE_CONN_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN,
+                       BLE_HCI_CREATE_CONN_LEN, cmd);
+
+    rc = host_hci_cmd_body_le_create_connection(hcc,
+                                                cmd + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+host_hci_cmd_le_create_connection(struct hci_create_conn *hcc)
+{
+    uint8_t cmd[BLE_HCI_CREATE_CONN_LEN];
+    int rc;
+
+    rc = host_hci_cmd_body_le_create_connection(hcc, cmd);
+    if (rc != 0) {
+        return rc;
+    }
+
     rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_CREATE_CONN,
                               BLE_HCI_CREATE_CONN_LEN, cmd);
-    return rc;
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+void
+host_hci_cmd_le_build_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,
+                       0, dst);
 }
 
 /**
@@ -644,6 +973,27 @@ host_hci_cmd_le_read_whitelist(void)
     return rc;
 }
 
+int
+host_hci_cmd_build_le_add_to_whitelist(uint8_t *addr, uint8_t addr_type,
+                                       uint8_t *dst, int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CHG_WHITE_LIST_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_WHITE_LIST,
+                       BLE_HCI_CHG_WHITE_LIST_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    rc = host_hci_cmd_body_le_whitelist_chg(addr, addr_type, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
 /**
  * Add a device to the whitelist.
  * 
@@ -696,6 +1046,14 @@ host_hci_cmd_reset(void)
     return rc;
 }
 
+void
+host_hci_cmd_build_read_adv_pwr(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_ADV_CHAN_TXPWR,
+                       0, dst);
+}
+
 /**
  * Read the transmit power level used for LE advertising channel packets.
  *
@@ -711,6 +1069,14 @@ host_hci_cmd_read_adv_pwr(void)
     return rc;
 }
 
+void
+host_hci_cmd_build_le_create_conn_cancel(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_CREATE_CONN_CANCEL,
+                       0, dst);
+}
+
 int
 host_hci_cmd_le_create_conn_cancel(void)
 {
@@ -721,24 +1087,60 @@ host_hci_cmd_le_create_conn_cancel(void)
     return rc;
 }
 
+static int
+host_hci_cmd_body_le_conn_update(struct hci_conn_update *hcu, uint8_t *dst)
+{
+    /* XXX: add parameter checking later */
+    htole16(dst + 0, hcu->handle);
+    htole16(dst + 2, hcu->conn_itvl_min);
+    htole16(dst + 4, hcu->conn_itvl_max);
+    htole16(dst + 6, hcu->conn_latency);
+    htole16(dst + 8, hcu->supervision_timeout);
+    htole16(dst + 10, hcu->min_ce_len);
+    htole16(dst + 12, hcu->max_ce_len);
+
+    return 0;
+}
+
 int
-host_hci_cmd_le_conn_update(struct hci_conn_update *hcu)
+host_hci_cmd_build_le_conn_update(struct hci_conn_update *hcu, uint8_t *dst,
+                                  int dst_len)
 {
     int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_UPDATE_LEN);
+
+    host_hci_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CONN_UPDATE,
+                       BLE_HCI_CONN_UPDATE_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    rc = host_hci_cmd_body_le_conn_update(hcu, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+host_hci_cmd_le_conn_update(struct hci_conn_update *hcu)
+{
     uint8_t cmd[BLE_HCI_CONN_UPDATE_LEN];
+    int rc;
 
-    /* XXX: add parameter checking later */
-    htole16(cmd + 0, hcu->handle);
-    htole16(cmd + 2, hcu->conn_itvl_min);
-    htole16(cmd + 4, hcu->conn_itvl_max);
-    htole16(cmd + 6, hcu->conn_latency);
-    htole16(cmd + 8, hcu->supervision_timeout);
-    htole16(cmd + 10, hcu->min_ce_len);
-    htole16(cmd + 12, hcu->max_ce_len);
+    rc = host_hci_cmd_body_le_conn_update(hcu, cmd);
+    if (rc != 0) {
+        return rc;
+    }
 
     rc = host_hci_le_cmd_send(BLE_HCI_OCF_LE_CONN_UPDATE,
                               BLE_HCI_CONN_UPDATE_LEN, cmd);
-    return rc;
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
 }
 
 /**

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/199d3941/net/nimble/host/src/test/ble_att_svr_test.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/test/ble_att_svr_test.c b/net/nimble/host/src/test/ble_att_svr_test.c
index 5690bc4..8ce414d 100644
--- a/net/nimble/host/src/test/ble_att_svr_test.c
+++ b/net/nimble/host/src/test/ble_att_svr_test.c
@@ -2115,7 +2115,6 @@ TEST_SUITE(ble_att_svr_suite)
 int
 ble_att_svr_test_all(void)
 {
-    tu_config.tc_system_assert = 1;
     ble_att_svr_suite();
 
     return tu_any_failed;