cea58bfbea2284d984d8e516d30a66728af2d647
[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/common/Constants.h>
12 #include <support/BufferReader.h>
13 #include <support/CodeUtils.h>
14 #include <support/ReturnMacros.h>
15 #include <system/SystemPacketBuffer.h>
16 #include <transport/SecureSessionMgr.h>
17
18 namespace {
19 constexpr uint8_t kBdxVersion         = 0;         ///< The version of this implementation of the BDX spec
20 constexpr size_t kStatusReportMinSize = 2 + 4 + 2; ///< 16 bits for GeneralCode, 32 bits for ProtocolId, 16 bits for ProtocolCode
21
22 /**
23  * @brief
24  *   Allocate a new PacketBuffer and write data from a BDX message struct.
25  */
26 CHIP_ERROR WriteToPacketBuffer(const ::chip::bdx::BdxMessage & msgStruct, ::chip::System::PacketBufferHandle & msgBuf)
27 {
28     size_t msgDataSize = msgStruct.MessageSize();
29     ::chip::Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(msgDataSize), msgDataSize);
30     if (bbuf.IsNull())
31     {
32         return CHIP_ERROR_NO_MEMORY;
33     }
34     msgStruct.WriteToBuffer(bbuf);
35     msgBuf = bbuf.Finalize();
36     if (msgBuf.IsNull())
37     {
38         return CHIP_ERROR_NO_MEMORY;
39     }
40     return CHIP_NO_ERROR;
41 }
42
43 // We could make this whole method a template, but it's probably smaller code to
44 // share the implementation across all message types.
45 CHIP_ERROR AttachHeader(uint16_t protocolId, uint8_t msgType, ::chip::System::PacketBufferHandle & msgBuf)
46 {
47     ::chip::PayloadHeader payloadHeader;
48
49     payloadHeader.SetMessageType(protocolId, msgType);
50
51     CHIP_ERROR err = payloadHeader.EncodeBeforeData(msgBuf);
52     SuccessOrExit(err);
53
54 exit:
55     return err;
56 }
57
58 template <typename MessageType>
59 inline CHIP_ERROR AttachHeader(MessageType msgType, ::chip::System::PacketBufferHandle & msgBuf)
60 {
61     return AttachHeader(chip::Protocols::MessageTypeTraits<MessageType>::ProtocolId, static_cast<uint8_t>(msgType), msgBuf);
62 }
63 } // anonymous namespace
64
65 namespace chip {
66 namespace bdx {
67
68 TransferSession::TransferSession()
69 {
70     mSuppportedXferOpts.SetRaw(0);
71 }
72
73 void TransferSession::PollOutput(OutputEvent & event, uint64_t curTimeMs)
74 {
75     event = OutputEvent(kNone);
76
77     if (mShouldInitTimeoutStart)
78     {
79         mTimeoutStartTimeMs     = curTimeMs;
80         mShouldInitTimeoutStart = false;
81     }
82
83     if (mAwaitingResponse && ((curTimeMs - mTimeoutStartTimeMs) >= mTimeoutMs))
84     {
85         event             = OutputEvent(kTransferTimeout);
86         mState            = kErrorState;
87         mAwaitingResponse = false;
88         return;
89     }
90
91     switch (mPendingOutput)
92     {
93     case kNone:
94         event = OutputEvent(kNone);
95         break;
96     case kInternalError:
97         event = OutputEvent::StatusReportEvent(kInternalError, mStatusReportData);
98         break;
99     case kStatusReceived:
100         event = OutputEvent::StatusReportEvent(kStatusReceived, mStatusReportData);
101         break;
102     case kMsgToSend:
103         event               = OutputEvent(kMsgToSend);
104         event.MsgData       = std::move(mPendingMsgHandle);
105         mTimeoutStartTimeMs = curTimeMs;
106         break;
107     case kInitReceived:
108         event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle));
109         break;
110     case kAcceptReceived:
111         event = OutputEvent::TransferAcceptEvent(mTransferAcceptData, std::move(mPendingMsgHandle));
112         break;
113     case kQueryReceived:
114         event = OutputEvent(kQueryReceived);
115         break;
116     case kBlockReceived:
117         event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle));
118         break;
119     case kAckReceived:
120         event = OutputEvent(kAckReceived);
121         break;
122     case kAckEOFReceived:
123         event = OutputEvent(kAckEOFReceived);
124         break;
125     default:
126         event = OutputEvent(kNone);
127         break;
128     }
129
130     // If there's no other pending output but an error occured or was received, then continue to output the error.
131     // This ensures that when the TransferSession encounters an error and needs to send a StatusReport, both a kMsgToSend and a
132     // kInternalError output event will be emitted.
133     if (event.EventType == kNone && mState == kErrorState)
134     {
135         event = OutputEvent::StatusReportEvent(kInternalError, mStatusReportData);
136     }
137
138     mPendingOutput = kNone;
139 }
140
141 CHIP_ERROR TransferSession::StartTransfer(TransferRole role, const TransferInitData & initData, uint32_t timeoutMs)
142 {
143     CHIP_ERROR err = CHIP_NO_ERROR;
144     MessageType msgType;
145     TransferInit initMsg;
146
147     VerifyOrExit(mState == kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
148
149     mRole      = role;
150     mTimeoutMs = timeoutMs;
151
152     // Set transfer parameters. They may be overridden later by an Accept message
153     mSuppportedXferOpts.SetRaw(initData.TransferCtlFlagsRaw);
154     mMaxSupportedBlockSize = initData.MaxBlockSize;
155     mStartOffset           = initData.StartOffset;
156     mTransferLength        = initData.Length;
157
158     // Prepare TransferInit message
159     initMsg.TransferCtlOptions.SetRaw(initData.TransferCtlFlagsRaw);
160     initMsg.Version        = kBdxVersion;
161     initMsg.MaxBlockSize   = mMaxSupportedBlockSize;
162     initMsg.StartOffset    = mStartOffset;
163     initMsg.MaxLength      = mTransferLength;
164     initMsg.FileDesignator = initData.FileDesignator;
165     initMsg.FileDesLength  = initData.FileDesLength;
166     initMsg.Metadata       = initData.Metadata;
167     initMsg.MetadataLength = initData.MetadataLength;
168
169     err = WriteToPacketBuffer(initMsg, mPendingMsgHandle);
170     SuccessOrExit(err);
171
172     msgType = (mRole == kRole_Sender) ? MessageType::SendInit : MessageType::ReceiveInit;
173     err     = AttachHeader(msgType, mPendingMsgHandle);
174     SuccessOrExit(err);
175
176     mState            = kAwaitingAccept;
177     mAwaitingResponse = true;
178
179     mPendingOutput = kMsgToSend;
180
181 exit:
182     return err;
183 }
184
185 CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags<uint8_t, TransferControlFlags> xferControlOpts,
186                                             uint16_t maxBlockSize, uint32_t timeoutMs)
187 {
188     CHIP_ERROR err = CHIP_NO_ERROR;
189
190     VerifyOrExit(mState == kUnitialized, err = CHIP_ERROR_INCORRECT_STATE);
191
192     // Used to determine compatibility with any future TransferInit parameters
193     mRole                  = role;
194     mTimeoutMs             = timeoutMs;
195     mSuppportedXferOpts    = xferControlOpts;
196     mMaxSupportedBlockSize = maxBlockSize;
197
198     mState = kAwaitingInitMsg;
199
200 exit:
201     return err;
202 }
203
204 CHIP_ERROR TransferSession::AcceptTransfer(const TransferAcceptData & acceptData)
205 {
206     CHIP_ERROR err = CHIP_NO_ERROR;
207     System::PacketBufferHandle outMsgBuf;
208     BitFlags<uint8_t, TransferControlFlags> proposedControlOpts;
209
210     VerifyOrExit(mState == kNegotiateTransferParams, err = CHIP_ERROR_INCORRECT_STATE);
211     VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
212
213     // Don't allow a Control method that wasn't supported by the initiator
214     // MaxBlockSize can't be larger than the proposed value
215     proposedControlOpts.SetRaw(mTransferRequestData.TransferCtlFlagsRaw);
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 == kRole_Sender)
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 = kMsgToSend;
258
259     mState = kTransferInProgress;
260
261     if ((mRole == kRole_Receiver && mControlMode == kControl_SenderDrive) ||
262         (mRole == kRole_Sender && mControlMode == kControl_ReceiverDrive))
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 == kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
277     VerifyOrExit(mRole == kRole_Receiver, err = CHIP_ERROR_INCORRECT_STATE);
278     VerifyOrExit(mPendingOutput == 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 = 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 == kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
305     VerifyOrExit(mRole == kRole_Sender, err = CHIP_ERROR_INCORRECT_STATE);
306     VerifyOrExit(mPendingOutput == 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 = kMsgToSend;
324
325     if (msgType == MessageType::BlockEOF)
326     {
327         mState = 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 == kRole_Receiver, err = CHIP_ERROR_INCORRECT_STATE);
344     VerifyOrExit((mState == kTransferInProgress) || (mState == kReceivedEOF), err = CHIP_ERROR_INCORRECT_STATE);
345     VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
346
347     ackMsg.BlockCounter = mLastBlockNum;
348     msgType             = (mState == kReceivedEOF) ? MessageType::BlockAckEOF : MessageType::BlockAck;
349
350     err = WriteToPacketBuffer(ackMsg, mPendingMsgHandle);
351     SuccessOrExit(err);
352
353     err = AttachHeader(msgType, mPendingMsgHandle);
354     SuccessOrExit(err);
355
356     if (mState == kTransferInProgress)
357     {
358         if (mControlMode == kControl_SenderDrive)
359         {
360             // In Sender Drive, a BlockAck is implied to also be a query for the next Block, so expect to receive a Block
361             // message.
362             mLastQueryNum     = ackMsg.BlockCounter + 1;
363             mAwaitingResponse = true;
364         }
365     }
366     else if (mState == kReceivedEOF)
367     {
368         mState            = kTransferDone;
369         mAwaitingResponse = false;
370     }
371
372     mPendingOutput = kMsgToSend;
373
374 exit:
375     return err;
376 }
377
378 CHIP_ERROR TransferSession::AbortTransfer(StatusCode reason)
379 {
380     CHIP_ERROR err = CHIP_NO_ERROR;
381
382     VerifyOrExit((mState != kUnitialized) && (mState != kTransferDone) && (mState != kErrorState),
383                  err = CHIP_ERROR_INCORRECT_STATE);
384
385     PrepareStatusReport(reason);
386
387 exit:
388     return err;
389 }
390
391 void TransferSession::Reset()
392 {
393     mPendingOutput = kNone;
394     mState         = kUnitialized;
395     mSuppportedXferOpts.SetRaw(0);
396     mTransferVersion       = 0;
397     mMaxSupportedBlockSize = 0;
398     mStartOffset           = 0;
399     mTransferLength        = 0;
400     mTransferMaxBlockSize  = 0;
401
402     mPendingMsgHandle = nullptr;
403
404     mNumBytesProcessed = 0;
405     mLastBlockNum      = 0;
406     mNextBlockNum      = 0;
407     mLastQueryNum      = 0;
408     mNextQueryNum      = 0;
409
410     mTimeoutMs              = 0;
411     mTimeoutStartTimeMs     = 0;
412     mShouldInitTimeoutStart = true;
413     mAwaitingResponse       = false;
414 }
415
416 CHIP_ERROR TransferSession::HandleMessageReceived(System::PacketBufferHandle msg, uint64_t curTimeMs)
417 {
418     CHIP_ERROR err = CHIP_NO_ERROR;
419     PayloadHeader payloadHeader;
420
421     VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
422
423     err = payloadHeader.DecodeAndConsume(msg);
424     SuccessOrExit(err);
425
426     if (payloadHeader.GetProtocolID() == Protocols::kProtocol_BDX)
427     {
428         err = HandleBdxMessage(payloadHeader, std::move(msg));
429         SuccessOrExit(err);
430
431         mTimeoutStartTimeMs = curTimeMs;
432     }
433     else if (payloadHeader.GetProtocolID() == Protocols::kProtocol_Protocol_Common &&
434              payloadHeader.GetMessageType() == static_cast<uint8_t>(Protocols::Common::MsgType::StatusReport))
435     {
436         err = HandleStatusReportMessage(payloadHeader, std::move(msg));
437         SuccessOrExit(err);
438     }
439     else
440     {
441         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
442     }
443
444 exit:
445     return err;
446 }
447
448 // Return CHIP_ERROR only if there was a problem decoding the message. Otherwise, call PrepareStatusReport().
449 CHIP_ERROR TransferSession::HandleBdxMessage(PayloadHeader & header, System::PacketBufferHandle msg)
450 {
451     CHIP_ERROR err      = CHIP_NO_ERROR;
452     MessageType msgType = static_cast<MessageType>(header.GetMessageType());
453
454     VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
455     VerifyOrExit(mPendingOutput == kNone, err = CHIP_ERROR_INCORRECT_STATE);
456
457     switch (msgType)
458     {
459     case MessageType::SendInit:
460     case MessageType::ReceiveInit:
461         HandleTransferInit(msgType, std::move(msg));
462         break;
463     case MessageType::SendAccept:
464         HandleSendAccept(std::move(msg));
465         break;
466     case MessageType::ReceiveAccept:
467         HandleReceiveAccept(std::move(msg));
468         break;
469     case MessageType::BlockQuery:
470         HandleBlockQuery(std::move(msg));
471         break;
472     case MessageType::Block:
473         HandleBlock(std::move(msg));
474         break;
475     case MessageType::BlockEOF:
476         HandleBlockEOF(std::move(msg));
477         break;
478     case MessageType::BlockAck:
479         HandleBlockAck(std::move(msg));
480         break;
481     case MessageType::BlockAckEOF:
482         HandleBlockAckEOF(std::move(msg));
483         break;
484     default:
485         err = CHIP_ERROR_INVALID_MESSAGE_TYPE;
486         break;
487     }
488
489 exit:
490     return err;
491 }
492
493 /**
494  * @brief
495  *   Parse a StatusReport message and prepare to emit an OutputEvent with the message data.
496  *
497  *   NOTE: BDX does not currently expect to ever use a "Success" general code, so it will be treated as an error along with any
498  *         other code.
499  */
500 CHIP_ERROR TransferSession::HandleStatusReportMessage(PayloadHeader & header, System::PacketBufferHandle msg)
501 {
502     VerifyOrReturnError(!msg.IsNull(), CHIP_ERROR_INVALID_ARGUMENT);
503
504     mState            = kErrorState;
505     mAwaitingResponse = false;
506
507     uint16_t generalCode  = 0;
508     uint32_t protocolId   = 0;
509     uint16_t protocolCode = 0;
510     Encoding::LittleEndian::Reader reader(msg->Start(), msg->DataLength());
511     ReturnErrorOnFailure(reader.Read16(&generalCode).Read32(&protocolId).Read16(&protocolCode).StatusCode());
512     VerifyOrReturnError((protocolId == Protocols::kProtocol_BDX), CHIP_ERROR_INVALID_MESSAGE_TYPE);
513
514     mStatusReportData.StatusCode = protocolCode;
515
516     mPendingOutput = kStatusReceived;
517
518     return CHIP_NO_ERROR;
519 }
520
521 void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
522 {
523     CHIP_ERROR err = CHIP_NO_ERROR;
524     TransferInit transferInit;
525
526     VerifyOrExit(mState == kAwaitingInitMsg, PrepareStatusReport(kStatus_ServerBadState));
527
528     if (mRole == kRole_Sender)
529     {
530         VerifyOrExit(msgType == MessageType::ReceiveInit, PrepareStatusReport(kStatus_ServerBadState));
531     }
532     else
533     {
534         VerifyOrExit(msgType == MessageType::SendInit, PrepareStatusReport(kStatus_ServerBadState));
535     }
536
537     err = transferInit.Parse(msgData.Retain());
538     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
539
540     ResolveTransferControlOptions(transferInit.TransferCtlOptions);
541     mTransferVersion      = ::chip::min(kBdxVersion, transferInit.Version);
542     mTransferMaxBlockSize = ::chip::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
543
544     // Accept for now, they may be changed or rejected by the peer if this is a ReceiveInit
545     mStartOffset    = transferInit.StartOffset;
546     mTransferLength = transferInit.MaxLength;
547
548     // Store the Request data to share with the caller for verification
549     mTransferRequestData.TransferCtlFlagsRaw = transferInit.TransferCtlOptions.Raw(),
550     mTransferRequestData.MaxBlockSize        = transferInit.MaxBlockSize;
551     mTransferRequestData.StartOffset         = transferInit.StartOffset;
552     mTransferRequestData.Length              = transferInit.MaxLength;
553     mTransferRequestData.FileDesignator      = transferInit.FileDesignator;
554     mTransferRequestData.FileDesLength       = transferInit.FileDesLength;
555     mTransferRequestData.Metadata            = transferInit.Metadata;
556     mTransferRequestData.MetadataLength      = transferInit.MetadataLength;
557
558     mPendingMsgHandle = std::move(msgData);
559     mPendingOutput    = kInitReceived;
560
561     mState = kNegotiateTransferParams;
562
563 exit:
564     return;
565 }
566
567 void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
568 {
569     CHIP_ERROR err = CHIP_NO_ERROR;
570     ReceiveAccept rcvAcceptMsg;
571
572     VerifyOrExit(mRole == kRole_Receiver, PrepareStatusReport(kStatus_ServerBadState));
573     VerifyOrExit(mState == kAwaitingAccept, PrepareStatusReport(kStatus_ServerBadState));
574
575     err = rcvAcceptMsg.Parse(msgData.Retain());
576     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
577
578     // Verify that Accept parameters are compatible with the original proposed parameters
579     err = VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags);
580     SuccessOrExit(err);
581
582     mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
583     mStartOffset          = rcvAcceptMsg.StartOffset;
584     mTransferLength       = rcvAcceptMsg.Length;
585
586     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
587     // message
588     mTransferAcceptData.ControlMode    = mControlMode;
589     mTransferAcceptData.MaxBlockSize   = rcvAcceptMsg.MaxBlockSize;
590     mTransferAcceptData.StartOffset    = rcvAcceptMsg.StartOffset;
591     mTransferAcceptData.Length         = rcvAcceptMsg.Length;
592     mTransferAcceptData.Metadata       = rcvAcceptMsg.Metadata;
593     mTransferAcceptData.MetadataLength = rcvAcceptMsg.MetadataLength;
594
595     mPendingMsgHandle = std::move(msgData);
596     mPendingOutput    = kAcceptReceived;
597
598     mAwaitingResponse = (mControlMode == kControl_SenderDrive);
599     mState            = kTransferInProgress;
600
601 exit:
602     return;
603 }
604
605 void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
606 {
607     CHIP_ERROR err = CHIP_NO_ERROR;
608     SendAccept sendAcceptMsg;
609
610     VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
611     VerifyOrExit(mState == kAwaitingAccept, PrepareStatusReport(kStatus_ServerBadState));
612
613     err = sendAcceptMsg.Parse(msgData.Retain());
614     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
615
616     // Verify that Accept parameters are compatible with the original proposed parameters
617     err = VerifyProposedMode(sendAcceptMsg.TransferCtlFlags);
618     SuccessOrExit(err);
619
620     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
621     // message
622     mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
623
624     mTransferAcceptData.ControlMode    = mControlMode;
625     mTransferAcceptData.MaxBlockSize   = sendAcceptMsg.MaxBlockSize;
626     mTransferAcceptData.StartOffset    = mStartOffset;    // Not included in SendAccept msg, so use member
627     mTransferAcceptData.Length         = mTransferLength; // Not included in SendAccept msg, so use member
628     mTransferAcceptData.Metadata       = sendAcceptMsg.Metadata;
629     mTransferAcceptData.MetadataLength = sendAcceptMsg.MetadataLength;
630
631     mPendingMsgHandle = std::move(msgData);
632     mPendingOutput    = kAcceptReceived;
633
634     mAwaitingResponse = (mControlMode == kControl_ReceiverDrive);
635     mState            = kTransferInProgress;
636
637 exit:
638     return;
639 }
640
641 void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
642 {
643     CHIP_ERROR err = CHIP_NO_ERROR;
644     BlockQuery query;
645
646     VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
647     VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
648     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
649
650     err = query.Parse(std::move(msgData));
651     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
652
653     VerifyOrExit(query.BlockCounter == mNextBlockNum, PrepareStatusReport(kStatus_BadBlockCounter));
654
655     mPendingOutput = kQueryReceived;
656
657     mAwaitingResponse = false;
658     mLastQueryNum     = query.BlockCounter;
659
660 exit:
661     return;
662 }
663
664 void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
665 {
666     CHIP_ERROR err = CHIP_NO_ERROR;
667     Block blockMsg;
668
669     VerifyOrExit(mRole == kRole_Receiver, PrepareStatusReport(kStatus_ServerBadState));
670     VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
671     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
672
673     err = blockMsg.Parse(msgData.Retain());
674     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
675
676     VerifyOrExit(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(kStatus_BadBlockCounter));
677     VerifyOrExit((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
678                  PrepareStatusReport(kStatus_BadMessageContents));
679
680     if (IsTransferLengthDefinite())
681     {
682         VerifyOrExit(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength, PrepareStatusReport(kStatus_LengthMismatch));
683     }
684
685     mBlockEventData.Data   = blockMsg.Data;
686     mBlockEventData.Length = blockMsg.DataLength;
687     mBlockEventData.IsEof  = false;
688
689     mPendingMsgHandle = std::move(msgData);
690     mPendingOutput    = kBlockReceived;
691
692     mNumBytesProcessed += blockMsg.DataLength;
693     mLastBlockNum = blockMsg.BlockCounter;
694
695     mAwaitingResponse = false;
696
697 exit:
698     return;
699 }
700
701 void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
702 {
703     CHIP_ERROR err = CHIP_NO_ERROR;
704     BlockEOF blockEOFMsg;
705
706     VerifyOrExit(mRole == kRole_Receiver, PrepareStatusReport(kStatus_ServerBadState));
707     VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
708     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
709
710     err = blockEOFMsg.Parse(msgData.Retain());
711     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
712
713     VerifyOrExit(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(kStatus_BadBlockCounter));
714     VerifyOrExit(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(kStatus_BadMessageContents));
715
716     mBlockEventData.Data   = blockEOFMsg.Data;
717     mBlockEventData.Length = blockEOFMsg.DataLength;
718     mBlockEventData.IsEof  = true;
719
720     mPendingMsgHandle = std::move(msgData);
721     mPendingOutput    = kBlockReceived;
722
723     mNumBytesProcessed += blockEOFMsg.DataLength;
724     mLastBlockNum = blockEOFMsg.BlockCounter;
725
726     mAwaitingResponse = false;
727     mState            = kReceivedEOF;
728
729 exit:
730     return;
731 }
732
733 void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
734 {
735     CHIP_ERROR err = CHIP_NO_ERROR;
736     BlockAck ackMsg;
737
738     VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
739     VerifyOrExit(mState == kTransferInProgress, PrepareStatusReport(kStatus_ServerBadState));
740     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
741
742     err = ackMsg.Parse(std::move(msgData));
743     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
744     VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(kStatus_BadBlockCounter));
745
746     mPendingOutput = kAckReceived;
747
748     // In Receiver Drive, the Receiver can send a BlockAck to indicate receipt of the message and reset the timeout.
749     // In this case, the Sender should wait to receive a BlockQuery next.
750     mAwaitingResponse = (mControlMode == kControl_ReceiverDrive);
751
752 exit:
753     return;
754 }
755
756 void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
757 {
758     CHIP_ERROR err = CHIP_NO_ERROR;
759     BlockAckEOF ackMsg;
760
761     VerifyOrExit(mRole == kRole_Sender, PrepareStatusReport(kStatus_ServerBadState));
762     VerifyOrExit(mState == kAwaitingEOFAck, PrepareStatusReport(kStatus_ServerBadState));
763     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(kStatus_ServerBadState));
764
765     err = ackMsg.Parse(std::move(msgData));
766     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(kStatus_BadMessageContents));
767     VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(kStatus_BadBlockCounter));
768
769     mPendingOutput = kAckEOFReceived;
770
771     mAwaitingResponse = false;
772
773     mState = kTransferDone;
774
775 exit:
776     return;
777 }
778
779 void TransferSession::ResolveTransferControlOptions(const BitFlags<uint8_t, TransferControlFlags> & proposed)
780 {
781     // Must specify at least one synchronous option
782     if (!proposed.Has(kControl_SenderDrive) && !proposed.Has(kControl_ReceiverDrive))
783     {
784         PrepareStatusReport(kStatus_TransferMethodNotSupported);
785         return;
786     }
787
788     // Ensure there are options supported by both nodes. Async gets priority.
789     // If there is only one common option, choose that one. Otherwise the application must pick.
790     BitFlags<uint8_t, TransferControlFlags> commonOpts;
791     commonOpts.SetRaw(proposed.Raw() & mSuppportedXferOpts.Raw());
792     if (commonOpts.Raw() == 0)
793     {
794         PrepareStatusReport(kStatus_TransferMethodNotSupported);
795     }
796     else if (commonOpts.HasOnly(kControl_Async))
797     {
798         mControlMode = kControl_Async;
799     }
800     else if (commonOpts.HasOnly(kControl_ReceiverDrive))
801     {
802         mControlMode = kControl_ReceiverDrive;
803     }
804     else if (commonOpts.HasOnly(kControl_SenderDrive))
805     {
806         mControlMode = kControl_SenderDrive;
807     }
808 }
809
810 CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<uint8_t, TransferControlFlags> & proposed)
811 {
812     TransferControlFlags mode;
813
814     // Must specify only one mode in Accept messages
815     if (proposed.HasOnly(kControl_Async))
816     {
817         mode = kControl_Async;
818     }
819     else if (proposed.HasOnly(kControl_ReceiverDrive))
820     {
821         mode = kControl_ReceiverDrive;
822     }
823     else if (proposed.HasOnly(kControl_SenderDrive))
824     {
825         mode = kControl_SenderDrive;
826     }
827     else
828     {
829         PrepareStatusReport(kStatus_BadMessageContents);
830         return CHIP_ERROR_INTERNAL;
831     }
832
833     // Verify the proposed mode is supported by this instance
834     if (mSuppportedXferOpts.Has(mode))
835     {
836         mControlMode = mode;
837     }
838     else
839     {
840         PrepareStatusReport(kStatus_TransferMethodNotSupported);
841         return CHIP_ERROR_INTERNAL;
842     }
843
844     return CHIP_NO_ERROR;
845 }
846
847 void TransferSession::PrepareStatusReport(StatusCode code)
848 {
849     mStatusReportData.StatusCode = code;
850
851     Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(kStatusReportMinSize), kStatusReportMinSize);
852     VerifyOrReturn(!bbuf.IsNull());
853
854     bbuf.Put16(static_cast<uint16_t>(Protocols::Common::StatusCode::Failure));
855     bbuf.Put32(Protocols::kProtocol_BDX);
856     bbuf.Put16(mStatusReportData.StatusCode);
857
858     mPendingMsgHandle = bbuf.Finalize();
859     if (mPendingMsgHandle.IsNull())
860     {
861         mPendingOutput = kInternalError;
862     }
863     else
864     {
865         CHIP_ERROR err = AttachHeader(Protocols::Common::MsgType::StatusReport, mPendingMsgHandle);
866         VerifyOrReturn(err == CHIP_NO_ERROR);
867
868         mPendingOutput = kMsgToSend;
869     }
870
871     mState            = 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(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(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(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