/* * 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 implements a spinel encoder. */ #include "spinel_encoder.hpp" #include #include "lib/utils/utils.hpp" namespace ot { namespace Spinel { otError Encoder::BeginFrame(Spinel::Buffer::Priority aPriority) { mNumOpenStructs = 0; mNcpBuffer.InFrameBegin(aPriority); return OT_ERROR_NONE; } otError Encoder::BeginFrame(uint8_t aHeader, unsigned int aCommand) { otError error = OT_ERROR_NONE; // Non-zero TID indicates this is a response to a spinel command. if (SPINEL_HEADER_GET_TID(aHeader) != 0) { EXPECT_NO_ERROR(error = BeginFrame(Spinel::Buffer::kPriorityHigh)); } else { EXPECT_NO_ERROR(error = BeginFrame(Spinel::Buffer::kPriorityLow)); } EXPECT_NO_ERROR(error = WriteUint8(aHeader)); EXPECT_NO_ERROR(error = WriteUintPacked(aCommand)); exit: return error; } otError Encoder::BeginFrame(uint8_t aHeader, unsigned int aCommand, spinel_prop_key_t aKey) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = BeginFrame(aHeader, aCommand)); // The write position is saved before writing the property key, // so that if fetching the property fails and we need to // reply with a `LAST_STATUS` error we can get back to // this saved write position and update the property key. // (Also see `OverwriteWithLastStatusError()`). EXPECT_NO_ERROR(error = SavePosition()); EXPECT_NO_ERROR(error = WriteUintPacked(aKey)); exit: return error; } otError Encoder::OverwriteWithLastStatusError(spinel_status_t aStatus) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = ResetToSaved()); EXPECT_NO_ERROR(error = WriteUintPacked(SPINEL_PROP_LAST_STATUS)); EXPECT_NO_ERROR(error = WriteUintPacked(aStatus)); exit: return error; } otError Encoder::EndFrame(void) { otError error = OT_ERROR_NONE; while (mNumOpenStructs > 0) { EXPECT_NO_ERROR(error = CloseStruct()); } error = mNcpBuffer.InFrameEnd(); exit: return error; } otError Encoder::WriteUint16(uint16_t aUint16) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint16 >> 0) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint16 >> 8) & 0xff)); exit: return error; } otError Encoder::WriteUint32(uint32_t aUint32) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 0) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 8) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 16) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint32 >> 24) & 0xff)); exit: return error; } otError Encoder::WriteUint64(uint64_t aUint64) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 0) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 8) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 16) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 24) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 32) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 40) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 48) & 0xff)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte((aUint64 >> 56) & 0xff)); exit: return error; } otError Encoder::WriteUintPacked(unsigned int aUint) { uint8_t buffer[6]; spinel_ssize_t len; len = spinel_packed_uint_encode(buffer, sizeof(buffer), aUint); return WriteData(buffer, static_cast(len)); } otError Encoder::WriteDataWithLen(const uint8_t *aData, uint16_t aDataLen) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = WriteUint16(aDataLen)); EXPECT_NO_ERROR(error = WriteData(aData, aDataLen)); exit: return error; } otError Encoder::WriteUtf8(const char *aUtf8) { otError error; size_t len = strlen(aUtf8); if (len >= 0xffff) { len = 0xffff; } EXPECT_NO_ERROR(error = WriteData(reinterpret_cast(aUtf8), static_cast(len))); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte(0)); exit: return error; } otError Encoder::OpenStruct(void) { otError error = OT_ERROR_NONE; EXPECT(mNumOpenStructs < kMaxNestedStructs, error = OT_ERROR_INVALID_STATE); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameGetPosition(mStructPosition[mNumOpenStructs])); // Reserve bytes for the length to be filled when the struct gets closed. EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte(0)); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameFeedByte(0)); mNumOpenStructs++; exit: return error; } otError Encoder::CloseStruct(void) { otError error = OT_ERROR_NONE; uint16_t len; uint8_t buffer[sizeof(uint16_t)]; EXPECT(mNumOpenStructs > 0, error = OT_ERROR_INVALID_STATE); mNumOpenStructs--; len = mNcpBuffer.InFrameGetDistance(mStructPosition[mNumOpenStructs]); EXPECT(len >= sizeof(uint16_t), error = OT_ERROR_INVALID_STATE); len -= sizeof(uint16_t); buffer[0] = (len >> 0 & 0xff); buffer[1] = (len >> 8 & 0xff); EXPECT_NO_ERROR(error = mNcpBuffer.InFrameOverwrite(mStructPosition[mNumOpenStructs], buffer, sizeof(buffer))); exit: return error; } otError Encoder::SavePosition(void) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = mNcpBuffer.InFrameGetPosition(mSavedPosition)); mSavedNumOpenStructs = mNumOpenStructs; exit: return error; } otError Encoder::ResetToSaved(void) { otError error = OT_ERROR_NONE; EXPECT_NO_ERROR(error = mNcpBuffer.InFrameReset(mSavedPosition)); mNumOpenStructs = mSavedNumOpenStructs; exit: return error; } otError Encoder::WritePacked(const char *aPackFormat, ...) { uint8_t buf[kPackFormatBufferSize]; otError error = OT_ERROR_NONE; spinel_ssize_t packedLen; va_list args; va_start(args, aPackFormat); packedLen = spinel_datatype_vpack(buf, sizeof(buf), aPackFormat, args); EXPECT((packedLen > 0) && (packedLen <= static_cast(sizeof(buf))), error = OT_ERROR_NO_BUFS); error = mNcpBuffer.InFrameFeedData(buf, static_cast(packedLen)); exit: va_end(args); return error; } otError Encoder::WriteVPacked(const char *aPackFormat, va_list aArgs) { uint8_t buf[kPackFormatBufferSize]; otError error = OT_ERROR_NONE; spinel_ssize_t packedLen; packedLen = spinel_datatype_vpack(buf, sizeof(buf), aPackFormat, aArgs); EXPECT((packedLen > 0) && (packedLen <= static_cast(sizeof(buf))), error = OT_ERROR_NO_BUFS); error = mNcpBuffer.InFrameFeedData(buf, static_cast(packedLen)); exit: return error; } void Encoder::ClearNcpBuffer(void) { mNcpBuffer.Clear(); } } // namespace Spinel } // namespace ot