blob: 370e0c3ce039a1d60c53847d4f1f08ceee911086 [file] [log] [blame]
Patrick Venture46470a32018-09-07 19:26:25 -07001#include "apphandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -07002
Xo Wangf542e8b2017-08-09 15:34:16 -07003#include "app/channel.hpp"
4#include "app/watchdog.hpp"
5#include "ipmid.hpp"
Xo Wangf542e8b2017-08-09 15:34:16 -07006#include "sys_info_param.hpp"
7#include "transporthandler.hpp"
8#include "types.hpp"
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05309#include "user_channel/usercommands.hpp"
Xo Wangf542e8b2017-08-09 15:34:16 -070010#include "utils.hpp"
11
Patrick Venture0b02be92018-08-31 11:55:55 -070012#include <arpa/inet.h>
Patrick Venture46470a32018-09-07 19:26:25 -070013#include <host-ipmid/ipmid-api.h>
Xo Wang87651332017-08-11 10:17:59 -070014#include <limits.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <mapper.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070016#include <systemd/sd-bus.h>
Xo Wang87651332017-08-11 10:17:59 -070017#include <unistd.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070018
Patrick Venture3a5071a2018-09-12 13:27:42 -070019#include <algorithm>
20#include <array>
21#include <cstddef>
22#include <fstream>
23#include <memory>
Patrick Venture46470a32018-09-07 19:26:25 -070024#include <nlohmann/json.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070025#include <phosphor-logging/elog-errors.hpp>
26#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070027#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070028#include <string>
29#include <tuple>
30#include <vector>
31#include <xyz/openbmc_project/Common/error.hpp>
Yong Li18d77262018-10-09 01:59:45 +080032#include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070033#include <xyz/openbmc_project/Software/Activation/server.hpp>
34#include <xyz/openbmc_project/Software/Version/server.hpp>
35#include <xyz/openbmc_project/State/BMC/server.hpp>
Ratan Guptab8e99552017-07-27 07:07:48 +053036
Vernon Mauery185b9f82018-07-20 10:52:36 -070037#if __has_include(<filesystem>)
38#include <filesystem>
39#elif __has_include(<experimental/filesystem>)
40#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070041namespace std
42{
43// splice experimental::filesystem into std
44namespace filesystem = std::experimental::filesystem;
45} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070046#else
Patrick Venture0b02be92018-08-31 11:55:55 -070047#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070048#endif
Ratan Gupta62736ec2017-09-02 12:02:47 +053049
Patrick Venture0b02be92018-08-31 11:55:55 -070050extern sd_bus* bus;
vishwabmcba0bd5f2015-09-30 16:50:23 +053051
Alexander Amelkinba19c182018-09-04 15:49:36 +030052constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
53constexpr auto bmc_state_property = "CurrentBMCState";
Marri Devender Rao5e007a52018-01-08 06:18:36 -060054constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
55constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
56constexpr auto bmc_guid_property = "UUID";
57constexpr auto bmc_guid_len = 16;
58
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060059static constexpr auto redundancyIntf =
60 "xyz.openbmc_project.Software.RedundancyPriority";
Patrick Venture0b02be92018-08-31 11:55:55 -070061static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060062static constexpr auto activationIntf =
63 "xyz.openbmc_project.Software.Activation";
64static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
65
Chris Austen6caf28b2015-10-13 12:40:40 -050066void register_netfn_app_functions() __attribute__((constructor));
vishwabmcba0bd5f2015-09-30 16:50:23 +053067
Ratan Guptab8e99552017-07-27 07:07:48 +053068using namespace phosphor::logging;
69using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060070using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
71using Activation =
72 sdbusplus::xyz::openbmc_project::Software::server::Activation;
Alexander Amelkinba19c182018-09-04 15:49:36 +030073using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC;
Vernon Mauery185b9f82018-07-20 10:52:36 -070074namespace fs = std::filesystem;
William A. Kennington III4c008022018-10-12 17:18:14 -070075namespace variant_ns = sdbusplus::message::variant_ns;
Ratan Guptab8e99552017-07-27 07:07:48 +053076
Nan Liee0cb902016-07-11 15:38:03 +080077// Offset in get device id command.
78typedef struct
79{
Patrick Venture0b02be92018-08-31 11:55:55 -070080 uint8_t id;
81 uint8_t revision;
82 uint8_t fw[2];
83 uint8_t ipmi_ver;
84 uint8_t addn_dev_support;
85 uint8_t manuf_id[3];
86 uint8_t prod_id[2];
87 uint8_t aux[4];
88} __attribute__((packed)) ipmi_device_id_t;
Chris Austen7303bdc2016-04-17 11:50:54 -050089
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060090/**
91 * @brief Returns the Version info from primary s/w object
92 *
93 * Get the Version info from the active s/w object which is having high
94 * "Priority" value(a smaller number is a higher priority) and "Purpose"
95 * is "BMC" from the list of all s/w objects those are implementing
96 * RedundancyPriority interface from the given softwareRoot path.
97 *
98 * @return On success returns the Version info from primary s/w object.
99 *
100 */
101std::string getActiveSoftwareVersionInfo()
102{
103 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
104
105 std::string revision{};
Patrick Venture0b02be92018-08-31 11:55:55 -0700106 auto objectTree =
107 ipmi::getAllDbusObjects(bus, softwareRoot, redundancyIntf, "");
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600108 if (objectTree.empty())
109 {
110 log<level::ERR>("No Obj has implemented the s/w redundancy interface",
111 entry("INTERFACE=%s", redundancyIntf));
112 elog<InternalFailure>();
113 }
114
115 auto objectFound = false;
116 for (auto& softObject : objectTree)
117 {
118 auto service = ipmi::getService(bus, redundancyIntf, softObject.first);
119 auto objValueTree = ipmi::getManagedObjects(bus, service, softwareRoot);
120
121 auto minPriority = 0xFF;
122 for (const auto& objIter : objValueTree)
123 {
124 try
125 {
126 auto& intfMap = objIter.second;
127 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
128 auto& versionProps = intfMap.at(versionIntf);
129 auto& activationProps = intfMap.at(activationIntf);
William A. Kennington III4c008022018-10-12 17:18:14 -0700130 auto priority = variant_ns::get<uint8_t>(
131 redundancyPriorityProps.at("Priority"));
132 auto purpose =
133 variant_ns::get<std::string>(versionProps.at("Purpose"));
134 auto activation = variant_ns::get<std::string>(
135 activationProps.at("Activation"));
136 auto version =
137 variant_ns::get<std::string>(versionProps.at("Version"));
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600138 if ((Version::convertVersionPurposeFromString(purpose) ==
139 Version::VersionPurpose::BMC) &&
140 (Activation::convertActivationsFromString(activation) ==
141 Activation::Activations::Active))
142 {
143 if (priority < minPriority)
144 {
145 minPriority = priority;
146 objectFound = true;
147 revision = std::move(version);
148 }
149 }
150 }
151 catch (const std::exception& e)
152 {
153 log<level::ERR>(e.what());
154 }
155 }
156 }
157
158 if (!objectFound)
159 {
160 log<level::ERR>("Could not found an BMC software Object");
161 elog<InternalFailure>();
162 }
163
164 return revision;
165}
166
Alexander Amelkinba19c182018-09-04 15:49:36 +0300167bool getCurrentBmcState()
168{
169 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
170
171 // Get the Inventory object implementing the BMC interface
172 ipmi::DbusObjectInfo bmcObject =
173 ipmi::getDbusObject(bus, bmc_state_interface);
174 auto variant =
175 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
176 bmc_state_interface, bmc_state_property);
177
William A. Kennington III4c008022018-10-12 17:18:14 -0700178 return variant_ns::holds_alternative<std::string>(variant) &&
179 BMC::convertBMCStateFromString(
180 variant_ns::get<std::string>(variant)) == BMC::BMCState::Ready;
Alexander Amelkinba19c182018-09-04 15:49:36 +0300181}
182
Yong Li18d77262018-10-09 01:59:45 +0800183namespace acpi_state
184{
185using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
186
187const static constexpr char* acpiObjPath =
188 "/xyz/openbmc_project/control/host0/acpi_power_state";
189const static constexpr char* acpiInterface =
190 "xyz.openbmc_project.Control.Power.ACPIPowerState";
191const static constexpr char* sysACPIProp = "SysACPIStatus";
192const static constexpr char* devACPIProp = "DevACPIStatus";
193
194enum class PowerStateType : uint8_t
195{
196 sysPowerState = 0x00,
197 devPowerState = 0x01,
198};
199
200// Defined in 20.6 of ipmi doc
201enum class PowerState : uint8_t
202{
203 s0G0D0 = 0x00,
204 s1D1 = 0x01,
205 s2D2 = 0x02,
206 s3D3 = 0x03,
207 s4 = 0x04,
208 s5G2 = 0x05,
209 s4S5 = 0x06,
210 g3 = 0x07,
211 sleep = 0x08,
212 g1Sleep = 0x09,
213 override = 0x0a,
214 legacyOn = 0x20,
215 legacyOff = 0x21,
216 unknown = 0x2a,
217 noChange = 0x7f,
218};
219
220static constexpr uint8_t stateChanged = 0x80;
221
222struct ACPIState
223{
224 uint8_t sysACPIState;
225 uint8_t devACPIState;
226} __attribute__((packed));
227
228std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = {
229 {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0},
230 {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1},
231 {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2},
232 {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3},
233 {ACPIPowerState::ACPI::S4, PowerState::s4},
234 {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2},
235 {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5},
236 {ACPIPowerState::ACPI::G3, PowerState::g3},
237 {ACPIPowerState::ACPI::SLEEP, PowerState::sleep},
238 {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep},
239 {ACPIPowerState::ACPI::OVERRIDE, PowerState::override},
240 {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn},
241 {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff},
242 {ACPIPowerState::ACPI::Unknown, PowerState::unknown}};
243
244bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state)
245{
246 if (type == acpi_state::PowerStateType::sysPowerState)
247 {
248 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) ||
249 (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) ||
250 (state ==
251 static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) ||
252 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
253 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
254 {
255 return true;
256 }
257 else
258 {
259 return false;
260 }
261 }
262 else if (type == acpi_state::PowerStateType::devPowerState)
263 {
264 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) ||
265 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
266 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
267 {
268 return true;
269 }
270 else
271 {
272 return false;
273 }
274 }
275 else
276 {
277 return false;
278 }
279 return false;
280}
281} // namespace acpi_state
282
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500283ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700284 ipmi_request_t request,
285 ipmi_response_t response,
286 ipmi_data_len_t data_len,
287 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500288{
Yong Li18d77262018-10-09 01:59:45 +0800289 auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown);
Chris Austen6caf28b2015-10-13 12:40:40 -0500290 ipmi_ret_t rc = IPMI_CC_OK;
Yong Li18d77262018-10-09 01:59:45 +0800291
292 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
293
294 auto value = acpi_state::ACPIPowerState::ACPI::Unknown;
295
296 auto* req = reinterpret_cast<acpi_state::ACPIState*>(request);
297
298 if (*data_len != sizeof(acpi_state::ACPIState))
299 {
300 log<level::ERR>("set_acpi invalid len");
301 *data_len = 0;
302 return IPMI_CC_REQ_DATA_LEN_INVALID;
303 }
304
Chris Austen6caf28b2015-10-13 12:40:40 -0500305 *data_len = 0;
306
Yong Li18d77262018-10-09 01:59:45 +0800307 if (req->sysACPIState & acpi_state::stateChanged)
308 {
309 // set system power state
310 s = req->sysACPIState & ~acpi_state::stateChanged;
311
312 if (!acpi_state::isValidACPIState(
313 acpi_state::PowerStateType::sysPowerState, s))
314 {
315 log<level::ERR>("set_acpi_power sys invalid input",
316 entry("S=%x", s));
317 return IPMI_CC_PARM_OUT_OF_RANGE;
318 }
319
320 // valid input
321 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
322 {
323 log<level::DEBUG>("No change for system power state");
324 }
325 else
326 {
327 auto found = std::find_if(
328 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
329 [&s](const auto& iter) {
330 return (static_cast<uint8_t>(iter.second) == s);
331 });
332
333 value = found->first;
334
335 try
336 {
337 auto acpiObject =
338 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
339 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
340 acpi_state::acpiInterface,
341 acpi_state::sysACPIProp,
342 convertForMessage(value));
343 }
344 catch (const InternalFailure& e)
345 {
346 log<level::ERR>("Failed in set ACPI system property",
347 entry("EXCEPTION=%s", e.what()));
348 return IPMI_CC_UNSPECIFIED_ERROR;
349 }
350 }
351 }
352 else
353 {
354 log<level::DEBUG>("Do not change system power state");
355 }
356
357 if (req->devACPIState & acpi_state::stateChanged)
358 {
359 // set device power state
360 s = req->devACPIState & ~acpi_state::stateChanged;
361 if (!acpi_state::isValidACPIState(
362 acpi_state::PowerStateType::devPowerState, s))
363 {
364 log<level::ERR>("set_acpi_power dev invalid input",
365 entry("S=%x", s));
366 return IPMI_CC_PARM_OUT_OF_RANGE;
367 }
368
369 // valid input
370 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
371 {
372 log<level::DEBUG>("No change for device power state");
373 }
374 else
375 {
376 auto found = std::find_if(
377 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
378 [&s](const auto& iter) {
379 return (static_cast<uint8_t>(iter.second) == s);
380 });
381
382 value = found->first;
383
384 try
385 {
386 auto acpiObject =
387 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
388 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
389 acpi_state::acpiInterface,
390 acpi_state::devACPIProp,
391 convertForMessage(value));
392 }
393 catch (const InternalFailure& e)
394 {
395 log<level::ERR>("Failed in set ACPI device property",
396 entry("EXCEPTION=%s", e.what()));
397 return IPMI_CC_UNSPECIFIED_ERROR;
398 }
399 }
400 }
401 else
402 {
403 log<level::DEBUG>("Do not change device power state");
404 }
405
406 return rc;
407}
408
409ipmi_ret_t ipmi_app_get_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
410 ipmi_request_t request,
411 ipmi_response_t response,
412 ipmi_data_len_t data_len,
413 ipmi_context_t context)
414{
415 ipmi_ret_t rc = IPMI_CC_OK;
416
417 auto* res = reinterpret_cast<acpi_state::ACPIState*>(response);
418
419 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
420
421 *data_len = 0;
422
423 try
424 {
425 auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface);
426
427 auto sysACPIVal = ipmi::getDbusProperty(
428 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
429 acpi_state::sysACPIProp);
430 auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString(
431 sysACPIVal.get<std::string>());
432 res->sysACPIState =
433 static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI));
434
435 auto devACPIVal = ipmi::getDbusProperty(
436 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
437 acpi_state::devACPIProp);
438 auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString(
439 devACPIVal.get<std::string>());
440 res->devACPIState =
441 static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI));
442
443 *data_len = sizeof(acpi_state::ACPIState);
444 }
445 catch (const InternalFailure& e)
446 {
447 log<level::ERR>("Failed in get ACPI property");
448 return IPMI_CC_UNSPECIFIED_ERROR;
449 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500450 return rc;
451}
452
Chris Austen7303bdc2016-04-17 11:50:54 -0500453typedef struct
454{
455 char major;
456 char minor;
Chris Austen176c9652016-04-30 16:32:17 -0500457 uint16_t d[2];
Chris Austen7303bdc2016-04-17 11:50:54 -0500458} rev_t;
459
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600460/* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */
461/* return -1 if not in those formats, this routine knows how to parse */
Chris Austen7303bdc2016-04-17 11:50:54 -0500462/* version = v0.6-19-gf363f61-dirty */
463/* ^ ^ ^^ ^ */
464/* | | |----------|-- additional details */
465/* | |---------------- Minor */
466/* |------------------ Major */
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600467/* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */
468/* ^ ^ ^^ ^ */
469/* | | |--|---------- additional details */
470/* | |---------------- Minor */
471/* |------------------ Major */
Chris Austen7303bdc2016-04-17 11:50:54 -0500472/* Additional details : If the option group exists it will force Auxiliary */
473/* Firmware Revision Information 4th byte to 1 indicating the build was */
474/* derived with additional edits */
Patrick Venture0b02be92018-08-31 11:55:55 -0700475int convert_version(const char* p, rev_t* rev)
Chris Austen7303bdc2016-04-17 11:50:54 -0500476{
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600477 std::string s(p);
478 std::string token;
Chris Austen176c9652016-04-30 16:32:17 -0500479 uint16_t commits;
Chris Austen7303bdc2016-04-17 11:50:54 -0500480
Patrick Venture0b02be92018-08-31 11:55:55 -0700481 auto location = s.find_first_of('v');
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600482 if (location != std::string::npos)
483 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700484 s = s.substr(location + 1);
Chris Austen176c9652016-04-30 16:32:17 -0500485 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500486
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600487 if (!s.empty())
488 {
489 location = s.find_first_of(".");
490 if (location != std::string::npos)
491 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700492 rev->major =
493 static_cast<char>(std::stoi(s.substr(0, location), 0, 16));
494 token = s.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600495 }
Chris Austen176c9652016-04-30 16:32:17 -0500496
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600497 if (!token.empty())
498 {
499 location = token.find_first_of(".-");
500 if (location != std::string::npos)
501 {
Patrick Ventured2117022018-02-06 08:54:37 -0800502 rev->minor = static_cast<char>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700503 std::stoi(token.substr(0, location), 0, 16));
504 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600505 }
506 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500507
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600508 // Capture the number of commits on top of the minor tag.
509 // I'm using BE format like the ipmi spec asked for
510 location = token.find_first_of(".-");
511 if (!token.empty())
512 {
513 commits = std::stoi(token.substr(0, location), 0, 16);
Patrick Venture0b02be92018-08-31 11:55:55 -0700514 rev->d[0] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600515
516 // commit number we skip
517 location = token.find_first_of(".-");
518 if (location != std::string::npos)
519 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700520 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600521 }
522 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700523 else
524 {
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600525 rev->d[0] = 0;
526 }
527
528 if (location != std::string::npos)
529 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700530 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600531 }
532
533 // Any value of the optional parameter forces it to 1
534 location = token.find_first_of(".-");
535 if (location != std::string::npos)
536 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700537 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600538 }
539 commits = (!token.empty()) ? 1 : 0;
540
Patrick Venture0b02be92018-08-31 11:55:55 -0700541 // We do this operation to get this displayed in least significant bytes
542 // of ipmitool device id command.
543 rev->d[1] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600544 }
545
Chris Austen7303bdc2016-04-17 11:50:54 -0500546 return 0;
547}
548
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500549ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700550 ipmi_request_t request,
551 ipmi_response_t response,
552 ipmi_data_len_t data_len,
553 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500554{
555 ipmi_ret_t rc = IPMI_CC_OK;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600556 int r = -1;
Chris Austen7303bdc2016-04-17 11:50:54 -0500557 rev_t rev = {0};
David Cobbleya1adb072017-11-21 15:58:13 -0800558 static ipmi_device_id_t dev_id{};
559 static bool dev_id_initialized = false;
560 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
Alexander Amelkinba19c182018-09-04 15:49:36 +0300561 constexpr auto ipmiDevIdStateShift = 7;
562 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
Chris Austen6caf28b2015-10-13 12:40:40 -0500563
564 // Data length
Chris Austen7303bdc2016-04-17 11:50:54 -0500565 *data_len = sizeof(dev_id);
566
David Cobbleya1adb072017-11-21 15:58:13 -0800567 if (!dev_id_initialized)
568 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600569 try
570 {
571 auto version = getActiveSoftwareVersionInfo();
572 r = convert_version(version.c_str(), &rev);
David Cobbleya1adb072017-11-21 15:58:13 -0800573 }
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600574 catch (const std::exception& e)
575 {
576 log<level::ERR>(e.what());
577 }
Nan Liee0cb902016-07-11 15:38:03 +0800578
Patrick Venture0b02be92018-08-31 11:55:55 -0700579 if (r >= 0)
580 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600581 // bit7 identifies if the device is available
582 // 0=normal operation
583 // 1=device firmware, SDR update,
584 // or self-initialization in progress.
Alexander Amelkinba19c182018-09-04 15:49:36 +0300585 // The availability may change in run time, so mask here
586 // and initialize later.
587 dev_id.fw[0] = rev.major & ipmiDevIdFw1Mask;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600588
589 rev.minor = (rev.minor > 99 ? 99 : rev.minor);
590 dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700591 std::memcpy(&dev_id.aux, rev.d, 4);
David Cobbleya1adb072017-11-21 15:58:13 -0800592 }
Nan Liee0cb902016-07-11 15:38:03 +0800593
David Cobbleya1adb072017-11-21 15:58:13 -0800594 // IPMI Spec version 2.0
595 dev_id.ipmi_ver = 2;
Adriana Kobylak0e912642016-06-22 16:54:39 -0500596
David Cobbleya1adb072017-11-21 15:58:13 -0800597 std::ifstream dev_id_file(filename);
598 if (dev_id_file.is_open())
599 {
600 auto data = nlohmann::json::parse(dev_id_file, nullptr, false);
601 if (!data.is_discarded())
602 {
603 dev_id.id = data.value("id", 0);
604 dev_id.revision = data.value("revision", 0);
605 dev_id.addn_dev_support = data.value("addn_dev_support", 0);
606 dev_id.manuf_id[2] = data.value("manuf_id", 0) >> 16;
607 dev_id.manuf_id[1] = data.value("manuf_id", 0) >> 8;
608 dev_id.manuf_id[0] = data.value("manuf_id", 0);
609 dev_id.prod_id[1] = data.value("prod_id", 0) >> 8;
610 dev_id.prod_id[0] = data.value("prod_id", 0);
Tom Josephaf8a0982018-03-09 07:54:02 -0600611 dev_id.aux[3] = data.value("aux", 0);
612 dev_id.aux[2] = data.value("aux", 0) >> 8;
613 dev_id.aux[1] = data.value("aux", 0) >> 16;
614 dev_id.aux[0] = data.value("aux", 0) >> 24;
David Cobbleya1adb072017-11-21 15:58:13 -0800615
Patrick Venture0b02be92018-08-31 11:55:55 -0700616 // Don't read the file every time if successful
David Cobbleya1adb072017-11-21 15:58:13 -0800617 dev_id_initialized = true;
618 }
619 else
620 {
621 log<level::ERR>("Device ID JSON parser failure");
622 rc = IPMI_CC_UNSPECIFIED_ERROR;
623 }
624 }
625 else
626 {
627 log<level::ERR>("Device ID file not found");
628 rc = IPMI_CC_UNSPECIFIED_ERROR;
Chris Austen7303bdc2016-04-17 11:50:54 -0500629 }
630 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500631
Alexander Amelkinba19c182018-09-04 15:49:36 +0300632 // Set availability to the actual current BMC state
633 dev_id.fw[0] &= ipmiDevIdFw1Mask;
634 if (!getCurrentBmcState())
635 {
636 dev_id.fw[0] |= (1 << ipmiDevIdStateShift);
637 }
638
Chris Austen6caf28b2015-10-13 12:40:40 -0500639 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700640 std::memcpy(response, &dev_id, *data_len);
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600641
Chris Austen6caf28b2015-10-13 12:40:40 -0500642 return rc;
643}
644
Nan Li41fa24a2016-11-10 20:12:37 +0800645ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700646 ipmi_request_t request,
647 ipmi_response_t response,
648 ipmi_data_len_t data_len,
649 ipmi_context_t context)
Nan Li41fa24a2016-11-10 20:12:37 +0800650{
651 ipmi_ret_t rc = IPMI_CC_OK;
652
653 // Byte 2:
654 // 55h - No error.
Gunnar Mills8991dd62017-10-25 17:11:29 -0500655 // 56h - Self Test function not implemented in this controller.
Nan Li41fa24a2016-11-10 20:12:37 +0800656 // 57h - Corrupted or inaccesssible data or devices.
657 // 58h - Fatal hardware error.
658 // FFh - reserved.
659 // all other: Device-specific 'internal failure'.
660 // Byte 3:
661 // For byte 2 = 55h, 56h, FFh: 00h
662 // For byte 2 = 58h, all other: Device-specific
663 // For byte 2 = 57h: self-test error bitfield.
664 // Note: returning 57h does not imply that all test were run.
665 // [7] 1b = Cannot access SEL device.
666 // [6] 1b = Cannot access SDR Repository.
667 // [5] 1b = Cannot access BMC FRU device.
668 // [4] 1b = IPMB signal lines do not respond.
669 // [3] 1b = SDR Repository empty.
670 // [2] 1b = Internal Use Area of BMC FRU corrupted.
671 // [1] 1b = controller update 'boot block' firmware corrupted.
672 // [0] 1b = controller operational firmware corrupted.
673
674 char selftestresults[2] = {0};
675
676 *data_len = 2;
677
678 selftestresults[0] = 0x56;
679 selftestresults[1] = 0;
680
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700681 std::memcpy(response, selftestresults, *data_len);
Nan Li41fa24a2016-11-10 20:12:37 +0800682
683 return rc;
684}
685
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500686ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700687 ipmi_request_t request,
688 ipmi_response_t response,
689 ipmi_data_len_t data_len,
690 ipmi_context_t context)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500691{
Patrick Venture0b02be92018-08-31 11:55:55 -0700692 const char* objname = "/org/openbmc/control/chassis0";
693 const char* iface = "org.freedesktop.DBus.Properties";
694 const char* chassis_iface = "org.openbmc.control.Chassis";
695 sd_bus_message* reply = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500696 sd_bus_error error = SD_BUS_ERROR_NULL;
697 int r = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700698 char* uuid = NULL;
699 char* busname = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500700
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500701 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Ventured2117022018-02-06 08:54:37 -0800702 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
703 // order
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500704 // Ex: 0x2332fc2c40e66298e511f2782395a361
705
Patrick Venture0b02be92018-08-31 11:55:55 -0700706 const int resp_size = 16; // Response is 16 hex bytes per IPMI Spec
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500707 uint8_t resp_uuid[resp_size]; // Array to hold the formatted response
Patrick Ventured2117022018-02-06 08:54:37 -0800708 // Point resp end of array to save in reverse order
Patrick Venture0b02be92018-08-31 11:55:55 -0700709 int resp_loc = resp_size - 1;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500710 int i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700711 char* tokptr = NULL;
712 char* id_octet = NULL;
Emily Shafferedb8bb02018-09-27 14:50:15 -0700713 size_t total_uuid_size = 0;
714 // 1 byte of resp is built from 2 chars of uuid.
715 constexpr size_t max_uuid_size = 2 * resp_size;
vishwa1eaea4f2016-02-26 11:57:40 -0600716
717 // Status code.
718 ipmi_ret_t rc = IPMI_CC_OK;
719 *data_len = 0;
720
vishwa1eaea4f2016-02-26 11:57:40 -0600721 // Call Get properties method with the interface and property name
Sergey Solomineb9b8142016-08-23 09:07:28 -0500722 r = mapper_get_service(bus, objname, &busname);
Patrick Venture0b02be92018-08-31 11:55:55 -0700723 if (r < 0)
724 {
725 log<level::ERR>("Failed to get bus name", entry("BUS=%s", objname),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530726 entry("ERRNO=0x%X", -r));
Sergey Solomineb9b8142016-08-23 09:07:28 -0500727 goto finish;
728 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700729 r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply,
730 "ss", chassis_iface, "uuid");
vishwa1eaea4f2016-02-26 11:57:40 -0600731 if (r < 0)
732 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700733 log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600734 rc = IPMI_CC_UNSPECIFIED_ERROR;
735 goto finish;
736 }
737
738 r = sd_bus_message_read(reply, "v", "s", &uuid);
739 if (r < 0 || uuid == NULL)
740 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700741 log<level::ERR>("Failed to get a response", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600742 rc = IPMI_CC_RESPONSE_ERROR;
743 goto finish;
744 }
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500745
746 // Traverse the UUID
Patrick Ventured2117022018-02-06 08:54:37 -0800747 // Get the UUID octects separated by dash
748 id_octet = strtok_r(uuid, "-", &tokptr);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500749
750 if (id_octet == NULL)
vishwa1eaea4f2016-02-26 11:57:40 -0600751 {
752 // Error
Patrick Venture0b02be92018-08-31 11:55:55 -0700753 log<level::ERR>("Unexpected UUID format", entry("UUID=%s", uuid));
vishwa1eaea4f2016-02-26 11:57:40 -0600754 rc = IPMI_CC_RESPONSE_ERROR;
755 goto finish;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500756 }
757
758 while (id_octet != NULL)
759 {
760 // Calculate the octet string size since it varies
761 // Divide it by 2 for the array size since 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700762 int tmp_size = strlen(id_octet) / 2;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500763
Emily Shafferedb8bb02018-09-27 14:50:15 -0700764 // Check if total UUID size has been exceeded
765 if ((total_uuid_size += strlen(id_octet)) > max_uuid_size)
766 {
767 // Error - UUID too long to store
768 log<level::ERR>("UUID too long", entry("UUID=%s", uuid));
769 rc = IPMI_CC_RESPONSE_ERROR;
770 goto finish;
771 }
772
Patrick Venture0b02be92018-08-31 11:55:55 -0700773 for (i = 0; i < tmp_size; i++)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500774 {
Patrick Ventured2117022018-02-06 08:54:37 -0800775 // Holder of the 2 chars that will become a byte
776 char tmp_array[3] = {0};
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500777 strncpy(tmp_array, id_octet, 2); // 2 chars at a time
778
779 int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
Patrick Ventured2117022018-02-06 08:54:37 -0800780 // Copy end to first
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700781 std::memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500782 resp_loc--;
Patrick Venture0b02be92018-08-31 11:55:55 -0700783 id_octet += 2; // Finished with the 2 chars, advance
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500784 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700785 id_octet = strtok_r(NULL, "-", &tokptr); // Get next octet
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500786 }
787
788 // Data length
789 *data_len = resp_size;
790
791 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700792 std::memcpy(response, &resp_uuid, *data_len);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500793
vishwa1eaea4f2016-02-26 11:57:40 -0600794finish:
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500795 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600796 reply = sd_bus_message_unref(reply);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500797 free(busname);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500798
799 return rc;
800}
Chris Austen6caf28b2015-10-13 12:40:40 -0500801
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500802ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700803 ipmi_request_t request,
804 ipmi_response_t response,
805 ipmi_data_len_t data_len,
806 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530807{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530808
809 // Status code.
810 ipmi_ret_t rc = IPMI_CC_OK;
811
Adriana Kobylak88ad8152016-12-13 10:09:08 -0600812 // Per IPMI 2.0 spec, the input and output buffer size must be the max
813 // buffer size minus one byte to allocate space for the length byte.
Patrick Venture0b02be92018-08-31 11:55:55 -0700814 uint8_t str[] = {0x01, MAX_IPMI_BUFFER - 1, MAX_IPMI_BUFFER - 1, 0x0A,
815 0x01};
vishwabmcba0bd5f2015-09-30 16:50:23 +0530816
817 // Data length
818 *data_len = sizeof(str);
819
820 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700821 std::memcpy(response, &str, *data_len);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530822
823 return rc;
824}
825
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500826ipmi_ret_t ipmi_app_wildcard_handler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700827 ipmi_request_t request,
828 ipmi_response_t response,
829 ipmi_data_len_t data_len,
830 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530831{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530832 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800833 ipmi_ret_t rc = IPMI_CC_INVALID;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530834
835 *data_len = strlen("THIS IS WILDCARD");
836
837 // Now pack actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700838 std::memcpy(response, "THIS IS WILDCARD", *data_len);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530839
840 return rc;
841}
842
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600843ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700844 ipmi_request_t request,
845 ipmi_response_t response,
846 ipmi_data_len_t data_len,
847 ipmi_context_t context)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600848
849{
850 ipmi_ret_t rc = IPMI_CC_OK;
851 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
852
853 try
854 {
855 // Get the Inventory object implementing BMC interface
856 ipmi::DbusObjectInfo bmcObject =
857 ipmi::getDbusObject(bus, bmc_interface);
858
859 // Read UUID property value from bmcObject
860 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Venture0b02be92018-08-31 11:55:55 -0700861 auto variant =
862 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
863 bmc_guid_interface, bmc_guid_property);
William A. Kennington III4c008022018-10-12 17:18:14 -0700864 std::string guidProp = variant_ns::get<std::string>(variant);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600865
866 // Erase "-" characters from the property value
867 guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'),
Patrick Venture0b02be92018-08-31 11:55:55 -0700868 guidProp.end());
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600869
870 auto guidPropLen = guidProp.length();
871 // Validate UUID data
872 // Divide by 2 as 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700873 if ((guidPropLen <= 0) || ((guidPropLen / 2) != bmc_guid_len))
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600874
875 {
876 log<level::ERR>("Invalid UUID property value",
Patrick Venture0b02be92018-08-31 11:55:55 -0700877 entry("UUID_LENGTH=%d", guidPropLen));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600878 return IPMI_CC_RESPONSE_ERROR;
879 }
880
881 // Convert data in RFC4122(MSB) format to LSB format
882 // Get 2 characters at a time as 1 byte is built from 2 chars and
883 // convert to hex byte
884 // TODO: Data printed for GUID command is not as per the
885 // GUID format defined in IPMI specification 2.0 section 20.8
886 // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/
887 uint8_t respGuid[bmc_guid_len];
888 for (size_t i = 0, respLoc = (bmc_guid_len - 1);
Patrick Venture0b02be92018-08-31 11:55:55 -0700889 i < guidPropLen && respLoc >= 0; i += 2, respLoc--)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600890 {
891 auto value = static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700892 std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600893 respGuid[respLoc] = value;
894 }
895
896 *data_len = bmc_guid_len;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700897 std::memcpy(response, &respGuid, bmc_guid_len);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600898 }
899 catch (const InternalFailure& e)
900 {
901 log<level::ERR>("Failed in reading BMC UUID property",
902 entry("INTERFACE=%s", bmc_interface),
903 entry("PROPERTY_INTERFACE=%s", bmc_guid_interface),
904 entry("PROPERTY=%s", bmc_guid_property));
905 return IPMI_CC_UNSPECIFIED_ERROR;
906 }
907 return rc;
908}
909
Xo Wangf542e8b2017-08-09 15:34:16 -0700910static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
911
Xo Wang87651332017-08-11 10:17:59 -0700912static std::string sysInfoReadSystemName()
913{
914 // Use the BMC hostname as the "System Name."
915 char hostname[HOST_NAME_MAX + 1] = {};
916 if (gethostname(hostname, HOST_NAME_MAX) != 0)
917 {
918 perror("System info parameter: system name");
919 }
920 return hostname;
921}
922
Xo Wangf542e8b2017-08-09 15:34:16 -0700923struct IpmiSysInfoResp
924{
925 uint8_t paramRevision;
926 uint8_t setSelector;
927 union
928 {
929 struct
930 {
931 uint8_t encoding;
932 uint8_t stringLen;
933 uint8_t stringData0[14];
934 } __attribute__((packed));
935 uint8_t stringDataN[16];
936 uint8_t byteData;
937 };
938} __attribute__((packed));
939
940/**
941 * Split a string into (up to) 16-byte chunks as expected in response for get
942 * system info parameter.
943 *
944 * @param[in] fullString: Input string to be split
945 * @param[in] chunkIndex: Index of the chunk to be written out
946 * @param[in,out] chunk: Output data buffer; must have 14 byte capacity if
947 * chunk_index = 0 and 16-byte capacity otherwise
948 * @return the number of bytes written into the output buffer, or -EINVAL for
949 * invalid arguments.
950 */
951static int splitStringParam(const std::string& fullString, int chunkIndex,
952 uint8_t* chunk)
953{
954 constexpr int maxChunk = 255;
955 constexpr int smallChunk = 14;
956 constexpr int chunkSize = 16;
957 if (chunkIndex > maxChunk || chunk == nullptr)
958 {
959 return -EINVAL;
960 }
961 try
962 {
963 std::string output;
964 if (chunkIndex == 0)
965 {
966 // Output must have 14 byte capacity.
967 output = fullString.substr(0, smallChunk);
968 }
969 else
970 {
971 // Output must have 16 byte capacity.
972 output = fullString.substr((chunkIndex * chunkSize) - 2, chunkSize);
973 }
974
975 std::memcpy(chunk, output.c_str(), output.length());
976 return output.length();
977 }
978 catch (const std::out_of_range& e)
979 {
980 // The position was beyond the end.
981 return -EINVAL;
982 }
983}
984
985/**
986 * Packs the Get Sys Info Request Item into the response.
987 *
988 * @param[in] paramString - the parameter.
989 * @param[in] setSelector - the selector
990 * @param[in,out] resp - the System info response.
991 * @return The number of bytes packed or failure from splitStringParam().
992 */
993static int packGetSysInfoResp(const std::string& paramString,
994 uint8_t setSelector, IpmiSysInfoResp* resp)
995{
996 uint8_t* dataBuffer = resp->stringDataN;
997 resp->setSelector = setSelector;
998 if (resp->setSelector == 0) // First chunk has only 14 bytes.
999 {
1000 resp->encoding = 0;
1001 resp->stringLen = paramString.length();
1002 dataBuffer = resp->stringData0;
1003 }
1004 return splitStringParam(paramString, resp->setSelector, dataBuffer);
1005}
1006
1007ipmi_ret_t ipmi_app_get_system_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1008 ipmi_request_t request,
1009 ipmi_response_t response,
1010 ipmi_data_len_t dataLen,
1011 ipmi_context_t context)
1012{
1013 IpmiSysInfoResp resp = {};
1014 size_t respLen = 0;
1015 uint8_t* const reqData = static_cast<uint8_t*>(request);
1016 std::string paramString;
1017 bool found;
1018 std::tuple<bool, std::string> ret;
1019 constexpr int minRequestSize = 4;
1020 constexpr int paramSelector = 1;
1021 constexpr uint8_t revisionOnly = 0x80;
1022 const uint8_t paramRequested = reqData[paramSelector];
1023 int rc;
1024
1025 if (*dataLen < minRequestSize)
1026 {
1027 return IPMI_CC_REQ_DATA_LEN_INVALID;
1028 }
1029
1030 *dataLen = 0; // default to 0.
1031
1032 // Parameters revision as of IPMI spec v2.0 rev. 1.1 (Feb 11, 2014 E6)
1033 resp.paramRevision = 0x11;
1034 if (reqData[0] & revisionOnly) // Get parameter revision only
1035 {
1036 respLen = 1;
1037 goto writeResponse;
1038 }
1039
1040 // The "Set In Progress" parameter can be used for rollback of parameter
1041 // data and is not implemented.
1042 if (paramRequested == 0)
1043 {
1044 resp.byteData = 0;
1045 respLen = 2;
1046 goto writeResponse;
1047 }
1048
1049 if (sysInfoParamStore == nullptr)
1050 {
1051 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
Xo Wang87651332017-08-11 10:17:59 -07001052 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1053 sysInfoReadSystemName);
Xo Wangf542e8b2017-08-09 15:34:16 -07001054 }
1055
1056 // Parameters other than Set In Progress are assumed to be strings.
1057 ret = sysInfoParamStore->lookup(paramRequested);
1058 found = std::get<0>(ret);
1059 paramString = std::get<1>(ret);
1060 if (!found)
1061 {
1062 return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
1063 }
1064 // TODO: Cache each parameter across multiple calls, until the whole string
1065 // has been read out. Otherwise, it's possible for a parameter to change
1066 // between requests for its chunks, returning chunks incoherent with each
1067 // other. For now, the parameter store is simply required to have only
1068 // idempotent callbacks.
1069 rc = packGetSysInfoResp(paramString, reqData[2], &resp);
1070 if (rc == -EINVAL)
1071 {
1072 return IPMI_CC_RESPONSE_ERROR;
1073 }
1074
1075 respLen = sizeof(resp); // Write entire string data chunk in response.
1076
1077writeResponse:
1078 std::memcpy(response, &resp, sizeof(resp));
1079 *dataLen = respLen;
1080 return IPMI_CC_OK;
1081}
1082
Chris Austen6caf28b2015-10-13 12:40:40 -05001083void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +05301084{
Tom05732372016-09-06 17:21:23 +05301085 // <Get BT Interface Capabilities>
Patrick Venture0b02be92018-08-31 11:55:55 -07001086 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL,
1087 ipmi_app_get_bt_capabilities, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001088
Tom05732372016-09-06 17:21:23 +05301089 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001090 ipmi_register_callback(NETFUN_APP, IPMI_CMD_WILDCARD, NULL,
1091 ipmi_app_wildcard_handler, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001092
Tom05732372016-09-06 17:21:23 +05301093 // <Reset Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001094 ipmi_register_callback(NETFUN_APP, IPMI_CMD_RESET_WD, NULL,
1095 ipmi_app_watchdog_reset, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -05001096
Tom05732372016-09-06 17:21:23 +05301097 // <Set Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001098 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL,
1099 ipmi_app_watchdog_set, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -05001100
William A. Kennington III73f44512018-02-09 15:28:46 -08001101 // <Get Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001102 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_WD, NULL,
1103 ipmi_app_watchdog_get, PRIVILEGE_OPERATOR);
William A. Kennington III73f44512018-02-09 15:28:46 -08001104
Tom05732372016-09-06 17:21:23 +05301105 // <Get Device ID>
Patrick Venture0b02be92018-08-31 11:55:55 -07001106 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_ID, NULL,
1107 ipmi_app_get_device_id, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001108
Tom05732372016-09-06 17:21:23 +05301109 // <Get Self Test Results>
Patrick Venture0b02be92018-08-31 11:55:55 -07001110 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS, NULL,
1111 ipmi_app_get_self_test_results, PRIVILEGE_USER);
Nan Li41fa24a2016-11-10 20:12:37 +08001112
Tom05732372016-09-06 17:21:23 +05301113 // <Get Device GUID>
Patrick Venture0b02be92018-08-31 11:55:55 -07001114 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID, NULL,
1115 ipmi_app_get_device_guid, PRIVILEGE_USER);
Adriana Kobylakd100ee52015-10-20 17:02:37 -05001116
Tom05732372016-09-06 17:21:23 +05301117 // <Set ACPI Power State>
Patrick Venture0b02be92018-08-31 11:55:55 -07001118 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL,
1119 ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN);
Chris Austen6caf28b2015-10-13 12:40:40 -05001120
Yong Li18d77262018-10-09 01:59:45 +08001121 // <Get ACPI Power State>
1122 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_ACPI, NULL,
1123 ipmi_app_get_acpi_power_state, PRIVILEGE_ADMIN);
1124
Tom Joseph69fabfe2017-08-04 10:15:01 +05301125 // <Get Channel Access>
Patrick Venture0b02be92018-08-31 11:55:55 -07001126 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
1127 ipmi_get_channel_access, PRIVILEGE_USER);
Tom Joseph69fabfe2017-08-04 10:15:01 +05301128
Tom05732372016-09-06 17:21:23 +05301129 // <Get Channel Info Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001130 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL,
1131 ipmi_app_channel_info, PRIVILEGE_USER);
Chris Austenc2cd29d2016-02-05 20:02:29 -06001132
Marri Devender Rao5e007a52018-01-08 06:18:36 -06001133 // <Get System GUID Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001134 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL,
1135 ipmi_app_get_sys_guid, PRIVILEGE_USER);
Tom Joseph7cbe2282018-03-21 21:17:33 +05301136
1137 // <Get Channel Cipher Suites Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001138 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_CIPHER_SUITES, NULL,
1139 getChannelCipherSuites, PRIVILEGE_CALLBACK);
Tom Joseph13227682018-08-10 01:05:21 +05301140 // <Set Channel Access Command>
1141 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL,
1142 ipmi_set_channel_access, PRIVILEGE_ADMIN);
Xo Wangf542e8b2017-08-09 15:34:16 -07001143
1144 // <Get System Info Command>
1145 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYSTEM_INFO, NULL,
1146 ipmi_app_get_system_info, PRIVILEGE_USER);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301147 ipmi::registerUserIpmiFunctions();
vishwabmcba0bd5f2015-09-30 16:50:23 +05301148 return;
1149}