Adding MAC layer for LoRaWAN implementation

The actual mac algorithms are being used as it is in the reference
implementation.

We introduce an internal class that starts a thread and constructs an event queue
to handle deffered calls from interrupt context for RTOS. The code base is
compatible with Mbed-OS 2 as well.

GetPhyEventHandlers() API provides mac callback funtions for PHY layer,
which are in turn delegated to radio driver from the PHY layer.

LoRaMacInitialization() is augmented with LoRaPHY parameter which let's
the MAC layer know which particular PHY layer is in use.

LoRaMacSetTxTimer() and LoRaMacStopTxTimer() are used when duty cycle is
off for testing purpose or to support custom application timers.

If the duty cycle is off, mac and phy layer work togather to figure
out the next possible transmission time.

LoRaMacCrypto APIs are provided which provide seemless integration of
mbedTLS into mac layer for cryptography. User application is supposed to
provide proper mbedTLS configuration file.

All other APIs are retained as it is.
pull/6087/head
Hasnain Virk 2017-11-27 15:03:15 +02:00 committed by Jimmy Brisson
parent c861c321be
commit 5734b57c0a
5 changed files with 4486 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,353 @@
/**
* \file LoRaMac.h
*
* \brief LoRa MAC layer implementation
*
* \copyright Revised BSD License, see LICENSE.TXT file include in the project
*
* \code
* ______ _
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
*
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* \endcode
*
* \author Miguel Luis ( Semtech )
*
* \author Gregory Cristian ( Semtech )
*
* \author Daniel Jaeckle ( STACKFORCE )
*
* \defgroup LORAMAC LoRa MAC layer implementation
* This module specifies the API implementation of the LoRaMAC layer.
* This is a placeholder for a detailed description of the LoRaMac
* layer and the supported features.
*
* Copyright (c) 2017, Arm Limited and affiliates.
* SPDX-License-Identifier: BSD-3-Clause
*
*/
#ifndef __LORAMAC_H__
#define __LORAMAC_H__
#include "lorawan/system/LoRaWANTimer.h"
#include "netsocket/LoRaRadio.h"
#include "lorastack/phy/LoRaPHY.h"
#include "lorawan/system/lorawan_data_structures.h"
/*!
* Check the MAC layer state every MAC_STATE_CHECK_TIMEOUT in ms.
*/
#define MAC_STATE_CHECK_TIMEOUT 1000
/*!
* The maximum number of times the MAC layer tries to get an acknowledge.
*/
#define MAX_ACK_RETRIES 8
/*!
* The frame direction definition for uplink communications.
*/
#define UP_LINK 0
/*!
* The frame direction definition for downlink communications.
*/
#define DOWN_LINK 1
/*!
* LoRaMAC max EIRP (dBm) table.
*/
static const uint8_t LoRaMacMaxEirpTable[] = { 8, 10, 12, 13, 14, 16, 18, 20, 21, 24, 26, 27, 29, 30, 33, 36 };
/*!
* \brief LoRaMAC layer initialization
*
* \details In addition to the initialization of the LoRaMAC layer, this
* function initializes the callback primitives of the MCPS and
* MLME services. Every data field of \ref LoRaMacPrimitives_t must be
* set to a valid callback function.
*
* \param primitives [in] - A pointer to the structure defining the LoRaMAC
* event functions. Refer to \ref LoRaMacPrimitives_t.
*
* \param callbacks [in] - A pointer to the structure defining the LoRaMAC
* callback functions. Refer to \ref LoRaMacCallback_t.
*
* \param phy [in]- A reference to the selected PHY layer.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_PARAMETER_INVALID
* \ref LORAMAC_STATUS_REGION_NOT_SUPPORTED.
*/
LoRaMacStatus_t LoRaMacInitialization( LoRaMacPrimitives_t *primitives, LoRaMacCallback_t *callbacks, LoRaPHY& phy);
/*!
* \brief Queries the LoRaMAC whether it is possible to send the next frame with
* a given payload size. The LoRaMAC takes the scheduled MAC commands into
* account and reports when the frame can be sent.
*
* \param size [in]- The size of the applicable payload to be sent next.
* \param txInfo [out] - The structure \ref LoRaMacTxInfo_t contains
* information on the actual maximum payload possible
* (according to the configured datarate or the next
* datarate according to ADR), and the maximum frame
* size, taking the scheduled MAC commands into account.
*
* \retval `LoRaMacStatus_t` The status of the operation. When the parameters are
* not valid, the function returns \ref LORAMAC_STATUS_PARAMETER_INVALID.
* In case of a length error caused by the applicable payload in combination
* with the MAC commands, the function returns \ref LORAMAC_STATUS_LENGTH_ERROR.
* Please note that if the size of the MAC commands in the queue do
* not fit into the payload size on the related datarate, the LoRaMAC will
* omit the MAC commands.
* If the query is valid, and the LoRaMAC is able to send the frame,
* the function returns \ref LORAMAC_STATUS_OK.
*/
LoRaMacStatus_t LoRaMacQueryTxPossible( uint8_t size, LoRaMacTxInfo_t* txInfo );
/*!
* \brief LoRaMAC channel add service.
*
* \details Adds a new channel to the channel list and activates the ID in
* the channel mask. Please note that this functionality is not available
* in all regions. Information on the allowed ranges is available at the LoRaWAN Regional Parameters V1.0.2rB.
*
* \param id [in] - The ID of the channel.
*
* \param params [in] - The channel parameters to set.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_BUSY
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacChannelAdd( uint8_t id, ChannelParams_t params );
/*!
* \brief LoRaMAC channel remove service.
*
* \details Deactivates the ID in the channel mask.
*
* \param id - Id of the channel.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_BUSY
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacChannelRemove( uint8_t id );
/*!
* \brief LoRaMAC multicast channel link service.
*
* \details Links a multicast channel into the linked list.
*
* \param [in] channelParam - The multicast channel parameters to link.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_BUSY
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacMulticastChannelLink( MulticastParams_t *channelParam );
/*!
* \brief LoRaMAC multicast channel unlink service.
*
* \details Unlinks a multicast channel from the linked list.
*
* \param [in] channelParam - The multicast channel parameters to unlink.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_BUSY
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacMulticastChannelUnlink( MulticastParams_t *channelParam );
/*!
* \brief LoRaMAC MIB-GET.
*
* \details The MAC information base service to get the attributes of the LoRaMac layer.
*
* The following code-snippet shows how to use the API to get the
* parameter `AdrEnable`, defined by the enumeration type
* \ref MIB_ADR.
* \code
* MibRequestConfirm_t mibReq;
* mibReq.Type = MIB_ADR;
*
* if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
* {
* // LoRaMAC updated the parameter mibParam.AdrEnable
* }
* \endcode
*
* \param [in] mibGet - The MIB-GET request to perform. Refer to \ref MibRequestConfirm_t.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_SERVICE_UNKNOWN
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacMibGetRequestConfirm( MibRequestConfirm_t *mibGet );
/*!
* \brief LoRaMAC MIB-SET.
*
* \details The MAC information base service to set the attributes of the LoRaMac layer.
*
* The following code-snippet shows how to use the API to set the
* parameter `AdrEnable`, defined by the enumeration type
* \ref MIB_ADR.
*
* \code
* MibRequestConfirm_t mibReq;
* mibReq.Type = MIB_ADR;
* mibReq.Param.AdrEnable = true;
*
* if( LoRaMacMibGetRequestConfirm( &mibReq ) == LORAMAC_STATUS_OK )
* {
* // LoRaMAC updated the parameter
* }
* \endcode
*
* \param [in] mibSet - The MIB-SET request to perform. Refer to \ref MibRequestConfirm_t.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_BUSY
* \ref LORAMAC_STATUS_SERVICE_UNKNOWN
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacMibSetRequestConfirm( MibRequestConfirm_t *mibSet );
/*!
* \brief LoRaMAC MLME request
*
* \details The MAC layer management entity handles the management services. The
* following code-snippet shows how to use the API to perform a
* network join request.
*
* \code
* static uint8_t DevEui[] =
* {
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
* };
* static uint8_t AppEui[] =
* {
* 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
* };
* static uint8_t AppKey[] =
* {
* 0x2B, 0x7E, 0x15, 0x16, 0x28, 0xAE, 0xD2, 0xA6,
* 0xAB, 0xF7, 0x15, 0x88, 0x09, 0xCF, 0x4F, 0x3C
* };
*
* MlmeReq_t mlmeReq;
* mlmeReq.Type = MLME_JOIN;
* mlmeReq.Req.Join.DevEui = DevEui;
* mlmeReq.Req.Join.AppEui = AppEui;
* mlmeReq.Req.Join.AppKey = AppKey;
*
* if( LoRaMacMlmeRequest( &mlmeReq ) == LORAMAC_STATUS_OK )
* {
* // Service started successfully. Waiting for the Mlme-Confirm event
* }
* \endcode
*
* \param [in] mlmeRequest - The MLME request to perform. Refer to \ref MlmeReq_t.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_BUSY
* \ref LORAMAC_STATUS_SERVICE_UNKNOWN
* \ref LORAMAC_STATUS_PARAMETER_INVALID
* \ref LORAMAC_STATUS_NO_NETWORK_JOINED
* \ref LORAMAC_STATUS_LENGTH_ERROR
* \ref LORAMAC_STATUS_DEVICE_OFF
*/
LoRaMacStatus_t LoRaMacMlmeRequest( MlmeReq_t *mlmeRequest );
/*!
* \brief LoRaMAC MCPS request
*
* \details The MAC Common Part Sublayer handles the data services. The following
* code-snippet shows how to use the API to send an unconfirmed
* LoRaMAC frame.
*
* \code
* uint8_t myBuffer[] = { 1, 2, 3 };
*
* McpsReq_t mcpsReq;
* mcpsReq.Type = MCPS_UNCONFIRMED;
* mcpsReq.Req.Unconfirmed.fPort = 1;
* mcpsReq.Req.Unconfirmed.fBuffer = myBuffer;
* mcpsReq.Req.Unconfirmed.fBufferSize = sizeof( myBuffer );
*
* if( LoRaMacMcpsRequest( &mcpsReq ) == LORAMAC_STATUS_OK )
* {
* // Service started successfully. Waiting for the MCPS-Confirm event
* }
* \endcode
*
* \param [in] mcpsRequest - The MCPS request to perform. Refer to \ref McpsReq_t.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_BUSY
* \ref LORAMAC_STATUS_SERVICE_UNKNOWN
* \ref LORAMAC_STATUS_PARAMETER_INVALID
* \ref LORAMAC_STATUS_NO_NETWORK_JOINED
* \ref LORAMAC_STATUS_LENGTH_ERROR
* \ref LORAMAC_STATUS_DEVICE_OFF
*/
LoRaMacStatus_t LoRaMacMcpsRequest( McpsReq_t *mcpsRequest );
/**
* \brief LoRaMAC layer provides its callback functions for
* PHY layer
*
* \return Pointer to callback functions for radio events
*/
radio_events_t *GetPhyEventHandlers();
/**
* \brief LoRaMAC set tx timer.
*
* \details Sets up a timer for next transmission (application specific timers).
*
* \param [in] NextTxTime - Periodic time for next uplink.
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacSetTxTimer( uint32_t NextTxTime );
/**
* \brief LoRaMAC stop tx timer.
*
* \details Stops the next tx timer.
*
* \retval `LoRaMacStatus_t` The status of the operation. The possible values are:
* \ref LORAMAC_STATUS_OK
* \ref LORAMAC_STATUS_PARAMETER_INVALID
*/
LoRaMacStatus_t LoRaMacStopTxTimer( );
#endif // __LORAMAC_H__

