blob: 5d0d624a006e70f1cc0f87ecb336b39ba9e854ca [file] [log] [blame]
/*
* Copyright (c) 2020 Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdint.h>
#include <sys/byteorder.h>
#include <sys/util.h>
#include <bluetooth/hci.h>
#include "hal/ccm.h"
#include "hal/radio.h"
#include "hal/ticker.h"
#include "util/memq.h"
#include "pdu.h"
#include "lll.h"
#include "lll_vendor.h"
#include "lll_clock.h"
#include "lll_filter.h"
#include "lll_conn.h"
#include "lll_scan.h"
#include "lll_scan_aux.h"
#include "lll_internal.h"
#include "lll_tim_internal.h"
#include "lll_prof_internal.h"
#include "lll_scan_internal.h"
#define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
#define LOG_MODULE_NAME bt_ctlr_lll_scan_aux
#include "common/log.h"
#include <soc.h>
#include <ull_scan_types.h>
#include "hal/debug.h"
#if defined(CONFIG_BT_CENTRAL)
static uint8_t lll_scan_connect_req_pdu[PDU_AC_LL_HEADER_SIZE +
sizeof(struct pdu_adv_connect_ind)];
#endif /* CONFIG_BT_CENTRAL */
static int init_reset(void);
static int prepare_cb(struct lll_prepare_param *p);
static void abort_cb(struct lll_prepare_param *prepare_param, void *param);
static void isr_rx(void *param);
static int isr_rx_pdu(struct lll_scan_aux *lll, uint8_t devmatch_ok,
uint8_t devmatch_id, uint8_t irkmatch_ok,
uint8_t irkmatch_id, uint8_t rl_idx, uint8_t rssi_ready);
#if defined(CONFIG_BT_CENTRAL)
static void isr_tx_connect_req(void *param);
static void isr_rx_connect_rsp(void *param);
#endif /* CONFIG_BT_CENTRAL */
static void isr_done(void *param);
#if defined(CONFIG_BT_CENTRAL)
static inline bool isr_scan_init_check(struct lll_scan *lll,
struct pdu_adv *pdu, uint8_t rl_idx);
static bool isr_scan_connect_rsp_check(struct pdu_adv *pdu_tx,
struct pdu_adv *pdu_rx);
#endif /* CONFIG_BT_CENTRAL */
static uint16_t trx_cnt; /* TODO: move to a union in lll.c, common to all roles
*/
int lll_scan_aux_init(void)
{
int err;
err = init_reset();
if (err) {
return err;
}
return 0;
}
int lll_scan_aux_reset(void)
{
int err;
err = init_reset();
if (err) {
return err;
}
return 0;
}
void lll_scan_aux_prepare(void *param)
{
int err;
err = lll_hfclock_on();
LL_ASSERT(err >= 0);
err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0, param);
LL_ASSERT(!err || err == -EINPROGRESS);
}
static int init_reset(void)
{
return 0;
}
static int prepare_cb(struct lll_prepare_param *p)
{
struct node_rx_pdu *node_rx;
struct ll_scan_aux_set *aux_set;
struct ll_scan_set *scan_set;
struct lll_scan *lll_scan;
struct lll_scan_aux *lll;
uint32_t ticks_at_event;
uint32_t ticks_at_start;
struct ull_hdr *ull;
uint32_t remainder_us;
uint32_t remainder;
uint32_t hcto;
uint32_t aa;
DEBUG_RADIO_START_O(1);
lll = p->param;
aux_set = HDR_LLL2ULL(lll);
scan_set = HDR_LLL2ULL(aux_set->rx_head->rx_ftr.param);
lll_scan = &scan_set->lll;
#if defined(CONFIG_BT_CENTRAL)
/* Check if stopped (on connection establishment race between LLL and
* ULL.
*/
if (unlikely(lll_scan->is_stop ||
(lll_scan->conn &&
(lll_scan->conn->master.initiated ||
lll_scan->conn->master.cancelled)))) {
radio_isr_set(lll_isr_early_abort, lll);
radio_disable();
return 0;
}
#endif /* CONFIG_BT_CENTRAL */
/* Start setting up Radio h/w */
radio_reset();
/* Reset Tx/rx count */
trx_cnt = 0U;
#if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
radio_tx_power_set(lll->tx_pwr_lvl);
#else
radio_tx_power_set(RADIO_TXP_DEFAULT);
#endif
radio_phy_set(lll->phy, 1);
radio_pkt_configure(8, PDU_AC_PAYLOAD_SIZE_MAX, (lll->phy << 1));
node_rx = ull_pdu_rx_alloc_peek(1);
LL_ASSERT(node_rx);
radio_pkt_rx_set(node_rx->pdu);
aa = sys_cpu_to_le32(PDU_AC_ACCESS_ADDR);
radio_aa_set((uint8_t *)&aa);
radio_crc_configure(((0x5bUL) | ((0x06UL) << 8) | ((0x00UL) << 16)),
0x555555);
lll_chan_set(lll->chan);
radio_isr_set(isr_rx, lll);
/* setup tIFS switching */
radio_tmr_tifs_set(EVENT_IFS_US);
radio_switch_complete_and_tx(lll->phy, 0, lll->phy, 1);
/* TODO: skip filtering if AdvA was already found in previous PDU */
if (0) {
#if defined(CONFIG_BT_CTLR_PRIVACY)
} else if (ull_filter_lll_rl_enabled()) {
struct lll_filter *filter = ull_filter_lll_get(
!!(lll_scan->filter_policy & 0x1));
uint8_t count, *irks = ull_filter_lll_irks_get(&count);
radio_filter_configure(filter->enable_bitmask,
filter->addr_type_bitmask,
(uint8_t *) filter->bdaddr);
radio_ar_configure(count, irks, (lll->phy << 2) | BIT(1));
#endif /* CONFIG_BT_CTLR_PRIVACY */
} else if (IS_ENABLED(CONFIG_BT_CTLR_FILTER) &&
lll_scan->filter_policy) {
/* Setup Radio Filter */
struct lll_filter *wl = ull_filter_lll_get(true);
radio_filter_configure(wl->enable_bitmask,
wl->addr_type_bitmask,
(uint8_t *)wl->bdaddr);
}
/* Calculate event timings, coarse and fine */
ticks_at_event = p->ticks_at_expire;
ull = HDR_LLL2ULL(lll);
ticks_at_event += lll_event_offset_get(ull);
ticks_at_start = ticks_at_event;
ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
remainder = p->remainder;
remainder_us = radio_tmr_start(0, ticks_at_start, remainder);
hcto = remainder_us + lll->window_size_us;
hcto += radio_rx_ready_delay_get(lll->phy, 1);
hcto += addr_us_get(lll->phy);
hcto += radio_rx_chain_delay_get(lll->phy, 1);
radio_tmr_hcto_configure(hcto);
/* capture end of Rx-ed PDU, extended scan to schedule auxiliary
* channel chaining or to create periodic sync.
*/
radio_tmr_end_capture();
/* scanner always measures RSSI */
radio_rssi_measure();
#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
radio_gpio_lna_setup();
radio_gpio_pa_lna_enable(remainder_us +
radio_rx_ready_delay_get(lll->phy, 1) -
CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
#endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
#if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
(EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US)
/* check if preempt to start has changed */
if (lll_preempt_calc(ull, (TICKER_ID_SCAN_AUX_BASE +
ull_scan_aux_lll_handle_get(lll)),
ticks_at_event)) {
radio_isr_set(isr_done, lll);
radio_disable();
} else
#endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
{
uint32_t ret;
ret = lll_prepare_done(lll);
LL_ASSERT(!ret);
}
DEBUG_RADIO_START_O(1);
return 0;
}
static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
{
int err;
/* NOTE: This is not a prepare being cancelled */
if (!prepare_param) {
/* Perform event abort here.
* After event has been cleanly aborted, clean up resources
* and dispatch event done.
*/
radio_isr_set(isr_done, param);
radio_disable();
return;
}
/* NOTE: Else clean the top half preparations of the aborted event
* currently in preparation pipeline.
*/
err = lll_hfclock_off();
LL_ASSERT(err >= 0);
lll_done(param);
}
static void isr_rx(void *param)
{
struct lll_scan_aux *lll_aux;
struct ll_scan_aux_set *aux;
struct ll_scan_set *scan;
struct lll_scan *lll;
uint8_t devmatch_ok;
uint8_t devmatch_id;
uint8_t irkmatch_ok;
uint8_t irkmatch_id;
uint8_t rssi_ready;
uint8_t trx_done;
uint8_t crc_ok;
uint8_t rl_idx;
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
lll_prof_latency_capture();
}
/* Read radio status and events */
trx_done = radio_is_done();
if (trx_done) {
crc_ok = radio_crc_is_valid();
devmatch_ok = radio_filter_has_match();
devmatch_id = radio_filter_match_get();
irkmatch_ok = radio_ar_has_match();
irkmatch_id = radio_ar_match_get();
rssi_ready = radio_rssi_is_ready();
} else {
crc_ok = devmatch_ok = irkmatch_ok = rssi_ready = 0U;
devmatch_id = irkmatch_id = 0xFF;
}
/* Clear radio rx status and events */
lll_isr_rx_status_reset();
lll_aux = param;
aux = HDR_LLL2ULL(lll_aux);
scan = HDR_LLL2ULL(aux->rx_head->rx_ftr.param);
lll = &scan->lll;
/* No Rx */
if (!trx_done) {
/* TODO: Combine the early exit with above if-then-else block
*/
goto isr_rx_do_close;
}
#if defined(CONFIG_BT_CTLR_PRIVACY)
rl_idx = devmatch_ok ?
ull_filter_lll_rl_idx(!!(lll->filter_policy & 0x01),
devmatch_id) :
irkmatch_ok ? ull_filter_lll_rl_irk_idx(irkmatch_id) :
FILTER_IDX_NONE;
#else
rl_idx = FILTER_IDX_NONE;
#endif /* CONFIG_BT_CTLR_PRIVACY */
if (crc_ok) {
int err;
err = isr_rx_pdu(lll_aux, devmatch_ok, devmatch_id,
irkmatch_ok, irkmatch_ok, rl_idx, rssi_ready);
if (!err) {
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
lll_prof_send();
}
return;
}
}
isr_rx_do_close:
radio_isr_set(isr_done, lll_aux);
radio_disable();
}
static int isr_rx_pdu(struct lll_scan_aux *lll, uint8_t devmatch_ok,
uint8_t devmatch_id, uint8_t irkmatch_ok,
uint8_t irkmatch_id, uint8_t rl_idx, uint8_t rssi_ready)
{
struct ll_scan_aux_set *aux;
struct ll_scan_set *scan;
struct node_rx_pdu *node_rx;
struct node_rx_ftr *ftr;
struct lll_scan *lll_scan;
struct pdu_adv *pdu;
node_rx = ull_pdu_rx_alloc_peek(3);
if (!node_rx) {
return -ENOBUFS;
}
pdu = (void *)node_rx->pdu;
if ((pdu->type != PDU_ADV_TYPE_EXT_IND) || !pdu->len) {
return -EINVAL;
}
aux = HDR_LLL2ULL(lll);
scan = HDR_LLL2ULL(aux->rx_head->rx_ftr.param);
lll_scan = &scan->lll;
if (0) {
#if defined(CONFIG_BT_CENTRAL)
/* Initiator */
} else if (lll_scan->conn && !lll_scan->conn->master.cancelled &&
(pdu->adv_ext_ind.adv_mode & BT_HCI_LE_ADV_PROP_CONN) &&
isr_scan_init_check(lll_scan, pdu, rl_idx)) {
struct node_rx_ftr *ftr;
struct node_rx_pdu *rx;
struct pdu_adv *pdu_tx;
uint32_t conn_space_us;
struct ull_hdr *ull;
uint32_t pdu_end_us;
uint8_t init_tx_addr;
uint8_t *init_addr;
#if defined(CONFIG_BT_CTLR_PRIVACY)
bt_addr_t *lrpa;
#endif /* CONFIG_BT_CTLR_PRIVACY */
/* Always use CSA#2 on secondary channel, we need 2 nodes for conn
* and CSA#2 events and 2 nodes are always reserved for connection.
*/
rx = ull_pdu_rx_alloc_peek(4);
if (!rx) {
return -ENOBUFS;
}
pdu_end_us = radio_tmr_end_get();
if (!lll_scan->ticks_window) {
uint32_t scan_interval_us;
/* FIXME: is this correct for continuous scanning? */
scan_interval_us = lll_scan->interval * SCAN_INT_UNIT_US;
pdu_end_us %= scan_interval_us;
}
/* AUX_CONNECT_REQ is the same as CONNECT_IND */
const uint8_t aux_connect_req_len =
sizeof(struct pdu_adv_connect_ind);
/* AUX_CONNECT_RSP has only AdvA and TargetA in extended common
* header
*/
const uint8_t aux_connect_rsp_len =
PDU_AC_EXT_HEADER_SIZE_MIN +
sizeof(struct pdu_adv_ext_hdr) +
ADVA_SIZE + TARGETA_SIZE;
ull = HDR_LLL2ULL(lll_scan);
if (pdu_end_us > (HAL_TICKER_TICKS_TO_US(ull->ticks_slot) -
EVENT_IFS_US -
PKT_AC_US(aux_connect_req_len, 0,
lll->phy) -
EVENT_IFS_US -
PKT_AC_US(aux_connect_rsp_len, 0,
lll->phy) -
EVENT_OVERHEAD_START_US -
EVENT_TICKER_RES_MARGIN_US)) {
return -ETIME;
}
#if defined(CONFIG_BT_CTLR_PRIVACY)
lrpa = ull_filter_lll_lrpa_get(rl_idx);
if (lll_scan->rpa_gen && lrpa) {
init_tx_addr = 1;
init_addr = lrpa->val;
} else {
#else
if (1) {
#endif
init_tx_addr = lll_scan->init_addr_type;
init_addr = lll_scan->init_addr;
}
pdu_tx = (void *)lll_scan_connect_req_pdu;
lll_scan_prepare_connect_req(lll_scan, pdu_tx, lll->phy,
pdu->tx_addr,
pdu->adv_ext_ind.ext_hdr.data,
init_tx_addr, init_addr,
&conn_space_us);
radio_pkt_tx_set(pdu_tx);
/* assert if radio packet ptr is not set and radio started tx */
LL_ASSERT(!radio_is_ready());
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
lll_prof_cputime_capture();
}
/* capture end of Tx-ed PDU, used to calculate HCTO. */
radio_tmr_end_capture();
radio_tmr_tifs_set(EVENT_IFS_US);
radio_switch_complete_and_rx(lll->phy);
radio_isr_set(isr_tx_connect_req, lll);
#if defined(CONFIG_BT_CTLR_GPIO_PA_PIN)
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
/* PA/LNA enable is overwriting packet end
* used in ISR profiling, hence back it up
* for later use.
*/
lll_prof_radio_end_backup();
}
radio_gpio_pa_setup();
radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
EVENT_IFS_US -
radio_rx_chain_delay_get(0, 0) -
CONFIG_BT_CTLR_GPIO_PA_OFFSET);
#endif /* CONFIG_BT_CTLR_GPIO_PA_PIN */
#if defined(CONFIG_BT_CTLR_CONN_RSSI)
if (rssi_ready) {
lll_scan->conn->rssi_latest = radio_rssi_get();
}
#endif /* CONFIG_BT_CTLR_CONN_RSSI */
/* block CPU so that there is no CRC error on pdu tx,
* this is only needed if we want the CPU to sleep.
* while(!radio_has_disabled())
* {cpu_sleep();}
* radio_status_reset();
*/
/* Stop further connection initiation */
lll_scan->conn->master.initiated = 1U;
/* Stop further initiating events */
lll_scan->is_stop = 1U;
rx = ull_pdu_rx_alloc();
rx->hdr.type = NODE_RX_TYPE_CONNECTION;
rx->hdr.handle = 0xffff;
memcpy(rx->pdu, pdu_tx, (offsetof(struct pdu_adv, connect_ind) +
sizeof(struct pdu_adv_connect_ind)));
/* ChSel is RFU in AUX_ADV_IND but we do need to use CSA#2 for
* connections initiated on the secondary advertising channel
* thus overwrise chan_sel to make it work seamlessly.
*/
pdu = (void *)rx->pdu;
pdu->chan_sel = 1;
ftr = &(rx->hdr.rx_ftr);
ftr->param = lll_scan;
ftr->ticks_anchor = radio_tmr_start_get();
ftr->radio_end_us = conn_space_us -
radio_rx_chain_delay_get(lll->phy, 1);
#if defined(CONFIG_BT_CTLR_PRIVACY)
ftr->rl_idx = irkmatch_ok ? rl_idx : FILTER_IDX_NONE;
ftr->lrpa_used = lll_scan->rpa_gen && lrpa;
#endif /* CONFIG_BT_CTLR_PRIVACY */
ftr->extra = ull_pdu_rx_alloc();
lll->node_conn_rx = rx;
return 0;
} else if (!lll_scan->conn) {
#else /* !CONFIG_BT_CENTRAL */
} else {
#endif /* !CONFIG_BT_CENTRAL */
ull_pdu_rx_alloc();
trx_cnt++;
node_rx->hdr.type = NODE_RX_TYPE_EXT_AUX_REPORT;
ftr = &(node_rx->hdr.rx_ftr);
ftr->param = lll;
ftr->ticks_anchor = radio_tmr_start_get();
ftr->radio_end_us = radio_tmr_end_get() -
radio_rx_chain_delay_get(lll->phy, 1);
ftr->rssi = (rssi_ready) ? radio_rssi_get() :
BT_HCI_LE_RSSI_NOT_AVAILABLE;
#if defined(CONFIG_BT_CTLR_PRIVACY)
/* TODO: Use correct rl_idx value when privacy support is added */
ftr->rl_idx = FILTER_IDX_NONE;
#endif /* CONFIG_BT_CTLR_PRIVACY */
ull_rx_put(node_rx->hdr.link, node_rx);
ull_rx_sched();
}
return -ECANCELED;
}
#if defined(CONFIG_BT_CENTRAL)
static void isr_tx_connect_req(void *param)
{
struct lll_scan_aux *lll_aux;
uint32_t hcto;
/* Clear radio tx status and events */
lll_isr_tx_status_reset();
lll_aux = param;
radio_pkt_rx_set(radio_pkt_scratch_get());
/* assert if radio packet ptr is not set and radio started rx */
LL_ASSERT(!radio_is_ready());
radio_tmr_tifs_set(EVENT_IFS_US);
radio_switch_complete_and_disable();
radio_isr_set(isr_rx_connect_rsp, param);
#if defined(CONFIG_BT_CTLR_PRIVACY)
if (ull_filter_lll_rl_enabled()) {
uint8_t count, *irks = ull_filter_lll_irks_get(&count);
radio_ar_configure(count, irks, (lll_aux->phy << 2) | BIT(1));
}
#endif /* CONFIG_BT_CTLR_PRIVACY */
/* +/- 2us active clock jitter, +1 us hcto compensation */
hcto = radio_tmr_tifs_base_get() + EVENT_IFS_US + 4 + 1;
hcto += radio_rx_chain_delay_get(lll_aux->phy, 1);
hcto += addr_us_get(lll_aux->phy);
hcto -= radio_tx_chain_delay_get(lll_aux->phy, 0);
radio_tmr_hcto_configure(hcto);
if (IS_ENABLED(CONFIG_BT_CTLR_SCAN_REQ_RSSI) ||
IS_ENABLED(CONFIG_BT_CTLR_CONN_RSSI)) {
radio_rssi_measure();
}
#if defined(CONFIG_BT_CTLR_GPIO_LNA_PIN)
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
/* PA/LNA enable is overwriting packet end used in ISR
* profiling, hence back it up for later use.
*/
lll_prof_radio_end_backup();
}
radio_gpio_lna_setup();
radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() + EVENT_IFS_US - 4 -
radio_tx_chain_delay_get(lll_aux->phy, 0) -
CONFIG_BT_CTLR_GPIO_LNA_OFFSET);
#endif /* CONFIG_BT_CTLR_GPIO_LNA_PIN */
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
/* NOTE: as scratch packet is used to receive, it is safe to
* generate profile event using rx nodes.
*/
lll_prof_send();
}
}
static void isr_rx_connect_rsp(void *param)
{
struct node_rx_pdu *rx;
struct ll_scan_aux_set *aux;
struct lll_scan *lll;
struct ll_scan_set *scan;
struct lll_scan_aux *lll_aux;
struct pdu_adv *pdu_rx;
uint8_t trx_done;
if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
lll_prof_latency_capture();
}
/* Read radio status */
trx_done = radio_is_done();
/* Clear radio rx status and events */
lll_isr_rx_status_reset();
lll_aux = param;
aux = HDR_LLL2ULL(lll_aux);
scan = HDR_LLL2ULL(aux->rx_head->rx_ftr.param);
lll = &scan->lll;
rx = lll_aux->node_conn_rx;
LL_ASSERT(rx);
lll_aux->node_conn_rx = NULL;
if (trx_done) {
pdu_rx = radio_pkt_scratch_get();
trx_done = isr_scan_connect_rsp_check(
(void *)lll_scan_connect_req_pdu,
pdu_rx);
}
/* No Rx or invalid PDU received */
if (!trx_done) {
struct node_rx_ftr *ftr;
/* Try again with connection initiation */
lll->conn->master.initiated = 0U;
/* Dont stop initiating events on primary channels */
lll->is_stop = 0U;
ftr = &(rx->hdr.rx_ftr);
rx->hdr.type = NODE_RX_TYPE_RELEASE;
ull_rx_put(rx->hdr.link, rx);
rx = ftr->extra;
rx->hdr.type = NODE_RX_TYPE_RELEASE;
goto isr_rx_do_close;
}
#if defined(CONFIG_BT_CTLR_PHY)
lll->conn->phy_tx = lll_aux->phy;
lll->conn->phy_tx_time = lll_aux->phy;
lll->conn->phy_rx = lll_aux->phy;
#endif /* CONFIG_BT_CTLR_PHY */
isr_rx_do_close:
ull_rx_put(rx->hdr.link, rx);
ull_rx_sched();
radio_isr_set(isr_done, lll_aux);
radio_disable();
}
#endif /* CONFIG_BT_CENTRAL */
static void isr_done(void *param)
{
struct event_done_extra *e;
lll_isr_status_reset();
if (!trx_cnt) {
e = ull_event_done_extra_get();
LL_ASSERT(e);
e->type = EVENT_DONE_EXTRA_TYPE_SCAN_AUX;
}
lll_isr_cleanup(param);
}
#if defined(CONFIG_BT_CENTRAL)
static inline bool isr_scan_init_check(struct lll_scan *lll,
struct pdu_adv *pdu, uint8_t rl_idx)
{
uint8_t is_directed = pdu->adv_ext_ind.ext_hdr.tgt_addr;
uint8_t tx_addr = pdu->tx_addr;
uint8_t rx_addr = pdu->rx_addr;
uint8_t *adva = &pdu->adv_ext_ind.ext_hdr.data[ADVA_OFFSET];
uint8_t *tgta = &pdu->adv_ext_ind.ext_hdr.data[TGTA_OFFSET];
if (pdu->len <
PDU_AC_EXT_HEADER_SIZE_MIN + sizeof(struct pdu_adv_ext_hdr) +
ADVA_SIZE) {
return false;
}
if (is_directed && (pdu->len < PDU_AC_EXT_HEADER_SIZE_MIN +
sizeof(struct pdu_adv_ext_hdr) +
ADVA_SIZE + TARGETA_SIZE)) {
return false;
}
return ((((lll->filter_policy & 0x01) != 0U) ||
lll_scan_adva_check(lll, tx_addr, adva, rl_idx)) &&
((!is_directed) || (is_directed &&
lll_scan_tgta_check(lll, true, rx_addr,
tgta, rl_idx, NULL))));
}
bool isr_scan_connect_rsp_check(struct pdu_adv *pdu_tx, struct pdu_adv *pdu_rx)
{
if (pdu_rx->type != PDU_ADV_TYPE_AUX_CONNECT_RSP) {
return false;
}
if (pdu_rx->len != offsetof(struct pdu_adv_com_ext_adv,
ext_hdr_adv_data) +
offsetof(struct pdu_adv_ext_hdr, data) + ADVA_SIZE +
TARGETA_SIZE) {
return false;
}
if (pdu_rx->adv_ext_ind.adv_mode ||
!pdu_rx->adv_ext_ind.ext_hdr.adv_addr ||
!pdu_rx->adv_ext_ind.ext_hdr.tgt_addr) {
return false;
}
return (pdu_rx->tx_addr == pdu_tx->rx_addr) &&
(pdu_rx->rx_addr == pdu_tx->tx_addr) &&
(memcmp(&pdu_rx->adv_ext_ind.ext_hdr.data[ADVA_OFFSET],
pdu_tx->connect_ind.adv_addr, BDADDR_SIZE) == 0) &&
(memcmp(&pdu_rx->adv_ext_ind.ext_hdr.data[TGTA_OFFSET],
pdu_tx->connect_ind.init_addr, BDADDR_SIZE) == 0);
}
#endif /* CONFIG_BT_CENTRAL */