xref: /openbmc/phosphor-net-ipmid/sol/sol_manager.cpp (revision bac2f1a31eb5d2613ae11b220b28764484d7c06c)
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