diff -urN ipmitool-1.5.9-orig/include/ipmitool/ipmi_fru.h ipmitool-1.5.9/include/ipmitool/ipmi_fru.h
--- ipmitool-1.5.9-orig/include/ipmitool/ipmi_fru.h	2004-03-03 15:22:32.000000000 -0600
+++ ipmitool-1.5.9/include/ipmitool/ipmi_fru.h	2004-08-06 07:37:30.000000000 -0500
@@ -83,16 +83,16 @@
 
 struct fru_area_chassis {
 	unsigned char area_ver;
-	unsigned char area_len;
 	unsigned char type;
+	unsigned short area_len;
 	char * part;
 	char * serial;
 };
 
 struct fru_area_board {
 	unsigned char area_ver;
-	unsigned char area_len;
 	unsigned char lang;
+	unsigned short area_len;
 	uint32_t mfg_date_time;
 	char * mfg;
 	char * prod;
@@ -103,8 +103,8 @@
 
 struct fru_area_product {
 	unsigned char area_ver;
-	unsigned char area_len;
 	unsigned char lang;
+	unsigned short area_len;
 	char * mfg;
 	char * name;
 	char * part;
diff -urN ipmitool-1.5.9-orig/include/ipmitool/ipmi.h ipmitool-1.5.9/include/ipmitool/ipmi.h
--- ipmitool-1.5.9-orig/include/ipmitool/ipmi.h	2004-03-03 15:22:32.000000000 -0600
+++ ipmitool-1.5.9/include/ipmitool/ipmi.h	2004-08-04 13:03:42.000000000 -0500
@@ -109,6 +109,7 @@
 	int (*open)(struct ipmi_intf *, char *, int, char *, char *);
 	void (*close)(struct ipmi_intf *);
 	struct ipmi_rs *(*sendrecv)(struct ipmi_intf *, struct ipmi_rq *);
+	unsigned char target_addr;
 };
 
 #define IPMI_NETFN_CHASSIS		0x0
diff -urN ipmitool-1.5.9-orig/ipmitool.spec ipmitool-1.5.9/ipmitool.spec
--- ipmitool-1.5.9-orig/ipmitool.spec	2004-04-02 11:39:26.000000000 -0600
+++ ipmitool-1.5.9/ipmitool.spec	1969-12-31 18:00:00.000000000 -0600
@@ -1,152 +0,0 @@
-Name:         ipmitool
-Summary:      ipmitool - Utility for interfacing with IPMI devices
-Version:      1.5.9
-Release:      1
-Copyright:    BSD
-Group:        Utilities
-Vendor:       Sun Microsystems
-Packager:     Duncan Laurie <duncan@sun.com>
-Source:       ipmitool-1.5.9.tar.gz
-Buildroot:    /var/tmp/ipmitool-root
-
-%package dev
-Summary: Development files for ipmitool
-Group: Utilities
-
-%description
-This package contains a utility for interfacing with IPMI-enabled devices
-through either the OpenIPMI kernel driver or with IPMI-over-LAN protocol.
-It provides some basic functions for reading the SDR and displaying sensor
-values, displaying the contents of the SEL, printing FRU information,
-reading and setting LAN configuration, and chassis power control.
-
-%description dev
-Additional development files for creating applications or interface plugins
-for ipmitool.
-
-%prep
-if [ "$RPM_BUILD_ROOT" ] && [ "$RPM_BUILD_ROOT" != "/" ]; then
-    rm -rf $RPM_BUILD_ROOT
-fi
-
-%setup
-
-%build
-./configure \
-	--enable-ipmievd \
-	--enable-intf-lan=static \
-	--enable-intf-open=static \
-	--with-kerneldir=/usr/src/linux-2.4 \
-	--prefix=%{_prefix} \
-	--bindir=%{_bindir} \
-	--datadir=%{_datadir} \
-	--includedir=%{_includedir} \
-	--libdir=%{_libdir} \
-	--mandir=%{_mandir} \
-	--sysconfdir=%{_sysconfdir}
-make
-
-%install
-make DESTDIR=$RPM_BUILD_ROOT install-strip
-
-DOCDIR=$RPM_BUILD_ROOT%{_datadir}/doc/ipmitool-1.5.9
-mkdir -p $DOCDIR
-for DOC in COPYING AUTHORS ChangeLog ; do
-    install -m 644 -o root -g root $DOC $DOCDIR/$DOC
-done
-
-%clean
-if [ "$RPM_BUILD_ROOT" ] && [ "$RPM_BUILD_ROOT" != "/" ]; then
-    rm -rf $RPM_BUILD_ROOT
-fi
-rm -rf $RPM_BUILD_DIR/ipmitool-1.5.9
-
-%files
-%defattr(-,root,root)
-%doc %{_mandir}/man1/*
-%{_bindir}/*
-%{_datadir}/doc/ipmitool-1.5.9/*
-
-%files dev
-%defattr(-,root,root)
-%dir %{_includedir}/ipmitool
-%{_includedir}/ipmitool/*.h
-
-%changelog
-* Sat May 27 2004 <duncan@sun.com>  1.5.9-1
- - Add ability to get a particular sensor by name
- - Add ability to set a particular sensor threshold
- - Add support for displaying V2 channel authentication levels
- - Add README for rrdtool scripts in contrib directory
- - Improve lan interface retry handling
- - Support prompting for password or reading from environment
- - Move chaninfo command into channel subcommand
- - Fix reservation ID handling when two sessions open to BMC
- - Fix reading of large FRU data
- - Add configure option for changing binary to ipmiadm for Solaris
- - Fix compile problem on Solaris 8
-
-* Tue Jan 27 2004 <duncan@sun.com>  1.5.8-1
- - Enable static compilation of interfaces
- - Fix types to be 64-bit safe
- - Fix compilation problems on Solaris
- - Fix multiple big-endian problems for Solaris/SPARC
- - Fix channel access to save settings to NVRAM
- - Set channel privilege limit to ADMIN during "access on"
- - Enable gratuitous ARP in bmcautoconf.sh
- - Add support for Linux kernel panic messages in SEL output
- - Add support for type 3 SDR records
-
-* Mon Jan  5 2004 <duncan@sun.com>  1.5.7-1
- - add IPMIv1.5 eratta fixes
- - additions to FRU printing and FRU multirecords
- - better handling of SDR printing
- - contrib scripts for creating rrdtool graphs
-
-* Thu Dec  4 2003 <duncan@sun.com>  1.5.6-1
- - Fix SEL event decoding for generic events
- - Handle empty SEL gracefully when doing "sel list"
- - Fix sdr handling of sensors that do not return a reading
- - Fix for CSV display of sensor readings/units from Fredrik Öhrn
-
-* Tue Nov 25 2003 <duncan@sun.com>  1.5.5-1
- - Add -U option for setting LAN username
- - Fix -v usage for plugin interfaces
-
-* Fri Nov 14 2003 <duncan@sun.com>  1.5.4-1
- - pull interface plugin api into library
- - fix ipmievd
-
-* Fri Oct 31 2003 <duncan@sun.com>  1.5.3-1
- - add -g optin for pedantic ipmi-over-lan communication
-
-* Fri Oct 24 2003 <duncan@sun.com>  1.5.2-1
- - add gratuitous arp interval setting
-
-* Wed Oct  8 2003 <duncan@sun.com>  1.5.1-1
- - better SEL support
- - fix display bug in SDR list
-
-* Fri Sep  5 2003 <duncan@sun.com>  1.5.0-1
- - use automake/autoconf/libtool
- - dynamic loading interface plugins
-
-* Wed May 28 2003 <duncan@sun.com>  1.4.0-1
- - make UDP packet handling more robust
- - fix imb driver support
-
-* Thu May 22 2003 <duncan@sun.com>  1.3-1
- - update manpage
- - rework of low-level network handling
- - add basic imb driver support
-
-* Wed Apr  2 2003 <duncan@sun.com>  1.2-1
- - change command line option parsing
- - support for more chassis commands
-
-* Tue Apr  1 2003 <duncan@sun.com>  1.1-1
- - minor fixes.
-
-* Sun Mar 30 2003 <duncan@sun.com>  1.0-1
- - Initial release.
-
diff -urN ipmitool-1.5.9-orig/lib/ipmi_fru.c ipmitool-1.5.9/lib/ipmi_fru.c
--- ipmitool-1.5.9-orig/lib/ipmi_fru.c	2004-01-31 21:17:29.000000000 -0600
+++ ipmitool-1.5.9/lib/ipmi_fru.c	2004-08-06 12:44:07.000000000 -0500
@@ -50,33 +50,141 @@
 
 static char * get_fru_area_str(unsigned char * data, int * offset)
 {
+	static const char bcd_plus[] = "0123456789 -.:,_";
 	char * str;
-	int len;
+	int len, size, i, j, k;
 	int off = *offset;
+	union {
+		uint32_t bits;
+		char chars[4];
+	} u;
 
+	k = ((data[off] & 0xC0) >> 6);		/* bits 6,7 contain format */
 	len = data[off++];
-	len &= 0x3f;		/* bits 0:5 contain length */
+	len &= 0x3f;								/* bits 0:5 contain length */
 
-	str = malloc(len+1);
+	switch(k) {
+		case 0:									/* 0: binary/unspecified */
+			size = (len*2);					/*   (hex dump -> 2x length) */
+			break;
+		case 2:									/* 2: 6-bit ASCII */
+			size = ((((len+2)*4)/3) & ~3);/*   (4 chars per group of 1-3 bytes) */
+			break;
+		case 3:									/* 3: 8-bit ASCII */
+		case 1:									/* 1: BCD plus */
+			size = len;							/*   (no length adjustment) */
+	}
+
+	str = malloc(size+1);
 	if (!str)
 		return NULL;
-	str[len] = '\0';
 
-	memcpy(str, &data[off], len);
+	if (len == 0)
+		str[0] = '\0';
+	else {
+		switch(k) {
+			case 0:
+				strcpy(str, buf2str(&data[off], len));
+				break;
+
+			case 1:
+				for (k=0; k<len; k++)
+					str[k] = bcd_plus[(data[off+k] & 0x0f)];
+				str[k] = '\0';
+				break;
+
+			case 2:
+				for (i=j=0; i<len; i+=3) {
+					u.bits = 0;
+					k = ((len-i) < 3 ? (len-i) : 3);
+#if WORDS_BIGENDIAN
+					u.chars[3] = data[off+i];
+					u.chars[2] = (k > 1 ? data[off+i+1] : 0);
+					u.chars[1] = (k > 2 ? data[off+i+2] : 0);
+#define CHAR_IDX 3
+#else
+					memcpy((void *)&u.bits, &data[off+i], k);
+#define CHAR_IDX 0
+#endif
+					for (k=0; k<4; k++) {
+						str[j++] = ((u.chars[CHAR_IDX] & 0x3f) + 0x20);
+						u.bits >>= 6;
+					}
+				}
+				str[j] = '\0';
+				break;
+
+			case 3:
+				memcpy(str, &data[off], len);
+				str[len] = '\0';
+		}
+		off += len;
+	}
 
-	off += len;
 	*offset = off;
 
 	return str;
 }
 
