Package: ipmitool
Version: 1.8.8-2
Severity: wishlist
Tags: patch

Hi !

Currently SOL for IPMI 1.5 is useless in ipmitool. Someone posted a
patch to fix the problem:

http://www.mail-archive.com/ipmitool-devel@lists.sourceforge.net/msg00370.html

I've tested it, and it works !
Here you'll find the patch which applies nicely to ipmitool 1.8.8-2.

Cheers,

  Ludovic Drolez.


-- System Information:
Debian Release: 4.0
  APT prefers testing
  APT policy: (500, 'testing')
Architecture: i386 (i686)
Shell:  /bin/sh linked to /bin/bash
Kernel: Linux 2.6.18
Locale: LANG=C, LC_CTYPE=C (charmap=ANSI_X3.4-1968)
--- ipmitool-1.8.8.orig/lib/ipmi_isol.c
+++ ipmitool-1.8.8/lib/ipmi_isol.c
@@ -32,7 +32,17 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <strings.h>
 #include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+
+
+#include <termios.h>
 
 #include <ipmitool/helper.h>
 #include <ipmitool/log.h>
@@ -41,39 +51,40 @@
 #include <ipmitool/ipmi_intf.h>
 #include <ipmitool/ipmi_isol.h>
 
-const struct valstr ipmi_isol_baud_vals[] = {
-	{ ISOL_BAUD_RATE_9600,   "9600" },
-	{ ISOL_BAUD_RATE_19200,  "19200" },
-	{ ISOL_BAUD_RATE_38400,  "38400" },
-	{ ISOL_BAUD_RATE_57600,  "57600" },
-	{ ISOL_BAUD_RATE_115200, "115200" },
-	{ 0x00, NULL }
-};
+static struct termios _saved_tio;
+static int            _in_raw_mode = 0;
 
 extern int verbose;
 
-static int ipmi_isol_setup(struct ipmi_intf * intf, char baudsetting)
+#define ISOL_ESCAPE_CHARACTER                    '~'
+
+/*
+ * ipmi_get_isol_info
+ */
+static int ipmi_get_isol_info(struct ipmi_intf * intf,
+			      struct isol_config_parameters * params)
 {
 	struct ipmi_rs * rsp;
 	struct ipmi_rq req;
-	unsigned char data[6];	
+	unsigned char data[6];
 
-	/* TEST FOR AVAILABILITY */
+	memset(&req, 0, sizeof(req));
+	req.msg.netfn = IPMI_NETFN_ISOL;
+	req.msg.cmd = GET_ISOL_CONFIG;
+	req.msg.data = data;
+	req.msg.data_len = 4;
 
+	/* GET ISOL ENABLED CONFIG */
+	
 	memset(data, 0, 6);
 	data[0] = 0x00;
 	data[1] = ISOL_ENABLE_PARAM;
-	data[2] = ISOL_ENABLE_FLAG;
-
-	memset(&req, 0, sizeof(req));
-	req.msg.netfn = IPMI_NETFN_ISOL;
-	req.msg.cmd = SET_ISOL_CONFIG;
-	req.msg.data = data;
-	req.msg.data_len = 3;
+	data[2] = 0x00;		/* block */
+	data[3] = 0x00;		/* selector */
 
 	rsp = intf->sendrecv(intf, &req);
 	if (rsp == NULL) {
-		lprintf(LOG_ERR, "Error in Set ISOL Config Command");
+		lprintf(LOG_ERR, "Error in Get ISOL Config Command");
 		return -1;
 	}
 	if (rsp->ccode == 0xc1) {
@@ -81,20 +92,19 @@
 		return -1;
 	}
 	if (rsp->ccode > 0) {
-		lprintf(LOG_ERR, "Error in Set ISOL Config Command: %s",
+		lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
 			val2str(rsp->ccode, completion_code_vals));
 		return -1;
 	}
+	params->enabled = rsp->data[1];
 
-	/* GET ISOL CONFIG */
-
+	/* GET ISOL AUTHENTICATON CONFIG */
+	
 	memset(data, 0, 6);
 	data[0] = 0x00;
 	data[1] = ISOL_AUTHENTICATION_PARAM;
 	data[2] = 0x00;		/* block */
 	data[3] = 0x00;		/* selector */
-	req.msg.cmd = GET_ISOL_CONFIG;
-	req.msg.data_len = 4;
 
 	rsp = intf->sendrecv(intf, &req);
 	if (rsp == NULL) {
@@ -106,86 +116,713 @@
 			val2str(rsp->ccode, completion_code_vals));
 		return -1;
 	}
-
-	if (verbose > 1)
-		printbuf(rsp->data, rsp->data_len, "ISOL Config");
-
-	/* SET ISOL CONFIG - AUTHENTICATION */
-
+	params->privilege_level = rsp->data[1];
+	
+	/* GET ISOL BAUD RATE CONFIG */
+	
 	memset(data, 0, 6);
 	data[0] = 0x00;
-	data[1] = ISOL_AUTHENTICATION_PARAM;
-	data[2] = ISOL_PRIVILEGE_LEVEL_USER | (rsp->data[1] & 0x80);
-	req.msg.cmd = SET_ISOL_CONFIG;
-	req.msg.data_len = 3;
+	data[1] = ISOL_BAUD_RATE_PARAM;
+	data[2] = 0x00;		/* block */
+	data[3] = 0x00;		/* selector */
 
 	rsp = intf->sendrecv(intf, &req);
 	if (rsp == NULL) {
-		lprintf(LOG_ERR, "Error in Set ISOL Config (Authentication) Command");
+		lprintf(LOG_ERR, "Error in Get ISOL Config Command");
 		return -1;
 	}
 	if (rsp->ccode > 0) {
-		lprintf(LOG_ERR, "Error in Set ISOL Config (Authentication) Command: %s",
+		lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
 			val2str(rsp->ccode, completion_code_vals));
 		return -1;
 	}
+	params->bit_rate = rsp->data[1];
 
-	/* SET ISOL CONFIG - BAUD RATE */
+	return 0;
+}
 
