mirror of
https://github.com/espressif/openthread.git
synced 2026-08-13 22:27:47 +00:00
[ncp] Transforming spinel frames between AP and NCP (#2402)
* [ncp] Transforming spinel frames between AP and NCP NCP Spinel Transformer allows to transform spinel frames sent between Application Processor (AP) and Network Co-Processor (NCP). Spinel frames can be transformed by using transformer library (or libraries) implementing spinel_transformer.hpp. Libraries can be specified using option --with-ncp-spinel-transformer-libs. Addidionaly, transformer's outbound buffer can be changed if needed, using option --with-ncp-spinel-transformer-outbound-buffer-size.
This commit is contained in:
committed by
Jonathan Hui
parent
c59da516ae
commit
6284d5cad6
@@ -921,6 +921,31 @@ AC_SUBST(OPENTHREAD_NCP_VENDOR_HOOK_SOURCE)
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_NCP_VENDOR_HOOK],[${OPENTHREAD_ENABLE_NCP_VENDOR_HOOK}],[Define to 1 if using NCP vendor hook])
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_NCP_VENDOR_HOOK], [test "${OPENTHREAD_ENABLE_NCP_VENDOR_HOOK}" = "1"])
|
||||
|
||||
#
|
||||
# NCP Spinel Encrypter
|
||||
#
|
||||
|
||||
AC_ARG_WITH(
|
||||
[ncp-spinel-encrypter-libs],
|
||||
[AS_HELP_STRING([--with-ncp-spinel-encrypter-libs=<LIBSPINEL_ENCRYPTER.A>],[Specify library files (absolute paths) implementing the NCP Spinel Encrypter. @<:@default=none@:>@.])],
|
||||
[
|
||||
if test "${withval}" = "no"
|
||||
then OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER=0
|
||||
else
|
||||
OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER=1
|
||||
OPENTHREAD_NCP_SPINEL_ENCRYPTER_LIBS=${withval}
|
||||
fi
|
||||
],
|
||||
[
|
||||
OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER=0
|
||||
])
|
||||
|
||||
AC_MSG_CHECKING([for NCP Spinel Encrypter])
|
||||
AC_MSG_RESULT(${OPENTHREAD_NCP_SPINEL_ENCRYPTER_LIBS-none})
|
||||
AC_SUBST(OPENTHREAD_NCP_SPINEL_ENCRYPTER_LIBS)
|
||||
AC_DEFINE_UNQUOTED([OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER],[${OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER}],[Define to 1 if using NCP Spinel Encrypter])
|
||||
AM_CONDITIONAL([OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER], [test "${OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER}" = "1"])
|
||||
|
||||
#
|
||||
# Child Supervision
|
||||
#
|
||||
@@ -1564,6 +1589,7 @@ AC_MSG_NOTICE([
|
||||
OpenThread NCP-FTD support : ${enable_ncp_app_ftd}
|
||||
OpenThread NCP-BUS Configuration : ${with_ncp_bus}
|
||||
OpenThread NCP Vendor Hook Source : ${with_ncp_vendor_hook_source}
|
||||
OpenThread NCP Spinel Encrypter : ${with_ncp_spinel_encrypter_libs}
|
||||
OpenThread Multiple Instances support : ${enable_multiple_instances}
|
||||
OpenThread MTD Network Diagnostic support : ${enable_mtd_network_diagnostic}
|
||||
OpenThread builtin mbedtls support : ${enable_builtin_mbedtls}
|
||||
|
||||
@@ -63,6 +63,12 @@ LDADD_COMMON += \
|
||||
$(NULL)
|
||||
endif
|
||||
|
||||
if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
LDADD_COMMON += \
|
||||
$(OPENTHREAD_NCP_SPINEL_ENCRYPTER_LIBS) \
|
||||
$(NULL)
|
||||
endif # OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
|
||||
if OPENTHREAD_ENABLE_NCP_FTD
|
||||
bin_PROGRAMS += \
|
||||
ot-ncp-ftd \
|
||||
|
||||
@@ -803,6 +803,17 @@
|
||||
#define OPENTHREAD_CONFIG_NCP_SPI_BUFFER_SIZE 1300
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NCP_SPINEL_ENCRYPTER_EXTRA_DATA_SIZE
|
||||
*
|
||||
* The size of extra data to be allocated in UART buffer,
|
||||
* needed by NCP Spinel Encrypter.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_NCP_SPINEL_ENCRYPTER_EXTRA_DATA_SIZE
|
||||
#define OPENTHREAD_CONFIG_NCP_SPINEL_ENCRYPTER_EXTRA_DATA_SIZE 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_PLATFORM_ASSERT_MANAGEMENT
|
||||
*
|
||||
|
||||
+86
-5
@@ -105,6 +105,9 @@ NcpUart::NcpUart(Instance *aInstance):
|
||||
mByte(0),
|
||||
mUartSendImmediate(false),
|
||||
mUartSendTask(*aInstance, EncodeAndSendToUart, this)
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
, mTxFrameBufferEncrypterReader(mTxFrameBuffer)
|
||||
#endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
{
|
||||
mTxFrameBuffer.SetFrameAddedCallback(HandleFrameAddedToNcpBuffer, this);
|
||||
|
||||
@@ -142,8 +145,13 @@ void NcpUart::EncodeAndSendToUart(void)
|
||||
{
|
||||
uint16_t len;
|
||||
bool prevHostPowerState;
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
NcpFrameBufferEncrypterReader &txFrameBuffer = mTxFrameBufferEncrypterReader;
|
||||
#else
|
||||
NcpFrameBuffer &txFrameBuffer = mTxFrameBuffer;
|
||||
#endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
|
||||
while (!mTxFrameBuffer.IsEmpty() || (mState == kFinalizingFrame))
|
||||
while (!txFrameBuffer.IsEmpty() || (mState == kFinalizingFrame))
|
||||
{
|
||||
switch (mState)
|
||||
{
|
||||
@@ -157,13 +165,13 @@ void NcpUart::EncodeAndSendToUart(void)
|
||||
VerifyOrExit(super_t::ShouldDeferHostSend() == false);
|
||||
SuccessOrExit(mFrameEncoder.Init(mUartBuffer));
|
||||
|
||||
mTxFrameBuffer.OutFrameBegin();
|
||||
txFrameBuffer.OutFrameBegin();
|
||||
|
||||
mState = kEncodingFrame;
|
||||
|
||||
while (!mTxFrameBuffer.OutFrameHasEnded())
|
||||
while (!txFrameBuffer.OutFrameHasEnded())
|
||||
{
|
||||
mByte = mTxFrameBuffer.OutFrameReadByte();
|
||||
mByte = txFrameBuffer.OutFrameReadByte();
|
||||
|
||||
case kEncodingFrame:
|
||||
|
||||
@@ -174,7 +182,7 @@ void NcpUart::EncodeAndSendToUart(void)
|
||||
// call to OutFrameRemove.
|
||||
prevHostPowerState = mHostPowerStateInProgress;
|
||||
|
||||
mTxFrameBuffer.OutFrameRemove();
|
||||
txFrameBuffer.OutFrameRemove();
|
||||
|
||||
if (prevHostPowerState && !mHostPowerStateInProgress)
|
||||
{
|
||||
@@ -256,7 +264,15 @@ void NcpUart::HandleFrame(void *aContext, uint8_t *aBuf, uint16_t aBufLength)
|
||||
|
||||
void NcpUart::HandleFrame(uint8_t *aBuf, uint16_t aBufLength)
|
||||
{
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
size_t dataLen = aBufLength;
|
||||
if (SpinelEncrypter::DecryptInbound(aBuf, sizeof(mRxBuffer), &dataLen))
|
||||
{
|
||||
super_t::HandleReceive(aBuf, dataLen);
|
||||
}
|
||||
#else
|
||||
super_t::HandleReceive(aBuf, aBufLength);
|
||||
#endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
}
|
||||
|
||||
void NcpUart::HandleError(void *aContext, otError aError, uint8_t *aBuf, uint16_t aBufLength)
|
||||
@@ -297,6 +313,71 @@ void NcpUart::HandleError(otError aError, uint8_t *aBuf, uint16_t aBufLength)
|
||||
otNcpStreamWrite(0, reinterpret_cast<uint8_t *>(hexbuf + 1), static_cast<int>(strlen(hexbuf) - 1));
|
||||
}
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
|
||||
NcpUart::NcpFrameBufferEncrypterReader::NcpFrameBufferEncrypterReader(NcpFrameBuffer &aTxFrameBuffer) :
|
||||
mTxFrameBuffer(aTxFrameBuffer),
|
||||
mDataBufferReadIndex(0),
|
||||
mOutputDataLength(0) {}
|
||||
|
||||
bool NcpUart::NcpFrameBufferEncrypterReader::IsEmpty() const
|
||||
{
|
||||
return mTxFrameBuffer.IsEmpty() && !mOutputDataLength;
|
||||
}
|
||||
|
||||
otError NcpUart::NcpFrameBufferEncrypterReader::OutFrameBegin()
|
||||
{
|
||||
otError status = OT_ERROR_FAILED;
|
||||
|
||||
Reset();
|
||||
|
||||
if ((status = mTxFrameBuffer.OutFrameBegin()) == OT_ERROR_NONE)
|
||||
{
|
||||
mOutputDataLength = mTxFrameBuffer.OutFrameGetLength();
|
||||
|
||||
if (mOutputDataLength > 0)
|
||||
{
|
||||
assert(mOutputDataLength <= sizeof(mDataBuffer));
|
||||
mTxFrameBuffer.OutFrameRead(mOutputDataLength, mDataBuffer);
|
||||
|
||||
if (!SpinelEncrypter::EncryptOutbound(mDataBuffer, sizeof(mDataBuffer), &mOutputDataLength))
|
||||
{
|
||||
mOutputDataLength = 0;
|
||||
status = OT_ERROR_FAILED;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
status = OT_ERROR_FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool NcpUart::NcpFrameBufferEncrypterReader::OutFrameHasEnded()
|
||||
{
|
||||
return (mDataBufferReadIndex >= mOutputDataLength);
|
||||
}
|
||||
|
||||
uint8_t NcpUart::NcpFrameBufferEncrypterReader::OutFrameReadByte()
|
||||
{
|
||||
return mDataBuffer[mDataBufferReadIndex++];
|
||||
}
|
||||
|
||||
otError NcpUart::NcpFrameBufferEncrypterReader::OutFrameRemove()
|
||||
{
|
||||
return mTxFrameBuffer.OutFrameRemove();
|
||||
}
|
||||
|
||||
void NcpUart::NcpFrameBufferEncrypterReader::Reset()
|
||||
{
|
||||
mOutputDataLength = 0;
|
||||
mDataBufferReadIndex = 0;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
|
||||
} // namespace Ncp
|
||||
} // namespace ot
|
||||
|
||||
|
||||
+40
-3
@@ -38,6 +38,10 @@
|
||||
#include "ncp/hdlc.hpp"
|
||||
#include "ncp/ncp_base.hpp"
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
#include "spinel_encrypter.hpp"
|
||||
#endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
|
||||
namespace ot {
|
||||
namespace Ncp {
|
||||
|
||||
@@ -70,9 +74,9 @@ private:
|
||||
|
||||
enum
|
||||
{
|
||||
kUartTxBufferSize = OPENTHREAD_CONFIG_NCP_UART_TX_CHUNK_SIZE, // Uart tx buffer size.
|
||||
kRxBufferSize = OPENTHREAD_CONFIG_NCP_UART_RX_BUFFER_SIZE, // Rx buffer size (should be large enough to fit
|
||||
// one whole (decoded) received frame).
|
||||
kUartTxBufferSize = OPENTHREAD_CONFIG_NCP_UART_TX_CHUNK_SIZE, // Uart tx buffer size.
|
||||
kRxBufferSize = OPENTHREAD_CONFIG_NCP_UART_RX_BUFFER_SIZE + // Rx buffer size (should be large enough to fit
|
||||
OPENTHREAD_CONFIG_NCP_SPINEL_ENCRYPTER_EXTRA_DATA_SIZE, // one whole (decoded) received frame).
|
||||
};
|
||||
|
||||
enum UartTxState
|
||||
@@ -96,6 +100,35 @@ private:
|
||||
uint8_t mBuffer[kUartTxBufferSize];
|
||||
};
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
/**
|
||||
* Wraps NcpFrameBuffer allowing to read data through spinel encrypter.
|
||||
* Creates additional buffers to allow transforming of the whole spinel frames.
|
||||
*/
|
||||
class NcpFrameBufferEncrypterReader
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* C-tor.
|
||||
* Takes a reference to NcpFrameBuffer in order to read spinel frames.
|
||||
*/
|
||||
explicit NcpFrameBufferEncrypterReader(NcpFrameBuffer &aTxFrameBuffer);
|
||||
bool IsEmpty() const;
|
||||
otError OutFrameBegin();
|
||||
bool OutFrameHasEnded();
|
||||
uint8_t OutFrameReadByte();
|
||||
otError OutFrameRemove();
|
||||
|
||||
private:
|
||||
void Reset();
|
||||
|
||||
NcpFrameBuffer &mTxFrameBuffer;
|
||||
uint8_t mDataBuffer[kRxBufferSize];
|
||||
size_t mDataBufferReadIndex;
|
||||
size_t mOutputDataLength;
|
||||
};
|
||||
#endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
|
||||
void EncodeAndSendToUart(void);
|
||||
void HandleFrame(uint8_t *aBuf, uint16_t aBufLength);
|
||||
void HandleError(otError aError, uint8_t *aBuf, uint16_t aBufLength);
|
||||
@@ -116,6 +149,10 @@ private:
|
||||
uint8_t mRxBuffer[kRxBufferSize];
|
||||
bool mUartSendImmediate;
|
||||
Tasklet mUartSendTask;
|
||||
|
||||
#if OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
NcpFrameBufferEncrypterReader mTxFrameBufferEncrypterReader;
|
||||
#endif // OPENTHREAD_ENABLE_NCP_SPINEL_ENCRYPTER
|
||||
};
|
||||
|
||||
} // namespace Ncp
|
||||
|
||||
@@ -82,6 +82,24 @@
|
||||
|
||||
#define SPINEL_FRAME_MAX_SIZE 1300
|
||||
|
||||
/**
|
||||
* @def SPINEL_ENCRYPTER_EXTRA_DATA_SIZE
|
||||
*
|
||||
* The size of extra data to be allocated for spinel frame buffer,
|
||||
* needed by Spinel Encrypter.
|
||||
*
|
||||
*/
|
||||
#define SPINEL_ENCRYPTER_EXTRA_DATA_SIZE 0
|
||||
|
||||
/**
|
||||
* @def SPINEL_FRAME_BUFFER_SIZE
|
||||
*
|
||||
* The size of buffer large enough to fit one whole spinel frame with extra data
|
||||
* needed by Spinel Encrypter.
|
||||
*
|
||||
*/
|
||||
#define SPINEL_FRAME_BUFFER_SIZE (SPINEL_FRAME_MAX_SIZE + SPINEL_ENCRYPTER_EXTRA_DATA_SIZE)
|
||||
|
||||
/// Macro for generating bit masks using bit index from the spec
|
||||
#define SPINEL_BIT_MASK(bit_index,field_bit_count) \
|
||||
( (1 << ((field_bit_count) - 1)) >> (bit_index) )
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* Allows to encrypt spinel frames sent between Application Processor (AP) and Network Co-Processor (NCP).
|
||||
*/
|
||||
|
||||
namespace SpinelEncrypter {
|
||||
|
||||
/**
|
||||
* Encrypts spinel frames before sending to AP/NCP.
|
||||
*
|
||||
* This method encrypts outbound frames in both directions, i.e. from AP to NCP and from NCP to AP.
|
||||
*
|
||||
* @param[in,out] aFrameBuf Pointer to buffer containing the frame, also where the encrypted frame will be placed.
|
||||
* @param[in] aFrameSize Max number of bytes in frame buffer (max length of spinel frame + additional data for encryption).
|
||||
* @param[in,out] aFrameLength Pointer to store frame length, on input value is set to frame length,
|
||||
* on output changed to show the frame length after encryption.
|
||||
* @return \c true on success, \c false otherwise.
|
||||
*/
|
||||
bool EncryptOutbound(unsigned char *aFrameBuf, size_t aFrameSize, size_t *aFrameLength);
|
||||
|
||||
/**
|
||||
* Decrypts spinel frames received from AP/NCP.
|
||||
*
|
||||
* This method decrypts inbound frames in both directions, i.e. from AP to NCP and from NCP to AP.
|
||||
*
|
||||
* @param[in,out] aFrameBuf Pointer to buffer containing encrypted frame, also where the decrypted frame will be placed.
|
||||
* @param[in] aFrameSize Max number of bytes in frame buffer (max length of spinel frame + additional data for encryption).
|
||||
* @param[in,out] aFrameLength Pointer to store frame length, on input value is set to encrypted frame length,
|
||||
* on output changed to show the frame length after decryption.
|
||||
* @return \c true on success, \c false otherwise.
|
||||
*/
|
||||
bool DecryptInbound(unsigned char *aFrameBuf, size_t aFrameSize, size_t *aFrameLength);
|
||||
|
||||
} // namespace SpinelEncrypter
|
||||
Reference in New Issue
Block a user