// 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 "bios_setting.hpp" #include "commands.hpp" #include "errors.hpp" #include "handler.hpp" #include #include #include #include #include #include #include #include #include #include #include namespace google { namespace ipmi { std::vector readBiosSettingFromFile(const std::string& biosSettingPath) { std::vector biosSettings; try { stdplus::ManagedFd managedFd = stdplus::fd::open( biosSettingPath, stdplus::fd::OpenFlags(stdplus::fd::OpenAccess::ReadOnly)); biosSettings = stdplus::fd::readAll>(managedFd); } catch (const std::exception& e) { stdplus::print(stderr, "Read unsuccessful: {}\n", e.what()); return {}; } return biosSettings; } Resp readBiosSetting(std::span, HandlerInterface*, const std::string& biosSettingPath) { std::vector biosSettings = readBiosSettingFromFile(biosSettingPath); size_t settingsLength = biosSettings.size(); if (settingsLength == 0) { return ::ipmi::responseRetBytesUnavailable(); } // Reply format is: Length of the payload (1 byte) + payload std::vector reply; reply.reserve(1 + settingsLength); reply.emplace_back(static_cast(settingsLength)); reply.insert(reply.end(), biosSettings.begin(), biosSettings.end()); return ::ipmi::responseSuccess(SysOEMCommands::SysReadBiosSetting, reply); } Resp writeBiosSetting(std::span data, HandlerInterface*, const std::string& biosSettingPath) { std::uint8_t payloadSize; try { // This subspans the data automatically payloadSize = stdplus::raw::extract< stdplus::EndianPacked>( data); } catch (const std::exception& e) { stdplus::print(stderr, "Extracting payload failed: {}\n", e.what()); return ::ipmi::responseReqDataLenInvalid(); } if (data.size() != payloadSize) { stdplus::print(stderr, "Invalid command length {} vs. payloadSize {}\n", static_cast(data.size()), static_cast(payloadSize)); return ::ipmi::responseReqDataLenInvalid(); } // Write the setting try { stdplus::ManagedFd managedFd = stdplus::fd::open( biosSettingPath, stdplus::fd::OpenFlags(stdplus::fd::OpenAccess::WriteOnly) .set(stdplus::fd::OpenFlag::Trunc) .set(stdplus::fd::OpenFlag::Create)); stdplus::fd::writeExact(managedFd, data); } catch (const std::exception& e) { stdplus::print(stderr, "Write unsuccessful: {}\n", e.what()); return ::ipmi::responseRetBytesUnavailable(); } // Reply format is: Length of the payload written std::vector reply; reply.reserve(1); reply.emplace_back(static_cast(payloadSize)); return ::ipmi::responseSuccess(SysOEMCommands::SysWriteBiosSetting, reply); } } // namespace ipmi } // namespace google