1 /*
2 * Copyright (c) 2023 Gardena GmbH
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include "lwm2m_engine.h"
8 #include "lwm2m_object.h"
9
10 #include <zephyr/ztest.h>
11
12 /* Declaration of 'private' function */
13 int prepare_msg_for_send(struct lwm2m_message *msg);
14 int build_msg_block_for_send(struct lwm2m_message *msg, uint16_t block_num,
15 enum coap_block_size block_size);
16 int request_output_block_ctx(struct coap_block_context **ctx);
17 void release_output_block_ctx(struct coap_block_context ** const ctx);
18
19 BUILD_ASSERT(IS_ENABLED(CONFIG_LWM2M_COAP_BLOCK_TRANSFER),
20 "These tests expect to have block transfer enabled.");
21
22 #define EXPECTED_LWM2M_COAP_FULL_BUFFER_SIZE 256
23 BUILD_ASSERT(CONFIG_LWM2M_COAP_ENCODE_BUFFER_SIZE == EXPECTED_LWM2M_COAP_FULL_BUFFER_SIZE,
24 "The expected max message size is wrong.");
25
26 #define EXPECTED_NUM_OUTPUT_BLOCK_CONTEXT 3
27 BUILD_ASSERT(NUM_OUTPUT_BLOCK_CONTEXT == EXPECTED_NUM_OUTPUT_BLOCK_CONTEXT,
28 "The expected number of output block contexts is wrong.");
29
30 #define EXPECTED_DEFAULT_HEADER_OFFSET 4
31
32 struct net_block_transfer_fixture {
33 uint8_t dummy_msg[CONFIG_LWM2M_COAP_ENCODE_BUFFER_SIZE];
34 struct lwm2m_ctx ctx;
35 struct lwm2m_message msg;
36 };
37
net_block_transfer_setup(void)38 static void *net_block_transfer_setup(void)
39 {
40 static struct net_block_transfer_fixture f;
41
42 for (uint_fast16_t i = 0; i < ARRAY_SIZE(f.dummy_msg); ++i) {
43 f.dummy_msg[i] = (uint8_t)i;
44 }
45
46 return &f;
47 }
48
net_block_transfer_before(void * f)49 static void net_block_transfer_before(void *f)
50 {
51 struct net_block_transfer_fixture *fixture = (struct net_block_transfer_fixture *)f;
52
53 memset(&fixture->ctx, 0, sizeof(struct lwm2m_ctx));
54 memset(&fixture->msg, 0, sizeof(struct lwm2m_message));
55 fixture->msg.ctx = &fixture->ctx;
56 }
57
net_block_transfer_after(void * f)58 static void net_block_transfer_after(void *f)
59 {
60 struct net_block_transfer_fixture *fixture = (struct net_block_transfer_fixture *)f;
61
62 lwm2m_reset_message(&fixture->msg, true);
63 }
64
ZTEST_F(net_block_transfer,test_init_message_use_big_buffer)65 ZTEST_F(net_block_transfer, test_init_message_use_big_buffer)
66 {
67 int ret;
68 struct lwm2m_message *msg = &fixture->msg;
69
70
71 ret = lwm2m_init_message(msg);
72 zassert_ok(ret, "Failed to initialize lwm2m message");
73
74 zassert_not_equal(msg->msg_data, msg->cpkt.data,
75 "Default data buffer should not be used for writing body");
76 zassert_equal(msg->cpkt.data, msg->body_encode_buffer.data,
77 "Full body buffer should be in use");
78
79 zassert_equal(EXPECTED_LWM2M_COAP_FULL_BUFFER_SIZE, msg->cpkt.max_len,
80 "Max length for the package is wrong");
81
82 zassert_equal(EXPECTED_DEFAULT_HEADER_OFFSET, msg->cpkt.offset);
83
84 /* write to buffer in a similar way as the writers */
85 msg->out.out_cpkt = &msg->cpkt;
86 ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), fixture->dummy_msg,
87 EXPECTED_LWM2M_COAP_FULL_BUFFER_SIZE - EXPECTED_DEFAULT_HEADER_OFFSET);
88 zassert_ok(ret, "Should be able to write to buffer");
89 zassert_equal(msg->cpkt.max_len, msg->cpkt.offset, "Buffer should be full");
90
91 const uint8_t one_byte = 0xAB;
92
93 ret = buf_append(CPKT_BUF_WRITE(msg->out.out_cpkt), &one_byte, 1);
94 zassert_equal(ret, -ENOMEM, "Should not be able to write to full buffer");
95 }
96
97 #define EXPECTED_HEADERS_LEN 7
ZTEST_F(net_block_transfer,test_one_block_with_big_buffer)98 ZTEST_F(net_block_transfer, test_one_block_with_big_buffer)
99 {
100 int ret;
101 struct lwm2m_message *msg = &fixture->msg;
102
103 /* Arrange */
104 ret = lwm2m_init_message(msg);
105 zassert_equal(0, ret, "Failed to initialize lwm2m message");
106
107 zassert_not_equal(msg->msg_data, msg->cpkt.data,
108 "Big body data buffer should be used for writing body");
109 zassert_equal(msg->cpkt.data, msg->body_encode_buffer.data,
110 "Full body buffer should be in use");
111
112 ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_CONTENT_FORMAT,
113 COAP_CONTENT_FORMAT_APP_LINK_FORMAT);
114 zassert_equal(0, ret, "Not able to append option");
115
116 ret = coap_packet_append_payload_marker(&msg->cpkt);
117 zassert_equal(0, ret, "Not able to append payload marker");
118
119 ret = buf_append(CPKT_BUF_WRITE(&msg->cpkt), fixture->dummy_msg,
120 CONFIG_LWM2M_COAP_BLOCK_SIZE);
121 zassert_ok(ret, "Should be able to write to buffer");
122
123 uint16_t payload_len;
124
125 coap_packet_get_payload(&msg->cpkt, &payload_len);
126 zassert_equal(payload_len, CONFIG_LWM2M_COAP_BLOCK_SIZE,
127 "Block was not filled as expected");
128
129 /* Act */
130 ret = prepare_msg_for_send(msg);
131 zassert_equal(0, ret, "Preparing message for sending failed");
132
133 /* Assert */
134 zassert_equal(msg->msg_data, msg->cpkt.data,
135 "Default data buffer should be used for sending the block");
136 zassert_is_null(msg->body_encode_buffer.data, "Complete body buffer should not be set");
137
138 const uint8_t *payload = coap_packet_get_payload(&msg->cpkt, &payload_len);
139
140 zassert_not_null(payload, "Payload expected");
141 zassert_equal(payload_len, CONFIG_LWM2M_COAP_BLOCK_SIZE,
142 "Block was not filled as expected");
143
144 zassert_equal(EXPECTED_HEADERS_LEN, msg->cpkt.hdr_len + msg->cpkt.opt_len + 1,
145 "Headers length not as expected");
146 /* payload should start after headers, options and payload marker (size: 1) */
147 zassert_equal(payload, msg->cpkt.data + EXPECTED_HEADERS_LEN,
148 "Payload not starting at expected address");
149
150 const uint8_t expected_headers[EXPECTED_HEADERS_LEN] = {0x40, 0, 0, 0, 0xc1, 0x28, 0xff};
151
152 zassert_mem_equal(msg->cpkt.data, expected_headers, EXPECTED_HEADERS_LEN,
153 "Payload not starting at expected address");
154
155 /* check payload */
156 for (uint_fast8_t i = 0; i < payload_len; ++i) {
157 zassert_equal(payload[i], i, "Byte %i in payload is wrong", i);
158 }
159
160 /* check first byte after payload */
161 zassert_equal(payload[payload_len], 0x00, "Byte after payload is wrong");
162 }
163
ZTEST_F(net_block_transfer,test_build_first_block_for_send)164 ZTEST_F(net_block_transfer, test_build_first_block_for_send)
165 {
166 int ret;
167 struct lwm2m_message *msg = &fixture->msg;
168 uint16_t payload_len;
169
170 /* Arrange */
171 msg->code = COAP_METHOD_GET;
172 ret = lwm2m_init_message(msg);
173 zassert_equal(0, ret, "Failed to initialize lwm2m message");
174
175 ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_CONTENT_FORMAT,
176 COAP_CONTENT_FORMAT_APP_LINK_FORMAT);
177 zassert_equal(0, ret, "Not able to append option");
178
179 ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_ACCEPT, COAP_CONTENT_FORMAT_APP_JSON);
180 zassert_equal(0, ret, "Not able to append option");
181
182 const uint8_t expected_header_len = 4;
183
184 zassert_equal(msg->cpkt.hdr_len, expected_header_len, "Header length not as expected");
185
186 const uint8_t expected_options_len = 4;
187
188 zassert_equal(msg->cpkt.opt_len, expected_options_len, "Options length not as expected");
189
190 ret = coap_packet_append_payload_marker(&msg->cpkt);
191 zassert_equal(0, ret, "Not able to append payload marker");
192
193 ret = buf_append(CPKT_BUF_WRITE(&msg->cpkt), fixture->dummy_msg,
194 2 * CONFIG_LWM2M_COAP_BLOCK_SIZE);
195 zassert_ok(ret, "Should be able to write to buffer");
196
197 zassert_not_equal(msg->msg_data, msg->cpkt.data, "Buffer for block data is not yet in use");
198
199 /* Act */
200 ret = prepare_msg_for_send(msg);
201 zassert_equal(ret, 0, "Could not create first block");
202
203 /* Assert */
204 zassert_equal(msg->msg_data, msg->cpkt.data, "Buffer for block data is not in use");
205
206 ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1);
207 zassert(ret > 0, "block 1 option not set");
208
209 const uint8_t *payload = coap_packet_get_payload(&msg->cpkt, &payload_len);
210
211 zassert_not_null(payload, "Payload expected");
212 zassert_equal(payload_len, CONFIG_LWM2M_COAP_BLOCK_SIZE, "Wrong payload size");
213 zassert_equal(0x00, payload[0], "First byte in payload wrong");
214 zassert_equal(0x3f, payload[CONFIG_LWM2M_COAP_BLOCK_SIZE - 1],
215 "Last byte in payload wrong");
216 }
217
ZTEST_F(net_block_transfer,test_build_blocks_for_send_exactly_2_blocks)218 ZTEST_F(net_block_transfer, test_build_blocks_for_send_exactly_2_blocks)
219 {
220 int ret;
221 struct lwm2m_message *msg = &fixture->msg;
222 uint16_t payload_len;
223 const uint8_t *payload;
224
225 /* Arrange */
226 msg->code = COAP_METHOD_PUT;
227 ret = lwm2m_init_message(msg);
228 zassert_equal(0, ret, "Failed to initialize lwm2m message");
229
230 const uint8_t *query = "query";
231
232 ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_URI_QUERY, query, strlen(query));
233 zassert_equal(0, ret, "Not able to append option");
234
235 ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_ACCEPT,
236 COAP_CONTENT_FORMAT_TEXT_PLAIN);
237 zassert_equal(0, ret, "Not able to append option");
238
239 const uint8_t expected_header_len = 4;
240
241 zassert_equal(msg->cpkt.hdr_len, expected_header_len, "Header length not as expected");
242
243 const uint8_t expected_options_len = 8;
244
245 zassert_equal(msg->cpkt.opt_len, expected_options_len, "Options length not as expected");
246
247 ret = coap_packet_append_payload_marker(&msg->cpkt);
248 zassert_equal(0, ret, "Not able to append payload marker");
249
250 ret = buf_append(CPKT_BUF_WRITE(&msg->cpkt), fixture->dummy_msg,
251 2 * CONFIG_LWM2M_COAP_BLOCK_SIZE);
252 zassert_ok(ret, "Should be able to write to buffer");
253
254 zassert_not_equal(msg->msg_data, msg->cpkt.data, "Buffer for block data is not yet in use");
255
256 /* block 0 */
257 ret = prepare_msg_for_send(msg);
258 zassert_equal(ret, 0, "Could not create first block");
259
260 zassert_equal(msg->msg_data, msg->cpkt.data, "Buffer for block data is not in use");
261
262 ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1);
263 zassert(ret > 0, "block 1 option not set");
264
265 payload = coap_packet_get_payload(&msg->cpkt, &payload_len);
266
267 zassert_not_null(payload, "Payload expected");
268 zassert_equal(payload_len, CONFIG_LWM2M_COAP_BLOCK_SIZE, "Wrong payload size");
269 zassert_equal(0x00, payload[0], "First byte in payload wrong");
270 zassert_equal(0x3f, payload[CONFIG_LWM2M_COAP_BLOCK_SIZE - 1],
271 "Last byte in payload wrong");
272
273 /* block 1 */
274 ret = build_msg_block_for_send(msg, 1, COAP_BLOCK_64);
275 zassert_equal(ret, 0, "Could not create second block");
276
277 ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1);
278 zassert(ret > 0, "block 1 option not set");
279
280 payload = coap_packet_get_payload(&msg->cpkt, &payload_len);
281
282 zassert_not_null(payload, "Payload expected");
283 zassert_equal(payload_len, CONFIG_LWM2M_COAP_BLOCK_SIZE, "Wrong payload size");
284 zassert_equal(0x40, payload[0], "First byte in payload wrong");
285 zassert_equal(0x7f, payload[CONFIG_LWM2M_COAP_BLOCK_SIZE - 1],
286 "Last byte in payload wrong");
287
288 /* block 2 doesn't exist */
289 ret = build_msg_block_for_send(msg, 2, COAP_BLOCK_64);
290 zassert_equal(ret, -EINVAL, "Could not create second block");
291 }
292
ZTEST_F(net_block_transfer,test_build_blocks_for_send_more_than_2_blocks)293 ZTEST_F(net_block_transfer, test_build_blocks_for_send_more_than_2_blocks)
294 {
295 int ret;
296 struct lwm2m_message *msg = &fixture->msg;
297 uint16_t payload_len;
298 const uint8_t *payload;
299
300 /* Arrange */
301 msg->code = COAP_METHOD_DELETE;
302 ret = lwm2m_init_message(msg);
303 zassert_equal(0, ret, "Failed to initialize lwm2m message");
304
305 const uint8_t *proxy_scheme = "coap";
306
307 ret = coap_packet_append_option(&msg->cpkt, COAP_OPTION_PROXY_SCHEME, proxy_scheme,
308 strlen(proxy_scheme));
309 zassert_equal(0, ret, "Not able to append option");
310
311 ret = coap_append_option_int(&msg->cpkt, COAP_OPTION_CONTENT_FORMAT,
312 COAP_CONTENT_FORMAT_APP_JSON);
313 zassert_equal(0, ret, "Not able to append option");
314
315 const uint8_t expected_header_len = 4;
316
317 zassert_equal(msg->cpkt.hdr_len, expected_header_len, "Header length not as expected");
318
319 const uint8_t expected_options_len = 8;
320
321 zassert_equal(msg->cpkt.opt_len, expected_options_len, "Options length not as expected");
322
323 ret = coap_packet_append_payload_marker(&msg->cpkt);
324 zassert_equal(0, ret, "Not able to append payload marker");
325
326 ret = buf_append(CPKT_BUF_WRITE(&msg->cpkt), fixture->dummy_msg,
327 2 * CONFIG_LWM2M_COAP_BLOCK_SIZE + 1);
328 zassert_ok(ret, "Should be able to write to buffer");
329
330 zassert_not_equal(msg->msg_data, msg->cpkt.data, "Buffer for block data is not yet in use");
331
332 /* block 0 */
333 ret = prepare_msg_for_send(msg);
334 zassert_equal(ret, 0, "Could not create first block");
335
336 zassert_equal(msg->msg_data, msg->cpkt.data, "Buffer for block data is not in use");
337
338 ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1);
339 zassert(ret > 0, "block 1 option not set");
340
341 payload = coap_packet_get_payload(&msg->cpkt, &payload_len);
342
343 zassert_not_null(payload, "Payload expected");
344 zassert_equal(payload_len, CONFIG_LWM2M_COAP_BLOCK_SIZE, "Wrong payload size");
345 zassert_equal(0x00, payload[0], "First byte in payload wrong");
346 zassert_equal(0x3f, payload[CONFIG_LWM2M_COAP_BLOCK_SIZE - 1],
347 "Last byte in payload wrong");
348
349 /* block 1 */
350 ret = build_msg_block_for_send(msg, 1, COAP_BLOCK_64);
351 zassert_equal(ret, 0, "Could not create second block");
352
353 ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1);
354 zassert(ret > 0, "block 1 option not set");
355
356 payload = coap_packet_get_payload(&msg->cpkt, &payload_len);
357
358 zassert_not_null(payload, "Payload expected");
359 zassert_equal(payload_len, CONFIG_LWM2M_COAP_BLOCK_SIZE, "Wrong payload size");
360 zassert_equal(0x40, payload[0], "First byte in payload wrong");
361 zassert_equal(0x7f, payload[CONFIG_LWM2M_COAP_BLOCK_SIZE - 1],
362 "Last byte in payload wrong");
363
364 /* block 2 */
365 ret = build_msg_block_for_send(msg, 2, COAP_BLOCK_64);
366 zassert_equal(ret, 0, "Could not create second block");
367
368 ret = coap_get_option_int(&msg->cpkt, COAP_OPTION_BLOCK1);
369 zassert(ret > 0, "block 1 option not set");
370
371 payload = coap_packet_get_payload(&msg->cpkt, &payload_len);
372
373 zassert_not_null(payload, "Payload expected");
374 zassert_equal(payload_len, 1, "Wrong payload size");
375 zassert_equal(0x80, payload[0], "First (and only) byte in payload wrong");
376
377 /* block 3 doesn't exist */
378 ret = build_msg_block_for_send(msg, 3, COAP_BLOCK_64);
379 zassert_equal(ret, -EINVAL, "Could not create second block");
380 }
381
ZTEST_F(net_block_transfer,test_block_context)382 ZTEST_F(net_block_transfer, test_block_context)
383 {
384 struct coap_block_context *ctx0, *ctx1, *ctx2, *ctx3, *ctx4;
385 int ret;
386
387 zassert_equal(NUM_OUTPUT_BLOCK_CONTEXT, 3);
388
389 /* block context 0 */
390 ret = request_output_block_ctx(&ctx0);
391 zassert_ok(ret);
392 zassert_not_null(ctx0);
393 /* block context 1 */
394 ret = request_output_block_ctx(&ctx1);
395 zassert_ok(ret);
396 zassert_not_null(ctx1);
397 /* block context 2 */
398 ret = request_output_block_ctx(&ctx2);
399 zassert_ok(ret);
400 zassert_not_null(ctx2);
401
402 /* Get one context more than available */
403 ret = request_output_block_ctx(&ctx3);
404 zassert_equal(ret, -ENOMEM);
405 zassert_is_null(ctx3);
406
407 /* release one block context */
408 release_output_block_ctx(&ctx2);
409 zassert_is_null(ctx2);
410
411 /* get another block context */
412 ret = request_output_block_ctx(&ctx4);
413 zassert_ok(ret);
414 zassert_not_null(ctx4);
415
416 /* release all block contexts */
417 release_output_block_ctx(&ctx0);
418 zassert_is_null(ctx0);
419 release_output_block_ctx(&ctx1);
420 zassert_is_null(ctx1);
421 release_output_block_ctx(&ctx2);
422 zassert_is_null(ctx2);
423 release_output_block_ctx(&ctx3);
424 zassert_is_null(ctx3);
425 release_output_block_ctx(&ctx4);
426 zassert_is_null(ctx4);
427 }
428
429 ZTEST_SUITE(net_block_transfer, NULL, net_block_transfer_setup, net_block_transfer_before,
430 net_block_transfer_after, NULL);
431