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 
AppendBlockOption(Message::BlockType aType,uint32_t aNum,bool aMore,otCoapBlockSzx aSize)278 Error Message::AppendBlockOption(Message::BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSzx aSize)
279 {
280     Error    error   = kErrorNone;
281     uint32_t encoded = aSize;
282 
283     VerifyOrExit(aType == kBlockType1 || aType == kBlockType2, error = kErrorInvalidArgs);
284     VerifyOrExit(aSize <= OT_COAP_OPTION_BLOCK_SZX_1024, error = kErrorInvalidArgs);
285     VerifyOrExit(aNum < kBlockNumMax, error = kErrorInvalidArgs);
286 
287     encoded |= static_cast<uint32_t>(aMore << kBlockMOffset);
288     encoded |= aNum << kBlockNumOffset;
289 
290     error = AppendUintOption((aType == kBlockType1) ? kOptionBlock1 : kOptionBlock2, encoded);
291 
292 exit:
293     return error;
294 }
295 
296 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
ReadBlockOptionValues(uint16_t aBlockType)297 Error Message::ReadBlockOptionValues(uint16_t aBlockType)
298 {
299     Error            error                     = kErrorNone;
300     uint8_t          buf[kMaxOptionHeaderSize] = {0};
301     Option::Iterator iterator;
302 
303     VerifyOrExit((aBlockType == kOptionBlock1) || (aBlockType == kOptionBlock2), error = kErrorInvalidArgs);
304 
305     SuccessOrExit(error = iterator.Init(*this, aBlockType));
306     SuccessOrExit(error = iterator.ReadOptionValue(buf));
307 
308     SetBlockWiseBlockNumber(0);
309     SetMoreBlocksFlag(false);
310 
311     switch (iterator.GetOption()->GetLength())
312     {
313     case 0:
314     case 1:
315         SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] & 0xf0) >> 4));
316         SetMoreBlocksFlag(static_cast<bool>((buf[0] & 0x08) >> 3 == 1));
317         SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[0] & 0x07));
318         break;
319     case 2:
320         SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 4) + ((buf[1] & 0xf0) >> 4)));
321         SetMoreBlocksFlag(static_cast<bool>((buf[1] & 0x08) >> 3 == 1));
322         SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[1] & 0x07));
323         break;
324     case 3:
325         SetBlockWiseBlockNumber(static_cast<uint32_t>((buf[0] << 12) + (buf[1] << 4) + ((buf[2] & 0xf0) >> 4)));
326         SetMoreBlocksFlag(static_cast<bool>((buf[2] & 0x08) >> 3 == 1));
327         SetBlockWiseBlockSize(static_cast<otCoapBlockSzx>(buf[2] & 0x07));
328         break;
329     default:
330         error = kErrorInvalidArgs;
331         break;
332     }
333 
334 exit:
335     return error;
336 }
337 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
338 
SetPayloadMarker(void)339 Error Message::SetPayloadMarker(void)
340 {
341     Error   error  = kErrorNone;
342     uint8_t marker = kPayloadMarker;
343 
344     VerifyOrExit(GetLength() < kMaxHeaderLength, error = kErrorNoBufs);
345     SuccessOrExit(error = Append(marker));
346     GetHelpData().mPayloadMarkerSet = true;
347     GetHelpData().mHeaderLength     = GetLength();
348 
349     // Set offset to the start of payload.
350     SetOffset(GetHelpData().mHeaderLength);
351 
352 exit:
353     return error;
354 }
355 
ParseHeader(void)356 Error Message::ParseHeader(void)
357 {
358     Error            error = kErrorNone;
359     Option::Iterator iterator;
360 
361     OT_ASSERT(GetReserved() >=
362               sizeof(HelpData) + static_cast<size_t>((reinterpret_cast<uint8_t *>(&GetHelpData()) - GetFirstData())));
363 
364     GetHelpData().Clear();
365 
366     GetHelpData().mHeaderOffset = GetOffset();
367     IgnoreError(Read(GetHelpData().mHeaderOffset, GetHelpData().mHeader));
368 
369     VerifyOrExit(GetTokenLength() <= kMaxTokenLength, error = kErrorParse);
370 
371     SuccessOrExit(error = iterator.Init(*this));
372 
373     while (!iterator.IsDone())
374     {
375         SuccessOrExit(error = iterator.Advance());
376     }
377 
378     GetHelpData().mHeaderLength = iterator.GetPayloadMessageOffset() - GetHelpData().mHeaderOffset;
379     MoveOffset(GetHelpData().mHeaderLength);
380 
381 exit:
382     return error;
383 }
384 
SetToken(const uint8_t * aToken,uint8_t aTokenLength)385 Error Message::SetToken(const uint8_t *aToken, uint8_t aTokenLength)
386 {
387     OT_ASSERT(aTokenLength <= kMaxTokenLength);
388 
389     SetTokenLength(aTokenLength);
390     memcpy(GetToken(), aToken, aTokenLength);
391     GetHelpData().mHeaderLength += aTokenLength;
392 
393     return SetLength(GetHelpData().mHeaderLength);
394 }
395 
GenerateRandomToken(uint8_t aTokenLength)396 Error Message::GenerateRandomToken(uint8_t aTokenLength)
397 {
398     uint8_t token[kMaxTokenLength];
399 
400     OT_ASSERT(aTokenLength <= sizeof(token));
401 
402     IgnoreError(Random::Crypto::FillBuffer(token, aTokenLength));
403 
404     return SetToken(token, aTokenLength);
405 }
406 
SetTokenFromMessage(const Message & aMessage)407 Error Message::SetTokenFromMessage(const Message &aMessage)
408 {
409     return SetToken(aMessage.GetToken(), aMessage.GetTokenLength());
410 }
411 
IsTokenEqual(const Message & aMessage) const412 bool Message::IsTokenEqual(const Message &aMessage) const
413 {
414     uint8_t tokenLength = GetTokenLength();
415 
416     return ((tokenLength == aMessage.GetTokenLength()) && (memcmp(GetToken(), aMessage.GetToken(), tokenLength) == 0));
417 }
418 
SetDefaultResponseHeader(const Message & aRequest)419 Error Message::SetDefaultResponseHeader(const Message &aRequest)
420 {
421     Init(kTypeAck, kCodeChanged);
422 
423     SetMessageId(aRequest.GetMessageId());
424 
425     return SetTokenFromMessage(aRequest);
426 }
427 
Clone(uint16_t aLength) const428 Message *Message::Clone(uint16_t aLength) const
429 {
430     Message *message = static_cast<Message *>(ot::Message::Clone(aLength));
431 
432     VerifyOrExit(message != nullptr);
433 
434     message->GetHelpData() = GetHelpData();
435 
436 exit:
437     return message;
438 }
439 
440 #if OPENTHREAD_CONFIG_COAP_API_ENABLE
CodeToString(void) const441 const char *Message::CodeToString(void) const
442 {
443     static constexpr Stringify::Entry kCodeTable[] = {
444         {kCodeEmpty, "Empty"},
445         {kCodeGet, "Get"},
446         {kCodePost, "Post"},
447         {kCodePut, "Put"},
448         {kCodeDelete, "Delete"},
449         {kCodeCreated, "Created"},
450         {kCodeDeleted, "Deleted"},
451         {kCodeValid, "Valid"},
452         {kCodeChanged, "Changed"},
453         {kCodeContent, "Content"},
454         {kCodeContinue, "Continue"},
455         {kCodeBadRequest, "BadRequest"},
456         {kCodeUnauthorized, "Unauthorized"},
457         {kCodeBadOption, "BadOption"},
458         {kCodeForbidden, "Forbidden"},
459         {kCodeNotFound, "NotFound"},
460         {kCodeMethodNotAllowed, "MethodNotAllowed"},
461         {kCodeNotAcceptable, "NotAcceptable"},
462         {kCodeRequestIncomplete, "RequestIncomplete"},
463         {kCodePreconditionFailed, "PreconditionFailed"},
464         {kCodeRequestTooLarge, "RequestTooLarge"},
465         {kCodeUnsupportedFormat, "UnsupportedFormat"},
466         {kCodeInternalError, "InternalError"},
467         {kCodeNotImplemented, "NotImplemented"},
468         {kCodeBadGateway, "BadGateway"},
469         {kCodeServiceUnavailable, "ServiceUnavailable"},
470         {kCodeGatewayTimeout, "GatewayTimeout"},
471         {kCodeProxyNotSupported, "ProxyNotSupported"},
472     };
473 
474     static_assert(Stringify::IsSorted(kCodeTable), "kCodeTable is not sorted");
475 
476     return Stringify::Lookup(GetCode(), kCodeTable, "Unknown");
477 }
478 #endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
479 
begin(void)480 Message::Iterator MessageQueue::begin(void) { return Message::Iterator(GetHead()); }
481 
begin(void) const482 Message::ConstIterator MessageQueue::begin(void) const { return Message::ConstIterator(GetHead()); }
483 
Init(const Message & aMessage)484 Error Option::Iterator::Init(const Message &aMessage)
485 {
486     Error    error  = kErrorParse;
487     uint32_t offset = static_cast<uint32_t>(aMessage.GetHelpData().mHeaderOffset) + aMessage.GetOptionStart();
488 
489     // Note that the case where `offset == aMessage.GetLength())` is
490     // valid and indicates an empty payload (no CoAP Option and no
491     // Payload Marker).
492 
493     VerifyOrExit(offset <= aMessage.GetLength(), MarkAsParseErrored());
494 
495     mOption.mNumber   = 0;
496     mOption.mLength   = 0;
497     mMessage          = &aMessage;
498     mNextOptionOffset = static_cast<uint16_t>(offset);
499 
500     error = Advance();
501 
502 exit:
503     return error;
504 }
505 
Advance(void)506 Error Option::Iterator::Advance(void)
507 {
508     Error    error = kErrorNone;
509     uint8_t  headerByte;
510     uint16_t optionDelta;
511     uint16_t optionLength;
512 
513     VerifyOrExit(!IsDone());
514 
515     error = Read(sizeof(uint8_t), &headerByte);
516 
517     if ((error != kErrorNone) || (headerByte == Message::kPayloadMarker))
518     {
519         // Payload Marker indicates end of options and start of payload.
520         // Absence of a Payload Marker indicates a zero-length payload.
521 
522         MarkAsDone();
523 
524         if (error == kErrorNone)
525         {
526             // The presence of a marker followed by a zero-length payload
527             // MUST be processed as a message format error.
528 
529             VerifyOrExit(mNextOptionOffset < GetMessage().GetLength(), error = kErrorParse);
530         }
531 
532         ExitNow(error = kErrorNone);
533     }
534 
535     optionDelta = (headerByte & Message::kOptionDeltaMask) >> Message::kOptionDeltaOffset;
536     SuccessOrExit(error = ReadExtendedOptionField(optionDelta));
537 
538     optionLength = (headerByte & Message::kOptionLengthMask) >> Message::kOptionLengthOffset;
539     SuccessOrExit(error = ReadExtendedOptionField(optionLength));
540 
541     VerifyOrExit(optionLength <= GetMessage().GetLength() - mNextOptionOffset, error = kErrorParse);
542     mNextOptionOffset += optionLength;
543 
544     mOption.mNumber += optionDelta;
545     mOption.mLength = optionLength;
546 
547 exit:
548     if (error != kErrorNone)
549     {
550         MarkAsParseErrored();
551     }
552 
553     return error;
554 }
555 
ReadOptionValue(void * aValue) const556 Error Option::Iterator::ReadOptionValue(void *aValue) const
557 {
558     Error error = kErrorNone;
559 
560     VerifyOrExit(!IsDone(), error = kErrorNotFound);
561     GetMessage().ReadBytes(mNextOptionOffset - mOption.mLength, aValue, mOption.mLength);
562 
563 exit:
564     return error;
565 }
566 
ReadOptionValue(uint64_t & aUintValue) const567 Error Option::Iterator::ReadOptionValue(uint64_t &aUintValue) const
568 {
569     Error   error = kErrorNone;
570     uint8_t buffer[sizeof(uint64_t)];
571 
572     VerifyOrExit(!IsDone(), error = kErrorNotFound);
573 
574     VerifyOrExit(mOption.mLength <= sizeof(uint64_t), error = kErrorNoBufs);
575     IgnoreError(ReadOptionValue(buffer));
576 
577     aUintValue = 0;
578 
579     for (uint16_t pos = 0; pos < mOption.mLength; pos++)
580     {
581         aUintValue <<= kBitsPerByte;
582         aUintValue |= buffer[pos];
583     }
584 
585 exit:
586     return error;
587 }
588 
Read(uint16_t aLength,void * aBuffer)589 Error Option::Iterator::Read(uint16_t aLength, void *aBuffer)
590 {
591     // Reads `aLength` bytes from the message into `aBuffer` at
592     // `mNextOptionOffset` and updates the `mNextOptionOffset` on a
593     // successful read (i.e., when entire `aLength` bytes can be read).
594 
595     Error error = kErrorNone;
596 
597     SuccessOrExit(error = GetMessage().Read(mNextOptionOffset, aBuffer, aLength));
598     mNextOptionOffset += aLength;
599 
600 exit:
601     return error;
602 }
603 
ReadExtendedOptionField(uint16_t & aValue)604 Error Option::Iterator::ReadExtendedOptionField(uint16_t &aValue)
605 {
606     Error error = kErrorNone;
607 
608     VerifyOrExit(aValue >= Message::kOption1ByteExtension);
609 
610     if (aValue == Message::kOption1ByteExtension)
611     {
612         uint8_t value8;
613 
614         SuccessOrExit(error = Read(sizeof(uint8_t), &value8));
615         aValue = static_cast<uint16_t>(value8) + Message::kOption1ByteExtensionOffset;
616     }
617     else if (aValue == Message::kOption2ByteExtension)
618     {
619         uint16_t value16;
620 
621         SuccessOrExit(error = Read(sizeof(uint16_t), &value16));
622         value16 = BigEndian::HostSwap16(value16);
623         aValue  = value16 + Message::kOption2ByteExtensionOffset;
624     }
625     else
626     {
627         error = kErrorParse;
628     }
629 
630 exit:
631     return error;
632 }
633 
InitOrAdvance(const Message * aMessage,uint16_t aNumber)634 Error Option::Iterator::InitOrAdvance(const Message *aMessage, uint16_t aNumber)
635 {
636     Error error = (aMessage != nullptr) ? Init(*aMessage) : Advance();
637 
638     while ((error == kErrorNone) && !IsDone() && (GetOption()->GetNumber() != aNumber))
639     {
640         error = Advance();
641     }
642 
643     return error;
644 }
645 
646 } // namespace Coap
647 } // namespace ot
648