blob: 17c850a262f6063887c72ea8c0cc5f7105f70ef3 [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"},
Jiaqing Zhaoc9290e72022-01-05 12:57:11 +080040 {solServiceBitPos,
41 "/xyz/openbmc_project/control/service/obmc_2dconsole_2dssh"},
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053042 {kvmServiceBitPos, "/xyz/openbmc_project/control/service/start_2dipkvm"},
Vernon Mauerya3702c12019-05-22 13:20:59 -070043};
44
Arun P. Mohanan98cb6182021-08-31 19:49:19 +053045static constexpr uint16_t maskBit15 = 0x8000;
Vernon Mauerya3702c12019-05-22 13:20:59 -070046
47static constexpr const char* objectManagerIntf =
48 "org.freedesktop.DBus.ObjectManager";
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053049static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties";
Vernon Mauerya3702c12019-05-22 13:20:59 -070050static constexpr const char* serviceConfigBasePath =
51 "/xyz/openbmc_project/control/service";
52static constexpr const char* serviceConfigAttrIntf =
53 "xyz.openbmc_project.Control.Service.Attributes";
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053054static constexpr const char* getMgdObjMethod = "GetManagedObjects";
55static constexpr const char* propMasked = "Masked";
Vernon Mauerya3702c12019-05-22 13:20:59 -070056
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053057std::string getServiceConfigMgrName()
Vernon Mauerya3702c12019-05-22 13:20:59 -070058{
Vernon Mauerya3702c12019-05-22 13:20:59 -070059 static std::string serviceCfgMgr{};
60 if (serviceCfgMgr.empty())
61 {
62 try
63 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053064 auto sdbusp = getSdBus();
65 serviceCfgMgr = ipmi::getService(*sdbusp, objectManagerIntf,
Vernon Mauerya3702c12019-05-22 13:20:59 -070066 serviceConfigBasePath);
67 }
Patrick Williams69245b72021-09-02 09:23:01 -050068 catch (const sdbusplus::exception::exception& e)
Vernon Mauerya3702c12019-05-22 13:20:59 -070069 {
70 serviceCfgMgr.clear();
71 phosphor::logging::log<phosphor::logging::level::ERR>(
72 "Error: In fetching disabling service manager name");
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053073 return serviceCfgMgr;
Vernon Mauerya3702c12019-05-22 13:20:59 -070074 }
75 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053076 return serviceCfgMgr;
77}
78
79static inline void checkAndThrowError(boost::system::error_code& ec,
80 const std::string& msg)
81{
82 if (ec)
Vernon Mauerya3702c12019-05-22 13:20:59 -070083 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053084 std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg);
85 phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str());
86 throw sdbusplus::exception::SdBusError(-EIO, msgToLog.c_str());
Vernon Mauerya3702c12019-05-22 13:20:59 -070087 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053088 return;
89}
90
91static inline bool getEnabledValue(const DbusInterfaceMap& intfMap)
92{
93 for (const auto& intf : intfMap)
Vernon Mauerya3702c12019-05-22 13:20:59 -070094 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053095 if (intf.first == serviceConfigAttrIntf)
96 {
97 auto it = intf.second.find(propMasked);
98 if (it == intf.second.end())
99 {
100 phosphor::logging::log<phosphor::logging::level::ERR>(
101 "Error: in getting Masked property value");
102 throw sdbusplus::exception::SdBusError(
103 -EIO, "ERROR in reading Masked property value");
104 }
105 // return !Masked value
106 return !std::get<bool>(it->second);
107 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700108 }
James Feist13b00392019-08-19 16:16:08 -0700109 return false;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700110}
111
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530112ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield,
113 uint8_t state, uint16_t serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700114{
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530115 constexpr uint16_t servicesRsvdMask = 0x3F97;
116 constexpr uint8_t enableService = 0x1;
117
118 if ((state > enableService) || (serviceValue & servicesRsvdMask) ||
119 !serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700120 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530121 return ipmi::responseInvalidFieldRequest();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700122 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530123 try
Vernon Mauerya3702c12019-05-22 13:20:59 -0700124 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530125 auto sdbusp = getSdBus();
126 boost::system::error_code ec;
127 auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
128 yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
129 objectManagerIntf, getMgdObjMethod);
130 checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
Vernon Mauerya3702c12019-05-22 13:20:59 -0700131
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530132 for (const auto& services : bmcServices)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700133 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530134 // services.first holds the bit position of the service, check
135 // whether it has to be updated.
136 const uint16_t serviceMask = 1 << services.first;
137 if (!(serviceValue & serviceMask))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700138 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530139 continue;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700140 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530141 for (const auto& obj : objectMap)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700142 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530143 if (boost::algorithm::starts_with(obj.first.str,
144 services.second))
145 {
146 if (state != getEnabledValue(obj.second))
147 {
148 ec.clear();
149 sdbusp->yield_method_call<>(
150 yield, ec, getServiceConfigMgrName().c_str(),
151 obj.first.str, dBusPropIntf, "Set",
152 serviceConfigAttrIntf, propMasked,
153 std::variant<bool>(!state));
154 checkAndThrowError(ec, "Set Masked property failed");
155 // Multiple instances may be present, so continue
156 }
157 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700158 }
159 }
160 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500161 catch (const sdbusplus::exception::exception& e)
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530162 {
163 return ipmi::responseUnspecifiedError();
164 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700165 return ipmi::responseSuccess();
166}
167
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530168ipmi::RspType<uint16_t> getBmcControlServices(boost::asio::yield_context yield)
169{
170 uint16_t serviceValue = 0;
171 try
172 {
173 auto sdbusp = getSdBus();
174 boost::system::error_code ec;
175 auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
176 yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
177 objectManagerIntf, getMgdObjMethod);
178 checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
179
180 for (const auto& services : bmcServices)
181 {
182 for (const auto& obj : objectMap)
183 {
184 if (boost::algorithm::starts_with(obj.first.str,
185 services.second))
186 {
187 serviceValue |= getEnabledValue(obj.second)
188 << services.first;
189 break;
190 }
191 }
192 }
193 }
Patrick Williamsbd51e6a2021-10-06 13:09:44 -0500194 catch (const sdbusplus::exception::exception& e)
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530195 {
196 return ipmi::responseUnspecifiedError();
197 }
198 // Bit 14 should match bit 15 as single service maintains Video & USB
199 // redirection
200 serviceValue |= (serviceValue & maskBit15) >> 1;
201 return ipmi::responseSuccess(serviceValue);
202}
203
Vernon Mauerya3702c12019-05-22 13:20:59 -0700204void register_netfn_bmc_control_functions()
205{
Vernon Mauery98bbf692019-09-16 11:14:59 -0700206 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
207 intel::general::cmdControlBmcServices, Privilege::Admin,
208 setBmcControlServices);
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530209
Vernon Mauery98bbf692019-09-16 11:14:59 -0700210 registerHandler(prioOpenBmcBase, intel::netFnGeneral,
211 intel::general::cmdGetBmcServiceStatus, Privilege::User,
212 getBmcControlServices);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700213}
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530214} // namespace ipmi