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