1 /*
2 * Copyright (c) 2023 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "bs_bt_utils.h"
8 #include <zephyr/bluetooth/addr.h>
9 #include <zephyr/bluetooth/conn.h>
10 #include <stdint.h>
11 #include <zephyr/bluetooth/bluetooth.h>
12 #include <zephyr/settings/settings.h>
13
14 #define EXPECTED_NUM_ROTATIONS 5
15
16 struct adv_set_data_t {
17 bt_addr_le_t old_addr;
18 int64_t old_time;
19 int rpa_rotations;
20 bool addr_set;
21 };
22
23 static uint8_t adv_index;
24 static struct adv_set_data_t adv_set_data[CONFIG_BT_EXT_ADV_MAX_ADV_SET];
25
data_cb(struct bt_data * data,void * user_data)26 static bool data_cb(struct bt_data *data, void *user_data)
27 {
28 switch (data->type) {
29 case BT_DATA_MANUFACTURER_DATA:
30 adv_index = data->data[0];
31 return false;
32 default:
33 return true;
34 }
35 }
36
validate_rpa_addr_generated_for_adv_sets(void)37 static void validate_rpa_addr_generated_for_adv_sets(void)
38 {
39 for (int i = 0; i < CONFIG_BT_EXT_ADV_MAX_ADV_SET; i++) {
40 if (!adv_set_data[i].addr_set) {
41 return;
42 }
43 }
44 if (bt_addr_le_eq(&adv_set_data[0].old_addr, &adv_set_data[1].old_addr)) {
45 /* With RPA sharing mode disabled, the first two adv sets should have
46 * a different address even though they use the same Bluetooth ID.
47 */
48 if (!IS_ENABLED(CONFIG_BT_RPA_SHARING)) {
49 FAIL("RPA same for adv sets with same id and RPA sharing disabled\n");
50 }
51 } else {
52 /* In the RPA sharing mode, the first two adv sets should have
53 * the same address as they use the same Bluetooth ID.
54 */
55 if (IS_ENABLED(CONFIG_BT_RPA_SHARING)) {
56 FAIL("RPA not same for adv sets with same id and RPA sharing enabled\n");
57 }
58 }
59 if (bt_addr_le_eq(&adv_set_data[0].old_addr, &adv_set_data[3].old_addr)) {
60 FAIL("RPA same for adv sets with different id's\n");
61 }
62 if (bt_addr_le_eq(&adv_set_data[1].old_addr, &adv_set_data[3].old_addr)) {
63 FAIL("RPA same for adv sets with different id's\n");
64 }
65 adv_set_data[0].addr_set = false;
66 adv_set_data[1].addr_set = false;
67 adv_set_data[2].addr_set = false;
68 }
69
test_address(bt_addr_le_t * addr)70 static void test_address(bt_addr_le_t *addr)
71 {
72 int64_t diff_ms, rpa_timeout_ms;
73
74 if (!BT_ADDR_IS_RPA(&addr->a)) {
75 FAIL("Bluetooth address is not RPA\n");
76 }
77
78 /* Only save the address + time if this is the first scan */
79 if (bt_addr_le_eq(&adv_set_data[adv_index].old_addr, BT_ADDR_LE_ANY)) {
80 bt_addr_le_copy(&adv_set_data[adv_index].old_addr, addr);
81 adv_set_data[adv_index].old_time = k_uptime_get();
82 return;
83 }
84
85 /* Compare old and new address */
86 if (bt_addr_le_eq(&adv_set_data[adv_index].old_addr, addr)) {
87 return;
88 }
89 adv_set_data[adv_index].addr_set = true;
90 printk("Ad set %d Old ", adv_index);
91 print_address(&adv_set_data[adv_index].old_addr);
92 printk("Ad set %d New ", adv_index);
93 print_address(addr);
94
95 adv_set_data[adv_index].rpa_rotations++;
96
97 /* Ensure the RPA rotation occurs within +-10% of CONFIG_BT_RPA_TIMEOUT */
98 diff_ms = k_uptime_get() - adv_set_data[adv_index].old_time;
99 rpa_timeout_ms = CONFIG_BT_RPA_TIMEOUT * MSEC_PER_SEC;
100
101 if (abs(diff_ms - rpa_timeout_ms) > (rpa_timeout_ms / 10)) {
102 FAIL("RPA rotation did not occur within +-10%% of CONFIG_BT_RPA_TIMEOUT\n");
103 }
104
105 bt_addr_le_copy(&adv_set_data[adv_index].old_addr, addr);
106 adv_set_data[adv_index].old_time = k_uptime_get();
107 validate_rpa_addr_generated_for_adv_sets();
108
109 if (adv_set_data[adv_index].rpa_rotations > EXPECTED_NUM_ROTATIONS) {
110 PASS("PASS\n");
111 }
112 }
113
cb_device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)114 static void cb_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
115 struct net_buf_simple *ad)
116 {
117 bt_data_parse(ad, data_cb, NULL);
118 test_address((bt_addr_le_t *)addr);
119 }
120
start_scanning(void)121 void start_scanning(void)
122 {
123 /* Start passive scanning */
124 struct bt_le_scan_param scan_param = {
125 .type = BT_LE_SCAN_TYPE_PASSIVE,
126 .options = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
127 .interval = 0x0040,
128 .window = 0x0020,
129 };
130
131 int err = bt_le_scan_start(&scan_param, cb_device_found);
132
133 if (err) {
134 FAIL("Failed to start scanning");
135 }
136 }
137
tester_procedure(void)138 void tester_procedure(void)
139 {
140 /* Enable bluetooth */
141 int err = bt_enable(NULL);
142
143 if (err) {
144 FAIL("Failed to enable bluetooth (err %d\n)", err);
145 }
146
147 err = settings_load();
148 if (err) {
149 FAIL("Failed to enable settings (err %d\n)", err);
150 }
151
152 start_scanning();
153
154 /* The rest of the test is driven by the callback */
155 }
156