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