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