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:
Abtin Keshavarzian
2017-06-13 10:08:31 -07:00
committed by Jonathan Hui
parent 8dc31d6e27
commit b6f821d728
4 changed files with 214 additions and 6 deletions
+32
View File
@@ -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
+13 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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;