/** * 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; }
/** * 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; }