Merge pull request #42 from shenki/travis
travis: Add Travis CI building
diff --git a/Makefile b/Makefile
index 1a37c0f..7a3b6af 100644
--- a/Makefile
+++ b/Makefile
@@ -5,8 +5,7 @@
TESTADDSEL = testaddsel
DAEMON = ipmid
-DAEMON_OBJ = $(DAEMON).o
-
+DAEMON_OBJ = ipmid.o
LIB_APP_OBJ = apphandler.o \
sensorhandler.o \
@@ -16,7 +15,10 @@
ipmisensor.o \
storageaddsel.o \
transporthandler.o \
+ globalhandler.o \
+ groupext.o
+LIB_HOST_SRV_OBJ = host-services.o
TESTADDSEL_OBJ = $(TESTADDSEL).o \
storageaddsel.o
@@ -25,10 +27,15 @@
testit.o
LIB_APP = libapphandler.so
-INSTALLED_LIBS += $(LIB_APP)
+LIB_HOST_SRV = libhostservice.so
+
+INSTALLED_LIBS += $(LIB_APP) $(LIB_HOST_SRV)
INSTALLED_HEADERS = ipmid-api.h
-INC_FLAG += $(shell pkg-config --cflags --libs libsystemd) -I. -O2
+CXXFLAGS += -Wall -Wno-unused-result
+CFLAGS += -Wall -Wno-unused-result
+
+INC_FLAG += $(shell pkg-config --cflags --libs libsystemd) -I. -O2
LIB_FLAG += $(shell pkg-config --libs libsystemd) -rdynamic
IPMID_PATH ?= -DHOST_IPMI_LIB_PATH=\"/usr/lib/host-ipmid/\"
@@ -37,7 +44,7 @@
INCLUDEDIR ?= /usr/include
LIBDIR ?= /usr/lib
-all: $(DAEMON) $(LIB_APP) $(TESTER)
+all: $(DAEMON) $(LIB_APP) $(LIB_HOST_SRV) $(TESTER)
%.o: %.C
$(CXX) -std=c++14 -fpic -c $< $(CXXFLAGS) $(INC_FLAG) $(IPMID_PATH) -o $@
@@ -45,6 +52,9 @@
$(LIB_APP): $(LIB_APP_OBJ)
$(CXX) $^ -shared $(LDFLAGS) $(LIB_FLAG) -o $@
+$(LIB_HOST_SRV): $(LIB_HOST_SRV_OBJ)
+ $(CXX) $^ -shared $(LDFLAGS) $(LIB_FLAG) -o $@
+
$(DAEMON): $(DAEMON_OBJ)
$(CXX) $^ $(LDFLAGS) $(LIB_FLAG) -o $@ -ldl
diff --git a/apphandler.C b/apphandler.C
index 6467397..71dba66 100644
--- a/apphandler.C
+++ b/apphandler.C
@@ -10,20 +10,80 @@
void register_netfn_app_functions() __attribute__((constructor));
+#define DEVICE_FW1 2
+#define DEVICE_FW2 3
+#define DEVICE_AUX 11
+//---------------------------------------------------------------------
+// Called by Host on seeing a SMS_ATN bit set. Return a hardcoded
+// value of 0x2 indicating we need Host read some data.
+//-------------------------------------------------------------------
+ipmi_ret_t ipmi_app_get_msg_flags(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ // Generic return from IPMI commands.
+ ipmi_ret_t rc = IPMI_CC_OK;
+
+ printf("IPMI APP GET MSG FLAGS returning with [bit:2] set\n");
+
+ // From IPMI spec V2.0 for Get Message Flags Command :
+ // bit:[1] from LSB : 1b = Event Message Buffer Full.
+ // Return as 0 if Event Message Buffer is not supported,
+ // or when the Event Message buffer is disabled.
+ // TODO. For now. assume its not disabled and send "0x2" anyway:
+
+ uint8_t set_event_msg_buffer_full = 0x2;
+ *data_len = sizeof(set_event_msg_buffer_full);
+
+ // Pack the actual response
+ memcpy(response, &set_event_msg_buffer_full, *data_len);
+
+ return rc;
+}
+
+//-------------------------------------------------------------------
+// Called by Host post response from Get_Message_Flags
+//-------------------------------------------------------------------
ipmi_ret_t ipmi_app_read_event(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
ipmi_ret_t rc = IPMI_CC_OK;
- *data_len = 0;
+ printf("IPMI APP READ EVENT command received\n");
- printf("IPMI APP READ EVENT Ignoring for now\n");
+ // TODO : For now, this is catering only to the Soft Power Off via OEM SEL
+ // mechanism. If we need to make this generically used for some
+ // other conditions, then we can take advantage of context pointer.
+
+ struct oem_sel_timestamped soft_off = {0};
+ *data_len = sizeof(struct oem_sel_timestamped);
+
+ // either id[0] -or- id[1] can be filled in. We will use id[0]
+ soft_off.id[0] = SEL_OEM_ID_0;
+ soft_off.id[1] = SEL_OEM_ID_0;
+ soft_off.type = SEL_RECORD_TYPE_OEM;
+
+ // Following 3 bytes are from IANA Manufactre_Id field. See below
+ soft_off.manuf_id[0]= 0x41;
+ soft_off.manuf_id[1]= 0xA7;
+ soft_off.manuf_id[2]= 0x00;
+
+ // per IPMI spec NetFuntion for OEM
+ soft_off.netfun = 0x3A;
+
+ // Mechanism to kick start soft shutdown.
+ soft_off.cmd = CMD_POWER;
+ soft_off.data[0] = SOFT_OFF;
+
+ // All '0xFF' since unused.
+ memset(&soft_off.data[1], 0xFF, 3);
+
+ // Pack the actual response
+ memcpy(response, &soft_off, *data_len);
return rc;
-
}
-
ipmi_ret_t ipmi_app_set_acpi_power_state(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
@@ -35,23 +95,105 @@
return rc;
}
+
+typedef struct
+{
+ char major;
+ char minor;
+ uint16_t d[2];
+} rev_t;
+
+
+/* Currently only supports the vx.x-x-[-x] format Will return -1 if not in */
+/* the format this routine knows how to parse */
+/* version = v0.6-19-gf363f61-dirty */
+/* ^ ^ ^^ ^ */
+/* | | |----------|-- additional details */
+/* | |---------------- Minor */
+/* |------------------ Major */
+/* Additional details : If the option group exists it will force Auxiliary */
+/* Firmware Revision Information 4th byte to 1 indicating the build was */
+/* derived with additional edits */
+int convert_version(const char *p, rev_t *rev)
+{
+ char *s, *token;
+ char hexbyte[5];
+ int l;
+ uint16_t commits;
+
+ if (*p != 'v')
+ return -1;
+ p++;
+
+ s = strdup(p);
+ token = strtok(s,".-");
+
+ rev->major = (int8_t) atoi(token);
+
+ token = strtok(NULL, ".-");
+ rev->minor = (int8_t) atoi(token);
+
+ // Capture the number of commits on top of the minor tag.
+ // I'm using BE format like the ipmi spec asked for
+ token = strtok(NULL,".-");
+
+ if (token) {
+ commits = (int16_t) atoi(token);
+ rev->d[0] = (commits>>8) | (commits<<8);
+
+ // commit number we skip
+ token = strtok(NULL,".-");
+
+ } else {
+ rev->d[0] = 0;
+ }
+
+ // Any value of the optional parameter forces it to 1
+ if (token)
+ token = strtok(NULL,".-");
+
+ rev->d[1] = (token != NULL) ? 1 : 0;
+
+ free(s);
+ return 0;
+}
+
ipmi_ret_t ipmi_app_get_device_id(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
ipmi_ret_t rc = IPMI_CC_OK;
+ const char *busname = "org.openbmc.Inventory";
+ const char *objname = "/org/openbmc/inventory/system/chassis/motherboard/bmc";
+ const char *iface = "org.openbmc.InventoryItem";
+ char *ver = NULL;
+ int r;
+ rev_t rev = {0};
// TODO:
// This value is the IANA number assigned to "IBM Platform Firmware
// Division", which is also used by our service processor. We may want
// a different number or at least a different version?
- uint8_t str[] = {0x00, 0, 1, 1,2, 0xD, 0x41, 0xA7, 0x00, 0x43, 0x40};
+ uint8_t dev_id[] = {0, 0, 0, 0, 2, 0xD, 0x41, 0xA7, 0x00, 0x43, 0x40, 0, 0, 0, 0};
// Data length
- *data_len = sizeof(str);
+ *data_len = sizeof(dev_id);
+
+ r = sd_bus_get_property_string(bus,busname,objname,iface,"version", NULL, &ver);
+ if ( r < 0 ) {
+ fprintf(stderr, "Failed to obtain version property: %s\n", strerror(-r));
+ } else {
+ r = convert_version(ver, &rev);
+ if( r >= 0 ) {
+ // bit7 identifies state of SDR repository, hence the mask
+ dev_id[DEVICE_FW1] |= 0x7F & rev.major;
+ dev_id[DEVICE_FW2] = rev.minor;
+ memcpy(&dev_id[DEVICE_AUX], rev.d, 4);
+ }
+ }
// Pack the actual response
- memcpy(response, &str, *data_len);
+ memcpy(response, &dev_id, *data_len);
return rc;
}
@@ -63,44 +205,11 @@
const char *objname = "/org/openbmc/control/chassis0";
const char *iface = "org.freedesktop.DBus.Properties";
const char *chassis_iface = "org.openbmc.control.Chassis";
- sd_bus_message *reply = NULL, *m = NULL;
+ sd_bus_message *reply = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
int r = 0;
char *uuid = NULL;
- // Status code.
- ipmi_ret_t rc = IPMI_CC_OK;
- *data_len = 0;
-
- printf("IPMI GET DEVICE GUID\n");
-
- // Call Get properties method with the interface and property name
- r = sd_bus_message_new_method_call(bus,&m,busname,objname,iface,"Get");
- if (r < 0) {
- fprintf(stderr, "Failed to add the Get method object: %s\n", strerror(-r));
- return IPMI_CC_UNSPECIFIED_ERROR;
- }
- r = sd_bus_message_append(m, "ss", chassis_iface, "uuid");
- if (r < 0) {
- fprintf(stderr, "Failed to append arguments: %s\n", strerror(-r));
- return -1;
- }
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- fprintf(stderr, "Failed to call the Get method: %s\n", strerror(-r));
- return IPMI_CC_UNSPECIFIED_ERROR;
- }
- r = sd_bus_message_read(reply, "v", "s", &uuid);
- if (r < 0) {
- fprintf(stderr, "Failed to get a response: %s", strerror(-r));
- return IPMI_CC_RESPONSE_ERROR;
- }
- if (uuid == NULL)
- {
- fprintf(stderr, "Failed to get a valid response: %s", strerror(-r));
- return IPMI_CC_RESPONSE_ERROR;
- }
-
// UUID is in RFC4122 format. Ex: 61a39523-78f2-11e5-9862-e6402cfc3223
// Per IPMI Spec 2.0 need to convert to 16 hex bytes and reverse the byte order
// Ex: 0x2332fc2c40e66298e511f2782395a361
@@ -110,14 +219,42 @@
int resp_loc = resp_size-1; // Point resp end of array to save in reverse order
int i = 0;
char *tokptr = NULL;
+ char *id_octet = NULL;
+
+ // Status code.
+ ipmi_ret_t rc = IPMI_CC_OK;
+ *data_len = 0;
+
+ printf("IPMI GET DEVICE GUID\n");
+
+ // Call Get properties method with the interface and property name
+ r = sd_bus_call_method(bus,busname,objname,iface,
+ "Get",&error, &reply, "ss",
+ chassis_iface, "uuid");
+ if (r < 0)
+ {
+ fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r));
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ goto finish;
+ }
+
+ r = sd_bus_message_read(reply, "v", "s", &uuid);
+ if (r < 0 || uuid == NULL)
+ {
+ fprintf(stderr, "Failed to get a response: %s", strerror(-r));
+ rc = IPMI_CC_RESPONSE_ERROR;
+ goto finish;
+ }
// Traverse the UUID
- char* id_octet = strtok_r(uuid, "-", &tokptr); // Get the UUID octects separated by dash
+ id_octet = strtok_r(uuid, "-", &tokptr); // Get the UUID octects separated by dash
if (id_octet == NULL)
- { // Error
+ {
+ // Error
fprintf(stderr, "Unexpected UUID format: %s", uuid);
- return IPMI_CC_RESPONSE_ERROR;
+ rc = IPMI_CC_RESPONSE_ERROR;
+ goto finish;
}
while (id_octet != NULL)
@@ -128,8 +265,7 @@
for(i = 0; i < tmp_size; i++)
{
- char tmp_array[3]; // Holder of the 2 chars that will become a byte
- tmp_array[3] = '\0';
+ char tmp_array[3] = {0}; // Holder of the 2 chars that will become a byte
strncpy(tmp_array, id_octet, 2); // 2 chars at a time
int resp_byte = strtoul(tmp_array, NULL, 16); // Convert to hex byte
@@ -146,8 +282,9 @@
// Pack the actual response
memcpy(response, &resp_uuid, *data_len);
+finish:
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
+ reply = sd_bus_message_unref(reply);
return rc;
}
@@ -191,15 +328,13 @@
const char *busname = "org.openbmc.watchdog.Host";
const char *objname = "/org/openbmc/watchdog/host0";
const char *iface = "org.openbmc.Watchdog";
- sd_bus_message *reply = NULL, *m = NULL;
+ sd_bus_message *reply = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
int r = 0;
set_wd_data_t *reqptr = (set_wd_data_t*) request;
uint16_t timer = 0;
uint32_t timer_ms = 0;
- // Status code.
- ipmi_ret_t rc = IPMI_CC_OK;
*data_len = 0;
@@ -211,53 +346,45 @@
printf("WATCHDOG SET Timer:[0x%X] 100ms intervals\n",timer);
// Set watchdog timer
- r = sd_bus_message_new_method_call(bus,&m,busname,objname,iface,"set");
- if (r < 0) {
- fprintf(stderr, "Failed to add the set method object: %s\n", strerror(-r));
- return -1;
- }
- r = sd_bus_message_append(m, "i", timer_ms);
- if (r < 0) {
- fprintf(stderr, "Failed to add timer value: %s\n", strerror(-r));
- return -1;
- }
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- fprintf(stderr, "Failed to call the set method: %s\n", strerror(-r));
- return -1;
- }
-
- // Stop the current watchdog if any
- r = sd_bus_message_new_method_call(bus,&m,busname,objname,iface,"stop");
- if (r < 0) {
- fprintf(stderr, "Failed to add the start method object: %s\n", strerror(-r));
- return -1;
- }
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- fprintf(stderr, "Failed to call the start method: %s\n", strerror(-r));
- return -1;
- }
-
- // Start the watchdog if requested
- if (reqptr->t_use & 0x40)
+ r = sd_bus_call_method(bus, busname, objname, iface,
+ "set", &error, &reply, "i", timer_ms);
+ if(r < 0)
{
- r = sd_bus_message_new_method_call(bus,&m,busname,objname,iface,"start");
- if (r < 0) {
- fprintf(stderr, "Failed to add the start method object: %s\n", strerror(-r));
- return -1;
- }
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- fprintf(stderr, "Failed to call the start method: %s\n", strerror(-r));
- return -1;
- }
+ fprintf(stderr, "Failed to call the SET method: %s\n", strerror(-r));
+ goto finish;
}
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
+ reply = sd_bus_message_unref(reply);
- return rc;
+ // Stop the current watchdog if any
+ r = sd_bus_call_method(bus, busname, objname, iface,
+ "stop", &error, &reply, NULL);
+ if(r < 0)
+ {
+ fprintf(stderr, "Failed to call the STOP method: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ if (reqptr->t_use & 0x40)
+ {
+ sd_bus_error_free(&error);
+ reply = sd_bus_message_unref(reply);
+
+ // Start the watchdog if requested
+ r = sd_bus_call_method(bus, busname, objname, iface,
+ "start", &error, &reply, NULL);
+ if(r < 0)
+ {
+ fprintf(stderr, "Failed to call the START method: %s\n", strerror(-r));
+ }
+ }
+
+finish:
+ sd_bus_error_free(&error);
+ reply = sd_bus_message_unref(reply);
+
+ return (r < 0) ? -1 : IPMI_CC_OK;
}
@@ -268,7 +395,7 @@
const char *busname = "org.openbmc.watchdog.Host";
const char *objname = "/org/openbmc/watchdog/host0";
const char *iface = "org.openbmc.Watchdog";
- sd_bus_message *reply = NULL, *m = NULL;
+ sd_bus_message *reply = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
int r = 0;
@@ -279,19 +406,53 @@
printf("WATCHDOG RESET\n");
// Refresh watchdog
- r = sd_bus_message_new_method_call(bus,&m,busname,objname,iface,"poke");
+ r = sd_bus_call_method(bus, busname, objname, iface,
+ "poke", &error, &reply, NULL);
if (r < 0) {
- fprintf(stderr, "Failed to add the method object: %s\n", strerror(-r));
- return -1;
- }
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- fprintf(stderr, "Failed to call the method: %s\n", strerror(-r));
- return -1;
+ fprintf(stderr, "Failed to add reset watchdog: %s\n", strerror(-r));
+ rc = -1;
}
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
+ reply = sd_bus_message_unref(reply);
+
+ return rc;
+}
+
+// ATTENTION: This ipmi function is very hardcoded on purpose
+// OpenBMC does not fully support IPMI. This command is useful
+// to have around because it enables testing of interfaces with
+// the IPMI tool.
+#define GET_CHANNEL_INFO_CHANNEL_OFFSET 0
+// IPMI Table 6-2
+#define IPMI_CHANNEL_TYPE_IPMB 1
+// IPMI Table 6-3
+#define IPMI_CHANNEL_MEDIUM_TYPE_OTHER 6
+
+ipmi_ret_t ipmi_app_channel_info(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ ipmi_ret_t rc = IPMI_CC_OK;
+ uint8_t resp[] = {
+ 1,
+ IPMI_CHANNEL_MEDIUM_TYPE_OTHER,
+ IPMI_CHANNEL_TYPE_IPMB,
+ 1,0x41,0xA7,0x00,0,0};
+ uint8_t *p = (uint8_t*) request;
+
+ printf("IPMI APP GET CHANNEL INFO\n");
+
+ // I"m only supporting channel 1. 0xE is the 'default channel'
+ if (*p == 0xe || *p == 1 || *p == 8) {
+
+ *data_len = sizeof(resp);
+ memcpy(response, resp, *data_len);
+
+ } else {
+ rc = IPMI_CC_PARM_OUT_OF_RANGE;
+ *data_len = 0;
+ }
return rc;
}
@@ -359,6 +520,15 @@
ipmi_register_callback(NETFUN_APP, IPMI_CMD_SET_BMC_GLOBAL_ENABLES, NULL,
ipmi_app_set_bmc_global_enables);
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_MSG_FLAGS);
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_MSG_FLAGS, NULL, ipmi_app_get_msg_flags);
+
+
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_GET_CHAN_INFO);
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_GET_CHAN_INFO, NULL, ipmi_app_channel_info);
+
+
+
return;
}
diff --git a/apphandler.h b/apphandler.h
index 35a2b20..a17ee7f 100644
--- a/apphandler.h
+++ b/apphandler.h
@@ -1,6 +1,19 @@
#ifndef __HOST_IPMI_APP_HANDLER_H__
#define __HOST_IPMI_APP_HANDLER_H__
+#include <stdint.h>
+
+// These are per skiboot ipmi-sel code
+
+// OEM_SEL type with Timestamp
+#define SEL_OEM_ID_0 0x55
+// SEL type is OEM and -not- general SEL
+#define SEL_RECORD_TYPE_OEM 0xC0
+// Minor command for soft shurdown
+#define SOFT_OFF 0x00
+// Major command for Any kind of power ops
+#define CMD_POWER 0x04
+
// IPMI commands for App net functions.
enum ipmi_netfn_app_cmds
{
@@ -11,9 +24,29 @@
IPMI_CMD_RESET_WD = 0x22,
IPMI_CMD_SET_WD = 0x24,
IPMI_CMD_SET_BMC_GLOBAL_ENABLES = 0x2E,
+ IPMI_CMD_GET_MSG_FLAGS = 0x31,
IPMI_CMD_READ_EVENT = 0x35,
IPMI_CMD_GET_CAP_BIT = 0x36,
+ IPMI_CMD_GET_CHAN_INFO = 0x42,
};
+// A Mechanism to tell host to shtudown hosts by sending this PEM SEL. Really
+// the only used fields by skiboot are:
+// id[0] / id[1] for ID_0 , ID_1
+// type : SEL_RECORD_TYPE_OEM as standard SELs are ignored by skiboot
+// cmd : CMD_POWER for power functions
+// data[0], specific commands. example Soft power off. power cycle, etc.
+struct oem_sel_timestamped
+{
+ /* SEL header */
+ uint8_t id[2];
+ uint8_t type;
+ uint8_t manuf_id[3];
+ uint8_t timestamp[4];
+ /* OEM SEL data (6 bytes) follows */
+ uint8_t netfun;
+ uint8_t cmd;
+ uint8_t data[4];
+};
#endif
diff --git a/chassishandler.C b/chassishandler.C
index d00a124..d5b3404 100644
--- a/chassishandler.C
+++ b/chassishandler.C
@@ -4,14 +4,243 @@
#include <string.h>
#include <stdint.h>
+
+//Defines
+#define SET_PARM_VERSION 1
+#define SET_PARM_BOOT_FLAGS_PERMANENT 0x40 //boot flags data1 7th bit on
+#define SET_PARM_BOOT_FLAGS_VALID_ONE_TIME 0x80 //boot flags data1 8th bit on
+#define SET_PARM_BOOT_FLAGS_VALID_PERMANENT 0xC0 //boot flags data1 7 & 8 bit on
+
+
+
+// OpenBMC Chassis Manager dbus framework
+const char *chassis_bus_name = "org.openbmc.control.Chassis";
+const char *chassis_object_name = "/org/openbmc/control/chassis0";
+const char *chassis_intf_name = "org.openbmc.control.Chassis";
+
+
void register_netfn_chassis_functions() __attribute__((constructor));
+// Host settings in dbus
+// Service name should be referenced by connection name got via object mapper
+const char *settings_object_name = "/org/openbmc/settings/host0";
+const char *settings_intf_name = "org.freedesktop.DBus.Properties";
+const char *host_intf_name = "org.openbmc.settings.Host";
+
+const char *objmapper_service_name = "org.openbmc.objectmapper";
+const char *objmapper_object_name = "/org/openbmc/objectmapper/objectmapper";
+const char *objmapper_intf_name = "org.openbmc.objectmapper.ObjectMapper";
+
+int object_mapper_get_connection(char **buf, const char *obj_path)
+{
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL;
+ sd_bus *bus = NULL;
+ char *temp_buf = NULL, *intf = NULL;
+ size_t buf_size = 0;
+ int r;
+
+ // Get the system bus where most system services are provided.
+ bus = ipmid_get_sd_bus_connection();
+
+ /*
+ * Bus, service, object path, interface and method are provided to call
+ * the method.
+ * Signatures and input arguments are provided by the arguments at the
+ * end.
+ */
+ r = sd_bus_call_method(bus,
+ objmapper_service_name, /* service to contact */
+ objmapper_object_name, /* object path */
+ objmapper_intf_name, /* interface name */
+ "GetObject", /* method name */
+ &error, /* object to return error in */
+ &m, /* return message on success */
+ "s", /* input signature */
+ obj_path /* first argument */
+ );
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to issue method call: %s\n", error.message);
+ goto finish;
+ }
+
+ // Get the key, aka, the connection name
+ sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
+
+ /*
+ * TODO: check the return code. Currently for no reason the message
+ * parsing of object mapper is always complaining about
+ * "Device or resource busy", but the result seems OK for now. Need
+ * further checks.
+ * TODO: The following code is preserved in the comments so that it can be
+ * resumed after the problem aforementioned is resolved.
+ *r = sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
+ *if (r < 0) {
+ * fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
+ * goto finish;
+ *}
+ */
+
+ buf_size = strlen(temp_buf) + 1;
+ printf("IPMID connection name: %s\n", temp_buf);
+ *buf = (char *)malloc(buf_size);
+
+ if (*buf == NULL) {
+ fprintf(stderr, "Malloc failed for get_sys_boot_options");
+ r = -1;
+ goto finish;
+ }
+
+ memcpy(*buf, temp_buf, buf_size);
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+
+ return r;
+}
+
+int dbus_get_property(const char *name, char **buf)
+{
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL;
+ sd_bus *bus = NULL;
+ char *temp_buf = NULL;
+ char *connection = NULL;
+ int r;
+
+ r = object_mapper_get_connection(&connection, settings_object_name);
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to get connection, return value: %d.\n", r);
+ goto finish;
+ }
+
+ printf("connection: %s\n", connection);
+
+ // Get the system bus where most system services are provided.
+ bus = ipmid_get_sd_bus_connection();
+
+ /*
+ * Bus, service, object path, interface and method are provided to call
+ * the method.
+ * Signatures and input arguments are provided by the arguments at the
+ * end.
+ */
+ r = sd_bus_call_method(bus,
+ connection, /* service to contact */
+ settings_object_name, /* object path */
+ settings_intf_name, /* interface name */
+ "Get", /* method name */
+ &error, /* object to return error in */
+ &m, /* return message on success */
+ "ss", /* input signature */
+ host_intf_name, /* first argument */
+ name); /* second argument */
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to issue method call: %s\n", error.message);
+ goto finish;
+ }
+
+ /*
+ * The output should be parsed exactly the same as the output formatting
+ * specified.
+ */
+ r = sd_bus_message_read(m, "v", "s", &temp_buf);
+ if (r < 0) {
+ fprintf(stderr, "Failed to parse response message: %s\n", strerror(-r));
+ goto finish;
+ }
+
+ asprintf(buf, "%s", temp_buf);
+/* *buf = (char*) malloc(strlen(temp_buf));
+ if (*buf) {
+ strcpy(*buf, temp_buf);
+ }
+*/
+ printf("IPMID boot option property get: {%s}.\n", (char *) temp_buf);
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+ free(connection);
+
+ return r;
+}
+
+int dbus_set_property(const char * name, const char *value)
+{
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL;
+ sd_bus *bus = NULL;
+ char *connection = NULL;
+ int r;
+
+ r = object_mapper_get_connection(&connection, settings_object_name);
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to get connection, return value: %d.\n", r);
+ goto finish;
+ }
+
+ printf("connection: %s\n", connection);
+
+ // Get the system bus where most system services are provided.
+ bus = ipmid_get_sd_bus_connection();
+
+ /*
+ * Bus, service, object path, interface and method are provided to call
+ * the method.
+ * Signatures and input arguments are provided by the arguments at the
+ * end.
+ */
+ r = sd_bus_call_method(bus,
+ connection, /* service to contact */
+ settings_object_name, /* object path */
+ settings_intf_name, /* interface name */
+ "Set", /* method name */
+ &error, /* object to return error in */
+ &m, /* return message on success */
+ "ssv", /* input signature */
+ host_intf_name, /* first argument */
+ name, /* second argument */
+ "s", /* third argument */
+ value); /* fourth argument */
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to issue method call: %s\n", error.message);
+ goto finish;
+ }
+
+ printf("IPMID boot option property set: {%s}.\n", value);
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+ free(connection);
+
+ return r;
+}
+
struct get_sys_boot_options_t {
uint8_t parameter;
uint8_t set;
uint8_t block;
} __attribute__ ((packed));
+struct get_sys_boot_options_response_t {
+ uint8_t version;
+ uint8_t parm;
+ uint8_t data[5];
+} __attribute__ ((packed));
+
+struct set_sys_boot_options_t {
+ uint8_t parameter;
+ uint8_t data[8];
+} __attribute__ ((packed));
+
ipmi_ret_t ipmi_chassis_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
@@ -23,29 +252,264 @@
return rc;
}
+//------------------------------------------------------------
+// Calls into Chassis Control Dbus object to do the power off
+//------------------------------------------------------------
+int ipmi_chassis_power_control(const char *method)
+{
+ // sd_bus error
+ int rc = 0;
+
+ // SD Bus error report mechanism.
+ sd_bus_error bus_error = SD_BUS_ERROR_NULL;
+
+ // Response from the call. Although there is no response for this call,
+ // obligated to mention this to make compiler happy.
+ sd_bus_message *response = NULL;
+
+ // Gets a hook onto either a SYSTEM or SESSION bus
+ sd_bus *bus_type = ipmid_get_sd_bus_connection();
+
+ rc = sd_bus_call_method(bus_type, // On the System Bus
+ chassis_bus_name, // Service to contact
+ chassis_object_name, // Object path
+ chassis_intf_name, // Interface name
+ method, // Method to be called
+ &bus_error, // object to return error
+ &response, // Response buffer if any
+ NULL); // No input arguments
+ if(rc < 0)
+ {
+ fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message);
+ }
+ else
+ {
+ printf("Chassis Power Off initiated successfully\n");
+ }
+
+ sd_bus_error_free(&bus_error);
+ sd_bus_message_unref(response);
+
+ return rc;
+}
+
+
+//----------------------------------------------------------------------
+// Chassis Control commands
+//----------------------------------------------------------------------
+ipmi_ret_t ipmi_chassis_control(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ // Error from power off.
+ int rc = 0;
+
+ // No response for this command.
+ *data_len = 0;
+
+ // Catch the actual operaton by peeking into request buffer
+ uint8_t chassis_ctrl_cmd = *(uint8_t *)request;
+ printf("Chassis Control Command: Operation:[0x%X]\n",chassis_ctrl_cmd);
+
+ switch(chassis_ctrl_cmd)
+ {
+ case CMD_POWER_OFF:
+ rc = ipmi_chassis_power_control("powerOff");
+ break;
+ case CMD_HARD_RESET:
+ rc = ipmi_chassis_power_control("reboot");
+ break;
+ default:
+ {
+ fprintf(stderr, "Invalid Chassis Control command:[0x%X] received\n",chassis_ctrl_cmd);
+ rc = -1;
+ }
+ }
+
+ return ( (rc < 0) ? IPMI_CC_INVALID : IPMI_CC_OK);
+}
+
+struct bootOptionTypeMap_t {
+ uint8_t ipmibootflag;
+ char dbusname[8];
+};
+
+#define INVALID_STRING "Invalid"
+// dbus supports this list of boot devices.
+bootOptionTypeMap_t g_bootOptionTypeMap_t[] = {
+
+ {0x01, "Network"},
+ {0x02, "Disk"},
+ {0x03, "Safe"},
+ {0x05, "CDROM"},
+ {0x06, "Setup"},
+ {0x00, "Default"},
+ {0xFF, INVALID_STRING}
+};
+
+uint8_t get_ipmi_boot_option(char *p) {
+
+ bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
+
+ while (s->ipmibootflag != 0xFF) {
+ if (!strcmp(s->dbusname,p))
+ break;
+ s++;
+ }
+
+ if (!s->ipmibootflag)
+ printf("Failed to find Sensor Type %s\n", p);
+
+ return s->ipmibootflag;
+}
+
+char* get_boot_option_by_ipmi(uint8_t p) {
+
+ bootOptionTypeMap_t *s = g_bootOptionTypeMap_t;
+
+ while (s->ipmibootflag != 0xFF) {
+
+ if (s->ipmibootflag == p)
+ break;
+
+ s++;
+ }
+
+
+ if (!s->ipmibootflag)
+ printf("Failed to find Sensor Type 0x%x\n", p);
+
+ return s->dbusname;
+}
+
ipmi_ret_t ipmi_chassis_get_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
- ipmi_ret_t rc = IPMI_CC_OK;
- *data_len = 0;
+ ipmi_ret_t rc = IPMI_CC_PARM_NOT_SUPPORTED;
+ char *p = NULL;
+ get_sys_boot_options_response_t *resp = (get_sys_boot_options_response_t *) response;
+ get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request;
+ uint8_t s;
printf("IPMI GET_SYS_BOOT_OPTIONS\n");
- get_sys_boot_options_t *reqptr = (get_sys_boot_options_t*) request;
+ memset(resp,0,sizeof(*resp));
+ resp->version = SET_PARM_VERSION;
+ resp->parm = 5;
+ resp->data[0] = SET_PARM_BOOT_FLAGS_VALID_ONE_TIME;
- // TODO Return default values to OPAL until dbus interface is available
+ *data_len = sizeof(*resp);
- if (reqptr->parameter == 5) // Parameter #5
- {
- uint8_t buf[] = {0x1,0x5,80,0,0,0,0};
- *data_len = sizeof(buf);
- memcpy(response, &buf, *data_len);
- }
- else
- {
+ /*
+ * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
+ * This is the only parameter used by petitboot.
+ */
+ if (reqptr->parameter == 5) {
+
+ /* Get the boot device */
+ int r = dbus_get_property("boot_flags",&p);
+
+ if (r < 0) {
+ fprintf(stderr, "Dbus get property(boot_flags) failed for get_sys_boot_options.\n");
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+
+ } else {
+
+ s = get_ipmi_boot_option(p);
+ resp->data[1] = (s << 2);
+ rc = IPMI_CC_OK;
+
+ }
+
+ if (p)
+ {
+ free(p);
+ p = NULL;
+ }
+
+ /* Get the boot policy */
+ r = dbus_get_property("boot_policy",&p);
+
+ if (r < 0) {
+ fprintf(stderr, "Dbus get property(boot_policy) failed for get_sys_boot_options.\n");
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+
+ } else {
+
+ printf("BootPolicy is[%s]", p);
+ resp->data[0] = (strncmp(p,"ONETIME",strlen("ONETIME"))==0) ?
+ SET_PARM_BOOT_FLAGS_VALID_ONE_TIME:
+ SET_PARM_BOOT_FLAGS_VALID_PERMANENT;
+ rc = IPMI_CC_OK;
+
+ }
+
+
+ } else {
fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
- return IPMI_CC_PARM_NOT_SUPPORTED;
+ }
+
+ if (p)
+ free(p);
+
+ return rc;
+}
+
+
+
+ipmi_ret_t ipmi_chassis_set_sys_boot_options(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ ipmi_ret_t rc = IPMI_CC_OK;
+ char *s;
+
+ printf("IPMI SET_SYS_BOOT_OPTIONS\n");
+
+ set_sys_boot_options_t *reqptr = (set_sys_boot_options_t *) request;
+
+ // This IPMI command does not have any resposne data
+ *data_len = 0;
+
+ /* 000101
+ * Parameter #5 means boot flags. Please refer to 28.13 of ipmi doc.
+ * This is the only parameter used by petitboot.
+ */
+ if (reqptr->parameter == 5) {
+
+ s = get_boot_option_by_ipmi(((reqptr->data[1] & 0x3C) >> 2));
+
+ printf("%d: %s\n", __LINE__, s);
+ if (!strcmp(s,INVALID_STRING)) {
+
+ rc = IPMI_CC_PARM_NOT_SUPPORTED;
+
+ } else {
+
+ int r = dbus_set_property("boot_flags",s);
+
+ if (r < 0) {
+ fprintf(stderr, "Dbus set property(boot_flags) failed for set_sys_boot_options.\n");
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ }
+
+ /* setting the boot policy */
+ s = (char *)(((reqptr->data[0] & SET_PARM_BOOT_FLAGS_PERMANENT) ==
+ SET_PARM_BOOT_FLAGS_PERMANENT) ?"PERMANENT":"ONETIME");
+
+ printf ( "\nBoot Policy is %s",s);
+ int r = dbus_set_property("boot_policy",s);
+
+ if (r < 0) {
+ fprintf(stderr, "Dbus set property(boot_policy) failed for set_sys_boot_options.\n");
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
+
+ } else {
+ fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
+ rc = IPMI_CC_PARM_NOT_SUPPORTED;
}
return rc;
@@ -58,5 +522,11 @@
printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS);
ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_GET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_get_sys_boot_options);
+
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL);
+ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_CHASSIS_CONTROL, NULL, ipmi_chassis_control);
+
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n", NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS);
+ ipmi_register_callback(NETFUN_CHASSIS, IPMI_CMD_SET_SYS_BOOT_OPTIONS, NULL, ipmi_chassis_set_sys_boot_options);
}
diff --git a/chassishandler.h b/chassishandler.h
index 99ed366..b6f7d93 100644
--- a/chassishandler.h
+++ b/chassishandler.h
@@ -1,17 +1,41 @@
#ifndef __HOST_IPMI_CHASSIS_HANDLER_H__
#define __HOST_IPMI_CHASSIS_HANDLER_H__
+#include <stdint.h>
+
// IPMI commands for Chassis net functions.
enum ipmi_netfn_app_cmds
{
+ // Chassis Control
+ IPMI_CMD_CHASSIS_CONTROL = 0x02,
// Get capability bits
+ IPMI_CMD_SET_SYS_BOOT_OPTIONS = 0x08,
IPMI_CMD_GET_SYS_BOOT_OPTIONS = 0x09,
};
// Command specific completion codes
enum ipmi_chassis_return_codes
{
+ IPMI_OK = 0x0,
IPMI_CC_PARM_NOT_SUPPORTED = 0x80,
};
+// Generic completion codes,
+// see IPMI doc section 5.2
+enum ipmi_generic_return_codes
+{
+ IPMI_OUT_OF_SPACE = 0xC4,
+};
+
+// Various Chassis operations under a single command.
+enum ipmi_chassis_control_cmds : uint8_t
+{
+ CMD_POWER_OFF = 0x00,
+ CMD_POWER_ON = 0x01,
+ CMD_POWER_CYCLE = 0x02,
+ CMD_HARD_RESET = 0x03,
+ CMD_PULSE_DIAGNOSTIC_INTR = 0x04,
+ CMD_SOFT_OFF_VIA_OVER_TEMP = 0x05,
+};
+
#endif
diff --git a/globalhandler.C b/globalhandler.C
new file mode 100644
index 0000000..2d3af92
--- /dev/null
+++ b/globalhandler.C
@@ -0,0 +1,152 @@
+#include "globalhandler.h"
+#include "ipmid-api.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+
+const char *control_object_name = "/org/openbmc/control/bmc0";
+const char *control_intf_name = "org.openbmc.control.Bmc";
+
+const char *objectmapper_service_name = "org.openbmc.objectmapper";
+const char *objectmapper_object_name = "/org/openbmc/objectmapper/objectmapper";
+const char *objectmapper_intf_name = "org.openbmc.objectmapper.ObjectMapper";
+
+void register_netfn_global_functions() __attribute__((constructor));
+
+int obj_mapper_get_connection(char** buf, const char* obj_path)
+{
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL;
+ sd_bus *bus = NULL;
+ char *temp_buf = NULL, *intf = NULL;
+ size_t buf_size = 0;
+ int r;
+
+ //Get the system bus where most system services are provided.
+ bus = ipmid_get_sd_bus_connection();
+
+ /*
+ * Bus, service, object path, interface and method are provided to call
+ * the method.
+ * Signatures and input arguments are provided by the arguments at the
+ * end.
+ */
+ r = sd_bus_call_method(bus,
+ objectmapper_service_name, /* service to contact */
+ objectmapper_object_name, /* object path */
+ objectmapper_intf_name, /* interface name */
+ "GetObject", /* method name */
+ &error, /* object to return error in */
+ &m, /* return message on success */
+ "s", /* input signature */
+ obj_path /* first argument */
+ );
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to issue method call: %s\n", error.message);
+ goto finish;
+ }
+
+ // Get the key, aka, the connection name
+ sd_bus_message_read(m, "a{sas}", 1, &temp_buf, 1, &intf);
+
+ /*
+ * TODO: check the return code. Currently for no reason the message
+ * parsing of object mapper is always complaining about
+ * "Device or resource busy", but the result seems OK for now. Need
+ * further checks.
+ */
+
+ buf_size = strlen(temp_buf) + 1;
+ printf("IPMID connection name: %s\n", temp_buf);
+ *buf = (char*)malloc(buf_size);
+
+ if (*buf == NULL) {
+ fprintf(stderr, "Malloc failed for warm reset");
+ r = -1;
+ goto finish;
+ }
+
+ memcpy(*buf, temp_buf, buf_size);
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+
+ return r;
+}
+
+int dbus_warm_reset()
+{
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m = NULL;
+ sd_bus *bus = NULL;
+ char* temp_buf = NULL;
+ uint8_t* get_value = NULL;
+ char* connection = NULL;
+ int r, i;
+
+ r = obj_mapper_get_connection(&connection, control_object_name);
+ if (r < 0) {
+ fprintf(stderr, "Failed to get connection, return value: %d.\n", r);
+ goto finish;
+ }
+
+ printf("connection: %s\n", connection);
+
+ // Open the system bus where most system services are provided.
+ bus = ipmid_get_sd_bus_connection();
+
+ /*
+ * Bus, service, object path, interface and method are provided to call
+ * the method.
+ * Signatures and input arguments are provided by the arguments at the
+ * end.
+ */
+ r = sd_bus_call_method(bus,
+ connection, /* service to contact */
+ control_object_name, /* object path */
+ control_intf_name, /* interface name */
+ "warmReset", /* method name */
+ &error, /* object to return error in */
+ &m, /* return message on success */
+ NULL,
+ NULL
+ );
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to issue method call: %s\n", error.message);
+ goto finish;
+ }
+
+finish:
+ sd_bus_error_free(&error);
+ sd_bus_message_unref(m);
+ free(connection);
+
+ return r;
+}
+
+ipmi_ret_t ipmi_global_warm_reset(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ printf("Handling GLOBAL warmReset Netfn:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
+
+ // TODO: call the correct dbus method for warmReset.
+ dbus_warm_reset();
+
+ // Status code.
+ ipmi_ret_t rc = IPMI_CC_OK;
+ *data_len = 0;
+ return rc;
+}
+
+
+void register_netfn_global_functions()
+{
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_APP, IPMI_CMD_WARM_RESET);
+ ipmi_register_callback(NETFUN_APP, IPMI_CMD_WARM_RESET, NULL, ipmi_global_warm_reset);
+
+ return;
+}
diff --git a/globalhandler.h b/globalhandler.h
new file mode 100644
index 0000000..608df3b
--- /dev/null
+++ b/globalhandler.h
@@ -0,0 +1,12 @@
+#ifndef __HOST_IPMI_GLOBAL_HANDLER_H__
+#define __HOST_IPMI_GLOBAL_HANDLER_H__
+
+#include <stdint.h>
+
+// Various GLOBAL operations under a single command.
+enum ipmi_global_control_cmds : uint8_t
+{
+IPMI_CMD_WARM_RESET = 0x02,
+};
+
+#endif
diff --git a/groupext.C b/groupext.C
new file mode 100644
index 0000000..b834f9b
--- /dev/null
+++ b/groupext.C
@@ -0,0 +1,31 @@
+#include "ipmid-api.h"
+#include "ipmid.H"
+#include <stdio.h>
+#include <stdint.h>
+
+#define GRPEXT_GET_GROUP_CMD 0
+void register_netfn_groupext_functions() __attribute__((constructor));
+
+ipmi_ret_t ipmi_groupext(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ // Generic return from IPMI commands.
+ ipmi_ret_t rc = IPMI_CC_OK;
+ uint8_t *p = (uint8_t*) response;
+
+ printf("IPMI GROUP EXTENTIONS\n");
+
+ *data_len = 1;
+ *p = 0;
+
+ return rc;
+}
+
+void register_netfn_groupext_functions()
+{
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_GRPEXT, GRPEXT_GET_GROUP_CMD);
+ ipmi_register_callback(NETFUN_GRPEXT, GRPEXT_GET_GROUP_CMD, NULL, ipmi_groupext);
+
+ return;
+}
diff --git a/host-services.c b/host-services.c
new file mode 100644
index 0000000..cc47439
--- /dev/null
+++ b/host-services.c
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <systemd/sd-bus.h>
+
+#include "ipmid-api.h"
+
+void register_host_services() __attribute__((constructor));
+
+// OpenBMC Host IPMI dbus framework
+const char *bus_name = "org.openbmc.HostIpmi";
+const char *object_name = "/org/openbmc/HostIpmi/1";
+const char *intf_name = "org.openbmc.HostIpmi";
+
+//-------------------------------------------------------------------
+// Gets called by PowerOff handler when a Soft Power off is requested
+//-------------------------------------------------------------------
+static int soft_power_off(sd_bus_message *m, void *userdata, sd_bus_error *ret_error)
+{
+ int64_t bt_resp = -1;
+ int rc = 0;
+
+ // Steps to be taken when we get this.
+ // 1: Send a SMS_ATN to the Host
+ // 2: Host receives it and sends a GetMsgFlags IPMI command
+ // 3: IPMID app handler will respond to that with a MSgFlag with bit:0x2
+ // set indicating we have a message for Host
+ // 4: Host sends a GetMsgBuffer command and app handler will respond to
+ // that with a OEM-SEL with certain fields packed indicating to the
+ // host that it do a shutdown of the partitions.
+ // 5: Host does the partition shutdown and calls Chassis Power off command
+ // 6: App handler handles the command by making a call to ChassisManager
+ // Dbus
+
+ // Now the job is to send the SMS_ATTN.
+
+ // Req message contains the specifics about which method etc that we want to
+ // access on which bus, object
+ sd_bus_message *response = NULL;
+
+ // Error return mechanism
+ sd_bus_error bus_error = SD_BUS_ERROR_NULL;
+
+ // Gets a hook onto either a SYSTEM or SESSION bus
+ sd_bus *bus = ipmid_get_sd_bus_connection();
+
+ rc = sd_bus_call_method(bus, // In the System Bus
+ bus_name, // Service to contact
+ object_name, // Object path
+ intf_name, // Interface name
+ "setAttention", // Method to be called
+ &bus_error, // object to return error
+ &response, // Response buffer if any
+ NULL); // No input arguments
+ if(rc < 0)
+ {
+ fprintf(stderr,"ERROR initiating Power Off:[%s]\n",bus_error.message);
+ goto finish;
+ }
+
+ // See if we were able to successfully raise SMS_ATN
+ rc = sd_bus_message_read(response, "x", &bt_resp);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Failed to get a rc from BT for SMS_ATN: %s\n", strerror(-rc));
+ goto finish;
+ }
+
+finish:
+ sd_bus_error_free(&bus_error);
+ response = sd_bus_message_unref(response);
+
+ if(rc < 0)
+ {
+ return sd_bus_reply_method_return(m, "x", rc);
+ }
+ else
+ {
+ return sd_bus_reply_method_return(m, "x", bt_resp);
+ }
+}
+
+//-------------------------------------------
+// Function pointer of APIs exposed via Dbus
+//-------------------------------------------
+static const sd_bus_vtable host_services_vtable[] =
+{
+ SD_BUS_VTABLE_START(0),
+ // Takes No("") arguments -but- returns a value of type 64 bit integer("x")
+ SD_BUS_METHOD("SoftPowerOff", "", "x", &soft_power_off, SD_BUS_VTABLE_UNPRIVILEGED),
+ SD_BUS_VTABLE_END,
+};
+
+//------------------------------------------------------
+// Called by IPMID as part of the start up
+// -----------------------------------------------------
+int start_host_service(sd_bus *bus, sd_bus_slot *slot)
+{
+ int rc = 0;
+
+ /* Install the object */
+ rc = sd_bus_add_object_vtable(bus,
+ &slot,
+ "/org/openbmc/HostServices", /* object path */
+ "org.openbmc.HostServices", /* interface name */
+ host_services_vtable,
+ NULL);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Failed to issue method call: %s\n", strerror(-rc));
+ }
+ else
+ {
+ /* Take one in OpenBmc */
+ rc = sd_bus_request_name(bus, "org.openbmc.HostServices", 0);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Failed to acquire service name: %s\n", strerror(-rc));
+ }
+ }
+
+ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
+}
+
+//------------------------------------------------------
+// Callback register function
+// -----------------------------------------------------
+void register_host_services()
+{
+ // Gets a hook onto SYSTEM bus used by host-ipmid
+ sd_bus *bus = ipmid_get_sd_bus_connection();
+
+ // Gets a hook onto SYSTEM bus slot used by host-ipmid
+ sd_bus_slot *ipmid_slot = ipmid_get_sd_bus_slot();
+
+ //start_host_service(bus, ipmid_slot);
+ start_host_service(bus, ipmid_slot);
+}
diff --git a/host-services.h b/host-services.h
new file mode 100644
index 0000000..0d93480
--- /dev/null
+++ b/host-services.h
@@ -0,0 +1,3 @@
+#include <systemd/sd-bus.h>
+
+extern "C" int start_host_service(sd_bus *, sd_bus_slot *);
diff --git a/ipmid-api.h b/ipmid-api.h
index 34d3bbe..cf3eaab 100644
--- a/ipmid-api.h
+++ b/ipmid-api.h
@@ -3,6 +3,10 @@
#include <stdlib.h>
#include <systemd/sd-bus.h>
+#ifdef __cplusplus
+extern "C" {
+#endif
+
// length of Completion Code and its ALWAYS _1_
#define IPMI_CC_LEN 1
@@ -51,11 +55,11 @@
// This is the constructor function that is called into by each plugin handlers.
// When ipmi sets up the callback handlers, a call is made to this with
// information of netfn, cmd, callback handler pointer and context data.
-// Making this a extern "C" so that plugin libraries written in C can also use
-// it.
-extern "C" void ipmi_register_callback(ipmi_netfn_t, ipmi_cmd_t,
+void ipmi_register_callback(ipmi_netfn_t, ipmi_cmd_t,
ipmi_context_t, ipmid_callback_t);
+unsigned short get_sel_reserve_id(void);
+
// These are the command network functions, the response
// network functions are the function + 1. So to determine
// the proper network function which issued the command
@@ -89,10 +93,18 @@
IPMI_CC_OK = 0x00,
IPMI_DCMI_CC_NO_ACTIVE_POWER_LIMIT = 0x80,
IPMI_CC_INVALID = 0xC1,
+ IPMI_CC_INVALID_RESERVATION_ID = 0xC5,
+ IPMI_CC_PARM_OUT_OF_RANGE = 0xC9,
IPMI_CC_SENSOR_INVALID = 0xCB,
IPMI_CC_RESPONSE_ERROR = 0xCE,
IPMI_CC_UNSPECIFIED_ERROR = 0xFF,
};
sd_bus *ipmid_get_sd_bus_connection(void);
+sd_bus_slot *ipmid_get_sd_bus_slot(void);
+
+#ifdef __cplusplus
+}
+#endif
+
#endif
diff --git a/ipmid.C b/ipmid.C
index 6b1eacc..7354958 100644
--- a/ipmid.C
+++ b/ipmid.C
@@ -13,8 +13,8 @@
#include <errno.h>
#include "sensorhandler.h"
-
sd_bus *bus = NULL;
+sd_bus_slot *ipmid_slot = NULL;
FILE *ipmiio, *ipmidbus, *ipmicmddetails;
@@ -26,8 +26,6 @@
fprintf(stderr, " mask : 0xFF - Print all trace\n");
}
-
-
const char * DBUS_INTF = "org.openbmc.HostIpmi";
const char * FILTER = "type='signal',interface='org.openbmc.HostIpmi',member='ReceivedMessage'";
@@ -39,7 +37,13 @@
// Global data structure that contains the IPMI command handler's registrations.
std::map<ipmi_fn_cmd_t, ipmi_fn_context_t> g_ipmid_router_map;
+// IPMI Spec, shared Reservation ID.
+unsigned short g_sel_reserve = 0xFFFF;
+unsigned short get_sel_reserve_id(void)
+{
+ return g_sel_reserve;
+}
#ifndef HEXDUMP_COLS
#define HEXDUMP_COLS 16
@@ -200,13 +204,13 @@
r = sd_bus_message_append(m, "yyyyy", seq, netfn, lun, cmd, cc);
if (r < 0) {
fprintf(stderr, "Failed add the netfn and others : %s\n", strerror(-r));
- return -1;
+ goto final;
}
r = sd_bus_message_append_array(m, 'y', buf, len);
if (r < 0) {
fprintf(stderr, "Failed to add the string of response bytes: %s\n", strerror(-r));
- return -1;
+ goto final;
}
@@ -214,19 +218,20 @@
// Call the IPMI responder on the bus so the message can be sent to the CEC
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
- fprintf(stderr, "Failed to call the method: %s", strerror(-r));
- return -1;
+ fprintf(stderr, "Failed to call the method: %s\n", strerror(-r));
+ fprintf(stderr, "Dest: %s, Path: %s\n", dest, path);
+ goto final;
}
r = sd_bus_message_read(reply, "x", &pty);
if (r < 0) {
fprintf(stderr, "Failed to get a rc from the method: %s\n", strerror(-r));
-
}
+final:
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
-
+ m = sd_bus_message_unref(m);
+ reply = sd_bus_message_unref(reply);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}
@@ -234,7 +239,6 @@
static int handle_ipmi_command(sd_bus_message *m, void *user_data, sd_bus_error
*ret_error) {
int r = 0;
- const char *msg = NULL;
unsigned char sequence, netfn, lun, cmd;
const void *request;
size_t sz;
@@ -268,6 +272,10 @@
if(r != 0)
{
fprintf(stderr,"ERROR:[0x%X] handling NetFn:[0x%X], Cmd:[0x%X]\n",r, netfn, cmd);
+
+ if(r == -1) {
+ response[0] = IPMI_CC_UNSPECIFIED_ERROR;
+ }
}
fprintf(ipmiio, "IPMI Response:\n");
@@ -342,8 +350,8 @@
handler_fqdn += "/";
num_handlers = scandir(ipmi_lib_path, &handler_list, handler_select, alphasort);
- if (num_handlers < 0)
- return;
+ if (num_handlers < 0)
+ return;
while(num_handlers--)
{
@@ -352,6 +360,7 @@
printf("Registering handler:[%s]\n",handler_fqdn.c_str());
lib_handler = dlopen(handler_fqdn.c_str(), RTLD_NOW);
+
if(lib_handler == NULL)
{
fprintf(stderr,"ERROR opening [%s]: %s\n",
@@ -360,6 +369,7 @@
// Wipe the memory allocated for this particular entry.
free(handler_list[num_handlers]);
}
+
// Done with all registration.
free(handler_list);
}
@@ -372,11 +382,13 @@
return bus;
}
+sd_bus_slot *ipmid_get_sd_bus_slot(void) {
+ return ipmid_slot;
+}
+
int main(int argc, char *argv[])
{
- sd_bus_slot *slot = NULL;
int r;
- char *mode = NULL;
unsigned long tvalue;
int c;
@@ -418,7 +430,8 @@
// Register all the handlers that provider implementation to IPMI commands.
ipmi_register_callback_handlers(HOST_IPMI_LIB_PATH);
- r = sd_bus_add_match(bus, &slot, FILTER, handle_ipmi_command, NULL);
+ // Watch for BT messages
+ r = sd_bus_add_match(bus, &ipmid_slot, FILTER, handle_ipmi_command, NULL);
if (r < 0) {
fprintf(stderr, "Failed: sd_bus_add_match: %s : %s\n", strerror(-r), FILTER);
goto finish;
@@ -427,7 +440,6 @@
for (;;) {
/* Process requests */
-
r = sd_bus_process(bus, NULL);
if (r < 0) {
fprintf(stderr, "Failed to process bus: %s\n", strerror(-r));
@@ -445,7 +457,7 @@
}
finish:
- sd_bus_slot_unref(slot);
+ sd_bus_slot_unref(ipmid_slot);
sd_bus_unref(bus);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
@@ -456,7 +468,7 @@
// step for mapping IPMI
int find_interface_property_fru_type(dbus_interface_t *interface, const char *property_name, char *property_value) {
- char *str1, *str2, *str3;
+ char *str1;
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *reply = NULL, *m=NULL;
@@ -468,6 +480,7 @@
fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
interface->bus, interface->path, interface->interface);
+ goto final;
}
r = sd_bus_message_append(m, "ss", "org.openbmc.InventoryItem", property_name);
@@ -475,6 +488,7 @@
fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
fprintf(stderr,"Bus: %s Path: %s Interface: %s \n",
interface->bus, interface->path, interface->interface);
+ goto final;
}
r = sd_bus_call(bus, m, 0, &error, &reply);
@@ -494,7 +508,8 @@
final:
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
+ m = sd_bus_message_unref(m);
+ reply = sd_bus_message_unref(reply);
return r;
}
@@ -510,29 +525,18 @@
char *str1, *str2, *str3;
sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus_message *reply = NULL, *m=NULL;
+ sd_bus_message *reply = NULL;
int r;
- r = sd_bus_message_new_method_call(bus,&m,busname,objname,busname,"getObjectFromByteId");
+ r = sd_bus_call_method(bus,busname,objname,busname, "getObjectFromByteId",
+ &error, &reply, "sy", type, num);
if (r < 0) {
fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
- }
-
- r = sd_bus_message_append(m, "sy", type, num);
- if (r < 0) {
- fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
- }
-
- // Call the IPMI responder on the bus so the message can be sent to the CEC
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- fprintf(stderr, "Failed to call the method: %s", strerror(-r));
goto final;
}
-
r = sd_bus_message_read(reply, "(sss)", &str1, &str2, &str3);
if (r < 0) {
fprintf(stderr, "Failed to get a response: %s", strerror(-r));
@@ -548,7 +552,7 @@
final:
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
+ reply = sd_bus_message_unref(reply);
return r;
}
@@ -559,64 +563,76 @@
// Routines used by ipmi commands wanting to interact on the dbus
//
/////////////////////////////////////////////////////////////////////
-
-
-// Simple set routine because some methods are standard.
-int set_sensor_dbus_state(uint8_t number, const char *method, const char *value) {
+int set_sensor_dbus_state_s(uint8_t number, const char *method, const char *value) {
dbus_interface_t a;
int r;
sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus_message *reply = NULL, *m=NULL;
-
- fprintf(ipmidbus, "Attempting to set a dbus Sensor 0x%02x via %s with a value of %s\n",
- number, method, value);
-
- r = find_openbmc_path("SENSOR", number, &a);
-
- r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
- if (r < 0) {
- fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
- }
-
- r = sd_bus_message_append(m, "s", value);
- if (r < 0) {
- fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
- }
-
- r = sd_bus_call(bus, m, 0, &error, &reply);
- if (r < 0) {
- fprintf(stderr, "Failed to call the method: %s", strerror(-r));
- }
-
- sd_bus_error_free(&error);
- sd_bus_message_unref(m);
-
- return 0;
-}
-
-int set_sensor_dbus_state_v(uint8_t number, const char *method, char *value) {
-
-
- dbus_interface_t a;
- int r;
- sd_bus_error error = SD_BUS_ERROR_NULL;
- sd_bus_message *reply = NULL, *m=NULL;
+ sd_bus_message *m=NULL;
fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of %s\n",
number, method, value);
r = find_openbmc_path("SENSOR", number, &a);
+ if (r < 0) {
+ fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
+ return 0;
+ }
+
r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
if (r < 0) {
fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
+ goto final;
}
r = sd_bus_message_append(m, "v", "s", value);
if (r < 0) {
fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
+ goto final;
+ }
+
+
+ r = sd_bus_call(bus, m, 0, &error, NULL);
+ if (r < 0) {
+ fprintf(stderr, "Failed to call the method: %s", strerror(-r));
+ }
+
+final:
+ sd_bus_error_free(&error);
+ m = sd_bus_message_unref(m);
+
+ return 0;
+}
+int set_sensor_dbus_state_y(uint8_t number, const char *method, const uint8_t value) {
+
+
+ dbus_interface_t a;
+ int r;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message *m=NULL;
+
+ fprintf(ipmidbus, "Attempting to set a dbus Variant Sensor 0x%02x via %s with a value of 0x%02x\n",
+ number, method, value);
+
+ r = find_openbmc_path("SENSOR", number, &a);
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to find Sensor 0x%02x\n", number);
+ return 0;
+ }
+
+ r = sd_bus_message_new_method_call(bus,&m,a.bus,a.path,a.interface,method);
+ if (r < 0) {
+ fprintf(stderr, "Failed to create a method call: %s", strerror(-r));
+ goto final;
+ }
+
+ r = sd_bus_message_append(m, "v", "i", value);
+ if (r < 0) {
+ fprintf(stderr, "Failed to create a input parameter: %s", strerror(-r));
+ goto final;
}
@@ -625,9 +641,9 @@
fprintf(stderr, "12 Failed to call the method: %s", strerror(-r));
}
-
+final:
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
+ m = sd_bus_message_unref(m);
return 0;
}
diff --git a/ipmid.H b/ipmid.H
index 73b60e6..679392d 100644
--- a/ipmid.H
+++ b/ipmid.H
@@ -2,6 +2,7 @@
#define __HOST_IPMID_IPMI_H__
#include "ipmid-api.h"
#include <stdio.h>
+#include "host-services.h"
// When the requester sends in a netfn and a command along with data, this
// function will look for registered handlers that will handle that [netfn,cmd]
@@ -15,8 +16,10 @@
// The BT FIFO in the AST2400 can only handle 64 bytes.
// Can only allow 63 because the BT interface still
// needs 1 byte for the length field.
-#define MAX_IPMI_BUFFER 63
+#define MAX_IPMI_BUFFER 64
extern FILE *ipmiio, *ipmidbus, *ipmicmddetails;
-#endif
+int set_sensor_dbus_state_s(uint8_t , const char *, const char *);
+int set_sensor_dbus_state_y(uint8_t , const char *, const uint8_t);
+#endif
\ No newline at end of file
diff --git a/ipmisensor.C b/ipmisensor.C
index 6d3d3bd..b6927ac 100644
--- a/ipmisensor.C
+++ b/ipmisensor.C
@@ -2,10 +2,10 @@
#include <string.h>
#include <stdint.h>
#include <malloc.h>
-
+#include <ipmid.H>
+#include "sensorhandler.h"
extern uint8_t find_sensor(uint8_t);
-extern int set_sensor_dbus_state_v(uint8_t , const char *, char *);
struct sensorRES_t {
@@ -30,19 +30,20 @@
uint8_t sensor_type;
uint8_t offset;
int (*func)(const sensorRES_t *, const lookup_t *, const char *);
- char method[16];
+ char member[16];
char assertion[64];
char deassertion[64];
};
-
-extern int updateDbusInterface(uint8_t , const char *, const char *) ;
-extern int set_sensor_dbus_state(uint8_t ,const char *, const char *);
+extern int updateDbusInterface(uint8_t , const char *, const char *);
+extern int find_openbmc_path(const char *, const uint8_t , dbus_interface_t *) ;
int set_sensor_dbus_state_simple(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {
- return set_sensor_dbus_state(pRec->sensor_number, pTable->method, value);
+ return set_sensor_dbus_state_s(pRec->sensor_number,
+ pTable->member,
+ value);
}
struct event_data_t {
@@ -129,22 +130,47 @@
break;
case 0x02 : snprintf(p, sizeof(valuestring), "FW Progress, %s", event_data_lookup(g_fwprogress02h, pRec->event_data2));
break;
+ default : snprintf(p, sizeof(valuestring), "Internal warning, fw_progres offset unknown (0x%02x)", pTable->offset);
+ break;
}
- return set_sensor_dbus_state_v(pRec->sensor_number, pTable->method, p);
+ return set_sensor_dbus_state_s(pRec->sensor_number,
+ pTable->member,
+ p);
}
// Handling this special OEM sensor by coping what is in byte 4. I also think that is odd
// considering byte 3 is for sensor reading. This seems like a misuse of the IPMI spec
int set_sensor_dbus_state_osbootcount(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {
- char valuestring[32];
- char* pStr = valuestring;
-
- sprintf(valuestring, "%d", pRec->assert_state7_0);
-
- return set_sensor_dbus_state_v(pRec->sensor_number, pTable->method, pStr);
+ return set_sensor_dbus_state_y(pRec->sensor_number,
+ "setValue",
+ pRec->assert_state7_0);
}
+int set_sensor_dbus_state_system_event(const sensorRES_t *pRec, const lookup_t *pTable, const char *value) {
+ char valuestring[128];
+ char* p = valuestring;
+
+ switch (pTable->offset) {
+
+ case 0x00 : snprintf(p, sizeof(valuestring), "System Reconfigured");
+ break;
+ case 0x01 : snprintf(p, sizeof(valuestring), "OEM Boot Event");
+ break;
+ case 0x02 : snprintf(p, sizeof(valuestring), "Undetermine System Hardware Failure");
+ break;
+ case 0x03 : snprintf(p, sizeof(valuestring), "System Failure see error log for more details (0x%02x)", pRec->event_data2);
+ break;
+ case 0x04 : snprintf(p, sizeof(valuestring), "System Failure see PEF error log for more details (0x%02x)", pRec->event_data2);
+ break;
+ default : snprintf(p, sizeof(valuestring), "Internal warning, system_event offset unknown (0x%02x)", pTable->offset);
+ break;
+ }
+
+ return set_sensor_dbus_state_s(pRec->sensor_number,
+ pTable->member,
+ p);
+}
// This table lists only senors we care about telling dbus about.
@@ -155,13 +181,13 @@
{0xe9, 0x00, set_sensor_dbus_state_simple, "setValue", "Disabled", ""}, // OCC Inactive 0
{0xe9, 0x01, set_sensor_dbus_state_simple, "setValue", "Enabled", ""}, // OCC Active 1
{0x07, 0x07, set_sensor_dbus_state_simple, "setPresent", "True", "False"},
- {0x07, 0x08, set_sensor_dbus_state_simple, "setFault", "True", ""},
+ {0x07, 0x08, set_sensor_dbus_state_simple, "setFault", "True", "False"},
{0x0C, 0x06, set_sensor_dbus_state_simple, "setPresent", "True", "False"},
- {0x0C, 0x04, set_sensor_dbus_state_simple, "setFault", "True", ""},
+ {0x0C, 0x04, set_sensor_dbus_state_simple, "setFault", "True", "False"},
{0x0F, 0x02, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
{0x0F, 0x01, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
{0x0F, 0x00, set_sensor_dbus_state_fwprogress, "setValue", "True", "False"},
- {0xC7, 0x01, set_sensor_dbus_state_simple, "setFault", "True", ""},
+ {0xC7, 0x01, set_sensor_dbus_state_simple, "setFault", "True", "False"},
{0xc3, 0x00, set_sensor_dbus_state_osbootcount, "setValue", "" ,""},
{0x1F, 0x00, set_sensor_dbus_state_simple, "setValue", "Boot completed (00)", ""},
{0x1F, 0x01, set_sensor_dbus_state_simple, "setValue", "Boot completed (01)", ""},
@@ -170,6 +196,11 @@
{0x1F, 0x04, set_sensor_dbus_state_simple, "setValue", "CD-ROM boot completed", ""},
{0x1F, 0x05, set_sensor_dbus_state_simple, "setValue", "ROM boot completed", ""},
{0x1F, 0x06, set_sensor_dbus_state_simple, "setValue", "Boot completed (06)", ""},
+ {0x12, 0x00, set_sensor_dbus_state_system_event, "setValue", "", ""},
+ {0x12, 0x01, set_sensor_dbus_state_system_event, "setValue", "", ""},
+ {0x12, 0x02, set_sensor_dbus_state_system_event, "setValue", "", ""},
+ {0x12, 0x03, set_sensor_dbus_state_system_event, "setValue", "", ""},
+ {0x12, 0x04, set_sensor_dbus_state_system_event, "setValue", "", ""},
{0xFF, 0xFF, NULL, "", "", ""}
};
diff --git a/sensorhandler.C b/sensorhandler.C
index cd57dd4..39de660 100644
--- a/sensorhandler.C
+++ b/sensorhandler.C
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
+#include <systemd/sd-bus.h>
extern int updateSensorRecordFromSSRAESC(const void *);
extern int find_interface_property_fru_type(dbus_interface_t *interface, const char *property_name, char *property_value) ;
@@ -29,15 +30,23 @@
{0xe9, 0x09, "OccStatus"}, // E9 is an internal mapping to handle sensor type code os 0x09
{0xC3, 0x6F, "BootCount"},
{0x1F, 0x6F, "OperatingSystemStatus"},
+ {0x12, 0x6F, "SYSTEM_EVENT"},
+ {0xC7, 0x03, "SYSTEM"},
+ {0xC7, 0x03, "MAIN_PLANAR"},
+ {0xC2, 0x6F, "PowerCap"},
{0xFF, 0x00, ""},
};
-
struct sensor_data_t {
uint8_t sennum;
} __attribute__ ((packed)) ;
+struct sensorreadingresp_t {
+ uint8_t value;
+ uint8_t operation;
+ uint8_t indication[2];
+} __attribute__ ((packed)) ;
uint8_t dbus_to_sensor_type(char *p) {
@@ -102,6 +111,10 @@
return r;
}
+
+
+
+
ipmi_ret_t ipmi_sen_get_sensor_type(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
@@ -119,15 +132,7 @@
// HACK UNTIL Dbus gets updated or we find a better way
if (buf[0] == 0) {
-
- switch(reqptr->sennum) {
- case 0x35 : buf[0] = 0x12; buf[1] = 0x6F; break;
- case 0x37 : buf[0] = 0xC7; buf[1] = 0x03; break;
- case 0x38 : buf[0] = 0xC7; buf[1] = 0x03; break;
- case 0x39 : buf[0] = 0xC7; buf[1] = 0x03; break;
- case 0x3A : buf[0] = 0xC7; buf[1] = 0x03; break;
- default: rc = IPMI_CC_SENSOR_INVALID;
- }
+ rc = IPMI_CC_SENSOR_INVALID;
}
@@ -145,9 +150,6 @@
{
sensor_data_t *reqptr = (sensor_data_t*)request;
ipmi_ret_t rc = IPMI_CC_OK;
- unsigned short rlen;
-
- rlen = (unsigned short) *data_len;
printf("IPMI SET_SENSOR [0x%02x]\n",reqptr->sennum);
@@ -158,6 +160,77 @@
return rc;
}
+
+ipmi_ret_t ipmi_sen_get_sensor_reading(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
+ ipmi_request_t request, ipmi_response_t response,
+ ipmi_data_len_t data_len, ipmi_context_t context)
+{
+ sensor_data_t *reqptr = (sensor_data_t*)request;
+ ipmi_ret_t rc = IPMI_CC_SENSOR_INVALID;
+ uint8_t type;
+ sensorreadingresp_t *resp = (sensorreadingresp_t*) response;
+ int r;
+ dbus_interface_t a;
+ sd_bus *bus = ipmid_get_sd_bus_connection();
+ sd_bus_message *reply = NULL;
+ int reading = 0;
+
+
+ printf("IPMI GET_SENSOR_READING [0x%02x]\n",reqptr->sennum);
+
+ r = find_openbmc_path("SENSOR", reqptr->sennum, &a);
+
+ if (r < 0) {
+ fprintf(stderr, "Failed to find Sensor 0x%02x\n", reqptr->sennum);
+ return IPMI_CC_SENSOR_INVALID;
+ }
+
+ type = find_sensor(reqptr->sennum);
+
+ fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n", a.bus, a.path, a.interface);
+
+ *data_len=0;
+
+ switch(type) {
+ case 0xC3:
+ case 0xC2:
+ r = sd_bus_get_property(bus,a.bus, a.path, a.interface, "value", NULL, &reply, "i");
+ if (r < 0) {
+ fprintf(stderr, "Failed to call sd_bus_get_property:%d, %s\n", r, strerror(-r));
+ fprintf(stderr, "Bus: %s, Path: %s, Interface: %s\n",
+ a.bus, a.path, a.interface);
+ break;
+ }
+
+ r = sd_bus_message_read(reply, "i", &reading);
+ if (r < 0) {
+ fprintf(stderr, "Failed to read sensor: %s\n", strerror(-r));
+ break;
+ }
+
+ printf("Contents of a 0x%02x is 0x%02x\n", type, reading);
+
+ rc = IPMI_CC_OK;
+ *data_len=sizeof(sensorreadingresp_t);
+
+ resp->value = (uint8_t)reading;
+ resp->operation = 0;
+ resp->indication[0] = 0;
+ resp->indication[1] = 0;
+ break;
+
+ default:
+ *data_len=0;
+ rc = IPMI_CC_SENSOR_INVALID;
+ break;
+ }
+
+
+ reply = sd_bus_message_unref(reply);
+
+ return rc;
+}
+
ipmi_ret_t ipmi_sen_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
@@ -182,5 +255,8 @@
printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_SENSOR, IPMI_CMD_SET_SENSOR);
ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_SET_SENSOR, NULL, ipmi_sen_set_sensor);
+ printf("Registering NetFn:[0x%X], Cmd:[0x%X]\n",NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING);
+ ipmi_register_callback(NETFUN_SENSOR, IPMI_CMD_GET_SENSOR_READING, NULL, ipmi_sen_get_sensor_reading);
+
return;
}
diff --git a/sensorhandler.h b/sensorhandler.h
index 7b89a18..dd940dc 100644
--- a/sensorhandler.h
+++ b/sensorhandler.h
@@ -6,6 +6,7 @@
// IPMI commands for net functions.
enum ipmi_netfn_sen_cmds
{
+ IPMI_CMD_GET_SENSOR_READING = 0x2D,
IPMI_CMD_GET_SENSOR_TYPE = 0x2F,
IPMI_CMD_SET_SENSOR = 0x30,
};
diff --git a/storageaddsel.C b/storageaddsel.C
index 64b0e6a..3343772 100644
--- a/storageaddsel.C
+++ b/storageaddsel.C
@@ -80,18 +80,39 @@
FILE *fp;
size_t size = 0;
+ int r;
if ((fp = fopen(fn, "rb")) != NULL) {
- fseek(fp, 0, SEEK_END);
- size = ftell(fp);
- fseek(fp, 0, SEEK_SET);
+ r = fseek(fp, 0, SEEK_END);
+ if (r) {
+ fprintf(stderr,"Fseek failed\n");
+ goto fclose_fp;
+ }
- size = 0x100;
+ size = ftell(fp);
+ if (size == -1L) {
+ fprintf(stderr,"Ftell failed for %s\n", strerror(errno));
+ size = 0;
+ goto fclose_fp;
+ }
+
+ r = fseek(fp, 0, SEEK_SET);
+ if (r) {
+ fprintf(stderr,"Fseek failed\n");
+ size = 0;
+ goto fclose_fp;
+ }
*buffer = new uint8_t [size];
- fread(*buffer, 1, size, fp);
+ r = fread(*buffer, 1, size, fp);
+ if ( r != size) {
+ size = 0;
+ fprintf(stderr,"Fread failed\n");
+ }
+
+fclose_fp:
fclose(fp);
}
@@ -120,9 +141,10 @@
find_openbmc_path("SENSOR", sensor, &dbusint);
+ // Simply no associations if the sensor can not be found
if (strlen(dbusint.path) < 1) {
- printf("Sensor not found\n");
- snprintf(dbusint.path, sizeof(dbusint.path), "0x%x", sensor);
+ printf("Sensor 0x%x not found\n", sensor);
+ memset(dbusint.path,0,sizeof(dbusint.path));
}
asprintf(m, "%s", dbusint.path);
@@ -136,7 +158,6 @@
ipmi_add_sel_request_t *p;
- int r;
char *m;
p = ( ipmi_add_sel_request_t *) buffer;
@@ -156,7 +177,7 @@
sd_bus *mbus = NULL;
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message *reply = NULL, *m=NULL;
- uint16_t *pty;
+ uint16_t x;
int r;
mbus = ipmid_get_sd_bus_connection();
@@ -168,88 +189,65 @@
"acceptHostMessage");
if (r < 0) {
fprintf(stderr, "Failed to add the method object: %s\n", strerror(-r));
- return -1;
+ goto finish;
}
r = sd_bus_message_append(m, "sss", desc, sev, details);
if (r < 0) {
fprintf(stderr, "Failed add the message strings : %s\n", strerror(-r));
- return -1;
+ goto finish;
}
r = sd_bus_message_append_array(m, 'y', debug, debuglen);
if (r < 0) {
fprintf(stderr, "Failed to add the raw array of bytes: %s\n", strerror(-r));
- return -1;
+ goto finish;
}
-
// Call the IPMI responder on the bus so the message can be sent to the CEC
r = sd_bus_call(mbus, m, 0, &error, &reply);
if (r < 0) {
- fprintf(stderr, "Failed to call the method: %s", strerror(-r));
- return -1;
+ fprintf(stderr, "Failed to call the method: %s %s\n", __FUNCTION__, strerror(-r));
+ goto finish;
}
-
- r = sd_bus_message_read(reply, "q", &pty);
+ r = sd_bus_message_read(reply, "q", &x);
if (r < 0) {
fprintf(stderr, "Failed to get a rc from the method: %s\n", strerror(-r));
- } else {
- r = *pty;
}
finish:
sd_bus_error_free(&error);
- sd_bus_message_unref(m);
- sd_bus_message_unref(reply);
-
+ m = sd_bus_message_unref(m);
+ reply = sd_bus_message_unref(reply);
return r;
}
void send_esel(uint16_t recordid) {
- char *desc, *assoc, *ascii;
+ char *desc, *assoc;
const char *sev;
uint8_t *buffer = NULL;
- char *path, *pathsent;
+ const char *path = "/tmp/esel";
size_t sz;
int r;
- uint8_t hack[] = {0x30, 0x32, 0x34};
-
- asprintf(&path,"%s%04x", "/tmp/esel", recordid);
-
sz = getfilestream(path, &buffer);
-
if (sz == 0) {
printf("Error file does not exist %d\n",__LINE__);
- free(path);
return;
}
-
sev = create_esel_severity(buffer);
-
create_esel_association(buffer, &assoc);
-
create_esel_description(buffer, sev, &desc);
+ r = send_esel_to_dbus(desc, sev, assoc, buffer, sz);
+ if (r < 0) {
+ fprintf(stderr, "Failed to send esel to dbus\n");
+ }
- // TODO until ISSUE https://github.com/openbmc/rest-dbus/issues/2
- // I cant send extended ascii chars. So 0,2,4 for now...
- r = send_esel_to_dbus(desc, sev, assoc, hack, 3);
-
- asprintf(&pathsent,"%s_%d", path, r);
-
-
- rename(path, pathsent);
-
- free(path);
- free(pathsent);
free(assoc);
free(desc);
-
delete[] buffer;
-
return;
}
diff --git a/storagehandler.C b/storagehandler.C
index 1459f94..9622ed9 100644
--- a/storagehandler.C
+++ b/storagehandler.C
@@ -2,6 +2,7 @@
#include <string.h>
#include <stdint.h>
#include <time.h>
+#include <sys/time.h>
#include <arpa/inet.h>
#include "storagehandler.h"
@@ -12,7 +13,7 @@
unsigned int g_sel_time = 0xFFFFFFFF;
-unsigned short g_sel_reserve = 0x1;
+extern unsigned short g_sel_reserve;
ipmi_ret_t ipmi_storage_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
@@ -52,14 +53,26 @@
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
- unsigned int *bufftype = (unsigned int *) request;
+ uint32_t* secs = (uint32_t*)request;
printf("Handling Set-SEL-Time:[0x%X], Cmd:[0x%X]\n",netfn, cmd);
- printf("Data: 0x%X]\n",*bufftype);
+ printf("Data: 0x%X]\n",*secs);
- g_sel_time = *bufftype;
-
+ struct timeval sel_time;
+ sel_time.tv_sec = le32toh(*secs);
+ sel_time.tv_usec = 0;
ipmi_ret_t rc = IPMI_CC_OK;
+ int rct = settimeofday(&sel_time, NULL);
+
+ if(rct == 0)
+ {
+ system("hwclock -w");
+ }
+ else
+ {
+ printf("settimeofday() failed\n");
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
*data_len = 0;
return rc;
}
@@ -87,17 +100,19 @@
return rc;
}
-
-
ipmi_ret_t ipmi_storage_reserve_sel(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
{
+ unsigned short res_id;
ipmi_ret_t rc = IPMI_CC_OK;
- printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
+ // IPMI spec, Reservation ID, the value simply increases against each execution of reserve_sel command.
+ if( ++g_sel_reserve == 0)
+ g_sel_reserve = 1;
+ printf("IPMI Handling RESERVE-SEL 0x%04x\n", g_sel_reserve);
*data_len = sizeof(g_sel_reserve);
@@ -125,8 +140,6 @@
// Pack the actual response
memcpy(response, &p->eventdata[1], 2);
- // TODO This code should grab the completed partial esel located in
- // the /tmp/esel0100 file and commit it to the error log handler.
send_esel(recordid);
return rc;
diff --git a/testit.C b/testit.C
index bfd9334..a0cd2c1 100644
--- a/testit.C
+++ b/testit.C
@@ -37,25 +37,31 @@
char g_results_value[64];
-int set_sensor_dbus_state_v(uint8_t number, const char *method, char *value) {
- printf("Attempting to log Variant Sensor 0x%02x via %s with a value of %s\n",
- number, method, value);
+int set_sensor_dbus_state_s(unsigned char number, const char *member, const char *value) {
+ printf("Attempting to log 0x%02x via %s with a value of %s\n",
+ number, member, value);
- strcpy(g_results_method, method);
+ strcpy(g_results_method, member);
strcpy(g_results_value, value);
return 0;
}
-int set_sensor_dbus_state(uint8_t number, const char *method, const char *value) {
+int set_sensor_dbus_state_y(unsigned char number, char const* member, uint8_t value) {
+
+ char val[2];
- printf("Attempting to log Sensor 0x%02x via %s with a value of %s\n",
- number, method, value);
- strcpy(g_results_method, method);
- strcpy(g_results_value, value);
+ printf("Attempting to log Variant Sensor 0x%02x via %s with a value of 0x%02x\n",
+ number, member, value);
- return 0;
+
+ snprintf(val, 2, "%d", value);
+
+ strcpy(g_results_method, member);
+ strcpy(g_results_value, val);
+
+ return 0;
}
diff --git a/transporthandler.C b/transporthandler.C
index ca8522d..3b4cf07 100644
--- a/transporthandler.C
+++ b/transporthandler.C
@@ -1,13 +1,127 @@
#include <stdio.h>
#include <string.h>
#include <stdint.h>
+#include <arpa/inet.h>
+#include <string>
#include "ipmid-api.h"
#include "ipmid.H"
#include "transporthandler.h"
+#define SYSTEMD_NETWORKD_DBUS 1
+
+#ifdef SYSTEMD_NETWORKD_DBUS
+#include <systemd/sd-bus.h>
+#endif
+
+// OpenBMC System Manager dbus framework
+const char *app = "org.openbmc.NetworkManager";
+const char *obj = "/org/openbmc/NetworkManager/Interface";
+const char *ifc = "org.openbmc.NetworkManager";
+
+const char *nwinterface = "eth0";
+
+const int SIZE_MAC = 18; //xx:xx:xx:xx:xx:xx
+
+char new_ipaddr [INET_ADDRSTRLEN] = "";
+char new_netmask [INET_ADDRSTRLEN] = "";
+char new_gateway [INET_ADDRSTRLEN] = "";
+
+const uint8_t SET_COMPLETE = 0;
+const uint8_t SET_IN_PROGRESS = 1;
+const uint8_t SET_COMMIT_WRITE = 2; //Optional
+const uint8_t SET_IN_PROGRESS_RESERVED = 3; //Reserved
+
+// Status of Set-In-Progress Parameter (# 0)
+uint8_t lan_set_in_progress = SET_COMPLETE;
+
+
+
void register_netfn_transport_functions() __attribute__((constructor));
+// Helper Function to get IP Address/NetMask/Gateway from Network Manager or Cache
+// based on Set-In-Progress State
+ipmi_ret_t getNetworkData(uint8_t lan_param, uint8_t * data)
+{
+ sd_bus *bus = ipmid_get_sd_bus_connection();
+ sd_bus_message *reply = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int family;
+ unsigned char prefixlen;
+ char* ipaddr = NULL;
+ unsigned long mask = 0xFFFFFFFF;
+ char* gateway = NULL;
+ int r = 0;
+ ipmi_ret_t rc = IPMI_CC_OK;
+
+ r = sd_bus_call_method(bus, app, obj, ifc, "GetAddress4", &error,
+ &reply, "s", nwinterface);
+ if(r < 0)
+ {
+ fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r));
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ goto cleanup;
+ }
+
+ r = sd_bus_message_read(reply, "iyss", &family, &prefixlen, &ipaddr, &gateway);
+ if(r < 0)
+ {
+ fprintf(stderr, "Failed to get a response: %s\n", strerror(-rc));
+ rc = IPMI_CC_RESPONSE_ERROR;
+ goto cleanup;
+ }
+
+ printf("N/W data from HW %s:%d:%s:%s\n", family==AF_INET?"IPv4":"IPv6", prefixlen, ipaddr,gateway);
+ printf("N/W data from Cache: %s:%s:%s\n", new_ipaddr, new_netmask, new_gateway);
+
+ if(lan_param == LAN_PARM_IP)
+ {
+ if(lan_set_in_progress == SET_COMPLETE)
+ {
+ std::string ipaddrstr(ipaddr);
+ inet_pton(AF_INET, ipaddrstr.c_str(),(void *)data);
+ }
+ else if(lan_set_in_progress == SET_IN_PROGRESS)
+ {
+ inet_pton(AF_INET, new_ipaddr, (void *)data);
+ }
+ }
+ else if(lan_param == LAN_PARM_SUBNET)
+ {
+ if(lan_set_in_progress == SET_COMPLETE)
+ {
+ mask = htonl(mask<<(32-prefixlen));
+ memcpy(data, &mask, 4);
+ }
+ else if(lan_set_in_progress == SET_IN_PROGRESS)
+ {
+ inet_pton(AF_INET, new_netmask, (void *)data);
+ }
+ }
+ else if(lan_param == LAN_PARM_GATEWAY)
+ {
+ if(lan_set_in_progress == SET_COMPLETE)
+ {
+ std::string gatewaystr(gateway);
+ inet_pton(AF_INET, gatewaystr.c_str(), (void *)data);
+ }
+ else if(lan_set_in_progress == SET_IN_PROGRESS)
+ {
+ inet_pton(AF_INET, new_gateway,(void *)data);
+ }
+ }
+ else
+ {
+ rc = IPMI_CC_PARM_OUT_OF_RANGE;
+ }
+
+cleanup:
+ sd_bus_error_free(&error);
+ reply = sd_bus_message_unref(reply);
+
+ return rc;
+}
+
ipmi_ret_t ipmi_transport_wildcard(ipmi_netfn_t netfn, ipmi_cmd_t cmd,
ipmi_request_t request, ipmi_response_t response,
ipmi_data_len_t data_len, ipmi_context_t context)
@@ -31,9 +145,10 @@
{
ipmi_ret_t rc = IPMI_CC_OK;
*data_len = 0;
-
- int i = 0;
- char syscmd[128];
+ sd_bus *bus = ipmid_get_sd_bus_connection();
+ sd_bus_message *reply = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r = 0;
printf("IPMI SET_LAN\n");
@@ -43,27 +158,90 @@
// TODO Add the rest of the parameters like setting auth type
// TODO Add error handling
- if (reqptr->parameter == 3) // IP
+ if (reqptr->parameter == LAN_PARM_IP)
{
- sprintf(syscmd, "ifconfig eth0 %d.%d.%d.%d", reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
- system(syscmd);
+ snprintf(new_ipaddr, INET_ADDRSTRLEN, "%d.%d.%d.%d",
+ reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
}
- else if (reqptr->parameter == 6) // Subnet
+ else if (reqptr->parameter == LAN_PARM_MAC)
{
- sprintf(syscmd, "ifconfig eth0 netmask %d.%d.%d.%d", reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
- system(syscmd);
+ char mac[SIZE_MAC];
+
+ snprintf(mac, SIZE_MAC, "%02x:%02x:%02x:%02x:%02x:%02x",
+ reqptr->data[0],
+ reqptr->data[1],
+ reqptr->data[2],
+ reqptr->data[3],
+ reqptr->data[4],
+ reqptr->data[5]);
+
+ r = sd_bus_call_method(bus, app, obj, ifc, "SetHwAddress", &error,
+ &reply, "ss", nwinterface, mac);
+ if(r < 0)
+ {
+ fprintf(stderr, "Failed to call the method: %s\n", strerror(-r));
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
}
- else if (reqptr->parameter == 12) // Gateway
+ else if (reqptr->parameter == LAN_PARM_SUBNET)
{
- sprintf(syscmd, "route add default gw %d.%d.%d.%d", reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
- system(syscmd);
+ snprintf(new_netmask, INET_ADDRSTRLEN, "%d.%d.%d.%d",
+ reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
+ }
+ else if (reqptr->parameter == LAN_PARM_GATEWAY)
+ {
+ snprintf(new_gateway, INET_ADDRSTRLEN, "%d.%d.%d.%d",
+ reqptr->data[0], reqptr->data[1], reqptr->data[2], reqptr->data[3]);
+ }
+ else if (reqptr->parameter == LAN_PARM_INPROGRESS)
+ {
+ if(reqptr->data[0] == SET_COMPLETE) // Set Complete
+ {
+ lan_set_in_progress = SET_COMPLETE;
+ // Apply the IP settings once IP Address, Netmask and Gateway is set
+ if (!strcmp(new_ipaddr, "") || !strcmp (new_netmask, "") || !strcmp (new_gateway, ""))
+ {
+ printf("ERROR: Incomplete LAN Parameters\n");
+ }
+ else
+ {
+
+ r = sd_bus_call_method(bus, // On the System Bus
+ app, // Service to contact
+ obj, // Object path
+ ifc, // Interface name
+ "SetAddress4", // Method to be called
+ &error, // object to return error
+ &reply, // Response message on success
+ "ssss", // input message (Interface, IP Address, Netmask, Gateway)
+ nwinterface, // eth0
+ new_ipaddr,
+ new_netmask,
+ new_gateway);
+ if(r < 0)
+ {
+ fprintf(stderr, "Failed to set network data %s:%s:%s %s\n", new_ipaddr, new_netmask, new_gateway, error.message);
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
+ memset(new_ipaddr, 0, INET_ADDRSTRLEN);
+ memset(new_netmask, 0, INET_ADDRSTRLEN);
+ memset(new_gateway, 0, INET_ADDRSTRLEN);
+ }
+ }
+ else if(reqptr->data[0] == SET_IN_PROGRESS) // Set In Progress
+ {
+ lan_set_in_progress = SET_IN_PROGRESS;
+ }
}
else
{
fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
- return IPMI_CC_PARM_NOT_SUPPORTED;
+ rc = IPMI_CC_PARM_NOT_SUPPORTED;
}
+ sd_bus_error_free(&error);
+ reply = sd_bus_message_unref(reply);
+
return rc;
}
@@ -80,9 +258,11 @@
{
ipmi_ret_t rc = IPMI_CC_OK;
*data_len = 0;
-
+ sd_bus *bus = ipmid_get_sd_bus_connection();
+ sd_bus_message *reply = NULL;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ int r = 0;
const uint8_t current_revision = 0x11; // Current rev per IPMI Spec 2.0
- char syscmd[128];
int i = 0;
printf("IPMI GET_LAN\n");
@@ -100,87 +280,103 @@
// TODO Use dbus interface once available. For now use ip cmd.
// TODO Add the rest of the parameters, like gateway
- if (reqptr->parameter == 0) // In progress
+ if (reqptr->parameter == LAN_PARM_INPROGRESS)
{
- uint8_t buf[] = {current_revision,0};
+ uint8_t buf[] = {current_revision, lan_set_in_progress};
*data_len = sizeof(buf);
memcpy(response, &buf, *data_len);
- return IPMI_CC_OK;
}
- else if (reqptr->parameter == 1) // Authentication support
+ else if (reqptr->parameter == LAN_PARM_AUTHSUPPORT)
{
uint8_t buf[] = {current_revision,0x04};
*data_len = sizeof(buf);
memcpy(response, &buf, *data_len);
- return IPMI_CC_OK;
}
- else if (reqptr->parameter == 2) // Authentication enables
+ else if (reqptr->parameter == LAN_PARM_AUTHENABLES)
{
uint8_t buf[] = {current_revision,0x04,0x04,0x04,0x04,0x04};
*data_len = sizeof(buf);
memcpy(response, &buf, *data_len);
- return IPMI_CC_OK;
}
- else if (reqptr->parameter == 3) // IP
+ else if ((reqptr->parameter == LAN_PARM_IP) || (reqptr->parameter == LAN_PARM_SUBNET) || (reqptr->parameter == LAN_PARM_GATEWAY))
{
- //string to parse: inet xx.xx.xxx.xxx/xx
-
uint8_t buf[5];
- memcpy((void*)&buf[0], ¤t_revision, 1);
- for (i=0; i<4; i++)
+ *data_len = sizeof(current_revision);
+ memcpy(buf, ¤t_revision, *data_len);
+
+ if(getNetworkData(reqptr->parameter, &buf[1]) == IPMI_CC_OK)
{
- char ip[5];
-
- sprintf(syscmd, "ip address show dev eth0|grep inet|cut -d'/' -f1|cut -d' ' -f 6|cut -d'.' -f%d|head -n1", i+1);
- FILE *fp = popen(syscmd, "r");
-
- memset(ip,0,sizeof(ip));
- while (fgets(ip, sizeof(ip), fp) != 0)
- {
- int tmpip = strtoul(ip, NULL, 10);
- memcpy((void*)&buf[i+1], &tmpip, 1);
- }
- pclose(fp);
+ *data_len = sizeof(buf);
+ memcpy(response, &buf, *data_len);
}
-
- *data_len = sizeof(buf);
- memcpy(response, &buf, *data_len);
- return IPMI_CC_OK;
+ else
+ {
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ }
}
- else if (reqptr->parameter == 5) // MAC
+ else if (reqptr->parameter == LAN_PARM_MAC)
{
//string to parse: link/ether xx:xx:xx:xx:xx:xx
-
uint8_t buf[7];
+ char *eaddr1 = NULL;
+
+ r = sd_bus_call_method(bus, app, obj, ifc, "GetHwAddress", &error,
+ &reply, "s", nwinterface);
+ if(r < 0)
+ {
+ fprintf(stderr, "Failed to call Get Method: %s\n", strerror(-r));
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ goto cleanup;
+ }
+
+ r = sd_bus_message_read(reply, "s", &eaddr1);
+ if (r < 0)
+ {
+ fprintf(stderr, "Failed to get a response: %s", strerror(-r));
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ goto cleanup;
+ }
+ if (eaddr1 == NULL)
+ {
+ fprintf(stderr, "Failed to get a valid response: %s", strerror(-r));
+ rc = IPMI_CC_UNSPECIFIED_ERROR;
+ goto cleanup;
+ }
+
memcpy((void*)&buf[0], ¤t_revision, 1);
- for (i=0; i<6; i++)
+ char *tokptr = NULL;
+ char* digit = strtok_r(eaddr1, ":", &tokptr);
+ if (digit == NULL)
{
- char mac[4];
+ fprintf(stderr, "Unexpected MAC format: %s", eaddr1);
+ rc = IPMI_CC_RESPONSE_ERROR;
+ goto cleanup;
+ }
- sprintf(syscmd, "ip address show dev eth0|grep link|cut -d' ' -f 6|cut -d':' -f%d", i+1);
- FILE *fp = popen(syscmd, "r");
-
- memset(mac,0,sizeof(mac));
- while (fgets(mac, sizeof(mac), fp) != 0)
- {
- int tmpmac = strtoul(mac, NULL, 16);
- memcpy((void*)&buf[i+1], &tmpmac, 1);
- }
- pclose(fp);
+ i=0;
+ while (digit != NULL)
+ {
+ int resp_byte = strtoul(digit, NULL, 16);
+ memcpy((void*)&buf[i+1], &resp_byte, 1);
+ i++;
+ digit = strtok_r(NULL, ":", &tokptr);
}
*data_len = sizeof(buf);
memcpy(response, &buf, *data_len);
- return IPMI_CC_OK;
}
else
{
fprintf(stderr, "Unsupported parameter 0x%x\n", reqptr->parameter);
- return IPMI_CC_PARM_NOT_SUPPORTED;
+ rc = IPMI_CC_PARM_NOT_SUPPORTED;
}
+cleanup:
+ sd_bus_error_free(&error);
+ reply = sd_bus_message_unref(reply);
+
return rc;
}
@@ -197,4 +393,3 @@
return;
}
-
diff --git a/transporthandler.h b/transporthandler.h
index 49b1d95..ce7842b 100644
--- a/transporthandler.h
+++ b/transporthandler.h
@@ -15,4 +15,13 @@
IPMI_CC_PARM_NOT_SUPPORTED = 0x80,
};
+// Parameters
+static const int LAN_PARM_INPROGRESS = 0;
+static const int LAN_PARM_AUTHSUPPORT = 1;
+static const int LAN_PARM_AUTHENABLES = 2;
+static const int LAN_PARM_IP = 3;
+static const int LAN_PARM_MAC = 5;
+static const int LAN_PARM_SUBNET = 6;
+static const int LAN_PARM_GATEWAY = 12;
+
#endif