int
bletest_hci_le_encrypt(uint8_t *key, uint8_t *pt)
{
    int rc;
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_LE_ENCRYPT_LEN];
    uint8_t rspbuf[16];
    uint8_t rsplen;

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_ENCRYPT,
                       BLE_HCI_LE_ENCRYPT_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    swap_buf(dst, key, BLE_ENC_BLOCK_SIZE);
    swap_buf(dst + BLE_ENC_BLOCK_SIZE, pt, BLE_ENC_BLOCK_SIZE);
    rc = ble_hs_hci_cmd_tx(buf, rspbuf, 16, &rsplen);
    if (rc != 0) {
        return rc;
    }

    if (rsplen != 16) {
        return BLE_HS_ECONTROLLER;
    }
    return rc;
}
int
bletest_hci_le_rd_chanmap(uint16_t handle)
{
    int rc;
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_RD_CHANMAP_LEN];
    uint8_t rspbuf[BLE_HCI_RD_CHANMAP_RSP_LEN];
    uint8_t rsplen;

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_CHAN_MAP,
                       BLE_HCI_RD_CHANMAP_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    put_le16(dst, handle);
    rc = ble_hs_hci_cmd_tx(buf, rspbuf, BLE_HCI_RD_CHANMAP_RSP_LEN, &rsplen);
    if (rc != 0) {
        return rc;
    }

    if (rsplen != BLE_HCI_RD_CHANMAP_RSP_LEN) {
        return BLE_HS_ECONTROLLER;
    }

    return rc;
}
int
bletest_hci_le_set_datalen(uint16_t handle, uint16_t txoctets, uint16_t txtime)
{
    int rc;
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_DATALEN_LEN];
    uint8_t rspbuf[2];
    uint8_t rsplen;

    dst = buf;
    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;

    put_le16(dst, handle);
    put_le16(dst + 2, txoctets);
    put_le16(dst + 4, txtime);
    rc = ble_hs_hci_cmd_tx(buf, rspbuf, 2, &rsplen);
    if (rc != 0) {
        return rc;
    }

    if (rsplen != 2) {
        return BLE_HS_ECONTROLLER;
    }

    return rc;
}
int
bletest_send_ltk_req_reply(uint16_t handle)
{
    struct hci_lt_key_req_reply hkr;
    uint16_t ack_conn_handle;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_LT_KEY_REQ_REPLY_LEN];
    uint8_t ack_params_len;
    int rc;

    hkr.conn_handle = handle;
    swap_buf(hkr.long_term_key, (uint8_t *)g_bletest_LTK, 16);

    ble_hs_hci_cmd_build_le_lt_key_req_reply(&hkr, buf, sizeof buf);
    rc = ble_hs_hci_cmd_tx(buf, &ack_conn_handle, sizeof ack_conn_handle,
                        &ack_params_len);
    if (rc != 0) {
        return rc;
    }
    if (ack_params_len != BLE_HCI_LT_KEY_REQ_REPLY_ACK_PARAM_LEN - 1) {
        return -1;
    }

    if (le16toh(ack_conn_handle) != handle) {
        return -1;
    }
    return 0;
}
int
bletest_hci_reset_ctlr(void)
{
    uint8_t buf[BLE_HCI_CMD_HDR_LEN];

    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_CTLR_BASEBAND, BLE_HCI_OCF_CB_RESET,
                             0, buf);
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_le_set_host_chan_class(uint8_t *chanmap)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_HOST_CHAN_CLASS_LEN];

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_HOST_CHAN_CLASS,
                       BLE_HCI_SET_HOST_CHAN_CLASS_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    memcpy(dst, chanmap, BLE_HCI_SET_HOST_CHAN_CLASS_LEN);
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_le_set_rand_addr(uint8_t *addr)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RAND_ADDR_LEN];

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_SET_RAND_ADDR,
                       BLE_DEV_ADDR_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    memcpy(dst, addr, BLE_DEV_ADDR_LEN);
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_le_read_rem_used_feat(uint16_t handle)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_CONN_RD_REM_FEAT_LEN];

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_REM_FEAT,
                       BLE_HCI_CONN_RD_REM_FEAT_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    put_le16(dst, handle);
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_le_set_adv_enable(uint8_t enable)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADV_ENABLE_LEN];

    dst = buf;
    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;

    dst[0] = enable;
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_rd_rem_version(uint16_t handle)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + sizeof(uint16_t)];

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LINK_CTRL, BLE_HCI_OCF_RD_REM_VER_INFO,
                       sizeof(uint16_t), dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    put_le16(dst, handle);
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
static int
ble_hs_pvcy_set_addr_timeout(uint16_t timeout)
{
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_RESOLV_PRIV_ADDR_TO_LEN];
    int rc;

    rc = ble_hs_hci_cmd_build_set_resolv_priv_addr_timeout(
            timeout, buf, sizeof(buf));

    if (rc != 0) {
        return rc;
    }

    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_le_write_sugg_datalen(uint16_t txoctets, uint16_t txtime)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_WR_SUGG_DATALEN_LEN];

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_WR_SUGG_DEF_DATA_LEN,
                       BLE_HCI_WR_SUGG_DATALEN_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    put_le16(dst, txoctets);
    put_le16(dst + 2, txtime);
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
static int
ble_hs_pvcy_clear_entries(void)
{
    uint8_t buf[BLE_HCI_CMD_HDR_LEN ];
    int rc;

    rc = ble_hs_hci_cmd_build_clear_resolv_list(buf, sizeof(buf));
    if (rc != 0) {
        return rc;
    }

    rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
    if (rc != 0) {
        return rc;
    }

    return 0;
}
static int
ble_hs_pvcy_set_resolve_enabled(int enable)
{
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_SET_ADDR_RESOL_ENA_LEN];
    int rc;

    rc = ble_hs_hci_cmd_build_set_addr_res_en(enable, buf, sizeof(buf));
    if (rc != 0) {
        return rc;
    }

    rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
    if (rc != 0) {
        return rc;
    }

    return 0;
}
int
bletest_hci_le_rd_max_datalen(void)
{
    int rc;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
    uint8_t rspbuf[BLE_HCI_RD_MAX_DATALEN_RSPLEN];
    uint8_t rsplen;

    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_MAX_DATA_LEN, 0, buf);
    rc = ble_hs_hci_cmd_tx(buf, rspbuf, BLE_HCI_RD_MAX_DATALEN_RSPLEN, &rsplen);
    if (rc != 0) {
        return rc;
    }

    if (rsplen != BLE_HCI_RD_MAX_DATALEN_RSPLEN) {
        return BLE_HS_ECONTROLLER;
    }
    return rc;
}
int
ble_hs_pvcy_remove_entry(uint8_t addr_type, uint8_t *addr)
{
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_RMV_FROM_RESOLV_LIST_LEN];
    int rc;

    rc = ble_hs_hci_cmd_build_remove_from_resolv_list(
        addr_type, addr, buf, sizeof(buf));
    if (rc != 0) {
        return rc;
    }

    rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
    if (rc != 0) {
        return rc;
    }

    return 0;
}
/**
 * Read supported states
 *
 * OGF = 0x08 (LE)
 * OCF = 0x001C
 *
 * @return int
 */
