blob: 99aabc46510bd1567687539540601f67c6055de9 [file] [log] [blame]
/*
*
* Copyright (c) 2020-2021 Project CHIP Authors
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file defines structures and utility methods for working with BDX
* messages, mainly for writing to and reading from PacketBuffers.
*/
#pragma once
#include <lib/support/BitFlags.h>
#include <lib/support/BufferWriter.h>
#include <lib/support/CodeUtils.h>
#include <protocols/Protocols.h>
#include <protocols/bdx/StatusCode.h>
#include <system/SystemPacketBuffer.h>
namespace chip {
namespace bdx {
inline constexpr uint16_t kMaxFileDesignatorLen = 0xFF;
inline constexpr char kProtocolName[] = "BDX";
enum class MessageType : uint8_t
{
SendInit = 0x01,
SendAccept = 0x02,
ReceiveInit = 0x04,
ReceiveAccept = 0x05,
BlockQuery = 0x10,
Block = 0x11,
BlockEOF = 0x12,
BlockAck = 0x13,
BlockAckEOF = 0x14,
BlockQueryWithSkip = 0x15,
};
enum class TransferControlFlags : uint8_t
{
// first 4 bits reserved for version
kSenderDrive = (1U << 4),
kReceiverDrive = (1U << 5),
kAsync = (1U << 6),
};
enum class RangeControlFlags : uint8_t
{
kDefLen = (1U),
kStartOffset = (1U << 1),
kWiderange = (1U << 4),
};
/**
* @brief
* Interface for defining methods that apply to all BDX messages.
*/
struct BdxMessage
{
/**
* @brief
* Parse data from an PacketBuffer into a BdxMessage struct.
*
* Note that this may store pointers that point into the passed PacketBuffer,
* so it is essential that the underlying PacketBuffer is not modified until after this
* struct is no longer needed.
*
* @param[in] aBuffer A PacketBufferHandle with a reference to the PacketBuffer containing the data.
*
* @return CHIP_ERROR Return an error if the message format is invalid and/or can't be parsed
*/
CHECK_RETURN_VALUE
virtual CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) = 0;
/**
* @brief
* Write the message fields to a buffer using the provided BufferWriter.
*
* It is up to the caller to use BufferWriter::Fit() to verify that the write was
* successful. This method will also not check for correctness or completeness for
* any of the fields - it is the caller's responsibility to ensure that the fields
* align with BDX specifications.
*
* @param aBuffer A BufferWriter object that will be used to write the message
*/
virtual Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const = 0;
/**
* @brief
* Returns the size of buffer needed to write the message.
*/
virtual size_t MessageSize() const = 0;
#if CHIP_AUTOMATION_LOGGING
/**
* @brief
* Log all parameters for this message.
*/
virtual void LogMessage(bdx::MessageType messageType) const = 0;
#endif // CHIP_AUTOMATION_LOGGING
virtual ~BdxMessage() = default;
};
/*
* A structure for representing a SendInit or ReceiveInit message (both contain
* identical parameters).
*/
struct TransferInit : public BdxMessage
{
bool operator==(const TransferInit &) const;
// Proposed Transfer Control (required)
BitFlags<TransferControlFlags> TransferCtlOptions;
uint8_t Version = 0; ///< The highest version supported by the sender
// Range Control
BitFlags<RangeControlFlags> mRangeCtlFlags;
// All required
uint16_t MaxBlockSize = 0; ///< Proposed max block size to use in transfer
uint64_t StartOffset = 0; ///< Proposed start offset of data. 0 for no offset
uint64_t MaxLength = 0; ///< Proposed max length of data in transfer, 0 for indefinite
// File designator (required) and additional metadata (optional, TLV format)
// WARNING: there is no guarantee at any point that these pointers will point to valid memory. The Buffer field should be used
// to hold a reference to the PacketBuffer containing the data in order to ensure the data is not freed.
const uint8_t * FileDesignator = nullptr;
uint16_t FileDesLength = 0; ///< Length of file designator string (not including null-terminator)
const uint8_t * Metadata = nullptr;
size_t MetadataLength = 0;
// Retain ownership of the packet buffer so that the FileDesignator and Metadata pointers remain valid.
System::PacketBufferHandle Buffer;
CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) override;
Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const override;
size_t MessageSize() const override;
#if CHIP_AUTOMATION_LOGGING
void LogMessage(bdx::MessageType messageType) const override;
#endif // CHIP_AUTOMATION_LOGGING
};
using SendInit = TransferInit;
using ReceiveInit = TransferInit;
/*
* A structure for representing a SendAccept message.
*/
struct SendAccept : public BdxMessage
{
bool operator==(const SendAccept &) const;
// Transfer Control (required, only one should be set)
BitFlags<TransferControlFlags> TransferCtlFlags;
uint8_t Version = 0; ///< The agreed upon version for the transfer (required)
uint16_t MaxBlockSize = 0; ///< Chosen max block size to use in transfer (required)
// Additional metadata (optional, TLV format)
// WARNING: there is no guarantee at any point that this pointer will point to valid memory. The Buffer field should be used to
// hold a reference to the PacketBuffer containing the data in order to ensure the data is not freed.
const uint8_t * Metadata = nullptr;
size_t MetadataLength = 0;
// Retain ownership of the packet buffer so that the FileDesignator and Metadata pointers remain valid.
System::PacketBufferHandle Buffer;
CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) override;
Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const override;
size_t MessageSize() const override;
#if CHIP_AUTOMATION_LOGGING
void LogMessage(bdx::MessageType messageType) const override;
#endif // CHIP_AUTOMATION_LOGGING
};
/**
* A structure for representing ReceiveAccept messages.
*/
struct ReceiveAccept : public BdxMessage
{
bool operator==(const ReceiveAccept &) const;
// Transfer Control (required, only one should be set)
BitFlags<TransferControlFlags> TransferCtlFlags;
// Range Control
BitFlags<RangeControlFlags> mRangeCtlFlags;
// All required
uint8_t Version = 0; ///< The agreed upon version for the transfer
uint16_t MaxBlockSize = 0; ///< Chosen max block size to use in transfer
uint64_t StartOffset = 0; ///< Chosen start offset of data. 0 for no offset.
uint64_t Length = 0; ///< Length of transfer. 0 if length is indefinite.
// Additional metadata (optional, TLV format)
// WARNING: there is no guarantee at any point that this pointer will point to valid memory. The Buffer field should be used to
// hold a reference to the PacketBuffer containing the data in order to ensure the data is not freed.
const uint8_t * Metadata = nullptr;
size_t MetadataLength = 0;
// Retain ownership of the packet buffer so that the FileDesignator and Metadata pointers remain valid.
System::PacketBufferHandle Buffer;
CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) override;
Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const override;
size_t MessageSize() const override;
#if CHIP_AUTOMATION_LOGGING
void LogMessage(bdx::MessageType messageType) const override;
#endif // CHIP_AUTOMATION_LOGGING
};
/**
* A struct for representing messages contiaining just a counter field. Can be used to
* represent BlockQuery, BlockAck, and BlockAckEOF.
*/
struct CounterMessage : public BdxMessage
{
bool operator==(const CounterMessage &) const;
uint32_t BlockCounter = 0;
CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) override;
Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const override;
size_t MessageSize() const override;
#if CHIP_AUTOMATION_LOGGING
void LogMessage(bdx::MessageType messageType) const override;
#endif // CHIP_AUTOMATION_LOGGING
};
using BlockQuery = CounterMessage;
using BlockAck = CounterMessage;
using BlockAckEOF = CounterMessage;
/**
* A struct that represents a message containing actual data (Block, BlockEOF).
*/
struct DataBlock : public BdxMessage
{
bool operator==(const DataBlock &) const;
uint32_t BlockCounter = 0;
// WARNING: there is no guarantee at any point that this pointer will point to valid memory. The Buffer field should be used to
// hold a reference to the PacketBuffer containing the data in order to ensure the data is not freed.
const uint8_t * Data = nullptr;
size_t DataLength = 0;
// Retain ownership of the packet buffer so that the FileDesignator and Metadata pointers remain valid.
System::PacketBufferHandle Buffer;
CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) override;
Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const override;
size_t MessageSize() const override;
#if CHIP_AUTOMATION_LOGGING
void LogMessage(bdx::MessageType messageType) const override;
#endif // CHIP_AUTOMATION_LOGGING
};
using Block = DataBlock;
using BlockEOF = DataBlock;
struct BlockQueryWithSkip : public BdxMessage
{
bool operator==(const BlockQueryWithSkip &) const;
uint32_t BlockCounter = 0;
uint64_t BytesToSkip = 0;
CHIP_ERROR Parse(System::PacketBufferHandle aBuffer) override;
Encoding::LittleEndian::BufferWriter & WriteToBuffer(Encoding::LittleEndian::BufferWriter & aBuffer) const override;
size_t MessageSize() const override;
#if CHIP_AUTOMATION_LOGGING
void LogMessage(bdx::MessageType messageType) const override;
#endif // CHIP_AUTOMATION_LOGGING
};
} // namespace bdx
namespace Protocols {
template <>
struct MessageTypeTraits<bdx::MessageType>
{
static constexpr const Protocols::Id & ProtocolId() { return BDX::Id; }
static auto GetTypeToNameTable()
{
static const std::array<MessageTypeNameLookup, 10> typeToNameTable = {
{
{ bdx::MessageType::SendInit, "SendInit" },
{ bdx::MessageType::SendAccept, "SendAccept" },
{ bdx::MessageType::ReceiveInit, "ReceiveInit" },
{ bdx::MessageType::ReceiveAccept, "ReceiveAccept" },
{ bdx::MessageType::BlockQuery, "BlockQuery" },
{ bdx::MessageType::Block, "Block" },
{ bdx::MessageType::BlockEOF, "BlockEOF" },
{ bdx::MessageType::BlockAck, "BlockAck" },
{ bdx::MessageType::BlockAckEOF, "BlockAckEOF" },
{ bdx::MessageType::BlockQueryWithSkip, "BlockQueryWithSkip" },
},
};
return &typeToNameTable;
}
};
} // namespace Protocols
} // namespace chip