1*c18ec02fSPetter Reinholdtsen /* 2*c18ec02fSPetter Reinholdtsen * Copyright (c) 2005 Tyan Computer Corp. All Rights Reserved. 3*c18ec02fSPetter Reinholdtsen * 4*c18ec02fSPetter Reinholdtsen * Redistribution and use in source and binary forms, with or without 5*c18ec02fSPetter Reinholdtsen * modification, are permitted provided that the following conditions 6*c18ec02fSPetter Reinholdtsen * are met: 7*c18ec02fSPetter Reinholdtsen * 8*c18ec02fSPetter Reinholdtsen * Redistribution of source code must retain the above copyright 9*c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer. 10*c18ec02fSPetter Reinholdtsen * 11*c18ec02fSPetter Reinholdtsen * Redistribution in binary form must reproduce the above copyright 12*c18ec02fSPetter Reinholdtsen * notice, this list of conditions and the following disclaimer in the 13*c18ec02fSPetter Reinholdtsen * documentation and/or other materials provided with the distribution. 14*c18ec02fSPetter Reinholdtsen * 15*c18ec02fSPetter Reinholdtsen * Neither the name of Sun Microsystems, Inc. or the names of 16*c18ec02fSPetter Reinholdtsen * contributors may be used to endorse or promote products derived 17*c18ec02fSPetter Reinholdtsen * from this software without specific prior written permission. 18*c18ec02fSPetter Reinholdtsen * 19*c18ec02fSPetter Reinholdtsen * This software is provided "AS IS," without a warranty of any kind. 20*c18ec02fSPetter Reinholdtsen * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, 21*c18ec02fSPetter Reinholdtsen * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A 22*c18ec02fSPetter Reinholdtsen * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. 23*c18ec02fSPetter Reinholdtsen * SUN MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE 24*c18ec02fSPetter Reinholdtsen * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING 25*c18ec02fSPetter Reinholdtsen * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL 26*c18ec02fSPetter Reinholdtsen * SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, 27*c18ec02fSPetter Reinholdtsen * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR 28*c18ec02fSPetter Reinholdtsen * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF 29*c18ec02fSPetter Reinholdtsen * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 30*c18ec02fSPetter Reinholdtsen * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 31*c18ec02fSPetter Reinholdtsen */ 32*c18ec02fSPetter Reinholdtsen 33*c18ec02fSPetter Reinholdtsen #include <sys/types.h> 34*c18ec02fSPetter Reinholdtsen #include <sys/stat.h> 35*c18ec02fSPetter Reinholdtsen #include <sys/poll.h> 36*c18ec02fSPetter Reinholdtsen #include <fcntl.h> 37*c18ec02fSPetter Reinholdtsen #include <unistd.h> 38*c18ec02fSPetter Reinholdtsen #include <errno.h> 39*c18ec02fSPetter Reinholdtsen #include <stdlib.h> 40*c18ec02fSPetter Reinholdtsen #include <stdio.h> 41*c18ec02fSPetter Reinholdtsen #include <string.h> 42*c18ec02fSPetter Reinholdtsen #include <sys/socket.h> 43*c18ec02fSPetter Reinholdtsen #include <netinet/in.h> 44*c18ec02fSPetter Reinholdtsen #include <arpa/inet.h> 45*c18ec02fSPetter Reinholdtsen #include <netdb.h> 46*c18ec02fSPetter Reinholdtsen #include <signal.h> 47*c18ec02fSPetter Reinholdtsen 48*c18ec02fSPetter Reinholdtsen #include <sys/select.h> 49*c18ec02fSPetter Reinholdtsen #include <sys/time.h> 50*c18ec02fSPetter Reinholdtsen #include <sys/ioctl.h> 51*c18ec02fSPetter Reinholdtsen 52*c18ec02fSPetter Reinholdtsen #if defined(HAVE_CONFIG_H) 53*c18ec02fSPetter Reinholdtsen # include <config.h> 54*c18ec02fSPetter Reinholdtsen #endif 55*c18ec02fSPetter Reinholdtsen 56*c18ec02fSPetter Reinholdtsen #if defined(HAVE_TERMIOS_H) 57*c18ec02fSPetter Reinholdtsen # include <termios.h> 58*c18ec02fSPetter Reinholdtsen #elif defined (HAVE_SYS_TERMIOS_H) 59*c18ec02fSPetter Reinholdtsen # include <sys/termios.h> 60*c18ec02fSPetter Reinholdtsen #endif 61*c18ec02fSPetter Reinholdtsen 62*c18ec02fSPetter Reinholdtsen #include <ipmitool/log.h> 63*c18ec02fSPetter Reinholdtsen #include <ipmitool/helper.h> 64*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi.h> 65*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_intf.h> 66*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_tsol.h> 67*c18ec02fSPetter Reinholdtsen #include <ipmitool/ipmi_strings.h> 68*c18ec02fSPetter Reinholdtsen #include <ipmitool/bswap.h> 69*c18ec02fSPetter Reinholdtsen 70*c18ec02fSPetter Reinholdtsen static struct timeval _start_keepalive; 71*c18ec02fSPetter Reinholdtsen static struct termios _saved_tio; 72*c18ec02fSPetter Reinholdtsen static struct winsize _saved_winsize; 73*c18ec02fSPetter Reinholdtsen static int _in_raw_mode = 0; 74*c18ec02fSPetter Reinholdtsen static int _altterm = 0; 75*c18ec02fSPetter Reinholdtsen 76*c18ec02fSPetter Reinholdtsen extern int verbose; 77*c18ec02fSPetter Reinholdtsen 78*c18ec02fSPetter Reinholdtsen static int 79*c18ec02fSPetter Reinholdtsen ipmi_tsol_command(struct ipmi_intf * intf, char *recvip, int port, unsigned char cmd) 80*c18ec02fSPetter Reinholdtsen { 81*c18ec02fSPetter Reinholdtsen struct ipmi_rs *rsp; 82*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 83*c18ec02fSPetter Reinholdtsen unsigned char data[6]; 84*c18ec02fSPetter Reinholdtsen unsigned ip1, ip2, ip3, ip4; 85*c18ec02fSPetter Reinholdtsen 86*c18ec02fSPetter Reinholdtsen if (sscanf(recvip, "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) != 4) { 87*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Invalid IP address: %s", recvip); 88*c18ec02fSPetter Reinholdtsen return -1; 89*c18ec02fSPetter Reinholdtsen } 90*c18ec02fSPetter Reinholdtsen 91*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(struct ipmi_rq)); 92*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_TSOL; 93*c18ec02fSPetter Reinholdtsen req.msg.cmd = cmd; 94*c18ec02fSPetter Reinholdtsen req.msg.data_len = 6; 95*c18ec02fSPetter Reinholdtsen req.msg.data = data; 96*c18ec02fSPetter Reinholdtsen 97*c18ec02fSPetter Reinholdtsen memset(data, 0, sizeof(data)); 98*c18ec02fSPetter Reinholdtsen data[0] = ip1; 99*c18ec02fSPetter Reinholdtsen data[1] = ip2; 100*c18ec02fSPetter Reinholdtsen data[2] = ip3; 101*c18ec02fSPetter Reinholdtsen data[3] = ip4; 102*c18ec02fSPetter Reinholdtsen data[4] = (port & 0xff00) >> 8; 103*c18ec02fSPetter Reinholdtsen data[5] = (port & 0xff); 104*c18ec02fSPetter Reinholdtsen 105*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 106*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 107*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to perform TSOL command"); 108*c18ec02fSPetter Reinholdtsen return -1; 109*c18ec02fSPetter Reinholdtsen } 110*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 111*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to perform TSOL command: %s", 112*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 113*c18ec02fSPetter Reinholdtsen return -1; 114*c18ec02fSPetter Reinholdtsen } 115*c18ec02fSPetter Reinholdtsen 116*c18ec02fSPetter Reinholdtsen return 0; 117*c18ec02fSPetter Reinholdtsen } 118*c18ec02fSPetter Reinholdtsen 119*c18ec02fSPetter Reinholdtsen static int 120*c18ec02fSPetter Reinholdtsen ipmi_tsol_start(struct ipmi_intf * intf, char *recvip, int port) 121*c18ec02fSPetter Reinholdtsen { 122*c18ec02fSPetter Reinholdtsen return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_START); 123*c18ec02fSPetter Reinholdtsen } 124*c18ec02fSPetter Reinholdtsen 125*c18ec02fSPetter Reinholdtsen static int 126*c18ec02fSPetter Reinholdtsen ipmi_tsol_stop(struct ipmi_intf * intf, char *recvip, int port) 127*c18ec02fSPetter Reinholdtsen { 128*c18ec02fSPetter Reinholdtsen return ipmi_tsol_command(intf, recvip, port, IPMI_TSOL_CMD_STOP); 129*c18ec02fSPetter Reinholdtsen } 130*c18ec02fSPetter Reinholdtsen 131*c18ec02fSPetter Reinholdtsen static int 132*c18ec02fSPetter Reinholdtsen ipmi_tsol_send_keystroke(struct ipmi_intf * intf, char *buff, int length) 133*c18ec02fSPetter Reinholdtsen { 134*c18ec02fSPetter Reinholdtsen struct ipmi_rs * rsp; 135*c18ec02fSPetter Reinholdtsen struct ipmi_rq req; 136*c18ec02fSPetter Reinholdtsen unsigned char data[16]; 137*c18ec02fSPetter Reinholdtsen static unsigned char keyseq = 0; 138*c18ec02fSPetter Reinholdtsen 139*c18ec02fSPetter Reinholdtsen memset(&req, 0, sizeof(struct ipmi_rq)); 140*c18ec02fSPetter Reinholdtsen req.msg.netfn = IPMI_NETFN_TSOL; 141*c18ec02fSPetter Reinholdtsen req.msg.cmd = IPMI_TSOL_CMD_SENDKEY; 142*c18ec02fSPetter Reinholdtsen req.msg.data_len = length + 2; 143*c18ec02fSPetter Reinholdtsen req.msg.data = data; 144*c18ec02fSPetter Reinholdtsen 145*c18ec02fSPetter Reinholdtsen memset(data, 0, sizeof(data)); 146*c18ec02fSPetter Reinholdtsen data[0] = length + 1; 147*c18ec02fSPetter Reinholdtsen memcpy(data + 1, buff, length); 148*c18ec02fSPetter Reinholdtsen data[length + 1] = keyseq++; 149*c18ec02fSPetter Reinholdtsen 150*c18ec02fSPetter Reinholdtsen rsp = intf->sendrecv(intf, &req); 151*c18ec02fSPetter Reinholdtsen if (verbose) { 152*c18ec02fSPetter Reinholdtsen if (rsp == NULL) { 153*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to send keystroke"); 154*c18ec02fSPetter Reinholdtsen return -1; 155*c18ec02fSPetter Reinholdtsen } 156*c18ec02fSPetter Reinholdtsen if (rsp->ccode > 0) { 157*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to send keystroke: %s", 158*c18ec02fSPetter Reinholdtsen val2str(rsp->ccode, completion_code_vals)); 159*c18ec02fSPetter Reinholdtsen return -1; 160*c18ec02fSPetter Reinholdtsen } 161*c18ec02fSPetter Reinholdtsen } 162*c18ec02fSPetter Reinholdtsen 163*c18ec02fSPetter Reinholdtsen return length; 164*c18ec02fSPetter Reinholdtsen } 165*c18ec02fSPetter Reinholdtsen 166*c18ec02fSPetter Reinholdtsen static int 167*c18ec02fSPetter Reinholdtsen tsol_keepalive(struct ipmi_intf * intf) 168*c18ec02fSPetter Reinholdtsen { 169*c18ec02fSPetter Reinholdtsen struct timeval end; 170*c18ec02fSPetter Reinholdtsen 171*c18ec02fSPetter Reinholdtsen gettimeofday(&end, 0); 172*c18ec02fSPetter Reinholdtsen 173*c18ec02fSPetter Reinholdtsen if (end.tv_sec - _start_keepalive.tv_sec <= 30) 174*c18ec02fSPetter Reinholdtsen return 0; 175*c18ec02fSPetter Reinholdtsen 176*c18ec02fSPetter Reinholdtsen intf->keepalive(intf); 177*c18ec02fSPetter Reinholdtsen 178*c18ec02fSPetter Reinholdtsen gettimeofday(&_start_keepalive, 0); 179*c18ec02fSPetter Reinholdtsen 180*c18ec02fSPetter Reinholdtsen return 0; 181*c18ec02fSPetter Reinholdtsen } 182*c18ec02fSPetter Reinholdtsen 183*c18ec02fSPetter Reinholdtsen static void 184*c18ec02fSPetter Reinholdtsen print_escape_seq(struct ipmi_intf *intf) 185*c18ec02fSPetter Reinholdtsen { 186*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, 187*c18ec02fSPetter Reinholdtsen " %c. - terminate connection\n" 188*c18ec02fSPetter Reinholdtsen " %c^Z - suspend ipmitool\n" 189*c18ec02fSPetter Reinholdtsen " %c^X - suspend ipmitool, but don't restore tty on restart\n" 190*c18ec02fSPetter Reinholdtsen " %c? - this message\n" 191*c18ec02fSPetter Reinholdtsen " %c%c - send the escape character by typing it twice\n" 192*c18ec02fSPetter Reinholdtsen " (Note that escapes are only recognized immediately after newline.)", 193*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char, 194*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char, 195*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char, 196*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char, 197*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char, 198*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char); 199*c18ec02fSPetter Reinholdtsen } 200*c18ec02fSPetter Reinholdtsen 201*c18ec02fSPetter Reinholdtsen static int 202*c18ec02fSPetter Reinholdtsen leave_raw_mode(void) 203*c18ec02fSPetter Reinholdtsen { 204*c18ec02fSPetter Reinholdtsen if (!_in_raw_mode) 205*c18ec02fSPetter Reinholdtsen return -1; 206*c18ec02fSPetter Reinholdtsen else if (tcsetattr(fileno(stdin), TCSADRAIN, &_saved_tio) == -1) 207*c18ec02fSPetter Reinholdtsen lperror(LOG_ERR, "tcsetattr(stdin)"); 208*c18ec02fSPetter Reinholdtsen else if (tcsetattr(fileno(stdout), TCSADRAIN, &_saved_tio) == -1) 209*c18ec02fSPetter Reinholdtsen lperror(LOG_ERR, "tcsetattr(stdout)"); 210*c18ec02fSPetter Reinholdtsen else 211*c18ec02fSPetter Reinholdtsen _in_raw_mode = 0; 212*c18ec02fSPetter Reinholdtsen 213*c18ec02fSPetter Reinholdtsen return 0; 214*c18ec02fSPetter Reinholdtsen } 215*c18ec02fSPetter Reinholdtsen 216*c18ec02fSPetter Reinholdtsen static int 217*c18ec02fSPetter Reinholdtsen enter_raw_mode(void) 218*c18ec02fSPetter Reinholdtsen { 219*c18ec02fSPetter Reinholdtsen struct termios tio; 220*c18ec02fSPetter Reinholdtsen 221*c18ec02fSPetter Reinholdtsen if (tcgetattr(fileno(stdout), &_saved_tio) < 0) { 222*c18ec02fSPetter Reinholdtsen lperror(LOG_ERR, "tcgetattr failed"); 223*c18ec02fSPetter Reinholdtsen return -1; 224*c18ec02fSPetter Reinholdtsen } 225*c18ec02fSPetter Reinholdtsen 226*c18ec02fSPetter Reinholdtsen tio = _saved_tio; 227*c18ec02fSPetter Reinholdtsen 228*c18ec02fSPetter Reinholdtsen if (_altterm) { 229*c18ec02fSPetter Reinholdtsen tio.c_iflag &= (ISTRIP | IGNBRK ); 230*c18ec02fSPetter Reinholdtsen tio.c_cflag &= ~(CSIZE | PARENB | IXON | IXOFF | IXANY); 231*c18ec02fSPetter Reinholdtsen tio.c_cflag |= (CS8 |CREAD) | (IXON|IXOFF|IXANY); 232*c18ec02fSPetter Reinholdtsen tio.c_lflag &= 0; 233*c18ec02fSPetter Reinholdtsen tio.c_cc[VMIN] = 1; 234*c18ec02fSPetter Reinholdtsen tio.c_cc[VTIME] = 0; 235*c18ec02fSPetter Reinholdtsen } else { 236*c18ec02fSPetter Reinholdtsen tio.c_iflag |= IGNPAR; 237*c18ec02fSPetter Reinholdtsen tio.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL | IXON | IXANY | IXOFF); 238*c18ec02fSPetter Reinholdtsen tio.c_lflag &= ~(ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHONL | IEXTEN); 239*c18ec02fSPetter Reinholdtsen tio.c_oflag &= ~OPOST; 240*c18ec02fSPetter Reinholdtsen tio.c_cc[VMIN] = 1; 241*c18ec02fSPetter Reinholdtsen tio.c_cc[VTIME] = 0; 242*c18ec02fSPetter Reinholdtsen } 243*c18ec02fSPetter Reinholdtsen 244*c18ec02fSPetter Reinholdtsen if (tcsetattr(fileno(stdin), TCSADRAIN, &tio) < 0) 245*c18ec02fSPetter Reinholdtsen lperror(LOG_ERR, "tcsetattr(stdin)"); 246*c18ec02fSPetter Reinholdtsen else if (tcsetattr(fileno(stdout), TCSADRAIN, &tio) < 0) 247*c18ec02fSPetter Reinholdtsen lperror(LOG_ERR, "tcsetattr(stdout)"); 248*c18ec02fSPetter Reinholdtsen else 249*c18ec02fSPetter Reinholdtsen _in_raw_mode = 1; 250*c18ec02fSPetter Reinholdtsen 251*c18ec02fSPetter Reinholdtsen return 0; 252*c18ec02fSPetter Reinholdtsen } 253*c18ec02fSPetter Reinholdtsen 254*c18ec02fSPetter Reinholdtsen static void 255*c18ec02fSPetter Reinholdtsen suspend_self(int restore_tty) 256*c18ec02fSPetter Reinholdtsen { 257*c18ec02fSPetter Reinholdtsen leave_raw_mode(); 258*c18ec02fSPetter Reinholdtsen 259*c18ec02fSPetter Reinholdtsen kill(getpid(), SIGTSTP); 260*c18ec02fSPetter Reinholdtsen 261*c18ec02fSPetter Reinholdtsen if (restore_tty) 262*c18ec02fSPetter Reinholdtsen enter_raw_mode(); 263*c18ec02fSPetter Reinholdtsen } 264*c18ec02fSPetter Reinholdtsen 265*c18ec02fSPetter Reinholdtsen static int 266*c18ec02fSPetter Reinholdtsen do_inbuf_actions(struct ipmi_intf *intf, char *in_buff, int len) 267*c18ec02fSPetter Reinholdtsen { 268*c18ec02fSPetter Reinholdtsen static int in_esc = 0; 269*c18ec02fSPetter Reinholdtsen static int last_was_cr = 1; 270*c18ec02fSPetter Reinholdtsen int i; 271*c18ec02fSPetter Reinholdtsen 272*c18ec02fSPetter Reinholdtsen for(i = 0; i < len ;) { 273*c18ec02fSPetter Reinholdtsen if (!in_esc) { 274*c18ec02fSPetter Reinholdtsen if (last_was_cr && 275*c18ec02fSPetter Reinholdtsen (in_buff[i] == intf->session->sol_escape_char)) { 276*c18ec02fSPetter Reinholdtsen in_esc = 1; 277*c18ec02fSPetter Reinholdtsen memmove(in_buff, in_buff + 1, len - i - 1); 278*c18ec02fSPetter Reinholdtsen len--; 279*c18ec02fSPetter Reinholdtsen continue; 280*c18ec02fSPetter Reinholdtsen } 281*c18ec02fSPetter Reinholdtsen } 282*c18ec02fSPetter Reinholdtsen if (in_esc) { 283*c18ec02fSPetter Reinholdtsen if (in_buff[i] == intf->session->sol_escape_char) { 284*c18ec02fSPetter Reinholdtsen in_esc = 0; 285*c18ec02fSPetter Reinholdtsen i++; 286*c18ec02fSPetter Reinholdtsen continue; 287*c18ec02fSPetter Reinholdtsen } 288*c18ec02fSPetter Reinholdtsen 289*c18ec02fSPetter Reinholdtsen switch (in_buff[i]) { 290*c18ec02fSPetter Reinholdtsen case '.': 291*c18ec02fSPetter Reinholdtsen printf("%c. [terminated ipmitool]\n", 292*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char); 293*c18ec02fSPetter Reinholdtsen return -1; 294*c18ec02fSPetter Reinholdtsen 295*c18ec02fSPetter Reinholdtsen case 'Z' - 64: 296*c18ec02fSPetter Reinholdtsen printf("%c^Z [suspend ipmitool]\n", 297*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char); 298*c18ec02fSPetter Reinholdtsen suspend_self(1); /* Restore tty back to raw */ 299*c18ec02fSPetter Reinholdtsen break; 300*c18ec02fSPetter Reinholdtsen 301*c18ec02fSPetter Reinholdtsen case 'X' - 64: 302*c18ec02fSPetter Reinholdtsen printf("%c^X [suspend ipmitool]\n", 303*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char); 304*c18ec02fSPetter Reinholdtsen suspend_self(0); /* Don't restore to raw mode */ 305*c18ec02fSPetter Reinholdtsen break; 306*c18ec02fSPetter Reinholdtsen 307*c18ec02fSPetter Reinholdtsen case '?': 308*c18ec02fSPetter Reinholdtsen printf("%c? [ipmitool help]\n", 309*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char); 310*c18ec02fSPetter Reinholdtsen print_escape_seq(intf); 311*c18ec02fSPetter Reinholdtsen break; 312*c18ec02fSPetter Reinholdtsen } 313*c18ec02fSPetter Reinholdtsen 314*c18ec02fSPetter Reinholdtsen memmove(in_buff, in_buff + 1, len - i - 1); 315*c18ec02fSPetter Reinholdtsen len--; 316*c18ec02fSPetter Reinholdtsen in_esc = 0; 317*c18ec02fSPetter Reinholdtsen 318*c18ec02fSPetter Reinholdtsen continue; 319*c18ec02fSPetter Reinholdtsen } 320*c18ec02fSPetter Reinholdtsen 321*c18ec02fSPetter Reinholdtsen last_was_cr = (in_buff[i] == '\r' || in_buff[i] == '\n'); 322*c18ec02fSPetter Reinholdtsen 323*c18ec02fSPetter Reinholdtsen i++; 324*c18ec02fSPetter Reinholdtsen } 325*c18ec02fSPetter Reinholdtsen 326*c18ec02fSPetter Reinholdtsen return len; 327*c18ec02fSPetter Reinholdtsen } 328*c18ec02fSPetter Reinholdtsen 329*c18ec02fSPetter Reinholdtsen 330*c18ec02fSPetter Reinholdtsen static void 331*c18ec02fSPetter Reinholdtsen do_terminal_cleanup(void) 332*c18ec02fSPetter Reinholdtsen { 333*c18ec02fSPetter Reinholdtsen if (_saved_winsize.ws_row > 0 && _saved_winsize.ws_col > 0) 334*c18ec02fSPetter Reinholdtsen ioctl(fileno(stdout), TIOCSWINSZ, &_saved_winsize); 335*c18ec02fSPetter Reinholdtsen 336*c18ec02fSPetter Reinholdtsen leave_raw_mode(); 337*c18ec02fSPetter Reinholdtsen 338*c18ec02fSPetter Reinholdtsen if (errno) 339*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Exiting due to error %d -> %s", 340*c18ec02fSPetter Reinholdtsen errno, strerror(errno)); 341*c18ec02fSPetter Reinholdtsen } 342*c18ec02fSPetter Reinholdtsen 343*c18ec02fSPetter Reinholdtsen static void 344*c18ec02fSPetter Reinholdtsen set_terminal_size(int rows, int cols) 345*c18ec02fSPetter Reinholdtsen { 346*c18ec02fSPetter Reinholdtsen struct winsize winsize; 347*c18ec02fSPetter Reinholdtsen 348*c18ec02fSPetter Reinholdtsen if (rows <= 0 || cols <= 0) 349*c18ec02fSPetter Reinholdtsen return; 350*c18ec02fSPetter Reinholdtsen 351*c18ec02fSPetter Reinholdtsen /* save initial winsize */ 352*c18ec02fSPetter Reinholdtsen ioctl(fileno(stdout), TIOCGWINSZ, &_saved_winsize); 353*c18ec02fSPetter Reinholdtsen 354*c18ec02fSPetter Reinholdtsen /* set new winsize */ 355*c18ec02fSPetter Reinholdtsen winsize.ws_row = rows; 356*c18ec02fSPetter Reinholdtsen winsize.ws_col = cols; 357*c18ec02fSPetter Reinholdtsen ioctl(fileno(stdout), TIOCSWINSZ, &winsize); 358*c18ec02fSPetter Reinholdtsen } 359*c18ec02fSPetter Reinholdtsen 360*c18ec02fSPetter Reinholdtsen static void 361*c18ec02fSPetter Reinholdtsen print_tsol_usage(void) 362*c18ec02fSPetter Reinholdtsen { 363*c18ec02fSPetter Reinholdtsen struct winsize winsize; 364*c18ec02fSPetter Reinholdtsen 365*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, "Usage: tsol [recvip] [port=NUM] [ro|rw] [rows=NUM] [cols=NUM] [altterm]"); 366*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, " recvip Receiver IP Address [default=local]"); 367*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, " port=NUM Receiver UDP Port [default=%d]", 368*c18ec02fSPetter Reinholdtsen IPMI_TSOL_DEF_PORT); 369*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, " ro|rw Set Read-Only or Read-Write [default=rw]"); 370*c18ec02fSPetter Reinholdtsen 371*c18ec02fSPetter Reinholdtsen ioctl(fileno(stdout), TIOCGWINSZ, &winsize); 372*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, " rows=NUM Set terminal rows [default=%d]", 373*c18ec02fSPetter Reinholdtsen winsize.ws_row); 374*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, " cols=NUM Set terminal columns [default=%d]", 375*c18ec02fSPetter Reinholdtsen winsize.ws_col); 376*c18ec02fSPetter Reinholdtsen 377*c18ec02fSPetter Reinholdtsen lprintf(LOG_NOTICE, " altterm Alternate terminal setup [default=off]"); 378*c18ec02fSPetter Reinholdtsen } 379*c18ec02fSPetter Reinholdtsen 380*c18ec02fSPetter Reinholdtsen int 381*c18ec02fSPetter Reinholdtsen ipmi_tsol_main(struct ipmi_intf * intf, int argc, char ** argv) 382*c18ec02fSPetter Reinholdtsen { 383*c18ec02fSPetter Reinholdtsen struct pollfd fds_wait[3], fds_data_wait[3], *fds; 384*c18ec02fSPetter Reinholdtsen struct sockaddr_in sin, myaddr, *sa_in; 385*c18ec02fSPetter Reinholdtsen socklen_t mylen; 386*c18ec02fSPetter Reinholdtsen char *recvip = NULL; 387*c18ec02fSPetter Reinholdtsen char out_buff[IPMI_BUF_SIZE * 8], in_buff[IPMI_BUF_SIZE]; 388*c18ec02fSPetter Reinholdtsen char buff[IPMI_BUF_SIZE + 4]; 389*c18ec02fSPetter Reinholdtsen int fd_socket, result, i; 390*c18ec02fSPetter Reinholdtsen int out_buff_fill, in_buff_fill; 391*c18ec02fSPetter Reinholdtsen int ip1, ip2, ip3, ip4; 392*c18ec02fSPetter Reinholdtsen int read_only = 0, rows = 0, cols = 0; 393*c18ec02fSPetter Reinholdtsen int port = IPMI_TSOL_DEF_PORT; 394*c18ec02fSPetter Reinholdtsen 395*c18ec02fSPetter Reinholdtsen if (strlen(intf->name) < 3 || strncmp(intf->name, "lan", 3) != 0) { 396*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Error: Tyan SOL is only available over lan interface"); 397*c18ec02fSPetter Reinholdtsen return -1; 398*c18ec02fSPetter Reinholdtsen } 399*c18ec02fSPetter Reinholdtsen 400*c18ec02fSPetter Reinholdtsen for (i = 0; i<argc; i++) { 401*c18ec02fSPetter Reinholdtsen if (sscanf(argv[i], "%d.%d.%d.%d", &ip1, &ip2, &ip3, &ip4) == 4) { 402*c18ec02fSPetter Reinholdtsen /* not free'd ...*/ 403*c18ec02fSPetter Reinholdtsen /* recvip = strdup(argv[i]); */ 404*c18ec02fSPetter Reinholdtsen recvip = argv[i]; 405*c18ec02fSPetter Reinholdtsen } 406*c18ec02fSPetter Reinholdtsen else if (sscanf(argv[i], "port=%d", &ip1) == 1) 407*c18ec02fSPetter Reinholdtsen port = ip1; 408*c18ec02fSPetter Reinholdtsen else if (sscanf(argv[i], "rows=%d", &ip1) == 1) 409*c18ec02fSPetter Reinholdtsen rows = ip1; 410*c18ec02fSPetter Reinholdtsen else if (sscanf(argv[i], "cols=%d", &ip1) == 1) 411*c18ec02fSPetter Reinholdtsen cols = ip1; 412*c18ec02fSPetter Reinholdtsen else if (strlen(argv[i]) == 2 && strncmp(argv[i], "ro", 2) == 0) 413*c18ec02fSPetter Reinholdtsen read_only = 1; 414*c18ec02fSPetter Reinholdtsen else if (strlen(argv[i]) == 2 && strncmp(argv[i], "rw", 2) == 0) 415*c18ec02fSPetter Reinholdtsen read_only = 0; 416*c18ec02fSPetter Reinholdtsen else if (strlen(argv[i]) == 7 && strncmp(argv[i], "altterm", 7) == 0) 417*c18ec02fSPetter Reinholdtsen _altterm = 1; 418*c18ec02fSPetter Reinholdtsen else if (strlen(argv[i]) == 4 && strncmp(argv[i], "help", 4) == 0) { 419*c18ec02fSPetter Reinholdtsen print_tsol_usage(); 420*c18ec02fSPetter Reinholdtsen return 0; 421*c18ec02fSPetter Reinholdtsen } 422*c18ec02fSPetter Reinholdtsen else { 423*c18ec02fSPetter Reinholdtsen print_tsol_usage(); 424*c18ec02fSPetter Reinholdtsen return 0; 425*c18ec02fSPetter Reinholdtsen } 426*c18ec02fSPetter Reinholdtsen } 427*c18ec02fSPetter Reinholdtsen 428*c18ec02fSPetter Reinholdtsen /* create udp socket to receive the packet */ 429*c18ec02fSPetter Reinholdtsen memset(&sin, 0, sizeof(sin)); 430*c18ec02fSPetter Reinholdtsen sin.sin_family = AF_INET; 431*c18ec02fSPetter Reinholdtsen sin.sin_port = htons(port); 432*c18ec02fSPetter Reinholdtsen 433*c18ec02fSPetter Reinholdtsen sa_in = (struct sockaddr_in *)&intf->session->addr; 434*c18ec02fSPetter Reinholdtsen result = inet_pton(AF_INET, (const char *)intf->session->hostname, 435*c18ec02fSPetter Reinholdtsen &sa_in->sin_addr); 436*c18ec02fSPetter Reinholdtsen 437*c18ec02fSPetter Reinholdtsen if (result <= 0) { 438*c18ec02fSPetter Reinholdtsen struct hostent *host = gethostbyname((const char *)intf->session->hostname); 439*c18ec02fSPetter Reinholdtsen if (host == NULL ) { 440*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Address lookup for %s failed", 441*c18ec02fSPetter Reinholdtsen intf->session->hostname); 442*c18ec02fSPetter Reinholdtsen return -1; 443*c18ec02fSPetter Reinholdtsen } 444*c18ec02fSPetter Reinholdtsen if (host->h_addrtype != AF_INET) { 445*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, 446*c18ec02fSPetter Reinholdtsen "Address lookup for %s failed. Got %s, expected IPv4 address.", 447*c18ec02fSPetter Reinholdtsen intf->session->hostname, 448*c18ec02fSPetter Reinholdtsen (host->h_addrtype == AF_INET6) ? "IPv6" : "Unknown"); 449*c18ec02fSPetter Reinholdtsen return (-1); 450*c18ec02fSPetter Reinholdtsen } 451*c18ec02fSPetter Reinholdtsen sa_in->sin_family = host->h_addrtype; 452*c18ec02fSPetter Reinholdtsen memcpy(&sa_in->sin_addr, host->h_addr, host->h_length); 453*c18ec02fSPetter Reinholdtsen } 454*c18ec02fSPetter Reinholdtsen 455*c18ec02fSPetter Reinholdtsen fd_socket = socket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); 456*c18ec02fSPetter Reinholdtsen if (fd_socket < 0) { 457*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Can't open port %d", port); 458*c18ec02fSPetter Reinholdtsen return -1; 459*c18ec02fSPetter Reinholdtsen } 460*c18ec02fSPetter Reinholdtsen if (-1 == bind(fd_socket, (struct sockaddr *)&sin, sizeof(sin))) { 461*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Failed to bind socket."); 462*c18ec02fSPetter Reinholdtsen close(fd_socket); 463*c18ec02fSPetter Reinholdtsen return -1; 464*c18ec02fSPetter Reinholdtsen } 465*c18ec02fSPetter Reinholdtsen 466*c18ec02fSPetter Reinholdtsen /* 467*c18ec02fSPetter Reinholdtsen * retrieve local IP address if not supplied on command line 468*c18ec02fSPetter Reinholdtsen */ 469*c18ec02fSPetter Reinholdtsen if (recvip == NULL) { 470*c18ec02fSPetter Reinholdtsen result = intf->open(intf); /* must connect first */ 471*c18ec02fSPetter Reinholdtsen if (result < 0) { 472*c18ec02fSPetter Reinholdtsen close(fd_socket); 473*c18ec02fSPetter Reinholdtsen return -1; 474*c18ec02fSPetter Reinholdtsen } 475*c18ec02fSPetter Reinholdtsen 476*c18ec02fSPetter Reinholdtsen mylen = sizeof(myaddr); 477*c18ec02fSPetter Reinholdtsen if (getsockname(intf->fd, (struct sockaddr *)&myaddr, &mylen) < 0) { 478*c18ec02fSPetter Reinholdtsen lperror(LOG_ERR, "getsockname failed"); 479*c18ec02fSPetter Reinholdtsen close(fd_socket); 480*c18ec02fSPetter Reinholdtsen return -1; 481*c18ec02fSPetter Reinholdtsen } 482*c18ec02fSPetter Reinholdtsen 483*c18ec02fSPetter Reinholdtsen recvip = inet_ntoa(myaddr.sin_addr); 484*c18ec02fSPetter Reinholdtsen if (recvip == NULL) { 485*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Unable to find local IP address"); 486*c18ec02fSPetter Reinholdtsen close(fd_socket); 487*c18ec02fSPetter Reinholdtsen return -1; 488*c18ec02fSPetter Reinholdtsen } 489*c18ec02fSPetter Reinholdtsen } 490*c18ec02fSPetter Reinholdtsen 491*c18ec02fSPetter Reinholdtsen printf("[Starting %sSOL with receiving address %s:%d]\n", 492*c18ec02fSPetter Reinholdtsen read_only ? "Read-only " : "", recvip, port); 493*c18ec02fSPetter Reinholdtsen 494*c18ec02fSPetter Reinholdtsen set_terminal_size(rows, cols); 495*c18ec02fSPetter Reinholdtsen enter_raw_mode(); 496*c18ec02fSPetter Reinholdtsen 497*c18ec02fSPetter Reinholdtsen /* 498*c18ec02fSPetter Reinholdtsen * talk to smdc to start Console redirect - IP address and port as parameter 499*c18ec02fSPetter Reinholdtsen * ipmitool -I lan -H 192.168.168.227 -U Administrator raw 0x30 0x06 0xC0 0xA8 0xA8 0x78 0x1A 0x0A 500*c18ec02fSPetter Reinholdtsen */ 501*c18ec02fSPetter Reinholdtsen result = ipmi_tsol_start(intf, recvip, port); 502*c18ec02fSPetter Reinholdtsen if (result < 0) { 503*c18ec02fSPetter Reinholdtsen lprintf(LOG_ERR, "Error starting SOL"); 504*c18ec02fSPetter Reinholdtsen close(fd_socket); 505*c18ec02fSPetter Reinholdtsen return -1; 506*c18ec02fSPetter Reinholdtsen } 507*c18ec02fSPetter Reinholdtsen 508*c18ec02fSPetter Reinholdtsen printf("[SOL Session operational. Use %c? for help]\n", 509*c18ec02fSPetter Reinholdtsen intf->session->sol_escape_char); 510*c18ec02fSPetter Reinholdtsen 511*c18ec02fSPetter Reinholdtsen gettimeofday(&_start_keepalive, 0); 512*c18ec02fSPetter Reinholdtsen 513*c18ec02fSPetter Reinholdtsen fds_wait[0].fd = fd_socket; 514*c18ec02fSPetter Reinholdtsen fds_wait[0].events = POLLIN; 515*c18ec02fSPetter Reinholdtsen fds_wait[0].revents = 0; 516*c18ec02fSPetter Reinholdtsen fds_wait[1].fd = fileno(stdin); 517*c18ec02fSPetter Reinholdtsen fds_wait[1].events = POLLIN; 518*c18ec02fSPetter Reinholdtsen fds_wait[1].revents = 0; 519*c18ec02fSPetter Reinholdtsen fds_wait[2].fd = -1; 520*c18ec02fSPetter Reinholdtsen fds_wait[2].events = 0; 521*c18ec02fSPetter Reinholdtsen fds_wait[2].revents = 0; 522*c18ec02fSPetter Reinholdtsen 523*c18ec02fSPetter Reinholdtsen fds_data_wait[0].fd = fd_socket; 524*c18ec02fSPetter Reinholdtsen fds_data_wait[0].events = POLLIN | POLLOUT; 525*c18ec02fSPetter Reinholdtsen fds_data_wait[0].revents = 0; 526*c18ec02fSPetter Reinholdtsen fds_data_wait[1].fd = fileno(stdin); 527*c18ec02fSPetter Reinholdtsen fds_data_wait[1].events = POLLIN; 528*c18ec02fSPetter Reinholdtsen fds_data_wait[1].revents = 0; 529*c18ec02fSPetter Reinholdtsen fds_data_wait[2].fd = fileno(stdout); 530*c18ec02fSPetter Reinholdtsen fds_data_wait[2].events = POLLOUT; 531*c18ec02fSPetter Reinholdtsen fds_data_wait[2].revents = 0; 532*c18ec02fSPetter Reinholdtsen 533*c18ec02fSPetter Reinholdtsen out_buff_fill = 0; 534*c18ec02fSPetter Reinholdtsen in_buff_fill = 0; 535*c18ec02fSPetter Reinholdtsen fds = fds_wait; 536*c18ec02fSPetter Reinholdtsen 537*c18ec02fSPetter Reinholdtsen for (;;) { 538*c18ec02fSPetter Reinholdtsen result = poll(fds, 3, 15*1000); 539*c18ec02fSPetter Reinholdtsen if (result < 0) 540*c18ec02fSPetter Reinholdtsen break; 541*c18ec02fSPetter Reinholdtsen 542*c18ec02fSPetter Reinholdtsen /* send keepalive packet */ 543*c18ec02fSPetter Reinholdtsen tsol_keepalive(intf); 544*c18ec02fSPetter Reinholdtsen 545*c18ec02fSPetter Reinholdtsen if ((fds[0].revents & POLLIN) && (sizeof(out_buff) > out_buff_fill)){ 546*c18ec02fSPetter Reinholdtsen socklen_t sin_len = sizeof(sin); 547*c18ec02fSPetter Reinholdtsen result = recvfrom(fd_socket, buff, sizeof(out_buff) - out_buff_fill + 4, 0, 548*c18ec02fSPetter Reinholdtsen (struct sockaddr *)&sin, &sin_len); 549*c18ec02fSPetter Reinholdtsen 550*c18ec02fSPetter Reinholdtsen /* read the data from udp socket, skip some bytes in the head */ 551*c18ec02fSPetter Reinholdtsen if((result - 4) > 0 ){ 552*c18ec02fSPetter Reinholdtsen int length = result - 4; 553*c18ec02fSPetter Reinholdtsen #if 1 554*c18ec02fSPetter Reinholdtsen length = (unsigned char)buff[2] & 0xff; 555*c18ec02fSPetter Reinholdtsen length *= 256; 556*c18ec02fSPetter Reinholdtsen length += ((unsigned char)buff[3] & 0xff); 557*c18ec02fSPetter Reinholdtsen if ((length <= 0) || (length > (result - 4))) 558*c18ec02fSPetter Reinholdtsen length = result - 4; 559*c18ec02fSPetter Reinholdtsen #endif 560*c18ec02fSPetter Reinholdtsen memcpy(out_buff + out_buff_fill, buff + 4, length); 561*c18ec02fSPetter Reinholdtsen out_buff_fill += length; 562*c18ec02fSPetter Reinholdtsen } 563*c18ec02fSPetter Reinholdtsen } 564*c18ec02fSPetter Reinholdtsen if ((fds[1].revents & POLLIN) && (sizeof(in_buff) > in_buff_fill)) { 565*c18ec02fSPetter Reinholdtsen result = read(fileno(stdin), in_buff + in_buff_fill, 566*c18ec02fSPetter Reinholdtsen sizeof(in_buff) - in_buff_fill); // read from keyboard 567*c18ec02fSPetter Reinholdtsen if (result > 0) { 568*c18ec02fSPetter Reinholdtsen int bytes; 569*c18ec02fSPetter Reinholdtsen bytes = do_inbuf_actions(intf, in_buff + in_buff_fill, result); 570*c18ec02fSPetter Reinholdtsen if(bytes < 0) { 571*c18ec02fSPetter Reinholdtsen result = ipmi_tsol_stop(intf, recvip, port); 572*c18ec02fSPetter Reinholdtsen do_terminal_cleanup(); 573*c18ec02fSPetter Reinholdtsen return result; 574*c18ec02fSPetter Reinholdtsen } 575*c18ec02fSPetter Reinholdtsen if (read_only) 576*c18ec02fSPetter Reinholdtsen bytes = 0; 577*c18ec02fSPetter Reinholdtsen in_buff_fill += bytes; 578*c18ec02fSPetter Reinholdtsen } 579*c18ec02fSPetter Reinholdtsen } 580*c18ec02fSPetter Reinholdtsen if ((fds[2].revents & POLLOUT) && out_buff_fill) { 581*c18ec02fSPetter Reinholdtsen result = write(fileno(stdout), out_buff, out_buff_fill); // to screen 582*c18ec02fSPetter Reinholdtsen if (result > 0) { 583*c18ec02fSPetter Reinholdtsen out_buff_fill -= result; 584*c18ec02fSPetter Reinholdtsen if (out_buff_fill) { 585*c18ec02fSPetter Reinholdtsen memmove(out_buff, out_buff + result, out_buff_fill); 586*c18ec02fSPetter Reinholdtsen } 587*c18ec02fSPetter Reinholdtsen } 588*c18ec02fSPetter Reinholdtsen } 589*c18ec02fSPetter Reinholdtsen if ((fds[0].revents & POLLOUT) && in_buff_fill) { 590*c18ec02fSPetter Reinholdtsen /* 591*c18ec02fSPetter Reinholdtsen * translate key and send that to SMDC using IPMI 592*c18ec02fSPetter Reinholdtsen * ipmitool -I lan -H 192.168.168.227 -U Administrator raw 0x30 0x03 0x04 0x1B 0x5B 0x43 593*c18ec02fSPetter Reinholdtsen */ 594*c18ec02fSPetter Reinholdtsen result = ipmi_tsol_send_keystroke(intf, in_buff, __min(in_buff_fill,14)); 595*c18ec02fSPetter Reinholdtsen if (result > 0) { 596*c18ec02fSPetter Reinholdtsen gettimeofday(&_start_keepalive, 0); 597*c18ec02fSPetter Reinholdtsen in_buff_fill -= result; 598*c18ec02fSPetter Reinholdtsen if (in_buff_fill) { 599*c18ec02fSPetter Reinholdtsen memmove(in_buff, in_buff + result, in_buff_fill); 600*c18ec02fSPetter Reinholdtsen } 601*c18ec02fSPetter Reinholdtsen } 602*c18ec02fSPetter Reinholdtsen } 603*c18ec02fSPetter Reinholdtsen fds = (in_buff_fill || out_buff_fill )? 604*c18ec02fSPetter Reinholdtsen fds_data_wait : fds_wait; 605*c18ec02fSPetter Reinholdtsen } 606*c18ec02fSPetter Reinholdtsen 607*c18ec02fSPetter Reinholdtsen return 0; 608*c18ec02fSPetter Reinholdtsen } 609