1 /*
2  * Copyright (c) 2022 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include <zephyr/bluetooth/addr.h>
9 #include <host/keys.h>
10 #include "mocks/conn.h"
11 #include "mocks/hci_core.h"
12 #include "mocks/keys_help_utils.h"
13 #include "mocks/hci_core_expects.h"
14 #include "testing_common_defs.h"
15 
16 /* This LUT contains different combinations of ID and Address pairs */
17 extern const struct id_addr_pair testing_id_addr_pair_lut[CONFIG_BT_MAX_PAIRED];
18 
19 /* This list holds returned references while filling keys pool */
20 extern struct bt_keys *returned_keys_refs[CONFIG_BT_MAX_PAIRED];
21 
22 /* Pointer to the current set of oldest testing parameter */
23 struct id_addr_pair const *oldest_params_vector;
24 
bt_unpair_custom_fake(uint8_t id,const bt_addr_le_t * addr)25 static int bt_unpair_custom_fake(uint8_t id, const bt_addr_le_t *addr)
26 {
27 	struct bt_keys *keys = NULL;
28 
29 	/* Find the key slot with matched id and address */
30 	keys = bt_keys_find_addr(id, addr);
31 	if (keys) {
32 		bt_keys_clear(keys);
33 	}
34 
35 	/* This check is used here because bt_unpair() is called with a local variable address */
36 	expect_single_call_bt_unpair(oldest_params_vector->id, oldest_params_vector->addr);
37 
38 	return 0;
39 }
40 
bt_unpair_unreachable_custom_fake(uint8_t id,const bt_addr_le_t * addr)41 static int bt_unpair_unreachable_custom_fake(uint8_t id, const bt_addr_le_t *addr)
42 {
43 	ARG_UNUSED(id);
44 	ARG_UNUSED(addr);
45 	zassert_unreachable("Unexpected call to 'bt_unpair()' occurred");
46 	return 0;
47 }
48 
bt_conn_foreach_key_slot_0_in_use_custom_fake(enum bt_conn_type type,bt_conn_foreach_cb func,void * data)49 static void bt_conn_foreach_key_slot_0_in_use_custom_fake(enum bt_conn_type type,
50 							  bt_conn_foreach_cb func, void *data)
51 {
52 	struct bt_conn conn;
53 
54 	/* This will make the effect as if there is a disconnection */
55 	conn.state = BT_CONN_DISCONNECTED;
56 	conn.id = 0x9E;
57 	func(&conn, data);
58 
59 	/* This will make the effect as if there is a connection with no key */
60 	conn.state = BT_CONN_CONNECTED;
61 	conn.id = 0xFF;
62 	bt_addr_le_copy(&conn.le.dst, (const bt_addr_le_t *)BT_ADDR_LE_ANY);
63 	bt_conn_get_dst_fake.return_val = &conn.le.dst;
64 	func(&conn, data);
65 
66 	/* This will make the effect as if key at slot 0 is in use with a connection */
67 	conn.state = BT_CONN_CONNECTED;
68 	conn.id = testing_id_addr_pair_lut[0].id;
69 	bt_addr_le_copy(&conn.le.dst, testing_id_addr_pair_lut[0].addr);
70 	bt_conn_get_dst_fake.return_val = &conn.le.dst;
71 	func(&conn, data);
72 }
73 
bt_conn_foreach_all_keys_in_use_custom_fake(enum bt_conn_type type,bt_conn_foreach_cb func,void * data)74 static void bt_conn_foreach_all_keys_in_use_custom_fake(enum bt_conn_type type,
75 							bt_conn_foreach_cb func, void *data)
76 {
77 	struct bt_conn conn;
78 
79 	/* This will make the effect as if key at slot 'x' is in use with a connection */
80 	for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_pair_lut); i++) {
81 		conn.state = BT_CONN_CONNECTED;
82 		conn.id = testing_id_addr_pair_lut[i].id;
83 		bt_addr_le_copy(&conn.le.dst, testing_id_addr_pair_lut[i].addr);
84 		bt_conn_get_dst_fake.return_val = &conn.le.dst;
85 		func(&conn, data);
86 	}
87 }
88 
bt_conn_foreach_no_keys_in_use_custom_fake(enum bt_conn_type type,bt_conn_foreach_cb func,void * data)89 static void bt_conn_foreach_no_keys_in_use_custom_fake(enum bt_conn_type type,
90 						       bt_conn_foreach_cb func, void *data)
91 {
92 	struct bt_conn conn;
93 
94 	/* This will make the effect as if key at slot 'x' is in use with a connection */
95 	for (size_t i = 0; i < ARRAY_SIZE(testing_id_addr_pair_lut); i++) {
96 		conn.state = BT_CONN_DISCONNECTED;
97 		conn.id = testing_id_addr_pair_lut[i].id;
98 		bt_addr_le_copy(&conn.le.dst, testing_id_addr_pair_lut[i].addr);
99 		bt_conn_get_dst_fake.return_val = &conn.le.dst;
100 		func(&conn, data);
101 	}
102 }
103 
104 /* Setup test variables */
test_case_setup(void * f)105 static void test_case_setup(void *f)
106 {
107 	Z_TEST_SKIP_IFNDEF(CONFIG_BT_KEYS_OVERWRITE_OLDEST);
108 
109 	clear_key_pool();
110 
111 	int rv = fill_key_pool_by_id_addr(testing_id_addr_pair_lut,
112 					  ARRAY_SIZE(testing_id_addr_pair_lut), returned_keys_refs);
113 
114 	zassert_true(rv == 0, "Failed to fill keys pool list, error code %d", -rv);
115 }
116 
117 ZTEST_SUITE(bt_keys_get_addr_full_list_overwrite_oldest, NULL, NULL, test_case_setup, NULL, NULL);
118 
119 /*
120  *  Test adding extra (ID, Address) pair while the keys pool list is full while all keys are in
121  *  use with connections so that no more (ID, Address) pairs can be added.
122  *
123  *  Constraints:
124  *   - Keys pool list is full
125  *   - All Keys are used with a connection
126  *   - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled
127  *
128  *  Expected behaviour:
129  *   - NULL pointer is returned as there is no room
130  */
ZTEST(bt_keys_get_addr_full_list_overwrite_oldest,test_full_list_all_keys_in_use)131 ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_all_keys_in_use)
132 {
133 	struct bt_keys *returned_key;
134 	uint8_t id = BT_ADDR_ID_3;
135 	bt_addr_le_t *addr = BT_ADDR_LE_3;
136 
137 	bt_unpair_fake.custom_fake = bt_unpair_unreachable_custom_fake;
138 	bt_conn_foreach_fake.custom_fake = bt_conn_foreach_all_keys_in_use_custom_fake;
139 
140 	returned_key = bt_keys_get_addr(id, addr);
141 
142 	zassert_true(returned_key == NULL, "bt_keys_get_addr() returned a non-NULL reference");
143 }
144 
145 /*
146  *  Test adding extra (ID, Address) pair while the keys pool list is full, but no keys are used with
147  *  connections. New (ID, Address) pairs can be added by replacing the oldest pair.
148  *
149  *  Constraints:
150  *   - Keys pool list is full
151  *   - All Keys are not used with a connection
152  *   - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled
153  *
154  *  Expected behaviour:
155  *   - A valid pointer in the keys pool is returned, matching the one previously assigned to the
156  *     oldest key (index 0).
157  */
ZTEST(bt_keys_get_addr_full_list_overwrite_oldest,test_full_list_no_keys_in_use)158 ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_no_keys_in_use)
159 {
160 	struct bt_keys *returned_key;
161 	uint8_t id = BT_ADDR_ID_3;
162 	bt_addr_le_t *addr = BT_ADDR_LE_3;
163 	uint32_t expected_oldest_params_ref_idx;
164 
165 	expected_oldest_params_ref_idx = 0;
166 	oldest_params_vector = &testing_id_addr_pair_lut[expected_oldest_params_ref_idx];
167 	bt_unpair_fake.custom_fake = bt_unpair_custom_fake;
168 	bt_conn_foreach_fake.custom_fake = bt_conn_foreach_no_keys_in_use_custom_fake;
169 
170 	returned_key = bt_keys_get_addr(id, addr);
171 
172 	zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a NULL reference");
173 	zassert_true(returned_key == returned_keys_refs[expected_oldest_params_ref_idx],
174 		     "bt_keys_get_addr() returned reference doesn't match expected one");
175 }
176 
177 /*
178  *  Test adding extra (ID, Address) pair while the keys pool list is full when the oldest key slot
179  *  is in use with a connection but others keys aren't.
180  *  New (ID, address) pair should replace the oldest one that's not in use.
181  *
182  *  Constraints:
183  *   - Keys pool list is full
184  *   - Oldest key at slot 0 is used with a connection
185  *   - Next oldest key (slot 1) isn't used with a connection
186  *   - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled
187  *
188  *  Expected behaviour:
189  *   - A valid pointer in the keys pool is returned, matching the one previously assigned to the
190  *     oldest key (index 1).
191  */
ZTEST(bt_keys_get_addr_full_list_overwrite_oldest,test_full_list_key_0_in_use_key_1_oldest)192 ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_key_0_in_use_key_1_oldest)
193 {
194 	struct bt_keys *returned_key;
195 	uint8_t id = BT_ADDR_ID_4;
196 	bt_addr_le_t *addr = BT_ADDR_LE_4;
197 	uint32_t expected_oldest_params_ref_idx;
198 
199 	expected_oldest_params_ref_idx = 1;
200 	oldest_params_vector = &testing_id_addr_pair_lut[expected_oldest_params_ref_idx];
201 	bt_unpair_fake.custom_fake = bt_unpair_custom_fake;
202 	bt_conn_foreach_fake.custom_fake = bt_conn_foreach_key_slot_0_in_use_custom_fake;
203 
204 	returned_key = bt_keys_get_addr(id, addr);
205 
206 	zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a NULL reference");
207 	zassert_true(returned_key == returned_keys_refs[expected_oldest_params_ref_idx],
208 		     "bt_keys_get_addr() returned reference doesn't match expected one");
209 }
210 
211 /*
212  *  Test adding extra (ID, Address) pair while the keys pool list is full when the oldest key slot
213  *  is in use with a connection but others keys aren't.
214  *  New (ID, address) pair should replace the oldest one that's not in use.
215  *
216  *  Constraints:
217  *   - Keys pool list is full
218  *   - Key at slot 0 is used with a connection
219  *   - oldest key (slot 2) isn't used with a connection
220  *   - CONFIG_BT_KEYS_OVERWRITE_OLDEST is enabled
221  *
222  *  Expected behaviour:
223  *   - A valid pointer in the keys pool is returned, matching the one previously assigned to the
224  *     oldest key (index 2).
225  */
ZTEST(bt_keys_get_addr_full_list_overwrite_oldest,test_full_list_key_0_in_use_key_2_oldest)226 ZTEST(bt_keys_get_addr_full_list_overwrite_oldest, test_full_list_key_0_in_use_key_2_oldest)
227 {
228 	struct bt_keys *returned_key;
229 	uint8_t id = BT_ADDR_ID_5;
230 	bt_addr_le_t *addr = BT_ADDR_LE_5;
231 	uint32_t expected_oldest_params_ref_idx;
232 
233 #if defined(CONFIG_BT_KEYS_OVERWRITE_OLDEST)
234 	/* Normally first items inserted in the list are the oldest.
235 	 * For this particular test, we need to override that by setting
236 	 * the 'aging_counter'
237 	 */
238 	returned_keys_refs[1]->aging_counter = bt_keys_get_aging_counter_val();
239 #endif
240 
241 	expected_oldest_params_ref_idx = 2;
242 	oldest_params_vector = &testing_id_addr_pair_lut[expected_oldest_params_ref_idx];
243 	bt_unpair_fake.custom_fake = bt_unpair_custom_fake;
244 	bt_conn_foreach_fake.custom_fake = bt_conn_foreach_key_slot_0_in_use_custom_fake;
245 
246 	returned_key = bt_keys_get_addr(id, addr);
247 
248 	zassert_true(returned_key != NULL, "bt_keys_get_addr() returned a NULL reference");
249 	zassert_true(returned_key == returned_keys_refs[expected_oldest_params_ref_idx],
250 		     "bt_keys_get_addr() returned reference doesn't match expected one");
251 }
252