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 #include "common/bt_str.h"
14
15 #define EXPECTED_NUM_ROTATIONS 5
16
17 #include <zephyr/logging/log.h>
18 LOG_MODULE_REGISTER(tester, 4);
19
20 struct test_data_t {
21 bool id_addr_ok;
22 bt_addr_le_t old_addr;
23 int64_t old_time;
24 int rpa_rotations;
25 bool addr_set;
26 } static test_data;
27
28 extern bt_addr_le_t dut_addr;
29
print_address(const bt_addr_le_t * addr)30 void print_address(const bt_addr_le_t *addr)
31 {
32 char array[BT_ADDR_LE_STR_LEN];
33
34 bt_addr_le_to_str(addr, array, sizeof(array));
35 LOG_DBG("Address : %s", array);
36 }
37
cb_expect_rpa(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)38 static void cb_expect_rpa(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
39 struct net_buf_simple *ad)
40 {
41 int64_t diff_ms, rpa_timeout_ms;
42
43 if (bt_addr_le_eq(addr, &dut_addr)) {
44 FAIL("DUT used identity addr instead of RPA\n");
45 }
46
47 /* Only save the address + time if this is the first scan */
48 if (bt_addr_le_eq(&test_data.old_addr, BT_ADDR_LE_ANY)) {
49 bt_addr_le_copy(&test_data.old_addr, addr);
50 test_data.old_time = k_uptime_get();
51 return;
52 }
53
54 /* Compare old and new address */
55 if (bt_addr_le_eq(&test_data.old_addr, addr)) {
56 return;
57 }
58 test_data.addr_set = true;
59 LOG_DBG("Old ");
60 print_address(&test_data.old_addr);
61 LOG_DBG("New ");
62 print_address(addr);
63
64 test_data.rpa_rotations++;
65
66 /* Ensure the RPA rotation occurs within +-10% of CONFIG_BT_RPA_TIMEOUT */
67 diff_ms = k_uptime_get() - test_data.old_time;
68 rpa_timeout_ms = CONFIG_BT_RPA_TIMEOUT * MSEC_PER_SEC;
69
70 if (abs(diff_ms - rpa_timeout_ms) > (rpa_timeout_ms / 10)) {
71 FAIL("RPA rotation did not occur within +-10% of CONFIG_BT_RPA_TIMEOUT\n");
72 }
73
74 bt_addr_le_copy(&test_data.old_addr, addr);
75 test_data.old_time = k_uptime_get();
76
77 if (test_data.rpa_rotations > EXPECTED_NUM_ROTATIONS) {
78 PASS("PASS\n");
79 }
80 }
81
cb_expect_id(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)82 static void cb_expect_id(const bt_addr_le_t *addr, int8_t rssi, uint8_t type,
83 struct net_buf_simple *ad)
84 {
85 LOG_DBG("expecting addr:");
86 print_address(&dut_addr);
87 LOG_DBG("got addr:");
88 print_address(addr);
89
90 if (addr->type != BT_ADDR_LE_RANDOM) {
91 FAIL("Expected public address (0x%x) got 0x%x\n",
92 BT_ADDR_LE_RANDOM, addr->type);
93 }
94
95 if (!bt_addr_le_eq(&dut_addr, addr)) {
96 FAIL("DUT not using identity address\n");
97 }
98 }
99
scan_cb(const bt_addr_le_t * addr,int8_t rssi,uint8_t type,struct net_buf_simple * ad)100 static void scan_cb(const bt_addr_le_t *addr, int8_t rssi, uint8_t type, struct net_buf_simple *ad)
101 {
102 /* The DUT advertises with the identity address first, to test
103 * that option, but also to allow the DUT time to start its
104 * scanner. The scanner must be ready to capture the one of
105 * first RPA advertisements to accurately judge the RPA
106 * timeout, which is measured from the first RPA advertisement.
107 */
108 if (!test_data.id_addr_ok) {
109 cb_expect_id(addr, rssi, type, ad);
110
111 /* Tell DUT to switch to RPA */
112 backchannel_sync_send();
113 test_data.id_addr_ok = true;
114 } else {
115 cb_expect_rpa(addr, rssi, type, ad);
116 }
117 }
118
tester_procedure(void)119 void tester_procedure(void)
120 {
121 int err;
122
123 /* open a backchannel to the peer */
124 backchannel_init(PERIPHERAL_SIM_ID);
125
126 err = bt_enable(NULL);
127 if (err) {
128 FAIL("Failed to enable bluetooth (err %d\n)", err);
129 }
130
131 err = bt_le_scan_start(BT_LE_SCAN_PASSIVE_CONTINUOUS, scan_cb);
132
133 if (err) {
134 FAIL("Failed to start scanning\n");
135 }
136 }
137