Steering data. (#743)

This commit is contained in:
Jonathan Hui
2016-10-10 09:40:08 -07:00
committed by GitHub
parent 10f9204da2
commit f3ef4046db
13 changed files with 389 additions and 32 deletions
+2
View File
@@ -21,6 +21,7 @@
<ItemGroup>
<ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
<ClCompile Include="..\..\src\core\coap\coap_server.cpp" />
<ClCompile Include="..\..\src\core\common\crc16.cpp" />
<ClCompile Include="..\..\src\core\common\logging.cpp" />
<ClCompile Include="..\..\src\core\common\message.cpp" />
<ClCompile Include="..\..\src\core\common\tasklet.cpp" />
@@ -79,6 +80,7 @@
<ClInclude Include="..\..\src\core\coap\coap_header.hpp" />
<ClInclude Include="..\..\src\core\coap\coap_server.hpp" />
<ClInclude Include="..\..\src\core\common\code_utils.hpp" />
<ClInclude Include="..\..\src\core\common\crc16.hpp" />
<ClInclude Include="..\..\src\core\common\debug.hpp" />
<ClInclude Include="..\..\src\core\common\encoding.hpp" />
<ClInclude Include="..\..\src\core\common\logging.hpp" />
@@ -21,6 +21,7 @@
<ItemGroup>
<ClCompile Include="..\..\src\core\coap\coap_header.cpp" />
<ClCompile Include="..\..\src\core\coap\coap_server.cpp" />
<ClCompile Include="..\..\src\core\common\crc16.cpp" />
<ClCompile Include="..\..\src\core\common\logging.cpp" />
<ClCompile Include="..\..\src\core\common\message.cpp" />
<ClCompile Include="..\..\src\core\common\tasklet.cpp" />
@@ -79,6 +80,7 @@
<ClInclude Include="..\..\src\core\coap\coap_header.hpp" />
<ClInclude Include="..\..\src\core\coap\coap_server.hpp" />
<ClInclude Include="..\..\src\core\common\code_utils.hpp" />
<ClInclude Include="..\..\src\core\common\crc16.hpp" />
<ClInclude Include="..\..\src\core\common\debug.hpp" />
<ClInclude Include="..\..\src\core\common\encoding.hpp" />
<ClInclude Include="..\..\src\core\common\logging.hpp" />
+13 -12
View File
@@ -317,6 +317,18 @@ typedef struct otIp6Address otIp6Address;
#define OT_CHANNEL_ALL 0xffffffff ///< All channels
#define OT_STEERING_DATA_MAX_LENGTH 16 ///< Max steering data length (bytes)
/**
* This structure represents the steering data.
*
*/
typedef struct otSteeringData
{
uint8_t mLength;
uint8_t m8[OT_STEERING_DATA_MAX_LENGTH];
} otSteeringData;
/**
* This struct represents a received IEEE 802.15.4 Beacon.
*
@@ -326,6 +338,7 @@ typedef struct otActiveScanResult
otExtAddress mExtAddress; ///< IEEE 802.15.4 Extended Address
otNetworkName mNetworkName; ///< Thread Network Name
otExtendedPanId mExtendedPanId; ///< Thread Extended PAN ID
otSteeringData mSteeringData; ///< Steering Data
uint16_t mPanId; ///< IEEE 802.15.4 PAN ID
uint16_t mJoinerUdpPort; ///< Joiner UDP Port
uint8_t mChannel; ///< IEEE 802.15.4 Channel
@@ -404,18 +417,6 @@ typedef struct otOperationalDataset
bool mIsChannelMaskPage0Set : 1; ///< TRUE if Channel Mask Page 0 is set, FALSE otherwise.
} otOperationalDataset;
#define OT_STEERING_DATA_MAX_LENGTH 16 ///< Max steering data length (bytes)
/**
* This structure represents the steering data.
*
*/
typedef struct otSteeringData
{
uint8_t mLength;
uint8_t m8[OT_STEERING_DATA_MAX_LENGTH];
} otSteeringData;
/**
* This structure represents a Commissioning Dataset.
*
+2
View File
@@ -39,6 +39,7 @@ libopenthread_a_SOURCES = \
openthread.cpp \
coap/coap_header.cpp \
coap/coap_server.cpp \
common/crc16.cpp \
common/logging.cpp \
common/message.cpp \
common/tasklet.cpp \
@@ -115,6 +116,7 @@ noinst_HEADERS = \
coap/coap_header.hpp \
coap/coap_server.hpp \
common/code_utils.hpp \
common/crc16.hpp \
common/debug.hpp \
common/encoding.hpp \
common/logging.hpp \
+75
View File
@@ -0,0 +1,75 @@
/*
* 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 CRC16 computations.
*/
#include <common/crc16.hpp>
namespace Thread {
Crc16::Crc16(Polynomial aPolynomial)
{
mPolynomial = static_cast<uint16_t>(aPolynomial);
Init();
}
void Crc16::Init(void)
{
mCrc = 0xffff;
}
void Crc16::Update(uint8_t aByte)
{
uint8_t i;
mCrc = mCrc ^ static_cast<uint16_t>(aByte << 8);
i = 8;
do
{
if (mCrc & 0x8000)
{
mCrc = static_cast<uint16_t>(mCrc << 1) ^ mPolynomial;
}
else
{
mCrc = static_cast<uint16_t>(mCrc << 1);
}
}
while (--i);
}
uint16_t Crc16::Get(void) const
{
return mCrc;
}
} // namespace Thread
+91
View File
@@ -0,0 +1,91 @@
/*
* 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 CRC16 computations.
*/
#ifndef CRC16_HPP_
#define CRC16_HPP_
#include <stdint.h>
namespace Thread {
/**
* This class implements CRC16 computations.
*
*/
class Crc16
{
public:
enum Polynomial
{
kCcitt = 0x1021, ///< CRC16_CCITT
kAnsi = 0x8005, ///< CRC16-ANSI
};
/**
* This constructor initializes the object.
*
* @param[in] aPolynomial The polynomial value.
*
*/
Crc16(Polynomial aPolynomial);
/**
* This method initializes the CRC16 computation.
*
*/
void Init(void);
/*c*
* This method feeds a byte value into the CRC16 computation.
*
* @param[in] aByte The byte value.
*
*/
void Update(uint8_t aByte);
/**
* This method gets the current CRC16 value.
*
* @returns The current CRC16 value.
*
*/
uint16_t Get(void) const;
private:
uint16_t mPolynomial;
uint16_t mCrc;
};
} // namespace Thread
#endif // CRC16_HPP_
+112 -8
View File
@@ -43,6 +43,7 @@
#include <string.h>
#include <coap/coap_header.hpp>
#include <common/crc16.hpp>
#include <common/logging.hpp>
#include <meshcop/commissioner.hpp>
#include <meshcop/joiner_router.hpp>
@@ -81,7 +82,10 @@ ThreadError Commissioner::Start(void)
VerifyOrExit(mState == kStateDisabled, error = kThreadError_InvalidState);
SuccessOrExit(error = mSocket.Open(HandleUdpReceive, this));
mState = kStatePetition;
mTransmitAttempts = 0;
SendPetition();
exit:
@@ -90,10 +94,84 @@ exit:
ThreadError Commissioner::Stop(void)
{
ThreadError error = kThreadError_None;
VerifyOrExit(mState != kStateDisabled, error = kThreadError_InvalidState);
mState = kStateDisabled;
mTransmitAttempts = 0;
SendKeepAlive();
mTimer.Start(1000);
return kThreadError_None;
exit:
return error;
}
ThreadError Commissioner::SendCommissionerSet(void)
{
ThreadError error;
otCommissioningDataset dataset;
SteeringDataTlv steeringData;
VerifyOrExit(mState == kStateActive, error = kThreadError_InvalidState);
memset(&dataset, 0, sizeof(dataset));
// session id
dataset.mSessionId = mSessionId;
dataset.mIsSessionIdSet = true;
// compute bloom filter
steeringData.Init();
steeringData.Clear();
for (size_t i = 0; i < sizeof(mJoiners) / sizeof(mJoiners[0]); i++)
{
Crc16 ccitt(Crc16::kCcitt);
Crc16 ansi(Crc16::kAnsi);
if (!mJoiners[i].mValid)
{
continue;
}
if (mJoiners[i].mAny)
{
steeringData.SetLength(1);
steeringData.Set();
break;
}
for (size_t j = 0; j < sizeof(mJoiners[i].mExtAddress.m8); j++)
{
uint8_t byte = mJoiners[i].mExtAddress.m8[j];
ccitt.Update(byte);
ansi.Update(byte);
}
steeringData.SetBit(ccitt.Get() % steeringData.GetNumBits());
steeringData.SetBit(ansi.Get() % steeringData.GetNumBits());
}
// set bloom filter
memcpy(dataset.mSteeringData.m8, steeringData.GetValue(), steeringData.GetLength());
dataset.mSteeringData.mLength = steeringData.GetLength();
dataset.mIsSteeringDataSet = true;
SuccessOrExit(error = SendMgmtCommissionerSetRequest(dataset, NULL, 0));
exit:
return error;
}
void Commissioner::ClearJoiners(void)
{
for (size_t i = 0; i < sizeof(mJoiners) / sizeof(mJoiners[0]); i++)
{
mJoiners[i].mValid = false;
}
SendCommissionerSet();
}
ThreadError Commissioner::AddJoiner(const Mac::ExtAddress *aExtAddress, const char *aPSKd)
@@ -122,6 +200,9 @@ ThreadError Commissioner::AddJoiner(const Mac::ExtAddress *aExtAddress, const ch
strncpy(mJoiners[i].mPsk, aPSKd, sizeof(mJoiners[i].mPsk));
mJoiners[i].mValid = true;
SendCommissionerSet();
ExitNow(error = kThreadError_None);
}
@@ -153,6 +234,9 @@ ThreadError Commissioner::RemoveJoiner(const Mac::ExtAddress *aExtAddress)
}
mJoiners[i].mValid = false;
SendCommissionerSet();
ExitNow(error = kThreadError_None);
}
@@ -189,7 +273,6 @@ void Commissioner::HandleTimer(void)
case kStateActive:
SendKeepAlive();
mTimer.Start(5000);
break;
}
}
@@ -333,10 +416,19 @@ ThreadError Commissioner::SendPetition(void)
{
ThreadError error = kThreadError_None;
Coap::Header header;
Message *message;
Message *message = NULL;
Ip6::MessageInfo messageInfo;
CommissionerIdTlv commissionerId;
if (mTransmitAttempts >= kPetitionRetryCount)
{
mState = kStateDisabled;
ExitNow();
}
mTimer.Start(Timer::SecToMsec(kPetitionRetryDelay));
mTransmitAttempts++;
for (size_t i = 0; i < sizeof(mCoapToken); i++)
{
mCoapToken[i] = otPlatRandomGet() & 0xff;
@@ -379,11 +471,20 @@ ThreadError Commissioner::SendKeepAlive(void)
{
ThreadError error = kThreadError_None;
Coap::Header header;
Message *message;
Message *message = NULL;
Ip6::MessageInfo messageInfo;
StateTlv state;
CommissionerSessionIdTlv sessionId;
if (mTransmitAttempts >= kPetitionRetryCount)
{
mState = kStateDisabled;
ExitNow();
}
mTimer.Start(Timer::SecToMsec(kPetitionRetryDelay));
mTransmitAttempts++;
for (size_t i = 0; i < sizeof(mCoapToken); i++)
{
mCoapToken[i] = otPlatRandomGet() & 0xff;
@@ -582,16 +683,19 @@ void Commissioner::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &a
case kStatePetition:
SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kCommissionerSessionId, sizeof(sessionId), sessionId));
VerifyOrExit(sessionId.IsValid(), ;);
mSessionId = sessionId.GetCommissionerSessionId();
mState = kStateActive;
mTimer.Start(5000);
otLogInfoMeshCoP("received petition response\r\n");
mState = kStateActive;
mTransmitAttempts = 0;
mTimer.Start(Timer::SecToMsec(kKeepAliveTimeout) / 2);
break;
case kStateActive:
otLogInfoMeshCoP("received keep alive response\r\n");
mTransmitAttempts = 0;
mTimer.Start(Timer::SecToMsec(kKeepAliveTimeout) / 2);
break;
}
+16 -2
View File
@@ -79,6 +79,12 @@ public:
*/
ThreadError Stop(void);
/**
* This method clears all Joiner entries.
*
*/
void ClearJoiners(void);
/**
* This method adds a Joiner entry.
*
@@ -152,6 +158,14 @@ public:
PanIdQueryClient mPanIdQuery;
private:
enum
{
kPetitionAttemptDelay = 5, ///< COMM_PET_ATTEMPT_DELAY (seconds)
kPetitionRetryCount = 2, ///< COMM_PET_RETRY_COUNT
kPetitionRetryDelay = 1, ///< COMM_PET_RETRY_DELAY (seconds)
kKeepAliveTimeout = 50, ///< TIMEOUT_COMM_PET (seconds)
};
static void HandleTimer(void *aContext);
void HandleTimer(void);
@@ -179,7 +193,7 @@ private:
void SendJoinFinalizeResponse(const Coap::Header &aRequestHeader, StateTlv::State aState);
void SendDatasetChangedResponse(const Coap::Header &aRequestHeader, const Ip6::MessageInfo &aMessageInfo);
ThreadError SendCommissionerSet(void);
ThreadError SendPetition(void);
ThreadError SendKeepAlive(void);
@@ -208,6 +222,7 @@ private:
Message *mTransmitMessage;
Timer mTimer;
Tasklet mTransmitTask;
uint8_t mTransmitAttempts;
bool mSendKek;
Ip6::UdpSocket mSocket;
@@ -218,7 +233,6 @@ private:
Coap::Resource mDatasetChanged;
Coap::Server &mCoapServer;
ThreadNetif &mNetif;
bool mIsSendMgmtCommRequest;
};
+25 -4
View File
@@ -43,6 +43,7 @@
#include <stdio.h>
#include <common/code_utils.hpp>
#include <common/crc16.hpp>
#include <common/encoding.hpp>
#include <common/logging.hpp>
#include <meshcop/joiner.hpp>
@@ -102,10 +103,30 @@ void Joiner::HandleDiscoverResult(otActiveScanResult *aResult)
{
if (aResult != NULL)
{
mJoinerUdpPort = aResult->mJoinerUdpPort;
mJoinerRouterPanId = aResult->mPanId;
mJoinerRouterChannel = aResult->mChannel;
memcpy(&mJoinerRouter, &aResult->mExtAddress, sizeof(mJoinerRouter));
SteeringDataTlv steeringData;
Mac::ExtAddress extAddress;
Crc16 ccitt(Crc16::kCcitt);
Crc16 ansi(Crc16::kAnsi);
mNetif.GetMac().GetHashMacAddress(&extAddress);
for (size_t i = 0; i < sizeof(extAddress); i++)
{
ccitt.Update(extAddress.m8[i]);
ansi.Update(extAddress.m8[i]);
}
steeringData.SetLength(aResult->mSteeringData.mLength);
memcpy(steeringData.GetValue(), aResult->mSteeringData.m8, steeringData.GetLength());
if (steeringData.GetBit(ccitt.Get() % steeringData.GetNumBits()) &&
steeringData.GetBit(ansi.Get() % steeringData.GetNumBits()))
{
mJoinerUdpPort = aResult->mJoinerUdpPort;
mJoinerRouterPanId = aResult->mPanId;
mJoinerRouterChannel = aResult->mChannel;
memcpy(&mJoinerRouter, &aResult->mExtAddress, sizeof(mJoinerRouter));
}
}
else
{
+19 -5
View File
@@ -568,13 +568,27 @@ public:
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() == sizeof(*this) - sizeof(Tlv); }
bool IsValid(void) const { return GetLength() <= sizeof(*this) - sizeof(Tlv); }
/**
* This method sets all bits in the Bloom Filter to zero.
*
*/
void Clear(void) { memset(mSteeringData, 0, sizeof(mSteeringData)); }
void Clear(void) { memset(mSteeringData, 0, GetLength()); }
/**
* Ths method sets all bits in the Bloom Filter to one.
*
*/
void Set(void) { memset(mSteeringData, 0xff, GetLength()); }
/**
* This method returns the number of bits in the Bloom Filter.
*
* @returns The number of bits in the Bloom Filter.
*
*/
uint8_t GetNumBits(void) const { return GetLength() * 8; }
/**
* This method indicates whether or not bit @p aBit is set.
@@ -585,7 +599,7 @@ public:
* @retval FALSE If bit @p aBit is not set.
*
*/
bool GetBit(uint8_t aBit) const { return (mSteeringData[aBit / 8] & (1 << (aBit % 8))) != 0; }
bool GetBit(uint8_t aBit) const { return (mSteeringData[GetLength() - 1 - (aBit / 8)] & (1 << (aBit % 8))) != 0; }
/**
* This method clears bit @p aBit.
@@ -593,7 +607,7 @@ public:
* @param[in] aBit The bit offset.
*
*/
void ClearBit(uint8_t aBit) { mSteeringData[aBit / 8] &= ~(1 << (aBit % 8)); }
void ClearBit(uint8_t aBit) { mSteeringData[GetLength() - 1 - (aBit / 8)] &= ~(1 << (aBit % 8)); }
/**
* This method sets bit @p aBit.
@@ -601,7 +615,7 @@ public:
* @param[in] aBit The bit offset.
*
*/
void SetBit(uint8_t aBit) { mSteeringData[aBit / 8] |= 1 << (aBit % 8); }
void SetBit(uint8_t aBit) { mSteeringData[GetLength() - 1 - (aBit / 8)] |= 1 << (aBit % 8); }
private:
uint8_t mSteeringData[OT_STEERING_DATA_MAX_LENGTH];
+29
View File
@@ -2406,6 +2406,8 @@ ThreadError Mle::SendDiscoveryResponse(const Ip6::Address &aDestination, uint16_
MeshCoP::ExtendedPanIdTlv extPanId;
MeshCoP::NetworkNameTlv networkName;
MeshCoP::JoinerUdpPortTlv joinerUdpPort;
uint8_t *cur;
uint8_t length;
VerifyOrExit((message = mSocket.NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
@@ -2434,6 +2436,25 @@ ThreadError Mle::SendDiscoveryResponse(const Ip6::Address &aDestination, uint16_
networkName.SetNetworkName(mMac.GetNetworkName());
SuccessOrExit(error = message->Append(&networkName, sizeof(tlv) + networkName.GetLength()));
// Steering Data TLV
if ((cur = mNetif.GetNetworkDataLeader().GetCommissioningData(length)) != NULL)
{
uint8_t *end = cur + length;
while (cur < end)
{
MeshCoP::Tlv *meshcop = reinterpret_cast<MeshCoP::Tlv *>(cur);
if (meshcop->GetType() == MeshCoP::Tlv::kSteeringData)
{
SuccessOrExit(message->Append(meshcop, sizeof(*meshcop) + meshcop->GetLength()));
break;
}
cur += sizeof(*meshcop) + meshcop->GetLength();
}
}
// Joiner UDP Port TLV
joinerUdpPort.Init();
joinerUdpPort.SetUdpPort(mJoinerRouter.GetJoinerUdpPort());
@@ -2465,6 +2486,7 @@ ThreadError Mle::HandleDiscoveryResponse(const Message &aMessage, const Ip6::Mes
MeshCoP::DiscoveryResponseTlv discoveryResponse;
MeshCoP::ExtendedPanIdTlv extPanId;
MeshCoP::NetworkNameTlv networkName;
MeshCoP::SteeringDataTlv steeringData;
MeshCoP::JoinerUdpPortTlv JoinerUdpPort;
otActiveScanResult result;
uint16_t offset;
@@ -2528,6 +2550,13 @@ ThreadError Mle::HandleDiscoveryResponse(const Message &aMessage, const Ip6::Mes
memcpy(&result.mNetworkName, networkName.GetNetworkName(), networkName.GetLength());
break;
case MeshCoP::Tlv::kSteeringData:
aMessage.Read(offset, sizeof(steeringData), &steeringData);
VerifyOrExit(steeringData.IsValid(), error = kThreadError_Parse);
result.mSteeringData.mLength = steeringData.GetLength();
memcpy(result.mSteeringData.m8, steeringData.GetValue(), result.mSteeringData.mLength);
break;
case MeshCoP::Tlv::kJoinerUdpPort:
aMessage.Read(offset, sizeof(JoinerUdpPort), &JoinerUdpPort);
VerifyOrExit(JoinerUdpPort.IsValid(), error = kThreadError_Parse);
@@ -60,7 +60,8 @@ class Cert_8_1_01_Commissioning(unittest.TestCase):
time.sleep(5)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
self.nodes[COMMISSIONER].commissioner_start()
self.nodes[COMMISSIONER].commissioner_add_joiner('*', 'openthread')
time.sleep(3)
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_hashmacaddr(), 'openthread')
self.nodes[JOINER].interface_up()
self.nodes[JOINER].joiner_start('openthread')
@@ -60,6 +60,7 @@ class Cert_8_1_02_Commissioning(unittest.TestCase):
time.sleep(5)
self.assertEqual(self.nodes[COMMISSIONER].get_state(), 'leader')
self.nodes[COMMISSIONER].commissioner_start()
time.sleep(3)
self.nodes[COMMISSIONER].commissioner_add_joiner(self.nodes[JOINER].get_hashmacaddr(), 'openthread')
self.nodes[JOINER].interface_up()