1 #include "chassishandler.h" 2 #include "host-ipmid/ipmid-api.h" 3 #include "types.hpp" 4 #include "ipmid.hpp" 5 #include "settings.hpp" 6 #include "utils.hpp" 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <stdint.h> 11 #include <mapper.h> 12 #include <arpa/inet.h> 13 #include <netinet/in.h> 14 #include <limits.h> 15 #include <string.h> 16 #include <endian.h> 17 #include <sstream> 18 #include <array> 19 #include <fstream> 20 #include <experimental/filesystem> 21 #include <string> 22 #include <map> 23 24 #include <phosphor-logging/log.hpp> 25 #include <phosphor-logging/elog-errors.hpp> 26 #include <xyz/openbmc_project/State/Host/server.hpp> 27 #include "xyz/openbmc_project/Common/error.hpp" 28 29 #include <sdbusplus/bus.hpp> 30 #include <sdbusplus/server/object.hpp> 31 #include <xyz/openbmc_project/Control/Boot/Source/server.hpp> 32 #include <xyz/openbmc_project/Control/Boot/Mode/server.hpp> 33 #include <xyz/openbmc_project/Control/Power/RestorePolicy/server.hpp> 34 35 #include "config.h" 36 37 //Defines 38 #define SET_PARM_VERSION 0x01 39 #define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 //boot flags data1 7th bit on 40 #define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 //boot flags data1 8th bit on 41 #define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 //boot flags data1 7 & 8 bit on 42 43 constexpr size_t SIZE_MAC = 18; 44 constexpr size_t SIZE_BOOT_OPTION = (uint8_t)BootOptionResponseSize:: 45 OPAL_NETWORK_SETTINGS;//Maximum size of the boot option parametrs 46 constexpr size_t SIZE_PREFIX = 7; 47 constexpr size_t MAX_PREFIX_VALUE = 32; 48 constexpr size_t SIZE_COOKIE = 4; 49 constexpr size_t SIZE_VERSION = 2; 50 51 //PetiBoot-Specific 52 static constexpr uint8_t net_conf_initial_bytes[] = {0x80, 0x21, 0x70, 0x62, 53 0x21, 0x00, 0x01, 0x06}; 54 55 static constexpr size_t COOKIE_OFFSET = 1; 56 static constexpr size_t VERSION_OFFSET = 5; 57 static constexpr size_t ADDR_SIZE_OFFSET = 8; 58 static constexpr size_t MAC_OFFSET = 9; 59 static constexpr size_t ADDRTYPE_OFFSET = 16; 60 static constexpr size_t IPADDR_OFFSET = 17; 61 62 63 void register_netfn_chassis_functions() __attribute__((constructor)); 64 65 // Host settings in dbus 66 // Service name should be referenced by connection name got via object mapper 67 const char *settings_object_name = "/org/openbmc/settings/host0"; 68 const char *settings_intf_name = "org.freedesktop.DBus.Properties"; 69 const char *host_intf_name = "org.openbmc.settings.Host"; 70 71 constexpr auto SETTINGS_ROOT = "/"; 72 constexpr auto SETTINGS_MATCH = "host0"; 73 74 constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP"; 75 constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress"; 76 77 78 typedef struct 79 { 80 uint8_t cap_flags; 81 uint8_t fru_info_dev_addr; 82 uint8_t sdr_dev_addr; 83 uint8_t sel_dev_addr; 84 uint8_t system_management_dev_addr; 85 uint8_t bridge_dev_addr; 86 }__attribute__((packed)) ipmi_chassis_cap_t; 87 88 typedef struct 89 { 90 uint8_t cur_power_state; 91 uint8_t last_power_event; 92 uint8_t misc_power_state; 93 uint8_t front_panel_button_cap_status; 94 }__attribute__((packed)) ipmi_get_chassis_status_t; 95 96 // Phosphor Host State manager 97 namespace State = sdbusplus::xyz::openbmc_project::State::server; 98 99 namespace fs = std::experimental::filesystem; 100 101 using namespace phosphor::logging; 102 using namespace sdbusplus::xyz::openbmc_project::Common::Error; 103 104 namespace chassis 105 { 106 namespace internal 107 { 108 109 constexpr auto bootModeIntf = "xyz.openbmc_project.Control.Boot.Mode"; 110 constexpr auto bootSourceIntf = "xyz.openbmc_project.Control.Boot.Source"; 111 constexpr auto powerRestoreIntf = 112 "xyz.openbmc_project.Control.Power.RestorePolicy"; 113 sdbusplus::bus::bus dbus(ipmid_get_sd_bus_connection()); 114 115 namespace cache 116 { 117 118 settings::Objects objects(dbus, 119 {bootModeIntf, bootSourceIntf, powerRestoreIntf}); 120 121 } // namespace cache 122 } // namespace internal 123 } // namespace chassis 124 125 //TODO : Can remove the below function as we have 126 // new functions which uses sdbusplus. 127 // 128 // openbmc/openbmc#1489 129 int dbus_get_property(const char *name, char **buf) 130 { 131 sd_bus_error error = SD_BUS_ERROR_NULL; 132 sd_bus_message *m = NULL; 133 sd_bus *bus = NULL; 134 char *temp_buf = NULL; 135 char *connection = NULL; 136 int r; 137 138 // Get the system bus where most system services are provided. 139 bus = ipmid_get_sd_bus_connection(); 140 141 r = mapper_get_service(bus, settings_object_name, &connection); 142 if (r < 0) { 143 fprintf(stderr, "Failed to get %s connection: %s\n", 144 settings_object_name, strerror(-r)); 145 goto finish; 146 } 147 148 /* 149 * Bus, service, object path, interface and method are provided to call 150 * the method. 151 * Signatures and input arguments are provided by the arguments at the 152 * end. 153 */ 154 r = sd_bus_call_method(bus, 155 connection, /* service to contact */ 156 settings_object_name, /* object path */ 157 settings_intf_name, /* interface name */ 158 "Get", /* method name */ 159 &error, /* object to return error in */ 160 &m, /* return message on success */ 161 "ss", /* input signature */ 162 host_intf_name, /* first argument */ 163 name); /* second argument */ 164 165 if (r < 0) { 166 fprintf(stderr, "Failed to issue method call: %s\n", error.message); 167 goto finish; 168 } 169 170 /* 171 * The output should be parsed exactly the same as the output formatting 172 * specified. 173 */ 174 r = sd_bus_message_read(m, "v", "s", &temp_buf); 175 if (r < 0) { 176 fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r)); 177 goto finish; 178 } 179 180 *buf = strdup(temp_buf); 181 /* *buf = (char*) malloc(strlen(temp_buf)); 182 if (*buf) { 183 strcpy(*buf, temp_buf); 184 } 185 */ 186 printf("IPMID boot option property get: {%s}.\n", (char *) temp_buf); 187 188 finish: 189 sd_bus_error_free(&error); 190 sd_bus_message_unref(m); 191 free(connection); 192 193 return r; 194 } 195 196 //TODO : Can remove the below function as we have 197 // new functions which uses sdbusplus. 198 // 199 // openbmc/openbmc#1489 200 201 int dbus_set_property(const char * name, const char *value) 202 { 203 sd_bus_error error = SD_BUS_ERROR_NULL; 204 sd_bus_message *m = NULL; 205 sd_bus *bus = NULL; 206 char *connection = NULL; 207 int r; 208 209 // Get the system bus where most system services are provided. 210 bus = ipmid_get_sd_bus_connection(); 211 212 r = mapper_get_service(bus, settings_object_name, &connection); 213 if (r < 0) { 214 fprintf(stderr, "Failed to get %s connection: %s\n", 215 settings_object_name, strerror(-r)); 216 goto finish; 217 } 218 219 /* 220 * Bus, service, object path, interface and method are provided to call 221 * the method. 222 * Signatures and input arguments are provided by the arguments at the 223 * end. 224 */ 225 r = sd_bus_call_method(bus, 226 connection, /* service to contact */ 227 settings_object_name, /* object path */ 228 settings_intf_name, /* interface name */ 229 "Set", /* method name */ 230 &error, /* object to return error in */ 231 &m, /* return message on success */ 232 "ssv", /* input signature */ 233 host_intf_name, /* first argument */ 234 name, /* second argument */ 235 "s", /* third argument */ 236 value); /* fourth argument */ 237 238 if (r < 0) { 239 fprintf(stderr, "Failed to issue method call: %s\n", error.message); 240 goto finish; 241 } 242 243 printf("IPMID boot option property set: {%s}.\n", value); 244 245 finish: 246 sd_bus_error_free(&error); 247 sd_bus_message_unref(m); 248 free(connection); 249 250 return r; 251 } 252 253 struct get_sys_boot_options_t { 254 uint8_t parameter; 255 uint8_t set; 256 uint8_t block; 257 } __attribute__ ((packed)); 258 259 struct get_sys_boot_options_response_t { 260 uint8_t version; 261 uint8_t parm; 262 uint8_t data[SIZE_BOOT_OPTION]; 263 } __attribute__ ((packed)); 264 265 struct set_sys_boot_options_t { 266 uint8_t parameter; 267 uint8_t data[SIZE_BOOT_OPTION]; 268 } __attribute__ ((packed)); 269 270 271 int getHostNetworkData(get_sys_boot_options_response_t* respptr) 272 { 273 ipmi::PropertyMap properties; 274 int rc = 0; 275 uint8_t addrSize = ipmi::network::IPV4_ADDRESS_SIZE_BYTE; 276 277 try 278 { 279 //TODO There may be cases where an interface is implemented by multiple 280 // objects,to handle such cases we are interested on that object 281 // which are on interested busname. 282 // Currenlty mapper doesn't give the readable busname(gives busid) 283 // so we can't match with bus name so giving some object specific info 284 // as SETTINGS_MATCH. 285 // Later SETTINGS_MATCH will be replaced with busname. 286 287 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 288 289 auto ipObjectInfo = ipmi::getDbusObject(bus, IP_INTERFACE, 290 SETTINGS_ROOT, SETTINGS_MATCH); 291 292 auto macObjectInfo = ipmi::getDbusObject(bus, MAC_INTERFACE, 293 SETTINGS_ROOT, SETTINGS_MATCH); 294 295 properties = ipmi::getAllDbusProperties(bus, ipObjectInfo.second, 296 ipObjectInfo.first, IP_INTERFACE); 297 auto variant = 298 ipmi::getDbusProperty(bus, macObjectInfo.second, 299 macObjectInfo.first, 300 MAC_INTERFACE, "MACAddress"); 301 302 auto ipAddress = properties["Address"].get<std::string>(); 303 304 auto gateway = properties["Gateway"].get<std::string>(); 305 306 auto prefix = properties["PrefixLength"].get<uint8_t>(); 307 308 uint8_t isStatic = (properties["Origin"].get<std::string>() == 309 "xyz.openbmc_project.Network.IP.AddressOrigin.Static") 310 ? 1 : 0; 311 312 auto MACAddress = variant.get<std::string>(); 313 314 // it is expected here that we should get the valid data 315 // but we may also get the default values. 316 // Validation of the data is done by settings. 317 // 318 // if mac address is default mac address then 319 // don't send blank override. 320 if ((MACAddress == ipmi::network::DEFAULT_MAC_ADDRESS)) 321 { 322 memset(respptr->data, 0, SIZE_BOOT_OPTION); 323 rc = -1; 324 return rc; 325 } 326 // if addr is static then ipaddress,gateway,prefix 327 // should not be default one,don't send blank override. 328 if (isStatic) 329 { 330 if((ipAddress == ipmi::network::DEFAULT_ADDRESS) || 331 (gateway == ipmi::network::DEFAULT_ADDRESS) || 332 (!prefix)) 333 { 334 memset(respptr->data, 0, SIZE_BOOT_OPTION); 335 rc = -1; 336 return rc; 337 } 338 } 339 340 sscanf(MACAddress.c_str(), ipmi::network::MAC_ADDRESS_FORMAT, 341 (respptr->data + MAC_OFFSET), 342 (respptr->data + MAC_OFFSET + 1), 343 (respptr->data + MAC_OFFSET + 2), 344 (respptr->data + MAC_OFFSET + 3), 345 (respptr->data + MAC_OFFSET + 4), 346 (respptr->data + MAC_OFFSET + 5)); 347 348 respptr->data[MAC_OFFSET + 6] = 0x00; 349 350 memcpy(respptr->data + ADDRTYPE_OFFSET, &isStatic, 351 sizeof(isStatic)); 352 353 uint8_t addressFamily = (properties["Type"].get<std::string>() == 354 "xyz.openbmc_project.Network.IP.Protocol.IPv4") ? 355 AF_INET : AF_INET6; 356 357 addrSize = (addressFamily == AF_INET) ? 358 ipmi::network::IPV4_ADDRESS_SIZE_BYTE : 359 ipmi::network::IPV6_ADDRESS_SIZE_BYTE; 360 361 // ipaddress and gateway would be in IPv4 format 362 inet_pton(addressFamily, ipAddress.c_str(), 363 (respptr->data + IPADDR_OFFSET)); 364 365 uint8_t prefixOffset = IPADDR_OFFSET + addrSize; 366 367 memcpy(respptr->data + prefixOffset, &prefix, sizeof(prefix)); 368 369 uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix)); 370 371 inet_pton(addressFamily, gateway.c_str(), 372 (respptr->data + gatewayOffset)); 373 374 } 375 catch (InternalFailure& e) 376 { 377 commit<InternalFailure>(); 378 memset(respptr->data, 0, SIZE_BOOT_OPTION); 379 rc = -1; 380 return rc; 381 } 382 383 //PetiBoot-Specific 384 //If success then copy the first 9 bytes to the data 385 memcpy(respptr->data, net_conf_initial_bytes, 386 sizeof(net_conf_initial_bytes)); 387 388 memcpy(respptr->data + ADDR_SIZE_OFFSET, &addrSize, sizeof(addrSize)); 389 390 #ifdef _IPMI_DEBUG_ 391 printf("\n===Printing the IPMI Formatted Data========\n"); 392 393 for (uint8_t pos = 0; pos < index; pos++) 394 { 395 printf("%02x ", respptr->data[pos]); 396 } 397 #endif 398 399 return rc; 400 } 401 402 /** @brief convert IPv4 and IPv6 addresses from binary to text form. 403 * @param[in] family - IPv4/Ipv6 404 * @param[in] data - req data pointer. 405 * @param[in] offset - offset in the data. 406 * @param[in] addrSize - size of the data which needs to be read from offset. 407 * @returns address in text form. 408 */ 409 410 std::string getAddrStr(uint8_t family, uint8_t* data, 411 uint8_t offset, uint8_t addrSize) 412 { 413 char ipAddr[INET6_ADDRSTRLEN] = {}; 414 415 switch(family) 416 { 417 case AF_INET: 418 { 419 struct sockaddr_in addr4 {}; 420 memcpy(&addr4.sin_addr.s_addr, &data[offset], addrSize); 421 422 inet_ntop(AF_INET, &addr4.sin_addr, 423 ipAddr, INET_ADDRSTRLEN); 424 425 break; 426 } 427 case AF_INET6: 428 { 429 struct sockaddr_in6 addr6 {}; 430 memcpy(&addr6.sin6_addr.s6_addr, &data[offset], addrSize); 431 432 inet_ntop(AF_INET6, &addr6.sin6_addr, 433 ipAddr, INET6_ADDRSTRLEN); 434 435 break; 436 } 437 default: 438 { 439 return {}; 440 } 441 } 442 443 return ipAddr; 444 } 445 446 int setHostNetworkData(set_sys_boot_options_t* reqptr) 447 { 448 using namespace std::string_literals; 449 std::string host_network_config; 450 char mac[] {"00:00:00:00:00:00"}; 451 std::string ipAddress, gateway; 452 char addrOrigin {0}; 453 uint8_t addrSize {0}; 454 std::string addressOrigin = 455 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP"; 456 std::string addressType = 457 "xyz.openbmc_project.Network.IP.Protocol.IPv4"; 458 uint8_t prefix {0}; 459 uint32_t zeroCookie = 0; 460 uint8_t family = AF_INET; 461 462 //cookie starts from second byte 463 // version starts from sixth byte 464 465 try 466 { 467 do 468 { 469 // cookie == 0x21 0x70 0x62 0x21 470 if (memcmp(&(reqptr->data[COOKIE_OFFSET]), 471 (net_conf_initial_bytes + COOKIE_OFFSET), 472 SIZE_COOKIE) != 0) 473 { 474 //cookie == 0 475 if (memcmp(&(reqptr->data[COOKIE_OFFSET]), 476 &zeroCookie, 477 SIZE_COOKIE) == 0) 478 { 479 // need to zero out the network settings. 480 break; 481 } 482 483 log<level::ERR>("Invalid Cookie"); 484 elog<InternalFailure>(); 485 } 486 487 // vesion == 0x00 0x01 488 if (memcmp(&(reqptr->data[VERSION_OFFSET]), 489 (net_conf_initial_bytes + VERSION_OFFSET), 490 SIZE_VERSION) != 0) 491 { 492 493 log<level::ERR>("Invalid Version"); 494 elog<InternalFailure>(); 495 } 496 497 snprintf(mac, SIZE_MAC, ipmi::network::MAC_ADDRESS_FORMAT, 498 reqptr->data[MAC_OFFSET], 499 reqptr->data[MAC_OFFSET + 1], 500 reqptr->data[MAC_OFFSET + 2], 501 reqptr->data[MAC_OFFSET + 3], 502 reqptr->data[MAC_OFFSET + 4], 503 reqptr->data[MAC_OFFSET + 5]); 504 505 memcpy(&addrOrigin, &(reqptr->data[ADDRTYPE_OFFSET]), 506 sizeof(decltype(addrOrigin))); 507 508 if (addrOrigin) 509 { 510 addressOrigin = 511 "xyz.openbmc_project.Network.IP.AddressOrigin.Static"; 512 } 513 514 // Get the address size 515 memcpy(&addrSize ,&reqptr->data[ADDR_SIZE_OFFSET], sizeof(addrSize)); 516 517 uint8_t prefixOffset = IPADDR_OFFSET + addrSize; 518 519 memcpy(&prefix, &(reqptr->data[prefixOffset]), 520 sizeof(decltype(prefix))); 521 522 uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix)); 523 524 if (addrSize != ipmi::network::IPV4_ADDRESS_SIZE_BYTE) 525 { 526 addressType = "xyz.openbmc_project.Network.IP.Protocol.IPv6"; 527 family = AF_INET6; 528 } 529 530 ipAddress = getAddrStr(family, reqptr->data, IPADDR_OFFSET, addrSize); 531 532 gateway = getAddrStr(family, reqptr->data, gatewayOffset, addrSize); 533 534 } while(0); 535 536 //Cookie == 0 or it is a valid cookie 537 host_network_config += "ipaddress="s + ipAddress + 538 ",prefix="s + std::to_string(prefix) + ",gateway="s + gateway + 539 ",mac="s + mac + ",addressOrigin="s + addressOrigin; 540 541 542 sdbusplus::bus::bus bus(ipmid_get_sd_bus_connection()); 543 544 auto ipObjectInfo = ipmi::getDbusObject(bus, IP_INTERFACE, 545 SETTINGS_ROOT, SETTINGS_MATCH); 546 auto macObjectInfo = ipmi::getDbusObject(bus, MAC_INTERFACE, 547 SETTINGS_ROOT, SETTINGS_MATCH); 548 // set the dbus property 549 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 550 IP_INTERFACE, "Address", std::string(ipAddress)); 551 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 552 IP_INTERFACE, "PrefixLength", prefix); 553 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 554 IP_INTERFACE, "Origin", addressOrigin); 555 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 556 IP_INTERFACE, "Gateway", std::string(gateway)); 557 ipmi::setDbusProperty(bus, ipObjectInfo.second, ipObjectInfo.first, 558 IP_INTERFACE, "Type", 559 std::string("xyz.openbmc_project.Network.IP.Protocol.IPv4")); 560 ipmi::setDbusProperty(bus, macObjectInfo.second, macObjectInfo.first, 561 MAC_INTERFACE,"MACAddress", std::string(mac)); 562 563 log<level::DEBUG>("Network configuration changed", 564 entry("NETWORKCONFIG=%s", host_network_config.c_str())); 565 566 } 567 catch (InternalFailure& e) 568 { 569 commit<InternalFailure>(); 570 return -1; 571 } 572 573 return 0; 574 } 575 576 ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 577 ipmi_request_t request, 578 ipmi_response_t response, 579 ipmi_data_len_t data_len, 580 ipmi_context_t context) 581 { 582 printf("Handling CHASSIS WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd); 583 // Status code. 584 ipmi_ret_t rc = IPMI_CC_INVALID; 585 *data_len = 0; 586 return rc; 587 } 588 589 ipmi_ret_t ipmi_get_chassis_cap(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 590 ipmi_request_t request, ipmi_response_t response, 591 ipmi_data_len_t data_len, ipmi_context_t context) 592 { 593 // sd_bus error 594 ipmi_ret_t rc = IPMI_CC_OK; 595 596 ipmi_chassis_cap_t chassis_cap{}; 597 598 *data_len = sizeof(ipmi_chassis_cap_t); 599 600 // TODO: need future work. Get those flag from MRW. 601 602 // capabilities flags 603 // [7..4] - reserved 604 // [3] – 1b = provides power interlock (IPM 1.5) 605 // [2] – 1b = provides Diagnostic Interrupt (FP NMI) 606 // [1] – 1b = provides “Front Panel Lockout” (indicates that the chassis has capabilities 607 // to lock out external power control and reset button or front panel interfaces 608 // and/or detect tampering with those interfaces). 609 // [0] -1b = Chassis provides intrusion (physical security) sensor. 610 // set to default value 0x0. 611 chassis_cap.cap_flags = 0x0; 612 613 // Since we do not have a separate SDR Device/SEL Device/ FRU repository. 614 // The 20h was given as those 5 device addresses. 615 // Chassis FRU info Device Address 616 chassis_cap.fru_info_dev_addr = 0x20; 617 618 // Chassis SDR Device Address 619 chassis_cap.sdr_dev_addr = 0x20; 620 621 // Chassis SEL Device Address 622 chassis_cap.sel_dev_addr = 0x20; 623 624 // Chassis System Management Device Address 625 chassis_cap.system_management_dev_addr = 0x20; 626 627 // Chassis Bridge Device Address. 628 chassis_cap.bridge_dev_addr = 0x20; 629 630 memcpy(response, &chassis_cap, *data_len); 631 632 return rc; 633 } 634 635 //------------------------------------------ 636 // Calls into Host State Manager Dbus object 637 //------------------------------------------ 638 int initiate_state_transition(State::Host::Transition transition) 639 { 640 // OpenBMC Host State Manager dbus framework 641 constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0"; 642 constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host"; 643 constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties"; 644 constexpr auto PROPERTY = "RequestedHostTransition"; 645 646 // sd_bus error 647 int rc = 0; 648 char *busname = NULL; 649 650 // SD Bus error report mechanism. 651 sd_bus_error bus_error = SD_BUS_ERROR_NULL; 652 653 // Gets a hook onto either a SYSTEM or SESSION bus 654 sd_bus *bus_type = ipmid_get_sd_bus_connection(); 655 rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname); 656 if (rc < 0) 657 { 658 log<level::ERR>("Failed to get bus name", 659 entry("ERROR=%s, OBJPATH=%s", 660 strerror(-rc), HOST_STATE_MANAGER_ROOT)); 661 return rc; 662 } 663 664 // Convert to string equivalent of the passed in transition enum. 665 auto request = State::convertForMessage(transition); 666 667 rc = sd_bus_call_method(bus_type, // On the system bus 668 busname, // Service to contact 669 HOST_STATE_MANAGER_ROOT, // Object path 670 DBUS_PROPERTY_IFACE, // Interface name 671 "Set", // Method to be called 672 &bus_error, // object to return error 673 nullptr, // Response buffer if any 674 "ssv", // Takes 3 arguments 675 HOST_STATE_MANAGER_IFACE, 676 PROPERTY, 677 "s", request.c_str()); 678 if(rc < 0) 679 { 680 log<level::ERR>("Failed to initiate transition", 681 entry("ERROR=%s, REQUEST=%s", 682 bus_error.message, request.c_str())); 683 } 684 else 685 { 686 log<level::INFO>("Transition request initiated successfully"); 687 } 688 689 sd_bus_error_free(&bus_error); 690 free(busname); 691 692 return rc; 693 } 694 695 namespace power_policy 696 { 697 698 using namespace sdbusplus::xyz::openbmc_project::Control::Power::server; 699 using IpmiValue = uint8_t; 700 using DbusValue = RestorePolicy::Policy; 701 702 std::map<DbusValue, IpmiValue> dbusToIpmi = 703 { 704 {RestorePolicy::Policy::AlwaysOff, 0x00}, 705 {RestorePolicy::Policy::Restore, 0x01}, 706 {RestorePolicy::Policy::AlwaysOn, 0x02} 707 }; 708 709 } // namespace power_policy 710 711 //---------------------------------------------------------------------- 712 // Get Chassis Status commands 713 //---------------------------------------------------------------------- 714 ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 715 ipmi_request_t request, 716 ipmi_response_t response, 717 ipmi_data_len_t data_len, 718 ipmi_context_t context) 719 { 720 const char *objname = "/org/openbmc/control/power0"; 721 const char *intf = "org.openbmc.control.Power"; 722 723 sd_bus *bus = NULL; 724 sd_bus_message *reply = NULL; 725 int r = 0; 726 int pgood = 0; 727 char *busname = NULL; 728 ipmi_ret_t rc = IPMI_CC_OK; 729 ipmi_get_chassis_status_t chassis_status{}; 730 731 uint8_t s = 0; 732 733 using namespace chassis::internal; 734 using namespace chassis::internal::cache; 735 using namespace power_policy; 736 737 const auto& powerRestoreSetting = objects.map.at(powerRestoreIntf).front(); 738 auto method = 739 dbus.new_method_call( 740 objects.service(powerRestoreSetting, powerRestoreIntf).c_str(), 741 powerRestoreSetting.c_str(), 742 ipmi::PROP_INTF, 743 "Get"); 744 method.append(powerRestoreIntf, "PowerRestorePolicy"); 745 auto resp = dbus.call(method); 746 if (resp.is_method_error()) 747 { 748 log<level::ERR>("Error in PowerRestorePolicy Get"); 749 report<InternalFailure>(); 750 *data_len = 0; 751 return IPMI_CC_UNSPECIFIED_ERROR; 752 } 753 sdbusplus::message::variant<std::string> result; 754 resp.read(result); 755 auto powerRestore = 756 RestorePolicy::convertPolicyFromString(result.get<std::string>()); 757 758 *data_len = 4; 759 760 bus = ipmid_get_sd_bus_connection(); 761 762 r = mapper_get_service(bus, objname, &busname); 763 if (r < 0) { 764 fprintf(stderr, "Failed to get bus name, return value: %s.\n", strerror(-r)); 765 rc = IPMI_CC_UNSPECIFIED_ERROR; 766 goto finish; 767 } 768 769 r = sd_bus_get_property(bus, busname, objname, intf, "pgood", NULL, &reply, "i"); 770 if (r < 0) { 771 fprintf(stderr, "Failed to call sd_bus_get_property:%d, %s\n", r, strerror(-r)); 772 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n", 773 busname, objname, intf); 774 rc = IPMI_CC_UNSPECIFIED_ERROR; 775 goto finish; 776 } 777 778 r = sd_bus_message_read(reply, "i", &pgood); 779 if (r < 0) { 780 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r)); 781 rc = IPMI_CC_UNSPECIFIED_ERROR; 782 goto finish; 783 } 784 785 printf("pgood is 0x%02x\n", pgood); 786 787 s = dbusToIpmi.at(powerRestore); 788 789 // Current Power State 790 // [7] reserved 791 // [6..5] power restore policy 792 // 00b = chassis stays powered off after AC/mains returns 793 // 01b = after AC returns, power is restored to the state that was 794 // in effect when AC/mains was lost. 795 // 10b = chassis always powers up after AC/mains returns 796 // 11b = unknow 797 // Set to 00b, by observing the hardware behavior. 798 // Do we need to define a dbus property to identify the restore policy? 799 800 // [4] power control fault 801 // 1b = controller attempted to turn system power on or off, but 802 // system did not enter desired state. 803 // Set to 0b, since We don't support it.. 804 805 // [3] power fault 806 // 1b = fault detected in main power subsystem. 807 // set to 0b. for we don't support it. 808 809 // [2] 1b = interlock (chassis is presently shut down because a chassis 810 // panel interlock switch is active). (IPMI 1.5) 811 // set to 0b, for we don't support it. 812 813 // [1] power overload 814 // 1b = system shutdown because of power overload condition. 815 // set to 0b, for we don't support it. 816 817 // [0] power is on 818 // 1b = system power is on 819 // 0b = system power is off(soft-off S4/S5, or mechanical off) 820 821 chassis_status.cur_power_state = ((s & 0x3)<<5) | (pgood & 0x1); 822 823 // Last Power Event 824 // [7..5] – reserved 825 // [4] – 1b = last ‘Power is on’ state was entered via IPMI command 826 // [3] – 1b = last power down caused by power fault 827 // [2] – 1b = last power down caused by a power interlock being activated 828 // [1] – 1b = last power down caused by a Power overload 829 // [0] – 1b = AC failed 830 // set to 0x0, for we don't support these fields. 831 832 chassis_status.last_power_event = 0; 833 834 // Misc. Chassis State 835 // [7] – reserved 836 // [6] – 1b = Chassis Identify command and state info supported (Optional) 837 // 0b = Chassis Identify command support unspecified via this command. 838 // (The Get Command Support command , if implemented, would still 839 // indicate support for the Chassis Identify command) 840 // [5..4] – Chassis Identify State. Mandatory when bit[6] =1b, reserved (return 841 // as 00b) otherwise. Returns the present chassis identify state. 842 // Refer to the Chassis Identify command for more info. 843 // 00b = chassis identify state = Off 844 // 01b = chassis identify state = Temporary(timed) On 845 // 10b = chassis identify state = Indefinite On 846 // 11b = reserved 847 // [3] – 1b = Cooling/fan fault detected 848 // [2] – 1b = Drive Fault 849 // [1] – 1b = Front Panel Lockout active (power off and reset via chassis 850 // push-buttons disabled.) 851 // [0] – 1b = Chassis Intrusion active 852 // set to 0, for we don't support them. 853 chassis_status.misc_power_state = 0; 854 855 // Front Panel Button Capabilities and disable/enable status(Optional) 856 // set to 0, for we don't support them. 857 chassis_status.front_panel_button_cap_status = 0; 858 859 // Pack the actual response 860 memcpy(response, &chassis_status, *data_len); 861 862 finish: 863 free(busname); 864 reply = sd_bus_message_unref(reply); 865 866 return rc; 867 } 868 869 //------------------------------------------------------------- 870 // Send a command to SoftPowerOff application to stop any timer 871 //------------------------------------------------------------- 872 int stop_soft_off_timer() 873 { 874 constexpr auto iface = "org.freedesktop.DBus.Properties"; 875 constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal." 876 "SoftPowerOff"; 877 878 constexpr auto property = "ResponseReceived"; 879 constexpr auto value = "xyz.openbmc_project.Ipmi.Internal." 880 "SoftPowerOff.HostResponse.HostShutdown"; 881 882 // Get the system bus where most system services are provided. 883 auto bus = ipmid_get_sd_bus_connection(); 884 885 // Get the service name 886 // TODO openbmc/openbmc#1661 - Mapper refactor 887 // 888 // See openbmc/openbmc#1743 for some details but high level summary is that 889 // for now the code will directly call the soft off interface due to a 890 // race condition with mapper usage 891 // 892 //char *busname = nullptr; 893 //auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname); 894 //if (r < 0) 895 //{ 896 // fprintf(stderr, "Failed to get %s bus name: %s\n", 897 // SOFTOFF_OBJPATH, strerror(-r)); 898 // return r; 899 //} 900 901 // No error object or reply expected. 902 int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface, 903 "Set", nullptr, nullptr, "ssv", 904 soft_off_iface, property, "s", value); 905 if (rc < 0) 906 { 907 fprintf(stderr, "Failed to set property in SoftPowerOff object: %s\n", 908 strerror(-rc)); 909 } 910 911 //TODO openbmc/openbmc#1661 - Mapper refactor 912 //free(busname); 913 return rc; 914 } 915 916 //---------------------------------------------------------------------- 917 // Create file to indicate there is no need for softoff notification to host 918 //---------------------------------------------------------------------- 919 void indicate_no_softoff_needed() 920 { 921 fs::path path{HOST_INBAND_REQUEST_DIR}; 922 if (!fs::is_directory(path)) 923 { 924 fs::create_directory(path); 925 } 926 927 // Add the host instance (default 0 for now) to the file name 928 std::string file{HOST_INBAND_REQUEST_FILE}; 929 auto size = std::snprintf(nullptr,0,file.c_str(),0); 930 size++; // null 931 std::unique_ptr<char[]> buf(new char[size]); 932 std::snprintf(buf.get(),size,file.c_str(),0); 933 934 // Append file name to directory and create it 935 path /= buf.get(); 936 std::ofstream(path.c_str()); 937 } 938 939 //---------------------------------------------------------------------- 940 // Chassis Control commands 941 //---------------------------------------------------------------------- 942 ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 943 ipmi_request_t request, 944 ipmi_response_t response, 945 ipmi_data_len_t data_len, 946 ipmi_context_t context) 947 { 948 // Error from power off. 949 int rc = 0; 950 951 // No response for this command. 952 *data_len = 0; 953 954 // Catch the actual operaton by peeking into request buffer 955 uint8_t chassis_ctrl_cmd = *(uint8_t *)request; 956 printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd); 957 958 switch(chassis_ctrl_cmd) 959 { 960 case CMD_POWER_ON: 961 rc = initiate_state_transition(State::Host::Transition::On); 962 break; 963 case CMD_POWER_OFF: 964 // This path would be hit in 2 conditions. 965 // 1: When user asks for power off using ipmi chassis command 0x04 966 // 2: Host asking for power off post shutting down. 967 968 // If it's a host requested power off, then need to nudge Softoff 969 // application that it needs to stop the watchdog timer if running. 970 // If it is a user requested power off, then this is not really 971 // needed. But then we need to differentiate between user and host 972 // calling this same command 973 974 // For now, we are going ahead with trying to nudge the soft off and 975 // interpret the failure to do so as a non softoff case 976 rc = stop_soft_off_timer(); 977 978 // Only request the Off transition if the soft power off 979 // application is not running 980 if (rc < 0) 981 { 982 // First create a file to indicate to the soft off application 983 // that it should not run. Not doing this will result in State 984 // manager doing a default soft power off when asked for power 985 // off. 986 indicate_no_softoff_needed(); 987 988 // Now request the shutdown 989 rc = initiate_state_transition(State::Host::Transition::Off); 990 } 991 else 992 { 993 log<level::INFO>("Soft off is running, so let shutdown target " 994 "stop the host"); 995 } 996 break; 997 998 case CMD_HARD_RESET: 999 case CMD_POWER_CYCLE: 1000 // SPEC has a section that says certain implementations can trigger 1001 // PowerOn if power is Off when a command to power cycle is 1002 // requested 1003 1004 // First create a file to indicate to the soft off application 1005 // that it should not run since this is a direct user initiated 1006 // power reboot request (i.e. a reboot request that is not 1007 // originating via a soft power off SMS request) 1008 indicate_no_softoff_needed(); 1009 1010 rc = initiate_state_transition(State::Host::Transition::Reboot); 1011 break; 1012 1013 case CMD_SOFT_OFF_VIA_OVER_TEMP: 1014 // Request Host State Manager to do a soft power off 1015 rc = initiate_state_transition(State::Host::Transition::Off); 1016 break; 1017 1018 default: 1019 { 1020 fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd); 1021 rc = -1; 1022 } 1023 } 1024 1025 return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK); 1026 } 1027 1028 namespace boot_options 1029 { 1030 1031 using namespace sdbusplus::xyz::openbmc_project::Control::Boot::server; 1032 using IpmiValue = uint8_t; 1033 constexpr auto ipmiDefault = 0; 1034 1035 std::map<IpmiValue, Source::Sources> sourceIpmiToDbus = 1036 { 1037 {0x01, Source::Sources::Network}, 1038 {0x02, Source::Sources::Disk}, 1039 {0x05, Source::Sources::ExternalMedia}, 1040 {ipmiDefault, Source::Sources::Default} 1041 }; 1042 1043 std::map<IpmiValue, Mode::Modes> modeIpmiToDbus = 1044 { 1045 {0x03, Mode::Modes::Safe}, 1046 {0x06, Mode::Modes::Setup}, 1047 {ipmiDefault, Mode::Modes::Regular} 1048 }; 1049 1050 std::map<Source::Sources, IpmiValue> sourceDbusToIpmi = 1051 { 1052 {Source::Sources::Network, 0x01}, 1053 {Source::Sources::Disk, 0x02}, 1054 {Source::Sources::ExternalMedia, 0x05}, 1055 {Source::Sources::Default, ipmiDefault} 1056 }; 1057 1058 std::map<Mode::Modes, IpmiValue> modeDbusToIpmi = 1059 { 1060 {Mode::Modes::Safe, 0x03}, 1061 {Mode::Modes::Setup, 0x06}, 1062 {Mode::Modes::Regular, ipmiDefault} 1063 }; 1064 1065 } // namespace boot_options 1066 1067 ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1068 ipmi_request_t request, 1069 ipmi_response_t response, 1070 ipmi_data_len_t data_len, 1071 ipmi_context_t context) 1072 { 1073 using namespace boot_options; 1074 ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED; 1075 char *p = NULL; 1076 get_sys_boot_options_response_t *resp = (get_sys_boot_options_response_t *) response; 1077 get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request; 1078 IpmiValue bootOption = ipmiDefault; 1079 1080 printf("IPMI GET_SYS_BOOT_OPTIONS\n"); 1081 1082 memset(resp,0,sizeof(*resp)); 1083 resp->version = SET_PARM_VERSION; 1084 resp->parm = 5; 1085 resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME; 1086 1087 1088 /* 1089 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. 1090 * This is the only parameter used by petitboot. 1091 */ 1092 if ( reqptr->parameter == static_cast<uint8_t> 1093 ( BootOptionParameter::BOOT_FLAGS )) { 1094 1095 *data_len = static_cast<uint8_t>(BootOptionResponseSize::BOOT_FLAGS); 1096 using namespace chassis::internal; 1097 using namespace chassis::internal::cache; 1098 1099 try 1100 { 1101 auto bootSetting = settings::boot::setting(objects, bootSourceIntf); 1102 const auto& bootSourceSetting = 1103 std::get<settings::Path>(bootSetting); 1104 auto oneTimeEnabled = 1105 std::get<settings::boot::OneTimeEnabled>(bootSetting); 1106 auto method = 1107 dbus.new_method_call( 1108 objects.service(bootSourceSetting, bootSourceIntf).c_str(), 1109 bootSourceSetting.c_str(), 1110 ipmi::PROP_INTF, 1111 "Get"); 1112 method.append(bootSourceIntf, "BootSource"); 1113 auto reply = dbus.call(method); 1114 if (reply.is_method_error()) 1115 { 1116 log<level::ERR>("Error in BootSource Get"); 1117 report<InternalFailure>(); 1118 *data_len = 0; 1119 return IPMI_CC_UNSPECIFIED_ERROR; 1120 } 1121 sdbusplus::message::variant<std::string> result; 1122 reply.read(result); 1123 auto bootSource = 1124 Source::convertSourcesFromString(result.get<std::string>()); 1125 1126 bootSetting = settings::boot::setting(objects, bootModeIntf); 1127 const auto& bootModeSetting = std::get<settings::Path>(bootSetting); 1128 method = dbus.new_method_call( 1129 objects.service(bootModeSetting, bootModeIntf). 1130 c_str(), 1131 bootModeSetting.c_str(), 1132 ipmi::PROP_INTF, 1133 "Get"); 1134 method.append(bootModeIntf, "BootMode"); 1135 reply = dbus.call(method); 1136 if (reply.is_method_error()) 1137 { 1138 log<level::ERR>("Error in BootMode Get"); 1139 report<InternalFailure>(); 1140 *data_len = 0; 1141 return IPMI_CC_UNSPECIFIED_ERROR; 1142 } 1143 reply.read(result); 1144 auto bootMode = 1145 Mode::convertModesFromString(result.get<std::string>()); 1146 1147 bootOption = sourceDbusToIpmi.at(bootSource); 1148 if ((Mode::Modes::Regular == bootMode) && 1149 (Source::Sources::Default == bootSource)) 1150 { 1151 bootOption = ipmiDefault; 1152 } 1153 else if (Source::Sources::Default == bootSource) 1154 { 1155 bootOption = modeDbusToIpmi.at(bootMode); 1156 } 1157 resp->data[1] = (bootOption << 2); 1158 1159 resp->data[0] = oneTimeEnabled ? 1160 SET_PARM_BOOT_FLAGS_VALID_ONE_TIME: 1161 SET_PARM_BOOT_FLAGS_VALID_PERMANENT; 1162 1163 rc = IPMI_CC_OK; 1164 } 1165 catch (InternalFailure& e) 1166 { 1167 report<InternalFailure>(); 1168 *data_len = 0; 1169 return IPMI_CC_UNSPECIFIED_ERROR; 1170 } 1171 } else if ( reqptr->parameter == static_cast<uint8_t> 1172 ( BootOptionParameter::OPAL_NETWORK_SETTINGS )) { 1173 1174 *data_len = static_cast<uint8_t>(BootOptionResponseSize::OPAL_NETWORK_SETTINGS); 1175 1176 resp->parm = static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS); 1177 1178 int ret = getHostNetworkData(resp); 1179 1180 if (ret < 0) { 1181 1182 fprintf(stderr, "getHostNetworkData failed for get_sys_boot_options.\n"); 1183 rc = IPMI_CC_UNSPECIFIED_ERROR; 1184 1185 }else 1186 rc = IPMI_CC_OK; 1187 } 1188 1189 else { 1190 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter); 1191 } 1192 1193 if (p) 1194 free(p); 1195 1196 if (rc == IPMI_CC_OK) 1197 { 1198 *data_len += 2; 1199 } 1200 1201 return rc; 1202 } 1203 1204 1205 1206 ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd, 1207 ipmi_request_t request, 1208 ipmi_response_t response, 1209 ipmi_data_len_t data_len, 1210 ipmi_context_t context) 1211 { 1212 using namespace boot_options; 1213 ipmi_ret_t rc = IPMI_CC_OK; 1214 set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request; 1215 1216 printf("IPMI SET_SYS_BOOT_OPTIONS reqptr->parameter =[%d]\n",reqptr->parameter); 1217 1218 // This IPMI command does not have any resposne data 1219 *data_len = 0; 1220 1221 /* 000101 1222 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc. 1223 * This is the only parameter used by petitboot. 1224 */ 1225 1226 if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) 1227 { 1228 IpmiValue bootOption = ((reqptr->data[1] & 0x3C) >> 2); 1229 using namespace chassis::internal; 1230 using namespace chassis::internal::cache; 1231 auto oneTimeEnabled = false; 1232 constexpr auto enabledIntf = "xyz.openbmc_project.Object.Enable"; 1233 constexpr auto oneTimePath = 1234 "/xyz/openbmc_project/control/host0/boot/one_time"; 1235 1236 try 1237 { 1238 bool permanent = 1239 (reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) == 1240 SET_PARM_BOOT_FLAGS_PERMANENT; 1241 1242 auto bootSetting = 1243 settings::boot::setting(objects, bootSourceIntf); 1244 1245 oneTimeEnabled = 1246 std::get<settings::boot::OneTimeEnabled>(bootSetting); 1247 1248 /* 1249 * Check if the current boot setting is onetime or permanent, if the 1250 * request in the command is otherwise, then set the "Enabled" 1251 * property in one_time object path to 'True' to indicate onetime 1252 * and 'False' to indicate permanent. 1253 * 1254 * Once the onetime/permanent setting is applied, then the bootMode 1255 * and bootSource is updated for the corresponding object. 1256 */ 1257 if ((permanent && oneTimeEnabled) || 1258 (!permanent && !oneTimeEnabled)) 1259 { 1260 auto service = ipmi::getService(dbus, enabledIntf, oneTimePath); 1261 1262 ipmi::setDbusProperty(dbus, 1263 service, 1264 oneTimePath, 1265 enabledIntf, 1266 "Enabled", 1267 !permanent); 1268 } 1269 1270 auto modeItr = modeIpmiToDbus.find(bootOption); 1271 auto sourceItr = sourceIpmiToDbus.find(bootOption); 1272 if (sourceIpmiToDbus.end() != sourceItr) 1273 { 1274 sdbusplus::message::variant<std::string> property = 1275 convertForMessage(sourceItr->second); 1276 auto bootSetting = settings::boot::setting(objects, 1277 bootSourceIntf); 1278 const auto& bootSourceSetting = 1279 std::get<settings::Path>(bootSetting); 1280 auto method = 1281 dbus.new_method_call( 1282 objects.service(bootSourceSetting, bootSourceIntf). 1283 c_str(), 1284 bootSourceSetting.c_str(), 1285 ipmi::PROP_INTF, 1286 "Set"); 1287 method.append(bootSourceIntf, "BootSource", property); 1288 auto reply = dbus.call(method); 1289 if (reply.is_method_error()) 1290 { 1291 log<level::ERR>("Error in BootSource Set"); 1292 report<InternalFailure>(); 1293 *data_len = 0; 1294 return IPMI_CC_UNSPECIFIED_ERROR; 1295 } 1296 1297 } 1298 if (modeIpmiToDbus.end() != modeItr) 1299 { 1300 sdbusplus::message::variant<std::string> property = 1301 convertForMessage(modeItr->second); 1302 auto bootSetting = settings::boot::setting(objects, 1303 bootModeIntf); 1304 const auto& bootModeSetting = 1305 std::get<settings::Path>(bootSetting); 1306 auto method = 1307 dbus.new_method_call( 1308 objects.service(bootModeSetting, bootModeIntf).c_str(), 1309 bootModeSetting.c_str(), 1310 ipmi::PROP_INTF, 1311 "Set"); 1312 method.append(bootModeIntf, "BootMode", property); 1313 auto reply = dbus.call(method); 1314 if (reply.is_method_error()) 1315 { 1316 log<level::ERR>("Error in BootMode Set"); 1317 report<InternalFailure>(); 1318 *data_len = 0; 1319 return IPMI_CC_UNSPECIFIED_ERROR; 1320 } 1321 } 1322 } 1323 catch (InternalFailure& e) 1324 { 1325 report<InternalFailure>(); 1326 *data_len = 0; 1327 return IPMI_CC_UNSPECIFIED_ERROR; 1328 } 1329 } else if (reqptr->parameter == 1330 (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) { 1331 1332 int ret = setHostNetworkData(reqptr); 1333 if (ret < 0) { 1334 fprintf(stderr, "setHostNetworkData failed for set_sys_boot_options.\n"); 1335 rc = IPMI_CC_UNSPECIFIED_ERROR; 1336 } 1337 } else if (reqptr->parameter == 1338 static_cast<uint8_t>(BootOptionParameter::BOOT_INFO)) { 1339 // Handle parameter #4 and return command completed normally 1340 // (IPMI_CC_OK). There is no implementation in OpenBMC for this 1341 // parameter. This is added to support the ipmitool command `chassis 1342 // bootdev` which sends set on parameter #4, before setting the boot 1343 // flags. 1344 rc = IPMI_CC_OK; 1345 } else { 1346 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter); 1347 rc = IPMI_CC_PARM_NOT_SUPPORTED; 1348 } 1349 1350 return rc; 1351 } 1352 1353 void register_netfn_chassis_functions() 1354 { 1355 // <Wildcard Command> 1356 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_WILDCARD); 1357 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_WILDCARD, NULL, ipmi_chassis_wildcard, 1358 PRIVILEGE_USER); 1359 1360 // Get Chassis Capabilities 1361 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP); 1362 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP, NULL, ipmi_get_chassis_cap, 1363 PRIVILEGE_USER); 1364 1365 // <Get System Boot Options> 1366 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS); 1367 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL, 1368 ipmi_chassis_get_sys_boot_options, PRIVILEGE_OPERATOR); 1369 1370 // <Get Chassis Status> 1371 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS); 1372 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS, NULL, ipmi_get_chassis_status, 1373 PRIVILEGE_USER); 1374 1375 // <Chassis Control> 1376 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL); 1377 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control, 1378 PRIVILEGE_OPERATOR); 1379 1380 // <Set System Boot Options> 1381 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS); 1382 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, 1383 ipmi_chassis_set_sys_boot_options, PRIVILEGE_OPERATOR); 1384 } 1385