Some Very Simple Fuzz Testing (#901)

* Add initial 'dump' fuzzing for radio receive.
This commit is contained in:
Nick Banks
2016-11-04 14:53:07 -07:00
committed by Jonathan Hui
parent 74a95f042d
commit 82e85a7300
15 changed files with 670 additions and 71 deletions
+2
View File
@@ -163,6 +163,7 @@
</ItemDefinitionGroup> </ItemDefinitionGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="..\..\tests\unit\test_aes.cpp" /> <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_hmac_sha256.cpp" />
<ClCompile Include="..\..\tests\unit\test_link_quality.cpp" /> <ClCompile Include="..\..\tests\unit\test_link_quality.cpp" />
<ClCompile Include="..\..\tests\unit\test_lowpan.cpp" /> <ClCompile Include="..\..\tests\unit\test_lowpan.cpp" />
@@ -177,6 +178,7 @@
<ClCompile Include="..\..\tests\unit\test_windows.cpp" /> <ClCompile Include="..\..\tests\unit\test_windows.cpp" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\tests\unit\test_platform.h" />
<ClInclude Include="..\..\tests\unit\test_util.h" /> <ClInclude Include="..\..\tests\unit\test_util.h" />
<ClInclude Include="..\..\tests\unit\test_util.hpp" /> <ClInclude Include="..\..\tests\unit\test_util.hpp" />
<ClInclude Include="..\..\tests\unit\test_vector.h" /> <ClInclude Include="..\..\tests\unit\test_vector.h" />
@@ -21,6 +21,9 @@
<ClCompile Include="..\..\tests\unit\test_aes.cpp"> <ClCompile Include="..\..\tests\unit\test_aes.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="..\..\tests\unit\test_fuzz.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="..\..\tests\unit\test_hmac_sha256.cpp"> <ClCompile Include="..\..\tests\unit\test_hmac_sha256.cpp">
<Filter>Source Files</Filter> <Filter>Source Files</Filter>
</ClCompile> </ClCompile>
@@ -56,6 +59,9 @@
</ClCompile> </ClCompile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClInclude Include="..\..\tests\unit\test_platform.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="..\..\tests\unit\test_util.h"> <ClInclude Include="..\..\tests\unit\test_util.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
+4
View File
@@ -51,6 +51,10 @@
(RtlAssert( #exp, __FILE__, __LINE__, NULL ),FALSE) : \ (RtlAssert( #exp, __FILE__, __LINE__, NULL ),FALSE) : \
TRUE) TRUE)
#elif defined(_WIN32)
#include <assert.h>
#else #else
#define assert(cond) \ #define assert(cond) \
+4
View File
@@ -1154,6 +1154,10 @@ void Mac::ReceiveDoneTask(Frame *aFrame, ThreadError aError)
mPcapCallback(aFrame, mPcapCallbackContext); 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); aFrame->GetSrcAddr(srcaddr);
neighbor = mMle.GetNeighbor(srcaddr); neighbor = mMle.GetNeighbor(srcaddr);
+120 -1
View File
@@ -58,7 +58,7 @@ ThreadError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
// Sequence Number // Sequence Number
length += kDsnSize; length += kDsnSize;
// Destinatino PAN + Address // Destinatinon PAN + Address
switch (aFcf & Frame::kFcfDstAddrMask) switch (aFcf & Frame::kFcfDstAddrMask)
{ {
case Frame::kFcfDstAddrNone: case Frame::kFcfDstAddrNone:
@@ -145,6 +145,125 @@ ThreadError Frame::InitMacHeader(uint16_t aFcf, uint8_t aSecurityControl)
return kThreadError_None; 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) uint8_t Frame::GetType(void)
{ {
return GetPsdu()[0] & Frame::kFcfFrameTypeMask; return GetPsdu()[0] & Frame::kFcfFrameTypeMask;
+9
View File
@@ -251,6 +251,15 @@ public:
*/ */
ThreadError InitMacHeader(uint16_t aFcf, uint8_t aSecCtl); 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. * This method returns the IEEE 802.15.4 Frame Type.
* *
+8 -3
View File
@@ -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 Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::Address &aIpAddress)
{ {
ThreadError error = kThreadError_None;
switch (aMacAddr.mLength) switch (aMacAddr.mLength)
{ {
case 2: case 2:
@@ -79,7 +81,7 @@ ThreadError Lowpan::ComputeIid(const Mac::Address &aMacAddr, const Context &aCon
break; break;
default: default:
assert(false); ExitNow(error = kThreadError_Parse);
} }
if (aContext.mPrefixLength > 64) 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, 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; break;
case kHcDstAddrMode3: case kHcDstAddrMode3:
ComputeIid(aMacDest, dstContext, ip6Header.GetDestination()); SuccessOrExit(error = ComputeIid(aMacDest, dstContext, ip6Header.GetDestination()));
break; break;
} }
@@ -946,6 +949,8 @@ int Lowpan::Decompress(Message &aMessage, const Mac::Address &aMacSource, const
uint16_t compressedLength = 0; uint16_t compressedLength = 0;
uint16_t currentOffset = aMessage.GetOffset(); uint16_t currentOffset = aMessage.GetOffset();
VerifyOrExit(aBufLen >= 2, error = kThreadError_Parse);
compressed = (((static_cast<uint16_t>(cur[0]) << 8) | cur[1]) & kHcNextHeader) != 0; compressed = (((static_cast<uint16_t>(cur[0]) << 8) | cur[1]) & kHcNextHeader) != 0;
VerifyOrExit((rval = DecompressBaseHeader(ip6Header, aMacSource, aMacDest, aBuf)) >= 0, VerifyOrExit((rval = DecompressBaseHeader(ip6Header, aMacSource, aMacDest, aBuf)) >= 0,
+9 -4
View File
@@ -1413,15 +1413,18 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame)
switch (aFrame.GetType()) switch (aFrame.GetType())
{ {
case Mac::Frame::kFcfFrameData: 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); 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); 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); HandleLowpanHC(payload, payloadLength, macSource, macDest, messageInfo);
} }
@@ -1564,6 +1567,8 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
aFrame += headerLength; aFrame += headerLength;
aFrameLength -= static_cast<uint8_t>(headerLength); aFrameLength -= static_cast<uint8_t>(headerLength);
VerifyOrExit(datagramLength >= message->GetOffset() + aFrameLength, error = kThreadError_Parse);
SuccessOrExit(error = message->SetLength(datagramLength)); SuccessOrExit(error = message->SetLength(datagramLength));
message->SetDatagramTag(datagramTag); message->SetDatagramTag(datagramTag);
@@ -1718,7 +1723,7 @@ void MeshForwarder::HandleDataRequest(const Mac::Address &aMacSource, const Thre
// Security Check: only process secure Data Poll frames. // Security Check: only process secure Data Poll frames.
VerifyOrExit(aMessageInfo.mLinkSecurity, ;); VerifyOrExit(aMessageInfo.mLinkSecurity, ;);
assert(mMle.GetDeviceState() != Mle::kDeviceStateDetached); VerifyOrExit(mMle.GetDeviceState() != Mle::kDeviceStateDetached, ;);
VerifyOrExit((child = mMle.GetChild(aMacSource)) != NULL, ;); VerifyOrExit((child = mMle.GetChild(aMacSource)) != NULL, ;);
child->mLastHeard = Timer::GetNow(); child->mLastHeard = Timer::GetNow();
+5
View File
@@ -33,6 +33,7 @@ include $(abs_top_nlbuild_autotools_dir)/automake/pre.am
# since they are not part of the package. # since they are not part of the package.
# #
noinst_HEADERS = \ noinst_HEADERS = \
test_platform.h \
test_util.h \ test_util.h \
test_util.hpp \ test_util.hpp \
test_vector.h \ test_vector.h \
@@ -73,6 +74,7 @@ endif # OPENTHREAD_ENABLE_BUILTIN_MBEDTLS
check_PROGRAMS = \ check_PROGRAMS = \
test-aes \ test-aes \
test-fuzz \
test-hmac-sha256 \ test-hmac-sha256 \
test-lowpan \ test-lowpan \
test-link-quality \ test-link-quality \
@@ -118,6 +120,9 @@ TESTS_ENVIRONMENT = \
test_aes_LDADD = $(COMMON_LDADD) test_aes_LDADD = $(COMMON_LDADD)
test_aes_SOURCES = test_platform.cpp test_aes.cpp 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_LDADD = $(COMMON_LDADD)
test_hmac_sha256_SOURCES = test_platform.cpp test_hmac_sha256.cpp test_hmac_sha256_SOURCES = test_platform.cpp test_hmac_sha256.cpp
+205
View File
@@ -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
View File
@@ -26,38 +26,54 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "test_platform.h"
#if _WIN32 #if _WIN32
#define _CRT_SECURE_NO_WARNINGS __forceinline int gettimeofday(struct timeval *tv, struct timezone *)
#include <windows.h> {
DWORD tick = GetTickCount();
tv->tv_sec = (long)(tick / 1000);
tv->tv_usec = (long)(tick * 1000);
return 0;
}
#else
#include <sys/time.h>
#endif #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> otRadioCaps g_testPlatRadioCaps = kRadioCapsNone;
#include <platform/alarm.h> testPlatRadioSetPanId g_testPlatRadioSetPanId = NULL;
#include <platform/logging.h> testPlatRadioSetExtendedAddress g_testPlatRadioSetExtendedAddress = NULL;
#include <platform/misc.h> testPlatRadioEnable g_testPlatRadioEnable = NULL;
#include <platform/radio.h> testPlatRadioDisable g_testPlatRadioDisable = NULL;
#include <platform/random.h> testPlatRadioSetShortAddress g_testPlatRadioSetShortAddress = NULL;
testPlatRadioReceive g_testPlatRadioReceive = NULL;
testPlatRadioTransmit g_testPlatRadioTransmit = NULL;
testPlatRadioGetTransmitBuffer g_testPlatRadioGetTransmitBuffer = NULL;
#include <stdio.h> void testPlatResetToDefaults(void)
#include <stdlib.h>
#include <string.h>
enum
{ {
kCallCountIndexAlarmStop = 0, g_testPlatAlarmSet = false;
kCallCountIndexAlarmStart, g_testPlatAlarmNext = 0;
kCallCountIndexTimerHandler, g_testPlatAlarmStop = NULL;
g_testPlatAlarmStartAt = NULL;
g_testPlatAlarmGetNow = NULL;
kCallCountIndexMax g_testPlatRadioCaps = kRadioCapsNone;
}; g_testPlatRadioSetPanId = NULL;
g_testPlatRadioSetExtendedAddress = NULL;
uint32_t sNow; g_testPlatRadioSetShortAddress = NULL;
uint32_t sPlatT0; g_testPlatRadioEnable = NULL;
uint32_t sPlatDt; g_testPlatRadioDisable = NULL;
bool sTimerOn; g_testPlatRadioReceive = NULL;
uint32_t sCallCount[kCallCountIndexMax]; g_testPlatRadioTransmit = NULL;
g_testPlatRadioGetTransmitBuffer = NULL;
}
bool sDiagMode = false; bool sDiagMode = false;
@@ -71,23 +87,43 @@ extern "C" {
// Alarm // Alarm
// //
void otPlatAlarmStop(otInstance *) void otPlatAlarmStop(otInstance *aInstance)
{ {
sTimerOn = false; if (g_testPlatAlarmStop)
sCallCount[kCallCountIndexAlarmStop]++; {
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; if (g_testPlatAlarmStartAt)
sCallCount[kCallCountIndexAlarmStart]++; {
sPlatT0 = aT0; g_testPlatAlarmStartAt(aInstance, aT0, aDt);
sPlatDt = aDt; }
else
{
g_testPlatAlarmSet = true;
g_testPlatAlarmNext = aT0 + aDt;
}
} }
uint32_t otPlatAlarmGetNow(void) 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) 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 *) ThreadError otPlatRadioSleep(otInstance *)
@@ -129,19 +191,40 @@ extern "C" {
return kThreadError_None; 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 *) int8_t otPlatRadioGetRssi(otInstance *)
@@ -151,7 +234,7 @@ extern "C" {
otRadioCaps otPlatRadioGetCaps(otInstance *) otRadioCaps otPlatRadioGetCaps(otInstance *)
{ {
return kRadioCapsNone; return g_testPlatRadioCaps;
} }
bool otPlatRadioGetPromiscuous(otInstance *) bool otPlatRadioGetPromiscuous(otInstance *)
+93
View File
@@ -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
+34 -9
View File
@@ -26,12 +26,9 @@
* POSSIBILITY OF SUCH DAMAGE. * POSSIBILITY OF SUCH DAMAGE.
*/ */
#include "test_util.h" #include "test_platform.h"
#include <openthread.h>
#include <common/debug.hpp> #include <common/debug.hpp>
#include <common/timer.hpp> #include <common/timer.hpp>
#include <platform/alarm.h>
#include <string.h>
#include <openthread-instance.h> #include <openthread-instance.h>
enum enum
@@ -43,11 +40,37 @@ enum
kCallCountIndexMax kCallCountIndexMax
}; };
extern uint32_t sNow; uint32_t sNow;
extern uint32_t sPlatT0; uint32_t sPlatT0;
extern uint32_t sPlatDt; uint32_t sPlatDt;
extern bool sTimerOn; bool sTimerOn;
extern uint32_t sCallCount[kCallCountIndexMax]; 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) void InitCounters(void)
{ {
@@ -76,6 +99,7 @@ int TestOneTimer(void)
// Test one Timer basic operation. // Test one Timer basic operation.
InitTestTimer();
InitCounters(); InitCounters();
sNow = kTimeT0; sNow = kTimeT0;
@@ -321,6 +345,7 @@ int TestTenTimers(void)
// Start the Ten timers. // Start the Ten timers.
InitTestTimer();
InitCounters(); InitCounters();
for (i = 0; i < kNumTimers ; i++) for (i = 0; i < kNumTimers ; i++)
+7
View File
@@ -72,6 +72,8 @@ extern "C" {
// //
#define CompileTimeAssert(COND, MSG) #define CompileTimeAssert(COND, MSG)
#define Log(aFormat, ...) printf(aFormat "\n", ## __VA_ARGS__)
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
@@ -81,12 +83,17 @@ extern "C" {
typedef void (*utAssertTrue)(bool condition, const wchar_t *message); typedef void (*utAssertTrue)(bool condition, const wchar_t *message);
extern utAssertTrue s_AssertTrue; 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 SuccessOrQuit(ERR, MSG) s_AssertTrue((ERR) == kThreadError_None, L##MSG)
#define VerifyOrQuit(ERR, MSG) s_AssertTrue(ERR, L##MSG) #define VerifyOrQuit(ERR, MSG) s_AssertTrue(ERR, L##MSG)
#define CompileTimeAssert(COND, MSG) static_assert(COND, MSG) #define CompileTimeAssert(COND, MSG) static_assert(COND, MSG)
#define Log(aFormat, ...) s_LogMessage(aFormat, ## __VA_ARGS__)
#endif #endif
#endif #endif
+33 -6
View File
@@ -29,6 +29,7 @@
#include <SDKDDKVer.h> #include <SDKDDKVer.h>
#include "CppUnitTest.h" #include "CppUnitTest.h"
#include "test_util.h" #include "test_util.h"
#include "test_platform.h"
using namespace Microsoft::VisualStudio::CppUnitTestFramework; using namespace Microsoft::VisualStudio::CppUnitTestFramework;
@@ -80,17 +81,21 @@ void test_packed2();
void test_packed_union(); void test_packed_union();
void test_packed_enum(); void test_packed_enum();
// test_fuzz.cpp
void TestFuzz(uint32_t aSeconds);
#pragma endregion #pragma endregion
utAssertTrue s_AssertTrue; utAssertTrue s_AssertTrue;
utLogMessage s_LogMessage;
namespace Thread namespace Thread
{ {
TEST_CLASS(UnitTests) TEST_CLASS(UnitTests)
{ {
public: public:
UnitTests() { s_AssertTrue = AssertTrue; } UnitTests() { s_AssertTrue = AssertTrue; s_LogMessage = LogMessage; }
// Helper for openthread test code to call // Helper for openthread test code to call
static void AssertTrue(bool condition, const wchar_t* message) static void AssertTrue(bool condition, const wchar_t* message)
@@ -98,6 +103,25 @@ namespace Thread
Assert::IsTrue(condition, message); 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_aes.cpp
TEST_METHOD(TestMacBeaconFrame) { ::TestMacBeaconFrame(); } TEST_METHOD(TestMacBeaconFrame) { ::TestMacBeaconFrame(); }
TEST_METHOD(TestMacDataFrame) { ::TestMacDataFrame(); } TEST_METHOD(TestMacDataFrame) { ::TestMacDataFrame(); }
@@ -131,5 +155,8 @@ namespace Thread
TEST_METHOD(test_packed2) { ::test_packed2(); } TEST_METHOD(test_packed2) { ::test_packed2(); }
TEST_METHOD(test_packed_union) { ::test_packed_union(); } TEST_METHOD(test_packed_union) { ::test_packed_union(); }
TEST_METHOD(test_packed_enum) { ::test_packed_enum(); } TEST_METHOD(test_packed_enum) { ::test_packed_enum(); }
};
// test_settings.cpp
TEST_METHOD(RunTestFuzz) { ::TestFuzz(0); }
};
} }