-	memset(data, 0, 6);
-	data[0] = 0x00;
-	data[1] = ISOL_BAUD_RATE_PARAM;
-	data[2] = baudsetting;
+static int ipmi_print_isol_info(struct ipmi_intf * intf)
+{
+	struct isol_config_parameters params = {0};
+	if (ipmi_get_isol_info(intf, &params))
+		return -1;
+
+	if (csv_output)
+	{
+		printf("%s,", (params.enabled & 0x1)?"true": "false");
+		printf("%s,",
+			   val2str((params.privilege_level & 0xf), ipmi_privlvl_vals));
+		printf("%s,",
+			   val2str((params.bit_rate & 0xf), impi_bit_rate_vals));
+	}
+	else
+	{
+		printf("Enabled                         : %s\n",
+		       (params.enabled & 0x1)?"true": "false");
+		printf("Privilege Level                 : %s\n",
+		       val2str((params.privilege_level & 0xf), ipmi_privlvl_vals));
+		printf("Bit Rate (kbps)                 : %s\n",
+		       val2str((params.bit_rate & 0xf), impi_bit_rate_vals));
+	}
+
+	return 0;
+}
+
+static int ipmi_isol_set_param(struct ipmi_intf * intf,
+			       const char *param,
+			       const char *value)
+{
+	struct ipmi_rs * rsp;
+	struct ipmi_rq req;
+	unsigned char data[6];	
+	struct isol_config_parameters params = {0};
+
+	/* We need other values to complete the request */
+	if (ipmi_get_isol_info(intf, &params))
+		return -1;
+
+	memset(&req, 0, sizeof(req));
+	req.msg.netfn = IPMI_NETFN_ISOL;
 	req.msg.cmd = SET_ISOL_CONFIG;
+	req.msg.data = data;
 	req.msg.data_len = 3;
 
+	memset(data, 0, 6);
+	
+	/*
+	 * enabled
+	 */
+	if (strcmp(param, "enabled") == 0)
+	{
+		data[1] = ISOL_ENABLE_PARAM;
+		if (strcmp(value, "true") == 0)
+			data[2] = 0x01;
+		else if (strcmp(value, "false") == 0)
+			data[2] = 0x00;
+		else {
+			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+				   value, param);
+			lprintf(LOG_ERR, "Valid values are true and false");
+			return -1;
+		}
+	}
+
+	/*
+	 * privilege-level
+	 */
+	else if (strcmp(param, "privilege-level") == 0)
+	{
+		data[1] = ISOL_AUTHENTICATION_PARAM;
+		if (! strcmp(value, "user"))
+			data[2] = 0x02;
+		else if (! strcmp(value, "operator"))
+			data[2] = 0x03;
+		else if (! strcmp(value, "admin"))
+			data[2] = 0x04;
+		else if (! strcmp(value, "oem"))
+			data[2] = 0x05;
+		else
+		{
+			lprintf(LOG_ERR, "Invalid value %s for parameter %s",
+				   value, param);
+			lprintf(LOG_ERR, "Valid values are user, operator, admin, and oem");
+			return -1;
+		}
+		/* We need to mask bit7 from the fetched value */
+		data[2] |= (params.privilege_level & 0x80) ? 0x80 : 0x00;
+	}
+
+	/*
+	 * bit-rate
+	 */
+	else if (strcmp(param, "bit-rate") == 0)
+	{
+		data[1] = ISOL_BAUD_RATE_PARAM;
+		if (strncmp(value, "9.6", 3) == 0) {
+			data[2] = 0x06;
+		}
+		else if (strncmp(value, "19.2", 4) == 0) {
+			data[2] = 0x07;
+		}
+		else if (strncmp(value, "38.4", 4) == 0) {
+			data[2] = 0x08;
+		}
+		else if (strncmp(value, "57.6", 4) == 0) {
+			data[2] = 0x09;
+		}
+		else if (strncmp(value, "115.2", 5) == 0) {
+			data[2] = 0x0A;
+		}
+		else {
+			lprintf(LOG_ERR, "ISOL - Unsupported baud rate: %s", value);
+			lprintf(LOG_ERR, "Valid values are 9.6, 19.2, 38.4, 57.6 and 115.2");
+			return -1;
+		}
+	}
+	else
+	{
+		lprintf(LOG_ERR, "Error: invalid ISOL parameter %s", param);
+		return -1;
+	}
+	
+	
+	/*
+	 * Execute the request
+	 */
+
 	rsp = intf->sendrecv(intf, &req);
 	if (rsp == NULL) {
-		lprintf(LOG_ERR, "Error in Set ISOL Config (Baud Rate) Command");
+		lprintf(LOG_ERR, "Error setting ISOL parameter '%s'", param);
 		return -1;
 	}
 	if (rsp->ccode > 0) {
-		lprintf(LOG_ERR, "Error in Set ISOL Config (Baud Rate) Command: %s",
-			val2str(rsp->ccode, completion_code_vals));
+		lprintf(LOG_ERR, "Error setting ISOL parameter '%s': %s",
+			   param, val2str(rsp->ccode, completion_code_vals));
 		return -1;
 	}
 
-	printf("Set ISOL Baud Rate to %s\n",
-	       val2str(baudsetting, ipmi_isol_baud_vals));
+	return 0;
+}
+
+static void
+leave_raw_mode(void)
+{
+	if (!_in_raw_mode)
+		return;
+	if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1)
+		perror("tcsetattr");
+	else
+		_in_raw_mode = 0;
+}
+
+
+
+static void
+enter_raw_mode(void)
+{
+	struct termios tio;
+	if (tcgetattr(fileno(stdin), &tio) == -1) {
+		perror("tcgetattr");
+		return;
+	}
+	_saved_tio = tio;
+	tio.c_iflag |= IGNPAR;
+	tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF)\
+		;
+	tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL);
+	//	#ifdef IEXTEN
+	tio.c_lflag &= ~IEXTEN;
+	//	#endif
+	tio.c_oflag &= ~OPOST;
+	tio.c_cc[VMIN] = 1;
+	tio.c_cc[VTIME] = 0;
+	if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) == -1)
+		perror("tcsetattr");
+	else
+		_in_raw_mode = 1;
+}
+
+
+static void
+sendBreak(struct ipmi_intf * intf)
+{
+	struct ipmi_v2_payload  v2_payload;
+
+	memset(&v2_payload, 0, sizeof(v2_payload));
+
+	v2_payload.payload.sol_packet.character_count = 0;
+	v2_payload.payload.sol_packet.generate_break  = 1;
+
+	intf->send_sol(intf, &v2_payload);
+}
+
+/*
+ * suspendSelf
+ *
+ * Put ourself in the background
+ *
+ * param bRestoreTty specifies whether we will put our self back
+ *       in raw mode when we resume
+ */
+static void
+suspendSelf(int bRestoreTty)
+{
+	leave_raw_mode();
+	kill(getpid(), SIGTSTP);
+
+	if (bRestoreTty)
+		enter_raw_mode();
+}
+
+
+
+/*
+ * printiSolEscapeSequences
+ *
+ * Send some useful documentation to the user
+ */
+static void
+printiSolEscapeSequences(void)
+{
+	printf(
+		   "%c?\r\n\
+	Supported escape sequences:\r\n\
+	%c.  - terminate connection\r\n\
+	%c^Z - suspend ipmitool\r\n\
+	%c^X - suspend ipmitool, but don't restore tty on restart\r\n\
+	%cB  - send break\r\n\
+	%c?  - this message\r\n\
+	%c%c  - send the escape character by typing it twice\r\n\
+	(Note that escapes are only recognized immediately after newline.)\r\n",
+		   ISOL_ESCAPE_CHARACTER,
+		   ISOL_ESCAPE_CHARACTER,
+		   ISOL_ESCAPE_CHARACTER,
+		   ISOL_ESCAPE_CHARACTER,
+		   ISOL_ESCAPE_CHARACTER,
+		   ISOL_ESCAPE_CHARACTER,
+		   ISOL_ESCAPE_CHARACTER,
+		   ISOL_ESCAPE_CHARACTER);
+}
+
+
+
+/*
+ * output
+ *
+ * Send the specified data to stdout
+ */
+static void
+output(struct ipmi_rs * rsp)
+{
+	if (rsp)
+	{
+		int i;
+		for (i = 0; i < rsp->data_len; ++i)
+			putc(rsp->data[i], stdout);
+
+		fflush(stdout);
+	}
+}
+
+/*
+ * ipmi_isol_deactivate
+ */
+static int
+ipmi_isol_deactivate(struct ipmi_intf * intf)
+{
+	struct ipmi_rs * rsp;
+	struct ipmi_rq   req;
+	uint8_t    data[6];	 
+	struct isol_config_parameters params;
+
+	memset(&req, 0, sizeof(req));
+	req.msg.netfn = IPMI_NETFN_ISOL;
+	req.msg.cmd = ACTIVATE_ISOL;
+	req.msg.data = data;
+	req.msg.data_len = 5;
 
+	memset(data, 0, 6);
+	data[0] = 0x00; /* Deactivate */
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	data[5] = 0x00;
+
+	rsp = intf->sendrecv(intf, &req);
+	if (rsp == NULL) {
+		lprintf(LOG_ERR, "Error deactivating ISOL");
+		return -1;
+	}
+	if (rsp->ccode > 0) {
+		lprintf(LOG_ERR, "Error deactivating ISOL: %s",
+			val2str(rsp->ccode, completion_code_vals));
+		return -1;
+	}
+	/* response contain 4 additional bytes : 80 00 32 ff
+	   Don't know what to use them for yet... */
 	return 0;
 }
 
