1 /*
2  * Copyright (c) 2022 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/kernel.h>
8 #include "mesh_test.h"
9 #include "mesh/net.h"
10 
11 #define LOG_MODULE_NAME test_ivi
12 
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
15 
16 #define WAIT_TIME 60 /*seconds*/
17 #define TEST_IV_IDX  100
18 #define BCN_IV_IN_PROGRESS true
19 #define BCN_IV_IN_IDLE false
20 
21 extern struct bt_mesh_net bt_mesh;
22 
23 static const struct bt_mesh_test_cfg ivu_cfg = {
24 	.addr = 0x0001,
25 	.dev_key = { 0x01 },
26 };
27 
async_send_end(int err,void * data)28 static void async_send_end(int err, void *data)
29 {
30 	struct k_sem *sem = data;
31 
32 	if (sem) {
33 		k_sem_give(sem);
34 	}
35 }
36 
37 static const struct bt_mesh_send_cb async_send_cb = {
38 	.end = async_send_end,
39 };
40 
test_ivu_init(void)41 static void test_ivu_init(void)
42 {
43 	bt_mesh_test_cfg_set(&ivu_cfg, WAIT_TIME);
44 }
45 
emulate_recovery_timeout(void)46 static void emulate_recovery_timeout(void)
47 {
48 	k_work_cancel_delayable(&bt_mesh.ivu_timer);
49 	bt_mesh.ivu_duration = 2 * BT_MESH_IVU_MIN_HOURS;
50 }
51 
test_ivu_recovery(void)52 static void test_ivu_recovery(void)
53 {
54 	bt_mesh_test_setup();
55 
56 	bt_mesh.iv_index = TEST_IV_IDX;
57 
58 	atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
59 
60 	/* Already in IV Update in Progress state */
61 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_PROGRESS));
62 
63 	/* Out of sync */
64 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX - 1, BCN_IV_IN_IDLE));
65 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX + 43, BCN_IV_IN_IDLE));
66 
67 	/* Start recovery */
68 	ASSERT_TRUE(bt_mesh_net_iv_update(TEST_IV_IDX + 2, BCN_IV_IN_IDLE));
69 	ASSERT_EQUAL(TEST_IV_IDX + 2, bt_mesh.iv_index);
70 	ASSERT_FALSE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
71 
72 	/* Start recovery before minimum delay */
73 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX + 4, BCN_IV_IN_IDLE));
74 
75 	emulate_recovery_timeout();
76 	bt_mesh.iv_index = TEST_IV_IDX;
77 
78 	atomic_clear_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
79 
80 	/* Already in IV normal mode */
81 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE));
82 
83 	/* Out of sync */
84 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX - 1, BCN_IV_IN_IDLE));
85 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX + 43, BCN_IV_IN_IDLE));
86 
87 	/* Start recovery */
88 	ASSERT_TRUE(bt_mesh_net_iv_update(TEST_IV_IDX + 1, BCN_IV_IN_IDLE));
89 	ASSERT_EQUAL(TEST_IV_IDX + 1, bt_mesh.iv_index);
90 	ASSERT_FALSE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
91 
92 	/* Start recovery before minimum delay */
93 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX + 4, BCN_IV_IN_IDLE));
94 
95 	PASS();
96 }
97 
test_ivu_normal(void)98 static void test_ivu_normal(void)
99 {
100 	bt_mesh_test_setup();
101 	bt_mesh.iv_index = TEST_IV_IDX;
102 	bt_mesh.seq = 100;
103 	atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
104 
105 	/* update before minimum duration */
106 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE));
107 	/* moving back into the normal mode */
108 	bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS;
109 	ASSERT_TRUE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE));
110 	ASSERT_FALSE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
111 	ASSERT_EQUAL(TEST_IV_IDX, bt_mesh.iv_index);
112 	ASSERT_EQUAL(0, bt_mesh.seq);
113 
114 	/* Ignore same iv index but iv in progress */
115 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_PROGRESS));
116 
117 	bt_mesh.seq = 100;
118 	/* update before minimum duration */
119 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX + 1, BCN_IV_IN_PROGRESS));
120 	/* moving into the IV update mode */
121 	bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS;
122 	ASSERT_TRUE(bt_mesh_net_iv_update(TEST_IV_IDX + 1, BCN_IV_IN_PROGRESS));
123 	ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
124 	ASSERT_EQUAL(TEST_IV_IDX + 1, bt_mesh.iv_index);
125 	ASSERT_EQUAL(100, bt_mesh.seq);
126 
127 	PASS();
128 }
129 
test_ivu_deferring(void)130 static void test_ivu_deferring(void)
131 {
132 	struct k_sem sem;
133 
134 	k_sem_init(&sem, 0, 1);
135 	bt_mesh_test_setup();
136 	bt_mesh.iv_index = TEST_IV_IDX;
137 	atomic_set_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS);
138 	bt_mesh.ivu_duration = BT_MESH_IVU_MIN_HOURS;
139 
140 	ASSERT_OK(bt_mesh_test_send_async(0x0002, NULL, 20, FORCE_SEGMENTATION, &async_send_cb,
141 					  &sem));
142 	ASSERT_FALSE(bt_mesh_net_iv_update(TEST_IV_IDX, BCN_IV_IN_IDLE));
143 	ASSERT_TRUE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
144 
145 	ASSERT_OK(k_sem_take(&sem, K_SECONDS(10)));
146 	ASSERT_FALSE(atomic_test_bit(bt_mesh.flags, BT_MESH_IVU_IN_PROGRESS));
147 
148 	PASS();
149 }
150 
151 #define TEST_CASE(role, name, description)                     \
152 	{                                                      \
153 		.test_id = "ivi_" #role "_" #name,             \
154 		.test_descr = description,                     \
155 		.test_pre_init_f = test_##role##_init,         \
156 		.test_tick_f = bt_mesh_test_timeout,           \
157 		.test_main_f = test_##role##_##name,           \
158 	}
159 
160 static const struct bst_test_instance test_ivi[] = {
161 	TEST_CASE(ivu, recovery,  "IVI: IV recovery procedure"),
162 	TEST_CASE(ivu, normal,    "IVI: IV update procedure"),
163 	TEST_CASE(ivu, deferring, "IVI: deferring of the IV update procedure"),
164 
165 	BSTEST_END_MARKER
166 };
167 
test_ivi_install(struct bst_test_list * tests)168 struct bst_test_list *test_ivi_install(struct bst_test_list *tests)
169 {
170 	tests = bst_add_tests(tests, test_ivi);
171 	return tests;
172 }
173