1 /* 2 * Copyright (c) 2017, 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 contains the definitions of a spinel decoder. 31 */ 32 33 #ifndef SPINEL_DECODER_HPP_ 34 #define SPINEL_DECODER_HPP_ 35 36 #include "openthread-spinel-config.h" 37 38 #include <openthread/ip6.h> 39 #include <openthread/ncp.h> 40 41 #include "spinel.h" 42 43 namespace ot { 44 namespace Spinel { 45 46 /** 47 * This class defines a spinel decoder. 48 * 49 */ 50 class Decoder 51 { 52 public: 53 enum 54 { 55 kMaxNestedStructs = 4, ///< Maximum number of nested structs. 56 }; 57 58 /** 59 * This constructor initializes a `Decoder` object. 60 * 61 */ 62 Decoder(void); 63 64 /** 65 * This method initializes the decoder to start decoding a new frame. 66 * 67 * It sets the read position to the start of the frame and also erases/voids any saved positions (see 68 * `SavePosition()` and `ResetToSaved()` methods). 69 * 70 * @param[in] aFrame Pointer to the buffer containing the frame to be decoded. 71 * @param[in] aLength Length (number of bytes) of the frame. 72 * 73 */ 74 void Init(const uint8_t *aFrame, uint16_t aLength); 75 76 /** 77 * This method returns the pointer to the start of the frame. 78 * 79 * @returns A pointer to buffer containing current frame being decoded. 80 * 81 */ GetFrame(void) const82 const uint8_t *GetFrame(void) const { return mFrame; } 83 84 /** 85 * This method returns the total length of current frame being decoded. 86 * 87 * @returns The length of current frame being decoded. 88 * 89 */ GetLength(void) const90 uint16_t GetLength(void) const { return mLength; } 91 92 /** 93 * This method returns the number of bytes that are already read/decoded from the frame. 94 * 95 * @returns The number of bytes already read from frame. 96 * 97 */ GetReadLength(void) const98 uint16_t GetReadLength(void) const { return mIndex; } 99 100 /** 101 * This method returns the number of remaining (not yet read/decoded) bytes in the frame. 102 * 103 * @returns The number of remaining unread bytes in the frame. 104 * 105 */ GetRemainingLength(void) const106 uint16_t GetRemainingLength(void) const { return mLength - mIndex; } 107 108 /** 109 * This method indicates whether or not all the bytes in the frame are read. 110 * 111 * @returns TRUE if all the bytes in the buffer are read, FALSE otherwise. 112 * 113 */ IsAllRead(void) const114 bool IsAllRead(void) const { return (mIndex == mLength); } 115 116 /** 117 * This method resets the read position to beginning of frame. It will also void/erase any previously saved 118 * position using `SavePosition()` method. 119 * 120 */ 121 void Reset(void); 122 123 /** 124 * This method decodes and reads a boolean value form the frame. 125 * 126 * On success, the read position gets updated. 127 * 128 * @param[out] aBool Reference to variable to output the read value. 129 * 130 * @retval OT_ERROR_NONE Successfully read the value. 131 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 132 * 133 */ 134 otError ReadBool(bool &aBool); 135 136 /** 137 * This method decodes and reads an `int8_t` value form the frame. 138 * 139 * On success, the read position get updated. 140 * 141 * @param[out] aInt8 Reference to variable to output the read value. 142 * 143 * @retval OT_ERROR_NONE Successfully read the value. 144 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 145 * 146 */ 147 otError ReadInt8(int8_t &aInt8); 148 149 /** 150 * This method decodes and reads an `uint8_t` value form the frame. 151 * 152 * On success, the read position gets updated. 153 * 154 * @param[out] aUint8 Reference to variable to output the read value. 155 * 156 * @retval OT_ERROR_NONE Successfully read the value. 157 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 158 * 159 */ 160 otError ReadUint8(uint8_t &aUint8); 161 162 /** 163 * This method decodes and reads an `int16_t` value form the frame. 164 * 165 * On success, the read position gets updated. 166 * 167 * @param[out] aInt16 Reference to variable to output the read value. 168 * 169 * @retval OT_ERROR_NONE Successfully read the value. 170 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 171 * 172 */ 173 otError ReadInt16(int16_t &aInt16); 174 175 /** 176 * This method decodes and reads an `uint16_t` value form the frame. 177 * 178 * On success, the read position gets updated. 179 * 180 * @param[out] aUint16 Reference to variable to output the read value. 181 * 182 * @retval OT_ERROR_NONE Successfully read the value. 183 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 184 * 185 */ 186 otError ReadUint16(uint16_t &aUint16); 187 188 /** 189 * This method decodes and reads an `int32_t` value form the frame. 190 * 191 * On success, the read position gets updated. 192 * 193 * @param[out] aInt32 Reference to variable to output the read value. 194 * 195 * @retval OT_ERROR_NONE Successfully read the value. 196 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 197 * 198 */ 199 otError ReadInt32(int32_t &aInt32); 200 201 /** 202 * This method decodes and reads an `uint32_t` value form the frame. 203 * 204 * On success, the read position gets updated. 205 * 206 * @param[out] aUint32 Reference to variable to output the read value. 207 * 208 * @retval OT_ERROR_NONE Successfully read the value. 209 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 210 * 211 */ 212 otError ReadUint32(uint32_t &aUint32); 213 214 /** 215 * This method decodes and reads an `int64_t` value form the frame. 216 * 217 * On success, the read position gets updated. 218 * 219 * @param[out] aInt64 Reference to variable to output the read value. 220 * 221 * @retval OT_ERROR_NONE Successfully read the value. 222 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 223 * 224 */ 225 otError ReadInt64(int64_t &aInt64); 226 227 /** 228 * This method decodes and reads an `uint64_t` value form the frame. 229 * 230 * On success, the read position gets updated. 231 * 232 * @param[out] aUint64 Reference to variable to output the read value. 233 * 234 * @retval OT_ERROR_NONE Successfully read the value. 235 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 236 * 237 */ 238 otError ReadUint64(uint64_t &aUint64); 239 240 /** 241 * This method decodes (using spinel packed integer format) and reads an unsigned integer value form the frame. 242 * 243 * On success, the read position gets updated. 244 * 245 * @param[out] aUint Reference to variable to output the read value. 246 * 247 * @retval OT_ERROR_NONE Successfully read the value. 248 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 249 * 250 */ 251 otError ReadUintPacked(unsigned int &aUint); 252 253 /** 254 * This method decodes and reads an IPv6 address form the frame. 255 * 256 * On success, the read position gets updated. 257 * 258 * @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `spinel_ipv6addr_t`). 259 * On success, the pointer variable is updated. 260 * 261 * @retval OT_ERROR_NONE Successfully read the value. 262 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 263 * 264 */ ReadIp6Address(const spinel_ipv6addr_t * & aIp6AddrPtr)265 otError ReadIp6Address(const spinel_ipv6addr_t *&aIp6AddrPtr) 266 { 267 return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t)); 268 } 269 270 /** 271 * This method decodes and reads an IPv6 address form the frame. 272 * 273 * On success, the read position gets updated. 274 * 275 * @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `otIp6Address`). 276 * On success, the pointer variable is updated. 277 * 278 * @retval OT_ERROR_NONE Successfully read the value. 279 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 280 * 281 */ ReadIp6Address(const otIp6Address * & aIp6AddrPtr)282 otError ReadIp6Address(const otIp6Address *&aIp6AddrPtr) 283 { 284 return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t)); 285 } 286 287 /** 288 * This method decodes and reads an IPv6 address form the frame. 289 * 290 * On success, the read position gets updated. 291 * 292 * @param[out] aIp6AddrBufPtr Reference to a buffer pointer to output the value. 293 * On success, the pointer variable is updated. 294 * 295 * @retval OT_ERROR_NONE Successfully read the value. 296 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 297 * 298 */ ReadIp6Address(const uint8_t * & aIp6AddrBufPtr)299 otError ReadIp6Address(const uint8_t *&aIp6AddrBufPtr) 300 { 301 return ReadItem(&aIp6AddrBufPtr, sizeof(spinel_ipv6addr_t)); 302 } 303 304 /** 305 * This method decodes and reads an IPv6 address form the frame. 306 * 307 * On success, the read position gets updated and the IP address is copied into the given output variable. 308 * 309 * @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as `spinel_ipv6addr_t`). 310 * On success, the address is copied into the output variable. 311 * 312 * @retval OT_ERROR_NONE Successfully read the value. 313 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 314 * 315 */ 316 otError ReadIp6Address(spinel_ipv6addr_t &aIp6Addr); 317 318 /** 319 * This method decodes and reads an IPv6 address form the frame. 320 * 321 * On success, the read position gets updated and the IP address is copied into the given output variable. 322 * 323 * @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as `otIp6Address`). 324 * On success, the address is copied into the output variable. 325 * 326 * @retval OT_ERROR_NONE Successfully read the value. 327 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 328 * 329 */ 330 otError ReadIp6Address(otIp6Address &aIp6Addr); 331 332 /** 333 * This method decodes and reads an EUI64 value form the frame. 334 * 335 * On success, the read position gets updated. 336 * 337 * @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `spinel_eui64_t`). 338 * On success, the pointer variable is updated. 339 * 340 * @retval OT_ERROR_NONE Successfully read the value. 341 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 342 * 343 */ ReadEui64(const spinel_eui64_t * & aEui64Ptr)344 otError ReadEui64(const spinel_eui64_t *&aEui64Ptr) 345 { 346 return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t)); 347 } 348 349 /** 350 * This method decodes and reads an EUI64 value form the frame. 351 * 352 * On success, the read position gets updated. 353 * 354 * @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `otExtAddress`). 355 * On success, the pointer variable is updated. 356 * 357 * @retval OT_ERROR_NONE Successfully read the value. 358 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 359 * 360 */ ReadEui64(const otExtAddress * & aEui64Ptr)361 otError ReadEui64(const otExtAddress *&aEui64Ptr) 362 { 363 return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t)); 364 } 365 366 /** 367 * This method decodes and reads an EUI64 value form the frame. 368 * 369 * On success, the read position gets updated. 370 * 371 * @param[out] aEui64BufPtr Reference to a buffer pointer to output the value. 372 * On success, the pointer variable is updated. 373 * 374 * @retval OT_ERROR_NONE Successfully read the value. 375 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 376 * 377 */ ReadEui64(const uint8_t * & aEui64BufPtr)378 otError ReadEui64(const uint8_t *&aEui64BufPtr) { return ReadItem(&aEui64BufPtr, sizeof(spinel_eui64_t)); } 379 380 /** 381 * This method decodes and reads an EUI64 value form the frame. 382 * 383 * On success, the read position gets updated and the EUI64 value is copied into the given output variable. 384 * 385 * @param[out] aEui64 Reference to EUI64 variable to output the value (as `spinel_eui64_t`). 386 * On success, the address is copied into the output variable. 387 * 388 * @retval OT_ERROR_NONE Successfully read the value. 389 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 390 * 391 */ 392 otError ReadEui64(spinel_eui64_t &aEui64); 393 394 /** 395 * This method decodes and reads an EUI64 value form the frame. 396 * 397 * On success, the read position gets updated and the EUI64 value is copied into the given output variable. 398 * 399 * @param[out] aEui64 Reference to EUI64 variable to output the value (as `otExtAddress`). 400 * On success, the address is copied into the output variable. 401 * 402 * @retval OT_ERROR_NONE Successfully read the value. 403 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 404 * 405 */ 406 otError ReadEui64(otExtAddress &aEui64); 407 408 /** 409 * This method decodes and reads an EUI48 value form the frame. 410 * 411 * On success, the read position gets updated. 412 * 413 * @param[out] aEui48Ptr Reference to an EUI48 pointer to output the value (as `spinel_eui48_t`). 414 * On success, the pointer variable is updated. 415 * 416 * @retval OT_ERROR_NONE Successfully read the value. 417 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 418 * 419 */ ReadEui48(const spinel_eui48_t * & aEui48Ptr)420 otError ReadEui48(const spinel_eui48_t *&aEui48Ptr) 421 { 422 return ReadItem(reinterpret_cast<const uint8_t **>(&aEui48Ptr), sizeof(spinel_eui48_t)); 423 } 424 425 /** 426 * This method decodes and reads an EUI48 value form the frame. 427 * 428 * On success, the read position gets updated. 429 * 430 * @param[out] aEui48BufPtr Reference to a buffer pointer to output the value. 431 * On success, the pointer variable is updated. 432 * 433 * @retval OT_ERROR_NONE Successfully read the value. 434 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 435 * 436 */ ReadEui48(const uint8_t * & aEui48BufPtr)437 otError ReadEui48(const uint8_t *&aEui48BufPtr) { return ReadItem(&aEui48BufPtr, sizeof(spinel_eui48_t)); } 438 439 /** 440 * This method decodes and reads an EUI48 value form the frame. 441 * 442 * On success, the read position gets updated and the EUI48 value is copied into the given output variable. 443 * 444 * @param[out] aEui48 Reference to EUI48 variable to output the value (as `spinel_eui48_t`). 445 * On success, value is copied into the output variable. 446 * 447 * @retval OT_ERROR_NONE Successfully read the value. 448 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 449 * 450 */ 451 otError ReadEui48(spinel_eui48_t &aEui48); 452 453 /** 454 * This method decodes and reads a UTF8 string form the frame. 455 * 456 * On success, the read position gets updated. 457 * 458 * @param[out] aUtf8 Reference to a `char` pointer to output the string. 459 * On success, the pointer variable is updated. 460 * 461 * @retval OT_ERROR_NONE Successfully read the value. 462 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 463 * 464 */ 465 otError ReadUtf8(const char *&aUtf8); 466 467 /** 468 * This method decodes and reads a data blob (sequence of bytes) form the frame. 469 * 470 * On success, the read position gets updated. 471 * 472 * @param[out] aData Reference to pointer variable to output the data. 473 * On success, the pointer variable is updated. 474 * @param[out] aDataLen Reference to variable to output the data length (number of bytes). 475 * 476 * @retval OT_ERROR_NONE Successfully read the value. 477 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 478 * 479 */ 480 otError ReadData(const uint8_t *&aData, uint16_t &aDataLen); 481 482 /** 483 * This method decodes and reads a data blob (sequence of bytes) with data length. 484 * 485 * The data length is assumed to be prepended before the data content (encoded as a `uint16_t`). The size of the 486 * length field should not be included in the length value. This method corresponds to `SPINEL_DATATYPE_DATA_WLEN` 487 * type. 488 * 489 * @param[out] aData Reference to pointer variable to output the data. 490 * On success, the pointer variable is updated. 491 * @param[out] aDataLen Reference to variable to out the data length (number of bytes). 492 * 493 * @retval OT_ERROR_NONE Successfully read the value. 494 * @retval OT_ERROR_PARSE Failed to parse/decode the value. 495 * 496 */ 497 otError ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen); 498 499 /** 500 * This method opens a struct in the frame. 501 * 502 * After a successful call to this method, all the subsequent `Read{SomeType}()` methods decode and read the 503 * field/value from the current open struct until the struct is closed using `CloseStruct()` method. Structures can 504 * be nested. Up to `kMaxNestedStructs` nested structs can be opened at the same time. 505 * 506 * @retval OT_ERROR_NONE Successfully opened a struct. 507 * @retval OT_ERROR_PARSE Failed to parse/open a struct. 508 * @retval OT_ERROR_INVALID_STATE Already at the maximum number of nested open structures. 509 * 510 */ 511 otError OpenStruct(void); 512 513 /** 514 * This method closes the most recently opened struct (using `OpenStruct()`) in the frame. 515 * 516 * On success, the read position is moved to end of the struct skipping any unread bytes within the struct. 517 * 518 * @retval OT_ERROR_NONE Successfully closed the struct. 519 * @retval OT_ERROR_INVALID_STATE There is no current open struct to close. 520 * 521 */ 522 otError CloseStruct(void); 523 524 /** 525 * This method returns the number of remaining/unread bytes in the current inner-most open structure. 526 * 527 * If there is no currently open structure the number of remaining bytes in whole frame is returned instead. 528 * 529 * @returns The number of remaining unread bytes in the inner-most open structure. 530 * 531 */ GetRemainingLengthInStruct(void) const532 uint16_t GetRemainingLengthInStruct(void) const { return mEnd - mIndex; } 533 534 /** 535 * This method indicates whether or not all the bytes in inner-most open structure are read. 536 * 537 * If there is no currently open structure, the whole frame is considered instead. 538 * 539 * @returns TRUE if all the bytes are read, FALSE otherwise. 540 * 541 */ IsAllReadInStruct(void) const542 bool IsAllReadInStruct(void) const { return (mIndex == mEnd); } 543 544 /** 545 * This method saves the current read position in the frame. 546 * 547 * A subsequent call to `SavePosition()` will overwrite the previously saved position. The saved position can be 548 * used to move the read position back (using `ResetToSaved()`) and re-read the same content. 549 * 550 * Saved position can be within an open struct, and it remembers its enclosing struct. When the enclosing struct is 551 * closed, the saved position will be voided and can no longer be used. This ensures that we cannot jump back to 552 * middle an already fully decoded/read and closed struct. 553 * 554 */ 555 void SavePosition(void); 556 557 /** 558 * This method resets/moves the read position to a previously saved position. 559 * 560 * The saved position remembers its enclosing structure. When `ResetToSaved()` is called, the current open 561 * structure will be the same as when position was saved. 562 * 563 * @retval OT_ERROR_NONE Successfully reset the read position. 564 * @retval OT_ERROR_INVALID_STATE The saved position is not valid (there is no saved position or the saved 565 * position was voided since its enclosing struct was closed). 566 * 567 */ 568 otError ResetToSaved(void); 569 570 private: 571 otError ReadItem(const uint8_t **aPtr, uint16_t aSize); ClearSavedPosition(void)572 void ClearSavedPosition(void) { mSavedIndex = mLength; } IsSavedPositionValid(void) const573 bool IsSavedPositionValid(void) const { return (mSavedIndex < mLength); } 574 575 const uint8_t *mFrame; // Frame buffer. 576 uint16_t mLength; // Frame length (number of bytes). 577 uint16_t mIndex; // Current read index. 578 uint16_t mEnd; // Current end index (end of struct if in a struct, or end of buffer otherwise). 579 uint8_t mNumOpenStructs; // Number of open structs. 580 581 uint8_t mSavedNumOpenStructs; // Number of open structs when read position was saved. 582 uint16_t mSavedIndex; // Read index when position was saved. 583 uint16_t mSavedEnd; // End index when position was saved. 584 585 uint16_t mPrevEnd[kMaxNestedStructs]; 586 }; 587 588 } // namespace Spinel 589 } // namespace ot 590 591 #endif // SPINEL_DECODER_HPP_ 592