Coverage Report

Created: 2026-09-24 06:58

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