Line data Source code
1 : /*
2 : *
3 : * Copyright (c) 2025 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 a WiFiPAF endpoint abstraction for CHIP over WiFiPAF (CHIPoPAF)
21 : * Public Action Frame Transport Protocol (PAFTP).
22 : *
23 : */
24 :
25 : #include "WiFiPAFEndPoint.h"
26 :
27 : #include <cstdint>
28 : #include <cstring>
29 : #include <utility>
30 :
31 : #include <lib/support/BitFlags.h>
32 : #include <lib/support/BufferReader.h>
33 : #include <lib/support/CodeUtils.h>
34 : #include <lib/support/logging/CHIPLogging.h>
35 : #include <system/SystemClock.h>
36 : #include <system/SystemLayer.h>
37 : #include <system/SystemPacketBuffer.h>
38 :
39 : #include "WiFiPAFConfig.h"
40 : #include "WiFiPAFError.h"
41 : #include "WiFiPAFLayer.h"
42 : #include "WiFiPAFTP.h"
43 :
44 : // Define below to enable extremely verbose, WiFiPAF end point-specific debug logging.
45 : #undef CHIP_WIFIPAF_END_POINT_DEBUG_LOGGING_ENABLED
46 : #define CHIP_WIFIPAF_END_POINT_DEBUG_LOGGING_LEVEL 0
47 :
48 : #ifdef CHIP_WIFIPAF_END_POINT_DEBUG_LOGGING_ENABLED
49 : #define ChipLogDebugWiFiPAFEndPoint_L0(MOD, MSG, ...) ChipLogDetail(MOD, MSG, ##__VA_ARGS__)
50 : #if (CHIP_WIFIPAF_END_POINT_DEBUG_LOGGING_LEVEL == 0)
51 : #define ChipLogDebugWiFiPAFEndPoint(MOD, MSG, ...)
52 : #else
53 : #define ChipLogDebugWiFiPAFEndPoint(MOD, MSG, ...) ChipLogDetail(MOD, MSG, ##__VA_ARGS__)
54 : #endif // CHIP_WIFIPAF_END_POINT_DEBUG_LOGGING_LEVEL
55 : #define ChipLogDebugBufferWiFiPAFEndPoint(MOD, BUF) \
56 : ChipLogByteSpan(MOD, ByteSpan((BUF)->Start(), ((BUF)->DataLength() < 8 ? (BUF)->DataLength() : 8u)))
57 : #else
58 : #define ChipLogDebugWiFiPAFEndPoint(MOD, MSG, ...)
59 : #define ChipLogDebugBufferWiFiPAFEndPoint(MOD, BUF)
60 : #endif
61 :
62 : /**
63 : * @def WIFIPAF_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD
64 : *
65 : * @brief
66 : * If an end point's receive window drops equal to or below this value, it will send an immediate acknowledgement
67 : * packet to re-open its window instead of waiting for the send-ack timer to expire.
68 : *
69 : */
70 : #define WIFIPAF_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD 1
71 :
72 : #define WIFIPAF_ACK_SEND_TIMEOUT_MS 2500
73 : #define WIFIPAF_WAIT_RES_TIMEOUT_MS 1000
74 : // Drop the connection if network resources remain unavailable for the period.
75 : #define WIFIPAF_MAX_RESOURCE_BLOCK_COUNT (PAFTP_CONN_IDLE_TIMEOUT_MS / WIFIPAF_WAIT_RES_TIMEOUT_MS)
76 :
77 : /**
78 : * @def WIFIPAF_WINDOW_NO_ACK_SEND_THRESHOLD
79 : *
80 : * @brief
81 : * Data fragments may only be sent without piggybacked acks if receiver's window size is above this threshold.
82 : *
83 : */
84 : #define WIFIPAF_WINDOW_NO_ACK_SEND_THRESHOLD 1
85 :
86 : namespace chip {
87 : namespace WiFiPAF {
88 :
89 1 : CHIP_ERROR WiFiPAFEndPoint::StartConnect()
90 : {
91 1 : CHIP_ERROR err = CHIP_NO_ERROR;
92 : PAFTransportCapabilitiesRequestMessage req;
93 1 : PacketBufferHandle buf;
94 1 : constexpr uint8_t numVersions =
95 : CHIP_PAF_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION - CHIP_PAF_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION + 1;
96 : static_assert(numVersions <= NUM_PAFTP_SUPPORTED_PROTOCOL_VERSIONS, "Incompatibly protocol versions");
97 :
98 : // Ensure we're in the correct state.
99 1 : VerifyOrExit(mState == kState_Ready, err = CHIP_ERROR_INCORRECT_STATE);
100 1 : mState = kState_Connecting;
101 :
102 : // Build PAF transport protocol capabilities request.
103 1 : buf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
104 1 : VerifyOrExit(!buf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
105 :
106 : // Zero-initialize PAF transport capabilities request.
107 1 : memset(&req, 0, sizeof(req));
108 1 : req.mMtu = CHIP_PAF_DEFAULT_MTU;
109 1 : req.mWindowSize = PAF_MAX_RECEIVE_WINDOW_SIZE;
110 :
111 : // Populate request with highest supported protocol versions
112 2 : for (uint8_t i = 0; i < numVersions; i++)
113 : {
114 1 : req.SetSupportedProtocolVersion(i, static_cast<uint8_t>(CHIP_PAF_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION - i));
115 : }
116 :
117 1 : err = req.Encode(buf);
118 1 : SuccessOrExit(err);
119 :
120 : // Start connect timer. Canceled when end point freed or connection established.
121 1 : err = StartConnectTimer();
122 1 : SuccessOrExit(err);
123 :
124 : // Send PAF transport capabilities request to peripheral.
125 : // Add reference to message fragment. CHIP retains partial ownership of message fragment's packet buffer,
126 : // since this is the same buffer as that of the whole message, just with a fragmenter-modified payload offset
127 : // and data length, by a Retain() on the handle when calling this function.
128 1 : err = SendWrite(buf.Retain());
129 1 : SuccessOrExit(err);
130 : // Free request buffer on write confirmation. Stash a reference to it in mSendQueue, which we don't use anyway
131 : // until the connection has been set up.
132 1 : QueueTx(std::move(buf), kType_Data);
133 :
134 1 : exit:
135 : // If we failed to initiate the connection, close the end point.
136 1 : if (err != CHIP_NO_ERROR)
137 : {
138 0 : StopConnectTimer();
139 0 : DoClose(kWiFiPAFCloseFlag_AbortTransmission, err);
140 : }
141 :
142 2 : return err;
143 1 : }
144 :
145 2 : CHIP_ERROR WiFiPAFEndPoint::HandleConnectComplete()
146 : {
147 2 : CHIP_ERROR err = CHIP_NO_ERROR;
148 :
149 2 : mState = kState_Connected;
150 : // Cancel the connect timer.
151 2 : StopConnectTimer();
152 :
153 : // We've successfully completed the PAF transport protocol handshake, so let the application know we're open for business.
154 2 : if (mWiFiPafLayer != nullptr)
155 : {
156 : // Indicate connect complete to next-higher layer.
157 2 : mWiFiPafLayer->OnEndPointConnectComplete(this, CHIP_NO_ERROR);
158 : }
159 : else
160 : {
161 : // If no connect complete callback has been set up, close the end point.
162 0 : err = WIFIPAF_ERROR_NO_CONNECT_COMPLETE_CALLBACK;
163 : }
164 2 : return err;
165 : }
166 :
167 14 : bool WiFiPAFEndPoint::IsConnected(uint8_t state) const
168 : {
169 14 : return (state == kState_Connected || state == kState_Closing);
170 : }
171 :
172 2 : void WiFiPAFEndPoint::DoClose(uint8_t flags, CHIP_ERROR err)
173 : {
174 2 : uint8_t oldState = mState;
175 :
176 : // If end point is not closed or closing, OR end point was closing gracefully, but tx abort has been specified...
177 2 : if ((mState != kState_Closed && mState != kState_Closing) ||
178 0 : (mState == kState_Closing && (flags & kWiFiPAFCloseFlag_AbortTransmission)))
179 : {
180 : // Cancel Connect and ReceiveConnect timers if they are running.
181 : // Check role first to avoid needless iteration over timer pool.
182 2 : if (mRole == kWiFiPafRole_Subscriber)
183 : {
184 1 : StopConnectTimer();
185 : }
186 :
187 : // Free the packets in re-order queue if ones exist
188 14 : for (uint8_t qidx = 0; qidx < PAFTP_REORDER_QUEUE_SIZE; qidx++)
189 : {
190 12 : if (ReorderQueue[qidx] != nullptr)
191 : {
192 0 : ReorderQueue[qidx] = nullptr;
193 0 : ItemsInReorderQueue--;
194 : }
195 : }
196 :
197 : // If transmit buffer is empty or a transmission abort was specified...
198 2 : if (mPafTP.TxState() == WiFiPAFTP::kState_Idle || (flags & kWiFiPAFCloseFlag_AbortTransmission))
199 : {
200 2 : FinalizeClose(oldState, flags, err);
201 : }
202 : else
203 : {
204 : // Wait for send queue and fragmenter's tx buffer to become empty, to ensure all pending messages have been
205 : // sent. Only free end point and tell platform it can throw away the underlying connection once all
206 : // pending messages have been sent and acknowledged by the remote CHIPoPAF stack, or once the remote stack
207 : // closes the CHIPoPAF connection.
208 : //
209 : // In so doing, WiFiPAFEndPoint attempts to emulate the level of reliability afforded by TCPEndPoint and TCP
210 : // sockets in general with a typical default SO_LINGER option. That said, there is no hard guarantee that
211 : // pending messages will be sent once (Do)Close() is called, so developers should use application-level
212 : // messages to confirm the receipt of all data sent prior to a Close() call.
213 0 : mState = kState_Closing;
214 :
215 0 : if ((flags & kWiFiPAFCloseFlag_SuppressCallback) == 0)
216 : {
217 0 : DoCloseCallback(oldState, flags, err);
218 : }
219 : }
220 : }
221 2 : }
222 :
223 2 : void WiFiPAFEndPoint::FinalizeClose(uint8_t oldState, uint8_t flags, CHIP_ERROR err)
224 : {
225 2 : mState = kState_Closed;
226 :
227 : // Ensure transmit queue is empty and set to NULL.
228 2 : mSendQueue = nullptr;
229 : // Clear the session information
230 2 : ChipLogProgress(WiFiPAF, "Shutdown PAF session (%u, %u)", mSessionInfo.id, mSessionInfo.role);
231 2 : mWiFiPafLayer->mWiFiPAFTransport->WiFiPAFCloseSession(mSessionInfo);
232 2 : memset(&mSessionInfo, 0, sizeof(mSessionInfo));
233 : // Fire application's close callback if we haven't already, and it's not suppressed.
234 2 : if (oldState != kState_Closing && (flags & kWiFiPAFCloseFlag_SuppressCallback) == 0)
235 : {
236 2 : DoCloseCallback(oldState, flags, err);
237 : }
238 :
239 : // If underlying WiFiPAF connection has closed, connection object is invalid, so just free the end point and return.
240 2 : if (err == WIFIPAF_ERROR_REMOTE_DEVICE_DISCONNECTED || err == WIFIPAF_ERROR_APP_CLOSED_CONNECTION)
241 : {
242 2 : Free();
243 : }
244 : else // Otherwise, try to signal close to remote device before end point releases WiFiPAF connection and frees itself.
245 : {
246 0 : if (mRole == kWiFiPafRole_Subscriber)
247 : {
248 : // Cancel send and receive-ack timers, if running.
249 0 : StopAckReceivedTimer();
250 0 : StopSendAckTimer();
251 0 : StopWaitResourceTimer();
252 0 : mConnStateFlags.Set(ConnectionStateFlag::kOperationInFlight);
253 : }
254 : else
255 : {
256 0 : Free();
257 : }
258 : }
259 2 : ClearAll();
260 2 : }
261 :
262 2 : void WiFiPAFEndPoint::DoCloseCallback(uint8_t state, uint8_t flags, CHIP_ERROR err)
263 : {
264 : // Callback fires once per end point lifetime.
265 2 : mOnPafSubscribeComplete = nullptr;
266 2 : mOnPafSubscribeError = nullptr;
267 2 : OnConnectionClosed = nullptr;
268 2 : }
269 :
270 2 : void WiFiPAFEndPoint::Free()
271 : {
272 : // Clear fragmentation and reassembly engine's Tx and Rx buffers. Counters will be reset by next engine init.
273 2 : FreePAFtpEngine();
274 :
275 : // Clear pending ack buffer, if any.
276 2 : mAckToSend = nullptr;
277 :
278 : // Cancel all timers.
279 2 : StopConnectTimer();
280 2 : StopAckReceivedTimer();
281 2 : StopSendAckTimer();
282 2 : StopWaitResourceTimer();
283 :
284 : // Clear callbacks.
285 2 : mOnPafSubscribeComplete = nullptr;
286 2 : mOnPafSubscribeError = nullptr;
287 2 : OnMessageReceived = nullptr;
288 2 : OnConnectionClosed = nullptr;
289 2 : }
290 :
291 2 : void WiFiPAFEndPoint::FreePAFtpEngine()
292 : {
293 : // Free transmit disassembly buffer
294 2 : mPafTP.ClearTxPacket();
295 :
296 : // Free receive reassembly buffer
297 2 : mPafTP.ClearRxPacket();
298 2 : }
299 :
300 2 : CHIP_ERROR WiFiPAFEndPoint::Init(WiFiPAFLayer * WiFiPafLayer, WiFiPAFSession & SessionInfo)
301 : {
302 : // Fail if already initialized.
303 2 : VerifyOrReturnError(mWiFiPafLayer == nullptr, CHIP_ERROR_INCORRECT_STATE);
304 :
305 : // Validate args.
306 2 : VerifyOrReturnError(WiFiPafLayer != nullptr, CHIP_ERROR_INVALID_ARGUMENT);
307 :
308 : // If end point plays subscriber role, expect ack as last step of PAFTP handshake.
309 : // If being publisher, subscriber's handshake indication 'ack's write sent by publisher to kick off the PAFTP handshake.
310 2 : bool expectInitialAck = (SessionInfo.role == kWiFiPafRole_Publisher);
311 :
312 2 : CHIP_ERROR err = mPafTP.Init(this, expectInitialAck);
313 2 : if (err != CHIP_NO_ERROR)
314 : {
315 0 : ChipLogError(WiFiPAF, "WiFiPAFTP init failed");
316 0 : return err;
317 : }
318 :
319 2 : mWiFiPafLayer = WiFiPafLayer;
320 :
321 : // WiFiPAF EndPoint data members:
322 2 : memcpy(&mSessionInfo, &SessionInfo, sizeof(mSessionInfo));
323 2 : mRole = SessionInfo.role;
324 2 : mTimerStateFlags.ClearAll();
325 2 : mLocalReceiveWindowSize = 0;
326 2 : mRemoteReceiveWindowSize = 0;
327 2 : mReceiveWindowMaxSize = 0;
328 2 : mSendQueue = nullptr;
329 2 : mAckToSend = nullptr;
330 :
331 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "initialized local rx window, size = %u", mLocalReceiveWindowSize);
332 :
333 : // End point is ready.
334 2 : mState = kState_Ready;
335 :
336 2 : return CHIP_NO_ERROR;
337 : }
338 :
339 9 : CHIP_ERROR WiFiPAFEndPoint::SendCharacteristic(PacketBufferHandle && buf)
340 : {
341 9 : CHIP_ERROR err = CHIP_NO_ERROR;
342 :
343 9 : SuccessOrExit(err = SendWrite(std::move(buf)));
344 : // Write succeeded, so shrink remote receive window counter by 1.
345 9 : mRemoteReceiveWindowSize = static_cast<SequenceNumber_t>(mRemoteReceiveWindowSize - 1);
346 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "decremented remote rx window, new size = %u", mRemoteReceiveWindowSize);
347 9 : exit:
348 9 : return err;
349 : }
350 :
351 : /*
352 : * Routine to queue the Tx packet with a packet type
353 : * kType_Data(0) - data packet
354 : * kType_Control(1) - control packet
355 : */
356 9 : void WiFiPAFEndPoint::QueueTx(PacketBufferHandle && data, PacketType_t type)
357 : {
358 9 : if (mSendQueue.IsNull())
359 : {
360 7 : mSendQueue = std::move(data);
361 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "%s: Set data as new mSendQueue %p, type %d", __FUNCTION__, mSendQueue->Start(), type);
362 : }
363 : else
364 : {
365 2 : mSendQueue->AddToEnd(std::move(data));
366 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "%s: Append data to mSendQueue %p, type %d", __FUNCTION__, mSendQueue->Start(), type);
367 : }
368 9 : }
369 :
370 7 : CHIP_ERROR WiFiPAFEndPoint::Send(PacketBufferHandle && data)
371 : {
372 7 : CHIP_ERROR err = CHIP_NO_ERROR;
373 :
374 7 : VerifyOrExit(!data.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
375 7 : VerifyOrExit(IsConnected(mState), err = CHIP_ERROR_INCORRECT_STATE);
376 :
377 : // Ensure outgoing message fits in a single contiguous packet buffer, as currently required by the
378 : // message fragmentation and reassembly engine.
379 7 : if (data->HasChainedBuffer())
380 : {
381 1 : data->CompactHead();
382 :
383 1 : if (data->HasChainedBuffer())
384 : {
385 0 : err = CHIP_ERROR_OUTBOUND_MESSAGE_TOO_BIG;
386 0 : ExitNow();
387 : }
388 : }
389 :
390 : // Add new message to send queue.
391 7 : QueueTx(std::move(data), kType_Data);
392 :
393 : // Send first fragment of new message, if we can.
394 7 : err = DriveSending();
395 7 : SuccessOrExit(err);
396 7 : exit:
397 7 : if (err != CHIP_NO_ERROR)
398 : {
399 0 : DoClose(kWiFiPAFCloseFlag_AbortTransmission, err);
400 : }
401 :
402 7 : return err;
403 : }
404 :
405 8 : bool WiFiPAFEndPoint::PrepareNextFragment(PacketBufferHandle && data, bool & sentAck)
406 : {
407 : // If we have a pending fragment acknowledgement to send, piggyback it on the fragment we're about to transmit.
408 8 : if (mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
409 : {
410 : // Reset local receive window counter.
411 2 : mLocalReceiveWindowSize = mReceiveWindowMaxSize;
412 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "reset local rx window on piggyback ack tx, size = %u", mLocalReceiveWindowSize);
413 :
414 : // Tell caller AND fragmenter we have an ack to piggyback.
415 2 : sentAck = true;
416 : }
417 : else
418 : {
419 : // No ack to piggyback.
420 6 : sentAck = false;
421 : }
422 :
423 8 : return mPafTP.HandleCharacteristicSend(std::move(data), sentAck);
424 : }
425 :
426 7 : CHIP_ERROR WiFiPAFEndPoint::SendNextMessage()
427 : {
428 : // Get the first queued packet to send
429 7 : PacketBufferHandle data = mSendQueue.PopHead();
430 :
431 : // Hand whole message payload to the fragmenter.
432 : bool sentAck;
433 7 : VerifyOrReturnError(PrepareNextFragment(std::move(data), sentAck), WIFIPAF_ERROR_CHIPPAF_PROTOCOL_ABORT);
434 :
435 7 : ReturnErrorOnFailure(SendCharacteristic(mPafTP.BorrowTxPacket()));
436 :
437 7 : if (sentAck)
438 : {
439 : // If sent piggybacked ack, stop send-ack timer.
440 2 : StopSendAckTimer();
441 : }
442 :
443 : // Start ack received timer, if it's not already running.
444 7 : return StartAckReceivedTimer();
445 7 : }
446 :
447 1 : CHIP_ERROR WiFiPAFEndPoint::ContinueMessageSend()
448 : {
449 : bool sentAck;
450 :
451 1 : if (!PrepareNextFragment(nullptr, sentAck))
452 : {
453 : // Log PAFTP error
454 0 : ChipLogError(WiFiPAF, "paftp fragmenter error on send!");
455 0 : mPafTP.LogState();
456 :
457 0 : return WIFIPAF_ERROR_CHIPPAF_PROTOCOL_ABORT;
458 : }
459 :
460 1 : ReturnErrorOnFailure(SendCharacteristic(mPafTP.BorrowTxPacket()));
461 :
462 1 : if (sentAck)
463 : {
464 : // If sent piggybacked ack, stop send-ack timer.
465 0 : StopSendAckTimer();
466 : }
467 :
468 : // Start ack received timer, if it's not already running.
469 1 : return StartAckReceivedTimer();
470 : }
471 :
472 2 : CHIP_ERROR WiFiPAFEndPoint::HandleHandshakeConfirmationReceived()
473 : {
474 : // Free capabilities request/response payload.
475 2 : mSendQueue.FreeHead();
476 :
477 2 : return CHIP_NO_ERROR;
478 : }
479 :
480 7 : CHIP_ERROR WiFiPAFEndPoint::HandleFragmentConfirmationReceived(bool result)
481 : {
482 7 : CHIP_ERROR err = CHIP_NO_ERROR;
483 : // Ensure we're in correct state to receive confirmation of non-handshake GATT send.
484 7 : VerifyOrExit(IsConnected(mState), err = CHIP_ERROR_INCORRECT_STATE);
485 :
486 7 : if (mConnStateFlags.Has(ConnectionStateFlag::kStandAloneAckInFlight))
487 : {
488 : // If confirmation was received for stand-alone ack, free its tx buffer.
489 0 : mAckToSend = nullptr;
490 0 : mConnStateFlags.Clear(ConnectionStateFlag::kStandAloneAckInFlight);
491 : }
492 :
493 7 : if (result != true)
494 : {
495 : // Something wrong in writing packets
496 0 : ChipLogError(WiFiPAF, "Failed to send PAF packet");
497 0 : err = CHIP_ERROR_SENDING_BLOCKED;
498 0 : StopAckReceivedTimer();
499 0 : SuccessOrExit(err);
500 : }
501 :
502 : // If local receive window size has shrunk to or below immediate ack threshold, AND a message fragment is not
503 : // pending on which to piggyback an ack, send immediate stand-alone ack.
504 : //
505 : // This check covers the case where the local receive window has shrunk between transmission and confirmation of
506 : // the stand-alone ack, and also the case where a window size < the immediate ack threshold was detected in
507 : // Receive(), but the stand-alone ack was deferred due to a pending outbound message fragment.
508 7 : if (mLocalReceiveWindowSize <= WIFIPAF_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD && mSendQueue.IsNull() &&
509 0 : mPafTP.TxState() != WiFiPAFTP::kState_InProgress)
510 : {
511 0 : err = DriveStandAloneAck(); // Encode stand-alone ack and drive sending.
512 0 : SuccessOrExit(err);
513 : }
514 : else
515 : {
516 7 : err = DriveSending();
517 7 : SuccessOrExit(err);
518 : }
519 :
520 7 : exit:
521 7 : if (err != CHIP_NO_ERROR)
522 : {
523 0 : DoClose(kWiFiPAFCloseFlag_AbortTransmission, err);
524 : }
525 :
526 7 : return err;
527 : }
528 :
529 9 : CHIP_ERROR WiFiPAFEndPoint::HandleSendConfirmationReceived(bool result)
530 : {
531 : // Mark outstanding operation as finished.
532 9 : mConnStateFlags.Clear(ConnectionStateFlag::kOperationInFlight);
533 :
534 : // If confirmation was for outbound portion of PAFTP connect handshake...
535 9 : if (!mConnStateFlags.Has(ConnectionStateFlag::kCapabilitiesConfReceived))
536 : {
537 2 : mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesConfReceived);
538 2 : return HandleHandshakeConfirmationReceived();
539 : }
540 :
541 7 : return HandleFragmentConfirmationReceived(result);
542 : }
543 :
544 1 : CHIP_ERROR WiFiPAFEndPoint::DriveStandAloneAck()
545 : {
546 : // Stop send-ack timer if running.
547 1 : StopSendAckTimer();
548 :
549 : // If stand-alone ack not already pending, allocate new payload buffer here.
550 1 : if (mAckToSend.IsNull())
551 : {
552 1 : mAckToSend = System::PacketBufferHandle::New(kTransferProtocolStandaloneAckHeaderSize);
553 1 : VerifyOrReturnError(!mAckToSend.IsNull(), CHIP_ERROR_NO_MEMORY);
554 : }
555 :
556 : // Attempt to send stand-alone ack.
557 1 : return DriveSending();
558 : }
559 :
560 1 : CHIP_ERROR WiFiPAFEndPoint::DoSendStandAloneAck()
561 : {
562 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "sending stand-alone ack");
563 :
564 : // Encode and transmit stand-alone ack.
565 1 : mPafTP.EncodeStandAloneAck(mAckToSend);
566 1 : ReturnErrorOnFailure(SendCharacteristic(mAckToSend.Retain()));
567 :
568 : // Reset local receive window counter.
569 1 : mLocalReceiveWindowSize = mReceiveWindowMaxSize;
570 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "reset local rx window on stand-alone ack tx, size = %u", mLocalReceiveWindowSize);
571 :
572 1 : mConnStateFlags.Set(ConnectionStateFlag::kStandAloneAckInFlight);
573 :
574 : // Start ack received timer, if it's not already running.
575 1 : return StartAckReceivedTimer();
576 : }
577 :
578 19 : CHIP_ERROR WiFiPAFEndPoint::DriveSending()
579 : {
580 : // If receiver's window is almost closed and we don't have an ack to send, OR we do have an ack to send but
581 : // receiver's window is completely empty, OR another operation is in flight, awaiting confirmation...
582 39 : if ((mRemoteReceiveWindowSize <= WIFIPAF_WINDOW_NO_ACK_SEND_THRESHOLD &&
583 1 : !mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning) && mAckToSend.IsNull()) ||
584 20 : (mRemoteReceiveWindowSize == 0) || (mConnStateFlags.Has(ConnectionStateFlag::kOperationInFlight)))
585 : {
586 4 : if (mRemoteReceiveWindowSize <= WIFIPAF_WINDOW_NO_ACK_SEND_THRESHOLD &&
587 3 : !mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning) && mAckToSend.IsNull())
588 : {
589 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "NO SEND: receive window almost closed, and no ack to send");
590 : }
591 :
592 3 : if (mRemoteReceiveWindowSize == 0)
593 : {
594 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "NO SEND: remote receive window closed");
595 : }
596 :
597 3 : if (mConnStateFlags.Has(ConnectionStateFlag::kOperationInFlight))
598 : {
599 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "NO SEND: Operation in flight");
600 : }
601 : // Can't send anything.
602 3 : return CHIP_NO_ERROR;
603 : }
604 :
605 16 : if (!mWiFiPafLayer->mWiFiPAFTransport->WiFiPAFResourceAvailable() && (!mAckToSend.IsNull() || !mSendQueue.IsNull()))
606 : {
607 : // Resource is currently unavailable, send packets later
608 1 : StartWaitResourceTimer();
609 1 : return CHIP_NO_ERROR;
610 : }
611 15 : mResourceWaitCount = 0;
612 :
613 : // Otherwise, let's see what we can send.
614 15 : if ((!mAckToSend.IsNull()) && !mConnStateFlags.Has(ConnectionStateFlag::kStandAloneAckInFlight))
615 : {
616 : // If immediate, stand-alone ack is pending, send it.
617 0 : ChipLogProgress(WiFiPAF, "Send the pending stand-alone ack");
618 0 : ReturnErrorOnFailure(DoSendStandAloneAck());
619 : }
620 15 : else if (mPafTP.TxState() == WiFiPAFTP::kState_Idle) // Else send next message fragment, if any.
621 : {
622 : // Fragmenter's idle, let's see what's in the send queue...
623 9 : if (!mSendQueue.IsNull())
624 : {
625 : // Transmit first fragment of next whole message in send queue.
626 6 : ReturnErrorOnFailure(SendNextMessage());
627 : }
628 : else
629 : {
630 : // Nothing to send!
631 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "=> No pending packets, nothing to send!");
632 : }
633 : }
634 6 : else if (mPafTP.TxState() == WiFiPAFTP::kState_InProgress)
635 : {
636 : // Send next fragment of message currently held by fragmenter.
637 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "Send the next fragment");
638 1 : ReturnErrorOnFailure(ContinueMessageSend());
639 : }
640 5 : else if (mPafTP.TxState() == WiFiPAFTP::kState_Complete)
641 : {
642 : // Clear fragmenter's pointer to sent message buffer and reset its Tx state.
643 : // Buffer will be freed at scope exit.
644 5 : PacketBufferHandle sentBuf = mPafTP.TakeTxPacket();
645 :
646 5 : if (!mSendQueue.IsNull())
647 : {
648 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "Send the next pkt");
649 : // Transmit first fragment of next whole message in send queue.
650 1 : ReturnErrorOnFailure(SendNextMessage());
651 : }
652 4 : else if (mState == kState_Closing && !mPafTP.ExpectingAck()) // and mSendQueue is NULL, per above...
653 : {
654 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "Closing and no expect ack!");
655 : // If end point closing, got last ack, and got out-of-order confirmation for last send, finalize close.
656 0 : FinalizeClose(mState, kWiFiPAFCloseFlag_SuppressCallback, CHIP_NO_ERROR);
657 : }
658 : else
659 : {
660 : // Nothing to send!
661 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "No more packets to send");
662 : }
663 5 : }
664 : else
665 : {
666 0 : ChipLogError(WiFiPAF, "Unknown TxState: %u", mPafTP.TxState());
667 : }
668 15 : return CHIP_NO_ERROR;
669 : }
670 :
671 1 : CHIP_ERROR WiFiPAFEndPoint::HandleCapabilitiesRequestReceived(PacketBufferHandle && data)
672 : {
673 : PAFTransportCapabilitiesRequestMessage req;
674 : PAFTransportCapabilitiesResponseMessage resp;
675 : uint16_t mtu;
676 :
677 1 : VerifyOrReturnError(!data.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
678 :
679 1 : mState = kState_Connecting;
680 :
681 : // Decode PAFTP capabilities request.
682 1 : ReturnErrorOnFailure(PAFTransportCapabilitiesRequestMessage::Decode(data, req));
683 :
684 1 : PacketBufferHandle responseBuf = System::PacketBufferHandle::New(kCapabilitiesResponseLength);
685 1 : VerifyOrReturnError(!responseBuf.IsNull(), CHIP_ERROR_NO_MEMORY);
686 :
687 1 : if (req.mMtu > 0) // If MTU was observed and provided by central...
688 : {
689 1 : mtu = req.mMtu; // Accept central's observation of the MTU.
690 : }
691 : else
692 : {
693 0 : mtu = CHIP_PAF_DEFAULT_MTU;
694 : }
695 :
696 : // Select fragment size for connection based on MTU.
697 1 : resp.mFragmentSize = std::min(static_cast<uint16_t>(mtu), WiFiPAFTP::sMaxFragmentSize);
698 :
699 : // Select local and remote max receive window size based on local resources available for both incoming writes
700 1 : mRemoteReceiveWindowSize = mLocalReceiveWindowSize = mReceiveWindowMaxSize =
701 1 : std::min(req.mWindowSize, static_cast<uint8_t>(PAF_MAX_RECEIVE_WINDOW_SIZE));
702 1 : resp.mWindowSize = mReceiveWindowMaxSize;
703 1 : ChipLogProgress(WiFiPAF, "local and remote recv window sizes = %u", resp.mWindowSize);
704 :
705 : // Select PAF transport protocol version from those supported by central, or none if no supported version found.
706 1 : resp.mSelectedProtocolVersion = WiFiPAFLayer::GetHighestSupportedProtocolVersion(req);
707 1 : ChipLogProgress(WiFiPAF, "selected PAFTP version %d", resp.mSelectedProtocolVersion);
708 :
709 1 : if (resp.mSelectedProtocolVersion == kWiFiPAFTransportProtocolVersion_None)
710 : {
711 : // If WiFiPAF transport protocol versions incompatible, prepare to close connection after capabilities response
712 : // has been sent.
713 0 : ChipLogError(WiFiPAF, "incompatible PAFTP versions; peripheral expected between %d and %d",
714 : CHIP_PAF_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION, CHIP_PAF_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION);
715 0 : mState = kState_Aborting;
716 : }
717 : else
718 : {
719 : // Set Rx and Tx fragment sizes to the same value
720 1 : mPafTP.SetRxFragmentSize(resp.mFragmentSize);
721 1 : mPafTP.SetTxFragmentSize(resp.mFragmentSize);
722 : }
723 :
724 1 : ChipLogProgress(WiFiPAF, "using PAFTP fragment sizes rx %d / tx %d.", mPafTP.GetRxFragmentSize(), mPafTP.GetTxFragmentSize());
725 1 : ReturnErrorOnFailure(resp.Encode(responseBuf));
726 :
727 : CHIP_ERROR err;
728 1 : err = SendWrite(responseBuf.Retain());
729 1 : SuccessOrExit(err);
730 :
731 : // Stash capabilities response payload
732 1 : QueueTx(std::move(responseBuf), kType_Data);
733 :
734 : // Response has been sent
735 1 : return HandleConnectComplete();
736 0 : exit:
737 0 : return err;
738 1 : }
739 :
740 1 : CHIP_ERROR WiFiPAFEndPoint::HandleCapabilitiesResponseReceived(PacketBufferHandle && data)
741 : {
742 : PAFTransportCapabilitiesResponseMessage resp;
743 :
744 1 : VerifyOrReturnError(!data.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
745 :
746 : // Decode PAFTP capabilities response.
747 1 : ReturnErrorOnFailure(PAFTransportCapabilitiesResponseMessage::Decode(data, resp));
748 :
749 1 : VerifyOrReturnError(resp.mFragmentSize > 0, WIFIPAF_ERROR_INVALID_FRAGMENT_SIZE);
750 :
751 1 : ChipLogProgress(WiFiPAF, "Publisher chose PAFTP version %d; subscriber expected between %d and %d",
752 : resp.mSelectedProtocolVersion, CHIP_PAF_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION,
753 : CHIP_PAF_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION);
754 :
755 1 : if ((resp.mSelectedProtocolVersion < CHIP_PAF_TRANSPORT_PROTOCOL_MIN_SUPPORTED_VERSION) ||
756 1 : (resp.mSelectedProtocolVersion > CHIP_PAF_TRANSPORT_PROTOCOL_MAX_SUPPORTED_VERSION))
757 : {
758 0 : return WIFIPAF_ERROR_INCOMPATIBLE_PROTOCOL_VERSIONS;
759 : }
760 :
761 : // Set fragment size as minimum of (reported ATT MTU, BTP characteristic size)
762 1 : resp.mFragmentSize = std::min(resp.mFragmentSize, WiFiPAFTP::sMaxFragmentSize);
763 :
764 1 : mPafTP.SetRxFragmentSize(resp.mFragmentSize);
765 1 : mPafTP.SetTxFragmentSize(resp.mFragmentSize);
766 :
767 1 : ChipLogProgress(WiFiPAF, "using PAFTP fragment sizes rx %d / tx %d.", mPafTP.GetRxFragmentSize(), mPafTP.GetTxFragmentSize());
768 :
769 : // Select local and remote max receive window size based on local resources available for both incoming indications
770 1 : mRemoteReceiveWindowSize = mLocalReceiveWindowSize = mReceiveWindowMaxSize = resp.mWindowSize;
771 :
772 1 : ChipLogProgress(WiFiPAF, "local and remote recv window size = %u", resp.mWindowSize);
773 :
774 : // Shrink local receive window counter by 1, since connect handshake indication requires acknowledgement.
775 1 : mLocalReceiveWindowSize = static_cast<SequenceNumber_t>(mLocalReceiveWindowSize - 1);
776 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "decremented local rx window, new size = %u", mLocalReceiveWindowSize);
777 :
778 : // Send ack for connection handshake indication when timer expires. Sequence numbers always start at 0,
779 : // and the reassembler's "last received seq num" is initialized to 0 and updated when new fragments are
780 : // received from the peripheral, so we don't need to explicitly mark the ack num to send here.
781 1 : ReturnErrorOnFailure(StartSendAckTimer());
782 :
783 : // We've sent a capabilities request write and received a compatible response, so the connect
784 : // operation has completed successfully.
785 1 : return HandleConnectComplete();
786 : }
787 :
788 : // Returns number of open slots in remote receive window given the input values.
789 4 : SequenceNumber_t WiFiPAFEndPoint::AdjustRemoteReceiveWindow(SequenceNumber_t lastReceivedAck, SequenceNumber_t maxRemoteWindowSize,
790 : SequenceNumber_t newestUnackedSentSeqNum)
791 : {
792 : // Assumption: SequenceNumber_t is uint8_t.
793 : // Assumption: Maximum possible sequence number value is UINT8_MAX.
794 : // Assumption: Sequence numbers incremented past maximum value wrap to 0.
795 : // Assumption: newest unacked sent sequence number never exceeds current (and by extension, new and un-wrapped)
796 : // window boundary, so it never wraps relative to last received ack, if new window boundary would not
797 : // also wrap.
798 :
799 : // Define new window boundary (inclusive) as uint16_t, so its value can temporarily exceed UINT8_MAX.
800 4 : uint16_t newRemoteWindowBoundary = static_cast<uint16_t>(lastReceivedAck + maxRemoteWindowSize);
801 :
802 4 : if (newRemoteWindowBoundary > UINT8_MAX && newestUnackedSentSeqNum < lastReceivedAck)
803 : {
804 : // New window boundary WOULD wrap, and latest unacked seq num already HAS wrapped, so add offset to difference.
805 0 : return static_cast<uint8_t>(newRemoteWindowBoundary - (newestUnackedSentSeqNum + UINT8_MAX));
806 : }
807 :
808 : // Neither values would or have wrapped, OR new boundary WOULD wrap but latest unacked seq num does not, so no
809 : // offset required.
810 4 : return static_cast<uint8_t>(newRemoteWindowBoundary - newestUnackedSentSeqNum);
811 : }
812 :
813 7 : CHIP_ERROR WiFiPAFEndPoint::GetPktSn(Encoding::LittleEndian::Reader & reader, uint8_t * pHead, SequenceNumber_t & seqNum)
814 : {
815 : CHIP_ERROR err;
816 7 : BitFlags<WiFiPAFTP::HeaderFlags> rx_flags;
817 7 : size_t SnOffset = 0;
818 : SequenceNumber_t * pSn;
819 7 : err = reader.Read8(rx_flags.RawStorage()).StatusCode();
820 7 : if (rx_flags.Has(WiFiPAFTP::HeaderFlags::kHankshake))
821 : {
822 : // Handkshake message => No ack/sn
823 2 : return CHIP_ERROR_INTERNAL;
824 : }
825 : // Always has header flag
826 5 : SnOffset += kTransferProtocolHeaderFlagsSize;
827 5 : if (rx_flags.Has(WiFiPAFTP::HeaderFlags::kManagementOpcode)) // Has Mgmt_Op
828 : {
829 0 : SnOffset += kTransferProtocolMgmtOpSize;
830 : }
831 5 : if (rx_flags.Has(WiFiPAFTP::HeaderFlags::kFragmentAck)) // Has ack
832 : {
833 5 : SnOffset += kTransferProtocolAckSize;
834 : }
835 5 : pSn = pHead + SnOffset;
836 5 : seqNum = *pSn;
837 :
838 5 : return CHIP_NO_ERROR;
839 : }
840 :
841 17 : CHIP_ERROR WiFiPAFEndPoint::DebugPktAckSn(const PktDirect_t PktDirect, Encoding::LittleEndian::Reader & reader, uint8_t * pHead)
842 : {
843 : #ifdef CHIP_WIFIPAF_END_POINT_DEBUG_LOGGING_ENABLED
844 : BitFlags<WiFiPAFTP::HeaderFlags> rx_flags;
845 : CHIP_ERROR err;
846 : uint8_t * pAct = nullptr;
847 : char AckBuff[4];
848 : uint8_t * pSn;
849 : size_t SnOffset = 0;
850 :
851 : err = reader.Read8(rx_flags.RawStorage()).StatusCode();
852 : SuccessOrExit(err);
853 : if (rx_flags.Has(WiFiPAFTP::HeaderFlags::kHankshake))
854 : {
855 : // Handkshake message => No ack/sn
856 : return CHIP_NO_ERROR;
857 : }
858 : // Always has header flag
859 : SnOffset += kTransferProtocolHeaderFlagsSize;
860 : if (rx_flags.Has(WiFiPAFTP::HeaderFlags::kManagementOpcode)) // Has Mgmt_Op
861 : {
862 : SnOffset += kTransferProtocolMgmtOpSize;
863 : }
864 : if (rx_flags.Has(WiFiPAFTP::HeaderFlags::kFragmentAck)) // Has ack
865 : {
866 : pAct = pHead + kTransferProtocolHeaderFlagsSize;
867 : SnOffset += kTransferProtocolAckSize;
868 : }
869 : pSn = pHead + SnOffset;
870 : if (pAct == nullptr)
871 : {
872 : strcpy(AckBuff, " ");
873 : }
874 : else
875 : {
876 : snprintf(AckBuff, sizeof(AckBuff), "%02hhu", *pAct);
877 : }
878 : if (PktDirect == PktDirect_t::kTx)
879 : {
880 : ChipLogDebugWiFiPAFEndPoint_L0(WiFiPAF, "==>[tx] [Sn, Ack] = [ %02u, -- %s]", *pSn, AckBuff);
881 : }
882 : else if (PktDirect == PktDirect_t::kRx)
883 : {
884 : ChipLogDebugWiFiPAFEndPoint_L0(WiFiPAF, "<==[rx] [Ack, Sn] = [-- %s, %02u]", AckBuff, *pSn);
885 : }
886 : exit:
887 : return err;
888 : #else
889 17 : return CHIP_NO_ERROR;
890 : #endif
891 : }
892 :
893 7 : CHIP_ERROR WiFiPAFEndPoint::Receive(PacketBufferHandle && data)
894 : {
895 7 : SequenceNumber_t ExpRxNextSeqNum = mPafTP.GetRxNextSeqNum();
896 : SequenceNumber_t seqNum;
897 7 : Encoding::LittleEndian::Reader reader(data->Start(), data->DataLength());
898 7 : CHIP_ERROR err = CHIP_NO_ERROR;
899 :
900 7 : err = GetPktSn(reader, data->Start(), seqNum);
901 7 : if (err != CHIP_NO_ERROR)
902 : {
903 : // Failed to get SeqNum. => Pass down to PAFTP engine directly
904 2 : return RxPacketProcess(std::move(data));
905 : }
906 : /*
907 : If reorder-queue is not empty => Need to queue the packet whose SeqNum is the next one at
908 : offset 0 to fill the hole.
909 : */
910 5 : if ((ExpRxNextSeqNum == seqNum) && (ItemsInReorderQueue == 0))
911 2 : return RxPacketProcess(std::move(data));
912 :
913 3 : ChipLogError(WiFiPAF, "Reorder the packet: [%u, %u]", ExpRxNextSeqNum, seqNum);
914 : // Start reordering packets
915 3 : SequenceNumber_t offset = OffsetSeqNum(seqNum, ExpRxNextSeqNum);
916 3 : if (offset >= PAFTP_REORDER_QUEUE_SIZE)
917 : {
918 : // Offset is too big
919 : // => It may be the unexpected packet or duplicate packet => drop it
920 1 : ChipLogError(WiFiPAF, "Offset (%u) is too big => drop the packet", offset);
921 : ChipLogDebugBufferWiFiPAFEndPoint(WiFiPAF, data);
922 1 : return CHIP_NO_ERROR;
923 : }
924 :
925 : // Save the packet to the reorder-queue
926 2 : if (ReorderQueue[offset] == nullptr)
927 : {
928 2 : ReorderQueue[offset] = std::move(data).UnsafeRelease();
929 2 : ItemsInReorderQueue++;
930 : }
931 :
932 : // Consume the packets in the reorder queue if no hole exists
933 2 : if (ReorderQueue[0] == nullptr)
934 : {
935 : // The hole still exists => Can't continue
936 1 : ChipLogError(WiFiPAF, "The hole still exists. Packets in reorder-queue: %u", ItemsInReorderQueue);
937 1 : return CHIP_NO_ERROR;
938 : }
939 : uint8_t qidx;
940 3 : for (qidx = 0; qidx < PAFTP_REORDER_QUEUE_SIZE; qidx++)
941 : {
942 : // The head slots should have been filled. => Do rx processing
943 3 : if (ReorderQueue[qidx] == nullptr)
944 : {
945 : // Stop consuming packets until the hole or no packets
946 1 : break;
947 : }
948 : // Consume the saved packets
949 2 : ChipLogProgress(WiFiPAF, "Rx processing from the re-order queue [%u]", qidx);
950 2 : err = RxPacketProcess(System::PacketBufferHandle::Adopt(ReorderQueue[qidx]));
951 2 : ReorderQueue[qidx] = nullptr;
952 2 : ItemsInReorderQueue--;
953 : }
954 : // Has reached the 1st hole in the queue => move the rest items forward
955 : // Note: It's to continue => No need to reinit "i"
956 5 : for (uint8_t newId = 0; qidx < PAFTP_REORDER_QUEUE_SIZE; qidx++, newId++)
957 : {
958 4 : if (ReorderQueue[qidx] != nullptr)
959 : {
960 0 : ReorderQueue[newId] = ReorderQueue[qidx];
961 0 : ReorderQueue[qidx] = nullptr;
962 : }
963 : }
964 1 : return err;
965 : }
966 :
967 6 : CHIP_ERROR WiFiPAFEndPoint::RxPacketProcess(PacketBufferHandle && data)
968 : {
969 : ChipLogDebugBufferWiFiPAFEndPoint(WiFiPAF, data);
970 :
971 6 : CHIP_ERROR err = CHIP_NO_ERROR;
972 6 : SequenceNumber_t receivedAck = 0;
973 6 : uint8_t closeFlags = kWiFiPAFCloseFlag_AbortTransmission;
974 6 : bool didReceiveAck = false;
975 6 : BitFlags<WiFiPAFTP::HeaderFlags> rx_flags;
976 6 : Encoding::LittleEndian::Reader reader(data->Start(), data->DataLength());
977 6 : DebugPktAckSn(PktDirect_t::kRx, reader, data->Start());
978 :
979 : { // This is a special handling on the first CHIPoPAF data packet, the CapabilitiesRequest.
980 : // If we're receiving the first inbound packet of a PAF transport connection handshake...
981 6 : if (!mConnStateFlags.Has(ConnectionStateFlag::kCapabilitiesMsgReceived))
982 : {
983 2 : if (mRole == kWiFiPafRole_Subscriber) // If we're a central receiving a capabilities response indication...
984 : {
985 : // Ensure end point's in the right state before continuing.
986 1 : VerifyOrExit(mState == kState_Connecting, err = CHIP_ERROR_INCORRECT_STATE);
987 1 : mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesMsgReceived);
988 1 : err = HandleCapabilitiesResponseReceived(std::move(data));
989 1 : SuccessOrExit(err);
990 : }
991 : else // Or, a peripheral receiving a capabilities request write...
992 : {
993 : // Ensure end point's in the right state before continuing.
994 1 : VerifyOrExit(mState == kState_Ready, err = CHIP_ERROR_INCORRECT_STATE);
995 1 : mConnStateFlags.Set(ConnectionStateFlag::kCapabilitiesMsgReceived);
996 1 : err = HandleCapabilitiesRequestReceived(std::move(data));
997 1 : if (err != CHIP_NO_ERROR)
998 : {
999 : // If an error occurred decoding and handling the capabilities request, release the BLE connection.
1000 : // Central's connect attempt will time out if peripheral's application decides to keep the BLE
1001 : // connection open, or fail immediately if the application closes the connection.
1002 0 : closeFlags = closeFlags | kWiFiPAFCloseFlag_SuppressCallback;
1003 0 : ExitNow();
1004 : }
1005 : }
1006 : // If received data was handshake packet, don't feed it to message reassembler.
1007 2 : ExitNow();
1008 : }
1009 : } // End handling the CapabilitiesRequest
1010 :
1011 4 : err = reader.Read8(rx_flags.RawStorage()).StatusCode();
1012 4 : SuccessOrExit(err);
1013 4 : if (rx_flags.Has(WiFiPAFTP::HeaderFlags::kHankshake))
1014 : {
1015 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "Unexpected handshake packet => drop");
1016 0 : ExitNow();
1017 : }
1018 :
1019 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "PAFTP about to rx characteristic, state before:");
1020 4 : mPafTP.LogStateDebug();
1021 :
1022 : // Pass received packet into PAFTP protocol engine.
1023 4 : err = mPafTP.HandleCharacteristicReceived(std::move(data), receivedAck, didReceiveAck);
1024 :
1025 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "PAFTP rx'd characteristic, state after:");
1026 4 : mPafTP.LogStateDebug();
1027 4 : SuccessOrExit(err);
1028 :
1029 : // Protocol engine accepted the fragment, so shrink local receive window counter by 1.
1030 4 : mLocalReceiveWindowSize = static_cast<SequenceNumber_t>(mLocalReceiveWindowSize - 1);
1031 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "decremented local rx window, new size = %u", mLocalReceiveWindowSize);
1032 :
1033 : // Respond to received ack, if any.
1034 4 : if (didReceiveAck)
1035 : {
1036 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "got paftp ack = %u", receivedAck);
1037 :
1038 : // If ack was rx'd for newest unacked sent fragment, stop ack received timer.
1039 4 : if (!mPafTP.ExpectingAck())
1040 : {
1041 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "got ack for last outstanding fragment");
1042 1 : StopAckReceivedTimer();
1043 :
1044 1 : if (mState == kState_Closing && mSendQueue.IsNull() && mPafTP.TxState() == WiFiPAFTP::kState_Idle)
1045 : {
1046 : // If end point closing, got confirmation for last send, and waiting for last ack, finalize close.
1047 0 : FinalizeClose(mState, kWiFiPAFCloseFlag_SuppressCallback, CHIP_NO_ERROR);
1048 0 : ExitNow();
1049 : }
1050 : }
1051 : else // Else there are still sent fragments for which acks are expected, so restart ack received timer.
1052 : {
1053 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "still expecting ack(s), restarting timer...");
1054 3 : err = RestartAckReceivedTimer();
1055 3 : SuccessOrExit(err);
1056 : }
1057 :
1058 : ChipLogDebugWiFiPAFEndPoint(
1059 : WiFiPAF, "about to adjust remote rx window; got ack num = %u, newest unacked sent seq num = %u, \
1060 : old window size = %u, max window size = %u",
1061 : receivedAck, mPafTP.GetNewestUnackedSentSequenceNumber(), mRemoteReceiveWindowSize, mReceiveWindowMaxSize);
1062 :
1063 : // Open remote device's receive window according to sequence number it just acknowledged.
1064 4 : mRemoteReceiveWindowSize =
1065 4 : AdjustRemoteReceiveWindow(receivedAck, mReceiveWindowMaxSize, mPafTP.GetNewestUnackedSentSequenceNumber());
1066 :
1067 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "adjusted remote rx window, new size = %u", mRemoteReceiveWindowSize);
1068 :
1069 : // Restart message transmission if it was previously paused due to window exhaustion.
1070 4 : err = DriveSending();
1071 4 : SuccessOrExit(err);
1072 : }
1073 :
1074 : // The previous DriveSending() might have generated a piggyback acknowledgement if there was
1075 : // previously un-acked data. Otherwise, prepare to send acknowledgement for newly received fragment.
1076 : //
1077 : // If local receive window is below immediate ack threshold, AND there is no previous stand-alone ack in
1078 : // flight, AND there is no pending outbound message fragment on which the ack can and will be piggybacked,
1079 : // send immediate stand-alone ack to reopen window for sender.
1080 : //
1081 : // The "operation in flight" check below covers "pending outbound message fragment" by extension, as when
1082 : // a message has been passed to the end point via Send(), its next outbound fragment must either be in flight
1083 : // itself, or awaiting the completion of another in-flight operation.
1084 : //
1085 : // If any operation is in flight that is NOT a stand-alone ack, the window size will be checked against
1086 : // this threshold again when the operation is confirmed.
1087 4 : if (mPafTP.HasUnackedData())
1088 : {
1089 4 : if (mLocalReceiveWindowSize <= WIFIPAF_CONFIG_IMMEDIATE_ACK_WINDOW_THRESHOLD &&
1090 0 : !mConnStateFlags.Has(ConnectionStateFlag::kOperationInFlight))
1091 : {
1092 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "sending immediate ack");
1093 0 : err = DriveStandAloneAck();
1094 0 : SuccessOrExit(err);
1095 : }
1096 : else
1097 : {
1098 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "starting send-ack timer");
1099 : // Send ack when timer expires.
1100 4 : err = StartSendAckTimer();
1101 4 : SuccessOrExit(err);
1102 : }
1103 : }
1104 :
1105 : // If we've reassembled a whole message...
1106 4 : if (mPafTP.RxState() == WiFiPAFTP::kState_Complete)
1107 : {
1108 : // Take ownership of message buffer
1109 2 : System::PacketBufferHandle full_packet = mPafTP.TakeRxPacket();
1110 :
1111 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "reassembled whole msg, len = %u", static_cast<unsigned>(full_packet->DataLength()));
1112 :
1113 : // If we have a message received callback, and end point is not closing...
1114 2 : if (mWiFiPafLayer != nullptr && mState != kState_Closing)
1115 : {
1116 : // Pass received message up the stack.
1117 2 : err = mWiFiPafLayer->OnWiFiPAFMsgRxComplete(mSessionInfo, std::move(full_packet));
1118 : }
1119 2 : }
1120 :
1121 2 : exit:
1122 6 : if (err != CHIP_NO_ERROR)
1123 : {
1124 0 : DoClose(closeFlags, err);
1125 : }
1126 :
1127 6 : return err;
1128 : }
1129 :
1130 11 : CHIP_ERROR WiFiPAFEndPoint::SendWrite(PacketBufferHandle && buf)
1131 : {
1132 11 : mConnStateFlags.Set(ConnectionStateFlag::kOperationInFlight);
1133 :
1134 : ChipLogDebugBufferWiFiPAFEndPoint(WiFiPAF, buf);
1135 11 : Encoding::LittleEndian::Reader reader(buf->Start(), buf->DataLength());
1136 11 : DebugPktAckSn(PktDirect_t::kTx, reader, buf->Start());
1137 11 : mWiFiPafLayer->mWiFiPAFTransport->WiFiPAFMessageSend(mSessionInfo, std::move(buf));
1138 :
1139 11 : return CHIP_NO_ERROR;
1140 : }
1141 :
1142 1 : CHIP_ERROR WiFiPAFEndPoint::StartConnectTimer()
1143 : {
1144 1 : const CHIP_ERROR timerErr = mWiFiPafLayer->mSystemLayer->StartTimer(System::Clock::Milliseconds32(PAFTP_CONN_RSP_TIMEOUT_MS),
1145 : HandleConnectTimeout, this);
1146 1 : ReturnErrorOnFailure(timerErr);
1147 1 : mTimerStateFlags.Set(TimerStateFlag::kConnectTimerRunning);
1148 :
1149 1 : return CHIP_NO_ERROR;
1150 : }
1151 :
1152 12 : CHIP_ERROR WiFiPAFEndPoint::StartAckReceivedTimer()
1153 : {
1154 12 : if (!mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning))
1155 : {
1156 6 : const CHIP_ERROR timerErr = mWiFiPafLayer->mSystemLayer->StartTimer(System::Clock::Milliseconds32(PAFTP_ACK_TIMEOUT_MS),
1157 : HandleAckReceivedTimeout, this);
1158 6 : ReturnErrorOnFailure(timerErr);
1159 :
1160 6 : mTimerStateFlags.Set(TimerStateFlag::kAckReceivedTimerRunning);
1161 : }
1162 :
1163 12 : return CHIP_NO_ERROR;
1164 : }
1165 :
1166 3 : CHIP_ERROR WiFiPAFEndPoint::RestartAckReceivedTimer()
1167 : {
1168 3 : VerifyOrReturnError(mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning), CHIP_ERROR_INCORRECT_STATE);
1169 :
1170 3 : StopAckReceivedTimer();
1171 :
1172 3 : return StartAckReceivedTimer();
1173 : }
1174 :
1175 5 : CHIP_ERROR WiFiPAFEndPoint::StartSendAckTimer()
1176 : {
1177 5 : if (!mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
1178 : {
1179 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "starting new SendAckTimer");
1180 3 : const CHIP_ERROR timerErr = mWiFiPafLayer->mSystemLayer->StartTimer(
1181 3 : System::Clock::Milliseconds32(WIFIPAF_ACK_SEND_TIMEOUT_MS), HandleSendAckTimeout, this);
1182 3 : ReturnErrorOnFailure(timerErr);
1183 :
1184 3 : mTimerStateFlags.Set(TimerStateFlag::kSendAckTimerRunning);
1185 : }
1186 :
1187 5 : return CHIP_NO_ERROR;
1188 : }
1189 :
1190 1 : CHIP_ERROR WiFiPAFEndPoint::StartWaitResourceTimer()
1191 : {
1192 1 : mResourceWaitCount++;
1193 1 : if (mResourceWaitCount >= WIFIPAF_MAX_RESOURCE_BLOCK_COUNT)
1194 : {
1195 0 : ChipLogError(WiFiPAF, "Network resource has been unavailable for a long time");
1196 0 : mResourceWaitCount = 0;
1197 0 : DoClose(kWiFiPAFCloseFlag_AbortTransmission, CHIP_ERROR_NOT_CONNECTED);
1198 0 : return CHIP_NO_ERROR;
1199 : }
1200 1 : if (!mTimerStateFlags.Has(TimerStateFlag::kWaitResTimerRunning))
1201 : {
1202 : ChipLogDebugWiFiPAFEndPoint(WiFiPAF, "starting new WaitResTimer");
1203 1 : const CHIP_ERROR timerErr = mWiFiPafLayer->mSystemLayer->StartTimer(
1204 1 : System::Clock::Milliseconds32(WIFIPAF_WAIT_RES_TIMEOUT_MS), HandleWaitResourceTimeout, this);
1205 1 : ReturnErrorOnFailure(timerErr);
1206 1 : mTimerStateFlags.Set(TimerStateFlag::kWaitResTimerRunning);
1207 : }
1208 1 : return CHIP_NO_ERROR;
1209 : }
1210 :
1211 5 : void WiFiPAFEndPoint::StopConnectTimer()
1212 : {
1213 : // Cancel any existing connect timer.
1214 5 : mWiFiPafLayer->mSystemLayer->CancelTimer(HandleConnectTimeout, this);
1215 5 : mTimerStateFlags.Clear(TimerStateFlag::kConnectTimerRunning);
1216 5 : }
1217 :
1218 6 : void WiFiPAFEndPoint::StopAckReceivedTimer()
1219 : {
1220 : // Cancel any existing ack-received timer.
1221 6 : mWiFiPafLayer->mSystemLayer->CancelTimer(HandleAckReceivedTimeout, this);
1222 6 : mTimerStateFlags.Clear(TimerStateFlag::kAckReceivedTimerRunning);
1223 6 : }
1224 :
1225 5 : void WiFiPAFEndPoint::StopSendAckTimer()
1226 : {
1227 : // Cancel any existing send-ack timer.
1228 5 : mWiFiPafLayer->mSystemLayer->CancelTimer(HandleSendAckTimeout, this);
1229 5 : mTimerStateFlags.Clear(TimerStateFlag::kSendAckTimerRunning);
1230 5 : }
1231 :
1232 2 : void WiFiPAFEndPoint::StopWaitResourceTimer()
1233 : {
1234 : // Cancel any existing wait-resource timer.
1235 2 : mWiFiPafLayer->mSystemLayer->CancelTimer(HandleWaitResourceTimeout, this);
1236 2 : mTimerStateFlags.Clear(TimerStateFlag::kWaitResTimerRunning);
1237 2 : }
1238 :
1239 0 : void WiFiPAFEndPoint::HandleConnectTimeout(chip::System::Layer * systemLayer, void * appState)
1240 : {
1241 0 : WiFiPAFEndPoint * ep = static_cast<WiFiPAFEndPoint *>(appState);
1242 :
1243 : // Check for event-based timer race condition.
1244 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kConnectTimerRunning))
1245 : {
1246 0 : ChipLogError(WiFiPAF, "connect handshake timed out, closing ep %p", ep);
1247 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kConnectTimerRunning);
1248 0 : ep->DoClose(kWiFiPAFCloseFlag_AbortTransmission, WIFIPAF_ERROR_CONNECT_TIMED_OUT);
1249 : }
1250 0 : }
1251 :
1252 0 : void WiFiPAFEndPoint::HandleAckReceivedTimeout(chip::System::Layer * systemLayer, void * appState)
1253 : {
1254 0 : WiFiPAFEndPoint * ep = static_cast<WiFiPAFEndPoint *>(appState);
1255 :
1256 : // Check for event-based timer race condition.
1257 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kAckReceivedTimerRunning))
1258 : {
1259 0 : ChipLogError(WiFiPAF, "ack recv timeout, closing ep %p", ep);
1260 0 : ep->mPafTP.LogStateDebug();
1261 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kAckReceivedTimerRunning);
1262 0 : ep->DoClose(kWiFiPAFCloseFlag_AbortTransmission, WIFIPAF_ERROR_FRAGMENT_ACK_TIMED_OUT);
1263 : }
1264 0 : }
1265 :
1266 0 : void WiFiPAFEndPoint::HandleSendAckTimeout(chip::System::Layer * systemLayer, void * appState)
1267 : {
1268 0 : WiFiPAFEndPoint * ep = static_cast<WiFiPAFEndPoint *>(appState);
1269 :
1270 : // Check for event-based timer race condition.
1271 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kSendAckTimerRunning))
1272 : {
1273 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kSendAckTimerRunning);
1274 :
1275 : // If previous stand-alone ack isn't still in flight...
1276 0 : if (!ep->mConnStateFlags.Has(ConnectionStateFlag::kStandAloneAckInFlight))
1277 : {
1278 0 : CHIP_ERROR sendErr = ep->DriveStandAloneAck();
1279 :
1280 0 : if (sendErr != CHIP_NO_ERROR)
1281 : {
1282 0 : ep->DoClose(kWiFiPAFCloseFlag_AbortTransmission, sendErr);
1283 : }
1284 : }
1285 : }
1286 0 : }
1287 :
1288 0 : void WiFiPAFEndPoint::HandleWaitResourceTimeout(chip::System::Layer * systemLayer, void * appState)
1289 : {
1290 0 : WiFiPAFEndPoint * ep = static_cast<WiFiPAFEndPoint *>(appState);
1291 :
1292 : // Check for event-based timer race condition.
1293 0 : if (ep->mTimerStateFlags.Has(TimerStateFlag::kWaitResTimerRunning))
1294 : {
1295 0 : ep->mTimerStateFlags.Clear(TimerStateFlag::kWaitResTimerRunning);
1296 0 : CHIP_ERROR sendErr = ep->DriveSending();
1297 0 : if (sendErr != CHIP_NO_ERROR)
1298 : {
1299 0 : ep->DoClose(kWiFiPAFCloseFlag_AbortTransmission, sendErr);
1300 : }
1301 : }
1302 0 : }
1303 :
1304 2 : void WiFiPAFEndPoint::ClearAll()
1305 : {
1306 2 : memset(reinterpret_cast<uint8_t *>(this), 0, sizeof(WiFiPAFEndPoint));
1307 2 : return;
1308 : }
1309 :
1310 : } /* namespace WiFiPAF */
1311 : } /* namespace chip */
|