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