Compare commits

..

1 Commits

Author SHA1 Message Date
57dc21a486 fru: Reduce duplicate code
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-03-07 19:44:54 +03:00
18 changed files with 382 additions and 1410 deletions

View File

@ -1,37 +1,10 @@
language: C language: C
sudo: enabled sudo: enabled
before_install:
- sudo apt-get install -y libssl-dev
before_script: before_script:
- ./bootstrap - ./bootstrap
addons: script:
apt: - ./configure --enable-intf-dummy
update: true - make
packages: - sudo make install
- 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
- sudo make install

32
INSTALL
View File

@ -9,33 +9,17 @@ are permitted in any medium without royalty provided the copyright
notice and this notice are preserved. This file is offered as-is, notice and this notice are preserved. This file is offered as-is,
without warranty of any kind. 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 Basic Installation
================== ==================
Briefly, the followong shell command should configure, build, and Briefly, the shell command `./configure && make && make install'
install this package: should configure, build, and install this package. The following
`./bootstrap && ./configure && make && make install` more-detailed instructions are generic; see the `README' file for
instructions specific to this package. Some packages provide this
The following more-detailed instructions are generic; see the `INSTALL' file but do not implement all of the features documented
`README' file for instructions specific to this package. Some below. The lack of an optional feature in a given package is not
packages provide this `INSTALL' file but do not implement all of the necessarily a bug. More recommendations for GNU packages can be found
features documented below. The lack of an optional feature in a given in *note Makefile Conventions: (standards)Makefile Conventions.
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 The `configure' shell script attempts to guess correct values for
various system-dependent variables used during compilation. It uses various system-dependent variables used during compilation. It uses

View File

