1 /*
2  * Copyright (c) 2007-2012 Pigeon Point Systems.  All Rights Reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * Redistribution of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *
11  * Redistribution in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * Neither the name of Pigeon Point Systems nor the names of
16  * contributors may be used to endorse or promote products derived
17  * from this software without specific prior written permission.
18  *
19  * This software is provided "AS IS," without a warranty of any kind.
20  * ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES,
21  * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A
22  * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED.
23  * PIGEON POINT SYSTEMS ("PPS") AND ITS LICENSORS SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
25  * OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.  IN NO EVENT WILL
26  * PPS OR ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA,
27  * OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR
28  * PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF
29  * LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE,
30  * EVEN IF PPS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31  */
32 #define _GNU_SOURCE 1
33 
34 /* Serial Interface, Terminal Mode plugin. */
35 
36 #include <stdio.h>
37 #include <fcntl.h>
38 #include <unistd.h>
39 #include <sys/ioctl.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 #include <string.h>
43 #include <time.h>
44 #include <ctype.h>
45 #include <sys/types.h>
46 #include <sys/stat.h>
47 #include <sys/poll.h>
48 #include <termios.h>
49 
50 #include <ipmitool/ipmi.h>
51 #include <ipmitool/ipmi_intf.h>
52 #include <ipmitool/helper.h>
53 #include <ipmitool/log.h>
54 
55 #if defined(HAVE_CONFIG_H)
56 # include <config.h>
57 #endif
58 
59 #define	IPMI_SERIAL_TIMEOUT		5
60 #define IPMI_SERIAL_RETRY		5
61 #define IPMI_SERIAL_MAX_RESPONSE	256
62 
63 /*
64  *	Terminal Mode interface is required to support 40 byte transactions.
65  */
66 #define IPMI_SERIAL_MAX_RQ_SIZE	37	/* 40 - 3 */
67 #define IPMI_SERIAL_MAX_RS_SIZE	36	/* 40 - 4 */
68 
69 /*
70  *	IPMB message header
71  */
72 struct ipmb_msg_hdr {
73 	unsigned char rsSA;
74 	unsigned char netFn;	/* NET FN | RS LUN */
75 	unsigned char csum1;
76 	unsigned char rqSA;
77 	unsigned char rqSeq;	/* RQ SEQ | RQ LUN */
78 	unsigned char cmd;
79 	unsigned char data[0];
80 };
81 
82 /*
83  *	Send Message command request for IPMB-format
84  */
85 struct ipmi_send_message_rq {
86 	unsigned char channel;
87 	struct ipmb_msg_hdr msg;
88 };
89 
90 /*
91  *	Get Message command response for IPMB-format
92  */
93 struct ipmi_get_message_rp {
94 	unsigned char completion;
95 	unsigned char channel;
96 	unsigned char netFn;
97 	unsigned char csum1;
98 	unsigned char rsSA;
99 	unsigned char rqSeq;
100 	unsigned char cmd;
101 	unsigned char data[0];
102 };
103 
104 /*
105  *	Terminal mode message header
106  */
107 struct serial_term_hdr {
108 	unsigned char netFn;
109 	unsigned char seq;
110 	unsigned char cmd;
111 };
112 
113 /*
114  *	Sending context
115  */
116 struct serial_term_request_ctx {
117 	uint8_t netFn;
118 	uint8_t sa;
119 	uint8_t seq;
120 	uint8_t cmd;
121 };
122 
123 /*
124  *	Table of supported baud rates
125  */
126 static const struct {
127 	int baudinit;
128 	int baudrate;
129 } rates[] = {
130 	{ B2400, 2400 },
131 	{ B9600, 9600 },
132 	{ B19200, 19200 },
133 	{ B38400, 38400 },
134 	{ B57600, 57600 },
135 	{ B115200, 115200 },
136 	{ B230400, 230400 },
137 #ifdef B460800
138 	{ B460800, 460800 },
139 #endif
140 };
141 
142 static int is_system;
143 
144 static int
145 ipmi_serial_term_open(struct ipmi_intf * intf)
146 {
147 	struct termios ti;
148 	unsigned int rate = 9600;
149 	char *p;
150 	int i;
151 
152 	if (!intf->devfile) {
153 		lprintf(LOG_ERR, "Serial device is not specified");
154 		return -1;
155 	}
156 
157 	is_system = 0;
158 
159 	/* check if baud rate is specified */
160 	if ((p = strchr(intf->devfile, ':'))) {
161 		char * pp;
162 
163 		/* separate device name from baud rate */
164 		*p++ = '\0';
165 
166 		/* check for second colon */
167 		if ((pp = strchr(p, ':'))) {
168 			/* this is needed to normally acquire baud rate */
169 			*pp++ = '\0';
170 
171 			/* check if it is a system interface */
172 			if (pp[0] == 'S' || pp[0] == 's') {
173 				is_system = 1;
174 			}
175 		}
176 
177 		if (str2uint(p, &rate)) {
178 			lprintf(LOG_ERR, "Invalid baud rate specified\n");
179 			return -1;
180 		}
181 	}
182 
183 	intf->fd = open(intf->devfile, O_RDWR | O_NONBLOCK, 0);
184 	if (intf->fd < 0) {
185 		lperror(LOG_ERR, "Could not open device at %s", intf->devfile);
186 		return -1;
187 	}
188 
189 	for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
190 		if (rates[i].baudrate == rate) {
191 			break;
192 		}
193 	}
194 	if (i >= sizeof(rates) / sizeof(rates[0])) {
195 		lprintf(LOG_ERR, "Unsupported baud rate %i specified", rate);
196 		return -1;
197 	}
198 
199 	tcgetattr(intf->fd, &ti);
200 
201 	cfsetispeed(&ti, rates[i].baudinit);
202 	cfsetospeed(&ti, rates[i].baudinit);
203 
204 	/* 8N1 */
205 	ti.c_cflag &= ~PARENB;
206 	ti.c_cflag &= ~CSTOPB;
207 	ti.c_cflag &= ~CSIZE;
208 	ti.c_cflag |= CS8;
209 
210 	/* enable the receiver and set local mode */
211 	ti.c_cflag |= (CLOCAL | CREAD);
212 
213 	/* no flow control */
214 	ti.c_cflag &= ~CRTSCTS;
215 	ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP
216 			| IXON | IXOFF | IXANY);
217 #ifdef IUCLC
218         /* Only disable uppercase-to-lowercase mapping on input for
219 	   platforms supporting the flag. */
220 	ti.c_iflag &= ~(IUCLC);
221 #endif
222 
223 	ti.c_oflag &= ~(OPOST);
224 	ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH);
225 
226 	/* set the new options for the port with flushing */
227 	tcsetattr(intf->fd, TCSAFLUSH, &ti);
228 
229 	if (intf->session->timeout == 0)
230 		intf->session->timeout = IPMI_SERIAL_TIMEOUT;
231 	if (intf->session->retry == 0)
232 		intf->session->retry = IPMI_SERIAL_RETRY;
233 
234 	intf->opened = 1;
235 
236 	return 0;
237 }
238 
239 static void
240 ipmi_serial_term_close(struct ipmi_intf * intf)
241 {
242 	if (intf->opened) {
243 		close(intf->fd);
244 		intf->fd = -1;
245 	}
246 	ipmi_intf_session_cleanup(intf);
247 	intf->opened = 0;
248 }
249 
250 /*
251  *	This function waits for incoming byte during timeout (ms).
252  */
253 static int
254 serial_wait_for_data(struct ipmi_intf * intf)
255 {
256 	int n;
257 	struct pollfd pfd;
258 
259 	pfd.fd = intf->fd;
260 	pfd.events = POLLIN;
261 	pfd.revents = 0;
262 
263 	n = poll(&pfd, 1, intf->session->timeout*1000);
264 	if (n < 0) {
265 		lperror(LOG_ERR, "Poll for serial data failed");
266 		return -1;
267 	} else if (!n) {
268 		return -1;
269 	}
270 	return 0;
271 }
272 
273 /*
274  *	Read a line from serial port
275  *	Returns > 0 if there is a line, < 0 on error or timeout
276  */
277 static int
278 serial_read_line(struct ipmi_intf * intf, char *str, int len)
279 {
280 	int rv, i;
281 
282 	*str = 0;
283 	i = 0;
284 	while (i < len) {
285 		if (serial_wait_for_data(intf)) {
286 			return -1;
287 		}
288 		rv = read(intf->fd, str + i, 1);
289 		if (rv < 0) {
290 			return -1;
291 		} else if (!rv) {
292 			lperror(LOG_ERR, "Serial read failed: %s", strerror(errno));
293 			return -1;
294 		}
295 		if (str[i] == '\n' || str[i] == '\r') {
296 			if (verbose > 4) {
297 				char c = str[i];
298 				str[i] = '\0';
299 				fprintf(stderr, "Received data: %s\n", str);
300 				str[i] = c;
301 			}
302 			return i + 1;
303 		} else {
304 			i++;
305 		}
306 	}
307 
308 	lprintf(LOG_ERR, "Serial data is too long");
309 	return -1;
310 }
311 
312 /*
313  *	Send zero-terminated string to serial port
314  *	Returns the string length or negative error code
315  */
316 static int
317 serial_write_line(struct ipmi_intf * intf, const char *str)
318 {
319 	int rv, cnt = 0;
320 	int cb = strlen(str);
321 
322 	while (cnt < cb) {
323 		rv = write(intf->fd, str + cnt, cb - cnt);
324 		if (rv < 0) {
325 			return -1;
326 		} else if (rv == 0) {
327 			return -1;
328 		}
329 		cnt += rv;
330 	}
331 
332 	return cnt;
333 }
334 
335 /*
336  *	Flush the buffers
337  */
338 static int
339 serial_flush(struct ipmi_intf * intf)
340 {
341 #if defined(TCFLSH)
342     return ioctl(intf->fd, TCFLSH, TCIOFLUSH);
343 #elif defined(TIOCFLUSH)
344     return ioctl(intf->fd, TIOCFLUSH);
345 #else
346 #   error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)"
347 #endif
348 
349 }
350 
351 /*
352  *	Receive IPMI response from the device
353  *	Len: buffer size
354  *	Returns: -1 or response lenth on success
355  */
356 static int
357 recv_response(struct ipmi_intf * intf, unsigned char *data, int len)
358 {
359 	char hex_rs[IPMI_SERIAL_MAX_RESPONSE * 3];
360 	int i, j, resp_len = 0;
361 	unsigned long rv;
362 	char *p, *pp;
363 	char ch, str_hex[3];
364 
365 	p = hex_rs;
366 	while (1) {
367 		if ((rv = serial_read_line(intf, p, sizeof(hex_rs) - resp_len)) < 0) {
368 			/* error */
369 			return -1;
370 		}
371 		p += rv;
372 		resp_len += rv;
373 		if (*(p - 2) == ']' && (*(p - 1) == '\n' || *(p - 1) == '\r')) {
374 			*p = 0;
375 			break;
376 		}
377 	}
378 
379 	p = strrchr(hex_rs, '[');
380 	if (!p) {
381 		lprintf(LOG_ERR, "Serial response is invalid");
382 		return -1;
383 	}
384 
385 	p++;
386 	pp = strchr(p, ']');
387 	if (!pp) {
388 		lprintf(LOG_ERR, "Serial response is invalid");
389 		return -1;
390 	}
391 	*pp = 0;
392 
393 	/* was it an error? */
394 	if (strncmp(p, "ERR ", 4) == 0) {
395 		serial_write_line(intf, "\r\r\r\r");
396 		sleep(1);
397 		serial_flush(intf);
398 		errno = 0;
399 		rv = strtoul(p + 4, &p, 16);
400 		if ((rv && rv < 0x100 && *p == '\0')
401 				|| (rv == 0 && !errno)) {
402 			/* The message didn't get it through. The upper
403 			   level will have to re-send */
404 			return 0;
405 		} else {
406 			lprintf(LOG_ERR, "Serial response is invalid");
407 			return -1;
408 		}
409 	}
410 
411 	/* this is needed for correct string to long conversion */
412 	str_hex[2] = 0;
413 
414 	/* parse the response */
415 	i = 0;
416 	j = 0;
417 	while (*p) {
418 		if (i >= len) {
419 			lprintf(LOG_ERR, "Serial response is too long(%d, %d)", i, len);
420 			return -1;
421 		}
422 		ch = *(p++);
423 		if (isxdigit(ch)) {
424 			str_hex[j++] = ch;
425 		} else {
426 			if (j == 1 || !isspace(ch)) {
427 				lprintf(LOG_ERR, "Serial response is invalid");
428 				return -1;
429 			}
430 		}
431 		if (j == 2) {
432 			unsigned long tmp;
433 			errno = 0;
434 			/* parse the hex number */
435 			tmp = strtoul(str_hex, NULL, 16);
436 			if ( tmp > 0xFF || ( !tmp && errno ) ) {
437 				lprintf(LOG_ERR, "Serial response is invalid");
438 				return -1;
439 			}
440 			data[i++] = tmp;
441 			j = 0;
442 		}
443 	}
444 
445 	return i;
446 }
447 
448 /*
449  *	Allocate sequence number for tracking
450  */
451 static uint8_t
452 serial_term_alloc_seq(void)
453 {
454 	static uint8_t seq = 0;
455 	if (++seq == 64) {
456 		seq = 0;
457 	}
458 	return seq;
459 }
460 
461 /*
462  *	Build IPMB message to be transmitted
463  */
464 static int
465 serial_term_build_msg(const struct ipmi_intf * intf,
466 		const struct ipmi_rq * req, uint8_t * msg, size_t max_len,
467 		struct serial_term_request_ctx * ctx, int * msg_len)
468 {
469 	uint8_t * data = msg, seq;
470 	struct serial_term_hdr * term_hdr = (struct serial_term_hdr *) msg;
471 	struct ipmi_send_message_rq * outer_rq = NULL;
472 	struct ipmi_send_message_rq * inner_rq = NULL;
473 	int bridging_level;
474 
475 	/* acquire bridging level */
476 	if (intf->target_addr && intf->target_addr != intf->my_addr) {
477 		if (intf->transit_addr != 0) {
478 			bridging_level = 2;
479 		} else {
480 			bridging_level = 1;
481 		}
482 	} else {
483 		bridging_level = 0;
484 	}
485 
486 	/* check overall packet length */
487 	if(req->msg.data_len + 3 + bridging_level * 8 > max_len) {
488 		lprintf(LOG_ERR, "ipmitool: Message data is too long");
489 		return -1;
490 	}
491 
492 	/* allocate new sequence number */
493 	seq = serial_term_alloc_seq() << 2;
494 
495 	/* check for bridging */
496 	if (bridging_level) {
497 		/* compose terminal message header */
498 		term_hdr->netFn = 0x18;
499 		term_hdr->seq = seq;
500 		term_hdr->cmd = 0x34;
501 
502 		/* set pointer to send message request data */
503 		outer_rq = (struct ipmi_send_message_rq *) (term_hdr + 1);
504 
505 		if (bridging_level == 2) {
506 			/* compose the outer send message request */
507 			outer_rq->channel = intf->transit_channel | 0x40;
508 			outer_rq->msg.rsSA = intf->transit_addr;
509 			outer_rq->msg.netFn = 0x18;
510 			outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn);
511 			outer_rq->msg.rqSA = intf->my_addr;
512 			outer_rq->msg.rqSeq = seq;
513 			outer_rq->msg.cmd = 0x34;
514 
515 			/* inner request is further */
516 			inner_rq = (outer_rq + 1);
517 		} else {
518 			/* there is only one header */
519 			inner_rq = outer_rq;
520 		}
521 
522 		/* compose the inner send message request */
523 		inner_rq->channel = intf->target_channel | 0x40;
524 		inner_rq->msg.rsSA = intf->target_addr;
525 		inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun;
526 		inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn);
527 		inner_rq->msg.rqSA = intf->my_addr;
528 		inner_rq->msg.rqSeq = seq;
529 		inner_rq->msg.cmd = req->msg.cmd;
530 
531 		/* check if interface is the system one */
532 		if (is_system) {
533 			/* need response to LUN 2 */
534 			outer_rq->msg.rqSeq |= 2;
535 
536 			/* do not track response */
537 			outer_rq->channel &= ~0x40;
538 
539 			/* restore BMC SA if bridging not to primary IPMB channel */
540 			if (outer_rq->channel) {
541 				outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR;
542 			}
543 		}
544 
545 		/* fill the second context */
546 		ctx[1].netFn = outer_rq->msg.netFn;
547 		ctx[1].sa = outer_rq->msg.rsSA;
548 		ctx[1].seq = outer_rq->msg.rqSeq;
549 		ctx[1].cmd = outer_rq->msg.cmd;
550 
551 		/* move write pointer */
552 		msg = (uint8_t *)(inner_rq + 1);
553 	} else {
554 		/* compose terminal message header */
555 		term_hdr->netFn = (req->msg.netfn << 2) | req->msg.lun;
556 		term_hdr->seq = seq;
557 		term_hdr->cmd = req->msg.cmd;
558 
559 		/* move write pointer */
560 		msg = (uint8_t *)(term_hdr + 1);
561 	}
562 
563 	/* fill the first context */
564 	ctx[0].netFn = term_hdr->netFn;
565 	ctx[0].seq = term_hdr->seq;
566 	ctx[0].cmd = term_hdr->cmd;
567 
568 	/* write request data */
569 	memcpy(msg, req->msg.data, req->msg.data_len);
570 
571 	/* move write pointer */
572 	msg += req->msg.data_len;
573 
574 	if (bridging_level) {
575 		/* write inner message checksum */
576 		*msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3);
577 
578 		/* check for double bridging */
579 		if (bridging_level == 2) {
580 			/* write outer message checksum */
581 			*msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4);
582 		}
583 	}
584 
585 
586 	/* save message length */
587 	*msg_len = msg - data;
588 
589 	/* return bridging level */
590 	return bridging_level;
591 }
592 
593 /*
594  *	Send message to serial port
595  */
596 static int
597 serial_term_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len)
598 {
599 	int i, size, tmp = 0;
600 	uint8_t * buf, * data;
601 
602 	if (verbose > 3) {
603 		fprintf(stderr, "Sending request:\n");
604 		fprintf(stderr, "  NetFN/rsLUN  = 0x%x\n", msg[0]);
605 		fprintf(stderr, "  rqSeq        = 0x%x\n", msg[1]);
606 		fprintf(stderr, "  cmd          = 0x%x\n", msg[2]);
607 		if (msg_len > 7) {
608 			fprintf(stderr, "  data_len     = %d\n", msg_len - 3);
609 			fprintf(stderr, "  data         = %s\n",
610 					buf2str(msg + 3, msg_len - 3));
611 		}
612 	}
613 
614 	if (verbose > 4) {
615 		fprintf(stderr, "Message data:\n");
616 		fprintf(stderr, " %s\n", buf2str(msg, msg_len));
617 	}
618 
619 	/* calculate required buffer size */
620 	size = msg_len * 2 + 4;
621 
622 	/* allocate buffer for output data */
623 	buf = data = (uint8_t *) alloca(size);
624 
625 	if (!buf) {
626 		lperror(LOG_ERR, "ipmitool: alloca error");
627 		return -1;
628 	}
629 
630 	/* start character */
631 	*buf++ = '[';
632 
633 	/* body */
634 	for (i = 0; i < msg_len; i++) {
635 		buf += sprintf( buf, "%02x", msg[i]);
636 	}
637 
638 	/* stop character */
639 	*buf++ = ']';
640 
641 	/* carriage return */
642 	*buf++ = '\r';
643 
644 	/* line feed */
645 	*buf++ = '\n';
646 
647 	/* write data to serial port */
648 	tmp = write(intf->fd, data, size);
649 	if (tmp <= 0) {
650 		lperror(LOG_ERR, "ipmitool: write error");
651 		return -1;
652 	}
653 
654 	return 0;
655 }
656 
657 /*
658  *	Wait for request response
659  */
660 static int
661 serial_term_wait_response(struct ipmi_intf * intf,
662 		struct serial_term_request_ctx * req_ctx,
663 		uint8_t * msg, size_t max_len)
664 {
665 	struct serial_term_hdr * hdr = (struct serial_term_hdr *) msg;
666 	int msg_len;
667 
668 	/* wait for response(s) */
669 	do {
670 		/* receive message */
671 		msg_len = recv_response(intf, msg, max_len);
672 
673 		/* check if valid message received  */
674 		if (msg_len > 0) {
675 			/* validate message size */
676 			if (msg_len < 4) {
677 				/* either bad response or non-related message */
678 				continue;
679 			}
680 
681 			/* check for the waited response */
682 			if (hdr->netFn == (req_ctx->netFn|4)
683 					&& (hdr->seq & ~3) == req_ctx->seq
684 					&& hdr->cmd == req_ctx->cmd) {
685 				/* check if something new has been parsed */
686 				if (verbose > 3) {
687 					fprintf(stderr, "Got response:\n");
688 					fprintf(stderr, "  NetFN/rsLUN     = 0x%x\n", msg[0]);
689 					fprintf(stderr, "  rqSeq/Bridge    = 0x%x\n", msg[1]);
690 					fprintf(stderr, "  cmd             = 0x%x\n", msg[2]);
691 					fprintf(stderr, "  completion code = 0x%x\n", msg[3]);
692 					if (msg_len > 8) {
693 						fprintf(stderr, "  data_len        = %d\n",
694 								msg_len - 4);
695 						fprintf(stderr, "  data            = %s\n",
696 								buf2str(msg + 4, msg_len - 4));
697 					}
698 				}
699 
700 				/* move to start from completion code */
701 				memmove(msg, hdr + 1, msg_len - sizeof (*hdr));
702 
703 				/* the waited one */
704 				return msg_len - sizeof (*hdr);
705 			}
706 		}
707 	} while (msg_len > 0);
708 
709 	return 0;
710 }
711 
712 /*
713  *	Get message from receive message queue
714  */
715 static int
716 serial_term_get_message(struct ipmi_intf * intf,
717 		struct serial_term_request_ctx * req_ctx,
718 		uint8_t * msg, size_t max_len)
719 {
720 	uint8_t data[IPMI_SERIAL_MAX_RESPONSE];
721 	struct serial_term_request_ctx tmp_ctx;
722 	struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data;
723 	struct serial_term_hdr hdr;
724 	clock_t start, tm;
725 	int rv, netFn, rqSeq;
726 
727 	start = clock();
728 
729 	do {
730 		/* fill-in request context */
731 		tmp_ctx.netFn = 0x18;
732 		tmp_ctx.seq = serial_term_alloc_seq() << 2;
733 		tmp_ctx.cmd = 0x33;
734 
735 		/* fill-in request data */
736 		hdr.netFn = tmp_ctx.netFn;
737 		hdr.seq = tmp_ctx.seq;
738 		hdr.cmd = tmp_ctx.cmd;
739 
740 		/* send request */
741 		serial_flush(intf);
742 		serial_term_send_msg(intf, (uint8_t *) &hdr, 3);
743 
744 		/* wait for response */
745 		rv = serial_term_wait_response(intf, &tmp_ctx, data, sizeof (data));
746 
747 		/* check for IO error or timeout */
748 		if (rv <= 0) {
749 			return rv;
750 		}
751 
752 		netFn = (req_ctx->netFn & ~3)|(req_ctx->seq & 3)|4;
753 		rqSeq = req_ctx->seq & ~3;
754 
755 		/* check completion code */
756 		if (rp->completion == 0) {
757 			/* check for the waited response */
758 			if (rp->netFn == netFn
759 					&& rp->rsSA == req_ctx->sa
760 					&& rp->rqSeq == rqSeq
761 					&& rp->cmd == req_ctx->cmd) {
762 				/* copy the rest of message */
763 				memcpy(msg, rp + 1, rv - sizeof (*rp) - 1);
764 				return rv - sizeof (*rp) - 1;
765 			}
766 		} else if (rp->completion != 0x80) {
767 			return 0;
768 		}
769 
770 		tm = clock() - start;
771 
772 		tm /= CLOCKS_PER_SEC;
773 	} while (tm < intf->session->timeout);
774 
775 	return 0;
776 }
777 
778 static struct ipmi_rs *
779 ipmi_serial_term_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req)
780 {
781 	static struct ipmi_rs rsp;
782 	uint8_t msg[IPMI_SERIAL_MAX_RESPONSE], * resp = msg;
783 	struct serial_term_request_ctx req_ctx[2];
784 	int retry, rv, msg_len, bridging_level;
785 
786 	if (!intf->opened && intf->open && intf->open(intf) < 0) {
787 		return NULL;
788 	}
789 
790 	/* Send the message and receive the answer */
791 	for (retry = 0; retry < intf->session->retry; retry++) {
792 		/* build output message */
793 		bridging_level = serial_term_build_msg(intf, req, msg,
794 				sizeof (msg), req_ctx, &msg_len);
795 		if (msg_len < 0) {
796 			return NULL;
797 		}
798 
799 		/* send request */
800 		serial_flush(intf);
801 		serial_term_send_msg(intf, msg, msg_len);
802 
803 		/* wait for response */
804 		rv = serial_term_wait_response(intf, &req_ctx[0], msg, sizeof (msg));
805 
806 		/* check for IO error */
807 		if (rv < 0) {
808 			return NULL;
809 		}
810 
811 		/* check for timeout */
812 		if (rv == 0) {
813 			continue;
814 		}
815 
816 		/* check for bridging */
817 		if (bridging_level && msg[0] == 0) {
818 			/* in the case of payload interface we check receive message queue */
819 			if (is_system) {
820 				/* check message flags */
821 				rv = serial_term_get_message(intf, &req_ctx[1],
822 						msg, sizeof (msg));
823 
824 				/* check for IO error */
825 				if (rv < 0) {
826 					return NULL;
827 				}
828 
829 				/* check for timeout */
830 				if (rv == 0) {
831 					continue;
832 				}
833 			/* check if response for inner request is not encapsulated */
834 			} else if (rv == 1) {
835 				/* wait for response for inner request */
836 				rv = serial_term_wait_response(intf, &req_ctx[1],
837 						msg, sizeof (msg));
838 
839 				/* check for IO error */
840 				if (rv < 0) {
841 					return NULL;
842 				}
843 
844 				/* check for timeout */
845 				if (rv == 0) {
846 					continue;
847 				}
848 			} else {
849 				/* skip outer level header */
850 				resp = msg + sizeof (struct ipmb_msg_hdr) + 1;
851 				/* decrement response size */
852 				rv -=  + sizeof (struct ipmb_msg_hdr) + 2;
853 			}
854 
855 			/* check response size */
856 			if (resp[0] == 0 && bridging_level == 2 && rv < 8) {
857 				lprintf(LOG_ERR, "ipmitool: Message response is too short");
858 				/* invalid message length */
859 				return NULL;
860 			}
861 		}
862 
863 		/* check for double bridging */
864 		if (bridging_level == 2 && resp[0] == 0) {
865 			/* get completion code */
866 			rsp.ccode = resp[7];
867 			rsp.data_len = rv - 9;
868 			memcpy(rsp.data, resp + 8, rsp.data_len);
869 		} else {
870 			rsp.ccode = resp[0];
871 			rsp.data_len = rv - 1;
872 			memcpy(rsp.data, resp + 1, rsp.data_len);
873 		}
874 
875 		/* return response */
876 		return &rsp;
877 	}
878 
879 	/* no valid response */
880 	return NULL;
881 }
882 
883 static int
884 ipmi_serial_term_setup(struct ipmi_intf * intf)
885 {
886 	intf->session = malloc(sizeof(struct ipmi_session));
887 	if (intf->session == NULL) {
888 		lprintf(LOG_ERR, "ipmitool: malloc failure");
889 		return -1;
890 	}
891 
892 	memset(intf->session, 0, sizeof(struct ipmi_session));
893 
894 	/* setup default LAN maximum request and response sizes */
895 	intf->max_request_data_size = IPMI_SERIAL_MAX_RQ_SIZE;
896 	intf->max_response_data_size = IPMI_SERIAL_MAX_RS_SIZE;
897 	return 0;
898 }
899 
900 int
901 ipmi_serial_term_set_my_addr(struct ipmi_intf * intf, uint8_t addr)
902 {
903 	intf->my_addr = addr;
904 	return 0;
905 }
906 
907 struct ipmi_intf ipmi_serial_term_intf = {
908 	.name = "serial-terminal",
909 	.desc = "Serial Interface, Terminal Mode",
910 	.setup = ipmi_serial_term_setup,
911 	.open = ipmi_serial_term_open,
912 	.close = ipmi_serial_term_close,
913 	.sendrecv = ipmi_serial_term_send_cmd,
914 	.set_my_addr = ipmi_serial_term_set_my_addr
915 };
916