LCOV - code coverage report
Current view: top level - protocols/bdx - BdxTransferSession.cpp (source / functions) Hit Total Coverage
Test: lcov_final.info Lines: 450 566 79.5 %
Date: 2024-02-15 08:20:41 Functions: 32 38 84.2 %

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

Generated by: LCOV version 1.14