Skip to content

Commit 58875c3

Browse files
Fix handling of a response that comes after MRP resends end. (#29640)
* Fix handling of a response that comes after MRP resends end. After #29173 we can get into the following situation: 1. A message is sent. 2. Before we get an ack or response, all MRP retries happen, MRP gives up, but the exchange response timer has not been hit yet. 3. We get an actual response. 4. Because our exchange is marked as having an un-acked message, but the incoming message is not treated as an ack (because the MRP state that would do that has been torn down), we do not clear our "have un-acked message" state and end up discarding the incoming message. The fix is as follows: * Rename things to make it clear that what we really have is "waiting for an ack" state, which in fact _does_ get cleared when we run out of MRP retries, not an "un-acked message" state. * Have a separate state bit for tracking that we ran out of MRP retries on a message we sent. * Address review comment.
1 parent 3dfffe7 commit 58875c3

7 files changed

+363
-29
lines changed

src/messaging/ExchangeContext.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ bool ExchangeContext::IsResponseExpected() const
7979
void ExchangeContext::SetResponseExpected(bool inResponseExpected)
8080
{
8181
mFlags.Set(Flags::kFlagResponseExpected, inResponseExpected);
82+
SetWaitingForResponseOrAck(inResponseExpected);
8283
}
8384

8485
void ExchangeContext::UseSuggestedResponseTimeout(Timeout applicationProcessingTimeout)
@@ -489,6 +490,9 @@ void ExchangeContext::NotifyResponseTimeout(bool aCloseIfNeeded)
489490
}
490491
#endif // CONFIG_DEVICE_LAYER && CHIP_CONFIG_ENABLE_ICD_SERVER
491492

493+
// Grab the value of WaitingForResponseOrAck() before we mess with our state.
494+
bool gotMRPAck = !WaitingForResponseOrAck();
495+
492496
SetResponseExpected(false);
493497