+static int
+read_fru_area(struct ipmi_intf * intf, struct fru_info *fru, unsigned char id,
+					unsigned int offset, unsigned int length, unsigned char *frubuf)
+{	/*
+	// fill in frubuf[offset:length] from the FRU[offset:length]
+	// rc=1 on success
+	*/
+	static unsigned int fru_data_rqst_size = 32;
+	unsigned int off = offset, tmp, finish;
+	struct ipmi_rs * rsp;
+	struct ipmi_rq req;
+	unsigned char msg_data[4];
+
+	finish = offset + length;
+	if (finish > fru->size)
+		return -1;
+
+	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;
+
+	if (fru->access && fru_data_rqst_size > 16)
+		fru_data_rqst_size = 16;
+	do {
+		tmp = fru->access ? off >> 1 : off;
+		msg_data[0] = id;
+		msg_data[1] = (unsigned char)tmp;
+		msg_data[2] = (unsigned char)(tmp >> 8);
+		tmp = finish - off;
+		if (tmp > fru_data_rqst_size)
+			msg_data[3] = (unsigned char)fru_data_rqst_size;
+		else
+			msg_data[3] = (unsigned char)tmp;
+
+		rsp = intf->sendrecv(intf, &req);
+		if (!rsp)
+			break;
+		if ((rsp->ccode==0xc7 || rsp->ccode==0xc8) && --fru_data_rqst_size > 8)
+			continue;
+		if (rsp->ccode)
+			break;
+
+		tmp = fru->access ? rsp->data[0] << 1 : rsp->data[0];
+		memcpy((frubuf + off), rsp->data + 1, tmp);
+		off += tmp;
+	} while (off < finish);
+
+	return (off >= finish);
+}
+
 static void ipmi_fru_print(struct ipmi_intf * intf, unsigned char id)
 {
 	struct ipmi_rs * rsp;
 	struct ipmi_rq req;
 	unsigned char * fru_data;
 	unsigned char msg_data[4];
-	int i, len, offset;
+	int i, len;
 
 	struct fru_area_chassis chassis;
 	struct fru_area_board board;
@@ -84,6 +192,15 @@
 
 	struct fru_info fru;
 	struct fru_header header;
+	enum {
+		OFF_INTERNAL
+	,	OFF_CHASSIS
+	,	OFF_BOARD
+	,	OFF_PRODUCT
+	,	OFF_MULTI
+	,	OFF_COUNT	/* must be last */
+	};
+	unsigned int area_offsets[OFF_COUNT];
 
 	msg_data[0] = id;
 
@@ -94,8 +211,15 @@
 	req.msg.data_len = 1;
 
 	rsp = intf->sendrecv(intf, &req);
-	if (!rsp || rsp->ccode)
+	if (!rsp)
 		return;
+
+	if(rsp->ccode)
+	{
+		if (rsp->ccode == 0xc3)
+			printf ("  Timeout accessing FRU info. (Device not present?)\n");
+		return;
+	}
 	fru.size = (rsp->data[1] << 8) | rsp->data[0];
 	fru.access = rsp->data[2] & 0x1;
 
@@ -139,154 +263,160 @@
 		return;
 	}
 
