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 19*edf25e61SRichard 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> 23*edf25e61SRichard Marian Thomaiyar #include <variant> 24a3702c1fSVernon Mauery 25*edf25e61SRichard Marian Thomaiyar namespace ipmi 26*edf25e61SRichard Marian Thomaiyar { 27a3702c1fSVernon Mauery void register_netfn_bmc_control_functions() __attribute__((constructor)); 28a3702c1fSVernon Mauery 29*edf25e61SRichard Marian Thomaiyar static constexpr uint8_t rmcpServiceBitPos = 3; 30*edf25e61SRichard Marian Thomaiyar static constexpr uint8_t webServiceBitPos = 5; 31*edf25e61SRichard Marian Thomaiyar static constexpr uint8_t solServiceBitPos = 6; 32*edf25e61SRichard Marian Thomaiyar static constexpr uint8_t kvmServiceBitPos = 15; 33*edf25e61SRichard Marian Thomaiyar 34*edf25e61SRichard Marian Thomaiyar static const std::unordered_map<uint8_t, std::string> bmcServices = { 35*edf25e61SRichard Marian Thomaiyar // {bit position for service, service object path} 36*edf25e61SRichard Marian Thomaiyar {rmcpServiceBitPos, 37*edf25e61SRichard Marian Thomaiyar "/xyz/openbmc_project/control/service/phosphor_2dipmi_2dnet"}, 38*edf25e61SRichard Marian Thomaiyar {webServiceBitPos, "/xyz/openbmc_project/control/service/bmcweb"}, 39*edf25e61SRichard Marian Thomaiyar {solServiceBitPos, "/xyz/openbmc_project/control/service/obmc_2dconsole"}, 40*edf25e61SRichard Marian Thomaiyar {kvmServiceBitPos, "/xyz/openbmc_project/control/service/start_2dipkvm"}, 41a3702c1fSVernon Mauery }; 42a3702c1fSVernon Mauery 43*edf25e61SRichard Marian Thomaiyar static constexpr uint16_t maskBit15 = 0xF000; 44a3702c1fSVernon Mauery 45a3702c1fSVernon Mauery static constexpr const char* objectManagerIntf = 46a3702c1fSVernon Mauery "org.freedesktop.DBus.ObjectManager"; 47*edf25e61SRichard 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"; 52*edf25e61SRichard Marian Thomaiyar static constexpr const char* getMgdObjMethod = "GetManagedObjects"; 53*edf25e61SRichard Marian Thomaiyar static constexpr const char* propMasked = "Masked"; 54a3702c1fSVernon Mauery 55*edf25e61SRichard 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 { 62*edf25e61SRichard Marian Thomaiyar auto sdbusp = getSdBus(); 63*edf25e61SRichard Marian Thomaiyar serviceCfgMgr = ipmi::getService(*sdbusp, objectManagerIntf, 64a3702c1fSVernon Mauery serviceConfigBasePath); 65a3702c1fSVernon Mauery } 66a3702c1fSVernon Mauery catch (const sdbusplus::exception::SdBusError& 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"); 71*edf25e61SRichard Marian Thomaiyar return serviceCfgMgr; 72a3702c1fSVernon Mauery } 73a3702c1fSVernon Mauery } 74*edf25e61SRichard Marian Thomaiyar return serviceCfgMgr; 75*edf25e61SRichard Marian Thomaiyar } 76*edf25e61SRichard Marian Thomaiyar 77*edf25e61SRichard Marian Thomaiyar static inline void checkAndThrowError(boost::system::error_code& ec, 78*edf25e61SRichard Marian Thomaiyar const std::string& msg) 79a3702c1fSVernon Mauery { 80*edf25e61SRichard Marian Thomaiyar if (ec) 81*edf25e61SRichard Marian Thomaiyar { 82*edf25e61SRichard Marian Thomaiyar std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg); 83*edf25e61SRichard Marian Thomaiyar phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str()); 84*edf25e61SRichard Marian Thomaiyar throw sdbusplus::exception::SdBusError(-EIO, msgToLog.c_str()); 85a3702c1fSVernon Mauery } 86*edf25e61SRichard Marian Thomaiyar return; 87*edf25e61SRichard Marian Thomaiyar } 88*edf25e61SRichard Marian Thomaiyar 89*edf25e61SRichard Marian Thomaiyar static inline bool getEnabledValue(const DbusInterfaceMap& intfMap) 90*edf25e61SRichard Marian Thomaiyar { 91*edf25e61SRichard Marian Thomaiyar for (const auto& intf : intfMap) 92*edf25e61SRichard Marian Thomaiyar { 93*edf25e61SRichard Marian Thomaiyar if (intf.first == serviceConfigAttrIntf) 94*edf25e61SRichard Marian Thomaiyar { 95*edf25e61SRichard Marian Thomaiyar auto it = intf.second.find(propMasked); 96*edf25e61SRichard Marian Thomaiyar if (it == intf.second.end()) 97a3702c1fSVernon Mauery { 98a3702c1fSVernon Mauery phosphor::logging::log<phosphor::logging::level::ERR>( 99*edf25e61SRichard Marian Thomaiyar "Error: in getting Masked property value"); 100*edf25e61SRichard Marian Thomaiyar throw sdbusplus::exception::SdBusError( 101*edf25e61SRichard Marian Thomaiyar -EIO, "ERROR in reading Masked property value"); 102*edf25e61SRichard Marian Thomaiyar } 103*edf25e61SRichard Marian Thomaiyar // return !Masked value 104*edf25e61SRichard Marian Thomaiyar return !std::get<bool>(it->second); 105*edf25e61SRichard Marian Thomaiyar } 106a3702c1fSVernon Mauery } 107a3702c1fSVernon Mauery } 108a3702c1fSVernon Mauery 109*edf25e61SRichard Marian Thomaiyar ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield, 110*edf25e61SRichard Marian Thomaiyar uint8_t state, uint16_t serviceValue) 111*edf25e61SRichard Marian Thomaiyar { 112*edf25e61SRichard Marian Thomaiyar constexpr uint16_t servicesRsvdMask = 0x3F97; 113*edf25e61SRichard Marian Thomaiyar constexpr uint8_t enableService = 0x1; 114a3702c1fSVernon Mauery 115*edf25e61SRichard Marian Thomaiyar if ((state > enableService) || (serviceValue & servicesRsvdMask) || 116*edf25e61SRichard Marian Thomaiyar !serviceValue) 117a3702c1fSVernon Mauery { 118*edf25e61SRichard Marian Thomaiyar return ipmi::responseInvalidFieldRequest(); 119a3702c1fSVernon Mauery } 120*edf25e61SRichard Marian Thomaiyar try 121*edf25e61SRichard Marian Thomaiyar { 122*edf25e61SRichard Marian Thomaiyar auto sdbusp = getSdBus(); 123*edf25e61SRichard Marian Thomaiyar boost::system::error_code ec; 124*edf25e61SRichard Marian Thomaiyar auto objectMap = sdbusp->yield_method_call<ObjectValueTree>( 125*edf25e61SRichard Marian Thomaiyar yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath, 126*edf25e61SRichard Marian Thomaiyar objectManagerIntf, getMgdObjMethod); 127*edf25e61SRichard Marian Thomaiyar checkAndThrowError(ec, "GetMangagedObjects for service cfg failed"); 128a3702c1fSVernon Mauery 129*edf25e61SRichard Marian Thomaiyar for (const auto& services : bmcServices) 130a3702c1fSVernon Mauery { 131*edf25e61SRichard Marian Thomaiyar // services.first holds the bit position of the service, check 132*edf25e61SRichard Marian Thomaiyar // whether it has to be updated. 133*edf25e61SRichard Marian Thomaiyar const uint16_t serviceMask = 1 << services.first; 134*edf25e61SRichard Marian Thomaiyar if (!(serviceValue & serviceMask)) 135*edf25e61SRichard Marian Thomaiyar { 136*edf25e61SRichard Marian Thomaiyar continue; 137a3702c1fSVernon Mauery } 138*edf25e61SRichard Marian Thomaiyar for (const auto& obj : objectMap) 139a3702c1fSVernon Mauery { 140*edf25e61SRichard Marian Thomaiyar if (boost::algorithm::starts_with(obj.first.str, 141*edf25e61SRichard Marian Thomaiyar services.second)) 142a3702c1fSVernon Mauery { 143*edf25e61SRichard Marian Thomaiyar if (state != getEnabledValue(obj.second)) 144a3702c1fSVernon Mauery { 145*edf25e61SRichard Marian Thomaiyar ec.clear(); 146*edf25e61SRichard Marian Thomaiyar sdbusp->yield_method_call<>( 147*edf25e61SRichard Marian Thomaiyar yield, ec, getServiceConfigMgrName().c_str(), 148*edf25e61SRichard Marian Thomaiyar obj.first.str, dBusPropIntf, "Set", 149*edf25e61SRichard Marian Thomaiyar serviceConfigAttrIntf, propMasked, 150*edf25e61SRichard Marian Thomaiyar std::variant<bool>(!state)); 151*edf25e61SRichard Marian Thomaiyar checkAndThrowError(ec, "Set Masked property failed"); 152*edf25e61SRichard Marian Thomaiyar // Multiple instances may be present, so continue 153a3702c1fSVernon Mauery } 154a3702c1fSVernon Mauery } 155a3702c1fSVernon Mauery } 156*edf25e61SRichard Marian Thomaiyar } 157*edf25e61SRichard Marian Thomaiyar } 158*edf25e61SRichard Marian Thomaiyar catch (sdbusplus::exception::SdBusError& e) 159*edf25e61SRichard Marian Thomaiyar { 160*edf25e61SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 161*edf25e61SRichard Marian Thomaiyar } 162a3702c1fSVernon Mauery return ipmi::responseSuccess(); 163a3702c1fSVernon Mauery } 164a3702c1fSVernon Mauery 165*edf25e61SRichard Marian Thomaiyar ipmi::RspType<uint16_t> getBmcControlServices(boost::asio::yield_context yield) 166*edf25e61SRichard Marian Thomaiyar { 167*edf25e61SRichard Marian Thomaiyar uint16_t serviceValue = 0; 168*edf25e61SRichard Marian Thomaiyar try 169*edf25e61SRichard Marian Thomaiyar { 170*edf25e61SRichard Marian Thomaiyar auto sdbusp = getSdBus(); 171*edf25e61SRichard Marian Thomaiyar boost::system::error_code ec; 172*edf25e61SRichard Marian Thomaiyar auto objectMap = sdbusp->yield_method_call<ObjectValueTree>( 173*edf25e61SRichard Marian Thomaiyar yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath, 174*edf25e61SRichard Marian Thomaiyar objectManagerIntf, getMgdObjMethod); 175*edf25e61SRichard Marian Thomaiyar checkAndThrowError(ec, "GetMangagedObjects for service cfg failed"); 176*edf25e61SRichard Marian Thomaiyar 177*edf25e61SRichard Marian Thomaiyar for (const auto& services : bmcServices) 178*edf25e61SRichard Marian Thomaiyar { 179*edf25e61SRichard Marian Thomaiyar for (const auto& obj : objectMap) 180*edf25e61SRichard Marian Thomaiyar { 181*edf25e61SRichard Marian Thomaiyar if (boost::algorithm::starts_with(obj.first.str, 182*edf25e61SRichard Marian Thomaiyar services.second)) 183*edf25e61SRichard Marian Thomaiyar { 184*edf25e61SRichard Marian Thomaiyar serviceValue |= getEnabledValue(obj.second) 185*edf25e61SRichard Marian Thomaiyar << services.first; 186*edf25e61SRichard Marian Thomaiyar break; 187*edf25e61SRichard Marian Thomaiyar } 188*edf25e61SRichard Marian Thomaiyar } 189*edf25e61SRichard Marian Thomaiyar } 190*edf25e61SRichard Marian Thomaiyar } 191*edf25e61SRichard Marian Thomaiyar catch (sdbusplus::exception::SdBusError& e) 192*edf25e61SRichard Marian Thomaiyar { 193*edf25e61SRichard Marian Thomaiyar return ipmi::responseUnspecifiedError(); 194*edf25e61SRichard Marian Thomaiyar } 195*edf25e61SRichard Marian Thomaiyar // Bit 14 should match bit 15 as single service maintains Video & USB 196*edf25e61SRichard Marian Thomaiyar // redirection 197*edf25e61SRichard Marian Thomaiyar serviceValue |= (serviceValue & maskBit15) >> 1; 198*edf25e61SRichard Marian Thomaiyar return ipmi::responseSuccess(serviceValue); 199*edf25e61SRichard Marian Thomaiyar } 200*edf25e61SRichard Marian Thomaiyar 201a3702c1fSVernon Mauery void register_netfn_bmc_control_functions() 202a3702c1fSVernon Mauery { 203a3702c1fSVernon Mauery ipmi::registerHandler(ipmi::prioOpenBmcBase, netfnIntcOEMGeneral, 204a3702c1fSVernon Mauery static_cast<ipmi_cmd_t>( 205*edf25e61SRichard Marian Thomaiyar IPMINetFnIntelOemGeneralCmds::controlBmcServices), 206*edf25e61SRichard Marian Thomaiyar ipmi::Privilege::Admin, setBmcControlServices); 207*edf25e61SRichard Marian Thomaiyar 208*edf25e61SRichard Marian Thomaiyar ipmi::registerHandler( 209*edf25e61SRichard Marian Thomaiyar ipmi::prioOpenBmcBase, netfnIntcOEMGeneral, 210*edf25e61SRichard Marian Thomaiyar static_cast<ipmi_cmd_t>( 211*edf25e61SRichard Marian Thomaiyar IPMINetFnIntelOemGeneralCmds::getBmcServiceStatus), 212*edf25e61SRichard Marian Thomaiyar ipmi::Privilege::User, getBmcControlServices); 213a3702c1fSVernon Mauery } 214*edf25e61SRichard Marian Thomaiyar } // namespace ipmi 215