1 /*
2  * Copyright (c) 2023 Nordic Semiconductor ASA
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/fff.h>
8 #include <zephyr/logging/log.h>
9 #include <zephyr/ztest.h>
10 #include <zephyr/net/socket.h>
11 
12 #include "lwm2m_engine.h"
13 #include "lwm2m_rd_client.h"
14 
15 #include "stubs.h"
16 #if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME)
17 #include "timer_model.h"
18 #endif
19 
20 #define LOG_LEVEL	LOG_LEVEL_DBG
21 LOG_MODULE_REGISTER(lwm2m_engine_test);
22 
23 DEFINE_FFF_GLOBALS;
24 #define FFF_FAKES_LIST(FAKE)
25 
26 static uint8_t my_buf[256];
27 static uint16_t my_data_len = 1;
28 static struct lwm2m_message my_msg;
29 static struct lwm2m_engine_obj_field my_obj_field;
30 
lwm2m_get_res_buf_custom_fake(const struct lwm2m_obj_path * path,void ** buffer_ptr,uint16_t * buffer_len,uint16_t * data_len,uint8_t * data_flags)31 static int lwm2m_get_res_buf_custom_fake(const struct lwm2m_obj_path *path, void **buffer_ptr,
32 					 uint16_t *buffer_len, uint16_t *data_len,
33 					 uint8_t *data_flags)
34 {
35 	if (buffer_ptr) {
36 		*buffer_ptr = my_buf;
37 	}
38 	if (buffer_len) {
39 		*buffer_len = sizeof(my_buf);
40 	}
41 	if (data_len) {
42 		*data_len = my_data_len;
43 	}
44 
45 	return 0;
46 }
47 
find_msg_custom_fake(struct coap_pending * pending,struct coap_reply * reply)48 static struct lwm2m_message *find_msg_custom_fake(struct coap_pending *pending,
49 						  struct coap_reply *reply)
50 {
51 	return &my_msg;
52 }
53 
54 static struct lwm2m_engine_obj_field *
lwm2m_get_engine_obj_field_custom_fake(struct lwm2m_engine_obj * obj,int res_id)55 lwm2m_get_engine_obj_field_custom_fake(struct lwm2m_engine_obj *obj, int res_id)
56 {
57 	return &my_obj_field;
58 }
59 
lwm2m_get_bool_custom_fake(const struct lwm2m_obj_path * path,bool * value)60 static int lwm2m_get_bool_custom_fake(const struct lwm2m_obj_path *path, bool *value)
61 {
62 	*value = false;
63 
64 	return 0;
65 }
66 
test_service(struct k_work * work)67 static void test_service(struct k_work *work)
68 {
69 	k_sleep(K_MSEC(10));
70 }
71 
setup(void * data)72 static void setup(void *data)
73 {
74 #if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME)
75 	/* It is enough that some slow-down is happening on sleeps, it does not have to be
76 	 * real time
77 	 */
78 	hwtimer_set_rt_ratio(100.0);
79 #endif
80 	/* Register resets */
81 	DO_FOREACH_FAKE(RESET_FAKE);
82 
83 	/* reset common FFF internal structures */
84 	FFF_RESET_HISTORY();
85 
86 	clear_socket_events();
87 	lwm2m_get_res_buf_fake.custom_fake = lwm2m_get_res_buf_custom_fake;
88 	find_msg_fake.custom_fake = find_msg_custom_fake;
89 	lwm2m_get_engine_obj_field_fake.custom_fake = lwm2m_get_engine_obj_field_custom_fake;
90 	lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_custom_fake;
91 }
92 
93 ZTEST_SUITE(lwm2m_engine, NULL, NULL, setup, NULL, NULL);
94 
ZTEST(lwm2m_engine,test_start_stop)95 ZTEST(lwm2m_engine, test_start_stop)
96 {
97 	int ret;
98 	struct lwm2m_ctx ctx;
99 	char host_name[10] = "my_host";
100 
101 	(void)memset(&ctx, 0x0, sizeof(ctx));
102 
103 	ctx.remote_addr.sa_family = AF_INET;
104 	ctx.sock_fd = -1;
105 	ctx.load_credentials = NULL;
106 	ctx.desthostname = host_name;
107 	ctx.desthostnamelen = strlen(host_name);
108 	ctx.use_dtls = true;
109 
110 	ret = lwm2m_engine_start(&ctx);
111 	zassert_equal(ret, 0);
112 
113 	struct lwm2m_ctx **eng_ctx = lwm2m_sock_ctx();
114 	int nfds = lwm2m_sock_nfds();
115 
116 	zassert_not_null(eng_ctx);
117 	zassert_true(nfds > 0);
118 	zassert_equal(eng_ctx[0], &ctx);
119 
120 	/* wait for socket receive thread */
121 	k_sleep(K_MSEC(1000));
122 	ret = lwm2m_engine_stop(&ctx);
123 	zassert_equal(ret, 0);
124 }
125 
ZTEST(lwm2m_engine,test_pause_resume)126 ZTEST(lwm2m_engine, test_pause_resume)
127 {
128 	int ret;
129 	struct lwm2m_ctx ctx;
130 
131 	(void)memset(&ctx, 0x0, sizeof(ctx));
132 
133 	ctx.remote_addr.sa_family = AF_INET;
134 	ctx.sock_fd = -1;
135 	ctx.load_credentials = NULL;
136 
137 	ret = lwm2m_engine_start(&ctx);
138 	zassert_equal(ret, 0);
139 	ret = lwm2m_engine_resume();
140 	zassert_equal(ret, -EPERM);
141 	ret = lwm2m_engine_pause();
142 	zassert_equal(ret, 0);
143 	ret = lwm2m_engine_pause();
144 	zassert_equal(ret, 0);
145 	ret = lwm2m_engine_resume();
146 	zassert_equal(ret, 0);
147 	ret = lwm2m_engine_stop(&ctx);
148 	zassert_equal(ret, 0);
149 }
150 
ZTEST(lwm2m_engine,test_engine_add_service)151 ZTEST(lwm2m_engine, test_engine_add_service)
152 {
153 	int ret;
154 	struct lwm2m_ctx ctx;
155 
156 	(void)memset(&ctx, 0x0, sizeof(ctx));
157 
158 	ctx.remote_addr.sa_family = AF_INET;
159 	ctx.load_credentials = NULL;
160 
161 	ret = lwm2m_engine_start(&ctx);
162 	zassert_equal(ret, 0);
163 	ret = lwm2m_engine_add_service(test_service, 1000);
164 	zassert_equal(ret, 0);
165 	/* wait for socket receive thread */
166 	k_sleep(K_MSEC(1500));
167 	ret = lwm2m_engine_update_service_period(test_service, 500);
168 	zassert_equal(ret, 0);
169 	ret = lwm2m_engine_stop(&ctx);
170 	zassert_equal(ret, 0);
171 }
172 
ZTEST(lwm2m_engine,test_no_sa_family)173 ZTEST(lwm2m_engine, test_no_sa_family)
174 {
175 	int ret;
176 	struct lwm2m_ctx ctx;
177 
178 	(void)memset(&ctx, 0x0, sizeof(ctx));
179 
180 	ctx.sock_fd = -1;
181 	ctx.load_credentials = NULL;
182 
183 	ret = lwm2m_engine_start(&ctx);
184 	zassert_equal(ret, -EPROTONOSUPPORT);
185 	lwm2m_engine_stop(&ctx);
186 }
187 
ZTEST(lwm2m_engine,test_connect_fail)188 ZTEST(lwm2m_engine, test_connect_fail)
189 {
190 	int ret;
191 	struct lwm2m_ctx ctx;
192 
193 	(void)memset(&ctx, 0x0, sizeof(ctx));
194 
195 	ctx.sock_fd = -1;
196 	ctx.load_credentials = NULL;
197 	ctx.remote_addr.sa_family = AF_INET;
198 
199 	errno = ENETDOWN;
200 	z_impl_zsock_connect_fake.return_val = -1;
201 	ret = lwm2m_engine_start(&ctx);
202 	zassert_equal(ret, -ENETDOWN);
203 	lwm2m_engine_stop(&ctx);
204 }
205 
ZTEST(lwm2m_engine,test_socket_suspend_resume_connection)206 ZTEST(lwm2m_engine, test_socket_suspend_resume_connection)
207 {
208 	int ret;
209 	struct lwm2m_ctx ctx;
210 
211 	(void)memset(&ctx, 0x0, sizeof(ctx));
212 
213 	ctx.sock_fd = -1;
214 	ctx.load_credentials = NULL;
215 	ctx.remote_addr.sa_family = AF_INET;
216 
217 	ret = lwm2m_engine_start(&ctx);
218 	zassert_equal(ret, 0);
219 	ret = lwm2m_socket_suspend(&ctx);
220 	zassert_equal(ret, 0);
221 	zassert_equal(ctx.connection_suspended, true);
222 	ret = lwm2m_engine_connection_resume(&ctx);
223 	zassert_equal(ret, 0);
224 	zassert_equal(ctx.connection_suspended, false);
225 	lwm2m_engine_stop(&ctx);
226 }
227 
ZTEST(lwm2m_engine,test_check_notifications)228 ZTEST(lwm2m_engine, test_check_notifications)
229 {
230 	int ret;
231 	struct lwm2m_ctx ctx;
232 	struct observe_node obs;
233 
234 	(void)memset(&ctx, 0x0, sizeof(ctx));
235 
236 	ctx.sock_fd = -1;
237 	ctx.load_credentials = NULL;
238 	ctx.remote_addr.sa_family = AF_INET;
239 	sys_slist_init(&ctx.observer);
240 
241 	obs.last_timestamp = k_uptime_get();
242 	obs.event_timestamp = k_uptime_get() + 1000U;
243 	obs.resource_update = false;
244 	obs.active_notify = NULL;
245 
246 	sys_slist_append(&ctx.observer, &obs.node);
247 
248 	lwm2m_rd_client_is_registred_fake.return_val = true;
249 	ret = lwm2m_engine_start(&ctx);
250 	zassert_equal(ret, 0);
251 	/* wait for socket receive thread */
252 	k_sleep(K_MSEC(2000));
253 	ret = lwm2m_engine_stop(&ctx);
254 	zassert_equal(ret, 0);
255 	zassert_equal(generate_notify_message_fake.call_count, 1, "Notify message not generated");
256 	zassert_equal(engine_observe_shedule_next_event_fake.call_count, 1,
257 		      "Next observe event not scheduled");
258 }
259 
ZTEST(lwm2m_engine,test_push_queued_buffers)260 ZTEST(lwm2m_engine, test_push_queued_buffers)
261 {
262 	int ret;
263 	struct lwm2m_ctx ctx;
264 	struct lwm2m_message msg;
265 	struct coap_pending pending;
266 
267 	(void)memset(&ctx, 0x0, sizeof(ctx));
268 
269 	sys_slist_init(&ctx.queued_messages);
270 	msg.ctx = &ctx;
271 	msg.pending = &pending;
272 	sys_slist_append(&ctx.queued_messages, &msg.node);
273 	ret = lwm2m_push_queued_buffers(&ctx);
274 	zassert_equal(ret, 0);
275 }
276 
ZTEST(lwm2m_engine,test_validate_write_access)277 ZTEST(lwm2m_engine, test_validate_write_access)
278 {
279 	int ret;
280 	struct lwm2m_ctx ctx;
281 	struct lwm2m_message msg;
282 	struct lwm2m_engine_res resources;
283 	struct lwm2m_engine_obj_inst obj_inst;
284 	struct lwm2m_engine_obj_field *obj_field = NULL;
285 
286 	(void)memset(&ctx, 0x0, sizeof(ctx));
287 
288 	ctx.bootstrap_mode = true;
289 	msg.ctx = &ctx;
290 	msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0);
291 	obj_inst.resources = &resources;
292 	obj_inst.resource_count = 1U;
293 	ret = lwm2m_engine_validate_write_access(&msg, &obj_inst, &obj_field);
294 	zassert_equal(ret, 0);
295 
296 	obj_inst.resource_count = 0U;
297 	ret = lwm2m_engine_validate_write_access(&msg, &obj_inst, &obj_field);
298 	zassert_equal(ret, -EINVAL);
299 
300 	msg.path = LWM2M_OBJ(LWM2M_OBJECT_DEVICE_ID, 0);
301 	ret = lwm2m_engine_validate_write_access(&msg, &obj_inst, &obj_field);
302 	zassert_equal(ret, -EPERM);
303 }
304 
ZTEST(lwm2m_engine,test_bootstrap_delete)305 ZTEST(lwm2m_engine, test_bootstrap_delete)
306 {
307 	int ret;
308 	struct lwm2m_message msg;
309 
310 	msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0);
311 	ret = bootstrap_delete(&msg);
312 	zassert_equal(ret, -EPERM);
313 
314 	msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 1);
315 	ret = bootstrap_delete(&msg);
316 	zassert_equal(ret, 0);
317 	zassert_equal(0, lwm2m_delete_obj_inst_fake.arg0_history[0]);
318 	zassert_equal(1, lwm2m_delete_obj_inst_fake.arg1_history[0]);
319 
320 
321 	struct lwm2m_engine_obj sec_obj = {.obj_id = 0};
322 	struct lwm2m_engine_obj_inst sec_inst = {
323 		.obj_inst_id = 2,
324 		.obj = &sec_obj
325 	};
326 	sys_slist_append(lwm2m_engine_obj_inst_list(), &sec_inst.node);
327 
328 	msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID);
329 	ret = bootstrap_delete(&msg);
330 	zassert_equal(ret, 0);
331 	zassert_equal(0, lwm2m_delete_obj_inst_fake.arg0_history[1]);
332 	zassert_equal(2, lwm2m_delete_obj_inst_fake.arg1_history[1]);
333 
334 	msg.path = LWM2M_OBJ(LWM2M_OBJECT_DEVICE_ID, 0);
335 	ret = bootstrap_delete(&msg);
336 	zassert_equal(ret, -EPERM);
337 }
338 
ZTEST(lwm2m_engine,test_retransmit_request)339 ZTEST(lwm2m_engine, test_retransmit_request)
340 {
341 	int ret;
342 	struct lwm2m_ctx ctx;
343 	struct coap_pending pending_1;
344 	struct coap_pending pending_2;
345 
346 	(void)memset(&ctx, 0x0, sizeof(ctx));
347 
348 	ctx.sock_fd = -1;
349 	ctx.load_credentials = NULL;
350 	ctx.remote_addr.sa_family = AF_INET;
351 
352 	pending_1.t0 = k_uptime_get();
353 	pending_1.timeout = 200U;
354 	pending_1.retries = 0;
355 	ctx.pendings[0] = pending_1;
356 
357 	pending_2.t0 = k_uptime_get();
358 	pending_2.timeout = 200U;
359 	pending_2.retries = 1;
360 	ctx.pendings[1] = pending_2;
361 
362 	ret = lwm2m_engine_start(&ctx);
363 	zassert_equal(ret, 0);
364 	/* wait for socket receive thread */
365 	k_sleep(K_MSEC(500));
366 	ret = lwm2m_engine_stop(&ctx);
367 	zassert_equal(ret, 0);
368 	zassert_not_equal(lwm2m_reset_message_fake.call_count, 0, "Message was not reseted");
369 	zassert_not_equal(lwm2m_send_message_async_fake.call_count, 0, "Message was not sent");
370 }
371 
ZTEST(lwm2m_engine,test_socket_recv)372 ZTEST(lwm2m_engine, test_socket_recv)
373 {
374 	int ret;
375 	struct lwm2m_ctx ctx;
376 
377 	(void)memset(&ctx, 0x0, sizeof(ctx));
378 
379 	ctx.remote_addr.sa_family = AF_INET;
380 	ctx.sock_fd = -1;
381 
382 	set_socket_events(ZSOCK_POLLIN);
383 
384 	ret = lwm2m_engine_start(&ctx);
385 	zassert_equal(ret, 0);
386 	/* wait for socket receive thread */
387 	k_sleep(K_MSEC(1000));
388 	ret = lwm2m_engine_stop(&ctx);
389 	zassert_equal(ret, 0);
390 	zassert_true(lwm2m_udp_receive_fake.call_count > 0);
391 }
392 
ZTEST(lwm2m_engine,test_socket_send)393 ZTEST(lwm2m_engine, test_socket_send)
394 {
395 	int ret;
396 	struct lwm2m_ctx ctx;
397 	struct lwm2m_message msg;
398 	struct coap_pending pending;
399 
400 	(void)memset(&ctx, 0x0, sizeof(ctx));
401 
402 	ctx.remote_addr.sa_family = AF_INET;
403 	ctx.sock_fd = -1;
404 	sys_slist_init(&ctx.queued_messages);
405 	msg.ctx = &ctx;
406 	msg.pending = &pending;
407 	msg.type = COAP_TYPE_CON;
408 	sys_slist_append(&ctx.queued_messages, &msg.node);
409 
410 	ret = lwm2m_push_queued_buffers(&ctx);
411 	zassert_equal(ret, 0);
412 
413 	set_socket_events(ZSOCK_POLLOUT);
414 
415 	ret = lwm2m_engine_start(&ctx);
416 	zassert_equal(ret, 0);
417 	/* wait for socket receive thread */
418 	k_sleep(K_MSEC(2000));
419 	ret = lwm2m_engine_stop(&ctx);
420 	zassert_equal(ret, 0);
421 	LOG_INF("Count %d", coap_pending_cycle_fake.call_count);
422 	zassert_equal(coap_pending_cycle_fake.call_count, 1, "coap_pending_cycle not called");
423 }
424 
ZTEST(lwm2m_engine,test_security)425 ZTEST(lwm2m_engine, test_security)
426 {
427 	struct lwm2m_ctx ctx;
428 	char host_name[10] = "my_host";
429 
430 	(void)memset(&ctx, 0x0, sizeof(ctx));
431 	my_data_len = snprintk(my_buf, sizeof(my_buf), "-----BEGIN SOMETHING");
432 
433 	ctx.remote_addr.sa_family = AF_INET;
434 	ctx.sock_fd = -1;
435 	ctx.load_credentials = NULL;
436 	ctx.desthostname = host_name;
437 	ctx.desthostnamelen = strlen(host_name);
438 	ctx.use_dtls = false;
439 
440 	lwm2m_security_mode_fake.return_val = LWM2M_SECURITY_NOSEC;
441 
442 	zassert_equal(lwm2m_engine_start(&ctx), 0);
443 	zassert_equal(lwm2m_engine_stop(&ctx), 0);
444 
445 	ctx.use_dtls = true;
446 	zassert_equal(lwm2m_engine_start(&ctx), -EINVAL);
447 	zassert_equal(lwm2m_engine_stop(&ctx), 0);
448 
449 	RESET_FAKE(z_impl_zsock_setsockopt);
450 	lwm2m_security_mode_fake.return_val = LWM2M_SECURITY_PSK;
451 	zassert_equal(lwm2m_engine_start(&ctx), 0);
452 	zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[0], TLS_SEC_TAG_LIST);
453 	zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[1], TLS_PEER_VERIFY);
454 	zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[2], TLS_CIPHERSUITE_LIST);
455 	zassert_true(tls_credential_delete_fake.call_count > 3);
456 	zassert_true(tls_credential_add_fake.call_count == 2);
457 	zassert_equal(tls_credential_add_fake.arg1_history[0], TLS_CREDENTIAL_PSK_ID);
458 	zassert_equal(tls_credential_add_fake.arg1_history[1], TLS_CREDENTIAL_PSK);
459 	zassert_equal(lwm2m_engine_stop(&ctx), 0);
460 
461 	RESET_FAKE(z_impl_zsock_setsockopt);
462 	RESET_FAKE(tls_credential_add);
463 	lwm2m_security_mode_fake.return_val = LWM2M_SECURITY_CERT;
464 	ctx.desthostname = NULL;
465 	zassert_equal(lwm2m_engine_start(&ctx), 0);
466 	zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[0], TLS_SEC_TAG_LIST);
467 	zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[1], TLS_PEER_VERIFY);
468 	zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[2], TLS_CIPHERSUITE_LIST);
469 	zassert_true(tls_credential_add_fake.call_count == 3);
470 	zassert_equal(tls_credential_add_fake.arg1_history[0], TLS_CREDENTIAL_SERVER_CERTIFICATE);
471 	zassert_equal(tls_credential_add_fake.arg1_history[1], TLS_CREDENTIAL_PRIVATE_KEY);
472 	zassert_equal(tls_credential_add_fake.arg1_history[2], TLS_CREDENTIAL_CA_CERTIFICATE);
473 	zassert_equal(lwm2m_engine_stop(&ctx), 0);
474 }
475 
476 static enum lwm2m_socket_states last_state;
477 
socket_state(int fd,enum lwm2m_socket_states state)478 static void socket_state(int fd, enum lwm2m_socket_states state)
479 {
480 	(void) fd;
481 	last_state = state;
482 }
483 
ZTEST(lwm2m_engine,test_socket_state)484 ZTEST(lwm2m_engine, test_socket_state)
485 {
486 	int ret;
487 	struct lwm2m_ctx ctx = {
488 		.remote_addr.sa_family = AF_INET,
489 		.sock_fd = -1,
490 		.set_socket_state = socket_state,
491 	};
492 	struct lwm2m_message msg1 = {
493 		.ctx = &ctx,
494 		.type = COAP_TYPE_CON,
495 	};
496 	struct lwm2m_message msg2 = msg1;
497 	struct lwm2m_message ack = {
498 		.ctx = &ctx,
499 		.type = COAP_TYPE_ACK,
500 	};
501 
502 	sys_slist_init(&ctx.pending_sends);
503 	ret = lwm2m_engine_start(&ctx);
504 	zassert_equal(ret, 0);
505 
506 	/* One confimable in queue, should cause ONE_RESPONSE status */
507 	coap_pendings_count_fake.return_val = 1;
508 	sys_slist_append(&ctx.pending_sends, &msg1.node);
509 	set_socket_events(ZSOCK_POLLOUT);
510 	k_sleep(K_MSEC(100));
511 	zassert_equal(last_state, LWM2M_SOCKET_STATE_ONE_RESPONSE);
512 
513 	/* More than one messages in queue, not empty, should cause ONGOING */
514 	coap_pendings_count_fake.return_val = 2;
515 	sys_slist_append(&ctx.pending_sends, &msg1.node);
516 	sys_slist_append(&ctx.pending_sends, &msg2.node);
517 	set_socket_events(ZSOCK_POLLOUT);
518 	k_sleep(K_MSEC(100));
519 	zassert_equal(last_state, LWM2M_SOCKET_STATE_ONGOING);
520 
521 	/* Last out, while waiting for ACK to both, should still cause ONGOING */
522 	coap_pendings_count_fake.return_val = 2;
523 	set_socket_events(ZSOCK_POLLOUT);
524 	k_sleep(K_MSEC(100));
525 	zassert_equal(last_state, LWM2M_SOCKET_STATE_ONGOING);
526 
527 	/* Only one Ack transmiting, nothing expected back -> LAST */
528 	coap_pendings_count_fake.return_val = 0;
529 	sys_slist_append(&ctx.pending_sends, &ack.node);
530 	set_socket_events(ZSOCK_POLLOUT);
531 	k_sleep(K_MSEC(100));
532 	zassert_equal(last_state, LWM2M_SOCKET_STATE_LAST);
533 
534 	/* Socket suspended (as in QUEUE_RX_OFF), should cause NO_DATA */
535 	ret = lwm2m_socket_suspend(&ctx);
536 	zassert_equal(ret, 0);
537 	zassert_equal(last_state, LWM2M_SOCKET_STATE_NO_DATA);
538 
539 	ret = lwm2m_engine_stop(&ctx);
540 	zassert_equal(ret, 0);
541 }
542