Skip to content

Commit 4b78a7c

Browse files
Hasnain VirkCruz Monrreal II
authored andcommitted
FRMPayload size validity
It was pointed out in #7432 and #7232 that the stack was comparing frame payload size with the allowed payload size in a wrong manner in shcedule_tx(). We must strip the overhead from the frame before comparison. We did have a similar check in prepare_ongoing_tx() API which would correctly analyse the situation but a check was needed in schedule_tx() as well. The reason is that the schedule_tx() API can be called automatically by the stack if the user intiated requested was not promptly entertained because of duty cycle restriction. Now, the datarate can change here (for CONFIRMED messages if the ack was not received after retries max out). That's why a test for validity was needed. We now perform a comparison using _ongoing_tx_message structure which contains the actual FRMPayload size. For proprietary type of messages only MHDR and Port field is used so we shouldn't add MAC commands and other overhead into them. In order to have consistent frame overhead, we have opted to always include Port field in the frame.
1 parent 2c15086 commit 4b78a7c

File tree

2 files changed

+75
-50
lines changed

2 files changed

+75
-50
lines changed

features/lorawan/lorastack/mac/LoRaMac.cpp

Lines changed: 58 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1034,6 +1034,7 @@ lorawan_status_t LoRaMac::schedule_tx()
10341034
{
10351035
channel_selection_params_t next_channel;
10361036
lorawan_time_t backoff_time = 0;
1037+
uint8_t fopts_len = 0;
10371038

10381039
if (_params.sys_params.max_duty_cycle == 255) {
10391040
return LORAWAN_STATUS_DEVICE_OFF;
@@ -1091,9 +1092,25 @@ lorawan_status_t LoRaMac::schedule_tx()
10911092
_params.rx_window2_delay = _params.sys_params.join_accept_delay2
10921093
+ _params.rx_window2_config.window_offset;
10931094
} else {
1094-
if (validate_payload_length(_params.tx_buffer_len,
1095+
1096+
// if the outgoing message is a proprietary message, it doesn't include any
1097+
// standard message formatting except port and MHDR.
1098+
if (_ongoing_tx_msg.type == MCPS_PROPRIETARY) {
1099+
fopts_len = 0;
1100+
} else {
1101+
fopts_len = _mac_commands.get_mac_cmd_length() + _mac_commands.get_repeat_commands_length();
1102+
}
1103+
1104+
// A check was performed for validity of FRMPayload in ::prepare_ongoing_tx() API.
1105+
// However, owing to the asynch nature of the send() API, we should check the
1106+
// validity again, as datarate may have changed since we last attempted to transmit.
1107+
if (validate_payload_length(_ongoing_tx_msg.f_buffer_size,
10951108
_params.sys_params.channel_data_rate,
1096-
_mac_commands.get_mac_cmd_length()) == false) {
1109+
fopts_len) == false) {
1110+
tr_error("Allowed FRMPayload = %d, FRMPayload = %d, MAC commands pending = %d",
1111+
_lora_phy->get_max_payload(_params.sys_params.channel_data_rate,
1112+
_params.is_repeater_supported),
1113+
_ongoing_tx_msg.f_buffer_size, fopts_len);
10971114
return LORAWAN_STATUS_LENGTH_ERROR;
10981115
}
10991116
_params.rx_window1_delay = _params.sys_params.recv_delay1
@@ -1216,27 +1233,9 @@ int16_t LoRaMac::prepare_ongoing_tx(const uint8_t port,
12161233
uint8_t num_retries)
12171234
{
12181235
_ongoing_tx_msg.port = port;
1219-
1220-
uint8_t max_possible_size = get_max_possible_tx_size(length);
1221-
1222-
if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) {
1223-
max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE;
1224-
}
1225-
1226-
if (max_possible_size < length) {
1227-
tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes",
1228-
length, max_possible_size);
1229-
1230-
_ongoing_tx_msg.pending_size = length - max_possible_size;
1231-
_ongoing_tx_msg.f_buffer_size = max_possible_size;
1232-
memcpy(_ongoing_tx_msg.f_buffer, data, _ongoing_tx_msg.f_buffer_size);
1233-
} else {
1234-
_ongoing_tx_msg.f_buffer_size = length;
1235-
_ongoing_tx_msg.pending_size = 0;
1236-
if (length > 0) {
1237-
memcpy(_ongoing_tx_msg.f_buffer, data, length);
1238-
}
1239-
}
1236+
uint8_t max_possible_size = 0;
1237+
uint8_t fopts_len = _mac_commands.get_mac_cmd_length()
1238+
+ _mac_commands.get_repeat_commands_length();
12401239

12411240
// Handles unconfirmed messages
12421241
if (flags & MSG_UNCONFIRMED_FLAG) {
@@ -1257,6 +1256,30 @@ int16_t LoRaMac::prepare_ongoing_tx(const uint8_t port,
12571256
_ongoing_tx_msg.type = MCPS_PROPRIETARY;
12581257
_ongoing_tx_msg.fport = port;
12591258
_ongoing_tx_msg.nb_trials = 1;
1259+
// a proprietary frame only includes an MHDR field which contains MTYPE field.
1260+
// Everything else is at the discretion of the implementer
1261+
fopts_len = 0;
1262+
}
1263+
1264+
max_possible_size = get_max_possible_tx_size(fopts_len);
1265+
1266+
if (max_possible_size > MBED_CONF_LORA_TX_MAX_SIZE) {
1267+
max_possible_size = MBED_CONF_LORA_TX_MAX_SIZE;
1268+
}
1269+
1270+
if (max_possible_size < length) {
1271+
tr_info("Cannot transmit %d bytes. Possible TX Size is %d bytes",
1272+
length, max_possible_size);
1273+
1274+
_ongoing_tx_msg.pending_size = length - max_possible_size;
1275+
_ongoing_tx_msg.f_buffer_size = max_possible_size;
1276+
memcpy(_ongoing_tx_msg.f_buffer, data, _ongoing_tx_msg.f_buffer_size);
1277+
} else {
1278+
_ongoing_tx_msg.f_buffer_size = length;
1279+
_ongoing_tx_msg.pending_size = 0;
1280+
if (length > 0) {
1281+
memcpy(_ongoing_tx_msg.f_buffer, data, length);
1282+
}
12601283
}
12611284

12621285
tr_info("RTS = %u bytes, PEND = %u, Port: %u",
@@ -1567,8 +1590,10 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
15671590

15681591
_mac_commands.parse_mac_commands_to_repeat();
15691592

1593+
// We always add Port Field. Spec leaves it optional.
1594+
_params.tx_buffer[pkt_header_len++] = frame_port;
1595+
15701596
if ((payload != NULL) && (_params.tx_buffer_len > 0)) {
1571-
_params.tx_buffer[pkt_header_len++] = frame_port;
15721597

15731598
uint8_t *key = _params.keys.app_skey;
15741599
uint32_t key_length = sizeof(_params.keys.app_skey) * 8;
@@ -1759,35 +1784,30 @@ void LoRaMac::disconnect()
17591784
reset_mcps_indication();
17601785
}
17611786

1762-
uint8_t LoRaMac::get_max_possible_tx_size(uint8_t size)
1787+
uint8_t LoRaMac::get_max_possible_tx_size(uint8_t fopts_len)
17631788
{
17641789
uint8_t max_possible_payload_size = 0;
1765-
uint8_t current_payload_size = 0;
1766-
uint8_t fopt_len = _mac_commands.get_mac_cmd_length()
1767-
+ _mac_commands.get_repeat_commands_length();
1790+
uint8_t allowed_frm_payload_size = 0;
17681791

17691792
if (_params.sys_params.adr_on) {
17701793
_lora_phy.get_next_ADR(false, _params.sys_params.channel_data_rate,
17711794
_params.sys_params.channel_tx_power,
17721795
_params.adr_ack_counter);
17731796
}
17741797

1775-
current_payload_size = _lora_phy.get_max_payload(_params.sys_params.channel_data_rate, _params.is_repeater_supported);
1798+
allowed_frm_payload_size = _lora_phy->get_max_payload(_params.sys_params.channel_data_rate,
1799+
_params.is_repeater_supported);
17761800

1777-
if (current_payload_size >= fopt_len) {
1778-
max_possible_payload_size = current_payload_size - fopt_len;
1801+
if (allowed_frm_payload_size >= fopts_len) {
1802+
max_possible_payload_size = allowed_frm_payload_size - fopts_len;
17791803
} else {
1780-
max_possible_payload_size = current_payload_size;
1781-
fopt_len = 0;
1804+
max_possible_payload_size = allowed_frm_payload_size;
1805+
fopts_len = 0;
17821806
_mac_commands.clear_command_buffer();
17831807
_mac_commands.clear_repeat_buffer();
17841808
}
17851809

1786-
if (validate_payload_length(size, _params.sys_params.channel_data_rate,
1787-
fopt_len) == false) {
1788-
return max_possible_payload_size;
1789-
}
1790-
return current_payload_size;
1810+
return max_possible_payload_size;
17911811
}
17921812

17931813
bool LoRaMac::nwk_joined()

features/lorawan/lorastack/mac/LoRaMac.h

Lines changed: 17 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -94,18 +94,18 @@ class LoRaMac {
9494
void disconnect(void);
9595

9696
/**
97-
* @brief Queries the LoRaMAC whether it is possible to send the next frame with
98-
* a given payload size. The LoRaMAC takes the scheduled MAC commands into
99-
* account and returns corresponding value.
97+
* @brief Queries the LoRaMAC the maximum possible FRMPayload size to send.
98+
* The LoRaMAC takes the scheduled MAC commands into account and returns
99+
* corresponding value.
100100
*
101-
* @param size [in] The size of the applicable payload to be sent next.
101+
* @param fopts_len [in] Number of mac commands in the queue pending.
102102
*
103103
* @return Size of the biggest packet that can be sent.
104104
* Please note that if the size of the MAC commands in the queue do
105105
* not fit into the payload size on the related datarate, the LoRaMAC will
106106
* omit the MAC commands.
107107
*/
108-
uint8_t get_max_possible_tx_size(uint8_t size);
108+
uint8_t get_max_possible_tx_size(uint8_t fopts_len);
109109

110110
/**
111111
* @brief nwk_joined Checks if device has joined to network
@@ -324,13 +324,18 @@ class LoRaMac {
324324

325325
/**
326326
* @brief prepare_ongoing_tx This will prepare (and override) ongoing_tx_msg.
327-
* @param port The application port number.
328-
* @param data A pointer to the data being sent. The ownership of the
329-
* buffer is not transferred.
330-
* @param length The size of data in bytes.
331-
* @param flags A flag used to determine what type of
332-
* message is being sent.
333-
* @param num_retries Number of retries for a confirmed type message
327+
* @param port The application port number.
328+
*
329+
* @param data A pointer to the data being sent. The ownership of the
330+
* buffer is not transferred.
331+
*
332+
* @param length The size of data in bytes.
333+
*
334+
* @param flags A flag used to determine what type of
335+
* message is being sent.
336+
*
337+
* @param num_retries Number of retries for a confirmed type message
338+
*
334339
* @return The number of bytes prepared for sending.
335340
*/
336341
int16_t prepare_ongoing_tx(const uint8_t port, const uint8_t *data,

0 commit comments

Comments
 (0)