Compare commits

...

20 Commits

Author SHA1 Message Date
ef92ab51e3 man: Add documentation for chassis bootmbox
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-10 12:27:48 +03:00
994d47b415 man: Update the chassis bootparam section
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-10 12:27:47 +03:00
90131f19fa chassis: Add boot initiator mailbox support
Add `chassis bootmbox` command to set and get Boot Initiator Mailbox
boot parameter (id 7) the easy way. The command allows for getting
and setting the data both in hex and text modes, as well as properly
decodes IANA Enterprise number for block 0. It can get/set the whole
mailbox at once or operate on separate data blocks.

This commit enhances the chassis_get_boot_param() function with extra
arguments to re-use its code in handling of the added command.

Documentation update will follow.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-10 12:27:47 +03:00
9bc1143e96 chassis: Use command-specific completion code parser
Get/set system boot option commands have some command-specific
completion codes that are now reported as "Unknown (0080)", etc.

Use the previously introduced specific_val2str() to convert those
specific error codes to human-readable strings.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-04 12:18:23 +03:00
69a44963d0 Add support for command-specific completion codes
Some commands may return command-specific completion codes.
Now they are all reported as 'Unknown'.
Add helper functions to support such command-specific codes.
Command handlers will need to define their own valstr arrays
with completion code descriptions and then use specific_val2str()
instead of generic val2str() to convert the completion code into
a string.

Also reduce code duplication in helper.c

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-04 12:18:23 +03:00
ca3a80fef8 Add a helper htoipmi24() function
The function converts a host 32-bit integer into an IPMI
24-bit value (LSB first).

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-04 12:18:23 +03:00
80350a744f Add a helper args2buf() function
The function converts a set of command line arguments representing
byte values into a byte buffer and verifies each individual value
to be a valid data byte.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-04 12:18:23 +03:00
619a02cf5d man: Cleanup the manpage formatting tags
The manpage contained a lot of redundant .RS/.RE tag pairs
with no content between the tags. This commits removes those.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-04 12:17:44 +03:00
e65a96b38d create_pen_list: only print if values are set
On a failed download of the PEN list, the create_pen_list script
improperly printed an invalid entry of { , "" } causing the build to
fail. The last line print must check that it has something to print or
it will print the wrong thing.

Partially resolves ipmitool/ipmitool#11

Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
2019-05-29 15:56:11 +03:00
9fa01f1a54 chassis: Refactor to reduce code duplication
Move boot information acknowledgement clearing code into
a helper funcion, call it instead of copy-pasted code.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-05-28 16:54:52 +03:00
432ea31804 chassis: Refactor to reduce code duplication
Get rid of repeated code that sets the set-in-progress parameter.
Introduce chassis_bootparam_set_in_progress() function to do
the job.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-05-28 14:49:43 +03:00
12e2f5da63 sdr: Fix segfault on invalid unit types
The program would crash if the BMC returned an out of range (>90)
unit type for a full sensor record. This commit adds a range check
and also add support for IPMI 2.0 additional unit types 91 and 92
("fatal error" and "grams").

Resolves ipmitool/ipmitool#118

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-05-27 15:38:23 +03:00
d818c2ff85 vendor: Add YADRO TATLIN Storage Controller ID
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-04-17 16:01:11 +03:00
cdd9d51c5f exchange-bmc-os-info: Remove dependency on ipmi.service
Resolves ipmitool/ipmitool#46

Most modern systems do not require ipmi.service to load the kernel
modules. Checking for /dev/ipmi* would be sufficient.

v2: Use Assert in place of Condition to explicitly fail based on
   AlexanderAmelkin's feedback.
Signed-off-by: Charles Rose <charles.rose@dell.com>
2019-04-16 11:41:51 +03:00
95038ba01b Add mechanism to configure to set the default interface
In some cases, the user may want to have a different default interface
without the need to always specify it on the command line. Add a
configure option that sets the default interface without the need to
patch the code.

Configure as: ./configure DEFAULT_INTF=name
where name is an interface name that might be enabled with
--enable-intf-<name>.

The configure will enforce that the selected default interface is
enabled.

Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
2019-04-16 11:31:18 +03:00
b0d84e0f15 ci: Update INSTALL to reflect recent changes
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-04-15 20:50:17 +03:00
1b636434a6 ci: Set up matrix builds with Travis CI
Enable CI building for Xenial and Trusty,
as well as for MacOS X 10.14 (Xcode 10.2).

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-04-15 20:50:17 +03:00
400622760f Enable Travis build of D-Bus interface
By default the D-Bus interface is not enabled, so in order to get it to
build in Travis, it must be enabled explicitly. This installs the
packages needed and sets the configure flag.

Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
2019-04-15 18:41:47 +03:00
b7b455a38c 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>
2019-04-15 18:41:47 +03:00
fa8e2ced19 Fix "ipmitool pef {status,info}" not printing final newline
Signed-off-by: Vaclav Dolezal <vdolezal@redhat.com>
2019-04-01 18:00:31 +03:00
17 changed files with 1269 additions and 311 deletions

View File

@ -1,9 +1,36 @@
language: C
sudo: enabled
before_install:
- sudo apt-get install -y libssl-dev
before_script:
- ./bootstrap
addons:
apt:
update: true
packages:
- libssl-dev
homebrew:
packages:
- openssl
matrix:
include:
- os: linux
dist: xenial
addons:
apt:
packages:
- libsystemd-dev
script:
- ./configure --enable-intf-dummy --enable-intf-dbus
- make
- sudo make install
- os: linux
dist: trusty
script:
- ./configure --enable-intf-dummy
- make
- sudo make install
- os: osx
osx_image: xcode10.2
script:
- ./configure --enable-intf-dummy
- make

32
INSTALL
View File

@ -9,17 +9,33 @@ are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is,
without warranty of any kind.
Prerequisites
=============
This project requires at least gcc 4.8.1 as it uses some GNU
extensions and some C11 features. For `lanplus` interface the OpenSSL
library and development headers are required. As of April 2019, the
project is tested automatically to build cleanly for the following
64-bit operating systems:
- Ubuntu 14.04 Trusty
- Ubuntu 16.04 Xenial
- MacOS X 10.14 (Xcode 10.2)
Basic Installation
==================
Briefly, the shell command `./configure && make && make install'
should configure, build, and install this package. The following
more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
`INSTALL' file but do not implement all of the features documented
below. The lack of an optional feature in a given package is not
necessarily a bug. More recommendations for GNU packages can be found
in *note Makefile Conventions: (standards)Makefile Conventions.
Briefly, the followong shell command should configure, build, and
install this package:
`./bootstrap && ./configure && make && make install`
The following more-detailed instructions are generic; see the
`README' file for instructions specific to this package. Some
packages provide this `INSTALL' file but do not implement all of the
features documented below. The lack of an optional feature in a given
package is not necessarily a bug. More recommendations for GNU
packages can be found in *note Makefile Conventions:
(standards)Makefile Conventions.
The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses

View File

@ -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],
@ -643,6 +671,25 @@ AC_TRY_COMPILE([],[
[Define to 1 if you need to use #pragma pack instead of __attribute__ ((packed))])]
)
dnl if no environment variable is set, set the default value for the default intf
if test "${xenable_intf_open}" = "xyes"; then
DEFAULT_INTF_NO_ENV=open
else dnl macOS does not build open interface, it defaults to lan
DEFAULT_INTF_NO_ENV=lan
fi
dnl allow for a default interface to be set on configure
AC_ARG_VAR(DEFAULT_INTF, [Set the default interface to use (default=${DEFAULT_INTF_NO_ENV})])
dnl set the default value for the default interface environment variable
if test "x${DEFAULT_INTF}" == "x"; then
echo "DEFAULT_INTF not found in environment; setting to ${DEFAULT_INTF_NO_ENV}"
DEFAULT_INTF=${DEFAULT_INTF_NO_ENV}
fi
xdefault_intf_is_enabled="xenable_intf_${DEFAULT_INTF}"
if test "x${!xdefault_intf_is_enabled}" != "xyes"; then
AC_MSG_ERROR([** Cannot set ${DEFAULT_INTF} as default; ${DEFAULT_INTF} is not enabled. :${!xdefault_intf_is_enabled}:])
fi
dnl Generate files for build
AC_CONFIG_FILES([Makefile
@ -664,6 +711,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
@ -674,13 +722,14 @@ AC_OUTPUT
AC_MSG_RESULT([])
AC_MSG_RESULT([ipmitool $VERSION])
AC_MSG_RESULT([])
AC_MSG_RESULT([Interfaces])
AC_MSG_RESULT([Interfaces (default=$DEFAULT_INTF)])
AC_MSG_RESULT([ lan : $xenable_intf_lan])
AC_MSG_RESULT([ lanplus : $xenable_intf_lanplus])
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])

View File

@ -1,7 +1,8 @@
[Unit]
Description=Exchange Information between BMC and OS
After=ipmi.service network.target
Requires=ipmi.service
After=network.target
AssertFileIsExecutable=/usr/bin/ipmitool
AssertPathExistsGlob=/dev/ipmi*
[Service]
Type=oneshot

View File

@ -384,39 +384,23 @@ application (ipmi or sol) on the given channel.
\fIstatus\fP
Status information related to power, buttons, cooling, drives and faults.
.RS
.RE
.TP
\fIpower\fP
.RS
.TP
\fIstatus\fP
.RS
.RE
.TP
\fIon\fP
.RS
.RE
.TP
\fIoff\fP
.RS
.RE
.TP
\fIcycle\fP
.RS
.RE
.TP
\fIreset\fP
.RS
.RE
.TP
\fIdiag\fP
.RS
.RE
.TP
\fIsoft\fP
.RS
.RE
.RE
.TP
\fIidentify\fP [<seconds>|force]
@ -428,8 +412,6 @@ Default is 15 seconds.
0 - Off
.br
force - To turn on indefinitely
.RS
.RE
.TP
\fIpolicy\fP
@ -439,34 +421,22 @@ What to do when power is restored.
\fIlist\fP
Show available options.
.RS
.RE
.TP
\fIalways-on\fP
.RS
.RE
.TP
\fIprevious\fP
.RS
.RE
.TP
\fIalways-off\fP
.RS
.RE
.RE
.TP
\fIrestart_cause\fP
Last restart cause.
.RS
.RE
.TP
\fIpoh\fP
Get power on hours.
.RS
.RE
.TP
\fIbootdev\fP
.RS
@ -474,95 +444,123 @@ Get power on hours.
\fInone\fP
Do not change boot device order.
.RS
.RE
.TP
\fIpxe\fP
Force PXE boot.
.RS
.RE
.TP
\fIdisk\fP
Force boot from default Hard-drive.
.RS
.RE
.TP
\fIsafe\fP
Force boot from default Hard-drive, request Safe Mode.
.RS
.RE
.TP
\fIdiag\fP
Force boot from Diagnostic Partition.
.RS
.RE
.TP
\fIcdrom\fP
Force boot from CD/DVD.
.RS
.RE
.TP
\fIbios\fP
Force boot into BIOS Setup.
.RS
.RE
.TP
\fIfloppy\fP
Force boot from Floppy/primary removable media.
.RS
.RE
.RE
.TP
\fIbootparam\fP
\fIbootmbox\fP \fIget\fP [text] [block <\fBblock#\fP>]
Read the Boot Initiator Mailbox in hex dump or in text mode.
By default the whole mailbox is read. If block number is specified,
that particular block is read. For block 0 or when the whole
mailbox is read, the Boot Initiator IANA Enterprise Number and
the corresponding enterprise name are printed.
.TP
\fIbootmbox\fP \fIset\fP text [block <\fBblock#\fP>] <\fBIANA_PEN\fP> "<\fBdata_string\fP>"
Write the specified <block> or the entire Boot Initiator Mailbox in text mode.
It is required to specify a decimal IANA Enterprise Number recognized
by the boot initiator on the target system. Refer to your target system
manufacturer for details. The rest of the arguments are a text string.
When single block write is requested, the total length of <data> may not
exceed 13 bytes for block 0, or 16 bytes otherwise.
.TP
\fIbootmbox\fP \fIset\fP [block <\fBblock#\fP>] <\fBIANA_PEN\fP> <\fBdata_byte\fP> [<\fBdata_byte\fP> ...]
Same as above, but the arguments after IANA PEN are separate
data byte values separated by spaces.
.TP
\fIbootparam\fP \fIget\fP <\fBopt_id\fR> [<\fBopt_param\fR>]
Get value of system boot option number <\fBopt_id\fR>. Some boot
options (e.g. option 7) can also take an optional numeric parameter.
.TP
\fIbootparam\fP \fIset\fP bootflag <\fBdevice\fR> [options=...]
Set a boot flag. Valid devices are:
.RS
.TP
\fIforce_pxe\fP
.IP \fIforce_pxe\fP
Force PXE boot
.RS
.RE
.TP
\fIforce_disk\fP
.IP \fIforce_disk\fP
Force boot from default Hard-drive
.RS
.RE
.TP
\fIforce_safe\fP
.IP \fIforce_safe\fP
Force boot from default Hard-drive, request Safe Mode
.RS
.RE
.TP
\fIforce_diag\fP
.IP \fIforce_diag\fP
Force boot from Diagnostic Partition
.RS
.RE
.TP
\fIforce_cdrom\fP
.IP \fIforce_cdrom\fP
Force boot from CD/DVD
.RS
.RE
.TP
\fIforce_bios\fP
.IP \fIforce_bios\fP
Force boot into BIOS Setup
.RS
.RE
.PP
Valid options are:
.IP \fIPEF\fP
Clear valid bit on reset/power cycle cause by PEF
.IP \fItimeout\fP
Automatically clear boot flag valid bit on timeout
.IP \fIwatchdog\fP
Clear valid bit on reset/power cycle cause by watchdog
.IP \fIreset\fP
Clear valid bit on push button reset/soft reset
.IP \fIpower\fP
Clear valid bit on power up via power push button or wake event
.RE
.TP
\fIselftest\fP
.RS
.RE
Get the chassis self-test results
.RE
.TP
\fIdcmi\fP
@ -957,8 +955,6 @@ Shows Extended SD Card information.
\fIecho\fP
For echoing lines to stdout in scripts.
.RS
.RE
.TP
\fIekanalyzer\fP <\fBcommand\fR> <\fBxx=filename1\fR> <\fBxx=filename2\fR> [<\fBrc=filename3\fR>] \fB...\fR
.RS
@ -1510,20 +1506,14 @@ Show firmware upgrade log.
\fIlist\fP
List All Generic Device Locators.
.RS
.RE
.TP
\fIread\fP <\fBsdr name\fR> <\fBfile\fR>
Read to file eeprom specify by Generic Device Locators.
.RS
.RE
.TP
\fIwrite\fP <\fBsdr name\fR> <\fBfile\fR>
Write from file eeprom specify by Generic Device Locators
.RS
.RE
.RE
.TP
\fIhpm\fP
@ -3150,50 +3140,34 @@ or by using the keyword `all' to specify all sessions.
\fIhostname\fP <\fBhost\fR>
Session hostname.
.RS
.RE
.TP
\fIusername\fP <\fBuser\fR>
Session username.
.RS
.RE
.TP
\fIpassword\fP <\fBpass\fR>
Session password.
.RS
.RE
.TP
\fIprivlvl\fP <\fBlevel\fR>
Session privilege level force.
.RS
.RE
.TP
\fIauthtype\fP <\fBtype\fR>
Authentication type force.
.RS
.RE
.TP
\fIlocaladdr\fP <\fBaddr\fR>
Local IPMB address.
.RS
.RE
.TP
\fItargetaddr\fP <\fBaddr\fR>
Remote target IPMB address.
.RS
.RE
.TP
\fIport\fP <\fBport\fR>
Remote RMCP port.
.RS
.RE
.TP
\fIcsv\fP [\fBlevel\fR]
@ -3201,14 +3175,10 @@ Enable output in comma separated format.
Affects following commands:
\fIuser\fP, \fIchannel\fP, \fIisol\fP, \fIsunoem\fP,
\fIsol\fP, \fIsensor\fP, \fIsdr\fP, \fIsel\fP, \fIsession\fP.
.RS
.RE
.TP
\fIverbose\fP [\fBverbose\fR]
Verbosity level.
.RS
.RE
.RE
.TP
\fIshell\fP

View File

@ -38,6 +38,7 @@
#include <stdio.h>
#include <string.h>
#include <stdlib.h> /* For free() */
#include <stdbool.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@ -79,6 +80,10 @@ struct oemvalstr {
const char * str;
};
const char *
specific_val2str(uint16_t val,
const struct valstr *specific,
const struct valstr *generic);
const char * val2str(uint16_t val, const struct valstr * vs);
const char * oemval2str(uint32_t oem,uint16_t val, const struct oemvalstr * vs);
@ -92,6 +97,8 @@ int str2ushort(const char * str, uint16_t * ushrt_ptr);
int str2char(const char * str, int8_t * chr_ptr);
int str2uchar(const char * str, uint8_t * uchr_ptr);
bool args2buf(int argc, char *argv[], uint8_t *out, size_t len);
int eval_ccode(const int ccode);
int is_fru_id(const char *argv_ptr, uint8_t *fru_id_ptr);
@ -166,6 +173,13 @@ static inline uint32_t ipmi24toh(void *ipmi24)
return h;
}
static inline void htoipmi24(uint32_t h, uint8_t *ipmi)
{
ipmi[0] = h & 0xFF; /* LSB */
ipmi[1] = (h >> 8) & 0xFF;
ipmi[2] = (h >> 16) & 0xFF; /* MSB */
}
static inline uint32_t ipmi32toh(void *ipmi32)
{
uint8_t *ipmi = ipmi32;

View File

@ -37,6 +37,7 @@
# include <config.h>
#endif
#include <stdbool.h>
#include <inttypes.h>
#include <math.h>
#include <ipmitool/bswap.h>
@ -381,6 +382,29 @@ struct sdr_record_common_sensor {
struct sdr_record_mask mask;
/* IPMI 2.0, Table 43-1, byte 21[7:6] Analog (numeric) Data Format */
#define SDR_UNIT_FMT_UNSIGNED 0 /* unsigned */
#define SDR_UNIT_FMT_1S_COMPL 1 /* 1's complement (signed) */
#define SDR_UNIT_FMT_2S_COMPL 2 /* 2's complement (signed) */
#define SDR_UNIT_FMT_NA 3 /* does not return analog (numeric) reading */
/* IPMI 2.0, Table 43-1, byte 21[5:3] Rate */
#define SDR_UNIT_RATE_NONE 0 /* none */
#define SDR_UNIT_RATE_MICROSEC 1 /* per us */
#define SDR_UNIT_RATE_MILLISEC 2 /* per ms */
#define SDR_UNIT_RATE_SEC 3 /* per s */
#define SDR_UNIT_RATE_MIN 4 /* per min */
#define SDR_UNIT_RATE_HR 5 /* per hour */
#define SDR_UNIT_RATE_DAY 6 /* per day */
#define SDR_UNIT_RATE_RSVD 7 /* reserved */
/* IPMI 2.0, Table 43-1, byte 21[2:1] Modifier Unit */
#define SDR_UNIT_MOD_NONE 0 /* none */
#define SDR_UNIT_MOD_DIV 1 /* Basic Unit / Modifier Unit */
#define SDR_UNIT_MOD_MUL 2 /* Basic Unit * Mofifier Unit */
#define SDR_UNIT_MOD_RSVD 3 /* Reserved */
/* IPMI 2.0, Table 43-1, byte 21[0] Percentage */
#define SDR_UNIT_PCT_NO 0
#define SDR_UNIT_PCT_YES 1
struct {
#if WORDS_BIGENDIAN
uint8_t analog:2;
@ -394,8 +418,8 @@ struct sdr_record_common_sensor {
uint8_t analog:2;
#endif
struct {
uint8_t base;
uint8_t modifier;
uint8_t base; /* Base unit type code per IPMI 2.0 Table 43-15 */
uint8_t modifier; /* Modifier unit type code per Table 43-15 */
} ATTRIBUTE_PACKING type;
} ATTRIBUTE_PACKING unit;
} ATTRIBUTE_PACKING;
@ -833,7 +857,7 @@ void ipmi_sdr_print_sensor_hysteresis(struct sdr_record_common_sensor *sensor,
struct sdr_record_full_sensor *full,
uint8_t hysteresis_value,
const char *hdrstr);
const char *ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type,
const char *ipmi_sdr_get_unit_string(bool pct, uint8_t type,
uint8_t base, uint8_t modifier);
struct sensor_reading *
ipmi_sdr_read_sensor_value(struct ipmi_intf *intf,

View File

@ -67,7 +67,9 @@ parse_pen_list() {
}
END {
if(PEN) {
print "{ " PEN ", \"" ENTERPRISE "\" },"
}
}'
}

View File

@ -319,26 +319,74 @@ mac2str(const uint8_t *buf)
return buf2str_extended(buf, 6, ":");
}
const char * val2str(uint16_t val, const struct valstr *vs)
/**
* Find the index of value in a valstr array
*
* @param[in] val The value to search for
* @param[in] vs The valstr array to search in
* @return >=0 The index into \p vs
* @return -1 Error: value \p val was not found in \p vs
*/
static
inline
off_t find_val_idx(uint16_t val, const struct valstr *vs)
{
static char un_str[32];
int i;
for (i = 0; vs[i].str; i++) {
if (vs[i].val == val)
return vs[i].str;
if (vs) {
for (off_t i = 0; vs[i].str; ++i) {
if (vs[i].val == val) {
return i;
}
}
}
return -1;
}
/**
* Generate a statically allocated 'Unknown' string for the provided value.
* The function is not thread-safe (as most of ipmitool).
*
* @param[in] val The value to put into the string
* @returns A pointer to a statically allocated string
*/
static
inline
const char *unknown_val_str(uint16_t val)
{
static char un_str[32];
memset(un_str, 0, 32);
snprintf(un_str, 32, "Unknown (0x%02X)", val);
return un_str;
}
const char *
specific_val2str(uint16_t val,
const struct valstr *specific,
const struct valstr *generic)
{
int i;
if (0 <= (i = find_val_idx(val, specific))) {
return specific[i].str;
}
if (0 <= (i = find_val_idx(val, generic))) {
return generic[i].str;
}
return unknown_val_str(val);
}
const char * val2str(uint16_t val, const struct valstr *vs)
{
return specific_val2str(val, NULL, vs);
}
const char * oemval2str(uint32_t oem, uint16_t val,
const struct oemvalstr *vs)
{
static char un_str[32];
int i;
for (i = 0; vs[i].oem != 0xffffff && vs[i].str; i++) {
@ -349,10 +397,7 @@ const char * oemval2str(uint32_t oem, uint16_t val,
}
}
memset(un_str, 0, 32);
snprintf(un_str, 32, "Unknown (0x%X)", val);
return un_str;
return unknown_val_str(val);
}
/* str2double - safely convert string to double
@ -1080,3 +1125,35 @@ ipmi_get_oem_id(struct ipmi_intf *intf)
return oem_id;
}
/** Parse command line arguments as numeric byte values (dec or hex)
* and store them in a \p len sized buffer \p out.
*
* @param[in] argc Number of arguments
* @param[in] argv Array of arguments
* @param[out] out The output buffer
* @param[in] len Length of the output buffer in bytes (no null-termination
* is assumed, the input data is treated as raw byte values,
* not as a string.
*
* @returns A success status indicator
* @return false Error
* @return true Success
*/
bool
args2buf(int argc, char *argv[], uint8_t *out, size_t len)
{
size_t i;
for (i = 0; i < len && i < (size_t)argc; ++i) {
uint8_t byte;
if (str2uchar(argv[i], &byte)) {
lprintf(LOG_ERR, "Bad byte value: %s", argv[i]);
return false;
}
out[i] = byte;
}
return true;
}

View File

@ -34,6 +34,8 @@
#include <string.h>
#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <limits.h>
#include <ipmitool/bswap.h>
#include <ipmitool/helper.h>
@ -44,8 +46,40 @@
#include <ipmitool/ipmi_chassis.h>
#include <ipmitool/ipmi_time.h>
#define CHASSIS_BOOT_MBOX_IANA_SZ 3
#define CHASSIS_BOOT_MBOX_BLOCK_SZ 16
#define CHASSIS_BOOT_MBOX_BLOCK0_SZ \
(CHASSIS_BOOT_MBOX_BLOCK_SZ - CHASSIS_BOOT_MBOX_IANA_SZ)
#define CHASSIS_BOOT_MBOX_MAX_BLOCK 0xFF
#define CHASSIS_BOOT_MBOX_MAX_BLOCKS (CHASSIS_BOOT_MBOX_MAX_BLOCK + 1)
typedef struct {
uint8_t iana[CHASSIS_BOOT_MBOX_IANA_SZ];
uint8_t data[CHASSIS_BOOT_MBOX_BLOCK0_SZ];
} mbox_b0_data_t;
typedef struct {
uint8_t block;
union {
uint8_t data[CHASSIS_BOOT_MBOX_BLOCK_SZ];
mbox_b0_data_t b0;
};
} mbox_t;
extern int verbose;
static const struct valstr get_bootparam_cc_vals[] = {
{ 0x80, "Unsupported parameter" },
{ 0x00, NULL }
};
static const struct valstr set_bootparam_cc_vals[] = {
{ 0x80, "Unsupported parameter" },
{ 0x81, "Attempt to set 'in progress' while not in 'complete' state" },
{ 0x82, "Parameter is read-only" },
{ 0x00, NULL }
};
int
ipmi_chassis_power_status(struct ipmi_intf * intf)
{
@ -446,61 +480,166 @@ ipmi_chassis_selftest(struct ipmi_intf * intf)
}
static int
ipmi_chassis_set_bootparam(struct ipmi_intf * intf, uint8_t param, uint8_t * data, int len)
ipmi_chassis_set_bootparam(struct ipmi_intf * intf,
uint8_t param, void *data, int len)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
uint8_t msg_data[16];
struct {
uint8_t param;
uint8_t data[];
} *msg_data;
int rc = -1;
size_t msgsize = 1 + len; /* Single-byte parameter plus the data */
static const uint8_t BOOTPARAM_MASK = 0x7F;
memset(msg_data, 0, 16);
msg_data[0] = param & 0x7f;
memcpy(msg_data+1, data, len);
msg_data = malloc(msgsize);
if (!msg_data) {
goto out;
}
memset(msg_data, 0, msgsize);
msg_data->param = param & BOOTPARAM_MASK;
memcpy(msg_data->data, data, len);
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_CHASSIS;
req.msg.cmd = 0x8;
req.msg.data = msg_data;
req.msg.data_len = len + 1;
req.msg.data = (uint8_t *)msg_data;
req.msg.data_len = msgsize;
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param);
return -1;
}
if (rsp->ccode) {
rc = rsp->ccode;
if (rc) {
if (param != 0) {
lprintf(LOG_ERR, "Set Chassis Boot Parameter %d failed: %s",
param, val2str(rsp->ccode, completion_code_vals));
lprintf(LOG_ERR,
"Set Chassis Boot Parameter %d failed: %s",
param,
specific_val2str(rsp->ccode,
set_bootparam_cc_vals,
completion_code_vals));
}
return -1;
goto out;
}
lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len));
return 0;
out:
free_n(&msg_data);
return rc;
}
/* Flags to ipmi_chassis_get_bootparam() */
typedef enum {
PARAM_NO_GENERIC_INFO, /* Do not print generic boot parameter info */
PARAM_NO_DATA_DUMP, /* Do not dump parameter data */
PARAM_NO_RANGE_ERROR, /* Do not report out of range info to user */
PARAM_SPECIFIC /* Parameter-specific flags start with this */
} chassis_bootparam_flags_t;
/* Flags to ipmi_chassis_get_bootparam() for Boot Mailbox parameter (7) */
typedef enum {
MBOX_PARSE_USE_TEXT = PARAM_SPECIFIC, /* Use text output vs. hex */
MBOX_PARSE_ALLBLOCKS /* Parse all blocks, not just one */
} chassis_bootmbox_parse_t;
#define BP_FLAG(x) (1 << (x))
static
void
chassis_bootmailbox_parse(void *buf, size_t len, int flags)
{
void *blockdata;
size_t datalen;
bool use_text = flags & BP_FLAG(MBOX_PARSE_USE_TEXT);
bool all_blocks = flags & BP_FLAG(MBOX_PARSE_ALLBLOCKS);
mbox_t *mbox;
if (!buf || !len) {
return;
}
mbox = buf;
blockdata = mbox->data;
datalen = len - sizeof(mbox->block);
if (!all_blocks) {
/* Print block selector only if a single block is printed */
printf(" Selector : %d\n", mbox->block);
}
if (!mbox->block) {
uint32_t iana = ipmi24toh(mbox->b0.iana);
/* For block zero print the IANA Private Enterprise Number */
printf(" IANA PEN : %" PRIu32 " [%s]\n",
iana,
val2str(iana, ipmi_oem_info));
blockdata = mbox->b0.data;
datalen -= sizeof(mbox->b0.iana);
}
printf(" Block ");
if (all_blocks) {
printf("%3" PRIu8 " Data : ", mbox->block);
}
else {
printf("Data : ");
}
if (use_text) {
/* Ensure the data string is null-terminated */
unsigned char text[CHASSIS_BOOT_MBOX_BLOCK_SZ + 1] = { 0 };
memcpy(text, blockdata, datalen);
printf("'%s'\n", text);
}
else {
printf("%s\n", buf2str(blockdata, datalen));
}
}
static int
ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
ipmi_chassis_get_bootparam(struct ipmi_intf * intf,
int argc, char *argv[], int flags)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
uint8_t msg_data[3];
uint8_t param_id = 0;
bool skip_generic = flags & BP_FLAG(PARAM_NO_GENERIC_INFO);
bool skip_data = flags & BP_FLAG(PARAM_NO_DATA_DUMP);
bool skip_range = flags & BP_FLAG(PARAM_NO_RANGE_ERROR);
int rc = -1;
if (!arg)
return -1;
if (str2uchar(arg, &param_id) != 0) {
lprintf(LOG_ERR, "Invalid parameter '%s' given instead of bootparam.",
arg);
return (-1);
if (argc < 1 || !argv[0]) {
goto out;
}
if (str2uchar(argv[0], &param_id)) {
lprintf(LOG_ERR,
"Invalid parameter '%s' given instead of bootparam.",
argv[0]);
goto out;
}
--argc;
++argv;
memset(msg_data, 0, 3);
msg_data[0] = param_id & 0x7f;
msg_data[1] = 0;
msg_data[2] = 0;
if (argc) {
if (str2uchar(argv[0], &msg_data[1])) {
lprintf(LOG_ERR,
"Invalid argument '%s' given to"
" bootparam %" PRIu8,
argv[0], msg_data[1]);
goto out;
}
}
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_CHASSIS;
@ -510,12 +649,21 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
lprintf(LOG_ERR, "Error Getting Chassis Boot Parameter %s", arg);
lprintf(LOG_ERR,
"Error Getting Chassis Boot Parameter %" PRIu8,
msg_data[0]);
return -1;
}
if (IPMI_CC_PARAM_OUT_OF_RANGE == rsp->ccode && skip_range) {
return -1;
}
if (rsp->ccode) {
lprintf(LOG_ERR, "Get Chassis Boot Parameter %s failed: %s",
arg, val2str(rsp->ccode, completion_code_vals));
lprintf(LOG_ERR,
"Get Chassis Boot Parameter %" PRIu8 " failed: %s",
msg_data[0],
specific_val2str(rsp->ccode,
get_bootparam_cc_vals,
completion_code_vals));
return -1;
}
@ -525,10 +673,17 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
param_id = 0;
param_id = (rsp->data[1] & 0x7f);
if (!skip_generic) {
printf("Boot parameter version: %d\n", rsp->data[0]);
printf("Boot parameter %d is %s\n", rsp->data[1] & 0x7f,
(rsp->data[1] & 0x80) ? "invalid/locked" : "valid/unlocked");
printf("Boot parameter data: %s\n", buf2str(rsp->data+2, rsp->data_len - 2));
(rsp->data[1] & 0x80)
? "invalid/locked"
: "valid/unlocked");
if (!skip_data) {
printf("Boot parameter data: %s\n",
buf2str(rsp->data+2, rsp->data_len - 2));
}
}
switch(param_id)
{
@ -716,17 +871,18 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
}
break;
case 7:
{
printf(" Selector : %d\n", rsp->data[2] );
printf(" Block Data : %s\n", buf2str(rsp->data+3, rsp->data_len - 2));
}
chassis_bootmailbox_parse(rsp->data + 2,
rsp->data_len - 2,
flags);
break;
default:
printf(" Undefined byte\n");
printf(" Unsupported parameter %" PRIu8 "\n", param_id);
break;
}
return 0;
rc = IPMI_CC_OK;
out:
return rc;
}
static int
@ -832,7 +988,10 @@ ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
}
if (rsp->ccode) {
lprintf(LOG_ERR, "Get Chassis Boot Parameter %d failed: %s",
param_id, val2str(rsp->ccode, completion_code_vals));
param_id,
specific_val2str(rsp->ccode,
get_bootparam_cc_vals,
completion_code_vals));
return -1;
}
@ -842,77 +1001,97 @@ ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
return(rsp->data[2]);
}
typedef enum {
SET_COMPLETE,
SET_IN_PROGRESS,
COMMIT_WRITE,
RESERVED
} progress_t;
static
void
chassis_bootparam_set_in_progress(struct ipmi_intf *intf, progress_t progress)
{
/*
* By default try to set/clear set-in-progress parameter before/after
* changing any boot parameters. If setting fails, the code will set
* this flag to false and stop trying to fiddle with it for future
* requests.
*/
static bool use_progress = true;
uint8_t flag = progress;
int rc;
if (!use_progress) {
return;
}
rc = ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
&flag, 1);
/*
* Only disable future checks if set in progress status setting failed.
* Setting of other statuses may fail legitimately.
*/
if (rc && SET_IN_PROGRESS == progress) {
use_progress = false;
}
}
typedef enum {
BIOS_POST_ACK = 1 << 0,
OS_LOADER_ACK = 1 << 1,
OS_SERVICE_PARTITION_ACK = 1 << 2,
SMS_ACK = 1 << 3,
OEM_ACK = 1 << 4,
RESERVED_ACK_MASK = 7 << 5
} bootinfo_ack_t;
static
int
chassis_bootparam_clear_ack(struct ipmi_intf *intf, bootinfo_ack_t flag)
{
uint8_t flags[2] = { flag & ~RESERVED_ACK_MASK,
flag & ~RESERVED_ACK_MASK };
return ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
flags, 2);
}
static int
ipmi_chassis_set_bootvalid(struct ipmi_intf *intf, uint8_t set_flag, uint8_t clr_flag)
{
int bootvalid;
uint8_t flags[5];
int rc = 0;
int use_progress = 1;
uint8_t param_id = IPMI_CHASSIS_BOOTPARAM_FLAG_VALID;
uint8_t flags[2];
int rc;
if (use_progress) {
/* set set-in-progress flag */
memset(flags, 0, 5);
flags[0] = 0x01;
rc = ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, flags, 1);
if (rc < 0)
use_progress = 0;
}
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS);
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK);
memset(flags, 0, 5);
flags[0] = 0x01;
flags[1] = 0x01;
rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
flags, 2);
if (rc < 0) {
if (use_progress) {
/* set-in-progress = set-complete */
memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
return -1;
if (rc) {
goto out;
}
bootvalid = ipmi_chassis_get_bootvalid(intf);
if (bootvalid < 0) {
if (use_progress) {
/* set-in-progress = set-complete */
memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
return -1;
lprintf(LOG_ERR, "Failed to read boot valid flag");
rc = bootvalid;
goto out;
}
flags[0] = (bootvalid & ~clr_flag) | set_flag;
rc = ipmi_chassis_set_bootparam(intf, param_id, flags, 1);
if (rc == 0) {
if (use_progress) {
/* set-in-progress = commit-write */
memset(flags, 0, 5);
flags[0] = 0x02;
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
}
if (use_progress) {
/* set-in-progress = set-complete */
memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
rc = ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_FLAG_VALID,
flags, 1);
if (IPMI_CC_OK == rc) {
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE);
}
out:
chassis_bootparam_set_in_progress(intf, SET_COMPLETE);
return rc;
}
@ -920,38 +1099,17 @@ static int
ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags)
{
uint8_t flags[5];
int rc = 0;
int use_progress = 1;
int rc;
if (use_progress) {
/* set set-in-progress flag */
memset(flags, 0, 5);
flags[0] = 0x01;
rc = ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS, flags, 1);
if (rc < 0)
use_progress = 0;
}
memset(flags, 0, 5);
flags[0] = 0x01;
flags[1] = 0x01;
rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_INFO_ACK,
flags, 2);
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS);
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK);
if (rc < 0) {
if (use_progress) {
/* set-in-progress = set-complete */
memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
return -1;
goto out;
}
if (!iflags)
memset(flags, 0, 5);
memset(flags, 0, sizeof(flags));
else
memcpy(flags, iflags, sizeof (flags));
@ -982,45 +1140,316 @@ ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags)
flags[1] |= 0x18;
else {
lprintf(LOG_ERR, "Invalid argument: %s", arg);
if (use_progress) {
/* set-in-progress = set-complete */
memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
return -1;
rc = -1;
goto out;
}
/* set flag valid bit */
flags[0] |= 0x80;
rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_BOOT_FLAGS,
rc = ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_BOOT_FLAGS,
flags, 5);
if (rc == 0) {
if (use_progress) {
/* set-in-progress = commit-write */
memset(flags, 0, 5);
flags[0] = 0x02;
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
if (IPMI_CC_OK == rc) {
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE);
printf("Set Boot Device to %s\n", arg);
}
if (use_progress) {
/* set-in-progress = set-complete */
memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
out:
chassis_bootparam_set_in_progress(intf, SET_COMPLETE);
return rc;
}
static void chassis_bootmailbox_help()
{
lprintf(LOG_NOTICE,
"bootmbox get [text] [block <block>]\n"
" Read the entire Boot Initiator Mailbox or the specified <block>.\n"
" If 'text' option is specified, the data is output as plain text, otherwise\n"
" hex dump mode is used.\n"
"\n"
"bootmbox set text [block <block>] <IANA_PEN> \"<data_string>\"\n"
"bootmbox set [block <block>] <IANA_PEN> <data_byte> [<data_byte> ...]\n"
" Write the specified <block> or the entire Boot Initiator Mailbox.\n"
" It is required to specify a decimal IANA Enterprise Number recognized\n"
" by the boot initiator on the target system. Refer to your target system\n"
" manufacturer for details. The rest of the arguments are either separate\n"
" data byte values separated by spaces, or a single text string argument.\n"
"\n"
" When single block write is requested, the total length of <data> may not\n"
" exceed 13 bytes for block 0, or 16 bytes otherwise.\n"
"\n"
"bootmbox help\n"
" Show this help.");
}
static
int
chassis_set_bootmailbox(struct ipmi_intf *intf, int16_t block, bool use_text,
int argc, char *argv[])
{
int rc = -1;
int32_t iana = 0;
size_t blocks = 0;
size_t datasize = 0;
off_t string_offset = 0;
lprintf(LOG_INFO, "Writing Boot Mailbox...");
if (argc < 1 || str2int(argv[0], &iana)) {
lprintf(LOG_ERR,
"No valid IANA PEN specified!\n");
chassis_bootmailbox_help();
goto out;
}
++argv;
--argc;
if (argc < 1) {
lprintf(LOG_ERR,
"No data provided!\n");
chassis_bootmailbox_help();
goto out;
}
/*
* Initialize the data size. For text mode it is just the
* single argument string length plus one byte for \0 termination.
* For byte mode the length is the number of byte arguments without
* any additional termination.
*/
if (!use_text) {
datasize = argc;
}
else {
datasize = strlen(argv[0]) + 1; /* Include the terminator */
}
lprintf(LOG_INFO, "Data size: %u", datasize);
/* Decide how many blocks we will be writing */
if (block >= 0) {
blocks = 1;
}
else {
/*
* We need to write all data, so calculate the data
* size in blocks and set the starting block to zero.
*/
blocks = datasize;
blocks += CHASSIS_BOOT_MBOX_BLOCK_SZ - 1;
blocks /= CHASSIS_BOOT_MBOX_BLOCK_SZ;
block = 0;
}
lprintf(LOG_INFO, "Blocks to write: %d", blocks);
if (blocks > CHASSIS_BOOT_MBOX_MAX_BLOCKS) {
lprintf(LOG_ERR,
"Data size %zu exceeds maximum (%d)",
datasize,
(CHASSIS_BOOT_MBOX_BLOCK_SZ
* CHASSIS_BOOT_MBOX_MAX_BLOCKS)
- CHASSIS_BOOT_MBOX_IANA_SZ);
goto out;
}
/* Indicate that we're touching the boot parameters */
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS);
for (size_t bindex = 0;
datasize > 0 && bindex < blocks;
++bindex, ++block)
{
/* The request data structure */
mbox_t mbox = { .block = block, {{0}} };
/* Destination for input data */
uint8_t *data = mbox.data;
/* The maximum amount of data this block may hold */
size_t maxblocksize = sizeof(mbox.data);
/* The actual amount of data in this block */
size_t blocksize;
off_t unused = 0;
/* Block 0 needs special care as it has IANA PEN specifier */
if (!block) {
data = mbox.b0.data;
maxblocksize = sizeof(mbox.b0.data);
htoipmi24(iana, mbox.b0.iana);
}
/*
* Find out how many bytes we are going to write to this
* block.
*/
if (datasize > maxblocksize) {
blocksize = maxblocksize;
}
else {
blocksize = datasize;
}
/* Remember how much data remains */
datasize -= blocksize;
if (!use_text) {
args2buf(argc, argv, data, blocksize);
argc -= blocksize;
argv += blocksize;
}
else {
memcpy(data, argv[0] + string_offset, blocksize);
string_offset += blocksize;
}
lprintf(LOG_INFO, "Block %3" PRId16 ": %s", block,
buf2str_extended(data, blocksize, " "));
unused = maxblocksize - blocksize;
rc = ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_INIT_MBOX,
&mbox,
sizeof(mbox) - unused);
if (IPMI_CC_PARAM_OUT_OF_RANGE == rc) {
lprintf(LOG_ERR,
"Hit end of mailbox writing block %" PRId16,
block);
}
if (rc) {
goto complete;
}
}
lprintf(LOG_INFO,
"Wrote %zu blocks of Boot Initiator Mailbox",
blocks);
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE);
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK | OS_LOADER_ACK);
complete:
chassis_bootparam_set_in_progress(intf, SET_COMPLETE);
out:
return rc;
}
static
int
chassis_get_bootmailbox(struct ipmi_intf *intf,
int16_t block, bool use_text)
{
int rc = IPMI_CC_UNSPECIFIED_ERROR;
char param_str[2]; /* Max "7" */
char block_str[4]; /* Max "255" */
char *bpargv[] = { param_str, block_str };
int flags;
flags = use_text ? BP_FLAG(MBOX_PARSE_USE_TEXT) : 0;
snprintf(param_str, sizeof(param_str),
"%" PRIu8, IPMI_CHASSIS_BOOTPARAM_INIT_MBOX);
if (block >= 0) {
snprintf(block_str, sizeof(block_str),
"%" PRIu8, (uint8_t)block);
rc = ipmi_chassis_get_bootparam(intf,
ARRAY_SIZE(bpargv),
bpargv,
flags);
}
else {
int currblk;
flags |= BP_FLAG(MBOX_PARSE_ALLBLOCKS);
for (currblk = 0; currblk <= UCHAR_MAX; ++currblk) {
snprintf(block_str, sizeof(block_str),
"%" PRIu8, (uint8_t)currblk);
if (currblk) {
/*
* If block 0 succeeded, we don't want to
* print generic info for each next block,
* and we don't want range error to be
* reported when we hit the end of blocks.
*/
flags |= BP_FLAG(PARAM_NO_GENERIC_INFO);
flags |= BP_FLAG(PARAM_NO_RANGE_ERROR);
}
rc = ipmi_chassis_get_bootparam(intf,
ARRAY_SIZE(bpargv),
bpargv,
flags);
if (rc) {
if (currblk) {
rc = IPMI_CC_OK;
}
break;
}
}
}
return rc;
}
static
int
chassis_bootmailbox(struct ipmi_intf *intf, int argc, char *argv[])
{
int rc = IPMI_CC_UNSPECIFIED_ERROR;
bool use_text = false; /* Default to data dump I/O mode */
int16_t block = -1; /* By default print all blocks */
const char *cmd;
if ((argc < 1) || !strcmp(argv[0], "help")) {
chassis_bootmailbox_help();
goto out;
} else {
cmd = argv[0];
++argv;
--argc;
if (argc > 0 && !strcmp(argv[0], "text")) {
use_text = true;
++argv;
--argc;
}
if (argc > 0 && !strcmp(argv[0], "block")) {
if (argc < 2) {
chassis_bootmailbox_help();
goto out;
}
if(str2short(argv[1], &block)) {
lprintf(LOG_ERR,
"Invalid block %s", argv[1]);
goto out;
}
argv += 2;
argc -= 2;
}
if (!strcmp(cmd, "get")) {
rc = chassis_get_bootmailbox(intf, block, use_text);
}
else if (!strcmp(cmd, "set")) {
rc = chassis_set_bootmailbox(intf, block, use_text,
argc, argv);
}
}
out:
return rc;
}
static int
ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy)
{
@ -1131,7 +1560,10 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
int rc = 0;
if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
lprintf(LOG_NOTICE, "Chassis Commands: status, power, identify, policy, restart_cause, poh, bootdev, bootparam, selftest");
lprintf(LOG_NOTICE, "Chassis Commands:\n"
" status, power, policy, restart_cause\n"
" poh, identify, selftest,\n"
" bootdev, bootparam, bootmbox");
}
else if (strncmp(argv[0], "status", 6) == 0) {
rc = ipmi_chassis_status(intf);
@ -1219,7 +1651,10 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
}
else {
if (strncmp(argv[1], "get", 3) == 0) {
rc = ipmi_chassis_get_bootparam(intf, argv[2]);
rc = ipmi_chassis_get_bootparam(intf,
argc - 2,
argv + 2,
0);
}
else if (strncmp(argv[1], "set", 3) == 0) {
unsigned char set_flag=0;
@ -1359,6 +1794,9 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
}
}
else if (!strcmp(argv[0], "bootmbox")) {
rc = chassis_bootmailbox(intf, argc -1, argv + 1);
}
else {
lprintf(LOG_ERR, "Invalid chassis command: %s", argv[0]);
return -1;

View File

@ -1486,6 +1486,7 @@ ipmi_pef2_get_info(struct ipmi_intf *intf)
ipmi_pef_print_guid(guid_ptr);
}
ipmi_pef_print_flags(&pef_b2s_actions, P_SUPP, pcap.actions);
putchar('\n');
return 0;
}
@ -1537,6 +1538,7 @@ ipmi_pef2_get_status(struct ipmi_intf *intf)
return (-1);
}
ipmi_pef_print_flags(&pef_b2s_actions, P_ACTV, rsp->data[1]);
putchar('\n');
return 0;
}

View File

@ -68,8 +68,9 @@ static struct sdr_record_list *sdr_list_head = NULL;
static struct sdr_record_list *sdr_list_tail = NULL;
static struct ipmi_sdr_iterator *sdr_list_itr = NULL;
/* unit description codes (IPMI v1.5 section 37.16) */
#define UNIT_MAX 0x90
/* IPMI 2.0 Table 43-15, Sensor Unit Type Codes */
#define UNIT_TYPE_MAX 92 /* This is the ID of "grams" */
#define UNIT_TYPE_LONGEST_NAME 19 /* This is the length of "color temp deg K" */
static const char *unit_desc[] = {
"unspecified",
"degrees C",
@ -161,7 +162,9 @@ static const char *unit_desc[] = {
"characters",
"error",
"correctable error",
"uncorrectable error"
"uncorrectable error",
"fatal error",
"grams"
};
/* sensor type codes (IPMI v1.5 table 36.3)
@ -220,35 +223,60 @@ void printf_sdr_usage();
uint16_t
ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf);
/* ipmi_sdr_get_unit_string - return units for base/modifier
/** ipmi_sdr_get_unit_string - return units for base/modifier
*
* @pct: units are a percentage
* @type: unit type
* @base: base
* @modifier: modifier
* @param[in] pct Indicates that units are a percentage
* @param[in] relation Modifier unit to base unit relation
* (SDR_UNIT_MOD_NONE, SDR_UNIT_MOD_MUL,
* or SDR_UNIT_MOD_DIV)
* @param[in] base The base unit type id
* @param[in] modifier The modifier unit type id
*
* returns pointer to static string
* @returns a pointer to static string
*/
const char *
ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifier)
ipmi_sdr_get_unit_string(bool pct, uint8_t relation,
uint8_t base, uint8_t modifier)
{
static char unitstr[16];
/*
* Twice as long as the longest possible unit name, plus
* two characters for '%' and relation (either '*' or '/'),
* plus the terminating null-byte.
*/
static char unitstr[2 * UNIT_TYPE_LONGEST_NAME + 2 + 1];
/*
* By default, if units are supposed to be percent, we will pre-pend
* the percent string to the textual representation of the units.
*/
char *pctstr = pct ? "% " : "";
memset(unitstr, 0, sizeof (unitstr));
switch (type) {
case 2:
const char *pctstr = pct ? "% " : "";
const char *basestr;
const char *modstr;
if (base <= UNIT_TYPE_MAX) {
basestr = unit_desc[base];
}
else {
basestr = "invalid";
}
if (modifier <= UNIT_TYPE_MAX) {
modstr = unit_desc[base];
}
else {
modstr = "invalid";
}
switch (relation) {
case SDR_UNIT_MOD_MUL:
snprintf(unitstr, sizeof (unitstr), "%s%s*%s",
pctstr, unit_desc[base], unit_desc[modifier]);
pctstr, basestr, modstr);
break;
case 1:
case SDR_UNIT_MOD_DIV:
snprintf(unitstr, sizeof (unitstr), "%s%s/%s",
pctstr, unit_desc[base], unit_desc[modifier]);
pctstr, basestr, modstr);
break;
case 0:
case SDR_UNIT_MOD_NONE:
default:
/*
* Display the text "percent" only when the Base unit is
@ -258,7 +286,7 @@ ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifi
snprintf(unitstr, sizeof(unitstr), "percent");
} else {
snprintf(unitstr, sizeof (unitstr), "%s%s",
pctstr, unit_desc[base]);
pctstr, basestr);
}
break;
}

View File

@ -249,6 +249,7 @@ const struct oemvalstr ipmi_oem_product_info[] = {
/* YADRO */
{ IPMI_OEM_YADRO, 0x0001, "VESNIN BMC" },
{ IPMI_OEM_YADRO, 0x000A, "TATLIN Storage Controller BMC" },
{ 0xffffff , 0xffff , NULL },
};

View File

@ -32,11 +32,12 @@ 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
libintf_la_CFLAGS = -DDEFAULT_INTF='"@DEFAULT_INTF@"'
libintf_la_LDFLAGS = -export-dynamic
libintf_la_LIBADD = @IPMITOOL_INTF_LIB@
libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@

View File

@ -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

241
src/plugins/dbus/dbus.c Normal file
View File

@ -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,
};

View File

@ -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
@ -118,10 +121,33 @@ struct ipmi_intf * ipmi_intf_table[] = {
#endif
#ifdef IPMI_INTF_USB
&ipmi_usb_intf,
#endif
#ifdef IPMI_INTF_DBUS
&ipmi_dbus_intf,
#endif
NULL
};
/* get_default_interface - return the interface that was chosen by configure
*
* returns a valid interface pointer
*/
static struct ipmi_intf *get_default_interface(void)
{
static const char *default_intf_name = DEFAULT_INTF;
struct ipmi_intf ** intf;
for (intf = ipmi_intf_table; intf && *intf; intf++) {
if (!strcmp(default_intf_name, (*intf)->name)) {
return *intf;
}
}
/* code should never reach this because the configure script checks
* to see that the default interface is actually enabled, but we have
* to return some valid value here, so the first entry works
*/
return ipmi_intf_table[0];
}
/* ipmi_intf_print - Print list of interfaces
*
* no meaningful return code
@ -129,10 +155,11 @@ struct ipmi_intf * ipmi_intf_table[] = {
void ipmi_intf_print(struct ipmi_intf_support * intflist)
{
struct ipmi_intf ** intf;
struct ipmi_intf *def_intf;
struct ipmi_intf_support * sup;
int def = 1;
int found;
def_intf = get_default_interface();
lprintf(LOG_NOTICE, "Interfaces:");
for (intf = ipmi_intf_table; intf && *intf; intf++) {
@ -151,8 +178,7 @@ void ipmi_intf_print(struct ipmi_intf_support * intflist)
lprintf(LOG_NOTICE, "\t%-12s %s %s",
(*intf)->name, (*intf)->desc,
def ? "[default]" : "");
def = 0;
def_intf == (*intf) ? "[default]" : "");
}
lprintf(LOG_NOTICE, "");
}
@ -171,7 +197,7 @@ struct ipmi_intf * ipmi_intf_load(char * name)
struct ipmi_intf * i;
if (!name) {
i = ipmi_intf_table[0];
i = get_default_interface();
if (i->setup && (i->setup(i) < 0)) {
lprintf(LOG_ERR, "Unable to setup "
"interface %s", name);