| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 1 | #include "apphandler.h" | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 2 |  | 
| Xo Wang | f542e8b | 2017-08-09 15:34:16 -0700 | [diff] [blame^] | 3 | #include "app/channel.hpp" | 
 | 4 | #include "app/watchdog.hpp" | 
 | 5 | #include "ipmid.hpp" | 
 | 6 | #include "nlohmann/json.hpp" | 
 | 7 | #include "sys_info_param.hpp" | 
 | 8 | #include "transporthandler.hpp" | 
 | 9 | #include "types.hpp" | 
 | 10 | #include "utils.hpp" | 
 | 11 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 12 | #include <arpa/inet.h> | 
 | 13 | #include <mapper.h> | 
 | 14 | #include <stdint.h> | 
 | 15 | #include <stdio.h> | 
 | 16 | #include <systemd/sd-bus.h> | 
 | 17 |  | 
| Patrick Williams | 37af733 | 2016-09-02 21:21:42 -0500 | [diff] [blame] | 18 | #include "host-ipmid/ipmid-api.h" | 
| Ratan Gupta | b8e9955 | 2017-07-27 07:07:48 +0530 | [diff] [blame] | 19 |  | 
| Vernon Mauery | 185b9f8 | 2018-07-20 10:52:36 -0700 | [diff] [blame] | 20 | #if __has_include(<filesystem>) | 
 | 21 | #include <filesystem> | 
 | 22 | #elif __has_include(<experimental/filesystem>) | 
 | 23 | #include <experimental/filesystem> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 24 | namespace std | 
 | 25 | { | 
 | 26 | // splice experimental::filesystem into std | 
 | 27 | namespace filesystem = std::experimental::filesystem; | 
 | 28 | } // namespace std | 
| Vernon Mauery | 185b9f8 | 2018-07-20 10:52:36 -0700 | [diff] [blame] | 29 | #else | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 30 | #error filesystem not available | 
| Vernon Mauery | 185b9f8 | 2018-07-20 10:52:36 -0700 | [diff] [blame] | 31 | #endif | 
| Ratan Gupta | 62736ec | 2017-09-02 12:02:47 +0530 | [diff] [blame] | 32 |  | 
| Xo Wang | f542e8b | 2017-08-09 15:34:16 -0700 | [diff] [blame^] | 33 | #include <algorithm> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 34 | #include <array> | 
 | 35 | #include <cstddef> | 
 | 36 | #include <fstream> | 
| Xo Wang | f542e8b | 2017-08-09 15:34:16 -0700 | [diff] [blame^] | 37 | #include <memory> | 
| Ratan Gupta | b8e9955 | 2017-07-27 07:07:48 +0530 | [diff] [blame] | 38 | #include <phosphor-logging/elog-errors.hpp> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 39 | #include <phosphor-logging/log.hpp> | 
 | 40 | #include <string> | 
| Xo Wang | f542e8b | 2017-08-09 15:34:16 -0700 | [diff] [blame^] | 41 | #include <tuple> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 42 | #include <vector> | 
 | 43 | #include <xyz/openbmc_project/Common/error.hpp> | 
 | 44 | #include <xyz/openbmc_project/Software/Activation/server.hpp> | 
 | 45 | #include <xyz/openbmc_project/Software/Version/server.hpp> | 
| Alexander Amelkin | ba19c18 | 2018-09-04 15:49:36 +0300 | [diff] [blame] | 46 | #include <xyz/openbmc_project/State/BMC/server.hpp> | 
| Ratan Gupta | b8e9955 | 2017-07-27 07:07:48 +0530 | [diff] [blame] | 47 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 48 | extern sd_bus* bus; | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 49 |  | 
| Alexander Amelkin | ba19c18 | 2018-09-04 15:49:36 +0300 | [diff] [blame] | 50 | constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC"; | 
 | 51 | constexpr auto bmc_state_property = "CurrentBMCState"; | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 52 | constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc"; | 
 | 53 | constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID"; | 
 | 54 | constexpr auto bmc_guid_property = "UUID"; | 
 | 55 | constexpr auto bmc_guid_len = 16; | 
 | 56 |  | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 57 | static constexpr auto redundancyIntf = | 
 | 58 |     "xyz.openbmc_project.Software.RedundancyPriority"; | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 59 | static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version"; | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 60 | static constexpr auto activationIntf = | 
 | 61 |     "xyz.openbmc_project.Software.Activation"; | 
 | 62 | static constexpr auto softwareRoot = "/xyz/openbmc_project/software"; | 
 | 63 |  | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 64 | void register_netfn_app_functions() __attribute__((constructor)); | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 65 |  | 
| Ratan Gupta | b8e9955 | 2017-07-27 07:07:48 +0530 | [diff] [blame] | 66 | using namespace phosphor::logging; | 
 | 67 | using namespace sdbusplus::xyz::openbmc_project::Common::Error; | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 68 | using Version = sdbusplus::xyz::openbmc_project::Software::server::Version; | 
 | 69 | using Activation = | 
 | 70 |     sdbusplus::xyz::openbmc_project::Software::server::Activation; | 
