1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /** @file mqtt_encoder.c
8 *
9 * @brief Encoding functions needed to create packet to be sent to the broker.
10 */
11
12 #include <zephyr/logging/log.h>
13 LOG_MODULE_REGISTER(net_mqtt_enc, CONFIG_MQTT_LOG_LEVEL);
14
15 #include "mqtt_internal.h"
16 #include "mqtt_os.h"
17
18 static const struct mqtt_utf8 mqtt_3_1_0_proto_desc =
19 MQTT_UTF8_LITERAL("MQIsdp");
20
21 static const struct mqtt_utf8 mqtt_proto_desc =
22 MQTT_UTF8_LITERAL("MQTT");
23
24 /** Never changing ping request, needed for Keep Alive. */
25 static const uint8_t ping_packet[MQTT_FIXED_HEADER_MIN_SIZE] = {
26 MQTT_PKT_TYPE_PINGREQ,
27 0x00
28 };
29
30 /** Never changing disconnect request. */
31 static const uint8_t empty_disc_packet[MQTT_FIXED_HEADER_MIN_SIZE] = {
32 MQTT_PKT_TYPE_DISCONNECT,
33 0x00
34 };
35
36 /**
37 * @brief Packs unsigned 8 bit value to the buffer at the offset requested.
38 *
39 * @param[in] val Value to be packed.
40 * @param[inout] buf A pointer to the buf_ctx structure containing current
41 * buffer position.
42 *
43 * @retval 0 if procedure is successful.
44 * @retval -ENOMEM if there is no place in the buffer to store the value.
45 */
pack_uint8(uint8_t val,struct buf_ctx * buf)46 static int pack_uint8(uint8_t val, struct buf_ctx *buf)
47 {
48 uint8_t *cur = buf->cur;
49 uint8_t *end = buf->end;
50
51 if ((end - cur) < sizeof(uint8_t)) {
52 return -ENOMEM;
53 }
54
55 NET_DBG(">> val:%02x cur:%p, end:%p", val, (void *)cur, (void *)end);
56
57 /* Pack value. */
58 cur[0] = val;
59 buf->cur = (cur + sizeof(uint8_t));
60
61 return 0;
62 }
63
64 /**
65 * @brief Packs unsigned 16 bit value to the buffer at the offset requested.
66 *
67 * @param[in] val Value to be packed.
68 * @param[inout] buf A pointer to the buf_ctx structure containing current
69 * buffer position.
70 *
71 * @retval 0 if the procedure is successful.
72 * @retval -ENOMEM if there is no place in the buffer to store the value.
73 */
pack_uint16(uint16_t val,struct buf_ctx * buf)74 static int pack_uint16(uint16_t val, struct buf_ctx *buf)
75 {
76 uint8_t *cur = buf->cur;
77 uint8_t *end = buf->end;
78
79 if ((end - cur) < sizeof(uint16_t)) {
80 return -ENOMEM;
81 }
82
83 NET_DBG(">> val:%04x cur:%p, end:%p", val, (void *)cur, (void *)end);
84
85 /* Pack value. */
86 sys_put_be16(val, cur);
87 buf->cur = (cur + sizeof(uint16_t));
88
89 return 0;
90 }
91
92 /**
93 * @brief Packs utf8 string to the buffer at the offset requested.
94 *
95 * @param[in] str UTF-8 string and its length to be packed.
96 * @param[inout] buf A pointer to the buf_ctx structure containing current
97 * buffer position.
98 *
99 * @retval 0 if the procedure is successful.
100 * @retval -ENOMEM if there is no place in the buffer to store the string.
101 */
pack_utf8_str(const struct mqtt_utf8 * str,struct buf_ctx * buf)102 static int pack_utf8_str(const struct mqtt_utf8 *str, struct buf_ctx *buf)
103 {
104 if ((buf->end - buf->cur) < GET_UT8STR_BUFFER_SIZE(str)) {
105 return -ENOMEM;
106 }
107
108 NET_DBG(">> str_size:%08x cur:%p, end:%p",
109 (uint32_t)GET_UT8STR_BUFFER_SIZE(str), (void *)buf->cur, (void *)buf->end);
110
111 /* Pack length followed by string. */
112 (void)pack_uint16(str->size, buf);
113
114 memcpy(buf->cur, str->utf8, str->size);
115 buf->cur += str->size;
116
117 return 0;
118 }
119
120 /**
121 * @brief Computes and encodes variable length integer.
122 *
123 * @note The variable length integer is based on algorithm below:
124 *
125 * @code
126 * do
127 * encodedByte = X MOD 128
128 * X = X DIV 128
129 * // if there are more data to encode, set the top bit of this byte
130 * if ( X > 0 )
131 * encodedByte = encodedByte OR 128
132 * endif
133 * 'output' encodedByte
134 * while ( X > 0 )
135 * @endcode
136 *
137 * @param[in] value Integer value to encode.
138 * @param[inout] buf A pointer to the buf_ctx structure containing current
139 * buffer position. May be NULL (in this case function will
140 * only calculate number of bytes needed).
141 *
142 * @return Number of bytes needed to encode integer or a negative error code.
143 */
pack_variable_int(uint32_t value,struct buf_ctx * buf)144 static int pack_variable_int(uint32_t value, struct buf_ctx *buf)
145 {
146 int encoded_bytes = 0U;
147
148 NET_DBG(">> value:0x%08x cur:%p, end:%p", value,
149 (buf == NULL) ? 0 : (void *)buf->cur, (buf == NULL) ? 0 : (void *)buf->end);
150
151 do {
152 encoded_bytes++;
153
154 if (buf != NULL) {
155 if (buf->cur >= buf->end) {
156 return -ENOMEM;
157 }
158
159 *(buf->cur) = value & MQTT_LENGTH_VALUE_MASK;
160 }
161
162 value >>= MQTT_LENGTH_SHIFT;
163
164 if (buf != NULL) {
165 if (value > 0) {
166 *(buf->cur) |= MQTT_LENGTH_CONTINUATION_BIT;
167 }
168 buf->cur++;
169 }
170 } while (value > 0);
171
172 return encoded_bytes;
173 }
174
175 /**
176 * @brief Encodes fixed header for the MQTT message and provides pointer to
177 * start of the header.
178 *
179 * @param[in] message_type Message type containing packet type and the flags.
180 * Use @ref MQTT_MESSAGES_OPTIONS to construct the
181 * message_type.
182 * @param[in] start Pointer to the start of the variable header.
183 * @param[inout] buf Buffer context used to encode the frame.
184 * The 5 bytes before the start of the message are assumed
185 * by the routine to be available to pack the fixed header.
186 * However, since the fixed header length is variable
187 * length, the pointer to the start of the MQTT message
188 * along with encoded fixed header is supplied as output
189 * parameter if the procedure was successful.
190 * As output, the pointers will point to beginning and the end
191 * of the frame.
192 *
193 * @retval 0 if the procedure is successful.
194 * @retval -EMSGSIZE if the message is too big for MQTT.
195 */
mqtt_encode_fixed_header(uint8_t message_type,uint8_t * start,struct buf_ctx * buf)196 static uint32_t mqtt_encode_fixed_header(uint8_t message_type, uint8_t *start,
197 struct buf_ctx *buf)
198 {
199 uint32_t length = buf->cur - start;
200 uint8_t fixed_header_length;
201
202 if (length > MQTT_MAX_PAYLOAD_SIZE) {
203 return -EMSGSIZE;
204 }
205
206 NET_DBG("<< msg type:0x%02x length:0x%08x", message_type, length);
207
208 fixed_header_length = pack_variable_int(length, NULL);
209 fixed_header_length += sizeof(uint8_t);
210
211 NET_DBG("Fixed header length = %02x", fixed_header_length);
212
213 /* Set the pointer at the start of the frame before encoding. */
214 buf->cur = start - fixed_header_length;
215
216 (void)pack_uint8(message_type, buf);
217 (void)pack_variable_int(length, buf);
218
219 /* Set the cur pointer back at the start of the frame,
220 * and end pointer to the end of the frame.
221 */
222 buf->cur = buf->cur - fixed_header_length;
223 buf->end = buf->cur + length + fixed_header_length;
224
225 return 0;
226 }
227
228 /**
229 * @brief Encodes a string of a zero length.
230 *
231 * @param[in] buffer_len Total size of the buffer on which string will be
232 * encoded. This shall not be zero.
233 * @param[inout] buf A pointer to the buf_ctx structure containing current
234 * buffer position.
235 *
236 * @retval 0 if the procedure is successful.
237 * @retval -ENOMEM if there is no place in the buffer to store the binary
238 * string.
239 */
zero_len_str_encode(struct buf_ctx * buf)240 static int zero_len_str_encode(struct buf_ctx *buf)
241 {
242 return pack_uint16(0x0000, buf);
243 }
244
245 #if defined(CONFIG_MQTT_VERSION_5_0)
246 /**
247 * @brief Packs unsigned 32 bit value to the buffer at the offset requested.
248 *
249 * @param[in] val Value to be packed.
250 * @param[inout] buf A pointer to the buf_ctx structure containing current
251 * buffer position.
252 *
253 * @retval 0 if the procedure is successful.
254 * @retval -ENOMEM if there is no place in the buffer to store the value.
255 */
pack_uint32(uint32_t val,struct buf_ctx * buf)256 static int pack_uint32(uint32_t val, struct buf_ctx *buf)
257 {
258 uint8_t *cur = buf->cur;
259 uint8_t *end = buf->end;
260
261 if ((end - cur) < sizeof(uint32_t)) {
262 return -ENOMEM;
263 }
264
265 /* Pack value. */
266 sys_put_be32(val, cur);
267 buf->cur = (cur + sizeof(uint32_t));
268
269 return 0;
270 }
271
272 /**
273 * @brief Packs binary data to the buffer at the offset requested.
274 *
275 * @param[in] bin Binary data and its length to be packed.
276 * @param[inout] buf A pointer to the buf_ctx structure containing current
277 * buffer position.
278 *
279 * @retval 0 if the procedure is successful.
280 * @retval -ENOMEM if there is no place in the buffer to store the data.
281 */
pack_bin_data(const struct mqtt_binstr * bin,struct buf_ctx * buf)282 static int pack_bin_data(const struct mqtt_binstr *bin, struct buf_ctx *buf)
283 {
284 if ((buf->end - buf->cur) < GET_BINSTR_BUFFER_SIZE(bin)) {
285 return -ENOMEM;
286 }
287
288 /* Pack length followed by binary data. */
289 (void)pack_uint16(bin->len, buf);
290
291 memcpy(buf->cur, bin->data, bin->len);
292 buf->cur += bin->len;
293
294 return 0;
295 }
296
get_uint8_property_default(uint8_t prop)297 static uint8_t get_uint8_property_default(uint8_t prop)
298 {
299 if (prop == MQTT_PROP_REQUEST_PROBLEM_INFORMATION) {
300 return 1;
301 }
302
303 return 0;
304 }
305
uint8_property_length(uint8_t prop,uint8_t value)306 static size_t uint8_property_length(uint8_t prop, uint8_t value)
307 {
308 uint8_t prop_default = get_uint8_property_default(prop);
309
310 if (value == prop_default) {
311 return 0;
312 }
313
314 return sizeof(uint8_t) + sizeof(uint8_t);
315 }
316
encode_uint8_property(uint8_t prop,uint8_t value,struct buf_ctx * buf)317 static int encode_uint8_property(uint8_t prop, uint8_t value, struct buf_ctx *buf)
318 {
319 uint8_t prop_default = get_uint8_property_default(prop);
320 int err;
321
322 if (value == prop_default) {
323 return 0;
324 }
325
326 err = pack_uint8(prop, buf);
327 if (err < 0) {
328 return err;
329 }
330
331 return pack_uint8(value, buf);
332 }
333
uint16_property_length(uint16_t value)334 static size_t uint16_property_length(uint16_t value)
335 {
336 if (value == 0) {
337 return 0;
338 }
339
340 return sizeof(uint8_t) + sizeof(uint16_t);
341 }
342
encode_uint16_property(uint8_t prop,uint16_t value,struct buf_ctx * buf)343 static int encode_uint16_property(uint8_t prop, uint16_t value,
344 struct buf_ctx *buf)
345 {
346 int err;
347
348 if (value == 0) {
349 return 0;
350 }
351
352 err = pack_uint8(prop, buf);
353 if (err < 0) {
354 return err;
355 }
356
357 return pack_uint16(value, buf);
358 }
359
uint32_property_length(uint32_t value)360 static size_t uint32_property_length(uint32_t value)
361 {
362 if (value == 0) {
363 return 0;
364 }
365
366 return sizeof(uint8_t) + sizeof(uint32_t);
367 }
368
encode_uint32_property(uint8_t prop,uint32_t value,struct buf_ctx * buf)369 static int encode_uint32_property(uint8_t prop, uint32_t value,
370 struct buf_ctx *buf)
371 {
372 int err;
373
374 if (value == 0) {
375 return 0;
376 }
377
378 err = pack_uint8(prop, buf);
379 if (err < 0) {
380 return err;
381 }
382
383 return pack_uint32(value, buf);
384 }
385
var_int_property_length(uint32_t value)386 static size_t var_int_property_length(uint32_t value)
387 {
388 if (value == 0) {
389 return 0;
390 }
391
392 return sizeof(uint8_t) + (size_t)pack_variable_int(value, NULL);
393 }
394
encode_var_int_property(uint8_t prop,uint32_t value,struct buf_ctx * buf)395 static int encode_var_int_property(uint8_t prop, uint32_t value,
396 struct buf_ctx *buf)
397 {
398 int err;
399
400 if (value == 0) {
401 return 0;
402 }
403
404 err = pack_uint8(prop, buf);
405 if (err < 0) {
406 return err;
407 }
408
409 return pack_variable_int(value, buf);
410 }
411
string_property_length(const struct mqtt_utf8 * str)412 static size_t string_property_length(const struct mqtt_utf8 *str)
413 {
414 if (str->size == 0) {
415 return 0;
416 }
417
418 return sizeof(uint8_t) + GET_UT8STR_BUFFER_SIZE(str);
419 }
420
encode_string_property(uint8_t prop,const struct mqtt_utf8 * str,struct buf_ctx * buf)421 static int encode_string_property(uint8_t prop, const struct mqtt_utf8 *str,
422 struct buf_ctx *buf)
423 {
424 int err;
425
426 if (str->size == 0) {
427 return 0;
428 }
429
430 err = pack_uint8(prop, buf);
431 if (err < 0) {
432 return err;
433 }
434
435 return pack_utf8_str(str, buf);
436 }
437
string_pair_property_length(const struct mqtt_utf8 * name,const struct mqtt_utf8 * value)438 static size_t string_pair_property_length(const struct mqtt_utf8 *name,
439 const struct mqtt_utf8 *value)
440 {
441 if ((name->size == 0) || (value->size == 0)) {
442 return 0;
443 }
444
445 return sizeof(uint8_t) + GET_UT8STR_BUFFER_SIZE(name) +
446 GET_UT8STR_BUFFER_SIZE(value);
447 }
448
encode_string_pair_property(uint8_t prop,const struct mqtt_utf8 * name,const struct mqtt_utf8 * value,struct buf_ctx * buf)449 static int encode_string_pair_property(uint8_t prop, const struct mqtt_utf8 *name,
450 const struct mqtt_utf8 *value,
451 struct buf_ctx *buf)
452 {
453 int err;
454
455 if ((name->size == 0) || (value->size == 0)) {
456 return 0;
457 }
458
459 err = pack_uint8(prop, buf);
460 if (err < 0) {
461 return err;
462 }
463
464 err = pack_utf8_str(name, buf);
465 if (err < 0) {
466 return err;
467 }
468
469 return pack_utf8_str(value, buf);
470 }
471
binary_property_length(const struct mqtt_binstr * bin)472 static size_t binary_property_length(const struct mqtt_binstr *bin)
473 {
474 if (bin->len == 0) {
475 return 0;
476 }
477
478 return sizeof(uint8_t) + GET_BINSTR_BUFFER_SIZE(bin);
479 }
480
encode_binary_property(uint8_t prop,const struct mqtt_binstr * bin,struct buf_ctx * buf)481 static int encode_binary_property(uint8_t prop, const struct mqtt_binstr *bin,
482 struct buf_ctx *buf)
483 {
484 int err;
485
486 if (bin->len == 0) {
487 return 0;
488 }
489
490 err = pack_uint8(prop, buf);
491 if (err < 0) {
492 return err;
493 }
494
495 return pack_bin_data(bin, buf);
496 }
497
user_properties_length(const struct mqtt_utf8_pair * user_props)498 static size_t user_properties_length(const struct mqtt_utf8_pair *user_props)
499 {
500 size_t total_len = 0;
501 size_t len;
502
503 for (int i = 0; i < CONFIG_MQTT_USER_PROPERTIES_MAX; i++) {
504 len = string_pair_property_length(&user_props[i].name,
505 &user_props[i].value);
506 if (len == 0) {
507 break;
508 }
509
510 total_len += len;
511 }
512
513 return total_len;
514 }
515
encode_user_properties(const struct mqtt_utf8_pair * user_props,struct buf_ctx * buf)516 static int encode_user_properties(const struct mqtt_utf8_pair *user_props,
517 struct buf_ctx *buf)
518 {
519 size_t len;
520 int err;
521
522 for (int i = 0; i < CONFIG_MQTT_USER_PROPERTIES_MAX; i++) {
523 len = string_pair_property_length(&user_props[i].name,
524 &user_props[i].value);
525
526 if (len == 0) {
527 break;
528 }
529
530 err = encode_string_pair_property(MQTT_PROP_USER_PROPERTY,
531 &user_props[i].name,
532 &user_props[i].value, buf);
533 if (err < 0) {
534 return err;
535 }
536 }
537
538 return 0;
539 }
540
connect_properties_length(const struct mqtt_client * client)541 static uint32_t connect_properties_length(const struct mqtt_client *client)
542 {
543 return uint32_property_length(client->prop.session_expiry_interval) +
544 uint16_property_length(client->prop.receive_maximum) +
545 uint32_property_length(client->prop.maximum_packet_size) +
546 uint16_property_length(CONFIG_MQTT_TOPIC_ALIAS_MAX) +
547 uint8_property_length(MQTT_PROP_REQUEST_RESPONSE_INFORMATION,
548 client->prop.request_response_info ? 1U : 0U) +
549 uint8_property_length(MQTT_PROP_REQUEST_PROBLEM_INFORMATION,
550 client->prop.request_problem_info ? 1U : 0U) +
551 user_properties_length(client->prop.user_prop) +
552 string_property_length(&client->prop.auth_method) +
553 binary_property_length(&client->prop.auth_data);
554 }
555
connect_properties_encode(const struct mqtt_client * client,struct buf_ctx * buf)556 static int connect_properties_encode(const struct mqtt_client *client,
557 struct buf_ctx *buf)
558 {
559 uint32_t properties_len;
560 int err;
561
562 /* Precalculate total properties length */
563 properties_len = connect_properties_length(client);
564 err = pack_variable_int(properties_len, buf);
565 if (err < 0) {
566 return err;
567 }
568
569 err = encode_uint32_property(MQTT_PROP_SESSION_EXPIRY_INTERVAL,
570 client->prop.session_expiry_interval, buf);
571 if (err < 0) {
572 return err;
573 }
574
575 err = encode_uint16_property(MQTT_PROP_RECEIVE_MAXIMUM,
576 client->prop.receive_maximum, buf);
577 if (err < 0) {
578 return err;
579 }
580
581 err = encode_uint32_property(MQTT_PROP_MAXIMUM_PACKET_SIZE,
582 client->prop.maximum_packet_size, buf);
583 if (err < 0) {
584 return err;
585 }
586
587 err = encode_uint16_property(MQTT_PROP_TOPIC_ALIAS_MAXIMUM,
588 CONFIG_MQTT_TOPIC_ALIAS_MAX, buf);
589 if (err < 0) {
590 return err;
591 }
592
593 err = encode_uint8_property(MQTT_PROP_REQUEST_RESPONSE_INFORMATION,
594 client->prop.request_response_info ? 1U : 0U,
595 buf);
596 if (err < 0) {
597 return err;
598 }
599
600 err = encode_uint8_property(MQTT_PROP_REQUEST_PROBLEM_INFORMATION,
601 client->prop.request_problem_info ? 1U : 0U,
602 buf);
603 if (err < 0) {
604 return err;
605 }
606
607 err = encode_user_properties(client->prop.user_prop, buf);
608 if (err < 0) {
609 return err;
610 }
611
612 err = encode_string_property(MQTT_PROP_AUTHENTICATION_METHOD,
613 &client->prop.auth_method, buf);
614 if (err < 0) {
615 return err;
616 }
617
618 err = encode_binary_property(MQTT_PROP_AUTHENTICATION_DATA,
619 &client->prop.auth_data, buf);
620 if (err < 0) {
621 return err;
622 }
623
624 return 0;
625 }
626
will_properties_length(const struct mqtt_client * client)627 static uint32_t will_properties_length(const struct mqtt_client *client)
628 {
629 return uint32_property_length(client->will_prop.will_delay_interval) +
630 uint8_property_length(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR,
631 client->will_prop.payload_format_indicator) +
632 uint32_property_length(client->will_prop.message_expiry_interval) +
633 string_property_length(&client->will_prop.content_type) +
634 string_property_length(&client->will_prop.response_topic) +
635 binary_property_length(&client->will_prop.correlation_data) +
636 user_properties_length(client->will_prop.user_prop);
637 }
638
will_properties_encode(const struct mqtt_client * client,struct buf_ctx * buf)639 static int will_properties_encode(const struct mqtt_client *client,
640 struct buf_ctx *buf)
641 {
642 uint32_t properties_len;
643 int err;
644
645 /* Precalculate total properties length */
646 properties_len = will_properties_length(client);
647 err = pack_variable_int(properties_len, buf);
648 if (err < 0) {
649 return err;
650 }
651
652 err = encode_uint32_property(MQTT_PROP_WILL_DELAY_INTERVAL,
653 client->will_prop.will_delay_interval, buf);
654 if (err < 0) {
655 return err;
656 }
657
658 err = encode_uint8_property(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR,
659 client->will_prop.payload_format_indicator,
660 buf);
661 if (err < 0) {
662 return err;
663 }
664
665 err = encode_uint32_property(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL,
666 client->will_prop.message_expiry_interval,
667 buf);
668 if (err < 0) {
669 return err;
670 }
671
672 err = encode_string_property(MQTT_PROP_CONTENT_TYPE,
673 &client->will_prop.content_type, buf);
674 if (err < 0) {
675 return err;
676 }
677
678 err = encode_string_property(MQTT_PROP_RESPONSE_TOPIC,
679 &client->will_prop.response_topic, buf);
680 if (err < 0) {
681 return err;
682 }
683
684 err = encode_binary_property(MQTT_PROP_CORRELATION_DATA,
685 &client->will_prop.correlation_data, buf);
686 if (err < 0) {
687 return err;
688 }
689
690 err = encode_user_properties(client->will_prop.user_prop, buf);
691 if (err < 0) {
692 return err;
693 }
694
695 return 0;
696 }
697
698 #else
connect_properties_encode(const struct mqtt_client * client,struct buf_ctx * buf)699 static int connect_properties_encode(const struct mqtt_client *client,
700 struct buf_ctx *buf)
701 {
702 ARG_UNUSED(client);
703 ARG_UNUSED(buf);
704
705 return -ENOTSUP;
706 }
707
will_properties_encode(const struct mqtt_client * client,struct buf_ctx * buf)708 static int will_properties_encode(const struct mqtt_client *client,
709 struct buf_ctx *buf)
710 {
711 ARG_UNUSED(client);
712 ARG_UNUSED(buf);
713
714 return -ENOTSUP;
715 }
716 #endif /* CONFIG_MQTT_VERSION_5_0 */
717
connect_request_encode(const struct mqtt_client * client,struct buf_ctx * buf)718 int connect_request_encode(const struct mqtt_client *client,
719 struct buf_ctx *buf)
720 {
721 uint8_t connect_flags = client->clean_session << 1;
722 const uint8_t message_type =
723 MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_CONNECT, 0, 0, 0);
724 const struct mqtt_utf8 *proto_desc;
725 uint8_t *connect_flags_pos;
726 int err_code;
727 uint8_t *start;
728
729 if (client->protocol_version == MQTT_VERSION_3_1_0) {
730 proto_desc = &mqtt_3_1_0_proto_desc;
731 } else {
732 /* MQTT 3.1.1 and newer share the same protocol prefix. */
733 proto_desc = &mqtt_proto_desc;
734 }
735
736 /* Reserve space for fixed header. */
737 buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
738 start = buf->cur;
739
740 NET_HEXDUMP_DBG(proto_desc->utf8, proto_desc->size,
741 "Encoding Protocol Description.");
742
743 err_code = pack_utf8_str(proto_desc, buf);
744 if (err_code != 0) {
745 return err_code;
746 }
747
748 NET_DBG("Encoding Protocol Version %02x.", client->protocol_version);
749 err_code = pack_uint8(client->protocol_version, buf);
750 if (err_code != 0) {
751 return err_code;
752 }
753
754 /* Remember position of connect flag and leave one byte for it to
755 * be packed once we determine its value.
756 */
757 connect_flags_pos = buf->cur;
758
759 err_code = pack_uint8(0, buf);
760 if (err_code != 0) {
761 return err_code;
762 }
763
764 NET_DBG("Encoding Keep Alive Time %04x.", client->keepalive);
765 err_code = pack_uint16(client->keepalive, buf);
766 if (err_code != 0) {
767 return err_code;
768 }
769
770 /* Properties (MQTT 5.0 only) */
771 if (mqtt_is_version_5_0(client)) {
772 err_code = connect_properties_encode(client, buf);
773 if (err_code != 0) {
774 return err_code;
775 }
776 }
777
778 NET_HEXDUMP_DBG(client->client_id.utf8, client->client_id.size,
779 "Encoding Client Id.");
780 err_code = pack_utf8_str(&client->client_id, buf);
781 if (err_code != 0) {
782 return err_code;
783 }
784
785 /* Pack will topic and QoS */
786 if (client->will_topic != NULL) {
787 connect_flags |= MQTT_CONNECT_FLAG_WILL_TOPIC;
788 /* QoS is always 1 as of now. */
789 connect_flags |= ((client->will_topic->qos & 0x03) << 3);
790 connect_flags |= client->will_retain << 5;
791
792 /* Will properties (MQTT 5.0 only) */
793 if (mqtt_is_version_5_0(client)) {
794 err_code = will_properties_encode(client, buf);
795 if (err_code != 0) {
796 return err_code;
797 }
798 }
799
800 NET_HEXDUMP_DBG(client->will_topic->topic.utf8,
801 client->will_topic->topic.size,
802 "Encoding Will Topic.");
803 err_code = pack_utf8_str(&client->will_topic->topic, buf);
804 if (err_code != 0) {
805 return err_code;
806 }
807
808 if (client->will_message != NULL) {
809 NET_HEXDUMP_DBG(client->will_message->utf8,
810 client->will_message->size,
811 "Encoding Will Message.");
812 err_code = pack_utf8_str(client->will_message, buf);
813 if (err_code != 0) {
814 return err_code;
815 }
816 } else {
817 NET_DBG("Encoding Zero Length Will Message.");
818 err_code = zero_len_str_encode(buf);
819 if (err_code != 0) {
820 return err_code;
821 }
822 }
823 }
824
825 /* Pack Username if any. */
826 if (client->user_name != NULL) {
827 connect_flags |= MQTT_CONNECT_FLAG_USERNAME;
828
829 NET_HEXDUMP_DBG(client->user_name->utf8,
830 client->user_name->size,
831 "Encoding Username.");
832 err_code = pack_utf8_str(client->user_name, buf);
833 if (err_code != 0) {
834 return err_code;
835 }
836 }
837
838 /* Pack Password if any. */
839 if (client->password != NULL) {
840 connect_flags |= MQTT_CONNECT_FLAG_PASSWORD;
841
842 NET_HEXDUMP_DBG(client->password->utf8,
843 client->password->size,
844 "Encoding Password.");
845 err_code = pack_utf8_str(client->password, buf);
846 if (err_code != 0) {
847 return err_code;
848 }
849 }
850
851 /* Write the flags the connect flags. */
852 *connect_flags_pos = connect_flags;
853
854 return mqtt_encode_fixed_header(message_type, start, buf);
855 }
856
857 #if defined(CONFIG_MQTT_VERSION_5_0)
publish_properties_length(const struct mqtt_publish_param * param)858 static uint32_t publish_properties_length(const struct mqtt_publish_param *param)
859 {
860 return uint8_property_length(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR,
861 param->prop.payload_format_indicator) +
862 uint32_property_length(param->prop.message_expiry_interval) +
863 uint16_property_length(param->prop.topic_alias) +
864 string_property_length(¶m->prop.response_topic) +
865 binary_property_length(¶m->prop.correlation_data) +
866 user_properties_length(param->prop.user_prop) +
867 /* Client does not include Subscription Identifier in any case. */
868 string_property_length(¶m->prop.content_type);
869 }
870
publish_properties_encode(const struct mqtt_publish_param * param,struct buf_ctx * buf)871 static int publish_properties_encode(const struct mqtt_publish_param *param,
872 struct buf_ctx *buf)
873 {
874 uint32_t properties_len;
875 int err;
876
877 /* Precalculate total properties length */
878 properties_len = publish_properties_length(param);
879 err = pack_variable_int(properties_len, buf);
880 if (err < 0) {
881 return err;
882 }
883
884 err = encode_uint8_property(MQTT_PROP_PAYLOAD_FORMAT_INDICATOR,
885 param->prop.payload_format_indicator, buf);
886 if (err < 0) {
887 return err;
888 }
889
890 err = encode_uint32_property(MQTT_PROP_MESSAGE_EXPIRY_INTERVAL,
891 param->prop.message_expiry_interval, buf);
892 if (err < 0) {
893 return err;
894 }
895
896 err = encode_uint16_property(MQTT_PROP_TOPIC_ALIAS,
897 param->prop.topic_alias, buf);
898 if (err < 0) {
899 return err;
900 }
901
902 err = encode_string_property(MQTT_PROP_RESPONSE_TOPIC,
903 ¶m->prop.response_topic, buf);
904 if (err < 0) {
905 return err;
906 }
907
908 err = encode_binary_property(MQTT_PROP_CORRELATION_DATA,
909 ¶m->prop.correlation_data, buf);
910 if (err < 0) {
911 return err;
912 }
913
914 err = encode_user_properties(param->prop.user_prop, buf);
915 if (err < 0) {
916 return err;
917 }
918
919 /* Client does not include Subscription Identifier in any case. */
920
921 err = encode_string_property(MQTT_PROP_CONTENT_TYPE,
922 ¶m->prop.content_type, buf);
923 if (err < 0) {
924 return err;
925 }
926
927 return 0;
928 }
929 #else
publish_properties_encode(const struct mqtt_publish_param * param,struct buf_ctx * buf)930 static int publish_properties_encode(const struct mqtt_publish_param *param,
931 struct buf_ctx *buf)
932 {
933 ARG_UNUSED(param);
934 ARG_UNUSED(buf);
935
936 return -ENOTSUP;
937 }
938 #endif /* CONFIG_MQTT_VERSION_5_0 */
939
publish_encode(const struct mqtt_client * client,const struct mqtt_publish_param * param,struct buf_ctx * buf)940 int publish_encode(const struct mqtt_client *client,
941 const struct mqtt_publish_param *param,
942 struct buf_ctx *buf)
943 {
944 const uint8_t message_type = MQTT_MESSAGES_OPTIONS(
945 MQTT_PKT_TYPE_PUBLISH, param->dup_flag,
946 param->message.topic.qos, param->retain_flag);
947 int err_code;
948 uint8_t *start;
949
950 /* Message id zero is not permitted by spec. */
951 if ((param->message.topic.qos) && (param->message_id == 0U)) {
952 return -EINVAL;
953 }
954
955 /* Reserve space for fixed header. */
956 buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
957 start = buf->cur;
958
959 err_code = pack_utf8_str(¶m->message.topic.topic, buf);
960 if (err_code != 0) {
961 return err_code;
962 }
963
964 if (param->message.topic.qos) {
965 err_code = pack_uint16(param->message_id, buf);
966 if (err_code != 0) {
967 return err_code;
968 }
969 }
970
971 if (mqtt_is_version_5_0(client)) {
972 err_code = publish_properties_encode(param, buf);
973 if (err_code != 0) {
974 return err_code;
975 }
976 }
977
978 /* Do not copy payload. We move the buffer pointer to ensure that
979 * message length in fixed header is encoded correctly.
980 */
981 buf->cur += param->message.payload.len;
982
983 err_code = mqtt_encode_fixed_header(message_type, start, buf);
984 if (err_code != 0) {
985 return err_code;
986 }
987
988 buf->end -= param->message.payload.len;
989
990 return 0;
991 }
992
993 #if defined(CONFIG_MQTT_VERSION_5_0)
common_ack_properties_length(const struct mqtt_common_ack_properties * prop)994 static uint32_t common_ack_properties_length(
995 const struct mqtt_common_ack_properties *prop)
996 {
997 return user_properties_length(prop->user_prop) +
998 string_property_length(&prop->reason_string);
999 }
1000
common_ack_properties_encode(const struct mqtt_common_ack_properties * prop,struct buf_ctx * buf)1001 static int common_ack_properties_encode(
1002 const struct mqtt_common_ack_properties *prop,
1003 struct buf_ctx *buf)
1004 {
1005 uint32_t properties_len;
1006 int err;
1007
1008 /* Precalculate total properties length */
1009 properties_len = common_ack_properties_length(prop);
1010 /* Properties length can be omitted if equal to 0. */
1011 if (properties_len == 0) {
1012 return 0;
1013 }
1014
1015 err = pack_variable_int(properties_len, buf);
1016 if (err < 0) {
1017 return err;
1018 }
1019
1020 err = encode_user_properties(prop->user_prop, buf);
1021 if (err < 0) {
1022 return err;
1023 }
1024
1025 err = encode_string_property(MQTT_PROP_REASON_STRING,
1026 &prop->reason_string, buf);
1027 if (err < 0) {
1028 return err;
1029 }
1030
1031 return 0;
1032 }
1033 #else /* CONFIG_MQTT_VERSION_5_0 */
common_ack_properties_length(const struct mqtt_common_ack_properties * prop)1034 static uint32_t common_ack_properties_length(
1035 const struct mqtt_common_ack_properties *prop)
1036 {
1037 return 0;
1038 }
1039
common_ack_properties_encode(const struct mqtt_common_ack_properties * prop,struct buf_ctx * buf)1040 static int common_ack_properties_encode(
1041 const struct mqtt_common_ack_properties *prop,
1042 struct buf_ctx *buf)
1043 {
1044 ARG_UNUSED(prop);
1045 ARG_UNUSED(buf);
1046
1047 return -ENOTSUP;
1048 }
1049 #endif /* CONFIG_MQTT_VERSION_5_0 */
1050
common_ack_encode(uint8_t message_type,uint16_t message_id,uint8_t reason_code,const struct mqtt_common_ack_properties * prop,struct buf_ctx * buf)1051 static int common_ack_encode(
1052 uint8_t message_type, uint16_t message_id, uint8_t reason_code,
1053 const struct mqtt_common_ack_properties *prop,
1054 struct buf_ctx *buf)
1055 {
1056 int err_code;
1057 uint8_t *start;
1058
1059 /* Message id zero is not permitted by spec. */
1060 if (message_id == 0U) {
1061 return -EINVAL;
1062 }
1063
1064 /* Reserve space for fixed header. */
1065 buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
1066 start = buf->cur;
1067
1068 err_code = pack_uint16(message_id, buf);
1069 if (err_code != 0) {
1070 return err_code;
1071 }
1072
1073 /* For MQTT < 5.0 properties are NULL. */
1074 if (prop != NULL) {
1075 /* The Reason Code and Property Length can be omitted if the
1076 * Reason Code is 0x00 (Success) and there are no Properties.
1077 */
1078 if (common_ack_properties_length(prop) == 0 &&
1079 reason_code == 0) {
1080 goto out;
1081 }
1082
1083 err_code = pack_uint8(reason_code, buf);
1084 if (err_code != 0) {
1085 return err_code;
1086 }
1087
1088 err_code = common_ack_properties_encode(prop, buf);
1089 if (err_code != 0) {
1090 return err_code;
1091 }
1092 }
1093
1094 out:
1095 return mqtt_encode_fixed_header(message_type, start, buf);
1096 }
1097
publish_ack_encode(const struct mqtt_client * client,const struct mqtt_puback_param * param,struct buf_ctx * buf)1098 int publish_ack_encode(const struct mqtt_client *client,
1099 const struct mqtt_puback_param *param,
1100 struct buf_ctx *buf)
1101 {
1102 const uint8_t message_type =
1103 MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_PUBACK, 0, 0, 0);
1104 const struct mqtt_common_ack_properties *prop = NULL;
1105 uint8_t reason_code = 0;
1106
1107 #if defined(CONFIG_MQTT_VERSION_5_0)
1108 if (mqtt_is_version_5_0(client)) {
1109 prop = ¶m->prop;
1110 reason_code = param->reason_code;
1111 }
1112 #endif
1113
1114 return common_ack_encode(message_type, param->message_id,
1115 reason_code, prop, buf);
1116 }
1117
publish_receive_encode(const struct mqtt_client * client,const struct mqtt_pubrec_param * param,struct buf_ctx * buf)1118 int publish_receive_encode(const struct mqtt_client *client,
1119 const struct mqtt_pubrec_param *param,
1120 struct buf_ctx *buf)
1121 {
1122 const uint8_t message_type =
1123 MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_PUBREC, 0, 0, 0);
1124 const struct mqtt_common_ack_properties *prop = NULL;
1125 uint8_t reason_code = 0;
1126
1127 #if defined(CONFIG_MQTT_VERSION_5_0)
1128 if (mqtt_is_version_5_0(client)) {
1129 prop = ¶m->prop;
1130 reason_code = param->reason_code;
1131 }
1132 #endif
1133
1134 return common_ack_encode(message_type, param->message_id,
1135 reason_code, prop, buf);
1136 }
1137
publish_release_encode(const struct mqtt_client * client,const struct mqtt_pubrel_param * param,struct buf_ctx * buf)1138 int publish_release_encode(const struct mqtt_client *client,
1139 const struct mqtt_pubrel_param *param,
1140 struct buf_ctx *buf)
1141 {
1142 const uint8_t message_type =
1143 MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_PUBREL, 0, 1, 0);
1144 const struct mqtt_common_ack_properties *prop = NULL;
1145 uint8_t reason_code = 0;
1146
1147 #if defined(CONFIG_MQTT_VERSION_5_0)
1148 if (mqtt_is_version_5_0(client)) {
1149 prop = ¶m->prop;
1150 reason_code = param->reason_code;
1151 }
1152 #endif
1153
1154 return common_ack_encode(message_type, param->message_id,
1155 reason_code, prop, buf);
1156 }
1157
publish_complete_encode(const struct mqtt_client * client,const struct mqtt_pubcomp_param * param,struct buf_ctx * buf)1158 int publish_complete_encode(const struct mqtt_client *client,
1159 const struct mqtt_pubcomp_param *param,
1160 struct buf_ctx *buf)
1161 {
1162 const uint8_t message_type =
1163 MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_PUBCOMP, 0, 0, 0);
1164 const struct mqtt_common_ack_properties *prop = NULL;
1165 uint8_t reason_code = 0;
1166
1167 #if defined(CONFIG_MQTT_VERSION_5_0)
1168 if (mqtt_is_version_5_0(client)) {
1169 prop = ¶m->prop;
1170 reason_code = param->reason_code;
1171 }
1172 #endif
1173
1174 return common_ack_encode(message_type, param->message_id,
1175 reason_code, prop, buf);
1176 }
1177
empty_disconnect_encode(struct buf_ctx * buf)1178 static int empty_disconnect_encode(struct buf_ctx *buf)
1179 {
1180 uint8_t *cur = buf->cur;
1181 uint8_t *end = buf->end;
1182
1183 if ((end - cur) < sizeof(empty_disc_packet)) {
1184 return -ENOMEM;
1185 }
1186
1187 memcpy(cur, empty_disc_packet, sizeof(empty_disc_packet));
1188 buf->end = (cur + sizeof(empty_disc_packet));
1189
1190 return 0;
1191 }
1192
1193 #if defined(CONFIG_MQTT_VERSION_5_0)
disconnect_properties_length(const struct mqtt_disconnect_param * param)1194 static uint32_t disconnect_properties_length(const struct mqtt_disconnect_param *param)
1195 {
1196 return uint32_property_length(param->prop.session_expiry_interval) +
1197 string_property_length(¶m->prop.reason_string) +
1198 user_properties_length(param->prop.user_prop) +
1199 string_property_length(¶m->prop.server_reference);
1200 }
1201
disconnect_properties_encode(const struct mqtt_disconnect_param * param,struct buf_ctx * buf)1202 static int disconnect_properties_encode(const struct mqtt_disconnect_param *param,
1203 struct buf_ctx *buf)
1204 {
1205 uint32_t properties_len;
1206 int err;
1207
1208 /* Precalculate total properties length */
1209 properties_len = disconnect_properties_length(param);
1210 /* Disconnect properties length can be omitted if equal to 0. */
1211 if (properties_len == 0) {
1212 return 0;
1213 }
1214
1215 err = pack_variable_int(properties_len, buf);
1216 if (err < 0) {
1217 return err;
1218 }
1219
1220 err = encode_uint32_property(MQTT_PROP_SESSION_EXPIRY_INTERVAL,
1221 param->prop.session_expiry_interval, buf);
1222 if (err < 0) {
1223 return err;
1224 }
1225
1226 err = encode_string_property(MQTT_PROP_REASON_STRING,
1227 ¶m->prop.reason_string, buf);
1228 if (err < 0) {
1229 return err;
1230 }
1231
1232 err = encode_user_properties(param->prop.user_prop, buf);
1233 if (err < 0) {
1234 return err;
1235 }
1236
1237 err = encode_string_property(MQTT_PROP_SERVER_REFERENCE,
1238 ¶m->prop.server_reference, buf);
1239 if (err < 0) {
1240 return err;
1241 }
1242
1243 return 0;
1244 }
1245
disconnect_5_0_encode(const struct mqtt_disconnect_param * param,struct buf_ctx * buf)1246 static int disconnect_5_0_encode(const struct mqtt_disconnect_param *param,
1247 struct buf_ctx *buf)
1248 {
1249 const uint8_t message_type =
1250 MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_DISCONNECT, 0, 0, 0);
1251 uint8_t *start;
1252 int err;
1253
1254 /* The Reason Code and Property Length can be omitted if the Reason Code
1255 * is 0x00 (Normal disconnecton) and there are no Properties.
1256 */
1257 if ((param->reason_code == MQTT_DISCONNECT_NORMAL) &&
1258 (disconnect_properties_length(param) == 0U)) {
1259 return empty_disconnect_encode(buf);
1260 }
1261
1262 /* Reserve space for fixed header. */
1263 buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
1264 start = buf->cur;
1265
1266 err = pack_uint8(param->reason_code, buf);
1267 if (err < 0) {
1268 return err;
1269 }
1270
1271 err = disconnect_properties_encode(param, buf);
1272 if (err != 0) {
1273 return err;
1274 }
1275
1276 err = mqtt_encode_fixed_header(message_type, start, buf);
1277 if (err != 0) {
1278 return err;
1279 }
1280
1281 return 0;
1282 }
1283 #else
disconnect_5_0_encode(const struct mqtt_disconnect_param * param,struct buf_ctx * buf)1284 static int disconnect_5_0_encode(const struct mqtt_disconnect_param *param,
1285 struct buf_ctx *buf)
1286 {
1287 ARG_UNUSED(param);
1288 ARG_UNUSED(buf);
1289
1290 return -ENOTSUP;
1291 }
1292 #endif /* CONFIG_MQTT_VERSION_5_0 */
1293
disconnect_encode(const struct mqtt_client * client,const struct mqtt_disconnect_param * param,struct buf_ctx * buf)1294 int disconnect_encode(const struct mqtt_client *client,
1295 const struct mqtt_disconnect_param *param,
1296 struct buf_ctx *buf)
1297 {
1298 if (!mqtt_is_version_5_0(client) || param == NULL) {
1299 return empty_disconnect_encode(buf);
1300 }
1301
1302 return disconnect_5_0_encode(param, buf);
1303 }
1304
1305 #if defined(CONFIG_MQTT_VERSION_5_0)
subscribe_properties_length(const struct mqtt_subscription_list * param)1306 static uint32_t subscribe_properties_length(
1307 const struct mqtt_subscription_list *param)
1308 {
1309 return var_int_property_length(param->prop.subscription_identifier) +
1310 user_properties_length(param->prop.user_prop);
1311 }
1312
subscribe_properties_encode(const struct mqtt_subscription_list * param,struct buf_ctx * buf)1313 static int subscribe_properties_encode(const struct mqtt_subscription_list *param,
1314 struct buf_ctx *buf)
1315 {
1316 uint32_t properties_len;
1317 int err;
1318
1319 /* Precalculate total properties length */
1320 properties_len = subscribe_properties_length(param);
1321 err = pack_variable_int(properties_len, buf);
1322 if (err < 0) {
1323 return err;
1324 }
1325
1326 err = encode_var_int_property(MQTT_PROP_SUBSCRIPTION_IDENTIFIER,
1327 param->prop.subscription_identifier,
1328 buf);
1329 if (err < 0) {
1330 return err;
1331 }
1332
1333 err = encode_user_properties(param->prop.user_prop, buf);
1334 if (err < 0) {
1335 return err;
1336 }
1337
1338 return 0;
1339 }
1340 #else
subscribe_properties_encode(const struct mqtt_subscription_list * param,struct buf_ctx * buf)1341 static int subscribe_properties_encode(const struct mqtt_subscription_list *param,
1342 struct buf_ctx *buf)
1343 {
1344 ARG_UNUSED(param);
1345 ARG_UNUSED(buf);
1346
1347 return -ENOTSUP;
1348 }
1349 #endif /* CONFIG_MQTT_VERSION_5_0 */
1350
subscribe_encode(const struct mqtt_client * client,const struct mqtt_subscription_list * param,struct buf_ctx * buf)1351 int subscribe_encode(const struct mqtt_client *client,
1352 const struct mqtt_subscription_list *param,
1353 struct buf_ctx *buf)
1354 {
1355 const uint8_t message_type = MQTT_MESSAGES_OPTIONS(
1356 MQTT_PKT_TYPE_SUBSCRIBE, 0, 1, 0);
1357 int err_code, i;
1358 uint8_t *start;
1359
1360 /* Message id zero is not permitted by spec. */
1361 if (param->message_id == 0U) {
1362 return -EINVAL;
1363 }
1364
1365 /* Reserve space for fixed header. */
1366 buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
1367 start = buf->cur;
1368
1369 err_code = pack_uint16(param->message_id, buf);
1370 if (err_code != 0) {
1371 return err_code;
1372 }
1373
1374 if (mqtt_is_version_5_0(client)) {
1375 err_code = subscribe_properties_encode(param, buf);
1376 if (err_code != 0) {
1377 return err_code;
1378 }
1379 }
1380
1381 for (i = 0; i < param->list_count; i++) {
1382 err_code = pack_utf8_str(¶m->list[i].topic, buf);
1383 if (err_code != 0) {
1384 return err_code;
1385 }
1386
1387 err_code = pack_uint8(param->list[i].qos, buf);
1388 if (err_code != 0) {
1389 return err_code;
1390 }
1391 }
1392
1393 return mqtt_encode_fixed_header(message_type, start, buf);
1394 }
1395
1396 #if defined(CONFIG_MQTT_VERSION_5_0)
unsubscribe_properties_length(const struct mqtt_subscription_list * param)1397 static uint32_t unsubscribe_properties_length(
1398 const struct mqtt_subscription_list *param)
1399 {
1400 return user_properties_length(param->prop.user_prop);
1401 }
1402
unsubscribe_properties_encode(const struct mqtt_subscription_list * param,struct buf_ctx * buf)1403 static int unsubscribe_properties_encode(
1404 const struct mqtt_subscription_list *param, struct buf_ctx *buf)
1405 {
1406 uint32_t properties_len;
1407 int err;
1408
1409 /* Precalculate total properties length */
1410 properties_len = unsubscribe_properties_length(param);
1411 err = pack_variable_int(properties_len, buf);
1412 if (err < 0) {
1413 return err;
1414 }
1415
1416 err = encode_user_properties(param->prop.user_prop, buf);
1417 if (err < 0) {
1418 return err;
1419 }
1420
1421 return 0;
1422 }
1423 #else
unsubscribe_properties_encode(const struct mqtt_subscription_list * param,struct buf_ctx * buf)1424 static int unsubscribe_properties_encode(
1425 const struct mqtt_subscription_list *param, struct buf_ctx *buf)
1426 {
1427 ARG_UNUSED(param);
1428 ARG_UNUSED(buf);
1429
1430 return -ENOTSUP;
1431 }
1432 #endif /* CONFIG_MQTT_VERSION_5_0 */
1433
unsubscribe_encode(const struct mqtt_client * client,const struct mqtt_subscription_list * param,struct buf_ctx * buf)1434 int unsubscribe_encode(const struct mqtt_client *client,
1435 const struct mqtt_subscription_list *param,
1436 struct buf_ctx *buf)
1437 {
1438 const uint8_t message_type = MQTT_MESSAGES_OPTIONS(
1439 MQTT_PKT_TYPE_UNSUBSCRIBE, 0, MQTT_QOS_1_AT_LEAST_ONCE, 0);
1440 int err_code, i;
1441 uint8_t *start;
1442
1443 /* Reserve space for fixed header. */
1444 buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
1445 start = buf->cur;
1446
1447 err_code = pack_uint16(param->message_id, buf);
1448 if (err_code != 0) {
1449 return err_code;
1450 }
1451
1452 if (mqtt_is_version_5_0(client)) {
1453 err_code = unsubscribe_properties_encode(param, buf);
1454 if (err_code != 0) {
1455 return err_code;
1456 }
1457 }
1458
1459 for (i = 0; i < param->list_count; i++) {
1460 err_code = pack_utf8_str(¶m->list[i].topic, buf);
1461 if (err_code != 0) {
1462 return err_code;
1463 }
1464 }
1465
1466 return mqtt_encode_fixed_header(message_type, start, buf);
1467 }
1468
ping_request_encode(struct buf_ctx * buf)1469 int ping_request_encode(struct buf_ctx *buf)
1470 {
1471 uint8_t *cur = buf->cur;
1472 uint8_t *end = buf->end;
1473
1474 if ((end - cur) < sizeof(ping_packet)) {
1475 return -ENOMEM;
1476 }
1477
1478 memcpy(cur, ping_packet, sizeof(ping_packet));
1479 buf->end = (cur + sizeof(ping_packet));
1480
1481 return 0;
1482 }
1483
1484 #if defined(CONFIG_MQTT_VERSION_5_0)
auth_properties_length(const struct mqtt_auth_param * param)1485 static uint32_t auth_properties_length(const struct mqtt_auth_param *param)
1486 {
1487 return string_property_length(¶m->prop.auth_method) +
1488 binary_property_length(¶m->prop.auth_data) +
1489 string_property_length(¶m->prop.reason_string) +
1490 user_properties_length(param->prop.user_prop);
1491 }
1492
auth_properties_encode(const struct mqtt_auth_param * param,struct buf_ctx * buf)1493 static int auth_properties_encode(const struct mqtt_auth_param *param,
1494 struct buf_ctx *buf)
1495 {
1496 uint32_t properties_len;
1497 int err;
1498
1499 /* Precalculate total properties length */
1500 properties_len = auth_properties_length(param);
1501 if (properties_len == 0) {
1502 return 0;
1503 }
1504
1505 err = pack_variable_int(properties_len, buf);
1506 if (err < 0) {
1507 return err;
1508 }
1509
1510 err = encode_string_property(MQTT_PROP_AUTHENTICATION_METHOD,
1511 ¶m->prop.auth_method, buf);
1512 if (err < 0) {
1513 return err;
1514 }
1515
1516 err = encode_binary_property(MQTT_PROP_AUTHENTICATION_DATA,
1517 ¶m->prop.auth_data, buf);
1518 if (err < 0) {
1519 return err;
1520 }
1521
1522 err = encode_string_property(MQTT_PROP_REASON_STRING,
1523 ¶m->prop.reason_string, buf);
1524 if (err < 0) {
1525 return err;
1526 }
1527
1528 err = encode_user_properties(param->prop.user_prop, buf);
1529 if (err < 0) {
1530 return err;
1531 }
1532
1533 return 0;
1534 }
1535
empty_auth_encode(struct buf_ctx * buf)1536 static int empty_auth_encode(struct buf_ctx *buf)
1537 {
1538 const uint8_t empty_auth_packet[] = {
1539 MQTT_PKT_TYPE_AUTH,
1540 0x00
1541 };
1542 uint8_t *cur = buf->cur;
1543 uint8_t *end = buf->end;
1544
1545 if ((end - cur) < sizeof(empty_auth_packet)) {
1546 return -ENOMEM;
1547 }
1548
1549 memcpy(cur, empty_auth_packet, sizeof(empty_auth_packet));
1550 buf->end = (cur + sizeof(empty_auth_packet));
1551
1552 return 0;
1553 }
1554
auth_encode(const struct mqtt_auth_param * param,struct buf_ctx * buf)1555 int auth_encode(const struct mqtt_auth_param *param, struct buf_ctx *buf)
1556 {
1557 const uint8_t message_type =
1558 MQTT_MESSAGES_OPTIONS(MQTT_PKT_TYPE_AUTH, 0, 0, 0);
1559 uint8_t *start;
1560 int err;
1561
1562 /* Reserve space for fixed header. */
1563 buf->cur += MQTT_FIXED_HEADER_MAX_SIZE;
1564 start = buf->cur;
1565
1566 if ((param->reason_code == MQTT_AUTH_SUCCESS) &&
1567 (auth_properties_length(param) == 0U)) {
1568 return empty_auth_encode(buf);
1569 }
1570
1571 err = pack_uint8(param->reason_code, buf);
1572 if (err < 0) {
1573 return err;
1574 }
1575
1576 err = auth_properties_encode(param, buf);
1577 if (err != 0) {
1578 return err;
1579 }
1580
1581 err = mqtt_encode_fixed_header(message_type, start, buf);
1582 if (err != 0) {
1583 return err;
1584 }
1585
1586 return 0;
1587 }
1588 #endif /* CONFIG_MQTT_VERSION_5_0 */
1589