Compare commits

...

35 Commits

Author SHA1 Message Date
2bf9964ce5 WIP: nm: Reduce complexity and use of magic numbers
The nm module has a lot of repeated code such as searching
for a subcommand, or verification of command line arguments.
It also extensively uses magic numbers for option processing.
This commit improves code reuse, reduces complexity of code,
and gets rid of at least some of magic numbers in the code.

This is a work in progress on this branch.
2019-08-30 17:32:32 +03:00
b6098c3bdb nm: Refactor to fix issues found by Codacy
Some ternary operator precedence clarification,
removal of useless variables, etc.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:42:42 +03:00
0c8ceb78a4 nm: Refactor to reduce complexity of nm_suspend()
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:42:42 +03:00
97da8c83ae dcmi: Refactor to simplify read length calculation
Multiple functions use a very complex equation employing
division, modulo, and ternary conditionals to perform a
very simple task of finding the minimum of two values.

Replace all those equations with a call to __min() macro.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:42:42 +03:00
8e4459f3dc Refactor to reduce complexity of dict print funcs
Dictionary print functions (print_valstr, print_valstr_2col,
dcmi_print_strs) are used in various modules and are excessively
complex. One of the reasons is support for loglevel -1, which means
printing to STDOUT. Another reason is support in dcmi_print_strs()
for so called 'horizontal printing' when only strings without
descriptions are printed in one line with separators.

Horizontal printing was in fact broken as dcmi_print_strs() was
always called with loglevel set to LOG_ERR, which resulted in using
lprintf() that adds a '\n' at the end of each printout.

This commit:
* Fixes horizontal printout for dcmi_print_strs();
* Reduces complexity of all three functions by introducing
  a macro helper called uprintf() that automatically chooses
  either printf() or lprintf() based on the selected loglevel;

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:42:17 +03:00
161bb88c6e nm: Refactor to get rid of magic numbers in cmd
Replace all magic numbers for nm commands with enum values.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:33:19 +03:00
67928205e7 nm: Refactor error checking
Make chk_nm_rsp() search for the codes really defined in the
NM dictionary and not just check some arbitrary completion codes
range. For all codes not defined in NM dictionary, print strings
from the generic IPMI completion codes dictionary.

Rename chk_nm_rsp() to is_nm_err() to better reflect the purpose
of the function. Make it 'bool'. Use centralized exiting for the
function.

Also fix wording for invalid NM ID.

End-user-impact: On invalid responses from the NM, instead of
                 "A valid NM command was not returned!" accompanied
                 by a single byte of data, the following message
                 with full 3 bytes of data will now be printed:
                 "No valid NM ID in response!"
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:33:19 +03:00
7469522fbb nm: Refactor to get rid of magic completion codes
Replace all magic numbers implied to mean NM completions codes
with descriptive macro names.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:33:19 +03:00
5372a57297 dcmi: Refactor macro names
Make DCMI command macros more relevant and easy to read.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:33:18 +03:00
be9f1660fb nm: Refactor to reduce code duplication
Add nm_set_id() and nm_check_id() functions, use them and
the existing htoipmi24() to reduce code duplication.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-30 13:31:15 +03:00
e0811437a2 nm: Fix coding style
Fix whitespaces, line lengths, etc.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-29 16:24:39 +03:00
75eada4859 nm: Separate code from dcmi
Move Node Manager related code to separate ipmi_nm.* files.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-29 16:24:39 +03:00
1724b031b3 intf: Add missing function declarations
ipmi_intf.h was missing a couple of declarations for the functions
used by fru, sdr and hpmfwupg modules. Add those declarations
to ipmi_intf.h and remove local declarations.

This fixes a couple of compilation warnings.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-08-29 12:26:40 +03:00
9006f2b26d doc: fix URL in README 2019-08-29 11:54:18 +03:00
b7db637984 event: Clean up event sending from a file
The ipmi_event_fromfile() function was massively repeating the code of
ipmi_send_platform_event() and ipmi_event_msg_print().

This commit cleans up ipmi_event_fromfile() to simply call
ipmi_send_platform_event() with all the prepared data read from the
file. That function in its turn calls ipmi_event_msg_print().

This commit also replaces the dummy generator ID 2 that was printed to
the user with a more relevant generator ID that will actually be sent
by ipmi_send_platform_event().

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-07-02 13:50:12 +03:00
82d6629a66 event: Clean up the event sending code
Get rid of magic numbers, reduce code duplication

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-07-02 13:50:12 +03:00
c396a310ba event: Fix event submission via SSIF
IPMI 2.0 specification is quite inconsistent about system interfaces.

They have section 1.7.16 "System Interfaces" that clearly states that
there are FOUR system interfaces (KCS, SMIC, BT and SSIF), but then they
have section 1.7.31 saying that "It is mandatory to implement a system
interface that is compatible with one of the **three** specified system
interfaces" without specifying which three of the four interfaces are
meant. Then in section 6 "IPMI Messaging interfaces" they again say that
"As mentioned earlier, there are three System Interface implementations
specified for the BMC: SMIC, KCS, and BT". Is all looks like during
update from 1.5 to 2.0 they have updated section 1.7.16, but forgot to
update Table 6-3, section 1.7.31 and section 6. Yet again, there is 'Get
System Interface Capabilities' command that has a parameter 'System
Interface Type' that can specify that SI is of SSIF type.

All that have lead to a situation where some BMC manufacturers treated
the specification as if it prohibited specifying media type 0xC
(which is "System Interface") for system interfaces using SSIF
(SMBus Sustem Interface), and so they specified an SMBUS media type
for their system interface channels.

As a result, ipmitool failed to properly send event data via such
system interfaces as it treated them as non-system and didn't add
the required Generator ID.

To mitigate the inconsistency of IPMI specification and yet not
ask BMC manufacturers to alter their code, thus increasing compatibility
with legacy BMCs, this commit adds checking of current interface number.
The system interface, according to Table 6-1 of IPMI Specification is
required to have channel number 15 (0Fh). So with this commit the
generator ID is added for any interfaces that are either marked
as media type 0Ch 'System Interface' or have channel number 0Fh.

Resolves ipmitool/ipmitool#111

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-07-02 13:50:12 +03:00
002e1d95f5 make: Use DESTDIR to install IANA PEN database
In order to support packaging, installation rules in Makefile
have to obey the specified DESTDIR. That support was missing
and is now added.

Signed-off-by: Andrey Kosteltsev <a.kosteltsev@yadro.com>
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-07-02 11:43:20 +03:00
2ee7aca4e4 lanplus: Fix embedded bridged responses handling
Resolves ipmitool/ipmitool#141

Signed-off-by: Dawid Frycki <dawid.frycki@intel.com>
2019-07-01 16:18:31 +03:00
efd28d1bc1 Update .gitignore
Ignore logs, ViM swap files, and patch rejects and originals.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-25 15:51:29 +03:00
d95775288d mc: Fix reporting of manufacturers > 64K
If a manufacturer's IANA PEN (aka manufacturer ID) was above
65535, it wasn't reported properly. Luckily there are no such
IDs so far, the biggest is 54077 as of 2019/06/18.

There is, however, an ID 0xFFFFFE used by fake_ipmistack
for debug purposes, and it was not reported correctly.

This commit expands the value argument to string searching functions
from 16-bit to 32-bit to allow for any possible IANA PEN.

Fixes: 73d6af5782
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-18 20:07:57 +03:00
ef78ef3792 Add installation of enterprise-numbers database
Download and install the IANA PEN database (enterprise-numbers).

The download is performed using either wget or curl,
and the database is installed into @IANADIR@.

Resolves ipmitool/ipmitool#11

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-18 16:43:41 +03:00
2676ae43fd Update documentation in regard to IANA PEN registry
Add information regarding IANA PEN registry locations into
ipmitool and ipmievd man pages. The locations in man pages are
automatically generated based on `configure` options.

Partially resolves ipmitool/ipmitool#11

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-18 16:43:41 +03:00
54abbaf0e8 Use configurable path to IANA PEN registry
Add support for IANADIR and IANAUSERDIR variables to configure
to allow for customizable locations of system and user-supplied
IANA PEN registry.

Also make path building code portable to Windows.

Partially resolves ipmitool/ipmitool#11

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-18 16:43:41 +03:00
bd0475ce4a Load IANA PEN registry from a file
Previously, the OEM names dictionary was compiled in and
updating it required rebuilding of `ipmitool`, thus taking a
long time for newly registered OEMs to get supported by the tool.

Building also required a direct internet connection to succeed.

With this commit, the OEM enterprise dictionary is now loaded from
either ${HOME}/.local/usr/share/misc/enterprise-numbers or from
/usr/share/misc/enterprise-numbers (in that precedence).

Those files can be downloaded from iana.org at
http://www.iana.org/assignments/enterprise-numbers

Partially resolves ipmitool/ipmitool#11

Fixes: 9d41136c9b
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-18 16:43:41 +03:00
b397a07e9e dbus: Replace obsolete INCLUDES with AM_CPPFLAGS
The `INCLUDES` variable is obsolete, `AM_CPPFLAGS` is the new name.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-13 12:24:07 +03:00
8071cf7389 oem: name change from Newisys to Viking Enterprise Solutions
Renamed the oem strings containing Newisys to Viking Enterprise Solutions.
IANA 9237
Built and tested with AMI's IPMI stack LTS 12.01.

