void Joiner::HandleJoinerEntrust(Coap::Message &aMessage, const Ip6::MessageInfo &aMessageInfo) { ThreadNetif & netif = GetNetif(); otError error; NetworkMasterKeyTlv masterKey; MeshLocalPrefixTlv meshLocalPrefix; ExtendedPanIdTlv extendedPanId; NetworkNameTlv networkName; ActiveTimestampTlv activeTimestamp; NetworkKeySequenceTlv networkKeySeq; VerifyOrExit(mState == OT_JOINER_STATE_ENTRUST && aMessage.GetType() == OT_COAP_TYPE_CONFIRMABLE && aMessage.GetCode() == OT_COAP_CODE_POST, error = OT_ERROR_DROP); otLogInfoMeshCoP("Received joiner entrust"); otLogCertMeshCoP("[THCI] direction=recv | type=JOIN_ENT.ntf"); SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkMasterKey, sizeof(masterKey), masterKey)); VerifyOrExit(masterKey.IsValid(), error = OT_ERROR_PARSE); SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kMeshLocalPrefix, sizeof(meshLocalPrefix), meshLocalPrefix)); VerifyOrExit(meshLocalPrefix.IsValid(), error = OT_ERROR_PARSE); SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kExtendedPanId, sizeof(extendedPanId), extendedPanId)); VerifyOrExit(extendedPanId.IsValid(), error = OT_ERROR_PARSE); SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkName, sizeof(networkName), networkName)); VerifyOrExit(networkName.IsValid(), error = OT_ERROR_PARSE); SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kActiveTimestamp, sizeof(activeTimestamp), activeTimestamp)); VerifyOrExit(activeTimestamp.IsValid(), error = OT_ERROR_PARSE); SuccessOrExit(error = Tlv::GetTlv(aMessage, Tlv::kNetworkKeySequence, sizeof(networkKeySeq), networkKeySeq)); VerifyOrExit(networkKeySeq.IsValid(), error = OT_ERROR_PARSE); netif.GetKeyManager().SetMasterKey(masterKey.GetNetworkMasterKey()); netif.GetKeyManager().SetCurrentKeySequence(networkKeySeq.GetNetworkKeySequence()); netif.GetMle().SetMeshLocalPrefix(meshLocalPrefix.GetMeshLocalPrefix()); netif.GetMac().SetExtendedPanId(extendedPanId.GetExtendedPanId()); { otNetworkName name; memcpy(name.m8, networkName.GetNetworkName(), networkName.GetLength()); name.m8[networkName.GetLength()] = '\0'; netif.GetMac().SetNetworkName(name.m8); } otLogInfoMeshCoP("join success!"); // Send dummy response. SendJoinerEntrustResponse(aMessage, aMessageInfo); // Delay extended address configuration to allow DTLS wrap up. mTimer.Start(kConfigExtAddressDelay); exit: if (error != OT_ERROR_NONE) { otLogWarnMeshCoP("Error while processing joiner entrust: %s", otThreadErrorToString(error)); } }
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); }