Bluetooth: controller: Add extended scan filter duplicates

Added implementation to filter out duplicates in generated
extended advertising reports.

Signed-off-by: Vinayak Kariappa Chettimada <vich@nordicsemi.no>
This commit is contained in:
Vinayak Kariappa Chettimada 2020-11-20 19:26:31 +05:30 committed by Carles Cufí
commit 17c006ce4a

View file

@ -70,6 +70,12 @@ static uint16_t _opcode;
struct dup {
uint8_t mask;
bt_addr_le_t addr;
#if defined(CONFIG_BT_CTLR_ADV_EXT)
uint8_t adv_mode:2;
uint8_t data_cmplt:1;
struct pdu_adv_adi adi;
#endif
};
static struct dup dup_filter[CONFIG_BT_CTLR_DUP_FILTER_LEN];
static int32_t dup_count;
@ -4078,33 +4084,90 @@ int hci_acl_handle(struct net_buf *buf, struct net_buf **evt)
#endif /* CONFIG_BT_CONN */
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
static inline bool dup_found(struct pdu_adv *adv)
#if defined(CONFIG_BT_CTLR_ADV_EXT)
static void store_adi(int i, struct pdu_adv_adi *adi)
{
if (adi) {
memcpy(&dup_filter[i].adi, adi, sizeof(*adi));
} else {
memset(&dup_filter[i].adi, 0, sizeof(*adi));
}
}
#endif /* CONFIG_BT_CTLR_ADV_EXT */
static inline bool is_dup_or_update(int i, uint8_t adv_type, uint8_t adv_mode,
struct pdu_adv_adi *adi,
uint8_t data_status)
{
if (!(dup_filter[i].mask & BIT(adv_type))) {
/* report different adv types */
dup_filter[i].mask |= BIT(adv_type);
#if defined(CONFIG_BT_CTLR_ADV_EXT)
dup_filter[i].adv_mode = adv_mode;
dup_filter[i].data_cmplt = !data_status;
store_adi(i, adi);
return false;
} else if (dup_filter[i].adv_mode != adv_mode) {
/* report different adv mode */
dup_filter[i].adv_mode = adv_mode;
dup_filter[i].data_cmplt = !data_status;
store_adi(i, adi);
return false;
} else if (adi && ((dup_filter[i].adi.sid != adi->sid) ||
(dup_filter[i].adi.did != adi->did))) {
/* report different adi */
store_adi(i, adi);
dup_filter[i].data_cmplt = !data_status;
return false;
} else if (!dup_filter[i].data_cmplt && !data_status) {
/* report data complete */
dup_filter[i].data_cmplt = !data_status;
#endif /* CONFIG_BT_CTLR_ADV_EXT */
return false;
}
return true;
}
static bool dup_found(uint8_t adv_type, uint8_t addr_type, uint8_t *addr,
uint8_t adv_mode, struct pdu_adv_adi *adi,
uint8_t data_status)
{
/* check for duplicate filtering */
if (dup_count >= 0) {
int i;
/* find for existing entry and update if changed */
for (i = 0; i < dup_count; i++) {
if (!memcmp(&adv->adv_ind.addr[0],
&dup_filter[i].addr.a.val[0],
sizeof(bt_addr_t)) &&
adv->tx_addr == dup_filter[i].addr.type) {
if (memcmp(addr, &dup_filter[i].addr.a.val[0],
sizeof(bt_addr_t)) ||
(addr_type != dup_filter[i].addr.type)) {
continue;
}
if (dup_filter[i].mask & BIT(adv->type)) {
/* duplicate found */
return true;
}
/* report different adv types */
dup_filter[i].mask |= BIT(adv->type);
return false;
}
/* still duplicate or update entry with change */
return is_dup_or_update(i, adv_type, adv_mode, adi,
data_status);
}
/* insert into the duplicate filter */
memcpy(&dup_filter[dup_curr].addr.a.val[0],
&adv->adv_ind.addr[0], sizeof(bt_addr_t));
dup_filter[dup_curr].addr.type = adv->tx_addr;
dup_filter[dup_curr].mask = BIT(adv->type);
memcpy(&dup_filter[dup_curr].addr.a.val[0], addr,
sizeof(bt_addr_t));
dup_filter[dup_curr].addr.type = addr_type;
dup_filter[dup_curr].mask = BIT(adv_type);
#if defined(CONFIG_BT_CTLR_ADV_EXT)
dup_filter[dup_curr].adv_mode = adv_mode;
dup_filter[i].data_cmplt = !data_status;
store_adi(dup_curr, adi);
#endif /* CONFIG_BT_CTLR_ADV_EXT */
if (dup_count < CONFIG_BT_CTLR_DUP_FILTER_LEN) {
dup_count++;
@ -4137,7 +4200,7 @@ static inline void le_dir_adv_report(struct pdu_adv *adv, struct net_buf *buf,
LL_ASSERT(adv->type == PDU_ADV_TYPE_DIRECT_IND);
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (dup_found(adv)) {
if (dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) {
return;
}
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -4291,7 +4354,7 @@ static void le_advertising_report(struct pdu_data *pdu_data,
}
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (dup_found(adv)) {
if (dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) {
return;
}
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -4401,7 +4464,7 @@ static void le_ext_adv_legacy_report(struct pdu_data *pdu_data,
#endif /* CONFIG_BT_CTLR_PRIVACY */
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (dup_found(adv)) {
if (dup_found(adv->type, adv->tx_addr, adv->adv_ind.addr, 0, NULL, 0)) {
return;
}
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
@ -4726,6 +4789,16 @@ no_ext_hdr:
adv = (void *)node_rx_curr->pdu;
} while (1);
#if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0
if (adv_addr) {
if (dup_found(PDU_ADV_TYPE_EXT_IND, adv_addr_type, adv_addr,
evt_type, adi, data_status)) {
node_rx_extra_list_release(node_rx->hdr.rx_ftr.extra);
return;
}
}
#endif /* CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 */
/* FIXME: move most of below into above loop to dispatch fragments of
* data in HCI event.
*/