diff --git a/src/core/thread/mle.cpp b/src/core/thread/mle.cpp index ca353fdde..d02f9bdcd 100644 --- a/src/core/thread/mle.cpp +++ b/src/core/thread/mle.cpp @@ -67,6 +67,7 @@ Mle::Mle(ThreadNetif &aThreadNetif) : mParentRequestState = kParentIdle; mParentRequestMode = kMleAttachAnyPartition; mParentConnectivity = 0; + mRetrieveNewNetworkData = false; mTimeout = kMaxNeighborAge; memset(&mLeaderData, 0, sizeof(mLeaderData)); @@ -1415,10 +1416,21 @@ ThreadError Mle::HandleAdvertisement(const Message &aMessage, const Ip6::Message Mac::ExtAddress macAddr; bool isNeighbor; Neighbor *neighbor; + SourceAddressTlv sourceAddress; LeaderDataTlv leaderData; uint8_t tlvs[] = {Tlv::kLeaderData, Tlv::kNetworkData}; - if (mDeviceState != kDeviceStateDetached) + // Source Address + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kSourceAddress, sizeof(sourceAddress), sourceAddress)); + VerifyOrExit(sourceAddress.IsValid(), error = kThreadError_Parse); + + // Leader Data + SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData)); + VerifyOrExit(leaderData.IsValid(), error = kThreadError_Parse); + + otLogInfoMle("Received advertisement from %04x\n", sourceAddress.GetRloc16()); + + if ((mDeviceState != kDeviceStateDetached) && (mDeviceMode & ModeTlv::kModeFFD)) { SuccessOrExit(error = mMleRouter.HandleAdvertisement(aMessage, aMessageInfo)); } @@ -1439,6 +1451,21 @@ ThreadError Mle::HandleAdvertisement(const Message &aMessage, const Ip6::Message break; } + if (mParent.mValid.mRloc16 != sourceAddress.GetRloc16()) + { + SetStateDetached(); + ExitNow(error = kThreadError_NoRoute); + } + else + { + if (leaderData.GetPartitionId() != mLeaderData.GetPartitionId() || + leaderData.GetLeaderRouterId() != GetLeaderId()) + { + SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); + mRetrieveNewNetworkData = true; + } + } + isNeighbor = true; mParent.mLastHeard = mParentRequestTimer.GetNow(); break; @@ -1456,10 +1483,8 @@ ThreadError Mle::HandleAdvertisement(const Message &aMessage, const Ip6::Message if (isNeighbor) { - SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData)); - VerifyOrExit(leaderData.IsValid(), error = kThreadError_Parse); - - if (static_cast(leaderData.GetDataVersion() - mNetworkData.GetVersion()) > 0) + if (mRetrieveNewNetworkData || + (static_cast(leaderData.GetDataVersion() - mNetworkData.GetVersion()) > 0)) { SendDataRequest(aMessageInfo.GetPeerAddr(), tlvs, sizeof(tlvs)); } @@ -1499,8 +1524,27 @@ ThreadError Mle::HandleDataResponse(const Message &aMessage, const Ip6::MessageI SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData)); VerifyOrExit(leaderData.IsValid(), error = kThreadError_Parse); - diff = leaderData.GetDataVersion() - mNetworkData.GetVersion(); - VerifyOrExit(diff > 0, ;); + if ((leaderData.GetPartitionId() != mLeaderData.GetPartitionId()) || + (leaderData.GetLeaderRouterId() != GetLeaderId())) + { + if ((mDeviceMode & ModeTlv::kModeRxOnWhenIdle) == 0) + { + SetLeaderData(leaderData.GetPartitionId(), leaderData.GetWeighting(), leaderData.GetLeaderRouterId()); + } + else + { + ExitNow(error = kThreadError_Drop); + } + } + else if (mRetrieveNewNetworkData) + { + mRetrieveNewNetworkData = false; + } + else + { + diff = leaderData.GetDataVersion() - mNetworkData.GetVersion(); + VerifyOrExit(diff > 0, ;); + } mNetworkData.SetNetworkData(leaderData.GetDataVersion(), leaderData.GetStableDataVersion(), (mDeviceMode & ModeTlv::kModeFullNetworkData) == 0, diff --git a/src/core/thread/mle.hpp b/src/core/thread/mle.hpp index a4a23cb9d..a5c3a8287 100644 --- a/src/core/thread/mle.hpp +++ b/src/core/thread/mle.hpp @@ -907,6 +907,7 @@ protected: NetworkData::Leader &mNetworkData; ///< The Network Data object. LeaderDataTlv mLeaderData; ///< Last received Leader Data TLV. + bool mRetrieveNewNetworkData; ///< Indicating new Network Data is needed if set. DeviceState mDeviceState; ///< Current Thread interface state. Router mParent; ///< Parent information. diff --git a/src/core/thread/mle_router.cpp b/src/core/thread/mle_router.cpp index b70f90a32..1f33fb3be 100644 --- a/src/core/thread/mle_router.cpp +++ b/src/core/thread/mle_router.cpp @@ -228,6 +228,7 @@ ThreadError MleRouter::BecomeLeader(void) memcpy(&mRouters[mRouterId].mMacAddr, mMac.GetExtAddress(), sizeof(mRouters[mRouterId].mMacAddr)); SetLeaderData(otPlatRandomGet(), mLeaderWeight, mRouterId); + mRouterIdSequence = otPlatRandomGet(); mNetworkData.Reset(); @@ -1083,7 +1084,6 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M // Source Address SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kSourceAddress, sizeof(sourceAddress), sourceAddress)); - VerifyOrExit(sourceAddress.IsValid(), error = kThreadError_Parse); // Remove stale neighbors if ((neighbor = GetNeighbor(macAddr)) != NULL && @@ -1094,9 +1094,6 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M // Leader Data SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kLeaderData, sizeof(leaderData), leaderData)); - VerifyOrExit(leaderData.IsValid(), error = kThreadError_Parse); - - otLogInfoMle("Received advertisement from %04x\n", sourceAddress.GetRloc16()); peerParitionId = leaderData.GetPartitionId(); @@ -1128,10 +1125,7 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kRoute, sizeof(route), route)); VerifyOrExit(route.IsValid(), error = kThreadError_Parse); - if (mDeviceMode & ModeTlv::kModeFFD) - { - SuccessOrExit(error = ProcessRouteTlv(route)); - } + SuccessOrExit(error = ProcessRouteTlv(route)); VerifyOrExit((routerId = GetRouterId(sourceAddress.GetRloc16())) < kMaxRouterId, error = kThreadError_Parse); @@ -1154,7 +1148,7 @@ ThreadError MleRouter::HandleAdvertisement(const Message &aMessage, const Ip6::M } } - if ((mDeviceMode & ModeTlv::kModeFFD) && (routerCount < mRouterUpgradeThreshold)) + if (routerCount < mRouterUpgradeThreshold) { BecomeRouter(); ExitNow();