Bluetooth: Add support for rotating RPA

If privacy is enabled we always use RPA, even for active scan.
This makes single point of controlling current random address
making code simple and not prone to subtle bugs with concurent
advertising, scanning and connecting.

Currently used RPA is rotated to improve privacy. Timeout value is
controlled by Kconfig and by default is 900 seconds (15 minutes).

Change-Id: I27a15666a4f2e2962cf6eb20c7cd06f90b7f2bb1
Signed-off-by: Szymon Janc <ext.szymon.janc@tieto.com>
This commit is contained in:
Szymon Janc 2016-07-19 11:55:21 +02:00 committed by Johan Hedberg
commit a0a52691f2
10 changed files with 97 additions and 31 deletions

View file

@ -182,6 +182,15 @@ config BLUETOOTH_PRIVACY
Enable local Privacy Feature support. This makes it possible Enable local Privacy Feature support. This makes it possible
to use Resolvable Private Addresses (RPAs). to use Resolvable Private Addresses (RPAs).
config BLUETOOTH_RPA_TIMEOUT
int "Resolvable Private Address timeout"
depends on BLUETOOTH_PRIVACY
default 900
range 1 65535
help
This option defines how often resolvable private address is rotated.
Value is provided in seconds and defaults to 900 seconds (15 minutes).
config BLUETOOTH_SIGNING config BLUETOOTH_SIGNING
bool "Data signing support" bool "Data signing support"
default n default n

View file

@ -25,6 +25,7 @@
#include <atomic.h> #include <atomic.h>
#include <misc/byteorder.h> #include <misc/byteorder.h>
#include <misc/util.h> #include <misc/util.h>
#include <misc/nano_work.h>
#include <bluetooth/log.h> #include <bluetooth/log.h>
#include <bluetooth/hci.h> #include <bluetooth/hci.h>

View file

@ -25,6 +25,7 @@
#include <atomic.h> #include <atomic.h>
#include <misc/byteorder.h> #include <misc/byteorder.h>
#include <misc/util.h> #include <misc/util.h>
#include <misc/nano_work.h>
#include <bluetooth/log.h> #include <bluetooth/log.h>
#include <bluetooth/hci.h> #include <bluetooth/hci.h>

View file

@ -24,6 +24,7 @@
#include <atomic.h> #include <atomic.h>
#include <misc/byteorder.h> #include <misc/byteorder.h>
#include <misc/util.h> #include <misc/util.h>
#include <misc/nano_work.h>
#include <bluetooth/log.h> #include <bluetooth/log.h>
#include <bluetooth/hci.h> #include <bluetooth/hci.h>

View file

