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