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