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 /**
30  * @file
31  *   This file implements the CoAP message generation and parsing.
32  */
33 
34 #include "coap_message.hpp"
35 
36 #include "coap/coap.hpp"
37 #include "common/array.hpp"
38 #include "common/code_utils.hpp"
39 #include "common/debug.hpp"
40 #include "common/encoding.hpp"
41 #include "common/random.hpp"
42 #include "common/string.hpp"
43 #include "instance/instance.hpp"
44 
45 namespace ot {
46 namespace Coap {
47 
Init(void)48 void Message::Init(void)
49 {
50     GetHelpData().Clear();
51     SetVersion(kVersion1);
52     SetOffset(0);
53     GetHelpData().mHeaderLength = kMinHeaderLength;
54 
55     IgnoreError(SetLength(GetHelpData().mHeaderLength));
56 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
57     SetBlockWiseBlockNumber(0);
58     SetMoreBlocksFlag(false);
59     SetBlockWiseBlockSize(OT_COAP_OPTION_BLOCK_SZX_16);
60 #endif
61 }
62 
Init(Type aType,Code aCode)63 void Message::Init(Type aType, Code aCode)
64 {
65     Init();
66     SetType(aType);
67     SetCode(aCode);
68 }
69 
Init(Type aType,Code aCode,Uri aUri)70 Error Message::Init(Type aType, Code aCode, Uri aUri)
71 {
72     Error error;
73 
74     Init(aType, aCode);
75     SuccessOrExit(error = GenerateRandomToken(kDefaultTokenLength));
76     SuccessOrExit(error = AppendUriPathOptions(PathForUri(aUri)));
77 
78 exit:
79     return error;
80 }
81 
InitAsPost(const Ip6::Address & aDestination,Uri aUri)82 Error Message::InitAsPost(const Ip6::Address &aDestination, Uri aUri)
83 {
84     return Init(aDestination.IsMulticast() ? kTypeNonConfirmable : kTypeConfirmable, kCodePost, aUri);
85 }
86 
IsConfirmablePostRequest(void) const87 bool Message::IsConfirmablePostRequest(void) const { return IsConfirmable() && IsPostRequest(); }
88 
IsNonConfirmablePostRequest(void) const89 bool Message::IsNonConfirmablePostRequest(void) const { return IsNonConfirmable() && IsPostRequest(); }
90 
Finish(void)91 void Message::Finish(void)
92 {
93     // If the payload marker is set but the message contains no
94     // payload, we remove the payload marker from the message. Note
95     // that the presence of a marker followed by a zero-length payload
96     // will be processed as a message format error on the receiver.
97 
98     if (GetHelpData().mPayloadMarkerSet && (GetHelpData().mHeaderLength == GetLength()))
99     {
100         RemoveFooter(sizeof(uint8_t));
101     }
102 
103     WriteBytes(0, &GetHelpData().mHeader, GetOptionStart());
104 }
105 
WriteExtendedOptionField(uint16_t aValue,uint8_t * & aBuffer)106 uint8_t Message::WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer)
107 {
108     /*
109      * Encodes a CoAP Option header field (Option Delta/Length) per
110      * RFC 7252. The returned value is a 4-bit unsigned integer. Extended fields
111      * (if needed) are written into the given buffer `aBuffer` and the pointer
112      * would also be updated.
113      *
114      * If `aValue < 13 (kOption1ByteExtensionOffset)`, it is returned as is
115      * (no extension).
116      *
117      * If `13 <= aValue < 269 (kOption2ByteExtensionOffset)`, one-byte
118      * extension is used, and the value minus 13 is written in `aBuffer` as an
119      * 8-bit unsigned integer, and `13 (kOption1ByteExtension)` is returned.
120      *
121      * If `269 <= aValue`, two-byte extension is used and the value minis 269
122      * is written as a 16-bit unsigned integer and `14 (kOption2ByteExtension)`
123      * is returned.
124      *
125      */
126 
127     uint8_t rval;
128 
129     if (aValue < kOption1ByteExtensionOffset)
130     {
131         rval = static_cast<uint8_t>(aValue);
132     }
133     else if (aValue < kOption2ByteExtensionOffset)
134     {
135         rval     = kOption1ByteExtension;
136         *aBuffer = static_cast<uint8_t>(aValue - kOption1ByteExtensionOffset);
137         aBuffer += sizeof(uint8_t);
138     }
139     else
140     {
141         rval = kOption2ByteExtension;
142         BigEndian::WriteUint16(aValue - kOption2ByteExtensionOffset, aBuffer);
143         aBuffer += sizeof(uint16_t);
144     }
145 
146     return rval;
147 }
148 
AppendOptionHeader(uint16_t aNumber,uint16_t aLength)149 Error Message::AppendOptionHeader(uint16_t aNumber, uint16_t aLength)
150 {
151     /*
152      * Appends a CoAP Option header field (Option Delta/Length) per RFC 7252.
153      */
154 
155     Error    error = kErrorNone;
156     uint16_t delta;
157     uint8_t  header[kMaxOptionHeaderSize];
158     uint16_t headerLength;
159     uint8_t *cur;
160 
161     VerifyOrExit(aNumber >= GetHelpData().mOptionLast, error = kErrorInvalidArgs);
162     delta = aNumber - GetHelpData().mOptionLast;
163 
164     cur = &header[1];
165 
166     header[0] = static_cast<uint8_t>(WriteExtendedOptionField(delta, cur) << kOptionDeltaOffset);
167     header[0] |= static_cast<uint8_t>(WriteExtendedOptionField(aLength, cur) << kOptionLengthOffset);
168 
169     headerLength = static_cast<uint16_t>(cur - header);
170 
171     VerifyOrExit(static_cast<uint32_t>(GetLength()) + headerLength + aLength < kMaxHeaderLength, error = kErrorNoBufs);
172 
173     SuccessOrExit(error = AppendBytes(header, headerLength));
174 
175     GetHelpData().mOptionLast = aNumber;
176 
177 exit:
178     return error;
179 }
180 
AppendOption(uint16_t aNumber,uint16_t aLength,const void * aValue)181 Error Message::AppendOption(uint16_t aNumber, uint16_t aLength, const void *aValue)
182 {
183     Error error = kErrorNone;
184 
185     SuccessOrExit(error = AppendOptionHeader(aNumber, aLength));
186     SuccessOrExit(error = AppendBytes(aValue, aLength));
187 
188     GetHelpData().mHeaderLength = GetLength();
189 
190 exit:
191     return error;
192 }
193 
AppendOptionFromMessage(uint16_t aNumber,uint16_t aLength,const Message & aMessage,uint16_t aOffset)194 Error Message::AppendOptionFromMessage(uint16_t aNumber, uint16_t aLength, const Message &aMessage, uint16_t aOffset)
195 {
196     Error error = kErrorNone;
197 
198     SuccessOrExit(error = AppendOptionHeader(aNumber, aLength));
199     SuccessOrExit(error = AppendBytesFromMessage(aMessage, aOffset, aLength));
200 
201     GetHelpData().mHeaderLength = GetLength();
202 
203 exit:
204     return error;
205 }
206 
AppendUintOption(uint16_t aNumber,uint32_t aValue)207 Error Message::AppendUintOption(uint16_t aNumber, uint32_t aValue)
208 {
209     uint8_t        buffer[sizeof(uint32_t)];
210     const uint8_t *value  = &buffer[0];
211     uint16_t       length = sizeof(uint32_t);
212 
213     BigEndian::WriteUint32(aValue, buffer);
214 
215     while ((length > 0) && (value[0] == 0))
216     {
217         value++;
218         length--;
219     }
220 
221     return AppendOption(aNumber, length, value);
222 }
223 
AppendStringOption(uint16_t aNumber,const char * aValue)224 Error Message::AppendStringOption(uint16_t aNumber, const char *aValue)
225 {
226     return AppendOption(aNumber, static_cast<uint16_t>(strlen(aValue)), aValue);
227 }
228 
AppendUriPathOptions(const char * aUriPath)229 Error Message::AppendUriPathOptions(const char *aUriPath)
230 {
231     Error       error = kErrorNone;
232     const char *cur   = aUriPath;
233     const char *end;
234 
235     while ((end = StringFind(cur, '/')) != nullptr)
236     {
237         SuccessOrExit(error = AppendOption(kOptionUriPath, static_cast<uint16_t>(end - cur), cur));
238         cur = end + 1;
239     }
240 
241     SuccessOrExit(error = AppendStringOption(kOptionUriPath, cur));
242 
243 exit:
244     return error;
245 }
246 
ReadUriPathOptions(char (& aUriPath)[kMaxReceivedUriPath+1]) const247 Error Message::ReadUriPathOptions(char (&aUriPath)[kMaxReceivedUriPath + 1]) const
248 {
249     char            *curUriPath = aUriPath;
250     Error            error      = kErrorNone;
251     Option::Iterator iterator;
252 
253     SuccessOrExit(error = iterator.Init(*this, kOptionUriPath));
254 
255     while (!iterator.IsDone())
256     {
257         uint16_t optionLength = iterator.GetOption()->GetLength();
258 
259         if (curUriPath != aUriPath)
260         {
261             *curUriPath++ = '/';
262         }
263 
264         VerifyOrExit(curUriPath + optionLength < GetArrayEnd(aUriPath), error = kErrorParse);
265 
266         IgnoreError(iterator.ReadOptionValue(curUriPath));
267         curUriPath += optionLength;
268 
269         SuccessOrExit(error = iterator.Advance(kOptionUriPath));
270     }
271 
272     *curUriPath = '\0';
273 
274 exit:
275     return error;
276 }
277 
AppendUriQueryOptions(const char * aUriQuery)278 Error Message::AppendUriQueryOptions(const char *aUriQuery)
279 {
280     Error       error = kErrorNone;
281     const char *cur   = aUriQuery;
282     const char *end;
283 
284     while ((end = StringFind(cur, '&')) != nullptr)
285     {
286         SuccessOrExit(error = AppendOption(kOptionUriQuery, static_cast<uint16_t>(end - cur), cur));
287         cur = end + 1;
288     }
289 
290     SuccessOrExit(error = AppendStringOption(kOptionUriQuery, cur));
291 
292 exit:
293     return error;
294 }
295 
AppendBlockOption(Message::BlockType aType,uint32_t aNum,bool aMore,otCoapBlockSzx aSize)296 Error Message::AppendBlockOption(Message::BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSzx aSize)
297 {
298     Error    error   = kErrorNone;
299     uint32_t encoded = aSize;
300 
301     VerifyOrExit(aType == kBlockType1 || aType == kBlockType2, error = kErrorInvalidArgs);
302     VerifyOrExit(aSize <= OT_COAP_OPTION_BLOCK_SZX_1024, error = kErrorInvalidArgs);
303     VerifyOrExit(aNum < kBlockNumMax, error = kErrorInvalidArgs);
304 
305     encoded |= static_cast<uint32_t>(aMore << kBlockMOffset);
306     encoded |= aNum << kBlockNumOffset;
307 
308     error = AppendUintOption((aType == kBlockType1) ? kOptionBlock1 : kOptionBlock2, encoded);
309 
310 exit:
311     return error;
312 }
313 
314 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
ReadBlockOptionValues(uint16_t aBlockType)315 Error Message::ReadBlockOptionValues(uint16_t aBlockType)
316 {
317     Error            error                     = kErrorNone;
318     uint8_t          buf[kMaxOptionHeaderSize] = {0};
319     Option::Iterator iterator;
320 
321     VerifyOrExit((aBlockType == kOptionBlock1) || (aBlockType == kOptionBlock2), error = kErrorInvalidArgs);
322 
323     SuccessOrExit(error = iterator.Init(*this, aBlockType));
324     SuccessOrExit(error = iterator.ReadOptionValue(buf));
325 
326     SetBlockWiseBlockNumber(0);
327     SetMoreBlocksFlag(false);
328 
329     switch (iterator.GetOption()->GetLength())
330     {
331     case 0:
332     case 1:
333         SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] & 0xf0) >> 4));
334         SetMoreBlocksFlag(static_cast<bool>((buf[0] & 0x08) >> 3 == 1));
335         SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[0] & 0x07));
336         break;
337     case 2:
338         SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 4) + ((buf[1] & 0xf0) >> 4)));
339         SetMoreBlocksFlag(static_cast<bool>((buf[1] & 0x08) >> 3 == 1));
340         SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[1] & 0x07));
341         break;
342     case 3:
343         SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 12) + (buf[1] << 4) + ((buf[2] & 0xf0) >> 4)));
344         SetMoreBlocksFlag(static_cast<bool>((buf[2] & 0x08) >> 3 == 1));
345         SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[2] & 0x07));
346         break;
347     default:
348         error = kErrorInvalidArgs;
349         break;
350     }
351 
352 exit:
353     return error;
354 }
355 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
356 
SetPayloadMarker(void)357 Error Message::SetPayloadMarker(void)
358 {
359     Error   error  = kErrorNone;
360     uint8_t marker = kPayloadMarker;
361 
362     VerifyOrExit(GetLength() < kMaxHeaderLength, error = kErrorNoBufs);
363     SuccessOrExit(error = Append(marker));
364     GetHelpData().mPayloadMarkerSet = true;
365     GetHelpData().mHeaderLength     = GetLength();
366 
367     // Set offset to the start of payload.
368     SetOffset(GetHelpData().mHeaderLength);
369 
370 exit:
371     return error;
372 }
373 
ParseHeader(void)374 Error Message::ParseHeader(void)
375 {
376     Error            error = kErrorNone;
377     Option::Iterator iterator;
378 
379     OT_ASSERT(GetReserved() >=
380               sizeof(HelpData) + static_cast<size_t>((reinterpret_cast<uint8_t *>(&GetHelpData()) - GetFirstData())));
381 
382     GetHelpData().Clear();
383 
384     GetHelpData().mHeaderOffset = GetOffset();
385     IgnoreError(Read(GetHelpData().mHeaderOffset, GetHelpData().mHeader));
386 
387     VerifyOrExit(GetTokenLength() <= kMaxTokenLength, error = kErrorParse);
388 
389     SuccessOrExit(error = iterator.Init(*this));
390 
391     while (!iterator.IsDone())
392     {
393         SuccessOrExit(error = iterator.Advance());
394     }
395 
396     GetHelpData().mHeaderLength = iterator.GetPayloadMessageOffset() - GetHelpData().mHeaderOffset;
397     MoveOffset(GetHelpData().mHeaderLength);
398 
399 exit:
400     return error;
401 }
402 
SetToken(const uint8_t * aToken,uint8_t aTokenLength)403 Error Message::SetToken(const uint8_t *aToken, uint8_t aTokenLength)
404 {
405     OT_ASSERT(aTokenLength <= kMaxTokenLength);
406 
407     SetTokenLength(aTokenLength);
408     memcpy(GetToken(), aToken, aTokenLength);
409     GetHelpData().mHeaderLength += aTokenLength;
410 
411     return SetLength(GetHelpData().mHeaderLength);
412 }
413 
GenerateRandomToken(uint8_t aTokenLength)414 Error Message::GenerateRandomToken(uint8_t aTokenLength)
415 {
416     uint8_t token[kMaxTokenLength];
417 
418     OT_ASSERT(aTokenLength <= sizeof(token));
419 
420     IgnoreError(Random::Crypto::FillBuffer(token, aTokenLength));
421 
422     return SetToken(token, aTokenLength);
423 }
424 
SetTokenFromMessage(const Message & aMessage)425 Error Message::SetTokenFromMessage(const Message &aMessage)
426 {
427     return SetToken(aMessage.GetToken(), aMessage.GetTokenLength());
428 }
429 
IsTokenEqual(const Message & aMessage) const430 bool Message::IsTokenEqual(const Message &aMessage) const
431 {
432     uint8_t tokenLength = GetTokenLength();
433 
434     return ((tokenLength == aMessage.GetTokenLength()) && (memcmp(GetToken(), aMessage.GetToken(), tokenLength) == 0));
435 }
436 
SetDefaultResponseHeader(const Message & aRequest)437 Error Message::SetDefaultResponseHeader(const Message &aRequest)
438 {
439     Init(kTypeAck, kCodeChanged);
440 
441     SetMessageId(aRequest.GetMessageId());
442 
443     return SetTokenFromMessage(aRequest);
444 }
445 
Clone(uint16_t aLength) const446 Message *Message::Clone(uint16_t aLength) const
447 {
448     Message *message = static_cast<Message *>(ot::Message::Clone(aLength));
449 
450     VerifyOrExit(message != nullptr);
451 
452     message->GetHelpData() = GetHelpData();
453 
454 exit:
455     return message;
456 }
457 
458 #if OPENTHREAD_CONFIG_COAP_API_ENABLE
CodeToString(void) const459 const char *Message::CodeToString(void) const
460 {
461     static constexpr Stringify::Entry kCodeTable[] = {
462         {kCodeEmpty, "Empty"},
463         {kCodeGet, "Get"},
464         {kCodePost, "Post"},
465         {kCodePut, "Put"},
466         {kCodeDelete, "Delete"},
467         {kCodeCreated, "Created"},
468         {kCodeDeleted, "Deleted"},
469         {kCodeValid, "Valid"},
470         {kCodeChanged, "Changed"},
471         {kCodeContent, "Content"},
472         {kCodeContinue, "Continue"},
473         {kCodeBadRequest, "BadRequest"},
474         {kCodeUnauthorized, "Unauthorized"},
475         {kCodeBadOption, "BadOption"},
476         {kCodeForbidden, "Forbidden"},
477         {kCodeNotFound, "NotFound"},
478         {kCodeMethodNotAllowed, "MethodNotAllowed"},
479         {kCodeNotAcceptable, "NotAcceptable"},
480         {kCodeRequestIncomplete, "RequestIncomplete"},
481         {kCodePreconditionFailed, "PreconditionFailed"},
482         {kCodeRequestTooLarge, "RequestTooLarge"},
483         {kCodeUnsupportedFormat, "UnsupportedFormat"},
484         {kCodeInternalError, "InternalError"},
485         {kCodeNotImplemented, "NotImplemented"},
486         {kCodeBadGateway, "BadGateway"},
487         {kCodeServiceUnavailable, "ServiceUnavailable"},
488         {kCodeGatewayTimeout, "GatewayTimeout"},
489         {kCodeProxyNotSupported, "ProxyNotSupported"},
490     };
491 
492     static_assert(Stringify::IsSorted(kCodeTable), "kCodeTable is not sorted");
493 
494     return Stringify::Lookup(GetCode(), kCodeTable, "Unknown");
495 }
496 #endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
497 
begin(void)498 Message::Iterator MessageQueue::begin(void) { return Message::Iterator(GetHead()); }
499 
begin(void) const500 Message::ConstIterator MessageQueue::begin(void) const { return Message::ConstIterator(GetHead()); }
501 
Init(const Message & aMessage)502 Error Option::Iterator::Init(const Message &aMessage)
503 {
504     Error    error  = kErrorParse;
505     uint32_t offset = static_cast<uint32_t>(aMessage.GetHelpData().mHeaderOffset) + aMessage.GetOptionStart();
506 
507     // Note that the case where `offset == aMessage.GetLength())` is
508     // valid and indicates an empty payload (no CoAP Option and no
509     // Payload Marker).
510 
511     VerifyOrExit(offset <= aMessage.GetLength(), MarkAsParseErrored());
512 
513     mOption.mNumber   = 0;
514     mOption.mLength   = 0;
515     mMessage          = &aMessage;
516     mNextOptionOffset = static_cast<uint16_t>(offset);
517 
518     error = Advance();
519 
520 exit:
521     return error;
522 }
523 
Advance(void)524 Error Option::Iterator::Advance(void)
525 {
526     Error    error = kErrorNone;
527     uint8_t  headerByte;
528     uint16_t optionDelta;
529     uint16_t optionLength;
530 
531     VerifyOrExit(!IsDone());
532 
533     error = Read(sizeof(uint8_t), &headerByte);
534 
535     if ((error != kErrorNone) || (headerByte == Message::kPayloadMarker))
536     {
537         // Payload Marker indicates end of options and start of payload.
538         // Absence of a Payload Marker indicates a zero-length payload.
539 
540         MarkAsDone();
541 
542         if (error == kErrorNone)
543         {
544             // The presence of a marker followed by a zero-length payload
545             // MUST be processed as a message format error.
546 
547             VerifyOrExit(mNextOptionOffset < GetMessage().GetLength(), error = kErrorParse);
548         }
549 
550         ExitNow(error = kErrorNone);
551     }
552 
553     optionDelta = (headerByte & Message::kOptionDeltaMask) >> Message::kOptionDeltaOffset;
554     SuccessOrExit(error = ReadExtendedOptionField(optionDelta));
555 
556     optionLength = (headerByte & Message::kOptionLengthMask) >> Message::kOptionLengthOffset;
557     SuccessOrExit(error = ReadExtendedOptionField(optionLength));
558 
559     VerifyOrExit(optionLength <= GetMessage().GetLength() - mNextOptionOffset, error = kErrorParse);
560     mNextOptionOffset += optionLength;
561 
562     mOption.mNumber += optionDelta;
563     mOption.mLength = optionLength;
564 
565 exit:
566     if (error != kErrorNone)
567     {
568         MarkAsParseErrored();
569     }
570 
571     return error;
572 }
573 
ReadOptionValue(void * aValue) const574 Error Option::Iterator::ReadOptionValue(void *aValue) const
575 {
576     Error error = kErrorNone;
577 
578     VerifyOrExit(!IsDone(), error = kErrorNotFound);
579     GetMessage().ReadBytes(mNextOptionOffset - mOption.mLength, aValue, mOption.mLength);
580 
581 exit:
582     return error;
583 }
584 
ReadOptionValue(uint64_t & aUintValue) const585 Error Option::Iterator::ReadOptionValue(uint64_t &aUintValue) const
586 {
587     Error   error = kErrorNone;
588     uint8_t buffer[sizeof(uint64_t)];
589 
590     VerifyOrExit(!IsDone(), error = kErrorNotFound);
591 
592     VerifyOrExit(mOption.mLength <= sizeof(uint64_t), error = kErrorNoBufs);
593     IgnoreError(ReadOptionValue(buffer));
594 
595     aUintValue = 0;
596 
597     for (uint16_t pos = 0; pos < mOption.mLength; pos++)
598     {
599         aUintValue <<= kBitsPerByte;
600         aUintValue |= buffer[pos];
601     }
602 
603 exit:
604     return error;
605 }
606 
Read(uint16_t aLength,void * aBuffer)607 Error Option::Iterator::Read(uint16_t aLength, void *aBuffer)
608 {
609     // Reads `aLength` bytes from the message into `aBuffer` at
610     // `mNextOptionOffset` and updates the `mNextOptionOffset` on a
611     // successful read (i.e., when entire `aLength` bytes can be read).
612 
613     Error error = kErrorNone;
614 
615     SuccessOrExit(error = GetMessage().Read(mNextOptionOffset, aBuffer, aLength));
616     mNextOptionOffset += aLength;
617 
618 exit:
619     return error;
620 }
621 
ReadExtendedOptionField(uint16_t & aValue)622 Error Option::Iterator::ReadExtendedOptionField(uint16_t &aValue)
623 {
624     Error error = kErrorNone;
625 
626     VerifyOrExit(aValue >= Message::kOption1ByteExtension);
627 
628     if (aValue == Message::kOption1ByteExtension)
629     {
630         uint8_t value8;
631 
632         SuccessOrExit(error = Read(sizeof(uint8_t), &value8));
633         aValue = static_cast<uint16_t>(value8) + Message::kOption1ByteExtensionOffset;
634     }
635     else if (aValue == Message::kOption2ByteExtension)
636     {
637         uint16_t value16;
638 
639         SuccessOrExit(error = Read(sizeof(uint16_t), &value16));
640         value16 = BigEndian::HostSwap16(value16);
641         aValue  = value16 + Message::kOption2ByteExtensionOffset;
642     }
643     else
644     {
645         error = kErrorParse;
646     }
647 
648 exit:
649     return error;
650 }
651 
InitOrAdvance(const Message * aMessage,uint16_t aNumber)652 Error Option::Iterator::InitOrAdvance(const Message *aMessage, uint16_t aNumber)
653 {
654     Error error = (aMessage != nullptr) ? Init(*aMessage) : Advance();
655 
656     while ((error == kErrorNone) && !IsDone() && (GetOption()->GetNumber() != aNumber))
657     {
658         error = Advance();
659     }
660 
661     return error;
662 }
663 
664 } // namespace Coap
665 } // namespace ot
666