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(&param->prop.response_topic) +
865 	       binary_property_length(&param->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(&param->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 				     &param->prop.response_topic, buf);
904 	if (err < 0) {
905 		return err;
906 	}
907 
908 	err = encode_binary_property(MQTT_PROP_CORRELATION_DATA,
909 				     &param->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 				     &param->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(&param->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 = &param->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 = &param->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 = &param->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 = &param->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(&param->prop.reason_string) +
1198 	       user_properties_length(param->prop.user_prop) +
1199 	       string_property_length(&param->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 				     &param->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 				     &param->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(&param->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(&param->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(&param->prop.auth_method) +
1488 	       binary_property_length(&param->prop.auth_data) +
1489 	       string_property_length(&param->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 				     &param->prop.auth_method, buf);
1512 	if (err < 0) {
1513 		return err;
1514 	}
1515 
1516 	err = encode_binary_property(MQTT_PROP_AUTHENTICATION_DATA,
1517 				     &param->prop.auth_data, buf);
1518 	if (err < 0) {
1519 		return err;
1520 	}
1521 
1522 	err = encode_string_property(MQTT_PROP_REASON_STRING,
1523 				     &param->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