mirror of
https://github.com/espressif/openthread.git
synced 2026-10-29 18:54:06 +00:00
NcpBase: Implement support for PEEK and POKE spinel commands (#1899)
The configuration option `OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE` enables/disables the peek/poke commands feature by NCP. By default it is disabled. If enabled, platform code can restrict access to certain memory regions using separate peek and poke delegate function pointers.
This commit is contained in:
committed by
Jonathan Hui
parent
8dc31d6e27
commit
b6f821d728
@@ -83,6 +83,38 @@ void otNcpInit(otInstance *aInstance);
|
||||
*/
|
||||
otError otNcpStreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Peek/Poke memory access control delegates
|
||||
|
||||
/**
|
||||
* Defines delegate (function pointer) type to control behavior of peek/poke operation.
|
||||
*
|
||||
* This delegate function is called to decide whether to allow peek or poke of a specific memory region. It is used
|
||||
* if NCP support for peek/poke commands is enabled.
|
||||
*
|
||||
* @param[in] aAddress Start address of memory region.
|
||||
* @param[in] aCount Number of bytes to peek or poke.
|
||||
*
|
||||
* @returns TRUE to allow peek/poke of the given memory region, FALSE otherwise.
|
||||
*
|
||||
*/
|
||||
typedef bool (*otNcpDelegateAllowPeekPoke)(uint32_t aAddress, uint16_t aCount);
|
||||
|
||||
/**
|
||||
* This method registers peek/poke delegate functions with NCP module.
|
||||
*
|
||||
* The delegate functions are called by NCP module to decide whether to allow peek or poke of a specific memory region.
|
||||
* If the delegate pointer is set to NULL, it allows peek/poke operation for any address.
|
||||
*
|
||||
* @param[in] aAllowPeekDelegate Delegate function pointer for peek operation.
|
||||
* @param[in] aAllowPeekDelegate Delegate function pointer for poke operation.
|
||||
*
|
||||
* @retval OT_ERROR_NONE Successfully registered delegate functions.
|
||||
* @retval OT_ERROR_DISABLED_FEATURE Peek/Poke feature is disabled (by a build-time configuration option).
|
||||
*
|
||||
*/
|
||||
otError otNcpRegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
|
||||
otNcpDelegateAllowPeekPoke aAllowPokeDelegate);
|
||||
|
||||
//-----------------------------------------------------------------------------------------
|
||||
// Legacy network APIs
|
||||
|
||||
@@ -810,7 +810,19 @@
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_SUPERVISION_MSG_NO_ACK_REQUEST
|
||||
#define OPENTHREAD_CONFIG_SUPERVISION_MSG_NO_ACK_REQUEST 0
|
||||
#define OPENTHREAD_CONFIG_SUPERVISION_MSG_NO_ACK_REQUEST 0
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @def OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
*
|
||||
* Define as 1 to enable peek/poke functionality on NCP.
|
||||
*
|
||||
* Peek/Poke allows the host to read/write to memory addresses on NCP. This is intended for debugging.
|
||||
*
|
||||
*/
|
||||
#ifndef OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
#define OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE 0
|
||||
#endif
|
||||
|
||||
#endif // OPENTHREAD_CORE_DEFAULT_CONFIG_H_
|
||||
|
||||
+153
-1
@@ -104,6 +104,10 @@ const NcpBase::CommandHandlerEntry NcpBase::mCommandHandlerTable[] =
|
||||
{ SPINEL_CMD_NET_SAVE, &NcpBase::CommandHandler_NET_SAVE },
|
||||
{ SPINEL_CMD_NET_CLEAR, &NcpBase::CommandHandler_NET_CLEAR },
|
||||
{ SPINEL_CMD_NET_RECALL, &NcpBase::CommandHandler_NET_RECALL },
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
{ SPINEL_CMD_PEEK, &NcpBase::CommandHandler_PEEK },
|
||||
{ SPINEL_CMD_POKE, &NcpBase::CommandHandler_POKE },
|
||||
#endif
|
||||
};
|
||||
|
||||
const NcpBase::GetPropertyHandlerEntry NcpBase::mGetPropertyHandlerTable[] =
|
||||
@@ -649,6 +653,10 @@ NcpBase::NcpBase(otInstance *aInstance):
|
||||
mHostPowerStateHeader(0),
|
||||
#if OPENTHREAD_ENABLE_JAM_DETECTION
|
||||
mShouldSignalJamStateChange(false),
|
||||
#endif
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
mAllowPeekDelegate(NULL),
|
||||
mAllowPokeDelegate(NULL),
|
||||
#endif
|
||||
mDroppedReplyTid(0),
|
||||
mDroppedReplyTidBitSet(0),
|
||||
@@ -2001,6 +2009,109 @@ otError NcpBase::CommandHandler_NET_RECALL(uint8_t header, unsigned int command,
|
||||
return SendLastStatus(header, SPINEL_STATUS_UNIMPLEMENTED);
|
||||
}
|
||||
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
|
||||
otError NcpBase::CommandHandler_PEEK(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len)
|
||||
{
|
||||
spinel_ssize_t parsedLength;
|
||||
uint32_t address;
|
||||
uint16_t count;
|
||||
spinel_status_t spinel_error = SPINEL_STATUS_OK;
|
||||
otError errorCode = OT_ERROR_NONE;
|
||||
|
||||
parsedLength = spinel_datatype_unpack(
|
||||
arg_ptr,
|
||||
arg_len,
|
||||
(
|
||||
SPINEL_DATATYPE_UINT32_S // Address
|
||||
SPINEL_DATATYPE_UINT16_S // Count
|
||||
),
|
||||
&address,
|
||||
&count
|
||||
);
|
||||
|
||||
VerifyOrExit(parsedLength == arg_len, spinel_error = SPINEL_STATUS_PARSE_ERROR);
|
||||
|
||||
VerifyOrExit(count != 0, spinel_error = SPINEL_STATUS_INVALID_ARGUMENT);
|
||||
|
||||
if (mAllowPeekDelegate != NULL)
|
||||
{
|
||||
VerifyOrExit(mAllowPeekDelegate(address, count), spinel_error = SPINEL_STATUS_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
SuccessOrExit(errorCode = OutboundFrameBegin());
|
||||
SuccessOrExit(
|
||||
errorCode = OutboundFrameFeedPacked(
|
||||
(
|
||||
SPINEL_DATATYPE_COMMAND_S // Header and Command
|
||||
SPINEL_DATATYPE_UINT32_S // Address
|
||||
SPINEL_DATATYPE_UINT16_S // Count
|
||||
),
|
||||
header,
|
||||
SPINEL_CMD_PEEK_RET,
|
||||
address,
|
||||
count
|
||||
));
|
||||
SuccessOrExit(errorCode = OutboundFrameFeedData(reinterpret_cast<const uint8_t *>(address), count));
|
||||
SuccessOrExit(errorCode = OutboundFrameSend());
|
||||
|
||||
exit:
|
||||
if (spinel_error != SPINEL_STATUS_OK)
|
||||
{
|
||||
errorCode = SendLastStatus(header, spinel_error);
|
||||
}
|
||||
|
||||
(void)command;
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
otError NcpBase::CommandHandler_POKE(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len)
|
||||
{
|
||||
spinel_ssize_t parsedLength;
|
||||
uint32_t address;
|
||||
uint16_t count;
|
||||
const uint8_t *data_ptr = NULL;
|
||||
spinel_size_t data_len;
|
||||
spinel_status_t spinel_error = SPINEL_STATUS_OK;
|
||||
otError errorCode = OT_ERROR_NONE;
|
||||
|
||||
parsedLength = spinel_datatype_unpack(
|
||||
arg_ptr,
|
||||
arg_len,
|
||||
(
|
||||
SPINEL_DATATYPE_UINT32_S // Address
|
||||
SPINEL_DATATYPE_UINT16_S // Count
|
||||
SPINEL_DATATYPE_DATA_S // Bytes
|
||||
),
|
||||
&address,
|
||||
&count,
|
||||
&data_ptr,
|
||||
&data_len
|
||||
);
|
||||
|
||||
VerifyOrExit(parsedLength == arg_len, spinel_error = SPINEL_STATUS_PARSE_ERROR);
|
||||
|
||||
VerifyOrExit(count != 0, spinel_error = SPINEL_STATUS_INVALID_ARGUMENT);
|
||||
VerifyOrExit(count <= data_len, spinel_error = SPINEL_STATUS_INVALID_ARGUMENT);
|
||||
|
||||
if (mAllowPokeDelegate != NULL)
|
||||
{
|
||||
VerifyOrExit(mAllowPokeDelegate(address, count), spinel_error = SPINEL_STATUS_INVALID_ARGUMENT);
|
||||
}
|
||||
|
||||
memcpy(reinterpret_cast<uint8_t *>(address), data_ptr, count);
|
||||
|
||||
exit:
|
||||
errorCode = SendLastStatus(header, spinel_error);
|
||||
|
||||
(void)command;
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// MARK: Individual Property Getters
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -2082,6 +2193,10 @@ otError NcpBase::GetPropertyHandler_CAPS(uint8_t header, spinel_prop_key_t key)
|
||||
SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_OOB_STEERING_DATA));
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
SuccessOrExit(errorCode = OutboundFrameFeedPacked(SPINEL_DATATYPE_UINT_PACKED_S, SPINEL_CAP_PEEK_POKE));
|
||||
#endif
|
||||
|
||||
// TODO: Somehow get the following capability from the radio.
|
||||
SuccessOrExit(
|
||||
errorCode = OutboundFrameFeedPacked(
|
||||
@@ -7914,8 +8029,18 @@ otError NcpBase::StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLe
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
} // namespace ot
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
|
||||
void NcpBase::RegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
|
||||
otNcpDelegateAllowPeekPoke aAllowPokeDelegate)
|
||||
{
|
||||
mAllowPeekDelegate = aAllowPeekDelegate;
|
||||
mAllowPokeDelegate = aAllowPokeDelegate;
|
||||
}
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
|
||||
} // namespace ot
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// MARK: Virtual Datastream I/O (Public API)
|
||||
@@ -7934,6 +8059,33 @@ otError otNcpStreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen)
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// MARK: Peek/Poke delegate API
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
otError otNcpRegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
|
||||
otNcpDelegateAllowPeekPoke aAllowPokeDelegate)
|
||||
{
|
||||
otError errorCode = OT_ERROR_NONE;
|
||||
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
ot::NcpBase *ncp = ot::NcpBase::GetNcpInstance();
|
||||
|
||||
if (ncp != NULL)
|
||||
{
|
||||
ncp->RegisterPeekPokeDelagates(aAllowPeekDelegate, aAllowPokeDelegate);
|
||||
}
|
||||
#else
|
||||
(void)aAllowPeekDelegate;
|
||||
(void)aAllowPokeDelegate;
|
||||
|
||||
errorCode = OT_ERROR_DISABLED_FEATURE;
|
||||
|
||||
#endif // OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
|
||||
return errorCode;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// MARK: Legacy network APIs
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
+16
-4
@@ -330,10 +330,12 @@ private:
|
||||
otError CommandHandler_PROP_VALUE_REMOVE(uint8_t header, unsigned int command, const uint8_t *arg_ptr,
|
||||
uint16_t arg_len);
|
||||
otError CommandHandler_NET_SAVE(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len);
|
||||
otError CommandHandler_NET_CLEAR(uint8_t header, unsigned int command, const uint8_t *arg_ptr,
|
||||
uint16_t arg_len);
|
||||
otError CommandHandler_NET_RECALL(uint8_t header, unsigned int command, const uint8_t *arg_ptr,
|
||||
uint16_t arg_len);
|
||||
otError CommandHandler_NET_CLEAR(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len);
|
||||
otError CommandHandler_NET_RECALL(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len);
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
otError CommandHandler_PEEK(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len);
|
||||
otError CommandHandler_POKE(uint8_t header, unsigned int command, const uint8_t *arg_ptr, uint16_t arg_len);
|
||||
#endif
|
||||
|
||||
otError GetPropertyHandler_ChannelMaskHelper(uint8_t header, spinel_prop_key_t key, uint32_t channel_mask);
|
||||
|
||||
@@ -673,6 +675,11 @@ private:
|
||||
public:
|
||||
otError StreamWrite(int aStreamId, const uint8_t *aDataPtr, int aDataLen);
|
||||
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
void RegisterPeekPokeDelagates(otNcpDelegateAllowPeekPoke aAllowPeekDelegate,
|
||||
otNcpDelegateAllowPeekPoke aAllowPokeDelegate);
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_ENABLE_LEGACY
|
||||
public:
|
||||
void HandleLegacyNodeDidJoin(const otExtAddress *aExtAddr);
|
||||
@@ -710,6 +717,11 @@ private:
|
||||
bool mShouldSignalJamStateChange;
|
||||
#endif
|
||||
|
||||
#if OPENTHREAD_CONFIG_NCP_ENABLE_PEEK_POKE
|
||||
otNcpDelegateAllowPeekPoke mAllowPeekDelegate;
|
||||
otNcpDelegateAllowPeekPoke mAllowPokeDelegate;
|
||||
#endif
|
||||
|
||||
spinel_tid_t mDroppedReplyTid;
|
||||
uint16_t mDroppedReplyTidBitSet;
|
||||
spinel_tid_t mNextExpectedTid;
|
||||
|
||||
Reference in New Issue
Block a user