blob: a08a2700a2982126626e378a960a6577197e6c98 [file] [log] [blame]
Vernon Mauerya3702c12019-05-22 13:20:59 -07001/*
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 Thomaiyaredf25e62019-06-11 01:14:49 +053019#include <boost/algorithm/string.hpp>
Vernon Mauerya3702c12019-05-22 13:20:59 -070020#include <ipmid/api.hpp>
21#include <ipmid/utils.hpp>
22#include <phosphor-logging/log.hpp>
James Feistfcd2d3a2020-05-28 10:38:15 -070023
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053024#include <variant>
Vernon Mauerya3702c12019-05-22 13:20:59 -070025
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053026namespace ipmi
27{
Vernon Mauerya3702c12019-05-22 13:20:59 -070028void register_netfn_bmc_control_functions() __attribute__((constructor));
29
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053030static constexpr uint8_t rmcpServiceBitPos = 3;
31static constexpr uint8_t webServiceBitPos = 5;
32static constexpr uint8_t solServiceBitPos = 6;
33static constexpr uint8_t kvmServiceBitPos = 15;
34
35static const std::unordered_map<uint8_t, std::string> bmcServices = {
36 // {bit position for service, service object path}
37 {rmcpServiceBitPos,
38 "/xyz/openbmc_project/control/service/phosphor_2dipmi_2dnet"},
39 {webServiceBitPos, "/xyz/openbmc_project/control/service/bmcweb"},
40 {solServiceBitPos, "/xyz/openbmc_project/control/service/obmc_2dconsole"},
41 {kvmServiceBitPos, "/xyz/openbmc_project/control/service/start_2dipkvm"},
Vernon Mauerya3702c12019-05-22 13:20:59 -070042};
43
Arun P. Mohanan98cb6182021-08-31 19:49:19 +053044static constexpr uint16_t maskBit15 = 0x8000;
Vernon Mauerya3702c12019-05-22 13:20:59 -070045
46static constexpr const char* objectManagerIntf =
47 "org.freedesktop.DBus.ObjectManager";
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053048static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties";
Vernon Mauerya3702c12019-05-22 13:20:59 -070049static constexpr const char* serviceConfigBasePath =
50 "/xyz/openbmc_project/control/service";
51static constexpr const char* serviceConfigAttrIntf =
52 "xyz.openbmc_project.Control.Service.Attributes";
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053053static constexpr const char* getMgdObjMethod = "GetManagedObjects";
54static constexpr const char* propMasked = "Masked";
Vernon Mauerya3702c12019-05-22 13:20:59 -070055
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053056std::string getServiceConfigMgrName()
Vernon Mauerya3702c12019-05-22 13:20:59 -070057{
Vernon Mauerya3702c12019-05-22 13:20:59 -070058 static std::string serviceCfgMgr{};
59 if (serviceCfgMgr.empty())
60 {
61 try
62 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053063 auto sdbusp = getSdBus();
64 serviceCfgMgr = ipmi::getService(*sdbusp, objectManagerIntf,
Vernon Mauerya3702c12019-05-22 13:20:59 -070065 serviceConfigBasePath);
66 }
Patrick Williams69245b72021-09-02 09:23:01 -050067 catch (const sdbusplus::exception::exception& e)
Vernon Mauerya3702c12019-05-22 13:20:59 -070068 {
69 serviceCfgMgr.clear();
70 phosphor::logging::log<phosphor::logging::level::ERR>(
71 "Error: In fetching disabling service manager name");
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053072 return serviceCfgMgr;
Vernon Mauerya3702c12019-05-22 13:20:59 -070073 }
74 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053075 return serviceCfgMgr;
76}
77
78static inline void checkAndThrowError(boost::system::error_code& ec,
79 const std::string& msg)
80{
81 if (ec)
Vernon Mauerya3702c12019-05-22 13:20:59 -070082 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053083 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 Mauerya3702c12019-05-22 13:20:59 -070086 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053087 return;
88}
89
90static inline bool getEnabledValue(const DbusInterfaceMap& intfMap)
91{
92 for (const auto& intf : intfMap)
Vernon Mauerya3702c12019-05-22 13:20:59 -070093 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053094 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 Mauerya3702c12019-05-22 13:20:59 -0700107 }
James Feist13b00392019-08-19 16:16:08 -0700108 return false;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700109}
110
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530111ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield,
112 uint8_t state, uint16_t serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700113{
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530114 constexpr uint16_t servicesRsvdMask = 0x3F97;
115 constexpr uint8_t enableService = 0x1;
116
117 if ((state > enableService) || (serviceValue & servicesRsvdMask) ||
118 !serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700119 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530120 return ipmi::responseInvalidFieldRequest();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700121 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530122 try
Vernon Mauerya3702c12019-05-22 13:20:59 -0700123 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530124 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 Mauerya3702c12019-05-22 13:20:59 -0700130
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530131 for (const auto& services : bmcServices)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700132 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530133 // 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 Mauerya3702c12019-05-22 13:20:59 -0700137 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530138 continue;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700139 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530140 for (const auto& obj : objectMap)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700141 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530142 if (boost::algorithm::starts_with(obj.first.str,
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,
152 std::variant<bool>(!state));
153 checkAndThrowError(ec, "Set Masked property failed");
154 // Multiple instances may be present, so continue
155 }
156 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700157 }
158 }
159 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500160 catch (const sdbusplus::exception::exception& e)
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530161 {
162 return ipmi::responseUnspecifiedError();
163 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700164 return ipmi::responseSuccess();
165}
166
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530167ipmi::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 {
183 if (boost::algorithm::starts_with(obj.first.str,
184 services.second))
185 {
186 serviceValue |= getEnabledValue(obj.second)
187 << services.first;
188 break;
189 }
190 }
191 }
192 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500193 catch (const sdbusplus::exception::exception& e)
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530194 {
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 Mauerya3702c12019-05-22 13:20:59 -0700203void register_netfn_bmc_control_functions()
204{
Vernon Mauery98bbf692019-09-16 11:14:59 -0700205 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
206 intel::general::cmdControlBmcServices, Privilege::Admin,
207 setBmcControlServices);
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530208
Vernon Mauery98bbf692019-09-16 11:14:59 -0700209 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
210 intel::general::cmdGetBmcServiceStatus, Privilege::User,
211 getBmcControlServices);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700212}
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530213} // namespace ipmi