Implement MLE Discovery Request and Response. (#322)

This commit is contained in:
Jonathan Hui
2016-08-03 13:16:35 -07:00
committed by GitHub
parent 2fe487f0e8
commit b326f01821
18 changed files with 1149 additions and 95 deletions
+2
View File
@@ -160,6 +160,8 @@ typedef struct otExtAddress
*
*/
#define OT_PANID_BROADCAST 0xffff ///< IEEE 802.15.4 Broadcast PAN ID
#define OT_CHANNEL_11_MASK (1 << 11) ///< Channel 11
#define OT_CHANNEL_12_MASK (1 << 12) ///< Channel 12
#define OT_CHANNEL_13_MASK (1 << 13) ///< Channel 13
+23 -1
View File
@@ -232,7 +232,7 @@ typedef void (*otHandleActiveScanResult)(otActiveScanResult *aResult);
*
* @param[in] aScanChannels A bit vector indicating which channels to scan (e.g. OT_CHANNEL_11_MASK).
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel.
* @param[in] aCallback A pointer to a function that is called when a beacon is received or the scan completes.
* @param[in] aCallback A pointer to a function called on receiving a beacon or scan completes.
*
* @retval kThreadError_None Accepted the Active Scan request.
* @retval kThreadError_Busy Already performing an Active Scan.
@@ -247,6 +247,28 @@ ThreadError otActiveScan(uint32_t aScanChannels, uint16_t aScanDuration, otHandl
*/
bool otActiveScanInProgress(void);
/**
* This function starts a Thread Discovery scan.
*
* @param[in] aScanChannels A bit vector indicating which channels to scan (e.g. OT_CHANNEL_11_MASK).
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel.
* @param[in] aPanId The PAN ID filter (set to Broadcast PAN to disable filter).
* @param[in] aCallback A pointer to a function called on receiving an MLE Discovery Response or scan completes.
*
* @retval kThreadError_None Accepted the Thread Discovery request.
* @retval kThreadError_Busy Already performing an Thread Discovery.
*
*/
ThreadError otDiscover(uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanid,
otHandleActiveScanResult aCallback);
/**
* This function determines if an MLE Thread Discovery is currently in progress.
*
* @returns true if an active scan is in progress.
*/
bool otDiscoverInProgress(void);
/**
* @}
*
+18 -3
View File
@@ -12,6 +12,7 @@ OpenThread test scripts use the CLI to execute test cases.
* [childtimeout](#childtimeout)
* [contextreusedelay](#contextreusedelay)
* [counter](#counter)
* [discover](#discover)
* [eidcache](#eidcache)
* [extaddr](#extaddr)
* [extpanid](#extpanid)
@@ -168,6 +169,20 @@ RxTotal: 11
RxErrOther: 0
```
### discover \[channel\]
Perform an MLE Discovery operation.
* channel: The channel to discover on. If no channel is provided, the discovery will cover all valid channels.
```bash
> discover
| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |
+---+------------------+------------------+------+------------------+----+-----+-----+
| 0 | OpenThread | dead00beef00cafe | ffff | f1d92a82c8d8fe43 | 11 | -20 | 0 |
Done
```
### eidcache
Print the EID-to-RLOC cache entries.
@@ -574,9 +589,9 @@ Perform an IEEE 802.15.4 Active Scan.
```bash
> scan
| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm |
+---+------------------+------------------+------+------------------+----+-----+
| 0 | OpenThread | dead00beef00cafe | ffff | f1d92a82c8d8fe43 | 11 | -20 |
| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |
+---+------------------+------------------+------+------------------+----+-----+-----+
| 0 | OpenThread | dead00beef00cafe | ffff | f1d92a82c8d8fe43 | 11 | -20 | 0 |
Done
```
+26 -2
View File
@@ -56,6 +56,7 @@ const struct Command Interpreter::sCommands[] =
{ "childtimeout", &ProcessChildTimeout },
{ "contextreusedelay", &ProcessContextIdReuseDelay },
{ "counter", &ProcessCounters },
{ "discover", &ProcessDiscover },
{ "eidcache", &ProcessEidCache },
{ "extaddr", &ProcessExtAddress },
{ "extpanid", &ProcessExtPanId },
@@ -353,6 +354,28 @@ void Interpreter::ProcessCounters(int argc, char *argv[])
}
}
void Interpreter::ProcessDiscover(int argc, char *argv[])
{
ThreadError error = kThreadError_None;
uint32_t scanChannels = 0;
long value;
if (argc > 0)
{
SuccessOrExit(error = ParseLong(argv[0], value));
scanChannels = 1 << value;
}
SuccessOrExit(error = otDiscover(scanChannels, 0, OT_PANID_BROADCAST, &HandleActiveScanResult));
sServer->OutputFormat("| J | Network Name | Extended PAN | PAN | MAC Address | Ch | dBm | LQI |\r\n");
sServer->OutputFormat("+---+------------------+------------------+------+------------------+----+-----+-----+\r\n");
return;
exit:
AppendResult(error);
}
void Interpreter::ProcessEidCache(int argc, char *argv[])
{
otEidCacheEntry entry;
@@ -1246,7 +1269,9 @@ void Interpreter::HandleActiveScanResult(otActiveScanResult *aResult)
if (aResult->mExtPanId != NULL)
{
sServer->OutputFormat("| ");
OutputBytes(aResult->mExtPanId, OT_EXT_PAN_ID_SIZE);
sServer->OutputFormat(" ");
}
else
{
@@ -1254,9 +1279,8 @@ void Interpreter::HandleActiveScanResult(otActiveScanResult *aResult)
}
sServer->OutputFormat("| %04x | ", aResult->mPanId);
OutputBytes(aResult->mExtAddress.m8, OT_EXT_ADDRESS_SIZE);
sServer->OutputFormat("| %2d ", aResult->mChannel);
sServer->OutputFormat(" | %2d ", aResult->mChannel);
sServer->OutputFormat("| %3d ", aResult->mRssi);
sServer->OutputFormat("| %3d |\r\n", aResult->mLqi);
+1
View File
@@ -93,6 +93,7 @@ private:
static void ProcessChildTimeout(int argc, char *argv[]);
static void ProcessContextIdReuseDelay(int argc, char *argv[]);
static void ProcessCounters(int argc, char *argv[]);
static void ProcessDiscover(int argc, char *argv[]);
static void ProcessEidCache(int argc, char *argv[]);
static void ProcessExtAddress(int argc, char *argv[]);
static void ProcessExtPanId(int argc, char *argv[]);
+1
View File
@@ -100,6 +100,7 @@ noinst_HEADERS = \
thread/key_manager.hpp \
thread/link_quality.hpp \
thread/lowpan.hpp \
thread/meshcop_tlvs.hpp \
thread/mesh_forwarder.hpp \
thread/mle.hpp \
thread/mle_constants.hpp \
+40 -10
View File
@@ -440,16 +440,6 @@ void Message::SetDatagramTag(uint16_t aTag)
mInfo.mDatagramTag = aTag;
}
uint8_t Message::GetTimeout(void) const
{
return mInfo.mTimeout;
}
void Message::SetTimeout(uint8_t aTimeout)
{
mInfo.mTimeout = aTimeout;
}
bool Message::GetChildMask(uint8_t aChildIndex) const
{
assert(aChildIndex < sizeof(mInfo.mChildMask) * 8);
@@ -484,6 +474,26 @@ exit:
return rval;
}
uint16_t Message::GetPanId(void) const
{
return mInfo.mPanId;
}
void Message::SetPanId(uint16_t aPanId)
{
mInfo.mPanId = aPanId;
}
uint8_t Message::GetTimeout(void) const
{
return mInfo.mTimeout;
}
void Message::SetTimeout(uint8_t aTimeout)
{
mInfo.mTimeout = aTimeout;
}
bool Message::GetDirectTransmission(void) const
{
return mInfo.mDirectTx;
@@ -509,6 +519,26 @@ 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;
}
uint16_t Message::UpdateChecksum(uint16_t aChecksum, uint16_t aOffset, uint16_t aLength) const
{
Buffer *curBuffer;
+71 -16
View File
@@ -108,13 +108,16 @@ struct MessageInfo
uint16_t mLength; ///< Number of bytes within the message.
uint16_t mOffset; ///< A byte offset within the message.
uint16_t mDatagramTag; ///< The datagram tag used for 6LoWPAN fragmentation.
uint8_t mTimeout; ///< Seconds remaining before dropping the message.
uint8_t mChildMask[8]; ///< A bit-vector to indicate which sleepy children need to receive this message.
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.
uint8_t mType : 2; ///< Identifies the type of message.
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.
};
/**
@@ -353,20 +356,6 @@ public:
*/
void SetDatagramTag(uint16_t aTag);
/**
* This method returns the timeout used for 6LoWPAN reassembly.
*
* @returns The time remaining in seconds.
*
*/
uint8_t GetTimeout(void) const;
/**
* This method sets the timeout used for 6LoWPAN reassembly.
*
*/
void SetTimeout(uint8_t aTimeout);
/**
* This method returns whether or not the message forwarding is scheduled for the child.
*
@@ -403,6 +392,38 @@ public:
*/
bool IsChildPending(void) const;
/**
* This method returns the IEEE 802.15.4 Destination PAN ID.
*
* @returns The IEEE 802.15.4 Destination PAN ID.
*
*/
uint16_t GetPanId(void) const;
/**
* This method sets the IEEE 802.15.4 Destination PAN ID.
*
* @param[in] aPanId The IEEE 802.15.4 Destination PAN ID.
*
*/
void SetPanId(uint16_t aPanId);
/**
* This method returns the timeout used for 6LoWPAN reassembly.
*
* @returns The time remaining in seconds.
*
*/
uint8_t GetTimeout(void) const;
/**
* This method sets the timeout used for 6LoWPAN reassembly.
*
* @param[in] aTimeout The timeout value.
*
*/
void SetTimeout(uint8_t aTimeout);
/**
* This method returns whether or not message forwarding is scheduled for direct transmission.
*
@@ -441,6 +462,40 @@ 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 is used to update a checksum value.
*
+4 -3
View File
@@ -382,15 +382,16 @@ exit:
ThreadError Frame::SetSrcPanId(PanId aPanId)
{
ThreadError error = kThreadError_None;
uint8_t *buf;
buf = FindSrcPanId();
assert(buf != NULL);
VerifyOrExit((buf = FindSrcPanId()) != NULL, error = kThreadError_Parse);
buf[0] = aPanId;
buf[1] = aPanId >> 8;
return kThreadError_None;
exit:
return error;
}
uint8_t *Frame::FindSrcAddr(void)
+14
View File
@@ -60,6 +60,7 @@ extern "C" {
static otDEFINE_ALIGNED_VAR(sThreadNetifRaw, sizeof(ThreadNetif), uint64_t);
static void HandleActiveScanResult(void *aContext, Mac::Frame *aFrame);
static void HandleMleDiscover(otActiveScanResult *aResult, void *aContext);
void otProcessNextTasklet(void)
{
@@ -813,6 +814,19 @@ exit:
return;
}
ThreadError otDiscover(uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanId,
otHandleActiveScanResult aCallback)
{
return sThreadNetif->GetMle().Discover(aScanChannels, aScanDuration, aPanId, &HandleMleDiscover,
reinterpret_cast<void *>(aCallback));
}
void HandleMleDiscover(otActiveScanResult *aResult, void *aContext)
{
otHandleActiveScanResult handler = reinterpret_cast<otHandleActiveScanResult>(aContext);
handler(aResult);
}
void otSetReceiveIp6DatagramCallback(otReceiveIp6DatagramCallback aCallback)
{
Ip6::Ip6::SetReceiveDatagramCallback(aCallback);
+88 -4
View File
@@ -53,6 +53,7 @@ namespace Thread {
MeshForwarder::MeshForwarder(ThreadNetif &aThreadNetif):
mMacReceiver(&HandleReceivedFrame, this),
mMacSender(&HandleFrameRequest, &HandleSentFrame, this),
mDiscoverTimer(&HandleDiscoverTimer, this),
mPollTimer(&HandlePollTimer, this),
mReassemblyTimer(&HandleReassemblyTimer, this),
mScheduleTransmissionTask(ScheduleTransmissionTask, this),
@@ -461,8 +462,6 @@ ThreadError MeshForwarder::UpdateIp6Route(Message &aMessage)
switch (mMle.GetDeviceState())
{
case Mle::kDeviceStateDisabled:
break;
case Mle::kDeviceStateDetached:
if (ip6Header.GetDestination().IsLinkLocal() || ip6Header.GetDestination().IsLinkLocalMulticast())
{
@@ -661,6 +660,25 @@ ThreadError MeshForwarder::HandleFrameRequest(Mac::Frame &aFrame)
switch (mSendMessage->GetType())
{
case Message::kTypeIp6:
if (mSendMessage->IsMleDiscoverRequest())
{
if (!mScanning)
{
mScanChannel = kPhyMinChannel;
mRestoreChannel = mMac.GetChannel();
mScanning = true;
}
while ((mScanChannels & 1) == 0)
{
mScanChannels >>= 1;
mScanChannel++;
}
mMac.SetChannel(mScanChannel);
aFrame.SetChannel(mScanChannel);
}
SendFragment(*mSendMessage, aFrame);
assert(aFrame.GetLength() != 7);
break;
@@ -772,6 +790,7 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
int payloadLength;
int hcLength;
uint16_t fragmentLength;
uint16_t dstpan;
if (mAddMeshHeader)
{
@@ -787,7 +806,7 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
}
// initialize MAC header
fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfPanidCompression | Mac::Frame::kFcfFrameVersion2006;
fcf = Mac::Frame::kFcfFrameData | Mac::Frame::kFcfFrameVersion2006;
fcf |= (mMacDest.mLength == 2) ? Mac::Frame::kFcfDstAddrShort : Mac::Frame::kFcfDstAddrExt;
fcf |= (mMacSource.mLength == 2) ? Mac::Frame::kFcfSrcAddrShort : Mac::Frame::kFcfSrcAddrExt;
@@ -802,8 +821,23 @@ ThreadError MeshForwarder::SendFragment(Message &aMessage, Mac::Frame &aFrame)
fcf |= Mac::Frame::kFcfSecurityEnabled;
}
if (aMessage.IsMleDiscoverRequest() || aMessage.IsMleDiscoverResponse())
{
dstpan = aMessage.GetPanId();
}
else
{
dstpan = mMac.GetPanId();
}
if (dstpan == mMac.GetPanId())
{
fcf |= Mac::Frame::kFcfPanidCompression;
}
aFrame.InitMacHeader(fcf, Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32);
aFrame.SetDstPanId(mMac.GetPanId());
aFrame.SetDstPanId(dstpan);
aFrame.SetSrcPanId(mMac.GetPanId());
if (mMacDest.mLength == 2)
{
@@ -961,6 +995,13 @@ void MeshForwarder::HandleSentFrame(Mac::Frame &aFrame)
mSendMessage->ClearDirectTransmission();
mSendMessage->SetOffset(0);
}
if (mSendMessage->IsMleDiscoverRequest())
{
mSendBusy = true;
mDiscoverTimer.Start(mScanDuration);
ExitNow();
}
}
if (mSendMessage->GetDirectTransmission() == false && mSendMessage->IsChildPending() == false)
@@ -975,6 +1016,44 @@ exit:
{}
}
void MeshForwarder::SetDiscoverParameters(uint32_t aScanChannels, uint16_t aScanDuration)
{
mScanChannels = (aScanChannels == 0) ? static_cast<uint32_t>(Mac::kScanChannelsAll) : aScanChannels;
mScanDuration = (aScanDuration == 0) ? static_cast<uint16_t>(Mac::kScanDurationDefault) : aScanDuration;
}
void MeshForwarder::HandleDiscoverTimer(void *aContext)
{
MeshForwarder *obj = static_cast<MeshForwarder *>(aContext);
obj->HandleDiscoverTimer();
}
void MeshForwarder::HandleDiscoverTimer(void)
{
do
{
mScanChannels >>= 1;
mScanChannel++;
if (mScanChannel > kPhyMaxChannel)
{
mSendQueue.Dequeue(*mSendMessage);
Message::Free(*mSendMessage);
mMac.SetChannel(mRestoreChannel);
mScanning = false;
mMle.HandleDiscoverComplete();
ExitNow();
}
}
while ((mScanChannels & 1) == 0);
mSendMessage->SetDirectTransmission();
exit:
mSendBusy = false;
mScheduleTransmissionTask.Post();
}
void MeshForwarder::HandleReceivedFrame(void *aContext, Mac::Frame &aFrame, ThreadError aError)
{
MeshForwarder *obj = reinterpret_cast<MeshForwarder *>(aContext);
@@ -1028,6 +1107,8 @@ void MeshForwarder::HandleReceivedFrame(Mac::Frame &aFrame, ThreadError aError)
}
SuccessOrExit(aFrame.GetDstAddr(macDest));
aFrame.GetSrcPanId(messageInfo.mPanId);
messageInfo.mChannel = aFrame.GetChannel();
messageInfo.mRss = aFrame.GetPower();
messageInfo.mLqi = aFrame.GetLqi();
messageInfo.mLinkSecurity = aFrame.GetSecurityEnabled();
@@ -1117,6 +1198,7 @@ void MeshForwarder::HandleMesh(uint8_t *aFrame, uint8_t aFrameLength, const Thre
SuccessOrExit(error = message->SetLength(aFrameLength));
message->Write(0, aFrameLength, aFrame);
message->SetLinkSecurityEnabled(aMessageInfo.mLinkSecurity);
message->SetPanId(aMessageInfo.mPanId);
SendMessage(*message);
}
@@ -1175,6 +1257,7 @@ void MeshForwarder::HandleFragment(uint8_t *aFrame, uint8_t aFrameLength,
VerifyOrExit((message = Message::New(Message::kTypeIp6, 0)) != NULL, error = kThreadError_NoBufs);
message->SetLinkSecurityEnabled(aMessageInfo.mLinkSecurity);
message->SetPanId(aMessageInfo.mPanId);
headerLength = mLowpan.Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, datagramLength);
VerifyOrExit(headerLength > 0, error = kThreadError_NoBufs);
@@ -1279,6 +1362,7 @@ void MeshForwarder::HandleLowpanHC(uint8_t *aFrame, uint8_t aFrameLength,
VerifyOrExit((message = Message::New(Message::kTypeIp6, 0)) != NULL, ;);
message->SetLinkSecurityEnabled(aMessageInfo.mLinkSecurity);
message->SetPanId(aMessageInfo.mPanId);
headerLength = mLowpan.Decompress(*message, aMacSource, aMacDest, aFrame, aFrameLength, 0);
VerifyOrExit(headerLength > 0, ;);
+18
View File
@@ -140,6 +140,15 @@ public:
*/
void SetPollPeriod(uint32_t aPeriod);
/**
* This method sets the scan parameters for MLE Discovery Request messages.
*
* @param[in] aScanChannels A bit vector indicating which channels to scan.
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel.
*
*/
void SetDiscoverParameters(uint32_t aScanChannels, uint16_t aScanDuration);
private:
enum
{
@@ -178,6 +187,8 @@ private:
static void HandleSentFrame(void *aContext, Mac::Frame &aFrame);
void HandleSentFrame(Mac::Frame &aFrame);
static void HandleDiscoverTimer(void *aContext);
void HandleDiscoverTimer(void);
static void HandleReassemblyTimer(void *aContext);
void HandleReassemblyTimer(void);
static void HandlePollTimer(void *aContext);
@@ -188,6 +199,7 @@ private:
Mac::Receiver mMacReceiver;
Mac::Sender mMacSender;
Timer mDiscoverTimer;
Timer mPollTimer;
Timer mReassemblyTimer;
@@ -210,6 +222,12 @@ private:
Tasklet mScheduleTransmissionTask;
bool mEnabled;
uint32_t mScanChannels;
uint16_t mScanDuration;
uint8_t mScanChannel;
uint8_t mRestoreChannel;
bool mScanning;
ThreadNetif &mNetif;
AddressResolver &mAddressResolver;
Lowpan::Lowpan &mLowpan;
+367
View File
@@ -0,0 +1,367 @@
/*
* 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 generating and processing MeshCoP TLVs.
*
*/
#ifndef MESHCOP_TLVS_HPP_
#define MESHCOP_TLVS_HPP_
#include <string.h>
#include <openthread-types.h>
#include <common/encoding.hpp>
using Thread::Encoding::BigEndian::HostSwap16;
namespace Thread {
namespace MeshCoP {
/**
* This class implements MeshCoP TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class Tlv
{
public:
/**
* MeshCoP TLV Types.
*
*/
enum Type
{
kExtendedPanId = 2, ///< Extended PAN ID TLV
kNetworkName = 3, ///< Newtork Name TLV
kDiscoveryRequest = 128, ///< Discovery Request TLV
kDiscoveryResponse = 129, ///< Discovery Response TLV
};
/**
* This method returns the Type value.
*
* @returns The Type value.
*
*/
Type GetType(void) const { return static_cast<Type>(mType); }
/**
* This method sets the Type value.
*
* @param[in] aType The Type value.
*
*/
void SetType(Type aType) { mType = static_cast<uint8_t>(aType); }
/**
* This method returns the Length value.
*
*/
uint8_t GetLength(void) const { return mLength; }
/**
* This method sets the Length value.
*
* @param[in] aLength The Length value.
*
*/
void SetLength(uint8_t aLength) { mLength = aLength; }
/**
* This method returns a pointer to the Value.
*
* @returns A pointer to the value.
*
*/
uint8_t *GetValue() { return reinterpret_cast<uint8_t *>(this) + sizeof(Tlv); }
/**
* This method returns a pointer to the next TLV.
*
* @returns A pointer to the next TLV.
*
*/
Tlv *GetNext() {
return reinterpret_cast<Tlv *>(reinterpret_cast<uint8_t *>(this) + sizeof(*this) + mLength);
}
private:
uint8_t mType;
uint8_t mLength;
} OT_TOOL_PACKED_END;
/**
* This class implements Extended PAN ID TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class ExtendedPanIdTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kExtendedPanId); 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 Extended PAN ID value.
*
* @returns The Extended PAN ID value.
*
*/
const uint8_t *GetExtendedPanId(void) const { return mExtendedPanId; }
/**
* This method sets the Extended PAN ID value.
*
* @param[in] aExtendedPanId A pointer to the Extended PAN ID value.
*
*/
void SetExtendedPanId(const uint8_t *aExtendedPanId) {
memcpy(mExtendedPanId, aExtendedPanId, OT_EXT_PAN_ID_SIZE);
}
private:
uint8_t mExtendedPanId[OT_EXT_PAN_ID_SIZE];
} OT_TOOL_PACKED_END;
/**
* This class implements Network Name TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class NetworkNameTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kNetworkName); SetLength(sizeof(*this) - sizeof(Tlv)); }
/**
* This method indicates whether or not the TLV appears to be well-formed.
*
* @retval TRUE If the TLV appears to be well-formed.
* @retval FALSE If the TLV does not appear to be well-formed.
*
*/
bool IsValid(void) const { return GetLength() <= sizeof(*this) - sizeof(Tlv); }
/**
* This method returns the Network Name value.
*
* @returns The Network Name value.
*
*/
const char *GetNetworkName(void) const { return mNetworkName; }
/**
* This method sets the Network Name value.
*
* @param[in] aNetworkName A pointer to the Network Name value.
*
*/
void SetNetworkName(const char *aNetworkName) {
int length = strnlen(aNetworkName, sizeof(mNetworkName));
memcpy(mNetworkName, aNetworkName, length);
SetLength(length);
}
private:
char mNetworkName[OT_NETWORK_NAME_SIZE];
} OT_TOOL_PACKED_END;
/**
* This class implements Discovery Request TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class DiscoveryRequestTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kDiscoveryRequest); SetLength(sizeof(*this) - sizeof(Tlv)); mReserved = 0; }
/**
* 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 Version value.
*
* @returns The Version value.
*
*/
uint8_t GetVersion(void) const { return mFlags >> kVersionOffset; }
/**
* This method sets the Version value.
*
* @param[in] aVersion The Version value.
*
*/
void SetVersion(uint8_t aVersion) { mFlags = (mFlags & ~kVersionMask) | (aVersion << kVersionOffset); }
/**
* This method indicates whether or not the Joiner flag is set.
*
* @retval TRUE If the Joiner flag is set.
* @retval FALSE If the Joiner flag is not set.
*
*/
bool IsJoiner(void) { return mFlags & kJoinerMask; }
/**
* This method sets the Joiner flag.
*
* @param[in] aJoiner TRUE if set, FALSE otherwise.
*
*/
void SetJoiner(bool aJoiner) {
if (aJoiner) {
mFlags |= kJoinerMask;
}
else {
mFlags &= ~kJoinerMask;
}
}
private:
enum
{
kVersionOffset = 4,
kVersionMask = 0xf << kVersionOffset,
kJoinerOffset = 3,
kJoinerMask = 1 << kJoinerOffset,
};
uint8_t mFlags;
uint8_t mReserved;
} OT_TOOL_PACKED_END;
/**
* This class implements Discovery Response TLV generation and parsing.
*
*/
OT_TOOL_PACKED_BEGIN
class DiscoveryResponseTlv: public Tlv
{
public:
/**
* This method initializes the TLV.
*
*/
void Init(void) { SetType(kDiscoveryResponse); SetLength(sizeof(*this) - sizeof(Tlv)); mReserved = 0; }
/**
* 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 Version value.
*
* @returns The Version value.
*
*/
uint8_t GetVersion(void) const { return mFlags >> kVersionOffset; }
/**
* This method sets the Version value.
*
* @param[in] aVersion The Version value.
*
*/
void SetVersion(uint8_t aVersion) { mFlags = (mFlags & ~kVersionMask) | (aVersion << kVersionOffset); }
/**
* This method indicates whether or not the Native Commissioner flag is set.
*
* @retval TRUE If the Native Commissioner flag is set.
* @retval FALSE If the Native Commissioner flag is not set.
*
*/
bool IsNativeCommissioner(void) { return mFlags & kNativeMask; }
/**
* This method sets the Native Commissioner flag.
*
* @param[in] aNativeCommissioner TRUE if set, FALSE otherwise.
*
*/
void SetNativeCommissioner(bool aNativeCommissioner) {
if (aNativeCommissioner) {
mFlags |= kNativeMask;
}
else {
mFlags &= ~kNativeMask;
}
}
private:
enum
{
kVersionOffset = 4,
kVersionMask = 0xf << kVersionOffset,
kNativeOffset = 3,
kNativeMask = 1 << kNativeOffset,
};
uint8_t mFlags;
uint8_t mReserved;
} OT_TOOL_PACKED_END;
} // namespace MeshCoP
} // namespace Thread
#endif // MESHCOP_TLVS_HPP_
+359 -43
View File
@@ -43,6 +43,7 @@
#include <platform/radio.h>
#include <platform/random.h>
#include <thread/address_resolver.hpp>
#include <thread/meshcop_tlvs.hpp>
#include <thread/key_manager.hpp>
#include <thread/mle_router.hpp>
#include <thread/thread_netif.hpp>
@@ -144,20 +145,39 @@ Mle::Mle(ThreadNetif &aThreadNetif) :
mNetif.RegisterCallback(mNetifCallback);
}
ThreadError Mle::Start(void)
ThreadError Mle::Enable(void)
{
ThreadError error = kThreadError_None;
Ip6::SockAddr sockaddr;
// cannot bring up the interface if IEEE 802.15.4 promiscuous mode is enabled
VerifyOrExit(otPlatRadioGetPromiscuous() == false, error = kThreadError_Busy);
VerifyOrExit(mNetif.IsUp(), error = kThreadError_InvalidState);
// memcpy(&sockaddr.mAddr, &mLinkLocal64.GetAddress(), sizeof(sockaddr.mAddr));
sockaddr.mPort = kUdpPort;
SuccessOrExit(error = mSocket.Open(&HandleUdpReceive, this));
SuccessOrExit(error = mSocket.Bind(sockaddr));
exit:
return error;
}
ThreadError Mle::Disable(void)
{
ThreadError error = kThreadError_None;
SuccessOrExit(error = Stop());
SuccessOrExit(error = mSocket.Close());
exit:
return error;
}
ThreadError Mle::Start(void)
{
ThreadError error = kThreadError_None;
// cannot bring up the interface if IEEE 802.15.4 promiscuous mode is enabled
VerifyOrExit(otPlatRadioGetPromiscuous() == false, error = kThreadError_Busy);
VerifyOrExit(mNetif.IsUp(), error = kThreadError_InvalidState);
mDeviceState = kDeviceStateDetached;
SetStateDetached();
@@ -183,13 +203,68 @@ exit:
ThreadError Mle::Stop(void)
{
SetStateDetached();
mSocket.Close();
mNetif.RemoveUnicastAddress(mLinkLocal16);
mNetif.RemoveUnicastAddress(mMeshLocal16);
mDeviceState = kDeviceStateDisabled;
return kThreadError_None;
}
ThreadError Mle::Discover(uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanId,
DiscoverHandler aCallback, void *aContext)
{
ThreadError error = kThreadError_None;
Message *message;
Ip6::Address destination;
Tlv tlv;
MeshCoP::DiscoveryRequestTlv discoveryRequest;
uint16_t startOffset;
mDiscoverHandler = aCallback;
mDiscoverContext = aContext;
mMesh.SetDiscoverParameters(aScanChannels, aScanDuration);
VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
message->SetMleDiscoverRequest(true);
message->SetPanId(aPanId);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDiscoveryRequest));
// Discovery TLV
tlv.SetType(Tlv::kDiscovery);
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
startOffset = message->GetLength();
// Discovery Request TLV
discoveryRequest.Init();
discoveryRequest.SetVersion(kVersion);
SuccessOrExit(error = message->Append(&discoveryRequest, sizeof(discoveryRequest)));
tlv.SetLength(message->GetLength() - startOffset);
message->Write(startOffset - sizeof(tlv), sizeof(tlv), &tlv);
memset(&destination, 0, sizeof(destination));
destination.mFields.m16[0] = HostSwap16(0xff02);
destination.mFields.m16[7] = HostSwap16(0x0002);
SuccessOrExit(error = SendMessage(*message, destination));
otLogInfoMle("Sent discovery request\n");
exit:
if (error != kThreadError_None && message != NULL)
{
Message::Free(*message);
}
return error;
}
void Mle::HandleDiscoverComplete(void)
{
mDiscoverHandler(NULL, mDiscoverContext);
}
ThreadError Mle::BecomeDetached(void)
{
ThreadError error = kThreadError_None;
@@ -514,17 +589,24 @@ ThreadError Mle::AppendHeader(Message &aMessage, Header::Command aCommand)
header.Init();
if (aCommand == Header::kCommandAdvertisement ||
aCommand == Header::kCommandChildIdRequest ||
aCommand == Header::kCommandLinkReject ||
aCommand == Header::kCommandParentRequest ||
aCommand == Header::kCommandParentResponse)
switch (aCommand)
{
case Header::kCommandDiscoveryRequest:
case Header::kCommandDiscoveryResponse:
header.SetSecuritySuite(255);
break;
case Header::kCommandAdvertisement:
case Header::kCommandChildIdRequest:
case Header::kCommandLinkReject:
case Header::kCommandParentRequest:
case Header::kCommandParentResponse:
header.SetKeyIdMode2();
}
else
{
break;
default:
header.SetKeyIdMode1();
break;
}
header.SetCommand(aCommand);
@@ -1149,36 +1231,42 @@ ThreadError Mle::SendMessage(Message &aMessage, const Ip6::Address &aDestination
Ip6::MessageInfo messageInfo;
aMessage.Read(0, sizeof(header), &header);
header.SetFrameCounter(mKeyManager.GetMleFrameCounter());
keySequence = mKeyManager.GetCurrentKeySequence();
header.SetKeyId(keySequence);
aMessage.Write(0, header.GetLength(), &header);
GenerateNonce(*mMac.GetExtAddress(), mKeyManager.GetMleFrameCounter(), Mac::Frame::kSecEncMic32, nonce);
aesCcm.SetKey(mKeyManager.GetCurrentMleKey(), 16);
aesCcm.Init(16 + 16 + header.GetHeaderLength(), aMessage.GetLength() - (header.GetLength() - 1),
sizeof(tag), nonce, sizeof(nonce));
aesCcm.Header(&mLinkLocal64.GetAddress(), sizeof(mLinkLocal64.GetAddress()));
aesCcm.Header(&aDestination, sizeof(aDestination));
aesCcm.Header(header.GetBytes() + 1, header.GetHeaderLength());
aMessage.SetOffset(header.GetLength() - 1);
while (aMessage.GetOffset() < aMessage.GetLength())
if (header.GetSecuritySuite() == 0)
{
length = aMessage.Read(aMessage.GetOffset(), sizeof(buf), buf);
aesCcm.Payload(buf, buf, length, true);
aMessage.Write(aMessage.GetOffset(), length, buf);
aMessage.MoveOffset(length);
}
header.SetFrameCounter(mKeyManager.GetMleFrameCounter());
tagLength = sizeof(tag);
aesCcm.Finalize(tag, &tagLength);
SuccessOrExit(aMessage.Append(tag, tagLength));
keySequence = mKeyManager.GetCurrentKeySequence();
header.SetKeyId(keySequence);
aMessage.Write(0, header.GetLength(), &header);
GenerateNonce(*mMac.GetExtAddress(), mKeyManager.GetMleFrameCounter(), Mac::Frame::kSecEncMic32, nonce);
aesCcm.SetKey(mKeyManager.GetCurrentMleKey(), 16);
aesCcm.Init(16 + 16 + header.GetHeaderLength(), aMessage.GetLength() - (header.GetLength() - 1),
sizeof(tag), nonce, sizeof(nonce));
aesCcm.Header(&mLinkLocal64.GetAddress(), sizeof(mLinkLocal64.GetAddress()));
aesCcm.Header(&aDestination, sizeof(aDestination));
aesCcm.Header(header.GetBytes() + 1, header.GetHeaderLength());
aMessage.SetOffset(header.GetLength() - 1);
while (aMessage.GetOffset() < aMessage.GetLength())
{
length = aMessage.Read(aMessage.GetOffset(), sizeof(buf), buf);
aesCcm.Payload(buf, buf, length, true);
aMessage.Write(aMessage.GetOffset(), length, buf);
aMessage.MoveOffset(length);
}
tagLength = sizeof(tag);
aesCcm.Finalize(tag, &tagLength);
SuccessOrExit(aMessage.Append(tag, tagLength));
mKeyManager.IncrementMleFrameCounter();
}
memset(&messageInfo, 0, sizeof(messageInfo));
memcpy(&messageInfo.GetPeerAddr(), &aDestination, sizeof(messageInfo.GetPeerAddr()));
@@ -1187,8 +1275,6 @@ ThreadError Mle::SendMessage(Message &aMessage, const Ip6::Address &aDestination
messageInfo.mInterfaceId = mNetif.GetInterfaceId();
messageInfo.mHopLimit = 255;
mKeyManager.IncrementMleFrameCounter();
SuccessOrExit(error = mSocket.SendTo(aMessage, messageInfo));
exit:
@@ -1224,6 +1310,29 @@ void Mle::HandleUdpReceive(Message &aMessage, const Ip6::MessageInfo &aMessageIn
aMessage.Read(aMessage.GetOffset(), sizeof(header), &header);
VerifyOrExit(header.IsValid(),);
if (header.GetSecuritySuite() == 255)
{
aMessage.MoveOffset(header.GetLength());
switch (header.GetCommand())
{
case Header::kCommandDiscoveryRequest:
HandleDiscoveryRequest(aMessage, aMessageInfo);
break;
case Header::kCommandDiscoveryResponse:
HandleDiscoveryResponse(aMessage, aMessageInfo);
break;
default:
break;
}
ExitNow();
}
VerifyOrExit(mDeviceState != kDeviceStateDisabled && header.GetSecuritySuite() == 0, ;);
if (header.IsKeyIdMode1())
{
keyid = header.GetKeyId();
@@ -1879,6 +1988,213 @@ exit:
return error;
}
ThreadError Mle::HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
Tlv tlv;
MeshCoP::Tlv meshcopTlv;
MeshCoP::DiscoveryRequestTlv discoveryRequest;
MeshCoP::ExtendedPanIdTlv extPanId;
uint16_t offset;
uint16_t end;
otLogInfoMle("Received discovery request\n");
// only Routers and REEDs respond
VerifyOrExit((mDeviceMode & ModeTlv::kModeFFD) != 0, ;);
offset = aMessage.GetOffset();
end = aMessage.GetLength();
// find MLE Discovery TLV
while (offset < end)
{
aMessage.Read(offset, sizeof(tlv), &tlv);
if (tlv.GetType() == Tlv::kDiscovery)
{
break;
}
offset += sizeof(tlv) + tlv.GetLength();
}
VerifyOrExit(offset < end, error = kThreadError_Parse);
offset += sizeof(tlv);
end = offset + sizeof(tlv) + tlv.GetLength();
while (offset < end)
{
aMessage.Read(offset, sizeof(meshcopTlv), &meshcopTlv);
switch (meshcopTlv.GetType())
{
case MeshCoP::Tlv::kDiscoveryRequest:
aMessage.Read(offset, sizeof(discoveryRequest), &discoveryRequest);
VerifyOrExit(discoveryRequest.IsValid(), error = kThreadError_Parse);
break;
case MeshCoP::Tlv::kExtendedPanId:
aMessage.Read(offset, sizeof(extPanId), &extPanId);
VerifyOrExit(extPanId.IsValid(), error = kThreadError_Parse);
VerifyOrExit(memcmp(mMac.GetExtendedPanId(), extPanId.GetExtendedPanId(), OT_EXT_PAN_ID_SIZE),
error = kThreadError_Drop);
break;
default:
break;
}
offset += sizeof(meshcopTlv) + meshcopTlv.GetLength();
}
error = SendDiscoveryResponse(aMessageInfo.GetPeerAddr(), aMessage.GetPanId());
exit:
return error;
}
ThreadError Mle::SendDiscoveryResponse(const Ip6::Address &aDestination, uint16_t aPanId)
{
ThreadError error = kThreadError_None;
Message *message;
uint16_t startOffset;
Tlv tlv;
MeshCoP::DiscoveryResponseTlv discoveryResponse;
MeshCoP::ExtendedPanIdTlv extPanId;
MeshCoP::NetworkNameTlv networkName;
VerifyOrExit((message = Ip6::Udp::NewMessage(0)) != NULL, ;);
message->SetLinkSecurityEnabled(false);
message->SetMleDiscoverResponse(true);
message->SetPanId(aPanId);
SuccessOrExit(error = AppendHeader(*message, Header::kCommandDiscoveryResponse));
// Discovery TLV
tlv.SetType(Tlv::kDiscovery);
SuccessOrExit(error = message->Append(&tlv, sizeof(tlv)));
startOffset = message->GetLength();
// Discovery Response TLV
discoveryResponse.Init();
discoveryResponse.SetVersion(kVersion);
SuccessOrExit(error = message->Append(&discoveryResponse, sizeof(discoveryResponse)));
// Extended PAN ID TLV
extPanId.Init();
extPanId.SetExtendedPanId(mMac.GetExtendedPanId());
SuccessOrExit(error = message->Append(&extPanId, sizeof(extPanId)));
// Network Name TLV
networkName.Init();
networkName.SetNetworkName(mMac.GetNetworkName());
SuccessOrExit(error = message->Append(&networkName, sizeof(tlv) + networkName.GetLength()));
tlv.SetLength(message->GetLength() - startOffset);
message->Write(startOffset - sizeof(tlv), sizeof(tlv), &tlv);
SuccessOrExit(error = SendMessage(*message, aDestination));
otLogInfoMle("Sent discovery response\n");
exit:
if (error != kThreadError_None && message != NULL)
{
Message::Free(*message);
}
return error;
}
ThreadError Mle::HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
{
ThreadError error = kThreadError_None;
const ThreadMessageInfo *threadMessageInfo = reinterpret_cast<const ThreadMessageInfo *>(aMessageInfo.mLinkInfo);
Tlv tlv;
MeshCoP::Tlv meshcopTlv;
MeshCoP::DiscoveryResponseTlv discoveryResponse;
MeshCoP::ExtendedPanIdTlv extPanId;
MeshCoP::NetworkNameTlv networkName;
otActiveScanResult result;
uint16_t offset;
uint16_t end;
char networkNameBuf[OT_NETWORK_NAME_SIZE];
otLogInfoMle("Handle discovery response\n");
offset = aMessage.GetOffset();
end = aMessage.GetLength();
// find MLE Discovery TLV
while (offset < end)
{
aMessage.Read(offset, sizeof(tlv), &tlv);
if (tlv.GetType() == Tlv::kDiscovery)
{
break;
}
offset += sizeof(tlv) + tlv.GetLength();
}
VerifyOrExit(offset < end, error = kThreadError_Parse);
offset += sizeof(tlv);
end = offset + sizeof(tlv) + tlv.GetLength();
memset(&result, 0, sizeof(result));
result.mPanId = threadMessageInfo->mPanId;
result.mChannel = threadMessageInfo->mChannel;
result.mRssi = threadMessageInfo->mRss;
result.mLqi = threadMessageInfo->mLqi;
static_cast<Mac::ExtAddress *>(&result.mExtAddress)->Set(aMessageInfo.GetPeerAddr());
// process MeshCoP TLVs
while (offset < end)
{
aMessage.Read(offset, sizeof(meshcopTlv), &meshcopTlv);
switch (meshcopTlv.GetType())
{
case MeshCoP::Tlv::kDiscoveryResponse:
aMessage.Read(offset, sizeof(discoveryResponse), &discoveryResponse);
VerifyOrExit(discoveryResponse.IsValid(), error = kThreadError_Parse);
result.mVersion = discoveryResponse.GetVersion();
result.mIsNative = discoveryResponse.IsNativeCommissioner();
break;
case MeshCoP::Tlv::kExtendedPanId:
aMessage.Read(offset, sizeof(extPanId), &extPanId);
VerifyOrExit(extPanId.IsValid(), error = kThreadError_Parse);
result.mExtPanId = extPanId.GetExtendedPanId();
break;
case MeshCoP::Tlv::kNetworkName:
aMessage.Read(offset, sizeof(networkName), &networkName);
VerifyOrExit(networkName.IsValid(), error = kThreadError_Parse);
memcpy(networkNameBuf, networkName.GetNetworkName(), networkName.GetLength());
memset(networkNameBuf + networkName.GetLength(), 0, sizeof(networkNameBuf) - networkName.GetLength());
result.mNetworkName = networkNameBuf;
break;
default:
break;
}
offset += sizeof(meshcopTlv) + meshcopTlv.GetLength();
}
// signal callback
mDiscoverHandler(&result, mDiscoverContext);
exit:
return error;
}
Neighbor *Mle::GetNeighbor(uint16_t aAddress)
{
return (mParent.mState == Neighbor::kStateValid && mParent.mValid.mRloc16 == aAddress) ? &mParent : NULL;
+109 -9
View File
@@ -124,9 +124,10 @@ public:
*
*/
bool IsValid(void) const {
return mSecuritySuite == 0 &&
(mSecurityControl == (Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32) ||
mSecurityControl == (Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecEncMic32));
return (mSecuritySuite == 255) ||
(mSecuritySuite == 0 &&
(mSecurityControl == (Mac::Frame::kKeyIdMode1 | Mac::Frame::kSecEncMic32) ||
mSecurityControl == (Mac::Frame::kKeyIdMode2 | Mac::Frame::kSecEncMic32)));
}
/**
@@ -136,10 +137,31 @@ public:
*
*/
uint8_t GetLength(void) const {
return sizeof(mSecuritySuite) + sizeof(mSecurityControl) + sizeof(mFrameCounter) +
(IsKeyIdMode1() ? 1 : 5) + sizeof(mCommand);
uint8_t rval = sizeof(mSecuritySuite) + sizeof(mCommand);
if (mSecuritySuite == 0) {
rval += sizeof(mSecurityControl) + sizeof(mFrameCounter) + (IsKeyIdMode1() ? 1 : 5);
}
return rval;
}
/**
* This method returns the Security Suite value.
*
* @returns The Security Suite value.
*
*/
uint8_t GetSecuritySuite(void) const { return mSecuritySuite; }
/**
* This method sets the Security Suite value.
*
* @param[in] aSecuritySuite The Security Suite value.
*
*/
void SetSecuritySuite(uint8_t aSecuritySuite) { mSecuritySuite = aSecuritySuite; }
/**
* This method returns the MLE header length (excluding the Command Type).
*
@@ -269,6 +291,8 @@ public:
kCommandChildIdResponse = 12, ///< Child ID Response
kCommandChildUpdateRequest = 13, ///< Child Update Request
kCommandChildUpdateResponse = 14, ///< Child Update Response
kCommandDiscoveryRequest = 16, ///< Discovery Request
kCommandDiscoveryResponse = 17, ///< Discovery Response
};
/**
@@ -278,8 +302,13 @@ public:
*
*/
Command GetCommand(void) const {
const uint8_t *command = IsKeyIdMode1() ? mKeyIdentifier + 1 : &mCommand;
return static_cast<Command>(*command);
if (mSecuritySuite == 255) {
return static_cast<Command>(mSecurityControl);
}
else {
const uint8_t *command = IsKeyIdMode1() ? mKeyIdentifier + 1 : &mCommand;
return static_cast<Command>(*command);
}
}
/**
@@ -289,8 +318,13 @@ public:
*
*/
void SetCommand(Command aCommand) {
uint8_t *commandField = IsKeyIdMode1() ? mKeyIdentifier + 1 : &mCommand;
*commandField = static_cast<uint8_t>(aCommand);
if (mSecuritySuite == 255) {
mSecurityControl = static_cast<uint8_t>(aCommand);
}
else {
uint8_t *commandField = IsKeyIdMode1() ? mKeyIdentifier + 1 : &mCommand;
*commandField = static_cast<uint8_t>(aCommand);
}
}
/**
@@ -325,6 +359,24 @@ public:
*/
explicit Mle(ThreadNetif &aThreadNetif);
/**
* This method enables MLE.
*
* @retval kThreadError_None Successfully enabled MLE.
* @retval kThreadError_Busy MLE was already enabled.
*
*/
ThreadError Enable(void);
/**
* This method disables MLE.
*
* @retval kThreadError_None Successfully disabled MLE.
* @retval kThreadError_Busy MLE was already disabled.
*
*/
ThreadError Disable(void);
/**
* This method starts the MLE protocol operation.
*
@@ -343,6 +395,37 @@ public:
*/
ThreadError Stop(void);
/**
* This function pointer is called on receiving an MLE Discovery Response message.
*
* @param[in] aResult A valid pointer to the Discovery Response information or NULL when the Discovery completes.
* @param[in] aContext A pointer to application-specific context.
*
*/
typedef void (*DiscoverHandler)(otActiveScanResult *aResult, void *aContext);
/**
* This method initiates a Thread Discovery.
*
* @param[in] aScanChannels A bit vector indicating which channels to scan.
* @param[in] aScanDuration The time in milliseconds to spend scanning each channel.
* @param[in] aPanId The PAN ID filter (set to Broadcast PAN to disable filter).
* @param[in] aHandler A pointer to a function that is called on receiving an MLE Discovery Response.
* @param[in] aContext A pointer to arbitrary context information.
*
* @retval kThreadError_None Successfully started a Thread Discovery.
* @retval kThreadError_Busy Thread Discovery is already in progress.
*
*/
ThreadError Discover(uint32_t aScanChannels, uint16_t aScanDuration, uint16_t aPanId,
DiscoverHandler aCallback, void *aContext);
/**
* This method is called by the MeshForwarder to indicate that discovery is complete.
*
*/
void HandleDiscoverComplete(void);
/**
* This method causes the Thread interface to detach from the Thread network.
*
@@ -774,6 +857,17 @@ protected:
*/
ThreadError AppendAddressRegistration(Message &aMessage);
/**
* This method appends a Thread Discovery TLV to a message.
*
* @param[in] aMessage A reference to the message.
*
* @retval kThreadError_None Successfully appended the Thread Discovery TLV.
* @retval kThreadError_NoBufs Insufficient buffers available to append the Address Registration TLV.
*
*/
ThreadError AppendDiscovery(Message &aMessage);
/**
* This method checks if the destination is reachable.
*
@@ -975,9 +1069,12 @@ private:
ThreadError HandleDataResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleParentResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo,
uint32_t aKeySequence);
ThreadError HandleDiscoveryRequest(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError HandleDiscoveryResponse(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo);
ThreadError SendParentRequest(void);
ThreadError SendChildIdRequest(void);
ThreadError SendDiscoveryResponse(const Ip6::Address &aDestination, uint16_t aPanId);
bool IsBetterParent(uint16_t aRloc16, uint8_t aLinkQuality, ConnectivityTlv &aConnectivityTlv) const;
@@ -1004,6 +1101,9 @@ private:
Ip6::UdpSocket mSocket;
uint32_t mTimeout;
DiscoverHandler mDiscoverHandler;
void *mDiscoverContext;
Ip6::NetifUnicastAddress mLinkLocal16;
Ip6::NetifUnicastAddress mLinkLocal64;
Ip6::NetifUnicastAddress mMeshLocal64;
+1
View File
@@ -93,6 +93,7 @@ public:
kStatus = 17, ///< Status TLV
kVersion = 18, ///< Version TLV
kAddressRegistration = 19, ///< Address Registration TLV
kDiscovery = 26, ///< Thread Discovery TLV
kInvalid = 255,
};
+2 -1
View File
@@ -81,6 +81,7 @@ ThreadError ThreadNetif::Up(void)
Netif::AddNetif();
mMeshForwarder.Start();
mCoapServer.Start();
mMleRouter.Enable();
mIsUp = true;
exit:
@@ -90,7 +91,7 @@ exit:
ThreadError ThreadNetif::Down(void)
{
mCoapServer.Stop();
mMleRouter.Stop();
mMleRouter.Disable();
mMeshForwarder.Stop();
Netif::RemoveNetif();
mIsUp = false;
+5 -3
View File
@@ -225,9 +225,11 @@ private:
*/
struct ThreadMessageInfo
{
int8_t mRss; ///< The Received Signal Strength in dBm.
uint8_t mLqi; ///< The Link Quality Indicator for a received message.
bool mLinkSecurity; ///< Indicates whether or not link security is enabled.
uint16_t mPanId; ///< Source PAN ID
uint8_t mChannel; ///< 802.15.4 Channel
int8_t mRss; ///< Received Signal Strength in dBm.
uint8_t mLqi; ///< Link Quality Indicator for a received message.
bool mLinkSecurity; ///< Indicates whether or not link security is enabled.
};
/**