Hardware components | ||||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
Software apps and online services | ||||||
| ||||||
| ||||||
| ||||||
|
Trusted Objects provides LoRaWAN secured stack. This stack can be easily integrated to any LoRaWAN project.
This project shows how to secure a LoRaWAN node using Trusted Objects-Avnet TO136 Secure Element, with Kerlink gateway, Actility servers, and AWS IoT backend.
Note : screenshot values are examples
Gateway setupKerlink iFemtoCell gateway installation and configuration is documented on Kerlink Wiki.
The gateway needs to be connected to a IP network with DHCP server.
Follow this guide to setup the gateway.
Gateway configurationLog-in Actility ThingPark by clicking Log in in title bar.
On your dashboard, click on Network Manager in the left column to configure your gateway.
Click on Base stations in the left column. Click on Create button in Add base stations section to do so.
Fill the form with informations of your gateway pre-configured for Actility. If your gateway is not pre-configured, follow these steps to configure it:
- Connect to your Actility ThingPark account
- Open FAQ
- Select YOUR GATEWAY tab
- Open section What to do if your GW is not pre-configured for partners.thingpark.com?
- Follow the procedure for your gateway
The procedure should give you informations for the form.(LRR ID is last 4 bytes of gateway MAC address).
Click on Create button on top to create the gateway.
On your dashboard, click on Device Manager in the left column to configure your application and your devices.
Click on Devices in left column to register your device. In Add devices section, click on Create button to create a new device. Fill all fields with devices informations (use DevEUI provisioned in your Trusted Objects-Avnet TO136 SE).
Select your connectivity plan in Network parameters section (use DEV Connectivity Supplier for testing purposes). Select your application server routing profile in Application layer handling section.
Click on Create button on top to create the device.
AWS IoT is a backend for IoT devices, which is connected with all other AWS services.
Follow Actility ThingPark DX AWS configuration guide to configure AWS to allow connections from Actility ThingPark DX API. You can ignore last part as we will use WebSocket to securely connect Actility ThinkPark DX to AWS IoT.
Connect to Actility ThingPark DX using your credentials. Once connected, a token is generated. Select Swagger-UI link of DX Dataflow API.
Open POST /bridgeDataflows section, and register your bridge dataflow with followingdata (replace values with data from AWS):
{
"id": "<unique id of your choice>",
"name": "Dataflow for AWS IoT",
"bidirectional": true,
"binder": {
"classRef": "LRC_HTTP",
"properties": {
"deviceEUIList": "<comma separated device EUIs>"
}
},
"driver": {
"classRef": "ASCII"
},
"connectors": [
{
"classRef": "AWSIoT",
"properties": {
"accountPrefix": "<account prefix>",
"region": "<region>",
"protocol": "WSS",
"deviceType": "<device type>",
"accessKeyId": "<access key ID>",
"secretAccessKey": "<secret access key>"
}
}
]
}
The server must return code 201 (success). Note ref value in response, it will be used to reference your dataflow.
Open GET /bridgeDataflows/{bridgeDataflowRef} section, fill your ref in bridgeDataflowRef field, and select Try it out! to get your dataflow state.
You need to wait the state to be READY. It will be updated by Actility in few hours. Now we need to route uplink messages to ThingPark DX. In Actility ThingPark DX, select Swagger-UI link of DX Core API.
Open GET /devices section, fill your devEUI in deviceEUI field, and select Try it out! to get your device informations.
Note ref value in response, it will be used to reference your device.
Open PUT /devices/{deviceRef} section, fill your ref in deviceRef field, the following JSON in device field, and select Try it out! to update your device informations.
{
"processingStrategyId": "DATAFLOW"
}
Your device is now configured to sent its uplink messages to AWS IoT.
IDE setupWe need to cross-compile sources with for our STM32 platform. Download and install C/C++ version of Eclipse. Create an account on OpenSTM32 website. Follow this guide to install System Workbench for STM32 from Eclipse.
Device setupAs the servers are now fully configured, we finally need to setup the device.
First of all, we need the I-CUBE-LRWANsoftware code (version 1.1.4 at the date we wrote these lines), which is going to be used as a basis for our Secure Element integration.
Download the archive, and extract it. The sources already contains Eclipse (and other IDEs) project files. Open Eclipse, then select File, Import…, open General tab and select Existing Projects into Workspace.
In Select root directory, select Browse, and navigate to Projects/Multi/Applications/LoRa/End_Node/SW4STM32/STM32L073RZ-Nucleo/sx1272mb2das/.
Select Finish to finalize the import of the project. Plug your ST L073RZ with its SX1272 shield to your computer through the USB port.
A new serial device should appear (/dev/ttyACM0 on Linux). Open a serial console to see output logs :
sudo picocom -b 115200 --imap lfcrlf,crcrlf --omap delbs,crlf /dev/ttyACM0
Select Run, Run to compile your sources and run the project.
The program should start normally. Join procedure will probably not succeed as AppEUI, DevEUI and AppKey are STM32CubeExpansion defaults. We can ignore for now, as we will use Secure Element configuration.
All is working, but with a low security level.
We need to secure the device by integrating the Trusted Objects-Avnet TO136 SE.
Add Trusted Objects’ library (libTO) to your new project Drivers/BSP/TO136 folder. This folder must be created in project before.
Trusted Objects library examples and wrappers (except for stm32_hal.c) must not be imported.
Folders Drivers/BSP/TO136/libTO/src and Drivers/BSP/TO136/libTO/include must be added to include paths of your project to allow to include new header :
Select Project, Properties and open the C/C++ General tab. Click on Paths and Symbols, Includes tab, and GNU C language. Press Add…, Workspace…, and go through your project files to select the folder to add.
First, we need to initialize Trusted Objects library during the stack initialization.To do so, apply the patch libto-init.patch using these commands :
cd <project root directory>
patch -p1 < <patch directory>/libto-init.patch
Then we need to modify cryptography layer. There is a default software LoRa MAC cryptography layer implementation already provided with STM32CubeExpansion LRWAN sources. It is located into the Middlewares/Third_Party/Lora/Mac directory of STM32CubeExpansion source tree.
We are going to use the Trusted Objects-Avnet TO136 SE cryptography layer implementation instead of this default one. Import the provided files (LoRaMacCrypto_TO.c/h) into the Middlewares/Third_Party/Lora/Mac directory.
The file LoRaMacCrypto_TO.c implements the new API described in LoRaMacCrypto_TO.h.
Folder Middlewares/Third_Party/Lora/Mac must be added to include paths of your project to allow to include new header. Use the same procedure as before.
As we change the cryptographic API, we need to adapt code by changing all calls to old API.
To do so, apply the patch new-cryptography-layer.patch using these commands :
cd <project root directory>
patch -p1 < <patch directory>/new-cryptography-layer.patch
The following preprocessor definitions needs to be added in the build process :
- TO_SE : Use Trusted Objects-Avnet TO136 SE LoRa MAC cryptography layer instead of software implementation (see Trusted Objects LoRa MAC cryptography layer)
- TO_ENABLE_LORA : Enable libTO LoRa API
- TO_ENABLE_LORA_OPTIMIZED : Enable libTO LoRa optimized API
Select Project, Properties and open the C/C++ General tab. Click on Paths and Symbols, Symbols tab, and GNU C language. Press Add…, and enter symbol name and value (optional).
Click on OK, and Apply and Close to validate.
Plug your Trusted Objects shield between the board and SX1272 shield.
Select Run, Run to compile your modified sources and run the project.
The program should start normally. Join procedure will now succeed as AppEUI, DevEUI and AppKey are Trusted Objects-Avnet TO136 SE provisionned values.
Data customizationBy default, STM32CubeExpansion end-node sends a payload containing some sensor values on LoRa port 2.
You can change this by editing Send function of file Projects/Multi/Applications/LoRa/End_Node/src/main.c.
In this demo, we will keep default values.
Data in AWSThe initial purpose of this project is to get LoRaWAN device data in AWS IoT. Devices data can be viewed using AWS IoT MQTT client. You need to subscribe to a topic to see data (use # topic to see everything). Topics can be application server specific, or AWS specific (listed here).
Any MQTT client also connected to AWS can subscribe to the device topic, and handle data.
From ef0ac1a61090cabf26197dfd676ef99d42402555 Mon Sep 17 00:00:00 2001
From: Ugo RENNER <u.renner@trusted-objects.com>
Date: Tue, 14 Nov 2017 14:04:57 +0100
Subject: [PATCH 1/2] libTO initialization
---
Middlewares/Third_Party/Lora/Core/lora.c | 18 ++++++++++++++
.../Multi/Applications/LoRa/End_Node/src/main.c | 28 ++++++++++++++++++++++
2 files changed, 46 insertions(+)
diff --git a/Middlewares/Third_Party/Lora/Core/lora.c b/Middlewares/Third_Party/Lora/Core/lora.c
index 78a0a34..53b52aa 100644
--- a/Middlewares/Third_Party/Lora/Core/lora.c
+++ b/Middlewares/Third_Party/Lora/Core/lora.c
@@ -51,6 +51,11 @@
#include "lora.h"
#include "lora-test.h"
+#ifdef TO_SE
+#include "TO.h"
+#include "TO_defs.h"
+#endif
+
/*!
* Join requests trials duty cycle.
*/
@@ -266,12 +271,23 @@ void LORA_Init (LoRaMainCallback_t *callbacks, LoRaParam_t* LoRaParam )
LoRaMainCallbacks->BoardGetUniqueId( DevEui );
#endif
+#ifdef TO_SE
+ if (TO_lora_get_app_eui(AppEui) != TORSP_SUCCESS) {
+ PRINTF("TO_lora_get_app_eui failed\n");
+ }
+ if (TO_lora_get_dev_eui(DevEui) != TORSP_SUCCESS) {
+ PRINTF("TO_lora_get_app_eui failed\n");
+ }
+#endif
+
#if( OVER_THE_AIR_ACTIVATION != 0 )
PRINTF("OTAA\n\r");
PRINTF("DevEui= %02X", DevEui[0]) ;for(int i=1; i<8 ; i++) {PRINTF("-%02X", DevEui[i]); }; PRINTF("\n\r");
PRINTF("AppEui= %02X", AppEui[0]) ;for(int i=1; i<8 ; i++) {PRINTF("-%02X", AppEui[i]); }; PRINTF("\n\r");
+#ifndef TO_SE
PRINTF("AppKey= %02X", AppKey[0]) ;for(int i=1; i<16; i++) {PRINTF(" %02X", AppKey[i]); }; PRINTF("\n\n\r");
+#endif
#else
#if (STATIC_DEVICE_ADDRESS != 1)
@@ -283,9 +299,11 @@ void LORA_Init (LoRaMainCallback_t *callbacks, LoRaParam_t* LoRaParam )
PRINTF("ABP\n\r");
PRINTF("DevEui= %02X", DevEui[0]) ;for(int i=1; i<8 ; i++) {PRINTF("-%02X", DevEui[i]); }; PRINTF("\n\r");
PRINTF("DevAdd= %08X\n\r", DevAddr) ;
+#ifndef TO_SE
PRINTF("NwkSKey= %02X", NwkSKey[0]) ;for(int i=1; i<16 ; i++) {PRINTF(" %02X", NwkSKey[i]); }; PRINTF("\n\r");
PRINTF("AppSKey= %02X", AppSKey[0]) ;for(int i=1; i<16 ; i++) {PRINTF(" %02X", AppSKey[i]); }; PRINTF("\n\r");
#endif
+#endif
LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
diff --git a/Projects/Multi/Applications/LoRa/End_Node/src/main.c b/Projects/Multi/Applications/LoRa/End_Node/src/main.c
index 64db291..9598c9b 100644
--- a/Projects/Multi/Applications/LoRa/End_Node/src/main.c
+++ b/Projects/Multi/Applications/LoRa/End_Node/src/main.c
@@ -53,6 +53,10 @@
#include "vcom.h"
#include "version.h"
+#ifdef TO_SE
+#include <TO.h>
+#endif
+
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
@@ -184,6 +188,26 @@ int main( void )
/* Configure the hardware*/
HW_Init( );
+#ifdef TO_SE
+ int ret, i;
+ uint8_t sn[TO_SN_SIZE];
+ ret = TO_init();
+ if (ret == TO_OK) {
+ PRINTF("TO initialized\n");
+ ret = TO_get_serial_number(sn);
+ if (ret == TORSP_SUCCESS) {
+ PRINTF("TO serial number : ");
+ for (i = 0; i < TO_SN_SIZE; i++)
+ PRINTF("%02X ", sn[i]);
+ PRINTF("\n");
+ } else {
+ PRINTF("Error: unable to get TO serial number\n");
+ }
+ } else {
+ PRINTF("Error: unable to initialize TO\n");
+ }
+#endif
+
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
@@ -214,6 +238,10 @@ int main( void )
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
}
+
+#ifdef TO_SE
+ TO_fini();
+#endif
}
static void LORA_HasJoined( void )
--
2.11.0
new-cryptography-layer.patch
C/C++From f68f5af50228c2be3950cf0c53662bcaa90eb08a Mon Sep 17 00:00:00 2001
From: Ugo RENNER <u.renner@trusted-objects.com>
Date: Tue, 14 Nov 2017 14:25:54 +0100
Subject: [PATCH 2/2] libTO optimized integration
---
Middlewares/Third_Party/Lora/Mac/LoRaMac.c | 80 +++++++++++++++++++
Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto.c | 4 +
.../Third_Party/Lora/Mac/LoRaMacCrypto_TO.c | 54 +++++++++++++
.../Third_Party/Lora/Mac/LoRaMacCrypto_TO.h | 92 ++++++++++++++++++++++
4 files changed, 230 insertions(+)
create mode 100644 Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.c
create mode 100644 Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.h
diff --git a/Middlewares/Third_Party/Lora/Mac/LoRaMac.c b/Middlewares/Third_Party/Lora/Mac/LoRaMac.c
index e71908b..1efab69 100644
--- a/Middlewares/Third_Party/Lora/Mac/LoRaMac.c
+++ b/Middlewares/Third_Party/Lora/Mac/LoRaMac.c
@@ -26,7 +26,11 @@ Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jae
#include "timeServer.h"
#include "LoRaMac.h"
#include "region/Region.h"
+#ifndef TO_SE
#include "LoRaMacCrypto.h"
+#else
+#include "LoRaMacCrypto_TO.h"
+#endif
#include "debug.h"
#include "LoRaMacTest.h"
@@ -68,6 +72,7 @@ static LoRaMacRegion_t LoRaMacRegion;
*/
#define BACKOFF_DC_24_HOURS 10000
+#ifndef TO_SE
/*!
* Device IEEE EUI
*/
@@ -106,6 +111,7 @@ static uint8_t LoRaMacAppSKey[] =
* measurements
*/
static uint16_t LoRaMacDevNonce;
+#endif
/*!
* Network ID ( 3 bytes )
@@ -712,8 +718,10 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
uint8_t appPayloadStartIndex = 0;
uint8_t port = 0xFF;
uint8_t frameLen = 0;
+#ifndef TO_SE
uint32_t mic = 0;
uint32_t micRx = 0;
+#endif
uint16_t sequenceCounter = 0;
uint16_t sequenceCounterPrev = 0;
@@ -721,8 +729,10 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
uint32_t downLinkCounter = 0;
MulticastParams_t *curMulticastParams = NULL;
+#ifndef TO_SE
uint8_t *nwkSKey = LoRaMacNwkSKey;
uint8_t *appSKey = LoRaMacAppSKey;
+#endif
uint8_t multicast = 0;
@@ -756,6 +766,7 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
PrepareRxDoneAbort( );
return;
}
+#ifndef TO_SE
LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 );
LoRaMacRxPayload[0] = macHdr.Value;
@@ -770,6 +781,10 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
if( micRx == mic )
{
LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
+#else
+ if (LoRaMacHandleJoinAccept( payload, size, LoRaMacRxPayload ) == LORAMAC_CRYPTO_STATUS_OK)
+ {
+#endif
LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4];
LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 );
@@ -843,8 +858,10 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
if( address == curMulticastParams->Address )
{
multicast = 1;
+#ifndef TO_SE
nwkSKey = curMulticastParams->NwkSKey;
appSKey = curMulticastParams->AppSKey;
+#endif
downLinkCounter = curMulticastParams->DownLinkCounter;
break;
}
@@ -861,8 +878,10 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
else
{
multicast = 0;
+#ifndef TO_SE
nwkSKey = LoRaMacNwkSKey;
appSKey = LoRaMacAppSKey;
+#endif
downLinkCounter = DownLinkCounter;
}
@@ -873,10 +892,12 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
+#ifndef TO_SE
micRx |= ( uint32_t )payload[size - LORAMAC_MFR_LEN];
micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 1] << 8 );
micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 2] << 16 );
micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 3] << 24 );
+#endif
sequenceCounterPrev = ( uint16_t )downLinkCounter;
sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
@@ -884,14 +905,17 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
if( sequenceCounterDiff < ( 1 << 15 ) )
{
downLinkCounter += sequenceCounterDiff;
+#ifndef TO_SE
LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
if( micRx == mic )
{
isMicOk = true;
}
+#endif
}
else
{
+#ifndef TO_SE
// check for sequence roll-over
uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff;
LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic );
@@ -900,6 +924,14 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
isMicOk = true;
downLinkCounter = downLinkCounterTmp;
}
+#else
+ // assume sequence roll-over
+ downLinkCounter += 0x10000 + ( int16_t )sequenceCounterDiff;
+ }
+ if ( LoRaMacUnsecurePHYPayload( payload, size, payload ) == LORAMAC_CRYPTO_STATUS_OK )
+ {
+ isMicOk = true;
+#endif
}
// Check for a the maximum allowed counter difference
@@ -998,6 +1030,7 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
{
port = payload[appPayloadStartIndex++];
frameLen = ( size - 4 ) - appPayloadStartIndex;
+ memcpy( LoRaMacRxPayload, payload + appPayloadStartIndex, frameLen );
McpsIndication.Port = port;
@@ -1006,6 +1039,7 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
// Only allow frames which do not have fOpts
if( fCtrl.Bits.FOptsLen == 0 )
{
+#ifndef TO_SE
LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
frameLen,
nwkSKey,
@@ -1013,6 +1047,7 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
DOWN_LINK,
downLinkCounter,
LoRaMacRxPayload );
+#endif
// Decode frame payload MAC commands
ProcessMacCommands( LoRaMacRxPayload, 0, frameLen, snr );
@@ -1030,6 +1065,7 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
ProcessMacCommands( payload, 8, appPayloadStartIndex - 1, snr );
}
+#ifndef TO_SE
LoRaMacPayloadDecrypt( payload + appPayloadStartIndex,
frameLen,
appSKey,
@@ -1037,6 +1073,7 @@ static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t
DOWN_LINK,
downLinkCounter,
LoRaMacRxPayload );
+#endif
if( skipIndication == false )
{
@@ -2054,9 +2091,13 @@ static void ResetMacParameters( void )
LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize )
{
AdrNextParams_t adrNext;
+#ifndef TO_SE
uint16_t i;
+#endif
uint8_t pktHeaderLen = 0;
+#ifndef TO_SE
uint32_t mic = 0;
+#endif
const void* payload = fBuffer;
uint8_t framePort = fPort;
@@ -2071,11 +2112,14 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl
LoRaMacTxPayloadLen = fBufferSize;
+#ifndef TO_SE
LoRaMacBuffer[pktHeaderLen++] = macHdr->Value;
+#endif
switch( macHdr->Bits.MType )
{
case FRAME_TYPE_JOIN_REQ:
+#ifndef TO_SE
LoRaMacBufferPktLen = pktHeaderLen;
memcpyr( LoRaMacBuffer + LoRaMacBufferPktLen, LoRaMacAppEui, 8 );
@@ -2094,6 +2138,9 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl
LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 8 ) & 0xFF;
LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 16 ) & 0xFF;
LoRaMacBuffer[LoRaMacBufferPktLen++] = ( mic >> 24 ) & 0xFF;
+#else
+ LoRaMacGetJoinRequest( LoRaMacBuffer, &LoRaMacBufferPktLen );
+#endif
break;
case FRAME_TYPE_DATA_CONFIRMED_UP:
@@ -2122,6 +2169,7 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl
fCtrl->Bits.Ack = 1;
}
+#ifndef TO_SE
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 8 ) & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( LoRaMacDevAddr >> 16 ) & 0xFF;
@@ -2131,6 +2179,7 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl
LoRaMacBuffer[pktHeaderLen++] = UpLinkCounter & 0xFF;
LoRaMacBuffer[pktHeaderLen++] = ( UpLinkCounter >> 8 ) & 0xFF;
+#endif
// Copy the MAC commands which must be re-send into the MAC command buffer
memcpy1( &MacCommandsBuffer[MacCommandsBufferIndex], MacCommandsBufferToRepeat, MacCommandsBufferToRepeatIndex );
@@ -2144,12 +2193,14 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl
{
fCtrl->Bits.FOptsLen += MacCommandsBufferIndex;
+#ifndef TO_SE
// Update FCtrl field with new value of OptionsLength
LoRaMacBuffer[0x05] = fCtrl->Value;
for( i = 0; i < MacCommandsBufferIndex; i++ )
{
LoRaMacBuffer[pktHeaderLen++] = MacCommandsBuffer[i];
}
+#endif
}
else
{
@@ -2176,6 +2227,7 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl
MacCommandsInNextTx = true;
}
+#ifndef TO_SE
if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) )
{
LoRaMacBuffer[pktHeaderLen++] = framePort;
@@ -2201,6 +2253,16 @@ LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl
LoRaMacBuffer[LoRaMacBufferPktLen + 3] = ( mic >> 24 ) & 0xFF;
LoRaMacBufferPktLen += LORAMAC_MFR_LEN;
+#else
+ if( ( payload != NULL ) && ( LoRaMacTxPayloadLen > 0 ) && framePort == 0 )
+ {
+ // Reset buffer index as the mac commands are being sent on port 0
+ MacCommandsBufferIndex = 0;
+ }
+
+ LoRaMacSecurePHYPayload( macHdr->Value, fCtrl->Value, MacCommandsBuffer, framePort, payload, LoRaMacTxPayloadLen, LoRaMacBuffer );
+ LoRaMacBufferPktLen = 6 + fCtrl->Bits.FOptsLen + 2 + (LoRaMacTxPayloadLen ? LoRaMacTxPayloadLen + 1 : 0) + LORAMAC_MFR_LEN;
+#endif
break;
case FRAME_TYPE_PROPRIETARY:
@@ -2543,14 +2605,20 @@ LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet )
break;
}
case MIB_NWK_SKEY:
+#ifndef TO_SE
{
mibGet->Param.NwkSKey = LoRaMacNwkSKey;
break;
}
+#endif
case MIB_APP_SKEY:
{
+#ifndef TO_SE
mibGet->Param.AppSKey = LoRaMacAppSKey;
break;
+#else
+ PRINTF("%s: Cannot get session key\n", __func__);
+#endif
}
case MIB_PUBLIC_NETWORK:
{
@@ -2747,6 +2815,7 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
break;
}
case MIB_NWK_SKEY:
+#ifndef TO_SE
{
if( mibSet->Param.NwkSKey != NULL )
{
@@ -2759,8 +2828,10 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
}
break;
}
+#endif
case MIB_APP_SKEY:
{
+#ifndef TO_SE
if( mibSet->Param.AppSKey != NULL )
{
memcpy1( LoRaMacAppSKey, mibSet->Param.AppSKey,
@@ -2770,6 +2841,9 @@ LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet )
{
status = LORAMAC_STATUS_PARAMETER_INVALID;
}
+#else
+ PRINTF("%s: Cannot set session key\n", __func__);
+#endif
break;
}
case MIB_PUBLIC_NETWORK:
@@ -3134,10 +3208,14 @@ LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest )
return LORAMAC_STATUS_BUSY;
}
+#ifndef TO_SE
if( ( mlmeRequest->Req.Join.DevEui == NULL ) ||
( mlmeRequest->Req.Join.AppEui == NULL ) ||
( mlmeRequest->Req.Join.AppKey == NULL ) ||
( mlmeRequest->Req.Join.NbTrials == 0 ) )
+#else
+ if( ( mlmeRequest->Req.Join.NbTrials == 0 ) )
+#endif
{
return LORAMAC_STATUS_PARAMETER_INVALID;
}
@@ -3156,9 +3234,11 @@ LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest )
LoRaMacFlags.Bits.MlmeReq = 1;
MlmeConfirm.MlmeRequest = mlmeRequest->Type;
+#ifndef TO_SE
LoRaMacDevEui = mlmeRequest->Req.Join.DevEui;
LoRaMacAppEui = mlmeRequest->Req.Join.AppEui;
LoRaMacAppKey = mlmeRequest->Req.Join.AppKey;
+#endif
MaxJoinRequestTrials = mlmeRequest->Req.Join.NbTrials;
// Reset variable JoinRequestTrials
diff --git a/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto.c b/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto.c
index 94026c4..2bc19f8 100644
--- a/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto.c
+++ b/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto.c
@@ -1,3 +1,5 @@
+#ifndef TO_SE
+
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
@@ -200,3 +202,5 @@ void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint1
memcpy1( nonce + 7, pDevNonce, 2 );
aes_encrypt( nonce, appSKey, &AesContext );
}
+
+#endif /* TO_SE */
diff --git a/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.c b/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.c
new file mode 100644
index 0000000..d1ddfca
--- /dev/null
+++ b/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.c
@@ -0,0 +1,54 @@
+#include <stdio.h>
+#include <stdint.h>
+#include <LoRaMacCrypto_TO.h>
+#include <TO.h>
+
+LoRaMacCryptoStatus_t LoRaMacGetJoinRequest( uint8_t *buffer, uint16_t *size )
+{
+ int ret;
+
+ ret = TO_lora_get_join_request_phypayload(buffer);
+ if (ret != TORSP_SUCCESS) {
+ fprintf(stderr, "TO get join request error, 0x%X\n", ret);
+ } else {
+ *size = TO_LORA_JOINREQUEST_SIZE;
+ }
+
+ return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
+}
+
+LoRaMacCryptoStatus_t LoRaMacHandleJoinAccept( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer )
+{
+ int ret;
+
+ ret = TO_lora_handle_join_accept_phypayload(buffer, size, outBuffer);
+ if (ret != TORSP_SUCCESS) {
+ fprintf(stderr, "TO handle join accept error, 0x%X\n", ret);
+ }
+
+ return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
+}
+
+LoRaMacCryptoStatus_t LoRaMacSecurePHYPayload( const uint8_t mhdr, const uint8_t fctrl, const uint8_t *fopts, const uint8_t fport, const uint8_t *payload, const size_t payloadSize, uint8_t *outBuffer )
+{
+ int ret;
+
+ ret = TO_lora_secure_phypayload(mhdr, fctrl, fopts, fport, payload, payloadSize, outBuffer);
+ if (ret != TORSP_SUCCESS) {
+ fprintf(stderr, "TO secure error, 0x%X\n", ret);
+ }
+
+ return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
+}
+
+LoRaMacCryptoStatus_t LoRaMacUnsecurePHYPayload( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer )
+{
+ int ret;
+
+ ret = TO_lora_unsecure_phypayload(buffer, size, outBuffer);
+ if (ret != TORSP_SUCCESS) {
+ fprintf(stderr, "TO unsecure error, 0x%X\n", ret);
+ }
+
+ return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
+}
diff --git a/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.h b/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.h
new file mode 100644
index 0000000..ea8403c
--- /dev/null
+++ b/Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.h
@@ -0,0 +1,92 @@
+/*!
+ * \file LoRaMacCrypto_TO.h
+ *
+ * \brief LoRa MAC layer cryptography implementation
+ *
+ * \copyright Revised BSD License, see section \ref LICENSE.
+ *
+ * \code
+ * ______ _
+ * / _____) _ | |
+ * ( (____ _____ ____ _| |_ _____ ____| |__
+ * \____ \| ___ | (_ _) ___ |/ ___) _ \
+ * _____) ) ____| | | || |_| ____( (___| | | |
+ * (______/|_____)_|_|_| \__)_____)\____)_| |_|
+ * (C)2013 Semtech
+ *
+ * ___ _____ _ ___ _ _____ ___ ___ ___ ___
+ * / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
+ * \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
+ * |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
+ * embedded.connectivity.solutions===============
+ *
+ * \endcode
+ *
+ * \author Miguel Luis ( Semtech )
+ *
+ * \author Gregory Cristian ( Semtech )
+ *
+ * \author Daniel Jckle ( STACKFORCE )
+ *
+ * \defgroup LORAMAC_CRYPTO LoRa MAC layer cryptography implementation
+ * This module covers the implementation of cryptographic functions
+ * of the LoRaMAC layer.
+ * \{
+ */
+#ifndef __LORAMAC_CRYPTO_H__
+#define __LORAMAC_CRYPTO_H__
+
+/*!
+ * LoRaMAC Crypto Status
+ */
+typedef enum eLoRaMacCryptoStatus
+{
+ /**
+ * Success
+ */
+ LORAMAC_CRYPTO_STATUS_OK,
+ /**
+ * Failure
+ */
+ LORAMAC_CRYPTO_STATUS_KO
+} LoRaMacCryptoStatus_t;
+
+/*!
+ * Get join request encrypted payload.
+ *
+ * \param [OUT] buffer - Encrypted payload
+ * \param [OUT] size - Encrypted payload size
+ */
+LoRaMacCryptoStatus_t LoRaMacGetJoinRequest( uint8_t *buffer, uint16_t *size );
+
+/*!
+ * Handle join accept payload.
+ *
+ * \param [IN] buffer - Encrypted join accept payload
+ * \param [IN] size - Encrypted join accept payload size
+ */
+LoRaMacCryptoStatus_t LoRaMacHandleJoinAccept( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer );
+
+/*!
+ * Encrypt PHYPayload.
+ *
+ * \param [IN] mhdr - MHDR
+ * \param [IN] fctrl - FCtrl
+ * \param [IN] fopts - FOpts (optional, depends on FCtrl)
+ * \param [IN] fport - FOpts (optional, depends on payload)
+ * \param [IN] payload - MACPayload (optional)
+ * \param [IN] payloadSize - MACPayload size (must be 0 if no payload)
+ */
+LoRaMacCryptoStatus_t LoRaMacSecurePHYPayload( const uint8_t mhdr, const uint8_t fctrl, const uint8_t *fopts, const uint8_t fport, const uint8_t *payload, const size_t payloadSize, uint8_t *outBuffer );
+
+/*!
+ * Decrypt PHYPayload.
+ *
+ * \param [IN] buffer - Payload to decrypt
+ * \param [IN] size - Size of payload
+ */
+LoRaMacCryptoStatus_t LoRaMacUnsecurePHYPayload( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer );
+
+/*! \} defgroup LORAMAC */
+
+#endif // __LORAMAC_CRYPTO_H__
--
2.11.0
main.c
C/C++File location: Projects/Multi/Applications/LoRa/End_Node/src/main.c
No preview (download only).
lora.c
C/C++File location: Middlewares/Third_Party/Lora/Core/lora.c
/******************************************************************************
* @file lora.c
* @author MCD Application Team
* @version V1.1.4
* @date 08-January-2018
* @brief lora API to drive the lora state Machine
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2017 STMicroelectronics International N.V.
* All rights reserved.</center></h2>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted, provided that the following conditions are met:
*
* 1. Redistribution of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of STMicroelectronics nor the names of other
* contributors to this software may be used to endorse or promote products
* derived from this software without specific written permission.
* 4. This software, including modifications and/or derivative works of this
* software, must execute solely and exclusively on microcontroller or
* microprocessor devices manufactured by or for STMicroelectronics.
* 5. Redistribution and use of this software other than as permitted under
* this license is void and will automatically terminate your rights under
* this license.
*
* THIS SOFTWARE IS PROVIDED BY STMICROELECTRONICS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS, IMPLIED OR STATUTORY WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
* PARTICULAR PURPOSE AND NON-INFRINGEMENT OF THIRD PARTY INTELLECTUAL PROPERTY
* RIGHTS ARE DISCLAIMED TO THE FULLEST EXTENT PERMITTED BY LAW. IN NO EVENT
* SHALL STMICROELECTRONICS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "hw.h"
#include "timeServer.h"
#include "LoRaMac.h"
#include "lora.h"
#include "lora-test.h"
#ifdef TO_SE
#include "TO.h"
#include "TO_defs.h"
#endif
/*!
* Join requests trials duty cycle.
*/
#define OVER_THE_AIR_ACTIVATION_DUTYCYCLE 10000 // 10 [s] value in ms
#if defined( REGION_EU868 )
#include "LoRaMacTest.h"
/*!
* LoRaWAN ETSI duty cycle control enable/disable
*
* \remark Please note that ETSI mandates duty cycled transmissions. Use only for test purposes
*/
#define LORAWAN_DUTYCYCLE_ON true
#define USE_SEMTECH_DEFAULT_CHANNEL_LINEUP 0
#if( USE_SEMTECH_DEFAULT_CHANNEL_LINEUP == 1 )
#define LC4 { 867100000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC5 { 867300000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC6 { 867500000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC7 { 867700000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC8 { 867900000, 0, { ( ( DR_5 << 4 ) | DR_0 ) }, 0 }
#define LC9 { 868800000, 0, { ( ( DR_7 << 4 ) | DR_7 ) }, 2 }
#define LC10 { 868300000, 0, { ( ( DR_6 << 4 ) | DR_6 ) }, 1 }
#endif
#endif
static uint8_t DevEui[] = LORAWAN_DEVICE_EUI;
static uint8_t AppEui[] = LORAWAN_APPLICATION_EUI;
static uint8_t AppKey[] = LORAWAN_APPLICATION_KEY;
static MlmeReqJoin_t JoinParameters;
#if( OVER_THE_AIR_ACTIVATION == 0 )
static uint8_t NwkSKey[] = LORAWAN_NWKSKEY;
static uint8_t AppSKey[] = LORAWAN_APPSKEY;
static uint32_t DevAddr = LORAWAN_DEVICE_ADDRESS;
#endif
/*!
* Defines the LoRa parameters at Init
*/
static LoRaParam_t* LoRaParamInit;
static LoRaMacPrimitives_t LoRaMacPrimitives;
static LoRaMacCallback_t LoRaMacCallbacks;
static MibRequestConfirm_t mibReq;
static LoRaMainCallback_t *LoRaMainCallbacks;
/*!
* \brief MCPS-Confirm event function
*
* \param [IN] McpsConfirm - Pointer to the confirm structure,
* containing confirm attributes.
*/
static void McpsConfirm( McpsConfirm_t *mcpsConfirm )
{
if( mcpsConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
switch( mcpsConfirm->McpsRequest )
{
case MCPS_UNCONFIRMED:
{
// Check Datarate
// Check TxPower
break;
}
case MCPS_CONFIRMED:
{
// Check Datarate
// Check TxPower
// Check AckReceived
// Check NbTrials
break;
}
case MCPS_PROPRIETARY:
{
break;
}
default:
break;
}
}
}
/*!
* \brief MCPS-Indication event function
*
* \param [IN] mcpsIndication - Pointer to the indication structure,
* containing indication attributes.
*/
static void McpsIndication( McpsIndication_t *mcpsIndication )
{
lora_AppData_t AppData;
if( mcpsIndication->Status != LORAMAC_EVENT_INFO_STATUS_OK )
{
return;
}
switch( mcpsIndication->McpsIndication )
{
case MCPS_UNCONFIRMED:
{
break;
}
case MCPS_CONFIRMED:
{
break;
}
case MCPS_PROPRIETARY:
{
break;
}
case MCPS_MULTICAST:
{
break;
}
default:
break;
}
// Check Multicast
// Check Port
// Check Datarate
// Check FramePending
// Check Buffer
// Check BufferSize
// Check Rssi
// Check Snr
// Check RxSlot
if (certif_running() == true )
{
certif_DownLinkIncrement( );
}
if( mcpsIndication->RxData == true )
{
switch( mcpsIndication->Port )
{
case CERTIF_PORT:
certif_rx( mcpsIndication, &JoinParameters );
break;
default:
AppData.Port = mcpsIndication->Port;
AppData.BuffSize = mcpsIndication->BufferSize;
AppData.Buff = mcpsIndication->Buffer;
LoRaMainCallbacks->LORA_RxData( &AppData );
break;
}
}
}
/*!
* \brief MLME-Confirm event function
*
* \param [IN] MlmeConfirm - Pointer to the confirm structure,
* containing confirm attributes.
*/
static void MlmeConfirm( MlmeConfirm_t *mlmeConfirm )
{
switch( mlmeConfirm->MlmeRequest )
{
case MLME_JOIN:
{
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
// Status is OK, node has joined the network
LoRaMainCallbacks->LORA_HasJoined();
}
else
{
// Join was not successful. Try to join again
LORA_Join();
}
break;
}
case MLME_LINK_CHECK:
{
if( mlmeConfirm->Status == LORAMAC_EVENT_INFO_STATUS_OK )
{
// Check DemodMargin
// Check NbGateways
if (certif_running() == true )
{
certif_linkCheck( mlmeConfirm);
}
}
break;
}
default:
break;
}
}
/**
* lora Init
*/
void LORA_Init (LoRaMainCallback_t *callbacks, LoRaParam_t* LoRaParam )
{
/* init the Tx Duty Cycle*/
LoRaParamInit = LoRaParam;
/* init the main call backs*/
LoRaMainCallbacks = callbacks;
#if (STATIC_DEVICE_EUI != 1)
LoRaMainCallbacks->BoardGetUniqueId( DevEui );
#endif
#ifdef TO_SE
if (TO_lora_get_app_eui(AppEui) != TORSP_SUCCESS) {
PRINTF("TO_lora_get_app_eui failed\n");
}
if (TO_lora_get_dev_eui(DevEui) != TORSP_SUCCESS) {
PRINTF("TO_lora_get_app_eui failed\n");
}
#endif
#if( OVER_THE_AIR_ACTIVATION != 0 )
PRINTF("OTAA\n\r");
PRINTF("DevEui= %02X", DevEui[0]) ;for(int i=1; i<8 ; i++) {PRINTF("-%02X", DevEui[i]); }; PRINTF("\n\r");
PRINTF("AppEui= %02X", AppEui[0]) ;for(int i=1; i<8 ; i++) {PRINTF("-%02X", AppEui[i]); }; PRINTF("\n\r");
#ifndef TO_SE
PRINTF("AppKey= %02X", AppKey[0]) ;for(int i=1; i<16; i++) {PRINTF(" %02X", AppKey[i]); }; PRINTF("\n\n\r");
#endif
#else
#if (STATIC_DEVICE_ADDRESS != 1)
// Random seed initialization
srand1( LoRaMainCallbacks->BoardGetRandomSeed( ) );
// Choose a random device address
DevAddr = randr( 0, 0x01FFFFFF );
#endif
PRINTF("ABP\n\r");
PRINTF("DevEui= %02X", DevEui[0]) ;for(int i=1; i<8 ; i++) {PRINTF("-%02X", DevEui[i]); }; PRINTF("\n\r");
PRINTF("DevAdd= %08X\n\r", DevAddr) ;
#ifndef TO_SE
PRINTF("NwkSKey= %02X", NwkSKey[0]) ;for(int i=1; i<16 ; i++) {PRINTF(" %02X", NwkSKey[i]); }; PRINTF("\n\r");
PRINTF("AppSKey= %02X", AppSKey[0]) ;for(int i=1; i<16 ; i++) {PRINTF(" %02X", AppSKey[i]); }; PRINTF("\n\r");
#endif
#endif
LoRaMacPrimitives.MacMcpsConfirm = McpsConfirm;
LoRaMacPrimitives.MacMcpsIndication = McpsIndication;
LoRaMacPrimitives.MacMlmeConfirm = MlmeConfirm;
LoRaMacCallbacks.GetBatteryLevel = LoRaMainCallbacks->BoardGetBatteryLevel;
#if defined( REGION_AS923 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_AS923 );
#elif defined( REGION_AU915 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_AU915 );
#elif defined( REGION_CN470 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_CN470 );
#elif defined( REGION_CN779 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_CN779 );
#elif defined( REGION_EU433 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_EU433 );
#elif defined( REGION_IN865 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_IN865 );
#elif defined( REGION_EU868 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_EU868 );
#elif defined( REGION_KR920 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_KR920 );
#elif defined( REGION_US915 )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_US915 );
#elif defined( REGION_US915_HYBRID )
LoRaMacInitialization( &LoRaMacPrimitives, &LoRaMacCallbacks, LORAMAC_REGION_US915_HYBRID );
#else
#error "Please define a region in the compiler options."
#endif
mibReq.Type = MIB_ADR;
mibReq.Param.AdrEnable = LoRaParamInit->AdrEnable;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_PUBLIC_NETWORK;
mibReq.Param.EnablePublicNetwork = LoRaParamInit->EnablePublicNetwork;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_DEVICE_CLASS;
mibReq.Param.Class= CLASS_A;
LoRaMacMibSetRequestConfirm( &mibReq );
#if defined( REGION_EU868 )
LoRaMacTestSetDutyCycleOn( LORAWAN_DUTYCYCLE_ON );
#if( USE_SEMTECH_DEFAULT_CHANNEL_LINEUP == 1 )
LoRaMacChannelAdd( 3, ( ChannelParams_t )LC4 );
LoRaMacChannelAdd( 4, ( ChannelParams_t )LC5 );
LoRaMacChannelAdd( 5, ( ChannelParams_t )LC6 );
LoRaMacChannelAdd( 6, ( ChannelParams_t )LC7 );
LoRaMacChannelAdd( 7, ( ChannelParams_t )LC8 );
LoRaMacChannelAdd( 8, ( ChannelParams_t )LC9 );
LoRaMacChannelAdd( 9, ( ChannelParams_t )LC10 );
mibReq.Type = MIB_RX2_DEFAULT_CHANNEL;
mibReq.Param.Rx2DefaultChannel = ( Rx2ChannelParams_t ){ 869525000, DR_3 };
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_RX2_CHANNEL;
mibReq.Param.Rx2Channel = ( Rx2ChannelParams_t ){ 869525000, DR_3 };
LoRaMacMibSetRequestConfirm( &mibReq );
#endif
#endif
}
void LORA_Join( void)
{
MlmeReq_t mlmeReq;
mlmeReq.Type = MLME_JOIN;
mlmeReq.Req.Join.DevEui = DevEui;
mlmeReq.Req.Join.AppEui = AppEui;
mlmeReq.Req.Join.AppKey = AppKey;
mlmeReq.Req.Join.NbTrials = LoRaParamInit->NbTrials;
JoinParameters = mlmeReq.Req.Join;
#if( OVER_THE_AIR_ACTIVATION != 0 )
LoRaMacMlmeRequest( &mlmeReq );
#else
mibReq.Type = MIB_NET_ID;
mibReq.Param.NetID = LORAWAN_NETWORK_ID;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_DEV_ADDR;
mibReq.Param.DevAddr = DevAddr;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_NWK_SKEY;
mibReq.Param.NwkSKey = NwkSKey;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_APP_SKEY;
mibReq.Param.AppSKey = AppSKey;
LoRaMacMibSetRequestConfirm( &mibReq );
mibReq.Type = MIB_NETWORK_JOINED;
mibReq.Param.IsNetworkJoined = true;
LoRaMacMibSetRequestConfirm( &mibReq );
LoRaMainCallbacks->LORA_HasJoined();
#endif
}
LoraFlagStatus LORA_JoinStatus( void)
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_NETWORK_JOINED;
LoRaMacMibGetRequestConfirm( &mibReq );
if( mibReq.Param.IsNetworkJoined == true )
{
return LORA_SET;
}
else
{
return LORA_RESET;
}
}
bool LORA_send(lora_AppData_t* AppData, LoraConfirm_t IsTxConfirmed)
{
McpsReq_t mcpsReq;
LoRaMacTxInfo_t txInfo;
/*if certification test are on going, application data is not sent*/
if (certif_running() == true)
{
return false;
}
if( LoRaMacQueryTxPossible( AppData->BuffSize, &txInfo ) != LORAMAC_STATUS_OK )
{
// Send empty frame in order to flush MAC commands
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fBuffer = NULL;
mcpsReq.Req.Unconfirmed.fBufferSize = 0;
mcpsReq.Req.Unconfirmed.Datarate = LoRaParamInit->TxDatarate;
}
else
{
if( IsTxConfirmed == LORAWAN_UNCONFIRMED_MSG )
{
mcpsReq.Type = MCPS_UNCONFIRMED;
mcpsReq.Req.Unconfirmed.fPort = AppData->Port;
mcpsReq.Req.Unconfirmed.fBufferSize = AppData->BuffSize;
mcpsReq.Req.Unconfirmed.fBuffer = AppData->Buff;
mcpsReq.Req.Unconfirmed.Datarate = LoRaParamInit->TxDatarate;
}
else
{
mcpsReq.Type = MCPS_CONFIRMED;
mcpsReq.Req.Confirmed.fPort = AppData->Port;
mcpsReq.Req.Confirmed.fBufferSize = AppData->BuffSize;
mcpsReq.Req.Confirmed.fBuffer = AppData->Buff;
mcpsReq.Req.Confirmed.NbTrials = 8;
mcpsReq.Req.Confirmed.Datarate = LoRaParamInit->TxDatarate;
}
}
if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
{
return false;
}
return true;
}
LoraErrorStatus LORA_RequestClass( DeviceClass_t newClass )
{
LoraErrorStatus Errorstatus = LORA_SUCCESS;
MibRequestConfirm_t mibReq;
DeviceClass_t currentClass;
mibReq.Type = MIB_DEVICE_CLASS;
LoRaMacMibGetRequestConfirm( &mibReq );
currentClass = mibReq.Param.Class;
/*attempt to swicth only if class update*/
if (currentClass != newClass)
{
switch (newClass)
{
case CLASS_A:
{
if (currentClass == CLASS_A)
{
mibReq.Param.Class = CLASS_A;
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
{
/*switch is instantanuous*/
LoRaMainCallbacks->LORA_ConfirmClass(CLASS_A);
}
else
{
Errorstatus = LORA_ERROR;
}
}
break;
}
case CLASS_C:
{
if (currentClass != CLASS_A)
{
Errorstatus = LORA_ERROR;
}
/*switch is instantanuous*/
mibReq.Param.Class = CLASS_C;
if( LoRaMacMibSetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
{
LoRaMainCallbacks->LORA_ConfirmClass(CLASS_C);
}
else
{
Errorstatus = LORA_ERROR;
}
break;
}
default:
break;
}
}
return Errorstatus;
}
void LORA_GetCurrentClass( DeviceClass_t *currentClass )
{
MibRequestConfirm_t mibReq;
mibReq.Type = MIB_DEVICE_CLASS;
LoRaMacMibGetRequestConfirm( &mibReq );
*currentClass = mibReq.Param.Class;
}
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
LoRaMac.c
C/C++File location: Middlewares/Third_Party/Lora/Mac/LoRaMac.c
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC layer implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
*/
#include <stdbool.h>
#include <string.h>
#include <stdint.h>
#include "radio.h"
#include "timeServer.h"
#include "LoRaMac.h"
#include "region/Region.h"
#ifndef TO_SE
#include "LoRaMacCrypto.h"
#else
#include "LoRaMacCrypto_TO.h"
#endif
#include "debug.h"
#include "LoRaMacTest.h"
/*!
* Maximum PHY layer payload size
*/
#define LORAMAC_PHY_MAXPAYLOAD 255
/*!
* Maximum MAC commands buffer size
*/
#define LORA_MAC_COMMAND_MAX_LENGTH 128
/*!
* Maximum length of the fOpts field
*/
#define LORA_MAC_COMMAND_MAX_FOPTS_LENGTH 15
/*!
* LoRaMac region.
*/
static LoRaMacRegion_t LoRaMacRegion;
/*!
* LoRaMac duty cycle for the back-off procedure during the first hour.
*/
#define BACKOFF_DC_1_HOUR 100
/*!
* LoRaMac duty cycle for the back-off procedure during the next 10 hours.
*/
#define BACKOFF_DC_10_HOURS 1000
/*!
* LoRaMac duty cycle for the back-off procedure during the next 24 hours.
*/
#define BACKOFF_DC_24_HOURS 10000
#ifndef TO_SE
/*!
* Device IEEE EUI
*/
static uint8_t *LoRaMacDevEui;
/*!
* Application IEEE EUI
*/
static uint8_t *LoRaMacAppEui;
/*!
* AES encryption/decryption cipher application key
*/
static uint8_t *LoRaMacAppKey;
/*!
* AES encryption/decryption cipher network session key
*/
static uint8_t LoRaMacNwkSKey[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*!
* AES encryption/decryption cipher application session key
*/
static uint8_t LoRaMacAppSKey[] =
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*!
* Device nonce is a random value extracted by issuing a sequence of RSSI
* measurements
*/
static uint16_t LoRaMacDevNonce;
#endif
/*!
* Network ID ( 3 bytes )
*/
static uint32_t LoRaMacNetID;
/*!
* Mote Address
*/
static uint32_t LoRaMacDevAddr;
/*!
* Multicast channels linked list
*/
static MulticastParams_t *MulticastChannels = NULL;
/*!
* Actual device class
*/
static DeviceClass_t LoRaMacDeviceClass;
/*!
* Indicates if the node is connected to a private or public network
*/
static bool PublicNetwork;
/*!
* Indicates if the node supports repeaters
*/
static bool RepeaterSupport;
/*!
* Buffer containing the data to be sent or received.
*/
static uint8_t LoRaMacBuffer[LORAMAC_PHY_MAXPAYLOAD];
/*!
* Length of packet in LoRaMacBuffer
*/
static uint16_t LoRaMacBufferPktLen = 0;
/*!
* Length of the payload in LoRaMacBuffer
*/
static uint8_t LoRaMacTxPayloadLen = 0;
/*!
* Buffer containing the upper layer data.
*/
static uint8_t LoRaMacRxPayload[LORAMAC_PHY_MAXPAYLOAD];
/*!
* LoRaMAC frame counter. Each time a packet is sent the counter is incremented.
* Only the 16 LSB bits are sent
*/
static uint32_t UpLinkCounter = 0;
/*!
* LoRaMAC frame counter. Each time a packet is received the counter is incremented.
* Only the 16 LSB bits are received
*/
static uint32_t DownLinkCounter = 0;
/*!
* IsPacketCounterFixed enables the MIC field tests by fixing the
* UpLinkCounter value
*/
static bool IsUpLinkCounterFixed = false;
/*!
* Used for test purposes. Disables the opening of the reception windows.
*/
static bool IsRxWindowsEnabled = true;
/*!
* Indicates if the MAC layer has already joined a network.
*/
static bool IsLoRaMacNetworkJoined = false;
/*!
* LoRaMac ADR control status
*/
static bool AdrCtrlOn = false;
/*!
* Counts the number of missed ADR acknowledgements
*/
static uint32_t AdrAckCounter = 0;
/*!
* If the node has sent a FRAME_TYPE_DATA_CONFIRMED_UP this variable indicates
* if the nodes needs to manage the server acknowledgement.
*/
static bool NodeAckRequested = false;
/*!
* If the server has sent a FRAME_TYPE_DATA_CONFIRMED_DOWN this variable indicates
* if the ACK bit must be set for the next transmission
*/
static bool SrvAckRequested = false;
/*!
* Indicates if the MAC layer wants to send MAC commands
*/
static bool MacCommandsInNextTx = false;
/*!
* Contains the current MacCommandsBuffer index
*/
static uint8_t MacCommandsBufferIndex = 0;
/*!
* Contains the current MacCommandsBuffer index for MAC commands to repeat
*/
static uint8_t MacCommandsBufferToRepeatIndex = 0;
/*!
* Buffer containing the MAC layer commands
*/
static uint8_t MacCommandsBuffer[LORA_MAC_COMMAND_MAX_LENGTH];
/*!
* Buffer containing the MAC layer commands which must be repeated
*/
static uint8_t MacCommandsBufferToRepeat[LORA_MAC_COMMAND_MAX_LENGTH];
/*!
* LoRaMac parameters
*/
LoRaMacParams_t LoRaMacParams;
/*!
* LoRaMac default parameters
*/
LoRaMacParams_t LoRaMacParamsDefaults;
/*!
* Uplink messages repetitions counter
*/
static uint8_t ChannelsNbRepCounter = 0;
/*!
* Maximum duty cycle
* \remark Possibility to shutdown the device.
*/
static uint8_t MaxDCycle = 0;
/*!
* Aggregated duty cycle management
*/
static uint16_t AggregatedDCycle;
static TimerTime_t AggregatedLastTxDoneTime;
static TimerTime_t AggregatedTimeOff;
/*!
* Enables/Disables duty cycle management (Test only)
*/
static bool DutyCycleOn;
/*!
* Current channel index
*/
static uint8_t Channel;
/*!
* Current channel index
*/
static uint8_t LastTxChannel;
/*!
* Set to true, if the last uplink was a join request
*/
static bool LastTxIsJoinRequest;
/*!
* Stores the time at LoRaMac initialization.
*
* \remark Used for the BACKOFF_DC computation.
*/
static TimerTime_t LoRaMacInitializationTime = 0;
/*!
* LoRaMac internal states
*/
enum eLoRaMacState
{
LORAMAC_IDLE = 0x00000000,
LORAMAC_TX_RUNNING = 0x00000001,
LORAMAC_RX = 0x00000002,
LORAMAC_ACK_REQ = 0x00000004,
LORAMAC_ACK_RETRY = 0x00000008,
LORAMAC_TX_DELAYED = 0x00000010,
LORAMAC_TX_CONFIG = 0x00000020,
LORAMAC_RX_ABORT = 0x00000040,
};
/*!
* LoRaMac internal state
*/
uint32_t LoRaMacState = LORAMAC_IDLE;
/*!
* LoRaMac timer used to check the LoRaMacState (runs every second)
*/
static TimerEvent_t MacStateCheckTimer;
/*!
* LoRaMac upper layer event functions
*/
static LoRaMacPrimitives_t *LoRaMacPrimitives;
/*!
* LoRaMac upper layer callback functions
*/
static LoRaMacCallback_t *LoRaMacCallbacks;
/*!
* Radio events function pointer
*/
static RadioEvents_t RadioEvents;
/*!
* LoRaMac duty cycle delayed Tx timer
*/
static TimerEvent_t TxDelayedTimer;
/*!
* LoRaMac reception windows timers
*/
static TimerEvent_t RxWindowTimer1;
static TimerEvent_t RxWindowTimer2;
/*!
* LoRaMac reception windows delay
* \remark normal frame: RxWindowXDelay = ReceiveDelayX - RADIO_WAKEUP_TIME
* join frame : RxWindowXDelay = JoinAcceptDelayX - RADIO_WAKEUP_TIME
*/
static uint32_t RxWindow1Delay;
static uint32_t RxWindow2Delay;
/*!
* LoRaMac Rx windows configuration
*/
static RxConfigParams_t RxWindow1Config;
static RxConfigParams_t RxWindow2Config;
/*!
* Acknowledge timeout timer. Used for packet retransmissions.
*/
static TimerEvent_t AckTimeoutTimer;
/*!
* Number of trials to get a frame acknowledged
*/
static uint8_t AckTimeoutRetries = 1;
/*!
* Number of trials to get a frame acknowledged
*/
static uint8_t AckTimeoutRetriesCounter = 1;
/*!
* Indicates if the AckTimeout timer has expired or not
*/
static bool AckTimeoutRetry = false;
/*!
* Last transmission time on air
*/
TimerTime_t TxTimeOnAir = 0;
/*!
* Number of trials for the Join Request
*/
static uint8_t JoinRequestTrials;
/*!
* Maximum number of trials for the Join Request
*/
static uint8_t MaxJoinRequestTrials;
/*!
* Structure to hold an MCPS indication data.
*/
static McpsIndication_t McpsIndication;
/*!
* Structure to hold MCPS confirm data.
*/
static McpsConfirm_t McpsConfirm;
/*!
* Structure to hold MLME confirm data.
*/
static MlmeConfirm_t MlmeConfirm;
/*!
* Holds the current rx window slot
*/
static uint8_t RxSlot = 0;
/*!
* LoRaMac tx/rx operation state
*/
LoRaMacFlags_t LoRaMacFlags;
/*!
* \brief Function to be executed on Radio Tx Done event
*/
static void OnRadioTxDone( void );
/*!
* \brief This function prepares the MAC to abort the execution of function
* OnRadioRxDone in case of a reception error.
*/
static void PrepareRxDoneAbort( void );
/*!
* \brief Function to be executed on Radio Rx Done event
*/
static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
/*!
* \brief Function executed on Radio Tx Timeout event
*/
static void OnRadioTxTimeout( void );
/*!
* \brief Function executed on Radio Rx error event
*/
static void OnRadioRxError( void );
/*!
* \brief Function executed on Radio Rx Timeout event
*/
static void OnRadioRxTimeout( void );
/*!
* \brief Function executed on Resend Frame timer event.
*/
static void OnMacStateCheckTimerEvent( void );
/*!
* \brief Function executed on duty cycle delayed Tx timer event
*/
static void OnTxDelayedTimerEvent( void );
/*!
* \brief Function executed on first Rx window timer event
*/
static void OnRxWindow1TimerEvent( void );
/*!
* \brief Function executed on second Rx window timer event
*/
static void OnRxWindow2TimerEvent( void );
/*!
* \brief Function executed on AckTimeout timer event
*/
static void OnAckTimeoutTimerEvent( void );
/*!
* \brief Initializes and opens the reception window
*
* \param [IN] rxContinuous Set to true, if the RX is in continuous mode
* \param [IN] maxRxWindow Maximum RX window timeout
*/
static void RxWindowSetup( bool rxContinuous, uint32_t maxRxWindow );
/*!
* \brief Adds a new MAC command to be sent.
*
* \Remark MAC layer internal function
*
* \param [in] cmd MAC command to be added
* [MOTE_MAC_LINK_CHECK_REQ,
* MOTE_MAC_LINK_ADR_ANS,
* MOTE_MAC_DUTY_CYCLE_ANS,
* MOTE_MAC_RX2_PARAM_SET_ANS,
* MOTE_MAC_DEV_STATUS_ANS
* MOTE_MAC_NEW_CHANNEL_ANS]
* \param [in] p1 1st parameter ( optional depends on the command )
* \param [in] p2 2nd parameter ( optional depends on the command )
*
* \retval status Function status [0: OK, 1: Unknown command, 2: Buffer full]
*/
static LoRaMacStatus_t AddMacCommand( uint8_t cmd, uint8_t p1, uint8_t p2 );
/*!
* \brief Parses the MAC commands which must be repeated.
*
* \Remark MAC layer internal function
*
* \param [IN] cmdBufIn Buffer which stores the MAC commands to send
* \param [IN] length Length of the input buffer to parse
* \param [OUT] cmdBufOut Buffer which stores the MAC commands which must be
* repeated.
*
* \retval Size of the MAC commands to repeat.
*/
static uint8_t ParseMacCommandsToRepeat( uint8_t* cmdBufIn, uint8_t length, uint8_t* cmdBufOut );
/*!
* \brief Validates if the payload fits into the frame, taking the datarate
* into account.
*
* \details Refer to chapter 4.3.2 of the LoRaWAN specification, v1.0
*
* \param lenN Length of the application payload. The length depends on the
* datarate and is region specific
*
* \param datarate Current datarate
*
* \param fOptsLen Length of the fOpts field
*
* \retval [false: payload does not fit into the frame, true: payload fits into
* the frame]
*/
static bool ValidatePayloadLength( uint8_t lenN, int8_t datarate, uint8_t fOptsLen );
/*!
* \brief Decodes MAC commands in the fOpts field and in the payload
*/
static void ProcessMacCommands( uint8_t *payload, uint8_t macIndex, uint8_t commandsSize, uint8_t snr );
/*!
* \brief LoRaMAC layer generic send frame
*
* \param [IN] macHdr MAC header field
* \param [IN] fPort MAC payload port
* \param [IN] fBuffer MAC data buffer to be sent
* \param [IN] fBufferSize MAC data buffer size
* \retval status Status of the operation.
*/
LoRaMacStatus_t Send( LoRaMacHeader_t *macHdr, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
/*!
* \brief LoRaMAC layer frame buffer initialization
*
* \param [IN] macHdr MAC header field
* \param [IN] fCtrl MAC frame control field
* \param [IN] fOpts MAC commands buffer
* \param [IN] fPort MAC payload port
* \param [IN] fBuffer MAC data buffer to be sent
* \param [IN] fBufferSize MAC data buffer size
* \retval status Status of the operation.
*/
LoRaMacStatus_t PrepareFrame( LoRaMacHeader_t *macHdr, LoRaMacFrameCtrl_t *fCtrl, uint8_t fPort, void *fBuffer, uint16_t fBufferSize );
/*
* \brief Schedules the frame according to the duty cycle
*
* \retval Status of the operation
*/
static LoRaMacStatus_t ScheduleTx( void );
/*
* \brief Calculates the back-off time for the band of a channel.
*
* \param [IN] channel The last Tx channel index
*/
static void CalculateBackOff( uint8_t channel );
/*!
* \brief LoRaMAC layer prepared frame buffer transmission with channel specification
*
* \remark PrepareFrame must be called at least once before calling this
* function.
*
* \param [IN] channel Channel to transmit on
* \retval status Status of the operation.
*/
LoRaMacStatus_t SendFrameOnChannel( uint8_t channel );
/*!
* \brief Sets the radio in continuous transmission mode
*
* \remark Uses the radio parameters set on the previous transmission.
*
* \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode
* \retval status Status of the operation.
*/
LoRaMacStatus_t SetTxContinuousWave( uint16_t timeout );
/*!
* \brief Sets the radio in continuous transmission mode
*
* \remark Uses the radio parameters set on the previous transmission.
*
* \param [IN] timeout Time in seconds while the radio is kept in continuous wave mode
* \param [IN] frequency RF frequency to be set.
* \param [IN] power RF output power to be set.
* \retval status Status of the operation.
*/
LoRaMacStatus_t SetTxContinuousWave1( uint16_t timeout, uint32_t frequency, uint8_t power );
/*!
* \brief Resets MAC specific parameters to default
*/
static void ResetMacParameters( void );
static void OnRadioTxDone( void )
{
GetPhyParams_t getPhy;
PhyParam_t phyParam;
SetBandTxDoneParams_t txDone;
TimerTime_t curTime = TimerGetCurrentTime( );
if( LoRaMacDeviceClass != CLASS_C )
{
Radio.Sleep( );
}
else
{
OnRxWindow2TimerEvent( );
}
// Setup timers
if( IsRxWindowsEnabled == true )
{
TimerSetValue( &RxWindowTimer1, RxWindow1Delay );
TimerStart( &RxWindowTimer1 );
if( LoRaMacDeviceClass != CLASS_C )
{
TimerSetValue( &RxWindowTimer2, RxWindow2Delay );
TimerStart( &RxWindowTimer2 );
}
if( ( LoRaMacDeviceClass == CLASS_C ) || ( NodeAckRequested == true ) )
{
getPhy.Attribute = PHY_ACK_TIMEOUT;
phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
TimerSetValue( &AckTimeoutTimer, RxWindow2Delay + phyParam.Value );
TimerStart( &AckTimeoutTimer );
}
}
else
{
McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_RX2_TIMEOUT;
if( LoRaMacFlags.Value == 0 )
{
LoRaMacFlags.Bits.McpsReq = 1;
}
LoRaMacFlags.Bits.MacDone = 1;
}
// Verify if the last uplink was a join request
if( ( LoRaMacFlags.Bits.MlmeReq == 1 ) && ( MlmeConfirm.MlmeRequest == MLME_JOIN ) )
{
LastTxIsJoinRequest = true;
}
else
{
LastTxIsJoinRequest = false;
}
// Store last Tx channel
LastTxChannel = Channel;
// Update last tx done time for the current channel
txDone.Channel = Channel;
txDone.Joined = IsLoRaMacNetworkJoined;
txDone.LastTxDoneTime = curTime;
RegionSetBandTxDone( LoRaMacRegion, &txDone );
// Update Aggregated last tx done time
AggregatedLastTxDoneTime = curTime;
if( NodeAckRequested == false )
{
McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
ChannelsNbRepCounter++;
}
}
static void PrepareRxDoneAbort( void )
{
LoRaMacState |= LORAMAC_RX_ABORT;
if( NodeAckRequested )
{
OnAckTimeoutTimerEvent( );
}
LoRaMacFlags.Bits.McpsInd = 1;
LoRaMacFlags.Bits.MacDone = 1;
// Trig OnMacCheckTimerEvent call as soon as possible
TimerSetValue( &MacStateCheckTimer, 1 );
TimerStart( &MacStateCheckTimer );
}
static void OnRadioRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
LoRaMacHeader_t macHdr;
LoRaMacFrameCtrl_t fCtrl;
ApplyCFListParams_t applyCFList;
GetPhyParams_t getPhy;
PhyParam_t phyParam;
bool skipIndication = false;
uint8_t pktHeaderLen = 0;
uint32_t address = 0;
uint8_t appPayloadStartIndex = 0;
uint8_t port = 0xFF;
uint8_t frameLen = 0;
#ifndef TO_SE
uint32_t mic = 0;
uint32_t micRx = 0;
#endif
uint16_t sequenceCounter = 0;
uint16_t sequenceCounterPrev = 0;
uint16_t sequenceCounterDiff = 0;
uint32_t downLinkCounter = 0;
MulticastParams_t *curMulticastParams = NULL;
#ifndef TO_SE
uint8_t *nwkSKey = LoRaMacNwkSKey;
uint8_t *appSKey = LoRaMacAppSKey;
#endif
uint8_t multicast = 0;
bool isMicOk = false;
McpsConfirm.AckReceived = false;
McpsIndication.Rssi = rssi;
McpsIndication.Snr = snr;
McpsIndication.RxSlot = RxSlot;
McpsIndication.Port = 0;
McpsIndication.Multicast = 0;
McpsIndication.FramePending = 0;
McpsIndication.Buffer = NULL;
McpsIndication.BufferSize = 0;
McpsIndication.RxData = false;
McpsIndication.AckReceived = false;
McpsIndication.DownLinkCounter = 0;
McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
Radio.Sleep( );
TimerStop( &RxWindowTimer2 );
macHdr.Value = payload[pktHeaderLen++];
switch( macHdr.Bits.MType )
{
case FRAME_TYPE_JOIN_ACCEPT:
if( IsLoRaMacNetworkJoined == true )
{
McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
PrepareRxDoneAbort( );
return;
}
#ifndef TO_SE
LoRaMacJoinDecrypt( payload + 1, size - 1, LoRaMacAppKey, LoRaMacRxPayload + 1 );
LoRaMacRxPayload[0] = macHdr.Value;
LoRaMacJoinComputeMic( LoRaMacRxPayload, size - LORAMAC_MFR_LEN, LoRaMacAppKey, &mic );
micRx |= ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN];
micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 1] << 8 );
micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 2] << 16 );
micRx |= ( ( uint32_t )LoRaMacRxPayload[size - LORAMAC_MFR_LEN + 3] << 24 );
if( micRx == mic )
{
LoRaMacJoinComputeSKeys( LoRaMacAppKey, LoRaMacRxPayload + 1, LoRaMacDevNonce, LoRaMacNwkSKey, LoRaMacAppSKey );
#else
if (LoRaMacHandleJoinAccept( payload, size, LoRaMacRxPayload ) == LORAMAC_CRYPTO_STATUS_OK)
{
#endif
LoRaMacNetID = ( uint32_t )LoRaMacRxPayload[4];
LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[5] << 8 );
LoRaMacNetID |= ( ( uint32_t )LoRaMacRxPayload[6] << 16 );
LoRaMacDevAddr = ( uint32_t )LoRaMacRxPayload[7];
LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[8] << 8 );
LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[9] << 16 );
LoRaMacDevAddr |= ( ( uint32_t )LoRaMacRxPayload[10] << 24 );
// DLSettings
LoRaMacParams.Rx1DrOffset = ( LoRaMacRxPayload[11] >> 4 ) & 0x07;
LoRaMacParams.Rx2Channel.Datarate = LoRaMacRxPayload[11] & 0x0F;
// RxDelay
LoRaMacParams.ReceiveDelay1 = ( LoRaMacRxPayload[12] & 0x0F );
if( LoRaMacParams.ReceiveDelay1 == 0 )
{
LoRaMacParams.ReceiveDelay1 = 1;
}
LoRaMacParams.ReceiveDelay1 *= 1000;
LoRaMacParams.ReceiveDelay2 = LoRaMacParams.ReceiveDelay1 + 1000;
// Apply CF list
applyCFList.Payload = &LoRaMacRxPayload[13];
// Size of the regular payload is 12. Plus 1 byte MHDR and 4 bytes MIC
applyCFList.Size = size - 17;
RegionApplyCFList( LoRaMacRegion, &applyCFList );
MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
IsLoRaMacNetworkJoined = true;
LoRaMacParams.ChannelsDatarate = LoRaMacParamsDefaults.ChannelsDatarate;
}
else
{
MlmeConfirm.Status = LORAMAC_EVENT_INFO_STATUS_JOIN_FAIL;
}
break;
case FRAME_TYPE_DATA_CONFIRMED_DOWN:
case FRAME_TYPE_DATA_UNCONFIRMED_DOWN:
{
// Check if the received payload size is valid
getPhy.UplinkDwellTime = LoRaMacParams.DownlinkDwellTime;
getPhy.Datarate = McpsIndication.RxDatarate;
getPhy.Attribute = PHY_MAX_PAYLOAD;
// Get the maximum payload length
if( RepeaterSupport == true )
{
getPhy.Attribute = PHY_MAX_PAYLOAD_REPEATER;
}
phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
if( MAX( 0, ( int16_t )( ( int16_t )size - ( int16_t )LORA_MAC_FRMPAYLOAD_OVERHEAD ) ) > phyParam.Value )
{
McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ERROR;
PrepareRxDoneAbort( );
return;
}
address = payload[pktHeaderLen++];
address |= ( (uint32_t)payload[pktHeaderLen++] << 8 );
address |= ( (uint32_t)payload[pktHeaderLen++] << 16 );
address |= ( (uint32_t)payload[pktHeaderLen++] << 24 );
if( address != LoRaMacDevAddr )
{
curMulticastParams = MulticastChannels;
while( curMulticastParams != NULL )
{
if( address == curMulticastParams->Address )
{
multicast = 1;
#ifndef TO_SE
nwkSKey = curMulticastParams->NwkSKey;
appSKey = curMulticastParams->AppSKey;
#endif
downLinkCounter = curMulticastParams->DownLinkCounter;
break;
}
curMulticastParams = curMulticastParams->Next;
}
if( multicast == 0 )
{
// We are not the destination of this frame.
McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_ADDRESS_FAIL;
PrepareRxDoneAbort( );
return;
}
}
else
{
multicast = 0;
#ifndef TO_SE
nwkSKey = LoRaMacNwkSKey;
appSKey = LoRaMacAppSKey;
#endif
downLinkCounter = DownLinkCounter;
}
fCtrl.Value = payload[pktHeaderLen++];
sequenceCounter = ( uint16_t )payload[pktHeaderLen++];
sequenceCounter |= ( uint16_t )payload[pktHeaderLen++] << 8;
appPayloadStartIndex = 8 + fCtrl.Bits.FOptsLen;
#ifndef TO_SE
micRx |= ( uint32_t )payload[size - LORAMAC_MFR_LEN];
micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 1] << 8 );
micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 2] << 16 );
micRx |= ( ( uint32_t )payload[size - LORAMAC_MFR_LEN + 3] << 24 );
#endif
sequenceCounterPrev = ( uint16_t )downLinkCounter;
sequenceCounterDiff = ( sequenceCounter - sequenceCounterPrev );
if( sequenceCounterDiff < ( 1 << 15 ) )
{
downLinkCounter += sequenceCounterDiff;
#ifndef TO_SE
LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounter, &mic );
if( micRx == mic )
{
isMicOk = true;
}
#endif
}
else
{
#ifndef TO_SE
// check for sequence roll-over
uint32_t downLinkCounterTmp = downLinkCounter + 0x10000 + ( int16_t )sequenceCounterDiff;
LoRaMacComputeMic( payload, size - LORAMAC_MFR_LEN, nwkSKey, address, DOWN_LINK, downLinkCounterTmp, &mic );
if( micRx == mic )
{
isMicOk = true;
downLinkCounter = downLinkCounterTmp;
}
#else
// assume sequence roll-over
downLinkCounter += 0x10000 + ( int16_t )sequenceCounterDiff;
}
if ( LoRaMacUnsecurePHYPayload( payload, size, payload ) == LORAMAC_CRYPTO_STATUS_OK )
{
isMicOk = true;
#endif
}
// Check for a the maximum allowed counter difference
getPhy.Attribute = PHY_MAX_FCNT_GAP;
phyParam = RegionGetPhyParam( LoRaMacRegion, &getPhy );
if( sequenceCounterDiff >= phyParam.Value )
{
McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_TOO_MANY_FRAMES_LOSS;
McpsIndication.DownLinkCounter = downLinkCounter;
PrepareRxDoneAbort( );
return;
}
if( isMicOk == true )
{
McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_OK;
McpsIndication.Multicast = multicast;
McpsIndication.FramePending = fCtrl.Bits.FPending;
McpsIndication.Buffer = NULL;
McpsIndication.BufferSize = 0;
McpsIndication.DownLinkCounter = downLinkCounter;
McpsConfirm.Status = LORAMAC_EVENT_INFO_STATUS_OK;
AdrAckCounter = 0;
MacCommandsBufferToRepeatIndex = 0;
// Update 32 bits downlink counter
if( multicast == 1 )
{
McpsIndication.McpsIndication = MCPS_MULTICAST;
if( ( curMulticastParams->DownLinkCounter == downLinkCounter ) &&
( curMulticastParams->DownLinkCounter != 0 ) )
{
McpsIndication.Status = LORAMAC_EVENT_INFO_STATUS_DOWNLINK_REPEATED;
McpsIndication.DownLinkCounter = downLinkCounter;
PrepareRxDoneAbort( );
return;
}
curMulticastParams->DownLinkCounter = downLinkCounter;
}
else
{
if( macHdr.Bits.MType == FRAME_TYPE_DATA_CONFIRMED_DOWN )
{
SrvAckRequested = true;
McpsIndication.McpsIndication = MCPS_CONFIRMED;
if( ( DownLinkCounter == downLinkCounter ) &&
( DownLinkCounter != 0 ) )
{
// Duplicated confirmed downlink. Skip indication.
// In this case, the MAC layer shall accept the MAC commands
// which are included in the downlink retransmission.
// It should not provide the same frame to the application
// layer again.
skipIndication = true;
}
}
else
{
SrvAckRequested = false;
McpsIndication.McpsIndication = MCPS_UNCONFIRMED;
if( ( DownLinkCounter == downLinkCounter ) &&
...
This file has been truncated, please download it to see its full contents.
LoRaMacCrypto.c
C/C++File location: Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto.c
#ifndef TO_SE
/*
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC layer implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
*/
#include <stdlib.h>
#include <stdint.h>
#include "utilities.h"
#include "aes.h"
#include "cmac.h"
#include "LoRaMacCrypto.h"
/*!
* CMAC/AES Message Integrity Code (MIC) Block B0 size
*/
#define LORAMAC_MIC_BLOCK_B0_SIZE 16
/*!
* MIC field computation initial data
*/
static uint8_t MicBlockB0[] = { 0x49, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*!
* Contains the computed MIC field.
*
* \remark Only the 4 first bytes are used
*/
static uint8_t Mic[16];
/*!
* Encryption aBlock and sBlock
*/
static uint8_t aBlock[] = { 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static uint8_t sBlock[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
/*!
* AES computation context variable
*/
static aes_context AesContext;
/*!
* CMAC computation context variable
*/
static AES_CMAC_CTX AesCmacCtx[1];
/*!
* \brief Computes the LoRaMAC frame MIC field
*
* \param [IN] buffer Data buffer
* \param [IN] size Data buffer size
* \param [IN] key AES key to be used
* \param [IN] address Frame address
* \param [IN] dir Frame direction [0: uplink, 1: downlink]
* \param [IN] sequenceCounter Frame sequence counter
* \param [OUT] mic Computed MIC field
*/
void LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic )
{
MicBlockB0[5] = dir;
MicBlockB0[6] = ( address ) & 0xFF;
MicBlockB0[7] = ( address >> 8 ) & 0xFF;
MicBlockB0[8] = ( address >> 16 ) & 0xFF;
MicBlockB0[9] = ( address >> 24 ) & 0xFF;
MicBlockB0[10] = ( sequenceCounter ) & 0xFF;
MicBlockB0[11] = ( sequenceCounter >> 8 ) & 0xFF;
MicBlockB0[12] = ( sequenceCounter >> 16 ) & 0xFF;
MicBlockB0[13] = ( sequenceCounter >> 24 ) & 0xFF;
MicBlockB0[15] = size & 0xFF;
AES_CMAC_Init( AesCmacCtx );
AES_CMAC_SetKey( AesCmacCtx, key );
AES_CMAC_Update( AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE );
AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF );
AES_CMAC_Final( Mic, AesCmacCtx );
*mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
}
void LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer )
{
uint16_t i;
uint8_t bufferIndex = 0;
uint16_t ctr = 1;
memset1( AesContext.ksch, '\0', 240 );
aes_set_key( key, 16, &AesContext );
aBlock[5] = dir;
aBlock[6] = ( address ) & 0xFF;
aBlock[7] = ( address >> 8 ) & 0xFF;
aBlock[8] = ( address >> 16 ) & 0xFF;
aBlock[9] = ( address >> 24 ) & 0xFF;
aBlock[10] = ( sequenceCounter ) & 0xFF;
aBlock[11] = ( sequenceCounter >> 8 ) & 0xFF;
aBlock[12] = ( sequenceCounter >> 16 ) & 0xFF;
aBlock[13] = ( sequenceCounter >> 24 ) & 0xFF;
while( size >= 16 )
{
aBlock[15] = ( ( ctr ) & 0xFF );
ctr++;
aes_encrypt( aBlock, sBlock, &AesContext );
for( i = 0; i < 16; i++ )
{
encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
}
size -= 16;
bufferIndex += 16;
}
if( size > 0 )
{
aBlock[15] = ( ( ctr ) & 0xFF );
aes_encrypt( aBlock, sBlock, &AesContext );
for( i = 0; i < size; i++ )
{
encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
}
}
}
void LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer )
{
LoRaMacPayloadEncrypt( buffer, size, key, address, dir, sequenceCounter, decBuffer );
}
void LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic )
{
AES_CMAC_Init( AesCmacCtx );
AES_CMAC_SetKey( AesCmacCtx, key );
AES_CMAC_Update( AesCmacCtx, buffer, size & 0xFF );
AES_CMAC_Final( Mic, AesCmacCtx );
*mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
}
void LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer )
{
memset1( AesContext.ksch, '\0', 240 );
aes_set_key( key, 16, &AesContext );
aes_encrypt( buffer, decBuffer, &AesContext );
// Check if optional CFList is included
if( size >= 16 )
{
aes_encrypt( buffer + 16, decBuffer + 16, &AesContext );
}
}
void LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey )
{
uint8_t nonce[16];
uint8_t *pDevNonce = ( uint8_t * )&devNonce;
memset1( AesContext.ksch, '\0', 240 );
aes_set_key( key, 16, &AesContext );
memset1( nonce, 0, sizeof( nonce ) );
nonce[0] = 0x01;
memcpy1( nonce + 1, appNonce, 6 );
memcpy1( nonce + 7, pDevNonce, 2 );
aes_encrypt( nonce, nwkSKey, &AesContext );
memset1( nonce, 0, sizeof( nonce ) );
nonce[0] = 0x02;
memcpy1( nonce + 1, appNonce, 6 );
memcpy1( nonce + 7, pDevNonce, 2 );
aes_encrypt( nonce, appSKey, &AesContext );
}
#endif /* TO_SE */
LoRaMacCrypto_TO.c
C/C++File location: Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.c
#include <stdio.h>
#include <stdint.h>
#include <LoRaMacCrypto_TO.h>
#include <TO.h>
LoRaMacCryptoStatus_t LoRaMacGetJoinRequest( uint8_t *buffer, uint16_t *size )
{
int ret;
ret = TO_lora_get_join_request_phypayload(buffer);
if (ret != TORSP_SUCCESS) {
fprintf(stderr, "TO get join request error, 0x%X\n", ret);
} else {
*size = TO_LORA_JOINREQUEST_SIZE;
}
return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
}
LoRaMacCryptoStatus_t LoRaMacHandleJoinAccept( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer )
{
int ret;
ret = TO_lora_handle_join_accept_phypayload(buffer, size, outBuffer);
if (ret != TORSP_SUCCESS) {
fprintf(stderr, "TO handle join accept error, 0x%X\n", ret);
}
return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
}
LoRaMacCryptoStatus_t LoRaMacSecurePHYPayload( const uint8_t mhdr, const uint8_t fctrl, const uint8_t *fopts, const uint8_t fport, const uint8_t *payload, const size_t payloadSize, uint8_t *outBuffer )
{
int ret;
ret = TO_lora_secure_phypayload(mhdr, fctrl, fopts, fport, payload, payloadSize, outBuffer);
if (ret != TORSP_SUCCESS) {
fprintf(stderr, "TO secure error, 0x%X\n", ret);
}
return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
}
LoRaMacCryptoStatus_t LoRaMacUnsecurePHYPayload( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer )
{
int ret;
ret = TO_lora_unsecure_phypayload(buffer, size, outBuffer);
if (ret != TORSP_SUCCESS) {
fprintf(stderr, "TO unsecure error, 0x%X\n", ret);
}
return (ret == TORSP_SUCCESS ? LORAMAC_CRYPTO_STATUS_OK : LORAMAC_CRYPTO_STATUS_KO);
}
LoRaMacCrypto_TO.h
C Header FileFile location: Middlewares/Third_Party/Lora/Mac/LoRaMacCrypto_TO.h
/*!
* \file LoRaMacCrypto_TO.h
*
* \brief LoRa MAC layer cryptography implementation
*
* \copyright Revised BSD License, see section \ref LICENSE.
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jckle ( STACKFORCE )
*
* \defgroup LORAMAC_CRYPTO LoRa MAC layer cryptography implementation
* This module covers the implementation of cryptographic functions
* of the LoRaMAC layer.
* \{
*/
#ifndef __LORAMAC_CRYPTO_H__
#define __LORAMAC_CRYPTO_H__
/*!
* LoRaMAC Crypto Status
*/
typedef enum eLoRaMacCryptoStatus
{
/**
* Success
*/
LORAMAC_CRYPTO_STATUS_OK,
/**
* Failure
*/
LORAMAC_CRYPTO_STATUS_KO
} LoRaMacCryptoStatus_t;
/*!
* Get join request encrypted payload.
*
* \param [OUT] buffer - Encrypted payload
* \param [OUT] size - Encrypted payload size
*/
LoRaMacCryptoStatus_t LoRaMacGetJoinRequest( uint8_t *buffer, uint16_t *size );
/*!
* Handle join accept payload.
*
* \param [IN] buffer - Encrypted join accept payload
* \param [IN] size - Encrypted join accept payload size
*/
LoRaMacCryptoStatus_t LoRaMacHandleJoinAccept( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer );
/*!
* Encrypt PHYPayload.
*
* \param [IN] mhdr - MHDR
* \param [IN] fctrl - FCtrl
* \param [IN] fopts - FOpts (optional, depends on FCtrl)
* \param [IN] fport - FOpts (optional, depends on payload)
* \param [IN] payload - MACPayload (optional)
* \param [IN] payloadSize - MACPayload size (must be 0 if no payload)
*/
LoRaMacCryptoStatus_t LoRaMacSecurePHYPayload( const uint8_t mhdr, const uint8_t fctrl, const uint8_t *fopts, const uint8_t fport, const uint8_t *payload, const size_t payloadSize, uint8_t *outBuffer );
/*!
* Decrypt PHYPayload.
*
* \param [IN] buffer - Payload to decrypt
* \param [IN] size - Size of payload
*/
LoRaMacCryptoStatus_t LoRaMacUnsecurePHYPayload( const uint8_t *buffer, const uint16_t size, uint8_t *outBuffer );
/*! \} defgroup LORAMAC */
#endif // __LORAMAC_CRYPTO_H__
Comments