View File

@ -0,0 +1,347 @@
/**
* / _____) _ | |
* ( (____ _____ ____ _| |_ _____ ____| |__
* \____ \| ___ | (_ _) ___ |/ ___) _ \
* _____) ) ____| | | || |_| ____( (___| | | |
* (______/|_____)_|_|_| \__)_____)\____)_| |_|
* (C)2013 Semtech
* ___ _____ _ ___ _ _____ ___ ___ ___ ___
* / __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
* \__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
* |___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
* embedded.connectivity.solutions===============
*
* Description: LoRa MAC crypto implementation
*
* License: Revised BSD License, see LICENSE.TXT file include in the project
*
* Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jäckle ( STACKFORCE )
*
*
* Copyright (c) 2017, Arm Limited and affiliates.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <stdlib.h>
#include <stdint.h>
#include "lorastack/mac/LoRaMacCrypto.h"
#include "lorawan/system/lorawan_data_structures.h"
#include "mbedtls/aes.h"
#include "mbedtls/cmac.h"
#if defined(MBEDTLS_CMAC_C) && defined(MBEDTLS_AES_C) && defined(MBEDTLS_CIPHER_C)
/**
* 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 mbedtls_aes_context AesContext;
/**
* CMAC computation context variable
*/
static mbedtls_cipher_context_t AesCmacCtx[1];
#define AES_CMAC_KEY_LENGTH 16
/**
* \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
*/
int LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic )
{
int ret = 0;
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;
mbedtls_cipher_init(AesCmacCtx);
const mbedtls_cipher_info_t* cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB);
if (NULL != cipher_info) {
ret = mbedtls_cipher_setup(AesCmacCtx, cipher_info);
if (0 != ret)
goto exit;
ret = mbedtls_cipher_cmac_starts(AesCmacCtx, key, AES_CMAC_KEY_LENGTH*8);
if (0 != ret)
goto exit;
ret = mbedtls_cipher_cmac_update(AesCmacCtx, MicBlockB0, LORAMAC_MIC_BLOCK_B0_SIZE);
if (0 != ret)
goto exit;
ret = mbedtls_cipher_cmac_update(AesCmacCtx, buffer, size & 0xFF);
if (0 != ret)
goto exit;
ret = mbedtls_cipher_cmac_finish(AesCmacCtx, Mic);
if (0 != ret)
goto exit;
*mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
} else {
ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED;
}
exit:
mbedtls_cipher_free( AesCmacCtx );
return ret;
}
int 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;
int ret = 0;
mbedtls_aes_init(&AesContext);
ret = mbedtls_aes_setkey_enc(&AesContext, key, 16*8);
if (0 != ret)
goto exit;
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++;
ret = mbedtls_aes_crypt_ecb(&AesContext, MBEDTLS_AES_ENCRYPT, aBlock, sBlock);
if (0 != ret)
goto exit;
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 );
ret = mbedtls_aes_crypt_ecb(&AesContext, MBEDTLS_AES_ENCRYPT, aBlock, sBlock);
if (0 != ret)
goto exit;
for( i = 0; i < size; i++ )
{
encBuffer[bufferIndex + i] = buffer[bufferIndex + i] ^ sBlock[i];
}
}
exit:
mbedtls_aes_free(&AesContext);
return ret;
}
int LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer )
{
return LoRaMacPayloadEncrypt( buffer, size, key, address, dir, sequenceCounter, decBuffer );
}
int LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic )
{
int ret = 0;
mbedtls_cipher_init(AesCmacCtx);
const mbedtls_cipher_info_t* cipher_info = mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB);
if (NULL != cipher_info) {
ret = mbedtls_cipher_setup(AesCmacCtx, cipher_info);
if (0 != ret)
goto exit;
ret = mbedtls_cipher_cmac_starts(AesCmacCtx, key, AES_CMAC_KEY_LENGTH*8);
if (0 != ret)
goto exit;
ret = mbedtls_cipher_cmac_update(AesCmacCtx, buffer, size & 0xFF);
if (0 != ret)
goto exit;
ret = mbedtls_cipher_cmac_finish(AesCmacCtx, Mic);
if (0 != ret)
goto exit;
*mic = ( uint32_t )( ( uint32_t )Mic[3] << 24 | ( uint32_t )Mic[2] << 16 | ( uint32_t )Mic[1] << 8 | ( uint32_t )Mic[0] );
} else {
ret = MBEDTLS_ERR_CIPHER_ALLOC_FAILED;
}
exit:
mbedtls_cipher_free(AesCmacCtx);
return ret;
}
int LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer )
{
int ret = 0;
mbedtls_aes_init(&AesContext);
ret = mbedtls_aes_setkey_enc(&AesContext, key, 16*8);
if (0 != ret)
goto exit;
ret = mbedtls_aes_crypt_ecb(&AesContext, MBEDTLS_AES_ENCRYPT, buffer, decBuffer);
if (0 != ret)
goto exit;
// Check if optional CFList is included
if( size >= 16 )
{
ret = mbedtls_aes_crypt_ecb(&AesContext, MBEDTLS_AES_ENCRYPT, buffer + 16, decBuffer + 16);
}
exit:
mbedtls_aes_free(&AesContext);
return ret;
}
int 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;
int ret = 0;
mbedtls_aes_init(&AesContext);
ret = mbedtls_aes_setkey_enc(&AesContext, key, 16*8);
if (0 != ret)
goto exit;
memset( nonce, 0, sizeof( nonce ) );
nonce[0] = 0x01;
memcpy( nonce + 1, appNonce, 6 );
memcpy( nonce + 7, pDevNonce, 2 );
ret = mbedtls_aes_crypt_ecb(&AesContext, MBEDTLS_AES_ENCRYPT, nonce, nwkSKey);
if (0 != ret)
goto exit;
memset( nonce, 0, sizeof( nonce ) );
nonce[0] = 0x02;
memcpy( nonce + 1, appNonce, 6 );
memcpy( nonce + 7, pDevNonce, 2 );
ret = mbedtls_aes_crypt_ecb(&AesContext, MBEDTLS_AES_ENCRYPT, nonce, appSKey);
exit:
mbedtls_aes_free(&AesContext);
return ret;
}
#else
// If mbedTLS is not configured properly, these dummies will ensure that
// user knows what is wrong and in addition to that these ensure that
// Mbed-OS compiles properly under normal conditions where LoRaWAN in conjunction
// with mbedTLS is not being used.
int LoRaMacComputeMic( const uint8_t *, uint16_t , const uint8_t *, uint32_t,
uint8_t dir, uint32_t, uint32_t * )
{
MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
// Never actually reaches here
return LORA_MAC_STATUS_CRYPTO_FAIL;
}
int LoRaMacPayloadEncrypt( const uint8_t *, uint16_t , const uint8_t *, uint32_t,
uint8_t , uint32_t , uint8_t * )
{
MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
// Never actually reaches here
return LORA_MAC_STATUS_CRYPTO_FAIL;
}
int LoRaMacPayloadDecrypt( const uint8_t *, uint16_t , const uint8_t *, uint32_t,
uint8_t , uint32_t , uint8_t * )
{
MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
// Never actually reaches here
return LORA_MAC_STATUS_CRYPTO_FAIL;
}
int LoRaMacJoinComputeMic( const uint8_t *, uint16_t , const uint8_t *, uint32_t * )
{
MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
// Never actually reaches here
return LORA_MAC_STATUS_CRYPTO_FAIL;
}
int LoRaMacJoinDecrypt( const uint8_t *, uint16_t , const uint8_t *, uint8_t * )
{
MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
// Never actually reaches here
return LORA_MAC_STATUS_CRYPTO_FAIL;
}
int LoRaMacJoinComputeSKeys( const uint8_t *, const uint8_t *, uint16_t , uint8_t *, uint8_t * )
{
MBED_ASSERT("[LoRaCrypto] Must enable AES, CMAC & CIPHER from mbedTLS");
// Never actually reaches here
return LORA_MAC_STATUS_CRYPTO_FAIL;
}
#endif

