From 27b94aa1df83abad63cbba69525273194b14ab9c Mon Sep 17 00:00:00 2001 From: Cheng C Yang Date: Wed, 16 Oct 2019 14:24:20 +0800 Subject: [PATCH] Move Set SOL config parameter to host-ipmid Move Set SOL config parameter command from net-ipmid to host-ipmid, so that BIOS in Intel platform can enable or disable SOL through KCS. Get SOL config parameter command will be moved later. Tested by: With the related change in phospher-ipmi-net and phospher-dbus-interface, Run commands: ipmitool raw 0x0c 0x21 0x0e 0x00 0x01 ipmitool raw 0x0c 0x21 0x0e 0x01 0x00 ipmitool raw 0x0c 0x21 0x0e 0x02 0x03 ipmitool raw 0x0c 0x21 0x0e 0x03 0x5 0x03 ipmitool raw 0x0c 0x21 0x0e 0x04 0x5 0x03 All these commands have correct response and all dbus interface for sol command change to same value in above commands. After reboot BMC, "Progress" property in dbus interface change back to 0 and other properties will not reset to default value. Signed-off-by: Cheng C Yang --- host-ipmid-whitelist.conf | 1 + transporthandler.cpp | 322 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 323 insertions(+) diff --git a/host-ipmid-whitelist.conf b/host-ipmid-whitelist.conf index e8df7c7..f030ef4 100644 --- a/host-ipmid-whitelist.conf +++ b/host-ipmid-whitelist.conf @@ -41,6 +41,7 @@ 0x0A:0x48 //: 0x0A:0x49 //: 0x0C:0x02 //: +0x0C:0x21 //: 0x2C:0x00 //: 0x2C:0x01 //: 0x2C:0x02 //: diff --git a/transporthandler.cpp b/transporthandler.cpp index e88eb63..4a42e7b 100644 --- a/transporthandler.cpp +++ b/transporthandler.cpp @@ -1469,8 +1469,323 @@ RspType getLan(uint4_t channelBits, uint3_t, bool revOnly, } // namespace transport } // namespace ipmi +constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL"; +constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/"; + void register_netfn_transport_functions() __attribute__((constructor)); +static std::string + getSOLService(std::shared_ptr dbus, + const std::string& solPathWitheEthName) +{ + static std::string solService{}; + if (solService.empty()) + { + try + { + solService = + ipmi::getService(*dbus, solInterface, solPathWitheEthName); + } + catch (const sdbusplus::exception::SdBusError& e) + { + solService.clear(); + phosphor::logging::log( + "Error: get SOL service failed"); + return solService; + } + } + return solService; +} + +static int setSOLParameter(const std::string& property, + const ipmi::Value& value, const uint8_t& channelNum) +{ + auto dbus = getSdBus(); + + std::string ethdevice = ipmi::getChannelName(channelNum); + + std::string solPathWitheEthName = std::string(solPath) + ethdevice; + + std::string service = getSOLService(dbus, solPathWitheEthName); + if (service.empty()) + { + phosphor::logging::log( + "Unable to get SOL service failed"); + return -1; + } + try + { + ipmi::setDbusProperty(*dbus, service, solPathWitheEthName, solInterface, + property, value); + } + catch (sdbusplus::exception_t&) + { + phosphor::logging::log( + "Error setting sol parameter"); + return -1; + } + + return 0; +} + +static int getSOLParameter(const std::string& property, ipmi::Value& value, + const uint8_t& channelNum) +{ + auto dbus = getSdBus(); + + std::string ethdevice = ipmi::getChannelName(channelNum); + + std::string solPathWitheEthName = std::string(solPath) + ethdevice; + + std::string service = getSOLService(dbus, solPathWitheEthName); + if (service.empty()) + { + phosphor::logging::log( + "Unable to get SOL service failed"); + return -1; + } + try + { + value = ipmi::getDbusProperty(*dbus, service, solPathWitheEthName, + solInterface, property); + } + catch (sdbusplus::exception_t&) + { + phosphor::logging::log( + "Error getting sol parameter"); + return -1; + } + + return 0; +} + +void initializeSOLInProgress() +{ + ipmi::ChannelInfo chInfo; + for (int chNum = 0; chNum < ipmi::maxIpmiChannels; chNum++) + { + if (!ipmi::isValidChannel(static_cast(chNum))) + { + continue; + } + ipmi_ret_t compCode = + ipmi::getChannelInfo(static_cast(chNum), chInfo); + if (compCode != IPMI_CC_OK || + chInfo.mediumType != + static_cast(ipmi::EChannelMediumType::lan8032)) + { + continue; + } + if (setSOLParameter("Progress", static_cast(0), chNum) < 0) + { + phosphor::logging::log( + "Error initialize sol progress"); + } + } +} + +static const constexpr uint8_t encryptMask = 0x80; +static const constexpr uint8_t encryptShift = 7; +static const constexpr uint8_t authMask = 0x40; +static const constexpr uint8_t authShift = 6; +static const constexpr uint8_t privilegeMask = 0xf; + +namespace ipmi +{ +constexpr Cc ccParmNotSupported = 0x80; +constexpr Cc ccSetInProgressActive = 0x81; +constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82; + +static inline auto responseParmNotSupported() +{ + return response(ccParmNotSupported); +} +static inline auto responseSetInProgressActive() +{ + return response(ccSetInProgressActive); +} +static inline auto responseSystemInfoParameterSetReadOnly() +{ + return response(ccSystemInfoParameterSetReadOnly); +} + +} // namespace ipmi + +namespace sol +{ +enum class Parameter +{ + progress, //!< Set In Progress. + enable, //!< SOL Enable. + authentication, //!< SOL Authentication. + accumulate, //!< Character Accumulate Interval & Send Threshold. + retry, //!< SOL Retry. + nvbitrate, //!< SOL non-volatile bit rate. + vbitrate, //!< SOL volatile bit rate. + channel, //!< SOL payload channel. + port, //!< SOL payload port. +}; + +enum class Privilege : uint8_t +{ + highestPriv, + callbackPriv, + userPriv, + operatorPriv, + adminPriv, + oemPriv, +}; + +} // namespace sol + +constexpr uint8_t progressMask = 0x03; +constexpr uint8_t enableMask = 0x01; +constexpr uint8_t retryMask = 0x07; + +ipmi::RspType<> setSOLConfParams(ipmi::Context::ptr ctx, uint4_t chNum, + uint4_t reserved, uint8_t paramSelector, + uint8_t configParamData1, + std::optional configParamData2) +{ + ipmi::ChannelInfo chInfo; + uint8_t channelNum = ipmi::convertCurrentChannelNum( + static_cast(chNum), ctx->channel); + if (reserved != 0 || + (!ipmi::isValidChannel(static_cast(channelNum)))) + { + return ipmi::responseInvalidFieldRequest(); + } + + ipmi_ret_t compCode = + ipmi::getChannelInfo(static_cast(channelNum), chInfo); + if (compCode != IPMI_CC_OK || + chInfo.mediumType != + static_cast(ipmi::EChannelMediumType::lan8032)) + { + return ipmi::responseInvalidFieldRequest(); + } + + switch (static_cast(paramSelector)) + { + case sol::Parameter::progress: + { + if (configParamData2) + { + return ipmi::responseReqDataLenInvalid(); + } + uint8_t progress = configParamData1 & progressMask; + ipmi::Value currentProgress = 0; + if (getSOLParameter("Progress", currentProgress, channelNum) < 0) + { + return ipmi::responseUnspecifiedError(); + } + + if ((std::get(currentProgress) == 1) && (progress == 1)) + { + return ipmi::responseSetInProgressActive(); + } + + if (setSOLParameter("Progress", progress, channelNum) < 0) + { + return ipmi::responseUnspecifiedError(); + } + break; + } + case sol::Parameter::enable: + { + if (configParamData2) + { + return ipmi::responseReqDataLenInvalid(); + } + bool enable = configParamData1 & enableMask; + if (setSOLParameter("Enable", enable, channelNum) < 0) + { + return ipmi::responseUnspecifiedError(); + } + break; + } + case sol::Parameter::authentication: + { + if (configParamData2) + { + return ipmi::responseReqDataLenInvalid(); + } + uint8_t encrypt = (configParamData1 & encryptMask) >> encryptShift; + uint8_t auth = (configParamData1 & authMask) >> authShift; + uint8_t privilege = configParamData1 & privilegeMask; + // For security considering encryption and authentication must be + // true. + if (!encrypt || !auth) + { + return ipmi::responseSystemInfoParameterSetReadOnly(); + } + else if (privilege < + static_cast(sol::Privilege::userPriv) || + privilege > static_cast(sol::Privilege::oemPriv)) + { + return ipmi::responseInvalidFieldRequest(); + } + + if (setSOLParameter("Privilege", privilege, channelNum) < 0) + { + return ipmi::responseUnspecifiedError(); + } + + break; + } + case sol::Parameter::accumulate: + { + if (!configParamData2) + { + return ipmi::responseReqDataLenInvalid(); + } + if (*configParamData2 == 0) + { + return ipmi::responseInvalidFieldRequest(); + } + if (setSOLParameter("AccumulateIntervalMS", configParamData1, + channelNum) < 0) + { + return ipmi::responseUnspecifiedError(); + } + if (setSOLParameter("Threshold", *configParamData2, channelNum) < 0) + { + return ipmi::responseUnspecifiedError(); + } + break; + } + case sol::Parameter::retry: + { + if (!configParamData2) + { + return ipmi::responseReqDataLenInvalid(); + } + if ((setSOLParameter( + "RetryCount", + static_cast(configParamData1 & retryMask), + channelNum) < 0) || + (setSOLParameter("RetryIntervalMS", *configParamData2, + channelNum) < 0)) + { + return ipmi::responseUnspecifiedError(); + } + + break; + } + case sol::Parameter::port: + { + return ipmi::responseSystemInfoParameterSetReadOnly(); + } + case sol::Parameter::nvbitrate: + case sol::Parameter::vbitrate: + case sol::Parameter::channel: + default: + return ipmi::responseParmNotSupported(); + } + + return ipmi::responseSuccess(); +} + void register_netfn_transport_functions() { ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, @@ -1479,4 +1794,11 @@ void register_netfn_transport_functions() ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, ipmi::transport::cmdGetLanConfigParameters, ipmi::Privilege::Operator, ipmi::transport::getLan); + + ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnTransport, + ipmi::transport::cmdSetSolConfigParameters, + ipmi::Privilege::Admin, setSOLConfParams); + + // Initialize dbus property progress to 0 every time sol manager restart. + initializeSOLInProgress(); } -- 2.7.4