-	header.offset.internal *= 8;
-	header.offset.chassis *= 8;
-	header.offset.board *= 8;
-	header.offset.product *= 8;
-	header.offset.multi *= 8;
+	area_offsets[OFF_INTERNAL] = 8 * header.offset.internal;
+	area_offsets[OFF_CHASSIS] = 8 * header.offset.chassis;
+	area_offsets[OFF_BOARD] = 8 * header.offset.board;
+	area_offsets[OFF_PRODUCT] = 8 * header.offset.product;
+	area_offsets[OFF_MULTI] = 8 * header.offset.multi;
 
 	if (verbose > 1) {
 		printf("fru.header.version:         0x%x\n", header.version);
-		printf("fru.header.offset.internal: 0x%x\n", header.offset.internal);
-		printf("fru.header.offset.chassis:  0x%x\n", header.offset.chassis);
-		printf("fru.header.offset.board:    0x%x\n", header.offset.board);
-		printf("fru.header.offset.product:  0x%x\n", header.offset.product);
-		printf("fru.header.offset.multi:    0x%x\n", header.offset.multi);
+		printf("fru.header.offset.internal: 0x%x\n", area_offsets[OFF_INTERNAL]);
+		printf("fru.header.offset.chassis:  0x%x\n", area_offsets[OFF_CHASSIS]);
+		printf("fru.header.offset.board:    0x%x\n", area_offsets[OFF_BOARD]);
+		printf("fru.header.offset.product:  0x%x\n", area_offsets[OFF_PRODUCT]);
+		printf("fru.header.offset.multi:    0x%x\n", area_offsets[OFF_MULTI]);
 	}
 
 	fru_data = malloc(fru.size+1);
 	if (!fru_data)
 		return;
 	memset(fru_data, 0, fru.size+1);
