| // Copyright 2024 Google LLC |
| // |
| // 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. |
| |
| #include "message_util.hpp" |
| |
| #include <stdplus/print.hpp> |
| #include <stdplus/raw.hpp> |
| #include <xyz/openbmc_project/Control/Hoth/error.hpp> |
| |
| #include <cstring> |
| #include <span> |
| |
| namespace google |
| { |
| namespace hoth |
| { |
| namespace internal |
| { |
| |
| using sdbusplus::error::xyz::openbmc_project::control::hoth::CommandFailure; |
| using sdbusplus::error::xyz::openbmc_project::control::hoth::ResponseFailure; |
| |
| void populateReqHeader(uint16_t command, uint8_t command_version, |
| const void* request, size_t request_size, |
| ReqHeader* request_header) |
| { |
| if (!request_header) |
| { |
| stdplus::print(stderr, "Request header argument cannot be NULL\n"); |
| throw CommandFailure(); |
| } |
| |
| if (request_size > 0 && !request) |
| { |
| stdplus::print(stderr, |
| "Request data argument cannot be NULL with size > 0\n"); |
| throw CommandFailure(); |
| } |
| |
| if (request_size > UINT16_MAX) |
| { |
| stdplus::print(stderr, |
| "Error, request_size({}) bigger than UINT16_MAX\n", |
| request_size); |
| throw CommandFailure(); |
| } |
| |
| request_header->struct_version = SUPPORTED_STRUCT_VERSION; |
| request_header->checksum = 0; |
| request_header->command = command; |
| request_header->command_version = command_version; |
| request_header->reserved = 0; |
| request_header->data_len = static_cast<uint16_t>(request_size); |
| // Note that we've set |checksum| to zero earlier, so this is deterministic. |
| request_header->checksum -= calculateChecksum( |
| stdplus::raw::asSpan<uint8_t>(*request_header), |
| std::span<const uint8_t>(reinterpret_cast<const uint8_t*>(request), |
| request_size)); |
| } |
| |
| size_t reqLen(const std::vector<uint8_t>& req) |
| { |
| struct ReqHeader header; |
| |
| if (req.size() < sizeof(header)) |
| { |
| stdplus::print(stderr, "Command is too short: `{} < {}`\n", req.size(), |
| sizeof(header)); |
| throw CommandFailure(); |
| } |
| |
| std::memcpy(&header, req.data(), sizeof(header)); |
| |
| if (header.struct_version != SUPPORTED_STRUCT_VERSION) |
| { |
| stdplus::print(stderr, "Unsupported struct_version in command {}\n", |
| static_cast<uint16_t>(header.struct_version)); |
| throw CommandFailure(); |
| } |
| |
| return sizeof(header) + header.data_len; |
| } |
| |
| size_t rspLen(const std::vector<uint8_t>& rsp) |
| { |
| struct RspHeader header; |
| |
| if (rsp.size() < sizeof(header)) |
| { |
| stdplus::print(stderr, "Response is too short `{} < {}`\n", rsp.size(), |
| sizeof(header)); |
| throw ResponseFailure(); |
| } |
| |
| std::memcpy(&header, rsp.data(), sizeof(header)); |
| |
| if (header.struct_version != SUPPORTED_STRUCT_VERSION) |
| { |
| stdplus::print(stderr, "Unsupported struct_version in response {}\n", |
| static_cast<uint16_t>(header.struct_version)); |
| throw ResponseFailure(); |
| } |
| |
| return sizeof(header) + header.data_len; |
| } |
| |
| std::vector<uint8_t> generateErrorResponse(uint8_t error) |
| { |
| RspHeader rsp = {}; |
| rsp.struct_version = SUPPORTED_STRUCT_VERSION; |
| rsp.result = error; |
| rsp.checksum -= calculateChecksum(stdplus::raw::asSpan<uint8_t>(rsp)); |
| std::vector<uint8_t> ret; |
| ret.resize(sizeof(rsp)); |
| std::memcpy(ret.data(), &rsp, sizeof(rsp)); |
| return ret; |
| } |
| |
| } // namespace internal |
| |
| } // namespace hoth |
| |
| } // namespace google |