From 17c006ce4ac8bcb4be25f0c0863ea37873d93c5d Mon Sep 17 00:00:00 2001 From: Vinayak Kariappa Chettimada Date: Fri, 20 Nov 2020 19:26:31 +0530 Subject: [PATCH] Bluetooth: controller: Add extended scan filter duplicates Added implementation to filter out duplicates in generated extended advertising reports. Signed-off-by: Vinayak Kariappa Chettimada --- subsys/bluetooth/controller/hci/hci.c | 115 +++++++++++++++++++++----- 1 file changed, 94 insertions(+), 21 deletions(-) diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c index 15740153dc0..a5fc3a8e1b6 100644 --- a/subsys/bluetooth/controller/hci/hci.c +++ b/subsys/bluetooth/controller/hci/hci.c @@ -68,8 +68,14 @@ static uint16_t _opcode; #if CONFIG_BT_CTLR_DUP_FILTER_LEN > 0 /* Scan duplicate filter */ struct dup { - uint8_t mask; + 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 (dup_filter[i].mask & BIT(adv->type)) { - /* duplicate found */ - return true; - } - /* report different adv types */ - dup_filter[i].mask |= BIT(adv->type); - return false; + if (memcmp(addr, &dup_filter[i].addr.a.val[0], + sizeof(bt_addr_t)) || + (addr_type != dup_filter[i].addr.type)) { + continue; } + + /* 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. */