void
ble_hs_atomic_conn_insert(struct ble_hs_conn *conn)
{
    ble_hs_lock();
    ble_hs_conn_insert(conn);
    ble_hs_unlock();
}
void
ble_sm_sc_dhkey_check_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
                         struct ble_sm_result *res)
{
    struct ble_sm_dhkey_check cmd;
    struct ble_sm_proc *proc;
    struct ble_sm_proc *prev;

    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_DHKEY_CHECK_SZ);
    if (res->app_status != 0) {
        res->enc_cb = 1;
        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
        return;
    }

    ble_sm_dhkey_check_parse((*om)->om_data, (*om)->om_len, &cmd);
    BLE_SM_LOG_CMD(0, "dhkey check", conn_handle, ble_sm_dhkey_check_log,
                   &cmd);

    ble_hs_lock();
    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_DHKEY_CHECK, -1,
                            &prev);
    if (proc == NULL) {
        res->app_status = BLE_HS_ENOENT;
    } else {
        ble_sm_dhkey_check_process(proc, &cmd, res);
    }
    ble_hs_unlock();
}
/**
 * Sets the device's random address.  The address type (static vs.
 * non-resolvable private) is inferred from the most-significant byte of the
 * address.  The address is specified in host byte order (little-endian!).
 *
 * @param rnd_addr              The random address to set.
 *
 * @return                      0 on success;
 *                              BLE_HS_EINVAL if the specified address is not a
 *                                  valid static random or non-resolvable
 *                                  private address.
 *                              Other nonzero on error.
 */
int
ble_hs_id_set_rnd(const uint8_t *rnd_addr)
{
    uint8_t addr_type_byte;
    int rc;

    ble_hs_lock();

    addr_type_byte = rnd_addr[5] & 0xc0;
    if (addr_type_byte != 0x00 && addr_type_byte != 0xc0) {
        rc = BLE_HS_EINVAL;
        goto done;
    }

    rc = ble_hs_hci_util_set_random_addr(rnd_addr);
    if (rc != 0) {
        goto done;
    }

    memcpy(ble_hs_id_rnd, rnd_addr, 6);

    rc = 0;

done:
    ble_hs_unlock();
    return rc;
}
int
ble_att_clt_rx_mtu(uint16_t conn_handle, struct os_mbuf **om)
{
    struct ble_att_mtu_cmd rsp;
    struct ble_l2cap_chan *chan;
    uint16_t mtu;
    int rc;

    mtu = 0;

    rc = ble_hs_misc_pullup_base(om, BLE_ATT_MTU_CMD_SZ);
    if (rc == 0) {
        ble_att_mtu_cmd_parse((*om)->om_data, (*om)->om_len, &rsp);

        ble_hs_lock();

        rc = ble_att_conn_chan_find(conn_handle, NULL, &chan);
        if (rc == 0) {
            ble_att_set_peer_mtu(chan, rsp.bamc_mtu);
            mtu = ble_l2cap_chan_mtu(chan);
        }

        ble_hs_unlock();
    }

    ble_gattc_rx_mtu(conn_handle, rc, mtu);
    return rc;
}
void
ble_hs_id_set_pub(const uint8_t *pub_addr)
{
    ble_hs_lock();
    memcpy(ble_hs_id_pub, pub_addr, 6);
    ble_hs_unlock();
}
int
ble_att_clt_tx_mtu(uint16_t conn_handle, struct ble_att_mtu_cmd *req)
{
    struct ble_l2cap_chan *chan;
    struct ble_hs_conn *conn;
    struct os_mbuf *txom;
    int rc;

    if (req->bamc_mtu < BLE_ATT_MTU_DFLT) {
        return BLE_HS_EINVAL;
    }

    rc = ble_att_clt_build_mtu_req(req, &txom);
    if (rc != 0) {
        return rc;
    }

    rc = ble_att_clt_tx_req(conn_handle, txom);
    if (rc != 0) {
        return rc;
    }

    ble_hs_lock();

    rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
    if (rc == 0) {
        chan->blc_flags |= BLE_L2CAP_CHAN_F_TXED_MTU;
    }

    ble_hs_unlock();

    return rc;
}
int
ble_hs_atomic_conn_delete(uint16_t conn_handle)
{
    struct ble_hs_conn *conn;

    ble_hs_lock();
    conn = ble_hs_conn_find(conn_handle);
    if (conn != NULL) {
        ble_hs_conn_remove(conn);
        ble_hs_conn_free(conn);

    }
    ble_hs_unlock();

    return conn != NULL ? 0 : BLE_HS_ENOTCONN;
}
static int
ble_os_test_misc_conn_exists(uint16_t conn_handle)
{
    struct ble_hs_conn *conn;

    ble_hs_lock();

    if (conn_handle == BLE_HS_CONN_HANDLE_NONE) {
        conn = ble_hs_conn_first();
    } else {
        conn = ble_hs_conn_find(conn_handle);
    }

    ble_hs_unlock();

    return conn != NULL;
}
/**
 * Retrieves one of the device's identity addresses.  The device can have two
 * identity addresses: one public and one random.  The id_addr_type argument
 * specifies which of these two addresses to retrieve.
 *
 * @param id_addr_type          The type of identity address to retrieve.
 *                                  Valid values are:
 *                                      o BLE_ADDR_TYPE_PUBLIC
 *                                      o BLE_ADDR_TYPE_RANDOM
 * @param out_id_addr           On success, the requested identity address is
 *                                  copied into this buffer.  The buffer must
 *                                  be at least six bytes in size.
 * @param out_is_nrpa           On success, the pointed-to value indicates
 *                                  whether the retrieved address is a
 *                                  non-resolvable private address.
 *
 * @return                      0 on success;
 *                              BLE_HS_EINVAL if an invalid address type was
 *                                  specified;
 *                              BLE_HS_ENOADDR if the device does not have an
 *                                  identity address of the requested type;
 *                              Other BLE host core code on error.
 */
