blob: 6d5a5fd6876bea40d9b1cf45bdb413dfa6b8dc15 [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"
Adriana Kobylak40814c62015-10-27 15:58:44 -05003#include <stdio.h>
Ratan Guptafd28dd72016-08-01 04:58:01 -05004#include <stdlib.h>
Adriana Kobylak40814c62015-10-27 15:58:44 -05005#include <stdint.h>
Brad Bishop35518682016-07-22 08:35:41 -04006#include <mapper.h>
Ratan Guptafd28dd72016-08-01 04:58:01 -05007#include <arpa/inet.h>
8#include <netinet/in.h>
9#include <limits.h>
10#include <string.h>
11#include <endian.h>
12#include <sstream>
13#include <array>
ratagupta6f6bff2016-04-04 06:20:11 -050014
15//Defines
Ratan Guptafd28dd72016-08-01 04:58:01 -050016#define SET_PARM_VERSION 0x01
17#define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 //boot flags data1 7th bit on
ratagupta6f6bff2016-04-04 06:20:11 -050018#define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 //boot flags data1 8th bit on
Ratan Guptafd28dd72016-08-01 04:58:01 -050019#define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 //boot flags data1 7 & 8 bit on
ratagupta6f6bff2016-04-04 06:20:11 -050020
Ratan Guptafd28dd72016-08-01 04:58:01 -050021constexpr size_t SIZE_MAC = 18;
22constexpr size_t SIZE_BOOT_OPTION = (uint8_t)BootOptionResponseSize::
23 OPAL_NETWORK_SETTINGS;//Maximum size of the boot option parametrs
24constexpr size_t SIZE_PREFIX = 7;
25constexpr size_t MAX_PREFIX_VALUE = 32;
26constexpr size_t SIZE_COOKIE = 4;
27constexpr size_t SIZE_VERSION = 2;
28constexpr auto MAC_ADDRESS_FORMAT = "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx";
29constexpr auto IP_ADDRESS_FORMAT = "%d.%d.%d.%d";
Matthew Barth8b470052016-09-21 10:02:57 -050030constexpr auto PREFIX_FORMAT = "%hhd";
Ratan Guptafd28dd72016-08-01 04:58:01 -050031constexpr auto ADDR_TYPE_FORMAT = "%hhx";
32//PetiBoot-Specific
33static constexpr uint8_t net_conf_initial_bytes[] = {0x80,0x21, 0x70 ,0x62 ,0x21,
34 0x00 ,0x01 ,0x06 ,0x04};
35
36static constexpr size_t COOKIE_OFFSET = 1;
37static constexpr size_t VERSION_OFFSET = 5;
38static constexpr size_t MAC_OFFSET = 9;
39static constexpr size_t ADDRTYPE_OFFSET = 16;
40static constexpr size_t IPADDR_OFFSET = 17;
41static constexpr size_t PREFIX_OFFSET = 21;
42static constexpr size_t GATEWAY_OFFSET = 22;
ratagupta6f6bff2016-04-04 06:20:11 -050043
44
vishwa36993272015-11-20 12:43:49 -060045// OpenBMC Chassis Manager dbus framework
vishwa36993272015-11-20 12:43:49 -060046const char *chassis_object_name = "/org/openbmc/control/chassis0";
47const char *chassis_intf_name = "org.openbmc.control.Chassis";
48
shgoupfd84fbbf2015-12-17 10:05:51 +080049
Adriana Kobylak40814c62015-10-27 15:58:44 -050050void register_netfn_chassis_functions() __attribute__((constructor));
51
shgoupfd84fbbf2015-12-17 10:05:51 +080052// Host settings in dbus
53// Service name should be referenced by connection name got via object mapper
54const char *settings_object_name = "/org/openbmc/settings/host0";
55const char *settings_intf_name = "org.freedesktop.DBus.Properties";
56const char *host_intf_name = "org.openbmc.settings.Host";
57
Nan Li8d15fb42016-08-16 22:29:40 +080058typedef struct
59{
60 uint8_t cap_flags;
61 uint8_t fru_info_dev_addr;
62 uint8_t sdr_dev_addr;
63 uint8_t sel_dev_addr;
64 uint8_t system_management_dev_addr;
65 uint8_t bridge_dev_addr;
66}__attribute__((packed)) ipmi_chassis_cap_t;
67
Nan Lifdd8ec52016-08-28 03:57:40 +080068typedef struct
69{
70 uint8_t cur_power_state;
71 uint8_t last_power_event;
72 uint8_t misc_power_state;
73 uint8_t front_panel_button_cap_status;
74}__attribute__((packed)) ipmi_get_chassis_status_t;
75
ratagupta6f6bff2016-04-04 06:20:11 -050076int dbus_get_property(const char *name, char **buf)
shgoupfd84fbbf2015-12-17 10:05:51 +080077{
78 sd_bus_error error = SD_BUS_ERROR_NULL;
79 sd_bus_message *m = NULL;
80 sd_bus *bus = NULL;
81 char *temp_buf = NULL;
82 char *connection = NULL;
83 int r;
84
Brad Bishop35518682016-07-22 08:35:41 -040085 // Get the system bus where most system services are provided.
86 bus = ipmid_get_sd_bus_connection();
shgoupfd84fbbf2015-12-17 10:05:51 +080087
Brad Bishop35518682016-07-22 08:35:41 -040088 r = mapper_get_service(bus, settings_object_name, &connection);
shgoupfd84fbbf2015-12-17 10:05:51 +080089 if (r < 0) {
Brad Bishop819ddd42016-10-05 21:19:19 -040090 fprintf(stderr, "Failed to get %s connection: %s\n",
91 settings_object_name, strerror(-r));
shgoupfd84fbbf2015-12-17 10:05:51 +080092 goto finish;
93 }
94
shgoupfd84fbbf2015-12-17 10:05:51 +080095 /*
96 * Bus, service, object path, interface and method are provided to call
97 * the method.
98 * Signatures and input arguments are provided by the arguments at the
99 * end.
100 */
101 r = sd_bus_call_method(bus,
102 connection, /* service to contact */
103 settings_object_name, /* object path */
104 settings_intf_name, /* interface name */
105 "Get", /* method name */
106 &error, /* object to return error in */
107 &m, /* return message on success */
108 "ss", /* input signature */
109 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500110 name); /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800111
112 if (r < 0) {
113 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
114 goto finish;
115 }
116
117 /*
118 * The output should be parsed exactly the same as the output formatting
119 * specified.
120 */
121 r = sd_bus_message_read(m, "v", "s", &temp_buf);
122 if (r < 0) {
123 fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
124 goto finish;
125 }
126
127 asprintf(buf, "%s", temp_buf);
128/* *buf = (char*) malloc(strlen(temp_buf));
129 if (*buf) {
130 strcpy(*buf, temp_buf);
131 }
132*/
133 printf("IPMID boot option property get: {%s}.\n", (char *) temp_buf);
134
135finish:
136 sd_bus_error_free(&error);
137 sd_bus_message_unref(m);
138 free(connection);
139
140 return r;
141}
142
ratagupta6f6bff2016-04-04 06:20:11 -0500143int dbus_set_property(const char * name, const char *value)
shgoupfd84fbbf2015-12-17 10:05:51 +0800144{
145 sd_bus_error error = SD_BUS_ERROR_NULL;
146 sd_bus_message *m = NULL;
147 sd_bus *bus = NULL;
148 char *connection = NULL;
149 int r;
150
Brad Bishop35518682016-07-22 08:35:41 -0400151 // Get the system bus where most system services are provided.
152 bus = ipmid_get_sd_bus_connection();
shgoupfd84fbbf2015-12-17 10:05:51 +0800153
Brad Bishop35518682016-07-22 08:35:41 -0400154 r = mapper_get_service(bus, settings_object_name, &connection);
shgoupfd84fbbf2015-12-17 10:05:51 +0800155 if (r < 0) {
Brad Bishop819ddd42016-10-05 21:19:19 -0400156 fprintf(stderr, "Failed to get %s connection: %s\n",
157 settings_object_name, strerror(-r));
shgoupfd84fbbf2015-12-17 10:05:51 +0800158 goto finish;
159 }
160
shgoupfd84fbbf2015-12-17 10:05:51 +0800161 /*
162 * Bus, service, object path, interface and method are provided to call
163 * the method.
164 * Signatures and input arguments are provided by the arguments at the
165 * end.
166 */
167 r = sd_bus_call_method(bus,
168 connection, /* service to contact */
169 settings_object_name, /* object path */
170 settings_intf_name, /* interface name */
171 "Set", /* method name */
172 &error, /* object to return error in */
173 &m, /* return message on success */
174 "ssv", /* input signature */
175 host_intf_name, /* first argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500176 name, /* second argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800177 "s", /* third argument */
ratagupta6f6bff2016-04-04 06:20:11 -0500178 value); /* fourth argument */
shgoupfd84fbbf2015-12-17 10:05:51 +0800179
180 if (r < 0) {
181 fprintf(stderr, "Failed to issue method call: %s\n", error.message);
182 goto finish;
183 }
184
ratagupta6f6bff2016-04-04 06:20:11 -0500185 printf("IPMID boot option property set: {%s}.\n", value);
shgoupfd84fbbf2015-12-17 10:05:51 +0800186
187finish:
188 sd_bus_error_free(&error);
189 sd_bus_message_unref(m);
190 free(connection);
191
192 return r;
193}
194
Adriana Kobylak40814c62015-10-27 15:58:44 -0500195struct get_sys_boot_options_t {
196 uint8_t parameter;
197 uint8_t set;
198 uint8_t block;
199} __attribute__ ((packed));
200
shgoupfd84fbbf2015-12-17 10:05:51 +0800201struct get_sys_boot_options_response_t {
202 uint8_t version;
203 uint8_t parm;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500204 uint8_t data[SIZE_BOOT_OPTION];
shgoupfd84fbbf2015-12-17 10:05:51 +0800205} __attribute__ ((packed));
206
207struct set_sys_boot_options_t {
208 uint8_t parameter;
Ratan Guptafd28dd72016-08-01 04:58:01 -0500209 uint8_t data[SIZE_BOOT_OPTION];
shgoupfd84fbbf2015-12-17 10:05:51 +0800210} __attribute__ ((packed));
211
Ratan Guptafd28dd72016-08-01 04:58:01 -0500212struct host_network_config_t {
213 std::string ipaddress;
214 std::string prefix;
215 std::string gateway;
216 std::string macaddress;
217 std::string addrType;
218
219 host_network_config_t()=default;
220};
221
222void fillNetworkConfig( host_network_config_t & host_config ,
223 const std::string& conf_str ) {
224
225 constexpr auto COMMA_DELIMITER = ",";
226 constexpr auto EQUAL_DELIMITER = "=";
227 size_t commaDelimtrPos = 0;
228 size_t equalDelimtrPos = 0,commaDelimtrPrevPos = 0;
229 std::string value;
230 while ( commaDelimtrPos < conf_str.length() ) {
231
232 commaDelimtrPos = conf_str.find(COMMA_DELIMITER,commaDelimtrPos);
233 //This condition is to extract the last
234 //Substring as we will not be having the delimeter
235 //at end. std::string::npos is -1
236
237 if ( commaDelimtrPos == std::string::npos ) {
238 commaDelimtrPos = conf_str.length();
239 }
240
241 equalDelimtrPos = conf_str.find (EQUAL_DELIMITER,commaDelimtrPrevPos);
242
243 //foo,ipaddress=1234
244 if ( equalDelimtrPos == std::string::npos ) {
245
246 commaDelimtrPos++;
247 commaDelimtrPrevPos= commaDelimtrPos;
248 continue;
249 }
250
251 value = conf_str.substr((equalDelimtrPos+1),
252 commaDelimtrPos-(equalDelimtrPos+1));
253
254#ifdef _IPMI_DEBUG_
255 printf ("Name=[%s],Value=[%s],commaDelimtrPos=[%d],\
256 commaDelimtrPrevPos=[%d],equalDelimtrPos=[%d]\n",
257 name.c_str(),value.c_str(),commaDelimtrPos,
258 commaDelimtrPrevPos,equalDelimtrPos);
259#endif
260
261 if ( 0 == conf_str.compare(commaDelimtrPrevPos,
262 equalDelimtrPos-commaDelimtrPrevPos,"ipaddress" )) {
263
264 host_config.ipaddress = std::move(value);
265 }
266 else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
267 equalDelimtrPos-commaDelimtrPrevPos,"prefix" )) {
268
269 host_config.prefix = std::move(value);
270 }
271 else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
272 equalDelimtrPos-commaDelimtrPrevPos, "gateway" )) {
273 host_config.gateway = std::move(value);
274 }
275 else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
276 equalDelimtrPos-commaDelimtrPrevPos, "mac" )) {
277 host_config.macaddress = std::move(value);
278 }
279 else if ( 0 == conf_str.compare(commaDelimtrPrevPos,
280 equalDelimtrPos-commaDelimtrPrevPos, "addr_type" )) {
281 host_config.addrType = std::move(value);
282 }
283
284 commaDelimtrPos++;
285 commaDelimtrPrevPos= commaDelimtrPos;
286 }
287}
288
289int getHostNetworkData(get_sys_boot_options_response_t* respptr)
290{
291
292 char *prop = nullptr;
293 int rc = dbus_get_property("network_config",&prop);
294
295 if ( rc < 0 ) {
296 fprintf(stderr, "Dbus get property(boot_flags) failed\
297 for get_sys_boot_options.\n");
298 return rc;
299 }
300
301 std::string conf_str(prop);
302
303 if ( prop ) {
304
305 free(prop);
306 prop = nullptr;
307 }
308
309 /* network_config property Value would be in the form of
310 * ipaddress=1.1.1.1,prefix=16,gateway=2.2.2.2,mac=11:22:33:44:55:66,dhcp=0
311 */
312
313 /* Parsing the string and fill the hostconfig structure with the
314 * values */
315
316 printf ("Configuration String[%s]\n ",conf_str.c_str());
317
318 host_network_config_t host_config;
319
320 // Fill the host_config from the configuration string
321 fillNetworkConfig(host_config,conf_str);
322
323 //Assigning the index as intialByteLength as it is fixed and prefilled.
324 printf ("host_config.macaddress.c_str()=[%s]\n",host_config.macaddress.c_str());
325 do{
326
327 rc = sscanf(host_config.macaddress.c_str(),MAC_ADDRESS_FORMAT,
328 (respptr->data+MAC_OFFSET), (respptr->data+MAC_OFFSET+1),
329 (respptr->data+MAC_OFFSET+2),(respptr->data+MAC_OFFSET+3),
330 (respptr->data+MAC_OFFSET+4), (respptr->data+MAC_OFFSET+5));
331
332
333 if ( rc < 6 ){
334 fprintf(stderr, "sscanf Failed in extracting mac address.\n");
335 rc = -1;
336 break;
337 }
338
339 //Conevrt the dhcp,ipaddress,mask and gateway as hex number
340 respptr->data[MAC_OFFSET+6]=0x00;
341
342 rc = sscanf(host_config.addrType.c_str(),ADDR_TYPE_FORMAT,
343 (respptr->data+ADDRTYPE_OFFSET));
344
345 if ( rc <= 0 ) {
346 fprintf(stderr, "sscanf Failed in extracting address type.\n");
347 rc = -1;
348 break;
349 }
350
351 //ipaddress and gateway would be in IPv4 format
352 rc = inet_pton(AF_INET,host_config.ipaddress.c_str(),
353 (respptr->data+IPADDR_OFFSET));
354
355 if ( rc <= 0 ) {
356 fprintf(stderr, "inet_pton failed during ipaddress coneversion\n");
357 rc = -1;
358 break;
359 }
360
361 rc = sscanf(host_config.prefix.c_str(),PREFIX_FORMAT,
362 (respptr->data+PREFIX_OFFSET));
363
364 if ( rc <= 0 ) {
365 fprintf(stderr, "sscanf failed during prefix extraction.\n");
366 rc = -1;
367 break;
368 }
369
370 rc = inet_pton(AF_INET,host_config.gateway.c_str(),
371 (respptr->data+GATEWAY_OFFSET));
372
373 if ( rc <= 0 ) {
374 fprintf(stderr, "inet_pton failed during gateway conversion.\n");
375 rc = -1;
376 break;
377 }
378
379 }while (0);
380
381 if ( rc ) {
382
383 //PetiBoot-Specific
384 //If sucess then copy the first 9 bytes to the data
385 //else set the respptr to 0
386
387 memcpy(respptr->data,net_conf_initial_bytes,
388 sizeof(net_conf_initial_bytes));
389
390#ifdef _IPMI_DEBUG_
391 printf ("\n===Printing the IPMI Formatted Data========\n");
392
393 for ( uint8_t pos = 0; pos<index; pos++ )
394 printf("%02x ", respptr->data[pos]);
395#endif
396
397 }else {
398
399 memset(respptr->data,0,SIZE_BOOT_OPTION);
400 }
401
402 return rc;
403}
404
405int setHostNetworkData(set_sys_boot_options_t * reqptr)
406{
407 std::string host_network_config;
408 char mac[SIZE_MAC] = {0};
409 char ipAddress[INET_ADDRSTRLEN] = {0};
410 char gateway[INET_ADDRSTRLEN] = {0};
411 char dhcp[SIZE_PREFIX] = {0};
412 char prefix[SIZE_PREFIX] = {0};
413 int rc = 0;
414 uint32_t zeroCookie=0;
415
416 //cookie starts from second byte
417 // version starts from sixth byte
418
419 do {
420
421 // cookie == 0x21 0x70 0x62 0x21
422 if ( memcmp(&(reqptr->data[COOKIE_OFFSET]),
423 (net_conf_initial_bytes+COOKIE_OFFSET),
424 SIZE_COOKIE) != 0 ) {
425 //cookie == 0
426 if ( memcmp(&(reqptr->data[COOKIE_OFFSET]),
427 &zeroCookie,
428 SIZE_COOKIE) == 0 ) {
429 rc = 0;
430 break;
431 }
432 //Invalid cookie
433 fprintf(stderr, "Invalid Cookie\n");
434 rc = -1;
435 break;
436 }
437 // vesion == 0x00 0x01
438 if ( memcmp(&(reqptr->data[VERSION_OFFSET]),
439 (net_conf_initial_bytes+VERSION_OFFSET),
440 SIZE_VERSION) != 0 ) {
441
442 fprintf(stderr, "Invalid Version\n");
443 rc = -1;
444 break;
445 }
446
447 snprintf(mac, SIZE_MAC, MAC_ADDRESS_FORMAT,
448 reqptr->data[MAC_OFFSET],
449 reqptr->data[MAC_OFFSET+1],
450 reqptr->data[MAC_OFFSET+2],
451 reqptr->data[MAC_OFFSET+3],
452 reqptr->data[MAC_OFFSET+4],
453 reqptr->data[MAC_OFFSET+5]);
454
455 snprintf(dhcp,SIZE_PREFIX, ADDR_TYPE_FORMAT, reqptr->data[ADDRTYPE_OFFSET]);
456 //Validating the address type which could be
457 //either static or dynamic
458 if( *(reqptr->data+ADDRTYPE_OFFSET) > 1 ) {
459
460 fprintf(stderr, "Invalid Address Type\n");
461 rc = -1;
462 break;
463
464 }
465
466 snprintf(ipAddress, INET_ADDRSTRLEN, IP_ADDRESS_FORMAT,
467 reqptr->data[IPADDR_OFFSET], reqptr->data[IPADDR_OFFSET+1],
468 reqptr->data[IPADDR_OFFSET+2], reqptr->data[IPADDR_OFFSET+3]);
469
470 //validating prefix
471 if ( *(reqptr->data+PREFIX_OFFSET) > (uint8_t)MAX_PREFIX_VALUE ) {
472
473 fprintf(stderr, "Invalid Prefix\n");
474 rc = -1;
475 break;
476 }
477
478 snprintf(prefix,SIZE_PREFIX,PREFIX_FORMAT, reqptr->data[PREFIX_OFFSET]);
479
480 snprintf(gateway, INET_ADDRSTRLEN,IP_ADDRESS_FORMAT,
481 reqptr->data[GATEWAY_OFFSET], reqptr->data[GATEWAY_OFFSET+1],
482 reqptr->data[GATEWAY_OFFSET+2], reqptr->data[GATEWAY_OFFSET+3]);
483
484
485 }while(0);
486
487 if( !rc )
488 {
489 //Cookie == 0 or it is a valid cookie
490 host_network_config += "ipaddress="+std::string(ipAddress)+",prefix="+
491 std::string(prefix)+",gateway="+std::string(gateway)+
492 ",mac="+std::string(mac)+",addr_type="+std::string(dhcp);
493
494 printf ("Network configuration changed: %s\n",host_network_config.c_str());
495
496 rc = dbus_set_property("network_config",host_network_config.c_str());
497
498 if ( rc < 0 ) {
499 fprintf(stderr, "Dbus set property(network_config)\
500 failed for set_sys_boot_options.\n");
501 rc = -1;
502 }
503
504 }
505 return rc;
506}
507
Adriana Kobylak40814c62015-10-27 15:58:44 -0500508ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
509 ipmi_request_t request, ipmi_response_t response,
510 ipmi_data_len_t data_len, ipmi_context_t context)
511{
512 printf("Handling CHASSIS WILDCARD Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
513 // Status code.
Nan Li70aa8d92016-08-29 00:11:10 +0800514 ipmi_ret_t rc = IPMI_CC_INVALID;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500515 *data_len = 0;
516 return rc;
517}
518
Nan Li8d15fb42016-08-16 22:29:40 +0800519ipmi_ret_t ipmi_get_chassis_cap(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
520 ipmi_request_t request, ipmi_response_t response,
521 ipmi_data_len_t data_len, ipmi_context_t context)
522{
523 // sd_bus error
524 ipmi_ret_t rc = IPMI_CC_OK;
525
526 ipmi_chassis_cap_t chassis_cap{};
527
528 *data_len = sizeof(ipmi_chassis_cap_t);
529
530 // TODO: need future work. Get those flag from MRW.
531
532 // capabilities flags
533 // [7..4] - reserved
534 // [3] – 1b = provides power interlock (IPM 1.5)
535 // [2] – 1b = provides Diagnostic Interrupt (FP NMI)
536 // [1] – 1b = provides “Front Panel Lockout” (indicates that the chassis has capabilities
537 // to lock out external power control and reset button or front panel interfaces
538 // and/or detect tampering with those interfaces).
539 // [0] -1b = Chassis provides intrusion (physical security) sensor.
540 // set to default value 0x0.
541 chassis_cap.cap_flags = 0x0;
542
543 // Since we do not have a separate SDR Device/SEL Device/ FRU repository.
544 // The 20h was given as those 5 device addresses.
545 // Chassis FRU info Device Address
546 chassis_cap.fru_info_dev_addr = 0x20;
547
548 // Chassis SDR Device Address
549 chassis_cap.sdr_dev_addr = 0x20;
550
551 // Chassis SEL Device Address
552 chassis_cap.sel_dev_addr = 0x20;
553
554 // Chassis System Management Device Address
555 chassis_cap.system_management_dev_addr = 0x20;
556
557 // Chassis Bridge Device Address.
558 chassis_cap.bridge_dev_addr = 0x20;
559
560 memcpy(response, &chassis_cap, *data_len);
561
562 return rc;
563}
564
vishwa36993272015-11-20 12:43:49 -0600565//------------------------------------------------------------
566// Calls into Chassis Control Dbus object to do the power off
567//------------------------------------------------------------
Chris Austen7888c4d2015-12-03 15:26:20 -0600568int ipmi_chassis_power_control(const char *method)
vishwa36993272015-11-20 12:43:49 -0600569{
570 // sd_bus error
571 int rc = 0;
Sergey Solomineb9b8142016-08-23 09:07:28 -0500572 char *busname = NULL;
vishwa36993272015-11-20 12:43:49 -0600573
Sergey Solomineb9b8142016-08-23 09:07:28 -0500574 // SD Bus error report mechanism.
575 sd_bus_error bus_error = SD_BUS_ERROR_NULL;
vishwa36993272015-11-20 12:43:49 -0600576
577 // Response from the call. Although there is no response for this call,
578 // obligated to mention this to make compiler happy.
579 sd_bus_message *response = NULL;
580
581 // Gets a hook onto either a SYSTEM or SESSION bus
582 sd_bus *bus_type = ipmid_get_sd_bus_connection();
Sergey Solomineb9b8142016-08-23 09:07:28 -0500583 rc = mapper_get_service(bus_type, chassis_object_name, &busname);
584 if (rc < 0) {
Brad Bishop819ddd42016-10-05 21:19:19 -0400585 fprintf(stderr, "Failed to get %s bus name: %s\n",
586 chassis_object_name, strerror(-rc));
Sergey Solomineb9b8142016-08-23 09:07:28 -0500587 goto finish;
588 }
vishwa36993272015-11-20 12:43:49 -0600589 rc = sd_bus_call_method(bus_type, // On the System Bus
Sergey Solomineb9b8142016-08-23 09:07:28 -0500590 busname, // Service to contact
vishwa36993272015-11-20 12:43:49 -0600591 chassis_object_name, // Object path
592 chassis_intf_name, // Interface name
Chris Austen7888c4d2015-12-03 15:26:20 -0600593 method, // Method to be called
vishwa36993272015-11-20 12:43:49 -0600594 &bus_error, // object to return error
595 &response, // Response buffer if any
596 NULL); // No input arguments
597 if(rc < 0)
598 {
599 fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message);
600 }
601 else
602 {
603 printf("Chassis Power Off initiated successfully\n");
604 }
605
Sergey Solomineb9b8142016-08-23 09:07:28 -0500606finish:
vishwa36993272015-11-20 12:43:49 -0600607 sd_bus_error_free(&bus_error);
608 sd_bus_message_unref(response);
Sergey Solomineb9b8142016-08-23 09:07:28 -0500609 free(busname);
vishwa36993272015-11-20 12:43:49 -0600610
Sergey Solomineb9b8142016-08-23 09:07:28 -0500611 return rc;
vishwa36993272015-11-20 12:43:49 -0600612}
613
Nan Lifdd8ec52016-08-28 03:57:40 +0800614struct hostPowerPolicyTypeMap_t {
615 uint8_t policyNum;
616 char policyName[19];
617};
618
619hostPowerPolicyTypeMap_t g_hostPowerPolicyTypeMap_t[] = {
620
621 {0x00, "LEAVE_OFF"},
622 {0x01, "RESTORE_LAST_STATE"},
623 {0x02, "ALWAYS_POWER_ON"},
624 {0x03, "UNKNOWN"}
625};
626
627uint8_t get_host_power_policy(char *p) {
628
629 hostPowerPolicyTypeMap_t *s = g_hostPowerPolicyTypeMap_t;
630
631 while (s->policyNum != 0x03) {
632 if (!strcmp(s->policyName,p))
633 break;
634 s++;
635 }
636
637 return s->policyNum;
638}
639
640//----------------------------------------------------------------------
641// Get Chassis Status commands
642//----------------------------------------------------------------------
643ipmi_ret_t ipmi_get_chassis_status(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
644 ipmi_request_t request, ipmi_response_t response,
645 ipmi_data_len_t data_len, ipmi_context_t context)
646{
647 const char *objname = "/org/openbmc/control/power0";
648 const char *intf = "org.openbmc.control.Power";
649
650 sd_bus *bus = NULL;
651 sd_bus_message *reply = NULL;
652 int r = 0;
653 int pgood = 0;
654 char *busname = NULL;
655 ipmi_ret_t rc = IPMI_CC_OK;
656 ipmi_get_chassis_status_t chassis_status{};
657
658 char *p = NULL;
659 uint8_t s = 0;
660
661 // Get the system bus where most system services are provided.
662 bus = ipmid_get_sd_bus_connection();
663
664 *data_len = 4;
665
666 r = mapper_get_service(bus, objname, &busname);
667 if (r < 0) {
668 fprintf(stderr, "Failed to get bus name, return value: %s.\n", strerror(-r));
669 rc = IPMI_CC_UNSPECIFIED_ERROR;
670 goto finish;
671 }
672
673 r = sd_bus_get_property(bus, busname, objname, intf, "pgood", NULL, &reply, "i");
674 if (r < 0) {
675 fprintf(stderr, "Failed to call sd_bus_get_property:%d, %s\n", r, strerror(-r));
676 fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
677 busname, objname, intf);
678 rc = IPMI_CC_UNSPECIFIED_ERROR;
679 goto finish;
680 }
681
682 r = sd_bus_message_read(reply, "i", &pgood);
683 if (r < 0) {
684 fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r));
685 rc = IPMI_CC_UNSPECIFIED_ERROR;
686 goto finish;
687 }
688
689 printf("pgood is 0x%02x\n", pgood);
690
691 // Get Power Policy
692 r = dbus_get_property("power_policy",&p);
693
694 if (r < 0) {
695 fprintf(stderr, "Dbus get property(power_policy) failed for get_sys_boot_options.\n");
696 rc = IPMI_CC_UNSPECIFIED_ERROR;
697 } else {
698 s = get_host_power_policy(p);
699 }
700
701 if (p)
702 {
703 free(p);
704 p = NULL;
705 }
706
707 // Current Power State
708 // [7] reserved
709 // [6..5] power restore policy
710 // 00b = chassis stays powered off after AC/mains returns
711 // 01b = after AC returns, power is restored to the state that was
712 // in effect when AC/mains was lost.
713 // 10b = chassis always powers up after AC/mains returns
714 // 11b = unknow
715 // Set to 00b, by observing the hardware behavior.
716 // Do we need to define a dbus property to identify the restore policy?
717
718 // [4] power control fault
719 // 1b = controller attempted to turn system power on or off, but
720 // system did not enter desired state.
721 // Set to 0b, since We don't support it..
722
723 // [3] power fault
724 // 1b = fault detected in main power subsystem.
725 // set to 0b. for we don't support it.
726
727 // [2] 1b = interlock (chassis is presently shut down because a chassis
728 // panel interlock switch is active). (IPMI 1.5)
729 // set to 0b, for we don't support it.
730
731 // [1] power overload
732 // 1b = system shutdown because of power overload condition.
733 // set to 0b, for we don't support it.
734
735 // [0] power is on
736 // 1b = system power is on
737 // 0b = system power is off(soft-off S4/S5, or mechanical off)
738
739 chassis_status.cur_power_state = ((s & 0x3)<<5) | (pgood & 0x1);
740
741 // Last Power Event
742 // [7..5] – reserved
743 // [4] – 1b = last ‘Power is on’ state was entered via IPMI command
744 // [3] – 1b = last power down caused by power fault
745 // [2] – 1b = last power down caused by a power interlock being activated
746 // [1] – 1b = last power down caused by a Power overload
747 // [0] – 1b = AC failed
748 // set to 0x0, for we don't support these fields.
749
750 chassis_status.last_power_event = 0;
751
752 // Misc. Chassis State
753 // [7] – reserved
754 // [6] – 1b = Chassis Identify command and state info supported (Optional)
755 // 0b = Chassis Identify command support unspecified via this command.
756 // (The Get Command Support command , if implemented, would still
757 // indicate support for the Chassis Identify command)
758 // [5..4] – Chassis Identify State. Mandatory when bit[6] =1b, reserved (return
759 // as 00b) otherwise. Returns the present chassis identify state.
760 // Refer to the Chassis Identify command for more info.
761 // 00b = chassis identify state = Off
762 // 01b = chassis identify state = Temporary(timed) On
763 // 10b = chassis identify state = Indefinite On
764 // 11b = reserved
765 // [3] – 1b = Cooling/fan fault detected
766 // [2] – 1b = Drive Fault
767 // [1] – 1b = Front Panel Lockout active (power off and reset via chassis
768 // push-buttons disabled.)
769 // [0] – 1b = Chassis Intrusion active
770 // set to 0, for we don't support them.
771 chassis_status.misc_power_state = 0;
772
773 // Front Panel Button Capabilities and disable/enable status(Optional)
774 // set to 0, for we don't support them.
775 chassis_status.front_panel_button_cap_status = 0;
776
777 // Pack the actual response
778 memcpy(response, &chassis_status, *data_len);
779
780finish:
781 free(busname);
782 reply = sd_bus_message_unref(reply);
783
784 return rc;
785}
Chris Austen7888c4d2015-12-03 15:26:20 -0600786
vishwa36993272015-11-20 12:43:49 -0600787//----------------------------------------------------------------------
788// Chassis Control commands
789//----------------------------------------------------------------------
790ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
791 ipmi_request_t request, ipmi_response_t response,
792 ipmi_data_len_t data_len, ipmi_context_t context)
793{
794 // Error from power off.
795 int rc = 0;
796
797 // No response for this command.
798 *data_len = 0;
799
800 // Catch the actual operaton by peeking into request buffer
801 uint8_t chassis_ctrl_cmd = *(uint8_t *)request;
802 printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd);
803
804 switch(chassis_ctrl_cmd)
805 {
806 case CMD_POWER_OFF:
Chris Austen7888c4d2015-12-03 15:26:20 -0600807 rc = ipmi_chassis_power_control("powerOff");
vishwa36993272015-11-20 12:43:49 -0600808 break;
Chris Austen7888c4d2015-12-03 15:26:20 -0600809 case CMD_HARD_RESET:
810 rc = ipmi_chassis_power_control("reboot");
811 break;
vishwa36993272015-11-20 12:43:49 -0600812 default:
813 {
814 fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd);
815 rc = -1;
816 }
817 }
818
819 return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK);
820}
821
shgoupfd84fbbf2015-12-17 10:05:51 +0800822struct bootOptionTypeMap_t {
823 uint8_t ipmibootflag;
824 char dbusname[8];
825};
826
827#define INVALID_STRING "Invalid"
828// dbus supports this list of boot devices.
829bootOptionTypeMap_t g_bootOptionTypeMap_t[] = {
830
831 {0x01, "Network"},
832 {0x02, "Disk"},
833 {0x03, "Safe"},
834 {0x05, "CDROM"},
835 {0x06, "Setup"},
836 {0x00, "Default"},
837 {0xFF, INVALID_STRING}
838};
839
840uint8_t get_ipmi_boot_option(char *p) {
841
842 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
843
844 while (s->ipmibootflag != 0xFF) {
845 if (!strcmp(s->dbusname,p))
846 break;
847 s++;
848 }
849
850 if (!s->ipmibootflag)
851 printf("Failed to find Sensor Type %s\n", p);
852
853 return s->ipmibootflag;
854}
855
856char* get_boot_option_by_ipmi(uint8_t p) {
857
858 bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
859
860 while (s->ipmibootflag != 0xFF) {
861
862 if (s->ipmibootflag == p)
863 break;
864
865 s++;
866 }
867
868
869 if (!s->ipmibootflag)
870 printf("Failed to find Sensor Type 0x%x\n", p);
871
872 return s->dbusname;
873}
874
Adriana Kobylak40814c62015-10-27 15:58:44 -0500875ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
876 ipmi_request_t request, ipmi_response_t response,
877 ipmi_data_len_t data_len, ipmi_context_t context)
878{
shgoupfd84fbbf2015-12-17 10:05:51 +0800879 ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED;
880 char *p = NULL;
881 get_sys_boot_options_response_t *resp = (get_sys_boot_options_response_t *) response;
882 get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request;
883 uint8_t s;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500884
885 printf("IPMI GET_SYS_BOOT_OPTIONS\n");
886
shgoupfd84fbbf2015-12-17 10:05:51 +0800887 memset(resp,0,sizeof(*resp));
888 resp->version = SET_PARM_VERSION;
889 resp->parm = 5;
ratagupta6f6bff2016-04-04 06:20:11 -0500890 resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
Adriana Kobylak40814c62015-10-27 15:58:44 -0500891
Adriana Kobylak40814c62015-10-27 15:58:44 -0500892
shgoupfd84fbbf2015-12-17 10:05:51 +0800893 /*
894 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
895 * This is the only parameter used by petitboot.
896 */
Ratan Guptafd28dd72016-08-01 04:58:01 -0500897 if ( reqptr->parameter == static_cast<uint8_t>
898 ( BootOptionParameter::BOOT_FLAGS )) {
shgoupfd84fbbf2015-12-17 10:05:51 +0800899
Ratan Guptafd28dd72016-08-01 04:58:01 -0500900 *data_len = static_cast<uint8_t>(BootOptionResponseSize::BOOT_FLAGS);
ratagupta6f6bff2016-04-04 06:20:11 -0500901 /* Get the boot device */
902 int r = dbus_get_property("boot_flags",&p);
shgoupfd84fbbf2015-12-17 10:05:51 +0800903
904 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -0500905 fprintf(stderr, "Dbus get property(boot_flags) failed for get_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +0800906 rc = IPMI_CC_UNSPECIFIED_ERROR;
907
908 } else {
909
910 s = get_ipmi_boot_option(p);
911 resp->data[1] = (s << 2);
912 rc = IPMI_CC_OK;
ratagupta6f6bff2016-04-04 06:20:11 -0500913
shgoupfd84fbbf2015-12-17 10:05:51 +0800914 }
915
ratagupta6f6bff2016-04-04 06:20:11 -0500916 if (p)
917 {
918 free(p);
919 p = NULL;
920 }
921
922 /* Get the boot policy */
923 r = dbus_get_property("boot_policy",&p);
924
925 if (r < 0) {
926 fprintf(stderr, "Dbus get property(boot_policy) failed for get_sys_boot_options.\n");
927 rc = IPMI_CC_UNSPECIFIED_ERROR;
928
929 } else {
930
Ratan Guptafd28dd72016-08-01 04:58:01 -0500931 printf("BootPolicy is[%s]", p);
ratagupta6f6bff2016-04-04 06:20:11 -0500932 resp->data[0] = (strncmp(p,"ONETIME",strlen("ONETIME"))==0) ?
933 SET_PARM_BOOT_FLAGS_VALID_ONE_TIME:
934 SET_PARM_BOOT_FLAGS_VALID_PERMANENT;
935 rc = IPMI_CC_OK;
936
937 }
938
939
Ratan Guptafd28dd72016-08-01 04:58:01 -0500940 } else if ( reqptr->parameter == static_cast<uint8_t>
941 ( BootOptionParameter::OPAL_NETWORK_SETTINGS )) {
942
943 *data_len = static_cast<uint8_t>(BootOptionResponseSize::OPAL_NETWORK_SETTINGS);
944
945 resp->parm = static_cast<uint8_t>(BootOptionParameter::OPAL_NETWORK_SETTINGS);
946
947 int ret = getHostNetworkData(resp);
948
949 if (ret < 0) {
950
951 fprintf(stderr, "getHostNetworkData failed for get_sys_boot_options.\n");
952 rc = IPMI_CC_UNSPECIFIED_ERROR;
953
954 }else
955 rc = IPMI_CC_OK;
956 }
957
958 else {
Adriana Kobylak40814c62015-10-27 15:58:44 -0500959 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
shgoupfd84fbbf2015-12-17 10:05:51 +0800960 }
961
962 if (p)
963 free(p);
964
Ratan Guptafd28dd72016-08-01 04:58:01 -0500965 if (rc == IPMI_CC_OK)
966 {
967 *data_len += 2;
968 }
969
shgoupfd84fbbf2015-12-17 10:05:51 +0800970 return rc;
971}
972
973
974
975ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
976 ipmi_request_t request, ipmi_response_t response,
977 ipmi_data_len_t data_len, ipmi_context_t context)
978{
979 ipmi_ret_t rc = IPMI_CC_OK;
980 char *s;
shgoupfd84fbbf2015-12-17 10:05:51 +0800981 set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request;
982
Ratan Guptafd28dd72016-08-01 04:58:01 -0500983 printf("IPMI SET_SYS_BOOT_OPTIONS reqptr->parameter =[%d]\n",reqptr->parameter);
984
shgoupfd84fbbf2015-12-17 10:05:51 +0800985 // This IPMI command does not have any resposne data
986 *data_len = 0;
987
988 /* 000101
989 * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
990 * This is the only parameter used by petitboot.
991 */
Ratan Guptafd28dd72016-08-01 04:58:01 -0500992
993 if (reqptr->parameter == (uint8_t)BootOptionParameter::BOOT_FLAGS) {
shgoupfd84fbbf2015-12-17 10:05:51 +0800994
995 s = get_boot_option_by_ipmi(((reqptr->data[1] & 0x3C) >> 2));
996
997 printf("%d: %s\n", __LINE__, s);
998 if (!strcmp(s,INVALID_STRING)) {
999
1000 rc = IPMI_CC_PARM_NOT_SUPPORTED;
1001
1002 } else {
1003
ratagupta6f6bff2016-04-04 06:20:11 -05001004 int r = dbus_set_property("boot_flags",s);
shgoupfd84fbbf2015-12-17 10:05:51 +08001005
1006 if (r < 0) {
ratagupta6f6bff2016-04-04 06:20:11 -05001007 fprintf(stderr, "Dbus set property(boot_flags) failed for set_sys_boot_options.\n");
shgoupfd84fbbf2015-12-17 10:05:51 +08001008 rc = IPMI_CC_UNSPECIFIED_ERROR;
1009 }
1010 }
Ratan Guptafd28dd72016-08-01 04:58:01 -05001011
ratagupta6f6bff2016-04-04 06:20:11 -05001012 /* setting the boot policy */
1013 s = (char *)(((reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) ==
Ratan Guptafd28dd72016-08-01 04:58:01 -05001014 SET_PARM_BOOT_FLAGS_PERMANENT) ?"PERMANENT":"ONETIME");
ratagupta6f6bff2016-04-04 06:20:11 -05001015
Ratan Guptafd28dd72016-08-01 04:58:01 -05001016 printf ( "\nBoot Policy is %s",s);
ratagupta6f6bff2016-04-04 06:20:11 -05001017 int r = dbus_set_property("boot_policy",s);
1018
1019 if (r < 0) {
1020 fprintf(stderr, "Dbus set property(boot_policy) failed for set_sys_boot_options.\n");
1021 rc = IPMI_CC_UNSPECIFIED_ERROR;
1022 }
shgoupfd84fbbf2015-12-17 10:05:51 +08001023
Ratan Guptafd28dd72016-08-01 04:58:01 -05001024 } else if (reqptr->parameter ==
1025 (uint8_t)BootOptionParameter::OPAL_NETWORK_SETTINGS) {
1026
1027 int ret = setHostNetworkData(reqptr);
1028 if (ret < 0) {
1029 fprintf(stderr, "setHostNetworkData failed for set_sys_boot_options.\n");
1030 rc = IPMI_CC_UNSPECIFIED_ERROR;
1031 }
1032 }
1033 else {
shgoupfd84fbbf2015-12-17 10:05:51 +08001034 fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
1035 rc = IPMI_CC_PARM_NOT_SUPPORTED;
Adriana Kobylak40814c62015-10-27 15:58:44 -05001036 }
1037
1038 return rc;
1039}
1040
1041void register_netfn_chassis_functions()
1042{
1043 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_WILDCARD);
1044 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_WILDCARD, NULL, ipmi_chassis_wildcard);
1045
Nan Li8d15fb42016-08-16 22:29:40 +08001046 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP);
1047 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_CHASSIS_CAP, NULL, ipmi_get_chassis_cap);
1048
Adriana Kobylak40814c62015-10-27 15:58:44 -05001049 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS);
1050 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_get_sys_boot_options);
Adriana Kobylak40814c62015-10-27 15:58:44 -05001051
Nan Lifdd8ec52016-08-28 03:57:40 +08001052 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS);
1053 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_STATUS, NULL, ipmi_get_chassis_status);
1054
vishwa36993272015-11-20 12:43:49 -06001055 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL);
1056 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control);
shgoupfd84fbbf2015-12-17 10:05:51 +08001057
1058 printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS);
1059 ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_set_sys_boot_options);
vishwa36993272015-11-20 12:43:49 -06001060}
shgoupfd84fbbf2015-12-17 10:05:51 +08001061