-int ipmi_isol_main(struct ipmi_intf * intf, int argc, char ** argv)
+/*
+ * processiSolUserInput
+ *
+ * Act on user input into the ISOL session.  The only reason this
+ * is complicated is that we have to process escape sequences.
+ *
+ * return   0 on success
+ *          1 if we should exit
+ *        < 0 on error (BMC probably closed the session)
+ */
+static int
+processiSolUserInput(struct ipmi_intf * intf,
+		    uint8_t * input,
+		    uint16_t  buffer_length)
 {
-	int ret = 0;
+	static int escape_pending = 0;
+	static int last_was_cr    = 1;
+	struct ipmi_v2_payload v2_payload;
+	int  length               = 0;
+	int  retval               = 0;
+	char ch;
+	int  i;
+
+	memset(&v2_payload, 0, sizeof(v2_payload));
+	
+	/*
+	 * Our first order of business is to check the input for escape
+	 * sequences to act on.
+	 */
+	for (i = 0; i < buffer_length; ++i)
+	{
+		ch = input[i];
+
+		if (escape_pending){
+			escape_pending = 0;
+			
+			/*
+			 * Process a possible escape sequence.
+			 */
+			switch (ch) {
+			case '.':
+				printf("%c. [terminated ipmitool]\r\n", ISOL_ESCAPE_CHARACTER);
+				retval = 1;
+				break;
+			case 'Z' - 64:
+				printf("%c^Z [suspend ipmitool]\r\n", ISOL_ESCAPE_CHARACTER);
+				suspendSelf(1); /* Restore tty back to raw */
+				continue;
+
+			case 'X' - 64:
+				printf("%c^X [suspend ipmitool]\r\n", ISOL_ESCAPE_CHARACTER);
+				suspendSelf(0); /* Don't restore to raw mode */
+				continue;
+
+			case 'B':
+				printf("%cb [send break]\r\n", ISOL_ESCAPE_CHARACTER);
+				sendBreak(intf);
+				continue;
+
+			case '?':
+				printiSolEscapeSequences();
+				continue;
+			default:
+				if (ch != ISOL_ESCAPE_CHARACTER)
+					v2_payload.payload.sol_packet.data[length++] =
+						ISOL_ESCAPE_CHARACTER;
+				v2_payload.payload.sol_packet.data[length++] = ch;
+			}
+		}
 
-	if (argc < 2 || strncmp(argv[0], "help", 4) == 0) {
-		lprintf(LOG_NOTICE, "ISOL Commands: setup <baud>");
-		lprintf(LOG_NOTICE, "ISOL Baud Rates:  9600, 19200, 38400, 57600, 115200");
-		return 0;
-	}
-		
-	if (strncmp(argv[0], "setup", 5) == 0) {
-		if (strncmp(argv[1], "9600", 4) == 0) {
-			ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_9600);
-		}
-		else if (strncmp(argv[1], "19200", 5) == 0) {
-			ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_19200);
+		else
+		{
+			if (last_was_cr && (ch == ISOL_ESCAPE_CHARACTER)) {
+				escape_pending = 1;
+				continue;
+			}
+
+			v2_payload.payload.sol_packet.data[length++] =	ch;
 		}
-		else if (strncmp(argv[1], "38400", 5) == 0) {
-			ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_38400);
+
+
+		/*
+		 * Normal character.  Record whether it was a newline.
+		 */
+		last_was_cr = (ch == '\r' || ch == '\n');
+	}
+
+	/*
+	 * If there is anything left to process we dispatch it to the BMC,
+	 * send intf->session->sol_data.max_outbound_payload_size bytes
+	 * at a time.
+	 */
+	if (length)
+	{
+		struct ipmi_rs * rsp;
+
+		v2_payload.payload.sol_packet.flush_outbound = 1; /* Not sure if necessary ? */
+		v2_payload.payload.sol_packet.character_count = length;
+		rsp = intf->send_sol(intf, &v2_payload);
+
+		if (! rsp) {
+			lprintf(LOG_ERR, "Error sending SOL data");
+			retval = -1;
 		}
-		else if (strncmp(argv[1], "57600", 5) == 0) {
-			ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_57600);
+
+		/* If the sequence number is set we know we have new data */
+		else if ((rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL)        &&
+			 (rsp->payload.sol_packet.packet_sequence_number))
+			output(rsp);
+	}
+	return retval;
+}
+
+/*
+ * ipmi_isol_red_pill
+ */
+static int
+ipmi_isol_red_pill(struct ipmi_intf * intf)
+{
+	char   * buffer;
+	int    numRead;
+	int    bShouldExit       = 0;
+	int    bBmcClosedSession = 0;
+	fd_set read_fds;
+	struct timeval tv;
+	int    retval;
+	int    buffer_size = 255;
+	int    timedout = 0;
+
+	buffer = (char*)malloc(buffer_size);
+	if (buffer == NULL) {
+		lprintf(LOG_ERR, "ipmitool: malloc failure");
+		return -1;
+	}
+
+	enter_raw_mode();
+
+	while (! bShouldExit)
+	{
+		FD_ZERO(&read_fds);
+		FD_SET(0, &read_fds);
+		FD_SET(intf->fd, &read_fds);
+
+		/* Wait up to half a second */
+		tv.tv_sec =  0;
+		tv.tv_usec = 500000;
+
+		retval = select(intf->fd + 1, &read_fds, NULL, NULL, &tv);
+
+		if (retval)
+		{
+			if (retval == -1)
+			{
+				/* ERROR */
+				perror("select");
+				return -1;
+			}
+
+			timedout = 0;
+
+			/*
+			 * Process input from the user
+			 */
+			if (FD_ISSET(0, &read_fds))
+	 		{
+				bzero(buffer, sizeof(buffer));
+				numRead = read(fileno(stdin),
+							   buffer,
+							   buffer_size);
+				
+				if (numRead > 0)
+				{
+					int rc = processiSolUserInput(intf, buffer, numRead);
+					
+					if (rc)
+					{
+						if (rc < 0)
+							bShouldExit = bBmcClosedSession = 1;
+						else
+							bShouldExit = 1;
+					}
+				}
+				else
+				{
+					bShouldExit = 1;
+				}
+			}
+
+
+			/*
+			 * Process input from the BMC
+			 */
+			else if (FD_ISSET(intf->fd, &read_fds))
+			{
+				struct ipmi_rs * rs = intf->recv_sol(intf);
+				if (! rs)
+				{
+					bShouldExit = bBmcClosedSession = 1;
+				}
+				else
+					output(rs);
+ 			}
+
+			
+			/*
+			 * ERROR in select
+			 */
+ 			else
+			{
+				lprintf(LOG_ERR, "Error: Select returned with nothing to read");
+				bShouldExit = 1;
+			}
 		}
-		else if (strncmp(argv[1], "115200", 6) == 0) {
-			ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_115200);
+		else
+		{
+			if ((++timedout) == 20) /* Every 10 seconds we send a keepalive */
+			{
+				intf->keepalive(intf);
+				timedout = 0;
+			}
 		}
-		else {
-			lprintf(LOG_ERR, "ISOL - Unsupported baud rate: %s", argv[1]);
-			ret = -1;
+	}		
+
+	leave_raw_mode();
+
+	if (bBmcClosedSession)
+	{
+		lprintf(LOG_ERR, "SOL session closed by BMC");
+	}
+	else
+		ipmi_isol_deactivate(intf);
+
+	return 0;
+}
+
+/*
+ * ipmi_isol_activate
+ */
+static int
+ipmi_isol_activate(struct ipmi_intf * intf)
+{
+	struct ipmi_rs * rsp;
+	struct ipmi_rq   req;
+	uint8_t    data[6];	 
+	struct isol_config_parameters params;
+
+	if (ipmi_get_isol_info(intf, &params))
+		return -1;
+
+	if (!(params.enabled & 0x1)) {
+		lprintf(LOG_ERR, "ISOL is not enabled!");
+		return -1;
+	}
+
+	/*
+	 * Setup a callback so that the lanplus processing knows what
+	 * to do with packets that come unexpectedly (while waiting for
+	 * an ACK, perhaps.
+	 */
+	intf->session->sol_data.sol_input_handler = output;
+	
+	memset(&req, 0, sizeof(req));
+	req.msg.netfn = IPMI_NETFN_ISOL;
+	req.msg.cmd = ACTIVATE_ISOL;
+	req.msg.data = data;
+	req.msg.data_len = 5;
+
+	memset(data, 0, 6);
+	data[0] = 0x01;
+	data[1] = 0x00;
+	data[2] = 0x00;
+	data[3] = 0x00;
+	data[5] = 0x00;
+
+	rsp = intf->sendrecv(intf, &req);
+	if (NULL != rsp) {
+		switch (rsp->ccode) {
+			case 0x00: 
+				if (rsp->data_len == 4) {
+					break;
+				} else {
+					lprintf(LOG_ERR, "Error: Unexpected data length (%d) received "
+						   "in ISOL activation response",
+						   rsp->data_len);
+					return -1;
+				}
+				break;
+			case 0x80:
+				lprintf(LOG_ERR, "Info: ISOL already active on another session");
+				return -1;
+			case 0x81:
+				lprintf(LOG_ERR, "Info: ISOL disabled");
+				return -1;
+			case 0x82:
+				lprintf(LOG_ERR, "Info: ISOL activation limit reached");
+				return -1;
+			default:
+				lprintf(LOG_ERR, "Error activating ISOL: %s",
+					val2str(rsp->ccode, completion_code_vals));
+				return -1;
+		}				
+	} else {
+		lprintf(LOG_ERR, "Error: No response activating ISOL");
+		return -1;
+	}
+
+	/* response contain 4 additional bytes : 80 01 32 ff
+	   Don't know what to use them for yet... */
+
+	printf("[SOL Session operational.  Use %c? for help]\r\n",
+	       ISOL_ESCAPE_CHARACTER);
+
+	/*
+	 * At this point we are good to go with our SOL session.  We
+	 * need to listen to
+	 * 1) STDIN for user input
+	 * 2) The FD for incoming SOL packets
+	 */
+	if (ipmi_isol_red_pill(intf)) {
+		lprintf(LOG_ERR, "Error in SOL session");
+		return -1;
+	}
+
+	return 0;
+}
+
+static void print_isol_set_usage(void) {
+	lprintf(LOG_NOTICE, "\nISOL set parameters and values: \n");
+	lprintf(LOG_NOTICE, "  enabled                     true | false");
+	lprintf(LOG_NOTICE, "  privilege-level             user | operator | admin | oem");
+	lprintf(LOG_NOTICE, "  bit-rate                    "
+		"9.6 | 19.2 | 38.4 | 57.6 | 115.2");
+	lprintf(LOG_NOTICE, "");
+}
+
+static void print_isol_usage(void) {
+	lprintf(LOG_NOTICE, "ISOL Commands: info");
+	lprintf(LOG_NOTICE, "               set <parameter> <setting>");
+	lprintf(LOG_NOTICE, "               activate");
+}
+
+int ipmi_isol_main(struct ipmi_intf * intf, int argc, char ** argv)
+{
+	int ret = 0;
+
+	/*
+	 * Help
+	 */
+	if (!argc || !strncmp(argv[0], "help", 4))
+		print_isol_usage();
+
+	/*
+	 * Info
+	 */
+	else if (!strncmp(argv[0], "info", 4)) {
+		ret = ipmi_print_isol_info(intf);
+	}
+
+	/*
+	 * Set a parameter value
+	 */
+	else if (!strncmp(argv[0], "set", 3)) {
+		if (argc < 3) {
+			print_isol_set_usage();
+			return -1;
 		}
+		ret = ipmi_isol_set_param(intf, argv[1], argv[2]);
+	}
+
+	/*
+	 * Activate
+	 */
+ 	else if (!strncmp(argv[0], "activate", 8)) {
+		ret = ipmi_isol_activate(intf);
+	}
+	
+	else {
+		print_isol_usage();
+		ret = -1;
 	}
+	
 	return ret;
 }
--- ipmitool-1.8.8.orig/src/plugins/lan/lan.c
+++ ipmitool-1.8.8/src/plugins/lan/lan.c
@@ -80,6 +80,12 @@
 static struct ipmi_rs * ipmi_lan_poll_recv(struct ipmi_intf * intf);
 static int ipmi_lan_setup(struct ipmi_intf * intf);
 static int ipmi_lan_keepalive(struct ipmi_intf * intf);
+ static struct ipmi_rs * ipmi_lan_send_payload(struct ipmi_intf * intf,
+        struct ipmi_v2_payload * payload);
+ static struct ipmi_rs * ipmi_lan_recv_sol(struct ipmi_intf * intf);
+ static struct ipmi_rs * ipmi_lan_send_sol(struct ipmi_intf * intf,
+        struct ipmi_v2_payload * payload);
+
 
 struct ipmi_intf ipmi_lan_intf = {
 	name:		"lan",
@@ -89,6 +95,8 @@
 	close:		ipmi_lan_close,
 	sendrecv:	ipmi_lan_send_cmd,
 	sendrsp:	ipmi_lan_send_rsp,
+	recv_sol:	ipmi_lan_recv_sol,
+	send_sol:	ipmi_lan_send_sol,
 	keepalive:	ipmi_lan_keepalive,
 	target_addr:	IPMI_BMC_SLAVE_ADDR,
 };
@@ -430,81 +438,143 @@
 		memcpy(&rsp->session.id, rsp->data+x, 4);
 		x += 4;
 
-		if (intf->session->active && (rsp->session.authtype || intf->session->authtype))
-			x += 16;
+		if (rsp->session.id == (intf->session->session_id + 0x10000000)) {
+			/* With SOL, authtype is always NONE, so we have no authcode */
+			rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_SOL;
+	
+			rsp->session.msglen = rsp->data[x++];
+			
+			rsp->payload.sol_packet.packet_sequence_number =
+				rsp->data[x++] & 0x0F;
+
+			rsp->payload.sol_packet.acked_packet_number =
+				rsp->data[x++] & 0x0F;
+
+			rsp->payload.sol_packet.accepted_character_count =
+				rsp->data[x++];
+
+			rsp->payload.sol_packet.is_nack =
+				rsp->data[x] & 0x40;
+
+			rsp->payload.sol_packet.transfer_unavailable =
+				rsp->data[x] & 0x20;
+
+			rsp->payload.sol_packet.sol_inactive = 
+				rsp->data[x] & 0x10;
 
-		rsp->session.msglen = rsp->data[x++];
-		rsp->payload.ipmi_response.rq_addr = rsp->data[x++];
-		rsp->payload.ipmi_response.netfn   = rsp->data[x] >> 2;
-		rsp->payload.ipmi_response.rq_lun  = rsp->data[x++] & 0x3;
-		x++;		/* checksum */
-		rsp->payload.ipmi_response.rs_addr = rsp->data[x++];
-		rsp->payload.ipmi_response.rq_seq  = rsp->data[x] >> 2;
-		rsp->payload.ipmi_response.rs_lun  = rsp->data[x++] & 0x3;
-		rsp->payload.ipmi_response.cmd     = rsp->data[x++]; 
-		rsp->ccode          = rsp->data[x++];
-
-		if (verbose > 2)
-			printbuf(rsp->data, rsp->data_len, "ipmi message header");
-
-		lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header");
-		lprintf(LOG_DEBUG+1, "<<   Authtype   : %s",
-		       val2str(rsp->session.authtype, ipmi_authtype_session_vals));
-		lprintf(LOG_DEBUG+1, "<<   Sequence   : 0x%08lx",
-			(long)rsp->session.seq);
-		lprintf(LOG_DEBUG+1, "<<   Session ID : 0x%08lx",
-			(long)rsp->session.id);
+			rsp->payload.sol_packet.transmit_overrun =
+				rsp->data[x] & 0x08;
+	
+			rsp->payload.sol_packet.break_detected =
+				rsp->data[x++] & 0x04;
+
+			x++; /* On ISOL there's and additional fifth byte before the data starts */
+	
+			lprintf(LOG_DEBUG, "SOL sequence number     : 0x%02x",
+				rsp->payload.sol_packet.packet_sequence_number);
+
+			lprintf(LOG_DEBUG, "SOL acked packet        : 0x%02x",
+				rsp->payload.sol_packet.acked_packet_number);
+			
+			lprintf(LOG_DEBUG, "SOL accepted char count : 0x%02x",
+				rsp->payload.sol_packet.accepted_character_count);
+			
+			lprintf(LOG_DEBUG, "SOL is nack             : %s",
+				rsp->payload.sol_packet.is_nack? "true" : "false");
+			
+			lprintf(LOG_DEBUG, "SOL xfer unavailable    : %s",
+				rsp->payload.sol_packet.transfer_unavailable? "true" : "false");
 			
-		lprintf(LOG_DEBUG+1, "<< IPMI Response Message Header");
-		lprintf(LOG_DEBUG+1, "<<   Rq Addr    : %02x",
-			rsp->payload.ipmi_response.rq_addr);
-		lprintf(LOG_DEBUG+1, "<<   NetFn      : %02x",
-			rsp->payload.ipmi_response.netfn);
-		lprintf(LOG_DEBUG+1, "<<   Rq LUN     : %01x",
-			rsp->payload.ipmi_response.rq_lun);
-		lprintf(LOG_DEBUG+1, "<<   Rs Addr    : %02x",
-			rsp->payload.ipmi_response.rs_addr);
-		lprintf(LOG_DEBUG+1, "<<   Rq Seq     : %02x",
-			rsp->payload.ipmi_response.rq_seq);
-		lprintf(LOG_DEBUG+1, "<<   Rs Lun     : %01x",
-			rsp->payload.ipmi_response.rs_lun);
-		lprintf(LOG_DEBUG+1, "<<   Command    : %02x",
-			rsp->payload.ipmi_response.cmd);
-		lprintf(LOG_DEBUG+1, "<<   Compl Code : 0x%02x",
-			rsp->ccode);
-
-		/* now see if we have outstanding entry in request list */
-		entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq,
-					      rsp->payload.ipmi_response.cmd);
-		if (entry) {
-			lprintf(LOG_DEBUG+2, "IPMI Request Match found");
-			if ((intf->target_addr != ourAddress) && bridgePossible) {
-				if ((rsp->data_len) &&
-				    (rsp->payload.ipmi_response.cmd != 0x34)) {
-					printbuf(&rsp->data[x], rsp->data_len-x,
-						 "bridge command response");
-				}
-				/* bridged command: lose extra header */
-				if (rsp->payload.ipmi_response.cmd == 0x34) {
-					if (rsp->data_len == 38) {
-						entry->req.msg.cmd = entry->req.msg.target_cmd;
-						rsp = ipmi_lan_recv_packet(intf);
-						continue;
+			lprintf(LOG_DEBUG, "SOL inactive            : %s",
+				rsp->payload.sol_packet.sol_inactive? "true" : "false");
+			
+			lprintf(LOG_DEBUG, "SOL transmit overrun    : %s",
+				rsp->payload.sol_packet.transmit_overrun? "true" : "false");
+			
+			lprintf(LOG_DEBUG, "SOL break detected      : %s",
+				rsp->payload.sol_packet.break_detected? "true" : "false");
+		}
+		else
+		{
+			/* Standard IPMI 1.5 packet */
+			rsp->session.payloadtype = IPMI_PAYLOAD_TYPE_IPMI;
+			if (intf->session->active && (rsp->session.authtype || intf->session->authtype))
+				x += 16;
+
+			rsp->session.msglen = rsp->data[x++];
+			rsp->payload.ipmi_response.rq_addr = rsp->data[x++];
+			rsp->payload.ipmi_response.netfn   = rsp->data[x] >> 2;
+			rsp->payload.ipmi_response.rq_lun  = rsp->data[x++] & 0x3;
+			x++;		/* checksum */
+			rsp->payload.ipmi_response.rs_addr = rsp->data[x++];
+			rsp->payload.ipmi_response.rq_seq  = rsp->data[x] >> 2;
+			rsp->payload.ipmi_response.rs_lun  = rsp->data[x++] & 0x3;
+			rsp->payload.ipmi_response.cmd     = rsp->data[x++];
+			rsp->ccode          = rsp->data[x++];
+			
+			if (verbose > 2)
+				printbuf(rsp->data, rsp->data_len, "ipmi message header");
+			
+			lprintf(LOG_DEBUG+1, "<< IPMI Response Session Header");
+			lprintf(LOG_DEBUG+1, "<<   Authtype   : %s",
+				val2str(rsp->session.authtype, ipmi_authtype_session_vals));
+			lprintf(LOG_DEBUG+1, "<<   Sequence   : 0x%08lx",
+				(long)rsp->session.seq);
+			lprintf(LOG_DEBUG+1, "<<   Session ID : 0x%08lx",
+				(long)rsp->session.id);
+			lprintf(LOG_DEBUG+1, "<< IPMI Response Message Header");
+			lprintf(LOG_DEBUG+1, "<<   Rq Addr    : %02x",
+				rsp->payload.ipmi_response.rq_addr);
+			lprintf(LOG_DEBUG+1, "<<   NetFn      : %02x",
+				rsp->payload.ipmi_response.netfn);
+			lprintf(LOG_DEBUG+1, "<<   Rq LUN     : %01x",
+				rsp->payload.ipmi_response.rq_lun);
+			lprintf(LOG_DEBUG+1, "<<   Rs Addr    : %02x",
+				rsp->payload.ipmi_response.rs_addr);
+			lprintf(LOG_DEBUG+1, "<<   Rq Seq     : %02x",
+				rsp->payload.ipmi_response.rq_seq);
+			lprintf(LOG_DEBUG+1, "<<   Rs Lun     : %01x",
+				rsp->payload.ipmi_response.rs_lun);
+			lprintf(LOG_DEBUG+1, "<<   Command    : %02x",
+				rsp->payload.ipmi_response.cmd);
+			lprintf(LOG_DEBUG+1, "<<   Compl Code : 0x%02x",
+				rsp->ccode);
+			
+			/* now see if we have outstanding entry in request list */
+			entry = ipmi_req_lookup_entry(rsp->payload.ipmi_response.rq_seq,
+						      rsp->payload.ipmi_response.cmd);
+			if (entry) {
+				lprintf(LOG_DEBUG+2, "IPMI Request Match found");
+#if 0
+				if ((intf->target_addr != our_address) && bridge_possible) {
+					if ((rsp->data_len) &&
+					    (rsp->payload.ipmi_response.cmd != 0x34)) {
+						printbuf(&rsp->data[x], rsp->data_len-x,
+							 "bridge command response");
 					}
-				} else {
-					//x += sizeof(rsp->payload.ipmi_response);
-					if (rsp->data[x-1] != 0)
-						lprintf(LOG_DEBUG, "WARNING: Bridged "
-							"cmd ccode = 0x%02x",
-						       rsp->data[x-1]);
-				}
-			}
-			ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq,
-					      rsp->payload.ipmi_response.cmd);
-		} else {
-			lprintf(LOG_INFO, "IPMI Request Match NOT FOUND");
-			rsp = ipmi_lan_recv_packet(intf);
-			continue;
+					/* bridged command: lose extra header */
+					if (rsp->payload.ipmi_response.cmd == 0x34) {
+						if (rsp->data_len == 38) {
+							entry->req.msg.cmd = entry->req.msg.target_cmd;
+							rsp = ipmi_lan_recv_packet(intf);
+							continue;
+						}
+					} else {
+						//x += sizeof(rsp->payload.ipmi_response);
+						if (rsp->data[x-1] != 0)
+							lprintf(LOG_DEBUG, "WARNING: Bridged "
+								"cmd ccode = 0x%02x",
+								rsp->data[x-1]);
+ 					}
+ 				}
+#endif
+				ipmi_req_remove_entry(rsp->payload.ipmi_response.rq_seq,
+						      rsp->payload.ipmi_response.cmd);
+			} else {
+				lprintf(LOG_INFO, "IPMI Request Match NOT FOUND");
+				rsp = ipmi_lan_recv_packet(intf);
+				continue;
+ 			}
 		}
 
 		break;
@@ -512,7 +582,9 @@
 
 	/* shift response data to start of array */
 	if (rsp && rsp->data_len > x) {
-		rsp->data_len -= x + 1;
+		rsp->data_len -= x;
+		if (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_IPMI)
+			rsp->data_len -= 1; /* We don't want the checksum */
 		memmove(rsp->data, rsp->data + x, rsp->data_len);
 		memset(rsp->data + rsp->data_len, 0, IPMI_BUF_SIZE - rsp->data_len);
 	}
@@ -528,9 +600,9 @@
  * |  rmcp.seq          |
  * |  rmcp.class        |
  * +--------------------+
- * |  session.authtype | 9 bytes
- * |  session.seq   |
- * |  session.id    |
+ * |  session.authtype  | 9 bytes
+ * |  session.seq       |
+ * |  session.id        |
  * +--------------------+
  * | [session.authcode] | 16 bytes (AUTHTYPE != none)
  * +--------------------+
@@ -883,6 +955,430 @@
 	return 0;
 }
 