int
ble_hs_id_copy_addr(uint8_t id_addr_type, uint8_t *out_id_addr,
                    int *out_is_nrpa)
{
    const uint8_t *addr;
    int rc;

    ble_hs_lock();

    rc = ble_hs_id_addr(id_addr_type, &addr, out_is_nrpa);
    if (rc == 0) {
        memcpy(out_id_addr, addr, 6);
    }

    ble_hs_unlock();

    return rc;
}
int
ble_hs_atomic_conn_flags(uint16_t conn_handle, ble_hs_conn_flags_t *out_flags)
{
    struct ble_hs_conn *conn;
    int rc;

    ble_hs_lock();

    conn = ble_hs_conn_find(conn_handle);
    if (conn == NULL) {
        rc = BLE_HS_ENOTCONN;
    } else {
        rc = 0;
        *out_flags = conn->bhc_flags;
    }

    ble_hs_unlock();

    return rc;
}
Exemple #11
0
uint16_t
ble_att_mtu(uint16_t conn_handle)
{
    struct ble_l2cap_chan *chan;
    struct ble_hs_conn *conn;
    uint16_t mtu;

    ble_hs_lock();

    ble_att_conn_chan_find(conn_handle, &conn, &chan);
    if (chan != NULL) {
        mtu = ble_l2cap_chan_mtu(chan);
    } else {
        mtu = 0;
    }

    ble_hs_unlock();

    return mtu;
}
static int
ble_att_clt_tx_req_flags(uint16_t conn_handle, struct os_mbuf *txom,
                         ble_hs_conn_flags_t flags_on_success)
{
    struct ble_l2cap_chan *chan;
    struct ble_hs_conn *conn;
    uint16_t total_len;
    uint16_t mtu;
    int extra_len;
    int rc;

    BLE_HS_DBG_ASSERT_EVAL(txom->om_len >= 1);
    ble_att_inc_tx_stat(txom->om_data[0]);

    ble_hs_lock();

    rc = ble_att_conn_chan_find(conn_handle, &conn, &chan);
    if (rc == 0) {
        /* Reduce the size of the transmission to fit the connection's ATT
         * MTU.
         */
        total_len = OS_MBUF_PKTLEN(txom);
        mtu = ble_l2cap_chan_mtu(chan);
        extra_len = total_len - mtu;
        if (extra_len > 0) {
            os_mbuf_adj(txom, -extra_len);
        }

        rc = ble_l2cap_tx(conn, chan, txom);
        txom = NULL;

        if (rc == 0) {
            conn->bhc_flags |= flags_on_success;
        }
    }

    ble_hs_unlock();

    os_mbuf_free_chain(txom);
    return rc;
}
static int
ble_l2cap_sig_tx(uint16_t conn_handle, struct os_mbuf *txom)
{
    struct ble_l2cap_chan *chan;
    struct ble_hs_conn *conn;
    int rc;

    STATS_INC(ble_l2cap_stats, sig_tx);

    ble_hs_lock();

    rc = ble_hs_misc_conn_chan_find_reqd(conn_handle, BLE_L2CAP_CID_SIG,
                                         &conn, &chan);
    if (rc == 0) {
        rc = ble_l2cap_tx(conn, chan, txom);
    }

    ble_hs_unlock();

    return rc;
}
void
ble_sm_sc_public_key_rx(uint16_t conn_handle, uint8_t op, struct os_mbuf **om,
                        struct ble_sm_result *res)
{
    struct ble_sm_public_key cmd;
    struct ble_sm_proc *proc;
    struct ble_sm_proc *prev;
    uint8_t ioact;
    int rc;

