bluetooth: add api for changing rpa timeout in runtime

Added a new Bluetooth API and Kconfig option for overriding the RPA
timeout in runtime.

Signed-off-by: Kamil Piszczek <Kamil.Piszczek@nordicsemi.no>
This commit is contained in:
Kamil Piszczek 2022-07-01 13:28:06 +02:00 committed by Fabio Baltieri
parent 8bdf363c0c
commit 1eb9d36d46
7 changed files with 96 additions and 6 deletions

View file

@ -2021,6 +2021,26 @@ static inline int bt_le_whitelist_clear(void)
*/
int bt_le_set_chan_map(uint8_t chan_map[5]);
/**
* @brief Set the Resolvable Private Address timeout in runtime
*
* The new RPA timeout value will be used for the next RPA rotation
* and all subsequent rotations until another override is scheduled
* with this API.
*
* Initially, the if @kconfig{CONFIG_BT_RPA_TIMEOUT} is used as the
* RPA timeout.
*
* This symbol is linkable if @kconfig{CONFIG_BT_RPA_TIMEOUT_DYNAMIC}
* is enabled.
*
* @param new_rpa_timeout Resolvable Private Address timeout in seconds
*
* @retval 0 Success.
* @retval -EINVAL RPA timeout value is invalid. Valid range is 1s - 3600s.
*/
int bt_le_set_rpa_timeout(uint16_t new_rpa_timeout);
/**
* @brief Helper for parsing advertising (or EIR or OOB) data.
*

View file

@ -350,6 +350,13 @@ config BT_RPA_TIMEOUT
This option defines how often resolvable private address is rotated.
Value is provided in seconds and defaults to 900 seconds (15 minutes).
config BT_RPA_TIMEOUT_DYNAMIC
bool "Support setting the Resolvable Private Address timeout at runtime"
depends on BT_PRIVACY
help
This option allows the user to override the default value of
the Resolvable Private Address timeout using dedicated APIs.
config BT_SIGNING
bool "Data signing support"
help

View file

@ -2492,7 +2492,7 @@ static bool create_param_validate(const struct bt_conn_le_create_param *param)
{
#if defined(CONFIG_BT_PRIVACY)
/* Initiation timeout cannot be greater than the RPA timeout */
const uint32_t timeout_max = (MSEC_PER_SEC / 10) * CONFIG_BT_RPA_TIMEOUT;
const uint32_t timeout_max = (MSEC_PER_SEC / 10) * bt_dev.rpa_timeout;
if (param->timeout > timeout_max) {
return false;

View file

@ -76,6 +76,9 @@ static void init_work(struct k_work *work);
struct bt_dev bt_dev = {
.init = Z_WORK_INITIALIZER(init_work),
#if defined(CONFIG_BT_PRIVACY)
.rpa_timeout = CONFIG_BT_RPA_TIMEOUT,
#endif
#if defined(CONFIG_BT_DEVICE_APPEARANCE_DYNAMIC)
.appearance = CONFIG_BT_DEVICE_APPEARANCE,
#endif
@ -2975,7 +2978,7 @@ static int le_init(void)
}
cp = net_buf_add(buf, sizeof(*cp));
cp->rpa_timeout = sys_cpu_to_le16(CONFIG_BT_RPA_TIMEOUT);
cp->rpa_timeout = sys_cpu_to_le16(bt_dev.rpa_timeout);
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_RPA_TIMEOUT, buf,
NULL);
if (err) {
@ -3933,6 +3936,24 @@ int bt_le_set_chan_map(uint8_t chan_map[5])
buf, NULL);
}
#if defined(CONFIG_BT_RPA_TIMEOUT_DYNAMIC)
int bt_le_set_rpa_timeout(uint16_t new_rpa_timeout)
{
if ((new_rpa_timeout == 0) || (new_rpa_timeout > 3600)) {
return -EINVAL;
}
if (new_rpa_timeout == bt_dev.rpa_timeout) {
return 0;
}
bt_dev.rpa_timeout = new_rpa_timeout;
atomic_set_bit(bt_dev.flags, BT_DEV_RPA_TIMEOUT_CHANGED);
return 0;
}
#endif
void bt_data_parse(struct net_buf_simple *ad,
bool (*func)(struct bt_data *data, void *user_data),
void *user_data)

View file

@ -44,6 +44,7 @@ enum {
BT_DEV_INITIATING,
BT_DEV_RPA_VALID,
BT_DEV_RPA_TIMEOUT_CHANGED,
BT_DEV_ID_PENDING,
BT_DEV_STORE_ID,
@ -358,6 +359,9 @@ struct bt_dev {
/* Work used for RPA rotation */
struct k_work_delayable rpa_update;
/* The RPA timeout value. */
uint16_t rpa_timeout;
#endif
/* Local Name */

View file

@ -6,6 +6,7 @@
*/
#include <zephyr/settings/settings.h>
#include <zephyr/sys/byteorder.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/hci_vs.h>
@ -204,9 +205,47 @@ static void le_rpa_invalidate(void)
}
#if defined(CONFIG_BT_PRIVACY)
#if defined(CONFIG_BT_RPA_TIMEOUT_DYNAMIC)
static void le_rpa_timeout_update(void)
{
int err = 0;
if (atomic_test_and_clear_bit(bt_dev.flags, BT_DEV_RPA_TIMEOUT_CHANGED)) {
struct net_buf *buf;
struct bt_hci_cp_le_set_rpa_timeout *cp;
buf = bt_hci_cmd_create(BT_HCI_OP_LE_SET_RPA_TIMEOUT,
sizeof(*cp));
if (!buf) {
BT_ERR("Failed to create HCI RPA timeout command");
err = -ENOBUFS;
goto submit;
}
cp = net_buf_add(buf, sizeof(*cp));
cp->rpa_timeout = sys_cpu_to_le16(bt_dev.rpa_timeout);
err = bt_hci_cmd_send_sync(BT_HCI_OP_LE_SET_RPA_TIMEOUT, buf, NULL);
if (err) {
BT_ERR("Failed to send HCI RPA timeout command");
goto submit;
}
}
submit:
if (err) {
atomic_set_bit(bt_dev.flags, BT_DEV_RPA_TIMEOUT_CHANGED);
}
}
#endif
static void le_rpa_timeout_submit(void)
{
(void)k_work_schedule(&bt_dev.rpa_update, RPA_TIMEOUT);
#if defined(CONFIG_BT_RPA_TIMEOUT_DYNAMIC)
le_rpa_timeout_update();
#endif
(void)k_work_schedule(&bt_dev.rpa_update, K_SECONDS(bt_dev.rpa_timeout));
}
/* this function sets new RPA only if current one is no longer valid */

View file

@ -5,8 +5,7 @@
* SPDX-License-Identifier: Apache-2.0
*/
#define RPA_TIMEOUT_MS (CONFIG_BT_RPA_TIMEOUT * MSEC_PER_SEC)
#define RPA_TIMEOUT K_MSEC(RPA_TIMEOUT_MS)
#define RPA_TIMEOUT_MS(_rpa_timeout) (_rpa_timeout * MSEC_PER_SEC)
static inline bool bt_id_rpa_is_new(void)
{
@ -16,7 +15,7 @@ static inline bool bt_id_rpa_is_new(void)
/* RPA is considered new if there is less than half a second since the
* timeout was started.
*/
return remaining_ms > (RPA_TIMEOUT_MS - 500);
return remaining_ms > (RPA_TIMEOUT_MS(bt_dev.rpa_timeout) - 500);
#else
return false;
#endif