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