[LoRaWAN] Improve persistence behaviour, bugfix subband

This commit is contained in:
StevenCellist 2024-02-27 00:23:12 +01:00
parent bc1ab86f1e
commit 0e9260f908
2 changed files with 50 additions and 31 deletions

View file

@ -82,7 +82,7 @@ int16_t LoRaWANNode::restore() {
return(RADIOLIB_ERR_NETWORK_NOT_JOINED); return(RADIOLIB_ERR_NETWORK_NOT_JOINED);
} }
if(!this->isActiveSession()) { if(!this->isValidSession()) {
return(RADIOLIB_ERR_NETWORK_NOT_JOINED); return(RADIOLIB_ERR_NETWORK_NOT_JOINED);
} }
@ -257,6 +257,7 @@ int16_t LoRaWANNode::restoreChannels() {
} else { // RADIOLIB_LORAWAN_BAND_FIXED } else { // RADIOLIB_LORAWAN_BAND_FIXED
uint8_t numADRCommands = mod->hal->getPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID); uint8_t numADRCommands = mod->hal->getPersistentParameter<uint8_t>(RADIOLIB_EEPROM_LORAWAN_NUM_ADR_MASKS_ID);
RADIOLIB_DEBUG_PRINTLN("Restoring %d stored channel masks", numADRCommands);
uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn; uint8_t numBytes = numADRCommands * MacTable[RADIOLIB_LORAWAN_MAC_LINK_ADR].lenDn;
uint8_t buffer[RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 }; uint8_t buffer[RADIOLIB_LORAWAN_MAX_NUM_ADR_COMMANDS * RADIOLIB_LORAWAN_MAX_MAC_COMMAND_LEN_DOWN] = { 0 };
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes); mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_UL_CHANNELS_ID), buffer, numBytes);
@ -284,33 +285,39 @@ int16_t LoRaWANNode::restoreChannels() {
void LoRaWANNode::clearSession() { void LoRaWANNode::clearSession() {
Module* mod = this->phyLayer->getMod(); Module* mod = this->phyLayer->getMod();
uint8_t zeroes[RADIOLIB_AES128_BLOCK_SIZE] = { 0 }; uint8_t zeroes[RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID), zeroes, sizeof(uint32_t));
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE); mod->hal->writePersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), zeroes, RADIOLIB_AES128_BLOCK_SIZE);
this->activeMode = RADIOLIB_LORAWAN_MODE_NONE;
} }
bool LoRaWANNode::isActiveSession() { bool LoRaWANNode::isValidSession() {
Module* mod = this->phyLayer->getMod();
this->devAddr = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID);
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), this->appSKey, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), this->nwkSEncKey, RADIOLIB_AES128_BLOCK_SIZE);
uint8_t mask = 0; uint8_t mask = 0;
for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { Module* mod = this->phyLayer->getMod();
mask |= this->appSKey[i]; uint8_t dummyBuf[RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_DEV_ADDR_ID), dummyBuf, sizeof(uint32_t));
for(size_t i = 0; i < sizeof(uint32_t); i++) {
mask |= dummyBuf[i];
} }
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_APP_S_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE);
for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) {
mask |= this->nwkSEncKey[i]; mask |= dummyBuf[i];
} }
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_FNWK_SINT_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE);
for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) {
mask |= this->fNwkSIntKey[i]; mask |= dummyBuf[i];
} }
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_SNWK_SINT_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE);
for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) { for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) {
mask |= this->sNwkSIntKey[i]; mask |= dummyBuf[i];
} }
mod->hal->readPersistentStorage(mod->hal->getPersistentAddr(RADIOLIB_EEPROM_LORAWAN_NWK_SENC_KEY_ID), dummyBuf, RADIOLIB_AES128_BLOCK_SIZE);
for(size_t i = 0; i < RADIOLIB_AES128_BLOCK_SIZE; i++) {
mask |= dummyBuf[i];
}
return(mask > 0); return(mask > 0);
} }
@ -440,16 +447,22 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
bool isValidCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool isValidCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum;
bool isValidMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; bool isValidMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA;
if(isValidCheckSum && isValidMode && !force && this->isActiveSession()) { if(isValidCheckSum && isValidMode) {
return(this->restore()); // if not forced and already joined, don't do anything
} if(!force && this->isJoined()) {
if(isValidCheckSum && isValidMode && (force || !this->isActiveSession())) { return(this->activeMode);
}
// if not forced and a valid session is stored, restore it
if(!force && this->isValidSession()) {
return(this->restore());
}
// either forced or no active session (a join was issued previously but didn't result in an active session)
this->clearSession(); this->clearSession();
// the credentials are still the same, so restore the DevNonce and JoinNonce // the credentials are still the same, so restore the DevNonce and JoinNonce
this->devNonce = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID); this->devNonce = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_DEV_NONCE_ID);
this->joinNonce = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID); this->joinNonce = mod->hal->getPersistentParameter<uint32_t>(RADIOLIB_EEPROM_LORAWAN_JOIN_NONCE_ID);
} } else {
if(!isValidCheckSum || !isValidMode) { // either invalid key checksum or mode, so wipe either way
#if RADIOLIB_DEBUG #if RADIOLIB_DEBUG
RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode);
RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:");
@ -723,15 +736,21 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* nwkSKey, uint8_t* appSKey,
if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); } if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); }
bool isValidCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum; bool isValidCheckSum = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_CHECKSUM_ID) == checkSum;
bool isValidMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_OTAA; bool isValidMode = mod->hal->getPersistentParameter<uint16_t>(RADIOLIB_EEPROM_LORAWAN_MODE_ID) == RADIOLIB_LORAWAN_MODE_ABP;
if(isValidCheckSum && isValidMode && !force && this->isActiveSession()) { if(isValidCheckSum && isValidMode) {
return(this->restore()); // if not forced and already joined, don't do anything
} if(!force && this->isJoined()) {
if(isValidCheckSum && isValidMode && (force || !this->isActiveSession())) { return(this->activeMode);
}
// if not forced and a valid session is stored, restore it
if(!force && this->isValidSession()) {
return(this->restore());
}
// either forced or no active session (a join was issued previously but didn't result in an active session)
this->clearSession(); this->clearSession();
} } else {
if(!isValidCheckSum || !isValidMode) { // either invalid key checksum or mode, so wipe either way
#if RADIOLIB_DEBUG #if RADIOLIB_DEBUG
RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode); RADIOLIB_DEBUG_PRINTLN("Didn't restore session (checksum: %d, mode: %d)", isValidCheckSum, isValidMode);
RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:"); RADIOLIB_DEBUG_PRINTLN("First 16 bytes of NVM:");
@ -1828,7 +1847,7 @@ int16_t LoRaWANNode::setupChannelsDyn(bool joinRequest) {
// setup a subband and its corresponding join-request datarate // setup a subband and its corresponding join-request datarate
// WARNING: subBand starts at 1 (corresponds to all populair schemes) // WARNING: subBand starts at 1 (corresponds to all populair schemes)
int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) { int16_t LoRaWANNode::setupChannelsFix(uint8_t subBand) {
RADIOLIB_DEBUG_PRINTLN("Setting up fixed channels"); RADIOLIB_DEBUG_PRINTLN("Setting up fixed channels (subband %d)", subBand);
// randomly select one of 8 or 9 channels and find corresponding datarate // randomly select one of 8 or 9 channels and find corresponding datarate
uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9; uint8_t numChannels = this->band->numTxSpans == 1 ? 8 : 9;
uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9 uint8_t rand = this->phyLayer->random(numChannels) + 1; // range 1-8 or 1-9
@ -2765,7 +2784,7 @@ bool LoRaWANNode::applyChannelMaskFix(uint8_t chMaskCntl, uint16_t chMask, bool
uint16_t mask = 1 << i; uint16_t mask = 1 << i;
if(mask & chMask) { if(mask & chMask) {
uint8_t chNum = chMaskCntl * 16 + i; // 0 through 63 or 95 uint8_t chNum = chMaskCntl * 16 + i; // 0 through 63 or 95
this->subBand = chNum % 8; // keep track of configured subband in case we must reset the channels this->subBand = chNum / 8 + 1; // save configured subband in case we must reset the channels (1-based)
chnl.enabled = true; chnl.enabled = true;
chnl.idx = chNum; chnl.idx = chNum;
chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep; chnl.freq = this->band->txSpans[0].freqStart + chNum*this->band->txSpans[0].freqStep;

View file

@ -833,7 +833,7 @@ class LoRaWANNode {
bool isMACPayload = false; bool isMACPayload = false;
// save the selected sub-band in case this must be restored in ADR control // save the selected sub-band in case this must be restored in ADR control
int8_t subBand = -1; uint8_t subBand = 0;
#if !defined(RADIOLIB_EEPROM_UNSUPPORTED) #if !defined(RADIOLIB_EEPROM_UNSUPPORTED)
/*! /*!
@ -852,7 +852,7 @@ class LoRaWANNode {
void clearSession(); void clearSession();
// test if saved keys are non-zero // test if saved keys are non-zero
bool isActiveSession(); bool isValidSession();
#endif #endif
// wait for, open and listen during Rx1 and Rx2 windows; only performs listening // wait for, open and listen during Rx1 and Rx2 windows; only performs listening