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 <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 	MQTT_TRC(">> cur:%p, end:%p", buf->cur, buf->end);
33 
34 	if ((buf->end - buf->cur) < sizeof(uint8_t)) {
35 		return -EINVAL;
36 	}
37 
38 	*val = *(buf->cur++);
39 
40 	MQTT_TRC("<< val:%02x", *val);
41 
42 	return 0;
43 }
44 
45 /**
46  * @brief Unpacks unsigned 16 bit value from the buffer from the offset
47  *        requested.
48  *
49  * @param[inout] buf A pointer to the buf_ctx structure containing current
50  *                   buffer position.
51  * @param[out] val Memory where the value is to be unpacked.
52  *
53  * @retval 0 if the procedure is successful.
54  * @retval -EINVAL if the buffer would be exceeded during the read
55  */
unpack_uint16(struct buf_ctx * buf,uint16_t * val)56 static int unpack_uint16(struct buf_ctx *buf, uint16_t *val)
57 {
58 	MQTT_TRC(">> cur:%p, end:%p", buf->cur, buf->end);
59 
60 	if ((buf->end - buf->cur) < sizeof(uint16_t)) {
61 		return -EINVAL;
62 	}
63 
64 	*val = *(buf->cur++) << 8; /* MSB */
65 	*val |= *(buf->cur++); /* LSB */
66 
67 	MQTT_TRC("<< val:%04x", *val);
68 
69 	return 0;
70 }
71 
72 /**
73  * @brief Unpacks utf8 string from the buffer from the offset requested.
74  *
75  * @param[inout] buf A pointer to the buf_ctx structure containing current
76  *                   buffer position.
77  * @param[out] str Pointer to a string that will hold the string location
78  *                 in the buffer.
79  *
80  * @retval 0 if the procedure is successful.
81  * @retval -EINVAL if the buffer would be exceeded during the read
82  */
unpack_utf8_str(struct buf_ctx * buf,struct mqtt_utf8 * str)83 static int unpack_utf8_str(struct buf_ctx *buf, struct mqtt_utf8 *str)
84 {
85 	uint16_t utf8_strlen;
86 	int err_code;
87 
88 	MQTT_TRC(">> cur:%p, end:%p", buf->cur, buf->end);
89 
90 	err_code = unpack_uint16(buf, &utf8_strlen);
91 	if (err_code != 0) {
92 		return err_code;
93 	}
94 
95 	if ((buf->end - buf->cur) < utf8_strlen) {
96 		return -EINVAL;
97 	}
98 
99 	str->size = utf8_strlen;
100 	/* Zero length UTF8 strings permitted. */
101 	if (utf8_strlen) {
102 		/* Point to right location in buffer. */
103 		str->utf8 = buf->cur;
104 		buf->cur += utf8_strlen;
105 	} else {
106 		str->utf8 = NULL;
107 	}
108 
109 	MQTT_TRC("<< str_size:%08x", (uint32_t)GET_UT8STR_BUFFER_SIZE(str));
110 
111 	return 0;
112 }
113 
114 /**
115  * @brief Unpacks binary string from the buffer from the offset requested.
116  *
117  * @param[in] length Binary string length.
118  * @param[inout] buf A pointer to the buf_ctx structure containing current
119  *                   buffer position.
120  * @param[out] str Pointer to a binary string that will hold the binary string
121  *                 location in the buffer.
122  *
123  * @retval 0 if the procedure is successful.
124  * @retval -EINVAL if the buffer would be exceeded during the read
125  */
unpack_data(uint32_t length,struct buf_ctx * buf,struct mqtt_binstr * str)126 static int unpack_data(uint32_t length, struct buf_ctx *buf,
127 		       struct mqtt_binstr *str)
128 {
129 	MQTT_TRC(">> cur:%p, end:%p", buf->cur, buf->end);
130 
131 	if ((buf->end - buf->cur) < length) {
132 		return -EINVAL;
133 	}
134 
135 	str->len = length;
136 
137 	/* Zero length binary strings are permitted. */
138 	if (length > 0) {
139 		str->data = buf->cur;
140 		buf->cur += length;
141 	} else {
142 		str->data = NULL;
143 	}
144 
145 	MQTT_TRC("<< bin len:%08x", GET_BINSTR_BUFFER_SIZE(str));
146 
147 	return 0;
148 }
149 
150 /**@brief Decode MQTT Packet Length in the MQTT fixed header.
151  *
152  * @param[inout] buf A pointer to the buf_ctx structure containing current
153  *                   buffer position.
154  * @param[out] length Length of variable header and payload in the
155  *                              MQTT message.
156  *
157  * @retval 0 if the procedure is successful.
158  * @retval -EINVAL if the length decoding would use more that 4 bytes.
159  * @retval -EAGAIN if the buffer would be exceeded during the read.
160  */
packet_length_decode(struct buf_ctx * buf,uint32_t * length)161 static int packet_length_decode(struct buf_ctx *buf, uint32_t *length)
162 {
163 	uint8_t shift = 0U;
164 	uint8_t bytes = 0U;
165 
166 	*length = 0U;
167 	do {
168 		if (bytes >= MQTT_MAX_LENGTH_BYTES) {
169 			return -EINVAL;
170 		}
171 
172 		if (buf->cur >= buf->end) {
173 			return -EAGAIN;
174 		}
175 
176 		*length += ((uint32_t)*(buf->cur) & MQTT_LENGTH_VALUE_MASK)
177 								<< shift;
178 		shift += MQTT_LENGTH_SHIFT;
179 		bytes++;
180 	} while ((*(buf->cur++) & MQTT_LENGTH_CONTINUATION_BIT) != 0U);
181 
182 	if (*length > MQTT_MAX_PAYLOAD_SIZE) {
183 		return -EINVAL;
184 	}
185 
186 	MQTT_TRC("length:0x%08x", *length);
187 
188 	return 0;
189 }
190 
fixed_header_decode(struct buf_ctx * buf,uint8_t * type_and_flags,uint32_t * length)191 int fixed_header_decode(struct buf_ctx *buf, uint8_t *type_and_flags,
192 			uint32_t *length)
193 {
194 	int err_code;
195 
196 	err_code = unpack_uint8(buf, type_and_flags);
197 	if (err_code != 0) {
198 		return err_code;
199 	}
200 
201 	return packet_length_decode(buf, length);
202 }
203 
connect_ack_decode(const struct mqtt_client * client,struct buf_ctx * buf,struct mqtt_connack_param * param)204 int connect_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
205 		       struct mqtt_connack_param *param)
206 {
207 	int err_code;
208 	uint8_t flags, ret_code;
209 
210 	err_code = unpack_uint8(buf, &flags);
211 	if (err_code != 0) {
212 		return err_code;
213 	}
214 
215 	err_code = unpack_uint8(buf, &ret_code);
216 	if (err_code != 0) {
217 		return err_code;
218 	}
219 
220 	if (client->protocol_version == MQTT_VERSION_3_1_1) {
221 		param->session_present_flag =
222 			flags & MQTT_CONNACK_FLAG_SESSION_PRESENT;
223 
224 		MQTT_TRC("[CID %p]: session_present_flag: %d", client,
225 			 param->session_present_flag);
226 	}
227 
228 	param->return_code = (enum mqtt_conn_return_code)ret_code;
229 
230 	return 0;
231 }
232 
publish_decode(uint8_t flags,uint32_t var_length,struct buf_ctx * buf,struct mqtt_publish_param * param)233 int publish_decode(uint8_t flags, uint32_t var_length, struct buf_ctx *buf,
234 		   struct mqtt_publish_param *param)
235 {
236 	int err_code;
237 	uint32_t var_header_length;
238 
239 	param->dup_flag = flags & MQTT_HEADER_DUP_MASK;
240 	param->retain_flag = flags & MQTT_HEADER_RETAIN_MASK;
241 	param->message.topic.qos = ((flags & MQTT_HEADER_QOS_MASK) >> 1);
242 
243 	err_code = unpack_utf8_str(buf, &param->message.topic.topic);
244 	if (err_code != 0) {
245 		return err_code;
246 	}
247 
248 	var_header_length = param->message.topic.topic.size + sizeof(uint16_t);
249 
250 	if (param->message.topic.qos > MQTT_QOS_0_AT_MOST_ONCE) {
251 		err_code = unpack_uint16(buf, &param->message_id);
252 		if (err_code != 0) {
253 			return err_code;
254 		}
255 
256 		var_header_length += sizeof(uint16_t);
257 	}
258 
259 	if (var_length < var_header_length) {
260 		MQTT_ERR("Corrupted PUBLISH message, header length (%u) larger "
261 			 "than total length (%u)", var_header_length,
262 			 var_length);
263 		return -EINVAL;
264 	}
265 
266 	param->message.payload.data = NULL;
267 	param->message.payload.len = var_length - var_header_length;
268 
269 	return 0;
270 }
271 
publish_ack_decode(struct buf_ctx * buf,struct mqtt_puback_param * param)272 int publish_ack_decode(struct buf_ctx *buf, struct mqtt_puback_param *param)
273 {
274 	return unpack_uint16(buf, &param->message_id);
275 }
276 
publish_receive_decode(struct buf_ctx * buf,struct mqtt_pubrec_param * param)277 int publish_receive_decode(struct buf_ctx *buf, struct mqtt_pubrec_param *param)
278 {
279 	return unpack_uint16(buf, &param->message_id);
280 }
281 
publish_release_decode(struct buf_ctx * buf,struct mqtt_pubrel_param * param)282 int publish_release_decode(struct buf_ctx *buf, struct mqtt_pubrel_param *param)
283 {
284 	return unpack_uint16(buf, &param->message_id);
285 }
286 
publish_complete_decode(struct buf_ctx * buf,struct mqtt_pubcomp_param * param)287 int publish_complete_decode(struct buf_ctx *buf,
288 			    struct mqtt_pubcomp_param *param)
289 {
290 	return unpack_uint16(buf, &param->message_id);
291 }
292 
subscribe_ack_decode(struct buf_ctx * buf,struct mqtt_suback_param * param)293 int subscribe_ack_decode(struct buf_ctx *buf, struct mqtt_suback_param *param)
294 {
295 	int err_code;
296 
297 	err_code = unpack_uint16(buf, &param->message_id);
298 	if (err_code != 0) {
299 		return err_code;
300 	}
301 
302 	return unpack_data(buf->end - buf->cur, buf, &param->return_codes);
303 }
304 
unsubscribe_ack_decode(struct buf_ctx * buf,struct mqtt_unsuback_param * param)305 int unsubscribe_ack_decode(struct buf_ctx *buf,
306 			   struct mqtt_unsuback_param *param)
307 {
308 	return unpack_uint16(buf, &param->message_id);
309 }
310