| Alexander Amelkin | ba19c18 | 2018-09-04 15:49:36 +0300 | [diff] [blame] | 71 | using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC; | 
| Vernon Mauery | 185b9f8 | 2018-07-20 10:52:36 -0700 | [diff] [blame] | 72 | namespace fs = std::filesystem; | 
| Ratan Gupta | b8e9955 | 2017-07-27 07:07:48 +0530 | [diff] [blame] | 73 |  | 
| Nan Li | ee0cb90 | 2016-07-11 15:38:03 +0800 | [diff] [blame] | 74 | // Offset in get device id command. | 
 | 75 | typedef struct | 
 | 76 | { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 77 |     uint8_t id; | 
 | 78 |     uint8_t revision; | 
 | 79 |     uint8_t fw[2]; | 
 | 80 |     uint8_t ipmi_ver; | 
 | 81 |     uint8_t addn_dev_support; | 
 | 82 |     uint8_t manuf_id[3]; | 
 | 83 |     uint8_t prod_id[2]; | 
 | 84 |     uint8_t aux[4]; | 
 | 85 | } __attribute__((packed)) ipmi_device_id_t; | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 86 |  | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 87 | /** | 
 | 88 |  * @brief Returns the Version info from primary s/w object | 
 | 89 |  * | 
 | 90 |  * Get the Version info from the active s/w object which is having high | 
 | 91 |  * "Priority" value(a smaller number is a higher priority) and "Purpose" | 
 | 92 |  * is "BMC" from the list of all s/w objects those are implementing | 
 | 93 |  * RedundancyPriority interface from the given softwareRoot path. | 
 | 94 |  * | 
 | 95 |  * @return On success returns the Version info from primary s/w object. | 
 | 96 |  * | 
 | 97 |  */ | 
 | 98 | std::string getActiveSoftwareVersionInfo() | 
 | 99 | { | 
 | 100 |     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; | 
 | 101 |  | 
 | 102 |     std::string revision{}; | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 103 |     auto objectTree = | 
 | 104 |         ipmi::getAllDbusObjects(bus, softwareRoot, redundancyIntf, ""); | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 105 |     if (objectTree.empty()) | 
 | 106 |     { | 
 | 107 |         log<level::ERR>("No Obj has implemented the s/w redundancy interface", | 
 | 108 |                         entry("INTERFACE=%s", redundancyIntf)); | 
 | 109 |         elog<InternalFailure>(); | 
 | 110 |     } | 
 | 111 |  | 
 | 112 |     auto objectFound = false; | 
 | 113 |     for (auto& softObject : objectTree) | 
 | 114 |     { | 
 | 115 |         auto service = ipmi::getService(bus, redundancyIntf, softObject.first); | 
 | 116 |         auto objValueTree = ipmi::getManagedObjects(bus, service, softwareRoot); | 
 | 117 |  | 
 | 118 |         auto minPriority = 0xFF; | 
 | 119 |         for (const auto& objIter : objValueTree) | 
 | 120 |         { | 
 | 121 |             try | 
 | 122 |             { | 
 | 123 |                 auto& intfMap = objIter.second; | 
 | 124 |                 auto& redundancyPriorityProps = intfMap.at(redundancyIntf); | 
 | 125 |                 auto& versionProps = intfMap.at(versionIntf); | 
 | 126 |                 auto& activationProps = intfMap.at(activationIntf); | 
 | 127 |                 auto priority = | 
 | 128 |                     redundancyPriorityProps.at("Priority").get<uint8_t>(); | 
 | 129 |                 auto purpose = versionProps.at("Purpose").get<std::string>(); | 
 | 130 |                 auto activation = | 
 | 131 |                     activationProps.at("Activation").get<std::string>(); | 
 | 132 |                 auto version = versionProps.at("Version").get<std::string>(); | 
 | 133 |                 if ((Version::convertVersionPurposeFromString(purpose) == | 
 | 134 |                      Version::VersionPurpose::BMC) && | 
 | 135 |                     (Activation::convertActivationsFromString(activation) == | 
 | 136 |                      Activation::Activations::Active)) | 
 | 137 |                 { | 
 | 138 |                     if (priority < minPriority) | 
 | 139 |                     { | 
 | 140 |                         minPriority = priority; | 
 | 141 |                         objectFound = true; | 
 | 142 |                         revision = std::move(version); | 
 | 143 |                     } | 
 | 144 |                 } | 
 | 145 |             } | 
 | 146 |             catch (const std::exception& e) | 
 | 147 |             { | 
 | 148 |                 log<level::ERR>(e.what()); | 
 | 149 |             } | 
 | 150 |         } | 
 | 151 |     } | 
 | 152 |  | 
 | 153 |     if (!objectFound) | 
 | 154 |     { | 
 | 155 |         log<level::ERR>("Could not found an BMC software Object"); | 
 | 156 |         elog<InternalFailure>(); | 
 | 157 |     } | 
 | 158 |  | 
 | 159 |     return revision; | 
 | 160 | } | 
 | 161 |  | 
| Alexander Amelkin | ba19c18 | 2018-09-04 15:49:36 +0300 | [diff] [blame] | 162 | bool getCurrentBmcState() | 
 | 163 | { | 
 | 164 |     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; | 
 | 165 |  | 
 | 166 |     // Get the Inventory object implementing the BMC interface | 
 | 167 |     ipmi::DbusObjectInfo bmcObject = | 
 | 168 |         ipmi::getDbusObject(bus, bmc_state_interface); | 
 | 169 |     auto variant = | 
 | 170 |         ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first, | 
 | 171 |                               bmc_state_interface, bmc_state_property); | 
 | 172 |  | 
 | 173 |     return variant.is<std::string>() && | 
 | 174 |            BMC::convertBMCStateFromString(variant.get<std::string>()) == | 
 | 175 |                BMC::BMCState::Ready; | 
 | 176 | } | 
 | 177 |  | 
