blob: 3abac14b2e6b10ed23e5994c0e21be5e04261a21 [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>
Alexander Amelkinba19c182018-09-04 15:49:36 +030042#include <xyz/openbmc_project/State/BMC/server.hpp>
Ratan Guptab8e99552017-07-27 07:07:48 +053043
Patrick Venture0b02be92018-08-31 11:55:55 -070044extern sd_bus* bus;
vishwabmcba0bd5f2015-09-30 16:50:23 +053045
Alexander Amelkinba19c182018-09-04 15:49:36 +030046constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC";
47constexpr auto bmc_state_property = "CurrentBMCState";
Marri Devender Rao5e007a52018-01-08 06:18:36 -060048constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc";
49constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID";
50constexpr auto bmc_guid_property = "UUID";
51constexpr auto bmc_guid_len = 16;
52
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060053static constexpr auto redundancyIntf =
54 "xyz.openbmc_project.Software.RedundancyPriority";
Patrick Venture0b02be92018-08-31 11:55:55 -070055static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version";
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060056static constexpr auto activationIntf =
57 "xyz.openbmc_project.Software.Activation";
58static constexpr auto softwareRoot = "/xyz/openbmc_project/software";
59
Chris Austen6caf28b2015-10-13 12:40:40 -050060void register_netfn_app_functions() __attribute__((constructor));
vishwabmcba0bd5f2015-09-30 16:50:23 +053061
Ratan Guptab8e99552017-07-27 07:07:48 +053062using namespace phosphor::logging;
63using namespace sdbusplus::xyz::openbmc_project::Common::Error;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060064using Version = sdbusplus::xyz::openbmc_project::Software::server::Version;
65using Activation =
66 sdbusplus::xyz::openbmc_project::Software::server::Activation;
Alexander Amelkinba19c182018-09-04 15:49:36 +030067using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC;
Vernon Mauery185b9f82018-07-20 10:52:36 -070068namespace fs = std::filesystem;
Ratan Guptab8e99552017-07-27 07:07:48 +053069
Nan Liee0cb902016-07-11 15:38:03 +080070// Offset in get device id command.
71typedef struct
72{
Patrick Venture0b02be92018-08-31 11:55:55 -070073 uint8_t id;
74 uint8_t revision;
75 uint8_t fw[2];
76 uint8_t ipmi_ver;
77 uint8_t addn_dev_support;
78 uint8_t manuf_id[3];
79 uint8_t prod_id[2];
80 uint8_t aux[4];
81} __attribute__((packed)) ipmi_device_id_t;
Chris Austen7303bdc2016-04-17 11:50:54 -050082
Nagaraju Goruganti744398d2018-02-20 09:52:00 -060083/**
84 * @brief Returns the Version info from primary s/w object
85 *
86 * Get the Version info from the active s/w object which is having high
87 * "Priority" value(a smaller number is a higher priority) and "Purpose"
88 * is "BMC" from the list of all s/w objects those are implementing
89 * RedundancyPriority interface from the given softwareRoot path.
90 *
91 * @return On success returns the Version info from primary s/w object.
92 *
93 */
94std::string getActiveSoftwareVersionInfo()
95{
96 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
97
98 std::string revision{};
Patrick Venture0b02be92018-08-31 11:55:55 -070099 auto objectTree =
100 ipmi::getAllDbusObjects(bus, softwareRoot, redundancyIntf, "");
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600101 if (objectTree.empty())
102 {
103 log<level::ERR>("No Obj has implemented the s/w redundancy interface",
104 entry("INTERFACE=%s", redundancyIntf));
105 elog<InternalFailure>();
106 }
107
108 auto objectFound = false;
109 for (auto& softObject : objectTree)
110 {
111 auto service = ipmi::getService(bus, redundancyIntf, softObject.first);
112 auto objValueTree = ipmi::getManagedObjects(bus, service, softwareRoot);
113
114 auto minPriority = 0xFF;
115 for (const auto& objIter : objValueTree)
116 {
117 try
118 {
119 auto& intfMap = objIter.second;
120 auto& redundancyPriorityProps = intfMap.at(redundancyIntf);
121 auto& versionProps = intfMap.at(versionIntf);
122 auto& activationProps = intfMap.at(activationIntf);
123 auto priority =
124 redundancyPriorityProps.at("Priority").get<uint8_t>();
125 auto purpose = versionProps.at("Purpose").get<std::string>();
126 auto activation =
127 activationProps.at("Activation").get<std::string>();
128 auto version = versionProps.at("Version").get<std::string>();
129 if ((Version::convertVersionPurposeFromString(purpose) ==
130 Version::VersionPurpose::BMC) &&
131 (Activation::convertActivationsFromString(activation) ==
132 Activation::Activations::Active))
133 {
134 if (priority < minPriority)
135 {
136 minPriority = priority;
137 objectFound = true;
138 revision = std::move(version);
139 }
140 }
141 }
142 catch (const std::exception& e)
143 {
144 log<level::ERR>(e.what());
145 }
146 }
147 }
148
149 if (!objectFound)
150 {
151 log<level::ERR>("Could not found an BMC software Object");
152 elog<InternalFailure>();
153 }
154
155 return revision;
156}
157
Alexander Amelkinba19c182018-09-04 15:49:36 +0300158bool getCurrentBmcState()
159{
160 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
161
162 // Get the Inventory object implementing the BMC interface
163 ipmi::DbusObjectInfo bmcObject =
164 ipmi::getDbusObject(bus, bmc_state_interface);
165 auto variant =
166 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
167 bmc_state_interface, bmc_state_property);
168
169 return variant.is<std::string>() &&
170 BMC::convertBMCStateFromString(variant.get<std::string>()) ==
171 BMC::BMCState::Ready;
172}
173
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500174ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700175 ipmi_request_t request,
176 ipmi_response_t response,
177 ipmi_data_len_t data_len,
178 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500179{
180 ipmi_ret_t rc = IPMI_CC_OK;
181 *data_len = 0;
182
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530183 log<level::DEBUG>("IPMI SET ACPI STATE Ignoring for now\n");
Chris Austen6caf28b2015-10-13 12:40:40 -0500184 return rc;
185}
186
Chris Austen7303bdc2016-04-17 11:50:54 -0500187typedef struct
188{
189 char major;
190 char minor;
Chris Austen176c9652016-04-30 16:32:17 -0500191 uint16_t d[2];
Chris Austen7303bdc2016-04-17 11:50:54 -0500192} rev_t;
193
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600194/* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */
195/* return -1 if not in those formats, this routine knows how to parse */
Chris Austen7303bdc2016-04-17 11:50:54 -0500196/* version = v0.6-19-gf363f61-dirty */
197/* ^ ^ ^^ ^ */
198/* | | |----------|-- additional details */
199/* | |---------------- Minor */
200/* |------------------ Major */
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600201/* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */
202/* ^ ^ ^^ ^ */
203/* | | |--|---------- additional details */
204/* | |---------------- Minor */
205/* |------------------ Major */
Chris Austen7303bdc2016-04-17 11:50:54 -0500206/* Additional details : If the option group exists it will force Auxiliary */
207/* Firmware Revision Information 4th byte to 1 indicating the build was */
208/* derived with additional edits */
Patrick Venture0b02be92018-08-31 11:55:55 -0700209int convert_version(const char* p, rev_t* rev)
Chris Austen7303bdc2016-04-17 11:50:54 -0500210{
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600211 std::string s(p);
212 std::string token;
Chris Austen176c9652016-04-30 16:32:17 -0500213 uint16_t commits;
Chris Austen7303bdc2016-04-17 11:50:54 -0500214
Patrick Venture0b02be92018-08-31 11:55:55 -0700215 auto location = s.find_first_of('v');
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600216 if (location != std::string::npos)
217 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700218 s = s.substr(location + 1);
Chris Austen176c9652016-04-30 16:32:17 -0500219 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500220
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600221 if (!s.empty())
222 {
223 location = s.find_first_of(".");
224 if (location != std::string::npos)
225 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700226 rev->major =
227 static_cast<char>(std::stoi(s.substr(0, location), 0, 16));
228 token = s.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600229 }
Chris Austen176c9652016-04-30 16:32:17 -0500230
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600231 if (!token.empty())
232 {
233 location = token.find_first_of(".-");
234 if (location != std::string::npos)
235 {
Patrick Ventured2117022018-02-06 08:54:37 -0800236 rev->minor = static_cast<char>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700237 std::stoi(token.substr(0, location), 0, 16));
238 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600239 }
240 }
Chris Austen7303bdc2016-04-17 11:50:54 -0500241
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600242 // Capture the number of commits on top of the minor tag.
243 // I'm using BE format like the ipmi spec asked for
244 location = token.find_first_of(".-");
245 if (!token.empty())
246 {
247 commits = std::stoi(token.substr(0, location), 0, 16);
Patrick Venture0b02be92018-08-31 11:55:55 -0700248 rev->d[0] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600249
250 // commit number we skip
251 location = token.find_first_of(".-");
252 if (location != std::string::npos)
253 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700254 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600255 }
256 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700257 else
258 {
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600259 rev->d[0] = 0;
260 }
261
262 if (location != std::string::npos)
263 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700264 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600265 }
266
267 // Any value of the optional parameter forces it to 1
268 location = token.find_first_of(".-");
269 if (location != std::string::npos)
270 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700271 token = token.substr(location + 1);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600272 }
273 commits = (!token.empty()) ? 1 : 0;
274
Patrick Venture0b02be92018-08-31 11:55:55 -0700275 // We do this operation to get this displayed in least significant bytes
276 // of ipmitool device id command.
277 rev->d[1] = (commits >> 8) | (commits << 8);
Dinesh Chinari2b7e07d2017-11-08 15:38:50 -0600278 }
279
Chris Austen7303bdc2016-04-17 11:50:54 -0500280 return 0;
281}
282
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500283ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700284 ipmi_request_t request,
285 ipmi_response_t response,
286 ipmi_data_len_t data_len,
287 ipmi_context_t context)
Chris Austen6caf28b2015-10-13 12:40:40 -0500288{
289 ipmi_ret_t rc = IPMI_CC_OK;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600290 int r = -1;
Chris Austen7303bdc2016-04-17 11:50:54 -0500291 rev_t rev = {0};
David Cobbleya1adb072017-11-21 15:58:13 -0800292 static ipmi_device_id_t dev_id{};
293 static bool dev_id_initialized = false;
294 const char* filename = "/usr/share/ipmi-providers/dev_id.json";
Alexander Amelkinba19c182018-09-04 15:49:36 +0300295 constexpr auto ipmiDevIdStateShift = 7;
296 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift);
Chris Austen6caf28b2015-10-13 12:40:40 -0500297
298 // Data length
Chris Austen7303bdc2016-04-17 11:50:54 -0500299 *data_len = sizeof(dev_id);
300
David Cobbleya1adb072017-11-21 15:58:13 -0800301 if (!dev_id_initialized)
302 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600303 try
304 {
305 auto version = getActiveSoftwareVersionInfo();
306 r = convert_version(version.c_str(), &rev);
David Cobbleya1adb072017-11-21 15:58:13 -0800307 }
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600308 catch (const std::exception& e)
309 {
310 log<level::ERR>(e.what());
311 }
Nan Liee0cb902016-07-11 15:38:03 +0800312
Patrick Venture0b02be92018-08-31 11:55:55 -0700313 if (r >= 0)
314 {
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600315 // bit7 identifies if the device is available
316 // 0=normal operation
317 // 1=device firmware, SDR update,
318 // or self-initialization in progress.
Alexander Amelkinba19c182018-09-04 15:49:36 +0300319 // The availability may change in run time, so mask here
320 // and initialize later.
321 dev_id.fw[0] = rev.major & ipmiDevIdFw1Mask;
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600322
323 rev.minor = (rev.minor > 99 ? 99 : rev.minor);
324 dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16;
325 memcpy(&dev_id.aux, rev.d, 4);
David Cobbleya1adb072017-11-21 15:58:13 -0800326 }
Nan Liee0cb902016-07-11 15:38:03 +0800327
David Cobbleya1adb072017-11-21 15:58:13 -0800328 // IPMI Spec version 2.0
329 dev_id.ipmi_ver = 2;
Adriana Kobylak0e912642016-06-22 16:54:39 -0500330
David Cobbleya1adb072017-11-21 15:58:13 -0800331 std::ifstream dev_id_file(filename);
332 if (dev_id_file.is_open())
333 {
334 auto data = nlohmann::json::parse(dev_id_file, nullptr, false);
335 if (!data.is_discarded())
336 {
337 dev_id.id = data.value("id", 0);
338 dev_id.revision = data.value("revision", 0);
339 dev_id.addn_dev_support = data.value("addn_dev_support", 0);
340 dev_id.manuf_id[2] = data.value("manuf_id", 0) >> 16;
341 dev_id.manuf_id[1] = data.value("manuf_id", 0) >> 8;
342 dev_id.manuf_id[0] = data.value("manuf_id", 0);
343 dev_id.prod_id[1] = data.value("prod_id", 0) >> 8;
344 dev_id.prod_id[0] = data.value("prod_id", 0);
Tom Josephaf8a0982018-03-09 07:54:02 -0600345 dev_id.aux[3] = data.value("aux", 0);
346 dev_id.aux[2] = data.value("aux", 0) >> 8;
347 dev_id.aux[1] = data.value("aux", 0) >> 16;
348 dev_id.aux[0] = data.value("aux", 0) >> 24;
David Cobbleya1adb072017-11-21 15:58:13 -0800349
Patrick Venture0b02be92018-08-31 11:55:55 -0700350 // Don't read the file every time if successful
David Cobbleya1adb072017-11-21 15:58:13 -0800351 dev_id_initialized = true;
352 }
353 else
354 {
355 log<level::ERR>("Device ID JSON parser failure");
356 rc = IPMI_CC_UNSPECIFIED_ERROR;
357 }
358 }
359 else
360 {
361 log<level::ERR>("Device ID file not found");
362 rc = IPMI_CC_UNSPECIFIED_ERROR;
Chris Austen7303bdc2016-04-17 11:50:54 -0500363 }
364 }
Chris Austen6caf28b2015-10-13 12:40:40 -0500365
Alexander Amelkinba19c182018-09-04 15:49:36 +0300366 // Set availability to the actual current BMC state
367 dev_id.fw[0] &= ipmiDevIdFw1Mask;
368 if (!getCurrentBmcState())
369 {
370 dev_id.fw[0] |= (1 << ipmiDevIdStateShift);
371 }
372
Chris Austen6caf28b2015-10-13 12:40:40 -0500373 // Pack the actual response
Chris Austen7303bdc2016-04-17 11:50:54 -0500374 memcpy(response, &dev_id, *data_len);
Nagaraju Goruganti744398d2018-02-20 09:52:00 -0600375
Chris Austen6caf28b2015-10-13 12:40:40 -0500376 return rc;
377}
378
Nan Li41fa24a2016-11-10 20:12:37 +0800379ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700380 ipmi_request_t request,
381 ipmi_response_t response,
382 ipmi_data_len_t data_len,
383 ipmi_context_t context)
Nan Li41fa24a2016-11-10 20:12:37 +0800384{
385 ipmi_ret_t rc = IPMI_CC_OK;
386
387 // Byte 2:
388 // 55h - No error.
Gunnar Mills8991dd62017-10-25 17:11:29 -0500389 // 56h - Self Test function not implemented in this controller.
Nan Li41fa24a2016-11-10 20:12:37 +0800390 // 57h - Corrupted or inaccesssible data or devices.
391 // 58h - Fatal hardware error.
392 // FFh - reserved.
393 // all other: Device-specific 'internal failure'.
394 // Byte 3:
395 // For byte 2 = 55h, 56h, FFh: 00h
396 // For byte 2 = 58h, all other: Device-specific
397 // For byte 2 = 57h: self-test error bitfield.
398 // Note: returning 57h does not imply that all test were run.
399 // [7] 1b = Cannot access SEL device.
400 // [6] 1b = Cannot access SDR Repository.
401 // [5] 1b = Cannot access BMC FRU device.
402 // [4] 1b = IPMB signal lines do not respond.
403 // [3] 1b = SDR Repository empty.
404 // [2] 1b = Internal Use Area of BMC FRU corrupted.
405 // [1] 1b = controller update 'boot block' firmware corrupted.
406 // [0] 1b = controller operational firmware corrupted.
407
408 char selftestresults[2] = {0};
409
410 *data_len = 2;
411
412 selftestresults[0] = 0x56;
413 selftestresults[1] = 0;
414
415 memcpy(response, selftestresults, *data_len);
416
417 return rc;
418}
419
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500420ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700421 ipmi_request_t request,
422 ipmi_response_t response,
423 ipmi_data_len_t data_len,
424 ipmi_context_t context)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500425{
Patrick Venture0b02be92018-08-31 11:55:55 -0700426 const char* objname = "/org/openbmc/control/chassis0";
427 const char* iface = "org.freedesktop.DBus.Properties";
428 const char* chassis_iface = "org.openbmc.control.Chassis";
429 sd_bus_message* reply = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500430 sd_bus_error error = SD_BUS_ERROR_NULL;
431 int r = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700432 char* uuid = NULL;
433 char* busname = NULL;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500434
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500435 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Ventured2117022018-02-06 08:54:37 -0800436 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte
437 // order
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500438 // Ex: 0x2332fc2c40e66298e511f2782395a361
439
Patrick Venture0b02be92018-08-31 11:55:55 -0700440 const int resp_size = 16; // Response is 16 hex bytes per IPMI Spec
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500441 uint8_t resp_uuid[resp_size]; // Array to hold the formatted response
Patrick Ventured2117022018-02-06 08:54:37 -0800442 // Point resp end of array to save in reverse order
Patrick Venture0b02be92018-08-31 11:55:55 -0700443 int resp_loc = resp_size - 1;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500444 int i = 0;
Patrick Venture0b02be92018-08-31 11:55:55 -0700445 char* tokptr = NULL;
446 char* id_octet = NULL;
vishwa1eaea4f2016-02-26 11:57:40 -0600447
448 // Status code.
449 ipmi_ret_t rc = IPMI_CC_OK;
450 *data_len = 0;
451
vishwa1eaea4f2016-02-26 11:57:40 -0600452 // Call Get properties method with the interface and property name
Sergey Solomineb9b8142016-08-23 09:07:28 -0500453 r = mapper_get_service(bus, objname, &busname);
Patrick Venture0b02be92018-08-31 11:55:55 -0700454 if (r < 0)
455 {
456 log<level::ERR>("Failed to get bus name", entry("BUS=%s", objname),
Aditya Saripalli5fb14602017-11-09 14:46:27 +0530457 entry("ERRNO=0x%X", -r));
Sergey Solomineb9b8142016-08-23 09:07:28 -0500458 goto finish;
459 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700460 r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply,
461 "ss", chassis_iface, "uuid");
vishwa1eaea4f2016-02-26 11:57:40 -0600462 if (r < 0)
463 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700464 log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600465 rc = IPMI_CC_UNSPECIFIED_ERROR;
466 goto finish;
467 }
468
469 r = sd_bus_message_read(reply, "v", "s", &uuid);
470 if (r < 0 || uuid == NULL)
471 {
Patrick Venture0b02be92018-08-31 11:55:55 -0700472 log<level::ERR>("Failed to get a response", entry("ERRNO=0x%X", -r));
vishwa1eaea4f2016-02-26 11:57:40 -0600473 rc = IPMI_CC_RESPONSE_ERROR;
474 goto finish;
475 }
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500476
477 // Traverse the UUID
Patrick Ventured2117022018-02-06 08:54:37 -0800478 // Get the UUID octects separated by dash
479 id_octet = strtok_r(uuid, "-", &tokptr);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500480
481 if (id_octet == NULL)
vishwa1eaea4f2016-02-26 11:57:40 -0600482 {
483 // Error
Patrick Venture0b02be92018-08-31 11:55:55 -0700484 log<level::ERR>("Unexpected UUID format", entry("UUID=%s", uuid));
vishwa1eaea4f2016-02-26 11:57:40 -0600485 rc = IPMI_CC_RESPONSE_ERROR;
486 goto finish;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500487 }
488
489 while (id_octet != NULL)
490 {
491 // Calculate the octet string size since it varies
492 // Divide it by 2 for the array size since 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700493 int tmp_size = strlen(id_octet) / 2;
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500494
Patrick Venture0b02be92018-08-31 11:55:55 -0700495 for (i = 0; i < tmp_size; i++)
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500496 {
Patrick Ventured2117022018-02-06 08:54:37 -0800497 // Holder of the 2 chars that will become a byte
498 char tmp_array[3] = {0};
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500499 strncpy(tmp_array, id_octet, 2); // 2 chars at a time
500
501 int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
Patrick Ventured2117022018-02-06 08:54:37 -0800502 // Copy end to first
503 memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500504 resp_loc--;
Patrick Venture0b02be92018-08-31 11:55:55 -0700505 id_octet += 2; // Finished with the 2 chars, advance
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500506 }
Patrick Venture0b02be92018-08-31 11:55:55 -0700507 id_octet = strtok_r(NULL, "-", &tokptr); // Get next octet
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500508 }
509
510 // Data length
511 *data_len = resp_size;
512
513 // Pack the actual response
514 memcpy(response, &resp_uuid, *data_len);
515
vishwa1eaea4f2016-02-26 11:57:40 -0600516finish:
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500517 sd_bus_error_free(&error);
vishwa1eaea4f2016-02-26 11:57:40 -0600518 reply = sd_bus_message_unref(reply);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500519 free(busname);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500520
521 return rc;
522}
Chris Austen6caf28b2015-10-13 12:40:40 -0500523
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500524ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700525 ipmi_request_t request,
526 ipmi_response_t response,
527 ipmi_data_len_t data_len,
528 ipmi_context_t context)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530529{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530530
531 // Status code.
532 ipmi_ret_t rc = IPMI_CC_OK;
533
Adriana Kobylak88ad8152016-12-13 10:09:08 -0600534 // Per IPMI 2.0 spec, the input and output buffer size must be the max
535 // buffer size minus one byte to allocate space for the length byte.
Patrick Venture0b02be92018-08-31 11:55:55 -0700536 uint8_t str[] = {0x01, MAX_IPMI_BUFFER - 1, MAX_IPMI_BUFFER - 1, 0x0A,
537 0x01};
vishwabmcba0bd5f2015-09-30 16:50:23 +0530538
539 // Data length
540 *data_len = sizeof(str);
541
542 // Pack the actual response
543 memcpy(response, &str, *data_len);
544
545 return rc;
546}
547
Adriana Kobylak3a552e12015-10-19 16:11:00 -0500548ipmi_ret_t ipmi_app_wildcard_handler(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)
vishwabmcba0bd5f2015-09-30 16:50:23 +0530553{
vishwabmcba0bd5f2015-09-30 16:50:23 +0530554 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800555 ipmi_ret_t rc = IPMI_CC_INVALID;
vishwabmcba0bd5f2015-09-30 16:50:23 +0530556
557 *data_len = strlen("THIS IS WILDCARD");
558
559 // Now pack actual response
560 memcpy(response, "THIS IS WILDCARD", *data_len);
561
562 return rc;
563}
564
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600565ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Patrick Venture0b02be92018-08-31 11:55:55 -0700566 ipmi_request_t request,
567 ipmi_response_t response,
568 ipmi_data_len_t data_len,
569 ipmi_context_t context)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600570
571{
572 ipmi_ret_t rc = IPMI_CC_OK;
573 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()};
574
575 try
576 {
577 // Get the Inventory object implementing BMC interface
578 ipmi::DbusObjectInfo bmcObject =
579 ipmi::getDbusObject(bus, bmc_interface);
580
581 // Read UUID property value from bmcObject
582 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
Patrick Venture0b02be92018-08-31 11:55:55 -0700583 auto variant =
584 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first,
585 bmc_guid_interface, bmc_guid_property);
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600586 std::string guidProp = variant.get<std::string>();
587
588 // Erase "-" characters from the property value
589 guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'),
Patrick Venture0b02be92018-08-31 11:55:55 -0700590 guidProp.end());
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600591
592 auto guidPropLen = guidProp.length();
593 // Validate UUID data
594 // Divide by 2 as 1 byte is built from 2 chars
Patrick Venture0b02be92018-08-31 11:55:55 -0700595 if ((guidPropLen <= 0) || ((guidPropLen / 2) != bmc_guid_len))
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600596
597 {
598 log<level::ERR>("Invalid UUID property value",
Patrick Venture0b02be92018-08-31 11:55:55 -0700599 entry("UUID_LENGTH=%d", guidPropLen));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600600 return IPMI_CC_RESPONSE_ERROR;
601 }
602
603 // Convert data in RFC4122(MSB) format to LSB format
604 // Get 2 characters at a time as 1 byte is built from 2 chars and
605 // convert to hex byte
606 // TODO: Data printed for GUID command is not as per the
607 // GUID format defined in IPMI specification 2.0 section 20.8
608 // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/
609 uint8_t respGuid[bmc_guid_len];
610 for (size_t i = 0, respLoc = (bmc_guid_len - 1);
Patrick Venture0b02be92018-08-31 11:55:55 -0700611 i < guidPropLen && respLoc >= 0; i += 2, respLoc--)
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600612 {
613 auto value = static_cast<uint8_t>(
Patrick Venture0b02be92018-08-31 11:55:55 -0700614 std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16));
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600615 respGuid[respLoc] = value;
616 }
617
618 *data_len = bmc_guid_len;
619 memcpy(response, &respGuid, bmc_guid_len);
620 }
621 catch (const InternalFailure& e)
622 {
623 log<level::ERR>("Failed in reading BMC UUID property",
624 entry("INTERFACE=%s", bmc_interface),
625 entry("PROPERTY_INTERFACE=%s", bmc_guid_interface),
626 entry("PROPERTY=%s", bmc_guid_property));
627 return IPMI_CC_UNSPECIFIED_ERROR;
628 }
629 return rc;
630}
631
Chris Austen6caf28b2015-10-13 12:40:40 -0500632void register_netfn_app_functions()
vishwabmcba0bd5f2015-09-30 16:50:23 +0530633{
Tom05732372016-09-06 17:21:23 +0530634 // <Get BT Interface Capabilities>
Patrick Venture0b02be92018-08-31 11:55:55 -0700635 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL,
636 ipmi_app_get_bt_capabilities, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -0500637
Tom05732372016-09-06 17:21:23 +0530638 // <Wildcard Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700639 ipmi_register_callback(NETFUN_APP, IPMI_CMD_WILDCARD, NULL,
640 ipmi_app_wildcard_handler, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -0500641
Tom05732372016-09-06 17:21:23 +0530642 // <Reset Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -0700643 ipmi_register_callback(NETFUN_APP, IPMI_CMD_RESET_WD, NULL,
644 ipmi_app_watchdog_reset, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -0500645
Tom05732372016-09-06 17:21:23 +0530646 // <Set Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -0700647 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL,
648 ipmi_app_watchdog_set, PRIVILEGE_OPERATOR);
Chris Austen6caf28b2015-10-13 12:40:40 -0500649
William A. Kennington III73f44512018-02-09 15:28:46 -0800650 // <Get Watchdog Timer>
Patrick Venture0b02be92018-08-31 11:55:55 -0700651 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_WD, NULL,
652 ipmi_app_watchdog_get, PRIVILEGE_OPERATOR);
William A. Kennington III73f44512018-02-09 15:28:46 -0800653
Tom05732372016-09-06 17:21:23 +0530654 // <Get Device ID>
Patrick Venture0b02be92018-08-31 11:55:55 -0700655 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_ID, NULL,
656 ipmi_app_get_device_id, PRIVILEGE_USER);
Chris Austen6caf28b2015-10-13 12:40:40 -0500657
Tom05732372016-09-06 17:21:23 +0530658 // <Get Self Test Results>
Patrick Venture0b02be92018-08-31 11:55:55 -0700659 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS, NULL,
660 ipmi_app_get_self_test_results, PRIVILEGE_USER);
Nan Li41fa24a2016-11-10 20:12:37 +0800661
Tom05732372016-09-06 17:21:23 +0530662 // <Get Device GUID>
Patrick Venture0b02be92018-08-31 11:55:55 -0700663 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID, NULL,
664 ipmi_app_get_device_guid, PRIVILEGE_USER);
Adriana Kobylakd100ee52015-10-20 17:02:37 -0500665
Tom05732372016-09-06 17:21:23 +0530666 // <Set ACPI Power State>
Patrick Venture0b02be92018-08-31 11:55:55 -0700667 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL,
668 ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN);
Chris Austen6caf28b2015-10-13 12:40:40 -0500669
Tom Joseph69fabfe2017-08-04 10:15:01 +0530670 // <Get Channel Access>
Patrick Venture0b02be92018-08-31 11:55:55 -0700671 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL,
672 ipmi_get_channel_access, PRIVILEGE_USER);
Tom Joseph69fabfe2017-08-04 10:15:01 +0530673
Tom05732372016-09-06 17:21:23 +0530674 // <Get Channel Info Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700675 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL,
676 ipmi_app_channel_info, PRIVILEGE_USER);
Chris Austenc2cd29d2016-02-05 20:02:29 -0600677
Marri Devender Rao5e007a52018-01-08 06:18:36 -0600678 // <Get System GUID Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700679 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL,
680 ipmi_app_get_sys_guid, PRIVILEGE_USER);
Tom Joseph7cbe2282018-03-21 21:17:33 +0530681
682 // <Get Channel Cipher Suites Command>
Patrick Venture0b02be92018-08-31 11:55:55 -0700683 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_CIPHER_SUITES, NULL,
684 getChannelCipherSuites, PRIVILEGE_CALLBACK);
Tom Joseph13227682018-08-10 01:05:21 +0530685
686 // <Set Channel Access Command>
687 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL,
688 ipmi_set_channel_access, PRIVILEGE_ADMIN);
vishwabmcba0bd5f2015-09-30 16:50:23 +0530689 return;
690}