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