| Adriana Kobylak | 3a552e1 | 2015-10-19 16:11:00 -0500 | [diff] [blame] | 178 | ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 179 |                                          ipmi_request_t request, | 
 | 180 |                                          ipmi_response_t response, | 
 | 181 |                                          ipmi_data_len_t data_len, | 
 | 182 |                                          ipmi_context_t context) | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 183 | { | 
 | 184 |     ipmi_ret_t rc = IPMI_CC_OK; | 
 | 185 |     *data_len = 0; | 
 | 186 |  | 
| Aditya Saripalli | 5fb1460 | 2017-11-09 14:46:27 +0530 | [diff] [blame] | 187 |     log<level::DEBUG>("IPMI SET ACPI STATE Ignoring for now\n"); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 188 |     return rc; | 
 | 189 | } | 
 | 190 |  | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 191 | typedef struct | 
 | 192 | { | 
 | 193 |     char major; | 
 | 194 |     char minor; | 
| Chris Austen | 176c965 | 2016-04-30 16:32:17 -0500 | [diff] [blame] | 195 |     uint16_t d[2]; | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 196 | } rev_t; | 
 | 197 |  | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 198 | /* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will     */ | 
 | 199 | /* return -1 if not in those formats, this routine knows how to parse       */ | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 200 | /* version = v0.6-19-gf363f61-dirty                                         */ | 
 | 201 | /*            ^ ^ ^^          ^                                             */ | 
 | 202 | /*            | |  |----------|-- additional details                        */ | 
 | 203 | /*            | |---------------- Minor                                     */ | 
 | 204 | /*            |------------------ Major                                     */ | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 205 | /* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715                        */ | 
 | 206 | /*                ^ ^  ^^ ^                                                 */ | 
 | 207 | /*                | |  |--|---------- additional details                    */ | 
 | 208 | /*                | |---------------- Minor                                 */ | 
 | 209 | /*                |------------------ Major                                 */ | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 210 | /* Additional details : If the option group exists it will force Auxiliary  */ | 
 | 211 | /* Firmware Revision Information 4th byte to 1 indicating the build was     */ | 
 | 212 | /* derived with additional edits                                            */ | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 213 | int convert_version(const char* p, rev_t* rev) | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 214 | { | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 215 |     std::string s(p); | 
 | 216 |     std::string token; | 
| Chris Austen | 176c965 | 2016-04-30 16:32:17 -0500 | [diff] [blame] | 217 |     uint16_t commits; | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 218 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 219 |     auto location = s.find_first_of('v'); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 220 |     if (location != std::string::npos) | 
 | 221 |     { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 222 |         s = s.substr(location + 1); | 
| Chris Austen | 176c965 | 2016-04-30 16:32:17 -0500 | [diff] [blame] | 223 |     } | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 224 |  | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 225 |     if (!s.empty()) | 
 | 226 |     { | 
 | 227 |         location = s.find_first_of("."); | 
 | 228 |         if (location != std::string::npos) | 
 | 229 |         { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 230 |             rev->major = | 
 | 231 |                 static_cast<char>(std::stoi(s.substr(0, location), 0, 16)); | 
 | 232 |             token = s.substr(location + 1); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 233 |         } | 
| Chris Austen | 176c965 | 2016-04-30 16:32:17 -0500 | [diff] [blame] | 234 |  | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 235 |         if (!token.empty()) | 
 | 236 |         { | 
 | 237 |             location = token.find_first_of(".-"); | 
 | 238 |             if (location != std::string::npos) | 
 | 239 |             { | 
| Patrick Venture | d211702 | 2018-02-06 08:54:37 -0800 | [diff] [blame] | 240 |                 rev->minor = static_cast<char>( | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 241 |                     std::stoi(token.substr(0, location), 0, 16)); | 
 | 242 |                 token = token.substr(location + 1); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 243 |             } | 
 | 244 |         } | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 245 |  | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 246 |         // Capture the number of commits on top of the minor tag. | 
 | 247 |         // I'm using BE format like the ipmi spec asked for | 
 | 248 |         location = token.find_first_of(".-"); | 
 | 249 |         if (!token.empty()) | 
 | 250 |         { | 
 | 251 |             commits = std::stoi(token.substr(0, location), 0, 16); | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 252 |             rev->d[0] = (commits >> 8) | (commits << 8); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 253 |  | 
 | 254 |             // commit number we skip | 
 | 255 |             location = token.find_first_of(".-"); | 
 | 256 |             if (location != std::string::npos) | 
 | 257 |             { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 258 |                 token = token.substr(location + 1); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 259 |             } | 
 | 260 |         } | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 261 |         else | 
 | 262 |         { | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 263 |             rev->d[0] = 0; | 
 | 264 |         } | 
 | 265 |  | 
 | 266 |         if (location != std::string::npos) | 
 | 267 |         { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 268 |             token = token.substr(location + 1); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 269 |         } | 
 | 270 |  | 
 | 271 |         // Any value of the optional parameter forces it to 1 | 
 | 272 |         location = token.find_first_of(".-"); | 
 | 273 |         if (location != std::string::npos) | 
 | 274 |         { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 275 |             token = token.substr(location + 1); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 276 |         } | 
 | 277 |         commits = (!token.empty()) ? 1 : 0; | 
 | 278 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 279 |         // We do this operation to get this displayed in least significant bytes | 
 | 280 |         // of ipmitool device id command. | 
 | 281 |         rev->d[1] = (commits >> 8) | (commits << 8); | 
| Dinesh Chinari | 2b7e07d | 2017-11-08 15:38:50 -0600 | [diff] [blame] | 282 |     } | 
 | 283 |  | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 284 |     return 0; | 
 | 285 | } | 
 | 286 |  | 