-	offset = 0;
-	do {
-		msg_data[0] = id;
-		msg_data[1] = offset;
-		msg_data[2] = 0;
-		msg_data[3] = (fru.size - offset) > 32 ? 32 : (fru.size - offset);
 
-		rsp = intf->sendrecv(intf, &req);
-		if (!rsp || rsp->ccode)
-			break;
-
-		len = rsp->data[0];
-		memcpy(&fru_data[offset], rsp->data + 1, len);
-		offset += len;
-	} while (offset < fru.size);
+	/* rather than reading the entire part, only read the areas we'll format */
 
 	/* chassis area */
 
-	if (header.offset.chassis)
+	if (area_offsets[OFF_CHASSIS] >= sizeof(struct fru_header))
 	{
-		i = header.offset.chassis;
-		chassis.area_ver = fru_data[i++];
-		chassis.area_len = fru_data[i++] * 8;
-		chassis.type = fru_data[i++];
-		chassis.part = get_fru_area_str(fru_data, &i);
-		chassis.serial = get_fru_area_str(fru_data, &i);
-
-		printf("  Chassis Type     : %s\n", chassis_type_desc[chassis.type]);
-		printf("  Chassis Part     : %s\n", chassis.part);
-		printf("  Chassis Serial   : %s\n", chassis.serial);
-
-		while (fru_data[i] != 0xc1 && i < header.offset.chassis + chassis.area_len)
+		i = area_offsets[OFF_CHASSIS];
+		read_fru_area(intf, &fru, id, i, 2, fru_data);
+		chassis.area_len = 8 * fru_data[i+1];
+		if (chassis.area_len > 0
+		&& read_fru_area(intf, &fru, id, i, chassis.area_len, fru_data) > 0)
 		{
-			char *extra;
+			chassis.area_ver = fru_data[i++];
+			chassis.area_len = fru_data[i++] * 8;
+			chassis.type = fru_data[i++];
+			chassis.part = get_fru_area_str(fru_data, &i);
+			chassis.serial = get_fru_area_str(fru_data, &i);
+
+			printf("  Chassis Type     : %s\n", chassis_type_desc[chassis.type]);
+			printf("  Chassis Part     : %s\n", chassis.part);
+			printf("  Chassis Serial   : %s\n", chassis.serial);
 
-			extra = get_fru_area_str(fru_data, &i);
-			if (extra [0]) printf("  Chassis Extra    : %s\n", extra);
-			free(extra);
+			while (fru_data[i] != 0xc1 && i < area_offsets[OFF_CHASSIS] + chassis.area_len)
+			{
+				char *extra;
+
+				extra = get_fru_area_str(fru_data, &i);
+				if (extra [0]) printf("  Chassis Extra    : %s\n", extra);
+				free(extra);
+			}
+
+			free(chassis.part);
+			free(chassis.serial);
 		}
-		free(chassis.part);
-		free(chassis.serial);
 	}
 
 	/* board area */
 