Resolves ipmitool/ipmitool#124

Signed-off-by: dan mcgee <dan.mcgee@vikingenterprise.com>
Signed-off-by: dan mcgee <dan.mcgee@sanmina.com>
2019-06-11 17:58:29 +03:00
ca7767793e Fix default interface to behave as it did before
Prior to 95038ba01b the default interface
was 'open' for builds where it was available and 'lan' otherwise. Due to
a logic error in 95038ba01b, the default
interface was always getting set to lan unless it was specified by the
environment variable. This commit fixes the logic and sets the default
to open if it is available and lan otherwise.

Resolves ipmitool/ipmitool#128

Tested: ./configure # no options reports 'open' as default
        ./configure --enable-intf-open=no # reports lan as default
        ./configure --enable-intf-dbus DEFAULT_INTF=dbus # reports dbus

Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
2019-06-10 14:21:02 +03:00
a45704e5ea man: Add documentation for chassis bootmbox
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-10 13:56:31 +03:00
94f7646a8e man: Update the chassis bootparam section
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-06-10 13:56:31 +03:00
62a04390e1 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 13:56:31 +03:00
de1d5c9924 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-10 13:56:31 +03:00
73d6af5782 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-10 13:56:31 +03:00
c9510635d7 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-10 13:56:31 +03:00
e11f463b4e 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-10 13:56:31 +03:00
33 changed files with 3594 additions and 2347 deletions

7
.gitignore vendored
View File

@ -1,6 +1,10 @@
.deps
.dirstamp
.libs
.*.swp
*.log
*.rej
*.orig
*.o
*.lo
*.la
@ -29,6 +33,7 @@ control/prototype
control/rpmmacros
src/ipmievd
src/ipmitool
lib/ipmi_pen_list.inc.c
doc/ipmievd.8
doc/ipmitool.1
cscope.out
tags

View File

@ -41,11 +41,37 @@ MAINTAINERCLEANFILES = Makefile.in aclocal.m4 configure configure-stamp \
$(distdir).tar.gz $(distdir).tar.bz2
SUBDIRS = lib src include doc contrib control
IANA_PEN = http://www.iana.org/assignments/enterprise-numbers
dist-hook:
cp control/ipmitool.spec $(distdir)
install-data-local:
.PHONY: install-pen-database
if DOWNLOAD
enterprise-numbers:
@echo Downloading IANA PEN database...
@$(DOWNLOAD) "$(IANA_PEN)" > tmpfile.$$PPID || {\
echo "FAILED to download the IANA PEN database"; \
rm tmpfile.$$PPID; \
false; \
}
@mv tmpfile.$$PPID $@
install-pen-database: enterprise-numbers
mkdir -m 755 -p $(DESTDIR)$(IANADIR)
$(INSTALL_DATA) $< -t $(DESTDIR)$(IANADIR)/
else
install-pen-database:
@echo "*** NOT installing the IANA PEN database."
@echo "*** Don't know how to download it."
endif
install-data-local: install-pen-database
mkdir -p $(DESTDIR)$(DOCDIR)
$(INSTALL_DATA) $(DOCLIST) $(DESTDIR)$(DOCDIR)

2
README
View File

@ -399,7 +399,7 @@ IPMItool homepage
http://github.com/ipmitool/ipmitool
IPMItool manpage
https://github.com/ipmitool/ipmitool/blob/master/doc/ipmitool.1
https://github.com/ipmitool/ipmitool/blob/master/doc/ipmitool.1.in
Intelligent Platform Management Interface specification
https://www.intel.com/content/www/us/en/servers/ipmi/ipmi-home.html

View File

