Matter SDK Coverage Report
Current view: top level - protocols/bdx - BdxTransferSession.cpp (source / functions) Coverage Total Hit
Test: SHA:f84fe08d06f240e801b5d923f8a938a9938ca110 Lines: 79.3 % 571 453
Test Date: 2025-02-22 08:08:07 Functions: 80.5 % 41 33

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

Generated by: LCOV version 2.0-1