@ -59,7 +59,6 @@ dnl
xenable_all_options=yes xenable_all_options=yes
xenable_intf_bmc=no xenable_intf_bmc=no
xenable_intf_dbus=no
xenable_intf_dummy=no xenable_intf_dummy=no
xenable_intf_imb=yes xenable_intf_imb=yes
xenable_intf_lipmi=yes xenable_intf_lipmi=yes
@ -192,14 +191,6 @@ AC_CHECK_LIB([crypto], [MD2_Init],
fi], fi],
[], [-lcrypto]) [], [-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 dnl enable IPMIv1.5 LAN interface
AC_ARG_ENABLE([intf-lan], AC_ARG_ENABLE([intf-lan],
[AC_HELP_STRING([--enable-intf-lan], [AC_HELP_STRING([--enable-intf-lan],
@ -563,25 +554,6 @@ if test "x$xenable_intf_bmc" = "xyes"; then
IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB bmc/libintf_bmc.la" IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB bmc/libintf_bmc.la"
fi 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 dnl enable Dummy interface for testing
AC_ARG_ENABLE([intf-dummy], AC_ARG_ENABLE([intf-dummy],
[AC_HELP_STRING([--enable-intf-dummy], [AC_HELP_STRING([--enable-intf-dummy],
@ -671,25 +643,6 @@ AC_TRY_COMPILE([],[
[Define to 1 if you need to use #pragma pack instead of __attribute__ ((packed))])] [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 dnl Generate files for build
AC_CONFIG_FILES([Makefile AC_CONFIG_FILES([Makefile
@ -711,7 +664,6 @@ AC_CONFIG_FILES([Makefile
src/plugins/free/Makefile src/plugins/free/Makefile
src/plugins/imb/Makefile src/plugins/imb/Makefile
src/plugins/bmc/Makefile src/plugins/bmc/Makefile
src/plugins/dbus/Makefile
src/plugins/usb/Makefile src/plugins/usb/Makefile
src/plugins/lipmi/Makefile src/plugins/lipmi/Makefile
src/plugins/serial/Makefile src/plugins/serial/Makefile
@ -722,14 +674,13 @@ AC_OUTPUT
AC_MSG_RESULT([]) AC_MSG_RESULT([])
AC_MSG_RESULT([ipmitool $VERSION]) AC_MSG_RESULT([ipmitool $VERSION])
AC_MSG_RESULT([]) AC_MSG_RESULT([])
AC_MSG_RESULT([Interfaces (default=$DEFAULT_INTF)]) AC_MSG_RESULT([Interfaces])
AC_MSG_RESULT([ lan : $xenable_intf_lan]) AC_MSG_RESULT([ lan : $xenable_intf_lan])
AC_MSG_RESULT([ lanplus : $xenable_intf_lanplus]) AC_MSG_RESULT([ lanplus : $xenable_intf_lanplus])
AC_MSG_RESULT([ open : $xenable_intf_open]) AC_MSG_RESULT([ open : $xenable_intf_open])
AC_MSG_RESULT([ free : $xenable_intf_free]) AC_MSG_RESULT([ free : $xenable_intf_free])
AC_MSG_RESULT([ imb : $xenable_intf_imb]) AC_MSG_RESULT([ imb : $xenable_intf_imb])
AC_MSG_RESULT([ bmc : $xenable_intf_bmc]) AC_MSG_RESULT([ bmc : $xenable_intf_bmc])
AC_MSG_RESULT([ dbus : $xenable_intf_dbus])
AC_MSG_RESULT([ usb : $xenable_intf_usb]) AC_MSG_RESULT([ usb : $xenable_intf_usb])
AC_MSG_RESULT([ lipmi : $xenable_intf_lipmi]) AC_MSG_RESULT([ lipmi : $xenable_intf_lipmi])
AC_MSG_RESULT([ serial : $xenable_intf_serial]) AC_MSG_RESULT([ serial : $xenable_intf_serial])

View File

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

View File

@ -384,23 +384,39 @@ application (ipmi or sol) on the given channel.
\fIstatus\fP \fIstatus\fP
Status information related to power, buttons, cooling, drives and faults. Status information related to power, buttons, cooling, drives and faults.
.RS
.RE
.TP .TP
\fIpower\fP \fIpower\fP
.RS .RS
.TP .TP
\fIstatus\fP \fIstatus\fP
.RS
.RE
.TP .TP
\fIon\fP \fIon\fP
.RS
.RE
.TP .TP
\fIoff\fP \fIoff\fP
.RS
.RE
.TP .TP
\fIcycle\fP \fIcycle\fP
.RS
.RE
.TP .TP
\fIreset\fP \fIreset\fP
.RS
.RE
.TP .TP
\fIdiag\fP \fIdiag\fP
.RS
.RE
.TP .TP
\fIsoft\fP \fIsoft\fP
.RS
.RE
.RE .RE
.TP .TP
\fIidentify\fP [<seconds>|force] \fIidentify\fP [<seconds>|force]
@ -412,6 +428,8 @@ Default is 15 seconds.
0 - Off 0 - Off
.br .br
force - To turn on indefinitely force - To turn on indefinitely
.RS
.RE
.TP .TP
\fIpolicy\fP \fIpolicy\fP
@ -421,22 +439,34 @@ What to do when power is restored.
\fIlist\fP \fIlist\fP
Show available options. Show available options.
.RS
.RE
.TP .TP
\fIalways-on\fP \fIalways-on\fP
.RS
.RE
.TP .TP
\fIprevious\fP \fIprevious\fP
.RS
.RE
.TP .TP
\fIalways-off\fP \fIalways-off\fP
.RS
.RE
.RE .RE
.TP .TP
\fIrestart_cause\fP \fIrestart_cause\fP
Last restart cause. Last restart cause.
.RS
.RE
.TP .TP
\fIpoh\fP \fIpoh\fP
Get power on hours. Get power on hours.
.RS
.RE
.TP .TP
\fIbootdev\fP \fIbootdev\fP
.RS .RS
@ -444,123 +474,95 @@ Get power on hours.
\fInone\fP \fInone\fP
Do not change boot device order. Do not change boot device order.
.RS
.RE
.TP .TP
\fIpxe\fP \fIpxe\fP
Force PXE boot. Force PXE boot.
.RS
.RE
.TP .TP
\fIdisk\fP \fIdisk\fP
Force boot from default Hard-drive. Force boot from default Hard-drive.
.RS
.RE
.TP .TP
\fIsafe\fP \fIsafe\fP
Force boot from default Hard-drive, request Safe Mode. Force boot from default Hard-drive, request Safe Mode.
.RS
.RE
.TP .TP
\fIdiag\fP \fIdiag\fP
Force boot from Diagnostic Partition. Force boot from Diagnostic Partition.
.RS
.RE
.TP .TP
\fIcdrom\fP \fIcdrom\fP
Force boot from CD/DVD. Force boot from CD/DVD.
.RS
.RE
.TP .TP
\fIbios\fP \fIbios\fP
Force boot into BIOS Setup. Force boot into BIOS Setup.
.RS
.RE
.TP .TP
\fIfloppy\fP \fIfloppy\fP
Force boot from Floppy/primary removable media. Force boot from Floppy/primary removable media.
.RE
.TP
\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 .RS
.IP \fIforce_pxe\fP .RE
.RE
.TP
\fIbootparam\fP
.RS
.TP
\fIforce_pxe\fP
Force PXE boot Force PXE boot
.IP \fIforce_disk\fP .RS
.RE
.TP
\fIforce_disk\fP
Force boot from default Hard-drive Force boot from default Hard-drive
.IP \fIforce_safe\fP .RS
.RE
.TP
\fIforce_safe\fP
Force boot from default Hard-drive, request Safe Mode Force boot from default Hard-drive, request Safe Mode
.IP \fIforce_diag\fP .RS
.RE
.TP
\fIforce_diag\fP
Force boot from Diagnostic Partition Force boot from Diagnostic Partition
.IP \fIforce_cdrom\fP .RS
.RE
.TP
\fIforce_cdrom\fP
Force boot from CD/DVD Force boot from CD/DVD
.IP \fIforce_bios\fP .RS
.RE
.TP
\fIforce_bios\fP
Force boot into BIOS Setup Force boot into BIOS Setup
.RS
.PP .RE
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 .RE
.TP .TP
\fIselftest\fP \fIselftest\fP
.RS
Get the chassis self-test results .RE
.RE .RE
.TP .TP
\fIdcmi\fP \fIdcmi\fP
@ -955,6 +957,8 @@ Shows Extended SD Card information.
\fIecho\fP \fIecho\fP
For echoing lines to stdout in scripts. For echoing lines to stdout in scripts.
.RS
.RE
.TP .TP
\fIekanalyzer\fP <\fBcommand\fR> <\fBxx=filename1\fR> <\fBxx=filename2\fR> [<\fBrc=filename3\fR>] \fB...\fR \fIekanalyzer\fP <\fBcommand\fR> <\fBxx=filename1\fR> <\fBxx=filename2\fR> [<\fBrc=filename3\fR>] \fB...\fR
.RS .RS
@ -1506,14 +1510,20 @@ Show firmware upgrade log.
\fIlist\fP \fIlist\fP
List All Generic Device Locators. List All Generic Device Locators.
.RS
.RE
.TP .TP
\fIread\fP <\fBsdr name\fR> <\fBfile\fR> \fIread\fP <\fBsdr name\fR> <\fBfile\fR>
Read to file eeprom specify by Generic Device Locators. Read to file eeprom specify by Generic Device Locators.
.RS
.RE
.TP .TP
\fIwrite\fP <\fBsdr name\fR> <\fBfile\fR> \fIwrite\fP <\fBsdr name\fR> <\fBfile\fR>
Write from file eeprom specify by Generic Device Locators Write from file eeprom specify by Generic Device Locators
.RS
.RE
.RE .RE
.TP .TP
\fIhpm\fP \fIhpm\fP
@ -3140,34 +3150,50 @@ or by using the keyword `all' to specify all sessions.
\fIhostname\fP <\fBhost\fR> \fIhostname\fP <\fBhost\fR>
Session hostname. Session hostname.
.RS
.RE
.TP .TP
\fIusername\fP <\fBuser\fR> \fIusername\fP <\fBuser\fR>
Session username. Session username.
.RS
.RE
.TP .TP
\fIpassword\fP <\fBpass\fR> \fIpassword\fP <\fBpass\fR>
Session password. Session password.
.RS
.RE
.TP .TP
\fIprivlvl\fP <\fBlevel\fR> \fIprivlvl\fP <\fBlevel\fR>
Session privilege level force. Session privilege level force.
.RS
.RE
.TP .TP
\fIauthtype\fP <\fBtype\fR> \fIauthtype\fP <\fBtype\fR>
Authentication type force. Authentication type force.
.RS
.RE
.TP .TP
\fIlocaladdr\fP <\fBaddr\fR> \fIlocaladdr\fP <\fBaddr\fR>
Local IPMB address. Local IPMB address.
.RS
.RE
.TP .TP
\fItargetaddr\fP <\fBaddr\fR> \fItargetaddr\fP <\fBaddr\fR>
Remote target IPMB address. Remote target IPMB address.
.RS
.RE
.TP .TP
\fIport\fP <\fBport\fR> \fIport\fP <\fBport\fR>
Remote RMCP port. Remote RMCP port.
.RS
.RE
.TP .TP
\fIcsv\fP [\fBlevel\fR] \fIcsv\fP [\fBlevel\fR]
@ -3175,10 +3201,14 @@ Enable output in comma separated format.
Affects following commands: Affects following commands:
\fIuser\fP, \fIchannel\fP, \fIisol\fP, \fIsunoem\fP, \fIuser\fP, \fIchannel\fP, \fIisol\fP, \fIsunoem\fP,
\fIsol\fP, \fIsensor\fP, \fIsdr\fP, \fIsel\fP, \fIsession\fP. \fIsol\fP, \fIsensor\fP, \fIsdr\fP, \fIsel\fP, \fIsession\fP.
.RS
.RE
.TP .TP
\fIverbose\fP [\fBverbose\fR] \fIverbose\fP [\fBverbose\fR]
Verbosity level. Verbosity level.
.RS
.RE
.RE .RE
.TP .TP
\fIshell\fP \fIshell\fP

View File

@ -38,7 +38,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <stdlib.h> /* For free() */ #include <stdlib.h> /* For free() */
#include <stdbool.h>
#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
@ -80,10 +79,6 @@ struct oemvalstr {
const char * str; 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 * val2str(uint16_t val, const struct valstr * vs);
const char * oemval2str(uint32_t oem,uint16_t val, const struct oemvalstr * vs); const char * oemval2str(uint32_t oem,uint16_t val, const struct oemvalstr * vs);
@ -97,8 +92,6 @@ int str2ushort(const char * str, uint16_t * ushrt_ptr);
int str2char(const char * str, int8_t * chr_ptr); int str2char(const char * str, int8_t * chr_ptr);
int str2uchar(const char * str, uint8_t * uchr_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 eval_ccode(const int ccode);
int is_fru_id(const char *argv_ptr, uint8_t *fru_id_ptr); int is_fru_id(const char *argv_ptr, uint8_t *fru_id_ptr);
@ -173,13 +166,6 @@ static inline uint32_t ipmi24toh(void *ipmi24)
return h; 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) static inline uint32_t ipmi32toh(void *ipmi32)
{ {
uint8_t *ipmi = ipmi32; uint8_t *ipmi = ipmi32;

View File

@ -37,7 +37,6 @@
# include <config.h> # include <config.h>
#endif #endif
#include <stdbool.h>
#include <inttypes.h> #include <inttypes.h>
#include <math.h> #include <math.h>
#include <ipmitool/bswap.h> #include <ipmitool/bswap.h>
@ -382,29 +381,6 @@ struct sdr_record_common_sensor {
struct sdr_record_mask mask; 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 { struct {
#if WORDS_BIGENDIAN #if WORDS_BIGENDIAN
uint8_t analog:2; uint8_t analog:2;
@ -418,8 +394,8 @@ struct sdr_record_common_sensor {
uint8_t analog:2; uint8_t analog:2;
#endif #endif
struct { struct {
uint8_t base; /* Base unit type code per IPMI 2.0 Table 43-15 */ uint8_t base;
uint8_t modifier; /* Modifier unit type code per Table 43-15 */ uint8_t modifier;
} ATTRIBUTE_PACKING type; } ATTRIBUTE_PACKING type;
} ATTRIBUTE_PACKING unit; } ATTRIBUTE_PACKING unit;
} ATTRIBUTE_PACKING; } ATTRIBUTE_PACKING;
@ -857,8 +833,8 @@ void ipmi_sdr_print_sensor_hysteresis(struct sdr_record_common_sensor *sensor,
struct sdr_record_full_sensor *full, struct sdr_record_full_sensor *full,
uint8_t hysteresis_value, uint8_t hysteresis_value,
const char *hdrstr); const char *hdrstr);
const char *ipmi_sdr_get_unit_string(bool pct, uint8_t type, const char *ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type,
uint8_t base, uint8_t modifier); uint8_t base, uint8_t modifier);
struct sensor_reading * struct sensor_reading *
ipmi_sdr_read_sensor_value(struct ipmi_intf *intf, ipmi_sdr_read_sensor_value(struct ipmi_intf *intf,
struct sdr_record_common_sensor *sensor, struct sdr_record_common_sensor *sensor,

View File

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

View File

@ -319,74 +319,26 @@ mac2str(const uint8_t *buf)
return buf2str_extended(buf, 6, ":"); 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)
{
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]; static char un_str[32];
int i;
for (i = 0; vs[i].str; i++) {
if (vs[i].val == val)
return vs[i].str;
}
memset(un_str, 0, 32); memset(un_str, 0, 32);
snprintf(un_str, 32, "Unknown (0x%02X)", val); snprintf(un_str, 32, "Unknown (0x%02X)", val);
return un_str; 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 char * oemval2str(uint32_t oem, uint16_t val,
const struct oemvalstr *vs) const struct oemvalstr *vs)
{ {
static char un_str[32];
int i; int i;
for (i = 0; vs[i].oem != 0xffffff && vs[i].str; i++) { for (i = 0; vs[i].oem != 0xffffff && vs[i].str; i++) {
@ -397,7 +349,10 @@ const char * oemval2str(uint32_t oem, uint16_t val,
} }
} }
return unknown_val_str(val); memset(un_str, 0, 32);
snprintf(un_str, 32, "Unknown (0x%X)", val);
return un_str;
} }
/* str2double - safely convert string to double /* str2double - safely convert string to double
@ -1125,35 +1080,3 @@ ipmi_get_oem_id(struct ipmi_intf *intf)
return oem_id; 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,8 +34,6 @@
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <errno.h>
#include <limits.h>
#include <ipmitool/bswap.h> #include <ipmitool/bswap.h>
#include <ipmitool/helper.h> #include <ipmitool/helper.h>
@ -46,40 +44,8 @@
#include <ipmitool/ipmi_chassis.h> #include <ipmitool/ipmi_chassis.h>
#include <ipmitool/ipmi_time.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; 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 int
ipmi_chassis_power_status(struct ipmi_intf * intf) ipmi_chassis_power_status(struct ipmi_intf * intf)
{ {
@ -480,166 +446,61 @@ ipmi_chassis_selftest(struct ipmi_intf * intf)
} }
static int static int
ipmi_chassis_set_bootparam(struct ipmi_intf * intf, ipmi_chassis_set_bootparam(struct ipmi_intf * intf, uint8_t param, uint8_t * data, int len)
uint8_t param, void *data, int len)
{ {
struct ipmi_rs * rsp; struct ipmi_rs * rsp;
struct ipmi_rq req; struct ipmi_rq req;
struct { uint8_t msg_data[16];
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;
msg_data = malloc(msgsize); memset(msg_data, 0, 16);
if (!msg_data) { msg_data[0] = param & 0x7f;
goto out; memcpy(msg_data+1, data, len);
}
memset(msg_data, 0, msgsize);
msg_data->param = param & BOOTPARAM_MASK;
memcpy(msg_data->data, data, len);
memset(&req, 0, sizeof(req)); memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_CHASSIS; req.msg.netfn = IPMI_NETFN_CHASSIS;
req.msg.cmd = 0x8; req.msg.cmd = 0x8;
req.msg.data = (uint8_t *)msg_data; req.msg.data = msg_data;
req.msg.data_len = msgsize; req.msg.data_len = len + 1;
rsp = intf->sendrecv(intf, &req); rsp = intf->sendrecv(intf, &req);
if (!rsp) { if (!rsp) {
lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param); lprintf(LOG_ERR, "Error setting Chassis Boot Parameter %d", param);
return -1; return -1;
} }
if (rsp->ccode) {
rc = rsp->ccode;
if (rc) {
if (param != 0) { if (param != 0) {
lprintf(LOG_ERR, lprintf(LOG_ERR, "Set Chassis Boot Parameter %d failed: %s",
"Set Chassis Boot Parameter %d failed: %s", param, val2str(rsp->ccode, completion_code_vals));
param,
specific_val2str(rsp->ccode,
set_bootparam_cc_vals,
completion_code_vals));
} }
goto out; return -1;
} }
lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len)); 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 static int
ipmi_chassis_get_bootparam(struct ipmi_intf * intf, ipmi_chassis_get_bootparam(struct ipmi_intf * intf, char * arg)
int argc, char *argv[], int flags)
{ {
struct ipmi_rs * rsp; struct ipmi_rs * rsp;
struct ipmi_rq req; struct ipmi_rq req;
uint8_t msg_data[3]; uint8_t msg_data[3];
uint8_t param_id = 0; 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 (argc < 1 || !argv[0]) { if (!arg)
goto out; return -1;
if (str2uchar(arg, &param_id) != 0) {
lprintf(LOG_ERR, "Invalid parameter '%s' given instead of bootparam.",
arg);
return (-1);
} }
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); memset(msg_data, 0, 3);
msg_data[0] = param_id & 0x7f; msg_data[0] = param_id & 0x7f;
msg_data[1] = 0;
if (argc) { msg_data[2] = 0;
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)); memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_CHASSIS; req.msg.netfn = IPMI_NETFN_CHASSIS;
@ -649,21 +510,12 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf,
rsp = intf->sendrecv(intf, &req); rsp = intf->sendrecv(intf, &req);
if (!rsp) { if (!rsp) {
lprintf(LOG_ERR, lprintf(LOG_ERR, "Error Getting Chassis Boot Parameter %s", arg);
"Error Getting Chassis Boot Parameter %" PRIu8,
msg_data[0]);
return -1;
}
if (IPMI_CC_PARAM_OUT_OF_RANGE == rsp->ccode && skip_range) {
return -1; return -1;
} }
if (rsp->ccode) { if (rsp->ccode) {
lprintf(LOG_ERR, lprintf(LOG_ERR, "Get Chassis Boot Parameter %s failed: %s",
"Get Chassis Boot Parameter %" PRIu8 " failed: %s", arg, val2str(rsp->ccode, completion_code_vals));
msg_data[0],
specific_val2str(rsp->ccode,
get_bootparam_cc_vals,
completion_code_vals));
return -1; return -1;
} }
@ -673,17 +525,10 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf,
param_id = 0; param_id = 0;
param_id = (rsp->data[1] & 0x7f); param_id = (rsp->data[1] & 0x7f);
if (!skip_generic) { printf("Boot parameter version: %d\n", rsp->data[0]);
printf("Boot parameter version: %d\n", rsp->data[0]); printf("Boot parameter %d is %s\n", rsp->data[1] & 0x7f,
printf("Boot parameter %d is %s\n", rsp->data[1] & 0x7f, (rsp->data[1] & 0x80) ? "invalid/locked" : "valid/unlocked");
(rsp->data[1] & 0x80) printf("Boot parameter data: %s\n", buf2str(rsp->data+2, rsp->data_len - 2));
? "invalid/locked"
: "valid/unlocked");
if (!skip_data) {
printf("Boot parameter data: %s\n",
buf2str(rsp->data+2, rsp->data_len - 2));
}
}
switch(param_id) switch(param_id)
{ {
@ -871,18 +716,17 @@ ipmi_chassis_get_bootparam(struct ipmi_intf * intf,
} }
break; break;
case 7: case 7:
chassis_bootmailbox_parse(rsp->data + 2, {
rsp->data_len - 2, printf(" Selector : %d\n", rsp->data[2] );
flags); printf(" Block Data : %s\n", buf2str(rsp->data+3, rsp->data_len - 2));
break; }
break;
default: default:
printf(" Unsupported parameter %" PRIu8 "\n", param_id); printf(" Undefined byte\n");
break; break;
} }
rc = IPMI_CC_OK; return 0;
out:
return rc;
} }
static int static int
@ -988,10 +832,7 @@ ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
} }
if (rsp->ccode) { if (rsp->ccode) {
lprintf(LOG_ERR, "Get Chassis Boot Parameter %d failed: %s", lprintf(LOG_ERR, "Get Chassis Boot Parameter %d failed: %s",
param_id, param_id, val2str(rsp->ccode, completion_code_vals));
specific_val2str(rsp->ccode,
get_bootparam_cc_vals,
completion_code_vals));
return -1; return -1;
} }
@ -1001,97 +842,77 @@ ipmi_chassis_get_bootvalid(struct ipmi_intf * intf)
return(rsp->data[2]); 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 static int
ipmi_chassis_set_bootvalid(struct ipmi_intf *intf, uint8_t set_flag, uint8_t clr_flag) ipmi_chassis_set_bootvalid(struct ipmi_intf *intf, uint8_t set_flag, uint8_t clr_flag)
{ {
int bootvalid; int bootvalid;
uint8_t flags[2]; uint8_t flags[5];
int rc; int rc = 0;
int use_progress = 1;
uint8_t param_id = IPMI_CHASSIS_BOOTPARAM_FLAG_VALID;
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS); if (use_progress) {
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK); /* 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;
}
if (rc) { memset(flags, 0, 5);
goto out; 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;
} }
bootvalid = ipmi_chassis_get_bootvalid(intf); bootvalid = ipmi_chassis_get_bootvalid(intf);
if (bootvalid < 0) { if (bootvalid < 0) {
lprintf(LOG_ERR, "Failed to read boot valid flag"); if (use_progress) {
rc = bootvalid; /* set-in-progress = set-complete */
goto out; memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
return -1;
} }
flags[0] = (bootvalid & ~clr_flag) | set_flag; flags[0] = (bootvalid & ~clr_flag) | set_flag;
rc = ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_FLAG_VALID, rc = ipmi_chassis_set_bootparam(intf, param_id, flags, 1);
flags, 1);
if (IPMI_CC_OK == rc) { if (rc == 0) {
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE); 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,
flags, 1);
} }
out:
chassis_bootparam_set_in_progress(intf, SET_COMPLETE);
return rc; return rc;
} }
@ -1099,17 +920,38 @@ static int
ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags) ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags)
{ {
uint8_t flags[5]; uint8_t flags[5];
int rc; int rc = 0;
int use_progress = 1;
chassis_bootparam_set_in_progress(intf, SET_IN_PROGRESS); if (use_progress) {
rc = chassis_bootparam_clear_ack(intf, BIOS_POST_ACK); /* 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);
if (rc < 0) { if (rc < 0) {
goto out; 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 (!iflags) if (!iflags)
memset(flags, 0, sizeof(flags)); memset(flags, 0, 5);
else else
memcpy(flags, iflags, sizeof (flags)); memcpy(flags, iflags, sizeof (flags));
@ -1140,316 +982,45 @@ ipmi_chassis_set_bootdev(struct ipmi_intf * intf, char * arg, uint8_t *iflags)
flags[1] |= 0x18; flags[1] |= 0x18;
else { else {
lprintf(LOG_ERR, "Invalid argument: %s", arg); lprintf(LOG_ERR, "Invalid argument: %s", arg);
rc = -1; if (use_progress) {
goto out; /* set-in-progress = set-complete */
memset(flags, 0, 5);
ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
flags, 1);
}
return -1;
} }
/* set flag valid bit */ /* set flag valid bit */
flags[0] |= 0x80; flags[0] |= 0x80;
rc = ipmi_chassis_set_bootparam(intf, rc = ipmi_chassis_set_bootparam(intf, IPMI_CHASSIS_BOOTPARAM_BOOT_FLAGS,
IPMI_CHASSIS_BOOTPARAM_BOOT_FLAGS, flags, 5);
flags, 5); if (rc == 0) {
if (IPMI_CC_OK == rc) { if (use_progress) {
chassis_bootparam_set_in_progress(intf, COMMIT_WRITE); /* 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);
}
printf("Set Boot Device to %s\n", arg); printf("Set Boot Device to %s\n", arg);
} }
out: if (use_progress) {
chassis_bootparam_set_in_progress(intf, SET_COMPLETE); /* set-in-progress = set-complete */
return rc; memset(flags, 0, 5);
} ipmi_chassis_set_bootparam(intf,
IPMI_CHASSIS_BOOTPARAM_SET_IN_PROGRESS,
static void chassis_bootmailbox_help() flags, 1);
{
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; 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 static int
ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy) ipmi_chassis_power_policy(struct ipmi_intf * intf, uint8_t policy)
{ {
@ -1560,10 +1131,7 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
int rc = 0; int rc = 0;
if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) { if ((argc == 0) || (strncmp(argv[0], "help", 4) == 0)) {
lprintf(LOG_NOTICE, "Chassis Commands:\n" lprintf(LOG_NOTICE, "Chassis Commands: status, power, identify, policy, restart_cause, poh, bootdev, bootparam, selftest");
" status, power, policy, restart_cause\n"
" poh, identify, selftest,\n"
" bootdev, bootparam, bootmbox");
} }
else if (strncmp(argv[0], "status", 6) == 0) { else if (strncmp(argv[0], "status", 6) == 0) {
rc = ipmi_chassis_status(intf); rc = ipmi_chassis_status(intf);
@ -1651,10 +1219,7 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
} }
else { else {
if (strncmp(argv[1], "get", 3) == 0) { if (strncmp(argv[1], "get", 3) == 0) {
rc = ipmi_chassis_get_bootparam(intf, rc = ipmi_chassis_get_bootparam(intf, argv[2]);
argc - 2,
argv + 2,
0);
} }
else if (strncmp(argv[1], "set", 3) == 0) { else if (strncmp(argv[1], "set", 3) == 0) {
unsigned char set_flag=0; unsigned char set_flag=0;
@ -1794,9 +1359,6 @@ ipmi_chassis_main(struct ipmi_intf * intf, int argc, char ** argv)
rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL); rc = ipmi_chassis_set_bootdev(intf, argv[1], NULL);
} }
} }
else if (!strcmp(argv[0], "bootmbox")) {
rc = chassis_bootmailbox(intf, argc -1, argv + 1);
}
else { else {
lprintf(LOG_ERR, "Invalid chassis command: %s", argv[0]); lprintf(LOG_ERR, "Invalid chassis command: %s", argv[0]);
return -1; return -1;

View File

@ -2872,27 +2872,32 @@ static void ipmi_fru_picmg_ext_print(uint8_t * fru_data, int off, int length)
} }
} }
/** __ipmi_get_fru_hdr - read FRU info and header from IPMI interface
/* __ipmi_fru_print - Do actual work to print a FRU by its ID *
* * @param[in] intf ipmi interface
* @intf: ipmi interface * @param[in] id fru id
* @id: fru id * @param[out] fru fru info structure pointer
* * @param[out] size size of the allocated fru structure
* returns -1 on error *
* returns 0 if successful * @retval 0 error
* returns 1 if device not present * @retval 1 success
*/ */
static int static int __ipmi_get_fru_hdr(struct ipmi_intf *intf,
__ipmi_fru_print(struct ipmi_intf * intf, uint8_t id) uint8_t id,
struct fru_info *fru,
struct fru_header *header)
{ {
struct ipmi_rs * rsp; struct ipmi_rs *rsp;
struct ipmi_rq req; struct ipmi_rq req;
struct fru_info fru;
struct fru_header header;
uint8_t msg_data[4]; uint8_t msg_data[4];
memset(&fru, 0, sizeof(struct fru_info)); /* Sanity checks */
memset(&header, 0, sizeof(struct fru_header)); if (!fru) return 0;
if (!header) return 0;
if (!intf) return 0;
memset(fru, 0, sizeof(*fru));
memset(header, 0, sizeof(*header));
/* /*
* get info about this FRU * get info about this FRU
@ -2909,66 +2914,63 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id)
rsp = intf->sendrecv(intf, &req); rsp = intf->sendrecv(intf, &req);
if (!rsp) { if (!rsp) {
printf(" Device not present (No Response)\n"); printf(" Device not present (No Response)\n");
return -1; return 0;
} }
if (rsp->ccode) { if (rsp->ccode) {
printf(" Device not present (%s)\n", printf(" Device not present (%s)\n",
val2str(rsp->ccode, completion_code_vals)); val2str(rsp->ccode, completion_code_vals));
return -1; return 0;
} }
memset(&fru, 0, sizeof(fru)); fru->size = (rsp->data[1] << 8) | rsp->data[0];
fru.size = (rsp->data[1] << 8) | rsp->data[0]; fru->access = rsp->data[2] & 0x1;
fru.access = rsp->data[2] & 0x1;
lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)", lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
fru.size, fru.access ? "words" : "bytes"); fru->size, fru->access ? "words" : "bytes");
if (fru.size < 1) { if (fru->size < 1) {
lprintf(LOG_ERR, " Invalid FRU size %d", fru.size); lprintf(LOG_ERR, " Invalid FRU size %d", fru->size);
return -1; return 0;
} }
/* /* Read the FRU header */
* retrieve the FRU header if (read_fru_area(intf, fru, id, 0, sizeof(*header), header)) {
*/ lprintf(LOG_ERR, " Failed to read FRU header");
msg_data[0] = id; return 0;
msg_data[1] = 0;
msg_data[2] = 0;
msg_data[3] = 8;
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_STORAGE;
req.msg.cmd = GET_FRU_DATA;
req.msg.data = msg_data;
req.msg.data_len = 4;
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
printf(" Device not present (No Response)\n");
return 1;
}
if (rsp->ccode) {
printf(" Device not present (%s)\n",
val2str(rsp->ccode, completion_code_vals));
return 1;
} }
if (verbose > 1) if (header->version != 1) {
printbuf(rsp->data, rsp->data_len, "FRU DATA");
memcpy(&header, rsp->data + 1, 8);
if (header.version != 1) {
lprintf(LOG_ERR, " Unknown FRU header version 0x%02x", lprintf(LOG_ERR, " Unknown FRU header version 0x%02x",
header.version); header->version);
return 0;
}
return 1;
}
/* __ipmi_fru_print - Do actual work to print a FRU by its ID
*
* @intf: ipmi interface
* @id: fru id
*
* returns -1 on error
* returns 0 if successful
* returns 1 if device not present
*/
static int
__ipmi_fru_print(struct ipmi_intf * intf, uint8_t id)
{
struct fru_info fru;
struct fru_header header;
if (!__ipmi_get_fru_hdr(intf, id, &fru, &header)) {
return -1; return -1;
} }
/* offsets need converted to bytes /* offsets need converted to bytes
* but that conversion is not done to the structure * but that conversion is not done to the structure
* because we may end up with offset > 255 * because we may end up with offset > 255
* which would overflow our 1-byte offset field */ * which would overflow our 1-byte offset field */
lprintf(LOG_DEBUG, "fru.header.version: 0x%x", lprintf(LOG_DEBUG, "fru.header.version: 0x%x",
header.version); header.version);
@ -4056,91 +4058,19 @@ ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
* returns 1 if device not present * returns 1 if device not present
*/ */
static int static int
ipmi_fru_get_internal_use_info( struct ipmi_intf * intf, ipmi_fru_get_internal_use_info(struct ipmi_intf *intf,
uint8_t id, uint8_t id,
struct fru_info * fru, struct fru_info *fru,
uint16_t * size, uint16_t *size,
uint16_t * offset) uint16_t *offset)
{ {
struct ipmi_rs * rsp;
struct ipmi_rq req;
struct fru_header header; struct fru_header header;
uint8_t msg_data[4];
// Init output value // Init output value
* offset = 0; * offset = 0;
* size = 0; * size = 0;
memset(fru, 0, sizeof(struct fru_info)); if (!__ipmi_get_fru_hdr(intf, id, fru, &header)) {
memset(&header, 0, sizeof(struct fru_header));
/*
* get info about this FRU
*/
memset(msg_data, 0, 4);
msg_data[0] = id;
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_STORAGE;
req.msg.cmd = GET_FRU_INFO;
req.msg.data = msg_data;
req.msg.data_len = 1;
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
printf(" Device not present (No Response)\n");
return -1;
}
if (rsp->ccode) {
printf(" Device not present (%s)\n",
val2str(rsp->ccode, completion_code_vals));
return -1;
}
fru->size = (rsp->data[1] << 8) | rsp->data[0];
fru->access = rsp->data[2] & 0x1;
lprintf(LOG_DEBUG, "fru.size = %d bytes (accessed by %s)",
fru->size, fru->access ? "words" : "bytes");
if (fru->size < 1) {
lprintf(LOG_ERR, " Invalid FRU size %d", fru->size);
return -1;
}
/*
* retrieve the FRU header
*/
msg_data[0] = id;
msg_data[1] = 0;
msg_data[2] = 0;
msg_data[3] = 8;
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_STORAGE;
req.msg.cmd = GET_FRU_DATA;
req.msg.data = msg_data;
req.msg.data_len = 4;
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
printf(" Device not present (No Response)\n");
return 1;
}
if (rsp->ccode) {
printf(" Device not present (%s)\n",
val2str(rsp->ccode, completion_code_vals));
return 1;
}
if (verbose > 1)
printbuf(rsp->data, rsp->data_len, "FRU DATA");
memcpy(&header, rsp->data + 1, 8);
if (header.version != 1) {
lprintf(LOG_ERR, " Unknown FRU header version 0x%02x",
header.version);
return -1; return -1;
} }

View File

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

View File

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

View File

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

View File

@ -32,12 +32,11 @@ MAINTAINERCLEANFILES = Makefile.in
AM_CPPFLAGS = -I$(top_srcdir)/include 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@ @INTF_DBUS@ 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 dbus DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy usb
noinst_LTLIBRARIES = libintf.la noinst_LTLIBRARIES = libintf.la
libintf_la_SOURCES = ipmi_intf.c libintf_la_SOURCES = ipmi_intf.c
libintf_la_CFLAGS = -DDEFAULT_INTF='"@DEFAULT_INTF@"'
libintf_la_LDFLAGS = -export-dynamic libintf_la_LDFLAGS = -export-dynamic
libintf_la_LIBADD = @IPMITOOL_INTF_LIB@ libintf_la_LIBADD = @IPMITOOL_INTF_LIB@
libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@ libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@

View File

@ -1,41 +0,0 @@
#
# 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

View File

@ -1,241 +0,0 @@
/*
* 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,9 +86,6 @@ extern struct ipmi_intf ipmi_dummy_intf;
#ifdef IPMI_INTF_USB #ifdef IPMI_INTF_USB
extern struct ipmi_intf ipmi_usb_intf; extern struct ipmi_intf ipmi_usb_intf;
#endif #endif
#ifdef IPMI_INTF_DBUS
extern struct ipmi_intf ipmi_dbus_intf;
#endif
struct ipmi_intf * ipmi_intf_table[] = { struct ipmi_intf * ipmi_intf_table[] = {
#ifdef IPMI_INTF_OPEN #ifdef IPMI_INTF_OPEN
@ -121,33 +118,10 @@ struct ipmi_intf * ipmi_intf_table[] = {
#endif #endif
#ifdef IPMI_INTF_USB #ifdef IPMI_INTF_USB
&ipmi_usb_intf, &ipmi_usb_intf,
#endif
#ifdef IPMI_INTF_DBUS
&ipmi_dbus_intf,
#endif #endif
NULL 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 /* ipmi_intf_print - Print list of interfaces
* *
* no meaningful return code * no meaningful return code
@ -155,11 +129,10 @@ static struct ipmi_intf *get_default_interface(void)
void ipmi_intf_print(struct ipmi_intf_support * intflist) void ipmi_intf_print(struct ipmi_intf_support * intflist)
{ {
struct ipmi_intf ** intf; struct ipmi_intf ** intf;
struct ipmi_intf *def_intf;
struct ipmi_intf_support * sup; struct ipmi_intf_support * sup;
int def = 1;
int found; int found;
def_intf = get_default_interface();
lprintf(LOG_NOTICE, "Interfaces:"); lprintf(LOG_NOTICE, "Interfaces:");
for (intf = ipmi_intf_table; intf && *intf; intf++) { for (intf = ipmi_intf_table; intf && *intf; intf++) {
@ -178,7 +151,8 @@ void ipmi_intf_print(struct ipmi_intf_support * intflist)
lprintf(LOG_NOTICE, "\t%-12s %s %s", lprintf(LOG_NOTICE, "\t%-12s %s %s",
(*intf)->name, (*intf)->desc, (*intf)->name, (*intf)->desc,
def_intf == (*intf) ? "[default]" : ""); def ? "[default]" : "");
def = 0;
} }
lprintf(LOG_NOTICE, ""); lprintf(LOG_NOTICE, "");
} }
@ -197,7 +171,7 @@ struct ipmi_intf * ipmi_intf_load(char * name)
struct ipmi_intf * i; struct ipmi_intf * i;
if (!name) { if (!name) {
i = get_default_interface(); i = ipmi_intf_table[0];
if (i->setup && (i->setup(i) < 0)) { if (i->setup && (i->setup(i) < 0)) {
lprintf(LOG_ERR, "Unable to setup " lprintf(LOG_ERR, "Unable to setup "
"interface %s", name); "interface %s", name);