494498
// Hold a ref to ourselves so we can make calls into our delegate that might
@@ -502,9 +506,8 @@ void ExchangeContext::NotifyResponseTimeout(bool aCloseIfNeeded)
502506
{
503507
// If we timed out _after_ getting an ack for the message, that means
504508
// the session is probably fine (since our message and the ack got
505-
// through), so don't mark the session defunct unless we have an
506-
// un-acked message here.
507-
if (IsMessageNotAcked())
509+
// through), so don't mark the session defunct if we got an MRP ack.
510+
if (!gotMRPAck)
508511
{
509512
if (mSession->IsSecureSession() && mSession->AsSecureSession()->IsCASESession())
510513
{
@@ -596,7 +599,7 @@ CHIP_ERROR ExchangeContext::HandleMessage(uint32_t messageCounter, const Payload
596599
return CHIP_NO_ERROR;
597600
}
598601

599-
if (IsMessageNotAcked())
602+
if (IsWaitingForAck())
600603
{
601604
// The only way we can get here is a spec violation on the other side:
602605
// we sent a message that needs an ack, and the other side responded

src/messaging/ReliableMessageContext.cpp

+8-4
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,14 @@ ReliableMessageMgr * ReliableMessageContext::GetReliableMessageMgr()
5555
return static_cast<ExchangeContext *>(this)->GetExchangeMgr()->GetReliableMessageMgr();
5656
}
5757

58-
void ReliableMessageContext::SetMessageNotAcked(bool messageNotAcked)
58+
void ReliableMessageContext::SetWaitingForAck(bool waitingForAck)
5959
{
60-
mFlags.Set(Flags::kFlagMessageNotAcked, messageNotAcked);
60+
mFlags.Set(Flags::kFlagWaitingForAck, waitingForAck);
6161

6262
#if CONFIG_DEVICE_LAYER && CHIP_CONFIG_ENABLE_ICD_SERVER
6363
DeviceLayer::ChipDeviceEvent event;
6464
event.Type = DeviceLayer::DeviceEventType::kICDMsgAckSyncEvent;
65-
event.AckSync.awaitingAck = messageNotAcked;
65+
event.AckSync.awaitingAck = waitingForAck;
6666
CHIP_ERROR status = DeviceLayer::PlatformMgr().PostEvent(&event);
6767
if (status != CHIP_NO_ERROR)
6868
{
@@ -103,7 +103,11 @@ CHIP_ERROR ReliableMessageContext::FlushAcks()
103103
void ReliableMessageContext::HandleRcvdAck(uint32_t ackMessageCounter)
104104
{
105105
// Msg is an Ack; Check Retrans Table and remove message context
106-
if (!GetReliableMessageMgr()->CheckAndRemRetransTable(this, ackMessageCounter))
106+
if (GetReliableMessageMgr()->CheckAndRemRetransTable(this, ackMessageCounter))
107+
{
108+
SetWaitingForResponseOrAck(false);
109+
}
110+
else
107111
{
108112
// This can happen quite easily due to a packet with a piggyback ack
109113
// being lost and retransmitted.

src/messaging/ReliableMessageContext.h

+30-8
Original file line numberDiff line numberDiff line change
@@ -114,11 +114,11 @@ class ReliableMessageContext
114114
*/
115115
bool IsAckPending() const;
116116

117-
/// Determine whether there is message hasn't been acknowledged.
118-
bool IsMessageNotAcked() const;
117+
/// Determine whether the reliable message context is waiting for an ack.
118+
bool IsWaitingForAck() const;
119119

120-
/// Set whether there is a message hasn't been acknowledged.
121-
void SetMessageNotAcked(bool messageNotAcked);
120+
/// Set whether the reliable message context is waiting for an ack.
121+
void SetWaitingForAck(bool waitingForAck);
122122

123123
/// Set if this exchange is requesting Sleepy End Device active mode
124124
void SetRequestingActiveMode(bool activeMode);
@@ -136,6 +136,9 @@ class ReliableMessageContext
136136
ReliableMessageMgr * GetReliableMessageMgr();
137137

138138
protected:
139+
bool WaitingForResponseOrAck() const;
140+
void SetWaitingForResponseOrAck(bool waitingForResponseOrAck);
141+
139142
enum class Flags : uint16_t
140143
{
141144
/// When set, signifies that this context is the initiator of the exchange.
@@ -147,8 +150,10 @@ class ReliableMessageContext
147150
/// When set, automatically request an acknowledgment whenever a message is sent via UDP.
148151
kFlagAutoRequestAck = (1u << 2),
149152

150-
/// When set, signifies there is a message which hasn't been acknowledged.
151-
kFlagMessageNotAcked = (1u << 3),
153+
/// When set, signifies the reliable message context is waiting for an
154+
/// ack: a message that needs an ack has been sent, no ack has been
155+
/// received, and we have not yet run out of MRP retries.
156+
kFlagWaitingForAck = (1u << 3),
152157

153158
/// When set, signifies that there is an acknowledgment pending to be sent back.
154159
kFlagAckPending = (1u << 4),
@@ -172,6 +177,13 @@ class ReliableMessageContext
172177

173178
/// When set, ignore session being released, because we are releasing it ourselves.
174179
kFlagIgnoreSessionRelease = (1u << 10),
180+
181+
/// When set:
182+
///
183+
/// (1) We sent a message that expected a response (hence
184+
/// IsResponseExpected() is true).
185+
/// (2) We have received neither a response nor an ack for that message.
186+
kFlagWaitingForResponseOrAck = (1u << 11),
175187
};
176188

177189
BitFlags<Flags> mFlags; // Internal state flags
@@ -216,9 +228,9 @@ inline bool ReliableMessageContext::IsAckPending() const
216228
return mFlags.Has(Flags::kFlagAckPending);
217229
}
218230

219-
inline bool ReliableMessageContext::IsMessageNotAcked() const
231+
inline bool ReliableMessageContext::IsWaitingForAck() const
220232
{
221-
return mFlags.Has(Flags::kFlagMessageNotAcked);
233+
return mFlags.Has(Flags::kFlagWaitingForAck);
222234
}
223235

224236
inline bool ReliableMessageContext::HasPiggybackAckPending() const
@@ -251,5 +263,15 @@ inline bool ReliableMessageContext::IsEphemeralExchange() const
251263
return mFlags.Has(Flags::kFlagEphemeralExchange);
252264
}
253265

266+
inline bool ReliableMessageContext::WaitingForResponseOrAck() const
267+
{
268+
return mFlags.Has(Flags::kFlagWaitingForResponseOrAck);
269+
}
270+
271+
inline void ReliableMessageContext::SetWaitingForResponseOrAck(bool waitingForResponseOrAck)
272+
{
273+
mFlags.Set(Flags::kFlagWaitingForResponseOrAck, waitingForResponseOrAck);
274+
}
275+
254276
} // namespace Messaging
255277
} // namespace chip

src/messaging/ReliableMessageMgr.cpp

+3-9
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,12 @@ namespace Messaging {
4949
ReliableMessageMgr::RetransTableEntry::RetransTableEntry(ReliableMessageContext * rc) :
5050
ec(*rc->GetExchangeContext()), nextRetransTime(0), sendCount(0)
5151
{
52-
ec->SetMessageNotAcked(true);
52+
ec->SetWaitingForAck(true);
5353
}
5454

5555
ReliableMessageMgr::RetransTableEntry::~RetransTableEntry()
5656
{
57-
ec->SetMessageNotAcked(false);
57+
ec->SetWaitingForAck(false);
5858
}
5959

6060
ReliableMessageMgr::ReliableMessageMgr(ObjectPool<ExchangeContext, CHIP_CONFIG_MAX_EXCHANGE_CONTEXTS> & contextPool) :
@@ -158,12 +158,6 @@ void ReliableMessageMgr::ExecuteActions()
158158
// Do not StartTimer, we will schedule the timer at the end of the timer handler.
159159
mRetransTable.ReleaseObject(entry);
160160

161-
// Dropping our entry marked the exchange as not having an un-acked
162-
// message... but of course it _does_ have an un-acked message and
163-
// we have just given up on waiting for the ack.
164-
165-
ec->GetReliableMessageContext()->SetMessageNotAcked(true);
166-
167161
return Loop::Continue;
168162
}
169163

@@ -204,7 +198,7 @@ void ReliableMessageMgr::Timeout(System::Layer * aSystemLayer, void * aAppState)
204198

205199
CHIP_ERROR ReliableMessageMgr::AddToRetransTable(ReliableMessageContext * rc, RetransTableEntry ** rEntry)
206200
{
207-
VerifyOrDie(!rc->IsMessageNotAcked());
201+
VerifyOrDie(!rc->IsWaitingForAck());
208202

209203
*rEntry = mRetransTable.CreateObject(rc);
210204
if (*rEntry == nullptr)

src/messaging/tests/MessagingContext.cpp

+14
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,26 @@ CHIP_ERROR MessagingContext::CreateSessionBobToAlice()
163163
mBobFabricIndex, mAliceAddress, CryptoContext::SessionRole::kInitiator);
164164
}
165165

166+
CHIP_ERROR MessagingContext::CreateCASESessionBobToAlice()
167+
{
168+
return mSessionManager.InjectCaseSessionWithTestKey(mSessionBobToAlice, kBobKeyId, kAliceKeyId, GetBobFabric()->GetNodeId(),
169+
GetAliceFabric()->GetNodeId(), mBobFabricIndex, mAliceAddress,
170+
CryptoContext::SessionRole::kInitiator);
171+
}
172+
166173
CHIP_ERROR MessagingContext::CreateSessionAliceToBob()
167174
{
168175
return mSessionManager.InjectPaseSessionWithTestKey(mSessionAliceToBob, kAliceKeyId, GetBobFabric()->GetNodeId(), kBobKeyId,
169176
mAliceFabricIndex, mBobAddress, CryptoContext::SessionRole::kResponder);
170177
}
171178

179+
CHIP_ERROR MessagingContext::CreateCASESessionAliceToBob()
180+
{
181+
return mSessionManager.InjectCaseSessionWithTestKey(mSessionAliceToBob, kAliceKeyId, kBobKeyId, GetAliceFabric()->GetNodeId(),
182+
GetBobFabric()->GetNodeId(), mAliceFabricIndex, mBobAddress,
183+
CryptoContext::SessionRole::kResponder);
184+
}
185+
172186
CHIP_ERROR MessagingContext::CreatePASESessionCharlieToDavid()
173187
{
174188
return mSessionManager.InjectPaseSessionWithTestKey(mSessionCharlieToDavid, kCharlieKeyId, 0xdeadbeef, kDavidKeyId,

src/messaging/tests/MessagingContext.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,11 @@ class MessagingContext : public PlatformMemoryUser
139139
const FabricInfo * GetAliceFabric() { return mFabricTable.FindFabricWithIndex(mAliceFabricIndex); }
140140
const FabricInfo * GetBobFabric() { return mFabricTable.FindFabricWithIndex(mBobFabricIndex); }
141141

142-
CHIP_ERROR CreateSessionBobToAlice();
143-
CHIP_ERROR CreateSessionAliceToBob();
144-
CHIP_ERROR CreateSessionBobToFriends();
142+
CHIP_ERROR CreateSessionBobToAlice(); // Creates PASE session
143+
CHIP_ERROR CreateCASESessionBobToAlice();
144+
CHIP_ERROR CreateSessionAliceToBob(); // Creates PASE session
145+
CHIP_ERROR CreateCASESessionAliceToBob();
146+
CHIP_ERROR CreateSessionBobToFriends(); // Creates PASE session
145147
CHIP_ERROR CreatePASESessionCharlieToDavid();
146148
CHIP_ERROR CreatePASESessionDavidToCharlie();
147149

0 commit comments

Comments
 (0)