Apply Upstream code (2021-03-15)
[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.ClearAll();
71 }
72
73 void TransferSession::PollOutput(OutputEvent & event, uint64_t curTimeMs)
74 {
75     event = OutputEvent(OutputEventType::kNone);
76
77     if (mShouldInitTimeoutStart)
78     {
79         mTimeoutStartTimeMs     = curTimeMs;
80         mShouldInitTimeoutStart = false;
81     }
82
83     if (mAwaitingResponse && ((curTimeMs - mTimeoutStartTimeMs) >= mTimeoutMs))
84     {
85         event             = OutputEvent(OutputEventType::kTransferTimeout);
86         mState            = TransferState::kErrorState;
87         mAwaitingResponse = false;
88         return;
89     }
90
91     switch (mPendingOutput)
92     {
93     case OutputEventType::kNone:
94         event = OutputEvent(OutputEventType::kNone);
95         break;
96     case OutputEventType::kInternalError:
97         event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
98         break;
99     case OutputEventType::kStatusReceived:
100         event = OutputEvent::StatusReportEvent(OutputEventType::kStatusReceived, mStatusReportData);
101         break;
102     case OutputEventType::kMsgToSend:
103         event               = OutputEvent(OutputEventType::kMsgToSend);
104         event.MsgData       = std::move(mPendingMsgHandle);
105         mTimeoutStartTimeMs = curTimeMs;
106         break;
107     case OutputEventType::kInitReceived:
108         event = OutputEvent::TransferInitEvent(mTransferRequestData, std::move(mPendingMsgHandle));
109         break;
110     case OutputEventType::kAcceptReceived:
111         event = OutputEvent::TransferAcceptEvent(mTransferAcceptData, std::move(mPendingMsgHandle));
112         break;
113     case OutputEventType::kQueryReceived:
114         event = OutputEvent(OutputEventType::kQueryReceived);
115         break;
116     case OutputEventType::kBlockReceived:
117         event = OutputEvent::BlockDataEvent(mBlockEventData, std::move(mPendingMsgHandle));
118         break;
119     case OutputEventType::kAckReceived:
120         event = OutputEvent(OutputEventType::kAckReceived);
121         break;
122     case OutputEventType::kAckEOFReceived:
123         event = OutputEvent(OutputEventType::kAckEOFReceived);
124         break;
125     default:
126         event = OutputEvent(OutputEventType::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 == OutputEventType::kNone && mState == TransferState::kErrorState)
134     {
135         event = OutputEvent::StatusReportEvent(OutputEventType::kInternalError, mStatusReportData);
136     }
137
138     mPendingOutput = OutputEventType::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 == TransferState::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    = initData.TransferCtlFlags;
154     mMaxSupportedBlockSize = initData.MaxBlockSize;
155     mStartOffset           = initData.StartOffset;
156     mTransferLength        = initData.Length;
157
158     // Prepare TransferInit message
159     initMsg.TransferCtlOptions = initData.TransferCtlFlags;
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 == TransferRole::kSender) ? MessageType::SendInit : MessageType::ReceiveInit;
173     err     = AttachHeader(msgType, mPendingMsgHandle);
174     SuccessOrExit(err);
175
176     mState            = TransferState::kAwaitingAccept;
177     mAwaitingResponse = true;
178
179     mPendingOutput = OutputEventType::kMsgToSend;
180
181 exit:
182     return err;
183 }
184
185 CHIP_ERROR TransferSession::WaitForTransfer(TransferRole role, BitFlags<TransferControlFlags> xferControlOpts,
186                                             uint16_t maxBlockSize, uint32_t timeoutMs)
187 {
188     CHIP_ERROR err = CHIP_NO_ERROR;
189
190     VerifyOrExit(mState == TransferState::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 = TransferState::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     const BitFlags<TransferControlFlags> proposedControlOpts(mTransferRequestData.TransferCtlFlags);
209
210     VerifyOrExit(mState == TransferState::kNegotiateTransferParams, err = CHIP_ERROR_INCORRECT_STATE);
211     VerifyOrExit(mPendingOutput == OutputEventType::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     VerifyOrExit(proposedControlOpts.Has(acceptData.ControlMode), err = CHIP_ERROR_INVALID_ARGUMENT);
216     VerifyOrExit(acceptData.MaxBlockSize <= mTransferRequestData.MaxBlockSize, err = CHIP_ERROR_INVALID_ARGUMENT);
217
218     mTransferMaxBlockSize = acceptData.MaxBlockSize;
219
220     if (mRole == TransferRole::kSender)
221     {
222         mStartOffset    = acceptData.StartOffset;
223         mTransferLength = acceptData.Length;
224
225         ReceiveAccept acceptMsg;
226         acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
227         acceptMsg.Version        = mTransferVersion;
228         acceptMsg.MaxBlockSize   = acceptData.MaxBlockSize;
229         acceptMsg.StartOffset    = acceptData.StartOffset;
230         acceptMsg.Length         = acceptData.Length;
231         acceptMsg.Metadata       = acceptData.Metadata;
232         acceptMsg.MetadataLength = acceptData.MetadataLength;
233
234         err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
235         SuccessOrExit(err);
236
237         err = AttachHeader(MessageType::ReceiveAccept, mPendingMsgHandle);
238         SuccessOrExit(err);
239     }
240     else
241     {
242         SendAccept acceptMsg;
243         acceptMsg.TransferCtlFlags.Set(acceptData.ControlMode);
244         acceptMsg.Version        = mTransferVersion;
245         acceptMsg.MaxBlockSize   = acceptData.MaxBlockSize;
246         acceptMsg.Metadata       = acceptData.Metadata;
247         acceptMsg.MetadataLength = acceptData.MetadataLength;
248
249         err = WriteToPacketBuffer(acceptMsg, mPendingMsgHandle);
250         SuccessOrExit(err);
251
252         err = AttachHeader(MessageType::SendAccept, mPendingMsgHandle);
253         SuccessOrExit(err);
254     }
255
256     mPendingOutput = OutputEventType::kMsgToSend;
257
258     mState = TransferState::kTransferInProgress;
259
260     if ((mRole == TransferRole::kReceiver && mControlMode == TransferControlFlags::kSenderDrive) ||
261         (mRole == TransferRole::kSender && mControlMode == TransferControlFlags::kReceiverDrive))
262     {
263         mAwaitingResponse = true;
264     }
265
266 exit:
267     return err;
268 }
269
270 CHIP_ERROR TransferSession::PrepareBlockQuery()
271 {
272     CHIP_ERROR err = CHIP_NO_ERROR;
273     BlockQuery queryMsg;
274
275     VerifyOrExit(mState == TransferState::kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
276     VerifyOrExit(mRole == TransferRole::kReceiver, err = CHIP_ERROR_INCORRECT_STATE);
277     VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
278     VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
279
280     queryMsg.BlockCounter = mNextQueryNum;
281
282     err = WriteToPacketBuffer(queryMsg, mPendingMsgHandle);
283     SuccessOrExit(err);
284
285     err = AttachHeader(MessageType::BlockQuery, mPendingMsgHandle);
286     SuccessOrExit(err);
287
288     mPendingOutput = OutputEventType::kMsgToSend;
289
290     mAwaitingResponse = true;
291     mLastQueryNum     = mNextQueryNum++;
292
293 exit:
294     return err;
295 }
296
297 CHIP_ERROR TransferSession::PrepareBlock(const BlockData & inData)
298 {
299     CHIP_ERROR err = CHIP_NO_ERROR;
300     DataBlock blockMsg;
301     MessageType msgType;
302
303     VerifyOrExit(mState == TransferState::kTransferInProgress, err = CHIP_ERROR_INCORRECT_STATE);
304     VerifyOrExit(mRole == TransferRole::kSender, err = CHIP_ERROR_INCORRECT_STATE);
305     VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
306     VerifyOrExit(!mAwaitingResponse, err = CHIP_ERROR_INCORRECT_STATE);
307
308     // Verify non-zero data is provided and is no longer than MaxBlockSize (BlockEOF may contain 0 length data)
309     VerifyOrExit((inData.Data != nullptr) && (inData.Length <= mTransferMaxBlockSize), err = CHIP_ERROR_INVALID_ARGUMENT);
310
311     blockMsg.BlockCounter = mNextBlockNum;
312     blockMsg.Data         = inData.Data;
313     blockMsg.DataLength   = inData.Length;
314
315     err = WriteToPacketBuffer(blockMsg, mPendingMsgHandle);
316     SuccessOrExit(err);
317
318     msgType = inData.IsEof ? MessageType::BlockEOF : MessageType::Block;
319     err     = AttachHeader(msgType, mPendingMsgHandle);
320     SuccessOrExit(err);
321
322     mPendingOutput = OutputEventType::kMsgToSend;
323
324     if (msgType == MessageType::BlockEOF)
325     {
326         mState = TransferState::kAwaitingEOFAck;
327     }
328
329     mAwaitingResponse = true;
330     mLastBlockNum     = mNextBlockNum++;
331
332 exit:
333     return err;
334 }
335
336 CHIP_ERROR TransferSession::PrepareBlockAck()
337 {
338     CHIP_ERROR err = CHIP_NO_ERROR;
339     CounterMessage ackMsg;
340     MessageType msgType;
341
342     VerifyOrExit(mRole == TransferRole::kReceiver, err = CHIP_ERROR_INCORRECT_STATE);
343     VerifyOrExit((mState == TransferState::kTransferInProgress) || (mState == TransferState::kReceivedEOF),
344                  err = CHIP_ERROR_INCORRECT_STATE);
345     VerifyOrExit(mPendingOutput == OutputEventType::kNone, err = CHIP_ERROR_INCORRECT_STATE);
346
347     ackMsg.BlockCounter = mLastBlockNum;
348     msgType             = (mState == TransferState::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 == TransferState::kTransferInProgress)
357     {
358         if (mControlMode == TransferControlFlags::kSenderDrive)
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 == TransferState::kReceivedEOF)
367     {
368         mState            = TransferState::kTransferDone;
369         mAwaitingResponse = false;
370     }
371
372     mPendingOutput = OutputEventType::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 != TransferState::kUnitialized) && (mState != TransferState::kTransferDone) &&
383                      (mState != TransferState::kErrorState),
384                  err = CHIP_ERROR_INCORRECT_STATE);
385
386     PrepareStatusReport(reason);
387
388 exit:
389     return err;
390 }
391
392 void TransferSession::Reset()
393 {
394     mPendingOutput = OutputEventType::kNone;
395     mState         = TransferState::kUnitialized;
396     mSuppportedXferOpts.ClearAll();
397     mTransferVersion       = 0;
398     mMaxSupportedBlockSize = 0;
399     mStartOffset           = 0;
400     mTransferLength        = 0;
401     mTransferMaxBlockSize  = 0;
402
403     mPendingMsgHandle = nullptr;
404
405     mNumBytesProcessed = 0;
406     mLastBlockNum      = 0;
407     mNextBlockNum      = 0;
408     mLastQueryNum      = 0;
409     mNextQueryNum      = 0;
410
411     mTimeoutMs              = 0;
412     mTimeoutStartTimeMs     = 0;
413     mShouldInitTimeoutStart = true;
414     mAwaitingResponse       = false;
415 }
416
417 CHIP_ERROR TransferSession::HandleMessageReceived(System::PacketBufferHandle msg, uint64_t curTimeMs)
418 {
419     CHIP_ERROR err = CHIP_NO_ERROR;
420     PayloadHeader payloadHeader;
421
422     VerifyOrExit(!msg.IsNull(), err = CHIP_ERROR_INVALID_ARGUMENT);
423
424     err = payloadHeader.DecodeAndConsume(msg);
425     SuccessOrExit(err);
426
427     if (payloadHeader.GetProtocolID() == Protocols::kProtocol_BDX)
428     {
429         err = HandleBdxMessage(payloadHeader, std::move(msg));
430         SuccessOrExit(err);
431
432         mTimeoutStartTimeMs = curTimeMs;
433     }
434     else if (payloadHeader.GetProtocolID() == Protocols::kProtocol_Protocol_Common &&
435              payloadHeader.GetMessageType() == static_cast<uint8_t>(Protocols::Common::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     uint16_t generalCode  = 0;
509     uint32_t protocolId   = 0;
510     uint16_t protocolCode = 0;
511     Encoding::LittleEndian::Reader reader(msg->Start(), msg->DataLength());
512     ReturnErrorOnFailure(reader.Read16(&generalCode).Read32(&protocolId).Read16(&protocolCode).StatusCode());
513     VerifyOrReturnError((protocolId == Protocols::kProtocol_BDX), CHIP_ERROR_INVALID_MESSAGE_TYPE);
514
515     mStatusReportData.statusCode = static_cast<StatusCode>(protocolCode);
516
517     mPendingOutput = OutputEventType::kStatusReceived;
518
519     return CHIP_NO_ERROR;
520 }
521
522 void TransferSession::HandleTransferInit(MessageType msgType, System::PacketBufferHandle msgData)
523 {
524     CHIP_ERROR err = CHIP_NO_ERROR;
525     TransferInit transferInit;
526
527     VerifyOrExit(mState == TransferState::kAwaitingInitMsg, PrepareStatusReport(StatusCode::kServerBadState));
528
529     if (mRole == TransferRole::kSender)
530     {
531         VerifyOrExit(msgType == MessageType::ReceiveInit, PrepareStatusReport(StatusCode::kServerBadState));
532     }
533     else
534     {
535         VerifyOrExit(msgType == MessageType::SendInit, PrepareStatusReport(StatusCode::kServerBadState));
536     }
537
538     err = transferInit.Parse(msgData.Retain());
539     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
540
541     ResolveTransferControlOptions(transferInit.TransferCtlOptions);
542     mTransferVersion      = ::chip::min(kBdxVersion, transferInit.Version);
543     mTransferMaxBlockSize = ::chip::min(mMaxSupportedBlockSize, transferInit.MaxBlockSize);
544
545     // Accept for now, they may be changed or rejected by the peer if this is a ReceiveInit
546     mStartOffset    = transferInit.StartOffset;
547     mTransferLength = transferInit.MaxLength;
548
549     // Store the Request data to share with the caller for verification
550     mTransferRequestData.TransferCtlFlags = transferInit.TransferCtlOptions;
551     mTransferRequestData.MaxBlockSize     = transferInit.MaxBlockSize;
552     mTransferRequestData.StartOffset      = transferInit.StartOffset;
553     mTransferRequestData.Length           = transferInit.MaxLength;
554     mTransferRequestData.FileDesignator   = transferInit.FileDesignator;
555     mTransferRequestData.FileDesLength    = transferInit.FileDesLength;
556     mTransferRequestData.Metadata         = transferInit.Metadata;
557     mTransferRequestData.MetadataLength   = transferInit.MetadataLength;
558
559     mPendingMsgHandle = std::move(msgData);
560     mPendingOutput    = OutputEventType::kInitReceived;
561
562     mState = TransferState::kNegotiateTransferParams;
563
564 exit:
565     return;
566 }
567
568 void TransferSession::HandleReceiveAccept(System::PacketBufferHandle msgData)
569 {
570     CHIP_ERROR err = CHIP_NO_ERROR;
571     ReceiveAccept rcvAcceptMsg;
572
573     VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kServerBadState));
574     VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kServerBadState));
575
576     err = rcvAcceptMsg.Parse(msgData.Retain());
577     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
578
579     // Verify that Accept parameters are compatible with the original proposed parameters
580     err = VerifyProposedMode(rcvAcceptMsg.TransferCtlFlags);
581     SuccessOrExit(err);
582
583     mTransferMaxBlockSize = rcvAcceptMsg.MaxBlockSize;
584     mStartOffset          = rcvAcceptMsg.StartOffset;
585     mTransferLength       = rcvAcceptMsg.Length;
586
587     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the ReceiveAccept
588     // message
589     mTransferAcceptData.ControlMode    = mControlMode;
590     mTransferAcceptData.MaxBlockSize   = rcvAcceptMsg.MaxBlockSize;
591     mTransferAcceptData.StartOffset    = rcvAcceptMsg.StartOffset;
592     mTransferAcceptData.Length         = rcvAcceptMsg.Length;
593     mTransferAcceptData.Metadata       = rcvAcceptMsg.Metadata;
594     mTransferAcceptData.MetadataLength = rcvAcceptMsg.MetadataLength;
595
596     mPendingMsgHandle = std::move(msgData);
597     mPendingOutput    = OutputEventType::kAcceptReceived;
598
599     mAwaitingResponse = (mControlMode == TransferControlFlags::kSenderDrive);
600     mState            = TransferState::kTransferInProgress;
601
602 exit:
603     return;
604 }
605
606 void TransferSession::HandleSendAccept(System::PacketBufferHandle msgData)
607 {
608     CHIP_ERROR err = CHIP_NO_ERROR;
609     SendAccept sendAcceptMsg;
610
611     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
612     VerifyOrExit(mState == TransferState::kAwaitingAccept, PrepareStatusReport(StatusCode::kServerBadState));
613
614     err = sendAcceptMsg.Parse(msgData.Retain());
615     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
616
617     // Verify that Accept parameters are compatible with the original proposed parameters
618     err = VerifyProposedMode(sendAcceptMsg.TransferCtlFlags);
619     SuccessOrExit(err);
620
621     // Note: if VerifyProposedMode() returned with no error, then mControlMode must match the proposed mode in the SendAccept
622     // message
623     mTransferMaxBlockSize = sendAcceptMsg.MaxBlockSize;
624
625     mTransferAcceptData.ControlMode    = mControlMode;
626     mTransferAcceptData.MaxBlockSize   = sendAcceptMsg.MaxBlockSize;
627     mTransferAcceptData.StartOffset    = mStartOffset;    // Not included in SendAccept msg, so use member
628     mTransferAcceptData.Length         = mTransferLength; // Not included in SendAccept msg, so use member
629     mTransferAcceptData.Metadata       = sendAcceptMsg.Metadata;
630     mTransferAcceptData.MetadataLength = sendAcceptMsg.MetadataLength;
631
632     mPendingMsgHandle = std::move(msgData);
633     mPendingOutput    = OutputEventType::kAcceptReceived;
634
635     mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
636     mState            = TransferState::kTransferInProgress;
637
638 exit:
639     return;
640 }
641
642 void TransferSession::HandleBlockQuery(System::PacketBufferHandle msgData)
643 {
644     CHIP_ERROR err = CHIP_NO_ERROR;
645     BlockQuery query;
646
647     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
648     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
649     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
650
651     err = query.Parse(std::move(msgData));
652     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
653
654     VerifyOrExit(query.BlockCounter == mNextBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
655
656     mPendingOutput = OutputEventType::kQueryReceived;
657
658     mAwaitingResponse = false;
659     mLastQueryNum     = query.BlockCounter;
660
661 exit:
662     return;
663 }
664
665 void TransferSession::HandleBlock(System::PacketBufferHandle msgData)
666 {
667     CHIP_ERROR err = CHIP_NO_ERROR;
668     Block blockMsg;
669
670     VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kServerBadState));
671     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
672     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
673
674     err = blockMsg.Parse(msgData.Retain());
675     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
676
677     VerifyOrExit(blockMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
678     VerifyOrExit((blockMsg.DataLength > 0) && (blockMsg.DataLength <= mTransferMaxBlockSize),
679                  PrepareStatusReport(StatusCode::kBadMessageContents));
680
681     if (IsTransferLengthDefinite())
682     {
683         VerifyOrExit(mNumBytesProcessed + blockMsg.DataLength <= mTransferLength, PrepareStatusReport(StatusCode::kLengthMismatch));
684     }
685
686     mBlockEventData.Data   = blockMsg.Data;
687     mBlockEventData.Length = blockMsg.DataLength;
688     mBlockEventData.IsEof  = false;
689
690     mPendingMsgHandle = std::move(msgData);
691     mPendingOutput    = OutputEventType::kBlockReceived;
692
693     mNumBytesProcessed += blockMsg.DataLength;
694     mLastBlockNum = blockMsg.BlockCounter;
695
696     mAwaitingResponse = false;
697
698 exit:
699     return;
700 }
701
702 void TransferSession::HandleBlockEOF(System::PacketBufferHandle msgData)
703 {
704     CHIP_ERROR err = CHIP_NO_ERROR;
705     BlockEOF blockEOFMsg;
706
707     VerifyOrExit(mRole == TransferRole::kReceiver, PrepareStatusReport(StatusCode::kServerBadState));
708     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
709     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
710
711     err = blockEOFMsg.Parse(msgData.Retain());
712     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
713
714     VerifyOrExit(blockEOFMsg.BlockCounter == mLastQueryNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
715     VerifyOrExit(blockEOFMsg.DataLength <= mTransferMaxBlockSize, PrepareStatusReport(StatusCode::kBadMessageContents));
716
717     mBlockEventData.Data   = blockEOFMsg.Data;
718     mBlockEventData.Length = blockEOFMsg.DataLength;
719     mBlockEventData.IsEof  = true;
720
721     mPendingMsgHandle = std::move(msgData);
722     mPendingOutput    = OutputEventType::kBlockReceived;
723
724     mNumBytesProcessed += blockEOFMsg.DataLength;
725     mLastBlockNum = blockEOFMsg.BlockCounter;
726
727     mAwaitingResponse = false;
728     mState            = TransferState::kReceivedEOF;
729
730 exit:
731     return;
732 }
733
734 void TransferSession::HandleBlockAck(System::PacketBufferHandle msgData)
735 {
736     CHIP_ERROR err = CHIP_NO_ERROR;
737     BlockAck ackMsg;
738
739     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
740     VerifyOrExit(mState == TransferState::kTransferInProgress, PrepareStatusReport(StatusCode::kServerBadState));
741     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
742
743     err = ackMsg.Parse(std::move(msgData));
744     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
745     VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
746
747     mPendingOutput = OutputEventType::kAckReceived;
748
749     // In Receiver Drive, the Receiver can send a BlockAck to indicate receipt of the message and reset the timeout.
750     // In this case, the Sender should wait to receive a BlockQuery next.
751     mAwaitingResponse = (mControlMode == TransferControlFlags::kReceiverDrive);
752
753 exit:
754     return;
755 }
756
757 void TransferSession::HandleBlockAckEOF(System::PacketBufferHandle msgData)
758 {
759     CHIP_ERROR err = CHIP_NO_ERROR;
760     BlockAckEOF ackMsg;
761
762     VerifyOrExit(mRole == TransferRole::kSender, PrepareStatusReport(StatusCode::kServerBadState));
763     VerifyOrExit(mState == TransferState::kAwaitingEOFAck, PrepareStatusReport(StatusCode::kServerBadState));
764     VerifyOrExit(mAwaitingResponse, PrepareStatusReport(StatusCode::kServerBadState));
765
766     err = ackMsg.Parse(std::move(msgData));
767     VerifyOrExit(err == CHIP_NO_ERROR, PrepareStatusReport(StatusCode::kBadMessageContents));
768     VerifyOrExit(ackMsg.BlockCounter == mLastBlockNum, PrepareStatusReport(StatusCode::kBadBlockCounter));
769
770     mPendingOutput = OutputEventType::kAckEOFReceived;
771
772     mAwaitingResponse = false;
773
774     mState = TransferState::kTransferDone;
775
776 exit:
777     return;
778 }
779
780 void TransferSession::ResolveTransferControlOptions(const BitFlags<TransferControlFlags> & proposed)
781 {
782     // Must specify at least one synchronous option
783     //
784     if (!proposed.HasAny(TransferControlFlags::kSenderDrive, TransferControlFlags::kReceiverDrive))
785     {
786         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
787         return;
788     }
789
790     // Ensure there are options supported by both nodes. Async gets priority.
791     // If there is only one common option, choose that one. Otherwise the application must pick.
792     const BitFlags<TransferControlFlags> commonOpts(proposed & mSuppportedXferOpts);
793     if (!commonOpts.HasAny())
794     {
795         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
796     }
797     else if (commonOpts.HasOnly(TransferControlFlags::kAsync))
798     {
799         mControlMode = TransferControlFlags::kAsync;
800     }
801     else if (commonOpts.HasOnly(TransferControlFlags::kReceiverDrive))
802     {
803         mControlMode = TransferControlFlags::kReceiverDrive;
804     }
805     else if (commonOpts.HasOnly(TransferControlFlags::kSenderDrive))
806     {
807         mControlMode = TransferControlFlags::kSenderDrive;
808     }
809 }
810
811 CHIP_ERROR TransferSession::VerifyProposedMode(const BitFlags<TransferControlFlags> & proposed)
812 {
813     TransferControlFlags mode;
814
815     // Must specify only one mode in Accept messages
816     if (proposed.HasOnly(TransferControlFlags::kAsync))
817     {
818         mode = TransferControlFlags::kAsync;
819     }
820     else if (proposed.HasOnly(TransferControlFlags::kReceiverDrive))
821     {
822         mode = TransferControlFlags::kReceiverDrive;
823     }
824     else if (proposed.HasOnly(TransferControlFlags::kSenderDrive))
825     {
826         mode = TransferControlFlags::kSenderDrive;
827     }
828     else
829     {
830         PrepareStatusReport(StatusCode::kBadMessageContents);
831         return CHIP_ERROR_INTERNAL;
832     }
833
834     // Verify the proposed mode is supported by this instance
835     if (mSuppportedXferOpts.Has(mode))
836     {
837         mControlMode = mode;
838     }
839     else
840     {
841         PrepareStatusReport(StatusCode::kTransferMethodNotSupported);
842         return CHIP_ERROR_INTERNAL;
843     }
844
845     return CHIP_NO_ERROR;
846 }
847
848 void TransferSession::PrepareStatusReport(StatusCode code)
849 {
850     mStatusReportData.statusCode = code;
851
852     Encoding::LittleEndian::PacketBufferWriter bbuf(chip::MessagePacketBuffer::New(kStatusReportMinSize), kStatusReportMinSize);
853     VerifyOrReturn(!bbuf.IsNull());
854
855     bbuf.Put16(static_cast<uint16_t>(Protocols::Common::StatusCode::Failure));
856     bbuf.Put32(Protocols::kProtocol_BDX);
857     bbuf.Put16(static_cast<uint16_t>(mStatusReportData.statusCode));
858
859     mPendingMsgHandle = bbuf.Finalize();
860     if (mPendingMsgHandle.IsNull())
861     {
862         mPendingOutput = OutputEventType::kInternalError;
863     }
864     else
865     {
866         CHIP_ERROR err = AttachHeader(Protocols::Common::MsgType::StatusReport, mPendingMsgHandle);
867         VerifyOrReturn(err == CHIP_NO_ERROR);
868
869         mPendingOutput = OutputEventType::kMsgToSend;
870     }
871
872     mState            = TransferState::kErrorState;
873     mAwaitingResponse = false; // Prevent triggering timeout
874 }
875
876 bool TransferSession::IsTransferLengthDefinite()
877 {
878     return (mTransferLength > 0);
879 }
880
881 TransferSession::OutputEvent TransferSession::OutputEvent::TransferInitEvent(TransferInitData data, System::PacketBufferHandle msg)
882 {
883     OutputEvent event(OutputEventType::kInitReceived);
884     event.MsgData          = std::move(msg);
885     event.transferInitData = data;
886     return event;
887 }
888
889 /**
890  * @brief
891  *   Convenience method for constructing an OutputEvent with TransferAcceptData that does not contain Metadata
892  */
893 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data)
894 {
895     OutputEvent event(OutputEventType::kAcceptReceived);
896     event.transferAcceptData = data;
897     return event;
898 }
899 /**
900  * @brief
901  *   Convenience method for constructing an OutputEvent with TransferAcceptData that contains Metadata
902  */
903 TransferSession::OutputEvent TransferSession::OutputEvent::TransferAcceptEvent(TransferAcceptData data,
904                                                                                System::PacketBufferHandle msg)
905 {
906     OutputEvent event = TransferAcceptEvent(data);
907     event.MsgData     = std::move(msg);
908     return event;
909 }
910
911 TransferSession::OutputEvent TransferSession::OutputEvent::BlockDataEvent(BlockData data, System::PacketBufferHandle msg)
912 {
913     OutputEvent event(OutputEventType::kBlockReceived);
914     event.MsgData   = std::move(msg);
915     event.blockdata = data;
916     return event;
917 }
918
919 /**
920  * @brief
921  *   Convenience method for constructing an event with kInternalError or kOutputStatusReceived
922  */
923 TransferSession::OutputEvent TransferSession::OutputEvent::StatusReportEvent(OutputEventType type, StatusReportData data)
924 {
925     OutputEvent event(type);
926     event.statusData = data;
927     return event;
928 }
929
930 } // namespace bdx
931 } // namespace chip