blob: b0893318623ae0ab707b8bfe26db48f9254d9752 [file] [log] [blame]
vishwabmcba0bd5f2015-09-30 16:50:23 +05301#include "apphandler.h"
Patrick Venture0b02be92018-08-31 11:55:55 -07002
3#include <arpa/inet.h>
4#include <mapper.h>
5#include <stdint.h>
6#include <stdio.h>
7#include <systemd/sd-bus.h>
8
Patrick Williams37af7332016-09-02 21:21:42 -05009#include "host-ipmid/ipmid-api.h"
Ratan Guptab8e99552017-07-27 07:07:48 +053010
Vernon Mauery185b9f82018-07-20 10:52:36 -070011#if __has_include(<filesystem>)
12#include <filesystem>
13#elif __has_include(<experimental/filesystem>)
14#include <experimental/filesystem>
Patrick Venture0b02be92018-08-31 11:55:55 -070015namespace std
16{
17// splice experimental::filesystem into std
18namespace filesystem = std::experimental::filesystem;
19} // namespace std
Vernon Mauery185b9f82018-07-20 10:52:36 -070020#else
Patrick Venture0b02be92018-08-31 11:55:55 -070021#error filesystem not available
Vernon Mauery185b9f82018-07-20 10:52:36 -070022#endif
Ratan Gupta62736ec2017-09-02 12:02:47 +053023
Patrick Venture0b02be92018-08-31 11:55:55 -070024#include "app/channel.hpp"
25#include "app/watchdog.hpp"
26#include "ipmid.hpp"
27#include "nlohmann/json.hpp"
Ratan Guptab8e99552017-07-27 07:07:48 +053028#include "transporthandler.hpp"
Patrick Venture0b02be92018-08-31 11:55:55 -070029#include "types.hpp"
30#include "utils.hpp"
Ratan Guptab8e99552017-07-27 07:07:48 +053031
Patrick Venture0b02be92018-08-31 11:55:55 -070032#include <array>
33#include <cstddef>
34#include <fstream>
Ratan Guptab8e99552017-07-27 07:07:48 +053035#include <phosphor-logging/elog-errors.hpp>
Patrick Venture0b02be92018-08-31 11:55:55 -070036#include <phosphor-logging/log.hpp>
37#include <string>
38#include <vector>
39#include <xyz/openbmc_project/Common/error.hpp>
40#include <xyz/openbmc_project/Software/Activation/server.hpp>
41#include <xyz/openbmc_project/Software/Version/server.hpp>
Ratan Guptab8e99552017-07-27 07:07:48 +053042
Patrick Venture0b02be92018-08-31 11:55:55 -070043extern sd_bus* bus;
vishwabmcba0bd5f2015-09-30 16:50:23 +053044
Marri Devender Rao5e007a52018-01-08 06:18:36 -060045constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
46constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
47constexpr auto bmc_guid_property = "UUID";
48constexpr auto bmc_guid_len = 16;
49
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060050static constexpr auto redundancyIntf =
51 "xyz.openbmc_project.Software.RedundancyPriority";
Patrick Venture0b02be92018-08-31 11:55:55 -070052static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060053static constexpr auto activationIntf =
54 "xyz.openbmc_project.Software.Activation";
55static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
56
Chris Austen6caf28b2015-10-13 12:40:40 -050057void register_netfn_app_functions() __attribute__((constructor));
vishwabmcba0bd5f2015-09-30 16:50:23 +053058
Ratan Guptab8e99552017-07-27 07:07:48 +053059using namespace phosphor::logging;
60using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060061using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
62using Activation =
63 sdbusplus::xyz::openbmc_project::Software::server::Activation;
Vernon Mauery185b9f82018-07-20 10:52:36 -070064namespace fs = std::filesystem;
Ratan Guptab8e99552017-07-27 07:07:48 +053065
Nan Liee0cb902016-07-11 15:38:03 +080066// Offset in get device id command.
67typedef struct
68{
Patrick Venture0b02be92018-08-31 11:55:55 -070069 uint8_t id;
70 uint8_t revision;
71 uint8_t fw[2];
72 uint8_t ipmi_ver;
73 uint8_t addn_dev_support;
74 uint8_t manuf_id[3];
75 uint8_t prod_id[2];
76 uint8_t aux[4];
77} __attribute__((packed)) ipmi_device_id_t;
Chris Austen7303bdc2016-04-17 11:50:54 -050078
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060079/**
80 * @brief Returns the Version info from primary s/w object
81 *
82 * Get the Version info from the active s/w object which is having high
83 * "Priority" value(a smaller number is a higher priority) and "Purpose"
84 * is "BMC" from the list of all s/w objects those are implementing
85 * RedundancyPriority interface from the given softwareRoot path.
86 *
87 * @return On success returns the Version info from primary s/w object.
88 *
89 */
90std::string getActiveSoftwareVersionInfo()
91{
92 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
93
94 std::string revision{};
Patrick Venture0b02be92018-08-31 11:55:55 -070095 auto objectTree =
96 ipmi::getAllDbusObjects(bus, softwareRoot, redundancyIntf, "");
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060097 if (objectTree.empty())
98 {
99 log<level::ERR>("No Obj has implemented the s/w redundancy interface",
100 entry("INTERFACE=%s", redundancyIntf));
101 elog<InternalFailure>();
102 }
103
104 auto objectFound = false;
105 for (auto& softObject : objectTree)
106 {
107 auto service = ipmi::getService(bus, redundancyIntf, softObject.first);
108 auto objValueTree = ipmi::getManagedObjects(bus, service, softwareRoot);
109
110 auto minPriority = 0xFF;
111 for (const auto& objIter : objValueTree)
112 {
113 try
114 {
115 auto& intfMap = objIter.second;
116 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
117 auto& versionProps = intfMap.at(versionIntf);
118 auto& activationProps = intfMap.at(activationIntf);
119 auto priority =
120 redundancyPriorityProps.at("Priority").get<uint8_t>();
121 auto purpose = versionProps.at("Purpose").get<std::string>();
122 auto activation =
123 activationProps.at("Activation").get<std::string>();
124 auto version = versionProps.at("Version").get<std::string>();
125 if ((Version::convertVersionPurposeFromString(purpose) ==
126 Version::VersionPurpose::BMC) &&
127 (Activation::convertActivationsFromString(activation) ==
128 Activation::Activations::Active))
129 {
130 if (priority < minPriority)
131 {
132 minPriority = priority;
133 objectFound = true;
134 revision = std::move(version);
135 }
136 }
137 }
138 catch (const std::exception& e)
139 {
140 log<level::ERR>(e.what());
141 }
142 }
143 }
144
145 if (!objectFound)
146 {
147 log<level::ERR>("Could not found an BMC software Object");
148 elog<InternalFailure>();
149 }
150
151 return revision;
152}
153
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500154ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700155 ipmi_request_t request,
156 ipmi_response_t response,
157 ipmi_data_len_t data_len,
158 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500159{
160 ipmi_ret_t rc = IPMI_CC_OK;
161 *data_len = 0;
162
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530163 log<level::DEBUG>("IPMI SET ACPI STATE Ignoring for now\n");
Chris Austen6caf28b2015-10-13 12:40:40 -0500164 return rc;
165}
166
Chris Austen7303bdc2016-04-17 11:50:54 -0500167typedef struct
168{
169 char major;
170 char minor;
Chris Austen176c9652016-04-30 16:32:17 -0500171 uint16_t d[2];
Chris Austen7303bdc2016-04-17 11:50:54 -0500172} rev_t;
173
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600174/* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */
175/* return -1 if not in those formats, this routine knows how to parse */
Chris Austen7303bdc2016-04-17 11:50:54 -0500176/* version = v0.6-19-gf363f61-dirty */
177/* ^ ^ ^^ ^ */
178/* | | |----------|-- additional details */
179/* | |---------------- Minor */
180/* |------------------ Major */
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600181/* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */
182/* ^ ^ ^^ ^ */
183/* | | |--|---------- additional details */
184/* | |---------------- Minor */
185/* |------------------ Major */
Chris Austen7303bdc2016-04-17 11:50:54 -0500186/* Additional details : If the option group exists it will force Auxiliary */
187/* Firmware Revision Information 4th byte to 1 indicating the build was */
188/* derived with additional edits */
Patrick Venture0b02be92018-08-31 11:55:55 -0700189int convert_version(const char* p, rev_t* rev)
Chris Austen7303bdc2016-04-17 11:50:54 -0500190{
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600191 std::string s(p);
192 std::string token;
Chris Austen176c9652016-04-30 16:32:17 -0500193 uint16_t commits;
Chris Austen7303bdc2016-04-17 11:50:54 -0500194
Patrick Venture0b02be92018-08-31 11:55:55 -0700195 auto location = s.find_first_of('v');
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600196 if (location != std::string::npos)
197 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700198 s = s.substr(location + 1);
Chris Austen176c9652016-04-30 16:32:17 -0500199 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500200
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600201 if (!s.empty())
202 {
203 location = s.find_first_of(".");
204 if (location != std::string::npos)
205 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700206 rev->major =
207 static_cast<char>(std::stoi(s.substr(0, location), 0, 16));
208 token = s.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600209 }
Chris Austen176c9652016-04-30 16:32:17 -0500210
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600211 if (!token.empty())
212 {
213 location = token.find_first_of(".-");
214 if (location != std::string::npos)
215 {
Patrick Ventured2117022018-02-06 08:54:37 -0800216 rev->minor = static_cast<char>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700217 std::stoi(token.substr(0, location), 0, 16));
218 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600219 }
220 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500221
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600222 // Capture the number of commits on top of the minor tag.
223 // I'm using BE format like the ipmi spec asked for
224 location = token.find_first_of(".-");
225 if (!token.empty())
226 {
227 commits = std::stoi(token.substr(0, location), 0, 16);
Patrick Venture0b02be92018-08-31 11:55:55 -0700228 rev->d[0] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600229
230 // commit number we skip
231 location = token.find_first_of(".-");
232 if (location != std::string::npos)
233 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700234 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600235 }
236 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700237 else
238 {
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600239 rev->d[0] = 0;
240 }
241
242 if (location != std::string::npos)
243 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700244 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600245 }
246
247 // Any value of the optional parameter forces it to 1
248 location = token.find_first_of(".-");
249 if (location != std::string::npos)
250 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700251 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600252 }
253 commits = (!token.empty()) ? 1 : 0;
254
Patrick Venture0b02be92018-08-31 11:55:55 -0700255 // We do this operation to get this displayed in least significant bytes
256 // of ipmitool device id command.
257 rev->d[1] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600258 }
259
Chris Austen7303bdc2016-04-17 11:50:54 -0500260 return 0;
261}
262
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500263ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700264 ipmi_request_t request,
265 ipmi_response_t response,
266 ipmi_data_len_t data_len,
267 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500268{
269 ipmi_ret_t rc = IPMI_CC_OK;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600270 int r = -1;
Chris Austen7303bdc2016-04-17 11:50:54 -0500271 rev_t rev = {0};
David Cobbleya1adb072017-11-21 15:58:13 -0800272 static ipmi_device_id_t dev_id{};
273 static bool dev_id_initialized = false;
274 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
Chris Austen6caf28b2015-10-13 12:40:40 -0500275
276 // Data length
Chris Austen7303bdc2016-04-17 11:50:54 -0500277 *data_len = sizeof(dev_id);
278
David Cobbleya1adb072017-11-21 15:58:13 -0800279 if (!dev_id_initialized)
280 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600281 try
282 {
283 auto version = getActiveSoftwareVersionInfo();
284 r = convert_version(version.c_str(), &rev);
David Cobbleya1adb072017-11-21 15:58:13 -0800285 }
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600286 catch (const std::exception& e)
287 {
288 log<level::ERR>(e.what());
289 }
Nan Liee0cb902016-07-11 15:38:03 +0800290
Patrick Venture0b02be92018-08-31 11:55:55 -0700291 if (r >= 0)
292 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600293 // bit7 identifies if the device is available
294 // 0=normal operation
295 // 1=device firmware, SDR update,
296 // or self-initialization in progress.
297 // our SDR is normal working condition, so mask:
298 dev_id.fw[0] = 0x7F & rev.major;
299
300 rev.minor = (rev.minor > 99 ? 99 : rev.minor);
301 dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
302 memcpy(&dev_id.aux, rev.d, 4);
David Cobbleya1adb072017-11-21 15:58:13 -0800303 }
Nan Liee0cb902016-07-11 15:38:03 +0800304
David Cobbleya1adb072017-11-21 15:58:13 -0800305 // IPMI Spec version 2.0
306 dev_id.ipmi_ver = 2;
Adriana Kobylak0e912642016-06-22 16:54:39 -0500307
David Cobbleya1adb072017-11-21 15:58:13 -0800308 std::ifstream dev_id_file(filename);
309 if (dev_id_file.is_open())
310 {
311 auto data = nlohmann::json::parse(dev_id_file, nullptr, false);
312 if (!data.is_discarded())
313 {
314 dev_id.id = data.value("id", 0);
315 dev_id.revision = data.value("revision", 0);
316 dev_id.addn_dev_support = data.value("addn_dev_support", 0);
317 dev_id.manuf_id[2] = data.value("manuf_id", 0) >> 16;
318 dev_id.manuf_id[1] = data.value("manuf_id", 0) >> 8;
319 dev_id.manuf_id[0] = data.value("manuf_id", 0);
320 dev_id.prod_id[1] = data.value("prod_id", 0) >> 8;
321 dev_id.prod_id[0] = data.value("prod_id", 0);
Tom Josephaf8a0982018-03-09 07:54:02 -0600322 dev_id.aux[3] = data.value("aux", 0);
323 dev_id.aux[2] = data.value("aux", 0) >> 8;
324 dev_id.aux[1] = data.value("aux", 0) >> 16;
325 dev_id.aux[0] = data.value("aux", 0) >> 24;
David Cobbleya1adb072017-11-21 15:58:13 -0800326
Patrick Venture0b02be92018-08-31 11:55:55 -0700327 // Don't read the file every time if successful
David Cobbleya1adb072017-11-21 15:58:13 -0800328 dev_id_initialized = true;
329 }
330 else
331 {
332 log<level::ERR>("Device ID JSON parser failure");
333 rc = IPMI_CC_UNSPECIFIED_ERROR;
334 }
335 }
336 else
337 {
338 log<level::ERR>("Device ID file not found");
339 rc = IPMI_CC_UNSPECIFIED_ERROR;
Chris Austen7303bdc2016-04-17 11:50:54 -0500340 }
341 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500342
343 // Pack the actual response
Chris Austen7303bdc2016-04-17 11:50:54 -0500344 memcpy(response, &dev_id, *data_len);
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600345
Chris Austen6caf28b2015-10-13 12:40:40 -0500346 return rc;
347}
348
Nan Li41fa24a2016-11-10 20:12:37 +0800349ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700350 ipmi_request_t request,
351 ipmi_response_t response,
352 ipmi_data_len_t data_len,
353 ipmi_context_t context)
Nan Li41fa24a2016-11-10 20:12:37 +0800354{
355 ipmi_ret_t rc = IPMI_CC_OK;
356
357 // Byte 2:
358 // 55h - No error.
Gunnar Mills8991dd62017-10-25 17:11:29 -0500359 // 56h - Self Test function not implemented in this controller.
Nan Li41fa24a2016-11-10 20:12:37 +0800360 // 57h - Corrupted or inaccesssible data or devices.
361 // 58h - Fatal hardware error.
362 // FFh - reserved.
363 // all other: Device-specific 'internal failure'.
364 // Byte 3:
365 // For byte 2 = 55h, 56h, FFh: 00h
366 // For byte 2 = 58h, all other: Device-specific
367 // For byte 2 = 57h: self-test error bitfield.
368 // Note: returning 57h does not imply that all test were run.
369 // [7] 1b = Cannot access SEL device.
370 // [6] 1b = Cannot access SDR Repository.
371 // [5] 1b = Cannot access BMC FRU device.
372 // [4] 1b = IPMB signal lines do not respond.
373 // [3] 1b = SDR Repository empty.
374 // [2] 1b = Internal Use Area of BMC FRU corrupted.
375 // [1] 1b = controller update 'boot block' firmware corrupted.
376 // [0] 1b = controller operational firmware corrupted.
377
378 char selftestresults[2] = {0};
379
380 *data_len = 2;
381
382 selftestresults[0] = 0x56;
383 selftestresults[1] = 0;
384
385 memcpy(response, selftestresults, *data_len);
386
387 return rc;
388}
389
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500390ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700391 ipmi_request_t request,
392 ipmi_response_t response,
393 ipmi_data_len_t data_len,
394 ipmi_context_t context)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500395{
Patrick Venture0b02be92018-08-31 11:55:55 -0700396 const char* objname = "/org/openbmc/control/chassis0";
397 const char* iface = "org.freedesktop.DBus.Properties";
398 const char* chassis_iface = "org.openbmc.control.Chassis";
399 sd_bus_message* reply = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500400 sd_bus_error error = SD_BUS_ERROR_NULL;
401 int r = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700402 char* uuid = NULL;
403 char* busname = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500404
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500405 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Ventured2117022018-02-06 08:54:37 -0800406 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
407 // order
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500408 // Ex: 0x2332fc2c40e66298e511f2782395a361
409
Patrick Venture0b02be92018-08-31 11:55:55 -0700410 const int resp_size = 16; // Response is 16 hex bytes per IPMI Spec
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500411 uint8_t resp_uuid[resp_size]; // Array to hold the formatted response
Patrick Ventured2117022018-02-06 08:54:37 -0800412 // Point resp end of array to save in reverse order
Patrick Venture0b02be92018-08-31 11:55:55 -0700413 int resp_loc = resp_size - 1;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500414 int i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700415 char* tokptr = NULL;
416 char* id_octet = NULL;
vishwa1eaea4f2016-02-26 11:57:40 -0600417
418 // Status code.
419 ipmi_ret_t rc = IPMI_CC_OK;
420 *data_len = 0;
421
vishwa1eaea4f2016-02-26 11:57:40 -0600422 // Call Get properties method with the interface and property name
Sergey Solomineb9b8142016-08-23 09:07:28 -0500423 r = mapper_get_service(bus, objname, &busname);
Patrick Venture0b02be92018-08-31 11:55:55 -0700424 if (r < 0)
425 {
426 log<level::ERR>("Failed to get bus name", entry("BUS=%s", objname),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530427 entry("ERRNO=0x%X", -r));
Sergey Solomineb9b8142016-08-23 09:07:28 -0500428 goto finish;
429 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700430 r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply,
431 "ss", chassis_iface, "uuid");
vishwa1eaea4f2016-02-26 11:57:40 -0600432 if (r < 0)
433 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700434 log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600435 rc = IPMI_CC_UNSPECIFIED_ERROR;
436 goto finish;
437 }
438
439 r = sd_bus_message_read(reply, "v", "s", &uuid);
440 if (r < 0 || uuid == NULL)
441 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700442 log<level::ERR>("Failed to get a response", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600443 rc = IPMI_CC_RESPONSE_ERROR;
444 goto finish;
445 }
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500446
447 // Traverse the UUID
Patrick Ventured2117022018-02-06 08:54:37 -0800448 // Get the UUID octects separated by dash
449 id_octet = strtok_r(uuid, "-", &tokptr);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500450
451 if (id_octet == NULL)
vishwa1eaea4f2016-02-26 11:57:40 -0600452 {
453 // Error
Patrick Venture0b02be92018-08-31 11:55:55 -0700454 log<level::ERR>("Unexpected UUID format", entry("UUID=%s", uuid));
vishwa1eaea4f2016-02-26 11:57:40 -0600455 rc = IPMI_CC_RESPONSE_ERROR;
456 goto finish;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500457 }
458
459 while (id_octet != NULL)
460 {
461 // Calculate the octet string size since it varies
462 // Divide it by 2 for the array size since 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700463 int tmp_size = strlen(id_octet) / 2;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500464
Patrick Venture0b02be92018-08-31 11:55:55 -0700465 for (i = 0; i < tmp_size; i++)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500466 {
Patrick Ventured2117022018-02-06 08:54:37 -0800467 // Holder of the 2 chars that will become a byte
468 char tmp_array[3] = {0};
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500469 strncpy(tmp_array, id_octet, 2); // 2 chars at a time
470
471 int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
Patrick Ventured2117022018-02-06 08:54:37 -0800472 // Copy end to first
473 memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500474 resp_loc--;
Patrick Venture0b02be92018-08-31 11:55:55 -0700475 id_octet += 2; // Finished with the 2 chars, advance
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500476 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700477 id_octet = strtok_r(NULL, "-", &tokptr); // Get next octet
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500478 }
479
480 // Data length
481 *data_len = resp_size;
482
483 // Pack the actual response
484 memcpy(response, &resp_uuid, *data_len);
485
vishwa1eaea4f2016-02-26 11:57:40 -0600486finish:
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500487 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600488 reply = sd_bus_message_unref(reply);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500489 free(busname);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500490
491 return rc;
492}
Chris Austen6caf28b2015-10-13 12:40:40 -0500493
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500494ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700495 ipmi_request_t request,
496 ipmi_response_t response,
497 ipmi_data_len_t data_len,
498 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530499{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530500
501 // Status code.
502 ipmi_ret_t rc = IPMI_CC_OK;
503
Adriana Kobylak88ad8152016-12-13 10:09:08 -0600504 // Per IPMI 2.0 spec, the input and output buffer size must be the max
505 // buffer size minus one byte to allocate space for the length byte.
Patrick Venture0b02be92018-08-31 11:55:55 -0700506 uint8_t str[] = {0x01, MAX_IPMI_BUFFER - 1, MAX_IPMI_BUFFER - 1, 0x0A,
507 0x01};
vishwabmcba0bd5f2015-09-30 16:50:23 +0530508
509 // Data length
510 *data_len = sizeof(str);
511
512 // Pack the actual response
513 memcpy(response, &str, *data_len);
514
515 return rc;
516}
517
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500518ipmi_ret_t ipmi_app_wildcard_handler(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700519 ipmi_request_t request,
520 ipmi_response_t response,
521 ipmi_data_len_t data_len,
522 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530523{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530524 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800525 ipmi_ret_t rc = IPMI_CC_INVALID;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530526
527 *data_len = strlen("THIS IS WILDCARD");
528
529 // Now pack actual response
530 memcpy(response, "THIS IS WILDCARD", *data_len);
531
532 return rc;
533}
534
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600535ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700536 ipmi_request_t request,
537 ipmi_response_t response,
538 ipmi_data_len_t data_len,
539 ipmi_context_t context)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600540
541{
542 ipmi_ret_t rc = IPMI_CC_OK;
543 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
544
545 try
546 {
547 // Get the Inventory object implementing BMC interface
548 ipmi::DbusObjectInfo bmcObject =
549 ipmi::getDbusObject(bus, bmc_interface);
550
551 // Read UUID property value from bmcObject
552 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Venture0b02be92018-08-31 11:55:55 -0700553 auto variant =
554 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
555 bmc_guid_interface, bmc_guid_property);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600556 std::string guidProp = variant.get<std::string>();
557
558 // Erase "-" characters from the property value
559 guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'),
Patrick Venture0b02be92018-08-31 11:55:55 -0700560 guidProp.end());
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600561
562 auto guidPropLen = guidProp.length();
563 // Validate UUID data
564 // Divide by 2 as 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700565 if ((guidPropLen <= 0) || ((guidPropLen / 2) != bmc_guid_len))
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600566
567 {
568 log<level::ERR>("Invalid UUID property value",
Patrick Venture0b02be92018-08-31 11:55:55 -0700569 entry("UUID_LENGTH=%d", guidPropLen));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600570 return IPMI_CC_RESPONSE_ERROR;
571 }
572
573 // Convert data in RFC4122(MSB) format to LSB format
574 // Get 2 characters at a time as 1 byte is built from 2 chars and
575 // convert to hex byte
576 // TODO: Data printed for GUID command is not as per the
577 // GUID format defined in IPMI specification 2.0 section 20.8
578 // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/
579 uint8_t respGuid[bmc_guid_len];
580 for (size_t i = 0, respLoc = (bmc_guid_len - 1);
Patrick Venture0b02be92018-08-31 11:55:55 -0700581 i < guidPropLen && respLoc >= 0; i += 2, respLoc--)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600582 {
583 auto value = static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700584 std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600585 respGuid[respLoc] = value;
586 }
587
588 *data_len = bmc_guid_len;
589 memcpy(response, &respGuid, bmc_guid_len);
590 }
591 catch (const InternalFailure& e)
592 {
593 log<level::ERR>("Failed in reading BMC UUID property",
594 entry("INTERFACE=%s", bmc_interface),
595 entry("PROPERTY_INTERFACE=%s", bmc_guid_interface),
596 entry("PROPERTY=%s", bmc_guid_property));
597 return IPMI_CC_UNSPECIFIED_ERROR;
598 }
599 return rc;
600}
601
Chris Austen6caf28b2015-10-13 12:40:40 -0500602void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +0530603{
Tom05732372016-09-06 17:21:23 +0530604 // <Get BT Interface Capabilities>
Patrick Venture0b02be92018-08-31 11:55:55 -0700605 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL,
606 ipmi_app_get_bt_capabilities, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -0500607
Tom05732372016-09-06 17:21:23 +0530608 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700609 ipmi_register_callback(NETFUN_APP, IPMI_CMD_WILDCARD, NULL,
610 ipmi_app_wildcard_handler, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -0500611
Tom05732372016-09-06 17:21:23 +0530612 // <Reset Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -0700613 ipmi_register_callback(NETFUN_APP, IPMI_CMD_RESET_WD, NULL,
614 ipmi_app_watchdog_reset, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -0500615
Tom05732372016-09-06 17:21:23 +0530616 // <Set Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -0700617 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL,
618 ipmi_app_watchdog_set, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -0500619
William A. Kennington III73f44512018-02-09 15:28:46 -0800620 // <Get Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -0700621 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_WD, NULL,
622 ipmi_app_watchdog_get, PRIVILEGE_OPERATOR);
William A. Kennington III73f44512018-02-09 15:28:46 -0800623
Tom05732372016-09-06 17:21:23 +0530624 // <Get Device ID>
Patrick Venture0b02be92018-08-31 11:55:55 -0700625 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_ID, NULL,
626 ipmi_app_get_device_id, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -0500627
Tom05732372016-09-06 17:21:23 +0530628 // <Get Self Test Results>
Patrick Venture0b02be92018-08-31 11:55:55 -0700629 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS, NULL,
630 ipmi_app_get_self_test_results, PRIVILEGE_USER);
Nan Li41fa24a2016-11-10 20:12:37 +0800631
Tom05732372016-09-06 17:21:23 +0530632 // <Get Device GUID>
Patrick Venture0b02be92018-08-31 11:55:55 -0700633 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID, NULL,
634 ipmi_app_get_device_guid, PRIVILEGE_USER);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500635
Tom05732372016-09-06 17:21:23 +0530636 // <Set ACPI Power State>
Patrick Venture0b02be92018-08-31 11:55:55 -0700637 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL,
638 ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN);
Chris Austen6caf28b2015-10-13 12:40:40 -0500639
Tom Joseph69fabfe2017-08-04 10:15:01 +0530640 // <Get Channel Access>
Patrick Venture0b02be92018-08-31 11:55:55 -0700641 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
642 ipmi_get_channel_access, PRIVILEGE_USER);
Tom Joseph69fabfe2017-08-04 10:15:01 +0530643
Tom05732372016-09-06 17:21:23 +0530644 // <Get Channel Info Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700645 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL,
646 ipmi_app_channel_info, PRIVILEGE_USER);
Chris Austenc2cd29d2016-02-05 20:02:29 -0600647
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600648 // <Get System GUID Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700649 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL,
650 ipmi_app_get_sys_guid, PRIVILEGE_USER);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530651
652 // <Get Channel Cipher Suites Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700653 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_CIPHER_SUITES, NULL,
654 getChannelCipherSuites, PRIVILEGE_CALLBACK);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530655 return;
656}