xref: /openbmc/ipmitool/lib/ipmi_tsol.c (revision c18ec02f3304ce2a889a50e378f07a4168af3884)
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