summaryrefslogtreecommitdiff
path: root/util/isol.c
diff options
context:
space:
mode:
authorJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-06 18:04:32 +0200
committerJörg Frings-Fürst <debian@jff-webhosting.net>2014-07-06 18:04:32 +0200
commita7f89980e5b3f4b9a74c70dbc5ffe8aabd28be28 (patch)
tree41c4deec1fdfbafd7821b4ca7a9772ac0abd92f5 /util/isol.c
Imported Upstream version 2.9.3upstream/2.9.3
Diffstat (limited to 'util/isol.c')
-rw-r--r--util/isol.c1347
1 files changed, 1347 insertions, 0 deletions
diff --git a/util/isol.c b/util/isol.c
new file mode 100644
index 0000000..381668e
--- /dev/null
+++ b/util/isol.c
@@ -0,0 +1,1347 @@
+/*
+ * isol.c (was isolconsole.c)
+ * IPMI Serial-Over-LAN console application
+ *
+ * Author: Andy Cress arcress at users.sourceforge.net
+ * Copyright (c) 2007 Intel Corporation
+ * Copyright (c) 2009 Kontron America, Inc.
+ *
+ * 10/12/06 Andy Cress - created, just a framework for now
+ * 02/08/07 Andy Cress - now working for IPMI LAN 2.0 SOL in Linux,
+ * still stdio problems in Windows
+ * 02/23/07 Andy Cress - fixed Windows stdin, still Windows output issues,
+ * need more in xlate_vt100_win().
+ * 04/06/07 Andy Cress - more vt100-to-windows translation,
+ * added -r for raw termio
+ * 04/19/07 Andy Cress - more vt100-to-windows translation,
+ * 05/08/07 Andy Cress - more logic for 1.5 SOL. Session opens but
+ * 1.5 SOL data packets are not yet working.
+ * 05/24/07 Andy Cress - Fix Enter key confusion in BIOS Setup (use CR+LF)
+ * 06/15/07 Andy Cress - More fixes to Windows translation (fUseWinCon)
+ * 08/20/07 Andy Cress - moved Windows translation to isolwin.c
+ * See ChangeLog for further changes
+ *
+ * NOTE: There are a few other options for Serial-Over-LAN console
+ * applications:
+ * ipmitool.sf.net has v2 sol console capability for Linux (BSD)
+ * Intel dpccli, a CLI console for Linux and Windows (proprietary)
+ * Intel ISM console for Windows (proprietary)
+ * Intel System Management Software (LANDesk) console, proprietary
+ * The Intel applications support both IPMI 1.5 and 2.0 SOL
+ * protocols.
+ */
+/*M*
+Copyright (c) 2007 Intel Corporation
+Copyright (c) 2009 Kontron America, 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:
+
+ a.. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ b.. Redistributions 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.
+ c.. Neither the name of Kontron nor the names of its contributors
+ may be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *M*/
+#if defined(DOS)
+#include <dos.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "getopt.h"
+int i_sol(int argc, char **argv)
+{
+ printf("IPMI SOL console is not supported under DOS.\n");
+ return(1);
+}
+#else
+
+/* All other OSs: Linux, Windows, Solaris, BSD */
+#ifdef WIN32
+#include <windows.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <winsock.h>
+#include <io.h>
+#include "getopt.h"
+#else
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <termios.h>
+#include <unistd.h>
+#if defined(HPUX)
+/* getopt is defined in stdio.h */
+#elif defined(MACOS)
+/* getopt is defined in unistd.h */
+#include <unistd.h>
+#else
+#include <getopt.h>
+#endif
+#endif
+#include <string.h>
+#include <time.h>
+#include "ipmicmd.h"
+#include "ipmilanplus.h"
+
+#define ACTIVATE_PAYLOAD 0x48
+#define DEACTIVATE_PAYLOAD 0x49
+#define PAYLOAD_TYPE_SOL 0x01
+#define SOL_SERIAL_ALERT_MASK_DEFERRED 0x04
+#define SOL_BMC_ASSERTS_CTS_MASK_TRUE 0x00
+#define SOL_BMC_ASSERTS_CTS_MASK_FALSE 0x02
+#define IPMI_PAYLOAD_TYPE_SOL 0x01
+#define AUTHTYPE_RMCP_PLUS 0x06
+#define RV_END -2
+#define CH_CR '\r' /*0x0D =='\r'*/
+#define CH_LF '\n' /*0x0A =='\n' LineFeed(Down) */
+#define CH_ESC '\033' /*0x1B == ASCII Escape */
+#define CH_CTL '\316' /*0xCE == VT100 Control */
+#define CH_DEL '\177' /*0x7F == Delete key */
+#define CH_BS '\010' /*0x08 == Backspace */
+#define CH_TAB '\011' /*0x09 == Tab */
+#define CH_UP '\013' /*0x0B == Up Arrow */
+
+/* Input data buffer size: screen size (80*24) = 1920 */
+/* IPMI_BUF_SIZE = 1024, less RMCP+IPMI hdr */
+/* IDATA_SZ=2048 was too big, used =300 thru v2.1.0 */
+#define IDATA_SZ 512
+#define IPKT_SZ 512
+#define MAX_INTEL_DATA 203 /*sol_send >= 204 bytes gives error w Intel BMC*/
+#define MAX_DELL_DATA 46 /*sol_send >= 46 bytes gives error w Dell BMC*/
+#define MAX_KONTRON_DATA 74 /*sol_send >= 75 bytes gives error w Kontron BMC*/
+#define MAX_OTHER_DATA 45 /*use a small sol_send limit of 45 by default */
+
+typedef struct {
+ int type;
+ int len;
+ char *data;
+ } SOL_RSP_PKT;
+
+extern void tty_setraw(int mode); /*from ipmicmd.c*/
+extern void tty_setnormal(int mode); /*from ipmicmd.c*/
+/* extern int tty_getattr(int *lflag,int *oflag,int *iflag); *from ipmicmd.c*/
+extern SockType lan_get_fd(void); /*from ipmilan.c*/
+extern int lan_send_sol( uchar *payload, int len, SOL_RSP_PKT *rsp);
+extern int lan_recv_sol( SOL_RSP_PKT *rsp );
+extern int lan_keepalive(int type);
+extern void lan_get_sol_data(uchar fEnc, uchar iseed, uint32 *seed);
+extern void lan_set_sol_data(uchar fEnc, uchar auth, uchar iseed,
+ int insize, int outsize);
+/* lan2 routines, from ipmilanplus.c, even if not HAVE_LANPLUS: */
+extern int lan2_get_fd(void); /*from ipmilanplus.c*/
+extern int lan2_send_sol( uchar *payload, int len, SOL_RSP_PKT *rsp);
+extern int lan2_recv_sol( SOL_RSP_PKT *rsp );
+extern void lan2_set_sol_data(int in, int out, int port, void*hnd, char esc);
+extern int lan2_keepalive(int type, SOL_RSP_PKT *rsp);
+extern void lan2_recv_handler( void *rs );
+extern long lan2_get_latency( void ); /*from ipmilanplus.c*/
+extern void lanplus_set_recvdelay( int delay ); /*lib/lanplus/lanplus.c*/
+extern int lan2_send_break( SOL_RSP_PKT *rsp );
+
+extern char fdbglog; /*see ipmilanplus.c*/
+extern char log_name[]; /*see ipmicmd.c*/
+extern int is_lan2intel(int vend, int prod); /*see oem_intel.c*/
+void dbglog( char *pattn, ... ); /*local prototype*/
+
+/*
+ * Global variables
+ */
+static char * progver = "2.93";
+static char * progname = "isol";
+static char fdebug = 0;
+static char fpicmg = 0;
+static char factivate = 0;
+static char fdeactivate = 0;
+static char fScript = 0;
+static char fTrace = 0;
+static char fprivset = 0;
+static char bDriver = 0;
+static uchar bSolVer = 0;
+static uchar bKeepAlive = 1; /*1=GetDeviceID, 2=empty SOL data*/
+static char sol_esc_len = 2; /* SOL escape seq ("~.") */
+static char sol_esc_ch = '~';
+static char sol_esc_pending = 0;
+static char sol_esc_fn[4] = {'.','b','d', '?'}; /* SOL escape functions */
+static char file_scr[80] = {""};
+static char file_trc[80] = {""};
+static char dbglog_name[40] = "isoldbg.log";
+static FILE *fp_scr = NULL;
+static FILE *fp_trc = NULL;
+static uchar ipmi_maj = 0;
+static uchar ipmi_min = 0;
+static int vend_id = 0; /* Manufacturer IANA vendor id */
+static int prod_id = 0;
+static uchar fSolEncryption = 1;
+static uchar fSolAuthentication = 1;
+static int sol_timeout = 30; /* default: send keepalive every 30 seconds */
+static time_t keepalive_start;
+static int max_bmc_data = MAX_OTHER_DATA;
+static int fgotrecv = 0;
+static int fsentok = 0;
+static uchar payload_instance = 1;
+char fUseWinCon = 1;
+uchar fCRLF = 0; /* 0=use CR, 1=use legacy CR+LF, 2=use LF (like raw) */
+uchar fRaw = 0;
+uchar bTextMode = 0;
+int sol_done = 0;
+int wait_time = 500; /*number of msec to wait*/
+int retry_time = 5; /*number of msec between retries*/
+
+static int sol_ver = 2; /*use IPMI 2.0 SOL by default*/
+static int sol_retries = 1; /*send retries for sol_input_handler*/
+static int sol_recvdelay = 0; /*if != 0, num us to delay before recv*/
+static uchar sol15_iseed = 0x01; /*initial seed count, usu 0 or 1 */
+static uint32 sol15_wseed = 0; /*32-bit seed value*/
+static long lan2_latency = 0; /*lan2 latency in msec */
+static long lan2_slow = 100; /*slow if latency > 100 msec */
+
+extern FILE *fplog; /*see ipmicmd.c*/
+#ifdef WIN32
+/* these routines are in isolwin.c */
+extern DWORD WINAPI input_thread( LPVOID lpParam);
+extern void console_open(char fdebugcmd);
+extern void console_close(void);
+extern void console_out(uchar *pdata, int len);
+extern int console_in(DWORD keydata, uchar *pdata, int len);
+extern int os_select(int infd, SockType sfd, fd_set *read_fds, fd_set *error_fds);
+extern int os_read(int fd, uchar *buf, int sz);
+extern void Ascii2KeyCode(uchar c, uchar *buf);
+#else
+
+/*======== start Linux ===============================*/
+int os_read(int fd, uchar *buf, int sz)
+{
+ int len = 0;
+ len = read(fd, buf, sz);
+ return(len);
+}
+
+int os_select(int infd, SockType sfd, fd_set *read_fds, fd_set *error_fds)
+{
+ int rv = 0;
+ struct timeval tv;
+
+ /* Linux handles both stdin & socket via select() */
+ FD_ZERO(read_fds);
+ FD_SET(infd, read_fds);
+ FD_SET(sfd, read_fds);
+ FD_ZERO(error_fds);
+ FD_SET(sfd, error_fds);
+ tv.tv_sec = 0;
+ tv.tv_usec = wait_time * 1000; /* 500000 usec, 500 msec, 0.5 sec*/
+ rv = select((int)(sfd + 1), read_fds, NULL, error_fds, &tv);
+ return rv;
+}
+
+void CheckTextMode(uchar *buffer, int sbuf)
+{
+ int c, i, j, imatch;
+ uchar pattern[5] = {CH_ESC,'[','0','0','m'}; /*was [0m */
+ int spattern = 5;
+
+ /* if CH_ESC,"[0m", TextMode change */
+ j = 0;
+ imatch = 0;
+ for (j = 0; j < sbuf; j++) {
+ if ((sbuf - j) < spattern && imatch == 0) break;
+ c = buffer[j];
+ if (c == pattern[imatch]) {
+ imatch++;
+ } else if (pattern[imatch] == '?') { /*wildcard char*/
+ imatch++;
+ } else if (pattern[imatch] == '0' && (c>='0' && c <='9')) { /*numeric*/
+ imatch++;
+ } else {
+ if (imatch > 0) {
+ if (j > 0) j--; /* try again with the first match char */
+ imatch = 0;
+ }
+ }
+ if (imatch == spattern) { /*match found*/
+ char mystr[5];
+ i = (j+1) - imatch; /*buffer[i] is the match */
+ // bTextMode = buffer[i+2] & 0x0f; /* usu 0 or 1 */
+ mystr[0] = buffer[i+2];
+ mystr[1] = buffer[i+3];
+ mystr[2] = 0;
+ bTextMode = atob(mystr);
+ dbglog("TextMode changed to %d\n",bTextMode);
+ }
+ else if (imatch > spattern) break;
+ }
+ return;
+}
+
+/*======== end Linux =================================*/
+#endif
+
+void printm( char *pattn, ... )
+{ /* all sol error/info messages go to log or stderr by default */
+ va_list arglist;
+ FILE *fp;
+ if (fdbglog && fplog != NULL) fp = fplog;
+ else fp = stderr;
+ va_start(arglist, pattn);
+ vfprintf(fp, pattn, arglist);
+ va_end(arglist);
+ fprintf(fp,"\r\n");
+}
+
+void dbglog( char *pattn, ... )
+{
+ va_list arglist;
+ int fadd = 0;
+ int l;
+#ifdef WIN32
+ FILE *fp;
+ // char _pattn[80];
+ if (fdebug == 0 && fdbglog == 0) return;
+ if (fdbglog && fplog != NULL) fp = fplog;
+ else fp = stderr;
+ l = (int)strlen(pattn);
+ if ((l >= 1) && (pattn[l-1] == '\n')) { /*check EOL chars*/
+ if (pattn[l-2] == '\r') fadd = 0;
+ else fadd = 0; /* '\n' only */
+ // else _pattn[l-1] = 0; /*truncate, add \r\n below, dangerous*/
+ } else fadd = 1; /*no line-end, so add it below*/
+ va_start(arglist, pattn);
+ vfprintf(fp, pattn, arglist);
+ va_end(arglist);
+ if (fadd) fprintf(fp,"\r\n");
+#else
+ char logtmp[LOG_MSG_LENGTH];
+ if (fdebug == 0 && fdbglog == 0) return;
+ l = strlen(pattn);
+ if ((l >= 1) && (pattn[l-1] == '\n')) fadd = 0;
+ else fadd = 1;
+ va_start( arglist, pattn );
+ vsnprintf(logtmp, LOG_MSG_LENGTH, pattn, arglist);
+ va_end( arglist );
+ if (fadd) strcat(logtmp,"\n");
+ if (fdbglog) print_log(logtmp);
+ else if (fdebug) fprintf( stderr, "%s", logtmp);
+#endif
+}
+
+void dbg_dump(char *tag, uchar *pdata, int len, int fascii)
+{
+ FILE *fp = NULL;
+ if (fdebug == 0 && fdbglog == 0) return;
+ if (fdbglog && (fplog != NULL)) fp = fplog;
+ dump_log(fp,tag,pdata,len,(char)fascii); /*uses fplog or fpdbg */
+}
+
+#ifdef OLD
+static void set_latency( struct timeval *t1, struct timeval *t2, long *latency)
+{
+ long nsec;
+ nsec = t2->tv_sec - t1->tv_sec;
+ if ((ulong)(nsec) > 1) nsec = 1;
+ *latency = nsec*1000 + (t2->tv_usec - t1->tv_usec)/1000;
+}
+#endif
+
+static int sol_send(uchar *buf, int len, SOL_RSP_PKT *rsp)
+{
+ int rv = 0;
+ if (bSolVer == 1) {
+ rv = lan_send_sol(buf, len, rsp);
+ } else {
+ rv = lan2_send_sol(buf, len, rsp);
+ if (rv == 0x01) rv = 0;
+ /* else bit-mapped error, 0x02 = need retry*/
+ }
+ return(rv);
+}
+
+static int sol_recv( SOL_RSP_PKT *rsp)
+{
+ int rv = 0;
+ if (bSolVer == 1) {
+ rv = lan_recv_sol( rsp );
+ } else
+ rv = lan2_recv_sol( rsp );
+ return(rv);
+}
+
+static SockType sol_get_fd(void)
+{
+ SockType fd = 0;
+ if (bSolVer == 1) {
+ fd = lan_get_fd();
+ } else
+ fd = lan2_get_fd();
+ return(fd);
+}
+
+/*
+ * sol_output_handler
+ * This routine is called both in isol.c and ipmilanplus.c/lan2_recv_handler
+ * whenever SOL data is received from the BMC for output to the console.
+ */
+void sol_output_handler(SOL_RSP_PKT *rsp)
+{
+ if (rsp == NULL) return;
+ if (rsp->type == PAYLOAD_TYPE_SOL)
+ {
+#ifdef WIN32
+ fgotrecv = 1;
+ if (fdbglog) dbg_dump("sol_output(console_out)",rsp->data,rsp->len,1);
+ console_out(rsp->data,rsp->len);
+#else
+ uchar *pdata;
+ int len;
+ int i;
+ uchar c;
+ // int mode;
+
+ fgotrecv = 1;
+ pdata = rsp->data;
+ len = rsp->len;
+ if (fdbglog) {
+ // dbglog("sol_output: len = %d\n",len);
+ dbg_dump("sol_output",pdata,len,1); /*like printlog*/
+ }
+ CheckTextMode(pdata,len);
+ for (i = 0; i < len; i++) {
+ c = pdata[i];
+ /* do special character handling here?
+ * CH_CR, 0xb0-0xb3, 0xdb */
+ putc(c, stdout);
+ }
+ fflush(stdout);
+#endif
+ if (fTrace) { fwrite(rsp->data,1,rsp->len,fp_trc); fflush(fp_trc); }
+ } else {
+ dbglog("sol_output: rsp.type=%x, rsp.len=%d\n", rsp->type, rsp->len);
+ }
+}
+
+static int sol_keepalive(int type)
+{
+ int rv = 0;
+ time_t end;
+
+ time(&end);
+ if (sol_timeout == 0) return(rv);
+ if ((end - keepalive_start) > sol_timeout) {
+ dbglog("sol_keepalive: timeout, lan%d\n",bSolVer); /*++++*/
+ if (bSolVer == 1) {
+ rv = lan_keepalive(type);
+ } else {
+ SOL_RSP_PKT rs;
+ rv = lan2_keepalive(type, &rs);
+ if (rv >= 0 && rs.len != 0) { /*handle any rsp data*/
+ if (rs.type == IPMI_PAYLOAD_TYPE_SOL) {
+ dbglog("keepalive: output_handler(%d)\n",rs.len);
+ sol_output_handler(&rs);
+ }
+ }
+ }
+ time(&keepalive_start); /*time in seconds*/
+ dbglog("sol_keepalive sent, rv = %d\n",rv);
+ flush_log();
+ }
+ return(rv);
+}
+
+static void sol_keepalive_reset(void)
+{
+ /* not idle, so reset the keepalive timer */
+ time(&keepalive_start); /*time in seconds*/
+}
+
+static int send_break( void )
+{
+ SOL_RSP_PKT rs;
+ int rv;
+
+ if (sol_ver == 1) return LAN_ERR_NOTSUPPORT;
+ rv = lan2_send_break(&rs);
+ dbglog("lan2_send_break rv=%d rs.len=%d\n", rv,rs.len);
+ return(rv);
+}
+
+static int send_ctlaltdel( void )
+{
+ uchar buf[8];
+ int rv, rlen;
+
+// #define TESTALT 1
+#ifdef TESTALT
+ SOL_RSP_PKT rs;
+ /* This doesn't work. Fix it later. */
+ /* Problem is that keycodes must be translated for serial console */
+ /* CtrlL = 0x0706, AltL = 0x0703, Del = 0x007f, MetaDel = 0x087f
+ * Del = keycode 0x53
+ * 1b 53 33 7e = alt+del
+ * 1b 4f 48 = ctl-alt-home
+ * 1b 4f 46 = ctl-alt-end
+ * 1b 53 33 3b 38 7e = ctl+alt+shift+del
+ * 1b 53 33 3b 33 7e = ctl+alt+ins
+ * 1b 53 33 3b 35 7e = ctl+alt+ins
+ * 1b 53 35 3b 37 7e = ctl+alt+pgup
+ * 1b 53 36 3b 37 7e = ctl+alt+pgdn
+ * Need to find a sequence at serial console that does a reboot
+ * when the command prompt is not up.
+ */
+ buf[0] = 0x1b;
+ buf[1] = 0x53;
+ buf[2] = 0x33;
+ buf[3] = 0x3b;
+ buf[4] = 0x36;
+ buf[5] = 0x7e;
+ rv = sol_send(buf, 6, &rs);
+ rlen = rs.len;
+#else
+ uchar rbuf[16];
+ uchar cc;
+
+ rlen = sizeof(rbuf);
+ buf[0] = 5; /*soft reset via ACPI */
+ rv = ipmi_cmdraw(CHASSIS_CTL,NETFN_CHAS,BMC_SA, PUBLIC_BUS, BMC_LUN,
+ buf,1,rbuf,&rlen,&cc,fdebug);
+ if (rv == 0 && cc != 0) rv = cc;
+#endif
+ dbglog("send_ctlaltdel rv=%d rlen=%d\n", rv,rlen);
+ return(rv);
+}
+
+static void show_esc_help( void )
+{
+ printf("%c?\r\n",sol_esc_ch);
+ printf("Supported SOL escape sequences:\r\n");
+ printf("\t%c. - terminate connection\r\n",sol_esc_ch);
+ printf("\t%cB - send break\r\n",sol_esc_ch);
+ printf("\t%cD - send ctl-alt-delete (chassis soft reset)\r\n",sol_esc_ch);
+ printf("\t%c? - show this help message\r\n",sol_esc_ch);
+ printf("\t%c%c - send the escape character by typing it twice\r\n",
+ sol_esc_ch, sol_esc_ch);
+}
+
+int sol_input_handler( uchar *input, int ilen)
+{
+ int rv = 0;
+ uchar payload[IPKT_SZ];
+ SOL_RSP_PKT rs;
+ int i, length, t;
+ static uchar lastc = 0;
+ char rvend = 0;
+ char fdoinput = 1;
+ uchar c;
+#ifdef WIN32
+ uchar c1, c2, c3;
+ unsigned long dwKeyCode;
+#endif
+
+ memset(&payload, 0, sizeof(payload));
+ length = 0;
+ rs.len = 0;
+
+ if ((fdebug > 2) && (ilen > 4))
+ dbg_dump("sol_input dump:",input,ilen,1);
+ // i = 0;
+ for (i = 0; i < ilen; i++)
+ {
+ if (fdebug > 2)
+ dbglog("sol_input keys[%d]: %02x %02x %02x %02x, ilen=%d\n",
+ i, input[i], input[i+1], input[i+2], input[i+3], ilen);
+ /* look for console escape sequences (~) */
+
+ if (sol_esc_pending) {
+ sol_esc_pending = 0;
+ /* next char in 2-char esc seq */
+#ifdef WIN32
+ if ( ((input[i+3] & 0x01) == 0) || /* h.o byte, if not keydown */
+ (i < 0)) { /* skip h.o. bytes in dwChar for windows */
+ fdoinput = 0; /*skip this input*/
+ sol_esc_pending = 1; /*if here, esc was pending*/
+ if (fdebug > 2)
+ dbglog("sol_input: skip, %02x!=X1 for i=%d\n",input[i+3],i);
+ } else
+#endif
+ switch(input[i]) {
+ case '.':
+ dbglog("sol_input RV_END (%02x %02x)\n",sol_esc_ch,input[i]);
+ rvend = 1;
+ fdoinput = 0;
+ break;
+ case 'b':
+ case 'B':
+ rv = send_break();
+ fdoinput = 0;
+ break;
+ case 'd':
+ case 'D':
+ rv = send_ctlaltdel();
+ fdoinput = 0;
+ break;
+ case '?':
+ show_esc_help();
+ fdoinput = 0;
+ break;
+ default:
+ /* includes entering "~~" to output '~' */
+ dbglog("sol_input sol_esc no match (%02x %02x/%c%c)\n",
+ sol_esc_ch,input[i], sol_esc_ch,input[i]);
+ fdoinput = 1;
+ break;
+ }
+ } else if (input[i] == sol_esc_ch) {
+ /* start of new sol_esc seq */
+ if (fdebug > 2)
+ dbglog("sol_input esc_pending (%02x %02x)\n",input[i],input[i+1]);
+ if ((sol_esc_len == 1) ||
+ ((ilen > (i+1)) && (input[i+1] == '.')) ) { /*then exit now*/
+ dbglog("sol_input RV_END (%02x %02x)\n",input[i],input[i+1]);
+ rvend = 1;
+ }
+ fdoinput = 0;
+ sol_esc_pending = 1;
+ }
+ else fdoinput = 1; /*send as normal input*/
+
+ if (fdoinput)
+ {
+ c = input[i];
+#ifdef WIN32
+ c1 = input[i+1];
+ c2 = input[i+2];
+ c3 = input[i+3];
+
+ dwKeyCode = (c << 24) | (c1 << 16) | (c2 << 8) | c3;
+ dbglog("sol_input[%d]: KeyCode=0x%08X, '%c'\n",
+ i, dwKeyCode, (0x20 <= c && c <= 0x7E ? c : '.') );
+
+ /* check Windows input to see if it should be sent */
+ t = console_in(dwKeyCode, &payload[length], sizeof(payload) - length);
+ if (t > 0) length += t;
+ lastc = c;
+#else
+ /*
+ * Linux end-of-line handling with fCRLF:
+ * (0) CR, (1) CR+LF, (2) LF
+ * Note that the CR+LF logic works for BIOS, but causes
+ * extra returns after Linux commands. Using -l sets CR+LF.
+ * Using bTextMode detects if bg color, as in BIOS Setup
+ * or other apps that need CR+LF.
+ *
+ * If stty has '-onlcr', then LF (fCRLF=2) is fine, but
+ * if stty has 'onlcr', LF causes two output lines,
+ * so CR is the default (fCRLF=0), which works for
+ * either 'onlcr' or '-onlcr'.
+ * Using -r (fRaw) has the same effect as LF (fCRLF=2).
+ */
+ if (c == CH_LF && !fRaw) { // input=enter/LF and not raw (-r)
+ if ((fCRLF == 1) || (bTextMode > 40)) { /*-l option or bg color*/
+ /*CR+LF: insert CR here, LF below*/
+ payload[length++] = CH_CR;
+ }
+ else if (fCRLF == 2) ; /*LF: same as raw, use CH_LF*/
+ else c = CH_CR; /* CR: switch LF to CR */
+ }
+ /* copy other data to payload */
+ payload[length++] = c;
+ lastc = c;
+ if (c == CH_CR || c == CH_LF)
+ dbglog("sol_input[%d] payload: %02x %02x, bTextMode=%d\n",
+ i,payload[0],payload[1],bTextMode);
+#endif
+ if (length >= max_bmc_data) { /*overflow, truncate*/
+ dbglog("sol_send: ilen(%d) >= BMC max data(%d), truncated\n",
+ ilen,max_bmc_data);
+ break;
+ } else if (length >= sizeof(payload)) { /*overflow, truncate*/
+ dbglog("sol_send: ilen(%d) >= buffer size(%d), truncated\n",
+ ilen,sizeof(payload));
+ break;
+ }
+ } /*endif fdoinput*/
+#ifdef WIN32
+ i += 3; /*increment to next dwKeyCode (3+1)*/
+#endif
+ } /*end-for input[ilen] */
+
+ if (length > 0) {
+ /* Send the SOL payload */
+ for (t = 0; t < sol_retries; t++)
+ {
+ if (t > 0)
+ os_usleep(0,(retry_time * 1000)); /*wait between retries 5000 us*/
+ rv = sol_send(payload, length, &rs);
+ dbglog("sol_send(%d,%d) rv=%d rs.len=%d\n", t,length,rv,rs.len);
+ if (rv >= 0) { /* rv ok */
+ if (rs.len != 0) { /* have some rsp data, so handle it */
+ if (rs.type == IPMI_PAYLOAD_TYPE_SOL) {
+ dbglog("output: handler(%d)\n",rs.len);
+ sol_output_handler(&rs);
+ } else {
+ dbglog("WARNING: after sol_send, rs.type=%d, not SOL\n",rs.type);
+ }
+ } /*endif have rsp data*/
+ rv = 0; /*recvd something, so dont retry */
+ }
+ if (rv == 0) break;
+ /* else retry again if rv < 0 or rv == 0x02 */
+ } /*end for loop*/
+ if (rv < 0) rv = LAN_ERR_DROPPED;
+ }
+ if (rvend) rv = RV_END;
+ return(rv);
+}
+
+static int send_activate_15sol(void)
+{
+ int rv = 0;
+ uchar actcmd;
+ uchar netfn;
+ uchar ibuf[64];
+ uchar rbuf[64];
+ int rlen;
+ uchar ilen, cc;
+
+ lan_get_sol_data(fSolEncryption,sol15_iseed,&sol15_wseed);
+ actcmd = (uchar)(ACTIVATE_SOL1 & 0x00ff);
+ netfn = NETFN_SOL;
+ if (fSolEncryption) ibuf[0] = 0x11; /* use encryption, activate SOL */
+ else ibuf[0] = 0x01; /*no encryptionn, no serial alerts, activate SOL */
+ memcpy(&ibuf[1],&sol15_wseed,4); /*32-bit seed*/
+ ilen = 5;
+ rlen = sizeof(rbuf);
+ rv = ipmi_cmdraw(actcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN,
+ ibuf,ilen,rbuf,&rlen,&cc,fdebug);
+ if (rv == 0 && cc != 0) rv = cc;
+ /* switch(cc) { case 0x80: SOL already active on another session
+ * case 0x81: SOL disabled
+ * case 0x82: SOL activation limit reached }
+ */
+ if (rv == 0) { /*success*/
+ dbg_dump("sol 15 act_resp",rbuf,rlen,0);
+ /* sol 15 act_resp (len=4): 0000: 00 01 64 64 */
+ /* 00=auth, 01=seed_cnt, 64=in_payload_sz, 64=out_payload_sz */
+ lan_set_sol_data(fSolEncryption,rbuf[0],rbuf[1], rbuf[2], rbuf[3]);
+ }
+ return(rv);
+}
+
+static int send_deactivate_15sol(void)
+{
+ int rv = -1;
+
+ uchar actcmd;
+ uchar netfn;
+ uchar ibuf[64];
+ uchar rbuf[64];
+ int rlen;
+ uchar ilen, cc;
+
+ /* SOL for IPMI 1.5 does not have an explicit deactivate, so
+ * use an activate with data0 = 00.
+ */
+ actcmd = (uchar)(ACTIVATE_SOL1 & 0x00ff);
+ netfn = NETFN_SOL;
+ if (fSolEncryption) ibuf[0] = 0x10; /* deactivate, use encryption */
+ else ibuf[0] = 0x00; /*deactivate*/
+ memcpy(&ibuf[1],&sol15_wseed,4); /*32-bit seed*/
+ ilen = 5;
+ rlen = sizeof(rbuf);
+ rv = ipmi_cmdraw(actcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN,
+ ibuf,ilen,rbuf,&rlen,&cc,fdebug);
+ if (rv == 0 && cc != 0) rv = cc;
+ dbg_dump("sol 15 deact_resp",rbuf,rlen,0); /* 80 00 32 ff */
+ return(rv);
+}
+
+int send_activate_sol(uchar verSOL)
+{
+ int rv = 0;
+ int in_payload_size, out_payload_size, udp_port;
+ uchar actcmd;
+ uchar netfn;
+ uchar ibuf[64];
+ uchar rbuf[64];
+ int rlen;
+ uchar ilen, cc;
+
+ sol_ver = verSOL;
+ /* activate SOL = 0x01, get SOL status = 0x05 */
+ if (verSOL == 1) {
+ rv = send_activate_15sol();
+ return(rv);
+ } else { /* use IPMI 2.0 method */
+ actcmd = ACTIVATE_PAYLOAD;
+ netfn = NETFN_APP;
+ ibuf[0] = PAYLOAD_TYPE_SOL;
+ ibuf[1] = payload_instance; /* payload instance */
+ ibuf[2] = SOL_SERIAL_ALERT_MASK_DEFERRED;
+ if (fSolEncryption) ibuf[2] |= 0x80;
+ if (fSolAuthentication) ibuf[2] |= 0x40;
+ if (vend_id == VENDOR_INTEL)
+ ibuf[2] |= SOL_BMC_ASSERTS_CTS_MASK_TRUE;
+ else ibuf[2] |= SOL_BMC_ASSERTS_CTS_MASK_FALSE;
+ ibuf[3] = 0;
+ ibuf[4] = 0;
+ ibuf[5] = 0;
+ ilen = 6;
+ }
+ rlen = sizeof(rbuf);
+ rv = ipmi_cmdraw(actcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN,
+ ibuf,ilen,rbuf,&rlen,&cc,fdebug);
+ dbg_dump("sol act_cmd",ibuf,ilen,0);
+ dbglog("send_activate v2(%x,%x) rv = %d cc = %x\n",actcmd,netfn,rv,cc);
+ if (rv >= 0) {
+ rv = cc;
+ switch(cc) {
+ case 0x00:
+ if (rlen != 12) {
+ printm("Unexpected SOL response data received, len=%d\n",rlen);
+ rv = -1;
+ }
+ break;
+ case 0x80:
+ printm("SOL payload already active on another session\n");
+ break;
+ case 0x81:
+ printm("SOL payload disabled\n");
+ break;
+ case 0x82:
+ printm("SOL payload activation limit reached\n");
+ break;
+ case 0x83:
+ printm("Cannot activate SOL payload with encryption\n");
+ break;
+ case 0x84:
+ printm("Cannot activate SOL payload without encryption\n");
+ break;
+ default:
+ printm("Cannot activate SOL, ccode = 0x%02x\n",cc);
+ break;
+ }
+ }
+ if (rv == 0) { /* success, use the response data */
+ /* only here if response data is from IPMI 2.0 method */
+ dbg_dump("sol act_resp",rbuf,rlen,0);
+ in_payload_size = rbuf[4] + (rbuf[5] << 8);
+ out_payload_size = rbuf[6] + (rbuf[7] << 8);
+ udp_port = rbuf[8] + (rbuf[9] << 8);
+ dbglog("activate ok, in=%d out=%d port=%d\n",
+ in_payload_size, out_payload_size, udp_port);
+ if (bSolVer == 2)
+ lan2_set_sol_data(in_payload_size, out_payload_size, udp_port,
+ (void *)lan2_recv_handler, sol_esc_ch);
+ }
+ return(rv);
+}
+
+int send_deactivate_sol(uchar verSOL)
+{
+ int rv = 0;
+ uchar deactcmd;
+ uchar netfn;
+ uchar ibuf[64];
+ uchar rbuf[64];
+ int rlen;
+ uchar ilen, cc;
+
+ if (verSOL == 1) {
+ return(send_deactivate_15sol());
+ } else { /* use IPMI 2.0 method */
+ deactcmd = DEACTIVATE_PAYLOAD;
+ netfn = NETFN_APP;
+ ibuf[0] = PAYLOAD_TYPE_SOL; /* payload type */
+ ibuf[1] = payload_instance; /* payload instance */
+ ibuf[2] = 0;
+ ibuf[3] = 0;
+ ibuf[4] = 0;
+ ibuf[5] = 0;
+ ilen = 6;
+ }
+ rlen = sizeof(rbuf);
+ rv = ipmi_cmdraw(deactcmd,netfn,BMC_SA, PUBLIC_BUS, BMC_LUN,
+ ibuf,ilen,rbuf,&rlen,&cc,fdebug);
+ dbglog("sol deactivate rv = %d, cc = %x\n",rv,cc);
+ if (rv == 0 && cc != 0) rv = cc;
+ return(rv);
+}
+
+int sol_data_loop( void )
+{
+ int istdin;
+ int rv = 0;
+ uchar ibuf[IDATA_SZ];
+ uchar cbuf[IDATA_SZ];
+ int szibuf, szcbuf;
+ SockType fd;
+ int len;
+ fd_set read_fds;
+ fd_set error_fds;
+ static uchar lastc = 0;
+ int c;
+#ifdef WIN32
+ int c1;
+ time_t ltime1 = 0;
+ time_t ltime2 = 0;
+ HANDLE thnd;
+ istdin = 0;
+#else
+ long ltime1 = 0;
+ long ltime2 = 0;
+ istdin = fileno(stdin);
+#endif
+
+ /*
+ * OK, now loop and listen to
+ * stdin for user input
+ * interface fd for incoming SOL data
+ */
+ /* sizeof(ibuf/cbuf)=IDATA_SZ(512), max_bmc_data=203 for sol data */
+ szibuf = max_bmc_data;
+ szcbuf = max_bmc_data;
+ fd = sol_get_fd();
+ if (fScript) { /* open file_scr */
+ fp_scr = fopen(file_scr,"r");
+ if (fp_scr == NULL) {
+ printm("Cannot open %s, ignoring\n",file_scr);
+ fScript = 0;
+ }
+ }
+ if (fTrace) { /* open file_trc for writing */
+ fp_trc = fopen(file_trc,"a");
+ if (fp_trc == NULL) {
+ printm("Cannot open %s, ignoring\n",file_trc);
+ fTrace = 0;
+ }
+ }
+
+ dbglog("stdin = %d, intf->fd = %d\n",istdin,fd);
+ if (sol_esc_len == 1)
+ printf("[SOL session is running, use '%c' to end session.]\n",sol_esc_ch);
+ else
+ printf("[SOL session is running, use '%c.' to end, '%c?' for help.]\n",
+ sol_esc_ch, sol_esc_ch);
+
+ tty_setraw(2);
+ sol_keepalive_reset();
+#ifdef WIN32
+ thnd = CreateThread(NULL, 0, &input_thread, NULL, 0, NULL);
+ if (thnd == NULL) {
+ printm("CreateThread error, aborting\n");
+ rv = -1;
+ sol_done = 1;
+ }
+ console_open(fdebug);
+#else
+ if (bSolVer == 1) { /* jump start the session v1.5 data */
+ ibuf[0] = 0x1b; /*escape*/
+ ibuf[1] = '{';
+ rv = sol_input_handler(ibuf,2);
+ }
+#endif
+ if (fdbglog) time((time_t *)&ltime1);
+
+ while (sol_done == 0)
+ {
+ if (bKeepAlive > 0) { /* send KeepAlive if needed */
+ rv = sol_keepalive(bKeepAlive);
+ /* if keepalive error, try to keep going anyway */
+ }
+ if (fdebug > 2) dbglog("os_select(%d,%d) called\n",istdin,fd);
+
+ rv = os_select(istdin,fd, &read_fds, &error_fds);
+ if (rv < 0) {
+ dbglog("os_select(%d,%d) error %d\n",istdin,fd,rv);
+ perror("select");
+ sol_done = 1;
+ } else if (rv > 0) {
+ if (fdbglog) {
+ time((time_t *)&ltime2);
+ dbglog("select rv = %d sockfd=%x stdin=%x time=%ld\n", rv,
+ FD_ISSET(fd, &read_fds),FD_ISSET(istdin, &read_fds),
+ (ltime2 - ltime1));
+ }
+
+ if (FD_ISSET(fd, &read_fds)) {
+ SOL_RSP_PKT rs;
+ rs.len = 0;
+ /* receive output from BMC SOL */
+ rv = sol_recv(&rs);
+#ifdef WIN32
+ /* Windows sometimes gets rv = -1 here */
+ if (rv == -1) rv = -(WSAGetLastError());
+#endif
+ dbglog("output: recv rv = %d, len = %d\n",rv,rs.len);
+ if (rv < 0) {
+ dbglog("Error %d reading SOL socket\n",rv);
+ printm("Error %d reading SOL socket\n",rv);
+ sol_done = 1;
+ } else {
+ /*sol_output_handler sets fgotrecv*/
+ sol_output_handler(&rs);
+ sol_keepalive_reset();
+ /* go back to select until there is no more socket data */
+ continue;
+ }
+ } /*endif fd*/
+
+ if (FD_ISSET(fd, &error_fds)) {
+ dbglog("Error selecting SOL socket\n",rv);
+ } /*endif fd*/
+
+ if (FD_ISSET(istdin, &read_fds)) {
+ /* input from stdin (user) if not WIN32 */
+ memset(ibuf,0,szibuf);
+ len = os_read(istdin, ibuf, szibuf);
+ dbglog("stdin: read len=%d, %02x %02x %02x %02x\n",
+ len,ibuf[0],ibuf[1],ibuf[2],ibuf[3]);
+ if (len <= 0) {
+ dbglog("Error %d reading stdin\n",len);
+ printm("Error %d reading stdin\n",len);
+ sol_done = 1;
+ } else {
+ rv = sol_input_handler(ibuf,len);
+ dbglog("sol_input: handler rv = %d\n",rv);
+ if (rv < 0) {
+ sol_done = 1;
+ if (rv == RV_END) {
+ dbglog("sol_data RV_END\n");
+ printf("\n%s exit via user input \n",progname);
+ } /* else drop through to show_outcomes */
+ }
+ else sol_keepalive_reset();
+ }
+ } /*endif stdin*/
+
+ } /*endif select rv > 0 */
+ else if (fScript) { /*rv == 0*/
+ /* if we sent a script line, but no receive yet, keep waiting*/
+ if (fsentok && (fgotrecv == 0)) {
+ dbglog("sol_data script sentok, but no recv\n");
+ // continue;
+ }
+ fsentok = 0;
+ /* read input stream from script file */
+ memset(cbuf,0,szcbuf);
+ /* read one line at a time */
+ rv = 0;
+ for (len = 0; len < szcbuf; ) {
+ c = fgetc(fp_scr);
+ if (c == EOF) { rv = -2; break; }
+#ifdef WIN32
+ if ((c == '\n') && (lastc != '\r')) c1 = '\r'; /*Enter*/
+ else c1 = c;
+ Ascii2KeyCode((uchar)c1,&cbuf[len]);
+ len += 4;
+#else
+ cbuf[len++] = c;
+#endif
+ if (c == '\n') break;
+ lastc = (uchar)c;
+ }
+ dbglog("script: read len=%d, %02x %02x %02x\n",
+ len,cbuf[0],cbuf[1],cbuf[2]);
+ if (rv != 0 || len == 0) {
+ dbglog("Stop reading file %s, rv=%d\n",file_scr,rv);
+ fclose(fp_scr);
+ fScript = 0;
+ } else {
+ /* TODO: add processing for some wait/sleep/prompt commands */
+ rv = sol_input_handler(cbuf,len);
+ dbglog("input: handler rv = %d\n",rv);
+ if (rv < 0) {
+ sol_done = 1;
+ if (rv == RV_END) {
+ dbglog("sol_data RV_END\n");
+ printf("\n%s exit via user input \n",progname);
+ } else printf("Error %d processing input\n",rv);
+ } else {
+ fsentok = 1; /*sent a script line successfully*/
+ fgotrecv = 0; /*need to wait for recv*/
+ }
+ }
+ } /*endif fScript*/
+ } /*end while*/
+ if (rv == RV_END) rv = 0;
+#ifdef WIN32
+ os_usleep(0,5000); /*wait 5 ms for thread to close itself*/
+ CloseHandle(thnd);
+ console_close();
+#endif
+ tty_setnormal(2);
+ if (fScript) fclose(fp_scr); /* close file_scr */
+ if (fTrace) fclose(fp_trc); /* close file_trc */
+ return(rv);
+}
+
+static void show_usage(void)
+{
+ printf("Usage: %s [-acdeiolnrsvxz -NUPREFTVY]\n", progname);
+ printf(" where -a activate SOL console session\n");
+ printf(" -d deactivate SOL console session\n");
+ printf(" -c'^' set escape Char to '^', default='~'\n");
+ printf(" -e Encryption off for SOL session\n");
+ printf(" -i file Input script file\n");
+ printf(" -o file Output trace file\n");
+ printf(" -l Legacy mode for BIOS/DOS CR+LF\n");
+ printf(" -n 1 Payload instance Number, default=1\n");
+ printf(" -r Raw termio, no VT-ANSI translation\n");
+ printf(" -s NNN Slow link delay, default=100usec\n");
+#ifdef NOT_DOCUMENTED
+ printf(" -t N SOL send timeout reTries, default=1\n");
+ printf(" -u N Wait time in msec for tuning, default=500\n");
+#endif
+#ifdef WIN32
+ printf(" -w do not use Windows Console buffer, use stdio\n");
+#endif
+ printf(" -v debug log filename (default=isoldbg.log)\n");
+ printf(" -x show eXtra debug messages in debug log\n");
+ printf(" -z show even more debug messages\n");
+ print_lan_opt_usage();
+}
+
+#ifdef METACOMMAND
+int i_sol(int argc, char **argv)
+#else
+#ifdef WIN32
+int __cdecl
+#else
+int
+#endif
+main(int argc, char **argv)
+#endif
+{
+ int ret = 0;
+ int i;
+ uchar devrec[16];
+ uchar bmcver[2];
+ int c;
+
+ printf("%s ver %s\n", progname,progver);
+
+ parse_lan_options('V',"2",0); /*default to user priv*/
+
+ while ( (c = getopt( argc, argv,"ac:dei:k:ln:o:rs:t:u:wv:xzEF:J:N:P:R:T:U:V:YZ:?")) != EOF )
+ switch(c) {
+ case 'a': factivate = 1; break; /*activate*/
+ case 'd': fdeactivate = 1; break; /*deactivate*/
+ case 'c': /* escape char */
+ if (strncmp(optarg,"0x",2) == 0)
+ sol_esc_ch = htoi(&optarg[2]); /*hex char value*/
+ else if (optarg[0] >= '0' && optarg[0] <= '9')
+ sol_esc_ch = atob(optarg); /*decimal char value*/
+ else sol_esc_ch = optarg[0]; /*single ascii char*/
+ sol_esc_len = 1; /*set single-char esc sequence */
+ break;
+ case 'e': fSolEncryption = 0; break; /*encryption off*/
+ case 'k': i = atoi(optarg); /*sol keepalive timeout, default = 30*/
+ if (i < 0)
+ printf("Invalid keepalive timeout %d, ignoring.\n",i);
+ else sol_timeout = i;
+ if (i == 0) bKeepAlive = 0;
+ if (i == 32) bKeepAlive = 2; /*++++ for debug*/
+ break;
+ case 'l': fCRLF = 1; break; /*do legacy CR+LF translation*/
+ case 'i': strncpy(file_scr,optarg,sizeof(file_scr));
+ fScript = 1; break; /*script input file*/
+ case 'n': i = atoi(optarg); /* payload_instance */
+ if ((i <= 0) || (i > 255))
+ printf("Invalid payload instance %d, ignoring.\n",i);
+ else payload_instance = i;
+ break;
+ case 'o': strncpy(file_trc,optarg,sizeof(file_trc));
+ fTrace = 1; break; /*trace output file*/
+ case 'r': fRaw = 1; fCRLF = 0; fUseWinCon = 0;
+ break; /*raw termio, xlate off*/
+ case 's': sol_recvdelay = atoi(optarg); break; /*slow recv delay*/
+ case 't': sol_retries = atoi(optarg); break; /*timeout/retries*/
+ case 'u': wait_time = atoi(optarg); break; /*wait_time for tuning*/
+ case 'v': strncpy(dbglog_name,optarg,sizeof(dbglog_name));
+ fdbglog = 1; break; /*name of debug log file*/
+ case 'w': fUseWinCon = 0; break; /*do not use Console routines*/
+ case 'x':
+ if (fdebug == 0) fdebug = 2; /*only normal via dbglog */
+ else fdebug++; /* -xx = full, -xxx = max */
+ break;
+ case 'z': fdebug = 3; break; /*full debug messages */
+ case 'V': /* priv level */
+ fprivset = 1;
+ case 'N': /* nodename */
+ case 'U': /* remote username */
+ case 'P': /* remote password */
+ case 'R': /* remote password */
+ case 'E': /* get password from IPMI_PASSWORD environment var */
+ case 'F': /* force driver type */
+ case 'T': /* auth type */
+ case 'J': /* cipher suite */
+ case 'Y': /* prompt for remote password */
+ case 'Z': /* set local MC address */
+ parse_lan_options(c,optarg,fdebug);
+ break;
+ default:
+ show_usage();
+ ret = ERR_USAGE;
+ goto do_exit;
+ }
+
+ if (is_remote() == 0) { /* no node specified */
+ printf("Serial-Over-Lan Console requires a -N nodename\n");
+ ret = ERR_BAD_PARAM;
+ goto do_exit;
+ }
+ if (fdeactivate && !fprivset)
+ parse_lan_options('V',"4",0); /*deactivate requires admin priv */
+
+ /* fdebug: 1=debug/no packets, 2=debug log only, 3=full debug, 4=max debug*/
+ if (fdebug > 1) fdbglog = 1;
+
+ if (factivate == 0 && fdeactivate == 0) {
+ show_usage();
+ printf("Error: Need either -a or -d for sol\n");
+ ret = ERR_BAD_PARAM;
+ goto do_exit;
+ }
+#ifdef WIN32
+ else if (factivate) {
+ if (fdebug) printf("%s activate, connecting ...\n", progname);
+ }
+#endif
+ if (fdbglog) {
+ // strcpy(log_name,dbglog_name);
+ open_log(dbglog_name);
+ dbglog("%s ver %s\r\n", progname,progver);
+ }
+
+ i = get_driver_type(); /*see if user explictly set type*/
+ if (i == DRV_UNKNOWN) bDriver = DRV_UNKNOWN; /*no driver type specified*/
+ else bDriver = (uchar)i;
+
+ ret = ipmi_getdeviceid(devrec,16,fdebug);
+ if (ret != 0) {
+ goto do_exit;
+ } else {
+ ipmi_maj = devrec[4] & 0x0f;
+ ipmi_min = devrec[4] >> 4;
+ vend_id = devrec[6] + (devrec[7] << 8) + (devrec[8] << 16);
+ prod_id = devrec[9] + (devrec[10] << 8);
+ show_devid( devrec[2], devrec[3], ipmi_maj, ipmi_min);
+ bmcver[0] = devrec[2];
+ bmcver[1] = devrec[3];
+ switch(vend_id) {
+ case VENDOR_DELL: /*Dell == 0x0002A2*/
+ max_bmc_data = MAX_DELL_DATA; /*shorter max data*/
+ break;
+ case VENDOR_SUPERMICRO:
+ case VENDOR_LMC:
+ case VENDOR_PEPPERCON: /* 0x0028C5 Peppercon/Raritan*/
+ sol_timeout = 10; /* shorter 10 sec SOL keepalive timeout */
+ max_bmc_data = MAX_OTHER_DATA;
+ break;
+ case VENDOR_INTEL:
+ max_bmc_data = MAX_INTEL_DATA;
+ break;
+ case VENDOR_KONTRON:
+ max_bmc_data = MAX_KONTRON_DATA;
+ // bKeepAlive = 1;
+ break;
+ default:
+ max_bmc_data = MAX_OTHER_DATA;
+ break;
+ }
+ }
+
+ ret = ipmi_getpicmg(devrec,16,fdebug);
+ if (ret == 0) fpicmg = 1;
+
+ dbglog("driver=%d fdebug=%d vend_id=%x bmcver=%x.%x ipmi %d.%d\n",
+ bDriver,fdebug,vend_id,bmcver[0],bmcver[1],ipmi_maj,ipmi_min);
+ /* check for SOL support */
+ if (ipmi_maj >= 2) {
+ if ((bDriver == DRV_LAN) && (vend_id == VENDOR_INTEL)) {
+ /* user specified to use IPMI LAN 1.5 SOL on Intel */
+ bSolVer = 1; /*IPMI 1.5 SOL*/
+ } else {
+ bSolVer = 2; /*IPMI 2.0 SOL*/
+ if (get_driver_type() == DRV_LAN) { /*now using IPMI LAN 1.5*/
+ char *ptyp;
+ ipmi_close_(); /*close current IPMI LAN 1.5*/
+ if (is_lan2intel(vend_id,prod_id)) ptyp = "lan2i";
+ else ptyp = "lan2";
+ i = set_driver_type(ptyp); /*switch to IPMI LAN 2.0*/
+ }
+ }
+ } else if (ipmi_maj == 1) {
+ if (ipmi_min >= 5) bSolVer = 1; /* IPMI 1.5 */
+ else bSolVer = 0; /* IPMI 1.0 */
+ } else bSolVer = 0;
+ if (bSolVer == 0) {
+ printf("Serial Over Lan not supported for this IPMI version\n");
+ ret = LAN_ERR_NOTSUPPORT;
+ goto do_exit;
+ }
+#ifndef HAVE_LANPLUS
+ if (bSolVer == 2) {
+ printf("2.0 LanPlus module not available, trying 1.5 SOL instead\n");
+ bSolVer = 1;
+ }
+#endif
+ /* May also want to verify that SOL is implemented here */
+
+ /*
+ * Spawn a console raw terminal thread now, which will wait for the
+ * "Activating cmd (0x02)" on success
+ * Using globals: gnode,guser,gpswd, gauth_type, gpriv_level
+ */
+ if (fdeactivate) {
+ /* Request admin privilege by default, since deactivate requires it. */
+ ret = send_deactivate_sol(bSolVer);
+ dbglog("send_deactivate_sol rv = %d\n",ret);
+ } else if (factivate) {
+ ret = send_activate_sol(bSolVer);
+ dbglog("send_activate_sol(%d) rv = %d\n",bSolVer,ret);
+ if (bSolVer == 2) {
+ lan2_latency = lan2_get_latency();
+ retry_time = lan2_latency;
+ dbglog("lan2_latency = %ld msec (slow > %ld msec)\n",
+ lan2_latency,lan2_slow);
+ if ((sol_recvdelay == 0) && (lan2_latency > lan2_slow))
+ sol_recvdelay = 500; /* it is slow, set recvdelay */
+ if (sol_recvdelay != 0) {
+ dbglog("set_recvdelay to %dus\n",sol_recvdelay);
+ lanplus_set_recvdelay(sol_recvdelay);
+ }
+ } /*endif bSolVer==2*/
+ if (ret == 0) {
+ ret = sol_data_loop();
+ } /*endif activate ok*/
+ } /*endif do activate */
+
+do_exit:
+ if (ret != LAN_ERR_DROPPED) { /*if link dropped, no need to close*/
+ ipmi_close_();
+ os_usleep(0,(wait_time * 1000)); /*wait 0.5 sec for BMC teardown*/
+ }
+ if (fdebug) show_outcome(progname,ret);
+ if (fdbglog) close_log();
+ return(ret);
+} /* end main()*/
+#endif
+
+/* end isol.c */