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" AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY 20 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 /** 29 * @file 30 * This file includes definitions for an HDLC-lite encoder and decoder. 31 */ 32 33 #ifndef HDLC_HPP_ 34 #define HDLC_HPP_ 35 36 #include <stdint.h> 37 #include <stdlib.h> 38 #include <string.h> 39 40 #include <openthread/error.h> 41 42 #include "common/array.hpp" 43 #include "common/code_utils.hpp" 44 #include "common/debug.hpp" 45 #include "common/encoding.hpp" 46 47 namespace ot { 48 49 /** 50 * @namespace ot::Hdlc 51 * 52 * @brief 53 * This namespace includes definitions for the HDLC-lite encoder and decoder. 54 * 55 */ 56 namespace Hdlc { 57 58 /** 59 * This class defines a frame write pointer used by `Hdlc::Encoder` or `Hdlc::Decoder`. 60 * 61 * This class defines the minimum set of APIs used by `Encoder/Decoder` for writing an encoded/decoded frame. It is 62 * simply a wrapper over a pointer into a buffer indicating where next byte should be written. Along with a write 63 * pointer, this class stores a remaining length variable indicating number of remaining bytes that can be written into 64 * the buffer. 65 * 66 * @note This class does NOT define the underlying buffer space or how it is being managed. 67 * 68 * `Encoder` or `Decoder` users are expected to use sub-classes of this class adding the buffer space and implementing 69 * the frame buffer management scheme. 70 * 71 * Two template sub-class `FrameBuffer` and `MultiFrameBuffer` are defined which respectively allow storing a single 72 * frame or multiple frames (FIFO queue of frame) in a buffer of a given size. 73 * 74 */ 75 class FrameWritePointer 76 { 77 public: 78 /** 79 * This method indicates whether there is buffer space available to write @p aWriteLength bytes. 80 * 81 * param[in] aWriteLength Number of bytes to write. 82 * 83 * @retval TRUE Enough buffer space is available to write the requested number of bytes. 84 * @retval FALSE Insufficient buffer space to write the requested number of bytes. 85 * 86 */ CanWrite(uint16_t aWriteLength) const87 bool CanWrite(uint16_t aWriteLength) const { return (mRemainingLength >= aWriteLength); } 88 89 /** 90 * This method writes a byte into the buffer and updates the write pointer (if space is available). 91 * 92 * @retval OT_ERROR_NONE Successfully wrote the byte and updated the pointer. 93 * @retval OT_ERROR_NO_BUFS Insufficient buffer space to write the byte. 94 * 95 */ WriteByte(uint8_t aByte)96 otError WriteByte(uint8_t aByte) 97 { 98 return CanWrite(sizeof(uint8_t)) ? (*mWritePointer++ = aByte, mRemainingLength--, OT_ERROR_NONE) 99 : OT_ERROR_NO_BUFS; 100 } 101 102 /** 103 * This method undoes the last @p aUndoLength writes, removing them from frame. 104 * 105 * @note Caller should ensure that @p aUndoLength is less than or equal to the number of previously written bytes 106 * into the frame. This method does not perform any checks and its behavior is undefined if @p aUndoLength is 107 * larger than the number of bytes previously written into the frame. 108 * 109 * @param[in] aUndoLength Number of bytes to remove (number of last `WriteByte()` calls to undo). 110 * 111 */ UndoLastWrites(uint16_t aUndoLength)112 void UndoLastWrites(uint16_t aUndoLength) 113 { 114 mWritePointer -= aUndoLength; 115 mRemainingLength += aUndoLength; 116 } 117 118 protected: FrameWritePointer(void)119 FrameWritePointer(void) 120 : mWritePointer(nullptr) 121 , mRemainingLength(0) 122 { 123 } 124 125 uint8_t *mWritePointer; ///< A pointer to current write position in the buffer. 126 uint16_t mRemainingLength; ///< Number of remaining bytes available to write. 127 }; 128 129 /** 130 * This class defines a template frame buffer of a given size for storing a single frame. 131 * 132 * The template parameter `kSize` specifies the size of the buffer. 133 * 134 */ 135 template <uint16_t kSize> class FrameBuffer : public FrameWritePointer 136 { 137 public: 138 /** 139 * This constructor initializes the `FrameBuffer` object. 140 * 141 */ FrameBuffer(void)142 FrameBuffer(void) 143 : FrameWritePointer() 144 { 145 Clear(); 146 } 147 148 /** 149 * This method clears the buffer, moving the write pointer to the beginning of the buffer. 150 * 151 */ Clear(void)152 void Clear(void) 153 { 154 mWritePointer = mBuffer; 155 mRemainingLength = sizeof(mBuffer); 156 } 157 158 /** 159 * This method indicates whether the buffer is empty or contains a frame. 160 * 161 * @retval TRUE Buffer is empty 162 * @retval FALSE Buffer contains a frame 163 * 164 */ IsEmpty(void) const165 bool IsEmpty(void) const { return (mWritePointer == mBuffer); } 166 167 /** 168 * This method gets the length (number of bytes) in the frame. 169 * 170 * @returns The length (number of bytes) in the frame. 171 * 172 */ GetLength(void) const173 uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - mBuffer); } 174 175 /** 176 * This method gets a pointer to start of the frame. 177 * 178 * @returns A pointer to start of the frame. 179 * 180 */ GetFrame(void)181 uint8_t *GetFrame(void) { return mBuffer; } 182 183 private: 184 uint8_t mBuffer[kSize]; 185 }; 186 187 /** 188 * This class defines a template frame buffer of a given size for storing multiple frames. 189 * 190 * The template parameter `kSize` specifies the total size of the buffer. 191 * 192 * Unlike `FrameBuffer` class where a single frame can be stored, this class is capable of saving multiple frames 193 * in a FIFO queue format. 194 * 195 */ 196 template <uint16_t kSize> class MultiFrameBuffer : public FrameWritePointer 197 { 198 public: 199 /** 200 * This constructor initializes the `MultiFrameBuffer` object. 201 * 202 */ MultiFrameBuffer(void)203 MultiFrameBuffer(void) 204 : FrameWritePointer() 205 { 206 Clear(); 207 } 208 209 /** 210 * This method clears the buffer, removing current frame and all previously saved frames. 211 * 212 * It moves the write pointer to the beginning of the buffer. 213 * 214 */ Clear(void)215 void Clear(void) 216 { 217 mWriteFrameStart = mBuffer; 218 mWritePointer = mBuffer + kHeaderSize; 219 mRemainingLength = kSize - kHeaderSize; 220 221 IgnoreError(SetSkipLength(0)); 222 } 223 224 /** 225 * This method indicates whether the current frame (being written) is empty or not. 226 * 227 * @retval TRUE Current frame is empty. 228 * @retval FALSE Current frame is not empty. 229 * 230 */ HasFrame(void) const231 bool HasFrame(void) const { return (mWritePointer != GetFrame()); } 232 233 /** 234 * This method sets the length (number of bytes) of the current frame being written. 235 * 236 * param[in] aLength The length of current frame. 237 * 238 * @retval OT_ERROR_NONE Successfully set the length of the current frame. 239 * @retval OT_ERROR_NO_BUFS Insufficient buffer space to hold a frame of length @p aLength. 240 * 241 */ SetLength(uint16_t aLength)242 otError SetLength(uint16_t aLength) 243 { 244 otError error = OT_ERROR_NO_BUFS; 245 246 if (GetFrame() + aLength <= GetArrayEnd(mBuffer)) 247 { 248 mWritePointer = GetFrame() + aLength; 249 mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer); 250 error = OT_ERROR_NONE; 251 } 252 253 return error; 254 } 255 256 /** 257 * This method gets the length (number of bytes) in the current frame being written into the buffer. 258 * 259 * @returns The length (number of bytes) in the frame. 260 * 261 */ GetLength(void) const262 uint16_t GetLength(void) const { return static_cast<uint16_t>(mWritePointer - GetFrame()); } 263 264 /** 265 * This method sets the length (number of bytes) of reserved buffer in front of the current frame being written. 266 * 267 * param[in] aSkipLength The length of reserved buffer. 268 * 269 * @retval OT_ERROR_NONE Successfully set the length of reserved buffer. 270 * @retval OT_ERROR_NO_BUFS Insufficient buffer space to hold a reserved buffer of length @p aLength. 271 * 272 */ SetSkipLength(uint16_t aSkipLength)273 otError SetSkipLength(uint16_t aSkipLength) 274 { 275 otError error = OT_ERROR_NO_BUFS; 276 277 if (mWriteFrameStart + kHeaderSize + aSkipLength <= GetArrayEnd(mBuffer)) 278 { 279 Encoding::LittleEndian::WriteUint16(aSkipLength, mWriteFrameStart + kHeaderSkipLengthOffset); 280 mWritePointer = GetFrame(); 281 mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer); 282 error = OT_ERROR_NONE; 283 } 284 285 return error; 286 } 287 288 /** 289 * This method gets the length (number of bytes) of reserved buffer in front of the current frame being written. 290 * 291 * @returns The length (number of bytes) of the reserved buffer. 292 * 293 */ GetSkipLength(void) const294 uint16_t GetSkipLength(void) const 295 { 296 return Encoding::LittleEndian::ReadUint16(mWriteFrameStart + kHeaderSkipLengthOffset); 297 } 298 299 /** 300 * This method gets a pointer to the start of the current frame. 301 * 302 * @returns A pointer to the start of the frame. 303 * 304 */ GetFrame(void) const305 uint8_t *GetFrame(void) const { return mWriteFrameStart + kHeaderSize + GetSkipLength(); } 306 307 /** 308 * This method gets the maximum length of the current frame. 309 * 310 * @returns The maximum length of the current frame. 311 * 312 */ GetFrameMaxLength(void) const313 uint16_t GetFrameMaxLength(void) const { return static_cast<uint16_t>(mBuffer + kSize - GetFrame()); } 314 315 /** 316 * This method saves the current frame and prepares the write pointer for a next frame to be written into the 317 * buffer. 318 * 319 * Saved frame can be retrieved later using `GetNextSavedFrame()`. 320 * 321 */ SaveFrame(void)322 void SaveFrame(void) 323 { 324 Encoding::LittleEndian::WriteUint16(GetSkipLength() + GetLength(), mWriteFrameStart + kHeaderTotalLengthOffset); 325 mWriteFrameStart = mWritePointer; 326 IgnoreError(SetSkipLength(0)); 327 mWritePointer = GetFrame(); 328 mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer); 329 } 330 331 /** 332 * This method discards the current frame and prepares the write pointer for a next frame to be written into the 333 * buffer. 334 * 335 */ DiscardFrame(void)336 void DiscardFrame(void) 337 { 338 IgnoreError(SetSkipLength(0)); 339 340 mWritePointer = GetFrame(); 341 mRemainingLength = static_cast<uint16_t>(mBuffer + kSize - mWritePointer); 342 } 343 344 /** 345 * This method indicates whether there are any saved frames in the buffer. 346 * 347 * @retval TRUE There is at least one saved frame in the buffer. 348 * @retval FALSE There is no saved frame in the buffer. 349 * 350 */ HasSavedFrame(void) const351 bool HasSavedFrame(void) const { return (mWriteFrameStart != mBuffer); } 352 353 /** 354 * This method iterates through previously saved frames in the buffer, getting a next frame in the queue. 355 * 356 * @param[in,out] aFrame On entry, should point to a previous saved frame or nullptr to get the first frame. 357 * On exit, the pointer variable is updated to next frame or set to nullptr if there are 358 * none. 359 * @param[in,out] aLength On entry, should be a reference to the frame length of the previous saved frame. 360 * On exit, the reference is updated to the frame length (number of bytes) of next frame. 361 * 362 * @retval OT_ERROR_NONE Updated @aFrame and @aLength successfully with the next saved frame. 363 * @retval OT_ERROR_NOT_FOUND No more saved frame in the buffer. 364 * 365 */ GetNextSavedFrame(uint8_t * & aFrame,uint16_t & aLength)366 otError GetNextSavedFrame(uint8_t *&aFrame, uint16_t &aLength) 367 { 368 otError error = OT_ERROR_NONE; 369 370 OT_ASSERT(aFrame == nullptr || (mBuffer <= aFrame && aFrame < GetArrayEnd(mBuffer))); 371 372 aFrame = (aFrame == nullptr) ? mBuffer : aFrame + aLength; 373 374 if (aFrame != mWriteFrameStart) 375 { 376 uint16_t totalLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderTotalLengthOffset); 377 uint16_t skipLength = Encoding::LittleEndian::ReadUint16(aFrame + kHeaderSkipLengthOffset); 378 379 aLength = totalLength - skipLength; 380 aFrame += kHeaderSize + skipLength; 381 } 382 else 383 { 384 aLength = 0; 385 aFrame = nullptr; 386 error = OT_ERROR_NOT_FOUND; 387 } 388 389 return error; 390 } 391 392 /** 393 * This method clears all saved frames from the buffer and adjusts all the pointers. 394 * 395 * @note This method moves the pointers into the buffer and also copies the content. Any previously retrieved 396 * pointer to buffer (from `GetFrame()` or `GetNextSavedFrame()`) should be considered invalid after calling this 397 * method. 398 * 399 */ ClearSavedFrames(void)400 void ClearSavedFrames(void) 401 { 402 uint16_t len = static_cast<uint16_t>(mWriteFrameStart - mBuffer); 403 404 if (len > 0) 405 { 406 memmove(mBuffer, mWriteFrameStart, static_cast<uint16_t>(mWritePointer - mWriteFrameStart)); 407 mWritePointer -= len; 408 mWriteFrameStart -= len; 409 mRemainingLength += len; 410 } 411 } 412 413 private: 414 /* 415 * The diagram below illustrates the format of a saved frame. 416 * 417 * +---------+-------------+------------+----------------+----------------------------+ 418 * | Octets: | 2 | 2 | SkipLength | TotalLength - SkipLength | 419 * +---------+-------------+------------+----------------+----------------------------+ 420 * | Fields: | TotalLength | SkipLength | ReservedBuffer | FrameBuffer | 421 * +---------+-------------+------------+----------------+----------------------------+ 422 * 423 * - "TotalLength" : The total length of the `ReservedBuffer` and `FrameBuffer`. It is stored in header bytes 424 * as a `uint16_t` value using little-endian encoding. 425 * - "SkipLength" : The length of the `ReservedBuffer`. It is stored in header bytes as a `uint16_t` value 426 * using little-endian encoding. 427 * - "ReservedBuffer": A reserved buffer in front of `FrameBuffer`. User can use it to store extra header, etc. 428 * - "FrameBuffer" : Frame buffer. 429 * 430 * The diagram below illustrates how the frames are saved in the buffer. 431 * 432 * The diagram shows `mBuffer` and different pointers into the buffer. It represents buffer state when there are 433 * two saved frames in the buffer. 434 * 435 * Saved frame #1 Saved frame #2 Current frame being written 436 * / \ / \ / \ 437 * +-----------+-------------+-----------+------------+---------+--------------------------------------------+ 438 * | header #1 | ... | header #2 | ... | header | ... | ... | 439 * +-----------+-------------+-----------+------------+---------+--------------------------------------------+ 440 * ^ ^ ^\ /^ 441 * | | | mRemainingLength | 442 * mBuffer[0] mWriteFrameStart | | 443 * | mBuffer[kSize] 444 * mWritePointer 445 */ 446 447 enum 448 { 449 kHeaderTotalLengthOffset = 0, 450 kHeaderSkipLengthOffset = sizeof(uint16_t), 451 kHeaderSize = sizeof(uint16_t) + sizeof(uint16_t), 452 }; 453 454 uint8_t mBuffer[kSize]; 455 uint8_t *mWriteFrameStart; // Pointer to start of current frame being written. 456 }; 457 458 /** 459 * This class implements the HDLC-lite encoder. 460 * 461 */ 462 class Encoder 463 { 464 public: 465 /** 466 * This constructor initializes the object. 467 * 468 * @param[in] aWritePointer The `FrameWritePointer` used by `Encoder` to write the encoded frames. 469 * 470 */ 471 explicit Encoder(FrameWritePointer &aWritePointer); 472 473 /** 474 * This method begins an HDLC frame. 475 * 476 * @retval OT_ERROR_NONE Successfully started the HDLC frame. 477 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to start the HDLC frame. 478 * 479 */ 480 otError BeginFrame(void); 481 482 /** 483 * This method encodes a single byte into current frame. 484 * 485 * If there is no space to add the byte, the write pointer in frame buffer remains the same. 486 * 487 * @param[in] aByte A byte value to encode and add to frame. 488 * 489 * @retval OT_ERROR_NONE Successfully encoded and added the byte to frame buffer. 490 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to encode and add the byte. 491 * 492 */ 493 otError Encode(uint8_t aByte); 494 495 /** 496 * This method encodes a given block of data into current frame. 497 * 498 * This method returns success only if there is space in buffer to encode the entire block of data. If there is no 499 * space to encode the entire block of data, the write pointer in frame buffer remains the same. 500 * 501 * @param[in] aData A pointer to a buffer containing the data to encode. 502 * @param[in] aLength The number of bytes in @p aData. 503 * 504 * @retval OT_ERROR_NONE Successfully encoded and added the data to frame. 505 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to add the frame. 506 * 507 */ 508 otError Encode(const uint8_t *aData, uint16_t aLength); 509 510 /** 511 * This method ends/finalizes the HDLC frame. 512 * 513 * @retval OT_ERROR_NONE Successfully ended the HDLC frame. 514 * @retval OT_ERROR_NO_BUFS Insufficient buffer space available to end the HDLC frame. 515 * 516 */ 517 otError EndFrame(void); 518 519 private: 520 FrameWritePointer &mWritePointer; 521 uint16_t mFcs; 522 }; 523 524 /** 525 * This class implements the HDLC-lite decoder. 526 * 527 */ 528 class Decoder 529 { 530 public: 531 /** 532 * This function pointer is called when either a complete frame has been decoded or an error occurs during 533 * decoding. 534 * 535 * The decoded frame (or the partially decoded frame in case of an error) is available in `aFrameWritePointer` 536 * buffer given in `Decoder` constructor. 537 * 538 * @param[in] aContext A pointer to arbitrary context information. 539 * @param[in] aError OT_ERROR_NONE if the frame was decoded successfully, 540 * OT_ERROR_PARSE if the Frame Check Sequence (FCS) was incorrect in decoded frame, 541 * OT_ERROR_NO_BUFS insufficient buffer space available to save the decoded frame. 542 * 543 */ 544 typedef void (*FrameHandler)(void *aContext, otError aError); 545 546 /** 547 * This constructor initializes the decoder. 548 * 549 * @param[in] aFrameWritePointer The `FrameWritePointer` used by `Decoder` to write the decoded frames. 550 * @param[in] aFrameHandler The frame handler callback function pointer. 551 * @param[in] aContext A pointer to arbitrary context information. 552 * 553 */ 554 Decoder(FrameWritePointer &aFrameWritePointer, FrameHandler aFrameHandler, void *aContext); 555 556 /** 557 * This method feeds a block of data into the decoder. 558 * 559 * If during decoding, a full HDLC frame is successfully decoded or an error occurs, the `FrameHandler` callback 560 * is called. The decoded frame (or the partially decoded frame in case of an error) is available in 561 * `aFrameWritePointer` buffer from the constructor. The `Decoder` user (if required) must update/reset the write 562 * pointer from this callback for the next frame to be decoded. 563 * 564 * @param[in] aData A pointer to a buffer containing data to be fed to decoder. 565 * @param[in] aLength The number of bytes in @p aData. 566 * 567 */ 568 void Decode(const uint8_t *aData, uint16_t aLength); 569 570 /** 571 * This method resets internal states of the decoder. 572 * 573 */ 574 void Reset(void); 575 576 private: 577 enum State 578 { 579 kStateNoSync, 580 kStateSync, 581 kStateEscaped, 582 }; 583 584 State mState; 585 FrameWritePointer &mWritePointer; 586 FrameHandler mFrameHandler; 587 void * mContext; 588 uint16_t mFcs; 589 uint16_t mDecodedLength; 590 }; 591 592 } // namespace Hdlc 593 } // namespace ot 594 595 #endif // HDLC_HPP_ 596