From e9b2e91e6feeaf594d45c5acfcbb571a20042fa2 Mon Sep 17 00:00:00 2001 From: Terry Moore Date: Mon, 5 Jul 2021 10:58:14 -0400 Subject: [PATCH] Fix #169: Fix #172: Fix #173: check size and tag of SessionChannelMask --- src/Arduino_LoRaWAN.h | 8 +- src/lib/arduino_lorawan_sessionstate.cpp | 197 +++++++++++++---------- 2 files changed, 117 insertions(+), 88 deletions(-) diff --git a/src/Arduino_LoRaWAN.h b/src/Arduino_LoRaWAN.h index feea68e..3dabfb6 100644 --- a/src/Arduino_LoRaWAN.h +++ b/src/Arduino_LoRaWAN.h @@ -194,10 +194,10 @@ class Arduino_LoRaWAN struct SessionChannelMask_Header { - enum eMaskKind : uint8_t { kEUlike = 0, kUSlike = 1 }; + enum eMaskKind : uint8_t { kEUlike = 0, kUSlike = 1, kCNlike = 2 }; uint8_t Tag; ///< discriminator, eMaskKind. - uint8_t Size; ///< size of SessionChannelMask, in bytes + uint8_t Size; ///< size of actual SessionChannelMask, in bytes }; template @@ -541,7 +541,9 @@ class Arduino_LoRaWAN { SessionStateHeader Header; SessionStateV1 V1; + bool isValid() const; } SessionState; + /* || the constructor. */ @@ -677,6 +679,8 @@ class Arduino_LoRaWAN uint8_t *pBuf ); + bool IsValidState(const SessionState &state) const; + // return true iff network seems to be provisioned. Make // it virtual so it can be overridden if needed. virtual bool IsProvisioned(void) diff --git a/src/lib/arduino_lorawan_sessionstate.cpp b/src/lib/arduino_lorawan_sessionstate.cpp index 9cbde19..098187b 100644 --- a/src/lib/arduino_lorawan_sessionstate.cpp +++ b/src/lib/arduino_lorawan_sessionstate.cpp @@ -257,6 +257,40 @@ Name: Arduino_LoRaWAN::ApplySessionState() */ +bool Arduino_LoRaWAN::IsValidState(const Arduino_LoRaWAN::SessionState &state) const + { + // do not apply the session state unless it roughly matches our configuration. + if (! state.isValid()) + return false; + + // make sure region and country match. TODO: make sure network matches. + if (! (Arduino_LoRaWAN::Region(state.V1.Region) == this->GetRegion() && + state.V1.Country == uint16_t(this->GetCountryCode()))) + return false; + + // it matches! + return true; + } + +bool Arduino_LoRaWAN::SessionState::isValid() const + { + if (! (this->Header.Tag == kSessionStateTag_V1 && + this->Header.Size == sizeof(*this))) + return false; + + switch (this->V1.Channels.Header.Tag) + { + case Arduino_LoRaWAN::SessionChannelMask_Header::eMaskKind::kEUlike: + return this->V1.Channels.Header.Size == sizeof(this->V1.Channels.EUlike); + + case Arduino_LoRaWAN::SessionChannelMask_Header::eMaskKind::kUSlike: + return this->V1.Channels.Header.Size == sizeof(this->V1.Channels.USlike); + + default: + return false; + } + } + #define FUNCTION "Arduino_LoRaWAN::ApplySessionState" bool @@ -265,124 +299,115 @@ Arduino_LoRaWAN::ApplySessionState( ) { // do not apply the session state unless it roughly matches our configuration. - if (State.Header.Tag == kSessionStateTag_V1 && - Arduino_LoRaWAN::Region(State.V1.Region) == this->GetRegion() && - State.V1.Country == uint16_t(this->GetCountryCode()) - ) - { - auto const tNow = os_getTime(); + if (! this->IsValidState(State)) + return false; - // record that we've done it. - this->m_savedSessionState = State; + auto const tNow = os_getTime(); + + // record that we've done it. + this->m_savedSessionState = State; - // set FcntUp, FcntDown, and session state - LMIC.datarate = State.V1.LinkDR; + // set FcntUp, FcntDown, and session state + LMIC.datarate = State.V1.LinkDR; - // set the uplink and downlink count - LMIC.seqnoDn = State.V1.FCntDown; - LMIC.seqnoUp = State.V1.FCntUp; + // set the uplink and downlink count + LMIC.seqnoDn = State.V1.FCntDown; + LMIC.seqnoUp = State.V1.FCntUp; - // - // TODO(tmm@mcci.com): State.V1.gpsTime can be used to tweak the saved cycle - // time and also as a fallback if the system clock is not robust. but right - // now we ignore it. - // + // + // TODO(tmm@mcci.com): State.V1.gpsTime can be used to tweak the saved cycle + // time and also as a fallback if the system clock is not robust. but right + // now we ignore it. + // - // conservatively set the global avail time. - LMIC.globalDutyAvail = tNow + State.V1.globalAvail; + // conservatively set the global avail time. + LMIC.globalDutyAvail = tNow + State.V1.globalAvail; - // set the Rx2 frequency - LMIC.dn2Freq = State.V1.Rx2Frequency; + // set the Rx2 frequency + LMIC.dn2Freq = State.V1.Rx2Frequency; #if !defined(DISABLE_PING) - // set the ping frequency - LMIC.ping.freq = State.V1.PingFrequency; + // set the ping frequency + LMIC.ping.freq = State.V1.PingFrequency; #endif - LMIC.adrAckReq = State.V1.LinkIntegrity; - LMIC.adrTxPow = State.V1.TxPower; - LMIC.upRepeat = State.V1.Redundancy; - LMIC.globalDutyRate = State.V1.DutyCycle; - LMIC.rx1DrOffset = State.V1.Rx1DRoffset; - LMIC.dn2Dr = State.V1.Rx2DataRate; - LMIC.rxDelay = State.V1.RxDelay; + LMIC.adrAckReq = State.V1.LinkIntegrity; + LMIC.adrTxPow = State.V1.TxPower; + LMIC.upRepeat = State.V1.Redundancy; + LMIC.globalDutyRate = State.V1.DutyCycle; + LMIC.rx1DrOffset = State.V1.Rx1DRoffset; + LMIC.dn2Dr = State.V1.Rx2DataRate; + LMIC.rxDelay = State.V1.RxDelay; #if LMIC_ENABLE_TxParamSetupReq - LMIC.txParam = State.V1.TxParam; + LMIC.txParam = State.V1.TxParam; #endif #if !defined(DISABLE_BEACONS) - LMIC.bcnChnl = State.V1.BeaconChannel; + LMIC.bcnChnl = State.V1.BeaconChannel; #endif #if !defined(DISABLE_PING) - LMIC.ping.dr = State.V1.PingDr; + LMIC.ping.dr = State.V1.PingDr; #endif - LMIC.dn2Ans = State.V1.MacRxParamAns; - LMIC.macDlChannelAns = State.V1.MacDlChannelAns; - LMIC.macRxTimingSetupAns = State.V1.MacRxTimingSetupAns; + LMIC.dn2Ans = State.V1.MacRxParamAns; + LMIC.macDlChannelAns = State.V1.MacDlChannelAns; + LMIC.macRxTimingSetupAns = State.V1.MacRxTimingSetupAns; #if CFG_LMIC_EU_like - // don't turn off bits: user can't fool us here. - // we can get the immutable channels from the - // channelMap value after reset. - auto const resetMap = LMIC.channelMap; - auto const & euLike = State.V1.Channels.EUlike; - LMIC.channelMap |= euLike.ChannelMap; + // don't turn off bits: user can't fool us here. + // we can get the immutable channels from the + // channelMap value after reset. + auto const resetMap = LMIC.channelMap; + auto const & euLike = State.V1.Channels.EUlike; + LMIC.channelMap |= euLike.ChannelMap; #if ARDUINO_LMIC_VERSION_COMPARE_GE(ARDUINO_LMIC_VERSION, ARDUINO_LMIC_VERSION_CALC(3,99,0,1)) - LMIC.channelShuffleMap = euLike.ChannelShuffleMap; + LMIC.channelShuffleMap = euLike.ChannelShuffleMap; #endif - for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) + for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) + { + if ((resetMap & (decltype(resetMap)(1) << ch)) == 0) { - if ((resetMap & (decltype(resetMap)(1) << ch)) == 0) - { - // copy data -- note that the saved band number is encoded - LMIC_setupChannel( - ch, - euLike.getFrequency(euLike.UplinkFreq, ch), - euLike.ChannelDrMap[ch], - euLike.getBand(ch) - ); + // copy data -- note that the saved band number is encoded + LMIC_setupChannel( + ch, + euLike.getFrequency(euLike.UplinkFreq, ch), + euLike.ChannelDrMap[ch], + euLike.getBand(ch) + ); #if !defined(DISABLE_MCMD_DlChannelReq) - LMIC.channelDlFreq[ch] = euLike.getFrequency(euLike.DownlinkFreq, ch); + LMIC.channelDlFreq[ch] = euLike.getFrequency(euLike.DownlinkFreq, ch); #endif - } } + } - for (unsigned band = 0; band < MAX_BANDS; ++band) - { - LMIC.bands[band].txcap = euLike.Bands[band].txDutyDenom; - LMIC.bands[band].txpow = euLike.Bands[band].txPower; - LMIC.bands[band].lastchnl = euLike.Bands[band].lastChannel; - // Heuristic; we don't know how long has passed since we saved - // this, because we don't currently have GPS time available. - // Conservatively reserve time from now. - LMIC.bands[band].avail = tNow + euLike.Bands[band].ostimeAvail; - } + for (unsigned band = 0; band < MAX_BANDS; ++band) + { + LMIC.bands[band].txcap = euLike.Bands[band].txDutyDenom; + LMIC.bands[band].txpow = euLike.Bands[band].txPower; + LMIC.bands[band].lastchnl = euLike.Bands[band].lastChannel; + // Heuristic; we don't know how long has passed since we saved + // this, because we don't currently have GPS time available. + // Conservatively reserve time from now. + LMIC.bands[band].avail = tNow + euLike.Bands[band].ostimeAvail; + } #elif CFG_LMIC_US_like # if ARDUINO_LMIC_VERSION_COMPARE_GE(ARDUINO_LMIC_VERSION, ARDUINO_LMIC_VERSION_CALC(3,99,0,1)) - static_assert(sizeof(LMIC.channelShuffleMap) == sizeof(State.V1.Channels.USlike.ChannelShuffleMap), - "shuffle map doesn't match"); - // copy the shuffle map bits - memcpy(LMIC.channelShuffleMap, State.V1.Channels.USlike.ChannelShuffleMap, sizeof(LMIC.channelShuffleMap)); + static_assert(sizeof(LMIC.channelShuffleMap) == sizeof(State.V1.Channels.USlike.ChannelShuffleMap), + "shuffle map doesn't match"); + // copy the shuffle map bits + memcpy(LMIC.channelShuffleMap, State.V1.Channels.USlike.ChannelShuffleMap, sizeof(LMIC.channelShuffleMap)); # endif - // copy the enabled states - for (unsigned ch = 0; ch < State.V1.Channels.USlike.nCh; ++ch) - { - const bool state = State.V1.Channels.USlike.isEnabled(ch); - - if (state) - LMIC_enableChannel(ch); - else - LMIC_disableChannel(ch); - } -#endif - - return true; - } - else + // copy the enabled states + for (unsigned ch = 0; ch < State.V1.Channels.USlike.nCh; ++ch) { - return false; + const bool state = State.V1.Channels.USlike.isEnabled(ch); + + if (state) + LMIC_enableChannel(ch); + else + LMIC_disableChannel(ch); } +#endif } #undef FUNCTION