blob: 838689900e1e0618386646fb93bac1c613db77a9 [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 }
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 {
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530141 if (boost::algorithm::starts_with(obj.first.str,
142 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 }
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530159 catch (sdbusplus::exception::SdBusError& e)
160 {
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 {
182 if (boost::algorithm::starts_with(obj.first.str,
183 services.second))
184 {
185 serviceValue |= getEnabledValue(obj.second)
186 << services.first;
187 break;
188 }
189 }
190 }
191 }
192 catch (sdbusplus::exception::SdBusError& e)
193 {
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{
204 ipmi::registerHandler(ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
205 static_cast<ipmi_cmd_t>(
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530206 IPMINetFnIntelOemGeneralCmds::controlBmcServices),
207 ipmi::Privilege::Admin, setBmcControlServices);
208
209 ipmi::registerHandler(
210 ipmi::prioOpenBmcBase, netfnIntcOEMGeneral,
211 static_cast<ipmi_cmd_t>(
212 IPMINetFnIntelOemGeneralCmds::getBmcServiceStatus),
213 ipmi::Privilege::User, getBmcControlServices);
Vernon Mauerya3702c12019-05-22 13:20:59 -0700214}
Richard Marian Thomaiyaredf25e62019-06-11 01:14:49 +0530215} // namespace ipmi