ID:302 - HPM.2 long message support

This patch adds basic long message support for PICMG-based systems according to
the HPM.2 specification.
It also introduces APIs for setting inbound and outbound messages sizes per
selected interface.
This APIs are used in LAN and LAN+ interfaces to set autonomously detected
inbound and outbound message sizes.
The newly introduced APIs also replace the existing message size detection code
in several ipmitool commands in order to leverage the advantages of long message
support (HPM.1 upgrade, SDR acquring, FRU inventory read and write).
The Kontron-specific long message support is moved under a OEM option.

Commit for Dmitry Bazhenov
This commit is contained in:
Zdenek Styblik
2014-04-08 15:18:50 +02:00
parent 707d77ffbc
commit 23e9340b49
15 changed files with 741 additions and 52 deletions

View File

@@ -53,6 +53,8 @@
#include <ipmitool/ipmi_sdr.h>
#include <ipmitool/log.h>
#define IPMI_DEFAULT_PAYLOAD_SIZE 25
#ifdef IPMI_INTF_OPEN
extern struct ipmi_intf ipmi_open_intf;
#endif
@@ -497,3 +499,153 @@ ipmi_intf_socket_connect(struct ipmi_intf * intf)
}
#endif
uint16_t
ipmi_intf_get_max_request_data_size(struct ipmi_intf * intf)
{
int16_t size;
size = intf->max_request_data_size;
/* check if request size is not specified */
if (!size) {
/*
* The IPMB standard overall message length for non -bridging
* messages is specified as 32 bytes, maximum, including slave
* address. This sets the upper limit for typical IPMI messages.
* With the exception of messages used for bridging messages to
* other busses or interfaces (e.g. Master Write-Read and Send Message)
* IPMI messages should be designed to fit within this 32-byte maximum.
* In order to support bridging, the Master Write -Read and Send Message
* commands are allowed to exceed the 32-byte maximum transaction on IPMB
*/
size = IPMI_DEFAULT_PAYLOAD_SIZE;
/* check if message is forwarded */
if (intf->target_addr && intf->target_addr != intf->my_addr) {
/* add Send Message request size */
size += 8;
}
}
/* check if message is forwarded */
if (intf->target_addr && intf->target_addr != intf->my_addr) {
/* subtract send message request size */
size -= 8;
/*
* Check that forwarded request size is not greater
* than the default payload size.
*/
if (size > IPMI_DEFAULT_PAYLOAD_SIZE) {
size = IPMI_DEFAULT_PAYLOAD_SIZE;
}
/* check for double bridging */
if (intf->transit_addr && intf->transit_addr != intf->target_addr) {
/* subtract inner send message request size */
size -= 8;
}
}
/* check for underflow */
if (size < 0) {
return 0;
}
return size;
}
uint16_t
ipmi_intf_get_max_response_data_size(struct ipmi_intf * intf)
{
int16_t size;
size = intf->max_response_data_size;
/* check if response size is not specified */
if (!size) {
/*
* The IPMB standard overall message length for non -bridging
* messages is specified as 32 bytes, maximum, including slave
* address. This sets the upper limit for typical IPMI messages.
* With the exception of messages used for bridging messages to
* other busses or interfaces (e.g. Master Write-Read and Send Message)
* IPMI messages should be designed to fit within this 32-byte maximum.
* In order to support bridging, the Master Write -Read and Send Message
* commands are allowed to exceed the 32-byte maximum transaction on IPMB
*/
size = IPMI_DEFAULT_PAYLOAD_SIZE; /* response length with subtracted header and checksum byte */
/* check if message is forwarded */
if (intf->target_addr && intf->target_addr != intf->my_addr) {
/* add Send Message header size */
size += 7;
}
}
/* check if message is forwarded */
if (intf->target_addr && intf->target_addr != intf->my_addr) {
/*
* Some IPMI controllers like PICMG AMC Carriers embed responses
* to the forwarded messages into the Send Message response.
* In order to be sure that the response is not truncated,
* subtract the internal message header size.
*/
size -= 8;
/*
* Check that forwarded response is not greater
* than the default payload size.
*/
if (size > IPMI_DEFAULT_PAYLOAD_SIZE) {
size = IPMI_DEFAULT_PAYLOAD_SIZE;
}
/* check for double bridging */
if (intf->transit_addr && intf->transit_addr != intf->target_addr) {
/* subtract inner send message header size */
size -= 8;
}
}
/* check for underflow */
if (size < 0) {
return 0;
}
return size;
}
void
ipmi_intf_set_max_request_data_size(struct ipmi_intf * intf, uint16_t size)
{
if (size < IPMI_DEFAULT_PAYLOAD_SIZE) {
lprintf(LOG_ERR, "Request size is too small (%d), leave default size",
size);
return;
}
if (intf->set_max_request_data_size) {
intf->set_max_request_data_size(intf, size);
} else {
intf->max_request_data_size = size;
}
}
void
ipmi_intf_set_max_response_data_size(struct ipmi_intf * intf, uint16_t size)
{
if (size < IPMI_DEFAULT_PAYLOAD_SIZE - 1) {
lprintf(LOG_ERR, "Response size is too small (%d), leave default size",
size);
return;
}
if (intf->set_max_response_data_size) {
intf->set_max_response_data_size(intf, size);
} else {
intf->max_response_data_size = size;
}
}

