summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorXo Wang <xow@google.com>2017-08-09 15:34:16 -0700
committerPatrick Venture <venture@google.com>2018-09-25 09:59:48 -0700
commitf542e8b0ecedb54fd4e1fbd7a8c2a9f73098dcec (patch)
tree898a92a6c85cee75b28863bcaef3e5a80317e4d1
parentba19c184dffca849007746ebb41e365bd6c60efe (diff)
downloadphosphor-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.cpp184
-rw-r--r--apphandler.h15
-rw-r--r--host-ipmid/ipmid-api.h2
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,
OpenPOWER on IntegriCloud