Compare commits

..

62 Commits

Author SHA1 Message Date
a6ff7b6cfb fru, sdr: Refactor description handling
Reduce code duplication, get rid of magic numbers, unused variables
and functions, and of unsafe memory handling in FRU and SDR description
printing.

Also add support for logging generic locator and fru locator SDR record
names during SDR population (`ipmitool sdr fill`).

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2020-05-26 23:16:51 +03:00
f80effb1fc sel: time: fix null pointer dereference in set
This is a refix of commit f0d5c17e
2020-02-12 16:37:02 +03:00
7ccea283dd fru, sdr: Fix id_string buffer overflows
Final part of the fixes for CVE-2020-5208, see
https://github.com/ipmitool/ipmitool/security/advisories/GHSA-g659-9qxw-p7cp

9 variants of stack buffer overflow when parsing `id_string` field of
SDR records returned from `CMD_GET_SDR` command.

SDR record structs have an `id_code` field, and an `id_string` `char`
array.

The length of `id_string` is calculated as `(id_code & 0x1f) + 1`,
which can be larger than expected 16 characters (if `id_code = 0xff`,
then length will be `(0xff & 0x1f) + 1 = 32`).

In numerous places, this can cause stack buffer overflow when copying
into fixed buffer of size `17` bytes from this calculated length.
2020-02-04 15:00:14 +03:00
d45572d71e lanp: Fix buffer overflows in get_lan_param_select
Partial fix for CVE-2020-5208, see
https://github.com/ipmitool/ipmitool/security/advisories/GHSA-g659-9qxw-p7cp

The `get_lan_param_select` function is missing a validation check on the
response’s `data_len`, which it then returns to caller functions, where
stack buffer overflow can occur.
2020-02-04 14:59:55 +03:00
9452be8718 channel: Fix buffer overflow
Partial fix for CVE-2020-5208, see
https://github.com/ipmitool/ipmitool/security/advisories/GHSA-g659-9qxw-p7cp

The `ipmi_get_channel_cipher_suites` function does not properly check
the final response’s `data_len`, which can lead to stack buffer overflow
on the final copy.
2020-02-04 14:59:52 +03:00
41d7026946 session: Fix buffer overflow in ipmi_get_session_info
Partial fix for CVE-2020-5208, see
https://github.com/ipmitool/ipmitool/security/advisories/GHSA-g659-9qxw-p7cp

The `ipmi_get_session_info` function does not properly check the
response `data_len`, which is used as a copy size, allowing stack buffer
overflow.
2020-02-04 14:59:49 +03:00
840fb1cbb4 fru: Fix buffer overflow in ipmi_spd_print_fru
Partial fix for CVE-2020-5208, see
https://github.com/ipmitool/ipmitool/security/advisories/GHSA-g659-9qxw-p7cp

The `ipmi_spd_print_fru` function has a similar issue as the one fixed
by the previous commit in `read_fru_area_section`. An initial request is
made to get the `fru.size`, which is used as the size for the allocation
of `spd_data`. Inside a loop, further requests are performed to get the
copy sizes which are not checked before being used as the size for a
copy into the buffer.
2020-02-04 14:59:43 +03:00
e824c23316 fru: Fix buffer overflow vulnerabilities
Partial fix for CVE-2020-5208, see
https://github.com/ipmitool/ipmitool/security/advisories/GHSA-g659-9qxw-p7cp

The `read_fru_area_section` function only performs size validation of
requested read size, and falsely assumes that the IPMI message will not
respond with more than the requested amount of data; it uses the
unvalidated response size to copy into `frubuf`. If the response is
larger than the request, this can result in overflowing the buffer.

The same issue affects the `read_fru_area` function.
2020-02-04 14:58:06 +03:00
7a66d8725d chassis: bootmbox: Refix 62a04390
Fix ipmitool not writing the last block of boot mailbox data if the
block is shorter than 3 bytes.

Signed-off-by: Ivan Mikhaylov <fr0st61te@gmail.com>
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2020-01-23 18:06:47 +03:00
63dd71c39c configure: Drop requirement for curses et. al libs
Libraries ncurses, curses, tinfo and termcap are not actually
needed as the tgetent() function listed as required is not actually
used anywhere in the code.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-12-05 13:45:57 +03:00
e60eac12cc configure: remove some duplicate code
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-12-05 13:45:57 +03:00
dec04e79fd doc: Update INSTALL to fix installation errors
The `sudo` was missing from `make install` which prevented installation
if build is performed, as it should be, by an unpriviliged user.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-29 14:34:20 +03:00
d9adbf12f1 ipmi_dcmi: fix typo in nm_policy_options initialization.
This re-enables "nm policy add" functionality.
2019-11-27 13:47:41 +03:00
5647cd16d2 Docs: Add info on packages to install on Ubuntu 16.04
Add some documenation on packages to install on Ubuntu 16.04 and
Fedora 31 before building the software.

This will make it easier for people who are building ipmitool as they
won't need to figure out all the package dependencies on their own.
2019-11-15 14:25:08 +03:00
42a023ff07 chassis: Refactor to get rid of strncmp()
For parameter checking replace calls to strncmp() with calls
to strcmp() in order to improve readability and get rid of literal
string lengths.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-12 17:55:21 +03:00
58c9263a28 chassis: Refactor main for centralized exiting
In ipmi_chassis_main:

* Default to error return code (-1).

* Use centralized exit.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-12 17:55:21 +03:00
0663814eec chassis: bootdev: Refactor more
* Get rid of magic '8' in bootdev options processing.

* Optimize the code of bootdev arguments processing, remove the
  special crafting of flags for 'clear-cmos' argument, make it use
  the same code as other options.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-12 17:55:21 +03:00
aa72d9c426 chassis: bootdev: Refactor to reduce nesting
Move bootdev options parsing to a separate helper function

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-12 17:55:21 +03:00
0854344db5 chassis: bootdev: Fix help message and its formatting
There was a wrong help message regarding the console redirection,
and also the help formatting was a bit off. Straightened this all up.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-12 17:55:21 +03:00
4b89f1b42d chassis: bootparam/bootdev: Refactor for less magic
Refactor the boot flags decoder:

* Add macros for boot flag bits, replace magic numbers in
  the `chassis bootparam get 5` and in `chassis bootdev`
  handlers.

  The macros are prefixed with BFx_ where x stands for the
  boot flags data byte as per IPMI 2.0 specification Table 28-14;

* Add decoding of remote/redirected media boot flags;

* Remove erroneous decoding of boot flags byte 3 bit 1 as
  Sleep button lockout whereas the bit is a part of console
  redirection setting;

* Fix console redirection settings reported under the 'BIOS verbosity'
  header and vice versa;

* Fix resetting of all other boot flags in the data byte when
  setting any of the bits in the same byte. This fixes inability
  to set both 'efiboot' and 'persistent' bits at the same time,
  and other similar cases.

Resolves ipmitool/ipmitool#163
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-12 17:55:21 +03:00
0e3e436eb6 oem: supermicro: Add product codes from IPMICFG
ftp://ftp.supermicro.com/utility/IPMICFG/IPMICFG_1.30.0_build.190710.zip
contains MBType.dat file that lists all known Supermicro product IDs
with their respective names.

Import that knowledge into ipmitool.

Resolves ipmitool/ipmitool#151
Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-11-06 18:50:08 +03:00
eed9d5950e lan: Refix 6e2b688e. Fix vlan range checking.
Commit 6e2b688e introduced a bug due to which VLAN id range checking
was negated and resulted in error messages printed for correct VLAN ids.

Resolves ipmitool/ipmitool#55

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-09-05 15:10:02 +03:00
4dc962b614 doc: Update man page regarding user set password
Document password length argument to "set password", as per usage info.

Since we don't check whether we're using IPMI1.5/2.0 when setting the
password, ipmitool can't reject 20-char passwords being sent to
16-char interfaces, so the behaviour is somewhat undefined.
For 20-chars, it's now clearer and long passwords will be rejected.

Man page changed to reflect the above.
2019-09-03 23:40:48 +03:00
6940a6717a user: Cleanup/refactor ipmi_user_password()
Get rid of magic numbers, fix some formatting, drop unneeded checks.

