blob: 8267e77ef60bef38bfb7087406170079714900f6 [file] [log] [blame]
/*
* Copyright (c) 2017, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* @file
* This file contains the definitions of a spinel decoder.
*/
#ifndef SPINEL_DECODER_HPP_
#define SPINEL_DECODER_HPP_
#include <openthread/config.h>
#include <openthread/ip6.h>
#include <openthread/ncp.h>
#include "openthread-core-config.h"
#include "ncp/spinel.h"
namespace ot {
namespace Ncp {
/**
* This class defines a spinel decoder.
*
*/
class SpinelDecoder
{
public:
enum
{
kMaxNestedStructs = 4, ///< Maximum number of nested structs.
};
/**
* This constructor initializes a `SpinelDecoder` object.
*
*/
SpinelDecoder(void);
/**
* This method initializes the decoder to start decoding a new frame.
*
* It sets the read position to the start of the frame and also erases/voids any saved positions (see
* `SavePosition()` and `ResetToSaved()` methods).
*
* @param[in] aFrame Pointer to the buffer containing the frame to be decoded.
* @param[in] aLength Length (number of bytes) of the frame.
*
*/
void Init(const uint8_t *aFrame, uint16_t aLength);
/**
* This method returns the pointer to the start of the frame.
*
* @returns A pointer to buffer containing current frame being decoded.
*
*/
const uint8_t *GetFrame(void) const { return mFrame; }
/**
* This method returns the total length of current frame being decoded.
*
* @returns The length of current frame being decoded.
*
*/
uint16_t GetLength(void) const { return mLength; }
/**
* This method returns the number of bytes that are already read/decoded from the frame.
*
* @returns The number of bytes already read from frame.
*
*/
uint16_t GetReadLength(void) const { return mIndex; }
/**
* This method returns the number of remaining (not yet read/decoded) bytes in the frame.
*
* @returns The number of remaining unread bytes in the frame.
*
*/
uint16_t GetRemainingLength(void) const { return mLength - mIndex; }
/**
* This method indicates whether or not all the bytes in the frame are read.
*
* @returns TRUE if all the bytes in the buffer are read, FALSE otherwise.
*
*/
bool IsAllRead(void) const { return (mIndex == mLength); }
/**
* This method resets the read position to beginning of frame. It will also void/erase any previously saved
* position using `SavePosition()` method.
*
*/
void Reset(void);
/**
* This method decodes and reads a boolean value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aBool Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadBool(bool &aBool);
/**
* This method decodes and reads an `int8_t` value form the frame.
*
* On success, the read position get updated.
*
* @param[out] aInt8 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadInt8(int8_t &aInt8);
/**
* This method decodes and reads an `uint8_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aUint8 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadUint8(uint8_t &aUint8);
/**
* This method decodes and reads an `int16_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aInt16 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadInt16(int16_t &aInt16);
/**
* This method decodes and reads an `uint16_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aUint16 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadUint16(uint16_t &aUint16);
/**
* This method decodes and reads an `int32_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aInt32 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadInt32(int32_t &aInt32);
/**
* This method decodes and reads an `uint32_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aUint32 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadUint32(uint32_t &aUint32);
/**
* This method decodes and reads an `int64_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aInt64 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadInt64(int64_t &aInt64);
/**
* This method decodes and reads an `uint64_t` value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aUint64 Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadUint64(uint64_t &aUint64);
/**
* This method decodes (using spinel packed integer format) and reads an unsigned integer value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aUint Reference to variable to output the read value.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadUintPacked(unsigned int &aUint);
/**
* This method decodes and reads an IPv6 address form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `spinel_ipv6addr_t`).
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadIp6Address(const spinel_ipv6addr_t *&aIp6AddrPtr)
{
return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
}
/**
* This method decodes and reads an IPv6 address form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aIp6AddrPtr Reference to IPv6 address pointer to output the value (as `otIp6Address`).
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadIp6Address(const otIp6Address *&aIp6AddrPtr)
{
return ReadItem(reinterpret_cast<const uint8_t **>(&aIp6AddrPtr), sizeof(spinel_ipv6addr_t));
}
/**
* This method decodes and reads an IPv6 address form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aIp6AddrBufPtr Reference to a buffer pointer to output the value.
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadIp6Address(const uint8_t *&aIp6AddrBufPtr)
{
return ReadItem(&aIp6AddrBufPtr, sizeof(spinel_ipv6addr_t));
}
/**
* This method decodes and reads an IPv6 address form the frame.
*
* On success, the read position gets updated and the IP address is copied into the given output variable.
*
* @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as `spinel_ipv6addr_t`).
* On success, the address is copied into the output variable.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadIp6Address(spinel_ipv6addr_t &aIp6Addr);
/**
* This method decodes and reads an IPv6 address form the frame.
*
* On success, the read position gets updated and the IP address is copied into the given output variable.
*
* @param[out] aIp6Addr Reference to IPv6 address variable to output the value (as `otIp6Address`).
* On success, the address is copied into the output variable.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadIp6Address(otIp6Address &aIp6Addr);
/**
* This method decodes and reads an EUI64 value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `spinel_eui64_t`).
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui64(const spinel_eui64_t *&aEui64Ptr)
{
return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t));
}
/**
* This method decodes and reads an EUI64 value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aEui64Ptr Reference to an EUI64 pointer to output the value (as `otExtAddress`).
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui64(const otExtAddress *&aEui64Ptr)
{
return ReadItem(reinterpret_cast<const uint8_t **>(&aEui64Ptr), sizeof(spinel_eui64_t));
}
/**
* This method decodes and reads an EUI64 value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aEui64BufPtr Reference to a buffer pointer to output the value.
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui64(const uint8_t *&aEui64BufPtr) { return ReadItem(&aEui64BufPtr, sizeof(spinel_eui64_t)); }
/**
* This method decodes and reads an EUI64 value form the frame.
*
* On success, the read position gets updated and the EUI64 value is copied into the given output variable.
*
* @param[out] aEui64 Reference to EUI64 variable to output the value (as `spinel_eui64_t`).
* On success, the address is copied into the output variable.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui64(spinel_eui64_t &aEui64);
/**
* This method decodes and reads an EUI64 value form the frame.
*
* On success, the read position gets updated and the EUI64 value is copied into the given output variable.
*
* @param[out] aEui64 Reference to EUI64 variable to output the value (as `otExtAddress`).
* On success, the address is copied into the output variable.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui64(otExtAddress &aEui64);
/**
* This method decodes and reads an EUI48 value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aEui48Ptr Reference to an EUI48 pointer to output the value (as `spinel_eui48_t`).
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui48(const spinel_eui48_t *&aEui48Ptr)
{
return ReadItem(reinterpret_cast<const uint8_t **>(&aEui48Ptr), sizeof(spinel_eui48_t));
}
/**
* This method decodes and reads an EUI48 value form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aEui48BufPtr Reference to a buffer pointer to output the value.
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui48(const uint8_t *&aEui48BufPtr) { return ReadItem(&aEui48BufPtr, sizeof(spinel_eui48_t)); }
/**
* This method decodes and reads an EUI48 value form the frame.
*
* On success, the read position gets updated and the EUI48 value is copied into the given output variable.
*
* @param[out] aEui48 Reference to EUI48 variable to output the value (as `spinel_eui48_t`).
* On success, value is copied into the output variable.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadEui48(spinel_eui48_t &aEui48);
/**
* This method decodes and reads a UTF8 string form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aUtf8 Reference to a `char` pointer to output the string.
* On success, the pointer variable is updated.
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadUtf8(const char *&aUtf8);
/**
* This method decodes and reads a data blob (sequence of bytes) form the frame.
*
* On success, the read position gets updated.
*
* @param[out] aData Reference to pointer variable to output the data.
* On success, the pointer variable is updated.
* @param[out] aDataLength Reference to variable to output the data length (number of bytes).
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadData(const uint8_t *&aData, uint16_t &aDataLen);
/**
* This method decodes and reads a data blob (sequence of bytes) with data length.
*
* The data length is assumed to be prepended before the data content (encoded as a `uint16_t`). The size of the
* length field should not be included in the length value. This method corresponds to `SPINEL_DATATYPE_DATA_WLEN`
* type.
*
* @param[out] aData Reference to pointer variable to output the data.
* On success, the pointer variable is updated.
* @param[out] aDataLength Reference to variable to out the data length (number of bytes).
*
* @retval OT_ERROR_NONE Successfully read the value.
* @retval OT_ERROR_PARSE Failed to parse/decode the value.
*
*/
otError ReadDataWithLen(const uint8_t *&aData, uint16_t &aDataLen);
/**
* This method opens a struct in the frame.
*
* After a successful call to this method, all the subsequent `Read{SomeType}()` methods decode and read the
* field/value from the current open struct until the struct is closed using `CloseStruct()` method. Structures can
* be nested. Up to `kMaxNestedStructs` nested structs can be opened at the same time.
*
* @retval OT_ERROR_NONE Successfully opened a struct.
* @retval OT_ERROR_PARSE Failed to parse/open a struct.
* @retval OT_ERROR_INVALID_STATE Already at the maximum number of nested open structures.
*
*/
otError OpenStruct(void);
/**
* This method closes the most recently opened struct (using `OpenStruct()`) in the frame.
*
* On success, the read position is moved to end of the struct skipping any unread bytes within the struct.
*
* @retval OT_ERROR_NONE Successfully closed the struct.
* @retval OT_ERROR_INVALID_STATE There is no current open struct to close.
*
*/
otError CloseStruct(void);
/**
* This method returns the number of remaining/unread bytes in the current inner-most open structure.
*
* If there is no currently open structure the number of remaining bytes in whole frame is returned instead.
*
* @returns The number of remaining unread bytes in the inner-most open structure.
*
*/
uint16_t GetRemainingLengthInStruct(void) const { return mEnd - mIndex; }
/**
* This method indicates whether or not all the bytes in inner-most open structure are read.
*
* If there is no currently open structure, the whole frame is considered instead.
*
* @returns TRUE if all the bytes are read, FALSE otherwise.
*
*/
bool IsAllReadInStruct(void) const { return (mIndex == mEnd); }
/**
* This method saves the current read position in the frame.
*
* A subsequent call to `SavePosition()` will overwrite the previously saved position. The saved position can be
* used to move the read position back (using `ResetToSaved()`) and re-read the same content.
*
* Saved position can be within an open struct, and it remembers its enclosing struct. When the enclosing struct is
* closed, the saved position will be voided and can no longer be used. This ensures that we cannot jump back to
* middle an already fully decoded/read and closed struct.
*
*/
void SavePosition(void);
/**
* This method resets/moves the read position to a previously saved position.
*
* The saved position remembers its enclosing structure. When `ResetToSaved()` is called, the current open
* structure will be the same as when position was saved.
*
* @retval OT_ERROR_NONE Successfully reset the read position.
* @retval OT_ERROR_INVALID_STATE The saved position is not valid (there is no saved position or the saved
* position was voided since its enclosing struct was closed).
*
*/
otError ResetToSaved(void);
private:
otError ReadItem(const uint8_t **aPtr, uint16_t aSize);
void ClearSavedPosition(void) { mSavedIndex = mLength; }
bool IsSavedPositionValid(void) const { return (mSavedIndex < mLength); }
const uint8_t *mFrame; // Frame buffer.
uint16_t mLength; // Frame length (number of bytes).
uint16_t mIndex; // Current read index.
uint16_t mEnd; // Current end index (end of struct if in a struct, or end of buffer otherwise).
uint8_t mNumOpenStructs; // Number of open structs.
uint8_t mSavedNumOpenStructs; // Number of open structs when read position was saved.
uint16_t mSavedIndex; // Read index when position was saved.
uint16_t mSavedEnd; // End index when position was saved.
uint16_t mPrevEnd[kMaxNestedStructs];
};
} // namespace Ncp
} // namespace ot
#endif // SPINEL_DECODER_HPP_