diff options
author | Xo Wang <xow@google.com> | 2017-08-09 15:34:16 -0700 |
---|---|---|
committer | Patrick Venture <venture@google.com> | 2018-09-25 09:59:48 -0700 |
commit | f542e8b0ecedb54fd4e1fbd7a8c2a9f73098dcec (patch) | |
tree | 898a92a6c85cee75b28863bcaef3e5a80317e4d1 | |
parent | ba19c184dffca849007746ebb41e365bd6c60efe (diff) | |
download | phosphor-host-ipmid-f542e8b0ecedb54fd4e1fbd7a8c2a9f73098dcec.tar.gz phosphor-host-ipmid-f542e8b0ecedb54fd4e1fbd7a8c2a9f73098dcec.zip |
apphandler: Implement Get/Set System Info Parameter
Implement Get System Info Parameter using the parameter storage code to
back the string-type parameters. Supports up to 255 chunks (known as
"sets" in the spec) for those parameters. Currently, iterated reads by
chunk of a string parameter will repeatedly invoke that parameter's
callback, which can result in chunks being incoherent with each other if
the string changes between invocations. This is noted in a TODO comment.
Stub out Set System Info Parameter. Full implementation for that is
pending support for read-only flags in the parameter storage code.
Change-Id: If0a9d807725ccf1f1f62e931010024841575469c
Signed-off-by: Xo Wang <xow@google.com>
Signed-off-by: Patrick Venture <venture@google.com>
-rw-r--r-- | apphandler.cpp | 184 | ||||
-rw-r--r-- | apphandler.h | 15 | ||||
-rw-r--r-- | host-ipmid/ipmid-api.h | 2 |
3 files changed, 193 insertions, 8 deletions
diff --git a/apphandler.cpp b/apphandler.cpp index 3abac14..7f16b1f 100644 --- a/apphandler.cpp +++ b/apphandler.cpp @@ -1,5 +1,14 @@ #include "apphandler.h" +#include "app/channel.hpp" +#include "app/watchdog.hpp" +#include "ipmid.hpp" +#include "nlohmann/json.hpp" +#include "sys_info_param.hpp" +#include "transporthandler.hpp" +#include "types.hpp" +#include "utils.hpp" + #include <arpa/inet.h> #include <mapper.h> #include <stdint.h> @@ -21,20 +30,15 @@ namespace filesystem = std::experimental::filesystem; #error filesystem not available #endif -#include "app/channel.hpp" -#include "app/watchdog.hpp" -#include "ipmid.hpp" -#include "nlohmann/json.hpp" -#include "transporthandler.hpp" -#include "types.hpp" -#include "utils.hpp" - +#include <algorithm> #include <array> #include <cstddef> #include <fstream> +#include <memory> #include <phosphor-logging/elog-errors.hpp> #include <phosphor-logging/log.hpp> #include <string> +#include <tuple> #include <vector> #include <xyz/openbmc_project/Common/error.hpp> #include <xyz/openbmc_project/Software/Activation/server.hpp> @@ -629,6 +633,166 @@ ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, return rc; } +static std::unique_ptr<SysInfoParamStore> sysInfoParamStore; + +struct IpmiSysInfoResp +{ + uint8_t paramRevision; + uint8_t setSelector; + union + { + struct + { + uint8_t encoding; + uint8_t stringLen; + uint8_t stringData0[14]; + } __attribute__((packed)); + uint8_t stringDataN[16]; + uint8_t byteData; + }; +} __attribute__((packed)); + +/** + * Split a string into (up to) 16-byte chunks as expected in response for get + * system info parameter. + * + * @param[in] fullString: Input string to be split + * @param[in] chunkIndex: Index of the chunk to be written out + * @param[in,out] chunk: Output data buffer; must have 14 byte capacity if + * chunk_index = 0 and 16-byte capacity otherwise + * @return the number of bytes written into the output buffer, or -EINVAL for + * invalid arguments. + */ +static int splitStringParam(const std::string& fullString, int chunkIndex, + uint8_t* chunk) +{ + constexpr int maxChunk = 255; + constexpr int smallChunk = 14; + constexpr int chunkSize = 16; + if (chunkIndex > maxChunk || chunk == nullptr) + { + return -EINVAL; + } + try + { + std::string output; + if (chunkIndex == 0) + { + // Output must have 14 byte capacity. + output = fullString.substr(0, smallChunk); + } + else + { + // Output must have 16 byte capacity. + output = fullString.substr((chunkIndex * chunkSize) - 2, chunkSize); + } + + std::memcpy(chunk, output.c_str(), output.length()); + return output.length(); + } + catch (const std::out_of_range& e) + { + // The position was beyond the end. + return -EINVAL; + } +} + +/** + * Packs the Get Sys Info Request Item into the response. + * + * @param[in] paramString - the parameter. + * @param[in] setSelector - the selector + * @param[in,out] resp - the System info response. + * @return The number of bytes packed or failure from splitStringParam(). + */ +static int packGetSysInfoResp(const std::string& paramString, + uint8_t setSelector, IpmiSysInfoResp* resp) +{ + uint8_t* dataBuffer = resp->stringDataN; + resp->setSelector = setSelector; + if (resp->setSelector == 0) // First chunk has only 14 bytes. + { + resp->encoding = 0; + resp->stringLen = paramString.length(); + dataBuffer = resp->stringData0; + } + return splitStringParam(paramString, resp->setSelector, dataBuffer); +} + +ipmi_ret_t ipmi_app_get_system_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, + ipmi_request_t request, + ipmi_response_t response, + ipmi_data_len_t dataLen, + ipmi_context_t context) +{ + IpmiSysInfoResp resp = {}; + size_t respLen = 0; + uint8_t* const reqData = static_cast<uint8_t*>(request); + std::string paramString; + bool found; + std::tuple<bool, std::string> ret; + constexpr int minRequestSize = 4; + constexpr int paramSelector = 1; + constexpr uint8_t revisionOnly = 0x80; + const uint8_t paramRequested = reqData[paramSelector]; + int rc; + + if (*dataLen < minRequestSize) + { + return IPMI_CC_REQ_DATA_LEN_INVALID; + } + + *dataLen = 0; // default to 0. + + // Parameters revision as of IPMI spec v2.0 rev. 1.1 (Feb 11, 2014 E6) + resp.paramRevision = 0x11; + if (reqData[0] & revisionOnly) // Get parameter revision only + { + respLen = 1; + goto writeResponse; + } + + // The "Set In Progress" parameter can be used for rollback of parameter + // data and is not implemented. + if (paramRequested == 0) + { + resp.byteData = 0; + respLen = 2; + goto writeResponse; + } + + if (sysInfoParamStore == nullptr) + { + sysInfoParamStore = std::make_unique<SysInfoParamStore>(); + } + + // Parameters other than Set In Progress are assumed to be strings. + ret = sysInfoParamStore->lookup(paramRequested); + found = std::get<0>(ret); + paramString = std::get<1>(ret); + if (!found) + { + return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED; + } + // TODO: Cache each parameter across multiple calls, until the whole string + // has been read out. Otherwise, it's possible for a parameter to change + // between requests for its chunks, returning chunks incoherent with each + // other. For now, the parameter store is simply required to have only + // idempotent callbacks. + rc = packGetSysInfoResp(paramString, reqData[2], &resp); + if (rc == -EINVAL) + { + return IPMI_CC_RESPONSE_ERROR; + } + + respLen = sizeof(resp); // Write entire string data chunk in response. + +writeResponse: + std::memcpy(response, &resp, sizeof(resp)); + *dataLen = respLen; + return IPMI_CC_OK; +} + void register_netfn_app_functions() { // <Get BT Interface Capabilities> @@ -686,5 +850,9 @@ void register_netfn_app_functions() // <Set Channel Access Command> ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL, ipmi_set_channel_access, PRIVILEGE_ADMIN); + + // <Get System Info Command> + ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYSTEM_INFO, NULL, + ipmi_app_get_system_info, PRIVILEGE_USER); return; } diff --git a/apphandler.h b/apphandler.h index db2d07c..cbfafb2 100644 --- a/apphandler.h +++ b/apphandler.h @@ -20,6 +20,21 @@ enum ipmi_netfn_app_cmds IPMI_CMD_GET_CHANNEL_ACCESS = 0x41, IPMI_CMD_GET_CHAN_INFO = 0x42, IPMI_CMD_GET_CHAN_CIPHER_SUITES = 0x54, + IPMI_CMD_SET_SYSTEM_INFO = 0x58, + IPMI_CMD_GET_SYSTEM_INFO = 0x59, +}; + +enum ipmi_app_sysinfo_params +{ + IPMI_SYSINFO_SET_STATE = 0x00, + IPMI_SYSINFO_SYSTEM_FW_VERSION = 0x01, + IPMI_SYSINFO_SYSTEM_NAME = 0x02, + IPMI_SYSINFO_PRIMARY_OS_NAME = 0x03, + IPMI_SYSINFO_OS_NAME = 0x04, + IPMI_SYSINFO_OS_VERSION = 0x05, + IPMI_SYSINFO_BMC_URL = 0x06, + IPMI_SYSINFO_OS_HYP_URL = 0x07, + IPMI_SYSINFO_OEM_START = 0xC0, // Start of range of OEM parameters }; #endif diff --git a/host-ipmid/ipmid-api.h b/host-ipmid/ipmid-api.h index a085270..820776a 100644 --- a/host-ipmid/ipmid-api.h +++ b/host-ipmid/ipmid-api.h @@ -114,6 +114,8 @@ enum ipmi_return_codes IPMI_CC_OK = 0x00, IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT = 0x80, IPMI_WDOG_CC_NOT_INIT = 0x80, + IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED = 0x80, + IPMI_CC_SYSTEM_INFO_PARAMETER_SET_READ_ONLY = 0x82, IPMI_CC_BUSY = 0xC0, IPMI_CC_INVALID = 0xC1, IPMI_CC_INVALID_RESERVATION_ID = 0xC5, |