Bluetooth: Controller: Periodic Adv ADI Support for Duplicate Filtering

Add implementation to support Periodic Advertiser ADI
support for duplicate filtering.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2021-10-28 07:51:04 +05:30 committed by Carles Cufí
commit 400ff7b99c
5 changed files with 239 additions and 53 deletions

View file

@ -1431,6 +1431,7 @@ struct bt_hci_cp_le_ext_create_conn {
#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST BIT(0) #define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_USE_LIST BIT(0)
#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED BIT(1) #define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED BIT(1)
#define BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE BIT(2)
#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING 0 #define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_FILTERING 0
#define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA BIT(0) #define BT_HCI_LE_PER_ADV_CREATE_SYNC_CTE_TYPE_NO_AOA BIT(0)

View file

@ -532,6 +532,14 @@ config BT_CTLR_SYNC_PERIODIC_ADV_LIST_SIZE
Set Periodic Advertiser List size, this will be return in the HCI LE Set Periodic Advertiser List size, this will be return in the HCI LE
Read Periodic Advertiser List Command. Read Periodic Advertiser List Command.
config BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT
bool "Periodic Advertising Sync with ADI support (duplicate filtering)"
depends on BT_CTLR_SYNC_PERIODIC
default y
help
Enable support for duplicate filtering using AdvDataInfo present in
Periodic Advertising PDUs.
config BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING config BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING
bool "LE Periodic Advertiser filtering by CTE type" bool "LE Periodic Advertiser filtering by CTE type"
depends on BT_CTLR_SYNC_PERIODIC depends on BT_CTLR_SYNC_PERIODIC

View file

@ -84,7 +84,29 @@
static uint16_t _opcode; static uint16_t _opcode;
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
/* NOTE: Duplicate filter uses two LS bits value of standard advertising modes:
* 0 - Non-Connectable Non-Scannable advertising report
* 1 - Connectable Non-Scannable advertising report
* 2 - Non-Connectable Scannable advertisig report
* 3 - Connectable Scannable advertising report
*
* FIXME: Duplicate filtering of Connectable Directed low and high duty
* cycle. If advertiser changes between Connectable Non-Scannable,
* Connectable Directed low, and high duty cycle without changing
* SID and DID, then such reports will be filtered out by the
* implementation. Needs enhancement to current implementation.
*
* Define a custom duplicate filter mode for periodic advertising:
* 4 - Periodic Advertising report
*/
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
#define DUP_EXT_ADV_MODE_MAX 5
#define DUP_EXT_ADV_MODE_PERIODIC BIT(2)
#else /* !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
#define DUP_EXT_ADV_MODE_MAX 4 #define DUP_EXT_ADV_MODE_MAX 4
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
#define DUP_EXT_ADV_MODE_COUNT 4 #define DUP_EXT_ADV_MODE_COUNT 4
/* Duplicate filter entries, one per Bluetooth address */ /* Duplicate filter entries, one per Bluetooth address */
@ -113,6 +135,18 @@ static struct dup_entry {
static int32_t dup_count; static int32_t dup_count;
/* Duplicate filtering current free entry, overwrites entries after rollover */ /* Duplicate filtering current free entry, overwrites entries after rollover */
static uint32_t dup_curr; static uint32_t dup_curr;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
/* Helper function to reset non-periodic advertising entries in filter table */
static void dup_ext_adv_reset(int count);
/* Flag for advertising reports be filtered for duplicates. */
static bool dup_scan;
#else /* !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
/* Set constant true so that (dup_count >= 0) decides if advertising duplicate
* filter is enabled when Periodic Advertising ADI support is disabled.
*/
static const bool dup_scan = true;
#endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
#if defined(CONFIG_BT_HCI_MESH_EXT) #if defined(CONFIG_BT_HCI_MESH_EXT)
@ -347,6 +381,9 @@ static void reset(struct net_buf *buf, struct net_buf **evt)
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
dup_count = DUP_FILTER_DISABLED; dup_count = DUP_FILTER_DISABLED;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
dup_scan = false;
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
/* reset event masks */ /* reset event masks */
@ -1628,10 +1665,31 @@ static void le_set_scan_enable(struct net_buf *buf, struct net_buf **evt)
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
/* Initialize duplicate filtering */ /* Initialize duplicate filtering */
if (cmd->enable && cmd->filter_dup) { if (cmd->enable && cmd->filter_dup) {
if (0) {
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
} else if (dup_count <= DUP_FILTER_DISABLED) {
dup_scan = true;
/* All entries reset */
dup_count = 0; dup_count = 0;
dup_curr = 0U; dup_curr = 0U;
} else if (!dup_scan) {
dup_scan = true;
dup_ext_adv_reset(dup_count);
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
} else { } else {
/* All entries reset */
dup_count = 0;
dup_curr = 0U;
}
} else {
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
dup_scan = false;
#else /* !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
dup_count = DUP_FILTER_DISABLED; dup_count = DUP_FILTER_DISABLED;
#endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
} }
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -3318,10 +3376,31 @@ static void le_set_ext_scan_enable(struct net_buf *buf, struct net_buf **evt)
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
/* Initialize duplicate filtering */ /* Initialize duplicate filtering */
if (cmd->enable && cmd->filter_dup) { if (cmd->enable && cmd->filter_dup) {
if (0) {
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
} else if (dup_count < 0) {
dup_scan = true;
/* All entries reset */
dup_count = 0; dup_count = 0;
dup_curr = 0U; dup_curr = 0U;
} else if (!dup_scan) {
dup_scan = true;
dup_ext_adv_reset(dup_count);
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
} else { } else {
/* All entries reset */
dup_count = 0;
dup_curr = 0U;
}
} else {
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
dup_scan = false;
#else /* !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
dup_count = DUP_FILTER_DISABLED; dup_count = DUP_FILTER_DISABLED;
#endif /* !CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
} }
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -3359,6 +3438,35 @@ static void le_per_adv_create_sync(struct net_buf *buf, struct net_buf **evt)
return; return;
} }
if (!IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT) &&
(cmd->options &
(BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_REPORTS_DISABLED |
BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE)) ==
BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE) {
*evt = cmd_status(BT_HCI_ERR_UNSUPP_FEATURE_PARAM_VAL);
return;
}
/* FIXME: Check for HCI LE Set Periodic Advertising Receive Enable
* command support and if reporting is initially disabled then
* return error code Connection Failed to be Established /
* Synchronization Timeout (0x3E).
*/
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
/* Initialize duplicate filtering */
if (cmd->options & BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE) {
if (!dup_scan || (dup_count < 0)) {
dup_count = 0;
dup_curr = 0U;
} else {
/* FIXME: Invalidate dup_ext_adv_mode array entries */
}
} else if (!dup_scan) {
dup_count = DUP_FILTER_DISABLED;
}
#endif
skip = sys_le16_to_cpu(cmd->skip); skip = sys_le16_to_cpu(cmd->skip);
sync_timeout = sys_le16_to_cpu(cmd->sync_timeout); sync_timeout = sys_le16_to_cpu(cmd->sync_timeout);
@ -4726,6 +4834,21 @@ static void dup_ext_adv_mode_reset(struct dup_ext_adv_mode *dup_adv_mode)
dup_mode->set_curr = 0U; dup_mode->set_curr = 0U;
} }
} }
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
static void dup_ext_adv_reset(int count)
{
int i;
for (i = 0; i < count; i++) {
struct dup_entry *dup;
dup = &dup_filter[i];
dup->mask = 0U;
dup_ext_adv_mode_reset(dup->adv_mode);
}
}
#endif /* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT */
#endif /* CONFIG_BT_CTLR_ADV_EXT */ #endif /* CONFIG_BT_CTLR_ADV_EXT */
static inline bool is_dup_or_update(struct dup_entry *dup, uint8_t adv_type, static inline bool is_dup_or_update(struct dup_entry *dup, uint8_t adv_type,
@ -4862,7 +4985,8 @@ static inline void le_dir_adv_report(struct pdu_adv *adv, struct net_buf *buf,
LL_ASSERT(adv->type == PDU_ADV_TYPE_DIRECT_IND); LL_ASSERT(adv->type == PDU_ADV_TYPE_DIRECT_IND);
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) { if (dup_scan &&
dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) {
return; return;
} }
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -5016,7 +5140,8 @@ static void le_advertising_report(struct pdu_data *pdu_data,
} }
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) { if (dup_scan &&
dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) {
return; return;
} }
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -5126,7 +5251,8 @@ static void le_ext_adv_legacy_report(struct pdu_data *pdu_data,
#endif /* CONFIG_BT_CTLR_PRIVACY */ #endif /* CONFIG_BT_CTLR_PRIVACY */
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) { if (dup_scan &&
dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) {
return; return;
} }
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */ #endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -5749,8 +5875,9 @@ no_ext_hdr:
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (adv_addr) { if (adv_addr) {
if (dup_found(PDU_ADV_TYPE_EXT_IND, adv_addr_type, adv_addr, if (dup_scan &&
evt_type, adi, data_status)) { dup_found(PDU_ADV_TYPE_EXT_IND, adv_addr_type, adv_addr,
(evt_type & BIT_MASK(2)), adi, data_status)) {
node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra); node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra);
return; return;
} }
@ -5918,7 +6045,7 @@ static void le_per_adv_sync_established(struct pdu_data *pdu_data,
scan = node_rx->hdr.rx_ftr.param; scan = node_rx->hdr.rx_ftr.param;
sep->sid = scan->per_scan.sid; sep->sid = scan->per_scan.sid;
/* FIXME: fill based on filter_policy options */ /* Resolved address, if private, has been populated in ULL */
sep->adv_addr.type = scan->per_scan.adv_addr_type; sep->adv_addr.type = scan->per_scan.adv_addr_type;
memcpy(&sep->adv_addr.a.val[0], scan->per_scan.adv_addr, BDADDR_SIZE); memcpy(&sep->adv_addr.a.val[0], scan->per_scan.adv_addr, BDADDR_SIZE);
sep->phy = find_lsb_set(se->phy); sep->phy = find_lsb_set(se->phy);
@ -5935,6 +6062,7 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data,
int8_t tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; int8_t tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF;
struct pdu_adv *adv = (void *)pdu_data; struct pdu_adv *adv = (void *)pdu_data;
struct pdu_adv_aux_ptr *aux_ptr = NULL; struct pdu_adv_aux_ptr *aux_ptr = NULL;
const struct pdu_adv_adi *adi = NULL;
uint8_t cte_type = BT_HCI_LE_NO_CTE; uint8_t cte_type = BT_HCI_LE_NO_CTE;
struct pdu_adv_com_ext_adv *p; struct pdu_adv_com_ext_adv *p;
struct pdu_adv_ext_hdr *h; struct pdu_adv_ext_hdr *h;
@ -5944,6 +6072,7 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data,
uint8_t *data = NULL; uint8_t *data = NULL;
uint8_t data_len_max; uint8_t data_len_max;
uint8_t hdr_buf_len; uint8_t hdr_buf_len;
bool dup = false;
uint8_t hdr_len; uint8_t hdr_len;
uint8_t *ptr; uint8_t *ptr;
int8_t rssi; int8_t rssi;
@ -6007,6 +6136,8 @@ static void le_per_adv_sync_report(struct pdu_data *pdu_data,
} }
if (h->adi) { if (h->adi) {
adi = (void *)ptr;
ptr += sizeof(struct pdu_adv_adi); ptr += sizeof(struct pdu_adv_adi);
} }
@ -6070,7 +6201,23 @@ no_ext_hdr:
BT_DBG(" AD Data (%u): <todo>", data_len); BT_DBG(" AD Data (%u): <todo>", data_len);
} }
adv = (void *)node_rx->pdu; #if (CONFIG_BT_CTLR_DUP_FILTER_LEN > 0) && \
defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
if (IS_ENABLED(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT) && adi) {
const struct ll_sync_set *sync = HDR_LLL2ULL(ftr->param);
/* FIXME: Use correct data status else chain PDU report will
* be filtered out.
*/
dup = sync->nodups && dup_found(PDU_ADV_TYPE_EXT_IND,
sync->peer_id_addr_type,
sync->peer_id_addr,
DUP_EXT_ADV_MODE_PERIODIC,
adi, 0U);
}
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 &&
* CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT
*/
data_len_max = ADV_REPORT_EVT_MAX_LEN - data_len_max = ADV_REPORT_EVT_MAX_LEN -
sizeof(struct bt_hci_evt_le_meta_event) - sizeof(struct bt_hci_evt_le_meta_event) -
@ -6078,6 +6225,7 @@ no_ext_hdr:
evt_buf = buf; evt_buf = buf;
if (!dup && (le_event_mask & BT_EVT_MASK_LE_PER_ADVERTISING_REPORT)) {
do { do {
uint8_t data_len_frag; uint8_t data_len_frag;
@ -6127,6 +6275,11 @@ no_ext_hdr:
tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF; tx_pwr = BT_HCI_LE_ADV_TX_POWER_NO_PREF;
} }
} while (data_len > 0); } while (data_len > 0);
evt_buf = NULL;
}
/* TODO: Generation of BIGInfo report */
} }
static void le_per_adv_sync_lost(struct pdu_data *pdu_data, static void le_per_adv_sync_lost(struct pdu_data *pdu_data,

View file

@ -158,6 +158,11 @@ uint8_t ll_sync_create(uint8_t options, uint8_t sid, uint8_t adv_addr_type,
} }
} }
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
sync->nodups = (options &
BT_HCI_LE_PER_ADV_CREATE_SYNC_FP_FILTER_DUPLICATE) ?
1U : 0U;
#endif
sync->skip = skip; sync->skip = skip;
sync->timeout = sync_timeout; sync->timeout = sync_timeout;
@ -481,6 +486,13 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
return; return;
} }
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
/* Remember the peer address */
sync->peer_id_addr_type = scan->per_scan.adv_addr_type;
(void)memcpy(sync->peer_id_addr, scan->per_scan.adv_addr,
sizeof(sync->peer_id_addr));
#endif
memcpy(lll->access_addr, &si->aa, sizeof(lll->access_addr)); memcpy(lll->access_addr, &si->aa, sizeof(lll->access_addr));
lll->data_chan_id = lll_chan_id(lll->access_addr); lll->data_chan_id = lll_chan_id(lll->access_addr);
memcpy(lll->crc_init, si->crc_init, sizeof(lll->crc_init)); memcpy(lll->crc_init, si->crc_init, sizeof(lll->crc_init));
@ -528,7 +540,9 @@ void ull_sync_setup(struct ll_scan_set *scan, struct ll_scan_aux_set *aux,
sync_handle = ull_sync_handle_get(sync); sync_handle = ull_sync_handle_get(sync);
/* Prepare and dispatch sync notification */ /* Prepare sync notification, dispatch only on successful AUX_SYNC_IND
* reception.
*/
rx = (void *)sync->node_rx_sync_estab; rx = (void *)sync->node_rx_sync_estab;
rx->hdr.type = NODE_RX_TYPE_SYNC; rx->hdr.type = NODE_RX_TYPE_SYNC;
rx->hdr.handle = sync_handle; rx->hdr.handle = sync_handle;

View file

@ -21,6 +21,16 @@ struct ll_sync_set {
uint16_t volatile timeout_reload; /* Non-zero when sync established */ uint16_t volatile timeout_reload; /* Non-zero when sync established */
uint16_t timeout_expire; uint16_t timeout_expire;
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
/* TODO: Use for same peer check too */
uint8_t peer_id_addr[BDADDR_SIZE];
uint8_t peer_id_addr_type:1;
#endif
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_ADI_SUPPORT)
uint8_t nodups:1;
#endif
#if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \ #if defined(CONFIG_BT_CTLR_SYNC_PERIODIC_CTE_TYPE_FILTERING) && \
!defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT) !defined(CONFIG_BT_CTLR_CTEINLINE_SUPPORT)
/* Member used to notify event done handler to terminate sync scanning. /* Member used to notify event done handler to terminate sync scanning.