| /* |
| // Copyright (c) 2018 Intel Corporation |
| // |
| // 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 <errno.h> |
| #include <ipmid/api.h> |
| |
| #include <commandutils.hpp> |
| #include <cstdint> |
| #include <ipmid/utils.hpp> |
| #include <phosphor-ipmi-host/ipmid.hpp> |
| #include <phosphor-logging/elog-errors.hpp> |
| #include <phosphor-logging/log.hpp> |
| #include <sdbusplus/bus.hpp> |
| #include <smbiosmdrv2.hpp> |
| #include <string> |
| #include <vector> |
| #include <xyz/openbmc_project/Common/error.hpp> |
| |
| constexpr const char* DBUS_PROPERTIES = "org.freedesktop.DBus.Properties"; |
| constexpr const char* MDRV2_PATH = "/xyz/openbmc_project/Smbios/MDR_V2"; |
| constexpr const char* MDRV2_INTERFACE = "xyz.openbmc_project.Smbios.MDR_V2"; |
| constexpr const int LAST_AGENT_INDEX = -1; |
| constexpr const uint16_t LAST_AGENT_ID = 0xFFFF; |
| |
| static void register_netfn_smbiosmdrv2_functions() __attribute__((constructor)); |
| static sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); |
| |
| int agentLookup(const uint16_t& agentId, const std::string& service) |
| { |
| int agentIndex = -1; |
| |
| if (LAST_AGENT_ID == agentId) |
| { |
| return LAST_AGENT_INDEX; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "AgentLookup"); |
| method.append(agentId); |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error get agent index, sdbusplus call failed"); |
| return -1; |
| } |
| reply.read(agentIndex); |
| |
| return agentIndex; |
| } |
| |
| int findLockHandle(const uint16_t& lockHandle, const std::string& service) |
| { |
| int idIndex = -1; |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "FindLockHandle"); |
| method.append(lockHandle); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error find lock handle", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return -1; |
| } |
| reply.read(idIndex); |
| |
| return idIndex; |
| } |
| |
| int sdplusMdrv2GetProperty(const std::string& name, |
| sdbusplus::message::variant<uint8_t>& value, |
| const std::string& service) |
| { |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, DBUS_PROPERTIES, "Get"); |
| method.append(MDRV2_INTERFACE, name); |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error get property, sdbusplus call failed"); |
| return -1; |
| } |
| reply.read(value); |
| |
| return 0; |
| } |
| |
| int findDataId(const uint8_t* dataInfo, const size_t& len, |
| const std::string& service) |
| { |
| int idIndex = -1; |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "FindIdIndex"); |
| std::vector<uint8_t> info; |
| for (int index = 0; index < len; index++) |
| { |
| info.push_back(dataInfo[index]); |
| } |
| method.append(info); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error find id index", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return -1; |
| } |
| reply.read(idIndex); |
| |
| return idIndex; |
| } |
| |
| ipmi_ret_t cmd_mdr2_agent_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, |
| ipmi_response_t response, |
| ipmi_data_len_t data_len, |
| ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiGetAgentStatus*>(request); |
| auto dataOut = reinterpret_cast<uint8_t*>(response); |
| std::vector<uint8_t> status; |
| |
| if (*data_len != sizeof(MDRiiGetAgentStatus)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "AgentStatus"); |
| method.append(requestData->dirVersion); |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error get agent status", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(status); |
| |
| if (status.size() != sizeof(MDRiiAgentStatusResponse)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Get agent status response length not valid"); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| *data_len = static_cast<size_t>(status.size()); |
| std::copy(&status[0], &status[*data_len], dataOut); |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_get_dir(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, ipmi_response_t response, |
| ipmi_data_len_t data_len, ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiGetDirRequest*>(request); |
| auto dataOut = reinterpret_cast<uint8_t*>(response); |
| std::vector<uint8_t> dirInfo; |
| |
| if (*data_len != sizeof(MDRiiGetDirRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::variant<uint8_t> value = 0; |
| if (0 != sdplusMdrv2GetProperty("DirEntries", value, service)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error getting DirEnries"); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| if (requestData->dirIndex > |
| sdbusplus::message::variant_ns::get<uint8_t>(value)) |
| { |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDir"); |
| |
| method.append(requestData->dirIndex); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error get dir", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(dirInfo); |
| |
| if (dirInfo.size() < sizeof(MDRiiGetDirResponse)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error get dir, response length invalid"); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| |
| auto responseData = reinterpret_cast<MDRiiGetDirResponse*>(dirInfo.data()); |
| |
| *data_len = dirInfo.size(); |
| |
| if (*data_len > MAX_IPMI_BUFFER) // length + completion code should no more |
| // than MAX_IPMI_BUFFER |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Data length send from service is invalid"); |
| *data_len = 0; |
| return IPMI_CC_RESPONSE_ERROR; |
| } |
| |
| std::copy(&dirInfo[0], &dirInfo[*data_len], dataOut); |
| |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_get_data_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, |
| ipmi_response_t response, |
| ipmi_data_len_t data_len, |
| ipmi_context_t context) |
| { |
| auto requestData = |
| reinterpret_cast<const MDRiiGetDataInfoRequest*>(request); |
| auto dataOut = reinterpret_cast<uint8_t*>(response); |
| std::vector<uint8_t> res; |
| |
| if (*data_len < sizeof(MDRiiGetDataInfoRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = |
| findDataId(requestData->dataSetInfo.dataInfo, |
| sizeof(requestData->dataSetInfo.dataInfo), service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDataInfo"); |
| |
| method.append(idIndex); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error get data info", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(res); |
| |
| if (res.size() != sizeof(MDRiiGetDataInfoResponse)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Get data info response length not invalid"); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| *data_len = static_cast<size_t>(res.size()); |
| std::copy(&res[0], &res[*data_len], dataOut); |
| |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_lock_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, ipmi_response_t response, |
| ipmi_data_len_t data_len, ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiLockDataRequest*>(request); |
| auto responseData = reinterpret_cast<MDRiiLockDataResponse*>(response); |
| |
| std::tuple<bool, uint8_t, uint16_t, uint32_t, uint32_t, uint32_t> res; |
| |
| if (*data_len < sizeof(MDRiiLockDataRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = |
| findDataId(requestData->dataSetInfo.dataInfo, |
| sizeof(requestData->dataSetInfo.dataInfo), service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "LockData"); |
| |
| method.append((uint8_t)idIndex, requestData->timeout); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| if (reply.get_errno() == EBUSY) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Lock Data failed - cannot lock idIndex"); |
| return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE; |
| } |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error lock data", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(res); |
| |
| if (std::get<0>(res) == false) |
| { |
| return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE; |
| } |
| |
| *data_len = sizeof(MDRiiLockDataResponse); |
| |
| responseData->mdrVersion = std::get<1>(res); |
| responseData->lockHandle = std::get<2>(res); |
| responseData->dataLength = std::get<3>(res); |
| responseData->xferAddress = std::get<4>(res); |
| responseData->xferLength = std::get<5>(res); |
| |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_unlock_data(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, |
| ipmi_response_t response, |
| ipmi_data_len_t data_len, |
| ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiUnlockDataRequest*>(request); |
| std::string resStatus; |
| |
| if (*data_len != sizeof(MDRiiUnlockDataRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = findLockHandle(requestData->lockHandle, service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "UnLockData"); |
| method.append((uint8_t)idIndex); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| if (reply.get_errno() == EBUSY) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unlock Data failed - cannot unlock idIndex"); |
| return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE; |
| } |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error unlock data", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(resStatus); |
| |
| if (resStatus != "success") |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Agent unlock Invalid lock status."); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_get_data_block(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, |
| ipmi_response_t response, |
| ipmi_data_len_t data_len, |
| ipmi_context_t context) |
| { |
| auto requestData = |
| reinterpret_cast<const MDRiiGetDataBlockRequest*>(request); |
| auto responseData = reinterpret_cast<MDRiiGetDataBlockResponse*>(response); |
| std::tuple<uint8_t, uint32_t, uint32_t, std::vector<uint8_t>> res; |
| std::vector<uint8_t> resData; |
| uint8_t status = 1; |
| |
| if (*data_len != sizeof(MDRiiGetDataBlockRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = findLockHandle(requestData->lockHandle, service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDataBlock"); |
| method.append((uint8_t)idIndex, requestData->xferOffset, |
| requestData->xferLength); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error get data block", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(res); |
| |
| // Get the status of get data block, 0 means succeed |
| status = std::get<0>(res); |
| if (status == 1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Request data offset is outside of range."); |
| return IPMI_CC_CANNOT_RETURN_NUMBER_OF_REQUESTED_DATA_BYTES; |
| } |
| else if (status != 0) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Get data block unexpected error."); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| |
| responseData->xferLength = std::get<1>(res); |
| if (responseData->xferLength > requestData->xferLength) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Get data block unexpected error."); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| |
| responseData->checksum = std::get<2>(res); |
| |
| resData = std::get<3>(res); |
| |
| *data_len = sizeof(responseData->xferLength) + |
| sizeof(responseData->checksum) + resData.size(); |
| |
| if (*data_len > MAX_IPMI_BUFFER) // length + completion code should no more |
| // than MAX_IPMI_BUFFER |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Data length send from service is invalid"); |
| *data_len = 0; |
| return IPMI_CC_RESPONSE_ERROR; |
| } |
| |
| std::copy(resData.begin(), resData.end(), responseData->data); |
| |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_send_dir(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, ipmi_response_t response, |
| ipmi_data_len_t data_len, ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiSendDirRequest*>(request); |
| std::vector<uint8_t> idVector; |
| bool teminate = false; |
| |
| if (*data_len != sizeof(MDRiiSendDirRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| if ((requestData->dirIndex + requestData->returnedEntries) > maxDirEntries) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Too many directory entries"); |
| return IPMI_CC_STORGE_LEAK; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "SendDir"); |
| method.append(requestData->dirVersion, requestData->dirIndex, |
| requestData->returnedEntries, requestData->remainingEntries); |
| uint8_t* reqPoint; |
| for (int index = 0; index < requestData->returnedEntries; index++) |
| { |
| reqPoint = (uint8_t*)&(requestData->data[index]); |
| std::copy(reqPoint, sizeof(Mdr2DirEntry) + reqPoint, idVector.data()); |
| } |
| method.append(idVector); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error send dir", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(teminate); |
| |
| *data_len = 1; |
| if (teminate == false) |
| *(static_cast<uint8_t*>(response)) = 0; |
| else |
| *(static_cast<uint8_t*>(response)) = 1; |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_data_info_offer(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, |
| ipmi_response_t response, |
| ipmi_data_len_t data_len, |
| ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiOfferDataInfo*>(request); |
| auto dataOut = reinterpret_cast<uint8_t*>(response); |
| std::vector<uint8_t> dataInfo; |
| |
| if (*data_len != sizeof(MDRiiOfferDataInfo)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "GetDataOffer"); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| if (reply.get_errno() == EBUSY) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send data info offer failed - not available to update data " |
| "into agent at present"); |
| return IPMI_CC_PARAMETER_NOT_SUPPORT_IN_PRESENT_STATE; |
| } |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error send data info offer", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(dataInfo); |
| if (dataInfo.size() != sizeof(MDRiiOfferDataInfoResponse)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error send data info offer, return length invalid"); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| |
| *data_len = dataInfo.size(); |
| std::copy(dataInfo.begin(), dataInfo.end(), dataOut); |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_send_data_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, |
| ipmi_response_t response, |
| ipmi_data_len_t data_len, |
| ipmi_context_t context) |
| { |
| auto requestData = |
| reinterpret_cast<const MDRiiSendDataInfoRequest*>(request); |
| bool entryChanged = true; |
| |
| if (*data_len != sizeof(MDRiiSendDataInfoRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| if (requestData->dataLength > smbiosTableStorageSize) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Requested data length is out of SMBIOS Table storage size."); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = |
| findDataId(requestData->dataSetInfo.dataInfo, |
| sizeof(requestData->dataSetInfo.dataInfo), service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "SendDataInfo"); |
| |
| method.append((uint8_t)idIndex, requestData->validFlag, |
| requestData->dataLength, requestData->dataVersion, |
| requestData->timeStamp); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error send data info", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(entryChanged); |
| |
| *data_len = 1; |
| |
| if (entryChanged) |
| { |
| *(static_cast<uint8_t*>(response)) = 1; |
| } |
| else |
| { |
| *(static_cast<uint8_t*>(response)) = 0; |
| } |
| |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_data_start(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, ipmi_response_t response, |
| ipmi_data_len_t data_len, ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiDataStartRequest*>(request); |
| auto responseData = reinterpret_cast<MDRiiDataStartResponse*>(response); |
| std::vector<uint8_t> idVector; |
| |
| if (*data_len != sizeof(MDRiiDataStartRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| if (requestData->dataLength > smbiosTableStorageSize) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Requested data length is out of SMBIOS Table storage size."); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| if ((requestData->xferLength + requestData->xferAddress) > mdriiSMSize) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid data address and size"); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = |
| findDataId(requestData->dataSetInfo.dataInfo, |
| sizeof(requestData->dataSetInfo.dataInfo), service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "DataStart"); |
| |
| for (uint8_t infoIndex = 0; infoIndex < sizeof(DataIdStruct); infoIndex++) |
| { |
| idVector.push_back(requestData->dataSetInfo.dataInfo[infoIndex]); |
| } |
| method.append((uint8_t)idIndex, idVector, requestData->dataLength, |
| requestData->xferAddress, requestData->xferLength, |
| requestData->timeout); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| int errNumber = reply.get_errno(); |
| if (errNumber == ENOMEM) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send data start failed - cannot map share memory"); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| else if (errNumber == EINVAL) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid data address and size"); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| else |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error Send Data Start", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| } |
| uint8_t xferStartAck = 0; |
| uint16_t sessionHandle = 0; |
| reply.read(xferStartAck, sessionHandle); |
| responseData->sessionHandle = sessionHandle; |
| responseData->xferStartAck = xferStartAck; |
| if (responseData->xferStartAck == 0) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send data start unexpected error"); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| |
| *data_len = sizeof(MDRiiDataStartResponse); |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_data_done(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, ipmi_response_t response, |
| ipmi_data_len_t data_len, ipmi_context_t context) |
| { |
| auto requestData = reinterpret_cast<const MDRiiDataDoneRequest*>(request); |
| std::string resStatus; |
| |
| if (*data_len != sizeof(MDRiiDataDoneRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = findLockHandle(requestData->lockHandle, service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "DataDone"); |
| method.append((uint8_t)idIndex); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| if (reply.get_errno() == EBUSY) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send data done failed - cannot unlock idIndex"); |
| return IPMI_CC_DESTINATION_UNAVAILABLE; |
| } |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error Send Data done", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| reply.read(resStatus); |
| |
| if (resStatus != "success") |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Data done failure."); |
| return IPMI_CC_DESTINATION_UNAVAILABLE; |
| } |
| |
| return IPMI_CC_OK; |
| } |
| |
| ipmi_ret_t cmd_mdr2_send_data_block(ipmi_netfn_t netfn, ipmi_cmd_t cmd, |
| ipmi_request_t request, |
| ipmi_response_t response, |
| ipmi_data_len_t data_len, |
| ipmi_context_t context) |
| { |
| auto requestData = |
| reinterpret_cast<const MDRiiSendDataBlockRequest*>(request); |
| std::string resStatus; |
| |
| if (*data_len != sizeof(MDRiiSendDataBlockRequest)) |
| { |
| *data_len = 0; |
| return IPMI_CC_REQ_DATA_LEN_INVALID; |
| } |
| |
| *data_len = 0; |
| |
| std::string service = ipmi::getService(bus, MDRV2_INTERFACE, MDRV2_PATH); |
| |
| int agentIndex = agentLookup(requestData->agentId, service); |
| if (agentIndex == -1) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Unknown agent id", |
| phosphor::logging::entry("ID=%x", requestData->agentId)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| int idIndex = findLockHandle(requestData->lockHandle, service); |
| |
| if ((idIndex < 0) || (idIndex >= maxDirEntries)) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Invalid Data ID", phosphor::logging::entry("IDINDEX=%x", idIndex)); |
| return IPMI_CC_PARM_OUT_OF_RANGE; |
| } |
| |
| sdbusplus::message::message method = bus.new_method_call( |
| service.c_str(), MDRV2_PATH, MDRV2_INTERFACE, "SendDataBlock"); |
| method.append((uint8_t)idIndex, requestData->xferOffset, |
| requestData->xferLength, requestData->checksum); |
| |
| sdbusplus::message::message reply = bus.call(method); |
| if (reply.is_method_error()) |
| { |
| int errNumber = reply.get_errno(); |
| if (errNumber == EINVAL) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send data block Invalid checksum"); |
| return IPMI_CC_OEM_INVALID_CHECKSUM; |
| } |
| else if (errNumber == ENOBUFS) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send data block Invalid offset/length"); |
| return IPMI_CC_REQUEST_DATA_FIELD_LENGTH_LIMIT_EXCEEDED; |
| } |
| else if (errNumber == EBUSY) |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Send data block failed, other data is updating"); |
| return IPMI_CC_DESTINATION_UNAVAILABLE; |
| } |
| else |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "Error Send data block", |
| phosphor::logging::entry("SERVICE=%s", service.c_str()), |
| phosphor::logging::entry("PATH=%s", MDRV2_PATH)); |
| return IPMI_CC_UNSPECIFIED_ERROR; |
| } |
| } |
| reply.read(resStatus); |
| |
| if (resStatus != "success") |
| { |
| phosphor::logging::log<phosphor::logging::level::ERR>( |
| "send data block failure."); |
| return IPMI_CC_DESTINATION_UNAVAILABLE; |
| } |
| |
| return IPMI_CC_OK; |
| } |
| |
| static void register_netfn_smbiosmdrv2_functions(void) |
| { |
| // MDR V2 Command |
| // <Get MDRII Status Command> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_AGENT_STATUS, |
| NULL, cmd_mdr2_agent_status, PRIVILEGE_OPERATOR); |
| |
| // <Get MDRII Directory Command> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DIR, NULL, |
| cmd_mdr2_get_dir, PRIVILEGE_OPERATOR); |
| |
| // <Get MDRII Data Info Command> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DATA_INFO, |
| NULL, cmd_mdr2_get_data_info, PRIVILEGE_OPERATOR); |
| |
| // <Lock MDRII Data Command> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_LOCK_DATA, NULL, |
| cmd_mdr2_lock_data, PRIVILEGE_OPERATOR); |
| |
| // <Unlock MDRII Data Command> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_UNLOCK_DATA, |
| NULL, cmd_mdr2_unlock_data, PRIVILEGE_OPERATOR); |
| |
| // <Get MDRII Data Block Command> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_GET_DATA_BLOCK, |
| NULL, cmd_mdr2_get_data_block, PRIVILEGE_OPERATOR); |
| |
| // <Send MDRII Directory Command> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DIR, NULL, |
| cmd_mdr2_send_dir, PRIVILEGE_OPERATOR); |
| |
| // <Send MDRII Info Offer> |
| ipmi_register_callback( |
| NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_INFO_OFFER, NULL, |
| cmd_mdr2_data_info_offer, PRIVILEGE_OPERATOR); |
| |
| // <Send MDRII Data Info> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_INFO, |
| NULL, cmd_mdr2_send_data_info, PRIVILEGE_OPERATOR); |
| |
| // <Send MDRII Data Start> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_DATA_START, NULL, |
| cmd_mdr2_data_start, PRIVILEGE_OPERATOR); |
| |
| // <Send MDRII Data Done> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_DATA_DONE, NULL, |
| cmd_mdr2_data_done, PRIVILEGE_OPERATOR); |
| |
| // <Send MDRII Data Block> |
| ipmi_register_callback(NETFUN_INTEL_APP_OEM, |
| IPMI_NETFN_INTEL_OEM_APP_CMD::MDRII_SEND_DATA_BLOCK, |
| NULL, cmd_mdr2_send_data_block, PRIVILEGE_OPERATOR); |
| } |