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.
123  *
124  * @param[in] length Binary string length.
125  * @param[inout] buf A pointer to the buf_ctx structure containing current
126  *                   buffer position.
127  * @param[out] str Pointer to a binary string that will hold the binary string
128  *                 location in the buffer.
129  *
130  * @retval 0 if the procedure is successful.
131  * @retval -EINVAL if the buffer would be exceeded during the read
132  */
unpack_data(uint32_t length,struct buf_ctx * buf,struct mqtt_binstr * str)133 static int unpack_data(uint32_t length, struct buf_ctx *buf,
134 		       struct mqtt_binstr *str)
135 {
136 	NET_DBG(">> cur:%p, end:%p", (void *)buf->cur, (void *)buf->end);
137 
138 	if ((buf->end - buf->cur) < length) {
139 		return -EINVAL;
140 	}
141 
142 	str->len = length;
143 
144 	/* Zero length binary strings are permitted. */
145 	if (length > 0) {
146 		str->data = buf->cur;
147 		buf->cur += length;
148 	} else {
149 		str->data = NULL;
150 	}
151 
152 	NET_DBG("<< bin len:%08x", GET_BINSTR_BUFFER_SIZE(str));
153 
154 	return 0;
155 }
156 
157 /**@brief Decode MQTT Packet Length in the MQTT fixed header.
158  *
159  * @param[inout] buf A pointer to the buf_ctx structure containing current
160  *                   buffer position.
161  * @param[out] length Length of variable header and payload in the
162  *                              MQTT message.
163  *
164  * @retval 0 if the procedure is successful.
165  * @retval -EINVAL if the length decoding would use more that 4 bytes.
166  * @retval -EAGAIN if the buffer would be exceeded during the read.
167  */
packet_length_decode(struct buf_ctx * buf,uint32_t * length)168 static int packet_length_decode(struct buf_ctx *buf, uint32_t *length)
169 {
170 	uint8_t shift = 0U;
171 	uint8_t bytes = 0U;
172 
173 	*length = 0U;
174 	do {
175 		if (bytes >= MQTT_MAX_LENGTH_BYTES) {
176 			return -EINVAL;
177 		}
178 
179 		if (buf->cur >= buf->end) {
180 			return -EAGAIN;
181 		}
182 
183 		*length += ((uint32_t)*(buf->cur) & MQTT_LENGTH_VALUE_MASK)
184 								<< shift;
185 		shift += MQTT_LENGTH_SHIFT;
186 		bytes++;
187 	} while ((*(buf->cur++) & MQTT_LENGTH_CONTINUATION_BIT) != 0U);
188 
189 	if (*length > MQTT_MAX_PAYLOAD_SIZE) {
190 		return -EINVAL;
191 	}
192 
193 	NET_DBG("length:0x%08x", *length);
194 
195 	return 0;
196 }
197 
fixed_header_decode(struct buf_ctx * buf,uint8_t * type_and_flags,uint32_t * length)198 int fixed_header_decode(struct buf_ctx *buf, uint8_t *type_and_flags,
199 			uint32_t *length)
200 {
201 	int err_code;
202 
203 	err_code = unpack_uint8(buf, type_and_flags);
204 	if (err_code != 0) {
205 		return err_code;
206 	}
207 
208 	return packet_length_decode(buf, length);
209 }
210 
connect_ack_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_connack_param * param)211 int connect_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
212 		       struct mqtt_connack_param *param)
213 {
214 	int err_code;
215 	uint8_t flags, ret_code;
216 
217 	err_code = unpack_uint8(buf, &flags);
218 	if (err_code != 0) {
219 		return err_code;
220 	}
221 
222 	err_code = unpack_uint8(buf, &ret_code);
223 	if (err_code != 0) {
224 		return err_code;
225 	}
226 
227 	if (client->protocol_version == MQTT_VERSION_3_1_1) {
228 		param->session_present_flag =
229 			flags & MQTT_CONNACK_FLAG_SESSION_PRESENT;
230 
231 		NET_DBG("[CID %p]: session_present_flag: %d", client,
232 			 param->session_present_flag);
233 	}
234 
235 	param->return_code = (enum mqtt_conn_return_code)ret_code;
236 
237 	return 0;
238 }
239 
publish_decode(uint8_t flags,uint32_t var_length,struct buf_ctx * buf,struct mqtt_publish_param * param)240 int publish_decode(uint8_t flags, uint32_t var_length, struct buf_ctx *buf,
241 		   struct mqtt_publish_param *param)
242 {
243 	int err_code;
244 	uint32_t var_header_length;
245 
246 	param->dup_flag = flags & MQTT_HEADER_DUP_MASK;
247 	param->retain_flag = flags & MQTT_HEADER_RETAIN_MASK;
248 	param->message.topic.qos = ((flags & MQTT_HEADER_QOS_MASK) >> 1);
249 
250 	err_code = unpack_utf8_str(buf, &param->message.topic.topic);
251 	if (err_code != 0) {
252 		return err_code;
253 	}
254 
255 	var_header_length = param->message.topic.topic.size + sizeof(uint16_t);
256 
257 	if (param->message.topic.qos > MQTT_QOS_0_AT_MOST_ONCE) {
258 		err_code = unpack_uint16(buf, &param->message_id);
259 		if (err_code != 0) {
260 			return err_code;
261 		}
262 
263 		var_header_length += sizeof(uint16_t);
264 	}
265 
266 	if (var_length < var_header_length) {
267 		NET_ERR("Corrupted PUBLISH message, header length (%u) larger "
268 			 "than total length (%u)", var_header_length,
269 			 var_length);
270 		return -EINVAL;
271 	}
272 
273 	param->message.payload.data = NULL;
274 	param->message.payload.len = var_length - var_header_length;
275 
276 	return 0;
277 }
278 
publish_ack_decode(struct buf_ctx * buf,struct mqtt_puback_param * param)279 int publish_ack_decode(struct buf_ctx *buf, struct mqtt_puback_param *param)
280 {
281 	return unpack_uint16(buf, &param->message_id);
282 }
283 
publish_receive_decode(struct buf_ctx * buf,struct mqtt_pubrec_param * param)284 int publish_receive_decode(struct buf_ctx *buf, struct mqtt_pubrec_param *param)
285 {
286 	return unpack_uint16(buf, &param->message_id);
287 }
288 
publish_release_decode(struct buf_ctx * buf,struct mqtt_pubrel_param * param)289 int publish_release_decode(struct buf_ctx *buf, struct mqtt_pubrel_param *param)
290 {
291 	return unpack_uint16(buf, &param->message_id);
292 }
293 
publish_complete_decode(struct buf_ctx * buf,struct mqtt_pubcomp_param * param)294 int publish_complete_decode(struct buf_ctx *buf,
295 			    struct mqtt_pubcomp_param *param)
296 {
297 	return unpack_uint16(buf, &param->message_id);
298 }
299 
subscribe_ack_decode(struct buf_ctx * buf,struct mqtt_suback_param * param)300 int subscribe_ack_decode(struct buf_ctx *buf, struct mqtt_suback_param *param)
301 {
302 	int err_code;
303 
304 	err_code = unpack_uint16(buf, &param->message_id);
305 	if (err_code != 0) {
306 		return err_code;
307 	}
308 
309 	return unpack_data(buf->end - buf->cur, buf, &param->return_codes);
310 }
311 
unsubscribe_ack_decode(struct buf_ctx * buf,struct mqtt_unsuback_param * param)312 int unsubscribe_ack_decode(struct buf_ctx *buf,
313 			   struct mqtt_unsuback_param *param)
314 {
315 	return unpack_uint16(buf, &param->message_id);
316 }
317