Matter SDK Coverage Report
Current view: top level - protocols/bdx - BdxTransferSession.cpp (source / functions) Coverage Total Hit
Test: SHA:6c8f029dd2432dc900f1c9245c324e69bd79e40a Lines: 83.8 % 573 480
Test Date: 2026-08-08 07:40:09 Functions: 85.4 % 41 35

            Line data    Source code
       1              : /**
       2              :  *    @file
       3              :  *      Implementation for the TransferSession class.
       4              :  *      // TODO: Support Asynchronous mode. Currently, only Synchronous mode is supported.
       5              :  */
       6              : 
       7              : #include <protocols/bdx/BdxTransferSession.h>
       8              : 
       9              : #include <lib/support/BufferReader.h>
      10              : #include <lib/support/CodeUtils.h>
      11              : #include <lib/support/TypeTraits.h>
      12              : #include <lib/support/logging/CHIPLogging.h>
      13              : #include <protocols/Protocols.h>
      14              : #include <protocols/bdx/BdxMessages.h>
      15              : #include <protocols/secure_channel/Constants.h>
      16              : #include <protocols/secure_channel/StatusReport.h>
      17              : #include <system/SystemPacketBuffer.h>
      18              : #include <transport/SessionManager.h>
      19              : 
      20              : #include <type_traits>
      21              : 
      22              : namespace {
      23              : constexpr uint8_t kBdxVersion = 0; ///< The version of this implementation of the BDX spec
      24              : 
      25              : /**
      26              :  * @brief
      27              :  *   Allocate a new PacketBuffer and write data from a BDX message struct.
      28              :  */
      29           55 : CHIP_ERROR WriteToPacketBuffer(const ::chip::bdx::BdxMessage & msgStruct, ::chip::System::PacketBufferHandle & msgBuf)
      30              : {
      31           55 :     size_t msgDataSize = msgStruct.MessageSize();
      32           55 :     ::chip::Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgDataSize), msgDataSize);
      33           55 :     if (bbuf.IsNull())
      34              :     {
      35            0 :         return CHIP_ERROR_NO_MEMORY;
      36              :     }
      37           55 :     msgStruct.WriteToBuffer(bbuf);
      38           55 :     msgBuf = bbuf.Finalize();
      39           55 :     if (msgBuf.IsNull())
      40              :     {
      41            0 :         return CHIP_ERROR_NO_MEMORY;
      42              :     }
      43           55 :     return CHIP_NO_ERROR;
      44           55 : }
      45              : 
      46              : template <typename MessageType>
      47           60 : void PrepareOutgoingMessageEvent(MessageType messageType, chip::bdx::TransferSession::OutputEventType & pendingOutput,
      48              :                                  chip::bdx::TransferSession::MessageTypeData & outputMsgType)
      49              : {
      50              :     static_assert(std::is_same<std::underlying_type_t<decltype(messageType)>, uint8_t>::value, "Cast is not safe");
      51              : 
      52           60 :     pendingOutput             = chip::bdx::TransferSession::OutputEventType::kMsgToSend;
      53           60 :     outputMsgType.ProtocolId  = chip::Protocols::MessageTypeTraits<MessageType>::ProtocolId();
      54           60 :     outputMsgType.MessageType = static_cast<uint8_t>(messageType);
      55           60 : }
      56              : 
      57              : } // anonymous namespace
      58              : 
      59              : namespace chip {
      60              : namespace bdx {
      61              : 
      62           25 : TransferSession::TransferSession()
      63              : {
      64           25 :     mSuppportedXferOpts.ClearAll();
      65           25 : }
      66              : 
      67          223 : void TransferSession::PollOutput(OutputEvent & event, System::Clock::Timestamp curTime)
      68              : {
      69          223 :     event = OutputEvent(OutputEventType::kNone);
      70              : 
      71          223 :     if (mShouldInitTimeoutStart)
      72              :     {
      73           23 :         mTimeoutStartTime       = curTime;
      74           23 :         mShouldInitTimeoutStart = false;
      75              :     }
      76              : 
      77          223 :     if (mAwaitingResponse && ((curTime - mTimeoutStartTime) >= mTimeout))
      78              :     {
      79            2 :         event             = OutputEvent(OutputEventType::kTransferTimeout);
      80            2 :         mState            = TransferState::kErrorState;
      81            2 :         mAwaitingResponse = false;
      82            2 :         return;
      83              :     }
      84              : 
      85          221 :     switch (mPendingOutput)
      86              :     {
      87          109 :     case OutputEventType::kNone:
      88          109 :         event = OutputEvent(OutputEventType::kNone);
      89          109 :         break;
      90            0 :     case OutputEventType::kInternalError:
      91            0 :         event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
      92            0 :         break;
      93            3 :     case OutputEventType::kStatusReceived:
      94            3 :         event = OutputEvent::StatusReportEvent(OutputEventType::kStatusReceived, mStatusReportData);
      95            3 :         break;
      96           59 :     case OutputEventType::kMsgToSend:
      97           59 :         event             = OutputEvent::MsgToSendEvent(mMsgTypeData, std::move(mPendingMsgHandle));
      98           59 :         mTimeoutStartTime = curTime;
      99           59 :         break;
     100           10 :     case OutputEventType::kInitReceived:
     101           10 :         event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle));
     102           10 :         break;
     103            4 :     case OutputEventType::kAcceptReceived:
     104            4 :         event = OutputEvent::TransferAcceptEvent(mTransferAcceptData, std::move(mPendingMsgHandle));
     105            4 :         break;
     106           12 :     case OutputEventType::kQueryReceived:
     107           12 :         event = OutputEvent(OutputEventType::kQueryReceived);
     108           12 :         break;
     109            0 :     case OutputEventType::kQueryWithSkipReceived:
     110            0 :         event = OutputEvent::QueryWithSkipEvent(mBytesToSkip);
     111            0 :         break;
     112           17 :     case OutputEventType::kBlockReceived:
     113           17 :         event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle));
     114           17 :         break;
     115            5 :     case OutputEventType::kAckReceived:
     116            5 :         event = OutputEvent(OutputEventType::kAckReceived);
     117            5 :         break;
     118            2 :     case OutputEventType::kAckEOFReceived:
     119            2 :         event = OutputEvent(OutputEventType::kAckEOFReceived);
     120            2 :         break;
     121            0 :     default:
     122            0 :         event = OutputEvent(OutputEventType::kNone);
     123            0 :         break;
     124              :     }
     125              : 
     126              :     // If there's no other pending output but an error occurred or was received, then continue to output the error.
     127              :     // This ensures that when the TransferSession encounters an error and needs to send a StatusReport, both a kMsgToSend and a
     128              :     // kInternalError output event will be emitted.
     129          221 :     if (event.EventType == OutputEventType::kNone && mState == TransferState::kErrorState)
     130              :     {
     131           11 :         event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
     132              :     }
     133              : 
     134          221 :     mPendingOutput = OutputEventType::kNone;
     135              : }
     136              : 
     137            0 : void TransferSession::GetNextAction(OutputEvent & event)
     138              : {
     139            0 :     PollOutput(event, System::SystemClock().GetMonotonicTimestamp());
     140            0 : }
     141              : 
     142           14 : CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitData & initData, System::Clock::Timeout timeout)
     143              : {
     144           14 :     VerifyOrReturnError(mState == TransferState::kUnitialized, CHIP_ERROR_INCORRECT_STATE);
     145              : 
     146           14 :     mRole    = role;
     147           14 :     mTimeout = timeout;
     148              : 
     149              :     // Set transfer parameters. They may be overridden later by an Accept message
     150           14 :     mSuppportedXferOpts    = initData.TransferCtlFlags;
     151           14 :     mMaxSupportedBlockSize = initData.MaxBlockSize;
     152           14 :     mStartOffset           = initData.StartOffset;
     153           14 :     mTransferLength        = initData.Length;
     154              : 
     155              :     // Prepare TransferInit message
     156           14 :     TransferInit initMsg;
     157           14 :     initMsg.TransferCtlOptions = initData.TransferCtlFlags;
     158           14 :     initMsg.Version            = kBdxVersion;
     159           14 :     initMsg.MaxBlockSize       = mMaxSupportedBlockSize;
     160           14 :     initMsg.StartOffset        = mStartOffset;
     161           14 :     initMsg.MaxLength          = mTransferLength;
     162           14 :     initMsg.FileDesignator     = initData.FileDesignator;
     163           14 :     initMsg.FileDesLength      = initData.FileDesLength;
     164           14 :     initMsg.Metadata           = initData.Metadata;
     165           14 :     initMsg.MetadataLength     = initData.MetadataLength;
     166              : 
     167           14 :     ReturnErrorOnFailure(WriteToPacketBuffer(initMsg, mPendingMsgHandle));
     168              : 
     169           14 :     const MessageType msgType = (mRole == TransferRole::kSender) ? MessageType::SendInit : MessageType::ReceiveInit;
     170              : 
     171              : #if CHIP_AUTOMATION_LOGGING
     172           14 :     ChipLogAutomation("Sending BDX Message");
     173           14 :     initMsg.LogMessage(msgType);
     174              : #endif // CHIP_AUTOMATION_LOGGING
     175              : 
     176           14 :     mState            = TransferState::kAwaitingAccept;
     177           14 :     mAwaitingResponse = true;
     178              : 
     179           14 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     180              : 
     181           14 :     return CHIP_NO_ERROR;
     182           14 : }
     183              : 
     184           11 : CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags<TransferControlFlags> xferControlOpts,
     185              :                                             uint16_t maxBlockSize, System::Clock::Timeout timeout)
     186              : {
     187           11 :     VerifyOrReturnError(mState == TransferState::kUnitialized, CHIP_ERROR_INCORRECT_STATE);
     188              : 
     189              :     // Used to determine compatibility with any future TransferInit parameters
     190           11 :     mRole                  = role;
     191           11 :     mTimeout               = timeout;
     192           11 :     mSuppportedXferOpts    = xferControlOpts;
     193           11 :     mMaxSupportedBlockSize = maxBlockSize;
     194              : 
     195           11 :     mState = TransferState::kAwaitingInitMsg;
     196              : 
     197           11 :     return CHIP_NO_ERROR;
     198              : }
     199              : 
     200            7 : CHIP_ERROR TransferSession::AcceptTransfer(const TransferAcceptData & acceptData)
     201              : {
     202              :     MessageType msgType;
     203              : 
     204            7 :     const BitFlags<TransferControlFlags> proposedControlOpts(mTransferRequestData.TransferCtlFlags);
     205              : 
     206            7 :     VerifyOrReturnError(mState == TransferState::kNegotiateTransferParams, CHIP_ERROR_INCORRECT_STATE);
     207            7 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     208              : 
     209              :     // Don't allow a Control method that wasn't supported by the initiator
     210              :     // MaxBlockSize can't be larger than the proposed value
     211            7 :     VerifyOrReturnError(proposedControlOpts.Has(acceptData.ControlMode), CHIP_ERROR_INVALID_ARGUMENT);
     212            6 :     VerifyOrReturnError(acceptData.MaxBlockSize <= mTransferRequestData.MaxBlockSize, CHIP_ERROR_INVALID_ARGUMENT);
     213              : 
     214            5 :     mTransferMaxBlockSize = acceptData.MaxBlockSize;
     215              : 
     216            5 :     if (mRole == TransferRole::kSender)
     217              :     {
     218            2 :         mStartOffset    = acceptData.StartOffset;
     219            2 :         mTransferLength = acceptData.Length;
     220              : 
     221            2 :         ReceiveAccept acceptMsg;
     222            2 :         acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
     223            2 :         acceptMsg.Version        = mTransferVersion;
     224            2 :         acceptMsg.MaxBlockSize   = acceptData.MaxBlockSize;
     225            2 :         acceptMsg.StartOffset    = acceptData.StartOffset;
     226            2 :         acceptMsg.Length         = acceptData.Length;
     227            2 :         acceptMsg.Metadata       = acceptData.Metadata;
     228            2 :         acceptMsg.MetadataLength = acceptData.MetadataLength;
     229              : 
     230            2 :         ReturnErrorOnFailure(WriteToPacketBuffer(acceptMsg, mPendingMsgHandle));
     231            2 :         msgType = MessageType::ReceiveAccept;
     232              : 
     233              : #if CHIP_AUTOMATION_LOGGING
     234            2 :         ChipLogAutomation("Sending BDX Message");
     235            2 :         acceptMsg.LogMessage(msgType);
     236              : #endif // CHIP_AUTOMATION_LOGGING
     237            2 :     }
     238              :     else
     239              :     {
     240            3 :         SendAccept acceptMsg;
     241            3 :         acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
     242            3 :         acceptMsg.Version        = mTransferVersion;
     243            3 :         acceptMsg.MaxBlockSize   = acceptData.MaxBlockSize;
     244            3 :         acceptMsg.Metadata       = acceptData.Metadata;
     245            3 :         acceptMsg.MetadataLength = acceptData.MetadataLength;
     246              : 
     247            3 :         ReturnErrorOnFailure(WriteToPacketBuffer(acceptMsg, mPendingMsgHandle));
     248            3 :         msgType = MessageType::SendAccept;
     249              : 
     250              : #if CHIP_AUTOMATION_LOGGING
     251            3 :         ChipLogAutomation("Sending BDX Message");
     252            3 :         acceptMsg.LogMessage(msgType);
     253              : #endif // CHIP_AUTOMATION_LOGGING
     254            3 :     }
     255              : 
     256            5 :     mState = TransferState::kTransferInProgress;
     257              : 
     258            5 :     if ((mRole == TransferRole::kReceiver && mControlMode == TransferControlFlags::kSenderDrive) ||
     259            2 :         (mRole == TransferRole::kSender && mControlMode == TransferControlFlags::kReceiverDrive))
     260              :     {
     261            5 :         mAwaitingResponse = true;
     262              :     }
     263              : 
     264            5 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     265              : 
     266            5 :     return CHIP_NO_ERROR;
     267              : }
     268              : 
     269            1 : CHIP_ERROR TransferSession::RejectTransfer(StatusCode reason)
     270              : {
     271            1 :     VerifyOrReturnError(mState == TransferState::kNegotiateTransferParams, CHIP_ERROR_INCORRECT_STATE);
     272            1 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     273              : 
     274            1 :     PrepareStatusReport(reason);
     275            1 :     mState = TransferState::kTransferDone;
     276              : 
     277            1 :     return CHIP_NO_ERROR;
     278              : }
     279              : 
     280           12 : CHIP_ERROR TransferSession::PrepareBlockQuery()
     281              : {
     282           12 :     const MessageType msgType = MessageType::BlockQuery;
     283              : 
     284           12 :     VerifyOrReturnError(mState == TransferState::kTransferInProgress, CHIP_ERROR_INCORRECT_STATE);
     285           12 :     VerifyOrReturnError(mRole == TransferRole::kReceiver, CHIP_ERROR_INCORRECT_STATE);
     286           12 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     287           12 :     VerifyOrReturnError(!mAwaitingResponse, CHIP_ERROR_INCORRECT_STATE);
     288              : 
     289           12 :     BlockQuery queryMsg;
     290           12 :     queryMsg.BlockCounter = mNextQueryNum;
     291              : 
     292           12 :     ReturnErrorOnFailure(WriteToPacketBuffer(queryMsg, mPendingMsgHandle));
     293              : 
     294           12 :     mAwaitingResponse = true;
     295           12 :     mLastQueryNum     = mNextQueryNum++;
     296              : 
     297           12 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     298              : 
     299           12 :     return CHIP_NO_ERROR;
     300           12 : }
     301              : 
     302            0 : CHIP_ERROR TransferSession::PrepareBlockQueryWithSkip(const uint64_t & bytesToSkip)
     303              : {
     304            0 :     const MessageType msgType = MessageType::BlockQueryWithSkip;
     305              : 
     306            0 :     VerifyOrReturnError(mState == TransferState::kTransferInProgress, CHIP_ERROR_INCORRECT_STATE);
     307            0 :     VerifyOrReturnError(mRole == TransferRole::kReceiver, CHIP_ERROR_INCORRECT_STATE);
     308            0 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     309            0 :     VerifyOrReturnError(!mAwaitingResponse, CHIP_ERROR_INCORRECT_STATE);
     310              : 
     311            0 :     BlockQueryWithSkip queryMsg;
     312            0 :     queryMsg.BlockCounter = mNextQueryNum;
     313            0 :     queryMsg.BytesToSkip  = bytesToSkip;
     314              : 
     315            0 :     ReturnErrorOnFailure(WriteToPacketBuffer(queryMsg, mPendingMsgHandle));
     316              : 
     317            0 :     mAwaitingResponse = true;
     318            0 :     mLastQueryNum     = mNextQueryNum++;
     319              : 
     320            0 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     321              : 
     322            0 :     return CHIP_NO_ERROR;
     323            0 : }
     324              : 
     325           18 : CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData)
     326              : {
     327           18 :     VerifyOrReturnError(mState == TransferState::kTransferInProgress, CHIP_ERROR_INCORRECT_STATE);
     328           18 :     VerifyOrReturnError(mRole == TransferRole::kSender, CHIP_ERROR_INCORRECT_STATE);
     329           18 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     330           18 :     VerifyOrReturnError(!mAwaitingResponse, CHIP_ERROR_INCORRECT_STATE);
     331              : 
     332              :     // Verify non-zero data is provided and is no longer than MaxBlockSize (BlockEOF may contain 0 length data)
     333           17 :     VerifyOrReturnError((inData.Data != nullptr) && (inData.Length <= mTransferMaxBlockSize), CHIP_ERROR_INVALID_ARGUMENT);
     334              : 
     335           17 :     DataBlock blockMsg;
     336           17 :     blockMsg.BlockCounter = mNextBlockNum;
     337           17 :     blockMsg.Data         = inData.Data;
     338           17 :     blockMsg.DataLength   = inData.Length;
     339              : 
     340           17 :     ReturnErrorOnFailure(WriteToPacketBuffer(blockMsg, mPendingMsgHandle));
     341              : 
     342           17 :     const MessageType msgType = inData.IsEof ? MessageType::BlockEOF : MessageType::Block;
     343              : 
     344           17 :     if (msgType == MessageType::BlockEOF)
     345              :     {
     346              : #if CHIP_AUTOMATION_LOGGING
     347            2 :         ChipLogAutomation("Sending BDX Message");
     348            2 :         blockMsg.LogMessage(msgType);
     349              : #endif // CHIP_AUTOMATION_LOGGING
     350            2 :         mState = TransferState::kAwaitingEOFAck;
     351              :     }
     352              : 
     353           17 :     mAwaitingResponse = true;
     354           17 :     mLastBlockNum     = mNextBlockNum++;
     355              : 
     356           17 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     357              : 
     358           17 :     return CHIP_NO_ERROR;
     359           17 : }
     360              : 
     361            7 : CHIP_ERROR TransferSession::PrepareBlockAck()
     362              : {
     363            7 :     VerifyOrReturnError(mRole == TransferRole::kReceiver, CHIP_ERROR_INCORRECT_STATE);
     364            7 :     VerifyOrReturnError((mState == TransferState::kTransferInProgress) || (mState == TransferState::kReceivedEOF),
     365              :                         CHIP_ERROR_INCORRECT_STATE);
     366            7 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     367              : 
     368            7 :     CounterMessage ackMsg;
     369            7 :     ackMsg.BlockCounter       = mLastBlockNum;
     370            7 :     const MessageType msgType = (mState == TransferState::kReceivedEOF) ? MessageType::BlockAckEOF : MessageType::BlockAck;
     371              : 
     372            7 :     ReturnErrorOnFailure(WriteToPacketBuffer(ackMsg, mPendingMsgHandle));
     373              : 
     374            7 :     if (mState == TransferState::kTransferInProgress)
     375              :     {
     376            5 :         if (mControlMode == TransferControlFlags::kSenderDrive)
     377              :         {
     378              :             // In Sender Drive, a BlockAck is implied to also be a query for the next Block, so expect to receive a Block
     379              :             // message.
     380            4 :             mLastQueryNum     = ackMsg.BlockCounter + 1;
     381            4 :             mAwaitingResponse = true;
     382              :         }
     383              :     }
     384            2 :     else if (mState == TransferState::kReceivedEOF)
     385              :     {
     386              : #if CHIP_AUTOMATION_LOGGING
     387            2 :         ChipLogAutomation("Sending BDX Message");
     388            2 :         ackMsg.LogMessage(msgType);
     389              : #endif // CHIP_AUTOMATION_LOGGING
     390            2 :         mState            = TransferState::kTransferDone;
     391            2 :         mAwaitingResponse = false;
     392              :     }
     393              : 
     394            7 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     395              : 
     396            7 :     return CHIP_NO_ERROR;
     397            7 : }
     398              : 
     399            1 : CHIP_ERROR TransferSession::AbortTransfer(StatusCode reason)
     400              : {
     401            1 :     VerifyOrReturnError((mState != TransferState::kUnitialized) && (mState != TransferState::kTransferDone) &&
     402              :                             (mState != TransferState::kErrorState),
     403              :                         CHIP_ERROR_INCORRECT_STATE);
     404              : 
     405            1 :     PrepareStatusReport(reason);
     406              : 
     407            1 :     return CHIP_NO_ERROR;
     408              : }
     409              : 
     410            5 : void TransferSession::Reset()
     411              : {
     412            5 :     mPendingOutput = OutputEventType::kNone;
     413            5 :     mState         = TransferState::kUnitialized;
     414            5 :     mSuppportedXferOpts.ClearAll();
     415            5 :     mTransferVersion       = 0;
     416            5 :     mMaxSupportedBlockSize = 0;
     417            5 :     mStartOffset           = 0;
     418            5 :     mTransferLength        = 0;
     419            5 :     mTransferMaxBlockSize  = 0;
     420              : 
     421            5 :     mPendingMsgHandle = nullptr;
     422              : 
     423            5 :     mNumBytesProcessed = 0;
     424            5 :     mLastBlockNum      = 0;
     425            5 :     mNextBlockNum      = 0;
     426            5 :     mLastQueryNum      = 0;
     427            5 :     mNextQueryNum      = 0;
     428              : 
     429            5 :     mTimeout                = System::Clock::kZero;
     430            5 :     mTimeoutStartTime       = System::Clock::kZero;
     431            5 :     mShouldInitTimeoutStart = true;
     432            5 :     mAwaitingResponse       = false;
     433            5 : }
     434              : 
     435           57 : CHIP_ERROR TransferSession::HandleMessageReceived(const PayloadHeader & payloadHeader, System::PacketBufferHandle msg,
     436              :                                                   System::Clock::Timestamp curTime)
     437              : {
     438           57 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     439              : 
     440           57 :     if (payloadHeader.HasProtocol(Protocols::BDX::Id))
     441              :     {
     442           54 :         ReturnErrorOnFailure(HandleBdxMessage(payloadHeader, std::move(msg)));
     443              : 
     444           54 :         mTimeoutStartTime = curTime;
     445              :     }
     446            3 :     else if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
     447              :     {
     448            3 :         ReturnErrorOnFailure(HandleStatusReportMessage(payloadHeader, std::move(msg)));
     449              :     }
     450              :     else
     451              :     {
     452            0 :         return CHIP_ERROR_INVALID_MESSAGE_TYPE;
     453              :     }
     454              : 
     455           57 :     return CHIP_NO_ERROR;
     456              : }
     457              : 
     458              : // Return CHIP_ERROR only if there was a problem decoding the message. Otherwise, call PrepareStatusReport().
     459           54 : CHIP_ERROR TransferSession::HandleBdxMessage(const PayloadHeader & header, System::PacketBufferHandle msg)
     460              : {
     461           54 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     462           54 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     463              : 
     464           54 :     const MessageType msgType = static_cast<MessageType>(header.GetMessageType());
     465              : 
     466           54 :     switch (msgType)
     467              :     {
     468           11 :     case MessageType::SendInit:
     469              :     case MessageType::ReceiveInit:
     470              : #if CHIP_AUTOMATION_LOGGING
     471           11 :         ChipLogAutomation("Handling received BDX Message");
     472              : #endif // CHIP_AUTOMATION_LOGGING
     473           11 :         HandleTransferInit(msgType, std::move(msg));
     474           11 :         break;
     475            3 :     case MessageType::SendAccept:
     476              : #if CHIP_AUTOMATION_LOGGING
     477            3 :         ChipLogAutomation("Handling received BDX Message");
     478              : #endif // CHIP_AUTOMATION_LOGGING
     479            3 :         HandleSendAccept(std::move(msg));
     480            3 :         break;
     481            3 :     case MessageType::ReceiveAccept:
     482              : #if CHIP_AUTOMATION_LOGGING
     483            3 :         ChipLogAutomation("Handling received BDX Message");
     484              : #endif // CHIP_AUTOMATION_LOGGING
     485            3 :         HandleReceiveAccept(std::move(msg));
     486            3 :         break;
     487           12 :     case MessageType::BlockQuery:
     488           12 :         HandleBlockQuery(std::move(msg));
     489           12 :         break;
     490            0 :     case MessageType::BlockQueryWithSkip:
     491            0 :         HandleBlockQueryWithSkip(std::move(msg));
     492            0 :         break;
     493           16 :     case MessageType::Block:
     494           16 :         HandleBlock(std::move(msg));
     495           16 :         break;
     496            2 :     case MessageType::BlockEOF:
     497            2 :         HandleBlockEOF(std::move(msg));
     498            2 :         break;
     499            5 :     case MessageType::BlockAck:
     500            5 :         HandleBlockAck(std::move(msg));
     501            5 :         break;
     502            2 :     case MessageType::BlockAckEOF:
     503            2 :         HandleBlockAckEOF(std::move(msg));
     504            2 :         break;
     505            0 :     default:
     506            0 :         return CHIP_ERROR_INVALID_MESSAGE_TYPE;
     507              :     }
     508              : 
     509           54 :     return CHIP_NO_ERROR;
     510              : }
     511              : 
     512              : /**
     513              :  * @brief
     514              :  *   Parse a StatusReport message and prepare to emit an OutputEvent with the message data.
     515              :  *
     516              :  *   NOTE: BDX does not currently expect to ever use a "Success" general code, so it will be treated as an error along with any
     517              :  *         other code.
     518              :  */
     519            3 : CHIP_ERROR TransferSession::HandleStatusReportMessage(const PayloadHeader & header, System::PacketBufferHandle msg)
     520              : {
     521            3 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     522              : 
     523            3 :     mState            = TransferState::kErrorState;
     524            3 :     mAwaitingResponse = false;
     525              : 
     526            3 :     Protocols::SecureChannel::StatusReport report;
     527            3 :     ReturnErrorOnFailure(report.Parse(std::move(msg)));
     528            3 :     VerifyOrReturnError((report.GetProtocolId() == Protocols::BDX::Id), CHIP_ERROR_INVALID_MESSAGE_TYPE);
     529              : 
     530            3 :     mStatusReportData.statusCode = static_cast<StatusCode>(report.GetProtocolCode());
     531              : 
     532            3 :     mPendingOutput = OutputEventType::kStatusReceived;
     533              : 
     534            3 :     return CHIP_NO_ERROR;
     535            3 : }
     536              : 
     537           11 : void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
     538              : {
     539           11 :     VerifyOrReturn(mState == TransferState::kAwaitingInitMsg, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     540              : 
     541           11 :     if (mRole == TransferRole::kSender)
     542              :     {
     543            5 :         VerifyOrReturn(msgType == MessageType::ReceiveInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     544              :     }
     545              :     else
     546              :     {
     547            6 :         VerifyOrReturn(msgType == MessageType::SendInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     548              :     }
     549              : 
     550           11 :     TransferInit transferInit;
     551           11 :     const CHIP_ERROR err = transferInit.Parse(msgData.Retain());
     552           22 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     553              : 
     554           11 :     ResolveTransferControlOptions(transferInit.TransferCtlOptions);
     555           11 :     mTransferVersion      = std::min(kBdxVersion, transferInit.Version);
     556           11 :     mTransferMaxBlockSize = std::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
     557              : 
     558              :     // Accept for now, they may be changed or rejected by the peer if this is a ReceiveInit
     559           11 :     mStartOffset    = transferInit.StartOffset;
     560           11 :     mTransferLength = transferInit.MaxLength;
     561              : 
     562              :     // Store the Request data to share with the caller for verification
     563           11 :     mTransferRequestData.TransferCtlFlags = transferInit.TransferCtlOptions;
     564           11 :     mTransferRequestData.MaxBlockSize     = transferInit.MaxBlockSize;
     565           11 :     mTransferRequestData.StartOffset      = transferInit.StartOffset;
     566           11 :     mTransferRequestData.Length           = transferInit.MaxLength;
     567           11 :     mTransferRequestData.FileDesignator   = transferInit.FileDesignator;
     568           11 :     mTransferRequestData.FileDesLength    = transferInit.FileDesLength;
     569           11 :     mTransferRequestData.Metadata         = transferInit.Metadata;
     570           11 :     mTransferRequestData.MetadataLength   = transferInit.MetadataLength;
     571              : 
     572           11 :     mPendingMsgHandle = std::move(msgData);
     573           11 :     mPendingOutput    = OutputEventType::kInitReceived;
     574              : 
     575           11 :     mState = TransferState::kNegotiateTransferParams;
     576              : 
     577              : #if CHIP_AUTOMATION_LOGGING
     578           11 :     transferInit.LogMessage(msgType);
     579              : #endif // CHIP_AUTOMATION_LOGGING
     580           11 : }
     581              : 
     582            3 : void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
     583              : {
     584            4 :     VerifyOrReturn(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     585            3 :     VerifyOrReturn(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     586              : 
     587            3 :     ReceiveAccept rcvAcceptMsg;
     588            3 :     const CHIP_ERROR err = rcvAcceptMsg.Parse(msgData.Retain());
     589            6 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     590              : 
     591              :     // Verify that Accept parameters are compatible with the original proposed parameters
     592            3 :     ReturnOnFailure(VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags));
     593              : 
     594              :     // Per the BDX spec, the chosen Max Block Size SHALL be <= the proposed Max Block Size. Validate the received value
     595              :     // rather than adopting it unconditionally.
     596            3 :     VerifyOrReturn(rcvAcceptMsg.MaxBlockSize <= mMaxSupportedBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
     597              : 
     598            2 :     mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
     599            2 :     mStartOffset          = rcvAcceptMsg.StartOffset;
     600            2 :     mTransferLength       = rcvAcceptMsg.Length;
     601              : 
     602              :     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
     603              :     // message
     604            2 :     mTransferAcceptData.ControlMode    = mControlMode;
     605            2 :     mTransferAcceptData.MaxBlockSize   = rcvAcceptMsg.MaxBlockSize;
     606            2 :     mTransferAcceptData.StartOffset    = rcvAcceptMsg.StartOffset;
     607            2 :     mTransferAcceptData.Length         = rcvAcceptMsg.Length;
     608            2 :     mTransferAcceptData.Metadata       = rcvAcceptMsg.Metadata;
     609            2 :     mTransferAcceptData.MetadataLength = rcvAcceptMsg.MetadataLength;
     610              : 
     611            2 :     mPendingMsgHandle = std::move(msgData);
     612            2 :     mPendingOutput    = OutputEventType::kAcceptReceived;
     613              : 
     614            2 :     mAwaitingResponse = (mControlMode == TransferControlFlags::kSenderDrive);
     615            2 :     mState            = TransferState::kTransferInProgress;
     616              : 
     617              : #if CHIP_AUTOMATION_LOGGING
     618            2 :     rcvAcceptMsg.LogMessage(MessageType::ReceiveAccept);
     619              : #endif // CHIP_AUTOMATION_LOGGING
     620            3 : }
     621              : 
     622            3 : void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
     623              : {
     624            4 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     625            3 :     VerifyOrReturn(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     626              : 
     627            3 :     SendAccept sendAcceptMsg;
     628            3 :     const CHIP_ERROR err = sendAcceptMsg.Parse(msgData.Retain());
     629            6 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     630              : 
     631              :     // Verify that Accept parameters are compatible with the original proposed parameters
     632            3 :     ReturnOnFailure(VerifyProposedMode(sendAcceptMsg.TransferCtlFlags));
     633              : 
     634              :     // Per the BDX spec, the chosen Max Block Size SHALL be <= the proposed Max Block Size. Validate the received value here too.
     635            3 :     VerifyOrReturn(sendAcceptMsg.MaxBlockSize <= mMaxSupportedBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
     636              : 
     637              :     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
     638              :     // message
     639            2 :     mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
     640              : 
     641            2 :     mTransferAcceptData.ControlMode    = mControlMode;
     642            2 :     mTransferAcceptData.MaxBlockSize   = sendAcceptMsg.MaxBlockSize;
     643            2 :     mTransferAcceptData.StartOffset    = mStartOffset;    // Not included in SendAccept msg, so use member
     644            2 :     mTransferAcceptData.Length         = mTransferLength; // Not included in SendAccept msg, so use member
     645            2 :     mTransferAcceptData.Metadata       = sendAcceptMsg.Metadata;
     646            2 :     mTransferAcceptData.MetadataLength = sendAcceptMsg.MetadataLength;
     647              : 
     648            2 :     mPendingMsgHandle = std::move(msgData);
     649            2 :     mPendingOutput    = OutputEventType::kAcceptReceived;
     650              : 
     651            2 :     mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
     652            2 :     mState            = TransferState::kTransferInProgress;
     653              : 
     654              : #if CHIP_AUTOMATION_LOGGING
     655            2 :     sendAcceptMsg.LogMessage(MessageType::SendAccept);
     656              : #endif // CHIP_AUTOMATION_LOGGING
     657            3 : }
     658              : 
     659           12 : void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
     660              : {
     661           12 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     662           12 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     663           12 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     664              : 
     665           12 :     BlockQuery query;
     666           12 :     const CHIP_ERROR err = query.Parse(std::move(msgData));
     667           24 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     668              : 
     669           12 :     VerifyOrReturn(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     670              : 
     671           12 :     mPendingOutput = OutputEventType::kQueryReceived;
     672              : 
     673           12 :     mAwaitingResponse = false;
     674           12 :     mLastQueryNum     = query.BlockCounter;
     675           12 : }
     676              : 
     677            0 : void TransferSession::HandleBlockQueryWithSkip(System::PacketBufferHandle msgData)
     678              : {
     679            0 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     680            0 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     681            0 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     682              : 
     683            0 :     BlockQueryWithSkip query;
     684            0 :     const CHIP_ERROR err = query.Parse(std::move(msgData));
     685            0 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     686              : 
     687            0 :     VerifyOrReturn(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     688              : 
     689            0 :     mPendingOutput = OutputEventType::kQueryWithSkipReceived;
     690              : 
     691            0 :     mAwaitingResponse        = false;
     692            0 :     mLastQueryNum            = query.BlockCounter;
     693            0 :     mBytesToSkip.BytesToSkip = query.BytesToSkip;
     694            0 : }
     695              : 
     696           16 : void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
     697              : {
     698           17 :     VerifyOrReturn(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     699           16 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     700           16 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     701              : 
     702           16 :     Block blockMsg;
     703           16 :     const CHIP_ERROR err = blockMsg.Parse(msgData.Retain());
     704           32 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     705              : 
     706           16 :     VerifyOrReturn(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     707           15 :     VerifyOrReturn((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
     708              :                    PrepareStatusReport(StatusCode::kBadMessageContents));
     709              : 
     710           15 :     if (IsTransferLengthDefinite())
     711              :     {
     712            2 :         VerifyOrReturn(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength,
     713              :                        PrepareStatusReport(StatusCode::kLengthMismatch));
     714              :     }
     715              : 
     716           15 :     mBlockEventData.Data         = blockMsg.Data;
     717           15 :     mBlockEventData.Length       = blockMsg.DataLength;
     718           15 :     mBlockEventData.IsEof        = false;
     719           15 :     mBlockEventData.BlockCounter = blockMsg.BlockCounter;
     720              : 
     721           15 :     mPendingMsgHandle = std::move(msgData);
     722           15 :     mPendingOutput    = OutputEventType::kBlockReceived;
     723              : 
     724           15 :     mNumBytesProcessed += blockMsg.DataLength;
     725           15 :     mLastBlockNum = blockMsg.BlockCounter;
     726              : 
     727           15 :     mAwaitingResponse = false;
     728           16 : }
     729              : 
     730            2 : void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
     731              : {
     732            2 :     VerifyOrReturn(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     733            2 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     734            2 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     735              : 
     736            2 :     BlockEOF blockEOFMsg;
     737            2 :     const CHIP_ERROR err = blockEOFMsg.Parse(msgData.Retain());
     738            4 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     739              : 
     740            2 :     VerifyOrReturn(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     741            2 :     VerifyOrReturn(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
     742              : 
     743            2 :     mBlockEventData.Data         = blockEOFMsg.Data;
     744            2 :     mBlockEventData.Length       = blockEOFMsg.DataLength;
     745            2 :     mBlockEventData.IsEof        = true;
     746            2 :     mBlockEventData.BlockCounter = blockEOFMsg.BlockCounter;
     747              : 
     748            2 :     mPendingMsgHandle = std::move(msgData);
     749            2 :     mPendingOutput    = OutputEventType::kBlockReceived;
     750              : 
     751            2 :     mNumBytesProcessed += blockEOFMsg.DataLength;
     752            2 :     mLastBlockNum = blockEOFMsg.BlockCounter;
     753              : 
     754            2 :     mAwaitingResponse = false;
     755            2 :     mState            = TransferState::kReceivedEOF;
     756              : 
     757              : #if CHIP_AUTOMATION_LOGGING
     758            2 :     blockEOFMsg.LogMessage(MessageType::BlockEOF);
     759              : #endif // CHIP_AUTOMATION_LOGGING
     760            2 : }
     761              : 
     762            5 : void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
     763              : {
     764            5 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     765            5 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     766            5 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     767              : 
     768            5 :     BlockAck ackMsg;
     769            5 :     const CHIP_ERROR err = ackMsg.Parse(std::move(msgData));
     770           10 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     771            5 :     VerifyOrReturn(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     772              : 
     773            5 :     mPendingOutput = OutputEventType::kAckReceived;
     774              : 
     775              :     // In Receiver Drive, the Receiver can send a BlockAck to indicate receipt of the message and reset the timeout.
     776              :     // In this case, the Sender should wait to receive a BlockQuery next.
     777            5 :     mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
     778            5 : }
     779              : 
     780            2 : void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
     781              : {
     782            2 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     783            2 :     VerifyOrReturn(mState == TransferState::kAwaitingEOFAck, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     784            2 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     785              : 
     786            2 :     BlockAckEOF ackMsg;
     787            2 :     const CHIP_ERROR err = ackMsg.Parse(std::move(msgData));
     788            4 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     789            2 :     VerifyOrReturn(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     790              : 
     791            2 :     mPendingOutput = OutputEventType::kAckEOFReceived;
     792              : 
     793            2 :     mAwaitingResponse = false;
     794              : 
     795            2 :     mState = TransferState::kTransferDone;
     796              : 
     797              : #if CHIP_AUTOMATION_LOGGING
     798            2 :     ackMsg.LogMessage(MessageType::BlockAckEOF);
     799              : #endif // CHIP_AUTOMATION_LOGGING
     800            2 : }
     801              : 
     802           11 : void TransferSession::ResolveTransferControlOptions(const BitFlags<TransferControlFlags> & proposed)
     803              : {
     804              :     // Must specify at least one synchronous option
     805              :     //
     806           11 :     if (!proposed.HasAny(TransferControlFlags::kSenderDrive, TransferControlFlags::kReceiverDrive))
     807              :     {
     808            0 :         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
     809            0 :         return;
     810              :     }
     811              : 
     812              :     // Ensure there are options supported by both nodes. Async gets priority.
     813              :     // If there is only one common option, choose that one. Otherwise the application must pick.
     814           11 :     const BitFlags<TransferControlFlags> commonOpts(proposed & mSuppportedXferOpts);
     815           11 :     if (!commonOpts.HasAny())
     816              :     {
     817            0 :         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
     818              :     }
     819           11 :     else if (commonOpts.HasOnly(TransferControlFlags::kAsync))
     820              :     {
     821            0 :         mControlMode = TransferControlFlags::kAsync;
     822              :     }
     823           11 :     else if (commonOpts.HasOnly(TransferControlFlags::kReceiverDrive))
     824              :     {
     825            5 :         mControlMode = TransferControlFlags::kReceiverDrive;
     826              :     }
     827            6 :     else if (commonOpts.HasOnly(TransferControlFlags::kSenderDrive))
     828              :     {
     829            6 :         mControlMode = TransferControlFlags::kSenderDrive;
     830              :     }
     831              : }
     832              : 
     833            6 : CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<TransferControlFlags> & proposed)
     834              : {
     835              :     TransferControlFlags mode;
     836              : 
     837              :     // Must specify only one mode in Accept messages
     838            6 :     if (proposed.HasOnly(TransferControlFlags::kAsync))
     839              :     {
     840            0 :         mode = TransferControlFlags::kAsync;
     841              :     }
     842            6 :     else if (proposed.HasOnly(TransferControlFlags::kReceiverDrive))
     843              :     {
     844            3 :         mode = TransferControlFlags::kReceiverDrive;
     845              :     }
     846            3 :     else if (proposed.HasOnly(TransferControlFlags::kSenderDrive))
     847              :     {
     848            3 :         mode = TransferControlFlags::kSenderDrive;
     849              :     }
     850              :     else
     851              :     {
     852            0 :         PrepareStatusReport(StatusCode::kBadMessageContents);
     853            0 :         return CHIP_ERROR_INTERNAL;
     854              :     }
     855              : 
     856              :     // Verify the proposed mode is supported by this instance
     857            6 :     if (mSuppportedXferOpts.Has(mode))
     858              :     {
     859            6 :         mControlMode = mode;
     860              :     }
     861              :     else
     862              :     {
     863            0 :         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
     864            0 :         return CHIP_ERROR_INTERNAL;
     865              :     }
     866              : 
     867            6 :     return CHIP_NO_ERROR;
     868              : }
     869              : 
     870            5 : void TransferSession::PrepareStatusReport(StatusCode code)
     871              : {
     872            5 :     mStatusReportData.statusCode = code;
     873              : 
     874              :     Protocols::SecureChannel::StatusReport report(Protocols::SecureChannel::GeneralStatusCode::kFailure, Protocols::BDX::Id,
     875            5 :                                                   to_underlying(code));
     876            5 :     size_t msgSize = report.Size();
     877            5 :     Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgSize), msgSize);
     878            5 :     VerifyOrExit(!bbuf.IsNull(), mPendingOutput = OutputEventType::kInternalError);
     879              : 
     880            5 :     report.WriteToBuffer(bbuf);
     881            5 :     mPendingMsgHandle = bbuf.Finalize();
     882            5 :     if (mPendingMsgHandle.IsNull())
     883              :     {
     884            0 :         ChipLogError(BDX, "%s: error preparing message: %" CHIP_ERROR_FORMAT, __FUNCTION__, CHIP_ERROR_NO_MEMORY.Format());
     885            0 :         mPendingOutput = OutputEventType::kInternalError;
     886              :     }
     887              :     else
     888              :     {
     889            5 :         PrepareOutgoingMessageEvent(Protocols::SecureChannel::MsgType::StatusReport, mPendingOutput, mMsgTypeData);
     890              :     }
     891              : 
     892            5 : exit:
     893            5 :     mState            = TransferState::kErrorState;
     894            5 :     mAwaitingResponse = false; // Prevent triggering timeout
     895            5 : }
     896              : 
     897           15 : bool TransferSession::IsTransferLengthDefinite() const
     898              : {
     899           15 :     return (mTransferLength > 0);
     900              : }
     901              : 
     902            0 : const char * TransferSession::OutputEvent::ToString(OutputEventType outputEventType)
     903              : {
     904            0 :     return TypeToString(outputEventType);
     905              : }
     906              : 
     907            0 : const char * TransferSession::OutputEvent::TypeToString(OutputEventType outputEventType)
     908              : {
     909            0 :     switch (outputEventType)
     910              :     {
     911            0 :     case OutputEventType::kNone:
     912            0 :         return "None";
     913            0 :     case OutputEventType::kMsgToSend:
     914            0 :         return "MsgToSend";
     915            0 :     case OutputEventType::kInitReceived:
     916            0 :         return "InitReceived";
     917            0 :     case OutputEventType::kAcceptReceived:
     918            0 :         return "AcceptReceived";
     919            0 :     case OutputEventType::kBlockReceived:
     920            0 :         return "BlockReceived";
     921            0 :     case OutputEventType::kQueryReceived:
     922            0 :         return "QueryReceived";
     923            0 :     case OutputEventType::kQueryWithSkipReceived:
     924            0 :         return "QueryWithSkipReceived";
     925            0 :     case OutputEventType::kAckReceived:
     926            0 :         return "AckReceived";
     927            0 :     case OutputEventType::kAckEOFReceived:
     928            0 :         return "AckEOFReceived";
     929            0 :     case OutputEventType::kStatusReceived:
     930            0 :         return "StatusReceived";
     931            0 :     case OutputEventType::kInternalError:
     932            0 :         return "InternalError";
     933            0 :     case OutputEventType::kTransferTimeout:
     934            0 :         return "TransferTimeout";
     935            0 :     default:
     936            0 :         return "Unknown";
     937              :     }
     938              : }
     939              : 
     940           10 : TransferSession::OutputEvent TransferSession::OutputEvent::TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg)
     941              : {
     942           10 :     OutputEvent event(OutputEventType::kInitReceived);
     943           10 :     event.MsgData          = std::move(msg);
     944           10 :     event.transferInitData = data;
     945           10 :     return event;
     946              : }
     947              : 
     948              : /**
     949              :  * @brief
     950              :  *   Convenience method for constructing an OutputEvent with TransferAcceptData that does not contain Metadata
     951              :  */
     952            4 : TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data)
     953              : {
     954            4 :     OutputEvent event(OutputEventType::kAcceptReceived);
     955            4 :     event.transferAcceptData = data;
     956            4 :     return event;
     957              : }
     958              : /**
     959              :  * @brief
     960              :  *   Convenience method for constructing an OutputEvent with TransferAcceptData that contains Metadata
     961              :  */
     962            4 : TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data,
     963              :                                                                                System::PacketBufferHandle msg)
     964              : {
     965            4 :     OutputEvent event = TransferAcceptEvent(data);
     966            4 :     event.MsgData     = std::move(msg);
     967            4 :     return event;
     968              : }
     969              : 
     970           17 : TransferSession::OutputEvent TransferSession::OutputEvent::BlockDataEvent(BlockData data, System::PacketBufferHandle msg)
     971              : {
     972           17 :     OutputEvent event(OutputEventType::kBlockReceived);
     973           17 :     event.MsgData   = std::move(msg);
     974           17 :     event.blockdata = data;
     975           17 :     return event;
     976              : }
     977              : 
     978              : /**
     979              :  * @brief
     980              :  *   Convenience method for constructing an event with kInternalError or kOutputStatusReceived
     981              :  */
     982           14 : TransferSession::OutputEvent TransferSession::OutputEvent::StatusReportEvent(OutputEventType type, StatusReportData data)
     983              : {
     984           14 :     OutputEvent event(type);
     985           14 :     event.statusData = data;
     986           14 :     return event;
     987              : }
     988              : 
     989           59 : TransferSession::OutputEvent TransferSession::OutputEvent::MsgToSendEvent(MessageTypeData typeData, System::PacketBufferHandle msg)
     990              : {
     991           59 :     OutputEvent event(OutputEventType::kMsgToSend);
     992           59 :     event.MsgData     = std::move(msg);
     993           59 :     event.msgTypeData = typeData;
     994           59 :     return event;
     995              : }
     996              : 
     997            0 : TransferSession::OutputEvent TransferSession::OutputEvent::QueryWithSkipEvent(TransferSkipData bytesToSkip)
     998              : {
     999            0 :     OutputEvent event(OutputEventType::kQueryWithSkipReceived);
    1000            0 :     event.bytesToSkip = bytesToSkip;
    1001            0 :     return event;
    1002              : }
    1003              : 
    1004              : } // namespace bdx
    1005              : } // namespace chip
        

Generated by: LCOV version 2.0-1