[LoRaWAN] Separate begin() and activate()
This commit is contained in:
parent
b7748206a2
commit
43fb48a267
4 changed files with 169 additions and 99 deletions
|
@ -319,8 +319,10 @@ setBufferNonces KEYWORD2
|
||||||
getBufferSession KEYWORD2
|
getBufferSession KEYWORD2
|
||||||
setBufferSession KEYWORD2
|
setBufferSession KEYWORD2
|
||||||
beginOTAA KEYWORD2
|
beginOTAA KEYWORD2
|
||||||
|
activateOTAA KEYWORD2
|
||||||
beginABP KEYWORD2
|
beginABP KEYWORD2
|
||||||
isJoined KEYWORD2
|
activateABP KEYWORD2
|
||||||
|
isActivated KEYWORD2
|
||||||
sendMacCommandReq KEYWORD2
|
sendMacCommandReq KEYWORD2
|
||||||
uplink KEYWORD2
|
uplink KEYWORD2
|
||||||
downlink KEYWORD2
|
downlink KEYWORD2
|
||||||
|
|
|
@ -573,6 +573,11 @@
|
||||||
*/
|
*/
|
||||||
#define RADIOLIB_LORAWAN_NEW_SESSION (-1118)
|
#define RADIOLIB_LORAWAN_NEW_SESSION (-1118)
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief The supplied Nonces buffer is discarded as its activation information is invalid.
|
||||||
|
*/
|
||||||
|
#define RADIOLIB_LORAWAN_NONCES_DISCARDED (-1119)
|
||||||
|
|
||||||
// LR11x0-specific status codes
|
// LR11x0-specific status codes
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -62,7 +62,7 @@ uint8_t* LoRaWANNode::getBufferNonces() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) {
|
int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) {
|
||||||
if(this->isJoined()) {
|
if(this->isActivated()) {
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active");
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active");
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
@ -70,6 +70,20 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) {
|
||||||
int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE);
|
int16_t state = LoRaWANNode::checkBufferCommon(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE);
|
||||||
RADIOLIB_ASSERT(state);
|
RADIOLIB_ASSERT(state);
|
||||||
|
|
||||||
|
bool isSameKeys = LoRaWANNode::ntoh<uint16_t>(&persistentBuffer[RADIOLIB_LW_NONCES_CHECKSUM]) == this->keyCheckSum;
|
||||||
|
bool isSameMode = LoRaWANNode::ntoh<uint16_t>(&persistentBuffer[RADIOLIB_LW_NONCES_MODE]) == this->lwMode;
|
||||||
|
bool isSameClass = LoRaWANNode::ntoh<uint8_t>(&persistentBuffer[RADIOLIB_LW_NONCES_CLASS]) == this->lwClass;
|
||||||
|
bool isSamePlan = LoRaWANNode::ntoh<uint8_t>(&persistentBuffer[RADIOLIB_LW_NONCES_PLAN]) == this->band->bandNum;
|
||||||
|
|
||||||
|
// check if Nonces buffer matches the current configuration
|
||||||
|
if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) {
|
||||||
|
// if configuration did not match, discard whatever is currently in the buffers and start fresh
|
||||||
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (keys: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan);
|
||||||
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Discarding the Nonces buffer:");
|
||||||
|
RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE);
|
||||||
|
return(RADIOLIB_LORAWAN_NONCES_DISCARDED);
|
||||||
|
}
|
||||||
|
|
||||||
// copy the whole buffer over
|
// copy the whole buffer over
|
||||||
memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE);
|
memcpy(this->bufferNonces, persistentBuffer, RADIOLIB_LW_NONCES_BUF_SIZE);
|
||||||
|
|
||||||
|
@ -78,6 +92,7 @@ int16_t LoRaWANNode::setBufferNonces(uint8_t* persistentBuffer) {
|
||||||
|
|
||||||
// revert to inactive as long as no session is restored
|
// revert to inactive as long as no session is restored
|
||||||
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false;
|
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false;
|
||||||
|
this->isActive = false;
|
||||||
|
|
||||||
return(state);
|
return(state);
|
||||||
}
|
}
|
||||||
|
@ -102,7 +117,7 @@ uint8_t* LoRaWANNode::getBufferSession() {
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) {
|
int16_t LoRaWANNode::setBufferSession(uint8_t* persistentBuffer) {
|
||||||
if(this->isJoined()) {
|
if(this->isActivated()) {
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active");
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Did not update buffer: session already active");
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
@ -279,26 +294,7 @@ int16_t LoRaWANNode::checkBufferCommon(uint8_t *buffer, uint16_t size) {
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaWANNode::verifyBuffers(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan) {
|
void LoRaWANNode::activateCommon(uint8_t initialDr) {
|
||||||
bool isSameKeys = LoRaWANNode::ntoh<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM]) == checkSum;
|
|
||||||
bool isSameMode = LoRaWANNode::ntoh<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE]) == lwMode;
|
|
||||||
bool isSameClass = LoRaWANNode::ntoh<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS]) == lwClass;
|
|
||||||
bool isSamePlan = LoRaWANNode::ntoh<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN]) == freqPlan;
|
|
||||||
|
|
||||||
// check if Nonces buffer matches the current configuration
|
|
||||||
if(!isSameKeys || !isSameMode || !isSameClass || !isSamePlan) {
|
|
||||||
// if configuration did not match, discard whatever is currently in the buffers and start fresh
|
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Configuration mismatch (checksum: %d, mode: %d, class: %d, plan: %d)", isSameKeys, isSameMode, isSameClass, isSamePlan);
|
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("Nonces buffer:");
|
|
||||||
RADIOLIB_DEBUG_PROTOCOL_HEXDUMP(this->bufferNonces, RADIOLIB_LW_NONCES_BUF_SIZE);
|
|
||||||
return(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
return(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void LoRaWANNode::beginCommon(uint8_t initialDr) {
|
|
||||||
uint8_t drUp = 0;
|
uint8_t drUp = 0;
|
||||||
if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) {
|
if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) {
|
||||||
// if join datarate is user-specified and valid, select that value
|
// if join datarate is user-specified and valid, select that value
|
||||||
|
@ -437,28 +433,48 @@ void LoRaWANNode::beginCommon(uint8_t initialDr) {
|
||||||
(void)execMacCommand(&cmd);
|
(void)execMacCommand(&cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force, uint8_t joinDr) {
|
void LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey) {
|
||||||
|
this->joinEUI = joinEUI;
|
||||||
|
this->devEUI = devEUI;
|
||||||
|
memcpy(this->nwkKey, nwkKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
|
memcpy(this->appKey, appKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
|
|
||||||
// generate activation key checksum
|
// generate activation key checksum
|
||||||
uint16_t checkSum = 0;
|
this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&joinEUI), 8);
|
||||||
checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&joinEUI), 8);
|
this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&devEUI), 8);
|
||||||
checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&devEUI), 8);
|
this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkKey, 16);
|
||||||
checkSum ^= LoRaWANNode::checkSum16(nwkKey, 16);
|
this->keyCheckSum ^= LoRaWANNode::checkSum16(appKey, 16);
|
||||||
checkSum ^= LoRaWANNode::checkSum16(appKey, 16);
|
|
||||||
|
|
||||||
// if the supplied activation info doesn't match the restored buffers, discard all contents of previous session
|
this->lwMode = RADIOLIB_LW_MODE_OTAA;
|
||||||
if(!this->verifyBuffers(checkSum, RADIOLIB_LW_MODE_OTAA, RADIOLIB_LW_CLASS_A, this->band->bandNum)) {
|
this->lwClass = RADIOLIB_LW_CLASS_A;
|
||||||
this->wipe();
|
}
|
||||||
|
|
||||||
|
int16_t LoRaWANNode::activateOTAA(bool force, uint8_t joinDr, LoRaWANJoinEvent_t *joinEvent) {
|
||||||
|
// if not forced by the user, check if there is an active session
|
||||||
|
if(!force) {
|
||||||
|
if(this->isActivated()) {
|
||||||
|
// already activated, don't do anything
|
||||||
|
return(RADIOLIB_ERR_NONE);
|
||||||
}
|
}
|
||||||
|
if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) {
|
||||||
// if the device is activated with a valid session, and user didn't force a new session, return
|
// session restored but not yet activated - do so now
|
||||||
if(this->isJoined() && !force) {
|
this->isActive = true;
|
||||||
return(RADIOLIB_LORAWAN_SESSION_RESTORED);
|
return(RADIOLIB_LORAWAN_SESSION_RESTORED);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int16_t state = RADIOLIB_ERR_UNKNOWN;
|
int16_t state = RADIOLIB_ERR_UNKNOWN;
|
||||||
|
|
||||||
// either no valid session was found or user forced a new session, so set active-bit to false
|
// either no valid session was found or user forced a new session, so set active-bit to false
|
||||||
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false;
|
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false;
|
||||||
|
this->isActive = false;
|
||||||
|
|
||||||
|
// starting a new session, so make sure to update event fields already
|
||||||
|
if(joinEvent) {
|
||||||
|
joinEvent->newSession = true;
|
||||||
|
joinEvent->devNonce = this->devNonce;
|
||||||
|
joinEvent->joinNonce = this->joinNonce;
|
||||||
|
}
|
||||||
|
|
||||||
// setup join-request uplink/downlink frequencies and datarates
|
// setup join-request uplink/downlink frequencies and datarates
|
||||||
if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) {
|
if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) {
|
||||||
|
@ -474,7 +490,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
joinDr = RADIOLIB_LW_DATA_RATE_UNUSED;
|
joinDr = RADIOLIB_LW_DATA_RATE_UNUSED;
|
||||||
}
|
}
|
||||||
// setup all MAC properties to default values
|
// setup all MAC properties to default values
|
||||||
this->beginCommon(joinDr);
|
this->activateCommon(joinDr);
|
||||||
|
|
||||||
// select a random pair of Tx/Rx channels
|
// select a random pair of Tx/Rx channels
|
||||||
state = this->selectChannels();
|
state = this->selectChannels();
|
||||||
|
@ -492,12 +508,12 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
|
|
||||||
// set the packet fields
|
// set the packet fields
|
||||||
joinRequestMsg[0] = RADIOLIB_LW_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LW_MHDR_MAJOR_R1;
|
joinRequestMsg[0] = RADIOLIB_LW_MHDR_MTYPE_JOIN_REQUEST | RADIOLIB_LW_MHDR_MAJOR_R1;
|
||||||
LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS], joinEUI);
|
LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_JOIN_EUI_POS], this->joinEUI);
|
||||||
LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS], devEUI);
|
LoRaWANNode::hton<uint64_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_EUI_POS], this->devEUI);
|
||||||
LoRaWANNode::hton<uint16_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed);
|
LoRaWANNode::hton<uint16_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_DEV_NONCE_POS], devNonceUsed);
|
||||||
|
|
||||||
// add the authentication code
|
// add the authentication code
|
||||||
uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t), nwkKey);
|
uint32_t mic = this->generateMIC(joinRequestMsg, RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t), this->nwkKey);
|
||||||
LoRaWANNode::hton<uint32_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic);
|
LoRaWANNode::hton<uint32_t>(&joinRequestMsg[RADIOLIB_LW_JOIN_REQUEST_LEN - sizeof(uint32_t)], mic);
|
||||||
|
|
||||||
// send it
|
// send it
|
||||||
|
@ -548,7 +564,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
// the first byte is the MAC header which is not encrypted
|
// the first byte is the MAC header which is not encrypted
|
||||||
uint8_t joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN];
|
uint8_t joinAcceptMsg[RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN];
|
||||||
joinAcceptMsg[0] = joinAcceptMsgEnc[0];
|
joinAcceptMsg[0] = joinAcceptMsgEnc[0];
|
||||||
RadioLibAES128Instance.init(nwkKey);
|
RadioLibAES128Instance.init(this->nwkKey);
|
||||||
RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]);
|
RadioLibAES128Instance.encryptECB(&joinAcceptMsgEnc[1], RADIOLIB_LW_JOIN_ACCEPT_MAX_LEN - 1, &joinAcceptMsg[1]);
|
||||||
|
|
||||||
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:");
|
RADIOLIB_DEBUG_PROTOCOL_PRINTLN("joinAcceptMsg:");
|
||||||
|
@ -577,14 +593,14 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
// 1.1 version, first we need to derive the join accept integrity key
|
// 1.1 version, first we need to derive the join accept integrity key
|
||||||
uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
|
uint8_t keyDerivationBuff[RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
|
||||||
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_JS_INT_KEY;
|
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_JS_INT_KEY;
|
||||||
LoRaWANNode::hton<uint64_t>(&keyDerivationBuff[1], devEUI);
|
LoRaWANNode::hton<uint64_t>(&keyDerivationBuff[1], this->devEUI);
|
||||||
RadioLibAES128Instance.init(nwkKey);
|
RadioLibAES128Instance.init(this->nwkKey);
|
||||||
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->jSIntKey);
|
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->jSIntKey);
|
||||||
|
|
||||||
// prepare the buffer for MIC calculation
|
// prepare the buffer for MIC calculation
|
||||||
uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
|
uint8_t micBuff[3*RADIOLIB_AES128_BLOCK_SIZE] = { 0 };
|
||||||
micBuff[0] = RADIOLIB_LW_JOIN_REQUEST_TYPE;
|
micBuff[0] = RADIOLIB_LW_JOIN_REQUEST_TYPE;
|
||||||
LoRaWANNode::hton<uint64_t>(&micBuff[1], joinEUI);
|
LoRaWANNode::hton<uint64_t>(&micBuff[1], this->joinEUI);
|
||||||
LoRaWANNode::hton<uint16_t>(&micBuff[9], devNonceUsed);
|
LoRaWANNode::hton<uint16_t>(&micBuff[9], devNonceUsed);
|
||||||
memcpy(&micBuff[11], joinAcceptMsg, lenRx);
|
memcpy(&micBuff[11], joinAcceptMsg, lenRx);
|
||||||
|
|
||||||
|
@ -594,7 +610,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
// 1.0 version
|
// 1.0 version
|
||||||
if(!verifyMIC(joinAcceptMsg, lenRx, nwkKey)) {
|
if(!verifyMIC(joinAcceptMsg, lenRx, this->nwkKey)) {
|
||||||
return(RADIOLIB_ERR_CRC_MISMATCH);
|
return(RADIOLIB_ERR_CRC_MISMATCH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -635,23 +651,23 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
// check protocol version (1.0 vs 1.1)
|
// check protocol version (1.0 vs 1.1)
|
||||||
if(this->rev == 1) {
|
if(this->rev == 1) {
|
||||||
// 1.1 version, derive the keys
|
// 1.1 version, derive the keys
|
||||||
LoRaWANNode::hton<uint64_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS], joinEUI);
|
LoRaWANNode::hton<uint64_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_JOIN_EUI_POS], this->joinEUI);
|
||||||
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed);
|
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_NONCE_POS], devNonceUsed);
|
||||||
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY;
|
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY;
|
||||||
|
|
||||||
RadioLibAES128Instance.init(appKey);
|
RadioLibAES128Instance.init(this->appKey);
|
||||||
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey);
|
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey);
|
||||||
|
|
||||||
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY;
|
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY;
|
||||||
RadioLibAES128Instance.init(nwkKey);
|
RadioLibAES128Instance.init(this->nwkKey);
|
||||||
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey);
|
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey);
|
||||||
|
|
||||||
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_S_NWK_S_INT_KEY;
|
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_S_NWK_S_INT_KEY;
|
||||||
RadioLibAES128Instance.init(nwkKey);
|
RadioLibAES128Instance.init(this->nwkKey);
|
||||||
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey);
|
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->sNwkSIntKey);
|
||||||
|
|
||||||
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_NWK_S_ENC_KEY;
|
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_NWK_S_ENC_KEY;
|
||||||
RadioLibAES128Instance.init(nwkKey);
|
RadioLibAES128Instance.init(this->nwkKey);
|
||||||
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey);
|
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->nwkSEncKey);
|
||||||
|
|
||||||
// enqueue the RekeyInd MAC command to be sent in the next uplink
|
// enqueue the RekeyInd MAC command to be sent in the next uplink
|
||||||
|
@ -669,11 +685,11 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3);
|
LoRaWANNode::hton<uint32_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_HOME_NET_ID_POS], this->homeNetId, 3);
|
||||||
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed);
|
LoRaWANNode::hton<uint16_t>(&keyDerivationBuff[RADIOLIB_LW_JOIN_ACCEPT_DEV_ADDR_POS], devNonceUsed);
|
||||||
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY;
|
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_APP_S_KEY;
|
||||||
RadioLibAES128Instance.init(nwkKey);
|
RadioLibAES128Instance.init(this->nwkKey);
|
||||||
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey);
|
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->appSKey);
|
||||||
|
|
||||||
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY;
|
keyDerivationBuff[0] = RADIOLIB_LW_JOIN_ACCEPT_F_NWK_S_INT_KEY;
|
||||||
RadioLibAES128Instance.init(nwkKey);
|
RadioLibAES128Instance.init(this->nwkKey);
|
||||||
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey);
|
RadioLibAES128Instance.encryptECB(keyDerivationBuff, RADIOLIB_AES128_BLOCK_SIZE, this->fNwkSIntKey);
|
||||||
|
|
||||||
memcpy(this->sNwkSIntKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
|
memcpy(this->sNwkSIntKey, this->fNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
|
@ -694,7 +710,7 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_OTAA);
|
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_OTAA);
|
||||||
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A);
|
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A);
|
||||||
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum);
|
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum);
|
||||||
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], checkSum);
|
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], this->keyCheckSum);
|
||||||
LoRaWANNode::hton<uint32_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], this->joinNonce, 3);
|
LoRaWANNode::hton<uint32_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_JOIN_NONCE], this->joinNonce, 3);
|
||||||
|
|
||||||
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true;
|
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true;
|
||||||
|
@ -710,39 +726,24 @@ int16_t LoRaWANNode::beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKe
|
||||||
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
||||||
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
||||||
|
|
||||||
// copy the signature of the Nonces buffer over to the Session buffer
|
// set the signature of the Nonces buffer in the Session buffer
|
||||||
uint16_t noncesSignature = LoRaWANNode::ntoh<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE]);
|
LoRaWANNode::hton<uint16_t>(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], signature);
|
||||||
LoRaWANNode::hton<uint16_t>(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], noncesSignature);
|
|
||||||
|
|
||||||
// store network parameters
|
// store network parameters
|
||||||
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId);
|
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId);
|
||||||
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev);
|
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev);
|
||||||
|
|
||||||
|
this->isActive = true;
|
||||||
|
|
||||||
|
// received join-accept, so update JoinNonce value in event
|
||||||
|
if(joinEvent) {
|
||||||
|
joinEvent->joinNonce = this->joinNonce;
|
||||||
|
}
|
||||||
|
|
||||||
return(RADIOLIB_LORAWAN_NEW_SESSION);
|
return(RADIOLIB_LORAWAN_NEW_SESSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force, uint8_t initialDr) {
|
void LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey) {
|
||||||
// generate activation key checksum
|
|
||||||
uint16_t checkSum = 0;
|
|
||||||
checkSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&addr), 4);
|
|
||||||
checkSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16);
|
|
||||||
checkSum ^= LoRaWANNode::checkSum16(appSKey, 16);
|
|
||||||
if(fNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); }
|
|
||||||
if(sNwkSIntKey) { checkSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); }
|
|
||||||
|
|
||||||
// if the supplied activation info doesn't match the restored buffers, discard all contents of previous session
|
|
||||||
if(!this->verifyBuffers(checkSum, RADIOLIB_LW_MODE_OTAA, RADIOLIB_LW_CLASS_A, this->band->bandNum)) {
|
|
||||||
this->wipe();
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the device is activated with a valid session, and user didn't force a new session, return
|
|
||||||
if(this->isJoined() && !force) {
|
|
||||||
return(RADIOLIB_ERR_NONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
// either no valid session was found or user forced a new session, so set active-bit to false
|
|
||||||
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false;
|
|
||||||
|
|
||||||
this->devAddr = addr;
|
this->devAddr = addr;
|
||||||
memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE);
|
memcpy(this->appSKey, appSKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE);
|
memcpy(this->nwkSEncKey, nwkSEncKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
|
@ -756,6 +757,35 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk
|
||||||
memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
|
memcpy(this->sNwkSIntKey, sNwkSIntKey, RADIOLIB_AES128_KEY_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// generate activation key checksum
|
||||||
|
this->keyCheckSum ^= LoRaWANNode::checkSum16(reinterpret_cast<uint8_t*>(&addr), 4);
|
||||||
|
this->keyCheckSum ^= LoRaWANNode::checkSum16(nwkSEncKey, 16);
|
||||||
|
this->keyCheckSum ^= LoRaWANNode::checkSum16(appSKey, 16);
|
||||||
|
if(fNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(fNwkSIntKey, 16); }
|
||||||
|
if(sNwkSIntKey) { this->keyCheckSum ^= LoRaWANNode::checkSum16(sNwkSIntKey, 16); }
|
||||||
|
|
||||||
|
this->lwMode = RADIOLIB_LW_MODE_ABP;
|
||||||
|
this->lwClass = RADIOLIB_LW_CLASS_A;
|
||||||
|
}
|
||||||
|
|
||||||
|
int16_t LoRaWANNode::activateABP(bool force, uint8_t initialDr) {
|
||||||
|
// if not forced by the user, check if there is an active session
|
||||||
|
if(!force) {
|
||||||
|
if(this->isActivated()) {
|
||||||
|
// already activated, don't do anything
|
||||||
|
return(RADIOLIB_ERR_NONE);
|
||||||
|
}
|
||||||
|
if(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]) {
|
||||||
|
// session restored but not yet activated - do so now
|
||||||
|
this->isActive = true;
|
||||||
|
return(RADIOLIB_LORAWAN_SESSION_RESTORED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// either no valid session was found or user forced a new session, so set active-bit to false
|
||||||
|
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)false;
|
||||||
|
this->isActive = false;
|
||||||
|
|
||||||
// setup the uplink/downlink channels and initial datarate
|
// setup the uplink/downlink channels and initial datarate
|
||||||
if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) {
|
if(this->band->bandType == RADIOLIB_LW_BAND_DYNAMIC) {
|
||||||
this->setupChannelsDyn();
|
this->setupChannelsDyn();
|
||||||
|
@ -764,7 +794,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk
|
||||||
}
|
}
|
||||||
|
|
||||||
// setup all MAC properties to default values
|
// setup all MAC properties to default values
|
||||||
this->beginCommon(initialDr);
|
this->activateCommon(initialDr);
|
||||||
|
|
||||||
// reset all frame counters
|
// reset all frame counters
|
||||||
this->fCntUp = 0;
|
this->fCntUp = 0;
|
||||||
|
@ -779,7 +809,7 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk
|
||||||
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_ABP);
|
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_MODE], RADIOLIB_LW_MODE_ABP);
|
||||||
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A);
|
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CLASS], RADIOLIB_LW_CLASS_A);
|
||||||
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum);
|
LoRaWANNode::hton<uint8_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_PLAN], this->band->bandNum);
|
||||||
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], checkSum);
|
LoRaWANNode::hton<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_CHECKSUM], this->keyCheckSum);
|
||||||
|
|
||||||
// new session all good, so set active-bit to true
|
// new session all good, so set active-bit to true
|
||||||
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true;
|
this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE] = (uint8_t)true;
|
||||||
|
@ -795,19 +825,18 @@ int16_t LoRaWANNode::beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwk
|
||||||
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_FNWK_SINT_KEY], this->fNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
||||||
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
memcpy(&this->bufferSession[RADIOLIB_LW_SESSION_SNWK_SINT_KEY], this->sNwkSIntKey, RADIOLIB_AES128_BLOCK_SIZE);
|
||||||
|
|
||||||
// copy the signature of the Nonces buffer over to the Session buffer
|
// set the signature of the Nonces buffer in the Session buffer
|
||||||
uint16_t noncesSignature = LoRaWANNode::ntoh<uint16_t>(&this->bufferNonces[RADIOLIB_LW_NONCES_SIGNATURE]);
|
LoRaWANNode::hton<uint16_t>(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], signature);
|
||||||
LoRaWANNode::hton<uint16_t>(&this->bufferSession[RADIOLIB_LW_SESSION_NONCES_SIGNATURE], noncesSignature);
|
|
||||||
|
|
||||||
// store network parameters
|
// store network parameters
|
||||||
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId);
|
LoRaWANNode::hton<uint32_t>(&this->bufferSession[RADIOLIB_LW_SESSION_HOMENET_ID], this->homeNetId);
|
||||||
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev);
|
LoRaWANNode::hton<uint8_t>(&this->bufferSession[RADIOLIB_LW_SESSION_VERSION], this->rev);
|
||||||
|
|
||||||
return(RADIOLIB_ERR_NONE);
|
return(RADIOLIB_LORAWAN_NEW_SESSION);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LoRaWANNode::isJoined() {
|
bool LoRaWANNode::isActivated() {
|
||||||
return(this->bufferNonces[RADIOLIB_LW_NONCES_ACTIVE]);
|
return(this->isActive);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(RADIOLIB_BUILD_ARDUINO)
|
#if defined(RADIOLIB_BUILD_ARDUINO)
|
||||||
|
@ -822,7 +851,7 @@ int16_t LoRaWANNode::uplink(const char* str, uint8_t fPort, bool isConfirmed, Lo
|
||||||
|
|
||||||
int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) {
|
int16_t LoRaWANNode::uplink(uint8_t* data, size_t len, uint8_t fPort, bool isConfirmed, LoRaWANEvent_t* event) {
|
||||||
// if not joined, don't do anything
|
// if not joined, don't do anything
|
||||||
if(!this->isJoined()) {
|
if(!this->isActivated()) {
|
||||||
return(RADIOLIB_ERR_NETWORK_NOT_JOINED);
|
return(RADIOLIB_ERR_NETWORK_NOT_JOINED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -460,6 +460,21 @@ enum LoRaWANBandNum_t {
|
||||||
// array of currently supported bands
|
// array of currently supported bands
|
||||||
extern const LoRaWANBand_t* LoRaWANBands[];
|
extern const LoRaWANBand_t* LoRaWANBands[];
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\struct LoRaWANJoinEvent_t
|
||||||
|
\brief Structure to save extra information about activation event.
|
||||||
|
*/
|
||||||
|
struct LoRaWANJoinEvent_t {
|
||||||
|
/*! \brief Whether a new session was started */
|
||||||
|
bool newSession = false;
|
||||||
|
|
||||||
|
/*! \brief The transmitted Join-Request DevNonce value */
|
||||||
|
uint16_t devNonce = 0;
|
||||||
|
|
||||||
|
/*! \brief The received Join-Request JoinNonce value */
|
||||||
|
uint32_t joinNonce = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\struct LoRaWANEvent_t
|
\struct LoRaWANEvent_t
|
||||||
\brief Structure to save extra information about uplink/downlink event.
|
\brief Structure to save extra information about uplink/downlink event.
|
||||||
|
@ -545,35 +560,46 @@ class LoRaWANNode {
|
||||||
int16_t setBufferSession(uint8_t* persistentBuffer);
|
int16_t setBufferSession(uint8_t* persistentBuffer);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Join network by performing over-the-air activation. By this procedure,
|
\brief Set the device credentials and activation configuration
|
||||||
the device will perform an exchange with the network server and set all necessary configuration.
|
|
||||||
\param joinEUI 8-byte application identifier.
|
\param joinEUI 8-byte application identifier.
|
||||||
\param devEUI 8-byte device identifier.
|
\param devEUI 8-byte device identifier.
|
||||||
\param nwkKey Pointer to the network AES-128 key.
|
\param nwkKey Pointer to the network AES-128 key.
|
||||||
\param appKey Pointer to the application AES-128 key.
|
\param appKey Pointer to the application AES-128 key.
|
||||||
|
*/
|
||||||
|
void beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Join network by restoring OTAA session or performing over-the-air activation. By this procedure,
|
||||||
|
the device will perform an exchange with the network server and set all necessary configuration.
|
||||||
\param force Set to true to force joining even if previously joined.
|
\param force Set to true to force joining even if previously joined.
|
||||||
\param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled)
|
\param joinDr The datarate at which to send the join-request and any subsequent uplinks (unless ADR is enabled)
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t beginOTAA(uint64_t joinEUI, uint64_t devEUI, uint8_t* nwkKey, uint8_t* appKey, bool force = false, uint8_t joinDr = RADIOLIB_LW_DATA_RATE_UNUSED);
|
int16_t activateOTAA(bool force = false, uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED, LoRaWANJoinEvent_t *joinEvent = NULL);
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Join network by performing activation by personalization.
|
\brief Set the device credentials and activation configuration
|
||||||
In this procedure, all necessary configuration must be provided by the user.
|
|
||||||
\param addr Device address.
|
\param addr Device address.
|
||||||
\param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0.
|
\param fNwkSIntKey Pointer to the Forwarding network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0.
|
||||||
\param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0.
|
\param sNwkSIntKey Pointer to the Serving network session (LoRaWAN 1.1), NULL for LoRaWAN 1.0.
|
||||||
\param nwkSEncKey Pointer to the MAC command network session key [NwkSEncKey] (LoRaWAN 1.1)
|
\param nwkSEncKey Pointer to the MAC command network session key [NwkSEncKey] (LoRaWAN 1.1)
|
||||||
or network session AES-128 key [NwkSKey] (LoRaWAN 1.0).
|
or network session AES-128 key [NwkSKey] (LoRaWAN 1.0).
|
||||||
\param appSKey Pointer to the application session AES-128 key.
|
\param appSKey Pointer to the application session AES-128 key.
|
||||||
\param force Set to true to force a new session, even if one exists.
|
*/
|
||||||
|
void beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey);
|
||||||
|
|
||||||
|
/*!
|
||||||
|
\brief Join network by restoring ABP session or performing over-the-air activation.
|
||||||
|
In this procedure, all necessary configuration must be provided by the user.
|
||||||
|
\param force Set to true to force joining even if previously joined.
|
||||||
\param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled)
|
\param initialDr The datarate at which to send the first uplink and any subsequent uplinks (unless ADR is enabled)
|
||||||
\returns \ref status_codes
|
\returns \ref status_codes
|
||||||
*/
|
*/
|
||||||
int16_t beginABP(uint32_t addr, uint8_t* fNwkSIntKey, uint8_t* sNwkSIntKey, uint8_t* nwkSEncKey, uint8_t* appSKey, bool force = false, uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED);
|
int16_t activateABP(bool force = false, uint8_t initialDr = RADIOLIB_LW_DATA_RATE_UNUSED);
|
||||||
|
|
||||||
|
|
||||||
/*! \brief Whether there is an ongoing session active */
|
/*! \brief Whether there is an ongoing session active */
|
||||||
bool isJoined();
|
bool isActivated();
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
\brief Add a MAC command to the uplink queue.
|
\brief Add a MAC command to the uplink queue.
|
||||||
|
@ -838,7 +864,7 @@ class LoRaWANNode {
|
||||||
|
|
||||||
static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size);
|
static int16_t checkBufferCommon(uint8_t *buffer, uint16_t size);
|
||||||
|
|
||||||
void beginCommon(uint8_t initialDr);
|
void activateCommon(uint8_t initialDr);
|
||||||
|
|
||||||
// a buffer that holds all LW base parameters that should persist at all times!
|
// a buffer that holds all LW base parameters that should persist at all times!
|
||||||
uint8_t bufferNonces[RADIOLIB_LW_NONCES_BUF_SIZE] = { 0 };
|
uint8_t bufferNonces[RADIOLIB_LW_NONCES_BUF_SIZE] = { 0 };
|
||||||
|
@ -857,6 +883,15 @@ class LoRaWANNode {
|
||||||
.commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } },
|
.commands = { { .cid = 0, .payload = { 0 }, .len = 0, .repeat = 0, } },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
uint16_t lwMode = RADIOLIB_LW_MODE_NONE;
|
||||||
|
uint8_t lwClass = RADIOLIB_LW_CLASS_A;
|
||||||
|
bool isActive = false;
|
||||||
|
|
||||||
|
uint64_t joinEUI = 0;
|
||||||
|
uint64_t devEUI = 0;
|
||||||
|
uint8_t nwkKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
||||||
|
uint8_t appKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
||||||
|
|
||||||
// the following is either provided by the network server (OTAA)
|
// the following is either provided by the network server (OTAA)
|
||||||
// or directly entered by the user (ABP)
|
// or directly entered by the user (ABP)
|
||||||
uint32_t devAddr = 0;
|
uint32_t devAddr = 0;
|
||||||
|
@ -866,6 +901,8 @@ class LoRaWANNode {
|
||||||
uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
uint8_t nwkSEncKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
||||||
uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
uint8_t jSIntKey[RADIOLIB_AES128_KEY_SIZE] = { 0 };
|
||||||
|
|
||||||
|
uint16_t keyCheckSum = 0;
|
||||||
|
|
||||||
// device-specific parameters, persistent through sessions
|
// device-specific parameters, persistent through sessions
|
||||||
uint16_t devNonce = 0;
|
uint16_t devNonce = 0;
|
||||||
uint32_t joinNonce = 0;
|
uint32_t joinNonce = 0;
|
||||||
|
@ -944,9 +981,6 @@ class LoRaWANNode {
|
||||||
// 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
|
||||||
uint8_t subBand = 0;
|
uint8_t subBand = 0;
|
||||||
|
|
||||||
// check if restored buffers match the supplied activation info
|
|
||||||
bool verifyBuffers(uint16_t checkSum, uint16_t lwMode, uint8_t lwClass, uint8_t freqPlan);
|
|
||||||
|
|
||||||
// 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
|
||||||
int16_t downlinkCommon();
|
int16_t downlinkCommon();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue