Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2020 Project CHIP Authors
4 : *
5 : * Licensed under the Apache License, Version 2.0 (the "License");
6 : * you may not use this file except in compliance with the License.
7 : * You may obtain a copy of the License at
8 : *
9 : * http://www.apache.org/licenses/LICENSE-2.0
10 : *
11 : * Unless required by applicable law or agreed to in writing, software
12 : * distributed under the License is distributed on an "AS IS" BASIS,
13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 : * See the License for the specific language governing permissions and
15 : * limitations under the License.
16 : */
17 :
18 : /**
19 : * @file
20 : * This file implements the ExchangeContext class.
21 : *
22 : */
23 : #ifndef __STDC_FORMAT_MACROS
24 : #define __STDC_FORMAT_MACROS
25 : #endif
26 :
27 : #ifndef __STDC_LIMIT_MACROS
28 : #define __STDC_LIMIT_MACROS
29 : #endif
30 :
31 : #include <inttypes.h>
32 : #include <stdint.h>
33 : #include <stdlib.h>
34 :
35 : #include <app/icd/server/ICDServerConfig.h>
36 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
37 : #include <app/icd/server/ICDNotifier.h> // nogncheck
38 : #endif
39 : #include <lib/core/CHIPCore.h>
40 : #include <lib/core/CHIPEncoding.h>
41 : #include <lib/core/CHIPKeyIds.h>
42 : #include <lib/support/Defer.h>
43 : #include <lib/support/TypeTraits.h>
44 : #include <lib/support/logging/CHIPLogging.h>
45 : #include <messaging/ApplicationExchangeDispatch.h>
46 : #include <messaging/EphemeralExchangeDispatch.h>
47 : #include <messaging/ExchangeContext.h>
48 : #include <messaging/ExchangeMgr.h>
49 : #include <platform/LockTracker.h>
50 : #include <protocols/Protocols.h>
51 : #include <protocols/secure_channel/Constants.h>
52 :
53 : using namespace chip::Encoding;
54 : using namespace chip::Inet;
55 : using namespace chip::System;
56 :
57 : namespace chip {
58 : namespace Messaging {
59 :
60 82 : static void DefaultOnMessageReceived(ExchangeContext * ec, Protocols::Id protocolId, uint8_t msgType, uint32_t messageCounter,
61 : PacketBufferHandle && payload)
62 : {
63 82 : ChipLogError(ExchangeManager,
64 : "Dropping unexpected message of type " ChipLogFormatMessageType " with protocolId " ChipLogFormatProtocolId
65 : " and MessageCounter:" ChipLogFormatMessageCounter " on exchange " ChipLogFormatExchange,
66 : msgType, ChipLogValueProtocolId(protocolId), messageCounter, ChipLogValueExchange(ec));
67 82 : }
68 :
69 36353 : bool ExchangeContext::IsInitiator() const
70 : {
71 36353 : return mFlags.Has(Flags::kFlagInitiator);
72 : }
73 :
74 33487 : bool ExchangeContext::IsResponseExpected() const
75 : {
76 33487 : return mFlags.Has(Flags::kFlagResponseExpected);
77 : }
78 :
79 12682 : void ExchangeContext::SetResponseExpected(bool inResponseExpected)
80 : {
81 12682 : mFlags.Set(Flags::kFlagResponseExpected, inResponseExpected);
82 12682 : SetWaitingForResponseOrAck(inResponseExpected);
83 12682 : }
84 :
85 6324 : void ExchangeContext::UseSuggestedResponseTimeout(Timeout applicationProcessingTimeout)
86 : {
87 6324 : SetResponseTimeout(mSession->ComputeRoundTripTimeout(applicationProcessingTimeout));
88 6324 : }
89 :
90 6362 : void ExchangeContext::SetResponseTimeout(Timeout timeout)
91 : {
92 6362 : mResponseTimeout = timeout;
93 6362 : }
94 :
95 9554 : CHIP_ERROR ExchangeContext::SendMessage(Protocols::Id protocolId, uint8_t msgType, PacketBufferHandle && msgBuf,
96 : const SendFlags & sendFlags)
97 : {
98 : // This is the first point all outgoing messages funnel through. Ensure
99 : // that our message sends are all synchronized correctly.
100 9554 : assertChipStackLockedByCurrentThread();
101 :
102 : bool isStandaloneAck =
103 9554 : (protocolId == Protocols::SecureChannel::Id) && msgType == to_underlying(Protocols::SecureChannel::MsgType::StandaloneAck);
104 :
105 9554 : VerifyOrReturnError(mExchangeMgr != nullptr, CHIP_ERROR_INTERNAL);
106 9554 : VerifyOrReturnError(mSession, CHIP_ERROR_CONNECTION_ABORTED);
107 :
108 : // Don't let method get called on a freed object.
109 9542 : VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() > 0);
110 :
111 : // we hold the exchange context here in case the entity that
112 : // originally generated it tries to close it as a result of
113 : // an error arising below. at the end, we have to close it.
114 9542 : ExchangeHandle ref(*this);
115 :
116 : // If session requires MRP, NoAutoRequestAck send flag is not specified and is not a group exchange context, request reliable
117 : // transmission.
118 : bool reliableTransmissionRequested =
119 9542 : GetSessionHandle()->AllowsMRP() && !sendFlags.Has(SendMessageFlags::kNoAutoRequestAck) && !IsGroupExchangeContext();
120 :
121 9542 : bool currentMessageExpectResponse = false;
122 : // If a response message is expected...
123 9542 : if (sendFlags.Has(SendMessageFlags::kExpectResponse) && !IsGroupExchangeContext())
124 : {
125 : // Only one 'response expected' message can be outstanding at a time.
126 6390 : if (IsResponseExpected())
127 : {
128 : // TODO: add a test for this case.
129 0 : return CHIP_ERROR_INCORRECT_STATE;
130 : }
131 :
132 6390 : SetResponseExpected(true);
133 :
134 : // Arm the response timer if a timeout has been specified.
135 6390 : if (mResponseTimeout > System::Clock::kZero)
136 : {
137 6337 : CHIP_ERROR err = StartResponseTimer();
138 6337 : if (err != CHIP_NO_ERROR)
139 : {
140 0 : SetResponseExpected(false);
141 0 : return err;
142 : }
143 6337 : currentMessageExpectResponse = true;
144 : }
145 : }
146 :
147 : {
148 : // ExchangeContext for group are supposed to always be Initiator
149 9542 : if (IsGroupExchangeContext() && !IsInitiator())
150 : {
151 0 : return CHIP_ERROR_INTERNAL;
152 : }
153 :
154 : //
155 : // It is possible that we might have evicted a session as a side-effect of processing an inbound message on this exchange.
156 : // We cannot proceed any further sending a message since we don't have an attached session, so let's error out.
157 : //
158 : // This should not happen to well-behaved logic attempting to sending messages on exchanges, so let's print out a warning
159 : // to ensure it alerts someone to fixing their logic...
160 : //
161 9542 : if (!mSession)
162 : {
163 0 : ChipLogError(ExchangeManager,
164 : "WARNING: We shouldn't be sending a message on an exchange that has no attached session...");
165 0 : return CHIP_ERROR_MISSING_SECURE_SESSION;
166 : }
167 :
168 9542 : SessionHandle session = GetSessionHandle();
169 : CHIP_ERROR err;
170 :
171 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
172 9542 : if (mInjectedFailures.Has(InjectedFailureType::kFailOnSend))
173 : {
174 3 : err = CHIP_ERROR_SENDING_BLOCKED;
175 : }
176 : else
177 : {
178 : #endif
179 9539 : err = mDispatch.SendMessage(GetExchangeMgr()->GetSessionManager(), session, mExchangeId, IsInitiator(),
180 : GetReliableMessageContext(), reliableTransmissionRequested, protocolId, msgType,
181 9539 : std::move(msgBuf));
182 : #if CONFIG_BUILD_FOR_HOST_UNIT_TEST
183 : }
184 : #endif
185 9542 : if (err != CHIP_NO_ERROR)
186 : {
187 : // We should only cancel the response timer if the ExchangeContext fails to send the message that expects a
188 : // response.
189 8 : if (currentMessageExpectResponse)
190 : {
191 3 : CancelResponseTimer();
192 3 : SetResponseExpected(false);
193 : }
194 :
195 : // If we can't even send a message (send failed with a non-transient
196 : // error), mark the session as defunct, just like we would if we
197 : // thought we sent the message and never got a response.
198 8 : if (session->IsSecureSession() && session->AsSecureSession()->IsCASESession())
199 : {
200 0 : session->AsSecureSession()->MarkAsDefunct();
201 : }
202 : }
203 : else
204 : {
205 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
206 : app::ICDNotifier::GetInstance().NotifyNetworkActivityNotification();
207 : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
208 :
209 : // Standalone acks are not application-level message sends.
210 9534 : if (!isStandaloneAck)
211 : {
212 : //
213 : // Once we've sent the message successfully, we can clear out the WillSendMessage flag.
214 : //
215 8005 : mFlags.Clear(Flags::kFlagWillSendMessage);
216 8005 : MessageHandled();
217 : }
218 : }
219 :
220 9542 : return err;
221 9542 : }
222 9542 : }
223 :
224 6546 : void ExchangeContext::DoClose(bool clearRetransTable)
225 : {
226 6546 : if (mFlags.Has(Flags::kFlagClosed))
227 : {
228 3278 : return;
229 : }
230 :
231 3268 : mFlags.Set(Flags::kFlagClosed);
232 :
233 : // Clear protocol callbacks
234 3268 : if (mDelegate != nullptr)
235 : {
236 2406 : mDelegate->OnExchangeClosing(this);
237 : }
238 3268 : mDelegate = nullptr;
239 :
240 : // Closure of an exchange context is based on ref counting. The Protocol, when it calls DoClose(), indicates that
241 : // it is done with the exchange context and the message layer sets all callbacks to NULL and does not send anything
242 : // received on the exchange context up to higher layers. At this point, the message layer needs to handle the
243 : // remaining work to be done on that exchange, (e.g. send all pending acks) before truly cleaning it up.
244 3268 : FlushAcks();
245 :
246 : // In case the protocol wants a harder release of the EC right away, such as calling Abort(), exchange
247 : // needs to clear the MRP retransmission table immediately.
248 3268 : if (clearRetransTable)
249 : {
250 202 : mExchangeMgr->GetReliableMessageMgr()->ClearRetransTable(this);
251 : }
252 :
253 3268 : if (IsResponseExpected())
254 : {
255 : // Cancel the response timer.
256 98 : CancelResponseTimer();
257 : }
258 : }
259 :
260 : /**
261 : * Gracefully close an exchange context. This call decrements the
262 : * reference count and releases the exchange when the reference
263 : * count goes to zero.
264 : *
265 : */
266 3071 : void ExchangeContext::Close()
267 : {
268 3071 : VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() > 0);
269 :
270 : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
271 : ChipLogDetail(ExchangeManager, "ec - close[" ChipLogFormatExchange "], %s", ChipLogValueExchange(this), __func__);
272 : #endif
273 :
274 3071 : DoClose(false);
275 3071 : Release();
276 3071 : }
277 : /**
278 : * Abort the Exchange context immediately and release all
279 : * references to it.
280 : *
281 : */
282 197 : void ExchangeContext::Abort()
283 : {
284 197 : VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() > 0);
285 :
286 : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
287 : ChipLogDetail(ExchangeManager, "ec - abort[" ChipLogFormatExchange "], %s", ChipLogValueExchange(this), __func__);
288 : #endif
289 :
290 197 : DoClose(true);
291 197 : Release();
292 197 : }
293 :
294 3268 : void ExchangeContextDeletor::Release(ExchangeContext * ec)
295 : {
296 3268 : ec->mExchangeMgr->ReleaseContext(ec);
297 3268 : }
298 :
299 3268 : ExchangeContext::ExchangeContext(ExchangeManager * em, uint16_t ExchangeId, const SessionHandle & session, bool Initiator,
300 3268 : ExchangeDelegate * delegate, bool isEphemeralExchange) :
301 6536 : mDispatch(GetMessageDispatch(isEphemeralExchange, delegate)),
302 3268 : mSession(*this)
303 : {
304 3268 : VerifyOrDie(mExchangeMgr == nullptr);
305 :
306 3268 : mExchangeMgr = em;
307 3268 : mExchangeId = ExchangeId;
308 3268 : mSession.Grab(session);
309 3268 : mFlags.Set(Flags::kFlagInitiator, Initiator);
310 3268 : mFlags.Set(Flags::kFlagEphemeralExchange, isEphemeralExchange);
311 3268 : mDelegate = delegate;
312 :
313 : //
314 : // If we're an initiator and we just created this exchange, we obviously did so to send a message. Let's go ahead and
315 : // set the flag on this to correctly mark it as so.
316 : //
317 : // This only applies to non-ephemeral exchanges. Ephemeral exchanges do not have an intention of sending out a message
318 : // since they're created expressly for the purposes of sending out a standalone ACK when the message could not be handled
319 : // through normal means.
320 : //
321 3268 : if (Initiator && !isEphemeralExchange)
322 : {
323 1642 : WillSendMessage();
324 : }
325 :
326 3268 : SetAckPending(false);
327 :
328 : // Try to use MRP by default, if it is allowed.
329 3268 : SetAutoRequestAck(session->AllowsMRP());
330 :
331 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
332 : app::ICDNotifier::GetInstance().NotifyActiveRequestNotification(app::ICDListener::KeepActiveFlag::kExchangeContextOpen);
333 : #endif
334 :
335 : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
336 : ChipLogDetail(ExchangeManager, "ec++ id: " ChipLogFormatExchange, ChipLogValueExchange(this));
337 : #endif
338 3268 : SYSTEM_STATS_INCREMENT(chip::System::Stats::kExchangeMgr_NumContexts);
339 3268 : }
340 :
341 3268 : ExchangeContext::~ExchangeContext()
342 : {
343 3268 : VerifyOrDie(mExchangeMgr != nullptr && GetReferenceCount() == 0);
344 :
345 : //
346 : // Ensure that DoClose has been called by the time we get here. If not, we have a leak somewhere.
347 : //
348 3268 : VerifyOrDie(mFlags.Has(Flags::kFlagClosed));
349 :
350 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
351 : app::ICDNotifier::GetInstance().NotifyActiveRequestWithdrawal(app::ICDListener::KeepActiveFlag::kExchangeContextOpen);
352 : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
353 :
354 : // Ideally, in this scenario, the retransmit table should
355 : // be clear of any outstanding messages for this context and
356 : // the boolean parameter passed to DoClose() should not matter.
357 :
358 3268 : DoClose(false);
359 3268 : mExchangeMgr = nullptr;
360 :
361 : #if defined(CHIP_EXCHANGE_CONTEXT_DETAIL_LOGGING)
362 : ChipLogDetail(ExchangeManager, "ec-- id: " ChipLogFormatExchange, ChipLogValueExchange(this));
363 : #endif
364 3268 : SYSTEM_STATS_DECREMENT(chip::System::Stats::kExchangeMgr_NumContexts);
365 3268 : }
366 :
367 34611 : bool ExchangeContext::MatchExchange(const SessionHandle & session, const PacketHeader & packetHeader,
368 : const PayloadHeader & payloadHeader)
369 : {
370 : // A given message is part of a particular exchange if...
371 : return
372 :
373 : // The exchange identifier of the message matches the exchange identifier of the context.
374 34611 : (mExchangeId == payloadHeader.GetExchangeID())
375 :
376 : // AND The Session associated with the incoming message matches the Session associated with the exchange.
377 11855 : && (mSession.Contains(session))
378 :
379 : // TODO: This check should be already implied by the equality of session check,
380 : // It should be removed after we have implemented the temporary node id for PASE and CASE sessions
381 7813 : && (IsEncryptionRequired() == packetHeader.IsEncrypted())
382 :
383 : // AND The message was sent by an initiator and the exchange context is a responder (IsInitiator==false)
384 : // OR The message was sent by a responder and the exchange context is an initiator (IsInitiator==true) (for the broadcast
385 : // case, the initiator is ill defined)
386 :
387 46466 : && (payloadHeader.IsInitiator() != IsInitiator());
388 : }
389 :
390 51 : void ExchangeContext::OnSessionReleased()
391 : {
392 51 : if (ShouldIgnoreSessionRelease())
393 : {
394 7 : return;
395 : }
396 :
397 49 : if (mFlags.Has(Flags::kFlagClosed))
398 : {
399 : // Exchange is already being closed. It may occur when closing an exchange after sending
400 : // RemoveFabric response which triggers removal of all sessions for the given fabric.
401 5 : mExchangeMgr->GetReliableMessageMgr()->ClearRetransTable(this);
402 5 : return;
403 : }
404 :
405 : // Hold a ref to ourselves so we can make calls into our delegate that might
406 : // decrease our refcount without worrying about use-after-free.
407 44 : ExchangeHandle ref(*this);
408 :
409 : //
410 : // If a send is not expected (either because we're waiting for a response OR
411 : // we're in the middle of processing a OnMessageReceived call), we can go ahead
412 : // and notify our delegate and abort the exchange since we still own the ref.
413 : //
414 44 : if (!IsSendExpected())
415 : {
416 34 : if (IsResponseExpected())
417 : {
418 : // If we're waiting on a response, we now know it's never going to show up
419 : // and we should notify our delegate accordingly.
420 31 : CancelResponseTimer();
421 : // We want to Abort, not just Close, so that RMP bits are cleared, so
422 : // don't let NotifyResponseTimeout close us.
423 31 : NotifyResponseTimeout(/* aCloseIfNeeded = */ false);
424 : }
425 :
426 34 : Abort();
427 : }
428 : else
429 : {
430 10 : DoClose(true /* clearRetransTable */);
431 : }
432 44 : }
433 :
434 6337 : CHIP_ERROR ExchangeContext::StartResponseTimer()
435 : {
436 6337 : System::Layer * lSystemLayer = mExchangeMgr->GetSessionManager()->SystemLayer();
437 6337 : if (lSystemLayer == nullptr)
438 : {
439 : // this is an assertion error, which shall never happen
440 0 : return CHIP_ERROR_INTERNAL;
441 : }
442 :
443 6337 : return lSystemLayer->StartTimer(mResponseTimeout, HandleResponseTimeout, this);
444 : }
445 :
446 6383 : void ExchangeContext::CancelResponseTimer()
447 : {
448 6383 : System::Layer * lSystemLayer = mExchangeMgr->GetSessionManager()->SystemLayer();
449 6383 : if (lSystemLayer == nullptr)
450 : {
451 : // this is an assertion error, which shall never happen
452 0 : return;
453 : }
454 :
455 6383 : lSystemLayer->CancelTimer(HandleResponseTimeout, this);
456 : }
457 :
458 7 : void ExchangeContext::HandleResponseTimeout(System::Layer * aSystemLayer, void * aAppState)
459 : {
460 7 : ExchangeContext * ec = reinterpret_cast<ExchangeContext *>(aAppState);
461 :
462 7 : if (ec == nullptr)
463 0 : return;
464 :
465 7 : ec->NotifyResponseTimeout(/* aCloseIfNeeded = */ true);
466 : }
467 :
468 38 : void ExchangeContext::NotifyResponseTimeout(bool aCloseIfNeeded)
469 : {
470 : // Grab the value of WaitingForResponseOrAck() before we mess with our state.
471 38 : bool gotMRPAck = !WaitingForResponseOrAck();
472 :
473 38 : SetResponseExpected(false);
474 :
475 : // Hold a ref to ourselves so we can make calls into our delegate that might
476 : // decrease our refcount (e.g. by expiring out session) without worrying
477 : // about use-after-free.
478 38 : ExchangeHandle ref(*this);
479 :
480 : // mSession might be null if this timeout is due to the session being
481 : // evicted.
482 38 : if (mSession)
483 : {
484 : // If we timed out _after_ getting an ack for the message, that means
485 : // the session is probably fine (since our message and the ack got
486 : // through), so don't mark the session defunct if we got an MRP ack.
487 7 : if (!gotMRPAck)
488 : {
489 5 : if (mSession->IsSecureSession() && mSession->AsSecureSession()->IsCASESession())
490 : {
491 1 : mSession->AsSecureSession()->MarkAsDefunct();
492 : }
493 5 : mSession->DispatchSessionEvent(&SessionDelegate::OnSessionHang);
494 : }
495 : }
496 :
497 38 : ExchangeDelegate * delegate = GetDelegate();
498 :
499 : // Call the user's timeout handler.
500 38 : if (delegate != nullptr)
501 : {
502 38 : delegate->OnResponseTimeout(this);
503 : }
504 :
505 38 : if (aCloseIfNeeded)
506 : {
507 7 : MessageHandled();
508 : }
509 38 : }
510 :
511 9417 : CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const PayloadHeader & payloadHeader, MessageFlags msgFlags,
512 : PacketBufferHandle && msgBuf)
513 : {
514 : // We hold a reference to the ExchangeContext here to
515 : // guard against Close() calls(decrementing the reference
516 : // count) by the protocol before the CHIP Exchange
517 : // layer has completed its work on the ExchangeContext.
518 9417 : ExchangeHandle ref(*this);
519 :
520 9417 : bool isStandaloneAck = payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StandaloneAck);
521 9417 : bool isDuplicate = msgFlags.Has(MessageFlagValues::kDuplicateMessage);
522 :
523 9417 : auto deferred = MakeDefer([&]() {
524 : // Duplicates and standalone acks are not application-level messages, so they should generally not lead to any state
525 : // changes. The one exception to that is that if we have a null mDelegate then our lifetime is not application-defined,
526 : // since we don't interact with the application at that point. That can happen when we are already closed (in which case
527 : // MessageHandled is a no-op) or if we were just created to send a standalone ack for this incoming message, in which case
528 : // we should treat it as an app-level message for purposes of our state.
529 9417 : if ((isStandaloneAck || isDuplicate) && mDelegate != nullptr)
530 : {
531 28 : return;
532 : }
533 :
534 9389 : MessageHandled();
535 9417 : });
536 :
537 9417 : if (mSession->AllowsMRP())
538 : {
539 9372 : if (mDispatch.IsReliableTransmissionAllowed())
540 : {
541 17158 : if (!msgFlags.Has(MessageFlagValues::kDuplicateMessage) && payloadHeader.IsAckMsg() &&
542 7786 : payloadHeader.GetAckMessageCounter().HasValue())
543 : {
544 7786 : HandleRcvdAck(payloadHeader.GetAckMessageCounter().Value());
545 : }
546 :
547 9372 : if (payloadHeader.NeedsAck())
548 : {
549 : // An acknowledgment needs to be sent back to the peer for this message on this exchange,
550 7857 : HandleNeedsAck(messageCounter, msgFlags);
551 : }
552 : }
553 :
554 9372 : if (IsAckPending() && !mDelegate)
555 : {
556 : // The incoming message wants an ack, but we have no delegate, so
557 : // there's not going to be a response to piggyback on. Just flush the
558 : // ack out right now.
559 92 : ReturnErrorOnFailure(FlushAcks());
560 : }
561 :
562 : // The SecureChannel::StandaloneAck message type is only used for MRP; do not pass such messages to the application layer.
563 9372 : if (isStandaloneAck)
564 : {
565 1479 : return CHIP_NO_ERROR;
566 : }
567 : } // AllowsMRP
568 :
569 : // Since the message is duplicate, let's not forward it up the stack
570 7938 : if (isDuplicate)
571 : {
572 5 : return CHIP_NO_ERROR;
573 : }
574 :
575 7933 : if (mSession->AllowsMRP())
576 : {
577 7888 : if (IsEphemeralExchange())
578 : {
579 : // The EphemeralExchange has done its job, since StandaloneAck is sent in previous FlushAcks() call.
580 9 : return CHIP_NO_ERROR;
581 : }
582 :
583 7879 : if (IsWaitingForAck())
584 : {
585 : // The only way we can get here is a spec violation on the other side:
586 : // we sent a message that needs an ack, and the other side responded
587 : // with a message that does not contain an ack for the message we sent.
588 : // Just drop this message; if we delivered it to our delegate it might
589 : // try to send another message-needing-an-ack in response, which would
590 : // violate our internal invariants.
591 0 : ChipLogError(ExchangeManager, "Dropping message without piggyback ack when we are waiting for an ack.");
592 0 : return CHIP_ERROR_INCORRECT_STATE;
593 : }
594 : } // AllowsMRP
595 :
596 : #if CHIP_CONFIG_ENABLE_ICD_SERVER
597 : // message received
598 : app::ICDNotifier::GetInstance().NotifyNetworkActivityNotification();
599 : #endif // CHIP_CONFIG_ENABLE_ICD_SERVER
600 :
601 : // Set kFlagReceivedAtLeastOneMessage to true since we have received at least one new application level message
602 7924 : SetHasReceivedAtLeastOneMessage(true);
603 :
604 7924 : if (IsResponseExpected())
605 : {
606 : // Since we got the response, cancel the response timer.
607 6251 : CancelResponseTimer();
608 :
609 : // If the context was expecting a response to a previously sent message, this message
610 : // is implicitly that response.
611 6251 : SetResponseExpected(false);
612 : }
613 :
614 : // Don't send messages on to our delegate if our dispatch does not allow
615 : // those messages.
616 7924 : if (mDelegate != nullptr && mDispatch.MessagePermitted(payloadHeader.GetProtocolID(), payloadHeader.GetMessageType()))
617 : {
618 7842 : return mDelegate->OnMessageReceived(this, payloadHeader, std::move(msgBuf));
619 : }
620 :
621 82 : DefaultOnMessageReceived(this, payloadHeader.GetProtocolID(), payloadHeader.GetMessageType(), messageCounter,
622 82 : std::move(msgBuf));
623 82 : return CHIP_NO_ERROR;
624 9417 : }
625 :
626 17401 : void ExchangeContext::MessageHandled()
627 : {
628 17401 : if (mFlags.Has(Flags::kFlagClosed) || IsResponseExpected() || IsSendExpected())
629 : {
630 14361 : return;
631 : }
632 :
633 3040 : Close();
634 : }
635 :
636 3268 : ExchangeMessageDispatch & ExchangeContext::GetMessageDispatch(bool isEphemeralExchange, ExchangeDelegate * delegate)
637 : {
638 3268 : if (isEphemeralExchange)
639 13 : return EphemeralExchangeDispatch::Instance();
640 :
641 3255 : if (delegate != nullptr)
642 3245 : return delegate->GetMessageDispatch();
643 :
644 10 : return ApplicationExchangeDispatch::Instance();
645 : }
646 :
647 2 : void ExchangeContext::AbortAllOtherCommunicationOnFabric()
648 : {
649 2 : if (!mSession || !mSession->IsSecureSession())
650 : {
651 0 : ChipLogError(ExchangeManager, "AbortAllOtherCommunicationOnFabric called when we don't have a PASE/CASE session");
652 0 : return;
653 : }
654 :
655 : // Save our session so it does not actually go away.
656 2 : Optional<SessionHandle> session = mSession.Get();
657 :
658 2 : SetIgnoreSessionRelease(true);
659 :
660 2 : GetExchangeMgr()->GetSessionManager()->ExpireAllSessionsForFabric(mSession->GetFabricIndex());
661 :
662 2 : mSession.GrabExpiredSession(session.Value());
663 :
664 2 : SetIgnoreSessionRelease(false);
665 2 : }
666 :
667 2 : void ExchangeContext::ExchangeSessionHolder::GrabExpiredSession(const SessionHandle & session)
668 : {
669 2 : VerifyOrDie(session->AsSecureSession()->IsPendingEviction());
670 2 : GrabUnchecked(session);
671 2 : }
672 :
673 : } // namespace Messaging
674 : } // namespace chip
|