1 /*
2 * Copyright (c) 2018 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 /** @file mqtt_internal.h
8 *
9 * @brief Function and data structures internal to MQTT module.
10 */
11
12 #ifndef MQTT_INTERNAL_H_
13 #define MQTT_INTERNAL_H_
14
15 #include <stdint.h>
16 #include <string.h>
17
18 #include <zephyr/net/mqtt.h>
19
20 #ifdef __cplusplus
21 extern "C" {
22 #endif
23
24 /**@brief Keep alive time for MQTT (in seconds). Sending of Ping Requests to
25 * keep the connection alive are governed by this value.
26 */
27 #define MQTT_KEEPALIVE CONFIG_MQTT_KEEPALIVE
28
29 /**@brief Clean session on every connect (1) or keep subscriptions and messages
30 * between connects (0)
31 */
32 #define MQTT_CLEAN_SESSION (IS_ENABLED(CONFIG_MQTT_CLEAN_SESSION) ? 1U : 0U)
33
34 /**@brief Minimum mandatory size of fixed header. */
35 #define MQTT_FIXED_HEADER_MIN_SIZE 2
36
37 /**@brief Maximum size of the fixed header. Remaining length size is 4 in this
38 * case.
39 */
40 #define MQTT_FIXED_HEADER_MAX_SIZE 5
41
42 /**@brief MQTT Control Packet Types. */
43 #define MQTT_PKT_TYPE_CONNECT 0x10
44 #define MQTT_PKT_TYPE_CONNACK 0x20
45 #define MQTT_PKT_TYPE_PUBLISH 0x30
46 #define MQTT_PKT_TYPE_PUBACK 0x40
47 #define MQTT_PKT_TYPE_PUBREC 0x50
48 #define MQTT_PKT_TYPE_PUBREL 0x60
49 #define MQTT_PKT_TYPE_PUBCOMP 0x70
50 #define MQTT_PKT_TYPE_SUBSCRIBE 0x80
51 #define MQTT_PKT_TYPE_SUBACK 0x90
52 #define MQTT_PKT_TYPE_UNSUBSCRIBE 0xA0
53 #define MQTT_PKT_TYPE_UNSUBACK 0xB0
54 #define MQTT_PKT_TYPE_PINGREQ 0xC0
55 #define MQTT_PKT_TYPE_PINGRSP 0xD0
56 #define MQTT_PKT_TYPE_DISCONNECT 0xE0
57 #define MQTT_PKT_TYPE_AUTH 0xF0
58
59 /**@brief MQTT Property Types. */
60 #define MQTT_PROP_PAYLOAD_FORMAT_INDICATOR 0x01
61 #define MQTT_PROP_MESSAGE_EXPIRY_INTERVAL 0x02
62 #define MQTT_PROP_CONTENT_TYPE 0x03
63 #define MQTT_PROP_RESPONSE_TOPIC 0x08
64 #define MQTT_PROP_CORRELATION_DATA 0x09
65 #define MQTT_PROP_SUBSCRIPTION_IDENTIFIER 0x0B
66 #define MQTT_PROP_SESSION_EXPIRY_INTERVAL 0x11
67 #define MQTT_PROP_ASSIGNED_CLIENT_IDENTIFIER 0x12
68 #define MQTT_PROP_SERVER_KEEP_ALIVE 0x13
69 #define MQTT_PROP_AUTHENTICATION_METHOD 0x15
70 #define MQTT_PROP_AUTHENTICATION_DATA 0x16
71 #define MQTT_PROP_REQUEST_PROBLEM_INFORMATION 0x17
72 #define MQTT_PROP_WILL_DELAY_INTERVAL 0x18
73 #define MQTT_PROP_REQUEST_RESPONSE_INFORMATION 0x19
74 #define MQTT_PROP_RESPONSE_INFORMATION 0x1A
75 #define MQTT_PROP_SERVER_REFERENCE 0x1C
76 #define MQTT_PROP_REASON_STRING 0x1F
77 #define MQTT_PROP_RECEIVE_MAXIMUM 0x21
78 #define MQTT_PROP_TOPIC_ALIAS_MAXIMUM 0x22
79 #define MQTT_PROP_TOPIC_ALIAS 0x23
80 #define MQTT_PROP_MAXIMUM_QOS 0x24
81 #define MQTT_PROP_RETAIN_AVAILABLE 0x25
82 #define MQTT_PROP_USER_PROPERTY 0x26
83 #define MQTT_PROP_MAXIMUM_PACKET_SIZE 0x27
84 #define MQTT_PROP_WILDCARD_SUBSCRIPTION_AVAILABLE 0x28
85 #define MQTT_PROP_SUBSCRIPTION_IDENTIFIER_AVAILABLE 0x29
86 #define MQTT_PROP_SHARED_SUBSCRIPTION_AVAILABLE 0x2A
87
88 /**@brief Masks for MQTT header flags. */
89 #define MQTT_HEADER_DUP_MASK 0x08
90 #define MQTT_HEADER_QOS_MASK 0x06
91 #define MQTT_HEADER_RETAIN_MASK 0x01
92
93 /**@brief Masks for MQTT header flags. */
94 #define MQTT_CONNECT_FLAG_CLEAN_SESSION 0x02
95 #define MQTT_CONNECT_FLAG_WILL_TOPIC 0x04
96 #define MQTT_CONNECT_FLAG_WILL_RETAIN 0x20
97 #define MQTT_CONNECT_FLAG_PASSWORD 0x40
98 #define MQTT_CONNECT_FLAG_USERNAME 0x80
99
100 #define MQTT_CONNACK_FLAG_SESSION_PRESENT 0x01
101
102 /**@brief Maximum payload size of MQTT packet. */
103 #define MQTT_MAX_PAYLOAD_SIZE 0x0FFFFFFF
104
105 /**@brief Computes total size needed to pack a UTF8 string. */
106 #define GET_UT8STR_BUFFER_SIZE(STR) (sizeof(uint16_t) + (STR)->size)
107
108 /**@brief Computes total size needed to pack a binary stream. */
109 #define GET_BINSTR_BUFFER_SIZE(STR) (sizeof(uint16_t) + (STR)->len)
110
111 /**@brief Sets MQTT Client's state with one indicated in 'STATE'. */
112 #define MQTT_SET_STATE(CLIENT, STATE) ((CLIENT)->internal.state |= (STATE))
113
114 /**@brief Sets MQTT Client's state exclusive to 'STATE'. */
115 #define MQTT_SET_STATE_EXCLUSIVE(CLIENT, STATE) \
116 ((CLIENT)->internal.state = (STATE))
117
118 /**@brief Verifies if MQTT Client's state is set with one indicated in 'STATE'.
119 */
120 #define MQTT_HAS_STATE(CLIENT, STATE) ((CLIENT)->internal.state & (STATE))
121
122 /**@brief Reset 'STATE' in MQTT Client's state. */
123 #define MQTT_RESET_STATE(CLIENT, STATE) ((CLIENT)->internal.state &= ~(STATE))
124
125 /**@brief Initialize MQTT Client's state. */
126 #define MQTT_STATE_INIT(CLIENT) ((CLIENT)->internal.state = MQTT_STATE_IDLE)
127
128 /**@brief Computes the first byte of MQTT message header based on message type,
129 * duplication flag, QoS and the retain flag.
130 */
131 #define MQTT_MESSAGES_OPTIONS(TYPE, DUP, QOS, RETAIN) \
132 (((TYPE) & 0xF0) | \
133 (((DUP) << 3) & 0x08) | \
134 (((QOS) << 1) & 0x06) | \
135 ((RETAIN) & 0x01))
136
137 #define MQTT_MAX_LENGTH_BYTES 4
138 #define MQTT_LENGTH_VALUE_MASK 0x7F
139 #define MQTT_LENGTH_CONTINUATION_BIT 0x80
140 #define MQTT_LENGTH_SHIFT 7
141
142 /**@brief Check if the input pointer is NULL, if so it returns -EINVAL. */
143 #define NULL_PARAM_CHECK(param) \
144 do { \
145 if ((param) == NULL) { \
146 return -EINVAL; \
147 } \
148 } while (false)
149
150 #define NULL_PARAM_CHECK_VOID(param) \
151 do { \
152 if ((param) == NULL) { \
153 return; \
154 } \
155 } while (false)
156
157 /** Buffer context to iterate over buffer. */
158 struct buf_ctx {
159 uint8_t *cur;
160 uint8_t *end;
161 };
162
163 /**@brief MQTT States. */
164 enum mqtt_state {
165 /** Idle state, implying the client entry in the table is unused/free.
166 */
167 MQTT_STATE_IDLE = 0x00000000,
168
169 /** TCP Connection has been requested, awaiting result of the request.
170 */
171 MQTT_STATE_TCP_CONNECTING = 0x00000001,
172
173 /** TCP Connection successfully established. */
174 MQTT_STATE_TCP_CONNECTED = 0x00000002,
175
176 /** MQTT Connection successful. */
177 MQTT_STATE_CONNECTED = 0x00000004,
178 };
179
mqtt_is_version_5_0(const struct mqtt_client * client)180 static inline int mqtt_is_version_5_0(const struct mqtt_client *client)
181 {
182 return (IS_ENABLED(CONFIG_MQTT_VERSION_5_0) &&
183 client->protocol_version == MQTT_VERSION_5_0);
184 }
185
186 /**@brief Notify application about MQTT event.
187 *
188 * @param[in] client Identifies the client for which event occurred.
189 * @param[in] evt MQTT event.
190 */
191 void event_notify(struct mqtt_client *client, const struct mqtt_evt *evt);
192
193 /**@brief Handles MQTT messages received from the peer.
194 *
195 * @param[in] client Identifies the client for which the data was received.
196
197 * @return 0 if the procedure is successful, an error code otherwise.
198 */
199 int mqtt_handle_rx(struct mqtt_client *client);
200
201 /**@brief Disconnect MQTT client.
202 *
203 * @param[in] client Identifies the client which disconnects.
204 * @param[in] result Disconnect reason.
205 * @param[in] notify Whether to notify the app or not.
206
207 * @return 0 if the procedure is successful, an error code otherwise.
208 */
209 void mqtt_client_disconnect(struct mqtt_client *client, int result, bool notify);
210
211 /**@brief Constructs/encodes Connect packet.
212 *
213 * @param[in] client Identifies the client for which the procedure is requested.
214 * All information required for creating the packet like
215 * client id, clean session flag, retain session flag etc are
216 * assumed to be populated for the client instance when this
217 * procedure is requested.
218 * @param[inout] buf_ctx Pointer to the buffer context structure,
219 * containing buffer for the encoded message.
220 * As output points to the beginning and end of
221 * the frame.
222 *
223 * @return 0 if the procedure is successful, an error code otherwise.
224 */
225 int connect_request_encode(const struct mqtt_client *client,
226 struct buf_ctx *buf);
227
228 /**@brief Constructs/encodes Publish packet.
229 *
230 * @param[in] param Publish message parameters.
231 * @param[inout] buf_ctx Pointer to the buffer context structure,
232 * containing buffer for the encoded message.
233 * As output points to the beginning and end of
234 * the frame.
235 *
236 * @return 0 if the procedure is successful, an error code otherwise.
237 */
238 int publish_encode(const struct mqtt_client *client,
239 const struct mqtt_publish_param *param,
240 struct buf_ctx *buf);
241
242 /**@brief Constructs/encodes Publish Ack packet.
243 *
244 * @param[in] param Publish Ack message parameters.
245 * @param[inout] buf_ctx Pointer to the buffer context structure,
246 * containing buffer for the encoded message.
247 * As output points to the beginning and end of
248 * the frame.
249 *
250 * @return 0 if the procedure is successful, an error code otherwise.
251 */
252 int publish_ack_encode(const struct mqtt_client *client,
253 const struct mqtt_puback_param *param,
254 struct buf_ctx *buf);
255
256 /**@brief Constructs/encodes Publish Receive packet.
257 *
258 * @param[in] param Publish Receive message parameters.
259 * @param[inout] buf_ctx Pointer to the buffer context structure,
260 * containing buffer for the encoded message.
261 * As output points to the beginning and end of
262 * the frame.
263 *
264 * @return 0 if the procedure is successful, an error code otherwise.
265 */
266 int publish_receive_encode(const struct mqtt_client *client,
267 const struct mqtt_pubrec_param *param,
268 struct buf_ctx *buf);
269
270 /**@brief Constructs/encodes Publish Release packet.
271 *
272 * @param[in] param Publish Release message parameters.
273 * @param[inout] buf_ctx Pointer to the buffer context structure,
274 * containing buffer for the encoded message.
275 * As output points to the beginning and end of
276 * the frame.
277 *
278 * @return 0 if the procedure is successful, an error code otherwise.
279 */
280 int publish_release_encode(const struct mqtt_client *client,
281 const struct mqtt_pubrel_param *param,
282 struct buf_ctx *buf);
283
284 /**@brief Constructs/encodes Publish Complete packet.
285 *
286 * @param[in] param Publish Complete message parameters.
287 * @param[inout] buf_ctx Pointer to the buffer context structure,
288 * containing buffer for the encoded message.
289 * As output points to the beginning and end of
290 * the frame.
291 *
292 * @return 0 if the procedure is successful, an error code otherwise.
293 */
294 int publish_complete_encode(const struct mqtt_client *client,
295 const struct mqtt_pubcomp_param *param,
296 struct buf_ctx *buf);
297
298 /**@brief Constructs/encodes Disconnect packet.
299 *
300 * @param[inout] buf_ctx Pointer to the buffer context structure,
301 * containing buffer for the encoded message.
302 * As output points to the beginning and end of
303 * the frame.
304 *
305 * @return 0 if the procedure is successful, an error code otherwise.
306 */
307 int disconnect_encode(const struct mqtt_client *client,
308 const struct mqtt_disconnect_param *param,
309 struct buf_ctx *buf);
310
311 /**@brief Constructs/encodes Subscribe packet.
312 *
313 * @param[in] param Subscribe message parameters.
314 * @param[inout] buf_ctx Pointer to the buffer context structure,
315 * containing buffer for the encoded message.
316 * As output points to the beginning and end of
317 * the frame.
318 *
319 * @return 0 if the procedure is successful, an error code otherwise.
320 */
321 int subscribe_encode(const struct mqtt_client *client,
322 const struct mqtt_subscription_list *param,
323 struct buf_ctx *buf);
324
325 /**@brief Constructs/encodes Unsubscribe packet.
326 *
327 * @param[in] param Unsubscribe message parameters.
328 * @param[inout] buf_ctx Pointer to the buffer context structure,
329 * containing buffer for the encoded message.
330 * As output points to the beginning and end of
331 * the frame.
332 *
333 * @return 0 if the procedure is successful, an error code otherwise.
334 */
335 int unsubscribe_encode(const struct mqtt_client *client,
336 const struct mqtt_subscription_list *param,
337 struct buf_ctx *buf);
338
339 /**@brief Constructs/encodes Ping Request packet.
340 *
341 * @param[inout] buf_ctx Pointer to the buffer context structure,
342 * containing buffer for the encoded message.
343 * As output points to the beginning and end of
344 * the frame.
345 *
346 * @return 0 if the procedure is successful, an error code otherwise.
347 */
348 int ping_request_encode(struct buf_ctx *buf);
349
350 #if defined(CONFIG_MQTT_VERSION_5_0)
351 /**@brief Constructs/encodes Authenticate packet.
352 *
353 * @param[in] param Authenticate message parameters.
354 * @param[inout] buf_ctx Pointer to the buffer context structure,
355 * containing buffer for the encoded message.
356 * As output points to the beginning and end of
357 * the frame.
358 *
359 * @return 0 if the procedure is successful, an error code otherwise.
360 */
361 int auth_encode(const struct mqtt_auth_param *param, struct buf_ctx *buf);
362 #endif /* CONFIG_MQTT_VERSION_5_0 */
363
364 /**@brief Decode MQTT Packet Type and Length in the MQTT fixed header.
365 *
366 * @param[inout] buf A pointer to the buf_ctx structure containing current
367 * buffer position.
368 * @param[out] type_and_flags Message type and flags.
369 * @param[out] length Length of variable header and payload in the MQTT message.
370 *
371 * @return 0 if the procedure is successful, an error code otherwise.
372 */
373 int fixed_header_decode(struct buf_ctx *buf, uint8_t *type_and_flags,
374 uint32_t *length);
375
376 /**@brief Decode MQTT Connect Ack packet.
377 *
378 * @param[in] client MQTT client for which packet is decoded.
379 * @param[inout] buf A pointer to the buf_ctx structure containing current
380 * buffer position.
381 * @param[out] param Pointer to buffer for decoded Connect Ack parameters.
382 *
383 * @return 0 if the procedure is successful, an error code otherwise.
384 */
385 int connect_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
386 struct mqtt_connack_param *param);
387
388 /**@brief Decode MQTT Publish packet.
389 *
390 * @param[inout] MQTT client for which packet is decoded.
391 * @param[in] flags Byte containing message type and flags.
392 * @param[in] var_length Length of the variable part of the message.
393 * @param[inout] buf A pointer to the buf_ctx structure containing current
394 * buffer position.
395 * @param[out] param Pointer to buffer for decoded Publish parameters.
396 *
397 * @return 0 if the procedure is successful, an error code otherwise.
398 */
399 int publish_decode(struct mqtt_client *client, uint8_t flags,
400 uint32_t var_length, struct buf_ctx *buf,
401 struct mqtt_publish_param *param);
402
403 /**@brief Decode MQTT Publish Ack packet.
404 *
405 * @param[in] MQTT client for which packet is decoded.
406 * @param[inout] buf A pointer to the buf_ctx structure containing current
407 * buffer position.
408 * @param[out] param Pointer to buffer for decoded Publish Ack parameters.
409 *
410 * @return 0 if the procedure is successful, an error code otherwise.
411 */
412 int publish_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
413 struct mqtt_puback_param *param);
414
415 /**@brief Decode MQTT Publish Receive packet.
416 *
417 * @param[in] MQTT client for which packet is decoded.
418 * @param[inout] buf A pointer to the buf_ctx structure containing current
419 * buffer position.
420 * @param[out] param Pointer to buffer for decoded Publish Receive parameters.
421 *
422 * @return 0 if the procedure is successful, an error code otherwise.
423 */
424 int publish_receive_decode(const struct mqtt_client *client, struct buf_ctx *buf,
425 struct mqtt_pubrec_param *param);
426
427 /**@brief Decode MQTT Publish Release packet.
428 *
429 * @param[in] MQTT client for which packet is decoded.
430 * @param[inout] buf A pointer to the buf_ctx structure containing current
431 * buffer position.
432 * @param[out] param Pointer to buffer for decoded Publish Release parameters.
433 *
434 * @return 0 if the procedure is successful, an error code otherwise.
435 */
436 int publish_release_decode(const struct mqtt_client *client, struct buf_ctx *buf,
437 struct mqtt_pubrel_param *param);
438
439 /**@brief Decode MQTT Publish Complete packet.
440 *
441 * @param[in] MQTT client for which packet is decoded.
442 * @param[inout] buf A pointer to the buf_ctx structure containing current
443 * buffer position.
444 * @param[out] param Pointer to buffer for decoded Publish Complete parameters.
445 *
446 * @return 0 if the procedure is successful, an error code otherwise.
447 */
448 int publish_complete_decode(const struct mqtt_client *client, struct buf_ctx *buf,
449 struct mqtt_pubcomp_param *param);
450
451 /**@brief Decode MQTT Subscribe packet.
452 *
453 * @param[in] MQTT client for which packet is decoded.
454 * @param[inout] buf A pointer to the buf_ctx structure containing current
455 * buffer position.
456 * @param[out] param Pointer to buffer for decoded Subscribe parameters.
457 *
458 * @return 0 if the procedure is successful, an error code otherwise.
459 */
460 int subscribe_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
461 struct mqtt_suback_param *param);
462
463 /**@brief Decode MQTT Unsubscribe packet.
464 *
465 * @param[in] MQTT client for which packet is decoded.
466 * @param[inout] buf A pointer to the buf_ctx structure containing current
467 * buffer position.
468 * @param[out] param Pointer to buffer for decoded Unsubscribe parameters.
469 *
470 * @return 0 if the procedure is successful, an error code otherwise.
471 */
472 int unsubscribe_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
473 struct mqtt_unsuback_param *param);
474
475 #if defined(CONFIG_MQTT_VERSION_5_0)
476 /**@brief Decode MQTT Disconnect packet.
477 *
478 * @param[in] MQTT client for which packet is decoded.
479 * @param[inout] buf A pointer to the buf_ctx structure containing current
480 * buffer position.
481 * @param[out] param Pointer to buffer for decoded Disconnect parameters.
482 *
483 * @return 0 if the procedure is successful, an error code otherwise.
484 */
485 int disconnect_decode(const struct mqtt_client *client, struct buf_ctx *buf,
486 struct mqtt_disconnect_param *param);
487
488 /**@brief Decode MQTT Auth packet.
489 *
490 * @param[in] MQTT client for which packet is decoded.
491 * @param[inout] buf A pointer to the buf_ctx structure containing current
492 * buffer position.
493 * @param[out] param Pointer to buffer for decoded Auth parameters.
494 *
495 * @return 0 if the procedure is successful, an error code otherwise.
496 */
497 int auth_decode(const struct mqtt_client *client, struct buf_ctx *buf,
498 struct mqtt_auth_param *param);
499
500 /**@brief Set MQTT 5.0 disconnect reason.
501 *
502 * Packet parser can use this function to set a custom disconnect reason code,
503 * if not set, the client will use the default mapping between errno values and
504 * reason codes.
505 *
506 * @param[inout] MQTT client.
507 * @param[in] reason MQTT 5.0 disconnect reason code.
508 */
set_disconnect_reason(struct mqtt_client * client,enum mqtt_disconnect_reason_code reason)509 static inline void set_disconnect_reason(struct mqtt_client *client,
510 enum mqtt_disconnect_reason_code reason)
511 {
512 client->internal.disconnect_reason = reason;
513 }
514 #else
set_disconnect_reason(struct mqtt_client * client,enum mqtt_disconnect_reason_code reason)515 static inline void set_disconnect_reason(struct mqtt_client *client,
516 enum mqtt_disconnect_reason_code reason)
517 {
518 ARG_UNUSED(client);
519 ARG_UNUSED(reason);
520 }
521 #endif /* CONFIG_MQTT_VERSION_5_0 */
522
523 /**
524 * @brief Unpacks variable length integer from the buffer from the offset
525 * requested.
526 *
527 * @param[inout] buf A pointer to the buf_ctx structure containing current
528 * buffer position.
529 * @param[out] val Memory where the value is to be unpacked.
530 *
531 * @retval Number of bytes parsed if the procedure is successful.
532 * @retval -EINVAL if the length decoding would use more that 4 bytes.
533 * @retval -EAGAIN if the buffer would be exceeded during the read.
534 */
535 int unpack_variable_int(struct buf_ctx *buf, uint32_t *val);
536
537 #ifdef __cplusplus
538 }
539 #endif
540
541 #endif /* MQTT_INTERNAL_H_ */
542