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