blob: ccfbc3c6b7c5f12e6f821ab6d774680643b82a20 [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>
George Liu7b7f25f2022-07-04 17:07:32 +080014#include <phosphor-logging/lg2.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/";
Tom Joseph22c5ad32017-03-14 18:04:22 +053022
23namespace sol
24{
25
srikanta mondalf6e72302020-06-08 12:46:28 +000026std::unique_ptr<sdbusplus::bus::match_t> matchPtrSOL(nullptr);
Jian Zhangc936eca2022-03-22 11:25:29 +080027std::unique_ptr<sdbusplus::bus::match_t> solConfPropertiesSignal(nullptr);
srikanta mondalf6e72302020-06-08 12:46:28 +000028
Vernon Mauery7e4a6512018-11-09 08:43:36 -080029void Manager::initConsoleSocket()
Tom Josephb81f7612017-04-25 17:59:02 +053030{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080031 // explicit length constructor for NUL-prefixed abstract path
32 std::string path(CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
33 boost::asio::local::stream_protocol::endpoint ep(path);
34 consoleSocket =
35 std::make_unique<boost::asio::local::stream_protocol::socket>(*io);
36 consoleSocket->connect(ep);
Tom Josephb81f7612017-04-25 17:59:02 +053037}
38
Vernon Mauery7e4a6512018-11-09 08:43:36 -080039void Manager::consoleInputHandler()
Tom Joseph22c5ad32017-03-14 18:04:22 +053040{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080041 boost::system::error_code ec;
42 boost::asio::socket_base::bytes_readable cmd(true);
43 consoleSocket->io_control(cmd, ec);
44 size_t readSize;
45 if (!ec)
Tom Joseph22c5ad32017-03-14 18:04:22 +053046 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -080047 readSize = cmd.get();
48 }
49 else
50 {
George Liu7b7f25f2022-07-04 17:07:32 +080051 lg2::error(
52 "Reading ready count from host console socket failed: {ERROR}",
53 "ERROR", ec.value());
Vernon Mauery7e4a6512018-11-09 08:43:36 -080054 return;
55 }
56 std::vector<uint8_t> buffer(readSize);
57 ec.clear();
Patrick Williams84256242024-08-16 15:20:21 -040058 size_t readDataLen =
59 consoleSocket->read_some(boost::asio::buffer(buffer), ec);
Vernon Mauery7e4a6512018-11-09 08:43:36 -080060 if (ec)
61 {
George Liu7b7f25f2022-07-04 17:07:32 +080062 lg2::error("Reading from host console socket failed: {ERROR}", "ERROR",
63 ec.value());
Vernon Mauery7e4a6512018-11-09 08:43:36 -080064 return;
Tom Joseph22c5ad32017-03-14 18:04:22 +053065 }
66
Vernon Mauery7e4a6512018-11-09 08:43:36 -080067 // Update the Console buffer with data read from the socket
68 buffer.resize(readDataLen);
69 dataBuffer.write(buffer);
Tom Joseph22c5ad32017-03-14 18:04:22 +053070}
71
Tingting Chenec437412022-09-27 18:35:22 +080072int Manager::writeConsoleSocket(const std::vector<uint8_t>& input,
73 bool breakFlag) const
Tom Josephb51f6412017-03-14 18:08:14 +053074{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080075 boost::system::error_code ec;
Tingting Chenec437412022-09-27 18:35:22 +080076 if (breakFlag)
77 {
78 consoleSocket->send(boost::asio::buffer(input), MSG_OOB, ec);
79 }
80 else
81 {
82 consoleSocket->send(boost::asio::buffer(input), 0, ec);
83 }
84
Vernon Mauery7e4a6512018-11-09 08:43:36 -080085 return ec.value();
86}
Tom Josephb51f6412017-03-14 18:08:14 +053087
Vernon Mauery7e4a6512018-11-09 08:43:36 -080088void Manager::startHostConsole()
89{
90 if (!consoleSocket)
Tom Josephb51f6412017-03-14 18:08:14 +053091 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -080092 initConsoleSocket();
Tom Josephb51f6412017-03-14 18:08:14 +053093 }
srikanta mondalf6e72302020-06-08 12:46:28 +000094
95 // Register callback to close SOL session for disable SSH SOL
96 if (matchPtrSOL == nullptr)
97 {
98 registerSOLServiceChangeCallback();
99 }
100
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800101 consoleSocket->async_wait(boost::asio::socket_base::wait_read,
102 [this](const boost::system::error_code& ec) {
Patrick Williams84256242024-08-16 15:20:21 -0400103 if (!ec)
104 {
105 consoleInputHandler();
106 startHostConsole();
107 }
108 });
Rashmi RV0f63e012019-11-21 15:38:50 +0530109} // namespace sol
Tom Josephb51f6412017-03-14 18:08:14 +0530110
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800111void Manager::stopHostConsole()
112{
113 if (consoleSocket)
114 {
115 consoleSocket->cancel();
116 consoleSocket.reset();
117 }
Tom Josephb51f6412017-03-14 18:08:14 +0530118}
119
Cheng C Yang29086952020-03-09 15:29:18 +0800120void Manager::updateSOLParameter(uint8_t channelNum)
121{
Patrick Williams0a590622022-07-22 19:26:53 -0500122 sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection());
Cheng C Yang29086952020-03-09 15:29:18 +0800123 static std::string solService{};
124 ipmi::PropertyMap properties;
125 std::string ethdevice = ipmi::getChannelName(channelNum);
126 std::string solPathWitheEthName = solPath + ethdevice;
127 if (solService.empty())
128 {
129 try
130 {
Patrick Williams84256242024-08-16 15:20:21 -0400131 solService =
132 ipmi::getService(dbus, solInterface, solPathWitheEthName);
Cheng C Yang29086952020-03-09 15:29:18 +0800133 }
134 catch (const std::runtime_error& e)
135 {
136 solService.clear();
George Liu7b7f25f2022-07-04 17:07:32 +0800137 lg2::error("Get SOL service failed: {ERROR}", "ERROR", e);
Cheng C Yang29086952020-03-09 15:29:18 +0800138 return;
139 }
140 }
141 try
142 {
143 properties = ipmi::getAllDbusProperties(
144 dbus, solService, solPathWitheEthName, solInterface);
145 }
George Liu7b7f25f2022-07-04 17:07:32 +0800146 catch (const std::runtime_error& e)
Cheng C Yang29086952020-03-09 15:29:18 +0800147 {
George Liu7b7f25f2022-07-04 17:07:32 +0800148 lg2::error("Setting sol parameter: {ERROR}", "ERROR", e);
Cheng C Yang29086952020-03-09 15:29:18 +0800149 return;
150 }
151
152 progress = std::get<uint8_t>(properties["Progress"]);
153
154 enable = std::get<bool>(properties["Enable"]);
155
156 forceEncrypt = std::get<bool>(properties["ForceEncryption"]);
157
158 forceAuth = std::get<bool>(properties["ForceAuthentication"]);
159
160 solMinPrivilege = static_cast<session::Privilege>(
161 std::get<uint8_t>(properties["Privilege"]));
162
163 accumulateInterval =
164 std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
165 sol::accIntervalFactor * 1ms;
166
167 sendThreshold = std::get<uint8_t>(properties["Threshold"]);
168
169 retryCount = std::get<uint8_t>(properties["RetryCount"]);
170
171 retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) *
172 sol::retryIntervalFactor * 1ms;
173
174 return;
175}
176
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530177void Manager::startPayloadInstance(uint8_t payloadInstance,
178 session::SessionID sessionID)
179{
180 if (payloadMap.empty())
181 {
Rashmi RV0f63e012019-11-21 15:38:50 +0530182 try
183 {
184 startHostConsole();
185 }
186 catch (const std::exception& e)
187 {
George Liu7b7f25f2022-07-04 17:07:32 +0800188 lg2::error(
189 "Encountered exception when starting host console. Hence stopping host console: {ERROR}",
190 "ERROR", e);
Rashmi RV0f63e012019-11-21 15:38:50 +0530191 stopHostConsole();
192 throw;
193 }
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530194 }
195
196 // Create the SOL Context data for payload instance
Vernon Mauerya6ad5e12020-02-21 14:54:24 -0800197 std::shared_ptr<Context> context = Context::makeContext(
198 io, retryCount, sendThreshold, payloadInstance, sessionID);
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530199
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530200 payloadMap.emplace(payloadInstance, std::move(context));
201}
202
Tom Joseph4ff14b52017-03-14 18:10:52 +0530203void Manager::stopPayloadInstance(uint8_t payloadInstance)
204{
205 auto iter = payloadMap.find(payloadInstance);
206 if (iter == payloadMap.end())
207 {
208 throw std::runtime_error("SOL Payload instance not found ");
209 }
210
211 payloadMap.erase(iter);
212
Tom Joseph4ff14b52017-03-14 18:10:52 +0530213 if (payloadMap.empty())
214 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800215 stopHostConsole();
Tom Josephde203ce2017-08-01 16:48:06 +0530216
217 dataBuffer.erase(dataBuffer.size());
Tom Joseph4ff14b52017-03-14 18:10:52 +0530218 }
219}
220
srikanta mondalf6e72302020-06-08 12:46:28 +0000221void Manager::stopAllPayloadInstance()
222{
223 // Erase all payload instance
224 payloadMap.erase(payloadMap.begin(), payloadMap.end());
225
226 stopHostConsole();
227
228 dataBuffer.erase(dataBuffer.size());
229}
230
231void registerSOLServiceChangeCallback()
232{
233 using namespace sdbusplus::bus::match::rules;
Patrick Williams0a590622022-07-22 19:26:53 -0500234 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
srikanta mondalf6e72302020-06-08 12:46:28 +0000235 try
236 {
237 auto servicePath = ipmi::getDbusObject(
238 bus, "xyz.openbmc_project.Control.Service.Attributes",
Konstantin Aladyshevcc540bf2023-03-28 17:27:13 +0300239 "/xyz/openbmc_project/control/service", "_6fbmc_2dconsole");
srikanta mondalf6e72302020-06-08 12:46:28 +0000240
241 if (!std::empty(servicePath.first))
242 {
243 matchPtrSOL = std::make_unique<sdbusplus::bus::match_t>(
244 bus,
245 path_namespace(servicePath.first) +
246 "arg0namespace='xyz.openbmc_project.Control.Service."
247 "Attributes'"
248 ", " +
249 type::signal() + member("PropertiesChanged") +
250 interface("org.freedesktop.DBus.Properties"),
Patrick Williams0a590622022-07-22 19:26:53 -0500251 [](sdbusplus::message_t& msg) {
Patrick Williams84256242024-08-16 15:20:21 -0400252 std::string intfName;
253 std::map<std::string, std::variant<bool>> properties;
254 msg.read(intfName, properties);
srikanta mondalf6e72302020-06-08 12:46:28 +0000255
Patrick Williams84256242024-08-16 15:20:21 -0400256 const auto it = properties.find("Enabled");
257 if (it != properties.end())
srikanta mondalf6e72302020-06-08 12:46:28 +0000258 {
Patrick Williams84256242024-08-16 15:20:21 -0400259 const bool* state = std::get_if<bool>(&it->second);
260
261 if (state != nullptr && *state == false)
262 {
263 // Stop all the payload session.
264 sol::Manager::get().stopAllPayloadInstance();
265 }
srikanta mondalf6e72302020-06-08 12:46:28 +0000266 }
Patrick Williams84256242024-08-16 15:20:21 -0400267 });
srikanta mondalf6e72302020-06-08 12:46:28 +0000268 }
269 }
Patrick Williams12d199b2021-10-06 12:36:48 -0500270 catch (const sdbusplus::exception_t& e)
srikanta mondalf6e72302020-06-08 12:46:28 +0000271 {
George Liu7b7f25f2022-07-04 17:07:32 +0800272 lg2::error(
273 "Failed to get service path in registerSOLServiceChangeCallback: {ERROR}",
274 "ERROR", e);
srikanta mondalf6e72302020-06-08 12:46:28 +0000275 }
276}
277
Patrick Williams0a590622022-07-22 19:26:53 -0500278void procSolConfChange(sdbusplus::message_t& msg)
Jian Zhangc936eca2022-03-22 11:25:29 +0800279{
280 using SolConfVariant = std::variant<bool, uint8_t>;
281 using SolConfProperties =
282 std::vector<std::pair<std::string, SolConfVariant>>;
283
284 std::string iface;
285 SolConfProperties properties;
286
287 try
288 {
289 msg.read(iface, properties);
290 }
291 catch (const std::exception& e)
292 {
George Liu7b7f25f2022-07-04 17:07:32 +0800293 lg2::error("procSolConfChange get properties FAIL: {ERROR}", "ERROR",
294 e);
Jian Zhangc936eca2022-03-22 11:25:29 +0800295 return;
296 }
297
298 for (const auto& prop : properties)
299 {
300 if (prop.first == "Progress")
301 {
302 sol::Manager::get().progress = std::get<uint8_t>(prop.second);
303 }
304 else if (prop.first == "Enable")
305 {
306 sol::Manager::get().enable = std::get<bool>(prop.second);
307 }
308 else if (prop.first == "ForceEncryption")
309 {
310 sol::Manager::get().forceEncrypt = std::get<bool>(prop.second);
311 }
312 else if (prop.first == "ForceAuthentication")
313 {
314 sol::Manager::get().forceAuth = std::get<bool>(prop.second);
315 }
316 else if (prop.first == "Privilege")
317 {
318 sol::Manager::get().solMinPrivilege =
319 static_cast<session::Privilege>(std::get<uint8_t>(prop.second));
320 }
321 else if (prop.first == "AccumulateIntervalMS")
322 {
323 sol::Manager::get().accumulateInterval =
324 std::get<uint8_t>(prop.second) * sol::accIntervalFactor * 1ms;
325 }
326 else if (prop.first == "Threshold")
327 {
328 sol::Manager::get().sendThreshold = std::get<uint8_t>(prop.second);
329 }
330 else if (prop.first == "RetryCount")
331 {
332 sol::Manager::get().retryCount = std::get<uint8_t>(prop.second);
333 }
334 else if (prop.first == "RetryIntervalMS")
335 {
Patrick Williams84256242024-08-16 15:20:21 -0400336 sol::Manager::get().retryInterval =
337 std::get<uint8_t>(prop.second) * sol::retryIntervalFactor * 1ms;
Jian Zhangc936eca2022-03-22 11:25:29 +0800338 }
339 }
340}
341
342void registerSolConfChangeCallbackHandler(std::string channel)
343{
344 if (solConfPropertiesSignal == nullptr)
345 {
346 using namespace sdbusplus::bus::match::rules;
Patrick Williams0a590622022-07-22 19:26:53 -0500347 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Jian Zhangc936eca2022-03-22 11:25:29 +0800348 try
349 {
350 auto servicePath = solPath + channel;
351
352 solConfPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
353 bus, propertiesChangedNamespace(servicePath, solInterface),
354 procSolConfChange);
355 }
356 catch (const sdbusplus::exception_t& e)
357 {
George Liu7b7f25f2022-07-04 17:07:32 +0800358 lg2::error(
359 "Failed to get service path in registerSolConfChangeCallbackHandler, channel: {CHANNEL}, error: {ERROR}",
360 "CHANNEL", channel, "ERROR", e);
Jian Zhangc936eca2022-03-22 11:25:29 +0800361 }
362 }
363 return;
364}
365
Tom Joseph22c5ad32017-03-14 18:04:22 +0530366} // namespace sol