1 /*
2  * Copyright (c) 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, Basic Mode plugin. */
34 
35 #include <stdio.h>
36 #include <fcntl.h>
37 #include <time.h>
38 #include <unistd.h>
39 #include <sys/ioctl.h>
40 #include <errno.h>
41 #include <stdlib.h>
42 #include <string.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 SERIAL_BM_MAX_MSG_SIZE	47
59 #define SERIAL_BM_MAX_RQ_SIZE	33	/* 40 - 7 */
60 #define SERIAL_BM_MAX_RS_SIZE	32	/* 40 - 8 */
61 #define	SERIAL_BM_TIMEOUT	5
62 #define SERIAL_BM_RETRY_COUNT	5
63 #define SERIAL_BM_MAX_BUFFER_SIZE 250
64 
65 #define BM_START		0xA0
66 #define BM_STOP			0xA5
67 #define BM_HANDSHAKE	0xA6
68 #define BM_ESCAPE		0xAA
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  *	State for the received message
107  */
108 enum {
109 	MSG_NONE,
110 	MSG_IN_PROGRESS,
111 	MSG_DONE
112 };
113 
114 /*
115  *	Message parsing context
116  */
117 struct  serial_bm_parse_ctx{
118 	int state;
119 	uint8_t * msg;
120 	size_t msg_len;
121 	size_t max_len;
122 	int escape;
123 };
124 
125 /*
126  *	Receiving context
127  */
128 struct serial_bm_recv_ctx {
129 	char buffer[SERIAL_BM_MAX_BUFFER_SIZE];
130 	size_t buffer_size;
131 	size_t max_buffer_size;
132 };
133 
134 /*
135  *	Sending context
136  */
137 struct serial_bm_request_ctx {
138 	uint8_t rsSA;
139 	uint8_t netFn;
140 	uint8_t rqSA;
141 	uint8_t rqSeq;
142 	uint8_t cmd;
143 };
144 
145 /*
146  *	Table of supported baud rates
147  */
148 static const struct {
149 	int baudinit;
150 	int baudrate;
151 } rates[] = {
152 	{ B2400, 2400 },
153 	{ B9600, 9600 },
154 	{ B19200, 19200 },
155 	{ B38400, 38400 },
156 	{ B57600, 57600 },
157 	{ B115200, 115200 },
158 	{ B230400, 230400 },
159 #ifdef B460800
160 	{ B460800, 460800 },
161 #endif
162 };
163 
164 /*
165  *	Table of special characters
166  */
167 static const struct {
168 	uint8_t character;
169 	uint8_t escape;
170 } characters[] = {
171 	{ BM_START,		0xB0 },	/* start */
172 	{ BM_STOP,		0xB5 },	/* stop */
173 	{ BM_HANDSHAKE,	0xB6 },	/* packet handshake */
174 	{ BM_ESCAPE,	0xBA },	/* data escape */
175 	{ 0x1B, 0x3B }			/* escape */
176 };
177 
178 static int is_system;
179 
180 /*
181  *	Setup serial interface
182  */
183 static int
184 serial_bm_setup(struct ipmi_intf * intf)
185 {
186 	intf->session = malloc(sizeof(struct ipmi_session));
187 	if (intf->session == NULL) {
188 		lprintf(LOG_ERR, "ipmitool: malloc failure");
189 		return -1;
190 	}
191 	memset(intf->session, 0, sizeof(struct ipmi_session));
192 
193 	/* setup default LAN maximum request and response sizes */
194 	intf->max_request_data_size = SERIAL_BM_MAX_RQ_SIZE;
195 	intf->max_response_data_size = SERIAL_BM_MAX_RS_SIZE;
196 	return 0;
197 }
198 
199 /*
200  *	Open serial interface
201  */
202 static int
203 serial_bm_open(struct ipmi_intf * intf)
204 {
205 	struct termios ti;
206 	unsigned int rate = 9600;
207 	char *p;
208 	int i;
209 
210 	if (!intf->devfile) {
211 		lprintf(LOG_ERR, "Serial device is not specified");
212 		return -1;
213 	}
214 
215 	is_system = 0;
216 
217 	/* check if baud rate is specified */
218 	if ((p = strchr(intf->devfile, ':'))) {
219 		char * pp;
220 
221 		/* separate device name from baud rate */
222 		*p++ = '\0';
223 
224 		/* check for second colon */
225 		if ((pp = strchr(p, ':'))) {
226 			/* this is needed to normally acquire baud rate */
227 			*pp++ = '\0';
228 
229 			/* check if it is a system interface */
230 			if (pp[0] == 'S' || pp[0] == 's') {
231 				is_system = 1;
232 			}
233 		}
234 
235 		if (str2uint(p, &rate)) {
236 			lprintf(LOG_ERR, "Invalid baud rate specified\n");
237 			return -1;
238 		}
239 	}
240 
241 	intf->fd = open(intf->devfile, O_RDWR | O_NONBLOCK, 0);
242 	if (intf->fd < 0) {
243 		lperror(LOG_ERR, "Could not open device at %s", intf->devfile);
244 		return -1;
245 	}
246 
247 	for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
248 		if (rates[i].baudrate == rate) {
249 			break;
250 		}
251 	}
252 	if (i >= sizeof(rates) / sizeof(rates[0])) {
253 		lprintf(LOG_ERR, "Unsupported baud rate %i specified", rate);
254 		return -1;
255 	}
256 
257 	tcgetattr(intf->fd, &ti);
258 
259 	cfsetispeed(&ti, rates[i].baudinit);
260 	cfsetospeed(&ti, rates[i].baudinit);
261 
262 	/* 8N1 */
263 	ti.c_cflag &= ~PARENB;
264 	ti.c_cflag &= ~CSTOPB;
265 	ti.c_cflag &= ~CSIZE;
266 	ti.c_cflag |= CS8;
267 
268 	/* enable the receiver and set local mode */
269 	ti.c_cflag |= (CLOCAL | CREAD);
270 
271 	/* no flow control */
272 	ti.c_cflag &= ~CRTSCTS;
273 	ti.c_iflag &= ~(IGNBRK | IGNCR | INLCR | ICRNL | INPCK | ISTRIP
274 			| IXON | IXOFF | IXANY);
275 #ifdef IUCLC
276         /* Only disable uppercase-to-lowercase mapping on input for
277 	   platforms supporting the flag. */
278 	ti.c_iflag &= ~(IUCLC);
279 #endif
280 
281 
282 	ti.c_oflag &= ~(OPOST);
283 	ti.c_lflag &= ~(ICANON | ISIG | ECHO | ECHONL | NOFLSH);
284 
285 	/* set the new options for the port with flushing */
286 	tcsetattr(intf->fd, TCSAFLUSH, &ti);
287 
288 	if (intf->session->timeout == 0)
289 		intf->session->timeout = SERIAL_BM_TIMEOUT;
290 	if (intf->session->retry == 0)
291 		intf->session->retry = SERIAL_BM_RETRY_COUNT;
292 
293 	intf->opened = 1;
294 
295 	return 0;
296 }
297 
298 /*
299  *	Close serial interface
300  */
301 static void
302 serial_bm_close(struct ipmi_intf * intf)
303 {
304 	if (intf->opened) {
305 		close(intf->fd);
306 		intf->fd = -1;
307 	}
308 	ipmi_intf_session_cleanup(intf);
309 	intf->opened = 0;
310 }
311 
312 /*
313  *	Allocate sequence number for tracking
314  */
315 static uint8_t
316 serial_bm_alloc_seq(void)
317 {
318 	static uint8_t seq = 0;
319 	if (++seq == 64) {
320 		seq = 0;
321 	}
322 	return seq;
323 }
324 
325 /*
326  *	Flush the buffers
327  */
328 static int
329 serial_bm_flush(struct ipmi_intf * intf)
330 {
331 #if defined(TCFLSH)
332     return ioctl(intf->fd, TCFLSH, TCIOFLUSH);
333 #elif defined(TIOCFLUSH)
334     return ioctl(intf->fd, TIOCFLUSH);
335 #else
336 #   error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)"
337 #endif
338 }
339 
340 /*
341  *	Return escaped character for the given one
342  */
343 static inline uint8_t
344 serial_bm_get_escaped_char(uint8_t c)
345 {
346 	int i;
347 
348 	for (i = 0; i < 5; i++) {
349 		if (characters[i].character == c) {
350 			return characters[i].escape;
351 		}
352 	}
353 
354 	return c;
355 }
356 
357 /*
358  *	Return unescaped character for the given one
359  */
360 static inline uint8_t
361 serial_bm_get_unescaped_char(uint8_t c)
362 {
363 	int i;
364 
365 	for (i = 0; i < 5; i++) {
366 		if (characters[i].escape == c) {
367 			return characters[i].character;
368 		}
369 	}
370 
371 	return c;
372 }
373 
374 /*
375  *	Send message to serial port
376  */
377 static int
378 serial_bm_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len)
379 {
380 	int i, size, tmp = 0;
381 	uint8_t * buf, * data;
382 
383 	if (verbose > 3) {
384 		fprintf(stderr, "Sending request:\n");
385 		fprintf(stderr, "  rsSA         = 0x%x\n", msg[0]);
386 		fprintf(stderr, "  NetFN/rsLUN  = 0x%x\n", msg[1]);
387 		fprintf(stderr, "  rqSA         = 0x%x\n", msg[3]);
388 		fprintf(stderr, "  rqSeq/rqLUN  = 0x%x\n", msg[4]);
389 		fprintf(stderr, "  cmd          = 0x%x\n", msg[5]);
390 		if (msg_len > 7) {
391 			fprintf(stderr, "  data_len     = %d\n", msg_len - 7);
392 			fprintf(stderr, "  data         = %s\n",
393 					buf2str(msg + 6, msg_len - 7));
394 		}
395 	}
396 
397 	if (verbose > 4) {
398 		fprintf(stderr, "Message data:\n");
399 		fprintf(stderr, " %s\n", buf2str(msg, msg_len));
400 	}
401 
402 	/* calculate escaped characters number */
403 	for (i = 0; i < msg_len; i++) {
404 		if (serial_bm_get_escaped_char(msg[i]) != msg[i]) {
405 			tmp++;
406 		}
407 	}
408 
409 	/* calculate required buffer size */
410 	size = msg_len + tmp + 2;
411 
412 	/* allocate buffer for output data */
413 	buf = data = (uint8_t *) alloca(size);
414 
415 	if (!buf) {
416 		lperror(LOG_ERR, "ipmitool: alloca error");
417 		return -1;
418 	}
419 
420 	/* start character */
421 	*buf++ = 0xA0;
422 
423 	for (i = 0; i < msg_len; i++) {
424 		tmp = serial_bm_get_escaped_char(msg[i]);
425 		if (tmp != msg[i]) {
426 			*buf++ = 0xAA;
427 		}
428 
429 		*buf++ = tmp;
430 	}
431 
432 	/* stop character */
433 	*buf++ = 0xA5;
434 
435 	if (verbose > 5) {
436 		fprintf(stderr, "Sent serial data:\n %s\n", buf2str(data, size));
437 	}
438 
439 	/* write data to serial port */
440 	tmp = write(intf->fd, data, size);
441 	if (tmp <= 0) {
442 		lperror(LOG_ERR, "ipmitool: write error");
443 		return -1;
444 	}
445 
446 	return 0;
447 }
448 
449 /*
450  *	This function waits for incoming data
451  */
452 static int
453 serial_bm_wait_for_data(struct ipmi_intf * intf)
454 {
455 	int n;
456 	struct pollfd pfd;
457 
458 	pfd.fd = intf->fd;
459 	pfd.events = POLLIN;
460 	pfd.revents = 0;
461 
462 	n = poll(&pfd, 1, intf->session->timeout*1000);
463 	if (n < 0) {
464 		lperror(LOG_ERR, "Poll for serial data failed");
465 		return -1;
466 	} else if (!n) {
467 		return -1;
468 	}
469 	return 0;
470 }
471 
472 /*
473  *	This function parses incoming data in basic mode format to IPMB message
474  */
475 static int
476 serial_bm_parse_buffer(const uint8_t * data, int data_len,
477 		struct serial_bm_parse_ctx * ctx)
478 {
479 	int i, tmp;
480 
481 	for (i = 0; i < data_len; i++) {
482 		/* check for start of new message */
483 		if (data[i] == BM_START) {
484 			ctx->state = MSG_IN_PROGRESS;
485 			ctx->escape = 0;
486 			ctx->msg_len = 0;
487 		/* check if message is not started */
488 		} else if (ctx->state != MSG_IN_PROGRESS) {
489 			/* skip character */
490 			continue;
491 		/* continue escape sequence */
492 		} else	if (ctx->escape) {
493 			/* get original character */
494 			tmp = serial_bm_get_unescaped_char(data[i]);
495 
496 			/* check if not special character */
497 			if (tmp == data[i]) {
498 				lprintf(LOG_ERR, "ipmitool: bad response");
499 				/* reset message state */
500 				ctx->state = MSG_NONE;
501 				continue;
502 			}
503 
504 			/* check message length */
505 			if (ctx->msg_len >= ctx->max_len) {
506 				lprintf(LOG_ERR, "ipmitool: response is too long");
507 				/* reset message state */
508 				ctx->state = MSG_NONE;
509 				continue;
510 			}
511 
512 			/* add parsed character */
513 			ctx->msg[ctx->msg_len++] = tmp;
514 
515 			/* clear escape flag */
516 			ctx->escape = 0;
517 		/* check for escape character */
518 		} else if (data[i] == BM_ESCAPE) {
519 			ctx->escape = 1;
520 			continue;
521 		/* check for stop character */
522 		} else if (data[i] == BM_STOP) {
523 			ctx->state = MSG_DONE;
524 			return i + 1;
525 		/* check for packet handshake character */
526 		} else if (data[i] == BM_HANDSHAKE) {
527 			/* just skip it */
528 			continue;
529 		} else {
530 			/* check message length */
531 			if (ctx->msg_len >= ctx->max_len) {
532 				lprintf(LOG_ERR, "ipmitool: response is too long");
533 				return -1;
534 			}
535 
536 			/* add parsed character */
537 			ctx->msg[ctx->msg_len++] = data[i];
538 		}
539 	}
540 
541 	/* return number of parsed characters */
542 	return i;
543 }
544 
545 /*
546  *	Read and parse data from serial port
547  */
548 static int
549 serial_bm_recv_msg(struct ipmi_intf * intf,
550 		struct serial_bm_recv_ctx * recv_ctx,
551 		uint8_t * msg_data, size_t msg_len)
552 {
553 	struct serial_bm_parse_ctx parse_ctx;
554 	int rv;
555 
556 	parse_ctx.state = MSG_NONE;
557 	parse_ctx.msg = msg_data;
558 	parse_ctx.max_len = msg_len;
559 
560 	do {
561 		/* wait for data in the port */
562 		if (serial_bm_wait_for_data(intf)) {
563 			return 0;
564 		}
565 
566 		/* read data into buffer */
567 		rv = read(intf->fd, recv_ctx->buffer + recv_ctx->buffer_size,
568 				recv_ctx->max_buffer_size - recv_ctx->buffer_size);
569 
570 		if (rv < 0) {
571 			lperror(LOG_ERR, "ipmitool: read error");
572 			return -1;
573 		}
574 
575 		if (verbose > 5) {
576 			fprintf(stderr, "Received serial data:\n %s\n",
577 					buf2str(recv_ctx->buffer + recv_ctx->buffer_size, rv));
578 		}
579 
580 		/* increment buffer size */
581 		recv_ctx->buffer_size += rv;
582 
583 		/* parse buffer */
584 		rv = serial_bm_parse_buffer(recv_ctx->buffer,
585 				recv_ctx->buffer_size, &parse_ctx);
586 
587 		if (rv < recv_ctx->buffer_size) {
588 			/* move non-parsed part of the buffer to the beginning */
589 			memmove(recv_ctx->buffer, recv_ctx->buffer + rv,
590 					recv_ctx->buffer_size - rv);
591 		}
592 
593 		/* decrement buffer size */
594 		recv_ctx->buffer_size -= rv;
595 	} while (parse_ctx.state != MSG_DONE);
596 
597 	if (verbose > 4) {
598 		printf("Received message:\n %s\n",
599 				buf2str(msg_data, parse_ctx.msg_len));
600 	}
601 
602 	/* received a message */
603 	return parse_ctx.msg_len;
604 }
605 
606 /*
607  *	Build IPMB message to be transmitted
608  */
609 static int
610 serial_bm_build_msg(const struct ipmi_intf * intf,
611 		const struct ipmi_rq * req, uint8_t * msg, size_t max_len,
612 		struct serial_bm_request_ctx * ctx, int * msg_len
613 		)
614 {
615 	uint8_t * data = msg, seq;
616 	struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg;
617 	struct ipmi_send_message_rq * inner_rq = NULL, * outer_rq = NULL;
618 	int bridging_level;
619 
620 	/* acquire bridging level */
621 	if (intf->target_addr && intf->target_addr != intf->my_addr) {
622 		if (intf->transit_addr != 0) {
623 			bridging_level = 2;
624 		} else {
625 			bridging_level = 1;
626 		}
627 	} else {
628 		bridging_level = 0;
629 	}
630 
631 	/* check overall packet length */
632 	if(req->msg.data_len + 7 + bridging_level * 8 > max_len) {
633 		lprintf(LOG_ERR, "ipmitool: Message data is too long");
634 		return -1;
635 	}
636 
637 	/* allocate new sequence number */
638 	seq = serial_bm_alloc_seq() << 2;
639 
640 	if (bridging_level) {
641 		/* compose send message request */
642 		hdr->netFn = 0x18;
643 		hdr->cmd = 0x34;
644 
645 		/* set pointer to send message request data */
646 		outer_rq = (struct ipmi_send_message_rq *) (hdr + 1);
647 
648 		/* compose the outer send message request */
649 		if (bridging_level == 2) {
650 			outer_rq->channel = intf->transit_channel | 0x40;
651 			outer_rq->msg.rsSA = intf->transit_addr;
652 			outer_rq->msg.netFn = 0x18;
653 			outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn);
654 			outer_rq->msg.rqSA = intf->my_addr;
655 			outer_rq->msg.rqSeq = seq;
656 			outer_rq->msg.cmd = 0x34;
657 
658 			/* inner send message request is further */
659 			inner_rq = (outer_rq + 1);
660 		} else {
661 			/* there is only outer send message reuest */
662 			inner_rq = outer_rq;
663 		}
664 
665 		/* compose the inner send message request */
666 		inner_rq->channel = intf->target_channel | 0x40;
667 		inner_rq->msg.rsSA = intf->target_addr;
668 		inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun;
669 		inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn);
670 		inner_rq->msg.rqSA = intf->my_addr;
671 		inner_rq->msg.rqSeq = seq;
672 		inner_rq->msg.cmd = req->msg.cmd;
673 
674 		/* check if interface is the system one */
675 		if (is_system) {
676 			/* need response to LUN 2 */
677 			outer_rq->msg.rqSeq |= 2;
678 
679 			/* do not track response */
680 			outer_rq->channel &= ~0x40;
681 
682 			/* restore BMC SA if bridging not to primary IPMB channel */
683 			if (outer_rq->channel) {
684 				outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR;
685 			}
686 		}
687 
688 		/* fill-in the second context */
689 		ctx[1].rsSA = outer_rq->msg.rsSA;
690 		ctx[1].netFn = outer_rq->msg.netFn;
691 		ctx[1].rqSA = outer_rq->msg.rqSA;
692 		ctx[1].rqSeq = outer_rq->msg.rqSeq;
693 		ctx[1].cmd = outer_rq->msg.cmd;
694 
695 		/* move write pointer */
696 		msg = (uint8_t *)(inner_rq + 1);
697 	} else {
698 		/* compose direct request */
699 		hdr->netFn = (req->msg.netfn << 2) | req->msg.lun;
700 		hdr->cmd = req->msg.cmd;
701 
702 		/* move write pointer */
703 		msg = (uint8_t *)(hdr + 1);
704 	}
705 
706 	/* fill-in the rest header fields */
707 	hdr->rsSA = IPMI_BMC_SLAVE_ADDR;
708 	hdr->csum1 = -(hdr->rsSA + hdr->netFn);
709 	hdr->rqSA = IPMI_REMOTE_SWID;
710 	hdr->rqSeq = seq;
711 
712 	/* fill-in the first context */
713 	ctx[0].rsSA = hdr->rsSA;
714 	ctx[0].netFn = hdr->netFn;
715 	ctx[0].rqSA = hdr->rqSA;
716 	ctx[0].rqSeq = hdr->rqSeq;
717 	ctx[0].cmd = hdr->cmd;
718 
719 	/* write request data */
720 	memcpy(msg, req->msg.data, req->msg.data_len);
721 
722 	/* move write pointer */
723 	msg += req->msg.data_len;
724 
725 	if (bridging_level) {
726 		/* write inner message checksum */
727 		*msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3);
728 
729 		/* check for double bridging */
730 		if (bridging_level == 2) {
731 			/* write outer message checksum */
732 			*msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4);
733 		}
734 
735 		/* write overall message checksum */
736 		*msg++ = ipmi_csum(&hdr->rqSA, 4);
737 	} else {
738 		/* write overall message checksum */
739 		*msg++ = ipmi_csum(&hdr->rqSA, req->msg.data_len + 3);
740 	}
741 
742 	/* save message length */
743 	*msg_len = msg - data;
744 
745 	/* return bridging level */
746 	return bridging_level;
747 }
748 
749 /*
750  *	Wait for request response
751  */
752 static int
753 serial_bm_wait_response(struct ipmi_intf * intf,
754 		struct serial_bm_request_ctx * req_ctx, struct serial_bm_recv_ctx * read_ctx,
755 		uint8_t * msg, size_t max_len)
756 {
757 	struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg;
758 	int msg_len, netFn, rqSeq;
759 
760 	/* receive and match message */
761 	while ((msg_len = serial_bm_recv_msg(intf, read_ctx, msg, max_len)) > 0) {
762 		/* validate message size */
763 		if (msg_len < 8) {
764 			lprintf(LOG_ERR, "ipmitool: response is too short");
765 			continue;
766 		}
767 
768 		/* validate checksum 1 */
769 		if (ipmi_csum(msg, 3)) {
770 			lprintf(LOG_ERR, "ipmitool: bad checksum 1");
771 			continue;
772 		}
773 
774 		/* validate checksum 2 */
775 		if (ipmi_csum(msg + 3, msg_len - 3)) {
776 			lprintf(LOG_ERR, "ipmitool: bad checksum 2");
777 			continue;
778 		}
779 
780 		/* swap requester and responder LUNs */
781 		netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3);
782 		rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3);
783 
784 		/* check for the waited response */
785 		if (hdr->rsSA == req_ctx->rqSA
786 				&& hdr->netFn == netFn
787 				&& hdr->rqSA == req_ctx->rsSA
788 				&& hdr->rqSeq == rqSeq
789 				&& hdr->cmd == req_ctx->cmd) {
790 			/* check if something new has been parsed */
791 			if (verbose > 3) {
792 				fprintf(stderr, "Got response:\n");
793 				fprintf(stderr, "  rsSA            = 0x%x\n", msg[0]);
794 				fprintf(stderr, "  NetFN/rsLUN     = 0x%x\n", msg[1]);
795 				fprintf(stderr, "  rqSA            = 0x%x\n", msg[3]);
796 				fprintf(stderr, "  rqSeq/rqLUN     = 0x%x\n", msg[4]);
797 				fprintf(stderr, "  cmd             = 0x%x\n", msg[5]);
798 				fprintf(stderr, "  completion code = 0x%x\n", msg[6]);
799 				if (msg_len > 8) {
800 					fprintf(stderr, "  data_len        = %d\n", msg_len - 8);
801 					fprintf(stderr, "  data            = %s\n",
802 							buf2str(msg + 7, msg_len - 8));
803 				}
804 			}
805 
806 			/* copy only completion and response data */
807 			memmove(msg, hdr + 1, msg_len - sizeof (*hdr) - 1);
808 
809 			/* update message length */
810 			msg_len -= sizeof (*hdr) + 1;
811 
812 			/* the waited one */
813 			break;
814 		}
815 	}
816 
817 	return msg_len;
818 }
819 
820 /*
821  *	Get message from receive message queue
822  */
823 static int
824 serial_bm_get_message(struct ipmi_intf * intf,
825 		struct serial_bm_request_ctx * req_ctx,
826 		struct serial_bm_recv_ctx * read_ctx,
827 		uint8_t * msg, size_t max_len)
828 {
829 	uint8_t data[SERIAL_BM_MAX_MSG_SIZE];
830 	struct serial_bm_request_ctx tmp_ctx;
831 	struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data;
832 	struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) data;
833 	clock_t start, tm;
834 	int rv, netFn, rqSeq;
835 
836 	start = clock();
837 
838 	do {
839 		/* fill-in request context */
840 		tmp_ctx.rsSA = IPMI_BMC_SLAVE_ADDR;
841 		tmp_ctx.netFn = 0x18;
842 		tmp_ctx.rqSA = IPMI_REMOTE_SWID;
843 		tmp_ctx.rqSeq = serial_bm_alloc_seq() << 2;
844 		tmp_ctx.cmd = 0x33;
845 
846 		/* fill-in request data */
847 		hdr->rsSA = tmp_ctx.rsSA;
848 		hdr->netFn = tmp_ctx.netFn;
849 		hdr->csum1 = ipmi_csum(data, 2);
850 		hdr->rqSA = tmp_ctx.rqSA;
851 		hdr->rqSeq = tmp_ctx.rqSeq;
852 		hdr->cmd = tmp_ctx.cmd;
853 		hdr->data[0] = ipmi_csum(&hdr->rqSA, 3);
854 
855 		/* send request */
856 		serial_bm_flush(intf);
857 		serial_bm_send_msg(intf, data, 7);
858 
859 		/* wait for response */
860 		rv = serial_bm_wait_response(intf, &tmp_ctx, read_ctx,
861 				data, sizeof (data));
862 
863 		/* check for IO error or timeout */
864 		if (rv <= 0) {
865 			return rv;
866 		}
867 
868 		/* check completion code */
869 		if (rp->completion == 0) {
870 			/* swap requester and responder LUNs */
871 			netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3);
872 			rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3);
873 
874 			/* check for the waited response */
875 			if (rp->netFn == netFn
876 					&& rp->rsSA == req_ctx->rsSA
877 					&& rp->rqSeq == rqSeq
878 					&& rp->cmd == req_ctx->cmd) {
879 				/* copy the rest of message */
880 				memcpy(msg, rp->data, rv - sizeof (*rp) - 1);
881 				return rv - sizeof (*rp) - 1;
882 			}
883 		} else if (rp->completion != 0x80) {
884 			return 0;
885 		}
886 
887 		tm = clock() - start;
888 
889 		tm /= CLOCKS_PER_SEC;
890 	} while (tm < intf->session->timeout);
891 
892 	return 0;
893 }
894 
895 static struct ipmi_rs *
896 serial_bm_send_request(struct ipmi_intf * intf, struct ipmi_rq * req)
897 {
898 	static struct ipmi_rs rsp;
899 	uint8_t msg[SERIAL_BM_MAX_MSG_SIZE], * resp = msg;
900 	struct serial_bm_request_ctx req_ctx[3];
901 	struct serial_bm_recv_ctx read_ctx;
902 	int retry, rv, msg_len, bridging_level;
903 
904 	if (!intf->opened && intf->open && intf->open(intf) < 0) {
905 		return NULL;
906 	}
907 
908 	/* reset receive context */
909 	read_ctx.buffer_size = 0;
910 	read_ctx.max_buffer_size = SERIAL_BM_MAX_BUFFER_SIZE;
911 
912 	/* Send the message and receive the answer */
913 	for (retry = 0; retry < intf->session->retry; retry++) {
914 		/* build output message */
915 		bridging_level = serial_bm_build_msg(intf, req, msg,
916 				sizeof (msg), req_ctx, &msg_len);
917 		if (msg_len < 0) {
918 			return NULL;
919 		}
920 
921 		/* send request */
922 		serial_bm_flush(intf);
923 		serial_bm_send_msg(intf, msg, msg_len);
924 
925 		/* wait for response */
926 		rv = serial_bm_wait_response(intf, &req_ctx[0],
927 				&read_ctx, msg, sizeof (msg));
928 
929 		/* check for IO error */
930 		if (rv < 0) {
931 			return NULL;
932 		}
933 
934 		/* check for timeout */
935 		if (rv == 0) {
936 			continue;
937 		}
938 
939 		/* check for bridging */
940 		if (bridging_level && msg[0] == 0) {
941 			/* in the case of payload interface we check receive message queue */
942 			if (is_system) {
943 				/* check message flags */
944 				rv = serial_bm_get_message(intf, &req_ctx[1],
945 						&read_ctx, msg, sizeof (msg));
946 
947 				/* check for IO error */
948 				if (rv < 0) {
949 					return NULL;
950 				}
951 
952 				/* check for timeout */
953 				if (rv == 0) {
954 					continue;
955 				}
956 			/* check if response for inner request is not encapsulated */
957 			} else if (rv == 1) {
958 				/* wait for response for inner request */
959 				rv = serial_bm_wait_response(intf, &req_ctx[0],
960 						&read_ctx, msg, sizeof (msg));
961 
962 				/* check for IO error */
963 				if (rv < 0) {
964 					return NULL;
965 				}
966 
967 				/* check for timeout */
968 				if (rv == 0) {
969 					continue;
970 				}
971 			} else {
972 				/* skip outer level header */
973 				resp = msg + 7;
974 				/* decrement response size */
975 				rv -= 8;
976 			}
977 
978 			/* check response size */
979 			if (resp[0] == 0 && bridging_level == 2 && rv < 8) {
980 				lprintf(LOG_ERR, "ipmitool: Message response is too short");
981 				/* invalid message length */
982 				return NULL;
983 			}
984 		}
985 
986 		/* check for double bridging */
987 		if (bridging_level == 2 && resp[0] == 0) {
988 			/* get completion code */
989 			rsp.ccode = resp[7];
990 			rsp.data_len = rv - 9;
991 			memcpy(rsp.data, resp + 8, rsp.data_len);
992 		} else {
993 			rsp.ccode = resp[0];
994 			rsp.data_len = rv - 1;
995 			memcpy(rsp.data, resp + 1, rsp.data_len);
996 		}
997 
998 		/* return response */
999 		return &rsp;
1000 	}
1001 
1002 	/* no valid response */
1003 	return NULL;
1004 }
1005 
1006 int
1007 serial_bm_set_my_addr(struct ipmi_intf * intf, uint8_t addr)
1008 {
1009 	intf->my_addr = addr;
1010 	return 0;
1011 }
1012 
1013 /*
1014  *	Serial BM interface
1015  */
1016 struct ipmi_intf ipmi_serial_bm_intf = {
1017 	name:		"serial-basic",
1018 	desc:		"Serial Interface, Basic Mode",
1019 	setup:		serial_bm_setup,
1020 	open:		serial_bm_open,
1021 	close:		serial_bm_close,
1022 	sendrecv:	serial_bm_send_request,
1023 	set_my_addr:serial_bm_set_my_addr
1024 };
1025