diff --git a/src/app/icd/BUILD.gn b/src/app/icd/BUILD.gn index aa0a6ef67bf28b..8b8f10fd5c1587 100644 --- a/src/app/icd/BUILD.gn +++ b/src/app/icd/BUILD.gn @@ -42,10 +42,25 @@ source_set("manager") { ":cluster", ":notifier", ":observer", + ":sender", "${chip_root}/src/credentials:credentials", ] } +source_set("sender") { + sources = [ + "ICDCheckInSender.cpp", + "ICDCheckInSender.h", + ] + + public_deps = [ + ":cluster", + "${chip_root}/src/credentials:credentials", + "${chip_root}/src/lib/address_resolve:address_resolve", + "${chip_root}/src/protocols/secure_channel", + ] +} + # ICD management cluster source-set is broken out of the main source-set to enable unit tests # All sources and configurations used by the ICD management cluster need to go in this source-set source_set("cluster") { diff --git a/src/app/icd/ICDCheckInSender.cpp b/src/app/icd/ICDCheckInSender.cpp new file mode 100644 index 00000000000000..bd2b86bb24fdd3 --- /dev/null +++ b/src/app/icd/ICDCheckInSender.cpp @@ -0,0 +1,104 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ICDCheckInSender.h" + +#include + +#include + +#include + +namespace chip { +namespace app { + +using namespace Protocols::SecureChannel; + +ICDCheckInSender::ICDCheckInSender(Messaging::ExchangeManager * exchangeManager) +{ + VerifyOrDie(exchangeManager != nullptr); + mExchangeManager = exchangeManager; + mAddressLookupHandle.SetListener(this); +} + +void ICDCheckInSender::OnNodeAddressResolved(const PeerId & peerId, const AddressResolve::ResolveResult & result) +{ + mResolveInProgress = false; + + VerifyOrReturn(CHIP_NO_ERROR != SendCheckInMsg(result.address), + ChipLogError(AppServer, "Failed to send the ICD Check-In message")); +} + +void ICDCheckInSender::OnNodeAddressResolutionFailed(const PeerId & peerId, CHIP_ERROR reason) +{ + mResolveInProgress = false; + ChipLogProgress(AppServer, "Node Address resolution failed for ICD Check-In with Node ID " ChipLogFormatX64, + ChipLogValueX64(peerId.GetNodeId())); +} + +CHIP_ERROR ICDCheckInSender::SendCheckInMsg(const Transport::PeerAddress & addr) +{ + System::PacketBufferHandle buffer = MessagePacketBuffer::New(CheckinMessage::sMinPayloadSize); + + VerifyOrReturnError(!buffer.IsNull(), CHIP_ERROR_NO_MEMORY); + MutableByteSpan output{ buffer->Start(), buffer->DataLength() }; + + // TODO retrieve Check-in counter + CounterType counter = 0; + + ReturnErrorOnFailure(CheckinMessage::GenerateCheckinMessagePayload(mKey, counter, ByteSpan(), output)); + + VerifyOrReturnError(mExchangeManager->GetSessionManager() != nullptr, CHIP_ERROR_INTERNAL); + + Optional session = + mExchangeManager->GetSessionManager()->CreateUnauthenticatedSession(addr, GetDefaultMRPConfig()); + VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY); + + // Using default MRP since we are not doing MRP in this context + Messaging::ExchangeContext * exchangeContext = mExchangeManager->NewContext(session.Value(), nullptr); + + VerifyOrReturnError(exchangeContext != nullptr, CHIP_ERROR_NO_MEMORY); + + return exchangeContext->SendMessage(MsgType::ICD_CheckIn, std::move(buffer), Messaging::SendMessageFlags::kNoAutoRequestAck); +} + +CHIP_ERROR ICDCheckInSender::RequestResolve(ICDMonitoringEntry & entry, FabricTable * fabricTable) +{ + VerifyOrReturnError(entry.IsValid(), CHIP_ERROR_INTERNAL); + VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INTERNAL); + const FabricInfo * fabricInfo = fabricTable->FindFabricWithIndex(entry.fabricIndex); + PeerId peerId(fabricInfo->GetCompressedFabricId(), entry.checkInNodeID); + + AddressResolve::NodeLookupRequest request(peerId); + + memcpy(mKey.AsMutable(), entry.key.As(), + sizeof(Crypto::Aes128KeyByteArray)); + + // TODO #30492 + // Device must stay active during MDNS resolution + CHIP_ERROR err = AddressResolve::Resolver::Instance().LookupNode(request, mAddressLookupHandle); + + if (err == CHIP_NO_ERROR) + { + mResolveInProgress = true; + } + + return err; +} + +} // namespace app +} // namespace chip diff --git a/src/app/icd/ICDCheckInSender.h b/src/app/icd/ICDCheckInSender.h new file mode 100644 index 00000000000000..a06efeee419287 --- /dev/null +++ b/src/app/icd/ICDCheckInSender.h @@ -0,0 +1,57 @@ +/* + * + * Copyright (c) 2023 Project CHIP Authors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#pragma once + +#include +#include +#include + +#include + +namespace chip { +namespace app { + +/** + * @brief ICD Check-In Sender is responsible for resolving the NodeId and sending the check-in message + */ +class ICDCheckInSender : public AddressResolve::NodeListener +{ +public: + ICDCheckInSender(Messaging::ExchangeManager * exchangeManager); + ~ICDCheckInSender(){}; + + CHIP_ERROR RequestResolve(ICDMonitoringEntry & entry, FabricTable * fabricTable); + + // AddressResolve::NodeListener - notifications when dnssd finds a node IP address + void OnNodeAddressResolved(const PeerId & peerId, const AddressResolve::ResolveResult & result) override; + void OnNodeAddressResolutionFailed(const PeerId & peerId, CHIP_ERROR reason) override; + + bool mResolveInProgress = false; + +private: + CHIP_ERROR SendCheckInMsg(const Transport::PeerAddress & addr); + + // This is used when a node address is required. + AddressResolve::NodeLookupHandle mAddressLookupHandle; + + Messaging::ExchangeManager * mExchangeManager = nullptr; + + Crypto::Aes128KeyHandle mKey = Crypto::Aes128KeyHandle(); +}; + +} // namespace app +} // namespace chip diff --git a/src/app/icd/ICDMonitoringTable.cpp b/src/app/icd/ICDMonitoringTable.cpp index f47da4187dda65..fe8c959983a714 100644 --- a/src/app/icd/ICDMonitoringTable.cpp +++ b/src/app/icd/ICDMonitoringTable.cpp @@ -161,6 +161,25 @@ bool ICDMonitoringEntry::IsKeyEquivalent(ByteSpan keyData) return (data == validation) ? true : false; } +ICDMonitoringEntry & ICDMonitoringEntry::operator=(const ICDMonitoringEntry & icdMonitoringEntry) +{ + if (this == &icdMonitoringEntry) + { + return *this; + } + + fabricIndex = icdMonitoringEntry.fabricIndex; + checkInNodeID = icdMonitoringEntry.checkInNodeID; + monitoredSubject = icdMonitoringEntry.monitoredSubject; + index = icdMonitoringEntry.index; + keyHandleValid = icdMonitoringEntry.keyHandleValid; + symmetricKeystore = icdMonitoringEntry.symmetricKeystore; + memcpy(key.AsMutable(), icdMonitoringEntry.key.As(), + sizeof(Crypto::Aes128KeyByteArray)); + + return *this; +} + CHIP_ERROR ICDMonitoringTable::Get(uint16_t index, ICDMonitoringEntry & entry) const { entry.fabricIndex = this->mFabric; diff --git a/src/app/icd/ICDMonitoringTable.h b/src/app/icd/ICDMonitoringTable.h index cf5fa28b4f1138..c97703b226aa75 100644 --- a/src/app/icd/ICDMonitoringTable.h +++ b/src/app/icd/ICDMonitoringTable.h @@ -54,7 +54,6 @@ struct ICDMonitoringEntry : public PersistentData this->symmetricKeystore = keyStore; } - bool IsValid() { return this->checkInNodeID != kUndefinedNodeId && this->fabricIndex != kUndefinedFabricIndex; } CHIP_ERROR UpdateKey(StorageKeyName & key) override; CHIP_ERROR Serialize(TLV::TLVWriter & writer) const override; CHIP_ERROR Deserialize(TLV::TLVReader & reader) override; @@ -77,6 +76,13 @@ struct ICDMonitoringEntry : public PersistentData */ CHIP_ERROR SetKey(ByteSpan keyData); CHIP_ERROR DeleteKey(void); + inline bool IsValid() + { + return (symmetricKeystore != nullptr && keyHandleValid && fabricIndex != kUndefinedFabricIndex && + checkInNodeID != kUndefinedNodeId); + } + + ICDMonitoringEntry & operator=(const ICDMonitoringEntry & icdMonitoringEntry); /** * @brief Implement the key verification needed by the ICDManagement Server. diff --git a/src/app/tests/TestICDMonitoringTable.cpp b/src/app/tests/TestICDMonitoringTable.cpp index a228e3368696fc..c6db890d68d087 100644 --- a/src/app/tests/TestICDMonitoringTable.cpp +++ b/src/app/tests/TestICDMonitoringTable.cpp @@ -61,6 +61,39 @@ constexpr uint8_t kKeyBuffer3a[] = { 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f }; +void TestEntryAssignationOverload(nlTestSuite * aSuite, void * aContext) +{ + TestSessionKeystoreImpl keystore; + ICDMonitoringEntry entry(&keystore); + + // Test Setting Key + NL_TEST_ASSERT(aSuite, CHIP_NO_ERROR == entry.SetKey(ByteSpan(kKeyBuffer1a))); + + entry.fabricIndex = 2; + + NL_TEST_ASSERT(aSuite, !entry.IsValid()); + + entry.checkInNodeID = 34; + entry.monitoredSubject = 32; + + // Entry should be valid now + NL_TEST_ASSERT(aSuite, entry.IsValid()); + + ICDMonitoringEntry entry2; + + NL_TEST_ASSERT(aSuite, !entry2.IsValid()); + + entry2 = entry; + + NL_TEST_ASSERT(aSuite, entry2.IsValid()); + + NL_TEST_ASSERT(aSuite, entry2.fabricIndex == entry.fabricIndex); + NL_TEST_ASSERT(aSuite, entry2.checkInNodeID == entry.checkInNodeID); + NL_TEST_ASSERT(aSuite, entry2.monitoredSubject == entry.monitoredSubject); + + NL_TEST_ASSERT(aSuite, entry.IsKeyEquivalent(ByteSpan(entry2.key.As()))); +} + void TestEntryKeyFunctions(nlTestSuite * aSuite, void * aContext) { TestSessionKeystoreImpl keystore; @@ -393,6 +426,7 @@ int Test_Setup(void * inContext) int TestClientMonitoringRegistrationTable() { static nlTest sTests[] = { NL_TEST_DEF("TestEntryKeyFunctions", TestEntryKeyFunctions), + NL_TEST_DEF("TestEntryAssignationOverload", TestEntryAssignationOverload), NL_TEST_DEF("TestSaveAndLoadRegistrationValue", TestSaveAndLoadRegistrationValue), NL_TEST_DEF("TestSaveAllInvalidRegistrationValues", TestSaveAllInvalidRegistrationValues), NL_TEST_DEF("TestSaveLoadRegistrationValueForMultipleFabrics", diff --git a/src/messaging/BUILD.gn b/src/messaging/BUILD.gn index cd32155d71a5d7..7289e7413b0039 100644 --- a/src/messaging/BUILD.gn +++ b/src/messaging/BUILD.gn @@ -77,8 +77,4 @@ static_library("messaging") { "${chip_root}/src/transport", "${chip_root}/src/transport/raw", ] - - if (chip_enable_icd_server) { - public_deps += [ "${chip_root}/src/app/icd:manager" ] - } } diff --git a/src/messaging/ReliableMessageProtocolConfig.cpp b/src/messaging/ReliableMessageProtocolConfig.cpp index 652531c8ee8567..c81325432cc51b 100644 --- a/src/messaging/ReliableMessageProtocolConfig.cpp +++ b/src/messaging/ReliableMessageProtocolConfig.cpp @@ -27,10 +27,7 @@ #include #include -#if CHIP_CONFIG_ENABLE_ICD_SERVER -#include // nogncheck -#include // nogncheck -#endif +#include namespace chip { @@ -73,9 +70,9 @@ Optional GetLocalMRPConfig() // TODO ICD LIT shall not advertise the SII key // Increase local MRP retry intervals by ICD polling intervals. That is, intervals for // which the device can be at sleep and not be able to receive any messages). - config.mIdleRetransTimeout += app::ICDManager::GetSlowPollingInterval(); - config.mActiveRetransTimeout += app::ICDManager::GetFastPollingInterval(); - config.mActiveThresholdTime = System::Clock::Milliseconds16(ICDManagementServer::GetInstance().GetActiveModeThresholdMs()); + config.mIdleRetransTimeout += CHIP_DEVICE_CONFIG_ICD_SLOW_POLL_INTERVAL; + config.mActiveRetransTimeout += CHIP_DEVICE_CONFIG_ICD_FAST_POLL_INTERVAL; + config.mActiveThresholdTime = System::Clock::Milliseconds16(CHIP_CONFIG_ICD_ACTIVE_MODE_THRESHOLD_MS); #endif #if CONFIG_BUILD_FOR_HOST_UNIT_TEST diff --git a/src/platform/Linux/BUILD.gn b/src/platform/Linux/BUILD.gn index 635fd446eb941e..9b0a50d026d168 100644 --- a/src/platform/Linux/BUILD.gn +++ b/src/platform/Linux/BUILD.gn @@ -109,7 +109,8 @@ static_library("Linux") { "${chip_root}/third_party/inipp", ] - public_configs = [] + public_configs = + [ "${chip_root}/src/lib/address_resolve:default_address_resolve_config" ] if (chip_mdns == "platform") { sources += [