-	if (header.offset.board)
+	if (area_offsets[OFF_BOARD] >= sizeof(struct fru_header))
 	{
-		i = header.offset.board;
-		board.area_ver = fru_data[i++];
-		board.area_len = fru_data[i++] * 8;
-		board.lang = fru_data[i++];
-		i += 3;	/* skip mfg. date time */
-		board.mfg = get_fru_area_str(fru_data, &i);
-		board.prod = get_fru_area_str(fru_data, &i);
-		board.serial = get_fru_area_str(fru_data, &i);
-		board.part = get_fru_area_str(fru_data, &i);
-		board.fru = get_fru_area_str(fru_data, &i);
-
-		printf("  Board Mfg        : %s\n", board.mfg);
-		printf("  Board Product    : %s\n", board.prod);
-		printf("  Board Serial     : %s\n", board.serial);
-		printf("  Board Part       : %s\n", board.part);
+		i = area_offsets[OFF_BOARD];
+		read_fru_area(intf, &fru, id, i, 2, fru_data);
+		board.area_len = 8 * fru_data[i+1];
+		if (board.area_len > 0
+		&& read_fru_area(intf, &fru, id, i, board.area_len, fru_data) > 0)
+		{
+			board.area_ver = fru_data[i++];
+			board.area_len = fru_data[i++] * 8;
+			board.lang = fru_data[i++];
+			i += 3;	/* skip mfg. date time */
+			board.mfg = get_fru_area_str(fru_data, &i);
+			board.prod = get_fru_area_str(fru_data, &i);
+			board.serial = get_fru_area_str(fru_data, &i);
+			board.part = get_fru_area_str(fru_data, &i);
+			board.fru = get_fru_area_str(fru_data, &i);
+
+			printf("  Board Mfg        : %s\n", board.mfg);
+			printf("  Board Product    : %s\n", board.prod);
+			printf("  Board Serial     : %s\n", board.serial);
+			printf("  Board Part       : %s\n", board.part);
 
-		if (verbose > 0)
-			printf("  Board FRU ID     : %s\n", board.fru);
+			if (verbose > 0)
+				printf("  Board FRU ID     : %s\n", board.fru);
 
-		while (fru_data[i] != 0xc1 && i < header.offset.board + board.area_len)
-		{
-			char *extra;
+			while (fru_data[i] != 0xc1 && i < area_offsets[OFF_BOARD] + board.area_len)
+			{
+				char *extra;
 
-			extra = get_fru_area_str(fru_data, &i);
-			if (extra [0]) printf("  Board Extra      : %s\n", extra);
-			free(extra);
-		}
+				extra = get_fru_area_str(fru_data, &i);
+				if (extra [0]) printf("  Board Extra      : %s\n", extra);
+				free(extra);
+			}
 
-		free(board.mfg);
-		free(board.prod);
-		free(board.serial);
-		free(board.part);
-		free(board.fru);
+			free(board.mfg);
+			free(board.prod);
+			free(board.serial);
+			free(board.part);
+			free(board.fru);
+		}
 	}
 
 	/* product area */
 
