Skip to content

Commit

Permalink
Add ICD Sender Class (#30385)
Browse files Browse the repository at this point in the history
  • Loading branch information
jepenven-silabs authored and pull[bot] committed Jan 31, 2024
1 parent 305ac27 commit d8e8700
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 13 deletions.
15 changes: 15 additions & 0 deletions src/app/icd/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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") {
Expand Down
104 changes: 104 additions & 0 deletions src/app/icd/ICDCheckInSender.cpp
Original file line number Diff line number Diff line change
@@ -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 <system/SystemPacketBuffer.h>

#include <protocols/secure_channel/CheckinMessage.h>

#include <lib/dnssd/Resolver.h>

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<SessionHandle> 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<Crypto::Aes128KeyByteArray>(), entry.key.As<Crypto::Aes128KeyByteArray>(),
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
57 changes: 57 additions & 0 deletions src/app/icd/ICDCheckInSender.h
Original file line number Diff line number Diff line change
@@ -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 <app/icd/ICDMonitoringTable.h>
#include <credentials/FabricTable.h>
#include <lib/address_resolve/AddressResolve.h>

#include <messaging/ExchangeMgr.h>

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
19 changes: 19 additions & 0 deletions src/app/icd/ICDMonitoringTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Crypto::Aes128KeyByteArray>(), icdMonitoringEntry.key.As<Crypto::Aes128KeyByteArray>(),
sizeof(Crypto::Aes128KeyByteArray));

return *this;
}

CHIP_ERROR ICDMonitoringTable::Get(uint16_t index, ICDMonitoringEntry & entry) const
{
entry.fabricIndex = this->mFabric;
Expand Down
8 changes: 7 additions & 1 deletion src/app/icd/ICDMonitoringTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,6 @@ struct ICDMonitoringEntry : public PersistentData<kICDMonitoringBufferSize>
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;
Expand All @@ -77,6 +76,13 @@ struct ICDMonitoringEntry : public PersistentData<kICDMonitoringBufferSize>
*/
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.
Expand Down
34 changes: 34 additions & 0 deletions src/app/tests/TestICDMonitoringTable.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<Crypto::Aes128KeyByteArray>())));
}

void TestEntryKeyFunctions(nlTestSuite * aSuite, void * aContext)
{
TestSessionKeystoreImpl keystore;
Expand Down Expand Up @@ -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",
Expand Down
4 changes: 0 additions & 4 deletions src/messaging/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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" ]
}
}
11 changes: 4 additions & 7 deletions src/messaging/ReliableMessageProtocolConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,7 @@
#include <platform/CHIPDeviceLayer.h>
#include <system/SystemClock.h>

#if CHIP_CONFIG_ENABLE_ICD_SERVER
#include <app/icd/ICDManagementServer.h> // nogncheck
#include <app/icd/ICDManager.h> // nogncheck
#endif
#include <platform/CHIPDeviceConfig.h>

namespace chip {

Expand Down Expand Up @@ -73,9 +70,9 @@ Optional<ReliableMessageProtocolConfig> 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
Expand Down
3 changes: 2 additions & 1 deletion src/platform/Linux/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -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 += [
Expand Down

0 comments on commit d8e8700

Please sign in to comment.