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