blob: 0b991fdc6d74b051de8f5f4bec0da7cf100726a0 [file] [log] [blame]
Adriana Kobylak40814c62015-10-27 15:58:44 -05001#include "chassishandler.h"
Patrick Williams37af7332016-09-02 21:21:42 -05002#include "host-ipmid/ipmid-api.h"
Ratan Guptadcb10672017-07-10 10:33:50 +05303#include "types.hpp"
4
Adriana Kobylak40814c62015-10-27 15:58:44 -05005#include <stdio.h>
Ratan Guptafd28dd72016-08-01 04:58:01 -05006#include <stdlib.h>
Adriana Kobylak40814c62015-10-27 15:58:44 -05007#include <stdint.h>
Brad Bishop35518682016-07-22 08:35:41 -04008#include <mapper.h>
Ratan Guptafd28dd72016-08-01 04:58:01 -05009#include <arpa/inet.h>
10#include <netinet/in.h>
11#include <limits.h>
12#include <string.h>
13#include <endian.h>
14#include <sstream>
15#include <array>
Andrew Geisslera6e3a302017-05-31 19:34:00 -050016#include <fstream>
17#include <experimental/filesystem>
Ratan Guptadcb10672017-07-10 10:33:50 +053018#include <string>
19
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +053020#include <phosphor-logging/log.hpp>
Ratan Guptadcb10672017-07-10 10:33:50 +053021#include <phosphor-logging/elog-errors.hpp>
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +053022#include <xyz/openbmc_project/State/Host/server.hpp>
Ratan Guptadcb10672017-07-10 10:33:50 +053023#include "xyz/openbmc_project/Common/error.hpp"
24
25#include <sdbusplus/bus.hpp>
26#include <sdbusplus/server/object.hpp>
27
Vishwanatha Subbannab891a572017-03-31 11:34:48 +053028#include "config.h"
ratagupta6f6bff2016-04-04 06:20:11 -050029
30//Defines
Ratan Guptafd28dd72016-08-01 04:58:01 -050031#define SET_PARM_VERSION 0x01
32#define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 //boot flags data1 7th bit on
ratagupta6f6bff2016-04-04 06:20:11 -050033#define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 //boot flags data1 8th bit on
Ratan Guptafd28dd72016-08-01 04:58:01 -050034#define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 //boot flags data1 7 & 8 bit on
ratagupta6f6bff2016-04-04 06:20:11 -050035
Ratan Guptafd28dd72016-08-01 04:58:01 -050036constexpr size_t SIZE_MAC = 18;
37constexpr size_t SIZE_BOOT_OPTION = (uint8_t)BootOptionResponseSize::
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -050038 OPAL_NETWORK_SETTINGS;//Maximum size of the boot option parametrs
Ratan Guptafd28dd72016-08-01 04:58:01 -050039constexpr size_t SIZE_PREFIX = 7;
40constexpr size_t MAX_PREFIX_VALUE = 32;
41constexpr size_t SIZE_COOKIE = 4;
42constexpr size_t SIZE_VERSION = 2;
43constexpr auto MAC_ADDRESS_FORMAT = "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx";
44constexpr auto IP_ADDRESS_FORMAT = "%d.%d.%d.%d";
Matthew Barth8b470052016-09-21 10:02:57 -050045constexpr auto PREFIX_FORMAT = "%hhd";
Ratan Guptafd28dd72016-08-01 04:58:01 -050046constexpr auto ADDR_TYPE_FORMAT = "%hhx";
47//PetiBoot-Specific
48static constexpr uint8_t net_conf_initial_bytes[] = {0x80,0x21, 0x70 ,0x62 ,0x21,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -050049 0x00 ,0x01 ,0x06 ,0x04};
Ratan Guptafd28dd72016-08-01 04:58:01 -050050
51static constexpr size_t COOKIE_OFFSET = 1;
52static constexpr size_t VERSION_OFFSET = 5;
53static constexpr size_t MAC_OFFSET = 9;
54static constexpr size_t ADDRTYPE_OFFSET = 16;
55static constexpr size_t IPADDR_OFFSET = 17;
56static constexpr size_t PREFIX_OFFSET = 21;
57static constexpr size_t GATEWAY_OFFSET = 22;
ratagupta6f6bff2016-04-04 06:20:11 -050058
shgoupfd84fbbf2015-12-17 10:05:51 +080059
Adriana Kobylak40814c62015-10-27 15:58:44 -050060void register_netfn_chassis_functions() __attribute__((constructor));
61
shgoupfd84fbbf2015-12-17 10:05:51 +080062// Host settings in dbus
63// Service name should be referenced by connection name got via object mapper
64const char *settings_object_name = "/org/openbmc/settings/host0";
65const char *settings_intf_name = "org.freedesktop.DBus.Properties";
66const char *host_intf_name = "org.openbmc.settings.Host";
67
Ratan Guptadcb10672017-07-10 10:33:50 +053068
69constexpr auto MAPPER_BUS_NAME = "xyz.openbmc_project.ObjectMapper";
70constexpr auto MAPPER_OBJ = "/xyz/openbmc_project/object_mapper";
71constexpr auto MAPPER_INTF = "xyz.openbmc_project.ObjectMapper";
72
73constexpr auto SETTINGS_ROOT = "/";
74constexpr auto SETTINGS_MATCH = "host0";
75constexpr auto PROP_INTF = "org.freedesktop.DBus.Properties";
76
77constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
78constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
79
80constexpr auto METHOD_GET = "Get";
81constexpr auto METHOD_GET_ALL = "GetAll";
82constexpr auto METHOD_SET = "Set";
83
Nan Li8d15fb42016-08-16 22:29:40 +080084typedef struct
85{
86 uint8_t cap_flags;
87 uint8_t fru_info_dev_addr;
88 uint8_t sdr_dev_addr;
89 uint8_t sel_dev_addr;
90 uint8_t system_management_dev_addr;
91 uint8_t bridge_dev_addr;
92}__attribute__((packed)) ipmi_chassis_cap_t;
93
Nan Lifdd8ec52016-08-28 03:57:40 +080094typedef struct
95{
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -050096 uint8_t cur_power_state;
97 uint8_t last_power_event;
98 uint8_t misc_power_state;
99 uint8_t front_panel_button_cap_status;
Nan Lifdd8ec52016-08-28 03:57:40 +0800100}__attribute__((packed)) ipmi_get_chassis_status_t;
101
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530102// Phosphor Host State manager
103namespace State = sdbusplus::xyz::openbmc_project::State::server;
104
Andrew Geisslera6e3a302017-05-31 19:34:00 -0500105namespace fs = std::experimental::filesystem;
106
Ratan Guptadcb10672017-07-10 10:33:50 +0530107using namespace phosphor::logging;
108using namespace sdbusplus::xyz::openbmc_project::Common::Error;
109
110/** @brief Gets the dbus object info implementing the given interface
111 * from the given subtree.
112 * @param[in] interface - Dbus interface.
113 * @param[in] serviceRoot - subtree from where the search should start.
114 * @param[in] match - identifier for object.
115 * @return On success returns the object having objectpath and servicename.
116 */
117
118//TODO There may be cases where an interface is implemented by multiple
119// objects,to handle such cases we are interested on that object
120// which are on interested busname.
121// Currently mapper doesn't give the readable busname(gives busid) so we can't
122// use busname to find the object,will do later once the support is there.
123
124ipmi::DbusObjectInfo getDbusObject(const std::string& interface,
125 const std::string& serviceRoot = SETTINGS_ROOT,
126 const std::string& match = "")
127{
128 std::vector<std::string>interfaces;
129 interfaces.emplace_back(interface);
130
131 auto bus = sdbusplus::bus::new_default();
132 auto depth = 0;
133
134 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
135 MAPPER_OBJ,
136 MAPPER_INTF,
137 "GetSubTree");
138
139 mapperCall.append(serviceRoot);
140 mapperCall.append(depth);
141 mapperCall.append(interfaces);
142
143 auto mapperReply = bus.call(mapperCall);
144 if (mapperReply.is_method_error())
145 {
146 log<level::ERR>("Error in mapper call");
147 elog<InternalFailure>();
148 }
149
150 ipmi::ObjectTree objectTree;
151 mapperReply.read(objectTree);
152
153 if (objectTree.empty())
154 {
155 log<level::ERR>("No Object have impelmented the interface",
156 entry("INTERFACE=%s", interface.c_str()));
157 elog<InternalFailure>();
158 }
159
160 ipmi::DbusObjectInfo objectInfo;
161
162 // if match is empty then return the first object
163 if(match == "")
164 {
165 objectInfo = make_pair(objectTree.begin()->first,
166 objectTree.begin()->second.begin()->first);
167 return objectInfo;
168 }
169
170 // else search the match string in the object path
171 auto objectFound = false;
172 for (auto& object : objectTree)
173 {
174 if(object.first.find(match)!= std::string::npos)
175 {
176 objectFound = true;
177 objectInfo = make_pair(object.first, object.second.begin()->first);
178 break;
179 }
180 }
181
182 if(!objectFound)
183 {
184 log<level::ERR>("Failed to find object which matches",
185 entry("MATCH=%s",match.c_str()));
186 elog<InternalFailure>();
187 }
188 return objectInfo;
189
190}
191
192/** @brief Gets the value associated with the given object
193 * and the interface.
194 * @param[in] service - Dbus service name.
195 * @param[in] objPath - Dbus object path.
196 * @param[in] interface - Dbus interface.
197 * @param[in] property - name of the property.
198 * @return On success returns the value of the property.
199 */
200std::string getDbusProperty(const std::string& service,
201 const std::string& objPath,
202 const std::string& interface,
203 const std::string& property)
204{
205
206 sdbusplus::message::variant<std::string> name;
207
208 auto bus = sdbusplus::bus::new_default();
209
210 auto method = bus.new_method_call(
211 service.c_str(),
212 objPath.c_str(),
213 PROP_INTF,
214 METHOD_GET);
215
216 method.append(interface, property);
217
218 auto reply = bus.call(method);
219
220 if (reply.is_method_error())
221 {
222 log<level::ERR>("Failed to get property",
223 entry("PROPERTY=%s", property.c_str()),
224 entry("PATH=%s", objPath.c_str()),
225 entry("INTERFACE=%s", interface.c_str()));
226 elog<InternalFailure>();
227 }
228
229 reply.read(name);
230
231 return name.get<std::string>();
232}
233
234/** @brief Gets all the properties associated with the given object
235 * and the interface.
236 * @param[in] service - Dbus service name.
237 * @param[in] objPath - Dbus object path.
238 * @param[in] interface - Dbus interface.
239 * @return On success returns the map of name value pair.
240 */
241ipmi::PropertyMap getAllDbusProperties(const std::string& service,
242 const std::string& objPath,
243 const std::string& interface)
244{
245 ipmi::PropertyMap properties;
246 auto bus = sdbusplus::bus::new_default();
247
248 auto method = bus.new_method_call(
249 service.c_str(),
250 objPath.c_str(),
251 PROP_INTF,
252 METHOD_GET_ALL);
253
254 method.append(interface);
255
256 auto reply = bus.call(method);
257
258 if (reply.is_method_error())
259 {
260 log<level::ERR>("Failed to get all properties",
261 entry("PATH=%s", objPath.c_str()),
262 entry("INTERFACE=%s", interface.c_str()));
263 elog<InternalFailure>();
264 }
265
266 reply.read(properties);
267 return properties;
268}
269
270/** @brief Sets the property value of the given object.
271 * @param[in] service - Dbus service name.
272 * @param[in] objPath - Dbus object path.
273 * @param[in] interface - Dbus interface.
274 * @param[in] property - name of the property.
275 * @param[in] value - value which needs to be set.
276 */
277void setDbusProperty(const std::string& service,
278 const std::string& objPath,
279 const std::string& interface,
280 const std::string& property,
281 const ipmi::Value& value)
282{
283 auto bus = sdbusplus::bus::new_default();
284
285 auto method = bus.new_method_call(
286 service.c_str(),
287 objPath.c_str(),
288 PROP_INTF,
289 METHOD_SET);
290
291 method.append(interface);
292 method.append(property, value);
293
294 if (!bus.call(method))
295 {
296 log<level::ERR>("Failed to set property",
297 entry("PROPERTY=%s", property.c_str()),
298 entry("PATH=%s",objPath.c_str()),
299 entry("INTERFACE=%s",interface.c_str()));
300 elog<InternalFailure>();
301 }
302
303}
304
305//TODO : Can remove the below function as we have
306// new functions which uses sdbusplus.
307//
308// openbmc/openbmc#1489
ratagupta6f6bff2016-04-04 06:20:11 -0500309int dbus_get_property(const char *name, char **buf)
shgoupfd84fbbf2015-12-17 10:05:51 +0800310{
311 sd_bus_error error = SD_BUS_ERROR_NULL;
312 sd_bus_message *m = NULL;
313 sd_bus *bus = NULL;
314 char *temp_buf = NULL;
315 char *connection = NULL;
316 int r;
317
Brad Bishop35518682016-07-22 08:35:41 -0400318 // Get the system bus where most system services are provided.
319 bus = ipmid_get_sd_bus_connection();
shgoupfd84fbbf2015-12-17 10:05:51 +0800320
Brad Bishop35518682016-07-22 08:35:41 -0400321 r = mapper_get_service(bus, settings_object_name, &connection);
shgoupfd84fbbf2015-12-17 10:05:51 +0800322 if (r < 0) {
Brad Bishop819ddd42016-10-05 21:19:19 -0400323 fprintf(stderr, "Failed to get %s connection: %s\n",
324 settings_object_name, strerror(-r));
shgoupfd84fbbf2015-12-17 10:05:51 +0800325 goto finish;
326 }
327
shgoupfd84fbbf2015-12-17 10:05:51 +0800328 /*
329 * Bus, service, object path, interface and method are provided to call
330 * the method.
331 * Signatures and input arguments are provided by the arguments at the
332 * end.
333 */
334 r = sd_bus_call_method(bus,
335 connection, /* service to contact */
336 settings_object_name, /* object path */
337 settings_intf_name, /* interface name */
338 "Get", /* method name */
339 &error, /* object to return error in */
340 &m, /* return message on success */
341 "ss", /* input signature */
342 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500343 name); /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800344
345 if (r < 0) {
346 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
347 goto finish;
348 }
349
350 /*
351 * The output should be parsed exactly the same as the output formatting
352 * specified.
353 */
354 r = sd_bus_message_read(m, "v", "s", &temp_buf);
355 if (r < 0) {
356 fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
357 goto finish;
358 }
359
Matthew Barth56181052017-01-23 09:36:29 -0600360 *buf = strdup(temp_buf);
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500361 /* *buf = (char*) malloc(strlen(temp_buf));
shgoupfd84fbbf2015-12-17 10:05:51 +0800362 if (*buf) {
363 strcpy(*buf, temp_buf);
364 }
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500365 */
shgoupfd84fbbf2015-12-17 10:05:51 +0800366 printf("IPMID boot option property get: {%s}.\n", (char *) temp_buf);
367
368finish:
369 sd_bus_error_free(&error);
370 sd_bus_message_unref(m);
371 free(connection);
372
373 return r;
374}
375
Ratan Guptadcb10672017-07-10 10:33:50 +0530376//TODO : Can remove the below function as we have
377// new functions which uses sdbusplus.
378//
379// openbmc/openbmc#1489
380
ratagupta6f6bff2016-04-04 06:20:11 -0500381int dbus_set_property(const char * name, const char *value)
shgoupfd84fbbf2015-12-17 10:05:51 +0800382{
383 sd_bus_error error = SD_BUS_ERROR_NULL;
384 sd_bus_message *m = NULL;
385 sd_bus *bus = NULL;
386 char *connection = NULL;
387 int r;
388
Brad Bishop35518682016-07-22 08:35:41 -0400389 // Get the system bus where most system services are provided.
390 bus = ipmid_get_sd_bus_connection();
shgoupfd84fbbf2015-12-17 10:05:51 +0800391
Brad Bishop35518682016-07-22 08:35:41 -0400392 r = mapper_get_service(bus, settings_object_name, &connection);
shgoupfd84fbbf2015-12-17 10:05:51 +0800393 if (r < 0) {
Brad Bishop819ddd42016-10-05 21:19:19 -0400394 fprintf(stderr, "Failed to get %s connection: %s\n",
395 settings_object_name, strerror(-r));
shgoupfd84fbbf2015-12-17 10:05:51 +0800396 goto finish;
397 }
398
shgoupfd84fbbf2015-12-17 10:05:51 +0800399 /*
400 * Bus, service, object path, interface and method are provided to call
401 * the method.
402 * Signatures and input arguments are provided by the arguments at the
403 * end.
404 */
405 r = sd_bus_call_method(bus,
406 connection, /* service to contact */
407 settings_object_name, /* object path */
408 settings_intf_name, /* interface name */
409 "Set", /* method name */
410 &error, /* object to return error in */
411 &m, /* return message on success */
412 "ssv", /* input signature */
413 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500414 name, /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800415 "s", /* third argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500416 value); /* fourth argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800417
418 if (r < 0) {
419 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
420 goto finish;
421 }
422
ratagupta6f6bff2016-04-04 06:20:11 -0500423 printf("IPMID boot option property set: {%s}.\n", value);
shgoupfd84fbbf2015-12-17 10:05:51 +0800424
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500425 finish:
shgoupfd84fbbf2015-12-17 10:05:51 +0800426 sd_bus_error_free(&error);
427 sd_bus_message_unref(m);
428 free(connection);
429
430 return r;
431}
432
Adriana Kobylak40814c62015-10-27 15:58:44 -0500433struct get_sys_boot_options_t {
434 uint8_t parameter;
435 uint8_t set;
436 uint8_t block;
437} __attribute__ ((packed));
438
shgoupfd84fbbf2015-12-17 10:05:51 +0800439struct get_sys_boot_options_response_t {
440 uint8_t version;
441 uint8_t parm;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500442 uint8_t data[SIZE_BOOT_OPTION];
shgoupfd84fbbf2015-12-17 10:05:51 +0800443} __attribute__ ((packed));
444
445struct set_sys_boot_options_t {
446 uint8_t parameter;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500447 uint8_t data[SIZE_BOOT_OPTION];
shgoupfd84fbbf2015-12-17 10:05:51 +0800448} __attribute__ ((packed));
449
Ratan Guptafd28dd72016-08-01 04:58:01 -0500450
Ratan Guptadcb10672017-07-10 10:33:50 +0530451int getHostNetworkData(get_sys_boot_options_response_t* respptr)
Ratan Guptafd28dd72016-08-01 04:58:01 -0500452{
Ratan Guptadcb10672017-07-10 10:33:50 +0530453 ipmi::PropertyMap properties;
454 int rc = 0;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500455
Ratan Guptadcb10672017-07-10 10:33:50 +0530456 try
457 {
458 //TODO There may be cases where an interface is implemented by multiple
459 // objects,to handle such cases we are interested on that object
460 // which are on interested busname.
461 // Currenlty mapper doesn't give the readable busname(gives busid)
462 // so we can't match with bus name so giving some object specific info
463 // as SETTINGS_MATCH.
464 // Later SETTINGS_MATCH will be replaced with busname.
Ratan Guptafd28dd72016-08-01 04:58:01 -0500465
Ratan Guptadcb10672017-07-10 10:33:50 +0530466 auto ipObjectInfo = getDbusObject(IP_INTERFACE, SETTINGS_ROOT,
467 SETTINGS_MATCH);
468 auto macObjectInfo = getDbusObject(MAC_INTERFACE, SETTINGS_ROOT,
469 SETTINGS_MATCH);
470
471 properties = getAllDbusProperties(ipObjectInfo.second,
472 ipObjectInfo.first, IP_INTERFACE);
473 auto MACAddress =
474 getDbusProperty(macObjectInfo.second, macObjectInfo.first,
475 MAC_INTERFACE, "MACAddress");
476
477 sscanf(MACAddress.c_str(), MAC_ADDRESS_FORMAT,
478 (respptr->data + MAC_OFFSET),
479 (respptr->data + MAC_OFFSET + 1),
480 (respptr->data + MAC_OFFSET + 2),
481 (respptr->data + MAC_OFFSET + 3),
482 (respptr->data + MAC_OFFSET + 4),
483 (respptr->data + MAC_OFFSET + 5));
484
485
486 respptr->data[MAC_OFFSET + 6] = 0x00;
487
488 uint8_t addrType = (properties["Origin"].get<std::string>() ==
489 "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ? 1 : 0;
490
491 memcpy(respptr->data + ADDRTYPE_OFFSET, &addrType, sizeof(addrType));
492
493 // ipaddress and gateway would be in IPv4 format
494
495 inet_pton(AF_INET, properties["Address"].get<std::string>().c_str(),
496 (respptr->data + IPADDR_OFFSET));
497
498 uint8_t prefix = properties["PrefixLength"].get<uint8_t>();
499 memcpy(respptr->data + PREFIX_OFFSET, &prefix, sizeof(prefix));
500
501 inet_pton(AF_INET, properties["Gateway"].get<std::string>().c_str(),
502 (respptr->data + GATEWAY_OFFSET));
503
504 }
505 catch (InternalFailure& e)
506 {
507 commit<InternalFailure>();
508 memset(respptr->data, 0, SIZE_BOOT_OPTION);
509 rc = -1;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500510 return rc;
511 }
512
Ratan Guptadcb10672017-07-10 10:33:50 +0530513 //PetiBoot-Specific
514 //If sucess then copy the first 9 bytes to the data
515 //else set the respptr to 0
Ratan Guptafd28dd72016-08-01 04:58:01 -0500516
Ratan Guptadcb10672017-07-10 10:33:50 +0530517 memcpy(respptr->data, net_conf_initial_bytes,
518 sizeof(net_conf_initial_bytes));
Ratan Guptafd28dd72016-08-01 04:58:01 -0500519
520#ifdef _IPMI_DEBUG_
Ratan Guptadcb10672017-07-10 10:33:50 +0530521 printf("\n===Printing the IPMI Formatted Data========\n");
Ratan Guptafd28dd72016-08-01 04:58:01 -0500522
Ratan Guptadcb10672017-07-10 10:33:50 +0530523 for (uint8_t pos = 0; pos < index; pos++)
524 {
525 printf("%02x ", respptr->data[pos]);
526 }
Ratan Guptafd28dd72016-08-01 04:58:01 -0500527#endif
528
Ratan Guptafd28dd72016-08-01 04:58:01 -0500529
530 return rc;
531}
532
Ratan Guptadcb10672017-07-10 10:33:50 +0530533int setHostNetworkData(set_sys_boot_options_t* reqptr)
Ratan Guptafd28dd72016-08-01 04:58:01 -0500534{
Ratan Guptadcb10672017-07-10 10:33:50 +0530535 using namespace std::string_literals;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500536 std::string host_network_config;
537 char mac[SIZE_MAC] = {0};
538 char ipAddress[INET_ADDRSTRLEN] = {0};
539 char gateway[INET_ADDRSTRLEN] = {0};
Ratan Guptadcb10672017-07-10 10:33:50 +0530540 char dhcp {0};
541 std::string addressOrigin =
542 "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
543 uint8_t prefix {0};
544 uint32_t zeroCookie = 0;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500545
546 //cookie starts from second byte
547 // version starts from sixth byte
548
Ratan Guptadcb10672017-07-10 10:33:50 +0530549 try
Ratan Guptafd28dd72016-08-01 04:58:01 -0500550 {
Ratan Guptadcb10672017-07-10 10:33:50 +0530551 do
552 {
553 // cookie == 0x21 0x70 0x62 0x21
554 if (memcmp(&(reqptr->data[COOKIE_OFFSET]),
555 (net_conf_initial_bytes + COOKIE_OFFSET),
556 SIZE_COOKIE) != 0)
557 {
558 //cookie == 0
559 if (memcmp(&(reqptr->data[COOKIE_OFFSET]),
560 &zeroCookie,
561 SIZE_COOKIE) == 0)
562 {
563 // need to zero out the network settings.
564 break;
565 }
566
567 log<level::ERR>("Invalid Cookie");
568 elog<InternalFailure>();
569 }
570
571 // vesion == 0x00 0x01
572 if (memcmp(&(reqptr->data[VERSION_OFFSET]),
573 (net_conf_initial_bytes + VERSION_OFFSET),
574 SIZE_VERSION) != 0)
575 {
576
577 log<level::ERR>("Invalid Version");
578 elog<InternalFailure>();
579 }
580
581 snprintf(mac, SIZE_MAC, MAC_ADDRESS_FORMAT,
582 reqptr->data[MAC_OFFSET],
583 reqptr->data[MAC_OFFSET + 1],
584 reqptr->data[MAC_OFFSET + 2],
585 reqptr->data[MAC_OFFSET + 3],
586 reqptr->data[MAC_OFFSET + 4],
587 reqptr->data[MAC_OFFSET + 5]);
588
589 memcpy(&dhcp, &(reqptr->data[ADDRTYPE_OFFSET]),
590 sizeof(decltype(dhcp)));
591
592 if (dhcp)
593 {
594 addressOrigin =
595 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
596 }
597
598 snprintf(ipAddress, INET_ADDRSTRLEN, IP_ADDRESS_FORMAT,
599 reqptr->data[IPADDR_OFFSET],
600 reqptr->data[IPADDR_OFFSET + 1],
601 reqptr->data[IPADDR_OFFSET + 2],
602 reqptr->data[IPADDR_OFFSET + 3]);
603
604
605 memcpy(&prefix, &(reqptr->data[PREFIX_OFFSET]),
606 sizeof(decltype(prefix)));
607
608 snprintf(gateway, INET_ADDRSTRLEN, IP_ADDRESS_FORMAT,
609 reqptr->data[GATEWAY_OFFSET],
610 reqptr->data[GATEWAY_OFFSET + 1],
611 reqptr->data[GATEWAY_OFFSET + 2],
612 reqptr->data[GATEWAY_OFFSET + 3]);
613 } while(0);
614
Ratan Guptafd28dd72016-08-01 04:58:01 -0500615 //Cookie == 0 or it is a valid cookie
Ratan Guptadcb10672017-07-10 10:33:50 +0530616 host_network_config += "ipaddress="s + ipAddress +
617 ",prefix="s + std::to_string(prefix) + ",gateway="s + gateway +
618 ",mac="s + mac + ",addressOrigin="s + addressOrigin;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500619
Ratan Guptadcb10672017-07-10 10:33:50 +0530620 log<level::DEBUG>("Network configuration changed",
621 entry("NETWORKCONFIG=%s", host_network_config.c_str()));
Ratan Guptafd28dd72016-08-01 04:58:01 -0500622
Ratan Guptadcb10672017-07-10 10:33:50 +0530623 auto ipObjectInfo = getDbusObject(IP_INTERFACE, SETTINGS_ROOT,
624 SETTINGS_MATCH);
625 auto macObjectInfo = getDbusObject(MAC_INTERFACE, SETTINGS_ROOT,
626 SETTINGS_MATCH);
627 // set the dbus property
628 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
629 IP_INTERFACE, "Address", std::string(ipAddress));
630 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
631 IP_INTERFACE, "PrefixLength", prefix);
632 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
633 IP_INTERFACE, "Origin", addressOrigin);
634 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
635 IP_INTERFACE, "Gateway", std::string(gateway));
636 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
637 IP_INTERFACE, "Type",
638 std::string("xyz.openbmc_project.Network.IP.Protocol.IPv4"));
639 setDbusProperty(macObjectInfo.second, macObjectInfo.first,
640 MAC_INTERFACE,"MACAddress", std::string(mac));
Ratan Guptafd28dd72016-08-01 04:58:01 -0500641
642 }
Ratan Guptadcb10672017-07-10 10:33:50 +0530643 catch (InternalFailure& e)
644 {
645 commit<InternalFailure>();
646 return -1;
647 }
648
649 return 0;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500650}
651
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500652ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
653 ipmi_request_t request,
654 ipmi_response_t response,
655 ipmi_data_len_t data_len,
656 ipmi_context_t context)
Adriana Kobylak40814c62015-10-27 15:58:44 -0500657{
658 printf("Handling CHASSIS WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
659 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800660 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500661 *data_len = 0;
662 return rc;
663}
664
Nan Li8d15fb42016-08-16 22:29:40 +0800665ipmi_ret_t ipmi_get_chassis_cap(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500666 ipmi_request_t request, ipmi_response_t response,
667 ipmi_data_len_t data_len, ipmi_context_t context)
Nan Li8d15fb42016-08-16 22:29:40 +0800668{
669 // sd_bus error
670 ipmi_ret_t rc = IPMI_CC_OK;
671
672 ipmi_chassis_cap_t chassis_cap{};
673
674 *data_len = sizeof(ipmi_chassis_cap_t);
675
676 // TODO: need future work. Get those flag from MRW.
677
678 // capabilities flags
679 // [7..4] - reserved
680 // [3] – 1b = provides power interlock (IPM 1.5)
681 // [2] – 1b = provides Diagnostic Interrupt (FP NMI)
682 // [1] – 1b = provides “Front Panel Lockout” (indicates that the chassis has capabilities
683 // to lock out external power control and reset button or front panel interfaces
684 // and/or detect tampering with those interfaces).
685 // [0] -1b = Chassis provides intrusion (physical security) sensor.
686 // set to default value 0x0.
687 chassis_cap.cap_flags = 0x0;
688
689 // Since we do not have a separate SDR Device/SEL Device/ FRU repository.
690 // The 20h was given as those 5 device addresses.
691 // Chassis FRU info Device Address
692 chassis_cap.fru_info_dev_addr = 0x20;
693
694 // Chassis SDR Device Address
695 chassis_cap.sdr_dev_addr = 0x20;
696
697 // Chassis SEL Device Address
698 chassis_cap.sel_dev_addr = 0x20;
699
700 // Chassis System Management Device Address
701 chassis_cap.system_management_dev_addr = 0x20;
702
703 // Chassis Bridge Device Address.
704 chassis_cap.bridge_dev_addr = 0x20;
705
706 memcpy(response, &chassis_cap, *data_len);
707
708 return rc;
709}
710
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530711//------------------------------------------
712// Calls into Host State Manager Dbus object
713//------------------------------------------
714int initiate_state_transition(State::Host::Transition transition)
vishwa36993272015-11-20 12:43:49 -0600715{
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500716 // OpenBMC Host State Manager dbus framework
717 constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0";
718 constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host";
719 constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
720 constexpr auto PROPERTY = "RequestedHostTransition";
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530721
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500722 // sd_bus error
723 int rc = 0;
724 char *busname = NULL;
vishwa36993272015-11-20 12:43:49 -0600725
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500726 // SD Bus error report mechanism.
727 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
vishwa36993272015-11-20 12:43:49 -0600728
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500729 // Gets a hook onto either a SYSTEM or SESSION bus
730 sd_bus *bus_type = ipmid_get_sd_bus_connection();
731 rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname);
732 if (rc < 0)
733 {
734 log<level::ERR>("Failed to get bus name",
735 entry("ERROR=%s, OBJPATH=%s",
736 strerror(-rc), HOST_STATE_MANAGER_ROOT));
737 return rc;
738 }
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530739
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500740 // Convert to string equivalent of the passed in transition enum.
741 auto request = State::convertForMessage(transition);
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530742
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500743 rc = sd_bus_call_method(bus_type, // On the system bus
744 busname, // Service to contact
745 HOST_STATE_MANAGER_ROOT, // Object path
746 DBUS_PROPERTY_IFACE, // Interface name
747 "Set", // Method to be called
748 &bus_error, // object to return error
749 nullptr, // Response buffer if any
750 "ssv", // Takes 3 arguments
751 HOST_STATE_MANAGER_IFACE,
752 PROPERTY,
753 "s", request.c_str());
754 if(rc < 0)
755 {
756 log<level::ERR>("Failed to initiate transition",
757 entry("ERROR=%s, REQUEST=%s",
758 bus_error.message, request.c_str()));
759 }
760 else
761 {
762 log<level::INFO>("Transition request initiated successfully");
763 }
vishwa36993272015-11-20 12:43:49 -0600764
765 sd_bus_error_free(&bus_error);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500766 free(busname);
vishwa36993272015-11-20 12:43:49 -0600767
Sergey Solomineb9b8142016-08-23 09:07:28 -0500768 return rc;
vishwa36993272015-11-20 12:43:49 -0600769}
770
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500771struct hostPowerPolicyTypeMap_t
772{
Nan Lifdd8ec52016-08-28 03:57:40 +0800773 uint8_t policyNum;
774 char policyName[19];
775};
776
777hostPowerPolicyTypeMap_t g_hostPowerPolicyTypeMap_t[] = {
778
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500779 {0x00, "LEAVE_OFF"},
780 {0x01, "RESTORE_LAST_STATE"},
781 {0x02, "ALWAYS_POWER_ON"},
782 {0x03, "UNKNOWN"}
Nan Lifdd8ec52016-08-28 03:57:40 +0800783};
784
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500785uint8_t get_host_power_policy(char *p)
786{
Nan Lifdd8ec52016-08-28 03:57:40 +0800787
788 hostPowerPolicyTypeMap_t *s = g_hostPowerPolicyTypeMap_t;
789
790 while (s->policyNum != 0x03) {
791 if (!strcmp(s->policyName,p))
792 break;
793 s++;
794 }
795
796 return s->policyNum;
797}
798
799//----------------------------------------------------------------------
800// Get Chassis Status commands
801//----------------------------------------------------------------------
802ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500803 ipmi_request_t request,
804 ipmi_response_t response,
805 ipmi_data_len_t data_len,
806 ipmi_context_t context)
Nan Lifdd8ec52016-08-28 03:57:40 +0800807{
808 const char *objname = "/org/openbmc/control/power0";
809 const char *intf = "org.openbmc.control.Power";
810
811 sd_bus *bus = NULL;
812 sd_bus_message *reply = NULL;
813 int r = 0;
814 int pgood = 0;
815 char *busname = NULL;
816 ipmi_ret_t rc = IPMI_CC_OK;
817 ipmi_get_chassis_status_t chassis_status{};
818
819 char *p = NULL;
820 uint8_t s = 0;
821
822 // Get the system bus where most system services are provided.
823 bus = ipmid_get_sd_bus_connection();
824
825 *data_len = 4;
826
827 r = mapper_get_service(bus, objname, &busname);
828 if (r < 0) {
829 fprintf(stderr, "Failed to get bus name, return value: %s.\n", strerror(-r));
830 rc = IPMI_CC_UNSPECIFIED_ERROR;
831 goto finish;
832 }
833
834 r = sd_bus_get_property(bus, busname, objname, intf, "pgood", NULL, &reply, "i");
835 if (r < 0) {
836 fprintf(stderr, "Failed to call sd_bus_get_property:%d, %s\n", r, strerror(-r));
837 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
838 busname, objname, intf);
839 rc = IPMI_CC_UNSPECIFIED_ERROR;
840 goto finish;
841 }
842
843 r = sd_bus_message_read(reply, "i", &pgood);
844 if (r < 0) {
845 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r));
846 rc = IPMI_CC_UNSPECIFIED_ERROR;
847 goto finish;
848 }
849
850 printf("pgood is 0x%02x\n", pgood);
851
852 // Get Power Policy
853 r = dbus_get_property("power_policy",&p);
854
855 if (r < 0) {
856 fprintf(stderr, "Dbus get property(power_policy) failed for get_sys_boot_options.\n");
857 rc = IPMI_CC_UNSPECIFIED_ERROR;
858 } else {
859 s = get_host_power_policy(p);
860 }
861
862 if (p)
863 {
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500864 free(p);
865 p = NULL;
Nan Lifdd8ec52016-08-28 03:57:40 +0800866 }
867
868 // Current Power State
869 // [7] reserved
870 // [6..5] power restore policy
871 // 00b = chassis stays powered off after AC/mains returns
872 // 01b = after AC returns, power is restored to the state that was
873 // in effect when AC/mains was lost.
874 // 10b = chassis always powers up after AC/mains returns
875 // 11b = unknow
876 // Set to 00b, by observing the hardware behavior.
877 // Do we need to define a dbus property to identify the restore policy?
878
879 // [4] power control fault
880 // 1b = controller attempted to turn system power on or off, but
881 // system did not enter desired state.
882 // Set to 0b, since We don't support it..
883
884 // [3] power fault
885 // 1b = fault detected in main power subsystem.
886 // set to 0b. for we don't support it.
887
888 // [2] 1b = interlock (chassis is presently shut down because a chassis
889 // panel interlock switch is active). (IPMI 1.5)
890 // set to 0b, for we don't support it.
891
892 // [1] power overload
893 // 1b = system shutdown because of power overload condition.
894 // set to 0b, for we don't support it.
895
896 // [0] power is on
897 // 1b = system power is on
898 // 0b = system power is off(soft-off S4/S5, or mechanical off)
899
900 chassis_status.cur_power_state = ((s & 0x3)<<5) | (pgood & 0x1);
901
902 // Last Power Event
903 // [7..5] – reserved
904 // [4] – 1b = last ‘Power is on’ state was entered via IPMI command
905 // [3] – 1b = last power down caused by power fault
906 // [2] – 1b = last power down caused by a power interlock being activated
907 // [1] – 1b = last power down caused by a Power overload
908 // [0] – 1b = AC failed
909 // set to 0x0, for we don't support these fields.
910
911 chassis_status.last_power_event = 0;
912
913 // Misc. Chassis State
914 // [7] – reserved
915 // [6] – 1b = Chassis Identify command and state info supported (Optional)
916 // 0b = Chassis Identify command support unspecified via this command.
917 // (The Get Command Support command , if implemented, would still
918 // indicate support for the Chassis Identify command)
919 // [5..4] – Chassis Identify State. Mandatory when bit[6] =1b, reserved (return
920 // as 00b) otherwise. Returns the present chassis identify state.
921 // Refer to the Chassis Identify command for more info.
922 // 00b = chassis identify state = Off
923 // 01b = chassis identify state = Temporary(timed) On
924 // 10b = chassis identify state = Indefinite On
925 // 11b = reserved
926 // [3] – 1b = Cooling/fan fault detected
927 // [2] – 1b = Drive Fault
928 // [1] – 1b = Front Panel Lockout active (power off and reset via chassis
929 // push-buttons disabled.)
930 // [0] – 1b = Chassis Intrusion active
931 // set to 0, for we don't support them.
932 chassis_status.misc_power_state = 0;
933
934 // Front Panel Button Capabilities and disable/enable status(Optional)
935 // set to 0, for we don't support them.
936 chassis_status.front_panel_button_cap_status = 0;
937
938 // Pack the actual response
939 memcpy(response, &chassis_status, *data_len);
940
941finish:
942 free(busname);
943 reply = sd_bus_message_unref(reply);
944
945 return rc;
946}
Chris Austen7888c4d2015-12-03 15:26:20 -0600947
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +0530948//-------------------------------------------------------------
949// Send a command to SoftPowerOff application to stop any timer
950//-------------------------------------------------------------
951int stop_soft_off_timer()
952{
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +0530953 constexpr auto iface = "org.freedesktop.DBus.Properties";
954 constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal."
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500955 "SoftPowerOff";
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +0530956
957 constexpr auto property = "ResponseReceived";
958 constexpr auto value = "xyz.openbmc_project.Ipmi.Internal."
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500959 "SoftPowerOff.HostResponse.HostShutdown";
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +0530960
961 // Get the system bus where most system services are provided.
962 auto bus = ipmid_get_sd_bus_connection();
963
964 // Get the service name
Andrew Geissler2b4e4592017-06-08 11:18:35 -0500965 // TODO openbmc/openbmc#1661 - Mapper refactor
966 //
967 // See openbmc/openbmc#1743 for some details but high level summary is that
968 // for now the code will directly call the soft off interface due to a
969 // race condition with mapper usage
970 //
971 //char *busname = nullptr;
972 //auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname);
973 //if (r < 0)
974 //{
975 // fprintf(stderr, "Failed to get %s bus name: %s\n",
976 // SOFTOFF_OBJPATH, strerror(-r));
977 // return r;
978 //}
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +0530979
980 // No error object or reply expected.
Andrew Geissler2b4e4592017-06-08 11:18:35 -0500981 int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500982 "Set", nullptr, nullptr, "ssv",
983 soft_off_iface, property, "s", value);
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +0530984 if (rc < 0)
985 {
986 fprintf(stderr, "Failed to set property in SoftPowerOff object: %s\n",
987 strerror(-rc));
988 }
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500989
Andrew Geissler2b4e4592017-06-08 11:18:35 -0500990 //TODO openbmc/openbmc#1661 - Mapper refactor
991 //free(busname);
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +0530992 return rc;
993}
994
vishwa36993272015-11-20 12:43:49 -0600995//----------------------------------------------------------------------
Andrew Geisslera6e3a302017-05-31 19:34:00 -0500996// Create file to indicate there is no need for softoff notification to host
997//----------------------------------------------------------------------
998void indicate_no_softoff_needed()
999{
1000 fs::path path{HOST_INBAND_REQUEST_DIR};
1001 if (!fs::is_directory(path))
1002 {
1003 fs::create_directory(path);
1004 }
1005
1006 // Add the host instance (default 0 for now) to the file name
1007 std::string file{HOST_INBAND_REQUEST_FILE};
1008 auto size = std::snprintf(nullptr,0,file.c_str(),0);
1009 size++; // null
1010 std::unique_ptr<char[]> buf(new char[size]);
1011 std::snprintf(buf.get(),size,file.c_str(),0);
1012
1013 // Append file name to directory and create it
1014 path /= buf.get();
1015 std::ofstream(path.c_str());
1016}
1017
1018//----------------------------------------------------------------------
vishwa36993272015-11-20 12:43:49 -06001019// Chassis Control commands
1020//----------------------------------------------------------------------
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001021ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1022 ipmi_request_t request,
1023 ipmi_response_t response,
1024 ipmi_data_len_t data_len,
1025 ipmi_context_t context)
vishwa36993272015-11-20 12:43:49 -06001026{
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001027 // Error from power off.
1028 int rc = 0;
vishwa36993272015-11-20 12:43:49 -06001029
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001030 // No response for this command.
vishwa36993272015-11-20 12:43:49 -06001031 *data_len = 0;
1032
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001033 // Catch the actual operaton by peeking into request buffer
1034 uint8_t chassis_ctrl_cmd = *(uint8_t *)request;
1035 printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd);
vishwa36993272015-11-20 12:43:49 -06001036
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001037 switch(chassis_ctrl_cmd)
1038 {
1039 case CMD_POWER_ON:
1040 rc = initiate_state_transition(State::Host::Transition::On);
1041 break;
1042 case CMD_POWER_OFF:
1043 // Need to Nudge SoftPowerOff application that it needs to stop the
1044 // watchdog timer if running.
1045 rc = stop_soft_off_timer();
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001046 // Only request the Off transition if the soft power off
1047 // application is not running
1048 if (rc < 0)
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001049 {
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001050 log<level::INFO>("Did not find soft off service so request "
1051 "Host:Transition:Off");
1052
1053 // First create a file to indicate to the soft off application
1054 // that it should not run since this is a direct user initiated
1055 // power off request (i.e. a power off request that is not
1056 // originating via a soft power off SMS request)
1057 indicate_no_softoff_needed();
1058
1059 // Now request the shutdown
1060 rc = initiate_state_transition(State::Host::Transition::Off);
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001061 }
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001062 else
1063 {
1064 log<level::INFO>("Soft off is running, so let that stop "
1065 "the host");
1066 }
1067
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001068 break;
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301069
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001070 case CMD_HARD_RESET:
1071 case CMD_POWER_CYCLE:
1072 // SPEC has a section that says certain implementations can trigger
1073 // PowerOn if power is Off when a command to power cycle is
1074 // requested
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001075
1076 // First create a file to indicate to the soft off application
1077 // that it should not run since this is a direct user initiated
1078 // power reboot request (i.e. a reboot request that is not
1079 // originating via a soft power off SMS request)
1080 indicate_no_softoff_needed();
1081
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001082 rc = initiate_state_transition(State::Host::Transition::Reboot);
1083 break;
1084 default:
1085 {
1086 fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd);
1087 rc = -1;
1088 }
1089 }
vishwa36993272015-11-20 12:43:49 -06001090
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001091 return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK);
vishwa36993272015-11-20 12:43:49 -06001092}
1093
shgoupfd84fbbf2015-12-17 10:05:51 +08001094struct bootOptionTypeMap_t {
1095 uint8_t ipmibootflag;
1096 char dbusname[8];
1097};
1098
1099#define INVALID_STRING "Invalid"
1100// dbus supports this list of boot devices.
1101bootOptionTypeMap_t g_bootOptionTypeMap_t[] = {
1102
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001103 {0x01, "Network"},
1104 {0x02, "Disk"},
1105 {0x03, "Safe"},
1106 {0x05, "CDROM"},
1107 {0x06, "Setup"},
1108 {0x00, "Default"},
1109 {0xFF, INVALID_STRING}
shgoupfd84fbbf2015-12-17 10:05:51 +08001110};
1111
1112uint8_t get_ipmi_boot_option(char *p) {
1113
1114 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
1115
1116 while (s->ipmibootflag != 0xFF) {
1117 if (!strcmp(s->dbusname,p))
1118 break;
1119 s++;
1120 }
1121
1122 if (!s->ipmibootflag)
1123 printf("Failed to find Sensor Type %s\n", p);
1124
1125 return s->ipmibootflag;
1126}
1127
1128char* get_boot_option_by_ipmi(uint8_t p) {
1129
1130 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
1131
1132 while (s->ipmibootflag != 0xFF) {
1133
1134 if (s->ipmibootflag == p)
1135 break;
1136
1137 s++;
1138 }
1139
1140
1141 if (!s->ipmibootflag)
1142 printf("Failed to find Sensor Type 0x%x\n", p);
1143
1144 return s->dbusname;
1145}
1146
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001147ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1148 ipmi_request_t request,
1149 ipmi_response_t response,
1150 ipmi_data_len_t data_len,
1151 ipmi_context_t context)
Adriana Kobylak40814c62015-10-27 15:58:44 -05001152{
shgoupfd84fbbf2015-12-17 10:05:51 +08001153 ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED;
1154 char *p = NULL;
1155 get_sys_boot_options_response_t *resp = (get_sys_boot_options_response_t *) response;
1156 get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request;
1157 uint8_t s;
Adriana Kobylak40814c62015-10-27 15:58:44 -05001158
1159 printf("IPMI GET_SYS_BOOT_OPTIONS\n");
1160
shgoupfd84fbbf2015-12-17 10:05:51 +08001161 memset(resp,0,sizeof(*resp));
1162 resp->version = SET_PARM_VERSION;
1163 resp->parm = 5;
ratagupta6f6bff2016-04-04 06:20:11 -05001164 resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
Adriana Kobylak40814c62015-10-27 15:58:44 -05001165
Adriana Kobylak40814c62015-10-27 15:58:44 -05001166
shgoupfd84fbbf2015-12-17 10:05:51 +08001167 /*
1168 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
1169 * This is the only parameter used by petitboot.
1170 */
Ratan Guptafd28dd72016-08-01 04:58:01 -05001171 if ( reqptr->parameter == static_cast<uint8_t>
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001172 ( BootOptionParameter::BOOT_FLAGS )) {
shgoupfd84fbbf2015-12-17 10:05:51 +08001173
Ratan Guptafd28dd72016-08-01 04:58:01 -05001174 *data_len = static_cast<uint8_t>(BootOptionResponseSize::BOOT_FLAGS);
ratagupta6f6bff2016-04-04 06:20:11 -05001175 /* Get the boot device */
1176 int r = dbus_get_property("boot_flags",&p);
shgoupfd84fbbf2015-12-17 10:05:51 +08001177
1178 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -05001179 fprintf(stderr, "Dbus get property(boot_flags) failed for get_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +08001180 rc = IPMI_CC_UNSPECIFIED_ERROR;
1181
1182 } else {
1183
1184 s = get_ipmi_boot_option(p);
1185 resp->data[1] = (s << 2);
1186 rc = IPMI_CC_OK;
ratagupta6f6bff2016-04-04 06:20:11 -05001187
shgoupfd84fbbf2015-12-17 10:05:51 +08001188 }
1189
ratagupta6f6bff2016-04-04 06:20:11 -05001190 if (p)
1191 {
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001192 free(p);
1193 p = NULL;
ratagupta6f6bff2016-04-04 06:20:11 -05001194 }
1195
1196 /* Get the boot policy */
1197 r = dbus_get_property("boot_policy",&p);
1198
1199 if (r < 0) {
1200 fprintf(stderr, "Dbus get property(boot_policy) failed for get_sys_boot_options.\n");
1201 rc = IPMI_CC_UNSPECIFIED_ERROR;
1202
1203 } else {
1204
George Keishing012d6a42017-06-14 03:06:48 -05001205 printf("BootPolicy is [%s]\n", p);
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001206 resp->data[0] = (strncmp(p,"ONETIME",strlen("ONETIME"))==0) ?
1207 SET_PARM_BOOT_FLAGS_VALID_ONE_TIME:
1208 SET_PARM_BOOT_FLAGS_VALID_PERMANENT;
ratagupta6f6bff2016-04-04 06:20:11 -05001209 rc = IPMI_CC_OK;
1210
1211 }
1212
1213
Ratan Guptafd28dd72016-08-01 04:58:01 -05001214 } else if ( reqptr->parameter == static_cast<uint8_t>
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001215 ( BootOptionParameter::OPAL_NETWORK_SETTINGS )) {
Ratan Guptafd28dd72016-08-01 04:58:01 -05001216
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001217 *data_len = static_cast<uint8_t>(BootOptionResponseSize::OPAL_NETWORK_SETTINGS);
Ratan Guptafd28dd72016-08-01 04:58:01 -05001218
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001219 resp->parm = static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS);
Ratan Guptafd28dd72016-08-01 04:58:01 -05001220
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001221 int ret = getHostNetworkData(resp);
Ratan Guptafd28dd72016-08-01 04:58:01 -05001222
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001223 if (ret < 0) {
Ratan Guptafd28dd72016-08-01 04:58:01 -05001224
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001225 fprintf(stderr, "getHostNetworkData failed for get_sys_boot_options.\n");
1226 rc = IPMI_CC_UNSPECIFIED_ERROR;
Ratan Guptafd28dd72016-08-01 04:58:01 -05001227
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001228 }else
1229 rc = IPMI_CC_OK;
Ratan Guptafd28dd72016-08-01 04:58:01 -05001230 }
1231
1232 else {
Adriana Kobylak40814c62015-10-27 15:58:44 -05001233 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
shgoupfd84fbbf2015-12-17 10:05:51 +08001234 }
1235
1236 if (p)
1237 free(p);
1238
Ratan Guptafd28dd72016-08-01 04:58:01 -05001239 if (rc == IPMI_CC_OK)
1240 {
1241 *data_len += 2;
1242 }
1243
shgoupfd84fbbf2015-12-17 10:05:51 +08001244 return rc;
1245}
1246
1247
1248
1249ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001250 ipmi_request_t request,
1251 ipmi_response_t response,
1252 ipmi_data_len_t data_len,
1253 ipmi_context_t context)
shgoupfd84fbbf2015-12-17 10:05:51 +08001254{
1255 ipmi_ret_t rc = IPMI_CC_OK;
1256 char *s;
shgoupfd84fbbf2015-12-17 10:05:51 +08001257 set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request;
1258
Ratan Guptafd28dd72016-08-01 04:58:01 -05001259 printf("IPMI SET_SYS_BOOT_OPTIONS reqptr->parameter =[%d]\n",reqptr->parameter);
1260
shgoupfd84fbbf2015-12-17 10:05:51 +08001261 // This IPMI command does not have any resposne data
1262 *data_len = 0;
1263
1264 /* 000101
1265 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
1266 * This is the only parameter used by petitboot.
1267 */
Ratan Guptafd28dd72016-08-01 04:58:01 -05001268
1269 if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) {
shgoupfd84fbbf2015-12-17 10:05:51 +08001270
1271 s = get_boot_option_by_ipmi(((reqptr->data[1] & 0x3C) >> 2));
1272
1273 printf("%d: %s\n", __LINE__, s);
1274 if (!strcmp(s,INVALID_STRING)) {
1275
1276 rc = IPMI_CC_PARM_NOT_SUPPORTED;
1277
1278 } else {
1279
ratagupta6f6bff2016-04-04 06:20:11 -05001280 int r = dbus_set_property("boot_flags",s);
shgoupfd84fbbf2015-12-17 10:05:51 +08001281
1282 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -05001283 fprintf(stderr, "Dbus set property(boot_flags) failed for set_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +08001284 rc = IPMI_CC_UNSPECIFIED_ERROR;
1285 }
1286 }
Ratan Guptafd28dd72016-08-01 04:58:01 -05001287
ratagupta6f6bff2016-04-04 06:20:11 -05001288 /* setting the boot policy */
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001289 s = (char *)(((reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) ==
1290 SET_PARM_BOOT_FLAGS_PERMANENT) ?"PERMANENT":"ONETIME");
ratagupta6f6bff2016-04-04 06:20:11 -05001291
Ratan Guptafd28dd72016-08-01 04:58:01 -05001292 printf ( "\nBoot Policy is %s",s);
ratagupta6f6bff2016-04-04 06:20:11 -05001293 int r = dbus_set_property("boot_policy",s);
1294
1295 if (r < 0) {
1296 fprintf(stderr, "Dbus set property(boot_policy) failed for set_sys_boot_options.\n");
1297 rc = IPMI_CC_UNSPECIFIED_ERROR;
1298 }
shgoupfd84fbbf2015-12-17 10:05:51 +08001299
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001300 } else if (reqptr->parameter ==
1301 (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) {
Ratan Guptafd28dd72016-08-01 04:58:01 -05001302
1303 int ret = setHostNetworkData(reqptr);
1304 if (ret < 0) {
1305 fprintf(stderr, "setHostNetworkData failed for set_sys_boot_options.\n");
1306 rc = IPMI_CC_UNSPECIFIED_ERROR;
1307 }
1308 }
1309 else {
shgoupfd84fbbf2015-12-17 10:05:51 +08001310 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
1311 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak40814c62015-10-27 15:58:44 -05001312 }
1313
1314 return rc;
1315}
1316
1317void register_netfn_chassis_functions()
1318{
Tom05732372016-09-06 17:21:23 +05301319 // <Wildcard Command>
Adriana Kobylak40814c62015-10-27 15:58:44 -05001320 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +05301321 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_WILDCARD, NULL, ipmi_chassis_wildcard,
1322 PRIVILEGE_USER);
Adriana Kobylak40814c62015-10-27 15:58:44 -05001323
Tom05732372016-09-06 17:21:23 +05301324 // Get Chassis Capabilities
Nan Li8d15fb42016-08-16 22:29:40 +08001325 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP);
Tom05732372016-09-06 17:21:23 +05301326 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP, NULL, ipmi_get_chassis_cap,
1327 PRIVILEGE_USER);
Nan Li8d15fb42016-08-16 22:29:40 +08001328
Tom05732372016-09-06 17:21:23 +05301329 // <Get System Boot Options>
Adriana Kobylak40814c62015-10-27 15:58:44 -05001330 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS);
Tom05732372016-09-06 17:21:23 +05301331 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL,
1332 ipmi_chassis_get_sys_boot_options, PRIVILEGE_OPERATOR);
Adriana Kobylak40814c62015-10-27 15:58:44 -05001333
Tom05732372016-09-06 17:21:23 +05301334 // <Get Chassis Status>
Nan Lifdd8ec52016-08-28 03:57:40 +08001335 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS);
Tom05732372016-09-06 17:21:23 +05301336 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS, NULL, ipmi_get_chassis_status,
1337 PRIVILEGE_USER);
Nan Lifdd8ec52016-08-28 03:57:40 +08001338
Tom05732372016-09-06 17:21:23 +05301339 // <Chassis Control>
vishwa36993272015-11-20 12:43:49 -06001340 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL);
Tom05732372016-09-06 17:21:23 +05301341 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control,
1342 PRIVILEGE_OPERATOR);
shgoupfd84fbbf2015-12-17 10:05:51 +08001343
Tom05732372016-09-06 17:21:23 +05301344 // <Set System Boot Options>
shgoupfd84fbbf2015-12-17 10:05:51 +08001345 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS);
Tom05732372016-09-06 17:21:23 +05301346 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL,
1347 ipmi_chassis_set_sys_boot_options, PRIVILEGE_OPERATOR);
vishwa36993272015-11-20 12:43:49 -06001348}