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/sessiondef.hpp> 24 #include <ipmid/sessionhelper.hpp> 25 #include <ipmid/types.hpp> 26 #include <ipmid/utils.hpp> 27 #include <memory> 28 #include <nlohmann/json.hpp> 29 #include <phosphor-logging/elog-errors.hpp> 30 #include <phosphor-logging/log.hpp> 31 #include <sdbusplus/message/types.hpp> 32 #include <string> 33 #include <sys_info_param.hpp> 34 #include <tuple> 35 #include <vector> 36 #include <xyz/openbmc_project/Common/error.hpp> 37 #include <xyz/openbmc_project/Control/Power/ACPIPowerState/server.hpp> 38 #include <xyz/openbmc_project/Software/Activation/server.hpp> 39 #include <xyz/openbmc_project/Software/Version/server.hpp> 40 #include <xyz/openbmc_project/State/BMC/server.hpp> 41 42 extern sd_bus* bus; 43 44 constexpr auto bmc_state_interface = "xyz.openbmc_project.State.BMC"; 45 constexpr auto bmc_state_property = "CurrentBMCState"; 46 47 static constexpr auto redundancyIntf = 48 "xyz.openbmc_project.Software.RedundancyPriority"; 49 static constexpr auto versionIntf = "xyz.openbmc_project.Software.Version"; 50 static constexpr auto activationIntf = 51 "xyz.openbmc_project.Software.Activation"; 52 static constexpr auto softwareRoot = "/xyz/openbmc_project/software"; 53 54 void register_netfn_app_functions() __attribute__((constructor)); 55 56 using namespace phosphor::logging; 57 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 58 using Version = sdbusplus::xyz::openbmc_project::Software::server::Version; 59 using Activation = 60 sdbusplus::xyz::openbmc_project::Software::server::Activation; 61 using BMC = sdbusplus::xyz::openbmc_project::State::server::BMC; 62 namespace fs = std::filesystem; 63 64 #ifdef ENABLE_I2C_WHITELIST_CHECK 65 typedef struct 66 { 67 uint8_t busId; 68 uint8_t slaveAddr; 69 uint8_t slaveAddrMask; 70 std::vector<uint8_t> data; 71 std::vector<uint8_t> dataMask; 72 } i2cMasterWRWhitelist; 73 74 static std::vector<i2cMasterWRWhitelist>& getWRWhitelist() 75 { 76 static std::vector<i2cMasterWRWhitelist> wrWhitelist; 77 return wrWhitelist; 78 } 79 80 static constexpr const char* i2cMasterWRWhitelistFile = 81 "/usr/share/ipmi-providers/master_write_read_white_list.json"; 82 83 static constexpr const char* filtersStr = "filters"; 84 static constexpr const char* busIdStr = "busId"; 85 static constexpr const char* slaveAddrStr = "slaveAddr"; 86 static constexpr const char* slaveAddrMaskStr = "slaveAddrMask"; 87 static constexpr const char* cmdStr = "command"; 88 static constexpr const char* cmdMaskStr = "commandMask"; 89 static constexpr int base_16 = 16; 90 #endif // ENABLE_I2C_WHITELIST_CHECK 91 static constexpr uint8_t maxIPMIWriteReadSize = 144; 92 93 /** 94 * @brief Returns the Version info from primary s/w object 95 * 96 * Get the Version info from the active s/w object which is having high 97 * "Priority" value(a smaller number is a higher priority) and "Purpose" 98 * is "BMC" from the list of all s/w objects those are implementing 99 * RedundancyPriority interface from the given softwareRoot path. 100 * 101 * @return On success returns the Version info from primary s/w object. 102 * 103 */ 104 std::string getActiveSoftwareVersionInfo(ipmi::Context::ptr ctx) 105 { 106 std::string revision{}; 107 ipmi::ObjectTree objectTree; 108 try 109 { 110 objectTree = 111 ipmi::getAllDbusObjects(*ctx->bus, softwareRoot, redundancyIntf); 112 } 113 catch (sdbusplus::exception::SdBusError& e) 114 { 115 log<level::ERR>("Failed to fetch redundancy object from dbus", 116 entry("INTERFACE=%s", redundancyIntf), 117 entry("ERRMSG=%s", e.what())); 118 elog<InternalFailure>(); 119 } 120 121 auto objectFound = false; 122 for (auto& softObject : objectTree) 123 { 124 auto service = 125 ipmi::getService(*ctx->bus, redundancyIntf, softObject.first); 126 auto objValueTree = 127 ipmi::getManagedObjects(*ctx->bus, service, softwareRoot); 128 129 auto minPriority = 0xFF; 130 for (const auto& objIter : objValueTree) 131 { 132 try 133 { 134 auto& intfMap = objIter.second; 135 auto& redundancyPriorityProps = intfMap.at(redundancyIntf); 136 auto& versionProps = intfMap.at(versionIntf); 137 auto& activationProps = intfMap.at(activationIntf); 138 auto priority = 139 std::get<uint8_t>(redundancyPriorityProps.at("Priority")); 140 auto purpose = 141 std::get<std::string>(versionProps.at("Purpose")); 142 auto activation = 143 std::get<std::string>(activationProps.at("Activation")); 144 auto version = 145 std::get<std::string>(versionProps.at("Version")); 146 if ((Version::convertVersionPurposeFromString(purpose) == 147 Version::VersionPurpose::BMC) && 148 (Activation::convertActivationsFromString(activation) == 149 Activation::Activations::Active)) 150 { 151 if (priority < minPriority) 152 { 153 minPriority = priority; 154 objectFound = true; 155 revision = std::move(version); 156 } 157 } 158 } 159 catch (const std::exception& e) 160 { 161 log<level::ERR>(e.what()); 162 } 163 } 164 } 165 166 if (!objectFound) 167 { 168 log<level::ERR>("Could not found an BMC software Object"); 169 elog<InternalFailure>(); 170 } 171 172 return revision; 173 } 174 175 bool getCurrentBmcState() 176 { 177 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 178 179 // Get the Inventory object implementing the BMC interface 180 ipmi::DbusObjectInfo bmcObject = 181 ipmi::getDbusObject(bus, bmc_state_interface); 182 auto variant = 183 ipmi::getDbusProperty(bus, bmcObject.second, bmcObject.first, 184 bmc_state_interface, bmc_state_property); 185 186 return std::holds_alternative<std::string>(variant) && 187 BMC::convertBMCStateFromString(std::get<std::string>(variant)) == 188 BMC::BMCState::Ready; 189 } 190 191 bool getCurrentBmcStateWithFallback(const bool fallbackAvailability) 192 { 193 try 194 { 195 return getCurrentBmcState(); 196 } 197 catch (...) 198 { 199 // Nothing provided the BMC interface, therefore return whatever was 200 // configured as the default. 201 return fallbackAvailability; 202 } 203 } 204 205 namespace acpi_state 206 { 207 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server; 208 209 const static constexpr char* acpiObjPath = 210 "/xyz/openbmc_project/control/host0/acpi_power_state"; 211 const static constexpr char* acpiInterface = 212 "xyz.openbmc_project.Control.Power.ACPIPowerState"; 213 const static constexpr char* sysACPIProp = "SysACPIStatus"; 214 const static constexpr char* devACPIProp = "DevACPIStatus"; 215 216 enum class PowerStateType : uint8_t 217 { 218 sysPowerState = 0x00, 219 devPowerState = 0x01, 220 }; 221 222 // Defined in 20.6 of ipmi doc 223 enum class PowerState : uint8_t 224 { 225 s0G0D0 = 0x00, 226 s1D1 = 0x01, 227 s2D2 = 0x02, 228 s3D3 = 0x03, 229 s4 = 0x04, 230 s5G2 = 0x05, 231 s4S5 = 0x06, 232 g3 = 0x07, 233 sleep = 0x08, 234 g1Sleep = 0x09, 235 override = 0x0a, 236 legacyOn = 0x20, 237 legacyOff = 0x21, 238 unknown = 0x2a, 239 noChange = 0x7f, 240 }; 241 242 static constexpr uint8_t stateChanged = 0x80; 243 244 struct ACPIState 245 { 246 uint8_t sysACPIState; 247 uint8_t devACPIState; 248 } __attribute__((packed)); 249 250 std::map<ACPIPowerState::ACPI, PowerState> dbusToIPMI = { 251 {ACPIPowerState::ACPI::S0_G0_D0, PowerState::s0G0D0}, 252 {ACPIPowerState::ACPI::S1_D1, PowerState::s1D1}, 253 {ACPIPowerState::ACPI::S2_D2, PowerState::s2D2}, 254 {ACPIPowerState::ACPI::S3_D3, PowerState::s3D3}, 255 {ACPIPowerState::ACPI::S4, PowerState::s4}, 256 {ACPIPowerState::ACPI::S5_G2, PowerState::s5G2}, 257 {ACPIPowerState::ACPI::S4_S5, PowerState::s4S5}, 258 {ACPIPowerState::ACPI::G3, PowerState::g3}, 259 {ACPIPowerState::ACPI::SLEEP, PowerState::sleep}, 260 {ACPIPowerState::ACPI::G1_SLEEP, PowerState::g1Sleep}, 261 {ACPIPowerState::ACPI::OVERRIDE, PowerState::override}, 262 {ACPIPowerState::ACPI::LEGACY_ON, PowerState::legacyOn}, 263 {ACPIPowerState::ACPI::LEGACY_OFF, PowerState::legacyOff}, 264 {ACPIPowerState::ACPI::Unknown, PowerState::unknown}}; 265 266 bool isValidACPIState(acpi_state::PowerStateType type, uint8_t state) 267 { 268 if (type == acpi_state::PowerStateType::sysPowerState) 269 { 270 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::override)) || 271 (state == static_cast<uint8_t>(acpi_state::PowerState::legacyOn)) || 272 (state == 273 static_cast<uint8_t>(acpi_state::PowerState::legacyOff)) || 274 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) || 275 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange))) 276 { 277 return true; 278 } 279 else 280 { 281 return false; 282 } 283 } 284 else if (type == acpi_state::PowerStateType::devPowerState) 285 { 286 if ((state <= static_cast<uint8_t>(acpi_state::PowerState::s3D3)) || 287 (state == static_cast<uint8_t>(acpi_state::PowerState::unknown)) || 288 (state == static_cast<uint8_t>(acpi_state::PowerState::noChange))) 289 { 290 return true; 291 } 292 else 293 { 294 return false; 295 } 296 } 297 else 298 { 299 return false; 300 } 301 return false; 302 } 303 } // namespace acpi_state 304 305 ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 306 ipmi_request_t request, 307 ipmi_response_t response, 308 ipmi_data_len_t data_len, 309 ipmi_context_t context) 310 { 311 auto s = static_cast<uint8_t>(acpi_state::PowerState::unknown); 312 ipmi_ret_t rc = IPMI_CC_OK; 313 314 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 315 316 auto value = acpi_state::ACPIPowerState::ACPI::Unknown; 317 318 auto* req = reinterpret_cast<acpi_state::ACPIState*>(request); 319 320 if (*data_len != sizeof(acpi_state::ACPIState)) 321 { 322 log<level::ERR>("set_acpi invalid len"); 323 *data_len = 0; 324 return IPMI_CC_REQ_DATA_LEN_INVALID; 325 } 326 327 *data_len = 0; 328 329 if (req->sysACPIState & acpi_state::stateChanged) 330 { 331 // set system power state 332 s = req->sysACPIState & ~acpi_state::stateChanged; 333 334 if (!acpi_state::isValidACPIState( 335 acpi_state::PowerStateType::sysPowerState, s)) 336 { 337 log<level::ERR>("set_acpi_power sys invalid input", 338 entry("S=%x", s)); 339 return IPMI_CC_PARM_OUT_OF_RANGE; 340 } 341 342 // valid input 343 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange)) 344 { 345 log<level::DEBUG>("No change for system power state"); 346 } 347 else 348 { 349 auto found = std::find_if( 350 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(), 351 [&s](const auto& iter) { 352 return (static_cast<uint8_t>(iter.second) == s); 353 }); 354 355 value = found->first; 356 357 try 358 { 359 auto acpiObject = 360 ipmi::getDbusObject(bus, acpi_state::acpiInterface); 361 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first, 362 acpi_state::acpiInterface, 363 acpi_state::sysACPIProp, 364 convertForMessage(value)); 365 } 366 catch (const InternalFailure& e) 367 { 368 log<level::ERR>("Failed in set ACPI system property", 369 entry("EXCEPTION=%s", e.what())); 370 return IPMI_CC_UNSPECIFIED_ERROR; 371 } 372 } 373 } 374 else 375 { 376 log<level::DEBUG>("Do not change system power state"); 377 } 378 379 if (req->devACPIState & acpi_state::stateChanged) 380 { 381 // set device power state 382 s = req->devACPIState & ~acpi_state::stateChanged; 383 if (!acpi_state::isValidACPIState( 384 acpi_state::PowerStateType::devPowerState, s)) 385 { 386 log<level::ERR>("set_acpi_power dev invalid input", 387 entry("S=%x", s)); 388 return IPMI_CC_PARM_OUT_OF_RANGE; 389 } 390 391 // valid input 392 if (s == static_cast<uint8_t>(acpi_state::PowerState::noChange)) 393 { 394 log<level::DEBUG>("No change for device power state"); 395 } 396 else 397 { 398 auto found = std::find_if( 399 acpi_state::dbusToIPMI.begin(), acpi_state::dbusToIPMI.end(), 400 [&s](const auto& iter) { 401 return (static_cast<uint8_t>(iter.second) == s); 402 }); 403 404 value = found->first; 405 406 try 407 { 408 auto acpiObject = 409 ipmi::getDbusObject(bus, acpi_state::acpiInterface); 410 ipmi::setDbusProperty(bus, acpiObject.second, acpiObject.first, 411 acpi_state::acpiInterface, 412 acpi_state::devACPIProp, 413 convertForMessage(value)); 414 } 415 catch (const InternalFailure& e) 416 { 417 log<level::ERR>("Failed in set ACPI device property", 418 entry("EXCEPTION=%s", e.what())); 419 return IPMI_CC_UNSPECIFIED_ERROR; 420 } 421 } 422 } 423 else 424 { 425 log<level::DEBUG>("Do not change device power state"); 426 } 427 428 return rc; 429 } 430 431 /** 432 * @brief implements the get ACPI power state command 433 * 434 * @return IPMI completion code plus response data on success. 435 * - ACPI system power state 436 * - ACPI device power state 437 **/ 438 ipmi::RspType<uint8_t, // acpiSystemPowerState 439 uint8_t // acpiDevicePowerState 440 > 441 ipmiGetAcpiPowerState() 442 { 443 uint8_t sysAcpiState; 444 uint8_t devAcpiState; 445 446 sdbusplus::bus::bus bus{ipmid_get_sd_bus_connection()}; 447 448 try 449 { 450 auto acpiObject = ipmi::getDbusObject(bus, acpi_state::acpiInterface); 451 452 auto sysACPIVal = ipmi::getDbusProperty( 453 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface, 454 acpi_state::sysACPIProp); 455 auto sysACPI = acpi_state::ACPIPowerState::convertACPIFromString( 456 std::get<std::string>(sysACPIVal)); 457 sysAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(sysACPI)); 458 459 auto devACPIVal = ipmi::getDbusProperty( 460 bus, acpiObject.second, acpiObject.first, acpi_state::acpiInterface, 461 acpi_state::devACPIProp); 462 auto devACPI = acpi_state::ACPIPowerState::convertACPIFromString( 463 std::get<std::string>(devACPIVal)); 464 devAcpiState = static_cast<uint8_t>(acpi_state::dbusToIPMI.at(devACPI)); 465 } 466 catch (const InternalFailure& e) 467 { 468 return ipmi::responseUnspecifiedError(); 469 } 470 471 return ipmi::responseSuccess(sysAcpiState, devAcpiState); 472 } 473 474 typedef struct 475 { 476 char major; 477 char minor; 478 uint16_t d[2]; 479 } Revision; 480 481 /* Currently supports the vx.x-x-[-x] and v1.x.x-x-[-x] format. It will */ 482 /* return -1 if not in those formats, this routine knows how to parse */ 483 /* version = v0.6-19-gf363f61-dirty */ 484 /* ^ ^ ^^ ^ */ 485 /* | | |----------|-- additional details */ 486 /* | |---------------- Minor */ 487 /* |------------------ Major */ 488 /* and version = v1.99.10-113-g65edf7d-r3-0-g9e4f715 */ 489 /* ^ ^ ^^ ^ */ 490 /* | | |--|---------- additional details */ 491 /* | |---------------- Minor */ 492 /* |------------------ Major */ 493 /* Additional details : If the option group exists it will force Auxiliary */ 494 /* Firmware Revision Information 4th byte to 1 indicating the build was */ 495 /* derived with additional edits */ 496 int convertVersion(std::string s, Revision& rev) 497 { 498 std::string token; 499 uint16_t commits; 500 501 auto location = s.find_first_of('v'); 502 if (location != std::string::npos) 503 { 504 s = s.substr(location + 1); 505 } 506 507 if (!s.empty()) 508 { 509 location = s.find_first_of("."); 510 if (location != std::string::npos) 511 { 512 rev.major = 513 static_cast<char>(std::stoi(s.substr(0, location), 0, 16)); 514 token = s.substr(location + 1); 515 } 516 517 if (!token.empty()) 518 { 519 location = token.find_first_of(".-"); 520 if (location != std::string::npos) 521 { 522 rev.minor = static_cast<char>( 523 std::stoi(token.substr(0, location), 0, 16)); 524 token = token.substr(location + 1); 525 } 526 } 527 528 // Capture the number of commits on top of the minor tag. 529 // I'm using BE format like the ipmi spec asked for 530 location = token.find_first_of(".-"); 531 if (!token.empty()) 532 { 533 commits = std::stoi(token.substr(0, location), 0, 16); 534 rev.d[0] = (commits >> 8) | (commits << 8); 535 536 // commit number we skip 537 location = token.find_first_of(".-"); 538 if (location != std::string::npos) 539 { 540 token = token.substr(location + 1); 541 } 542 } 543 else 544 { 545 rev.d[0] = 0; 546 } 547 548 if (location != std::string::npos) 549 { 550 token = token.substr(location + 1); 551 } 552 553 // Any value of the optional parameter forces it to 1 554 location = token.find_first_of(".-"); 555 if (location != std::string::npos) 556 { 557 token = token.substr(location + 1); 558 } 559 commits = (!token.empty()) ? 1 : 0; 560 561 // We do this operation to get this displayed in least significant bytes 562 // of ipmitool device id command. 563 rev.d[1] = (commits >> 8) | (commits << 8); 564 } 565 566 return 0; 567 } 568 569 /* @brief: Implement the Get Device ID IPMI command per the IPMI spec 570 * @param[in] ctx - shared_ptr to an IPMI context struct 571 * 572 * @returns IPMI completion code plus response data 573 * - Device ID (manufacturer defined) 574 * - Device revision[4 bits]; reserved[3 bits]; SDR support[1 bit] 575 * - FW revision major[7 bits] (binary encoded); available[1 bit] 576 * - FW Revision minor (BCD encoded) 577 * - IPMI version (0x02 for IPMI 2.0) 578 * - device support (bitfield of supported options) 579 * - MFG IANA ID (3 bytes) 580 * - product ID (2 bytes) 581 * - AUX info (4 bytes) 582 */ 583 ipmi::RspType<uint8_t, // Device ID 584 uint8_t, // Device Revision 585 uint8_t, // Firmware Revision Major 586 uint8_t, // Firmware Revision minor 587 uint8_t, // IPMI version 588 uint8_t, // Additional device support 589 uint24_t, // MFG ID 590 uint16_t, // Product ID 591 uint32_t // AUX info 592 > 593 ipmiAppGetDeviceId(ipmi::Context::ptr ctx) 594 { 595 int r = -1; 596 Revision rev = {0}; 597 static struct 598 { 599 uint8_t id; 600 uint8_t revision; 601 uint8_t fw[2]; 602 uint8_t ipmiVer; 603 uint8_t addnDevSupport; 604 uint24_t manufId; 605 uint16_t prodId; 606 uint32_t aux; 607 } devId; 608 static bool dev_id_initialized = false; 609 static bool defaultActivationSetting = true; 610 const char* filename = "/usr/share/ipmi-providers/dev_id.json"; 611 constexpr auto ipmiDevIdStateShift = 7; 612 constexpr auto ipmiDevIdFw1Mask = ~(1 << ipmiDevIdStateShift); 613 614 if (!dev_id_initialized) 615 { 616 try 617 { 618 auto version = getActiveSoftwareVersionInfo(ctx); 619 r = convertVersion(version, rev); 620 } 621 catch (const std::exception& e) 622 { 623 log<level::ERR>(e.what()); 624 } 625 626 if (r >= 0) 627 { 628 // bit7 identifies if the device is available 629 // 0=normal operation 630 // 1=device firmware, SDR update, 631 // or self-initialization in progress. 632 // The availability may change in run time, so mask here 633 // and initialize later. 634 devId.fw[0] = rev.major & ipmiDevIdFw1Mask; 635 636 rev.minor = (rev.minor > 99 ? 99 : rev.minor); 637 devId.fw[1] = rev.minor % 10 + (rev.minor / 10) * 16; 638 std::memcpy(&devId.aux, rev.d, 4); 639 } 640 641 // IPMI Spec version 2.0 642 devId.ipmiVer = 2; 643 644 std::ifstream devIdFile(filename); 645 if (devIdFile.is_open()) 646 { 647 auto data = nlohmann::json::parse(devIdFile, nullptr, false); 648 if (!data.is_discarded()) 649 { 650 devId.id = data.value("id", 0); 651 devId.revision = data.value("revision", 0); 652 devId.addnDevSupport = data.value("addn_dev_support", 0); 653 devId.manufId = data.value("manuf_id", 0); 654 devId.prodId = data.value("prod_id", 0); 655 devId.aux = data.value("aux", 0); 656 657 // Set the availablitity of the BMC. 658 defaultActivationSetting = data.value("availability", true); 659 660 // Don't read the file every time if successful 661 dev_id_initialized = true; 662 } 663 else 664 { 665 log<level::ERR>("Device ID JSON parser failure"); 666 return ipmi::responseUnspecifiedError(); 667 } 668 } 669 else 670 { 671 log<level::ERR>("Device ID file not found"); 672 return ipmi::responseUnspecifiedError(); 673 } 674 } 675 676 // Set availability to the actual current BMC state 677 devId.fw[0] &= ipmiDevIdFw1Mask; 678 if (!getCurrentBmcStateWithFallback(defaultActivationSetting)) 679 { 680 devId.fw[0] |= (1 << ipmiDevIdStateShift); 681 } 682 683 return ipmi::responseSuccess( 684 devId.id, devId.revision, devId.fw[0], devId.fw[1], devId.ipmiVer, 685 devId.addnDevSupport, devId.manufId, devId.prodId, devId.aux); 686 } 687 688 auto ipmiAppGetSelfTestResults() -> ipmi::RspType<uint8_t, uint8_t> 689 { 690 // Byte 2: 691 // 55h - No error. 692 // 56h - Self Test function not implemented in this controller. 693 // 57h - Corrupted or inaccesssible data or devices. 694 // 58h - Fatal hardware error. 695 // FFh - reserved. 696 // all other: Device-specific 'internal failure'. 697 // Byte 3: 698 // For byte 2 = 55h, 56h, FFh: 00h 699 // For byte 2 = 58h, all other: Device-specific 700 // For byte 2 = 57h: self-test error bitfield. 701 // Note: returning 57h does not imply that all test were run. 702 // [7] 1b = Cannot access SEL device. 703 // [6] 1b = Cannot access SDR Repository. 704 // [5] 1b = Cannot access BMC FRU device. 705 // [4] 1b = IPMB signal lines do not respond. 706 // [3] 1b = SDR Repository empty. 707 // [2] 1b = Internal Use Area of BMC FRU corrupted. 708 // [1] 1b = controller update 'boot block' firmware corrupted. 709 // [0] 1b = controller operational firmware corrupted. 710 constexpr uint8_t notImplemented = 0x56; 711 constexpr uint8_t zero = 0; 712 return ipmi::responseSuccess(notImplemented, zero); 713 } 714 715 static constexpr size_t uuidBinaryLength = 16; 716 static std::array<uint8_t, uuidBinaryLength> rfc4122ToIpmi(std::string rfc4122) 717 { 718 using Argument = xyz::openbmc_project::Common::InvalidArgument; 719 // UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 720 // Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte 721 // order 722 // Ex: 0x2332fc2c40e66298e511f2782395a361 723 constexpr size_t uuidHexLength = (2 * uuidBinaryLength); 724 constexpr size_t uuidRfc4122Length = (uuidHexLength + 4); 725 std::array<uint8_t, uuidBinaryLength> uuid; 726 if (rfc4122.size() == uuidRfc4122Length) 727 { 728 rfc4122.erase(std::remove(rfc4122.begin(), rfc4122.end(), '-'), 729 rfc4122.end()); 730 } 731 if (rfc4122.size() != uuidHexLength) 732 { 733 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 734 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 735 } 736 for (size_t ind = 0; ind < uuidHexLength; ind += 2) 737 { 738 char v[3]; 739 v[0] = rfc4122[ind]; 740 v[1] = rfc4122[ind + 1]; 741 v[2] = 0; 742 size_t err; 743 long b; 744 try 745 { 746 b = std::stoul(v, &err, 16); 747 } 748 catch (std::exception& e) 749 { 750 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 751 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 752 } 753 // check that exactly two ascii bytes were converted 754 if (err != 2) 755 { 756 elog<InvalidArgument>(Argument::ARGUMENT_NAME("rfc4122"), 757 Argument::ARGUMENT_VALUE(rfc4122.c_str())); 758 } 759 uuid[uuidBinaryLength - (ind / 2) - 1] = static_cast<uint8_t>(b); 760 } 761 return uuid; 762 } 763 764 auto ipmiAppGetDeviceGuid() 765 -> ipmi::RspType<std::array<uint8_t, uuidBinaryLength>> 766 { 767 // return a fixed GUID based on /etc/machine-id 768 // This should match the /redfish/v1/Managers/bmc's UUID data 769 770 // machine specific application ID (for BMC ID) 771 // generated by systemd-id128 -p new as per man page 772 static constexpr sd_id128_t bmcUuidAppId = SD_ID128_MAKE( 773 e0, e1, 73, 76, 64, 61, 47, da, a5, 0c, d0, cc, 64, 12, 45, 78); 774 775 sd_id128_t bmcUuid; 776 // create the UUID from /etc/machine-id via the systemd API 777 sd_id128_get_machine_app_specific(bmcUuidAppId, &bmcUuid); 778 779 char bmcUuidCstr[SD_ID128_STRING_MAX]; 780 std::string systemUuid = sd_id128_to_string(bmcUuid, bmcUuidCstr); 781 782 std::array<uint8_t, uuidBinaryLength> uuid = rfc4122ToIpmi(systemUuid); 783 return ipmi::responseSuccess(uuid); 784 } 785 786 auto ipmiAppGetBtCapabilities() 787 -> ipmi::RspType<uint8_t, uint8_t, uint8_t, uint8_t, uint8_t> 788 { 789 // Per IPMI 2.0 spec, the input and output buffer size must be the max 790 // buffer size minus one byte to allocate space for the length byte. 791 constexpr uint8_t nrOutstanding = 0x01; 792 constexpr uint8_t inputBufferSize = MAX_IPMI_BUFFER - 1; 793 constexpr uint8_t outputBufferSize = MAX_IPMI_BUFFER - 1; 794 constexpr uint8_t transactionTime = 0x0A; 795 constexpr uint8_t nrRetries = 0x01; 796 797 return ipmi::responseSuccess(nrOutstanding, inputBufferSize, 798 outputBufferSize, transactionTime, nrRetries); 799 } 800 801 auto ipmiAppGetSystemGuid() -> ipmi::RspType<std::array<uint8_t, 16>> 802 { 803 static constexpr auto bmcInterface = 804 "xyz.openbmc_project.Inventory.Item.Bmc"; 805 static constexpr auto uuidInterface = "xyz.openbmc_project.Common.UUID"; 806 static constexpr auto uuidProperty = "UUID"; 807 808 ipmi::Value propValue; 809 try 810 { 811 // Get the Inventory object implementing BMC interface 812 auto busPtr = getSdBus(); 813 auto objectInfo = ipmi::getDbusObject(*busPtr, bmcInterface); 814 815 // Read UUID property value from bmcObject 816 // UUID is in RFC4122 format Ex: 61a39523-78f2-11e5-9862-e6402cfc3223 817 propValue = 818 ipmi::getDbusProperty(*busPtr, objectInfo.second, objectInfo.first, 819 uuidInterface, uuidProperty); 820 } 821 catch (const InternalFailure& e) 822 { 823 log<level::ERR>("Failed in reading BMC UUID property", 824 entry("INTERFACE=%s", uuidInterface), 825 entry("PROPERTY=%s", uuidProperty)); 826 return ipmi::responseUnspecifiedError(); 827 } 828 std::array<uint8_t, 16> uuid; 829 std::string rfc4122Uuid = std::get<std::string>(propValue); 830 try 831 { 832 // convert to IPMI format 833 uuid = rfc4122ToIpmi(rfc4122Uuid); 834 } 835 catch (const InvalidArgument& e) 836 { 837 log<level::ERR>("Failed in parsing BMC UUID property", 838 entry("INTERFACE=%s", uuidInterface), 839 entry("PROPERTY=%s", uuidProperty), 840 entry("VALUE=%s", rfc4122Uuid.c_str())); 841 return ipmi::responseUnspecifiedError(); 842 } 843 return ipmi::responseSuccess(uuid); 844 } 845 846 /** 847 * @brief set the session state as teardown 848 * 849 * This function is to set the session state to tear down in progress if the 850 * state is active. 851 * 852 * @param[in] busp - Dbus obj 853 * @param[in] service - service name 854 * @param[in] obj - object path 855 * 856 * @return success completion code if it sets the session state to 857 * tearDownInProgress else return the corresponding error completion code. 858 **/ 859 uint8_t setSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp, 860 const std::string& service, const std::string& obj) 861 { 862 try 863 { 864 uint8_t sessionState = std::get<uint8_t>(ipmi::getDbusProperty( 865 *busp, service, obj, session::sessionIntf, "State")); 866 867 if (sessionState == static_cast<uint8_t>(session::State::active)) 868 { 869 ipmi::setDbusProperty( 870 *busp, service, obj, session::sessionIntf, "State", 871 static_cast<uint8_t>(session::State::tearDownInProgress)); 872 return ipmi::ccSuccess; 873 } 874 } 875 catch (std::exception& e) 876 { 877 log<level::ERR>("Failed in getting session state property", 878 entry("service=%s", service.c_str()), 879 entry("object path=%s", obj.c_str()), 880 entry("interface=%s", session::sessionIntf)); 881 return ipmi::ccUnspecifiedError; 882 } 883 884 return ipmi::ccInvalidFieldRequest; 885 } 886 887 ipmi::RspType<> ipmiAppCloseSession(uint32_t reqSessionId, 888 std::optional<uint8_t> requestSessionHandle) 889 { 890 auto busp = getSdBus(); 891 uint8_t reqSessionHandle = 892 requestSessionHandle.value_or(session::defaultSessionHandle); 893 894 if (reqSessionId == session::sessionZero && 895 reqSessionHandle == session::defaultSessionHandle) 896 { 897 return ipmi::response(session::ccInvalidSessionId); 898 } 899 900 if (reqSessionId == session::sessionZero && 901 reqSessionHandle == session::invalidSessionHandle) 902 { 903 return ipmi::response(session::ccInvalidSessionHandle); 904 } 905 906 if (reqSessionId != session::sessionZero && 907 reqSessionHandle != session::defaultSessionHandle) 908 { 909 return ipmi::response(ipmi::ccInvalidFieldRequest); 910 } 911 912 try 913 { 914 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects( 915 *busp, session::sessionManagerRootPath, session::sessionIntf); 916 917 for (auto& objectTreeItr : objectTree) 918 { 919 const std::string obj = objectTreeItr.first; 920 921 if (isSessionObjectMatched(obj, reqSessionId, reqSessionHandle)) 922 { 923 auto& serviceMap = objectTreeItr.second; 924 925 // Session id and session handle are unique for each session. 926 // Session id and handler are retrived from the object path and 927 // object path will be unique for each session. Checking if 928 // multiple objects exist with same object path under multiple 929 // services. 930 if (serviceMap.size() != 1) 931 { 932 return ipmi::responseUnspecifiedError(); 933 } 934 935 auto itr = serviceMap.begin(); 936 const std::string service = itr->first; 937 return ipmi::response(setSessionState(busp, service, obj)); 938 } 939 } 940 } 941 catch (sdbusplus::exception::SdBusError& e) 942 { 943 log<level::ERR>("Failed to fetch object from dbus", 944 entry("INTERFACE=%s", session::sessionIntf), 945 entry("ERRMSG=%s", e.what())); 946 return ipmi::responseUnspecifiedError(); 947 } 948 949 return ipmi::responseInvalidFieldRequest(); 950 } 951 952 uint8_t getTotalSessionCount() 953 { 954 uint8_t count = 0, ch = 1; 955 956 while (ch < ipmi::maxIpmiChannels && 957 count < session::maxNetworkInstanceSupported) 958 { 959 ipmi::ChannelInfo chInfo; 960 ipmi::getChannelInfo(ch, chInfo); 961 if (static_cast<ipmi::EChannelMediumType>(chInfo.mediumType) == 962 ipmi::EChannelMediumType::lan8032) 963 { 964 count++; 965 } 966 ch++; 967 } 968 return count * session::maxSessionCountPerChannel; 969 } 970 971 /** 972 * @brief get session info request data. 973 * 974 * This function validates the request data and retrive request session id, 975 * session handle. 976 * 977 * @param[in] sessionIndex - request session index 978 * @param[in] payload - input payload 979 * @param[in] reqSessionId - unpacked session Id will be asigned 980 * @param[in] reqSessionHandle - unpacked session handle will be asigned 981 * 982 * @return success completion code if request data is valid 983 * else return the correcponding error completion code. 984 **/ 985 uint8_t getSessionInfoRequestData(const uint8_t sessionIndex, 986 ipmi::message::Payload& payload, 987 uint32_t& reqSessionId, 988 uint8_t& reqSessionHandle) 989 { 990 if (sessionIndex == session::sessionZero || 991 ((sessionIndex > session::maxSessionCountPerChannel) && 992 (sessionIndex < session::searchSessionByHandle))) 993 { 994 return ipmi::ccInvalidFieldRequest; 995 } 996 997 switch (sessionIndex) 998 { 999 case session::searchSessionByHandle: 1000 1001 if ((payload.unpack(reqSessionHandle)) || 1002 (!payload.fullyUnpacked())) 1003 { 1004 return ipmi::ccReqDataLenInvalid; 1005 } 1006 1007 if ((reqSessionHandle == session::sessionZero) || 1008 ((reqSessionHandle & session::multiIntfaceSessionHandleMask) > 1009 session::maxSessionCountPerChannel)) 1010 { 1011 return session::ccInvalidSessionHandle; 1012 } 1013 break; 1014 1015 case session::searchSessionById: 1016 1017 if ((payload.unpack(reqSessionId)) || (!payload.fullyUnpacked())) 1018 { 1019 return ipmi::ccReqDataLenInvalid; 1020 } 1021 1022 if (reqSessionId == session::sessionZero) 1023 { 1024 return session::ccInvalidSessionId; 1025 } 1026 break; 1027 1028 default: 1029 if (!payload.fullyUnpacked()) 1030 { 1031 return ipmi::ccReqDataLenInvalid; 1032 } 1033 break; 1034 } 1035 return ipmi::ccSuccess; 1036 } 1037 1038 uint8_t getSessionState(std::shared_ptr<sdbusplus::asio::connection>& busp, 1039 const std::string& service, const std::string& objPath, 1040 uint8_t& sessionState) 1041 { 1042 try 1043 { 1044 sessionState = std::get<uint8_t>(ipmi::getDbusProperty( 1045 *busp, service, objPath, session::sessionIntf, "State")); 1046 } 1047 catch (sdbusplus::exception::SdBusError& e) 1048 { 1049 log<level::ERR>("Failed to fetch state property ", 1050 entry("SERVICE=%s", service.c_str()), 1051 entry("OBJECTPATH=%s", objPath.c_str()), 1052 entry("INTERFACE=%s", session::sessionIntf), 1053 entry("ERRMSG=%s", e.what())); 1054 return ipmi::ccUnspecifiedError; 1055 } 1056 1057 return ipmi::ccSuccess; 1058 } 1059 1060 static constexpr uint8_t macAddrLen = 6; 1061 struct GetSessionInfoRes 1062 { 1063 uint8_t sessionHandle; 1064 uint8_t totalSessionCount; 1065 uint8_t activeSessionCount; 1066 uint8_t userID; 1067 uint8_t privLevel; 1068 uint8_t channelNumber; 1069 uint32_t remoteIpAddr; 1070 std::array<uint8_t, macAddrLen> macAddr = {0}; 1071 uint16_t remotePort; 1072 }; 1073 1074 uint8_t 1075 fillGetSessionInfoRes(std::shared_ptr<sdbusplus::asio::connection>& busp, 1076 const std::string& service, 1077 const std::string& objPath, 1078 struct GetSessionInfoRes& resp, uint8_t& sessionState) 1079 { 1080 try 1081 { 1082 ipmi::PropertyMap sessionProps = ipmi::getAllDbusProperties( 1083 *busp, service, objPath, session::sessionIntf); 1084 1085 sessionState = std::get<uint8_t>(sessionProps.at("State")); 1086 if (sessionState == static_cast<uint8_t>(session::State::active)) 1087 { 1088 resp.sessionHandle = 1089 std::get<uint8_t>(sessionProps["SessionHandle"]); 1090 resp.userID = std::get<uint8_t>(sessionProps["UserID"]); 1091 resp.privLevel = 1092 std::get<uint8_t>(sessionProps["CurrentPrivilege"]); 1093 resp.channelNumber = std::get<uint8_t>(sessionProps["ChannelNum"]); 1094 resp.remoteIpAddr = 1095 std::get<uint32_t>(sessionProps["RemoteIPAddr"]); 1096 resp.remotePort = std::get<uint16_t>(sessionProps["RemotePort"]); 1097 } 1098 } 1099 catch (sdbusplus::exception::SdBusError& e) 1100 { 1101 log<level::ERR>("Failed to fetch state property ", 1102 entry("SERVICE=%s", service.c_str()), 1103 entry("OBJECTPATH=%s", objPath.c_str()), 1104 entry("INTERFACE=%s", session::sessionIntf), 1105 entry("ERRMSG=%s", e.what())); 1106 return ipmi::ccUnspecifiedError; 1107 } 1108 1109 return ipmi::ccSuccess; 1110 } 1111 1112 ipmi::RspType< 1113 uint8_t, // session handle, 1114 uint8_t, // total session count 1115 uint8_t, // active session count 1116 std::optional<std::tuple<uint8_t, // user ID 1117 uint8_t, // privilege level 1118 uint8_t, // channel number 1119 uint32_t, // remote ip address, 1120 std::array<uint8_t, macAddrLen>, // mac address 1121 uint16_t // remote port 1122 >>> 1123 ipmiAppGetSessionInfo(uint8_t sessionIndex, ipmi::message::Payload& payload) 1124 { 1125 uint32_t reqSessionId = 0; 1126 uint8_t reqSessionHandle = session::defaultSessionHandle; 1127 // initializing state to 0xff as 0 represents state as inactive. 1128 uint8_t state = 0xFF; 1129 1130 uint8_t completionCode = getSessionInfoRequestData( 1131 sessionIndex, payload, reqSessionId, reqSessionHandle); 1132 1133 if (completionCode) 1134 { 1135 return ipmi::response(completionCode); 1136 } 1137 struct GetSessionInfoRes res = {0}; 1138 res.totalSessionCount = getTotalSessionCount(); 1139 res.activeSessionCount = 0; 1140 auto busp = getSdBus(); 1141 1142 try 1143 { 1144 uint8_t index = 0; 1145 ipmi::ObjectTree objectTree = ipmi::getAllDbusObjects( 1146 *busp, session::sessionManagerRootPath, session::sessionIntf); 1147 1148 for (auto& objectTreeItr : objectTree) 1149 { 1150 uint32_t sessionId = 0; 1151 uint8_t sessionHandle = session::defaultSessionHandle; 1152 std::string objectPath = objectTreeItr.first; 1153 1154 if (!parseCloseSessionInputPayload(objectPath, sessionId, 1155 sessionHandle)) 1156 { 1157 continue; 1158 } 1159 index++; 1160 auto& serviceMap = objectTreeItr.second; 1161 auto itr = serviceMap.begin(); 1162 1163 if (serviceMap.size() != 1) 1164 { 1165 return ipmi::responseUnspecifiedError(); 1166 } 1167 1168 std::string service = itr->first; 1169 uint8_t sessionState = 0; 1170 completionCode = 1171 getSessionState(busp, service, objectPath, sessionState); 1172 if (completionCode) 1173 { 1174 return ipmi::response(completionCode); 1175 } 1176 1177 if (sessionState == static_cast<uint8_t>(session::State::active)) 1178 { 1179 res.activeSessionCount++; 1180 } 1181 1182 if (index != sessionIndex && reqSessionId != sessionId && 1183 reqSessionHandle != sessionHandle) 1184 { 1185 continue; 1186 } 1187 1188 completionCode = 1189 fillGetSessionInfoRes(busp, service, objectPath, res, state); 1190 1191 if (completionCode) 1192 { 1193 return ipmi::response(completionCode); 1194 } 1195 } 1196 } 1197 1198 catch (sdbusplus::exception::SdBusError& e) 1199 { 1200 log<level::ERR>("Failed to fetch object from dbus", 1201 entry("INTERFACE=%s", session::sessionIntf), 1202 entry("ERRMSG=%s", e.what())); 1203 return ipmi::responseUnspecifiedError(); 1204 } 1205 1206 if (state == static_cast<uint8_t>(session::State::active)) 1207 { 1208 return ipmi::responseSuccess( 1209 res.sessionHandle, res.totalSessionCount, res.activeSessionCount, 1210 std::make_tuple(res.userID, res.privLevel, res.channelNumber, 1211 res.remoteIpAddr, res.macAddr, res.remotePort)); 1212 } 1213 else if (state == static_cast<uint8_t>(session::State::tearDownInProgress)) 1214 { 1215 res.sessionHandle = 0; 1216 return ipmi::responseSuccess(res.sessionHandle, res.totalSessionCount, 1217 res.activeSessionCount, std::nullopt); 1218 } 1219 1220 return ipmi::responseInvalidFieldRequest(); 1221 } 1222 1223 static std::unique_ptr<SysInfoParamStore> sysInfoParamStore; 1224 1225 static std::string sysInfoReadSystemName() 1226 { 1227 // Use the BMC hostname as the "System Name." 1228 char hostname[HOST_NAME_MAX + 1] = {}; 1229 if (gethostname(hostname, HOST_NAME_MAX) != 0) 1230 { 1231 perror("System info parameter: system name"); 1232 } 1233 return hostname; 1234 } 1235 1236 static constexpr uint8_t revisionOnly = 0x80; 1237 static constexpr uint8_t paramRevision = 0x11; 1238 static constexpr size_t configParameterLength = 16; 1239 1240 static constexpr size_t smallChunkSize = 14; 1241 static constexpr size_t fullChunkSize = 16; 1242 static constexpr uint8_t progressMask = 0x3; 1243 1244 static constexpr uint8_t setComplete = 0x0; 1245 static constexpr uint8_t setInProgress = 0x1; 1246 static constexpr uint8_t commitWrite = 0x2; 1247 static uint8_t transferStatus = setComplete; 1248 1249 static constexpr uint8_t configDataOverhead = 2; 1250 1251 // For EFI based system, 256 bytes is recommended. 1252 static constexpr size_t maxBytesPerParameter = 256; 1253 1254 namespace ipmi 1255 { 1256 constexpr Cc ccParmNotSupported = 0x80; 1257 constexpr Cc ccSetInProgressActive = 0x81; 1258 constexpr Cc ccSystemInfoParameterSetReadOnly = 0x82; 1259 1260 static inline auto responseParmNotSupported() 1261 { 1262 return response(ccParmNotSupported); 1263 } 1264 static inline auto responseSetInProgressActive() 1265 { 1266 return response(ccSetInProgressActive); 1267 } 1268 static inline auto responseSystemInfoParameterSetReadOnly() 1269 { 1270 return response(ccSystemInfoParameterSetReadOnly); 1271 } 1272 } // namespace ipmi 1273 1274 ipmi::RspType<uint8_t, // Parameter revision 1275 std::optional<uint8_t>, // data1 / setSelector / ProgressStatus 1276 std::optional<std::vector<uint8_t>>> // data2-17 1277 ipmiAppGetSystemInfo(uint8_t getRevision, uint8_t paramSelector, 1278 uint8_t setSelector, uint8_t BlockSelector) 1279 { 1280 if (getRevision & revisionOnly) 1281 { 1282 return ipmi::responseSuccess(paramRevision, std::nullopt, std::nullopt); 1283 } 1284 1285 if (paramSelector == 0) 1286 { 1287 return ipmi::responseSuccess(paramRevision, transferStatus, 1288 std::nullopt); 1289 } 1290 1291 if (BlockSelector != 0) // 00h if parameter does not require a block number 1292 { 1293 return ipmi::responseParmNotSupported(); 1294 } 1295 1296 if (sysInfoParamStore == nullptr) 1297 { 1298 sysInfoParamStore = std::make_unique<SysInfoParamStore>(); 1299 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME, 1300 sysInfoReadSystemName); 1301 } 1302 1303 // Parameters other than Set In Progress are assumed to be strings. 1304 std::tuple<bool, std::string> ret = 1305 sysInfoParamStore->lookup(paramSelector); 1306 bool found = std::get<0>(ret); 1307 if (!found) 1308 { 1309 return ipmi::responseParmNotSupported(); 1310 } 1311 std::string& paramString = std::get<1>(ret); 1312 std::vector<uint8_t> configData; 1313 size_t count = 0; 1314 if (setSelector == 0) 1315 { // First chunk has only 14 bytes. 1316 configData.emplace_back(0); // encoding 1317 configData.emplace_back(paramString.length()); // string length 1318 count = std::min(paramString.length(), smallChunkSize); 1319 configData.resize(count + configDataOverhead); 1320 std::copy_n(paramString.begin(), count, 1321 configData.begin() + configDataOverhead); // 14 bytes thunk 1322 } 1323 else 1324 { 1325 size_t offset = (setSelector * fullChunkSize) - configDataOverhead; 1326 if (offset >= paramString.length()) 1327 { 1328 return ipmi::responseParmOutOfRange(); 1329 } 1330 count = std::min(paramString.length() - offset, fullChunkSize); 1331 configData.resize(count); 1332 std::copy_n(paramString.begin() + offset, count, 1333 configData.begin()); // 16 bytes chunk 1334 } 1335 return ipmi::responseSuccess(paramRevision, setSelector, configData); 1336 } 1337 1338 ipmi::RspType<> ipmiAppSetSystemInfo(uint8_t paramSelector, uint8_t data1, 1339 std::vector<uint8_t> configData) 1340 { 1341 if (paramSelector == 0) 1342 { 1343 // attempt to set the 'set in progress' value (in parameter #0) 1344 // when not in the set complete state. 1345 if ((transferStatus != setComplete) && (data1 == setInProgress)) 1346 { 1347 return ipmi::responseSetInProgressActive(); 1348 } 1349 // only following 2 states are supported 1350 if (data1 > setInProgress) 1351 { 1352 phosphor::logging::log<phosphor::logging::level::ERR>( 1353 "illegal SetInProgress status"); 1354 return ipmi::responseInvalidFieldRequest(); 1355 } 1356 1357 transferStatus = data1 & progressMask; 1358 return ipmi::responseSuccess(); 1359 } 1360 1361 if (configData.size() > configParameterLength) 1362 { 1363 return ipmi::responseInvalidFieldRequest(); 1364 } 1365 1366 if (!sysInfoParamStore) 1367 { 1368 sysInfoParamStore = std::make_unique<SysInfoParamStore>(); 1369 sysInfoParamStore->update(IPMI_SYSINFO_SYSTEM_NAME, 1370 sysInfoReadSystemName); 1371 } 1372 1373 // lookup 1374 std::tuple<bool, std::string> ret = 1375 sysInfoParamStore->lookup(paramSelector); 1376 bool found = std::get<0>(ret); 1377 std::string& paramString = std::get<1>(ret); 1378 if (!found) 1379 { 1380 // parameter does not exist. Init new 1381 paramString = ""; 1382 } 1383 1384 uint8_t setSelector = data1; 1385 size_t count = 0; 1386 if (setSelector == 0) // First chunk has only 14 bytes. 1387 { 1388 size_t stringLen = configData.at(1); // string length 1389 // maxBytesPerParamter is 256. It will always be greater than stringLen 1390 // (unit8_t) if maxBytes changes in future, then following line is 1391 // needed. 1392 // stringLen = std::min(stringLen, maxBytesPerParameter); 1393 count = std::min(stringLen, smallChunkSize); 1394 count = std::min(count, configData.size()); 1395 paramString.resize(stringLen); // reserve space 1396 std::copy_n(configData.begin() + configDataOverhead, count, 1397 paramString.begin()); 1398 } 1399 else 1400 { 1401 size_t offset = (setSelector * fullChunkSize) - configDataOverhead; 1402 if (offset >= paramString.length()) 1403 { 1404 return ipmi::responseParmOutOfRange(); 1405 } 1406 count = std::min(paramString.length() - offset, configData.size()); 1407 std::copy_n(configData.begin(), count, paramString.begin() + offset); 1408 } 1409 sysInfoParamStore->update(paramSelector, paramString); 1410 return ipmi::responseSuccess(); 1411 } 1412 1413 #ifdef ENABLE_I2C_WHITELIST_CHECK 1414 inline std::vector<uint8_t> convertStringToData(const std::string& command) 1415 { 1416 std::istringstream iss(command); 1417 std::string token; 1418 std::vector<uint8_t> dataValue; 1419 while (std::getline(iss, token, ' ')) 1420 { 1421 dataValue.emplace_back( 1422 static_cast<uint8_t>(std::stoul(token, nullptr, base_16))); 1423 } 1424 return dataValue; 1425 } 1426 1427 static bool populateI2CMasterWRWhitelist() 1428 { 1429 nlohmann::json data = nullptr; 1430 std::ifstream jsonFile(i2cMasterWRWhitelistFile); 1431 1432 if (!jsonFile.good()) 1433 { 1434 log<level::WARNING>("i2c white list file not found!", 1435 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile)); 1436 return false; 1437 } 1438 1439 try 1440 { 1441 data = nlohmann::json::parse(jsonFile, nullptr, false); 1442 } 1443 catch (nlohmann::json::parse_error& e) 1444 { 1445 log<level::ERR>("Corrupted i2c white list config file", 1446 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile), 1447 entry("MSG: %s", e.what())); 1448 return false; 1449 } 1450 1451 try 1452 { 1453 // Example JSON Structure format 1454 // "filters": [ 1455 // { 1456 // "Description": "Allow full read - ignore first byte write value 1457 // for 0x40 to 0x4F", 1458 // "busId": "0x01", 1459 // "slaveAddr": "0x40", 1460 // "slaveAddrMask": "0x0F", 1461 // "command": "0x00", 1462 // "commandMask": "0xFF" 1463 // }, 1464 // { 1465 // "Description": "Allow full read - first byte match 0x05 and 1466 // ignore second byte", 1467 // "busId": "0x01", 1468 // "slaveAddr": "0x57", 1469 // "slaveAddrMask": "0x00", 1470 // "command": "0x05 0x00", 1471 // "commandMask": "0x00 0xFF" 1472 // },] 1473 1474 nlohmann::json filters = data[filtersStr].get<nlohmann::json>(); 1475 std::vector<i2cMasterWRWhitelist>& whitelist = getWRWhitelist(); 1476 for (const auto& it : filters.items()) 1477 { 1478 nlohmann::json filter = it.value(); 1479 if (filter.is_null()) 1480 { 1481 log<level::ERR>( 1482 "Corrupted I2C master write read whitelist config file", 1483 entry("FILE_NAME: %s", i2cMasterWRWhitelistFile)); 1484 return false; 1485 } 1486 const std::vector<uint8_t>& writeData = 1487 convertStringToData(filter[cmdStr].get<std::string>()); 1488 const std::vector<uint8_t>& writeDataMask = 1489 convertStringToData(filter[cmdMaskStr].get<std::string>()); 1490 if (writeDataMask.size() != writeData.size()) 1491 { 1492 log<level::ERR>("I2C master write read whitelist filter " 1493 "mismatch for command & mask size"); 1494 return false; 1495 } 1496 whitelist.push_back( 1497 {static_cast<uint8_t>(std::stoul( 1498 filter[busIdStr].get<std::string>(), nullptr, base_16)), 1499 static_cast<uint8_t>( 1500 std::stoul(filter[slaveAddrStr].get<std::string>(), 1501 nullptr, base_16)), 1502 static_cast<uint8_t>( 1503 std::stoul(filter[slaveAddrMaskStr].get<std::string>(), 1504 nullptr, base_16)), 1505 writeData, writeDataMask}); 1506 } 1507 if (whitelist.size() != filters.size()) 1508 { 1509 log<level::ERR>( 1510 "I2C master write read whitelist filter size mismatch"); 1511 return false; 1512 } 1513 } 1514 catch (std::exception& e) 1515 { 1516 log<level::ERR>("I2C master write read whitelist unexpected exception", 1517 entry("ERROR=%s", e.what())); 1518 return false; 1519 } 1520 return true; 1521 } 1522 1523 static inline bool isWriteDataWhitelisted(const std::vector<uint8_t>& data, 1524 const std::vector<uint8_t>& dataMask, 1525 const std::vector<uint8_t>& writeData) 1526 { 1527 std::vector<uint8_t> processedDataBuf(data.size()); 1528 std::vector<uint8_t> processedReqBuf(dataMask.size()); 1529 std::transform(writeData.begin(), writeData.end(), dataMask.begin(), 1530 processedReqBuf.begin(), std::bit_or<uint8_t>()); 1531 std::transform(data.begin(), data.end(), dataMask.begin(), 1532 processedDataBuf.begin(), std::bit_or<uint8_t>()); 1533 1534 return (processedDataBuf == processedReqBuf); 1535 } 1536 1537 static bool isCmdWhitelisted(uint8_t busId, uint8_t slaveAddr, 1538 std::vector<uint8_t>& writeData) 1539 { 1540 std::vector<i2cMasterWRWhitelist>& whiteList = getWRWhitelist(); 1541 for (const auto& wlEntry : whiteList) 1542 { 1543 if ((busId == wlEntry.busId) && 1544 ((slaveAddr | wlEntry.slaveAddrMask) == 1545 (wlEntry.slaveAddr | wlEntry.slaveAddrMask))) 1546 { 1547 const std::vector<uint8_t>& dataMask = wlEntry.dataMask; 1548 // Skip as no-match, if requested write data is more than the 1549 // write data mask size 1550 if (writeData.size() > dataMask.size()) 1551 { 1552 continue; 1553 } 1554 if (isWriteDataWhitelisted(wlEntry.data, dataMask, writeData)) 1555 { 1556 return true; 1557 } 1558 } 1559 } 1560 return false; 1561 } 1562 #else 1563 static bool populateI2CMasterWRWhitelist() 1564 { 1565 log<level::INFO>( 1566 "I2C_WHITELIST_CHECK is disabled, do not populate whitelist"); 1567 return true; 1568 } 1569 #endif // ENABLE_I2C_WHITELIST_CHECK 1570 1571 /** @brief implements master write read IPMI command which can be used for 1572 * low-level I2C/SMBus write, read or write-read access 1573 * @param isPrivateBus -to indicate private bus usage 1574 * @param busId - bus id 1575 * @param channelNum - channel number 1576 * @param reserved - skip 1 bit 1577 * @param slaveAddr - slave address 1578 * @param read count - number of bytes to be read 1579 * @param writeData - data to be written 1580 * 1581 * @returns IPMI completion code plus response data 1582 * - readData - i2c response data 1583 */ 1584 ipmi::RspType<std::vector<uint8_t>> 1585 ipmiMasterWriteRead(bool isPrivateBus, uint3_t busId, uint4_t channelNum, 1586 bool reserved, uint7_t slaveAddr, uint8_t readCount, 1587 std::vector<uint8_t> writeData) 1588 { 1589 if (readCount > maxIPMIWriteReadSize) 1590 { 1591 log<level::ERR>("Master write read command: Read count exceeds limit"); 1592 return ipmi::responseParmOutOfRange(); 1593 } 1594 const size_t writeCount = writeData.size(); 1595 if (!readCount && !writeCount) 1596 { 1597 log<level::ERR>("Master write read command: Read & write count are 0"); 1598 return ipmi::responseInvalidFieldRequest(); 1599 } 1600 #ifdef ENABLE_I2C_WHITELIST_CHECK 1601 if (!isCmdWhitelisted(static_cast<uint8_t>(busId), 1602 static_cast<uint8_t>(slaveAddr), writeData)) 1603 { 1604 log<level::ERR>("Master write read request blocked!", 1605 entry("BUS=%d", static_cast<uint8_t>(busId)), 1606 entry("ADDR=0x%x", static_cast<uint8_t>(slaveAddr))); 1607 return ipmi::responseInvalidFieldRequest(); 1608 } 1609 #endif // ENABLE_I2C_WHITELIST_CHECK 1610 std::vector<uint8_t> readBuf(readCount); 1611 std::string i2cBus = 1612 "/dev/i2c-" + std::to_string(static_cast<uint8_t>(busId)); 1613 1614 ipmi::Cc ret = ipmi::i2cWriteRead(i2cBus, static_cast<uint8_t>(slaveAddr), 1615 writeData, readBuf); 1616 if (ret != ipmi::ccSuccess) 1617 { 1618 return ipmi::response(ret); 1619 } 1620 return ipmi::responseSuccess(readBuf); 1621 } 1622 1623 void register_netfn_app_functions() 1624 { 1625 // <Get Device ID> 1626 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1627 ipmi::app::cmdGetDeviceId, ipmi::Privilege::User, 1628 ipmiAppGetDeviceId); 1629 1630 // <Get BT Interface Capabilities> 1631 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1632 ipmi::app::cmdGetBtIfaceCapabilities, 1633 ipmi::Privilege::User, ipmiAppGetBtCapabilities); 1634 1635 // <Reset Watchdog Timer> 1636 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1637 ipmi::app::cmdResetWatchdogTimer, 1638 ipmi::Privilege::Operator, ipmiAppResetWatchdogTimer); 1639 1640 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1641 ipmi::app::cmdGetSessionInfo, 1642 ipmi::Privilege::Callback, ipmiAppGetSessionInfo); 1643 1644 // <Set Watchdog Timer> 1645 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1646 ipmi::app::cmdSetWatchdogTimer, 1647 ipmi::Privilege::Operator, ipmiSetWatchdogTimer); 1648 1649 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1650 ipmi::app::cmdCloseSession, ipmi::Privilege::Callback, 1651 ipmiAppCloseSession); 1652 1653 // <Get Watchdog Timer> 1654 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1655 ipmi::app::cmdGetWatchdogTimer, 1656 ipmi::Privilege::Operator, ipmiGetWatchdogTimer); 1657 1658 // <Get Self Test Results> 1659 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1660 ipmi::app::cmdGetSelfTestResults, 1661 ipmi::Privilege::User, ipmiAppGetSelfTestResults); 1662 1663 // <Get Device GUID> 1664 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1665 ipmi::app::cmdGetDeviceGuid, ipmi::Privilege::User, 1666 ipmiAppGetDeviceGuid); 1667 1668 // <Set ACPI Power State> 1669 ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_ACPI, NULL, 1670 ipmi_app_set_acpi_power_state, PRIVILEGE_ADMIN); 1671 1672 // <Get ACPI Power State> 1673 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1674 ipmi::app::cmdGetAcpiPowerState, 1675 ipmi::Privilege::Admin, ipmiGetAcpiPowerState); 1676 1677 // Note: For security reason, this command will be registered only when 1678 // there are proper I2C Master write read whitelist 1679 if (populateI2CMasterWRWhitelist()) 1680 { 1681 // Note: For security reasons, registering master write read as admin 1682 // privilege command, even though IPMI 2.0 specification allows it as 1683 // operator privilege. 1684 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1685 ipmi::app::cmdMasterWriteRead, 1686 ipmi::Privilege::Admin, ipmiMasterWriteRead); 1687 } 1688 1689 // <Get System GUID Command> 1690 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1691 ipmi::app::cmdGetSystemGuid, ipmi::Privilege::User, 1692 ipmiAppGetSystemGuid); 1693 1694 // <Get Channel Cipher Suites Command> 1695 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1696 ipmi::app::cmdGetChannelCipherSuites, 1697 ipmi::Privilege::Callback, getChannelCipherSuites); 1698 1699 // <Get System Info Command> 1700 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1701 ipmi::app::cmdGetSystemInfoParameters, 1702 ipmi::Privilege::User, ipmiAppGetSystemInfo); 1703 // <Set System Info Command> 1704 ipmi::registerHandler(ipmi::prioOpenBmcBase, ipmi::netFnApp, 1705 ipmi::app::cmdSetSystemInfoParameters, 1706 ipmi::Privilege::Admin, ipmiAppSetSystemInfo); 1707 return; 1708 } 1709