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 			&param->prop.session_expiry_interval,
568 			&param->prop.rx.has_session_expiry_interval,
569 			MQTT_PROP_SESSION_EXPIRY_INTERVAL
570 		},
571 		{
572 			&param->prop.receive_maximum,
573 			&param->prop.rx.has_receive_maximum,
574 			MQTT_PROP_RECEIVE_MAXIMUM
575 		},
576 		{
577 			&param->prop.maximum_qos,
578 			&param->prop.rx.has_maximum_qos,
579 			MQTT_PROP_MAXIMUM_QOS
580 		},
581 		{
582 			&param->prop.retain_available,
583 			&param->prop.rx.has_retain_available,
584 			MQTT_PROP_RETAIN_AVAILABLE
585 		},
586 		{
587 			&param->prop.maximum_packet_size,
588 			&param->prop.rx.has_maximum_packet_size,
589 			MQTT_PROP_MAXIMUM_PACKET_SIZE
590 		},
591 		{
592 			&param->prop.assigned_client_id,
593 			&param->prop.rx.has_assigned_client_id,
594 			MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER
595 		},
596 		{
597 			&param->prop.topic_alias_maximum,
598 			&param->prop.rx.has_topic_alias_maximum,
599 			MQTT_PROP_TOPIC_ALIAS_MAXIMUM
600 		},
601 		{
602 			&param->prop.reason_string,
603 			&param->prop.rx.has_reason_string,
604 			MQTT_PROP_REASON_STRING
605 		},
606 		{
607 			&param->prop.user_prop,
608 			&param->prop.rx.has_user_prop,
609 			MQTT_PROP_USER_PROPERTY
610 		},
611 		{
612 			&param->prop.wildcard_sub_available,
613 			&param->prop.rx.has_wildcard_sub_available,
614 			MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE
615 		},
616 		{
617 			&param->prop.subscription_ids_available,
618 			&param->prop.rx.has_subscription_ids_available,
619 			MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE
620 		},
621 		{
622 			&param->prop.shared_sub_available,
623 			&param->prop.rx.has_shared_sub_available,
624 			MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE
625 		},
626 		{
627 			&param->prop.server_keep_alive,
628 			&param->prop.rx.has_server_keep_alive,
629 			MQTT_PROP_SERVER_KEEP_ALIVE
630 		},
631 		{
632 			&param->prop.response_information,
633 			&param->prop.rx.has_response_information,
634 			MQTT_PROP_RESPONSE_INFORMATION
635 		},
636 		{
637 			&param->prop.server_reference,
638 			&param->prop.rx.has_server_reference,
639 			MQTT_PROP_SERVER_REFERENCE
640 		},
641 		{
642 			&param->prop.auth_method,
643 			&param->prop.rx.has_auth_method,
644 			MQTT_PROP_AUTHENTICATION_METHOD
645 		},
646 		{
647 			&param->prop.auth_data,
648 			&param->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 			&param->prop.payload_format_indicator,
710 			&param->prop.rx.has_payload_format_indicator,
711 			MQTT_PROP_PAYLOAD_FORMAT_INDICATOR
712 		},
713 		{
714 			&param->prop.message_expiry_interval,
715 			&param->prop.rx.has_message_expiry_interval,
716 			MQTT_PROP_MESSAGE_EXPIRY_INTERVAL
717 		},
718 		{
719 			&param->prop.topic_alias,
720 			&param->prop.rx.has_topic_alias,
721 			MQTT_PROP_TOPIC_ALIAS
722 		},
723 		{
724 			&param->prop.response_topic,
725 			&param->prop.rx.has_response_topic,
726 			MQTT_PROP_RESPONSE_TOPIC
727 		},
728 		{
729 			&param->prop.correlation_data,
730 			&param->prop.rx.has_correlation_data,
731 			MQTT_PROP_CORRELATION_DATA
732 		},
733 		{
734 			&param->prop.user_prop,
735 			&param->prop.rx.has_user_prop,
736 			MQTT_PROP_USER_PROPERTY
737 		},
738 		{
739 			&param->prop.subscription_identifier,
740 			&param->prop.rx.has_subscription_identifier,
741 			MQTT_PROP_SUBSCRIPTION_IDENTIFIER
742 		},
743 		{
744 			&param->prop.content_type,
745 			&param->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 = &param->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, &param->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, &param->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 = &param->prop;
952 		reason_code = &param->reason_code;
953 	}
954 #endif
955 
956 	return common_pub_ack_decode(buf, &param->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 = &param->prop;
968 		reason_code = &param->reason_code;
969 	}
970 #endif
971 
972 	return common_pub_ack_decode(buf, &param->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 = &param->prop;
984 		reason_code = &param->reason_code;
985 	}
986 #endif
987 
988 	return common_pub_ack_decode(buf, &param->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 = &param->prop;
1000 		reason_code = &param->reason_code;
1001 	}
1002 #endif
1003 
1004 	return common_pub_ack_decode(buf, &param->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, &param->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, &param->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, &param->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, &param->prop);
1051 	if (err < 0) {
1052 		return err;
1053 	}
1054 
1055 	return unpack_raw_data(buf->end - buf->cur, buf, &param->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, &param->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 			&param->prop.session_expiry_interval,
1092 			&param->prop.rx.has_session_expiry_interval,
1093 			MQTT_PROP_SESSION_EXPIRY_INTERVAL
1094 		},
1095 		{
1096 			&param->prop.reason_string,
1097 			&param->prop.rx.has_reason_string,
1098 			MQTT_PROP_REASON_STRING
1099 		},
1100 		{
1101 			&param->prop.user_prop,
1102 			&param->prop.rx.has_user_prop,
1103 			MQTT_PROP_USER_PROPERTY
1104 		},
1105 		{
1106 			&param->prop.server_reference,
1107 			&param->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 			&param->prop.auth_method,
1154 			&param->prop.rx.has_auth_method,
1155 			MQTT_PROP_AUTHENTICATION_METHOD
1156 		},
1157 		{
1158 			&param->prop.auth_data,
1159 			&param->prop.rx.has_auth_data,
1160 			MQTT_PROP_AUTHENTICATION_DATA
1161 		},
1162 		{
1163 			&param->prop.reason_string,
1164 			&param->prop.rx.has_reason_string,
1165 			MQTT_PROP_REASON_STRING
1166 		},
1167 		{
1168 			&param->prop.user_prop,
1169 			&param->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