1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /** @file mqtt_decoder.c
8 *
9 * @brief Decoder functions needed for decoding packets received from the
10 * broker.
11 */
12
13 #include <zephyr/logging/log.h>
14 LOG_MODULE_REGISTER(net_mqtt_dec, CONFIG_MQTT_LOG_LEVEL);
15
16 #include "mqtt_internal.h"
17 #include "mqtt_os.h"
18
19 /**
20 * @brief Unpacks unsigned 8 bit value from the buffer from the offset
21 * requested.
22 *
23 * @param[inout] buf A pointer to the buf_ctx structure containing current
24 * buffer position.
25 * @param[out] val Memory where the value is to be unpacked.
26 *
27 * @retval 0 if the procedure is successful.
28 * @retval -EINVAL if the buffer would be exceeded during the read
29 */
unpack_uint8(struct buf_ctx * buf,uint8_t * val)30 static int unpack_uint8(struct buf_ctx *buf, uint8_t *val)
31 {
32 uint8_t *cur = buf->cur;
33 uint8_t *end = buf->end;
34
35 NET_DBG(">> cur:%p, end:%p", (void *)cur, (void *)end);
36
37 if ((end - cur) < sizeof(uint8_t)) {
38 return -EINVAL;
39 }
40
41 *val = cur[0];
42 buf->cur = (cur + sizeof(uint8_t));
43
44 NET_DBG("<< val:%02x", *val);
45
46 return 0;
47 }
48
49 /**
50 * @brief Unpacks unsigned 16 bit value from the buffer from the offset
51 * requested.
52 *
53 * @param[inout] buf A pointer to the buf_ctx structure containing current
54 * buffer position.
55 * @param[out] val Memory where the value is to be unpacked.
56 *
57 * @retval 0 if the procedure is successful.
58 * @retval -EINVAL if the buffer would be exceeded during the read
59 */
unpack_uint16(struct buf_ctx * buf,uint16_t * val)60 static int unpack_uint16(struct buf_ctx *buf, uint16_t *val)
61 {
62 uint8_t *cur = buf->cur;
63 uint8_t *end = buf->end;
64
65 NET_DBG(">> cur:%p, end:%p", (void *)cur, (void *)end);
66
67 if ((end - cur) < sizeof(uint16_t)) {
68 return -EINVAL;
69 }
70
71 *val = sys_get_be16(cur);
72 buf->cur = (cur + sizeof(uint16_t));
73
74 NET_DBG("<< val:%04x", *val);
75
76 return 0;
77 }
78
79 /**
80 * @brief Unpacks utf8 string from the buffer from the offset requested.
81 *
82 * @param[inout] buf A pointer to the buf_ctx structure containing current
83 * buffer position.
84 * @param[out] str Pointer to a string that will hold the string location
85 * in the buffer.
86 *
87 * @retval 0 if the procedure is successful.
88 * @retval -EINVAL if the buffer would be exceeded during the read
89 */
unpack_utf8_str(struct buf_ctx * buf,struct mqtt_utf8 * str)90 static int unpack_utf8_str(struct buf_ctx *buf, struct mqtt_utf8 *str)
91 {
92 uint16_t utf8_strlen;
93 int err_code;
94
95 NET_DBG(">> cur:%p, end:%p", (void *)buf->cur, (void *)buf->end);
96
97 err_code = unpack_uint16(buf, &utf8_strlen);
98 if (err_code != 0) {
99 return err_code;
100 }
101
102 if ((buf->end - buf->cur) < utf8_strlen) {
103 return -EINVAL;
104 }
105
106 str->size = utf8_strlen;
107 /* Zero length UTF8 strings permitted. */
108 if (utf8_strlen) {
109 /* Point to right location in buffer. */
110 str->utf8 = buf->cur;
111 buf->cur += utf8_strlen;
112 } else {
113 str->utf8 = NULL;
114 }
115
116 NET_DBG("<< str_size:%08x", (uint32_t)GET_UT8STR_BUFFER_SIZE(str));
117
118 return 0;
119 }
120
121 /**
122 * @brief Unpacks binary string from the buffer from the offset requested with
123 * the length provided.
124 *
125 * @param[in] length Binary string length.
126 * @param[inout] buf A pointer to the buf_ctx structure containing current
127 * buffer position.
128 * @param[out] str Pointer to a binary string that will hold the binary string
129 * location in the buffer.
130 *
131 * @retval 0 if the procedure is successful.
132 * @retval -EINVAL if the buffer would be exceeded during the read
133 */
unpack_raw_data(uint32_t length,struct buf_ctx * buf,struct mqtt_binstr * str)134 static int unpack_raw_data(uint32_t length, struct buf_ctx *buf,
135 struct mqtt_binstr *str)
136 {
137 NET_DBG(">> cur:%p, end:%p", (void *)buf->cur, (void *)buf->end);
138
139 if ((buf->end - buf->cur) < length) {
140 return -EINVAL;
141 }
142
143 str->len = length;
144
145 /* Zero length binary strings are permitted. */
146 if (length > 0) {
147 str->data = buf->cur;
148 buf->cur += length;
149 } else {
150 str->data = NULL;
151 }
152
153 NET_DBG("<< bin len:%08x", GET_BINSTR_BUFFER_SIZE(str));
154
155 return 0;
156 }
157
unpack_variable_int(struct buf_ctx * buf,uint32_t * val)158 int unpack_variable_int(struct buf_ctx *buf, uint32_t *val)
159 {
160 uint8_t shift = 0U;
161 int bytes = 0;
162
163 *val = 0U;
164 do {
165 if (bytes >= MQTT_MAX_LENGTH_BYTES) {
166 return -EINVAL;
167 }
168
169 if (buf->cur >= buf->end) {
170 return -EAGAIN;
171 }
172
173 *val += ((uint32_t)*(buf->cur) & MQTT_LENGTH_VALUE_MASK)
174 << shift;
175 shift += MQTT_LENGTH_SHIFT;
176 bytes++;
177 } while ((*(buf->cur++) & MQTT_LENGTH_CONTINUATION_BIT) != 0U);
178
179 if (*val > MQTT_MAX_PAYLOAD_SIZE) {
180 return -EINVAL;
181 }
182
183 NET_DBG("variable int:0x%08x", *val);
184
185 return bytes;
186 }
187
fixed_header_decode(struct buf_ctx * buf,uint8_t * type_and_flags,uint32_t * length)188 int fixed_header_decode(struct buf_ctx *buf, uint8_t *type_and_flags,
189 uint32_t *length)
190 {
191 int err_code;
192
193 err_code = unpack_uint8(buf, type_and_flags);
194 if (err_code != 0) {
195 return err_code;
196 }
197
198 err_code = unpack_variable_int(buf, length);
199 if (err_code < 0) {
200 return err_code;
201 }
202
203 return 0;
204 }
205
206 #if defined(CONFIG_MQTT_VERSION_5_0)
207 /**
208 * @brief Unpacks unsigned 32 bit value from the buffer from the offset
209 * requested.
210 *
211 * @param[inout] buf A pointer to the buf_ctx structure containing current
212 * buffer position.
213 * @param[out] val Memory where the value is to be unpacked.
214 *
215 * @retval 0 if the procedure is successful.
216 * @retval -EINVAL if the buffer would be exceeded during the read
217 */
unpack_uint32(struct buf_ctx * buf,uint32_t * val)218 static int unpack_uint32(struct buf_ctx *buf, uint32_t *val)
219 {
220 uint8_t *cur = buf->cur;
221 uint8_t *end = buf->end;
222
223 NET_DBG(">> cur:%p, end:%p", (void *)cur, (void *)end);
224
225 if ((end - cur) < sizeof(uint32_t)) {
226 return -EINVAL;
227 }
228
229 *val = sys_get_be32(cur);
230 buf->cur = (cur + sizeof(uint32_t));
231
232 NET_DBG("<< val:%08x", *val);
233
234 return 0;
235 }
236
237 /**
238 * @brief Unpacks binary string from the buffer from the offset requested.
239 * Binary string length is decoded from the first two bytes of the buffer.
240 *
241 * @param[inout] buf A pointer to the buf_ctx structure containing current
242 * buffer position.
243 * @param[out] bin Pointer to a binary string that will hold the binary string
244 * location in the buffer.
245 *
246 * @retval 0 if the procedure is successful.
247 * @retval -EINVAL if the buffer would be exceeded during the read
248 */
unpack_binary_data(struct buf_ctx * buf,struct mqtt_binstr * bin)249 static int unpack_binary_data(struct buf_ctx *buf, struct mqtt_binstr *bin)
250 {
251 uint16_t len;
252 int err;
253
254 NET_DBG(">> cur:%p, end:%p", (void *)buf->cur, (void *)buf->end);
255
256 err = unpack_uint16(buf, &len);
257 if (err != 0) {
258 return err;
259 }
260
261 if ((buf->end - buf->cur) < len) {
262 return -EINVAL;
263 }
264
265 bin->len = len;
266 /* Zero length binary strings are permitted. */
267 if (len > 0) {
268 bin->data = buf->cur;
269 buf->cur += len;
270 } else {
271 bin->data = NULL;
272 }
273
274 NET_DBG("<< bin len:%08x", GET_BINSTR_BUFFER_SIZE(bin));
275
276 return 0;
277 }
278
279 struct property_decoder {
280 void *data;
281 bool *found;
282 uint8_t type;
283 };
284
decode_uint32_property(struct property_decoder * prop,uint32_t * remaining_len,struct buf_ctx * buf)285 int decode_uint32_property(struct property_decoder *prop,
286 uint32_t *remaining_len,
287 struct buf_ctx *buf)
288 {
289 uint32_t *value = prop->data;
290
291 if (*remaining_len < sizeof(uint32_t)) {
292 return -EINVAL;
293 }
294
295 if (unpack_uint32(buf, value) < 0) {
296 return -EINVAL;
297 }
298
299 *remaining_len -= sizeof(uint32_t);
300 *prop->found = true;
301
302 return 0;
303 }
304
decode_uint16_property(struct property_decoder * prop,uint32_t * remaining_len,struct buf_ctx * buf)305 int decode_uint16_property(struct property_decoder *prop,
306 uint32_t *remaining_len,
307 struct buf_ctx *buf)
308 {
309 uint16_t *value = prop->data;
310
311 if (*remaining_len < sizeof(uint16_t)) {
312 return -EINVAL;
313 }
314
315 if (unpack_uint16(buf, value) < 0) {
316 return -EINVAL;
317 }
318
319 *remaining_len -= sizeof(uint16_t);
320 *prop->found = true;
321
322 return 0;
323 }
324
decode_uint8_property(struct property_decoder * prop,uint32_t * remaining_len,struct buf_ctx * buf)325 int decode_uint8_property(struct property_decoder *prop,
326 uint32_t *remaining_len,
327 struct buf_ctx *buf)
328 {
329 uint8_t *value = prop->data;
330
331 if (*remaining_len < sizeof(uint8_t)) {
332 return -EINVAL;
333 }
334
335 if (unpack_uint8(buf, value) < 0) {
336 return -EINVAL;
337 }
338
339 *remaining_len -= sizeof(uint8_t);
340 *prop->found = true;
341
342 return 0;
343 }
344
decode_string_property(struct property_decoder * prop,uint32_t * remaining_len,struct buf_ctx * buf)345 int decode_string_property(struct property_decoder *prop,
346 uint32_t *remaining_len,
347 struct buf_ctx *buf)
348 {
349 struct mqtt_utf8 *str = prop->data;
350
351 if (unpack_utf8_str(buf, str) < 0) {
352 return -EINVAL;
353 }
354
355 if (*remaining_len < sizeof(uint16_t) + str->size) {
356 return -EINVAL;
357 }
358
359 *remaining_len -= sizeof(uint16_t) + str->size;
360 *prop->found = true;
361
362 return 0;
363 }
364
decode_binary_property(struct property_decoder * prop,uint32_t * remaining_len,struct buf_ctx * buf)365 int decode_binary_property(struct property_decoder *prop,
366 uint32_t *remaining_len,
367 struct buf_ctx *buf)
368 {
369 struct mqtt_binstr *bin = prop->data;
370
371 if (unpack_binary_data(buf, bin) < 0) {
372 return -EINVAL;
373 }
374
375 if (*remaining_len < sizeof(uint16_t) + bin->len) {
376 return -EINVAL;
377 }
378
379 *remaining_len -= sizeof(uint16_t) + bin->len;
380 *prop->found = true;
381
382 return 0;
383 }
384
decode_user_property(struct property_decoder * prop,uint32_t * remaining_len,struct buf_ctx * buf)385 int decode_user_property(struct property_decoder *prop,
386 uint32_t *remaining_len,
387 struct buf_ctx *buf)
388 {
389 struct mqtt_utf8_pair *user_prop = prop->data;
390 struct mqtt_utf8_pair *chosen = NULL;
391 struct mqtt_utf8_pair temp = { 0 };
392 size_t prop_len;
393
394 if (unpack_utf8_str(buf, &temp.name) < 0) {
395 return -EINVAL;
396 }
397
398 if (unpack_utf8_str(buf, &temp.value) < 0) {
399 return -EINVAL;
400 }
401
402 prop_len = (2 * sizeof(uint16_t)) + temp.name.size + temp.value.size;
403 if (*remaining_len < prop_len) {
404 return -EINVAL;
405 }
406
407 *remaining_len -= prop_len;
408 *prop->found = true;
409
410 for (int i = 0; i < CONFIG_MQTT_USER_PROPERTIES_MAX; i++) {
411 if (user_prop[i].name.utf8 == NULL) {
412 chosen = &user_prop[i];
413 break;
414 }
415 }
416
417 if (chosen == NULL) {
418 NET_DBG("Cannot parse all user properties, ignore excess");
419 } else {
420 memcpy(chosen, &temp, sizeof(struct mqtt_utf8_pair));
421 }
422
423 return 0;
424 }
425
decode_sub_id_property(struct property_decoder * prop,uint32_t * remaining_len,struct buf_ctx * buf)426 int decode_sub_id_property(struct property_decoder *prop,
427 uint32_t *remaining_len,
428 struct buf_ctx *buf)
429 {
430 uint32_t *sub_id_array = prop->data;
431 uint32_t *chosen = NULL;
432 uint32_t value;
433 int bytes;
434
435 bytes = unpack_variable_int(buf, &value);
436 if (bytes < 0) {
437 return -EINVAL;
438 }
439
440 if (*remaining_len < bytes) {
441 return -EINVAL;
442 }
443
444 *remaining_len -= bytes;
445 *prop->found = true;
446
447 for (int i = 0; i < CONFIG_MQTT_SUBSCRIPTION_ID_PROPERTIES_MAX; i++) {
448 if (sub_id_array[i] == 0) {
449 chosen = &sub_id_array[i];
450 break;
451 }
452 }
453
454 if (chosen == NULL) {
455 NET_DBG("Cannot parse all subscription id properties, ignore excess");
456 } else {
457 *chosen = value;
458 }
459
460 return 0;
461 }
462
properties_decode(struct property_decoder * prop,uint8_t cnt,struct buf_ctx * buf)463 static int properties_decode(struct property_decoder *prop, uint8_t cnt,
464 struct buf_ctx *buf)
465 {
466 uint32_t properties_len;
467 int bytes;
468 int err;
469
470 bytes = unpack_variable_int(buf, &properties_len);
471 if (bytes < 0) {
472 return -EINVAL;
473 }
474
475 bytes += (int)properties_len;
476
477 while (properties_len > 0) {
478 struct property_decoder *current_prop = NULL;
479 uint8_t type;
480
481 /* Decode property type */
482 err = unpack_uint8(buf, &type);
483 if (err < 0) {
484 return -EINVAL;
485 }
486
487 properties_len--;
488
489 /* Search if the property is supported in the provided property
490 * array.
491 */
492 for (int i = 0; i < cnt; i++) {
493 if (type == prop[i].type) {
494 current_prop = &prop[i];
495 }
496 }
497
498 if (current_prop == NULL) {
499 NET_DBG("Unsupported property %u", type);
500 return -EBADMSG;
501 }
502
503 /* Decode property value. */
504 switch (type) {
505 case MQTT_PROP_SESSION_EXPIRY_INTERVAL:
506 case MQTT_PROP_MAXIMUM_PACKET_SIZE:
507 case MQTT_PROP_MESSAGE_EXPIRY_INTERVAL:
508 err = decode_uint32_property(current_prop,
509 &properties_len, buf);
510 break;
511 case MQTT_PROP_RECEIVE_MAXIMUM:
512 case MQTT_PROP_TOPIC_ALIAS_MAXIMUM:
513 case MQTT_PROP_SERVER_KEEP_ALIVE:
514 case MQTT_PROP_TOPIC_ALIAS:
515 err = decode_uint16_property(current_prop,
516 &properties_len, buf);
517 break;
518 case MQTT_PROP_MAXIMUM_QOS:
519 case MQTT_PROP_RETAIN_AVAILABLE:
520 case MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE:
521 case MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE:
522 case MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE:
523 case MQTT_PROP_PAYLOAD_FORMAT_INDICATOR:
524 err = decode_uint8_property(current_prop,
525 &properties_len, buf);
526 break;
527 case MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER:
528 case MQTT_PROP_REASON_STRING:
529 case MQTT_PROP_RESPONSE_INFORMATION:
530 case MQTT_PROP_SERVER_REFERENCE:
531 case MQTT_PROP_AUTHENTICATION_METHOD:
532 case MQTT_PROP_RESPONSE_TOPIC:
533 case MQTT_PROP_CONTENT_TYPE:
534 err = decode_string_property(current_prop,
535 &properties_len, buf);
536 break;
537 case MQTT_PROP_USER_PROPERTY:
538 err = decode_user_property(current_prop,
539 &properties_len, buf);
540 break;
541 case MQTT_PROP_AUTHENTICATION_DATA:
542 case MQTT_PROP_CORRELATION_DATA:
543 err = decode_binary_property(current_prop,
544 &properties_len, buf);
545 break;
546 case MQTT_PROP_SUBSCRIPTION_IDENTIFIER:
547 err = decode_sub_id_property(current_prop,
548 &properties_len, buf);
549 break;
550 default:
551 err = -ENOTSUP;
552 }
553
554 if (err < 0) {
555 return err;
556 }
557 }
558
559 return bytes;
560 }
561
connack_properties_decode(struct buf_ctx * buf,struct mqtt_connack_param * param)562 static int connack_properties_decode(struct buf_ctx *buf,
563 struct mqtt_connack_param *param)
564 {
565 struct property_decoder prop[] = {
566 {
567 ¶m->prop.session_expiry_interval,
568 ¶m->prop.rx.has_session_expiry_interval,
569 MQTT_PROP_SESSION_EXPIRY_INTERVAL
570 },
571 {
572 ¶m->prop.receive_maximum,
573 ¶m->prop.rx.has_receive_maximum,
574 MQTT_PROP_RECEIVE_MAXIMUM
575 },
576 {
577 ¶m->prop.maximum_qos,
578 ¶m->prop.rx.has_maximum_qos,
579 MQTT_PROP_MAXIMUM_QOS
580 },
581 {
582 ¶m->prop.retain_available,
583 ¶m->prop.rx.has_retain_available,
584 MQTT_PROP_RETAIN_AVAILABLE
585 },
586 {
587 ¶m->prop.maximum_packet_size,
588 ¶m->prop.rx.has_maximum_packet_size,
589 MQTT_PROP_MAXIMUM_PACKET_SIZE
590 },
591 {
592 ¶m->prop.assigned_client_id,
593 ¶m->prop.rx.has_assigned_client_id,
594 MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER
595 },
596 {
597 ¶m->prop.topic_alias_maximum,
598 ¶m->prop.rx.has_topic_alias_maximum,
599 MQTT_PROP_TOPIC_ALIAS_MAXIMUM
600 },
601 {
602 ¶m->prop.reason_string,
603 ¶m->prop.rx.has_reason_string,
604 MQTT_PROP_REASON_STRING
605 },
606 {
607 ¶m->prop.user_prop,
608 ¶m->prop.rx.has_user_prop,
609 MQTT_PROP_USER_PROPERTY
610 },
611 {
612 ¶m->prop.wildcard_sub_available,
613 ¶m->prop.rx.has_wildcard_sub_available,
614 MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE
615 },
616 {
617 ¶m->prop.subscription_ids_available,
618 ¶m->prop.rx.has_subscription_ids_available,
619 MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE
620 },
621 {
622 ¶m->prop.shared_sub_available,
623 ¶m->prop.rx.has_shared_sub_available,
624 MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE
625 },
626 {
627 ¶m->prop.server_keep_alive,
628 ¶m->prop.rx.has_server_keep_alive,
629 MQTT_PROP_SERVER_KEEP_ALIVE
630 },
631 {
632 ¶m->prop.response_information,
633 ¶m->prop.rx.has_response_information,
634 MQTT_PROP_RESPONSE_INFORMATION
635 },
636 {
637 ¶m->prop.server_reference,
638 ¶m->prop.rx.has_server_reference,
639 MQTT_PROP_SERVER_REFERENCE
640 },
641 {
642 ¶m->prop.auth_method,
643 ¶m->prop.rx.has_auth_method,
644 MQTT_PROP_AUTHENTICATION_METHOD
645 },
646 {
647 ¶m->prop.auth_data,
648 ¶m->prop.rx.has_auth_data,
649 MQTT_PROP_AUTHENTICATION_DATA
650 }
651 };
652
653 return properties_decode(prop, ARRAY_SIZE(prop), buf);
654 }
655 #else
connack_properties_decode(struct buf_ctx * buf,struct mqtt_connack_param * param)656 static int connack_properties_decode(struct buf_ctx *buf,
657 struct mqtt_connack_param *param)
658 {
659 ARG_UNUSED(param);
660 ARG_UNUSED(buf);
661
662 return -ENOTSUP;
663 }
664 #endif /* CONFIG_MQTT_VERSION_5_0 */
665
connect_ack_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_connack_param * param)666 int connect_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
667 struct mqtt_connack_param *param)
668 {
669 int err_code;
670 uint8_t flags, ret_code;
671
672 err_code = unpack_uint8(buf, &flags);
673 if (err_code != 0) {
674 return err_code;
675 }
676
677 err_code = unpack_uint8(buf, &ret_code);
678 if (err_code != 0) {
679 return err_code;
680 }
681
682 param->return_code = ret_code;
683
684 if (client->protocol_version == MQTT_VERSION_3_1_0) {
685 goto out;
686 }
687
688 param->session_present_flag = flags & MQTT_CONNACK_FLAG_SESSION_PRESENT;
689 NET_DBG("[CID %p]: session_present_flag: %d", client,
690 param->session_present_flag);
691
692 if (mqtt_is_version_5_0(client)) {
693 err_code = connack_properties_decode(buf, param);
694 if (err_code < 0) {
695 return err_code;
696 }
697 }
698
699 out:
700 return 0;
701 }
702
703 #if defined(CONFIG_MQTT_VERSION_5_0)
publish_properties_decode(struct buf_ctx * buf,struct mqtt_publish_param * param)704 static int publish_properties_decode(struct buf_ctx *buf,
705 struct mqtt_publish_param *param)
706 {
707 struct property_decoder prop[] = {
708 {
709 ¶m->prop.payload_format_indicator,
710 ¶m->prop.rx.has_payload_format_indicator,
711 MQTT_PROP_PAYLOAD_FORMAT_INDICATOR
712 },
713 {
714 ¶m->prop.message_expiry_interval,
715 ¶m->prop.rx.has_message_expiry_interval,
716 MQTT_PROP_MESSAGE_EXPIRY_INTERVAL
717 },
718 {
719 ¶m->prop.topic_alias,
720 ¶m->prop.rx.has_topic_alias,
721 MQTT_PROP_TOPIC_ALIAS
722 },
723 {
724 ¶m->prop.response_topic,
725 ¶m->prop.rx.has_response_topic,
726 MQTT_PROP_RESPONSE_TOPIC
727 },
728 {
729 ¶m->prop.correlation_data,
730 ¶m->prop.rx.has_correlation_data,
731 MQTT_PROP_CORRELATION_DATA
732 },
733 {
734 ¶m->prop.user_prop,
735 ¶m->prop.rx.has_user_prop,
736 MQTT_PROP_USER_PROPERTY
737 },
738 {
739 ¶m->prop.subscription_identifier,
740 ¶m->prop.rx.has_subscription_identifier,
741 MQTT_PROP_SUBSCRIPTION_IDENTIFIER
742 },
743 {
744 ¶m->prop.content_type,
745 ¶m->prop.rx.has_content_type,
746 MQTT_PROP_CONTENT_TYPE
747 }
748 };
749
750 return properties_decode(prop, ARRAY_SIZE(prop), buf);
751 }
752
publish_topic_alias_check(struct mqtt_client * client,struct mqtt_publish_param * param)753 static int publish_topic_alias_check(struct mqtt_client *client,
754 struct mqtt_publish_param *param)
755 {
756 uint16_t alias = param->prop.topic_alias;
757 struct mqtt_utf8 *topic_str = ¶m->message.topic.topic;
758 struct mqtt_topic_alias *topic_alias;
759
760 /* Topic alias must not exceed configured CONFIG_MQTT_TOPIC_ALIAS_MAX */
761 if (alias > CONFIG_MQTT_TOPIC_ALIAS_MAX) {
762 set_disconnect_reason(client, MQTT_DISCONNECT_TOPIC_ALIAS_INVALID);
763 return -EBADMSG;
764 }
765
766 if (topic_str->size == 0) {
767 /* In case there's no topic, topic alias must be set */
768 if (alias == 0) {
769 return -EBADMSG;
770 }
771
772 /* Topic alias number corresponds to the aliases array index. */
773 topic_alias = &client->internal.topic_aliases[alias - 1];
774
775 /* In case topic alias has not been configured yet, report an error. */
776 if (topic_alias->topic_size == 0) {
777 return -EBADMSG;
778 }
779
780 topic_str->utf8 = topic_alias->topic_buf;
781 topic_str->size = topic_alias->topic_size;
782
783 return 0;
784 }
785
786 /* If topic is present and topic alias is set, configure the alias locally. */
787 if (alias > 0) {
788 topic_alias = &client->internal.topic_aliases[alias - 1];
789
790 if (topic_str->size > ARRAY_SIZE(topic_alias->topic_buf)) {
791 NET_ERR("Topic too long (%d bytes) to store, increase "
792 "CONFIG_MQTT_TOPIC_ALIAS_STRING_MAX",
793 topic_str->size);
794 set_disconnect_reason(client, MQTT_DISCONNECT_IMPL_SPECIFIC_ERROR);
795 return -ENOMEM;
796 }
797
798 memcpy(topic_alias->topic_buf, topic_str->utf8, topic_str->size);
799 topic_alias->topic_size = topic_str->size;
800 }
801
802 return 0;
803 }
804 #else
publish_properties_decode(struct buf_ctx * buf,struct mqtt_publish_param * param)805 static int publish_properties_decode(struct buf_ctx *buf,
806 struct mqtt_publish_param *param)
807 {
808 ARG_UNUSED(param);
809 ARG_UNUSED(buf);
810
811 return -ENOTSUP;
812 }
813
publish_topic_alias_check(struct mqtt_client * client,struct mqtt_publish_param * param)814 static int publish_topic_alias_check(struct mqtt_client *client,
815 struct mqtt_publish_param *param)
816 {
817 ARG_UNUSED(client);
818 ARG_UNUSED(param);
819
820 return -ENOTSUP;
821 }
822 #endif /* CONFIG_MQTT_VERSION_5_0 */
823
publish_decode(struct mqtt_client * client,uint8_t flags,uint32_t var_length,struct buf_ctx * buf,struct mqtt_publish_param * param)824 int publish_decode(struct mqtt_client *client, uint8_t flags,
825 uint32_t var_length, struct buf_ctx *buf,
826 struct mqtt_publish_param *param)
827 {
828 int err_code;
829 uint32_t var_header_length;
830
831 param->dup_flag = flags & MQTT_HEADER_DUP_MASK;
832 param->retain_flag = flags & MQTT_HEADER_RETAIN_MASK;
833 param->message.topic.qos = ((flags & MQTT_HEADER_QOS_MASK) >> 1);
834
835 err_code = unpack_utf8_str(buf, ¶m->message.topic.topic);
836 if (err_code != 0) {
837 return err_code;
838 }
839
840 var_header_length = param->message.topic.topic.size + sizeof(uint16_t);
841
842 if (param->message.topic.qos > MQTT_QOS_0_AT_MOST_ONCE) {
843 err_code = unpack_uint16(buf, ¶m->message_id);
844 if (err_code != 0) {
845 return err_code;
846 }
847
848 var_header_length += sizeof(uint16_t);
849 }
850
851 if (mqtt_is_version_5_0(client)) {
852 err_code = publish_properties_decode(buf, param);
853 if (err_code < 0) {
854 return err_code;
855 }
856
857 /* Add parsed properties length */
858 var_header_length += err_code;
859
860 err_code = publish_topic_alias_check(client, param);
861 if (err_code < 0) {
862 return err_code;
863 }
864 }
865
866 if (var_length < var_header_length) {
867 NET_ERR("Corrupted PUBLISH message, header length (%u) larger "
868 "than total length (%u)", var_header_length,
869 var_length);
870 return -EINVAL;
871 }
872
873 param->message.payload.data = NULL;
874 param->message.payload.len = var_length - var_header_length;
875
876 return 0;
877 }
878
879 #if defined(CONFIG_MQTT_VERSION_5_0)
common_ack_properties_decode(struct buf_ctx * buf,struct mqtt_common_ack_properties * prop)880 static int common_ack_properties_decode(struct buf_ctx *buf,
881 struct mqtt_common_ack_properties *prop)
882 {
883 struct property_decoder prop_dec[] = {
884 {
885 &prop->reason_string,
886 &prop->rx.has_reason_string,
887 MQTT_PROP_REASON_STRING
888 },
889 {
890 &prop->user_prop,
891 &prop->rx.has_user_prop,
892 MQTT_PROP_USER_PROPERTY
893 }
894 };
895
896 return properties_decode(prop_dec, ARRAY_SIZE(prop_dec), buf);
897 }
898 #else
common_ack_properties_decode(struct buf_ctx * buf,struct mqtt_common_ack_properties * prop)899 static int common_ack_properties_decode(struct buf_ctx *buf,
900 struct mqtt_common_ack_properties *prop)
901 {
902 ARG_UNUSED(prop);
903 ARG_UNUSED(buf);
904
905 return -ENOTSUP;
906 }
907 #endif /* CONFIG_MQTT_VERSION_5_0 */
908
common_pub_ack_decode(struct buf_ctx * buf,uint16_t * message_id,uint8_t * reason_code,struct mqtt_common_ack_properties * prop)909 static int common_pub_ack_decode(struct buf_ctx *buf, uint16_t *message_id,
910 uint8_t *reason_code,
911 struct mqtt_common_ack_properties *prop)
912 {
913 size_t remaining_len;
914 int err;
915
916 err = unpack_uint16(buf, message_id);
917 if (err < 0) {
918 return err;
919 }
920
921 remaining_len = buf->end - buf->cur;
922
923 /* For MQTT < 5.0 properties are NULL. */
924 if (prop != NULL && reason_code != NULL) {
925 if (remaining_len > 0) {
926 err = unpack_uint8(buf, reason_code);
927 if (err < 0) {
928 return err;
929 }
930 }
931
932 if (remaining_len > 1) {
933 err = common_ack_properties_decode(buf, prop);
934 if (err < 0) {
935 return err;
936 }
937 }
938 }
939
940 return 0;
941 }
942
publish_ack_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_puback_param * param)943 int publish_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
944 struct mqtt_puback_param *param)
945 {
946 struct mqtt_common_ack_properties *prop = NULL;
947 uint8_t *reason_code = NULL;
948
949 #if defined(CONFIG_MQTT_VERSION_5_0)
950 if (mqtt_is_version_5_0(client)) {
951 prop = ¶m->prop;
952 reason_code = ¶m->reason_code;
953 }
954 #endif
955
956 return common_pub_ack_decode(buf, ¶m->message_id, reason_code, prop);
957 }
958
publish_receive_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_pubrec_param * param)959 int publish_receive_decode(const struct mqtt_client *client, struct buf_ctx *buf,
960 struct mqtt_pubrec_param *param)
961 {
962 struct mqtt_common_ack_properties *prop = NULL;
963 uint8_t *reason_code = NULL;
964
965 #if defined(CONFIG_MQTT_VERSION_5_0)
966 if (mqtt_is_version_5_0(client)) {
967 prop = ¶m->prop;
968 reason_code = ¶m->reason_code;
969 }
970 #endif
971
972 return common_pub_ack_decode(buf, ¶m->message_id, reason_code, prop);
973 }
974
publish_release_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_pubrel_param * param)975 int publish_release_decode(const struct mqtt_client *client, struct buf_ctx *buf,
976 struct mqtt_pubrel_param *param)
977 {
978 struct mqtt_common_ack_properties *prop = NULL;
979 uint8_t *reason_code = NULL;
980
981 #if defined(CONFIG_MQTT_VERSION_5_0)
982 if (mqtt_is_version_5_0(client)) {
983 prop = ¶m->prop;
984 reason_code = ¶m->reason_code;
985 }
986 #endif
987
988 return common_pub_ack_decode(buf, ¶m->message_id, reason_code, prop);
989 }
990
publish_complete_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_pubcomp_param * param)991 int publish_complete_decode(const struct mqtt_client *client, struct buf_ctx *buf,
992 struct mqtt_pubcomp_param *param)
993 {
994 struct mqtt_common_ack_properties *prop = NULL;
995 uint8_t *reason_code = NULL;
996
997 #if defined(CONFIG_MQTT_VERSION_5_0)
998 if (mqtt_is_version_5_0(client)) {
999 prop = ¶m->prop;
1000 reason_code = ¶m->reason_code;
1001 }
1002 #endif
1003
1004 return common_pub_ack_decode(buf, ¶m->message_id, reason_code, prop);
1005 }
1006
1007 #if defined(CONFIG_MQTT_VERSION_5_0)
suback_properties_decode(struct buf_ctx * buf,struct mqtt_suback_param * param)1008 static int suback_properties_decode(struct buf_ctx *buf,
1009 struct mqtt_suback_param *param)
1010 {
1011 return common_ack_properties_decode(buf, ¶m->prop);
1012 }
1013 #else
suback_properties_decode(struct buf_ctx * buf,struct mqtt_suback_param * param)1014 static int suback_properties_decode(struct buf_ctx *buf,
1015 struct mqtt_suback_param *param)
1016 {
1017 ARG_UNUSED(param);
1018 ARG_UNUSED(buf);
1019
1020 return -ENOTSUP;
1021 }
1022 #endif /* CONFIG_MQTT_VERSION_5_0 */
1023
subscribe_ack_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_suback_param * param)1024 int subscribe_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
1025 struct mqtt_suback_param *param)
1026 {
1027 int err_code;
1028
1029 err_code = unpack_uint16(buf, ¶m->message_id);
1030 if (err_code != 0) {
1031 return err_code;
1032 }
1033
1034 if (mqtt_is_version_5_0(client)) {
1035 err_code = suback_properties_decode(buf, param);
1036 if (err_code < 0) {
1037 return err_code;
1038 }
1039 }
1040
1041 return unpack_raw_data(buf->end - buf->cur, buf, ¶m->return_codes);
1042 }
1043
1044 #if defined(CONFIG_MQTT_VERSION_5_0)
unsuback_5_0_decode(struct buf_ctx * buf,struct mqtt_unsuback_param * param)1045 static int unsuback_5_0_decode(struct buf_ctx *buf,
1046 struct mqtt_unsuback_param *param)
1047 {
1048 int err;
1049
1050 err = common_ack_properties_decode(buf, ¶m->prop);
1051 if (err < 0) {
1052 return err;
1053 }
1054
1055 return unpack_raw_data(buf->end - buf->cur, buf, ¶m->reason_codes);
1056 }
1057 #else
unsuback_5_0_decode(struct buf_ctx * buf,struct mqtt_unsuback_param * param)1058 static int unsuback_5_0_decode(struct buf_ctx *buf,
1059 struct mqtt_unsuback_param *param)
1060 {
1061 ARG_UNUSED(param);
1062 ARG_UNUSED(buf);
1063
1064 return -ENOTSUP;
1065 }
1066 #endif /* CONFIG_MQTT_VERSION_5_0 */
1067
unsubscribe_ack_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_unsuback_param * param)1068 int unsubscribe_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
1069 struct mqtt_unsuback_param *param)
1070 {
1071 int err;
1072
1073 err = unpack_uint16(buf, ¶m->message_id);
1074 if (err < 0) {
1075 return 0;
1076 }
1077
1078 if (mqtt_is_version_5_0(client)) {
1079 return unsuback_5_0_decode(buf, param);
1080 }
1081
1082 return 0;
1083 }
1084
1085 #if defined(CONFIG_MQTT_VERSION_5_0)
disconnect_properties_decode(struct buf_ctx * buf,struct mqtt_disconnect_param * param)1086 static int disconnect_properties_decode(struct buf_ctx *buf,
1087 struct mqtt_disconnect_param *param)
1088 {
1089 struct property_decoder prop[] = {
1090 {
1091 ¶m->prop.session_expiry_interval,
1092 ¶m->prop.rx.has_session_expiry_interval,
1093 MQTT_PROP_SESSION_EXPIRY_INTERVAL
1094 },
1095 {
1096 ¶m->prop.reason_string,
1097 ¶m->prop.rx.has_reason_string,
1098 MQTT_PROP_REASON_STRING
1099 },
1100 {
1101 ¶m->prop.user_prop,
1102 ¶m->prop.rx.has_user_prop,
1103 MQTT_PROP_USER_PROPERTY
1104 },
1105 {
1106 ¶m->prop.server_reference,
1107 ¶m->prop.rx.has_server_reference,
1108 MQTT_PROP_SERVER_REFERENCE
1109 }
1110 };
1111
1112 return properties_decode(prop, ARRAY_SIZE(prop), buf);
1113 }
1114
disconnect_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_disconnect_param * param)1115 int disconnect_decode(const struct mqtt_client *client, struct buf_ctx *buf,
1116 struct mqtt_disconnect_param *param)
1117 {
1118
1119 size_t remaining_len;
1120 uint8_t reason_code;
1121 int err;
1122
1123 if (!mqtt_is_version_5_0(client)) {
1124 return -ENOTSUP;
1125 }
1126
1127 remaining_len = buf->end - buf->cur;
1128
1129 if (remaining_len > 0) {
1130 err = unpack_uint8(buf, &reason_code);
1131 if (err < 0) {
1132 return err;
1133 }
1134
1135 param->reason_code = reason_code;
1136 }
1137
1138 if (remaining_len > 1) {
1139 err = disconnect_properties_decode(buf, param);
1140 if (err < 0) {
1141 return err;
1142 }
1143 }
1144
1145 return 0;
1146 }
1147
auth_properties_decode(struct buf_ctx * buf,struct mqtt_auth_param * param)1148 static int auth_properties_decode(struct buf_ctx *buf,
1149 struct mqtt_auth_param *param)
1150 {
1151 struct property_decoder prop[] = {
1152 {
1153 ¶m->prop.auth_method,
1154 ¶m->prop.rx.has_auth_method,
1155 MQTT_PROP_AUTHENTICATION_METHOD
1156 },
1157 {
1158 ¶m->prop.auth_data,
1159 ¶m->prop.rx.has_auth_data,
1160 MQTT_PROP_AUTHENTICATION_DATA
1161 },
1162 {
1163 ¶m->prop.reason_string,
1164 ¶m->prop.rx.has_reason_string,
1165 MQTT_PROP_REASON_STRING
1166 },
1167 {
1168 ¶m->prop.user_prop,
1169 ¶m->prop.rx.has_user_prop,
1170 MQTT_PROP_USER_PROPERTY
1171 }
1172 };
1173
1174 return properties_decode(prop, ARRAY_SIZE(prop), buf);
1175 }
1176
auth_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_auth_param * param)1177 int auth_decode(const struct mqtt_client *client, struct buf_ctx *buf,
1178 struct mqtt_auth_param *param)
1179 {
1180 size_t remaining_len;
1181 uint8_t reason_code;
1182 int err;
1183
1184 if (!mqtt_is_version_5_0(client)) {
1185 return -ENOTSUP;
1186 }
1187
1188 remaining_len = buf->end - buf->cur;
1189
1190 if (remaining_len > 0) {
1191 err = unpack_uint8(buf, &reason_code);
1192 if (err < 0) {
1193 return err;
1194 }
1195
1196 param->reason_code = reason_code;
1197 }
1198
1199 if (remaining_len > 1) {
1200 err = auth_properties_decode(buf, param);
1201 if (err < 0) {
1202 return err;
1203 }
1204 }
1205
1206 return 0;
1207 }
1208 #endif /* CONFIG_MQTT_VERSION_5_0 */
1209