-	if (header.offset.product)
+	if (area_offsets[OFF_PRODUCT] >= sizeof(struct fru_header))
 	{
-		i = header.offset.product;
-		product.area_ver = fru_data[i++];
-		product.area_len = fru_data[i++] * 8;
-		product.lang = fru_data[i++];
-		product.mfg = get_fru_area_str(fru_data, &i);
-		product.name = get_fru_area_str(fru_data, &i);
-		product.part = get_fru_area_str(fru_data, &i);
-		product.version = get_fru_area_str(fru_data, &i);
-		product.serial = get_fru_area_str(fru_data, &i);
-		product.asset = get_fru_area_str(fru_data, &i);
-		product.fru = get_fru_area_str(fru_data, &i);
-
-		printf("  Product Mfg      : %s\n", product.mfg);
-		printf("  Product Name     : %s\n", product.name);
-		printf("  Product Part     : %s\n", product.part);
-		printf("  Product Version  : %s\n", product.version);
-		printf("  Product Serial   : %s\n", product.serial);
-		printf("  Product Asset    : %s\n", product.asset);
+		i = area_offsets[OFF_PRODUCT];
+		read_fru_area(intf, &fru, id, i, 2, fru_data);
+		product.area_len = 8 * fru_data[i+1];
+		if (product.area_len > 0
+		&& read_fru_area(intf, &fru, id, i, product.area_len, fru_data) > 0)
+		{
+			product.area_ver = fru_data[i++];
+			product.area_len = fru_data[i++] * 8;
+			product.lang = fru_data[i++];
+			product.mfg = get_fru_area_str(fru_data, &i);
+			product.name = get_fru_area_str(fru_data, &i);
+			product.part = get_fru_area_str(fru_data, &i);
+			product.version = get_fru_area_str(fru_data, &i);
+			product.serial = get_fru_area_str(fru_data, &i);
+			product.asset = get_fru_area_str(fru_data, &i);
+			product.fru = get_fru_area_str(fru_data, &i);
+
+			printf("  Product Mfg      : %s\n", product.mfg);
+			printf("  Product Name     : %s\n", product.name);
+			printf("  Product Part     : %s\n", product.part);
+			printf("  Product Version  : %s\n", product.version);
+			printf("  Product Serial   : %s\n", product.serial);
+			printf("  Product Asset    : %s\n", product.asset);
 
-		if (verbose > 0)
-			printf("  Product FRU ID   : %s\n", product.fru);
+			if (verbose > 0)
+				printf("  Product FRU ID   : %s\n", product.fru);
 
-		while (fru_data[i] != 0xc1 && i < header.offset.product + product.area_len)
-		{
-			char *extra;
+			while (fru_data[i] != 0xc1 && i < area_offsets[OFF_PRODUCT] + product.area_len)
+			{
+				char *extra;
 
-			extra = get_fru_area_str(fru_data, &i);
-			if (extra [0]) printf("  Product Extra    : %s\n", extra);
-			free(extra);
-		}
+				extra = get_fru_area_str(fru_data, &i);
+				if (extra [0]) printf("  Product Extra    : %s\n", extra);
+				free(extra);
+			}
 
-		free(product.mfg);
-		free(product.name);
-		free(product.part);
-		free(product.version);
-		free(product.serial);
-		free(product.asset);
-		free(product.fru);
+			free(product.mfg);
+			free(product.name);
+			free(product.part);
+			free(product.version);
+			free(product.serial);
+			free(product.asset);
+			free(product.fru);
+		}
 	}
 
 	/* multirecord area */
 
-	if (header.offset.multi)
+	if (area_offsets[OFF_MULTI] >= sizeof(struct fru_header))
 	{
 		struct fru_multirec_header * h;
 		struct fru_multirec_powersupply * ps;
@@ -294,13 +424,29 @@
 		struct fru_multirec_dcload * dl;
 		unsigned short peak_capacity;
 		unsigned char peak_hold_up_time;
+		unsigned int last_off;
+		#define CHUNK_SIZE (255 + sizeof(struct fru_multirec_header))
 
-		i = header.offset.multi;
-
+		i = last_off = area_offsets[OFF_MULTI];
 		do
 		{
 			h = (struct fru_multirec_header *) (fru_data + i);
 
+			/* read multirec area in (at most) CHUNK_SIZE bytes at a time */
+			if (last_off < i+sizeof(*h) || last_off < i+h->len)
+			{
+				len = fru.size - last_off;
+				if (len > CHUNK_SIZE)
+					len = CHUNK_SIZE;
+
+				if (read_fru_area(intf, &fru, id, last_off, len, fru_data) > 0)
+					last_off += len;
+				else {
+					printf("ERROR: reading FRU data\n");
+					break;
+				}
+			}
+			
 			switch (h->type)
 			{
 			case FRU_RECORD_TYPE_POWER_SUPPLY_INFORMATION:
@@ -420,7 +566,11 @@
 			continue;
 
 		fru = (struct sdr_record_fru_device_locator *) ipmi_sdr_get_record(intf, header, itr);
-		if (!fru || fru->device_type != 0x10)
+		if (!fru)
+			continue;
+		if (fru->device_type != 0x10
+		&& (fru->device_type_modifier != 0x02
+				|| fru->device_type < 0x08 || fru->device_type > 0x0f))
 			continue;
 
 		memset(desc, 0, sizeof(desc));
@@ -431,7 +581,16 @@
 		switch (fru->device_type_modifier) {
 		case 0x00:
 		case 0x02:
-			ipmi_fru_print(intf, fru->keys.fru_device_id);
+			intf->target_addr = ((fru->keys.dev_access_addr << 1)
+			                  |  (fru->keys.__reserved2 << 7));
+
+			if (intf->target_addr == IPMI_BMC_SLAVE_ADDR
+			&&  fru->keys.fru_device_id == 0)
+				printf("  (Builtin FRU device)\n");
+			else {
+				ipmi_fru_print(intf, fru->keys.fru_device_id);
+				intf->target_addr = IPMI_BMC_SLAVE_ADDR;
+			}
 			break;
 		case 0x01:
 			ipmi_spd_print(intf, fru->keys.fru_device_id);
diff -urN ipmitool-1.5.9-orig/src/plugins/ipmi_intf.c ipmitool-1.5.9/src/plugins/ipmi_intf.c
--- ipmitool-1.5.9-orig/src/plugins/ipmi_intf.c	2004-03-26 15:49:45.000000000 -0600
+++ ipmitool-1.5.9/src/plugins/ipmi_intf.c	2004-08-04 13:12:29.000000000 -0500
@@ -92,6 +92,7 @@
 				printf("ERROR: Unable to setup static interface %s\n", name);
 				return NULL;
 			}
+			intf->target_addr = IPMI_BMC_SLAVE_ADDR;
 			return intf;
 		}
 		i++;
@@ -129,6 +130,7 @@
 		return NULL;
 	}
 
+	intf->target_addr = IPMI_BMC_SLAVE_ADDR;
 	return intf;
 }
 
