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/[email protected]/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, ¶ms))
+ 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, ¶ms))
+ 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, ¶ms))
+ 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 **);