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