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>
This commit is contained in:
Carles Cufi 2017-04-04 12:54:56 +02:00 committed by Johan Hedberg
commit 27e83660ff
3 changed files with 105 additions and 6 deletions

View file

@ -82,6 +82,14 @@ config BLUETOOTH_CONTROLLER_RX_PRIO_STACK_SIZE
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

View file

@ -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 @@ static void reset(struct net_buf *buf, struct net_buf **evt)
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 @@ static void le_set_scan_enable(struct net_buf *buf, struct net_buf **evt)
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 @@ static void le_advertising_report(struct pdu_data *pdu_data, uint8_t *b,
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);

View file

@ -566,11 +566,20 @@ static int cmd_init(int argc, char *argv[])
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(&param, device_found);
if (err) {
printk("Bluetooth set active scan failed (err %d)\n", err);
} else {
@ -578,7 +587,7 @@ static void cmd_active_scan_on(void)
}
}
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 @@ static void cmd_passive_scan_on(void)
.window = 0x10 };
int err;
if (dups >= 0) {
param.filter_dup = dups;
}
err = bt_le_scan_start(&param, device_found);
if (err) {
printk("Bluetooth set passive scan failed (err %d)\n", err);
@ -610,18 +623,32 @@ static void cmd_scan_off(void)
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 int cmd_bredr_sdp_find_record(int argc, char *argv[])
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 },