1 /*
2  *  Copyright (c) 2016, The OpenThread Authors.
3  *  All rights reserved.
4  *
5  *  Redistribution and use in source and binary forms, with or without
6  *  modification, are permitted provided that the following conditions are met:
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. Neither the name of the copyright holder nor the
13  *     names of its contributors may be used to endorse or promote products
14  *     derived from this software without specific prior written permission.
15  *
16  *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17  *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
20  *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  *  POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include "coap.hpp"
30 
31 #include "common/code_utils.hpp"
32 #include "common/debug.hpp"
33 #include "common/instance.hpp"
34 #include "common/locator_getters.hpp"
35 #include "common/logging.hpp"
36 #include "common/random.hpp"
37 #include "net/ip6.hpp"
38 #include "net/udp6.hpp"
39 #include "thread/thread_netif.hpp"
40 
41 /**
42  * @file
43  *   This file contains common code base for CoAP client and server.
44  */
45 
46 namespace ot {
47 namespace Coap {
48 
CoapBase(Instance & aInstance,Sender aSender)49 CoapBase::CoapBase(Instance &aInstance, Sender aSender)
50     : InstanceLocator(aInstance)
51     , mMessageId(Random::NonCrypto::GetUint16())
52     , mRetransmissionTimer(aInstance, Coap::HandleRetransmissionTimer, this)
53     , mContext(nullptr)
54     , mInterceptor(nullptr)
55     , mResponsesQueue(aInstance)
56     , mDefaultHandler(nullptr)
57     , mDefaultHandlerContext(nullptr)
58     , mSender(aSender)
59 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
60     , mLastResponse(nullptr)
61 #endif
62 {
63 }
64 
ClearRequestsAndResponses(void)65 void CoapBase::ClearRequestsAndResponses(void)
66 {
67     ClearRequests(nullptr); // Clear requests matching any address.
68     mResponsesQueue.DequeueAllResponses();
69 }
70 
ClearRequests(const Ip6::Address & aAddress)71 void CoapBase::ClearRequests(const Ip6::Address &aAddress)
72 {
73     ClearRequests(&aAddress);
74 }
75 
ClearRequests(const Ip6::Address * aAddress)76 void CoapBase::ClearRequests(const Ip6::Address *aAddress)
77 {
78     Message *nextMessage;
79 
80     for (Message *message = mPendingRequests.GetHead(); message != nullptr; message = nextMessage)
81     {
82         Metadata metadata;
83 
84         nextMessage = message->GetNextCoapMessage();
85         metadata.ReadFrom(*message);
86 
87         if ((aAddress == nullptr) || (metadata.mSourceAddress == *aAddress))
88         {
89             FinalizeCoapTransaction(*message, metadata, nullptr, nullptr, kErrorAbort);
90         }
91     }
92 }
93 
94 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
AddBlockWiseResource(ResourceBlockWise & aResource)95 void CoapBase::AddBlockWiseResource(ResourceBlockWise &aResource)
96 {
97     IgnoreError(mBlockWiseResources.Add(aResource));
98 }
99 
RemoveBlockWiseResource(ResourceBlockWise & aResource)100 void CoapBase::RemoveBlockWiseResource(ResourceBlockWise &aResource)
101 {
102     IgnoreError(mBlockWiseResources.Remove(aResource));
103     aResource.SetNext(nullptr);
104 }
105 #endif
106 
AddResource(Resource & aResource)107 void CoapBase::AddResource(Resource &aResource)
108 {
109     IgnoreError(mResources.Add(aResource));
110 }
111 
RemoveResource(Resource & aResource)112 void CoapBase::RemoveResource(Resource &aResource)
113 {
114     IgnoreError(mResources.Remove(aResource));
115     aResource.SetNext(nullptr);
116 }
117 
SetDefaultHandler(RequestHandler aHandler,void * aContext)118 void CoapBase::SetDefaultHandler(RequestHandler aHandler, void *aContext)
119 {
120     mDefaultHandler        = aHandler;
121     mDefaultHandlerContext = aContext;
122 }
123 
SetInterceptor(Interceptor aInterceptor,void * aContext)124 void CoapBase::SetInterceptor(Interceptor aInterceptor, void *aContext)
125 {
126     mInterceptor = aInterceptor;
127     mContext     = aContext;
128 }
129 
NewMessage(const Message::Settings & aSettings)130 Message *CoapBase::NewMessage(const Message::Settings &aSettings)
131 {
132     Message *message = nullptr;
133 
134     VerifyOrExit((message = static_cast<Message *>(Get<Ip6::Udp>().NewMessage(0, aSettings))) != nullptr);
135     message->SetOffset(0);
136 
137 exit:
138     return message;
139 }
140 
Send(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)141 Error CoapBase::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
142 {
143     Error error;
144 
145 #if OPENTHREAD_CONFIG_OTNS_ENABLE
146     Get<Utils::Otns>().EmitCoapSend(static_cast<Message &>(aMessage), aMessageInfo);
147 #endif
148 
149     error = mSender(*this, aMessage, aMessageInfo);
150 
151 #if OPENTHREAD_CONFIG_OTNS_ENABLE
152     if (error != kErrorNone)
153     {
154         Get<Utils::Otns>().EmitCoapSendFailure(error, static_cast<Message &>(aMessage), aMessageInfo);
155     }
156 #endif
157     return error;
158 }
159 
160 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const TxParameters & aTxParameters,ResponseHandler aHandler,void * aContext,otCoapBlockwiseTransmitHook aTransmitHook,otCoapBlockwiseReceiveHook aReceiveHook)161 Error CoapBase::SendMessage(Message &                   aMessage,
162                             const Ip6::MessageInfo &    aMessageInfo,
163                             const TxParameters &        aTxParameters,
164                             ResponseHandler             aHandler,
165                             void *                      aContext,
166                             otCoapBlockwiseTransmitHook aTransmitHook,
167                             otCoapBlockwiseReceiveHook  aReceiveHook)
168 #else
169 Error CoapBase::SendMessage(Message &               aMessage,
170                             const Ip6::MessageInfo &aMessageInfo,
171                             const TxParameters &    aTxParameters,
172                             ResponseHandler         aHandler,
173                             void *                  aContext)
174 #endif
175 {
176     Error    error;
177     Message *storedCopy = nullptr;
178     uint16_t copyLength = 0;
179 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
180     uint8_t  buf[kMaxBlockLength] = {0};
181     uint16_t bufLen               = kMaxBlockLength;
182     bool     moreBlocks           = false;
183 #endif
184 
185     switch (aMessage.GetType())
186     {
187     case kTypeAck:
188 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
189         // Check for block-wise transfer
190         if ((aTransmitHook != nullptr) && (aMessage.ReadBlockOptionValues(kOptionBlock2) == kErrorNone) &&
191             (aMessage.GetBlockWiseBlockNumber() == 0))
192         {
193             // Set payload for first block of the transfer
194             VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
195                          error = kErrorNoBufs);
196             SuccessOrExit(error = aTransmitHook(aContext, buf, aMessage.GetBlockWiseBlockNumber() * bufLen, &bufLen,
197                                                 &moreBlocks));
198             SuccessOrExit(error = aMessage.AppendBytes(buf, bufLen));
199 
200             SuccessOrExit(error = CacheLastBlockResponse(&aMessage));
201         }
202 #endif
203 
204         mResponsesQueue.EnqueueResponse(aMessage, aMessageInfo, aTxParameters);
205         break;
206     case kTypeReset:
207         OT_ASSERT(aMessage.GetCode() == kCodeEmpty);
208         break;
209     default:
210 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
211         // Check for block-wise transfer
212         if ((aTransmitHook != nullptr) && (aMessage.ReadBlockOptionValues(kOptionBlock1) == kErrorNone) &&
213             (aMessage.GetBlockWiseBlockNumber() == 0))
214         {
215             // Set payload for first block of the transfer
216             VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
217                          error = kErrorNoBufs);
218             SuccessOrExit(error = aTransmitHook(aContext, buf, aMessage.GetBlockWiseBlockNumber() * bufLen, &bufLen,
219                                                 &moreBlocks));
220             SuccessOrExit(error = aMessage.AppendBytes(buf, bufLen));
221 
222             // Block-Wise messages always have to be confirmable
223             if (aMessage.IsNonConfirmable())
224             {
225                 aMessage.SetType(kTypeConfirmable);
226             }
227         }
228 #endif
229 
230         aMessage.SetMessageId(mMessageId++);
231         break;
232     }
233 
234     aMessage.Finish();
235 
236     if (aMessage.IsConfirmable())
237     {
238         copyLength = aMessage.GetLength();
239     }
240     else if (aMessage.IsNonConfirmable() && (aHandler != nullptr))
241     {
242         // As we do not retransmit non confirmable messages, create a
243         // copy of header only, for token information.
244         copyLength = aMessage.GetOptionStart();
245     }
246 
247     if (copyLength > 0)
248     {
249         Metadata metadata;
250 
251 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
252         // Whether or not to turn on special "Observe" handling.
253         Option::Iterator iterator;
254         bool             observe;
255 
256         SuccessOrExit(error = iterator.Init(aMessage, kOptionObserve));
257         observe = !iterator.IsDone();
258 
259         // Special case, if we're sending a GET with Observe=1, that is a cancellation.
260         if (observe && aMessage.IsGetRequest())
261         {
262             uint64_t observeVal = 0;
263 
264             SuccessOrExit(error = iterator.ReadOptionValue(observeVal));
265 
266             if (observeVal == 1)
267             {
268                 Metadata handlerMetadata;
269 
270                 // We're cancelling our subscription, so disable special-case handling on this request.
271                 observe = false;
272 
273                 // If we can find the previous handler context, cancel that too.  Peer address
274                 // and tokens, etc should all match.
275                 Message *origRequest = FindRelatedRequest(aMessage, aMessageInfo, handlerMetadata);
276                 if (origRequest != nullptr)
277                 {
278                     FinalizeCoapTransaction(*origRequest, handlerMetadata, nullptr, nullptr, kErrorNone);
279                 }
280             }
281         }
282 #endif // OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
283 
284         metadata.mSourceAddress            = aMessageInfo.GetSockAddr();
285         metadata.mDestinationPort          = aMessageInfo.GetPeerPort();
286         metadata.mDestinationAddress       = aMessageInfo.GetPeerAddr();
287         metadata.mMulticastLoop            = aMessageInfo.GetMulticastLoop();
288         metadata.mResponseHandler          = aHandler;
289         metadata.mResponseContext          = aContext;
290         metadata.mRetransmissionsRemaining = aTxParameters.mMaxRetransmit;
291         metadata.mRetransmissionTimeout    = aTxParameters.CalculateInitialRetransmissionTimeout();
292         metadata.mAcknowledged             = false;
293         metadata.mConfirmable              = aMessage.IsConfirmable();
294 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
295         metadata.mHopLimit        = aMessageInfo.GetHopLimit();
296         metadata.mIsHostInterface = aMessageInfo.IsHostInterface();
297 #endif
298 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
299         metadata.mBlockwiseReceiveHook  = aReceiveHook;
300         metadata.mBlockwiseTransmitHook = aTransmitHook;
301 #endif
302 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
303         metadata.mObserve = observe;
304 #endif
305         metadata.mNextTimerShot =
306             TimerMilli::GetNow() +
307             (metadata.mConfirmable ? metadata.mRetransmissionTimeout : aTxParameters.CalculateMaxTransmitWait());
308 
309         storedCopy = CopyAndEnqueueMessage(aMessage, copyLength, metadata);
310         VerifyOrExit(storedCopy != nullptr, error = kErrorNoBufs);
311     }
312 
313     SuccessOrExit(error = Send(aMessage, aMessageInfo));
314 
315 exit:
316 
317     if (error != kErrorNone && storedCopy != nullptr)
318     {
319         DequeueMessage(*storedCopy);
320     }
321 
322     return error;
323 }
324 
SendMessage(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,ResponseHandler aHandler,void * aContext)325 Error CoapBase::SendMessage(Message &               aMessage,
326                             const Ip6::MessageInfo &aMessageInfo,
327                             ResponseHandler         aHandler,
328                             void *                  aContext)
329 {
330 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
331     return SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext, nullptr, nullptr);
332 #else
333     return SendMessage(aMessage, aMessageInfo, TxParameters::GetDefault(), aHandler, aContext);
334 #endif
335 }
336 
SendReset(Message & aRequest,const Ip6::MessageInfo & aMessageInfo)337 Error CoapBase::SendReset(Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
338 {
339     return SendEmptyMessage(kTypeReset, aRequest, aMessageInfo);
340 }
341 
SendAck(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)342 Error CoapBase::SendAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
343 {
344     return SendEmptyMessage(kTypeAck, aRequest, aMessageInfo);
345 }
346 
SendEmptyAck(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo,Code aCode)347 Error CoapBase::SendEmptyAck(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo, Code aCode)
348 {
349     return (aRequest.IsConfirmable() ? SendHeaderResponse(aCode, aRequest, aMessageInfo) : kErrorInvalidArgs);
350 }
351 
SendNotFound(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)352 Error CoapBase::SendNotFound(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
353 {
354     return SendHeaderResponse(kCodeNotFound, aRequest, aMessageInfo);
355 }
356 
SendEmptyMessage(Type aType,const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)357 Error CoapBase::SendEmptyMessage(Type aType, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
358 {
359     Error    error   = kErrorNone;
360     Message *message = nullptr;
361 
362     VerifyOrExit(aRequest.IsConfirmable(), error = kErrorInvalidArgs);
363 
364     VerifyOrExit((message = NewMessage()) != nullptr, error = kErrorNoBufs);
365 
366     message->Init(aType, kCodeEmpty);
367     message->SetMessageId(aRequest.GetMessageId());
368 
369     message->Finish();
370     SuccessOrExit(error = Send(*message, aMessageInfo));
371 
372 exit:
373     FreeMessageOnError(message, error);
374     return error;
375 }
376 
SendHeaderResponse(Message::Code aCode,const Message & aRequest,const Ip6::MessageInfo & aMessageInfo)377 Error CoapBase::SendHeaderResponse(Message::Code aCode, const Message &aRequest, const Ip6::MessageInfo &aMessageInfo)
378 {
379     Error    error   = kErrorNone;
380     Message *message = nullptr;
381 
382     VerifyOrExit(aRequest.IsRequest(), error = kErrorInvalidArgs);
383     VerifyOrExit((message = NewMessage()) != nullptr, error = kErrorNoBufs);
384 
385     switch (aRequest.GetType())
386     {
387     case kTypeConfirmable:
388         message->Init(kTypeAck, aCode);
389         message->SetMessageId(aRequest.GetMessageId());
390         break;
391 
392     case kTypeNonConfirmable:
393         message->Init(kTypeNonConfirmable, aCode);
394         break;
395 
396     default:
397         ExitNow(error = kErrorInvalidArgs);
398         OT_UNREACHABLE_CODE(break);
399     }
400 
401     SuccessOrExit(error = message->SetTokenFromMessage(aRequest));
402 
403     SuccessOrExit(error = SendMessage(*message, aMessageInfo));
404 
405 exit:
406     FreeMessageOnError(message, error);
407     return error;
408 }
409 
HandleRetransmissionTimer(Timer & aTimer)410 void CoapBase::HandleRetransmissionTimer(Timer &aTimer)
411 {
412     static_cast<Coap *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleRetransmissionTimer();
413 }
414 
HandleRetransmissionTimer(void)415 void CoapBase::HandleRetransmissionTimer(void)
416 {
417     TimeMilli        now      = TimerMilli::GetNow();
418     TimeMilli        nextTime = now.GetDistantFuture();
419     Metadata         metadata;
420     Message *        nextMessage;
421     Ip6::MessageInfo messageInfo;
422 
423     for (Message *message = mPendingRequests.GetHead(); message != nullptr; message = nextMessage)
424     {
425         nextMessage = message->GetNextCoapMessage();
426 
427         metadata.ReadFrom(*message);
428 
429         if (now >= metadata.mNextTimerShot)
430         {
431 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
432             if (message->IsRequest() && metadata.mObserve && metadata.mAcknowledged)
433             {
434                 // This is a RFC7641 subscription.  Do not time out.
435                 continue;
436             }
437 #endif
438 
439             if (!metadata.mConfirmable || (metadata.mRetransmissionsRemaining == 0))
440             {
441                 // No expected response or acknowledgment.
442                 FinalizeCoapTransaction(*message, metadata, nullptr, nullptr, kErrorResponseTimeout);
443                 continue;
444             }
445 
446             // Increment retransmission counter and timer.
447             metadata.mRetransmissionsRemaining--;
448             metadata.mRetransmissionTimeout *= 2;
449             metadata.mNextTimerShot = now + metadata.mRetransmissionTimeout;
450             metadata.UpdateIn(*message);
451 
452             // Retransmit
453             if (!metadata.mAcknowledged)
454             {
455                 messageInfo.SetPeerAddr(metadata.mDestinationAddress);
456                 messageInfo.SetPeerPort(metadata.mDestinationPort);
457                 messageInfo.SetSockAddr(metadata.mSourceAddress);
458 #if OPENTHREAD_CONFIG_BACKBONE_ROUTER_ENABLE
459                 messageInfo.SetHopLimit(metadata.mHopLimit);
460                 messageInfo.SetIsHostInterface(metadata.mIsHostInterface);
461 #endif
462                 messageInfo.SetMulticastLoop(metadata.mMulticastLoop);
463 
464                 SendCopy(*message, messageInfo);
465             }
466         }
467 
468         if (nextTime > metadata.mNextTimerShot)
469         {
470             nextTime = metadata.mNextTimerShot;
471         }
472     }
473 
474     if (nextTime < now.GetDistantFuture())
475     {
476         mRetransmissionTimer.FireAt(nextTime);
477     }
478 }
479 
FinalizeCoapTransaction(Message & aRequest,const Metadata & aMetadata,Message * aResponse,const Ip6::MessageInfo * aMessageInfo,Error aResult)480 void CoapBase::FinalizeCoapTransaction(Message &               aRequest,
481                                        const Metadata &        aMetadata,
482                                        Message *               aResponse,
483                                        const Ip6::MessageInfo *aMessageInfo,
484                                        Error                   aResult)
485 {
486     DequeueMessage(aRequest);
487 
488     if (aMetadata.mResponseHandler != nullptr)
489     {
490         aMetadata.mResponseHandler(aMetadata.mResponseContext, aResponse, aMessageInfo, aResult);
491     }
492 }
493 
AbortTransaction(ResponseHandler aHandler,void * aContext)494 Error CoapBase::AbortTransaction(ResponseHandler aHandler, void *aContext)
495 {
496     Error    error = kErrorNotFound;
497     Message *nextMessage;
498     Metadata metadata;
499 
500     for (Message *message = mPendingRequests.GetHead(); message != nullptr; message = nextMessage)
501     {
502         nextMessage = message->GetNextCoapMessage();
503         metadata.ReadFrom(*message);
504 
505         if (metadata.mResponseHandler == aHandler && metadata.mResponseContext == aContext)
506         {
507             FinalizeCoapTransaction(*message, metadata, nullptr, nullptr, kErrorAbort);
508             error = kErrorNone;
509         }
510     }
511 
512     return error;
513 }
514 
CopyAndEnqueueMessage(const Message & aMessage,uint16_t aCopyLength,const Metadata & aMetadata)515 Message *CoapBase::CopyAndEnqueueMessage(const Message &aMessage, uint16_t aCopyLength, const Metadata &aMetadata)
516 {
517     Error    error       = kErrorNone;
518     Message *messageCopy = nullptr;
519 
520     VerifyOrExit((messageCopy = aMessage.Clone(aCopyLength)) != nullptr, error = kErrorNoBufs);
521 
522     SuccessOrExit(error = aMetadata.AppendTo(*messageCopy));
523 
524     mRetransmissionTimer.FireAtIfEarlier(aMetadata.mNextTimerShot);
525 
526     mPendingRequests.Enqueue(*messageCopy);
527 
528 exit:
529     FreeAndNullMessageOnError(messageCopy, error);
530     return messageCopy;
531 }
532 
DequeueMessage(Message & aMessage)533 void CoapBase::DequeueMessage(Message &aMessage)
534 {
535     mPendingRequests.Dequeue(aMessage);
536 
537     if (mRetransmissionTimer.IsRunning() && (mPendingRequests.GetHead() == nullptr))
538     {
539         mRetransmissionTimer.Stop();
540     }
541 
542     aMessage.Free();
543 
544     // No need to worry that the earliest pending message was removed -
545     // the timer would just shoot earlier and then it'd be setup again.
546 }
547 
548 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
FreeLastBlockResponse(void)549 void CoapBase::FreeLastBlockResponse(void)
550 {
551     if (mLastResponse != nullptr)
552     {
553         mLastResponse->Free();
554         mLastResponse = nullptr;
555     }
556 }
557 
CacheLastBlockResponse(Message * aResponse)558 Error CoapBase::CacheLastBlockResponse(Message *aResponse)
559 {
560     Error error = kErrorNone;
561     // Save last response for block-wise transfer
562     FreeLastBlockResponse();
563 
564     if ((mLastResponse = aResponse->Clone()) == nullptr)
565     {
566         error = kErrorNoBufs;
567     }
568 
569     return error;
570 }
571 
PrepareNextBlockRequest(Message::BlockType aType,bool aMoreBlocks,Message & aRequestOld,Message & aRequest,Message & aMessage)572 Error CoapBase::PrepareNextBlockRequest(Message::BlockType aType,
573                                         bool               aMoreBlocks,
574                                         Message &          aRequestOld,
575                                         Message &          aRequest,
576                                         Message &          aMessage)
577 {
578     Error            error       = kErrorNone;
579     bool             isOptionSet = false;
580     uint64_t         optionBuf   = 0;
581     uint16_t         blockOption = 0;
582     Option::Iterator iterator;
583 
584     blockOption = (aType == Message::kBlockType1) ? kOptionBlock1 : kOptionBlock2;
585 
586     aRequest.Init(kTypeConfirmable, static_cast<ot::Coap::Code>(aRequestOld.GetCode()));
587     SuccessOrExit(error = iterator.Init(aRequestOld));
588 
589     // Copy options from last response to next message
590     for (; !iterator.IsDone() && iterator.GetOption()->GetLength() != 0; error = iterator.Advance())
591     {
592         uint16_t optionNumber = iterator.GetOption()->GetNumber();
593 
594         SuccessOrExit(error);
595 
596         // Check if option to copy next is higher than or equal to Block1 option
597         if (optionNumber >= blockOption && !isOptionSet)
598         {
599             // Write Block1 option to next message
600             SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
601                                                              aMessage.GetBlockWiseBlockSize()));
602             aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
603             aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
604             aRequest.SetMoreBlocksFlag(aMoreBlocks);
605 
606             isOptionSet = true;
607 
608             // If option to copy next is Block1 or Block2 option, option is not copied
609             if (optionNumber == kOptionBlock1 || optionNumber == kOptionBlock2)
610             {
611                 continue;
612             }
613         }
614 
615         // Copy option
616         SuccessOrExit(error = iterator.ReadOptionValue(&optionBuf));
617         SuccessOrExit(error = aRequest.AppendOption(optionNumber, iterator.GetOption()->GetLength(), &optionBuf));
618     }
619 
620     if (!isOptionSet)
621     {
622         // Write Block1 option to next message
623         SuccessOrExit(error = aRequest.AppendBlockOption(aType, aMessage.GetBlockWiseBlockNumber() + 1, aMoreBlocks,
624                                                          aMessage.GetBlockWiseBlockSize()));
625         aRequest.SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber() + 1);
626         aRequest.SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
627         aRequest.SetMoreBlocksFlag(aMoreBlocks);
628 
629         isOptionSet = true;
630     }
631 
632 exit:
633     return error;
634 }
635 
SendNextBlock1Request(Message & aRequest,Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Metadata & aCoapMetadata)636 Error CoapBase::SendNextBlock1Request(Message &               aRequest,
637                                       Message &               aMessage,
638                                       const Ip6::MessageInfo &aMessageInfo,
639                                       const Metadata &        aCoapMetadata)
640 {
641     Error    error                = kErrorNone;
642     Message *request              = nullptr;
643     bool     moreBlocks           = false;
644     uint8_t  buf[kMaxBlockLength] = {0};
645     uint16_t bufLen               = kMaxBlockLength;
646 
647     SuccessOrExit(error = aRequest.ReadBlockOptionValues(kOptionBlock1));
648     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
649 
650     // Conclude block-wise transfer if last block has been received
651     if (!aRequest.IsMoreBlocksFlagSet())
652     {
653         FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, kErrorNone);
654         ExitNow();
655     }
656 
657     // Get next block
658     VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
659                  error = kErrorNoBufs);
660 
661     SuccessOrExit(
662         error = aCoapMetadata.mBlockwiseTransmitHook(aCoapMetadata.mResponseContext, buf,
663                                                      otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
664                                                          (aMessage.GetBlockWiseBlockNumber() + 1),
665                                                      &bufLen, &moreBlocks));
666 
667     // Check if block length is valid
668     VerifyOrExit(bufLen <= otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), error = kErrorInvalidArgs);
669 
670     // Init request for next block
671     VerifyOrExit((request = NewMessage()) != nullptr, error = kErrorNoBufs);
672     SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType1, moreBlocks, aRequest, *request, aMessage));
673 
674     SuccessOrExit(error = request->SetPayloadMarker());
675 
676     SuccessOrExit(error = request->AppendBytes(buf, bufLen));
677 
678     DequeueMessage(aRequest);
679 
680     otLogInfoCoap("Send Block1 Nr. %d, Size: %d bytes, More Blocks Flag: %d", request->GetBlockWiseBlockNumber(),
681                   otCoapBlockSizeFromExponent(request->GetBlockWiseBlockSize()), request->IsMoreBlocksFlagSet());
682 
683     SuccessOrExit(error = SendMessage(*request, aMessageInfo, TxParameters::GetDefault(),
684                                       aCoapMetadata.mResponseHandler, aCoapMetadata.mResponseContext,
685                                       aCoapMetadata.mBlockwiseTransmitHook, aCoapMetadata.mBlockwiseReceiveHook));
686 
687 exit:
688     FreeMessageOnError(request, error);
689 
690     return error;
691 }
692 
SendNextBlock2Request(Message & aRequest,Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const Metadata & aCoapMetadata,uint32_t aTotalLength,bool aBeginBlock1Transfer)693 Error CoapBase::SendNextBlock2Request(Message &               aRequest,
694                                       Message &               aMessage,
695                                       const Ip6::MessageInfo &aMessageInfo,
696                                       const Metadata &        aCoapMetadata,
697                                       uint32_t                aTotalLength,
698                                       bool                    aBeginBlock1Transfer)
699 {
700     Error    error                = kErrorNone;
701     Message *request              = nullptr;
702     uint8_t  buf[kMaxBlockLength] = {0};
703     uint16_t bufLen               = kMaxBlockLength;
704 
705     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
706 
707     // Check payload and block length
708     VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <=
709                          otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) &&
710                      (aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength,
711                  error = kErrorNoBufs);
712 
713     // Read and then forward payload to receive hook function
714     bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
715     SuccessOrExit(
716         error = aCoapMetadata.mBlockwiseReceiveHook(aCoapMetadata.mResponseContext, buf,
717                                                     otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
718                                                         aMessage.GetBlockWiseBlockNumber(),
719                                                     bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
720 
721     // CoAP Block-Wise Transfer continues
722     otLogInfoCoap("Received Block2 Nr. %d , Size: %d bytes, More Blocks Flag: %d", aMessage.GetBlockWiseBlockNumber(),
723                   otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()), aMessage.IsMoreBlocksFlagSet());
724 
725     // Conclude block-wise transfer if last block has been received
726     if (!aMessage.IsMoreBlocksFlagSet())
727     {
728         FinalizeCoapTransaction(aRequest, aCoapMetadata, &aMessage, &aMessageInfo, kErrorNone);
729         ExitNow();
730     }
731 
732     // Init request for next block
733     VerifyOrExit((request = NewMessage()) != nullptr, error = kErrorNoBufs);
734     SuccessOrExit(error = PrepareNextBlockRequest(Message::kBlockType2, aMessage.IsMoreBlocksFlagSet(), aRequest,
735                                                   *request, aMessage));
736 
737     if (!aBeginBlock1Transfer)
738     {
739         DequeueMessage(aRequest);
740     }
741 
742     otLogInfoCoap("Request Block2 Nr. %d, Size: %d bytes", request->GetBlockWiseBlockNumber(),
743                   otCoapBlockSizeFromExponent(request->GetBlockWiseBlockSize()));
744 
745     SuccessOrExit(error =
746                       SendMessage(*request, aMessageInfo, TxParameters::GetDefault(), aCoapMetadata.mResponseHandler,
747                                   aCoapMetadata.mResponseContext, nullptr, aCoapMetadata.mBlockwiseReceiveHook));
748 
749 exit:
750     FreeMessageOnError(request, error);
751 
752     return error;
753 }
754 
ProcessBlock1Request(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const ResourceBlockWise & aResource,uint32_t aTotalLength)755 Error CoapBase::ProcessBlock1Request(Message &                aMessage,
756                                      const Ip6::MessageInfo & aMessageInfo,
757                                      const ResourceBlockWise &aResource,
758                                      uint32_t                 aTotalLength)
759 {
760     Error    error                = kErrorNone;
761     Message *response             = nullptr;
762     uint8_t  buf[kMaxBlockLength] = {0};
763     uint16_t bufLen               = kMaxBlockLength;
764 
765     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock1));
766 
767     // Read and then forward payload to receive hook function
768     VerifyOrExit((aMessage.GetLength() - aMessage.GetOffset()) <= kMaxBlockLength, error = kErrorNoBufs);
769     bufLen = aMessage.ReadBytes(aMessage.GetOffset(), buf, aMessage.GetLength() - aMessage.GetOffset());
770     SuccessOrExit(error = aResource.HandleBlockReceive(buf,
771                                                        otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
772                                                            aMessage.GetBlockWiseBlockNumber(),
773                                                        bufLen, aMessage.IsMoreBlocksFlagSet(), aTotalLength));
774 
775     if (aMessage.IsMoreBlocksFlagSet())
776     {
777         // Set up next response
778         VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorFailed);
779         response->Init(kTypeAck, kCodeContinue);
780         response->SetMessageId(aMessage.GetMessageId());
781         IgnoreReturnValue(
782             response->SetToken(static_cast<const Message &>(aMessage).GetToken(), aMessage.GetTokenLength()));
783 
784         response->SetBlockWiseBlockNumber(aMessage.GetBlockWiseBlockNumber());
785         response->SetMoreBlocksFlag(aMessage.IsMoreBlocksFlagSet());
786         response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
787 
788         SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType1, response->GetBlockWiseBlockNumber(),
789                                                           response->IsMoreBlocksFlagSet(),
790                                                           response->GetBlockWiseBlockSize()));
791 
792         SuccessOrExit(error = CacheLastBlockResponse(response));
793 
794         otLogInfoCoap("Acknowledge Block1 Nr. %d, Size: %d bytes", response->GetBlockWiseBlockNumber(),
795                       otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize()));
796 
797         SuccessOrExit(error = SendMessage(*response, aMessageInfo));
798 
799         error = kErrorBusy;
800     }
801     else
802     {
803         // Conclude block-wise transfer if last block has been received
804         FreeLastBlockResponse();
805         error = kErrorNone;
806     }
807 
808 exit:
809     if (error != kErrorNone && error != kErrorBusy && response != nullptr)
810     {
811         response->Free();
812     }
813 
814     return error;
815 }
816 
ProcessBlock2Request(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const ResourceBlockWise & aResource)817 Error CoapBase::ProcessBlock2Request(Message &                aMessage,
818                                      const Ip6::MessageInfo & aMessageInfo,
819                                      const ResourceBlockWise &aResource)
820 {
821     Error            error                = kErrorNone;
822     Message *        response             = nullptr;
823     uint8_t          buf[kMaxBlockLength] = {0};
824     uint16_t         bufLen               = kMaxBlockLength;
825     bool             moreBlocks           = false;
826     uint64_t         optionBuf            = 0;
827     Option::Iterator iterator;
828 
829     SuccessOrExit(error = aMessage.ReadBlockOptionValues(kOptionBlock2));
830 
831     otLogInfoCoap("Request for Block2 Nr. %d, Size: %d bytes received", aMessage.GetBlockWiseBlockNumber(),
832                   otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()));
833 
834     if (aMessage.GetBlockWiseBlockNumber() == 0)
835     {
836         aResource.HandleRequest(aMessage, aMessageInfo);
837         ExitNow();
838     }
839 
840     // Set up next response
841     VerifyOrExit((response = NewMessage()) != nullptr, error = kErrorNoBufs);
842     response->Init(kTypeAck, kCodeContent);
843     response->SetMessageId(aMessage.GetMessageId());
844 
845     VerifyOrExit((bufLen = otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize())) <= kMaxBlockLength,
846                  error = kErrorNoBufs);
847     SuccessOrExit(error = aResource.HandleBlockTransmit(buf,
848                                                         otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) *
849                                                             aMessage.GetBlockWiseBlockNumber(),
850                                                         &bufLen, &moreBlocks));
851 
852     response->SetMoreBlocksFlag(moreBlocks);
853     if (moreBlocks)
854     {
855         switch (bufLen)
856         {
857         case 1024:
858             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_1024);
859             break;
860         case 512:
861             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_512);
862             break;
863         case 256:
864             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_256);
865             break;
866         case 128:
867             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_128);
868             break;
869         case 64:
870             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_64);
871             break;
872         case 32:
873             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_32);
874             break;
875         case 16:
876             response->SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_16);
877             break;
878         default:
879             error = kErrorInvalidArgs;
880             ExitNow();
881             break;
882         }
883     }
884     else
885     {
886         // Verify that buffer length is not larger than requested block size
887         VerifyOrExit(bufLen <= otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()),
888                      error = kErrorInvalidArgs);
889         response->SetBlockWiseBlockSize(aMessage.GetBlockWiseBlockSize());
890     }
891 
892     response->SetBlockWiseBlockNumber(
893         (otCoapBlockSizeFromExponent(aMessage.GetBlockWiseBlockSize()) * aMessage.GetBlockWiseBlockNumber()) /
894         (otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize())));
895 
896     // Copy options from last response
897     SuccessOrExit(error = iterator.Init(*mLastResponse));
898 
899     while (!iterator.IsDone())
900     {
901         uint16_t optionNumber = iterator.GetOption()->GetNumber();
902 
903         if (optionNumber == kOptionBlock2)
904         {
905             SuccessOrExit(error = response->AppendBlockOption(Message::kBlockType2, response->GetBlockWiseBlockNumber(),
906                                                               response->IsMoreBlocksFlagSet(),
907                                                               response->GetBlockWiseBlockSize()));
908         }
909         else if (optionNumber == kOptionBlock1)
910         {
911             SuccessOrExit(error = iterator.ReadOptionValue(&optionBuf));
912             SuccessOrExit(error = response->AppendOption(optionNumber, iterator.GetOption()->GetLength(), &optionBuf));
913         }
914 
915         SuccessOrExit(error = iterator.Advance());
916     }
917 
918     SuccessOrExit(error = response->SetPayloadMarker());
919     SuccessOrExit(error = response->AppendBytes(buf, bufLen));
920 
921     if (response->IsMoreBlocksFlagSet())
922     {
923         SuccessOrExit(error = CacheLastBlockResponse(response));
924     }
925     else
926     {
927         // Conclude block-wise transfer if last block has been received
928         FreeLastBlockResponse();
929     }
930 
931     otLogInfoCoap("Send Block2 Nr. %d, Size: %d bytes, More Blocks Flag %d", response->GetBlockWiseBlockNumber(),
932                   otCoapBlockSizeFromExponent(response->GetBlockWiseBlockSize()), response->IsMoreBlocksFlagSet());
933 
934     SuccessOrExit(error = SendMessage(*response, aMessageInfo));
935 
936 exit:
937     FreeMessageOnError(response, error);
938 
939     return error;
940 }
941 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
942 
SendCopy(const Message & aMessage,const Ip6::MessageInfo & aMessageInfo)943 void CoapBase::SendCopy(const Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
944 {
945     Error    error;
946     Message *messageCopy = nullptr;
947 
948     // Create a message copy for lower layers.
949     messageCopy = aMessage.Clone(aMessage.GetLength() - sizeof(Metadata));
950     VerifyOrExit(messageCopy != nullptr, error = kErrorNoBufs);
951 
952     SuccessOrExit(error = Send(*messageCopy, aMessageInfo));
953 
954 exit:
955 
956     if (error != kErrorNone)
957     {
958         otLogWarnCoap("Failed to send copy: %s", ErrorToString(error));
959         FreeMessage(messageCopy);
960     }
961 }
962 
FindRelatedRequest(const Message & aResponse,const Ip6::MessageInfo & aMessageInfo,Metadata & aMetadata)963 Message *CoapBase::FindRelatedRequest(const Message &         aResponse,
964                                       const Ip6::MessageInfo &aMessageInfo,
965                                       Metadata &              aMetadata)
966 {
967     Message *message;
968 
969     for (message = mPendingRequests.GetHead(); message != nullptr; message = message->GetNextCoapMessage())
970     {
971         aMetadata.ReadFrom(*message);
972 
973         if (((aMetadata.mDestinationAddress == aMessageInfo.GetPeerAddr()) ||
974              aMetadata.mDestinationAddress.IsMulticast() ||
975              aMetadata.mDestinationAddress.GetIid().IsAnycastLocator()) &&
976             (aMetadata.mDestinationPort == aMessageInfo.GetPeerPort()))
977         {
978             switch (aResponse.GetType())
979             {
980             case kTypeReset:
981             case kTypeAck:
982                 if (aResponse.GetMessageId() == message->GetMessageId())
983                 {
984                     ExitNow();
985                 }
986 
987                 break;
988 
989             case kTypeConfirmable:
990             case kTypeNonConfirmable:
991                 if (aResponse.IsTokenEqual(*message))
992                 {
993                     ExitNow();
994                 }
995 
996                 break;
997             }
998         }
999     }
1000 
1001 exit:
1002     return message;
1003 }
1004 
Receive(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1005 void CoapBase::Receive(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1006 {
1007     Message &message = static_cast<Message &>(aMessage);
1008 
1009     if (message.ParseHeader() != kErrorNone)
1010     {
1011         otLogDebgCoap("Failed to parse CoAP header");
1012 
1013         if (!aMessageInfo.GetSockAddr().IsMulticast() && message.IsConfirmable())
1014         {
1015             IgnoreError(SendReset(message, aMessageInfo));
1016         }
1017     }
1018     else if (message.IsRequest())
1019     {
1020         ProcessReceivedRequest(message, aMessageInfo);
1021     }
1022     else
1023     {
1024         ProcessReceivedResponse(message, aMessageInfo);
1025     }
1026 
1027 #if OPENTHREAD_CONFIG_OTNS_ENABLE
1028     Get<Utils::Otns>().EmitCoapReceive(message, aMessageInfo);
1029 #endif
1030 }
1031 
ProcessReceivedResponse(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1032 void CoapBase::ProcessReceivedResponse(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1033 {
1034     Metadata metadata;
1035     Message *request = nullptr;
1036     Error    error   = kErrorNone;
1037 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1038     bool responseObserve = false;
1039 #endif
1040 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1041     uint8_t  blockOptionType    = 0;
1042     uint32_t totalTransfereSize = 0;
1043 #endif
1044 
1045     request = FindRelatedRequest(aMessage, aMessageInfo, metadata);
1046     VerifyOrExit(request != nullptr);
1047 
1048 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1049     if (metadata.mObserve && request->IsRequest())
1050     {
1051         // We sent Observe in our request, see if we received Observe in the response too.
1052         Option::Iterator iterator;
1053 
1054         SuccessOrExit(error = iterator.Init(aMessage, kOptionObserve));
1055         responseObserve = !iterator.IsDone();
1056     }
1057 #endif
1058 
1059     switch (aMessage.GetType())
1060     {
1061     case kTypeReset:
1062         if (aMessage.IsEmpty())
1063         {
1064             FinalizeCoapTransaction(*request, metadata, nullptr, nullptr, kErrorAbort);
1065         }
1066 
1067         // Silently ignore non-empty reset messages (RFC 7252, p. 4.2).
1068         break;
1069 
1070     case kTypeAck:
1071         if (aMessage.IsEmpty())
1072         {
1073             // Empty acknowledgment.
1074 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1075             if (metadata.mObserve && !request->IsRequest())
1076             {
1077                 // This is the ACK to our RFC7641 notification.  There will be no
1078                 // "separate" response so pass it back as if it were a piggy-backed
1079                 // response so we can stop re-sending and the application can move on.
1080                 FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1081             }
1082             else
1083 #endif
1084             {
1085                 // This is not related to RFC7641 or the outgoing "request" was not a
1086                 // notification.
1087                 if (metadata.mConfirmable)
1088                 {
1089                     metadata.mAcknowledged = true;
1090                     metadata.UpdateIn(*request);
1091                 }
1092 
1093                 // Remove the message if response is not expected, otherwise await
1094                 // response.
1095                 if (metadata.mResponseHandler == nullptr)
1096                 {
1097                     DequeueMessage(*request);
1098                 }
1099             }
1100         }
1101         else if (aMessage.IsResponse() && aMessage.IsTokenEqual(*request))
1102         {
1103             // Piggybacked response.  If there's an Observe option present in both
1104             // request and response, and we have a response handler; then we're
1105             // dealing with RFC7641 rules here.
1106             // (If there is no response handler, then we're wasting our time!)
1107 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1108             if (metadata.mObserve && responseObserve && (metadata.mResponseHandler != nullptr))
1109             {
1110                 // This is a RFC7641 notification.  The request is *not* done!
1111                 metadata.mResponseHandler(metadata.mResponseContext, &aMessage, &aMessageInfo, kErrorNone);
1112 
1113                 // Consider the message acknowledged at this point.
1114                 metadata.mAcknowledged = true;
1115                 metadata.UpdateIn(*request);
1116             }
1117             else
1118 #endif
1119 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1120             {
1121                 if (metadata.mBlockwiseTransmitHook != nullptr || metadata.mBlockwiseReceiveHook != nullptr)
1122                 {
1123                     // Search for CoAP Block-Wise Option [RFC7959]
1124                     Option::Iterator iterator;
1125 
1126                     SuccessOrExit(error = iterator.Init(aMessage));
1127                     while (!iterator.IsDone())
1128                     {
1129                         switch (iterator.GetOption()->GetNumber())
1130                         {
1131                         case kOptionBlock1:
1132                             blockOptionType += 1;
1133                             break;
1134 
1135                         case kOptionBlock2:
1136                             blockOptionType += 2;
1137                             break;
1138 
1139                         case kOptionSize2:
1140                             // ToDo: wait for method to read uint option values
1141                             totalTransfereSize = 0;
1142                             break;
1143 
1144                         default:
1145                             break;
1146                         }
1147 
1148                         SuccessOrExit(error = iterator.Advance());
1149                     }
1150                 }
1151                 switch (blockOptionType)
1152                 {
1153                 case 0:
1154                     // Piggybacked response.
1155                     FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1156                     break;
1157                 case 1: // Block1 option
1158                     if (aMessage.GetCode() == kCodeContinue && metadata.mBlockwiseTransmitHook != nullptr)
1159                     {
1160                         error = SendNextBlock1Request(*request, aMessage, aMessageInfo, metadata);
1161                     }
1162 
1163                     if (aMessage.GetCode() != kCodeContinue || metadata.mBlockwiseTransmitHook == nullptr ||
1164                         error != kErrorNone)
1165                     {
1166                         FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1167                     }
1168                     break;
1169                 case 2: // Block2 option
1170                     if (aMessage.GetCode() < kCodeBadRequest && metadata.mBlockwiseReceiveHook != nullptr)
1171                     {
1172                         error = SendNextBlock2Request(*request, aMessage, aMessageInfo, metadata, totalTransfereSize,
1173                                                       false);
1174                     }
1175 
1176                     if (aMessage.GetCode() >= kCodeBadRequest || metadata.mBlockwiseReceiveHook == nullptr ||
1177                         error != kErrorNone)
1178                     {
1179                         FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1180                     }
1181                     break;
1182                 case 3: // Block1 & Block2 option
1183                     if (aMessage.GetCode() < kCodeBadRequest && metadata.mBlockwiseReceiveHook != nullptr)
1184                     {
1185                         error =
1186                             SendNextBlock2Request(*request, aMessage, aMessageInfo, metadata, totalTransfereSize, true);
1187                     }
1188 
1189                     FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1190                     break;
1191                 default:
1192                     error = kErrorAbort;
1193                     FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, error);
1194                     break;
1195                 }
1196             }
1197 #else  // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1198             {
1199                 FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1200             }
1201 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1202         }
1203 
1204         // Silently ignore acknowledgments carrying requests (RFC 7252, p. 4.2)
1205         // or with no token match (RFC 7252, p. 5.3.2)
1206         break;
1207 
1208     case kTypeConfirmable:
1209         // Send empty ACK if it is a CON message.
1210         IgnoreError(SendAck(aMessage, aMessageInfo));
1211 
1212         OT_FALL_THROUGH;
1213         // Handling of RFC7641 and multicast is below.
1214     case kTypeNonConfirmable:
1215         // Separate response or observation notification.  If the request was to a multicast
1216         // address, OR both the request and response carry Observe options, then this is NOT
1217         // the final message, we may see multiples.
1218         if ((metadata.mResponseHandler != nullptr) && (metadata.mDestinationAddress.IsMulticast()
1219 #if OPENTHREAD_CONFIG_COAP_OBSERVE_API_ENABLE
1220                                                        || (metadata.mObserve && responseObserve)
1221 #endif
1222                                                            ))
1223         {
1224             // If multicast non-confirmable request, allow multiple responses
1225             metadata.mResponseHandler(metadata.mResponseContext, &aMessage, &aMessageInfo, kErrorNone);
1226         }
1227         else
1228         {
1229             FinalizeCoapTransaction(*request, metadata, &aMessage, &aMessageInfo, kErrorNone);
1230         }
1231 
1232         break;
1233     }
1234 
1235 exit:
1236 
1237     if (error == kErrorNone && request == nullptr)
1238     {
1239         if (aMessage.IsConfirmable() || aMessage.IsNonConfirmable())
1240         {
1241             // Successfully parsed a header but no matching request was
1242             // found - reject the message by sending reset.
1243             IgnoreError(SendReset(aMessage, aMessageInfo));
1244         }
1245     }
1246 }
1247 
ProcessReceivedRequest(Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1248 void CoapBase::ProcessReceivedRequest(Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1249 {
1250     char     uriPath[Message::kMaxReceivedUriPath + 1];
1251     Message *cachedResponse = nullptr;
1252     Error    error          = kErrorNotFound;
1253 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1254     Option::Iterator iterator;
1255     char *           curUriPath         = uriPath;
1256     uint8_t          blockOptionType    = 0;
1257     uint32_t         totalTransfereSize = 0;
1258 #endif
1259 
1260     if (mInterceptor != nullptr)
1261     {
1262         SuccessOrExit(error = mInterceptor(aMessage, aMessageInfo, mContext));
1263     }
1264 
1265     switch (mResponsesQueue.GetMatchedResponseCopy(aMessage, aMessageInfo, &cachedResponse))
1266     {
1267     case kErrorNone:
1268         cachedResponse->Finish();
1269         error = Send(*cachedResponse, aMessageInfo);
1270 
1271         OT_FALL_THROUGH;
1272 
1273     case kErrorNoBufs:
1274         ExitNow();
1275 
1276     case kErrorNotFound:
1277     default:
1278         break;
1279     }
1280 
1281 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1282     SuccessOrExit(error = iterator.Init(aMessage));
1283 
1284     while (!iterator.IsDone())
1285     {
1286         switch (iterator.GetOption()->GetNumber())
1287         {
1288         case kOptionUriPath:
1289             if (curUriPath != uriPath)
1290             {
1291                 *curUriPath++ = '/';
1292             }
1293 
1294             VerifyOrExit(curUriPath + iterator.GetOption()->GetLength() < OT_ARRAY_END(uriPath), error = kErrorParse);
1295 
1296             IgnoreError(iterator.ReadOptionValue(curUriPath));
1297             curUriPath += iterator.GetOption()->GetLength();
1298             break;
1299 
1300         case kOptionBlock1:
1301             blockOptionType += 1;
1302             break;
1303 
1304         case kOptionBlock2:
1305             blockOptionType += 2;
1306             break;
1307 
1308         case kOptionSize1:
1309             // ToDo: wait for method to read uint option values
1310             totalTransfereSize = 0;
1311             break;
1312 
1313         default:
1314             break;
1315         }
1316 
1317         SuccessOrExit(error = iterator.Advance());
1318     }
1319 
1320     curUriPath[0] = '\0';
1321 
1322     for (const ResourceBlockWise &resource : mBlockWiseResources)
1323     {
1324         if (strcmp(resource.GetUriPath(), uriPath) != 0)
1325         {
1326             continue;
1327         }
1328 
1329         if ((resource.mReceiveHook != nullptr || resource.mTransmitHook != nullptr) && blockOptionType != 0)
1330         {
1331             switch (blockOptionType)
1332             {
1333             case 1:
1334                 if (resource.mReceiveHook != nullptr)
1335                 {
1336                     switch (ProcessBlock1Request(aMessage, aMessageInfo, resource, totalTransfereSize))
1337                     {
1338                     case kErrorNone:
1339                         resource.HandleRequest(aMessage, aMessageInfo);
1340                         // Fall through
1341                     case kErrorBusy:
1342                         error = kErrorNone;
1343                         break;
1344                     case kErrorNoBufs:
1345                         IgnoreReturnValue(SendHeaderResponse(kCodeRequestTooLarge, aMessage, aMessageInfo));
1346                         error = kErrorDrop;
1347                         break;
1348                     case kErrorNoFrameReceived:
1349                         IgnoreReturnValue(SendHeaderResponse(kCodeRequestIncomplete, aMessage, aMessageInfo));
1350                         error = kErrorDrop;
1351                         break;
1352                     default:
1353                         IgnoreReturnValue(SendHeaderResponse(kCodeInternalError, aMessage, aMessageInfo));
1354                         error = kErrorDrop;
1355                         break;
1356                     }
1357                 }
1358                 break;
1359             case 2:
1360                 if (resource.mTransmitHook != nullptr)
1361                 {
1362                     if ((error = ProcessBlock2Request(aMessage, aMessageInfo, resource)) != kErrorNone)
1363                     {
1364                         IgnoreReturnValue(SendHeaderResponse(kCodeInternalError, aMessage, aMessageInfo));
1365                         error = kErrorDrop;
1366                     }
1367                 }
1368                 break;
1369             }
1370             ExitNow();
1371         }
1372         else
1373         {
1374             resource.HandleRequest(aMessage, aMessageInfo);
1375             error = kErrorNone;
1376             ExitNow();
1377         }
1378     }
1379 #else
1380     SuccessOrExit(error = aMessage.ReadUriPathOptions(uriPath));
1381 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
1382 
1383     for (const Resource &resource : mResources)
1384     {
1385         if (strcmp(resource.mUriPath, uriPath) == 0)
1386         {
1387             resource.HandleRequest(aMessage, aMessageInfo);
1388             error = kErrorNone;
1389             ExitNow();
1390         }
1391     }
1392 
1393     if (mDefaultHandler)
1394     {
1395         mDefaultHandler(mDefaultHandlerContext, &aMessage, &aMessageInfo);
1396         error = kErrorNone;
1397     }
1398 
1399 exit:
1400 
1401     if (error != kErrorNone)
1402     {
1403         otLogInfoCoap("Failed to process request: %s", ErrorToString(error));
1404 
1405         if (error == kErrorNotFound && !aMessageInfo.GetSockAddr().IsMulticast())
1406         {
1407             IgnoreError(SendNotFound(aMessage, aMessageInfo));
1408         }
1409 
1410         FreeMessage(cachedResponse);
1411     }
1412 }
1413 
ReadFrom(const Message & aMessage)1414 void CoapBase::Metadata::ReadFrom(const Message &aMessage)
1415 {
1416     uint16_t length = aMessage.GetLength();
1417 
1418     OT_ASSERT(length >= sizeof(*this));
1419     IgnoreError(aMessage.Read(length - sizeof(*this), *this));
1420 }
1421 
UpdateIn(Message & aMessage) const1422 void CoapBase::Metadata::UpdateIn(Message &aMessage) const
1423 {
1424     aMessage.Write(aMessage.GetLength() - sizeof(*this), *this);
1425 }
1426 
ResponsesQueue(Instance & aInstance)1427 ResponsesQueue::ResponsesQueue(Instance &aInstance)
1428     : mTimer(aInstance, ResponsesQueue::HandleTimer, this)
1429 {
1430 }
1431 
GetMatchedResponseCopy(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo,Message ** aResponse)1432 Error ResponsesQueue::GetMatchedResponseCopy(const Message &         aRequest,
1433                                              const Ip6::MessageInfo &aMessageInfo,
1434                                              Message **              aResponse)
1435 {
1436     Error          error = kErrorNone;
1437     const Message *cacheResponse;
1438 
1439     cacheResponse = FindMatchedResponse(aRequest, aMessageInfo);
1440     VerifyOrExit(cacheResponse != nullptr, error = kErrorNotFound);
1441 
1442     *aResponse = cacheResponse->Clone(cacheResponse->GetLength() - sizeof(ResponseMetadata));
1443     VerifyOrExit(*aResponse != nullptr, error = kErrorNoBufs);
1444 
1445 exit:
1446     return error;
1447 }
1448 
FindMatchedResponse(const Message & aRequest,const Ip6::MessageInfo & aMessageInfo) const1449 const Message *ResponsesQueue::FindMatchedResponse(const Message &aRequest, const Ip6::MessageInfo &aMessageInfo) const
1450 {
1451     Message *message;
1452 
1453     for (message = mQueue.GetHead(); message != nullptr; message = message->GetNextCoapMessage())
1454     {
1455         if (message->GetMessageId() == aRequest.GetMessageId())
1456         {
1457             ResponseMetadata metadata;
1458 
1459             metadata.ReadFrom(*message);
1460 
1461             if ((metadata.mMessageInfo.GetPeerPort() == aMessageInfo.GetPeerPort()) &&
1462                 (metadata.mMessageInfo.GetPeerAddr() == aMessageInfo.GetPeerAddr()))
1463             {
1464                 break;
1465             }
1466         }
1467     }
1468 
1469     return message;
1470 }
1471 
EnqueueResponse(Message & aMessage,const Ip6::MessageInfo & aMessageInfo,const TxParameters & aTxParameters)1472 void ResponsesQueue::EnqueueResponse(Message &               aMessage,
1473                                      const Ip6::MessageInfo &aMessageInfo,
1474                                      const TxParameters &    aTxParameters)
1475 {
1476     Message *        responseCopy;
1477     ResponseMetadata metadata;
1478 
1479     metadata.mDequeueTime = TimerMilli::GetNow() + aTxParameters.CalculateExchangeLifetime();
1480     metadata.mMessageInfo = aMessageInfo;
1481 
1482     VerifyOrExit(FindMatchedResponse(aMessage, aMessageInfo) == nullptr);
1483 
1484     UpdateQueue();
1485 
1486     VerifyOrExit((responseCopy = aMessage.Clone()) != nullptr);
1487 
1488     VerifyOrExit(metadata.AppendTo(*responseCopy) == kErrorNone, responseCopy->Free());
1489 
1490     mQueue.Enqueue(*responseCopy);
1491 
1492     mTimer.FireAtIfEarlier(metadata.mDequeueTime);
1493 
1494 exit:
1495     return;
1496 }
1497 
UpdateQueue(void)1498 void ResponsesQueue::UpdateQueue(void)
1499 {
1500     uint16_t  msgCount    = 0;
1501     Message * earliestMsg = nullptr;
1502     TimeMilli earliestDequeueTime(0);
1503 
1504     // Check the number of messages in the queue and if number is at
1505     // `kMaxCachedResponses` remove the one with earliest dequeue
1506     // time.
1507 
1508     for (Message *message = mQueue.GetHead(); message != nullptr; message = message->GetNextCoapMessage())
1509     {
1510         ResponseMetadata metadata;
1511 
1512         metadata.ReadFrom(*message);
1513 
1514         if ((earliestMsg == nullptr) || (metadata.mDequeueTime < earliestDequeueTime))
1515         {
1516             earliestMsg         = message;
1517             earliestDequeueTime = metadata.mDequeueTime;
1518         }
1519 
1520         msgCount++;
1521     }
1522 
1523     if (msgCount >= kMaxCachedResponses)
1524     {
1525         DequeueResponse(*earliestMsg);
1526     }
1527 }
1528 
DequeueResponse(Message & aMessage)1529 void ResponsesQueue::DequeueResponse(Message &aMessage)
1530 {
1531     mQueue.DequeueAndFree(aMessage);
1532 }
1533 
DequeueAllResponses(void)1534 void ResponsesQueue::DequeueAllResponses(void)
1535 {
1536     mQueue.DequeueAndFreeAll();
1537 }
1538 
HandleTimer(Timer & aTimer)1539 void ResponsesQueue::HandleTimer(Timer &aTimer)
1540 {
1541     static_cast<ResponsesQueue *>(static_cast<TimerMilliContext &>(aTimer).GetContext())->HandleTimer();
1542 }
1543 
HandleTimer(void)1544 void ResponsesQueue::HandleTimer(void)
1545 {
1546     TimeMilli now             = TimerMilli::GetNow();
1547     TimeMilli nextDequeueTime = now.GetDistantFuture();
1548     Message * nextMessage;
1549 
1550     for (Message *message = mQueue.GetHead(); message != nullptr; message = nextMessage)
1551     {
1552         ResponseMetadata metadata;
1553 
1554         nextMessage = message->GetNextCoapMessage();
1555 
1556         metadata.ReadFrom(*message);
1557 
1558         if (now >= metadata.mDequeueTime)
1559         {
1560             DequeueResponse(*message);
1561             continue;
1562         }
1563 
1564         if (metadata.mDequeueTime < nextDequeueTime)
1565         {
1566             nextDequeueTime = metadata.mDequeueTime;
1567         }
1568     }
1569 
1570     if (nextDequeueTime < now.GetDistantFuture())
1571     {
1572         mTimer.FireAt(nextDequeueTime);
1573     }
1574 }
1575 
ReadFrom(const Message & aMessage)1576 void ResponsesQueue::ResponseMetadata::ReadFrom(const Message &aMessage)
1577 {
1578     uint16_t length = aMessage.GetLength();
1579 
1580     OT_ASSERT(length >= sizeof(*this));
1581     IgnoreError(aMessage.Read(length - sizeof(*this), *this));
1582 }
1583 
1584 /// Return product of @p aValueA and @p aValueB if no overflow otherwise 0.
Multiply(uint32_t aValueA,uint32_t aValueB)1585 static uint32_t Multiply(uint32_t aValueA, uint32_t aValueB)
1586 {
1587     uint32_t result = 0;
1588 
1589     VerifyOrExit(aValueA);
1590 
1591     result = aValueA * aValueB;
1592     result = (result / aValueA == aValueB) ? result : 0;
1593 
1594 exit:
1595     return result;
1596 }
1597 
IsValid(void) const1598 bool TxParameters::IsValid(void) const
1599 {
1600     bool rval = false;
1601 
1602     if ((mAckRandomFactorDenominator > 0) && (mAckRandomFactorNumerator >= mAckRandomFactorDenominator) &&
1603         (mAckTimeout >= OT_COAP_MIN_ACK_TIMEOUT) && (mMaxRetransmit <= OT_COAP_MAX_RETRANSMIT))
1604     {
1605         // Calulate exchange lifetime step by step and verify no overflow.
1606         uint32_t tmp = Multiply(mAckTimeout, (1U << (mMaxRetransmit + 1)) - 1);
1607 
1608         tmp = Multiply(tmp, mAckRandomFactorNumerator);
1609         tmp /= mAckRandomFactorDenominator;
1610 
1611         rval = (tmp != 0 && (tmp + mAckTimeout + 2 * kDefaultMaxLatency) > tmp);
1612     }
1613 
1614     return rval;
1615 }
1616 
CalculateInitialRetransmissionTimeout(void) const1617 uint32_t TxParameters::CalculateInitialRetransmissionTimeout(void) const
1618 {
1619     return Random::NonCrypto::GetUint32InRange(
1620         mAckTimeout, mAckTimeout * mAckRandomFactorNumerator / mAckRandomFactorDenominator + 1);
1621 }
1622 
CalculateExchangeLifetime(void) const1623 uint32_t TxParameters::CalculateExchangeLifetime(void) const
1624 {
1625     // Final `mAckTimeout` is to account for processing delay.
1626     return CalculateSpan(mMaxRetransmit) + 2 * kDefaultMaxLatency + mAckTimeout;
1627 }
1628 
CalculateMaxTransmitWait(void) const1629 uint32_t TxParameters::CalculateMaxTransmitWait(void) const
1630 {
1631     return CalculateSpan(mMaxRetransmit + 1);
1632 }
1633 
CalculateSpan(uint8_t aMaxRetx) const1634 uint32_t TxParameters::CalculateSpan(uint8_t aMaxRetx) const
1635 {
1636     return static_cast<uint32_t>(mAckTimeout * ((1U << aMaxRetx) - 1) / mAckRandomFactorDenominator *
1637                                  mAckRandomFactorNumerator);
1638 }
1639 
1640 const otCoapTxParameters TxParameters::kDefaultTxParameters = {
1641     kDefaultAckTimeout,
1642     kDefaultAckRandomFactorNumerator,
1643     kDefaultAckRandomFactorDenominator,
1644     kDefaultMaxRetransmit,
1645 };
1646 
Coap(Instance & aInstance)1647 Coap::Coap(Instance &aInstance)
1648     : CoapBase(aInstance, &Coap::Send)
1649     , mSocket(aInstance)
1650 {
1651 }
1652 
Start(uint16_t aPort,otNetifIdentifier aNetifIdentifier)1653 Error Coap::Start(uint16_t aPort, otNetifIdentifier aNetifIdentifier)
1654 {
1655     Error error        = kErrorNone;
1656     bool  socketOpened = false;
1657 
1658     VerifyOrExit(!mSocket.IsBound());
1659 
1660     SuccessOrExit(error = mSocket.Open(&Coap::HandleUdpReceive, this));
1661     socketOpened = true;
1662 
1663     SuccessOrExit(error = mSocket.Bind(aPort, aNetifIdentifier));
1664 
1665 exit:
1666     if (error != kErrorNone && socketOpened)
1667     {
1668         IgnoreError(mSocket.Close());
1669     }
1670 
1671     return error;
1672 }
1673 
Stop(void)1674 Error Coap::Stop(void)
1675 {
1676     Error error = kErrorNone;
1677 
1678     VerifyOrExit(mSocket.IsBound());
1679 
1680     SuccessOrExit(error = mSocket.Close());
1681     ClearRequestsAndResponses();
1682 
1683 exit:
1684     return error;
1685 }
1686 
HandleUdpReceive(void * aContext,otMessage * aMessage,const otMessageInfo * aMessageInfo)1687 void Coap::HandleUdpReceive(void *aContext, otMessage *aMessage, const otMessageInfo *aMessageInfo)
1688 {
1689     static_cast<Coap *>(aContext)->Receive(*static_cast<Message *>(aMessage),
1690                                            *static_cast<const Ip6::MessageInfo *>(aMessageInfo));
1691 }
1692 
Send(CoapBase & aCoapBase,ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1693 Error Coap::Send(CoapBase &aCoapBase, ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1694 {
1695     return static_cast<Coap &>(aCoapBase).Send(aMessage, aMessageInfo);
1696 }
1697 
Send(ot::Message & aMessage,const Ip6::MessageInfo & aMessageInfo)1698 Error Coap::Send(ot::Message &aMessage, const Ip6::MessageInfo &aMessageInfo)
1699 {
1700     return mSocket.IsBound() ? mSocket.SendTo(aMessage, aMessageInfo) : kErrorInvalidState;
1701 }
1702 
1703 } // namespace Coap
1704 } // namespace ot
1705