summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZdenek Styblik <stybla@turnovfree.net>2014-04-08 15:18:50 +0200
committerZdenek Styblik <stybla@turnovfree.net>2014-04-08 15:18:50 +0200
commit23e9340b49c7f339762dda0c3d56a1db6ef6efb1 (patch)
tree07480b230c96a8082ba715582a18aa2998ac08fb
parent707d77ffbc8930fe3a899da16fa1405a76c5eb19 (diff)
downloadipmitool-23e9340b49c7f339762dda0c3d56a1db6ef6efb1.tar.gz
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
-rw-r--r--include/ipmitool/hpm2.h86
-rw-r--r--include/ipmitool/ipmi_intf.h5
-rw-r--r--lib/Makefile.am2
-rw-r--r--lib/hpm2.c288
-rw-r--r--lib/ipmi_fru.c42
-rw-r--r--lib/ipmi_hpmfwupg.c50
-rw-r--r--lib/ipmi_main.c18
-rw-r--r--lib/ipmi_oem.c4
-rw-r--r--lib/ipmi_sdr.c13
-rw-r--r--src/plugins/ipmi_intf.c152
-rw-r--r--src/plugins/lan/lan.c41
-rw-r--r--src/plugins/lanplus/lanplus.c58
-rw-r--r--src/plugins/open/open.c26
-rw-r--r--src/plugins/serial/serial_basic.c4
-rw-r--r--src/plugins/serial/serial_terminal.c4
15 files changed, 741 insertions, 52 deletions
diff --git a/include/ipmitool/hpm2.h b/include/ipmitool/hpm2.h
new file mode 100644
index 0000000..1c0a612
--- /dev/null
+++ b/include/ipmitool/hpm2.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2012 Pigeon Point Systems. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution 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.
+ *
+ * Neither the name of Pigeon Point Systems nor the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <stdint.h>
+#include <ipmitool/ipmi_intf.h>
+
+/* Global HPM.2 defines */
+#define HPM2_REVISION 0x01
+#define HPM3_REVISION 0x01
+#define HPM2_LAN_PARAMS_REV 0x01
+#define HPM2_SOL_PARAMS_REV 0x01
+#define HPM3_LAN_PARAMS_REV 0x01
+
+/* HPM.2 capabilities */
+#define HPM2_CAPS_SOL_EXTENSION 0x01
+#define HPM2_CAPS_PACKET_TRACE 0x02
+#define HPM2_CAPS_EXT_MANAGEMENT 0x04
+#define HPM2_CAPS_VERSION_SENSOR 0x08
+#define HPM2_CAPS_DYNAMIC_SESSIONS 0x10
+
+#if HAVE_PRAGMA_PACK
+# pragma pack(push, 1)
+#endif
+
+/* HPM.2 LAN attach capabilities */
+struct hpm2_lan_attach_capabilities {
+ uint8_t hpm2_revision_id;
+ uint16_t lan_channel_mask;
+ uint8_t hpm2_caps;
+ uint8_t hpm2_lan_params_start;
+ uint8_t hpm2_lan_params_rev;
+ uint8_t hpm2_sol_params_start;
+ uint8_t hpm2_sol_params_rev;
+} ATTRIBUTE_PACKING;
+
+/* HPM.2 LAN channel capabilities */
+struct hpm2_lan_channel_capabilities {
+ uint8_t capabilities;
+ uint8_t attach_type;
+ uint8_t bandwidth_class;
+ uint16_t max_inbound_pld_size;
+ uint16_t max_outbound_pld_size;
+} ATTRIBUTE_PACKING;
+
+#if HAVE_PRAGMA_PACK
+# pragma pack(pop)
+#endif
+
+/* HPM.2 command assignments */
+#define HPM2_GET_LAN_ATTACH_CAPABILITIES 0x3E
+
+extern int hpm2_get_capabilities(struct ipmi_intf * intf,
+ struct hpm2_lan_attach_capabilities * caps);
+extern int hpm2_get_lan_channel_capabilities(struct ipmi_intf * intf,
+ uint8_t hpm2_lan_params_start,
+ struct hpm2_lan_channel_capabilities * caps);
+extern int hpm2_detect_max_payload_size(struct ipmi_intf * intf);
diff --git a/include/ipmitool/ipmi_intf.h b/include/ipmitool/ipmi_intf.h
index 774c6b2..437a427 100644
--- a/include/ipmitool/ipmi_intf.h
+++ b/include/ipmitool/ipmi_intf.h
@@ -180,7 +180,8 @@ struct ipmi_intf {
uint8_t target_channel;
uint32_t transit_addr;
uint8_t transit_channel;
- uint8_t channel_buf_size;
+ uint16_t max_request_data_size;
+ uint16_t max_response_data_size;
uint8_t devnum;
@@ -193,6 +194,8 @@ struct ipmi_intf {
struct ipmi_rs *(*send_sol)(struct ipmi_intf * intf, struct ipmi_v2_payload * payload);
int (*keepalive)(struct ipmi_intf * intf);
int (*set_my_addr)(struct ipmi_intf * intf, uint8_t addr);
+ void (*set_max_request_data_size)(struct ipmi_intf * intf, uint16_t size);
+ void (*set_max_response_data_size)(struct ipmi_intf * intf, uint16_t size);
};
struct ipmi_intf * ipmi_intf_load(char * name);
diff --git a/lib/Makefile.am b/lib/Makefile.am
index 3422521..d878b11 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -39,7 +39,7 @@ libipmitool_la_SOURCES = helper.c ipmi_sdr.c ipmi_sel.c ipmi_sol.c ipmi_pef.c \
ipmi_oem.c ipmi_isol.c ipmi_sunoem.c ipmi_fwum.c ipmi_picmg.c \
ipmi_main.c ipmi_tsol.c ipmi_firewall.c ipmi_kontronoem.c \
ipmi_hpmfwupg.c ipmi_sdradd.c ipmi_ekanalyzer.c ipmi_gendev.c \
- ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c \
+ ipmi_ime.c ipmi_delloem.c ipmi_dcmi.c hpm2.c \
../src/plugins/lan/md5.c ../src/plugins/lan/md5.h
libipmitool_la_LDFLAGS = -export-dynamic
diff --git a/lib/hpm2.c b/lib/hpm2.c
new file mode 100644
index 0000000..6f75f03
--- /dev/null
+++ b/lib/hpm2.c
@@ -0,0 +1,288 @@
+/*
+ * Copyright (c) 2012 Pigeon Point Systems. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * Redistribution of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * Redistribution 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.
+ *
+ * Neither the name of Pigeon Point Systems nor the names of
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * This software is provided "AS IS," without a warranty of any kind.
+ * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
+ * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
+ * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
+ * PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
+ * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
+ * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
+ * PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
+ * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
+ * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
+ * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
+ * EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
+ */
+
+#include <ipmitool/hpm2.h>
+#include <ipmitool/ipmi_intf.h>
+#include <ipmitool/log.h>
+
+#if HAVE_PRAGMA_PACK
+# pragma pack(push, 1)
+#endif
+
+/* HPM.x Get Capabilities request */
+struct hpmx_cmd_get_capabilities_rq {
+ uint8_t picmg_id;
+ uint8_t hpmx_id;
+} ATTRIBUTE_PACKING;
+
+/* HPM.2 Get Capabilities response */
+struct hpm2_cmd_get_capabilities_rp {
+ uint8_t picmg_id;
+ struct hpm2_lan_attach_capabilities caps;
+} ATTRIBUTE_PACKING;
+
+#if HAVE_PRAGMA_PACK
+# pragma pack(pop)
+#endif
+
+/* IPMI Get LAN Configuration Parameters command */
+#define IPMI_LAN_GET_CONFIG 0x02
+
+int hpm2_get_capabilities(struct ipmi_intf * intf,
+ struct hpm2_lan_attach_capabilities * caps)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ struct hpmx_cmd_get_capabilities_rq rq;
+
+ /* reset result */
+ memset(caps, 0, sizeof(struct hpm2_lan_attach_capabilities));
+
+ /* prepare request */
+ rq.picmg_id = 0;
+ rq.hpmx_id = 2;
+
+ /* prepare request */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_PICMG;
+ req.msg.cmd = HPM2_GET_LAN_ATTACH_CAPABILITIES;
+ req.msg.data = (uint8_t *)&rq;
+ req.msg.data_len = sizeof(rq);
+
+
+ /* send */
+ rsp = intf->sendrecv(intf, &req);
+
+ if (!rsp) {
+ lprintf(LOG_NOTICE, "Error sending request.");
+ return -1;
+ }
+
+ if (rsp->ccode == 0xC1) {
+ lprintf(LOG_DEBUG, "IPM Controller is not HPM.2 compatible");
+ return rsp->ccode;
+ } else if (rsp->ccode) {
+ lprintf(LOG_NOTICE, "Get HPM.x Capabilities request failed,"
+ " compcode = %x", rsp->ccode);
+ return rsp->ccode;
+ }
+
+ /* check response length */
+ if (rsp->data_len < 2 || rsp->data_len > 10) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check HPM.x identifier */
+ if (rsp->data[1] != 2) {
+ lprintf(LOG_NOTICE, "Bad HPM.x ID, id=%d", rsp->data[1]);
+ return rsp->ccode;
+ }
+
+ /*
+ * this hardly can happen, since completion code is already checked.
+ * but check for safety
+ */
+ if (rsp->data_len < 4) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* copy HPM.2 capabilities */
+ memcpy(caps, rsp->data + 2, rsp->data_len - 2);
+
+#if WORDS_BIGENDIAN
+ /* swap bytes to convert from little-endian format */
+ caps->lan_channel_mask = BSWAP_16(caps->lan_channel_mask);
+#endif
+
+ /* check HPM.2 revision */
+ if (caps->hpm2_revision_id != HPM2_REVISION) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 revision, rev=%d",
+ caps->hpm2_revision_id);
+ return -1;
+ }
+
+ if (!caps->lan_channel_mask) {
+ return -1;
+ }
+
+ /* check response length */
+ if (rsp->data_len < 8) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check HPM.2 LAN parameters start */
+ if (caps->hpm2_lan_params_start < 0xC0) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 LAN params start, start=%x",
+ caps->hpm2_lan_params_start);
+ return -1;
+ }
+
+ /* check HPM.2 LAN parameters revision */
+ if (caps->hpm2_lan_params_rev != HPM2_LAN_PARAMS_REV) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 LAN params revision, rev=%d",
+ caps->hpm2_lan_params_rev);
+ return -1;
+ }
+
+ /* check for HPM.2 SOL extension */
+ if (!(caps->hpm2_caps & HPM2_CAPS_SOL_EXTENSION)) {
+ /* no further checks */
+ return 0;
+ }
+
+ /* check response length */
+ if (rsp->data_len < 10) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check HPM.2 SOL parameters start */
+ if (caps->hpm2_sol_params_start < 0xC0) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 SOL params start, start=%x",
+ caps->hpm2_sol_params_start);
+ return -1;
+ }
+
+ /* check HPM.2 SOL parameters revision */
+ if (caps->hpm2_sol_params_rev != HPM2_SOL_PARAMS_REV) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 SOL params revision, rev=%d",
+ caps->hpm2_sol_params_rev);
+ return -1;
+ }
+
+ return 0;
+}
+
+int hpm2_get_lan_channel_capabilities(struct ipmi_intf * intf,
+ uint8_t hpm2_lan_params_start,
+ struct hpm2_lan_channel_capabilities * caps)
+{
+ struct ipmi_rq req;
+ struct ipmi_rs * rsp;
+ uint8_t rq[4];
+
+ /* reset result */
+ memset(caps, 0, sizeof(struct hpm2_lan_channel_capabilities));
+
+ /* prepare request */
+ memset(&req, 0, sizeof(req));
+ req.msg.netfn = IPMI_NETFN_TRANSPORT;
+ req.msg.cmd = IPMI_LAN_GET_CONFIG;
+ req.msg.data = (uint8_t *)&rq;
+ req.msg.data_len = sizeof(rq);
+
+ /* prepare request data */
+ rq[0] = 0xE; /* sending channel */
+ rq[1] = hpm2_lan_params_start; /* HPM.2 Channel Caps */
+ rq[2] = rq[3] = 0;
+
+ /* send */
+ rsp = intf->sendrecv(intf, &req);
+
+ if (rsp) {
+ lprintf(LOG_NOTICE, "Error sending request");
+ return -1;
+ }
+
+ if (rsp->ccode == 0x80) {
+ lprintf(LOG_DEBUG, "HPM.2 Channel Caps parameter is not supported");
+ return rsp->ccode;
+ } else if (rsp->ccode) {
+ lprintf(LOG_NOTICE, "Get LAN Configuration Parameters request failed,"
+ " compcode = %x", rsp->ccode);
+ return rsp->ccode;
+ }
+
+ /* check response length */
+ if (rsp->data_len != sizeof (struct hpm2_lan_channel_capabilities) + 1) {
+ lprintf(LOG_NOTICE, "Bad response length, len=%d", rsp->data_len);
+ return -1;
+ }
+
+ /* check parameter revision */
+ if (rsp->data[0] != HPM2_LAN_PARAMS_REV) {
+ lprintf(LOG_NOTICE, "Bad HPM.2 LAN parameter revision, rev=%d",
+ rsp->data[0]);
+ return -1;
+ }
+
+ /* copy parameter data */
+ memcpy(caps, &rsp->data[1], sizeof (struct hpm2_lan_channel_capabilities));
+
+#if WORDS_BIGENDIAN
+ /* swap bytes to convert from little-endian format */
+ caps->max_inbound_pld_size = BSWAP_16(caps->max_inbound_pld_size);
+ caps->max_outbound_pld_size = BSWAP_16(caps->max_outbound_pld_size);
+#endif
+
+ return 0;
+}
+
+int hpm2_detect_max_payload_size(struct ipmi_intf * intf)
+{
+ struct hpm2_lan_attach_capabilities attach_caps;
+ struct hpm2_lan_channel_capabilities channel_caps;
+ int err;
+
+ /* query HPM.2 support */
+ err = hpm2_get_capabilities(intf, &attach_caps);
+
+ /* check if HPM.2 is supported */
+ if (err != 0 || !attach_caps.lan_channel_mask) {
+ return err;
+ }
+
+ /* query channel capabilities */
+ err = hpm2_get_lan_channel_capabilities(intf,
+ attach_caps.hpm2_lan_params_start, &channel_caps);
+
+ /* check if succeeded */
+ if (err != 0) {
+ return err;
+ }
+
+ /* update request and response sizes */
+ ipmi_intf_set_max_request_data_size(intf,
+ channel_caps.max_inbound_pld_size - 7);
+ ipmi_intf_set_max_response_data_size(intf,
+ channel_caps.max_outbound_pld_size - 8);
+
+ /* print debug info */
+ lprintf(LOG_DEBUG, "Set maximum request size to %d\n"
+ "Set maximum response size to %d",
+ intf->max_request_data_size, intf->max_response_data_size);
+
+ return 0;
+}
diff --git a/lib/ipmi_fru.c b/lib/ipmi_fru.c
index 09d5abe..6aeead0 100644
--- a/lib/ipmi_fru.c
+++ b/lib/ipmi_fru.c
@@ -454,12 +454,25 @@ write_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
/* initialize request size only once */
if (fru->max_write_size == 0) {
- if (intf->channel_buf_size != 0) {
- /* subtract 1 byte for FRU ID an 2 bytes for offset */
- fru->max_write_size = intf->channel_buf_size - 3;
+ uint16_t max_rq_size = ipmi_intf_get_max_request_data_size(intf);
+
+ /* validate lower bound of the maximum request data size */
+ if (max_rq_size <= 3) {
+ lprintf(LOG_ERROR, "Maximum request size is too small to send "
+ "a write request");
+ return -1;
+ }
+
+ /*
+ * Write FRU Info command returns the number of written bytes in
+ * a single byte field.
+ */
+ if (max_rq_size - 3 > 255) {
+ /* Limit the max write size with 255 bytes. */
+ fru->max_write_size = 255;
} else {
/* subtract 1 byte for FRU ID an 2 bytes for offset */
- fru->max_write_size = 32 - 3;
+ fru->max_write_size = max_rq_size - 3;
}
/* check word access */
@@ -611,8 +624,25 @@ read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, uint8_t id,
req.msg.data_len = 4;
if (fru->max_read_size == 0) {
- /* subtract 1 byte for completion code and 1 for byte count */
- fru->max_read_size = 32 - 2;
+ uint16_t max_rs_size = ipmi_intf_get_max_response_data_size(intf) - 1;
+
+ /* validate lower bound of the maximum response data size */
+ if (max_rs_size <= 1) {
+ lprintf(LOG_ERROR, "Maximum response size is too small to send "
+ "a read request");
+ return -1;
+ }
+
+ /*
+ * Read FRU Info command may read up to 255 bytes of data.
+ */
+ if (max_rs_size - 1 > 255) {
+ /* Limit the max read size with 255 bytes. */
+ fru->max_read_size = 255;
+ } else {
+ /* subtract 1 byte for bytes count */
+ fru->max_write_size = max_rs_size - 1;
+ }
/* check word access */
if (fru->access) {
diff --git a/lib/ipmi_hpmfwupg.c b/lib/ipmi_hpmfwupg.c
index 0a56857..69950b7 100644
--- a/lib/ipmi_hpmfwupg.c
+++ b/lib/ipmi_hpmfwupg.c
@@ -1073,38 +1073,6 @@ HpmfwupgUpgradeStage(struct ipmi_intf *intf,
}
int
-get_max_rq_data_size(struct ipmi_intf *intf)
-{
- int bufLength;
- /* Check if we receive size in parameters */
- if(intf->channel_buf_size != 0) {
- /* Plan for overhead */
- if (intf->target_addr == intf->my_addr) {
- bufLength = intf->channel_buf_size - 9;
- } else {
- bufLength = intf->channel_buf_size - 11;
- }
- } else if (strstr(intf->name,"lan") != NULL) {
- /* Find max buffer length according the connection
- * parameters
- */
- bufLength = HPMFWUPG_SEND_DATA_COUNT_LAN - 2;
- if (intf->transit_addr != intf->my_addr
- && intf->transit_addr != 0) {
- bufLength -= 8;
- }
- } else if (strstr(intf->name,"open") != NULL
- && intf->target_addr == intf->my_addr) {
- bufLength = HPMFWUPG_SEND_DATA_COUNT_KCS - 2;
- } else if (intf->target_channel == 7) {
- bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMBL;
- } else {
- bufLength = HPMFWUPG_SEND_DATA_COUNT_IPMB;
- }
- return bufLength;
-}
-
-int
HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
struct HpmfwupgUpgradeCtx *pFwupgCtx,
unsigned char **pImagePtr,
@@ -1138,6 +1106,8 @@ HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
unsigned char mode = 0;
unsigned char componentId = 0x00;
unsigned char componentIdByte = 0x00;
+ uint16_t max_rq_size;
+
/* Save component ID on which the upload is done */
componentIdByte = components.ComponentBits.byte;
while ((componentIdByte>>= 1) != 0) {
@@ -1150,8 +1120,19 @@ HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
pDataInitial = ((unsigned char *)pFwImage
+ sizeof(struct HpmfwupgFirmwareImage));
pData = pDataInitial;
+
/* Find max buffer length according the connection parameters */
- bufLength = get_max_rq_data_size(intf);
+ max_rq_size = ipmi_intf_get_max_request_data_size(intf);
+
+ /* validate lower bound of max request size */
+ if (max_rq_size <= sizeof(struct HpmfwupgUploadFirmwareBlockReq)) {
+ lprintf(LOG_ERROR, "Maximum request size is too small to "
+ "send a upload request.");
+ return HPMFWUPG_ERROR;
+ }
+
+ bufLength = max_rq_size - sizeof(struct HpmfwupgUploadFirmwareBlockReq);
+
/* Get firmware length */
firmwareLength = pFwImage->length[0];
firmwareLength|= (pFwImage->length[1] << 8) & 0xff00;
@@ -1178,8 +1159,7 @@ HpmFwupgActionUploadFirmware(struct HpmfwupgComponentBitMask components,
if (!skip) {
HpmDisplayUpgrade(0,0,1,0);
/* Initialize parameters */
- uploadCmd.req = malloc(get_max_rq_data_size(intf)
- + sizeof(struct HpmfwupgUploadFirmwareBlockReq));
+ uploadCmd.req = malloc(max_rq_size);
if (!uploadCmd.req) {
lprintf(LOG_ERR, "ipmitool: malloc failure");
return HPMFWUPG_ERROR;
diff --git a/lib/ipmi_main.c b/lib/ipmi_main.c
index 1885bb5..14ca183 100644
--- a/lib/ipmi_main.c
+++ b/lib/ipmi_main.c
@@ -982,13 +982,15 @@ ipmi_main(int argc, char ** argv,
}
/* Enable Big Buffer when requested */
- ipmi_main_intf->channel_buf_size = 0;
if ( my_long_packet_size != 0 ) {
- printf("Setting large buffer to %i\n", my_long_packet_size);
- if (ipmi_kontronoem_set_large_buffer( ipmi_main_intf, my_long_packet_size ) == 0)
- {
+ /* Enable Big Buffer when requested */
+ if (!ipmi_oem_active(ipmi_main_intf, "kontron") ||
+ ipmi_kontronoem_set_large_buffer(ipmi_main_intf,
+ my_long_packet_size ) == 0) {
+ printf("Setting large buffer to %i\n", my_long_packet_size);
my_long_packet_set = 1;
- ipmi_main_intf->channel_buf_size = my_long_packet_size;
+ ipmi_intf_set_max_request_data_size(ipmi_main_intf,
+ my_long_packet_size);
}
}
@@ -1002,8 +1004,10 @@ ipmi_main(int argc, char ** argv,
rc = ipmi_cmd_run(ipmi_main_intf, NULL, 0, NULL);
if (my_long_packet_set == 1) {
- /* Restore defaults */
- ipmi_kontronoem_set_large_buffer( ipmi_main_intf, 0 );
+ if (ipmi_oem_active(ipmi_main_intf, "kontron")) {
+ /* Restore defaults */
+ ipmi_kontronoem_set_large_buffer( ipmi_main_intf, 0 );
+ }
}
/* clean repository caches */
diff --git a/lib/ipmi_oem.c b/lib/ipmi_oem.c
index f0fd598..89495c0 100644
--- a/lib/ipmi_oem.c
+++ b/lib/ipmi_oem.c
@@ -67,6 +67,10 @@ static struct ipmi_oem_handle ipmi_oem_list[] = {
name: "i82571spt",
desc: "Intel 82571 MAC with integrated RMCP+ support in super pass-through mode",
},
+ {
+ name: "kontron",
+ desc: "Kontron OEM big buffer support"
+ },
{ 0 }
};
diff --git a/lib/ipmi_sdr.c b/lib/ipmi_sdr.c
index d44bbbb..fa7b082 100644
--- a/lib/ipmi_sdr.c
+++ b/lib/ipmi_sdr.c
@@ -59,7 +59,7 @@
extern int verbose;
static int use_built_in; /* Uses DeviceSDRs instead of SDRR */
-static int sdr_max_read_len = GET_SDR_ENTIRE_RECORD;
+static int sdr_max_read_len = 0;
static int sdr_extended = 0;
static long sdriana = 0;
@@ -3024,6 +3024,17 @@ ipmi_sdr_get_record(struct ipmi_intf * intf, struct sdr_get_rs * header,
req.msg.data = (uint8_t *) & sdr_rq;
req.msg.data_len = sizeof (sdr_rq);
+ /* check if max length is null */
+ if ( sdr_max_read_len == 0 ) {
+ /* get maximum response size */
+ sdr_max_read_len = ipmi_intf_get_max_response_data_size(intf) - 2;
+
+ /* cap the number of bytes to read */
+ if (sdr_max_read_len > 0xFE) {
+ sdr_max_read_len = 0xFE;
+ }
+ }
+
/* read SDR record with partial reads
* because a full read usually exceeds the maximum
* transport buffer size. (completion code 0xca)
diff --git a/src/plugins/ipmi_intf.c b/src/plugins/ipmi_intf.c
index 48e2b61..0fa76be 100644
--- a/src/plugins/ipmi_intf.c
+++ b/src/plugins/ipmi_intf.c
@@ -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;
+ }
+}
diff --git a/src/plugins/lan/lan.c b/src/plugins/lan/lan.c
index fc90000..fb1a633 100644
--- a/src/plugins/lan/lan.c
+++ b/src/plugins/lan/lan.c
@@ -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;
+}
diff --git a/src/plugins/lanplus/lanplus.c b/src/plugins/lanplus/lanplus.c
index 7b3c6be..9cf3c5e 100644
--- a/src/plugins/lanplus/lanplus.c
+++ b/src/plugins/lanplus/lanplus.c
@@ -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;
+}
diff --git a/src/plugins/open/open.c b/src/plugins/open/open.c
index fe1fd75..92b6f37 100644
--- a/src/plugins/open/open.c
+++ b/src/plugins/open/open.c
@@ -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,
diff --git a/src/plugins/serial/serial_basic.c b/src/plugins/serial/serial_basic.c
index 23c98b7..5f4b926 100644
--- a/src/plugins/serial/serial_basic.c
+++ b/src/plugins/serial/serial_basic.c
@@ -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;
}
diff --git a/src/plugins/serial/serial_terminal.c b/src/plugins/serial/serial_terminal.c
index c82073e..41d3753 100644
--- a/src/plugins/serial/serial_terminal.c
+++ b/src/plugins/serial/serial_terminal.c
@@ -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;
}