| Adriana Kobylak | 3a552e1 | 2015-10-19 16:11:00 -0500 | [diff] [blame] | 287 | ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 288 |                                   ipmi_request_t request, | 
 | 289 |                                   ipmi_response_t response, | 
 | 290 |                                   ipmi_data_len_t data_len, | 
 | 291 |                                   ipmi_context_t context) | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 292 | { | 
 | 293 |     ipmi_ret_t rc = IPMI_CC_OK; | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 294 |     int r = -1; | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 295 |     rev_t rev = {0}; | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 296 |     static ipmi_device_id_t dev_id{}; | 
 | 297 |     static bool dev_id_initialized = false; | 
 | 298 |     const char* filename = "/usr/share/ipmi-providers/dev_id.json"; | 
| Alexander Amelkin | ba19c18 | 2018-09-04 15:49:36 +0300 | [diff] [blame] | 299 |     constexpr auto ipmiDevIdStateShift = 7; | 
 | 300 |     constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 301 |  | 
 | 302 |     // Data length | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 303 |     *data_len = sizeof(dev_id); | 
 | 304 |  | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 305 |     if (!dev_id_initialized) | 
 | 306 |     { | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 307 |         try | 
 | 308 |         { | 
 | 309 |             auto version = getActiveSoftwareVersionInfo(); | 
 | 310 |             r = convert_version(version.c_str(), &rev); | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 311 |         } | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 312 |         catch (const std::exception& e) | 
 | 313 |         { | 
 | 314 |             log<level::ERR>(e.what()); | 
 | 315 |         } | 
| Nan Li | ee0cb90 | 2016-07-11 15:38:03 +0800 | [diff] [blame] | 316 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 317 |         if (r >= 0) | 
 | 318 |         { | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 319 |             // bit7 identifies if the device is available | 
 | 320 |             // 0=normal operation | 
 | 321 |             // 1=device firmware, SDR update, | 
 | 322 |             // or self-initialization in progress. | 
| Alexander Amelkin | ba19c18 | 2018-09-04 15:49:36 +0300 | [diff] [blame] | 323 |             // The availability may change in run time, so mask here | 
 | 324 |             // and initialize later. | 
 | 325 |             dev_id.fw[0] = rev.major & ipmiDevIdFw1Mask; | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 326 |  | 
 | 327 |             rev.minor = (rev.minor > 99 ? 99 : rev.minor); | 
 | 328 |             dev_id.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16; | 
 | 329 |             memcpy(&dev_id.aux, rev.d, 4); | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 330 |         } | 
| Nan Li | ee0cb90 | 2016-07-11 15:38:03 +0800 | [diff] [blame] | 331 |  | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 332 |         // IPMI Spec version 2.0 | 
 | 333 |         dev_id.ipmi_ver = 2; | 
| Adriana Kobylak | 0e91264 | 2016-06-22 16:54:39 -0500 | [diff] [blame] | 334 |  | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 335 |         std::ifstream dev_id_file(filename); | 
 | 336 |         if (dev_id_file.is_open()) | 
 | 337 |         { | 
 | 338 |             auto data = nlohmann::json::parse(dev_id_file, nullptr, false); | 
 | 339 |             if (!data.is_discarded()) | 
 | 340 |             { | 
 | 341 |                 dev_id.id = data.value("id", 0); | 
 | 342 |                 dev_id.revision = data.value("revision", 0); | 
 | 343 |                 dev_id.addn_dev_support = data.value("addn_dev_support", 0); | 
 | 344 |                 dev_id.manuf_id[2] = data.value("manuf_id", 0) >> 16; | 
 | 345 |                 dev_id.manuf_id[1] = data.value("manuf_id", 0) >> 8; | 
 | 346 |                 dev_id.manuf_id[0] = data.value("manuf_id", 0); | 
 | 347 |                 dev_id.prod_id[1] = data.value("prod_id", 0) >> 8; | 
 | 348 |                 dev_id.prod_id[0] = data.value("prod_id", 0); | 
| Tom Joseph | af8a098 | 2018-03-09 07:54:02 -0600 | [diff] [blame] | 349 |                 dev_id.aux[3] = data.value("aux", 0); | 
 | 350 |                 dev_id.aux[2] = data.value("aux", 0) >> 8; | 
 | 351 |                 dev_id.aux[1] = data.value("aux", 0) >> 16; | 
 | 352 |                 dev_id.aux[0] = data.value("aux", 0) >> 24; | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 353 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 354 |                 // Don't read the file every time if successful | 
| David Cobbley | a1adb07 | 2017-11-21 15:58:13 -0800 | [diff] [blame] | 355 |                 dev_id_initialized = true; | 
 | 356 |             } | 
 | 357 |             else | 
 | 358 |             { | 
 | 359 |                 log<level::ERR>("Device ID JSON parser failure"); | 
 | 360 |                 rc = IPMI_CC_UNSPECIFIED_ERROR; | 
 | 361 |             } | 
 | 362 |         } | 
 | 363 |         else | 
 | 364 |         { | 
 | 365 |             log<level::ERR>("Device ID file not found"); | 
 | 366 |             rc = IPMI_CC_UNSPECIFIED_ERROR; | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 367 |         } | 
 | 368 |     } | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 369 |  | 
| Alexander Amelkin | ba19c18 | 2018-09-04 15:49:36 +0300 | [diff] [blame] | 370 |     // Set availability to the actual current BMC state | 
 | 371 |     dev_id.fw[0] &= ipmiDevIdFw1Mask; | 
 | 372 |     if (!getCurrentBmcState()) | 
 | 373 |     { | 
 | 374 |         dev_id.fw[0] |= (1 << ipmiDevIdStateShift); | 
 | 375 |     } | 
 | 376 |  | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 377 |     // Pack the actual response | 
| Chris Austen | 7303bdc | 2016-04-17 11:50:54 -0500 | [diff] [blame] | 378 |     memcpy(response, &dev_id, *data_len); | 
| Nagaraju Goruganti | 744398d | 2018-02-20 09:52:00 -0600 | [diff] [blame] | 379 |  | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 380 |     return rc; | 
 | 381 | } | 
 | 382 |  | 
| Nan Li | 41fa24a | 2016-11-10 20:12:37 +0800 | [diff] [blame] | 383 | ipmi_ret_t ipmi_app_get_self_test_results(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 384 |                                           ipmi_request_t request, | 
 | 385 |                                           ipmi_response_t response, | 
 | 386 |                                           ipmi_data_len_t data_len, | 
 | 387 |                                           ipmi_context_t context) | 
