Support meshcop datasets and propagation. (#330)

This commit is contained in:
Jonathan Hui
2016-08-04 09:46:48 -07:00
committed by GitHub
parent b209ac63aa
commit 2a493e7ec0
27 changed files with 2702 additions and 95 deletions
+4
View File
@@ -107,6 +107,10 @@ void otPlatLog(otLogLevel aLogLevel, otLogRegion aLogRegion, const char *aFormat
case kLogRegionNcp:
fprintf(stderr, "NCP ");
break;
case kLogRegionMeshCoP:
fprintf(stderr, "MCOP ");
break;
}
va_start(args, aFormat);
+1
View File
@@ -86,6 +86,7 @@ typedef enum otLogRegion
kLogRegionMac = 7, ///< IEEE 802.15.4 MAC
kLogRegionMem = 8, ///< Memory
kLogRegionNcp = 9, ///< NCP
kLogRegionMeshCoP = 10, ///< Mesh Commissioning Protocol
} otLogRegion;
/**
+2
View File
@@ -39,12 +39,14 @@ libopenthread_cli_a_CPPFLAGS = \
libopenthread_cli_a_SOURCES = \
cli.cpp \
cli_dataset.cpp \
cli_uart.cpp \
cli_udp.cpp \
$(NULL)
noinst_HEADERS = \
cli.hpp \
cli_dataset.hpp \
cli_uart.hpp \
cli_server.hpp \
cli_udp.hpp \
+9
View File
@@ -39,6 +39,7 @@
#include <openthread-config.h>
#include "cli.hpp"
#include "cli_dataset.hpp"
#include <common/encoding.hpp>
#include <platform/uart.h>
@@ -56,6 +57,7 @@ const struct Command Interpreter::sCommands[] =
{ "childtimeout", &ProcessChildTimeout },
{ "contextreusedelay", &ProcessContextIdReuseDelay },
{ "counter", &ProcessCounters },
{ "dataset", &ProcessDataset },
{ "discover", &ProcessDiscover },
{ "eidcache", &ProcessEidCache },
{ "extaddr", &ProcessExtAddress },
@@ -354,6 +356,13 @@ void Interpreter::ProcessCounters(int argc, char *argv[])
}
}
void Interpreter::ProcessDataset(int argc, char *argv[])
{
ThreadError error;
error = Dataset::Process(argc, argv, *sServer);
AppendResult(error);
}
void Interpreter::ProcessDiscover(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
+4 -2
View File
@@ -78,6 +78,9 @@ public:
*/
static void ProcessLine(char *aBuf, uint16_t aBufLength, Server &aServer);
static ThreadError ParseLong(char *argv, long &value);
static int Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength);
private:
enum
{
@@ -93,6 +96,7 @@ private:
static void ProcessChildTimeout(int argc, char *argv[]);
static void ProcessContextIdReuseDelay(int argc, char *argv[]);
static void ProcessCounters(int argc, char *argv[]);
static void ProcessDataset(int argc, char *argv[]);
static void ProcessDiscover(int argc, char *argv[]);
static void ProcessEidCache(int argc, char *argv[]);
static void ProcessExtAddress(int argc, char *argv[]);
@@ -130,8 +134,6 @@ private:
static void HandleEchoResponse(void *aContext, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandlePingTimer(void *aContext);
static void HandleActiveScanResult(otActiveScanResult *aResult);
static int Hex2Bin(const char *aHex, uint8_t *aBin, uint16_t aBinLength);
static ThreadError ParseLong(char *argv, long &value);
static const struct Command sCommands[];
static otNetifAddress sAddress;
+386
View File
@@ -0,0 +1,386 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file implements the CLI interpreter.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <openthread.h>
#include <openthread-config.h>
#include "cli.hpp"
#include "cli_dataset.hpp"
#include <common/encoding.hpp>
#include <thread/meshcop_dataset.hpp>
#include <thread/thread_netif.hpp>
using Thread::Encoding::BigEndian::HostSwap16;
using Thread::Encoding::BigEndian::HostSwap32;
namespace Thread {
extern ThreadNetif *sThreadNetif;
namespace Cli {
const DatasetCommand Dataset::sCommands[] =
{
{ "help", &ProcessHelp },
{ "active", &ProcessActive },
{ "activetimestamp", &ProcessActiveTimestamp },
{ "channel", &ProcessChannel },
{ "clear", &ProcessClear },
{ "commit", &ProcessCommit },
{ "delay", &ProcessDelay },
{ "extpanid", &ProcessExtPanId },
{ "masterkey", &ProcessMasterKey },
{ "meshlocalprefix", &ProcessMeshLocalPrefix },
{ "networkname", &ProcessNetworkName },
{ "panid", &ProcessPanId },
{ "pending", &ProcessPending },
{ "timestamp", &ProcessTimestamp },
};
Server *Dataset::sServer;
MeshCoP::Dataset sDataset;
void Dataset::OutputBytes(const uint8_t *aBytes, uint8_t aLength)
{
for (int i = 0; i < aLength; i++)
{
sServer->OutputFormat("%02x", aBytes[i]);
}
}
ThreadError Dataset::Print(MeshCoP::Dataset &aDataset)
{
MeshCoP::Tlv *tlv;
sServer->OutputFormat("Timestamp: %d\r\n", aDataset.GetTimestamp().GetSeconds());
if ((tlv = aDataset.Get(MeshCoP::Tlv::kActiveTimestamp)) != NULL)
{
MeshCoP::ActiveTimestampTlv *tmp = static_cast<MeshCoP::ActiveTimestampTlv *>(tlv);
sServer->OutputFormat("Active Timestamp: %d\r\n", tmp->GetSeconds());
}
if ((tlv = aDataset.Get(MeshCoP::Tlv::kChannel)) != NULL)
{
MeshCoP::ChannelTlv *tmp = static_cast<MeshCoP::ChannelTlv *>(tlv);
sServer->OutputFormat("Channel: %d\r\n", tmp->GetChannel());
}
if ((tlv = aDataset.Get(MeshCoP::Tlv::kDelayTimer)) != NULL)
{
MeshCoP::DelayTimerTlv *tmp = static_cast<MeshCoP::DelayTimerTlv *>(tlv);
sServer->OutputFormat("Delay: %d\r\n", tmp->GetDelayTimer());
}
if ((tlv = aDataset.Get(MeshCoP::Tlv::kExtendedPanId)) != NULL)
{
MeshCoP::ExtendedPanIdTlv *tmp = static_cast<MeshCoP::ExtendedPanIdTlv *>(tlv);
sServer->OutputFormat("Ext PAN ID: ");
OutputBytes(tmp->GetExtendedPanId(), OT_EXT_PAN_ID_SIZE);
sServer->OutputFormat("\r\n");
}
if ((tlv = aDataset.Get(MeshCoP::Tlv::kMeshLocalPrefix)) != NULL)
{
MeshCoP::MeshLocalPrefixTlv *tmp = static_cast<MeshCoP::MeshLocalPrefixTlv *>(tlv);
const uint8_t *prefix = tmp->GetMeshLocalPrefix();
sServer->OutputFormat("Mesh Local Prefix: %x:%x:%x:%x/64\r\n",
(static_cast<uint16_t>(prefix[0]) << 16) | prefix[1],
(static_cast<uint16_t>(prefix[2]) << 16) | prefix[3],
(static_cast<uint16_t>(prefix[4]) << 16) | prefix[5],
(static_cast<uint16_t>(prefix[6]) << 16) | prefix[7]);
}
if ((tlv = aDataset.Get(MeshCoP::Tlv::kNetworkMasterKey)) != NULL)
{
MeshCoP::NetworkMasterKeyTlv *tmp = static_cast<MeshCoP::NetworkMasterKeyTlv *>(tlv);
sServer->OutputFormat("Master Key: ");
OutputBytes(tmp->GetNetworkMasterKey(), tmp->GetLength());
sServer->OutputFormat("\r\n");
}
if ((tlv = aDataset.Get(MeshCoP::Tlv::kNetworkName)) != NULL)
{
MeshCoP::NetworkNameTlv *tmp = static_cast<MeshCoP::NetworkNameTlv *>(tlv);
sServer->OutputFormat("Network Name: ");
sServer->OutputFormat("%.*s\r\n", OT_NETWORK_NAME_SIZE, tmp->GetNetworkName());
}
if ((tlv = aDataset.Get(MeshCoP::Tlv::kPanId)) != NULL)
{
MeshCoP::PanIdTlv *tmp = static_cast<MeshCoP::PanIdTlv *>(tlv);
sServer->OutputFormat("PAN ID: 0x%04x\r\n", tmp->GetPanId());
}
return kThreadError_None;
}
ThreadError Dataset::Process(int argc, char *argv[], Server &aServer)
{
ThreadError error = kThreadError_None;
sServer = &aServer;
if (argc == 0)
{
ExitNow(error = Print(sDataset));
}
for (unsigned int i = 0; i < sizeof(sCommands) / sizeof(sCommands[0]); i++)
{
if (strcmp(argv[0], sCommands[i].mName) == 0)
{
error = sCommands[i].mCommand(argc - 1, argv + 1);
break;
}
}
exit:
return error;
}
ThreadError Dataset::ProcessHelp(int argc, char *argv[])
{
for (unsigned int i = 0; i < sizeof(sCommands) / sizeof(sCommands[0]); i++)
{
sServer->OutputFormat("%s\r\n", sCommands[i].mName);
}
(void)argc;
(void)argv;
return kThreadError_None;
}
ThreadError Dataset::ProcessActive(int argc, char *argv[])
{
(void)argc;
(void)argv;
return Print(sThreadNetif->GetActiveDataset().GetLocal());
}
ThreadError Dataset::ProcessActiveTimestamp(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::ActiveTimestampTlv tlv;
long value;
VerifyOrExit(argc > 0, ;);
SuccessOrExit(error = Interpreter::ParseLong(argv[0], value));
tlv.Init();
tlv.SetSeconds(value);
tlv.SetTicks(0);
tlv.SetAuthoritative(false);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessChannel(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::ChannelTlv tlv;
long value;
VerifyOrExit(argc > 0, error = kThreadError_Parse);
SuccessOrExit(error = Interpreter::ParseLong(argv[0], value));
tlv.Init();
tlv.SetChannelPage(0);
tlv.SetChannel(value);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessClear(int argc, char *argv[])
{
sDataset.Clear();
(void)argc;
(void)argv;
return kThreadError_None;
}
ThreadError Dataset::ProcessCommit(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
VerifyOrExit(argc > 0, ;);
if (strcmp(argv[0], "active") == 0)
{
sThreadNetif->GetActiveDataset().Set(sDataset);
}
else if (strcmp(argv[0], "pending") == 0)
{
sThreadNetif->GetPendingDataset().Set(sDataset);
}
else
{
ExitNow(error = kThreadError_Parse);
}
sThreadNetif->GetNetworkDataLeader().IncrementVersion();
sThreadNetif->GetNetworkDataLeader().IncrementStableVersion();
exit:
return error;
}
ThreadError Dataset::ProcessDelay(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::DelayTimerTlv tlv;
long value;
VerifyOrExit(argc > 0, error = kThreadError_Parse);
SuccessOrExit(error = Interpreter::ParseLong(argv[0], value));
tlv.Init();
tlv.SetDelayTimer(value);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessExtPanId(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::ExtendedPanIdTlv tlv;
uint8_t extPanId[8];
VerifyOrExit(argc > 0, error = kThreadError_Parse);
VerifyOrExit(Interpreter::Hex2Bin(argv[0], extPanId, sizeof(extPanId)) >= 0, error = kThreadError_Parse);
tlv.Init();
tlv.SetExtendedPanId(extPanId);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessMasterKey(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::NetworkMasterKeyTlv tlv;
int8_t keyLength;
uint8_t key[16];
VerifyOrExit(argc > 0, error = kThreadError_Parse);
VerifyOrExit((keyLength = Interpreter::Hex2Bin(argv[0], key, sizeof(key))) == 16, error = kThreadError_Parse);
tlv.Init();
tlv.SetNetworkMasterKey(key);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessMeshLocalPrefix(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::MeshLocalPrefixTlv tlv;
struct otIp6Address prefix;
VerifyOrExit(argc > 0, error = kThreadError_Parse);
SuccessOrExit(error = otIp6AddressFromString(argv[0], &prefix));
tlv.Init();
tlv.SetMeshLocalPrefix(prefix.mFields.m8);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessNetworkName(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::NetworkNameTlv tlv;
VerifyOrExit(argc > 0, error = kThreadError_Parse);
tlv.Init();
tlv.SetNetworkName(argv[0]);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessPanId(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::PanIdTlv tlv;
long value;
VerifyOrExit(argc > 0, error = kThreadError_Parse);
SuccessOrExit(error = Interpreter::ParseLong(argv[0], value));
tlv.Init();
tlv.SetPanId(value);
error = sDataset.Set(tlv);
exit:
return error;
}
ThreadError Dataset::ProcessPending(int argc, char *argv[])
{
(void)argc;
(void)argv;
return Print(sThreadNetif->GetPendingDataset().GetLocal());
}
ThreadError Dataset::ProcessTimestamp(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
MeshCoP::Timestamp timestamp;
long value;
VerifyOrExit(argc > 0, error = kThreadError_Parse);
SuccessOrExit(error = Interpreter::ParseLong(argv[0], value));
timestamp.Init();
timestamp.SetSeconds(value);
sDataset.SetTimestamp(timestamp);
exit:
return error;
}
} // namespace Cli
} // namespace Thread
+97
View File
@@ -0,0 +1,97 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file contains definitions for the CLI interpreter.
*/
#ifndef CLI_DATASET_HPP_
#define CLI_DATASET_HPP_
#include <stdarg.h>
#include <cli/cli_server.hpp>
#include <thread/meshcop_dataset.hpp>
namespace Thread {
namespace Cli {
/**
* This structure represents a CLI command.
*
*/
struct DatasetCommand
{
const char *mName; ///< A pointer to the command string.
ThreadError(*mCommand)(int argc, char *argv[]); ///< A function pointer to process the command.
};
/**
* This class implements the CLI interpreter.
*
*/
class Dataset
{
public:
/**
* This method interprets a list of CLI arguments.
*
* @param[in] argc The number of elements in argv.
* @param[in] argv A pointer to an array of command line arguments.
*
*/
static ThreadError Process(int argc, char *argv[], Server &aServer);
private:
static void OutputBytes(const uint8_t *aBytes, uint8_t aLength);
static ThreadError Print(MeshCoP::Dataset &aDataset);
static ThreadError ProcessHelp(int argc, char *argv[]);
static ThreadError ProcessActive(int argc, char *argv[]);
static ThreadError ProcessActiveTimestamp(int argc, char *argv[]);
static ThreadError ProcessChannel(int argc, char *argv[]);
static ThreadError ProcessClear(int argc, char *argv[]);
static ThreadError ProcessCommit(int argc, char *argv[]);
static ThreadError ProcessDelay(int argc, char *argv[]);
static ThreadError ProcessExtPanId(int argc, char *argv[]);
static ThreadError ProcessMasterKey(int argc, char *argv[]);
static ThreadError ProcessMeshLocalPrefix(int argc, char *argv[]);
static ThreadError ProcessNetworkName(int argc, char *argv[]);
static ThreadError ProcessPanId(int argc, char *argv[]);
static ThreadError ProcessPending(int argc, char *argv[]);
static ThreadError ProcessTimestamp(int argc, char *argv[]);
static const DatasetCommand sCommands[];
static Server *sServer;
};
} // namespace Cli
} // namespace Thread
#endif // CLI_DATASET_HPP_
+6
View File
@@ -59,6 +59,9 @@ libopenthread_a_SOURCES = \
thread/key_manager.cpp \
thread/link_quality.cpp \
thread/lowpan.cpp \
thread/meshcop_dataset.cpp \
thread/meshcop_dataset_manager.cpp \
thread/meshcop_tlvs.cpp \
thread/mesh_forwarder.cpp \
thread/mle.cpp \
thread/mle_router.cpp \
@@ -102,6 +105,9 @@ noinst_HEADERS = \
thread/lowpan.hpp \
thread/meshcop_tlvs.hpp \
thread/mesh_forwarder.hpp \
thread/meshcop_dataset.hpp \
thread/meshcop_dataset_manager.hpp \
thread/meshcop_tlvs.hpp \
thread/mle.hpp \
thread/mle_constants.hpp \
thread/mle_router.hpp \
+51
View File
@@ -160,6 +160,57 @@ extern "C" {
#define otLogDebgApi(aFormat, ...)
#endif
/**
* @def otLogCritMeshCoP
*
* This method generates a log with level critical for the MLE region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
/**
* @def otLogWarnMeshCoP
*
* This method generates a log with level warning for the MLE region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
/**
* @def otLogInfoMeshCoP
*
* This method generates a log with level info for the MLE region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
/**
* @def otLogDebgMeshCoP
*
* This method generates a log with level debug for the MLE region.
*
* @param[in] aFormat A pointer to the format string.
* @param[in] ... Arguments for the format specification.
*
*/
#ifdef OPENTHREAD_CONFIG_LOG_MLE
#define otLogCritMeshCoP(aFormat, ...) otLogCrit(kLogRegionMeshCoP, aFormat, ## __VA_ARGS__)
#define otLogWarnMeshCoP(aFormat, ...) otLogWarn(kLogRegionMeshCoP, aFormat, ## __VA_ARGS__)
#define otLogInfoMeshCoP(aFormat, ...) otLogInfo(kLogRegionMeshCoP, aFormat, ## __VA_ARGS__)
#define otLogDebgMeshCoP(aFormat, ...) otLogDebg(kLogRegionMeshCoP, aFormat, ## __VA_ARGS__)
#else
#define otLogCritMeshCoP(aFormat, ...)
#define otLogWarnMeshCoP(aFormat, ...)
#define otLogInfoMeshCoP(aFormat, ...)
#define otLogDebgMeshCoP(aFormat, ...)
#endif
/**
* @def otLogCritMle
*
+163
View File
@@ -0,0 +1,163 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file implements common methods for manipulating MeshCoP Datasets.
*
*/
#include <stdio.h>
#include <common/code_utils.hpp>
#include <thread/meshcop_tlvs.hpp>
#include <thread/meshcop_dataset.hpp>
namespace Thread {
namespace MeshCoP {
Dataset::Dataset(void) :
mLength(0)
{
mTimestamp.Init();
}
void Dataset::Clear(void)
{
mTimestamp.Init();
mLength = 0;
}
Tlv *Dataset::Get(Tlv::Type aType)
{
Tlv *cur = reinterpret_cast<Tlv *>(mTlvs);
Tlv *end = reinterpret_cast<Tlv *>(mTlvs + mLength);
Tlv *rval = NULL;
while (cur < end)
{
if (cur->GetType() == aType)
{
ExitNow(rval = cur);
}
cur = cur->GetNext();
}
exit:
return rval;
}
const Tlv *Dataset::Get(Tlv::Type aType) const
{
const Tlv *cur = reinterpret_cast<const Tlv *>(mTlvs);
const Tlv *end = reinterpret_cast<const Tlv *>(mTlvs + mLength);
const Tlv *rval = NULL;
while (cur < end)
{
if (cur->GetType() == aType)
{
ExitNow(rval = cur);
}
cur = cur->GetNext();
}
exit:
return rval;
}
const Timestamp &Dataset::GetTimestamp(void) const
{
return mTimestamp;
}
void Dataset::SetTimestamp(const Timestamp &aTimestamp)
{
mTimestamp = aTimestamp;
}
ThreadError Dataset::Set(const Tlv &aTlv)
{
ThreadError error = kThreadError_None;
uint16_t bytesAvailable = sizeof(mTlvs) - mLength;
Tlv *old = Get(aTlv.GetType());
if (old != NULL)
{
bytesAvailable += sizeof(Tlv) + old->GetLength();
}
VerifyOrExit(sizeof(Tlv) + aTlv.GetLength() <= bytesAvailable, error = kThreadError_NoBufs);
// remove old TLV
if (old != NULL)
{
Remove(reinterpret_cast<uint8_t *>(old), sizeof(Tlv) + old->GetLength());
}
// add new TLV
memcpy(mTlvs + mLength, &aTlv, sizeof(Tlv) + aTlv.GetLength());
mLength += sizeof(Tlv) + aTlv.GetLength();
exit:
return error;
}
ThreadError Dataset::Set(const Message &aMessage, uint16_t aOffset, uint16_t aLength)
{
ThreadError error = kThreadError_None;
VerifyOrExit(aLength <= kMaxSize, error = kThreadError_InvalidArgs);
aMessage.Read(aOffset, aLength, mTlvs);
mLength = aLength;
exit:
return error;
}
void Dataset::Remove(Tlv::Type aType)
{
Tlv *tlv;
VerifyOrExit((tlv = Get(aType)) != NULL, ;);
Remove(reinterpret_cast<uint8_t *>(tlv), sizeof(Tlv) + tlv->GetLength());
exit:
return;
}
void Dataset::Remove(uint8_t *aStart, uint8_t aLength)
{
memmove(aStart, aStart + aLength, mLength - ((aStart - mTlvs) + aLength));
mLength -= aLength;
}
} // namespace MeshCoP
} // namespace Thread
+136
View File
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file includes definitions for managing MeshCoP Datasets.
*
*/
#ifndef MESHCOP_DATASET_HPP_
#define MESHCOP_DATASET_HPP_
#include <common/message.hpp>
#include <thread/meshcop_tlvs.hpp>
namespace Thread {
namespace MeshCoP {
class Dataset
{
public:
enum
{
kMaxSize = 256, ///< Maximum size of MeshCoP Dataset (bytes)
};
/**
* This constructor initializes the object.
*
*/
Dataset(void);
/**
* This method clears the Dataset.
*
*/
void Clear(void);
/**
* This method returns a pointer to the TLV.
*
* @returns A pointer to the TLV or NULL if none is found.
*
*/
Tlv *Get(Tlv::Type aType);
/**
* This method returns a pointer to the TLV.
*
* @returns A pointer to the TLV or NULL if none is found.
*
*/
const Tlv *Get(Tlv::Type aType) const;
/**
* This method returns a pointer to the byte representation of the Dataset.
*
* @returns A pointer to the byte representation of the Dataset.
*
*/
const uint8_t *GetBytes(void) const { return mTlvs; }
/**
* This method returns the Dataset size in bytes.
*
* @returns The Dataset size in bytes.
*
*/
uint16_t GetSize(void) const { return mLength; }
/**
* This method returns a reference to the Timestamp.
*
* @returns A reference to the Timestamp.
*
*/
const Timestamp &GetTimestamp(void) const;
/**
* This method sets the Timestamp value.
*
*/
void SetTimestamp(const Timestamp &aTimestamp);
/**
* This method sets a TLV in the Dataset.
*
* @param[in] aTlv A reference to the TLV.
*
* @retval kThreadError_None Successfully set the TLV.
* @retval kThreadError_NoBufs Could not set the TLV due to insufficient buffer space.
*
*/
ThreadError Set(const Tlv &aTlv);
ThreadError Set(const Message &aMessage, uint16_t aOffset, uint16_t aLength);
void Remove(Tlv::Type aType);
private:
void Remove(uint8_t *aStart, uint8_t aLength);
Timestamp mTimestamp; ///< Active or Pending Timestamp
uint8_t mTlvs[kMaxSize]; ///< The Dataset buffer
uint16_t mLength; ///< The number of valid bytes in @var mTlvs
};
} // namespace MeshCoP
} // namespace Thread
#endif // MESHCOP_DATASET_HPP_
+540
View File
@@ -0,0 +1,540 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file implements common methods for manipulating MeshCoP Datasets.
*
*/
#include <stdio.h>
#include <coap/coap_header.hpp>
#include <common/code_utils.hpp>
#include <common/logging.hpp>
#include <common/timer.hpp>
#include <platform/random.h>
#include <thread/meshcop_dataset.hpp>
#include <thread/meshcop_dataset_manager.hpp>
#include <thread/thread_netif.hpp>
#include <thread/thread_tlvs.hpp>
#include <thread/thread_uris.hpp>
namespace Thread {
namespace MeshCoP {
DatasetManager::DatasetManager(ThreadNetif &aThreadNetif, const char *aUri):
mMle(aThreadNetif.GetMle()),
mNetif(aThreadNetif),
mNetworkDataLeader(aThreadNetif.GetNetworkDataLeader()),
mResource(aUri, &HandleSet, this),
mTimer(&HandleTimer, this),
mUri(aUri),
mCoapServer(aThreadNetif.GetCoapServer())
{
mCoapServer.AddResource(mResource);
}
ThreadError DatasetManager::Set(const Dataset &aDataset, uint8_t &aFlags)
{
ThreadError error = kThreadError_None;
aFlags = 0;
VerifyOrExit(mNetwork.GetTimestamp().Compare(aDataset.GetTimestamp()) > 0, error = kThreadError_InvalidArgs);
mLocal = aDataset;
aFlags |= kFlagLocalUpdated;
switch (mMle.GetDeviceState())
{
case Mle::kDeviceStateChild:
case Mle::kDeviceStateRouter:
mTimer.Start(1000);
break;
case Mle::kDeviceStateLeader:
mNetwork = mLocal;
aFlags |= kFlagNetworkUpdated;
mNetworkDataLeader.IncrementVersion();
mNetworkDataLeader.IncrementStableVersion();
break;
default:
break;
}
exit:
return error;
}
ThreadError DatasetManager::Set(const Timestamp &aTimestamp, const Message &aMessage,
uint16_t aOffset, uint16_t aLength, uint8_t &aFlags)
{
ThreadError error = kThreadError_None;
int compare;
aFlags = 0;
SuccessOrExit(error = mNetwork.Set(aMessage, aOffset, aLength));
mNetwork.SetTimestamp(aTimestamp);
aFlags |= kFlagNetworkUpdated;
compare = mLocal.GetTimestamp().Compare(aTimestamp);
if (compare > 0)
{
SuccessOrExit(error = mLocal.Set(aMessage, aOffset, aLength));
mLocal.SetTimestamp(aTimestamp);
aFlags |= kFlagLocalUpdated;
}
else if (compare < 0)
{
mTimer.Start(1000);
}
exit:
return error;
}
ThreadError DatasetManager::ApplyLocalToNetwork(void)
{
mNetwork = mLocal;
return kThreadError_None;
}
void DatasetManager::HandleTimer(void *aContext)
{
DatasetManager *obj = static_cast<DatasetManager *>(aContext);
obj->HandleTimer();
}
void DatasetManager::HandleTimer(void)
{
VerifyOrExit(mMle.IsAttached() && mNetwork.GetTimestamp().Compare(mLocal.GetTimestamp()) > 0, ;);
VerifyOrExit(mLocal.Get(Tlv::kDelayTimer) != NULL, ;);
Register();
mTimer.Start(1000);
exit:
return;
}
ThreadError DatasetManager::Register(void)
{
ThreadError error = kThreadError_None;
Coap::Header header;
Message *message;
Ip6::Address leader;
Ip6::MessageInfo messageInfo;
ActiveTimestampTlv timestamp;
mSocket.Open(&HandleUdpReceive, this);
for (size_t i = 0; i < sizeof(mCoapToken); i++)
{
mCoapToken[i] = otPlatRandomGet();
}
header.Init();
header.SetVersion(1);
header.SetType(Coap::Header::kTypeConfirmable);
header.SetCode(Coap::Header::kCodePost);
header.SetMessageId(++mCoapMessageId);
header.SetToken(mCoapToken, sizeof(mCoapToken));
header.AppendUriPathOptions(mUri);
header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream);
header.Finalize();
VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, error = kThreadError_NoBufs);
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
timestamp.Init();
*static_cast<Timestamp *>(&timestamp) = mLocal.GetTimestamp();
SuccessOrExit(error = message->Append(&timestamp, sizeof(timestamp)));
SuccessOrExit(error = message->Append(mLocal.GetBytes(), mLocal.GetSize()));
mMle.GetLeaderAddress(leader);
memset(&messageInfo, 0, sizeof(messageInfo));
memcpy(&messageInfo.mPeerAddr, &leader, sizeof(messageInfo.mPeerAddr));
messageInfo.mPeerPort = kCoapUdpPort;
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
otLogInfoMeshCoP("sent dataset to leader\n");
exit:
if (error != kThreadError_None && message != NULL)
{
Message::Free(*message);
}
return error;
}
void DatasetManager::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
{
DatasetManager *obj = static_cast<DatasetManager *>(aContext);
obj->HandleUdpReceive(*static_cast<Message *>(aMessage), *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
}
void DatasetManager::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
Coap::Header header;
(void)aMessageInfo;
SuccessOrExit(header.FromMessage(aMessage));
VerifyOrExit(header.GetType() == Coap::Header::kTypeAcknowledgment &&
header.GetCode() == Coap::Header::kCodeChanged &&
header.GetMessageId() == mCoapMessageId &&
header.GetTokenLength() == sizeof(mCoapToken) &&
memcmp(mCoapToken, header.GetToken(), sizeof(mCoapToken)) == 0, ;);
otLogInfoMeshCoP("received response from leader\n");
exit:
return;
}
void DatasetManager::HandleSet(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
DatasetManager *obj = static_cast<DatasetManager *>(aContext);
obj->HandleSet(aHeader, aMessage, aMessageInfo);
}
void DatasetManager::HandleSet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
Tlv tlv;
Timestamp timestamp;
uint16_t offset = aMessage.GetOffset();
uint8_t type;
VerifyOrExit(mMle.GetDeviceState() == Mle::kDeviceStateLeader, ;);
type = strcmp(mUri, OPENTHREAD_URI_ACTIVE_SET) == 0 ? Tlv::kActiveTimestamp : Tlv::kPendingTimestamp;
while (offset < aMessage.GetLength())
{
aMessage.Read(offset, sizeof(tlv), &tlv);
if (tlv.GetType() == type)
{
aMessage.Read(offset + sizeof(Tlv), sizeof(timestamp), &timestamp);
break;
}
offset += sizeof(tlv) + tlv.GetLength();
}
// verify the request includes a timestamp that is ahead of the locally stored value
VerifyOrExit(offset < aMessage.GetLength() && mLocal.GetTimestamp().Compare(timestamp) > 0, ;);
mLocal.Set(aMessage, aMessage.GetOffset(), aMessage.GetLength() - aMessage.GetOffset());
mNetwork = mLocal;
mNetworkDataLeader.IncrementVersion();
mNetworkDataLeader.IncrementStableVersion();
SendSetResponse(aHeader, aMessageInfo);
exit:
return;
}
void DatasetManager::SendSetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
Coap::Header responseHeader;
Message *message;
VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, error = kThreadError_NoBufs);
responseHeader.Init();
responseHeader.SetVersion(1);
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
responseHeader.SetCode(Coap::Header::kCodeChanged);
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
responseHeader.AppendContentFormatOption(Coap::Header::kApplicationOctetStream);
responseHeader.Finalize();
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
SuccessOrExit(error = mCoapServer.SendMessage(*message, aMessageInfo));
otLogInfoMeshCoP("sent dataset response\n");
exit:
if (error != kThreadError_None && message != NULL)
{
Message::Free(*message);
}
}
ActiveDataset::ActiveDataset(ThreadNetif &aThreadNetif):
DatasetManager(aThreadNetif, OPENTHREAD_URI_ACTIVE_SET)
{
}
ThreadError ActiveDataset::Set(const Dataset &aDataset)
{
ThreadError error = kThreadError_None;
uint8_t flags;
SuccessOrExit(error = DatasetManager::Set(aDataset, flags));
ApplyConfiguration();
exit:
return error;
}
ThreadError ActiveDataset::Set(const Timestamp &aTimestamp, const Message &aMessage,
uint16_t aOffset, uint16_t aLength)
{
ThreadError error = kThreadError_None;
uint8_t flags;
SuccessOrExit(error = DatasetManager::Set(aTimestamp, aMessage, aOffset, aLength, flags));
ApplyConfiguration();
exit:
return error;
}
ThreadError ActiveDataset::ApplyConfiguration(void)
{
ThreadError error = kThreadError_None;
Dataset *dataset;
const Tlv *cur;
const Tlv *end;
dataset = mMle.IsAttached() ? &mNetwork : &mLocal;
cur = reinterpret_cast<const Tlv *>(dataset->GetBytes());
end = reinterpret_cast<const Tlv *>(dataset->GetBytes() + dataset->GetSize());
while (cur < end)
{
switch (cur->GetType())
{
case Tlv::kChannel:
{
const ChannelTlv *channel = static_cast<const ChannelTlv *>(cur);
mNetif.GetMac().SetChannel(channel->GetChannel());
break;
}
case Tlv::kPanId:
{
const PanIdTlv *panid = static_cast<const PanIdTlv *>(cur);
mNetif.GetMac().SetPanId(panid->GetPanId());
break;
}
case Tlv::kExtendedPanId:
{
const ExtendedPanIdTlv *extpanid = static_cast<const ExtendedPanIdTlv *>(cur);
mNetif.GetMac().SetExtendedPanId(extpanid->GetExtendedPanId());
break;
}
case Tlv::kNetworkName:
{
const NetworkNameTlv *extpanid = static_cast<const NetworkNameTlv *>(cur);
mNetif.GetMac().SetNetworkName(extpanid->GetNetworkName());
break;
}
case Tlv::kNetworkMasterKey:
{
const NetworkMasterKeyTlv *key = static_cast<const NetworkMasterKeyTlv *>(cur);
mNetif.GetKeyManager().SetMasterKey(key->GetNetworkMasterKey(), key->GetLength());
break;
}
case Tlv::kMeshLocalPrefix:
{
const MeshLocalPrefixTlv *prefix = static_cast<const MeshLocalPrefixTlv *>(cur);
mMle.SetMeshLocalPrefix(prefix->GetMeshLocalPrefix());
break;
}
default:
{
break;
}
}
cur = cur->GetNext();
}
return error;
}
PendingDataset::PendingDataset(ThreadNetif &aThreadNetif):
DatasetManager(aThreadNetif, OPENTHREAD_URI_PENDING_SET),
mTimer(HandleTimer, this)
{
}
ThreadError PendingDataset::Set(const Dataset &aDataset)
{
ThreadError error = kThreadError_None;
uint8_t flags;
SuccessOrExit(error = DatasetManager::Set(aDataset, flags));
ResetDelayTimer(flags);
exit:
return error;
}
ThreadError PendingDataset::Set(const Timestamp &aTimestamp, const Message &aMessage,
uint16_t aOffset, uint16_t aLength)
{
ThreadError error = kThreadError_None;
uint8_t flags;
SuccessOrExit(error = DatasetManager::Set(aTimestamp, aMessage, aOffset, aLength, flags));
ResetDelayTimer(flags);
exit:
return error;
}
void PendingDataset::ApplyLocalToNetwork(void)
{
DatasetManager::ApplyLocalToNetwork();
mNetworkTime = mLocalTime;
}
void PendingDataset::ResetDelayTimer(uint8_t aFlags)
{
DelayTimerTlv *delayTimer;
if (aFlags & kFlagLocalUpdated)
{
mLocalTime = Timer::GetNow();
mTimer.Stop();
if ((delayTimer = static_cast<DelayTimerTlv *>(mLocal.Get(Tlv::kDelayTimer))) != NULL)
{
mTimer.Start(delayTimer->GetDelayTimer());
otLogInfoMeshCoP("delay timer started\n");
}
}
if (aFlags & kFlagNetworkUpdated)
{
mNetworkTime = Timer::GetNow();
// if partition is up to date and delay timer already expired
if ((mNetwork.GetTimestamp().Compare(mLocal.GetTimestamp()) == 0) &&
(delayTimer = static_cast<DelayTimerTlv *>(mLocal.Get(Tlv::kDelayTimer))) != NULL &&
(delayTimer->GetDelayTimer() == 0))
{
HandleTimer();
}
}
}
void PendingDataset::UpdateDelayTimer(void)
{
UpdateDelayTimer(mLocal, mLocalTime);
UpdateDelayTimer(mNetwork, mNetworkTime);
}
void PendingDataset::UpdateDelayTimer(Dataset &aDataset, uint32_t &aStartTime)
{
DelayTimerTlv *delayTimer;
uint32_t now = Timer::GetNow();
uint32_t elapsed;
uint32_t delay;
VerifyOrExit((delayTimer = static_cast<DelayTimerTlv *>(aDataset.Get(Tlv::kDelayTimer))) != NULL, ;);
elapsed = now - aStartTime;
delay = delayTimer->GetDelayTimer();
if (delay > elapsed)
{
delay -= elapsed;
}
else
{
delay = 0;
}
delayTimer->SetDelayTimer(delay);
aStartTime = now;
exit:
return;
}
void PendingDataset::HandleTimer(void *aContext)
{
PendingDataset *obj = static_cast<PendingDataset *>(aContext);
obj->HandleTimer();
}
void PendingDataset::HandleTimer(void)
{
ActiveTimestampTlv *activeTimestamp;
otLogInfoMeshCoP("pending delay timer expired\n");
UpdateDelayTimer();
// update only if one of the following is true
// 1) not attached
// 2) partition's pending dataset is up to date
VerifyOrExit(!mMle.IsAttached() || mNetwork.GetTimestamp().Compare(mLocal.GetTimestamp()) == 0, ;);
mLocal.Remove(Tlv::kDelayTimer);
VerifyOrExit((activeTimestamp = static_cast<ActiveTimestampTlv *>(mLocal.Get(Tlv::kActiveTimestamp))) != NULL, ;);
mNetif.GetActiveDataset().GetLocal() = mLocal;
mNetif.GetActiveDataset().GetLocal().SetTimestamp(*activeTimestamp);
mNetif.GetActiveDataset().GetLocal().Remove(Tlv::kActiveTimestamp);
mNetif.GetActiveDataset().GetNetwork() = mNetif.GetActiveDataset().GetLocal();
mNetif.GetActiveDataset().ApplyConfiguration();
mNetworkDataLeader.IncrementVersion();
mNetworkDataLeader.IncrementStableVersion();
exit:
return;
}
} // namespace MeshCoP
} // namespace Thread
+147
View File
@@ -0,0 +1,147 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file includes definitions for managing MeshCoP Datasets.
*
*/
#ifndef MESHCOP_DATASET_MANAGER_HPP_
#define MESHCOP_DATASET_MANAGER_HPP_
#include <coap/coap_server.hpp>
#include <common/timer.hpp>
#include <net/udp6.hpp>
#include <thread/meshcop_dataset.hpp>
#include <thread/mle.hpp>
#include <thread/network_data_leader.hpp>
namespace Thread {
class ThreadNetif;
namespace MeshCoP {
class DatasetManager
{
public:
ThreadError ApplyLocalToNetwork(void);
Dataset &GetLocal(void) { return mLocal; }
Dataset &GetNetwork(void) { return mNetwork; }
protected:
enum
{
kFlagLocalUpdated = 1 << 0,
kFlagNetworkUpdated = 1 << 1,
};
DatasetManager(ThreadNetif &aThreadNetif, const char *aUri);
ThreadError Set(const Dataset &aDataset, uint8_t &aFlags);
ThreadError Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength,
uint8_t &aFlags);
Dataset mLocal;
Dataset mNetwork;
Mle::Mle &mMle;
ThreadNetif &mNetif;
NetworkData::Leader &mNetworkDataLeader;
private:
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
void HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleSet(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo);
void HandleSet(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleTimer(void *aContext);
void HandleTimer(void);
ThreadError Register(void);
void SendSetResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo);
Coap::Resource mResource;
Timer mTimer;
Ip6::UdpSocket mSocket;
uint8_t mCoapToken[2];
uint16_t mCoapMessageId;
const char *mUri;
Coap::Server &mCoapServer;
};
class ActiveDataset: public DatasetManager
{
public:
ActiveDataset(ThreadNetif &aThreadNetif);
ThreadError Set(const Dataset &aDataset);
ThreadError Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength);
ThreadError ApplyConfiguration(void);
};
class PendingDataset: public DatasetManager
{
public:
PendingDataset(ThreadNetif &aThreadNetif);
ThreadError Set(const Dataset &aDataset);
ThreadError Set(const Timestamp &aTimestamp, const Message &aMessage, uint16_t aOffset, uint16_t aLength);
void ApplyLocalToNetwork(void);
void UpdateDelayTimer(void);
private:
static void HandleTimer(void *aContext);
void HandleTimer(void);
void ResetDelayTimer(uint8_t aFlags);
void UpdateDelayTimer(Dataset &aDataset, uint32_t &aStartTime);
Timer mTimer;
uint32_t mLocalTime;
uint32_t mNetworkTime;
};
} // namespace MeshCoP
} // namespace Thread
#endif // MESHCOP_DATASET_MANAGER_HPP_
+73
View File
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2016, Nest Labs, Inc.
* 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.
*/
/**
* @file
* This file implements common MeshCoP TLV processing.
*/
#include <common/code_utils.hpp>
#include <thread/meshcop_tlvs.hpp>
namespace Thread {
namespace MeshCoP {
int Timestamp::Compare(const Timestamp &aCompare) const
{
uint64_t thisSeconds = GetSeconds();
uint64_t compareSeconds = aCompare.GetSeconds();
uint16_t thisTicks = GetTicks();
uint16_t compareTicks = aCompare.GetTicks();
int rval;
if (compareSeconds > thisSeconds)
{
rval = 1;
}
else if (compareSeconds < thisSeconds)
{
rval = -1;
}
else if (compareTicks > thisTicks)
{
rval = 1;
}
else if (compareTicks < thisTicks)
{
rval = -1;
}
else
{
rval = 0;
}
return rval;
}
} // namespace MeshCoP
} // namespace Thread
+618 -3
View File
@@ -41,6 +41,7 @@
#include <common/encoding.hpp>
using Thread::Encoding::BigEndian::HostSwap16;
using Thread::Encoding::BigEndian::HostSwap32;
namespace Thread {
namespace MeshCoP {
@@ -59,8 +60,18 @@ public:
*/
enum Type
{
kExtendedPanId = 2, ///< Extended PAN ID TLV
kNetworkName = 3, ///< Newtork Name TLV
kChannel = 0, ///< Channel TLV
kPanId = 1, ///< PAN ID TLV
kExtendedPanId = 2, ///< Extended PAN ID TLV
kNetworkName = 3, ///< Newtork Name TLV
kPSKc = 4, ///< PSKc TLV
kNetworkMasterKey = 5, ///< Network Master Key TLV
kMeshLocalPrefix = 7, ///< Mesh Local Prefix TLV
kSecurityPolicy = 12, ///< Security Policy TLV
kActiveTimestamp = 14, ///< Active Timestamp TLV
kPendingTimestamp = 51, ///< Pending Timestamp TLV
kDelayTimer = 52, ///< Delay Timer TLV
kChannelMask = 53, ///< Channel Mask TLV
kDiscoveryRequest = 128, ///< Discovery Request TLV
kDiscoveryResponse = 129, ///< Discovery Response TLV
};
@@ -113,11 +124,118 @@ public:
return reinterpret_cast<Tlv *>(reinterpret_cast<uint8_t *>(this) + sizeof(*this) + mLength);
}
const Tlv *GetNext() const {
return reinterpret_cast<const Tlv *>(reinterpret_cast<const uint8_t *>(this) + sizeof(*this) + mLength);
}
private:
uint8_t mType;
uint8_t mLength;
} OT_TOOL_PACKED_END;
/**
* This class implements Channel TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ChannelTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kChannel); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the ChannelPage value.
*
* @returns The ChannelPage value.
*
*/
uint8_t GetChannelPage(void) const { return mChannelPage; }
/**
* This method sets the ChannelPage value.
*
* @param[in] aChannelPage The ChannelPage value.
*
*/
void SetChannelPage(uint8_t aChannelPage) { mChannelPage = aChannelPage; }
/**
* This method returns the Channel value.
*
* @returns The Channel value.
*
*/
uint16_t GetChannel(void) const { return HostSwap16(mChannel); }
/**
* This method sets the Channel value.
*
* @param[in] aChannel The Channel value.
*
*/
void SetChannel(uint16_t aChannel) { mChannel = HostSwap16(aChannel); }
private:
uint8_t mChannelPage;
uint16_t mChannel;
} OT_TOOL_PACKED_END;
/**
* This class implements PAN ID TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class PanIdTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kPanId); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the PAN ID value.
*
* @returns The PAN ID value.
*
*/
uint16_t GetPanId(void) const { return HostSwap16(mPanId); }
/**
* This method sets the PAN ID value.
*
* @param[in] aPanId The PAN ID value.
*
*/
void SetPanId(uint16_t aPanId) { mPanId = HostSwap16(aPanId); }
private:
uint16_t mPanId;
} OT_TOOL_PACKED_END;
/**
* This class implements Extended PAN ID TLV generation and parsing.
*
@@ -203,13 +321,510 @@ public:
void SetNetworkName(const char *aNetworkName) {
int length = strnlen(aNetworkName, sizeof(mNetworkName));
memcpy(mNetworkName, aNetworkName, length);
SetLength(length);
}
private:
char mNetworkName[OT_NETWORK_NAME_SIZE];
} OT_TOOL_PACKED_END;
/**
* This class implements PSKc TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class PSKcTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kPSKc); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the PSKc value.
*
* @returns The PSKc value.
*
*/
const uint8_t *GetPSKc(void) const { return mPSKc; }
/**
* This method sets the PSKc value.
*
* @param[in] aPSKc A pointer to the PSKc value.
*
*/
void SetPSKc(const uint8_t *aPSKc) {
memcpy(mPSKc, aPSKc, sizeof(mPSKc));
}
private:
uint8_t mPSKc[16];
} OT_TOOL_PACKED_END;
/**
* This class implements Network Master Key TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class NetworkMasterKeyTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kNetworkMasterKey); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the Network Master Key value.
*
* @returns The Network Master Key value.
*
*/
const uint8_t *GetNetworkMasterKey(void) const { return mNetworkMasterKey; }
/**
* This method sets the Network Master Key value.
*
* @param[in] aNetworkMasterKey A pointer to the Network Master Key value.
*
*/
void SetNetworkMasterKey(const uint8_t *aNetworkMasterKey) {
memcpy(mNetworkMasterKey, aNetworkMasterKey, sizeof(mNetworkMasterKey));
}
private:
uint8_t mNetworkMasterKey[16];
} OT_TOOL_PACKED_END;
/**
* This class implements Mesh Local Prefix TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class MeshLocalPrefixTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kMeshLocalPrefix); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the Mesh Local Prefix value.
*
* @returns The Mesh Local Prefix value.
*
*/
const uint8_t *GetMeshLocalPrefix(void) const { return mMeshLocalPrefix; }
/**
* This method sets the Mesh Local Prefix value.
*
* @param[in] aMeshLocalPrefix A pointer to the Mesh Local Prefix value.
*
*/
void SetMeshLocalPrefix(const uint8_t *aMeshLocalPrefix) {
memcpy(mMeshLocalPrefix, aMeshLocalPrefix, sizeof(mMeshLocalPrefix));
}
private:
uint8_t mMeshLocalPrefix[8];
} OT_TOOL_PACKED_END;
/**
* This class implements Security Policy TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class SecurityPolicyTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kSecurityPolicy); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the Rotation Time value.
*
* @returns The Rotation Time value.
*
*/
uint16_t GetRotationTime(void) const { return HostSwap16(mRotationTime); }
/**
* This method sets the Rotation Time value.
*
* @param[in] aRotationTime The Rotation Time value.
*
*/
void SetRotationTime(uint16_t aRotationTime) { mRotationTime = HostSwap16(aRotationTime); }
enum
{
kObtainMasterKeyFlag = 1 << 7, ///< Obtaining the Master Key
kNativeCommissioningFlag = 1 << 6, ///< Native Commissioning
kRoutersFlag = 1 << 5, ///< Routers enabled
kExternalCommissionerFlag = 1 << 4, ///< External Commissioner allowed
kBeaconsFlag = 1 << 3, ///< Beacons enabled
};
/**
* This method returns the Flags value.
*
* @returns The Flags value.
*
*/
uint8_t GetFlags(void) const { return mFlags; }
/**
* This method sets the Flags value.
*
* @param[in] aFlags The Flags value.
*
*/
void SetFlags(uint8_t aFlags) { mFlags = aFlags; }
private:
uint16_t mRotationTime;
uint8_t mFlags;
} OT_TOOL_PACKED_END;
/**
* This class implements Timestamp generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class Timestamp
{
public:
/**
* This method initializes the Timestamp
*
*/
void Init(void) { memset(mSeconds, 0, sizeof(mSeconds)); mTicks = 0; }
/**
* This method compares this timestamp to another.
*
* @param[in] aCompare A reference to the timestamp to compare.
*
* @retval -1 if @p aCompare is less than this timestamp.
* @retval 0 if @p aCompare is equal to this timestamp.
* @retval 1 if @p aCompare is greater than this timestamp.
*
*/
int Compare(const Timestamp &aCompare) const;
/**
* This method returns the Seconds value.
*
* @returns The Seconds value.
*
*/
uint64_t GetSeconds(void) const {
uint64_t seconds = 0;
for (size_t i = 0; i < sizeof(mSeconds); i++) {
seconds = (seconds << 8) | mSeconds[i];
}
return seconds;
}
/**
* This method sets the Seconds value.
*
* @param[in] aSeconds The Seconds value.
*
*/
void SetSeconds(uint64_t aSeconds) {
for (size_t i = 0; i < sizeof(mSeconds); i++, aSeconds >>= 8) {
mSeconds[sizeof(mSeconds) - 1 - i] = aSeconds;
}
}
/**
* This method returns the Ticks value.
*
* @returns The Ticks value.
*
*/
uint16_t GetTicks(void) const { return mTicks >> kTicksOffset; }
/**
* This method sets the Ticks value.
*
* @param[in] aTicks The Ticks value.
*
*/
void SetTicks(uint16_t aTicks) { mTicks = (mTicks & ~kTicksMask) | (aTicks << kTicksOffset); }
/**
* This method returns the Authoritative value.
*
* @returns The Authoritative value.
*
*/
bool GetAuthoritative(void) const { return (mTicks & kAuthoritativeMask) != 0; }
/**
* This method sets the Authoritative value.
*
* @param[in] aAuthoritative The Authoritative value.
*
*/
void SetAuthoritative(bool aAuthoritative) {
mTicks = (mTicks & kTicksMask) | (aAuthoritative << kAuthoritativeOffset);
}
private:
uint8_t mSeconds[6];
enum
{
kTicksOffset = 1,
kTicksMask = 0x7fff << kTicksOffset,
kAuthoritativeOffset = 0,
kAuthoritativeMask = 1 << kAuthoritativeOffset,
};
uint16_t mTicks;
} OT_TOOL_PACKED_END;
/**
* This class implements Active Timestamp TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ActiveTimestampTlv : public Tlv, public Timestamp
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kActiveTimestamp); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
} OT_TOOL_PACKED_END;
/**
* This class implements Pending Timestamp TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class PendingTimestampTlv : public Tlv, public Timestamp
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kPendingTimestamp); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
} OT_TOOL_PACKED_END;
/**
* This class implements Delay Timer TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class DelayTimerTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kDelayTimer); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the Delay Timer value.
*
* @returns The Delay Timer value.
*
*/
uint16_t GetDelayTimer(void) const { return HostSwap32(mDelayTimer); }
/**
* This method sets the Delay Timer value.
*
* @param[in] aDelayTimer The Delay Timer value.
*
*/
void SetDelayTimer(uint32_t aDelayTimer) { mDelayTimer = HostSwap32(aDelayTimer); }
private:
uint32_t mDelayTimer;
} OT_TOOL_PACKED_END;
/**
* This class implements Channel Mask Entry generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ChannelMaskEntry
{
public:
/**
* This method gets the ChannelPage value.
*
* @returns The ChannelPage value.
*
*/
uint8_t GetChannelPage(void) const { return mChannelPage; }
/**
* This method sets the ChannelPage value.
*
* @param[in] aChannelPage The ChannelPage value.
*
*/
void SetChannelPage(uint8_t aChannelPage) { mChannelPage = aChannelPage; }
/**
* This method gets the MaskLength value.
*
* @returns The MaskLength value.
*
*/
uint8_t GetMaskLength(void) const { return mMaskLength; }
/**
* This method sets the MaskLength value.
*
* @param[in] aMaskLength The MaskLength value.
*
*/
void SetMaskLength(uint8_t aMaskLength) { mMaskLength = aMaskLength; }
/**
* This method clears the bit corresponding to @p aChannel in ChannelMask.
*
* @param[in] aChannel The channel in ChannelMask to clear.
*
*/
void ClearChannel(uint8_t aChannel) {
uint8_t *mask = reinterpret_cast<uint8_t *>(this) + sizeof(*this);
mask[aChannel / 8] &= ~(1 << (aChannel % 8));
}
/**
* This method sets the bit corresponding to @p aChannel in ChannelMask.
*
* @param[in] aChannel The channel in ChannelMask to set.
*
*/
void SetChannel(uint8_t aChannel) {
uint8_t *mask = reinterpret_cast<uint8_t *>(this) + sizeof(*this);
mask[aChannel / 8] |= 1 << (aChannel % 8);
}
/**
* This method indicates whether or not the bit corresponding to @p aChannel in ChannelMask is set.
*
* @param[in] aChannel The channel in ChannelMask to get.
*
*/
bool IsChannelSet(uint8_t aChannel) const {
const uint8_t *mask = reinterpret_cast<const uint8_t *>(this) + sizeof(*this);
return (aChannel < (mMaskLength * 8)) ? mask[aChannel / 8] & (1 << (aChannel % 8)) : false;
}
private:
uint8_t mChannelPage;
uint8_t mMaskLength;
} OT_TOOL_PACKED_END;
/**
* This class implements Channel Mask TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ChannelMaskTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kChannelMask); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return true; }
} OT_TOOL_PACKED_END;
/**
* This class implements Discovery Request TLV generation and parsing.
*
+112 -59
View File
@@ -301,6 +301,13 @@ exit:
return error;
}
bool Mle::IsAttached(void) const
{
return (mDeviceState == kDeviceStateChild ||
mDeviceState == kDeviceStateRouter ||
mDeviceState == kDeviceStateLeader);
}
DeviceState Mle::GetDeviceState(void) const
{
return mDeviceState;
@@ -830,6 +837,38 @@ exit:
return error;
}
ThreadError Mle::AppendActiveTimestamp(Message &aMessage)
{
ThreadError error;
ActiveTimestampTlv timestampTlv;
const MeshCoP::Timestamp &timestamp(mNetif.GetActiveDataset().GetNetwork().GetTimestamp());
VerifyOrExit(timestamp.GetSeconds() != 0, error = kThreadError_None);
timestampTlv.Init();
*static_cast<MeshCoP::Timestamp *>(&timestampTlv) = timestamp;
error = aMessage.Append(&timestampTlv, sizeof(timestampTlv));
exit:
return error;
}
ThreadError Mle::AppendPendingTimestamp(Message &aMessage)
{
ThreadError error;
PendingTimestampTlv timestampTlv;
const MeshCoP::Timestamp &timestamp(mNetif.GetPendingDataset().GetNetwork().GetTimestamp());
VerifyOrExit(timestamp.GetSeconds() != 0, error = kThreadError_None);
timestampTlv.Init();
*static_cast<MeshCoP::Timestamp *>(&timestampTlv) = timestamp;
error = aMessage.Append(&timestampTlv, sizeof(timestampTlv));
exit:
return error;
}
void Mle::HandleNetifStateChanged(uint32_t aFlags, void *aContext)
{
Mle *obj = reinterpret_cast<Mle *>(aContext);
@@ -1066,6 +1105,8 @@ ThreadError Mle::SendChildIdRequest(void)
}
SuccessOrExit(error = AppendTlvRequest(*message, tlvs, sizeof(tlvs)));
SuccessOrExit(error = AppendActiveTimestamp(*message));
SuccessOrExit(error = AppendPendingTimestamp(*message));
memset(&destination, 0, sizeof(destination));
destination.mFields.m16[0] = HostSwap16(0xfe80);
@@ -1098,6 +1139,8 @@ ThreadError Mle::SendDataRequest(const Ip6::Address &aDestination, const uint8_t
message->SetLinkSecurityEnabled(false);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDataRequest));
SuccessOrExit(error = AppendTlvRequest(*message, aTlvs, aTlvsLength));
SuccessOrExit(error = AppendActiveTimestamp(*message));
SuccessOrExit(error = AppendPendingTimestamp(*message));
SuccessOrExit(error = SendMessage(*message, aDestination));
@@ -1113,46 +1156,6 @@ exit:
return error;
}
ThreadError Mle::SendDataResponse(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength)
{
ThreadError error = kThreadError_None;
Message *message;
Neighbor *neighbor;
bool stableOnly;
VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDataResponse));
SuccessOrExit(error = AppendSourceAddress(*message));
SuccessOrExit(error = AppendLeaderData(*message));
neighbor = mMleRouter.GetNeighbor(aDestination);
for (int i = 0; i < aTlvsLength; i++)
{
switch (aTlvs[i])
{
case Tlv::kNetworkData:
stableOnly = neighbor != NULL ? (neighbor->mMode & ModeTlv::kModeFullNetworkData) == 0 : false;
SuccessOrExit(error = AppendNetworkData(*message, stableOnly));
break;
}
}
SuccessOrExit(error = SendMessage(*message, aDestination));
otLogInfoMle("Sent Data Response\n");
exit:
if (error != kThreadError_None && message != NULL)
{
Message::Free(*message);
}
return error;
}
ThreadError Mle::SendChildUpdateRequest(void)
{
ThreadError error = kThreadError_None;
@@ -1486,7 +1489,7 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
break;
case Header::kCommandDataRequest:
HandleDataRequest(aMessage, aMessageInfo);
mMleRouter.HandleDataRequest(aMessage, aMessageInfo);
break;
case Header::kCommandDataResponse:
@@ -1599,33 +1602,20 @@ exit:
return error;
}
ThreadError Mle::HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
TlvRequestTlv tlvRequest;
otLogInfoMle("Received Data Request\n");
// TLV Request
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kTlvRequest, sizeof(tlvRequest), tlvRequest));
VerifyOrExit(tlvRequest.IsValid(), error = kThreadError_Parse);
SendDataResponse(aMessageInfo.GetPeerAddr(), tlvRequest.GetTlvs(), tlvRequest.GetLength());
exit:
return error;
}
ThreadError Mle::HandleDataResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
LeaderDataTlv leaderData;
NetworkDataTlv networkData;
ActiveTimestampTlv activeTimestamp;
PendingTimestampTlv pendingTimestamp;
Tlv tlv;
uint16_t offset;
int8_t diff;
otLogInfoMle("Received Data Response\n");
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkData, sizeof(networkData), networkData));
// Leader Data
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData));
VerifyOrExit(leaderData.IsValid(), error = kThreadError_Parse);
@@ -1651,6 +1641,37 @@ ThreadError Mle::HandleDataResponse(const Message &aMessage, const Ip6::MessageI
VerifyOrExit(diff > 0, ;);
}
// Network Data
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkData, sizeof(networkData), networkData));
VerifyOrExit(networkData.IsValid(), error = kThreadError_Parse);
// Active Timestamp
if (Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp) == kThreadError_None)
{
VerifyOrExit(activeTimestamp.IsValid(), error = kThreadError_Parse);
// Active Dataset
if (Tlv::GetOffset(aMessage, Tlv::kActiveDataset, offset) == kThreadError_None)
{
aMessage.Read(offset, sizeof(tlv), &tlv);
mNetif.GetActiveDataset().Set(activeTimestamp, aMessage, offset + sizeof(tlv), tlv.GetLength());
}
}
// Pending Timestamp
if (Tlv::GetTlv(aMessage, Tlv::kPendingTimestamp, sizeof(pendingTimestamp), pendingTimestamp) == kThreadError_None)
{
VerifyOrExit(pendingTimestamp.IsValid(), error = kThreadError_Parse);
// Pending Dataset
if (Tlv::GetOffset(aMessage, Tlv::kPendingDataset, offset) == kThreadError_None)
{
aMessage.Read(offset, sizeof(tlv), &tlv);
mNetif.GetPendingDataset().Set(activeTimestamp, aMessage, offset + sizeof(tlv), tlv.GetLength());
}
}
// Network Data
mNetworkData.SetNetworkData(leaderData.GetDataVersion(), leaderData.GetStableDataVersion(),
(mDeviceMode & ModeTlv::kModeFullNetworkData) == 0,
networkData.GetNetworkData(), networkData.GetLength());
@@ -1833,6 +1854,10 @@ ThreadError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::Messa
Address16Tlv shortAddress;
NetworkDataTlv networkData;
RouteTlv route;
ActiveTimestampTlv activeTimestamp;
PendingTimestampTlv pendingTimestamp;
Tlv tlv;
uint16_t offset;
uint8_t numRouters = 0;
otLogInfoMle("Received Child ID Response\n");
@@ -1854,6 +1879,32 @@ ThreadError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::Messa
// Network Data
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkData, sizeof(networkData), networkData));
// Active Timestamp
if (Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp) == kThreadError_None)
{
VerifyOrExit(activeTimestamp.IsValid(), error = kThreadError_Parse);
// Active Dataset
if (Tlv::GetOffset(aMessage, Tlv::kActiveDataset, offset) == kThreadError_None)
{
aMessage.Read(offset, sizeof(tlv), &tlv);
mNetif.GetActiveDataset().Set(activeTimestamp, aMessage, offset + sizeof(tlv), tlv.GetLength());
}
}
// Pending Timestamp
if (Tlv::GetTlv(aMessage, Tlv::kPendingTimestamp, sizeof(pendingTimestamp), pendingTimestamp) == kThreadError_None)
{
VerifyOrExit(pendingTimestamp.IsValid(), error = kThreadError_Parse);
// Pending Dataset
if (Tlv::GetOffset(aMessage, Tlv::kPendingDataset, offset) == kThreadError_None)
{
aMessage.Read(offset, sizeof(tlv), &tlv);
mNetif.GetPendingDataset().Set(pendingTimestamp, aMessage, offset + sizeof(tlv), tlv.GetLength());
}
}
// Parent Attach Success
mParentRequestTimer.Stop();
@@ -1876,6 +1927,8 @@ ThreadError Mle::HandleChildIdResponse(const Message &aMessage, const Ip6::Messa
(mDeviceMode & ModeTlv::kModeFullNetworkData) == 0,
networkData.GetNetworkData(), networkData.GetLength());
mNetif.GetActiveDataset().ApplyConfiguration();
// Route
if ((Tlv::GetTlv(aMessage, Tlv::kRoute, sizeof(route), route) == kThreadError_None) &&
(mDeviceMode & ModeTlv::kModeFFD))
+31 -14
View File
@@ -446,6 +446,15 @@ public:
*/
ThreadError BecomeChild(otMleAttachFilter aFilter);
/**
* This method indicates whether or not the Thread device is attached to a Thread network.
*
* @retval TRUE Attached to a Thread network.
* @retval FALSE Not attached to a Thread network.
*
*/
bool IsAttached(void) const;
/**
* This method returns the current Thread interface state.
*
@@ -857,6 +866,28 @@ protected:
*/
ThreadError AppendAddressRegistration(Message &aMessage);
/**
* This method appends a Active Timestamp TLV to a message.
*
* @param[in] aMessage A reference to the message.
*
* @retval kThreadError_None Successfully appended the Active Timestamp TLV.
* @retval kThreadError_NoBufs Insufficient buffers available to append the Active Timestamp TLV.
*
*/
ThreadError AppendActiveTimestamp(Message &aMessage);
/**
* This method appends a Pending Timestamp TLV to a message.
*
* @param[in] aMessage A reference to the message.
*
* @retval kThreadError_None Successfully appended the Pending Timestamp TLV.
* @retval kThreadError_NoBufs Insufficient buffers available to append the Pending Timestamp TLV.
*
*/
ThreadError AppendPendingTimestamp(Message &aMessage);
/**
* This method appends a Thread Discovery TLV to a message.
*
@@ -944,19 +975,6 @@ protected:
*/
ThreadError SendDataRequest(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength);
/**
* This method generates an MLE Data Response message.
*
* @param[in] aDestination A reference to the IPv6 address of the destination.
* @param[in] aTlvs A pointer to TLV types that should be included.
* @param[in] aTlvsLength The number of TLV types in @p aTlvs.
*
* @retval kThreadError_None Successfully generated an MLE Data Response message.
* @retval kThreadError_NoBufs Insufficient buffers to generate the MLE Data Response message.
*
*/
ThreadError SendDataResponse(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength);
/**
* This method generates an MLE Child Update Request message.
*
@@ -1065,7 +1083,6 @@ private:
ThreadError HandleAdvertisement(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleChildIdResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleChildUpdateResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleDataResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleParentResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
uint32_t aKeySequence);
+171 -5
View File
@@ -359,6 +359,8 @@ ThreadError MleRouter::SetStateLeader(uint16_t aRloc16)
mRouters[mRouterId].mLastHeard = Timer::GetNow();
mNetworkData.Start();
mNetif.GetActiveDataset().ApplyLocalToNetwork();
mNetif.GetPendingDataset().ApplyLocalToNetwork();
mCoapServer.AddResource(mAddressSolicit);
mCoapServer.AddResource(mAddressRelease);
@@ -1734,7 +1736,10 @@ ThreadError MleRouter::HandleChildIdRequest(const Message &aMessage, const Ip6::
TimeoutTlv timeout;
AddressRegistrationTlv address;
TlvRequestTlv tlvRequest;
ActiveTimestampTlv activeTimestamp;
PendingTimestampTlv pendingTimestamp;
Child *child;
uint8_t numTlvs;
otLogInfoMle("Received Child ID Request\n");
@@ -1783,7 +1788,24 @@ ThreadError MleRouter::HandleChildIdRequest(const Message &aMessage, const Ip6::
// TLV Request
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kTlvRequest, sizeof(tlvRequest), tlvRequest));
VerifyOrExit(tlvRequest.IsValid(), error = kThreadError_Parse);
VerifyOrExit(tlvRequest.IsValid() && tlvRequest.GetLength() <= sizeof(child->mRequestTlvs),
error = kThreadError_Parse);
// Active Timestamp
activeTimestamp.SetLength(0);
if (Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp) == kThreadError_None)
{
VerifyOrExit(activeTimestamp.IsValid(), error = kThreadError_Parse);
}
// Pending Timestamp
pendingTimestamp.SetLength(0);
if (Tlv::GetTlv(aMessage, Tlv::kPendingTimestamp, sizeof(pendingTimestamp), pendingTimestamp) == kThreadError_None)
{
VerifyOrExit(pendingTimestamp.IsValid(), error = kThreadError_Parse);
}
// Remove from router table
for (int i = 0; i < kMaxRouterId; i++)
@@ -1816,14 +1838,20 @@ ThreadError MleRouter::HandleChildIdRequest(const Message &aMessage, const Ip6::
UpdateChildAddresses(address, *child);
for (uint8_t i = 0; i < tlvRequest.GetLength(); i++)
memset(child->mRequestTlvs, Tlv::kInvalid, sizeof(child->mRequestTlvs));
memcpy(child->mRequestTlvs, tlvRequest.GetTlvs(), tlvRequest.GetLength());
numTlvs = tlvRequest.GetLength();
if (activeTimestamp.GetLength() == 0 ||
mNetif.GetActiveDataset().GetNetwork().GetTimestamp().Compare(activeTimestamp) != 0)
{
child->mRequestTlvs[i] = tlvRequest.GetTlvs()[i];
child->mRequestTlvs[numTlvs++] = Tlv::kActiveDataset;
}
for (uint8_t i = tlvRequest.GetLength(); i < sizeof(child->mRequestTlvs); i++)
if (pendingTimestamp.GetLength() == 0 ||
mNetif.GetPendingDataset().GetNetwork().GetTimestamp().Compare(pendingTimestamp) != 0)
{
child->mRequestTlvs[i] = Tlv::kInvalid;
child->mRequestTlvs[numTlvs++] = Tlv::kPendingDataset;
}
switch (GetDeviceState())
@@ -1929,6 +1957,54 @@ exit:
return error;
}
ThreadError MleRouter::HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
TlvRequestTlv tlvRequest;
ActiveTimestampTlv activeTimestamp;
PendingTimestampTlv pendingTimestamp;
uint8_t tlvs[4];
uint8_t numTlvs;
otLogInfoMle("Received Data Request\n");
// TLV Request
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kTlvRequest, sizeof(tlvRequest), tlvRequest));
VerifyOrExit(tlvRequest.IsValid() && tlvRequest.GetLength() <= sizeof(tlvs), error = kThreadError_Parse);
// Active Timestamp
SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp));
VerifyOrExit(activeTimestamp.IsValid(), error = kThreadError_Parse);
// Pending Timestamp
pendingTimestamp.SetLength(0);
if (Tlv::GetTlv(aMessage, Tlv::kPendingTimestamp, sizeof(pendingTimestamp), pendingTimestamp) == kThreadError_None)
{
VerifyOrExit(pendingTimestamp.IsValid(), error = kThreadError_Parse);
}
memset(tlvs, Tlv::kInvalid, sizeof(tlvs));
memcpy(tlvs, tlvRequest.GetTlvs(), tlvRequest.GetLength());
numTlvs = tlvRequest.GetLength();
if (mNetif.GetActiveDataset().GetNetwork().GetTimestamp().Compare(activeTimestamp) != 0)
{
tlvs[numTlvs++] = Tlv::kActiveDataset;
}
if (pendingTimestamp.GetLength() == 0 ||
mNetif.GetPendingDataset().GetNetwork().GetTimestamp().Compare(pendingTimestamp) != 0)
{
tlvs[numTlvs++] = Tlv::kPendingDataset;
}
SendDataResponse(aMessageInfo.GetPeerAddr(), tlvs, numTlvs);
exit:
return error;
}
ThreadError MleRouter::HandleNetworkDataUpdateRouter(void)
{
static const uint8_t tlvs[] = {Tlv::kLeaderData, Tlv::kNetworkData};
@@ -1986,6 +2062,14 @@ ThreadError MleRouter::SendChildIdResponse(Child *aChild)
case Tlv::kRoute:
SuccessOrExit(error = AppendRoute(*message));
break;
case Tlv::kActiveDataset:
SuccessOrExit(error = AppendActiveDataset(*message));
break;
case Tlv::kPendingDataset:
SuccessOrExit(error = AppendPendingDataset(*message));
break;
}
}
@@ -2073,6 +2157,55 @@ exit:
return kThreadError_None;
}
ThreadError MleRouter::SendDataResponse(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength)
{
ThreadError error = kThreadError_None;
Message *message;
Neighbor *neighbor;
bool stableOnly;
VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDataResponse));
SuccessOrExit(error = AppendSourceAddress(*message));
SuccessOrExit(error = AppendLeaderData(*message));
SuccessOrExit(error = AppendActiveTimestamp(*message));
SuccessOrExit(error = AppendPendingTimestamp(*message));
for (int i = 0; i < aTlvsLength; i++)
{
switch (aTlvs[i])
{
case Tlv::kNetworkData:
neighbor = mMleRouter.GetNeighbor(aDestination);
stableOnly = neighbor != NULL ? (neighbor->mMode & ModeTlv::kModeFullNetworkData) == 0 : false;
SuccessOrExit(error = AppendNetworkData(*message, stableOnly));
break;
case Tlv::kActiveDataset:
SuccessOrExit(error = AppendActiveDataset(*message));
break;
case Tlv::kPendingDataset:
SuccessOrExit(error = AppendPendingDataset(*message));
break;
}
}
SuccessOrExit(error = SendMessage(*message, aDestination));
otLogInfoMle("Sent Data Response\n");
exit:
if (error != kThreadError_None && message != NULL)
{
Message::Free(*message);
}
return error;
}
Child *MleRouter::GetChild(uint16_t aAddress)
{
for (int i = 0; i < kMaxChildren; i++)
@@ -3177,5 +3310,38 @@ exit:
return error;
}
ThreadError MleRouter::AppendActiveDataset(Message &aMessage)
{
ThreadError error = kThreadError_None;
Tlv tlv;
SuccessOrExit(error = AppendActiveTimestamp(aMessage));
tlv.SetType(Tlv::kActiveDataset);
tlv.SetLength(mNetif.GetActiveDataset().GetNetwork().GetSize());
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(tlv)));
SuccessOrExit(error = aMessage.Append(mNetif.GetActiveDataset().GetNetwork().GetBytes(), tlv.GetLength()));
exit:
return error;
}
ThreadError MleRouter::AppendPendingDataset(Message &aMessage)
{
ThreadError error = kThreadError_None;
Tlv tlv;
SuccessOrExit(error = AppendPendingTimestamp(aMessage));
tlv.SetType(Tlv::kPendingDataset);
tlv.SetLength(mNetif.GetPendingDataset().GetNetwork().GetSize());
SuccessOrExit(error = aMessage.Append(&tlv, sizeof(tlv)));
mNetif.GetPendingDataset().UpdateDelayTimer();
SuccessOrExit(error = aMessage.Append(mNetif.GetPendingDataset().GetNetwork().GetBytes(), tlv.GetLength()));
exit:
return error;
}
} // namespace Mle
} // namespace Thread
+5
View File
@@ -404,6 +404,8 @@ private:
ThreadError AppendConnectivity(Message &aMessage);
ThreadError AppendChildAddresses(Message &aMessage, Child &aChild);
ThreadError AppendRoute(Message &aMessage);
ThreadError AppendActiveDataset(Message &aMessage);
ThreadError AppendPendingDataset(Message &aMessage);
uint8_t GetLinkCost(uint8_t aRouterId);
void GetChildInfo(Child &aChild, otChildInfo &aChildInfo);
ThreadError HandleDetachStart(void);
@@ -420,6 +422,7 @@ private:
ThreadError HandleChildIdRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
uint32_t aKeySequence);
ThreadError HandleChildUpdateRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleDataRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleNetworkDataUpdateRouter(void);
bool IsSingleton(void);
@@ -437,6 +440,8 @@ private:
ThreadError SendChildIdResponse(Child *aChild);
ThreadError SendChildUpdateResponse(Child *aChild, const Ip6::MessageInfo &aMessageInfo,
const uint8_t *aTlvs, uint8_t aTlvsLength, const ChallengeTlv *challenge);
ThreadError SendDataResponse(const Ip6::Address &aDestination, const uint8_t *aTlvs, uint8_t aTlvsLength);
ThreadError SetStateRouter(uint16_t aRloc16);
ThreadError SetStateLeader(uint16_t aRloc16);
ThreadError UpdateChildAddresses(const AddressRegistrationTlv &aTlv, Child &aChild);
+24 -10
View File
@@ -39,28 +39,42 @@ namespace Thread {
namespace Mle {
ThreadError Tlv::GetTlv(const Message &aMessage, Type aType, uint16_t aMaxLength, Tlv &aTlv)
{
ThreadError error = kThreadError_Parse;
uint16_t offset;
SuccessOrExit(error = GetOffset(aMessage, aType, offset));
aMessage.Read(offset, sizeof(Tlv), &aTlv);
if (aMaxLength > sizeof(aTlv) + aTlv.GetLength())
{
aMaxLength = sizeof(aTlv) + aTlv.GetLength();
}
aMessage.Read(offset, aMaxLength, &aTlv);
exit:
return error;
}
ThreadError Tlv::GetOffset(const Message &aMessage, Type aType, uint16_t &aOffset)
{
ThreadError error = kThreadError_Parse;
uint16_t offset = aMessage.GetOffset();
uint16_t end = aMessage.GetLength();
Tlv tlv;
while (offset < end)
{
aMessage.Read(offset, sizeof(Tlv), &aTlv);
aMessage.Read(offset, sizeof(Tlv), &tlv);
if (aTlv.GetType() == aType && (offset + sizeof(aTlv) + aTlv.GetLength()) <= end)
if (tlv.GetType() == aType && (offset + sizeof(tlv) + tlv.GetLength()) <= end)
{
if (aMaxLength > sizeof(aTlv) + aTlv.GetLength())
{
aMaxLength = sizeof(aTlv) + aTlv.GetLength();
}
aMessage.Read(offset, aMaxLength, &aTlv);
aOffset = offset;
ExitNow(error = kThreadError_None);
}
offset += sizeof(aTlv) + aTlv.GetLength();
offset += sizeof(tlv) + tlv.GetLength();
}
exit:
+66
View File
@@ -40,6 +40,7 @@
#include <common/encoding.hpp>
#include <common/message.hpp>
#include <net/ip6_address.hpp>
#include <thread/meshcop_tlvs.hpp>
#include <thread/mle_constants.hpp>
using Thread::Encoding::BigEndian::HostSwap16;
@@ -93,6 +94,10 @@ public:
kStatus = 17, ///< Status TLV
kVersion = 18, ///< Version TLV
kAddressRegistration = 19, ///< Address Registration TLV
kActiveTimestamp = 22, ///< Active Timestamp TLV
kPendingTimestamp = 23, ///< Pending Timestamp TLV
kActiveDataset = 24, ///< Active Operational Dataset TLV
kPendingDataset = 25, ///< Pending Operational Dataset TLV
kDiscovery = 26, ///< Thread Discovery TLV
kInvalid = 255,
};
@@ -141,6 +146,19 @@ public:
*/
static ThreadError GetTlv(const Message &aMessage, Type aType, uint16_t aMaxLength, Tlv &aTlv);
/**
* This static method obtains the offset of a TLV within @p aMessage.
*
* @param[in] aMessage A reference to the message.
* @param[in] aType The Type value to search for.
* @param[out] aOffset A reference to the offset of the TLV.
*
* @retval kThreadError_None Successfully copied the TLV.
* @retval kThreadError_NotFound Could not find the TLV with Type @p aType.
*
*/
static ThreadError GetOffset(const Message &aMessage, Type aType, uint16_t &aOffset);
private:
uint8_t mType;
uint8_t mLength;
@@ -1429,6 +1447,54 @@ private:
AddressRegistrationEntry mAddresses[4];
} OT_TOOL_PACKED_END;
/**
* This class implements Active Timestamp TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ActiveTimestampTlv : public Tlv, public MeshCoP::Timestamp
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(Mle::Tlv::kActiveTimestamp); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
} OT_TOOL_PACKED_END;
/**
* This class implements Pending Timestamp TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class PendingTimestampTlv : public Tlv, public MeshCoP::Timestamp
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(Mle::Tlv::kPendingTimestamp); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
} OT_TOOL_PACKED_END;
/**
* @}
*
+16
View File
@@ -86,11 +86,27 @@ uint8_t Leader::GetVersion(void) const
return mVersion;
}
void Leader::IncrementVersion(void)
{
if (mMle.GetDeviceState() == Mle::kDeviceStateLeader)
{
mVersion++;
}
}
uint8_t Leader::GetStableVersion(void) const
{
return mStableVersion;
}
void Leader::IncrementStableVersion(void)
{
if (mMle.GetDeviceState() == Mle::kDeviceStateLeader)
{
mStableVersion++;
}
}
uint32_t Leader::GetContextIdReuseDelay(void) const
{
return mContextIdReuseDelay;
+13 -1
View File
@@ -99,6 +99,12 @@ public:
*/
uint8_t GetVersion(void) const;
/**
* This method increments the Thread Network Data version.
*
*/
void IncrementVersion(void);
/**
* This method returns the Thread Network Data stable version.
*
@@ -107,6 +113,12 @@ public:
*/
uint8_t GetStableVersion(void) const;
/**
* This method increments the Thread Network Data stable version.
*
*/
void IncrementStableVersion(void);
/**
* This method returns CONTEXT_ID_RESUSE_DELAY value.
*
@@ -258,7 +270,7 @@ private:
uint8_t mVersion;
Coap::Server &mCoapServer;
Ip6::Netif &mNetif;
ThreadNetif &mNetif;
Mle::MleRouter &mMle;
};
+3
View File
@@ -40,6 +40,7 @@
#include <thread/mle.hpp>
#include <thread/thread_netif.hpp>
#include <thread/thread_tlvs.hpp>
#include <thread/thread_uris.hpp>
using Thread::Encoding::BigEndian::HostSwap16;
@@ -56,6 +57,8 @@ static const char name[] = "thread";
ThreadNetif::ThreadNetif(void):
mCoapServer(kCoapUdpPort),
mAddressResolver(*this),
mActiveDataset(*this),
mPendingDataset(*this),
mKeyManager(*this),
mLowpan(*this),
mMac(*this),
+7
View File
@@ -40,6 +40,7 @@
#include <net/netif.hpp>
#include <thread/address_resolver.hpp>
#include <thread/key_manager.hpp>
#include <thread/meshcop_dataset_manager.hpp>
#include <thread/mesh_forwarder.hpp>
#include <thread/mle.hpp>
#include <thread/mle_router.hpp>
@@ -205,9 +206,15 @@ public:
*/
NetworkData::Leader &GetNetworkDataLeader(void) { return mNetworkDataLeader; }
MeshCoP::ActiveDataset &GetActiveDataset(void) { return mActiveDataset; }
MeshCoP::PendingDataset &GetPendingDataset(void) { return mPendingDataset; }
private:
Coap::Server mCoapServer;
AddressResolver mAddressResolver;
MeshCoP::ActiveDataset mActiveDataset;
MeshCoP::PendingDataset mPendingDataset;
Ip6::Filter mIp6Filter;
KeyManager mKeyManager;
Lowpan::Lowpan mLowpan;
+16
View File
@@ -74,6 +74,22 @@ namespace Thread {
*/
#define OPENTHREAD_URI_ADDRESS_SOLICIT "a/as"
/**
* @def OPENTHREAD_URI_ACTIVE_SET
*
* The URI Path for MGMT_ACTIVE_SET
*
*/
#define OPENTHREAD_URI_ACTIVE_SET "c/as"
/**
* @def OPENTHREAD_URI_PENDING_SET
*
* The URI Path for MGMT_PENDING_SET
*
*/
#define OPENTHREAD_URI_PENDING_SET "c/ps"
/**
* @def OPENTHREAD_URI_SERVER_DATA
*
+1 -1
View File
@@ -101,7 +101,7 @@ public:
Ip6::Address mIp6Address[kMaxIp6AddressPerChild]; ///< Registered IPv6 addresses
uint32_t mTimeout; ///< Child timeout
uint16_t mFragmentOffset; ///< 6LoWPAN fragment offset
uint8_t mRequestTlvs[4]; ///< Requested MLE TLVs
uint8_t mRequestTlvs[5]; ///< Requested MLE TLVs
uint8_t mNetworkDataVersion; ///< Current Network Data version
};