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 3595f69336SJiaqing Zhao static constexpr std::array<std::pair<uint8_t, const char*>, 4> bmcServices = {{ 3695f69336SJiaqing Zhao // {bit position for service, service name} 3795f69336SJiaqing Zhao {rmcpServiceBitPos, "phosphor-ipmi-net"}, 3895f69336SJiaqing Zhao {webServiceBitPos, "bmcweb"}, 3995f69336SJiaqing Zhao {solServiceBitPos, "obmc-console-ssh"}, 4095f69336SJiaqing Zhao {kvmServiceBitPos, "start-ipkvm"}, 4195f69336SJiaqing Zhao }}; 42a3702c1fSVernon Mauery 4398cb6186SArun P. Mohanan static constexpr uint16_t maskBit15 = 0x8000; 44a3702c1fSVernon Mauery 45a3702c1fSVernon Mauery static constexpr const char* objectManagerIntf = 46a3702c1fSVernon Mauery "org.freedesktop.DBus.ObjectManager"; 47edf25e61SRichard Marian Thomaiyar static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties"; 48a3702c1fSVernon Mauery static constexpr const char* serviceConfigBasePath = 49a3702c1fSVernon Mauery "/xyz/openbmc_project/control/service"; 50a3702c1fSVernon Mauery static constexpr const char* serviceConfigAttrIntf = 51a3702c1fSVernon Mauery "xyz.openbmc_project.Control.Service.Attributes"; 52edf25e61SRichard Marian Thomaiyar static constexpr const char* getMgdObjMethod = "GetManagedObjects"; 53edf25e61SRichard Marian Thomaiyar static constexpr const char* propMasked = "Masked"; 54a3702c1fSVernon Mauery 55edf25e61SRichard Marian Thomaiyar std::string getServiceConfigMgrName() 56a3702c1fSVernon Mauery { 57a3702c1fSVernon Mauery static std::string serviceCfgMgr{}; 58a3702c1fSVernon Mauery if (serviceCfgMgr.empty()) 59a3702c1fSVernon Mauery { 60a3702c1fSVernon Mauery try 61a3702c1fSVernon Mauery { 62edf25e61SRichard Marian Thomaiyar auto sdbusp = getSdBus(); 63edf25e61SRichard Marian Thomaiyar serviceCfgMgr = ipmi::getService(*sdbusp, objectManagerIntf, 64a3702c1fSVernon Mauery serviceConfigBasePath); 65a3702c1fSVernon Mauery } 66*f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 67a3702c1fSVernon Mauery { 68a3702c1fSVernon Mauery serviceCfgMgr.clear(); 69a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::ERR>( 70a3702c1fSVernon Mauery "Error: In fetching disabling service manager name"); 71edf25e61SRichard Marian Thomaiyar return serviceCfgMgr; 72a3702c1fSVernon Mauery } 73a3702c1fSVernon Mauery } 74edf25e61SRichard Marian Thomaiyar return serviceCfgMgr; 75edf25e61SRichard Marian Thomaiyar } 76edf25e61SRichard Marian Thomaiyar 77edf25e61SRichard Marian Thomaiyar static inline void checkAndThrowError(boost::system::error_code& ec, 78edf25e61SRichard Marian Thomaiyar const std::string& msg) 79a3702c1fSVernon Mauery { 80edf25e61SRichard Marian Thomaiyar if (ec) 81edf25e61SRichard Marian Thomaiyar { 82edf25e61SRichard Marian Thomaiyar std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg); 83edf25e61SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str()); 84edf25e61SRichard Marian Thomaiyar throw sdbusplus::exception::SdBusError(-EIO, msgToLog.c_str()); 85a3702c1fSVernon Mauery } 86edf25e61SRichard Marian Thomaiyar return; 87edf25e61SRichard Marian Thomaiyar } 88edf25e61SRichard Marian Thomaiyar 89edf25e61SRichard Marian Thomaiyar static inline bool getEnabledValue(const DbusInterfaceMap& intfMap) 90edf25e61SRichard Marian Thomaiyar { 91edf25e61SRichard Marian Thomaiyar for (const auto& intf : intfMap) 92edf25e61SRichard Marian Thomaiyar { 93edf25e61SRichard Marian Thomaiyar if (intf.first == serviceConfigAttrIntf) 94edf25e61SRichard Marian Thomaiyar { 95edf25e61SRichard Marian Thomaiyar auto it = intf.second.find(propMasked); 96edf25e61SRichard Marian Thomaiyar if (it == intf.second.end()) 97a3702c1fSVernon Mauery { 98a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::ERR>( 99edf25e61SRichard Marian Thomaiyar "Error: in getting Masked property value"); 100edf25e61SRichard Marian Thomaiyar throw sdbusplus::exception::SdBusError( 101edf25e61SRichard Marian Thomaiyar -EIO, "ERROR in reading Masked property value"); 102edf25e61SRichard Marian Thomaiyar } 103edf25e61SRichard Marian Thomaiyar // return !Masked value 104edf25e61SRichard Marian Thomaiyar return !std::get<bool>(it->second); 105edf25e61SRichard Marian Thomaiyar } 106a3702c1fSVernon Mauery } 10713b0039dSJames Feist return false; 108a3702c1fSVernon Mauery } 109a3702c1fSVernon Mauery 110edf25e61SRichard Marian Thomaiyar ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield, 111edf25e61SRichard Marian Thomaiyar uint8_t state, uint16_t serviceValue) 112edf25e61SRichard Marian Thomaiyar { 113edf25e61SRichard Marian Thomaiyar constexpr uint16_t servicesRsvdMask = 0x3F97; 114edf25e61SRichard Marian Thomaiyar constexpr uint8_t enableService = 0x1; 115a3702c1fSVernon Mauery 116edf25e61SRichard Marian Thomaiyar if ((state > enableService) || (serviceValue & servicesRsvdMask) || 117edf25e61SRichard Marian Thomaiyar !serviceValue) 118a3702c1fSVernon Mauery { 119edf25e61SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 120a3702c1fSVernon Mauery } 121edf25e61SRichard Marian Thomaiyar try 122edf25e61SRichard Marian Thomaiyar { 123edf25e61SRichard Marian Thomaiyar auto sdbusp = getSdBus(); 124edf25e61SRichard Marian Thomaiyar boost::system::error_code ec; 125edf25e61SRichard Marian Thomaiyar auto objectMap = sdbusp->yield_method_call<ObjectValueTree>( 126edf25e61SRichard Marian Thomaiyar yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath, 127edf25e61SRichard Marian Thomaiyar objectManagerIntf, getMgdObjMethod); 128edf25e61SRichard Marian Thomaiyar checkAndThrowError(ec, "GetMangagedObjects for service cfg failed"); 129a3702c1fSVernon Mauery 130edf25e61SRichard Marian Thomaiyar for (const auto& services : bmcServices) 131a3702c1fSVernon Mauery { 132edf25e61SRichard Marian Thomaiyar // services.first holds the bit position of the service, check 133edf25e61SRichard Marian Thomaiyar // whether it has to be updated. 134edf25e61SRichard Marian Thomaiyar const uint16_t serviceMask = 1 << services.first; 135edf25e61SRichard Marian Thomaiyar if (!(serviceValue & serviceMask)) 136edf25e61SRichard Marian Thomaiyar { 137edf25e61SRichard Marian Thomaiyar continue; 138a3702c1fSVernon Mauery } 139edf25e61SRichard Marian Thomaiyar for (const auto& obj : objectMap) 140a3702c1fSVernon Mauery { 14195f69336SJiaqing Zhao if (boost::algorithm::starts_with(obj.first.filename(), 142edf25e61SRichard Marian Thomaiyar services.second)) 143a3702c1fSVernon Mauery { 144edf25e61SRichard Marian Thomaiyar if (state != getEnabledValue(obj.second)) 145a3702c1fSVernon Mauery { 146edf25e61SRichard Marian Thomaiyar ec.clear(); 147edf25e61SRichard Marian Thomaiyar sdbusp->yield_method_call<>( 148edf25e61SRichard Marian Thomaiyar yield, ec, getServiceConfigMgrName().c_str(), 149edf25e61SRichard Marian Thomaiyar obj.first.str, dBusPropIntf, "Set", 150edf25e61SRichard Marian Thomaiyar serviceConfigAttrIntf, propMasked, 151edf25e61SRichard Marian Thomaiyar std::variant<bool>(!state)); 152edf25e61SRichard Marian Thomaiyar checkAndThrowError(ec, "Set Masked property failed"); 153edf25e61SRichard Marian Thomaiyar // Multiple instances may be present, so continue 154a3702c1fSVernon Mauery } 155a3702c1fSVernon Mauery } 156a3702c1fSVernon Mauery } 157edf25e61SRichard Marian Thomaiyar } 158edf25e61SRichard Marian Thomaiyar } 159*f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 160edf25e61SRichard Marian Thomaiyar { 161edf25e61SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 162edf25e61SRichard Marian Thomaiyar } 163a3702c1fSVernon Mauery return ipmi::responseSuccess(); 164a3702c1fSVernon Mauery } 165a3702c1fSVernon Mauery 166edf25e61SRichard Marian Thomaiyar ipmi::RspType<uint16_t> getBmcControlServices(boost::asio::yield_context yield) 167edf25e61SRichard Marian Thomaiyar { 168edf25e61SRichard Marian Thomaiyar uint16_t serviceValue = 0; 169edf25e61SRichard Marian Thomaiyar try 170edf25e61SRichard Marian Thomaiyar { 171edf25e61SRichard Marian Thomaiyar auto sdbusp = getSdBus(); 172edf25e61SRichard Marian Thomaiyar boost::system::error_code ec; 173edf25e61SRichard Marian Thomaiyar auto objectMap = sdbusp->yield_method_call<ObjectValueTree>( 174edf25e61SRichard Marian Thomaiyar yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath, 175edf25e61SRichard Marian Thomaiyar objectManagerIntf, getMgdObjMethod); 176edf25e61SRichard Marian Thomaiyar checkAndThrowError(ec, "GetMangagedObjects for service cfg failed"); 177edf25e61SRichard Marian Thomaiyar 178edf25e61SRichard Marian Thomaiyar for (const auto& services : bmcServices) 179edf25e61SRichard Marian Thomaiyar { 180edf25e61SRichard Marian Thomaiyar for (const auto& obj : objectMap) 181edf25e61SRichard Marian Thomaiyar { 18295f69336SJiaqing Zhao if (boost::algorithm::starts_with(obj.first.filename(), 183edf25e61SRichard Marian Thomaiyar services.second)) 184edf25e61SRichard Marian Thomaiyar { 185edf25e61SRichard Marian Thomaiyar serviceValue |= getEnabledValue(obj.second) 186edf25e61SRichard Marian Thomaiyar << services.first; 187edf25e61SRichard Marian Thomaiyar break; 188edf25e61SRichard Marian Thomaiyar } 189edf25e61SRichard Marian Thomaiyar } 190edf25e61SRichard Marian Thomaiyar } 191edf25e61SRichard Marian Thomaiyar } 192*f944d2e5SPatrick Williams catch (const sdbusplus::exception_t& e) 193edf25e61SRichard Marian Thomaiyar { 194edf25e61SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 195edf25e61SRichard Marian Thomaiyar } 196edf25e61SRichard Marian Thomaiyar // Bit 14 should match bit 15 as single service maintains Video & USB 197edf25e61SRichard Marian Thomaiyar // redirection 198edf25e61SRichard Marian Thomaiyar serviceValue |= (serviceValue & maskBit15) >> 1; 199edf25e61SRichard Marian Thomaiyar return ipmi::responseSuccess(serviceValue); 200edf25e61SRichard Marian Thomaiyar } 201edf25e61SRichard Marian Thomaiyar 202a3702c1fSVernon Mauery void register_netfn_bmc_control_functions() 203a3702c1fSVernon Mauery { 20498bbf69aSVernon Mauery registerHandler(prioOpenBmcBase, intel::netFnGeneral, 20598bbf69aSVernon Mauery intel::general::cmdControlBmcServices, Privilege::Admin, 20698bbf69aSVernon Mauery setBmcControlServices); 207edf25e61SRichard Marian Thomaiyar 20898bbf69aSVernon Mauery registerHandler(prioOpenBmcBase, intel::netFnGeneral, 20998bbf69aSVernon Mauery intel::general::cmdGetBmcServiceStatus, Privilege::User, 21098bbf69aSVernon Mauery getBmcControlServices); 211a3702c1fSVernon Mauery } 212edf25e61SRichard Marian Thomaiyar } // namespace ipmi 213