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