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