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