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