Matter SDK Coverage Report
Current view: top level - wifipaf - WiFiPAFTP.cpp (source / functions) Coverage Total Hit
Test: SHA:6c8f029dd2432dc900f1c9245c324e69bd79e40a Lines: 88.1 % 244 215
Test Date: 2026-08-08 07:40:09 Functions: 100.0 % 15 15

            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 module implements encode, decode, fragmentation and reassembly of
      21              :  *      PAF Transport Layer (PAFTP) packet types for transport of
      22              :  *      CHIP-over-WiFiPAF (CHIPoPAF) links.
      23              :  *
      24              :  */
      25              : 
      26              : #define _CHIP_WIFI_PAFTP_H
      27              : #include "WiFiPAFTP.h"
      28              : 
      29              : #include <cstdio>
      30              : #include <lib/core/CHIPConfig.h>
      31              : #include <lib/support/BitFlags.h>
      32              : #include <lib/support/BufferReader.h>
      33              : #include <lib/support/CodeUtils.h>
      34              : #include <lib/support/SafeInt.h>
      35              : #include <lib/support/Span.h>
      36              : #include <lib/support/logging/CHIPLogging.h>
      37              : #include <system/SystemPacketBuffer.h>
      38              : #include <utility>
      39              : 
      40              : #include "WiFiPAFConfig.h"
      41              : #include "WiFiPAFError.h"
      42              : 
      43              : // Define below to enable extremely verbose PAFTP-specific debug logging.
      44              : #undef CHIP_PAF_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
      45              : 
      46              : #ifdef CHIP_PAF_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
      47              : #define ChipLogDebugWiFiPAFTP(MOD, MSG, ...) ChipLogError(MOD, MSG, ##__VA_ARGS__)
      48              : #define ChipLogDebugBufferWiFiPAFTP(MOD, BUF)                                                                                      \
      49              :     ChipLogByteSpan(MOD, ByteSpan((BUF)->Start(), ((BUF)->DataLength() < 8 ? (BUF)->DataLength() : 8u)))
      50              : #else
      51              : #define ChipLogDebugWiFiPAFTP(MOD, MSG, ...)
      52              : #define ChipLogDebugBufferWiFiPAFTP(MOD, BUF)
      53              : #endif
      54              : 
      55              : namespace chip {
      56              : namespace WiFiPAF {
      57            3 : SequenceNumber_t OffsetSeqNum(SequenceNumber_t & tgtSeqNum, SequenceNumber_t & baseSeqNum)
      58              : {
      59            3 :     if (tgtSeqNum >= baseSeqNum)
      60            2 :         return static_cast<SequenceNumber_t>(tgtSeqNum - baseSeqNum);
      61            1 :     return static_cast<SequenceNumber_t>((0xff - baseSeqNum) + tgtSeqNum + 1);
      62              : }
      63              : 
      64            3 : static inline bool DidReceiveData(BitFlags<WiFiPAFTP::HeaderFlags> rx_flags)
      65              : {
      66            6 :     return rx_flags.HasAny(WiFiPAFTP::HeaderFlags::kStartMessage, WiFiPAFTP::HeaderFlags::kContinueMessage,
      67            3 :                            WiFiPAFTP::HeaderFlags::kEndMessage);
      68              : }
      69              : 
      70              : const uint16_t WiFiPAFTP::sDefaultFragmentSize = CHIP_PAF_DEFAULT_MTU; // minimum MTU - 3 bytes for operation header
      71              : const uint16_t WiFiPAFTP::sMaxFragmentSize =
      72              :     CHIP_PAF_DEFAULT_MTU; // Maximum size of PAFTP segment. Ref: 4.21.3.1, "Supported Maximum Service Specific Info Length"
      73              : const uint16_t WiFiPAFTP::sMinFragmentSize = kTransferProtocolMaxHeaderSize + 1;
      74              : 
      75           17 : CHIP_ERROR WiFiPAFTP::Init(void * an_app_state, bool expect_first_ack)
      76              : {
      77           17 :     mAppState              = an_app_state;
      78           17 :     mRxState               = kState_Idle;
      79           17 :     mRxBuf                 = nullptr;
      80           17 :     mRxNewestUnackedSeqNum = 0;
      81           17 :     mRxOldestUnackedSeqNum = 0;
      82           17 :     mRxFragmentSize        = sDefaultFragmentSize;
      83           17 :     mRxSeqHistId           = 0;
      84           17 :     memset(mRxSeqHist, 0, sizeof(mRxSeqHist));
      85           17 :     mTxState               = kState_Idle;
      86           17 :     mTxBuf                 = nullptr;
      87           17 :     mTxFragmentSize        = sDefaultFragmentSize;
      88           17 :     mRxCharCount           = 0;
      89           17 :     mRxPacketCount         = 0;
      90           17 :     mTxCharCount           = 0;
      91           17 :     mTxPacketCount         = 0;
      92           17 :     mTxNewestUnackedSeqNum = 0;
      93           17 :     mTxOldestUnackedSeqNum = 0;
      94              : 
      95           17 :     if (expect_first_ack)
      96              :     {
      97            4 :         mTxNextSeqNum = 1;
      98            4 :         mExpectingAck = true;
      99            4 :         mRxNextSeqNum = 0;
     100              :     }
     101              :     else
     102              :     {
     103           13 :         mTxNextSeqNum = 0;
     104           13 :         mExpectingAck = false;
     105           13 :         mRxNextSeqNum = 1;
     106              :     }
     107              : 
     108           17 :     return CHIP_NO_ERROR;
     109              : }
     110              : 
     111           14 : SequenceNumber_t WiFiPAFTP::GetAndIncrementNextTxSeqNum()
     112              : {
     113           14 :     SequenceNumber_t ret = mTxNextSeqNum;
     114              : 
     115              :     // If not already expecting ack...
     116           14 :     if (!mExpectingAck)
     117              :     {
     118            5 :         mExpectingAck          = true;
     119            5 :         mTxOldestUnackedSeqNum = mTxNextSeqNum;
     120              :     }
     121              : 
     122              :     // Update newest unacknowledged sequence number.
     123           14 :     mTxNewestUnackedSeqNum = mTxNextSeqNum;
     124              : 
     125              :     // Increment mTxNextSeqNum.
     126           14 :     mTxNextSeqNum = IncSeqNum(mTxNextSeqNum);
     127              : 
     128           14 :     return ret;
     129              : }
     130              : 
     131            6 : SequenceNumber_t WiFiPAFTP::GetAndRecordRxAckSeqNum()
     132              : {
     133            6 :     SequenceNumber_t ret = mRxNewestUnackedSeqNum;
     134              : 
     135            6 :     mRxNewestUnackedSeqNum = mRxNextSeqNum;
     136            6 :     mRxOldestUnackedSeqNum = mRxNextSeqNum;
     137              : 
     138            6 :     return ret;
     139              : }
     140              : 
     141            8 : bool WiFiPAFTP::HasUnackedData() const
     142              : {
     143            8 :     return (mRxOldestUnackedSeqNum != mRxNextSeqNum);
     144              : }
     145              : 
     146            6 : bool WiFiPAFTP::IsValidAck(SequenceNumber_t ack_num) const
     147              : {
     148              :     ChipLogDebugWiFiPAFTP(WiFiPAF, "entered IsValidAck, ack = %u, oldest = %u, newest = %u", ack_num, mTxOldestUnackedSeqNum,
     149              :                           mTxNewestUnackedSeqNum);
     150              : 
     151              :     // Return false if not awaiting any ack.
     152            6 :     if (!mExpectingAck)
     153              :     {
     154              :         ChipLogDebugWiFiPAFTP(WiFiPAF, "unexpected ack is invalid");
     155            1 :         return false;
     156              :     }
     157              : 
     158              :     // Assumption: maximum valid sequence number equals maximum value of SequenceNumber_t.
     159            5 :     if (mTxNewestUnackedSeqNum >= mTxOldestUnackedSeqNum) // If current unacked interval does NOT wrap...
     160              :     {
     161            5 :         return (ack_num <= mTxNewestUnackedSeqNum && ack_num >= mTxOldestUnackedSeqNum);
     162              :     }
     163              :     // Else, if current unacked interval DOES wrap...
     164            0 :     return (ack_num <= mTxNewestUnackedSeqNum || ack_num >= mTxOldestUnackedSeqNum);
     165              : }
     166              : 
     167            6 : CHIP_ERROR WiFiPAFTP::HandleAckReceived(SequenceNumber_t ack_num)
     168              : {
     169              :     ChipLogDebugWiFiPAFTP(WiFiPAF, "entered HandleAckReceived, ack_num = %u", ack_num);
     170              : 
     171              :     // Ensure ack_num falls within range of ack values we're expecting.
     172            6 :     VerifyOrReturnError(IsValidAck(ack_num), WIFIPAF_ERROR_INVALID_ACK);
     173              : 
     174            2 :     if (mTxNewestUnackedSeqNum == ack_num) // If ack is for newest outstanding unacknowledged fragment...
     175              :     {
     176            1 :         mTxOldestUnackedSeqNum = ack_num;
     177              : 
     178              :         // All outstanding fragments have been acknowledged.
     179            1 :         mExpectingAck = false;
     180              :     }
     181              :     else // If ack is valid, but not for newest outstanding unacknowledged fragment...
     182              :     {
     183              :         // Update newest unacknowledged fragment to one past that which was just acknowledged.
     184            1 :         mTxOldestUnackedSeqNum = ack_num;
     185            1 :         mTxOldestUnackedSeqNum = IncSeqNum(mTxOldestUnackedSeqNum);
     186              :     }
     187              : 
     188            2 :     return CHIP_NO_ERROR;
     189              : }
     190              : 
     191              : // Calling convention:
     192              : //   EncodeStandAloneAck may only be called if data arg is committed for immediate, synchronous subsequent transmission.
     193            2 : CHIP_ERROR WiFiPAFTP::EncodeStandAloneAck(const PacketBufferHandle & data)
     194              : {
     195              :     // Ensure enough headroom exists for the lower BLE layers.
     196            2 :     VerifyOrReturnError(data->EnsureReservedSize(CHIP_CONFIG_BLE_PKT_RESERVED_SIZE), CHIP_ERROR_NO_MEMORY);
     197              : 
     198              :     // Ensure enough space for standalone ack payload.
     199            2 :     VerifyOrReturnError(data->MaxDataLength() >= kTransferProtocolStandaloneAckHeaderSize, CHIP_ERROR_NO_MEMORY);
     200            2 :     uint8_t * characteristic = data->Start();
     201              : 
     202              :     // Since there's no preexisting message payload, we can write BTP header without adjusting data start pointer.
     203            2 :     characteristic[0] = static_cast<uint8_t>(HeaderFlags::kFragmentAck);
     204              : 
     205              :     // Acknowledge most recently received sequence number.
     206            2 :     characteristic[1] = GetAndRecordRxAckSeqNum();
     207              :     ChipLogDebugWiFiPAFTP(WiFiPAF, "===> encoded stand-alone ack = %u", characteristic[1]);
     208              : 
     209              :     // Include sequence number for stand-alone ack itself.
     210            2 :     characteristic[2] = GetAndIncrementNextTxSeqNum();
     211              : 
     212              :     // Set ack payload data length.
     213            2 :     data->SetDataLength(kTransferProtocolStandaloneAckHeaderSize);
     214              : 
     215            2 :     return CHIP_NO_ERROR;
     216              : }
     217              : 
     218              : // Calling convention:
     219              : //   WiFiPAFTP does not retain ownership of reassembled messages, layer above needs to free when done.
     220              : //
     221              : //   WiFiPAFTP does not reset itself on error. Upper layer should free outbound message and inbound reassembly buffers
     222              : //   if there is a problem.
     223              : 
     224              : // HandleCharacteristicReceived():
     225              : //
     226              : //   Non-NULL characteristic data arg is always either designated as or appended to the message reassembly buffer,
     227              : //   or freed if it holds a stand-alone ack. In all cases, caller must clear its reference to data arg when this
     228              : //   function returns.
     229              : //
     230              : //   Upper layer must immediately clean up and reinitialize protocol engine if returned err != CHIP_NO_ERROR.
     231            9 : CHIP_ERROR WiFiPAFTP::HandleCharacteristicReceived(System::PacketBufferHandle && data, SequenceNumber_t & receivedAck,
     232              :                                                    bool & didReceiveAck)
     233              : {
     234            9 :     CHIP_ERROR err = CHIP_NO_ERROR;
     235            9 :     BitFlags<HeaderFlags> rx_flags;
     236              : 
     237            9 :     VerifyOrExit(!data.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
     238              : 
     239              :     { // Scope for reader, so we can do the VerifyOrExit above.
     240              :         // Data uses little-endian byte order.
     241            9 :         Encoding::LittleEndian::Reader reader(data->Start(), data->DataLength());
     242              : 
     243            9 :         mRxCharCount++;
     244              : 
     245              :         // Get header flags, always in first byte.
     246            9 :         err = reader.Read8(rx_flags.RawStorage()).StatusCode();
     247            9 :         SuccessOrExit(err);
     248              : 
     249            8 :         didReceiveAck = rx_flags.Has(HeaderFlags::kFragmentAck);
     250              : 
     251              :         // Get ack number, if any.
     252            8 :         if (didReceiveAck)
     253              :         {
     254            6 :             err = reader.Read8(&receivedAck).StatusCode();
     255            6 :             SuccessOrExit(err);
     256              : 
     257            6 :             err = HandleAckReceived(receivedAck);
     258              :             // Multiple-ACK
     259           12 :             if (err != CHIP_NO_ERROR)
     260              :             {
     261              :                 ChipLogDebugWiFiPAFTP(WiFiPAF, "Drop the invalid ack, but update the seq_n and leave");
     262            4 :                 err = reader.Read8(&mRxNewestUnackedSeqNum).StatusCode();
     263            4 :                 SuccessOrExit(err);
     264              :                 ChipLogDebugWiFiPAFTP(WiFiPAF, "Update the seq_n: %u", mRxNewestUnackedSeqNum);
     265            4 :                 mRxNextSeqNum = mRxNewestUnackedSeqNum;
     266            4 :                 mRxNextSeqNum = IncSeqNum(mRxNextSeqNum);
     267            4 :                 LogState();
     268            4 :                 return CHIP_NO_ERROR;
     269              :             }
     270              :         }
     271              : 
     272              :         // Get sequence number.
     273            4 :         err = reader.Read8(&mRxNewestUnackedSeqNum).StatusCode();
     274            4 :         SuccessOrExit(err);
     275              :         ChipLogDebugWiFiPAFTP(WiFiPAF, "(Rx_Seq, mRxNextSeqNum)=(%u, %u), mRxState: %u", mRxNewestUnackedSeqNum, mRxNextSeqNum,
     276              :                               mRxState);
     277            4 :         mRxSeqHist[mRxSeqHistId] = mRxNewestUnackedSeqNum;
     278            4 :         mRxSeqHistId             = (mRxSeqHistId + 1) % CHIP_PAFTP_RXHIST_SIZE;
     279            4 :         if (mRxNewestUnackedSeqNum < mRxNextSeqNum)
     280              :         {
     281              :             // Drop the duplicated rx-pkt
     282            1 :             ChipLogError(WiFiPAF, "Drop the duplicated rx pkt!");
     283            1 :             return CHIP_NO_ERROR;
     284              :         }
     285              : 
     286              :         // Verify that received sequence number is the next one we'd expect.
     287            3 :         VerifyOrExit(mRxNewestUnackedSeqNum == mRxNextSeqNum, err = WIFIPAF_ERROR_INVALID_PAFTP_SEQUENCE_NUMBER);
     288              : 
     289              :         // Increment next expected rx sequence number.
     290            3 :         mRxNextSeqNum = IncSeqNum(mRxNextSeqNum);
     291              : 
     292              :         // If fragment was stand-alone ack, we're done here; no payload for message reassembler.
     293            3 :         if (!DidReceiveData(rx_flags))
     294              :         {
     295            0 :             ExitNow();
     296              :         }
     297              : 
     298              :         // Truncate the incoming fragment length by the mRxFragmentSize as the negotiated
     299              :         // mRxFragmentSize may be smaller than the characteristic size.  Make sure
     300              :         // we're not truncating to a data length smaller than what we have already consumed.
     301            3 :         VerifyOrExit(reader.OctetsRead() <= mRxFragmentSize, err = WIFIPAF_ERROR_REASSEMBLER_INCORRECT_STATE);
     302            3 :         data->SetDataLength(std::min(data->DataLength(), static_cast<size_t>(mRxFragmentSize)));
     303              : 
     304              :         // Now mark the bytes we consumed as consumed.
     305            3 :         data->ConsumeHead(static_cast<uint16_t>(reader.OctetsRead()));
     306              : 
     307              :         ChipLogDebugWiFiPAFTP(WiFiPAF, ">>> PAFTP reassembler received data:");
     308              :         ChipLogDebugBufferWiFiPAFTP(WiFiPAF, data);
     309              :     }
     310              : 
     311            3 :     if (mRxState == kState_Idle)
     312              :     {
     313              :         // We need a new reader, because the state of our outer reader no longer
     314              :         // matches the state of the packetbuffer, both in terms of start
     315              :         // position and available length.
     316            3 :         Encoding::LittleEndian::Reader startReader(data->Start(), data->DataLength());
     317              : 
     318              :         // Verify StartMessage header flag set.
     319            3 :         VerifyOrExit(rx_flags.Has(HeaderFlags::kStartMessage), err = WIFIPAF_ERROR_INVALID_PAFTP_HEADER_FLAGS);
     320              : 
     321            3 :         err = startReader.Read16(&mRxLength).StatusCode();
     322            3 :         SuccessOrExit(err);
     323              : 
     324            3 :         mRxState = kState_InProgress;
     325              : 
     326            3 :         data->ConsumeHead(static_cast<uint16_t>(startReader.OctetsRead()));
     327              : 
     328              :         // Create a new buffer for use as the Rx re-assembly area.
     329            3 :         mRxBuf = System::PacketBufferHandle::New(System::PacketBuffer::kMaxSize);
     330              : 
     331            3 :         VerifyOrExit(!mRxBuf.IsNull(), err = CHIP_ERROR_NO_MEMORY);
     332              : 
     333            3 :         mRxBuf->AddToEnd(std::move(data));
     334            3 :         mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
     335              : 
     336              :         // For now, limit WiFiPAFTP message size to max length of 1 pbuf, as we do for chip messages sent via IP.
     337              :         // TODO add support for WiFiPAFTP messages longer than 1 pbuf
     338            3 :         VerifyOrExit(!mRxBuf->HasChainedBuffer(), err = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG);
     339              :     }
     340            0 :     else if (mRxState == kState_InProgress)
     341              :     {
     342              :         // Verify StartMessage header flag NOT set, since we're in the middle of receiving a message.
     343            0 :         VerifyOrExit(!rx_flags.Has(HeaderFlags::kStartMessage), err = WIFIPAF_ERROR_INVALID_PAFTP_HEADER_FLAGS);
     344              : 
     345              :         // Verify ContinueMessage or EndMessage header flag set.
     346            0 :         VerifyOrExit(rx_flags.HasAny(HeaderFlags::kContinueMessage, HeaderFlags::kEndMessage),
     347              :                      err = WIFIPAF_ERROR_INVALID_PAFTP_HEADER_FLAGS);
     348              : 
     349              :         // Add received fragment to reassembled message buffer.
     350            0 :         mRxBuf->AddToEnd(std::move(data));
     351            0 :         mRxBuf->CompactHead(); // will free 'data' and adjust rx buf's end/length
     352              : 
     353              :         // For now, limit WiFiPAFTP message size to max length of 1 pbuf, as we do for chip messages sent via IP.
     354              :         // TODO add support for WiFiPAFTP messages longer than 1 pbuf
     355            0 :         VerifyOrExit(!mRxBuf->HasChainedBuffer(), err = CHIP_ERROR_INBOUND_MESSAGE_TOO_BIG);
     356              :     }
     357              :     else
     358              :     {
     359            0 :         err = WIFIPAF_ERROR_REASSEMBLER_INCORRECT_STATE;
     360            0 :         ExitNow();
     361              :     }
     362              : 
     363            3 :     if (rx_flags.Has(HeaderFlags::kEndMessage))
     364              :     {
     365              :         // Trim remainder, if any, of the received packet buffer based on sender-specified length of reassembled message.
     366            3 :         VerifyOrExit(CanCastTo<uint16_t>(mRxBuf->DataLength()), err = CHIP_ERROR_MESSAGE_TOO_LONG);
     367            3 :         int padding = static_cast<uint16_t>(mRxBuf->DataLength()) - mRxLength;
     368              : 
     369            3 :         if (padding > 0)
     370              :         {
     371            0 :             mRxBuf->SetDataLength(static_cast<size_t>(mRxLength));
     372              :         }
     373              : 
     374              :         // Ensure all received fragments add up to sender-specified total message size.
     375            3 :         VerifyOrExit(mRxBuf->DataLength() == mRxLength, err = WIFIPAF_ERROR_REASSEMBLER_MISSING_DATA);
     376              : 
     377              :         // We've reassembled the entire message.
     378            3 :         mRxState = kState_Complete;
     379            3 :         mRxPacketCount++;
     380              :     }
     381              : 
     382            0 : exit:
     383            8 :     if (err != CHIP_NO_ERROR)
     384              :     {
     385            1 :         mRxState = kState_Error;
     386              :         // Dump protocol engine state, plus header flags and received data length.
     387            1 :         ChipLogError(WiFiPAF, "HandleCharacteristicReceived failed, err = %" CHIP_ERROR_FORMAT ", rx_flags = %u", err.Format(),
     388              :                      rx_flags.Raw());
     389            1 :         if (didReceiveAck)
     390              :         {
     391            0 :             ChipLogError(WiFiPAF, "With rx'd ack = %u", receivedAck);
     392              :         }
     393            1 :         if (!mRxBuf.IsNull())
     394              :         {
     395            0 :             ChipLogError(WiFiPAF, "With rx buf data length = %u", static_cast<unsigned>(mRxBuf->DataLength()));
     396              :         }
     397            1 :         LogState();
     398              : 
     399            1 :         if (!data.IsNull()) // NOLINT(bugprone-use-after-move)
     400              :         {
     401              :             // Tack received data onto rx buffer, to be freed when end point resets protocol engine on close.
     402            1 :             if (!mRxBuf.IsNull())
     403              :             {
     404            0 :                 mRxBuf->AddToEnd(std::move(data));
     405              :             }
     406              :             else
     407              :             {
     408            1 :                 mRxBuf = std::move(data);
     409              :             }
     410              :         }
     411              :     }
     412              : 
     413            4 :     return err;
     414              : }
     415              : 
     416           18 : PacketBufferHandle WiFiPAFTP::TakeRxPacket()
     417              : {
     418           18 :     if (mRxState == kState_Complete)
     419              :     {
     420            3 :         mRxState = kState_Idle;
     421              :     }
     422           18 :     return std::move(mRxBuf);
     423              : }
     424              : 
     425              : // Calling convention:
     426              : //   May only be called if data arg is committed for immediate, synchronous subsequent transmission.
     427              : //   Returns false on error. Caller must free data arg on error.
     428           11 : bool WiFiPAFTP::HandleCharacteristicSend(System::PacketBufferHandle data, bool send_ack)
     429              : {
     430              :     uint8_t * characteristic;
     431           11 :     mTxCharCount++;
     432              : 
     433           11 :     if (send_ack && !HasUnackedData())
     434              :     {
     435            0 :         ChipLogError(Inet, "HandleCharacteristicSend: send_ack true, but nothing to acknowledge.");
     436            0 :         return false;
     437              :     }
     438              : 
     439           11 :     if (mTxState == kState_Idle)
     440              :     {
     441            9 :         if (data.IsNull())
     442              :         {
     443            0 :             return false;
     444              :         }
     445              : 
     446            9 :         mTxBuf   = std::move(data);
     447            9 :         mTxState = kState_InProgress;
     448            9 :         VerifyOrReturnError(CanCastTo<uint16_t>(mTxBuf->DataLength()), false);
     449            9 :         mTxLength = static_cast<uint16_t>(mTxBuf->DataLength());
     450              : 
     451              :         ChipLogDebugWiFiPAFTP(WiFiPAF, ">>> CHIPoWiFiPAF preparing to send whole message:");
     452              :         ChipLogDebugBufferWiFiPAFTP(WiFiPAF, mTxBuf);
     453              : 
     454              :         // Determine fragment header size.
     455            9 :         uint8_t header_size =
     456              :             send_ack ? kTransferProtocolMaxHeaderSize : (kTransferProtocolMaxHeaderSize - kTransferProtocolAckSize);
     457              : 
     458              :         // Ensure enough headroom exists for the PAFTP header
     459            9 :         if (!mTxBuf->EnsureReservedSize(header_size))
     460              :         {
     461              :             // handle error
     462            0 :             ChipLogError(Inet, "HandleCharacteristicSend: not enough headroom");
     463            0 :             mTxState = kState_Error;
     464            0 :             mTxBuf   = nullptr; // Avoid double-free after assignment above, as caller frees data on error.
     465              : 
     466            0 :             return false;
     467              :         }
     468              : 
     469              :         // prepend header.
     470            9 :         characteristic = mTxBuf->Start();
     471            9 :         characteristic -= header_size;
     472            9 :         mTxBuf->SetStart(characteristic);
     473            9 :         uint8_t cursor = 1; // first position past header flags byte
     474            9 :         BitFlags<HeaderFlags> headerFlags(HeaderFlags::kStartMessage);
     475              : 
     476            9 :         if (send_ack)
     477              :         {
     478            3 :             headerFlags.Set(HeaderFlags::kFragmentAck);
     479            3 :             characteristic[cursor++] = GetAndRecordRxAckSeqNum();
     480              :             ChipLogDebugWiFiPAFTP(WiFiPAF, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
     481              :         }
     482              : 
     483            9 :         characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
     484            9 :         characteristic[cursor++] = static_cast<uint8_t>(mTxLength & 0xff);
     485            9 :         characteristic[cursor++] = static_cast<uint8_t>(mTxLength >> 8);
     486              : 
     487            9 :         if ((mTxLength + cursor) <= mTxFragmentSize)
     488              :         {
     489            7 :             mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
     490            7 :             mTxLength = 0;
     491            7 :             headerFlags.Set(HeaderFlags::kEndMessage);
     492            7 :             mTxState = kState_Complete;
     493            7 :             mTxPacketCount++;
     494              :         }
     495              :         else
     496              :         {
     497            2 :             mTxBuf->SetDataLength(mTxFragmentSize);
     498            2 :             mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
     499              :         }
     500              : 
     501            9 :         characteristic[0] = headerFlags.Raw();
     502              :         ChipLogDebugWiFiPAFTP(WiFiPAF, ">>> CHIPoWiFiPAF preparing to send first fragment:");
     503              :         ChipLogDebugBufferWiFiPAFTP(WiFiPAF, mTxBuf);
     504              :     }
     505            2 :     else if (mTxState == kState_InProgress)
     506              :     {
     507            2 :         if (!data.IsNull())
     508              :         {
     509            0 :             return false;
     510              :         }
     511              : 
     512              :         // advance past the previous fragment
     513            2 :         characteristic = mTxBuf->Start();
     514            2 :         characteristic += mTxFragmentSize;
     515              : 
     516              :         // prepend header
     517            2 :         characteristic -= send_ack ? kTransferProtocolMidFragmentMaxHeaderSize
     518              :                                    : (kTransferProtocolMidFragmentMaxHeaderSize - kTransferProtocolAckSize);
     519            2 :         mTxBuf->SetStart(characteristic);
     520            2 :         uint8_t cursor = 1; // first position past header flags byte
     521              : 
     522            2 :         BitFlags<HeaderFlags> headerFlags(HeaderFlags::kContinueMessage);
     523              : 
     524            2 :         if (send_ack)
     525              :         {
     526            0 :             headerFlags.Set(HeaderFlags::kFragmentAck);
     527            0 :             characteristic[cursor++] = GetAndRecordRxAckSeqNum();
     528              :             ChipLogDebugWiFiPAFTP(WiFiPAF, "===> encoded piggybacked ack, ack_num = %u", characteristic[cursor - 1]);
     529              :         }
     530              : 
     531            2 :         characteristic[cursor++] = GetAndIncrementNextTxSeqNum();
     532              : 
     533            2 :         if ((mTxLength + cursor) <= mTxFragmentSize)
     534              :         {
     535            2 :             mTxBuf->SetDataLength(static_cast<uint16_t>(mTxLength + cursor));
     536            2 :             mTxLength = 0;
     537            2 :             headerFlags.Set(HeaderFlags::kEndMessage);
     538            2 :             mTxState = kState_Complete;
     539            2 :             mTxPacketCount++;
     540              :         }
     541              :         else
     542              :         {
     543            0 :             mTxBuf->SetDataLength(mTxFragmentSize);
     544            0 :             mTxLength = static_cast<uint16_t>((mTxLength + cursor) - mTxFragmentSize);
     545              :         }
     546              : 
     547            2 :         characteristic[0] = headerFlags.Raw();
     548              :         ChipLogDebugWiFiPAFTP(WiFiPAF, ">>> CHIPoWiFiPAF preparing to send additional fragment:");
     549              :         ChipLogDebugBufferWiFiPAFTP(WiFiPAF, mTxBuf);
     550              :     }
     551              :     else
     552              :     {
     553              :         // Invalid tx state.
     554            0 :         ChipLogError(WiFiPAF, "Invalid tx state: %u", mTxState);
     555            0 :         return false;
     556              :     }
     557              : 
     558           11 :     return true;
     559              : }
     560              : 
     561           22 : PacketBufferHandle WiFiPAFTP::TakeTxPacket()
     562              : {
     563           22 :     if (mTxState == kState_Complete)
     564              :     {
     565            9 :         mTxState = kState_Idle;
     566              :     }
     567           22 :     return std::move(mTxBuf);
     568              : }
     569              : 
     570            6 : void WiFiPAFTP::LogState() const
     571              : {
     572            6 :     ChipLogError(WiFiPAF, "mAppState: %p", mAppState);
     573              : 
     574            6 :     ChipLogError(WiFiPAF, "mRxFragmentSize: %d", mRxFragmentSize);
     575            6 :     ChipLogError(WiFiPAF, "mRxState: %d", mRxState);
     576            6 :     ChipLogError(WiFiPAF, "mRxBuf: %d", !mRxBuf.IsNull());
     577            6 :     ChipLogError(WiFiPAF, "mRxNextSeqNum: %d", mRxNextSeqNum);
     578            6 :     ChipLogError(WiFiPAF, "mRxNewestUnackedSeqNum: %d", mRxNewestUnackedSeqNum);
     579            6 :     ChipLogError(WiFiPAF, "mRxOldestUnackedSeqNum: %d", mRxOldestUnackedSeqNum);
     580            6 :     ChipLogError(WiFiPAF, "mRxCharCount: %d", mRxCharCount);
     581            6 :     ChipLogError(WiFiPAF, "mRxPacketCount: %d", mRxPacketCount);
     582              : 
     583              :     char RxSeqHistMsg[64];
     584            6 :     memset(RxSeqHistMsg, 0, sizeof(RxSeqHistMsg));
     585           54 :     for (uint8_t idx = 0; idx < CHIP_PAFTP_RXHIST_SIZE; idx++)
     586              :     {
     587              :         char RxSeq[6];
     588           48 :         snprintf(RxSeq, sizeof(RxSeq), "%03u ", mRxSeqHist[(mRxSeqHistId + 1 + idx) % CHIP_PAFTP_RXHIST_SIZE]);
     589           48 :         strcat(RxSeqHistMsg, RxSeq);
     590              :     }
     591            6 :     ChipLogError(WiFiPAF, "Rx_Seq_History: [%s]", RxSeqHistMsg);
     592              : 
     593            6 :     ChipLogError(WiFiPAF, "mTxFragmentSize: %d", mTxFragmentSize);
     594            6 :     ChipLogError(WiFiPAF, "mTxState: %d", mTxState);
     595            6 :     ChipLogError(WiFiPAF, "mTxBuf: %d", !mTxBuf.IsNull());
     596            6 :     ChipLogError(WiFiPAF, "mTxNextSeqNum: %d", mTxNextSeqNum);
     597            6 :     ChipLogError(WiFiPAF, "mTxNewestUnackedSeqNum: %d", mTxNewestUnackedSeqNum);
     598            6 :     ChipLogError(WiFiPAF, "mTxOldestUnackedSeqNum: %d", mTxOldestUnackedSeqNum);
     599            6 :     ChipLogError(WiFiPAF, "mTxCharCount: %d", mTxCharCount);
     600            6 :     ChipLogError(WiFiPAF, "mTxPacketCount: %d", mTxPacketCount);
     601            6 : }
     602              : 
     603            8 : void WiFiPAFTP::LogStateDebug() const
     604              : {
     605              : #ifdef CHIP_PAF_PROTOCOL_ENGINE_DEBUG_LOGGING_ENABLED
     606              :     LogState();
     607              : #endif
     608            8 : }
     609              : 
     610              : } /* namespace WiFiPAF */
     611              : } /* namespace chip */
        

Generated by: LCOV version 2.0-1