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 if (buffer_len)
38 *buffer_len = sizeof(my_buf);
39 if (data_len)
40 *data_len = my_data_len;
41
42 return 0;
43 }
44
find_msg_custom_fake(struct coap_pending * pending,struct coap_reply * reply)45 static struct lwm2m_message *find_msg_custom_fake(struct coap_pending *pending,
46 struct coap_reply *reply)
47 {
48 return &my_msg;
49 }
50
51 static struct lwm2m_engine_obj_field *
lwm2m_get_engine_obj_field_custom_fake(struct lwm2m_engine_obj * obj,int res_id)52 lwm2m_get_engine_obj_field_custom_fake(struct lwm2m_engine_obj *obj, int res_id)
53 {
54 return &my_obj_field;
55 }
56
lwm2m_get_bool_custom_fake(const struct lwm2m_obj_path * path,bool * value)57 static int lwm2m_get_bool_custom_fake(const struct lwm2m_obj_path *path, bool *value)
58 {
59 *value = false;
60
61 return 0;
62 }
63
test_service(struct k_work * work)64 static void test_service(struct k_work *work)
65 {
66 k_sleep(K_MSEC(10));
67 }
68
setup(void * data)69 static void setup(void *data)
70 {
71 #if defined(CONFIG_NATIVE_SIM_SLOWDOWN_TO_REAL_TIME)
72 /* It is enough that some slow-down is happening on sleeps, it does not have to be
73 * real time
74 */
75 hwtimer_set_rt_ratio(100.0);
76 #endif
77 /* Register resets */
78 DO_FOREACH_FAKE(RESET_FAKE);
79
80 /* reset common FFF internal structures */
81 FFF_RESET_HISTORY();
82
83 clear_socket_events();
84 lwm2m_get_res_buf_fake.custom_fake = lwm2m_get_res_buf_custom_fake;
85 find_msg_fake.custom_fake = find_msg_custom_fake;
86 lwm2m_get_engine_obj_field_fake.custom_fake = lwm2m_get_engine_obj_field_custom_fake;
87 lwm2m_get_bool_fake.custom_fake = lwm2m_get_bool_custom_fake;
88 }
89
90 ZTEST_SUITE(lwm2m_engine, NULL, NULL, setup, NULL, NULL);
91
ZTEST(lwm2m_engine,test_start_stop)92 ZTEST(lwm2m_engine, test_start_stop)
93 {
94 int ret;
95 struct lwm2m_ctx ctx;
96 char host_name[10] = "my_host";
97
98 (void)memset(&ctx, 0x0, sizeof(ctx));
99
100 ctx.remote_addr.sa_family = AF_INET;
101 ctx.sock_fd = -1;
102 ctx.load_credentials = NULL;
103 ctx.desthostname = host_name;
104 ctx.desthostnamelen = strlen(host_name);
105 ctx.hostname_verify = true;
106 ctx.use_dtls = true;
107
108 ret = lwm2m_engine_start(&ctx);
109 zassert_equal(ret, 0);
110
111 struct lwm2m_ctx **eng_ctx = lwm2m_sock_ctx();
112 int nfds = lwm2m_sock_nfds();
113
114 zassert_not_null(eng_ctx);
115 zassert_true(nfds > 0);
116 zassert_equal(eng_ctx[0], &ctx);
117
118 /* wait for socket receive thread */
119 k_sleep(K_MSEC(1000));
120 ret = lwm2m_engine_stop(&ctx);
121 zassert_equal(ret, 0);
122 }
123
ZTEST(lwm2m_engine,test_pause_resume)124 ZTEST(lwm2m_engine, test_pause_resume)
125 {
126 int ret;
127 struct lwm2m_ctx ctx;
128
129 (void)memset(&ctx, 0x0, sizeof(ctx));
130
131 ctx.remote_addr.sa_family = AF_INET;
132 ctx.sock_fd = -1;
133 ctx.load_credentials = NULL;
134
135 ret = lwm2m_engine_start(&ctx);
136 zassert_equal(ret, 0);
137 ret = lwm2m_engine_resume();
138 zassert_equal(ret, -EPERM);
139 ret = lwm2m_engine_pause();
140 zassert_equal(ret, 0);
141 ret = lwm2m_engine_pause();
142 zassert_equal(ret, 0);
143 ret = lwm2m_engine_resume();
144 zassert_equal(ret, 0);
145 ret = lwm2m_engine_stop(&ctx);
146 zassert_equal(ret, 0);
147 }
148
ZTEST(lwm2m_engine,test_engine_add_service)149 ZTEST(lwm2m_engine, test_engine_add_service)
150 {
151 int ret;
152 struct lwm2m_ctx ctx;
153
154 (void)memset(&ctx, 0x0, sizeof(ctx));
155
156 ctx.remote_addr.sa_family = AF_INET;
157 ctx.load_credentials = NULL;
158
159 ret = lwm2m_engine_start(&ctx);
160 zassert_equal(ret, 0);
161 ret = lwm2m_engine_add_service(test_service, 1000);
162 zassert_equal(ret, 0);
163 /* wait for socket receive thread */
164 k_sleep(K_MSEC(1500));
165 ret = lwm2m_engine_update_service_period(test_service, 500);
166 zassert_equal(ret, 0);
167 ret = lwm2m_engine_stop(&ctx);
168 zassert_equal(ret, 0);
169 }
170
ZTEST(lwm2m_engine,test_no_sa_family)171 ZTEST(lwm2m_engine, test_no_sa_family)
172 {
173 int ret;
174 struct lwm2m_ctx ctx;
175
176 (void)memset(&ctx, 0x0, sizeof(ctx));
177
178 ctx.sock_fd = -1;
179 ctx.load_credentials = NULL;
180
181 ret = lwm2m_engine_start(&ctx);
182 zassert_equal(ret, -EPROTONOSUPPORT);
183 lwm2m_engine_stop(&ctx);
184 }
185
ZTEST(lwm2m_engine,test_connect_fail)186 ZTEST(lwm2m_engine, test_connect_fail)
187 {
188 int ret;
189 struct lwm2m_ctx ctx;
190
191 (void)memset(&ctx, 0x0, sizeof(ctx));
192
193 ctx.sock_fd = -1;
194 ctx.load_credentials = NULL;
195 ctx.remote_addr.sa_family = AF_INET;
196
197 errno = ENETDOWN;
198 z_impl_zsock_connect_fake.return_val = -1;
199 ret = lwm2m_engine_start(&ctx);
200 zassert_equal(ret, -ENETDOWN);
201 lwm2m_engine_stop(&ctx);
202 }
203
ZTEST(lwm2m_engine,test_socket_suspend_resume_connection)204 ZTEST(lwm2m_engine, test_socket_suspend_resume_connection)
205 {
206 int ret;
207 struct lwm2m_ctx ctx;
208
209 (void)memset(&ctx, 0x0, sizeof(ctx));
210
211 ctx.sock_fd = -1;
212 ctx.load_credentials = NULL;
213 ctx.remote_addr.sa_family = AF_INET;
214
215 ret = lwm2m_engine_start(&ctx);
216 zassert_equal(ret, 0);
217 ret = lwm2m_socket_suspend(&ctx);
218 zassert_equal(ret, 0);
219 zassert_equal(ctx.connection_suspended, true);
220 ret = lwm2m_engine_connection_resume(&ctx);
221 zassert_equal(ret, 0);
222 zassert_equal(ctx.connection_suspended, false);
223 lwm2m_engine_stop(&ctx);
224 }
225
ZTEST(lwm2m_engine,test_check_notifications)226 ZTEST(lwm2m_engine, test_check_notifications)
227 {
228 int ret;
229 struct lwm2m_ctx ctx;
230 struct observe_node obs;
231
232 (void)memset(&ctx, 0x0, sizeof(ctx));
233
234 ctx.sock_fd = -1;
235 ctx.load_credentials = NULL;
236 ctx.remote_addr.sa_family = AF_INET;
237 sys_slist_init(&ctx.observer);
238
239 obs.last_timestamp = k_uptime_get();
240 obs.event_timestamp = k_uptime_get() + 1000U;
241 obs.resource_update = false;
242 obs.active_notify = NULL;
243
244 sys_slist_append(&ctx.observer, &obs.node);
245
246 lwm2m_rd_client_is_registred_fake.return_val = true;
247 ret = lwm2m_engine_start(&ctx);
248 zassert_equal(ret, 0);
249 /* wait for socket receive thread */
250 k_sleep(K_MSEC(2000));
251 ret = lwm2m_engine_stop(&ctx);
252 zassert_equal(ret, 0);
253 zassert_equal(generate_notify_message_fake.call_count, 1, "Notify message not generated");
254 zassert_equal(engine_observe_shedule_next_event_fake.call_count, 1,
255 "Next observe event not scheduled");
256 }
257
ZTEST(lwm2m_engine,test_push_queued_buffers)258 ZTEST(lwm2m_engine, test_push_queued_buffers)
259 {
260 int ret;
261 struct lwm2m_ctx ctx;
262 struct lwm2m_message msg;
263 struct coap_pending pending;
264
265 (void)memset(&ctx, 0x0, sizeof(ctx));
266
267 sys_slist_init(&ctx.queued_messages);
268 msg.ctx = &ctx;
269 msg.pending = &pending;
270 sys_slist_append(&ctx.queued_messages, &msg.node);
271 ret = lwm2m_push_queued_buffers(&ctx);
272 zassert_equal(ret, 0);
273 }
274
ZTEST(lwm2m_engine,test_validate_write_access)275 ZTEST(lwm2m_engine, test_validate_write_access)
276 {
277 int ret;
278 struct lwm2m_ctx ctx;
279 struct lwm2m_message msg;
280 struct lwm2m_engine_res resources;
281 struct lwm2m_engine_obj_inst obj_inst;
282 struct lwm2m_engine_obj_field *obj_field = NULL;
283
284 (void)memset(&ctx, 0x0, sizeof(ctx));
285
286 ctx.bootstrap_mode = true;
287 msg.ctx = &ctx;
288 msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0);
289 obj_inst.resources = &resources;
290 obj_inst.resource_count = 1U;
291 ret = lwm2m_engine_validate_write_access(&msg, &obj_inst, &obj_field);
292 zassert_equal(ret, 0);
293
294 obj_inst.resource_count = 0U;
295 ret = lwm2m_engine_validate_write_access(&msg, &obj_inst, &obj_field);
296 zassert_equal(ret, -EINVAL);
297
298 msg.path = LWM2M_OBJ(LWM2M_OBJECT_DEVICE_ID, 0);
299 ret = lwm2m_engine_validate_write_access(&msg, &obj_inst, &obj_field);
300 zassert_equal(ret, -EPERM);
301 }
302
ZTEST(lwm2m_engine,test_bootstrap_delete)303 ZTEST(lwm2m_engine, test_bootstrap_delete)
304 {
305 int ret;
306 struct lwm2m_message msg;
307
308 msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 0, 0);
309 ret = bootstrap_delete(&msg);
310 zassert_equal(ret, -EPERM);
311
312 msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID, 1);
313 ret = bootstrap_delete(&msg);
314 zassert_equal(ret, 0);
315 zassert_equal(0, lwm2m_delete_obj_inst_fake.arg0_history[0]);
316 zassert_equal(1, lwm2m_delete_obj_inst_fake.arg1_history[0]);
317
318
319 struct lwm2m_engine_obj sec_obj = {.obj_id = 0};
320 struct lwm2m_engine_obj_inst sec_inst = {
321 .obj_inst_id = 2,
322 .obj = &sec_obj
323 };
324 sys_slist_append(lwm2m_engine_obj_inst_list(), &sec_inst.node);
325
326 msg.path = LWM2M_OBJ(LWM2M_OBJECT_SECURITY_ID);
327 ret = bootstrap_delete(&msg);
328 zassert_equal(ret, 0);
329 zassert_equal(0, lwm2m_delete_obj_inst_fake.arg0_history[1]);
330 zassert_equal(2, lwm2m_delete_obj_inst_fake.arg1_history[1]);
331
332 msg.path = LWM2M_OBJ(LWM2M_OBJECT_DEVICE_ID, 0);
333 ret = bootstrap_delete(&msg);
334 zassert_equal(ret, -EPERM);
335 }
336
ZTEST(lwm2m_engine,test_retransmit_request)337 ZTEST(lwm2m_engine, test_retransmit_request)
338 {
339 int ret;
340 struct lwm2m_ctx ctx;
341 struct coap_pending pending_1;
342 struct coap_pending pending_2;
343
344 (void)memset(&ctx, 0x0, sizeof(ctx));
345
346 ctx.sock_fd = -1;
347 ctx.load_credentials = NULL;
348 ctx.remote_addr.sa_family = AF_INET;
349
350 pending_1.t0 = k_uptime_get();
351 pending_1.timeout = 200U;
352 pending_1.retries = 0;
353 ctx.pendings[0] = pending_1;
354
355 pending_2.t0 = k_uptime_get();
356 pending_2.timeout = 200U;
357 pending_2.retries = 1;
358 ctx.pendings[1] = pending_2;
359
360 ret = lwm2m_engine_start(&ctx);
361 zassert_equal(ret, 0);
362 /* wait for socket receive thread */
363 k_sleep(K_MSEC(500));
364 ret = lwm2m_engine_stop(&ctx);
365 zassert_equal(ret, 0);
366 zassert_not_equal(lwm2m_reset_message_fake.call_count, 0, "Message was not reseted");
367 zassert_not_equal(lwm2m_send_message_async_fake.call_count, 0, "Message was not sent");
368 }
369
ZTEST(lwm2m_engine,test_socket_recv)370 ZTEST(lwm2m_engine, test_socket_recv)
371 {
372 int ret;
373 struct lwm2m_ctx ctx;
374
375 (void)memset(&ctx, 0x0, sizeof(ctx));
376
377 ctx.remote_addr.sa_family = AF_INET;
378 ctx.sock_fd = -1;
379
380 set_socket_events(ZSOCK_POLLIN);
381
382 ret = lwm2m_engine_start(&ctx);
383 zassert_equal(ret, 0);
384 /* wait for socket receive thread */
385 k_sleep(K_MSEC(1000));
386 ret = lwm2m_engine_stop(&ctx);
387 zassert_equal(ret, 0);
388 zassert_true(lwm2m_udp_receive_fake.call_count > 0);
389 }
390
ZTEST(lwm2m_engine,test_socket_send)391 ZTEST(lwm2m_engine, test_socket_send)
392 {
393 int ret;
394 struct lwm2m_ctx ctx;
395 struct lwm2m_message msg;
396 struct coap_pending pending;
397
398 (void)memset(&ctx, 0x0, sizeof(ctx));
399
400 ctx.remote_addr.sa_family = AF_INET;
401 ctx.sock_fd = -1;
402 sys_slist_init(&ctx.queued_messages);
403 msg.ctx = &ctx;
404 msg.pending = &pending;
405 msg.type = COAP_TYPE_CON;
406 sys_slist_append(&ctx.queued_messages, &msg.node);
407
408 ret = lwm2m_push_queued_buffers(&ctx);
409 zassert_equal(ret, 0);
410
411 set_socket_events(ZSOCK_POLLOUT);
412
413 ret = lwm2m_engine_start(&ctx);
414 zassert_equal(ret, 0);
415 /* wait for socket receive thread */
416 k_sleep(K_MSEC(2000));
417 ret = lwm2m_engine_stop(&ctx);
418 zassert_equal(ret, 0);
419 LOG_INF("Count %d", coap_pending_cycle_fake.call_count);
420 zassert_equal(coap_pending_cycle_fake.call_count, 1, "coap_pending_cycle not called");
421 }
422
ZTEST(lwm2m_engine,test_security)423 ZTEST(lwm2m_engine, test_security)
424 {
425 struct lwm2m_ctx ctx;
426 char host_name[10] = "my_host";
427
428 (void)memset(&ctx, 0x0, sizeof(ctx));
429 my_data_len = snprintk(my_buf, sizeof(my_buf), "-----BEGIN SOMETHING");
430
431 ctx.remote_addr.sa_family = AF_INET;
432 ctx.sock_fd = -1;
433 ctx.load_credentials = NULL;
434 ctx.desthostname = host_name;
435 ctx.desthostnamelen = strlen(host_name);
436 ctx.hostname_verify = true;
437 ctx.use_dtls = false;
438
439 lwm2m_security_mode_fake.return_val = LWM2M_SECURITY_NOSEC;
440
441 zassert_equal(lwm2m_engine_start(&ctx), 0);
442 zassert_equal(lwm2m_engine_stop(&ctx), 0);
443
444 ctx.use_dtls = true;
445 zassert_equal(lwm2m_engine_start(&ctx), -EINVAL);
446 zassert_equal(lwm2m_engine_stop(&ctx), 0);
447
448 RESET_FAKE(z_impl_zsock_setsockopt);
449 lwm2m_security_mode_fake.return_val = LWM2M_SECURITY_PSK;
450 zassert_equal(lwm2m_engine_start(&ctx), 0);
451 zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[0], TLS_SEC_TAG_LIST);
452 zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[1], TLS_HOSTNAME);
453 zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[2], TLS_PEER_VERIFY);
454 zassert_equal(z_impl_zsock_setsockopt_fake.arg2_history[3], 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.hostname_verify = false;
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