blob: b446886b3bd401fd6992ad7d3058c1e3577bb1e2 [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>
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053023#include <variant>
Vernon Mauerya3702c12019-05-22 13:20:59 -070024
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053025namespace ipmi
26{
Vernon Mauerya3702c12019-05-22 13:20:59 -070027void register_netfn_bmc_control_functions() __attribute__((constructor));
28
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053029static constexpr uint8_t rmcpServiceBitPos = 3;
30static constexpr uint8_t webServiceBitPos = 5;
31static constexpr uint8_t solServiceBitPos = 6;
32static constexpr uint8_t kvmServiceBitPos = 15;
33
34static const std::unordered_map<uint8_t, std::string> bmcServices = {
35 // {bit position for service, service object path}
36 {rmcpServiceBitPos,
37 "/xyz/openbmc_project/control/service/phosphor_2dipmi_2dnet"},
38 {webServiceBitPos, "/xyz/openbmc_project/control/service/bmcweb"},
39 {solServiceBitPos, "/xyz/openbmc_project/control/service/obmc_2dconsole"},
40 {kvmServiceBitPos, "/xyz/openbmc_project/control/service/start_2dipkvm"},
Vernon Mauerya3702c12019-05-22 13:20:59 -070041};
42
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +053043static constexpr uint16_t maskBit15 = 0xF000;
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 }
66 catch (const sdbusplus::exception::SdBusError& e)
67 {
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 }
107}
108
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530109ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield,
110 uint8_t state, uint16_t serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700111{
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530112 constexpr uint16_t servicesRsvdMask = 0x3F97;
113 constexpr uint8_t enableService = 0x1;
114
115 if ((state > enableService) || (serviceValue & servicesRsvdMask) ||
116 !serviceValue)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700117 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530118 return ipmi::responseInvalidFieldRequest();
Vernon Mauerya3702c12019-05-22 13:20:59 -0700119 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530120 try
Vernon Mauerya3702c12019-05-22 13:20:59 -0700121 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530122 auto sdbusp = getSdBus();
123 boost::system::error_code ec;
124 auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
125 yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
126 objectManagerIntf, getMgdObjMethod);
127 checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
Vernon Mauerya3702c12019-05-22 13:20:59 -0700128
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530129 for (const auto& services : bmcServices)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700130 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530131 // services.first holds the bit position of the service, check
132 // whether it has to be updated.
133 const uint16_t serviceMask = 1 << services.first;
134 if (!(serviceValue & serviceMask))
Vernon Mauerya3702c12019-05-22 13:20:59 -0700135 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530136 continue;
Vernon Mauerya3702c12019-05-22 13:20:59 -0700137 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530138 for (const auto& obj : objectMap)
Vernon Mauerya3702c12019-05-22 13:20:59 -0700139 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530140 if (boost::algorithm::starts_with(obj.first.str,
141 services.second))
142 {
143 if (state != getEnabledValue(obj.second))
144 {
145 ec.clear();
146 sdbusp->yield_method_call<>(
147 yield, ec, getServiceConfigMgrName().c_str(),
148 obj.first.str, dBusPropIntf, "Set",
149 serviceConfigAttrIntf, propMasked,
150 std::variant<bool>(!state));
151 checkAndThrowError(ec, "Set Masked property failed");
152 // Multiple instances may be present, so continue
153 }
154 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700155 }
156 }
157 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530158 catch (sdbusplus::exception::SdBusError& e)
159 {
160 return ipmi::responseUnspecifiedError();
161 }
Vernon Mauerya3702c12019-05-22 13:20:59 -0700162 return ipmi::responseSuccess();
163}
164
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530165ipmi::RspType<uint16_t> getBmcControlServices(boost::asio::yield_context yield)
166{
167 uint16_t serviceValue = 0;
168 try
169 {
170 auto sdbusp = getSdBus();
171 boost::system::error_code ec;
172 auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
173 yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
174 objectManagerIntf, getMgdObjMethod);
175 checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
176
177 for (const auto& services : bmcServices)
178 {
179 for (const auto& obj : objectMap)
180 {
181 if (boost::algorithm::starts_with(obj.first.str,
182 services.second))
183 {
184 serviceValue |= getEnabledValue(obj.second)
185 << services.first;
186 break;
187 }
188 }
189 }
190 }
191 catch (sdbusplus::exception::SdBusError& e)
192 {
193 return ipmi::responseUnspecifiedError();
194 }
195 // Bit 14 should match bit 15 as single service maintains Video & USB
196 // redirection
197 serviceValue |= (serviceValue & maskBit15) >> 1;
198 return ipmi::responseSuccess(serviceValue);
199}
200
Vernon Mauerya3702c12019-05-22 13:20:59 -0700201void register_netfn_bmc_control_functions()
202{
203 ipmi::registerHandler(ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
204 static_cast<ipmi_cmd_t>(
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530205 IPMINetFnIntelOemGeneralCmds::controlBmcServices),
206 ipmi::Privilege::Admin, setBmcControlServices);
207
208 ipmi::registerHandler(
209 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
210 static_cast<ipmi_cmd_t>(
211 IPMINetFnIntelOemGeneralCmds::getBmcServiceStatus),
212 ipmi::Privilege::User, getBmcControlServices);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700213}
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530214} // namespace ipmi