|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* Copyright (c) 2005 Tyan Computer Corp. All Rights Reserved.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Redistribution and use in source and binary forms, with or without
|
|
Packit Service |
ed0f68 |
* modification, are permitted provided that the following conditions
|
|
Packit Service |
ed0f68 |
* are met:
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Redistribution of source code must retain the above copyright
|
|
Packit Service |
ed0f68 |
* notice, this list of conditions and the following disclaimer.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Redistribution in binary form must reproduce the above copyright
|
|
Packit Service |
ed0f68 |
* notice, this list of conditions and the following disclaimer in the
|
|
Packit Service |
ed0f68 |
* documentation and/or other materials provided with the distribution.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* Neither the name of Sun Microsystems, Inc. or the names of
|
|
Packit Service |
ed0f68 |
* contributors may be used to endorse or promote products derived
|
|
Packit Service |
ed0f68 |
* from this software without specific prior written permission.
|
|
Packit Service |
ed0f68 |
*
|
|
Packit Service |
ed0f68 |
* This software is provided "AS IS," without a warranty of any kind.
|
|
Packit Service |
ed0f68 |
* ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
|
|
Packit Service |
ed0f68 |
* INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
|
|
Packit Service |
ed0f68 |
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
|
|
Packit Service |
ed0f68 |
* SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE
|
|
Packit Service |
ed0f68 |
* FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
|
|
Packit Service |
ed0f68 |
* OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
|
|
Packit Service |
ed0f68 |
* SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
|
|
Packit Service |
ed0f68 |
* OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
|
|
Packit Service |
ed0f68 |
* PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
|
|
Packit Service |
ed0f68 |
* LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
|
|
Packit Service |
ed0f68 |
* EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
#define _DEFAULT_SOURCE
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
#include <sys/types.h>
|
|
Packit Service |
ed0f68 |
#include <sys/stat.h>
|
|
Packit Service |
ed0f68 |
#include <poll.h>
|
|
Packit Service |
ed0f68 |
#include <fcntl.h>
|
|
Packit Service |
ed0f68 |
#include <unistd.h>
|
|
Packit Service |
ed0f68 |
#include <errno.h>
|
|
Packit Service |
ed0f68 |
#include <stdlib.h>
|
|
Packit Service |
ed0f68 |
#include <stdio.h>
|
|
Packit Service |
ed0f68 |
#include <string.h>
|
|
Packit Service |
ed0f68 |
#include <sys/socket.h>
|
|
Packit Service |
ed0f68 |
#include <netinet/in.h>
|
|
Packit Service |
ed0f68 |
#include <arpa/inet.h>
|
|
Packit Service |
ed0f68 |
#include <netdb.h>
|
|
Packit Service |
ed0f68 |
#include <signal.h>
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
#include <sys/select.h>
|
|
Packit Service |
ed0f68 |
#include <sys/time.h>
|
|
Packit Service |
ed0f68 |
#include <sys/ioctl.h>
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
#if defined(HAVE_CONFIG_H)
|
|
Packit Service |
ed0f68 |
# include <config.h>
|
|
Packit Service |
ed0f68 |
#endif
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
#if defined(HAVE_TERMIOS_H)
|
|
Packit Service |
ed0f68 |
# include <termios.h>
|
|
Packit Service |
ed0f68 |
#elif defined (HAVE_SYS_TERMIOS_H)
|
|
Packit Service |
ed0f68 |
# include <sys/termios.h>
|
|
Packit Service |
ed0f68 |
#endif
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
#include <ipmitool/log.h>
|
|
Packit Service |
ed0f68 |
#include <ipmitool/helper.h>
|
|
Packit Service |
ed0f68 |
#include <ipmitool/ipmi.h>
|
|
Packit Service |
ed0f68 |
#include <ipmitool/ipmi_intf.h>
|
|
Packit Service |
ed0f68 |
#include <ipmitool/ipmi_tsol.h>
|
|
Packit Service |
ed0f68 |
#include <ipmitool/ipmi_strings.h>
|
|
Packit Service |
ed0f68 |
#include <ipmitool/bswap.h>
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static struct timeval _start_keepalive;
|
|
Packit Service |
ed0f68 |
static struct termios _saved_tio;
|
|
Packit Service |
ed0f68 |
static struct winsize _saved_winsize;
|
|
Packit Service |
ed0f68 |
static int _in_raw_mode = 0;
|
|
Packit Service |
ed0f68 |
static int _altterm = 0;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
extern int verbose;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
ipmi_tsol_command(struct ipmi_intf *intf, char *recvip, int port,
|
|
Packit Service |
ed0f68 |
unsigned char cmd)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
struct ipmi_rs *rsp;
|
|
Packit Service |
ed0f68 |
struct ipmi_rq req;
|
|
Packit Service |
ed0f68 |
unsigned char data[6];
|
|
Packit Service |
ed0f68 |
unsigned ip1, ip2, ip3, ip4;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (sscanf(recvip, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Invalid IP address: %s", recvip);
|
|
Packit Service |
ed0f68 |
return (-1);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
memset(&req, 0, sizeof(struct ipmi_rq));
|
|
Packit Service |
ed0f68 |
req.msg.netfn = IPMI_NETFN_TSOL;
|
|
Packit Service |
ed0f68 |
req.msg.cmd = cmd;
|
|
Packit Service |
ed0f68 |
req.msg.data_len = 6;
|
|
Packit Service |
ed0f68 |
req.msg.data = data;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
memset(data, 0, sizeof(data));
|
|
Packit Service |
ed0f68 |
data[0] = ip1;
|
|
Packit Service |
ed0f68 |
data[1] = ip2;
|
|
Packit Service |
ed0f68 |
data[2] = ip3;
|
|
Packit Service |
ed0f68 |
data[3] = ip4;
|
|
Packit Service |
ed0f68 |
data[4] = (port & 0xff00) >> 8;
|
|
Packit Service |
ed0f68 |
data[5] = (port & 0xff);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
rsp = intf->sendrecv(intf, &req;;
|
|
Packit Service |
ed0f68 |
if (rsp == NULL) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Unable to perform TSOL command");
|
|
Packit Service |
ed0f68 |
return (-1);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if (rsp->ccode > 0) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Unable to perform TSOL command: %s",
|
|
Packit Service |
ed0f68 |
val2str(rsp->ccode, completion_code_vals));
|
|
Packit Service |
ed0f68 |
return (-1);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
ipmi_tsol_start(struct ipmi_intf *intf, char *recvip, int port)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_START);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
ipmi_tsol_stop(struct ipmi_intf *intf, char *recvip, int port)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_STOP);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
ipmi_tsol_send_keystroke(struct ipmi_intf *intf, char *buff, int length)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
struct ipmi_rs *rsp;
|
|
Packit Service |
ed0f68 |
struct ipmi_rq req;
|
|
Packit Service |
ed0f68 |
unsigned char data[16];
|
|
Packit Service |
ed0f68 |
static unsigned char keyseq = 0;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
memset(&req, 0, sizeof(struct ipmi_rq));
|
|
Packit Service |
ed0f68 |
req.msg.netfn = IPMI_NETFN_TSOL;
|
|
Packit Service |
ed0f68 |
req.msg.cmd = IPMI_TSOL_CMD_SENDKEY;
|
|
Packit Service |
ed0f68 |
req.msg.data_len = length + 2;
|
|
Packit Service |
ed0f68 |
req.msg.data = data;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
memset(data, 0, sizeof(data));
|
|
Packit Service |
ed0f68 |
data[0] = length + 1;
|
|
Packit Service |
ed0f68 |
memcpy(data + 1, buff, length);
|
|
Packit Service |
ed0f68 |
data[length + 1] = keyseq++;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
rsp = intf->sendrecv(intf, &req;;
|
|
Packit Service |
ed0f68 |
if (verbose) {
|
|
Packit Service |
ed0f68 |
if (rsp == NULL) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Unable to send keystroke");
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if (rsp->ccode > 0) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Unable to send keystroke: %s",
|
|
Packit Service |
ed0f68 |
val2str(rsp->ccode, completion_code_vals));
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
return length;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
tsol_keepalive(struct ipmi_intf *intf)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
struct timeval end;
|
|
Packit Service |
ed0f68 |
gettimeofday(&end, 0);
|
|
Packit Service |
ed0f68 |
if (end.tv_sec - _start_keepalive.tv_sec <= 30) {
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
intf->keepalive(intf);
|
|
Packit Service |
ed0f68 |
gettimeofday(&_start_keepalive, 0);
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static void
|
|
Packit Service |
ed0f68 |
print_escape_seq(struct ipmi_intf *intf)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
" %c. - terminate connection\n"
|
|
Packit Service |
ed0f68 |
" %c^Z - suspend ipmitool\n"
|
|
Packit Service |
ed0f68 |
" %c^X - suspend ipmitool, but don't restore tty on restart\n"
|
|
Packit Service |
ed0f68 |
" %c? - this message\n"
|
|
Packit Service |
ed0f68 |
" %c%c - send the escape character by typing it twice\n"
|
|
Packit Service |
ed0f68 |
" (Note that escapes are only recognized immediately after newline.)",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char,
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char,
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char,
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char,
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char,
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
leave_raw_mode(void)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
if (!_in_raw_mode) {
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
} else if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) {
|
|
Packit Service |
ed0f68 |
lperror(LOG_ERR, "tcsetattr(stdin)");
|
|
Packit Service |
ed0f68 |
} else if (tcsetattr(fileno(stdout), TCSADRAIN, &_saved_tio) == -1) {
|
|
Packit Service |
ed0f68 |
lperror(LOG_ERR, "tcsetattr(stdout)");
|
|
Packit Service |
ed0f68 |
} else {
|
|
Packit Service |
ed0f68 |
_in_raw_mode = 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
enter_raw_mode(void)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
struct termios tio;
|
|
Packit Service |
ed0f68 |
if (tcgetattr(fileno(stdout), &_saved_tio) < 0) {
|
|
Packit Service |
ed0f68 |
lperror(LOG_ERR, "tcgetattr failed");
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
tio = _saved_tio;
|
|
Packit Service |
ed0f68 |
if (_altterm) {
|
|
Packit Service |
ed0f68 |
tio.c_iflag &= (ISTRIP | IGNBRK);
|
|
Packit Service |
ed0f68 |
tio.c_cflag &= ~(CSIZE | PARENB | IXON | IXOFF | IXANY);
|
|
Packit Service |
ed0f68 |
tio.c_cflag |= (CS8 |CREAD) | (IXON|IXOFF|IXANY);
|
|
Packit Service |
ed0f68 |
tio.c_lflag &= 0;
|
|
Packit Service |
ed0f68 |
tio.c_cc[VMIN] = 1;
|
|
Packit Service |
ed0f68 |
tio.c_cc[VTIME] = 0;
|
|
Packit Service |
ed0f68 |
} else {
|
|
Packit Service |
ed0f68 |
tio.c_iflag |= IGNPAR;
|
|
Packit Service |
ed0f68 |
tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF);
|
|
Packit Service |
ed0f68 |
tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN);
|
|
Packit Service |
ed0f68 |
tio.c_oflag &= ~OPOST;
|
|
Packit Service |
ed0f68 |
tio.c_cc[VMIN] = 1;
|
|
Packit Service |
ed0f68 |
tio.c_cc[VTIME] = 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0) {
|
|
Packit Service |
ed0f68 |
lperror(LOG_ERR, "tcsetattr(stdin)");
|
|
Packit Service |
ed0f68 |
} else if (tcsetattr(fileno(stdout), TCSADRAIN, &tio) < 0) {
|
|
Packit Service |
ed0f68 |
lperror(LOG_ERR, "tcsetattr(stdout)");
|
|
Packit Service |
ed0f68 |
} else {
|
|
Packit Service |
ed0f68 |
_in_raw_mode = 1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static void
|
|
Packit Service |
ed0f68 |
suspend_self(int restore_tty)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
leave_raw_mode();
|
|
Packit Service |
ed0f68 |
kill(getpid(), SIGTSTP);
|
|
Packit Service |
ed0f68 |
if (restore_tty) {
|
|
Packit Service |
ed0f68 |
enter_raw_mode();
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static int
|
|
Packit Service |
ed0f68 |
do_inbuf_actions(struct ipmi_intf *intf, char *in_buff, int len)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
static int in_esc = 0;
|
|
Packit Service |
ed0f68 |
static int last_was_cr = 1;
|
|
Packit Service |
ed0f68 |
int i;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
for(i = 0; i < len ;) {
|
|
Packit Service |
ed0f68 |
if (!in_esc) {
|
|
Packit Service |
ed0f68 |
if (last_was_cr &&
|
|
Packit Service |
ed0f68 |
(in_buff[i] == intf->ssn_params.sol_escape_char)) {
|
|
Packit Service |
ed0f68 |
in_esc = 1;
|
|
Packit Service |
ed0f68 |
memmove(in_buff, in_buff + 1, len - i - 1);
|
|
Packit Service |
ed0f68 |
len--;
|
|
Packit Service |
ed0f68 |
continue;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if (in_esc) {
|
|
Packit Service |
ed0f68 |
if (in_buff[i] == intf->ssn_params.sol_escape_char) {
|
|
Packit Service |
ed0f68 |
in_esc = 0;
|
|
Packit Service |
ed0f68 |
i++;
|
|
Packit Service |
ed0f68 |
continue;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
switch (in_buff[i]) {
|
|
Packit Service |
ed0f68 |
case '.':
|
|
Packit Service |
ed0f68 |
printf("%c. [terminated ipmitool]\n",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char);
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
case 'Z' - 64:
|
|
Packit Service |
ed0f68 |
printf("%c^Z [suspend ipmitool]\n",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char);
|
|
Packit Service |
ed0f68 |
/* Restore tty back to raw */
|
|
Packit Service |
ed0f68 |
suspend_self(1);
|
|
Packit Service |
ed0f68 |
break;
|
|
Packit Service |
ed0f68 |
case 'X' - 64:
|
|
Packit Service |
ed0f68 |
printf("%c^X [suspend ipmitool]\n",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char);
|
|
Packit Service |
ed0f68 |
/* Don't restore to raw mode */
|
|
Packit Service |
ed0f68 |
suspend_self(0);
|
|
Packit Service |
ed0f68 |
break;
|
|
Packit Service |
ed0f68 |
case '?':
|
|
Packit Service |
ed0f68 |
printf("%c? [ipmitool help]\n",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char);
|
|
Packit Service |
ed0f68 |
print_escape_seq(intf);
|
|
Packit Service |
ed0f68 |
break;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
memmove(in_buff, (in_buff + 1), (len - i - 1));
|
|
Packit Service |
ed0f68 |
len--;
|
|
Packit Service |
ed0f68 |
in_esc = 0;
|
|
Packit Service |
ed0f68 |
continue;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
last_was_cr = (in_buff[i] == '\r' || in_buff[i] == '\n');
|
|
Packit Service |
ed0f68 |
i++;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
return len;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static void
|
|
Packit Service |
ed0f68 |
do_terminal_cleanup(void)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
if (_saved_winsize.ws_row > 0 && _saved_winsize.ws_col > 0) {
|
|
Packit Service |
ed0f68 |
ioctl(fileno(stdout), TIOCSWINSZ, &_saved_winsize);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
leave_raw_mode();
|
|
Packit Service |
ed0f68 |
if (errno) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Exiting due to error %d -> %s",
|
|
Packit Service |
ed0f68 |
errno, strerror(errno));
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static void
|
|
Packit Service |
ed0f68 |
set_terminal_size(int rows, int cols)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
struct winsize winsize;
|
|
Packit Service |
ed0f68 |
if (rows <= 0 || cols <= 0) {
|
|
Packit Service |
ed0f68 |
return;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
/* save initial winsize */
|
|
Packit Service |
ed0f68 |
ioctl(fileno(stdout), TIOCGWINSZ, &_saved_winsize);
|
|
Packit Service |
ed0f68 |
/* set new winsize */
|
|
Packit Service |
ed0f68 |
winsize.ws_row = rows;
|
|
Packit Service |
ed0f68 |
winsize.ws_col = cols;
|
|
Packit Service |
ed0f68 |
ioctl(fileno(stdout), TIOCSWINSZ, &winsize);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
static void
|
|
Packit Service |
ed0f68 |
print_tsol_usage(void)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
struct winsize winsize;
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
"Usage: tsol [recvip] [port=NUM] [ro|rw] [rows=NUM] [cols=NUM] [altterm]");
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
" recvip Receiver IP Address [default=local]");
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
" port=NUM Receiver UDP Port [default=%d]",
|
|
Packit Service |
ed0f68 |
IPMI_TSOL_DEF_PORT);
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
" ro|rw Set Read-Only or Read-Write [default=rw]");
|
|
Packit Service |
ed0f68 |
ioctl(fileno(stdout), TIOCGWINSZ, &winsize);
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
" rows=NUM Set terminal rows [default=%d]",
|
|
Packit Service |
ed0f68 |
winsize.ws_row);
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
" cols=NUM Set terminal columns [default=%d]",
|
|
Packit Service |
ed0f68 |
winsize.ws_col);
|
|
Packit Service |
ed0f68 |
lprintf(LOG_NOTICE,
|
|
Packit Service |
ed0f68 |
" altterm Alternate terminal setup [default=off]");
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
int
|
|
Packit Service |
ed0f68 |
ipmi_tsol_main(struct ipmi_intf *intf, int argc, char **argv)
|
|
Packit Service |
ed0f68 |
{
|
|
Packit Service |
ed0f68 |
struct pollfd fds_wait[3], fds_data_wait[3], *fds;
|
|
Packit Service |
ed0f68 |
struct sockaddr_in sin, myaddr, *sa_in;
|
|
Packit Service |
ed0f68 |
socklen_t mylen;
|
|
Packit Service |
ed0f68 |
char *recvip = NULL;
|
|
Packit Service |
ed0f68 |
char in_buff[IPMI_BUF_SIZE];
|
|
Packit Service |
ed0f68 |
char out_buff[IPMI_BUF_SIZE * 8];
|
|
Packit Service |
ed0f68 |
char buff[IPMI_BUF_SIZE + 4];
|
|
Packit Service |
ed0f68 |
int fd_socket, result, i;
|
|
Packit Service |
ed0f68 |
int out_buff_fill, in_buff_fill;
|
|
Packit Service |
ed0f68 |
int ip1, ip2, ip3, ip4;
|
|
Packit Service |
ed0f68 |
int read_only = 0, rows = 0, cols = 0;
|
|
Packit Service |
ed0f68 |
int port = IPMI_TSOL_DEF_PORT;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (strlen(intf->name) < 3 || strncmp(intf->name, "lan", 3) != 0) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Error: Tyan SOL is only available over lan interface");
|
|
Packit Service |
ed0f68 |
return (-1);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
for (i = 0; i
|
|
Packit Service |
ed0f68 |
if (sscanf(argv[i], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4) {
|
|
Packit Service |
ed0f68 |
/* not free'd ...*/
|
|
Packit Service |
ed0f68 |
/* recvip = strdup(argv[i]); */
|
|
Packit Service |
ed0f68 |
recvip = argv[i];
|
|
Packit Service |
ed0f68 |
} else if (sscanf(argv[i], "port=%d", &ip1) == 1) {
|
|
Packit Service |
ed0f68 |
port = ip1;
|
|
Packit Service |
ed0f68 |
} else if (sscanf(argv[i], "rows=%d", &ip1) == 1) {
|
|
Packit Service |
ed0f68 |
rows = ip1;
|
|
Packit Service |
ed0f68 |
} else if (sscanf(argv[i], "cols=%d", &ip1) == 1) {
|
|
Packit Service |
ed0f68 |
cols = ip1;
|
|
Packit Service |
ed0f68 |
} else if (strlen(argv[i]) == 2
|
|
Packit Service |
ed0f68 |
&& strncmp(argv[i], "ro", 2) == 0) {
|
|
Packit Service |
ed0f68 |
read_only = 1;
|
|
Packit Service |
ed0f68 |
} else if (strlen(argv[i]) == 2
|
|
Packit Service |
ed0f68 |
&& strncmp(argv[i], "rw", 2) == 0) {
|
|
Packit Service |
ed0f68 |
read_only = 0;
|
|
Packit Service |
ed0f68 |
} else if (strlen(argv[i]) == 7
|
|
Packit Service |
ed0f68 |
&& strncmp(argv[i], "altterm", 7) == 0) {
|
|
Packit Service |
ed0f68 |
_altterm = 1;
|
|
Packit Service |
ed0f68 |
} else if (strlen(argv[i]) == 4
|
|
Packit Service |
ed0f68 |
&& strncmp(argv[i], "help", 4) == 0) {
|
|
Packit Service |
ed0f68 |
print_tsol_usage();
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
} else {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Invalid tsol command: '%s'\n",
|
|
Packit Service |
ed0f68 |
argv[i]);
|
|
Packit Service |
ed0f68 |
print_tsol_usage();
|
|
Packit Service |
ed0f68 |
return (-1);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/* create udp socket to receive the packet */
|
|
Packit Service |
ed0f68 |
memset(&sin, 0, sizeof(sin));
|
|
Packit Service |
ed0f68 |
sin.sin_family = AF_INET;
|
|
Packit Service |
ed0f68 |
sin.sin_port = htons(port);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
sa_in = (struct sockaddr_in *)&intf->session->addr;
|
|
Packit Service |
ed0f68 |
result = inet_pton(AF_INET, (const char *)intf->ssn_params.hostname,
|
|
Packit Service |
ed0f68 |
&sa_in->sin_addr);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if (result <= 0) {
|
|
Packit Service |
ed0f68 |
struct hostent *host = gethostbyname((const char *)intf->ssn_params.hostname);
|
|
Packit Service |
ed0f68 |
if (host == NULL ) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Address lookup for %s failed",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.hostname);
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if (host->h_addrtype != AF_INET) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR,
|
|
Packit Service |
ed0f68 |
"Address lookup for %s failed. Got %s, expected IPv4 address.",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.hostname,
|
|
Packit Service |
ed0f68 |
(host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown");
|
|
Packit Service |
ed0f68 |
return (-1);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
sa_in->sin_family = host->h_addrtype;
|
|
Packit Service |
ed0f68 |
memcpy(&sa_in->sin_addr, host->h_addr_list[0], host->h_length);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
fd_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
|
Packit Service |
ed0f68 |
if (fd_socket < 0) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Can't open port %d", port);
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if (bind(fd_socket, (struct sockaddr *)&sin, sizeof(sin)) == (-1)) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Failed to bind socket.");
|
|
Packit Service |
ed0f68 |
close(fd_socket);
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* retrieve local IP address if not supplied on command line
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
if (recvip == NULL) {
|
|
Packit Service |
ed0f68 |
/* must connect first */
|
|
Packit Service |
ed0f68 |
result = intf->open(intf);
|
|
Packit Service |
ed0f68 |
if (result < 0) {
|
|
Packit Service |
ed0f68 |
close(fd_socket);
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
mylen = sizeof(myaddr);
|
|
Packit Service |
ed0f68 |
if (getsockname(intf->fd, (struct sockaddr *)&myaddr, &mylen) < 0) {
|
|
Packit Service |
ed0f68 |
lperror(LOG_ERR, "getsockname failed");
|
|
Packit Service |
ed0f68 |
close(fd_socket);
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
recvip = inet_ntoa(myaddr.sin_addr);
|
|
Packit Service |
ed0f68 |
if (recvip == NULL) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Unable to find local IP address");
|
|
Packit Service |
ed0f68 |
close(fd_socket);
|
|
Packit Service |
ed0f68 |
return -1;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
printf("[Starting %sSOL with receiving address %s:%d]\n",
|
|
Packit Service |
ed0f68 |
read_only ? "Read-only " : "", recvip, port);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
set_terminal_size(rows, cols);
|
|
Packit Service |
ed0f68 |
enter_raw_mode();
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* talk to smdc to start Console redirect - IP address and port as parameter
|
|
Packit Service |
ed0f68 |
* ipmitool -I lan -H 192.168.168.227 -U Administrator raw 0x30 0x06 0xC0 0xA8 0xA8 0x78 0x1A 0x0A
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
result = ipmi_tsol_start(intf, recvip, port);
|
|
Packit Service |
ed0f68 |
if (result < 0) {
|
|
Packit Service |
ed0f68 |
lprintf(LOG_ERR, "Error starting SOL");
|
|
Packit Service |
ed0f68 |
close(fd_socket);
|
|
Packit Service |
ed0f68 |
return (-1);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
printf("[SOL Session operational. Use %c? for help]\n",
|
|
Packit Service |
ed0f68 |
intf->ssn_params.sol_escape_char);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
gettimeofday(&_start_keepalive, 0);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
fds_wait[0].fd = fd_socket;
|
|
Packit Service |
ed0f68 |
fds_wait[0].events = POLLIN;
|
|
Packit Service |
ed0f68 |
fds_wait[0].revents = 0;
|
|
Packit Service |
ed0f68 |
fds_wait[1].fd = fileno(stdin);
|
|
Packit Service |
ed0f68 |
fds_wait[1].events = POLLIN;
|
|
Packit Service |
ed0f68 |
fds_wait[1].revents = 0;
|
|
Packit Service |
ed0f68 |
fds_wait[2].fd = -1;
|
|
Packit Service |
ed0f68 |
fds_wait[2].events = 0;
|
|
Packit Service |
ed0f68 |
fds_wait[2].revents = 0;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
fds_data_wait[0].fd = fd_socket;
|
|
Packit Service |
ed0f68 |
fds_data_wait[0].events = POLLIN | POLLOUT;
|
|
Packit Service |
ed0f68 |
fds_data_wait[0].revents = 0;
|
|
Packit Service |
ed0f68 |
fds_data_wait[1].fd = fileno(stdin);
|
|
Packit Service |
ed0f68 |
fds_data_wait[1].events = POLLIN;
|
|
Packit Service |
ed0f68 |
fds_data_wait[1].revents = 0;
|
|
Packit Service |
ed0f68 |
fds_data_wait[2].fd = fileno(stdout);
|
|
Packit Service |
ed0f68 |
fds_data_wait[2].events = POLLOUT;
|
|
Packit Service |
ed0f68 |
fds_data_wait[2].revents = 0;
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
out_buff_fill = 0;
|
|
Packit Service |
ed0f68 |
in_buff_fill = 0;
|
|
Packit Service |
ed0f68 |
fds = fds_wait;
|
|
Packit Service |
ed0f68 |
for (;;) {
|
|
Packit Service |
ed0f68 |
result = poll(fds, 3, 15 * 1000);
|
|
Packit Service |
ed0f68 |
if (result < 0) {
|
|
Packit Service |
ed0f68 |
break;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
/* send keepalive packet */
|
|
Packit Service |
ed0f68 |
tsol_keepalive(intf);
|
|
Packit Service |
ed0f68 |
|
|
Packit Service |
ed0f68 |
if ((fds[0].revents & POLLIN) && (sizeof(out_buff) > out_buff_fill)) {
|
|
Packit Service |
ed0f68 |
socklen_t sin_len = sizeof(sin);
|
|
Packit Service |
ed0f68 |
int buff_size = sizeof(buff);
|
|
Packit Service |
ed0f68 |
if ((sizeof(out_buff) - out_buff_fill + 4) < buff_size) {
|
|
Packit Service |
ed0f68 |
buff_size = (sizeof(out_buff) - out_buff_fill) + 4;
|
|
Packit Service |
ed0f68 |
if ((buff_size - 4) <= 0) {
|
|
Packit Service |
ed0f68 |
buff_size = 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
result = recvfrom(fd_socket, buff,
|
|
Packit Service |
ed0f68 |
buff_size, 0,
|
|
Packit Service |
ed0f68 |
(struct sockaddr *)&sin, &sin_len);
|
|
Packit Service |
ed0f68 |
/* read the data from udp socket,
|
|
Packit Service |
ed0f68 |
* skip some bytes in the head
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
if ((result - 4) > 0) {
|
|
Packit Service |
ed0f68 |
int length = result - 4;
|
|
Packit Service |
ed0f68 |
memcpy(out_buff + out_buff_fill, buff + 4, length);
|
|
Packit Service |
ed0f68 |
out_buff_fill += length;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if ((fds[1].revents & POLLIN) && (sizeof(in_buff) > in_buff_fill)) {
|
|
Packit Service |
ed0f68 |
/* Read from keyboard */
|
|
Packit Service |
ed0f68 |
result = read(fileno(stdin), in_buff + in_buff_fill,
|
|
Packit Service |
ed0f68 |
sizeof(in_buff) - in_buff_fill);
|
|
Packit Service |
ed0f68 |
if (result > 0) {
|
|
Packit Service |
ed0f68 |
int bytes;
|
|
Packit Service |
ed0f68 |
bytes = do_inbuf_actions(intf,
|
|
Packit Service |
ed0f68 |
in_buff + in_buff_fill, result);
|
|
Packit Service |
ed0f68 |
if (bytes < 0) {
|
|
Packit Service |
ed0f68 |
result = ipmi_tsol_stop(intf, recvip, port);
|
|
Packit Service |
ed0f68 |
do_terminal_cleanup();
|
|
Packit Service |
ed0f68 |
return result;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if (read_only) {
|
|
Packit Service |
ed0f68 |
bytes = 0;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
in_buff_fill += bytes;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if ((fds[2].revents & POLLOUT) && out_buff_fill) {
|
|
Packit Service |
ed0f68 |
/* To screen */
|
|
Packit Service |
ed0f68 |
result = write(fileno(stdout), out_buff, out_buff_fill);
|
|
Packit Service |
ed0f68 |
if (result > 0) {
|
|
Packit Service |
ed0f68 |
out_buff_fill -= result;
|
|
Packit Service |
ed0f68 |
if (out_buff_fill) {
|
|
Packit Service |
ed0f68 |
memmove(out_buff, out_buff + result, out_buff_fill);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
if ((fds[0].revents & POLLOUT) && in_buff_fill) {
|
|
Packit Service |
ed0f68 |
/*
|
|
Packit Service |
ed0f68 |
* translate key and send that to SMDC using IPMI
|
|
Packit Service |
ed0f68 |
* ipmitool -I lan -H 192.168.168.227 -U Administrator raw 0x30 0x03 0x04 0x1B 0x5B 0x43
|
|
Packit Service |
ed0f68 |
*/
|
|
Packit Service |
ed0f68 |
result = ipmi_tsol_send_keystroke(intf,
|
|
Packit Service |
ed0f68 |
in_buff, __min(in_buff_fill, 14));
|
|
Packit Service |
ed0f68 |
if (result > 0) {
|
|
Packit Service |
ed0f68 |
gettimeofday(&_start_keepalive, 0);
|
|
Packit Service |
ed0f68 |
in_buff_fill -= result;
|
|
Packit Service |
ed0f68 |
if (in_buff_fill) {
|
|
Packit Service |
ed0f68 |
memmove(in_buff, in_buff + result, in_buff_fill);
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
fds = (in_buff_fill || out_buff_fill )?
|
|
Packit Service |
ed0f68 |
fds_data_wait : fds_wait;
|
|
Packit Service |
ed0f68 |
}
|
|
Packit Service |
ed0f68 |
return 0;
|
|
Packit Service |
ed0f68 |
}
|