1 #include <arpa/inet.h> 2 #include <fcntl.h> 3 #include <limits.h> 4 #include <linux/i2c-dev.h> 5 #include <linux/i2c.h> 6 #include <mapper.h> 7 #include <sys/ioctl.h> 8 #include <sys/stat.h> 9 #include <sys/types.h> 10 #include <systemd/sd-bus.h> 11 #include <unistd.h> 12 13 #include <algorithm> 14 #include <app/channel.hpp> 15 #include <app/watchdog.hpp> 16 #include <apphandler.hpp> 17 #include <array> 18 #include <cstddef> 19 #include <cstdint> 20 #include <filesystem> 21 #include <fstream> 22 #include <ipmid/api.hpp> 23 #include <ipmid/types.hpp> 24 #include <ipmid/utils.hpp> 25 #include <memory> 26 #include <nlohmann/json.hpp> 27 #include <phosphor-logging/elog-errors.hpp> 28 #include <phosphor-logging/log.hpp> 29 #include <sdbusplus/message/types.hpp> 30 #include <string> 31 #include <sys_info_param.hpp> 32 #include <transporthandler.hpp> 33 #include <tuple> 34 #include <vector> 35 #include <xyz/openbmc_project/Common/error.hpp> 36 #include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp> 37 #include <xyz/openbmc_project/Software/Activation/server.hpp> 38 #include <xyz/openbmc_project/Software/Version/server.hpp> 39 #include <xyz/openbmc_project/State/BMC/server.hpp> 40 41 extern sd_bus* bus; 42 43 constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC"; 44 constexpr auto bmc_state_property = "CurrentBMCState"; 45 constexpr auto bmc_interface = "xyz.openbmc_project.Inventory.Item.Bmc"; 46 constexpr auto bmc_guid_interface = "xyz.openbmc_project.Common.UUID"; 47 constexpr auto bmc_guid_property = "UUID"; 48 constexpr auto bmc_guid_len = 16; 49 50 static constexpr auto redundancyIntf = 51 "xyz.openbmc_project.Software.RedundancyPriority"; 52 static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version"; 53 static constexpr auto activationIntf = 54 "xyz.openbmc_project.Software.Activation"; 55 static constexpr auto softwareRoot = "/xyz/openbmc_project/software"; 56 57 void register_netfn_app_functions() __attribute__((constructor)); 58 59 using namespace phosphor::logging; 60 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 61 using Version = sdbusplus::xyz::openbmc_project::Software::server::Version; 62 using Activation = 63 sdbusplus::xyz::openbmc_project::Software::server::Activation; 64 using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC; 65 namespace fs = std::filesystem; 66 67 typedef struct 68 { 69 uint8_t busId; 70 uint8_t slaveAddr; 71 uint8_t slaveAddrMask; 72 std::vector<uint8_t> data; 73 std::vector<uint8_t> dataMask; 74 } i2cMasterWRWhitelist; 75 76 static std::vector<i2cMasterWRWhitelist>& getWRWhitelist() 77 { 78 static std::vector<i2cMasterWRWhitelist> wrWhitelist; 79 return wrWhitelist; 80 } 81 82 static constexpr const char* i2cMasterWRWhitelistFile = 83 "/usr/share/ipmi-providers/master_write_read_white_list.json"; 84 85 static constexpr uint8_t maxIPMIWriteReadSize = 144; 86 static constexpr const char* filtersStr = "filters"; 87 static constexpr const char* busIdStr = "busId"; 88 static constexpr const char* slaveAddrStr = "slaveAddr"; 89 static constexpr const char* slaveAddrMaskStr = "slaveAddrMask"; 90 static constexpr const char* cmdStr = "command"; 91 static constexpr const char* cmdMaskStr = "commandMask"; 92 static constexpr int base_16 = 16; 93 94 /** 95 * @brief Returns the Version info from primary s/w object 96 * 97 * Get the Version info from the active s/w object which is having high 98 * "Priority" value(a smaller number is a higher priority) and "Purpose" 99 * is "BMC" from the list of all s/w objects those are implementing 100 * RedundancyPriority interface from the given softwareRoot path. 101 * 102 * @return On success returns the Version info from primary s/w object. 103 * 104 */ 105 std::string getActiveSoftwareVersionInfo() 106 { 107 auto busp = getSdBus(); 108 109 std::string revision{}; 110 ipmi::ObjectTree objectTree; 111 try 112 { 113 objectTree = 114 ipmi::getAllDbusObjects(*busp, softwareRoot, redundancyIntf); 115 } 116 catch (sdbusplus::exception::SdBusError& e) 117 { 118 log<level::ERR>("Failed to fetch redundancy object from dbus", 119 entry("INTERFACE=%s", redundancyIntf), 120 entry("ERRMSG=%s", e.what())); 121 elog<InternalFailure>(); 122 } 123 124 auto objectFound = false; 125 for (auto& softObject : objectTree) 126 { 127 auto service = 128 ipmi::getService(*busp, redundancyIntf, softObject.first); 129 auto objValueTree = 130 ipmi::getManagedObjects(*busp, service, softwareRoot); 131 132 auto minPriority = 0xFF; 133 for (const auto& objIter : objValueTree) 134 { 135 try 136 { 137 auto& intfMap = objIter.second; 138 auto& redundancyPriorityProps = intfMap.at(redundancyIntf); 139 auto& versionProps = intfMap.at(versionIntf); 140 auto& activationProps = intfMap.at(activationIntf); 141 auto priority = 142 std::get<uint8_t>(redundancyPriorityProps.at("Priority")); 143 auto purpose = 144 std::get<std::string>(versionProps.at("Purpose")); 145 auto activation = 146 std::get<std::string>(activationProps.at("Activation")); 147 auto version = 148 std::get<std::string>(versionProps.at("Version")); 149 if ((Version::convertVersionPurposeFromString(purpose) == 150 Version::VersionPurpose::BMC) && 151 (Activation::convertActivationsFromString(activation) == 152 Activation::Activations::Active)) 153 { 154 if (priority < minPriority) 155 { 156 minPriority = priority; 157 objectFound = true; 158 revision = std::move(version); 159 } 160 } 161 } 162 catch (const std::exception& e) 163 { 164 log<level::ERR>(e.what()); 165 } 166 } 167 } 168 169 if (!objectFound) 170 { 171 log<level::ERR>("Could not found an BMC software Object"); 172 elog<InternalFailure>(); 173 } 174 175 return revision; 176 } 177 178 bool getCurrentBmcState() 179 { 180 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 181 182 // Get the Inventory object implementing the BMC interface 183 ipmi::DbusObjectInfo bmcObject = 184 ipmi::getDbusObject(bus, bmc_state_interface); 185 auto variant = 186 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first, 187 bmc_state_interface, bmc_state_property); 188 189 return std::holds_alternative<std::string>(variant) && 190 BMC::convertBMCStateFromString(std::get<std::string>(variant)) == 191 BMC::BMCState::Ready; 192 } 193 194 bool getCurrentBmcStateWithFallback(const bool fallbackAvailability) 195 { 196 try 197 { 198 return getCurrentBmcState(); 199 } 200 catch (...) 201 { 202 // Nothing provided the BMC interface, therefore return whatever was 203 // configured as the default. 204 return fallbackAvailability; 205 } 206 } 207 208 namespace acpi_state 209 { 210 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server; 211 212 const static constexpr char* acpiObjPath = 213 "/xyz/openbmc_project/control/host0/acpi_power_state"; 214 const static constexpr char* acpiInterface = 215 "xyz.openbmc_project.Control.Power.ACPIPowerState"; 216 const static constexpr char* sysACPIProp = "SysACPIStatus"; 217 const static constexpr char* devACPIProp = "DevACPIStatus"; 218 219 enum class PowerStateType : uint8_t 220 { 221 sysPowerState = 0x00, 222 devPowerState = 0x01, 223 }; 224 225 // Defined in 20.6 of ipmi doc 226 enum class PowerState : uint8_t 227 { 228 s0G0D0 = 0x00, 229 s1D1 = 0x01, 230 s2D2 = 0x02, 231 s3D3 = 0x03, 232 s4 = 0x04, 233 s5G2 = 0x05, 234 s4S5 = 0x06, 235 g3 = 0x07, 236 sleep = 0x08, 237 g1Sleep = 0x09, 238 override = 0x0a, 239 legacyOn = 0x20, 240 legacyOff = 0x21, 241 unknown = 0x2a, 242 noChange = 0x7f, 243 }; 244 245 static constexpr uint8_t stateChanged = 0x80; 246 247 struct ACPIState 248 { 249 uint8_t sysACPIState; 250 uint8_t devACPIState; 251 } __attribute__((packed)); 252 253 std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = { 254 {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0}, 255 {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1}, 256 {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2}, 257 {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3}, 258 {ACPIPowerState::ACPI::S4, PowerState::s4}, 259 {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2}, 260 {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5}, 261 {ACPIPowerState::ACPI::G3, PowerState::g3}, 262 {ACPIPowerState::ACPI::SLEEP, PowerState::sleep}, 263 {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep}, 264 {ACPIPowerState::ACPI::OVERRIDE, PowerState::override}, 265 {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn}, 266 {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff}, 267 {ACPIPowerState::ACPI::Unknown, PowerState::unknown}}; 268 269 bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state) 270 { 271 if (type == acpi_state::PowerStateType::sysPowerState) 272 { 273 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) || 274 (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) || 275 (state == 276 static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) || 277 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) || 278 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange))) 279 { 280 return true; 281 } 282 else 283 { 284 return false; 285 } 286 } 287 else if (type == acpi_state::PowerStateType::devPowerState) 288 { 289 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) || 290 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) || 291 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange))) 292 { 293 return true; 294 } 295 else 296 { 297 return false; 298 } 299 } 300 else 301 { 302 return false; 303 } 304 return false; 305 } 306 } // namespace acpi_state 307 308 ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 309 ipmi_request_t request, 310 ipmi_response_t response, 311 ipmi_data_len_t data_len, 312 ipmi_context_t context) 313 { 314 auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown); 315 ipmi_ret_t rc = IPMI_CC_OK; 316 317 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 318 319 auto value = acpi_state::ACPIPowerState::ACPI::Unknown; 320 321 auto* req = reinterpret_cast<acpi_state::ACPIState*>(request); 322 323 if (*data_len != sizeof(acpi_state::ACPIState)) 324 { 325 log<level::ERR>("set_acpi invalid len"); 326 *data_len = 0; 327 return IPMI_CC_REQ_DATA_LEN_INVALID; 328 } 329 330 *data_len = 0; 331 332 if (req->sysACPIState & acpi_state::stateChanged) 333 { 334 // set system power state 335 s = req->sysACPIState & ~acpi_state::stateChanged; 336 337 if (!acpi_state::isValidACPIState( 338 acpi_state::PowerStateType::sysPowerState, s)) 339 { 340 log<level::ERR>("set_acpi_power sys invalid input", 341 entry("S=%x", s)); 342 return IPMI_CC_PARM_OUT_OF_RANGE; 343 } 344 345 // valid input 346 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange)) 347 { 348 log<level::DEBUG>("No change for system power state"); 349 } 350 else 351 { 352 auto found = std::find_if( 353 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(), 354 [&s](const auto& iter) { 355 return (static_cast<uint8_t>(iter.second) == s); 356 }); 357 358 value = found->first; 359 360 try 361 { 362 auto acpiObject = 363 ipmi::getDbusObject(bus, acpi_state::acpiInterface); 364 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first, 365 acpi_state::acpiInterface, 366 acpi_state::sysACPIProp, 367 convertForMessage(value)); 368 } 369 catch (const InternalFailure& e) 370 { 371 log<level::ERR>("Failed in set ACPI system property", 372 entry("EXCEPTION=%s", e.what())); 373 return IPMI_CC_UNSPECIFIED_ERROR; 374 } 375 } 376 } 377 else 378 { 379 log<level::DEBUG>("Do not change system power state"); 380 } 381 382 if (req->devACPIState & acpi_state::stateChanged) 383 { 384 // set device power state 385 s = req->devACPIState & ~acpi_state::stateChanged; 386 if (!acpi_state::isValidACPIState( 387 acpi_state::PowerStateType::devPowerState, s)) 388 { 389 log<level::ERR>("set_acpi_power dev invalid input", 390 entry("S=%x", s)); 391 return IPMI_CC_PARM_OUT_OF_RANGE; 392 } 393 394 // valid input 395 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange)) 396 { 397 log<level::DEBUG>("No change for device power state"); 398 } 399 else 400 { 401 auto found = std::find_if( 402 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(), 403 [&s](const auto& iter) { 404 return (static_cast<uint8_t>(iter.second) == s); 405 }); 406 407 value = found->first; 408 409 try 410 { 411 auto acpiObject = 412 ipmi::getDbusObject(bus, acpi_state::acpiInterface); 413 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first, 414 acpi_state::acpiInterface, 415 acpi_state::devACPIProp, 416 convertForMessage(value)); 417 } 418 catch (const InternalFailure& e) 419 { 420 log<level::ERR>("Failed in set ACPI device property", 421 entry("EXCEPTION=%s", e.what())); 422 return IPMI_CC_UNSPECIFIED_ERROR; 423 } 424 } 425 } 426 else 427 { 428 log<level::DEBUG>("Do not change device power state"); 429 } 430 431 return rc; 432 } 433 434 /** 435 * @brief implements the get ACPI power state command 436 * 437 * @return IPMI completion code plus response data on success. 438 * - ACPI system power state 439 * - ACPI device power state 440 **/ 441 ipmi::RspType<uint8_t, // acpiSystemPowerState 442 uint8_t // acpiDevicePowerState 443 > 444 ipmiGetAcpiPowerState() 445 { 446 uint8_t sysAcpiState; 447 uint8_t devAcpiState; 448 449 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 450 451 try 452 { 453 auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface); 454 455 auto sysACPIVal = ipmi::getDbusProperty( 456 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface, 457 acpi_state::sysACPIProp); 458 auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString( 459 std::get<std::string>(sysACPIVal)); 460 sysAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI)); 461 462 auto devACPIVal = ipmi::getDbusProperty( 463 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface, 464 acpi_state::devACPIProp); 465 auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString( 466 std::get<std::string>(devACPIVal)); 467 devAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI)); 468 } 469 catch (const InternalFailure& e) 470 { 471 return ipmi::responseUnspecifiedError(); 472 } 473 474 return ipmi::responseSuccess(sysAcpiState, devAcpiState); 475 } 476 477 typedef struct 478 { 479 char major; 480 char minor; 481 uint16_t d[2]; 482 } Revision; 483 484 /* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */ 485 /* return -1 if not in those formats, this routine knows how to parse */ 486 /* version = v0.6-19-gf363f61-dirty */ 487 /* ^ ^ ^^ ^ */ 488 /* | | |----------|-- additional details */ 489 /* | |---------------- Minor */ 490 /* |------------------ Major */ 491 /* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */ 492 /* ^ ^ ^^ ^ */ 493 /* | | |--|---------- additional details */ 494 /* | |---------------- Minor */ 495 /* |------------------ Major */ 496 /* Additional details : If the option group exists it will force Auxiliary */ 497 /* Firmware Revision Information 4th byte to 1 indicating the build was */ 498 /* derived with additional edits */ 499 int convertVersion(std::string s, Revision& rev) 500 { 501 std::string token; 502 uint16_t commits; 503 504 auto location = s.find_first_of('v'); 505 if (location != std::string::npos) 506 { 507 s = s.substr(location + 1); 508 } 509 510 if (!s.empty()) 511 { 512 location = s.find_first_of("."); 513 if (location != std::string::npos) 514 { 515 rev.major = 516 static_cast<char>(std::stoi(s.substr(0, location), 0, 16)); 517 token = s.substr(location + 1); 518 } 519 520 if (!token.empty()) 521 { 522 location = token.find_first_of(".-"); 523 if (location != std::string::npos) 524 { 525 rev.minor = static_cast<char>( 526 std::stoi(token.substr(0, location), 0, 16)); 527 token = token.substr(location + 1); 528 } 529 } 530 531 // Capture the number of commits on top of the minor tag. 532 // I'm using BE format like the ipmi spec asked for 533 location = token.find_first_of(".-"); 534 if (!token.empty()) 535 { 536 commits = std::stoi(token.substr(0, location), 0, 16); 537 rev.d[0] = (commits >> 8) | (commits << 8); 538 539 // commit number we skip 540 location = token.find_first_of(".-"); 541 if (location != std::string::npos) 542 { 543 token = token.substr(location + 1); 544 } 545 } 546 else 547 { 548 rev.d[0] = 0; 549 } 550 551 if (location != std::string::npos) 552 { 553 token = token.substr(location + 1); 554 } 555 556 // Any value of the optional parameter forces it to 1 557 location = token.find_first_of(".-"); 558 if (location != std::string::npos) 559 { 560 token = token.substr(location + 1); 561 } 562 commits = (!token.empty()) ? 1 : 0; 563 564 // We do this operation to get this displayed in least significant bytes 565 // of ipmitool device id command. 566 rev.d[1] = (commits >> 8) | (commits << 8); 567 } 568 569 return 0; 570 } 571 572 auto ipmiAppGetDeviceId() -> ipmi::RspType<uint8_t, // Device ID 573 uint8_t, // Device Revision 574 uint8_t, // Firmware Revision Major 575 uint8_t, // Firmware Revision minor 576 uint8_t, // IPMI version 577 uint8_t, // Additional device support 578 uint24_t, // MFG ID 579 uint16_t, // Product ID 580 uint32_t // AUX info 581 > 582 { 583 int r = -1; 584 Revision rev = {0}; 585 static struct 586 { 587 uint8_t id; 588 uint8_t revision; 589 uint8_t fw[2]; 590 uint8_t ipmiVer; 591 uint8_t addnDevSupport; 592 uint24_t manufId; 593 uint16_t prodId; 594 uint32_t aux; 595 } devId; 596 static bool dev_id_initialized = false; 597 static bool defaultActivationSetting = true; 598 const char* filename = "/usr/share/ipmi-providers/dev_id.json"; 599 constexpr auto ipmiDevIdStateShift = 7; 600 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift); 601 602 if (!dev_id_initialized) 603 { 604 try 605 { 606 auto version = getActiveSoftwareVersionInfo(); 607 r = convertVersion(version, rev); 608 } 609 catch (const std::exception& e) 610 { 611 log<level::ERR>(e.what()); 612 } 613 614 if (r >= 0) 615 { 616 // bit7 identifies if the device is available 617 // 0=normal operation 618 // 1=device firmware, SDR update, 619 // or self-initialization in progress. 620 // The availability may change in run time, so mask here 621 // and initialize later. 622 devId.fw[0] = rev.major & ipmiDevIdFw1Mask; 623 624 rev.minor = (rev.minor > 99 ? 99 : rev.minor); 625 devId.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16; 626 std::memcpy(&devId.aux, rev.d, 4); 627 } 628 629 // IPMI Spec version 2.0 630 devId.ipmiVer = 2; 631 632 std::ifstream devIdFile(filename); 633 if (devIdFile.is_open()) 634 { 635 auto data = nlohmann::json::parse(devIdFile, nullptr, false); 636 if (!data.is_discarded()) 637 { 638 devId.id = data.value("id", 0); 639 devId.revision = data.value("revision", 0); 640 devId.addnDevSupport = data.value("addn_dev_support", 0); 641 devId.manufId = data.value("manuf_id", 0); 642 devId.prodId = data.value("prod_id", 0); 643 devId.aux = data.value("aux", 0); 644 645 // Set the availablitity of the BMC. 646 defaultActivationSetting = data.value("availability", true); 647 648 // Don't read the file every time if successful 649 dev_id_initialized = true; 650 } 651 else 652 { 653 log<level::ERR>("Device ID JSON parser failure"); 654 return ipmi::responseUnspecifiedError(); 655 } 656 } 657 else 658 { 659 log<level::ERR>("Device ID file not found"); 660 return ipmi::responseUnspecifiedError(); 661 } 662 } 663 664 // Set availability to the actual current BMC state 665 devId.fw[0] &= ipmiDevIdFw1Mask; 666 if (!getCurrentBmcStateWithFallback(defaultActivationSetting)) 667 { 668 devId.fw[0] |= (1 << ipmiDevIdStateShift); 669 } 670 671 return ipmi::responseSuccess( 672 devId.id, devId.revision, devId.fw[0], devId.fw[1], devId.ipmiVer, 673 devId.addnDevSupport, devId.manufId, devId.prodId, devId.aux); 674 } 675 676 auto ipmiAppGetSelfTestResults() -> ipmi::RspType<uint8_t, uint8_t> 677 { 678 // Byte 2: 679 // 55h - No error. 680 // 56h - Self Test function not implemented in this controller. 681 // 57h - Corrupted or inaccesssible data or devices. 682 // 58h - Fatal hardware error. 683 // FFh - reserved. 684 // all other: Device-specific 'internal failure'. 685 // Byte 3: 686 // For byte 2 = 55h, 56h, FFh: 00h 687 // For byte 2 = 58h, all other: Device-specific 688 // For byte 2 = 57h: self-test error bitfield. 689 // Note: returning 57h does not imply that all test were run. 690 // [7] 1b = Cannot access SEL device. 691 // [6] 1b = Cannot access SDR Repository. 692 // [5] 1b = Cannot access BMC FRU device. 693 // [4] 1b = IPMB signal lines do not respond. 694 // [3] 1b = SDR Repository empty. 695 // [2] 1b = Internal Use Area of BMC FRU corrupted. 696 // [1] 1b = controller update 'boot block' firmware corrupted. 697 // [0] 1b = controller operational firmware corrupted. 698 constexpr uint8_t notImplemented = 0x56; 699 constexpr uint8_t zero = 0; 700 return ipmi::responseSuccess(notImplemented, zero); 701 } 702 703 static constexpr size_t uuidBinaryLength = 16; 704 static std::array<uint8_t, uuidBinaryLength> rfc4122ToIpmi(std::string rfc4122) 705 { 706 using Argument = xyz::openbmc_project::Common::InvalidArgument; 707 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 708 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte 709 // order 710 // Ex: 0x2332fc2c40e66298e511f2782395a361 711 constexpr size_t uuidHexLength = (2 * uuidBinaryLength); 712 constexpr size_t uuidRfc4122Length = (uuidHexLength + 4); 713 std::array<uint8_t, uuidBinaryLength> uuid; 714 if (rfc4122.size() == uuidRfc4122Length) 715 { 716 rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'), 717 rfc4122.end()); 718 } 719 if (rfc4122.size() != uuidHexLength) 720 { 721 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 722 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 723 } 724 for (size_t ind = 0; ind < uuidHexLength; ind += 2) 725 { 726 char v[3]; 727 v[0] = rfc4122[ind]; 728 v[1] = rfc4122[ind + 1]; 729 v[2] = 0; 730 size_t err; 731 long b; 732 try 733 { 734 b = std::stoul(v, &err, 16); 735 } 736 catch (std::exception& e) 737 { 738 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 739 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 740 } 741 // check that exactly two ascii bytes were converted 742 if (err != 2) 743 { 744 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 745 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 746 } 747 uuid[uuidBinaryLength - (ind / 2) - 1] = static_cast<uint8_t>(b); 748 } 749 return uuid; 750 } 751 752 auto ipmiAppGetDeviceGuid() 753 -> ipmi::RspType<std::array<uint8_t, uuidBinaryLength>> 754 { 755 // return a fixed GUID based on /etc/machine-id 756 // This should match the /redfish/v1/Managers/bmc's UUID data 757 758 // machine specific application ID (for BMC ID) 759 // generated by systemd-id128 -p new as per man page 760 static constexpr sd_id128_t bmcUuidAppId = SD_ID128_MAKE( 761 e0, e1, 73, 76, 64, 61, 47, da, a5, 0c, d0, cc, 64, 12, 45, 78); 762 763 sd_id128_t bmcUuid; 764 // create the UUID from /etc/machine-id via the systemd API 765 sd_id128_get_machine_app_specific(bmcUuidAppId, &bmcUuid); 766 767 char bmcUuidCstr[SD_ID128_STRING_MAX]; 768 std::string systemUuid = sd_id128_to_string(bmcUuid, bmcUuidCstr); 769 770 std::array<uint8_t, uuidBinaryLength> uuid = rfc4122ToIpmi(systemUuid); 771 return ipmi::responseSuccess(uuid); 772 } 773 774 auto ipmiAppGetBtCapabilities() 775 -> ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t> 776 { 777 // Per IPMI 2.0 spec, the input and output buffer size must be the max 778 // buffer size minus one byte to allocate space for the length byte. 779 constexpr uint8_t nrOutstanding = 0x01; 780 constexpr uint8_t inputBufferSize = MAX_IPMI_BUFFER - 1; 781 constexpr uint8_t outputBufferSize = MAX_IPMI_BUFFER - 1; 782 constexpr uint8_t transactionTime = 0x0A; 783 constexpr uint8_t nrRetries = 0x01; 784 785 return ipmi::responseSuccess(nrOutstanding, inputBufferSize, 786 outputBufferSize, transactionTime, nrRetries); 787 } 788 789 ipmi_ret_t ipmi_app_get_sys_guid(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 790 ipmi_request_t request, 791 ipmi_response_t response, 792 ipmi_data_len_t data_len, 793 ipmi_context_t context) 794 795 { 796 ipmi_ret_t rc = IPMI_CC_OK; 797 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 798 799 try 800 { 801 // Get the Inventory object implementing BMC interface 802 ipmi::DbusObjectInfo bmcObject = 803 ipmi::getDbusObject(bus, bmc_interface); 804 805 // Read UUID property value from bmcObject 806 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 807 auto variant = 808 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first, 809 bmc_guid_interface, bmc_guid_property); 810 std::string guidProp = std::get<std::string>(variant); 811 812 // Erase "-" characters from the property value 813 guidProp.erase(std::remove(guidProp.begin(), guidProp.end(), '-'), 814 guidProp.end()); 815 816 auto guidPropLen = guidProp.length(); 817 // Validate UUID data 818 // Divide by 2 as 1 byte is built from 2 chars 819 if ((guidPropLen <= 0) || ((guidPropLen / 2) != bmc_guid_len)) 820 821 { 822 log<level::ERR>("Invalid UUID property value", 823 entry("UUID_LENGTH=%d", guidPropLen)); 824 return IPMI_CC_RESPONSE_ERROR; 825 } 826 827 // Convert data in RFC4122(MSB) format to LSB format 828 // Get 2 characters at a time as 1 byte is built from 2 chars and 829 // convert to hex byte 830 // TODO: Data printed for GUID command is not as per the 831 // GUID format defined in IPMI specification 2.0 section 20.8 832 // Ticket raised: https://sourceforge.net/p/ipmitool/bugs/501/ 833 uint8_t respGuid[bmc_guid_len]; 834 for (size_t i = 0, respLoc = (bmc_guid_len - 1); 835 i < guidPropLen && respLoc >= 0; i += 2, respLoc--) 836 { 837 auto value = static_cast<uint8_t>( 838 std::stoi(guidProp.substr(i, 2).c_str(), NULL, 16)); 839 respGuid[respLoc] = value; 840 } 841 842 *data_len = bmc_guid_len; 843 std::memcpy(response, &respGuid, bmc_guid_len); 844 } 845 catch (const InternalFailure& e) 846 { 847 log<level::ERR>("Failed in reading BMC UUID property", 848 entry("INTERFACE=%s", bmc_interface), 849 entry("PROPERTY_INTERFACE=%s", bmc_guid_interface), 850 entry("PROPERTY=%s", bmc_guid_property)); 851 return IPMI_CC_UNSPECIFIED_ERROR; 852 } 853 return rc; 854 } 855 856 static std::unique_ptr<SysInfoParamStore> sysInfoParamStore; 857 858 static std::string sysInfoReadSystemName() 859 { 860 // Use the BMC hostname as the "System Name." 861 char hostname[HOST_NAME_MAX + 1] = {}; 862 if (gethostname(hostname, HOST_NAME_MAX) != 0) 863 { 864 perror("System info parameter: system name"); 865 } 866 return hostname; 867 } 868 869 struct IpmiSysInfoResp 870 { 871 uint8_t paramRevision; 872 uint8_t setSelector; 873 union 874 { 875 struct 876 { 877 uint8_t encoding; 878 uint8_t stringLen; 879 uint8_t stringData0[14]; 880 } __attribute__((packed)); 881 uint8_t stringDataN[16]; 882 uint8_t byteData; 883 }; 884 } __attribute__((packed)); 885 886 /** 887 * Split a string into (up to) 16-byte chunks as expected in response for get 888 * system info parameter. 889 * 890 * @param[in] fullString: Input string to be split 891 * @param[in] chunkIndex: Index of the chunk to be written out 892 * @param[in,out] chunk: Output data buffer; must have 14 byte capacity if 893 * chunk_index = 0 and 16-byte capacity otherwise 894 * @return the number of bytes written into the output buffer, or -EINVAL for 895 * invalid arguments. 896 */ 897 static int splitStringParam(const std::string& fullString, int chunkIndex, 898 uint8_t* chunk) 899 { 900 constexpr int maxChunk = 255; 901 constexpr int smallChunk = 14; 902 constexpr int chunkSize = 16; 903 if (chunkIndex > maxChunk || chunk == nullptr) 904 { 905 return -EINVAL; 906 } 907 try 908 { 909 std::string output; 910 if (chunkIndex == 0) 911 { 912 // Output must have 14 byte capacity. 913 output = fullString.substr(0, smallChunk); 914 } 915 else 916 { 917 // Output must have 16 byte capacity. 918 output = fullString.substr((chunkIndex * chunkSize) - 2, chunkSize); 919 } 920 921 std::memcpy(chunk, output.c_str(), output.length()); 922 return output.length(); 923 } 924 catch (const std::out_of_range& e) 925 { 926 // The position was beyond the end. 927 return -EINVAL; 928 } 929 } 930 931 /** 932 * Packs the Get Sys Info Request Item into the response. 933 * 934 * @param[in] paramString - the parameter. 935 * @param[in] setSelector - the selector 936 * @param[in,out] resp - the System info response. 937 * @return The number of bytes packed or failure from splitStringParam(). 938 */ 939 static int packGetSysInfoResp(const std::string& paramString, 940 uint8_t setSelector, IpmiSysInfoResp* resp) 941 { 942 uint8_t* dataBuffer = resp->stringDataN; 943 resp->setSelector = setSelector; 944 if (resp->setSelector == 0) // First chunk has only 14 bytes. 945 { 946 resp->encoding = 0; 947 resp->stringLen = paramString.length(); 948 dataBuffer = resp->stringData0; 949 } 950 return splitStringParam(paramString, resp->setSelector, dataBuffer); 951 } 952 953 ipmi_ret_t ipmi_app_get_system_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 954 ipmi_request_t request, 955 ipmi_response_t response, 956 ipmi_data_len_t dataLen, 957 ipmi_context_t context) 958 { 959 IpmiSysInfoResp resp = {}; 960 size_t respLen = 0; 961 uint8_t* const reqData = static_cast<uint8_t*>(request); 962 std::string paramString; 963 bool found; 964 std::tuple<bool, std::string> ret; 965 constexpr int minRequestSize = 4; 966 constexpr int paramSelector = 1; 967 constexpr uint8_t revisionOnly = 0x80; 968 const uint8_t paramRequested = reqData[paramSelector]; 969 int rc; 970 971 if (*dataLen < minRequestSize) 972 { 973 return IPMI_CC_REQ_DATA_LEN_INVALID; 974 } 975 976 *dataLen = 0; // default to 0. 977 978 // Parameters revision as of IPMI spec v2.0 rev. 1.1 (Feb 11, 2014 E6) 979 resp.paramRevision = 0x11; 980 if (reqData[0] & revisionOnly) // Get parameter revision only 981 { 982 respLen = 1; 983 goto writeResponse; 984 } 985 986 // The "Set In Progress" parameter can be used for rollback of parameter 987 // data and is not implemented. 988 if (paramRequested == 0) 989 { 990 resp.byteData = 0; 991 respLen = 2; 992 goto writeResponse; 993 } 994 995 if (sysInfoParamStore == nullptr) 996 { 997 sysInfoParamStore = std::make_unique<SysInfoParamStore>(); 998 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME, 999 sysInfoReadSystemName); 1000 } 1001 1002 // Parameters other than Set In Progress are assumed to be strings. 1003 ret = sysInfoParamStore->lookup(paramRequested); 1004 found = std::get<0>(ret); 1005 paramString = std::get<1>(ret); 1006 if (!found) 1007 { 1008 return IPMI_CC_SYSTEM_INFO_PARAMETER_NOT_SUPPORTED; 1009 } 1010 // TODO: Cache each parameter across multiple calls, until the whole string 1011 // has been read out. Otherwise, it's possible for a parameter to change 1012 // between requests for its chunks, returning chunks incoherent with each 1013 // other. For now, the parameter store is simply required to have only 1014 // idempotent callbacks. 1015 rc = packGetSysInfoResp(paramString, reqData[2], &resp); 1016 if (rc == -EINVAL) 1017 { 1018 return IPMI_CC_RESPONSE_ERROR; 1019 } 1020 1021 respLen = sizeof(resp); // Write entire string data chunk in response. 1022 1023 writeResponse: 1024 std::memcpy(response, &resp, sizeof(resp)); 1025 *dataLen = respLen; 1026 return IPMI_CC_OK; 1027 } 1028 1029 inline std::vector<uint8_t> convertStringToData(const std::string& command) 1030 { 1031 std::istringstream iss(command); 1032 std::string token; 1033 std::vector<uint8_t> dataValue; 1034 while (std::getline(iss, token, ' ')) 1035 { 1036 dataValue.emplace_back( 1037 static_cast<uint8_t>(std::stoul(token, nullptr, base_16))); 1038 } 1039 return dataValue; 1040 } 1041 1042 static bool populateI2CMasterWRWhitelist() 1043 { 1044 nlohmann::json data = nullptr; 1045 std::ifstream jsonFile(i2cMasterWRWhitelistFile); 1046 1047 if (!jsonFile.good()) 1048 { 1049 log<level::WARNING>("i2c white list file not found!", 1050 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile)); 1051 return false; 1052 } 1053 1054 try 1055 { 1056 data = nlohmann::json::parse(jsonFile, nullptr, false); 1057 } 1058 catch (nlohmann::json::parse_error& e) 1059 { 1060 log<level::ERR>("Corrupted i2c white list config file", 1061 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile), 1062 entry("MSG: %s", e.what())); 1063 return false; 1064 } 1065 1066 try 1067 { 1068 // Example JSON Structure format 1069 // "filters": [ 1070 // { 1071 // "Description": "Allow full read - ignore first byte write value 1072 // for 0x40 to 0x4F", 1073 // "busId": "0x01", 1074 // "slaveAddr": "0x40", 1075 // "slaveAddrMask": "0x0F", 1076 // "command": "0x00", 1077 // "commandMask": "0xFF" 1078 // }, 1079 // { 1080 // "Description": "Allow full read - first byte match 0x05 and 1081 // ignore second byte", 1082 // "busId": "0x01", 1083 // "slaveAddr": "0x57", 1084 // "slaveAddrMask": "0x00", 1085 // "command": "0x05 0x00", 1086 // "commandMask": "0x00 0xFF" 1087 // },] 1088 1089 nlohmann::json filters = data[filtersStr].get<nlohmann::json>(); 1090 std::vector<i2cMasterWRWhitelist>& whitelist = getWRWhitelist(); 1091 for (const auto& it : filters.items()) 1092 { 1093 nlohmann::json filter = it.value(); 1094 if (filter.is_null()) 1095 { 1096 log<level::ERR>( 1097 "Corrupted I2C master write read whitelist config file", 1098 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile)); 1099 return false; 1100 } 1101 const std::vector<uint8_t>& writeData = 1102 convertStringToData(filter[cmdStr].get<std::string>()); 1103 const std::vector<uint8_t>& writeDataMask = 1104 convertStringToData(filter[cmdMaskStr].get<std::string>()); 1105 if (writeDataMask.size() != writeData.size()) 1106 { 1107 log<level::ERR>("I2C master write read whitelist filter " 1108 "mismatch for command & mask size"); 1109 return false; 1110 } 1111 whitelist.push_back( 1112 {static_cast<uint8_t>(std::stoul( 1113 filter[busIdStr].get<std::string>(), nullptr, base_16)), 1114 static_cast<uint8_t>( 1115 std::stoul(filter[slaveAddrStr].get<std::string>(), 1116 nullptr, base_16)), 1117 static_cast<uint8_t>( 1118 std::stoul(filter[slaveAddrMaskStr].get<std::string>(), 1119 nullptr, base_16)), 1120 writeData, writeDataMask}); 1121 } 1122 if (whitelist.size() != filters.size()) 1123 { 1124 log<level::ERR>( 1125 "I2C master write read whitelist filter size mismatch"); 1126 return false; 1127 } 1128 } 1129 catch (std::exception& e) 1130 { 1131 log<level::ERR>("I2C master write read whitelist unexpected exception", 1132 entry("ERROR=%s", e.what())); 1133 return false; 1134 } 1135 return true; 1136 } 1137 1138 static inline bool isWriteDataWhitelisted(const std::vector<uint8_t>& data, 1139 const std::vector<uint8_t>& dataMask, 1140 const std::vector<uint8_t>& writeData) 1141 { 1142 std::vector<uint8_t> processedDataBuf(data.size()); 1143 std::vector<uint8_t> processedReqBuf(dataMask.size()); 1144 std::transform(writeData.begin(), writeData.end(), dataMask.begin(), 1145 processedReqBuf.begin(), std::bit_or<uint8_t>()); 1146 std::transform(data.begin(), data.end(), dataMask.begin(), 1147 processedDataBuf.begin(), std::bit_or<uint8_t>()); 1148 1149 return (processedDataBuf == processedReqBuf); 1150 } 1151 1152 static bool isCmdWhitelisted(uint8_t busId, uint8_t slaveAddr, 1153 std::vector<uint8_t>& writeData) 1154 { 1155 std::vector<i2cMasterWRWhitelist>& whiteList = getWRWhitelist(); 1156 for (const auto& wlEntry : whiteList) 1157 { 1158 if ((busId == wlEntry.busId) && 1159 ((slaveAddr | wlEntry.slaveAddrMask) == 1160 (wlEntry.slaveAddr | wlEntry.slaveAddrMask))) 1161 { 1162 const std::vector<uint8_t>& dataMask = wlEntry.dataMask; 1163 // Skip as no-match, if requested write data is more than the 1164 // write data mask size 1165 if (writeData.size() > dataMask.size()) 1166 { 1167 continue; 1168 } 1169 if (isWriteDataWhitelisted(wlEntry.data, dataMask, writeData)) 1170 { 1171 return true; 1172 } 1173 } 1174 } 1175 return false; 1176 } 1177 1178 /** @brief implements master write read IPMI command which can be used for 1179 * low-level I2C/SMBus write, read or write-read access 1180 * @param isPrivateBus -to indicate private bus usage 1181 * @param busId - bus id 1182 * @param channelNum - channel number 1183 * @param reserved - skip 1 bit 1184 * @param slaveAddr - slave address 1185 * @param read count - number of bytes to be read 1186 * @param writeData - data to be written 1187 * 1188 * @returns IPMI completion code plus response data 1189 * - readData - i2c response data 1190 */ 1191 ipmi::RspType<std::vector<uint8_t>> 1192 ipmiMasterWriteRead(bool isPrivateBus, uint3_t busId, uint4_t channelNum, 1193 bool reserved, uint7_t slaveAddr, uint8_t readCount, 1194 std::vector<uint8_t> writeData) 1195 { 1196 i2c_rdwr_ioctl_data msgReadWrite = {0}; 1197 i2c_msg i2cmsg[2] = {0}; 1198 1199 if (readCount > maxIPMIWriteReadSize) 1200 { 1201 log<level::ERR>("Master write read command: Read count exceeds limit"); 1202 return ipmi::responseParmOutOfRange(); 1203 } 1204 const size_t writeCount = writeData.size(); 1205 if (!readCount && !writeCount) 1206 { 1207 log<level::ERR>("Master write read command: Read & write count are 0"); 1208 return ipmi::responseInvalidFieldRequest(); 1209 } 1210 if (!isCmdWhitelisted(static_cast<uint8_t>(busId), 1211 static_cast<uint8_t>(slaveAddr), writeData)) 1212 { 1213 log<level::ERR>("Master write read request blocked!", 1214 entry("BUS=%d", static_cast<uint8_t>(busId)), 1215 entry("ADDR=0x%x", static_cast<uint8_t>(slaveAddr))); 1216 return ipmi::responseInvalidFieldRequest(); 1217 } 1218 std::vector<uint8_t> readBuf(readCount); 1219 std::string i2cBus = 1220 "/dev/i2c-" + std::to_string(static_cast<uint8_t>(busId)); 1221 1222 int i2cDev = ::open(i2cBus.c_str(), O_RDWR | O_CLOEXEC); 1223 if (i2cDev < 0) 1224 { 1225 log<level::ERR>("Failed to open i2c bus", 1226 entry("BUS=%s", i2cBus.c_str())); 1227 return ipmi::responseInvalidFieldRequest(); 1228 } 1229 1230 int msgCount = 0; 1231 if (writeCount) 1232 { 1233 i2cmsg[msgCount].addr = static_cast<uint8_t>(slaveAddr); 1234 i2cmsg[msgCount].flags = 0x00; 1235 i2cmsg[msgCount].len = writeCount; 1236 i2cmsg[msgCount].buf = writeData.data(); 1237 msgCount++; 1238 } 1239 if (readCount) 1240 { 1241 i2cmsg[msgCount].addr = static_cast<uint8_t>(slaveAddr); 1242 i2cmsg[msgCount].flags = I2C_M_RD; 1243 i2cmsg[msgCount].len = readCount; 1244 i2cmsg[msgCount].buf = readBuf.data(); 1245 msgCount++; 1246 } 1247 1248 msgReadWrite.msgs = i2cmsg; 1249 msgReadWrite.nmsgs = msgCount; 1250 1251 int ret = ::ioctl(i2cDev, I2C_RDWR, &msgReadWrite); 1252 ::close(i2cDev); 1253 1254 if (ret < 0) 1255 { 1256 log<level::ERR>("Master write read: Failed", entry("RET=%d", ret)); 1257 return ipmi::responseUnspecifiedError(); 1258 } 1259 if (readCount) 1260 { 1261 readBuf.resize(msgReadWrite.msgs[msgCount - 1].len); 1262 } 1263 return ipmi::responseSuccess(readBuf); 1264 } 1265 1266 void register_netfn_app_functions() 1267 { 1268 // <Get Device ID> 1269 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1270 ipmi::app::cmdGetDeviceId, ipmi::Privilege::User, 1271 ipmiAppGetDeviceId); 1272 1273 // <Get BT Interface Capabilities> 1274 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1275 ipmi::app::cmdGetBtIfaceCapabilities, 1276 ipmi::Privilege::User, ipmiAppGetBtCapabilities); 1277 1278 // <Reset Watchdog Timer> 1279 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1280 ipmi::app::cmdResetWatchdogTimer, 1281 ipmi::Privilege::Operator, ipmiAppResetWatchdogTimer); 1282 1283 // <Set Watchdog Timer> 1284 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_WD, NULL, 1285 ipmi_app_watchdog_set, PRIVILEGE_OPERATOR); 1286 1287 // <Get Watchdog Timer> 1288 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_WD, NULL, 1289 ipmi_app_watchdog_get, PRIVILEGE_OPERATOR); 1290 1291 // <Get Self Test Results> 1292 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1293 ipmi::app::cmdGetSelfTestResults, 1294 ipmi::Privilege::User, ipmiAppGetSelfTestResults); 1295 1296 // <Get Device GUID> 1297 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1298 ipmi::app::cmdGetDeviceGuid, ipmi::Privilege::User, 1299 ipmiAppGetDeviceGuid); 1300 1301 // <Set ACPI Power State> 1302 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL, 1303 ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN); 1304 1305 // <Get ACPI Power State> 1306 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1307 ipmi::app::cmdGetAcpiPowerState, 1308 ipmi::Privilege::Admin, ipmiGetAcpiPowerState); 1309 1310 // Note: For security reason, this command will be registered only when 1311 // there are proper I2C Master write read whitelist 1312 if (populateI2CMasterWRWhitelist()) 1313 { 1314 // Note: For security reasons, registering master write read as admin 1315 // privilege command, even though IPMI 2.0 specification allows it as 1316 // operator privilege. 1317 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1318 ipmi::app::cmdMasterWriteRead, 1319 ipmi::Privilege::Admin, ipmiMasterWriteRead); 1320 } 1321 1322 // <Get System GUID Command> 1323 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYS_GUID, NULL, 1324 ipmi_app_get_sys_guid, PRIVILEGE_USER); 1325 1326 // <Get Channel Cipher Suites Command> 1327 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_CIPHER_SUITES, NULL, 1328 getChannelCipherSuites, PRIVILEGE_CALLBACK); 1329 1330 // <Get System Info Command> 1331 ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_SYSTEM_INFO, NULL, 1332 ipmi_app_get_system_info, PRIVILEGE_USER); 1333 return; 1334 } 1335