blob: 870bc6a5aeab0bebc148b3ddd6cb1d1e46f659b1 [file] [log] [blame]
Vernon Mauery9e801a22018-10-12 13:20:49 -07001#include "sol_manager.hpp"
2
3#include "main.hpp"
4#include "sol_context.hpp"
5
Tom Joseph22c5ad32017-03-14 18:04:22 +05306#include <sys/socket.h>
7#include <sys/un.h>
Vernon Mauery9e801a22018-10-12 13:20:49 -07008
Vernon Mauery7e4a6512018-11-09 08:43:36 -08009#include <boost/asio/basic_stream_socket.hpp>
10#include <boost/asio/io_context.hpp>
11#include <boost/asio/local/stream_protocol.hpp>
12#include <boost/asio/write.hpp>
srikanta mondalf6e72302020-06-08 12:46:28 +000013#include <ipmid/utils.hpp>
Tom Joseph22c5ad32017-03-14 18:04:22 +053014#include <phosphor-logging/log.hpp>
Cheng C Yang29086952020-03-09 15:29:18 +080015#include <sdbusplus/message/types.hpp>
16
George Liubc8958f2022-07-04 09:29:49 +080017#include <chrono>
18#include <cmath>
19
Cheng C Yang29086952020-03-09 15:29:18 +080020constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
21constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
22constexpr const char* PROP_INTF = "org.freedesktop.DBus.Properties";
Tom Joseph22c5ad32017-03-14 18:04:22 +053023
24namespace sol
25{
26
27using namespace phosphor::logging;
28
srikanta mondalf6e72302020-06-08 12:46:28 +000029std::unique_ptr<sdbusplus::bus::match_t> matchPtrSOL(nullptr);
Jian Zhangc936eca2022-03-22 11:25:29 +080030std::unique_ptr<sdbusplus::bus::match_t> solConfPropertiesSignal(nullptr);
srikanta mondalf6e72302020-06-08 12:46:28 +000031
Vernon Mauery7e4a6512018-11-09 08:43:36 -080032void Manager::initConsoleSocket()
Tom Josephb81f7612017-04-25 17:59:02 +053033{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080034 // explicit length constructor for NUL-prefixed abstract path
35 std::string path(CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
36 boost::asio::local::stream_protocol::endpoint ep(path);
37 consoleSocket =
38 std::make_unique<boost::asio::local::stream_protocol::socket>(*io);
39 consoleSocket->connect(ep);
Tom Josephb81f7612017-04-25 17:59:02 +053040}
41
Vernon Mauery7e4a6512018-11-09 08:43:36 -080042void Manager::consoleInputHandler()
Tom Joseph22c5ad32017-03-14 18:04:22 +053043{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080044 boost::system::error_code ec;
45 boost::asio::socket_base::bytes_readable cmd(true);
46 consoleSocket->io_control(cmd, ec);
47 size_t readSize;
48 if (!ec)
Tom Joseph22c5ad32017-03-14 18:04:22 +053049 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -080050 readSize = cmd.get();
51 }
52 else
53 {
54 log<level::ERR>("Reading ready count from host console socket failed:",
55 entry("EXCEPTION=%s", ec.message().c_str()));
56 return;
57 }
58 std::vector<uint8_t> buffer(readSize);
59 ec.clear();
60 size_t readDataLen =
61 consoleSocket->read_some(boost::asio::buffer(buffer), ec);
62 if (ec)
63 {
64 log<level::ERR>("Reading from host console socket failed:",
65 entry("EXCEPTION=%s", ec.message().c_str()));
66 return;
Tom Joseph22c5ad32017-03-14 18:04:22 +053067 }
68
Vernon Mauery7e4a6512018-11-09 08:43:36 -080069 // Update the Console buffer with data read from the socket
70 buffer.resize(readDataLen);
71 dataBuffer.write(buffer);
Tom Joseph22c5ad32017-03-14 18:04:22 +053072}
73
Vernon Mauery70fd29c2017-11-30 13:11:43 -080074int Manager::writeConsoleSocket(const std::vector<uint8_t>& input) const
Tom Josephb51f6412017-03-14 18:08:14 +053075{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080076 boost::system::error_code ec;
77 boost::asio::write(*consoleSocket, boost::asio::buffer(input), ec);
78 return ec.value();
79}
Tom Josephb51f6412017-03-14 18:08:14 +053080
Vernon Mauery7e4a6512018-11-09 08:43:36 -080081void Manager::startHostConsole()
82{
83 if (!consoleSocket)
Tom Josephb51f6412017-03-14 18:08:14 +053084 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -080085 initConsoleSocket();
Tom Josephb51f6412017-03-14 18:08:14 +053086 }
srikanta mondalf6e72302020-06-08 12:46:28 +000087
88 // Register callback to close SOL session for disable SSH SOL
89 if (matchPtrSOL == nullptr)
90 {
91 registerSOLServiceChangeCallback();
92 }
93
Vernon Mauery7e4a6512018-11-09 08:43:36 -080094 consoleSocket->async_wait(boost::asio::socket_base::wait_read,
95 [this](const boost::system::error_code& ec) {
96 if (!ec)
97 {
98 consoleInputHandler();
99 startHostConsole();
100 }
101 });
Rashmi RV0f63e012019-11-21 15:38:50 +0530102} // namespace sol
Tom Josephb51f6412017-03-14 18:08:14 +0530103
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800104void Manager::stopHostConsole()
105{
106 if (consoleSocket)
107 {
108 consoleSocket->cancel();
109 consoleSocket.reset();
110 }
Tom Josephb51f6412017-03-14 18:08:14 +0530111}
112
Cheng C Yang29086952020-03-09 15:29:18 +0800113void Manager::updateSOLParameter(uint8_t channelNum)
114{
115 std::variant<uint8_t, bool> value;
116 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection());
117 static std::string solService{};
118 ipmi::PropertyMap properties;
119 std::string ethdevice = ipmi::getChannelName(channelNum);
120 std::string solPathWitheEthName = solPath + ethdevice;
121 if (solService.empty())
122 {
123 try
124 {
125 solService =
126 ipmi::getService(dbus, solInterface, solPathWitheEthName);
127 }
128 catch (const std::runtime_error& e)
129 {
130 solService.clear();
131 phosphor::logging::log<phosphor::logging::level::ERR>(
132 "Error: get SOL service failed");
133 return;
134 }
135 }
136 try
137 {
138 properties = ipmi::getAllDbusProperties(
139 dbus, solService, solPathWitheEthName, solInterface);
140 }
141 catch (const std::runtime_error&)
142 {
143 phosphor::logging::log<phosphor::logging::level::ERR>(
144 "Error setting sol parameter");
145 return;
146 }
147
148 progress = std::get<uint8_t>(properties["Progress"]);
149
150 enable = std::get<bool>(properties["Enable"]);
151
152 forceEncrypt = std::get<bool>(properties["ForceEncryption"]);
153
154 forceAuth = std::get<bool>(properties["ForceAuthentication"]);
155
156 solMinPrivilege = static_cast<session::Privilege>(
157 std::get<uint8_t>(properties["Privilege"]));
158
159 accumulateInterval =
160 std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
161 sol::accIntervalFactor * 1ms;
162
163 sendThreshold = std::get<uint8_t>(properties["Threshold"]);
164
165 retryCount = std::get<uint8_t>(properties["RetryCount"]);
166
167 retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) *
168 sol::retryIntervalFactor * 1ms;
169
170 return;
171}
172
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530173void Manager::startPayloadInstance(uint8_t payloadInstance,
174 session::SessionID sessionID)
175{
176 if (payloadMap.empty())
177 {
Rashmi RV0f63e012019-11-21 15:38:50 +0530178 try
179 {
180 startHostConsole();
181 }
182 catch (const std::exception& e)
183 {
184 log<level::ERR>("Encountered exception when starting host console. "
185 "Hence stopping host console.",
186 entry("EXCEPTION=%s", e.what()));
187 stopHostConsole();
188 throw;
189 }
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530190 }
191
192 // Create the SOL Context data for payload instance
Vernon Mauerya6ad5e12020-02-21 14:54:24 -0800193 std::shared_ptr<Context> context = Context::makeContext(
194 io, retryCount, sendThreshold, payloadInstance, sessionID);
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530195
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530196 payloadMap.emplace(payloadInstance, std::move(context));
197}
198
Tom Joseph4ff14b52017-03-14 18:10:52 +0530199void Manager::stopPayloadInstance(uint8_t payloadInstance)
200{
201 auto iter = payloadMap.find(payloadInstance);
202 if (iter == payloadMap.end())
203 {
204 throw std::runtime_error("SOL Payload instance not found ");
205 }
206
207 payloadMap.erase(iter);
208
Tom Joseph4ff14b52017-03-14 18:10:52 +0530209 if (payloadMap.empty())
210 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800211 stopHostConsole();
Tom Josephde203ce2017-08-01 16:48:06 +0530212
213 dataBuffer.erase(dataBuffer.size());
Tom Joseph4ff14b52017-03-14 18:10:52 +0530214 }
215}
216
srikanta mondalf6e72302020-06-08 12:46:28 +0000217void Manager::stopAllPayloadInstance()
218{
219 // Erase all payload instance
220 payloadMap.erase(payloadMap.begin(), payloadMap.end());
221
222 stopHostConsole();
223
224 dataBuffer.erase(dataBuffer.size());
225}
226
227void registerSOLServiceChangeCallback()
228{
229 using namespace sdbusplus::bus::match::rules;
230 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
231 try
232 {
233 auto servicePath = ipmi::getDbusObject(
234 bus, "xyz.openbmc_project.Control.Service.Attributes",
235 "/xyz/openbmc_project/control/service", "obmc_2dconsole");
236
237 if (!std::empty(servicePath.first))
238 {
239 matchPtrSOL = std::make_unique<sdbusplus::bus::match_t>(
240 bus,
241 path_namespace(servicePath.first) +
242 "arg0namespace='xyz.openbmc_project.Control.Service."
243 "Attributes'"
244 ", " +
245 type::signal() + member("PropertiesChanged") +
246 interface("org.freedesktop.DBus.Properties"),
247 [](sdbusplus::message::message& msg) {
248 std::string intfName;
249 std::map<std::string, std::variant<bool>> properties;
250 msg.read(intfName, properties);
251
252 const auto it = properties.find("Enabled");
253 if (it != properties.end())
254 {
255 const bool* state = std::get_if<bool>(&it->second);
256
257 if (state != nullptr && *state == false)
258 {
259 // Stop all the payload session.
Vernon Mauery2085ae02021-06-10 11:51:00 -0700260 sol::Manager::get().stopAllPayloadInstance();
srikanta mondalf6e72302020-06-08 12:46:28 +0000261 }
262 }
263 });
264 }
265 }
Patrick Williams12d199b2021-10-06 12:36:48 -0500266 catch (const sdbusplus::exception_t& e)
srikanta mondalf6e72302020-06-08 12:46:28 +0000267 {
268 log<level::ERR>(
269 "Failed to get service path in registerSOLServiceChangeCallback");
270 }
271}
272
Jian Zhangc936eca2022-03-22 11:25:29 +0800273void procSolConfChange(sdbusplus::message::message& msg)
274{
275 using SolConfVariant = std::variant<bool, uint8_t>;
276 using SolConfProperties =
277 std::vector<std::pair<std::string, SolConfVariant>>;
278
279 std::string iface;
280 SolConfProperties properties;
281
282 try
283 {
284 msg.read(iface, properties);
285 }
286 catch (const std::exception& e)
287 {
288 phosphor::logging::log<phosphor::logging::level::ERR>(
289 "procSolConfChange get properties FAIL",
290 entry("ERROR=%s", e.what()));
291 return;
292 }
293
294 for (const auto& prop : properties)
295 {
296 if (prop.first == "Progress")
297 {
298 sol::Manager::get().progress = std::get<uint8_t>(prop.second);
299 }
300 else if (prop.first == "Enable")
301 {
302 sol::Manager::get().enable = std::get<bool>(prop.second);
303 }
304 else if (prop.first == "ForceEncryption")
305 {
306 sol::Manager::get().forceEncrypt = std::get<bool>(prop.second);
307 }
308 else if (prop.first == "ForceAuthentication")
309 {
310 sol::Manager::get().forceAuth = std::get<bool>(prop.second);
311 }
312 else if (prop.first == "Privilege")
313 {
314 sol::Manager::get().solMinPrivilege =
315 static_cast<session::Privilege>(std::get<uint8_t>(prop.second));
316 }
317 else if (prop.first == "AccumulateIntervalMS")
318 {
319 sol::Manager::get().accumulateInterval =
320 std::get<uint8_t>(prop.second) * sol::accIntervalFactor * 1ms;
321 }
322 else if (prop.first == "Threshold")
323 {
324 sol::Manager::get().sendThreshold = std::get<uint8_t>(prop.second);
325 }
326 else if (prop.first == "RetryCount")
327 {
328 sol::Manager::get().retryCount = std::get<uint8_t>(prop.second);
329 }
330 else if (prop.first == "RetryIntervalMS")
331 {
332 sol::Manager::get().retryInterval =
333 std::get<uint8_t>(prop.second) * sol::retryIntervalFactor * 1ms;
334 }
335 }
336}
337
338void registerSolConfChangeCallbackHandler(std::string channel)
339{
340 if (solConfPropertiesSignal == nullptr)
341 {
342 using namespace sdbusplus::bus::match::rules;
343 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
344 try
345 {
346 auto servicePath = solPath + channel;
347
348 solConfPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
349 bus, propertiesChangedNamespace(servicePath, solInterface),
350 procSolConfChange);
351 }
352 catch (const sdbusplus::exception_t& e)
353 {
354 log<level::ERR>("Failed to get service path in "
355 "registerSolConfChangeCallbackHandler",
356 entry("CHANNEL=%s", channel.c_str()));
357 }
358 }
359 return;
360}
361
Tom Joseph22c5ad32017-03-14 18:04:22 +0530362} // namespace sol