+/*
+ * IPMI SOL Payload Format
+ * +--------------------+
+ * |  rmcp.ver          | 4 bytes
+ * |  rmcp.__reserved   |
+ * |  rmcp.seq          |
+ * |  rmcp.class        |
+ * +--------------------+
+ * |  session.authtype  | 9 bytes
+ * |  session.seq       |
+ * |  session.id        |
+ * +--------------------+
+ * |  message length    | 1 byte
+ * +--------------------+
+ * |  sol.seq           | 5 bytes
+ * |  sol.ack_seq       |
+ * |  sol.acc_count     |
+ * |  sol.control       |
+ * |  sol.__reserved    |
+ * +--------------------+
+ * | [request data]     | data_len bytes
+ * +--------------------+
+ */
+uint8_t * ipmi_lan_build_sol_msg(struct ipmi_intf * intf,
+				 struct ipmi_v2_payload * payload,
+				 int * llen)
+{
+	struct rmcp_hdr rmcp = {
+		.ver		= RMCP_VERSION_1,
+		.class		= RMCP_CLASS_IPMI,
+		.seq		= 0xff,
+	};
+	struct ipmi_session * session = intf->session;
+
+	/* msg will hold the entire message to be sent */
+	uint8_t * msg;
+
+	int len = 0;
+
+	len =	sizeof(rmcp)                                 +  // RMCP Header (4)
+		10                                           +  // IPMI Session Header
+		5                                            +  // SOL header
+		payload->payload.sol_packet.character_count;    // The actual payload
+
+	msg = malloc(len);
+	if (msg == NULL) {
+		lprintf(LOG_ERR, "ipmitool: malloc failure");
+		return;
+	}
+	memset(msg, 0, len);
+
+	/* rmcp header */
+	memcpy(msg, &rmcp, sizeof(rmcp));
+	len = sizeof(rmcp);
+
+	/* ipmi session header */
+	msg[len++] = 0; /* SOL is always authtype = NONE */
+	msg[len++] = session->in_seq & 0xff;
+	msg[len++] = (session->in_seq >> 8) & 0xff;
+	msg[len++] = (session->in_seq >> 16) & 0xff;
+	msg[len++] = (session->in_seq >> 24) & 0xff;
+
+	msg[len++] = session->session_id & 0xff;
+	msg[len++] = (session->session_id >> 8) & 0xff;
+	msg[len++] = (session->session_id >> 16) & 0xff;
+	msg[len++] = ((session->session_id >> 24) + 0x10) & 0xff; /* Add 0x10 to MSB for SOL */
+
+	msg[len++] = payload->payload.sol_packet.character_count + 5;
+	
+	/* sol header */
+	msg[len++] = payload->payload.sol_packet.packet_sequence_number;
+	msg[len++] = payload->payload.sol_packet.acked_packet_number;
+	msg[len++] = payload->payload.sol_packet.accepted_character_count;
+	msg[len]    = payload->payload.sol_packet.is_nack           ? 0x40 : 0;
+	msg[len]   |= payload->payload.sol_packet.assert_ring_wor   ? 0x20 : 0;
+	msg[len]   |= payload->payload.sol_packet.generate_break    ? 0x10 : 0;
+	msg[len]   |= payload->payload.sol_packet.deassert_cts      ? 0x08 : 0;
+	msg[len]   |= payload->payload.sol_packet.deassert_dcd_dsr  ? 0x04 : 0;
+	msg[len]   |= payload->payload.sol_packet.flush_inbound     ? 0x02 : 0;
+	msg[len++] |= payload->payload.sol_packet.flush_outbound    ? 0x01 : 0;
+
+	len++; /* On SOL there's and additional fifth byte before the data starts */
+
+	if (payload->payload.sol_packet.character_count) {
+		/* We may have data to add */
+		memcpy(msg + len,
+		       payload->payload.sol_packet.data,
+		       payload->payload.sol_packet.character_count);
+		len += payload->payload.sol_packet.character_count;		
+	}
+
+	session->in_seq++;
+	if (session->in_seq == 0)
+		session->in_seq++;
+	
+	*llen = len;
+	return msg;
+}
+
+/*
+ * is_sol_packet
+ */
+static int
+is_sol_packet(struct ipmi_rs * rsp)
+{
+	return (rsp                                                           &&
+		(rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL));
+}
+
+
+
+/*
+ * sol_response_acks_packet
+ */
+static int
+sol_response_acks_packet(struct ipmi_rs         * rsp,
+			 struct ipmi_v2_payload * payload)
+{
+	return (is_sol_packet(rsp)                                            &&
+		payload                                                       &&
+		(payload->payload_type    == IPMI_PAYLOAD_TYPE_SOL)           && 
+		(rsp->payload.sol_packet.acked_packet_number ==
+		 payload->payload.sol_packet.packet_sequence_number));
+}
+
+/*
+ * ipmi_lan_send_sol_payload
+ *
+ */
+static struct ipmi_rs *
+ipmi_lan_send_sol_payload(struct ipmi_intf * intf,
+			  struct ipmi_v2_payload * payload)
+{
+	struct ipmi_rs      * rsp = NULL;
+	uint8_t             * msg;
+	int                   len;
+	int                   try = 0;
+
+	if (intf->opened == 0 && intf->open != NULL) {
+		if (intf->open(intf) < 0)
+			return NULL;
+	}
+
+	msg = ipmi_lan_build_sol_msg(intf, payload, &len);
+	if (len <= 0 || msg == NULL) {
+		lprintf(LOG_ERR, "Invalid SOL payload packet");
+		if (msg != NULL)
+			free(msg);
+		return NULL;
+	}
+
+	lprintf(LOG_DEBUG, ">> SENDING A SOL MESSAGE\n");
+
+	for (;;) {
+		if (ipmi_lan_send_packet(intf, msg, len) < 0) {
+			try++;
+			usleep(5000);
+			continue;
+		}
+
+		/* if we are set to noanswer we do not expect response */
+		if (intf->noanswer)
+			break;
+		
+		if (payload->payload.sol_packet.packet_sequence_number == 0) {
+			/* We're just sending an ACK.  No need to retry. */
+			break;
+		}
+
+		usleep(100);
+		
+		rsp = ipmi_lan_recv_sol(intf); /* Grab the next packet */
+
+		if (sol_response_acks_packet(rsp, payload))
+			break;
+
+		else if (is_sol_packet(rsp) && rsp->data_len)
+		{
+			/*
+			 * We're still waiting for our ACK, but we more data from
+			 * the BMC
+			 */
+			intf->session->sol_data.sol_input_handler(rsp);
+		}
+
+		usleep(5000);
+		if (++try >= intf->session->retry) {
+			lprintf(LOG_DEBUG, "  No response from remote controller");
+			break;
+		}
+	}
+
+	return rsp;
+}
+
+/*
+ * is_sol_partial_ack
+ *
+ * Determine if the response is a partial ACK/NACK that indicates
+ * we need to resend part of our packet.
+ *
+ * returns the number of characters we need to resend, or
+ *         0 if this isn't an ACK or we don't need to resend anything
+ */
+static int is_sol_partial_ack(struct ipmi_v2_payload * v2_payload,
+			      struct ipmi_rs         * rsp)
+{
+	int chars_to_resend = 0;
+
+	if (v2_payload                                &&
+	    rsp                                       &&
+	    is_sol_packet(rsp)                        &&
+	    sol_response_acks_packet(rsp, v2_payload) &&
+	    (rsp->payload.sol_packet.accepted_character_count <
+	     v2_payload->payload.sol_packet.character_count))
+	{
+		if (rsp->payload.sol_packet.accepted_character_count == 0) {
+			/* We should not resend data */
+			chars_to_resend = 0;
+		}
+		else
+		{
+			chars_to_resend =
+				v2_payload->payload.sol_packet.character_count -
+				rsp->payload.sol_packet.accepted_character_count;
+		}
+	}
+
+	return chars_to_resend;
+}
+
+/*
+ * set_sol_packet_sequence_number
+ */
+static void set_sol_packet_sequence_number(struct ipmi_intf * intf,
+					   struct ipmi_v2_payload * v2_payload)
+{
+	/* Keep our sequence number sane */
+	if (intf->session->sol_data.sequence_number > 0x0F)
+		intf->session->sol_data.sequence_number = 1;
+
+	v2_payload->payload.sol_packet.packet_sequence_number =
+		intf->session->sol_data.sequence_number++;
+}
+
+/*
+ * ipmi_lan_send_sol
+ *
+ * Sends a SOL packet..  We handle partial ACK/NACKs from the BMC here.
+ *
+ * Returns a pointer to the SOL ACK we received, or
+ *         0 on failure
+ * 
+ */
+struct ipmi_rs *
+ipmi_lan_send_sol(struct ipmi_intf * intf,
+		  struct ipmi_v2_payload * v2_payload)
+{
+	struct ipmi_rs * rsp;
+	int chars_to_resend = 0;
+
+	v2_payload->payload_type   = IPMI_PAYLOAD_TYPE_SOL;
+
+	/*
+	 * Payload length is just the length of the character
+	 * data here.
+	 */
+	v2_payload->payload.sol_packet.acked_packet_number = 0; /* NA */
+
+	set_sol_packet_sequence_number(intf, v2_payload);
+	
+	v2_payload->payload.sol_packet.accepted_character_count = 0; /* NA */
+
+	rsp = ipmi_lan_send_sol_payload(intf, v2_payload);
+
+	/* Determine if we need to resend some of our data */
+	chars_to_resend = is_sol_partial_ack(v2_payload, rsp);
+
+	while (chars_to_resend)
+	{
+		/*
+		 * We first need to handle any new data we might have
+		 * received in our NACK
+		 */
+		if (rsp->data_len)
+			intf->session->sol_data.sol_input_handler(rsp);
+
+		set_sol_packet_sequence_number(intf, v2_payload);
+		
+		/* Just send the required data */
+		memmove(v2_payload->payload.sol_packet.data,
+			v2_payload->payload.sol_packet.data +
+			rsp->payload.sol_packet.accepted_character_count,
+			chars_to_resend);
+
+		v2_payload->payload.sol_packet.character_count = chars_to_resend;
+
+		rsp = ipmi_lan_send_sol_payload(intf, v2_payload);
+
+		chars_to_resend = is_sol_partial_ack(v2_payload, rsp);
+	}
+
+	return rsp;
+}
+
+/*
+ * check_sol_packet_for_new_data
+ *
+ * Determine whether the SOL packet has already been seen
+ * and whether the packet has new data for us.
+ *
+ * This function has the side effect of removing an previously
+ * seen data, and moving new data to the front.
+ *
+ * It also "Remembers" the data so we don't get repeats.
+ *
+ */
+static int
+check_sol_packet_for_new_data(struct ipmi_intf * intf,
+			      struct ipmi_rs *rsp)
+{
+	static uint8_t last_received_sequence_number = 0;
+	static uint8_t last_received_byte_count      = 0;
+	int new_data_size                            = 0;
+
+	if (rsp &&
+	    (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL))
+	    
+	{
+		uint8_t unaltered_data_len = rsp->data_len;
+		if (rsp->payload.sol_packet.packet_sequence_number ==
+		    last_received_sequence_number)
+		{
+			/*
+			 * This is the same as the last packet, but may include
+			 * extra data
+			 */
+			new_data_size = rsp->data_len - last_received_byte_count;
+			
+			if (new_data_size > 0)
+			{
+				/* We have more data to process */
+				memmove(rsp->data,
+					rsp->data +
+					rsp->data_len - new_data_size,
+					new_data_size);
+			}
+			
+			rsp->data_len = new_data_size;
+		}
+	
+		/*
+		 *Rember the data for next round
+		 */
+		if (rsp && rsp->payload.sol_packet.packet_sequence_number)
+		{
+			last_received_sequence_number =
+				rsp->payload.sol_packet.packet_sequence_number;
+			last_received_byte_count = unaltered_data_len;
+		}
+	}
+
+	return new_data_size;
+}
+
+/*
+ * ack_sol_packet
+ *
+ * Provided the specified packet looks reasonable, ACK it.
+ */
+static void
+ack_sol_packet(struct ipmi_intf * intf,
+	       struct ipmi_rs * rsp)
+{
+	if (rsp &&
+	    (rsp->session.payloadtype == IPMI_PAYLOAD_TYPE_SOL) &&
+	    (rsp->payload.sol_packet.packet_sequence_number))
+	{
+		struct ipmi_v2_payload ack;
+
+		memset(&ack, 0, sizeof(struct ipmi_v2_payload));
+
+		ack.payload_type = IPMI_PAYLOAD_TYPE_SOL;
+
+		/*
+		 * Payload length is just the length of the character
+		 * data here.
+		 */
+		ack.payload_length = 0;
+
+		/* ACK packets have sequence numbers of 0 */
+		ack.payload.sol_packet.packet_sequence_number = 0;
+
+		ack.payload.sol_packet.acked_packet_number =
+			rsp->payload.sol_packet.packet_sequence_number;
+
+		ack.payload.sol_packet.accepted_character_count = rsp->data_len;
+		
+		ipmi_lan_send_sol_payload(intf, &ack);
+	}
+}
+
+/*
+ * ipmi_recv_sol
+ *
+ * Receive a SOL packet and send an ACK in response.
+ *
+ */
+struct ipmi_rs *
+ipmi_lan_recv_sol(struct ipmi_intf * intf)
+{
+	struct ipmi_rs * rsp = ipmi_lan_poll_recv(intf);
+
+	ack_sol_packet(intf, rsp);              
+
+	/*
+	 * Remembers the data sent, and alters the data to just
+	 * include the new stuff.
+	 */
+	check_sol_packet_for_new_data(intf, rsp);
+
+	return rsp;
+}
+
 /* send a get device id command to keep session active */
 static int
 ipmi_lan_keepalive(struct ipmi_intf * intf)
