Matter SDK Coverage Report
Current view: top level - wifipaf - WiFiPAFEndPoint.cpp (source / functions) Coverage Total Hit
Test: SHA:6c8f029dd2432dc900f1c9245c324e69bd79e40a Lines: 84.0 % 536 450
Test Date: 2026-08-08 07:40:09 Functions: 91.3 % 46 42

            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 */
        

Generated by: LCOV version 2.0-1