summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVernon Mauery <vernon.mauery@intel.com>2019-02-06 12:00:54 -0800
committerAlexander Amelkin <mocbuhtig@amelkin.msk.ru>2019-04-15 18:41:47 +0300
commitb7b455a38cbd5f46fb6231168ac9b3acf5dd392a (patch)
tree1ac5c4fe31635647269f21761a01fabed4c6aba0
parentfa8e2ced19705de81bfd946f473a8f1528a39030 (diff)
downloadipmitool-b7b455a38cbd5f46fb6231168ac9b3acf5dd392a.tar.gz
add OpenBMC D-Bus interface
OpenBMC runs a D-Bus interface internally and has the option of compiling ipmitool so it can run natively on the BMC. This adds the D-Bus interface to ipmitool so it can be used with the OpenBMC project. Signed-off-by: Vernon Mauery <vernon.mauery@linux.intel.com>
-rw-r--r--configure.ac30
-rw-r--r--src/plugins/Makefile.am4
-rw-r--r--src/plugins/dbus/Makefile.am41
-rw-r--r--src/plugins/dbus/dbus.c241
-rw-r--r--src/plugins/ipmi_intf.c6
5 files changed, 320 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac
index 7bb6cbc..34c2081 100644
--- a/configure.ac
+++ b/configure.ac
@@ -59,6 +59,7 @@ dnl
xenable_all_options=yes
xenable_intf_bmc=no
+xenable_intf_dbus=no
xenable_intf_dummy=no
xenable_intf_imb=yes
xenable_intf_lipmi=yes
@@ -191,6 +192,14 @@ AC_CHECK_LIB([crypto], [MD2_Init],
fi],
[], [-lcrypto])
+dnl check for libsystemd in case dbus-intf is requested
+AC_CHECK_LIB([systemd], [sd_bus_default],
+ [
+ LIBS="$LIBS -lsystemd"
+ have_systemd=yes
+ ],
+ [ have_systemd=no],[])
+
dnl enable IPMIv1.5 LAN interface
AC_ARG_ENABLE([intf-lan],
[AC_HELP_STRING([--enable-intf-lan],
@@ -554,6 +563,25 @@ if test "x$xenable_intf_bmc" = "xyes"; then
IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB bmc/libintf_bmc.la"
fi
+dnl enable IPMI dbus interface
+AC_ARG_ENABLE([intf-dbus],
+ [AC_HELP_STRING([--enable-intf-dbus],
+ [enable IPMI dbus interface [default=no]])],
+ [xenable_intf_dbus=$enableval],
+ [xenable_intf_dbus=no])
+if test "x$xenable_intf_dbus" != "xno"; then
+ if test "x$have_systemd" != "xyes"; then
+ AC_MSG_ERROR([** Unable to find libsystemd required by dbus-intf.])
+ xenable_intf_dbus=no
+ fi
+fi
+if test "x$xenable_intf_dbus" = "xyes"; then
+ AC_DEFINE(IPMI_INTF_DBUS, [1], [Define to 1 to enable dbus interface.])
+ AC_SUBST(INTF_DBUS, [dbus])
+ AC_SUBST(INTF_DBUS_LIB, [libintf_dbus.la])
+ IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB dbus/libintf_dbus.la"
+fi
+
dnl enable Dummy interface for testing
AC_ARG_ENABLE([intf-dummy],
[AC_HELP_STRING([--enable-intf-dummy],
@@ -664,6 +692,7 @@ AC_CONFIG_FILES([Makefile
src/plugins/free/Makefile
src/plugins/imb/Makefile
src/plugins/bmc/Makefile
+ src/plugins/dbus/Makefile
src/plugins/usb/Makefile
src/plugins/lipmi/Makefile
src/plugins/serial/Makefile
@@ -681,6 +710,7 @@ AC_MSG_RESULT([ open : $xenable_intf_open])
AC_MSG_RESULT([ free : $xenable_intf_free])
AC_MSG_RESULT([ imb : $xenable_intf_imb])
AC_MSG_RESULT([ bmc : $xenable_intf_bmc])
+AC_MSG_RESULT([ dbus : $xenable_intf_dbus])
AC_MSG_RESULT([ usb : $xenable_intf_usb])
AC_MSG_RESULT([ lipmi : $xenable_intf_lipmi])
AC_MSG_RESULT([ serial : $xenable_intf_serial])
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index 7ad8173..c0b0b29 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -32,8 +32,8 @@ MAINTAINERCLEANFILES = Makefile.in
AM_CPPFLAGS = -I$(top_srcdir)/include
-SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ @INTF_USB@
-DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy usb
+SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ @INTF_USB@ @INTF_DBUS@
+DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy usb dbus
noinst_LTLIBRARIES = libintf.la
libintf_la_SOURCES = ipmi_intf.c
diff --git a/src/plugins/dbus/Makefile.am b/src/plugins/dbus/Makefile.am
new file mode 100644
index 0000000..3e92113
--- /dev/null
+++ b/src/plugins/dbus/Makefile.am
@@ -0,0 +1,41 @@
+ #
+ # Copyright (c) 2015 IBM Corporation
+ # All rights reserved.
+ #
+ # Redistribution and use in source and binary forms, with or without
+ # modification,are permitted provided that the following conditions are met:
+ #
+ # 1. Redistributions of source code must retain the above copyright notice,
+ # this list of conditions and the following disclaimer.
+ #
+ # 2. Redistributions in binary form must reproduce the above copyright notice,
+ # this list of conditions and the following disclaimer in the documentation
+ # and/or other materials provided with the distribution.
+ #
+ # 3. Neither the name of the copyright holder nor the names of its contributors
+ # may be used to endorse or promote products derived from this software
+ # without specific prior written permission.
+ #
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ # AND ANY EXPRESS OR IMPLIED WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE
+ # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ # POSSIBILITY OF SUCH DAMAGE.
+ #
+
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES = -I$(top_srcdir)/include
+
+EXTRA_LTLIBRARIES = libintf_dbus.la
+noinst_LTLIBRARIES = @INTF_DBUS_LIB@
+libintf_dbus_la_LDFLAGS = -lsystemd
+libintf_dbus_la_LIBADD = $(top_builddir)/lib/libipmitool.la
+libintf_dbus_la_SOURCES = dbus.c
+
diff --git a/src/plugins/dbus/dbus.c b/src/plugins/dbus/dbus.c
new file mode 100644
index 0000000..be72dcb
--- /dev/null
+++ b/src/plugins/dbus/dbus.c
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2015 IBM Corporation
+ * Copyright (c) 2019 Intel Corporation
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its
+ * contributors may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdbool.h>
+
+#include <systemd/sd-bus.h>
+
+#include <ipmitool/log.h>
+#include <ipmitool/ipmi.h>
+#include <ipmitool/ipmi_intf.h>
+
+static sd_bus *bus;
+
+static
+struct ipmi_rs *
+ipmi_dbus_sendrecv(struct ipmi_intf *intf,
+ struct ipmi_rq *req)
+{
+ static const char *destination = "xyz.openbmc_project.Ipmi.Host";
+ static const char *object_path = "/xyz/openbmc_project/Ipmi";
+ static const char *interface = "xyz.openbmc_project.Ipmi.Server";
+ static const char *method_name = "execute";
+ static const char SD_BUS_TYPE_3_BYTES[] = {
+ SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, 0
+ };
+ static const char SD_BUS_TYPE_4_BYTES[] = {
+ SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
+ SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, 0
+ };
+ static const char SD_BUS_TYPE_DICT_OF_VARIANTS[] = {
+ SD_BUS_TYPE_ARRAY,
+ SD_BUS_TYPE_DICT_ENTRY_BEGIN,
+ SD_BUS_TYPE_STRING, SD_BUS_TYPE_VARIANT,
+ SD_BUS_TYPE_DICT_ENTRY_END, 0
+ };
+ static const char SD_BUS_TYPE_IPMI_RESPONSE[] = {
+ SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
+ SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
+ SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_BYTE, 0
+ };
+
+ sd_bus_message *request = NULL;
+ int rc;
+ sd_bus_error error = SD_BUS_ERROR_NULL;
+ sd_bus_message* reply = NULL;
+ uint8_t recv_netfn;
+ uint8_t recv_lun;
+ uint8_t recv_cmd;
+ uint8_t recv_cc;
+ const void *data;
+ size_t data_len;
+ static struct ipmi_rs rsp;
+ struct ipmi_rs *ipmi_response = NULL;
+
+ if (!intf->opened || !bus)
+ {
+ goto out_no_free;
+ }
+
+ rsp.ccode = IPMI_CC_UNSPECIFIED_ERROR;
+ rsp.data_len = 0;
+ memset(rsp.data, 0, sizeof(rsp.data));
+
+ /* The D-Bus xyz.openbmc_project.Ipmi.Server.execute interface
+ * looks like this:
+ *
+ * Request:
+ * byte: net function
+ * byte: lun
+ * byte: command
+ * byte array: data (possibly zero length)
+ * array of (string,variant): options
+ * Response:
+ * byte: net function
+ * byte: lun
+ * byte: command
+ * byte: completion code
+ * byte array: response data (possibly zero length)
+ */
+ rc = sd_bus_message_new_method_call(bus, &request, destination,
+ object_path, interface,
+ method_name);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to create message: %s\n",
+ __func__, strerror(-rc));
+ goto out_no_free;
+ }
+ /* pack the header: netfn, lun, cmd */
+ rc = sd_bus_message_append(request, SD_BUS_TYPE_3_BYTES, req->msg.netfn,
+ req->msg.lun, req->msg.cmd);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to append parameters\n", __func__);
+ goto out_free_request;
+ }
+ /* pack the variable length data */
+ rc = sd_bus_message_append_array(request, SD_BUS_TYPE_BYTE,
+ req->msg.data, req->msg.data_len);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to append body\n", __func__);
+ goto out_free_request;
+ }
+
+ /* Options are only needed for session-based channels, but
+ * in order to fulfill the correct signature, an empty array
+ * must be packed */
+ rc = sd_bus_message_append(request, SD_BUS_TYPE_DICT_OF_VARIANTS,
+ NULL, 0);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to append options\n", __func__);
+ goto out_free_request;
+ }
+
+ rc = sd_bus_call(bus, request, 0, &error, &reply);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to send dbus message (%s)\n",
+ __func__, error.message);
+ goto out_free_request;
+ }
+
+ /* unpack the response; check that it has the expected types */
+ rc = sd_bus_message_enter_container(reply, SD_BUS_TYPE_STRUCT,
+ SD_BUS_TYPE_IPMI_RESPONSE);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to parse reply\n", __func__);
+ goto out_free_reply;
+ }
+ /* read the header: CC netfn lun cmd */
+ rc = sd_bus_message_read(reply, SD_BUS_TYPE_4_BYTES, &recv_netfn,
+ &recv_lun, &recv_cmd, &recv_cc);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to read reply\n", __func__);
+ goto out_free_reply;
+ }
+ /* read the variable length data */
+ rc = sd_bus_message_read_array(reply, SD_BUS_TYPE_BYTE,
+ &data, &data_len);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: failed to read reply data\n", __func__);
+ goto out_free_reply;
+ }
+ rc = sd_bus_message_exit_container(reply);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "%s: final unpack of message failed\n",
+ __func__);
+ goto out_free_reply;
+ }
+
+ if (data_len > sizeof(rsp.data)) {
+ lprintf(LOG_ERR, "%s: data too long!\n", __func__);
+ goto out_free_reply;
+ }
+
+ /* At this point, all the parts are available for a response
+ * other than unspecified error. */
+ rsp.ccode = recv_cc;
+ rsp.data_len = data_len;
+ memcpy(rsp.data, data, data_len);
+ ipmi_response = &rsp;
+
+out_free_reply:
+ /* message unref will free resources owned by the message */
+ sd_bus_message_unref(reply);
+out_free_request:
+ sd_bus_message_unref(request);
+out_no_free:
+ return ipmi_response;
+}
+
+static
+int
+ipmi_dbus_setup(struct ipmi_intf *intf)
+{
+ int rc;
+
+ rc = sd_bus_default_system(&bus);
+ if (rc < 0) {
+ lprintf(LOG_ERR, "Can't connect to session bus: %s\n",
+ strerror(-rc));
+ return -1;
+ }
+ intf->opened = 1;
+
+ return 0;
+}
+
+static
+void
+ipmi_dbus_close(struct ipmi_intf *intf)
+{
+ if (intf->opened)
+ {
+ sd_bus_close(bus);
+ }
+ intf->opened = 0;
+}
+
+struct ipmi_intf ipmi_dbus_intf = {
+ .name = "dbus",
+ .desc = "OpenBMC D-Bus interface",
+ .setup = ipmi_dbus_setup,
+ .close = ipmi_dbus_close,
+ .sendrecv = ipmi_dbus_sendrecv,
+};
+
+
diff --git a/src/plugins/ipmi_intf.c b/src/plugins/ipmi_intf.c
index f6bd2f6..d815e2b 100644
--- a/src/plugins/ipmi_intf.c
+++ b/src/plugins/ipmi_intf.c
@@ -86,6 +86,9 @@ extern struct ipmi_intf ipmi_dummy_intf;
#ifdef IPMI_INTF_USB
extern struct ipmi_intf ipmi_usb_intf;
#endif
+#ifdef IPMI_INTF_DBUS
+extern struct ipmi_intf ipmi_dbus_intf;
+#endif
struct ipmi_intf * ipmi_intf_table[] = {
#ifdef IPMI_INTF_OPEN
@@ -119,6 +122,9 @@ struct ipmi_intf * ipmi_intf_table[] = {
#ifdef IPMI_INTF_USB
&ipmi_usb_intf,
#endif
+#ifdef IPMI_INTF_DBUS
+ &ipmi_dbus_intf,
+#endif
NULL
};