Bluetooth: controller: Implement scan duplicate filter
Implement the controller's ability to drop duplicate advertising reports
when instructed by the Host.
Jira: ZEP-1246
Change-Id: I2d1b7abf1ed950dde705e5df30a858c595f3834c
Signed-off-by: Carles Cufi <carles.cufi@nordicsemi.no>
diff --git a/subsys/bluetooth/controller/Kconfig b/subsys/bluetooth/controller/Kconfig
index 01fa344..513e8a0 100644
--- a/subsys/bluetooth/controller/Kconfig
+++ b/subsys/bluetooth/controller/Kconfig
@@ -82,6 +82,14 @@
int
default 320
+config BLUETOOTH_CONTROLLER_DUP_FILTER_LEN
+ prompt "Number of addresses in the scan duplicate filter"
+ int
+ default 16
+ help
+ Set the number of unique BLE addresses that can be filtered as
+ duplicates while scanning.
+
comment "BLE Controller features"
config BLUETOOTH_CONTROLLER_LE_PING
diff --git a/subsys/bluetooth/controller/hci/hci.c b/subsys/bluetooth/controller/hci/hci.c
index 76ca6dd..34d8fb2 100644
--- a/subsys/bluetooth/controller/hci/hci.c
+++ b/subsys/bluetooth/controller/hci/hci.c
@@ -35,6 +35,17 @@
*/
static uint16_t _opcode;
+#if CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN > 0
+/* Scan duplicate filter */
+struct dup {
+ uint8_t mask;
+ bt_addr_le_t addr;
+};
+static struct dup dup_filter[CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN];
+static int32_t dup_count;
+static uint32_t dup_curr;
+#endif
+
static void evt_create(struct net_buf *buf, uint8_t evt, uint8_t len)
{
struct bt_hci_evt_hdr *hdr;
@@ -143,6 +154,10 @@
ll_reset();
+#if CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN > 0
+ dup_count = -1;
+#endif
+
ccst = cmd_complete(evt, sizeof(*ccst));
ccst->status = 0x00;
}
@@ -411,6 +426,15 @@
struct bt_hci_evt_cc_status *ccst;
uint32_t status;
+#if CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN > 0
+ /* initialize duplicate filtering */
+ if (cmd->enable && cmd->filter_dup) {
+ dup_count = 0;
+ dup_curr = 0;
+ } else {
+ dup_count = -1;
+ }
+#endif
status = ll_scan_enable(cmd->enable);
ccst = cmd_complete(evt, sizeof(*ccst));
@@ -973,6 +997,46 @@
uint8_t data_len;
uint8_t *rssi;
uint8_t info_len;
+ int i;
+
+#if CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN > 0
+ /* check for duplicate filtering */
+ if (dup_count >= 0) {
+ for (i = 0; i < dup_count; i++) {
+ if (!memcmp(&adv->payload.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;
+ }
+ /* report different adv types */
+ dup_filter[i].mask |= BIT(adv->type);
+ goto fill_report;
+ }
+ }
+
+ /* insert into the duplicate filter */
+ memcpy(&dup_filter[dup_curr].addr.a.val[0],
+ &adv->payload.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);
+
+ if (dup_count < CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN) {
+ dup_count++;
+ dup_curr = dup_count;
+ } else {
+ dup_curr++;
+ }
+
+ if (dup_curr == CONFIG_BLUETOOTH_CONTROLLER_DUP_FILTER_LEN) {
+ dup_curr = 0;
+ }
+ }
+fill_report:
+#endif
if (adv->type != PDU_ADV_TYPE_DIRECT_IND) {
data_len = (adv->len - BDADDR_SIZE);
diff --git a/tests/bluetooth/shell/src/main.c b/tests/bluetooth/shell/src/main.c
index dc04ef9..b5a00a6 100644
--- a/tests/bluetooth/shell/src/main.c
+++ b/tests/bluetooth/shell/src/main.c
@@ -566,11 +566,20 @@
return 0;
}
-static void cmd_active_scan_on(void)
+static void cmd_active_scan_on(int dups)
{
int err;
+ struct bt_le_scan_param param = {
+ .type = BT_HCI_LE_SCAN_PASSIVE,
+ .filter_dup = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE,
+ .interval = BT_GAP_SCAN_FAST_INTERVAL,
+ .window = BT_GAP_SCAN_FAST_WINDOW };
- err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
+ if (dups >= 0) {
+ param.filter_dup = dups;
+ }
+
+ err = bt_le_scan_start(¶m, device_found);
if (err) {
printk("Bluetooth set active scan failed (err %d)\n", err);
} else {
@@ -578,7 +587,7 @@
}
}
-static void cmd_passive_scan_on(void)
+static void cmd_passive_scan_on(int dups)
{
struct bt_le_scan_param param = {
.type = BT_HCI_LE_SCAN_PASSIVE,
@@ -587,6 +596,10 @@
.window = 0x10 };
int err;
+ if (dups >= 0) {
+ param.filter_dup = dups;
+ }
+
err = bt_le_scan_start(¶m, device_found);
if (err) {
printk("Bluetooth set passive scan failed (err %d)\n", err);
@@ -610,18 +623,32 @@
static int cmd_scan(int argc, char *argv[])
{
const char *action;
+ int dups = -1;
if (argc < 2) {
return -EINVAL;
}
+ /* Parse duplicate filtering data */
+ if (argc >= 3) {
+ const char *dup_filter = argv[2];
+
+ if (!strcmp(dup_filter, "dups")) {
+ dups = BT_HCI_LE_SCAN_FILTER_DUP_DISABLE;
+ } else if (!strcmp(dup_filter, "nodups")) {
+ dups = BT_HCI_LE_SCAN_FILTER_DUP_ENABLE;
+ } else {
+ return -EINVAL;
+ }
+ }
+
action = argv[1];
if (!strcmp(action, "on")) {
- cmd_active_scan_on();
+ cmd_active_scan_on(dups);
} else if (!strcmp(action, "off")) {
cmd_scan_off();
} else if (!strcmp(action, "passive")) {
- cmd_passive_scan_on();
+ cmd_passive_scan_on(dups);
} else {
return -EINVAL;
}
@@ -2494,7 +2521,7 @@
static const struct shell_cmd commands[] = {
{ "init", cmd_init, HELP_ADDR_LE },
- { "scan", cmd_scan, "<value: on, off>" },
+ { "scan", cmd_scan, "<value: on, off> <dup filter: dups, nodups>" },
{ "advertise", cmd_advertise,
"<type: off, on, scan, nconn> <mode: discov, non_discov>" },
{ "connect", cmd_connect_le, HELP_ADDR_LE },