1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/net_buf.h>
9 #include <zephyr/bluetooth/mesh.h>
10 #include <stdlib.h>
11 
12 #include "settings.h"
13 #include "brg_cfg.h"
14 #include "foundation.h"
15 
16 #define TEST_VECT_SZ (CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX + 1)
17 
18 static struct test_brg_cfg_row {
19 	uint8_t direction;
20 	uint16_t net_idx1;
21 	uint16_t net_idx2;
22 	uint16_t addr1;
23 	uint16_t addr2;
24 } test_vector[TEST_VECT_SZ];
25 
26 #define ADDR1_BASE (1)
27 #define ADDR2_BASE (100)
28 
29 /**** Helper functions ****/
setup(void * f)30 static void setup(void *f)
31 {
32 	/* create test vector */
33 	for (int i = 0; i < TEST_VECT_SZ; i++) {
34 		test_vector[i].direction = i < (TEST_VECT_SZ / 2) ? 1 : 2;
35 		test_vector[i].net_idx1 = (i / 8);
36 		test_vector[i].addr1 = ADDR1_BASE + i;
37 		test_vector[i].net_idx2 = (i / 8) + 16;
38 		test_vector[i].addr2 = ADDR2_BASE + i;
39 	}
40 }
41 
42 /**** Mocked functions ****/
43 
bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)44 void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
45 {
46 	ztest_check_expected_value(flag);
47 }
48 
settings_save_one(const char * name,const void * value,size_t val_len)49 int settings_save_one(const char *name, const void *value, size_t val_len)
50 {
51 	ztest_check_expected_data(name, strlen(name));
52 	ztest_check_expected_value(val_len);
53 	ztest_check_expected_data(value, val_len);
54 	return 0;
55 }
56 
settings_delete(const char * name)57 int settings_delete(const char *name)
58 {
59 	ztest_check_expected_data(name, strlen(name));
60 	return 0;
61 }
62 
bt_mesh_subnet_get(uint16_t net_idx)63 struct bt_mesh_subnet *bt_mesh_subnet_get(uint16_t net_idx)
64 {
65 	/* Return anything non-zero. */
66 	return (struct bt_mesh_subnet *)1;
67 }
68 
69 /**** Mocked functions - end ****/
70 
check_fill_all_bt_entries(void)71 static void check_fill_all_bt_entries(void)
72 {
73 	uint8_t status;
74 	int err;
75 
76 	for (int i = 0; i < TEST_VECT_SZ; i++) {
77 
78 		if (i < CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX) {
79 			ztest_expect_value(bt_mesh_settings_store_schedule, flag,
80 					   BT_MESH_SETTINGS_BRG_PENDING);
81 		}
82 
83 		err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction, test_vector[i].net_idx1,
84 					      test_vector[i].net_idx2, test_vector[i].addr1,
85 					      test_vector[i].addr2, &status);
86 
87 		zassert_equal(err, 0);
88 
89 		if (i != CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX) {
90 			zassert_equal(status, STATUS_SUCCESS);
91 		} else {
92 			zassert_equal(status, STATUS_INSUFF_RESOURCES);
93 		}
94 	}
95 }
96 
check_delete_all_bt_entries(void)97 static void check_delete_all_bt_entries(void)
98 {
99 	uint8_t status;
100 
101 	for (int i = 0; i < TEST_VECT_SZ; i++) {
102 
103 		if (i < CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX) {
104 			ztest_expect_value(bt_mesh_settings_store_schedule, flag,
105 					   BT_MESH_SETTINGS_BRG_PENDING);
106 		}
107 
108 		int err = bt_mesh_brg_cfg_tbl_remove(test_vector[i].net_idx1,
109 						     test_vector[i].net_idx2, test_vector[i].addr1,
110 						     test_vector[i].addr2, &status);
111 
112 		zassert_equal(err, 0);
113 		zassert_equal(status, STATUS_SUCCESS);
114 	}
115 }
116 
check_bt_mesh_brg_cfg_tbl_reset(void)117 static void check_bt_mesh_brg_cfg_tbl_reset(void)
118 {
119 	int err;
120 
121 	ztest_expect_data(settings_delete, name, "bt/mesh/brg_en");
122 	ztest_expect_data(settings_delete, name, "bt/mesh/brg_tbl");
123 	err = bt_mesh_brg_cfg_tbl_reset();
124 	zassert_equal(err, 0);
125 }
126 
127 /**** Tests ****/
128 
129 ZTEST_SUITE(bt_mesh_brg_cfg, NULL, NULL, setup, NULL, NULL);
130 
131 /* Test if basic functionality (add and remove entries) works correctly. */
ZTEST(bt_mesh_brg_cfg,test_basic_functionality_storage)132 ZTEST(bt_mesh_brg_cfg, test_basic_functionality_storage)
133 {
134 	check_bt_mesh_brg_cfg_tbl_reset();
135 
136 	/* Test add entries to bridging table. */
137 	check_fill_all_bt_entries();
138 
139 	/* Test remove entries from bridging table, and then fill it again. */
140 	check_delete_all_bt_entries();
141 	check_fill_all_bt_entries();
142 
143 	/* Test resetting of the table, and then fill it again. */
144 	check_bt_mesh_brg_cfg_tbl_reset();
145 	check_fill_all_bt_entries();
146 
147 	uint8_t status;
148 	int err;
149 	uint16_t net_idx1 = test_vector[TEST_VECT_SZ - 1].net_idx1;
150 	uint16_t net_idx2 = test_vector[TEST_VECT_SZ - 1].net_idx2;
151 	uint16_t addr1 = BT_MESH_ADDR_UNASSIGNED;
152 
153 	/* Try removing entries with invalid params */
154 	uint16_t addr2 = BT_MESH_ADDR_ALL_NODES;
155 
156 	err = bt_mesh_brg_cfg_tbl_remove(net_idx1, net_idx2, addr1, addr2, &status);
157 	zassert_equal(err, -EINVAL);
158 
159 	addr2 = BT_MESH_ADDR_UNASSIGNED;
160 	addr1 = BT_MESH_ADDR_RELAYS;
161 	err = bt_mesh_brg_cfg_tbl_remove(net_idx1, net_idx2, addr1, addr2, &status);
162 	zassert_equal(err, -EINVAL);
163 
164 	addr1 = BT_MESH_ADDR_UNASSIGNED;
165 	net_idx1 = 4096;
166 	err = bt_mesh_brg_cfg_tbl_remove(net_idx1, net_idx2, addr1, addr2, &status);
167 	zassert_equal(err, -EINVAL);
168 
169 	net_idx1 = test_vector[TEST_VECT_SZ - 1].net_idx1;
170 	net_idx2 = 4096;
171 	err = bt_mesh_brg_cfg_tbl_remove(net_idx1, net_idx2, addr1, addr2, &status);
172 	zassert_equal(err, -EINVAL);
173 
174 	/* Test remove entries matching netkey1, and netkey2 */
175 	net_idx2 = test_vector[TEST_VECT_SZ - 1].net_idx2;
176 	err = bt_mesh_brg_cfg_tbl_remove(net_idx1, net_idx2, addr1, addr2, &status);
177 	zassert_equal(err, 0);
178 
179 	const struct bt_mesh_brg_cfg_row *brg_tbl;
180 	int n = bt_mesh_brg_cfg_tbl_get(&brg_tbl);
181 
182 	zassert_true(n > 0);
183 
184 	for (int i = 0; i < n; i++) {
185 		zassert_true(brg_tbl[i].net_idx1 != net_idx1);
186 		zassert_true(brg_tbl[i].net_idx2 != net_idx2);
187 	}
188 
189 	check_bt_mesh_brg_cfg_tbl_reset();
190 	check_fill_all_bt_entries();
191 
192 	/* Test remove entries matching netkey1, and netkey2, and addr1 */
193 	addr1 = test_vector[TEST_VECT_SZ - 1].addr1;
194 	n = bt_mesh_brg_cfg_tbl_get(&brg_tbl);
195 
196 	zassert_true(n > 0);
197 
198 	for (int i = 0; i < n; i++) {
199 		zassert_true(brg_tbl[i].net_idx1 != net_idx1);
200 		zassert_true(brg_tbl[i].net_idx2 != net_idx2);
201 		zassert_true(brg_tbl[i].addr1 != addr1);
202 	}
203 
204 	check_bt_mesh_brg_cfg_tbl_reset();
205 	check_fill_all_bt_entries();
206 
207 	/* Test remove entries matching netkey1, and netkey2, and addr2 */
208 	addr1 = BT_MESH_ADDR_UNASSIGNED;
209 	addr2 = test_vector[TEST_VECT_SZ - 1].addr2;
210 	n = bt_mesh_brg_cfg_tbl_get(&brg_tbl);
211 
212 	zassert_true(n > 0);
213 
214 	for (int i = 0; i < n; i++) {
215 		zassert_true(brg_tbl[i].net_idx1 != net_idx1);
216 		zassert_true(brg_tbl[i].net_idx2 != net_idx2);
217 		zassert_true(brg_tbl[i].addr2 != addr2);
218 	}
219 }
220 
check_bt_mesh_brg_cfg_tbl_multiple_delete(int expect_left)221 static void check_bt_mesh_brg_cfg_tbl_multiple_delete(int expect_left)
222 {
223 	uint8_t status;
224 	int err;
225 	int n;
226 	const struct bt_mesh_brg_cfg_row *brg_tbl;
227 
228 	n = bt_mesh_brg_cfg_tbl_get(&brg_tbl);
229 	zassert_equal(n, TEST_VECT_SZ - 1);
230 
231 	ztest_expect_value(bt_mesh_settings_store_schedule, flag, BT_MESH_SETTINGS_BRG_PENDING);
232 	err = bt_mesh_brg_cfg_tbl_remove(test_vector[1].net_idx1, test_vector[1].net_idx2,
233 					 test_vector[1].addr1, BT_MESH_ADDR_UNASSIGNED, &status);
234 	zassert_equal(err, 0);
235 
236 	n = bt_mesh_brg_cfg_tbl_get(&brg_tbl);
237 	zassert_equal(n, expect_left);
238 
239 	for (int i = 0; i < n; i++) {
240 		zassert_true(brg_tbl[i].net_idx1 == test_vector[0].net_idx1);
241 		zassert_true(brg_tbl[i].net_idx2 == test_vector[0].net_idx2);
242 		zassert_true(brg_tbl[i].addr1 == test_vector[0].addr1);
243 		zassert_true(brg_tbl[i].addr2 == test_vector[i * 2].addr2);
244 	}
245 }
246 
ZTEST(bt_mesh_brg_cfg,test_removal_multiple_entries)247 ZTEST(bt_mesh_brg_cfg, test_removal_multiple_entries)
248 {
249 	check_bt_mesh_brg_cfg_tbl_reset();
250 
251 	uint8_t status;
252 	int err;
253 
254 	/* Test removal of every second entry */
255 	for (int i = 0; i < TEST_VECT_SZ - 1; i++) {
256 		ztest_expect_value(bt_mesh_settings_store_schedule, flag,
257 				   BT_MESH_SETTINGS_BRG_PENDING);
258 		err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction, test_vector[i % 2].net_idx1,
259 					      test_vector[i % 2].net_idx2, test_vector[i % 2].addr1,
260 					      test_vector[i].addr2, &status);
261 		zassert_equal(err, 0);
262 		zassert_equal(status, STATUS_SUCCESS);
263 	}
264 
265 	check_bt_mesh_brg_cfg_tbl_multiple_delete((TEST_VECT_SZ - 1) / 2);
266 	check_bt_mesh_brg_cfg_tbl_reset();
267 
268 	/* Test removal of all entries, except first */
269 	for (int i = 0; i < TEST_VECT_SZ - 1; i++) {
270 		ztest_expect_value(bt_mesh_settings_store_schedule, flag,
271 				   BT_MESH_SETTINGS_BRG_PENDING);
272 		if (i == 0) {
273 			err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction,
274 						      test_vector[i].net_idx1,
275 						      test_vector[i].net_idx2, test_vector[i].addr1,
276 						      test_vector[i].addr2, &status);
277 		} else {
278 			err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction,
279 						      test_vector[1].net_idx1,
280 						      test_vector[1].net_idx2, test_vector[1].addr1,
281 						      test_vector[i].addr2, &status);
282 		}
283 		zassert_equal(err, 0);
284 		zassert_equal(status, STATUS_SUCCESS);
285 	}
286 
287 	check_bt_mesh_brg_cfg_tbl_multiple_delete(1);
288 	check_bt_mesh_brg_cfg_tbl_reset();
289 
290 	/* Test removal of all entries, except last */
291 	for (int i = TEST_VECT_SZ - 2; i >= 0; i--) {
292 		ztest_expect_value(bt_mesh_settings_store_schedule, flag,
293 				   BT_MESH_SETTINGS_BRG_PENDING);
294 		if (i == 0) {
295 			err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction,
296 						      test_vector[i].net_idx1,
297 						      test_vector[i].net_idx2, test_vector[i].addr1,
298 						      test_vector[i].addr2, &status);
299 		} else {
300 			err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction,
301 						      test_vector[1].net_idx1,
302 						      test_vector[1].net_idx2, test_vector[1].addr1,
303 						      test_vector[i].addr2, &status);
304 		}
305 		zassert_equal(err, 0);
306 		zassert_equal(status, STATUS_SUCCESS);
307 	}
308 
309 	check_bt_mesh_brg_cfg_tbl_multiple_delete(1);
310 	check_bt_mesh_brg_cfg_tbl_reset();
311 
312 	/* Test removal of all entries */
313 	for (int i = 0; i < TEST_VECT_SZ - 1; i++) {
314 		ztest_expect_value(bt_mesh_settings_store_schedule, flag,
315 				   BT_MESH_SETTINGS_BRG_PENDING);
316 		err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction, test_vector[1].net_idx1,
317 					      test_vector[1].net_idx2, test_vector[1].addr1,
318 					      test_vector[i].addr2, &status);
319 		zassert_equal(err, 0);
320 		zassert_equal(status, STATUS_SUCCESS);
321 	}
322 
323 	check_bt_mesh_brg_cfg_tbl_multiple_delete(0);
324 }
325 
pending_store_enable_create_expectations(bool * enable_val)326 static void pending_store_enable_create_expectations(bool *enable_val)
327 {
328 	if (*enable_val) {
329 		ztest_expect_data(settings_save_one, name, "bt/mesh/brg_en");
330 		ztest_expect_value(settings_save_one, val_len, 1);
331 		ztest_expect_data(settings_save_one, value, enable_val);
332 	} else {
333 		ztest_expect_data(settings_delete, name, "bt/mesh/brg_en");
334 	}
335 }
336 
pending_store_tbl_create_expectations(int n,const struct bt_mesh_brg_cfg_row * tbl_val)337 static void pending_store_tbl_create_expectations(int n, const struct bt_mesh_brg_cfg_row *tbl_val)
338 {
339 	if (n > 0) {
340 		ztest_expect_data(settings_save_one, name, "bt/mesh/brg_tbl");
341 		ztest_expect_value(settings_save_one, val_len,
342 				   n * sizeof(struct bt_mesh_brg_cfg_row));
343 		ztest_expect_data(settings_save_one, value, tbl_val);
344 	} else {
345 		ztest_expect_data(settings_delete, name, "bt/mesh/brg_tbl");
346 	}
347 }
348 
349 /* Test if enable flag is stored correctly. */
ZTEST(bt_mesh_brg_cfg,test_brg_cfg_en)350 ZTEST(bt_mesh_brg_cfg, test_brg_cfg_en)
351 {
352 	int err;
353 	bool val;
354 
355 	check_bt_mesh_brg_cfg_tbl_reset();
356 	val = bt_mesh_brg_cfg_enable_get();
357 	zassert_equal(val, false, NULL);
358 	/* No changed to the states, nothing to check. */
359 
360 	ztest_expect_value(bt_mesh_settings_store_schedule, flag, BT_MESH_SETTINGS_BRG_PENDING);
361 	err = bt_mesh_brg_cfg_enable_set(true);
362 	zassert_equal(err, 0, NULL);
363 	val = bt_mesh_brg_cfg_enable_get();
364 	pending_store_enable_create_expectations(&val);
365 	bt_mesh_brg_cfg_pending_store();
366 
367 	zassert_equal(bt_mesh_brg_cfg_enable_get(), true, NULL);
368 }
369 
370 /* Test if pending store works correctly by adding one entry to the table. */
ZTEST(bt_mesh_brg_cfg,test_brg_tbl_pending_store)371 ZTEST(bt_mesh_brg_cfg, test_brg_tbl_pending_store)
372 {
373 	uint8_t status;
374 	int n, err;
375 	struct bt_mesh_brg_cfg_row test_vec = {
376 		.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
377 		.net_idx1 = 1,
378 		.net_idx2 = 2,
379 		.addr1 = 3,
380 		.addr2 = 4,
381 	};
382 
383 	check_bt_mesh_brg_cfg_tbl_reset();
384 	ztest_expect_value(bt_mesh_settings_store_schedule, flag, BT_MESH_SETTINGS_BRG_PENDING);
385 	err = bt_mesh_brg_cfg_tbl_add(test_vec.direction, test_vec.net_idx1, test_vec.net_idx2,
386 				      test_vec.addr1, test_vec.addr2, &status);
387 	zassert_equal(err, 0);
388 	zassert_equal(status, STATUS_SUCCESS);
389 
390 	const struct bt_mesh_brg_cfg_row *tbl;
391 
392 	n = bt_mesh_brg_cfg_tbl_get(&tbl);
393 
394 	zassert_equal(n, 1);
395 	zassert_true(tbl);
396 
397 	pending_store_tbl_create_expectations(1, &test_vec);
398 	bt_mesh_brg_cfg_pending_store();
399 }
400 
401 /* Value is prohibited. */
402 #define BT_MESH_BRG_CFG_DIR_PROHIBITED 0
403 /* Values above and including this is prohibited. */
404 #define BT_MESH_BRG_CFG_DIR_MAX 3
405 
406 /* Test if invalid entries are not added to the table. */
ZTEST(bt_mesh_brg_cfg,test_tbl_add_invalid_ip)407 ZTEST(bt_mesh_brg_cfg, test_tbl_add_invalid_ip)
408 {
409 	uint8_t status;
410 	int err;
411 	/* Create test vector array of test_brg_cfg_row iteams with invalid values.
412 	 * Each vector has only one invalid field value, rest all are valid values.
413 	 */
414 	const struct test_brg_cfg_row inv_test_vector[] = {
415 		/* Direction has invalid values */
416 		{.direction = BT_MESH_BRG_CFG_DIR_PROHIBITED,
417 		 .net_idx1 = 0,
418 		 .net_idx2 = 1,
419 		 .addr1 = 1,
420 		 .addr2 = 2},
421 		{.direction = BT_MESH_BRG_CFG_DIR_MAX,
422 		 .net_idx1 = 0,
423 		 .net_idx2 = 1,
424 		 .addr1 = 1,
425 		 .addr2 = 2},
426 		/* Out of range netidx values */
427 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
428 		 .net_idx1 = 4096,
429 		 .net_idx2 = 1,
430 		 .addr1 = 1,
431 		 .addr2 = 2},
432 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
433 		 .net_idx1 = 0,
434 		 .net_idx2 = 4096,
435 		 .addr1 = 1,
436 		 .addr2 = 2},
437 		/* Same netidx values */
438 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
439 		 .net_idx1 = 0,
440 		 .net_idx2 = 0,
441 		 .addr1 = 1,
442 		 .addr2 = 2},
443 		/* Same addr values */
444 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
445 		 .net_idx1 = 0,
446 		 .net_idx2 = 1,
447 		 .addr1 = 1,
448 		 .addr2 = 1},
449 		/* Invalid address1 value */
450 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
451 		 .net_idx1 = 0,
452 		 .net_idx2 = 1,
453 		 .addr1 = 0,
454 		 .addr2 = 1},
455 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
456 		 .net_idx1 = 0,
457 		 .net_idx2 = 1,
458 		 .addr1 = 0x8000,
459 		 .addr2 = 1},
460 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
461 		 .net_idx1 = 0,
462 		 .net_idx2 = 1,
463 		 .addr1 = 0xC000,
464 		 .addr2 = 1},
465 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
466 		 .net_idx1 = 0,
467 		 .net_idx2 = 1,
468 		 .addr1 = 0xFFFE,
469 		 .addr2 = 1},
470 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
471 		 .net_idx1 = 0,
472 		 .net_idx2 = 1,
473 		 .addr1 = 0xFFFF,
474 		 .addr2 = 1},
475 		/* Invalid address2 values */
476 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
477 		 .net_idx1 = 0,
478 		 .net_idx2 = 1,
479 		 .addr1 = 1,
480 		 .addr2 = 0},
481 		{.direction = BT_MESH_BRG_CFG_DIR_ONEWAY,
482 		 .net_idx1 = 0,
483 		 .net_idx2 = 1,
484 		 .addr1 = 1,
485 		 .addr2 = 0xFFFF},
486 		{.direction = BT_MESH_BRG_CFG_DIR_TWOWAY,
487 		 .net_idx1 = 0,
488 		 .net_idx2 = 1,
489 		 .addr1 = 1,
490 		 .addr2 = 0x8000},
491 		{.direction = BT_MESH_BRG_CFG_DIR_TWOWAY,
492 		 .net_idx1 = 0,
493 		 .net_idx2 = 1,
494 		 .addr1 = 1,
495 		 .addr2 = 0xC000},
496 		{.direction = BT_MESH_BRG_CFG_DIR_TWOWAY,
497 		 .net_idx1 = 0,
498 		 .net_idx2 = 1,
499 		 .addr1 = 1,
500 		 .addr2 = 0xFFFE},
501 		{.direction = BT_MESH_BRG_CFG_DIR_TWOWAY,
502 		 .net_idx1 = 0,
503 		 .net_idx2 = 1,
504 		 .addr1 = 1,
505 		 .addr2 = 0xFFFF},
506 	};
507 
508 	check_bt_mesh_brg_cfg_tbl_reset();
509 
510 	for (int i = 0; i < ARRAY_SIZE(inv_test_vector); i++) {
511 		err = bt_mesh_brg_cfg_tbl_add(inv_test_vector[i].direction,
512 					      inv_test_vector[i].net_idx1,
513 					      inv_test_vector[i].net_idx2, inv_test_vector[i].addr1,
514 					      inv_test_vector[i].addr2, &status);
515 		zassert_equal(err, -EINVAL, "Test vector index: %zu", i);
516 	}
517 }
518 
519 /* Following are helper functions for the test that checks the iteration logic */
520 #define NUM_MSGS (10000)
521 
print_brg_tbl(void)522 static void print_brg_tbl(void)
523 {
524 	const struct bt_mesh_brg_cfg_row *tbl;
525 	int n = bt_mesh_brg_cfg_tbl_get(&tbl);
526 
527 	zassert_true(n <= CONFIG_BT_MESH_BRG_TABLE_ITEMS_MAX);
528 
529 	for (int i = 0; i < n; i++) {
530 		printk("entry: %3d # dir: %d, net_idx1: %3d, addr1: %3d, net_idx2: %3d, addr2: "
531 		       "%3d\n",
532 		       i, tbl[i].direction, tbl[i].net_idx1, tbl[i].addr1, tbl[i].net_idx2,
533 		       tbl[i].addr2);
534 	}
535 }
536 
check_fill_all_bt_entries_reversed(void)537 static void check_fill_all_bt_entries_reversed(void)
538 {
539 	uint8_t status;
540 	int err;
541 
542 	for (int i = TEST_VECT_SZ - 2; i >= 0; i--) {
543 		ztest_expect_value(bt_mesh_settings_store_schedule, flag,
544 				   BT_MESH_SETTINGS_BRG_PENDING);
545 		err = bt_mesh_brg_cfg_tbl_add(test_vector[i].direction, test_vector[i].net_idx1,
546 					      test_vector[i].net_idx2, test_vector[i].addr1,
547 					      test_vector[i].addr2, &status);
548 		zassert_equal(err, 0);
549 	}
550 
551 	int last = TEST_VECT_SZ - 1;
552 
553 	err = bt_mesh_brg_cfg_tbl_add(test_vector[last].direction, test_vector[last].net_idx1,
554 				      test_vector[last].net_idx2, test_vector[last].addr1,
555 				      test_vector[last].addr2, &status);
556 	zassert_equal(err, 0);
557 	zassert_equal(status, STATUS_INSUFF_RESOURCES);
558 }
559 
560 static struct test_brg_cfg_row test_vector_copy[TEST_VECT_SZ - 1];
561 
check_fill_all_bt_entries_randomly(void)562 static void check_fill_all_bt_entries_randomly(void)
563 {
564 	uint8_t status;
565 	int err;
566 	int copy_cnt = ARRAY_SIZE(test_vector_copy);
567 
568 	memcpy(test_vector_copy, test_vector, sizeof(test_vector_copy));
569 
570 	for (int i = 0; i < copy_cnt; i++) {
571 		int idx = rand() % copy_cnt;
572 		struct test_brg_cfg_row tmp = test_vector_copy[i];
573 
574 		test_vector_copy[i] = test_vector_copy[idx];
575 		test_vector_copy[idx] = tmp;
576 	}
577 
578 	for (int i = 0; i < copy_cnt; i++) {
579 		ztest_expect_value(bt_mesh_settings_store_schedule, flag,
580 				   BT_MESH_SETTINGS_BRG_PENDING);
581 		err = bt_mesh_brg_cfg_tbl_add(
582 			test_vector_copy[i].direction, test_vector_copy[i].net_idx1,
583 			test_vector_copy[i].net_idx2, test_vector_copy[i].addr1,
584 			test_vector_copy[i].addr2, &status);
585 		zassert_equal(err, 0);
586 		zassert_equal(status, STATUS_SUCCESS);
587 	}
588 
589 	int last = TEST_VECT_SZ - 1;
590 
591 	err = bt_mesh_brg_cfg_tbl_add(test_vector[last].direction, test_vector[last].net_idx1,
592 				      test_vector[last].net_idx2, test_vector[last].addr1,
593 				      test_vector[last].addr2, &status);
594 	zassert_equal(err, 0);
595 	zassert_equal(status, STATUS_INSUFF_RESOURCES);
596 }
597 
subnet_relay_cb_check(uint16_t new_net_idx,void * user_data)598 static void subnet_relay_cb_check(uint16_t new_net_idx, void *user_data)
599 {
600 	int idx = *(int *)user_data;
601 
602 	zassert_equal(new_net_idx, test_vector[idx].net_idx2);
603 }
604 
subnet_relay_cb_check_rev(uint16_t new_net_idx,void * user_data)605 static void subnet_relay_cb_check_rev(uint16_t new_net_idx, void *user_data)
606 {
607 	int idx = *(int *)user_data;
608 
609 	if (test_vector[idx].direction == 2) {
610 		zassert_equal(new_net_idx, test_vector[idx].net_idx1);
611 	} else {
612 		/* Should never assert. Test vector created in setup(). */
613 		zassert_true(false);
614 	}
615 }
616 
test_bridging_performance(bool test_one_way)617 static void test_bridging_performance(bool test_one_way)
618 {
619 	int idx;
620 	uint32_t tick1;
621 	uint32_t ticks = 0;
622 
623 	for (int i = 0; i < NUM_MSGS; i++) {
624 		/* randomly pick an entry from the test vector */
625 		idx = rand() % TEST_VECT_SZ;
626 
627 		/* check src to dst bridging*/
628 		const struct bt_mesh_brg_cfg_row *tbl_row = NULL;
629 
630 		tick1 = k_uptime_ticks();
631 		bt_mesh_brg_cfg_tbl_foreach_subnet(test_vector[idx].addr1, test_vector[idx].addr2,
632 						   test_vector[idx].net_idx1, subnet_relay_cb_check,
633 						   &idx);
634 		ticks += k_uptime_ticks() - tick1;
635 
636 		if (test_one_way) {
637 			continue;
638 		}
639 
640 		/* check dst to src bridging - for the same test vector src-dst pairs
641 		 * but now, reverse them and consider packets are arriving on net_idx2
642 		 */
643 		tbl_row = NULL;
644 		tick1 = k_uptime_ticks();
645 		bt_mesh_brg_cfg_tbl_foreach_subnet(test_vector[idx].addr2, test_vector[idx].addr1,
646 						   test_vector[idx].net_idx2,
647 						   subnet_relay_cb_check_rev, &idx);
648 		ticks += k_uptime_ticks() - tick1;
649 	}
650 	printk("ticks: %8u  us: %u\n", ticks, k_ticks_to_us_floor32(ticks));
651 }
652 
653 /* Test checks iteration logic and performance when run on real devices. */
ZTEST(bt_mesh_brg_cfg,test_zcheck_entry_randomly_sorting)654 ZTEST(bt_mesh_brg_cfg, test_zcheck_entry_randomly_sorting)
655 {
656 	printk("num msgs: %d\n\n", NUM_MSGS);
657 
658 	/* Test performance when packets are flowing in one directions */
659 	/* Fill bridging table in sorted order */
660 	printk("\n\nPackets going only in one direction (from outside towards the subnet)\n");
661 	printk("\nBridging table is pre-filled in sorted order\n");
662 
663 	check_bt_mesh_brg_cfg_tbl_reset();
664 	check_fill_all_bt_entries();
665 	print_brg_tbl();
666 	test_bridging_performance(true);
667 
668 	/* Fill bridging table in reversed order */
669 	printk("\nBridging table is pre-filled in reversed order\n");
670 
671 	check_bt_mesh_brg_cfg_tbl_reset();
672 	check_fill_all_bt_entries_reversed();
673 	print_brg_tbl();
674 	test_bridging_performance(true);
675 
676 	/* Fill bridging table in random order */
677 	printk("\nBridging table is pre-filled in random order\n");
678 
679 	check_bt_mesh_brg_cfg_tbl_reset();
680 	check_fill_all_bt_entries_randomly();
681 	print_brg_tbl();
682 	test_bridging_performance(true);
683 
684 	/* Test performance when packets are flowing in both directions - use same dataset. */
685 	printk("\n\nPackets going in both directions (same data set, flip src and dst pairs)\n");
686 	printk("\nBridging table is pre-filled in sorted order\n");
687 
688 	check_bt_mesh_brg_cfg_tbl_reset();
689 	check_fill_all_bt_entries();
690 	print_brg_tbl();
691 	test_bridging_performance(false);
692 
693 	/* Fill bridging table in reversed order */
694 	printk("\nBridging table is pre-filled in reversed order\n");
695 
696 	check_bt_mesh_brg_cfg_tbl_reset();
697 	check_fill_all_bt_entries_reversed();
698 	print_brg_tbl();
699 	test_bridging_performance(false);
700 
701 	/* Fill bridging table in random order */
702 	printk("\nBridging table is pre-filled in random order\n");
703 
704 	check_bt_mesh_brg_cfg_tbl_reset();
705 	check_fill_all_bt_entries_randomly();
706 	print_brg_tbl();
707 	test_bridging_performance(false);
708 }
709