View File

@@ -52,6 +52,7 @@
#include <ipmitool/ipmi_oem.h>
#include <ipmitool/ipmi_strings.h>
#include <ipmitool/ipmi_constants.h>
#include <ipmitool/hpm2.h>
#if HAVE_CONFIG_H
# include <config.h>
@@ -67,6 +68,13 @@
#define IPMI_LAN_PORT 0x26f
#define IPMI_LAN_CHANNEL_E 0x0e
/*
* LAN interface is required to support 45 byte request transactions and
* 42 byte response transactions.
*/
#define IPMI_LAN_MAX_REQUEST_SIZE 38 /* 45 - 7 */
#define IPMI_LAN_MAX_RESPONSE_SIZE 34 /* 42 - 8 */
extern const struct valstr ipmi_privlvl_vals[];
extern const struct valstr ipmi_authtype_session_vals[];
extern int verbose;
@@ -88,6 +96,8 @@ static int ipmi_lan_send_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp);
static int ipmi_lan_open(struct ipmi_intf * intf);
static void ipmi_lan_close(struct ipmi_intf * intf);
static int ipmi_lan_ping(struct ipmi_intf * intf);
static void ipmi_lan_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size);
static void ipmi_lan_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size);
struct ipmi_intf ipmi_lan_intf = {
name: "lan",
@@ -100,6 +110,8 @@ struct ipmi_intf ipmi_lan_intf = {
recv_sol: ipmi_lan_recv_sol,
send_sol: ipmi_lan_send_sol,
keepalive: ipmi_lan_keepalive,
set_max_request_data_size: ipmi_lan_set_max_rq_data_size,
set_max_response_data_size: ipmi_lan_set_max_rp_data_size,
target_addr: IPMI_BMC_SLAVE_ADDR,
};
@@ -2055,6 +2067,10 @@ ipmi_lan_open(struct ipmi_intf * intf)
}
intf->manufacturer_id = ipmi_get_oem(intf);
/* automatically detect interface request and response sizes */
hpm2_detect_max_payload_size(intf);
return intf->fd;
}
@@ -2067,5 +2083,30 @@ ipmi_lan_setup(struct ipmi_intf * intf)
return -1;
}
memset(intf->session, 0, sizeof(struct ipmi_session));
/* setup default LAN maximum request and response sizes */
intf->max_request_data_size = IPMI_LAN_MAX_REQUEST_SIZE;
intf->max_response_data_size = IPMI_LAN_MAX_RESPONSE_SIZE;
return 0;
}
static void
ipmi_lan_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size)
{
if (size + 7 > 0xFF) {
size = 0xFF - 7;
}
intf->max_request_data_size = size;
}
static void
ipmi_lan_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size)
{
if (size + 8 > 0xFF) {
size = 0xFF - 8;
}
intf->max_response_data_size = size;
}

View File

