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 includes definitions for generating and processing CoAP messages.
32  */
33 
34 #ifndef COAP_HEADER_HPP_
35 #define COAP_HEADER_HPP_
36 
37 #include "openthread-core-config.h"
38 
39 #include <openthread/coap.h>
40 
41 #include "common/as_core_type.hpp"
42 #include "common/clearable.hpp"
43 #include "common/code_utils.hpp"
44 #include "common/const_cast.hpp"
45 #include "common/encoding.hpp"
46 #include "common/message.hpp"
47 #include "net/ip6.hpp"
48 #include "net/ip6_address.hpp"
49 #include "net/udp6.hpp"
50 #include "thread/uri_paths.hpp"
51 
52 namespace ot {
53 
54 /**
55  * @namespace ot::Coap
56  * @brief
57  *   This namespace includes definitions for CoAP.
58  *
59  */
60 namespace Coap {
61 
62 using ot::Encoding::BigEndian::HostSwap16;
63 
64 /**
65  * @addtogroup core-coap
66  *
67  * @brief
68  *   This module includes definitions for CoAP.
69  *
70  * @{
71  *
72  */
73 
74 class Option;
75 
76 /**
77  * CoAP Type values.
78  *
79  */
80 enum Type : uint8_t
81 {
82     kTypeConfirmable    = OT_COAP_TYPE_CONFIRMABLE,     ///< Confirmable type.
83     kTypeNonConfirmable = OT_COAP_TYPE_NON_CONFIRMABLE, ///< Non-confirmable type.
84     kTypeAck            = OT_COAP_TYPE_ACKNOWLEDGMENT,  ///< Acknowledgment type.
85     kTypeReset          = OT_COAP_TYPE_RESET,           ///< Reset type.
86 };
87 
88 /**
89  * CoAP Code values.
90  *
91  */
92 enum Code : uint8_t
93 {
94     // Request Codes:
95 
96     kCodeEmpty  = OT_COAP_CODE_EMPTY,  ///< Empty message code
97     kCodeGet    = OT_COAP_CODE_GET,    ///< Get
98     kCodePost   = OT_COAP_CODE_POST,   ///< Post
99     kCodePut    = OT_COAP_CODE_PUT,    ///< Put
100     kCodeDelete = OT_COAP_CODE_DELETE, ///< Delete
101 
102     // Response Codes:
103 
104     kCodeResponseMin = OT_COAP_CODE_RESPONSE_MIN, ///< 2.00
105     kCodeCreated     = OT_COAP_CODE_CREATED,      ///< Created
106     kCodeDeleted     = OT_COAP_CODE_DELETED,      ///< Deleted
107     kCodeValid       = OT_COAP_CODE_VALID,        ///< Valid
108     kCodeChanged     = OT_COAP_CODE_CHANGED,      ///< Changed
109     kCodeContent     = OT_COAP_CODE_CONTENT,      ///< Content
110     kCodeContinue    = OT_COAP_CODE_CONTINUE,     ///< RFC7959 Continue
111 
112     // Client Error Codes:
113 
114     kCodeBadRequest         = OT_COAP_CODE_BAD_REQUEST,         ///< Bad Request
115     kCodeUnauthorized       = OT_COAP_CODE_UNAUTHORIZED,        ///< Unauthorized
116     kCodeBadOption          = OT_COAP_CODE_BAD_OPTION,          ///< Bad Option
117     kCodeForbidden          = OT_COAP_CODE_FORBIDDEN,           ///< Forbidden
118     kCodeNotFound           = OT_COAP_CODE_NOT_FOUND,           ///< Not Found
119     kCodeMethodNotAllowed   = OT_COAP_CODE_METHOD_NOT_ALLOWED,  ///< Method Not Allowed
120     kCodeNotAcceptable      = OT_COAP_CODE_NOT_ACCEPTABLE,      ///< Not Acceptable
121     kCodeRequestIncomplete  = OT_COAP_CODE_REQUEST_INCOMPLETE,  ///< RFC7959 Request Entity Incomplete
122     kCodePreconditionFailed = OT_COAP_CODE_PRECONDITION_FAILED, ///< Precondition Failed
123     kCodeRequestTooLarge    = OT_COAP_CODE_REQUEST_TOO_LARGE,   ///< Request Entity Too Large
124     kCodeUnsupportedFormat  = OT_COAP_CODE_UNSUPPORTED_FORMAT,  ///< Unsupported Content-Format
125 
126     // Server Error Codes:
127 
128     kCodeInternalError      = OT_COAP_CODE_INTERNAL_ERROR,      ///< Internal Server Error
129     kCodeNotImplemented     = OT_COAP_CODE_NOT_IMPLEMENTED,     ///< Not Implemented
130     kCodeBadGateway         = OT_COAP_CODE_BAD_GATEWAY,         ///< Bad Gateway
131     kCodeServiceUnavailable = OT_COAP_CODE_SERVICE_UNAVAILABLE, ///< Service Unavailable
132     kCodeGatewayTimeout     = OT_COAP_CODE_GATEWAY_TIMEOUT,     ///< Gateway Timeout
133     kCodeProxyNotSupported  = OT_COAP_CODE_PROXY_NOT_SUPPORTED, ///< Proxying Not Supported
134 };
135 
136 /**
137  * CoAP Option Numbers.
138  *
139  */
140 enum OptionNumber : uint16_t
141 {
142     kOptionIfMatch       = OT_COAP_OPTION_IF_MATCH,       ///< If-Match
143     kOptionUriHost       = OT_COAP_OPTION_URI_HOST,       ///< Uri-Host
144     kOptionETag          = OT_COAP_OPTION_E_TAG,          ///< ETag
145     kOptionIfNoneMatch   = OT_COAP_OPTION_IF_NONE_MATCH,  ///< If-None-Match
146     kOptionObserve       = OT_COAP_OPTION_OBSERVE,        ///< Observe [RFC7641]
147     kOptionUriPort       = OT_COAP_OPTION_URI_PORT,       ///< Uri-Port
148     kOptionLocationPath  = OT_COAP_OPTION_LOCATION_PATH,  ///< Location-Path
149     kOptionUriPath       = OT_COAP_OPTION_URI_PATH,       ///< Uri-Path
150     kOptionContentFormat = OT_COAP_OPTION_CONTENT_FORMAT, ///< Content-Format
151     kOptionMaxAge        = OT_COAP_OPTION_MAX_AGE,        ///< Max-Age
152     kOptionUriQuery      = OT_COAP_OPTION_URI_QUERY,      ///< Uri-Query
153     kOptionAccept        = OT_COAP_OPTION_ACCEPT,         ///< Accept
154     kOptionLocationQuery = OT_COAP_OPTION_LOCATION_QUERY, ///< Location-Query
155     kOptionBlock2        = OT_COAP_OPTION_BLOCK2,         ///< Block2 (RFC7959)
156     kOptionBlock1        = OT_COAP_OPTION_BLOCK1,         ///< Block1 (RFC7959)
157     kOptionSize2         = OT_COAP_OPTION_SIZE2,          ///< Size2 (RFC7959)
158     kOptionProxyUri      = OT_COAP_OPTION_PROXY_URI,      ///< Proxy-Uri
159     kOptionProxyScheme   = OT_COAP_OPTION_PROXY_SCHEME,   ///< Proxy-Scheme
160     kOptionSize1         = OT_COAP_OPTION_SIZE1,          ///< Size1
161 };
162 
163 /**
164  * Implements CoAP message generation and parsing.
165  *
166  */
167 class Message : public ot::Message
168 {
169     friend class Option;
170     friend class MessageQueue;
171 
172 public:
173     static constexpr uint8_t kDefaultTokenLength = OT_COAP_DEFAULT_TOKEN_LENGTH; ///< Default token length.
174     static constexpr uint8_t kMaxReceivedUriPath = 32;                           ///< Max URI path length on rx msgs.
175     static constexpr uint8_t kMaxTokenLength     = OT_COAP_MAX_TOKEN_LENGTH;     ///< Maximum token length.
176 
177     typedef ot::Coap::Type Type; ///< CoAP Type.
178     typedef ot::Coap::Code Code; ///< CoAP Code.
179 
180     /**
181      * CoAP Block1/Block2 Types
182      *
183      */
184     enum BlockType : uint8_t
185     {
186         kBlockType1 = 1,
187         kBlockType2 = 2,
188     };
189 
190     static constexpr uint8_t kBlockSzxBase = 4;
191 
192     /**
193      * Initializes the CoAP header.
194      *
195      */
196     void Init(void);
197 
198     /**
199      * Initializes the CoAP header with specific Type and Code.
200      *
201      * @param[in]  aType  The Type value.
202      * @param[in]  aCode  The Code value.
203      *
204      */
205     void Init(Type aType, Code aCode);
206 
207     /**
208      * Initializes the CoAP header with specific Type and Code.
209      *
210      * @param[in]  aType              The Type value.
211      * @param[in]  aCode              The Code value.
212      * @param[in]  aUri               The URI.
213      *
214      * @retval kErrorNone         Successfully appended the option.
215      * @retval kErrorNoBufs       The option length exceeds the buffer size.
216      *
217      */
218     Error Init(Type aType, Code aCode, Uri aUri);
219 
220     /**
221      * Initializes the CoAP header as `kCodePost` with a given URI Path with its type determined from a
222      * given destination IPv6 address.
223      *
224      * @param[in]  aDestination       The message destination IPv6 address used to determine the CoAP type,
225      *                                `kTypeNonConfirmable` if multicast address, `kTypeConfirmable` otherwise.
226      * @param[in]  aUri               The URI.
227      *
228      * @retval kErrorNone         Successfully appended the option.
229      * @retval kErrorNoBufs       The option length exceeds the buffer size.
230      *
231      */
232     Error InitAsPost(const Ip6::Address &aDestination, Uri aUri);
233 
234     /**
235      * Writes header to the message. This must be called before sending the message.
236      *
237      * Also checks whether the payload marker is set (`SetPayloadMarker()`) but the message contains no
238      * payload, and if so it removes the payload marker from the message.
239      *
240      */
241     void Finish(void);
242 
243     /**
244      * Returns the Version value.
245      *
246      * @returns The Version value.
247      *
248      */
GetVersion(void) const249     uint8_t GetVersion(void) const
250     {
251         return (GetHelpData().mHeader.mVersionTypeToken & kVersionMask) >> kVersionOffset;
252     }
253 
254     /**
255      * Sets the Version value.
256      *
257      * @param[in]  aVersion  The Version value.
258      *
259      */
SetVersion(uint8_t aVersion)260     void SetVersion(uint8_t aVersion)
261     {
262         GetHelpData().mHeader.mVersionTypeToken &= ~kVersionMask;
263         GetHelpData().mHeader.mVersionTypeToken |= aVersion << kVersionOffset;
264     }
265 
266     /**
267      * Returns the Type value.
268      *
269      * @returns The Type value.
270      *
271      */
GetType(void) const272     uint8_t GetType(void) const { return (GetHelpData().mHeader.mVersionTypeToken & kTypeMask) >> kTypeOffset; }
273 
274     /**
275      * Sets the Type value.
276      *
277      * @param[in]  aType  The Type value.
278      *
279      */
SetType(Type aType)280     void SetType(Type aType)
281     {
282         GetHelpData().mHeader.mVersionTypeToken &= ~kTypeMask;
283         GetHelpData().mHeader.mVersionTypeToken |= (static_cast<uint8_t>(aType) << kTypeOffset);
284     }
285 
286     /**
287      * Returns the Code value.
288      *
289      * @returns The Code value.
290      *
291      */
GetCode(void) const292     uint8_t GetCode(void) const { return static_cast<Code>(GetHelpData().mHeader.mCode); }
293 
294     /**
295      * Sets the Code value.
296      *
297      * @param[in]  aCode  The Code value.
298      *
299      */
SetCode(Code aCode)300     void SetCode(Code aCode) { GetHelpData().mHeader.mCode = static_cast<uint8_t>(aCode); }
301 
302 #if OPENTHREAD_CONFIG_COAP_API_ENABLE
303     /**
304      * Returns the CoAP Code as human readable string.
305      *
306      * @ returns The CoAP Code as string.
307      *
308      */
309     const char *CodeToString(void) const;
310 #endif // OPENTHREAD_CONFIG_COAP_API_ENABLE
311 
312     /**
313      * Returns the Message ID value.
314      *
315      * @returns The Message ID value.
316      *
317      */
GetMessageId(void) const318     uint16_t GetMessageId(void) const { return HostSwap16(GetHelpData().mHeader.mMessageId); }
319 
320     /**
321      * Sets the Message ID value.
322      *
323      * @param[in]  aMessageId  The Message ID value.
324      *
325      */
SetMessageId(uint16_t aMessageId)326     void SetMessageId(uint16_t aMessageId) { GetHelpData().mHeader.mMessageId = HostSwap16(aMessageId); }
327 
328     /**
329      * Returns the Token length.
330      *
331      * @returns The Token length.
332      *
333      */
GetTokenLength(void) const334     uint8_t GetTokenLength(void) const
335     {
336         return (GetHelpData().mHeader.mVersionTypeToken & kTokenLengthMask) >> kTokenLengthOffset;
337     }
338 
339     /**
340      * Returns a pointer to the Token value.
341      *
342      * @returns A pointer to the Token value.
343      *
344      */
GetToken(void) const345     const uint8_t *GetToken(void) const { return GetHelpData().mHeader.mToken; }
346 
347     /**
348      * Sets the Token value and length.
349      *
350      * @param[in]  aToken        A pointer to the Token value.
351      * @param[in]  aTokenLength  The Length of @p aToken.
352      *
353      * @retval kErrorNone    Successfully set the token value.
354      * @retval kErrorNoBufs  Insufficient message buffers available to set the token value.
355      *
356      */
357     Error SetToken(const uint8_t *aToken, uint8_t aTokenLength);
358 
359     /**
360      * Sets the Token value and length by copying it from another given message.
361      *
362      * @param[in] aMessage       The message to copy the Token from.
363      *
364      * @retval kErrorNone    Successfully set the token value.
365      * @retval kErrorNoBufs  Insufficient message buffers available to set the token value.
366      *
367      */
368     Error SetTokenFromMessage(const Message &aMessage);
369 
370     /**
371      * Sets the Token length and randomizes its value.
372      *
373      * @param[in]  aTokenLength  The Length of a Token to set.
374      *
375      * @retval kErrorNone    Successfully set the token value.
376      * @retval kErrorNoBufs  Insufficient message buffers available to set the token value.
377      *
378      */
379     Error GenerateRandomToken(uint8_t aTokenLength);
380 
381     /**
382      * Checks if Tokens in two CoAP headers are equal.
383      *
384      * @param[in]  aMessage  A header to compare.
385      *
386      * @retval TRUE   If two Tokens are equal.
387      * @retval FALSE  If Tokens differ in length or value.
388      *
389      */
390     bool IsTokenEqual(const Message &aMessage) const;
391 
392     /**
393      * Appends a CoAP option.
394      *
395      * @param[in] aNumber   The CoAP Option number.
396      * @param[in] aLength   The CoAP Option length.
397      * @param[in] aValue    A pointer to the CoAP Option value (@p aLength bytes are used as Option value).
398      *
399      * @retval kErrorNone         Successfully appended the option.
400      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
401      * @retval kErrorNoBufs       The option length exceeds the buffer size.
402      *
403      */
404     Error AppendOption(uint16_t aNumber, uint16_t aLength, const void *aValue);
405 
406     /**
407      * Appends an unsigned integer CoAP option as specified in RFC-7252 section-3.2
408      *
409      * @param[in]  aNumber  The CoAP Option number.
410      * @param[in]  aValue   The CoAP Option unsigned integer value.
411      *
412      * @retval kErrorNone         Successfully appended the option.
413      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
414      * @retval kErrorNoBufs       The option length exceeds the buffer size.
415      *
416      */
417     Error AppendUintOption(uint16_t aNumber, uint32_t aValue);
418 
419     /**
420      * Appends a string CoAP option.
421      *
422      * @param[in]  aNumber  The CoAP Option number.
423      * @param[in]  aValue   The CoAP Option string value.
424      *
425      * @retval kErrorNone         Successfully appended the option.
426      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
427      * @retval kErrorNoBufs       The option length exceeds the buffer size.
428      *
429      */
430     Error AppendStringOption(uint16_t aNumber, const char *aValue);
431 
432     /**
433      * Appends an Observe option.
434      *
435      * @param[in]  aObserve  Observe field value.
436      *
437      * @retval kErrorNone         Successfully appended the option.
438      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
439      * @retval kErrorNoBufs       The option length exceeds the buffer size.
440      */
AppendObserveOption(uint32_t aObserve)441     Error AppendObserveOption(uint32_t aObserve) { return AppendUintOption(kOptionObserve, aObserve & kObserveMask); }
442 
443     /**
444      * Appends a Uri-Path option.
445      *
446      * @param[in]  aUriPath           A pointer to a null-terminated string.
447      *
448      * @retval kErrorNone         Successfully appended the option.
449      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
450      * @retval kErrorNoBufs       The option length exceeds the buffer size.
451      *
452      */
453     Error AppendUriPathOptions(const char *aUriPath);
454 
455     /**
456      * Reads the Uri-Path options and constructs the URI path in the buffer referenced by @p `aUriPath`.
457      *
458      * @param[in] aUriPath  A reference to the buffer for storing URI path.
459      *                      NOTE: The buffer size must be `kMaxReceivedUriPath + 1`.
460      *
461      * @retval  kErrorNone   Successfully read the Uri-Path options.
462      * @retval  kErrorParse  CoAP Option header not well-formed.
463      *
464      */
465     Error ReadUriPathOptions(char (&aUriPath)[kMaxReceivedUriPath + 1]) const;
466 
467     /**
468      * Appends a Block option
469      *
470      * @param[in]  aType              Type of block option, 1 or 2.
471      * @param[in]  aNum               Current block number.
472      * @param[in]  aMore              Boolean to indicate more blocks are to be sent.
473      * @param[in]  aSize              Maximum block size.
474      *
475      * @retval kErrorNone         Successfully appended the option.
476      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
477      * @retval kErrorNoBufs       The option length exceeds the buffer size.
478      *
479      */
480     Error AppendBlockOption(BlockType aType, uint32_t aNum, bool aMore, otCoapBlockSzx aSize);
481 
482     /**
483      * Appends a Proxy-Uri option.
484      *
485      * @param[in]  aProxyUri          A pointer to a null-terminated string.
486      *
487      * @retval kErrorNone         Successfully appended the option.
488      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
489      * @retval kErrorNoBufs       The option length exceeds the buffer size.
490      *
491      */
AppendProxyUriOption(const char * aProxyUri)492     Error AppendProxyUriOption(const char *aProxyUri) { return AppendStringOption(kOptionProxyUri, aProxyUri); }
493 
494     /**
495      * Appends a Content-Format option.
496      *
497      * @param[in]  aContentFormat  The Content Format value.
498      *
499      * @retval kErrorNone         Successfully appended the option.
500      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
501      * @retval kErrorNoBufs       The option length exceeds the buffer size.
502      *
503      */
AppendContentFormatOption(otCoapOptionContentFormat aContentFormat)504     Error AppendContentFormatOption(otCoapOptionContentFormat aContentFormat)
505     {
506         return AppendUintOption(kOptionContentFormat, static_cast<uint32_t>(aContentFormat));
507     }
508 
509     /**
510      * Appends a Max-Age option.
511      *
512      * @param[in]  aMaxAge  The Max-Age value.
513      *
514      * @retval kErrorNone         Successfully appended the option.
515      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
516      * @retval kErrorNoBufs       The option length exceeds the buffer size.
517      */
AppendMaxAgeOption(uint32_t aMaxAge)518     Error AppendMaxAgeOption(uint32_t aMaxAge) { return AppendUintOption(kOptionMaxAge, aMaxAge); }
519 
520     /**
521      * Appends a single Uri-Query option.
522      *
523      * @param[in]  aUriQuery  A pointer to null-terminated string, which should contain a single key=value pair.
524      *
525      * @retval kErrorNone         Successfully appended the option.
526      * @retval kErrorInvalidArgs  The option type is not equal or greater than the last option type.
527      * @retval kErrorNoBufs       The option length exceeds the buffer size.
528      */
AppendUriQueryOption(const char * aUriQuery)529     Error AppendUriQueryOption(const char *aUriQuery) { return AppendStringOption(kOptionUriQuery, aUriQuery); }
530 
531 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
532     /**
533      * Reads the information contained in a Block1 or Block2 option and set it in
534      * the HelpData of the message.
535      *
536      * @param[in]   aBlockType  Block1 or Block2 option value.
537      *
538      * @retval  kErrorNone          The option has been found and is valid.
539      * @retval  kErrorNotFound      The option has not been found.
540      * @retval  kErrorInvalidArgs   The option is invalid.
541      */
542     Error ReadBlockOptionValues(uint16_t aBlockType);
543 
544     /**
545      * Returns the current header length of a message.
546      *
547      * @returns The length of the message header.
548      *
549      */
GetHeaderLength(void) const550     uint16_t GetHeaderLength(void) const { return GetHelpData().mHeaderLength; }
551 
552     /**
553      * Returns the block number of a CoAP block-wise transfer message.
554      *
555      * @returns The block number.
556      *
557      */
GetBlockWiseBlockNumber(void) const558     uint32_t GetBlockWiseBlockNumber(void) const { return GetHelpData().mBlockWiseData.mBlockNumber; }
559 
560     /**
561      * Checks if the More Blocks flag is set.
562      *
563      * @retval TRUE   More Blocks flag is set.
564      * @retval FALSE  More Blocks flag is not set.
565      *
566      */
IsMoreBlocksFlagSet(void) const567     bool IsMoreBlocksFlagSet(void) const { return GetHelpData().mBlockWiseData.mMoreBlocks; }
568 
569     /**
570      * Returns the block size of a CoAP block-wise transfer message.
571      *
572      * @returns The block size.
573      *
574      */
GetBlockWiseBlockSize(void) const575     otCoapBlockSzx GetBlockWiseBlockSize(void) const { return GetHelpData().mBlockWiseData.mBlockSize; }
576 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
577 
578     /**
579      * Reads and reassembles the URI path string and fills it into @p aUriPath.
580      *
581      * @retval  kErrorNone      URI path string has been reassembled.
582      * @retval  kErrorNoBufs    URI path string is too long.
583      *
584      */
585     Error GetUriPath(char *aUriPath) const;
586 
587     /**
588      * Adds Payload Marker indicating beginning of the payload to the CoAP header.
589      *
590      * It also set offset to the start of payload.
591      *
592      * @retval kErrorNone    Payload Marker successfully added.
593      * @retval kErrorNoBufs  Message Payload Marker exceeds the buffer size.
594      *
595      */
596     Error SetPayloadMarker(void);
597 
598     /**
599      * Returns the offset of the first CoAP option.
600      *
601      * @returns The offset of the first CoAP option.
602      *
603      */
GetOptionStart(void) const604     uint16_t GetOptionStart(void) const { return kMinHeaderLength + GetTokenLength(); }
605 
606     /**
607      * Parses CoAP header and moves offset end of CoAP header.
608      *
609      * @retval  kErrorNone   Successfully parsed CoAP header from the message.
610      * @retval  kErrorParse  Failed to parse the CoAP header.
611      *
612      */
613     Error ParseHeader(void);
614 
615     /**
616      * Sets a default response header based on request header.
617      *
618      * @param[in]  aRequest  The request message.
619      *
620      * @retval kErrorNone    Successfully set the default response header.
621      * @retval kErrorNoBufs  Insufficient message buffers available to set the default response header.
622      *
623      */
624     Error SetDefaultResponseHeader(const Message &aRequest);
625 
626 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
627 
628     /**
629      * Sets the block number value in the message HelpData.
630      *
631      * @param[in]   aBlockNumber    Block number value to set.
632      *
633      */
SetBlockWiseBlockNumber(uint32_t aBlockNumber)634     void SetBlockWiseBlockNumber(uint32_t aBlockNumber) { GetHelpData().mBlockWiseData.mBlockNumber = aBlockNumber; }
635 
636     /**
637      * Sets the More Blocks flag in the message HelpData.
638      *
639      * @param[in]   aMoreBlocks    TRUE or FALSE.
640      *
641      */
SetMoreBlocksFlag(bool aMoreBlocks)642     void SetMoreBlocksFlag(bool aMoreBlocks) { GetHelpData().mBlockWiseData.mMoreBlocks = aMoreBlocks; }
643 
644     /**
645      * Sets the block size value in the message HelpData.
646      *
647      * @param[in]   aBlockSize    Block size value to set.
648      *
649      */
SetBlockWiseBlockSize(otCoapBlockSzx aBlockSize)650     void SetBlockWiseBlockSize(otCoapBlockSzx aBlockSize) { GetHelpData().mBlockWiseData.mBlockSize = aBlockSize; }
651 #endif // OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
652 
653     /**
654      * Checks if a header is an empty message header.
655      *
656      * @retval TRUE   Message is an empty message header.
657      * @retval FALSE  Message is not an empty message header.
658      *
659      */
IsEmpty(void) const660     bool IsEmpty(void) const { return (GetCode() == kCodeEmpty); }
661 
662     /**
663      * Checks if a header is a request header.
664      *
665      * @retval TRUE   Message is a request header.
666      * @retval FALSE  Message is not a request header.
667      *
668      */
IsRequest(void) const669     bool IsRequest(void) const { return (GetCode() >= kCodeGet) && (GetCode() <= kCodeDelete); }
670 
671     /**
672      * Indicates whether or not the CoAP code in header is "Get" request.
673      *
674      * @retval TRUE   Message is a Get request.
675      * @retval FALSE  Message is not a Get request.
676      *
677      */
IsGetRequest(void) const678     bool IsGetRequest(void) const { return GetCode() == kCodeGet; }
679 
680     /**
681      * Indicates whether or not the CoAP code in header is "Post" request.
682      *
683      * @retval TRUE   Message is a Post request.
684      * @retval FALSE  Message is not a Post request.
685      *
686      */
IsPostRequest(void) const687     bool IsPostRequest(void) const { return GetCode() == kCodePost; }
688 
689     /**
690      * Indicates whether or not the CoAP code in header is "Put" request.
691      *
692      * @retval TRUE   Message is a Put request.
693      * @retval FALSE  Message is not a Put request.
694      *
695      */
IsPutRequest(void) const696     bool IsPutRequest(void) const { return GetCode() == kCodePut; }
697 
698     /**
699      * Indicates whether or not the CoAP code in header is "Delete" request.
700      *
701      * @retval TRUE   Message is a Delete request.
702      * @retval FALSE  Message is not a Delete request.
703      *
704      */
IsDeleteRequest(void) const705     bool IsDeleteRequest(void) const { return GetCode() == kCodeDelete; }
706 
707     /**
708      * Checks if a header is a response header.
709      *
710      * @retval TRUE   Message is a response header.
711      * @retval FALSE  Message is not a response header.
712      *
713      */
IsResponse(void) const714     bool IsResponse(void) const { return GetCode() >= OT_COAP_CODE_RESPONSE_MIN; }
715 
716     /**
717      * Checks if a header is a CON message header.
718      *
719      * @retval TRUE   Message is a CON message header.
720      * @retval FALSE  Message is not is a CON message header.
721      *
722      */
IsConfirmable(void) const723     bool IsConfirmable(void) const { return (GetType() == kTypeConfirmable); }
724 
725     /**
726      * Checks if a header is a NON message header.
727      *
728      * @retval TRUE   Message is a NON message header.
729      * @retval FALSE  Message is not is a NON message header.
730      *
731      */
IsNonConfirmable(void) const732     bool IsNonConfirmable(void) const { return (GetType() == kTypeNonConfirmable); }
733 
734     /**
735      * Checks if a header is a ACK message header.
736      *
737      * @retval TRUE   Message is a ACK message header.
738      * @retval FALSE  Message is not is a ACK message header.
739      *
740      */
IsAck(void) const741     bool IsAck(void) const { return (GetType() == kTypeAck); }
742 
743     /**
744      * Checks if a header is a RST message header.
745      *
746      * @retval TRUE   Message is a RST message header.
747      * @retval FALSE  Message is not is a RST message header.
748      *
749      */
IsReset(void) const750     bool IsReset(void) const { return (GetType() == kTypeReset); }
751 
752     /**
753      * Indicates whether or not the header is a confirmable Put request (i.e, `kTypeConfirmable` with
754      *  `kCodePost`).
755      *
756      * @retval TRUE   Message is a confirmable Post request.
757      * @retval FALSE  Message is not a confirmable Post request.
758      *
759      */
760     bool IsConfirmablePostRequest(void) const;
761 
762     /**
763      * Indicates whether or not the header is a non-confirmable Put request (i.e, `kTypeNonConfirmable` with
764      *  `kCodePost`).
765      *
766      * @retval TRUE   Message is a non-confirmable Post request.
767      * @retval FALSE  Message is not a non-confirmable Post request.
768      *
769      */
770     bool IsNonConfirmablePostRequest(void) const;
771 
772     /**
773      * Creates a copy of this CoAP message.
774      *
775      * It allocates the new message from the same message pool as the original one and copies @p aLength octets
776      * of the payload. The `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the
777      * cloned message are also copied from the original one.
778      *
779      * @param[in] aLength  Number of payload bytes to copy.
780      *
781      * @returns A pointer to the message or `nullptr` if insufficient message buffers are available.
782      *
783      */
784     Message *Clone(uint16_t aLength) const;
785 
786     /**
787      * Creates a copy of the message.
788      *
789      * It allocates the new message from the same message pool as the original one and copies the entire payload. The
790      * `Type`, `SubType`, `LinkSecurity`, `Offset`, `InterfaceId`, and `Priority` fields on the cloned message are also
791      * copied from the original one.
792      *
793      * @returns A pointer to the message or `nullptr` if insufficient message buffers are available.
794      *
795      */
Clone(void) const796     Message *Clone(void) const { return Clone(GetLength()); }
797 
798     /**
799      * Returns the minimal reserved bytes required for CoAP message.
800      *
801      */
GetHelpDataReserved(void)802     static uint16_t GetHelpDataReserved(void) { return sizeof(HelpData) + kHelpDataAlignment; }
803 
804     /**
805      * Returns a pointer to the next message after this as a `Coap::Message`.
806      *
807      * Should be used when the message is in a `Coap::MessageQueue` (i.e., a queue containing only CoAP
808      * messages).
809      *
810      * @returns A pointer to the next message in the queue or `nullptr` if at the end of the queue.
811      *
812      */
GetNextCoapMessage(void)813     Message *GetNextCoapMessage(void) { return static_cast<Message *>(GetNext()); }
814 
815     /**
816      * Returns a pointer to the next message after this as a `Coap::Message`.
817      *
818      * Should be used when the message is in a `Coap::MessageQueue` (i.e., a queue containing only CoAP
819      * messages).
820      *
821      * @returns A pointer to the next message in the queue or `nullptr` if at the end of the queue.
822      *
823      */
GetNextCoapMessage(void) const824     const Message *GetNextCoapMessage(void) const { return static_cast<const Message *>(GetNext()); }
825 
826 private:
827     /*
828      * Header field first byte (RFC 7252).
829      *
830      *    7 6 5 4 3 2 1 0
831      *   +-+-+-+-+-+-+-+-+
832      *   |Ver| T |  TKL  |  (Version, Type and Token Length).
833      *   +-+-+-+-+-+-+-+-+
834      */
835     static constexpr uint8_t kVersionOffset     = 6;
836     static constexpr uint8_t kVersionMask       = 0x3 << kVersionOffset;
837     static constexpr uint8_t kVersion1          = 1;
838     static constexpr uint8_t kTypeOffset        = 4;
839     static constexpr uint8_t kTypeMask          = 0x3 << kTypeOffset;
840     static constexpr uint8_t kTokenLengthOffset = 0;
841     static constexpr uint8_t kTokenLengthMask   = 0xf << kTokenLengthOffset;
842 
843     /*
844      *
845      * Option Format (RFC 7252).
846      *
847      *      7   6   5   4   3   2   1   0
848      *    +---------------+---------------+
849      *    |  Option Delta | Option Length |   1 byte
850      *    +---------------+---------------+
851      *    /         Option Delta          /   0-2 bytes
852      *    \          (extended)           \
853      *    +-------------------------------+
854      *    /         Option Length         /   0-2 bytes
855      *    \          (extended)           \
856      *    +-------------------------------+
857      *    /         Option Value          /   0 or more bytes
858      *    +-------------------------------+
859      *
860      */
861 
862     static constexpr uint8_t kOptionDeltaOffset  = 4;
863     static constexpr uint8_t kOptionDeltaMask    = 0xf << kOptionDeltaOffset;
864     static constexpr uint8_t kOptionLengthOffset = 0;
865     static constexpr uint8_t kOptionLengthMask   = 0xf << kOptionLengthOffset;
866 
867     static constexpr uint8_t kMaxOptionHeaderSize = 5;
868 
869     static constexpr uint8_t kOption1ByteExtension = 13; // Indicates a one-byte extension.
870     static constexpr uint8_t kOption2ByteExtension = 14; // Indicates a two-byte extension.
871 
872     static constexpr uint8_t kPayloadMarker = 0xff;
873 
874     static constexpr uint8_t kHelpDataAlignment = sizeof(uint16_t); // Alignment of help data.
875 
876     static constexpr uint16_t kMinHeaderLength = 4;
877     static constexpr uint16_t kMaxHeaderLength = 512;
878 
879     static constexpr uint16_t kOption1ByteExtensionOffset = 13;  // Delta/Length offset as specified (RFC 7252).
880     static constexpr uint16_t kOption2ByteExtensionOffset = 269; // Delta/Length offset as specified (RFC 7252).
881 
882     static constexpr uint8_t kBlockSzxOffset = 0;
883     static constexpr uint8_t kBlockMOffset   = 3;
884     static constexpr uint8_t kBlockNumOffset = 4;
885 
886     static constexpr uint32_t kObserveMask = 0xffffff;
887     static constexpr uint32_t kBlockNumMax = 0xffff;
888 
889 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
890     struct BlockWiseData
891     {
892         uint32_t       mBlockNumber;
893         bool           mMoreBlocks;
894         otCoapBlockSzx mBlockSize;
895     };
896 #endif
897 
898     /**
899      * Represents a CoAP header excluding CoAP options.
900      *
901      */
902     OT_TOOL_PACKED_BEGIN
903     struct Header
904     {
905         uint8_t  mVersionTypeToken;       ///< The CoAP Version, Type, and Token Length
906         uint8_t  mCode;                   ///< The CoAP Code
907         uint16_t mMessageId;              ///< The CoAP Message ID
908         uint8_t  mToken[kMaxTokenLength]; ///< The CoAP Token
909     } OT_TOOL_PACKED_END;
910 
911     /**
912      * Represents a HelpData used by this CoAP message.
913      *
914      */
915     struct HelpData : public Clearable<HelpData>
916     {
917         Header   mHeader;
918         uint16_t mOptionLast;
919         uint16_t mHeaderOffset; ///< The byte offset for the CoAP Header
920         uint16_t mHeaderLength;
921         bool     mPayloadMarkerSet;
922 #if OPENTHREAD_CONFIG_COAP_BLOCKWISE_TRANSFER_ENABLE
923         BlockWiseData mBlockWiseData;
924 #endif
925     };
926 
927     class ConstIterator : public ot::Message::ConstIterator
928     {
929     public:
930         using ot::Message::ConstIterator::ConstIterator;
931 
operator *(void)932         const Message &operator*(void) { return static_cast<const Message &>(ot::Message::ConstIterator::operator*()); }
operator ->(void)933         const Message *operator->(void)
934         {
935             return static_cast<const Message *>(ot::Message::ConstIterator::operator->());
936         }
937     };
938 
939     class Iterator : public ot::Message::Iterator
940     {
941     public:
942         using ot::Message::Iterator::Iterator;
943 
operator *(void)944         Message &operator*(void) { return static_cast<Message &>(ot::Message::Iterator::operator*()); }
operator ->(void)945         Message *operator->(void) { return static_cast<Message *>(ot::Message::Iterator::operator->()); }
946     };
947 
948     static_assert(sizeof(HelpData) <= sizeof(Ip6::Header) + sizeof(Ip6::HopByHopHeader) + sizeof(Ip6::MplOption) +
949                                           sizeof(Ip6::Udp::Header),
950                   "HelpData size exceeds the size of the reserved region in the message");
951 
GetHelpData(void) const952     const HelpData &GetHelpData(void) const
953     {
954         static_assert(sizeof(HelpData) + kHelpDataAlignment <= kHeadBufferDataSize,
955                       "Insufficient buffer size for CoAP processing! Increase OPENTHREAD_CONFIG_MESSAGE_BUFFER_SIZE.");
956 
957         return *static_cast<const HelpData *>(OT_ALIGN(GetFirstData(), kHelpDataAlignment));
958     }
959 
GetHelpData(void)960     HelpData &GetHelpData(void) { return AsNonConst(AsConst(this)->GetHelpData()); }
961 
GetToken(void)962     uint8_t *GetToken(void) { return GetHelpData().mHeader.mToken; }
963 
SetTokenLength(uint8_t aTokenLength)964     void SetTokenLength(uint8_t aTokenLength)
965     {
966         GetHelpData().mHeader.mVersionTypeToken &= ~kTokenLengthMask;
967         GetHelpData().mHeader.mVersionTypeToken |= ((aTokenLength << kTokenLengthOffset) & kTokenLengthMask);
968     }
969 
970     uint8_t WriteExtendedOptionField(uint16_t aValue, uint8_t *&aBuffer);
971 };
972 
973 /**
974  * Implements a CoAP message queue.
975  *
976  */
977 class MessageQueue : public ot::MessageQueue
978 {
979 public:
980     /**
981      * Initializes the message queue.
982      *
983      */
984     MessageQueue(void) = default;
985 
986     /**
987      * Returns a pointer to the first message.
988      *
989      * @returns A pointer to the first message.
990      *
991      */
GetHead(void)992     Message *GetHead(void) { return static_cast<Message *>(ot::MessageQueue::GetHead()); }
993 
994     /**
995      * Returns a pointer to the first message.
996      *
997      * @returns A pointer to the first message.
998      *
999      */
GetHead(void) const1000     const Message *GetHead(void) const { return static_cast<const Message *>(ot::MessageQueue::GetHead()); }
1001 
1002     /**
1003      * Adds a message to the end of the queue.
1004      *
1005      * @param[in]  aMessage  The message to add.
1006      *
1007      */
Enqueue(Message & aMessage)1008     void Enqueue(Message &aMessage) { Enqueue(aMessage, kQueuePositionTail); }
1009 
1010     /**
1011      * Adds a message at a given position (head/tail) of the queue.
1012      *
1013      * @param[in]  aMessage  The message to add.
1014      * @param[in]  aPosition The position (head or tail) where to add the message.
1015      *
1016      */
Enqueue(Message & aMessage,QueuePosition aPosition)1017     void Enqueue(Message &aMessage, QueuePosition aPosition) { ot::MessageQueue::Enqueue(aMessage, aPosition); }
1018 
1019     /**
1020      * Removes a message from the queue.
1021      *
1022      * @param[in]  aMessage  The message to remove.
1023      *
1024      */
Dequeue(Message & aMessage)1025     void Dequeue(Message &aMessage) { ot::MessageQueue::Dequeue(aMessage); }
1026 
1027     /**
1028      * Removes a message from the queue and frees it.
1029      *
1030      * @param[in]  aMessage  The message to remove and free.
1031      *
1032      */
DequeueAndFree(Message & aMessage)1033     void DequeueAndFree(Message &aMessage) { ot::MessageQueue::DequeueAndFree(aMessage); }
1034 
1035     // The following methods are intended to support range-based `for`
1036     // loop iteration over the queue entries and should not be used
1037     // directly. The range-based `for` works correctly even if the
1038     // current entry is removed from the queue during iteration.
1039 
1040     Message::Iterator begin(void);
end(void)1041     Message::Iterator end(void) { return Message::Iterator(); }
1042 
1043     Message::ConstIterator begin(void) const;
end(void) const1044     Message::ConstIterator end(void) const { return Message::ConstIterator(); }
1045 };
1046 
1047 /**
1048  * Represents a CoAP option.
1049  *
1050  */
1051 class Option : public otCoapOption
1052 {
1053 public:
1054     /**
1055      * Represents an iterator for CoAP options.
1056      *
1057      */
1058     class Iterator : public otCoapOptionIterator
1059     {
1060     public:
1061         /**
1062          * Initializes the iterator to iterate over CoAP Options in a CoAP message.
1063          *
1064          * The iterator MUST be initialized before any other methods are used, otherwise its behavior is undefined.
1065          *
1066          * After initialization, the iterator is either updated to point to the first option, or it is marked as done
1067          * (i.e., `IsDone()` returns `true`) when there is no option or if there is a parse error.
1068          *
1069          * @param[in] aMessage  The CoAP message.
1070          *
1071          * @retval kErrorNone   Successfully initialized. Iterator is either at the first option or done.
1072          * @retval kErrorParse  CoAP Option header in @p aMessage is not well-formed.
1073          *
1074          */
1075         Error Init(const Message &aMessage);
1076 
1077         /**
1078          * Initializes the iterator to iterate over CoAP Options in a CoAP message matching a given Option
1079          * Number value.
1080          *
1081          * The iterator MUST be initialized before any other methods are used, otherwise its behavior is undefined.
1082          *
1083          * After initialization, the iterator is either updated to point to the first option matching the given Option
1084          * Number value, or it is marked as done (i.e., `IsDone()` returns `true`) when there is no matching option or
1085          * if there is a parse error.
1086          *
1087          * @param[in] aMessage  The CoAP message.
1088          * @param[in] aNumber   The CoAP Option Number.
1089          *
1090          * @retval  kErrorNone   Successfully initialized. Iterator is either at the first matching option or done.
1091          * @retval  kErrorParse  CoAP Option header in @p aMessage is not well-formed.
1092          *
1093          */
Init(const Message & aMessage,uint16_t aNumber)1094         Error Init(const Message &aMessage, uint16_t aNumber) { return InitOrAdvance(&aMessage, aNumber); }
1095 
1096         /**
1097          * Indicates whether or not the iterator is done (i.e., has reached the end of CoAP Option Header).
1098          *
1099          * @retval TRUE   Iterator is done (reached end of Option header).
1100          * @retval FALSE  Iterator is not done and currently pointing to a CoAP Option.
1101          *
1102          */
IsDone(void) const1103         bool IsDone(void) const { return mOption.mLength == kIteratorDoneLength; }
1104 
1105         /**
1106          * Indicates whether or not there was a earlier parse error (i.e., whether the iterator is valid).
1107          *
1108          * After a parse errors, iterator would also be marked as done.
1109          *
1110          * @retval TRUE   There was an earlier parse error and the iterator is not valid.
1111          * @retval FALSE  There was no earlier parse error and the iterator is valid.
1112          *
1113          */
HasParseErrored(void) const1114         bool HasParseErrored(void) const { return mNextOptionOffset == kNextOptionOffsetParseError; }
1115 
1116         /**
1117          * Advances the iterator to the next CoAP Option in the header.
1118          *
1119          * The iterator is updated to point to the next option or marked as done when there are no more options.
1120          *
1121          * @retval  kErrorNone   Successfully advanced the iterator.
1122          * @retval  kErrorParse  CoAP Option header is not well-formed.
1123          *
1124          */
1125         Error Advance(void);
1126 
1127         /**
1128          * Advances the iterator to the next CoAP Option in the header matching a given Option Number value.
1129          *
1130          * The iterator is updated to point to the next matching option or marked as done when there are no more
1131          * matching options.
1132          *
1133          * @param[in] aNumber   The CoAP Option Number.
1134          *
1135          * @retval  kErrorNone   Successfully advanced the iterator.
1136          * @retval  kErrorParse  CoAP Option header is not well-formed.
1137          *
1138          */
Advance(uint16_t aNumber)1139         Error Advance(uint16_t aNumber) { return InitOrAdvance(nullptr, aNumber); }
1140 
1141         /**
1142          * Gets the CoAP message associated with the iterator.
1143          *
1144          * @returns A reference to the CoAP message.
1145          *
1146          */
GetMessage(void) const1147         const Message &GetMessage(void) const { return *static_cast<const Message *>(mMessage); }
1148 
1149         /**
1150          * Gets a pointer to the current CoAP Option to which the iterator is currently pointing.
1151          *
1152          * @returns A pointer to the current CoAP Option, or `nullptr` if iterator is done (or there was an earlier
1153          *          parse error).
1154          *
1155          */
GetOption(void) const1156         const Option *GetOption(void) const { return IsDone() ? nullptr : static_cast<const Option *>(&mOption); }
1157 
1158         /**
1159          * Reads the current Option Value into a given buffer.
1160          *
1161          * @param[out]  aValue   The pointer to a buffer to copy the Option Value. The buffer is assumed to be
1162          *                       sufficiently large (i.e. at least `GetOption()->GetLength()` bytes).
1163          *
1164          * @retval kErrorNone       Successfully read and copied the Option Value into given buffer.
1165          * @retval kErrorNotFound   Iterator is done (not pointing to any option).
1166          *
1167          */
1168         Error ReadOptionValue(void *aValue) const;
1169 
1170         /**
1171          * Read the current Option Value which is assumed to be an unsigned integer.
1172          *
1173          * @param[out]  aUintValue      A reference to `uint64_t` to output the read Option Value.
1174          *
1175          * @retval kErrorNone       Successfully read the Option value.
1176          * @retval kErrorNoBufs     Value is too long to fit in an `uint64_t`.
1177          * @retval kErrorNotFound   Iterator is done (not pointing to any option).
1178          *
1179          */
1180         Error ReadOptionValue(uint64_t &aUintValue) const;
1181 
1182         /**
1183          * Gets the offset of beginning of the CoAP message payload (after the CoAP header).
1184          *
1185          * MUST be used after the iterator is done (i.e. iterated through all options).
1186          *
1187          * @returns The offset of beginning of the CoAP message payload
1188          *
1189          */
GetPayloadMessageOffset(void) const1190         uint16_t GetPayloadMessageOffset(void) const { return mNextOptionOffset; }
1191 
1192     private:
1193         // `mOption.mLength` value to indicate iterator is done.
1194         static constexpr uint16_t kIteratorDoneLength = 0xffff;
1195 
1196         // Special `mNextOptionOffset` value to indicate a parse error.
1197         static constexpr uint16_t kNextOptionOffsetParseError = 0;
1198 
MarkAsDone(void)1199         void MarkAsDone(void) { mOption.mLength = kIteratorDoneLength; }
MarkAsParseErrored(void)1200         void MarkAsParseErrored(void) { MarkAsDone(), mNextOptionOffset = kNextOptionOffsetParseError; }
1201 
1202         Error Read(uint16_t aLength, void *aBuffer);
1203         Error ReadExtendedOptionField(uint16_t &aValue);
1204         Error InitOrAdvance(const Message *aMessage, uint16_t aNumber);
1205     };
1206 
1207     /**
1208      * Gets the CoAP Option Number.
1209      *
1210      * @returns The CoAP Option Number.
1211      *
1212      */
GetNumber(void) const1213     uint16_t GetNumber(void) const { return mNumber; }
1214 
1215     /**
1216      * Gets the CoAP Option Length (length of Option Value in bytes).
1217      *
1218      * @returns The CoAP Option Length (in bytes).
1219      *
1220      */
GetLength(void) const1221     uint16_t GetLength(void) const { return mLength; }
1222 };
1223 
1224 /**
1225  * @}
1226  *
1227  */
1228 
1229 } // namespace Coap
1230 
1231 DefineCoreType(otCoapOption, Coap::Option);
1232 DefineCoreType(otCoapOptionIterator, Coap::Option::Iterator);
1233 DefineMapEnum(otCoapType, Coap::Type);
1234 DefineMapEnum(otCoapCode, Coap::Code);
1235 
1236 /**
1237  * Casts an `otMessage` pointer to a `Coap::Message` reference.
1238  *
1239  * @param[in] aMessage   A pointer to an `otMessage`.
1240  *
1241  * @returns A reference to `Coap::Message` matching @p aMessage.
1242  *
1243  */
AsCoapMessage(otMessage * aMessage)1244 inline Coap::Message &AsCoapMessage(otMessage *aMessage) { return *static_cast<Coap::Message *>(aMessage); }
1245 
1246 /**
1247  * Casts an `otMessage` pointer to a `Coap::Message` reference.
1248  *
1249  * @param[in] aMessage   A pointer to an `otMessage`.
1250  *
1251  * @returns A reference to `Coap::Message` matching @p aMessage.
1252  *
1253  */
AsCoapMessagePtr(otMessage * aMessage)1254 inline Coap::Message *AsCoapMessagePtr(otMessage *aMessage) { return static_cast<Coap::Message *>(aMessage); }
1255 
1256 /**
1257  * Casts an `otMessage` pointer to a `Coap::Message` pointer.
1258  *
1259  * @param[in] aMessage   A pointer to an `otMessage`.
1260  *
1261  * @returns A pointer to `Coap::Message` matching @p aMessage.
1262  *
1263  */
AsCoapMessage(const otMessage * aMessage)1264 inline const Coap::Message &AsCoapMessage(const otMessage *aMessage)
1265 {
1266     return *static_cast<const Coap::Message *>(aMessage);
1267 }
1268 
1269 /**
1270  * Casts an `otMessage` pointer to a `Coap::Message` reference.
1271  *
1272  * @param[in] aMessage   A pointer to an `otMessage`.
1273  *
1274  * @returns A pointer to `Coap::Message` matching @p aMessage.
1275  *
1276  */
AsCoapMessagePtr(const otMessage * aMessage)1277 inline const Coap::Message *AsCoapMessagePtr(const otMessage *aMessage)
1278 {
1279     return static_cast<const Coap::Message *>(aMessage);
1280 }
1281 
1282 } // namespace ot
1283 
1284 #endif // COAP_HEADER_HPP_
1285