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