summaryrefslogtreecommitdiff
path: root/debian/patches/20_ipmi_isol
diff options
context:
space:
mode:
Diffstat (limited to 'debian/patches/20_ipmi_isol')
-rw-r--r--debian/patches/20_ipmi_isol1852
1 files changed, 1852 insertions, 0 deletions
diff --git a/debian/patches/20_ipmi_isol b/debian/patches/20_ipmi_isol
new file mode 100644
index 0000000..ac70722
--- /dev/null
+++ b/debian/patches/20_ipmi_isol
@@ -0,0 +1,1852 @@
+## 20_ipmi_isol.dpatch by <mjj29@debian.org>
+##
+## 20_ipmi_isol, closes #412816
+diff -urN ipmitool-1.8.9.orig/include/ipmitool/ipmi_isol.h ipmitool-1.8.9/include/ipmitool/ipmi_isol.h
+--- ipmitool-1.8.9.orig/include/ipmitool/ipmi_isol.h 2007-02-22 08:38:55.000000000 +0000
++++ ipmitool-1.8.9/include/ipmitool/ipmi_isol.h 2007-12-13 10:16:57.063986495 +0000
+@@ -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 **);
+
+diff -urN ipmitool-1.8.9.orig/include/ipmitool/ipmi_isol.h.orig ipmitool-1.8.9/include/ipmitool/ipmi_isol.h.orig
+--- ipmitool-1.8.9.orig/include/ipmitool/ipmi_isol.h.orig 1970-01-01 01:00:00.000000000 +0100
++++ ipmitool-1.8.9/include/ipmitool/ipmi_isol.h.orig 2007-02-22 08:38:55.000000000 +0000
+@@ -0,0 +1,56 @@
++/*
++ * 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.
++ */
++
++#ifndef IPMI_ISOL_H
++#define IPMI_ISOL_H
++
++#include <ipmitool/ipmi.h>
++
++#define ACTIVATE_ISOL 0x01
++#define SET_ISOL_CONFIG 0x03
++#define GET_ISOL_CONFIG 0x04
++
++#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
++
++int ipmi_isol_main(struct ipmi_intf *, int, char **);
++
++#endif /* IPMI_SOL_H */
+diff -urN ipmitool-1.8.9.orig/lib/ipmi_isol.c ipmitool-1.8.9/lib/ipmi_isol.c
+--- ipmitool-1.8.9.orig/lib/ipmi_isol.c 2007-02-22 08:38:56.000000000 +0000
++++ ipmitool-1.8.9/lib/ipmi_isol.c 2007-12-13 10:16:57.063986495 +0000
+@@ -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), ipmi_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), ipmi_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;
+ }
+diff -urN ipmitool-1.8.9.orig/lib/ipmi_isol.c.orig ipmitool-1.8.9/lib/ipmi_isol.c.orig
+--- ipmitool-1.8.9.orig/lib/ipmi_isol.c.orig 1970-01-01 01:00:00.000000000 +0100
++++ ipmitool-1.8.9/lib/ipmi_isol.c.orig 2007-02-22 08:38:56.000000000 +0000
+@@ -0,0 +1,191 @@
++/*
++ * 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.
++ */
++
++#include <stdlib.h>
++#include <string.h>
++#include <stdio.h>
++
++#include <ipmitool/helper.h>
++#include <ipmitool/log.h>
++#include <ipmitool/ipmi.h>
++#include <ipmitool/ipmi_strings.h>
++#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 }
++};
++
++extern int verbose;
++
++static int ipmi_isol_setup(struct ipmi_intf * intf, char baudsetting)
++{
++ struct ipmi_rs * rsp;
++ struct ipmi_rq req;
++ unsigned char data[6];
++
++ /* TEST FOR AVAILABILITY */
++
++ 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;
++
++ rsp = intf->sendrecv(intf, &req);
++ if (rsp == NULL) {
++ lprintf(LOG_ERR, "Error in Set ISOL Config Command");
++ return -1;
++ }
++ if (rsp->ccode == 0xc1) {
++ lprintf(LOG_ERR, "IPMI v1.5 Serial Over Lan (ISOL) not supported!");
++ return -1;
++ }
++ if (rsp->ccode > 0) {
++ lprintf(LOG_ERR, "Error in Set ISOL Config Command: %s",
++ val2str(rsp->ccode, completion_code_vals));
++ return -1;
++ }
++
++ /* GET ISOL 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) {
++ lprintf(LOG_ERR, "Error in Get ISOL Config Command");
++ return -1;
++ }
++ if (rsp->ccode > 0) {
++ lprintf(LOG_ERR, "Error in Get ISOL Config Command: %s",
++ val2str(rsp->ccode, completion_code_vals));
++ return -1;
++ }
++
++ if (verbose > 1)
++ printbuf(rsp->data, rsp->data_len, "ISOL Config");
++
++ /* SET ISOL CONFIG - AUTHENTICATION */
++
++ 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;
++
++ rsp = intf->sendrecv(intf, &req);
++ if (rsp == NULL) {
++ lprintf(LOG_ERR, "Error in Set ISOL Config (Authentication) Command");
++ return -1;
++ }
++ if (rsp->ccode > 0) {
++ lprintf(LOG_ERR, "Error in Set ISOL Config (Authentication) Command: %s",
++ val2str(rsp->ccode, completion_code_vals));
++ return -1;
++ }
++
++ /* SET ISOL CONFIG - BAUD RATE */
++
++ memset(data, 0, 6);
++ data[0] = 0x00;
++ data[1] = ISOL_BAUD_RATE_PARAM;
++ data[2] = baudsetting;
++ req.msg.cmd = SET_ISOL_CONFIG;
++ req.msg.data_len = 3;
++
++ rsp = intf->sendrecv(intf, &req);
++ if (rsp == NULL) {
++ lprintf(LOG_ERR, "Error in Set ISOL Config (Baud Rate) Command");
++ return -1;
++ }
++ if (rsp->ccode > 0) {
++ lprintf(LOG_ERR, "Error in Set ISOL Config (Baud Rate) Command: %s",
++ val2str(rsp->ccode, completion_code_vals));
++ return -1;
++ }
++
++ printf("Set ISOL Baud Rate to %s\n",
++ val2str(baudsetting, ipmi_isol_baud_vals));
++
++ return 0;
++}
++
++int ipmi_isol_main(struct ipmi_intf * intf, int argc, char ** argv)
++{
++ int ret = 0;
++
++ 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 (strncmp(argv[1], "38400", 5) == 0) {
++ ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_38400);
++ }
++ else if (strncmp(argv[1], "57600", 5) == 0) {
++ ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_57600);
++ }
++ else if (strncmp(argv[1], "115200", 6) == 0) {
++ ret = ipmi_isol_setup(intf, ISOL_BAUD_RATE_115200);
++ }
++ else {
++ lprintf(LOG_ERR, "ISOL - Unsupported baud rate: %s", argv[1]);
++ ret = -1;
++ }
++ }
++ return ret;
++}
+diff -urN ipmitool-1.8.9.orig/src/plugins/lan/lan.c ipmitool-1.8.9/src/plugins/lan/lan.c
+--- ipmitool-1.8.9.orig/src/plugins/lan/lan.c 2007-02-22 08:38:57.000000000 +0000
++++ ipmitool-1.8.9/src/plugins/lan/lan.c 2007-12-13 10:16:57.063986495 +0000
+@@ -79,6 +79,11 @@
+ 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);
+ static struct ipmi_rs * ipmi_lan_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req);
+ static int ipmi_lan_send_rsp(struct ipmi_intf * intf, struct ipmi_rs * rsp);
+ static int ipmi_lan_open(struct ipmi_intf * intf);
+@@ -93,6 +98,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,
+ };
+@@ -456,80 +463,141 @@
+ memcpy(&rsp->session.id, rsp->data+x, 4);
+ x += 4;
+
+- 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 ((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");
+- }
+- /* 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;
++ 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->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, "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 ((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");
++ }
++ /* 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]);
+ }
+- } 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;
+ }
+- 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;
+@@ -537,7 +605,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);
+ }
+@@ -553,9 +623,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)
+ * +--------------------+
+@@ -910,6 +980,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)
+@@ -1411,6 +1905,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;