19e801a2bSVernon Mauery #include "sol_manager.hpp"
29e801a2bSVernon Mauery
39e801a2bSVernon Mauery #include "main.hpp"
49e801a2bSVernon Mauery #include "sol_context.hpp"
59e801a2bSVernon Mauery
622c5ad34STom Joseph #include <sys/socket.h>
722c5ad34STom Joseph #include <sys/un.h>
89e801a2bSVernon Mauery
97e4a6517SVernon Mauery #include <boost/asio/basic_stream_socket.hpp>
107e4a6517SVernon Mauery #include <boost/asio/io_context.hpp>
117e4a6517SVernon Mauery #include <boost/asio/local/stream_protocol.hpp>
127e4a6517SVernon Mauery #include <boost/asio/write.hpp>
13f6e7230dSsrikanta mondal #include <ipmid/utils.hpp>
147b7f25f7SGeorge Liu #include <phosphor-logging/lg2.hpp>
1529086950SCheng C Yang #include <sdbusplus/message/types.hpp>
1629086950SCheng C Yang
17bc8958feSGeorge Liu #include <chrono>
18bc8958feSGeorge Liu #include <cmath>
19bc8958feSGeorge Liu
2029086950SCheng C Yang constexpr const char* solInterface = "xyz.openbmc_project.Ipmi.SOL";
2129086950SCheng C Yang constexpr const char* solPath = "/xyz/openbmc_project/ipmi/sol/";
2222c5ad34STom Joseph
2322c5ad34STom Joseph namespace sol
2422c5ad34STom Joseph {
2522c5ad34STom Joseph
26f6e7230dSsrikanta mondal std::unique_ptr<sdbusplus::bus::match_t> matchPtrSOL(nullptr);
27c936ecaaSJian Zhang std::unique_ptr<sdbusplus::bus::match_t> solConfPropertiesSignal(nullptr);
28f6e7230dSsrikanta mondal
initConsoleSocket()297e4a6517SVernon Mauery void Manager::initConsoleSocket()
30b81f7617STom Joseph {
317e4a6517SVernon Mauery // explicit length constructor for NUL-prefixed abstract path
327e4a6517SVernon Mauery std::string path(CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
337e4a6517SVernon Mauery boost::asio::local::stream_protocol::endpoint ep(path);
347e4a6517SVernon Mauery consoleSocket =
357e4a6517SVernon Mauery std::make_unique<boost::asio::local::stream_protocol::socket>(*io);
367e4a6517SVernon Mauery consoleSocket->connect(ep);
37b81f7617STom Joseph }
38b81f7617STom Joseph
consoleInputHandler()397e4a6517SVernon Mauery void Manager::consoleInputHandler()
4022c5ad34STom Joseph {
417e4a6517SVernon Mauery boost::system::error_code ec;
427e4a6517SVernon Mauery boost::asio::socket_base::bytes_readable cmd(true);
437e4a6517SVernon Mauery consoleSocket->io_control(cmd, ec);
447e4a6517SVernon Mauery size_t readSize;
457e4a6517SVernon Mauery if (!ec)
4622c5ad34STom Joseph {
477e4a6517SVernon Mauery readSize = cmd.get();
487e4a6517SVernon Mauery }
497e4a6517SVernon Mauery else
507e4a6517SVernon Mauery {
517b7f25f7SGeorge Liu lg2::error(
527b7f25f7SGeorge Liu "Reading ready count from host console socket failed: {ERROR}",
537b7f25f7SGeorge Liu "ERROR", ec.value());
547e4a6517SVernon Mauery return;
557e4a6517SVernon Mauery }
567e4a6517SVernon Mauery std::vector<uint8_t> buffer(readSize);
577e4a6517SVernon Mauery ec.clear();
58*8425624aSPatrick Williams size_t readDataLen =
59*8425624aSPatrick Williams consoleSocket->read_some(boost::asio::buffer(buffer), ec);
607e4a6517SVernon Mauery if (ec)
617e4a6517SVernon Mauery {
627b7f25f7SGeorge Liu lg2::error("Reading from host console socket failed: {ERROR}", "ERROR",
637b7f25f7SGeorge Liu ec.value());
647e4a6517SVernon Mauery return;
6522c5ad34STom Joseph }
6622c5ad34STom Joseph
677e4a6517SVernon Mauery // Update the Console buffer with data read from the socket
687e4a6517SVernon Mauery buffer.resize(readDataLen);
697e4a6517SVernon Mauery dataBuffer.write(buffer);
7022c5ad34STom Joseph }
7122c5ad34STom Joseph
writeConsoleSocket(const std::vector<uint8_t> & input,bool breakFlag) const72ec437414STingting Chen int Manager::writeConsoleSocket(const std::vector<uint8_t>& input,
73ec437414STingting Chen bool breakFlag) const
74b51f641eSTom Joseph {
757e4a6517SVernon Mauery boost::system::error_code ec;
76ec437414STingting Chen if (breakFlag)
77ec437414STingting Chen {
78ec437414STingting Chen consoleSocket->send(boost::asio::buffer(input), MSG_OOB, ec);
79ec437414STingting Chen }
80ec437414STingting Chen else
81ec437414STingting Chen {
82ec437414STingting Chen consoleSocket->send(boost::asio::buffer(input), 0, ec);
83ec437414STingting Chen }
84ec437414STingting Chen
857e4a6517SVernon Mauery return ec.value();
86b51f641eSTom Joseph }
87b51f641eSTom Joseph
startHostConsole()887e4a6517SVernon Mauery void Manager::startHostConsole()
897e4a6517SVernon Mauery {
907e4a6517SVernon Mauery if (!consoleSocket)
917e4a6517SVernon Mauery {
927e4a6517SVernon Mauery initConsoleSocket();
937e4a6517SVernon Mauery }
94f6e7230dSsrikanta mondal
95f6e7230dSsrikanta mondal // Register callback to close SOL session for disable SSH SOL
96f6e7230dSsrikanta mondal if (matchPtrSOL == nullptr)
97f6e7230dSsrikanta mondal {
98f6e7230dSsrikanta mondal registerSOLServiceChangeCallback();
99f6e7230dSsrikanta mondal }
100f6e7230dSsrikanta mondal
1017e4a6517SVernon Mauery consoleSocket->async_wait(boost::asio::socket_base::wait_read,
1027e4a6517SVernon Mauery [this](const boost::system::error_code& ec) {
1037e4a6517SVernon Mauery if (!ec)
1047e4a6517SVernon Mauery {
1057e4a6517SVernon Mauery consoleInputHandler();
1067e4a6517SVernon Mauery startHostConsole();
1077e4a6517SVernon Mauery }
1087e4a6517SVernon Mauery });
1090f63e01cSRashmi RV } // namespace sol
1107e4a6517SVernon Mauery
stopHostConsole()1117e4a6517SVernon Mauery void Manager::stopHostConsole()
1127e4a6517SVernon Mauery {
1137e4a6517SVernon Mauery if (consoleSocket)
1147e4a6517SVernon Mauery {
1157e4a6517SVernon Mauery consoleSocket->cancel();
1167e4a6517SVernon Mauery consoleSocket.reset();
1177e4a6517SVernon Mauery }
118b51f641eSTom Joseph }
119b51f641eSTom Joseph
updateSOLParameter(uint8_t channelNum)12029086950SCheng C Yang void Manager::updateSOLParameter(uint8_t channelNum)
12129086950SCheng C Yang {
1220a59062cSPatrick Williams sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection());
12329086950SCheng C Yang static std::string solService{};
12429086950SCheng C Yang ipmi::PropertyMap properties;
12529086950SCheng C Yang std::string ethdevice = ipmi::getChannelName(channelNum);
12629086950SCheng C Yang std::string solPathWitheEthName = solPath + ethdevice;
12729086950SCheng C Yang if (solService.empty())
12829086950SCheng C Yang {
12929086950SCheng C Yang try
13029086950SCheng C Yang {
131*8425624aSPatrick Williams solService =
132*8425624aSPatrick Williams ipmi::getService(dbus, solInterface, solPathWitheEthName);
13329086950SCheng C Yang }
13429086950SCheng C Yang catch (const std::runtime_error& e)
13529086950SCheng C Yang {
13629086950SCheng C Yang solService.clear();
1377b7f25f7SGeorge Liu lg2::error("Get SOL service failed: {ERROR}", "ERROR", e);
13829086950SCheng C Yang return;
13929086950SCheng C Yang }
14029086950SCheng C Yang }
14129086950SCheng C Yang try
14229086950SCheng C Yang {
14329086950SCheng C Yang properties = ipmi::getAllDbusProperties(
14429086950SCheng C Yang dbus, solService, solPathWitheEthName, solInterface);
14529086950SCheng C Yang }
1467b7f25f7SGeorge Liu catch (const std::runtime_error& e)
14729086950SCheng C Yang {
1487b7f25f7SGeorge Liu lg2::error("Setting sol parameter: {ERROR}", "ERROR", e);
14929086950SCheng C Yang return;
15029086950SCheng C Yang }
15129086950SCheng C Yang
15229086950SCheng C Yang progress = std::get<uint8_t>(properties["Progress"]);
15329086950SCheng C Yang
15429086950SCheng C Yang enable = std::get<bool>(properties["Enable"]);
15529086950SCheng C Yang
15629086950SCheng C Yang forceEncrypt = std::get<bool>(properties["ForceEncryption"]);
15729086950SCheng C Yang
15829086950SCheng C Yang forceAuth = std::get<bool>(properties["ForceAuthentication"]);
15929086950SCheng C Yang
16029086950SCheng C Yang solMinPrivilege = static_cast<session::Privilege>(
16129086950SCheng C Yang std::get<uint8_t>(properties["Privilege"]));
16229086950SCheng C Yang
16329086950SCheng C Yang accumulateInterval =
16429086950SCheng C Yang std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
16529086950SCheng C Yang sol::accIntervalFactor * 1ms;
16629086950SCheng C Yang
16729086950SCheng C Yang sendThreshold = std::get<uint8_t>(properties["Threshold"]);
16829086950SCheng C Yang
16929086950SCheng C Yang retryCount = std::get<uint8_t>(properties["RetryCount"]);
17029086950SCheng C Yang
17129086950SCheng C Yang retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) *
17229086950SCheng C Yang sol::retryIntervalFactor * 1ms;
17329086950SCheng C Yang
17429086950SCheng C Yang return;
17529086950SCheng C Yang }
17629086950SCheng C Yang
startPayloadInstance(uint8_t payloadInstance,session::SessionID sessionID)1772e44e0efSTom Joseph void Manager::startPayloadInstance(uint8_t payloadInstance,
1782e44e0efSTom Joseph session::SessionID sessionID)
1792e44e0efSTom Joseph {
1802e44e0efSTom Joseph if (payloadMap.empty())
1812e44e0efSTom Joseph {
1820f63e01cSRashmi RV try
1830f63e01cSRashmi RV {
1847e4a6517SVernon Mauery startHostConsole();
1852e44e0efSTom Joseph }
1860f63e01cSRashmi RV catch (const std::exception& e)
1870f63e01cSRashmi RV {
1887b7f25f7SGeorge Liu lg2::error(
1897b7f25f7SGeorge Liu "Encountered exception when starting host console. Hence stopping host console: {ERROR}",
1907b7f25f7SGeorge Liu "ERROR", e);
1910f63e01cSRashmi RV stopHostConsole();
1920f63e01cSRashmi RV throw;
1930f63e01cSRashmi RV }
1940f63e01cSRashmi RV }
1952e44e0efSTom Joseph
1962e44e0efSTom Joseph // Create the SOL Context data for payload instance
197a6ad5e16SVernon Mauery std::shared_ptr<Context> context = Context::makeContext(
198a6ad5e16SVernon Mauery io, retryCount, sendThreshold, payloadInstance, sessionID);
1992e44e0efSTom Joseph
2002e44e0efSTom Joseph payloadMap.emplace(payloadInstance, std::move(context));
2012e44e0efSTom Joseph }
2022e44e0efSTom Joseph
stopPayloadInstance(uint8_t payloadInstance)2034ff14b59STom Joseph void Manager::stopPayloadInstance(uint8_t payloadInstance)
2044ff14b59STom Joseph {
2054ff14b59STom Joseph auto iter = payloadMap.find(payloadInstance);
2064ff14b59STom Joseph if (iter == payloadMap.end())
2074ff14b59STom Joseph {
2084ff14b59STom Joseph throw std::runtime_error("SOL Payload instance not found ");
2094ff14b59STom Joseph }
2104ff14b59STom Joseph
2114ff14b59STom Joseph payloadMap.erase(iter);
2124ff14b59STom Joseph
2134ff14b59STom Joseph if (payloadMap.empty())
2144ff14b59STom Joseph {
2157e4a6517SVernon Mauery stopHostConsole();
216de203cedSTom Joseph
217de203cedSTom Joseph dataBuffer.erase(dataBuffer.size());
2184ff14b59STom Joseph }
2194ff14b59STom Joseph }
2204ff14b59STom Joseph
stopAllPayloadInstance()221f6e7230dSsrikanta mondal void Manager::stopAllPayloadInstance()
222f6e7230dSsrikanta mondal {
223f6e7230dSsrikanta mondal // Erase all payload instance
224f6e7230dSsrikanta mondal payloadMap.erase(payloadMap.begin(), payloadMap.end());
225f6e7230dSsrikanta mondal
226f6e7230dSsrikanta mondal stopHostConsole();
227f6e7230dSsrikanta mondal
228f6e7230dSsrikanta mondal dataBuffer.erase(dataBuffer.size());
229f6e7230dSsrikanta mondal }
230f6e7230dSsrikanta mondal
registerSOLServiceChangeCallback()231f6e7230dSsrikanta mondal void registerSOLServiceChangeCallback()
232f6e7230dSsrikanta mondal {
233f6e7230dSsrikanta mondal using namespace sdbusplus::bus::match::rules;
2340a59062cSPatrick Williams sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
235f6e7230dSsrikanta mondal try
236f6e7230dSsrikanta mondal {
237f6e7230dSsrikanta mondal auto servicePath = ipmi::getDbusObject(
238f6e7230dSsrikanta mondal bus, "xyz.openbmc_project.Control.Service.Attributes",
239cc540bfdSKonstantin Aladyshev "/xyz/openbmc_project/control/service", "_6fbmc_2dconsole");
240f6e7230dSsrikanta mondal
241f6e7230dSsrikanta mondal if (!std::empty(servicePath.first))
242f6e7230dSsrikanta mondal {
243f6e7230dSsrikanta mondal matchPtrSOL = std::make_unique<sdbusplus::bus::match_t>(
244f6e7230dSsrikanta mondal bus,
245f6e7230dSsrikanta mondal path_namespace(servicePath.first) +
246f6e7230dSsrikanta mondal "arg0namespace='xyz.openbmc_project.Control.Service."
247f6e7230dSsrikanta mondal "Attributes'"
248f6e7230dSsrikanta mondal ", " +
249f6e7230dSsrikanta mondal type::signal() + member("PropertiesChanged") +
250f6e7230dSsrikanta mondal interface("org.freedesktop.DBus.Properties"),
2510a59062cSPatrick Williams [](sdbusplus::message_t& msg) {
252f6e7230dSsrikanta mondal std::string intfName;
253f6e7230dSsrikanta mondal std::map<std::string, std::variant<bool>> properties;
254f6e7230dSsrikanta mondal msg.read(intfName, properties);
255f6e7230dSsrikanta mondal
256f6e7230dSsrikanta mondal const auto it = properties.find("Enabled");
257f6e7230dSsrikanta mondal if (it != properties.end())
258f6e7230dSsrikanta mondal {
259f6e7230dSsrikanta mondal const bool* state = std::get_if<bool>(&it->second);
260f6e7230dSsrikanta mondal
261f6e7230dSsrikanta mondal if (state != nullptr && *state == false)
262f6e7230dSsrikanta mondal {
263f6e7230dSsrikanta mondal // Stop all the payload session.
2642085ae07SVernon Mauery sol::Manager::get().stopAllPayloadInstance();
265f6e7230dSsrikanta mondal }
266f6e7230dSsrikanta mondal }
267f6e7230dSsrikanta mondal });
268f6e7230dSsrikanta mondal }
269f6e7230dSsrikanta mondal }
27012d199b2SPatrick Williams catch (const sdbusplus::exception_t& e)
271f6e7230dSsrikanta mondal {
2727b7f25f7SGeorge Liu lg2::error(
2737b7f25f7SGeorge Liu "Failed to get service path in registerSOLServiceChangeCallback: {ERROR}",
2747b7f25f7SGeorge Liu "ERROR", e);
275f6e7230dSsrikanta mondal }
276f6e7230dSsrikanta mondal }
277f6e7230dSsrikanta mondal
procSolConfChange(sdbusplus::message_t & msg)2780a59062cSPatrick Williams void procSolConfChange(sdbusplus::message_t& msg)
279c936ecaaSJian Zhang {
280c936ecaaSJian Zhang using SolConfVariant = std::variant<bool, uint8_t>;
281c936ecaaSJian Zhang using SolConfProperties =
282c936ecaaSJian Zhang std::vector<std::pair<std::string, SolConfVariant>>;
283c936ecaaSJian Zhang
284c936ecaaSJian Zhang std::string iface;
285c936ecaaSJian Zhang SolConfProperties properties;
286c936ecaaSJian Zhang
287c936ecaaSJian Zhang try
288c936ecaaSJian Zhang {
289c936ecaaSJian Zhang msg.read(iface, properties);
290c936ecaaSJian Zhang }
291c936ecaaSJian Zhang catch (const std::exception& e)
292c936ecaaSJian Zhang {
2937b7f25f7SGeorge Liu lg2::error("procSolConfChange get properties FAIL: {ERROR}", "ERROR",
2947b7f25f7SGeorge Liu e);
295c936ecaaSJian Zhang return;
296c936ecaaSJian Zhang }
297c936ecaaSJian Zhang
298c936ecaaSJian Zhang for (const auto& prop : properties)
299c936ecaaSJian Zhang {
300c936ecaaSJian Zhang if (prop.first == "Progress")
301c936ecaaSJian Zhang {
302c936ecaaSJian Zhang sol::Manager::get().progress = std::get<uint8_t>(prop.second);
303c936ecaaSJian Zhang }
304c936ecaaSJian Zhang else if (prop.first == "Enable")
305c936ecaaSJian Zhang {
306c936ecaaSJian Zhang sol::Manager::get().enable = std::get<bool>(prop.second);
307c936ecaaSJian Zhang }
308c936ecaaSJian Zhang else if (prop.first == "ForceEncryption")
309c936ecaaSJian Zhang {
310c936ecaaSJian Zhang sol::Manager::get().forceEncrypt = std::get<bool>(prop.second);
311c936ecaaSJian Zhang }
312c936ecaaSJian Zhang else if (prop.first == "ForceAuthentication")
313c936ecaaSJian Zhang {
314c936ecaaSJian Zhang sol::Manager::get().forceAuth = std::get<bool>(prop.second);
315c936ecaaSJian Zhang }
316c936ecaaSJian Zhang else if (prop.first == "Privilege")
317c936ecaaSJian Zhang {
318c936ecaaSJian Zhang sol::Manager::get().solMinPrivilege =
319c936ecaaSJian Zhang static_cast<session::Privilege>(std::get<uint8_t>(prop.second));
320c936ecaaSJian Zhang }
321c936ecaaSJian Zhang else if (prop.first == "AccumulateIntervalMS")
322c936ecaaSJian Zhang {
323c936ecaaSJian Zhang sol::Manager::get().accumulateInterval =
324c936ecaaSJian Zhang std::get<uint8_t>(prop.second) * sol::accIntervalFactor * 1ms;
325c936ecaaSJian Zhang }
326c936ecaaSJian Zhang else if (prop.first == "Threshold")
327c936ecaaSJian Zhang {
328c936ecaaSJian Zhang sol::Manager::get().sendThreshold = std::get<uint8_t>(prop.second);
329c936ecaaSJian Zhang }
330c936ecaaSJian Zhang else if (prop.first == "RetryCount")
331c936ecaaSJian Zhang {
332c936ecaaSJian Zhang sol::Manager::get().retryCount = std::get<uint8_t>(prop.second);
333c936ecaaSJian Zhang }
334c936ecaaSJian Zhang else if (prop.first == "RetryIntervalMS")
335c936ecaaSJian Zhang {
336*8425624aSPatrick Williams sol::Manager::get().retryInterval =
337*8425624aSPatrick Williams std::get<uint8_t>(prop.second) * sol::retryIntervalFactor * 1ms;
338c936ecaaSJian Zhang }
339c936ecaaSJian Zhang }
340c936ecaaSJian Zhang }
341c936ecaaSJian Zhang
registerSolConfChangeCallbackHandler(std::string channel)342c936ecaaSJian Zhang void registerSolConfChangeCallbackHandler(std::string channel)
343c936ecaaSJian Zhang {
344c936ecaaSJian Zhang if (solConfPropertiesSignal == nullptr)
345c936ecaaSJian Zhang {
346c936ecaaSJian Zhang using namespace sdbusplus::bus::match::rules;
3470a59062cSPatrick Williams sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
348c936ecaaSJian Zhang try
349c936ecaaSJian Zhang {
350c936ecaaSJian Zhang auto servicePath = solPath + channel;
351c936ecaaSJian Zhang
352c936ecaaSJian Zhang solConfPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
353c936ecaaSJian Zhang bus, propertiesChangedNamespace(servicePath, solInterface),
354c936ecaaSJian Zhang procSolConfChange);
355c936ecaaSJian Zhang }
356c936ecaaSJian Zhang catch (const sdbusplus::exception_t& e)
357c936ecaaSJian Zhang {
3587b7f25f7SGeorge Liu lg2::error(
3597b7f25f7SGeorge Liu "Failed to get service path in registerSolConfChangeCallbackHandler, channel: {CHANNEL}, error: {ERROR}",
3607b7f25f7SGeorge Liu "CHANNEL", channel, "ERROR", e);
361c936ecaaSJian Zhang }
362c936ecaaSJian Zhang }
363c936ecaaSJian Zhang return;
364c936ecaaSJian Zhang }
365c936ecaaSJian Zhang
36622c5ad34STom Joseph } // namespace sol
367