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