| Nan Li | 41fa24a | 2016-11-10 20:12:37 +0800 | [diff] [blame] | 388 | { | 
 | 389 |     ipmi_ret_t rc = IPMI_CC_OK; | 
 | 390 |  | 
 | 391 |     // Byte 2: | 
 | 392 |     //  55h - No error. | 
| Gunnar Mills | 8991dd6 | 2017-10-25 17:11:29 -0500 | [diff] [blame] | 393 |     //  56h - Self Test function not implemented in this controller. | 
| Nan Li | 41fa24a | 2016-11-10 20:12:37 +0800 | [diff] [blame] | 394 |     //  57h - Corrupted or inaccesssible data or devices. | 
 | 395 |     //  58h - Fatal hardware error. | 
 | 396 |     //  FFh - reserved. | 
 | 397 |     //  all other: Device-specific 'internal failure'. | 
 | 398 |     //  Byte 3: | 
 | 399 |     //      For byte 2 = 55h, 56h, FFh:     00h | 
 | 400 |     //      For byte 2 = 58h, all other:    Device-specific | 
 | 401 |     //      For byte 2 = 57h:   self-test error bitfield. | 
 | 402 |     //      Note: returning 57h does not imply that all test were run. | 
 | 403 |     //      [7] 1b = Cannot access SEL device. | 
 | 404 |     //      [6] 1b = Cannot access SDR Repository. | 
 | 405 |     //      [5] 1b = Cannot access BMC FRU device. | 
 | 406 |     //      [4] 1b = IPMB signal lines do not respond. | 
 | 407 |     //      [3] 1b = SDR Repository empty. | 
 | 408 |     //      [2] 1b = Internal Use Area of BMC FRU corrupted. | 
 | 409 |     //      [1] 1b = controller update 'boot block' firmware corrupted. | 
 | 410 |     //      [0] 1b = controller operational firmware corrupted. | 
 | 411 |  | 
 | 412 |     char selftestresults[2] = {0}; | 
 | 413 |  | 
 | 414 |     *data_len = 2; | 
 | 415 |  | 
 | 416 |     selftestresults[0] = 0x56; | 
 | 417 |     selftestresults[1] = 0; | 
 | 418 |  | 
 | 419 |     memcpy(response, selftestresults, *data_len); | 
 | 420 |  | 
 | 421 |     return rc; | 
 | 422 | } | 
 | 423 |  | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 424 | ipmi_ret_t ipmi_app_get_device_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 425 |                                     ipmi_request_t request, | 
 | 426 |                                     ipmi_response_t response, | 
 | 427 |                                     ipmi_data_len_t data_len, | 
 | 428 |                                     ipmi_context_t context) | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 429 | { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 430 |     const char* objname = "/org/openbmc/control/chassis0"; | 
 | 431 |     const char* iface = "org.freedesktop.DBus.Properties"; | 
 | 432 |     const char* chassis_iface = "org.openbmc.control.Chassis"; | 
 | 433 |     sd_bus_message* reply = NULL; | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 434 |     sd_bus_error error = SD_BUS_ERROR_NULL; | 
 | 435 |     int r = 0; | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 436 |     char* uuid = NULL; | 
 | 437 |     char* busname = NULL; | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 438 |  | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 439 |     // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 | 
| Patrick Venture | d211702 | 2018-02-06 08:54:37 -0800 | [diff] [blame] | 440 |     // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte | 
 | 441 |     // order | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 442 |     // Ex: 0x2332fc2c40e66298e511f2782395a361 | 
 | 443 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 444 |     const int resp_size = 16;     // Response is 16 hex bytes per IPMI Spec | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 445 |     uint8_t resp_uuid[resp_size]; // Array to hold the formatted response | 
| Patrick Venture | d211702 | 2018-02-06 08:54:37 -0800 | [diff] [blame] | 446 |     // Point resp end of array to save in reverse order | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 447 |     int resp_loc = resp_size - 1; | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 448 |     int i = 0; | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 449 |     char* tokptr = NULL; | 
 | 450 |     char* id_octet = NULL; | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 451 |  | 
 | 452 |     // Status code. | 
 | 453 |     ipmi_ret_t rc = IPMI_CC_OK; | 
 | 454 |     *data_len = 0; | 
 | 455 |  | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 456 |     // Call Get properties method with the interface and property name | 
| Sergey Solomin | eb9b814 | 2016-08-23 09:07:28 -0500 | [diff] [blame] | 457 |     r = mapper_get_service(bus, objname, &busname); | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 458 |     if (r < 0) | 
 | 459 |     { | 
 | 460 |         log<level::ERR>("Failed to get bus name", entry("BUS=%s", objname), | 
| Aditya Saripalli | 5fb1460 | 2017-11-09 14:46:27 +0530 | [diff] [blame] | 461 |                         entry("ERRNO=0x%X", -r)); | 
| Sergey Solomin | eb9b814 | 2016-08-23 09:07:28 -0500 | [diff] [blame] | 462 |         goto finish; | 
 | 463 |     } | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 464 |     r = sd_bus_call_method(bus, busname, objname, iface, "Get", &error, &reply, | 
 | 465 |                            "ss", chassis_iface, "uuid"); | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 466 |     if (r < 0) | 
 | 467 |     { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 468 |         log<level::ERR>("Failed to call Get Method", entry("ERRNO=0x%X", -r)); | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 469 |         rc = IPMI_CC_UNSPECIFIED_ERROR; | 
 | 470 |         goto finish; | 
 | 471 |     } | 
 | 472 |  | 
 | 473 |     r = sd_bus_message_read(reply, "v", "s", &uuid); | 
 | 474 |     if (r < 0 || uuid == NULL) | 
 | 475 |     { | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 476 |         log<level::ERR>("Failed to get a response", entry("ERRNO=0x%X", -r)); | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 477 |         rc = IPMI_CC_RESPONSE_ERROR; | 
 | 478 |         goto finish; | 
 | 479 |     } | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 480 |  | 
 | 481 |     // Traverse the UUID | 
| Patrick Venture | d211702 | 2018-02-06 08:54:37 -0800 | [diff] [blame] | 482 |     // Get the UUID octects separated by dash | 
 | 483 |     id_octet = strtok_r(uuid, "-", &tokptr); | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 484 |  | 
 | 485 |     if (id_octet == NULL) | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 486 |     { | 
 | 487 |         // Error | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 488 |         log<level::ERR>("Unexpected UUID format", entry("UUID=%s", uuid)); | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 489 |         rc = IPMI_CC_RESPONSE_ERROR; | 
 | 490 |         goto finish; | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 491 |     } | 
 | 492 |  | 
 | 493 |     while (id_octet != NULL) | 
 | 494 |     { | 
 | 495 |         // Calculate the octet string size since it varies | 
 | 496 |         // Divide it by 2 for the array size since 1 byte is built from 2 chars | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 497 |         int tmp_size = strlen(id_octet) / 2; | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 498 |  | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 499 |         for (i = 0; i < tmp_size; i++) | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 500 |         { | 
| Patrick Venture | d211702 | 2018-02-06 08:54:37 -0800 | [diff] [blame] | 501 |             // Holder of the 2 chars that will become a byte | 
 | 502 |             char tmp_array[3] = {0}; | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 503 |             strncpy(tmp_array, id_octet, 2); // 2 chars at a time | 
 | 504 |  | 
 | 505 |             int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte | 
| Patrick Venture | d211702 | 2018-02-06 08:54:37 -0800 | [diff] [blame] | 506 |             // Copy end to first | 
 | 507 |             memcpy((void*)&resp_uuid[resp_loc], &resp_byte, 1); | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 508 |             resp_loc--; | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 509 |             id_octet += 2; // Finished with the 2 chars, advance | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 510 |         } | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 511 |         id_octet = strtok_r(NULL, "-", &tokptr); // Get next octet | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 512 |     } | 
 | 513 |  | 
 | 514 |     // Data length | 
 | 515 |     *data_len = resp_size; | 
 | 516 |  | 
 | 517 |     // Pack the actual response | 
 | 518 |     memcpy(response, &resp_uuid, *data_len); | 
 | 519 |  | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 520 | finish: | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 521 |     sd_bus_error_free(&error); | 
| vishwa | 1eaea4f | 2016-02-26 11:57:40 -0600 | [diff] [blame] | 522 |     reply = sd_bus_message_unref(reply); | 
| Sergey Solomin | eb9b814 | 2016-08-23 09:07:28 -0500 | [diff] [blame] | 523 |     free(busname); | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 524 |  | 
 | 525 |     return rc; | 
 | 526 | } | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 527 |  | 
| Adriana Kobylak | 3a552e1 | 2015-10-19 16:11:00 -0500 | [diff] [blame] | 528 | ipmi_ret_t ipmi_app_get_bt_capabilities(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 529 |                                         ipmi_request_t request, | 
 | 530 |                                         ipmi_response_t response, | 
 | 531 |                                         ipmi_data_len_t data_len, | 
 | 532 |                                         ipmi_context_t context) | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 533 | { | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 534 |  | 
 | 535 |     // Status code. | 
 | 536 |     ipmi_ret_t rc = IPMI_CC_OK; | 
 | 537 |  | 
| Adriana Kobylak | 88ad815 | 2016-12-13 10:09:08 -0600 | [diff] [blame] | 538 |     // Per IPMI 2.0 spec, the input and output buffer size must be the max | 
 | 539 |     // buffer size minus one byte to allocate space for the length byte. | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 540 |     uint8_t str[] = {0x01, MAX_IPMI_BUFFER - 1, MAX_IPMI_BUFFER - 1, 0x0A, | 
 | 541 |                      0x01}; | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 542 |  | 
 | 543 |     // Data length | 
 | 544 |     *data_len = sizeof(str); | 
 | 545 |  | 
 | 546 |     // Pack the actual response | 
 | 547 |     memcpy(response, &str, *data_len); | 
 | 548 |  | 
 | 549 |     return rc; | 
 | 550 | } | 
 | 551 |  | 
