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