mirror of
https://github.com/espressif/openthread.git
synced 2026-07-27 14:27:47 +00:00
Implement PAN ID Query/Conflict. (#556)
This commit is contained in:
@@ -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);
|
||||
|
||||
/**
|
||||
* @}
|
||||
*
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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[];
|
||||
|
||||
|
||||
@@ -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 \
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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_
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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_
|
||||
|
||||
@@ -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
@@ -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()
|
||||
@@ -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')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user