/* * Copyright (c) 2023 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include "bs_bt_utils.h" #include #include #include #include #define EXPECTED_NUM_ROTATIONS 5 struct adv_set_data_t { bt_addr_le_t old_addr; int64_t old_time; int rpa_rotations; bool addr_set; }; static uint8_t adv_index; static struct adv_set_data_t adv_set_data[CONFIG_BT_EXT_ADV_MAX_ADV_SET]; static bool data_cb(struct bt_data *data, void *user_data) { switch (data->type) { case BT_DATA_MANUFACTURER_DATA: adv_index = data->data[0]; return false; default: return true; } } static void validate_rpa_addr_generated_for_adv_sets(void) { for (int i = 0; i < CONFIG_BT_EXT_ADV_MAX_ADV_SET; i++) { if (!adv_set_data[i].addr_set) { return; } } /* First two adv sets have same address as they use same ID and third adv set use diff ID */ if (!bt_addr_le_eq(&adv_set_data[0].old_addr, &adv_set_data[1].old_addr)) { FAIL("RPA not same for adv sets with same id\n"); } if (bt_addr_le_eq(&adv_set_data[0].old_addr, &adv_set_data[3].old_addr)) { FAIL("RPA same for adv sets with different id's\n"); } if (bt_addr_le_eq(&adv_set_data[1].old_addr, &adv_set_data[3].old_addr)) { FAIL("RPA same for adv sets with different id's\n"); } adv_set_data[0].addr_set = false; adv_set_data[1].addr_set = false; adv_set_data[2].addr_set = false; } static void test_address(bt_addr_le_t *addr) { int64_t diff_ms, rpa_timeout_ms; /* Only save the address + time if this is the first scan */ if (bt_addr_le_eq(&adv_set_data[adv_index].old_addr, BT_ADDR_LE_ANY)) { bt_addr_le_copy(&adv_set_data[adv_index].old_addr, addr); adv_set_data[adv_index].old_time = k_uptime_get(); return; } /* Compare old and new address */ if (bt_addr_le_eq(&adv_set_data[adv_index].old_addr, addr)) { return; } adv_set_data[adv_index].addr_set = true; printk("Ad set %d Old ", adv_index); print_address(&adv_set_data[adv_index].old_addr); printk("Ad set %d New ", adv_index); print_address(addr); adv_set_data[adv_index].rpa_rotations++; /* Ensure the RPA rotation occurs within +-10% of CONFIG_BT_RPA_TIMEOUT */ diff_ms = k_uptime_get() - adv_set_data[adv_index].old_time; rpa_timeout_ms = CONFIG_BT_RPA_TIMEOUT * MSEC_PER_SEC; if (abs(diff_ms - rpa_timeout_ms) > (rpa_timeout_ms / 10)) { FAIL("RPA rotation did not occur within +-10%% of CONFIG_BT_RPA_TIMEOUT\n"); } bt_addr_le_copy(&adv_set_data[adv_index].old_addr, addr); adv_set_data[adv_index].old_time = k_uptime_get(); validate_rpa_addr_generated_for_adv_sets(); if (adv_set_data[adv_index].rpa_rotations > EXPECTED_NUM_ROTATIONS) { PASS("PASS\n"); } } static void cb_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad) { bt_data_parse(ad, data_cb, NULL); test_address((bt_addr_le_t *)addr); } void start_scanning(void) { /* Start passive scanning */ struct bt_le_scan_param scan_param = { .type = BT_HCI_LE_SCAN_PASSIVE, .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE, .interval = 0x0040, .window = 0x0020, }; int err = bt_le_scan_start(&scan_param, cb_device_found); if (err) { FAIL("Failed to start scanning"); } } void tester_procedure(void) { /* Enable bluetooth */ int err = bt_enable(NULL); if (err) { FAIL("Failed to enable bluetooth (err %d\n)", err); } start_scanning(); /* The rest of the test is driven by the callback */ }