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>
<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>
+4
View File
@@ -51,6 +51,10 @@
(RtlAssert( #exp, __FILE__, __LINE__, NULL ),FALSE) : \
TRUE)
#elif defined(_WIN32)
#include <assert.h>
#else
#define assert(cond) \
+4
View File
@@ -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
View File
@@ -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;
+9
View File
@@ -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.
*
+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 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,
+9 -4
View File
@@ -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();
+5
View File
@@ -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
+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.
*/
#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 *)
+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.
*/
#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++)
+7
View File
@@ -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
+33 -6
View File
@@ -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); }
};
}