blob: e30c4a9140c82639acdbc38d3c850d9eacb27161 [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
Jiaqing Zhao95f69332022-06-04 15:09:45 +080035static constexpr std::array<std::pair<uint8_t, const char*>, 4> bmcServices = {{
36 // {bit position for service, service name}
37 {rmcpServiceBitPos, "phosphor-ipmi-net"},
38 {webServiceBitPos, "bmcweb"},
39 {solServiceBitPos, "obmc-console-ssh"},
40 {kvmServiceBitPos, "start-ipkvm"},
41}};
Vernon Mauerya3702c12019-05-22 13:20:59 -070042
Arun P. Mohanan98cb6182021-08-31 19:49:19 +053043static constexpr uint16_t maskBit15 = 0x8000;
Vernon Mauerya3702c12019-05-22 13:20:59 -070044
45static constexpr const char* objectManagerIntf =
46 "org.freedesktop.DBus.ObjectManager";
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053047static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties";
Vernon Mauerya3702c12019-05-22 13:20:59 -070048static constexpr const char* serviceConfigBasePath =
49 "/xyz/openbmc_project/control/service";
50static constexpr const char* serviceConfigAttrIntf =
51 "xyz.openbmc_project.Control.Service.Attributes";
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053052static constexpr const char* getMgdObjMethod = "GetManagedObjects";
53static constexpr const char* propMasked = "Masked";
Vernon Mauerya3702c12019-05-22 13:20:59 -070054
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053055std::string getServiceConfigMgrName()
Vernon Mauerya3702c12019-05-22 13:20:59 -070056{
Vernon Mauerya3702c12019-05-22 13:20:59 -070057 static std::string serviceCfgMgr{};
58 if (serviceCfgMgr.empty())
59 {
60 try
61 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053062 auto sdbusp = getSdBus();
63 serviceCfgMgr = ipmi::getService(*sdbusp, objectManagerIntf,
Vernon Mauerya3702c12019-05-22 13:20:59 -070064 serviceConfigBasePath);
65 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -050066 catch (const sdbusplus::exception_t& e)
Vernon Mauerya3702c12019-05-22 13:20:59 -070067 {
68 serviceCfgMgr.clear();
69 phosphor::logging::log<phosphor::logging::level::ERR>(
70 "Error: In fetching disabling service manager name");
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053071 return serviceCfgMgr;
Vernon Mauerya3702c12019-05-22 13:20:59 -070072 }
73 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053074 return serviceCfgMgr;
75}
76
77static inline void checkAndThrowError(boost::system::error_code& ec,
78 const std::string& msg)
79{
80 if (ec)
Vernon Mauerya3702c12019-05-22 13:20:59 -070081 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053082 std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg);
83 phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str());
84 throw sdbusplus::exception::SdBusError(-EIO, msgToLog.c_str());
Vernon Mauerya3702c12019-05-22 13:20:59 -070085 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053086 return;
87}
88
89static inline bool getEnabledValue(const DbusInterfaceMap& intfMap)
90{
91 for (const auto& intf : intfMap)
Vernon Mauerya3702c12019-05-22 13:20:59 -070092 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053093 if (intf.first == serviceConfigAttrIntf)
94 {
95 auto it = intf.second.find(propMasked);
96 if (it == intf.second.end())
97 {
98 phosphor::logging::log<phosphor::logging::level::ERR>(
99 "Error: in getting Masked property value");
100 throw sdbusplus::exception::SdBusError(
101 -EIO, "ERROR in reading Masked property value");
102 }
103 // return !Masked value
104 return !std::get<bool>(it->second);
105 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700106 }
James Feist13b00392019-08-19 16:16:08 -0700107 return false;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700108}
109
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530110ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield,
111 uint8_t state, uint16_t serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700112{
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530113 constexpr uint16_t servicesRsvdMask = 0x3F97;
114 constexpr uint8_t enableService = 0x1;
115
116 if ((state > enableService) || (serviceValue & servicesRsvdMask) ||
117 !serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700118 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530119 return ipmi::responseInvalidFieldRequest();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700120 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530121 try
Vernon Mauerya3702c12019-05-22 13:20:59 -0700122 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530123 auto sdbusp = getSdBus();
124 boost::system::error_code ec;
125 auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
126 yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
127 objectManagerIntf, getMgdObjMethod);
128 checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
Vernon Mauerya3702c12019-05-22 13:20:59 -0700129
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530130 for (const auto& services : bmcServices)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700131 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530132 // services.first holds the bit position of the service, check
133 // whether it has to be updated.
134 const uint16_t serviceMask = 1 << services.first;
135 if (!(serviceValue & serviceMask))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700136 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530137 continue;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700138 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530139 for (const auto& obj : objectMap)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700140 {
Jiaqing Zhao95f69332022-06-04 15:09:45 +0800141 if (boost::algorithm::starts_with(obj.first.filename(),
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530142 services.second))
143 {
144 if (state != getEnabledValue(obj.second))
145 {
146 ec.clear();
147 sdbusp->yield_method_call<>(
148 yield, ec, getServiceConfigMgrName().c_str(),
149 obj.first.str, dBusPropIntf, "Set",
150 serviceConfigAttrIntf, propMasked,
151 std::variant<bool>(!state));
152 checkAndThrowError(ec, "Set Masked property failed");
153 // Multiple instances may be present, so continue
154 }
155 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700156 }
157 }
158 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500159 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530160 {
161 return ipmi::responseUnspecifiedError();
162 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700163 return ipmi::responseSuccess();
164}
165
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530166ipmi::RspType<uint16_t> getBmcControlServices(boost::asio::yield_context yield)
167{
168 uint16_t serviceValue = 0;
169 try
170 {
171 auto sdbusp = getSdBus();
172 boost::system::error_code ec;
173 auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
174 yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
175 objectManagerIntf, getMgdObjMethod);
176 checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
177
178 for (const auto& services : bmcServices)
179 {
180 for (const auto& obj : objectMap)
181 {
Jiaqing Zhao95f69332022-06-04 15:09:45 +0800182 if (boost::algorithm::starts_with(obj.first.filename(),
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530183 services.second))
184 {
185 serviceValue |= getEnabledValue(obj.second)
186 << services.first;
187 break;
188 }
189 }
190 }
191 }
Patrick Williamsf944d2e2022-07-22 19:26:52 -0500192 catch (const sdbusplus::exception_t& e)
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530193 {
194 return ipmi::responseUnspecifiedError();
195 }
196 // Bit 14 should match bit 15 as single service maintains Video & USB
197 // redirection
198 serviceValue |= (serviceValue & maskBit15) >> 1;
199 return ipmi::responseSuccess(serviceValue);
200}
201
Vernon Mauerya3702c12019-05-22 13:20:59 -0700202void register_netfn_bmc_control_functions()
203{
Vernon Mauery98bbf692019-09-16 11:14:59 -0700204 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
205 intel::general::cmdControlBmcServices, Privilege::Admin,
206 setBmcControlServices);
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530207
Vernon Mauery98bbf692019-09-16 11:14:59 -0700208 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
209 intel::general::cmdGetBmcServiceStatus, Privilege::User,
210 getBmcControlServices);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700211}
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530212} // namespace ipmi