1 /*
2  * Copyright (c) 2023 Nordic Semiconductor
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Composition Data Page 1 (CDP1) test
7  */
8 
9 #include "mesh_test.h"
10 
11 #include <stddef.h>
12 #include <string.h>
13 #include <mesh/access.h>
14 #include <mesh/net.h>
15 
16 #include <zephyr/logging/log.h>
17 #define LOG_MODULE_NAME test_cdp1
18 LOG_MODULE_REGISTER(LOG_MODULE_NAME, LOG_LEVEL_INF);
19 
20 #define NODE_ADDR 0x00a1
21 #define WAIT_TIME 60 /* seconds */
22 
23 #define TEST_MODEL_ID_1     0x2a2a
24 #define TEST_MODEL_ID_2     0x2b2b
25 #define TEST_MODEL_ID_3     0x2c2c
26 #define TEST_MODEL_ID_4     0x2d2d
27 #define TEST_MODEL_ID_5     0x2e2e
28 #define TEST_MODEL_ID_6     0x2f2f
29 #define TEST_VND_MODEL_ID_1 0x3a3a
30 
31 #define TEST_MODEL_DECLARE(number)                                                                 \
32 	static int model_##number##_init(struct bt_mesh_model *model);                             \
33 	static const struct bt_mesh_model_cb test_model_##number##_cb = {                          \
34 		.init = model_##number##_init,                                                     \
35 	};                                                                                         \
36 	static const struct bt_mesh_model_op model_op_##number[] = {                               \
37 		BT_MESH_MODEL_OP_END,                                                              \
38 	};
39 
40 TEST_MODEL_DECLARE(1);
41 TEST_MODEL_DECLARE(2);
42 TEST_MODEL_DECLARE(3);
43 TEST_MODEL_DECLARE(4);
44 TEST_MODEL_DECLARE(5);
45 TEST_MODEL_DECLARE(6);
46 TEST_MODEL_DECLARE(vnd1);
47 
48 static uint8_t app_key[16] = {0xaa};
49 static uint8_t net_key[16] = {0xcc};
50 
51 static const struct bt_mesh_test_cfg node_1_cfg = {
52 	.addr = NODE_ADDR,
53 	.dev_key = {0xaa},
54 };
55 
56 static struct bt_mesh_prov prov;
57 static struct bt_mesh_cfg_cli cfg_cli;
58 
59 static struct bt_mesh_model models_1[] = {
60 	BT_MESH_MODEL_CFG_SRV,
61 	BT_MESH_MODEL_CFG_CLI(&cfg_cli),
62 	BT_MESH_MODEL_CB(TEST_MODEL_ID_1, model_op_1, NULL, NULL, &test_model_1_cb),
63 	BT_MESH_MODEL_CB(TEST_MODEL_ID_2, model_op_2, NULL, NULL, &test_model_2_cb),
64 	BT_MESH_MODEL_CB(TEST_MODEL_ID_3, model_op_3, NULL, NULL, &test_model_3_cb),
65 };
66 
67 static struct bt_mesh_model models_2[] = {
68 	BT_MESH_MODEL_CB(TEST_MODEL_ID_4, model_op_4, NULL, NULL, &test_model_4_cb),
69 };
70 
71 static struct bt_mesh_model models_3[] = {
72 	BT_MESH_MODEL_CB(TEST_MODEL_ID_5, model_op_5, NULL, NULL, &test_model_5_cb),
73 };
74 
75 static struct bt_mesh_model models_4[] = {
76 	BT_MESH_MODEL_CB(TEST_MODEL_ID_6, model_op_6, NULL, NULL, &test_model_6_cb),
77 };
78 
79 static struct bt_mesh_model models_vnd1[] = {
80 	BT_MESH_MODEL_VND_CB(TEST_VND_COMPANY_ID, TEST_VND_MODEL_ID_1, model_op_vnd1, NULL, NULL,
81 			     &test_model_vnd1_cb),
82 };
83 
84 static struct bt_mesh_elem elems[] = {
85 	BT_MESH_ELEM(0, models_1, models_vnd1),
86 	BT_MESH_ELEM(1, models_2, BT_MESH_MODEL_NONE),
87 	BT_MESH_ELEM(2, models_3, BT_MESH_MODEL_NONE),
88 	BT_MESH_ELEM(3, models_3, BT_MESH_MODEL_NONE),
89 	BT_MESH_ELEM(4, models_4, BT_MESH_MODEL_NONE),
90 };
91 
92 static const struct bt_mesh_comp comp = {
93 	.cid = TEST_VND_COMPANY_ID,
94 	.vid = 0xdead,
95 	.pid = 0xface,
96 	.elem = elems,
97 	.elem_count = ARRAY_SIZE(elems),
98 };
99 
100 /* The extensions and correspondence between models are as follows:
101  * Within elements:
102  * E0: M2 extends M1. VND1 extends M2. M3 and VND1 corresponds.
103  *
104  * Between elements:
105  * M3 on E0 extends M4 on E1.
106  * M2 on E0 and M4 on E1 corresponds.
107  * M6 on E4 extends M1 on E0
108  */
model_1_init(struct bt_mesh_model * model)109 static int model_1_init(struct bt_mesh_model *model)
110 {
111 	return 0;
112 }
113 
model_2_init(struct bt_mesh_model * model)114 static int model_2_init(struct bt_mesh_model *model)
115 {
116 	ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1)));
117 	return 0;
118 }
119 
model_3_init(struct bt_mesh_model * model)120 static int model_3_init(struct bt_mesh_model *model)
121 {
122 	return 0;
123 }
124 
model_4_init(struct bt_mesh_model * model)125 static int model_4_init(struct bt_mesh_model *model)
126 {
127 	ASSERT_OK(bt_mesh_model_extend(bt_mesh_model_find(&elems[0], TEST_MODEL_ID_3), model));
128 	ASSERT_OK(bt_mesh_model_correspond(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_2)));
129 	return 0;
130 }
131 
model_5_init(struct bt_mesh_model * model)132 static int model_5_init(struct bt_mesh_model *model)
133 {
134 	return 0;
135 }
136 
model_6_init(struct bt_mesh_model * model)137 static int model_6_init(struct bt_mesh_model *model)
138 {
139 	ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1)));
140 	return 0;
141 }
142 
model_vnd1_init(struct bt_mesh_model * model)143 static int model_vnd1_init(struct bt_mesh_model *model)
144 {
145 	ASSERT_OK(bt_mesh_model_extend(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_1)));
146 	ASSERT_OK(bt_mesh_model_correspond(model, bt_mesh_model_find(&elems[0], TEST_MODEL_ID_3)));
147 	return 0;
148 }
149 
150 /* Hardcoded version of the CDP1 fields.
151  * Extensions are named extending-model_base-model.
152  */
153 
154 static struct bt_mesh_comp_p1_ext_item test_p1_ext_mod2_mod1 = {.type = SHORT,
155 								.short_item = {
156 									.elem_offset = 0,
157 									.mod_item_idx = 2,
158 								}};
159 
160 static struct bt_mesh_comp_p1_ext_item test_p1_ext_vnd1_mod1 = {.type = SHORT,
161 								.short_item = {
162 									.elem_offset = 0,
163 									.mod_item_idx = 2,
164 								}};
165 
166 static struct bt_mesh_comp_p1_ext_item test_p1_ext_mod3_mod4 = {.type = SHORT,
167 								.short_item = {
168 									.elem_offset = 7,
169 									.mod_item_idx = 0,
170 								}};
171 
172 static struct bt_mesh_comp_p1_ext_item test_p1_ext_mod6_mod1 = {.type = LONG,
173 								.long_item = {
174 									.elem_offset = 4,
175 									.mod_item_idx = 2,
176 								}};
177 
178 static const struct bt_mesh_comp_p1_model_item test_p1_cfg_srv_mod = {
179 	.cor_present = 0,
180 	.format = 0,
181 	.ext_item_cnt = 0,
182 };
183 
184 static const struct bt_mesh_comp_p1_model_item test_p1_cfg_cli_mod = {
185 	.cor_present = 0,
186 	.format = 0,
187 	.ext_item_cnt = 0,
188 };
189 
190 static const struct bt_mesh_comp_p1_model_item test_p1_mod1 = {
191 	.cor_present = 0,
192 	.format = 0,
193 	.ext_item_cnt = 0,
194 };
195 
196 static const struct bt_mesh_comp_p1_model_item test_p1_mod2 = {
197 	.cor_present = 1,
198 	.format = 0,
199 	.ext_item_cnt = 1,
200 	.cor_id = 0,
201 };
202 
203 static const struct bt_mesh_comp_p1_model_item test_p1_mod3 = {
204 	.cor_present = 1,
205 	.format = 0,
206 	.ext_item_cnt = 1,
207 	.cor_id = 0,
208 };
209 
210 static const struct bt_mesh_comp_p1_model_item test_p1_mod4 = {
211 	.cor_present = 1,
212 	.format = 0,
213 	.ext_item_cnt = 0,
214 	.cor_id = 0,
215 };
216 
217 static const struct bt_mesh_comp_p1_model_item test_p1_mod5 = {
218 	.cor_present = 0,
219 	.format = 0,
220 	.ext_item_cnt = 0,
221 };
222 
223 static const struct bt_mesh_comp_p1_model_item test_p1_mod6 = {
224 	.cor_present = 0,
225 	.format = 1,
226 	.ext_item_cnt = 1,
227 };
228 
229 static const struct bt_mesh_comp_p1_model_item test_p1_vnd1 = {
230 	.cor_present = 1,
231 	.format = 0,
232 	.ext_item_cnt = 1,
233 	.cor_id = 0,
234 };
235 
236 static const struct bt_mesh_comp_p1_model_item test_p1_elem0_models[] = {
237 	test_p1_cfg_srv_mod, test_p1_cfg_cli_mod, test_p1_mod1,
238 	test_p1_mod2,        test_p1_mod3,        test_p1_vnd1,
239 };
240 
241 static const struct bt_mesh_comp_p1_model_item test_p1_elem1_models[] = {
242 	test_p1_mod4,
243 };
244 
245 static const struct bt_mesh_comp_p1_model_item test_p1_elem2_models[] = {
246 	test_p1_mod5,
247 };
248 
249 static const struct bt_mesh_comp_p1_model_item test_p1_elem3_models[] = {
250 	test_p1_mod5,
251 };
252 
253 static const struct bt_mesh_comp_p1_model_item test_p1_elem4_models[] = {
254 	test_p1_mod6,
255 };
256 
257 static const struct bt_mesh_comp_p1_model_item *test_p1_elem_models[] = {
258 	test_p1_elem0_models, test_p1_elem1_models, test_p1_elem2_models,
259 	test_p1_elem3_models, test_p1_elem4_models,
260 };
261 
262 static const struct bt_mesh_comp_p1_elem test_p1_elem0 = {
263 	.nsig = 5,
264 	.nvnd = 1,
265 };
266 
267 static const struct bt_mesh_comp_p1_elem test_p1_elem1 = {
268 	.nsig = 1,
269 	.nvnd = 0,
270 };
271 
272 static const struct bt_mesh_comp_p1_elem test_p1_elem2 = {
273 	.nsig = 1,
274 	.nvnd = 0,
275 };
276 
277 static const struct bt_mesh_comp_p1_elem test_p1_elem3 = {
278 	.nsig = 1,
279 	.nvnd = 0,
280 };
281 
282 static const struct bt_mesh_comp_p1_elem test_p1_elem4 = {
283 	.nsig = 1,
284 	.nvnd = 0,
285 };
286 
287 static struct bt_mesh_comp_p1_elem test_p1_elems[] = {
288 	test_p1_elem0, test_p1_elem1, test_p1_elem2, test_p1_elem3, test_p1_elem4,
289 };
290 
provision_and_configure(struct bt_mesh_test_cfg cfg)291 static void provision_and_configure(struct bt_mesh_test_cfg cfg)
292 {
293 	int err;
294 	uint8_t status;
295 
296 	err = bt_mesh_provision(net_key, 0, 0, 0, cfg.addr, cfg.dev_key);
297 	if (err) {
298 		FAIL("Provisioning failed (err %d)", err);
299 	}
300 
301 	err = bt_mesh_cfg_cli_app_key_add(0, cfg.addr, 0, 0, app_key, &status);
302 	if (err || status) {
303 		FAIL("AppKey add failed (err %d, status %u)", err, status);
304 	}
305 }
306 
verify_model_item(struct bt_mesh_comp_p1_model_item * mod_item,int elem_idx,int mod_idx,int offset)307 static void verify_model_item(struct bt_mesh_comp_p1_model_item *mod_item, int elem_idx,
308 			      int mod_idx, int offset)
309 {
310 	ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].cor_present,
311 		     mod_item->cor_present);
312 	ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].format, mod_item->format);
313 	ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].ext_item_cnt,
314 		     mod_item->ext_item_cnt);
315 	if (mod_item->cor_present) {
316 		ASSERT_EQUAL(test_p1_elem_models[elem_idx][mod_idx + offset].cor_id,
317 			     mod_item->cor_id);
318 	}
319 }
320 
verify_ext_item(struct bt_mesh_comp_p1_ext_item * ext_item,int elem_idx,int mod_idx,int offset)321 static void verify_ext_item(struct bt_mesh_comp_p1_ext_item *ext_item, int elem_idx, int mod_idx,
322 			    int offset)
323 {
324 	struct bt_mesh_comp_p1_ext_item *test_p1_ext_item;
325 
326 	switch (elem_idx * 100 + (mod_idx + offset)) {
327 	case 3: /* elem_idx=0, mod_idx=3, offset = 0 */
328 		test_p1_ext_item = &test_p1_ext_mod2_mod1;
329 		break;
330 	case 4: /* elem_idx=0, mod_idx=4, offset = 0 */
331 		test_p1_ext_item = &test_p1_ext_mod3_mod4;
332 		break;
333 	case 5: /* elem_idx=0, mod_idx=0, offset = 5 */
334 		test_p1_ext_item = &test_p1_ext_vnd1_mod1;
335 		break;
336 	case 400: /* elem_idx=4, mod_idx=0, offset = 0 */
337 		test_p1_ext_item = &test_p1_ext_mod6_mod1;
338 		break;
339 	default:
340 		FAIL("Unexpected call to %s (elem %d, mod %d, offset %d)", __func__, elem_idx,
341 		     mod_idx, offset);
342 	}
343 
344 	ASSERT_EQUAL(test_p1_ext_item->type, ext_item->type);
345 	if (ext_item->type == SHORT) {
346 		ASSERT_EQUAL(test_p1_ext_item->short_item.elem_offset,
347 			     ext_item->short_item.elem_offset);
348 		ASSERT_EQUAL(test_p1_ext_item->short_item.mod_item_idx,
349 			     ext_item->short_item.mod_item_idx);
350 	} else {
351 		ASSERT_EQUAL(test_p1_ext_item->long_item.elem_offset,
352 			     ext_item->long_item.elem_offset);
353 		ASSERT_EQUAL(test_p1_ext_item->long_item.mod_item_idx,
354 			     ext_item->long_item.mod_item_idx);
355 	}
356 }
357 
verify_cdp1(struct bt_mesh_comp_p1_elem * p1_elem,struct bt_mesh_comp_p1_model_item * mod_item,struct bt_mesh_comp_p1_ext_item * ext_item,struct net_buf_simple * p1_dev_comp)358 static void verify_cdp1(struct bt_mesh_comp_p1_elem *p1_elem,
359 			struct bt_mesh_comp_p1_model_item *mod_item,
360 			struct bt_mesh_comp_p1_ext_item *ext_item,
361 			struct net_buf_simple *p1_dev_comp)
362 {
363 	int elem_idx = 0;
364 
365 	while (bt_mesh_comp_p1_elem_pull(p1_dev_comp, p1_elem)) {
366 		ASSERT_EQUAL(test_p1_elems[elem_idx].nsig, p1_elem->nsig);
367 		ASSERT_EQUAL(test_p1_elems[elem_idx].nvnd, p1_elem->nvnd);
368 
369 		for (int mod_idx = 0; mod_idx < p1_elem->nsig; mod_idx++) {
370 			if (bt_mesh_comp_p1_item_pull(p1_elem, mod_item)) {
371 				verify_model_item(mod_item, elem_idx, mod_idx, 0);
372 			}
373 
374 			for (int ext_mod_idx = 0; ext_mod_idx < mod_item->ext_item_cnt;
375 			     ext_mod_idx++) {
376 				bt_mesh_comp_p1_pull_ext_item(mod_item, ext_item);
377 				verify_ext_item(ext_item, elem_idx, mod_idx, 0);
378 			}
379 		}
380 
381 		for (int mod_idx = 0; mod_idx < p1_elem->nvnd; mod_idx++) {
382 			if (bt_mesh_comp_p1_item_pull(p1_elem, mod_item)) {
383 				verify_model_item(mod_item, elem_idx, mod_idx, p1_elem->nsig);
384 			}
385 
386 			for (int ext_mod_idx = 0; ext_mod_idx < mod_item->ext_item_cnt;
387 			     ext_mod_idx++) {
388 				bt_mesh_comp_p1_pull_ext_item(mod_item, ext_item);
389 				verify_ext_item(ext_item, elem_idx, mod_idx, p1_elem->nsig);
390 			}
391 		}
392 		elem_idx++;
393 	}
394 }
395 
test_node_data_comparison(void)396 static void test_node_data_comparison(void)
397 {
398 	bt_mesh_test_cfg_set(NULL, WAIT_TIME);
399 	bt_mesh_device_setup(&prov, &comp);
400 	provision_and_configure(node_1_cfg);
401 
402 	NET_BUF_SIMPLE_DEFINE(p1_dev_comp, 500);
403 	uint8_t page_rsp;
404 
405 	ASSERT_OK(bt_mesh_cfg_cli_comp_data_get(0, node_1_cfg.addr, 1, &page_rsp, &p1_dev_comp));
406 	ASSERT_EQUAL(1, page_rsp);
407 
408 	NET_BUF_SIMPLE_DEFINE(p1_buf, 500);
409 	NET_BUF_SIMPLE_DEFINE(p1_item_buf, 500);
410 	struct bt_mesh_comp_p1_elem p1_elem = {._buf = &p1_buf};
411 	struct bt_mesh_comp_p1_model_item mod_item = {._buf = &p1_item_buf};
412 	struct bt_mesh_comp_p1_ext_item ext_item = {0};
413 
414 	verify_cdp1(&p1_elem, &mod_item, &ext_item, &p1_dev_comp);
415 
416 	PASS();
417 }
418 
419 #define TEST_CASE(role, name, description)                                                         \
420 	{                                                                                          \
421 		.test_id = "cdp1_" #role "_" #name, .test_descr = description,                     \
422 		.test_tick_f = bt_mesh_test_timeout, .test_main_f = test_##role##_##name,          \
423 	}
424 
425 static const struct bst_test_instance test_cdp1[] = {
426 	TEST_CASE(node, data_comparison, "Compare encoded and decoded CDP1 data."),
427 
428 	BSTEST_END_MARKER};
429 
test_cdp1_install(struct bst_test_list * tests)430 struct bst_test_list *test_cdp1_install(struct bst_test_list *tests)
431 {
432 	tests = bst_add_tests(tests, test_cdp1);
433 	return tests;
434 }
435