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, ¶ms_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, ¶ms_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, ¶ms_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,
+ ¶ms_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);