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