Matter SDK Coverage Report
Current view: top level - protocols/bdx - BdxTransferSession.cpp (source / functions) Coverage Total Hit
Test: SHA:b879ecb8e99e175eea0a293a888bda853da2b19c Lines: 79.0 % 577 456
Test Date: 2025-01-17 19:00:11 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              : #if CHIP_AUTOMATION_LOGGING
     295           12 :     ChipLogAutomation("Sending BDX Message");
     296           12 :     queryMsg.LogMessage(msgType);
     297              : #endif // CHIP_AUTOMATION_LOGGING
     298              : 
     299           12 :     mAwaitingResponse = true;
     300           12 :     mLastQueryNum     = mNextQueryNum++;
     301              : 
     302           12 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     303              : 
     304           12 :     return CHIP_NO_ERROR;
     305           12 : }
     306              : 
     307            0 : CHIP_ERROR TransferSession::PrepareBlockQueryWithSkip(const uint64_t & bytesToSkip)
     308              : {
     309            0 :     const MessageType msgType = MessageType::BlockQueryWithSkip;
     310              : 
     311            0 :     VerifyOrReturnError(mState == TransferState::kTransferInProgress, CHIP_ERROR_INCORRECT_STATE);
     312            0 :     VerifyOrReturnError(mRole == TransferRole::kReceiver, CHIP_ERROR_INCORRECT_STATE);
     313            0 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     314            0 :     VerifyOrReturnError(!mAwaitingResponse, CHIP_ERROR_INCORRECT_STATE);
     315              : 
     316            0 :     BlockQueryWithSkip queryMsg;
     317            0 :     queryMsg.BlockCounter = mNextQueryNum;
     318            0 :     queryMsg.BytesToSkip  = bytesToSkip;
     319              : 
     320            0 :     ReturnErrorOnFailure(WriteToPacketBuffer(queryMsg, mPendingMsgHandle));
     321              : 
     322              : #if CHIP_AUTOMATION_LOGGING
     323            0 :     ChipLogAutomation("Sending BDX Message");
     324            0 :     queryMsg.LogMessage(msgType);
     325              : #endif // CHIP_AUTOMATION_LOGGING
     326              : 
     327            0 :     mAwaitingResponse = true;
     328            0 :     mLastQueryNum     = mNextQueryNum++;
     329              : 
     330            0 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     331              : 
     332            0 :     return CHIP_NO_ERROR;
     333            0 : }
     334              : 
     335           16 : CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData)
     336              : {
     337           16 :     VerifyOrReturnError(mState == TransferState::kTransferInProgress, CHIP_ERROR_INCORRECT_STATE);
     338           16 :     VerifyOrReturnError(mRole == TransferRole::kSender, CHIP_ERROR_INCORRECT_STATE);
     339           16 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     340           16 :     VerifyOrReturnError(!mAwaitingResponse, CHIP_ERROR_INCORRECT_STATE);
     341              : 
     342              :     // Verify non-zero data is provided and is no longer than MaxBlockSize (BlockEOF may contain 0 length data)
     343           15 :     VerifyOrReturnError((inData.Data != nullptr) && (inData.Length <= mTransferMaxBlockSize), CHIP_ERROR_INVALID_ARGUMENT);
     344              : 
     345           15 :     DataBlock blockMsg;
     346           15 :     blockMsg.BlockCounter = mNextBlockNum;
     347           15 :     blockMsg.Data         = inData.Data;
     348           15 :     blockMsg.DataLength   = inData.Length;
     349              : 
     350           15 :     ReturnErrorOnFailure(WriteToPacketBuffer(blockMsg, mPendingMsgHandle));
     351              : 
     352           15 :     const MessageType msgType = inData.IsEof ? MessageType::BlockEOF : MessageType::Block;
     353              : 
     354              : #if CHIP_AUTOMATION_LOGGING
     355           15 :     ChipLogAutomation("Sending BDX Message");
     356           15 :     blockMsg.LogMessage(msgType);
     357              : #endif // CHIP_AUTOMATION_LOGGING
     358              : 
     359           15 :     if (msgType == MessageType::BlockEOF)
     360              :     {
     361            2 :         mState = TransferState::kAwaitingEOFAck;
     362              :     }
     363              : 
     364           15 :     mAwaitingResponse = true;
     365           15 :     mLastBlockNum     = mNextBlockNum++;
     366              : 
     367           15 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     368              : 
     369           15 :     return CHIP_NO_ERROR;
     370           15 : }
     371              : 
     372            6 : CHIP_ERROR TransferSession::PrepareBlockAck()
     373              : {
     374            6 :     VerifyOrReturnError(mRole == TransferRole::kReceiver, CHIP_ERROR_INCORRECT_STATE);
     375            6 :     VerifyOrReturnError((mState == TransferState::kTransferInProgress) || (mState == TransferState::kReceivedEOF),
     376              :                         CHIP_ERROR_INCORRECT_STATE);
     377            6 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     378              : 
     379            6 :     CounterMessage ackMsg;
     380            6 :     ackMsg.BlockCounter       = mLastBlockNum;
     381            6 :     const MessageType msgType = (mState == TransferState::kReceivedEOF) ? MessageType::BlockAckEOF : MessageType::BlockAck;
     382              : 
     383            6 :     ReturnErrorOnFailure(WriteToPacketBuffer(ackMsg, mPendingMsgHandle));
     384              : 
     385              : #if CHIP_AUTOMATION_LOGGING
     386            6 :     ChipLogAutomation("Sending BDX Message");
     387            6 :     ackMsg.LogMessage(msgType);
     388              : #endif // CHIP_AUTOMATION_LOGGING
     389              : 
     390            6 :     if (mState == TransferState::kTransferInProgress)
     391              :     {
     392            4 :         if (mControlMode == TransferControlFlags::kSenderDrive)
     393              :         {
     394              :             // In Sender Drive, a BlockAck is implied to also be a query for the next Block, so expect to receive a Block
     395              :             // message.
     396            3 :             mLastQueryNum     = ackMsg.BlockCounter + 1;
     397            3 :             mAwaitingResponse = true;
     398              :         }
     399              :     }
     400            2 :     else if (mState == TransferState::kReceivedEOF)
     401              :     {
     402            2 :         mState            = TransferState::kTransferDone;
     403            2 :         mAwaitingResponse = false;
     404              :     }
     405              : 
     406            6 :     PrepareOutgoingMessageEvent(msgType, mPendingOutput, mMsgTypeData);
     407              : 
     408            6 :     return CHIP_NO_ERROR;
     409            6 : }
     410              : 
     411            0 : CHIP_ERROR TransferSession::AbortTransfer(StatusCode reason)
     412              : {
     413            0 :     VerifyOrReturnError((mState != TransferState::kUnitialized) && (mState != TransferState::kTransferDone) &&
     414              :                             (mState != TransferState::kErrorState),
     415              :                         CHIP_ERROR_INCORRECT_STATE);
     416              : 
     417            0 :     PrepareStatusReport(reason);
     418              : 
     419            0 :     return CHIP_NO_ERROR;
     420              : }
     421              : 
     422            0 : void TransferSession::Reset()
     423              : {
     424            0 :     mPendingOutput = OutputEventType::kNone;
     425            0 :     mState         = TransferState::kUnitialized;
     426            0 :     mSuppportedXferOpts.ClearAll();
     427            0 :     mTransferVersion       = 0;
     428            0 :     mMaxSupportedBlockSize = 0;
     429            0 :     mStartOffset           = 0;
     430            0 :     mTransferLength        = 0;
     431            0 :     mTransferMaxBlockSize  = 0;
     432              : 
     433            0 :     mPendingMsgHandle = nullptr;
     434              : 
     435            0 :     mNumBytesProcessed = 0;
     436            0 :     mLastBlockNum      = 0;
     437            0 :     mNextBlockNum      = 0;
     438            0 :     mLastQueryNum      = 0;
     439            0 :     mNextQueryNum      = 0;
     440              : 
     441            0 :     mTimeout                = System::Clock::kZero;
     442            0 :     mTimeoutStartTime       = System::Clock::kZero;
     443            0 :     mShouldInitTimeoutStart = true;
     444            0 :     mAwaitingResponse       = false;
     445            0 : }
     446              : 
     447           44 : CHIP_ERROR TransferSession::HandleMessageReceived(const PayloadHeader & payloadHeader, System::PacketBufferHandle msg,
     448              :                                                   System::Clock::Timestamp curTime)
     449              : {
     450           44 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     451              : 
     452           44 :     if (payloadHeader.HasProtocol(Protocols::BDX::Id))
     453              :     {
     454           42 :         ReturnErrorOnFailure(HandleBdxMessage(payloadHeader, std::move(msg)));
     455              : 
     456           42 :         mTimeoutStartTime = curTime;
     457              :     }
     458            2 :     else if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
     459              :     {
     460            2 :         ReturnErrorOnFailure(HandleStatusReportMessage(payloadHeader, std::move(msg)));
     461              :     }
     462              :     else
     463              :     {
     464            0 :         return CHIP_ERROR_INVALID_MESSAGE_TYPE;
     465              :     }
     466              : 
     467           44 :     return CHIP_NO_ERROR;
     468              : }
     469              : 
     470              : // Return CHIP_ERROR only if there was a problem decoding the message. Otherwise, call PrepareStatusReport().
     471           42 : CHIP_ERROR TransferSession::HandleBdxMessage(const PayloadHeader & header, System::PacketBufferHandle msg)
     472              : {
     473           42 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     474           42 :     VerifyOrReturnError(mPendingOutput == OutputEventType::kNone, CHIP_ERROR_INCORRECT_STATE);
     475              : 
     476           42 :     const MessageType msgType = static_cast<MessageType>(header.GetMessageType());
     477              : 
     478              : #if CHIP_AUTOMATION_LOGGING
     479           42 :     ChipLogAutomation("Handling received BDX Message");
     480              : #endif // CHIP_AUTOMATION_LOGGING
     481              : 
     482           42 :     switch (msgType)
     483              :     {
     484            5 :     case MessageType::SendInit:
     485              :     case MessageType::ReceiveInit:
     486            5 :         HandleTransferInit(msgType, std::move(msg));
     487            5 :         break;
     488            1 :     case MessageType::SendAccept:
     489            1 :         HandleSendAccept(std::move(msg));
     490            1 :         break;
     491            2 :     case MessageType::ReceiveAccept:
     492            2 :         HandleReceiveAccept(std::move(msg));
     493            2 :         break;
     494           12 :     case MessageType::BlockQuery:
     495           12 :         HandleBlockQuery(std::move(msg));
     496           12 :         break;
     497            0 :     case MessageType::BlockQueryWithSkip:
     498            0 :         HandleBlockQueryWithSkip(std::move(msg));
     499            0 :         break;
     500           14 :     case MessageType::Block:
     501           14 :         HandleBlock(std::move(msg));
     502           14 :         break;
     503            2 :     case MessageType::BlockEOF:
     504            2 :         HandleBlockEOF(std::move(msg));
     505            2 :         break;
     506            4 :     case MessageType::BlockAck:
     507            4 :         HandleBlockAck(std::move(msg));
     508            4 :         break;
     509            2 :     case MessageType::BlockAckEOF:
     510            2 :         HandleBlockAckEOF(std::move(msg));
     511            2 :         break;
     512            0 :     default:
     513            0 :         return CHIP_ERROR_INVALID_MESSAGE_TYPE;
     514              :     }
     515              : 
     516           42 :     return CHIP_NO_ERROR;
     517              : }
     518              : 
     519              : /**
     520              :  * @brief
     521              :  *   Parse a StatusReport message and prepare to emit an OutputEvent with the message data.
     522              :  *
     523              :  *   NOTE: BDX does not currently expect to ever use a "Success" general code, so it will be treated as an error along with any
     524              :  *         other code.
     525              :  */
     526            2 : CHIP_ERROR TransferSession::HandleStatusReportMessage(const PayloadHeader & header, System::PacketBufferHandle msg)
     527              : {
     528            2 :     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
     529              : 
     530            2 :     mState            = TransferState::kErrorState;
     531            2 :     mAwaitingResponse = false;
     532              : 
     533            2 :     Protocols::SecureChannel::StatusReport report;
     534            2 :     ReturnErrorOnFailure(report.Parse(std::move(msg)));
     535            2 :     VerifyOrReturnError((report.GetProtocolId() == Protocols::BDX::Id), CHIP_ERROR_INVALID_MESSAGE_TYPE);
     536              : 
     537            2 :     mStatusReportData.statusCode = static_cast<StatusCode>(report.GetProtocolCode());
     538              : 
     539            2 :     mPendingOutput = OutputEventType::kStatusReceived;
     540              : 
     541            2 :     return CHIP_NO_ERROR;
     542            2 : }
     543              : 
     544            5 : void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
     545              : {
     546            5 :     VerifyOrReturn(mState == TransferState::kAwaitingInitMsg, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     547              : 
     548            5 :     if (mRole == TransferRole::kSender)
     549              :     {
     550            4 :         VerifyOrReturn(msgType == MessageType::ReceiveInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     551              :     }
     552              :     else
     553              :     {
     554            1 :         VerifyOrReturn(msgType == MessageType::SendInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     555              :     }
     556              : 
     557            5 :     TransferInit transferInit;
     558            5 :     const CHIP_ERROR err = transferInit.Parse(msgData.Retain());
     559            5 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     560              : 
     561            5 :     ResolveTransferControlOptions(transferInit.TransferCtlOptions);
     562            5 :     mTransferVersion      = std::min(kBdxVersion, transferInit.Version);
     563            5 :     mTransferMaxBlockSize = std::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
     564              : 
     565              :     // Accept for now, they may be changed or rejected by the peer if this is a ReceiveInit
     566            5 :     mStartOffset    = transferInit.StartOffset;
     567            5 :     mTransferLength = transferInit.MaxLength;
     568              : 
     569              :     // Store the Request data to share with the caller for verification
     570            5 :     mTransferRequestData.TransferCtlFlags = transferInit.TransferCtlOptions;
     571            5 :     mTransferRequestData.MaxBlockSize     = transferInit.MaxBlockSize;
     572            5 :     mTransferRequestData.StartOffset      = transferInit.StartOffset;
     573            5 :     mTransferRequestData.Length           = transferInit.MaxLength;
     574            5 :     mTransferRequestData.FileDesignator   = transferInit.FileDesignator;
     575            5 :     mTransferRequestData.FileDesLength    = transferInit.FileDesLength;
     576            5 :     mTransferRequestData.Metadata         = transferInit.Metadata;
     577            5 :     mTransferRequestData.MetadataLength   = transferInit.MetadataLength;
     578              : 
     579            5 :     mPendingMsgHandle = std::move(msgData);
     580            5 :     mPendingOutput    = OutputEventType::kInitReceived;
     581              : 
     582            5 :     mState = TransferState::kNegotiateTransferParams;
     583              : 
     584              : #if CHIP_AUTOMATION_LOGGING
     585            5 :     transferInit.LogMessage(msgType);
     586              : #endif // CHIP_AUTOMATION_LOGGING
     587            5 : }
     588              : 
     589            2 : void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
     590              : {
     591            2 :     VerifyOrReturn(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     592            2 :     VerifyOrReturn(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     593              : 
     594            2 :     ReceiveAccept rcvAcceptMsg;
     595            2 :     const CHIP_ERROR err = rcvAcceptMsg.Parse(msgData.Retain());
     596            2 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     597              : 
     598              :     // Verify that Accept parameters are compatible with the original proposed parameters
     599            2 :     ReturnOnFailure(VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags));
     600              : 
     601            2 :     mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
     602            2 :     mStartOffset          = rcvAcceptMsg.StartOffset;
     603            2 :     mTransferLength       = rcvAcceptMsg.Length;
     604              : 
     605              :     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
     606              :     // message
     607            2 :     mTransferAcceptData.ControlMode    = mControlMode;
     608            2 :     mTransferAcceptData.MaxBlockSize   = rcvAcceptMsg.MaxBlockSize;
     609            2 :     mTransferAcceptData.StartOffset    = rcvAcceptMsg.StartOffset;
     610            2 :     mTransferAcceptData.Length         = rcvAcceptMsg.Length;
     611            2 :     mTransferAcceptData.Metadata       = rcvAcceptMsg.Metadata;
     612            2 :     mTransferAcceptData.MetadataLength = rcvAcceptMsg.MetadataLength;
     613              : 
     614            2 :     mPendingMsgHandle = std::move(msgData);
     615            2 :     mPendingOutput    = OutputEventType::kAcceptReceived;
     616              : 
     617            2 :     mAwaitingResponse = (mControlMode == TransferControlFlags::kSenderDrive);
     618            2 :     mState            = TransferState::kTransferInProgress;
     619              : 
     620              : #if CHIP_AUTOMATION_LOGGING
     621            2 :     rcvAcceptMsg.LogMessage(MessageType::ReceiveAccept);
     622              : #endif // CHIP_AUTOMATION_LOGGING
     623            2 : }
     624              : 
     625            1 : void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
     626              : {
     627            1 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     628            1 :     VerifyOrReturn(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     629              : 
     630            1 :     SendAccept sendAcceptMsg;
     631            1 :     const CHIP_ERROR err = sendAcceptMsg.Parse(msgData.Retain());
     632            1 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     633              : 
     634              :     // Verify that Accept parameters are compatible with the original proposed parameters
     635            1 :     ReturnOnFailure(VerifyProposedMode(sendAcceptMsg.TransferCtlFlags));
     636              : 
     637              :     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
     638              :     // message
     639            1 :     mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
     640              : 
     641            1 :     mTransferAcceptData.ControlMode    = mControlMode;
     642            1 :     mTransferAcceptData.MaxBlockSize   = sendAcceptMsg.MaxBlockSize;
     643            1 :     mTransferAcceptData.StartOffset    = mStartOffset;    // Not included in SendAccept msg, so use member
     644            1 :     mTransferAcceptData.Length         = mTransferLength; // Not included in SendAccept msg, so use member
     645            1 :     mTransferAcceptData.Metadata       = sendAcceptMsg.Metadata;
     646            1 :     mTransferAcceptData.MetadataLength = sendAcceptMsg.MetadataLength;
     647              : 
     648            1 :     mPendingMsgHandle = std::move(msgData);
     649            1 :     mPendingOutput    = OutputEventType::kAcceptReceived;
     650              : 
     651            1 :     mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
     652            1 :     mState            = TransferState::kTransferInProgress;
     653              : 
     654              : #if CHIP_AUTOMATION_LOGGING
     655            1 :     sendAcceptMsg.LogMessage(MessageType::SendAccept);
     656              : #endif // CHIP_AUTOMATION_LOGGING
     657            1 : }
     658              : 
     659           12 : void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
     660              : {
     661           12 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     662           12 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     663           12 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     664              : 
     665           12 :     BlockQuery query;
     666           12 :     const CHIP_ERROR err = query.Parse(std::move(msgData));
     667           12 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     668              : 
     669           12 :     VerifyOrReturn(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     670              : 
     671           12 :     mPendingOutput = OutputEventType::kQueryReceived;
     672              : 
     673           12 :     mAwaitingResponse = false;
     674           12 :     mLastQueryNum     = query.BlockCounter;
     675              : 
     676              : #if CHIP_AUTOMATION_LOGGING
     677           12 :     query.LogMessage(MessageType::BlockQuery);
     678              : #endif // CHIP_AUTOMATION_LOGGING
     679           12 : }
     680              : 
     681            0 : void TransferSession::HandleBlockQueryWithSkip(System::PacketBufferHandle msgData)
     682              : {
     683            0 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     684            0 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     685            0 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     686              : 
     687            0 :     BlockQueryWithSkip query;
     688            0 :     const CHIP_ERROR err = query.Parse(std::move(msgData));
     689            0 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     690              : 
     691            0 :     VerifyOrReturn(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     692              : 
     693            0 :     mPendingOutput = OutputEventType::kQueryWithSkipReceived;
     694              : 
     695            0 :     mAwaitingResponse        = false;
     696            0 :     mLastQueryNum            = query.BlockCounter;
     697            0 :     mBytesToSkip.BytesToSkip = query.BytesToSkip;
     698              : 
     699              : #if CHIP_AUTOMATION_LOGGING
     700            0 :     query.LogMessage(MessageType::BlockQueryWithSkip);
     701              : #endif // CHIP_AUTOMATION_LOGGING
     702            0 : }
     703              : 
     704           14 : void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
     705              : {
     706           15 :     VerifyOrReturn(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     707           14 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     708           14 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     709              : 
     710           14 :     Block blockMsg;
     711           14 :     const CHIP_ERROR err = blockMsg.Parse(msgData.Retain());
     712           14 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     713              : 
     714           14 :     VerifyOrReturn(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     715           13 :     VerifyOrReturn((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
     716              :                    PrepareStatusReport(StatusCode::kBadMessageContents));
     717              : 
     718           13 :     if (IsTransferLengthDefinite())
     719              :     {
     720            0 :         VerifyOrReturn(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength,
     721              :                        PrepareStatusReport(StatusCode::kLengthMismatch));
     722              :     }
     723              : 
     724           13 :     mBlockEventData.Data         = blockMsg.Data;
     725           13 :     mBlockEventData.Length       = blockMsg.DataLength;
     726           13 :     mBlockEventData.IsEof        = false;
     727           13 :     mBlockEventData.BlockCounter = blockMsg.BlockCounter;
     728              : 
     729           13 :     mPendingMsgHandle = std::move(msgData);
     730           13 :     mPendingOutput    = OutputEventType::kBlockReceived;
     731              : 
     732           13 :     mNumBytesProcessed += blockMsg.DataLength;
     733           13 :     mLastBlockNum = blockMsg.BlockCounter;
     734              : 
     735           13 :     mAwaitingResponse = false;
     736              : 
     737              : #if CHIP_AUTOMATION_LOGGING
     738           13 :     blockMsg.LogMessage(MessageType::Block);
     739              : #endif // CHIP_AUTOMATION_LOGGING
     740           14 : }
     741              : 
     742            2 : void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
     743              : {
     744            2 :     VerifyOrReturn(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     745            2 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     746            2 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     747              : 
     748            2 :     BlockEOF blockEOFMsg;
     749            2 :     const CHIP_ERROR err = blockEOFMsg.Parse(msgData.Retain());
     750            2 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     751              : 
     752            2 :     VerifyOrReturn(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     753            2 :     VerifyOrReturn(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
     754              : 
     755            2 :     mBlockEventData.Data         = blockEOFMsg.Data;
     756            2 :     mBlockEventData.Length       = blockEOFMsg.DataLength;
     757            2 :     mBlockEventData.IsEof        = true;
     758            2 :     mBlockEventData.BlockCounter = blockEOFMsg.BlockCounter;
     759              : 
     760            2 :     mPendingMsgHandle = std::move(msgData);
     761            2 :     mPendingOutput    = OutputEventType::kBlockReceived;
     762              : 
     763            2 :     mNumBytesProcessed += blockEOFMsg.DataLength;
     764            2 :     mLastBlockNum = blockEOFMsg.BlockCounter;
     765              : 
     766            2 :     mAwaitingResponse = false;
     767            2 :     mState            = TransferState::kReceivedEOF;
     768              : 
     769              : #if CHIP_AUTOMATION_LOGGING
     770            2 :     blockEOFMsg.LogMessage(MessageType::BlockEOF);
     771              : #endif // CHIP_AUTOMATION_LOGGING
     772            2 : }
     773              : 
     774            4 : void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
     775              : {
     776            4 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     777            4 :     VerifyOrReturn(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     778            4 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     779              : 
     780            4 :     BlockAck ackMsg;
     781            4 :     const CHIP_ERROR err = ackMsg.Parse(std::move(msgData));
     782            4 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     783            4 :     VerifyOrReturn(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     784              : 
     785            4 :     mPendingOutput = OutputEventType::kAckReceived;
     786              : 
     787              :     // In Receiver Drive, the Receiver can send a BlockAck to indicate receipt of the message and reset the timeout.
     788              :     // In this case, the Sender should wait to receive a BlockQuery next.
     789            4 :     mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
     790              : 
     791              : #if CHIP_AUTOMATION_LOGGING
     792            4 :     ackMsg.LogMessage(MessageType::BlockAck);
     793              : #endif // CHIP_AUTOMATION_LOGGING
     794            4 : }
     795              : 
     796            2 : void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
     797              : {
     798            2 :     VerifyOrReturn(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     799            2 :     VerifyOrReturn(mState == TransferState::kAwaitingEOFAck, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     800            2 :     VerifyOrReturn(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
     801              : 
     802            2 :     BlockAckEOF ackMsg;
     803            2 :     const CHIP_ERROR err = ackMsg.Parse(std::move(msgData));
     804            2 :     VerifyOrReturn(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
     805            2 :     VerifyOrReturn(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
     806              : 
     807            2 :     mPendingOutput = OutputEventType::kAckEOFReceived;
     808              : 
     809            2 :     mAwaitingResponse = false;
     810              : 
     811            2 :     mState = TransferState::kTransferDone;
     812              : 
     813              : #if CHIP_AUTOMATION_LOGGING
     814            2 :     ackMsg.LogMessage(MessageType::BlockAckEOF);
     815              : #endif // CHIP_AUTOMATION_LOGGING
     816            2 : }
     817              : 
     818            5 : void TransferSession::ResolveTransferControlOptions(const BitFlags<TransferControlFlags> & proposed)
     819              : {
     820              :     // Must specify at least one synchronous option
     821              :     //
     822            5 :     if (!proposed.HasAny(TransferControlFlags::kSenderDrive, TransferControlFlags::kReceiverDrive))
     823              :     {
     824            0 :         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
     825            0 :         return;
     826              :     }
     827              : 
     828              :     // Ensure there are options supported by both nodes. Async gets priority.
     829              :     // If there is only one common option, choose that one. Otherwise the application must pick.
     830            5 :     const BitFlags<TransferControlFlags> commonOpts(proposed & mSuppportedXferOpts);
     831            5 :     if (!commonOpts.HasAny())
     832              :     {
     833            0 :         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
     834              :     }
     835            5 :     else if (commonOpts.HasOnly(TransferControlFlags::kAsync))
     836              :     {
     837            0 :         mControlMode = TransferControlFlags::kAsync;
     838              :     }
     839            5 :     else if (commonOpts.HasOnly(TransferControlFlags::kReceiverDrive))
     840              :     {
     841            4 :         mControlMode = TransferControlFlags::kReceiverDrive;
     842              :     }
     843            1 :     else if (commonOpts.HasOnly(TransferControlFlags::kSenderDrive))
     844              :     {
     845            1 :         mControlMode = TransferControlFlags::kSenderDrive;
     846              :     }
     847              : }
     848              : 
     849            3 : CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<TransferControlFlags> & proposed)
     850              : {
     851              :     TransferControlFlags mode;
     852              : 
     853              :     // Must specify only one mode in Accept messages
     854            3 :     if (proposed.HasOnly(TransferControlFlags::kAsync))
     855              :     {
     856            0 :         mode = TransferControlFlags::kAsync;
     857              :     }
     858            3 :     else if (proposed.HasOnly(TransferControlFlags::kReceiverDrive))
     859              :     {
     860            2 :         mode = TransferControlFlags::kReceiverDrive;
     861              :     }
     862            1 :     else if (proposed.HasOnly(TransferControlFlags::kSenderDrive))
     863              :     {
     864            1 :         mode = TransferControlFlags::kSenderDrive;
     865              :     }
     866              :     else
     867              :     {
     868            0 :         PrepareStatusReport(StatusCode::kBadMessageContents);
     869            0 :         return CHIP_ERROR_INTERNAL;
     870              :     }
     871              : 
     872              :     // Verify the proposed mode is supported by this instance
     873            3 :     if (mSuppportedXferOpts.Has(mode))
     874              :     {
     875            3 :         mControlMode = mode;
     876              :     }
     877              :     else
     878              :     {
     879            0 :         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
     880            0 :         return CHIP_ERROR_INTERNAL;
     881              :     }
     882              : 
     883            3 :     return CHIP_NO_ERROR;
     884              : }
     885              : 
     886            2 : void TransferSession::PrepareStatusReport(StatusCode code)
     887              : {
     888            2 :     mStatusReportData.statusCode = code;
     889              : 
     890              :     Protocols::SecureChannel::StatusReport report(Protocols::SecureChannel::GeneralStatusCode::kFailure, Protocols::BDX::Id,
     891            2 :                                                   to_underlying(code));
     892            2 :     size_t msgSize = report.Size();
     893            2 :     Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgSize), msgSize);
     894            2 :     VerifyOrExit(!bbuf.IsNull(), mPendingOutput = OutputEventType::kInternalError);
     895              : 
     896            2 :     report.WriteToBuffer(bbuf);
     897            2 :     mPendingMsgHandle = bbuf.Finalize();
     898            2 :     if (mPendingMsgHandle.IsNull())
     899              :     {
     900            0 :         ChipLogError(BDX, "%s: error preparing message: %" CHIP_ERROR_FORMAT, __FUNCTION__, CHIP_ERROR_NO_MEMORY.Format());
     901            0 :         mPendingOutput = OutputEventType::kInternalError;
     902              :     }
     903              :     else
     904              :     {
     905            2 :         PrepareOutgoingMessageEvent(Protocols::SecureChannel::MsgType::StatusReport, mPendingOutput, mMsgTypeData);
     906              :     }
     907              : 
     908            2 : exit:
     909            2 :     mState            = TransferState::kErrorState;
     910            2 :     mAwaitingResponse = false; // Prevent triggering timeout
     911            2 : }
     912              : 
     913           13 : bool TransferSession::IsTransferLengthDefinite() const
     914              : {
     915           13 :     return (mTransferLength > 0);
     916              : }
     917              : 
     918            0 : const char * TransferSession::OutputEvent::ToString(OutputEventType outputEventType)
     919              : {
     920            0 :     return TypeToString(outputEventType);
     921              : }
     922              : 
     923            0 : const char * TransferSession::OutputEvent::TypeToString(OutputEventType outputEventType)
     924              : {
     925            0 :     switch (outputEventType)
     926              :     {
     927            0 :     case OutputEventType::kNone:
     928            0 :         return "None";
     929            0 :     case OutputEventType::kMsgToSend:
     930            0 :         return "MsgToSend";
     931            0 :     case OutputEventType::kInitReceived:
     932            0 :         return "InitReceived";
     933            0 :     case OutputEventType::kAcceptReceived:
     934            0 :         return "AcceptReceived";
     935            0 :     case OutputEventType::kBlockReceived:
     936            0 :         return "BlockReceived";
     937            0 :     case OutputEventType::kQueryReceived:
     938            0 :         return "QueryReceived";
     939            0 :     case OutputEventType::kQueryWithSkipReceived:
     940            0 :         return "QueryWithSkipReceived";
     941            0 :     case OutputEventType::kAckReceived:
     942            0 :         return "AckReceived";
     943            0 :     case OutputEventType::kAckEOFReceived:
     944            0 :         return "AckEOFReceived";
     945            0 :     case OutputEventType::kStatusReceived:
     946            0 :         return "StatusReceived";
     947            0 :     case OutputEventType::kInternalError:
     948            0 :         return "InternalError";
     949            0 :     case OutputEventType::kTransferTimeout:
     950            0 :         return "TransferTimeout";
     951            0 :     default:
     952            0 :         return "Unknown";
     953              :     }
     954              : }
     955              : 
     956            5 : TransferSession::OutputEvent TransferSession::OutputEvent::TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg)
     957              : {
     958            5 :     OutputEvent event(OutputEventType::kInitReceived);
     959            5 :     event.MsgData          = std::move(msg);
     960            5 :     event.transferInitData = data;
     961            5 :     return event;
     962              : }
     963              : 
     964              : /**
     965              :  * @brief
     966              :  *   Convenience method for constructing an OutputEvent with TransferAcceptData that does not contain Metadata
     967              :  */
     968            3 : TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data)
     969              : {
     970            3 :     OutputEvent event(OutputEventType::kAcceptReceived);
     971            3 :     event.transferAcceptData = data;
     972            3 :     return event;
     973              : }
     974              : /**
     975              :  * @brief
     976              :  *   Convenience method for constructing an OutputEvent with TransferAcceptData that contains Metadata
     977              :  */
     978            3 : TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data,
     979              :                                                                                System::PacketBufferHandle msg)
     980              : {
     981            3 :     OutputEvent event = TransferAcceptEvent(data);
     982            3 :     event.MsgData     = std::move(msg);
     983            3 :     return event;
     984              : }
     985              : 
     986           15 : TransferSession::OutputEvent TransferSession::OutputEvent::BlockDataEvent(BlockData data, System::PacketBufferHandle msg)
     987              : {
     988           15 :     OutputEvent event(OutputEventType::kBlockReceived);
     989           15 :     event.MsgData   = std::move(msg);
     990           15 :     event.blockdata = data;
     991           15 :     return event;
     992              : }
     993              : 
     994              : /**
     995              :  * @brief
     996              :  *   Convenience method for constructing an event with kInternalError or kOutputStatusReceived
     997              :  */
     998           13 : TransferSession::OutputEvent TransferSession::OutputEvent::StatusReportEvent(OutputEventType type, StatusReportData data)
     999              : {
    1000           13 :     OutputEvent event(type);
    1001           13 :     event.statusData = data;
    1002           13 :     return event;
    1003              : }
    1004              : 
    1005           44 : TransferSession::OutputEvent TransferSession::OutputEvent::MsgToSendEvent(MessageTypeData typeData, System::PacketBufferHandle msg)
    1006              : {
    1007           44 :     OutputEvent event(OutputEventType::kMsgToSend);
    1008           44 :     event.MsgData     = std::move(msg);
    1009           44 :     event.msgTypeData = typeData;
    1010           44 :     return event;
    1011              : }
    1012              : 
    1013            0 : TransferSession::OutputEvent TransferSession::OutputEvent::QueryWithSkipEvent(TransferSkipData bytesToSkip)
    1014              : {
    1015            0 :     OutputEvent event(OutputEventType::kQueryWithSkipReceived);
    1016            0 :     event.bytesToSkip = bytesToSkip;
    1017            0 :     return event;
    1018              : }
    1019              : 
    1020              : } // namespace bdx
    1021              : } // namespace chip
        

Generated by: LCOV version 2.0-1