/**
 * Set the scan response data that the controller will send.
 *
 * @param cmd
 * @param len
 *
 * @return int
 */
int
ble_ll_adv_set_scan_rsp_data(uint8_t *cmd, uint8_t len)
{
    uint8_t datalen;
    os_sr_t sr;
    struct ble_ll_adv_sm *advsm;

    /* Check for valid scan response data length */
    datalen = cmd[0];
    if (datalen > BLE_SCAN_RSP_DATA_MAX_LEN) {
        return BLE_ERR_INV_HCI_CMD_PARMS;
    }

    /* Copy the new data into the advertising structure. */
    advsm = &g_ble_ll_adv_sm;
    advsm->scan_rsp_len = datalen;
    memcpy(advsm->scan_rsp_data, cmd + 1, datalen);

    /* Re-make the scan response PDU since data may have changed */
    OS_ENTER_CRITICAL(sr);
    /*
     * XXX: there is a chance, even with interrupts disabled, that
     * we are transmitting the scan response PDU while writing to it.
     */
    ble_ll_adv_scan_rsp_pdu_make(advsm);
    OS_EXIT_CRITICAL(sr);

    return 0;
}
/**
 * Start the advertising state machine. This is called when the host sends
 * the "enable advertising" command and is not called again while in the
 * advertising state.
 *
 * Context: Link-layer task.
 *
 * @param advsm Pointer to advertising state machine
 *
 * @return int
 */
static int
ble_ll_adv_sm_start(struct ble_ll_adv_sm *advsm)
{
    uint8_t adv_chan;

    /*
     * This is not in the specification. I will reject the command with a
     * command disallowed error if no random address has been sent by the
     * host. All the parameter errors refer to the command
     * parameter (which in this case is just enable or disable) so that
     * is why I chose command disallowed.
     */
    if (advsm->own_addr_type == BLE_HCI_ADV_OWN_ADDR_RANDOM) {
        if (!ble_ll_is_valid_random_addr(g_random_addr)) {
            return BLE_ERR_CMD_DISALLOWED;
        }
    }

    /* Set flag telling us that advertising is enabled */
    advsm->enabled = 1;

    /* Determine the advertising interval we will use */
    if (advsm->adv_type == BLE_HCI_ADV_TYPE_ADV_DIRECT_IND_HD) {
        /* Set it to max. allowed for high duty cycle advertising */
        advsm->adv_itvl_usecs = BLE_LL_ADV_PDU_ITVL_HD_MS_MAX;
    } else {
        advsm->adv_itvl_usecs = (uint32_t)advsm->adv_itvl_max;
        advsm->adv_itvl_usecs *= BLE_LL_ADV_ITVL;
    }

    /* Create scan response PDU (if needed) */
    if (advsm->adv_type != BLE_HCI_ADV_TYPE_ADV_NONCONN_IND) {
        ble_ll_adv_scan_rsp_pdu_make(advsm);
    }

    /* Set first advertising channel */
    adv_chan = ble_ll_adv_first_chan(advsm);
    advsm->adv_chan = adv_chan;

    /*
     * Schedule advertising. We set the initial schedule start and end
     * times to the earliest possible start/end.
     */
    ble_ll_adv_set_sched(advsm, 1);
    ble_ll_sched_adv_new(&advsm->adv_sch);

    return BLE_ERR_SUCCESS;
}
Ejemplo n.º 3
0
/**
 * Called when the LL receives a scan request or connection request
 *
 * Context: Called from interrupt context.
 *
 * @param rxbuf
 *
 * @return -1: request not for us or is a connect request.
 *          0: request (scan) is for us and we successfully went from rx to tx.
 *        > 0: PHY error attempting to go from rx to tx.
 */
static int
ble_ll_adv_rx_req(uint8_t pdu_type, struct os_mbuf *rxpdu)
{
    int rc;
    int resolved;
    uint8_t chk_wl;
    uint8_t txadd;
    uint8_t peer_addr_type;
    uint8_t *rxbuf;
    uint8_t *adva;
    uint8_t *peer;
    struct ble_mbuf_hdr *ble_hdr;
    struct ble_ll_adv_sm *advsm;
    struct os_mbuf *scan_rsp;

    /* See if adva in the request (scan or connect) matches what we sent */
    advsm = &g_ble_ll_adv_sm;
    rxbuf = rxpdu->om_data;
    adva = rxbuf + BLE_LL_PDU_HDR_LEN + BLE_DEV_ADDR_LEN;
    if (memcmp(advsm->adva, adva, BLE_DEV_ADDR_LEN)) {
        return -1;
    }

    /* Set device match bit if we are whitelisting */
    if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
        chk_wl = advsm->adv_filter_policy & 1;
    } else {
        chk_wl = advsm->adv_filter_policy & 2;
    }

    /* Get the peer address type */
    if (rxbuf[0] & BLE_ADV_PDU_HDR_TXADD_MASK) {
        txadd = BLE_ADDR_TYPE_RANDOM;
    } else {
        txadd = BLE_ADDR_TYPE_PUBLIC;
    }

    ble_hdr = BLE_MBUF_HDR_PTR(rxpdu);
    peer = rxbuf + BLE_LL_PDU_HDR_LEN;
    peer_addr_type = txadd;
    resolved = 0;

#if (MYNEWT_VAL(BLE_LL_CFG_FEAT_LL_PRIVACY) == 1)
    if (ble_ll_is_rpa(peer, txadd) && ble_ll_resolv_enabled()) {
        advsm->adv_rpa_index = ble_hw_resolv_list_match();
        if (advsm->adv_rpa_index >= 0) {
            ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_RESOLVED;
            if (chk_wl) {
                peer = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_identity_addr;
                peer_addr_type = g_ble_ll_resolv_list[advsm->adv_rpa_index].rl_addr_type;
                resolved = 1;
            }
        } else {
            if (chk_wl) {
                return -1;
            }
        }
    }
#endif

    /* Set device match bit if we are whitelisting */
    if (chk_wl && !ble_ll_whitelist_match(peer, peer_addr_type, resolved)) {
        return -1;
    }

    /*
     * We set the device match bit to tell the upper layer that we will
     * accept the request
     */
    ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_DEVMATCH;

    /* Setup to transmit the scan response if appropriate */
    rc = -1;
    if (pdu_type == BLE_ADV_PDU_TYPE_SCAN_REQ) {
        scan_rsp = ble_ll_adv_scan_rsp_pdu_make(advsm);
        if (scan_rsp) {
            ble_phy_set_txend_cb(ble_ll_adv_tx_done, &g_ble_ll_adv_sm);
            rc = ble_phy_tx(scan_rsp, BLE_PHY_TRANSITION_NONE);
            if (!rc) {
                ble_hdr->rxinfo.flags |= BLE_MBUF_HDR_F_SCAN_RSP_TXD;
                STATS_INC(ble_ll_stats, scan_rsp_txg);
            }
            os_mbuf_free_chain(scan_rsp);
        }
    }

    return rc;
}