Signed-off-by: Alexander Amelkin <alexander@amelkin.msk.ru>
2019-09-03 23:40:48 +03:00
51a2ab8180 user: Improve password length handling
No longer truncate passwords (16 < p <= 20) silently, instead attempt
to set a 20-char password when such a password is given.
Fail if an explicit length is exceeded, and any time the upper limit
is exceeded.
2019-09-03 23:40:48 +03:00
af062a9a5e user: Alter "set password" usage information
This changes the usage string to match reality and note that [<16|20>]
is an optional argument to set password.
2019-09-03 23:40:48 +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
619a02cf5d man: Cleanup the manpage formatting tags
The manpage contained a lot of redundant .RS/.RE tag pairs
with no content between the tags. This commits removes those.

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

Partially resolves ipmitool/ipmitool#11

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

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

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

Resolves ipmitool/ipmitool#118

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

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

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

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

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

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

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

Signed-off-by: Vernon Mauery <vernon.mauery@intel.com>
2019-04-15 18:41:47 +03:00
b7b455a38c add OpenBMC D-Bus interface
OpenBMC runs a D-Bus interface internally and has the option of
compiling ipmitool so it can run natively on the BMC. This adds the
D-Bus interface to ipmitool so it can be used with the OpenBMC project.

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

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

38
INSTALL
View File

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

View File

