1 /*
2 * Copyright (c) 2023 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
11 #include "settings.h"
12 #include "net.h"
13 #include "rpl.h"
14
15 #define EMPTY_ENTRIES_CNT (CONFIG_BT_MESH_CRPL - ARRAY_SIZE(test_vector))
16
17 /* Used for cleaning RPL without checking it. */
18 static bool skip_delete;
19
20 /* Test function that should call bt_mesh_rpl_check(). */
21 static enum {
22 SETTINGS_SAVE_ONE = 1,
23 SETTINGS_DELETE
24 } settings_func;
25 /* Number of `settings_func` calls before calling bt_mesh_rpl_check() (1 means first call). */
26 static int settings_func_cnt;
27 /* Received message context. */
28 static struct bt_mesh_net_rx recv_msg;
29
30 /* We will change test vector during the test as it is convenient to do so. Therefore, we need
31 * to keep default values separately.
32 */
33 static const struct test_rpl_entry {
34 char *name;
35 uint16_t src;
36 bool old_iv;
37 uint32_t seq;
38 } test_vector_default[] = {
39 { .name = "bt/mesh/RPL/1", .src = 0x1, .old_iv = false, .seq = 10, },
40 { .name = "bt/mesh/RPL/17", .src = 0x17, .old_iv = true, .seq = 32, },
41 { .name = "bt/mesh/RPL/7c", .src = 0x7c, .old_iv = false, .seq = 20, },
42 { .name = "bt/mesh/RPL/2c", .src = 0x2c, .old_iv = true, .seq = 5, },
43 { .name = "bt/mesh/RPL/5a", .src = 0x5a, .old_iv = true, .seq = 12, },
44 };
45 static struct test_rpl_entry test_vector[ARRAY_SIZE(test_vector_default)];
46
47 /**** Helper functions ****/
48
prepare_rpl_and_start_reset(void)49 static void prepare_rpl_and_start_reset(void)
50 {
51 /* Add test vector to RPL. */
52 for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
53 struct bt_mesh_net_rx msg = {
54 .local_match = true,
55 .ctx.addr = test_vector[i].src,
56 .old_iv = test_vector[i].old_iv,
57 .seq = test_vector[i].seq,
58 };
59
60 ztest_expect_value(bt_mesh_settings_store_schedule, flag,
61 BT_MESH_SETTINGS_RPL_PENDING);
62 zassert_false(bt_mesh_rpl_check(&msg, NULL, false));
63 }
64
65 /* settings_save_one() will be triggered for all new entries when
66 * bt_mesh_rpl_pending_store() is called.
67 */
68 for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
69 ztest_expect_data(settings_save_one, name, test_vector[i].name);
70 }
71 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
72
73 /* Check that all added entries are in RPL. */
74 for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
75 struct bt_mesh_net_rx msg = {
76 .local_match = true,
77 .ctx.addr = test_vector[i].src,
78 .old_iv = test_vector[i].old_iv,
79 .seq = test_vector[i].seq,
80 };
81
82 zassert_true(bt_mesh_rpl_check(&msg, NULL, false));
83 }
84
85 /* Simulate IVI Update. This should only flip flags. The actual storing will happen
86 * when bt_mesh_rpl_pending_store() is called.
87 */
88 ztest_expect_value(bt_mesh_settings_store_schedule, flag, BT_MESH_SETTINGS_RPL_PENDING);
89 bt_mesh_rpl_reset();
90 }
91
92 /* Should be called after the reset operation is finished. */
check_entries_from_test_vector(void)93 static void check_entries_from_test_vector(void)
94 {
95 for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
96 struct bt_mesh_net_rx msg = {
97 .local_match = true,
98 .ctx.addr = test_vector[i].src,
99 /* Entries with old_iv == true should have been deleted. old_iv in entries
100 * is flipped, so to check this we can try to add the removed entries
101 * again. RPL should accept them.
102 */
103 .old_iv = !test_vector[i].old_iv,
104 .seq = test_vector[i].seq
105 };
106
107 /* Removed entries can now be added again. */
108 if (test_vector[i].old_iv) {
109 ztest_expect_value(bt_mesh_settings_store_schedule, flag,
110 BT_MESH_SETTINGS_RPL_PENDING);
111 zassert_false(bt_mesh_rpl_check(&msg, NULL, false));
112 } else {
113 zassert_true(bt_mesh_rpl_check(&msg, NULL, false));
114 }
115 }
116 }
117
check_empty_entries(int cnt)118 static void check_empty_entries(int cnt)
119 {
120 /* Check that RPL has the specified amount of empty entries. */
121 for (int i = 0; i < cnt; i++) {
122 struct bt_mesh_net_rx msg = {
123 .local_match = true,
124 .ctx.addr = 0x7fff - i,
125 .old_iv = false,
126 .seq = i,
127 };
128
129 ztest_expect_value(bt_mesh_settings_store_schedule, flag,
130 BT_MESH_SETTINGS_RPL_PENDING);
131 zassert_false(bt_mesh_rpl_check(&msg, NULL, false));
132 }
133
134 /* Check that there are no more empty entries in RPL. */
135 struct bt_mesh_net_rx msg = {
136 .local_match = true,
137 .ctx.addr = 0x1024,
138 .old_iv = false,
139 .seq = 1024,
140 };
141 zassert_true(bt_mesh_rpl_check(&msg, NULL, false));
142 }
143
check_op(int op)144 static void check_op(int op)
145 {
146 if (settings_func == op) {
147 if (settings_func_cnt > 1) {
148 settings_func_cnt--;
149 } else {
150 ztest_expect_value(bt_mesh_settings_store_schedule, flag,
151 BT_MESH_SETTINGS_RPL_PENDING);
152 zassert_false(bt_mesh_rpl_check(&recv_msg, NULL, false));
153
154 settings_func_cnt--;
155 settings_func = 0;
156 }
157 }
158 }
159
call_rpl_check_on(int func,int cnt,struct test_rpl_entry * entry)160 static void call_rpl_check_on(int func, int cnt, struct test_rpl_entry *entry)
161 {
162 settings_func = func;
163 settings_func_cnt = cnt;
164
165 recv_msg.local_match = true;
166 recv_msg.ctx.addr = entry->src;
167 recv_msg.seq = entry->seq;
168 recv_msg.old_iv = entry->old_iv;
169 }
170
expect_pending_store(void)171 static void expect_pending_store(void)
172 {
173 /* Entries with old_iv == true should be removed, others should be stored. */
174 for (int i = 0; i < ARRAY_SIZE(test_vector); i++) {
175 if (test_vector[i].old_iv) {
176 ztest_expect_value(settings_delete, name, test_vector[i].name);
177 } else {
178 ztest_expect_data(settings_save_one, name, test_vector[i].name);
179 }
180 }
181 }
182
is_rpl_check_called(void)183 static bool is_rpl_check_called(void)
184 {
185 return settings_func_cnt == 0;
186 }
187
verify_rpl(void)188 static void verify_rpl(void)
189 {
190 check_entries_from_test_vector();
191 check_empty_entries(EMPTY_ENTRIES_CNT);
192 }
193
setup(void * f)194 static void setup(void *f)
195 {
196 /* Restore test vector. */
197 memcpy(test_vector, test_vector_default, sizeof(test_vector));
198
199 /* Clear RPL before every test. */
200 skip_delete = true;
201 ztest_expect_value(bt_mesh_settings_store_schedule, flag, BT_MESH_SETTINGS_RPL_PENDING);
202 bt_mesh_rpl_clear();
203 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
204 skip_delete = false;
205
206 settings_func = 0;
207 settings_func_cnt = 0;
208 }
209
210 /**** Mocked functions ****/
211
bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)212 void bt_mesh_settings_store_schedule(enum bt_mesh_settings_flag flag)
213 {
214 ztest_check_expected_value(flag);
215 }
216
bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag)217 void bt_mesh_settings_store_cancel(enum bt_mesh_settings_flag flag)
218 {
219 }
220
settings_save_one(const char * name,const void * value,size_t val_len)221 int settings_save_one(const char *name, const void *value, size_t val_len)
222 {
223 ztest_check_expected_data(name, strlen(name));
224
225 check_op(SETTINGS_SAVE_ONE);
226
227 return 0;
228 }
229
settings_delete(const char * name)230 int settings_delete(const char *name)
231 {
232 if (skip_delete) {
233 return 0;
234 }
235
236 ztest_check_expected_data(name, strlen(name));
237
238 check_op(SETTINGS_DELETE);
239
240 return 0;
241 }
242
243 /**** Tests ****/
244
245 ZTEST_SUITE(bt_mesh_rpl_reset, NULL, NULL, setup, NULL, NULL);
246
247 /** Test that entries with old_iv == true are removed after the reset operation finished. */
ZTEST(bt_mesh_rpl_reset,test_reset_normal)248 ZTEST(bt_mesh_rpl_reset, test_reset_normal)
249 {
250 prepare_rpl_and_start_reset();
251 expect_pending_store();
252
253 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
254
255 verify_rpl();
256 }
257
258 /** Test that RPL accepts and stores a valid entry that was just deleted. The entry should be
259 * stored after the reset operation is finished.
260 */
ZTEST(bt_mesh_rpl_reset,test_rpl_check_on_delete_same_entry)261 ZTEST(bt_mesh_rpl_reset, test_rpl_check_on_delete_same_entry)
262 {
263 prepare_rpl_and_start_reset();
264 expect_pending_store();
265
266 /* Take the first entry with old_iv == true and simulate msg reception with same src
267 * address and correct IVI after the entry was deleted.
268 */
269 struct test_rpl_entry *entry = &test_vector[1];
270
271 zassert_true(entry->old_iv);
272 entry->old_iv = false;
273 call_rpl_check_on(SETTINGS_DELETE, 1, entry);
274
275 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
276 zassert_true(is_rpl_check_called());
277
278 /* Call bt_mesh_rpl_pending_store() to store new entry. */
279 ztest_expect_data(settings_save_one, name, entry->name);
280 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
281
282 verify_rpl();
283 }
284
285 /** Test that RPL accepts and stores a valid entry that was just stored. The entry should be stored
286 * after the reset operation is finished.
287 */
ZTEST(bt_mesh_rpl_reset,test_rpl_check_on_save_same_entry)288 ZTEST(bt_mesh_rpl_reset, test_rpl_check_on_save_same_entry)
289 {
290 prepare_rpl_and_start_reset();
291 expect_pending_store();
292
293 /* Take the first entry with old_iv == false and simulate msg reception with same src
294 * address and correct IVI after the entry was stored.
295 */
296 struct test_rpl_entry *entry = &test_vector[0];
297
298 zassert_false(entry->old_iv);
299 call_rpl_check_on(SETTINGS_SAVE_ONE, 1, entry);
300
301 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
302 zassert_true(is_rpl_check_called());
303
304 /* Call bt_mesh_rpl_pending_store() to store new entry. */
305 ztest_expect_data(settings_save_one, name, entry->name);
306 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
307
308 verify_rpl();
309 }
310
311 /** Test that RPL accepts and stores a valid entry that has not yet been deleted. The entry should
312 * be stored during the reset operation.
313 */
ZTEST(bt_mesh_rpl_reset,test_rpl_check_on_delete_other_entry)314 ZTEST(bt_mesh_rpl_reset, test_rpl_check_on_delete_other_entry)
315 {
316 prepare_rpl_and_start_reset();
317
318 /* Take the non-first entry with old_iv == true and simulate msg reception with same src
319 * address and correct IVI before the entry is deleted.
320 *
321 * Should be done before calling ztest_expect_data() because the expectation changes.
322 */
323 struct test_rpl_entry *entry = &test_vector[3];
324
325 zassert_true(entry->old_iv);
326 entry->old_iv = false;
327 call_rpl_check_on(SETTINGS_DELETE, 1, entry);
328
329 expect_pending_store();
330
331 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
332 zassert_true(is_rpl_check_called());
333
334 /* The entry should have been deleted in previous bt_mesh_rpl_pending_store() call. Another
335 * call should not do anything.
336 */
337 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
338
339 verify_rpl();
340 }
341
342 /* Test that RPL accepts and stores a valid entry that has not yet been stored. The entry should be
343 * stored during the reset operation.
344 */
ZTEST(bt_mesh_rpl_reset,test_rpl_check_on_save_other_entry)345 ZTEST(bt_mesh_rpl_reset, test_rpl_check_on_save_other_entry)
346 {
347 prepare_rpl_and_start_reset();
348
349 /* Take RPL entry from test vector that has old_iv == false and is not stored yet after
350 * bt_mesh_reset() call and try to store it again. RPL has such entry with flipped old_iv,
351 * so this one can be accepted as is.
352 *
353 * Should be done before calling ztest_expect_data() because the expectation changes.
354 */
355 struct test_rpl_entry *entry = &test_vector[2];
356
357 zassert_false(entry->old_iv);
358 call_rpl_check_on(SETTINGS_SAVE_ONE, 1, entry);
359
360 expect_pending_store();
361
362 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
363 zassert_true(is_rpl_check_called());
364
365 /* The entry should have been stored in previous bt_mesh_rpl_pending_store() call. Another
366 * call should not do anything.
367 */
368 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
369
370 verify_rpl();
371 }
372
373 /** Test that RPL accepts and stores a valid entry that has been deleted during the reset operation.
374 * The entry will be added at the end of RPL, therefore it should be stored during the reset
375 * operation.
376 */
ZTEST(bt_mesh_rpl_reset,test_rpl_check_on_delete_deleted_entry)377 ZTEST(bt_mesh_rpl_reset, test_rpl_check_on_delete_deleted_entry)
378 {
379 prepare_rpl_and_start_reset();
380 expect_pending_store();
381
382 /* Take the first entry with old_iv == true, wait until bt_mesh_rpl_pending_store() takes
383 * another entry after that one and simulate msg reception.
384 */
385 struct test_rpl_entry *entry = &test_vector[1];
386
387 zassert_true(entry->old_iv);
388 entry->old_iv = false;
389 call_rpl_check_on(SETTINGS_DELETE, 2, entry);
390 /* The entry will be stored during the reset operation as it will be added to the end of
391 * the RPL.
392 */
393 ztest_expect_data(settings_save_one, name, entry->name);
394
395 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
396 zassert_true(is_rpl_check_called());
397
398 /* The new entry should have been stored already. Another bt_mesh_rpl_pending_store() call
399 * should not do anything.
400 */
401 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
402
403 verify_rpl();
404 }
405
406 /** Test that RPL accepts and stores a valid entry that has been stored during the reset operation.
407 * Since the entry has been already in the list, it should be stored again after the reset
408 * operation is finished.
409 */
ZTEST(bt_mesh_rpl_reset,test_rpl_check_on_store_stored_entry)410 ZTEST(bt_mesh_rpl_reset, test_rpl_check_on_store_stored_entry)
411 {
412 prepare_rpl_and_start_reset();
413 expect_pending_store();
414
415 /* Take the first entry with old_iv == false, wait until bt_mesh_rpl_pending_store() takes
416 * another entry after that one and simulate msg reception.
417 */
418 struct test_rpl_entry *entry = &test_vector[0];
419
420 zassert_false(entry->old_iv);
421 entry->old_iv = true;
422 entry->seq++;
423 call_rpl_check_on(SETTINGS_SAVE_ONE, 2, entry);
424
425 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
426 zassert_true(is_rpl_check_called());
427
428 /* The entry was updated after bt_mesh_rpl_pending_store() checked it. So it should be
429 * stored again.
430 */
431 ztest_expect_data(settings_save_one, name, entry->name);
432 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
433
434 verify_rpl();
435 }
436
437 /** Test that RPL accepts and stores a new entry when the reset operation is not yet finished. */
ZTEST(bt_mesh_rpl_reset,test_rpl_check_on_save_new_entry)438 ZTEST(bt_mesh_rpl_reset, test_rpl_check_on_save_new_entry)
439 {
440 prepare_rpl_and_start_reset();
441 expect_pending_store();
442
443 /* Add a new entry to RPL during the reset operation. */
444 struct test_rpl_entry entry = {
445 .name = "bt/mesh/RPL/2b",
446 .src = 43,
447 .old_iv = false,
448 .seq = 32,
449 };
450 ztest_expect_data(settings_save_one, name, entry.name);
451 call_rpl_check_on(SETTINGS_SAVE_ONE, 1, &entry);
452
453 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
454 zassert_true(is_rpl_check_called());
455
456 /* The entry should have been stored in previous bt_mesh_rpl_pending_store() call. Another
457 * call should not do anything.
458 */
459 bt_mesh_rpl_pending_store(BT_MESH_ADDR_ALL_NODES);
460
461 check_entries_from_test_vector();
462 /* Check that added entry in the RPL. */
463 struct bt_mesh_net_rx msg = {
464 .local_match = true,
465 .ctx.addr = entry.src,
466 .old_iv = entry.old_iv,
467 .seq = entry.seq
468 };
469 zassert_true(bt_mesh_rpl_check(&msg, NULL, false));
470 check_empty_entries(EMPTY_ENTRIES_CNT - 1);
471 }
472