blob: ac969e940e1692f1b871663ddb03218a8327e5cc [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"
9#include "utils.hpp"
10
Patrick Venture0b02be92018-08-31 11:55:55 -070011#include <arpa/inet.h>
William A. Kennington III194375f2018-12-14 02:14:33 -080012#include <ipmid/api.h>
Xo Wang87651332017-08-11 10:17:59 -070013#include <limits.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070014#include <mapper.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070015#include <systemd/sd-bus.h>
Xo Wang87651332017-08-11 10:17:59 -070016#include <unistd.h>
Patrick Venture0b02be92018-08-31 11:55:55 -070017
Patrick Venture3a5071a2018-09-12 13:27:42 -070018#include <algorithm>
19#include <array>
20#include <cstddef>
21#include <fstream>
22#include <memory>
Patrick Venture46470a32018-09-07 19:26:25 -070023#include <nlohmann/json.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070024#include <phosphor-logging/elog-errors.hpp>
25#include <phosphor-logging/log.hpp>
William A. Kennington III4c008022018-10-12 17:18:14 -070026#include <sdbusplus/message/types.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070027#include <string>
28#include <tuple>
29#include <vector>
30#include <xyz/openbmc_project/Common/error.hpp>
Yong Li18d77262018-10-09 01:59:45 +080031#include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp>
Patrick Venture3a5071a2018-09-12 13:27:42 -070032#include <xyz/openbmc_project/Software/Activation/server.hpp>
33#include <xyz/openbmc_project/Software/Version/server.hpp>
34#include <xyz/openbmc_project/State/BMC/server.hpp>
Ratan Guptab8e99552017-07-27 07:07:48 +053035
Vernon Mauery185b9f82018-07-20 10:52:36 -070036#if __has_include(<filesystem>)
37#include <filesystem>
38#elif __has_include(<experimental/filesystem>)
39#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070040namespace std
41{
42// splice experimental::filesystem into std
43namespace filesystem = std::experimental::filesystem;
44} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070045#else
Patrick Venture0b02be92018-08-31 11:55:55 -070046#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070047#endif
Ratan Gupta62736ec2017-09-02 12:02:47 +053048
Patrick Venture0b02be92018-08-31 11:55:55 -070049extern sd_bus* bus;
vishwabmcba0bd5f2015-09-30 16:50:23 +053050
Alexander Amelkinba19c182018-09-04 15:49:36 +030051constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
52constexpr auto bmc_state_property = "CurrentBMCState";
Marri Devender Rao5e007a52018-01-08 06:18:36 -060053constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
54constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
55constexpr auto bmc_guid_property = "UUID";
56constexpr auto bmc_guid_len = 16;
57
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060058static constexpr auto redundancyIntf =
59 "xyz.openbmc_project.Software.RedundancyPriority";
Patrick Venture0b02be92018-08-31 11:55:55 -070060static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060061static constexpr auto activationIntf =
62 "xyz.openbmc_project.Software.Activation";
63static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
64
Chris Austen6caf28b2015-10-13 12:40:40 -050065void register_netfn_app_functions() __attribute__((constructor));
vishwabmcba0bd5f2015-09-30 16:50:23 +053066
Ratan Guptab8e99552017-07-27 07:07:48 +053067using namespace phosphor::logging;
68using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060069using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
70using Activation =
71 sdbusplus::xyz::openbmc_project::Software::server::Activation;
Alexander Amelkinba19c182018-09-04 15:49:36 +030072using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC;
Vernon Mauery185b9f82018-07-20 10:52:36 -070073namespace fs = std::filesystem;
William A. Kennington III4c008022018-10-12 17:18:14 -070074namespace variant_ns = sdbusplus::message::variant_ns;
Ratan Guptab8e99552017-07-27 07:07:48 +053075
Nan Liee0cb902016-07-11 15:38:03 +080076// Offset in get device id command.
77typedef struct
78{
Patrick Venture0b02be92018-08-31 11:55:55 -070079 uint8_t id;
80 uint8_t revision;
81 uint8_t fw[2];
82 uint8_t ipmi_ver;
83 uint8_t addn_dev_support;
84 uint8_t manuf_id[3];
85 uint8_t prod_id[2];
86 uint8_t aux[4];
87} __attribute__((packed)) ipmi_device_id_t;
Chris Austen7303bdc2016-04-17 11:50:54 -050088
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060089/**
90 * @brief Returns the Version info from primary s/w object
91 *
92 * Get the Version info from the active s/w object which is having high
93 * "Priority" value(a smaller number is a higher priority) and "Purpose"
94 * is "BMC" from the list of all s/w objects those are implementing
95 * RedundancyPriority interface from the given softwareRoot path.
96 *
97 * @return On success returns the Version info from primary s/w object.
98 *
99 */
100std::string getActiveSoftwareVersionInfo()
101{
102 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
103
104 std::string revision{};
Patrick Venture0b02be92018-08-31 11:55:55 -0700105 auto objectTree =
106 ipmi::getAllDbusObjects(bus, softwareRoot, redundancyIntf, "");
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600107 if (objectTree.empty())
108 {
109 log<level::ERR>("No Obj has implemented the s/w redundancy interface",
110 entry("INTERFACE=%s", redundancyIntf));
111 elog<InternalFailure>();
112 }
113
114 auto objectFound = false;
115 for (auto& softObject : objectTree)
116 {
117 auto service = ipmi::getService(bus, redundancyIntf, softObject.first);
118 auto objValueTree = ipmi::getManagedObjects(bus, service, softwareRoot);
119
120 auto minPriority = 0xFF;
121 for (const auto& objIter : objValueTree)
122 {
123 try
124 {
125 auto& intfMap = objIter.second;
126 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
127 auto& versionProps = intfMap.at(versionIntf);
128 auto& activationProps = intfMap.at(activationIntf);
William A. Kennington III4c008022018-10-12 17:18:14 -0700129 auto priority = variant_ns::get<uint8_t>(
130 redundancyPriorityProps.at("Priority"));
131 auto purpose =
132 variant_ns::get<std::string>(versionProps.at("Purpose"));
133 auto activation = variant_ns::get<std::string>(
134 activationProps.at("Activation"));
135 auto version =
136 variant_ns::get<std::string>(versionProps.at("Version"));
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600137 if ((Version::convertVersionPurposeFromString(purpose) ==
138 Version::VersionPurpose::BMC) &&
139 (Activation::convertActivationsFromString(activation) ==
140 Activation::Activations::Active))
141 {
142 if (priority < minPriority)
143 {
144 minPriority = priority;
145 objectFound = true;
146 revision = std::move(version);
147 }
148 }
149 }
150 catch (const std::exception& e)
151 {
152 log<level::ERR>(e.what());
153 }
154 }
155 }
156
157 if (!objectFound)
158 {
159 log<level::ERR>("Could not found an BMC software Object");
160 elog<InternalFailure>();
161 }
162
163 return revision;
164}
165
Alexander Amelkinba19c182018-09-04 15:49:36 +0300166bool getCurrentBmcState()
167{
168 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
169
170 // Get the Inventory object implementing the BMC interface
171 ipmi::DbusObjectInfo bmcObject =
172 ipmi::getDbusObject(bus, bmc_state_interface);
173 auto variant =
174 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
175 bmc_state_interface, bmc_state_property);
176
William A. Kennington III4c008022018-10-12 17:18:14 -0700177 return variant_ns::holds_alternative<std::string>(variant) &&
178 BMC::convertBMCStateFromString(
179 variant_ns::get<std::string>(variant)) == BMC::BMCState::Ready;
Alexander Amelkinba19c182018-09-04 15:49:36 +0300180}
181
Yong Li18d77262018-10-09 01:59:45 +0800182namespace acpi_state
183{
184using namespace sdbusplus::xyz::openbmc_project::Control::Power::server;
185
186const static constexpr char* acpiObjPath =
187 "/xyz/openbmc_project/control/host0/acpi_power_state";
188const static constexpr char* acpiInterface =
189 "xyz.openbmc_project.Control.Power.ACPIPowerState";
190const static constexpr char* sysACPIProp = "SysACPIStatus";
191const static constexpr char* devACPIProp = "DevACPIStatus";
192
193enum class PowerStateType : uint8_t
194{
195 sysPowerState = 0x00,
196 devPowerState = 0x01,
197};
198
199// Defined in 20.6 of ipmi doc
200enum class PowerState : uint8_t
201{
202 s0G0D0 = 0x00,
203 s1D1 = 0x01,
204 s2D2 = 0x02,
205 s3D3 = 0x03,
206 s4 = 0x04,
207 s5G2 = 0x05,
208 s4S5 = 0x06,
209 g3 = 0x07,
210 sleep = 0x08,
211 g1Sleep = 0x09,
212 override = 0x0a,
213 legacyOn = 0x20,
214 legacyOff = 0x21,
215 unknown = 0x2a,
216 noChange = 0x7f,
217};
218
219static constexpr uint8_t stateChanged = 0x80;
220
221struct ACPIState
222{
223 uint8_t sysACPIState;
224 uint8_t devACPIState;
225} __attribute__((packed));
226
227std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = {
228 {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0},
229 {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1},
230 {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2},
231 {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3},
232 {ACPIPowerState::ACPI::S4, PowerState::s4},
233 {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2},
234 {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5},
235 {ACPIPowerState::ACPI::G3, PowerState::g3},
236 {ACPIPowerState::ACPI::SLEEP, PowerState::sleep},
237 {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep},
238 {ACPIPowerState::ACPI::OVERRIDE, PowerState::override},
239 {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn},
240 {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff},
241 {ACPIPowerState::ACPI::Unknown, PowerState::unknown}};
242
243bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state)
244{
245 if (type == acpi_state::PowerStateType::sysPowerState)
246 {
247 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) ||
248 (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) ||
249 (state ==
250 static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) ||
251 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
252 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
253 {
254 return true;
255 }
256 else
257 {
258 return false;
259 }
260 }
261 else if (type == acpi_state::PowerStateType::devPowerState)
262 {
263 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) ||
264 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) ||
265 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange)))
266 {
267 return true;
268 }
269 else
270 {
271 return false;
272 }
273 }
274 else
275 {
276 return false;
277 }
278 return false;
279}
280} // namespace acpi_state
281
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500282ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700283 ipmi_request_t request,
284 ipmi_response_t response,
285 ipmi_data_len_t data_len,
286 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500287{
Yong Li18d77262018-10-09 01:59:45 +0800288 auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown);
Chris Austen6caf28b2015-10-13 12:40:40 -0500289 ipmi_ret_t rc = IPMI_CC_OK;
Yong Li18d77262018-10-09 01:59:45 +0800290
291 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
292
293 auto value = acpi_state::ACPIPowerState::ACPI::Unknown;
294
295 auto* req = reinterpret_cast<acpi_state::ACPIState*>(request);
296
297 if (*data_len != sizeof(acpi_state::ACPIState))
298 {
299 log<level::ERR>("set_acpi invalid len");
300 *data_len = 0;
301 return IPMI_CC_REQ_DATA_LEN_INVALID;
302 }
303
Chris Austen6caf28b2015-10-13 12:40:40 -0500304 *data_len = 0;
305
Yong Li18d77262018-10-09 01:59:45 +0800306 if (req->sysACPIState & acpi_state::stateChanged)
307 {
308 // set system power state
309 s = req->sysACPIState & ~acpi_state::stateChanged;
310
311 if (!acpi_state::isValidACPIState(
312 acpi_state::PowerStateType::sysPowerState, s))
313 {
314 log<level::ERR>("set_acpi_power sys invalid input",
315 entry("S=%x", s));
316 return IPMI_CC_PARM_OUT_OF_RANGE;
317 }
318
319 // valid input
320 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
321 {
322 log<level::DEBUG>("No change for system power state");
323 }
324 else
325 {
326 auto found = std::find_if(
327 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
328 [&s](const auto& iter) {
329 return (static_cast<uint8_t>(iter.second) == s);
330 });
331
332 value = found->first;
333
334 try
335 {
336 auto acpiObject =
337 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
338 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
339 acpi_state::acpiInterface,
340 acpi_state::sysACPIProp,
341 convertForMessage(value));
342 }
343 catch (const InternalFailure& e)
344 {
345 log<level::ERR>("Failed in set ACPI system property",
346 entry("EXCEPTION=%s", e.what()));
347 return IPMI_CC_UNSPECIFIED_ERROR;
348 }
349 }
350 }
351 else
352 {
353 log<level::DEBUG>("Do not change system power state");
354 }
355
356 if (req->devACPIState & acpi_state::stateChanged)
357 {
358 // set device power state
359 s = req->devACPIState & ~acpi_state::stateChanged;
360 if (!acpi_state::isValidACPIState(
361 acpi_state::PowerStateType::devPowerState, s))
362 {
363 log<level::ERR>("set_acpi_power dev invalid input",
364 entry("S=%x", s));
365 return IPMI_CC_PARM_OUT_OF_RANGE;
366 }
367
368 // valid input
369 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange))
370 {
371 log<level::DEBUG>("No change for device power state");
372 }
373 else
374 {
375 auto found = std::find_if(
376 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(),
377 [&s](const auto& iter) {
378 return (static_cast<uint8_t>(iter.second) == s);
379 });
380
381 value = found->first;
382
383 try
384 {
385 auto acpiObject =
386 ipmi::getDbusObject(bus, acpi_state::acpiInterface);
387 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first,
388 acpi_state::acpiInterface,
389 acpi_state::devACPIProp,
390 convertForMessage(value));
391 }
392 catch (const InternalFailure& e)
393 {
394 log<level::ERR>("Failed in set ACPI device property",
395 entry("EXCEPTION=%s", e.what()));
396 return IPMI_CC_UNSPECIFIED_ERROR;
397 }
398 }
399 }
400 else
401 {
402 log<level::DEBUG>("Do not change device power state");
403 }
404
405 return rc;
406}
407
408ipmi_ret_t ipmi_app_get_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
409 ipmi_request_t request,
410 ipmi_response_t response,
411 ipmi_data_len_t data_len,
412 ipmi_context_t context)
413{
414 ipmi_ret_t rc = IPMI_CC_OK;
415
416 auto* res = reinterpret_cast<acpi_state::ACPIState*>(response);
417
418 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
419
420 *data_len = 0;
421
422 try
423 {
424 auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface);
425
426 auto sysACPIVal = ipmi::getDbusProperty(
427 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
428 acpi_state::sysACPIProp);
429 auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString(
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800430 variant_ns::get<std::string>(sysACPIVal));
Yong Li18d77262018-10-09 01:59:45 +0800431 res->sysACPIState =
432 static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI));
433
434 auto devACPIVal = ipmi::getDbusProperty(
435 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface,
436 acpi_state::devACPIProp);
437 auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString(
William A. Kennington IIIdfad4862018-11-19 17:45:35 -0800438 variant_ns::get<std::string>(devACPIVal));
Yong Li18d77262018-10-09 01:59:45 +0800439 res->devACPIState =
440 static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI));
441
442 *data_len = sizeof(acpi_state::ACPIState);
443 }
444 catch (const InternalFailure& e)
445 {
446 log<level::ERR>("Failed in get ACPI property");
447 return IPMI_CC_UNSPECIFIED_ERROR;
448 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500449 return rc;
450}
451
Chris Austen7303bdc2016-04-17 11:50:54 -0500452typedef struct
453{
454 char major;
455 char minor;
Chris Austen176c9652016-04-30 16:32:17 -0500456 uint16_t d[2];
Chris Austen7303bdc2016-04-17 11:50:54 -0500457} rev_t;
458
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600459/* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */
460/* return -1 if not in those formats, this routine knows how to parse */
Chris Austen7303bdc2016-04-17 11:50:54 -0500461/* version = v0.6-19-gf363f61-dirty */
462/* ^ ^ ^^ ^ */
463/* | | |----------|-- additional details */
464/* | |---------------- Minor */
465/* |------------------ Major */
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600466/* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */
467/* ^ ^ ^^ ^ */
468/* | | |--|---------- additional details */
469/* | |---------------- Minor */
470/* |------------------ Major */
Chris Austen7303bdc2016-04-17 11:50:54 -0500471/* Additional details : If the option group exists it will force Auxiliary */
472/* Firmware Revision Information 4th byte to 1 indicating the build was */
473/* derived with additional edits */
Patrick Venture0b02be92018-08-31 11:55:55 -0700474int convert_version(const char* p, rev_t* rev)
Chris Austen7303bdc2016-04-17 11:50:54 -0500475{
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600476 std::string s(p);
477 std::string token;
Chris Austen176c9652016-04-30 16:32:17 -0500478 uint16_t commits;
Chris Austen7303bdc2016-04-17 11:50:54 -0500479
Patrick Venture0b02be92018-08-31 11:55:55 -0700480 auto location = s.find_first_of('v');
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600481 if (location != std::string::npos)
482 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700483 s = s.substr(location + 1);
Chris Austen176c9652016-04-30 16:32:17 -0500484 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500485
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600486 if (!s.empty())
487 {
488 location = s.find_first_of(".");
489 if (location != std::string::npos)
490 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700491 rev->major =
492 static_cast<char>(std::stoi(s.substr(0, location), 0, 16));
493 token = s.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600494 }
Chris Austen176c9652016-04-30 16:32:17 -0500495
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600496 if (!token.empty())
497 {
498 location = token.find_first_of(".-");
499 if (location != std::string::npos)
500 {
Patrick Ventured2117022018-02-06 08:54:37 -0800501 rev->minor = static_cast<char>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700502 std::stoi(token.substr(0, location), 0, 16));
503 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600504 }
505 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500506
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600507 // Capture the number of commits on top of the minor tag.
508 // I'm using BE format like the ipmi spec asked for
509 location = token.find_first_of(".-");
510 if (!token.empty())
511 {
512 commits = std::stoi(token.substr(0, location), 0, 16);
Patrick Venture0b02be92018-08-31 11:55:55 -0700513 rev->d[0] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600514
515 // commit number we skip
516 location = token.find_first_of(".-");
517 if (location != std::string::npos)
518 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700519 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600520 }
521 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700522 else
523 {
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600524 rev->d[0] = 0;
525 }
526
527 if (location != std::string::npos)
528 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700529 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600530 }
531
532 // Any value of the optional parameter forces it to 1
533 location = token.find_first_of(".-");
534 if (location != std::string::npos)
535 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700536 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600537 }
538 commits = (!token.empty()) ? 1 : 0;
539
Patrick Venture0b02be92018-08-31 11:55:55 -0700540 // We do this operation to get this displayed in least significant bytes
541 // of ipmitool device id command.
542 rev->d[1] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600543 }
544
Chris Austen7303bdc2016-04-17 11:50:54 -0500545 return 0;
546}
547
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500548ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700549 ipmi_request_t request,
550 ipmi_response_t response,
551 ipmi_data_len_t data_len,
552 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500553{
554 ipmi_ret_t rc = IPMI_CC_OK;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600555 int r = -1;
Chris Austen7303bdc2016-04-17 11:50:54 -0500556 rev_t rev = {0};
David Cobbleya1adb072017-11-21 15:58:13 -0800557 static ipmi_device_id_t dev_id{};
558 static bool dev_id_initialized = false;
559 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
Alexander Amelkinba19c182018-09-04 15:49:36 +0300560 constexpr auto ipmiDevIdStateShift = 7;
561 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
Chris Austen6caf28b2015-10-13 12:40:40 -0500562
563 // Data length
Chris Austen7303bdc2016-04-17 11:50:54 -0500564 *data_len = sizeof(dev_id);
565
David Cobbleya1adb072017-11-21 15:58:13 -0800566 if (!dev_id_initialized)
567 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600568 try
569 {
570 auto version = getActiveSoftwareVersionInfo();
571 r = convert_version(version.c_str(), &rev);
David Cobbleya1adb072017-11-21 15:58:13 -0800572 }
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600573 catch (const std::exception& e)
574 {
575 log<level::ERR>(e.what());
576 }
Nan Liee0cb902016-07-11 15:38:03 +0800577
Patrick Venture0b02be92018-08-31 11:55:55 -0700578 if (r >= 0)
579 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600580 // bit7 identifies if the device is available
581 // 0=normal operation
582 // 1=device firmware, SDR update,
583 // or self-initialization in progress.
Alexander Amelkinba19c182018-09-04 15:49:36 +0300584 // The availability may change in run time, so mask here
585 // and initialize later.
586 dev_id.fw[0] = rev.major & ipmiDevIdFw1Mask;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600587
588 rev.minor = (rev.minor > 99 ? 99 : rev.minor);
589 dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700590 std::memcpy(&dev_id.aux, rev.d, 4);
David Cobbleya1adb072017-11-21 15:58:13 -0800591 }
Nan Liee0cb902016-07-11 15:38:03 +0800592
David Cobbleya1adb072017-11-21 15:58:13 -0800593 // IPMI Spec version 2.0
594 dev_id.ipmi_ver = 2;
Adriana Kobylak0e912642016-06-22 16:54:39 -0500595
David Cobbleya1adb072017-11-21 15:58:13 -0800596 std::ifstream dev_id_file(filename);
597 if (dev_id_file.is_open())
598 {
599 auto data = nlohmann::json::parse(dev_id_file, nullptr, false);
600 if (!data.is_discarded())
601 {
602 dev_id.id = data.value("id", 0);
603 dev_id.revision = data.value("revision", 0);
604 dev_id.addn_dev_support = data.value("addn_dev_support", 0);
605 dev_id.manuf_id[2] = data.value("manuf_id", 0) >> 16;
606 dev_id.manuf_id[1] = data.value("manuf_id", 0) >> 8;
607 dev_id.manuf_id[0] = data.value("manuf_id", 0);
608 dev_id.prod_id[1] = data.value("prod_id", 0) >> 8;
609 dev_id.prod_id[0] = data.value("prod_id", 0);
Tom Josephaf8a0982018-03-09 07:54:02 -0600610 dev_id.aux[3] = data.value("aux", 0);
611 dev_id.aux[2] = data.value("aux", 0) >> 8;
612 dev_id.aux[1] = data.value("aux", 0) >> 16;
613 dev_id.aux[0] = data.value("aux", 0) >> 24;
David Cobbleya1adb072017-11-21 15:58:13 -0800614
Patrick Venture0b02be92018-08-31 11:55:55 -0700615 // Don't read the file every time if successful
David Cobbleya1adb072017-11-21 15:58:13 -0800616 dev_id_initialized = true;
617 }
618 else
619 {
620 log<level::ERR>("Device ID JSON parser failure");
621 rc = IPMI_CC_UNSPECIFIED_ERROR;
622 }
623 }
624 else
625 {
626 log<level::ERR>("Device ID file not found");
627 rc = IPMI_CC_UNSPECIFIED_ERROR;
Chris Austen7303bdc2016-04-17 11:50:54 -0500628 }
629 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500630
Alexander Amelkinba19c182018-09-04 15:49:36 +0300631 // Set availability to the actual current BMC state
632 dev_id.fw[0] &= ipmiDevIdFw1Mask;
633 if (!getCurrentBmcState())
634 {
635 dev_id.fw[0] |= (1 << ipmiDevIdStateShift);
636 }
637
Chris Austen6caf28b2015-10-13 12:40:40 -0500638 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700639 std::memcpy(response, &dev_id, *data_len);
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600640
Chris Austen6caf28b2015-10-13 12:40:40 -0500641 return rc;
642}
643
Nan Li41fa24a2016-11-10 20:12:37 +0800644ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700645 ipmi_request_t request,
646 ipmi_response_t response,
647 ipmi_data_len_t data_len,
648 ipmi_context_t context)
Nan Li41fa24a2016-11-10 20:12:37 +0800649{
650 ipmi_ret_t rc = IPMI_CC_OK;
651
652 // Byte 2:
653 // 55h - No error.
Gunnar Mills8991dd62017-10-25 17:11:29 -0500654 // 56h - Self Test function not implemented in this controller.
Nan Li41fa24a2016-11-10 20:12:37 +0800655 // 57h - Corrupted or inaccesssible data or devices.
656 // 58h - Fatal hardware error.
657 // FFh - reserved.
658 // all other: Device-specific 'internal failure'.
659 // Byte 3:
660 // For byte 2 = 55h, 56h, FFh: 00h
661 // For byte 2 = 58h, all other: Device-specific
662 // For byte 2 = 57h: self-test error bitfield.
663 // Note: returning 57h does not imply that all test were run.
664 // [7] 1b = Cannot access SEL device.
665 // [6] 1b = Cannot access SDR Repository.
666 // [5] 1b = Cannot access BMC FRU device.
667 // [4] 1b = IPMB signal lines do not respond.
668 // [3] 1b = SDR Repository empty.
669 // [2] 1b = Internal Use Area of BMC FRU corrupted.
670 // [1] 1b = controller update 'boot block' firmware corrupted.
671 // [0] 1b = controller operational firmware corrupted.
672
673 char selftestresults[2] = {0};
674
675 *data_len = 2;
676
677 selftestresults[0] = 0x56;
678 selftestresults[1] = 0;
679
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700680 std::memcpy(response, selftestresults, *data_len);
Nan Li41fa24a2016-11-10 20:12:37 +0800681
682 return rc;
683}
684
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500685ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700686 ipmi_request_t request,
687 ipmi_response_t response,
688 ipmi_data_len_t data_len,
689 ipmi_context_t context)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500690{
Patrick Venture0b02be92018-08-31 11:55:55 -0700691 const char* objname = "/org/openbmc/control/chassis0";
692 const char* iface = "org.freedesktop.DBus.Properties";
693 const char* chassis_iface = "org.openbmc.control.Chassis";
694 sd_bus_message* reply = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500695 sd_bus_error error = SD_BUS_ERROR_NULL;
696 int r = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700697 char* uuid = NULL;
698 char* busname = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500699
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500700 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Ventured2117022018-02-06 08:54:37 -0800701 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
702 // order
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500703 // Ex: 0x2332fc2c40e66298e511f2782395a361
704
Patrick Venture0b02be92018-08-31 11:55:55 -0700705 const int resp_size = 16; // Response is 16 hex bytes per IPMI Spec
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500706 uint8_t resp_uuid[resp_size]; // Array to hold the formatted response
Patrick Ventured2117022018-02-06 08:54:37 -0800707 // Point resp end of array to save in reverse order
Patrick Venture0b02be92018-08-31 11:55:55 -0700708 int resp_loc = resp_size - 1;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500709 int i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700710 char* tokptr = NULL;
711 char* id_octet = NULL;
Emily Shafferedb8bb02018-09-27 14:50:15 -0700712 size_t total_uuid_size = 0;
713 // 1 byte of resp is built from 2 chars of uuid.
714 constexpr size_t max_uuid_size = 2 * resp_size;
vishwa1eaea4f2016-02-26 11:57:40 -0600715
716 // Status code.
717 ipmi_ret_t rc = IPMI_CC_OK;
718 *data_len = 0;
719
vishwa1eaea4f2016-02-26 11:57:40 -0600720 // Call Get properties method with the interface and property name
Sergey Solomineb9b8142016-08-23 09:07:28 -0500721 r = mapper_get_service(bus, objname, &busname);
Patrick Venture0b02be92018-08-31 11:55:55 -0700722 if (r < 0)
723 {
724 log<level::ERR>("Failed to get bus name", entry("BUS=%s", objname),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530725 entry("ERRNO=0x%X", -r));
Sergey Solomineb9b8142016-08-23 09:07:28 -0500726 goto finish;
727 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700728 r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply,
729 "ss", chassis_iface, "uuid");
vishwa1eaea4f2016-02-26 11:57:40 -0600730 if (r < 0)
731 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700732 log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600733 rc = IPMI_CC_UNSPECIFIED_ERROR;
734 goto finish;
735 }
736
737 r = sd_bus_message_read(reply, "v", "s", &uuid);
738 if (r < 0 || uuid == NULL)
739 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700740 log<level::ERR>("Failed to get a response", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600741 rc = IPMI_CC_RESPONSE_ERROR;
742 goto finish;
743 }
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500744
745 // Traverse the UUID
Patrick Ventured2117022018-02-06 08:54:37 -0800746 // Get the UUID octects separated by dash
747 id_octet = strtok_r(uuid, "-", &tokptr);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500748
749 if (id_octet == NULL)
vishwa1eaea4f2016-02-26 11:57:40 -0600750 {
751 // Error
Patrick Venture0b02be92018-08-31 11:55:55 -0700752 log<level::ERR>("Unexpected UUID format", entry("UUID=%s", uuid));
vishwa1eaea4f2016-02-26 11:57:40 -0600753 rc = IPMI_CC_RESPONSE_ERROR;
754 goto finish;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500755 }
756
757 while (id_octet != NULL)
758 {
759 // Calculate the octet string size since it varies
760 // Divide it by 2 for the array size since 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700761 int tmp_size = strlen(id_octet) / 2;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500762
Emily Shafferedb8bb02018-09-27 14:50:15 -0700763 // Check if total UUID size has been exceeded
764 if ((total_uuid_size += strlen(id_octet)) > max_uuid_size)
765 {
766 // Error - UUID too long to store
767 log<level::ERR>("UUID too long", entry("UUID=%s", uuid));
768 rc = IPMI_CC_RESPONSE_ERROR;
769 goto finish;
770 }
771
Patrick Venture0b02be92018-08-31 11:55:55 -0700772 for (i = 0; i < tmp_size; i++)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500773 {
Patrick Ventured2117022018-02-06 08:54:37 -0800774 // Holder of the 2 chars that will become a byte
775 char tmp_array[3] = {0};
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500776 strncpy(tmp_array, id_octet, 2); // 2 chars at a time
777
778 int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
Patrick Ventured2117022018-02-06 08:54:37 -0800779 // Copy end to first
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700780 std::memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500781 resp_loc--;
Patrick Venture0b02be92018-08-31 11:55:55 -0700782 id_octet += 2; // Finished with the 2 chars, advance
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500783 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700784 id_octet = strtok_r(NULL, "-", &tokptr); // Get next octet
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500785 }
786
787 // Data length
788 *data_len = resp_size;
789
790 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700791 std::memcpy(response, &resp_uuid, *data_len);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500792
vishwa1eaea4f2016-02-26 11:57:40 -0600793finish:
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500794 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600795 reply = sd_bus_message_unref(reply);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500796 free(busname);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500797
798 return rc;
799}
Chris Austen6caf28b2015-10-13 12:40:40 -0500800
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500801ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700802 ipmi_request_t request,
803 ipmi_response_t response,
804 ipmi_data_len_t data_len,
805 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530806{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530807
808 // Status code.
809 ipmi_ret_t rc = IPMI_CC_OK;
810
Adriana Kobylak88ad8152016-12-13 10:09:08 -0600811 // Per IPMI 2.0 spec, the input and output buffer size must be the max
812 // buffer size minus one byte to allocate space for the length byte.
Patrick Venture0b02be92018-08-31 11:55:55 -0700813 uint8_t str[] = {0x01, MAX_IPMI_BUFFER - 1, MAX_IPMI_BUFFER - 1, 0x0A,
814 0x01};
vishwabmcba0bd5f2015-09-30 16:50:23 +0530815
816 // Data length
817 *data_len = sizeof(str);
818
819 // Pack the actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700820 std::memcpy(response, &str, *data_len);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530821
822 return rc;
823}
824
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500825ipmi_ret_t ipmi_app_wildcard_handler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700826 ipmi_request_t request,
827 ipmi_response_t response,
828 ipmi_data_len_t data_len,
829 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530830{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530831 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800832 ipmi_ret_t rc = IPMI_CC_INVALID;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530833
834 *data_len = strlen("THIS IS WILDCARD");
835
836 // Now pack actual response
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700837 std::memcpy(response, "THIS IS WILDCARD", *data_len);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530838
839 return rc;
840}
841
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600842ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700843 ipmi_request_t request,
844 ipmi_response_t response,
845 ipmi_data_len_t data_len,
846 ipmi_context_t context)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600847
848{
849 ipmi_ret_t rc = IPMI_CC_OK;
850 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
851
852 try
853 {
854 // Get the Inventory object implementing BMC interface
855 ipmi::DbusObjectInfo bmcObject =
856 ipmi::getDbusObject(bus, bmc_interface);
857
858 // Read UUID property value from bmcObject
859 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Venture0b02be92018-08-31 11:55:55 -0700860 auto variant =
861 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
862 bmc_guid_interface, bmc_guid_property);
William A. Kennington III4c008022018-10-12 17:18:14 -0700863 std::string guidProp = variant_ns::get<std::string>(variant);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600864
865 // Erase "-" characters from the property value
866 guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'),
Patrick Venture0b02be92018-08-31 11:55:55 -0700867 guidProp.end());
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600868
869 auto guidPropLen = guidProp.length();
870 // Validate UUID data
871 // Divide by 2 as 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700872 if ((guidPropLen <= 0) || ((guidPropLen / 2) != bmc_guid_len))
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600873
874 {
875 log<level::ERR>("Invalid UUID property value",
Patrick Venture0b02be92018-08-31 11:55:55 -0700876 entry("UUID_LENGTH=%d", guidPropLen));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600877 return IPMI_CC_RESPONSE_ERROR;
878 }
879
880 // Convert data in RFC4122(MSB) format to LSB format
881 // Get 2 characters at a time as 1 byte is built from 2 chars and
882 // convert to hex byte
883 // TODO: Data printed for GUID command is not as per the
884 // GUID format defined in IPMI specification 2.0 section 20.8
885 // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/
886 uint8_t respGuid[bmc_guid_len];
887 for (size_t i = 0, respLoc = (bmc_guid_len - 1);
Patrick Venture0b02be92018-08-31 11:55:55 -0700888 i < guidPropLen && respLoc >= 0; i += 2, respLoc--)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600889 {
890 auto value = static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700891 std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600892 respGuid[respLoc] = value;
893 }
894
895 *data_len = bmc_guid_len;
Patrick Ventureb51bf9c2018-09-10 15:53:14 -0700896 std::memcpy(response, &respGuid, bmc_guid_len);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600897 }
898 catch (const InternalFailure& e)
899 {
900 log<level::ERR>("Failed in reading BMC UUID property",
901 entry("INTERFACE=%s", bmc_interface),
902 entry("PROPERTY_INTERFACE=%s", bmc_guid_interface),
903 entry("PROPERTY=%s", bmc_guid_property));
904 return IPMI_CC_UNSPECIFIED_ERROR;
905 }
906 return rc;
907}
908
Xo Wangf542e8b2017-08-09 15:34:16 -0700909static std::unique_ptr<SysInfoParamStore> sysInfoParamStore;
910
Xo Wang87651332017-08-11 10:17:59 -0700911static std::string sysInfoReadSystemName()
912{
913 // Use the BMC hostname as the "System Name."
914 char hostname[HOST_NAME_MAX + 1] = {};
915 if (gethostname(hostname, HOST_NAME_MAX) != 0)
916 {
917 perror("System info parameter: system name");
918 }
919 return hostname;
920}
921
Xo Wangf542e8b2017-08-09 15:34:16 -0700922struct IpmiSysInfoResp
923{
924 uint8_t paramRevision;
925 uint8_t setSelector;
926 union
927 {
928 struct
929 {
930 uint8_t encoding;
931 uint8_t stringLen;
932 uint8_t stringData0[14];
933 } __attribute__((packed));
934 uint8_t stringDataN[16];
935 uint8_t byteData;
936 };
937} __attribute__((packed));
938
939/**
940 * Split a string into (up to) 16-byte chunks as expected in response for get
941 * system info parameter.
942 *
943 * @param[in] fullString: Input string to be split
944 * @param[in] chunkIndex: Index of the chunk to be written out
945 * @param[in,out] chunk: Output data buffer; must have 14 byte capacity if
946 * chunk_index = 0 and 16-byte capacity otherwise
947 * @return the number of bytes written into the output buffer, or -EINVAL for
948 * invalid arguments.
949 */
950static int splitStringParam(const std::string& fullString, int chunkIndex,
951 uint8_t* chunk)
952{
953 constexpr int maxChunk = 255;
954 constexpr int smallChunk = 14;
955 constexpr int chunkSize = 16;
956 if (chunkIndex > maxChunk || chunk == nullptr)
957 {
958 return -EINVAL;
959 }
960 try
961 {
962 std::string output;
963 if (chunkIndex == 0)
964 {
965 // Output must have 14 byte capacity.
966 output = fullString.substr(0, smallChunk);
967 }
968 else
969 {
970 // Output must have 16 byte capacity.
971 output = fullString.substr((chunkIndex * chunkSize) - 2, chunkSize);
972 }
973
974 std::memcpy(chunk, output.c_str(), output.length());
975 return output.length();
976 }
977 catch (const std::out_of_range& e)
978 {
979 // The position was beyond the end.
980 return -EINVAL;
981 }
982}
983
984/**
985 * Packs the Get Sys Info Request Item into the response.
986 *
987 * @param[in] paramString - the parameter.
988 * @param[in] setSelector - the selector
989 * @param[in,out] resp - the System info response.
990 * @return The number of bytes packed or failure from splitStringParam().
991 */
992static int packGetSysInfoResp(const std::string& paramString,
993 uint8_t setSelector, IpmiSysInfoResp* resp)
994{
995 uint8_t* dataBuffer = resp->stringDataN;
996 resp->setSelector = setSelector;
997 if (resp->setSelector == 0) // First chunk has only 14 bytes.
998 {
999 resp->encoding = 0;
1000 resp->stringLen = paramString.length();
1001 dataBuffer = resp->stringData0;
1002 }
1003 return splitStringParam(paramString, resp->setSelector, dataBuffer);
1004}
1005
1006ipmi_ret_t ipmi_app_get_system_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1007 ipmi_request_t request,
1008 ipmi_response_t response,
1009 ipmi_data_len_t dataLen,
1010 ipmi_context_t context)
1011{
1012 IpmiSysInfoResp resp = {};
1013 size_t respLen = 0;
1014 uint8_t* const reqData = static_cast<uint8_t*>(request);
1015 std::string paramString;
1016 bool found;
1017 std::tuple<bool, std::string> ret;
1018 constexpr int minRequestSize = 4;
1019 constexpr int paramSelector = 1;
1020 constexpr uint8_t revisionOnly = 0x80;
1021 const uint8_t paramRequested = reqData[paramSelector];
1022 int rc;
1023
1024 if (*dataLen < minRequestSize)
1025 {
1026 return IPMI_CC_REQ_DATA_LEN_INVALID;
1027 }
1028
1029 *dataLen = 0; // default to 0.
1030
1031 // Parameters revision as of IPMI spec v2.0 rev. 1.1 (Feb 11, 2014 E6)
1032 resp.paramRevision = 0x11;
1033 if (reqData[0] & revisionOnly) // Get parameter revision only
1034 {
1035 respLen = 1;
1036 goto writeResponse;
1037 }
1038
1039 // The "Set In Progress" parameter can be used for rollback of parameter
1040 // data and is not implemented.
1041 if (paramRequested == 0)
1042 {
1043 resp.byteData = 0;
1044 respLen = 2;
1045 goto writeResponse;
1046 }
1047
1048 if (sysInfoParamStore == nullptr)
1049 {
1050 sysInfoParamStore = std::make_unique<SysInfoParamStore>();
Xo Wang87651332017-08-11 10:17:59 -07001051 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME,
1052 sysInfoReadSystemName);
Xo Wangf542e8b2017-08-09 15:34:16 -07001053 }
1054
1055 // Parameters other than Set In Progress are assumed to be strings.
1056 ret = sysInfoParamStore->lookup(paramRequested);
1057 found = std::get<0>(ret);
1058 paramString = std::get<1>(ret);
1059 if (!found)
1060 {
1061 return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED;
1062 }
1063 // TODO: Cache each parameter across multiple calls, until the whole string
1064 // has been read out. Otherwise, it's possible for a parameter to change
1065 // between requests for its chunks, returning chunks incoherent with each
1066 // other. For now, the parameter store is simply required to have only
1067 // idempotent callbacks.
1068 rc = packGetSysInfoResp(paramString, reqData[2], &resp);
1069 if (rc == -EINVAL)
1070 {
1071 return IPMI_CC_RESPONSE_ERROR;
1072 }
1073
1074 respLen = sizeof(resp); // Write entire string data chunk in response.
1075
1076writeResponse:
1077 std::memcpy(response, &resp, sizeof(resp));
1078 *dataLen = respLen;
1079 return IPMI_CC_OK;
1080}
1081
Chris Austen6caf28b2015-10-13 12:40:40 -05001082void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +05301083{
Tom05732372016-09-06 17:21:23 +05301084 // <Get BT Interface Capabilities>
Patrick Venture0b02be92018-08-31 11:55:55 -07001085 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL,
1086 ipmi_app_get_bt_capabilities, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001087
Tom05732372016-09-06 17:21:23 +05301088 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001089 ipmi_register_callback(NETFUN_APP, IPMI_CMD_WILDCARD, NULL,
1090 ipmi_app_wildcard_handler, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001091
Tom05732372016-09-06 17:21:23 +05301092 // <Reset Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001093 ipmi_register_callback(NETFUN_APP, IPMI_CMD_RESET_WD, NULL,
1094 ipmi_app_watchdog_reset, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -05001095
Tom05732372016-09-06 17:21:23 +05301096 // <Set Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001097 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL,
1098 ipmi_app_watchdog_set, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -05001099
William A. Kennington III73f44512018-02-09 15:28:46 -08001100 // <Get Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -07001101 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_WD, NULL,
1102 ipmi_app_watchdog_get, PRIVILEGE_OPERATOR);
William A. Kennington III73f44512018-02-09 15:28:46 -08001103
Tom05732372016-09-06 17:21:23 +05301104 // <Get Device ID>
Patrick Venture0b02be92018-08-31 11:55:55 -07001105 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_ID, NULL,
1106 ipmi_app_get_device_id, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -05001107
Tom05732372016-09-06 17:21:23 +05301108 // <Get Self Test Results>
Patrick Venture0b02be92018-08-31 11:55:55 -07001109 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS, NULL,
1110 ipmi_app_get_self_test_results, PRIVILEGE_USER);
Nan Li41fa24a2016-11-10 20:12:37 +08001111
Tom05732372016-09-06 17:21:23 +05301112 // <Get Device GUID>
Patrick Venture0b02be92018-08-31 11:55:55 -07001113 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID, NULL,
1114 ipmi_app_get_device_guid, PRIVILEGE_USER);
Adriana Kobylakd100ee52015-10-20 17:02:37 -05001115
Tom05732372016-09-06 17:21:23 +05301116 // <Set ACPI Power State>
Patrick Venture0b02be92018-08-31 11:55:55 -07001117 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL,
1118 ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN);
Chris Austen6caf28b2015-10-13 12:40:40 -05001119
Yong Li18d77262018-10-09 01:59:45 +08001120 // <Get ACPI Power State>
1121 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_ACPI, NULL,
1122 ipmi_app_get_acpi_power_state, PRIVILEGE_ADMIN);
1123
AppaRao Puli071f3f22018-05-24 16:45:30 +05301124// TODO: Below code and associated api's need to be removed later.
1125// Its commented for now to avoid merge conflicts with upstream
1126// changes and smooth upstream upgrades.
1127#if 0
1128>>>>>>> IPMI Channel commands implementation
Tom Joseph69fabfe2017-08-04 10:15:01 +05301129 // <Get Channel Access>
Patrick Venture0b02be92018-08-31 11:55:55 -07001130 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
1131 ipmi_get_channel_access, PRIVILEGE_USER);
Tom Joseph69fabfe2017-08-04 10:15:01 +05301132
Tom05732372016-09-06 17:21:23 +05301133 // <Get Channel Info Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001134 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL,
1135 ipmi_app_channel_info, PRIVILEGE_USER);
AppaRao Puli071f3f22018-05-24 16:45:30 +05301136#endif
Chris Austenc2cd29d2016-02-05 20:02:29 -06001137
Marri Devender Rao5e007a52018-01-08 06:18:36 -06001138 // <Get System GUID Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001139 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL,
1140 ipmi_app_get_sys_guid, PRIVILEGE_USER);
Tom Joseph7cbe2282018-03-21 21:17:33 +05301141
1142 // <Get Channel Cipher Suites Command>
Patrick Venture0b02be92018-08-31 11:55:55 -07001143 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_CIPHER_SUITES, NULL,
1144 getChannelCipherSuites, PRIVILEGE_CALLBACK);
AppaRao Puli071f3f22018-05-24 16:45:30 +05301145#if 0
Tom Joseph13227682018-08-10 01:05:21 +05301146 // <Set Channel Access Command>
1147 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL,
1148 ipmi_set_channel_access, PRIVILEGE_ADMIN);
AppaRao Puli071f3f22018-05-24 16:45:30 +05301149#endif
Xo Wangf542e8b2017-08-09 15:34:16 -07001150 // <Get System Info Command>
1151 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYSTEM_INFO, NULL,
1152 ipmi_app_get_system_info, PRIVILEGE_USER);
vishwabmcba0bd5f2015-09-30 16:50:23 +05301153 return;
1154}