| Adriana Kobylak | 3a552e1 | 2015-10-19 16:11:00 -0500 | [diff] [blame] | 552 | ipmi_ret_t ipmi_app_wildcard_handler(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 553 |                                      ipmi_request_t request, | 
 | 554 |                                      ipmi_response_t response, | 
 | 555 |                                      ipmi_data_len_t data_len, | 
 | 556 |                                      ipmi_context_t context) | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 557 | { | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 558 |     // Status code. | 
| Nan Li | 70aa8d9 | 2016-08-29 00:11:10 +0800 | [diff] [blame] | 559 |     ipmi_ret_t rc = IPMI_CC_INVALID; | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 560 |  | 
 | 561 |     *data_len = strlen("THIS IS WILDCARD"); | 
 | 562 |  | 
 | 563 |     // Now pack actual response | 
 | 564 |     memcpy(response, "THIS IS WILDCARD", *data_len); | 
 | 565 |  | 
 | 566 |     return rc; | 
 | 567 | } | 
 | 568 |  | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 569 | ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 570 |                                  ipmi_request_t request, | 
 | 571 |                                  ipmi_response_t response, | 
 | 572 |                                  ipmi_data_len_t data_len, | 
 | 573 |                                  ipmi_context_t context) | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 574 |  | 
 | 575 | { | 
 | 576 |     ipmi_ret_t rc = IPMI_CC_OK; | 
 | 577 |     sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; | 
 | 578 |  | 
 | 579 |     try | 
 | 580 |     { | 
 | 581 |         // Get the Inventory object implementing BMC interface | 
 | 582 |         ipmi::DbusObjectInfo bmcObject = | 
 | 583 |             ipmi::getDbusObject(bus, bmc_interface); | 
 | 584 |  | 
 | 585 |         // Read UUID property value from bmcObject | 
 | 586 |         // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 587 |         auto variant = | 
 | 588 |             ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first, | 
 | 589 |                                   bmc_guid_interface, bmc_guid_property); | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 590 |         std::string guidProp = variant.get<std::string>(); | 
 | 591 |  | 
 | 592 |         // Erase "-" characters from the property value | 
 | 593 |         guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'), | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 594 |                        guidProp.end()); | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 595 |  | 
 | 596 |         auto guidPropLen = guidProp.length(); | 
 | 597 |         // Validate UUID data | 
 | 598 |         // Divide by 2 as 1 byte is built from 2 chars | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 599 |         if ((guidPropLen <= 0) || ((guidPropLen / 2) != bmc_guid_len)) | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 600 |  | 
 | 601 |         { | 
 | 602 |             log<level::ERR>("Invalid UUID property value", | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 603 |                             entry("UUID_LENGTH=%d", guidPropLen)); | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 604 |             return IPMI_CC_RESPONSE_ERROR; | 
 | 605 |         } | 
 | 606 |  | 
 | 607 |         // Convert data in RFC4122(MSB) format to LSB format | 
 | 608 |         // Get 2 characters at a time as 1 byte is built from 2 chars and | 
 | 609 |         // convert to hex byte | 
 | 610 |         // TODO: Data printed for GUID command is not as per the | 
 | 611 |         // GUID format defined in IPMI specification 2.0 section 20.8 | 
 | 612 |         // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/ | 
 | 613 |         uint8_t respGuid[bmc_guid_len]; | 
 | 614 |         for (size_t i = 0, respLoc = (bmc_guid_len - 1); | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 615 |              i < guidPropLen && respLoc >= 0; i += 2, respLoc--) | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 616 |         { | 
 | 617 |             auto value = static_cast<uint8_t>( | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 618 |                 std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16)); | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 619 |             respGuid[respLoc] = value; | 
 | 620 |         } | 
 | 621 |  | 
 | 622 |         *data_len = bmc_guid_len; | 
 | 623 |         memcpy(response, &respGuid, bmc_guid_len); | 
 | 624 |     } | 
 | 625 |     catch (const InternalFailure& e) | 
 | 626 |     { | 
 | 627 |         log<level::ERR>("Failed in reading BMC UUID property", | 
 | 628 |                         entry("INTERFACE=%s", bmc_interface), | 
 | 629 |                         entry("PROPERTY_INTERFACE=%s", bmc_guid_interface), | 
 | 630 |                         entry("PROPERTY=%s", bmc_guid_property)); | 
 | 631 |         return IPMI_CC_UNSPECIFIED_ERROR; | 
 | 632 |     } | 
 | 633 |     return rc; | 
 | 634 | } | 
 | 635 |  | 