diff -urN ipmitool-1.5.9-orig/src/plugins/ipmi_intf_static.c ipmitool-1.5.9/src/plugins/ipmi_intf_static.c
--- ipmitool-1.5.9-orig/src/plugins/ipmi_intf_static.c	2004-04-02 11:38:46.000000000 -0600
+++ ipmitool-1.5.9/src/plugins/ipmi_intf_static.c	1969-12-31 18:00:00.000000000 -0600
@@ -1,49 +0,0 @@
-/*
- * Copyright (c) 2003 Sun Microsystems, Inc.  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 Sun Microsystems, Inc. or 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.
- * SUN MICROSYSTEMS, INC. ("SUN") 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
- * SUN 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 SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
- * 
- * You acknowledge that this software is not designed or intended for use
- * in the design, construction, operation or maintenance of any nuclear
- * facility.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-
-#include <config.h>
-#include <ipmitool/ipmi_intf.h>
-#include <ipmitool/ipmi.h>
-
- extern int open_intf_setup(struct ipmi_intf ** intf); extern int lan_intf_setup(struct ipmi_intf ** intf);
-
-struct static_intf static_intf_list[] = {
-	 { "intf_open", open_intf_setup }, { "intf_lan", lan_intf_setup },
-	{ 0, 0 }
-};
diff -urN ipmitool-1.5.9-orig/src/plugins/lan/lan.c ipmitool-1.5.9/src/plugins/lan/lan.c
--- ipmitool-1.5.9-orig/src/plugins/lan/lan.c	2004-04-02 11:22:53.000000000 -0600
+++ ipmitool-1.5.9/src/plugins/lan/lan.c	2004-08-07 07:17:45.000000000 -0500
@@ -133,6 +133,33 @@
 };
 
 static struct ipmi_rq_entry *
+ipmi_req_add_entry(struct ipmi_intf * intf, struct ipmi_rq * req)
+{
+	struct ipmi_rq_entry * e = malloc(sizeof(struct ipmi_rq_entry));
+
+	if (e == NULL)
+		printf("WARNING: no memory!\n");
+	else {
+		memset(e, 0, sizeof(struct ipmi_rq_entry));
+		memcpy(&e->req, req, sizeof(struct ipmi_rq));
+
+		e->intf = intf;
+		e->session = &lan_session;
+
+		if (!ipmi_req_entries) {
+			ipmi_req_entries = e;
+		} else {
+			ipmi_req_entries_tail->next = e;
+		}
+		ipmi_req_entries_tail = e;
+		if (verbose > 3)
+			printf("added list entry seq=0x%02x cmd=0x%02x\n",
+			       curr_seq, req->msg.cmd);
+	}
+	return e;
+}
+
+static struct ipmi_rq_entry *
 ipmi_req_lookup_entry(unsigned char seq, unsigned char cmd)
 {
 	struct ipmi_rq_entry * e = ipmi_req_entries;
@@ -505,9 +532,18 @@
 
 		/* now see if we have oustanding entry in request list */
 		entry = ipmi_req_lookup_entry(rsp->header.rq_seq, rsp->header.cmd);
+
 		if (entry) {
 			if (verbose > 2)
 				printf("IPMI Request Match found\n");
+
+			if (intf->target_addr != IPMI_BMC_SLAVE_ADDR) {
+				/* bridged command: lose the extra header */
+				x += sizeof(rsp->header);
+				if (verbose	&& rsp->data[x-1] != 0)
+					printf("WARNING: Bridged Cmd Compl Code = 0x%02x\n",
+							rsp->data[x-1]);
+			}
 			ipmi_req_remove_entry(rsp->header.rq_seq, rsp->header.cmd);
 		} else {
 			if (verbose)
@@ -566,30 +602,15 @@
 		.seq		= 0xff,
 	};
 	unsigned char * msg;
