2424 #include <config.h>
2525#endif
2626
27- #include "wolfmqtt/mqtt_types.h"
2827#include "wolfmqtt/mqtt_broker.h"
28+ #include "wolfmqtt/mqtt_types.h"
2929#include "wolfmqtt/mqtt_client.h"
3030#include "wolfmqtt/mqtt_packet.h"
3131#include "wolfmqtt/mqtt_socket.h"
@@ -1278,8 +1278,13 @@ static int BrokerNetDisconnect(void* context)
12781278/* must NOT be re-delivered to subscribers. The state is per-client and is */
12791279/* cleared on disconnect; surviving across reconnect would require the */
12801280/* broader session-state work (see #485/#489/#494). */
1281+ /* */
1282+ /* The entire QoS 2 inbound state and PUBREL/PUBREC/PUBCOMP handling is */
1283+ /* compiled out when WOLFMQTT_MAX_QOS < 2. Subscribe-grant capping and */
1284+ /* inbound-publish QoS rejection cover the corresponding wire paths. */
12811285/* -------------------------------------------------------------------------- */
12821286
1287+ #if WOLFMQTT_MAX_QOS >= 2
12831288/* Returns 1 if packet_id is currently awaiting PUBREL, 0 otherwise. */
12841289static int BrokerInboundQos2_Contains (BrokerClient * bc , word16 packet_id )
12851290{
@@ -1425,13 +1430,16 @@ static void BrokerInboundQos2_Clear(BrokerClient* bc)
14251430 bc -> qos2_pending_count = 0 ;
14261431#endif
14271432}
1433+ #endif /* WOLFMQTT_MAX_QOS >= 2 */
14281434
14291435static void BrokerClient_Free (BrokerClient * bc )
14301436{
14311437 if (bc == NULL ) {
14321438 return ;
14331439 }
1440+ #if WOLFMQTT_MAX_QOS >= 2
14341441 BrokerInboundQos2_Clear (bc );
1442+ #endif
14351443
14361444#ifdef ENABLE_MQTT_WEBSOCKET
14371445 if (bc -> ws_ctx != NULL ) {
@@ -3264,7 +3272,12 @@ static int BrokerHandle_Connect(BrokerClient* bc, int rx_len,
32643272#endif
32653273 bc -> will_payload_len = wp_len ;
32663274 }
3267- bc -> will_qos = mc .lwt_msg -> qos ;
3275+ /* Clamp will QoS to this build's Maximum QoS. A v5 client that
3276+ * sent Will QoS > advertised Max QoS would already be in
3277+ * Protocol Error territory, but for v3.1.1 (no advertisement)
3278+ * we silently downgrade rather than rejecting CONNECT. */
3279+ bc -> will_qos = (mc .lwt_msg -> qos > WOLFMQTT_MAX_QOS ) ?
3280+ (MqttQoS )WOLFMQTT_MAX_QOS : mc .lwt_msg -> qos ;
32683281 bc -> will_retain = mc .lwt_msg -> retain ;
32693282 bc -> will_delay_sec = 0 ;
32703283#ifdef WOLFMQTT_V5
@@ -3445,11 +3458,18 @@ static int BrokerHandle_Connect(BrokerClient* bc, int rx_len,
34453458 prop -> data_byte = 0 ;
34463459 #endif
34473460 }
3461+ /* [MQTT-3.2.2.3.4] Maximum QoS property MUST be 0 or 1. Absence
3462+ * of the property signals server supports Maximum QoS 2. Emitting
3463+ * Maximum QoS = 2 is a Protocol Error and strict v5 clients will
3464+ * disconnect on receipt. Emit the property only when this build
3465+ * caps below QoS 2 via WOLFMQTT_MAX_QOS. */
3466+ #if WOLFMQTT_MAX_QOS < 2
34483467 prop = MqttProps_Add (& ack .props );
34493468 if (prop != NULL ) {
34503469 prop -> type = MQTT_PROP_MAX_QOS ;
3451- prop -> data_byte = MQTT_QOS_2 ;
3470+ prop -> data_byte = ( byte ) WOLFMQTT_MAX_QOS ;
34523471 }
3472+ #endif
34533473 }
34543474#endif
34553475
@@ -3517,9 +3537,10 @@ static int BrokerHandle_Subscribe(BrokerClient* bc, int rx_len,
35173537 MqttQoS topic_qos = sub .topics [i ].qos ;
35183538 MqttQoS granted_qos ;
35193539
3520- /* Cap at QoS 2 */
3521- if (topic_qos > MQTT_QOS_2 ) {
3522- topic_qos = MQTT_QOS_2 ;
3540+ /* [MQTT-3.8.4-7] / [MQTT-3.9.3]: subscribe grant capped at the
3541+ * build's Maximum QoS. Default is QoS 2. */
3542+ if (topic_qos > WOLFMQTT_MAX_QOS ) {
3543+ topic_qos = (MqttQoS )WOLFMQTT_MAX_QOS ;
35233544 }
35243545 granted_qos = topic_qos ;
35253546
@@ -3662,7 +3683,9 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len,
36623683 MqttPublishResp resp ;
36633684 byte * payload = NULL ;
36643685 char * topic = NULL ;
3686+ #if WOLFMQTT_MAX_QOS >= 2
36653687 int qos2_duplicate = 0 ;
3688+ #endif
36663689#ifdef WOLFMQTT_STATIC_MEMORY
36673690 char topic_buf [BROKER_MAX_TOPIC_LEN ];
36683691#endif
@@ -3684,6 +3707,26 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len,
36843707 * MALFORMED_DATA before reaching this handler. The broker no longer
36853708 * needs a per-handler scan. */
36863709
3710+ #if WOLFMQTT_MAX_QOS < 2
3711+ /* [MQTT-3.2.2.3.4] / [MQTT-3.3.4]: this build advertised Maximum QoS
3712+ * below 2. A client publishing at QoS > our cap is a Protocol Error;
3713+ * v5 spec wants reason 0x9B QoS Not Supported. v3 has no reason code
3714+ * field, so we just abnormally close. */
3715+ if (pub .qos > WOLFMQTT_MAX_QOS ) {
3716+ WBLOG_ERR (broker ,
3717+ "broker: PUBLISH QoS %d exceeds WOLFMQTT_MAX_QOS=%d sock=%d" ,
3718+ pub .qos , WOLFMQTT_MAX_QOS , (int )bc -> sock );
3719+ #ifdef WOLFMQTT_V5
3720+ if (bc -> protocol_level >= MQTT_CONNECT_PROTOCOL_LEVEL_5 ) {
3721+ (void )BrokerSend_Disconnect (bc , MQTT_REASON_QOS_NOT_SUPPORTED );
3722+ }
3723+ #endif
3724+ rc = MQTT_CODE_ERROR_MALFORMED_DATA ;
3725+ goto publish_cleanup ;
3726+ }
3727+ #endif /* WOLFMQTT_MAX_QOS < 2 */
3728+
3729+ #if WOLFMQTT_MAX_QOS >= 2
36873730 /* [MQTT-4.3.3] QoS 2 duplicate detection. If we already PUBREC'd this
36883731 * packet_id and are still waiting for PUBREL, treat the inbound PUBLISH
36893732 * as a retransmission: send another PUBREC but DO NOT re-deliver the
@@ -3722,6 +3765,7 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len,
37223765 }
37233766 }
37243767 }
3768+ #endif /* WOLFMQTT_MAX_QOS >= 2 */
37253769
37263770 /* Create null-terminated topic copy for matching/logging */
37273771 if (pub .topic_name && pub .topic_name_len > 0 ) {
@@ -3749,7 +3793,11 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len,
37493793#ifdef WOLFMQTT_BROKER_RETAINED
37503794 /* Handle retained messages - skipped for QoS 2 duplicates: the original
37513795 * PUBLISH already updated the retained store. */
3752- if (!qos2_duplicate && topic != NULL && pub .retain ) {
3796+ if (
3797+ #if WOLFMQTT_MAX_QOS >= 2
3798+ !qos2_duplicate &&
3799+ #endif
3800+ topic != NULL && pub .retain ) {
37533801 if (pub .total_len == 0 ) {
37543802 BrokerRetained_Delete (broker , topic );
37553803 }
@@ -3778,7 +3826,10 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len,
37783826
37793827 /* Fan-out is skipped for QoS 2 duplicates: subscribers already received
37803828 * the application message from the original PUBLISH ([MQTT-4.3.3]). */
3781- if (!qos2_duplicate &&
3829+ if (
3830+ #if WOLFMQTT_MAX_QOS >= 2
3831+ !qos2_duplicate &&
3832+ #endif
37823833 topic != NULL && (payload != NULL || pub .total_len == 0 )) {
37833834#ifdef WOLFMQTT_STATIC_MEMORY
37843835 int i ;
@@ -3883,6 +3934,7 @@ static int BrokerHandle_Publish(BrokerClient* bc, int rx_len,
38833934 return rc ;
38843935}
38853936
3937+ #if WOLFMQTT_MAX_QOS >= 2
38863938static int BrokerHandle_PublishRel (BrokerClient * bc , int rx_len )
38873939{
38883940 int rc ;
@@ -3957,6 +4009,7 @@ static int BrokerHandle_PublishRec(BrokerClient* bc, int rx_len)
39574009 }
39584010 return rc ;
39594011}
4012+ #endif /* WOLFMQTT_MAX_QOS >= 2 */
39604013
39614014/* [MQTT-2.2.2-2] / [MQTT-3.8.1-1] etc.: a malformed packet MUST cause the
39624015 * server to close the network connection. Mirrors the read-failure close
@@ -4129,6 +4182,7 @@ static int BrokerClient_Process(MqttBroker* broker, BrokerClient* bc)
41294182 case MQTT_PACKET_TYPE_PUBLISH_ACK :
41304183 /* QoS 1 ack from subscriber - delivery complete */
41314184 break ;
4185+ #if WOLFMQTT_MAX_QOS >= 2
41324186 case MQTT_PACKET_TYPE_PUBLISH_REC :
41334187 {
41344188 /* QoS 2 step 2: subscriber sends PUBREC, broker
@@ -4155,6 +4209,7 @@ static int BrokerClient_Process(MqttBroker* broker, BrokerClient* bc)
41554209 /* QoS 2 step 4: subscriber sends PUBCOMP - delivery
41564210 * complete */
41574211 break ;
4212+ #endif /* WOLFMQTT_MAX_QOS >= 2 */
41584213 case MQTT_PACKET_TYPE_SUBSCRIBE :
41594214 {
41604215 int s_rc = BrokerHandle_Subscribe (bc , rc , broker );
0 commit comments