@ -27,6 +27,7 @@
#include <misc/util.h> #include <misc/util.h>
#include <misc/byteorder.h> #include <misc/byteorder.h>
#include <misc/stack.h> #include <misc/stack.h>
#include <misc/nano_work.h>
#ifdef CONFIG_MICROKERNEL #ifdef CONFIG_MICROKERNEL
#include <microkernel.h> #include <microkernel.h>
@ -61,6 +62,7 @@
/* Peripheral timeout to initialize Connection Parameter Update procedure */ /* Peripheral timeout to initialize Connection Parameter Update procedure */
#define CONN_UPDATE_TIMEOUT (5 * sys_clock_ticks_per_sec) #define CONN_UPDATE_TIMEOUT (5 * sys_clock_ticks_per_sec)
#define RPA_TIMEOUT (CONFIG_BLUETOOTH_RPA_TIMEOUT * sys_clock_ticks_per_sec)
/* Stacks for the fibers */ /* Stacks for the fibers */
static BT_STACK_NOINIT(rx_fiber_stack, CONFIG_BLUETOOTH_RX_STACK_SIZE); static BT_STACK_NOINIT(rx_fiber_stack, CONFIG_BLUETOOTH_RX_STACK_SIZE);
@ -433,6 +435,67 @@ static int set_random_address(const bt_addr_t *addr)
return 0; return 0;
} }
#if defined(CONFIG_BLUETOOTH_PRIVACY)
/* this function sets new RPA only if current one is no longer valid */
static int le_set_rpa(void)
{
bt_addr_t rpa;
int err;
/* work is not idle so current RPA is valid */
if (!atomic_test_bit(bt_dev.rpa_update.work.flags,
NANO_WORK_STATE_IDLE)) {
return 0;
}
err = bt_smp_create_rpa(bt_dev.irk, &rpa);
if (!err) {
err = set_random_address(&rpa);
}
/* restart timer even if failed to set new RPA */
nano_delayed_work_submit(&bt_dev.rpa_update, RPA_TIMEOUT);
return err;
}
static void rpa_timeout(struct nano_work *work)
{
BT_DBG("");
/*
* we need to update rpa only if advertising is ongoing, with
* BT_DEV_KEEP_ADVERTISING flag is handled in disconnected event
*/
if (atomic_test_bit(bt_dev.flags, BT_DEV_ADVERTISING)) {
/* make sure new address is used */
set_advertise_disable();
le_set_rpa();
set_advertise_enable();
}
if (atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN)) {
/* TODO do we need to toggle scan? */
le_set_rpa();
}
}
#else
static int le_set_nrpa(void)
{
bt_addr_t nrpa;
int err;
err = bt_rand(nrpa.val, sizeof(nrpa.val));
if (err) {
return err;
}
nrpa.val[5] &= 0x3f;
return set_random_address(&nrpa);
}
#endif
#if defined(CONFIG_BLUETOOTH_CONN) #if defined(CONFIG_BLUETOOTH_CONN)
static void hci_acl(struct net_buf *buf) static void hci_acl(struct net_buf *buf)
{ {
@ -588,6 +651,9 @@ static void hci_disconn_complete(struct net_buf *buf)
advertise: advertise:
if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) { if (atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) {
#if defined(CONFIG_BLUETOOTH_PRIVACY)
le_set_rpa();
#endif
set_advertise_enable(); set_advertise_enable();
} }
} }
@ -851,21 +917,6 @@ static void le_conn_update_complete(struct net_buf *buf)
bt_conn_unref(conn); bt_conn_unref(conn);
} }
#if defined(CONFIG_BLUETOOTH_PRIVACY)
static int le_set_rpa(void)
{
bt_addr_t rpa;
int err;
err = bt_smp_create_rpa(bt_dev.irk, &rpa);
if (err) {
return err;
}
return set_random_address(&rpa);
}
#endif
static void check_pending_conn(const bt_addr_le_t *id_addr, static void check_pending_conn(const bt_addr_le_t *id_addr,
const bt_addr_le_t *addr, uint8_t evtype) const bt_addr_le_t *addr, uint8_t evtype)
{ {
@ -2313,21 +2364,6 @@ int bt_rand(void *buf, size_t len)
return -EIO; return -EIO;
} }
static int le_set_nrpa(void)
{
bt_addr_t nrpa;
int err;
err = bt_rand(nrpa.val, sizeof(nrpa.val));
if (err) {
return err;
}
nrpa.val[5] &= 0x3f;
return set_random_address(&nrpa);
}
static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window, static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window,
uint8_t filter_dup) uint8_t filter_dup)
{ {
@ -2354,6 +2390,13 @@ static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window,
set_param->filter_policy = 0x00; set_param->filter_policy = 0x00;
if (scan_type == BT_HCI_LE_SCAN_ACTIVE) { if (scan_type == BT_HCI_LE_SCAN_ACTIVE) {
#if defined(CONFIG_BLUETOOTH_PRIVACY)
err = le_set_rpa();
if (err) {
net_buf_unref(buf);
return err;
}
#else
/* only set NRPA if there is no advertising ongoing */ /* only set NRPA if there is no advertising ongoing */
if (!atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) { if (!atomic_test_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING)) {
err = le_set_nrpa(); err = le_set_nrpa();
@ -2362,6 +2405,7 @@ static int start_le_scan(uint8_t scan_type, uint16_t interval, uint16_t window,
return err; return err;
} }
} }
#endif
set_param->addr_type = BT_ADDR_LE_RANDOM; set_param->addr_type = BT_ADDR_LE_RANDOM;
} else { } else {
@ -3313,6 +3357,8 @@ static int bt_init(void)
if (err) { if (err) {
return err; return err;
} }
nano_delayed_work_init(&bt_dev.rpa_update, rpa_timeout);
#endif #endif
bt_monitor_send(BT_MONITOR_OPEN_INDEX, NULL, 0); bt_monitor_send(BT_MONITOR_OPEN_INDEX, NULL, 0);
@ -3603,11 +3649,12 @@ int bt_le_adv_stop(void)
atomic_clear_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING); atomic_clear_bit(bt_dev.flags, BT_DEV_KEEP_ADVERTISING);
#if !defined(CONFIG_BLUETOOTH_PRIVACY)
/* If active scan is ongoing set NRPA */ /* If active scan is ongoing set NRPA */
if (atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN)) { if (atomic_test_bit(bt_dev.flags, BT_DEV_ACTIVE_SCAN)) {
le_set_nrpa(); le_set_nrpa();
} }
#endif
return 0; return 0;
} }

View file

@ -116,6 +116,9 @@ struct bt_dev {
#if defined(CONFIG_BLUETOOTH_PRIVACY) #if defined(CONFIG_BLUETOOTH_PRIVACY)
/* Local Identity Resolving Key */ /* Local Identity Resolving Key */
uint8_t irk[16]; uint8_t irk[16];
/* Work used for RPA rotation */
struct nano_delayed_work rpa_update;
#endif #endif
}; };

View file

@ -23,6 +23,7 @@
#include <atomic.h> #include <atomic.h>
#include <microkernel/task.h> #include <microkernel/task.h>
#include <misc/byteorder.h> #include <misc/byteorder.h>
#include <misc/nano_work.h>
#include <tinycrypt/utils.h> #include <tinycrypt/utils.h>
#include <tinycrypt/ecc.h> #include <tinycrypt/ecc.h>
#include <tinycrypt/ecc_dh.h> #include <tinycrypt/ecc_dh.h>

View file

@ -20,6 +20,7 @@
#include <nanokernel.h> #include <nanokernel.h>
#include <atomic.h> #include <atomic.h>
#include <misc/util.h> #include <misc/util.h>
#include <misc/nano_work.h>
#include <bluetooth/log.h> #include <bluetooth/log.h>
#include <bluetooth/bluetooth.h> #include <bluetooth/bluetooth.h>

View file

@ -24,6 +24,7 @@
#include <atomic.h> #include <atomic.h>
#include <misc/byteorder.h> #include <misc/byteorder.h>
#include <misc/util.h> #include <misc/util.h>
#include <misc/nano_work.h>
#include <bluetooth/log.h> #include <bluetooth/log.h>
#include <bluetooth/hci.h> #include <bluetooth/hci.h>

View file

@ -24,6 +24,7 @@
#include <atomic.h> #include <atomic.h>
#include <misc/byteorder.h> #include <misc/byteorder.h>
#include <misc/util.h> #include <misc/util.h>
#include <misc/nano_work.h>
#include <bluetooth/log.h> #include <bluetooth/log.h>
#include <bluetooth/hci.h> #include <bluetooth/hci.h>