void Leader::HandleKeepAlive(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { StateTlv state; CommissionerSessionIdTlv sessionId; StateTlv::State responseState; otLogInfoMeshCoP(GetInstance(), "received keep alive"); SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kState, sizeof(state), state)); VerifyOrExit(state.IsValid()); SuccessOrExit(Tlv::GetTlv(aMessage, Tlv::kCommissionerSessionId, sizeof(sessionId), sessionId)); VerifyOrExit(sessionId.IsValid()); if (sessionId.GetCommissionerSessionId() != mSessionId) { responseState = StateTlv::kReject; } else if (state.GetState() != StateTlv::kAccept) { responseState = StateTlv::kReject; ResignCommissioner(); } else { responseState = StateTlv::kAccept; mTimer.Start(TimerMilli::SecToMsec(kTimeoutLeaderPetition)); } SendKeepAliveResponse(aHeader, aMessageInfo, responseState); exit: return; }
ThreadError DatasetManager::Set(Coap::Header &aHeader, Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { Tlv tlv; Timestamp *timestamp; uint16_t offset = aMessage.GetOffset(); Tlv::Type type; bool isUpdateFromCommissioner = false; bool doesAffectConnectivity = false; StateTlv::State state = StateTlv::kAccept; ActiveTimestampTlv activeTimestamp; PendingTimestampTlv pendingTimestamp; ChannelTlv channel; CommissionerSessionIdTlv sessionId; MeshLocalPrefixTlv meshLocalPrefix; NetworkMasterKeyTlv masterKey; PanIdTlv panId; activeTimestamp.SetLength(0); pendingTimestamp.SetLength(0); channel.SetLength(0); masterKey.SetLength(0); meshLocalPrefix.SetLength(0); panId.SetLength(0); pendingTimestamp.SetLength(0); sessionId.SetLength(0); VerifyOrExit(mNetif.GetMle().GetDeviceState() == Mle::kDeviceStateLeader, state = StateTlv::kReject); // verify that TLV data size is less than maximum TLV value size while (offset < aMessage.GetLength()) { aMessage.Read(offset, sizeof(tlv), &tlv); VerifyOrExit(tlv.GetLength() <= Dataset::kMaxValueSize, state = StateTlv::kReject); offset += sizeof(tlv) + tlv.GetLength(); } // verify that does not overflow dataset buffer VerifyOrExit((offset - aMessage.GetOffset()) <= Dataset::kMaxSize, state = StateTlv::kReject); type = (strcmp(mUriSet, OPENTHREAD_URI_ACTIVE_SET) == 0 ? Tlv::kActiveTimestamp : Tlv::kPendingTimestamp); if (Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp) != kThreadError_None) { ExitNow(state = StateTlv::kReject); } VerifyOrExit(activeTimestamp.IsValid(), state = StateTlv::kReject); if (Tlv::GetTlv(aMessage, Tlv::kPendingTimestamp, sizeof(pendingTimestamp), pendingTimestamp) == kThreadError_None) { VerifyOrExit(pendingTimestamp.IsValid(), state = StateTlv::kReject); } // verify the request includes a timestamp that is ahead of the locally stored value timestamp = (type == Tlv::kActiveTimestamp) ? static_cast<Timestamp *>(&activeTimestamp) : static_cast<Timestamp *>(&pendingTimestamp); VerifyOrExit(mLocal.GetTimestamp() == NULL || mLocal.GetTimestamp()->Compare(*timestamp) > 0, state = StateTlv::kReject); // check channel if (Tlv::GetTlv(aMessage, Tlv::kChannel, sizeof(channel), channel) == kThreadError_None) { VerifyOrExit(channel.IsValid() && channel.GetChannel() >= kPhyMinChannel && channel.GetChannel() <= kPhyMaxChannel, state = StateTlv::kReject); if (type == Tlv::kActiveTimestamp && channel.GetChannel() != mNetif.GetMac().GetChannel()) { doesAffectConnectivity = true; } } // check PAN ID if (Tlv::GetTlv(aMessage, Tlv::kPanId, sizeof(panId), panId) == kThreadError_None && type == Tlv::kActiveTimestamp && panId.IsValid() && panId.GetPanId() != mNetif.GetMac().GetPanId()) { doesAffectConnectivity = true; } // check mesh local prefix if (Tlv::GetTlv(aMessage, Tlv::kMeshLocalPrefix, sizeof(meshLocalPrefix), meshLocalPrefix) == kThreadError_None && type == Tlv::kActiveTimestamp && memcmp(meshLocalPrefix.GetMeshLocalPrefix(), mNetif.GetMle().GetMeshLocalPrefix(), meshLocalPrefix.GetLength())) { doesAffectConnectivity = true; } // check network master key if (Tlv::GetTlv(aMessage, Tlv::kNetworkMasterKey, sizeof(masterKey), masterKey) == kThreadError_None && type == Tlv::kActiveTimestamp && memcmp(masterKey.GetNetworkMasterKey(), mNetif.GetKeyManager().GetMasterKey(NULL), masterKey.GetLength())) { doesAffectConnectivity = true; } // check active timestamp rollback if (type == Tlv::kPendingTimestamp && (masterKey.GetLength() == 0 || memcmp(masterKey.GetNetworkMasterKey(), mNetif.GetKeyManager().GetMasterKey(NULL), masterKey.GetLength()) == 0)) { // no change to master key, active timestamp must be ahead const Timestamp *localActiveTimestamp = mNetif.GetActiveDataset().GetNetwork().GetTimestamp(); VerifyOrExit(localActiveTimestamp == NULL || localActiveTimestamp->Compare(activeTimestamp) > 0, state = StateTlv::kReject); } // check commissioner session id if (Tlv::GetTlv(aMessage, Tlv::kCommissionerSessionId, sizeof(sessionId), sessionId) == kThreadError_None) { CommissionerSessionIdTlv *localId; isUpdateFromCommissioner = true; localId = static_cast<CommissionerSessionIdTlv *>(mNetif.GetNetworkDataLeader().GetCommissioningDataSubTlv( Tlv::kCommissionerSessionId)); VerifyOrExit(sessionId.IsValid() && localId != NULL && localId->GetCommissionerSessionId() == sessionId.GetCommissionerSessionId(), state = StateTlv::kReject); } // verify the update from commissioner should not contain tlv would affect connectivity VerifyOrExit(!isUpdateFromCommissioner || !doesAffectConnectivity, state = StateTlv::kReject); // update dataset if (type == Tlv::kPendingTimestamp && isUpdateFromCommissioner) { mLocal.Clear(true); mLocal.Set(mNetif.GetActiveDataset().GetNetwork()); } if (!doesAffectConnectivity) { offset = aMessage.GetOffset(); while (offset < aMessage.GetLength()) { OT_TOOL_PACKED_BEGIN struct { Tlv tlv; uint8_t value[Dataset::kMaxValueSize]; } OT_TOOL_PACKED_END data; aMessage.Read(offset, sizeof(Tlv), &data.tlv); aMessage.Read(offset + sizeof(Tlv), data.tlv.GetLength(), data.value); if (data.tlv.GetType() != Tlv::kCommissionerSessionId) { mLocal.Set(data.tlv); } offset += sizeof(Tlv) + data.tlv.GetLength(); } mLocal.Store(); mNetwork = mLocal; mNetif.GetNetworkDataLeader().IncrementVersion(); mNetif.GetNetworkDataLeader().IncrementStableVersion(); } else { mNetif.GetPendingDataset().ApplyActiveDataset(activeTimestamp, aMessage); } // notify commissioner if update is from thread device if (!isUpdateFromCommissioner) { BorderAgentLocatorTlv *borderAgentLocator; Ip6::Address destination; borderAgentLocator = static_cast<BorderAgentLocatorTlv *>(mNetif.GetNetworkDataLeader().GetCommissioningDataSubTlv( Tlv::kBorderAgentLocator)); VerifyOrExit(borderAgentLocator != NULL,); memset(&destination, 0, sizeof(destination)); destination = mNetif.GetMle().GetMeshLocal16(); destination.mFields.m16[4] = HostSwap16(0x0000); destination.mFields.m16[5] = HostSwap16(0x00ff); destination.mFields.m16[6] = HostSwap16(0xfe00); destination.mFields.m16[7] = HostSwap16(borderAgentLocator->GetBorderAgentLocator()); mNetif.GetLeader().SendDatasetChanged(destination); }