| Xo Wang | f542e8b | 2017-08-09 15:34:16 -0700 | [diff] [blame^] | 636 | static std::unique_ptr<SysInfoParamStore> sysInfoParamStore; | 
 | 637 |  | 
 | 638 | struct IpmiSysInfoResp | 
 | 639 | { | 
 | 640 |     uint8_t paramRevision; | 
 | 641 |     uint8_t setSelector; | 
 | 642 |     union | 
 | 643 |     { | 
 | 644 |         struct | 
 | 645 |         { | 
 | 646 |             uint8_t encoding; | 
 | 647 |             uint8_t stringLen; | 
 | 648 |             uint8_t stringData0[14]; | 
 | 649 |         } __attribute__((packed)); | 
 | 650 |         uint8_t stringDataN[16]; | 
 | 651 |         uint8_t byteData; | 
 | 652 |     }; | 
 | 653 | } __attribute__((packed)); | 
 | 654 |  | 
 | 655 | /** | 
 | 656 |  * Split a string into (up to) 16-byte chunks as expected in response for get | 
 | 657 |  * system info parameter. | 
 | 658 |  * | 
 | 659 |  * @param[in] fullString: Input string to be split | 
 | 660 |  * @param[in] chunkIndex: Index of the chunk to be written out | 
 | 661 |  * @param[in,out] chunk: Output data buffer; must have 14 byte capacity if | 
 | 662 |  *          chunk_index = 0 and 16-byte capacity otherwise | 
 | 663 |  * @return the number of bytes written into the output buffer, or -EINVAL for | 
 | 664 |  * invalid arguments. | 
 | 665 |  */ | 
 | 666 | static int splitStringParam(const std::string& fullString, int chunkIndex, | 
 | 667 |                             uint8_t* chunk) | 
 | 668 | { | 
 | 669 |     constexpr int maxChunk = 255; | 
 | 670 |     constexpr int smallChunk = 14; | 
 | 671 |     constexpr int chunkSize = 16; | 
 | 672 |     if (chunkIndex > maxChunk || chunk == nullptr) | 
 | 673 |     { | 
 | 674 |         return -EINVAL; | 
 | 675 |     } | 
 | 676 |     try | 
 | 677 |     { | 
 | 678 |         std::string output; | 
 | 679 |         if (chunkIndex == 0) | 
 | 680 |         { | 
 | 681 |             // Output must have 14 byte capacity. | 
 | 682 |             output = fullString.substr(0, smallChunk); | 
 | 683 |         } | 
 | 684 |         else | 
 | 685 |         { | 
 | 686 |             // Output must have 16 byte capacity. | 
 | 687 |             output = fullString.substr((chunkIndex * chunkSize) - 2, chunkSize); | 
 | 688 |         } | 
 | 689 |  | 
 | 690 |         std::memcpy(chunk, output.c_str(), output.length()); | 
 | 691 |         return output.length(); | 
 | 692 |     } | 
 | 693 |     catch (const std::out_of_range& e) | 
 | 694 |     { | 
 | 695 |         // The position was beyond the end. | 
 | 696 |         return -EINVAL; | 
 | 697 |     } | 
 | 698 | } | 
 | 699 |  | 
 | 700 | /** | 
 | 701 |  * Packs the Get Sys Info Request Item into the response. | 
 | 702 |  * | 
 | 703 |  * @param[in] paramString - the parameter. | 
 | 704 |  * @param[in] setSelector - the selector | 
 | 705 |  * @param[in,out] resp - the System info response. | 
 | 706 |  * @return The number of bytes packed or failure from splitStringParam(). | 
 | 707 |  */ | 
 | 708 | static int packGetSysInfoResp(const std::string& paramString, | 
 | 709 |                               uint8_t setSelector, IpmiSysInfoResp* resp) | 
 | 710 | { | 
 | 711 |     uint8_t* dataBuffer = resp->stringDataN; | 
 | 712 |     resp->setSelector = setSelector; | 
 | 713 |     if (resp->setSelector == 0) // First chunk has only 14 bytes. | 
 | 714 |     { | 
 | 715 |         resp->encoding = 0; | 
 | 716 |         resp->stringLen = paramString.length(); | 
 | 717 |         dataBuffer = resp->stringData0; | 
 | 718 |     } | 
 | 719 |     return splitStringParam(paramString, resp->setSelector, dataBuffer); | 
 | 720 | } | 
 | 721 |  | 
 | 722 | ipmi_ret_t ipmi_app_get_system_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, | 
 | 723 |                                     ipmi_request_t request, | 
 | 724 |                                     ipmi_response_t response, | 
 | 725 |                                     ipmi_data_len_t dataLen, | 
 | 726 |                                     ipmi_context_t context) | 
 | 727 | { | 
 | 728 |     IpmiSysInfoResp resp = {}; | 
 | 729 |     size_t respLen = 0; | 
 | 730 |     uint8_t* const reqData = static_cast<uint8_t*>(request); | 
 | 731 |     std::string paramString; | 
 | 732 |     bool found; | 
 | 733 |     std::tuple<bool, std::string> ret; | 
 | 734 |     constexpr int minRequestSize = 4; | 
 | 735 |     constexpr int paramSelector = 1; | 
 | 736 |     constexpr uint8_t revisionOnly = 0x80; | 
 | 737 |     const uint8_t paramRequested = reqData[paramSelector]; | 
 | 738 |     int rc; | 
 | 739 |  | 
 | 740 |     if (*dataLen < minRequestSize) | 
 | 741 |     { | 
 | 742 |         return IPMI_CC_REQ_DATA_LEN_INVALID; | 
 | 743 |     } | 
 | 744 |  | 
 | 745 |     *dataLen = 0; // default to 0. | 
 | 746 |  | 
 | 747 |     // Parameters revision as of IPMI spec v2.0 rev. 1.1 (Feb 11, 2014 E6) | 
 | 748 |     resp.paramRevision = 0x11; | 
 | 749 |     if (reqData[0] & revisionOnly) // Get parameter revision only | 
 | 750 |     { | 
 | 751 |         respLen = 1; | 
 | 752 |         goto writeResponse; | 
 | 753 |     } | 
 | 754 |  | 
 | 755 |     // The "Set In Progress" parameter can be used for rollback of parameter | 
 | 756 |     // data and is not implemented. | 
 | 757 |     if (paramRequested == 0) | 
 | 758 |     { | 
 | 759 |         resp.byteData = 0; | 
 | 760 |         respLen = 2; | 
 | 761 |         goto writeResponse; | 
 | 762 |     } | 
 | 763 |  | 
 | 764 |     if (sysInfoParamStore == nullptr) | 
 | 765 |     { | 
 | 766 |         sysInfoParamStore = std::make_unique<SysInfoParamStore>(); | 
 | 767 |     } | 
 | 768 |  | 
 | 769 |     // Parameters other than Set In Progress are assumed to be strings. | 
 | 770 |     ret = sysInfoParamStore->lookup(paramRequested); | 
 | 771 |     found = std::get<0>(ret); | 
 | 772 |     paramString = std::get<1>(ret); | 
 | 773 |     if (!found) | 
 | 774 |     { | 
 | 775 |         return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED; | 
 | 776 |     } | 
 | 777 |     // TODO: Cache each parameter across multiple calls, until the whole string | 
 | 778 |     // has been read out. Otherwise, it's possible for a parameter to change | 
 | 779 |     // between requests for its chunks, returning chunks incoherent with each | 
 | 780 |     // other. For now, the parameter store is simply required to have only | 
 | 781 |     // idempotent callbacks. | 
 | 782 |     rc = packGetSysInfoResp(paramString, reqData[2], &resp); | 
 | 783 |     if (rc == -EINVAL) | 
 | 784 |     { | 
 | 785 |         return IPMI_CC_RESPONSE_ERROR; | 
 | 786 |     } | 
 | 787 |  | 
 | 788 |     respLen = sizeof(resp); // Write entire string data chunk in response. | 
 | 789 |  | 
 | 790 | writeResponse: | 
 | 791 |     std::memcpy(response, &resp, sizeof(resp)); | 
 | 792 |     *dataLen = respLen; | 
 | 793 |     return IPMI_CC_OK; | 
 | 794 | } | 
 | 795 |  | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 796 | void register_netfn_app_functions() | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 797 | { | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 798 |     // <Get BT Interface Capabilities> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 799 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CAP_BIT, NULL, | 
 | 800 |                            ipmi_app_get_bt_capabilities, PRIVILEGE_USER); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 801 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 802 |     // <Wildcard Command> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 803 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_WILDCARD, NULL, | 
 | 804 |                            ipmi_app_wildcard_handler, PRIVILEGE_USER); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 805 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 806 |     // <Reset Watchdog Timer> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 807 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_RESET_WD, NULL, | 
 | 808 |                            ipmi_app_watchdog_reset, PRIVILEGE_OPERATOR); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 809 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 810 |     // <Set Watchdog Timer> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 811 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL, | 
 | 812 |                            ipmi_app_watchdog_set, PRIVILEGE_OPERATOR); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 813 |  | 
