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