Matter SDK Coverage Report
Current view: top level - wifipaf - WiFiPAFEndPoint.cpp (source / functions) Coverage Total Hit
Test: SHA:4d2388ac7eed75b2fe5e05e20de377999c632502 Lines: 80.7 % 482 389
Test Date: 2025-07-27 07:17:09 Functions: 90.7 % 43 39

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

Generated by: LCOV version 2.0-1