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 6LoWPAN header compression. 32 */ 33 34 #ifndef LOWPAN_HPP_ 35 #define LOWPAN_HPP_ 36 37 #include "openthread-core-config.h" 38 39 #include "common/clearable.hpp" 40 #include "common/debug.hpp" 41 #include "common/frame_builder.hpp" 42 #include "common/frame_data.hpp" 43 #include "common/locator.hpp" 44 #include "common/message.hpp" 45 #include "common/non_copyable.hpp" 46 #include "mac/mac_types.hpp" 47 #include "net/ip6.hpp" 48 #include "net/ip6_address.hpp" 49 #include "net/ip6_types.hpp" 50 51 namespace ot { 52 53 /** 54 * @addtogroup core-6lowpan 55 * 56 * @brief 57 * This module includes definitions for 6LoWPAN header compression. 58 * 59 * @{ 60 */ 61 62 /** 63 * @namespace ot::Lowpan 64 * 65 * @brief 66 * This namespace includes definitions for 6LoWPAN message processing. 67 * 68 */ 69 namespace Lowpan { 70 71 using ot::Encoding::BigEndian::HostSwap16; 72 73 /** 74 * Represents a LOWPAN_IPHC Context. 75 * 76 */ 77 struct Context : public Clearable<Context> 78 { 79 Ip6::Prefix mPrefix; ///< The Prefix 80 uint8_t mContextId; ///< The Context ID. 81 bool mCompressFlag; ///< The Context compression flag. 82 bool mIsValid; ///< Indicates whether the context is valid. 83 }; 84 85 /** 86 * Implements LOWPAN_IPHC header compression. 87 * 88 */ 89 class Lowpan : public InstanceLocator, private NonCopyable 90 { 91 public: 92 /** 93 * Initializes the object. 94 * 95 * @param[in] aInstance A reference to the OpenThread instance. 96 * 97 */ 98 explicit Lowpan(Instance &aInstance); 99 100 /** 101 * Indicates whether or not the header is a LOWPAN_IPHC header. 102 * 103 * @param[in] aHeader A pointer to the header. 104 * 105 * @retval TRUE If the header matches the LOWPAN_IPHC dispatch value. 106 * @retval FALSE If the header does not match the LOWPAN_IPHC dispatch value. 107 */ IsLowpanHc(const uint8_t * aHeader)108 static bool IsLowpanHc(const uint8_t *aHeader) 109 { 110 return (aHeader[0] & (Lowpan::kHcDispatchMask >> 8)) == (Lowpan::kHcDispatch >> 8); 111 } 112 113 /** 114 * Indicates whether or not header in a given frame is a LOWPAN_IPHC header. 115 * 116 * @param[in] aFrameData The frame data. 117 * 118 * @retval TRUE If the header matches the LOWPAN_IPHC dispatch value. 119 * @retval FALSE If the header does not match the LOWPAN_IPHC dispatch value. 120 */ IsLowpanHc(const FrameData & aFrameData)121 static bool IsLowpanHc(const FrameData &aFrameData) 122 { 123 return (aFrameData.GetLength() > 0) && IsLowpanHc(aFrameData.GetBytes()); 124 } 125 126 /** 127 * Compresses an IPv6 header. 128 * 129 * @param[in] aMessage A reference to the IPv6 message. 130 * @param[in] aMacAddrs The MAC source and destination addresses. 131 * @param[in] aFrameBuilder The `FrameBuilder` to use to append the compressed headers. 132 * 133 * @returns The size of the compressed header in bytes. 134 * 135 */ 136 Error Compress(Message &aMessage, const Mac::Addresses &aMacAddrs, FrameBuilder &aFrameBuilder); 137 138 /** 139 * Decompresses a LOWPAN_IPHC header. 140 * 141 * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes. 142 * 143 * @param[out] aMessage A reference where the IPv6 header will be placed. 144 * @param[in] aMacAddrs The MAC source and destination addresses. 145 * @param[in,out] aFrameData A frame data containing the LOWPAN_IPHC header. 146 * @param[in] aDatagramLength The IPv6 datagram length. 147 * 148 * @retval kErrorNone The header was decompressed successfully. @p aMessage and @p aFrameData are updated. 149 * @retval kErrorParse Failed to parse the lowpan header. 150 * @retval kErrorNoBufs Could not grow @p aMessage to write the parsed IPv6 header. 151 * 152 */ 153 Error Decompress(Message &aMessage, 154 const Mac::Addresses &aMacAddrs, 155 FrameData &aFrameData, 156 uint16_t aDatagramLength); 157 158 /** 159 * Decompresses a LOWPAN_IPHC header. 160 * 161 * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes. 162 * 163 * @param[out] aIp6Header A reference where the IPv6 header will be placed. 164 * @param[out] aCompressedNextHeader A boolean reference to output whether next header is compressed or not. 165 * @param[in] aMacAddrs The MAC source and destination addresses 166 * @param[in,out] aFrameData A frame data containing the LOWPAN_IPHC header. 167 * 168 * @retval kErrorNone The header was decompressed successfully. @p aIp6Header and @p aFrameData are updated. 169 * @retval kErrorParse Failed to parse the lowpan header. 170 * 171 */ 172 Error DecompressBaseHeader(Ip6::Header &aIp6Header, 173 bool &aCompressedNextHeader, 174 const Mac::Addresses &aMacAddrs, 175 FrameData &aFrameData); 176 177 /** 178 * Decompresses a LOWPAN_NHC UDP header. 179 * 180 * If the header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes. 181 * 182 * @param[out] aUdpHeader A reference where the UDP header will be placed. 183 * @param[in,out] aFrameData A frame data containing the LOWPAN_NHC header. 184 * 185 * @retval kErrorNone The header was decompressed successfully. @p aUdpHeader and @p aFrameData are updated. 186 * @retval kErrorParse Failed to parse the lowpan header. 187 * 188 */ 189 Error DecompressUdpHeader(Ip6::Udp::Header &aUdpHeader, FrameData &aFrameData); 190 191 /** 192 * Decompresses the IPv6 ECN field in a LOWPAN_IPHC header. 193 * 194 * @param[in] aMessage The message to read the IPHC header from. 195 * @param[in] aOffset The offset in @p aMessage to start of IPHC header. 196 * 197 * @returns The decompressed ECN field. If the IPHC header is not valid `kEcnNotCapable` is returned. 198 * 199 */ 200 Ip6::Ecn DecompressEcn(const Message &aMessage, uint16_t aOffset) const; 201 202 /** 203 * Updates the compressed ECN field in a LOWPAN_IPHC header to `kEcnMarked`. 204 * 205 * MUST be used when the ECN field is not elided in the IPHC header. Note that the ECN is not elided 206 * when it is not zero (`kEcnNotCapable`). 207 * 208 * @param[in,out] aMessage The message containing the IPHC header and to update. 209 * @param[in] aOffset The offset in @p aMessage to start of IPHC header. 210 * 211 */ 212 void MarkCompressedEcn(Message &aMessage, uint16_t aOffset); 213 214 private: 215 static constexpr uint16_t kHcDispatch = 3 << 13; 216 static constexpr uint16_t kHcDispatchMask = 7 << 13; 217 218 static constexpr uint16_t kHcTrafficClass = 1 << 11; 219 static constexpr uint16_t kHcFlowLabel = 2 << 11; 220 static constexpr uint16_t kHcTrafficFlow = 3 << 11; 221 static constexpr uint16_t kHcTrafficFlowMask = 3 << 11; 222 static constexpr uint16_t kHcNextHeader = 1 << 10; 223 static constexpr uint16_t kHcHopLimit1 = 1 << 8; 224 static constexpr uint16_t kHcHopLimit64 = 2 << 8; 225 static constexpr uint16_t kHcHopLimit255 = 3 << 8; 226 static constexpr uint16_t kHcHopLimitMask = 3 << 8; 227 static constexpr uint16_t kHcContextId = 1 << 7; 228 static constexpr uint16_t kHcSrcAddrContext = 1 << 6; 229 static constexpr uint16_t kHcSrcAddrMode0 = 0 << 4; 230 static constexpr uint16_t kHcSrcAddrMode1 = 1 << 4; 231 static constexpr uint16_t kHcSrcAddrMode2 = 2 << 4; 232 static constexpr uint16_t kHcSrcAddrMode3 = 3 << 4; 233 static constexpr uint16_t kHcSrcAddrModeMask = 3 << 4; 234 static constexpr uint16_t kHcMulticast = 1 << 3; 235 static constexpr uint16_t kHcDstAddrContext = 1 << 2; 236 static constexpr uint16_t kHcDstAddrMode0 = 0 << 0; 237 static constexpr uint16_t kHcDstAddrMode1 = 1 << 0; 238 static constexpr uint16_t kHcDstAddrMode2 = 2 << 0; 239 static constexpr uint16_t kHcDstAddrMode3 = 3 << 0; 240 static constexpr uint16_t kHcDstAddrModeMask = 3 << 0; 241 242 static constexpr uint8_t kEcnOffset = 6; 243 static constexpr uint8_t kEcnMask = 3 << kEcnOffset; 244 245 static constexpr uint8_t kExtHdrDispatch = 0xe0; 246 static constexpr uint8_t kExtHdrDispatchMask = 0xf0; 247 248 static constexpr uint8_t kExtHdrEidHbh = 0x00; 249 static constexpr uint8_t kExtHdrEidRouting = 0x02; 250 static constexpr uint8_t kExtHdrEidFragment = 0x04; 251 static constexpr uint8_t kExtHdrEidDst = 0x06; 252 static constexpr uint8_t kExtHdrEidMobility = 0x08; 253 static constexpr uint8_t kExtHdrEidIp6 = 0x0e; 254 static constexpr uint8_t kExtHdrEidMask = 0x0e; 255 256 static constexpr uint8_t kExtHdrNextHeader = 0x01; 257 static constexpr uint16_t kExtHdrMaxLength = 255; 258 259 static constexpr uint8_t kUdpDispatch = 0xf0; 260 static constexpr uint8_t kUdpDispatchMask = 0xf8; 261 262 static constexpr uint8_t kUdpChecksum = 1 << 2; 263 static constexpr uint8_t kUdpPortMask = 3 << 0; 264 265 void FindContextForId(uint8_t aContextId, Context &aContext) const; 266 void FindContextToCompressAddress(const Ip6::Address &aIp6Address, Context &aContext) const; 267 Error Compress(Message &aMessage, 268 const Mac::Addresses &aMacAddrs, 269 FrameBuilder &aFrameBuilder, 270 uint8_t &aHeaderDepth); 271 272 Error CompressExtensionHeader(Message &aMessage, FrameBuilder &aFrameBuilder, uint8_t &aNextHeader); 273 Error CompressSourceIid(const Mac::Address &aMacAddr, 274 const Ip6::Address &aIpAddr, 275 const Context &aContext, 276 uint16_t &aHcCtl, 277 FrameBuilder &aFrameBuilder); 278 Error CompressDestinationIid(const Mac::Address &aMacAddr, 279 const Ip6::Address &aIpAddr, 280 const Context &aContext, 281 uint16_t &aHcCtl, 282 FrameBuilder &aFrameBuilder); 283 Error CompressMulticast(const Ip6::Address &aIpAddr, uint16_t &aHcCtl, FrameBuilder &aFrameBuilder); 284 Error CompressUdp(Message &aMessage, FrameBuilder &aFrameBuilder); 285 286 Error DecompressExtensionHeader(Message &aMessage, FrameData &aFrameData); 287 Error DecompressUdpHeader(Message &aMessage, FrameData &aFrameData, uint16_t aDatagramLength); 288 Error DispatchToNextHeader(uint8_t aDispatch, uint8_t &aNextHeader); 289 290 static Error ComputeIid(const Mac::Address &aMacAddr, const Context &aContext, Ip6::InterfaceIdentifier &aIid); 291 }; 292 293 /** 294 * Implements Mesh Header generation and processing. 295 * 296 */ 297 class MeshHeader 298 { 299 public: 300 /** 301 * Initializes the Mesh Header with a given Mesh Source, Mesh Destination and Hops Left value. 302 * 303 * @param[in] aSource The Mesh Source address. 304 * @param[in] aDestination The Mesh Destination address. 305 * @param[in] aHopsLeft The Hops Left value. 306 * 307 */ 308 void Init(uint16_t aSource, uint16_t aDestination, uint8_t aHopsLeft); 309 310 /** 311 * Indicates whether or not the header (in a given frame) is a Mesh Header. 312 * 313 * @note This method checks whether the first byte in header/frame (dispatch byte) matches the Mesh Header dispatch 314 * It does not fully parse and validate the Mesh Header. `ParseFrom()` method can be used to fully parse and 315 * validate the header. 316 * 317 * @retval TRUE If the header matches the Mesh Header dispatch value. 318 * @retval FALSE If the header does not match the Mesh Header dispatch value. 319 * 320 */ 321 static bool IsMeshHeader(const FrameData &aFrameData); 322 323 /** 324 * Parses the Mesh Header from a frame @p aFrame. 325 * 326 * @param[in] aFrame The pointer to the frame. 327 * @param[in] aFrameLength The length of the frame. 328 * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). 329 * 330 * @retval kErrorNone Mesh Header parsed successfully. 331 * @retval kErrorParse Mesh Header could not be parsed. 332 * 333 */ 334 Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength); 335 336 /** 337 * Parses the Mesh Header from a given frame data. 338 * 339 * If the Mesh Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes. 340 * 341 * @param[in,out] aFrameData The frame data to parse from. 342 * 343 * @retval kErrorNone Mesh Header parsed successfully. @p aFrameData is updated to skip over parsed header. 344 * @retval kErrorParse Mesh Header could not be parsed. 345 * 346 */ 347 Error ParseFrom(FrameData &aFrameData); 348 349 /** 350 * Parses the Mesh Header from a given message. 351 * 352 * @note The Mesh Header is read from offset zero within the @p aMessage. 353 * 354 * @param[in] aMessage The message to read from. 355 * 356 * @retval kErrorNone Mesh Header parsed successfully. 357 * @retval kErrorParse Mesh Header could not be parsed. 358 * 359 */ 360 Error ParseFrom(const Message &aMessage); 361 362 /** 363 * Parses the Mesh Header from a given message. 364 * 365 * @note The Mesh Header is read from offset zero within the @p aMessage. 366 * 367 * @param[in] aMessage The message to read from. 368 * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). 369 * 370 * @retval kErrorNone Mesh Header parsed successfully. 371 * @retval kErrorParse Mesh Header could not be parsed. 372 * 373 */ 374 Error ParseFrom(const Message &aMessage, uint16_t &aHeaderLength); 375 376 /** 377 * Returns the the Mesh Header length when written to a frame. 378 * 379 * @note The returned value from this method gives the header length (number of bytes) when the header is written 380 * to a frame or message. This should not be used to determine the parsed length (number of bytes read) when the 381 * Mesh Header is parsed from a frame/message (using `ParseFrom()` methods). 382 * 383 * @returns The length of the Mesh Header (in bytes) when written to a frame. 384 * 385 */ 386 uint16_t GetHeaderLength(void) const; 387 388 /** 389 * Returns the Hops Left value. 390 * 391 * @returns The Hops Left value. 392 * 393 */ GetHopsLeft(void) const394 uint8_t GetHopsLeft(void) const { return mHopsLeft; } 395 396 /** 397 * Decrements the Hops Left value (if it is not zero). 398 * 399 */ 400 void DecrementHopsLeft(void); 401 402 /** 403 * Returns the Mesh Source address. 404 * 405 * @returns The Mesh Source address. 406 * 407 */ GetSource(void) const408 uint16_t GetSource(void) const { return mSource; } 409 410 /** 411 * Returns the Mesh Destination address. 412 * 413 * @returns The Mesh Destination address. 414 * 415 */ GetDestination(void) const416 uint16_t GetDestination(void) const { return mDestination; } 417 418 /** 419 * Appends the Mesh Header into a given frame. 420 * 421 * @param[out] aFrameBuilder The `FrameBuilder` to append to. 422 * 423 * @retval kErrorNone Successfully appended the MeshHeader to @p aFrameBuilder. 424 * @retval kErrorNoBufs Insufficient available buffers. 425 * 426 */ 427 Error AppendTo(FrameBuilder &aFrameBuilder) const; 428 429 /** 430 * Appends the Mesh Header to a given message. 431 * 432 * 433 * @param[out] aMessage A message to append the Mesh Header to. 434 * 435 * @retval kErrorNone Successfully appended the Mesh Header to @p aMessage. 436 * @retval kErrorNoBufs Insufficient available buffers to grow @p aMessage. 437 * 438 */ 439 Error AppendTo(Message &aMessage) const; 440 441 private: 442 static constexpr uint8_t kDispatch = 2 << 6; 443 static constexpr uint8_t kDispatchMask = 3 << 6; 444 static constexpr uint8_t kHopsLeftMask = 0x0f; 445 static constexpr uint8_t kSourceShort = 1 << 5; 446 static constexpr uint8_t kDestShort = 1 << 4; 447 static constexpr uint8_t kDeepHopsLeft = 0x0f; 448 449 // Dispatch byte + src + dest 450 static constexpr uint16_t kMinHeaderLength = sizeof(uint8_t) + sizeof(uint16_t) + sizeof(uint16_t); 451 static constexpr uint16_t kDeepHopsHeaderLength = kMinHeaderLength + sizeof(uint8_t); // min header + deep hops 452 453 uint16_t mSource; 454 uint16_t mDestination; 455 uint8_t mHopsLeft; 456 }; 457 458 /** 459 * Implements Fragment Header generation and parsing. 460 * 461 */ 462 class FragmentHeader 463 { 464 public: 465 OT_TOOL_PACKED_BEGIN 466 class FirstFrag 467 { 468 public: 469 /** 470 * Initializes the `FirstFrag`. 471 * 472 * @param[in] aSize The Datagram Size value. 473 * @param[in] aTag The Datagram Tag value. 474 * 475 */ Init(uint16_t aSize,uint16_t aTag)476 void Init(uint16_t aSize, uint16_t aTag) 477 { 478 mDispatchSize = HostSwap16(kFirstDispatch | (aSize & kSizeMask)); 479 mTag = HostSwap16(aTag); 480 } 481 482 private: 483 // 1 2 3 484 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 485 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 486 // |1 1 0 0 0| datagram_size | datagram_tag | 487 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 488 489 static constexpr uint16_t kFirstDispatch = 0xc000; // 0b11000_0000_0000_0000 490 491 uint16_t mDispatchSize; 492 uint16_t mTag; 493 } OT_TOOL_PACKED_END; 494 495 OT_TOOL_PACKED_BEGIN 496 class NextFrag 497 { 498 public: 499 /** 500 * Initializes the `NextFrag`. 501 * 502 * @param[in] aSize The Datagram Size value. 503 * @param[in] aTag The Datagram Tag value. 504 * @param[in] aOffset The Datagram Offset value. 505 * 506 */ Init(uint16_t aSize,uint16_t aTag,uint16_t aOffset)507 void Init(uint16_t aSize, uint16_t aTag, uint16_t aOffset) 508 { 509 mDispatchSize = HostSwap16(kNextDispatch | (aSize & kSizeMask)); 510 mTag = HostSwap16(aTag); 511 mOffset = static_cast<uint8_t>(aOffset >> 3); 512 } 513 514 private: 515 // 1 2 3 516 // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 517 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 518 // |1 1 1 0 0| datagram_size | datagram_tag | 519 // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ 520 // |datagram_offset| 521 // +-+-+-+-+-+-+-+-+ 522 523 static constexpr uint16_t kNextDispatch = 0xe000; // 0b11100_0000_0000_0000 524 525 uint16_t mDispatchSize; 526 uint16_t mTag; 527 uint8_t mOffset; 528 } OT_TOOL_PACKED_END; 529 530 /** 531 * Indicates whether or not the header (in a given frame) is a Fragment Header. 532 * 533 * @note This method checks whether the frame has the minimum required length and that the first byte in 534 * header (dispatch byte) matches the Fragment Header dispatch value. It does not fully parse and validate the 535 * Fragment Header. `ParseFrom()` method can be used to fully parse and validate the header. 536 * 537 * @param[in] aFrameData The frame data. 538 * 539 * @retval TRUE If the header matches the Fragment Header dispatch value. 540 * @retval FALSE If the header does not match the Fragment Header dispatch value. 541 * 542 */ 543 static bool IsFragmentHeader(const FrameData &aFrameData); 544 545 /** 546 * Parses the Fragment Header from a given frame data. 547 * 548 * If the Fragment Header is parsed successfully the @p aFrameData is updated to skip over the parsed header bytes. 549 * 550 * @param[in,out] aFrameData The frame data to parse from. 551 * 552 * @retval kErrorNone Fragment Header parsed successfully. @p aFrameData is updated to skip over parsed header. 553 * @retval kErrorParse Fragment header could not be parsed. 554 * 555 */ 556 Error ParseFrom(FrameData &aFrameData); 557 558 /** 559 * Parses the Fragment Header from a message. 560 * 561 * @param[in] aMessage The message to read from. 562 * @param[in] aOffset The offset within the message to start reading from. 563 * @param[out] aHeaderLength A reference to a variable to output the parsed header length (on success). 564 * 565 * @retval kErrorNone Fragment Header parsed successfully. 566 * @retval kErrorParse Fragment header could not be parsed from @p aFrame. 567 * 568 */ 569 Error ParseFrom(const Message &aMessage, uint16_t aOffset, uint16_t &aHeaderLength); 570 571 /** 572 * Returns the Datagram Size value. 573 * 574 * @returns The Datagram Size value. 575 * 576 */ GetDatagramSize(void) const577 uint16_t GetDatagramSize(void) const { return mSize; } 578 579 /** 580 * Returns the Datagram Tag value. 581 * 582 * @returns The Datagram Tag value. 583 * 584 */ GetDatagramTag(void) const585 uint16_t GetDatagramTag(void) const { return mTag; } 586 587 /** 588 * Returns the Datagram Offset value. 589 * 590 * The returned offset value is always multiple of 8. 591 * 592 * @returns The Datagram Offset value (multiple of 8). 593 * 594 */ GetDatagramOffset(void) const595 uint16_t GetDatagramOffset(void) const { return mOffset; } 596 597 private: 598 static constexpr uint8_t kDispatch = 0xc0; // 0b1100_0000 599 static constexpr uint8_t kDispatchMask = 0xd8; // 0b1101_1000 accepts first (0b1100_0xxx) and next (0b1110_0xxx). 600 static constexpr uint8_t kOffsetFlag = 1 << 5; // Indicate first (no offset) vs. next (offset present) fragment. 601 602 static constexpr uint16_t kSizeMask = 0x7ff; // 0b0111_1111_1111 (first 11 bits). 603 static constexpr uint16_t kOffsetMask = 0xfff8; // Clears the last 3 bits to ensure offset is a multiple of 8. 604 605 static constexpr uint8_t kSizeIndex = 0; // Start index of Size field in the Fragment Header byte sequence. 606 static constexpr uint8_t kTagIndex = 2; // Start index of Tag field in the Fragment Header byte sequence. 607 static constexpr uint8_t kOffsetIndex = 4; // Start index of Offset field in the Fragment Header byte sequence. 608 609 static bool IsFragmentHeader(const uint8_t *aFrame, uint16_t aFrameLength); 610 611 Error ParseFrom(const uint8_t *aFrame, uint16_t aFrameLength, uint16_t &aHeaderLength); 612 613 uint16_t mSize; 614 uint16_t mTag; 615 uint16_t mOffset; 616 }; 617 618 /** 619 * @} 620 */ 621 622 } // namespace Lowpan 623 } // namespace ot 624 625 #endif // LOWPAN_HPP_ 626