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/08/04 02:59:35 UTC

[11/14] incubator-mynewt-core git commit: BLE Host - Rename HCI identifiers and files.

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d842a43c/net/nimble/host/src/ble_hs_hci.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_hci.c b/net/nimble/host/src/ble_hs_hci.c
new file mode 100644
index 0000000..cd5cc6c
--- /dev/null
+++ b/net/nimble/host/src/ble_hs_hci.c
@@ -0,0 +1,528 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "os/os.h"
+#include "nimble/ble_hci_trans.h"
+#include "ble_hs_priv.h"
+#include "ble_hs_dbg_priv.h"
+
+#define BLE_HCI_CMD_TIMEOUT     (OS_TICKS_PER_SEC)
+
+static struct os_mutex ble_hs_hci_mutex;
+static struct os_sem ble_hs_hci_sem;
+
+static uint8_t *ble_hs_hci_ack;
+static uint16_t ble_hs_hci_buf_sz;
+static uint8_t ble_hs_hci_max_pkts;
+
+#if PHONY_HCI_ACKS
+static ble_hs_hci_phony_ack_fn *ble_hs_hci_phony_ack_cb;
+#endif
+
+#if PHONY_HCI_ACKS
+void
+ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn *cb)
+{
+    ble_hs_hci_phony_ack_cb = cb;
+}
+#endif
+
+static void
+ble_hs_hci_lock(void)
+{
+    int rc;
+
+    rc = os_mutex_pend(&ble_hs_hci_mutex, 0xffffffff);
+    BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
+}
+
+static void
+ble_hs_hci_unlock(void)
+{
+    int rc;
+
+    rc = os_mutex_release(&ble_hs_hci_mutex);
+    BLE_HS_DBG_ASSERT_EVAL(rc == 0 || rc == OS_NOT_STARTED);
+}
+
+int
+ble_hs_hci_set_buf_sz(uint16_t pktlen, uint8_t max_pkts)
+{
+    if (pktlen == 0 || max_pkts == 0) {
+        return BLE_HS_EINVAL;
+    }
+
+    ble_hs_hci_buf_sz = pktlen;
+    ble_hs_hci_max_pkts = max_pkts;
+
+    return 0;
+}
+
+static int
+ble_hs_hci_rx_cmd_complete(uint8_t event_code, uint8_t *data, int len,
+                           struct ble_hs_hci_ack *out_ack)
+{
+    uint16_t opcode;
+    uint8_t *params;
+    uint8_t params_len;
+    uint8_t num_pkts;
+
+    if (len < BLE_HCI_EVENT_CMD_COMPLETE_HDR_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    num_pkts = data[2];
+    opcode = le16toh(data + 3);
+    params = data + 5;
+
+    /* XXX: Process num_pkts field. */
+    (void)num_pkts;
+
+    out_ack->bha_opcode = opcode;
+
+    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;
+    }
+
+    /* 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 {
+        out_ack->bha_params = NULL;
+        out_ack->bha_params_len = 0;
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_rx_cmd_status(uint8_t event_code, uint8_t *data, int len,
+                         struct ble_hs_hci_ack *out_ack)
+{
+    uint16_t opcode;
+    uint8_t num_pkts;
+    uint8_t status;
+
+    if (len < BLE_HCI_EVENT_CMD_STATUS_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    status = data[2];
+    num_pkts = data[3];
+    opcode = le16toh(data + 4);
+
+    /* XXX: Process num_pkts field. */
+    (void)num_pkts;
+
+    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;
+}
+
+static int
+ble_hs_hci_process_ack(uint16_t expected_opcode,
+                       uint8_t *params_buf, uint8_t params_buf_len,
+                       struct ble_hs_hci_ack *out_ack)
+{
+    uint8_t event_code;
+    uint8_t param_len;
+    uint8_t event_len;
+    int rc;
+
+    BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL);
+
+    /* Count events received */
+    STATS_INC(ble_hs_stats, hci_event);
+
+    /* Display to console */
+    ble_hs_dbg_event_disp(ble_hs_hci_ack);
+
+    event_code = ble_hs_hci_ack[0];
+    param_len = ble_hs_hci_ack[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 = ble_hs_hci_rx_cmd_complete(event_code, ble_hs_hci_ack,
+                                         event_len, out_ack);
+        break;
+
+    case BLE_HCI_EVCODE_COMMAND_STATUS:
+        rc = ble_hs_hci_rx_cmd_status(event_code, ble_hs_hci_ack,
+                                       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_ECONTROLLER;
+            }
+            memcpy(params_buf, out_ack->bha_params, out_ack->bha_params_len);
+        }
+        out_ack->bha_params = params_buf;
+
+        if (out_ack->bha_opcode != expected_opcode) {
+            rc = BLE_HS_ECONTROLLER;
+        }
+    }
+
+    if (rc != 0) {
+        STATS_INC(ble_hs_stats, hci_invalid_ack);
+    }
+
+    return rc;
+}
+
+static int
+ble_hs_hci_wait_for_ack(void)
+{
+    int rc;
+
+#if PHONY_HCI_ACKS
+    if (ble_hs_hci_phony_ack_cb == NULL) {
+        rc = BLE_HS_ETIMEOUT_HCI;
+    } else {
+        ble_hs_hci_ack =
+            ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
+        BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL);
+        rc = ble_hs_hci_phony_ack_cb(ble_hs_hci_ack, 260);
+    }
+#else
+    rc = os_sem_pend(&ble_hs_hci_sem, BLE_HCI_CMD_TIMEOUT);
+    switch (rc) {
+    case 0:
+        BLE_HS_DBG_ASSERT(ble_hs_hci_ack != NULL);
+        break;
+    case OS_TIMEOUT:
+        rc = BLE_HS_ETIMEOUT_HCI;
+        STATS_INC(ble_hs_stats, hci_timeout);
+        break;
+    default:
+        rc = BLE_HS_EOS;
+        break;
+    }
+#endif
+
+    return rc;
+}
+
+int
+ble_hs_hci_cmd_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len,
+                  uint8_t *out_evt_buf_len)
+{
+    struct ble_hs_hci_ack ack;
+    uint16_t opcode;
+    int rc;
+
+    opcode = le16toh(cmd);
+
+    BLE_HS_DBG_ASSERT(ble_hs_hci_ack == NULL);
+    ble_hs_hci_lock();
+
+    rc = ble_hs_hci_cmd_send_buf(cmd);
+    if (rc != 0) {
+        goto done;
+    }
+
+    rc = ble_hs_hci_wait_for_ack();
+    if (rc != 0) {
+        ble_hs_sched_reset(rc);
+        goto done;
+    }
+
+    rc = ble_hs_hci_process_ack(opcode, evt_buf, evt_buf_len, &ack);
+    if (rc != 0) {
+        ble_hs_sched_reset(rc);
+        goto done;
+    }
+
+    if (out_evt_buf_len != NULL) {
+        *out_evt_buf_len = ack.bha_params_len;
+    }
+
+    rc = ack.bha_status;
+
+done:
+    if (ble_hs_hci_ack != NULL) {
+        ble_hci_trans_buf_free(ble_hs_hci_ack);
+        ble_hs_hci_ack = NULL;
+    }
+
+    ble_hs_hci_unlock();
+    return rc;
+}
+
+int
+ble_hs_hci_cmd_tx_empty_ack(void *cmd)
+{
+    int rc;
+
+    rc = ble_hs_hci_cmd_tx(cmd, NULL, 0, NULL);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+void
+ble_hs_hci_rx_ack(uint8_t *ack_ev)
+{
+    if (ble_hs_hci_sem.sem_tokens != 0) {
+        /* This ack is unexpected; ignore it. */
+        ble_hci_trans_buf_free(ack_ev);
+        return;
+    }
+    BLE_HS_DBG_ASSERT(ble_hs_hci_ack == NULL);
+
+    /* Unblock the application now that the HCI command buffer is populated
+     * with the acknowledgement.
+     */
+    ble_hs_hci_ack = ack_ev;
+    os_sem_release(&ble_hs_hci_sem);
+}
+
+int
+ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg)
+{
+    int enqueue;
+
+    BLE_HS_DBG_ASSERT(hci_ev != NULL);
+
+    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 {
+            ble_hs_hci_rx_ack(hci_ev);
+            enqueue = 0;
+        }
+        break;
+
+    default:
+        enqueue = 1;
+        break;
+    }
+
+    if (enqueue) {
+        ble_hs_enqueue_hci_event(hci_ev);
+    }
+
+    return 0;
+}
+
+
+/**
+ * Splits an appropriately-sized fragment from the front of an outgoing ACL
+ * data packet, if necessary.  If the packet size is within the controller's
+ * buffer size requirements, no splitting is performed.  The fragment data is
+ * removed from the data packet mbuf.
+ *
+ * @param om                    The ACL data packet.
+ * @param out_frag              On success, this points to the fragment to
+ *                                  send.  If the entire packet can fit within
+ *                                  a single fragment, this will point to the
+ *                                  ACL data packet itself ('om').
+ *
+ * @return                      BLE_HS_EDONE: success; this is the final
+ *                                  fragment.
+ *                              BLE_HS_EAGAIN: success; more data remains in
+ *                                  the original mbuf.
+ *                              Other BLE host core return code on error.
+ */
+static int
+ble_hs_hci_split_frag(struct os_mbuf **om, struct os_mbuf **out_frag)
+{
+    struct os_mbuf *frag;
+    int rc;
+
+    if (OS_MBUF_PKTLEN(*om) <= ble_hs_hci_buf_sz) {
+        /* Final fragment. */
+        *out_frag = *om;
+        *om = NULL;
+        return BLE_HS_EDONE;
+    }
+
+    frag = ble_hs_mbuf_acm_pkt();
+    if (frag == NULL) {
+        rc = BLE_HS_ENOMEM;
+        goto err;
+    }
+
+    /* Move data from the front of the packet into the fragment mbuf. */
+    rc = os_mbuf_appendfrom(frag, *om, 0, ble_hs_hci_buf_sz);
+    if (rc != 0) {
+        rc = BLE_HS_ENOMEM;
+        goto err;
+    }
+    os_mbuf_adj(*om, ble_hs_hci_buf_sz);
+
+    /* More fragments to follow. */
+    *out_frag = frag;
+    return BLE_HS_EAGAIN;
+
+err:
+    os_mbuf_free_chain(frag);
+    return rc;
+}
+
+static struct os_mbuf *
+ble_hs_hci_acl_hdr_prepend(struct os_mbuf *om, uint16_t handle,
+                           uint8_t pb_flag)
+{
+    struct hci_data_hdr hci_hdr;
+    struct os_mbuf *om2;
+
+    hci_hdr.hdh_handle_pb_bc =
+        ble_hs_hci_util_handle_pb_bc_join(handle, pb_flag, 0);
+    htole16(&hci_hdr.hdh_len, OS_MBUF_PKTHDR(om)->omp_len);
+
+    om2 = os_mbuf_prepend(om, sizeof hci_hdr);
+    if (om2 == NULL) {
+        return NULL;
+    }
+
+    om = om2;
+    om = os_mbuf_pullup(om, sizeof hci_hdr);
+    if (om == NULL) {
+        return NULL;
+    }
+
+    memcpy(om->om_data, &hci_hdr, sizeof hci_hdr);
+
+    BLE_HS_LOG(DEBUG, "host tx hci data; handle=%d length=%d\n", handle,
+               le16toh(&hci_hdr.hdh_len));
+
+    return om;
+}
+
+/**
+ * Transmits an HCI ACL data packet.  This function consumes the supplied mbuf,
+ * regardless of the outcome.
+ *
+ * XXX: Ensure the controller has sufficient buffer capacity for the outgoing
+ * fragments.
+ */
+int
+ble_hs_hci_acl_tx(struct ble_hs_conn *connection, struct os_mbuf *txom)
+{
+    struct os_mbuf *frag;
+    uint8_t pb;
+    int done;
+    int rc;
+
+    /* The first fragment uses the first-non-flush packet boundary value.
+     * After sending the first fragment, pb gets set appropriately for all
+     * subsequent fragments in this packet.
+     */
+    pb = BLE_HCI_PB_FIRST_NON_FLUSH;
+
+    /* Send fragments until the entire packet has been sent. */
+    done = 0;
+    while (!done) {
+        rc = ble_hs_hci_split_frag(&txom, &frag);
+        switch (rc) {
+        case BLE_HS_EDONE:
+            /* This is the final fragment. */
+            done = 1;
+            break;
+
+        case BLE_HS_EAGAIN:
+            /* More fragments to follow. */
+            break;
+
+        default:
+            goto err;
+        }
+
+        frag = ble_hs_hci_acl_hdr_prepend(frag, connection->bhc_handle, pb);
+        if (frag == NULL) {
+            rc = BLE_HS_ENOMEM;
+            goto err;
+        }
+        pb = BLE_HCI_PB_MIDDLE;
+
+        BLE_HS_LOG(DEBUG, "ble_hs_hci_acl_tx(): ");
+        ble_hs_log_mbuf(frag);
+        BLE_HS_LOG(DEBUG, "\n");
+
+        /* XXX: Try to pullup the entire fragment.  The controller currently
+         * requires the entire fragment to fit in a single buffer.  When this
+         * restriction is removed from the controller, this operation can be
+         * removed.
+         */
+        frag = os_mbuf_pullup(frag, OS_MBUF_PKTLEN(frag));
+        if (frag == NULL) {
+            rc = BLE_HS_ENOMEM;
+            goto err;
+        }
+
+        rc = ble_hs_tx_data(frag);
+        if (rc != 0) {
+            goto err;
+        }
+
+        connection->bhc_outstanding_pkts++;
+    }
+
+    return 0;
+
+err:
+    BLE_HS_DBG_ASSERT(rc != 0);
+
+    os_mbuf_free_chain(txom);
+    return rc;
+}
+
+void
+ble_hs_hci_init(void)
+{
+    int rc;
+
+    rc = os_sem_init(&ble_hs_hci_sem, 0);
+    BLE_HS_DBG_ASSERT_EVAL(rc == 0);
+
+    rc = os_mutex_init(&ble_hs_hci_mutex);
+    BLE_HS_DBG_ASSERT_EVAL(rc == 0);
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d842a43c/net/nimble/host/src/ble_hs_hci_cmd.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_hci_cmd.c b/net/nimble/host/src/ble_hs_hci_cmd.c
new file mode 100644
index 0000000..82b442d
--- /dev/null
+++ b/net/nimble/host/src/ble_hs_hci_cmd.c
@@ -0,0 +1,1375 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <stdint.h>
+#include <assert.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "os/os.h"
+#include "console/console.h"
+#include "nimble/hci_common.h"
+#include "nimble/ble_hci_trans.h"
+#include "ble_hs_dbg_priv.h"
+#include "ble_hs_priv.h"
+
+static int
+ble_hs_hci_cmd_transport(uint8_t *cmdbuf)
+{
+    int rc;
+
+    rc = ble_hci_trans_hs_cmd_tx(cmdbuf);
+    switch (rc) {
+    case 0:
+        return 0;
+
+    case BLE_ERR_MEM_CAPACITY:
+        return BLE_HS_ENOMEM_EVT;
+
+    default:
+        return BLE_HS_EUNKNOWN;
+    }
+}
+
+void
+ble_hs_hci_cmd_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
+ble_hs_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len, const void *cmddata)
+{
+    uint8_t *buf;
+    int rc;
+
+    buf = ble_hci_trans_buf_alloc(BLE_HCI_TRANS_BUF_CMD);
+    BLE_HS_DBG_ASSERT(buf != NULL);
+
+    htole16(buf, ogf << 10 | ocf);
+    buf[2] = len;
+    if (len != 0) {
+        memcpy(buf + BLE_HCI_CMD_HDR_LEN, cmddata, len);
+    }
+
+    BLE_HS_LOG(DEBUG, "ble_hs_hci_cmd_send: ogf=0x%02x ocf=0x%02x len=%d\n",
+               ogf, ocf, len);
+    ble_hs_log_flat_buf(buf, len + BLE_HCI_CMD_HDR_LEN);
+    BLE_HS_LOG(DEBUG, "\n");
+    rc = ble_hs_hci_cmd_transport(buf);
+
+    if (rc == 0) {
+        STATS_INC(ble_hs_stats, hci_cmd);
+    } else {
+        BLE_HS_LOG(DEBUG, "ble_hs_hci_cmd_send failure; rc=%d\n", rc);
+    }
+
+    return rc;
+}
+
+int
+ble_hs_hci_cmd_send_buf(void *buf)
+{
+    uint16_t opcode;
+    uint8_t *u8ptr;
+    uint8_t len;
+    int rc;
+
+    switch (ble_hs_sync_state) {
+    case BLE_HS_SYNC_STATE_BAD:
+        return BLE_HS_ENOTSYNCED;
+
+    case BLE_HS_SYNC_STATE_BRINGUP:
+        if (!ble_hs_is_parent_task()) {
+            return BLE_HS_ENOTSYNCED;
+        }
+        break;
+
+    case BLE_HS_SYNC_STATE_GOOD:
+        break;
+
+    default:
+        BLE_HS_DBG_ASSERT(0);
+        return BLE_HS_EUNKNOWN;
+    }
+
+    u8ptr = buf;
+
+    opcode = le16toh(u8ptr + 0);
+    len = u8ptr[2];
+
+    rc = ble_hs_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.
+ *
+ * @param ocf
+ * @param len
+ * @param cmddata
+ *
+ * @return int
+ */
+static int
+ble_hs_hci_cmd_le_send(uint16_t ocf, uint8_t len, void *cmddata)
+{
+    int rc;
+    rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LE, ocf, len, cmddata);
+    return rc;
+}
+
+/**
+ * Read BD_ADDR
+ *
+ * OGF = 0x04 (Informational parameters)
+ * OCF = 0x0009
+ */
+void
+ble_hs_hci_cmd_build_read_bd_addr(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_INFO_PARAMS,
+                             BLE_HCI_OCF_IP_RD_BD_ADDR,
+                             0, dst);
+}
+
+static int
+ble_hs_hci_cmd_body_le_whitelist_chg(const 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
+ble_hs_hci_cmd_body_le_set_adv_params(const struct hci_adv_params *adv,
+                                      uint8_t *dst)
+{
+    uint16_t itvl;
+
+    BLE_HS_DBG_ASSERT(adv != NULL);
+
+    /* Make sure parameters are valid */
+    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) ||
+        (adv->adv_filter_policy > BLE_HCI_ADV_FILT_MAX) ||
+        (adv->adv_type > BLE_HCI_ADV_TYPE_MAX) ||
+        (adv->adv_channel_map == 0) ||
+        ((adv->adv_channel_map & 0xF8) != 0)) {
+        /* These parameters are not valid */
+        return -1;
+    }
+
+    /* Make sure interval is valid for advertising type. */
+    if ((adv->adv_type == BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) ||
+        (adv->adv_type == BLE_HCI_ADV_TYPE_ADV_SCAN_IND)) {
+        itvl = BLE_HCI_ADV_ITVL_NONCONN_MIN;
+    } else {
+        itvl = BLE_HCI_ADV_ITVL_MIN;
+    }
+
+    /* Do not check if high duty-cycle directed */
+    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 -1;
+        }
+    }
+
+    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
+ble_hs_hci_cmd_build_le_set_adv_params(const 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);
+
+    ble_hs_hci_cmd_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 = ble_hs_hci_cmd_body_le_set_adv_params(adv, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+/**
+ * Set advertising data
+ *
+ * OGF = 0x08 (LE)
+ * OCF = 0x0008
+ *
+ * @param data
+ * @param len
+ * @param dst
+ *
+ * @return int
+ */
+static int
+ble_hs_hci_cmd_body_le_set_adv_data(const 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;
+}
+
+/**
+ * Set advertising data
+ *
+ * OGF = 0x08 (LE)
+ * OCF = 0x0008
+ *
+ * @param data
+ * @param len
+ * @param dst
+ *
+ * @return int
+ */
+int
+ble_hs_hci_cmd_build_le_set_adv_data(const 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);
+
+    ble_hs_hci_cmd_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 = ble_hs_hci_cmd_body_le_set_adv_data(data, len, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_cmd_body_le_set_scan_rsp_data(const 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
+ble_hs_hci_cmd_build_le_set_scan_rsp_data(const 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);
+
+    ble_hs_hci_cmd_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 = ble_hs_hci_cmd_body_le_set_scan_rsp_data(data, len, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static void
+ble_hs_hci_cmd_body_set_event_mask(uint64_t event_mask, uint8_t *dst)
+{
+    htole64(dst, event_mask);
+}
+
+void
+ble_hs_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);
+
+    ble_hs_hci_cmd_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;
+
+    ble_hs_hci_cmd_body_set_event_mask(event_mask, dst);
+}
+
+void
+ble_hs_hci_cmd_build_set_event_mask2(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);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND,
+                       BLE_HCI_OCF_CB_SET_EVENT_MASK2,
+                       BLE_HCI_SET_EVENT_MASK_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    ble_hs_hci_cmd_body_set_event_mask(event_mask, dst);
+}
+
+static void
+ble_hs_hci_cmd_body_disconnect(uint16_t handle, uint8_t reason, uint8_t *dst)
+{
+    htole16(dst + 0, handle);
+    dst[2] = reason;
+}
+
+void
+ble_hs_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);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_DISCONNECT_CMD,
+                       BLE_HCI_DISCONNECT_CMD_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    ble_hs_hci_cmd_body_disconnect(handle, reason, dst);
+}
+
+int
+ble_hs_hci_cmd_disconnect(uint16_t handle, uint8_t reason)
+{
+    uint8_t cmd[BLE_HCI_DISCONNECT_CMD_LEN];
+    int rc;
+
+    ble_hs_hci_cmd_body_disconnect(handle, reason, cmd);
+    rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LINK_CTRL,
+                           BLE_HCI_OCF_DISCONNECT_CMD,
+                           BLE_HCI_DISCONNECT_CMD_LEN,
+                           cmd);
+    return rc;
+}
+
+static void
+ble_hs_hci_cmd_body_le_set_event_mask(uint64_t event_mask, uint8_t *dst)
+{
+    htole64(dst, event_mask);
+}
+
+void
+ble_hs_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);
+
+    ble_hs_hci_cmd_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;
+
+    ble_hs_hci_cmd_body_le_set_event_mask(event_mask, dst);
+}
+
+/**
+ * LE Read buffer size
+ *
+ * OGF = 0x08 (LE)
+ * OCF = 0x0002
+ *
+ * @return int
+ */
+void
+ble_hs_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+    ble_hs_hci_cmd_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
+ble_hs_hci_cmd_le_read_buffer_size(void)
+{
+    int rc;
+
+    rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_RD_BUF_SIZE, 0, NULL);
+    return rc;
+}
+
+/**
+ * OGF=LE, OCF=0x0003
+ */
+void
+ble_hs_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);
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_LOC_SUPP_FEAT,
+                       0, dst);
+}
+
+static void
+ble_hs_hci_cmd_body_le_set_adv_enable(uint8_t enable, uint8_t *dst)
+{
+    dst[0] = enable;
+}
+
+void
+ble_hs_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);
+
+    ble_hs_hci_cmd_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;
+
+    ble_hs_hci_cmd_body_le_set_adv_enable(enable, dst);
+}
+
+static int
+ble_hs_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) &&
+        (scan_type != BLE_HCI_SCAN_TYPE_ACTIVE)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check interval and window */
+    if ((scan_itvl < BLE_HCI_SCAN_ITVL_MIN) ||
+        (scan_itvl > BLE_HCI_SCAN_ITVL_MAX) ||
+        (scan_window < BLE_HCI_SCAN_WINDOW_MIN) ||
+        (scan_window > BLE_HCI_SCAN_WINDOW_MAX) ||
+        (scan_itvl < scan_window)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check own addr type */
+    if (own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check scanner filter policy */
+    if (filter_policy > BLE_HCI_SCAN_FILT_MAX) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    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
+ble_hs_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 *dst, int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_SCAN_PARAM_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_PARAMS,
+                       BLE_HCI_SET_SCAN_PARAM_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    rc = ble_hs_hci_cmd_body_le_set_scan_params(scan_type, scan_itvl,
+                                              scan_window, own_addr_type,
+                                              filter_policy, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static void
+ble_hs_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
+ble_hs_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);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_SCAN_ENABLE,
+                       BLE_HCI_SET_SCAN_ENABLE_LEN, dst);
+
+    ble_hs_hci_cmd_body_le_set_scan_enable(enable, filter_dups,
+                                         dst + BLE_HCI_CMD_HDR_LEN);
+}
+
+static int
+ble_hs_hci_cmd_body_le_create_connection(const struct hci_create_conn *hcc,
+                                         uint8_t *cmd)
+{
+    /* Check scan interval and scan window */
+    if ((hcc->scan_itvl < BLE_HCI_SCAN_ITVL_MIN) ||
+        (hcc->scan_itvl > BLE_HCI_SCAN_ITVL_MAX) ||
+        (hcc->scan_window < BLE_HCI_SCAN_WINDOW_MIN) ||
+        (hcc->scan_window > BLE_HCI_SCAN_WINDOW_MAX) ||
+        (hcc->scan_itvl < hcc->scan_window)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check initiator filter policy */
+    if (hcc->filter_policy > BLE_HCI_CONN_FILT_MAX) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check peer addr type */
+    if (hcc->peer_addr_type > BLE_HCI_CONN_PEER_ADDR_MAX) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check own addr type */
+    if (hcc->own_addr_type > BLE_HCI_ADV_OWN_ADDR_MAX) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check connection interval min */
+    if ((hcc->conn_itvl_min < BLE_HCI_CONN_ITVL_MIN) ||
+        (hcc->conn_itvl_min > BLE_HCI_CONN_ITVL_MAX)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check connection interval max */
+    if ((hcc->conn_itvl_max < BLE_HCI_CONN_ITVL_MIN) ||
+        (hcc->conn_itvl_max > BLE_HCI_CONN_ITVL_MAX) ||
+        (hcc->conn_itvl_max < hcc->conn_itvl_min)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check connection latency */
+    if ((hcc->conn_latency < BLE_HCI_CONN_LATENCY_MIN) ||
+        (hcc->conn_latency > BLE_HCI_CONN_LATENCY_MAX)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check supervision timeout */
+    if ((hcc->supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN) ||
+        (hcc->supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX)) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    /* Check connection event length */
+    if (hcc->min_ce_len > hcc->max_ce_len) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    htole16(cmd + 0, hcc->scan_itvl);
+    htole16(cmd + 2, hcc->scan_window);
+    cmd[4] = hcc->filter_policy;
+    cmd[5] = hcc->peer_addr_type;
+    memcpy(cmd + 6, hcc->peer_addr, BLE_DEV_ADDR_LEN);
+    cmd[12] = hcc->own_addr_type;
+    htole16(cmd + 13, hcc->conn_itvl_min);
+    htole16(cmd + 15, hcc->conn_itvl_max);
+    htole16(cmd + 17, hcc->conn_latency);
+    htole16(cmd + 19, hcc->supervision_timeout);
+    htole16(cmd + 21, hcc->min_ce_len);
+    htole16(cmd + 23, hcc->max_ce_len);
+
+    return 0;
+}
+
+int
+ble_hs_hci_cmd_build_le_create_connection(const 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);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN,
+                       BLE_HCI_CREATE_CONN_LEN, cmd);
+
+    rc = ble_hs_hci_cmd_body_le_create_connection(hcc,
+                                                cmd + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+void
+ble_hs_hci_cmd_build_le_clear_whitelist(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLEAR_WHITE_LIST,
+                       0, dst);
+}
+
+int
+ble_hs_hci_cmd_build_le_add_to_whitelist(const 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);
+
+    ble_hs_hci_cmd_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 = ble_hs_hci_cmd_body_le_whitelist_chg(addr, addr_type, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+void
+ble_hs_hci_cmd_build_reset(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET,
+                       0, dst);
+}
+
+/**
+ * Reset the controller and link manager.
+ *
+ * @return int
+ */
+int
+ble_hs_hci_cmd_reset(void)
+{
+    int rc;
+
+    rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET,
+                             0, NULL);
+    return rc;
+}
+
+void
+ble_hs_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+    ble_hs_hci_cmd_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.
+ *
+ * @return int
+ */
+int
+ble_hs_hci_cmd_read_adv_pwr(void)
+{
+    int rc;
+
+    rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_ADV_CHAN_TXPWR,
+                             0, NULL);
+    return rc;
+}
+
+void
+ble_hs_hci_cmd_build_le_create_conn_cancel(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN_CANCEL,
+                       0, dst);
+}
+
+int
+ble_hs_hci_cmd_le_create_conn_cancel(void)
+{
+    int rc;
+
+    rc = ble_hs_hci_cmd_send(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CREATE_CONN_CANCEL,
+                           0, NULL);
+    return rc;
+}
+
+static int
+ble_hs_hci_cmd_body_le_conn_update(const 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
+ble_hs_hci_cmd_build_le_conn_update(const 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);
+
+    ble_hs_hci_cmd_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 = ble_hs_hci_cmd_body_le_conn_update(hcu, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+int
+ble_hs_hci_cmd_le_conn_update(const struct hci_conn_update *hcu)
+{
+    uint8_t cmd[BLE_HCI_CONN_UPDATE_LEN];
+    int rc;
+
+    rc = ble_hs_hci_cmd_body_le_conn_update(hcu, cmd);
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_CONN_UPDATE,
+                              BLE_HCI_CONN_UPDATE_LEN, cmd);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static void
+ble_hs_hci_cmd_body_le_lt_key_req_reply(const 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
+ble_hs_hci_cmd_build_le_lt_key_req_reply(
+    const 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);
+
+    ble_hs_hci_cmd_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;
+
+    ble_hs_hci_cmd_body_le_lt_key_req_reply(hkr, dst);
+}
+
+void
+ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle,
+                                             uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE,
+                             BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY,
+                             BLE_HCI_LT_KEY_REQ_NEG_REPLY_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    htole16(dst + 0, conn_handle);
+}
+
+static void
+ble_hs_hci_cmd_body_le_conn_param_reply(const 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
+ble_hs_hci_cmd_build_le_conn_param_reply(
+    const 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);
+
+    ble_hs_hci_cmd_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;
+
+    ble_hs_hci_cmd_body_le_conn_param_reply(hcr, dst);
+}
+
+int
+ble_hs_hci_cmd_le_conn_param_reply(const struct hci_conn_param_reply *hcr)
+{
+    uint8_t cmd[BLE_HCI_CONN_PARAM_REPLY_LEN];
+    int rc;
+
+    htole16(cmd + 0, hcr->handle);
+    htole16(cmd + 2, hcr->conn_itvl_min);
+    htole16(cmd + 4, hcr->conn_itvl_max);
+    htole16(cmd + 6, hcr->conn_latency);
+    htole16(cmd + 8, hcr->supervision_timeout);
+    htole16(cmd + 10, hcr->min_ce_len);
+    htole16(cmd + 12, hcr->max_ce_len);
+
+    rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_RR,
+                              BLE_HCI_CONN_PARAM_REPLY_LEN, cmd);
+    return rc;
+}
+
+static void
+ble_hs_hci_cmd_body_le_conn_param_neg_reply(
+    const struct hci_conn_param_neg_reply *hcn, uint8_t *dst)
+{
+    htole16(dst + 0, hcn->handle);
+    dst[2] = hcn->reason;
+}
+
+
+void
+ble_hs_hci_cmd_build_le_conn_param_neg_reply(
+    const 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);
+
+    ble_hs_hci_cmd_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;
+
+    ble_hs_hci_cmd_body_le_conn_param_neg_reply(hcn, dst);
+}
+
+int
+ble_hs_hci_cmd_le_conn_param_neg_reply(
+    const struct hci_conn_param_neg_reply *hcn)
+{
+    uint8_t cmd[BLE_HCI_CONN_PARAM_NEG_REPLY_LEN];
+    int rc;
+
+    ble_hs_hci_cmd_body_le_conn_param_neg_reply(hcn, cmd);
+
+    rc = ble_hs_hci_cmd_le_send(BLE_HCI_OCF_LE_REM_CONN_PARAM_NRR,
+                              BLE_HCI_CONN_PARAM_NEG_REPLY_LEN, cmd);
+    return rc;
+}
+
+/**
+ * Get random data
+ *
+ * OGF = 0x08 (LE)
+ * OCF = 0x0018
+ *
+ * @return int
+ */
+void
+ble_hs_hci_cmd_build_le_rand(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RAND, 0, dst);
+}
+
+static void
+ble_hs_hci_cmd_body_le_start_encrypt(const 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);
+}
+
+/*
+ * OGF=0x08 OCF=0x0019
+ */
+void
+ble_hs_hci_cmd_build_le_start_encrypt(const 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);
+
+    ble_hs_hci_cmd_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;
+
+    ble_hs_hci_cmd_body_le_start_encrypt(cmd, dst);
+}
+
+/**
+ * Read the RSSI for a given connection handle
+ *
+ * NOTE: OGF=0x05 OCF=0x0005
+ *
+ * @param handle
+ *
+ * @return int
+ */
+static void
+ble_hs_hci_cmd_body_read_rssi(uint16_t handle, uint8_t *dst)
+{
+    htole16(dst, handle);
+}
+
+void
+ble_hs_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_READ_RSSI_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_STATUS_PARAMS, BLE_HCI_OCF_RD_RSSI,
+                       BLE_HCI_READ_RSSI_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    ble_hs_hci_cmd_body_read_rssi(handle, dst);
+}
+
+static int
+ble_hs_hci_cmd_body_set_data_len(uint16_t connection_handle,
+                                 uint16_t tx_octets,
+                                 uint16_t tx_time, uint8_t *dst)
+{
+
+    if (tx_octets < BLE_HCI_SET_DATALEN_TX_OCTETS_MIN ||
+        tx_octets > BLE_HCI_SET_DATALEN_TX_OCTETS_MAX) {
+
+        return BLE_HS_EINVAL;
+    }
+
+    if (tx_time < BLE_HCI_SET_DATALEN_TX_TIME_MIN ||
+        tx_time > BLE_HCI_SET_DATALEN_TX_TIME_MAX) {
+
+        return BLE_HS_EINVAL;
+    }
+
+    htole16(dst + 0, connection_handle);
+    htole16(dst + 2, tx_octets);
+    htole16(dst + 4, tx_time);
+
+    return 0;
+}
+
+/*
+ * OGF=0x08 OCF=0x0022
+ */
+int
+ble_hs_hci_cmd_build_set_data_len(uint16_t connection_handle,
+                                  uint16_t tx_octets, uint16_t tx_time,
+                                  uint8_t *dst, int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_DATALEN_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_DATA_LEN,
+                       BLE_HCI_SET_DATALEN_LEN, dst);
+    dst += BLE_HCI_CMD_HDR_LEN;
+
+    rc = ble_hs_hci_cmd_body_set_data_len(connection_handle, tx_octets,
+                                          tx_time, dst);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+/**
+ * IRKs are in little endian.
+ */
+static int
+ble_hs_hci_cmd_body_add_to_resolv_list(uint8_t addr_type, const uint8_t *addr,
+                                       const uint8_t *peer_irk,
+                                       const uint8_t *local_irk,
+                                       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);
+    memcpy(dst + 1 + 6, peer_irk , 16);
+    memcpy(dst + 1 + 6 + 16, local_irk , 16);
+    /* 16 + 16 + 6 + 1 == 39 */
+    return 0;
+}
+
+/**
+ * OGF=0x08 OCF=0x0027
+ *
+ * IRKs are in little endian.
+ */
+int
+ble_hs_hci_cmd_build_add_to_resolv_list(
+    const struct hci_add_dev_to_resolving_list *padd,
+    uint8_t *dst,
+    int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_ADD_TO_RESOLV_LIST_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ADD_RESOLV_LIST,
+                       BLE_HCI_ADD_TO_RESOLV_LIST_LEN, dst);
+
+    rc = ble_hs_hci_cmd_body_add_to_resolv_list(
+        padd->addr_type, padd->addr, padd->peer_irk, padd->local_irk,
+        dst + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_cmd_body_remove_from_resolv_list(uint8_t addr_type,
+                                            const uint8_t *addr,
+                                            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;
+}
+
+
+int
+ble_hs_hci_cmd_build_remove_from_resolv_list(uint8_t addr_type,
+                                             const uint8_t *addr,
+                                             uint8_t *dst, int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_RMV_FROM_RESOLV_LIST_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RMV_RESOLV_LIST,
+                       BLE_HCI_RMV_FROM_RESOLV_LIST_LEN, dst);
+
+    rc = ble_hs_hci_cmd_body_remove_from_resolv_list(addr_type, addr,
+                                                dst + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+    return 0;
+}
+
+int
+ble_hs_hci_cmd_build_clear_resolv_list(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_CLR_RESOLV_LIST,
+                       0, dst);
+
+    return 0;
+}
+
+int
+ble_hs_hci_cmd_build_read_resolv_list_size(uint8_t *dst, int dst_len)
+{
+    BLE_HS_DBG_ASSERT(dst_len >= BLE_HCI_CMD_HDR_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE,
+                             BLE_HCI_OCF_LE_RD_RESOLV_LIST_SIZE,
+                             0, dst);
+
+    return 0;
+}
+
+static int
+ble_hs_hci_cmd_body_read_peer_resolv_addr(uint8_t peer_identity_addr_type,
+                                          const uint8_t *peer_identity_addr,
+                                          uint8_t *dst)
+{
+    if (peer_identity_addr_type > BLE_ADDR_TYPE_RANDOM) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    dst[0] = peer_identity_addr_type;
+    memcpy(dst + 1, peer_identity_addr, BLE_DEV_ADDR_LEN);
+    return 0;
+}
+
+int
+ble_hs_hci_cmd_build_read_peer_resolv_addr(uint8_t peer_identity_addr_type,
+                                           const uint8_t *peer_identity_addr,
+                                           uint8_t *dst,
+                                           int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_RD_PEER_RESOLV_ADDR_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE,
+                             BLE_HCI_OCF_LE_RD_PEER_RESOLV_ADDR,
+                             BLE_HCI_RD_PEER_RESOLV_ADDR_LEN, dst);
+
+    rc = ble_hs_hci_cmd_body_read_peer_resolv_addr(peer_identity_addr_type,
+                                                   peer_identity_addr,
+                                                   dst + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+    return 0;
+}
+
+static int
+ble_hs_hci_cmd_body_read_lcl_resolv_addr(
+    uint8_t local_identity_addr_type,
+    const uint8_t *local_identity_addr,
+    uint8_t *dst)
+{
+    if (local_identity_addr_type > BLE_ADDR_TYPE_RANDOM) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    dst[0] = local_identity_addr_type;
+    memcpy(dst + 1, local_identity_addr, BLE_DEV_ADDR_LEN);
+    return 0;
+}
+
+/*
+ * OGF=0x08 OCF=0x002c
+ */
+int
+ble_hs_hci_cmd_build_read_lcl_resolv_addr(uint8_t local_identity_addr_type,
+                                          const uint8_t *local_identity_addr,
+                                          uint8_t *dst,
+                                          int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_RD_LOC_RESOLV_ADDR_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE,
+                             BLE_HCI_OCF_LE_RD_LOCAL_RESOLV_ADDR,
+                             BLE_HCI_RD_LOC_RESOLV_ADDR_LEN, dst);
+
+    rc = ble_hs_hci_cmd_body_read_lcl_resolv_addr(local_identity_addr_type,
+                                                  local_identity_addr,
+                                                  dst + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+    return 0;
+}
+
+static int
+ble_hs_hci_cmd_body_set_addr_res_en(uint8_t enable, uint8_t *dst)
+{
+    if (enable > 1) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    dst[0] = enable;
+    return 0;
+}
+
+/*
+ * OGF=0x08 OCF=0x002d
+ */
+int
+ble_hs_hci_cmd_build_set_addr_res_en(uint8_t enable, uint8_t *dst, int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADDR_RESOL_ENA_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_ADDR_RES_EN,
+                       BLE_HCI_SET_ADDR_RESOL_ENA_LEN, dst);
+
+    rc = ble_hs_hci_cmd_body_set_addr_res_en(enable,
+                                             dst + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+    return 0;
+}
+
+static int
+ble_hs_hci_cmd_body_set_resolv_priv_addr_timeout(uint16_t timeout,
+                                                 uint8_t *dst)
+{
+    if (timeout == 0 || timeout > 0xA1B8) {
+        return BLE_ERR_INV_HCI_CMD_PARMS;
+    }
+
+    htole16(dst, timeout);
+    return 0;
+}
+
+/*
+ * OGF=0x08 OCF=0x002e
+ */
+int
+ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout(
+    uint16_t timeout, uint8_t *dst, int dst_len)
+{
+    int rc;
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RPA_TMO,
+                       BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN, dst);
+
+    rc = ble_hs_hci_cmd_body_set_resolv_priv_addr_timeout(
+        timeout, dst + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+    return 0;
+}
+
+static int
+ble_hs_hci_cmd_body_set_random_addr(const struct hci_rand_addr *paddr,
+                                    uint8_t *dst)
+{
+    memcpy(dst, paddr->addr, BLE_DEV_ADDR_LEN);
+    return 0;
+}
+
+int
+ble_hs_hci_cmd_build_set_random_addr(const uint8_t *addr,
+                                     uint8_t *dst, int dst_len)
+{
+    struct hci_rand_addr r_addr;
+    int rc;
+
+    memcpy(r_addr.addr, addr, sizeof(r_addr.addr));
+
+    BLE_HS_DBG_ASSERT(
+        dst_len >= BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RAND_ADDR_LEN);
+
+    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RAND_ADDR,
+                       BLE_HCI_SET_RAND_ADDR_LEN, dst);
+
+    rc = ble_hs_hci_cmd_body_set_random_addr(&r_addr,
+                                             dst + BLE_HCI_CMD_HDR_LEN);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d842a43c/net/nimble/host/src/ble_hs_hci_evt.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_hci_evt.c b/net/nimble/host/src/ble_hs_hci_evt.c
new file mode 100644
index 0000000..3d382dc
--- /dev/null
+++ b/net/nimble/host/src/ble_hs_hci_evt.c
@@ -0,0 +1,677 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ * 
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+#include "os/os.h"
+#include "console/console.h"
+#include "nimble/hci_common.h"
+#include "nimble/ble_hci_trans.h"
+#include "host/ble_gap.h"
+#include "ble_hs_priv.h"
+#include "ble_hs_dbg_priv.h"
+
+_Static_assert(sizeof (struct hci_data_hdr) == BLE_HCI_DATA_HDR_SZ,
+               "struct hci_data_hdr must be 4 bytes");
+
+typedef int ble_hs_hci_evt_fn(uint8_t event_code, uint8_t *data, int len);
+static ble_hs_hci_evt_fn ble_hs_hci_evt_disconn_complete;
+static ble_hs_hci_evt_fn ble_hs_hci_evt_encrypt_change;
+static ble_hs_hci_evt_fn ble_hs_hci_evt_hw_error;
+static ble_hs_hci_evt_fn ble_hs_hci_evt_num_completed_pkts;
+static ble_hs_hci_evt_fn ble_hs_hci_evt_enc_key_refresh;
+static ble_hs_hci_evt_fn ble_hs_hci_evt_le_meta;
+
+typedef int ble_hs_hci_evt_le_fn(uint8_t subevent, uint8_t *data, int len);
+static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_complete;
+static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_adv_rpt;
+static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_upd_complete;
+static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_lt_key_req;
+static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_conn_parm_req;
+static ble_hs_hci_evt_le_fn ble_hs_hci_evt_le_dir_adv_rpt;
+
+/* Statistics */
+struct host_hci_stats
+{
+    uint32_t events_rxd;
+    uint32_t good_acks_rxd;
+    uint32_t bad_acks_rxd;
+    uint32_t unknown_events_rxd;
+};
+
+#define BLE_HS_HCI_EVT_TIMEOUT        50      /* Milliseconds. */
+
+/** Dispatch table for incoming HCI events.  Sorted by event code field. */
+struct ble_hs_hci_evt_dispatch_entry {
+    uint8_t event_code;
+    ble_hs_hci_evt_fn *cb;
+};
+
+static const struct ble_hs_hci_evt_dispatch_entry ble_hs_hci_evt_dispatch[] = {
+    { BLE_HCI_EVCODE_DISCONN_CMP, ble_hs_hci_evt_disconn_complete },
+    { BLE_HCI_EVCODE_ENCRYPT_CHG, ble_hs_hci_evt_encrypt_change },
+    { BLE_HCI_EVCODE_HW_ERROR, ble_hs_hci_evt_hw_error },
+    { BLE_HCI_EVCODE_NUM_COMP_PKTS, ble_hs_hci_evt_num_completed_pkts },
+    { BLE_HCI_EVCODE_ENC_KEY_REFRESH, ble_hs_hci_evt_enc_key_refresh },
+    { BLE_HCI_EVCODE_LE_META, ble_hs_hci_evt_le_meta },
+};
+
+#define BLE_HS_HCI_EVT_DISPATCH_SZ \
+    (sizeof ble_hs_hci_evt_dispatch / sizeof ble_hs_hci_evt_dispatch[0])
+
+/** Dispatch table for incoming LE meta events.  Sorted by subevent field. */
+struct ble_hs_hci_evt_le_dispatch_entry {
+    uint8_t subevent;
+    ble_hs_hci_evt_le_fn *cb;
+};
+
+static const struct ble_hs_hci_evt_le_dispatch_entry
+        ble_hs_hci_evt_le_dispatch[] = {
+    { BLE_HCI_LE_SUBEV_CONN_COMPLETE, ble_hs_hci_evt_le_conn_complete },
+    { BLE_HCI_LE_SUBEV_ADV_RPT, ble_hs_hci_evt_le_adv_rpt },
+    { BLE_HCI_LE_SUBEV_CONN_UPD_COMPLETE,
+          ble_hs_hci_evt_le_conn_upd_complete },
+    { BLE_HCI_LE_SUBEV_LT_KEY_REQ, ble_hs_hci_evt_le_lt_key_req },
+    { BLE_HCI_LE_SUBEV_REM_CONN_PARM_REQ, ble_hs_hci_evt_le_conn_parm_req },
+    { BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE, ble_hs_hci_evt_le_conn_complete },
+    { BLE_HCI_LE_SUBEV_DIRECT_ADV_RPT, ble_hs_hci_evt_le_dir_adv_rpt },
+};
+
+#define BLE_HS_HCI_EVT_LE_DISPATCH_SZ \
+    (sizeof ble_hs_hci_evt_le_dispatch / sizeof ble_hs_hci_evt_le_dispatch[0])
+
+static const struct ble_hs_hci_evt_dispatch_entry *
+ble_hs_hci_evt_dispatch_find(uint8_t event_code)
+{
+    const struct ble_hs_hci_evt_dispatch_entry *entry;
+    int i;
+
+    for (i = 0; i < BLE_HS_HCI_EVT_DISPATCH_SZ; i++) {
+        entry = ble_hs_hci_evt_dispatch + i;
+        if (entry->event_code == event_code) {
+            return entry;
+        }
+    }
+
+    return NULL;
+}
+
+static const struct ble_hs_hci_evt_le_dispatch_entry *
+ble_hs_hci_evt_le_dispatch_find(uint8_t event_code)
+{
+    const struct ble_hs_hci_evt_le_dispatch_entry *entry;
+    int i;
+
+    for (i = 0; i < BLE_HS_HCI_EVT_LE_DISPATCH_SZ; i++) {
+        entry = ble_hs_hci_evt_le_dispatch + i;
+        if (entry->subevent == event_code) {
+            return entry;
+        }
+    }
+
+    return NULL;
+}
+
+static int
+ble_hs_hci_evt_disconn_complete(uint8_t event_code, uint8_t *data, int len)
+{
+    struct hci_disconn_complete evt;
+
+    if (len < BLE_HCI_EVENT_DISCONN_COMPLETE_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    evt.status = data[2];
+    evt.connection_handle = le16toh(data + 3);
+    evt.reason = data[5];
+
+    ble_gap_rx_disconn_complete(&evt);
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_encrypt_change(uint8_t event_code, uint8_t *data, int len)
+{
+    struct hci_encrypt_change evt;
+
+    if (len < BLE_HCI_EVENT_ENCRYPT_CHG_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    evt.status = data[2];
+    evt.connection_handle = le16toh(data + 3);
+    evt.encryption_enabled = data[5];
+
+    ble_sm_enc_change_rx(&evt);
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_hw_error(uint8_t event_code, uint8_t *data, int len)
+{
+    uint8_t hw_code;
+
+    if (len < BLE_HCI_EVENT_HW_ERROR_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    hw_code = data[0];
+    ble_hs_hw_error(hw_code);
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_enc_key_refresh(uint8_t event_code, uint8_t *data, int len)
+{
+    struct hci_encrypt_key_refresh evt;
+
+    if (len < BLE_HCI_EVENT_ENC_KEY_REFRESH_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    evt.status = data[2];
+    evt.connection_handle = le16toh(data + 3);
+
+    ble_sm_enc_key_refresh_rx(&evt);
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_num_completed_pkts(uint8_t event_code, uint8_t *data, int len)
+{
+    uint16_t num_pkts;
+    uint16_t handle;
+    uint8_t num_handles;
+    int off;
+    int i;
+
+    if (len < BLE_HCI_EVENT_HDR_LEN + BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    off = BLE_HCI_EVENT_HDR_LEN;
+    num_handles = data[off];
+    if (len < BLE_HCI_EVENT_NUM_COMP_PKTS_HDR_LEN +
+              num_handles * BLE_HCI_EVENT_NUM_COMP_PKTS_ENT_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+    off++;
+
+    for (i = 0; i < num_handles; i++) {
+        handle = le16toh(data + off + 2 * i);
+        num_pkts = le16toh(data + off + 2 * num_handles + 2 * i);
+
+        /* XXX: Do something with these values. */
+        (void)handle;
+        (void)num_pkts;
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_meta(uint8_t event_code, uint8_t *data, int len)
+{
+    const struct ble_hs_hci_evt_le_dispatch_entry *entry;
+    uint8_t subevent;
+    int rc;
+
+    if (len < BLE_HCI_EVENT_HDR_LEN + BLE_HCI_LE_MIN_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    subevent = data[2];
+    entry = ble_hs_hci_evt_le_dispatch_find(subevent);
+    if (entry != NULL) {
+        rc = entry->cb(subevent, data + BLE_HCI_EVENT_HDR_LEN,
+                           len - BLE_HCI_EVENT_HDR_LEN);
+        if (rc != 0) {
+            return rc;
+        }
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_conn_complete(uint8_t subevent, uint8_t *data, int len)
+{
+    struct hci_le_conn_complete evt;
+    int extended_offset = 0;
+    int rc;
+
+    if (len < BLE_HCI_LE_CONN_COMPLETE_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    /* this code processes two different events that are really similar */
+    if ((subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE) &&
+        ( len < BLE_HCI_LE_ENH_CONN_COMPLETE_LEN)) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    evt.subevent_code = data[0];
+    evt.status = data[1];
+    evt.connection_handle = le16toh(data + 2);
+    evt.role = data[4];
+    evt.peer_addr_type = data[5];
+    memcpy(evt.peer_addr, data + 6, BLE_DEV_ADDR_LEN);
+
+    /* enhanced connection event has the same information with these
+     * extra fields stuffed into the middle */
+    if (subevent == BLE_HCI_LE_SUBEV_ENH_CONN_COMPLETE) {
+        memcpy(evt.local_rpa, data + 12, BLE_DEV_ADDR_LEN);
+        memcpy(evt.peer_rpa, data + 18, BLE_DEV_ADDR_LEN);
+        extended_offset = 12;
+    } else {
+        memset(evt.local_rpa, 0, BLE_DEV_ADDR_LEN);
+        memset(evt.peer_rpa, 0, BLE_DEV_ADDR_LEN);
+    }
+
+    evt.conn_itvl = le16toh(data + 12 + extended_offset);
+    evt.conn_latency = le16toh(data + 14 + extended_offset);
+    evt.supervision_timeout = le16toh(data + 16 + extended_offset);
+    evt.master_clk_acc = data[18 + extended_offset];
+
+    if (evt.status == 0) {
+        if (evt.role != BLE_HCI_LE_CONN_COMPLETE_ROLE_MASTER &&
+            evt.role != BLE_HCI_LE_CONN_COMPLETE_ROLE_SLAVE) {
+
+            return BLE_HS_EBADDATA;
+        }
+    }
+
+    rc = ble_gap_rx_conn_complete(&evt);
+    if (rc != 0) {
+        return rc;
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_adv_rpt_first_pass(uint8_t *data, int len,
+                                     uint8_t *out_num_reports,
+                                     int *out_rssi_off)
+{
+    uint8_t num_reports;
+    int data_len;
+    int off;
+    int i;
+
+    if (len < BLE_HCI_LE_ADV_RPT_MIN_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    num_reports = data[1];
+    if (num_reports < BLE_HCI_LE_ADV_RPT_NUM_RPTS_MIN ||
+        num_reports > BLE_HCI_LE_ADV_RPT_NUM_RPTS_MAX) {
+
+        return BLE_HS_EBADDATA;
+    }
+
+    off = 2 +       /* Subevent code and num reports. */
+          (1 +      /* Event type. */
+           1 +      /* Address type. */
+           6        /* Address. */
+          ) * num_reports;
+    if (off + num_reports >= len) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    data_len = 0;
+    for (i = 0; i < num_reports; i++) {
+        data_len += data[off];
+        off++;
+    }
+
+    off += data_len;
+
+    /* Check if RSSI fields fit in the packet. */
+    if (off + num_reports > len) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    *out_num_reports = num_reports;
+    *out_rssi_off = off;
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_adv_rpt(uint8_t subevent, uint8_t *data, int len)
+{
+    struct ble_gap_disc_desc desc;
+    uint8_t num_reports;
+    int rssi_off;
+    int data_off;
+    int suboff;
+    int off;
+    int rc;
+    int i;
+
+    rc = ble_hs_hci_evt_le_adv_rpt_first_pass(data, len, &num_reports,
+                                             &rssi_off);
+    if (rc != 0) {
+        return rc;
+    }
+
+    /* Direct address fields not present in a standard advertising report. */
+    desc.direct_addr_type = BLE_GAP_ADDR_TYPE_NONE;
+    memset(desc.direct_addr, 0, sizeof desc.direct_addr);
+
+    data_off = 0;
+    for (i = 0; i < num_reports; i++) {
+        suboff = 0;
+
+        off = 2 + suboff * num_reports + i;
+        desc.event_type = data[off];
+        suboff++;
+
+        off = 2 + suboff * num_reports + i;
+        desc.addr_type = data[off];
+        suboff++;
+
+        off = 2 + suboff * num_reports + i * 6;
+        memcpy(desc.addr, data + off, 6);
+        suboff += 6;
+
+        off = 2 + suboff * num_reports + i;
+        desc.length_data = data[off];
+        suboff++;
+
+        off = 2 + suboff * num_reports + data_off;
+        desc.data = data + off;
+        data_off += desc.length_data;
+
+        off = rssi_off + 1 * i;
+        desc.rssi = data[off];
+
+        ble_gap_rx_adv_report(&desc);
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_dir_adv_rpt(uint8_t subevent, uint8_t *data, int len)
+{
+    struct ble_gap_disc_desc desc;
+    uint8_t num_reports;
+    int suboff;
+    int off;
+    int i;
+
+    if (len < BLE_HCI_LE_ADV_DIRECT_RPT_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    num_reports = data[1];
+    if (len != 2 + num_reports * BLE_HCI_LE_ADV_DIRECT_RPT_SUB_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    /* Data fields not present in a direct advertising report. */
+    desc.data = NULL;
+    desc.fields = NULL;
+
+    for (i = 0; i < num_reports; i++) {
+        suboff = 0;
+
+        off = 2 + suboff * num_reports + i;
+        desc.event_type = data[off];
+        suboff++;
+
+        off = 2 + suboff * num_reports + i;
+        desc.addr_type = data[off];
+        suboff++;
+
+        off = 2 + suboff * num_reports + i * 6;
+        memcpy(desc.addr, data + off, 6);
+        suboff += 6;
+
+        off = 2 + suboff * num_reports + i;
+        desc.direct_addr_type = data[off];
+        suboff++;
+
+        off = 2 + suboff * num_reports + i * 6;
+        memcpy(desc.direct_addr, data + off, 6);
+        suboff += 6;
+
+        off = 2 + suboff * num_reports + i;
+        desc.rssi = data[off];
+        suboff++;
+
+        ble_gap_rx_adv_report(&desc);
+    }
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_conn_upd_complete(uint8_t subevent, uint8_t *data, int len)
+{
+    struct hci_le_conn_upd_complete evt;
+
+    if (len < BLE_HCI_LE_CONN_UPD_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    evt.subevent_code = data[0];
+    evt.status = data[1];
+    evt.connection_handle = le16toh(data + 2);
+    evt.conn_itvl = le16toh(data + 4);
+    evt.conn_latency = le16toh(data + 6);
+    evt.supervision_timeout = le16toh(data + 8);
+
+    if (evt.status == 0) {
+        if (evt.conn_itvl < BLE_HCI_CONN_ITVL_MIN ||
+            evt.conn_itvl > BLE_HCI_CONN_ITVL_MAX) {
+
+            return BLE_HS_EBADDATA;
+        }
+        if (evt.conn_latency < BLE_HCI_CONN_LATENCY_MIN ||
+            evt.conn_latency > BLE_HCI_CONN_LATENCY_MAX) {
+
+            return BLE_HS_EBADDATA;
+        }
+        if (evt.supervision_timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN ||
+            evt.supervision_timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX) {
+
+            return BLE_HS_EBADDATA;
+        }
+    }
+
+    ble_gap_rx_update_complete(&evt);
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_lt_key_req(uint8_t subevent, uint8_t *data, int len)
+{
+    struct hci_le_lt_key_req evt;
+
+    if (len < BLE_HCI_LE_LT_KEY_REQ_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    evt.subevent_code = data[0];
+    evt.connection_handle = le16toh(data + 1);
+    evt.random_number = le64toh(data + 3);
+    evt.encrypted_diversifier = le16toh(data + 11);
+
+    ble_sm_ltk_req_rx(&evt);
+
+    return 0;
+}
+
+static int
+ble_hs_hci_evt_le_conn_parm_req(uint8_t subevent, uint8_t *data, int len)
+{
+    struct hci_le_conn_param_req evt;
+
+    if (len < BLE_HCI_LE_REM_CONN_PARM_REQ_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    evt.subevent_code = data[0];
+    evt.connection_handle = le16toh(data + 1);
+    evt.itvl_min = le16toh(data + 3);
+    evt.itvl_max = le16toh(data + 5);
+    evt.latency = le16toh(data + 7);
+    evt.timeout = le16toh(data + 9);
+
+    if (evt.itvl_min < BLE_HCI_CONN_ITVL_MIN ||
+        evt.itvl_max > BLE_HCI_CONN_ITVL_MAX ||
+        evt.itvl_min > evt.itvl_max) {
+
+        return BLE_HS_EBADDATA;
+    }
+    if (evt.latency < BLE_HCI_CONN_LATENCY_MIN ||
+        evt.latency > BLE_HCI_CONN_LATENCY_MAX) {
+
+        return BLE_HS_EBADDATA;
+    }
+    if (evt.timeout < BLE_HCI_CONN_SPVN_TIMEOUT_MIN ||
+        evt.timeout > BLE_HCI_CONN_SPVN_TIMEOUT_MAX) {
+
+        return BLE_HS_EBADDATA;
+    }
+
+    ble_gap_rx_param_req(&evt);
+
+    return 0;
+}
+
+int
+ble_hs_hci_evt_process(uint8_t *data)
+{
+    const struct ble_hs_hci_evt_dispatch_entry *entry;
+    uint8_t event_code;
+    uint8_t param_len;
+    int event_len;
+    int rc;
+
+    /* Count events received */
+    STATS_INC(ble_hs_stats, hci_event);
+
+    /* Display to console */
+    ble_hs_dbg_event_disp(data);
+
+    /* Process the event */
+    event_code = data[0];
+    param_len = data[1];
+
+    event_len = param_len + 2;
+
+    entry = ble_hs_hci_evt_dispatch_find(event_code);
+    if (entry == NULL) {
+        STATS_INC(ble_hs_stats, hci_unknown_event);
+        rc = BLE_HS_ENOTSUP;
+    } else {
+        rc = entry->cb(event_code, data, event_len);
+    }
+
+    ble_hci_trans_buf_free(data);
+
+    return rc;
+}
+
+/**
+ * Called when a data packet is received from the controller.  This function
+ * consumes the supplied mbuf, regardless of the outcome.
+ *
+ * @param om                    The incoming data packet, beginning with the
+ *                                  HCI ACL data header.
+ *
+ * @return                      0 on success; nonzero on failure.
+ */
+int
+ble_hs_hci_evt_acl_process(struct os_mbuf *om)
+{
+    struct hci_data_hdr hci_hdr;
+    struct ble_hs_conn *conn;
+    ble_l2cap_rx_fn *rx_cb;
+    struct os_mbuf *rx_buf;
+    uint16_t handle;
+    int rc;
+
+    rc = ble_hs_hci_util_data_hdr_strip(om, &hci_hdr);
+    if (rc != 0) {
+        goto err;
+    }
+
+#if (BLETEST_THROUGHPUT_TEST == 0)
+    BLE_HS_LOG(DEBUG, "ble_hs_hci_evt_acl_process(): handle=%u pb=%x len=%u "
+                      "data=",
+               BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc), 
+               BLE_HCI_DATA_PB(hci_hdr.hdh_handle_pb_bc), 
+               hci_hdr.hdh_len);
+    ble_hs_log_mbuf(om);
+    BLE_HS_LOG(DEBUG, "\n");
+#endif
+
+    if (hci_hdr.hdh_len != OS_MBUF_PKTHDR(om)->omp_len) {
+        rc = BLE_HS_EBADDATA;
+        goto err;
+    }
+
+    handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc);
+
+    ble_hs_lock();
+
+    conn = ble_hs_conn_find(handle);
+    if (conn == NULL) {
+        rc = BLE_HS_ENOTCONN;
+    } else {
+        rc = ble_l2cap_rx(conn, &hci_hdr, om, &rx_cb, &rx_buf);
+        om = NULL;
+    }
+
+    ble_hs_unlock();
+
+    switch (rc) {
+    case 0:
+        /* Final fragment received. */
+        BLE_HS_DBG_ASSERT(rx_cb != NULL);
+        BLE_HS_DBG_ASSERT(rx_buf != NULL);
+        rc = rx_cb(handle, &rx_buf);
+        os_mbuf_free_chain(rx_buf);
+        break;
+
+    case BLE_HS_EAGAIN:
+        /* More fragments on the way. */
+        break;
+
+    default:
+        goto err;
+    }
+
+    return 0;
+
+err:
+    os_mbuf_free_chain(om);
+    return rc;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d842a43c/net/nimble/host/src/ble_hs_hci_priv.h
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_hci_priv.h b/net/nimble/host/src/ble_hs_hci_priv.h
new file mode 100644
index 0000000..7d2fb12
--- /dev/null
+++ b/net/nimble/host/src/ble_hs_hci_priv.h
@@ -0,0 +1,158 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#ifndef H_BLE_HS_HCI_PRIV_
+#define H_BLE_HS_HCI_PRIV_
+
+#include "nimble/hci_common.h"
+struct ble_hs_conn;
+struct os_mbuf;
+
+struct ble_hs_hci_ack {
+    int bha_status;         /* A BLE_HS_E<...> error; NOT a naked HCI code. */
+    uint8_t *bha_params;
+    int bha_params_len;
+    uint16_t bha_opcode;
+    uint8_t bha_hci_handle;
+};
+
+int ble_hs_hci_cmd_tx(void *cmd, void *evt_buf, uint8_t evt_buf_len,
+                      uint8_t *out_evt_buf_len);
+int ble_hs_hci_cmd_tx_empty_ack(void *cmd);
+void ble_hs_hci_rx_ack(uint8_t *ack_ev);
+void ble_hs_hci_init(void);
+
+#if PHONY_HCI_ACKS
+typedef int ble_hs_hci_phony_ack_fn(uint8_t *ack, int ack_buf_len);
+void ble_hs_hci_set_phony_ack_cb(ble_hs_hci_phony_ack_fn *cb);
+#endif
+
+int ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_pwr);
+int ble_hs_hci_util_rand(void *dst, int len);
+int ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi);
+int ble_hs_hci_util_set_random_addr(const uint8_t *addr);
+int ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets,
+                                 uint16_t tx_time);
+int ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om,
+                                   struct hci_data_hdr *out_hdr);
+
+int ble_hs_hci_evt_process(uint8_t *data);
+uint16_t ble_hs_hci_util_opcode_join(uint8_t ogf, uint16_t ocf);
+void ble_hs_hci_cmd_write_hdr(uint8_t ogf, uint8_t ocf, uint8_t len,
+                              void *buf);
+int ble_hs_hci_cmd_send(uint8_t ogf, uint8_t ocf, uint8_t len,
+                        const void *cmddata);
+int ble_hs_hci_cmd_send_buf(void *cmddata);
+void ble_hs_hci_cmd_build_read_bd_addr(uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_set_event_mask(uint64_t event_mask,
+                                         uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_set_event_mask2(uint64_t event_mask, uint8_t *dst,
+                                          int dst_len);
+void ble_hs_hci_cmd_build_disconnect(uint16_t handle, uint8_t reason,
+                                     uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_disconnect(uint16_t handle, uint8_t reason);
+void ble_hs_hci_cmd_build_read_rssi(uint16_t handle, uint8_t *dst,
+                                    int dst_len);
+int ble_hs_hci_cmd_read_rssi(uint16_t handle);
+int ble_hs_hci_cmd_build_le_set_scan_rsp_data(const uint8_t *data, uint8_t len,
+                                              uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_le_set_adv_data(const uint8_t *data, uint8_t len,
+                                         uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_le_set_adv_params(const struct hci_adv_params *adv,
+                                           uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_le_set_event_mask(uint64_t event_mask,
+                                            uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_le_read_buffer_size(uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_le_read_buffer_size(void);
+void ble_hs_hci_cmd_build_le_read_loc_supp_feat(uint8_t *dst, uint8_t dst_len);
+void ble_hs_hci_cmd_build_le_set_adv_enable(uint8_t enable, uint8_t *dst,
+                                            int dst_len);
+int ble_hs_hci_cmd_le_set_adv_enable(uint8_t enable);
+int ble_hs_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 *dst, int dst_len);
+void ble_hs_hci_cmd_build_le_set_scan_enable(uint8_t enable,
+                                             uint8_t filter_dups,
+                                             uint8_t *dst, uint8_t dst_len);
+int ble_hs_hci_cmd_le_set_scan_enable(uint8_t enable, uint8_t filter_dups);
+int ble_hs_hci_cmd_build_le_create_connection(
+    const struct hci_create_conn *hcc, uint8_t *cmd, int cmd_len);
+int ble_hs_hci_cmd_le_create_connection(const struct hci_create_conn *hcc);
+void ble_hs_hci_cmd_build_le_clear_whitelist(uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_le_add_to_whitelist(const uint8_t *addr,
+                                             uint8_t addr_type,
+                                             uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_reset(uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_reset(void);
+void ble_hs_hci_cmd_build_read_adv_pwr(uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_read_adv_pwr(void);
+void ble_hs_hci_cmd_build_le_create_conn_cancel(uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_le_create_conn_cancel(void);
+int ble_hs_hci_cmd_build_le_conn_update(const struct hci_conn_update *hcu,
+                                        uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_le_conn_update(const struct hci_conn_update *hcu);
+void ble_hs_hci_cmd_build_le_lt_key_req_reply(
+    const struct hci_lt_key_req_reply *hkr, uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_le_lt_key_req_neg_reply(uint16_t conn_handle,
+                                                  uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_le_conn_param_reply(
+    const struct hci_conn_param_reply *hcr, uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_le_conn_param_reply(const struct hci_conn_param_reply *hcr);
+void ble_hs_hci_cmd_build_le_conn_param_neg_reply(
+    const struct hci_conn_param_neg_reply *hcn, uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_le_conn_param_neg_reply(
+    const struct hci_conn_param_neg_reply *hcn);
+void ble_hs_hci_cmd_build_le_rand(uint8_t *dst, int dst_len);
+void ble_hs_hci_cmd_build_le_start_encrypt(const struct hci_start_encrypt *cmd,
+                                           uint8_t *dst, int dst_len);
+int ble_hs_hci_set_buf_sz(uint16_t pktlen, uint8_t max_pkts);
+
+uint16_t ble_hs_hci_util_handle_pb_bc_join(uint16_t handle, uint8_t pb,
+                                           uint8_t bc);
+
+int ble_hs_hci_acl_tx(struct ble_hs_conn *connection, struct os_mbuf *txom);
+
+int ble_hs_hci_cmd_build_set_data_len(uint16_t connection_handle,
+                                      uint16_t tx_octets, uint16_t tx_time,
+                                      uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_add_to_resolv_list(
+    const struct hci_add_dev_to_resolving_list *padd,
+    uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_remove_from_resolv_list(
+    uint8_t addr_type, const uint8_t *addr, uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_read_resolv_list_size(uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_clear_resolv_list(uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_read_peer_resolv_addr(
+    uint8_t peer_identity_addr_type, const uint8_t *peer_identity_addr,
+    uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_read_lcl_resolv_addr(
+    uint8_t local_identity_addr_type, const uint8_t *local_identity_addr,
+    uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_set_addr_res_en(
+    uint8_t enable, uint8_t *dst, int dst_len);
+int ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout(
+    uint16_t timeout, uint8_t *dst, int dst_len);
+
+int ble_hs_hci_cmd_build_set_random_addr(const uint8_t *addr,
+                                         uint8_t *dst, int dst_len);
+
+#endif

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d842a43c/net/nimble/host/src/ble_hs_hci_util.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_hci_util.c b/net/nimble/host/src/ble_hs_hci_util.c
new file mode 100644
index 0000000..0d9f625
--- /dev/null
+++ b/net/nimble/host/src/ble_hs_hci_util.c
@@ -0,0 +1,196 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+#include <string.h>
+#include "nimble/hci_common.h"
+#include "ble_hs_priv.h"
+
+uint16_t
+ble_hs_hci_util_opcode_join(uint8_t ogf, uint16_t ocf)
+{
+    return (ogf << 10) | ocf;
+}
+
+uint16_t
+ble_hs_hci_util_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);
+}
+
+int
+ble_hs_hci_util_read_adv_tx_pwr(int8_t *out_tx_pwr)
+{
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
+    uint8_t params_len;
+    int rc;
+
+    ble_hs_hci_cmd_build_read_adv_pwr(buf, sizeof buf);
+    rc = ble_hs_hci_cmd_tx(buf, out_tx_pwr, 1, &params_len);
+    if (rc != 0) {
+        return rc;
+    }
+
+    if (params_len != 1                     ||
+        *out_tx_pwr < BLE_HCI_ADV_CHAN_TXPWR_MIN ||
+        *out_tx_pwr > BLE_HCI_ADV_CHAN_TXPWR_MAX) {
+
+        return BLE_HS_ECONTROLLER;
+    }
+
+    return 0;
+}
+
+int
+ble_hs_hci_util_rand(void *dst, int len)
+{
+    uint8_t rsp_buf[BLE_HCI_LE_RAND_LEN];
+    uint8_t req_buf[BLE_HCI_CMD_HDR_LEN];
+    uint8_t params_len;
+    uint8_t *u8ptr;
+    int chunk_sz;
+    int rc;
+
+    ble_hs_hci_cmd_build_le_rand(req_buf, sizeof req_buf);
+
+    u8ptr = dst;
+    while (len > 0) {
+        rc = ble_hs_hci_cmd_tx(req_buf, rsp_buf, sizeof rsp_buf, &params_len);
+        if (rc != 0) {
+            return rc;
+        }
+        if (params_len != sizeof rsp_buf) {
+            return BLE_HS_ECONTROLLER;
+        }
+
+        chunk_sz = min(len, sizeof rsp_buf);
+        memcpy(u8ptr, rsp_buf, chunk_sz);
+
+        len -= chunk_sz;
+        u8ptr += chunk_sz;
+    }
+
+    return 0;
+}
+
+int
+ble_hs_hci_util_read_rssi(uint16_t conn_handle, int8_t *out_rssi)
+{
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_READ_RSSI_LEN];
+    uint8_t params[BLE_HCI_READ_RSSI_ACK_PARAM_LEN];
+    uint16_t params_conn_handle;
+    uint8_t params_len;
+    int rc;
+
+    ble_hs_hci_cmd_build_read_rssi(conn_handle, buf, sizeof buf);
+    rc = ble_hs_hci_cmd_tx(buf, params, sizeof params, &params_len);
+    if (rc != 0) {
+        return rc;
+    }
+
+    if (params_len != BLE_HCI_READ_RSSI_ACK_PARAM_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    params_conn_handle = le16toh(params + 0);
+    if (params_conn_handle != conn_handle) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    *out_rssi = params[2];
+
+    return 0;
+}
+
+int
+ble_hs_hci_util_set_random_addr(const uint8_t *addr)
+{
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RAND_ADDR_LEN];
+    int rc;
+
+    /* set the address in the controller */
+
+    rc = ble_hs_hci_cmd_build_set_random_addr(addr, buf, sizeof(buf));
+    if (rc != 0) {
+        return rc;
+    }
+
+    rc = ble_hs_hci_cmd_tx_empty_ack(buf);
+    return rc;
+}
+
+int
+ble_hs_hci_util_set_data_len(uint16_t conn_handle, uint16_t tx_octets,
+                             uint16_t tx_time)
+{
+
+    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_DATALEN_LEN];
+    uint8_t params[BLE_HCI_SET_DATALEN_ACK_PARAM_LEN];
+    uint16_t params_conn_handle;
+    uint8_t params_len;
+    int rc;
+
+    rc = ble_hs_hci_cmd_build_set_data_len(conn_handle, tx_octets, tx_time,
+                                           buf, sizeof buf);
+    if (rc != 0) {
+        return BLE_HS_HCI_ERR(rc);
+    }
+
+    rc = ble_hs_hci_cmd_tx(buf, params, BLE_HCI_SET_DATALEN_ACK_PARAM_LEN,
+                           &params_len);
+    if (rc != 0) {
+        return rc;
+    }
+
+    if (params_len != BLE_HCI_SET_DATALEN_ACK_PARAM_LEN) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    params_conn_handle = le16toh(params + 0);
+    if (params_conn_handle != conn_handle) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    return 0;
+}
+
+int
+ble_hs_hci_util_data_hdr_strip(struct os_mbuf *om,
+                               struct hci_data_hdr *out_hdr)
+{
+    int rc;
+
+    rc = os_mbuf_copydata(om, 0, BLE_HCI_DATA_HDR_SZ, out_hdr);
+    if (rc != 0) {
+        return BLE_HS_ECONTROLLER;
+    }
+
+    /* Strip HCI ACL data header from the front of the packet. */
+    os_mbuf_adj(om, BLE_HCI_DATA_HDR_SZ);
+
+    out_hdr->hdh_handle_pb_bc = le16toh(&out_hdr->hdh_handle_pb_bc);
+    out_hdr->hdh_len = le16toh(&out_hdr->hdh_len);
+
+    return 0;
+}

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d842a43c/net/nimble/host/src/ble_hs_id.c
----------------------------------------------------------------------
diff --git a/net/nimble/host/src/ble_hs_id.c b/net/nimble/host/src/ble_hs_id.c
index 6d7df2b..9ef384b 100644
--- a/net/nimble/host/src/ble_hs_id.c
+++ b/net/nimble/host/src/ble_hs_id.c
@@ -50,7 +50,7 @@ ble_hs_id_gen_rnd(int nrpa, uint8_t *out_addr)
 {
     int rc;
 
-    rc = ble_hci_util_rand(out_addr, 6);
+    rc = ble_hs_hci_util_rand(out_addr, 6);
     if (rc != 0) {
         return rc;
     }
@@ -91,7 +91,7 @@ ble_hs_id_set_rnd(const uint8_t *rnd_addr)
         goto done;
     }
 
-    rc = ble_hci_util_set_random_addr(rnd_addr);
+    rc = ble_hs_hci_util_set_random_addr(rnd_addr);
     if (rc != 0) {
         goto done;
     }

http://git-wip-us.apache.org/repos/asf/incubator-mynewt-core/blob/d842a43c/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 d8b5e82..d61f0ba 100644
--- a/net/nimble/host/src/ble_hs_priv.h
+++ b/net/nimble/host/src/ble_hs_priv.h
@@ -26,7 +26,8 @@
 #include "ble_att_priv.h"
 #include "ble_gap_priv.h"
 #include "ble_gatt_priv.h"
-#include "ble_hci_priv.h"
+#include "ble_hs_dbg_priv.h"
+#include "ble_hs_hci_priv.h"
 #include "ble_hs_atomic_priv.h"
 #include "ble_hs_conn_priv.h"
 #include "ble_hs_atomic_priv.h"
@@ -82,8 +83,8 @@ int ble_hs_tx_data(struct os_mbuf *om);
 void ble_hs_enqueue_hci_event(uint8_t *hci_evt);
 void ble_hs_event_enqueue(struct os_event *ev);
 
-int host_hci_evt_rx(uint8_t *hci_ev, void *arg);
-int host_hci_acl_process(struct os_mbuf *om);
+int ble_hs_hci_rx_evt(uint8_t *hci_ev, void *arg);
+int ble_hs_hci_evt_acl_process(struct os_mbuf *om);
 
 int ble_hs_misc_malloc_mempool(void **mem, struct os_mempool *pool,
                                int num_entries, int entry_size, char *name);