1a3702c1fSVernon Mauery /*
2a3702c1fSVernon Mauery // Copyright (c) 2018 Intel Corporation
3a3702c1fSVernon Mauery //
4a3702c1fSVernon Mauery // Licensed under the Apache License, Version 2.0 (the "License");
5a3702c1fSVernon Mauery // you may not use this file except in compliance with the License.
6a3702c1fSVernon Mauery // You may obtain a copy of the License at
7a3702c1fSVernon Mauery //
8a3702c1fSVernon Mauery //      http://www.apache.org/licenses/LICENSE-2.0
9a3702c1fSVernon Mauery //
10a3702c1fSVernon Mauery // Unless required by applicable law or agreed to in writing, software
11a3702c1fSVernon Mauery // distributed under the License is distributed on an "AS IS" BASIS,
12a3702c1fSVernon Mauery // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13a3702c1fSVernon Mauery // See the License for the specific language governing permissions and
14a3702c1fSVernon Mauery // limitations under the License.
15a3702c1fSVernon Mauery */
16a3702c1fSVernon Mauery 
17a3702c1fSVernon Mauery #include "oemcommands.hpp"
18a3702c1fSVernon Mauery 
19edf25e61SRichard Marian Thomaiyar #include <boost/algorithm/string.hpp>
20a3702c1fSVernon Mauery #include <ipmid/api.hpp>
21a3702c1fSVernon Mauery #include <ipmid/utils.hpp>
22a3702c1fSVernon Mauery #include <phosphor-logging/log.hpp>
23*0748c69dSJason M. Bills #include <types.hpp>
24fcd2d3a9SJames Feist 
25edf25e61SRichard Marian Thomaiyar #include <variant>
26a3702c1fSVernon Mauery 
27edf25e61SRichard Marian Thomaiyar namespace ipmi
28edf25e61SRichard Marian Thomaiyar {
29a3702c1fSVernon Mauery void register_netfn_bmc_control_functions() __attribute__((constructor));
30a3702c1fSVernon Mauery 
31edf25e61SRichard Marian Thomaiyar static constexpr uint8_t rmcpServiceBitPos = 3;
32edf25e61SRichard Marian Thomaiyar static constexpr uint8_t webServiceBitPos = 5;
33edf25e61SRichard Marian Thomaiyar static constexpr uint8_t solServiceBitPos = 6;
34edf25e61SRichard Marian Thomaiyar static constexpr uint8_t kvmServiceBitPos = 15;
35edf25e61SRichard Marian Thomaiyar 
3695f69336SJiaqing Zhao static constexpr std::array<std::pair<uint8_t, const char*>, 4> bmcServices = {{
3795f69336SJiaqing Zhao     // {bit position for service, service name}
3895f69336SJiaqing Zhao     {rmcpServiceBitPos, "phosphor-ipmi-net"},
3995f69336SJiaqing Zhao     {webServiceBitPos, "bmcweb"},
4095f69336SJiaqing Zhao     {solServiceBitPos, "obmc-console-ssh"},
4195f69336SJiaqing Zhao     {kvmServiceBitPos, "start-ipkvm"},
4295f69336SJiaqing Zhao }};
43a3702c1fSVernon Mauery 
4498cb6186SArun P. Mohanan static constexpr uint16_t maskBit15 = 0x8000;
45a3702c1fSVernon Mauery 
46a3702c1fSVernon Mauery static constexpr const char* objectManagerIntf =
47a3702c1fSVernon Mauery     "org.freedesktop.DBus.ObjectManager";
48edf25e61SRichard Marian Thomaiyar static constexpr const char* dBusPropIntf = "org.freedesktop.DBus.Properties";
49a3702c1fSVernon Mauery static constexpr const char* serviceConfigBasePath =
50a3702c1fSVernon Mauery     "/xyz/openbmc_project/control/service";
51a3702c1fSVernon Mauery static constexpr const char* serviceConfigAttrIntf =
52a3702c1fSVernon Mauery     "xyz.openbmc_project.Control.Service.Attributes";
53edf25e61SRichard Marian Thomaiyar static constexpr const char* getMgdObjMethod = "GetManagedObjects";
54edf25e61SRichard Marian Thomaiyar static constexpr const char* propMasked = "Masked";
55a3702c1fSVernon Mauery 
getServiceConfigMgrName()56edf25e61SRichard Marian Thomaiyar std::string getServiceConfigMgrName()
57a3702c1fSVernon Mauery {
58a3702c1fSVernon Mauery     static std::string serviceCfgMgr{};
59a3702c1fSVernon Mauery     if (serviceCfgMgr.empty())
60a3702c1fSVernon Mauery     {
61a3702c1fSVernon Mauery         try
62a3702c1fSVernon Mauery         {
63edf25e61SRichard Marian Thomaiyar             auto sdbusp = getSdBus();
64edf25e61SRichard Marian Thomaiyar             serviceCfgMgr = ipmi::getService(*sdbusp, objectManagerIntf,
65a3702c1fSVernon Mauery                                              serviceConfigBasePath);
66a3702c1fSVernon Mauery         }
67f944d2e5SPatrick Williams         catch (const sdbusplus::exception_t& e)
68a3702c1fSVernon Mauery         {
69a3702c1fSVernon Mauery             serviceCfgMgr.clear();
70a3702c1fSVernon Mauery             phosphor::logging::log<phosphor::logging::level::ERR>(
71a3702c1fSVernon Mauery                 "Error: In fetching disabling service manager name");
72edf25e61SRichard Marian Thomaiyar             return serviceCfgMgr;
73a3702c1fSVernon Mauery         }
74a3702c1fSVernon Mauery     }
75edf25e61SRichard Marian Thomaiyar     return serviceCfgMgr;
76edf25e61SRichard Marian Thomaiyar }
77edf25e61SRichard Marian Thomaiyar 
checkAndThrowError(boost::system::error_code & ec,const std::string & msg)78edf25e61SRichard Marian Thomaiyar static inline void checkAndThrowError(boost::system::error_code& ec,
79edf25e61SRichard Marian Thomaiyar                                       const std::string& msg)
80a3702c1fSVernon Mauery {
81edf25e61SRichard Marian Thomaiyar     if (ec)
82edf25e61SRichard Marian Thomaiyar     {
83edf25e61SRichard Marian Thomaiyar         std::string msgToLog = ec.message() + (msg.empty() ? "" : " - " + msg);
84edf25e61SRichard Marian Thomaiyar         phosphor::logging::log<phosphor::logging::level::ERR>(msgToLog.c_str());
85edf25e61SRichard Marian Thomaiyar         throw sdbusplus::exception::SdBusError(-EIO, msgToLog.c_str());
86a3702c1fSVernon Mauery     }
87edf25e61SRichard Marian Thomaiyar     return;
88edf25e61SRichard Marian Thomaiyar }
89edf25e61SRichard Marian Thomaiyar 
getEnabledValue(const DbusInterfaceMap & intfMap)90edf25e61SRichard Marian Thomaiyar static inline bool getEnabledValue(const DbusInterfaceMap& intfMap)
91edf25e61SRichard Marian Thomaiyar {
92edf25e61SRichard Marian Thomaiyar     for (const auto& intf : intfMap)
93edf25e61SRichard Marian Thomaiyar     {
94edf25e61SRichard Marian Thomaiyar         if (intf.first == serviceConfigAttrIntf)
95edf25e61SRichard Marian Thomaiyar         {
96edf25e61SRichard Marian Thomaiyar             auto it = intf.second.find(propMasked);
97edf25e61SRichard Marian Thomaiyar             if (it == intf.second.end())
98a3702c1fSVernon Mauery             {
99a3702c1fSVernon Mauery                 phosphor::logging::log<phosphor::logging::level::ERR>(
100edf25e61SRichard Marian Thomaiyar                     "Error: in getting Masked property value");
101edf25e61SRichard Marian Thomaiyar                 throw sdbusplus::exception::SdBusError(
102edf25e61SRichard Marian Thomaiyar                     -EIO, "ERROR in reading Masked property value");
103edf25e61SRichard Marian Thomaiyar             }
104edf25e61SRichard Marian Thomaiyar             // return !Masked value
105edf25e61SRichard Marian Thomaiyar             return !std::get<bool>(it->second);
106edf25e61SRichard Marian Thomaiyar         }
107a3702c1fSVernon Mauery     }
10813b0039dSJames Feist     return false;
109a3702c1fSVernon Mauery }
110a3702c1fSVernon Mauery 
setBmcControlServices(boost::asio::yield_context yield,uint8_t state,uint16_t serviceValue)111edf25e61SRichard Marian Thomaiyar ipmi::RspType<> setBmcControlServices(boost::asio::yield_context yield,
112edf25e61SRichard Marian Thomaiyar                                       uint8_t state, uint16_t serviceValue)
113edf25e61SRichard Marian Thomaiyar {
114edf25e61SRichard Marian Thomaiyar     constexpr uint16_t servicesRsvdMask = 0x3F97;
115edf25e61SRichard Marian Thomaiyar     constexpr uint8_t enableService = 0x1;
116a3702c1fSVernon Mauery 
117edf25e61SRichard Marian Thomaiyar     if ((state > enableService) || (serviceValue & servicesRsvdMask) ||
118edf25e61SRichard Marian Thomaiyar         !serviceValue)
119a3702c1fSVernon Mauery     {
120edf25e61SRichard Marian Thomaiyar         return ipmi::responseInvalidFieldRequest();
121a3702c1fSVernon Mauery     }
122edf25e61SRichard Marian Thomaiyar     try
123edf25e61SRichard Marian Thomaiyar     {
124edf25e61SRichard Marian Thomaiyar         auto sdbusp = getSdBus();
125edf25e61SRichard Marian Thomaiyar         boost::system::error_code ec;
126edf25e61SRichard Marian Thomaiyar         auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
127edf25e61SRichard Marian Thomaiyar             yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
128edf25e61SRichard Marian Thomaiyar             objectManagerIntf, getMgdObjMethod);
129edf25e61SRichard Marian Thomaiyar         checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
130a3702c1fSVernon Mauery 
131edf25e61SRichard Marian Thomaiyar         for (const auto& services : bmcServices)
132a3702c1fSVernon Mauery         {
133edf25e61SRichard Marian Thomaiyar             // services.first holds the bit position of the service, check
134edf25e61SRichard Marian Thomaiyar             // whether it has to be updated.
135edf25e61SRichard Marian Thomaiyar             const uint16_t serviceMask = 1 << services.first;
136edf25e61SRichard Marian Thomaiyar             if (!(serviceValue & serviceMask))
137edf25e61SRichard Marian Thomaiyar             {
138edf25e61SRichard Marian Thomaiyar                 continue;
139a3702c1fSVernon Mauery             }
140edf25e61SRichard Marian Thomaiyar             for (const auto& obj : objectMap)
141a3702c1fSVernon Mauery             {
14295f69336SJiaqing Zhao                 if (boost::algorithm::starts_with(obj.first.filename(),
143edf25e61SRichard Marian Thomaiyar                                                   services.second))
144a3702c1fSVernon Mauery                 {
145edf25e61SRichard Marian Thomaiyar                     if (state != getEnabledValue(obj.second))
146a3702c1fSVernon Mauery                     {
147edf25e61SRichard Marian Thomaiyar                         ec.clear();
148edf25e61SRichard Marian Thomaiyar                         sdbusp->yield_method_call<>(
149edf25e61SRichard Marian Thomaiyar                             yield, ec, getServiceConfigMgrName().c_str(),
150edf25e61SRichard Marian Thomaiyar                             obj.first.str, dBusPropIntf, "Set",
151edf25e61SRichard Marian Thomaiyar                             serviceConfigAttrIntf, propMasked,
152*0748c69dSJason M. Bills                             ipmi::DbusVariant(!state));
153edf25e61SRichard Marian Thomaiyar                         checkAndThrowError(ec, "Set Masked property failed");
154edf25e61SRichard Marian Thomaiyar                         // Multiple instances may be present, so continue
155a3702c1fSVernon Mauery                     }
156a3702c1fSVernon Mauery                 }
157a3702c1fSVernon Mauery             }
158edf25e61SRichard Marian Thomaiyar         }
159edf25e61SRichard Marian Thomaiyar     }
160f944d2e5SPatrick Williams     catch (const sdbusplus::exception_t& e)
161edf25e61SRichard Marian Thomaiyar     {
162edf25e61SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
163edf25e61SRichard Marian Thomaiyar     }
164a3702c1fSVernon Mauery     return ipmi::responseSuccess();
165a3702c1fSVernon Mauery }
166a3702c1fSVernon Mauery 
getBmcControlServices(boost::asio::yield_context yield)167edf25e61SRichard Marian Thomaiyar ipmi::RspType<uint16_t> getBmcControlServices(boost::asio::yield_context yield)
168edf25e61SRichard Marian Thomaiyar {
169edf25e61SRichard Marian Thomaiyar     uint16_t serviceValue = 0;
170edf25e61SRichard Marian Thomaiyar     try
171edf25e61SRichard Marian Thomaiyar     {
172edf25e61SRichard Marian Thomaiyar         auto sdbusp = getSdBus();
173edf25e61SRichard Marian Thomaiyar         boost::system::error_code ec;
174edf25e61SRichard Marian Thomaiyar         auto objectMap = sdbusp->yield_method_call<ObjectValueTree>(
175edf25e61SRichard Marian Thomaiyar             yield, ec, getServiceConfigMgrName().c_str(), serviceConfigBasePath,
176edf25e61SRichard Marian Thomaiyar             objectManagerIntf, getMgdObjMethod);
177edf25e61SRichard Marian Thomaiyar         checkAndThrowError(ec, "GetMangagedObjects for service cfg failed");
178edf25e61SRichard Marian Thomaiyar 
179edf25e61SRichard Marian Thomaiyar         for (const auto& services : bmcServices)
180edf25e61SRichard Marian Thomaiyar         {
181edf25e61SRichard Marian Thomaiyar             for (const auto& obj : objectMap)
182edf25e61SRichard Marian Thomaiyar             {
18395f69336SJiaqing Zhao                 if (boost::algorithm::starts_with(obj.first.filename(),
184edf25e61SRichard Marian Thomaiyar                                                   services.second))
185edf25e61SRichard Marian Thomaiyar                 {
186edf25e61SRichard Marian Thomaiyar                     serviceValue |= getEnabledValue(obj.second)
187edf25e61SRichard Marian Thomaiyar                                     << services.first;
188edf25e61SRichard Marian Thomaiyar                     break;
189edf25e61SRichard Marian Thomaiyar                 }
190edf25e61SRichard Marian Thomaiyar             }
191edf25e61SRichard Marian Thomaiyar         }
192edf25e61SRichard Marian Thomaiyar     }
193f944d2e5SPatrick Williams     catch (const sdbusplus::exception_t& e)
194edf25e61SRichard Marian Thomaiyar     {
195edf25e61SRichard Marian Thomaiyar         return ipmi::responseUnspecifiedError();
196edf25e61SRichard Marian Thomaiyar     }
197edf25e61SRichard Marian Thomaiyar     // Bit 14 should match bit 15 as single service maintains Video & USB
198edf25e61SRichard Marian Thomaiyar     // redirection
199edf25e61SRichard Marian Thomaiyar     serviceValue |= (serviceValue & maskBit15) >> 1;
200edf25e61SRichard Marian Thomaiyar     return ipmi::responseSuccess(serviceValue);
201edf25e61SRichard Marian Thomaiyar }
202edf25e61SRichard Marian Thomaiyar 
register_netfn_bmc_control_functions()203a3702c1fSVernon Mauery void register_netfn_bmc_control_functions()
204a3702c1fSVernon Mauery {
20598bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
20698bbf69aSVernon Mauery                     intel::general::cmdControlBmcServices, Privilege::Admin,
20798bbf69aSVernon Mauery                     setBmcControlServices);
208edf25e61SRichard Marian Thomaiyar 
20998bbf69aSVernon Mauery     registerHandler(prioOpenBmcBase, intel::netFnGeneral,
21098bbf69aSVernon Mauery                     intel::general::cmdGetBmcServiceStatus, Privilege::User,
21198bbf69aSVernon Mauery                     getBmcControlServices);
212a3702c1fSVernon Mauery }
213edf25e61SRichard Marian Thomaiyar } // namespace ipmi
214