MLE Announce. (#736)

This commit is contained in:
Jonathan Hui
2016-10-04 10:26:30 -07:00
committed by GitHub
parent 933ce83999
commit 671964c2d4
26 changed files with 1153 additions and 105 deletions
+4
View File
@@ -35,6 +35,7 @@
<ClCompile Include="..\..\src\core\mac\mac_blacklist.cpp" />
<ClCompile Include="..\..\src\core\mac\mac_frame.cpp" />
<ClCompile Include="..\..\src\core\mac\mac_whitelist.cpp" />
<ClCompile Include="..\..\src\core\meshcop\announce_begin_client.cpp" />
<ClCompile Include="..\..\src\core\meshcop\commissioner.cpp" />
<ClCompile Include="..\..\src\core\meshcop\dtls.cpp" />
<ClCompile Include="..\..\src\core\meshcop\energy_scan_client.cpp" />
@@ -52,6 +53,7 @@
<ClCompile Include="..\..\src\core\net\udp6.cpp" />
<ClCompile Include="..\..\src\core\openthread.cpp" />
<ClCompile Include="..\..\src\core\thread\address_resolver.cpp" />
<ClCompile Include="..\..\src\core\thread\announce_begin_server.cpp" />
<ClCompile Include="..\..\src\core\thread\energy_scan_server.cpp" />
<ClCompile Include="..\..\src\core\thread\key_manager.cpp" />
<ClCompile Include="..\..\src\core\thread\link_quality.cpp" />
@@ -94,6 +96,7 @@
<ClInclude Include="..\..\src\core\mac\mac_blacklist.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_frame.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_whitelist.hpp" />
<ClInclude Include="..\..\src\core\meshcop\announce_begin_client.hpp" />
<ClInclude Include="..\..\src\core\meshcop\commissioner.hpp" />
<ClInclude Include="..\..\src\core\meshcop\dtls.hpp" />
<ClInclude Include="..\..\src\core\meshcop\energy_scan_client.hpp" />
@@ -113,6 +116,7 @@
<ClInclude Include="..\..\src\core\openthread-core-config.h" />
<ClInclude Include="..\..\src\core\openthreadcontext.h" />
<ClInclude Include="..\..\src\core\thread\address_resolver.hpp" />
<ClInclude Include="..\..\src\core\meshcop\announce_begin_server.hpp" />
<ClInclude Include="..\..\src\core\thread\energy_scan_server.hpp" />
<ClInclude Include="..\..\src\core\thread\key_manager.hpp" />
<ClInclude Include="..\..\src\core\thread\link_quality.hpp" />
@@ -37,6 +37,7 @@
<ClCompile Include="..\..\src\core\mac\mac_whitelist.cpp" />
<ClCompile Include="..\..\src\core\meshcop\commissioner.cpp" />
<ClCompile Include="..\..\src\core\meshcop\dtls.cpp" />
<ClCompile Include="..\..\src\core\meshcop\announce_begin_client.cpp" />
<ClCompile Include="..\..\src\core\meshcop\energy_scan_client.cpp" />
<ClCompile Include="..\..\src\core\meshcop\joiner.cpp" />
<ClCompile Include="..\..\src\core\meshcop\joiner_router.cpp" />
@@ -52,6 +53,7 @@
<ClCompile Include="..\..\src\core\net\udp6.cpp" />
<ClCompile Include="..\..\src\core\openthread.cpp" />
<ClCompile Include="..\..\src\core\thread\address_resolver.cpp" />
<ClCompile Include="..\..\src\core\thread\announce_begin_server.cpp" />
<ClCompile Include="..\..\src\core\thread\energy_scan_server.cpp" />
<ClCompile Include="..\..\src\core\thread\key_manager.cpp" />
<ClCompile Include="..\..\src\core\thread\link_quality.cpp" />
@@ -94,6 +96,7 @@
<ClInclude Include="..\..\src\core\mac\mac_blacklist.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_frame.hpp" />
<ClInclude Include="..\..\src\core\mac\mac_whitelist.hpp" />
<ClInclude Include="..\..\src\core\meshcop\announce_begin_client.hpp" />
<ClInclude Include="..\..\src\core\meshcop\commissioner.hpp" />
<ClInclude Include="..\..\src\core\meshcop\dtls.hpp" />
<ClInclude Include="..\..\src\core\meshcop\energy_scan_client.hpp" />
@@ -113,6 +116,7 @@
<ClInclude Include="..\..\src\core\openthread-core-config.h" />
<ClInclude Include="..\..\src\core\openthreadcontext.h" />
<ClInclude Include="..\..\src\core\thread\address_resolver.hpp" />
<ClInclude Include="..\..\src\core\meshcop\announce_begin_server.hpp" />
<ClInclude Include="..\..\src\core\thread\energy_scan_server.hpp" />
<ClInclude Include="..\..\src\core\thread\key_manager.hpp" />
<ClInclude Include="..\..\src\core\thread\link_quality.hpp" />
+16
View File
@@ -104,6 +104,22 @@ ThreadError otCommissionerRemoveJoiner(otInstance *aIntsance, const otExtAddress
*/
ThreadError otCommissionerSetProvisioningUrl(otInstance *aInstance, const char *aProvisioningUrl);
/**
* This function sends an Announce Begin message.
*
* @param[in] aInstance A pointer to an OpenThread instance.
* @param[in] aChannelMask The channel mask value.
* @param[in] aCount The number of energy measurements per channel.
* @param[in] aPeriod The time between energy measurements (milliseconds).
* @param[in] aAddress A pointer to the IPv6 destination.
*
* @retval kThreadError_None Successfully enqueued the Announce Begin message.
* @retval kThreadError_NoBufs Insufficient buffers to generate an Announce Begin message.
*
*/
ThreadError otCommissionerAnnounceBegin(otInstance *aInstance, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
const otIp6Address *aAddress);
/**
* This function pointer is called when the Commissioner receives an Energy Report.
*
+27
View File
@@ -2029,6 +2029,33 @@ void Interpreter::ProcessCommissioner(int argc, char *argv[])
{
SuccessOrExit(error = otCommissionerSetProvisioningUrl(mInstance, (argc > 1) ? argv[1] : NULL));
}
else if (strcmp(argv[0], "announce") == 0)
{
long mask;
long count;
long period;
otIp6Address address;
VerifyOrExit(argc > 4, error = kThreadError_Parse);
// mask
SuccessOrExit(error = ParseLong(argv[1], mask));
// count
SuccessOrExit(error = ParseLong(argv[2], count));
// period
SuccessOrExit(error = ParseLong(argv[3], period));
// destination
SuccessOrExit(error = otIp6AddressFromString(argv[4], &address));
SuccessOrExit(error = otCommissionerAnnounceBegin(mInstance,
static_cast<uint32_t>(mask),
static_cast<uint8_t>(count),
static_cast<uint16_t>(period),
&address));
}
else if (strcmp(argv[0], "energy") == 0)
{
long mask;
+4
View File
@@ -64,6 +64,7 @@ libopenthread_a_SOURCES = \
net/netif.cpp \
net/udp6.cpp \
thread/address_resolver.cpp \
thread/announce_begin_server.cpp \
thread/energy_scan_server.cpp \
thread/key_manager.cpp \
thread/link_quality.cpp \
@@ -88,6 +89,7 @@ libopenthread_a_SOURCES = \
if OPENTHREAD_ENABLE_COMMISSIONER
libopenthread_a_SOURCES += \
meshcop/announce_begin_client.cpp \
meshcop/commissioner.cpp \
meshcop/energy_scan_client.cpp \
meshcop/panid_query_client.cpp \
@@ -129,6 +131,7 @@ noinst_HEADERS = \
mac/mac_frame.hpp \
mac/mac_whitelist.hpp \
mac/mac_blacklist.hpp \
meshcop/announce_begin_client.hpp \
meshcop/commissioner.hpp \
meshcop/dtls.hpp \
meshcop/energy_scan_client.hpp \
@@ -148,6 +151,7 @@ noinst_HEADERS = \
net/udp6.hpp \
net/tcp.hpp \
thread/address_resolver.hpp \
thread/announce_begin_server.hpp \
thread/energy_scan_server.hpp \
thread/key_manager.hpp \
thread/link_quality.hpp \
+20 -30
View File
@@ -238,6 +238,16 @@ void Message::SetType(uint8_t aType)
mInfo.mType = aType;
}
uint8_t Message::GetSubType(void) const
{
return mInfo.mSubType;
}
void Message::SetSubType(uint8_t aSubType)
{
mInfo.mSubType = aSubType;
}
ThreadError Message::Append(const void *aBuf, uint16_t aLength)
{
ThreadError error = kThreadError_None;
@@ -498,6 +508,16 @@ void Message::SetPanId(uint16_t aPanId)
mInfo.mPanId = aPanId;
}
uint8_t Message::GetChannel(void) const
{
return mInfo.mChannel;
}
void Message::SetChannel(uint8_t aChannel)
{
mInfo.mChannel = aChannel;
}
uint8_t Message::GetTimeout(void) const
{
return mInfo.mTimeout;
@@ -543,36 +563,6 @@ void Message::SetLinkSecurityEnabled(bool aLinkSecurityEnabled)
mInfo.mLinkSecurity = aLinkSecurityEnabled;
}
bool Message::IsMleDiscoverRequest(void) const
{
return mInfo.mMleDiscoverRequest;
}
void Message::SetMleDiscoverRequest(bool aMleDiscoverRequest)
{
mInfo.mMleDiscoverRequest = aMleDiscoverRequest;
}
bool Message::IsMleDiscoverResponse(void) const
{
return mInfo.mMleDiscoverResponse;
}
void Message::SetMleDiscoverResponse(bool aMleDiscoverResponse)
{
mInfo.mMleDiscoverResponse = aMleDiscoverResponse;
}
bool Message::IsJoinerEntrust(void) const
{
return mInfo.mJoinerEntrust;
}
void Message::SetJoinerEntrust(bool aJoinerEntrust)
{
mInfo.mJoinerEntrust = aJoinerEntrust;
}
uint16_t Message::UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const
{
Buffer *curBuffer;
+55 -55
View File
@@ -118,16 +118,18 @@ struct MessageInfo
uint16_t mDatagramTag; ///< The datagram tag used for 6LoWPAN fragmentation.
uint8_t mChildMask[8]; ///< A bit-vector to indicate which sleepy children need to receive this.
uint16_t mPanId; ///< The Destination PAN ID.
uint8_t mTimeout; ///< Seconds remaining before dropping the message.
int8_t mInterfaceId; ///< The interface ID.
union
{
uint16_t mPanId; ///< Used for MLE Discover Request and Response messages.
uint8_t mChannel; ///< Used for MLE Announce.
};
uint8_t mType : 2; ///< Identifies the type of message.
uint8_t mSubType : 3; ///< Identifies the message sub type.
bool mDirectTx : 1; ///< Used to indicate whether a direct transmission is required.
bool mLinkSecurity : 1; ///< Indicates whether or not link security is enabled.
bool mMleDiscoverRequest : 1; ///< Identifies MLE Discover Request.
bool mMleDiscoverResponse : 1; ///< Identifies MLE Discover Response.
bool mJoinerEntrust : 1; ///< Indicates whether or not this message is a Joiner Entrust.
};
/**
@@ -221,6 +223,15 @@ public:
kTypeMacDataPoll = 2, ///< A MAC data poll message
};
enum
{
kSubTypeNone = 0, ///< None
kSubTypeMleAnnounce = 1, ///< MLE Announce
kSubTypeMleDiscoverRequest = 2, ///< MLE Discover Request
kSubTypeMleDiscoverResponse = 3, ///< MLE Discover Response
kSubTypeJoinerEntrust = 4, ///< Joiner Entrust
};
/**
* This method frees this message buffer.
*
@@ -292,6 +303,22 @@ public:
*/
uint8_t GetType(void) const;
/**
* This method returns the sub type of the message.
*
* @returns The sub type of the message.
*
*/
uint8_t GetSubType(void) const;
/**
* This method sets the message sub type.
*
* @param[in] aSubType The message sub type.
*
*/
void SetSubType(uint8_t aSubType);
/**
* This method prepends bytes to the front of the message.
*
@@ -412,6 +439,8 @@ public:
/**
* This method returns the IEEE 802.15.4 Destination PAN ID.
*
* @note Only use this when sending MLE Discover Request or Response messages.
*
* @returns The IEEE 802.15.4 Destination PAN ID.
*
*/
@@ -420,11 +449,33 @@ public:
/**
* This method sets the IEEE 802.15.4 Destination PAN ID.
*
* @note Only use this when sending MLE Discover Request or Response messages.
*
* @param[in] aPanId The IEEE 802.15.4 Destination PAN ID.
*
*/
void SetPanId(uint16_t aPanId);
/**
* This method returns the IEEE 802.15.4 Channel to use for transmission.
*
* @note Only use this when sending MLE Announce messages.
*
* @returns The IEEE 802.15.4 Channel to use for transmission.
*
*/
uint8_t GetChannel(void) const;
/**
* This method sets the IEEE 802.15.4 Channel to use for transmission.
*
* @note Only use this when sending MLE Announce messages.
*
* @param[in] aChannel The IEEE 802.15.4 Channel to use for transmission.
*
*/
void SetChannel(uint8_t aChannel);
/**
* This method returns the timeout used for 6LoWPAN reassembly.
*
@@ -495,57 +546,6 @@ public:
*/
void SetLinkSecurityEnabled(bool aLinkSecurityEnabled);
/**
* This method indicates whether or not this message is an MLE Discovery Request.
*
* @retval TRUE If this message is an MLE Discovery Request.
* @retval FALSE If this message is not an MLE Discovery Request.
*
*/
bool IsMleDiscoverRequest(void) const;
/**
* This method sets whether or not this message is an MLE Discovery Request.
*
* @param[in] aLinkSecurityEnabled TRUE if this message is an MLE Discovery Request, FALSE otherwise.
*
*/
void SetMleDiscoverRequest(bool aMleDiscoverRequest);
/**
* This method indicates whether or not this message is an MLE Discovery Response.
*
* @retval TRUE If this message is an MLE Discovery Response.
* @retval FALSE If this message is not an MLE Discovery Response.
*
*/
bool IsMleDiscoverResponse(void) const;
/**
* This method sets whether or not this message is an MLE Discovery Response.
*
* @param[in] aLinkSecurityEnabled TRUE if this message is an MLE Discovery Response, FALSE otherwise.
*
*/
void SetMleDiscoverResponse(bool aMleDiscoverResponse);
/**
* This method indicates whether or not this message is an Joiner Entrust.
*
* @retval TRUE If this message is an Joiner Entrust.
* @retval FALSE If this message is not an Joiner Entrust.
*
*/
bool IsJoinerEntrust(void) const;
/**
* This method sets whether or not this message is an Joiner Entrust.
*
* @param[in] aLinkSecurityEnabled TRUE if this message is an Joiner Entrust, FALSE otherwise.
*
*/
void SetJoinerEntrust(bool aJoinerEntrust);
/**
* This method is used to update a checksum value.
*
+31 -2
View File
@@ -55,6 +55,16 @@
namespace Thread {
namespace Mac {
static const uint8_t sMode2Key[] =
{
0x78, 0x58, 0x16, 0x86, 0xfd, 0xb4, 0x58, 0x0f, 0xb0, 0x92, 0x54, 0x6a, 0xec, 0xbd, 0x15, 0x66
};
static const otExtAddress sMode2ExtAddress =
{
{ 0x35, 0x06, 0xfe, 0xb8, 0x23, 0xd4, 0x87, 0x12 },
};
static const uint8_t sExtendedPanidInit[] = {0xde, 0xad, 0x00, 0xbe, 0xef, 0x00, 0xca, 0xfe};
static const char sNetworkNameInit[] = "OpenThread";
static Mac *sMac;
@@ -561,6 +571,7 @@ void Mac::ProcessTransmitSecurity(Frame &aFrame)
uint8_t tagLength;
Crypto::AesCcm aesCcm;
const uint8_t *key = NULL;
const ExtAddress *extAddress = NULL;
if (aFrame.GetSecurityEnabled() == false)
{
@@ -574,6 +585,7 @@ void Mac::ProcessTransmitSecurity(Frame &aFrame)
case Frame::kKeyIdMode0:
key = mKeyManager.GetKek();
frameCounter = mKeyManager.GetKekFrameCounter();
extAddress = &mExtAddress;
break;
case Frame::kKeyIdMode1:
@@ -581,6 +593,14 @@ void Mac::ProcessTransmitSecurity(Frame &aFrame)
frameCounter = mKeyManager.GetMacFrameCounter();
mKeyManager.IncrementMacFrameCounter();
aFrame.SetKeyId((mKeyManager.GetCurrentKeySequence() & 0x7f) + 1);
extAddress = &mExtAddress;
break;
case Frame::kKeyIdMode2:
key = sMode2Key;
frameCounter = 0xffffffff;
aFrame.SetKeyId(0xff);
extAddress = static_cast<const ExtAddress *>(&sMode2ExtAddress);
break;
default:
@@ -591,7 +611,7 @@ void Mac::ProcessTransmitSecurity(Frame &aFrame)
aFrame.GetSecurityLevel(securityLevel);
aFrame.SetFrameCounter(frameCounter);
GenerateNonce(mExtAddress, frameCounter, securityLevel, nonce);
GenerateNonce(*extAddress, frameCounter, securityLevel, nonce);
aesCcm.SetKey(key, 16);
tagLength = aFrame.GetFooterLength() - Frame::kFcsSize;
@@ -915,6 +935,7 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
uint8_t keyid;
uint32_t keySequence = 0;
const uint8_t *macKey;
const ExtAddress *extAddress;
Crypto::AesCcm aesCcm;
aFrame.SetSecurityValid(false);
@@ -934,6 +955,7 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
{
case Frame::kKeyIdMode0:
VerifyOrExit((macKey = mKeyManager.GetKek()) != NULL, error = kThreadError_Security);
extAddress = &aSrcAddr.mExtAddress;
break;
case Frame::kKeyIdMode1:
@@ -970,6 +992,13 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
(frameCounter >= aNeighbor->mValid.mLinkFrameCounter)),
error = kThreadError_Security);
extAddress = &aSrcAddr.mExtAddress;
break;
case Frame::kKeyIdMode2:
macKey = sMode2Key;
extAddress = static_cast<const ExtAddress *>(&sMode2ExtAddress);
break;
default:
@@ -977,7 +1006,7 @@ ThreadError Mac::ProcessReceiveSecurity(Frame &aFrame, const Address &aSrcAddr,
break;
}
GenerateNonce(aSrcAddr.mExtAddress, frameCounter, securityLevel, nonce);
GenerateNonce(*extAddress, frameCounter, securityLevel, nonce);
tagLength = aFrame.GetFooterLength() - Frame::kFcsSize;
aesCcm.SetKey(macKey, 16);
+144
View File
@@ -0,0 +1,144 @@
/*
* 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.
*/
/**
* @file
* This file implements the Announce Begin Client.
*/
#define WPP_NAME "announce_begin_client.tmh"
#ifdef OPENTHREAD_CONFIG_FILE
#include OPENTHREAD_CONFIG_FILE
#else
#include <openthread-config.h>
#endif
#include <coap/coap_header.hpp>
#include <common/code_utils.hpp>
#include <common/debug.hpp>
#include <common/logging.hpp>
#include <platform/random.h>
#include <meshcop/announce_begin_client.hpp>
#include <thread/meshcop_tlvs.hpp>
#include <thread/thread_netif.hpp>
#include <thread/thread_uris.hpp>
namespace Thread {
AnnounceBeginClient::AnnounceBeginClient(ThreadNetif &aThreadNetif) :
mSocket(aThreadNetif.GetIp6().mUdp),
mNetif(aThreadNetif)
{
mSocket.Open(HandleUdpReceive, this);
mCoapMessageId = static_cast<uint8_t>(otPlatRandomGet());
}
ThreadError AnnounceBeginClient::SendRequest(uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
const Ip6::Address &aAddress)
{
ThreadError error = kThreadError_None;
Coap::Header header;
MeshCoP::CommissionerSessionIdTlv sessionId;
OT_TOOL_PACKED_BEGIN
struct
{
MeshCoP::ChannelMaskTlv tlv;
MeshCoP::ChannelMaskEntry header;
uint32_t mask;
} OT_TOOL_PACKED_END channelMask;
MeshCoP::CountTlv count;
MeshCoP::PeriodTlv period;
Ip6::MessageInfo messageInfo;
Message *message;
for (size_t i = 0; i < sizeof(mCoapToken); i++)
{
mCoapToken[i] = static_cast<uint8_t>(otPlatRandomGet());
}
header.Init();
header.SetType(aAddress.IsMulticast() ? Coap::Header::kTypeNonConfirmable : Coap::Header::kTypeConfirmable);
header.SetCode(Coap::Header::kCodePost);
header.SetMessageId(++mCoapMessageId);
header.SetToken(mCoapToken, sizeof(mCoapToken));
header.AppendUriPathOptions(OPENTHREAD_URI_ANNOUNCE_BEGIN);
header.Finalize();
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
sessionId.Init();
sessionId.SetCommissionerSessionId(mNetif.GetCommissioner().GetSessionId());
SuccessOrExit(error = message->Append(&sessionId, sizeof(sessionId)));
channelMask.tlv.Init();
channelMask.tlv.SetLength(sizeof(channelMask.header) + sizeof(channelMask.mask));
channelMask.header.SetChannelPage(0);
channelMask.header.SetMaskLength(sizeof(channelMask.mask));
channelMask.mask = HostSwap32(aChannelMask);
SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask)));
count.Init();
count.SetCount(aCount);
SuccessOrExit(error = message->Append(&count, sizeof(count)));
period.Init();
period.SetPeriod(aPeriod);
SuccessOrExit(error = message->Append(&period, sizeof(period)));
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.GetPeerAddr() = aAddress;
messageInfo.mPeerPort = kCoapUdpPort;
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
otLogInfoMeshCoP("sent announce begin query\r\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void AnnounceBeginClient::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
{
otLogInfoMeshCoP("received announce begin response\r\n");
(void)aContext;
(void)aMessage;
(void)aMessageInfo;
}
} // namespace Thread
@@ -0,0 +1,89 @@
/*
* 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.
*/
/**
* @file
* This file includes definitions for responding to Announce Requests.
*/
#ifndef ANNOUNCE_BEGIN_CLIENT_HPP_
#define ANNOUNCE_BEGIN_CLIENT_HPP_
#include <openthread-core-config.h>
#include <openthread-types.h>
#include <commissioning/commissioner.h>
#include <coap/coap_server.hpp>
#include <net/ip6_address.hpp>
#include <net/udp6.hpp>
namespace Thread {
class ThreadNetif;
/**
* This class implements handling Announce Begin Requests.
*
*/
class AnnounceBeginClient
{
public:
/**
* This constructor initializes the object.
*
*/
AnnounceBeginClient(ThreadNetif &aThreadNetif);
/**
* This method sends a Announce Begin message.
*
* @param[in] aChannelMask The channel mask value.
* @param[in] aCount The number of energy measurements per channel.
* @param[in] aPeriod The time between energy measurements (milliseconds).
*
* @retval kThreadError_None Successfully enqueued the Announce Begin message.
* @retval kThreadError_NoBufs Insufficient buffers to generate a Announce Begin message.
*
*/
ThreadError SendRequest(uint32_t aChannelMask, uint8_t aCount, uint16_t mPeriod, const Ip6::Address &aAddress);
private:
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
Ip6::UdpSocket mSocket;
uint8_t mCoapToken[2];
uint16_t mCoapMessageId;
ThreadNetif &mNetif;
};
/**
* @}
*/
} // namespace Thread
#endif // ANNOUNCE_BEGIN_CLIENT_HPP_
+1
View File
@@ -56,6 +56,7 @@ namespace Thread {
namespace MeshCoP {
Commissioner::Commissioner(ThreadNetif &aThreadNetif):
mAnnounceBegin(aThreadNetif),
mEnergyScan(aThreadNetif),
mPanIdQuery(aThreadNetif),
mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this),
+5 -3
View File
@@ -39,6 +39,7 @@
#include <coap/coap_server.hpp>
#include <common/timer.hpp>
#include <mac/mac_frame.hpp>
#include <meshcop/announce_begin_client.hpp>
#include <meshcop/dtls.hpp>
#include <meshcop/energy_scan_client.hpp>
#include <meshcop/panid_query_client.hpp>
@@ -120,9 +121,6 @@ public:
*/
uint16_t GetSessionId(void) const;
EnergyScanClient mEnergyScan;
PanIdQueryClient mPanIdQuery;
/**
* This method sends MGMT_COMMISSIONER_GET.
*
@@ -149,6 +147,10 @@ public:
ThreadError SendMgmtCommissionerSetRequest(const otCommissioningDataset &aDataset,
const uint8_t *aTlvs, uint8_t aLength);
AnnounceBeginClient mAnnounceBegin;
EnergyScanClient mEnergyScan;
PanIdQueryClient mPanIdQuery;
private:
static void HandleTimer(void *aContext);
void HandleTimer(void);
+1 -1
View File
@@ -340,7 +340,7 @@ ThreadError JoinerRouter::SendJoinerEntrust(const Ip6::MessageInfo &aMessageInfo
Tlv *tlv;
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
message->SetJoinerEntrust(true);
message->SetSubType(Message::kSubTypeJoinerEntrust);
header.Init();
header.SetType(Coap::Header::kTypeConfirmable);
+7
View File
@@ -1445,6 +1445,13 @@ ThreadError otCommissionerSetProvisioningUrl(otInstance *, const char *aProvisio
return sThreadNetif->GetCommissioner().SetProvisioningUrl(aProvisioningUrl);
}
ThreadError otCommissionerAnnounceBegin(otInstance *, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
const otIp6Address *aAddress)
{
return sThreadNetif->GetCommissioner().mAnnounceBegin.SendRequest(aChannelMask, aCount, aPeriod,
*static_cast<const Ip6::Address *>(aAddress));
}
ThreadError otCommissionerEnergyScan(otInstance *, uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod,
uint16_t aScanDuration, const otIp6Address *aAddress,
otCommissionerEnergyReportCallback aCallback, void *aContext)
+193
View File
@@ -0,0 +1,193 @@
/*
* 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.
*/
/**
* @file
* This file implements the Announce Begin Server.
*/
#define WPP_NAME "announce_begin_server.tmh"
#ifdef OPENTHREAD_CONFIG_FILE
#include OPENTHREAD_CONFIG_FILE
#else
#include <openthread-config.h>
#endif
#include <coap/coap_header.hpp>
#include <common/code_utils.hpp>
#include <common/debug.hpp>
#include <common/logging.hpp>
#include <platform/radio.h>
#include <thread/meshcop_tlvs.hpp>
#include <thread/announce_begin_server.hpp>
#include <thread/thread_netif.hpp>
#include <thread/thread_uris.hpp>
using Thread::Encoding::BigEndian::HostSwap32;
namespace Thread {
AnnounceBeginServer::AnnounceBeginServer(ThreadNetif &aThreadNetif) :
mTimer(aThreadNetif.GetIp6().mTimerScheduler, &AnnounceBeginServer::HandleTimer, this),
mAnnounceBegin(OPENTHREAD_URI_ANNOUNCE_BEGIN, &AnnounceBeginServer::HandleRequest, this),
mCoapServer(aThreadNetif.GetCoapServer()),
mNetif(aThreadNetif)
{
mCoapServer.AddResource(mAnnounceBegin);
}
ThreadError AnnounceBeginServer::SendAnnounce(uint32_t aChannelMask)
{
return SendAnnounce(aChannelMask, kDefaultCount, kDefaultPeriod);
}
ThreadError AnnounceBeginServer::SendAnnounce(uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod)
{
ThreadError error = kThreadError_None;
mChannelMask = aChannelMask;
mCount = aCount;
mPeriod = aPeriod;
mChannel = kPhyMinChannel;
while ((mChannelMask & (1 << mChannel)) == 0)
{
mChannel++;
VerifyOrExit(mChannel <= kPhyMaxChannel,);
}
mTimer.Start(mPeriod);
exit:
return error;
}
void AnnounceBeginServer::HandleRequest(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
static_cast<AnnounceBeginServer *>(aContext)->HandleRequest(aHeader, aMessage, aMessageInfo);
}
void AnnounceBeginServer::HandleRequest(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
OT_TOOL_PACKED_BEGIN
struct
{
MeshCoP::ChannelMaskTlv tlv;
MeshCoP::ChannelMaskEntry entry;
uint32_t mask;
} OT_TOOL_PACKED_END channelMask;
MeshCoP::CountTlv count;
MeshCoP::PeriodTlv period;
VerifyOrExit(aHeader.GetCode() == Coap::Header::kCodePost, ;);
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kChannelMask, sizeof(channelMask), channelMask.tlv));
VerifyOrExit(channelMask.tlv.IsValid() &&
channelMask.entry.GetChannelPage() == 0 &&
channelMask.entry.GetMaskLength() == sizeof(uint32_t), ;);
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kCount, sizeof(count), count));
VerifyOrExit(count.IsValid(), ;);
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kPeriod, sizeof(period), period));
VerifyOrExit(period.IsValid(), ;);
SendAnnounce(HostSwap32(channelMask.mask), count.GetCount(), period.GetPeriod());
SendResponse(aHeader, aMessageInfo);
exit:
return;
}
ThreadError AnnounceBeginServer::SendResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestInfo)
{
ThreadError error = kThreadError_None;
Message *message = NULL;
Coap::Header responseHeader;
Ip6::MessageInfo responseInfo;
VerifyOrExit(aRequestHeader.GetType() == Coap::Header::kTypeConfirmable, ;);
VerifyOrExit((message = mCoapServer.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
responseHeader.Init();
responseHeader.SetType(Coap::Header::kTypeAcknowledgment);
responseHeader.SetCode(Coap::Header::kCodeChanged);
responseHeader.SetMessageId(aRequestHeader.GetMessageId());
responseHeader.SetToken(aRequestHeader.GetToken(), aRequestHeader.GetTokenLength());
responseHeader.Finalize();
SuccessOrExit(error = message->Append(responseHeader.GetBytes(), responseHeader.GetLength()));
memcpy(&responseInfo, &aRequestInfo, sizeof(responseInfo));
memset(&responseInfo.mSockAddr, 0, sizeof(responseInfo.mSockAddr));
SuccessOrExit(error = mCoapServer.SendMessage(*message, responseInfo));
otLogInfoMeshCoP("sent announce begin response\r\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void AnnounceBeginServer::HandleTimer(void *aContext)
{
static_cast<AnnounceBeginServer *>(aContext)->HandleTimer();
}
void AnnounceBeginServer::HandleTimer(void)
{
mNetif.GetMle().SendAnnounce(mChannel++);
while (mCount > 0)
{
if (mChannelMask & (1 << mChannel))
{
mTimer.Start(mPeriod);
break;
}
mChannel++;
if (mChannel > kPhyMaxChannel)
{
mChannel = kPhyMinChannel;
mCount--;
}
}
}
} // namespace Thread
+116
View File
@@ -0,0 +1,116 @@
/*
* 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.
*/
/**
* @file
* This file includes definitions for responding to Announce Requests.
*/
#ifndef ANNOUNCE_BEGIN_SERVER_HPP_
#define ANNOUNCE_BEGIN_SERVER_HPP_
#include <openthread-core-config.h>
#include <openthread-types.h>
#include <coap/coap_server.hpp>
#include <common/timer.hpp>
#include <net/ip6_address.hpp>
namespace Thread {
class ThreadNetif;
/**
* This class implements handling Announce Begin Requests.
*
*/
class AnnounceBeginServer
{
public:
/**
* This constructor initializes the object.
*
*/
AnnounceBeginServer(ThreadNetif &aThreadNetif);
/**
* This method begins the MLE Announce transmission process using Count=3 and Period=1s.
*
* @param[in] aChannelMask The channels to use for transmission.
*
* @retval kThreadError_None Successfully started the transmission process.
*
*/
ThreadError SendAnnounce(uint32_t aChannelMask);
/**
* This method begins the MLE Announce transmission process.
*
* @param[in] aChannelMask The channels to use for transmission.
* @param[in] aCount The number of transmissions per channel.
* @param[in] aPeriod The time between transmissions (milliseconds).
*
* @retval kThreadError_None Successfully started the transmission process.
*
*/
ThreadError SendAnnounce(uint32_t aChannelMask, uint8_t aCount, uint16_t aPeriod);
private:
enum
{
kDefaultCount = 3,
kDefaultPeriod = 1000,
};
static void HandleRequest(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo);
void HandleRequest(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError SendResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestMessageInfo);
static void HandleTimer(void *aContext);
void HandleTimer(void);
uint32_t mChannelMask;
uint16_t mPeriod;
uint8_t mCount;
uint8_t mChannel;
Timer mTimer;
Coap::Resource mAnnounceBegin;
Coap::Server &mCoapServer;
ThreadNetif &mNetif;
};
/**
* @}
*/
} // namespace Thread
#endif // ANNOUNCE_BEGIN_SERVER_HPP_
+42 -9
View File
@@ -613,7 +613,16 @@ ThreadError MeshForwarder::UpdateIp6Route(Message &aMessage)
if (aMessage.IsLinkSecurityEnabled())
{
mMacDest.mLength = sizeof(mMacDest.mShortAddress);
mMacDest.mShortAddress = mMle.GetNextHop(Mac::kShortAddrBroadcast);
if (ip6Header.GetDestination().IsLinkLocalMulticast())
{
mMacDest.mShortAddress = Mac::kShortAddrBroadcast;
}
else
{
mMacDest.mShortAddress = mMle.GetNextHop(Mac::kShortAddrBroadcast);
}
GetMacSourceAddress(ip6Header.GetSource(), mMacSource);
}
else if (ip6Header.GetDestination().IsLinkLocal() || ip6Header.GetDestination().IsLinkLocalMulticast())
@@ -824,7 +833,7 @@ ThreadError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame)
switch (mSendMessage->GetType())
{
case Message::kTypeIp6:
if (mSendMessage->IsMleDiscoverRequest())
if (mSendMessage->GetSubType() == Message::kSubTypeMleDiscoverRequest)
{
if (!mScanning)
{
@@ -995,17 +1004,41 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
if (aMessage.IsLinkSecurityEnabled())
{
fcf |= Mac::Frame::kFcfSecurityEnabled;
secCtl = static_cast<uint8_t>(aMessage.IsJoinerEntrust() ? Mac::Frame::kKeyIdMode0 : Mac::Frame::kKeyIdMode1);
switch (aMessage.GetSubType())
{
case Message::kSubTypeJoinerEntrust:
secCtl = static_cast<uint8_t>(Mac::Frame::kKeyIdMode0);
break;
case Message::kSubTypeMleAnnounce:
secCtl = static_cast<uint8_t>(Mac::Frame::kKeyIdMode2);
break;
default:
secCtl = static_cast<uint8_t>(Mac::Frame::kKeyIdMode1);
break;
}
secCtl |= Mac::Frame::kSecEncMic32;
}
if (aMessage.IsMleDiscoverRequest() || aMessage.IsMleDiscoverResponse())
dstpan = mMac.GetPanId();
switch (aMessage.GetSubType())
{
case Message::kSubTypeMleAnnounce:
aFrame.SetChannel(aMessage.GetChannel());
dstpan = Mac::kPanIdBroadcast;
break;
case Message::kSubTypeMleDiscoverRequest:
case Message::kSubTypeMleDiscoverResponse:
dstpan = aMessage.GetPanId();
}
else
{
dstpan = mMac.GetPanId();
break;
default:
break;
}
if (dstpan == mMac.GetPanId())
@@ -1219,7 +1252,7 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame, ThreadError aError)
mSendMessage->SetOffset(0);
}
if (mSendMessage->IsMleDiscoverRequest())
if (mSendMessage->GetSubType() == Message::kSubTypeMleDiscoverRequest)
{
mSendBusy = true;
mDiscoverTimer.Start(mScanDuration);
+101 -4
View File
@@ -161,6 +161,8 @@ Mle::Mle(ThreadNetif &aThreadNetif) :
mRouterSelectionJitterTimeout = 0;
mRouterSelectionJitter = kRouterSelectionJitter;
mPreviousPanId = Mac::kPanIdBroadcast;
}
ThreadError Mle::Enable(void)
@@ -245,7 +247,7 @@ ThreadError Mle::Discover(uint32_t aScanChannels, uint16_t aScanDuration, uint16
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
message->SetMleDiscoverRequest(true);
message->SetSubType(Message::kSubTypeMleDiscoverRequest);
message->SetPanId(aPanId);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDiscoveryRequest));
@@ -384,6 +386,12 @@ ThreadError Mle::SetStateChild(uint16_t aRloc16)
mNetif.GetNetworkDataLocal().ClearResubmitDelayTimer();
mNetif.GetIp6().SetForwardingEnabled(false);
if (mPreviousPanId != Mac::kPanIdBroadcast)
{
mPreviousPanId = Mac::kPanIdBroadcast;
mNetif.GetAnnounceBeginServer().SendAnnounce(1 << mPreviousChannel);
}
otLogInfoMle("Mode -> Child\n");
return kThreadError_None;
}
@@ -1064,7 +1072,14 @@ void Mle::HandleParentRequestTimer(void)
switch (mParentRequestMode)
{
case kMleAttachAnyPartition:
if (mMleRouter.BecomeLeader() != kThreadError_None)
if (mPreviousPanId != Mac::kPanIdBroadcast)
{
mMac.SetChannel(mPreviousChannel);
mMac.SetPanId(mPreviousPanId);
mPreviousPanId = Mac::kPanIdBroadcast;
BecomeDetached();
}
else if (mMleRouter.BecomeLeader() != kThreadError_None)
{
mParentRequestState = kParentIdle;
BecomeDetached();
@@ -1326,6 +1341,48 @@ exit:
return error;
}
ThreadError Mle::SendAnnounce(uint8_t aChannel)
{
ThreadError error = kThreadError_None;
ChannelTlv channel;
PanIdTlv panid;
Ip6::Address destination;
Message *message;
(void)aChannel;
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
message->SetSubType(Message::kSubTypeMleAnnounce);
message->SetChannel(aChannel);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandAnnounce));
channel.Init();
channel.SetChannelPage(0);
channel.SetChannel(mMac.GetChannel());
SuccessOrExit(error = message->Append(&channel, sizeof(channel)));
SuccessOrExit(error = AppendActiveTimestamp(*message));
panid.Init();
panid.SetPanId(mMac.GetPanId());
SuccessOrExit(error = message->Append(&panid, sizeof(panid)));
memset(&destination, 0, sizeof(destination));
destination.mFields.m16[0] = HostSwap16(0xff02);
destination.mFields.m16[7] = HostSwap16(0x0001);
SuccessOrExit(error = SendMessage(*message, destination));
otLogInfoMle("sent announce on channel %d\n", aChannel);
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
ThreadError Mle::SendMessage(Message &aMessage, const Ip6::Address &aDestination)
{
ThreadError error = kThreadError_None;
@@ -1554,7 +1611,8 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
command == Header::kCommandParentRequest ||
command == Header::kCommandParentResponse ||
command == Header::kCommandChildIdRequest ||
command == Header::kCommandChildUpdateRequest))
command == Header::kCommandChildUpdateRequest ||
command == Header::kCommandAnnounce))
{
otLogDebgMle("mle sequence unknown! %d\n", command);
ExitNow();
@@ -1614,6 +1672,10 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
case Header::kCommandChildUpdateResponse:
HandleChildUpdateResponse(aMessage, aMessageInfo);
break;
case Header::kCommandAnnounce:
HandleAnnounce(aMessage, aMessageInfo);
break;
}
exit:
@@ -2211,6 +2273,41 @@ exit:
return error;
}
ThreadError Mle::HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
ChannelTlv channel;
ActiveTimestampTlv timestamp;
const MeshCoP::Timestamp *localTimestamp;
PanIdTlv panid;
otLogInfoMle("Received announce\n");
SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kChannel, sizeof(channel), channel));
VerifyOrExit(channel.IsValid(),);
SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(timestamp), timestamp));
VerifyOrExit(timestamp.IsValid(),);
SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kPanId, sizeof(panid), panid));
VerifyOrExit(panid.IsValid(),);
localTimestamp = mNetif.GetActiveDataset().GetNetwork().GetTimestamp();
VerifyOrExit(localTimestamp == NULL || localTimestamp->Compare(timestamp) > 0,);
Stop();
mPreviousChannel = mMac.GetChannel();
mPreviousPanId = mMac.GetPanId();
mMac.SetChannel(static_cast<uint8_t>(channel.GetChannel()));
mMac.SetPanId(panid.GetPanId());
Start();
exit:
(void)aMessageInfo;
return error;
}
ThreadError Mle::HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
@@ -2291,7 +2388,7 @@ ThreadError Mle::SendDiscoveryResponse(const Ip6::Address &aDestination, uint16_
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
message->SetMleDiscoverResponse(true);
message->SetSubType(Message::kSubTypeMleDiscoverResponse);
message->SetPanId(aPanId);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDiscoveryResponse));
+17 -1
View File
@@ -277,6 +277,7 @@ public:
kCommandChildIdResponse = 12, ///< Child ID Response
kCommandChildUpdateRequest = 13, ///< Child Update Request
kCommandChildUpdateResponse = 14, ///< Child Update Response
kCommandAnnounce = 15, ///< Announce
kCommandDiscoveryRequest = 16, ///< Discovery Request
kCommandDiscoveryResponse = 17, ///< Discovery Response
};
@@ -410,6 +411,17 @@ public:
*/
void HandleDiscoverComplete(void);
/**
* This method generates an MLE Announce message.
*
* @param[in] aChannel The channel to use when transmitting.
*
* @retval kThreadError_None Successfully generated an MLE Announce message.
* @retval kThreadError_NoBufs Insufficient buffers to generate the MLE Announce message.
*
*/
ThreadError SendAnnounce(uint8_t aChannel);
/**
* This method causes the Thread interface to detach from the Thread network.
*
@@ -1002,7 +1014,7 @@ protected:
/**
* This method generates an MLE Child Update Request message.
*
* @retval kThreadError_None Successfully generated an MLE Child Update Request message..
* @retval kThreadError_None Successfully generated an MLE Child Update Request message.
* @retval kThreadError_NoBufs Insufficient buffers to generate the MLE Child Update Request message.
*
*/
@@ -1121,6 +1133,7 @@ private:
ThreadError HandleDataResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleParentResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
uint32_t aKeySequence);
ThreadError HandleAnnounce(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
@@ -1159,6 +1172,9 @@ private:
void *mDiscoverContext;
bool mIsDiscoverInProgress;
uint8_t mPreviousChannel;
uint16_t mPreviousPanId;
Ip6::NetifUnicastAddress mLinkLocal16;
Ip6::NetifUnicastAddress mLinkLocal64;
Ip6::NetifUnicastAddress mMeshLocal64;
+105
View File
@@ -94,6 +94,8 @@ public:
kStatus = 17, ///< Status TLV
kVersion = 18, ///< Version TLV
kAddressRegistration = 19, ///< Address Registration TLV
kChannel = 20, ///< Channel TLV
kPanId = 21, ///< PAN ID TLV
kActiveTimestamp = 22, ///< Active Timestamp TLV
kPendingTimestamp = 23, ///< Pending Timestamp TLV
kActiveDataset = 24, ///< Active Operational Dataset TLV
@@ -1450,6 +1452,109 @@ private:
AddressRegistrationEntry mAddresses[4];
} 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 Channel Page value.
*
* @returns The Channel Page value.
*
*/
uint8_t GetChannelPage(void) const { return mChannelPage; }
/**
* This method sets the Channel Page value.
*
* @param[in] aChannelPage The Channel Page 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 Active Timestamp TLV generation and parsing.
*
+1
View File
@@ -79,6 +79,7 @@ ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6):
#endif // OPENTHREAD_ENABLE_JOINER
mJoinerRouter(*this),
mLeader(*this),
mAnnounceBegin(*this),
mPanIdQuery(*this),
mEnergyScan(*this)
{
+4
View File
@@ -48,6 +48,7 @@
#include <net/ip6_filter.hpp>
#include <net/netif.hpp>
#include <thread/address_resolver.hpp>
#include <thread/announce_begin_server.hpp>
#include <thread/energy_scan_server.hpp>
#include <thread/network_diag.hpp>
#include <thread/key_manager.hpp>
@@ -246,6 +247,8 @@ public:
MeshCoP::JoinerRouter &GetJoinerRouter(void) { return mJoinerRouter; }
AnnounceBeginServer &GetAnnounceBeginServer(void) { return mAnnounceBegin; }
#if OPENTHREAD_ENABLE_COMMISSIONER
MeshCoP::Commissioner &GetCommissioner(void) { return mCommissioner; }
#endif // OPENTHREAD_ENABLE_COMMISSIONER
@@ -288,6 +291,7 @@ private:
MeshCoP::JoinerRouter mJoinerRouter;
MeshCoP::Leader mLeader;
AnnounceBeginServer mAnnounceBegin;
PanIdQueryServer mPanIdQuery;
EnergyScanServer mEnergyScan;
};
+8
View File
@@ -130,6 +130,14 @@ namespace Thread {
*/
#define OPENTHREAD_URI_SERVER_DATA "a/sd"
/**
* @def OPENTHREAD_URI_ANNOUNCE_BEGIN
*
* The URI Path for Announce Begin.
*
*/
#define OPENTHREAD_URI_ANNOUNCE_BEGIN "c/ab"
/**
* @def OPENTHREAD_URI_RELAY_RX
*
+3
View File
@@ -104,6 +104,7 @@ EXTRA_DIST = \
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
thread-cert/Cert_8_1_01_Commissioning.py \
thread-cert/Cert_8_1_02_Commissioning.py \
thread-cert/Cert_9_2_12_Announce.py \
thread-cert/Cert_9_2_13_EnergyScan.py \
thread-cert/Cert_9_2_14_PanIdQuery.py \
thread-cert/node.py \
@@ -222,6 +223,7 @@ check_SCRIPTS += \
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
thread-cert/Cert_8_1_01_Commissioning.py \
thread-cert/Cert_8_1_02_Commissioning.py \
thread-cert/Cert_9_2_12_Announce.py \
thread-cert/Cert_9_2_13_EnergyScan.py \
thread-cert/Cert_9_2_14_PanIdQuery.py \
$(NULL)
@@ -242,6 +244,7 @@ TESTS = \
XFAIL_NCP_TESTS = \
thread-cert/Cert_8_1_01_Commissioning.py \
thread-cert/Cert_8_1_02_Commissioning.py \
thread-cert/Cert_9_2_12_Announce.py \
thread-cert/Cert_9_2_13_EnergyScan.py \
thread-cert/Cert_9_2_14_PanIdQuery.py \
$(NULL)
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/python
#
# 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.
#
import time
import unittest
import node
LEADER1 = 1
ROUTER1 = 2
LEADER2 = 3
ROUTER2 = 4
MED = 5
DATASET1_TIMESTAMP = 20
DATASET1_CHANNEL = 11
DATASET1_PANID = 0xface
DATASET2_TIMESTAMP = 10
DATASET2_CHANNEL = 12
DATASET2_PANID = 0xafce
class Cert_9_2_12_Announce(unittest.TestCase):
def setUp(self):
self.nodes = {}
for i in range(1,6):
self.nodes[i] = node.Node(i)
self.nodes[LEADER1].set_active_dataset(DATASET1_TIMESTAMP, channel=DATASET1_CHANNEL, panid=DATASET1_PANID)
self.nodes[LEADER1].set_mode('rsdn')
self.nodes[LEADER1].add_whitelist(self.nodes[ROUTER1].get_addr64())
self.nodes[LEADER1].enable_whitelist()
self.nodes[ROUTER1].set_active_dataset(DATASET1_TIMESTAMP, channel=DATASET1_CHANNEL, panid=DATASET1_PANID)
self.nodes[ROUTER1].set_mode('rsdn')
self.nodes[ROUTER1].add_whitelist(self.nodes[LEADER1].get_addr64())
self.nodes[ROUTER1].add_whitelist(self.nodes[LEADER2].get_addr64())
self.nodes[ROUTER1].enable_whitelist()
self.nodes[ROUTER1].set_router_selection_jitter(1)
self.nodes[LEADER2].set_active_dataset(DATASET2_TIMESTAMP, channel=DATASET2_CHANNEL, panid=DATASET1_PANID)
self.nodes[LEADER2].set_mode('rsdn')
self.nodes[LEADER2].add_whitelist(self.nodes[ROUTER1].get_addr64())
self.nodes[LEADER2].add_whitelist(self.nodes[ROUTER2].get_addr64())
self.nodes[LEADER2].enable_whitelist()
self.nodes[LEADER2].set_router_selection_jitter(1)
self.nodes[ROUTER2].set_active_dataset(DATASET2_TIMESTAMP, channel=DATASET2_CHANNEL, panid=DATASET1_PANID)
self.nodes[ROUTER2].set_mode('rsdn')
self.nodes[ROUTER2].add_whitelist(self.nodes[LEADER2].get_addr64())
self.nodes[ROUTER2].add_whitelist(self.nodes[MED].get_addr64())
self.nodes[ROUTER2].enable_whitelist()
self.nodes[ROUTER2].set_router_selection_jitter(1)
self.nodes[MED].set_active_dataset(DATASET2_TIMESTAMP, channel=DATASET2_CHANNEL, panid=DATASET1_PANID)
self.nodes[MED].set_mode('rsn')
self.nodes[MED].add_whitelist(self.nodes[ROUTER2].get_addr64())
self.nodes[MED].enable_whitelist()
def tearDown(self):
for node in list(self.nodes.values()):
node.stop()
del self.nodes
def test(self):
self.nodes[LEADER1].start()
self.nodes[LEADER1].set_state('leader')
self.assertEqual(self.nodes[LEADER1].get_state(), 'leader')
self.nodes[ROUTER1].start()
time.sleep(5)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[LEADER2].start()
self.nodes[LEADER2].set_state('leader')
self.assertEqual(self.nodes[LEADER2].get_state(), 'leader')
self.nodes[ROUTER2].start()
time.sleep(5)
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.nodes[MED].start()
time.sleep(5)
self.assertEqual(self.nodes[MED].get_state(), 'child')
ipaddrs = self.nodes[ROUTER1].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.nodes[LEADER1].announce_begin(0x1000, 1, 1000, ipaddr)
time.sleep(30)
self.assertEqual(self.nodes[LEADER2].get_state(), 'router')
self.assertEqual(self.nodes[ROUTER2].get_state(), 'router')
self.assertEqual(self.nodes[MED].get_state(), 'child')
ipaddrs = self.nodes[MED].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
self.assertTrue(self.nodes[LEADER1].ping(ipaddr))
if __name__ == '__main__':
unittest.main()
+26
View File
@@ -425,5 +425,31 @@ class Node:
self.send_command(cmd)
self.pexpect.expect('Done')
def set_active_dataset(self, timestamp, panid=None, channel=None):
self.send_command('dataset clear')
self.pexpect.expect('Done')
cmd = 'dataset activetimestamp %d' % timestamp
self.send_command(cmd)
self.pexpect.expect('Done')
if panid != None:
cmd = 'dataset panid %d' % panid
self.send_command(cmd)
self.pexpect.expect('Done')
if channel != None:
cmd = 'dataset channel %d' % channel
self.send_command(cmd)
self.pexpect.expect('Done')
self.send_command('dataset commit active')
self.pexpect.expect('Done')
def announce_begin(self, mask, count, period, ipaddr):
cmd = 'commissioner announce ' + str(mask) + ' ' + str(count) + ' ' + str(period) + ' ' + ipaddr
self.send_command(cmd)
self.pexpect.expect('Done')
if __name__ == '__main__':
unittest.main()