Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / src / protocols / bdx / BdxTransferSession.cpp
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 <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>
17
18 #include <type_traits>
19
20 namespace {
21 constexpr uint8_t kBdxVersion = 0; ///< The version of this implementation of the BDX spec
22
23 /**
24  * @brief
25  *   Allocate a new PacketBuffer and write data from a BDX message struct.
26  */
27 CHIP_ERROR WriteToPacketBuffer(const ::chip::bdx::BdxMessage & msgStruct, ::chip::System::PacketBufferHandle & msgBuf)
28 {
29     size_t msgDataSize = msgStruct.MessageSize();
30     ::chip::Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgDataSize), msgDataSize);
31     if (bbuf.IsNull())
32     {
33         return CHIP_ERROR_NO_MEMORY;
34     }
35     msgStruct.WriteToBuffer(bbuf);
36     msgBuf = bbuf.Finalize();
37     if (msgBuf.IsNull())
38     {
39         return CHIP_ERROR_NO_MEMORY;
40     }
41     return CHIP_NO_ERROR;
42 }
43
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)
47 {
48     ::chip::PayloadHeader payloadHeader;
49
50     payloadHeader.SetMessageType(protocolId, msgType);
51
52     CHIP_ERROR err = payloadHeader.EncodeBeforeData(msgBuf);
53     SuccessOrExit(err);
54
55 exit:
56     return err;
57 }
58
59 template <typename MessageType>
60 inline CHIP_ERROR AttachHeader(MessageType msgType, ::chip::System::PacketBufferHandle & msgBuf)
61 {
62     return AttachHeader(chip::Protocols::MessageTypeTraits<MessageType>::ProtocolId(), static_cast<uint8_t>(msgType), msgBuf);
63 }
64 } // anonymous namespace
65
66 namespace chip {
67 namespace bdx {
68
69 TransferSession::TransferSession()
70 {
71     mSuppportedXferOpts.ClearAll();
72 }
73
74 void TransferSession::PollOutput(OutputEvent & event, uint64_t curTimeMs)
75 {
76     event = OutputEvent(OutputEventType::kNone);
77
78     if (mShouldInitTimeoutStart)
79     {
80         mTimeoutStartTimeMs     = curTimeMs;
81         mShouldInitTimeoutStart = false;
82     }
83
84     if (mAwaitingResponse && ((curTimeMs - mTimeoutStartTimeMs) >= mTimeoutMs))
85     {
86         event             = OutputEvent(OutputEventType::kTransferTimeout);
87         mState            = TransferState::kErrorState;
88         mAwaitingResponse = false;
89         return;
90     }
91
92     switch (mPendingOutput)
93     {
94     case OutputEventType::kNone:
95         event = OutputEvent(OutputEventType::kNone);
96         break;
97     case OutputEventType::kInternalError:
98         event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
99         break;
100     case OutputEventType::kStatusReceived:
101         event = OutputEvent::StatusReportEvent(OutputEventType::kStatusReceived, mStatusReportData);
102         break;
103     case OutputEventType::kMsgToSend:
104         event               = OutputEvent(OutputEventType::kMsgToSend);
105         event.MsgData       = std::move(mPendingMsgHandle);
106         mTimeoutStartTimeMs = curTimeMs;
107         break;
108     case OutputEventType::kInitReceived:
109         event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle));
110         break;
111     case OutputEventType::kAcceptReceived:
112         event = OutputEvent::TransferAcceptEvent(mTransferAcceptData, std::move(mPendingMsgHandle));
113         break;
114     case OutputEventType::kQueryReceived:
115         event = OutputEvent(OutputEventType::kQueryReceived);
116         break;
117     case OutputEventType::kBlockReceived:
118         event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle));
119         break;
120     case OutputEventType::kAckReceived:
121         event = OutputEvent(OutputEventType::kAckReceived);
122         break;
123     case OutputEventType::kAckEOFReceived:
124         event = OutputEvent(OutputEventType::kAckEOFReceived);
125         break;
126     default:
127         event = OutputEvent(OutputEventType::kNone);
128         break;
129     }
130
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)
135     {
136         event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
137     }
138
139     mPendingOutput = OutputEventType::kNone;
140 }
141
142 CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitData & initData, uint32_t timeoutMs)
143 {
144     CHIP_ERROR err = CHIP_NO_ERROR;
145     MessageType msgType;
146     TransferInit initMsg;
147
148     VerifyOrExit(mState == TransferState::kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
149
150     mRole      = role;
151     mTimeoutMs = timeoutMs;
152
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;
158
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;
169
170     err = WriteToPacketBuffer(initMsg, mPendingMsgHandle);
171     SuccessOrExit(err);
172
173     msgType = (mRole == TransferRole::kSender) ? MessageType::SendInit : MessageType::ReceiveInit;
174     err     = AttachHeader(msgType, mPendingMsgHandle);
175     SuccessOrExit(err);
176
177     mState            = TransferState::kAwaitingAccept;
178     mAwaitingResponse = true;
179
180     mPendingOutput = OutputEventType::kMsgToSend;
181
182 exit:
183     return err;
184 }
185
186 CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags<TransferControlFlags> xferControlOpts,
187                                             uint16_t maxBlockSize, uint32_t timeoutMs)
188 {
189     CHIP_ERROR err = CHIP_NO_ERROR;
190
191     VerifyOrExit(mState == TransferState::kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
192
193     // Used to determine compatibility with any future TransferInit parameters
194     mRole                  = role;
195     mTimeoutMs             = timeoutMs;
196     mSuppportedXferOpts    = xferControlOpts;
197     mMaxSupportedBlockSize = maxBlockSize;
198
199     mState = TransferState::kAwaitingInitMsg;
200
201 exit:
202     return err;
203 }
204
205 CHIP_ERROR TransferSession::AcceptTransfer(const TransferAcceptData & acceptData)
206 {
207     CHIP_ERROR err = CHIP_NO_ERROR;
208     System::PacketBufferHandle outMsgBuf;
209     const BitFlags<TransferControlFlags> proposedControlOpts(mTransferRequestData.TransferCtlFlags);
210
211     VerifyOrExit(mState == TransferState::kNegotiateTransferParams, err = CHIP_ERROR_INCORRECT_STATE);
212     VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
213
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);
218
219     mTransferMaxBlockSize = acceptData.MaxBlockSize;
220
221     if (mRole == TransferRole::kSender)
222     {
223         mStartOffset    = acceptData.StartOffset;
224         mTransferLength = acceptData.Length;
225
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;
234
235         err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
236         SuccessOrExit(err);
237
238         err = AttachHeader(MessageType::ReceiveAccept, mPendingMsgHandle);
239         SuccessOrExit(err);
240     }
241     else
242     {
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;
249
250         err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
251         SuccessOrExit(err);
252
253         err = AttachHeader(MessageType::SendAccept, mPendingMsgHandle);
254         SuccessOrExit(err);
255     }
256
257     mPendingOutput = OutputEventType::kMsgToSend;
258
259     mState = TransferState::kTransferInProgress;
260
261     if ((mRole == TransferRole::kReceiver && mControlMode == TransferControlFlags::kSenderDrive) ||
262         (mRole == TransferRole::kSender && mControlMode == TransferControlFlags::kReceiverDrive))
263     {
264         mAwaitingResponse = true;
265     }
266
267 exit:
268     return err;
269 }
270
271 CHIP_ERROR TransferSession::PrepareBlockQuery()
272 {
273     CHIP_ERROR err = CHIP_NO_ERROR;
274     BlockQuery queryMsg;
275
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);
280
281     queryMsg.BlockCounter = mNextQueryNum;
282
283     err = WriteToPacketBuffer(queryMsg, mPendingMsgHandle);
284     SuccessOrExit(err);
285
286     err = AttachHeader(MessageType::BlockQuery, mPendingMsgHandle);
287     SuccessOrExit(err);
288
289     mPendingOutput = OutputEventType::kMsgToSend;
290
291     mAwaitingResponse = true;
292     mLastQueryNum     = mNextQueryNum++;
293
294 exit:
295     return err;
296 }
297
298 CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData)
299 {
300     CHIP_ERROR err = CHIP_NO_ERROR;
301     DataBlock blockMsg;
302     MessageType msgType;
303
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);
308
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);
311
312     blockMsg.BlockCounter = mNextBlockNum;
313     blockMsg.Data         = inData.Data;
314     blockMsg.DataLength   = inData.Length;
315
316     err = WriteToPacketBuffer(blockMsg, mPendingMsgHandle);
317     SuccessOrExit(err);
318
319     msgType = inData.IsEof ? MessageType::BlockEOF : MessageType::Block;
320     err     = AttachHeader(msgType, mPendingMsgHandle);
321     SuccessOrExit(err);
322
323     mPendingOutput = OutputEventType::kMsgToSend;
324
325     if (msgType == MessageType::BlockEOF)
326     {
327         mState = TransferState::kAwaitingEOFAck;
328     }
329
330     mAwaitingResponse = true;
331     mLastBlockNum     = mNextBlockNum++;
332
333 exit:
334     return err;
335 }
336
337 CHIP_ERROR TransferSession::PrepareBlockAck()
338 {
339     CHIP_ERROR err = CHIP_NO_ERROR;
340     CounterMessage ackMsg;
341     MessageType msgType;
342
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);
347
348     ackMsg.BlockCounter = mLastBlockNum;
349     msgType             = (mState == TransferState::kReceivedEOF) ? MessageType::BlockAckEOF : MessageType::BlockAck;
350
351     err = WriteToPacketBuffer(ackMsg, mPendingMsgHandle);
352     SuccessOrExit(err);
353
354     err = AttachHeader(msgType, mPendingMsgHandle);
355     SuccessOrExit(err);
356
357     if (mState == TransferState::kTransferInProgress)
358     {
359         if (mControlMode == TransferControlFlags::kSenderDrive)
360         {
361             // In Sender Drive, a BlockAck is implied to also be a query for the next Block, so expect to receive a Block
362             // message.
363             mLastQueryNum     = ackMsg.BlockCounter + 1;
364             mAwaitingResponse = true;
365         }
366     }
367     else if (mState == TransferState::kReceivedEOF)
368     {
369         mState            = TransferState::kTransferDone;
370         mAwaitingResponse = false;
371     }
372
373     mPendingOutput = OutputEventType::kMsgToSend;
374
375 exit:
376     return err;
377 }
378
379 CHIP_ERROR TransferSession::AbortTransfer(StatusCode reason)
380 {
381     CHIP_ERROR err = CHIP_NO_ERROR;
382
383     VerifyOrExit((mState != TransferState::kUnitialized) && (mState != TransferState::kTransferDone) &&
384                      (mState != TransferState::kErrorState),
385                  err = CHIP_ERROR_INCORRECT_STATE);
386
387     PrepareStatusReport(reason);
388
389 exit:
390     return err;
391 }
392
393 void TransferSession::Reset()
394 {
395     mPendingOutput = OutputEventType::kNone;
396     mState         = TransferState::kUnitialized;
397     mSuppportedXferOpts.ClearAll();
398     mTransferVersion       = 0;
399     mMaxSupportedBlockSize = 0;
400     mStartOffset           = 0;
401     mTransferLength        = 0;
402     mTransferMaxBlockSize  = 0;
403
404     mPendingMsgHandle = nullptr;
405
406     mNumBytesProcessed = 0;
407     mLastBlockNum      = 0;
408     mNextBlockNum      = 0;
409     mLastQueryNum      = 0;
410     mNextQueryNum      = 0;
411
412     mTimeoutMs              = 0;
413     mTimeoutStartTimeMs     = 0;
414     mShouldInitTimeoutStart = true;
415     mAwaitingResponse       = false;
416 }
417
418 CHIP_ERROR TransferSession::HandleMessageReceived(System::PacketBufferHandle msg, uint64_t curTimeMs)
419 {
420     CHIP_ERROR err = CHIP_NO_ERROR;
421     PayloadHeader payloadHeader;
422
423     VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
424
425     err = payloadHeader.DecodeAndConsume(msg);
426     SuccessOrExit(err);
427
428     if (payloadHeader.HasProtocol(Protocols::BDX::Id))
429     {
430         err = HandleBdxMessage(payloadHeader, std::move(msg));
431         SuccessOrExit(err);
432
433         mTimeoutStartTimeMs = curTimeMs;
434     }
435     else if (payloadHeader.HasMessageType(Protocols::SecureChannel::MsgType::StatusReport))
436     {
437         err = HandleStatusReportMessage(payloadHeader, std::move(msg));
438         SuccessOrExit(err);
439     }
440     else
441     {
442         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
443     }
444
445 exit:
446     return err;
447 }
448
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)
451 {
452     CHIP_ERROR err      = CHIP_NO_ERROR;
453     MessageType msgType = static_cast<MessageType>(header.GetMessageType());
454
455     VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
456     VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
457
458     switch (msgType)
459     {
460     case MessageType::SendInit:
461     case MessageType::ReceiveInit:
462         HandleTransferInit(msgType, std::move(msg));
463         break;
464     case MessageType::SendAccept:
465         HandleSendAccept(std::move(msg));
466         break;
467     case MessageType::ReceiveAccept:
468         HandleReceiveAccept(std::move(msg));
469         break;
470     case MessageType::BlockQuery:
471         HandleBlockQuery(std::move(msg));
472         break;
473     case MessageType::Block:
474         HandleBlock(std::move(msg));
475         break;
476     case MessageType::BlockEOF:
477         HandleBlockEOF(std::move(msg));
478         break;
479     case MessageType::BlockAck:
480         HandleBlockAck(std::move(msg));
481         break;
482     case MessageType::BlockAckEOF:
483         HandleBlockAckEOF(std::move(msg));
484         break;
485     default:
486         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
487         break;
488     }
489
490 exit:
491     return err;
492 }
493
494 /**
495  * @brief
496  *   Parse a StatusReport message and prepare to emit an OutputEvent with the message data.
497  *
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
499  *         other code.
500  */
501 CHIP_ERROR TransferSession::HandleStatusReportMessage(PayloadHeader & header, System::PacketBufferHandle msg)
502 {
503     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
504
505     mState            = TransferState::kErrorState;
506     mAwaitingResponse = false;
507
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);
511
512     mStatusReportData.statusCode = static_cast<StatusCode>(report.GetProtocolCode());
513
514     mPendingOutput = OutputEventType::kStatusReceived;
515
516     return CHIP_NO_ERROR;
517 }
518
519 void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
520 {
521     CHIP_ERROR err = CHIP_NO_ERROR;
522     TransferInit transferInit;
523
524     VerifyOrExit(mState == TransferState::kAwaitingInitMsg, PrepareStatusReport(StatusCode::kUnexpectedMessage));
525
526     if (mRole == TransferRole::kSender)
527     {
528         VerifyOrExit(msgType == MessageType::ReceiveInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
529     }
530     else
531     {
532         VerifyOrExit(msgType == MessageType::SendInit, PrepareStatusReport(StatusCode::kUnexpectedMessage));
533     }
534
535     err = transferInit.Parse(msgData.Retain());
536     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
537
538     ResolveTransferControlOptions(transferInit.TransferCtlOptions);
539     mTransferVersion      = ::chip::min(kBdxVersion, transferInit.Version);
540     mTransferMaxBlockSize = ::chip::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
541
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;
545
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;
555
556     mPendingMsgHandle = std::move(msgData);
557     mPendingOutput    = OutputEventType::kInitReceived;
558
559     mState = TransferState::kNegotiateTransferParams;
560
561 exit:
562     return;
563 }
564
565 void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
566 {
567     CHIP_ERROR err = CHIP_NO_ERROR;
568     ReceiveAccept rcvAcceptMsg;
569
570     VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
571     VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
572
573     err = rcvAcceptMsg.Parse(msgData.Retain());
574     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
575
576     // Verify that Accept parameters are compatible with the original proposed parameters
577     err = VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags);
578     SuccessOrExit(err);
579
580     mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
581     mStartOffset          = rcvAcceptMsg.StartOffset;
582     mTransferLength       = rcvAcceptMsg.Length;
583
584     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
585     // message
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;
592
593     mPendingMsgHandle = std::move(msgData);
594     mPendingOutput    = OutputEventType::kAcceptReceived;
595
596     mAwaitingResponse = (mControlMode == TransferControlFlags::kSenderDrive);
597     mState            = TransferState::kTransferInProgress;
598
599 exit:
600     return;
601 }
602
603 void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
604 {
605     CHIP_ERROR err = CHIP_NO_ERROR;
606     SendAccept sendAcceptMsg;
607
608     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
609     VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kUnexpectedMessage));
610
611     err = sendAcceptMsg.Parse(msgData.Retain());
612     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
613
614     // Verify that Accept parameters are compatible with the original proposed parameters
615     err = VerifyProposedMode(sendAcceptMsg.TransferCtlFlags);
616     SuccessOrExit(err);
617
618     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
619     // message
620     mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
621
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;
628
629     mPendingMsgHandle = std::move(msgData);
630     mPendingOutput    = OutputEventType::kAcceptReceived;
631
632     mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
633     mState            = TransferState::kTransferInProgress;
634
635 exit:
636     return;
637 }
638
639 void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
640 {
641     CHIP_ERROR err = CHIP_NO_ERROR;
642     BlockQuery query;
643
644     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
645     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
646     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
647
648     err = query.Parse(std::move(msgData));
649     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
650
651     VerifyOrExit(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
652
653     mPendingOutput = OutputEventType::kQueryReceived;
654
655     mAwaitingResponse = false;
656     mLastQueryNum     = query.BlockCounter;
657
658 exit:
659     return;
660 }
661
662 void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
663 {
664     CHIP_ERROR err = CHIP_NO_ERROR;
665     Block blockMsg;
666
667     VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
668     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
669     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
670
671     err = blockMsg.Parse(msgData.Retain());
672     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
673
674     VerifyOrExit(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
675     VerifyOrExit((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
676                  PrepareStatusReport(StatusCode::kBadMessageContents));
677
678     if (IsTransferLengthDefinite())
679     {
680         VerifyOrExit(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength, PrepareStatusReport(StatusCode::kLengthMismatch));
681     }
682
683     mBlockEventData.Data   = blockMsg.Data;
684     mBlockEventData.Length = blockMsg.DataLength;
685     mBlockEventData.IsEof  = false;
686
687     mPendingMsgHandle = std::move(msgData);
688     mPendingOutput    = OutputEventType::kBlockReceived;
689
690     mNumBytesProcessed += blockMsg.DataLength;
691     mLastBlockNum = blockMsg.BlockCounter;
692
693     mAwaitingResponse = false;
694
695 exit:
696     return;
697 }
698
699 void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
700 {
701     CHIP_ERROR err = CHIP_NO_ERROR;
702     BlockEOF blockEOFMsg;
703
704     VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kUnexpectedMessage));
705     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
706     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
707
708     err = blockEOFMsg.Parse(msgData.Retain());
709     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
710
711     VerifyOrExit(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
712     VerifyOrExit(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
713
714     mBlockEventData.Data   = blockEOFMsg.Data;
715     mBlockEventData.Length = blockEOFMsg.DataLength;
716     mBlockEventData.IsEof  = true;
717
718     mPendingMsgHandle = std::move(msgData);
719     mPendingOutput    = OutputEventType::kBlockReceived;
720
721     mNumBytesProcessed += blockEOFMsg.DataLength;
722     mLastBlockNum = blockEOFMsg.BlockCounter;
723
724     mAwaitingResponse = false;
725     mState            = TransferState::kReceivedEOF;
726
727 exit:
728     return;
729 }
730
731 void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
732 {
733     CHIP_ERROR err = CHIP_NO_ERROR;
734     BlockAck ackMsg;
735
736     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
737     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kUnexpectedMessage));
738     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
739
740     err = ackMsg.Parse(std::move(msgData));
741     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
742     VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
743
744     mPendingOutput = OutputEventType::kAckReceived;
745
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);
749
750 exit:
751     return;
752 }
753
754 void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
755 {
756     CHIP_ERROR err = CHIP_NO_ERROR;
757     BlockAckEOF ackMsg;
758
759     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kUnexpectedMessage));
760     VerifyOrExit(mState == TransferState::kAwaitingEOFAck, PrepareStatusReport(StatusCode::kUnexpectedMessage));
761     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kUnexpectedMessage));
762
763     err = ackMsg.Parse(std::move(msgData));
764     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
765     VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
766
767     mPendingOutput = OutputEventType::kAckEOFReceived;
768
769     mAwaitingResponse = false;
770
771     mState = TransferState::kTransferDone;
772
773 exit:
774     return;
775 }
776
777 void TransferSession::ResolveTransferControlOptions(const BitFlags<TransferControlFlags> & proposed)
778 {
779     // Must specify at least one synchronous option
780     //
781     if (!proposed.HasAny(TransferControlFlags::kSenderDrive, TransferControlFlags::kReceiverDrive))
782     {
783         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
784         return;
785     }
786
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())
791     {
792         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
793     }
794     else if (commonOpts.HasOnly(TransferControlFlags::kAsync))
795     {
796         mControlMode = TransferControlFlags::kAsync;
797     }
798     else if (commonOpts.HasOnly(TransferControlFlags::kReceiverDrive))
799     {
800         mControlMode = TransferControlFlags::kReceiverDrive;
801     }
802     else if (commonOpts.HasOnly(TransferControlFlags::kSenderDrive))
803     {
804         mControlMode = TransferControlFlags::kSenderDrive;
805     }
806 }
807
808 CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<TransferControlFlags> & proposed)
809 {
810     TransferControlFlags mode;
811
812     // Must specify only one mode in Accept messages
813     if (proposed.HasOnly(TransferControlFlags::kAsync))
814     {
815         mode = TransferControlFlags::kAsync;
816     }
817     else if (proposed.HasOnly(TransferControlFlags::kReceiverDrive))
818     {
819         mode = TransferControlFlags::kReceiverDrive;
820     }
821     else if (proposed.HasOnly(TransferControlFlags::kSenderDrive))
822     {
823         mode = TransferControlFlags::kSenderDrive;
824     }
825     else
826     {
827         PrepareStatusReport(StatusCode::kBadMessageContents);
828         return CHIP_ERROR_INTERNAL;
829     }
830
831     // Verify the proposed mode is supported by this instance
832     if (mSuppportedXferOpts.Has(mode))
833     {
834         mControlMode = mode;
835     }
836     else
837     {
838         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
839         return CHIP_ERROR_INTERNAL;
840     }
841
842     return CHIP_NO_ERROR;
843 }
844
845 void TransferSession::PrepareStatusReport(StatusCode code)
846 {
847     static_assert(std::is_same<std::underlying_type_t<decltype(code)>, uint16_t>::value, "Cast is not safe");
848
849     mStatusReportData.statusCode = code;
850
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);
856
857     report.WriteToBuffer(bbuf);
858     mPendingMsgHandle = bbuf.Finalize();
859     if (mPendingMsgHandle.IsNull())
860     {
861         mPendingOutput = OutputEventType::kInternalError;
862     }
863     else
864     {
865         CHIP_ERROR err = AttachHeader(Protocols::SecureChannel::MsgType::StatusReport, mPendingMsgHandle);
866         VerifyOrExit(err == CHIP_NO_ERROR, mPendingOutput = OutputEventType::kInternalError);
867         mPendingOutput = OutputEventType::kMsgToSend;
868     }
869
870 exit:
871     mState            = TransferState::kErrorState;
872     mAwaitingResponse = false; // Prevent triggering timeout
873 }
874
875 bool TransferSession::IsTransferLengthDefinite()
876 {
877     return (mTransferLength > 0);
878 }
879
880 TransferSession::OutputEvent TransferSession::OutputEvent::TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg)
881 {
882     OutputEvent event(OutputEventType::kInitReceived);
883     event.MsgData          = std::move(msg);
884     event.transferInitData = data;
885     return event;
886 }
887
888 /**
889  * @brief
890  *   Convenience method for constructing an OutputEvent with TransferAcceptData that does not contain Metadata
891  */
892 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data)
893 {
894     OutputEvent event(OutputEventType::kAcceptReceived);
895     event.transferAcceptData = data;
896     return event;
897 }
898 /**
899  * @brief
900  *   Convenience method for constructing an OutputEvent with TransferAcceptData that contains Metadata
901  */
902 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data,
903                                                                                System::PacketBufferHandle msg)
904 {
905     OutputEvent event = TransferAcceptEvent(data);
906     event.MsgData     = std::move(msg);
907     return event;
908 }
909
910 TransferSession::OutputEvent TransferSession::OutputEvent::BlockDataEvent(BlockData data, System::PacketBufferHandle msg)
911 {
912     OutputEvent event(OutputEventType::kBlockReceived);
913     event.MsgData   = std::move(msg);
914     event.blockdata = data;
915     return event;
916 }
917
918 /**
919  * @brief
920  *   Convenience method for constructing an event with kInternalError or kOutputStatusReceived
921  */
922 TransferSession::OutputEvent TransferSession::OutputEvent::StatusReportEvent(OutputEventType type, StatusReportData data)
923 {
924     OutputEvent event(type);
925     event.statusData = data;
926     return event;
927 }
928
929 } // namespace bdx
930 } // namespace chip