Implement PAN ID Query/Conflict. (#556)

This commit is contained in:
Jonathan Hui
2016-09-13 09:18:05 -07:00
committed by GitHub
parent 6243511d61
commit c44c20ef66
17 changed files with 865 additions and 1 deletions
+6
View File
@@ -66,6 +66,12 @@ ThreadError otCommissionerStart(otInstance *aInstance, const char *aPSKd);
*/
ThreadError otCommissionerStop(otInstance *aInstance);
typedef void (*otCommissionerPanIdConflictCallback)(uint16_t aPanId, uint32_t aChannelMask, void *aContext);
ThreadError otCommissionerPanIdQuery(otInstance *, uint16_t aPanId, uint32_t aChannelMask,
const otIp6Address *aAddress,
otCommissionerPanIdConflictCallback aCallback, void *aContext);
/**
* @}
*
+31
View File
@@ -1860,11 +1860,42 @@ void Interpreter::ProcessCommissioner(int argc, char *argv[])
{
otCommissionerStop(mInstance);
}
else if (strcmp(argv[0], "panid") == 0)
{
long panid;
long mask;
otIp6Address address;
VerifyOrExit(argc > 3, error = kThreadError_Parse);
// panid
SuccessOrExit(error = ParseLong(argv[1], panid));
// mask
SuccessOrExit(error = ParseLong(argv[2], mask));
// destination
SuccessOrExit(error = otIp6AddressFromString(argv[3], &address));
SuccessOrExit(error = otCommissionerPanIdQuery(mInstance, static_cast<uint16_t>(panid),
static_cast<uint32_t>(mask),
&address, Interpreter::s_HandlePanIdConflict, this));
}
exit:
AppendResult(error);
}
void Interpreter::s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext)
{
static_cast<Interpreter *>(aContext)->HandlePanIdConflict(aPanId, aChannelMask);
}
void Interpreter::HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask)
{
sServer->OutputFormat("Conflict: %04x, %08x\r\n", aPanId, aChannelMask);
}
#endif // OPENTHREAD_ENABLE_COMMISSIONER
#if OPENTHREAD_ENABLE_JOINER
+2
View File
@@ -201,12 +201,14 @@ private:
static void s_HandleActiveScanResult(otActiveScanResult *aResult, void *aContext);
static void s_HandleNetifStateChanged(uint32_t aFlags, void *aContext);
static void s_HandleLinkPcapReceive(const RadioPacket *aFrame, void *aContext);
static void s_HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask, void *aContext);
void HandleEchoResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
void HandlePingTimer();
void HandleActiveScanResult(otActiveScanResult *aResult);
void HandleNetifStateChanged(uint32_t aFlags);
void HandleLinkPcapReceive(const RadioPacket *aFrame);
void HandlePanIdConflict(uint16_t aPanId, uint32_t aChannelMask);
static const struct Command sCommands[];
+4
View File
@@ -76,6 +76,7 @@ libopenthread_a_SOURCES = \
thread/network_data.cpp \
thread/network_data_local.cpp \
thread/network_data_leader.cpp \
thread/panid_query_server.cpp \
thread/thread_netif.cpp \
thread/thread_tlvs.cpp \
$(NULL)
@@ -83,6 +84,7 @@ libopenthread_a_SOURCES = \
if OPENTHREAD_ENABLE_COMMISSIONER
libopenthread_a_SOURCES += \
meshcop/commissioner.cpp \
meshcop/panid_query_client.cpp \
$(NULL)
endif # OPENTHREAD_ENABLE_COMMISSIONER
@@ -125,6 +127,7 @@ noinst_HEADERS = \
meshcop/joiner.hpp \
meshcop/joiner_router.hpp \
meshcop/leader.hpp \
meshcop/panid_query_client.hpp \
net/icmp6.hpp \
net/ip6.hpp \
net/ip6_address.hpp \
@@ -153,6 +156,7 @@ noinst_HEADERS = \
thread/network_data_leader.hpp \
thread/network_data_local.hpp \
thread/network_data_tlvs.hpp \
thread/panid_query_server.hpp \
thread/thread_netif.hpp \
thread/thread_tlvs.hpp \
thread/thread_uris.hpp \
+6
View File
@@ -49,6 +49,7 @@ namespace Thread {
namespace MeshCoP {
Commissioner::Commissioner(ThreadNetif &aThreadNetif):
mPanIdQuery(aThreadNetif),
mTimer(aThreadNetif.GetIp6().mTimerScheduler, HandleTimer, this),
mTransmitTask(aThreadNetif.GetIp6().mTaskletScheduler, &HandleUdpTransmit, this),
mSendKek(false),
@@ -83,6 +84,11 @@ ThreadError Commissioner::Stop(void)
return kThreadError_None;
}
uint16_t Commissioner::GetSessionId(void) const
{
return mSessionId;
}
void Commissioner::HandleTimer(void *aContext)
{
static_cast<Commissioner *>(aContext)->HandleTimer();
+11
View File
@@ -36,6 +36,7 @@
#include <coap/coap_server.hpp>
#include <common/timer.hpp>
#include <meshcop/panid_query_client.hpp>
#include <net/udp6.hpp>
#include <thread/mle.hpp>
@@ -74,6 +75,16 @@ public:
*/
ThreadError Stop(void);
/**
* This method returns the Commissioner Session ID.
*
* @retuns The Commissioner Session ID.
*
*/
uint16_t GetSessionId(void) const;
PanIdQueryClient mPanIdQuery;
private:
static void HandleTimer(void *aContext);
void HandleTimer(void);
+226
View File
@@ -0,0 +1,226 @@
/*
* 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 PAN ID Query Client.
*/
#include <coap/coap_header.hpp>
#include <common/code_utils.hpp>
#include <common/debug.hpp>
#include <common/logging.hpp>
#include <meshcop/panid_query_client.hpp>
#include <thread/meshcop_tlvs.hpp>
#include <thread/thread_netif.hpp>
#include <thread/thread_uris.hpp>
namespace Thread {
PanIdQueryClient::PanIdQueryClient(ThreadNetif &aThreadNetif) :
mPanIdQuery(OPENTHREAD_URI_PANID_CONFLICT, &HandleConflict, this),
mSocket(aThreadNetif.GetIp6().mUdp),
mTimer(aThreadNetif.GetIp6().mTimerScheduler, &HandleTimer, this),
mCoapServer(aThreadNetif.GetCoapServer()),
mNetif(aThreadNetif)
{
mCoapServer.AddResource(mPanIdQuery);
mSocket.Open(HandleUdpReceive, this);
}
ThreadError PanIdQueryClient::SendQuery(uint16_t aPanId, uint32_t aChannelMask, const Ip6::Address &aAddress,
otCommissionerPanIdConflictCallback aCallback, void *aContext)
{
ThreadError error = kThreadError_None;
Coap::Header header;
MeshCoP::CommissionerSessionIdTlv sessionId;
MeshCoP::ChannelMaskTlv channelMask;
union
{
MeshCoP::ChannelMaskEntry channelMaskEntry;
uint8_t channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + sizeof(aChannelMask)];
};
MeshCoP::PanIdTlv panId;
Ip6::MessageInfo messageInfo;
Message *message;
header.Init();
header.SetVersion(1);
header.SetType(aAddress.IsMulticast() ? Coap::Header::kTypeNonConfirmable : Coap::Header::kTypeConfirmable);
header.SetCode(Coap::Header::kCodePost);
header.SetMessageId(0);
header.SetToken(NULL, 0);
header.AppendUriPathOptions(OPENTHREAD_URI_PANID_QUERY);
header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream);
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.Init();
channelMask.SetLength(sizeof(channelMaskBuf));
SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask)));
channelMaskEntry.SetChannelPage(0);
channelMaskEntry.SetMaskLength(sizeof(aChannelMask));
for (size_t i = 0; i < sizeof(aChannelMask); i++)
{
channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + i] = (aChannelMask >> (8 * i)) & 0xff;
}
SuccessOrExit(error = message->Append(channelMaskBuf, sizeof(channelMaskBuf)));
panId.Init();
panId.SetPanId(aPanId);
SuccessOrExit(error = message->Append(&panId, sizeof(panId)));
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.GetPeerAddr() = aAddress;
messageInfo.mPeerPort = kCoapUdpPort;
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
otLogInfoMeshCoP("sent panid query\r\n");
mCallback = aCallback;
mContext = aContext;
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void PanIdQueryClient::HandleConflict(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
static_cast<PanIdQueryClient *>(aContext)->HandleConflict(aHeader, aMessage, aMessageInfo);
}
void PanIdQueryClient::HandleConflict(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
MeshCoP::PanIdTlv panId;
union
{
MeshCoP::ChannelMaskEntry channelMaskEntry;
uint8_t channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + sizeof(uint32_t)];
};
uint32_t channelMask;
uint16_t offset;
uint16_t length;
VerifyOrExit(aHeader.GetType() == Coap::Header::kTypeConfirmable &&
aHeader.GetCode() == Coap::Header::kCodePost, ;);
otLogInfoMeshCoP("received panid conflict\r\n");
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kPanId, sizeof(panId), panId));
VerifyOrExit(panId.IsValid(), ;);
SuccessOrExit(MeshCoP::Tlv::GetValueOffset(aMessage, MeshCoP::Tlv::kChannelMask, offset, length));
aMessage.Read(offset, sizeof(channelMaskBuf), channelMaskBuf);
VerifyOrExit(channelMaskEntry.GetChannelPage() == 0 &&
channelMaskEntry.GetMaskLength() == sizeof(uint32_t), ;);
channelMask =
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 0]) << 0) |
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 1]) << 8) |
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 2]) << 16) |
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 3]) << 24);
if (mCallback != NULL)
{
mCallback(panId.GetPanId(), channelMask, mContext);
}
SendConflictResponse(aHeader, aMessageInfo);
exit:
return;
}
ThreadError PanIdQueryClient::SendConflictResponse(const Coap::Header &aRequestHeader,
const Ip6::MessageInfo &aRequestInfo)
{
ThreadError error = kThreadError_None;
Message *message;
Coap::Header responseHeader;
Ip6::MessageInfo responseInfo;
VerifyOrExit((message = mCoapServer.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.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));
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void PanIdQueryClient::HandleTimer(void *aContext)
{
static_cast<PanIdQueryClient *>(aContext)->HandleTimer();
}
void PanIdQueryClient::HandleTimer(void)
{
}
void PanIdQueryClient::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
{
otLogInfoMeshCoP("received panid query response\r\n");
(void)aContext;
(void)aMessage;
(void)aMessageInfo;
}
} // namespace Thread
+94
View File
@@ -0,0 +1,94 @@
/*
* 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 responding to PANID Query Requests.
*/
#ifndef PANID_QUERY_CLIENT_HPP_
#define PANID_QUERY_CLIENT_HPP_
#include <openthread-core-config.h>
#include <openthread-types.h>
#include <commissioning/commissioner.h>
#include <coap/coap_server.hpp>
#include <common/timer.hpp>
#include <net/ip6_address.hpp>
#include <net/udp6.hpp>
namespace Thread {
class ThreadNetif;
/**
* This class implements handling PANID Query Requests.
*
*/
class PanIdQueryClient
{
public:
/**
* This constructor initializes the object.
*
*/
PanIdQueryClient(ThreadNetif &aThreadNetif);
ThreadError SendQuery(uint16_t aPanId, uint32_t aChannelMask, const Ip6::Address &aAddress,
otCommissionerPanIdConflictCallback aCallback, void *aContext);
private:
static void HandleConflict(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo);
void HandleConflict(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleTimer(void *aContext);
void HandleTimer(void);
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
ThreadError SendConflictResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestMessageInfo);
otCommissionerPanIdConflictCallback mCallback;
void *mContext;
Coap::Resource mPanIdQuery;
Ip6::UdpSocket mSocket;
Timer mTimer;
Coap::Server &mCoapServer;
ThreadNetif &mNetif;
};
/**
* @}
*/
} // namespace Thread
#endif // PANID_QUERY_CLIENT_HPP_
+10
View File
@@ -1283,6 +1283,7 @@ ThreadError otSendPendingSet(otInstance *, const otOperationalDataset *aDataset,
}
#if OPENTHREAD_ENABLE_COMMISSIONER
#include <commissioning/commissioner.h>
ThreadError otCommissionerStart(otInstance *, const char *aPSKd)
{
return sThreadNetif->GetCommissioner().Start(aPSKd);
@@ -1292,6 +1293,15 @@ ThreadError otCommissionerStop(otInstance *)
{
return sThreadNetif->GetCommissioner().Stop();
}
ThreadError otCommissionerPanIdQuery(otInstance *, uint16_t aPanId, uint32_t aChannelMask,
const otIp6Address *aAddress,
otCommissionerPanIdConflictCallback aCallback, void *aContext)
{
return sThreadNetif->GetCommissioner().mPanIdQuery.SendQuery(aPanId, aChannelMask,
*static_cast<const Ip6::Address *>(aAddress),
aCallback, aContext);
}
#endif // OPENTHREAD_ENABLE_COMMISSIONER
#if OPENTHREAD_ENABLE_JOINER
+241
View File
@@ -0,0 +1,241 @@
/*
* 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 PAN ID Query Server.
*/
#include <coap/coap_header.hpp>
#include <common/code_utils.hpp>
#include <common/debug.hpp>
#include <common/logging.hpp>
#include <thread/meshcop_tlvs.hpp>
#include <thread/panid_query_server.hpp>
#include <thread/thread_netif.hpp>
#include <thread/thread_uris.hpp>
namespace Thread {
PanIdQueryServer::PanIdQueryServer(ThreadNetif &aThreadNetif) :
mPanIdQuery(OPENTHREAD_URI_PANID_QUERY, &HandleQuery, this),
mSocket(aThreadNetif.GetIp6().mUdp),
mTimer(aThreadNetif.GetIp6().mTimerScheduler, &HandleTimer, this),
mCoapServer(aThreadNetif.GetCoapServer()),
mNetif(aThreadNetif)
{
mCoapServer.AddResource(mPanIdQuery);
mSocket.Open(HandleUdpReceive, this);
}
void PanIdQueryServer::HandleQuery(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo)
{
static_cast<PanIdQueryServer *>(aContext)->HandleQuery(aHeader, aMessage, aMessageInfo);
}
void PanIdQueryServer::HandleQuery(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
MeshCoP::PanIdTlv panId;
union
{
MeshCoP::ChannelMaskEntry channelMaskEntry;
uint8_t channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + sizeof(uint32_t)];
};
uint16_t offset;
uint16_t length;
VerifyOrExit(aHeader.GetCode() == Coap::Header::kCodePost, ;);
SuccessOrExit(MeshCoP::Tlv::GetValueOffset(aMessage, MeshCoP::Tlv::kChannelMask, offset, length));
aMessage.Read(offset, sizeof(channelMaskBuf), channelMaskBuf);
VerifyOrExit(channelMaskEntry.GetChannelPage() == 0 &&
channelMaskEntry.GetMaskLength() == sizeof(uint32_t), ;);
mChannelMask =
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 0]) << 0) |
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 1]) << 8) |
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 2]) << 16) |
(static_cast<uint32_t>(channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + 3]) << 24);
SuccessOrExit(MeshCoP::Tlv::GetTlv(aMessage, MeshCoP::Tlv::kPanId, sizeof(panId), panId));
VerifyOrExit(panId.IsValid(), ;);
mCommissioner = aMessageInfo.GetPeerAddr();
mPanId = panId.GetPanId();
mTimer.Start(kScanDelay);
SendQueryResponse(aHeader, aMessageInfo);
exit:
return;
}
ThreadError PanIdQueryServer::SendQueryResponse(const Coap::Header &aRequestHeader,
const Ip6::MessageInfo &aRequestInfo)
{
ThreadError error = kThreadError_None;
Message *message;
Coap::Header responseHeader;
Ip6::MessageInfo responseInfo;
VerifyOrExit(aRequestHeader.GetType() == Coap::Header::kTypeConfirmable, ;);
VerifyOrExit((message = mCoapServer.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.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 panid query response\r\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void PanIdQueryServer::HandleScanResult(void *aContext, Mac::Frame *aFrame)
{
static_cast<PanIdQueryServer *>(aContext)->HandleScanResult(aFrame);
}
void PanIdQueryServer::HandleScanResult(Mac::Frame *aFrame)
{
uint16_t panId;
if (aFrame != NULL)
{
aFrame->GetSrcPanId(panId);
if (panId == mPanId)
{
mChannelMask |= 1 << aFrame->GetChannel();
}
}
else if (mChannelMask != 0)
{
SendConflict();
}
}
ThreadError PanIdQueryServer::SendConflict(void)
{
ThreadError error = kThreadError_None;
Coap::Header header;
MeshCoP::ChannelMaskTlv channelMask;
union
{
MeshCoP::ChannelMaskEntry channelMaskEntry;
uint8_t channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + sizeof(uint32_t)];
};
MeshCoP::PanIdTlv panId;
Ip6::MessageInfo messageInfo;
Message *message;
header.Init();
header.SetVersion(1);
header.SetType(Coap::Header::kTypeConfirmable);
header.SetCode(Coap::Header::kCodePost);
header.SetMessageId(0);
header.SetToken(NULL, 0);
header.AppendUriPathOptions(OPENTHREAD_URI_PANID_CONFLICT);
header.AppendContentFormatOption(Coap::Header::kApplicationOctetStream);
header.Finalize();
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, error = kThreadError_NoBufs);
SuccessOrExit(error = message->Append(header.GetBytes(), header.GetLength()));
channelMask.Init();
channelMask.SetLength(sizeof(channelMaskBuf));
SuccessOrExit(error = message->Append(&channelMask, sizeof(channelMask)));
channelMaskEntry.SetChannelPage(0);
channelMaskEntry.SetMaskLength(sizeof(mChannelMask));
for (size_t i = 0; i < sizeof(mChannelMask); i++)
{
channelMaskBuf[sizeof(MeshCoP::ChannelMaskEntry) + i] = (mChannelMask >> (8 * i)) & 0xff;
}
SuccessOrExit(error = message->Append(channelMaskBuf, sizeof(channelMaskBuf)));
panId.Init();
panId.SetPanId(mPanId);
SuccessOrExit(error = message->Append(&panId, sizeof(panId)));
memset(&messageInfo, 0, sizeof(messageInfo));
messageInfo.GetPeerAddr() = mCommissioner;
messageInfo.mPeerPort = kCoapUdpPort;
SuccessOrExit(error = mSocket.SendTo(*message, messageInfo));
otLogInfoMeshCoP("sent panid conflict\r\n");
exit:
if (error != kThreadError_None && message != NULL)
{
message->Free();
}
return error;
}
void PanIdQueryServer::HandleTimer(void *aContext)
{
static_cast<PanIdQueryServer *>(aContext)->HandleTimer();
}
void PanIdQueryServer::HandleTimer(void)
{
otLogInfoMeshCoP("%x\r\n", mChannelMask);
mNetif.GetMac().ActiveScan(mChannelMask, 0, HandleScanResult, this);
mChannelMask = 0;
}
void PanIdQueryServer::HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo)
{
(void)aContext;
(void)aMessage;
(void)aMessageInfo;
}
} // namespace Thread
+104
View File
@@ -0,0 +1,104 @@
/*
* 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 responding to PANID Query Requests.
*/
#ifndef PANID_QUERY_SERVER_HPP_
#define PANID_QUERY_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>
#include <net/udp6.hpp>
namespace Thread {
class MeshForwarder;
class ThreadLastTransactionTimeTlv;
class ThreadMeshLocalEidTlv;
class ThreadNetif;
class ThreadTargetTlv;
/**
* This class implements handling PANID Query Requests.
*
*/
class PanIdQueryServer
{
public:
/**
* This constructor initializes the object.
*
*/
PanIdQueryServer(ThreadNetif &aThreadNetif);
private:
enum
{
kScanDelay = 1000, ///< SCAN_DELAY (milliseconds)
};
static void HandleQuery(void *aContext, Coap::Header &aHeader, Message &aMessage,
const Ip6::MessageInfo &aMessageInfo);
void HandleQuery(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
static void HandleScanResult(void *aContext, Mac::Frame *aFrame);
void HandleScanResult(Mac::Frame *aFrame);
static void HandleTimer(void *aContext);
void HandleTimer(void);
static void HandleUdpReceive(void *aContext, otMessage aMessage, const otMessageInfo *aMessageInfo);
ThreadError SendConflict();
ThreadError SendQueryResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aRequestMessageInfo);
Ip6::Address mCommissioner;
uint32_t mChannelMask;
uint16_t mPanId;
Coap::Resource mPanIdQuery;
Ip6::UdpSocket mSocket;
Timer mTimer;
Coap::Server &mCoapServer;
ThreadNetif &mNetif;
};
/**
* @}
*/
} // namespace Thread
#endif // PANID_QUERY_SERVER_HPP_
+2 -1
View File
@@ -77,7 +77,8 @@ ThreadNetif::ThreadNetif(Ip6::Ip6 &aIp6):
mJoiner(*this),
#endif // OPENTHREAD_ENABLE_JOINER
mJoinerRouter(*this),
mLeader(*this)
mLeader(*this),
mPanIdQuery(*this)
{
mKeyManager.SetMasterKey(kThreadMasterKey, sizeof(kThreadMasterKey));
}
+2
View File
@@ -49,6 +49,7 @@
#include <thread/mle.hpp>
#include <thread/mle_router.hpp>
#include <thread/network_data_local.hpp>
#include <thread/panid_query_server.hpp>
#if OPENTHREAD_ENABLE_COMMISSIONER
#include <meshcop/commissioner.hpp>
@@ -271,6 +272,7 @@ private:
MeshCoP::JoinerRouter mJoinerRouter;
MeshCoP::Leader mLeader;
PanIdQueryServer mPanIdQuery;
};
/**
+16
View File
@@ -162,6 +162,22 @@ namespace Thread {
*/
#define OPENTHREAD_URI_LEADER_KEEP_ALIVE "c/la"
/**
* @def OPENTHREAD_URI_PANID_CONFLICT
*
* The URI Path for PAN ID Conflict
*
*/
#define OPENTHREAD_URI_PANID_CONFLICT "c/pc"
/**
* @def OPENTHREAD_URI_PANID_QUERY
*
* The URI Path for PAN ID Query
*
*/
#define OPENTHREAD_URI_PANID_QUERY "c/pq"
} // namespace Thread
#endif // THREAD_URIS_HPP_
+3
View File
@@ -102,6 +102,7 @@ EXTRA_DIST = \
thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \
thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
thread-cert/Cert_9_2_14_PanIdQuery.py \
thread-cert/node.py \
$(NULL)
@@ -216,6 +217,7 @@ check_SCRIPTS += \
thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \
thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
thread-cert/Cert_9_2_14_PanIdQuery.py \
$(NULL)
endif # OPENTHREAD_TESTS_SUBSET5
@@ -247,6 +249,7 @@ XFAIL_NCP_TESTS = \
thread-cert/Cert_7_1_03_BorderRouterAsLeader.py \
thread-cert/Cert_7_1_04_BorderRouterAsRouter.py \
thread-cert/Cert_7_1_05_BorderRouterAsRouter.py \
thread-cert/Cert_9_2_14_PanIdQuery.py \
$(NULL)
XFAIL_TESTS = $(if $(filter $(NODE_TYPE),ncp-sim),$(XFAIL_NCP_TESTS))
+102
View File
@@ -0,0 +1,102 @@
#!/usr/bin/python
#
# 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.
#
import time
import unittest
import node
COMMISSIONER = 1
LEADER1 = 2
ROUTER1 = 3
LEADER2 = 4
class Cert_9_2_14_PanIdQuery(unittest.TestCase):
def setUp(self):
self.nodes = {}
for i in range(1,5):
self.nodes[i] = node.Node(i)
self.nodes[COMMISSIONER].set_panid(0xface)
self.nodes[COMMISSIONER].set_mode('rsdn')
self.nodes[COMMISSIONER].add_whitelist(self.nodes[LEADER1].get_addr64())
self.nodes[COMMISSIONER].enable_whitelist()
self.nodes[LEADER1].set_panid(0xface)
self.nodes[LEADER1].set_mode('rsdn')
self.nodes[LEADER1].add_whitelist(self.nodes[COMMISSIONER].get_addr64())
self.nodes[LEADER1].add_whitelist(self.nodes[ROUTER1].get_addr64())
self.nodes[LEADER1].enable_whitelist()
self.nodes[ROUTER1].set_panid(0xface)
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[LEADER2].set_panid(0xdead)
self.nodes[LEADER2].set_mode('rsdn')
self.nodes[LEADER2].add_whitelist(self.nodes[ROUTER1].get_addr64())
self.nodes[LEADER2].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[COMMISSIONER].start()
time.sleep(3)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'router')
self.nodes[ROUTER1].start()
time.sleep(3)
self.assertEqual(self.nodes[ROUTER1].get_state(), 'router')
self.nodes[LEADER2].start()
time.sleep(5)
self.assertEqual(self.nodes[LEADER2].get_state(), 'leader')
ipaddrs = self.nodes[ROUTER1].get_addrs()
for ipaddr in ipaddrs:
if ipaddr[0:4] != 'fe80':
break
self.nodes[COMMISSIONER].panid_query('0xdead', '0xffffffff', ipaddr)
self.nodes[COMMISSIONER].panid_query('0xdead', '0xffffffff', 'ff33:0040:fdde:ad00:beef:0:0:1')
self.nodes[COMMISSIONER].ping(ipaddr)
if __name__ == '__main__':
unittest.main()
+5
View File
@@ -325,6 +325,11 @@ class Node:
self.send_command('netdataregister')
self.pexpect.expect('Done')
def panid_query(self, panid, mask, ipaddr):
cmd = 'commissioner panid ' + panid + ' ' + mask + ' ' + ipaddr
self.send_command(cmd)
self.pexpect.expect('Conflict:', timeout=8)
def scan(self):
self.send_command('scan')