    res->app_status = ble_hs_mbuf_pullup_base(om, BLE_SM_PUBLIC_KEY_SZ);
    if (res->app_status != 0) {
        res->enc_cb = 1;
        return;
    }

    res->app_status = ble_sm_sc_ensure_keys_generated();
    if (res->app_status != 0) {
        res->enc_cb = 1;
        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
        return;
    }

    ble_sm_public_key_parse((*om)->om_data, (*om)->om_len, &cmd);
    BLE_SM_LOG_CMD(0, "public key", conn_handle, ble_sm_public_key_log, &cmd);

    ble_hs_lock();
    proc = ble_sm_proc_find(conn_handle, BLE_SM_PROC_STATE_PUBLIC_KEY, -1,
                            &prev);
    if (proc == NULL) {
        res->app_status = BLE_HS_ENOENT;
        res->sm_err = BLE_SM_ERR_UNSPECIFIED;
    } else {
        proc->pub_key_peer = cmd;
        rc = ble_sm_alg_gen_dhkey(proc->pub_key_peer.x,
                                  proc->pub_key_peer.y,
                                  ble_sm_sc_priv_key.u32,
                                  proc->dhkey);
        if (rc != 0) {
            res->app_status = BLE_HS_SM_US_ERR(BLE_SM_ERR_DHKEY);
            res->sm_err = BLE_SM_ERR_DHKEY;
            res->enc_cb = 1;
        } else {
            if (proc->flags & BLE_SM_PROC_F_INITIATOR) {
                proc->state = BLE_SM_PROC_STATE_CONFIRM;

                ioact = ble_sm_sc_io_action(proc);
                if (ble_sm_ioact_state(ioact) == proc->state) {
                    res->passkey_params.action = ioact;
                }

                if (ble_sm_proc_can_advance(proc) &&
                    ble_sm_sc_initiator_txes_confirm(proc)) {

                    res->execute = 1;
                }
            } else {
                res->execute = 1;
            }
        }
    }
    ble_hs_unlock();
}
/**
 * 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;
    uint16_t conn_handle;
    int reject_cid;
    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(): conn_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;
    }

    conn_handle = BLE_HCI_DATA_HANDLE(hci_hdr.hdh_handle_pb_bc);

    ble_hs_lock();

    conn = ble_hs_conn_find(conn_handle);
    if (conn == NULL) {
        /* Peer not connected; quietly discard packet. */
        rc = BLE_HS_ENOTCONN;
        reject_cid = -1;
    } else {
        /* Forward ACL data to L2CAP. */
        rc = ble_l2cap_rx(conn, &hci_hdr, om, &rx_cb, &reject_cid);
        om = NULL;
    }

    ble_hs_unlock();

    switch (rc) {
    case 0:
        /* Final fragment received. */
        BLE_HS_DBG_ASSERT(rx_cb != NULL);
        rc = rx_cb(conn->bhc_rx_chan);
        ble_l2cap_forget_rx(conn, conn->bhc_rx_chan);
        break;

    case BLE_HS_EAGAIN:
        /* More fragments on the way. */
        break;

    default:
        if (reject_cid != -1) {
            ble_l2cap_sig_reject_invalid_cid_tx(conn_handle, 0, 0, reject_cid);
        }
        goto err;
    }

    return 0;

err:
    os_mbuf_free_chain(om);
    return rc;
}