| William A. Kennington III | 73f4451 | 2018-02-09 15:28:46 -0800 | [diff] [blame] | 814 |     // <Get Watchdog Timer> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 815 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_WD, NULL, | 
 | 816 |                            ipmi_app_watchdog_get, PRIVILEGE_OPERATOR); | 
| William A. Kennington III | 73f4451 | 2018-02-09 15:28:46 -0800 | [diff] [blame] | 817 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 818 |     // <Get Device ID> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 819 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_ID, NULL, | 
 | 820 |                            ipmi_app_get_device_id, PRIVILEGE_USER); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 821 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 822 |     // <Get Self Test Results> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 823 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SELF_TEST_RESULTS, NULL, | 
 | 824 |                            ipmi_app_get_self_test_results, PRIVILEGE_USER); | 
| Nan Li | 41fa24a | 2016-11-10 20:12:37 +0800 | [diff] [blame] | 825 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 826 |     // <Get Device GUID> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 827 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_DEVICE_GUID, NULL, | 
 | 828 |                            ipmi_app_get_device_guid, PRIVILEGE_USER); | 
| Adriana Kobylak | d100ee5 | 2015-10-20 17:02:37 -0500 | [diff] [blame] | 829 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 830 |     // <Set ACPI Power State> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 831 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL, | 
 | 832 |                            ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN); | 
| Chris Austen | 6caf28b | 2015-10-13 12:40:40 -0500 | [diff] [blame] | 833 |  | 
| Tom Joseph | 69fabfe | 2017-08-04 10:15:01 +0530 | [diff] [blame] | 834 |     // <Get Channel Access> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 835 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHANNEL_ACCESS, NULL, | 
 | 836 |                            ipmi_get_channel_access, PRIVILEGE_USER); | 
| Tom Joseph | 69fabfe | 2017-08-04 10:15:01 +0530 | [diff] [blame] | 837 |  | 
| Tom | 0573237 | 2016-09-06 17:21:23 +0530 | [diff] [blame] | 838 |     // <Get Channel Info Command> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 839 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL, | 
 | 840 |                            ipmi_app_channel_info, PRIVILEGE_USER); | 
| Chris Austen | c2cd29d | 2016-02-05 20:02:29 -0600 | [diff] [blame] | 841 |  | 
| Marri Devender Rao | 5e007a5 | 2018-01-08 06:18:36 -0600 | [diff] [blame] | 842 |     // <Get System GUID Command> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 843 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL, | 
 | 844 |                            ipmi_app_get_sys_guid, PRIVILEGE_USER); | 
| Tom Joseph | 7cbe228 | 2018-03-21 21:17:33 +0530 | [diff] [blame] | 845 |  | 
 | 846 |     // <Get Channel Cipher Suites Command> | 
| Patrick Venture | 0b02be9 | 2018-08-31 11:55:55 -0700 | [diff] [blame] | 847 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_CIPHER_SUITES, NULL, | 
 | 848 |                            getChannelCipherSuites, PRIVILEGE_CALLBACK); | 
| Tom Joseph | 1322768 | 2018-08-10 01:05:21 +0530 | [diff] [blame] | 849 |  | 
 | 850 |     // <Set Channel Access Command> | 
 | 851 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_CHAN_ACCESS, NULL, | 
 | 852 |                            ipmi_set_channel_access, PRIVILEGE_ADMIN); | 
| Xo Wang | f542e8b | 2017-08-09 15:34:16 -0700 | [diff] [blame^] | 853 |  | 
 | 854 |     // <Get System Info Command> | 
 | 855 |     ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYSTEM_INFO, NULL, | 
 | 856 |                            ipmi_app_get_system_info, PRIVILEGE_USER); | 
| vishwabmc | ba0bd5f | 2015-09-30 16:50:23 +0530 | [diff] [blame] | 857 |     return; | 
 | 858 | } |