blob: bd4b5c3a7435b3b14cc004b3064b9514f6c2bffb [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"
AppaRao Puli071f3f22018-05-24 16:45:30 +05309#include "user_channel/channelcommands.hpp"
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +053010#include "user_channel/usercommands.hpp"
Xo Wangf542e8b2017-08-09 15:34:16 -070011#include "utils.hpp"
12
Patrick Venture0b02be92018-08-31 11:55:55 -070013#include <arpa/inet.h>
Patrick Venture46470a32018-09-07 19:26:25 -070014#include <host-ipmid/ipmid-api.h>
Xo Wang87651332017-08-11 10:17:59 -070015#include <limits.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070016#include <mapper.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070017#include <systemd/sd-bus.h>
Xo Wang87651332017-08-11 10:17:59 -070018#include <unistd.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070019
Patrick Venture3a5071a2018-09-12 13:27:42 -070020#include <algorithm>
21#include <array>
22#include <cstddef>
23#include <fstream>
24#include <memory>
Patrick Venture46470a32018-09-07 19:26:25 -070025#include <nlohmann/json.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070026#include <phosphor-logging/elog-errors.hpp>
27#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070028#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070029#include <string>
30#include <tuple>
31#include <vector>
32#include <xyz/openbmc_project/Common/error.hpp>
Yong Li18d77262018-10-09 01:59:45 +080033#include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070034#include <xyz/openbmc_project/Software/Activation/server.hpp>
35#include <xyz/openbmc_project/Software/Version/server.hpp>
36#include <xyz/openbmc_project/State/BMC/server.hpp>
Ratan Guptab8e99552017-07-27 07:07:48 +053037
Vernon Mauery185b9f82018-07-20 10:52:36 -070038#if __has_include(<filesystem>)
39#include <filesystem>
40#elif __has_include(<experimental/filesystem>)
41#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070042namespace std
43{
44// splice experimental::filesystem into std
45namespace filesystem = std::experimental::filesystem;
46} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070047#else
Patrick Venture0b02be92018-08-31 11:55:55 -070048#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070049#endif
Ratan Gupta62736ec2017-09-02 12:02:47 +053050
Patrick Venture0b02be92018-08-31 11:55:55 -070051extern sd_bus* bus;
vishwabmcba0bd5f2015-09-30 16:50:23 +053052
Alexander Amelkinba19c182018-09-04 15:49:36 +030053constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
54constexpr auto bmc_state_property = "CurrentBMCState";
Marri Devender Rao5e007a52018-01-08 06:18:36 -060055constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
56constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
57constexpr auto bmc_guid_property = "UUID";
58constexpr auto bmc_guid_len = 16;
59
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060060static constexpr auto redundancyIntf =
61 "xyz.openbmc_project.Software.RedundancyPriority";
Patrick Venture0b02be92018-08-31 11:55:55 -070062static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060063static constexpr auto activationIntf =
64 "xyz.openbmc_project.Software.Activation";
65static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
66
Chris Austen6caf28b2015-10-13 12:40:40 -050067void register_netfn_app_functions() __attribute__((constructor));
vishwabmcba0bd5f2015-09-30 16:50:23 +053068
Ratan Guptab8e99552017-07-27 07:07:48 +053069using namespace phosphor::logging;
70using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060071using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
72using Activation =
73 sdbusplus::xyz::openbmc_project::Software::server::Activation;
Alexander Amelkinba19c182018-09-04 15:49:36 +030074using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC;
Vernon Mauery185b9f82018-07-20 10:52:36 -070075namespace fs = std::filesystem;
William A. Kennington III4c008022018-10-12 17:18:14 -070076namespace variant_ns = sdbusplus::message::variant_ns;
Ratan Guptab8e99552017-07-27 07:07:48 +053077
Nan Liee0cb902016-07-11 15:38:03 +080078// Offset in get device id command.
79typedef struct
80{
Patrick Venture0b02be92018-08-31 11:55:55 -070081 uint8_t id;
82 uint8_t revision;
83 uint8_t fw[2];
84 uint8_t ipmi_ver;
85 uint8_t addn_dev_support;
86 uint8_t manuf_id[3];
87 uint8_t prod_id[2];
88 uint8_t aux[4];
89} __attribute__((packed)) ipmi_device_id_t;
Chris Austen7303bdc2016-04-17 11:50:54 -050090
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060091/**
92 * @brief Returns the Version info from primary s/w object
93 *
94 * Get the Version info from the active s/w object which is having high
95 * "Priority" value(a smaller number is a higher priority) and "Purpose"
96 * is "BMC" from the list of all s/w objects those are implementing
97 * RedundancyPriority interface from the given softwareRoot path.
98 *
99 * @return On success returns the Version info from primary s/w object.
100 *
101 */
102std::string getActiveSoftwareVersionInfo()
103{
104 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
105
106 std::string revision{};
Patrick Venture0b02be92018-08-31 11:55:55 -0700107 auto objectTree =
108 ipmi::getAllDbusObjects(bus, softwareRoot, redundancyIntf, "");
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600109 if (objectTree.empty())
110 {
111 log<level::ERR>("No Obj has implemented the s/w redundancy interface",
112 entry("INTERFACE=%s", redundancyIntf));
113 elog<InternalFailure>();
114 }
115
116 auto objectFound = false;
117 for (auto& softObject : objectTree)
118 {
119 auto service = ipmi::getService(bus, redundancyIntf, softObject.first);
120 auto objValueTree = ipmi::getManagedObjects(bus, service, softwareRoot);
121
122 auto minPriority = 0xFF;
123 for (const auto& objIter : objValueTree)
124 {
125 try
126 {
127 auto& intfMap = objIter.second;
128 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
129 auto& versionProps = intfMap.at(versionIntf);
130 auto& activationProps = intfMap.at(activationIntf);
William A. Kennington III4c008022018-10-12 17:18:14 -0700131 auto priority = variant_ns::get<uint8_t>(
132 redundancyPriorityProps.at("Priority"));
133 auto purpose =
134 variant_ns::get<std::string>(versionProps.at("Purpose"));
135 auto activation = variant_ns::get<std::string>(
136 activationProps.at("Activation"));
137 auto version =
138 variant_ns::get<std::string>(versionProps.at("Version"));
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600139 if ((Version::convertVersionPurposeFromString(purpose) ==
140 Version::VersionPurpose::BMC) &&
141 (Activation::convertActivationsFromString(activation) ==
142 Activation::Activations::Active))
143 {
144 if (priority < minPriority)
145 {
146 minPriority = priority;
147 objectFound = true;
148 revision = std::move(version);
149 }
150 }
151 }
152 catch (const std::exception& e)
153 {
154 log<level::ERR>(e.what());
155 }
156 }
157 }
158
159 if (!objectFound)
160 {
161 log<level::ERR>("Could not found an BMC software Object");
162 elog<InternalFailure>();
163 }
164
165 return revision;
166}
167
Alexander Amelkinba19c182018-09-04 15:49:36 +0300168bool getCurrentBmcState()
169{
170 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
171
172 // Get the Inventory object implementing the BMC interface
173 ipmi::DbusObjectInfo bmcObject =
174 ipmi::getDbusObject(bus, bmc_state_interface);
175 auto variant =
176 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
177 bmc_state_interface, bmc_state_property);
178
William A. Kennington III4c008022018-10-12 17:18:14 -0700179 return variant_ns::holds_alternative<std::string>(variant) &&
180 BMC::convertBMCStateFromString(
181 variant_ns::get<std::string>(variant)) == BMC::BMCState::Ready;
Alexander Amelkinba19c182018-09-04 15:49:36 +0300182}
183
Yong Li18d77262018-10-09 01:59:45 +0800184namespace acpi_state
185{
186using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
187
188const static constexpr char* acpiObjPath =
189 "/xyz/openbmc_project/control/host0/acpi_power_state";
190const static constexpr char* acpiInterface =
191 "xyz.openbmc_project.Control.Power.ACPIPowerState";
192const static constexpr char* sysACPIProp = "SysACPIStatus";
193const static constexpr char* devACPIProp = "DevACPIStatus";
194
195enum class PowerStateType : uint8_t
196{
197 sysPowerState = 0x00,
198 devPowerState = 0x01,
199};
200
201// Defined in 20.6 of ipmi doc
202enum class PowerState : uint8_t
203{
204 s0G0D0 = 0x00,
205 s1D1 = 0x01,
206 s2D2 = 0x02,
207 s3D3 = 0x03,
208 s4 = 0x04,
209 s5G2 = 0x05,
210 s4S5 = 0x06,
211 g3 = 0x07,
212 sleep = 0x08,
213 g1Sleep = 0x09,
214 override = 0x0a,
215 legacyOn = 0x20,
216 legacyOff = 0x21,
217 unknown = 0x2a,
218 noChange = 0x7f,
219};
220
221static constexpr uint8_t stateChanged = 0x80;
222
223struct ACPIState
224{
225 uint8_t sysACPIState;
226 uint8_t devACPIState;
227} __attribute__((packed));
228
229std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = {
230 {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0},
231 {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1},
232 {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2},
233 {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3},
234 {ACPIPowerState::ACPI::S4, PowerState::s4},
235 {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2},
236 {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5},
237 {ACPIPowerState::ACPI::G3, PowerState::g3},
238 {ACPIPowerState::ACPI::SLEEP, PowerState::sleep},
239 {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep},
240 {ACPIPowerState::ACPI::OVERRIDE, PowerState::override},
241 {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn},
242 {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff},
243 {ACPIPowerState::ACPI::Unknown, PowerState::unknown}};
244
245bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state)
246{
247 if (type == acpi_state::PowerStateType::sysPowerState)
248 {
249 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) ||
250 (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) ||
251 (state ==
252 static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) ||
253 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
254 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
255 {
256 return true;
257 }
258 else
259 {
260 return false;
261 }
262 }
263 else if (type == acpi_state::PowerStateType::devPowerState)
264 {
265 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) ||
266 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
267 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
268 {
269 return true;
270 }
271 else
272 {
273 return false;
274 }
275 }
276 else
277 {
278 return false;
279 }
280 return false;
281}
282} // namespace acpi_state
283
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500284ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700285 ipmi_request_t request,
286 ipmi_response_t response,
287 ipmi_data_len_t data_len,
288 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500289{
Yong Li18d77262018-10-09 01:59:45 +0800290 auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown);
Chris Austen6caf28b2015-10-13 12:40:40 -0500291 ipmi_ret_t rc = IPMI_CC_OK;
Yong Li18d77262018-10-09 01:59:45 +0800292
293 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
294
295 auto value = acpi_state::ACPIPowerState::ACPI::Unknown;
296
297 auto* req = reinterpret_cast<acpi_state::ACPIState*>(request);
298
299 if (*data_len != sizeof(acpi_state::ACPIState))
300 {
301 log<level::ERR>("set_acpi invalid len");
302 *data_len = 0;
303 return IPMI_CC_REQ_DATA_LEN_INVALID;
304 }
305
Chris Austen6caf28b2015-10-13 12:40:40 -0500306 *data_len = 0;
307
Yong Li18d77262018-10-09 01:59:45 +0800308 if (req->sysACPIState & acpi_state::stateChanged)
309 {
310 // set system power state
311 s = req->sysACPIState & ~acpi_state::stateChanged;
312
313 if (!acpi_state::isValidACPIState(
314 acpi_state::PowerStateType::sysPowerState, s))
315 {
316 log<level::ERR>("set_acpi_power sys invalid input",
317 entry("S=%x", s));
318 return IPMI_CC_PARM_OUT_OF_RANGE;
319 }
320
321 // valid input
322 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
323 {
324 log<level::DEBUG>("No change for system power state");
325 }
326 else
327 {
328 auto found = std::find_if(
329 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
330 [&s](const auto& iter) {
331 return (static_cast<uint8_t>(iter.second) == s);
332 });
333
334 value = found->first;
335
336 try
337 {
338 auto acpiObject =
339 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
340 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
341 acpi_state::acpiInterface,
342 acpi_state::sysACPIProp,
343 convertForMessage(value));
344 }
345 catch (const InternalFailure& e)
346 {
347 log<level::ERR>("Failed in set ACPI system property",
348 entry("EXCEPTION=%s", e.what()));
349 return IPMI_CC_UNSPECIFIED_ERROR;
350 }
351 }
352 }
353 else
354 {
355 log<level::DEBUG>("Do not change system power state");
356 }
357
358 if (req->devACPIState & acpi_state::stateChanged)
359 {
360 // set device power state
361 s = req->devACPIState & ~acpi_state::stateChanged;
362 if (!acpi_state::isValidACPIState(
363 acpi_state::PowerStateType::devPowerState, s))
364 {
365 log<level::ERR>("set_acpi_power dev invalid input",
366 entry("S=%x", s));
367 return IPMI_CC_PARM_OUT_OF_RANGE;
368 }
369
370 // valid input
371 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
372 {
373 log<level::DEBUG>("No change for device power state");
374 }
375 else
376 {
377 auto found = std::find_if(
378 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
379 [&s](const auto& iter) {
380 return (static_cast<uint8_t>(iter.second) == s);
381 });
382
383 value = found->first;
384
385 try
386 {
387 auto acpiObject =
388 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
389 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
390 acpi_state::acpiInterface,
391 acpi_state::devACPIProp,
392 convertForMessage(value));
393 }
394 catch (const InternalFailure& e)
395 {
396 log<level::ERR>("Failed in set ACPI device property",
397 entry("EXCEPTION=%s", e.what()));
398 return IPMI_CC_UNSPECIFIED_ERROR;
399 }
400 }
401 }
402 else
403 {
404 log<level::DEBUG>("Do not change device power state");
405 }
406
407 return rc;
408}
409
410ipmi_ret_t ipmi_app_get_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
411 ipmi_request_t request,
412 ipmi_response_t response,
413 ipmi_data_len_t data_len,
414 ipmi_context_t context)
415{
416 ipmi_ret_t rc = IPMI_CC_OK;
417
418 auto* res = reinterpret_cast<acpi_state::ACPIState*>(response);
419
420 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
421
422 *data_len = 0;
423
424 try
425 {
426 auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface);
427
428 auto sysACPIVal = ipmi::getDbusProperty(
429 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
430 acpi_state::sysACPIProp);
431 auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString(
432 sysACPIVal.get<std::string>());
433 res->sysACPIState =
434 static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI));
435
436 auto devACPIVal = ipmi::getDbusProperty(
437 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
438 acpi_state::devACPIProp);
439 auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString(
440 devACPIVal.get<std::string>());
441 res->devACPIState =
442 static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI));
443
444 *data_len = sizeof(acpi_state::ACPIState);
445 }
446 catch (const InternalFailure& e)
447 {
448 log<level::ERR>("Failed in get ACPI property");
449 return IPMI_CC_UNSPECIFIED_ERROR;
450 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500451 return rc;
452}
453
Chris Austen7303bdc2016-04-17 11:50:54 -0500454typedef struct
455{
456 char major;
457 char minor;
Chris Austen176c9652016-04-30 16:32:17 -0500458 uint16_t d[2];
Chris Austen7303bdc2016-04-17 11:50:54 -0500459} rev_t;
460
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600461/* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */
462/* return -1 if not in those formats, this routine knows how to parse */
Chris Austen7303bdc2016-04-17 11:50:54 -0500463/* version = v0.6-19-gf363f61-dirty */
464/* ^ ^ ^^ ^ */
465/* | | |----------|-- additional details */
466/* | |---------------- Minor */
467/* |------------------ Major */
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600468/* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */
469/* ^ ^ ^^ ^ */
470/* | | |--|---------- additional details */
471/* | |---------------- Minor */
472/* |------------------ Major */
Chris Austen7303bdc2016-04-17 11:50:54 -0500473/* Additional details : If the option group exists it will force Auxiliary */
474/* Firmware Revision Information 4th byte to 1 indicating the build was */
475/* derived with additional edits */
Patrick Venture0b02be92018-08-31 11:55:55 -0700476int convert_version(const char* p, rev_t* rev)
Chris Austen7303bdc2016-04-17 11:50:54 -0500477{
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600478 std::string s(p);
479 std::string token;
Chris Austen176c9652016-04-30 16:32:17 -0500480 uint16_t commits;
Chris Austen7303bdc2016-04-17 11:50:54 -0500481
Patrick Venture0b02be92018-08-31 11:55:55 -0700482 auto location = s.find_first_of('v');
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600483 if (location != std::string::npos)
484 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700485 s = s.substr(location + 1);
Chris Austen176c9652016-04-30 16:32:17 -0500486 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500487
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600488 if (!s.empty())
489 {
490 location = s.find_first_of(".");
491 if (location != std::string::npos)
492 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700493 rev->major =
494 static_cast<char>(std::stoi(s.substr(0, location), 0, 16));
495 token = s.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600496 }
Chris Austen176c9652016-04-30 16:32:17 -0500497
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600498 if (!token.empty())
499 {
500 location = token.find_first_of(".-");
501 if (location != std::string::npos)
502 {
Patrick Ventured2117022018-02-06 08:54:37 -0800503 rev->minor = static_cast<char>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700504 std::stoi(token.substr(0, location), 0, 16));
505 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600506 }
507 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500508
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600509 // Capture the number of commits on top of the minor tag.
510 // I'm using BE format like the ipmi spec asked for
511 location = token.find_first_of(".-");
512 if (!token.empty())
513 {
514 commits = std::stoi(token.substr(0, location), 0, 16);
Patrick Venture0b02be92018-08-31 11:55:55 -0700515 rev->d[0] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600516
517 // commit number we skip
518 location = token.find_first_of(".-");
519 if (location != std::string::npos)
520 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700521 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600522 }
523 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700524 else
525 {
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600526 rev->d[0] = 0;
527 }
528
529 if (location != std::string::npos)
530 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700531 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600532 }
533
534 // Any value of the optional parameter forces it to 1
535 location = token.find_first_of(".-");
536 if (location != std::string::npos)
537 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700538 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600539 }
540 commits = (!token.empty()) ? 1 : 0;
541
Patrick Venture0b02be92018-08-31 11:55:55 -0700542 // We do this operation to get this displayed in least significant bytes
543 // of ipmitool device id command.
544 rev->d[1] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600545 }
546
Chris Austen7303bdc2016-04-17 11:50:54 -0500547 return 0;
548}
549
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500550ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700551 ipmi_request_t request,
552 ipmi_response_t response,
553 ipmi_data_len_t data_len,
554 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500555{
556 ipmi_ret_t rc = IPMI_CC_OK;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600557 int r = -1;
Chris Austen7303bdc2016-04-17 11:50:54 -0500558 rev_t rev = {0};
David Cobbleya1adb072017-11-21 15:58:13 -0800559 static ipmi_device_id_t dev_id{};
560 static bool dev_id_initialized = false;
561 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
Alexander Amelkinba19c182018-09-04 15:49:36 +0300562 constexpr auto ipmiDevIdStateShift = 7;
563 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
Chris Austen6caf28b2015-10-13 12:40:40 -0500564
565 // Data length
Chris Austen7303bdc2016-04-17 11:50:54 -0500566 *data_len = sizeof(dev_id);
567
David Cobbleya1adb072017-11-21 15:58:13 -0800568 if (!dev_id_initialized)
569 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600570 try
571 {
572 auto version = getActiveSoftwareVersionInfo();
573 r = convert_version(version.c_str(), &rev);
David Cobbleya1adb072017-11-21 15:58:13 -0800574 }
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600575 catch (const std::exception& e)
576 {
577 log<level::ERR>(e.what());
578 }
Nan Liee0cb902016-07-11 15:38:03 +0800579
Patrick Venture0b02be92018-08-31 11:55:55 -0700580 if (r >= 0)
581 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600582 // bit7 identifies if the device is available
583 // 0=normal operation
584 // 1=device firmware, SDR update,
585 // or self-initialization in progress.
Alexander Amelkinba19c182018-09-04 15:49:36 +0300586 // The availability may change in run time, so mask here
587 // and initialize later.
588 dev_id.fw[0] = rev.major & ipmiDevIdFw1Mask;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600589
590 rev.minor = (rev.minor > 99 ? 99 : rev.minor);
591 dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700592 std::memcpy(&dev_id.aux, rev.d, 4);
David Cobbleya1adb072017-11-21 15:58:13 -0800593 }
Nan Liee0cb902016-07-11 15:38:03 +0800594
David Cobbleya1adb072017-11-21 15:58:13 -0800595 // IPMI Spec version 2.0
596 dev_id.ipmi_ver = 2;
Adriana Kobylak0e912642016-06-22 16:54:39 -0500597
David Cobbleya1adb072017-11-21 15:58:13 -0800598 std::ifstream dev_id_file(filename);
599 if (dev_id_file.is_open())
600 {
601 auto data = nlohmann::json::parse(dev_id_file, nullptr, false);
602 if (!data.is_discarded())
603 {
604 dev_id.id = data.value("id", 0);
605 dev_id.revision = data.value("revision", 0);
606 dev_id.addn_dev_support = data.value("addn_dev_support", 0);
607 dev_id.manuf_id[2] = data.value("manuf_id", 0) >> 16;
608 dev_id.manuf_id[1] = data.value("manuf_id", 0) >> 8;
609 dev_id.manuf_id[0] = data.value("manuf_id", 0);
610 dev_id.prod_id[1] = data.value("prod_id", 0) >> 8;
611 dev_id.prod_id[0] = data.value("prod_id", 0);
Tom Josephaf8a0982018-03-09 07:54:02 -0600612 dev_id.aux[3] = data.value("aux", 0);
613 dev_id.aux[2] = data.value("aux", 0) >> 8;
614 dev_id.aux[1] = data.value("aux", 0) >> 16;
615 dev_id.aux[0] = data.value("aux", 0) >> 24;
David Cobbleya1adb072017-11-21 15:58:13 -0800616
Patrick Venture0b02be92018-08-31 11:55:55 -0700617 // Don't read the file every time if successful
David Cobbleya1adb072017-11-21 15:58:13 -0800618 dev_id_initialized = true;
619 }
620 else
621 {
622 log<level::ERR>("Device ID JSON parser failure");
623 rc = IPMI_CC_UNSPECIFIED_ERROR;
624 }
625 }
626 else
627 {
628 log<level::ERR>("Device ID file not found");
629 rc = IPMI_CC_UNSPECIFIED_ERROR;
Chris Austen7303bdc2016-04-17 11:50:54 -0500630 }
631 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500632
Alexander Amelkinba19c182018-09-04 15:49:36 +0300633 // Set availability to the actual current BMC state
634 dev_id.fw[0] &= ipmiDevIdFw1Mask;
635 if (!getCurrentBmcState())
636 {
637 dev_id.fw[0] |= (1 << ipmiDevIdStateShift);
638 }
639
Chris Austen6caf28b2015-10-13 12:40:40 -0500640 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700641 std::memcpy(response, &dev_id, *data_len);
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600642
Chris Austen6caf28b2015-10-13 12:40:40 -0500643 return rc;
644}
645
Nan Li41fa24a2016-11-10 20:12:37 +0800646ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700647 ipmi_request_t request,
648 ipmi_response_t response,
649 ipmi_data_len_t data_len,
650 ipmi_context_t context)
Nan Li41fa24a2016-11-10 20:12:37 +0800651{
652 ipmi_ret_t rc = IPMI_CC_OK;
653
654 // Byte 2:
655 // 55h - No error.
Gunnar Mills8991dd62017-10-25 17:11:29 -0500656 // 56h - Self Test function not implemented in this controller.
Nan Li41fa24a2016-11-10 20:12:37 +0800657 // 57h - Corrupted or inaccesssible data or devices.
658 // 58h - Fatal hardware error.
659 // FFh - reserved.
660 // all other: Device-specific 'internal failure'.
661 // Byte 3:
662 // For byte 2 = 55h, 56h, FFh: 00h
663 // For byte 2 = 58h, all other: Device-specific
664 // For byte 2 = 57h: self-test error bitfield.
665 // Note: returning 57h does not imply that all test were run.
666 // [7] 1b = Cannot access SEL device.
667 // [6] 1b = Cannot access SDR Repository.
668 // [5] 1b = Cannot access BMC FRU device.
669 // [4] 1b = IPMB signal lines do not respond.
670 // [3] 1b = SDR Repository empty.
671 // [2] 1b = Internal Use Area of BMC FRU corrupted.
672 // [1] 1b = controller update 'boot block' firmware corrupted.
673 // [0] 1b = controller operational firmware corrupted.
674
675 char selftestresults[2] = {0};
676
677 *data_len = 2;
678
679 selftestresults[0] = 0x56;
680 selftestresults[1] = 0;
681
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700682 std::memcpy(response, selftestresults, *data_len);
Nan Li41fa24a2016-11-10 20:12:37 +0800683
684 return rc;
685}
686
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500687ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700688 ipmi_request_t request,
689 ipmi_response_t response,
690 ipmi_data_len_t data_len,
691 ipmi_context_t context)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500692{
Patrick Venture0b02be92018-08-31 11:55:55 -0700693 const char* objname = "/org/openbmc/control/chassis0";
694 const char* iface = "org.freedesktop.DBus.Properties";
695 const char* chassis_iface = "org.openbmc.control.Chassis";
696 sd_bus_message* reply = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500697 sd_bus_error error = SD_BUS_ERROR_NULL;
698 int r = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700699 char* uuid = NULL;
700 char* busname = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500701
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500702 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Ventured2117022018-02-06 08:54:37 -0800703 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
704 // order
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500705 // Ex: 0x2332fc2c40e66298e511f2782395a361
706
Patrick Venture0b02be92018-08-31 11:55:55 -0700707 const int resp_size = 16; // Response is 16 hex bytes per IPMI Spec
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500708 uint8_t resp_uuid[resp_size]; // Array to hold the formatted response
Patrick Ventured2117022018-02-06 08:54:37 -0800709 // Point resp end of array to save in reverse order
Patrick Venture0b02be92018-08-31 11:55:55 -0700710 int resp_loc = resp_size - 1;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500711 int i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700712 char* tokptr = NULL;
713 char* id_octet = NULL;
Emily Shafferedb8bb02018-09-27 14:50:15 -0700714 size_t total_uuid_size = 0;
715 // 1 byte of resp is built from 2 chars of uuid.
716 constexpr size_t max_uuid_size = 2 * resp_size;
vishwa1eaea4f2016-02-26 11:57:40 -0600717
718 // Status code.
719 ipmi_ret_t rc = IPMI_CC_OK;
720 *data_len = 0;
721
vishwa1eaea4f2016-02-26 11:57:40 -0600722 // Call Get properties method with the interface and property name
Sergey Solomineb9b8142016-08-23 09:07:28 -0500723 r = mapper_get_service(bus, objname, &busname);
Patrick Venture0b02be92018-08-31 11:55:55 -0700724 if (r < 0)
725 {
726 log<level::ERR>("Failed to get bus name", entry("BUS=%s", objname),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530727 entry("ERRNO=0x%X", -r));
Sergey Solomineb9b8142016-08-23 09:07:28 -0500728 goto finish;
729 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700730 r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply,
731 "ss", chassis_iface, "uuid");
vishwa1eaea4f2016-02-26 11:57:40 -0600732 if (r < 0)
733 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700734 log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600735 rc = IPMI_CC_UNSPECIFIED_ERROR;
736 goto finish;
737 }
738
739 r = sd_bus_message_read(reply, "v", "s", &uuid);
740 if (r < 0 || uuid == NULL)
741 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700742 log<level::ERR>("Failed to get a response", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600743 rc = IPMI_CC_RESPONSE_ERROR;
744 goto finish;
745 }
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500746
747 // Traverse the UUID
Patrick Ventured2117022018-02-06 08:54:37 -0800748 // Get the UUID octects separated by dash
749 id_octet = strtok_r(uuid, "-", &tokptr);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500750
751 if (id_octet == NULL)
vishwa1eaea4f2016-02-26 11:57:40 -0600752 {
753 // Error
Patrick Venture0b02be92018-08-31 11:55:55 -0700754 log<level::ERR>("Unexpected UUID format", entry("UUID=%s", uuid));
vishwa1eaea4f2016-02-26 11:57:40 -0600755 rc = IPMI_CC_RESPONSE_ERROR;
756 goto finish;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500757 }
758
759 while (id_octet != NULL)
760 {
761 // Calculate the octet string size since it varies
762 // Divide it by 2 for the array size since 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700763 int tmp_size = strlen(id_octet) / 2;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500764
Emily Shafferedb8bb02018-09-27 14:50:15 -0700765 // Check if total UUID size has been exceeded
766 if ((total_uuid_size += strlen(id_octet)) > max_uuid_size)
767 {
768 // Error - UUID too long to store
769 log<level::ERR>("UUID too long", entry("UUID=%s", uuid));
770 rc = IPMI_CC_RESPONSE_ERROR;
771 goto finish;
772 }
773
Patrick Venture0b02be92018-08-31 11:55:55 -0700774 for (i = 0; i < tmp_size; i++)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500775 {
Patrick Ventured2117022018-02-06 08:54:37 -0800776 // Holder of the 2 chars that will become a byte
777 char tmp_array[3] = {0};
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500778 strncpy(tmp_array, id_octet, 2); // 2 chars at a time
779
780 int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
Patrick Ventured2117022018-02-06 08:54:37 -0800781 // Copy end to first
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700782 std::memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500783 resp_loc--;
Patrick Venture0b02be92018-08-31 11:55:55 -0700784 id_octet += 2; // Finished with the 2 chars, advance
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500785 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700786 id_octet = strtok_r(NULL, "-", &tokptr); // Get next octet
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500787 }
788
789 // Data length
790 *data_len = resp_size;
791
792 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700793 std::memcpy(response, &resp_uuid, *data_len);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500794
vishwa1eaea4f2016-02-26 11:57:40 -0600795finish:
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500796 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600797 reply = sd_bus_message_unref(reply);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500798 free(busname);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500799
800 return rc;
801}
Chris Austen6caf28b2015-10-13 12:40:40 -0500802
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500803ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700804 ipmi_request_t request,
805 ipmi_response_t response,
806 ipmi_data_len_t data_len,
807 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530808{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530809
810 // Status code.
811 ipmi_ret_t rc = IPMI_CC_OK;
812
Adriana Kobylak88ad8152016-12-13 10:09:08 -0600813 // Per IPMI 2.0 spec, the input and output buffer size must be the max
814 // buffer size minus one byte to allocate space for the length byte.
Patrick Venture0b02be92018-08-31 11:55:55 -0700815 uint8_t str[] = {0x01, MAX_IPMI_BUFFER - 1, MAX_IPMI_BUFFER - 1, 0x0A,
816 0x01};
vishwabmcba0bd5f2015-09-30 16:50:23 +0530817
818 // Data length
819 *data_len = sizeof(str);
820
821 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700822 std::memcpy(response, &str, *data_len);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530823
824 return rc;
825}
826
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500827ipmi_ret_t ipmi_app_wildcard_handler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700828 ipmi_request_t request,
829 ipmi_response_t response,
830 ipmi_data_len_t data_len,
831 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530832{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530833 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800834 ipmi_ret_t rc = IPMI_CC_INVALID;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530835
836 *data_len = strlen("THIS IS WILDCARD");
837
838 // Now pack actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700839 std::memcpy(response, "THIS IS WILDCARD", *data_len);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530840
841 return rc;
842}
843
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600844ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700845 ipmi_request_t request,
846 ipmi_response_t response,
847 ipmi_data_len_t data_len,
848 ipmi_context_t context)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600849
850{
851 ipmi_ret_t rc = IPMI_CC_OK;
852 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
853
854 try
855 {
856 // Get the Inventory object implementing BMC interface
857 ipmi::DbusObjectInfo bmcObject =
858 ipmi::getDbusObject(bus, bmc_interface);
859
860 // Read UUID property value from bmcObject
861 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Venture0b02be92018-08-31 11:55:55 -0700862 auto variant =
863 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
864 bmc_guid_interface, bmc_guid_property);
William A. Kennington III4c008022018-10-12 17:18:14 -0700865 std::string guidProp = variant_ns::get<std::string>(variant);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600866
867 // Erase "-" characters from the property value
868 guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'),
Patrick Venture0b02be92018-08-31 11:55:55 -0700869 guidProp.end());
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600870
871 auto guidPropLen = guidProp.length();
872 // Validate UUID data
873 // Divide by 2 as 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700874 if ((guidPropLen <= 0) || ((guidPropLen / 2) != bmc_guid_len))
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600875
876 {
877 log<level::ERR>("Invalid UUID property value",
Patrick Venture0b02be92018-08-31 11:55:55 -0700878 entry("UUID_LENGTH=%d", guidPropLen));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600879 return IPMI_CC_RESPONSE_ERROR;
880 }
881
882 // Convert data in RFC4122(MSB) format to LSB format
883 // Get 2 characters at a time as 1 byte is built from 2 chars and
884 // convert to hex byte
885 // TODO: Data printed for GUID command is not as per the
886 // GUID format defined in IPMI specification 2.0 section 20.8
887 // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/
888 uint8_t respGuid[bmc_guid_len];
889 for (size_t i = 0, respLoc = (bmc_guid_len - 1);
Patrick Venture0b02be92018-08-31 11:55:55 -0700890 i < guidPropLen && respLoc >= 0; i += 2, respLoc--)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600891 {
892 auto value = static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700893 std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600894 respGuid[respLoc] = value;
895 }
896
897 *data_len = bmc_guid_len;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700898 std::memcpy(response, &respGuid, bmc_guid_len);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600899 }
900 catch (const InternalFailure& e)
901 {
902 log<level::ERR>("Failed in reading BMC UUID property",
903 entry("INTERFACE=%s", bmc_interface),
904 entry("PROPERTY_INTERFACE=%s", bmc_guid_interface),
905 entry("PROPERTY=%s", bmc_guid_property));
906 return IPMI_CC_UNSPECIFIED_ERROR;
907 }
908 return rc;
909}
910
Xo Wangf542e8b2017-08-09 15:34:16 -0700911static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
912
Xo Wang87651332017-08-11 10:17:59 -0700913static std::string sysInfoReadSystemName()
914{
915 // Use the BMC hostname as the "System Name."
916 char hostname[HOST_NAME_MAX + 1] = {};
917 if (gethostname(hostname, HOST_NAME_MAX) != 0)
918 {
919 perror("System info parameter: system name");
920 }
921 return hostname;
922}
923
Xo Wangf542e8b2017-08-09 15:34:16 -0700924struct IpmiSysInfoResp
925{
926 uint8_t paramRevision;
927 uint8_t setSelector;
928 union
929 {
930 struct
931 {
932 uint8_t encoding;
933 uint8_t stringLen;
934 uint8_t stringData0[14];
935 } __attribute__((packed));
936 uint8_t stringDataN[16];
937 uint8_t byteData;
938 };
939} __attribute__((packed));
940
941/**
942 * Split a string into (up to) 16-byte chunks as expected in response for get
943 * system info parameter.
944 *
945 * @param[in] fullString: Input string to be split
946 * @param[in] chunkIndex: Index of the chunk to be written out
947 * @param[in,out] chunk: Output data buffer; must have 14 byte capacity if
948 * chunk_index = 0 and 16-byte capacity otherwise
949 * @return the number of bytes written into the output buffer, or -EINVAL for
950 * invalid arguments.
951 */
952static int splitStringParam(const std::string& fullString, int chunkIndex,
953 uint8_t* chunk)
954{
955 constexpr int maxChunk = 255;
956 constexpr int smallChunk = 14;
957 constexpr int chunkSize = 16;
958 if (chunkIndex > maxChunk || chunk == nullptr)
959 {
960 return -EINVAL;
961 }
962 try
963 {
964 std::string output;
965 if (chunkIndex == 0)
966 {
967 // Output must have 14 byte capacity.
968 output = fullString.substr(0, smallChunk);
969 }
970 else
971 {
972 // Output must have 16 byte capacity.
973 output = fullString.substr((chunkIndex * chunkSize) - 2, chunkSize);
974 }
975
976 std::memcpy(chunk, output.c_str(), output.length());
977 return output.length();
978 }
979 catch (const std::out_of_range& e)
980 {
981 // The position was beyond the end.
982 return -EINVAL;
983 }
984}
985
986/**
987 * Packs the Get Sys Info Request Item into the response.
988 *
989 * @param[in] paramString - the parameter.
990 * @param[in] setSelector - the selector
991 * @param[in,out] resp - the System info response.
992 * @return The number of bytes packed or failure from splitStringParam().
993 */
994static int packGetSysInfoResp(const std::string& paramString,
995 uint8_t setSelector, IpmiSysInfoResp* resp)
996{
997 uint8_t* dataBuffer = resp->stringDataN;
998 resp->setSelector = setSelector;
999 if (resp->setSelector == 0) // First chunk has only 14 bytes.
1000 {
1001 resp->encoding = 0;
1002 resp->stringLen = paramString.length();
1003 dataBuffer = resp->stringData0;
1004 }
1005 return splitStringParam(paramString, resp->setSelector, dataBuffer);
1006}
1007
1008ipmi_ret_t ipmi_app_get_system_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1009 ipmi_request_t request,
1010 ipmi_response_t response,
1011 ipmi_data_len_t dataLen,
1012 ipmi_context_t context)
1013{
1014 IpmiSysInfoResp resp = {};
1015 size_t respLen = 0;
1016 uint8_t* const reqData = static_cast<uint8_t*>(request);
1017 std::string paramString;
1018 bool found;
1019 std::tuple<bool, std::string> ret;
1020 constexpr int minRequestSize = 4;
1021 constexpr int paramSelector = 1;
1022 constexpr uint8_t revisionOnly = 0x80;
1023 const uint8_t paramRequested = reqData[paramSelector];
1024 int rc;
1025
1026 if (*dataLen < minRequestSize)
1027 {
1028 return IPMI_CC_REQ_DATA_LEN_INVALID;
1029 }
1030
1031 *dataLen = 0; // default to 0.
1032
1033 // Parameters revision as of IPMI spec v2.0 rev. 1.1 (Feb 11, 2014 E6)
1034 resp.paramRevision = 0x11;
1035 if (reqData[0] & revisionOnly) // Get parameter revision only
1036 {
1037 respLen = 1;
1038 goto writeResponse;
1039 }
1040
1041 // The "Set In Progress" parameter can be used for rollback of parameter
1042 // data and is not implemented.
1043 if (paramRequested == 0)
1044 {
1045 resp.byteData = 0;
1046 respLen = 2;
1047 goto writeResponse;
1048 }
1049
1050 if (sysInfoParamStore == nullptr)
1051 {
1052 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
Xo Wang87651332017-08-11 10:17:59 -07001053 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1054 sysInfoReadSystemName);
Xo Wangf542e8b2017-08-09 15:34:16 -07001055 }
1056
1057 // Parameters other than Set In Progress are assumed to be strings.
1058 ret = sysInfoParamStore->lookup(paramRequested);
1059 found = std::get<0>(ret);
1060 paramString = std::get<1>(ret);
1061 if (!found)
1062 {
1063 return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
1064 }
1065 // TODO: Cache each parameter across multiple calls, until the whole string
1066 // has been read out. Otherwise, it's possible for a parameter to change
1067 // between requests for its chunks, returning chunks incoherent with each
1068 // other. For now, the parameter store is simply required to have only
1069 // idempotent callbacks.
1070 rc = packGetSysInfoResp(paramString, reqData[2], &resp);
1071 if (rc == -EINVAL)
1072 {
1073 return IPMI_CC_RESPONSE_ERROR;
1074 }
1075
1076 respLen = sizeof(resp); // Write entire string data chunk in response.
1077
1078writeResponse:
1079 std::memcpy(response, &resp, sizeof(resp));
1080 *dataLen = respLen;
1081 return IPMI_CC_OK;
1082}
1083
Chris Austen6caf28b2015-10-13 12:40:40 -05001084void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +05301085{
Tom05732372016-09-06 17:21:23 +05301086 // <Get BT Interface Capabilities>
Patrick Venture0b02be92018-08-31 11:55:55 -07001087 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL,
1088 ipmi_app_get_bt_capabilities, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001089
Tom05732372016-09-06 17:21:23 +05301090 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001091 ipmi_register_callback(NETFUN_APP, IPMI_CMD_WILDCARD, NULL,
1092 ipmi_app_wildcard_handler, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001093
Tom05732372016-09-06 17:21:23 +05301094 // <Reset Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001095 ipmi_register_callback(NETFUN_APP, IPMI_CMD_RESET_WD, NULL,
1096 ipmi_app_watchdog_reset, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -05001097
Tom05732372016-09-06 17:21:23 +05301098 // <Set Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001099 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL,
1100 ipmi_app_watchdog_set, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -05001101
William A. Kennington III73f44512018-02-09 15:28:46 -08001102 // <Get Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001103 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_WD, NULL,
1104 ipmi_app_watchdog_get, PRIVILEGE_OPERATOR);
William A. Kennington III73f44512018-02-09 15:28:46 -08001105
Tom05732372016-09-06 17:21:23 +05301106 // <Get Device ID>
Patrick Venture0b02be92018-08-31 11:55:55 -07001107 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_ID, NULL,
1108 ipmi_app_get_device_id, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001109
Tom05732372016-09-06 17:21:23 +05301110 // <Get Self Test Results>
Patrick Venture0b02be92018-08-31 11:55:55 -07001111 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS, NULL,
1112 ipmi_app_get_self_test_results, PRIVILEGE_USER);
Nan Li41fa24a2016-11-10 20:12:37 +08001113
Tom05732372016-09-06 17:21:23 +05301114 // <Get Device GUID>
Patrick Venture0b02be92018-08-31 11:55:55 -07001115 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID, NULL,
1116 ipmi_app_get_device_guid, PRIVILEGE_USER);
Adriana Kobylakd100ee52015-10-20 17:02:37 -05001117
Tom05732372016-09-06 17:21:23 +05301118 // <Set ACPI Power State>
Patrick Venture0b02be92018-08-31 11:55:55 -07001119 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL,
1120 ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN);
Chris Austen6caf28b2015-10-13 12:40:40 -05001121
Yong Li18d77262018-10-09 01:59:45 +08001122 // <Get ACPI Power State>
1123 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_ACPI, NULL,
1124 ipmi_app_get_acpi_power_state, PRIVILEGE_ADMIN);
1125
AppaRao Puli071f3f22018-05-24 16:45:30 +05301126// TODO: Below code and associated api's need to be removed later.
1127// Its commented for now to avoid merge conflicts with upstream
1128// changes and smooth upstream upgrades.
1129#if 0
1130>>>>>>> IPMI Channel commands implementation
Tom Joseph69fabfe2017-08-04 10:15:01 +05301131 // <Get Channel Access>
Patrick Venture0b02be92018-08-31 11:55:55 -07001132 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
1133 ipmi_get_channel_access, PRIVILEGE_USER);
Tom Joseph69fabfe2017-08-04 10:15:01 +05301134
Tom05732372016-09-06 17:21:23 +05301135 // <Get Channel Info Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001136 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL,
1137 ipmi_app_channel_info, PRIVILEGE_USER);
AppaRao Puli071f3f22018-05-24 16:45:30 +05301138#endif
Chris Austenc2cd29d2016-02-05 20:02:29 -06001139
Marri Devender Rao5e007a52018-01-08 06:18:36 -06001140 // <Get System GUID Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001141 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL,
1142 ipmi_app_get_sys_guid, PRIVILEGE_USER);
Tom Joseph7cbe2282018-03-21 21:17:33 +05301143
1144 // <Get Channel Cipher Suites Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001145 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_CIPHER_SUITES, NULL,
1146 getChannelCipherSuites, PRIVILEGE_CALLBACK);
AppaRao Puli071f3f22018-05-24 16:45:30 +05301147#if 0
Tom Joseph13227682018-08-10 01:05:21 +05301148 // <Set Channel Access Command>
1149 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL,
1150 ipmi_set_channel_access, PRIVILEGE_ADMIN);
AppaRao Puli071f3f22018-05-24 16:45:30 +05301151#endif
Xo Wangf542e8b2017-08-09 15:34:16 -07001152 // <Get System Info Command>
1153 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYSTEM_INFO, NULL,
1154 ipmi_app_get_system_info, PRIVILEGE_USER);
Richard Marian Thomaiyar5a6b6362018-03-12 23:42:34 +05301155 ipmi::registerUserIpmiFunctions();
AppaRao Puli071f3f22018-05-24 16:45:30 +05301156 ipmi::registerChannelFunctions();
vishwabmcba0bd5f2015-09-30 16:50:23 +05301157 return;
1158}