mirror of
https://github.com/espressif/openthread.git
synced 2026-08-01 16:47:47 +00:00
Some Very Simple Fuzz Testing (#901)
* Add initial 'dump' fuzzing for radio receive.
This commit is contained in:
@@ -163,6 +163,7 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="..\..\tests\unit\test_aes.cpp" />
|
||||
<ClCompile Include="..\..\tests\unit\test_fuzz.cpp" />
|
||||
<ClCompile Include="..\..\tests\unit\test_hmac_sha256.cpp" />
|
||||
<ClCompile Include="..\..\tests\unit\test_link_quality.cpp" />
|
||||
<ClCompile Include="..\..\tests\unit\test_lowpan.cpp" />
|
||||
@@ -177,6 +178,7 @@
|
||||
<ClCompile Include="..\..\tests\unit\test_windows.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\tests\unit\test_platform.h" />
|
||||
<ClInclude Include="..\..\tests\unit\test_util.h" />
|
||||
<ClInclude Include="..\..\tests\unit\test_util.hpp" />
|
||||
<ClInclude Include="..\..\tests\unit\test_vector.h" />
|
||||
|
||||
@@ -21,6 +21,9 @@
|
||||
<ClCompile Include="..\..\tests\unit\test_aes.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\tests\unit\test_fuzz.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\tests\unit\test_hmac_sha256.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
@@ -56,6 +59,9 @@
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\tests\unit\test_platform.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\..\tests\unit\test_util.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
||||
@@ -51,6 +51,10 @@
|
||||
(RtlAssert( #exp, __FILE__, __LINE__, NULL ),FALSE) : \
|
||||
TRUE)
|
||||
|
||||
#elif defined(_WIN32)
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#else
|
||||
|
||||
#define assert(cond) \
|
||||
|
||||
@@ -1154,6 +1154,10 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError)
|
||||
mPcapCallback(aFrame, mPcapCallbackContext);
|
||||
}
|
||||
|
||||
// Ensure we have a valid frame before attempting to read any contents of
|
||||
// the buffer received from the radio.
|
||||
SuccessOrExit(error = aFrame->ValidatePsdu());
|
||||
|
||||
aFrame->GetSrcAddr(srcaddr);
|
||||
neighbor = mMle.GetNeighbor(srcaddr);
|
||||
|
||||
|
||||
+120
-1
@@ -58,7 +58,7 @@ ThreadError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
|
||||
// Sequence Number
|
||||
length += kDsnSize;
|
||||
|
||||
// Destinatino PAN + Address
|
||||
// Destinatinon PAN + Address
|
||||
switch (aFcf & Frame::kFcfDstAddrMask)
|
||||
{
|
||||
case Frame::kFcfDstAddrNone:
|
||||
@@ -145,6 +145,125 @@ ThreadError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
ThreadError Frame::ValidatePsdu(void)
|
||||
{
|
||||
ThreadError error = kThreadError_Parse;
|
||||
uint8_t offset = 0;
|
||||
uint16_t fcf;
|
||||
uint8_t footerLength = kFcsSize;
|
||||
|
||||
VerifyOrExit((offset += kFcfSize + kDsnSize) <= GetPsduLength(),);
|
||||
fcf = static_cast<uint16_t>((GetPsdu()[1] << 8) | GetPsdu()[0]);
|
||||
|
||||
// Destinatinon PAN + Address
|
||||
switch (fcf & Frame::kFcfDstAddrMask)
|
||||
{
|
||||
case Frame::kFcfDstAddrNone:
|
||||
break;
|
||||
|
||||
case Frame::kFcfDstAddrShort:
|
||||
offset += sizeof(PanId) + sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case Frame::kFcfDstAddrExt:
|
||||
offset += sizeof(PanId) + sizeof(ExtAddress);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Source PAN + Address
|
||||
switch (fcf & Frame::kFcfSrcAddrMask)
|
||||
{
|
||||
case Frame::kFcfSrcAddrNone:
|
||||
break;
|
||||
|
||||
case Frame::kFcfSrcAddrShort:
|
||||
if ((fcf & Frame::kFcfPanidCompression) == 0)
|
||||
{
|
||||
offset += sizeof(PanId);
|
||||
}
|
||||
|
||||
offset += sizeof(ShortAddress);
|
||||
break;
|
||||
|
||||
case Frame::kFcfSrcAddrExt:
|
||||
if ((fcf & Frame::kFcfPanidCompression) == 0)
|
||||
{
|
||||
offset += sizeof(PanId);
|
||||
}
|
||||
|
||||
offset += sizeof(ExtAddress);
|
||||
break;
|
||||
|
||||
default:
|
||||
goto exit;
|
||||
}
|
||||
|
||||
// Security Header
|
||||
if (fcf & Frame::kFcfSecurityEnabled)
|
||||
{
|
||||
VerifyOrExit(offset <= GetPsduLength(),);
|
||||
uint8_t secControl = GetPsdu()[offset];
|
||||
|
||||
switch (secControl & kKeyIdModeMask)
|
||||
{
|
||||
case kKeyIdMode0:
|
||||
offset += kKeySourceSizeMode0;
|
||||
break;
|
||||
|
||||
case kKeyIdMode1:
|
||||
offset += kKeySourceSizeMode1 + kKeyIndexSize;
|
||||
break;
|
||||
|
||||
case kKeyIdMode2:
|
||||
offset += kKeySourceSizeMode2 + kKeyIndexSize;
|
||||
break;
|
||||
|
||||
case kKeyIdMode3:
|
||||
offset += kKeySourceSizeMode3 + kKeyIndexSize;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (secControl & kSecLevelMask)
|
||||
{
|
||||
case kSecNone:
|
||||
case kSecEnc:
|
||||
footerLength += kMic0Size;
|
||||
break;
|
||||
|
||||
case kSecMic32:
|
||||
case kSecEncMic32:
|
||||
footerLength += kMic32Size;
|
||||
break;
|
||||
|
||||
case kSecMic64:
|
||||
case kSecEncMic64:
|
||||
footerLength += kMic64Size;
|
||||
break;
|
||||
|
||||
case kSecMic128:
|
||||
case kSecEncMic128:
|
||||
footerLength += kMic128Size;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Command ID
|
||||
if ((fcf & kFcfFrameTypeMask) == kFcfFrameMacCmd)
|
||||
{
|
||||
offset += kCommandIdSize;
|
||||
}
|
||||
|
||||
VerifyOrExit((offset + footerLength) <= GetPsduLength(),);
|
||||
|
||||
error = kThreadError_None;
|
||||
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
uint8_t Frame::GetType(void)
|
||||
{
|
||||
return GetPsdu()[0] & Frame::kFcfFrameTypeMask;
|
||||
|
||||
@@ -251,6 +251,15 @@ public:
|
||||
*/
|
||||
ThreadError InitMacHeader(uint16_t aFcf, uint8_t aSecCtl);
|
||||
|
||||
/**
|
||||
* This method validates the frame.
|
||||
*
|
||||
* @retval kThreadError_None Successfully parsed the MAC header.
|
||||
* @retval kThreadError_Parse Failed to parse through the MAC header.
|
||||
*
|
||||
*/
|
||||
ThreadError ValidatePsdu(void);
|
||||
|
||||
/**
|
||||
* This method returns the IEEE 802.15.4 Frame Type.
|
||||
*
|
||||
|
||||
@@ -65,6 +65,8 @@ ThreadError Lowpan::CopyContext(const Context &aContext, Ip6::Address &aAddress)
|
||||
|
||||
ThreadError Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::Address &aIpAddress)
|
||||
{
|
||||
ThreadError error = kThreadError_None;
|
||||
|
||||
switch (aMacAddr.mLength)
|
||||
{
|
||||
case 2:
|
||||
@@ -79,7 +81,7 @@ ThreadError Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aCon
|
||||
break;
|
||||
|
||||
default:
|
||||
assert(false);
|
||||
ExitNow(error = kThreadError_Parse);
|
||||
}
|
||||
|
||||
if (aContext.mPrefixLength > 64)
|
||||
@@ -91,7 +93,8 @@ ThreadError Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aCon
|
||||
}
|
||||
}
|
||||
|
||||
return kThreadError_None;
|
||||
exit:
|
||||
return error;
|
||||
}
|
||||
|
||||
int Lowpan::CompressSourceIid(const Mac::Address &aMacAddr, const Ip6::Address &aIpAddr, const Context &aContext,
|
||||
@@ -716,7 +719,7 @@ int Lowpan::DecompressBaseHeader(Ip6::Header &ip6Header, const Mac::Address &aMa
|
||||
break;
|
||||
|
||||
case kHcDstAddrMode3:
|
||||
ComputeIid(aMacDest, dstContext, ip6Header.GetDestination());
|
||||
SuccessOrExit(error = ComputeIid(aMacDest, dstContext, ip6Header.GetDestination()));
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -946,6 +949,8 @@ int Lowpan::Decompress(Message &aMessage, const Mac::Address &aMacSource, const
|
||||
uint16_t compressedLength = 0;
|
||||
uint16_t currentOffset = aMessage.GetOffset();
|
||||
|
||||
VerifyOrExit(aBufLen >= 2, error = kThreadError_Parse);
|
||||
|
||||
compressed = (((static_cast<uint16_t>(cur[0]) << 8) | cur[1]) & kHcNextHeader) != 0;
|
||||
|
||||
VerifyOrExit((rval = DecompressBaseHeader(ip6Header, aMacSource, aMacDest, aBuf)) >= 0,
|
||||
|
||||
@@ -1413,15 +1413,18 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame)
|
||||
switch (aFrame.GetType())
|
||||
{
|
||||
case Mac::Frame::kFcfFrameData:
|
||||
if (reinterpret_cast<Lowpan::MeshHeader *>(payload)->IsMeshHeader())
|
||||
if (payloadLength >= sizeof(Lowpan::MeshHeader) &&
|
||||
reinterpret_cast<Lowpan::MeshHeader *>(payload)->IsMeshHeader())
|
||||
{
|
||||
HandleMesh(payload, payloadLength, messageInfo);
|
||||
}
|
||||
else if (reinterpret_cast<Lowpan::FragmentHeader *>(payload)->IsFragmentHeader())
|
||||
else if (payloadLength >= sizeof(Lowpan::FragmentHeader) &&
|
||||
reinterpret_cast<Lowpan::FragmentHeader *>(payload)->IsFragmentHeader())
|
||||
{
|
||||
HandleFragment(payload, payloadLength, macSource, macDest, messageInfo);
|
||||
}
|
||||
else if (Lowpan::Lowpan::IsLowpanHc(payload))
|
||||
else if (payloadLength >= 1 &&
|
||||
Lowpan::Lowpan::IsLowpanHc(payload))
|
||||
{
|
||||
HandleLowpanHC(payload, payloadLength, macSource, macDest, messageInfo);
|
||||
}
|
||||
@@ -1564,6 +1567,8 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
|
||||
aFrame += headerLength;
|
||||
aFrameLength -= static_cast<uint8_t>(headerLength);
|
||||
|
||||
VerifyOrExit(datagramLength >= message->GetOffset() + aFrameLength, error = kThreadError_Parse);
|
||||
|
||||
SuccessOrExit(error = message->SetLength(datagramLength));
|
||||
|
||||
message->SetDatagramTag(datagramTag);
|
||||
@@ -1718,7 +1723,7 @@ void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource, const Thre
|
||||
// Security Check: only process secure Data Poll frames.
|
||||
VerifyOrExit(aMessageInfo.mLinkSecurity, ;);
|
||||
|
||||
assert(mMle.GetDeviceState() != Mle::kDeviceStateDetached);
|
||||
VerifyOrExit(mMle.GetDeviceState() != Mle::kDeviceStateDetached, ;);
|
||||
|
||||
VerifyOrExit((child = mMle.GetChild(aMacSource)) != NULL, ;);
|
||||
child->mLastHeard = Timer::GetNow();
|
||||
|
||||
@@ -33,6 +33,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
|
||||
# since they are not part of the package.
|
||||
#
|
||||
noinst_HEADERS = \
|
||||
test_platform.h \
|
||||
test_util.h \
|
||||
test_util.hpp \
|
||||
test_vector.h \
|
||||
@@ -73,6 +74,7 @@ endif # OPENTHREAD_ENABLE_BUILTIN_MBEDTLS
|
||||
|
||||
check_PROGRAMS = \
|
||||
test-aes \
|
||||
test-fuzz \
|
||||
test-hmac-sha256 \
|
||||
test-lowpan \
|
||||
test-link-quality \
|
||||
@@ -118,6 +120,9 @@ TESTS_ENVIRONMENT = \
|
||||
test_aes_LDADD = $(COMMON_LDADD)
|
||||
test_aes_SOURCES = test_platform.cpp test_aes.cpp
|
||||
|
||||
test_fuzz_LDADD = $(COMMON_LDADD)
|
||||
test_fuzz_SOURCES = test_platform.cpp test_fuzz.cpp
|
||||
|
||||
test_hmac_sha256_LDADD = $(COMMON_LDADD)
|
||||
test_hmac_sha256_SOURCES = test_platform.cpp test_hmac_sha256.cpp
|
||||
|
||||
|
||||
@@ -0,0 +1,205 @@
|
||||
/*
|
||||
* Copyright (c) 2016, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions 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 the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#include "test_platform.h"
|
||||
//#include <mac/mac_frame.hpp>
|
||||
|
||||
//#define DBG_FUZZ 1
|
||||
|
||||
bool g_fRadioEnabled = false;
|
||||
uint8_t g_RecvChannel = 0;
|
||||
uint8_t g_TransmitPsdu[128];
|
||||
RadioPacket g_TransmitRadioPacket;
|
||||
bool g_fTransmit = false;
|
||||
|
||||
ThreadError testFuzzRadioEnable(otInstance *)
|
||||
{
|
||||
#ifdef DBG_FUZZ
|
||||
Log("Radio enabled");
|
||||
#endif
|
||||
g_fRadioEnabled = true;
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
ThreadError testFuzzRadioDisable(otInstance *)
|
||||
{
|
||||
#ifdef DBG_FUZZ
|
||||
Log("Radio disabled");
|
||||
#endif
|
||||
g_fRadioEnabled = false;
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
ThreadError testFuzzRadioReceive(otInstance *, uint8_t aChannel)
|
||||
{
|
||||
#ifdef DBG_FUZZ
|
||||
Log("==> receive");
|
||||
#endif
|
||||
g_RecvChannel = aChannel;
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
ThreadError testFuzzRadioTransmit(otInstance *)
|
||||
{
|
||||
#ifdef DBG_FUZZ
|
||||
Log("==> transmit");
|
||||
#endif
|
||||
g_fTransmit = true;
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
RadioPacket *testFuzztRadioGetTransmitBuffer(otInstance *)
|
||||
{
|
||||
return &g_TransmitRadioPacket;
|
||||
}
|
||||
|
||||
void TestFuzz(uint32_t aSeconds)
|
||||
{
|
||||
// Set the radio capabilities to disable any Mac related timer dependencies
|
||||
g_testPlatRadioCaps = (otRadioCaps)(kRadioCapsAckTimeout | kRadioCapsTransmitRetries);
|
||||
|
||||
// Set the platform function pointers
|
||||
g_TransmitRadioPacket.mPsdu = g_TransmitPsdu;
|
||||
g_testPlatRadioEnable = testFuzzRadioEnable;
|
||||
g_testPlatRadioDisable = testFuzzRadioDisable;
|
||||
g_testPlatRadioReceive = testFuzzRadioReceive;
|
||||
g_testPlatRadioTransmit = testFuzzRadioTransmit;
|
||||
g_testPlatRadioGetTransmitBuffer = testFuzztRadioGetTransmitBuffer;
|
||||
|
||||
// Initialize our timing variables
|
||||
uint32_t tStart = otPlatAlarmGetNow();
|
||||
uint32_t tEnd = tStart + (aSeconds * 1000);
|
||||
|
||||
otInstance *aInstance;
|
||||
|
||||
#ifdef _WIN32
|
||||
uint32_t seed = (uint32_t)time(NULL);
|
||||
srand(seed);
|
||||
Log("Initialized seed = 0x%X", seed);
|
||||
#endif
|
||||
|
||||
#ifdef OPENTHREAD_MULTIPLE_INSTANCE
|
||||
uint64_t otInstanceBufferLength = 0;
|
||||
uint8_t *otInstanceBuffer = NULL;
|
||||
|
||||
// Call to query the buffer size
|
||||
(void)otInstanceInit(NULL, &otInstanceBufferLength);
|
||||
|
||||
// Call to allocate the buffer
|
||||
otInstanceBuffer = (uint8_t *)malloc(otInstanceBufferLength);
|
||||
VerifyOrQuit(otInstanceBuffer != NULL, "Failed to allocate otInstance");
|
||||
memset(&otInstanceBuffer, 0, otInstanceBufferLength);
|
||||
|
||||
// Initialize Openthread with the buffer
|
||||
aInstance = otInstanceInit(otInstanceBuffer, &otInstanceBufferLength);
|
||||
#else
|
||||
aInstance = otInstanceInit();
|
||||
#endif
|
||||
|
||||
VerifyOrQuit(aInstance != NULL, "Failed to initialize otInstance");
|
||||
|
||||
// Start the Thread network
|
||||
otSetPanId(aInstance, (otPanId)0xFACE);
|
||||
otInterfaceUp(aInstance);
|
||||
otThreadStart(aInstance);
|
||||
|
||||
uint32_t countRecv = 0;
|
||||
|
||||
while (otPlatAlarmGetNow() < tEnd)
|
||||
{
|
||||
otProcessQueuedTasklets(aInstance);
|
||||
|
||||
if (g_testPlatAlarmSet && otPlatAlarmGetNow() >= g_testPlatAlarmNext)
|
||||
{
|
||||
g_testPlatAlarmSet = false;
|
||||
otPlatAlarmFired(aInstance);
|
||||
}
|
||||
|
||||
if (g_fRadioEnabled)
|
||||
{
|
||||
if (g_fTransmit)
|
||||
{
|
||||
g_fTransmit = false;
|
||||
otPlatRadioTransmitDone(aInstance, true, kThreadError_None);
|
||||
#ifdef DBG_FUZZ
|
||||
Log("<== transmit");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (g_RecvChannel != 0)
|
||||
{
|
||||
uint8_t fuzzRecvBuff[128];
|
||||
RadioPacket fuzzPacket;
|
||||
|
||||
// Initialize the radio packet with a random length
|
||||
memset(&fuzzPacket, 0, sizeof(fuzzPacket));
|
||||
fuzzPacket.mPsdu = fuzzRecvBuff;
|
||||
fuzzPacket.mChannel = g_RecvChannel;
|
||||
fuzzPacket.mLength = (uint8_t)(otPlatRandomGet() % 127);
|
||||
|
||||
// Populate the length with random
|
||||
for (uint8_t i = 0; i < fuzzPacket.mLength; i++)
|
||||
{
|
||||
fuzzRecvBuff[i] = (uint8_t)otPlatRandomGet();
|
||||
}
|
||||
|
||||
// Clear the global flag
|
||||
g_RecvChannel = 0;
|
||||
|
||||
// Indicate the receive complete
|
||||
otPlatRadioReceiveDone(aInstance, &fuzzPacket, kThreadError_None);
|
||||
|
||||
countRecv++;
|
||||
#ifdef DBG_FUZZ
|
||||
Log("<== receive (%llu, %u bytes)", countRecv, fuzzPacket.mLength);
|
||||
#endif
|
||||
|
||||
// Hack to get a receive poll immediately
|
||||
otSetChannel(aInstance, 11);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Log("%u packets received", countRecv);
|
||||
|
||||
// Clean up the instance
|
||||
otInstanceFinalize(aInstance);
|
||||
|
||||
#ifdef OPENTHREAD_MULTIPLE_INSTANCE
|
||||
free(otInstanceBuffer);
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef ENABLE_TEST_MAIN
|
||||
int main(void)
|
||||
{
|
||||
TestFuzz(0); // For the time being, don't actually fuzz, just validate we can start and clean up
|
||||
printf("All tests passed\n");
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
+131
-48
@@ -26,38 +26,54 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test_platform.h"
|
||||
|
||||
#if _WIN32
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <windows.h>
|
||||
__forceinline int gettimeofday(struct timeval *tv, struct timezone *)
|
||||
{
|
||||
DWORD tick = GetTickCount();
|
||||
tv->tv_sec = (long)(tick / 1000);
|
||||
tv->tv_usec = (long)(tick * 1000);
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
#include <sys/time.h>
|
||||
#endif
|
||||
|
||||
#include <openthread.h>
|
||||
bool g_testPlatAlarmSet = false;
|
||||
uint32_t g_testPlatAlarmNext = 0;
|
||||
testPlatAlarmStop g_testPlatAlarmStop = NULL;
|
||||
testPlatAlarmStartAt g_testPlatAlarmStartAt = NULL;
|
||||
testPlatAlarmGetNow g_testPlatAlarmGetNow = NULL;
|
||||
|
||||
#include <common/code_utils.hpp>
|
||||
#include <platform/alarm.h>
|
||||
#include <platform/logging.h>
|
||||
#include <platform/misc.h>
|
||||
#include <platform/radio.h>
|
||||
#include <platform/random.h>
|
||||
otRadioCaps g_testPlatRadioCaps = kRadioCapsNone;
|
||||
testPlatRadioSetPanId g_testPlatRadioSetPanId = NULL;
|
||||
testPlatRadioSetExtendedAddress g_testPlatRadioSetExtendedAddress = NULL;
|
||||
testPlatRadioEnable g_testPlatRadioEnable = NULL;
|
||||
testPlatRadioDisable g_testPlatRadioDisable = NULL;
|
||||
testPlatRadioSetShortAddress g_testPlatRadioSetShortAddress = NULL;
|
||||
testPlatRadioReceive g_testPlatRadioReceive = NULL;
|
||||
testPlatRadioTransmit g_testPlatRadioTransmit = NULL;
|
||||
testPlatRadioGetTransmitBuffer g_testPlatRadioGetTransmitBuffer = NULL;
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
enum
|
||||
void testPlatResetToDefaults(void)
|
||||
{
|
||||
kCallCountIndexAlarmStop = 0,
|
||||
kCallCountIndexAlarmStart,
|
||||
kCallCountIndexTimerHandler,
|
||||
g_testPlatAlarmSet = false;
|
||||
g_testPlatAlarmNext = 0;
|
||||
g_testPlatAlarmStop = NULL;
|
||||
g_testPlatAlarmStartAt = NULL;
|
||||
g_testPlatAlarmGetNow = NULL;
|
||||
|
||||
kCallCountIndexMax
|
||||
};
|
||||
|
||||
uint32_t sNow;
|
||||
uint32_t sPlatT0;
|
||||
uint32_t sPlatDt;
|
||||
bool sTimerOn;
|
||||
uint32_t sCallCount[kCallCountIndexMax];
|
||||
g_testPlatRadioCaps = kRadioCapsNone;
|
||||
g_testPlatRadioSetPanId = NULL;
|
||||
g_testPlatRadioSetExtendedAddress = NULL;
|
||||
g_testPlatRadioSetShortAddress = NULL;
|
||||
g_testPlatRadioEnable = NULL;
|
||||
g_testPlatRadioDisable = NULL;
|
||||
g_testPlatRadioReceive = NULL;
|
||||
g_testPlatRadioTransmit = NULL;
|
||||
g_testPlatRadioGetTransmitBuffer = NULL;
|
||||
}
|
||||
|
||||
bool sDiagMode = false;
|
||||
|
||||
@@ -71,23 +87,43 @@ extern "C" {
|
||||
// Alarm
|
||||
//
|
||||
|
||||
void otPlatAlarmStop(otInstance *)
|
||||
void otPlatAlarmStop(otInstance *aInstance)
|
||||
{
|
||||
sTimerOn = false;
|
||||
sCallCount[kCallCountIndexAlarmStop]++;
|
||||
if (g_testPlatAlarmStop)
|
||||
{
|
||||
g_testPlatAlarmStop(aInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_testPlatAlarmSet = false;
|
||||
}
|
||||
}
|
||||
|
||||
void otPlatAlarmStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
||||
void otPlatAlarmStartAt(otInstance *aInstance, uint32_t aT0, uint32_t aDt)
|
||||
{
|
||||
sTimerOn = true;
|
||||
sCallCount[kCallCountIndexAlarmStart]++;
|
||||
sPlatT0 = aT0;
|
||||
sPlatDt = aDt;
|
||||
if (g_testPlatAlarmStartAt)
|
||||
{
|
||||
g_testPlatAlarmStartAt(aInstance, aT0, aDt);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_testPlatAlarmSet = true;
|
||||
g_testPlatAlarmNext = aT0 + aDt;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t otPlatAlarmGetNow(void)
|
||||
{
|
||||
return sNow;
|
||||
if (g_testPlatAlarmGetNow)
|
||||
{
|
||||
return g_testPlatAlarmGetNow();
|
||||
}
|
||||
else
|
||||
{
|
||||
struct timeval tv;
|
||||
gettimeofday(&tv, NULL);
|
||||
return (uint32_t)((tv.tv_sec * 1000) + (tv.tv_usec / 1000) + 123456);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
@@ -98,30 +134,56 @@ extern "C" {
|
||||
{
|
||||
}
|
||||
|
||||
void otPlatRadioSetPanId(otInstance *, uint16_t)
|
||||
void otPlatRadioSetPanId(otInstance *aInstance, uint16_t aPanId)
|
||||
{
|
||||
if (g_testPlatRadioSetPanId)
|
||||
{
|
||||
g_testPlatRadioSetPanId(aInstance, aPanId);
|
||||
}
|
||||
}
|
||||
|
||||
void otPlatRadioSetExtendedAddress(otInstance *, uint8_t *)
|
||||
void otPlatRadioSetExtendedAddress(otInstance *aInstance, uint8_t *aExtAddr)
|
||||
{
|
||||
if (g_testPlatRadioSetExtendedAddress)
|
||||
{
|
||||
g_testPlatRadioSetExtendedAddress(aInstance, aExtAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void otPlatRadioSetShortAddress(otInstance *, uint16_t)
|
||||
void otPlatRadioSetShortAddress(otInstance *aInstance, uint16_t aShortAddr)
|
||||
{
|
||||
if (g_testPlatRadioSetShortAddress)
|
||||
{
|
||||
g_testPlatRadioSetShortAddress(aInstance, aShortAddr);
|
||||
}
|
||||
}
|
||||
|
||||
void otPlatRadioSetPromiscuous(otInstance *, bool)
|
||||
{
|
||||
}
|
||||
|
||||
ThreadError otPlatRadioEnable(otInstance *)
|
||||
ThreadError otPlatRadioEnable(otInstance *aInstance)
|
||||
{
|
||||
return kThreadError_None;
|
||||
if (g_testPlatRadioEnable)
|
||||
{
|
||||
return g_testPlatRadioEnable(aInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
return kThreadError_None;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadError otPlatRadioDisable(otInstance *)
|
||||
ThreadError otPlatRadioDisable(otInstance *aInstance)
|
||||
{
|
||||
return kThreadError_None;
|
||||
if (g_testPlatRadioEnable)
|
||||
{
|
||||
return g_testPlatRadioDisable(aInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
return kThreadError_None;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadError otPlatRadioSleep(otInstance *)
|
||||
@@ -129,19 +191,40 @@ extern "C" {
|
||||
return kThreadError_None;
|
||||
}
|
||||
|
||||
ThreadError otPlatRadioReceive(otInstance *, uint8_t)
|
||||
ThreadError otPlatRadioReceive(otInstance *aInstance, uint8_t aChannel)
|
||||
{
|
||||
return kThreadError_None;
|
||||
if (g_testPlatRadioReceive)
|
||||
{
|
||||
return g_testPlatRadioReceive(aInstance, aChannel);
|
||||
}
|
||||
else
|
||||
{
|
||||
return kThreadError_None;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadError otPlatRadioTransmit(otInstance *)
|
||||
ThreadError otPlatRadioTransmit(otInstance *aInstance)
|
||||
{
|
||||
return kThreadError_None;
|
||||
if (g_testPlatRadioTransmit)
|
||||
{
|
||||
return g_testPlatRadioTransmit(aInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
return kThreadError_None;
|
||||
}
|
||||
}
|
||||
|
||||
RadioPacket *otPlatRadioGetTransmitBuffer(otInstance *)
|
||||
RadioPacket *otPlatRadioGetTransmitBuffer(otInstance *aInstance)
|
||||
{
|
||||
return (RadioPacket *)0;
|
||||
if (g_testPlatRadioGetTransmitBuffer)
|
||||
{
|
||||
return g_testPlatRadioGetTransmitBuffer(aInstance);
|
||||
}
|
||||
else
|
||||
{
|
||||
return (RadioPacket *)0;
|
||||
}
|
||||
}
|
||||
|
||||
int8_t otPlatRadioGetRssi(otInstance *)
|
||||
@@ -151,7 +234,7 @@ extern "C" {
|
||||
|
||||
otRadioCaps otPlatRadioGetCaps(otInstance *)
|
||||
{
|
||||
return kRadioCapsNone;
|
||||
return g_testPlatRadioCaps;
|
||||
}
|
||||
|
||||
bool otPlatRadioGetPromiscuous(otInstance *)
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright (c) 2016, The OpenThread Authors.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* 1. Redistributions 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 the copyright holder nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER 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.
|
||||
*/
|
||||
|
||||
#ifndef TEST_PLATFORM_H
|
||||
#define TEST_PLATFORM_H
|
||||
|
||||
#if _WIN32
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#include <windows.h>
|
||||
#include <time.h>
|
||||
#endif
|
||||
|
||||
#include <openthread.h>
|
||||
#include <openthread-tasklet.h>
|
||||
|
||||
#include <common/code_utils.hpp>
|
||||
#include <platform/alarm.h>
|
||||
#include <platform/logging.h>
|
||||
#include <platform/misc.h>
|
||||
#include <platform/radio.h>
|
||||
#include <platform/random.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "test_util.h"
|
||||
|
||||
//
|
||||
// Alarm Platform
|
||||
//
|
||||
|
||||
typedef void (*testPlatAlarmStop)(otInstance *);
|
||||
typedef void (*testPlatAlarmStartAt)(otInstance *, uint32_t, uint32_t);
|
||||
typedef uint32_t (*testPlatAlarmGetNow)(void);
|
||||
|
||||
extern bool g_testPlatAlarmSet;
|
||||
extern uint32_t g_testPlatAlarmNext;
|
||||
extern testPlatAlarmStop g_testPlatAlarmStop;
|
||||
extern testPlatAlarmStartAt g_testPlatAlarmStartAt;
|
||||
extern testPlatAlarmGetNow g_testPlatAlarmGetNow;
|
||||
|
||||
//
|
||||
// Radio Platform
|
||||
//
|
||||
|
||||
typedef void (*testPlatRadioSetPanId)(otInstance *, uint16_t);
|
||||
typedef void (*testPlatRadioSetExtendedAddress)(otInstance *, uint8_t *);
|
||||
typedef void (*testPlatRadioSetShortAddress)(otInstance *, uint16_t);
|
||||
|
||||
typedef ThreadError(*testPlatRadioEnable)(otInstance *);
|
||||
typedef ThreadError(*testPlatRadioDisable)(otInstance *);
|
||||
typedef ThreadError(*testPlatRadioReceive)(otInstance *, uint8_t);
|
||||
typedef ThreadError(*testPlatRadioTransmit)(otInstance *);
|
||||
typedef RadioPacket *(*testPlatRadioGetTransmitBuffer)(otInstance *);
|
||||
|
||||
extern otRadioCaps g_testPlatRadioCaps;
|
||||
extern testPlatRadioSetPanId g_testPlatRadioSetPanId;
|
||||
extern testPlatRadioSetExtendedAddress g_testPlatRadioSetExtendedAddress;
|
||||
extern testPlatRadioSetShortAddress g_testPlatRadioSetShortAddress;
|
||||
extern testPlatRadioEnable g_testPlatRadioEnable;
|
||||
extern testPlatRadioDisable g_testPlatRadioDisable;
|
||||
extern testPlatRadioReceive g_testPlatRadioReceive;
|
||||
extern testPlatRadioTransmit g_testPlatRadioTransmit;
|
||||
extern testPlatRadioGetTransmitBuffer g_testPlatRadioGetTransmitBuffer;
|
||||
|
||||
// Resets platform functions to defaults
|
||||
void testPlatResetToDefaults(void);
|
||||
|
||||
#endif // TEST_PLATFORM_H
|
||||
@@ -26,12 +26,9 @@
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "test_util.h"
|
||||
#include <openthread.h>
|
||||
#include "test_platform.h"
|
||||
#include <common/debug.hpp>
|
||||
#include <common/timer.hpp>
|
||||
#include <platform/alarm.h>
|
||||
#include <string.h>
|
||||
#include <openthread-instance.h>
|
||||
|
||||
enum
|
||||
@@ -43,11 +40,37 @@ enum
|
||||
kCallCountIndexMax
|
||||
};
|
||||
|
||||
extern uint32_t sNow;
|
||||
extern uint32_t sPlatT0;
|
||||
extern uint32_t sPlatDt;
|
||||
extern bool sTimerOn;
|
||||
extern uint32_t sCallCount[kCallCountIndexMax];
|
||||
uint32_t sNow;
|
||||
uint32_t sPlatT0;
|
||||
uint32_t sPlatDt;
|
||||
bool sTimerOn;
|
||||
uint32_t sCallCount[kCallCountIndexMax];
|
||||
|
||||
void testTimerAlarmStop(otInstance *)
|
||||
{
|
||||
sTimerOn = false;
|
||||
sCallCount[kCallCountIndexAlarmStop]++;
|
||||
}
|
||||
|
||||
void testTimerAlarmStartAt(otInstance *, uint32_t aT0, uint32_t aDt)
|
||||
{
|
||||
sTimerOn = true;
|
||||
sCallCount[kCallCountIndexAlarmStart]++;
|
||||
sPlatT0 = aT0;
|
||||
sPlatDt = aDt;
|
||||
}
|
||||
|
||||
uint32_t testTimerAlarmGetNow(void)
|
||||
{
|
||||
return sNow;
|
||||
}
|
||||
|
||||
void InitTestTimer(void)
|
||||
{
|
||||
g_testPlatAlarmStop = testTimerAlarmStop;
|
||||
g_testPlatAlarmStartAt = testTimerAlarmStartAt;
|
||||
g_testPlatAlarmGetNow = testTimerAlarmGetNow;
|
||||
}
|
||||
|
||||
void InitCounters(void)
|
||||
{
|
||||
@@ -76,6 +99,7 @@ int TestOneTimer(void)
|
||||
|
||||
// Test one Timer basic operation.
|
||||
|
||||
InitTestTimer();
|
||||
InitCounters();
|
||||
|
||||
sNow = kTimeT0;
|
||||
@@ -321,6 +345,7 @@ int TestTenTimers(void)
|
||||
|
||||
// Start the Ten timers.
|
||||
|
||||
InitTestTimer();
|
||||
InitCounters();
|
||||
|
||||
for (i = 0; i < kNumTimers ; i++)
|
||||
|
||||
@@ -72,6 +72,8 @@ extern "C" {
|
||||
//
|
||||
#define CompileTimeAssert(COND, MSG)
|
||||
|
||||
#define Log(aFormat, ...) printf(aFormat "\n", ## __VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
@@ -81,12 +83,17 @@ extern "C" {
|
||||
typedef void (*utAssertTrue)(bool condition, const wchar_t *message);
|
||||
extern utAssertTrue s_AssertTrue;
|
||||
|
||||
typedef void (*utLogMessage)(const char *format, ...);
|
||||
extern utLogMessage s_LogMessage;
|
||||
|
||||
#define SuccessOrQuit(ERR, MSG) s_AssertTrue((ERR) == kThreadError_None, L##MSG)
|
||||
|
||||
#define VerifyOrQuit(ERR, MSG) s_AssertTrue(ERR, L##MSG)
|
||||
|
||||
#define CompileTimeAssert(COND, MSG) static_assert(COND, MSG)
|
||||
|
||||
#define Log(aFormat, ...) s_LogMessage(aFormat, ## __VA_ARGS__)
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include <SDKDDKVer.h>
|
||||
#include "CppUnitTest.h"
|
||||
#include "test_util.h"
|
||||
#include "test_platform.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
@@ -80,17 +81,21 @@ void test_packed2();
|
||||
void test_packed_union();
|
||||
void test_packed_enum();
|
||||
|
||||
// test_fuzz.cpp
|
||||
void TestFuzz(uint32_t aSeconds);
|
||||
|
||||
#pragma endregion
|
||||
|
||||
utAssertTrue s_AssertTrue;
|
||||
utLogMessage s_LogMessage;
|
||||
|
||||
namespace Thread
|
||||
{
|
||||
TEST_CLASS(UnitTests)
|
||||
{
|
||||
public:
|
||||
{
|
||||
TEST_CLASS(UnitTests)
|
||||
{
|
||||
public:
|
||||
|
||||
UnitTests() { s_AssertTrue = AssertTrue; }
|
||||
UnitTests() { s_AssertTrue = AssertTrue; s_LogMessage = LogMessage; }
|
||||
|
||||
// Helper for openthread test code to call
|
||||
static void AssertTrue(bool condition, const wchar_t* message)
|
||||
@@ -98,6 +103,25 @@ namespace Thread
|
||||
Assert::IsTrue(condition, message);
|
||||
}
|
||||
|
||||
// Helper for logging a message
|
||||
static void LogMessage(const char* format, ...)
|
||||
{
|
||||
char message[512];
|
||||
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vsnprintf(message, sizeof(message), format, args);
|
||||
va_end(args);
|
||||
|
||||
Logger::WriteMessage(message);
|
||||
}
|
||||
|
||||
// Make sure to reset the test platform functions before each test
|
||||
TEST_METHOD_INITIALIZE(TestMethodInit)
|
||||
{
|
||||
testPlatResetToDefaults();
|
||||
}
|
||||
|
||||
// test_aes.cpp
|
||||
TEST_METHOD(TestMacBeaconFrame) { ::TestMacBeaconFrame(); }
|
||||
TEST_METHOD(TestMacDataFrame) { ::TestMacDataFrame(); }
|
||||
@@ -131,5 +155,8 @@ namespace Thread
|
||||
TEST_METHOD(test_packed2) { ::test_packed2(); }
|
||||
TEST_METHOD(test_packed_union) { ::test_packed_union(); }
|
||||
TEST_METHOD(test_packed_enum) { ::test_packed_enum(); }
|
||||
};
|
||||
|
||||
// test_settings.cpp
|
||||
TEST_METHOD(RunTestFuzz) { ::TestFuzz(0); }
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user