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