@@ -1385,6 +1881,8 @@
 
 	intf->abort = 1;
 
+	intf->session->sol_data.sequence_number = 1;
+	
 	/* open port to BMC */
 	memset(&s->addr, 0, sizeof(struct sockaddr_in));
 	s->addr.sin_family = AF_INET;
--- ipmitool-1.8.8.orig/include/ipmitool/ipmi_isol.h
+++ ipmitool-1.8.8/include/ipmitool/ipmi_isol.h
@@ -41,15 +41,16 @@
 
 #define ISOL_ENABLE_PARAM		0x01
 #define ISOL_AUTHENTICATION_PARAM	0x02
-#define ISOL_ENABLE_FLAG			0x01
-#define ISOL_PRIVILEGE_LEVEL_USER	0x02
+
 #define ISOL_BAUD_RATE_PARAM		0x05
-#define ISOL_BAUD_RATE_9600		0x06
-#define ISOL_BAUD_RATE_19200		0x07
-#define ISOL_BAUD_RATE_38400		0x08
-#define ISOL_BAUD_RATE_57600		0x09
-#define ISOL_BAUD_RATE_115200		0x0A
-#define ISOL_PREFERRED_BAUD_RATE		0x07
+
+#define ISOL_PREFERRED_BAUD_RATE	0x07
+
+struct isol_config_parameters {
+	uint8_t  enabled;
+	uint8_t  privilege_level;
+	uint8_t  bit_rate;
+};
 
 int ipmi_isol_main(struct ipmi_intf *, int, char **);
 

Reply via email to