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, ¶m->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, ¶m->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, ¶m->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, ¶m->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, ¶m->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, ¶m->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, ¶m->message_id);
305 if (err_code != 0) {
306 return err_code;
307 }
308
309 return unpack_data(buf->end - buf->cur, buf, ¶m->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, ¶m->message_id);
316 }
317