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