@ -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,12 +56,30 @@ 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
xenable_all_options=yes
xenable_intf_bmc=no
xenable_intf_dbus=no
xenable_intf_dummy=no
xenable_intf_imb=yes
xenable_intf_lipmi=yes
@ -191,6 +212,14 @@ AC_CHECK_LIB([crypto], [MD2_Init],
fi],
[], [-lcrypto])
dnl check for libsystemd in case dbus-intf is requested
AC_CHECK_LIB([systemd], [sd_bus_default],
[
LIBS="$LIBS -lsystemd"
have_systemd=yes
],
[ have_systemd=no],[])
dnl enable IPMIv1.5 LAN interface
AC_ARG_ENABLE([intf-lan],
[AC_HELP_STRING([--enable-intf-lan],
@ -554,6 +583,25 @@ if test "x$xenable_intf_bmc" = "xyes"; then
IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB bmc/libintf_bmc.la"
fi
dnl enable IPMI dbus interface
AC_ARG_ENABLE([intf-dbus],
[AC_HELP_STRING([--enable-intf-dbus],
[enable IPMI dbus interface [default=no]])],
[xenable_intf_dbus=$enableval],
[xenable_intf_dbus=no])
if test "x$xenable_intf_dbus" != "xno"; then
if test "x$have_systemd" != "xyes"; then
AC_MSG_ERROR([** Unable to find libsystemd required by dbus-intf.])
xenable_intf_dbus=no
fi
fi
if test "x$xenable_intf_dbus" = "xyes"; then
AC_DEFINE(IPMI_INTF_DBUS, [1], [Define to 1 to enable dbus interface.])
AC_SUBST(INTF_DBUS, [dbus])
AC_SUBST(INTF_DBUS_LIB, [libintf_dbus.la])
IPMITOOL_INTF_LIB="$IPMITOOL_INTF_LIB dbus/libintf_dbus.la"
fi
dnl enable Dummy interface for testing
AC_ARG_ENABLE([intf-dummy],
[AC_HELP_STRING([--enable-intf-dummy],
@ -568,30 +616,18 @@ fi
AC_SUBST(IPMITOOL_INTF_LIB)
if test "x$xenable_ipmishell" = "xyes"; then
AC_SEARCH_LIBS([tgetent], [tinfo ncurses curses readline termcap])
AC_SEARCH_LIBS([initscr], [ncurses curses], [have_curses=yes])
AC_SEARCH_LIBS([readline], [readline edit], [have_readline=yes])
if test "x$have_curses" != "xyes" || test "x$have_readline" != "xyes"; then
xenable_ipmishell=no
fi
fi
dnl check for readline library to enable ipmi shell
AC_ARG_ENABLE([ipmishell],
[AC_HELP_STRING([--enable-ipmishell],
[enable IPMI shell interface [default=auto]])],
[xenable_ipmishell=$enableval],
[])
dnl check for readline library to enable ipmi shell
if test "x$xenable_ipmishell" = "xyes"; then
AC_SEARCH_LIBS([tgetent], [tinfo ncurses curses readline termcap])
AC_SEARCH_LIBS([initscr], [ncurses curses], [have_curses=yes])
AC_SEARCH_LIBS([readline], [readline edit], [have_readline=yes])
if test "x$have_curses" != "xyes"; then
AC_MSG_ERROR([** Unable to find curses required by ipmishell.])
fi
if test "x$have_readline" != "xyes"; then
AC_MSG_ERROR([** Unable to find readline required by ipmishell.])
xenable_ipmishell=no
fi
AC_DEFINE(HAVE_READLINE, [1], [Define to 1 if readline present.])
fi
@ -643,6 +679,51 @@ AC_TRY_COMPILE([],[
[Define to 1 if you need to use #pragma pack instead of __attribute__ ((packed))])]
)
dnl if no environment variable is set, set the default value for the default intf
if test "${xenable_intf_open}" = "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='open' if available, 'lan' otherwise)])
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
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
@ -664,23 +745,28 @@ AC_CONFIG_FILES([Makefile
src/plugins/free/Makefile
src/plugins/imb/Makefile
src/plugins/bmc/Makefile
src/plugins/dbus/Makefile
src/plugins/usb/Makefile
src/plugins/lipmi/Makefile
src/plugins/serial/Makefile
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([])
AC_MSG_RESULT([ipmitool $VERSION])
AC_MSG_RESULT([])
AC_MSG_RESULT([Interfaces])
AC_MSG_RESULT([Interfaces (default=$DEFAULT_INTF)])
AC_MSG_RESULT([ lan : $xenable_intf_lan])
AC_MSG_RESULT([ lanplus : $xenable_intf_lanplus])
AC_MSG_RESULT([ open : $xenable_intf_open])
AC_MSG_RESULT([ free : $xenable_intf_free])
AC_MSG_RESULT([ imb : $xenable_intf_imb])
AC_MSG_RESULT([ bmc : $xenable_intf_bmc])
AC_MSG_RESULT([ dbus : $xenable_intf_dbus])
AC_MSG_RESULT([ usb : $xenable_intf_usb])
AC_MSG_RESULT([ lipmi : $xenable_intf_lipmi])
AC_MSG_RESULT([ serial : $xenable_intf_serial])

View File

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

View File

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

@ -259,11 +259,15 @@ system. It is thus recommended that IPMI password management only be done
over IPMIv2.0 \fIlanplus\fP interface or the system interface on the
local station.
For IPMI v1.5, the maximum password length is 16 characters.
Passwords longer than 16 characters will be truncated.
For IPMI v1.5, the maximum password length is 16 characters; longer
passwords might be truncated or rejected by the server, or rejected
by
.BR ipmitool .
For IPMI v2.0, the maximum password length is 20 characters; longer
passwords will be rejected by
.BR ipmitool .
For IPMI v2.0, the maximum password length is 20 characters;
longer passwords are truncated.
.SH "COMMANDS"
.TP
\fIhelp\fP
@ -384,39 +388,23 @@ application (ipmi or sol) on the given channel.
\fIstatus\fP
Status information related to power, buttons, cooling, drives and faults.
.RS
.RE
.TP
\fIpower\fP
.RS
.TP
\fIstatus\fP
.RS
.RE
.TP
\fIon\fP
.RS
.RE
.TP
\fIoff\fP
.RS
.RE
.TP
\fIcycle\fP
.RS
.RE
.TP
\fIreset\fP
.RS
.RE
.TP
\fIdiag\fP
.RS
.RE
.TP
\fIsoft\fP
.RS
.RE
.RE
.TP
\fIidentify\fP [<seconds>|force]
@ -428,8 +416,6 @@ Default is 15 seconds.
0 - Off
.br
force - To turn on indefinitely
.RS
.RE
.TP
\fIpolicy\fP
@ -439,34 +425,22 @@ What to do when power is restored.
\fIlist\fP
Show available options.
.RS
.RE
.TP
\fIalways-on\fP
.RS
.RE
.TP
\fIprevious\fP
.RS
.RE
.TP
\fIalways-off\fP
.RS
.RE
.RE
.TP
\fIrestart_cause\fP
Last restart cause.
.RS
.RE
.TP
\fIpoh\fP
Get power on hours.
.RS
.RE
.TP
\fIbootdev\fP
.RS
@ -474,95 +448,123 @@ Get power on hours.
\fInone\fP
Do not change boot device order.
.RS
.RE
.TP
\fIpxe\fP
Force PXE boot.
.RS
.RE
.TP
\fIdisk\fP
Force boot from default Hard-drive.
.RS
.RE
.TP
\fIsafe\fP
Force boot from default Hard-drive, request Safe Mode.
.RS
.RE
.TP
\fIdiag\fP
Force boot from Diagnostic Partition.
.RS
.RE
.TP
\fIcdrom\fP
Force boot from CD/DVD.
.RS
.RE
.TP
\fIbios\fP
Force boot into BIOS Setup.
.RS
.RE
.TP
\fIfloppy\fP
Force boot from Floppy/primary removable media.
.RS
.RE
.RE
.TP
\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
.RS
.RE
.TP
\fIforce_disk\fP
.IP \fIforce_disk\fP
Force boot from default Hard-drive
.RS
.RE
.TP
\fIforce_safe\fP
.IP \fIforce_safe\fP
Force boot from default Hard-drive, request Safe Mode
.RS
.RE
.TP
\fIforce_diag\fP
.IP \fIforce_diag\fP
Force boot from Diagnostic Partition
.RS
.RE
.TP
\fIforce_cdrom\fP
.IP \fIforce_cdrom\fP
Force boot from CD/DVD
.RS
.RE
.TP
\fIforce_bios\fP
.IP \fIforce_bios\fP
Force boot into BIOS Setup
.RS
.RE
.PP
Valid options are:
.IP \fIPEF\fP
Clear valid bit on reset/power cycle cause by PEF
.IP \fItimeout\fP
Automatically clear boot flag valid bit on timeout
.IP \fIwatchdog\fP
Clear valid bit on reset/power cycle cause by watchdog
.IP \fIreset\fP
Clear valid bit on push button reset/soft reset
.IP \fIpower\fP
Clear valid bit on power up via power push button or wake event
.RE
.TP
\fIselftest\fP
.RS
.RE
Get the chassis self-test results
.RE
.TP
\fIdcmi\fP
@ -957,8 +959,6 @@ Shows Extended SD Card information.
\fIecho\fP
For echoing lines to stdout in scripts.
.RS
.RE
.TP
\fIekanalyzer\fP <\fBcommand\fR> <\fBxx=filename1\fR> <\fBxx=filename2\fR> [<\fBrc=filename3\fR>] \fB...\fR
.RS
@ -1510,20 +1510,14 @@ Show firmware upgrade log.
\fIlist\fP
List All Generic Device Locators.
.RS
.RE
.TP
\fIread\fP <\fBsdr name\fR> <\fBfile\fR>
Read to file eeprom specify by Generic Device Locators.
.RS
.RE
.TP
\fIwrite\fP <\fBsdr name\fR> <\fBfile\fR>
Write from file eeprom specify by Generic Device Locators
.RS
.RE
.RE
.TP
\fIhpm\fP
@ -3150,50 +3144,34 @@ or by using the keyword `all' to specify all sessions.
\fIhostname\fP <\fBhost\fR>
Session hostname.
.RS
.RE
.TP
\fIusername\fP <\fBuser\fR>
Session username.
.RS
.RE
.TP
\fIpassword\fP <\fBpass\fR>
Session password.
.RS
.RE
.TP
\fIprivlvl\fP <\fBlevel\fR>
Session privilege level force.
.RS
.RE
.TP
\fIauthtype\fP <\fBtype\fR>
Authentication type force.
.RS
.RE
.TP
\fIlocaladdr\fP <\fBaddr\fR>
Local IPMB address.
.RS
.RE
.TP
\fItargetaddr\fP <\fBaddr\fR>
Remote target IPMB address.
.RS
.RE
.TP
\fIport\fP <\fBport\fR>
Remote RMCP port.
.RS
.RE
.TP
\fIcsv\fP [\fBlevel\fR]
@ -3201,14 +3179,10 @@ Enable output in comma separated format.
Affects following commands:
\fIuser\fP, \fIchannel\fP, \fIisol\fP, \fIsunoem\fP,
\fIsol\fP, \fIsensor\fP, \fIsdr\fP, \fIsel\fP, \fIsession\fP.
.RS
.RE
.TP
\fIverbose\fP [\fBverbose\fR]
Verbosity level.
.RS
.RE
.RE
.TP
\fIshell\fP
@ -3556,12 +3530,13 @@ Displays a list of user information for all defined userids.
Sets the username associated with the given userid.
.TP
\fIpassword\fP <\fBuserid\fR> [<\fBpassword\fR>]
\fIpassword\fP <\fBuserid\fR> [<\fBpassword\fR> [<\fB16|20\fR>]]
.br
Sets the password for the given userid. If no password is given,
the password is cleared (set to the NULL password). Be careful when
removing passwords from administrator\-level accounts.
removing passwords from administrator\-level accounts. If specified,
16 or 20 determines the maximum password length.
.RE
.TP
\fIdisable\fP <\fBuserid\fR>
@ -3847,7 +3822,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

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

View File

@ -37,6 +37,7 @@
# include <config.h>
#endif
#include <stdbool.h>
#include <inttypes.h>
#include <math.h>
#include <ipmitool/bswap.h>
@ -103,6 +104,24 @@ enum {
#define GET_SENSOR_READING 0x2d
#define GET_SENSOR_TYPE 0x2f
/*
* IPMI Specification limits the length of the ID string to 16 bytes for
* SDR records, although the ID type/length code may contain a number up
* to 31 (0x1F). See IPMI 2.0 Specification Tables 43-6 through 43-8.
*/
#define SDR_TYPECODE_LEN_MASK 0x1f
#define SDR_ID_STRING_MAX 16
#define SDR_ID_STRLEN_BYTYPE(typelen) \
((size_t)__max(typelen & SDR_TYPECODE_LEN_MASK, SDR_ID_STRING_MAX))
#define SDR_ID_STRLEN(sdr) SDR_ID_STRLEN_BYTYPE((sdr)->id_code)
#define SDR_ID_TO_CSTRING(cstring, sdr) \
do { \
memset((cstring), 0, sizeof(cstring)); \
snprintf((cstring), sizeof(cstring), "%.*s", \
SDR_ID_STRLEN(sdr), (sdr)->id_string); \
} while(0)
#ifdef HAVE_PRAGMA_PACK
#pragma pack(1)
#endif
@ -381,6 +400,29 @@ struct sdr_record_common_sensor {
struct sdr_record_mask mask;
/* IPMI 2.0, Table 43-1, byte 21[7:6] Analog (numeric) Data Format */
#define SDR_UNIT_FMT_UNSIGNED 0 /* unsigned */
#define SDR_UNIT_FMT_1S_COMPL 1 /* 1's complement (signed) */
#define SDR_UNIT_FMT_2S_COMPL 2 /* 2's complement (signed) */
#define SDR_UNIT_FMT_NA 3 /* does not return analog (numeric) reading */
/* IPMI 2.0, Table 43-1, byte 21[5:3] Rate */
#define SDR_UNIT_RATE_NONE 0 /* none */
#define SDR_UNIT_RATE_MICROSEC 1 /* per us */
#define SDR_UNIT_RATE_MILLISEC 2 /* per ms */
#define SDR_UNIT_RATE_SEC 3 /* per s */
#define SDR_UNIT_RATE_MIN 4 /* per min */
#define SDR_UNIT_RATE_HR 5 /* per hour */
#define SDR_UNIT_RATE_DAY 6 /* per day */
#define SDR_UNIT_RATE_RSVD 7 /* reserved */
/* IPMI 2.0, Table 43-1, byte 21[2:1] Modifier Unit */
#define SDR_UNIT_MOD_NONE 0 /* none */
#define SDR_UNIT_MOD_DIV 1 /* Basic Unit / Modifier Unit */
#define SDR_UNIT_MOD_MUL 2 /* Basic Unit * Mofifier Unit */
#define SDR_UNIT_MOD_RSVD 3 /* Reserved */
/* IPMI 2.0, Table 43-1, byte 21[0] Percentage */
#define SDR_UNIT_PCT_NO 0
#define SDR_UNIT_PCT_YES 1
struct {
#if WORDS_BIGENDIAN
uint8_t analog:2;
@ -394,8 +436,8 @@ struct sdr_record_common_sensor {
uint8_t analog:2;
#endif
struct {
uint8_t base;
uint8_t modifier;
uint8_t base; /* Base unit type code per IPMI 2.0 Table 43-15 */
uint8_t modifier; /* Modifier unit type code per Table 43-15 */
} ATTRIBUTE_PACKING type;
} ATTRIBUTE_PACKING unit;
} ATTRIBUTE_PACKING;
@ -442,7 +484,7 @@ struct sdr_record_compact_sensor {
uint8_t __reserved[3];
uint8_t oem; /* reserved for OEM use */
uint8_t id_code; /* sensor ID string type/length code */
uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */
uint8_t id_string[SDR_ID_STRING_MAX]; /* sensor ID string bytes */
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
@ -493,7 +535,7 @@ struct sdr_record_eventonly_sensor {
uint8_t __reserved;
uint8_t oem; /* reserved for OEM use */
uint8_t id_code; /* sensor ID string type/length code */
uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */
uint8_t id_string[SDR_ID_STRING_MAX]; /* sensor ID string bytes */
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
@ -563,7 +605,7 @@ struct sdr_record_full_sensor {
uint8_t __reserved[2];
uint8_t oem; /* reserved for OEM use */
uint8_t id_code; /* sensor ID string type/length code */
uint8_t id_string[16]; /* sensor ID string bytes, only if id_code != 0 */
uint8_t id_string[SDR_ID_STRING_MAX]; /* sensor ID string bytes */
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
@ -595,7 +637,7 @@ struct sdr_record_mc_locator {
struct entity_id entity;
uint8_t oem;
uint8_t id_code;
uint8_t id_string[16];
uint8_t id_string[SDR_ID_STRING_MAX];
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
@ -628,7 +670,7 @@ struct sdr_record_fru_locator {
struct entity_id entity;
uint8_t oem;
uint8_t id_code;
uint8_t id_string[16];
uint8_t id_string[SDR_ID_STRING_MAX];
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
@ -662,7 +704,7 @@ struct sdr_record_generic_locator {
struct entity_id entity;
uint8_t oem;
uint8_t id_code;
uint8_t id_string[16];
uint8_t id_string[SDR_ID_STRING_MAX];
} ATTRIBUTE_PACKING;
#ifdef HAVE_PRAGMA_PACK
#pragma pack(0)
@ -776,9 +818,12 @@ struct sdr_record_list {
#define SENSOR_TYPE_MAX 0x2C
struct sensor_reading {
char s_id[17]; /* name of the sensor */
struct sdr_record_full_sensor *full;
struct sdr_record_compact_sensor *compact;
char s_id[SDR_ID_STRING_MAX + 1]; /* sensor name, null-terminated */
union {
struct sdr_record_full_sensor *full;
struct sdr_record_compact_sensor *compact;
void *raw;
};
uint8_t s_reading_valid; /* read value valididity */
uint8_t s_scanning_disabled; /* read of value disabled */
uint8_t s_reading_unavailable; /* read value unavailable */
@ -824,7 +869,7 @@ uint8_t *ipmi_sdr_get_record(struct ipmi_intf *intf, struct sdr_get_rs *header,
void ipmi_sdr_end(struct ipmi_sdr_iterator *i);
int ipmi_sdr_print_sdr(struct ipmi_intf *intf, uint8_t type);
int ipmi_sdr_print_name_from_rawentry(uint16_t id, uint8_t type,uint8_t * raw);
int sdr_get_name_from_rawentry(uint8_t type, void *raw, char *buf, size_t len);
int ipmi_sdr_print_rawentry(struct ipmi_intf *intf, uint8_t type, uint8_t * raw,
int len);
int ipmi_sdr_print_listentry(struct ipmi_intf *intf,
@ -833,8 +878,8 @@ void ipmi_sdr_print_sensor_hysteresis(struct sdr_record_common_sensor *sensor,
struct sdr_record_full_sensor *full,
uint8_t hysteresis_value,
const char *hdrstr);
const char *ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type,
uint8_t base, uint8_t modifier);
const char *ipmi_sdr_get_unit_string(bool pct, uint8_t type,
uint8_t base, uint8_t modifier);
struct sensor_reading *
ipmi_sdr_read_sensor_value(struct ipmi_intf *intf,
struct sdr_record_common_sensor *sensor,

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

@ -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 \
@ -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,75 +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 {
print "{ " PEN ", \"" ENTERPRISE "\" },"
}'
}
echo "Generating IANA PEN list..."
curl -# "$PENLIST_URL" | parse_pen_list > "$OUTFILE"

View File

@ -1621,7 +1621,7 @@ ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id)
struct ipmi_rq req;
struct fru_info fru;
uint8_t *spd_data, msg_data[4];
int len, offset;
uint32_t len, offset;
msg_data[0] = id;
@ -1697,6 +1697,13 @@ ipmi_spd_print_fru(struct ipmi_intf * intf, uint8_t id)
}
len = rsp->data[0];
if(rsp->data_len < 1
|| len > rsp->data_len - 1
|| len > fru.size - offset)
{
printf(" Not enough buffer size");
return -1;
}
memcpy(&spd_data[offset], rsp->data + 1, len);
offset += len;
} while (offset < fru.size);

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;
@ -1080,3 +1125,35 @@ ipmi_get_oem_id(struct ipmi_intf *intf)
return oem_id;
}
/** Parse command line arguments as numeric byte values (dec or hex)
* and store them in a \p len sized buffer \p out.
*
* @param[in] argc Number of arguments
* @param[in] argv Array of arguments
* @param[out] out The output buffer
* @param[in] len Length of the output buffer in bytes (no null-termination
* is assumed, the input data is treated as raw byte values,
* not as a string.
*
* @returns A success status indicator
* @return false Error
* @return true Success
*/
bool
args2buf(int argc, char *argv[], uint8_t *out, size_t len)
{
size_t i;
for (i = 0; i < len && i < (size_t)argc; ++i) {
uint8_t byte;
if (str2uchar(argv[i], &byte)) {
lprintf(LOG_ERR, "Bad byte value: %s", argv[i]);
return false;
}
out[i] = byte;
}
return true;
}

View File

@ -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;
}
/**
@ -480,7 +498,10 @@ ipmi_get_channel_cipher_suites(struct ipmi_intf *intf,
lprintf(LOG_ERR, "Unable to Get Channel Cipher Suites");
return -1;
}
if (rsp->ccode || rsp->data_len < 1) {
if (rsp->ccode
|| rsp->data_len < 1
|| rsp->data_len > sizeof(uint8_t) + MAX_CIPHER_SUITE_DATA_LEN)
{
lprintf(LOG_ERR, "Get Channel Cipher Suites failed: %s",
val2str(rsp->ccode, completion_code_vals));
return -1;
@ -684,13 +705,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",

File diff suppressed because it is too large Load Diff

View File

@ -450,7 +450,7 @@ const struct dcmi_cmd nm_policy_options[] = {
{ 0x02, "disable", "" },
{ 0x03, "domain", "" },
{ 0x04, "inlet", "inlet air temp full limiting (SCRAM)" },
{ 0x06, "correction" "auto, soft, hard" },
{ 0x06, "correction","auto, soft, hard" },
{ 0x08, "power", "power limit in watts" },
{ 0x09, "trig_lim", "time to send alert" },
{ 0x0A, "stats", "moving window averaging time" },

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);
@ -669,7 +663,10 @@ int
read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
uint32_t offset, uint32_t length, uint8_t *frubuf)
{
uint32_t off = offset, tmp, finish;
uint32_t off = offset;
uint32_t tmp;
uint32_t finish;
uint32_t size_left_in_buffer;
struct ipmi_rs * rsp;
struct ipmi_rq req;
uint8_t msg_data[4];
@ -682,10 +679,12 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
finish = offset + length;
if (finish > fru->size) {
memset(frubuf + fru->size, 0, length - fru->size);
finish = fru->size;
lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
"Adjusting to %d",
offset + length, finish - offset);
length = finish - offset;
}
memset(&req, 0, sizeof(req));
@ -721,6 +720,7 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
}
}
size_left_in_buffer = length;
do {
tmp = fru->access ? off >> 1 : off;
msg_data[0] = id;
@ -762,9 +762,18 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
}
tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
if(rsp->data_len < 1
|| tmp > rsp->data_len - 1
|| tmp > size_left_in_buffer)
{
printf(" Not enough buffer size");
return -1;
}
memcpy(frubuf, rsp->data + 1, tmp);
off += tmp;
frubuf += tmp;
size_left_in_buffer -= tmp;
/* sometimes the size returned in the Info command
* is too large. return 0 so higher level function
* still attempts to parse what was returned */
@ -797,7 +806,9 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
uint32_t offset, uint32_t length, uint8_t *frubuf)
{
static uint32_t fru_data_rqst_size = 20;
uint32_t off = offset, tmp, finish;
uint32_t off = offset;
uint32_t tmp, finish;
uint32_t size_left_in_buffer;
struct ipmi_rs * rsp;
struct ipmi_rq req;
uint8_t msg_data[4];
@ -810,10 +821,12 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
finish = offset + length;
if (finish > fru->size) {
memset(frubuf + fru->size, 0, length - fru->size);
finish = fru->size;
lprintf(LOG_NOTICE, "Read FRU Area length %d too large, "
"Adjusting to %d",
offset + length, finish - offset);
length = finish - offset;
}
memset(&req, 0, sizeof(req));
@ -828,6 +841,8 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
if (fru->access && fru_data_rqst_size > 16)
#endif
fru_data_rqst_size = 16;
size_left_in_buffer = length;
do {
tmp = fru->access ? off >> 1 : off;
msg_data[0] = id;
@ -859,8 +874,16 @@ read_fru_area_section(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
}
tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
if(rsp->data_len < 1
|| tmp > rsp->data_len - 1
|| tmp > size_left_in_buffer)
{
printf(" Not enough buffer size");
return -1;
}
memcpy((frubuf + off)-offset, rsp->data + 1, tmp);
off += tmp;
size_left_in_buffer -= tmp;
/* sometimes the size returned in the Info command
* is too large. return 0 so higher level function
@ -2872,32 +2895,27 @@ 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
*
* @param[in] intf ipmi interface
* @param[in] id fru id
* @param[out] fru fru info structure pointer
* @param[out] size size of the allocated fru structure
*
* @retval 0 error
* @retval 1 success
*/
static int __ipmi_get_fru_hdr(struct ipmi_intf *intf,
uint8_t id,
struct fru_info *fru,
struct fru_header *header)
/* __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 ipmi_rs *rsp;
struct ipmi_rs * rsp;
struct ipmi_rq req;
struct fru_info fru;
struct fru_header header;
uint8_t msg_data[4];
/* Sanity checks */
if (!fru) return 0;
if (!header) return 0;
if (!intf) return 0;
memset(fru, 0, sizeof(*fru));
memset(header, 0, sizeof(*header));
memset(&fru, 0, sizeof(struct fru_info));
memset(&header, 0, sizeof(struct fru_header));
/*
* get info about this FRU
@ -2914,63 +2932,66 @@ static int __ipmi_get_fru_hdr(struct ipmi_intf *intf,
rsp = intf->sendrecv(intf, &req);
if (!rsp) {
printf(" Device not present (No Response)\n");
return 0;
return -1;
}
if (rsp->ccode) {
printf(" Device not present (%s)\n",
val2str(rsp->ccode, completion_code_vals));
return 0;
val2str(rsp->ccode, completion_code_vals));
return -1;
}
fru->size = (rsp->data[1] << 8) | rsp->data[0];
fru->access = rsp->data[2] & 0x1;
memset(&fru, 0, sizeof(fru));
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");
fru.size, fru.access ? "words" : "bytes");
if (fru->size < 1) {
lprintf(LOG_ERR, " Invalid FRU size %d", fru->size);
return 0;
if (fru.size < 1) {
lprintf(LOG_ERR, " Invalid FRU size %d", fru.size);
return -1;
}
/* Read the FRU header */
if (read_fru_area(intf, fru, id, 0, sizeof(*header), header)) {
lprintf(LOG_ERR, " Failed to read FRU header");
return 0;
/*
* 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 (header->version != 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 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)) {
header.version);
return -1;
}
/* offsets need converted to bytes
* but that conversion is not done to the structure
* because we may end up with offset > 255
* which would overflow our 1-byte offset field */
* but that conversion is not done to the structure
* because we may end up with offset > 255
* which would overflow our 1-byte offset field */
lprintf(LOG_DEBUG, "fru.header.version: 0x%x",
header.version);
@ -3021,7 +3042,6 @@ __ipmi_fru_print(struct ipmi_intf * intf, uint8_t id)
int
ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru)
{
char desc[17];
uint8_t bridged_request = 0;
uint32_t save_addr;
uint32_t save_channel;
@ -3056,10 +3076,10 @@ ipmi_fru_print(struct ipmi_intf * intf, struct sdr_record_fru_locator * fru)
fru->device_id == 0)
return 0;
memset(desc, 0, sizeof(desc));
memcpy(desc, fru->id_string, fru->id_code & 0x01f);
desc[fru->id_code & 0x01f] = 0;
printf("FRU Device Description : %s (ID %d)\n", desc, fru->device_id);
printf("FRU Device Description : %.*s (ID %d)\n"
, SDR_ID_STRLEN(fru)
, fru->id_string
, fru->device_id);
switch (fru->dev_type_modifier) {
case 0x00:
@ -3171,7 +3191,9 @@ ipmi_fru_print_all(struct ipmi_intf * intf)
/* set new target address to satellite controller */
intf->target_addr = mc->dev_slave_addr;
printf("FRU Device Description : %-16s\n", mc->id_string);
printf("FRU Device Description : %.*s\n"
, SDR_ID_STRLEN(fru)
, fru->id_string);
/* print the FRU by issuing FRU commands to the satellite */
/* controller. */
@ -4058,19 +4080,91 @@ ipmi_fru_get_multirec_location_from_fru(struct ipmi_intf * intf,
* returns 1 if device not present
*/
static int
ipmi_fru_get_internal_use_info(struct ipmi_intf *intf,
uint8_t id,
struct fru_info *fru,
uint16_t *size,
uint16_t *offset)
ipmi_fru_get_internal_use_info( struct ipmi_intf * intf,
uint8_t id,
struct fru_info * fru,
uint16_t * size,
uint16_t * offset)
{
struct ipmi_rs * rsp;
struct ipmi_rq req;
struct fru_header header;
uint8_t msg_data[4];
// Init output value
* offset = 0;
* size = 0;
if (!__ipmi_get_fru_hdr(intf, id, fru, &header)) {
memset(fru, 0, sizeof(struct fru_info));
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;
}

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

@ -1260,7 +1260,7 @@ ipmi_lan_set_vlan_id(struct ipmi_intf *intf, uint8_t chan, char *string)
rc = 0;
goto out;
}
if (IPMI_LANP_IS_VLAN_VALID(id)) {
if (!IPMI_LANP_IS_VLAN_VALID(id)) {
lprintf(LOG_ERR,
"Retrieved VLAN ID %i is out of "
"range <%d..%d>.",
@ -1285,7 +1285,7 @@ ipmi_lan_set_vlan_id(struct ipmi_intf *intf, uint8_t chan, char *string)
goto out;
}
if (IPMI_LANP_IS_VLAN_VALID(id)) {
if (!IPMI_LANP_IS_VLAN_VALID(id)) {
lprintf(LOG_NOTICE,
"VLAN ID must be between %d and %d.",
IPMI_LANP_VLAN_ID_MIN,
@ -1865,7 +1865,7 @@ ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
if (!p) {
return (-1);
}
memcpy(data, p->data, p->data_len);
memcpy(data, p->data, __min(p->data_len, sizeof(data)));
/* set new ipaddr */
memcpy(data+3, temp, 4);
printf("Setting LAN Alert %d IP Address to %d.%d.%d.%d\n", alert,
@ -1880,7 +1880,7 @@ ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
if (!p) {
return (-1);
}
memcpy(data, p->data, p->data_len);
memcpy(data, p->data, __min(p->data_len, sizeof(data)));
/* set new macaddr */
memcpy(data+7, temp, 6);
printf("Setting LAN Alert %d MAC Address to "
@ -1894,7 +1894,7 @@ ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
if (!p) {
return (-1);
}
memcpy(data, p->data, p->data_len);
memcpy(data, p->data, __min(p->data_len, sizeof(data)));
if (strncasecmp(argv[1], "def", 3) == 0 ||
strncasecmp(argv[1], "default", 7) == 0) {
@ -1920,7 +1920,7 @@ ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
if (!p) {
return (-1);
}
memcpy(data, p->data, p->data_len);
memcpy(data, p->data, __min(p->data_len, sizeof(data)));
if (strncasecmp(argv[1], "on", 2) == 0 ||
strncasecmp(argv[1], "yes", 3) == 0) {
@ -1945,7 +1945,7 @@ ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
if (!p) {
return (-1);
}
memcpy(data, p->data, p->data_len);
memcpy(data, p->data, __min(p->data_len, sizeof(data)));
if (strncasecmp(argv[1], "pet", 3) == 0) {
printf("Setting LAN Alert %d destination to PET Trap\n", alert);
@ -1973,7 +1973,7 @@ ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
if (!p) {
return (-1);
}
memcpy(data, p->data, p->data_len);
memcpy(data, p->data, __min(p->data_len, sizeof(data)));
if (str2uchar(argv[1], &data[2]) != 0) {
lprintf(LOG_ERR, "Invalid time: %s", argv[1]);
@ -1989,7 +1989,7 @@ ipmi_lan_alert_set(struct ipmi_intf * intf, uint8_t chan, uint8_t alert,
if (!p) {
return (-1);
}
memcpy(data, p->data, p->data_len);
memcpy(data, p->data, __min(p->data_len, sizeof(data)));
if (str2uchar(argv[1], &data[3]) != 0) {
lprintf(LOG_ERR, "Invalid retry: %s", argv[1]);

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

View File

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

View File

@ -68,8 +68,9 @@ static struct sdr_record_list *sdr_list_head = NULL;
static struct sdr_record_list *sdr_list_tail = NULL;
static struct ipmi_sdr_iterator *sdr_list_itr = NULL;
/* unit description codes (IPMI v1.5 section 37.16) */
#define UNIT_MAX 0x90
/* IPMI 2.0 Table 43-15, Sensor Unit Type Codes */
#define UNIT_TYPE_MAX 92 /* This is the ID of "grams" */
#define UNIT_TYPE_LONGEST_NAME 19 /* This is the length of "color temp deg K" */
static const char *unit_desc[] = {
"unspecified",
"degrees C",
@ -161,7 +162,9 @@ static const char *unit_desc[] = {
"characters",
"error",
"correctable error",
"uncorrectable error"
"uncorrectable error",
"fatal error",
"grams"
};
/* sensor type codes (IPMI v1.5 table 36.3)
@ -216,39 +219,60 @@ 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
/** ipmi_sdr_get_unit_string - return units for base/modifier
*
* @pct: units are a percentage
* @type: unit type
* @base: base
* @modifier: modifier
* @param[in] pct Indicates that units are a percentage
* @param[in] relation Modifier unit to base unit relation
* (SDR_UNIT_MOD_NONE, SDR_UNIT_MOD_MUL,
* or SDR_UNIT_MOD_DIV)
* @param[in] base The base unit type id
* @param[in] modifier The modifier unit type id
*
* returns pointer to static string
* @returns a pointer to static string
*/
const char *
ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifier)
ipmi_sdr_get_unit_string(bool pct, uint8_t relation,
uint8_t base, uint8_t modifier)
{
static char unitstr[16];
/*
* Twice as long as the longest possible unit name, plus
* two characters for '%' and relation (either '*' or '/'),
* plus the terminating null-byte.
*/
static char unitstr[2 * UNIT_TYPE_LONGEST_NAME + 2 + 1];
/*
* By default, if units are supposed to be percent, we will pre-pend
* the percent string to the textual representation of the units.
*/
char *pctstr = pct ? "% " : "";
memset(unitstr, 0, sizeof (unitstr));
switch (type) {
case 2:
snprintf(unitstr, sizeof (unitstr), "%s%s * %s",
pctstr, unit_desc[base], unit_desc[modifier]);
const char *pctstr = pct ? "% " : "";
const char *basestr;
const char *modstr;
if (base <= UNIT_TYPE_MAX) {
basestr = unit_desc[base];
}
else {
basestr = "invalid";
}
if (modifier <= UNIT_TYPE_MAX) {
modstr = unit_desc[base];
}
else {
modstr = "invalid";
}
switch (relation) {
case SDR_UNIT_MOD_MUL:
snprintf(unitstr, sizeof (unitstr), "%s%s*%s",
pctstr, basestr, modstr);
break;
case 1:
case SDR_UNIT_MOD_DIV:
snprintf(unitstr, sizeof (unitstr), "%s%s/%s",
pctstr, unit_desc[base], unit_desc[modifier]);
pctstr, basestr, modstr);
break;
case 0:
case SDR_UNIT_MOD_NONE:
default:
/*
* Display the text "percent" only when the Base unit is
@ -257,8 +281,8 @@ ipmi_sdr_get_unit_string(uint8_t pct, uint8_t type, uint8_t base, uint8_t modifi
if (base == 0 && pct) {
snprintf(unitstr, sizeof(unitstr), "percent");
} else {
snprintf(unitstr, sizeof (unitstr), "%s%s",
pctstr, unit_desc[base]);
snprintf(unitstr, sizeof (unitstr), "%s%s",
pctstr, basestr);
}
break;
}
@ -1550,22 +1574,14 @@ ipmi_sdr_read_sensor_value(struct ipmi_intf *intf,
/* Initialize to reading valid value of zero */
memset(&sr, 0, sizeof(sr));
sr.raw = sensor;
switch (sdr_record_type) {
unsigned int idlen;
case (SDR_RECORD_TYPE_FULL_SENSOR):
sr.full = (struct sdr_record_full_sensor *)sensor;
idlen = sr.full->id_code & 0x1f;
idlen = idlen < sizeof(sr.s_id) ?
idlen : sizeof(sr.s_id) - 1;
memcpy(sr.s_id, sr.full->id_string, idlen);
case SDR_RECORD_TYPE_FULL_SENSOR:
SDR_ID_TO_CSTRING(sr.s_id, sr.full);
break;
case SDR_RECORD_TYPE_COMPACT_SENSOR:
sr.compact = (struct sdr_record_compact_sensor *)sensor;
idlen = sr.compact->id_code & 0x1f;
idlen = idlen < sizeof(sr.s_id) ?
idlen : sizeof(sr.s_id) - 1;
memcpy(sr.s_id, sr.compact->id_string, idlen);
SDR_ID_TO_CSTRING(sr.s_id, sr.compact);
break;
default:
return NULL;
@ -2224,13 +2240,12 @@ int
ipmi_sdr_print_sensor_eventonly(struct ipmi_intf *intf,
struct sdr_record_eventonly_sensor *sensor)
{
char desc[17];
char desc[SDR_ID_STRING_MAX + 1];
if (!sensor)
return -1;
memset(desc, 0, sizeof (desc));
snprintf(desc, (sensor->id_code & 0x1f) + 1, "%s", sensor->id_string);
SDR_ID_TO_CSTRING(desc, sensor);
if (verbose) {
printf("Sensor ID : %s (0x%x)\n",
@ -2273,13 +2288,12 @@ ipmi_sdr_print_sensor_eventonly(struct ipmi_intf *intf,
int
ipmi_sdr_print_sensor_mc_locator(struct sdr_record_mc_locator *mc)
{
char desc[17];
char desc[SDR_ID_STRING_MAX + 1];
if (!mc)
return -1;
memset(desc, 0, sizeof (desc));
snprintf(desc, (mc->id_code & 0x1f) + 1, "%s", mc->id_string);
SDR_ID_TO_CSTRING(desc, mc);
if (verbose == 0) {
if (csv_output)
@ -2367,10 +2381,12 @@ ipmi_sdr_print_sensor_mc_locator(struct sdr_record_mc_locator *mc)
int
ipmi_sdr_print_sensor_generic_locator(struct sdr_record_generic_locator *dev)
{
char desc[17];
char desc[SDR_ID_STRING_MAX + 1];
memset(desc, 0, sizeof (desc));
snprintf(desc, (dev->id_code & 0x1f) + 1, "%s", dev->id_string);
if (!dev)
return -1;
SDR_ID_TO_CSTRING(desc, dev);
if (!verbose) {
if (csv_output)
@ -2422,10 +2438,12 @@ ipmi_sdr_print_sensor_generic_locator(struct sdr_record_generic_locator *dev)
int
ipmi_sdr_print_sensor_fru_locator(struct sdr_record_fru_locator *fru)
{
char desc[17];
char desc[SDR_ID_STRING_MAX + 1];
memset(desc, 0, sizeof (desc));
snprintf(desc, (fru->id_code & 0x1f) + 1, "%s", fru->id_string);
if (!fru)
return -1;
SDR_ID_TO_CSTRING(desc, fru);
if (!verbose) {
if (csv_output)
@ -2585,17 +2603,20 @@ ipmi_sdr_print_sensor_oem(struct sdr_record_oem *oem)
return rc;
}
/* ipmi_sdr_print_name_from_rawentry - Print SDR name from raw data
/**
* Get SDR record name from raw data
*
* @type: sensor type
* @raw: raw sensor data
* @param[in] type SDR record type
* @param[in] raw raw SDR record data
* @param[out] buf The SDR record description target buffer
* @param[in] len The length of the target buffer
*
* returns 0 on success
* returns -1 on error
* @returns Error status
* @retval 0 Success
* @retval -1 Error
*/
int
ipmi_sdr_print_name_from_rawentry(uint16_t id,
uint8_t type, uint8_t *raw)
sdr_get_name_from_rawentry(uint8_t type, void *raw, char *buf, size_t len)
{
union {
struct sdr_record_full_sensor *full;
@ -2606,39 +2627,50 @@ ipmi_sdr_print_name_from_rawentry(uint16_t id,
struct sdr_record_mc_locator *mcloc;
struct sdr_record_entity_assoc *entassoc;
struct sdr_record_oem *oem;
void *raw;
} record;
int rc =0;
char desc[17];
memset(desc, ' ', sizeof (desc));
char desc[SDR_ID_STRING_MAX + 1] = { 0 };
record.raw = raw;
switch ( type) {
/* Sensor records */
case SDR_RECORD_TYPE_FULL_SENSOR:
record.full = (struct sdr_record_full_sensor *) raw;
snprintf(desc, (record.full->id_code & 0x1f) +1, "%s",
(const char *)record.full->id_string);
SDR_ID_TO_CSTRING(desc, record.full);
break;
case SDR_RECORD_TYPE_COMPACT_SENSOR:
record.compact = (struct sdr_record_compact_sensor *) raw ;
snprintf(desc, (record.compact->id_code & 0x1f) +1, "%s",
(const char *)record.compact->id_string);
SDR_ID_TO_CSTRING(desc, record.compact);
break;
case SDR_RECORD_TYPE_EVENTONLY_SENSOR:
record.eventonly = (struct sdr_record_eventonly_sensor *) raw ;
snprintf(desc, (record.eventonly->id_code & 0x1f) +1, "%s",
(const char *)record.eventonly->id_string);
break;
case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
record.mcloc = (struct sdr_record_mc_locator *) raw ;
snprintf(desc, (record.mcloc->id_code & 0x1f) +1, "%s",
(const char *)record.mcloc->id_string);
SDR_ID_TO_CSTRING(desc, record.eventonly);
break;
/* Device locator records */
case SDR_RECORD_TYPE_GENERIC_DEVICE_LOCATOR:
SDR_ID_TO_CSTRING(desc, record.genloc);
break;
case SDR_RECORD_TYPE_FRU_DEVICE_LOCATOR:
SDR_ID_TO_CSTRING(desc, record.fruloc);
break;
case SDR_RECORD_TYPE_MC_DEVICE_LOCATOR:
SDR_ID_TO_CSTRING(desc, record.mcloc);
break;
/* All other records don't have the id_string field */
default:
rc = -1;
break;
}
}
memcpy(buf, desc, __min(sizeof(buf), len));
lprintf(LOG_INFO, "ID: 0x%04x , NAME: %-16s", id, desc);
return rc;
}

View File

@ -250,6 +250,7 @@ sdrr_get_records(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr,
while ((header = ipmi_sdr_get_next_header(intf, itr))) {
struct sdr_record_list *sdrr;
char desc[SDR_ID_STRING_MAX + 1];
sdrr = malloc(sizeof (struct sdr_record_list));
if (!sdrr) {
@ -263,7 +264,8 @@ sdrr_get_records(struct ipmi_intf *intf, struct ipmi_sdr_iterator *itr,
sdrr->type = header->type;
sdrr->length = header->length;
sdrr->raw = ipmi_sdr_get_record(intf, header, itr);
(void)ipmi_sdr_print_name_from_rawentry(sdrr->id, sdrr->type,sdrr->raw);
(void)sdr_get_name_from_rawentry(sdrr->type, sdrr->raw, desc, sizeof(desc));
lprintf(LOG_INFO, "ID: 0x%04x , NAME: %s", sdrr->id, desc);
/* put in the record queue */
if (!queue->head)

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);
@ -2743,6 +2743,7 @@ ipmi_sel_set_time(struct ipmi_intf * intf, const char * time_string)
struct ipmi_rs *rsp;
struct ipmi_rq req;
struct tm tm = {0};
uint8_t msg_data[4] = {0};
time_t t;
const char *time_format = "%x %X"; /* Use locale-defined format */
@ -2787,8 +2788,9 @@ ipmi_sel_set_time(struct ipmi_intf * intf, const char * time_string)
* At this point `t` is UTC. Convert it to LE and send.
*/
req.msg.data = msg_data;
htoipmi32(t, req.msg.data);
req.msg.data_len = 4;
req.msg.data_len = sizeof(msg_data);
rsp = intf->sendrecv(intf, &req);
if (!rsp || rsp->ccode) {

View File

@ -309,8 +309,10 @@ ipmi_get_session_info(struct ipmi_intf * intf,
}
else
{
memcpy(&session_info, rsp->data, rsp->data_len);
print_session_info(&session_info, rsp->data_len);
memcpy(&session_info, rsp->data,
__min(rsp->data_len, sizeof(session_info)));
print_session_info(&session_info,
__min(rsp->data_len, sizeof(session_info)));
}
break;
@ -341,8 +343,10 @@ ipmi_get_session_info(struct ipmi_intf * intf,
break;
}
memcpy(&session_info, rsp->data, rsp->data_len);
print_session_info(&session_info, rsp->data_len);
memcpy(&session_info, rsp->data,
__min(rsp->data_len, sizeof(session_info)));
print_session_info(&session_info,
__min(rsp->data_len, sizeof(session_info)));
} while (i <= session_info.session_slot_count);
break;

File diff suppressed because it is too large Load Diff

View File

@ -434,7 +434,7 @@ print_user_usage(void)
lprintf(LOG_NOTICE,
" set name <user id> <username>");
lprintf(LOG_NOTICE,
" set password <user id> [<password> <16|20>]");
" set password <user id> [<password> [<16|20>]]");
lprintf(LOG_NOTICE,
" disable <user id>");
lprintf(LOG_NOTICE,
@ -626,12 +626,17 @@ ipmi_user_mod(struct ipmi_intf *intf, int argc, char **argv)
return 0;
}
#define USER_PW_IPMI15_LEN 16 /* IPMI 1.5 only allowed for 16 bytes */
#define USER_PW_IPMI20_LEN 20 /* IPMI 2.0 allows for 20 bytes */
#define USER_PW_MAX_LEN USER_PW_IPMI20_LEN
int
ipmi_user_password(struct ipmi_intf *intf, int argc, char **argv)
{
char *password = NULL;
int ccode = 0;
uint8_t password_type = 16;
uint8_t password_type = USER_PW_IPMI15_LEN;
size_t password_len;
uint8_t user_id = 0;
if (is_ipmi_user_id(argv[2], &user_id)) {
return (-1);
@ -640,52 +645,63 @@ ipmi_user_password(struct ipmi_intf *intf, int argc, char **argv)
if (argc == 3) {
/* We need to prompt for a password */
char *tmp;
size_t tmplen;
password = ask_password(user_id);
if (!password) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return (-1);
}
tmp = ask_password(user_id);
tmplen = strnlen(tmp, USER_PW_MAX_LEN + 1);
if (!tmp) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return (-1);
}
if (strlen(password) != strlen(tmp)
|| strncmp(password, tmp, strlen(tmp))) {
lprintf(LOG_ERR, "Passwords do not match.");
if (strncmp(password, tmp, tmplen)) {
lprintf(LOG_ERR, "Passwords do not match or are "
"longer than %d", USER_PW_MAX_LEN);
return (-1);
}
} else {
password = argv[3];
if (argc > 4) {
if ((str2uchar(argv[4], &password_type) != 0)
|| (password_type != 16 && password_type != 20)) {
lprintf(LOG_ERR, "Invalid password length '%s'", argv[4]);
return (-1);
}
} else {
password_type = 16;
}
}
if (!password) {
lprintf(LOG_ERR, "Unable to parse password argument.");
return (-1);
} else if (strlen(password) > 20) {
lprintf(LOG_ERR, "Password is too long (> 20 bytes)");
}
password_len = strnlen(password, USER_PW_MAX_LEN + 1);
if (argc > 4) {
if ((str2uchar(argv[4], &password_type) != 0)
|| (password_type != USER_PW_IPMI15_LEN
&& password_type != USER_PW_IPMI20_LEN))
{
lprintf(LOG_ERR, "Invalid password length '%s'",
argv[4]);
return (-1);
}
} else if (password_len > USER_PW_IPMI15_LEN) {
password_type = USER_PW_IPMI20_LEN;
}
if (password_len > password_type) {
lprintf(LOG_ERR, "Password is too long (> %d bytes)",
password_type);
return (-1);
}
ccode = _ipmi_set_user_password(intf, user_id,
IPMI_PASSWORD_SET_PASSWORD, password,
password_type > 16);
IPMI_PASSWORD_SET_PASSWORD, password,
password_type > USER_PW_IPMI15_LEN);
if (eval_ccode(ccode) != 0) {
lprintf(LOG_ERR, "Set User Password command failed (user %d)",
user_id);
user_id);
return (-1);
} else {
printf("Set User Password command successful (user %d)\n",
user_id);
user_id);
return 0;
}
}

View File

@ -32,11 +32,12 @@ MAINTAINERCLEANFILES = Makefile.in
AM_CPPFLAGS = -I$(top_srcdir)/include
SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ @INTF_USB@
DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy usb
SUBDIRS = @INTF_LAN@ @INTF_LANPLUS@ @INTF_OPEN@ @INTF_LIPMI@ @INTF_IMB@ @INTF_BMC@ @INTF_FREE@ @INTF_SERIAL@ @INTF_DUMMY@ @INTF_USB@ @INTF_DBUS@
DIST_SUBDIRS = lan lanplus open lipmi imb bmc free serial dummy usb dbus
noinst_LTLIBRARIES = libintf.la
libintf_la_SOURCES = ipmi_intf.c
libintf_la_CFLAGS = -DDEFAULT_INTF='"@DEFAULT_INTF@"'
libintf_la_LDFLAGS = -export-dynamic
libintf_la_LIBADD = @IPMITOOL_INTF_LIB@
libintf_la_DEPENDENCIES = @IPMITOOL_INTF_LIB@

View File

@ -0,0 +1,41 @@
#
# Copyright (c) 2015 IBM Corporation
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification,are permitted provided that the following conditions are met:
#
# 1. Redistributions of source code must retain the above copyright notice,
# this list of conditions and the following disclaimer.
#
# 2. Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# 3. Neither the name of the copyright holder nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES,INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
# POSSIBILITY OF SUCH DAMAGE.
#
MAINTAINERCLEANFILES = Makefile.in
AM_CPPFLAGS = -I$(top_srcdir)/include
EXTRA_LTLIBRARIES = libintf_dbus.la
noinst_LTLIBRARIES = @INTF_DBUS_LIB@
libintf_dbus_la_LDFLAGS = -lsystemd
libintf_dbus_la_LIBADD = $(top_builddir)/lib/libipmitool.la
libintf_dbus_la_SOURCES = dbus.c

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

@ -0,0 +1,241 @@
/*
* Copyright (c) 2015 IBM Corporation
* Copyright (c) 2019 Intel Corporation
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <sys/file.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <unistd.h>
#include <stdbool.h>
#include <systemd/sd-bus.h>
#include <ipmitool/log.h>
#include <ipmitool/ipmi.h>
#include <ipmitool/ipmi_intf.h>
static sd_bus *bus;
static
struct ipmi_rs *
ipmi_dbus_sendrecv(struct ipmi_intf *intf,
struct ipmi_rq *req)
{
static const char *destination = "xyz.openbmc_project.Ipmi.Host";
static const char *object_path = "/xyz/openbmc_project/Ipmi";
static const char *interface = "xyz.openbmc_project.Ipmi.Server";
static const char *method_name = "execute";
static const char SD_BUS_TYPE_3_BYTES[] = {
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, 0
};
static const char SD_BUS_TYPE_4_BYTES[] = {
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE, 0
};
static const char SD_BUS_TYPE_DICT_OF_VARIANTS[] = {
SD_BUS_TYPE_ARRAY,
SD_BUS_TYPE_DICT_ENTRY_BEGIN,
SD_BUS_TYPE_STRING, SD_BUS_TYPE_VARIANT,
SD_BUS_TYPE_DICT_ENTRY_END, 0
};
static const char SD_BUS_TYPE_IPMI_RESPONSE[] = {
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
SD_BUS_TYPE_BYTE, SD_BUS_TYPE_BYTE,
SD_BUS_TYPE_ARRAY, SD_BUS_TYPE_BYTE, 0
};
sd_bus_message *request = NULL;
int rc;
sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus_message* reply = NULL;
uint8_t recv_netfn;
uint8_t recv_lun;
uint8_t recv_cmd;
uint8_t recv_cc;
const void *data;
size_t data_len;
static struct ipmi_rs rsp;
struct ipmi_rs *ipmi_response = NULL;
if (!intf->opened || !bus)
{
goto out_no_free;
}
rsp.ccode = IPMI_CC_UNSPECIFIED_ERROR;
rsp.data_len = 0;
memset(rsp.data, 0, sizeof(rsp.data));
/* The D-Bus xyz.openbmc_project.Ipmi.Server.execute interface
* looks like this:
*
* Request:
* byte: net function
* byte: lun
* byte: command
* byte array: data (possibly zero length)
* array of (string,variant): options
* Response:
* byte: net function
* byte: lun
* byte: command
* byte: completion code
* byte array: response data (possibly zero length)
*/
rc = sd_bus_message_new_method_call(bus, &request, destination,
object_path, interface,
method_name);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to create message: %s\n",
__func__, strerror(-rc));
goto out_no_free;
}
/* pack the header: netfn, lun, cmd */
rc = sd_bus_message_append(request, SD_BUS_TYPE_3_BYTES, req->msg.netfn,
req->msg.lun, req->msg.cmd);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to append parameters\n", __func__);
goto out_free_request;
}
/* pack the variable length data */
rc = sd_bus_message_append_array(request, SD_BUS_TYPE_BYTE,
req->msg.data, req->msg.data_len);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to append body\n", __func__);
goto out_free_request;
}
/* Options are only needed for session-based channels, but
* in order to fulfill the correct signature, an empty array
* must be packed */
rc = sd_bus_message_append(request, SD_BUS_TYPE_DICT_OF_VARIANTS,
NULL, 0);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to append options\n", __func__);
goto out_free_request;
}
rc = sd_bus_call(bus, request, 0, &error, &reply);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to send dbus message (%s)\n",
__func__, error.message);
goto out_free_request;
}
/* unpack the response; check that it has the expected types */
rc = sd_bus_message_enter_container(reply, SD_BUS_TYPE_STRUCT,
SD_BUS_TYPE_IPMI_RESPONSE);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to parse reply\n", __func__);
goto out_free_reply;
}
/* read the header: CC netfn lun cmd */
rc = sd_bus_message_read(reply, SD_BUS_TYPE_4_BYTES, &recv_netfn,
&recv_lun, &recv_cmd, &recv_cc);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to read reply\n", __func__);
goto out_free_reply;
}
/* read the variable length data */
rc = sd_bus_message_read_array(reply, SD_BUS_TYPE_BYTE,
&data, &data_len);
if (rc < 0) {
lprintf(LOG_ERR, "%s: failed to read reply data\n", __func__);
goto out_free_reply;
}
rc = sd_bus_message_exit_container(reply);
if (rc < 0) {
lprintf(LOG_ERR, "%s: final unpack of message failed\n",
__func__);
goto out_free_reply;
}
if (data_len > sizeof(rsp.data)) {
lprintf(LOG_ERR, "%s: data too long!\n", __func__);
goto out_free_reply;
}
/* At this point, all the parts are available for a response
* other than unspecified error. */
rsp.ccode = recv_cc;
rsp.data_len = data_len;
memcpy(rsp.data, data, data_len);
ipmi_response = &rsp;
out_free_reply:
/* message unref will free resources owned by the message */
sd_bus_message_unref(reply);
out_free_request:
sd_bus_message_unref(request);
out_no_free:
return ipmi_response;
}
static
int
ipmi_dbus_setup(struct ipmi_intf *intf)
{
int rc;
rc = sd_bus_default_system(&bus);
if (rc < 0) {
lprintf(LOG_ERR, "Can't connect to session bus: %s\n",
strerror(-rc));
return -1;
}
intf->opened = 1;
return 0;
}
static
void
ipmi_dbus_close(struct ipmi_intf *intf)
{
if (intf->opened)
{
sd_bus_close(bus);
}
intf->opened = 0;
}
struct ipmi_intf ipmi_dbus_intf = {
.name = "dbus",
.desc = "OpenBMC D-Bus interface",
.setup = ipmi_dbus_setup,
.close = ipmi_dbus_close,
.sendrecv = ipmi_dbus_sendrecv,
};

View File

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

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