@@ -1004,6 +1004,86 @@ TEST(decode_connack_malformed_remain_len_one)
10041004 ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA , rc );
10051005}
10061006
1007+ /* [MQTT-3.2.2-1] / [MQTT-3.2.2-4] CONNACK Flags receive-side validation.
1008+ *
1009+ * The Connect Acknowledge Flags byte has only bit 0 (Session Present)
1010+ * defined; bits 7-1 are reserved and MUST be 0. Additionally, a non-zero
1011+ * return code (refusal) MUST come back with Session Present = 0. The
1012+ * decoder must reject violations so the client closes the connection
1013+ * per [MQTT-4.8.0-1].
1014+ *
1015+ * Helper: build a 4-byte v3.1.1 CONNACK with the given flags+return_code
1016+ * and ask MqttDecode_ConnectAck what it returns. */
1017+ static int decode_connack_flags (byte flags , byte return_code )
1018+ {
1019+ byte buf [4 ];
1020+ MqttConnectAck ack ;
1021+ buf [0 ] = MQTT_PACKET_TYPE_SET (MQTT_PACKET_TYPE_CONNECT_ACK );
1022+ buf [1 ] = 2 ;
1023+ buf [2 ] = flags ;
1024+ buf [3 ] = return_code ;
1025+ XMEMSET (& ack , 0 , sizeof (ack ));
1026+ return MqttDecode_ConnectAck (buf , (int )sizeof (buf ), & ack );
1027+ }
1028+
1029+ TEST (decode_connack_flags_session_present_accepted )
1030+ {
1031+ /* SP=1 with return_code=0 is the canonical resumed-session case. */
1032+ int rc = decode_connack_flags (0x01 , MQTT_CONNECT_ACK_CODE_ACCEPTED );
1033+ ASSERT_TRUE (rc > 0 );
1034+ }
1035+
1036+ TEST (decode_connack_flags_no_session_accepted )
1037+ {
1038+ int rc = decode_connack_flags (0x00 , MQTT_CONNECT_ACK_CODE_ACCEPTED );
1039+ ASSERT_TRUE (rc > 0 );
1040+ }
1041+
1042+ TEST (decode_connack_flags_reserved_bit_1_rejected )
1043+ {
1044+ /* 0x02: bit 1 set (reserved). */
1045+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA ,
1046+ decode_connack_flags (0x02 , MQTT_CONNECT_ACK_CODE_ACCEPTED ));
1047+ }
1048+
1049+ TEST (decode_connack_flags_reserved_bit_7_rejected )
1050+ {
1051+ /* 0x80: bit 7 set (reserved). */
1052+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA ,
1053+ decode_connack_flags (0x80 , MQTT_CONNECT_ACK_CODE_ACCEPTED ));
1054+ }
1055+
1056+ TEST (decode_connack_flags_all_reserved_rejected )
1057+ {
1058+ /* 0xFE: bits 7-1 all set, SP=0. */
1059+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA ,
1060+ decode_connack_flags (0xFE , MQTT_CONNECT_ACK_CODE_ACCEPTED ));
1061+ }
1062+
1063+ TEST (decode_connack_flags_all_bits_rejected )
1064+ {
1065+ /* 0xFF: bits 7-1 set + SP=1. Reserved-bit check fires first. */
1066+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA ,
1067+ decode_connack_flags (0xFF , MQTT_CONNECT_ACK_CODE_ACCEPTED ));
1068+ }
1069+
1070+ TEST (decode_connack_refused_with_session_present_rejected )
1071+ {
1072+ /* [MQTT-3.2.2-4]: refused CONNACK MUST have SP=0. flags=0x01 with a
1073+ * non-zero return code is malformed. */
1074+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA ,
1075+ decode_connack_flags (0x01 , MQTT_CONNECT_ACK_CODE_REFUSED_PROTO ));
1076+ ASSERT_EQ (MQTT_CODE_ERROR_MALFORMED_DATA ,
1077+ decode_connack_flags (0x01 , MQTT_CONNECT_ACK_CODE_REFUSED_ID ));
1078+ }
1079+
1080+ TEST (decode_connack_refused_without_session_present_accepted )
1081+ {
1082+ /* Refusal with SP=0 is the legal shape. */
1083+ int rc = decode_connack_flags (0x00 , MQTT_CONNECT_ACK_CODE_REFUSED_PROTO );
1084+ ASSERT_TRUE (rc > 0 );
1085+ }
1086+
10071087/* ============================================================================
10081088 * MqttEncode_Subscribe
10091089 * ============================================================================ */
@@ -2718,6 +2798,14 @@ void run_mqtt_packet_tests(void)
27182798 RUN_TEST (decode_connack_valid );
27192799 RUN_TEST (decode_connack_malformed_remain_len_zero );
27202800 RUN_TEST (decode_connack_malformed_remain_len_one );
2801+ RUN_TEST (decode_connack_flags_session_present_accepted );
2802+ RUN_TEST (decode_connack_flags_no_session_accepted );
2803+ RUN_TEST (decode_connack_flags_reserved_bit_1_rejected );
2804+ RUN_TEST (decode_connack_flags_reserved_bit_7_rejected );
2805+ RUN_TEST (decode_connack_flags_all_reserved_rejected );
2806+ RUN_TEST (decode_connack_flags_all_bits_rejected );
2807+ RUN_TEST (decode_connack_refused_with_session_present_rejected );
2808+ RUN_TEST (decode_connack_refused_without_session_present_accepted );
27212809
27222810 /* MqttEncode_Subscribe */
27232811 RUN_TEST (encode_subscribe_packet_id_zero );
0 commit comments