3 * Implementation for the TransferSession class.
4 * // TODO: Support Asynchronous mode. Currently, only Synchronous mode is supported.
7 #include <protocols/bdx/BdxTransferSession.h>
9 #include <protocols/Protocols.h>
10 #include <protocols/bdx/BdxMessages.h>
11 #include <protocols/secure_channel/Constants.h>
12 #include <protocols/secure_channel/StatusReport.h>
13 #include <support/BufferReader.h>
14 #include <support/CodeUtils.h>
15 #include <system/SystemPacketBuffer.h>
16 #include <transport/SecureSessionMgr.h>
18 #include <type_traits>
21 constexpr uint8_t kBdxVersion = 0; ///< The version of this implementation of the BDX spec
25 * Allocate a new PacketBuffer and write data from a BDX message struct.
27 CHIP_ERROR WriteToPacketBuffer(const ::chip::bdx::BdxMessage & msgStruct, ::chip::System::PacketBufferHandle & msgBuf)
29 size_t msgDataSize = msgStruct.MessageSize();
30 ::chip::Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgDataSize), msgDataSize);
33 return CHIP_ERROR_NO_MEMORY;
35 msgStruct.WriteToBuffer(bbuf);
36 msgBuf = bbuf.Finalize();
39 return CHIP_ERROR_NO_MEMORY;
44 // We could make this whole method a template, but it's probably smaller code to
45 // share the implementation across all message types.
46 CHIP_ERROR AttachHeader(chip::Protocols::Id protocolId, uint8_t msgType, ::chip::System::PacketBufferHandle & msgBuf)
48 ::chip::PayloadHeader payloadHeader;
50 payloadHeader.SetMessageType(protocolId, msgType);
52 CHIP_ERROR err = payloadHeader.EncodeBeforeData(msgBuf);
59 template <typename MessageType>
60 inline CHIP_ERROR AttachHeader(MessageType msgType, ::chip::System::PacketBufferHandle & msgBuf)
62 return AttachHeader(chip::Protocols::MessageTypeTraits<MessageType>::ProtocolId(), static_cast<uint8_t>(msgType), msgBuf);
64 } // anonymous namespace
69 TransferSession::TransferSession()
71 mSuppportedXferOpts.ClearAll();
74 void TransferSession::PollOutput(OutputEvent & event, uint64_t curTimeMs)
76 event = OutputEvent(OutputEventType::kNone);
78 if (mShouldInitTimeoutStart)
80 mTimeoutStartTimeMs = curTimeMs;
81 mShouldInitTimeoutStart = false;
84 if (mAwaitingResponse && ((curTimeMs - mTimeoutStartTimeMs) >= mTimeoutMs))
86 event = OutputEvent(OutputEventType::kTransferTimeout);
87 mState = TransferState::kErrorState;
88 mAwaitingResponse = false;
92 switch (mPendingOutput)
94 case OutputEventType::kNone:
95 event = OutputEvent(OutputEventType::kNone);
97 case OutputEventType::kInternalError:
98 event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
100 case OutputEventType::kStatusReceived:
101 event = OutputEvent::StatusReportEvent(OutputEventType::kStatusReceived, mStatusReportData);
103 case OutputEventType::kMsgToSend:
104 event = OutputEvent(OutputEventType::kMsgToSend);
105 event.MsgData = std::move(mPendingMsgHandle);
106 mTimeoutStartTimeMs = curTimeMs;
108 case OutputEventType::kInitReceived:
109 event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle));
111 case OutputEventType::kAcceptReceived:
112 event = OutputEvent::TransferAcceptEvent(mTransferAcceptData, std::move(mPendingMsgHandle));
114 case OutputEventType::kQueryReceived:
115 event = OutputEvent(OutputEventType::kQueryReceived);
117 case OutputEventType::kBlockReceived:
118 event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle));
120 case OutputEventType::kAckReceived:
121 event = OutputEvent(OutputEventType::kAckReceived);
123 case OutputEventType::kAckEOFReceived:
124 event = OutputEvent(OutputEventType::kAckEOFReceived);
127 event = OutputEvent(OutputEventType::kNone);
131 // If there's no other pending output but an error occured or was received, then continue to output the error.
132 // This ensures that when the TransferSession encounters an error and needs to send a StatusReport, both a kMsgToSend and a
133 // kInternalError output event will be emitted.
134 if (event.EventType == OutputEventType::kNone && mState == TransferState::kErrorState)
136 event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
139 mPendingOutput = OutputEventType::kNone;
142 CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitData & initData, uint32_t timeoutMs)
144 CHIP_ERROR err = CHIP_NO_ERROR;
146 TransferInit initMsg;
148 VerifyOrExit(mState == TransferState::kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
151 mTimeoutMs = timeoutMs;
153 // Set transfer parameters. They may be overridden later by an Accept message
154 mSuppportedXferOpts = initData.TransferCtlFlags;
155 mMaxSupportedBlockSize = initData.MaxBlockSize;
156 mStartOffset = initData.StartOffset;
157 mTransferLength = initData.Length;
159 // Prepare TransferInit message
160 initMsg.TransferCtlOptions = initData.TransferCtlFlags;
161 initMsg.Version = kBdxVersion;
162 initMsg.MaxBlockSize = mMaxSupportedBlockSize;
163 initMsg.StartOffset = mStartOffset;
164 initMsg.MaxLength = mTransferLength;
165 initMsg.FileDesignator = initData.FileDesignator;
166 initMsg.FileDesLength = initData.FileDesLength;
167 initMsg.Metadata = initData.Metadata;
168 initMsg.MetadataLength = initData.MetadataLength;
170 err = WriteToPacketBuffer(initMsg, mPendingMsgHandle);
173 msgType = (mRole == TransferRole::kSender) ? MessageType::SendInit : MessageType::ReceiveInit;
174 err = AttachHeader(msgType, mPendingMsgHandle);
177 mState = TransferState::kAwaitingAccept;
178 mAwaitingResponse = true;
180 mPendingOutput = OutputEventType::kMsgToSend;
186 CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags<TransferControlFlags> xferControlOpts,
187 uint16_t maxBlockSize, uint32_t timeoutMs)
189 CHIP_ERROR err = CHIP_NO_ERROR;
191 VerifyOrExit(mState == TransferState::kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
193 // Used to determine compatibility with any future TransferInit parameters
195 mTimeoutMs = timeoutMs;
196 mSuppportedXferOpts = xferControlOpts;
197 mMaxSupportedBlockSize = maxBlockSize;
199 mState = TransferState::kAwaitingInitMsg;
205 CHIP_ERROR TransferSession::AcceptTransfer(const TransferAcceptData & acceptData)
207 CHIP_ERROR err = CHIP_NO_ERROR;
208 System::PacketBufferHandle outMsgBuf;
209 const BitFlags<TransferControlFlags> proposedControlOpts(mTransferRequestData.TransferCtlFlags);
211 VerifyOrExit(mState == TransferState::kNegotiateTransferParams, err = CHIP_ERROR_INCORRECT_STATE);
212 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
214 // Don't allow a Control method that wasn't supported by the initiator
215 // MaxBlockSize can't be larger than the proposed value
216 VerifyOrExit(proposedControlOpts.Has(acceptData.ControlMode), err = CHIP_ERROR_INVALID_ARGUMENT);
217 VerifyOrExit(acceptData.MaxBlockSize <= mTransferRequestData.MaxBlockSize, err = CHIP_ERROR_INVALID_ARGUMENT);
219 mTransferMaxBlockSize = acceptData.MaxBlockSize;
221 if (mRole == TransferRole::kSender)
223 mStartOffset = acceptData.StartOffset;
224 mTransferLength = acceptData.Length;
226 ReceiveAccept acceptMsg;
227 acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
228 acceptMsg.Version = mTransferVersion;
229 acceptMsg.MaxBlockSize = acceptData.MaxBlockSize;
230 acceptMsg.StartOffset = acceptData.StartOffset;
231 acceptMsg.Length = acceptData.Length;
232 acceptMsg.Metadata = acceptData.Metadata;
233 acceptMsg.MetadataLength = acceptData.MetadataLength;
235 err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
238 err = AttachHeader(MessageType::ReceiveAccept, mPendingMsgHandle);
243 SendAccept acceptMsg;
244 acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
245 acceptMsg.Version = mTransferVersion;
246 acceptMsg.MaxBlockSize = acceptData.MaxBlockSize;
247 acceptMsg.Metadata = acceptData.Metadata;
248 acceptMsg.MetadataLength = acceptData.MetadataLength;
250 err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
253 err = AttachHeader(MessageType::SendAccept, mPendingMsgHandle);
257 mPendingOutput = OutputEventType::kMsgToSend;
259 mState = TransferState::kTransferInProgress;
261 if ((mRole == TransferRole::kReceiver && mControlMode == TransferControlFlags::kSenderDrive) ||
262 (mRole == TransferRole::kSender && mControlMode == TransferControlFlags::kReceiverDrive))
264 mAwaitingResponse = true;
271 CHIP_ERROR TransferSession::PrepareBlockQuery()
273 CHIP_ERROR err = CHIP_NO_ERROR;
276 VerifyOrExit(mState == TransferState::kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
277 VerifyOrExit(mRole == TransferRole::kReceiver, err = CHIP_ERROR_INCORRECT_STATE);
278 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
279 VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
281 queryMsg.BlockCounter = mNextQueryNum;
283 err = WriteToPacketBuffer(queryMsg, mPendingMsgHandle);
286 err = AttachHeader(MessageType::BlockQuery, mPendingMsgHandle);
289 mPendingOutput = OutputEventType::kMsgToSend;
291 mAwaitingResponse = true;
292 mLastQueryNum = mNextQueryNum++;
298 CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData)
300 CHIP_ERROR err = CHIP_NO_ERROR;
304 VerifyOrExit(mState == TransferState::kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
305 VerifyOrExit(mRole == TransferRole::kSender, err = CHIP_ERROR_INCORRECT_STATE);
306 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
307 VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
309 // Verify non-zero data is provided and is no longer than MaxBlockSize (BlockEOF may contain 0 length data)
310 VerifyOrExit((inData.Data != nullptr) && (inData.Length <= mTransferMaxBlockSize), err = CHIP_ERROR_INVALID_ARGUMENT);
312 blockMsg.BlockCounter = mNextBlockNum;
313 blockMsg.Data = inData.Data;
314 blockMsg.DataLength = inData.Length;
316 err = WriteToPacketBuffer(blockMsg, mPendingMsgHandle);
319 msgType = inData.IsEof ? MessageType::BlockEOF : MessageType::Block;
320 err = AttachHeader(msgType, mPendingMsgHandle);
323 mPendingOutput = OutputEventType::kMsgToSend;
325 if (msgType == MessageType::BlockEOF)
327 mState = TransferState::kAwaitingEOFAck;
330 mAwaitingResponse = true;
331 mLastBlockNum = mNextBlockNum++;
337 CHIP_ERROR TransferSession::PrepareBlockAck()
339 CHIP_ERROR err = CHIP_NO_ERROR;
340 CounterMessage ackMsg;
343 VerifyOrExit(mRole == TransferRole::kReceiver, err = CHIP_ERROR_INCORRECT_STATE);
344 VerifyOrExit((mState == TransferState::kTransferInProgress) || (mState == TransferState::kReceivedEOF),
345 err = CHIP_ERROR_INCORRECT_STATE);
346 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
348 ackMsg.BlockCounter = mLastBlockNum;
349 msgType = (mState == TransferState::kReceivedEOF) ? MessageType::BlockAckEOF : MessageType::BlockAck;
351 err = WriteToPacketBuffer(ackMsg, mPendingMsgHandle);
354 err = AttachHeader(msgType, mPendingMsgHandle);
357 if (mState == TransferState::kTransferInProgress)
359 if (mControlMode == TransferControlFlags::kSenderDrive)
361 // In Sender Drive, a BlockAck is implied to also be a query for the next Block, so expect to receive a Block
363 mLastQueryNum = ackMsg.BlockCounter + 1;
364 mAwaitingResponse = true;
367 else if (mState == TransferState::kReceivedEOF)
369 mState = TransferState::kTransferDone;
370 mAwaitingResponse = false;
373 mPendingOutput = OutputEventType::kMsgToSend;
379 CHIP_ERROR TransferSession::AbortTransfer(StatusCode reason)
381 CHIP_ERROR err = CHIP_NO_ERROR;
383 VerifyOrExit((mState != TransferState::kUnitialized) && (mState != TransferState::kTransferDone) &&
384 (mState != TransferState::kErrorState),
385 err = CHIP_ERROR_INCORRECT_STATE);
387 PrepareStatusReport(reason);
393 void TransferSession::Reset()
395 mPendingOutput = OutputEventType::kNone;
396 mState = TransferState::kUnitialized;
397 mSuppportedXferOpts.ClearAll();
398 mTransferVersion = 0;
399 mMaxSupportedBlockSize = 0;
402 mTransferMaxBlockSize = 0;
404 mPendingMsgHandle = nullptr;
406 mNumBytesProcessed = 0;
413 mTimeoutStartTimeMs = 0;
414 mShouldInitTimeoutStart = true;
415 mAwaitingResponse = false;
418 CHIP_ERROR TransferSession::HandleMessageReceived(System::PacketBufferHandle msg, uint64_t curTimeMs)
420 CHIP_ERROR err = CHIP_NO_ERROR;
421 PayloadHeader payloadHeader;
423 VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
425 err = payloadHeader.DecodeAndConsume(msg);
428 if (payloadHeader.HasProtocol(Protocols::BDX::Id))
430 err = HandleBdxMessage(payloadHeader, std::move(msg));
433 mTimeoutStartTimeMs = curTimeMs;
435 else if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
437 err = HandleStatusReportMessage(payloadHeader, std::move(msg));
442 err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
449 // Return CHIP_ERROR only if there was a problem decoding the message. Otherwise, call PrepareStatusReport().
450 CHIP_ERROR TransferSession::HandleBdxMessage(PayloadHeader & header, System::PacketBufferHandle msg)
452 CHIP_ERROR err = CHIP_NO_ERROR;
453 MessageType msgType = static_cast<MessageType>(header.GetMessageType());
455 VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
456 VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
460 case MessageType::SendInit:
461 case MessageType::ReceiveInit:
462 HandleTransferInit(msgType, std::move(msg));
464 case MessageType::SendAccept:
465 HandleSendAccept(std::move(msg));
467 case MessageType::ReceiveAccept:
468 HandleReceiveAccept(std::move(msg));
470 case MessageType::BlockQuery:
471 HandleBlockQuery(std::move(msg));
473 case MessageType::Block:
474 HandleBlock(std::move(msg));
476 case MessageType::BlockEOF:
477 HandleBlockEOF(std::move(msg));
479 case MessageType::BlockAck:
480 HandleBlockAck(std::move(msg));
482 case MessageType::BlockAckEOF:
483 HandleBlockAckEOF(std::move(msg));
486 err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
496 * Parse a StatusReport message and prepare to emit an OutputEvent with the message data.
498 * NOTE: BDX does not currently expect to ever use a "Success" general code, so it will be treated as an error along with any
501 CHIP_ERROR TransferSession::HandleStatusReportMessage(PayloadHeader & header, System::PacketBufferHandle msg)
503 VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
505 mState = TransferState::kErrorState;
506 mAwaitingResponse = false;
508 Protocols::SecureChannel::StatusReport report;
509 ReturnErrorOnFailure(report.Parse(std::move(msg)));
510 VerifyOrReturnError((report.GetProtocolId() == Protocols::BDX::Id.ToFullyQualifiedSpecForm()), CHIP_ERROR_INVALID_MESSAGE_TYPE);
512 mStatusReportData.statusCode = static_cast<StatusCode>(report.GetProtocolCode());
514 mPendingOutput = OutputEventType::kStatusReceived;
516 return CHIP_NO_ERROR;
519 void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
521 CHIP_ERROR err = CHIP_NO_ERROR;
522 TransferInit transferInit;
524 VerifyOrExit(mState == TransferState::kAwaitingInitMsg, PrepareStatusReport(StatusCode::kUnexpectedMessage));
526 if (mRole == TransferRole::kSender)
528 VerifyOrExit(msgType == MessageType::ReceiveInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
532 VerifyOrExit(msgType == MessageType::SendInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
535 err = transferInit.Parse(msgData.Retain());
536 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
538 ResolveTransferControlOptions(transferInit.TransferCtlOptions);
539 mTransferVersion = ::chip::min(kBdxVersion, transferInit.Version);
540 mTransferMaxBlockSize = ::chip::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
542 // Accept for now, they may be changed or rejected by the peer if this is a ReceiveInit
543 mStartOffset = transferInit.StartOffset;
544 mTransferLength = transferInit.MaxLength;
546 // Store the Request data to share with the caller for verification
547 mTransferRequestData.TransferCtlFlags = transferInit.TransferCtlOptions;
548 mTransferRequestData.MaxBlockSize = transferInit.MaxBlockSize;
549 mTransferRequestData.StartOffset = transferInit.StartOffset;
550 mTransferRequestData.Length = transferInit.MaxLength;
551 mTransferRequestData.FileDesignator = transferInit.FileDesignator;
552 mTransferRequestData.FileDesLength = transferInit.FileDesLength;
553 mTransferRequestData.Metadata = transferInit.Metadata;
554 mTransferRequestData.MetadataLength = transferInit.MetadataLength;
556 mPendingMsgHandle = std::move(msgData);
557 mPendingOutput = OutputEventType::kInitReceived;
559 mState = TransferState::kNegotiateTransferParams;
565 void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
567 CHIP_ERROR err = CHIP_NO_ERROR;
568 ReceiveAccept rcvAcceptMsg;
570 VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
571 VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
573 err = rcvAcceptMsg.Parse(msgData.Retain());
574 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
576 // Verify that Accept parameters are compatible with the original proposed parameters
577 err = VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags);
580 mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
581 mStartOffset = rcvAcceptMsg.StartOffset;
582 mTransferLength = rcvAcceptMsg.Length;
584 // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
586 mTransferAcceptData.ControlMode = mControlMode;
587 mTransferAcceptData.MaxBlockSize = rcvAcceptMsg.MaxBlockSize;
588 mTransferAcceptData.StartOffset = rcvAcceptMsg.StartOffset;
589 mTransferAcceptData.Length = rcvAcceptMsg.Length;
590 mTransferAcceptData.Metadata = rcvAcceptMsg.Metadata;
591 mTransferAcceptData.MetadataLength = rcvAcceptMsg.MetadataLength;
593 mPendingMsgHandle = std::move(msgData);
594 mPendingOutput = OutputEventType::kAcceptReceived;
596 mAwaitingResponse = (mControlMode == TransferControlFlags::kSenderDrive);
597 mState = TransferState::kTransferInProgress;
603 void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
605 CHIP_ERROR err = CHIP_NO_ERROR;
606 SendAccept sendAcceptMsg;
608 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
609 VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
611 err = sendAcceptMsg.Parse(msgData.Retain());
612 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
614 // Verify that Accept parameters are compatible with the original proposed parameters
615 err = VerifyProposedMode(sendAcceptMsg.TransferCtlFlags);
618 // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
620 mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
622 mTransferAcceptData.ControlMode = mControlMode;
623 mTransferAcceptData.MaxBlockSize = sendAcceptMsg.MaxBlockSize;
624 mTransferAcceptData.StartOffset = mStartOffset; // Not included in SendAccept msg, so use member
625 mTransferAcceptData.Length = mTransferLength; // Not included in SendAccept msg, so use member
626 mTransferAcceptData.Metadata = sendAcceptMsg.Metadata;
627 mTransferAcceptData.MetadataLength = sendAcceptMsg.MetadataLength;
629 mPendingMsgHandle = std::move(msgData);
630 mPendingOutput = OutputEventType::kAcceptReceived;
632 mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
633 mState = TransferState::kTransferInProgress;
639 void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
641 CHIP_ERROR err = CHIP_NO_ERROR;
644 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
645 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
646 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
648 err = query.Parse(std::move(msgData));
649 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
651 VerifyOrExit(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
653 mPendingOutput = OutputEventType::kQueryReceived;
655 mAwaitingResponse = false;
656 mLastQueryNum = query.BlockCounter;
662 void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
664 CHIP_ERROR err = CHIP_NO_ERROR;
667 VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
668 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
669 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
671 err = blockMsg.Parse(msgData.Retain());
672 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
674 VerifyOrExit(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
675 VerifyOrExit((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
676 PrepareStatusReport(StatusCode::kBadMessageContents));
678 if (IsTransferLengthDefinite())
680 VerifyOrExit(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength, PrepareStatusReport(StatusCode::kLengthMismatch));
683 mBlockEventData.Data = blockMsg.Data;
684 mBlockEventData.Length = blockMsg.DataLength;
685 mBlockEventData.IsEof = false;
687 mPendingMsgHandle = std::move(msgData);
688 mPendingOutput = OutputEventType::kBlockReceived;
690 mNumBytesProcessed += blockMsg.DataLength;
691 mLastBlockNum = blockMsg.BlockCounter;
693 mAwaitingResponse = false;
699 void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
701 CHIP_ERROR err = CHIP_NO_ERROR;
702 BlockEOF blockEOFMsg;
704 VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
705 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
706 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
708 err = blockEOFMsg.Parse(msgData.Retain());
709 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
711 VerifyOrExit(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
712 VerifyOrExit(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
714 mBlockEventData.Data = blockEOFMsg.Data;
715 mBlockEventData.Length = blockEOFMsg.DataLength;
716 mBlockEventData.IsEof = true;
718 mPendingMsgHandle = std::move(msgData);
719 mPendingOutput = OutputEventType::kBlockReceived;
721 mNumBytesProcessed += blockEOFMsg.DataLength;
722 mLastBlockNum = blockEOFMsg.BlockCounter;
724 mAwaitingResponse = false;
725 mState = TransferState::kReceivedEOF;
731 void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
733 CHIP_ERROR err = CHIP_NO_ERROR;
736 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
737 VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
738 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
740 err = ackMsg.Parse(std::move(msgData));
741 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
742 VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
744 mPendingOutput = OutputEventType::kAckReceived;
746 // In Receiver Drive, the Receiver can send a BlockAck to indicate receipt of the message and reset the timeout.
747 // In this case, the Sender should wait to receive a BlockQuery next.
748 mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
754 void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
756 CHIP_ERROR err = CHIP_NO_ERROR;
759 VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
760 VerifyOrExit(mState == TransferState::kAwaitingEOFAck, PrepareStatusReport(StatusCode::kUnexpectedMessage));
761 VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
763 err = ackMsg.Parse(std::move(msgData));
764 VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
765 VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
767 mPendingOutput = OutputEventType::kAckEOFReceived;
769 mAwaitingResponse = false;
771 mState = TransferState::kTransferDone;
777 void TransferSession::ResolveTransferControlOptions(const BitFlags<TransferControlFlags> & proposed)
779 // Must specify at least one synchronous option
781 if (!proposed.HasAny(TransferControlFlags::kSenderDrive, TransferControlFlags::kReceiverDrive))
783 PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
787 // Ensure there are options supported by both nodes. Async gets priority.
788 // If there is only one common option, choose that one. Otherwise the application must pick.
789 const BitFlags<TransferControlFlags> commonOpts(proposed & mSuppportedXferOpts);
790 if (!commonOpts.HasAny())
792 PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
794 else if (commonOpts.HasOnly(TransferControlFlags::kAsync))
796 mControlMode = TransferControlFlags::kAsync;
798 else if (commonOpts.HasOnly(TransferControlFlags::kReceiverDrive))
800 mControlMode = TransferControlFlags::kReceiverDrive;
802 else if (commonOpts.HasOnly(TransferControlFlags::kSenderDrive))
804 mControlMode = TransferControlFlags::kSenderDrive;
808 CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<TransferControlFlags> & proposed)
810 TransferControlFlags mode;
812 // Must specify only one mode in Accept messages
813 if (proposed.HasOnly(TransferControlFlags::kAsync))
815 mode = TransferControlFlags::kAsync;
817 else if (proposed.HasOnly(TransferControlFlags::kReceiverDrive))
819 mode = TransferControlFlags::kReceiverDrive;
821 else if (proposed.HasOnly(TransferControlFlags::kSenderDrive))
823 mode = TransferControlFlags::kSenderDrive;
827 PrepareStatusReport(StatusCode::kBadMessageContents);
828 return CHIP_ERROR_INTERNAL;
831 // Verify the proposed mode is supported by this instance
832 if (mSuppportedXferOpts.Has(mode))
838 PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
839 return CHIP_ERROR_INTERNAL;
842 return CHIP_NO_ERROR;
845 void TransferSession::PrepareStatusReport(StatusCode code)
847 static_assert(std::is_same<std::underlying_type_t<decltype(code)>, uint16_t>::value, "Cast is not safe");
849 mStatusReportData.statusCode = code;
851 Protocols::SecureChannel::StatusReport report(Protocols::SecureChannel::GeneralStatusCode::kFailure,
852 Protocols::BDX::Id.ToFullyQualifiedSpecForm(), static_cast<uint16_t>(code));
853 size_t msgSize = report.Size();
854 Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgSize), msgSize);
855 VerifyOrExit(!bbuf.IsNull(), mPendingOutput = OutputEventType::kInternalError);
857 report.WriteToBuffer(bbuf);
858 mPendingMsgHandle = bbuf.Finalize();
859 if (mPendingMsgHandle.IsNull())
861 mPendingOutput = OutputEventType::kInternalError;
865 CHIP_ERROR err = AttachHeader(Protocols::SecureChannel::MsgType::StatusReport, mPendingMsgHandle);
866 VerifyOrExit(err == CHIP_NO_ERROR, mPendingOutput = OutputEventType::kInternalError);
867 mPendingOutput = OutputEventType::kMsgToSend;
871 mState = TransferState::kErrorState;
872 mAwaitingResponse = false; // Prevent triggering timeout
875 bool TransferSession::IsTransferLengthDefinite()
877 return (mTransferLength > 0);
880 TransferSession::OutputEvent TransferSession::OutputEvent::TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg)
882 OutputEvent event(OutputEventType::kInitReceived);
883 event.MsgData = std::move(msg);
884 event.transferInitData = data;
890 * Convenience method for constructing an OutputEvent with TransferAcceptData that does not contain Metadata
892 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data)
894 OutputEvent event(OutputEventType::kAcceptReceived);
895 event.transferAcceptData = data;
900 * Convenience method for constructing an OutputEvent with TransferAcceptData that contains Metadata
902 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data,
903 System::PacketBufferHandle msg)
905 OutputEvent event = TransferAcceptEvent(data);
906 event.MsgData = std::move(msg);
910 TransferSession::OutputEvent TransferSession::OutputEvent::BlockDataEvent(BlockData data, System::PacketBufferHandle msg)
912 OutputEvent event(OutputEventType::kBlockReceived);
913 event.MsgData = std::move(msg);
914 event.blockdata = data;
920 * Convenience method for constructing an event with kInternalError or kOutputStatusReceived
922 TransferSession::OutputEvent TransferSession::OutputEvent::StatusReportEvent(OutputEventType type, StatusReportData data)
924 OutputEvent event(type);
925 event.statusData = data;