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