@ -4,6 +4,7 @@ dnl
m4_define([git_suffix], m4_esyscmd_s(./csv-revision))
AC_INIT([ipmitool], [1.8.18git_suffix])
AC_CONFIG_SRCDIR([src/ipmitool.c])
AC_CONFIG_COMMANDS_PRE([export prefix=$prefix])
AC_CANONICAL_SYSTEM
AM_INIT_AUTOMAKE([foreign])
AM_CONFIG_HEADER(config.h)
@ -17,6 +18,8 @@ AC_PROG_LN_S
AC_PROG_MAKE_SET
AC_CHECK_PROG([RPMBUILD], [rpmbuild], [rpmbuild], [rpm])
AC_CHECK_PROG([SED], [sed], [sed])
AC_CHECK_PROG([WGET], [wget], [wget])
AC_CHECK_PROG([CURL], [curl], [curl])
AC_HEADER_STDC
AC_CHECK_HEADERS([stdlib.h string.h sys/ioctl.h sys/stat.h unistd.h paths.h])
@ -53,6 +56,23 @@ if test "x$exec_prefix" = "xNONE"; then
exec_prefix="$prefix"
fi
if test "x$WGET" = "x"; then
if test "x$CURL" = "x"; then
AC_MSG_WARN([** Neither wget nor curl could be found.])
AC_MSG_WARN([** IANA PEN database will not be installed by `make install` !])
else
DOWNLOAD="$CURL -#"
AM_CONDITIONAL([DOWNLOAD], [true])
fi
else
DOWNLOAD="$WGET -c -nd -O -"
AM_CONDITIONAL([DOWNLOAD], [true])
fi
AC_MSG_WARN([** Download is:])
AC_MSG_WARN($DOWNLOAD)
AC_SUBST(DOWNLOAD, $DOWNLOAD)
dnl
dnl set default option values
dnl
@ -672,13 +692,13 @@ AC_TRY_COMPILE([],[
)
dnl if no environment variable is set, set the default value for the default intf
if test "${xenable_intf_open}" = "xyes"; then
if test "${xenable_intf_open}" = "yes"; 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})])
AC_ARG_VAR(DEFAULT_INTF, [Set the default interface to use (default='open' if available, 'lan' otherwise)])
dnl set the default value for the default interface environment variable
if test "x${DEFAULT_INTF}" == "x"; then
@ -691,6 +711,32 @@ 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
AC_ARG_VAR(IANADIR, [Configure the path to IANA PEN dictionary (default=DATAROOTDIR/misc)])
AC_ARG_VAR(IANAUSERDIR, [Configure the path to IANA PEN dictionary wihtin the user's HOME directory (default=.local/usr/share/misc)])
if test "x${IANADIR}" == "x"; then
echo Set IANA PEN dictionary search path to ${datarootdir}/misc
IANADIR="${datarootdir}/misc"
fi
if test "x${IANAUSERDIR}" == "x"; then
IANAUSERDIR=".local/usr/share/misc"
echo Set user\'s IANA PEN dictionary search path to ${IANAUSERDIR}
fi
AH_TEMPLATE([IANADIR],[The path to system IANA PEN dictionary])
AC_DEFINE_UNQUOTED(IANADIR, "`eval "echo ${IANADIR}"`", [])
AH_TEMPLATE([IANAUSERDIR],[The subpath to user IANA PEN dictionary within the user's HOME])
AC_DEFINE_UNQUOTED(IANAUSERDIR, "`eval "echo ${IANAUSERDIR}"`", [])
AH_TEMPLATE([PATH_SEPARATOR], [The path separator string])
#if defined _WIN32 || defined __CYGWIN__
AC_DEFINE(PATH_SEPARATOR, "\\")
#else
AC_DEFINE(PATH_SEPARATOR, "/")
#endif
dnl Generate files for build
AC_CONFIG_FILES([Makefile
doc/Makefile
@ -717,6 +763,9 @@ AC_CONFIG_FILES([Makefile
src/plugins/serial/Makefile
src/plugins/dummy/Makefile])
AC_CONFIG_FILES([doc/ipmitool.1], [${SED} -i -e "s%\${prefix}%$prefix%" doc/ipmitool.1])
AC_CONFIG_FILES([doc/ipmievd.8], [${SED} -i -e "s%\${prefix}%$prefix%" doc/ipmievd.8])
AC_OUTPUT
AC_MSG_RESULT([])

View File

@ -217,6 +217,16 @@ Reading Sensors...
.br
Waiting for Events...
.br
.SH FILES
.TP
.B @IANADIR@/enterprise-numbers
system IANA PEN registry taken from http://www.iana.org/assignments/enterprise-numbers
.TP
.B ~/@IANAUSERDIR@/enterprise-numbers
user's override for the system IANA PEN registry, this file if it exists is loaded instead
of the system registry (see above).
.SH "AUTHOR"
Duncan Laurie <duncan@iceblink.org>
.SH "SEE ALSO"

View File

@ -473,36 +473,94 @@ Force boot into BIOS Setup.
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
\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
.TP
\fIforce_disk\fP
.IP \fIforce_disk\fP
Force boot from default Hard-drive
.TP
\fIforce_safe\fP
.IP \fIforce_safe\fP
Force boot from default Hard-drive, request Safe Mode
.TP
\fIforce_diag\fP
.IP \fIforce_diag\fP
Force boot from Diagnostic Partition
.TP
\fIforce_cdrom\fP
.IP \fIforce_cdrom\fP
Force boot from CD/DVD
.TP
\fIforce_bios\fP
.IP \fIforce_bios\fP
Force boot into BIOS Setup
.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
Get the chassis self-test results
.RE
.TP
\fIdcmi\fP
@ -3759,7 +3817,16 @@ Chassis Power is on
> ipmitool \-I lan \-H 1.2.3.4 \-f passfile chassis power on
.br
Chassis Power Control: Up/On
.SH FILES
.TP
.B @IANADIR@/enterprise-numbers
system IANA PEN registry taken from http://www.iana.org/assignments/enterprise-numbers
.TP
.B ~/@IANAUSERDIR@/enterprise-numbers
user's override for the system IANA PEN registry, this file if it exists is loaded instead
of the system registry (see above).
.SH "AUTHORS"
Originally written by Duncan Laurie <duncan@iceblink.org>.
.br

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,8 +80,12 @@ struct oemvalstr {
const char * str;
};
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 *
specific_val2str(uint32_t val,
const struct valstr *specific,
const struct valstr *generic);
const char *val2str(uint32_t val, const struct valstr * vs);
const char *oemval2str(uint32_t oem, uint32_t val, const struct oemvalstr * vs);
int str2double(const char * str, double * double_ptr);
int str2long(const char * str, int64_t * lng_ptr);
@ -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);
@ -99,7 +106,11 @@ int is_ipmi_channel_num(const char *argv_ptr, uint8_t *channel_ptr);
int is_ipmi_user_id(const char *argv_ptr, uint8_t *ipmi_uid_ptr);
int is_ipmi_user_priv_limit(const char *argv_ptr, uint8_t *ipmi_priv_limit_ptr);
uint16_t str2val(const char * str, const struct valstr * vs);
uint32_t str2val32(const char *str, const struct valstr *vs);
static inline uint16_t str2val(const char *str, const struct valstr *vs)
{
return (uint16_t)str2val32(str, vs);
}
void print_valstr(const struct valstr * vs, const char * title, int loglevel);
void print_valstr_2col(const struct valstr * vs, const char * title, int loglevel);
@ -166,6 +177,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

@ -283,7 +283,7 @@ typedef enum IPMI_OEM {
IPMI_OEM_MAGNUM = 5593,
IPMI_OEM_TYAN = 6653,
IPMI_OEM_QUANTA = 7244,
IPMI_OEM_NEWISYS = 9237,
IPMI_OEM_VIKING = 9237,
IPMI_OEM_ADVANTECH = 10297,
IPMI_OEM_FUJITSU_SIEMENS = 10368,
IPMI_OEM_AVOCENT = 10418,

View File

@ -57,6 +57,28 @@
#define IPMI_CHANNEL_SESSION_MULTI 0x80
#define IPMI_CHANNEL_SESSION_BASED 0xC0
/* Fixed channel numbers as per Table 6-1 */
typedef enum {
CH_PRIMARY_IPMB,
CH_IMP_SPECIFIC_1,
CH_IMP_SPECIFIC_2,
CH_IMP_SPECIFIC_3,
CH_IMP_SPECIFIC_4,
CH_IMP_SPECIFIC_5,
CH_IMP_SPECIFIC_6,
CH_IMP_SPECIFIC_7,
CH_IMP_SPECIFIC_8,
CH_IMP_SPECIFIC_9,
CH_IMP_SPECIFIC_A,
CH_IMP_SPECIFIC_B,
CH_RSVD1,
CH_RSVD2,
CH_CURRENT,
CH_SYSTEM,
CH_TOTAL,
CH_UNKNOWN = UINT8_MAX
} ipmi_channel_num_t;
/* (22.24) Get Channel Info */
struct channel_info_t {
uint8_t channel;
@ -189,7 +211,8 @@ int _ipmi_set_channel_access(struct ipmi_intf *intf,
uint8_t privilege_option);
uint8_t ipmi_get_channel_medium(struct ipmi_intf * intf, uint8_t channel);
uint8_t ipmi_current_channel_medium(struct ipmi_intf * intf);
void ipmi_current_channel_info(struct ipmi_intf *intf,
struct channel_info_t *chinfo);
int ipmi_channel_main(struct ipmi_intf * intf, int argc, char ** argv);
int ipmi_get_channel_auth_cap(struct ipmi_intf * intf,
uint8_t channel, uint8_t priv);

View File

@ -24,23 +24,22 @@
/* DCMI commands per DCMI 1.5 SPEC */
#define IPMI_DCMI 0xDC /* Group Extension Identification */
#define IPMI_DCMI_COMPAT 0x01
#define IPMI_DCMI_GETRED 0x02
#define IPMI_DCMI_GETLMT 0x03
#define IPMI_DCMI_SETLMT 0x04
#define IPMI_DCMI_PWRACT 0x05
#define IPMI_DCMI_GETASSET 0x06
#define IPMI_DCMI_SETASSET 0x08
#define IPMI_DCMI_GETMNGCTRLIDS 0x09
#define IPMI_DCMI_SETMNGCTRLIDS 0x0A
#define IPMI_DCMI_SETTERMALLIMIT 0x0B
#define IPMI_DCMI_GETTERMALLIMIT 0x0C
#define IPMI_DCMI_GETSNSR 0x07
#define IPMI_DCMI_PWRMGT 0x08
#define IPMI_DCMI_GETTEMPRED 0x10
#define IPMI_DCMI_SETCONFPARAM 0x12
#define IPMI_DCMI_GETCONFPARAM 0x13
#define IPMI_DCMI 0xDC /* Group Extension Identification */
#define IPMI_DCMI_GET_CAPS 0x01 /* Get Capabilities */
#define IPMI_DCMI_GET_PWR_READING 0x02 /* Get Power Reading */
#define IPMI_DCMI_GET_PWR_LIM 0x03 /* Get Power Limit */
#define IPMI_DCMI_SET_PWR_LIM 0x04 /* Set Power Limit */
#define IPMI_DCMI_ACT_PWR_LIM 0x05 /* Activate/Deactivate Power Limit */
#define IPMI_DCMI_GET_ASSET_TAG 0x06 /* Get Asset Tag */
#define IPMI_DCMI_SET_ASSET_TAG 0x08 /* Set Asset Tag */
#define IPMI_DCMI_GET_MC_ID 0x09 /* Get Management Controller ID String */
#define IPMI_DCMI_SET_MC_ID 0x0A /* Set Management Controller ID String */
#define IPMI_DCMI_SET_THERM_LIM 0x0B /* Set Thermal Limit */
#define IPMI_DCMI_GET_THERM_LIM 0x0C /* Get Thermal Limit */
#define IPMI_DCMI_GET_SENSOR_INFO 0x07 /* Get DCMI Sensor Info */
#define IPMI_DCMI_GET_TEMP 0x10 /* Get Temperature Readings */
#define IPMI_DCMI_SET_CONF_PARAM 0x12 /* Set DCMI Configuration Parameters */
#define IPMI_DCMI_GET_CONF_PARAM 0x13 /* Get DCMI Configuration Parameters */
#define IPMI_DCMI_CONFORM 0x0001
#define IPMI_DCMI_1_1_CONFORM 0x0101
@ -52,53 +51,6 @@
#define GOOD_PWR_GLIMIT_CCODE(ccode) ((ccode = ((ccode == 0x80) ? 0 : ccode)))
#define GOOD_ASSET_TAG_CCODE(ccode) ((ccode = (((ccode == 0x80) || (ccode == 0x81) || (ccode == 0x82) || (ccode == 0x83)) ? 0 : ccode)))
/* External Node Manager Configuration and Control Commands per spec 2.0 */
#define IPMI_NM_POLICY_CTL 0xC0
#define IPMI_NM_SET_POLICY 0xC1
#define IPMI_NM_GET_POLICY 0xC2
#define IPMI_NM_SET_ALERT_TH 0xC3
#define IPMI_NM_GET_ALERT_TH 0xC4
#define IPMI_NM_SET_SUSPEND 0xC5
#define IPMI_NM_GET_SUSPEND 0xC6
#define IPMI_NM_RESET_STATS 0xC7
#define IPMI_NM_GET_STATS 0xC8
#define IPMI_NM_GET_CAP 0xC9
#define IPMI_NM_GET_VERSION 0xCA
#define IPMI_NM_SET_POWER 0xCB
#define IPMI_NM_SET_ALERT_DS 0xCE
#define IPMI_NM_GET_ALERT_DS 0xCF
#define IPMI_NM_LIMITING 0xF2
/* Node Manager Policy Control Flags */
#define IPMI_NM_GLOBAL_ENABLE 0x01
#define IPMI_NM_DOMAIN_ENABLE 0x02
#define IPMI_NM_PER_POLICY_ENABLE 0x04
/* Node Manager Set Policy Enable */
#define IPMI_NM_POLICY_ENABLE 0x10
/* Node Manager Policy Trigger Codes */
#define IPMI_NM_NO_POLICY_TRIG 0x00
#define IPMI_NM_TEMP_TRIGGER 0x01
#define IPMI_NM_NO_READ_TRIG 0x02
#define IPMI_NM_RESET_TRIGGER 0x03
#define IPMI_NM_BOOT_TRIGGER 0x04
/* Policy Exception Actions flags */
#define IPMI_NM_POLICY_ALERT 0x01
#define IPMI_NM_POLICY_SHUT 0x02
/* Power Correction codes for Policy action */
#define IPMI_NM_PWR_AUTO_CORR 0x00
#define IPMI_NM_PWR_SOFT_CORR 0x01
#define IPMI_NM_PWR_AGGR_CORR 0x02
/* Set Threshold message size */
#define IPMI_NM_SET_THRESH_LEN 12
/* Number of Suspend Periods */
#define IPMI_NM_SUSPEND_PERIOD_MAX 5
struct dcmi_cmd {
uint16_t val;
@ -106,6 +58,13 @@ struct dcmi_cmd {
const char * desc;
};
/*
* This is a termination macro for all struct dcmi_cmd arrays,
* def argument is the default value returned by str2val2()
* when string is not found in the array
*/
#define DCMI_CMD_END(def) { (def), NULL, NULL }
/* make a struct for the return from the get limit command */
struct power_limit {
uint8_t grp_id; /* first byte: Group Extension ID */
@ -172,99 +131,11 @@ struct thermal_limit {
} __attribute__ ((packed));
int ipmi_dcmi_main(struct ipmi_intf * intf, int argc, char ** argv);
uint16_t dcmi_str2val(const char *str, const struct dcmi_cmd *vs);
const char *dcmi_val2str(uint16_t val, const struct dcmi_cmd *vs);
void dcmi_print_strs(const struct dcmi_cmd * vs,
const char * title,
int loglevel,
int verthorz);
/* Node Manager discover command */
struct nm_discover {
uint8_t intel_id[3]; /* Always returns 000157 */
uint8_t nm_version;
uint8_t ipmi_version;
uint8_t patch_version;
uint8_t major_rev;
uint8_t minor_rev;
} __attribute__ ((packed));
/* Node Manager get capabilities command */
struct nm_capability {
uint8_t intel_id[3];
uint8_t max_settings;
uint16_t max_value; /* max power/thermal/time after reset */
uint16_t min_value; /* min "" */
uint32_t min_corr; /* min correction time inmillesecs */
uint32_t max_corr;
uint16_t min_stats;
uint16_t max_stats;
uint8_t scope;
} __attribute__ ((packed));
/* Node Manager get statistics command */
struct nm_statistics {
uint8_t intel_id[3];
uint16_t curr_value;
uint16_t min_value;
uint16_t max_value;
uint16_t ave_value;
uint32_t time_stamp;
uint32_t stat_period;
uint8_t id_state;
} __attribute__ ((packed));
/* Node Manager set policy */
struct nm_policy {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_id;
uint8_t policy_type; /* 0:3 trigger type 4 = action 5:6 correction */
uint8_t policy_exception; /* exception actions */
uint16_t policy_limits;
uint32_t corr_time;
uint16_t trigger_limit;
uint16_t stats_period;
} __attribute__ ((packed));
/* Node Maager get policy */
struct nm_get_policy {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_type; /* 0:3 trigger type 4 = action 5:6 correction */
uint8_t policy_exception; /* exception actions */
uint16_t policy_limits;
uint32_t corr_time;
uint16_t trigger_limit;
uint16_t stats_period;
} __attribute__ ((packed));
/* Node Manager set alert destination */
struct nm_set_alert {
uint8_t intel_id[3];
uint8_t chan; /* 0:3 BMC chan, 4:6 reserved, bit 7=0 register alert receiver =1 invalidate */
uint8_t dest; /* lan destination */
uint8_t string; /* alert string selector */
} __attribute__ ((packed));
/* Node Manager set alert threshold */
struct nm_thresh {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_id;
uint8_t count;
uint16_t thresholds[3];
} __attribute__ ((packed));
/* Node Manager suspend period struct */
struct nm_period {
uint8_t start;
uint8_t stop;
uint8_t repeat;
} __attribute__ ((packed));
/* Node Manager set suspend period */
struct nm_suspend {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_id;
uint8_t count;
struct nm_period period[IPMI_NM_SUSPEND_PERIOD_MAX];
} __attribute__ ((packed));
int ipmi_nm_main(struct ipmi_intf * intf, int argc, char ** argv);
#endif /*IPMI_DCMI_H*/

View File

@ -61,6 +61,33 @@ struct platform_event_msg {
#pragma pack(0)
#endif
/* See IPMI 2.0 Specification, Appendix G, Table G-1, "Event Commands" */
typedef enum {
IPMI_CMD_SET_EVENT_RCVR = 0,
IPMI_CMD_GET_EVENT_RCVR,
IPMI_CMD_PLATFORM_EVENT
} ipmi_event_cmd_t;
typedef enum {
PLATFORM_EVENT_DATA_LEN_NON_SI = sizeof(struct platform_event_msg),
PLATFORM_EVENT_DATA_LEN_SI, /* System interfaces require generator ID */
PLATFORM_EVENT_DATA_LEN_MAX = PLATFORM_EVENT_DATA_LEN_SI
} ipmi_platform_event_data_len_t;
/* See Table 5-4 */
typedef enum {
EVENT_SWID_BIOS_BASE = 0x00, /* BIOS */
EVENT_SWID_SMI_BASE = 0x10, /* SMI Handler */
EVENT_SWID_SMS_BASE = 0x20, /* System Management Software */
EVENT_SWID_OEM_BASE = 0x30, /* OEM */
EVENT_SWID_REMOTE_CONSOLE_BASE = 0x40, /* Remote Console SW */
EVENT_SWID_TERMINAL_MODE_BASE = 0x47 /* Terminal Mode RC SW */
} ipmi_event_swid_t;
#define EVENT_SWID(base, index) ((EVENT_SWID_##base##_BASE + index) & 0x7F)
/* See Figure 29-2, Table 32-1 */
#define EVENT_GENERATOR(base, index) (EVENT_SWID(base,index) << 1 | 1)
int ipmi_event_main(struct ipmi_intf *, int, char **);
#endif /*IPMI_EVENT_H*/

View File

@ -241,6 +241,9 @@ struct ipmi_intf {
void (*set_max_response_data_size)(struct ipmi_intf * intf, uint16_t size);
};
uint16_t ipmi_intf_get_max_request_data_size(struct ipmi_intf *intf);
uint16_t ipmi_intf_get_max_response_data_size(struct ipmi_intf *intf);
struct ipmi_intf * ipmi_intf_load(char * name);
void ipmi_intf_print(struct ipmi_intf_support * intflist);

202
include/ipmitool/ipmi_nm.h Normal file
View File

@ -0,0 +1,202 @@
/*
* Copyright (C) 2008 Intel Corporation.
* All rights reserved
*
* 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 OWNER 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.
*
*/
#pragma once
#include <ipmitool/ipmi.h>
#include <ipmitool/helper.h>
/* Configuration and control commands per
* Intel Intelligent Power Node Manager 2.0
* External Interface Specification Using IPMI
*/
#define IPMI_NM_POLICY_CTL 0xC0
#define IPMI_NM_SET_POLICY 0xC1
#define IPMI_NM_GET_POLICY 0xC2
#define IPMI_NM_SET_ALERT_TH 0xC3
#define IPMI_NM_GET_ALERT_TH 0xC4
#define IPMI_NM_SET_SUSPEND 0xC5
#define IPMI_NM_GET_SUSPEND 0xC6
#define IPMI_NM_RESET_STATS 0xC7
#define IPMI_NM_GET_STATS 0xC8
#define IPMI_NM_GET_CAP 0xC9
#define IPMI_NM_GET_VERSION 0xCA
#define IPMI_NM_SET_POWER 0xCB
#define IPMI_NM_SET_ALERT_DS 0xCE
#define IPMI_NM_GET_ALERT_DS 0xCF
#define IPMI_NM_LIMITING 0xF2
/* Node Manager identification */
#define IPMI_NM_ID 0x000157 /* Three bytes */
/* Node Manager Policy Control Flags */
#define IPMI_NM_GLOBAL_ENABLE 0x01
#define IPMI_NM_DOMAIN_ENABLE 0x02
#define IPMI_NM_PER_POLICY_ENABLE 0x04
/* Node Manager Set Policy Enable */
#define IPMI_NM_POLICY_ENABLE 0x10
/* Node Manager Policy Trigger Codes */
#define IPMI_NM_NO_POLICY_TRIG 0x00
#define IPMI_NM_TEMP_TRIGGER 0x01
#define IPMI_NM_NO_READ_TRIG 0x02
#define IPMI_NM_RESET_TRIGGER 0x03
#define IPMI_NM_BOOT_TRIGGER 0x04
/* Node Manager status codes, as per
* "Intel Intelligent Power Node Manager 3.0
* External Interface Specification using IPMI"
*/
#define IPMI_NM_CC_POLICY_ID_INVALID 0x80
#define IPMI_NM_CC_POLICY_DOMAIN_INVALID 0x81
#define IPMI_NM_CC_POLICY_TRIGGER_UNKNOWN 0x82
#define IPMI_NM_CC_POLICY_CORRECTION_RANGE 0x85
#define IPMI_NM_CC_POLICY_TRIGGER_RANGE 0x86
#define IPMI_NM_CC_POLICY_STATS_RANGE 0x89
#define IPMI_NM_CC_POLICY_LIMIT_NONE 0xA1
#define IPMI_NM_CC_POLICY_PARAM_BUSY 0xD5
#define IPMI_NM_CC_POLICY_DOMAIN_ERR 0xD6
#define IPMI_NM_CC_POLICY_VALUE_INVALID 0x8B
#define IPMI_NM_CC_STATS_MODE_INVALID 0x88
#define IPMI_NM_CC_POWER_LIMIT_RANGE 0x84
/* Policy Exception Actions flags */
#define IPMI_NM_POLICY_ALERT 0x01
#define IPMI_NM_POLICY_SHUT 0x02
/* Power Correction codes for Policy action */
#define IPMI_NM_PWR_AUTO_CORR 0x00
#define IPMI_NM_PWR_SOFT_CORR 0x01
#define IPMI_NM_PWR_AGGR_CORR 0x02
/* Set Threshold message size */
#define IPMI_NM_SET_THRESH_LEN 12
/* Number of Suspend Periods */
#define IPMI_NM_SUSPEND_PERIOD_MAX 5
/* Node Manager discover command */
struct nm_discover {
uint8_t intel_id[3]; /* Always returns 000157 */
uint8_t nm_version;
uint8_t ipmi_version;
uint8_t patch_version;
uint8_t major_rev;
uint8_t minor_rev;
} __attribute__ ((packed));
/* Node Manager get capabilities command */
struct nm_capability {
uint8_t intel_id[3];
uint8_t max_settings;
uint16_t max_value; /* max power/thermal/time after reset */
uint16_t min_value; /* min "" */
uint32_t min_corr; /* min correction time inmillesecs */
uint32_t max_corr;
uint16_t min_stats;
uint16_t max_stats;
uint8_t scope;
} __attribute__ ((packed));
/* Node Manager get statistics command */
struct nm_statistics {
uint8_t intel_id[3];
uint16_t curr_value;
uint16_t min_value;
uint16_t max_value;
uint16_t ave_value;
uint32_t time_stamp;
uint32_t stat_period;
uint8_t id_state;
} __attribute__ ((packed));
/* Node Manager set policy */
struct nm_policy {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_id;
uint8_t policy_type; /* 0:3 trigger type 4 = action 5:6 correction */
uint8_t policy_exception; /* exception actions */
uint16_t policy_limits;
uint32_t corr_time;
uint16_t trigger_limit;
uint16_t stats_period;
} __attribute__ ((packed));
/* Node Maager get policy */
struct nm_get_policy {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_type; /* 0:3 trigger type 4 = action 5:6 correction */
uint8_t policy_exception; /* exception actions */
uint16_t policy_limits;
uint32_t corr_time;
uint16_t trigger_limit;
uint16_t stats_period;
} __attribute__ ((packed));
/* Node Manager set alert destination */
struct nm_set_alert {
uint8_t intel_id[3];
uint8_t chan; /* 0:3 BMC chan
* 4:6 reserved
* 7 = 0 register alert receiver
* = 1 invalidate
*/
uint8_t dest; /* LAN destination */
uint8_t string; /* alert string selector */
} __attribute__ ((packed));
/* Node Manager set alert threshold */
struct nm_thresh {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_id;
uint8_t count;
uint16_t thresholds[3];
} __attribute__ ((packed));
/* Node Manager suspend period struct */
struct nm_period {
uint8_t start;
uint8_t stop;
uint8_t repeat;
} __attribute__ ((packed));
/* Node Manager set suspend period */
struct nm_suspend {
uint8_t intel_id[3];
uint8_t domain; /* 0:3 are domain, 4 = Policy enabled */
uint8_t policy_id;
uint8_t count;
struct nm_period period[IPMI_NM_SUSPEND_PERIOD_MAX];
} __attribute__ ((packed));
int ipmi_nm_main(struct ipmi_intf *intf, int argc, char **argv);
static inline void nm_set_id(void *buf)
{
htoipmi24(IPMI_NM_ID, buf);
}
static inline bool nm_check_id(void *buf)
{
return IPMI_NM_ID == ipmi24toh(buf);
}

View File

@ -679,7 +679,7 @@ void ipmi_sel_print_extended_entry_verbose(struct ipmi_intf * intf, struct sel_e
void ipmi_get_event_desc(struct ipmi_intf * intf, struct sel_event_record * rec, char ** desc);
const char * ipmi_get_sensor_type(struct ipmi_intf *intf, uint8_t code);
uint16_t ipmi_sel_get_std_entry(struct ipmi_intf * intf, uint16_t id, struct sel_event_record * evt);
char * get_newisys_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec);
char * get_viking_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec);
IPMI_OEM ipmi_get_oem(struct ipmi_intf * intf);
char * ipmi_get_oem_desc(struct ipmi_intf * intf, struct sel_event_record * rec);
int ipmi_sel_oem_init(const char * filename);

View File

@ -53,8 +53,10 @@ extern const struct valstr ipmi_chassis_power_control_vals[];
extern const struct valstr ipmi_auth_algorithms[];
extern const struct valstr ipmi_integrity_algorithms[];
extern const struct valstr ipmi_encryption_algorithms[];
extern const struct valstr ipmi_oem_info[];
extern const struct valstr ipmi_user_enable_status_vals[];
extern const struct valstr *ipmi_oem_info;
int ipmi_oem_info_init();
void ipmi_oem_info_free();
extern const struct valstr picmg_frucontrol_vals[];
extern const struct valstr picmg_clk_family_vals[];

View File

@ -59,5 +59,17 @@ int log_level_get(void);
void lprintf(int level, const char * format, ...);
void lperror(int level, const char * format, ...);
/**
* @brief Print to log or to STDOUT depending on the \p ll argument.
* @param[in] ll Log level. Negative values meant "print to stdout".
* @param[in] fmt The printf format string. No '\n' is needed at the end.
*/
#define uprintf(ll, fmt, ...) do { \
if (ll < 0) \
printf(fmt "\n", ##__VA_ARGS__); \
else \
lprintf(ll, fmt, ##__VA_ARGS__); \
} while(0)
#endif /*IPMITOOL_LOG_H*/

View File

@ -31,7 +31,6 @@
AUTOMAKE_OPTIONS = subdir-objects
AM_CPPFLAGS = -I$(top_srcdir)/include
MAINTAINERCLEANFILES = Makefile.in
PEN_LIST = $(srcdir)/ipmi_pen_list.inc.c
noinst_LTLIBRARIES = libipmitool.la
libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \
@ -41,7 +40,7 @@ libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \
ipmi_oem.c ipmi_isol.c ipmi_sunoem.c ipmi_fwum.c ipmi_picmg.c \
ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c \
ipmi_hpmfwupg.c ipmi_sdradd.c ipmi_ekanalyzer.c ipmi_gendev.c \
ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c hpm2.c ipmi_vita.c \
ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c ipmi_nm.c hpm2.c ipmi_vita.c \
ipmi_lanp6.c ipmi_cfgp.c ipmi_quantaoem.c ipmi_time.c \
../src/plugins/lan/md5.c ../src/plugins/lan/md5.h
@ -49,8 +48,3 @@ libipmitool_la_LDFLAGS = -export-dynamic
libipmitool_la_LIBADD = -lm
libipmitool_la_DEPENDENCIES =
$(PEN_LIST):
$(srcdir)/create_pen_list $(PEN_LIST)
ipmi_strings.lo: $(PEN_LIST)

View File

@ -1,77 +0,0 @@
#!/bin/bash
# vi: set ts=2 sw=2 et :
#
# IANA PEN List generator
#
# This script takes the official IANA PEN registry and generates
# a C language output for inclusion into ipmi_strings.c
#
# Copyright (c) 2018 Alexander Amelkin <alexander@amelkin.msk.ru>
#
# 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.
#
OUTFILE=$1
PENLIST_URL=https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
if [ -z "$OUTFILE" ]; then
echo $0: Must specify output file
exit
fi
parse_pen_list() {
iconv -f utf8 -t ascii//TRANSLIT//IGNORE \
| awk '
/^[0-9]+/ {
if(PEN) {
print "{ " PEN ", \"" ENTERPRISE "\" },"
}
PEN=$1
}
/^ [[:alnum:]]/ {
# Remove leading spaces
sub(/^[[:space:]]+/,"")
# Remove question marks (Chinese characters after iconv)
gsub(/\?/,"");
# Remove non-printable characters
gsub(/[^[:print:]]/,"");
# Escape slashes and double quotes
gsub(/["\\]/,"\\\\&")
ENTERPRISE=$0;
}
END {
if(PEN) {
print "{ " PEN ", \"" ENTERPRISE "\" },"
}
}'
}
echo "Generating IANA PEN list..."
curl -# "$PENLIST_URL" | parse_pen_list > "$OUTFILE"

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(uint32_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(uint32_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 * oemval2str(uint32_t oem, uint16_t val,
const struct oemvalstr *vs)
const char *
specific_val2str(uint32_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(uint32_t val, const struct valstr *vs)
{
return specific_val2str(val, NULL, vs);
}
const char *oemval2str(uint32_t oem, uint32_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
@ -597,7 +642,7 @@ int str2uchar(const char * str, uint8_t * uchr_ptr)
return 0;
} /* str2uchar(...) */
uint16_t str2val(const char *str, const struct valstr *vs)
uint32_t str2val32(const char *str, const struct valstr *vs)
{
int i;
@ -624,38 +669,22 @@ print_valstr(const struct valstr * vs, const char * title, int loglevel)
return;
if (title) {
if (loglevel < 0)
printf("\n%s:\n\n", title);
else
lprintf(loglevel, "\n%s:\n", title);
uprintf(loglevel, "\n%s:\n", title);
}
if (loglevel < 0) {
printf(" VALUE\tHEX\tSTRING\n");
printf("==============================================\n");
} else {
lprintf(loglevel, " VAL\tHEX\tSTRING");
lprintf(loglevel, "==============================================");
}
uprintf(loglevel, " VALUE\tHEX\tSTRING");
uprintf(loglevel, "==============================================");
for (i = 0; vs[i].str; i++) {
if (loglevel < 0) {
if (vs[i].val < 256)
printf(" %d\t0x%02x\t%s\n", vs[i].val, vs[i].val, vs[i].str);
else
printf(" %d\t0x%04x\t%s\n", vs[i].val, vs[i].val, vs[i].str);
} else {
if (vs[i].val < 256)
lprintf(loglevel, " %d\t0x%02x\t%s", vs[i].val, vs[i].val, vs[i].str);
else
lprintf(loglevel, " %d\t0x%04x\t%s", vs[i].val, vs[i].val, vs[i].str);
}
if (vs[i].val < 256)
uprintf(loglevel, " %d\t0x%02x\t%s",
vs[i].val, vs[i].val, vs[i].str);
else
uprintf(loglevel, " %d\t0x%04x\t%s",
vs[i].val, vs[i].val, vs[i].str);
}
if (loglevel < 0)
printf("\n");
else
lprintf(loglevel, "");
uprintf(loglevel, "");
}
/* print_valstr_2col - print value string list in two columns to log or stdout
@ -673,37 +702,22 @@ print_valstr_2col(const struct valstr * vs, const char * title, int loglevel)
return;
if (title) {
if (loglevel < 0)
printf("\n%s:\n\n", title);
else
lprintf(loglevel, "\n%s:\n", title);
uprintf(loglevel, "\n%s:\n", title);
}
for (i = 0; vs[i].str; i++) {
if (!vs[i+1].str) {
/* last one */
if (loglevel < 0) {
printf(" %4d %-32s\n", vs[i].val, vs[i].str);
} else {
lprintf(loglevel, " %4d %-32s\n", vs[i].val, vs[i].str);
}
uprintf(loglevel, " %4d %-32s\n", vs[i].val, vs[i].str);
}
else {
if (loglevel < 0) {
printf(" %4d %-32s %4d %-32s\n",
vs[i].val, vs[i].str, vs[i+1].val, vs[i+1].str);
} else {
lprintf(loglevel, " %4d %-32s %4d %-32s\n",
vs[i].val, vs[i].str, vs[i+1].val, vs[i+1].str);
}
uprintf(loglevel, " %4d %-32s %4d %-32s\n",
vs[i].val, vs[i].str, vs[i+1].val, vs[i+1].str);
i++;
}
}
if (loglevel < 0)
printf("\n");
else
lprintf(loglevel, "");
uprintf(loglevel, ""); /* Empty spacer line */
}
/* ipmi_csum - calculate an ipmi checksum
@ -1080,3 +1094,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

@ -244,10 +244,28 @@ ipmi_1_5_authtypes(uint8_t n)
return supportedTypes;
}
uint8_t
ipmi_current_channel_medium(struct ipmi_intf *intf)
void
ipmi_current_channel_info(struct ipmi_intf *intf,
struct channel_info_t *chinfo)
{
return ipmi_get_channel_medium(intf, 0xE);
int ccode = 0;
chinfo->channel = CH_CURRENT;
ccode = _ipmi_get_channel_info(intf, chinfo);
if (ccode) {
if (ccode != IPMI_CC_INV_DATA_FIELD_IN_REQ) {
if (ccode > 0) {
lprintf(LOG_ERR, "Get Channel Info command failed: %s",
val2str(ccode, completion_code_vals));
}
else {
eval_ccode(ccode);
}
}
chinfo->channel = CH_UNKNOWN;
chinfo->medium = IPMI_CHANNEL_MEDIUM_RESERVED;
}
return;
}
/**
@ -684,13 +702,16 @@ ipmi_get_channel_medium(struct ipmi_intf *intf, uint8_t channel)
channel_info.channel = channel;
ccode = _ipmi_get_channel_info(intf, &channel_info);
if (ccode == 0xCC) {
return IPMI_CHANNEL_MEDIUM_RESERVED;
} else if (ccode < 0 && eval_ccode(ccode) != 0) {
return 0;
} else if (ccode) {
lprintf(LOG_ERR, "Get Channel Info command failed: %s",
val2str(ccode, completion_code_vals));
if (ccode) {
if (ccode != IPMI_CC_INV_DATA_FIELD_IN_REQ) {
if (ccode > 0) {
lprintf(LOG_ERR, "Get Channel Info command failed: %s",
val2str(ccode, completion_code_vals));
}
else {
eval_ccode(ccode);
}
}
return IPMI_CHANNEL_MEDIUM_RESERVED;
}
lprintf(LOG_DEBUG, "Channel type: %s",

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 rsp->ccode;
goto out;
}
lprintf(LOG_DEBUG, "Chassis Set Boot Parameter %d to %s", param, buf2str(data, len));
return IPMI_CC_OK;
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);
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));
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");
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));
}
break;
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;
}
@ -1001,6 +1160,296 @@ out:
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)
{
@ -1111,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);
@ -1199,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;
@ -1339,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;

File diff suppressed because it is too large Load Diff

View File

@ -52,6 +52,14 @@
#include <ipmitool/ipmi_event.h>
#include <ipmitool/ipmi_sdr.h>
static
inline
bool
is_system(const struct channel_info_t *chinfo)
{
return (IPMI_CHANNEL_MEDIUM_SYSTEM == chinfo->medium
|| CH_SYSTEM == chinfo->channel);
}
static void
ipmi_event_msg_print(struct ipmi_intf * intf, struct platform_event_msg * pmsg)
@ -61,7 +69,8 @@ ipmi_event_msg_print(struct ipmi_intf * intf, struct platform_event_msg * pmsg)
memset(&sel_event, 0, sizeof(struct sel_event_record));
sel_event.record_id = 0;
sel_event.sel_type.standard_type.gen_id = 2;
htoipmi16(EVENT_GENERATOR(SMS, 0),
(void *)&sel_event.sel_type.standard_type.gen_id);
sel_event.sel_type.standard_type.evm_rev = pmsg->evm_rev;
sel_event.sel_type.standard_type.sensor_type = pmsg->sensor_type;
@ -83,28 +92,34 @@ ipmi_send_platform_event(struct ipmi_intf * intf, struct platform_event_msg * em
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
uint8_t rqdata[8];
uint8_t chmed;
uint8_t rqdata[PLATFORM_EVENT_DATA_LEN_MAX];
uint8_t *rqdata_start = rqdata;
struct channel_info_t chinfo;
memset(&req, 0, sizeof(req));
memset(rqdata, 0, 8);
memset(rqdata, 0, sizeof(rqdata));
req.msg.netfn = IPMI_NETFN_SE;
req.msg.cmd = 0x02;
req.msg.cmd = IPMI_CMD_PLATFORM_EVENT;
req.msg.data = rqdata;
req.msg.data_len = PLATFORM_EVENT_DATA_LEN_NON_SI;
chmed = ipmi_current_channel_medium(intf);
if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) {
/* system interface, need extra generator ID */
req.msg.data_len = 8;
rqdata[0] = 0x41; // As per Fig. 29-2 and Table 5-4
memcpy(rqdata+1, emsg, sizeof(struct platform_event_msg));
ipmi_current_channel_info(intf, &chinfo);
if (chinfo.channel == CH_UNKNOWN) {
lprintf(LOG_ERR, "Failed to send the platform event "
"via an unknown channel");
return -3;
}
else {
req.msg.data_len = 7;
memcpy(rqdata, emsg, sizeof(struct platform_event_msg));
if (is_system(&chinfo)) {
/* system interface, need extra generator ID, see Fig. 29-2 */
req.msg.data_len = PLATFORM_EVENT_DATA_LEN_SI;
rqdata[0] = EVENT_GENERATOR(SMS, 0);
rqdata_start++;
}
memcpy(rqdata_start, emsg, sizeof(struct platform_event_msg));
ipmi_event_msg_print(intf, emsg);
rsp = intf->sendrecv(intf, &req);
@ -484,43 +499,30 @@ static int
ipmi_event_fromfile(struct ipmi_intf * intf, char * file)
{
FILE * fp;
struct ipmi_rs * rsp;
struct ipmi_rq req;
struct sel_event_record sel_event;
uint8_t rqdata[8];
/* For ease of filling in from file data */
union {
struct platform_event_msg emsg;
uint8_t bytes[sizeof(struct platform_event_msg)];
} __attribute__ ((packed)) rqdata;
char buf[1024];
char * ptr, * tok;
int i, j;
uint8_t chmed;
int rc = 0;
if (!file)
return -1;
memset(rqdata, 0, 8);
/* setup Platform Event Message command */
memset(&req, 0, sizeof(req));
req.msg.netfn = IPMI_NETFN_SE;
req.msg.cmd = 0x02;
req.msg.data = rqdata;
req.msg.data_len = 7;
chmed = ipmi_current_channel_medium(intf);
if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) {
/* system interface, need extra generator ID */
rqdata[0] = 0x41; // As per Fig. 29-2 and Table 5-4
req.msg.data_len = 8;
}
fp = ipmi_open_file_read(file);
if (!fp)
return -1;
while (feof(fp) == 0) {
size_t count = 0;
if (!fgets(buf, 1024, fp))
continue;
/* Each line is a new event */
memset(&rqdata, 0, sizeof(rqdata));
/* clip off optional comment tail indicated by # */
ptr = strchr(buf, '#');
if (ptr)
@ -540,49 +542,28 @@ ipmi_event_fromfile(struct ipmi_intf * intf, char * file)
/* parse the event, 7 bytes with optional comment */
/* 0x00 0x00 0x00 0x00 0x00 0x00 0x00 # event */
i = 0;
tok = strtok(ptr, " ");
while (tok) {
if (i == 7)
if (count == sizeof(struct platform_event_msg))
break;
j = i++;
if (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM)
j++;
rqdata[j] = (uint8_t)strtol(tok, NULL, 0);
if (0 > str2uchar(tok, &rqdata.bytes[count])) {
lprintf(LOG_ERR, "Invalid token in file: [%s]", tok);
rc = -1;
break;
}
tok = strtok(NULL, " ");
++count;
}
if (i < 7) {
if (count < sizeof(struct platform_event_msg)) {
lprintf(LOG_ERR, "Invalid Event: %s",
buf2str(rqdata, sizeof(rqdata)));
buf2str(rqdata.bytes, sizeof(rqdata.bytes)));
continue;
}
memset(&sel_event, 0, sizeof(struct sel_event_record));
sel_event.record_id = 0;
sel_event.sel_type.standard_type.gen_id = 2;
j = (chmed == IPMI_CHANNEL_MEDIUM_SYSTEM) ? 1 : 0;
sel_event.sel_type.standard_type.evm_rev = rqdata[j++];
sel_event.sel_type.standard_type.sensor_type = rqdata[j++];
sel_event.sel_type.standard_type.sensor_num = rqdata[j++];
sel_event.sel_type.standard_type.event_type = rqdata[j] & 0x7f;
sel_event.sel_type.standard_type.event_dir = (rqdata[j++] & 0x80) >> 7;
sel_event.sel_type.standard_type.event_data[0] = rqdata[j++];
sel_event.sel_type.standard_type.event_data[1] = rqdata[j++];
sel_event.sel_type.standard_type.event_data[2] = rqdata[j++];
ipmi_sel_print_std_entry(intf, &sel_event);
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
lprintf(LOG_ERR, "Platform Event Message command failed");
rc = -1;
}
else if (rsp->ccode) {
lprintf(LOG_ERR, "Platform Event Message command failed: %s",
val2str(rsp->ccode, completion_code_vals));
rc = -1;
}
/* Now actually send it, failures will be logged by the sender */
rc = ipmi_send_platform_event(intf, &rqdata.emsg);
if (IPMI_CC_OK != rc)
break;
}
fclose(fp);

View File

@ -111,12 +111,6 @@ static inline bool fru_cc_rq2big(int code) {
int
ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id);
/* From src/plugins/ipmi_intf.c: */
void
ipmi_intf_set_max_request_data_size(struct ipmi_intf * intf, uint16_t size);
void
ipmi_intf_set_max_response_data_size(struct ipmi_intf * intf, uint16_t size);
extern int verbose;
static void ipmi_fru_read_to_bin(struct ipmi_intf * intf, char * pFileName, uint8_t fruId);

View File

@ -48,10 +48,6 @@
# include <config.h>
#endif
/* From src/plugins/ipmi_intf.c: */
uint16_t
ipmi_intf_get_max_request_data_size(struct ipmi_intf * intf);
extern int verbose;
int HpmfwupgUpgrade(struct ipmi_intf *intf, char *imageFilename,

View File

@ -844,6 +844,12 @@ ipmi_main(int argc, char ** argv,
/* setup log */
log_init(progname, 0, verbose);
/* load the IANA PEN registry */
if (ipmi_oem_info_init()) {
lprintf(LOG_ERR, "Failed to initialize the OEM info dictionary");
goto out_free;
}
/* run OEM setup if found */
if (oemtype &&
ipmi_oem_setup(ipmi_main_intf, oemtype) < 0) {
@ -1063,6 +1069,8 @@ ipmi_main(int argc, char ** argv,
devfile = NULL;
}
ipmi_oem_info_free();
return rc;
}

1899
lib/ipmi_nm.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -219,10 +219,6 @@ static const char *sensor_type_desc[] = {
void printf_sdr_usage();
/* From src/plugins/ipmi_intf.c: */
uint16_t
ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf);
/** ipmi_sdr_get_unit_string - return units for base/modifier
*
* @param[in] pct Indicates that units are a percentage

View File

@ -454,10 +454,10 @@ get_kontron_evt_desc(struct ipmi_intf *__UNUSED__(intf), struct sel_event_record
}
char *
get_newisys_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
get_viking_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
{
/*
* Newisys OEM event descriptions can be retrieved through an
* Viking OEM event descriptions can be retrieved through an
* OEM IPMI command.
*/
struct ipmi_rs * rsp;
@ -495,17 +495,17 @@ get_newisys_evt_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
/* Verify our response before we use it */
if (rsp->data_len < 5)
{
lprintf(LOG_ERR, "Newisys OEM response too short");
lprintf(LOG_ERR, "Viking OEM response too short");
return NULL;
}
else if (rsp->data_len != (4 + rsp->data[3]))
{
lprintf(LOG_ERR, "Newisys OEM response has unexpected length");
lprintf(LOG_ERR, "Viking OEM response has unexpected length");
return NULL;
}
else if (IPM_DEV_MANUFACTURER_ID(rsp->data) != IPMI_OEM_NEWISYS)
else if (IPM_DEV_MANUFACTURER_ID(rsp->data) != IPMI_OEM_VIKING)
{
lprintf(LOG_ERR, "Newisys OEM response has unexpected length");
lprintf(LOG_ERR, "Viking OEM response has unexpected length");
return NULL;
}
@ -1205,8 +1205,8 @@ ipmi_get_oem_desc(struct ipmi_intf * intf, struct sel_event_record * rec)
switch (ipmi_get_oem(intf))
{
case IPMI_OEM_NEWISYS:
desc = get_newisys_evt_desc(intf, rec);
case IPMI_OEM_VIKING:
desc = get_viking_evt_desc(intf, rec);
break;
case IPMI_OEM_KONTRON:
desc = get_kontron_evt_desc(intf, rec);

View File

@ -30,29 +30,52 @@
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
*/
#include <ctype.h>
#include <limits.h>
#include <stddef.h>
#include <ipmitool/ipmi_strings.h>
#include <ipmitool/ipmi_constants.h>
#include <ipmitool/ipmi_sensor.h>
#include <ipmitool/ipmi_sel.h> /* for IPMI_OEM */
const struct valstr ipmi_oem_info[] = {
/* These are at the top so they are found first */
{ IPMI_OEM_UNKNOWN, "Unknown" },
{ IPMI_OEM_RESERVED, "Unspecified" },
/* The included file is auto-generated from official IANA PEN list */
#include "ipmi_pen_list.inc.c"
#include <ipmitool/log.h>
/*
* This debug ID is at the bottom so that if IANA assigns it to
* any entity, that IANA's value is found first and reported.
* These are put at the head so they are found first because they
* may overlap with IANA specified numbers found in the registry.
*/
{ IPMI_OEM_DEBUG, "A Debug Assisting Company, Ltd." },
{ -1 , NULL },
static const struct valstr ipmi_oem_info_head[] = {
{ IPMI_OEM_UNKNOWN, "Unknown" }, /* IPMI Unknown */
{ IPMI_OEM_RESERVED, "Unspecified" }, /* IPMI Reserved */
{ UINT32_MAX , NULL },
};
/*
* These are our own technical values. We don't want them to take precedence
* over IANA's defined values, so they go at the very end of the array.
*/
static const struct valstr ipmi_oem_info_tail[] = {
{ IPMI_OEM_DEBUG, "A Debug Assisting Company, Ltd." },
{ UINT32_MAX , NULL },
};
/*
* This is used when ipmi_oem_info couldn't be allocated.
* ipmitool would report all OEMs as unknown, but would be functional otherwise.
*/
static const struct valstr ipmi_oem_info_dummy[] = {
{ UINT32_MAX , NULL },
};
/* This will point to an array filled from IANA's enterprise numbers registry */
const struct valstr *ipmi_oem_info;
/* Single-linked list of OEM valstrs */
typedef struct oem_valstr_list_s {
struct valstr valstr;
struct oem_valstr_list_s *next;
} oem_valstr_list_t;
const struct oemvalstr ipmi_oem_product_info[] = {
/* Keep OEM grouped together */
@ -754,3 +777,326 @@ const struct oemvalstr picmg_busres_shmc_status_vals[] = {
{ 0xffffff, 0x00, NULL }
};
/**
* A helper function to count repetitions of the same byte
* at the beginning of a string.
*/
static
size_t count_bytes(const char *s, unsigned char c)
{
size_t count;
for (count = 0; s && s[0] == c; ++s, ++count);
return count;
}
/**
* Parse the IANA PEN registry file.
*
* See https://www.iana.org/assignments/enterprise-numbers/enterprise-numbers
* The expected entry format is:
*
* Decimal
* | Organization
* | | Contact
* | | | Email
* | | | |
* 0
* Reserved
* Internet Assigned Numbers Authority
* iana&iana.org
*
* That is, IANA PEN at position 0, enterprise name at position 2.
*/
#define IANA_NAME_OFFSET 2
#define IANA_PEN_REGISTRY "enterprise-numbers"
static
int oem_info_list_load(oem_valstr_list_t **list)
{
FILE *in = NULL;
char *home;
oem_valstr_list_t *oemlist = *list;
int count = 0;
/*
* First try to open user's local registry if HOME is set
*/
if ((home = getenv("HOME"))) {
char path[PATH_MAX + 1] = { 0 };
snprintf(path, PATH_MAX, "%s%s",
home,
PATH_SEPARATOR IANAUSERDIR PATH_SEPARATOR IANA_PEN_REGISTRY);
in = fopen(path, "r");
}
if (!in) {
/*
* Now open the system default file
*/
in = fopen(IANADIR PATH_SEPARATOR IANA_PEN_REGISTRY, "r");
if (!in) {
lperror(LOG_ERR, "IANA PEN registry open failed");
return -1;
}
}
/*
* Read the registry file line by line, fill in the linked list,
* and count the entries. No sorting is done, entries will come in
* reverse registry order.
*/
while (!feof(in)) {
oem_valstr_list_t *item;
char *line = NULL;
char *endptr = NULL;
size_t len = 0;
long iana;
if (!getline(&line, &len, in)) {
/* Either an EOF or an empty line. Start over. */
continue;
}
/*
* Check if the line starts with a digit. If so, take it as IANA PEN.
* Any numbers not starting at position 0 are discarded.
*/
iana = strtol(line, &endptr, 10);
if (!isdigit(line[0]) || endptr == line) {
free_n(&line);
continue;
}
free_n(&line);
/*
* Now as we have the enterprise number, we're expecting the
* organization name to immediately follow.
*/
len = 0;
if (!getline(&line, &len, in)) {
/*
* Either an EOF or an empty line. Neither one can happen in
* a valid registry entry. Start over.
*/
continue;
}
if (len < IANA_NAME_OFFSET + 1
|| count_bytes(line, ' ') != IANA_NAME_OFFSET)
{
/*
* This is not a valid line, it doesn't start with
* a correct-sized indentation or is too short.
* Start over.
*/
free_n(&line);
continue;
}
/* Adjust to real line length, don't count the indentation */
len = strnlen(line + IANA_NAME_OFFSET, len - IANA_NAME_OFFSET);
/* Don't count the trailing newline */
if (line[IANA_NAME_OFFSET + len - 1] == '\n') {
--len;
}
item = malloc(sizeof(oem_valstr_list_t));
if (!item) {
lperror(LOG_ERR, "IANA PEN registry entry allocation failed");
free_n(&line);
/* Just stop reading, and process what has already been read */
break;
}
/*
* Looks like we have a valid entry, store it in the list.
*/
item->valstr.val = iana;
item->valstr.str = malloc(len + 1); /* Add 1 for \0 terminator */
if (!item->valstr.str) {
lperror(LOG_ERR, "IANA PEN registry string allocation failed");
free_n(&line);
free_n(&item);
/* Just stop reading, and process what has already been read */
break;
}
/*
* Most other valstr arrays are constant and all of them aren't meant
* for modification, so the string inside 'struct valstr' is const.
* Here we're loading the strings dynamically so we intentionally
* cast to a non-const type to be able to modify data here and
* keep the compiler silent about it. Restrictions still apply to
* other places where these strings are used.
*/
snprintf((void *)item->valstr.str, len + 1,
"%s", line + IANA_NAME_OFFSET);
free_n(&line);
item->next = oemlist;
oemlist = item;
++count;
}
fclose (in);
*list = oemlist;
return count;
}
/**
* Free the allocated list items and, if needed, strings.
*/
static
void
oem_info_list_free(oem_valstr_list_t **list, bool free_strings)
{
while ((*list)->next) {
oem_valstr_list_t *item = *list;
*list = item->next;
if (free_strings) {
free_n(&item->valstr.str);
}
free_n(&item);
}
}
/**
* Initialize the ipmi_oem_info array from a list
*/
static
bool
oem_info_init_from_list(oem_valstr_list_t *oemlist, size_t count)
{
/* Do not count terminators */
size_t head_entries = ARRAY_SIZE(ipmi_oem_info_head) - 1;
size_t tail_entries = ARRAY_SIZE(ipmi_oem_info_tail) - 1;
static oem_valstr_list_t *item;
bool rc = false;
/* Include static entries and the terminator */
count += head_entries + tail_entries + 1;
/*
* Allocate as much memory as needed to accomodata all the entries
* of the loaded linked list, plus the static head and tail, not including
* their terminating entries, plus the terminating entry for the new
* array.
*/
ipmi_oem_info = malloc(count * sizeof(*ipmi_oem_info));
if (!ipmi_oem_info) {
/*
* We can't identify OEMs without an allocated ipmi_oem_info.
* Report an error, set the pointer to dummy and clean up.
*/
lperror(LOG_ERR, "IANA PEN registry array allocation failed");
ipmi_oem_info = ipmi_oem_info_dummy;
goto out;
}
lprintf(LOG_DEBUG + 3, " Allocating %6zu entries", count);
/* Add a terminator at the very end */
--count;
((struct valstr *)ipmi_oem_info)[count].val = -1;
((struct valstr *)ipmi_oem_info)[count].str = NULL;
/* Add tail entries from the end */
while (count-- < SIZE_MAX && tail_entries--) {
((struct valstr *)ipmi_oem_info)[count] =
ipmi_oem_info_tail[tail_entries];
lprintf(LOG_DEBUG + 3, " [%6zu] %8d | %s", count,
ipmi_oem_info[count].val, ipmi_oem_info[count].str);
}
/* Now add the loaded entries */
item = oemlist;
while (count < SIZE_MAX && item->next) {
((struct valstr *)ipmi_oem_info)[count] =
item->valstr;
lprintf(LOG_DEBUG + 3, " [%6zu] %8d | %s", count,
ipmi_oem_info[count].val, ipmi_oem_info[count].str);
item = item->next;
--count;
}
/* Now add head entries */
while (count < SIZE_MAX && head_entries--) {
((struct valstr *)ipmi_oem_info)[count] =
ipmi_oem_info_head[head_entries];
lprintf(LOG_DEBUG + 3, " [%6zu] %8d | %s", count,
ipmi_oem_info[count].val, ipmi_oem_info[count].str);
--count;
}
rc = true;
out:
return rc;
}
int ipmi_oem_info_init()
{
oem_valstr_list_t terminator = { { -1, NULL}, NULL }; /* Terminator */
oem_valstr_list_t *oemlist = &terminator;
bool free_strings = true;
size_t count;
int rc = -4;
lprintf(LOG_INFO, "Loading IANA PEN Registry...");
if (ipmi_oem_info) {
lprintf(LOG_INFO, "IANA PEN Registry is already loaded");
rc = 0;
goto out;
}
if (!(count = oem_info_list_load(&oemlist))) {
/*
* We can't identify OEMs without a loaded registry.
* Set the pointer to dummy and return.
*/
ipmi_oem_info = ipmi_oem_info_dummy;
goto out;
}
/* In the array was allocated, don't free the strings at cleanup */
free_strings = !oem_info_init_from_list(oemlist, count);
rc = IPMI_CC_OK;
out:
oem_info_list_free(&oemlist, free_strings);
return rc;
}
void ipmi_oem_info_free()
{
/* Start with the dynamically allocated entries */
size_t i = ARRAY_SIZE(ipmi_oem_info_head) - 1;
if (ipmi_oem_info == ipmi_oem_info_dummy) {
return;
}
/*
* Proceed dynamically allocated entries until we hit the first
* entry of ipmi_oem_info_tail[], which is statically allocated.
*/
while (ipmi_oem_info
&& ipmi_oem_info[i].val < UINT32_MAX
&& ipmi_oem_info[i].str != ipmi_oem_info_tail[0].str)
{
free_n(&((struct valstr *)ipmi_oem_info)[i].str);
++i;
}
/* Free the array itself */
free_n(&ipmi_oem_info);
}

View File

@ -65,6 +65,7 @@
#include <ipmitool/ipmi_ekanalyzer.h>
#include <ipmitool/ipmi_ime.h>
#include <ipmitool/ipmi_dcmi.h>
#include <ipmitool/ipmi_nm.h>
#include <ipmitool/ipmi_vita.h>
#include <ipmitool/ipmi_quantaoem.h>

View File

@ -31,7 +31,7 @@
MAINTAINERCLEANFILES = Makefile.in
INCLUDES = -I$(top_srcdir)/include
AM_CPPFLAGS = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_dbus.la
noinst_LTLIBRARIES = @INTF_DBUS_LIB@

View File

@ -761,12 +761,6 @@ ipmi_lan_poll_single(struct ipmi_intf * intf)
if (payload_size > 8) {
printbuf(&rsp->data[offset], (rsp->data_len-offset-1),
"bridge command response");
/*
* decrement payload size
* (cks2 for outer Send Message)
*/
payload_size--;
/*
* need to make a loop for embedded bridged response
*/
@ -793,6 +787,9 @@ ipmi_lan_poll_single(struct ipmi_intf * intf)
if (extra_data_length > 0) {
rsp->data_len = extra_data_length;
memmove(rsp->data, rsp->data + offset, extra_data_length);
offset = 0;
payload_start = 0;
payload_size = extra_data_length;
} else {
rsp->data_len = 0;
}