blob: a8a9faa7065cda19863cf8b248e8bd11f32bca62 [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/";
22constexpr const char* PROP_INTF = "org.freedesktop.DBus.Properties";
Tom Joseph22c5ad32017-03-14 18:04:22 +053023
24namespace sol
25{
26
srikanta mondalf6e72302020-06-08 12:46:28 +000027std::unique_ptr<sdbusplus::bus::match_t> matchPtrSOL(nullptr);
Jian Zhangc936eca2022-03-22 11:25:29 +080028std::unique_ptr<sdbusplus::bus::match_t> solConfPropertiesSignal(nullptr);
srikanta mondalf6e72302020-06-08 12:46:28 +000029
Vernon Mauery7e4a6512018-11-09 08:43:36 -080030void Manager::initConsoleSocket()
Tom Josephb81f7612017-04-25 17:59:02 +053031{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080032 // explicit length constructor for NUL-prefixed abstract path
33 std::string path(CONSOLE_SOCKET_PATH, CONSOLE_SOCKET_PATH_LEN);
34 boost::asio::local::stream_protocol::endpoint ep(path);
35 consoleSocket =
36 std::make_unique<boost::asio::local::stream_protocol::socket>(*io);
37 consoleSocket->connect(ep);
Tom Josephb81f7612017-04-25 17:59:02 +053038}
39
Vernon Mauery7e4a6512018-11-09 08:43:36 -080040void Manager::consoleInputHandler()
Tom Joseph22c5ad32017-03-14 18:04:22 +053041{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080042 boost::system::error_code ec;
43 boost::asio::socket_base::bytes_readable cmd(true);
44 consoleSocket->io_control(cmd, ec);
45 size_t readSize;
46 if (!ec)
Tom Joseph22c5ad32017-03-14 18:04:22 +053047 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -080048 readSize = cmd.get();
49 }
50 else
51 {
George Liu7b7f25f2022-07-04 17:07:32 +080052 lg2::error(
53 "Reading ready count from host console socket failed: {ERROR}",
54 "ERROR", ec.value());
Vernon Mauery7e4a6512018-11-09 08:43:36 -080055 return;
56 }
57 std::vector<uint8_t> buffer(readSize);
58 ec.clear();
59 size_t readDataLen =
60 consoleSocket->read_some(boost::asio::buffer(buffer), ec);
61 if (ec)
62 {
George Liu7b7f25f2022-07-04 17:07:32 +080063 lg2::error("Reading from host console socket failed: {ERROR}", "ERROR",
64 ec.value());
Vernon Mauery7e4a6512018-11-09 08:43:36 -080065 return;
Tom Joseph22c5ad32017-03-14 18:04:22 +053066 }
67
Vernon Mauery7e4a6512018-11-09 08:43:36 -080068 // Update the Console buffer with data read from the socket
69 buffer.resize(readDataLen);
70 dataBuffer.write(buffer);
Tom Joseph22c5ad32017-03-14 18:04:22 +053071}
72
Tingting Chenec437412022-09-27 18:35:22 +080073int Manager::writeConsoleSocket(const std::vector<uint8_t>& input,
74 bool breakFlag) const
Tom Josephb51f6412017-03-14 18:08:14 +053075{
Vernon Mauery7e4a6512018-11-09 08:43:36 -080076 boost::system::error_code ec;
Tingting Chenec437412022-09-27 18:35:22 +080077 if (breakFlag)
78 {
79 consoleSocket->send(boost::asio::buffer(input), MSG_OOB, ec);
80 }
81 else
82 {
83 consoleSocket->send(boost::asio::buffer(input), 0, ec);
84 }
85
Vernon Mauery7e4a6512018-11-09 08:43:36 -080086 return ec.value();
87}
Tom Josephb51f6412017-03-14 18:08:14 +053088
Vernon Mauery7e4a6512018-11-09 08:43:36 -080089void Manager::startHostConsole()
90{
91 if (!consoleSocket)
Tom Josephb51f6412017-03-14 18:08:14 +053092 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -080093 initConsoleSocket();
Tom Josephb51f6412017-03-14 18:08:14 +053094 }
srikanta mondalf6e72302020-06-08 12:46:28 +000095
96 // Register callback to close SOL session for disable SSH SOL
97 if (matchPtrSOL == nullptr)
98 {
99 registerSOLServiceChangeCallback();
100 }
101
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800102 consoleSocket->async_wait(boost::asio::socket_base::wait_read,
103 [this](const boost::system::error_code& ec) {
104 if (!ec)
105 {
106 consoleInputHandler();
107 startHostConsole();
108 }
109 });
Rashmi RV0f63e012019-11-21 15:38:50 +0530110} // namespace sol
Tom Josephb51f6412017-03-14 18:08:14 +0530111
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800112void Manager::stopHostConsole()
113{
114 if (consoleSocket)
115 {
116 consoleSocket->cancel();
117 consoleSocket.reset();
118 }
Tom Josephb51f6412017-03-14 18:08:14 +0530119}
120
Cheng C Yang29086952020-03-09 15:29:18 +0800121void Manager::updateSOLParameter(uint8_t channelNum)
122{
123 std::variant<uint8_t, bool> value;
Patrick Williams0a590622022-07-22 19:26:53 -0500124 sdbusplus::bus_t dbus(ipmid_get_sd_bus_connection());
Cheng C Yang29086952020-03-09 15:29:18 +0800125 static std::string solService{};
126 ipmi::PropertyMap properties;
127 std::string ethdevice = ipmi::getChannelName(channelNum);
128 std::string solPathWitheEthName = solPath + ethdevice;
129 if (solService.empty())
130 {
131 try
132 {
133 solService =
134 ipmi::getService(dbus, solInterface, solPathWitheEthName);
135 }
136 catch (const std::runtime_error& e)
137 {
138 solService.clear();
George Liu7b7f25f2022-07-04 17:07:32 +0800139 lg2::error("Get SOL service failed: {ERROR}", "ERROR", e);
Cheng C Yang29086952020-03-09 15:29:18 +0800140 return;
141 }
142 }
143 try
144 {
145 properties = ipmi::getAllDbusProperties(
146 dbus, solService, solPathWitheEthName, solInterface);
147 }
George Liu7b7f25f2022-07-04 17:07:32 +0800148 catch (const std::runtime_error& e)
Cheng C Yang29086952020-03-09 15:29:18 +0800149 {
George Liu7b7f25f2022-07-04 17:07:32 +0800150 lg2::error("Setting sol parameter: {ERROR}", "ERROR", e);
Cheng C Yang29086952020-03-09 15:29:18 +0800151 return;
152 }
153
154 progress = std::get<uint8_t>(properties["Progress"]);
155
156 enable = std::get<bool>(properties["Enable"]);
157
158 forceEncrypt = std::get<bool>(properties["ForceEncryption"]);
159
160 forceAuth = std::get<bool>(properties["ForceAuthentication"]);
161
162 solMinPrivilege = static_cast<session::Privilege>(
163 std::get<uint8_t>(properties["Privilege"]));
164
165 accumulateInterval =
166 std::get<uint8_t>((properties["AccumulateIntervalMS"])) *
167 sol::accIntervalFactor * 1ms;
168
169 sendThreshold = std::get<uint8_t>(properties["Threshold"]);
170
171 retryCount = std::get<uint8_t>(properties["RetryCount"]);
172
173 retryInterval = std::get<uint8_t>(properties["RetryIntervalMS"]) *
174 sol::retryIntervalFactor * 1ms;
175
176 return;
177}
178
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530179void Manager::startPayloadInstance(uint8_t payloadInstance,
180 session::SessionID sessionID)
181{
182 if (payloadMap.empty())
183 {
Rashmi RV0f63e012019-11-21 15:38:50 +0530184 try
185 {
186 startHostConsole();
187 }
188 catch (const std::exception& e)
189 {
George Liu7b7f25f2022-07-04 17:07:32 +0800190 lg2::error(
191 "Encountered exception when starting host console. Hence stopping host console: {ERROR}",
192 "ERROR", e);
Rashmi RV0f63e012019-11-21 15:38:50 +0530193 stopHostConsole();
194 throw;
195 }
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530196 }
197
198 // Create the SOL Context data for payload instance
Vernon Mauerya6ad5e12020-02-21 14:54:24 -0800199 std::shared_ptr<Context> context = Context::makeContext(
200 io, retryCount, sendThreshold, payloadInstance, sessionID);
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530201
Tom Joseph2e44e0e2017-03-14 18:09:11 +0530202 payloadMap.emplace(payloadInstance, std::move(context));
203}
204
Tom Joseph4ff14b52017-03-14 18:10:52 +0530205void Manager::stopPayloadInstance(uint8_t payloadInstance)
206{
207 auto iter = payloadMap.find(payloadInstance);
208 if (iter == payloadMap.end())
209 {
210 throw std::runtime_error("SOL Payload instance not found ");
211 }
212
213 payloadMap.erase(iter);
214
Tom Joseph4ff14b52017-03-14 18:10:52 +0530215 if (payloadMap.empty())
216 {
Vernon Mauery7e4a6512018-11-09 08:43:36 -0800217 stopHostConsole();
Tom Josephde203ce2017-08-01 16:48:06 +0530218
219 dataBuffer.erase(dataBuffer.size());
Tom Joseph4ff14b52017-03-14 18:10:52 +0530220 }
221}
222
srikanta mondalf6e72302020-06-08 12:46:28 +0000223void Manager::stopAllPayloadInstance()
224{
225 // Erase all payload instance
226 payloadMap.erase(payloadMap.begin(), payloadMap.end());
227
228 stopHostConsole();
229
230 dataBuffer.erase(dataBuffer.size());
231}
232
233void registerSOLServiceChangeCallback()
234{
235 using namespace sdbusplus::bus::match::rules;
Patrick Williams0a590622022-07-22 19:26:53 -0500236 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
srikanta mondalf6e72302020-06-08 12:46:28 +0000237 try
238 {
239 auto servicePath = ipmi::getDbusObject(
240 bus, "xyz.openbmc_project.Control.Service.Attributes",
241 "/xyz/openbmc_project/control/service", "obmc_2dconsole");
242
243 if (!std::empty(servicePath.first))
244 {
245 matchPtrSOL = std::make_unique<sdbusplus::bus::match_t>(
246 bus,
247 path_namespace(servicePath.first) +
248 "arg0namespace='xyz.openbmc_project.Control.Service."
249 "Attributes'"
250 ", " +
251 type::signal() + member("PropertiesChanged") +
252 interface("org.freedesktop.DBus.Properties"),
Patrick Williams0a590622022-07-22 19:26:53 -0500253 [](sdbusplus::message_t& msg) {
srikanta mondalf6e72302020-06-08 12:46:28 +0000254 std::string intfName;
255 std::map<std::string, std::variant<bool>> properties;
256 msg.read(intfName, properties);
257
258 const auto it = properties.find("Enabled");
259 if (it != properties.end())
260 {
261 const bool* state = std::get_if<bool>(&it->second);
262
263 if (state != nullptr && *state == false)
264 {
265 // Stop all the payload session.
Vernon Mauery2085ae02021-06-10 11:51:00 -0700266 sol::Manager::get().stopAllPayloadInstance();
srikanta mondalf6e72302020-06-08 12:46:28 +0000267 }
268 }
269 });
270 }
271 }
Patrick Williams12d199b2021-10-06 12:36:48 -0500272 catch (const sdbusplus::exception_t& e)
srikanta mondalf6e72302020-06-08 12:46:28 +0000273 {
George Liu7b7f25f2022-07-04 17:07:32 +0800274 lg2::error(
275 "Failed to get service path in registerSOLServiceChangeCallback: {ERROR}",
276 "ERROR", e);
srikanta mondalf6e72302020-06-08 12:46:28 +0000277 }
278}
279
Patrick Williams0a590622022-07-22 19:26:53 -0500280void procSolConfChange(sdbusplus::message_t& msg)
Jian Zhangc936eca2022-03-22 11:25:29 +0800281{
282 using SolConfVariant = std::variant<bool, uint8_t>;
283 using SolConfProperties =
284 std::vector<std::pair<std::string, SolConfVariant>>;
285
286 std::string iface;
287 SolConfProperties properties;
288
289 try
290 {
291 msg.read(iface, properties);
292 }
293 catch (const std::exception& e)
294 {
George Liu7b7f25f2022-07-04 17:07:32 +0800295 lg2::error("procSolConfChange get properties FAIL: {ERROR}", "ERROR",
296 e);
Jian Zhangc936eca2022-03-22 11:25:29 +0800297 return;
298 }
299
300 for (const auto& prop : properties)
301 {
302 if (prop.first == "Progress")
303 {
304 sol::Manager::get().progress = std::get<uint8_t>(prop.second);
305 }
306 else if (prop.first == "Enable")
307 {
308 sol::Manager::get().enable = std::get<bool>(prop.second);
309 }
310 else if (prop.first == "ForceEncryption")
311 {
312 sol::Manager::get().forceEncrypt = std::get<bool>(prop.second);
313 }
314 else if (prop.first == "ForceAuthentication")
315 {
316 sol::Manager::get().forceAuth = std::get<bool>(prop.second);
317 }
318 else if (prop.first == "Privilege")
319 {
320 sol::Manager::get().solMinPrivilege =
321 static_cast<session::Privilege>(std::get<uint8_t>(prop.second));
322 }
323 else if (prop.first == "AccumulateIntervalMS")
324 {
325 sol::Manager::get().accumulateInterval =
326 std::get<uint8_t>(prop.second) * sol::accIntervalFactor * 1ms;
327 }
328 else if (prop.first == "Threshold")
329 {
330 sol::Manager::get().sendThreshold = std::get<uint8_t>(prop.second);
331 }
332 else if (prop.first == "RetryCount")
333 {
334 sol::Manager::get().retryCount = std::get<uint8_t>(prop.second);
335 }
336 else if (prop.first == "RetryIntervalMS")
337 {
338 sol::Manager::get().retryInterval =
339 std::get<uint8_t>(prop.second) * sol::retryIntervalFactor * 1ms;
340 }
341 }
342}
343
344void registerSolConfChangeCallbackHandler(std::string channel)
345{
346 if (solConfPropertiesSignal == nullptr)
347 {
348 using namespace sdbusplus::bus::match::rules;
Patrick Williams0a590622022-07-22 19:26:53 -0500349 sdbusplus::bus_t bus{ipmid_get_sd_bus_connection()};
Jian Zhangc936eca2022-03-22 11:25:29 +0800350 try
351 {
352 auto servicePath = solPath + channel;
353
354 solConfPropertiesSignal = std::make_unique<sdbusplus::bus::match_t>(
355 bus, propertiesChangedNamespace(servicePath, solInterface),
356 procSolConfChange);
357 }
358 catch (const sdbusplus::exception_t& e)
359 {
George Liu7b7f25f2022-07-04 17:07:32 +0800360 lg2::error(
361 "Failed to get service path in registerSolConfChangeCallbackHandler, channel: {CHANNEL}, error: {ERROR}",
362 "CHANNEL", channel, "ERROR", e);
Jian Zhangc936eca2022-03-22 11:25:29 +0800363 }
364 }
365 return;
366}
367
Tom Joseph22c5ad32017-03-14 18:04:22 +0530368} // namespace sol