RaspberrPi project source code
guowenxue
2024-04-11 69b42a43ca4b2d93be203c34f6b45f5de1e32a15
commit | author | age
d6b4a7 1 /*
G 2  * coreMQTT v2.1.1
3  * Copyright (C) 2022 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * SPDX-License-Identifier: MIT
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy of
8  * this software and associated documentation files (the "Software"), to deal in
9  * the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
11  * the Software, and to permit persons to whom the Software is furnished to do so,
12  * subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in all
15  * copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
19  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
20  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
21  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  */
24
25 /**
26  * @file core_mqtt_serializer.c
27  * @brief Implements the user-facing functions in core_mqtt_serializer.h.
28  */
29 #include <string.h>
30 #include <assert.h>
31
32 #include "core_mqtt_serializer.h"
33
34 /* Include config defaults header to get default values of configs. */
35 #include "core_mqtt_config_defaults.h"
36
37 #include "core_mqtt_default_logging.h"
38
39 /**
40  * @brief MQTT protocol version 3.1.1.
41  */
42 #define MQTT_VERSION_3_1_1                          ( ( uint8_t ) 4U )
43
44 /**
45  * @brief Size of the fixed and variable header of a CONNECT packet.
46  */
47 #define MQTT_PACKET_CONNECT_HEADER_SIZE             ( 10UL )
48
49 /* MQTT CONNECT flags. */
50 #define MQTT_CONNECT_FLAG_CLEAN                     ( 1 ) /**< @brief Clean session. */
51 #define MQTT_CONNECT_FLAG_WILL                      ( 2 ) /**< @brief Will present. */
52 #define MQTT_CONNECT_FLAG_WILL_QOS1                 ( 3 ) /**< @brief Will QoS 1. */
53 #define MQTT_CONNECT_FLAG_WILL_QOS2                 ( 4 ) /**< @brief Will QoS 2. */
54 #define MQTT_CONNECT_FLAG_WILL_RETAIN               ( 5 ) /**< @brief Will retain. */
55 #define MQTT_CONNECT_FLAG_PASSWORD                  ( 6 ) /**< @brief Password present. */
56 #define MQTT_CONNECT_FLAG_USERNAME                  ( 7 ) /**< @brief User name present. */
57
58 /*
59  * Positions of each flag in the first byte of an MQTT PUBLISH packet's
60  * fixed header.
61  */
62 #define MQTT_PUBLISH_FLAG_RETAIN                    ( 0 ) /**< @brief MQTT PUBLISH retain flag. */
63 #define MQTT_PUBLISH_FLAG_QOS1                      ( 1 ) /**< @brief MQTT PUBLISH QoS1 flag. */
64 #define MQTT_PUBLISH_FLAG_QOS2                      ( 2 ) /**< @brief MQTT PUBLISH QoS2 flag. */
65 #define MQTT_PUBLISH_FLAG_DUP                       ( 3 ) /**< @brief MQTT PUBLISH duplicate flag. */
66
67 /**
68  * @brief The size of MQTT DISCONNECT packets, per MQTT spec.
69  */
70 #define MQTT_DISCONNECT_PACKET_SIZE                 ( 2UL )
71
72 /**
73  * @brief A PINGREQ packet is always 2 bytes in size, defined by MQTT 3.1.1 spec.
74  */
75 #define MQTT_PACKET_PINGREQ_SIZE                    ( 2UL )
76
77 /**
78  * @brief The Remaining Length field of MQTT disconnect packets, per MQTT spec.
79  */
80 #define MQTT_DISCONNECT_REMAINING_LENGTH            ( ( uint8_t ) 0 )
81
82 /*
83  * Constants relating to CONNACK packets, defined by MQTT 3.1.1 spec.
84  */
85 #define MQTT_PACKET_CONNACK_REMAINING_LENGTH        ( ( uint8_t ) 2U )    /**< @brief A CONNACK packet always has a "Remaining length" of 2. */
86 #define MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK    ( ( uint8_t ) 0x01U ) /**< @brief The "Session Present" bit is always the lowest bit. */
87
88 /*
89  * UNSUBACK, PUBACK, PUBREC, PUBREL, and PUBCOMP always have a remaining length
90  * of 2.
91  */
92 #define MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH     ( ( uint8_t ) 2 ) /**< @brief PUBACK, PUBREC, PUBREl, PUBCOMP, UNSUBACK Remaining length. */
93 #define MQTT_PACKET_PINGRESP_REMAINING_LENGTH       ( 0U )            /**< @brief A PINGRESP packet always has a "Remaining length" of 0. */
94
95 /**
96  * @brief Per the MQTT 3.1.1 spec, the largest "Remaining Length" of an MQTT
97  * packet is this value, 256 MB.
98  */
99 #define MQTT_MAX_REMAINING_LENGTH                   ( 268435455UL )
100
101 /**
102  * @brief Set a bit in an 8-bit unsigned integer.
103  */
104 #define UINT8_SET_BIT( x, position )      ( ( x ) = ( uint8_t ) ( ( x ) | ( 0x01U << ( position ) ) ) )
105
106 /**
107  * @brief Macro for checking if a bit is set in a 1-byte unsigned int.
108  *
109  * @param[in] x The unsigned int to check.
110  * @param[in] position Which bit to check.
111  */
112 #define UINT8_CHECK_BIT( x, position )    ( ( ( x ) & ( 0x01U << ( position ) ) ) == ( 0x01U << ( position ) ) )
113
114 /**
115  * @brief Get the high byte of a 16-bit unsigned integer.
116  */
117 #define UINT16_HIGH_BYTE( x )             ( ( uint8_t ) ( ( x ) >> 8 ) )
118
119 /**
120  * @brief Get the low byte of a 16-bit unsigned integer.
121  */
122 #define UINT16_LOW_BYTE( x )              ( ( uint8_t ) ( ( x ) & 0x00ffU ) )
123
124 /**
125  * @brief Macro for decoding a 2-byte unsigned int from a sequence of bytes.
126  *
127  * @param[in] ptr A uint8_t* that points to the high byte.
128  */
129 #define UINT16_DECODE( ptr )                            \
130     ( uint16_t ) ( ( ( ( uint16_t ) ptr[ 0 ] ) << 8 ) | \
131                    ( ( uint16_t ) ptr[ 1 ] ) )
132
133 /**
134  * @brief A value that represents an invalid remaining length.
135  *
136  * This value is greater than what is allowed by the MQTT specification.
137  */
138 #define MQTT_REMAINING_LENGTH_INVALID             ( ( size_t ) 268435456 )
139
140 /**
141  * @brief The minimum remaining length for a QoS 0 PUBLISH.
142  *
143  * Includes two bytes for topic name length and one byte for topic name.
144  */
145 #define MQTT_MIN_PUBLISH_REMAINING_LENGTH_QOS0    ( 3U )
146
147 /*-----------------------------------------------------------*/
148
149
150 /**
151  * @brief MQTT Subscription packet types.
152  */
153 typedef enum MQTTSubscriptionType
154 {
155     MQTT_SUBSCRIBE,  /**< @brief The type is a SUBSCRIBE packet. */
156     MQTT_UNSUBSCRIBE /**< @brief The type is a UNSUBSCRIBE packet. */
157 } MQTTSubscriptionType_t;
158
159 /*-----------------------------------------------------------*/
160
161 /**
162  * @brief Serializes MQTT PUBLISH packet into the buffer provided.
163  *
164  * This function serializes MQTT PUBLISH packet into #MQTTFixedBuffer_t.pBuffer.
165  * Copy of the payload into the buffer is done as part of the serialization
166  * only if @p serializePayload is true.
167  *
168  * @brief param[in] pPublishInfo Publish information.
169  * @brief param[in] remainingLength Remaining length of the PUBLISH packet.
170  * @brief param[in] packetIdentifier Packet identifier of PUBLISH packet.
171  * @brief param[in, out] pFixedBuffer Buffer to which PUBLISH packet will be
172  * serialized.
173  * @brief param[in] serializePayload Copy payload to the serialized buffer
174  * only if true. Only PUBLISH header will be serialized if false.
175  *
176  * @return Total number of bytes sent; -1 if there is an error.
177  */
178 static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
179                                     size_t remainingLength,
180                                     uint16_t packetIdentifier,
181                                     const MQTTFixedBuffer_t * pFixedBuffer,
182                                     bool serializePayload );
183
184 /**
185  * @brief Calculates the packet size and remaining length of an MQTT
186  * PUBLISH packet.
187  *
188  * @param[in] pPublishInfo MQTT PUBLISH packet parameters.
189  * @param[out] pRemainingLength The Remaining Length of the MQTT PUBLISH packet.
190  * @param[out] pPacketSize The total size of the MQTT PUBLISH packet.
191  *
192  * @return false if the packet would exceed the size allowed by the
193  * MQTT spec; true otherwise.
194  */
195 static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
196                                         size_t * pRemainingLength,
197                                         size_t * pPacketSize );
198
199 /**
200  * @brief Calculates the packet size and remaining length of an MQTT
201  * SUBSCRIBE or UNSUBSCRIBE packet.
202  *
203  * @param[in] pSubscriptionList List of MQTT subscription info.
204  * @param[in] subscriptionCount The number of elements in pSubscriptionList.
205  * @param[out] pRemainingLength The Remaining Length of the MQTT SUBSCRIBE or
206  * UNSUBSCRIBE packet.
207  * @param[out] pPacketSize The total size of the MQTT MQTT SUBSCRIBE or
208  * UNSUBSCRIBE packet.
209  * @param[in] subscriptionType #MQTT_SUBSCRIBE or #MQTT_UNSUBSCRIBE.
210  *
211  * #MQTTBadParameter if the packet would exceed the size allowed by the
212  * MQTT spec or a subscription is empty; #MQTTSuccess otherwise.
213  */
214 static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
215                                                      size_t subscriptionCount,
216                                                      size_t * pRemainingLength,
217                                                      size_t * pPacketSize,
218                                                      MQTTSubscriptionType_t subscriptionType );
219
220 /**
221  * @brief Validates parameters of #MQTT_SerializeSubscribe or
222  * #MQTT_SerializeUnsubscribe.
223  *
224  * @param[in] pSubscriptionList List of MQTT subscription info.
225  * @param[in] subscriptionCount The number of elements in pSubscriptionList.
226  * @param[in] packetId Packet identifier.
227  * @param[in] remainingLength Remaining length of the packet.
228  * @param[in] pFixedBuffer Buffer for packet serialization.
229  *
230  * @return #MQTTNoMemory if pBuffer is too small to hold the MQTT packet;
231  * #MQTTBadParameter if invalid parameters are passed;
232  * #MQTTSuccess otherwise.
233  */
234 static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
235                                                          size_t subscriptionCount,
236                                                          uint16_t packetId,
237                                                          size_t remainingLength,
238                                                          const MQTTFixedBuffer_t * pFixedBuffer );
239
240 /**
241  * @brief Serialize an MQTT CONNECT packet in the given buffer.
242  *
243  * @param[in] pConnectInfo MQTT CONNECT packet parameters.
244  * @param[in] pWillInfo Last Will and Testament. Pass NULL if not used.
245  * @param[in] remainingLength Remaining Length of MQTT CONNECT packet.
246  * @param[out] pFixedBuffer Buffer for packet serialization.
247  */
248 static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
249                                     const MQTTPublishInfo_t * pWillInfo,
250                                     size_t remainingLength,
251                                     const MQTTFixedBuffer_t * pFixedBuffer );
252
253 /**
254  * @brief Prints the appropriate message for the CONNACK response code if logs
255  * are enabled.
256  *
257  * @param[in] responseCode MQTT standard CONNACK response code.
258  */
259 static void logConnackResponse( uint8_t responseCode );
260
261 /**
262  * @brief Encodes the remaining length of the packet using the variable length
263  * encoding scheme provided in the MQTT v3.1.1 specification.
264  *
265  * @param[out] pDestination The destination buffer to store the encoded remaining
266  * length.
267  * @param[in] length The remaining length to encode.
268  *
269  * @return The location of the byte following the encoded value.
270  */
271 static uint8_t * encodeRemainingLength( uint8_t * pDestination,
272                                         size_t length );
273
274 /**
275  * @brief Retrieve the size of the remaining length if it were to be encoded.
276  *
277  * @param[in] length The remaining length to be encoded.
278  *
279  * @return The size of the remaining length if it were to be encoded.
280  */
281 static size_t remainingLengthEncodedSize( size_t length );
282
283 /**
284  * @brief Encode a string whose size is at maximum 16 bits in length.
285  *
286  * @param[out] pDestination Destination buffer for the encoding.
287  * @param[in] pSource The source string to encode.
288  * @param[in] sourceLength The length of the source string to encode.
289  *
290  * @return A pointer to the end of the encoded string.
291  */
292 static uint8_t * encodeString( uint8_t * pDestination,
293                                const char * pSource,
294                                uint16_t sourceLength );
295
296 /**
297  * @brief Retrieves and decodes the Remaining Length from the network interface
298  * by reading a single byte at a time.
299  *
300  * @param[in] recvFunc Network interface receive function.
301  * @param[in] pNetworkContext Network interface context to the receive function.
302  *
303  * @return The Remaining Length of the incoming packet.
304  */
305 static size_t getRemainingLength( TransportRecv_t recvFunc,
306                                   NetworkContext_t * pNetworkContext );
307
308 /**
309  * @brief Retrieves, decodes and stores the Remaining Length from the network
310  * interface by reading a single byte at a time.
311  *
312  * @param[in] pBuffer The buffer holding the raw data to be processed
313  * @param[in] pIndex Pointer to the index within the buffer to marking the end of raw data
314  *            available.
315  * @param[in] pIncomingPacket Structure used to hold the fields of the
316  *            incoming packet.
317  *
318  * @return MQTTNeedMoreBytes is returned to show that the incoming
319  *         packet is not yet fully received and decoded. Otherwise, MQTTSuccess
320  *         shows that processing of the packet was successful.
321  */
322 static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
323                                             const size_t * pIndex,
324                                             MQTTPacketInfo_t * pIncomingPacket );
325
326 /**
327  * @brief Check if an incoming packet type is valid.
328  *
329  * @param[in] packetType The packet type to check.
330  *
331  * @return `true` if the packet type is valid; `false` otherwise.
332  */
333 static bool incomingPacketValid( uint8_t packetType );
334
335 /**
336  * @brief Check the remaining length of an incoming PUBLISH packet against some
337  * value for QoS 0, or for QoS 1 and 2.
338  *
339  * The remaining length for a QoS 1 and 2 packet will always be two greater than
340  * for a QoS 0.
341  *
342  * @param[in] remainingLength Remaining length of the PUBLISH packet.
343  * @param[in] qos The QoS of the PUBLISH.
344  * @param[in] qos0Minimum Minimum possible remaining length for a QoS 0 PUBLISH.
345  *
346  * @return #MQTTSuccess or #MQTTBadResponse.
347  */
348 static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
349                                                  MQTTQoS_t qos,
350                                                  size_t qos0Minimum );
351
352 /**
353  * @brief Process the flags of an incoming PUBLISH packet.
354  *
355  * @param[in] publishFlags Flags of an incoming PUBLISH.
356  * @param[in, out] pPublishInfo Pointer to #MQTTPublishInfo_t struct where
357  * output will be written.
358  *
359  * @return #MQTTSuccess or #MQTTBadResponse.
360  */
361 static MQTTStatus_t processPublishFlags( uint8_t publishFlags,
362                                          MQTTPublishInfo_t * pPublishInfo );
363
364 /**
365  * @brief Deserialize a CONNACK packet.
366  *
367  * Converts the packet from a stream of bytes to an #MQTTStatus_t.
368  *
369  * @param[in] pConnack Pointer to an MQTT packet struct representing a
370  * CONNACK.
371  * @param[out] pSessionPresent Whether a previous session was present.
372  *
373  * @return #MQTTSuccess if CONNACK specifies that CONNECT was accepted;
374  * #MQTTServerRefused if CONNACK specifies that CONNECT was rejected;
375  * #MQTTBadResponse if the CONNACK packet doesn't follow MQTT spec.
376  */
377 static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
378                                         bool * pSessionPresent );
379
380 /**
381  * @brief Decode the status bytes of a SUBACK packet to a #MQTTStatus_t.
382  *
383  * @param[in] statusCount Number of status bytes in the SUBACK.
384  * @param[in] pStatusStart The first status byte in the SUBACK.
385  *
386  * @return #MQTTSuccess, #MQTTServerRefused, or #MQTTBadResponse.
387  */
388 static MQTTStatus_t readSubackStatus( size_t statusCount,
389                                       const uint8_t * pStatusStart );
390
391 /**
392  * @brief Deserialize a SUBACK packet.
393  *
394  * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
395  * the packet identifier.
396  *
397  * @param[in] pSuback Pointer to an MQTT packet struct representing a SUBACK.
398  * @param[out] pPacketIdentifier Packet ID of the SUBACK.
399  *
400  * @return #MQTTSuccess if SUBACK is valid; #MQTTBadResponse if SUBACK packet
401  * doesn't follow the MQTT spec.
402  */
403 static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
404                                        uint16_t * pPacketIdentifier );
405
406 /**
407  * @brief Deserialize a PUBLISH packet received from the server.
408  *
409  * Converts the packet from a stream of bytes to an #MQTTPublishInfo_t and
410  * extracts the packet identifier. Also prints out debug log messages about the
411  * packet.
412  *
413  * @param[in] pIncomingPacket Pointer to an MQTT packet struct representing a
414  * PUBLISH.
415  * @param[out] pPacketId Packet identifier of the PUBLISH.
416  * @param[out] pPublishInfo Pointer to #MQTTPublishInfo_t where output is
417  * written.
418  *
419  * @return #MQTTSuccess if PUBLISH is valid; #MQTTBadResponse
420  * if the PUBLISH packet doesn't follow MQTT spec.
421  */
422 static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
423                                         uint16_t * pPacketId,
424                                         MQTTPublishInfo_t * pPublishInfo );
425
426 /**
427  * @brief Deserialize an UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP packet.
428  *
429  * Converts the packet from a stream of bytes to an #MQTTStatus_t and extracts
430  * the packet identifier.
431  *
432  * @param[in] pAck Pointer to the MQTT packet structure representing the packet.
433  * @param[out] pPacketIdentifier Packet ID of the ack type packet.
434  *
435  * @return #MQTTSuccess if UNSUBACK, PUBACK, PUBREC, PUBREL, or PUBCOMP is valid;
436  * #MQTTBadResponse if the packet doesn't follow the MQTT spec.
437  */
438 static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
439                                           uint16_t * pPacketIdentifier );
440
441 /**
442  * @brief Deserialize a PINGRESP packet.
443  *
444  * Converts the packet from a stream of bytes to an #MQTTStatus_t.
445  *
446  * @param[in] pPingresp Pointer to an MQTT packet struct representing a PINGRESP.
447  *
448  * @return #MQTTSuccess if PINGRESP is valid; #MQTTBadResponse if the PINGRESP
449  * packet doesn't follow MQTT spec.
450  */
451 static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp );
452
453 /*-----------------------------------------------------------*/
454
455 static size_t remainingLengthEncodedSize( size_t length )
456 {
457     size_t encodedSize;
458
459     /* Determine how many bytes are needed to encode length.
460      * The values below are taken from the MQTT 3.1.1 spec. */
461
462     /* 1 byte is needed to encode lengths between 0 and 127. */
463     if( length < 128U )
464     {
465         encodedSize = 1U;
466     }
467     /* 2 bytes are needed to encode lengths between 128 and 16,383. */
468     else if( length < 16384U )
469     {
470         encodedSize = 2U;
471     }
472     /* 3 bytes are needed to encode lengths between 16,384 and 2,097,151. */
473     else if( length < 2097152U )
474     {
475         encodedSize = 3U;
476     }
477     /* 4 bytes are needed to encode lengths between 2,097,152 and 268,435,455. */
478     else
479     {
480         encodedSize = 4U;
481     }
482
483     LogDebug( ( "Encoded size for length %lu is %lu bytes.",
484                 ( unsigned long ) length,
485                 ( unsigned long ) encodedSize ) );
486
487     return encodedSize;
488 }
489
490 /*-----------------------------------------------------------*/
491
492 static uint8_t * encodeRemainingLength( uint8_t * pDestination,
493                                         size_t length )
494 {
495     uint8_t lengthByte;
496     uint8_t * pLengthEnd = NULL;
497     size_t remainingLength = length;
498
499     assert( pDestination != NULL );
500
501     pLengthEnd = pDestination;
502
503     /* This algorithm is copied from the MQTT v3.1.1 spec. */
504     do
505     {
506         lengthByte = ( uint8_t ) ( remainingLength % 128U );
507         remainingLength = remainingLength / 128U;
508
509         /* Set the high bit of this byte, indicating that there's more data. */
510         if( remainingLength > 0U )
511         {
512             UINT8_SET_BIT( lengthByte, 7 );
513         }
514
515         /* Output a single encoded byte. */
516         *pLengthEnd = lengthByte;
517         pLengthEnd++;
518     } while( remainingLength > 0U );
519
520     return pLengthEnd;
521 }
522
523 /*-----------------------------------------------------------*/
524
525 static uint8_t * encodeString( uint8_t * pDestination,
526                                const char * pSource,
527                                uint16_t sourceLength )
528 {
529     uint8_t * pBuffer = NULL;
530
531     /* Typecast const char * typed source buffer to const uint8_t *.
532      * This is to use same type buffers in memcpy. */
533     const uint8_t * pSourceBuffer = ( const uint8_t * ) pSource;
534
535     assert( pDestination != NULL );
536
537     pBuffer = pDestination;
538
539     /* The first byte of a UTF-8 string is the high byte of the string length. */
540     *pBuffer = UINT16_HIGH_BYTE( sourceLength );
541     pBuffer++;
542
543     /* The second byte of a UTF-8 string is the low byte of the string length. */
544     *pBuffer = UINT16_LOW_BYTE( sourceLength );
545     pBuffer++;
546
547     /* Copy the string into pBuffer. */
548     if( pSourceBuffer != NULL )
549     {
550         ( void ) memcpy( pBuffer, pSourceBuffer, sourceLength );
551     }
552
553     /* Return the pointer to the end of the encoded string. */
554     pBuffer = &pBuffer[ sourceLength ];
555
556     return pBuffer;
557 }
558
559 /*-----------------------------------------------------------*/
560
561 static bool calculatePublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
562                                         size_t * pRemainingLength,
563                                         size_t * pPacketSize )
564 {
565     bool status = true;
566     size_t packetSize = 0, payloadLimit = 0;
567
568     assert( pPublishInfo != NULL );
569     assert( pRemainingLength != NULL );
570     assert( pPacketSize != NULL );
571
572     /* The variable header of a PUBLISH packet always contains the topic name.
573      * The first 2 bytes of UTF-8 string contains length of the string.
574      */
575     packetSize += pPublishInfo->topicNameLength + sizeof( uint16_t );
576
577     /* The variable header of a QoS 1 or 2 PUBLISH packet contains a 2-byte
578      * packet identifier. */
579     if( pPublishInfo->qos > MQTTQoS0 )
580     {
581         packetSize += sizeof( uint16_t );
582     }
583
584     /* Calculate the maximum allowed size of the payload for the given parameters.
585      * This calculation excludes the "Remaining length" encoding, whose size is not
586      * yet known. */
587     payloadLimit = MQTT_MAX_REMAINING_LENGTH - packetSize - 1U;
588
589     /* Ensure that the given payload fits within the calculated limit. */
590     if( pPublishInfo->payloadLength > payloadLimit )
591     {
592         LogError( ( "PUBLISH payload length of %lu cannot exceed "
593                     "%lu so as not to exceed the maximum "
594                     "remaining length of MQTT 3.1.1 packet( %lu ).",
595                     ( unsigned long ) pPublishInfo->payloadLength,
596                     ( unsigned long ) payloadLimit,
597                     MQTT_MAX_REMAINING_LENGTH ) );
598         status = false;
599     }
600     else
601     {
602         /* Add the length of the PUBLISH payload. At this point, the "Remaining length"
603          * has been calculated. */
604         packetSize += pPublishInfo->payloadLength;
605
606         /* Now that the "Remaining length" is known, recalculate the payload limit
607          * based on the size of its encoding. */
608         payloadLimit -= remainingLengthEncodedSize( packetSize );
609
610         /* Check that the given payload fits within the size allowed by MQTT spec. */
611         if( pPublishInfo->payloadLength > payloadLimit )
612         {
613             LogError( ( "PUBLISH payload length of %lu cannot exceed "
614                         "%lu so as not to exceed the maximum "
615                         "remaining length of MQTT 3.1.1 packet( %lu ).",
616                         ( unsigned long ) pPublishInfo->payloadLength,
617                         ( unsigned long ) payloadLimit,
618                         MQTT_MAX_REMAINING_LENGTH ) );
619             status = false;
620         }
621         else
622         {
623             /* Set the "Remaining length" output parameter and calculate the full
624              * size of the PUBLISH packet. */
625             *pRemainingLength = packetSize;
626
627             packetSize += 1U + remainingLengthEncodedSize( packetSize );
628             *pPacketSize = packetSize;
629         }
630     }
631
632     LogDebug( ( "PUBLISH packet remaining length=%lu and packet size=%lu.",
633                 ( unsigned long ) *pRemainingLength,
634                 ( unsigned long ) *pPacketSize ) );
635     return status;
636 }
637
638 /*-----------------------------------------------------------*/
639
640 MQTTStatus_t MQTT_SerializePublishHeaderWithoutTopic( const MQTTPublishInfo_t * pPublishInfo,
641                                                       size_t remainingLength,
642                                                       uint8_t * pBuffer,
643                                                       size_t * headerSize )
644 {
645     size_t headerLength;
646     uint8_t * pIndex;
647     MQTTStatus_t status = MQTTSuccess;
648
649     /* The first byte of a PUBLISH packet contains the packet type and flags. */
650     uint8_t publishFlags = MQTT_PACKET_TYPE_PUBLISH;
651
652     /* Get the start address of the buffer. */
653     pIndex = pBuffer;
654
655     /* Length of serialized packet = First byte
656      *                               + Length of encoded remaining length
657      *                               + Encoded topic length. */
658     headerLength = 1U + remainingLengthEncodedSize( remainingLength ) + 2U;
659
660     if( pPublishInfo->qos == MQTTQoS1 )
661     {
662         LogDebug( ( "Adding QoS as QoS1 in PUBLISH flags." ) );
663         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );
664     }
665     else if( pPublishInfo->qos == MQTTQoS2 )
666     {
667         LogDebug( ( "Adding QoS as QoS2 in PUBLISH flags." ) );
668         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );
669     }
670     else
671     {
672         /* Empty else MISRA 15.7 */
673     }
674
675     if( pPublishInfo->retain == true )
676     {
677         LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
678         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
679     }
680
681     if( pPublishInfo->dup == true )
682     {
683         LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
684         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
685     }
686
687     *pIndex = publishFlags;
688     pIndex++;
689
690     /* The "Remaining length" is encoded from the second byte. */
691     pIndex = encodeRemainingLength( pIndex, remainingLength );
692
693     /* The first byte of a UTF-8 string is the high byte of the string length. */
694     *pIndex = UINT16_HIGH_BYTE( pPublishInfo->topicNameLength );
695     pIndex++;
696
697     /* The second byte of a UTF-8 string is the low byte of the string length. */
698     *pIndex = UINT16_LOW_BYTE( pPublishInfo->topicNameLength );
699     pIndex++;
700
701     *headerSize = headerLength;
702
703     return status;
704 }
705
706 /*-----------------------------------------------------------*/
707
708 static void serializePublishCommon( const MQTTPublishInfo_t * pPublishInfo,
709                                     size_t remainingLength,
710                                     uint16_t packetIdentifier,
711                                     const MQTTFixedBuffer_t * pFixedBuffer,
712                                     bool serializePayload )
713 {
714     uint8_t * pIndex = NULL;
715     const uint8_t * pPayloadBuffer = NULL;
716
717     /* The first byte of a PUBLISH packet contains the packet type and flags. */
718     uint8_t publishFlags = MQTT_PACKET_TYPE_PUBLISH;
719
720     assert( pPublishInfo != NULL );
721     assert( pFixedBuffer != NULL );
722     assert( pFixedBuffer->pBuffer != NULL );
723     /* Packet Id should be non zero for Qos 1 and Qos 2. */
724     assert( ( pPublishInfo->qos == MQTTQoS0 ) || ( packetIdentifier != 0U ) );
725     /* Duplicate flag should be set only for Qos 1 or Qos 2. */
726     assert( ( pPublishInfo->dup != true ) || ( pPublishInfo->qos != MQTTQoS0 ) );
727
728     /* Get the start address of the buffer. */
729     pIndex = pFixedBuffer->pBuffer;
730
731     if( pPublishInfo->qos == MQTTQoS1 )
732     {
733         LogDebug( ( "Adding QoS as QoS1 in PUBLISH flags." ) );
734         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 );
735     }
736     else if( pPublishInfo->qos == MQTTQoS2 )
737     {
738         LogDebug( ( "Adding QoS as QoS2 in PUBLISH flags." ) );
739         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 );
740     }
741     else
742     {
743         /* Empty else MISRA 15.7 */
744     }
745
746     if( pPublishInfo->retain == true )
747     {
748         LogDebug( ( "Adding retain bit in PUBLISH flags." ) );
749         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
750     }
751
752     if( pPublishInfo->dup == true )
753     {
754         LogDebug( ( "Adding dup bit in PUBLISH flags." ) );
755         UINT8_SET_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
756     }
757
758     *pIndex = publishFlags;
759     pIndex++;
760
761     /* The "Remaining length" is encoded from the second byte. */
762     pIndex = encodeRemainingLength( pIndex, remainingLength );
763
764     /* The topic name is placed after the "Remaining length". */
765     pIndex = encodeString( pIndex,
766                            pPublishInfo->pTopicName,
767                            pPublishInfo->topicNameLength );
768
769     /* A packet identifier is required for QoS 1 and 2 messages. */
770     if( pPublishInfo->qos > MQTTQoS0 )
771     {
772         LogDebug( ( "Adding packet Id in PUBLISH packet." ) );
773         /* Place the packet identifier into the PUBLISH packet. */
774         *pIndex = UINT16_HIGH_BYTE( packetIdentifier );
775         pIndex[ 1U ] = UINT16_LOW_BYTE( packetIdentifier );
776         pIndex = &pIndex[ 2U ];
777     }
778
779     /* The payload is placed after the packet identifier.
780      * Payload is copied over only if required by the flag serializePayload.
781      * This will help reduce an unnecessary copy of the payload into the buffer.
782      */
783     if( ( pPublishInfo->payloadLength > 0U ) &&
784         ( serializePayload == true ) )
785     {
786         LogDebug( ( "Copying PUBLISH payload of length =%lu to buffer",
787                     ( unsigned long ) pPublishInfo->payloadLength ) );
788
789         /* Typecast const void * typed payload buffer to const uint8_t *.
790          * This is to use same type buffers in memcpy. */
791         pPayloadBuffer = ( const uint8_t * ) pPublishInfo->pPayload;
792
793         ( void ) memcpy( pIndex, pPayloadBuffer, pPublishInfo->payloadLength );
794         /* Move the index to after the payload. */
795         pIndex = &pIndex[ pPublishInfo->payloadLength ];
796     }
797
798     /* Ensure that the difference between the end and beginning of the buffer
799      * is less than the buffer size. */
800     assert( ( ( size_t ) ( pIndex - pFixedBuffer->pBuffer ) ) <= pFixedBuffer->size );
801 }
802
803 static size_t getRemainingLength( TransportRecv_t recvFunc,
804                                   NetworkContext_t * pNetworkContext )
805 {
806     size_t remainingLength = 0, multiplier = 1, bytesDecoded = 0, expectedSize = 0;
807     uint8_t encodedByte = 0;
808     int32_t bytesReceived = 0;
809
810     /* This algorithm is copied from the MQTT v3.1.1 spec. */
811     do
812     {
813         if( multiplier > 2097152U ) /* 128 ^ 3 */
814         {
815             remainingLength = MQTT_REMAINING_LENGTH_INVALID;
816         }
817         else
818         {
819             bytesReceived = recvFunc( pNetworkContext, &encodedByte, 1U );
820
821             if( bytesReceived == 1 )
822             {
823                 remainingLength += ( ( size_t ) encodedByte & 0x7FU ) * multiplier;
824                 multiplier *= 128U;
825                 bytesDecoded++;
826             }
827             else
828             {
829                 remainingLength = MQTT_REMAINING_LENGTH_INVALID;
830             }
831         }
832
833         if( remainingLength == MQTT_REMAINING_LENGTH_INVALID )
834         {
835             break;
836         }
837     } while( ( encodedByte & 0x80U ) != 0U );
838
839     /* Check that the decoded remaining length conforms to the MQTT specification. */
840     if( remainingLength != MQTT_REMAINING_LENGTH_INVALID )
841     {
842         expectedSize = remainingLengthEncodedSize( remainingLength );
843
844         if( bytesDecoded != expectedSize )
845         {
846             remainingLength = MQTT_REMAINING_LENGTH_INVALID;
847         }
848     }
849
850     return remainingLength;
851 }
852
853 /*-----------------------------------------------------------*/
854
855 static MQTTStatus_t processRemainingLength( const uint8_t * pBuffer,
856                                             const size_t * pIndex,
857                                             MQTTPacketInfo_t * pIncomingPacket )
858 {
859     size_t remainingLength = 0;
860     size_t multiplier = 1;
861     size_t bytesDecoded = 0;
862     size_t expectedSize = 0;
863     uint8_t encodedByte = 0;
864     MQTTStatus_t status = MQTTSuccess;
865
866     /* This algorithm is copied from the MQTT v3.1.1 spec. */
867     do
868     {
869         if( multiplier > 2097152U ) /* 128 ^ 3 */
870         {
871             remainingLength = MQTT_REMAINING_LENGTH_INVALID;
872
873             LogError( ( "Invalid remaining length in the packet.\n" ) );
874
875             status = MQTTBadResponse;
876         }
877         else
878         {
879             if( *pIndex > ( bytesDecoded + 1U ) )
880             {
881                 /* Get the next byte. It is at the next position after the bytes
882                  * decoded till now since the header of one byte was read before. */
883                 encodedByte = pBuffer[ bytesDecoded + 1U ];
884
885                 remainingLength += ( ( size_t ) encodedByte & 0x7FU ) * multiplier;
886                 multiplier *= 128U;
887                 bytesDecoded++;
888             }
889             else
890             {
891                 status = MQTTNeedMoreBytes;
892             }
893         }
894
895         /* If the response is incorrect, or no more data is available, then
896          * break out of the loop. */
897         if( ( remainingLength == MQTT_REMAINING_LENGTH_INVALID ) ||
898             ( status != MQTTSuccess ) )
899         {
900             break;
901         }
902     } while( ( encodedByte & 0x80U ) != 0U );
903
904     if( status == MQTTSuccess )
905     {
906         /* Check that the decoded remaining length conforms to the MQTT specification. */
907         expectedSize = remainingLengthEncodedSize( remainingLength );
908
909         if( bytesDecoded != expectedSize )
910         {
911             LogError( ( "Expected and actual length of decoded bytes do not match.\n" ) );
912             status = MQTTBadResponse;
913         }
914         else
915         {
916             pIncomingPacket->remainingLength = remainingLength;
917             pIncomingPacket->headerLength = bytesDecoded + 1U;
918         }
919     }
920
921     return status;
922 }
923
924 /*-----------------------------------------------------------*/
925
926 static bool incomingPacketValid( uint8_t packetType )
927 {
928     bool status = false;
929
930     /* Check packet type. Mask out lower bits to ignore flags. */
931     switch( packetType & 0xF0U )
932     {
933         /* Valid incoming packet types. */
934         case MQTT_PACKET_TYPE_CONNACK:
935         case MQTT_PACKET_TYPE_PUBLISH:
936         case MQTT_PACKET_TYPE_PUBACK:
937         case MQTT_PACKET_TYPE_PUBREC:
938         case MQTT_PACKET_TYPE_PUBCOMP:
939         case MQTT_PACKET_TYPE_SUBACK:
940         case MQTT_PACKET_TYPE_UNSUBACK:
941         case MQTT_PACKET_TYPE_PINGRESP:
942             status = true;
943             break;
944
945         case ( MQTT_PACKET_TYPE_PUBREL & 0xF0U ):
946
947             /* The second bit of a PUBREL must be set. */
948             if( ( packetType & 0x02U ) > 0U )
949             {
950                 status = true;
951             }
952
953             break;
954
955         /* Any other packet type is invalid. */
956         default:
957             LogWarn( ( "Incoming packet invalid: Packet type=%u.",
958                        ( unsigned int ) packetType ) );
959             break;
960     }
961
962     return status;
963 }
964
965 /*-----------------------------------------------------------*/
966
967 static MQTTStatus_t checkPublishRemainingLength( size_t remainingLength,
968                                                  MQTTQoS_t qos,
969                                                  size_t qos0Minimum )
970 {
971     MQTTStatus_t status = MQTTSuccess;
972
973     /* Sanity checks for "Remaining length". */
974     if( qos == MQTTQoS0 )
975     {
976         /* Check that the "Remaining length" is greater than the minimum. */
977         if( remainingLength < qos0Minimum )
978         {
979             LogError( ( "QoS 0 PUBLISH cannot have a remaining length less than %lu.",
980                         ( unsigned long ) qos0Minimum ) );
981
982             status = MQTTBadResponse;
983         }
984     }
985     else
986     {
987         /* Check that the "Remaining length" is greater than the minimum. For
988          * QoS 1 or 2, this will be two bytes greater than for QoS 0 due to the
989          * packet identifier. */
990         if( remainingLength < ( qos0Minimum + 2U ) )
991         {
992             LogError( ( "QoS 1 or 2 PUBLISH cannot have a remaining length less than %lu.",
993                         ( unsigned long ) ( qos0Minimum + 2U ) ) );
994
995             status = MQTTBadResponse;
996         }
997     }
998
999     return status;
1000 }
1001
1002 /*-----------------------------------------------------------*/
1003
1004 static MQTTStatus_t processPublishFlags( uint8_t publishFlags,
1005                                          MQTTPublishInfo_t * pPublishInfo )
1006 {
1007     MQTTStatus_t status = MQTTSuccess;
1008
1009     assert( pPublishInfo != NULL );
1010
1011     /* Check for QoS 2. */
1012     if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS2 ) )
1013     {
1014         /* PUBLISH packet is invalid if both QoS 1 and QoS 2 bits are set. */
1015         if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) )
1016         {
1017             LogError( ( "Bad QoS: 3." ) );
1018
1019             status = MQTTBadResponse;
1020         }
1021         else
1022         {
1023             pPublishInfo->qos = MQTTQoS2;
1024         }
1025     }
1026     /* Check for QoS 1. */
1027     else if( UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_QOS1 ) )
1028     {
1029         pPublishInfo->qos = MQTTQoS1;
1030     }
1031     /* If the PUBLISH isn't QoS 1 or 2, then it's QoS 0. */
1032     else
1033     {
1034         pPublishInfo->qos = MQTTQoS0;
1035     }
1036
1037     if( status == MQTTSuccess )
1038     {
1039         LogDebug( ( "QoS is %d.", ( int ) pPublishInfo->qos ) );
1040
1041         /* Parse the Retain bit. */
1042         pPublishInfo->retain = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_RETAIN );
1043
1044         LogDebug( ( "Retain bit is %d.", ( int ) pPublishInfo->retain ) );
1045
1046         /* Parse the DUP bit. */
1047         pPublishInfo->dup = UINT8_CHECK_BIT( publishFlags, MQTT_PUBLISH_FLAG_DUP );
1048
1049         LogDebug( ( "DUP bit is %d.", ( int ) pPublishInfo->dup ) );
1050     }
1051
1052     return status;
1053 }
1054
1055 /*-----------------------------------------------------------*/
1056
1057 static void logConnackResponse( uint8_t responseCode )
1058 {
1059     const char * const pConnackResponses[ 6 ] =
1060     {
1061         "Connection accepted.",                               /* 0 */
1062         "Connection refused: unacceptable protocol version.", /* 1 */
1063         "Connection refused: identifier rejected.",           /* 2 */
1064         "Connection refused: server unavailable",             /* 3 */
1065         "Connection refused: bad user name or password.",     /* 4 */
1066         "Connection refused: not authorized."                 /* 5 */
1067     };
1068
1069     /* Avoid unused parameter warning when assert and logs are disabled. */
1070     ( void ) responseCode;
1071     ( void ) pConnackResponses;
1072
1073     assert( responseCode <= 5U );
1074
1075     if( responseCode == 0u )
1076     {
1077         /* Log at Debug level for a success CONNACK response. */
1078         LogDebug( ( "%s", pConnackResponses[ 0 ] ) );
1079     }
1080     else
1081     {
1082         /* Log an error based on the CONNACK response code. */
1083         LogError( ( "%s", pConnackResponses[ responseCode ] ) );
1084     }
1085 }
1086
1087 /*-----------------------------------------------------------*/
1088
1089 static MQTTStatus_t deserializeConnack( const MQTTPacketInfo_t * pConnack,
1090                                         bool * pSessionPresent )
1091 {
1092     MQTTStatus_t status = MQTTSuccess;
1093     const uint8_t * pRemainingData = NULL;
1094
1095     assert( pConnack != NULL );
1096     assert( pSessionPresent != NULL );
1097     pRemainingData = pConnack->pRemainingData;
1098
1099     /* According to MQTT 3.1.1, the second byte of CONNACK must specify a
1100      * "Remaining length" of 2. */
1101     if( pConnack->remainingLength != MQTT_PACKET_CONNACK_REMAINING_LENGTH )
1102     {
1103         LogError( ( "CONNACK does not have remaining length of %u.",
1104                     ( unsigned int ) MQTT_PACKET_CONNACK_REMAINING_LENGTH ) );
1105
1106         status = MQTTBadResponse;
1107     }
1108
1109     /* Check the reserved bits in CONNACK. The high 7 bits of the third byte
1110      * in CONNACK must be 0. */
1111     else if( ( pRemainingData[ 0 ] | 0x01U ) != 0x01U )
1112     {
1113         LogError( ( "Reserved bits in CONNACK incorrect." ) );
1114
1115         status = MQTTBadResponse;
1116     }
1117     else
1118     {
1119         /* Determine if the "Session Present" bit is set. This is the lowest bit of
1120          * the third byte in CONNACK. */
1121         if( ( pRemainingData[ 0 ] & MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )
1122             == MQTT_PACKET_CONNACK_SESSION_PRESENT_MASK )
1123         {
1124             LogDebug( ( "CONNACK session present bit set." ) );
1125             *pSessionPresent = true;
1126
1127             /* MQTT 3.1.1 specifies that the fourth byte in CONNACK must be 0 if the
1128              * "Session Present" bit is set. */
1129             if( pRemainingData[ 1 ] != 0U )
1130             {
1131                 LogError( ( "Session Present bit is set, but connect return code in CONNACK is %u (nonzero).",
1132                             ( unsigned int ) pRemainingData[ 1 ] ) );
1133                 status = MQTTBadResponse;
1134             }
1135         }
1136         else
1137         {
1138             LogDebug( ( "CONNACK session present bit not set." ) );
1139             *pSessionPresent = false;
1140         }
1141     }
1142
1143     if( status == MQTTSuccess )
1144     {
1145         /* In MQTT 3.1.1, only values 0 through 5 are valid CONNACK response codes. */
1146         if( pRemainingData[ 1 ] > 5U )
1147         {
1148             LogError( ( "CONNACK response %u is invalid.",
1149                         ( unsigned int ) pRemainingData[ 1 ] ) );
1150
1151             status = MQTTBadResponse;
1152         }
1153         else
1154         {
1155             /* Print the appropriate message for the CONNACK response code if logs are
1156              * enabled. */
1157             logConnackResponse( pRemainingData[ 1 ] );
1158
1159             /* A nonzero CONNACK response code means the connection was refused. */
1160             if( pRemainingData[ 1 ] > 0U )
1161             {
1162                 status = MQTTServerRefused;
1163             }
1164         }
1165     }
1166
1167     return status;
1168 }
1169
1170 /*-----------------------------------------------------------*/
1171
1172 static MQTTStatus_t calculateSubscriptionPacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
1173                                                      size_t subscriptionCount,
1174                                                      size_t * pRemainingLength,
1175                                                      size_t * pPacketSize,
1176                                                      MQTTSubscriptionType_t subscriptionType )
1177 {
1178     MQTTStatus_t status = MQTTSuccess;
1179     size_t i = 0, packetSize = 0;
1180
1181     assert( pSubscriptionList != NULL );
1182     assert( subscriptionCount != 0U );
1183     assert( pRemainingLength != NULL );
1184     assert( pPacketSize != NULL );
1185
1186     /* The variable header of a subscription packet consists of a 2-byte packet
1187      * identifier. */
1188     packetSize += sizeof( uint16_t );
1189
1190     /* Sum the lengths of all subscription topic filters; add 1 byte for each
1191      * subscription's QoS if type is MQTT_SUBSCRIBE. */
1192     for( i = 0; i < subscriptionCount; i++ )
1193     {
1194         /* Add the length of the topic filter. MQTT strings are prepended
1195          * with 2 byte string length field. Hence 2 bytes are added to size. */
1196         packetSize += pSubscriptionList[ i ].topicFilterLength + sizeof( uint16_t );
1197
1198         /* Only SUBSCRIBE packets include the QoS. */
1199         if( subscriptionType == MQTT_SUBSCRIBE )
1200         {
1201             packetSize += 1U;
1202         }
1203
1204         /* Validate each topic filter. */
1205         if( ( pSubscriptionList[ i ].topicFilterLength == 0U ) ||
1206             ( pSubscriptionList[ i ].pTopicFilter == NULL ) )
1207         {
1208             status = MQTTBadParameter;
1209             LogError( ( "Subscription #%lu in %sSUBSCRIBE packet cannot be empty.",
1210                         ( unsigned long ) i,
1211                         ( subscriptionType == MQTT_SUBSCRIBE ) ? "" : "UN" ) );
1212             /* It is not necessary to break as an error status has already been set. */
1213         }
1214     }
1215
1216     /* At this point, the "Remaining length" has been calculated. Return error
1217      * if the "Remaining length" exceeds what is allowed by MQTT 3.1.1. Otherwise,
1218      * set the output parameter.*/
1219     if( packetSize > MQTT_MAX_REMAINING_LENGTH )
1220     {
1221         LogError( ( "Subscription packet length of %lu exceeds"
1222                     "the MQTT 3.1.1 maximum packet length of %lu.",
1223                     ( unsigned long ) packetSize,
1224                     MQTT_MAX_REMAINING_LENGTH ) );
1225         status = MQTTBadParameter;
1226     }
1227
1228     if( status == MQTTSuccess )
1229     {
1230         *pRemainingLength = packetSize;
1231
1232         /* Calculate the full size of the subscription packet by adding
1233          * number of bytes required to encode the "Remaining length" field
1234          * plus 1 byte for the "Packet type" field. */
1235         packetSize += 1U + remainingLengthEncodedSize( packetSize );
1236
1237         /*Set the pPacketSize output parameter. */
1238         *pPacketSize = packetSize;
1239     }
1240
1241     LogDebug( ( "Subscription packet remaining length=%lu and packet size=%lu.",
1242                 ( unsigned long ) *pRemainingLength,
1243                 ( unsigned long ) *pPacketSize ) );
1244
1245     return status;
1246 }
1247
1248 /*-----------------------------------------------------------*/
1249
1250 static MQTTStatus_t readSubackStatus( size_t statusCount,
1251                                       const uint8_t * pStatusStart )
1252 {
1253     MQTTStatus_t status = MQTTSuccess;
1254     uint8_t subscriptionStatus = 0;
1255     size_t i = 0;
1256
1257     assert( pStatusStart != NULL );
1258
1259     /* Iterate through each status byte in the SUBACK packet. */
1260     for( i = 0; i < statusCount; i++ )
1261     {
1262         /* Read a single status byte in SUBACK. */
1263         subscriptionStatus = pStatusStart[ i ];
1264
1265         /* MQTT 3.1.1 defines the following values as status codes. */
1266         switch( subscriptionStatus )
1267         {
1268             case 0x00:
1269             case 0x01:
1270             case 0x02:
1271
1272                 LogDebug( ( "Topic filter %lu accepted, max QoS %u.",
1273                             ( unsigned long ) i,
1274                             ( unsigned int ) subscriptionStatus ) );
1275                 break;
1276
1277             case 0x80:
1278
1279                 LogWarn( ( "Topic filter %lu refused.", ( unsigned long ) i ) );
1280
1281                 /* Application should remove subscription from the list */
1282                 status = MQTTServerRefused;
1283
1284                 break;
1285
1286             default:
1287                 LogError( ( "Bad SUBSCRIBE status %u.",
1288                             ( unsigned int ) subscriptionStatus ) );
1289
1290                 status = MQTTBadResponse;
1291
1292                 break;
1293         }
1294
1295         /* Stop parsing the subscription statuses if a bad response was received. */
1296         if( status == MQTTBadResponse )
1297         {
1298             break;
1299         }
1300     }
1301
1302     return status;
1303 }
1304
1305 /*-----------------------------------------------------------*/
1306
1307 static MQTTStatus_t deserializeSuback( const MQTTPacketInfo_t * pSuback,
1308                                        uint16_t * pPacketIdentifier )
1309 {
1310     MQTTStatus_t status = MQTTSuccess;
1311     size_t remainingLength;
1312     const uint8_t * pVariableHeader = NULL;
1313
1314     assert( pSuback != NULL );
1315     assert( pPacketIdentifier != NULL );
1316
1317     remainingLength = pSuback->remainingLength;
1318     pVariableHeader = pSuback->pRemainingData;
1319
1320     /* A SUBACK must have a remaining length of at least 3 to accommodate the
1321      * packet identifier and at least 1 return code. */
1322     if( remainingLength < 3U )
1323     {
1324         LogError( ( "SUBACK cannot have a remaining length less than 3." ) );
1325         status = MQTTBadResponse;
1326     }
1327     else
1328     {
1329         /* Extract the packet identifier (first 2 bytes of variable header) from SUBACK. */
1330         *pPacketIdentifier = UINT16_DECODE( pVariableHeader );
1331
1332         LogDebug( ( "Packet identifier %hu.",
1333                     ( unsigned short ) *pPacketIdentifier ) );
1334
1335         if( *pPacketIdentifier == 0U )
1336         {
1337             status = MQTTBadResponse;
1338         }
1339         else
1340         {
1341             status = readSubackStatus( remainingLength - sizeof( uint16_t ),
1342                                        &pVariableHeader[ sizeof( uint16_t ) ] );
1343         }
1344     }
1345
1346     return status;
1347 }
1348
1349 /*-----------------------------------------------------------*/
1350
1351 static MQTTStatus_t validateSubscriptionSerializeParams( const MQTTSubscribeInfo_t * pSubscriptionList,
1352                                                          size_t subscriptionCount,
1353                                                          uint16_t packetId,
1354                                                          size_t remainingLength,
1355                                                          const MQTTFixedBuffer_t * pFixedBuffer )
1356 {
1357     MQTTStatus_t status = MQTTSuccess;
1358     size_t packetSize = 0;
1359
1360     /* Validate all the parameters. */
1361     if( ( pFixedBuffer == NULL ) || ( pSubscriptionList == NULL ) )
1362     {
1363         LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
1364                     "pSubscriptionList=%p.",
1365                     ( void * ) pFixedBuffer,
1366                     ( void * ) pSubscriptionList ) );
1367         status = MQTTBadParameter;
1368     }
1369     /* A buffer must be configured for serialization. */
1370     else if( pFixedBuffer->pBuffer == NULL )
1371     {
1372         LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
1373         status = MQTTBadParameter;
1374     }
1375     else if( subscriptionCount == 0U )
1376     {
1377         LogError( ( "Subscription count is 0." ) );
1378         status = MQTTBadParameter;
1379     }
1380     else if( packetId == 0U )
1381     {
1382         LogError( ( "Packet Id for subscription packet is 0." ) );
1383         status = MQTTBadParameter;
1384     }
1385     else
1386     {
1387         /* The serialized packet size = First byte
1388          * + length of encoded size of remaining length
1389          * + remaining length. */
1390         packetSize = 1U + remainingLengthEncodedSize( remainingLength )
1391                      + remainingLength;
1392
1393         if( packetSize > pFixedBuffer->size )
1394         {
1395             LogError( ( "Buffer size of %lu is not sufficient to hold "
1396                         "serialized packet of size of %lu.",
1397                         ( unsigned long ) pFixedBuffer->size,
1398                         ( unsigned long ) packetSize ) );
1399             status = MQTTNoMemory;
1400         }
1401     }
1402
1403     return status;
1404 }
1405
1406 /*-----------------------------------------------------------*/
1407
1408 static MQTTStatus_t deserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
1409                                         uint16_t * pPacketId,
1410                                         MQTTPublishInfo_t * pPublishInfo )
1411 {
1412     MQTTStatus_t status = MQTTSuccess;
1413     const uint8_t * pVariableHeader, * pPacketIdentifierHigh = NULL;
1414
1415     assert( pIncomingPacket != NULL );
1416     assert( pPacketId != NULL );
1417     assert( pPublishInfo != NULL );
1418     assert( pIncomingPacket->pRemainingData != NULL );
1419
1420     pVariableHeader = pIncomingPacket->pRemainingData;
1421     /* The flags are the lower 4 bits of the first byte in PUBLISH. */
1422     status = processPublishFlags( ( pIncomingPacket->type & 0x0FU ), pPublishInfo );
1423
1424     if( status == MQTTSuccess )
1425     {
1426         /* Sanity checks for "Remaining length". A QoS 0 PUBLISH  must have a remaining
1427          * length of at least 3 to accommodate topic name length (2 bytes) and topic
1428          * name (at least 1 byte). A QoS 1 or 2 PUBLISH must have a remaining length of
1429          * at least 5 for the packet identifier in addition to the topic name length and
1430          * topic name. */
1431         status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
1432                                               pPublishInfo->qos,
1433                                               MQTT_MIN_PUBLISH_REMAINING_LENGTH_QOS0 );
1434     }
1435
1436     if( status == MQTTSuccess )
1437     {
1438         /* Extract the topic name starting from the first byte of the variable header.
1439          * The topic name string starts at byte 3 in the variable header. */
1440         pPublishInfo->topicNameLength = UINT16_DECODE( pVariableHeader );
1441
1442         /* Sanity checks for topic name length and "Remaining length". The remaining
1443          * length must be at least as large as the variable length header. */
1444         status = checkPublishRemainingLength( pIncomingPacket->remainingLength,
1445                                               pPublishInfo->qos,
1446                                               pPublishInfo->topicNameLength + sizeof( uint16_t ) );
1447     }
1448
1449     if( status == MQTTSuccess )
1450     {
1451         /* Parse the topic. */
1452         pPublishInfo->pTopicName = ( const char * ) ( &pVariableHeader[ sizeof( uint16_t ) ] );
1453         LogDebug( ( "Topic name length: %hu.", ( unsigned short ) pPublishInfo->topicNameLength ) );
1454
1455         /* Extract the packet identifier for QoS 1 or 2 PUBLISH packets. Packet
1456          * identifier starts immediately after the topic name. */
1457         pPacketIdentifierHigh = ( const uint8_t * ) ( &pPublishInfo->pTopicName[ pPublishInfo->topicNameLength ] );
1458
1459         if( pPublishInfo->qos > MQTTQoS0 )
1460         {
1461             *pPacketId = UINT16_DECODE( pPacketIdentifierHigh );
1462
1463             LogDebug( ( "Packet identifier %hu.",
1464                         ( unsigned short ) *pPacketId ) );
1465
1466             /* Advance pointer two bytes to start of payload as in the QoS 0 case. */
1467             pPacketIdentifierHigh = &pPacketIdentifierHigh[ sizeof( uint16_t ) ];
1468
1469             /* Packet identifier cannot be 0. */
1470             if( *pPacketId == 0U )
1471             {
1472                 LogError( ( "Packet identifier cannot be 0." ) );
1473                 status = MQTTBadResponse;
1474             }
1475         }
1476     }
1477
1478     if( status == MQTTSuccess )
1479     {
1480         /* Calculate the length of the payload. QoS 1 or 2 PUBLISH packets contain
1481          * a packet identifier, but QoS 0 PUBLISH packets do not. */
1482         pPublishInfo->payloadLength = pIncomingPacket->remainingLength - pPublishInfo->topicNameLength - sizeof( uint16_t );
1483
1484         if( pPublishInfo->qos != MQTTQoS0 )
1485         {
1486             /* Two more bytes for the packet identifier. */
1487             pPublishInfo->payloadLength -= sizeof( uint16_t );
1488         }
1489
1490         /* Set payload if it exists. */
1491         pPublishInfo->pPayload = ( pPublishInfo->payloadLength != 0U ) ? pPacketIdentifierHigh : NULL;
1492
1493         LogDebug( ( "Payload length %lu.",
1494                     ( unsigned long ) pPublishInfo->payloadLength ) );
1495     }
1496
1497     return status;
1498 }
1499
1500 /*-----------------------------------------------------------*/
1501
1502 static MQTTStatus_t deserializeSimpleAck( const MQTTPacketInfo_t * pAck,
1503                                           uint16_t * pPacketIdentifier )
1504 {
1505     MQTTStatus_t status = MQTTSuccess;
1506
1507     assert( pAck != NULL );
1508     assert( pPacketIdentifier != NULL );
1509
1510     /* Check that the "Remaining length" of the received ACK is 2. */
1511     if( pAck->remainingLength != MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH )
1512     {
1513         LogError( ( "ACK does not have remaining length of %u.",
1514                     ( unsigned int ) MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH ) );
1515
1516         status = MQTTBadResponse;
1517     }
1518     else
1519     {
1520         /* Extract the packet identifier (third and fourth bytes) from ACK. */
1521         *pPacketIdentifier = UINT16_DECODE( pAck->pRemainingData );
1522
1523         LogDebug( ( "Packet identifier %hu.",
1524                     ( unsigned short ) *pPacketIdentifier ) );
1525
1526         /* Packet identifier cannot be 0. */
1527         if( *pPacketIdentifier == 0U )
1528         {
1529             LogError( ( "Packet identifier cannot be 0." ) );
1530             status = MQTTBadResponse;
1531         }
1532     }
1533
1534     return status;
1535 }
1536
1537 /*-----------------------------------------------------------*/
1538
1539 static MQTTStatus_t deserializePingresp( const MQTTPacketInfo_t * pPingresp )
1540 {
1541     MQTTStatus_t status = MQTTSuccess;
1542
1543     assert( pPingresp != NULL );
1544
1545     /* Check the "Remaining length" (second byte) of the received PINGRESP is 0. */
1546     if( pPingresp->remainingLength != MQTT_PACKET_PINGRESP_REMAINING_LENGTH )
1547     {
1548         LogError( ( "PINGRESP does not have remaining length of %u.",
1549                     MQTT_PACKET_PINGRESP_REMAINING_LENGTH ) );
1550
1551         status = MQTTBadResponse;
1552     }
1553
1554     return status;
1555 }
1556
1557 uint8_t * MQTT_SerializeConnectFixedHeader( uint8_t * pIndex,
1558                                             const MQTTConnectInfo_t * pConnectInfo,
1559                                             const MQTTPublishInfo_t * pWillInfo,
1560                                             size_t remainingLength )
1561 {
1562     uint8_t * pIndexLocal = pIndex;
1563     uint8_t connectFlags = 0U;
1564
1565     /* The first byte in the CONNECT packet is the control packet type. */
1566     *pIndexLocal = MQTT_PACKET_TYPE_CONNECT;
1567     pIndexLocal++;
1568
1569     /* The remaining length of the CONNECT packet is encoded starting from the
1570      * second byte. The remaining length does not include the length of the fixed
1571      * header or the encoding of the remaining length. */
1572     pIndexLocal = encodeRemainingLength( pIndexLocal, remainingLength );
1573
1574     /* The string "MQTT" is placed at the beginning of the CONNECT packet's variable
1575      * header. This string is 4 bytes long. */
1576     pIndexLocal = encodeString( pIndexLocal, "MQTT", 4 );
1577
1578     /* The MQTT protocol version is the second field of the variable header. */
1579     *pIndexLocal = MQTT_VERSION_3_1_1;
1580     pIndexLocal++;
1581
1582     /* Set the clean session flag if needed. */
1583     if( pConnectInfo->cleanSession == true )
1584     {
1585         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_CLEAN );
1586     }
1587
1588     /* Set the flags for username and password if provided. */
1589     if( pConnectInfo->pUserName != NULL )
1590     {
1591         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_USERNAME );
1592     }
1593
1594     if( pConnectInfo->pPassword != NULL )
1595     {
1596         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_PASSWORD );
1597     }
1598
1599     /* Set will flag if a Last Will and Testament is provided. */
1600     if( pWillInfo != NULL )
1601     {
1602         UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL );
1603
1604         /* Flags only need to be changed for Will QoS 1 or 2. */
1605         if( pWillInfo->qos == MQTTQoS1 )
1606         {
1607             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS1 );
1608         }
1609         else if( pWillInfo->qos == MQTTQoS2 )
1610         {
1611             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_QOS2 );
1612         }
1613         else
1614         {
1615             /* Empty else MISRA 15.7 */
1616         }
1617
1618         if( pWillInfo->retain == true )
1619         {
1620             UINT8_SET_BIT( connectFlags, MQTT_CONNECT_FLAG_WILL_RETAIN );
1621         }
1622     }
1623
1624     *pIndexLocal = connectFlags;
1625     pIndexLocal++;
1626
1627     /* Write the 2 bytes of the keep alive interval into the CONNECT packet. */
1628     pIndexLocal[ 0 ] = UINT16_HIGH_BYTE( pConnectInfo->keepAliveSeconds );
1629     pIndexLocal[ 1 ] = UINT16_LOW_BYTE( pConnectInfo->keepAliveSeconds );
1630     pIndexLocal = &pIndexLocal[ 2 ];
1631
1632     return pIndexLocal;
1633 }
1634 /*-----------------------------------------------------------*/
1635
1636 static void serializeConnectPacket( const MQTTConnectInfo_t * pConnectInfo,
1637                                     const MQTTPublishInfo_t * pWillInfo,
1638                                     size_t remainingLength,
1639                                     const MQTTFixedBuffer_t * pFixedBuffer )
1640 {
1641     uint8_t * pIndex = NULL;
1642
1643     assert( pConnectInfo != NULL );
1644     assert( pFixedBuffer != NULL );
1645     assert( pFixedBuffer->pBuffer != NULL );
1646
1647     pIndex = pFixedBuffer->pBuffer;
1648
1649     /* Serialize the header. */
1650     pIndex = MQTT_SerializeConnectFixedHeader( pIndex,
1651                                                pConnectInfo,
1652                                                pWillInfo,
1653                                                remainingLength );
1654
1655     /* Write the client identifier into the CONNECT packet. */
1656     pIndex = encodeString( pIndex,
1657                            pConnectInfo->pClientIdentifier,
1658                            pConnectInfo->clientIdentifierLength );
1659
1660     /* Write the will topic name and message into the CONNECT packet if provided. */
1661     if( pWillInfo != NULL )
1662     {
1663         pIndex = encodeString( pIndex,
1664                                pWillInfo->pTopicName,
1665                                pWillInfo->topicNameLength );
1666
1667         pIndex = encodeString( pIndex,
1668                                pWillInfo->pPayload,
1669                                ( uint16_t ) pWillInfo->payloadLength );
1670     }
1671
1672     /* Encode the user name if provided. */
1673     if( pConnectInfo->pUserName != NULL )
1674     {
1675         pIndex = encodeString( pIndex, pConnectInfo->pUserName, pConnectInfo->userNameLength );
1676     }
1677
1678     /* Encode the password if provided. */
1679     if( pConnectInfo->pPassword != NULL )
1680     {
1681         pIndex = encodeString( pIndex, pConnectInfo->pPassword, pConnectInfo->passwordLength );
1682     }
1683
1684     LogDebug( ( "Length of serialized CONNECT packet is %lu.",
1685                 ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
1686
1687     /* Ensure that the difference between the end and beginning of the buffer
1688      * is less than the buffer size. */
1689     assert( ( ( size_t ) ( pIndex - pFixedBuffer->pBuffer ) ) <= pFixedBuffer->size );
1690 }
1691
1692 /*-----------------------------------------------------------*/
1693
1694 MQTTStatus_t MQTT_GetConnectPacketSize( const MQTTConnectInfo_t * pConnectInfo,
1695                                         const MQTTPublishInfo_t * pWillInfo,
1696                                         size_t * pRemainingLength,
1697                                         size_t * pPacketSize )
1698 {
1699     MQTTStatus_t status = MQTTSuccess;
1700     size_t remainingLength;
1701
1702     /* The CONNECT packet will always include a 10-byte variable header. */
1703     size_t connectPacketSize = MQTT_PACKET_CONNECT_HEADER_SIZE;
1704
1705     /* Validate arguments. */
1706     if( ( pConnectInfo == NULL ) || ( pRemainingLength == NULL ) ||
1707         ( pPacketSize == NULL ) )
1708     {
1709         LogError( ( "Argument cannot be NULL: pConnectInfo=%p, "
1710                     "pRemainingLength=%p, pPacketSize=%p.",
1711                     ( void * ) pConnectInfo,
1712                     ( void * ) pRemainingLength,
1713                     ( void * ) pPacketSize ) );
1714         status = MQTTBadParameter;
1715     }
1716     else if( ( pConnectInfo->clientIdentifierLength == 0U ) || ( pConnectInfo->pClientIdentifier == NULL ) )
1717     {
1718         LogError( ( "Mqtt_GetConnectPacketSize() client identifier must be set." ) );
1719         status = MQTTBadParameter;
1720     }
1721     else if( ( pWillInfo != NULL ) && ( pWillInfo->payloadLength > ( size_t ) UINT16_MAX ) )
1722     {
1723         /* The MQTTPublishInfo_t is reused for the will message. The payload
1724          * length for any other message could be larger than 65,535, but
1725          * the will message length is required to be represented in 2 bytes.
1726          * By bounding the payloadLength of the will message, the CONNECT
1727          * packet will never be larger than 327699 bytes. */
1728         LogError( ( "The Will Message length must not exceed %d. "
1729                     "pWillInfo->payloadLength=%lu.",
1730                     UINT16_MAX,
1731                     ( unsigned long ) pWillInfo->payloadLength ) );
1732         status = MQTTBadParameter;
1733     }
1734     else
1735     {
1736         /* Add the length of the client identifier. */
1737         connectPacketSize += pConnectInfo->clientIdentifierLength + sizeof( uint16_t );
1738
1739         /* Add the lengths of the will message and topic name if provided. */
1740         if( pWillInfo != NULL )
1741         {
1742             connectPacketSize += pWillInfo->topicNameLength + sizeof( uint16_t ) +
1743                                  pWillInfo->payloadLength + sizeof( uint16_t );
1744         }
1745
1746         /* Add the lengths of the user name and password if provided. */
1747         if( pConnectInfo->pUserName != NULL )
1748         {
1749             connectPacketSize += pConnectInfo->userNameLength + sizeof( uint16_t );
1750         }
1751
1752         if( pConnectInfo->pPassword != NULL )
1753         {
1754             connectPacketSize += pConnectInfo->passwordLength + sizeof( uint16_t );
1755         }
1756
1757         /* At this point, the "Remaining Length" field of the MQTT CONNECT packet has
1758          * been calculated. */
1759         remainingLength = connectPacketSize;
1760
1761         /* Calculate the full size of the MQTT CONNECT packet by adding the size of
1762          * the "Remaining Length" field plus 1 byte for the "Packet Type" field. */
1763         connectPacketSize += 1U + remainingLengthEncodedSize( connectPacketSize );
1764
1765         /* The connectPacketSize calculated from this function's parameters is
1766          * guaranteed to be less than the maximum MQTT CONNECT packet size, which
1767          * is 327700. If the maximum client identifier length, the maximum will
1768          * message topic length, the maximum will topic payload length, the
1769          * maximum username length, and the maximum password length are all present
1770          * in the MQTT CONNECT packet, the total size will be calculated to be
1771          * 327699:
1772          * (variable length header)10 +
1773          * (maximum client identifier length) 65535 + (encoded length) 2 +
1774          * (maximum will message topic name length) 65535 + (encoded length)2 +
1775          * (maximum will message payload length) 65535 + 2 +
1776          * (maximum username length) 65535 + (encoded length) 2 +
1777          * (maximum password length) 65535 + (encoded length) 2 +
1778          * (packet type field length) 1 +
1779          * (CONNECT packet encoded length) 3 = 327699 */
1780
1781         *pRemainingLength = remainingLength;
1782         *pPacketSize = connectPacketSize;
1783
1784         LogDebug( ( "CONNECT packet remaining length=%lu and packet size=%lu.",
1785                     ( unsigned long ) *pRemainingLength,
1786                     ( unsigned long ) *pPacketSize ) );
1787     }
1788
1789     return status;
1790 }
1791
1792 /*-----------------------------------------------------------*/
1793
1794 MQTTStatus_t MQTT_SerializeConnect( const MQTTConnectInfo_t * pConnectInfo,
1795                                     const MQTTPublishInfo_t * pWillInfo,
1796                                     size_t remainingLength,
1797                                     const MQTTFixedBuffer_t * pFixedBuffer )
1798 {
1799     MQTTStatus_t status = MQTTSuccess;
1800     size_t connectPacketSize = 0;
1801
1802     /* Validate arguments. */
1803     if( ( pConnectInfo == NULL ) || ( pFixedBuffer == NULL ) )
1804     {
1805         LogError( ( "Argument cannot be NULL: pConnectInfo=%p, "
1806                     "pFixedBuffer=%p.",
1807                     ( void * ) pConnectInfo,
1808                     ( void * ) pFixedBuffer ) );
1809         status = MQTTBadParameter;
1810     }
1811     /* A buffer must be configured for serialization. */
1812     else if( pFixedBuffer->pBuffer == NULL )
1813     {
1814         LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
1815         status = MQTTBadParameter;
1816     }
1817     else if( ( pWillInfo != NULL ) && ( pWillInfo->pTopicName == NULL ) )
1818     {
1819         LogError( ( "pWillInfo->pTopicName cannot be NULL if Will is present." ) );
1820         status = MQTTBadParameter;
1821     }
1822     else
1823     {
1824         /* Calculate CONNECT packet size. Overflow in in this addition is not checked
1825          * because it is part of the API contract to call Mqtt_GetConnectPacketSize()
1826          * before this function. */
1827         connectPacketSize = remainingLength + remainingLengthEncodedSize( remainingLength ) + 1U;
1828
1829         /* Check that the full packet size fits within the given buffer. */
1830         if( connectPacketSize > pFixedBuffer->size )
1831         {
1832             LogError( ( "Buffer size of %lu is not sufficient to hold "
1833                         "serialized CONNECT packet of size of %lu.",
1834                         ( unsigned long ) pFixedBuffer->size,
1835                         ( unsigned long ) connectPacketSize ) );
1836             status = MQTTNoMemory;
1837         }
1838         else
1839         {
1840             serializeConnectPacket( pConnectInfo,
1841                                     pWillInfo,
1842                                     remainingLength,
1843                                     pFixedBuffer );
1844         }
1845     }
1846
1847     return status;
1848 }
1849
1850 /*-----------------------------------------------------------*/
1851
1852 MQTTStatus_t MQTT_GetSubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
1853                                           size_t subscriptionCount,
1854                                           size_t * pRemainingLength,
1855                                           size_t * pPacketSize )
1856 {
1857     MQTTStatus_t status = MQTTSuccess;
1858
1859     /* Validate parameters. */
1860     if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
1861         ( pPacketSize == NULL ) )
1862     {
1863         LogError( ( "Argument cannot be NULL: pSubscriptionList=%p, "
1864                     "pRemainingLength=%p, pPacketSize=%p.",
1865                     ( void * ) pSubscriptionList,
1866                     ( void * ) pRemainingLength,
1867                     ( void * ) pPacketSize ) );
1868         status = MQTTBadParameter;
1869     }
1870     else if( subscriptionCount == 0U )
1871     {
1872         LogError( ( "subscriptionCount is 0." ) );
1873         status = MQTTBadParameter;
1874     }
1875     else
1876     {
1877         /* Calculate the MQTT SUBSCRIBE packet size. */
1878         status = calculateSubscriptionPacketSize( pSubscriptionList,
1879                                                   subscriptionCount,
1880                                                   pRemainingLength,
1881                                                   pPacketSize,
1882                                                   MQTT_SUBSCRIBE );
1883     }
1884
1885     return status;
1886 }
1887
1888 /*-----------------------------------------------------------*/
1889
1890 uint8_t * MQTT_SerializeSubscribeHeader( size_t remainingLength,
1891                                          uint8_t * pIndex,
1892                                          uint16_t packetId )
1893 {
1894     uint8_t * pIterator = pIndex;
1895
1896     /* The first byte in SUBSCRIBE is the packet type. */
1897     *pIterator = MQTT_PACKET_TYPE_SUBSCRIBE;
1898     pIterator++;
1899
1900     /* Encode the "Remaining length" starting from the second byte. */
1901     pIterator = encodeRemainingLength( pIterator, remainingLength );
1902
1903     /* Place the packet identifier into the SUBSCRIBE packet. */
1904     pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
1905     pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
1906     /* Advance the pointer. */
1907     pIterator = &pIterator[ 2 ];
1908
1909     return pIterator;
1910 }
1911
1912 /*-----------------------------------------------------------*/
1913
1914 uint8_t * MQTT_SerializeUnsubscribeHeader( size_t remainingLength,
1915                                            uint8_t * pIndex,
1916                                            uint16_t packetId )
1917 {
1918     uint8_t * pIterator = pIndex;
1919
1920     /* The first byte in UNSUBSCRIBE is the packet type. */
1921     *pIterator = MQTT_PACKET_TYPE_UNSUBSCRIBE;
1922     pIterator++;
1923
1924     /* Encode the "Remaining length" starting from the second byte. */
1925     pIterator = encodeRemainingLength( pIterator, remainingLength );
1926
1927     /* Place the packet identifier into the SUBSCRIBE packet. */
1928     pIterator[ 0 ] = UINT16_HIGH_BYTE( packetId );
1929     pIterator[ 1 ] = UINT16_LOW_BYTE( packetId );
1930     /* Increment the pointer. */
1931     pIterator = &pIterator[ 2 ];
1932
1933     return pIterator;
1934 }
1935
1936 MQTTStatus_t MQTT_SerializeSubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
1937                                       size_t subscriptionCount,
1938                                       uint16_t packetId,
1939                                       size_t remainingLength,
1940                                       const MQTTFixedBuffer_t * pFixedBuffer )
1941 {
1942     size_t i = 0;
1943     uint8_t * pIndex = NULL;
1944
1945     /* Validate all the parameters. */
1946     MQTTStatus_t status =
1947         validateSubscriptionSerializeParams( pSubscriptionList,
1948                                              subscriptionCount,
1949                                              packetId,
1950                                              remainingLength,
1951                                              pFixedBuffer );
1952
1953     if( status == MQTTSuccess )
1954     {
1955         pIndex = pFixedBuffer->pBuffer;
1956
1957         pIndex = MQTT_SerializeSubscribeHeader( remainingLength,
1958                                                 pIndex,
1959                                                 packetId );
1960
1961         /* Serialize each subscription topic filter and QoS. */
1962         for( i = 0; i < subscriptionCount; i++ )
1963         {
1964             pIndex = encodeString( pIndex,
1965                                    pSubscriptionList[ i ].pTopicFilter,
1966                                    pSubscriptionList[ i ].topicFilterLength );
1967
1968             /* Place the QoS in the SUBSCRIBE packet. */
1969             *pIndex = ( uint8_t ) ( pSubscriptionList[ i ].qos );
1970             pIndex++;
1971         }
1972
1973         LogDebug( ( "Length of serialized SUBSCRIBE packet is %lu.",
1974                     ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
1975     }
1976
1977     return status;
1978 }
1979
1980 /*-----------------------------------------------------------*/
1981
1982 MQTTStatus_t MQTT_GetUnsubscribePacketSize( const MQTTSubscribeInfo_t * pSubscriptionList,
1983                                             size_t subscriptionCount,
1984                                             size_t * pRemainingLength,
1985                                             size_t * pPacketSize )
1986 {
1987     MQTTStatus_t status = MQTTSuccess;
1988
1989     /* Validate parameters. */
1990     if( ( pSubscriptionList == NULL ) || ( pRemainingLength == NULL ) ||
1991         ( pPacketSize == NULL ) )
1992     {
1993         LogError( ( "Argument cannot be NULL: pSubscriptionList=%p, "
1994                     "pRemainingLength=%p, pPacketSize=%p.",
1995                     ( void * ) pSubscriptionList,
1996                     ( void * ) pRemainingLength,
1997                     ( void * ) pPacketSize ) );
1998         status = MQTTBadParameter;
1999     }
2000     else if( subscriptionCount == 0U )
2001     {
2002         LogError( ( "Subscription count is 0." ) );
2003         status = MQTTBadParameter;
2004     }
2005     else
2006     {
2007         /* Calculate the MQTT UNSUBSCRIBE packet size. */
2008         status = calculateSubscriptionPacketSize( pSubscriptionList,
2009                                                   subscriptionCount,
2010                                                   pRemainingLength,
2011                                                   pPacketSize,
2012                                                   MQTT_UNSUBSCRIBE );
2013     }
2014
2015     return status;
2016 }
2017
2018 /*-----------------------------------------------------------*/
2019
2020 MQTTStatus_t MQTT_SerializeUnsubscribe( const MQTTSubscribeInfo_t * pSubscriptionList,
2021                                         size_t subscriptionCount,
2022                                         uint16_t packetId,
2023                                         size_t remainingLength,
2024                                         const MQTTFixedBuffer_t * pFixedBuffer )
2025 {
2026     MQTTStatus_t status = MQTTSuccess;
2027     size_t i = 0;
2028     uint8_t * pIndex = NULL;
2029
2030     /* Validate all the parameters. */
2031     status = validateSubscriptionSerializeParams( pSubscriptionList,
2032                                                   subscriptionCount,
2033                                                   packetId,
2034                                                   remainingLength,
2035                                                   pFixedBuffer );
2036
2037     if( status == MQTTSuccess )
2038     {
2039         /* Get the start of the buffer to the iterator variable. */
2040         pIndex = pFixedBuffer->pBuffer;
2041
2042         pIndex = MQTT_SerializeUnsubscribeHeader( remainingLength, pIndex, packetId );
2043
2044         /* Serialize each subscription topic filter. */
2045         for( i = 0; i < subscriptionCount; i++ )
2046         {
2047             pIndex = encodeString( pIndex,
2048                                    pSubscriptionList[ i ].pTopicFilter,
2049                                    pSubscriptionList[ i ].topicFilterLength );
2050         }
2051
2052         LogDebug( ( "Length of serialized UNSUBSCRIBE packet is %lu.",
2053                     ( ( unsigned long ) ( pIndex - pFixedBuffer->pBuffer ) ) ) );
2054     }
2055
2056     return status;
2057 }
2058
2059 /*-----------------------------------------------------------*/
2060
2061 MQTTStatus_t MQTT_GetPublishPacketSize( const MQTTPublishInfo_t * pPublishInfo,
2062                                         size_t * pRemainingLength,
2063                                         size_t * pPacketSize )
2064 {
2065     MQTTStatus_t status = MQTTSuccess;
2066
2067     if( ( pPublishInfo == NULL ) || ( pRemainingLength == NULL ) || ( pPacketSize == NULL ) )
2068     {
2069         LogError( ( "Argument cannot be NULL: pPublishInfo=%p, "
2070                     "pRemainingLength=%p, pPacketSize=%p.",
2071                     ( void * ) pPublishInfo,
2072                     ( void * ) pRemainingLength,
2073                     ( void * ) pPacketSize ) );
2074         status = MQTTBadParameter;
2075     }
2076     else if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0U ) )
2077     {
2078         LogError( ( "Invalid topic name for PUBLISH: pTopicName=%p, "
2079                     "topicNameLength=%hu.",
2080                     ( void * ) pPublishInfo->pTopicName,
2081                     ( unsigned short ) pPublishInfo->topicNameLength ) );
2082         status = MQTTBadParameter;
2083     }
2084     else
2085     {
2086         /* Calculate the "Remaining length" field and total packet size. If it exceeds
2087          * what is allowed in the MQTT standard, return an error. */
2088         if( calculatePublishPacketSize( pPublishInfo, pRemainingLength, pPacketSize ) == false )
2089         {
2090             LogError( ( "PUBLISH packet remaining length exceeds %lu, which is the "
2091                         "maximum size allowed by MQTT 3.1.1.",
2092                         MQTT_MAX_REMAINING_LENGTH ) );
2093             status = MQTTBadParameter;
2094         }
2095     }
2096
2097     return status;
2098 }
2099
2100 /*-----------------------------------------------------------*/
2101
2102 MQTTStatus_t MQTT_SerializePublish( const MQTTPublishInfo_t * pPublishInfo,
2103                                     uint16_t packetId,
2104                                     size_t remainingLength,
2105                                     const MQTTFixedBuffer_t * pFixedBuffer )
2106 {
2107     MQTTStatus_t status = MQTTSuccess;
2108     size_t packetSize = 0;
2109
2110     if( ( pFixedBuffer == NULL ) || ( pPublishInfo == NULL ) )
2111     {
2112         LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
2113                     "pPublishInfo=%p.",
2114                     ( void * ) pFixedBuffer,
2115                     ( void * ) pPublishInfo ) );
2116         status = MQTTBadParameter;
2117     }
2118     /* A buffer must be configured for serialization. */
2119     else if( pFixedBuffer->pBuffer == NULL )
2120     {
2121         LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
2122         status = MQTTBadParameter;
2123     }
2124
2125     /* For serializing a publish, if there exists a payload, then the buffer
2126      * cannot be NULL. */
2127     else if( ( pPublishInfo->payloadLength > 0U ) && ( pPublishInfo->pPayload == NULL ) )
2128     {
2129         LogError( ( "A nonzero payload length requires a non-NULL payload: "
2130                     "payloadLength=%lu, pPayload=%p.",
2131                     ( unsigned long ) pPublishInfo->payloadLength,
2132                     pPublishInfo->pPayload ) );
2133         status = MQTTBadParameter;
2134     }
2135     else if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0U ) )
2136     {
2137         LogError( ( "Invalid topic name for PUBLISH: pTopicName=%p, "
2138                     "topicNameLength=%hu.",
2139                     ( void * ) pPublishInfo->pTopicName,
2140                     ( unsigned short ) pPublishInfo->topicNameLength ) );
2141         status = MQTTBadParameter;
2142     }
2143     else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
2144     {
2145         LogError( ( "Packet ID is 0 for PUBLISH with QoS=%u.",
2146                     ( unsigned int ) pPublishInfo->qos ) );
2147         status = MQTTBadParameter;
2148     }
2149     else if( ( pPublishInfo->dup == true ) && ( pPublishInfo->qos == MQTTQoS0 ) )
2150     {
2151         LogError( ( "Duplicate flag is set for PUBLISH with Qos 0." ) );
2152         status = MQTTBadParameter;
2153     }
2154     else
2155     {
2156         /* Length of serialized packet = First byte
2157          *                                + Length of encoded remaining length
2158          *                                + Remaining length. */
2159         packetSize = 1U + remainingLengthEncodedSize( remainingLength )
2160                      + remainingLength;
2161     }
2162
2163     if( ( status == MQTTSuccess ) && ( packetSize > pFixedBuffer->size ) )
2164     {
2165         LogError( ( "Buffer size of %lu is not sufficient to hold "
2166                     "serialized PUBLISH packet of size of %lu.",
2167                     ( unsigned long ) pFixedBuffer->size,
2168                     ( unsigned long ) packetSize ) );
2169         status = MQTTNoMemory;
2170     }
2171
2172     if( status == MQTTSuccess )
2173     {
2174         /* Serialize publish with header and payload. */
2175         serializePublishCommon( pPublishInfo,
2176                                 remainingLength,
2177                                 packetId,
2178                                 pFixedBuffer,
2179                                 true );
2180     }
2181
2182     return status;
2183 }
2184
2185 /*-----------------------------------------------------------*/
2186
2187 MQTTStatus_t MQTT_SerializePublishHeader( const MQTTPublishInfo_t * pPublishInfo,
2188                                           uint16_t packetId,
2189                                           size_t remainingLength,
2190                                           const MQTTFixedBuffer_t * pFixedBuffer,
2191                                           size_t * pHeaderSize )
2192 {
2193     MQTTStatus_t status = MQTTSuccess;
2194     size_t packetSize = 0;
2195
2196     if( ( pFixedBuffer == NULL ) || ( pPublishInfo == NULL ) ||
2197         ( pHeaderSize == NULL ) )
2198     {
2199         LogError( ( "Argument cannot be NULL: pFixedBuffer=%p, "
2200                     "pPublishInfo=%p, pHeaderSize=%p.",
2201                     ( void * ) pFixedBuffer,
2202                     ( void * ) pPublishInfo,
2203                     ( void * ) pHeaderSize ) );
2204         status = MQTTBadParameter;
2205     }
2206     /* A buffer must be configured for serialization. */
2207     else if( pFixedBuffer->pBuffer == NULL )
2208     {
2209         LogError( ( "Argument cannot be NULL: pFixedBuffer->pBuffer is NULL." ) );
2210         status = MQTTBadParameter;
2211     }
2212     else if( ( pPublishInfo->pTopicName == NULL ) || ( pPublishInfo->topicNameLength == 0U ) )
2213     {
2214         LogError( ( "Invalid topic name for publish: pTopicName=%p, "
2215                     "topicNameLength=%hu.",
2216                     ( void * ) pPublishInfo->pTopicName,
2217                     ( unsigned short ) pPublishInfo->topicNameLength ) );
2218         status = MQTTBadParameter;
2219     }
2220     else if( ( pPublishInfo->qos != MQTTQoS0 ) && ( packetId == 0U ) )
2221     {
2222         LogError( ( "Packet Id is 0 for publish with QoS=%hu.",
2223                     ( unsigned short ) pPublishInfo->qos ) );
2224         status = MQTTBadParameter;
2225     }
2226     else if( ( pPublishInfo->dup == true ) && ( pPublishInfo->qos == MQTTQoS0 ) )
2227     {
2228         LogError( ( "Duplicate flag is set for PUBLISH with Qos 0." ) );
2229         status = MQTTBadParameter;
2230     }
2231     else
2232     {
2233         /* Length of serialized packet = First byte
2234          *                               + Length of encoded remaining length
2235          *                               + Remaining length
2236          *                               - Payload Length.
2237          */
2238         packetSize = 1U + remainingLengthEncodedSize( remainingLength )
2239                      + remainingLength
2240                      - pPublishInfo->payloadLength;
2241     }
2242
2243     if( ( status == MQTTSuccess ) && ( packetSize > pFixedBuffer->size ) )
2244     {
2245         LogError( ( "Buffer size of %lu is not sufficient to hold "
2246                     "serialized PUBLISH header packet of size of %lu.",
2247                     ( unsigned long ) pFixedBuffer->size,
2248                     ( unsigned long ) ( packetSize - pPublishInfo->payloadLength ) ) );
2249         status = MQTTNoMemory;
2250     }
2251
2252     if( status == MQTTSuccess )
2253     {
2254         /* Serialize publish without copying the payload. */
2255         serializePublishCommon( pPublishInfo,
2256                                 remainingLength,
2257                                 packetId,
2258                                 pFixedBuffer,
2259                                 false );
2260
2261         /* Header size is the same as calculated packet size. */
2262         *pHeaderSize = packetSize;
2263     }
2264
2265     return status;
2266 }
2267
2268 /*-----------------------------------------------------------*/
2269
2270 MQTTStatus_t MQTT_SerializeAck( const MQTTFixedBuffer_t * pFixedBuffer,
2271                                 uint8_t packetType,
2272                                 uint16_t packetId )
2273 {
2274     MQTTStatus_t status = MQTTSuccess;
2275
2276     if( pFixedBuffer == NULL )
2277     {
2278         LogError( ( "Provided buffer is NULL." ) );
2279         status = MQTTBadParameter;
2280     }
2281     else if( pFixedBuffer->pBuffer == NULL )
2282     {
2283         LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
2284         status = MQTTBadParameter;
2285     }
2286     /* The buffer must be able to fit 4 bytes for the packet. */
2287     else if( pFixedBuffer->size < MQTT_PUBLISH_ACK_PACKET_SIZE )
2288     {
2289         LogError( ( "Insufficient memory for packet." ) );
2290         status = MQTTNoMemory;
2291     }
2292     else if( packetId == 0U )
2293     {
2294         LogError( ( "Packet ID cannot be 0." ) );
2295         status = MQTTBadParameter;
2296     }
2297     else
2298     {
2299         switch( packetType )
2300         {
2301             /* Only publish acks are serialized by the client. */
2302             case MQTT_PACKET_TYPE_PUBACK:
2303             case MQTT_PACKET_TYPE_PUBREC:
2304             case MQTT_PACKET_TYPE_PUBREL:
2305             case MQTT_PACKET_TYPE_PUBCOMP:
2306                 pFixedBuffer->pBuffer[ 0 ] = packetType;
2307                 pFixedBuffer->pBuffer[ 1 ] = MQTT_PACKET_SIMPLE_ACK_REMAINING_LENGTH;
2308                 pFixedBuffer->pBuffer[ 2 ] = UINT16_HIGH_BYTE( packetId );
2309                 pFixedBuffer->pBuffer[ 3 ] = UINT16_LOW_BYTE( packetId );
2310                 break;
2311
2312             default:
2313                 LogError( ( "Packet type is not a publish ACK: Packet type=%02x",
2314                             ( unsigned int ) packetType ) );
2315                 status = MQTTBadParameter;
2316                 break;
2317         }
2318     }
2319
2320     return status;
2321 }
2322
2323 /*-----------------------------------------------------------*/
2324
2325 MQTTStatus_t MQTT_GetDisconnectPacketSize( size_t * pPacketSize )
2326 {
2327     MQTTStatus_t status = MQTTSuccess;
2328
2329     if( pPacketSize == NULL )
2330     {
2331         LogError( ( "pPacketSize is NULL." ) );
2332         status = MQTTBadParameter;
2333     }
2334     else
2335     {
2336         /* MQTT DISCONNECT packets always have the same size. */
2337         *pPacketSize = MQTT_DISCONNECT_PACKET_SIZE;
2338     }
2339
2340     return status;
2341 }
2342
2343 /*-----------------------------------------------------------*/
2344
2345 MQTTStatus_t MQTT_SerializeDisconnect( const MQTTFixedBuffer_t * pFixedBuffer )
2346 {
2347     MQTTStatus_t status = MQTTSuccess;
2348
2349     /* Validate arguments. */
2350     if( pFixedBuffer == NULL )
2351     {
2352         LogError( ( "pFixedBuffer cannot be NULL." ) );
2353         status = MQTTBadParameter;
2354     }
2355     else if( pFixedBuffer->pBuffer == NULL )
2356     {
2357         LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
2358         status = MQTTBadParameter;
2359     }
2360     else
2361     {
2362         /* Empty else MISRA 15.7 */
2363     }
2364
2365     if( status == MQTTSuccess )
2366     {
2367         if( pFixedBuffer->size < MQTT_DISCONNECT_PACKET_SIZE )
2368         {
2369             LogError( ( "Buffer size of %lu is not sufficient to hold "
2370                         "serialized DISCONNECT packet of size of %lu.",
2371                         ( unsigned long ) pFixedBuffer->size,
2372                         MQTT_DISCONNECT_PACKET_SIZE ) );
2373             status = MQTTNoMemory;
2374         }
2375     }
2376
2377     if( status == MQTTSuccess )
2378     {
2379         pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_DISCONNECT;
2380         pFixedBuffer->pBuffer[ 1 ] = MQTT_DISCONNECT_REMAINING_LENGTH;
2381     }
2382
2383     return status;
2384 }
2385
2386 /*-----------------------------------------------------------*/
2387
2388 MQTTStatus_t MQTT_GetPingreqPacketSize( size_t * pPacketSize )
2389 {
2390     MQTTStatus_t status = MQTTSuccess;
2391
2392     if( pPacketSize == NULL )
2393     {
2394         LogError( ( "pPacketSize is NULL." ) );
2395         status = MQTTBadParameter;
2396     }
2397     else
2398     {
2399         /* MQTT PINGREQ packets always have the same size. */
2400         *pPacketSize = MQTT_PACKET_PINGREQ_SIZE;
2401     }
2402
2403     return status;
2404 }
2405
2406 /*-----------------------------------------------------------*/
2407
2408 MQTTStatus_t MQTT_SerializePingreq( const MQTTFixedBuffer_t * pFixedBuffer )
2409 {
2410     MQTTStatus_t status = MQTTSuccess;
2411
2412     if( pFixedBuffer == NULL )
2413     {
2414         LogError( ( "pFixedBuffer is NULL." ) );
2415         status = MQTTBadParameter;
2416     }
2417     else if( pFixedBuffer->pBuffer == NULL )
2418     {
2419         LogError( ( "pFixedBuffer->pBuffer cannot be NULL." ) );
2420         status = MQTTBadParameter;
2421     }
2422     else
2423     {
2424         /* Empty else MISRA 15.7 */
2425     }
2426
2427     if( status == MQTTSuccess )
2428     {
2429         if( pFixedBuffer->size < MQTT_PACKET_PINGREQ_SIZE )
2430         {
2431             LogError( ( "Buffer size of %lu is not sufficient to hold "
2432                         "serialized PINGREQ packet of size of %lu.",
2433                         ( unsigned long ) pFixedBuffer->size,
2434                         MQTT_PACKET_PINGREQ_SIZE ) );
2435             status = MQTTNoMemory;
2436         }
2437     }
2438
2439     if( status == MQTTSuccess )
2440     {
2441         /* Ping request packets are always the same. */
2442         pFixedBuffer->pBuffer[ 0 ] = MQTT_PACKET_TYPE_PINGREQ;
2443         pFixedBuffer->pBuffer[ 1 ] = 0x00;
2444     }
2445
2446     return status;
2447 }
2448
2449 /*-----------------------------------------------------------*/
2450
2451 MQTTStatus_t MQTT_DeserializePublish( const MQTTPacketInfo_t * pIncomingPacket,
2452                                       uint16_t * pPacketId,
2453                                       MQTTPublishInfo_t * pPublishInfo )
2454 {
2455     MQTTStatus_t status = MQTTSuccess;
2456
2457     if( ( pIncomingPacket == NULL ) || ( pPacketId == NULL ) || ( pPublishInfo == NULL ) )
2458     {
2459         LogError( ( "Argument cannot be NULL: pIncomingPacket=%p, "
2460                     "pPacketId=%p, pPublishInfo=%p",
2461                     ( void * ) pIncomingPacket,
2462                     ( void * ) pPacketId,
2463                     ( void * ) pPublishInfo ) );
2464         status = MQTTBadParameter;
2465     }
2466     else if( ( pIncomingPacket->type & 0xF0U ) != MQTT_PACKET_TYPE_PUBLISH )
2467     {
2468         LogError( ( "Packet is not publish. Packet type: %02x.",
2469                     ( unsigned int ) pIncomingPacket->type ) );
2470         status = MQTTBadParameter;
2471     }
2472     else if( pIncomingPacket->pRemainingData == NULL )
2473     {
2474         LogError( ( "Argument cannot be NULL: "
2475                     "pIncomingPacket->pRemainingData is NULL." ) );
2476         status = MQTTBadParameter;
2477     }
2478     else
2479     {
2480         status = deserializePublish( pIncomingPacket, pPacketId, pPublishInfo );
2481     }
2482
2483     return status;
2484 }
2485
2486 /*-----------------------------------------------------------*/
2487
2488 MQTTStatus_t MQTT_DeserializeAck( const MQTTPacketInfo_t * pIncomingPacket,
2489                                   uint16_t * pPacketId,
2490                                   bool * pSessionPresent )
2491 {
2492     MQTTStatus_t status = MQTTSuccess;
2493
2494     if( pIncomingPacket == NULL )
2495     {
2496         LogError( ( "pIncomingPacket cannot be NULL." ) );
2497         status = MQTTBadParameter;
2498     }
2499
2500     /* Pointer for packet identifier cannot be NULL for packets other than
2501      * CONNACK and PINGRESP. */
2502     else if( ( pPacketId == NULL ) &&
2503              ( ( pIncomingPacket->type != MQTT_PACKET_TYPE_CONNACK ) &&
2504                ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) ) )
2505     {
2506         LogError( ( "pPacketId cannot be NULL for packet type %02x.",
2507                     ( unsigned int ) pIncomingPacket->type ) );
2508         status = MQTTBadParameter;
2509     }
2510     /* Pointer for session present cannot be NULL for CONNACK. */
2511     else if( ( pSessionPresent == NULL ) &&
2512              ( pIncomingPacket->type == MQTT_PACKET_TYPE_CONNACK ) )
2513     {
2514         LogError( ( "pSessionPresent cannot be NULL for CONNACK packet." ) );
2515         status = MQTTBadParameter;
2516     }
2517
2518     /* Pointer for remaining data cannot be NULL for packets other
2519      * than PINGRESP. */
2520     else if( ( pIncomingPacket->pRemainingData == NULL ) &&
2521              ( pIncomingPacket->type != MQTT_PACKET_TYPE_PINGRESP ) )
2522     {
2523         LogError( ( "Remaining data of incoming packet is NULL." ) );
2524         status = MQTTBadParameter;
2525     }
2526     else
2527     {
2528         /* Make sure response packet is a valid ack. */
2529         switch( pIncomingPacket->type )
2530         {
2531             case MQTT_PACKET_TYPE_CONNACK:
2532                 status = deserializeConnack( pIncomingPacket, pSessionPresent );
2533                 break;
2534
2535             case MQTT_PACKET_TYPE_SUBACK:
2536                 status = deserializeSuback( pIncomingPacket, pPacketId );
2537                 break;
2538
2539             case MQTT_PACKET_TYPE_PINGRESP:
2540                 status = deserializePingresp( pIncomingPacket );
2541                 break;
2542
2543             case MQTT_PACKET_TYPE_UNSUBACK:
2544             case MQTT_PACKET_TYPE_PUBACK:
2545             case MQTT_PACKET_TYPE_PUBREC:
2546             case MQTT_PACKET_TYPE_PUBREL:
2547             case MQTT_PACKET_TYPE_PUBCOMP:
2548                 status = deserializeSimpleAck( pIncomingPacket, pPacketId );
2549                 break;
2550
2551             /* Any other packet type is invalid. */
2552             default:
2553                 LogError( ( "IotMqtt_DeserializeResponse() called with unknown packet type:(%02x).",
2554                             ( unsigned int ) pIncomingPacket->type ) );
2555                 status = MQTTBadResponse;
2556                 break;
2557         }
2558     }
2559
2560     return status;
2561 }
2562
2563 /*-----------------------------------------------------------*/
2564
2565 MQTTStatus_t MQTT_GetIncomingPacketTypeAndLength( TransportRecv_t readFunc,
2566                                                   NetworkContext_t * pNetworkContext,
2567                                                   MQTTPacketInfo_t * pIncomingPacket )
2568 {
2569     MQTTStatus_t status = MQTTSuccess;
2570     int32_t bytesReceived = 0;
2571
2572     if( pIncomingPacket == NULL )
2573     {
2574         LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
2575         status = MQTTBadParameter;
2576     }
2577     else
2578     {
2579         /* Read a single byte. */
2580         bytesReceived = readFunc( pNetworkContext,
2581                                   &( pIncomingPacket->type ),
2582                                   1U );
2583     }
2584
2585     if( bytesReceived == 1 )
2586     {
2587         /* Check validity. */
2588         if( incomingPacketValid( pIncomingPacket->type ) == true )
2589         {
2590             pIncomingPacket->remainingLength = getRemainingLength( readFunc,
2591                                                                    pNetworkContext );
2592
2593             if( pIncomingPacket->remainingLength == MQTT_REMAINING_LENGTH_INVALID )
2594             {
2595                 LogError( ( "Incoming packet remaining length invalid." ) );
2596                 status = MQTTBadResponse;
2597             }
2598         }
2599         else
2600         {
2601             LogError( ( "Incoming packet invalid: Packet type=%u.",
2602                         ( unsigned int ) pIncomingPacket->type ) );
2603             status = MQTTBadResponse;
2604         }
2605     }
2606     else if( ( status != MQTTBadParameter ) && ( bytesReceived == 0 ) )
2607     {
2608         status = MQTTNoDataAvailable;
2609     }
2610
2611     /* If the input packet was valid, then any other number of bytes received is
2612      * a failure. */
2613     else if( status != MQTTBadParameter )
2614     {
2615         LogError( ( "A single byte was not read from the transport: "
2616                     "transportStatus=%ld.",
2617                     ( long int ) bytesReceived ) );
2618         status = MQTTRecvFailed;
2619     }
2620     else
2621     {
2622         /* Empty else MISRA 15.7 */
2623     }
2624
2625     return status;
2626 }
2627
2628 /*-----------------------------------------------------------*/
2629
2630 MQTTStatus_t MQTT_ProcessIncomingPacketTypeAndLength( const uint8_t * pBuffer,
2631                                                       const size_t * pIndex,
2632                                                       MQTTPacketInfo_t * pIncomingPacket )
2633 {
2634     MQTTStatus_t status = MQTTSuccess;
2635
2636     if( pIncomingPacket == NULL )
2637     {
2638         LogError( ( "Invalid parameter: pIncomingPacket is NULL." ) );
2639         status = MQTTBadParameter;
2640     }
2641     else if( pIndex == NULL )
2642     {
2643         LogError( ( "Invalid parameter: pIndex is NULL." ) );
2644         status = MQTTBadParameter;
2645     }
2646     else if( pBuffer == NULL )
2647     {
2648         LogError( ( "Invalid parameter: pBuffer is NULL." ) );
2649         status = MQTTBadParameter;
2650     }
2651     /* There should be at least one byte in the buffer */
2652     else if( *pIndex < 1U )
2653     {
2654         /* No data is available. There are 0 bytes received from the network
2655          * receive function. */
2656         status = MQTTNoDataAvailable;
2657     }
2658     else
2659     {
2660         /* At least one byte is present which should be deciphered. */
2661         pIncomingPacket->type = pBuffer[ 0 ];
2662     }
2663
2664     if( status == MQTTSuccess )
2665     {
2666         /* Check validity. */
2667         if( incomingPacketValid( pIncomingPacket->type ) == true )
2668         {
2669             status = processRemainingLength( pBuffer,
2670                                              pIndex,
2671                                              pIncomingPacket );
2672         }
2673         else
2674         {
2675             LogError( ( "Incoming packet invalid: Packet type=%u.",
2676                         ( unsigned int ) pIncomingPacket->type ) );
2677             status = MQTTBadResponse;
2678         }
2679     }
2680
2681     return status;
2682 }
2683
2684 /*-----------------------------------------------------------*/