blob: 506d628bcf6cfe85823f0d091a3bff9f30b2b801 [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";
Ratan Gupta6ec7daa2017-07-15 14:13:01 +053047constexpr auto IPV4_ADDRESS_SIZE_BYTE = 4;
48constexpr auto IPV6_ADDRESS_SIZE_BYTE = 16;
49
Ratan Guptafd28dd72016-08-01 04:58:01 -050050//PetiBoot-Specific
Ratan Gupta6ec7daa2017-07-15 14:13:01 +053051static constexpr uint8_t net_conf_initial_bytes[] = {0x80, 0x21, 0x70, 0x62,
52 0x21, 0x00, 0x01, 0x06};
Ratan Guptafd28dd72016-08-01 04:58:01 -050053
54static constexpr size_t COOKIE_OFFSET = 1;
55static constexpr size_t VERSION_OFFSET = 5;
Ratan Gupta6ec7daa2017-07-15 14:13:01 +053056static constexpr size_t ADDR_SIZE_OFFSET = 8;
Ratan Guptafd28dd72016-08-01 04:58:01 -050057static constexpr size_t MAC_OFFSET = 9;
58static constexpr size_t ADDRTYPE_OFFSET = 16;
59static constexpr size_t IPADDR_OFFSET = 17;
ratagupta6f6bff2016-04-04 06:20:11 -050060
shgoupfd84fbbf2015-12-17 10:05:51 +080061
Adriana Kobylak40814c62015-10-27 15:58:44 -050062void register_netfn_chassis_functions() __attribute__((constructor));
63
shgoupfd84fbbf2015-12-17 10:05:51 +080064// Host settings in dbus
65// Service name should be referenced by connection name got via object mapper
66const char *settings_object_name = "/org/openbmc/settings/host0";
67const char *settings_intf_name = "org.freedesktop.DBus.Properties";
68const char *host_intf_name = "org.openbmc.settings.Host";
69
Ratan Guptadcb10672017-07-10 10:33:50 +053070constexpr auto MAPPER_BUS_NAME = "xyz.openbmc_project.ObjectMapper";
71constexpr auto MAPPER_OBJ = "/xyz/openbmc_project/object_mapper";
72constexpr auto MAPPER_INTF = "xyz.openbmc_project.ObjectMapper";
73
74constexpr auto SETTINGS_ROOT = "/";
75constexpr auto SETTINGS_MATCH = "host0";
76constexpr auto PROP_INTF = "org.freedesktop.DBus.Properties";
77
78constexpr auto IP_INTERFACE = "xyz.openbmc_project.Network.IP";
79constexpr auto MAC_INTERFACE = "xyz.openbmc_project.Network.MACAddress";
80
81constexpr auto METHOD_GET = "Get";
82constexpr auto METHOD_GET_ALL = "GetAll";
83constexpr auto METHOD_SET = "Set";
84
Nan Li8d15fb42016-08-16 22:29:40 +080085typedef struct
86{
87 uint8_t cap_flags;
88 uint8_t fru_info_dev_addr;
89 uint8_t sdr_dev_addr;
90 uint8_t sel_dev_addr;
91 uint8_t system_management_dev_addr;
92 uint8_t bridge_dev_addr;
93}__attribute__((packed)) ipmi_chassis_cap_t;
94
Nan Lifdd8ec52016-08-28 03:57:40 +080095typedef struct
96{
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -050097 uint8_t cur_power_state;
98 uint8_t last_power_event;
99 uint8_t misc_power_state;
100 uint8_t front_panel_button_cap_status;
Nan Lifdd8ec52016-08-28 03:57:40 +0800101}__attribute__((packed)) ipmi_get_chassis_status_t;
102
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530103// Phosphor Host State manager
104namespace State = sdbusplus::xyz::openbmc_project::State::server;
105
Andrew Geisslera6e3a302017-05-31 19:34:00 -0500106namespace fs = std::experimental::filesystem;
107
Ratan Guptadcb10672017-07-10 10:33:50 +0530108using namespace phosphor::logging;
109using namespace sdbusplus::xyz::openbmc_project::Common::Error;
110
111/** @brief Gets the dbus object info implementing the given interface
112 * from the given subtree.
113 * @param[in] interface - Dbus interface.
114 * @param[in] serviceRoot - subtree from where the search should start.
115 * @param[in] match - identifier for object.
116 * @return On success returns the object having objectpath and servicename.
117 */
118
119//TODO There may be cases where an interface is implemented by multiple
120// objects,to handle such cases we are interested on that object
121// which are on interested busname.
122// Currently mapper doesn't give the readable busname(gives busid) so we can't
123// use busname to find the object,will do later once the support is there.
124
125ipmi::DbusObjectInfo getDbusObject(const std::string& interface,
126 const std::string& serviceRoot = SETTINGS_ROOT,
127 const std::string& match = "")
128{
129 std::vector<std::string>interfaces;
130 interfaces.emplace_back(interface);
131
132 auto bus = sdbusplus::bus::new_default();
133 auto depth = 0;
134
135 auto mapperCall = bus.new_method_call(MAPPER_BUS_NAME,
136 MAPPER_OBJ,
137 MAPPER_INTF,
138 "GetSubTree");
139
140 mapperCall.append(serviceRoot);
141 mapperCall.append(depth);
142 mapperCall.append(interfaces);
143
144 auto mapperReply = bus.call(mapperCall);
145 if (mapperReply.is_method_error())
146 {
147 log<level::ERR>("Error in mapper call");
148 elog<InternalFailure>();
149 }
150
151 ipmi::ObjectTree objectTree;
152 mapperReply.read(objectTree);
153
154 if (objectTree.empty())
155 {
156 log<level::ERR>("No Object have impelmented the interface",
157 entry("INTERFACE=%s", interface.c_str()));
158 elog<InternalFailure>();
159 }
160
161 ipmi::DbusObjectInfo objectInfo;
162
163 // if match is empty then return the first object
164 if(match == "")
165 {
166 objectInfo = make_pair(objectTree.begin()->first,
167 objectTree.begin()->second.begin()->first);
168 return objectInfo;
169 }
170
171 // else search the match string in the object path
172 auto objectFound = false;
173 for (auto& object : objectTree)
174 {
175 if(object.first.find(match)!= std::string::npos)
176 {
177 objectFound = true;
178 objectInfo = make_pair(object.first, object.second.begin()->first);
179 break;
180 }
181 }
182
183 if(!objectFound)
184 {
185 log<level::ERR>("Failed to find object which matches",
186 entry("MATCH=%s",match.c_str()));
187 elog<InternalFailure>();
188 }
189 return objectInfo;
190
191}
192
193/** @brief Gets the value associated with the given object
194 * and the interface.
195 * @param[in] service - Dbus service name.
196 * @param[in] objPath - Dbus object path.
197 * @param[in] interface - Dbus interface.
198 * @param[in] property - name of the property.
199 * @return On success returns the value of the property.
200 */
201std::string getDbusProperty(const std::string& service,
202 const std::string& objPath,
203 const std::string& interface,
204 const std::string& property)
205{
206
207 sdbusplus::message::variant<std::string> name;
208
209 auto bus = sdbusplus::bus::new_default();
210
211 auto method = bus.new_method_call(
212 service.c_str(),
213 objPath.c_str(),
214 PROP_INTF,
215 METHOD_GET);
216
217 method.append(interface, property);
218
219 auto reply = bus.call(method);
220
221 if (reply.is_method_error())
222 {
223 log<level::ERR>("Failed to get property",
224 entry("PROPERTY=%s", property.c_str()),
225 entry("PATH=%s", objPath.c_str()),
226 entry("INTERFACE=%s", interface.c_str()));
227 elog<InternalFailure>();
228 }
229
230 reply.read(name);
231
232 return name.get<std::string>();
233}
234
235/** @brief Gets all the properties associated with the given object
236 * and the interface.
237 * @param[in] service - Dbus service name.
238 * @param[in] objPath - Dbus object path.
239 * @param[in] interface - Dbus interface.
240 * @return On success returns the map of name value pair.
241 */
242ipmi::PropertyMap getAllDbusProperties(const std::string& service,
243 const std::string& objPath,
244 const std::string& interface)
245{
246 ipmi::PropertyMap properties;
247 auto bus = sdbusplus::bus::new_default();
248
249 auto method = bus.new_method_call(
250 service.c_str(),
251 objPath.c_str(),
252 PROP_INTF,
253 METHOD_GET_ALL);
254
255 method.append(interface);
256
257 auto reply = bus.call(method);
258
259 if (reply.is_method_error())
260 {
261 log<level::ERR>("Failed to get all properties",
262 entry("PATH=%s", objPath.c_str()),
263 entry("INTERFACE=%s", interface.c_str()));
264 elog<InternalFailure>();
265 }
266
267 reply.read(properties);
268 return properties;
269}
270
271/** @brief Sets the property value of the given object.
272 * @param[in] service - Dbus service name.
273 * @param[in] objPath - Dbus object path.
274 * @param[in] interface - Dbus interface.
275 * @param[in] property - name of the property.
276 * @param[in] value - value which needs to be set.
277 */
278void setDbusProperty(const std::string& service,
279 const std::string& objPath,
280 const std::string& interface,
281 const std::string& property,
282 const ipmi::Value& value)
283{
284 auto bus = sdbusplus::bus::new_default();
285
286 auto method = bus.new_method_call(
287 service.c_str(),
288 objPath.c_str(),
289 PROP_INTF,
290 METHOD_SET);
291
292 method.append(interface);
293 method.append(property, value);
294
295 if (!bus.call(method))
296 {
297 log<level::ERR>("Failed to set property",
298 entry("PROPERTY=%s", property.c_str()),
299 entry("PATH=%s",objPath.c_str()),
300 entry("INTERFACE=%s",interface.c_str()));
301 elog<InternalFailure>();
302 }
303
304}
305
306//TODO : Can remove the below function as we have
307// new functions which uses sdbusplus.
308//
309// openbmc/openbmc#1489
ratagupta6f6bff2016-04-04 06:20:11 -0500310int dbus_get_property(const char *name, char **buf)
shgoupfd84fbbf2015-12-17 10:05:51 +0800311{
312 sd_bus_error error = SD_BUS_ERROR_NULL;
313 sd_bus_message *m = NULL;
314 sd_bus *bus = NULL;
315 char *temp_buf = NULL;
316 char *connection = NULL;
317 int r;
318
Brad Bishop35518682016-07-22 08:35:41 -0400319 // Get the system bus where most system services are provided.
320 bus = ipmid_get_sd_bus_connection();
shgoupfd84fbbf2015-12-17 10:05:51 +0800321
Brad Bishop35518682016-07-22 08:35:41 -0400322 r = mapper_get_service(bus, settings_object_name, &connection);
shgoupfd84fbbf2015-12-17 10:05:51 +0800323 if (r < 0) {
Brad Bishop819ddd42016-10-05 21:19:19 -0400324 fprintf(stderr, "Failed to get %s connection: %s\n",
325 settings_object_name, strerror(-r));
shgoupfd84fbbf2015-12-17 10:05:51 +0800326 goto finish;
327 }
328
shgoupfd84fbbf2015-12-17 10:05:51 +0800329 /*
330 * Bus, service, object path, interface and method are provided to call
331 * the method.
332 * Signatures and input arguments are provided by the arguments at the
333 * end.
334 */
335 r = sd_bus_call_method(bus,
336 connection, /* service to contact */
337 settings_object_name, /* object path */
338 settings_intf_name, /* interface name */
339 "Get", /* method name */
340 &error, /* object to return error in */
341 &m, /* return message on success */
342 "ss", /* input signature */
343 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500344 name); /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800345
346 if (r < 0) {
347 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
348 goto finish;
349 }
350
351 /*
352 * The output should be parsed exactly the same as the output formatting
353 * specified.
354 */
355 r = sd_bus_message_read(m, "v", "s", &temp_buf);
356 if (r < 0) {
357 fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
358 goto finish;
359 }
360
Matthew Barth56181052017-01-23 09:36:29 -0600361 *buf = strdup(temp_buf);
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500362 /* *buf = (char*) malloc(strlen(temp_buf));
shgoupfd84fbbf2015-12-17 10:05:51 +0800363 if (*buf) {
364 strcpy(*buf, temp_buf);
365 }
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500366 */
shgoupfd84fbbf2015-12-17 10:05:51 +0800367 printf("IPMID boot option property get: {%s}.\n", (char *) temp_buf);
368
369finish:
370 sd_bus_error_free(&error);
371 sd_bus_message_unref(m);
372 free(connection);
373
374 return r;
375}
376
Ratan Guptadcb10672017-07-10 10:33:50 +0530377//TODO : Can remove the below function as we have
378// new functions which uses sdbusplus.
379//
380// openbmc/openbmc#1489
381
ratagupta6f6bff2016-04-04 06:20:11 -0500382int dbus_set_property(const char * name, const char *value)
shgoupfd84fbbf2015-12-17 10:05:51 +0800383{
384 sd_bus_error error = SD_BUS_ERROR_NULL;
385 sd_bus_message *m = NULL;
386 sd_bus *bus = NULL;
387 char *connection = NULL;
388 int r;
389
Brad Bishop35518682016-07-22 08:35:41 -0400390 // Get the system bus where most system services are provided.
391 bus = ipmid_get_sd_bus_connection();
shgoupfd84fbbf2015-12-17 10:05:51 +0800392
Brad Bishop35518682016-07-22 08:35:41 -0400393 r = mapper_get_service(bus, settings_object_name, &connection);
shgoupfd84fbbf2015-12-17 10:05:51 +0800394 if (r < 0) {
Brad Bishop819ddd42016-10-05 21:19:19 -0400395 fprintf(stderr, "Failed to get %s connection: %s\n",
396 settings_object_name, strerror(-r));
shgoupfd84fbbf2015-12-17 10:05:51 +0800397 goto finish;
398 }
399
shgoupfd84fbbf2015-12-17 10:05:51 +0800400 /*
401 * Bus, service, object path, interface and method are provided to call
402 * the method.
403 * Signatures and input arguments are provided by the arguments at the
404 * end.
405 */
406 r = sd_bus_call_method(bus,
407 connection, /* service to contact */
408 settings_object_name, /* object path */
409 settings_intf_name, /* interface name */
410 "Set", /* method name */
411 &error, /* object to return error in */
412 &m, /* return message on success */
413 "ssv", /* input signature */
414 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500415 name, /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800416 "s", /* third argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500417 value); /* fourth argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800418
419 if (r < 0) {
420 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
421 goto finish;
422 }
423
ratagupta6f6bff2016-04-04 06:20:11 -0500424 printf("IPMID boot option property set: {%s}.\n", value);
shgoupfd84fbbf2015-12-17 10:05:51 +0800425
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500426 finish:
shgoupfd84fbbf2015-12-17 10:05:51 +0800427 sd_bus_error_free(&error);
428 sd_bus_message_unref(m);
429 free(connection);
430
431 return r;
432}
433
Adriana Kobylak40814c62015-10-27 15:58:44 -0500434struct get_sys_boot_options_t {
435 uint8_t parameter;
436 uint8_t set;
437 uint8_t block;
438} __attribute__ ((packed));
439
shgoupfd84fbbf2015-12-17 10:05:51 +0800440struct get_sys_boot_options_response_t {
441 uint8_t version;
442 uint8_t parm;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500443 uint8_t data[SIZE_BOOT_OPTION];
shgoupfd84fbbf2015-12-17 10:05:51 +0800444} __attribute__ ((packed));
445
446struct set_sys_boot_options_t {
447 uint8_t parameter;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500448 uint8_t data[SIZE_BOOT_OPTION];
shgoupfd84fbbf2015-12-17 10:05:51 +0800449} __attribute__ ((packed));
450
Ratan Guptafd28dd72016-08-01 04:58:01 -0500451
Ratan Guptadcb10672017-07-10 10:33:50 +0530452int getHostNetworkData(get_sys_boot_options_response_t* respptr)
Ratan Guptafd28dd72016-08-01 04:58:01 -0500453{
Ratan Guptadcb10672017-07-10 10:33:50 +0530454 ipmi::PropertyMap properties;
455 int rc = 0;
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530456 uint8_t addrSize = IPV4_ADDRESS_SIZE_BYTE;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500457
Ratan Guptadcb10672017-07-10 10:33:50 +0530458 try
459 {
460 //TODO There may be cases where an interface is implemented by multiple
461 // objects,to handle such cases we are interested on that object
462 // which are on interested busname.
463 // Currenlty mapper doesn't give the readable busname(gives busid)
464 // so we can't match with bus name so giving some object specific info
465 // as SETTINGS_MATCH.
466 // Later SETTINGS_MATCH will be replaced with busname.
Ratan Guptafd28dd72016-08-01 04:58:01 -0500467
Ratan Guptadcb10672017-07-10 10:33:50 +0530468 auto ipObjectInfo = getDbusObject(IP_INTERFACE, SETTINGS_ROOT,
469 SETTINGS_MATCH);
470 auto macObjectInfo = getDbusObject(MAC_INTERFACE, SETTINGS_ROOT,
471 SETTINGS_MATCH);
472
473 properties = getAllDbusProperties(ipObjectInfo.second,
474 ipObjectInfo.first, IP_INTERFACE);
475 auto MACAddress =
476 getDbusProperty(macObjectInfo.second, macObjectInfo.first,
477 MAC_INTERFACE, "MACAddress");
478
479 sscanf(MACAddress.c_str(), MAC_ADDRESS_FORMAT,
480 (respptr->data + MAC_OFFSET),
481 (respptr->data + MAC_OFFSET + 1),
482 (respptr->data + MAC_OFFSET + 2),
483 (respptr->data + MAC_OFFSET + 3),
484 (respptr->data + MAC_OFFSET + 4),
485 (respptr->data + MAC_OFFSET + 5));
486
487
488 respptr->data[MAC_OFFSET + 6] = 0x00;
489
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530490 uint8_t addrOrigin = (properties["Origin"].get<std::string>() ==
Ratan Guptadcb10672017-07-10 10:33:50 +0530491 "xyz.openbmc_project.Network.IP.AddressOrigin.Static") ? 1 : 0;
492
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530493 memcpy(respptr->data + ADDRTYPE_OFFSET, &addrOrigin,
494 sizeof(addrOrigin));
495
496 uint8_t addressFamily = (properties["Type"].get<std::string>() ==
497 "xyz.openbmc_project.Network.IP.Protocol.IPv4") ?
498 AF_INET : AF_INET6;
499
500 addrSize = (addressFamily == AF_INET) ? IPV4_ADDRESS_SIZE_BYTE :
501 IPV6_ADDRESS_SIZE_BYTE;
Ratan Guptadcb10672017-07-10 10:33:50 +0530502
503 // ipaddress and gateway would be in IPv4 format
504
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530505 inet_pton(addressFamily,
506 properties["Address"].get<std::string>().c_str(),
Ratan Guptadcb10672017-07-10 10:33:50 +0530507 (respptr->data + IPADDR_OFFSET));
508
509 uint8_t prefix = properties["PrefixLength"].get<uint8_t>();
Ratan Guptadcb10672017-07-10 10:33:50 +0530510
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530511 uint8_t prefixOffset = IPADDR_OFFSET + addrSize;
512
513 memcpy(respptr->data + prefixOffset, &prefix, sizeof(prefix));
514
515 uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix));
516
517 inet_pton(addressFamily,
518 properties["Gateway"].get<std::string>().c_str(),
519 (respptr->data + gatewayOffset));
Ratan Guptadcb10672017-07-10 10:33:50 +0530520
521 }
522 catch (InternalFailure& e)
523 {
524 commit<InternalFailure>();
525 memset(respptr->data, 0, SIZE_BOOT_OPTION);
526 rc = -1;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500527 return rc;
528 }
529
Ratan Guptadcb10672017-07-10 10:33:50 +0530530 //PetiBoot-Specific
531 //If sucess then copy the first 9 bytes to the data
Ratan Guptadcb10672017-07-10 10:33:50 +0530532 memcpy(respptr->data, net_conf_initial_bytes,
533 sizeof(net_conf_initial_bytes));
Ratan Guptafd28dd72016-08-01 04:58:01 -0500534
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530535 memcpy(respptr->data + ADDR_SIZE_OFFSET, &addrSize, sizeof(addrSize));
536
Ratan Guptafd28dd72016-08-01 04:58:01 -0500537#ifdef _IPMI_DEBUG_
Ratan Guptadcb10672017-07-10 10:33:50 +0530538 printf("\n===Printing the IPMI Formatted Data========\n");
Ratan Guptafd28dd72016-08-01 04:58:01 -0500539
Ratan Guptadcb10672017-07-10 10:33:50 +0530540 for (uint8_t pos = 0; pos < index; pos++)
541 {
542 printf("%02x ", respptr->data[pos]);
543 }
Ratan Guptafd28dd72016-08-01 04:58:01 -0500544#endif
545
Ratan Guptafd28dd72016-08-01 04:58:01 -0500546 return rc;
547}
548
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530549/** @brief convert IPv4 and IPv6 addresses from binary to text form.
550 * @param[in] family - IPv4/Ipv6
551 * @param[in] data - req data pointer.
552 * @param[in] offset - offset in the data.
553 * @param[in] addrSize - size of the data which needs to be read from offset.
554 * @returns address in text form.
555 */
556
557std::string getAddrStr(uint8_t family, uint8_t* data,
558 uint8_t offset, uint8_t addrSize)
559{
560 char ipAddr[INET6_ADDRSTRLEN] = {};
561
562 switch(family)
563 {
564 case AF_INET:
565 {
566 struct sockaddr_in addr4 {};
567 memcpy(&addr4.sin_addr.s_addr, &data[offset], addrSize);
568
569 inet_ntop(AF_INET, &addr4.sin_addr,
570 ipAddr, INET_ADDRSTRLEN);
571
572 break;
573 }
574 case AF_INET6:
575 {
576 struct sockaddr_in6 addr6 {};
577 memcpy(&addr6.sin6_addr.s6_addr, &data[offset], addrSize);
578
579 inet_ntop(AF_INET6, &addr6.sin6_addr,
580 ipAddr, INET6_ADDRSTRLEN);
581
582 break;
583 }
584 default:
585 {
586 return {};
587 }
588 }
589
590 return ipAddr;
591}
592
Ratan Guptadcb10672017-07-10 10:33:50 +0530593int setHostNetworkData(set_sys_boot_options_t* reqptr)
Ratan Guptafd28dd72016-08-01 04:58:01 -0500594{
Ratan Guptadcb10672017-07-10 10:33:50 +0530595 using namespace std::string_literals;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500596 std::string host_network_config;
597 char mac[SIZE_MAC] = {0};
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530598 std::string ipAddress, gateway;
599 char addrOrigin {0};
600 uint8_t addrSize {0};
Ratan Guptadcb10672017-07-10 10:33:50 +0530601 std::string addressOrigin =
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530602 "xyz.openbmc_project.Network.IP.AddressOrigin.DHCP";
603 std::string addressType =
604 "xyz.openbmc_project.Network.IP.Protocol.IPv4";
Ratan Guptadcb10672017-07-10 10:33:50 +0530605 uint8_t prefix {0};
606 uint32_t zeroCookie = 0;
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530607 uint8_t family = AF_INET;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500608
609 //cookie starts from second byte
610 // version starts from sixth byte
611
Ratan Guptadcb10672017-07-10 10:33:50 +0530612 try
Ratan Guptafd28dd72016-08-01 04:58:01 -0500613 {
Ratan Guptadcb10672017-07-10 10:33:50 +0530614 do
615 {
616 // cookie == 0x21 0x70 0x62 0x21
617 if (memcmp(&(reqptr->data[COOKIE_OFFSET]),
618 (net_conf_initial_bytes + COOKIE_OFFSET),
619 SIZE_COOKIE) != 0)
620 {
621 //cookie == 0
622 if (memcmp(&(reqptr->data[COOKIE_OFFSET]),
623 &zeroCookie,
624 SIZE_COOKIE) == 0)
625 {
626 // need to zero out the network settings.
627 break;
628 }
629
630 log<level::ERR>("Invalid Cookie");
631 elog<InternalFailure>();
632 }
633
634 // vesion == 0x00 0x01
635 if (memcmp(&(reqptr->data[VERSION_OFFSET]),
636 (net_conf_initial_bytes + VERSION_OFFSET),
637 SIZE_VERSION) != 0)
638 {
639
640 log<level::ERR>("Invalid Version");
641 elog<InternalFailure>();
642 }
643
644 snprintf(mac, SIZE_MAC, MAC_ADDRESS_FORMAT,
645 reqptr->data[MAC_OFFSET],
646 reqptr->data[MAC_OFFSET + 1],
647 reqptr->data[MAC_OFFSET + 2],
648 reqptr->data[MAC_OFFSET + 3],
649 reqptr->data[MAC_OFFSET + 4],
650 reqptr->data[MAC_OFFSET + 5]);
651
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530652 memcpy(&addrOrigin, &(reqptr->data[ADDRTYPE_OFFSET]),
653 sizeof(decltype(addrOrigin)));
Ratan Guptadcb10672017-07-10 10:33:50 +0530654
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530655 if (addrOrigin)
Ratan Guptadcb10672017-07-10 10:33:50 +0530656 {
657 addressOrigin =
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530658 "xyz.openbmc_project.Network.IP.AddressOrigin.Static";
Ratan Guptadcb10672017-07-10 10:33:50 +0530659 }
660
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530661 // Get the address size
662 memcpy(&addrSize ,&reqptr->data[ADDR_SIZE_OFFSET], sizeof(addrSize));
Ratan Guptadcb10672017-07-10 10:33:50 +0530663
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530664 uint8_t prefixOffset = IPADDR_OFFSET + addrSize;
Ratan Guptadcb10672017-07-10 10:33:50 +0530665
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530666 memcpy(&prefix, &(reqptr->data[prefixOffset]), sizeof(decltype(prefix)));
Ratan Guptadcb10672017-07-10 10:33:50 +0530667
Ratan Gupta6ec7daa2017-07-15 14:13:01 +0530668 uint8_t gatewayOffset = prefixOffset + sizeof(decltype(prefix));
669
670 if (addrSize != IPV4_ADDRESS_SIZE_BYTE)
671 {
672 addressType = "xyz.openbmc_project.Network.IP.Protocol.IPv6";
673 family = AF_INET6;
674 }
675
676 ipAddress = getAddrStr(family, reqptr->data, IPADDR_OFFSET, addrSize);
677 gateway = getAddrStr(family, reqptr->data, gatewayOffset, addrSize);
678
Ratan Guptadcb10672017-07-10 10:33:50 +0530679 } while(0);
680
Ratan Guptafd28dd72016-08-01 04:58:01 -0500681 //Cookie == 0 or it is a valid cookie
Ratan Guptadcb10672017-07-10 10:33:50 +0530682 host_network_config += "ipaddress="s + ipAddress +
683 ",prefix="s + std::to_string(prefix) + ",gateway="s + gateway +
684 ",mac="s + mac + ",addressOrigin="s + addressOrigin;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500685
Ratan Guptadcb10672017-07-10 10:33:50 +0530686 log<level::DEBUG>("Network configuration changed",
687 entry("NETWORKCONFIG=%s", host_network_config.c_str()));
Ratan Guptafd28dd72016-08-01 04:58:01 -0500688
Ratan Guptadcb10672017-07-10 10:33:50 +0530689 auto ipObjectInfo = getDbusObject(IP_INTERFACE, SETTINGS_ROOT,
690 SETTINGS_MATCH);
691 auto macObjectInfo = getDbusObject(MAC_INTERFACE, SETTINGS_ROOT,
692 SETTINGS_MATCH);
693 // set the dbus property
694 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
695 IP_INTERFACE, "Address", std::string(ipAddress));
696 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
697 IP_INTERFACE, "PrefixLength", prefix);
698 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
699 IP_INTERFACE, "Origin", addressOrigin);
700 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
701 IP_INTERFACE, "Gateway", std::string(gateway));
702 setDbusProperty(ipObjectInfo.second, ipObjectInfo.first,
703 IP_INTERFACE, "Type",
704 std::string("xyz.openbmc_project.Network.IP.Protocol.IPv4"));
705 setDbusProperty(macObjectInfo.second, macObjectInfo.first,
706 MAC_INTERFACE,"MACAddress", std::string(mac));
Ratan Guptafd28dd72016-08-01 04:58:01 -0500707
708 }
Ratan Guptadcb10672017-07-10 10:33:50 +0530709 catch (InternalFailure& e)
710 {
711 commit<InternalFailure>();
712 return -1;
713 }
714
715 return 0;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500716}
717
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500718ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
719 ipmi_request_t request,
720 ipmi_response_t response,
721 ipmi_data_len_t data_len,
722 ipmi_context_t context)
Adriana Kobylak40814c62015-10-27 15:58:44 -0500723{
724 printf("Handling CHASSIS WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
725 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800726 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500727 *data_len = 0;
728 return rc;
729}
730
Nan Li8d15fb42016-08-16 22:29:40 +0800731ipmi_ret_t ipmi_get_chassis_cap(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500732 ipmi_request_t request, ipmi_response_t response,
733 ipmi_data_len_t data_len, ipmi_context_t context)
Nan Li8d15fb42016-08-16 22:29:40 +0800734{
735 // sd_bus error
736 ipmi_ret_t rc = IPMI_CC_OK;
737
738 ipmi_chassis_cap_t chassis_cap{};
739
740 *data_len = sizeof(ipmi_chassis_cap_t);
741
742 // TODO: need future work. Get those flag from MRW.
743
744 // capabilities flags
745 // [7..4] - reserved
746 // [3] – 1b = provides power interlock (IPM 1.5)
747 // [2] – 1b = provides Diagnostic Interrupt (FP NMI)
748 // [1] – 1b = provides “Front Panel Lockout” (indicates that the chassis has capabilities
749 // to lock out external power control and reset button or front panel interfaces
750 // and/or detect tampering with those interfaces).
751 // [0] -1b = Chassis provides intrusion (physical security) sensor.
752 // set to default value 0x0.
753 chassis_cap.cap_flags = 0x0;
754
755 // Since we do not have a separate SDR Device/SEL Device/ FRU repository.
756 // The 20h was given as those 5 device addresses.
757 // Chassis FRU info Device Address
758 chassis_cap.fru_info_dev_addr = 0x20;
759
760 // Chassis SDR Device Address
761 chassis_cap.sdr_dev_addr = 0x20;
762
763 // Chassis SEL Device Address
764 chassis_cap.sel_dev_addr = 0x20;
765
766 // Chassis System Management Device Address
767 chassis_cap.system_management_dev_addr = 0x20;
768
769 // Chassis Bridge Device Address.
770 chassis_cap.bridge_dev_addr = 0x20;
771
772 memcpy(response, &chassis_cap, *data_len);
773
774 return rc;
775}
776
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530777//------------------------------------------
778// Calls into Host State Manager Dbus object
779//------------------------------------------
780int initiate_state_transition(State::Host::Transition transition)
vishwa36993272015-11-20 12:43:49 -0600781{
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500782 // OpenBMC Host State Manager dbus framework
783 constexpr auto HOST_STATE_MANAGER_ROOT = "/xyz/openbmc_project/state/host0";
784 constexpr auto HOST_STATE_MANAGER_IFACE = "xyz.openbmc_project.State.Host";
785 constexpr auto DBUS_PROPERTY_IFACE = "org.freedesktop.DBus.Properties";
786 constexpr auto PROPERTY = "RequestedHostTransition";
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530787
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500788 // sd_bus error
789 int rc = 0;
790 char *busname = NULL;
vishwa36993272015-11-20 12:43:49 -0600791
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500792 // SD Bus error report mechanism.
793 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
vishwa36993272015-11-20 12:43:49 -0600794
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500795 // Gets a hook onto either a SYSTEM or SESSION bus
796 sd_bus *bus_type = ipmid_get_sd_bus_connection();
797 rc = mapper_get_service(bus_type, HOST_STATE_MANAGER_ROOT, &busname);
798 if (rc < 0)
799 {
800 log<level::ERR>("Failed to get bus name",
801 entry("ERROR=%s, OBJPATH=%s",
802 strerror(-rc), HOST_STATE_MANAGER_ROOT));
803 return rc;
804 }
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530805
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500806 // Convert to string equivalent of the passed in transition enum.
807 auto request = State::convertForMessage(transition);
Vishwanatha Subbannab12b0c02017-03-07 18:17:19 +0530808
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500809 rc = sd_bus_call_method(bus_type, // On the system bus
810 busname, // Service to contact
811 HOST_STATE_MANAGER_ROOT, // Object path
812 DBUS_PROPERTY_IFACE, // Interface name
813 "Set", // Method to be called
814 &bus_error, // object to return error
815 nullptr, // Response buffer if any
816 "ssv", // Takes 3 arguments
817 HOST_STATE_MANAGER_IFACE,
818 PROPERTY,
819 "s", request.c_str());
820 if(rc < 0)
821 {
822 log<level::ERR>("Failed to initiate transition",
823 entry("ERROR=%s, REQUEST=%s",
824 bus_error.message, request.c_str()));
825 }
826 else
827 {
828 log<level::INFO>("Transition request initiated successfully");
829 }
vishwa36993272015-11-20 12:43:49 -0600830
831 sd_bus_error_free(&bus_error);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500832 free(busname);
vishwa36993272015-11-20 12:43:49 -0600833
Sergey Solomineb9b8142016-08-23 09:07:28 -0500834 return rc;
vishwa36993272015-11-20 12:43:49 -0600835}
836
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500837struct hostPowerPolicyTypeMap_t
838{
Nan Lifdd8ec52016-08-28 03:57:40 +0800839 uint8_t policyNum;
840 char policyName[19];
841};
842
843hostPowerPolicyTypeMap_t g_hostPowerPolicyTypeMap_t[] = {
844
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500845 {0x00, "LEAVE_OFF"},
846 {0x01, "RESTORE_LAST_STATE"},
847 {0x02, "ALWAYS_POWER_ON"},
848 {0x03, "UNKNOWN"}
Nan Lifdd8ec52016-08-28 03:57:40 +0800849};
850
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500851uint8_t get_host_power_policy(char *p)
852{
Nan Lifdd8ec52016-08-28 03:57:40 +0800853
854 hostPowerPolicyTypeMap_t *s = g_hostPowerPolicyTypeMap_t;
855
856 while (s->policyNum != 0x03) {
857 if (!strcmp(s->policyName,p))
858 break;
859 s++;
860 }
861
862 return s->policyNum;
863}
864
865//----------------------------------------------------------------------
866// Get Chassis Status commands
867//----------------------------------------------------------------------
868ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500869 ipmi_request_t request,
870 ipmi_response_t response,
871 ipmi_data_len_t data_len,
872 ipmi_context_t context)
Nan Lifdd8ec52016-08-28 03:57:40 +0800873{
874 const char *objname = "/org/openbmc/control/power0";
875 const char *intf = "org.openbmc.control.Power";
876
877 sd_bus *bus = NULL;
878 sd_bus_message *reply = NULL;
879 int r = 0;
880 int pgood = 0;
881 char *busname = NULL;
882 ipmi_ret_t rc = IPMI_CC_OK;
883 ipmi_get_chassis_status_t chassis_status{};
884
885 char *p = NULL;
886 uint8_t s = 0;
887
888 // Get the system bus where most system services are provided.
889 bus = ipmid_get_sd_bus_connection();
890
891 *data_len = 4;
892
893 r = mapper_get_service(bus, objname, &busname);
894 if (r < 0) {
895 fprintf(stderr, "Failed to get bus name, return value: %s.\n", strerror(-r));
896 rc = IPMI_CC_UNSPECIFIED_ERROR;
897 goto finish;
898 }
899
900 r = sd_bus_get_property(bus, busname, objname, intf, "pgood", NULL, &reply, "i");
901 if (r < 0) {
902 fprintf(stderr, "Failed to call sd_bus_get_property:%d, %s\n", r, strerror(-r));
903 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
904 busname, objname, intf);
905 rc = IPMI_CC_UNSPECIFIED_ERROR;
906 goto finish;
907 }
908
909 r = sd_bus_message_read(reply, "i", &pgood);
910 if (r < 0) {
911 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r));
912 rc = IPMI_CC_UNSPECIFIED_ERROR;
913 goto finish;
914 }
915
916 printf("pgood is 0x%02x\n", pgood);
917
918 // Get Power Policy
919 r = dbus_get_property("power_policy",&p);
920
921 if (r < 0) {
922 fprintf(stderr, "Dbus get property(power_policy) failed for get_sys_boot_options.\n");
923 rc = IPMI_CC_UNSPECIFIED_ERROR;
924 } else {
925 s = get_host_power_policy(p);
926 }
927
928 if (p)
929 {
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -0500930 free(p);
931 p = NULL;
Nan Lifdd8ec52016-08-28 03:57:40 +0800932 }
933
934 // Current Power State
935 // [7] reserved
936 // [6..5] power restore policy
937 // 00b = chassis stays powered off after AC/mains returns
938 // 01b = after AC returns, power is restored to the state that was
939 // in effect when AC/mains was lost.
940 // 10b = chassis always powers up after AC/mains returns
941 // 11b = unknow
942 // Set to 00b, by observing the hardware behavior.
943 // Do we need to define a dbus property to identify the restore policy?
944
945 // [4] power control fault
946 // 1b = controller attempted to turn system power on or off, but
947 // system did not enter desired state.
948 // Set to 0b, since We don't support it..
949
950 // [3] power fault
951 // 1b = fault detected in main power subsystem.
952 // set to 0b. for we don't support it.
953
954 // [2] 1b = interlock (chassis is presently shut down because a chassis
955 // panel interlock switch is active). (IPMI 1.5)
956 // set to 0b, for we don't support it.
957
958 // [1] power overload
959 // 1b = system shutdown because of power overload condition.
960 // set to 0b, for we don't support it.
961
962 // [0] power is on
963 // 1b = system power is on
964 // 0b = system power is off(soft-off S4/S5, or mechanical off)
965
966 chassis_status.cur_power_state = ((s & 0x3)<<5) | (pgood & 0x1);
967
968 // Last Power Event
969 // [7..5] – reserved
970 // [4] – 1b = last ‘Power is on’ state was entered via IPMI command
971 // [3] – 1b = last power down caused by power fault
972 // [2] – 1b = last power down caused by a power interlock being activated
973 // [1] – 1b = last power down caused by a Power overload
974 // [0] – 1b = AC failed
975 // set to 0x0, for we don't support these fields.
976
977 chassis_status.last_power_event = 0;
978
979 // Misc. Chassis State
980 // [7] – reserved
981 // [6] – 1b = Chassis Identify command and state info supported (Optional)
982 // 0b = Chassis Identify command support unspecified via this command.
983 // (The Get Command Support command , if implemented, would still
984 // indicate support for the Chassis Identify command)
985 // [5..4] – Chassis Identify State. Mandatory when bit[6] =1b, reserved (return
986 // as 00b) otherwise. Returns the present chassis identify state.
987 // Refer to the Chassis Identify command for more info.
988 // 00b = chassis identify state = Off
989 // 01b = chassis identify state = Temporary(timed) On
990 // 10b = chassis identify state = Indefinite On
991 // 11b = reserved
992 // [3] – 1b = Cooling/fan fault detected
993 // [2] – 1b = Drive Fault
994 // [1] – 1b = Front Panel Lockout active (power off and reset via chassis
995 // push-buttons disabled.)
996 // [0] – 1b = Chassis Intrusion active
997 // set to 0, for we don't support them.
998 chassis_status.misc_power_state = 0;
999
1000 // Front Panel Button Capabilities and disable/enable status(Optional)
1001 // set to 0, for we don't support them.
1002 chassis_status.front_panel_button_cap_status = 0;
1003
1004 // Pack the actual response
1005 memcpy(response, &chassis_status, *data_len);
1006
1007finish:
1008 free(busname);
1009 reply = sd_bus_message_unref(reply);
1010
1011 return rc;
1012}
Chris Austen7888c4d2015-12-03 15:26:20 -06001013
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301014//-------------------------------------------------------------
1015// Send a command to SoftPowerOff application to stop any timer
1016//-------------------------------------------------------------
1017int stop_soft_off_timer()
1018{
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301019 constexpr auto iface = "org.freedesktop.DBus.Properties";
1020 constexpr auto soft_off_iface = "xyz.openbmc_project.Ipmi.Internal."
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001021 "SoftPowerOff";
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301022
1023 constexpr auto property = "ResponseReceived";
1024 constexpr auto value = "xyz.openbmc_project.Ipmi.Internal."
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001025 "SoftPowerOff.HostResponse.HostShutdown";
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301026
1027 // Get the system bus where most system services are provided.
1028 auto bus = ipmid_get_sd_bus_connection();
1029
1030 // Get the service name
Andrew Geissler2b4e4592017-06-08 11:18:35 -05001031 // TODO openbmc/openbmc#1661 - Mapper refactor
1032 //
1033 // See openbmc/openbmc#1743 for some details but high level summary is that
1034 // for now the code will directly call the soft off interface due to a
1035 // race condition with mapper usage
1036 //
1037 //char *busname = nullptr;
1038 //auto r = mapper_get_service(bus, SOFTOFF_OBJPATH, &busname);
1039 //if (r < 0)
1040 //{
1041 // fprintf(stderr, "Failed to get %s bus name: %s\n",
1042 // SOFTOFF_OBJPATH, strerror(-r));
1043 // return r;
1044 //}
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301045
1046 // No error object or reply expected.
Andrew Geissler2b4e4592017-06-08 11:18:35 -05001047 int rc = sd_bus_call_method(bus, SOFTOFF_BUSNAME, SOFTOFF_OBJPATH, iface,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001048 "Set", nullptr, nullptr, "ssv",
1049 soft_off_iface, property, "s", value);
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301050 if (rc < 0)
1051 {
1052 fprintf(stderr, "Failed to set property in SoftPowerOff object: %s\n",
1053 strerror(-rc));
1054 }
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001055
Andrew Geissler2b4e4592017-06-08 11:18:35 -05001056 //TODO openbmc/openbmc#1661 - Mapper refactor
1057 //free(busname);
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301058 return rc;
1059}
1060
vishwa36993272015-11-20 12:43:49 -06001061//----------------------------------------------------------------------
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001062// Create file to indicate there is no need for softoff notification to host
1063//----------------------------------------------------------------------
1064void indicate_no_softoff_needed()
1065{
1066 fs::path path{HOST_INBAND_REQUEST_DIR};
1067 if (!fs::is_directory(path))
1068 {
1069 fs::create_directory(path);
1070 }
1071
1072 // Add the host instance (default 0 for now) to the file name
1073 std::string file{HOST_INBAND_REQUEST_FILE};
1074 auto size = std::snprintf(nullptr,0,file.c_str(),0);
1075 size++; // null
1076 std::unique_ptr<char[]> buf(new char[size]);
1077 std::snprintf(buf.get(),size,file.c_str(),0);
1078
1079 // Append file name to directory and create it
1080 path /= buf.get();
1081 std::ofstream(path.c_str());
1082}
1083
1084//----------------------------------------------------------------------
vishwa36993272015-11-20 12:43:49 -06001085// Chassis Control commands
1086//----------------------------------------------------------------------
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001087ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1088 ipmi_request_t request,
1089 ipmi_response_t response,
1090 ipmi_data_len_t data_len,
1091 ipmi_context_t context)
vishwa36993272015-11-20 12:43:49 -06001092{
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001093 // Error from power off.
1094 int rc = 0;
vishwa36993272015-11-20 12:43:49 -06001095
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001096 // No response for this command.
vishwa36993272015-11-20 12:43:49 -06001097 *data_len = 0;
1098
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001099 // Catch the actual operaton by peeking into request buffer
1100 uint8_t chassis_ctrl_cmd = *(uint8_t *)request;
1101 printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd);
vishwa36993272015-11-20 12:43:49 -06001102
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001103 switch(chassis_ctrl_cmd)
1104 {
1105 case CMD_POWER_ON:
1106 rc = initiate_state_transition(State::Host::Transition::On);
1107 break;
1108 case CMD_POWER_OFF:
1109 // Need to Nudge SoftPowerOff application that it needs to stop the
1110 // watchdog timer if running.
1111 rc = stop_soft_off_timer();
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001112 // Only request the Off transition if the soft power off
1113 // application is not running
1114 if (rc < 0)
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001115 {
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001116 log<level::INFO>("Did not find soft off service so request "
1117 "Host:Transition:Off");
1118
1119 // First create a file to indicate to the soft off application
1120 // that it should not run since this is a direct user initiated
1121 // power off request (i.e. a power off request that is not
1122 // originating via a soft power off SMS request)
1123 indicate_no_softoff_needed();
1124
1125 // Now request the shutdown
1126 rc = initiate_state_transition(State::Host::Transition::Off);
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001127 }
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001128 else
1129 {
1130 log<level::INFO>("Soft off is running, so let that stop "
1131 "the host");
1132 }
1133
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001134 break;
Vishwanatha Subbanna83b5c1c2017-01-25 18:41:51 +05301135
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001136 case CMD_HARD_RESET:
1137 case CMD_POWER_CYCLE:
1138 // SPEC has a section that says certain implementations can trigger
1139 // PowerOn if power is Off when a command to power cycle is
1140 // requested
Andrew Geisslera6e3a302017-05-31 19:34:00 -05001141
1142 // First create a file to indicate to the soft off application
1143 // that it should not run since this is a direct user initiated
1144 // power reboot request (i.e. a reboot request that is not
1145 // originating via a soft power off SMS request)
1146 indicate_no_softoff_needed();
1147
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001148 rc = initiate_state_transition(State::Host::Transition::Reboot);
1149 break;
1150 default:
1151 {
1152 fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd);
1153 rc = -1;
1154 }
1155 }
vishwa36993272015-11-20 12:43:49 -06001156
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001157 return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK);
vishwa36993272015-11-20 12:43:49 -06001158}
1159
shgoupfd84fbbf2015-12-17 10:05:51 +08001160struct bootOptionTypeMap_t {
1161 uint8_t ipmibootflag;
1162 char dbusname[8];
1163};
1164
1165#define INVALID_STRING "Invalid"
1166// dbus supports this list of boot devices.
1167bootOptionTypeMap_t g_bootOptionTypeMap_t[] = {
1168
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001169 {0x01, "Network"},
1170 {0x02, "Disk"},
1171 {0x03, "Safe"},
1172 {0x05, "CDROM"},
1173 {0x06, "Setup"},
1174 {0x00, "Default"},
1175 {0xFF, INVALID_STRING}
shgoupfd84fbbf2015-12-17 10:05:51 +08001176};
1177
1178uint8_t get_ipmi_boot_option(char *p) {
1179
1180 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
1181
1182 while (s->ipmibootflag != 0xFF) {
1183 if (!strcmp(s->dbusname,p))
1184 break;
1185 s++;
1186 }
1187
1188 if (!s->ipmibootflag)
1189 printf("Failed to find Sensor Type %s\n", p);
1190
1191 return s->ipmibootflag;
1192}
1193
1194char* get_boot_option_by_ipmi(uint8_t p) {
1195
1196 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
1197
1198 while (s->ipmibootflag != 0xFF) {
1199
1200 if (s->ipmibootflag == p)
1201 break;
1202
1203 s++;
1204 }
1205
1206
1207 if (!s->ipmibootflag)
1208 printf("Failed to find Sensor Type 0x%x\n", p);
1209
1210 return s->dbusname;
1211}
1212
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001213ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
1214 ipmi_request_t request,
1215 ipmi_response_t response,
1216 ipmi_data_len_t data_len,
1217 ipmi_context_t context)
Adriana Kobylak40814c62015-10-27 15:58:44 -05001218{
shgoupfd84fbbf2015-12-17 10:05:51 +08001219 ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED;
1220 char *p = NULL;
1221 get_sys_boot_options_response_t *resp = (get_sys_boot_options_response_t *) response;
1222 get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request;
1223 uint8_t s;
Adriana Kobylak40814c62015-10-27 15:58:44 -05001224
1225 printf("IPMI GET_SYS_BOOT_OPTIONS\n");
1226
shgoupfd84fbbf2015-12-17 10:05:51 +08001227 memset(resp,0,sizeof(*resp));
1228 resp->version = SET_PARM_VERSION;
1229 resp->parm = 5;
ratagupta6f6bff2016-04-04 06:20:11 -05001230 resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
Adriana Kobylak40814c62015-10-27 15:58:44 -05001231
Adriana Kobylak40814c62015-10-27 15:58:44 -05001232
shgoupfd84fbbf2015-12-17 10:05:51 +08001233 /*
1234 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
1235 * This is the only parameter used by petitboot.
1236 */
Ratan Guptafd28dd72016-08-01 04:58:01 -05001237 if ( reqptr->parameter == static_cast<uint8_t>
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001238 ( BootOptionParameter::BOOT_FLAGS )) {
shgoupfd84fbbf2015-12-17 10:05:51 +08001239
Ratan Guptafd28dd72016-08-01 04:58:01 -05001240 *data_len = static_cast<uint8_t>(BootOptionResponseSize::BOOT_FLAGS);
ratagupta6f6bff2016-04-04 06:20:11 -05001241 /* Get the boot device */
1242 int r = dbus_get_property("boot_flags",&p);
shgoupfd84fbbf2015-12-17 10:05:51 +08001243
1244 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -05001245 fprintf(stderr, "Dbus get property(boot_flags) failed for get_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +08001246 rc = IPMI_CC_UNSPECIFIED_ERROR;
1247
1248 } else {
1249
1250 s = get_ipmi_boot_option(p);
1251 resp->data[1] = (s << 2);
1252 rc = IPMI_CC_OK;
ratagupta6f6bff2016-04-04 06:20:11 -05001253
shgoupfd84fbbf2015-12-17 10:05:51 +08001254 }
1255
ratagupta6f6bff2016-04-04 06:20:11 -05001256 if (p)
1257 {
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001258 free(p);
1259 p = NULL;
ratagupta6f6bff2016-04-04 06:20:11 -05001260 }
1261
1262 /* Get the boot policy */
1263 r = dbus_get_property("boot_policy",&p);
1264
1265 if (r < 0) {
1266 fprintf(stderr, "Dbus get property(boot_policy) failed for get_sys_boot_options.\n");
1267 rc = IPMI_CC_UNSPECIFIED_ERROR;
1268
1269 } else {
1270
George Keishing012d6a42017-06-14 03:06:48 -05001271 printf("BootPolicy is [%s]\n", p);
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001272 resp->data[0] = (strncmp(p,"ONETIME",strlen("ONETIME"))==0) ?
1273 SET_PARM_BOOT_FLAGS_VALID_ONE_TIME:
1274 SET_PARM_BOOT_FLAGS_VALID_PERMANENT;
ratagupta6f6bff2016-04-04 06:20:11 -05001275 rc = IPMI_CC_OK;
1276
1277 }
1278
1279
Ratan Guptafd28dd72016-08-01 04:58:01 -05001280 } else if ( reqptr->parameter == static_cast<uint8_t>
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001281 ( BootOptionParameter::OPAL_NETWORK_SETTINGS )) {
Ratan Guptafd28dd72016-08-01 04:58:01 -05001282
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001283 *data_len = static_cast<uint8_t>(BootOptionResponseSize::OPAL_NETWORK_SETTINGS);
Ratan Guptafd28dd72016-08-01 04:58:01 -05001284
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001285 resp->parm = static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS);
Ratan Guptafd28dd72016-08-01 04:58:01 -05001286
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001287 int ret = getHostNetworkData(resp);
Ratan Guptafd28dd72016-08-01 04:58:01 -05001288
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001289 if (ret < 0) {
Ratan Guptafd28dd72016-08-01 04:58:01 -05001290
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001291 fprintf(stderr, "getHostNetworkData failed for get_sys_boot_options.\n");
1292 rc = IPMI_CC_UNSPECIFIED_ERROR;
Ratan Guptafd28dd72016-08-01 04:58:01 -05001293
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001294 }else
1295 rc = IPMI_CC_OK;
Ratan Guptafd28dd72016-08-01 04:58:01 -05001296 }
1297
1298 else {
Adriana Kobylak40814c62015-10-27 15:58:44 -05001299 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
shgoupfd84fbbf2015-12-17 10:05:51 +08001300 }
1301
1302 if (p)
1303 free(p);
1304
Ratan Guptafd28dd72016-08-01 04:58:01 -05001305 if (rc == IPMI_CC_OK)
1306 {
1307 *data_len += 2;
1308 }
1309
shgoupfd84fbbf2015-12-17 10:05:51 +08001310 return rc;
1311}
1312
1313
1314
1315ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001316 ipmi_request_t request,
1317 ipmi_response_t response,
1318 ipmi_data_len_t data_len,
1319 ipmi_context_t context)
shgoupfd84fbbf2015-12-17 10:05:51 +08001320{
1321 ipmi_ret_t rc = IPMI_CC_OK;
1322 char *s;
shgoupfd84fbbf2015-12-17 10:05:51 +08001323 set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request;
1324
Ratan Guptafd28dd72016-08-01 04:58:01 -05001325 printf("IPMI SET_SYS_BOOT_OPTIONS reqptr->parameter =[%d]\n",reqptr->parameter);
1326
shgoupfd84fbbf2015-12-17 10:05:51 +08001327 // This IPMI command does not have any resposne data
1328 *data_len = 0;
1329
1330 /* 000101
1331 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
1332 * This is the only parameter used by petitboot.
1333 */
Ratan Guptafd28dd72016-08-01 04:58:01 -05001334
1335 if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) {
shgoupfd84fbbf2015-12-17 10:05:51 +08001336
1337 s = get_boot_option_by_ipmi(((reqptr->data[1] & 0x3C) >> 2));
1338
1339 printf("%d: %s\n", __LINE__, s);
1340 if (!strcmp(s,INVALID_STRING)) {
1341
1342 rc = IPMI_CC_PARM_NOT_SUPPORTED;
1343
1344 } else {
1345
ratagupta6f6bff2016-04-04 06:20:11 -05001346 int r = dbus_set_property("boot_flags",s);
shgoupfd84fbbf2015-12-17 10:05:51 +08001347
1348 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -05001349 fprintf(stderr, "Dbus set property(boot_flags) failed for set_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +08001350 rc = IPMI_CC_UNSPECIFIED_ERROR;
1351 }
1352 }
Ratan Guptafd28dd72016-08-01 04:58:01 -05001353
ratagupta6f6bff2016-04-04 06:20:11 -05001354 /* setting the boot policy */
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001355 s = (char *)(((reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) ==
1356 SET_PARM_BOOT_FLAGS_PERMANENT) ?"PERMANENT":"ONETIME");
ratagupta6f6bff2016-04-04 06:20:11 -05001357
Ratan Guptafd28dd72016-08-01 04:58:01 -05001358 printf ( "\nBoot Policy is %s",s);
ratagupta6f6bff2016-04-04 06:20:11 -05001359 int r = dbus_set_property("boot_policy",s);
1360
1361 if (r < 0) {
1362 fprintf(stderr, "Dbus set property(boot_policy) failed for set_sys_boot_options.\n");
1363 rc = IPMI_CC_UNSPECIFIED_ERROR;
1364 }
shgoupfd84fbbf2015-12-17 10:05:51 +08001365
Andrew Geisslerfca6a4f2017-05-30 10:55:39 -05001366 } else if (reqptr->parameter ==
1367 (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) {
Ratan Guptafd28dd72016-08-01 04:58:01 -05001368
1369 int ret = setHostNetworkData(reqptr);
1370 if (ret < 0) {
1371 fprintf(stderr, "setHostNetworkData failed for set_sys_boot_options.\n");
1372 rc = IPMI_CC_UNSPECIFIED_ERROR;
1373 }
1374 }
1375 else {
shgoupfd84fbbf2015-12-17 10:05:51 +08001376 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
1377 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak40814c62015-10-27 15:58:44 -05001378 }
1379
1380 return rc;
1381}
1382
1383void register_netfn_chassis_functions()
1384{
Tom05732372016-09-06 17:21:23 +05301385 // <Wildcard Command>
Adriana Kobylak40814c62015-10-27 15:58:44 -05001386 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_WILDCARD);
Tom05732372016-09-06 17:21:23 +05301387 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_WILDCARD, NULL, ipmi_chassis_wildcard,
1388 PRIVILEGE_USER);
Adriana Kobylak40814c62015-10-27 15:58:44 -05001389
Tom05732372016-09-06 17:21:23 +05301390 // Get Chassis Capabilities
Nan Li8d15fb42016-08-16 22:29:40 +08001391 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP);
Tom05732372016-09-06 17:21:23 +05301392 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP, NULL, ipmi_get_chassis_cap,
1393 PRIVILEGE_USER);
Nan Li8d15fb42016-08-16 22:29:40 +08001394
Tom05732372016-09-06 17:21:23 +05301395 // <Get System Boot Options>
Adriana Kobylak40814c62015-10-27 15:58:44 -05001396 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS);
Tom05732372016-09-06 17:21:23 +05301397 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL,
1398 ipmi_chassis_get_sys_boot_options, PRIVILEGE_OPERATOR);
Adriana Kobylak40814c62015-10-27 15:58:44 -05001399
Tom05732372016-09-06 17:21:23 +05301400 // <Get Chassis Status>
Nan Lifdd8ec52016-08-28 03:57:40 +08001401 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS);
Tom05732372016-09-06 17:21:23 +05301402 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS, NULL, ipmi_get_chassis_status,
1403 PRIVILEGE_USER);
Nan Lifdd8ec52016-08-28 03:57:40 +08001404
Tom05732372016-09-06 17:21:23 +05301405 // <Chassis Control>
vishwa36993272015-11-20 12:43:49 -06001406 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL);
Tom05732372016-09-06 17:21:23 +05301407 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control,
1408 PRIVILEGE_OPERATOR);
shgoupfd84fbbf2015-12-17 10:05:51 +08001409
Tom05732372016-09-06 17:21:23 +05301410 // <Set System Boot Options>
shgoupfd84fbbf2015-12-17 10:05:51 +08001411 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS);
Tom05732372016-09-06 17:21:23 +05301412 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL,
1413 ipmi_chassis_set_sys_boot_options, PRIVILEGE_OPERATOR);
vishwa36993272015-11-20 12:43:49 -06001414}