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 	uint8_t         rpa_rotations;
19 	int64_t			old_time;
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 
test_address(bt_addr_le_t * addr)36 static void test_address(bt_addr_le_t *addr)
37 {
38 	int64_t diff_ms;
39 	static int64_t rpa_timeout_ms = CONFIG_BT_RPA_TIMEOUT * MSEC_PER_SEC;
40 
41 	if (!BT_ADDR_IS_RPA(&addr->a)) {
42 		FAIL("Bluetooth address is not RPA\n");
43 	}
44 
45 	/* Only save the address if this is the first scan */
46 	if (bt_addr_le_eq(&adv_set_data[adv_index].old_addr, BT_ADDR_LE_ANY)) {
47 		bt_addr_le_copy(&adv_set_data[adv_index].old_addr, addr);
48 		adv_set_data[adv_index].old_time = k_uptime_get();
49 		return;
50 	}
51 
52 	diff_ms = k_uptime_get() - adv_set_data[adv_index].old_time;
53 
54 	if (diff_ms < rpa_timeout_ms) {
55 		return;
56 	}
57 
58 	printk("Ad set %d Old ", adv_index);
59 	print_address(&adv_set_data[adv_index].old_addr);
60 	printk("Ad set %d New ", adv_index);
61 	print_address(addr);
62 
63 	/*	For the first 2 rpa rotations, either of the first 2 adv sets returns false.
64 	 *	Hence first 2 adv sets continue with old rpa in first 2 rpa rotations.
65 	 *	For the next 2 rpa rotations, either of the last 2 adv sets returns false.
66 	 *	Hence last 2 adv sets continue with old rpa in next 2 rpa rotations.
67 	 */
68 	if ((adv_set_data[adv_index].rpa_rotations % CONFIG_BT_EXT_ADV_MAX_ADV_SET)  < 2) {
69 
70 		if (adv_index < 2) {
71 			if (!bt_addr_le_eq(addr, &adv_set_data[adv_index].old_addr)) {
72 				FAIL("Adv sets should continue with old rpa\n");
73 			}
74 		} else {
75 			if (bt_addr_le_eq(addr, &adv_set_data[adv_index].old_addr)) {
76 				FAIL("New RPA should have been generated\n");
77 			}
78 		}
79 	} else {
80 		if (adv_index < 2) {
81 			if (bt_addr_le_eq(addr, &adv_set_data[adv_index].old_addr)) {
82 				FAIL("New RPA should have been generated\n");
83 			}
84 		} else {
85 			if (!bt_addr_le_eq(addr, &adv_set_data[adv_index].old_addr)) {
86 				FAIL("Adv sets should continue with old rpa\n");
87 			}
88 		}
89 	}
90 
91 	adv_set_data[adv_index].rpa_rotations++;
92 	if (adv_set_data[adv_index].rpa_rotations > EXPECTED_NUM_ROTATIONS) {
93 		PASS("PASS\n");
94 	}
95 
96 	adv_set_data[adv_index].old_time = k_uptime_get();
97 	bt_addr_le_copy(&adv_set_data[adv_index].old_addr, addr);
98 }
99 
cb_device_found(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)100 static void cb_device_found(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
101 			    struct net_buf_simple *ad)
102 {
103 	bt_data_parse(ad, data_cb, NULL);
104 	test_address((bt_addr_le_t *)addr);
105 }
106 
start_rpa_scanning(void)107 void start_rpa_scanning(void)
108 {
109 	/* Start passive scanning */
110 	struct bt_le_scan_param scan_param = {
111 		.type       = BT_LE_SCAN_TYPE_PASSIVE,
112 		.options    = BT_LE_SCAN_OPT_FILTER_DUPLICATE,
113 		.interval   = 0x0040,
114 		.window     = 0x0020,
115 	};
116 
117 	int err = bt_le_scan_start(&scan_param, cb_device_found);
118 
119 	if (err) {
120 		FAIL("Failed to start scanning");
121 	}
122 }
123 
tester_verify_rpa_procedure(void)124 void tester_verify_rpa_procedure(void)
125 {
126 	/* Enable bluetooth */
127 	int err = bt_enable(NULL);
128 
129 	if (err) {
130 		FAIL("Failed to enable bluetooth (err %d\n)", err);
131 	}
132 
133 	err = settings_load();
134 	if (err) {
135 		FAIL("Failed to enable settings (err %d\n)", err);
136 	}
137 
138 	start_rpa_scanning();
139 	/* The rest of the test is driven by the callback */
140 }
141