-	int cs, mp, ap = 0, len = 0, tmp;
+	int cs, mp, ap = 0, len = 0, tmp, cs2;
 	struct ipmi_rq_entry * entry;
 
 	if (curr_seq >= 64)
 		curr_seq = 0;
 
-	entry = malloc(sizeof(struct ipmi_rq_entry));
-	memset(entry, 0, sizeof(struct ipmi_rq_entry));
-	memcpy(&entry->req, req, sizeof(struct ipmi_rq));
-
-	entry->intf = intf;
-	entry->session = &lan_session;
-
-	if (!ipmi_req_entries) {
-		ipmi_req_entries = entry;
-	} else {
-		ipmi_req_entries_tail->next = entry;
-	}
-	ipmi_req_entries_tail = entry;
-	if (verbose > 3)
-		printf("added list entry seq=0x%02x cmd=0x%02x\n",
-		       curr_seq, req->msg.cmd);
-	
-	len = req->msg.data_len + 21;
+	entry = ipmi_req_add_entry(intf, req);
+
+	len = req->msg.data_len + 29;
 	if (lan_session.active && lan_session.authtype)
 		len += 16;
 	msg = malloc(len);
@@ -617,11 +638,29 @@
 	}
 
 	/* message length */
-	msg[len++] = req->msg.data_len + 7;
+	if (intf->target_addr == IPMI_BMC_SLAVE_ADDR) {
+		msg[len++] = req->msg.data_len + 7;
+		cs = mp = len;
+	}
+	else {
+		/* bridged request: encapsulate w/in Send Message */
+		msg[len++] = req->msg.data_len + 15;
+		cs = mp = len;
+		msg[len++] = IPMI_BMC_SLAVE_ADDR;
+		msg[len++] = IPMI_NETFN_APP << 2;
+		tmp = len - cs;
+		msg[len++] = ipmi_csum(msg+cs, tmp);
+		cs2 = len;
+		msg[len++] = IPMI_REMOTE_SWID;
+		msg[len++] = curr_seq << 2;
+		msg[len++] = 0x34;			/* Send Message rqst */
+		entry->req.msg.cmd = 0x34;	/* (fixup request entry) */
+		msg[len++] = 0x40;			/* Track request, Channel=IPMB */
+		cs = len;
+	}
 
 	/* ipmi message header */
-	cs = mp = len;
-	msg[len++] = IPMI_BMC_SLAVE_ADDR;
+	msg[len++] = intf->target_addr;
 	msg[len++] = req->msg.netfn << 2;
 	tmp = len - cs;
 	msg[len++] = ipmi_csum(msg+cs, tmp);
@@ -640,7 +679,7 @@
 		printf(">>   Session ID : 0x%08lx\n", lan_session.id);
 		
 		printf(">> IPMI Request Message Header\n");
-		printf(">>   Rs Addr    : %02x\n", IPMI_BMC_SLAVE_ADDR);
+		printf(">>   Rs Addr    : %02x\n", intf->target_addr);
 		printf(">>   NetFn      : %02x\n", req->msg.netfn);
 		printf(">>   Rs LUN     : %01x\n", 0);
 		printf(">>   Rq Addr    : %02x\n", IPMI_REMOTE_SWID);
@@ -659,6 +698,12 @@
 	tmp = len - cs;
 	msg[len++] = ipmi_csum(msg+cs, tmp);
 
+	/* bridged request: 2nd checksum */
+	if (intf->target_addr != IPMI_BMC_SLAVE_ADDR) {
+		tmp = len - cs2;
+		msg[len++] = ipmi_csum(msg+cs2, tmp);
+	}
+
 	if (lan_session.active &&
 	    lan_session.authtype == IPMI_SESSION_AUTHTYPE_MD5) {
 		unsigned char * d = ipmi_auth_md5(msg+mp, msg[mp-1]);
@@ -690,7 +735,7 @@
 		return NULL;
 	}
 
-	while (try < IPMI_LAN_RETRY) {
+	for (;;) {
 		if (ipmi_lan_send_packet(intf, entry->msg_data, entry->msg_len) < 0) {
 			printf("ipmi_lan_send_cmd failed\n");
 			return NULL;
@@ -706,7 +751,10 @@
 			break;
 
 		usleep(5000);
-		try++;
+		if (++try >= IPMI_LAN_RETRY) {
+			printf("  No response.\n");
+			break;
+		}
 	}
 
 	return rsp;
