/*! * \file NvmCtxMgmt.c * * \brief NVM context management implementation * * \copyright Revised BSD License, see section \ref LICENSE. * * \code * ______ _ * / _____) _ | | * ( (____ _____ ____ _| |_ _____ ____| |__ * \____ \| ___ | (_ _) ___ |/ ___) _ \ * _____) ) ____| | | || |_| ____( (___| | | | * (______/|_____)_|_|_| \__)_____)\____)_| |_| * (C)2013-2017 Semtech * * ___ _____ _ ___ _ _____ ___ ___ ___ ___ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __| * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _| * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___| * embedded.connectivity.solutions=============== * * \endcode * * \author Miguel Luis ( Semtech ) * * \author Gregory Cristian ( Semtech ) * * \author Daniel Jaeckle ( STACKFORCE ) * * \author Johannes Bruder ( STACKFORCE ) */ /** ****************************************************************************** * * Portions COPYRIGHT 2020 STMicroelectronics * * @file NvmCtxMgmt.c * @author MCD Application Team * @brief NVM Context Management definition ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "NvmCtxMgmt.h" /* Private typedef -----------------------------------------------------------*/ #if ( CONTEXT_MANAGEMENT_ENABLED == 1 ) /*! * LoRaMAC Structure holding contexts changed status * in case of a \ref MLME_NVM_CTXS_UPDATE indication. */ typedef union uLoRaMacCtxsUpdateInfo { /*! * Byte-access to the bits */ uint8_t Value; /*! * The according context bit will be set to one * if the context changed or 0 otherwise. */ struct sElements { /*! * Mac core nvm context */ uint8_t Mac : 1; /*! * Region module nvm contexts */ uint8_t Region : 1; /*! * Crypto module context */ uint8_t Crypto : 1; /*! * Secure Element driver context */ uint8_t SecureElement : 1; /*! * MAC commands module context */ uint8_t Commands : 1; /*! * Class B module context */ uint8_t ClassB : 1; /*! * Confirm queue module context */ uint8_t ConfirmQueue : 1; /*! * FCnt Handler module context */ uint8_t FCntHandlerNvmCtx : 1; } Elements; } LoRaMacCtxUpdateStatus_t; #endif /* CONTEXT_MANAGEMENT_ENABLED == 1 */ /* Private define ------------------------------------------------------------*/ /*! * Enables/Disables the context storage management storage at all. Must be enabled for LoRaWAN 1.1.x. * WARNING: Still under development and not tested yet. */ #define CONTEXT_MANAGEMENT_ENABLED 0 /*! * Enables/Disables maximum persistent context storage management. All module contexts will be saved on a non-volatile memory. * WARNING: Still under development and not tested yet. */ #define MAX_PERSISTENT_CTX_MGMT_ENABLED 0 #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) #define NVM_CTX_STORAGE_MASK 0xFF #else /* MAX_PERSISTENT_CTX_MGMT_ENABLED == 0 */ #define NVM_CTX_STORAGE_MASK 0x8C #endif /* MAX_PERSISTENT_CTX_MGMT_ENABLED */ /* Private macro -------------------------------------------------------------*/ /* Private function prototypes -----------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ #if ( CONTEXT_MANAGEMENT_ENABLED == 1 ) static LoRaMacCtxUpdateStatus_t CtxUpdateStatus = { .Value = 0 }; /* * Nvmm handles */ static NvmmDataBlock_t SecureElementNvmCtxDataBlock; static NvmmDataBlock_t CryptoNvmCtxDataBlock; #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) static NvmmDataBlock_t MacNvmCtxDataBlock; static NvmmDataBlock_t RegionNvmCtxDataBlock; static NvmmDataBlock_t CommandsNvmCtxDataBlock; static NvmmDataBlock_t ConfirmQueueNvmCtxDataBlock; static NvmmDataBlock_t ClassBNvmCtxDataBlock; #endif /* MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 */ #endif /* CONTEXT_MANAGEMENT_ENABLED == 1 */ /* Exported functions ---------------------------------------------------------*/ void NvmCtxMgmtEvent(LoRaMacNvmCtxModule_t module) { #if ( CONTEXT_MANAGEMENT_ENABLED == 1 ) switch (module) { case LORAMAC_NVMCTXMODULE_MAC: { CtxUpdateStatus.Elements.Mac = 1; break; } case LORAMAC_NVMCTXMODULE_REGION: { CtxUpdateStatus.Elements.Region = 1; break; } case LORAMAC_NVMCTXMODULE_CRYPTO: { CtxUpdateStatus.Elements.Crypto = 1; break; } case LORAMAC_NVMCTXMODULE_SECURE_ELEMENT: { CtxUpdateStatus.Elements.SecureElement = 1; break; } case LORAMAC_NVMCTXMODULE_COMMANDS: { CtxUpdateStatus.Elements.Commands = 1; break; } case LORAMAC_NVMCTXMODULE_CLASS_B: { CtxUpdateStatus.Elements.ClassB = 1; break; } case LORAMAC_NVMCTXMODULE_CONFIRM_QUEUE: { CtxUpdateStatus.Elements.ConfirmQueue = 1; break; } default: { break; } } #endif /* CONTEXT_MANAGEMENT_ENABLED == 1 */ } NvmCtxMgmtStatus_t NvmCtxMgmtStore(void) { #if ( CONTEXT_MANAGEMENT_ENABLED == 1 ) /* Read out the contexts lengths and pointers */ MibRequestConfirm_t mibReq; mibReq.Type = MIB_NVM_CTXS; LoRaMacMibGetRequestConfirm(&mibReq); LoRaMacCtxs_t *MacContexts = mibReq.Param.Contexts; /* Input checks */ if ((CtxUpdateStatus.Value & NVM_CTX_STORAGE_MASK) == 0) { return NVMCTXMGMT_STATUS_FAIL; } if (LoRaMacStop() != LORAMAC_STATUS_OK) { return NVMCTXMGMT_STATUS_FAIL; } /* Write */ if (CtxUpdateStatus.Elements.Crypto == 1) { if (NvmmWrite(&CryptoNvmCtxDataBlock, MacContexts->CryptoNvmCtx, MacContexts->CryptoNvmCtxSize) != NVMM_SUCCESS) { return NVMCTXMGMT_STATUS_FAIL; } } if (CtxUpdateStatus.Elements.SecureElement == 1) { if (NvmmWrite(&SecureElementNvmCtxDataBlock, MacContexts->SecureElementNvmCtx, MacContexts->SecureElementNvmCtxSize) != NVMM_SUCCESS) { return NVMCTXMGMT_STATUS_FAIL; } } #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) if (CtxUpdateStatus.Elements.Mac == 1) { if (NvmmWrite(&MacNvmCtxDataBlock, MacContexts->MacNvmCtx, MacContexts->MacNvmCtxSize) != NVMM_SUCCESS) { return NVMCTXMGMT_STATUS_FAIL; } } if (CtxUpdateStatus.Elements.Region == 1) { if (NvmmWrite(&RegionNvmCtxDataBlock, MacContexts->RegionNvmCtx, MacContexts->RegionNvmCtxSize) != NVMM_SUCCESS) { return NVMCTXMGMT_STATUS_FAIL; } } if (CtxUpdateStatus.Elements.Commands == 1) { if (NvmmWrite(&CommandsNvmCtxDataBlock, MacContexts->CommandsNvmCtx, MacContexts->CommandsNvmCtxSize) != NVMM_SUCCESS) { return NVMCTXMGMT_STATUS_FAIL; } } if (CtxUpdateStatus.Elements.ClassB == 1) { if (NvmmWrite(&ClassBNvmCtxDataBlock, MacContexts->ClassBNvmCtx, MacContexts->ClassBNvmCtxSize) != NVMM_SUCCESS) { return NVMCTXMGMT_STATUS_FAIL; } } if (CtxUpdateStatus.Elements.ConfirmQueue == 1) { if (NvmmWrite(&ConfirmQueueNvmCtxDataBlock, MacContexts->ConfirmQueueNvmCtx, MacContexts->ConfirmQueueNvmCtxSize) != NVMM_SUCCESS) { return NVMCTXMGMT_STATUS_FAIL; } } #endif /* MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 */ CtxUpdateStatus.Value = 0x00; /* Resume LoRaMac */ LoRaMacStart(); return NVMCTXMGMT_STATUS_SUCCESS; #else /* CONTEXT_MANAGEMENT_ENABLED == 0 */ return NVMCTXMGMT_STATUS_FAIL; #endif /* CONTEXT_MANAGEMENT_ENABLED */ } NvmCtxMgmtStatus_t NvmCtxMgmtRestore(void) { #if ( CONTEXT_MANAGEMENT_ENABLED == 1 ) MibRequestConfirm_t mibReq; LoRaMacCtxs_t contexts = { 0 }; NvmCtxMgmtStatus_t status = NVMCTXMGMT_STATUS_SUCCESS; /* Read out the contexts lengths */ mibReq.Type = MIB_NVM_CTXS; LoRaMacMibGetRequestConfirm(&mibReq); uint8_t NvmCryptoCtxRestore[mibReq.Param.Contexts->CryptoNvmCtxSize]; uint8_t NvmSecureElementCtxRestore[mibReq.Param.Contexts->SecureElementNvmCtxSize]; #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) uint8_t NvmMacCtxRestore[mibReq.Param.Contexts->MacNvmCtxSize]; uint8_t NvmRegionCtxRestore[mibReq.Param.Contexts->RegionNvmCtxSize]; uint8_t NvmCommandsCtxRestore[mibReq.Param.Contexts->CommandsNvmCtxSize]; uint8_t NvmClassBCtxRestore[mibReq.Param.Contexts->ClassBNvmCtxSize]; uint8_t NvmConfirmQueueCtxRestore[mibReq.Param.Contexts->ConfirmQueueNvmCtxSize]; #endif /* MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 */ if (NvmmDeclare(&CryptoNvmCtxDataBlock, mibReq.Param.Contexts->CryptoNvmCtxSize) == NVMM_SUCCESS) { NvmmRead(&CryptoNvmCtxDataBlock, NvmCryptoCtxRestore, mibReq.Param.Contexts->CryptoNvmCtxSize); contexts.CryptoNvmCtx = &NvmCryptoCtxRestore; contexts.CryptoNvmCtxSize = mibReq.Param.Contexts->CryptoNvmCtxSize; } else { status = NVMCTXMGMT_STATUS_FAIL; } if (NvmmDeclare(&SecureElementNvmCtxDataBlock, mibReq.Param.Contexts->SecureElementNvmCtxSize) == NVMM_SUCCESS) { NvmmRead(&SecureElementNvmCtxDataBlock, NvmSecureElementCtxRestore, mibReq.Param.Contexts->SecureElementNvmCtxSize); contexts.SecureElementNvmCtx = &NvmSecureElementCtxRestore; contexts.SecureElementNvmCtxSize = mibReq.Param.Contexts->SecureElementNvmCtxSize; } else { status = NVMCTXMGMT_STATUS_FAIL; } #if ( MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 ) if (NvmmDeclare(&MacNvmCtxDataBlock, mibReq.Param.Contexts->MacNvmCtxSize) == NVMM_SUCCESS) { NvmmRead(&MacNvmCtxDataBlock, NvmMacCtxRestore, mibReq.Param.Contexts->MacNvmCtxSize); contexts.MacNvmCtx = &NvmMacCtxRestore; contexts.MacNvmCtxSize = mibReq.Param.Contexts->MacNvmCtxSize; } else { status = NVMCTXMGMT_STATUS_FAIL; } if (NvmmDeclare(&RegionNvmCtxDataBlock, mibReq.Param.Contexts->RegionNvmCtxSize) == NVMM_SUCCESS) { NvmmRead(&RegionNvmCtxDataBlock, NvmRegionCtxRestore, mibReq.Param.Contexts->RegionNvmCtxSize); contexts.RegionNvmCtx = &NvmRegionCtxRestore; contexts.RegionNvmCtxSize = mibReq.Param.Contexts->RegionNvmCtxSize; } else { status = NVMCTXMGMT_STATUS_FAIL; } if (NvmmDeclare(&CommandsNvmCtxDataBlock, mibReq.Param.Contexts->CommandsNvmCtxSize) == NVMM_SUCCESS) { NvmmRead(&CommandsNvmCtxDataBlock, NvmCommandsCtxRestore, mibReq.Param.Contexts->CommandsNvmCtxSize); contexts.CommandsNvmCtx = &NvmCommandsCtxRestore; contexts.CommandsNvmCtxSize = mibReq.Param.Contexts->CommandsNvmCtxSize; } else { status = NVMCTXMGMT_STATUS_FAIL; } if (NvmmDeclare(&ClassBNvmCtxDataBlock, mibReq.Param.Contexts->ClassBNvmCtxSize) == NVMM_SUCCESS) { NvmmRead(&ClassBNvmCtxDataBlock, NvmClassBCtxRestore, mibReq.Param.Contexts->ClassBNvmCtxSize); contexts.ClassBNvmCtx = &NvmClassBCtxRestore; contexts.ClassBNvmCtxSize = mibReq.Param.Contexts->ClassBNvmCtxSize; } else { status = NVMCTXMGMT_STATUS_FAIL; } if (NvmmDeclare(&ConfirmQueueNvmCtxDataBlock, mibReq.Param.Contexts->ConfirmQueueNvmCtxSize) == NVMM_SUCCESS) { NvmmRead(&ConfirmQueueNvmCtxDataBlock, NvmConfirmQueueCtxRestore, mibReq.Param.Contexts->ConfirmQueueNvmCtxSize); contexts.ConfirmQueueNvmCtx = &NvmConfirmQueueCtxRestore; contexts.ConfirmQueueNvmCtxSize = mibReq.Param.Contexts->ConfirmQueueNvmCtxSize; } else { status = NVMCTXMGMT_STATUS_FAIL; } #endif /* MAX_PERSISTENT_CTX_MGMT_ENABLED == 1 */ /* Enforce storing all contexts */ if (status == NVMCTXMGMT_STATUS_FAIL) { CtxUpdateStatus.Value = 0xFF; NvmCtxMgmtStore(); } else { /* If successful query the mac to restore contexts */ mibReq.Type = MIB_NVM_CTXS; mibReq.Param.Contexts = &contexts; LoRaMacMibSetRequestConfirm(&mibReq); } return status; #else /* CONTEXT_MANAGEMENT_ENABLED == 0 */ return NVMCTXMGMT_STATUS_FAIL; #endif /* CONTEXT_MANAGEMENT_ENABLED */ } /* Private functions ---------------------------------------------------------*/