| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | // Copyright (c) 2018 Intel Corporation | 
|  | 3 | // | 
|  | 4 | // Licensed under the Apache License, Version 2.0 (the "License"); | 
|  | 5 | // you may not use this file except in compliance with the License. | 
|  | 6 | // You may obtain a copy of the License at | 
|  | 7 | // | 
|  | 8 | //      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | // | 
|  | 10 | // Unless required by applicable law or agreed to in writing, software | 
|  | 11 | // distributed under the License is distributed on an "AS IS" BASIS, | 
|  | 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
|  | 13 | // See the License for the specific language governing permissions and | 
|  | 14 | // limitations under the License. | 
|  | 15 | */ | 
|  | 16 |  | 
|  | 17 | #include "oemcommands.hpp" | 
|  | 18 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 19 | #include <boost/algorithm/string.hpp> | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 20 | #include <ipmid/api.hpp> | 
|  | 21 | #include <ipmid/utils.hpp> | 
|  | 22 | #include <phosphor-logging/log.hpp> | 
| Jason M. Bills | 0748c69 | 2022-09-08 15:34:08 -0700 | [diff] [blame] | 23 | #include <types.hpp> | 
| James Feist | fcd2d3a | 2020-05-28 10:38:15 -0700 | [diff] [blame] | 24 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 25 | #include <variant> | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 26 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 27 | namespace ipmi | 
|  | 28 | { | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 29 | void register_netfn_bmc_control_functions() __attribute__((constructor)); | 
|  | 30 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 31 | static constexpr uint8_t rmcpServiceBitPos = 3; | 
|  | 32 | static constexpr uint8_t webServiceBitPos = 5; | 
|  | 33 | static constexpr uint8_t solServiceBitPos = 6; | 
|  | 34 | static constexpr uint8_t kvmServiceBitPos = 15; | 
|  | 35 |  | 
| Jiaqing Zhao | 95f6933 | 2022-06-04 15:09:45 +0800 | [diff] [blame] | 36 | static constexpr std::array<std::pair<uint8_t, const char*>, 4> bmcServices = {{ | 
|  | 37 | // {bit position for service, service name} | 
|  | 38 | {rmcpServiceBitPos, "phosphor-ipmi-net"}, | 
|  | 39 | {webServiceBitPos, "bmcweb"}, | 
|  | 40 | {solServiceBitPos, "obmc-console-ssh"}, | 
|  | 41 | {kvmServiceBitPos, "start-ipkvm"}, | 
|  | 42 | }}; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 43 |  | 
| Arun P. Mohanan | 98cb618 | 2021-08-31 19:49:19 +0530 | [diff] [blame] | 44 | static constexpr uint16_t maskBit15 = 0x8000; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 45 |  | 
|  | 46 | static constexpr const char* objectManagerIntf = | 
|  | 47 | "org.freedesktop.DBus.ObjectManager"; | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 48 | static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties"; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 49 | static constexpr const char* serviceConfigBasePath = | 
|  | 50 | "/xyz/openbmc_project/control/service"; | 
|  | 51 | static constexpr const char* serviceConfigAttrIntf = | 
|  | 52 | "xyz.openbmc_project.Control.Service.Attributes"; | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 53 | static constexpr const char* getMgdObjMethod = "GetManagedObjects"; | 
|  | 54 | static constexpr const char* propMasked = "Masked"; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 55 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 56 | std::string getServiceConfigMgrName() | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 57 | { | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 58 | static std::string serviceCfgMgr{}; | 
|  | 59 | if (serviceCfgMgr.empty()) | 
|  | 60 | { | 
|  | 61 | try | 
|  | 62 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 63 | auto sdbusp = getSdBus(); | 
|  | 64 | serviceCfgMgr = ipmi::getService(*sdbusp, objectManagerIntf, | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 65 | serviceConfigBasePath); | 
|  | 66 | } | 
| Patrick Williams | f944d2e | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 67 | catch (const sdbusplus::exception_t& e) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 68 | { | 
|  | 69 | serviceCfgMgr.clear(); | 
|  | 70 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 71 | "Error: In fetching disabling service manager name"); | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 72 | return serviceCfgMgr; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 73 | } | 
|  | 74 | } | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 75 | return serviceCfgMgr; | 
|  | 76 | } | 
|  | 77 |  | 
|  | 78 | static inline void checkAndThrowError(boost::system::error_code& ec, | 
|  | 79 | const std::string& msg) | 
|  | 80 | { | 
|  | 81 | if (ec) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 82 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 83 | std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg); | 
|  | 84 | phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str()); | 
|  | 85 | throw sdbusplus::exception::SdBusError(-EIO, msgToLog.c_str()); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 86 | } | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 87 | return; | 
|  | 88 | } | 
|  | 89 |  | 
|  | 90 | static inline bool getEnabledValue(const DbusInterfaceMap& intfMap) | 
|  | 91 | { | 
|  | 92 | for (const auto& intf : intfMap) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 93 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 94 | if (intf.first == serviceConfigAttrIntf) | 
|  | 95 | { | 
|  | 96 | auto it = intf.second.find(propMasked); | 
|  | 97 | if (it == intf.second.end()) | 
|  | 98 | { | 
|  | 99 | phosphor::logging::log<phosphor::logging::level::ERR>( | 
|  | 100 | "Error: in getting Masked property value"); | 
|  | 101 | throw sdbusplus::exception::SdBusError( | 
|  | 102 | -EIO, "ERROR in reading Masked property value"); | 
|  | 103 | } | 
|  | 104 | // return !Masked value | 
|  | 105 | return !std::get<bool>(it->second); | 
|  | 106 | } | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 107 | } | 
| James Feist | 13b0039 | 2019-08-19 16:16:08 -0700 | [diff] [blame] | 108 | return false; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 109 | } | 
|  | 110 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 111 | ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield, | 
|  | 112 | uint8_t state, uint16_t serviceValue) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 113 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 114 | constexpr uint16_t servicesRsvdMask = 0x3F97; | 
|  | 115 | constexpr uint8_t enableService = 0x1; | 
|  | 116 |  | 
|  | 117 | if ((state > enableService) || (serviceValue & servicesRsvdMask) || | 
|  | 118 | !serviceValue) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 119 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 120 | return ipmi::responseInvalidFieldRequest(); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 121 | } | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 122 | try | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 123 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 124 | auto sdbusp = getSdBus(); | 
|  | 125 | boost::system::error_code ec; | 
|  | 126 | auto objectMap = sdbusp->yield_method_call<ObjectValueTree>( | 
|  | 127 | yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath, | 
|  | 128 | objectManagerIntf, getMgdObjMethod); | 
|  | 129 | checkAndThrowError(ec, "GetMangagedObjects for service cfg failed"); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 130 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 131 | for (const auto& services : bmcServices) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 132 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 133 | // services.first holds the bit position of the service, check | 
|  | 134 | // whether it has to be updated. | 
|  | 135 | const uint16_t serviceMask = 1 << services.first; | 
|  | 136 | if (!(serviceValue & serviceMask)) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 137 | { | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 138 | continue; | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 139 | } | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 140 | for (const auto& obj : objectMap) | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 141 | { | 
| Jiaqing Zhao | 95f6933 | 2022-06-04 15:09:45 +0800 | [diff] [blame] | 142 | if (boost::algorithm::starts_with(obj.first.filename(), | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 143 | services.second)) | 
|  | 144 | { | 
|  | 145 | if (state != getEnabledValue(obj.second)) | 
|  | 146 | { | 
|  | 147 | ec.clear(); | 
|  | 148 | sdbusp->yield_method_call<>( | 
|  | 149 | yield, ec, getServiceConfigMgrName().c_str(), | 
|  | 150 | obj.first.str, dBusPropIntf, "Set", | 
|  | 151 | serviceConfigAttrIntf, propMasked, | 
| Jason M. Bills | 0748c69 | 2022-09-08 15:34:08 -0700 | [diff] [blame] | 152 | ipmi::DbusVariant(!state)); | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 153 | checkAndThrowError(ec, "Set Masked property failed"); | 
|  | 154 | // Multiple instances may be present, so continue | 
|  | 155 | } | 
|  | 156 | } | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 157 | } | 
|  | 158 | } | 
|  | 159 | } | 
| Patrick Williams | f944d2e | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 160 | catch (const sdbusplus::exception_t& e) | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 161 | { | 
|  | 162 | return ipmi::responseUnspecifiedError(); | 
|  | 163 | } | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 164 | return ipmi::responseSuccess(); | 
|  | 165 | } | 
|  | 166 |  | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 167 | ipmi::RspType<uint16_t> getBmcControlServices(boost::asio::yield_context yield) | 
|  | 168 | { | 
|  | 169 | uint16_t serviceValue = 0; | 
|  | 170 | try | 
|  | 171 | { | 
|  | 172 | auto sdbusp = getSdBus(); | 
|  | 173 | boost::system::error_code ec; | 
|  | 174 | auto objectMap = sdbusp->yield_method_call<ObjectValueTree>( | 
|  | 175 | yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath, | 
|  | 176 | objectManagerIntf, getMgdObjMethod); | 
|  | 177 | checkAndThrowError(ec, "GetMangagedObjects for service cfg failed"); | 
|  | 178 |  | 
|  | 179 | for (const auto& services : bmcServices) | 
|  | 180 | { | 
|  | 181 | for (const auto& obj : objectMap) | 
|  | 182 | { | 
| Jiaqing Zhao | 95f6933 | 2022-06-04 15:09:45 +0800 | [diff] [blame] | 183 | if (boost::algorithm::starts_with(obj.first.filename(), | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 184 | services.second)) | 
|  | 185 | { | 
|  | 186 | serviceValue |= getEnabledValue(obj.second) | 
|  | 187 | << services.first; | 
|  | 188 | break; | 
|  | 189 | } | 
|  | 190 | } | 
|  | 191 | } | 
|  | 192 | } | 
| Patrick Williams | f944d2e | 2022-07-22 19:26:52 -0500 | [diff] [blame] | 193 | catch (const sdbusplus::exception_t& e) | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 194 | { | 
|  | 195 | return ipmi::responseUnspecifiedError(); | 
|  | 196 | } | 
|  | 197 | // Bit 14 should match bit 15 as single service maintains Video & USB | 
|  | 198 | // redirection | 
|  | 199 | serviceValue |= (serviceValue & maskBit15) >> 1; | 
|  | 200 | return ipmi::responseSuccess(serviceValue); | 
|  | 201 | } | 
|  | 202 |  | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 203 | void register_netfn_bmc_control_functions() | 
|  | 204 | { | 
| Vernon Mauery | 98bbf69 | 2019-09-16 11:14:59 -0700 | [diff] [blame] | 205 | registerHandler(prioOpenBmcBase, intel::netFnGeneral, | 
|  | 206 | intel::general::cmdControlBmcServices, Privilege::Admin, | 
|  | 207 | setBmcControlServices); | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 208 |  | 
| Vernon Mauery | 98bbf69 | 2019-09-16 11:14:59 -0700 | [diff] [blame] | 209 | registerHandler(prioOpenBmcBase, intel::netFnGeneral, | 
|  | 210 | intel::general::cmdGetBmcServiceStatus, Privilege::User, | 
|  | 211 | getBmcControlServices); | 
| Vernon Mauery | a3702c1 | 2019-05-22 13:20:59 -0700 | [diff] [blame] | 212 | } | 
| Richard Marian Thomaiyar | edf25e6 | 2019-06-11 01:14:49 +0530 | [diff] [blame] | 213 | } // namespace ipmi |