View File

@ -0,0 +1,112 @@
/**
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC Crypto implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
Copyright (c) 2017, Arm Limited and affiliates.
SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__
#define MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__
/**
* 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
*
* \return 0 if successful, or a cipher specific error code
*/
int LoRaMacComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint32_t *mic );
/**
* Computes the LoRaMAC payload encryption
*
* \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] encBuffer - Encrypted buffer
*
* \return 0 if successful, or a cipher specific error code
*/
int LoRaMacPayloadEncrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *encBuffer );
/**
* Computes the LoRaMAC payload decryption
*
* \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] decBuffer - Decrypted buffer
*
* \return 0 if successful, or a cipher specific error code
*/
int LoRaMacPayloadDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t address, uint8_t dir, uint32_t sequenceCounter, uint8_t *decBuffer );
/**
* Computes the LoRaMAC Join Request frame MIC field
*
* \param [in] buffer - Data buffer
* \param [in] size - Data buffer size
* \param [in] key - AES key to be used
* \param [out] mic - Computed MIC field
*
* \return 0 if successful, or a cipher specific error code
*
*/
int LoRaMacJoinComputeMic( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint32_t *mic );
/**
* Computes the LoRaMAC join frame decryption
*
* \param [in] buffer - Data buffer
* \param [in] size - Data buffer size
* \param [in] key - AES key to be used
* \param [out] decBuffer - Decrypted buffer
*
* \return 0 if successful, or a cipher specific error code
*/
int LoRaMacJoinDecrypt( const uint8_t *buffer, uint16_t size, const uint8_t *key, uint8_t *decBuffer );
/**
* Computes the LoRaMAC join frame decryption
*
* \param [in] key - AES key to be used
* \param [in] appNonce - Application nonce
* \param [in] devNonce - Device nonce
* \param [out] nwkSKey - Network session key
* \param [out] appSKey - Application session key
*
* \return 0 if successful, or a cipher specific error code
*/
int LoRaMacJoinComputeSKeys( const uint8_t *key, const uint8_t *appNonce, uint16_t devNonce, uint8_t *nwkSKey, uint8_t *appSKey );
#endif // MBED_LORAWAN_MAC_LORAMAC_CRYPTO_H__

