mirror of https://github.com/ARMmbed/mbed-os.git
LoRaWAN 1.1 Features added (Some LoRaPhy impl missing still + some TODOs in code)
- MLME confirm handling refactored - Rejoin handling missing - new CF_LIST mechanism missing (+resets involved) - NVM handling missing Fixed automerge issuefeature-lorawan-1-1
parent
8dc15ee6e1
commit
0d3283e3a0
|
@ -72,6 +72,12 @@ LoRaWANStack::LoRaWANStack()
|
|||
_ctrl_flags(IDLE_FLAG),
|
||||
_app_port(INVALID_PORT),
|
||||
_link_check_requested(false),
|
||||
_reset_ind_requested(false),
|
||||
_rekey_ind_needed(false),
|
||||
_rekey_ind_counter(0),
|
||||
_device_mode_ind_needed(false),
|
||||
_device_mode_ind_ongoing(false),
|
||||
_new_class_type(CLASS_A),
|
||||
_automatic_uplink_ongoing(false),
|
||||
_queue(NULL)
|
||||
{
|
||||
|
@ -295,6 +301,31 @@ int16_t LoRaWANStack::handle_tx(const uint8_t port, const uint8_t *data,
|
|||
|
||||
if (!null_allowed && !data) {
|
||||
return LORAWAN_STATUS_PARAMETER_INVALID;
|
||||
} else if (DEVICE_STATE_NOT_INITIALIZED == _device_current_state) {
|
||||
return LORAWAN_STATUS_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
// ResetInd is only used for ABP devices after connect, until ResetConf is received
|
||||
if (_reset_ind_requested) {
|
||||
set_reset_indication();
|
||||
} else if (_rekey_ind_needed) {
|
||||
if (_rekey_ind_counter < _loramac.get_current_adr_ack_limit()) {
|
||||
set_rekey_indication();
|
||||
_rekey_ind_counter++;
|
||||
} else {
|
||||
//TODO: Check if something else is needed also (reset settings?)
|
||||
_rekey_ind_needed = false;
|
||||
send_event_to_application(JOIN_FAILURE);
|
||||
_device_current_state = DEVICE_STATE_IDLE;
|
||||
}
|
||||
} else if (_link_check_requested) {
|
||||
// add a link check request with normal data, until the application
|
||||
// explicitly removes it.
|
||||
_loramac.setup_link_check_request();
|
||||
}
|
||||
|
||||
if (_device_mode_ind_needed) {
|
||||
set_device_mode_indication();
|
||||
}
|
||||
|
||||
if (!_lw_session.active) {
|
||||
|
@ -430,6 +461,21 @@ lorawan_status_t LoRaWANStack::set_link_check_request()
|
|||
return LORAWAN_STATUS_OK;
|
||||
}
|
||||
|
||||
void LoRaWANStack::set_reset_indication()
|
||||
{
|
||||
_loramac.setup_reset_indication();
|
||||
}
|
||||
|
||||
void LoRaWANStack::set_rekey_indication()
|
||||
{
|
||||
_loramac.setup_rekey_indication();
|
||||
}
|
||||
|
||||
void LoRaWANStack::set_device_mode_indication()
|
||||
{
|
||||
_loramac.setup_device_mode_indication(_new_class_type);
|
||||
}
|
||||
|
||||
void LoRaWANStack::remove_link_check_request()
|
||||
{
|
||||
_link_check_requested = false;
|
||||
|
@ -453,8 +499,18 @@ lorawan_status_t LoRaWANStack::set_device_class(const device_class_t &device_cla
|
|||
if (device_class == CLASS_B) {
|
||||
return LORAWAN_STATUS_UNSUPPORTED;
|
||||
}
|
||||
_loramac.set_device_class(device_class,
|
||||
mbed::callback(this, &LoRaWANStack::post_process_tx_no_reception));
|
||||
// Only change the class when needed
|
||||
if (_loramac.get_device_class() != device_class) {
|
||||
if (_loramac.get_server_type() == LW1_1) {
|
||||
_new_class_type = device_class;
|
||||
set_device_mode_indication();
|
||||
_device_mode_ind_needed = true;
|
||||
_device_mode_ind_ongoing = true;
|
||||
} else {
|
||||
_loramac.set_device_class(device_class, mbed::callback(this, &LoRaWANStack::post_process_tx_no_reception));
|
||||
}
|
||||
|
||||
}
|
||||
return LORAWAN_STATUS_OK;
|
||||
}
|
||||
|
||||
|
@ -565,7 +621,9 @@ void LoRaWANStack::process_transmission_timeout()
|
|||
_loramac.on_radio_tx_timeout();
|
||||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
if (_device_current_state == DEVICE_STATE_JOINING) {
|
||||
mlme_confirm_handler();
|
||||
_device_current_state = DEVICE_STATE_IDLE;
|
||||
tr_error("Joining abandoned: Radio failed to transmit");
|
||||
send_event_to_application(TX_TIMEOUT);
|
||||
} else {
|
||||
state_controller(DEVICE_STATE_STATUS_CHECK);
|
||||
}
|
||||
|
@ -576,6 +634,15 @@ void LoRaWANStack::process_transmission_timeout()
|
|||
void LoRaWANStack::process_transmission(void)
|
||||
{
|
||||
tr_debug("Transmission completed");
|
||||
_loramac.on_radio_tx_done(_tx_timestamp);
|
||||
|
||||
if (_loramac.get_server_type() == LW1_1 && _device_mode_ind_ongoing) {
|
||||
_device_mode_ind_ongoing = false;
|
||||
_loramac.set_device_class(device_class_t(_new_class_type), mbed::callback(this, &LoRaWANStack::post_process_tx_no_reception));
|
||||
send_event_to_application(CLASS_CHANGED);
|
||||
}
|
||||
|
||||
make_tx_metadata_available();
|
||||
|
||||
if (_device_current_state == DEVICE_STATE_JOINING) {
|
||||
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
|
||||
|
@ -701,7 +768,7 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
|
|||
_ctrl_flags &= ~TX_DONE_FLAG;
|
||||
_ctrl_flags &= ~RETRY_EXHAUSTED_FLAG;
|
||||
|
||||
_loramac.on_radio_rx_done(payload, size, rssi, snr);
|
||||
_loramac.on_radio_rx_done(payload, size, rssi, snr, callback(this, &LoRaWANStack::mlme_confirm_handler));
|
||||
|
||||
if (_loramac.get_mlme_confirmation()->pending) {
|
||||
_loramac.post_process_mlme_request();
|
||||
|
@ -712,6 +779,7 @@ void LoRaWANStack::process_reception(const uint8_t *const payload, uint16_t size
|
|||
return;
|
||||
}
|
||||
}
|
||||
make_rx_metadata_available();
|
||||
|
||||
if (!_loramac.nwk_joined()) {
|
||||
core_util_atomic_flag_clear(&_rx_payload_in_use);
|
||||
|
@ -900,6 +968,7 @@ lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa)
|
|||
_lw_session.downlink_counter = 0;
|
||||
_lw_session.uplink_counter = 0;
|
||||
_ctrl_flags |= USING_OTAA_FLAG;
|
||||
//We cannot set _rekey_ind_needed here, because server might not support LW1.1
|
||||
} else {
|
||||
// If current state is SHUTDOWN, device may be trying to re-establish
|
||||
// communication. In case of ABP specification is meddled about frame counters.
|
||||
|
@ -910,6 +979,11 @@ lorawan_status_t LoRaWANStack::handle_connect(bool is_otaa)
|
|||
//_lw_session.downlink_counter; //Get from NVM
|
||||
//_lw_session.uplink_counter; //Get from NVM
|
||||
|
||||
if (MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
|
||||
_reset_ind_requested = true;
|
||||
//TODO: Switch back to default MAC and radio parameters, but leave counters untouched
|
||||
}
|
||||
|
||||
tr_debug("Initiating ABP");
|
||||
tr_debug("Frame Counters. UpCnt=%lu, DownCnt=%lu",
|
||||
_lw_session.uplink_counter, _lw_session.downlink_counter);
|
||||
|
@ -939,27 +1013,37 @@ void LoRaWANStack::mlme_indication_handler()
|
|||
tr_error("Unknown MLME Indication type.");
|
||||
}
|
||||
|
||||
void LoRaWANStack::mlme_confirm_handler()
|
||||
void LoRaWANStack::mlme_confirm_handler(loramac_mlme_confirm_t& mlme_confirm)
|
||||
{
|
||||
if (_loramac.get_mlme_confirmation()->req_type == MLME_LINK_CHECK) {
|
||||
if (_loramac.get_mlme_confirmation()->status
|
||||
== LORAMAC_EVENT_INFO_STATUS_OK) {
|
||||
|
||||
if (mlme_confirm.type == MLME_LINK_CHECK) {
|
||||
if (mlme_confirm.status == LORAMAC_EVENT_INFO_STATUS_OK) {
|
||||
if (_callbacks.link_check_resp) {
|
||||
const int ret = _queue->call(
|
||||
_callbacks.link_check_resp,
|
||||
_loramac.get_mlme_confirmation()->demod_margin,
|
||||
_loramac.get_mlme_confirmation()->nb_gateways);
|
||||
const int ret = _queue->call(_callbacks.link_check_resp,
|
||||
mlme_confirm.demod_margin,
|
||||
mlme_confirm.nb_gateways);
|
||||
MBED_ASSERT(ret != 0);
|
||||
(void) ret;
|
||||
(void)ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_loramac.get_mlme_confirmation()->req_type == MLME_JOIN) {
|
||||
|
||||
switch (_loramac.get_mlme_confirmation()->status) {
|
||||
} else if (mlme_confirm.type == MLME_RESET) {
|
||||
_reset_ind_requested = false;
|
||||
} else if (mlme_confirm.type == MLME_REKEY) {
|
||||
_rekey_ind_needed = false;
|
||||
_rekey_ind_counter = 0;
|
||||
} else if (mlme_confirm.type == MLME_DEVICE_MODE) {
|
||||
_device_mode_ind_needed = false;
|
||||
if (_loramac.get_device_class() == mlme_confirm.classType) {
|
||||
send_event_to_application(SERVER_ACCEPTED_CLASS_IN_USE);
|
||||
} else {
|
||||
send_event_to_application(SERVER_DOES_NOT_SUPPORT_CLASS_IN_USE);
|
||||
}
|
||||
} else if (mlme_confirm.type == MLME_JOIN_ACCEPT) {
|
||||
switch (mlme_confirm.status) {
|
||||
case LORAMAC_EVENT_INFO_STATUS_OK:
|
||||
if (_loramac.get_server_type() == LW1_1) {
|
||||
_rekey_ind_needed = true;
|
||||
_rekey_ind_counter = 0;
|
||||
}
|
||||
state_controller(DEVICE_STATE_CONNECTED);
|
||||
break;
|
||||
|
||||
|
@ -969,19 +1053,13 @@ void LoRaWANStack::mlme_confirm_handler()
|
|||
tr_error("Joining abandoned: CRYPTO_ERROR");
|
||||
send_event_to_application(CRYPTO_ERROR);
|
||||
break;
|
||||
|
||||
case LORAMAC_EVENT_INFO_STATUS_TX_TIMEOUT:
|
||||
// fatal error
|
||||
_device_current_state = DEVICE_STATE_IDLE;
|
||||
tr_error("Joining abandoned: Radio failed to transmit");
|
||||
send_event_to_application(TX_TIMEOUT);
|
||||
break;
|
||||
|
||||
default:
|
||||
// non-fatal, retry if possible
|
||||
_device_current_state = DEVICE_STATE_AWAITING_JOIN_ACCEPT;
|
||||
state_controller(DEVICE_STATE_JOINING);
|
||||
}
|
||||
} else if (mlme_confirm.type == MLME_FORCE_REJOIN) {
|
||||
//TODO: handle this
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -405,6 +405,27 @@ private:
|
|||
*/
|
||||
lorawan_status_t state_controller(device_states_t new_state);
|
||||
|
||||
|
||||
/**
|
||||
* Send Reset indication (only in ABP & LW1.1)
|
||||
* LoRaWAN 1.1 specification mandates ABP device to send
|
||||
* ResetInd MAC command until ResetConf is received.
|
||||
*
|
||||
*/
|
||||
void set_reset_indication();
|
||||
|
||||
/**
|
||||
* Send Rekey indication (only in OTAA & LW1.1)
|
||||
*
|
||||
*/
|
||||
void set_rekey_indication();
|
||||
|
||||
/**
|
||||
* Send Device mode indication (only in OTAA & LW1.1)
|
||||
*
|
||||
*/
|
||||
void set_device_mode_indication();
|
||||
|
||||
/**
|
||||
* Helpers for state controller
|
||||
*/
|
||||
|
@ -426,7 +447,7 @@ private:
|
|||
/**
|
||||
* Handles an MLME confirmation
|
||||
*/
|
||||
void mlme_confirm_handler(void);
|
||||
void mlme_confirm_handler(loramac_mlme_confirm_t& mlme_confirm);
|
||||
|
||||
/**
|
||||
* Handles an MCPS confirmation
|
||||
|
@ -507,6 +528,12 @@ private:
|
|||
uint32_t _ctrl_flags;
|
||||
uint8_t _app_port;
|
||||
bool _link_check_requested;
|
||||
bool _reset_ind_requested;
|
||||
bool _rekey_ind_needed;
|
||||
uint8_t _rekey_ind_counter;
|
||||
bool _device_mode_ind_needed;
|
||||
bool _device_mode_ind_ongoing;
|
||||
uint8_t _new_class_type;
|
||||
bool _automatic_uplink_ongoing;
|
||||
core_util_atomic_flag _rx_payload_in_use;
|
||||
uint8_t _rx_payload[LORAMAC_PHY_MAXPAYLOAD];
|
||||
|
|
|
@ -90,8 +90,13 @@ LoRaMac::LoRaMac()
|
|||
_params.max_ack_timeout_retries = 1;
|
||||
_params.ack_timeout_retry_counter = 1;
|
||||
|
||||
_params.join_request_type = JOIN_REQUEST;
|
||||
|
||||
//TODO: RJcount1 must be stored to NVM!
|
||||
_params.RJcount0 = 0;
|
||||
_params.RJcount1 = 0;
|
||||
|
||||
reset_mcps_confirmation();
|
||||
reset_mlme_confirmation();
|
||||
reset_mcps_indication();
|
||||
}
|
||||
|
||||
|
@ -123,11 +128,6 @@ const loramac_mlme_indication_t *LoRaMac::get_mlme_indication() const
|
|||
return &_mlme_indication;
|
||||
}
|
||||
|
||||
void LoRaMac::post_process_mlme_request()
|
||||
{
|
||||
_mlme_confirmation.pending = false;
|
||||
}
|
||||
|
||||
void LoRaMac::post_process_mcps_req()
|
||||
{
|
||||
_params.is_last_tx_join_request = false;
|
||||
|
@ -178,61 +178,115 @@ rx_slot_t LoRaMac::get_current_slot(void)
|
|||
/**
|
||||
* This part handles incoming frames in response to Radio RX Interrupt
|
||||
*/
|
||||
void LoRaMac::handle_join_accept_frame(const uint8_t *payload, uint16_t size)
|
||||
loramac_event_info_status_t LoRaMac::handle_join_accept_frame(const uint8_t *payload, uint16_t size)
|
||||
{
|
||||
uint32_t mic = 0;
|
||||
uint32_t mic_rx = 0;
|
||||
server_type_t stype = LW1_0_2;
|
||||
|
||||
_mlme_confirmation.nb_retries = _params.join_request_trial_counter;
|
||||
//Store server type to local so that invalid join accept of rejoin request won't affect the orig. type.
|
||||
if ( (((_params.rx_buffer[11] >> 7) & 0x01) == 1) && MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
|
||||
stype = LW1_1;
|
||||
} else {
|
||||
stype = LW1_0_2;
|
||||
//Server does not support LW 1.1 so we need to unset JS keys
|
||||
memcpy(_params.keys.js_intkey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey));
|
||||
memcpy(_params.keys.js_enckey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey));
|
||||
}
|
||||
|
||||
uint8_t *decrypt_key = NULL;
|
||||
uint8_t *mic_key = _params.keys.js_intkey; //in case of LW1.0.2 js_intkey == nwk_key == app_key
|
||||
|
||||
if (_params.join_request_type == JOIN_REQUEST) {
|
||||
decrypt_key = _params.keys.nwk_key;
|
||||
} else {
|
||||
decrypt_key = _params.keys.js_enckey;
|
||||
}
|
||||
|
||||
//Store server type to local so that invalid join accept of rejoin request won't affect the orig. type.
|
||||
if ( (((_params.rx_buffer[11] >> 7) & 0x01) == 1) && MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
|
||||
stype = LW1_1;
|
||||
} else {
|
||||
stype = LW1_0_2;
|
||||
//Server does not support LW 1.1 so we need to unset JS keys
|
||||
memcpy(_params.keys.js_intkey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey));
|
||||
memcpy(_params.keys.js_enckey, _params.keys.nwk_key, sizeof(_params.keys.nwk_skey));
|
||||
}
|
||||
|
||||
if (0 != _lora_crypto.decrypt_join_frame(payload + 1, size - 1,
|
||||
_params.keys.app_key, APPKEY_KEY_LENGTH,
|
||||
decrypt_key, APPKEY_KEY_LENGTH,
|
||||
_params.rx_buffer + 1)) {
|
||||
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
|
||||
return;
|
||||
return LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
_params.rx_buffer[0] = payload[0];
|
||||
uint8_t payload_start = 1;
|
||||
uint8_t mic_start = 0;
|
||||
uint8_t args_size = 0;
|
||||
uint8_t args[16];
|
||||
if (stype == LW1_0_2) {
|
||||
_params.rx_buffer[0] = payload[0];
|
||||
mic_start = size - LORAMAC_MFR_LEN;
|
||||
|
||||
memcpy(args, _params.rx_buffer + 1, 6);
|
||||
memcpy(args + 6, (uint8_t *) &_params.dev_nonce, 2);
|
||||
args_size = 8;
|
||||
} else {
|
||||
//MIC calculation needs more params, so we move the payload a bit
|
||||
_params.rx_buffer[0] = (uint8_t)_params.join_request_type;
|
||||
memcpy(_params.rx_buffer + 11, _params.rx_buffer, size - LORAMAC_MFR_LEN);
|
||||
memcpy(_params.rx_buffer + 1, _params.keys.app_eui, 8);
|
||||
memcpy(_params.rx_buffer + 9, (uint8_t *) &_params.dev_nonce, 2);
|
||||
mic_start = size - LORAMAC_MFR_LEN + 11;
|
||||
payload_start += 11;
|
||||
|
||||
memcpy(args, _params.rx_buffer + payload_start, 3);
|
||||
memcpy(args + 3, _params.keys.app_eui, 8);
|
||||
memcpy(args + 3 + 8, (uint8_t *) &_params.dev_nonce, 2);
|
||||
args_size = 13;
|
||||
}
|
||||
|
||||
if (_lora_crypto.compute_join_frame_mic(_params.rx_buffer,
|
||||
size - LORAMAC_MFR_LEN,
|
||||
_params.keys.app_key,
|
||||
mic_start,
|
||||
mic_key,
|
||||
APPKEY_KEY_LENGTH,
|
||||
&mic) != 0) {
|
||||
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
|
||||
return;
|
||||
return LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
mic_rx |= (uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN];
|
||||
mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 1] << 8);
|
||||
mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 2] << 16);
|
||||
mic_rx |= ((uint32_t) _params.rx_buffer[size - LORAMAC_MFR_LEN + 3] << 24);
|
||||
mic_rx |= (uint32_t) _params.rx_buffer[mic_start];
|
||||
mic_rx |= ((uint32_t) _params.rx_buffer[mic_start + 1] << 8);
|
||||
mic_rx |= ((uint32_t) _params.rx_buffer[mic_start + 2] << 16);
|
||||
mic_rx |= ((uint32_t) _params.rx_buffer[mic_start + 3] << 24);
|
||||
|
||||
if (mic_rx == mic) {
|
||||
_lora_time.stop(_params.timers.rx_window2_timer);
|
||||
if (_lora_crypto.compute_skeys_for_join_frame(_params.keys.app_key,
|
||||
_params.server_type = stype;
|
||||
if (_lora_crypto.compute_skeys_for_join_frame(_params.keys.nwk_key,
|
||||
APPKEY_KEY_LENGTH,
|
||||
_params.rx_buffer + 1,
|
||||
_params.dev_nonce,
|
||||
_params.keys.app_key,
|
||||
APPKEY_KEY_LENGTH,
|
||||
args, args_size,
|
||||
_params.keys.nwk_skey,
|
||||
_params.keys.app_skey) != 0) {
|
||||
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
|
||||
return;
|
||||
_params.keys.app_skey,
|
||||
_params.keys.snwk_sintkey,
|
||||
_params.keys.nwk_senckey,
|
||||
_params.server_type) != 0) {
|
||||
return LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
_params.net_id = (uint32_t) _params.rx_buffer[4];
|
||||
_params.net_id |= ((uint32_t) _params.rx_buffer[5] << 8);
|
||||
_params.net_id |= ((uint32_t) _params.rx_buffer[6] << 16);
|
||||
_params.net_id = (uint32_t) _params.rx_buffer[payload_start + 3];
|
||||
_params.net_id |= ((uint32_t) _params.rx_buffer[payload_start + 4] << 8);
|
||||
_params.net_id |= ((uint32_t) _params.rx_buffer[payload_start + 5] << 16);
|
||||
|
||||
_params.dev_addr = (uint32_t) _params.rx_buffer[7];
|
||||
_params.dev_addr |= ((uint32_t) _params.rx_buffer[8] << 8);
|
||||
_params.dev_addr |= ((uint32_t) _params.rx_buffer[9] << 16);
|
||||
_params.dev_addr |= ((uint32_t) _params.rx_buffer[10] << 24);
|
||||
_params.dev_addr = (uint32_t) _params.rx_buffer[payload_start + 6];
|
||||
_params.dev_addr |= ((uint32_t) _params.rx_buffer[payload_start + 7] << 8);
|
||||
_params.dev_addr |= ((uint32_t) _params.rx_buffer[payload_start + 8] << 16);
|
||||
_params.dev_addr |= ((uint32_t) _params.rx_buffer[payload_start + 9] << 24);
|
||||
|
||||
_params.sys_params.rx1_dr_offset = (_params.rx_buffer[11] >> 4) & 0x07;
|
||||
_params.sys_params.rx2_channel.datarate = _params.rx_buffer[11] & 0x0F;
|
||||
_params.sys_params.rx1_dr_offset = (_params.rx_buffer[payload_start + 10] >> 4) & 0x07;
|
||||
_params.sys_params.rx2_channel.datarate = _params.rx_buffer[payload_start + 10] & 0x0F;
|
||||
|
||||
_params.sys_params.recv_delay1 = (_params.rx_buffer[12] & 0x0F);
|
||||
_params.sys_params.recv_delay1 = (_params.rx_buffer[payload_start + 11] & 0x0F);
|
||||
|
||||
if (_params.sys_params.recv_delay1 == 0) {
|
||||
_params.sys_params.recv_delay1 = 1;
|
||||
|
@ -241,19 +295,22 @@ void LoRaMac::handle_join_accept_frame(const uint8_t *payload, uint16_t size)
|
|||
_params.sys_params.recv_delay1 *= 1000;
|
||||
_params.sys_params.recv_delay2 = _params.sys_params.recv_delay1 + 1000;
|
||||
|
||||
// Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
|
||||
_lora_phy->apply_cf_list(&_params.rx_buffer[13], size - 17);
|
||||
// Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC (== 17)
|
||||
//TODO: join request type is needed here also! See LW1.1 lines 1711 -> 1719 (Reset or not)
|
||||
// LW1.1 CF_LIST's 16th byte is CFListType!
|
||||
_lora_phy->apply_cf_list(&_params.rx_buffer[payload_start + 12], size - 17);
|
||||
|
||||
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
||||
_is_nwk_joined = true;
|
||||
// Node joined successfully
|
||||
_params.ul_frame_counter = 0;
|
||||
_params.ul_nb_rep_counter = 0;
|
||||
_params.adr_ack_counter = 0;
|
||||
|
||||
_params.RJcount0 = 0;
|
||||
} else {
|
||||
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
|
||||
return LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
|
||||
}
|
||||
return LORAMAC_EVENT_INFO_STATUS_OK;
|
||||
}
|
||||
|
||||
void LoRaMac::check_frame_size(uint16_t size)
|
||||
|
@ -269,13 +326,14 @@ void LoRaMac::check_frame_size(uint16_t size)
|
|||
|
||||
bool LoRaMac::message_integrity_check(const uint8_t *const payload,
|
||||
const uint16_t size,
|
||||
uint8_t *const ptr_pos,
|
||||
uint8_t *const ptr_pos, uint16_t confFCnt,
|
||||
uint32_t address,
|
||||
uint32_t *downlink_counter,
|
||||
const uint8_t *nwk_skey)
|
||||
{
|
||||
uint32_t mic = 0;
|
||||
uint32_t mic_rx = 0;
|
||||
uint32_t args = confFCnt;
|
||||
|
||||
uint16_t sequence_counter = 0;
|
||||
uint16_t sequence_counter_prev = 0;
|
||||
|
@ -299,10 +357,9 @@ bool LoRaMac::message_integrity_check(const uint8_t *const payload,
|
|||
return false;
|
||||
}
|
||||
|
||||
// sizeof nws_skey must be the same as _params.keys.nwk_skey,
|
||||
// sizeof nwk_skey must be the same as _params.keys.nwk_skey,
|
||||
_lora_crypto.compute_mic(payload, size - LORAMAC_MFR_LEN,
|
||||
nwk_skey,
|
||||
sizeof(_params.keys.nwk_skey) * 8,
|
||||
nwk_skey, sizeof(_params.keys.nwk_skey) * 8, args,
|
||||
address, DOWN_LINK, *downlink_counter, &mic);
|
||||
|
||||
if (mic_rx != mic) {
|
||||
|
@ -321,7 +378,8 @@ void LoRaMac::extract_data_and_mac_commands(const uint8_t *payload,
|
|||
uint32_t address,
|
||||
uint32_t downlink_counter,
|
||||
int16_t rssi,
|
||||
int8_t snr)
|
||||
int8_t snr,
|
||||
Callback<void(loramac_mlme_confirm_t&)> confirm_handler)
|
||||
{
|
||||
uint8_t frame_len = 0;
|
||||
uint8_t payload_start_index = 8 + fopts_len;
|
||||
|
@ -346,8 +404,8 @@ void LoRaMac::extract_data_and_mac_commands(const uint8_t *payload,
|
|||
}
|
||||
|
||||
if (_mac_commands.process_mac_commands(_params.rx_buffer, 0, frame_len,
|
||||
snr, _mlme_confirmation,
|
||||
_params.sys_params, *_lora_phy)
|
||||
snr, _params.sys_params, *_lora_phy,
|
||||
confirm_handler)
|
||||
!= LORAWAN_STATUS_OK) {
|
||||
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
|
||||
return;
|
||||
|
@ -368,23 +426,8 @@ void LoRaMac::extract_data_and_mac_commands(const uint8_t *payload,
|
|||
return;
|
||||
}
|
||||
|
||||
// normal unicast/multicast port handling
|
||||
if (fopts_len > 0) {
|
||||
// Decode Options field MAC commands. Omit the fPort.
|
||||
if (_mac_commands.process_mac_commands(payload, 8,
|
||||
payload_start_index - 1,
|
||||
snr,
|
||||
_mlme_confirmation,
|
||||
_params.sys_params,
|
||||
*_lora_phy) != LORAWAN_STATUS_OK) {
|
||||
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_mac_commands.has_sticky_mac_cmd()) {
|
||||
set_mlme_schedule_ul_indication();
|
||||
_mac_commands.clear_sticky_mac_cmd();
|
||||
}
|
||||
if(!extract_mac_commands_only(payload, snr, fopts_len, confirm_handler)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// sizeof app_skey must be the same as _params.keys.app_skey
|
||||
|
@ -404,18 +447,34 @@ void LoRaMac::extract_data_and_mac_commands(const uint8_t *payload,
|
|||
}
|
||||
}
|
||||
|
||||
void LoRaMac::extract_mac_commands_only(const uint8_t *payload,
|
||||
bool LoRaMac::extract_mac_commands_only(const uint8_t *payload,
|
||||
int8_t snr,
|
||||
uint8_t fopts_len)
|
||||
uint8_t fopts_len,
|
||||
Callback<void(loramac_mlme_confirm_t&)> confirm_handler)
|
||||
{
|
||||
uint8_t payload_start_index = 8 + fopts_len;
|
||||
if (fopts_len > 0) {
|
||||
if (_mac_commands.process_mac_commands(payload, 8, payload_start_index,
|
||||
snr, _mlme_confirmation,
|
||||
_params.sys_params, *_lora_phy)
|
||||
uint8_t buffer[15];
|
||||
|
||||
if (_params.server_type == LW1_1) {
|
||||
if (0 != _lora_crypto.encrypt_payload(payload + 8, fopts_len,
|
||||
_params.keys.nwk_senckey, sizeof(_params.keys.nwk_senckey) * 8,
|
||||
_params.dev_addr, DOWN_LINK,
|
||||
_params.dl_frame_counter,
|
||||
buffer)) {
|
||||
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_CRYPTO_FAIL;
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
memcpy(buffer, payload + 8, fopts_len);
|
||||
}
|
||||
|
||||
if (_mac_commands.process_mac_commands(buffer, 0, fopts_len,
|
||||
snr, _params.sys_params,
|
||||
*_lora_phy, confirm_handler)
|
||||
|
||||
!= LORAWAN_STATUS_OK) {
|
||||
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_mac_commands.has_sticky_mac_cmd()) {
|
||||
|
@ -423,6 +482,7 @@ void LoRaMac::extract_mac_commands_only(const uint8_t *payload,
|
|||
_mac_commands.clear_sticky_mac_cmd();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
||||
|
@ -430,7 +490,8 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
|||
uint8_t ptr_pos,
|
||||
uint8_t msg_type,
|
||||
int16_t rssi,
|
||||
int8_t snr)
|
||||
int8_t snr,
|
||||
Callback<void(loramac_mlme_confirm_t&)> confirm_handler)
|
||||
{
|
||||
check_frame_size(size);
|
||||
|
||||
|
@ -441,13 +502,19 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
|||
uint32_t downlink_counter = 0;
|
||||
uint8_t app_payload_start_index = 0;
|
||||
uint8_t *nwk_skey = _params.keys.nwk_skey;
|
||||
uint8_t *mic_key = _params.keys.nwk_skey;
|
||||
uint8_t *app_skey = _params.keys.app_skey;
|
||||
uint16_t fport = 0;
|
||||
uint16_t confFCnt = 0;
|
||||
|
||||
address = payload[ptr_pos++];
|
||||
address |= ((uint32_t) payload[ptr_pos++] << 8);
|
||||
address |= ((uint32_t) payload[ptr_pos++] << 16);
|
||||
address |= ((uint32_t) payload[ptr_pos++] << 24);
|
||||
|
||||
fctrl.value = payload[ptr_pos++];
|
||||
fport = payload[7 + fctrl.bits.fopts_len];
|
||||
|
||||
if (address != _params.dev_addr) {
|
||||
// check if Multicast is destined for us
|
||||
cur_multicast_params = _params.multicast_channels;
|
||||
|
@ -456,6 +523,7 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
|||
if (address == cur_multicast_params->address) {
|
||||
is_multicast = true;
|
||||
nwk_skey = cur_multicast_params->nwk_skey;
|
||||
mic_key = cur_multicast_params->nwk_skey;
|
||||
app_skey = cur_multicast_params->app_skey;
|
||||
downlink_counter = cur_multicast_params->dl_frame_counter;
|
||||
break;
|
||||
|
@ -473,16 +541,29 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
|||
} else {
|
||||
is_multicast = false;
|
||||
nwk_skey = _params.keys.nwk_skey;
|
||||
mic_key = _params.keys.snwk_sintkey;
|
||||
app_skey = _params.keys.app_skey;
|
||||
downlink_counter = _params.dl_frame_counter;
|
||||
}
|
||||
|
||||
fctrl.value = payload[ptr_pos++];
|
||||
app_payload_start_index = 8 + fctrl.bits.fopts_len;
|
||||
|
||||
if (_params.server_type == LW1_1) {
|
||||
if (_params.is_node_ack_requested && fctrl.bits.ack) {
|
||||
confFCnt = _mcps_confirmation.ul_frame_counter;
|
||||
}
|
||||
if (!is_multicast) {
|
||||
if (fport != 0) {
|
||||
downlink_counter = _params.app_dl_frame_counter;
|
||||
} else {
|
||||
nwk_skey = _params.keys.nwk_senckey;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//perform MIC check
|
||||
if (!message_integrity_check(payload, size, &ptr_pos, address,
|
||||
&downlink_counter, nwk_skey)) {
|
||||
if (!message_integrity_check(payload, size, &ptr_pos, confFCnt, address,
|
||||
&downlink_counter, mic_key)) {
|
||||
tr_error("MIC failed");
|
||||
_mcps_indication.status = LORAMAC_EVENT_INFO_STATUS_MIC_FAIL;
|
||||
_mcps_indication.pending = false;
|
||||
|
@ -526,6 +607,7 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
|||
} else {
|
||||
if (msg_type == FRAME_TYPE_DATA_CONFIRMED_DOWN) {
|
||||
_params.is_srv_ack_requested = true;
|
||||
_params.counterForAck = downlink_counter;
|
||||
_mcps_indication.type = MCPS_CONFIRMED;
|
||||
|
||||
if ((_params.dl_frame_counter == downlink_counter)
|
||||
|
@ -580,9 +662,10 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
|||
if (frame_len > 0) {
|
||||
extract_data_and_mac_commands(payload, size, fctrl.bits.fopts_len,
|
||||
nwk_skey, app_skey, address,
|
||||
downlink_counter, rssi, snr);
|
||||
downlink_counter, rssi, snr,
|
||||
confirm_handler);
|
||||
} else {
|
||||
extract_mac_commands_only(payload, snr, fctrl.bits.fopts_len);
|
||||
extract_mac_commands_only(payload, snr, fctrl.bits.fopts_len, confirm_handler);
|
||||
}
|
||||
|
||||
// Handle proprietary messages.
|
||||
|
@ -595,7 +678,7 @@ void LoRaMac::handle_data_frame(const uint8_t *const payload,
|
|||
_mcps_indication.buffer_size = size - ptr_pos;
|
||||
}
|
||||
|
||||
// only stop act timer, if the ack is actually recieved
|
||||
// only stop ack timer, if the ack is actually received
|
||||
if (_mcps_confirmation.ack_received) {
|
||||
_lora_time.stop(_params.timers.ack_timeout_timer);
|
||||
}
|
||||
|
@ -673,7 +756,8 @@ void LoRaMac::on_radio_tx_done(lorawan_time_t timestamp)
|
|||
}
|
||||
|
||||
void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size,
|
||||
int16_t rssi, int8_t snr)
|
||||
int16_t rssi, int8_t snr,
|
||||
Callback<void(loramac_mlme_confirm_t&)> confirm_handler)
|
||||
{
|
||||
_demod_ongoing = false;
|
||||
if (_device_class == CLASS_C && !_continuous_rx2_window_open) {
|
||||
|
@ -685,6 +769,7 @@ void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size,
|
|||
}
|
||||
|
||||
loramac_mhdr_t mac_hdr;
|
||||
loramac_mlme_confirm_t mlme;
|
||||
uint8_t pos = 0;
|
||||
mac_hdr.value = payload[pos++];
|
||||
|
||||
|
@ -693,11 +778,14 @@ void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size,
|
|||
case FRAME_TYPE_JOIN_ACCEPT:
|
||||
|
||||
if (nwk_joined()) {
|
||||
_mlme_confirmation.pending = false;
|
||||
//TODO: this might need more logic as with rejoin this will happen more often
|
||||
_params.RJcount0 = 0;
|
||||
return;
|
||||
} else {
|
||||
handle_join_accept_frame(payload, size);
|
||||
_mlme_confirmation.pending = true;
|
||||
loramac_event_info_status_t ret = handle_join_accept_frame(payload, size);
|
||||
mlme.type = MLME_JOIN_ACCEPT;
|
||||
mlme.status = ret;
|
||||
confirm_handler(mlme);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -706,7 +794,7 @@ void LoRaMac::on_radio_rx_done(const uint8_t *const payload, uint16_t size,
|
|||
case FRAME_TYPE_DATA_CONFIRMED_DOWN:
|
||||
case FRAME_TYPE_PROPRIETARY:
|
||||
|
||||
handle_data_frame(payload, size, pos, mac_hdr.bits.mtype, rssi, snr);
|
||||
handle_data_frame(payload, size, pos, mac_hdr.bits.mtype, rssi, snr, confirm_handler);
|
||||
|
||||
break;
|
||||
|
||||
|
@ -823,15 +911,20 @@ lorawan_status_t LoRaMac::send_join_request()
|
|||
_lora_phy->get_alternate_DR(_params.join_request_trial_counter + 1);
|
||||
|
||||
mac_hdr.value = 0;
|
||||
mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ;
|
||||
if (_params.join_request_type == JOIN_REQUEST) {
|
||||
mac_hdr.bits.mtype = FRAME_TYPE_JOIN_REQ;
|
||||
_params.is_last_tx_join_request = true;
|
||||
} else {
|
||||
mac_hdr.bits.mtype = FRAME_TYPE_REJOIN_REQUEST;
|
||||
_params.is_last_tx_join_request = false;
|
||||
}
|
||||
|
||||
fctrl.value = 0;
|
||||
fctrl.bits.adr = _params.sys_params.adr_on;
|
||||
_params.is_last_tx_join_request = true;
|
||||
|
||||
/* In case of join request retransmissions, the stack must prepare
|
||||
* the frame again, because the network server keeps track of the random
|
||||
* LoRaMacDevNonce values to prevent reply attacks. */
|
||||
* LoRaMacDevNonce values to prevent replay attacks. */
|
||||
status = prepare_frame(&mac_hdr, &fctrl, 0, NULL, 0);
|
||||
|
||||
if (status == LORAWAN_STATUS_OK) {
|
||||
|
@ -851,7 +944,8 @@ lorawan_status_t LoRaMac::send_join_request()
|
|||
*/
|
||||
lorawan_status_t LoRaMac::handle_retransmission()
|
||||
{
|
||||
if (!nwk_joined() && (_mlme_confirmation.req_type == MLME_JOIN)) {
|
||||
//TODO: Rejoin requests are not retransmitted (except in case of ForceRejoinReq), in most of the cases server won't respond
|
||||
if (!nwk_joined() && _params.is_last_tx_join_request) {
|
||||
return send_join_request();
|
||||
}
|
||||
|
||||
|
@ -966,7 +1060,7 @@ void LoRaMac::on_ack_timeout_timer_event(void)
|
|||
lorawan_status_t status = handle_retransmission();
|
||||
|
||||
if (status == LORAWAN_STATUS_NO_CHANNEL_FOUND ||
|
||||
status == LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND) {
|
||||
status == LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND) {
|
||||
// In a case when enabled channels are not found, PHY layer
|
||||
// resorts to default channels. Next attempt should go forward as the
|
||||
// default channels are always available if there is a base station in the
|
||||
|
@ -1425,6 +1519,7 @@ void LoRaMac::set_device_class(const device_class_t &device_class,
|
|||
tr_debug("Changing device class to -> CLASS_A");
|
||||
_lora_phy->put_radio_to_sleep();
|
||||
} else if (CLASS_C == _device_class) {
|
||||
tr_debug("Changing device class to -> CLASS_C");
|
||||
_params.is_node_ack_requested = false;
|
||||
_lora_phy->put_radio_to_sleep();
|
||||
_lora_phy->compute_rx_win_params(_params.sys_params.rx2_channel.datarate,
|
||||
|
@ -1441,13 +1536,24 @@ void LoRaMac::set_device_class(const device_class_t &device_class,
|
|||
|
||||
void LoRaMac::setup_link_check_request()
|
||||
{
|
||||
reset_mlme_confirmation();
|
||||
|
||||
_mlme_confirmation.req_type = MLME_LINK_CHECK;
|
||||
_mlme_confirmation.pending = true;
|
||||
_mac_commands.add_link_check_req();
|
||||
}
|
||||
|
||||
void LoRaMac::setup_reset_indication()
|
||||
{
|
||||
_mac_commands.add_reset_ind(1);
|
||||
}
|
||||
|
||||
void LoRaMac::setup_rekey_indication()
|
||||
{
|
||||
_mac_commands.add_rekey_ind(1);
|
||||
}
|
||||
|
||||
void LoRaMac::setup_device_mode_indication(uint8_t classType)
|
||||
{
|
||||
_mac_commands.add_device_mode_indication(classType);
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_otaa)
|
||||
{
|
||||
if (params) {
|
||||
|
@ -1455,19 +1561,30 @@ lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_
|
|||
if ((params->connection_u.otaa.dev_eui == NULL)
|
||||
|| (params->connection_u.otaa.app_eui == NULL)
|
||||
|| (params->connection_u.otaa.app_key == NULL)
|
||||
|| (params->connection_u.otaa.nwk_key == NULL )
|
||||
|| (params->connection_u.otaa.nb_trials == 0)) {
|
||||
return LORAWAN_STATUS_PARAMETER_INVALID;
|
||||
}
|
||||
_params.keys.dev_eui = params->connection_u.otaa.dev_eui;
|
||||
_params.keys.app_eui = params->connection_u.otaa.app_eui;
|
||||
_params.keys.app_key = params->connection_u.otaa.app_key;
|
||||
_params.keys.nwk_key = params->connection_u.otaa.nwk_key;
|
||||
|
||||
if (MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_0_2) {
|
||||
_params.keys.nwk_key = params->connection_u.otaa.app_key;
|
||||
}
|
||||
|
||||
if (0 != _lora_crypto.compute_join_server_keys(_params.keys.nwk_key, APPKEY_KEY_LENGTH, _params.keys.dev_eui,
|
||||
_params.keys.js_intkey, _params.keys.js_enckey)) {
|
||||
return LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
_params.max_join_request_trials = params->connection_u.otaa.nb_trials;
|
||||
|
||||
if (!_lora_phy->verify_nb_join_trials(params->connection_u.otaa.nb_trials)) {
|
||||
// Value not supported, get default
|
||||
_params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS;
|
||||
}
|
||||
// Reset variable JoinRequestTrials
|
||||
|
||||
_params.join_request_trial_counter = 0;
|
||||
|
||||
reset_mac_parameters();
|
||||
|
@ -1482,6 +1599,12 @@ lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_
|
|||
return LORAWAN_STATUS_PARAMETER_INVALID;
|
||||
}
|
||||
|
||||
if (MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1
|
||||
&& ((params->connection_u.abp.snwk_sintkey == NULL)
|
||||
|| (params->connection_u.abp.nwk_senckey == NULL))) {
|
||||
return LORAWAN_STATUS_PARAMETER_INVALID;
|
||||
}
|
||||
|
||||
_params.net_id = params->connection_u.abp.nwk_id;
|
||||
_params.dev_addr = params->connection_u.abp.dev_addr;
|
||||
|
||||
|
@ -1490,18 +1613,47 @@ lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_
|
|||
|
||||
memcpy(_params.keys.app_skey, params->connection_u.abp.app_skey,
|
||||
sizeof(_params.keys.app_skey));
|
||||
|
||||
if (MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
|
||||
memcpy(_params.keys.snwk_sintkey, params->connection_u.abp.snwk_sintkey,
|
||||
sizeof(_params.keys.snwk_sintkey));
|
||||
|
||||
memcpy(_params.keys.nwk_senckey, params->connection_u.abp.nwk_senckey,
|
||||
sizeof(_params.keys.nwk_senckey));
|
||||
|
||||
_params.server_type = LW1_1;
|
||||
} else {
|
||||
memcpy(_params.keys.snwk_sintkey, params->connection_u.abp.nwk_skey,
|
||||
sizeof(_params.keys.snwk_sintkey));
|
||||
|
||||
memcpy(_params.keys.nwk_senckey, params->connection_u.abp.nwk_skey,
|
||||
sizeof(_params.keys.nwk_senckey));
|
||||
|
||||
_params.server_type = LW1_0_2;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
#if MBED_CONF_LORA_OVER_THE_AIR_ACTIVATION
|
||||
const static uint8_t dev_eui[] = MBED_CONF_LORA_DEVICE_EUI;
|
||||
const static uint8_t app_eui[] = MBED_CONF_LORA_APPLICATION_EUI;
|
||||
const static uint8_t app_key[] = MBED_CONF_LORA_APPLICATION_KEY;
|
||||
const static uint8_t nwk_key[] = MBED_CONF_LORA_NETWORK_KEY;
|
||||
|
||||
_params.keys.app_eui = const_cast<uint8_t *>(app_eui);
|
||||
_params.keys.dev_eui = const_cast<uint8_t *>(dev_eui);
|
||||
_params.keys.app_key = const_cast<uint8_t *>(app_key);
|
||||
_params.keys.nwk_key = const_cast<uint8_t *>(nwk_key);
|
||||
_params.max_join_request_trials = MBED_CONF_LORA_NB_TRIALS;
|
||||
|
||||
if( MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_0_2 ) {
|
||||
_params.keys.nwk_key = _params.keys.app_key;
|
||||
}
|
||||
|
||||
if (0 != _lora_crypto.compute_join_server_keys(_params.keys.nwk_key, APPKEY_KEY_LENGTH, _params.keys.dev_eui,
|
||||
_params.keys.js_intkey, _params.keys.js_enckey)) {
|
||||
return LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
// Reset variable JoinRequestTrials
|
||||
_params.join_request_trial_counter = 0;
|
||||
|
||||
|
@ -1513,13 +1665,23 @@ lorawan_status_t LoRaMac::prepare_join(const lorawan_connect_t *params, bool is_
|
|||
#else
|
||||
const static uint8_t nwk_skey[] = MBED_CONF_LORA_NWKSKEY;
|
||||
const static uint8_t app_skey[] = MBED_CONF_LORA_APPSKEY;
|
||||
const static uint8_t snwk_sintkey[] = MBED_CONF_LORA_SNWKSINTKEY;
|
||||
const static uint8_t nwk_senckey[] = MBED_CONF_LORA_NWKSENCKEY;
|
||||
|
||||
_params.net_id = (MBED_CONF_LORA_DEVICE_ADDRESS & LORAWAN_NETWORK_ID_MASK) >> 25;
|
||||
_params.dev_addr = MBED_CONF_LORA_DEVICE_ADDRESS;
|
||||
|
||||
memcpy(_params.keys.nwk_skey, nwk_skey, sizeof(_params.keys.nwk_skey));
|
||||
|
||||
memcpy(_params.keys.app_skey, app_skey, sizeof(_params.keys.app_skey));
|
||||
if (MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_1) {
|
||||
memcpy(_params.keys.snwk_sintkey, snwk_sintkey, sizeof(_params.keys.snwk_sintkey));
|
||||
memcpy(_params.keys.nwk_senckey, nwk_senckey, sizeof(_params.keys.nwk_senckey));
|
||||
_params.server_type = LW1_1;
|
||||
} else {
|
||||
memcpy(_params.keys.snwk_sintkey, nwk_skey, sizeof(_params.keys.snwk_sintkey));
|
||||
memcpy(_params.keys.nwk_senckey, nwk_skey, sizeof(_params.keys.nwk_senckey));
|
||||
_params.server_type = LW1_0_2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1533,8 +1695,14 @@ lorawan_status_t LoRaMac::join(bool is_otaa)
|
|||
return LORAWAN_STATUS_OK;
|
||||
}
|
||||
|
||||
reset_mlme_confirmation();
|
||||
_mlme_confirmation.req_type = MLME_JOIN;
|
||||
_params.join_request_type = JOIN_REQUEST;
|
||||
|
||||
return send_join_request();
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMac::rejoin(join_req_type_t rejoin_type)
|
||||
{
|
||||
_params.join_request_type = rejoin_type;
|
||||
|
||||
return send_join_request();
|
||||
}
|
||||
|
@ -1558,9 +1726,11 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
uint16_t i;
|
||||
uint8_t pkt_header_len = 0;
|
||||
uint32_t mic = 0;
|
||||
uint32_t mic2 = 0;
|
||||
const void *payload = fbuffer;
|
||||
uint8_t frame_port = fport;
|
||||
lorawan_status_t status = LORAWAN_STATUS_OK;
|
||||
uint32_t args = 0;
|
||||
|
||||
_params.tx_buffer_len = 0;
|
||||
|
||||
|
@ -1593,7 +1763,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
|
||||
if (0 != _lora_crypto.compute_join_frame_mic(_params.tx_buffer,
|
||||
_params.tx_buffer_len & 0xFF,
|
||||
_params.keys.app_key,
|
||||
_params.keys.nwk_key,
|
||||
APPKEY_KEY_LENGTH,
|
||||
&mic)) {
|
||||
return LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
|
@ -1604,6 +1774,45 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
_params.tx_buffer[_params.tx_buffer_len++] = (mic >> 16) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (mic >> 24) & 0xFF;
|
||||
|
||||
break;
|
||||
case FRAME_TYPE_REJOIN_REQUEST:
|
||||
_params.tx_buffer_len = pkt_header_len;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (uint8_t)_params.join_request_type;
|
||||
|
||||
if (_params.join_request_type == REJOIN_REQUEST_TYPE0 || _params.join_request_type == REJOIN_REQUEST_TYPE2) {
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = _params.net_id & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (_params.net_id >> 8) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (_params.net_id >> 16) & 0xFF;
|
||||
|
||||
memcpy_convert_endianess(_params.tx_buffer + _params.tx_buffer_len,
|
||||
_params.keys.dev_eui, 8);
|
||||
_params.tx_buffer_len += 8;
|
||||
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = _params.RJcount0 & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (_params.RJcount0 >> 8) & 0xFF;
|
||||
} else { //_params.join_request_type == REJOIN_REQUEST_TYPE1
|
||||
memcpy_convert_endianess(_params.tx_buffer + _params.tx_buffer_len,
|
||||
_params.keys.app_eui, 8);
|
||||
_params.tx_buffer_len += 8;
|
||||
memcpy_convert_endianess(_params.tx_buffer + _params.tx_buffer_len,
|
||||
_params.keys.dev_eui, 8);
|
||||
_params.tx_buffer_len += 8;
|
||||
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = _params.RJcount1 & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (_params.RJcount1 >> 8) & 0xFF;
|
||||
}
|
||||
if (0 != _lora_crypto.compute_join_frame_mic(_params.tx_buffer,
|
||||
_params.tx_buffer_len & 0xFF,
|
||||
_params.keys.snwk_sintkey,
|
||||
APPKEY_KEY_LENGTH,
|
||||
&mic)) {
|
||||
return LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = mic & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (mic >> 8) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (mic >> 16) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len++] = (mic >> 24) & 0xFF;
|
||||
|
||||
break;
|
||||
case FRAME_TYPE_DATA_CONFIRMED_UP:
|
||||
_params.is_node_ack_requested = true;
|
||||
|
@ -1643,6 +1852,7 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
const uint8_t mac_commands_len = _mac_commands.get_mac_cmd_length();
|
||||
|
||||
if ((payload != NULL) && (_params.tx_buffer_len > 0)) {
|
||||
|
||||
if (mac_commands_len <= LORA_MAC_COMMAND_MAX_FOPTS_LENGTH) {
|
||||
fctrl->bits.fopts_len += mac_commands_len;
|
||||
|
||||
|
@ -1650,8 +1860,20 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
_params.tx_buffer[0x05] = fctrl->value;
|
||||
|
||||
const uint8_t *buffer = _mac_commands.get_mac_commands_buffer();
|
||||
for (i = 0; i < mac_commands_len; i++) {
|
||||
_params.tx_buffer[pkt_header_len++] = buffer[i];
|
||||
if (_params.server_type == LW1_1) {
|
||||
if (0 != _lora_crypto.encrypt_payload(buffer, mac_commands_len,
|
||||
_params.keys.nwk_senckey,
|
||||
sizeof(_params.keys.nwk_senckey) * 8,
|
||||
_params.dev_addr, UP_LINK,
|
||||
_params.ul_frame_counter,
|
||||
&_params.tx_buffer[pkt_header_len])) {
|
||||
status = LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
pkt_header_len += mac_commands_len;
|
||||
} else {
|
||||
for (i = 0; i < mac_commands_len; i++) {
|
||||
_params.tx_buffer[pkt_header_len++] = buffer[i];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_params.tx_buffer_len = mac_commands_len;
|
||||
|
@ -1659,11 +1881,9 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
frame_port = 0;
|
||||
}
|
||||
} else {
|
||||
if (mac_commands_len > 0) {
|
||||
_params.tx_buffer_len = mac_commands_len;
|
||||
payload = _mac_commands.get_mac_commands_buffer();
|
||||
frame_port = 0;
|
||||
}
|
||||
_params.tx_buffer_len = mac_commands_len;
|
||||
payload = _mac_commands.get_mac_commands_buffer();
|
||||
frame_port = 0;
|
||||
}
|
||||
|
||||
_mac_commands.parse_mac_commands_to_repeat();
|
||||
|
@ -1676,10 +1896,11 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
uint8_t *key = _params.keys.app_skey;
|
||||
uint32_t key_length = sizeof(_params.keys.app_skey) * 8;
|
||||
if (frame_port == 0) {
|
||||
key = _params.keys.nwk_skey;
|
||||
key_length = sizeof(_params.keys.nwk_skey) * 8;
|
||||
key = _params.keys.nwk_senckey;
|
||||
key_length = sizeof(_params.keys.nwk_senckey) * 8;
|
||||
}
|
||||
if (0 != _lora_crypto.encrypt_payload((uint8_t *) payload, _params.tx_buffer_len,
|
||||
if (0 != _lora_crypto.encrypt_payload((uint8_t *) payload,
|
||||
_params.tx_buffer_len,
|
||||
key, key_length,
|
||||
_params.dev_addr, UP_LINK,
|
||||
_params.ul_frame_counter,
|
||||
|
@ -1691,16 +1912,38 @@ lorawan_status_t LoRaMac::prepare_frame(loramac_mhdr_t *machdr,
|
|||
_params.tx_buffer_len = pkt_header_len + _params.tx_buffer_len;
|
||||
|
||||
if (0 != _lora_crypto.compute_mic(_params.tx_buffer, _params.tx_buffer_len,
|
||||
_params.keys.nwk_skey, sizeof(_params.keys.nwk_skey) * 8,
|
||||
_params.dev_addr,
|
||||
_params.keys.nwk_skey,
|
||||
sizeof(_params.keys.nwk_skey) * 8,
|
||||
args, _params.dev_addr,
|
||||
UP_LINK, _params.ul_frame_counter, &mic)) {
|
||||
status = LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
_params.tx_buffer[_params.tx_buffer_len + 0] = mic & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 1] = (mic >> 8) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 2] = (mic >> 16) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 3] = (mic >> 24) & 0xFF;
|
||||
if (_params.server_type == LW1_1) {
|
||||
if (_params.is_srv_ack_requested) {
|
||||
args = _params.counterForAck;
|
||||
}
|
||||
args |= _params.sys_params.channel_data_rate << 16;
|
||||
args |= _params.channel << 24;
|
||||
|
||||
if (0 != _lora_crypto.compute_mic(_params.tx_buffer, _params.tx_buffer_len,
|
||||
_params.keys.snwk_sintkey,
|
||||
sizeof(_params.keys.snwk_sintkey) * 8,
|
||||
args, _params.dev_addr,
|
||||
UP_LINK, _params.ul_frame_counter, &mic2)) {
|
||||
status = LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
_params.tx_buffer[_params.tx_buffer_len + 0] = mic2 & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 1] = (mic2 >> 8) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 2] = mic & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 3] = (mic >> 8) & 0xFF;
|
||||
} else {
|
||||
_params.tx_buffer[_params.tx_buffer_len + 0] = mic & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 1] = (mic >> 8) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 2] = (mic >> 16) & 0xFF;
|
||||
_params.tx_buffer[_params.tx_buffer_len + 3] = (mic >> 24) & 0xFF;
|
||||
}
|
||||
|
||||
_params.tx_buffer_len += LORAMAC_MFR_LEN;
|
||||
}
|
||||
|
@ -1743,7 +1986,6 @@ lorawan_status_t LoRaMac::send_frame_on_channel(uint8_t channel)
|
|||
_mcps_confirmation.channel = channel;
|
||||
|
||||
_mcps_confirmation.tx_toa = _params.timers.tx_toa;
|
||||
_mlme_confirmation.tx_toa = _params.timers.tx_toa;
|
||||
|
||||
if (!_is_nwk_joined) {
|
||||
_params.join_request_trial_counter++;
|
||||
|
@ -1760,12 +2002,6 @@ void LoRaMac::reset_mcps_confirmation()
|
|||
_mcps_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
|
||||
}
|
||||
|
||||
void LoRaMac::reset_mlme_confirmation()
|
||||
{
|
||||
memset((uint8_t *) &_mlme_confirmation, 0, sizeof(_mlme_confirmation));
|
||||
_mlme_confirmation.status = LORAMAC_EVENT_INFO_STATUS_ERROR;
|
||||
}
|
||||
|
||||
void LoRaMac::reset_mcps_indication()
|
||||
{
|
||||
memset((uint8_t *) &_mcps_indication, 0, sizeof(_mcps_indication));
|
||||
|
@ -1841,7 +2077,6 @@ void LoRaMac::disconnect()
|
|||
_mac_commands.clear_repeat_buffer();
|
||||
|
||||
reset_mcps_confirmation();
|
||||
reset_mlme_confirmation();
|
||||
reset_mcps_indication();
|
||||
}
|
||||
|
||||
|
@ -1989,3 +2224,12 @@ uint8_t LoRaMac::get_prev_QOS_level()
|
|||
return _prev_qos_level;
|
||||
}
|
||||
|
||||
server_type_t LoRaMac::get_server_type()
|
||||
{
|
||||
return _params.server_type;
|
||||
}
|
||||
|
||||
uint8_t LoRaMac::get_current_adr_ack_limit()
|
||||
{
|
||||
return _lora_phy->get_adr_ack_limit();
|
||||
}
|
||||
|
|
|
@ -310,6 +310,30 @@ public:
|
|||
*/
|
||||
void setup_link_check_request();
|
||||
|
||||
/**
|
||||
* @brief setup_reset_indication Adds reset indication command
|
||||
* to be put on next uplink message
|
||||
*/
|
||||
void setup_reset_indication();
|
||||
|
||||
/**
|
||||
* @brief setup_rekey_indication Adds rekey indication command
|
||||
* to be put on next uplink message
|
||||
*/
|
||||
void setup_rekey_indication();
|
||||
|
||||
/**
|
||||
* @brief setup_device_mode_indication Adds Device mode indication command
|
||||
* to be put on next uplink message
|
||||
*/
|
||||
void setup_device_mode_indication(uint8_t classType);
|
||||
|
||||
/**
|
||||
* @brief get_server_type Gets the server's type (Supported LoRaWAN spec version)
|
||||
* @return Server type
|
||||
*/
|
||||
server_type_t get_server_type();
|
||||
|
||||
/**
|
||||
* @brief prepare_join prepares arguments to be ready for join() call.
|
||||
* @param params Join parameters to use, if NULL, the default will be used.
|
||||
|
@ -326,6 +350,13 @@ public:
|
|||
*/
|
||||
lorawan_status_t join(bool is_otaa);
|
||||
|
||||
/**
|
||||
* @brief rejoin Rejoins the network
|
||||
* @param rejoin_type Rejoin type indicates the rejoin message payload
|
||||
* @return LORAWAN_STATUS_OK or a negative error code on failure.
|
||||
*/
|
||||
lorawan_status_t rejoin(join_req_type_t rejoin_type);
|
||||
|
||||
/**
|
||||
* MAC operations upon successful transmission
|
||||
*/
|
||||
|
@ -335,7 +366,8 @@ public:
|
|||
* MAC operations upon reception
|
||||
*/
|
||||
void on_radio_rx_done(const uint8_t *const payload, uint16_t size,
|
||||
int16_t rssi, int8_t snr);
|
||||
int16_t rssi, int8_t snr,
|
||||
mbed::Callback<void(loramac_mlme_confirm_t&)> confirm_handler);
|
||||
|
||||
/**
|
||||
* MAC operations upon transmission timeout
|
||||
|
@ -379,7 +411,6 @@ public:
|
|||
*/
|
||||
void post_process_mcps_req(void);
|
||||
void post_process_mcps_ind(void);
|
||||
void post_process_mlme_request(void);
|
||||
void post_process_mlme_ind(void);
|
||||
|
||||
/**
|
||||
|
@ -408,6 +439,8 @@ public:
|
|||
*/
|
||||
rx_slot_t get_current_slot(void);
|
||||
|
||||
uint8_t get_current_adr_ack_limit();
|
||||
|
||||
/**
|
||||
* Indicates what level of QOS is set by network server. QOS level is set
|
||||
* in response to a LinkADRReq for UNCONFIRMED messages
|
||||
|
@ -472,13 +505,14 @@ private:
|
|||
/**
|
||||
* Handles a Join Accept frame
|
||||
*/
|
||||
void handle_join_accept_frame(const uint8_t *payload, uint16_t size);
|
||||
loramac_event_info_status_t handle_join_accept_frame(const uint8_t *payload, uint16_t size);
|
||||
|
||||
/**
|
||||
* Handles data frames
|
||||
*/
|
||||
void handle_data_frame(const uint8_t *payload, uint16_t size, uint8_t ptr_pos,
|
||||
uint8_t msg_type, int16_t rssi, int8_t snr);
|
||||
uint8_t msg_type, int16_t rssi, int8_t snr,
|
||||
mbed::Callback<void(loramac_mlme_confirm_t&)> confirm_handler);
|
||||
|
||||
/**
|
||||
* Send a Join Request
|
||||
|
@ -499,7 +533,7 @@ private:
|
|||
* Performs MIC
|
||||
*/
|
||||
bool message_integrity_check(const uint8_t *payload, uint16_t size,
|
||||
uint8_t *ptr_pos, uint32_t address,
|
||||
uint8_t *ptr_pos, uint16_t confFCnt, uint32_t address,
|
||||
uint32_t *downlink_counter, const uint8_t *nwk_skey);
|
||||
|
||||
/**
|
||||
|
@ -510,12 +544,15 @@ private:
|
|||
uint8_t fopts_len, uint8_t *nwk_skey,
|
||||
uint8_t *app_skey, uint32_t address,
|
||||
uint32_t downlink_frame_counter,
|
||||
int16_t rssi, int8_t snr);
|
||||
int16_t rssi, int8_t snr,
|
||||
mbed::Callback<void(loramac_mlme_confirm_t&)> confirm_handler);
|
||||
/**
|
||||
* Decrypts and extracts MAC commands from the received encrypted
|
||||
* payload if there is no data
|
||||
* @return True if successful, false otherwise
|
||||
*/
|
||||
void extract_mac_commands_only(const uint8_t *payload, int8_t snr, uint8_t fopts_len);
|
||||
bool extract_mac_commands_only(const uint8_t *payload, int8_t snr, uint8_t fopts_len,
|
||||
mbed::Callback<void(loramac_mlme_confirm_t&)> confirm_handler);
|
||||
|
||||
/**
|
||||
* Callback function to be executed when the DC backoff timer expires
|
||||
|
|
|
@ -29,6 +29,8 @@ SPDX-License-Identifier: BSD-3-Clause
|
|||
#include "mbed-trace/mbed_trace.h"
|
||||
#define TRACE_GROUP "LMACC"
|
||||
|
||||
using namespace mbed;
|
||||
|
||||
/**
|
||||
* LoRaMAC max EIRP (dBm) table.
|
||||
*/
|
||||
|
@ -77,7 +79,6 @@ void LoRaMacCommand::parse_mac_commands_to_repeat()
|
|||
mac_cmd_buffer_to_repeat[cmd_cnt++] = mac_cmd_buffer[i];
|
||||
break;
|
||||
}
|
||||
|
||||
// NON-STICKY
|
||||
case MOTE_MAC_DEV_STATUS_ANS: { // 2 bytes payload
|
||||
i += 2;
|
||||
|
@ -130,9 +131,9 @@ bool LoRaMacCommand::has_sticky_mac_cmd() const
|
|||
|
||||
lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, uint8_t mac_index,
|
||||
uint8_t commands_size, uint8_t snr,
|
||||
loramac_mlme_confirm_t &mlme_conf,
|
||||
lora_mac_system_params_t &mac_sys_params,
|
||||
LoRaPHY &lora_phy)
|
||||
LoRaPHY &lora_phy,
|
||||
Callback<void(loramac_mlme_confirm_t&)> confirm_handler)
|
||||
{
|
||||
uint8_t status = 0;
|
||||
lorawan_status_t ret_value = LORAWAN_STATUS_OK;
|
||||
|
@ -140,10 +141,20 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, ui
|
|||
while (mac_index < commands_size) {
|
||||
// Decode Frame MAC commands
|
||||
switch (payload[mac_index++]) {
|
||||
case SRV_MAC_LINK_CHECK_ANS:
|
||||
case SRV_MAC_RESET_CONF: {
|
||||
loramac_mlme_confirm_t mlme_conf;
|
||||
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
||||
mlme_conf.version = payload[mac_index++] & 0x0F;
|
||||
confirm_handler(mlme_conf);
|
||||
}
|
||||
break;
|
||||
case SRV_MAC_LINK_CHECK_ANS: {
|
||||
loramac_mlme_confirm_t mlme_conf;
|
||||
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
||||
mlme_conf.demod_margin = payload[mac_index++];
|
||||
mlme_conf.nb_gateways = payload[mac_index++];
|
||||
confirm_handler(mlme_conf);
|
||||
}
|
||||
break;
|
||||
case SRV_MAC_LINK_ADR_REQ: {
|
||||
adr_req_params_t link_adr_req;
|
||||
|
@ -291,7 +302,75 @@ lorawan_status_t LoRaMacCommand::process_mac_commands(const uint8_t *payload, ui
|
|||
|
||||
ret_value = add_dl_channel_ans(status);
|
||||
}
|
||||
break;
|
||||
break;
|
||||
case SRV_MAC_REKEY_CONF: {
|
||||
loramac_mlme_confirm_t mlme_conf;
|
||||
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
||||
mlme_conf.version = payload[mac_index++] & 0x0F;
|
||||
confirm_handler(mlme_conf);
|
||||
}
|
||||
break;
|
||||
case SRV_MAC_ADR_PARAM_SETUP_REQ: {
|
||||
uint16_t limit = 1;
|
||||
uint16_t delay = 1;
|
||||
uint8_t adrParam = payload[mac_index++];
|
||||
delay = delay << (adrParam & 0x0f);
|
||||
limit = limit << (adrParam >> 4 & 0x0f);
|
||||
lora_phy.set_adr_ack_limit(limit);
|
||||
lora_phy.set_adr_ack_delay(delay);
|
||||
ret_value = add_adr_param_setup_ans();
|
||||
}
|
||||
break;
|
||||
case SRV_MAC_DEVICE_TIME_ANS: {
|
||||
uint32_t secs = (uint32_t) payload[mac_index++];
|
||||
secs |= (uint32_t) payload[mac_index++] << 8;
|
||||
secs |= (uint32_t) payload[mac_index++] << 16;
|
||||
secs |= (uint32_t) payload[mac_index++] << 24;
|
||||
uint32_t millis = ((uint32_t) payload[mac_index++] * 1000) >> 8;
|
||||
|
||||
lora_phy.time_received(secs, millis);
|
||||
}
|
||||
break;
|
||||
case SRV_MAC_FORCE_REJOIN_REQ: {
|
||||
loramac_mlme_confirm_t mlme_conf;
|
||||
uint8_t data = payload[mac_index++];
|
||||
uint8_t max_retries = data & 0x07;
|
||||
uint8_t period = (data >> 3) & 0x07;
|
||||
data = payload[mac_index++];
|
||||
uint8_t datarate = data & 0x0F;
|
||||
uint8_t rejoin_type = (data >> 4) & 0x07;
|
||||
|
||||
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
||||
mlme_conf.type = MLME_FORCE_REJOIN;
|
||||
mlme_conf.max_retries = max_retries;
|
||||
mlme_conf.period = period;
|
||||
mlme_conf.datarate = datarate;
|
||||
mlme_conf.rejoin_type = rejoin_type;
|
||||
confirm_handler(mlme_conf);
|
||||
|
||||
}
|
||||
break;
|
||||
case SRV_MAC_REJOIN_PARAM_SETUP_REQ: {
|
||||
uint8_t data = payload[mac_index++];
|
||||
uint8_t count = (data & 0x0F) + 4;
|
||||
uint8_t time = ((data >> 4) & 0x0F) + 10;
|
||||
|
||||
uint32_t max_count = 1 << count;
|
||||
uint32_t max_time = 1 << time;
|
||||
|
||||
uint8_t time_available = lora_phy.update_rejoin_params(max_time, max_count);
|
||||
add_rejoin_param_setup_ans(time_available);
|
||||
}
|
||||
break;
|
||||
case SRV_MAC_DEVICE_MODE_CONF: {
|
||||
loramac_mlme_confirm_t mlme_conf;
|
||||
uint8_t classType = payload[mac_index++];
|
||||
mlme_conf.classType = classType;
|
||||
mlme_conf.status = LORAMAC_EVENT_INFO_STATUS_OK;
|
||||
mlme_conf.type = MLME_DEVICE_MODE;
|
||||
confirm_handler(mlme_conf);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// Unknown command. ABORT MAC commands processing
|
||||
tr_error("Invalid MAC command (0x%X)!", payload[mac_index]);
|
||||
|
@ -323,6 +402,53 @@ lorawan_status_t LoRaMacCommand::add_link_check_req()
|
|||
return ret;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMacCommand::add_reset_ind(uint8_t version)
|
||||
{
|
||||
lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR;
|
||||
if (cmd_buffer_remaining() > 0) {
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_RESET_IND;
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = version & 0x0F;
|
||||
ret = LORAWAN_STATUS_OK;
|
||||
mac_cmd_in_next_tx = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMacCommand::add_rekey_ind(uint8_t version)
|
||||
{
|
||||
lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR;
|
||||
if (cmd_buffer_remaining() > 0) {
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_REKEY_IND;
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = version & 0x0F;
|
||||
ret = LORAWAN_STATUS_OK;
|
||||
mac_cmd_in_next_tx = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMacCommand::add_device_mode_indication(uint8_t classType)
|
||||
{
|
||||
lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR;
|
||||
if (cmd_buffer_remaining() > 0) {
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_DEVICE_MODE_IND;
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = classType;
|
||||
ret = LORAWAN_STATUS_OK;
|
||||
mac_cmd_in_next_tx = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMacCommand::add_device_time_req()
|
||||
{
|
||||
lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR;
|
||||
if (cmd_buffer_remaining() > 0) {
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_DEVICE_TIME_REQ;
|
||||
ret = LORAWAN_STATUS_OK;
|
||||
mac_cmd_in_next_tx = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMacCommand::add_link_adr_ans(uint8_t status)
|
||||
{
|
||||
lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR;
|
||||
|
@ -422,3 +548,22 @@ lorawan_status_t LoRaMacCommand::add_dl_channel_ans(uint8_t status)
|
|||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMacCommand::add_adr_param_setup_ans()
|
||||
{
|
||||
lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR;
|
||||
if (cmd_buffer_remaining() > 0) {
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_ADR_PARAM_SETUP_ANS;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
lorawan_status_t LoRaMacCommand::add_rejoin_param_setup_ans(uint8_t status)
|
||||
{
|
||||
lorawan_status_t ret = LORAWAN_STATUS_LENGTH_ERROR;
|
||||
if (cmd_buffer_remaining() > 0) {
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = MOTE_MAC_REJOIN_PARAM_SETUP_ANS;
|
||||
mac_cmd_buffer[mac_cmd_buf_idx++] = status & 0x01;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -119,9 +119,9 @@ public:
|
|||
*/
|
||||
lorawan_status_t process_mac_commands(const uint8_t *payload, uint8_t mac_index,
|
||||
uint8_t commands_size, uint8_t snr,
|
||||
loramac_mlme_confirm_t &mlme_conf,
|
||||
lora_mac_system_params_t &mac_params,
|
||||
LoRaPHY &lora_phy);
|
||||
lora_mac_system_params_t& mac_params,
|
||||
LoRaPHY& lora_phy,
|
||||
mbed::Callback<void(loramac_mlme_confirm_t&)> confirm_handler);
|
||||
|
||||
/**
|
||||
* @brief Adds a new LinkCheckReq MAC command to be sent.
|
||||
|
@ -131,6 +131,40 @@ public:
|
|||
*/
|
||||
lorawan_status_t add_link_check_req();
|
||||
|
||||
/**
|
||||
* @brief add_reset_ind Adds a ResetInd MAC command to be sent.
|
||||
*
|
||||
* @param version LoRaWAN version of the stack
|
||||
* @return status Function status: LORAWAN_STATUS_OK: OK,
|
||||
* LORAWAN_STATUS_LENGTH_ERROR: Buffer full
|
||||
*/
|
||||
lorawan_status_t add_reset_ind(uint8_t version);
|
||||
|
||||
/**
|
||||
* @brief add_rekey_ind Adds a RekeyInd MAC command to be sent.
|
||||
*
|
||||
* @param version LoRaWAN version of the stack
|
||||
* @return status Function status: LORAWAN_STATUS_OK: OK,
|
||||
* LORAWAN_STATUS_LENGTH_ERROR: Buffer full
|
||||
*/
|
||||
lorawan_status_t add_rekey_ind(uint8_t version);
|
||||
|
||||
/**
|
||||
* @brief add_device_mode_indication Adds a DeviceModeInd MAC command to be sent.
|
||||
* @param classType Class type that is used from now on
|
||||
* @return status Function status: LORAWAN_STATUS_OK: OK,
|
||||
* LORAWAN_STATUS_LENGTH_ERROR: Buffer full
|
||||
*/
|
||||
lorawan_status_t add_device_mode_indication(uint8_t classType);
|
||||
|
||||
/**
|
||||
* @brief add_device_time_req Adds DeviceTimeReq MAC command to be sent.
|
||||
* Requests server's current time
|
||||
* @return status Function status: LORAWAN_STATUS_OK: OK,
|
||||
* LORAWAN_STATUS_LENGTH_ERROR: Buffer full
|
||||
*/
|
||||
lorawan_status_t add_device_time_req();
|
||||
|
||||
/**
|
||||
* @brief Set battery level query callback method
|
||||
* If callback is not set, BAT_LEVEL_NO_MEASURE is returned.
|
||||
|
@ -220,6 +254,21 @@ private:
|
|||
*/
|
||||
lorawan_status_t add_dl_channel_ans(uint8_t status);
|
||||
|
||||
/**
|
||||
* @brief Adds a new AdrParamSetupAns MAC command to be sent.
|
||||
* @return status Function status: LORAWAN_STATUS_OK: OK,
|
||||
* LORAWAN_STATUS_LENGTH_ERROR: Buffer full
|
||||
*/
|
||||
lorawan_status_t add_adr_param_setup_ans();
|
||||
|
||||
/**
|
||||
* @brief Adds a new RejoinParamSetupAns MAC command to be sent.
|
||||
* @param status 1 if time limitation was accepted, 0 otherwise.
|
||||
* @return status Function status: LORAWAN_STATUS_OK: OK,
|
||||
* LORAWAN_STATUS_LENGTH_ERROR: Buffer full
|
||||
*/
|
||||
lorawan_status_t add_rejoin_param_setup_ans(uint8_t status);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Indicates if there are any pending sticky MAC commands
|
||||
|
|
|
@ -53,7 +53,8 @@ LoRaMacCrypto::~LoRaMacCrypto()
|
|||
|
||||
int LoRaMacCrypto::compute_mic(const uint8_t *buffer, uint16_t size,
|
||||
const uint8_t *key, const uint32_t key_length,
|
||||
uint32_t address, uint8_t dir, uint32_t seq_counter,
|
||||
uint32_t args, uint32_t address,
|
||||
uint8_t dir, uint32_t seq_counter,
|
||||
uint32_t *mic)
|
||||
{
|
||||
uint8_t computed_mic[16] = {};
|
||||
|
@ -61,6 +62,10 @@ int LoRaMacCrypto::compute_mic(const uint8_t *buffer, uint16_t size,
|
|||
int ret = 0;
|
||||
|
||||
mic_block_b0[0] = 0x49;
|
||||
mic_block_b0[1] = (args) & 0xFF;
|
||||
mic_block_b0[2] = (args >> 8) & 0xFF;
|
||||
mic_block_b0[3] = (args >> 16) & 0xFF;
|
||||
mic_block_b0[4] = (args >> 24) & 0xFF;
|
||||
|
||||
mic_block_b0[5] = dir;
|
||||
|
||||
|
@ -266,15 +271,30 @@ exit:
|
|||
}
|
||||
|
||||
int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length,
|
||||
const uint8_t *app_nonce, uint16_t dev_nonce,
|
||||
uint8_t *nwk_skey, uint8_t *app_skey)
|
||||
const uint8_t *app_key, uint32_t app_key_length,
|
||||
const uint8_t *args, uint8_t args_size,
|
||||
uint8_t *nwk_skey, uint8_t *app_skey,
|
||||
uint8_t *snwk_sintkey, uint8_t *nwk_senckey,
|
||||
server_type_t stype)
|
||||
{
|
||||
uint8_t nonce[16];
|
||||
uint8_t *p_dev_nonce = (uint8_t *) &dev_nonce;
|
||||
int ret = 0;
|
||||
|
||||
mbedtls_aes_init(&aes_ctx);
|
||||
|
||||
ret = mbedtls_aes_setkey_enc(&aes_ctx, app_key, app_key_length);
|
||||
if (0 != ret)
|
||||
goto exit;
|
||||
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
nonce[0] = 0x02;
|
||||
memcpy(nonce + 1, args, args_size);
|
||||
ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, app_skey);
|
||||
if (0 != ret)
|
||||
goto exit;
|
||||
|
||||
mbedtls_aes_free(&aes_ctx);
|
||||
mbedtls_aes_init(&aes_ctx);
|
||||
ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length);
|
||||
if (0 != ret) {
|
||||
goto exit;
|
||||
|
@ -282,23 +302,73 @@ int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *key, uint32_t key
|
|||
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
nonce[0] = 0x01;
|
||||
memcpy(nonce + 1, app_nonce, 6);
|
||||
memcpy(nonce + 7, p_dev_nonce, 2);
|
||||
memcpy(nonce + 1, args, args_size);
|
||||
ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, nwk_skey);
|
||||
if (0 != ret) {
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (stype == LW1_0_2) {
|
||||
memcpy(nwk_senckey, nwk_skey, key_length / 8);
|
||||
memcpy(snwk_sintkey, nwk_skey, key_length / 8);
|
||||
} else {
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
nonce[0] = 0x03;
|
||||
memcpy(nonce + 1, args, args_size);
|
||||
ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, snwk_sintkey);
|
||||
if (0 != ret)
|
||||
goto exit;
|
||||
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
nonce[0] = 0x04;
|
||||
memcpy(nonce + 1, args, args_size);
|
||||
ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, nwk_senckey);
|
||||
if (0 != ret)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
exit: mbedtls_aes_free(&aes_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int LoRaMacCrypto::compute_join_server_keys(const uint8_t *key, uint32_t key_length, const uint8_t *eui,
|
||||
uint8_t *js_intkey, uint8_t *js_enckey)
|
||||
{
|
||||
uint8_t nonce[16];
|
||||
int ret = 0;
|
||||
|
||||
if( MBED_CONF_LORA_VERSION == LORAWAN_VERSION_1_0_2 ) {
|
||||
memcpy(js_intkey, key, key_length/8);
|
||||
memcpy(js_enckey, key, key_length/8);
|
||||
return ret;
|
||||
}
|
||||
|
||||
mbedtls_aes_init(&aes_ctx);
|
||||
|
||||
ret = mbedtls_aes_setkey_enc(&aes_ctx, key, key_length);
|
||||
if (0 != ret)
|
||||
goto exit;
|
||||
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
nonce[0] = 0x02;
|
||||
memcpy(nonce + 1, app_nonce, 6);
|
||||
memcpy(nonce + 7, p_dev_nonce, 2);
|
||||
ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, app_skey);
|
||||
nonce[0] = 0x05;
|
||||
memcpy(nonce + 1, eui, 8);
|
||||
ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, js_enckey);
|
||||
if (0 != ret)
|
||||
goto exit;
|
||||
|
||||
mbedtls_aes_free(&aes_ctx);
|
||||
memset(nonce, 0, sizeof(nonce));
|
||||
nonce[0] = 0x06;
|
||||
memcpy(nonce + 1, eui, 8);
|
||||
ret = mbedtls_aes_crypt_ecb(&aes_ctx, MBEDTLS_AES_ENCRYPT, nonce, js_intkey);
|
||||
if (0 != ret)
|
||||
goto exit;
|
||||
|
||||
exit:
|
||||
mbedtls_aes_free(&aes_ctx);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
LoRaMacCrypto::LoRaMacCrypto()
|
||||
|
@ -314,8 +384,8 @@ LoRaMacCrypto::~LoRaMacCrypto()
|
|||
// user knows what is wrong and in addition to that these ensure that
|
||||
// Mbed-OS compiles properly under normal conditions where LoRaWAN in conjunction
|
||||
// with mbedTLS is not being used.
|
||||
int LoRaMacCrypto::compute_mic(const uint8_t *, uint16_t, const uint8_t *, uint32_t, uint32_t,
|
||||
uint8_t dir, uint32_t, uint32_t *)
|
||||
int LoRaMacCrypto::compute_mic(const uint8_t *, uint16_t , const uint8_t *, uint32_t, uint32_t, uint32_t,
|
||||
uint8_t, uint32_t, uint32_t *)
|
||||
{
|
||||
MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
|
||||
|
||||
|
@ -357,8 +427,19 @@ int LoRaMacCrypto::decrypt_join_frame(const uint8_t *, uint16_t, const uint8_t *
|
|||
return LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *, uint32_t, const uint8_t *, uint16_t,
|
||||
uint8_t *, uint8_t *)
|
||||
int LoRaMacCrypto::compute_skeys_for_join_frame(const uint8_t *, uint32_t, const uint8_t *, uint32_t,
|
||||
const uint8_t *, uint8_t ,
|
||||
uint8_t *, uint8_t *, uint8_t *, uint8_t *,
|
||||
server_type_t)
|
||||
{
|
||||
MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
|
||||
|
||||
// Never actually reaches here
|
||||
return LORAWAN_STATUS_CRYPTO_FAIL;
|
||||
}
|
||||
|
||||
int compute_join_server_keys(const uint8_t *, const uint8_t *,
|
||||
uint8_t *, uint8_t *)
|
||||
{
|
||||
MBED_ASSERT(0 && "[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ SPDX-License-Identifier: BSD-3-Clause
|
|||
#include "mbedtls/config.h"
|
||||
#include "mbedtls/aes.h"
|
||||
#include "mbedtls/cmac.h"
|
||||
#include "system/lorawan_data_structures.h"
|
||||
|
||||
|
||||
class LoRaMacCrypto {
|
||||
|
@ -54,6 +55,7 @@ public:
|
|||
* @param [in] size - Data buffer size
|
||||
* @param [in] key - AES key to be used
|
||||
* @param [in] key_length - Length of the key (bits)
|
||||
* @param [in] args - LW1.1 bytes 1-4 (ConfFCnt, TxDr, TxCh)
|
||||
* @param [in] address - Frame address
|
||||
* @param [in] dir - Frame direction [0: uplink, 1: downlink]
|
||||
* @param [in] seq_counter - Frame sequence counter
|
||||
|
@ -63,7 +65,8 @@ public:
|
|||
*/
|
||||
int compute_mic(const uint8_t *buffer, uint16_t size,
|
||||
const uint8_t *key, uint32_t key_length,
|
||||
uint32_t address, uint8_t dir, uint32_t seq_counter,
|
||||
uint32_t args, uint32_t address,
|
||||
uint8_t dir, uint32_t seq_counter,
|
||||
uint32_t *mic);
|
||||
|
||||
/**
|
||||
|
@ -138,18 +141,42 @@ public:
|
|||
/**
|
||||
* Computes the LoRaMAC join frame decryption
|
||||
*
|
||||
* @param [in] key - AES key to be used
|
||||
* @param [in] key - AES nwk key to be used
|
||||
* @param [in] key_length - Length of the key (bits)
|
||||
* @param [in] app_nonce - Application nonce
|
||||
* @param [in] dev_nonce - Device nonce
|
||||
* @param [in] app_key - AES app key to be used
|
||||
* @param [in] app_key_length - Length of the app key (bits)
|
||||
* @param [in] args - Combined string of args needed for key derivation
|
||||
* @param [in] args_size - Args size
|
||||
* @param [out] nwk_skey - Network session key
|
||||
* @param [out] app_skey - Application session key
|
||||
* @param [out] snwk_sintkey - Serving Network Session Integrity Key
|
||||
* @param [out] nwk_senckey - Network Session Encryption Key
|
||||
* @param stype - Server type (LW1_0_2 or LW1_1) which defines
|
||||
*
|
||||
* @return 0 if successful, or a cipher specific error code
|
||||
*/
|
||||
int compute_skeys_for_join_frame(const uint8_t *key, uint32_t key_length,
|
||||
const uint8_t *app_nonce, uint16_t dev_nonce,
|
||||
uint8_t *nwk_skey, uint8_t *app_skey);
|
||||
const uint8_t *app_key, uint32_t app_key_length,
|
||||
const uint8_t *args, uint8_t args_size,
|
||||
uint8_t *nwk_skey, uint8_t *app_skey,
|
||||
uint8_t *snwk_sintkey, uint8_t *nwk_senckey,
|
||||
server_type_t stype);
|
||||
|
||||
/**
|
||||
* Computes the LoRaMAC join server keys
|
||||
* In case of LoRaWAN 1.0.x key will be copied to outputs,
|
||||
* so we can continue using same code for all versions
|
||||
*
|
||||
* @param [in] key - AES key to be used
|
||||
* @param [in] key_length - Length of the key (bits)
|
||||
* @param [in] eui - DevEUI
|
||||
* @param [out] js_intkey - Join server integrity key
|
||||
* @param [out] js_enckey - Join server encryption key
|
||||
*
|
||||
* @return 0 if successful, or a cipher specific error code
|
||||
*/
|
||||
int compute_join_server_keys(const uint8_t *key, uint32_t key_length, const uint8_t *eui,
|
||||
uint8_t *js_intkey, uint8_t *js_enckey);
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
|
@ -27,6 +27,7 @@ SPDX-License-Identifier: BSD-3-Clause
|
|||
#include <stdint.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "mbed_rtc_time.h"
|
||||
#include "LoRaPHY.h"
|
||||
|
||||
#define BACKOFF_DC_1_HOUR 100
|
||||
|
@ -35,10 +36,16 @@ SPDX-License-Identifier: BSD-3-Clause
|
|||
#define MAX_PREAMBLE_LENGTH 8.0f
|
||||
#define TICK_GRANULARITY_JITTER 1.0f
|
||||
#define CHANNELS_IN_MASK 16
|
||||
#define GPS_EPOCH_DIFF_WITH_UTC 315964800
|
||||
#define CHANNELS_IN_MASK 16
|
||||
|
||||
LoRaPHY::LoRaPHY()
|
||||
: _radio(NULL),
|
||||
_lora_time(NULL)
|
||||
_lora_time(NULL),
|
||||
_server_adr_ack_limit(0),
|
||||
_server_adr_ack_delay(0),
|
||||
_rejoin_max_time(MBED_CONF_LORA_REJOIN_DEFAULT_MAX_TIME),
|
||||
_rejoin_max_count(MBED_CONF_LORA_REJOIN_DEFAULT_MAX_COUNT)
|
||||
{
|
||||
memset(&phy_params, 0, sizeof(phy_params));
|
||||
}
|
||||
|
@ -666,6 +673,26 @@ bool LoRaPHY::is_custom_channel_plan_supported()
|
|||
return phy_params.custom_channelplans_supported;
|
||||
}
|
||||
|
||||
void LoRaPHY::time_received(uint32_t secs, uint32_t milliseconds)
|
||||
{
|
||||
time_t seconds = time(NULL) + GPS_EPOCH_DIFF_WITH_UTC + secs;
|
||||
//Since RTC does not support milliseconds, we round millis to closest second
|
||||
if (milliseconds > 499) {
|
||||
seconds++;
|
||||
}
|
||||
|
||||
set_time(seconds);
|
||||
//TODO: Do we need/want to inform application about updated time??
|
||||
}
|
||||
|
||||
uint8_t LoRaPHY::update_rejoin_params(uint32_t max_time, uint32_t max_count)
|
||||
{
|
||||
//These will be taken into use at next rejoin "cycle"
|
||||
_rejoin_max_time = max_time;
|
||||
_rejoin_max_count = max_count;
|
||||
return 1;
|
||||
}
|
||||
|
||||
void LoRaPHY::restore_default_channels()
|
||||
{
|
||||
// Restore channels default mask
|
||||
|
@ -678,7 +705,6 @@ bool LoRaPHY::verify_rx_datarate(uint8_t datarate)
|
|||
{
|
||||
if (is_datarate_supported(datarate)) {
|
||||
if (phy_params.dl_dwell_time_setting == 0) {
|
||||
//TODO: Check this! datarate must be same as minimum! Can be compared directly if OK
|
||||
return val_in_range(datarate,
|
||||
phy_params.min_rx_datarate,
|
||||
phy_params.max_rx_datarate);
|
||||
|
@ -731,6 +757,32 @@ bool LoRaPHY::verify_nb_join_trials(uint8_t nb_join_trials)
|
|||
return true;
|
||||
}
|
||||
|
||||
uint16_t LoRaPHY::get_adr_ack_limit() const
|
||||
{
|
||||
if (_server_adr_ack_limit != 0) {
|
||||
return _server_adr_ack_limit;
|
||||
}
|
||||
return phy_params.adr_ack_limit;
|
||||
}
|
||||
|
||||
void LoRaPHY::set_adr_ack_limit(const uint16_t& value)
|
||||
{
|
||||
_server_adr_ack_limit = value;
|
||||
}
|
||||
|
||||
uint16_t LoRaPHY::get_adr_ack_delay() const
|
||||
{
|
||||
if (_server_adr_ack_delay != 0) {
|
||||
return _server_adr_ack_delay;
|
||||
}
|
||||
return phy_params.adr_ack_delay;
|
||||
}
|
||||
|
||||
void LoRaPHY::set_adr_ack_delay(const uint16_t& value)
|
||||
{
|
||||
_server_adr_ack_delay = value;
|
||||
}
|
||||
|
||||
void LoRaPHY::apply_cf_list(const uint8_t *payload, uint8_t size)
|
||||
{
|
||||
// if the underlying PHY doesn't support CF-List, ignore the request
|
||||
|
@ -791,14 +843,14 @@ bool LoRaPHY::get_next_ADR(bool restore_channel_mask, int8_t &dr_out,
|
|||
{
|
||||
bool set_adr_ack_bit = false;
|
||||
|
||||
uint16_t ack_limit_plus_delay = phy_params.adr_ack_limit + phy_params.adr_ack_delay;
|
||||
uint16_t ack_limit_plus_delay = get_adr_ack_limit() + get_adr_ack_delay();
|
||||
|
||||
if (dr_out == phy_params.min_tx_datarate) {
|
||||
adr_ack_cnt = 0;
|
||||
return set_adr_ack_bit;
|
||||
}
|
||||
|
||||
if (adr_ack_cnt < phy_params.adr_ack_limit) {
|
||||
if (adr_ack_cnt < get_adr_ack_limit()) {
|
||||
return set_adr_ack_bit;
|
||||
}
|
||||
|
||||
|
@ -807,7 +859,7 @@ bool LoRaPHY::get_next_ADR(bool restore_channel_mask, int8_t &dr_out,
|
|||
tx_power_out = phy_params.max_tx_power;
|
||||
|
||||
if (adr_ack_cnt >= ack_limit_plus_delay) {
|
||||
if ((adr_ack_cnt % phy_params.adr_ack_delay) == 1) {
|
||||
if ((adr_ack_cnt % get_adr_ack_delay()) == 1) {
|
||||
// Decrease the datarate
|
||||
dr_out = get_next_lower_tx_datarate(dr_out);
|
||||
|
||||
|
|
|
@ -526,6 +526,22 @@ public:
|
|||
*/
|
||||
uint32_t get_rx_time_on_air(uint8_t modem, uint16_t pkt_len);
|
||||
|
||||
/**
|
||||
* @brief time_received Function which is called in LW1.1 when time is received from network
|
||||
* @param secs Seconds since GPS Epoch
|
||||
* @param milliseconds Number of milliseconds
|
||||
*/
|
||||
void time_received(uint32_t secs, uint32_t milliseconds);
|
||||
|
||||
/**
|
||||
* @brief update_rejoin_params Update Rejoin parameters
|
||||
* @param max_time Maximum time in seconds between Rejoin requests
|
||||
* @param max_count Maximum amount of messages allowed to be sent between Rejoin requests
|
||||
* @return 1 If device supports a time variable, 0 otherwise.
|
||||
* Currently we always support time!
|
||||
*/
|
||||
uint8_t update_rejoin_params(uint32_t max_time, uint32_t max_count);
|
||||
|
||||
public: //Verifiers
|
||||
|
||||
/**
|
||||
|
@ -564,6 +580,30 @@ public: //Verifiers
|
|||
*/
|
||||
bool verify_nb_join_trials(uint8_t nb_join_trials);
|
||||
|
||||
/**
|
||||
* @brief get_adr_ack_limit Gets the ADR ACK limit currently in use.
|
||||
* @return ADR ACK limit used
|
||||
*/
|
||||
uint16_t get_adr_ack_limit() const;
|
||||
|
||||
/**
|
||||
* @brief set_adr_ack_limit Sets ADR ACK limit to be used.
|
||||
* @param value New value for ack limit
|
||||
*/
|
||||
void set_adr_ack_limit(const uint16_t& value);
|
||||
|
||||
/**
|
||||
* @brief get_adr_ack_delay Gets the ADR ACK delay currently in use.
|
||||
* @return ADR ACK delay used
|
||||
*/
|
||||
uint16_t get_adr_ack_delay() const;
|
||||
|
||||
/**
|
||||
* @brief set_adr_ack_delay Sets ADR ACK delay to be used.
|
||||
* @param value New value for ack delay
|
||||
*/
|
||||
void set_adr_ack_delay(const uint16_t& value);
|
||||
|
||||
protected:
|
||||
LoRaPHY();
|
||||
|
||||
|
@ -678,6 +718,13 @@ protected:
|
|||
LoRaRadio *_radio;
|
||||
LoRaWANTimeHandler *_lora_time;
|
||||
loraphy_params_t phy_params;
|
||||
|
||||
private:
|
||||
uint16_t _server_adr_ack_limit;
|
||||
uint16_t _server_adr_ack_delay;
|
||||
|
||||
uint32_t _rejoin_max_time;
|
||||
uint32_t _rejoin_max_count;
|
||||
};
|
||||
|
||||
#endif /* MBED_OS_LORAPHY_BASE_ */
|
||||
|
|
|
@ -51,6 +51,9 @@
|
|||
#define MSG_MULTICAST_FLAG 0x04
|
||||
#define MSG_PROPRIETARY_FLAG 0x08
|
||||
|
||||
#define LORAWAN_VERSION_1_0_2 0
|
||||
#define LORAWAN_VERSION_1_1 10
|
||||
|
||||
/**
|
||||
* LoRaWAN device classes definition.
|
||||
*
|
||||
|
@ -62,19 +65,19 @@ typedef enum {
|
|||
*
|
||||
* LoRaWAN Specification V1.0.2, chapter 3.
|
||||
*/
|
||||
CLASS_A,
|
||||
CLASS_A = 0x00,
|
||||
/**
|
||||
* LoRaWAN device class B.
|
||||
*
|
||||
* LoRaWAN Specification V1.0.2, chapter 8.
|
||||
*/
|
||||
CLASS_B,
|
||||
CLASS_B = 0x01,
|
||||
/**
|
||||
* LoRaWAN device class C.
|
||||
*
|
||||
* LoRaWAN Specification V1.0.2, chapter 17.
|
||||
*/
|
||||
CLASS_C,
|
||||
CLASS_C = 0x02,
|
||||
} device_class_t;
|
||||
|
||||
/**
|
||||
|
@ -105,7 +108,7 @@ typedef enum lorawan_status {
|
|||
LORAWAN_STATUS_NO_CHANNEL_FOUND = -1021, /**< None of the channels is enabled at the moment*/
|
||||
LORAWAN_STATUS_NO_FREE_CHANNEL_FOUND = -1022, /**< None of the enabled channels is ready for another TX (duty cycle limited)*/
|
||||
LORAWAN_STATUS_METADATA_NOT_AVAILABLE = -1023, /**< Meta-data after an RX or TX is stale*/
|
||||
LORAWAN_STATUS_ALREADY_CONNECTED = -1024 /**< The device has already joined a network*/
|
||||
LORAWAN_STATUS_ALREADY_CONNECTED = -1024 /**< The device has already joined a network*/
|
||||
} lorawan_status_t;
|
||||
|
||||
/** The lorawan_connect_otaa structure.
|
||||
|
@ -122,6 +125,7 @@ typedef struct {
|
|||
/** Application identifier
|
||||
*
|
||||
* LoRaWAN Specification V1.0.2, chapter 6.1.2
|
||||
* In case of LW1.1 or greater this is same as JoinEUI
|
||||
*/
|
||||
uint8_t *app_eui;
|
||||
/** AES-128 application key
|
||||
|
@ -129,6 +133,12 @@ typedef struct {
|
|||
* LoRaWAN Specification V1.0.2, chapter 6.2.2
|
||||
*/
|
||||
uint8_t *app_key;
|
||||
/** AES-128 network key
|
||||
*
|
||||
* In case of LoRaWAN Specification V1.0.2, must be same as app_key!
|
||||
* LoRaWAN specification 1.1, chapter 6.2.2
|
||||
*/
|
||||
uint8_t *nwk_key;
|
||||
/** Join request trials
|
||||
*
|
||||
* Number of trials for the join request.
|
||||
|
@ -155,6 +165,7 @@ typedef struct {
|
|||
/** Network session key
|
||||
*
|
||||
* LoRaWAN Specification V1.0.2, chapter 6.1.3
|
||||
* LoRaWAN Spec V1.1 onwards this is used as FNwkSIntKey
|
||||
*/
|
||||
uint8_t *nwk_skey;
|
||||
/** Application session key
|
||||
|
@ -162,6 +173,18 @@ typedef struct {
|
|||
* LoRaWAN Specification V1.0.2, chapter 6.1.4
|
||||
*/
|
||||
uint8_t *app_skey;
|
||||
|
||||
/** Serving Network session integrity key
|
||||
*
|
||||
* LoRaWAN Specification V1.1, chapter 6.1.2.3
|
||||
*/
|
||||
uint8_t *snwk_sintkey;
|
||||
|
||||
/** Network session encryption key
|
||||
*
|
||||
* LoRaWAN Specification V1.1, chapter 6.1.2.4
|
||||
*/
|
||||
uint8_t *nwk_senckey;
|
||||
} lorawan_connect_abp_t;
|
||||
|
||||
/** lorawan_connect_t structure
|
||||
|
@ -222,6 +245,9 @@ typedef enum lora_events {
|
|||
JOIN_FAILURE,
|
||||
UPLINK_REQUIRED,
|
||||
AUTOMATIC_UPLINK_ERROR,
|
||||
CLASS_CHANGED, //only in Lorawan 1.1 (ch 18.1)
|
||||
SERVER_ACCEPTED_CLASS_IN_USE, //only in Lorawan 1.1 (ch 18.1)
|
||||
SERVER_DOES_NOT_SUPPORT_CLASS_IN_USE //only in Lorawan 1.1 (ch 18.1)
|
||||
} lorawan_event_t;
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
{
|
||||
"name": "lora",
|
||||
"config": {
|
||||
"version": {
|
||||
"help": "LoRaWAN Version: LW1.0.2 = 0, LW1.1 = 10",
|
||||
"value": 0
|
||||
},
|
||||
"phy": {
|
||||
"help": "LoRa PHY region: EU868, AS923, AU915, CN470, CN779, EU433, IN865, KR920, US915",
|
||||
"value": "EU868"
|
||||
|
@ -18,19 +22,31 @@
|
|||
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
|
||||
},
|
||||
"application-eui": {
|
||||
"help": "Application IEEE EUI",
|
||||
"help": "Application IEEE EUI. In case of LW1.1 or greater this will be used as JoinEUI",
|
||||
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
|
||||
},
|
||||
"application-key": {
|
||||
"help": "AES encryption/decryption cipher application key",
|
||||
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
|
||||
},
|
||||
"network-key": {
|
||||
"help": "AES encryption/decryption cipher network key, in case of LW1.0.x not used",
|
||||
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
|
||||
},
|
||||
"device-address": {
|
||||
"help": "Device address on the network",
|
||||
"value": "0x00000000"
|
||||
},
|
||||
"nwkskey": {
|
||||
"help": "AES encryption/decryption cipher network session key",
|
||||
"help": "AES encryption/decryption cipher network session key. In case of LW1.1 or greater is used as FNwkSIntKey",
|
||||
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
|
||||
},
|
||||
"snwksintkey": {
|
||||
"help": "Serving network session integrity key. For LW1.1 or greater",
|
||||
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
|
||||
},
|
||||
"nwksenckey": {
|
||||
"help": "Network session encryption key. For LW1.1 or greater",
|
||||
"value": "{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}"
|
||||
},
|
||||
"appskey": {
|
||||
|
@ -92,6 +108,14 @@
|
|||
"fsb-mask-china": {
|
||||
"help": "FSB mask for upstream [CN470 PHY] Check lorawan/FSB_Usage.txt for more details",
|
||||
"value": "{0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}"
|
||||
},
|
||||
"rejoin-default-max-time": {
|
||||
"help": "LW1.1 only! Maximum time in seconds between Rejoin requests.",
|
||||
"value": 3600
|
||||
},
|
||||
"rejoin-default-max-count": {
|
||||
"help": "LW1.1 only! Maximum amount of messages which can be sent between Rejoin requests.",
|
||||
"value": 1000
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -153,6 +153,18 @@ typedef enum {
|
|||
RX_SLOT_WIN_PING_SLOT
|
||||
} rx_slot_t;
|
||||
|
||||
typedef enum {
|
||||
REJOIN_REQUEST_TYPE0 = 0,
|
||||
REJOIN_REQUEST_TYPE1 = 1,
|
||||
REJOIN_REQUEST_TYPE2 = 2,
|
||||
JOIN_REQUEST = 0xFF
|
||||
} join_req_type_t;
|
||||
|
||||
typedef enum {
|
||||
LW1_0_2,
|
||||
LW1_1
|
||||
} server_type_t;
|
||||
|
||||
/*!
|
||||
* The global MAC layer parameters.
|
||||
*/
|
||||
|
@ -288,9 +300,9 @@ typedef enum {
|
|||
*/
|
||||
FRAME_TYPE_DATA_CONFIRMED_DOWN = 0x05,
|
||||
/*!
|
||||
* LoRaMAC RFU frame.
|
||||
* LoRaMAC Rejoin request frame.
|
||||
*/
|
||||
FRAME_TYPE_RFU = 0x06,
|
||||
FRAME_TYPE_REJOIN_REQUEST = 0x06,
|
||||
/*!
|
||||
* LoRaMAC proprietary frame.
|
||||
*/
|
||||
|
@ -303,6 +315,10 @@ typedef enum {
|
|||
* LoRaWAN Specification V1.0.2, chapter 5, table 4.
|
||||
*/
|
||||
typedef enum {
|
||||
/*!
|
||||
* ResetInd
|
||||
*/
|
||||
MOTE_MAC_RESET_IND = 0x01,
|
||||
/*!
|
||||
* LinkCheckReq
|
||||
*/
|
||||
|
@ -338,7 +354,27 @@ typedef enum {
|
|||
/*!
|
||||
* DlChannelAns
|
||||
*/
|
||||
MOTE_MAC_DL_CHANNEL_ANS = 0x0A
|
||||
MOTE_MAC_DL_CHANNEL_ANS = 0x0A,
|
||||
/*!
|
||||
* RekeyInd
|
||||
*/
|
||||
MOTE_MAC_REKEY_IND = 0x0B,
|
||||
/*!
|
||||
* ADRParamSetupAns
|
||||
*/
|
||||
MOTE_MAC_ADR_PARAM_SETUP_ANS = 0x0C,
|
||||
/*!
|
||||
* DeviceTimeReq
|
||||
*/
|
||||
MOTE_MAC_DEVICE_TIME_REQ = 0x0D,
|
||||
/*!
|
||||
* RejoinParamSetupAns
|
||||
*/
|
||||
MOTE_MAC_REJOIN_PARAM_SETUP_ANS = 0x0F,
|
||||
/*!
|
||||
* DeviceModeInd
|
||||
*/
|
||||
MOTE_DEVICE_MODE_IND = 0x20
|
||||
} mote_mac_cmds_t;
|
||||
|
||||
/*!
|
||||
|
@ -347,6 +383,10 @@ typedef enum {
|
|||
* LoRaWAN Specification V1.0.2 chapter 5, table 4.
|
||||
*/
|
||||
typedef enum {
|
||||
/*!
|
||||
* ResetConf
|
||||
*/
|
||||
SRV_MAC_RESET_CONF = 0x01,
|
||||
/*!
|
||||
* LinkCheckAns
|
||||
*/
|
||||
|
@ -383,6 +423,30 @@ typedef enum {
|
|||
* DlChannelReq
|
||||
*/
|
||||
SRV_MAC_DL_CHANNEL_REQ = 0x0A,
|
||||
/*!
|
||||
* RekeyConf
|
||||
*/
|
||||
SRV_MAC_REKEY_CONF = 0x0B,
|
||||
/*!
|
||||
* ADRParamSetupReq
|
||||
*/
|
||||
SRV_MAC_ADR_PARAM_SETUP_REQ = 0x0C,
|
||||
/*!
|
||||
* DeviceTimeAns
|
||||
*/
|
||||
SRV_MAC_DEVICE_TIME_ANS = 0x0D,
|
||||
/*!
|
||||
* ForceRejoinReq
|
||||
*/
|
||||
SRV_MAC_FORCE_REJOIN_REQ = 0x0E,
|
||||
/*!
|
||||
* RejoinParamSetupReq
|
||||
*/
|
||||
SRV_MAC_REJOIN_PARAM_SETUP_REQ = 0x0F,
|
||||
/*!
|
||||
* DeviceModeConf
|
||||
*/
|
||||
SRV_MAC_DEVICE_MODE_CONF = 0x20
|
||||
} server_mac_cmds_t;
|
||||
|
||||
/*!
|
||||
|
@ -699,9 +763,7 @@ typedef struct {
|
|||
*
|
||||
* Name | Request | Indication | Response | Confirm
|
||||
* ---------------------------- | :-----: | :--------: | :------: | :-----:
|
||||
* \ref MLME_JOIN | YES | NO | NO | YES
|
||||
* \ref MLME_LINK_CHECK | YES | NO | NO | YES
|
||||
* \ref MLME_TXCW | YES | NO | NO | YES
|
||||
* \ref MLME_SCHEDULE_UPLINK | NO | YES | NO | NO
|
||||
*
|
||||
*/
|
||||
|
@ -711,30 +773,48 @@ typedef enum {
|
|||
*
|
||||
* LoRaWAN Specification V1.0.2, chapter 6.2.
|
||||
*/
|
||||
MLME_JOIN,
|
||||
MLME_JOIN_ACCEPT,
|
||||
/*!
|
||||
* Initiates Rejoin request
|
||||
*
|
||||
* LoRaWAN specification V1.1, chapter 6.2.4
|
||||
*/
|
||||
MLME_REJOIN,
|
||||
/*!
|
||||
* LinkCheckReq - Connectivity validation.
|
||||
*
|
||||
* LoRaWAN Specification V1.0.2, chapter 5, table 4.
|
||||
*/
|
||||
MLME_LINK_CHECK,
|
||||
/*!
|
||||
* Sets TX continuous wave mode.
|
||||
*
|
||||
* LoRaWAN end-device certification.
|
||||
*/
|
||||
MLME_TXCW,
|
||||
/*!
|
||||
* Sets TX continuous wave mode (new LoRa-Alliance CC definition).
|
||||
*
|
||||
* LoRaWAN end-device certification.
|
||||
*/
|
||||
MLME_TXCW_1,
|
||||
/*!
|
||||
* Indicates that the application shall perform an uplink as
|
||||
* soon as possible.
|
||||
*/
|
||||
MLME_SCHEDULE_UPLINK
|
||||
MLME_SCHEDULE_UPLINK,
|
||||
|
||||
/*!
|
||||
* Indicates that ABP device has resetted
|
||||
* LoRaWAN specification V1.1, chapter 5.1
|
||||
*/
|
||||
MLME_RESET,
|
||||
|
||||
/*!
|
||||
* Indicates that OTAA device has updated keys
|
||||
* LoRaWAN specification V1.1, chapter 5.10
|
||||
*/
|
||||
MLME_REKEY,
|
||||
|
||||
/*!
|
||||
* Indicates that device has changed LoRa class
|
||||
* LoRaWAN specification V1.1, chapter 18.1
|
||||
*/
|
||||
MLME_DEVICE_MODE,
|
||||
|
||||
/*!
|
||||
* Indicates that device has received force rejoin MAC command
|
||||
* LoRaWAN specification V1.1, chapter 5.13
|
||||
*/
|
||||
MLME_FORCE_REJOIN
|
||||
} mlme_type_t;
|
||||
|
||||
/*!
|
||||
|
@ -783,28 +863,19 @@ typedef struct {
|
|||
uint8_t power;
|
||||
} mlme_cw_tx_mode_t;
|
||||
|
||||
|
||||
/*!
|
||||
* LoRaMAC MLME-Confirm primitive.
|
||||
*/
|
||||
typedef struct {
|
||||
/*!
|
||||
* Indicates if a request is pending or not
|
||||
*/
|
||||
bool pending;
|
||||
/*!
|
||||
* The previously performed MLME-Request. i.e., the request type
|
||||
* for which the confirmation is being generated
|
||||
*/
|
||||
mlme_type_t req_type;
|
||||
mlme_type_t type;
|
||||
/*!
|
||||
* The status of the operation.
|
||||
*/
|
||||
loramac_event_info_status_t status;
|
||||
/*!
|
||||
* The transmission time on air of the frame.
|
||||
*/
|
||||
lorawan_time_t tx_toa;
|
||||
/*!
|
||||
* The demodulation margin. Contains the link margin [dB] of the last LinkCheckReq
|
||||
* successfully received.
|
||||
|
@ -815,9 +886,31 @@ typedef struct {
|
|||
*/
|
||||
uint8_t nb_gateways;
|
||||
/*!
|
||||
* The number of retransmissions.
|
||||
* Number of retries done for RejoinRequest
|
||||
*/
|
||||
uint8_t nb_retries;
|
||||
uint8_t max_retries;
|
||||
/*!
|
||||
* Period between RejoinRequest (2^period + rand(0, 32))
|
||||
*/
|
||||
uint8_t period;
|
||||
/*!
|
||||
* A datarate used to send RejoinRequest
|
||||
*/
|
||||
uint8_t datarate;
|
||||
/*!
|
||||
* Value 0 or 1 means RejoinRequest type 0 shall be transmitted,
|
||||
* Value 2 means RejoinRequest type 2 shall be transmitted,
|
||||
* Other values are RFU and shall not be processed.
|
||||
*/
|
||||
uint8_t rejoin_type;
|
||||
/*!
|
||||
* Class type from device mode conf
|
||||
*/
|
||||
uint8_t classType;
|
||||
/*!
|
||||
* LoRaWAN version
|
||||
*/
|
||||
uint8_t version;
|
||||
} loramac_mlme_confirm_t;
|
||||
|
||||
/*!
|
||||
|
@ -1067,6 +1160,8 @@ typedef struct {
|
|||
|
||||
/*!
|
||||
* Application IEEE EUI
|
||||
*
|
||||
* In case of LW1.1 or greater this is same as JoinEUI
|
||||
*/
|
||||
uint8_t *app_eui;
|
||||
|
||||
|
@ -1075,9 +1170,15 @@ typedef struct {
|
|||
*/
|
||||
uint8_t *app_key;
|
||||
|
||||
/*!
|
||||
* AES encryption/decryption cipher network key
|
||||
*/
|
||||
uint8_t *nwk_key;
|
||||
|
||||
/*!
|
||||
* AES encryption/decryption cipher network session key
|
||||
* NOTE! LoRaMac determines the length of the key based on sizeof this variable
|
||||
* From LW1.1 onwards, this is used as FNwkSIntKey.
|
||||
*/
|
||||
uint8_t nwk_skey[16];
|
||||
|
||||
|
@ -1087,6 +1188,30 @@ typedef struct {
|
|||
*/
|
||||
uint8_t app_skey[16];
|
||||
|
||||
/*!
|
||||
* AES encryption/decryption cipher Serving network session integrity key
|
||||
* NOTE! LoRaMac determines the length of the key based on sizeof this variable
|
||||
*/
|
||||
uint8_t snwk_sintkey[16];
|
||||
|
||||
/*!
|
||||
* AES encryption/decryption cipher network session encryption key
|
||||
* NOTE! LoRaMac determines the length of the key based on sizeof this variable
|
||||
*/
|
||||
uint8_t nwk_senckey[16];
|
||||
|
||||
/*!
|
||||
* AES encryption/decryption cipher Join server integrity key
|
||||
* NOTE! LoRaMac determines the length of the key based on sizeof this variable
|
||||
*/
|
||||
uint8_t js_intkey[16];
|
||||
|
||||
/*!
|
||||
* AES encryption/decryption cipher Join server encryption key
|
||||
* NOTE! LoRaMac determines the length of the key based on sizeof this variable
|
||||
*/
|
||||
uint8_t js_enckey[16];
|
||||
|
||||
} loramac_keys;
|
||||
|
||||
/*!
|
||||
|
@ -1252,6 +1377,21 @@ typedef struct {
|
|||
*/
|
||||
uint16_t dev_nonce;
|
||||
|
||||
/*!
|
||||
* counterForAck is needed for LoRaWAN 1.1 spec onwards
|
||||
*/
|
||||
uint16_t counterForAck;
|
||||
|
||||
/*!
|
||||
* Rejoin type 0 or 2 specific counter
|
||||
*/
|
||||
uint16_t RJcount0;
|
||||
|
||||
/*!
|
||||
* Rejoin type 1 specific counter
|
||||
*/
|
||||
uint16_t RJcount1;
|
||||
|
||||
/*!
|
||||
* Network ID ( 3 bytes )
|
||||
*/
|
||||
|
@ -1269,11 +1409,17 @@ typedef struct {
|
|||
uint32_t ul_frame_counter;
|
||||
|
||||
/*!
|
||||
* LoRaMAC frame counter. Each time a packet is received the counter is incremented.
|
||||
* LoRaMAC NS frame counter. Each time a packet is received for port 0 the counter is incremented.
|
||||
* Only the 16 LSB bits are received
|
||||
*/
|
||||
uint32_t dl_frame_counter;
|
||||
|
||||
/*!
|
||||
* Application Server DL frame_counter. Each time a packet is received to port > 0 this counter is incremented.
|
||||
* Only the 16 LSB bits are received
|
||||
*/
|
||||
uint32_t app_dl_frame_counter;
|
||||
|
||||
/*!
|
||||
* Counts the number of missed ADR acknowledgements
|
||||
*/
|
||||
|
@ -1303,6 +1449,10 @@ typedef struct {
|
|||
rx_config_params_t rx_window1_config;
|
||||
rx_config_params_t rx_window2_config;
|
||||
|
||||
join_req_type_t join_request_type;
|
||||
|
||||
server_type_t server_type;
|
||||
|
||||
/*!
|
||||
* Multicast channels linked list
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue