Linux preempt-rt

Check our new training course

Real-Time Linux with PREEMPT_RT

Check our new training course
with Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2018 Nordic Semiconductor ASA
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/** @file mqtt_internal.h
 *
 * @brief Function and data structures internal to MQTT module.
 */

#ifndef MQTT_INTERNAL_H_
#define MQTT_INTERNAL_H_

#include <stdint.h>
#include <string.h>

#include <net/mqtt.h>

#ifdef __cplusplus
extern "C" {
#endif

/**@brief Keep alive time for MQTT (in seconds). Sending of Ping Requests to
 *        keep the connection alive are governed by this value.
 */
#define MQTT_KEEPALIVE CONFIG_MQTT_KEEPALIVE

/**@brief Clean session on every connect (1) or keep subscriptions and messages
 *        between connects (0)
 */
#define MQTT_CLEAN_SESSION (IS_ENABLED(CONFIG_MQTT_CLEAN_SESSION) ? 1U : 0U)

/**@brief Minimum mandatory size of fixed header. */
#define MQTT_FIXED_HEADER_MIN_SIZE 2

/**@brief Maximum size of the fixed header. Remaining length size is 4 in this
 *        case.
 */
#define MQTT_FIXED_HEADER_MAX_SIZE 5

/**@brief MQTT Control Packet Types. */
#define MQTT_PKT_TYPE_CONNECT     0x10
#define MQTT_PKT_TYPE_CONNACK     0x20
#define MQTT_PKT_TYPE_PUBLISH     0x30
#define MQTT_PKT_TYPE_PUBACK      0x40
#define MQTT_PKT_TYPE_PUBREC      0x50
#define MQTT_PKT_TYPE_PUBREL      0x60
#define MQTT_PKT_TYPE_PUBCOMP     0x70
#define MQTT_PKT_TYPE_SUBSCRIBE   0x80
#define MQTT_PKT_TYPE_SUBACK      0x90
#define MQTT_PKT_TYPE_UNSUBSCRIBE 0xA0
#define MQTT_PKT_TYPE_UNSUBACK    0xB0
#define MQTT_PKT_TYPE_PINGREQ     0xC0
#define MQTT_PKT_TYPE_PINGRSP     0xD0
#define MQTT_PKT_TYPE_DISCONNECT  0xE0

/**@brief Masks for MQTT header flags. */
#define MQTT_HEADER_DUP_MASK     0x08
#define MQTT_HEADER_QOS_MASK     0x06
#define MQTT_HEADER_RETAIN_MASK  0x01

/**@brief Masks for MQTT header flags. */
#define MQTT_CONNECT_FLAG_CLEAN_SESSION   0x02
#define MQTT_CONNECT_FLAG_WILL_TOPIC      0x04
#define MQTT_CONNECT_FLAG_WILL_RETAIN     0x20
#define MQTT_CONNECT_FLAG_PASSWORD        0x40
#define MQTT_CONNECT_FLAG_USERNAME        0x80

#define MQTT_CONNACK_FLAG_SESSION_PRESENT 0x01

/**@brief Maximum payload size of MQTT packet. */
#define MQTT_MAX_PAYLOAD_SIZE 0x0FFFFFFF

/**@brief Computes total size needed to pack a UTF8 string. */
#define GET_UT8STR_BUFFER_SIZE(STR) (sizeof(uint16_t) + (STR)->size)

/**@brief Computes total size needed to pack a binary stream. */
#define GET_BINSTR_BUFFER_SIZE(STR) ((STR)->len)

/**@brief Sets MQTT Client's state with one indicated in 'STATE'. */
#define MQTT_SET_STATE(CLIENT, STATE) ((CLIENT)->internal.state |= (STATE))

/**@brief Sets MQTT Client's state exclusive to 'STATE'. */
#define MQTT_SET_STATE_EXCLUSIVE(CLIENT, STATE) \
					((CLIENT)->internal.state = (STATE))

/**@brief Verifies if MQTT Client's state is set with one indicated in 'STATE'.
 */
#define MQTT_HAS_STATE(CLIENT, STATE) ((CLIENT)->internal.state & (STATE))

/**@brief Reset 'STATE' in MQTT Client's state. */
#define MQTT_RESET_STATE(CLIENT, STATE) ((CLIENT)->internal.state &= ~(STATE))

/**@brief Initialize MQTT Client's state. */
#define MQTT_STATE_INIT(CLIENT) ((CLIENT)->internal.state = MQTT_STATE_IDLE)

/**@brief Computes the first byte of MQTT message header based on message type,
 *        duplication flag, QoS and  the retain flag.
 */
#define MQTT_MESSAGES_OPTIONS(TYPE, DUP, QOS, RETAIN) \
	(((TYPE)      & 0xF0)  | \
	 (((DUP) << 3) & 0x08) | \
	 (((QOS) << 1) & 0x06) | \
	 ((RETAIN) & 0x01))

#define MQTT_MAX_LENGTH_BYTES 4
#define MQTT_LENGTH_VALUE_MASK 0x7F
#define MQTT_LENGTH_CONTINUATION_BIT 0x80
#define MQTT_LENGTH_SHIFT 7

/**@brief Check if the input pointer is NULL, if so it returns -EINVAL. */
#define NULL_PARAM_CHECK(param) \
	do { \
		if ((param) == NULL) { \
			return -EINVAL; \
		} \
	} while (0)

#define NULL_PARAM_CHECK_VOID(param) \
	do { \
		if ((param) == NULL) { \
			return; \
		} \
	} while (0)

/** Buffer context to iterate over buffer. */
struct buf_ctx {
	uint8_t *cur;
	uint8_t *end;
};

/**@brief MQTT States. */
enum mqtt_state {
	/** Idle state, implying the client entry in the table is unused/free.
	 */
	MQTT_STATE_IDLE                 = 0x00000000,

	/** TCP Connection has been requested, awaiting result of the request.
	 */
	MQTT_STATE_TCP_CONNECTING       = 0x00000001,

	/** TCP Connection successfully established. */
	MQTT_STATE_TCP_CONNECTED        = 0x00000002,

	/** MQTT Connection successful. */
	MQTT_STATE_CONNECTED            = 0x00000004,
};

/**@brief Notify application about MQTT event.
 *
 * @param[in] client Identifies the client for which event occurred.
 * @param[in] evt MQTT event.
 */
void event_notify(struct mqtt_client *client, const struct mqtt_evt *evt);

/**@brief Handles MQTT messages received from the peer.
 *
 * @param[in] client Identifies the client for which the data was received.

 * @return 0 if the procedure is successful, an error code otherwise.
 */
int mqtt_handle_rx(struct mqtt_client *client);

/**@brief Constructs/encodes Connect packet.
 *
 * @param[in] client Identifies the client for which the procedure is requested.
 *                   All information required for creating the packet like
 *                   client id, clean session flag, retain session flag etc are
 *                   assumed to be populated for the client instance when this
 *                   procedure is requested.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int connect_request_encode(const struct mqtt_client *client,
			   struct buf_ctx *buf);

/**@brief Constructs/encodes Publish packet.
 *
 * @param[in] param Publish message parameters.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_encode(const struct mqtt_publish_param *param, struct buf_ctx *buf);

/**@brief Constructs/encodes Publish Ack packet.
 *
 * @param[in] param Publish Ack message parameters.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_ack_encode(const struct mqtt_puback_param *param,
		       struct buf_ctx *buf);

/**@brief Constructs/encodes Publish Receive packet.
 *
 * @param[in] param Publish Receive message parameters.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_receive_encode(const struct mqtt_pubrec_param *param,
			   struct buf_ctx *buf);

/**@brief Constructs/encodes Publish Release packet.
 *
 * @param[in] param Publish Release message parameters.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_release_encode(const struct mqtt_pubrel_param *param,
			   struct buf_ctx *buf);

/**@brief Constructs/encodes Publish Complete packet.
 *
 * @param[in] param Publish Complete message parameters.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_complete_encode(const struct mqtt_pubcomp_param *param,
			    struct buf_ctx *buf);

/**@brief Constructs/encodes Disconnect packet.
 *
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int disconnect_encode(struct buf_ctx *buf);

/**@brief Constructs/encodes Subscribe packet.
 *
 * @param[in] param Subscribe message parameters.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int subscribe_encode(const struct mqtt_subscription_list *param,
		     struct buf_ctx *buf);

/**@brief Constructs/encodes Unsubscribe packet.
 *
 * @param[in] param Unsubscribe message parameters.
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int unsubscribe_encode(const struct mqtt_subscription_list *param,
		       struct buf_ctx *buf);

/**@brief Constructs/encodes Ping Request packet.
 *
 * @param[inout] buf_ctx Pointer to the buffer context structure,
 *                       containing buffer for the encoded message.
 *                       As output points to the beginning and end of
 *                       the frame.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int ping_request_encode(struct buf_ctx *buf);

/**@brief Decode MQTT Packet Type and Length in the MQTT fixed header.
 *
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] type_and_flags Message type and flags.
 * @param[out] length Length of variable header and payload in the MQTT message.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int fixed_header_decode(struct buf_ctx *buf, uint8_t *type_and_flags,
			uint32_t *length);

/**@brief Decode MQTT Connect Ack packet.
 *
 * @param[in] client MQTT client for which packet is decoded.
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Connect Ack parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int connect_ack_decode(const struct mqtt_client *client, struct buf_ctx *buf,
		       struct mqtt_connack_param *param);

/**@brief Decode MQTT Publish packet.
 *
 * @param[in] flags Byte containing message type and flags.
 * @param[in] var_length Length of the variable part of the message.
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Publish parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_decode(uint8_t flags, uint32_t var_length, struct buf_ctx *buf,
		   struct mqtt_publish_param *param);

/**@brief Decode MQTT Publish Ack packet.
 *
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Publish Ack parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_ack_decode(struct buf_ctx *buf, struct mqtt_puback_param *param);

/**@brief Decode MQTT Publish Receive packet.
 *
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Publish Receive parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_receive_decode(struct buf_ctx *buf,
			   struct mqtt_pubrec_param *param);

/**@brief Decode MQTT Publish Release packet.
 *
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Publish Release parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_release_decode(struct buf_ctx *buf,
			   struct mqtt_pubrel_param *param);

/**@brief Decode MQTT Publish Complete packet.
 *
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Publish Complete parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int publish_complete_decode(struct buf_ctx *buf,
			    struct mqtt_pubcomp_param *param);

/**@brief Decode MQTT Subscribe packet.
 *
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Subscribe parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int subscribe_ack_decode(struct buf_ctx *buf,
			 struct mqtt_suback_param *param);

/**@brief Decode MQTT Unsubscribe packet.
 *
 * @param[inout] buf A pointer to the buf_ctx structure containing current
 *                   buffer position.
 * @param[out] param Pointer to buffer for decoded Unsubscribe parameters.
 *
 * @return 0 if the procedure is successful, an error code otherwise.
 */
int unsubscribe_ack_decode(struct buf_ctx *buf,
			   struct mqtt_unsuback_param *param);

#ifdef __cplusplus
}
#endif

#endif /* MQTT_INTERNAL_H_ */