Skip to content

Commit 9a77b5d

Browse files
author
Hasnain Virk
committed
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 e1df16e commit 9a77b5d

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
@@ -1033,6 +1033,7 @@ lorawan_status_t LoRaMac::schedule_tx()
10331033
{
10341034
channel_selection_params_t next_channel;
10351035
lorawan_time_t backoff_time = 0;
1036+
uint8_t fopts_len = 0;
10361037

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

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

12611284
tr_info("RTS = %u bytes, PEND = %u, Port: %u",
@@ -1566,8 +1589,10 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
15661589

15671590
_mac_commands.parse_mac_commands_to_repeat();
15681591

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

15721597
uint8_t *key = _params.keys.app_skey;
15731598
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
@@ -93,18 +93,18 @@ class LoRaMac {
9393
void disconnect(void);
9494

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

109109
/**
110110
* @brief nwk_joined Checks if device has joined to network
@@ -316,13 +316,18 @@ class LoRaMac {
316316

317317
/**
318318
* @brief prepare_ongoing_tx This will prepare (and override) ongoing_tx_msg.
319-
* @param port The application port number.
320-
* @param data A pointer to the data being sent. The ownership of the
321-
* buffer is not transferred.
322-
* @param length The size of data in bytes.
323-
* @param flags A flag used to determine what type of
324-
* message is being sent.
325-
* @param num_retries Number of retries for a confirmed type message
319+
* @param port The application port number.
320+
*
321+
* @param data A pointer to the data being sent. The ownership of the
322+
* buffer is not transferred.
323+
*
324+
* @param length The size of data in bytes.
325+
*
326+
* @param flags A flag used to determine what type of
327+
* message is being sent.
328+
*
329+
* @param num_retries Number of retries for a confirmed type message
330+
*
326331
* @return The number of bytes prepared for sending.
327332
*/
328333
int16_t prepare_ongoing_tx(const uint8_t port, const uint8_t *data,

0 commit comments

Comments
 (0)