int
bletest_hci_le_read_supp_states(void)
{
    int rc;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
    uint8_t rspbuf[BLE_HCI_RD_SUPP_STATES_RSPLEN];
    uint8_t rsplen;

    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_RD_SUPP_STATES, 0, buf);
    rc = ble_hs_hci_cmd_tx(buf, rspbuf, BLE_HCI_RD_SUPP_STATES_RSPLEN, &rsplen);
    if (rc != 0) {
        return rc;
    }

    if (rsplen != BLE_HCI_RD_SUPP_STATES_RSPLEN) {
        return BLE_HS_ECONTROLLER;
    }
    return rc;
}
int
bletest_hci_le_set_multi_adv_enable(uint8_t enable, uint8_t instance)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_MULTI_ADV_ENABLE_LEN];

    if (instance >= BLE_LL_ADV_INSTANCES) {
        return -1;
    }

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_VENDOR, BLE_HCI_OCF_MULTI_ADV,
                             BLE_HCI_MULTI_ADV_ENABLE_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    dst[0] = BLE_HCI_MULTI_ADV_ENABLE;
    dst[1] = enable;
    dst[2] = instance;
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_rd_local_supp_cmd(void)
{
    int rc;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
    uint8_t rspbuf[BLE_HCI_RD_LOC_SUPP_CMD_RSPLEN];
    uint8_t rsplen;

    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_LOC_SUPP_CMD,
                       0, buf);
    rc = ble_hs_hci_cmd_tx(buf, rspbuf, BLE_HCI_RD_LOC_SUPP_CMD_RSPLEN, &rsplen);
    if (rc != 0) {
        return rc;
    }

    if (rsplen != BLE_HCI_RD_LOC_SUPP_CMD_RSPLEN) {
        return BLE_HS_ECONTROLLER;
    }
    return rc;
}
int
bletest_hci_le_set_multi_rand_addr(uint8_t *addr, uint8_t instance)
{
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_MULTI_ADV_SET_RAND_ADDR_LEN];

    if (instance >= BLE_LL_ADV_INSTANCES) {
        return -1;
    }

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_VENDOR, BLE_HCI_OCF_MULTI_ADV,
                       BLE_HCI_MULTI_ADV_SET_RAND_ADDR_LEN, dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    dst[0] = BLE_HCI_MULTI_ADV_SET_RAND_ADDR;
    memcpy(dst + 1, addr, BLE_DEV_ADDR_LEN);
    dst[7] = instance;
    return ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
}
int
bletest_hci_rd_bd_addr(void)
{
    int rc;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN];
    uint8_t rspbuf[BLE_DEV_ADDR_LEN];
    uint8_t rsplen;

    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_INFO_PARAMS, BLE_HCI_OCF_IP_RD_BD_ADDR, 0,
                       buf);
    rc = ble_hs_hci_cmd_tx(buf, rspbuf, BLE_DEV_ADDR_LEN, &rsplen);
    if (rc != 0) {
        return rc;
    }

    if (rsplen != BLE_DEV_ADDR_LEN) {
        return BLE_HS_ECONTROLLER;
    }

    return rc;
}
int
ble_hs_pvcy_add_entry(uint8_t *addr, uint8_t addr_type, uint8_t *irk)
{
    struct hci_add_dev_to_resolving_list add;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + BLE_HCI_ADD_TO_RESOLV_LIST_LEN];
    int rc;

    add.addr_type = addr_type;
    memcpy(add.addr, addr, 6);
    memcpy(add.local_irk, ble_hs_pvcy_irk, 16);
    memcpy(add.peer_irk, irk, 16);

    rc = ble_hs_hci_cmd_build_add_to_resolv_list(&add, buf, sizeof(buf));
    if (rc != 0) {
        return rc;
    }

    rc = ble_hs_hci_cmd_tx(buf, NULL, 0, NULL);
    if (rc != 0) {
        return rc;
    }

    return 0;
}
int
bletest_send_ltk_req_neg_reply(uint16_t handle)
{
    int rc;
    uint8_t *dst;
    uint8_t buf[BLE_HCI_CMD_HDR_LEN + sizeof(uint16_t)];
    uint16_t ack_conn_handle;
    uint8_t rsplen;

    dst = buf;
    ble_hs_hci_cmd_write_hdr(BLE_HCI_OGF_LE, BLE_HCI_OCF_LE_LT_KEY_REQ_NEG_REPLY,
                       sizeof(uint16_t), dst);
    dst += BLE_HCI_CMD_HDR_LEN;

    put_le16(dst, handle);
    rc = ble_hs_hci_cmd_tx(buf, &ack_conn_handle, 2, &rsplen);
    if (rc == 0) {
        if (rsplen != 2) {
            rc = -1;
        }
    }

    return rc;
}