Zdenek,

Here is the updated patch.

Regards,
Dmitry

31.03.2014 13:37, Dmitry Bazhenov пишет:
Zdenek,

Okay then. I'll provide the updated patch later today.

Regards,
Dmitry

31.03.2014 13:34, Zdenek Styblik пишет:
On Mon, Mar 31, 2014 at 9:14 AM, Dmitry Bazhenov <dim...@pigeonpoint.com> wrote:
Hello, Zdenek,

I think there should be no such checks inside these callbacks.
However, I guess there should be a check inside thr
ipmi_intf_set_max_request/response_data_size
functions which guarantee that the minimum value will be not less than 25
bytes (required by IPMI spec).

Could you please add such check or is it better for me to provide a new
patch revision?

Regards,
Dmitry

Dmitry,

I don't have access to any IPMI capable hardware, so I'm afraid it's
either up to you or somebody else. I'm sorry.

Best regards,
Z.

31.03.2014 13:07, Zdenek Styblik пишет:

On Thu, Mar 20, 2014 at 6:54 AM, Zdenek Styblik
<zdenek.styb...@gmail.com> wrote:
On Wed, Mar 19, 2014 at 8:33 AM, Dmitry Bazhenov <dim...@pigeonpoint.com>
wrote:
[...]
I got a bit "scared" by solution applied to
ipmi_intf_get_max_request_data_size() and
ipmi_intf_get_max_response_data_size(). But then I've tried to compile just this one function with all kinds of switches and compiler didn't
comply, so I guess it's ok.
I wonder, shouldn't be the same logic applied to
ipmi_lanp_set_max_rq_data_size() and ipmi_lanp_set_max_rp_data_size()
as well?
[DB] Calculations in the ipmi_intf_get_max_request_data_size() are
required
for the case if the target IPMC device is accessed via IPMI bridging.
Since
we can not deduce the target channel maximum message size, we use the minimum required size. These calculations are not needed for direct IPMC
device access.
[DB] Set max size functions are required if maximum message size over
the
chosen interface must be somehow modified from the value received from
the
interface properties. This is the case for the encrypted RMCP+ payload
where
maximum message size must be reduced by the confidentiality
header/trailer
sizes. Other interface types do not even implement these callbacks.

What I meant is whether under/over-flow shouldn't be checked in those
functions as well.

Ping?

Z.



diff --git a/include/ipmitool/hpm2.h b/include/ipmitool/hpm2.h
new file mode 100755
index 0000000..b222734
--- /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
old mode 100644
new mode 100755
index 774c6b2..ca8d21c
--- 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
old mode 100644
new mode 100755
index 3422521..d878b11
--- 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 100755
index 0000000..1d05936
--- /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\n");
+		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\n", 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\n", rsp->data_len);
+		return -1;
+	}
+
+	/* check HPM.x identifier */
+	if (rsp->data[1] != 2) {
+		lprintf(LOG_NOTICE,"Bad HPM.x ID, id=%d\n", 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\n", 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\n",
+				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\n", 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\n",
+				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\n",
+				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\n", 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\n",
+				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\n",
+				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\n");
+		return -1;
+	}
+
+	if (rsp->ccode == 0x80) {
+		lprintf(LOG_DEBUG,"HPM.2 Channel Caps parameter is not supported\n");
+		return rsp->ccode;
+	} else if (rsp->ccode) {
+		lprintf(LOG_NOTICE,"Get LAN Configuration Parameters request failed,"
+				" compcode = %x\n", 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\n", 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\n",
+				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\n",
+			intf->max_request_data_size, intf->max_response_data_size);
+
+	return 0;
+}
diff --git a/lib/ipmi_fru.c b/lib/ipmi_fru.c
old mode 100644
new mode 100755
index 09d5abe..e9867b0
--- 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
old mode 100644
new mode 100755
index 0a56857..2f89793
--- 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
old mode 100644
new mode 100755
index 1885bb5..f139adc
--- 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
old mode 100644
new mode 100755
index f0fd598..f1be611
--- 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
old mode 100644
new mode 100755
index d44bbbb..f2e92cb
--- 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
old mode 100644
new mode 100755
index 48e2b61..93eb5b7
--- 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
old mode 100644
new mode 100755
index fc90000..3eecc29
--- 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
old mode 100644
new mode 100755
index 7b3c6be..e14bc36
--- 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
old mode 100644
new mode 100755
index 0fd8c9e..5d0b9aa
--- 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
old mode 100644
new mode 100755
index 23c98b7..5f4b926
--- 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
old mode 100644
new mode 100755
index c82073e..41d3753
--- 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;
 }
 
------------------------------------------------------------------------------
_______________________________________________
Ipmitool-devel mailing list
Ipmitool-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/ipmitool-devel

Reply via email to