Add a class to handle RDE commands
This class is used to process RDE packets received from BIOS-BMC
circular buffer. RdeCommandHandler will manage dictionary data,
decode RDE BEJ encoded payloads and push them to the ExternalStorer.
Tested:
Tested this with unit tests.
Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Ic66e4e4e2afa523906835713d36015457f324fcc
diff --git a/include/rde/rde_handler.hpp b/include/rde/rde_handler.hpp
new file mode 100644
index 0000000..65e9361
--- /dev/null
+++ b/include/rde/rde_handler.hpp
@@ -0,0 +1,219 @@
+#pragma once
+
+#include "bej_decoder_json.hpp"
+#include "external_storer_interface.hpp"
+#include "rde_dictionary_manager.hpp"
+
+#include <cstdint>
+#include <span>
+#include <string_view>
+
+namespace bios_bmc_smm_error_logger
+{
+namespace rde
+{
+
+/**
+ * @brief Supported RDE commands.
+ *
+ * The values used are the same as what BIOS uses.
+ */
+enum class RdeCommandType : char
+{
+ // Used for RDE BEJ dictionary transfer.
+ RdeMultiPartReceiveResponse = 1,
+ // Used for RDE BEJ encoded data.
+ RdeOperationInitRequest = 2,
+};
+
+/**
+ * @brief Used to keep track of RdeMultiPartReceiveResponse START flag
+ * reception.
+ */
+enum class RdeDictTransferFlagState
+{
+ RdeStateIdle,
+ RdeStateStartRecvd,
+};
+
+/**
+ * @brief Status of RDE command processing.
+ */
+enum class RdeDecodeStatus
+{
+ RdeOk,
+ RdeInvalidCommand,
+ RdeUnsupportedOperation,
+ RdeNoDictionary,
+ RdePayloadOverflow,
+ RdeBejDecodingError,
+ RdeInvalidPktOrder,
+ RdeDictionaryError,
+ RdeFileCreationFailed,
+ RdeExternalStorerError,
+ // This implies that the stop flag has been received.
+ RdeInvalidChecksum,
+ // This implies that the checksum is correct.
+ RdeStopFlagReceived,
+};
+
+/**
+ * @brief Handles RDE messages from the BIOS - BMC circular buffer and updates
+ * ExternalStorer.
+ */
+class RdeCommandHandler
+{
+ public:
+ /**
+ * @brief Constructor for RdeExternalStorer.
+ *
+ * @param[in] exStorer - valid ExternalStorerInterface. This class will take
+ * the ownership of this object.
+ */
+ explicit RdeCommandHandler(
+ std::unique_ptr<ExternalStorerInterface> exStorer);
+
+ /**
+ * @brief Decode a RDE command.
+ *
+ * @param[in] rdeCommand - RDE command.
+ * @param[in] type - RDE command type.
+ * @return RdeDecodeStatus code.
+ */
+ RdeDecodeStatus decodeRdeCommand(std::span<const uint8_t> rdeCommand,
+ RdeCommandType type);
+
+ /**
+ * @brief Get the number of complete dictionaries received.
+ *
+ * @return number of complete dictionaries.
+ */
+ uint32_t getDictionaryCount();
+
+ private:
+ /**
+ * @brief This keeps track of whether we received the dictionary start flag
+ * or not.
+ */
+ RdeDictTransferFlagState flagState;
+
+ std::unique_ptr<ExternalStorerInterface> exStorer;
+
+ /**
+ * @brief We are using the prevDictResourceId to detect a new dictionary.
+ *
+ * BIOS-BMC buffer uses RdeMultiPartReceiveResponse START flag to indicate
+ * the first dictionary data chunk. BMC will not receive this flag at start
+ * of every new dictionary but only for the first data chunk. Therefore
+ * difference between resource ID is used to identify a new dictionary
+ * start. prevDictResourceId keeps track of the resource ID of the last
+ * dictionary data chunk.
+ */
+ uint32_t prevDictResourceId;
+
+ DictionaryManager dictionaryManager;
+ libbej::BejDecoderJson decoder;
+
+ uint32_t crc;
+ std::array<uint32_t, UINT8_MAX + 1> crcTable;
+
+ /**
+ * @brief Handles OperationInit request messages.
+ *
+ * @param[in] rdeCommand - RDE command.
+ * @return RdeDecodeStatus
+ */
+ RdeDecodeStatus operationInitRequest(std::span<const uint8_t> rdeCommand);
+
+ /**
+ * @brief Handles MultiPartReceive response messages.
+ *
+ * @param[in] rdeCommand - RDE command.
+ * @return RdeDecodeStatus
+ */
+ RdeDecodeStatus multiPartReceiveResp(std::span<const uint8_t> rdeCommand);
+
+ /**
+ * @brief Initializes the CRC table.
+ */
+ void calcCrcTable();
+
+ /**
+ * @brief Update the existing CRC using the provided byte stream.
+ *
+ * According to the RDE BEJ specification: "32-bit CRC for the entire block
+ * of data (all parts concatenated together, excluding this checksum)".
+ * Therefore when calculating the CRC whole RDEMultipartReceive Response
+ * data packet is considered, not just the dictionary data contained within
+ * it.
+ *
+ * @param[in] stream - a byte stream.
+ */
+ void updateCrc(std::span<const uint8_t> stream);
+
+ /**
+ * @brief Get the final checksum value.
+ *
+ * @return uint32_t - final checksum value.
+ */
+ uint32_t finalChecksum();
+
+ /**
+ * @brief Process received CRC field from a multi receive response command.
+ * END or START_AND_END flag should be set in the command.
+ *
+ * @param multiReceiveRespCmd - payload with a checksum field populated.
+ * @return RdeDecodeStatus
+ */
+ RdeDecodeStatus handleCrc(std::span<const uint8_t> multiReceiveRespCmd);
+
+ /**
+ * @brief Handle dictionary data with flag Start.
+ *
+ * @param[in] header - RDE header portion of the RDE command.
+ * @param[in] data - data portion of the RDE command.
+ * @param[in] resourceId - PDR resource ID of the dictionary.
+ */
+ void handleFlagStart(const MultipartReceiveResHeader* header,
+ const uint8_t* data, uint32_t resourceId);
+
+ /**
+ * @brief Handle dictionary data with flag Middle.
+ *
+ * @param[in] header - RDE header portion of the RDE command.
+ * @param[in] data - data portion of the RDE command.
+ * @param[in] resourceId - PDR resource ID of the dictionary.
+ * @return RdeDecodeStatus
+ */
+ RdeDecodeStatus handleFlagMiddle(const MultipartReceiveResHeader* header,
+ const uint8_t* data, uint32_t resourceId);
+ /**
+ * @brief Handle dictionary data with flag End.
+ *
+ * @param[in] rdeCommand - RDE command.
+ * @param[in] header - RDE header portion of the RDE command.
+ * @param[in] data - data portion of the RDE command.
+ * @param[in] resourceId - PDR resource ID of the dictionary.
+ * @return RdeDecodeStatus
+ */
+ RdeDecodeStatus handleFlagEnd(std::span<const uint8_t> rdeCommand,
+ const MultipartReceiveResHeader* header,
+ const uint8_t* data, uint32_t resourceId);
+
+ /**
+ * @brief Handle dictionary data with flag StartAndEnd.
+ *
+ * @param[in] rdeCommand - RDE command.
+ * @param[in] header - RDE header portion of the RDE command.
+ * @param[in] data - data portion of the RDE command.
+ * @param[in] resourceId - PDR resource ID of the dictionary.
+ * @return RdeDecodeStatus
+ */
+ RdeDecodeStatus
+ handleFlagStartAndEnd(std::span<const uint8_t> rdeCommand,
+ const MultipartReceiveResHeader* header,
+ const uint8_t* data, uint32_t resourceId);
+};
+
+} // namespace rde
+} // namespace bios_bmc_smm_error_logger