View File

@ -0,0 +1,68 @@
/**
/ _____) _ | |
( (____ _____ ____ _| |_ _____ ____| |__
\____ \| ___ | (_ _) ___ |/ ___) _ \
_____) ) ____| | | || |_| ____( (___| | | |
(______/|_____)_|_|_| \__)_____)\____)_| |_|
(C)2013 Semtech
___ _____ _ ___ _ _____ ___ ___ ___ ___
/ __|_ _/_\ / __| |/ / __/ _ \| _ \/ __| __|
\__ \ | |/ _ \ (__| ' <| _| (_) | / (__| _|
|___/ |_/_/ \_\___|_|\_\_| \___/|_|_\\___|___|
embedded.connectivity.solutions===============
Description: LoRa MAC layer test function implementation
License: Revised BSD License, see LICENSE.TXT file include in the project
Maintainer: Miguel Luis ( Semtech ), Gregory Cristian ( Semtech ) and Daniel Jaeckle ( STACKFORCE )
Copyright (c) 2017, Arm Limited and affiliates.
SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef __LORAMACTEST_H__
#define __LORAMACTEST_H__
/**
* \brief Enabled or disables the reception windows
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [in] enable - Enabled or disables the reception windows
*/
void LoRaMacTestRxWindowsOn( bool enable );
/**
* \brief Enables the MIC field test
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [in] txPacketCounter - Fixed Tx packet counter value
*/
void LoRaMacTestSetMic( uint16_t txPacketCounter );
/**
* \brief Enabled or disables the duty cycle
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [in] enable - Enabled or disables the duty cycle
*/
void LoRaMacTestSetDutyCycleOn( bool enable );
/**
* \brief Sets the channel index
*
* \details This is a test function. It shall be used for testing purposes only.
* Changing this attribute may lead to a non-conformance LoRaMac operation.
*
* \param [in] channel - Channel index
*/
void LoRaMacTestSetChannel( uint8_t channel );
#endif // __LORAMACTEST_H__