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