What is proper transmit behavior if user packet exceeds DR_ spec, and processing a Mac command

This is a followup to a previous Topic where I thought packet length verification was incorrect and it still may be. This is a bit more information,

The Previous Topic: LoRaWan: LoRaMac.c - ValidatePayloadLength( ) fails to catch too large payload if fOptsLen != 0

NOTE: My understanding of LoRaWan protocol could use some work, this is how I currently understand what is happening.

The issue: I am seeing a user payload whose size is greater than allowed by the currently defined data rate, DR_, that is still being delivered to the network server.

This will occur if the LoRaMac runtime is processing a response to a network server request, in this case a SRV_MAC_LINK_ADR_REQ was returned during the Rx window of a previous uplink message.

The runtime is preparing a response by adding the mac command response data to the message that is to be delivered to the network server during the next uplink.

In this case during the next uplink the “user packet”, which again violates the DR_ maximum, is delivered to the network server along with what is apparently the MAC response.

Previous and follow on uplink messages of the same packet size are flagged as invalid and not delivered, only the one containing the MAC response is sent with the user packet intact.

Is this correct LoRaWan behavior, deliver the user packet even though it violates DR_ maximum?

The scenario (RegionUS915)

  • Default Data Rate = 3
  • end node user app overrides Data Rate, DR = 0, (implies max user packet of 11 bytes)
  • end node user app is in a loop sending a packet that is size 24, (yes, too large for DR_0)

-Join attempt
– network join attempts alternate between DR_0 and DR_3, In this scenario the join succeeds with DR_3.

- first user uplink attempt
– the first packet length error is not caught by the LoRaWan library level’s max length test because DR_3 is used as the compare DR ( this does not look correct either)
– LoRWan library layer resets the Data Rate to the correct DR_0 before passing the packet buffer off to lower layers (this is after the length check)
– LoRaMac layer catches the user packet excess length error and aborts the send, nothing is sent to the network server.

- Next user uplink attempt
– this attempt fails the packet length check in LoRaWan lib layer, as now the data rate used in the compare is DR_0
– user packet length is set to 0
– zero length user packet is sent to the LoRMac layer and on to the network server
– network server decodes the fact the packet is zero length
– at this point the network server is returning (downlink) a SRV_MAC_LINK_ADR_REQ to the end node during the Rx time.
– the response is partially packaged for delivery during the next uplink transmission.

- Next user send attempt
– now the response to the SRV_MAC_LINK_ADR_REQ is returned to the network server,
– this time the LoRaWan lib packet length test passes because fOptsLen is not zero, (though I’m not sure why it should be passing??)

– now the response to the SRV_MAC_LINK_ADR_REQ is completed, mac data is added to the packet to be sent
– the send is successful, mac data plus user packet data
– the network server successfully extracts out the user packet.

This does not seem correct, that the user packet data is sent even though it exceeds the max length for the given DR_.

It seems the size check indeed may not be correct
( is this part correct?? “payloadSize > maxN”, should not that be
“payloadSize < maxN” ?

actual data:
user payload size lenN: 24, fOptsLen: 4, maxN: 11,

The code:
payloadSize = userPayload + fOptsLen;

 ( payloadSize > maxN ) && (fOptsLen != 0) && (fOptsLen <= maxN)) || ( payloadSize <= maxN )) && ( payloadSize <= LORAMAC_PHY_MAXPAYLOAD )

Should this size check pass in this instance?

Apologies for the messiness of these two topics. Just trying to provide as much info as possible.


We recommend that you modify the default ADR to a higher level.


Food for thought

Below an extract from some more recent code, your suspicion might be right …

static uint8_t GetMaxAppPayloadWithoutFOptsLength( int8_t datarate )
GetPhyParams_t getPhy;
PhyParam_t phyParam;

// Setup PHY request
getPhy.UplinkDwellTime = MacCtx.NvmCtx->MacParams.UplinkDwellTime;
getPhy.Datarate = datarate;
getPhy.Attribute = PHY_MAX_PAYLOAD;
phyParam = RegionGetPhyParam( MacCtx.NvmCtx->Region, &getPhy );

return phyParam.Value;


static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen )
uint16_t maxN = 0;
uint16_t payloadSize = 0;

maxN = GetMaxAppPayloadWithoutFOptsLength( datarate );

// Calculate the resulting payload size
payloadSize = ( lenN + fOptsLen );

// Validation of the application payload size
if( ( payloadSize <= maxN ) && ( payloadSize <= LORAMAC_PHY_MAXPAYLOAD ) )
    return true;
return false;


Yes, this would be a good temporary fix. But it does not solve the problem.

I’m not sure why it would be proper to send a user packet if it exceeds the data rate maximum. (payloadSize > maxN).
Are we sure the “>” is not a mistake??

Perhaps this is to try to return the MAC response to the network? In this case would it be more proper to return the MAC response but not the user packet?

I will admit I do not know the network impact of exceeding the data rate packet maximum.

This issue along with a couple of others is bothersome. The other issues:

  1. If the packet exceeds the DR max and no MAC responses are queued the send will fail silently. There is no feedback to the user application.
  2. In this case the runtime sends a zero length packet, I guess in order to return any pending MAC responses? Why transmit anything if there are “no” pending responses?

It does not look like the Semtech LoRaWan reference implementation handles these last two either, might be nice add ons.

Unfortunately just changing “>” to “<” exposes more issues. While that will prevent the delivery of the over sized user packet. The MAC response is then not properly delivered.
This MAC response should be tested if the above changes are considered.