Matter SDK Coverage Report
Current view: top level - transport - SessionManager.cpp (source / functions) Coverage Total Hit
Test: SHA:704d97f9c619242ad76fcf75aeabc67802fa72d4 Lines: 78.3 % 604 473
Test Date: 2026-05-18 07:37:39 Functions: 65.2 % 46 30

            Line data    Source code
       1              : /*
       2              :  *
       3              :  *    Copyright (c) 2020-2021 Project CHIP Authors
       4              :  *    Copyright (c) 2013-2017 Nest Labs, Inc.
       5              :  *    All rights reserved.
       6              :  *
       7              :  *    Licensed under the Apache License, Version 2.0 (the "License");
       8              :  *    you may not use this file except in compliance with the License.
       9              :  *    You may obtain a copy of the License at
      10              :  *
      11              :  *        http://www.apache.org/licenses/LICENSE-2.0
      12              :  *
      13              :  *    Unless required by applicable law or agreed to in writing, software
      14              :  *    distributed under the License is distributed on an "AS IS" BASIS,
      15              :  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      16              :  *    See the License for the specific language governing permissions and
      17              :  *    limitations under the License.
      18              :  */
      19              : 
      20              : /**
      21              :  *    @file
      22              :  *      This file implements the CHIP Connection object that maintains a UDP connection.
      23              :  *      TODO This class should be extended to support TCP as well...
      24              :  *
      25              :  */
      26              : 
      27              : #include "SessionManager.h"
      28              : 
      29              : #include <inttypes.h>
      30              : #include <string.h>
      31              : 
      32              : #include "transport/TraceMessage.h"
      33              : #include <app/util/basic-types.h>
      34              : #include <credentials/GroupDataProvider.h>
      35              : #include <inttypes.h>
      36              : #include <lib/core/CHIPKeyIds.h>
      37              : #include <lib/core/Global.h>
      38              : #include <lib/support/AutoRelease.h>
      39              : #include <lib/support/CodeUtils.h>
      40              : #include <lib/support/SafeInt.h>
      41              : #include <lib/support/logging/CHIPLogging.h>
      42              : #include <platform/CHIPDeviceLayer.h>
      43              : #include <protocols/Protocols.h>
      44              : #include <protocols/secure_channel/Constants.h>
      45              : #include <tracing/macros.h>
      46              : #include <transport/GroupPeerMessageCounter.h>
      47              : #include <transport/GroupSession.h>
      48              : #include <transport/SecureMessageCodec.h>
      49              : #include <transport/TracingStructs.h>
      50              : #include <transport/TransportMgr.h>
      51              : #include <transport/raw/GroupcastTesting.h>
      52              : 
      53              : namespace chip {
      54              : 
      55              : using System::PacketBufferHandle;
      56              : using Transport::GroupPeerTable;
      57              : using Transport::PeerAddress;
      58              : using Transport::SecureSession;
      59              : 
      60              : namespace {
      61              : Global<GroupPeerTable> gGroupPeerTable;
      62              : 
      63              : // Helper function that strips off the interface ID from a peer address that is
      64              : // not an IPv6 link-local address.  For any other address type we should rely on
      65              : // the device's routing table to route messages sent.  Forcing messages down a
      66              : // specific interface might fail with "no route to host".
      67        15018 : void CorrectPeerAddressInterfaceID(Transport::PeerAddress & peerAddress)
      68              : {
      69        15018 :     if (peerAddress.GetIPAddress().IsIPv6LinkLocal())
      70              :     {
      71            0 :         return;
      72              :     }
      73        15018 :     peerAddress.SetInterface(Inet::InterfaceId::Null());
      74              : }
      75              : 
      76              : } // namespace
      77              : 
      78        25457 : uint32_t EncryptedPacketBufferHandle::GetMessageCounter() const
      79              : {
      80        25457 :     PacketHeader header;
      81        25457 :     uint16_t headerSize = 0;
      82        25457 :     CHIP_ERROR err      = header.Decode((*this)->Start(), (*this)->DataLength(), &headerSize);
      83              : 
      84        50914 :     if (err == CHIP_NO_ERROR)
      85              :     {
      86        25457 :         return header.GetMessageCounter();
      87              :     }
      88              : 
      89            0 :     ChipLogError(Inet, "Failed to decode EncryptedPacketBufferHandle header with error: %" CHIP_ERROR_FORMAT, err.Format());
      90              : 
      91            0 :     return 0;
      92              : }
      93              : 
      94          654 : SessionManager::SessionManager() : mState(State::kNotReady) {}
      95              : 
      96          654 : SessionManager::~SessionManager()
      97              : {
      98          654 :     this->Shutdown();
      99          654 : }
     100              : 
     101          464 : CHIP_ERROR SessionManager::Init(System::Layer * systemLayer, TransportMgrBase * transportMgr,
     102              :                                 Transport::MessageCounterManagerInterface * messageCounterManager,
     103              :                                 chip::PersistentStorageDelegate * storageDelegate, FabricTable * fabricTable,
     104              :                                 Crypto::SessionKeystore & sessionKeystore)
     105              : {
     106          464 :     VerifyOrReturnError(mState == State::kNotReady, CHIP_ERROR_INCORRECT_STATE);
     107          464 :     VerifyOrReturnError(transportMgr != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     108          464 :     VerifyOrReturnError(storageDelegate != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     109          464 :     VerifyOrReturnError(fabricTable != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     110          464 :     ReturnErrorOnFailure(fabricTable->AddFabricDelegate(this));
     111              : 
     112          464 :     mState                 = State::kInitialized;
     113          464 :     mSystemLayer           = systemLayer;
     114          464 :     mTransportMgr          = transportMgr;
     115          464 :     mMessageCounterManager = messageCounterManager;
     116          464 :     mFabricTable           = fabricTable;
     117          464 :     mSessionKeystore       = &sessionKeystore;
     118              : 
     119          464 :     mSecureSessions.Init();
     120              : 
     121          464 :     mGlobalUnencryptedMessageCounter.Init();
     122              : 
     123          464 :     ReturnErrorOnFailure(mGroupClientCounter.Init(storageDelegate));
     124              : 
     125          464 :     mTransportMgr->SetSessionManager(this);
     126              : 
     127              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     128          464 :     mConnCompleteCb = nullptr;
     129          464 :     mConnClosedCb   = nullptr;
     130              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     131              : 
     132              :     // Ensure MessageStats struct is at default state on Init
     133          464 :     mMessageStats = MessageStats();
     134              : 
     135          464 :     return CHIP_NO_ERROR;
     136              : }
     137              : 
     138         1117 : void SessionManager::Shutdown()
     139              : {
     140         1117 :     if (mFabricTable != nullptr)
     141              :     {
     142          464 :         mFabricTable->RemoveFabricDelegate(this);
     143          464 :         mFabricTable = nullptr;
     144              :     }
     145              : 
     146              :     // Ensure that we don't create new sessions as we iterate our session table.
     147         1117 :     mState = State::kNotReady;
     148              : 
     149              :     // Just in case some consumer forgot to do it, expire all our secure
     150              :     // sessions.  Note that this stands a good chance of crashing with a
     151              :     // null-deref if there are in fact any secure sessions left, since they will
     152              :     // try to notify their exchanges, which will then try to operate on
     153              :     // partially-shut-down objects.
     154         1117 :     ExpireAllSecureSessions();
     155              : 
     156              :     // We don't have a safe way to check or affect the state of our
     157              :     // mUnauthenticatedSessions.  We can only hope they got shut down properly.
     158              : 
     159         1117 :     mMessageCounterManager = nullptr;
     160              : 
     161         1117 :     mSystemLayer  = nullptr;
     162         1117 :     mTransportMgr = nullptr;
     163         1117 :     mCB           = nullptr;
     164         1117 : }
     165              : 
     166              : /**
     167              :  * @brief Notification that a fabric was removed.
     168              :  *        This function doesn't call ExpireAllSessionsForFabric
     169              :  *        since the CASE session might still be open to send a response
     170              :  *        on the removed fabric.
     171              :  */
     172            7 : void SessionManager::FabricRemoved(FabricIndex fabricIndex)
     173              : {
     174            7 :     TEMPORARY_RETURN_IGNORED gGroupPeerTable->FabricRemoved(fabricIndex);
     175            7 : }
     176              : 
     177        15111 : CHIP_ERROR SessionManager::PrepareMessage(const SessionHandle & sessionHandle, PayloadHeader & payloadHeader,
     178              :                                           System::PacketBufferHandle && message, EncryptedPacketBufferHandle & preparedMessage)
     179              : {
     180              :     MATTER_TRACE_SCOPE("PrepareMessage", "SessionManager");
     181              : 
     182        15111 :     PacketHeader packetHeader;
     183        15111 :     bool isControlMsg = IsControlMessage(payloadHeader);
     184        15111 :     if (isControlMsg)
     185              :     {
     186            0 :         packetHeader.SetSecureSessionControlMsg(true);
     187              :     }
     188              : 
     189        15111 :     if (sessionHandle->AllowsLargePayload())
     190              :     {
     191            0 :         VerifyOrReturnError(message->TotalLength() <= kMaxLargeAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG);
     192              :     }
     193              :     else
     194              :     {
     195        15111 :         VerifyOrReturnError(message->TotalLength() <= kMaxAppMessageLen, CHIP_ERROR_MESSAGE_TOO_LONG);
     196              :     }
     197              : 
     198              : #if CHIP_PROGRESS_LOGGING
     199              :     NodeId destination;
     200              :     FabricIndex fabricIndex;
     201              : #endif // CHIP_PROGRESS_LOGGING
     202              : 
     203        15110 :     NodeId sourceNodeId = kUndefinedNodeId;
     204        15110 :     PeerAddress destination_address;
     205              : 
     206        15110 :     switch (sessionHandle->GetSessionType())
     207              :     {
     208            3 :     case Transport::Session::SessionType::kGroupOutgoing: {
     209            3 :         auto groupSession = sessionHandle->AsOutgoingGroupSession();
     210            3 :         auto * groups     = Credentials::GetGroupDataProvider();
     211            3 :         VerifyOrReturnError(nullptr != groups, CHIP_ERROR_INTERNAL);
     212              : 
     213            3 :         const FabricInfo * fabric = mFabricTable->FindFabricWithIndex(groupSession->GetFabricIndex());
     214            3 :         VerifyOrReturnError(fabric != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     215              : 
     216            3 :         packetHeader.SetDestinationGroupId(groupSession->GetGroupId());
     217            3 :         packetHeader.SetMessageCounter(mGroupClientCounter.GetCounter(isControlMsg));
     218            3 :         TEMPORARY_RETURN_IGNORED mGroupClientCounter.IncrementCounter(isControlMsg);
     219            3 :         packetHeader.SetSessionType(Header::SessionType::kGroupSession);
     220            3 :         sourceNodeId = fabric->GetNodeId();
     221            3 :         packetHeader.SetSourceNodeId(sourceNodeId);
     222              : 
     223            3 :         if (!packetHeader.IsValidGroupMsg())
     224              :         {
     225            0 :             return CHIP_ERROR_INTERNAL;
     226              :         }
     227              : 
     228            3 :         Credentials::GroupDataProvider::GroupInfo info;
     229            3 :         ReturnErrorOnFailure(groups->GetGroupInfo(groupSession->GetFabricIndex(), groupSession->GetGroupId(), info));
     230            3 :         destination_address = (info.UsePerGroupAddress())
     231            3 :             ? Transport::PeerAddress::BuildMatterPerGroupMulticastAddress(fabric->GetFabricId(), groupSession->GetGroupId())
     232            3 :             : Transport::PeerAddress::BuildMatterIanaMulticastAddress();
     233              : 
     234              :         Crypto::SymmetricKeyContext * keyContext =
     235            3 :             groups->GetKeyContext(groupSession->GetFabricIndex(), groupSession->GetGroupId());
     236            3 :         VerifyOrReturnError(nullptr != keyContext, CHIP_ERROR_INTERNAL);
     237            3 :         packetHeader.SetSessionId(keyContext->GetKeyHash());
     238            3 :         CryptoContext cryptoContext(keyContext);
     239              : 
     240              :         // Trace before any encryption
     241              :         MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kGroupMessage, &payloadHeader, &packetHeader,
     242              :                                 chip::ByteSpan(message->Start(), message->TotalLength()),
     243              :                                 /* messageTotalSize = */
     244              :                                 (packetHeader.EncodeSizeBytes() + payloadHeader.EncodeSizeBytes() + message->TotalLength() +
     245              :                                  packetHeader.MICTagLength()));
     246            3 :         CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
     247              : 
     248              :         CryptoContext::NonceStorage nonce;
     249            3 :         ReturnErrorOnFailure(
     250              :             CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), packetHeader.GetMessageCounter(), sourceNodeId));
     251            3 :         CHIP_ERROR err = SecureMessageCodec::Encrypt(cryptoContext, nonce, payloadHeader, packetHeader, message);
     252            3 :         keyContext->Release();
     253            3 :         ReturnErrorOnFailure(err);
     254              : 
     255              : #if CHIP_PROGRESS_LOGGING
     256            3 :         destination = NodeIdFromGroupId(groupSession->GetGroupId());
     257            3 :         fabricIndex = groupSession->GetFabricIndex();
     258              : #endif // CHIP_PROGRESS_LOGGING
     259            3 :     }
     260            3 :     break;
     261        14984 :     case Transport::Session::SessionType::kSecure: {
     262        14984 :         SecureSession * session = sessionHandle->AsSecureSession();
     263        14984 :         if (session == nullptr)
     264              :         {
     265            0 :             return CHIP_ERROR_NOT_CONNECTED;
     266              :         }
     267              : 
     268        14984 :         MessageCounter & counter = session->GetSessionMessageCounter().GetLocalMessageCounter();
     269              :         uint32_t messageCounter;
     270        14984 :         ReturnErrorOnFailure(counter.AdvanceAndConsume(messageCounter));
     271              :         packetHeader
     272        14983 :             .SetMessageCounter(messageCounter)         //
     273        14983 :             .SetSessionId(session->GetPeerSessionId()) //
     274        14983 :             .SetSessionType(Header::SessionType::kUnicastSession);
     275              : 
     276        14983 :         destination_address           = session->GetPeerAddress();
     277        14983 :         CryptoContext & cryptoContext = session->GetCryptoContext();
     278              : 
     279              :         // Trace before any encryption
     280              :         MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kSecureSession, &payloadHeader, &packetHeader,
     281              :                                 chip::ByteSpan(message->Start(), message->TotalLength()),
     282              :                                 /* totalMessageSize = */
     283              :                                 (packetHeader.EncodeSizeBytes() + payloadHeader.EncodeSizeBytes() + message->TotalLength() +
     284              :                                  packetHeader.MICTagLength()));
     285        14983 :         CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
     286              : 
     287              :         CryptoContext::NonceStorage nonce;
     288        14983 :         sourceNodeId = session->GetLocalScopedNodeId().GetNodeId();
     289        14983 :         ReturnErrorOnFailure(CryptoContext::BuildNonce(nonce, packetHeader.GetSecurityFlags(), messageCounter, sourceNodeId));
     290              : 
     291        14983 :         ReturnErrorOnFailure(SecureMessageCodec::Encrypt(cryptoContext, nonce, payloadHeader, packetHeader, message));
     292              : 
     293              : #if CHIP_PROGRESS_LOGGING
     294        14983 :         destination = session->GetPeerNodeId();
     295        14983 :         fabricIndex = session->GetFabricIndex();
     296              : #endif // CHIP_PROGRESS_LOGGING
     297              :     }
     298        14983 :     break;
     299          123 :     case Transport::Session::SessionType::kUnauthenticated: {
     300          123 :         MessageCounter & counter = mGlobalUnencryptedMessageCounter;
     301              :         uint32_t messageCounter;
     302          123 :         ReturnErrorOnFailure(counter.AdvanceAndConsume(messageCounter));
     303          123 :         packetHeader.SetMessageCounter(messageCounter);
     304          123 :         Transport::UnauthenticatedSession * session = sessionHandle->AsUnauthenticatedSession();
     305          123 :         switch (session->GetSessionRole())
     306              :         {
     307           72 :         case Transport::UnauthenticatedSession::SessionRole::kInitiator:
     308           72 :             packetHeader.SetSourceNodeId(session->GetEphemeralInitiatorNodeID());
     309           72 :             break;
     310           51 :         case Transport::UnauthenticatedSession::SessionRole::kResponder:
     311           51 :             packetHeader.SetDestinationNodeId(session->GetEphemeralInitiatorNodeID());
     312           51 :             break;
     313              :         }
     314              : 
     315          123 :         auto unauthenticated = sessionHandle->AsUnauthenticatedSession();
     316          123 :         destination_address  = unauthenticated->GetPeerAddress();
     317              : 
     318              :         // Trace after all headers are settled.
     319              :         MATTER_LOG_MESSAGE_SEND(chip::Tracing::OutgoingMessageType::kUnauthenticated, &payloadHeader, &packetHeader,
     320              :                                 chip::ByteSpan(message->Start(), message->TotalLength()),
     321              :                                 /* messageTotalSize = */ packetHeader.EncodeSizeBytes() + payloadHeader.EncodeSizeBytes() +
     322              :                                     message->TotalLength());
     323          123 :         CHIP_TRACE_MESSAGE_SENT(payloadHeader, packetHeader, destination_address, message->Start(), message->TotalLength());
     324              : 
     325          123 :         ReturnErrorOnFailure(payloadHeader.EncodeBeforeData(message));
     326              : 
     327              : #if CHIP_PROGRESS_LOGGING
     328          123 :         destination = kUndefinedNodeId;
     329          123 :         fabricIndex = kUndefinedFabricIndex;
     330          123 :         if (session->GetSessionRole() == Transport::UnauthenticatedSession::SessionRole::kResponder)
     331              :         {
     332           51 :             destination = session->GetEphemeralInitiatorNodeID();
     333              :         }
     334           72 :         else if (session->GetSessionRole() == Transport::UnauthenticatedSession::SessionRole::kInitiator)
     335              :         {
     336           72 :             sourceNodeId = session->GetEphemeralInitiatorNodeID();
     337              :         }
     338              : #endif // CHIP_PROGRESS_LOGGING
     339              :     }
     340          123 :     break;
     341            0 :     default:
     342            0 :         return CHIP_ERROR_INTERNAL;
     343              :     }
     344              : 
     345        15109 :     ReturnErrorOnFailure(packetHeader.EncodeBeforeData(message));
     346              : 
     347              : #if CHIP_PROGRESS_LOGGING
     348        15109 :     CompressedFabricId compressedFabricId = kUndefinedCompressedFabricId;
     349              : 
     350        15109 :     if (fabricIndex != kUndefinedFabricIndex && mFabricTable != nullptr)
     351              :     {
     352        14939 :         auto fabricInfo = mFabricTable->FindFabricWithIndex(fabricIndex);
     353        14939 :         if (fabricInfo)
     354              :         {
     355        14939 :             compressedFabricId = fabricInfo->GetCompressedFabricId();
     356              :         }
     357              :     }
     358              : 
     359        15109 :     auto * protocolName = Protocols::GetProtocolName(payloadHeader.GetProtocolID());
     360        15109 :     auto * msgTypeName  = Protocols::GetMessageTypeName(payloadHeader.GetProtocolID(), payloadHeader.GetMessageType());
     361              : 
     362              :     //
     363              :     // 32-bit value maximum = 10 chars + text preamble (6) + trailer (1) + null (1) + 2 buffer = 20
     364              :     //
     365              :     char ackBuf[20];
     366        15109 :     ackBuf[0] = '\0';
     367        15109 :     if (payloadHeader.GetAckMessageCounter().HasValue())
     368              :     {
     369        12682 :         snprintf(ackBuf, sizeof(ackBuf), " (Ack:" ChipLogFormatMessageCounter ")", payloadHeader.GetAckMessageCounter().Value());
     370              :     }
     371              : 
     372        15109 :     char addressStr[Transport::PeerAddress::kMaxToStringSize] = { 0 };
     373        15109 :     destination_address.ToString(addressStr);
     374              : 
     375              :     // Work around pigweed not allowing more than 14 format args in a log
     376              :     // message when using tokenized logs.
     377              :     char typeStr[4 + 1 + 2 + 1];
     378        15109 :     snprintf(typeStr, sizeof(typeStr), "%04X:%02X", payloadHeader.GetProtocolID().GetProtocolId(), payloadHeader.GetMessageType());
     379              : 
     380              :     // More work around pigweed not allowing more than 14 format args in a log
     381              :     // message when using tokenized logs.
     382              :     // ChipLogFormatExchangeId logs the numeric exchange ID (at most 5 chars,
     383              :     // since it's a uint16_t) and one char for initiator/responder.  Plus we
     384              :     // need a null-terminator.
     385              :     char exchangeStr[5 + 1 + 1];
     386        15109 :     snprintf(exchangeStr, sizeof(exchangeStr), ChipLogFormatExchangeId, ChipLogValueExchangeIdFromSentHeader(payloadHeader));
     387              : 
     388              :     // More work around pigweed not allowing more than 14 format args in a log
     389              :     // message when using tokenized logs.
     390              :     // text(5) + source(16) + text(4) + fabricIndex(uint16_t, at most 5 chars) + text(1) + destination(16) + text(2) + compressed
     391              :     // fabric id(4) + text(1) + null-terminator
     392              :     char sourceDestinationStr[5 + 16 + 4 + 5 + 1 + 16 + 2 + 4 + 1 + 1];
     393        15109 :     snprintf(sourceDestinationStr, sizeof(sourceDestinationStr), "from " ChipLogFormatX64 " to %u:" ChipLogFormatX64 " [%04X]",
     394        15109 :              ChipLogValueX64(sourceNodeId), fabricIndex, ChipLogValueX64(destination), static_cast<uint16_t>(compressedFabricId));
     395              : 
     396              :     //
     397              :     // Legend that can be used to decode this log line can be found in messaging/README.md
     398              :     //
     399        15109 :     ChipLogProgress(ExchangeManager,
     400              :                     "<<< [E:%s S:%u M:" ChipLogFormatMessageCounter "%s] (%s) Msg TX %s [%s] --- Type %s (%s:%s) (B:%u)",
     401              :                     exchangeStr, sessionHandle->SessionIdForLogging(), packetHeader.GetMessageCounter(), ackBuf,
     402              :                     Transport::GetSessionTypeString(sessionHandle), sourceDestinationStr, addressStr, typeStr, protocolName,
     403              :                     msgTypeName, static_cast<unsigned>(message->TotalLength()));
     404              : #endif
     405              : 
     406        15109 :     preparedMessage = EncryptedPacketBufferHandle::MarkEncrypted(std::move(message));
     407              : 
     408        15109 :     CountMessagesSent(sessionHandle, payloadHeader);
     409        15109 :     return CHIP_NO_ERROR;
     410              : }
     411              : 
     412        15139 : CHIP_ERROR SessionManager::SendPreparedMessage(const SessionHandle & sessionHandle,
     413              :                                                const EncryptedPacketBufferHandle & preparedMessage)
     414              : {
     415        15139 :     VerifyOrReturnError(mState == State::kInitialized, CHIP_ERROR_INCORRECT_STATE);
     416        15139 :     VerifyOrReturnError(!preparedMessage.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     417              : 
     418        15139 :     Transport::PeerAddress multicastAddress; // Only used for the group case
     419              :     const Transport::PeerAddress * destination;
     420              : 
     421        15139 :     switch (sessionHandle->GetSessionType())
     422              :     {
     423            3 :     case Transport::Session::SessionType::kGroupOutgoing: {
     424            3 :         auto groupSession = sessionHandle->AsOutgoingGroupSession();
     425              : 
     426            3 :         const FabricInfo * fabric = mFabricTable->FindFabricWithIndex(groupSession->GetFabricIndex());
     427            3 :         VerifyOrReturnError(fabric != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
     428            3 :         auto * groups = Credentials::GetGroupDataProvider();
     429            3 :         VerifyOrReturnError(nullptr != groups, CHIP_ERROR_INTERNAL);
     430              : 
     431            3 :         Credentials::GroupDataProvider::GroupInfo info;
     432            3 :         ReturnErrorOnFailure(groups->GetGroupInfo(groupSession->GetFabricIndex(), groupSession->GetGroupId(), info));
     433            3 :         multicastAddress = (info.UsePerGroupAddress())
     434            3 :             ? Transport::PeerAddress::BuildMatterPerGroupMulticastAddress(fabric->GetFabricId(), groupSession->GetGroupId())
     435            3 :             : Transport::PeerAddress::BuildMatterIanaMulticastAddress();
     436            3 :         destination      = &multicastAddress;
     437              :     }
     438            3 :     break;
     439        15010 :     case Transport::Session::SessionType::kSecure: {
     440              :         // Find an active connection to the specified peer node
     441        15010 :         SecureSession * secure = sessionHandle->AsSecureSession();
     442              : 
     443              :         // This marks any connection where we send data to as 'active'
     444        15010 :         secure->MarkActive();
     445              : 
     446        15010 :         destination = &secure->GetPeerAddress();
     447              :     }
     448        15010 :     break;
     449          126 :     case Transport::Session::SessionType::kUnauthenticated: {
     450          126 :         auto unauthenticated = sessionHandle->AsUnauthenticatedSession();
     451          126 :         unauthenticated->MarkActive();
     452          126 :         destination = &unauthenticated->GetPeerAddress();
     453              :     }
     454          126 :     break;
     455            0 :     default:
     456            0 :         return CHIP_ERROR_INTERNAL;
     457              :     }
     458              : 
     459        30278 :     PacketBufferHandle msgBuf = preparedMessage.CastToWritable();
     460        15139 :     VerifyOrReturnError(!msgBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     461        15139 :     VerifyOrReturnError(!msgBuf->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     462              : 
     463              : #if CHIP_SYSTEM_CONFIG_MULTICAST_HOMING
     464        15139 :     if (sessionHandle->GetSessionType() == Transport::Session::SessionType::kGroupOutgoing)
     465              :     {
     466            3 :         chip::Inet::InterfaceIterator interfaceIt;
     467            3 :         chip::Inet::InterfaceId interfaceId = chip::Inet::InterfaceId::Null();
     468              :         chip::Inet::IPAddress addr;
     469            3 :         bool interfaceFound = false;
     470              : 
     471            9 :         while (interfaceIt.Next())
     472              :         {
     473            6 :             if (interfaceIt.SupportsMulticast() && interfaceIt.IsUp())
     474              :             {
     475              :                 char name[Inet::InterfaceId::kMaxIfNameLength];
     476            3 :                 TEMPORARY_RETURN_IGNORED interfaceIt.GetInterfaceName(name, Inet::InterfaceId::kMaxIfNameLength);
     477            3 :                 interfaceId = interfaceIt.GetInterfaceId();
     478            6 :                 if (CHIP_NO_ERROR == interfaceId.GetLinkLocalAddr(&addr))
     479              :                 {
     480            3 :                     ChipLogDetail(Inet, "Interface %s has a link local address", name);
     481              : 
     482            3 :                     interfaceFound             = true;
     483            3 :                     PacketBufferHandle tempBuf = msgBuf.CloneData();
     484            3 :                     VerifyOrReturnError(!tempBuf.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     485            3 :                     VerifyOrReturnError(!tempBuf->HasChainedBuffer(), CHIP_ERROR_INVALID_MESSAGE_LENGTH);
     486              : 
     487            3 :                     destination = &(multicastAddress.SetInterface(interfaceId));
     488            3 :                     if (mTransportMgr != nullptr)
     489              :                     {
     490            6 :                         if (CHIP_NO_ERROR != mTransportMgr->SendMessage(*destination, std::move(tempBuf)))
     491              :                         {
     492            0 :                             ChipLogError(Inet, "Failed to send Multicast message on interface %s", name);
     493              :                         }
     494              :                         else
     495              :                         {
     496            3 :                             ChipLogDetail(Inet, "Successfully send Multicast message on interface %s", name);
     497              :                         }
     498              :                     }
     499            3 :                 }
     500              :             }
     501              :         }
     502              : 
     503            3 :         if (!interfaceFound)
     504              :         {
     505            0 :             ChipLogError(Inet, "No valid Interface found.. Sending to the default one.. ");
     506              :         }
     507              :         else
     508              :         {
     509              :             // Always return No error, because we expect some interface to fails and others to always succeed (e.g. lo interface)
     510            3 :             return CHIP_NO_ERROR;
     511              :         }
     512            3 :     }
     513              : 
     514              : #endif // CHIP_SYSTEM_CONFIG_MULTICAST_HOMING
     515              : 
     516        15136 :     if (mTransportMgr != nullptr)
     517              :     {
     518        15136 :         CHIP_ERROR err = mTransportMgr->SendMessage(*destination, std::move(msgBuf));
     519              : #if CHIP_ERROR_LOGGING
     520        30272 :         if (err != CHIP_NO_ERROR)
     521              :         {
     522            5 :             char addressStr[Transport::PeerAddress::kMaxToStringSize] = { 0 };
     523            5 :             destination->ToString(addressStr);
     524            5 :             ChipLogError(Inet, "SendMessage() to %s failed: %" CHIP_ERROR_FORMAT, addressStr, err.Format());
     525              :         }
     526              : #endif // CHIP_ERROR_LOGGING
     527        15136 :         return err;
     528              :     }
     529              : 
     530            0 :     ChipLogError(Inet, "The transport manager is not initialized. Unable to send the message");
     531            0 :     return CHIP_ERROR_INCORRECT_STATE;
     532              : }
     533              : 
     534            0 : void SessionManager::ExpireAllSessions(const ScopedNodeId & node)
     535              : {
     536            0 :     ChipLogDetail(Inet, "Expiring all sessions for node " ChipLogFormatScopedNodeId "!!", ChipLogValueScopedNodeId(node));
     537              : 
     538            0 :     ForEachMatchingSession(node, [](auto * session) { session->MarkForEviction(); });
     539            0 : }
     540              : 
     541            2 : void SessionManager::ExpireAllSessionsForFabric(FabricIndex fabricIndex)
     542              : {
     543            2 :     ChipLogDetail(Inet, "Expiring all sessions for fabric 0x%x!!", static_cast<unsigned>(fabricIndex));
     544              : 
     545            8 :     ForEachMatchingSession(fabricIndex, [](auto * session) { session->MarkForEviction(); });
     546            2 : }
     547              : 
     548            0 : CHIP_ERROR SessionManager::ExpireAllSessionsOnLogicalFabric(const ScopedNodeId & node)
     549              : {
     550            0 :     ChipLogDetail(Inet, "Expiring all sessions to peer " ChipLogFormatScopedNodeId " that are on the same logical fabric!!",
     551              :                   ChipLogValueScopedNodeId(node));
     552              : 
     553            0 :     return ForEachMatchingSessionOnLogicalFabric(node, [](auto * session) { session->MarkForEviction(); });
     554              : }
     555              : 
     556            0 : CHIP_ERROR SessionManager::ExpireAllSessionsOnLogicalFabric(FabricIndex fabricIndex)
     557              : {
     558            0 :     ChipLogDetail(Inet, "Expiring all sessions on the same logical fabric as fabric 0x%x!!", static_cast<unsigned>(fabricIndex));
     559              : 
     560            0 :     return ForEachMatchingSessionOnLogicalFabric(fabricIndex, [](auto * session) { session->MarkForEviction(); });
     561              : }
     562              : 
     563            0 : void SessionManager::ExpireAllPASESessions()
     564              : {
     565            0 :     ChipLogDetail(Inet, "Expiring all PASE sessions");
     566            0 :     mSecureSessions.ForEachSession([&](auto session) {
     567            0 :         if (session->GetSecureSessionType() == Transport::SecureSession::Type::kPASE)
     568              :         {
     569            0 :             session->MarkForEviction();
     570              :         }
     571            0 :         return Loop::Continue;
     572              :     });
     573            0 : }
     574              : 
     575         1118 : void SessionManager::ExpireAllSecureSessions()
     576              : {
     577         1118 :     mSecureSessions.ForEachSession([&](auto session) {
     578         1650 :         session->MarkForEviction();
     579         1650 :         return Loop::Continue;
     580              :     });
     581         1118 : }
     582              : 
     583            0 : void SessionManager::MarkSessionsAsDefunct(const ScopedNodeId & node, const Optional<Transport::SecureSession::Type> & type)
     584              : {
     585            0 :     mSecureSessions.ForEachSession([&node, &type](auto session) {
     586            0 :         if (session->IsActiveSession() && session->GetPeer() == node &&
     587            0 :             (!type.HasValue() || type.Value() == session->GetSecureSessionType()))
     588              :         {
     589            0 :             session->MarkAsDefunct();
     590              :         }
     591            0 :         return Loop::Continue;
     592              :     });
     593            0 : }
     594              : 
     595            0 : void SessionManager::UpdateAllSessionsPeerAddress(const ScopedNodeId & node, const Transport::PeerAddress & addr)
     596              : {
     597            0 :     mSecureSessions.ForEachSession([&node, &addr](auto session) {
     598              :         // Arguably we should only be updating active and defunct sessions, but there is no harm
     599              :         // in updating evicted sessions.
     600            0 :         if (session->GetPeer() == node && Transport::SecureSession::Type::kCASE == session->GetSecureSessionType())
     601              :         {
     602            0 :             session->SetPeerAddress(addr);
     603              :         }
     604            0 :         return Loop::Continue;
     605              :     });
     606            0 : }
     607              : 
     608       133662 : Optional<SessionHandle> SessionManager::AllocateSession(SecureSession::Type secureSessionType,
     609              :                                                         const ScopedNodeId & sessionEvictionHint)
     610              : {
     611       133662 :     VerifyOrReturnValue(mState == State::kInitialized, NullOptional);
     612       133662 :     return mSecureSessions.CreateNewSecureSession(secureSessionType, sessionEvictionHint);
     613              : }
     614              : 
     615         1734 : CHIP_ERROR SessionManager::InjectPaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId, NodeId peerNodeId,
     616              :                                                         uint16_t peerSessionId, FabricIndex fabric,
     617              :                                                         const Transport::PeerAddress & peerAddress, CryptoContext::SessionRole role)
     618              : {
     619         1734 :     NodeId localNodeId              = kUndefinedNodeId;
     620              :     Optional<SessionHandle> session = mSecureSessions.CreateNewSecureSessionForTest(
     621              :         chip::Transport::SecureSession::Type::kPASE, localSessionId, localNodeId, peerNodeId, CATValues{}, peerSessionId, fabric,
     622         1734 :         GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig()));
     623         1734 :     VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY);
     624         1734 :     SecureSession * secureSession = session.Value()->AsSecureSession();
     625         1734 :     secureSession->SetPeerAddress(peerAddress);
     626              : 
     627         1734 :     size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH;
     628         1734 :     ByteSpan secret(reinterpret_cast<const uint8_t *>(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen);
     629         1734 :     ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret(
     630              :         *mSessionKeystore, secret, ByteSpan(), CryptoContext::SessionInfoType::kSessionEstablishment, role));
     631         1734 :     secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
     632         1734 :     sessionHolder.Grab(session.Value());
     633         1734 :     return CHIP_NO_ERROR;
     634         1734 : }
     635              : 
     636           24 : CHIP_ERROR SessionManager::InjectCaseSessionWithTestKey(SessionHolder & sessionHolder, uint16_t localSessionId,
     637              :                                                         uint16_t peerSessionId, NodeId localNodeId, NodeId peerNodeId,
     638              :                                                         FabricIndex fabric, const Transport::PeerAddress & peerAddress,
     639              :                                                         CryptoContext::SessionRole role, const CATValues & cats)
     640              : {
     641              :     Optional<SessionHandle> session = mSecureSessions.CreateNewSecureSessionForTest(
     642              :         chip::Transport::SecureSession::Type::kCASE, localSessionId, localNodeId, peerNodeId, cats, peerSessionId, fabric,
     643           24 :         GetLocalMRPConfig().ValueOr(GetDefaultMRPConfig()));
     644           24 :     VerifyOrReturnError(session.HasValue(), CHIP_ERROR_NO_MEMORY);
     645           24 :     SecureSession * secureSession = session.Value()->AsSecureSession();
     646           24 :     secureSession->SetPeerAddress(peerAddress);
     647              : 
     648           24 :     size_t secretLen = CHIP_CONFIG_TEST_SHARED_SECRET_LENGTH;
     649           24 :     ByteSpan secret(reinterpret_cast<const uint8_t *>(CHIP_CONFIG_TEST_SHARED_SECRET_VALUE), secretLen);
     650           24 :     ReturnErrorOnFailure(secureSession->GetCryptoContext().InitFromSecret(
     651              :         *mSessionKeystore, secret, ByteSpan(), CryptoContext::SessionInfoType::kSessionEstablishment, role));
     652           24 :     secureSession->GetSessionMessageCounter().GetPeerMessageCounter().SetCounter(Transport::PeerMessageCounter::kInitialSyncValue);
     653           24 :     sessionHolder.Grab(session.Value());
     654           24 :     return CHIP_NO_ERROR;
     655           24 : }
     656              : 
     657        15037 : void SessionManager::OnMessageReceived(const PeerAddress & peerAddress, System::PacketBufferHandle && msg,
     658              :                                        Transport::MessageTransportContext * ctxt)
     659              : {
     660        15037 :     PacketHeader partialPacketHeader;
     661              : 
     662        15037 :     CHIP_ERROR err = partialPacketHeader.DecodeFixed(msg);
     663        30074 :     if (err != CHIP_NO_ERROR)
     664              :     {
     665            0 :         ChipLogError(Inet, "Failed to decode packet header: %" CHIP_ERROR_FORMAT, err.Format());
     666            0 :         return;
     667              :     }
     668              : 
     669        15037 :     if (partialPacketHeader.IsEncrypted())
     670              :     {
     671        14915 :         if (partialPacketHeader.IsGroupSession())
     672              :         {
     673            9 :             SecureGroupMessageDispatch(partialPacketHeader, peerAddress, std::move(msg));
     674              :         }
     675              :         else
     676              :         {
     677        14906 :             SecureUnicastMessageDispatch(partialPacketHeader, peerAddress, std::move(msg), ctxt);
     678              :         }
     679              :     }
     680              :     else
     681              :     {
     682          122 :         UnauthenticatedMessageDispatch(partialPacketHeader, peerAddress, std::move(msg), ctxt);
     683              :     }
     684              : }
     685              : 
     686              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     687            3 : void SessionManager::HandleConnectionReceived(Transport::ActiveTCPConnectionState & conn)
     688              : {
     689              :     char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
     690              : 
     691            3 :     conn.mPeerAddr.ToString(peerAddrBuf);
     692            3 :     ChipLogProgress(Inet, "Received TCP connection request from %s.", peerAddrBuf);
     693              : 
     694            3 :     Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn.mAppState;
     695            3 :     if (appTCPConnCbCtxt != nullptr && appTCPConnCbCtxt->connReceivedCb != nullptr)
     696              :     {
     697            0 :         appTCPConnCbCtxt->connReceivedCb(conn);
     698              :     }
     699            3 : }
     700              : 
     701            3 : void SessionManager::HandleConnectionAttemptComplete(Transport::ActiveTCPConnectionHandle & conn, CHIP_ERROR conErr)
     702              : {
     703            3 :     VerifyOrReturn(!conn.IsNull());
     704              : 
     705            3 :     Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn->mAppState;
     706            3 :     bool callbackHandled                                       = false;
     707            3 :     if (appTCPConnCbCtxt != nullptr && appTCPConnCbCtxt->connCompleteCb != nullptr)
     708              :     {
     709            0 :         appTCPConnCbCtxt->connCompleteCb(conn, conErr);
     710            0 :         callbackHandled = true;
     711              :     }
     712              : 
     713            3 :     if ((mConnDelegate == nullptr || !mConnDelegate->OnTCPConnectionAttemptComplete(conn, conErr)) && !callbackHandled)
     714              :     {
     715              :         char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
     716            0 :         conn->mPeerAddr.ToString(peerAddrBuf);
     717              : 
     718            0 :         ChipLogProgress(Inet, "TCP Connection established with peer %s, but no registered handler.", peerAddrBuf);
     719              :     }
     720              : }
     721              : 
     722            4 : void SessionManager::HandleConnectionClosed(Transport::ActiveTCPConnectionState & conn, CHIP_ERROR conErr)
     723              : {
     724            4 :     Transport::AppTCPConnectionCallbackCtxt * appTCPConnCbCtxt = conn.mAppState;
     725            4 :     if (appTCPConnCbCtxt != nullptr && appTCPConnCbCtxt->connClosedCb != nullptr)
     726              :     {
     727            0 :         appTCPConnCbCtxt->connClosedCb(conn, conErr);
     728              :     }
     729            4 :     MarkSecureSessionOverTCPForEviction(conn, conErr);
     730            4 :     mUnauthenticatedSessions.MarkSessionOverTCPForEviction(conn);
     731            4 : }
     732              : 
     733            0 : CHIP_ERROR SessionManager::TCPConnect(const PeerAddress & peerAddress, Transport::AppTCPConnectionCallbackCtxt * appState,
     734              :                                       Transport::ActiveTCPConnectionHandle & peerConnState)
     735              : {
     736              :     char peerAddrBuf[chip::Transport::PeerAddress::kMaxToStringSize];
     737            0 :     peerAddress.ToString(peerAddrBuf);
     738            0 :     if (mTransportMgr != nullptr)
     739              :     {
     740            0 :         ChipLogProgress(Inet, "Connecting over TCP with peer at %s.", peerAddrBuf);
     741            0 :         return mTransportMgr->TCPConnect(peerAddress, appState, peerConnState);
     742              :     }
     743              : 
     744            0 :     ChipLogError(Inet, "The transport manager is not initialized. Unable to connect to peer at %s.", peerAddrBuf);
     745              : 
     746            0 :     return CHIP_ERROR_INCORRECT_STATE;
     747              : }
     748              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     749              : 
     750          122 : void SessionManager::UnauthenticatedMessageDispatch(const PacketHeader & partialPacketHeader,
     751              :                                                     const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg,
     752              :                                                     Transport::MessageTransportContext * ctxt)
     753              : {
     754              :     MATTER_TRACE_SCOPE("Unauthenticated Message Dispatch", "SessionManager");
     755              : 
     756              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     757          122 :     if (peerAddress.GetTransportType() == Transport::Type::kTcp && ctxt->conn.IsNull())
     758              :     {
     759            0 :         ChipLogError(Inet, "Connection object is missing for received message.");
     760            0 :         return;
     761              :     }
     762              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     763              : 
     764              :     // Drop unsecured messages with privacy enabled.
     765          122 :     if (partialPacketHeader.HasPrivacyFlag())
     766              :     {
     767            0 :         ChipLogError(Inet, "Dropping unauthenticated message with privacy flag set");
     768            0 :         return;
     769              :     }
     770              : 
     771              :     // Capture length before consuming headers.
     772          122 :     [[maybe_unused]] size_t messageTotalSize = msg->TotalLength();
     773              : 
     774          122 :     PacketHeader packetHeader;
     775          122 :     ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
     776              : 
     777          122 :     Optional<NodeId> source      = packetHeader.GetSourceNodeId();
     778          122 :     Optional<NodeId> destination = packetHeader.GetDestinationNodeId();
     779              : 
     780          122 :     if ((source.HasValue() && destination.HasValue()) || (!source.HasValue() && !destination.HasValue()))
     781              :     {
     782            0 :         ChipLogProgress(Inet,
     783              :                         "Received malformed unsecure packet with source 0x" ChipLogFormatX64 " destination 0x" ChipLogFormatX64,
     784              :                         ChipLogValueX64(source.ValueOr(kUndefinedNodeId)), ChipLogValueX64(destination.ValueOr(kUndefinedNodeId)));
     785            0 :         return; // ephemeral node id is only assigned to the initiator, there should be one and only one node id exists.
     786              :     }
     787              : 
     788          122 :     Optional<SessionHandle> optionalSession;
     789          122 :     if (source.HasValue())
     790              :     {
     791              :         // Assume peer is the initiator, we are the responder.
     792           71 :         optionalSession = mUnauthenticatedSessions.FindOrAllocateResponder(source.Value(), GetDefaultMRPConfig(), peerAddress);
     793           71 :         if (!optionalSession.HasValue())
     794              :         {
     795            0 :             ChipLogError(Inet, "UnauthenticatedSession exhausted");
     796            0 :             return;
     797              :         }
     798              :     }
     799              :     else
     800              :     {
     801              :         // Assume peer is the responder, we are the initiator.
     802           51 :         optionalSession = mUnauthenticatedSessions.FindInitiator(destination.Value(), peerAddress);
     803           51 :         if (!optionalSession.HasValue())
     804              :         {
     805            0 :             ChipLogProgress(Inet, "Received unknown unsecure packet for initiator 0x" ChipLogFormatX64,
     806              :                             ChipLogValueX64(destination.Value()));
     807            0 :             return;
     808              :         }
     809              :     }
     810              : 
     811          122 :     const SessionHandle & session                        = optionalSession.Value();
     812          122 :     Transport::UnauthenticatedSession * unsecuredSession = session->AsUnauthenticatedSession();
     813          122 :     Transport::PeerAddress mutablePeerAddress            = peerAddress;
     814          122 :     CorrectPeerAddressInterfaceID(mutablePeerAddress);
     815          122 :     unsecuredSession->SetPeerAddress(mutablePeerAddress);
     816          122 :     SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No;
     817              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     818              :     // Associate the unauthenticated session with the connection, if not done already.
     819          122 :     if (peerAddress.GetTransportType() == Transport::Type::kTcp)
     820              :     {
     821            1 :         Transport::ActiveTCPConnectionHandle sessionConn = unsecuredSession->GetTCPConnection();
     822            1 :         if (sessionConn.IsNull())
     823              :         {
     824            1 :             unsecuredSession->SetTCPConnection(ctxt->conn);
     825              :         }
     826              :         else
     827              :         {
     828            0 :             if (sessionConn != ctxt->conn)
     829              :             {
     830            0 :                 ChipLogError(Inet, "Unauthenticated data received over TCP connection %p instead of %p. Dropping it!",
     831              :                              static_cast<const void *>(ctxt->conn), static_cast<const void *>(sessionConn));
     832            0 :                 return;
     833              :             }
     834              :         }
     835            1 :     }
     836              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     837              : 
     838          122 :     unsecuredSession->MarkActiveRx();
     839              : 
     840          122 :     PayloadHeader payloadHeader;
     841          122 :     ReturnOnFailure(payloadHeader.DecodeAndConsume(msg));
     842              : 
     843              :     // Verify message counter
     844          122 :     CHIP_ERROR err = unsecuredSession->GetPeerMessageCounter().VerifyUnencrypted(packetHeader.GetMessageCounter());
     845          244 :     if (err == CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED)
     846              :     {
     847            0 :         ChipLogDetail(Inet,
     848              :                       "Received a duplicate message with MessageCounter:" ChipLogFormatMessageCounter
     849              :                       " on exchange " ChipLogFormatExchangeId,
     850              :                       packetHeader.GetMessageCounter(), ChipLogValueExchangeIdFromReceivedHeader(payloadHeader));
     851            0 :         isDuplicate = SessionMessageDelegate::DuplicateMessage::Yes;
     852            0 :         err         = CHIP_NO_ERROR;
     853              :     }
     854              :     else
     855              :     {
     856              :         // VerifyUnencrypted always returns one of CHIP_NO_ERROR or
     857              :         // CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED.
     858          122 :         unsecuredSession->GetPeerMessageCounter().CommitUnencrypted(packetHeader.GetMessageCounter());
     859              :     }
     860          122 :     if (mCB != nullptr)
     861              :     {
     862              :         MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kUnauthenticated, &payloadHeader, &packetHeader,
     863              :                                     unsecuredSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()),
     864              :                                     messageTotalSize);
     865              : 
     866          122 :         CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeader, unsecuredSession, peerAddress, msg->Start(), msg->TotalLength());
     867          122 :         CountMessagesReceived(session, payloadHeader);
     868          122 :         mCB->OnMessageReceived(packetHeader, payloadHeader, session, isDuplicate, std::move(msg));
     869              :     }
     870              :     else
     871              :     {
     872            0 :         ChipLogError(Inet, "Received UNSECURED message was not processed.");
     873              :     }
     874          122 : }
     875              : 
     876        14906 : void SessionManager::SecureUnicastMessageDispatch(const PacketHeader & partialPacketHeader,
     877              :                                                   const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg,
     878              :                                                   Transport::MessageTransportContext * ctxt)
     879              : {
     880              :     MATTER_TRACE_SCOPE("Secure Unicast Message Dispatch", "SessionManager");
     881              : 
     882        14906 :     CHIP_ERROR err = CHIP_NO_ERROR;
     883              : 
     884              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     885        14906 :     if (peerAddress.GetTransportType() == Transport::Type::kTcp && ctxt->conn.IsNull())
     886              :     {
     887            0 :         ChipLogError(Inet, "Connection object is missing for received message.");
     888           16 :         return;
     889              :     }
     890              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     891              : 
     892        14906 :     Optional<SessionHandle> session = mSecureSessions.FindSecureSessionByLocalKey(partialPacketHeader.GetSessionId());
     893        14906 :     if (!session.HasValue())
     894              :     {
     895           10 :         ChipLogError(Inet, "Data received on an unknown session (LSID=%d). Dropping it!", partialPacketHeader.GetSessionId());
     896           10 :         return;
     897              :     }
     898              : 
     899        14896 :     Transport::SecureSession * secureSession  = session.Value()->AsSecureSession();
     900        14896 :     Transport::PeerAddress mutablePeerAddress = peerAddress;
     901        14896 :     CorrectPeerAddressInterfaceID(mutablePeerAddress);
     902        14896 :     if (secureSession->GetPeerAddress() != mutablePeerAddress)
     903              :     {
     904            6 :         secureSession->SetPeerAddress(mutablePeerAddress);
     905              :     }
     906              : 
     907              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
     908              :     // Associate the secure session with the connection, if not done already.
     909        14896 :     if (peerAddress.GetTransportType() == Transport::Type::kTcp)
     910              :     {
     911            0 :         auto sessionConn = secureSession->GetTCPConnection();
     912            0 :         if (sessionConn.IsNull())
     913              :         {
     914            0 :             secureSession->SetTCPConnection(ctxt->conn);
     915              :         }
     916              :         else
     917              :         {
     918            0 :             if (sessionConn != ctxt->conn)
     919              :             {
     920            0 :                 ChipLogError(Inet, "Unicast data received over TCP connection %p instead of %p. Dropping it!",
     921              :                              static_cast<const void *>(ctxt->conn), static_cast<const void *>(sessionConn));
     922            0 :                 return;
     923              :             }
     924              :         }
     925            0 :     }
     926              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
     927              :     // Capture length before consuming headers.
     928        14896 :     [[maybe_unused]] size_t messageTotalSize = msg->TotalLength();
     929              : 
     930        14896 :     PayloadHeader payloadHeader;
     931              : 
     932              :     // Drop secure unicast messages with privacy enabled.
     933        14896 :     if (partialPacketHeader.HasPrivacyFlag())
     934              :     {
     935            1 :         ChipLogError(Inet, "Dropping secure unicast message with privacy flag set");
     936            1 :         return;
     937              :     }
     938              : 
     939        14895 :     PacketHeader packetHeader;
     940        14895 :     ReturnOnFailure(packetHeader.DecodeAndConsume(msg));
     941              : 
     942        14895 :     SessionMessageDelegate::DuplicateMessage isDuplicate = SessionMessageDelegate::DuplicateMessage::No;
     943              : 
     944        14895 :     if (msg.IsNull())
     945              :     {
     946            0 :         ChipLogError(Inet, "Secure transport received Unicast NULL packet, discarding");
     947            0 :         return;
     948              :     }
     949              : 
     950              :     // We need to allow through messages even on sessions that are pending
     951              :     // evictions, because for some cases (UpdateNOC, RemoveFabric, etc) there
     952              :     // can be a single exchange alive on the session waiting for a MRP ack, and
     953              :     // we need to make sure to send the ack through.  The exchange manager is
     954              :     // responsible for ensuring that such messages do not lead to new exchange
     955              :     // creation.
     956        14895 :     if (!secureSession->IsDefunct() && !secureSession->IsActiveSession() && !secureSession->IsPendingEviction())
     957              :     {
     958            0 :         ChipLogError(Inet, "Secure transport received message on a session in an invalid state (state = '%s')",
     959              :                      secureSession->GetStateStr());
     960            0 :         return;
     961              :     }
     962              : 
     963              :     // Decrypt and verify the message before message counter verification or any further processing.
     964              :     CryptoContext::NonceStorage nonce;
     965              :     // PASE Sessions use the undefined node ID of all zeroes, since there is no node ID to use
     966              :     // and the key is short-lived and always different for each PASE session.
     967        29800 :     CHIP_ERROR nonceResult = CryptoContext::BuildNonce(
     968        14895 :         nonce, packetHeader.GetSecurityFlags(), packetHeader.GetMessageCounter(),
     969        14905 :         secureSession->GetSecureSessionType() == SecureSession::Type::kCASE ? secureSession->GetPeerNodeId() : kUndefinedNodeId);
     970        44685 :     if ((nonceResult != CHIP_NO_ERROR) ||
     971        44685 :         SecureMessageCodec::Decrypt(secureSession->GetCryptoContext(), nonce, payloadHeader, packetHeader, msg) != CHIP_NO_ERROR)
     972              :     {
     973            3 :         ChipLogError(Inet, "Secure transport received message, but failed to decode/authenticate it, discarding");
     974            3 :         return;
     975              :     }
     976              : 
     977              :     err =
     978        14892 :         secureSession->GetSessionMessageCounter().GetPeerMessageCounter().VerifyEncryptedUnicast(packetHeader.GetMessageCounter());
     979        29784 :     if (err == CHIP_ERROR_DUPLICATE_MESSAGE_RECEIVED)
     980              :     {
     981            8 :         ChipLogDetail(Inet,
     982              :                       "Received a duplicate message with MessageCounter:" ChipLogFormatMessageCounter
     983              :                       " on exchange " ChipLogFormatExchangeId,
     984              :                       packetHeader.GetMessageCounter(), ChipLogValueExchangeIdFromReceivedHeader(payloadHeader));
     985            8 :         isDuplicate = SessionMessageDelegate::DuplicateMessage::Yes;
     986            8 :         err         = CHIP_NO_ERROR;
     987              :     }
     988        29784 :     if (err != CHIP_NO_ERROR)
     989              :     {
     990            0 :         ChipLogError(Inet, "Message counter verify failed, err = %" CHIP_ERROR_FORMAT, err.Format());
     991            0 :         return;
     992              :     }
     993              : 
     994        14892 :     secureSession->MarkActiveRx();
     995              : 
     996        14892 :     if (isDuplicate == SessionMessageDelegate::DuplicateMessage::Yes && !payloadHeader.NeedsAck())
     997              :     {
     998              :         // If it's a duplicate message, but doesn't require an ack, let's drop it right here to save CPU
     999              :         // cycles on further message processing.
    1000            2 :         return;
    1001              :     }
    1002              : 
    1003        14890 :     if (isDuplicate == SessionMessageDelegate::DuplicateMessage::No)
    1004              :     {
    1005        14884 :         secureSession->GetSessionMessageCounter().GetPeerMessageCounter().CommitEncryptedUnicast(packetHeader.GetMessageCounter());
    1006              :     }
    1007              : 
    1008        14890 :     if (mCB != nullptr)
    1009              :     {
    1010              :         MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kSecureUnicast, &payloadHeader, &packetHeader,
    1011              :                                     secureSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()),
    1012              :                                     messageTotalSize);
    1013        14890 :         CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeader, secureSession, peerAddress, msg->Start(), msg->TotalLength());
    1014              : 
    1015              :         // Always recompute whether a message is for a commissioning session based on the latest knowledge of
    1016              :         // the fabric table.
    1017        14890 :         if (secureSession->IsCASESession())
    1018              :         {
    1019           20 :             secureSession->SetCaseCommissioningSessionStatus(secureSession->GetFabricIndex() ==
    1020           10 :                                                              mFabricTable->GetPendingNewFabricIndex());
    1021              :         }
    1022              : 
    1023        14890 :         CountMessagesReceived(session.Value(), payloadHeader);
    1024        14890 :         mCB->OnMessageReceived(packetHeader, payloadHeader, session.Value(), isDuplicate, std::move(msg));
    1025              :     }
    1026              :     else
    1027              :     {
    1028            0 :         ChipLogError(Inet, "Received SECURED message was not processed.");
    1029              :     }
    1030        14906 : }
    1031              : 
    1032              : /**
    1033              :  * Helper function to implement a single attempt to decrypt a groupcast message
    1034              :  * using the given group key and privacy setting.
    1035              :  *
    1036              :  * @param[in] partialPacketHeader The partial packet header with non-obfuscated message fields (result of calling DecodeFixed).
    1037              :  * @param[out] packetHeaderCopy A copy of the packet header, to be filled with privacy decrypted fields
    1038              :  * @param[out] payloadHeader The payload header of the decrypted message
    1039              :  * @param[in] applyPrivacy Whether to apply privacy deobfuscation
    1040              :  * @param[out] msgCopy A copy of the message, to be filled with the decrypted message
    1041              :  * @param[in] mac The MAC of the message
    1042              :  * @param[in] groupContext The group context to use for decryption key material
    1043              :  *
    1044              :  * @return true if the message was decrypted successfully
    1045              :  * @return false if the message could not be decrypted
    1046              :  */
    1047           12 : static bool GroupKeyDecryptAttempt(const PacketHeader & partialPacketHeader, PacketHeader & packetHeaderCopy,
    1048              :                                    PayloadHeader & payloadHeader, bool applyPrivacy, System::PacketBufferHandle & msgCopy,
    1049              :                                    const MessageAuthenticationCode & mac,
    1050              :                                    const Credentials::GroupDataProvider::GroupSession & groupContext)
    1051              : {
    1052           12 :     bool decrypted = false;
    1053           12 :     CryptoContext context(groupContext.keyContext);
    1054              : 
    1055           12 :     if (applyPrivacy)
    1056              :     {
    1057              :         // Perform privacy deobfuscation, if applicable.
    1058            4 :         uint8_t * privacyHeader = partialPacketHeader.PrivacyHeader(msgCopy->Start());
    1059            4 :         size_t privacyLength    = partialPacketHeader.PrivacyHeaderLength();
    1060              : 
    1061              :         // Bounds check: we decrypt in place a privacy header located inside the packet.
    1062              :         // Validate that we are still within the packet as the length is based on header flags.
    1063            4 :         VerifyOrReturnValue(privacyHeader + privacyLength <= msgCopy->Start() + msgCopy->DataLength(), false);
    1064              : 
    1065            6 :         if (CHIP_NO_ERROR != context.PrivacyDecrypt(privacyHeader, privacyLength, privacyHeader, partialPacketHeader, mac))
    1066              :         {
    1067            0 :             return false;
    1068              :         }
    1069              :     }
    1070              : 
    1071           22 :     if (packetHeaderCopy.DecodeAndConsume(msgCopy) != CHIP_NO_ERROR)
    1072              :     {
    1073            1 :         ChipLogError(Inet, "Failed to decode Groupcast packet header. Discarding.");
    1074            1 :         return false;
    1075              :     }
    1076              : 
    1077              :     // Optimization to reduce number of decryption attempts
    1078           10 :     GroupId groupId = packetHeaderCopy.GetDestinationGroupId().Value();
    1079           10 :     if (groupId != groupContext.group_id)
    1080              :     {
    1081            3 :         return false;
    1082              :     }
    1083              : 
    1084              :     CryptoContext::NonceStorage nonce;
    1085              :     CHIP_ERROR nonceResult =
    1086            7 :         CryptoContext::BuildNonce(nonce, packetHeaderCopy.GetSecurityFlags(), packetHeaderCopy.GetMessageCounter(),
    1087            7 :                                   packetHeaderCopy.GetSourceNodeId().Value());
    1088           21 :     decrypted = (nonceResult == CHIP_NO_ERROR) &&
    1089           14 :         (CHIP_NO_ERROR == SecureMessageCodec::Decrypt(context, nonce, payloadHeader, packetHeaderCopy, msgCopy));
    1090              : 
    1091            7 :     return decrypted;
    1092           12 : }
    1093              : 
    1094            9 : void SessionManager::SecureGroupMessageDispatch(const PacketHeader & partialPacketHeader,
    1095              :                                                 const Transport::PeerAddress & peerAddress, System::PacketBufferHandle && msg)
    1096              : {
    1097              :     MATTER_TRACE_SCOPE("Group Message Dispatch", "SessionManager");
    1098              : 
    1099              :     // Capture length before consuming headers.
    1100            9 :     [[maybe_unused]] size_t messageTotalSize = msg->TotalLength();
    1101              : 
    1102            9 :     PayloadHeader payloadHeader;
    1103            9 :     PacketHeader packetHeaderCopy; /// Packet header decoded per group key, with privacy decrypted fields
    1104            9 :     System::PacketBufferHandle msgCopy;
    1105            9 :     Credentials::GroupDataProvider * groups = Credentials::GetGroupDataProvider();
    1106            9 :     VerifyOrReturn(nullptr != groups);
    1107            9 :     CHIP_ERROR err = CHIP_NO_ERROR;
    1108              : 
    1109            9 :     if (!partialPacketHeader.HasDestinationGroupId())
    1110              :     {
    1111            0 :         return; // malformed packet
    1112              :     }
    1113              : 
    1114              :     // Check if Message Header is valid first
    1115            9 :     if (!(partialPacketHeader.IsValidMCSPMsg() || partialPacketHeader.IsValidGroupMsg()))
    1116              :     {
    1117            0 :         ChipLogError(Inet, "Invalid condition found in packet header");
    1118            0 :         return;
    1119              :     }
    1120              : 
    1121              :     // Trial decryption with GroupDataProvider
    1122            9 :     Credentials::GroupDataProvider::GroupSession groupContext;
    1123              : 
    1124              :     AutoRelease<Credentials::GroupDataProvider::GroupSessionIterator> iter(
    1125            9 :         groups->IterateGroupSessions(partialPacketHeader.GetSessionId()));
    1126              : 
    1127            9 :     if (iter.IsNull())
    1128              :     {
    1129            0 :         ChipLogError(Inet, "Failed to retrieve Groups iterator. Discarding everything");
    1130            0 :         return;
    1131              :     }
    1132              : 
    1133              :     // Extract MIC from the end of the message.
    1134            9 :     uint8_t * data     = msg->Start();
    1135            9 :     size_t len         = msg->DataLength();
    1136            9 :     uint16_t footerLen = partialPacketHeader.MICTagLength();
    1137            9 :     VerifyOrReturn(footerLen <= len);
    1138              : 
    1139            9 :     uint16_t taglen = 0;
    1140              :     MessageAuthenticationCode mac;
    1141            9 :     ReturnOnFailure(mac.Decode(partialPacketHeader, &data[len - footerLen], footerLen, &taglen));
    1142            9 :     VerifyOrReturn(taglen == footerLen);
    1143              : 
    1144            9 :     bool decrypted = false;
    1145           18 :     while (!decrypted && iter->Next(groupContext))
    1146              :     {
    1147            9 :         CryptoContext context(groupContext.keyContext);
    1148            9 :         msgCopy = msg.CloneData();
    1149            9 :         if (msgCopy.IsNull())
    1150              :         {
    1151            0 :             ChipLogError(Inet, "Failed to clone Groupcast message buffer. Discarding.");
    1152            0 :             return;
    1153              :         }
    1154              : 
    1155            9 :         bool privacy = partialPacketHeader.HasPrivacyFlag();
    1156              :         decrypted =
    1157            9 :             GroupKeyDecryptAttempt(partialPacketHeader, packetHeaderCopy, payloadHeader, privacy, msgCopy, mac, groupContext);
    1158              : 
    1159              : #if CHIP_CONFIG_PRIVACY_ACCEPT_NONSPEC_SVE2
    1160            9 :         if (privacy && !decrypted)
    1161              :         {
    1162              :             // Try processing the P=1 message again without privacy as a work-around for invalid early-SVE2 nodes.
    1163            3 :             msgCopy = msg.CloneData();
    1164            3 :             if (msgCopy.IsNull())
    1165              :             {
    1166            0 :                 ChipLogError(Inet, "Failed to clone Groupcast message buffer. Discarding.");
    1167            0 :                 return;
    1168              :             }
    1169              :             decrypted =
    1170            3 :                 GroupKeyDecryptAttempt(partialPacketHeader, packetHeaderCopy, payloadHeader, false, msgCopy, mac, groupContext);
    1171              :         }
    1172              : #endif // CHIP_CONFIG_PRIVACY_ACCEPT_NONSPEC_SVE2
    1173            9 :     }
    1174              :     iter.Release();
    1175              :     // Groupcast Testing
    1176            9 :     auto & testing = chip::Groupcast::GetTesting();
    1177            9 :     if (testing.IsEnabled() && testing.IsFabricUnderTest(groupContext.fabric_index))
    1178              :     {
    1179            0 :         testing.SetGroupID(packetHeaderCopy.GetDestinationGroupId().Value());
    1180            0 :         if (!decrypted)
    1181              :         {
    1182            0 :             testing.SetTestResult(chip::Groupcast::Testing::Result::kNoAvailableKey);
    1183              :         }
    1184              :     }
    1185            9 :     if (!decrypted)
    1186              :     {
    1187            2 :         ChipLogError(Inet, "Failed to decrypt group message. Discarding everything");
    1188            2 :         return;
    1189              :     }
    1190            7 :     msg = std::move(msgCopy);
    1191              : 
    1192              :     // MCSP check
    1193            7 :     if (packetHeaderCopy.IsValidMCSPMsg())
    1194              :     {
    1195              :         // TODO: When MCSP Msg, create Secure Session instead of a Group session
    1196              : 
    1197              :         // TODO
    1198              :         // if (packetHeaderCopy.GetDestinationNodeId().Value() == ThisDeviceNodeID)
    1199              :         // {
    1200              :         //     MCSP processing..
    1201              :         // }
    1202              : 
    1203            0 :         return;
    1204              :     }
    1205              : 
    1206              :     // Group Messages should never send an Ack
    1207            7 :     if (payloadHeader.NeedsAck())
    1208              :     {
    1209            0 :         ChipLogError(Inet, "Unexpected ACK requested for group message");
    1210            0 :         return;
    1211              :     }
    1212              : 
    1213              :     // Handle Group message counter here spec 4.7.3
    1214              :     // spec 4.5.1.2 for msg counter
    1215            7 :     Transport::PeerMessageCounter * counter = nullptr;
    1216              : 
    1217            7 :     if (CHIP_NO_ERROR ==
    1218           21 :         gGroupPeerTable->FindOrAddPeer(groupContext.fabric_index, packetHeaderCopy.GetSourceNodeId().Value(),
    1219           14 :                                        packetHeaderCopy.IsSecureSessionControlMsg(), counter))
    1220              :     {
    1221            7 :         if (Credentials::GroupDataProvider::SecurityPolicy::kTrustFirst == groupContext.security_policy)
    1222              :         {
    1223            4 :             err = counter->VerifyOrTrustFirstGroup(packetHeaderCopy.GetMessageCounter());
    1224              :         }
    1225              :         else
    1226              :         {
    1227              : 
    1228              :             // TODO support cache and sync with MCSP. Issue  #11689
    1229            3 :             ChipLogError(Inet, "Received Group Msg with key policy Cache and Sync, but MCSP is not implemented");
    1230            3 :             return;
    1231              : 
    1232              :             // cache and sync
    1233              :             // err = counter->VerifyGroup(packetHeaderCopy.GetMessageCounter());
    1234              :         }
    1235              : 
    1236            8 :         if (err != CHIP_NO_ERROR)
    1237              :         {
    1238              :             // Exit now, since Group Messages don't have acks or responses of any kind.
    1239            1 :             ChipLogError(Inet, "Message counter verify failed, err = %" CHIP_ERROR_FORMAT, err.Format());
    1240            1 :             return;
    1241              :         }
    1242              :     }
    1243              :     else
    1244              :     {
    1245            0 :         ChipLogError(Inet,
    1246              :                      "Group Counter Tables full or invalid NodeId/FabricIndex after decryption of message, dropping everything");
    1247            0 :         return;
    1248              :     }
    1249              : 
    1250            3 :     counter->CommitGroup(packetHeaderCopy.GetMessageCounter());
    1251              : 
    1252            3 :     if (mCB != nullptr)
    1253              :     {
    1254              :         // TODO : When MCSP is done, clean up session creation logic
    1255            3 :         Transport::IncomingGroupSession groupSession(groupContext.group_id, groupContext.fabric_index,
    1256            3 :                                                      packetHeaderCopy.GetSourceNodeId().Value());
    1257              : 
    1258              :         MATTER_LOG_MESSAGE_RECEIVED(chip::Tracing::IncomingMessageType::kGroupMessage, &payloadHeader, &packetHeaderCopy,
    1259              :                                     &groupSession, &peerAddress, chip::ByteSpan(msg->Start(), msg->TotalLength()),
    1260              :                                     messageTotalSize);
    1261              : 
    1262            3 :         CHIP_TRACE_MESSAGE_RECEIVED(payloadHeader, packetHeaderCopy, &groupSession, peerAddress, msg->Start(), msg->TotalLength());
    1263            3 :         SessionHandle session(groupSession);
    1264              : 
    1265            3 :         CountMessagesReceived(session, payloadHeader);
    1266            3 :         mCB->OnMessageReceived(packetHeaderCopy, payloadHeader, session, SessionMessageDelegate::DuplicateMessage::No,
    1267            3 :                                std::move(msg));
    1268            3 :     }
    1269              :     else
    1270              :     {
    1271            0 :         ChipLogError(Inet, "Received GROUP message was not processed.");
    1272              :     }
    1273           18 : }
    1274              : 
    1275            1 : Optional<SessionHandle> SessionManager::FindSecureSessionForNode(ScopedNodeId peerNodeId,
    1276              :                                                                  const Optional<Transport::SecureSession::Type> & type,
    1277              :                                                                  TransportPayloadCapability transportPayloadCapability)
    1278              : {
    1279            1 :     SecureSession * mrpSession = nullptr;
    1280              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
    1281            1 :     SecureSession * tcpSession = nullptr;
    1282              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
    1283              : 
    1284            1 :     mSecureSessions.ForEachSession([&peerNodeId, &type, &mrpSession,
    1285              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
    1286              :                                     &tcpSession,
    1287              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
    1288           15 :                                     &transportPayloadCapability](auto session) {
    1289            4 :         if (session->IsActiveSession() && session->GetPeer() == peerNodeId &&
    1290            2 :             (!type.HasValue() || type.Value() == session->GetSecureSessionType()))
    1291              :         {
    1292            2 :             if (transportPayloadCapability == TransportPayloadCapability::kMRPOrTCPCompatiblePayload ||
    1293            2 :                 transportPayloadCapability == TransportPayloadCapability::kLargePayload)
    1294              :             {
    1295              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
    1296              :                 // Set up a TCP transport based session as standby
    1297            0 :                 if ((tcpSession == nullptr || tcpSession->GetLastPeerActivityTime() < session->GetLastPeerActivityTime()) &&
    1298            0 :                     !session->GetTCPConnection().IsNull())
    1299              :                 {
    1300            0 :                     tcpSession = session;
    1301              :                 }
    1302              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
    1303              :             }
    1304              : 
    1305            2 :             if ((mrpSession == nullptr) || (mrpSession->GetLastPeerActivityTime() < session->GetLastPeerActivityTime()))
    1306              :             {
    1307            2 :                 mrpSession = session;
    1308              :             }
    1309              :         }
    1310              : 
    1311            2 :         return Loop::Continue;
    1312              :     });
    1313              : 
    1314              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
    1315            1 :     if (transportPayloadCapability == TransportPayloadCapability::kLargePayload)
    1316              :     {
    1317            0 :         return tcpSession != nullptr ? MakeOptional<SessionHandle>(*tcpSession) : Optional<SessionHandle>::Missing();
    1318              :     }
    1319              : 
    1320            1 :     if (transportPayloadCapability == TransportPayloadCapability::kMRPOrTCPCompatiblePayload)
    1321              :     {
    1322              :         // If MRP-based session is available, use it.
    1323            0 :         if (mrpSession != nullptr)
    1324              :         {
    1325            0 :             return MakeOptional<SessionHandle>(*mrpSession);
    1326              :         }
    1327              : 
    1328              :         // Otherwise, look for a tcp-based session
    1329            0 :         if (tcpSession != nullptr)
    1330              :         {
    1331            0 :             return MakeOptional<SessionHandle>(*tcpSession);
    1332              :         }
    1333              : 
    1334            0 :         return Optional<SessionHandle>::Missing();
    1335              :     }
    1336              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
    1337              : 
    1338            1 :     return mrpSession != nullptr ? MakeOptional<SessionHandle>(*mrpSession) : Optional<SessionHandle>::Missing();
    1339              : }
    1340              : 
    1341              : #if INET_CONFIG_ENABLE_TCP_ENDPOINT
    1342            4 : void SessionManager::MarkSecureSessionOverTCPForEviction(Transport::ActiveTCPConnectionState & conn, CHIP_ERROR conErr)
    1343              : {
    1344              :     // Mark the corresponding secure sessions for eviction
    1345            4 :     mSecureSessions.ForEachSession([&](auto session) {
    1346            1 :         if (session->GetTCPConnection() == conn)
    1347              :         {
    1348            1 :             bool isActive = session->IsActiveSession();
    1349              : 
    1350            1 :             if (isActive)
    1351              :             {
    1352              :                 // Notify the SessionConnection delegate of the connection
    1353              :                 // closure before session eviction detaches holders and
    1354              :                 // releases exchanges.
    1355            0 :                 if (mConnDelegate != nullptr)
    1356              :                 {
    1357            0 :                     SessionHandle handle(*session);
    1358            0 :                     mConnDelegate->OnTCPConnectionClosed(conn, handle, conErr);
    1359            0 :                 }
    1360              :             }
    1361              : 
    1362              :             // Explicitly release the TCP connection handle to ensure the transport resource is reclaimed immediately.
    1363            1 :             session->ReleaseTCPConnection();
    1364              : 
    1365              :             // Mark session for eviction regardless of its current state (Active, Defunct, or Establishing).
    1366            1 :             session->MarkForEviction();
    1367              :         }
    1368              : 
    1369            1 :         return Loop::Continue;
    1370              :     });
    1371            4 : }
    1372              : #endif // INET_CONFIG_ENABLE_TCP_ENDPOINT
    1373              : 
    1374              : /**
    1375              :  * Provides a means to get diagnostic information such as number of sessions.
    1376              :  */
    1377            0 : [[maybe_unused]] CHIP_ERROR SessionManager::ForEachSessionHandle(void * context, SessionHandleCallback lambda)
    1378              : {
    1379            0 :     mSecureSessions.ForEachSession([&](auto session) {
    1380            0 :         SessionHandle handle(*session);
    1381            0 :         lambda(context, handle);
    1382            0 :         return Loop::Continue;
    1383            0 :     });
    1384            0 :     return CHIP_NO_ERROR;
    1385              : }
    1386              : 
    1387              : // Session handle parameter included here for future counting usage.
    1388        15015 : void SessionManager::CountMessagesReceived(const SessionHandle &, const PayloadHeader & payloadHeader)
    1389              : {
    1390        15015 :     if (payloadHeader.GetProtocolID() == Protocols::InteractionModel::Id)
    1391              :     {
    1392        12560 :         mMessageStats.interactionModelMessagesReceived++;
    1393              :     }
    1394        15015 : }
    1395              : 
    1396              : // Session handle parameter included here for future counting usage.
    1397        15109 : void SessionManager::CountMessagesSent(const SessionHandle &, const PayloadHeader & payloadHeader)
    1398              : {
    1399        15109 :     if (payloadHeader.GetProtocolID() == Protocols::InteractionModel::Id)
    1400              :     {
    1401        12614 :         mMessageStats.interactionModelMessagesSent++;
    1402              :     }
    1403        15109 : }
    1404              : 
    1405              : } // namespace chip
        

Generated by: LCOV version 2.0-1