@@ -55,6 +55,7 @@
#include <ipmitool/ipmi_channel.h>
#include <ipmitool/ipmi_intf.h>
#include <ipmitool/ipmi_strings.h>
#include <ipmitool/hpm2.h>
#include <ipmitool/bswap.h>
#include <openssl/rand.h>
@@ -65,6 +66,13 @@
#include "rmcp.h"
#include "asf.h"
/*
* LAN interface is required to support 45 byte request transactions and
* 42 byte response transactions.
*/
#define IPMI_LAN_MAX_REQUEST_SIZE 38 /* 45 - 7 */
#define IPMI_LAN_MAX_RESPONSE_SIZE 34 /* 42 - 8 */
extern const struct valstr ipmi_rakp_return_codes[];
extern const struct valstr ipmi_priv_levels[];
extern const struct valstr ipmi_auth_algorithms[];
@@ -112,8 +120,10 @@ static int check_sol_packet_for_new_data(
static void ack_sol_packet(
struct ipmi_intf * intf,
struct ipmi_rs * rsp);
static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size);
static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size);
static uint8_t bridgePossible = 0;
static uint8_t bridgePossible = 0;
struct ipmi_intf ipmi_lanplus_intf = {
name: "lanplus",
@@ -125,6 +135,8 @@ struct ipmi_intf ipmi_lanplus_intf = {
recv_sol: ipmi_lanplus_recv_sol,
send_sol: ipmi_lanplus_send_sol,
keepalive: ipmi_lanplus_keepalive,
set_max_request_data_size: ipmi_lanp_set_max_rq_data_size,
set_max_response_data_size: ipmi_lanp_set_max_rp_data_size,
target_addr: IPMI_BMC_SLAVE_ADDR,
};
@@ -3473,6 +3485,9 @@ ipmi_lanplus_open(struct ipmi_intf * intf)
intf->manufacturer_id = ipmi_get_oem(intf);
bridgePossible = 1;
/* automatically detect interface request and response sizes */
hpm2_detect_max_payload_size(intf);
return intf->fd;
fail:
@@ -3624,5 +3639,46 @@ static int ipmi_lanplus_setup(struct ipmi_intf * intf)
return -1;
}
memset(intf->session, 0, sizeof(struct ipmi_session));
/* setup default LAN maximum request and response sizes */
intf->max_request_data_size = IPMI_LAN_MAX_REQUEST_SIZE;
intf->max_response_data_size = IPMI_LAN_MAX_RESPONSE_SIZE;
return 0;
}
static void ipmi_lanp_set_max_rq_data_size(struct ipmi_intf * intf, uint16_t size)
{
if (intf->session->cipher_suite_id == 3) {
/*
* encrypted payload can only be multiple of 16 bytes
*/
size &= ~15;
/*
* decrement payload size on confidentiality header size
* plus minimal confidentiality trailer size
*/
size -= (16 + 1);
}
intf->max_request_data_size = size;
}
static void ipmi_lanp_set_max_rp_data_size(struct ipmi_intf * intf, uint16_t size)
{
if (intf->session->cipher_suite_id == 3) {
/*
* encrypted payload can only be multiple of 16 bytes
*/
size &= ~15;
/*
* decrement payload size on confidentiality header size
* plus minimal confidentiality trailer size
*/
size -= (16 + 1);
}
intf->max_response_data_size = size;
}

View File

@@ -65,6 +65,22 @@
# include "open.h"
#endif
/**
* Maximum input message size for KCS/SMIC is 40 with 2 utility bytes and
* 38 bytes of data.
* Maximum input message size for BT is 42 with 4 utility bytes and
* 38 bytes of data.
*/
#define IPMI_OPENIPMI_MAX_RQ_DATA_SIZE 38
/**
* Maximum output message size for KCS/SMIC is 38 with 2 utility bytes, a byte
* for completion code and 35 bytes of data.
* Maximum output message size for BT is 40 with 4 utility bytes, a byte
* for completion code and 35 bytes of data.
*/
#define IPMI_OPENIPMI_MAX_RS_DATA_SIZE 35
extern int verbose;
static int
@@ -401,9 +417,19 @@ ipmi_openipmi_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
return &rsp;
}
int ipmi_openipmi_setup(struct ipmi_intf * intf)
{
/* set default payload size */
intf->max_request_data_size = IPMI_OPENIPMI_MAX_RQ_DATA_SIZE;
intf->max_response_data_size = IPMI_OPENIPMI_MAX_RS_DATA_SIZE;
return 0;
}
struct ipmi_intf ipmi_open_intf = {
name: "open",
desc: "Linux OpenIPMI Interface",
setup: ipmi_openipmi_setup,
open: ipmi_openipmi_open,
close: ipmi_openipmi_close,
sendrecv: ipmi_openipmi_send_cmd,

View File

@@ -189,6 +189,10 @@ serial_bm_setup(struct ipmi_intf * intf)
return -1;
}
memset(intf->session, 0, sizeof(struct ipmi_session));
/* setup default LAN maximum request and response sizes */
intf->max_request_data_size = SERIAL_BM_MAX_RQ_SIZE;
intf->max_response_data_size = SERIAL_BM_MAX_RS_SIZE;
return 0;
}

View File

@@ -894,6 +894,10 @@ ipmi_serial_term_setup(struct ipmi_intf * intf)
}
memset(intf->session, 0, sizeof(struct ipmi_session));
/* setup default LAN maximum request and response sizes */
intf->max_request_data_size = IPMI_SERIAL_MAX_RQ_SIZE;
intf->max_response_data_size = IPMI_SERIAL_MAX_RS_SIZE;
return 0;
}