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 
309 	if (intf->session) {
310 		free(intf->session);
311 		intf->session = NULL;
312 	}
313 
314 	intf->opened = 0;
315 }
316 
317 /*
318  *	Allocate sequence number for tracking
319  */
320 static uint8_t
321 serial_bm_alloc_seq(void)
322 {
323 	static uint8_t seq = 0;
324 	if (++seq == 64) {
325 		seq = 0;
326 	}
327 	return seq;
328 }
329 
330 /*
331  *	Flush the buffers
332  */
333 static int
334 serial_bm_flush(struct ipmi_intf * intf)
335 {
336 #if defined(TCFLSH)
337     return ioctl(intf->fd, TCFLSH, TCIOFLUSH);
338 #elif defined(TIOCFLUSH)
339     return ioctl(intf->fd, TIOCFLUSH);
340 #else
341 #   error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)"
342 #endif
343 }
344 
345 /*
346  *	Return escaped character for the given one
347  */
348 static inline uint8_t
349 serial_bm_get_escaped_char(uint8_t c)
350 {
351 	int i;
352 
353 	for (i = 0; i < 5; i++) {
354 		if (characters[i].character == c) {
355 			return characters[i].escape;
356 		}
357 	}
358 
359 	return c;
360 }
361 
362 /*
363  *	Return unescaped character for the given one
364  */
365 static inline uint8_t
366 serial_bm_get_unescaped_char(uint8_t c)
367 {
368 	int i;
369 
370 	for (i = 0; i < 5; i++) {
371 		if (characters[i].escape == c) {
372 			return characters[i].character;
373 		}
374 	}
375 
376 	return c;
377 }
378 
379 /*
380  *	Send message to serial port
381  */
382 static int
383 serial_bm_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len)
384 {
385 	int i, size, tmp = 0;
386 	uint8_t * buf, * data;
387 
388 	if (verbose > 3) {
389 		fprintf(stderr, "Sending request:\n");
390 		fprintf(stderr, "  rsSA         = 0x%x\n", msg[0]);
391 		fprintf(stderr, "  NetFN/rsLUN  = 0x%x\n", msg[1]);
392 		fprintf(stderr, "  rqSA         = 0x%x\n", msg[3]);
393 		fprintf(stderr, "  rqSeq/rqLUN  = 0x%x\n", msg[4]);
394 		fprintf(stderr, "  cmd          = 0x%x\n", msg[5]);
395 		if (msg_len > 7) {
396 			fprintf(stderr, "  data_len     = %d\n", msg_len - 7);
397 			fprintf(stderr, "  data         = %s\n",
398 					buf2str(msg + 6, msg_len - 7));
399 		}
400 	}
401 
402 	if (verbose > 4) {
403 		fprintf(stderr, "Message data:\n");
404 		fprintf(stderr, " %s\n", buf2str(msg, msg_len));
405 	}
406 
407 	/* calculate escaped characters number */
408 	for (i = 0; i < msg_len; i++) {
409 		if (serial_bm_get_escaped_char(msg[i]) != msg[i]) {
410 			tmp++;
411 		}
412 	}
413 
414 	/* calculate required buffer size */
415 	size = msg_len + tmp + 2;
416 
417 	/* allocate buffer for output data */
418 	buf = data = (uint8_t *) alloca(size);
419 
420 	if (!buf) {
421 		lperror(LOG_ERR, "ipmitool: alloca error");
422 		return -1;
423 	}
424 
425 	/* start character */
426 	*buf++ = 0xA0;
427 
428 	for (i = 0; i < msg_len; i++) {
429 		tmp = serial_bm_get_escaped_char(msg[i]);
430 		if (tmp != msg[i]) {
431 			*buf++ = 0xAA;
432 		}
433 
434 		*buf++ = tmp;
435 	}
436 
437 	/* stop character */
438 	*buf++ = 0xA5;
439 
440 	if (verbose > 5) {
441 		fprintf(stderr, "Sent serial data:\n %s\n", buf2str(data, size));
442 	}
443 
444 	/* write data to serial port */
445 	tmp = write(intf->fd, data, size);
446 	if (tmp <= 0) {
447 		lperror(LOG_ERR, "ipmitool: write error");
448 		return -1;
449 	}
450 
451 	return 0;
452 }
453 
454 /*
455  *	This function waits for incoming data
456  */
457 static int
458 serial_bm_wait_for_data(struct ipmi_intf * intf)
459 {
460 	int n;
461 	struct pollfd pfd;
462 
463 	pfd.fd = intf->fd;
464 	pfd.events = POLLIN;
465 	pfd.revents = 0;
466 
467 	n = poll(&pfd, 1, intf->session->timeout*1000);
468 	if (n < 0) {
469 		lperror(LOG_ERR, "Poll for serial data failed");
470 		return -1;
471 	} else if (!n) {
472 		return -1;
473 	}
474 	return 0;
475 }
476 
477 /*
478  *	This function parses incoming data in basic mode format to IPMB message
479  */
480 static int
481 serial_bm_parse_buffer(const uint8_t * data, int data_len,
482 		struct serial_bm_parse_ctx * ctx)
483 {
484 	int i, tmp;
485 
486 	for (i = 0; i < data_len; i++) {
487 		/* check for start of new message */
488 		if (data[i] == BM_START) {
489 			ctx->state = MSG_IN_PROGRESS;
490 			ctx->escape = 0;
491 			ctx->msg_len = 0;
492 		/* check if message is not started */
493 		} else if (ctx->state != MSG_IN_PROGRESS) {
494 			/* skip character */
495 			continue;
496 		/* continue escape sequence */
497 		} else	if (ctx->escape) {
498 			/* get original character */
499 			tmp = serial_bm_get_unescaped_char(data[i]);
500 
501 			/* check if not special character */
502 			if (tmp == data[i]) {
503 				lprintf(LOG_ERR, "ipmitool: bad response");
504 				/* reset message state */
505 				ctx->state = MSG_NONE;
506 				continue;
507 			}
508 
509 			/* check message length */
510 			if (ctx->msg_len >= ctx->max_len) {
511 				lprintf(LOG_ERR, "ipmitool: response is too long");
512 				/* reset message state */
513 				ctx->state = MSG_NONE;
514 				continue;
515 			}
516 
517 			/* add parsed character */
518 			ctx->msg[ctx->msg_len++] = tmp;
519 
520 			/* clear escape flag */
521 			ctx->escape = 0;
522 		/* check for escape character */
523 		} else if (data[i] == BM_ESCAPE) {
524 			ctx->escape = 1;
525 			continue;
526 		/* check for stop character */
527 		} else if (data[i] == BM_STOP) {
528 			ctx->state = MSG_DONE;
529 			return i + 1;
530 		/* check for packet handshake character */
531 		} else if (data[i] == BM_HANDSHAKE) {
532 			/* just skip it */
533 			continue;
534 		} else {
535 			/* check message length */
536 			if (ctx->msg_len >= ctx->max_len) {
537 				lprintf(LOG_ERR, "ipmitool: response is too long");
538 				return -1;
539 			}
540 
541 			/* add parsed character */
542 			ctx->msg[ctx->msg_len++] = data[i];
543 		}
544 	}
545 
546 	/* return number of parsed characters */
547 	return i;
548 }
549 
550 /*
551  *	Read and parse data from serial port
552  */
553 static int
554 serial_bm_recv_msg(struct ipmi_intf * intf,
555 		struct serial_bm_recv_ctx * recv_ctx,
556 		uint8_t * msg_data, size_t msg_len)
557 {
558 	struct serial_bm_parse_ctx parse_ctx;
559 	int rv;
560 
561 	parse_ctx.state = MSG_NONE;
562 	parse_ctx.msg = msg_data;
563 	parse_ctx.max_len = msg_len;
564 
565 	do {
566 		/* wait for data in the port */
567 		if (serial_bm_wait_for_data(intf)) {
568 			return 0;
569 		}
570 
571 		/* read data into buffer */
572 		rv = read(intf->fd, recv_ctx->buffer + recv_ctx->buffer_size,
573 				recv_ctx->max_buffer_size - recv_ctx->buffer_size);
574 
575 		if (rv < 0) {
576 			lperror(LOG_ERR, "ipmitool: read error");
577 			return -1;
578 		}
579 
580 		if (verbose > 5) {
581 			fprintf(stderr, "Received serial data:\n %s\n",
582 					buf2str(recv_ctx->buffer + recv_ctx->buffer_size, rv));
583 		}
584 
585 		/* increment buffer size */
586 		recv_ctx->buffer_size += rv;
587 
588 		/* parse buffer */
589 		rv = serial_bm_parse_buffer(recv_ctx->buffer,
590 				recv_ctx->buffer_size, &parse_ctx);
591 
592 		if (rv < recv_ctx->buffer_size) {
593 			/* move non-parsed part of the buffer to the beginning */
594 			memmove(recv_ctx->buffer, recv_ctx->buffer + rv,
595 					recv_ctx->buffer_size - rv);
596 		}
597 
598 		/* decrement buffer size */
599 		recv_ctx->buffer_size -= rv;
600 	} while (parse_ctx.state != MSG_DONE);
601 
602 	if (verbose > 4) {
603 		printf("Received message:\n %s\n",
604 				buf2str(msg_data, parse_ctx.msg_len));
605 	}
606 
607 	/* received a message */
608 	return parse_ctx.msg_len;
609 }
610 
611 /*
612  *	Build IPMB message to be transmitted
613  */
614 static int
615 serial_bm_build_msg(const struct ipmi_intf * intf,
616 		const struct ipmi_rq * req, uint8_t * msg, size_t max_len,
617 		struct serial_bm_request_ctx * ctx, int * msg_len
618 		)
619 {
620 	uint8_t * data = msg, seq;
621 	struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg;
622 	struct ipmi_send_message_rq * inner_rq = NULL, * outer_rq = NULL;
623 	int bridging_level;
624 
625 	/* acquire bridging level */
626 	if (intf->target_addr && intf->target_addr != intf->my_addr) {
627 		if (intf->transit_addr != 0) {
628 			bridging_level = 2;
629 		} else {
630 			bridging_level = 1;
631 		}
632 	} else {
633 		bridging_level = 0;
634 	}
635 
636 	/* check overall packet length */
637 	if(req->msg.data_len + 7 + bridging_level * 8 > max_len) {
638 		lprintf(LOG_ERR, "ipmitool: Message data is too long");
639 		return -1;
640 	}
641 
642 	/* allocate new sequence number */
643 	seq = serial_bm_alloc_seq() << 2;
644 
645 	if (bridging_level) {
646 		/* compose send message request */
647 		hdr->netFn = 0x18;
648 		hdr->cmd = 0x34;
649 
650 		/* set pointer to send message request data */
651 		outer_rq = (struct ipmi_send_message_rq *) (hdr + 1);
652 
653 		/* compose the outer send message request */
654 		if (bridging_level == 2) {
655 			outer_rq->channel = intf->transit_channel | 0x40;
656 			outer_rq->msg.rsSA = intf->transit_addr;
657 			outer_rq->msg.netFn = 0x18;
658 			outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn);
659 			outer_rq->msg.rqSA = intf->my_addr;
660 			outer_rq->msg.rqSeq = seq;
661 			outer_rq->msg.cmd = 0x34;
662 
663 			/* inner send message request is further */
664 			inner_rq = (outer_rq + 1);
665 		} else {
666 			/* there is only outer send message reuest */
667 			inner_rq = outer_rq;
668 		}
669 
670 		/* compose the inner send message request */
671 		inner_rq->channel = intf->target_channel | 0x40;
672 		inner_rq->msg.rsSA = intf->target_addr;
673 		inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun;
674 		inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn);
675 		inner_rq->msg.rqSA = intf->my_addr;
676 		inner_rq->msg.rqSeq = seq;
677 		inner_rq->msg.cmd = req->msg.cmd;
678 
679 		/* check if interface is the system one */
680 		if (is_system) {
681 			/* need response to LUN 2 */
682 			outer_rq->msg.rqSeq |= 2;
683 
684 			/* do not track response */
685 			outer_rq->channel &= ~0x40;
686 
687 			/* restore BMC SA if bridging not to primary IPMB channel */
688 			if (outer_rq->channel) {
689 				outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR;
690 			}
691 		}
692 
693 		/* fill-in the second context */
694 		ctx[1].rsSA = outer_rq->msg.rsSA;
695 		ctx[1].netFn = outer_rq->msg.netFn;
696 		ctx[1].rqSA = outer_rq->msg.rqSA;
697 		ctx[1].rqSeq = outer_rq->msg.rqSeq;
698 		ctx[1].cmd = outer_rq->msg.cmd;
699 
700 		/* move write pointer */
701 		msg = (uint8_t *)(inner_rq + 1);
702 	} else {
703 		/* compose direct request */
704 		hdr->netFn = (req->msg.netfn << 2) | req->msg.lun;
705 		hdr->cmd = req->msg.cmd;
706 
707 		/* move write pointer */
708 		msg = (uint8_t *)(hdr + 1);
709 	}
710 
711 	/* fill-in the rest header fields */
712 	hdr->rsSA = IPMI_BMC_SLAVE_ADDR;
713 	hdr->csum1 = -(hdr->rsSA + hdr->netFn);
714 	hdr->rqSA = IPMI_REMOTE_SWID;
715 	hdr->rqSeq = seq;
716 
717 	/* fill-in the first context */
718 	ctx[0].rsSA = hdr->rsSA;
719 	ctx[0].netFn = hdr->netFn;
720 	ctx[0].rqSA = hdr->rqSA;
721 	ctx[0].rqSeq = hdr->rqSeq;
722 	ctx[0].cmd = hdr->cmd;
723 
724 	/* write request data */
725 	memcpy(msg, req->msg.data, req->msg.data_len);
726 
727 	/* move write pointer */
728 	msg += req->msg.data_len;
729 
730 	if (bridging_level) {
731 		/* write inner message checksum */
732 		*msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3);
733 
734 		/* check for double bridging */
735 		if (bridging_level == 2) {
736 			/* write outer message checksum */
737 			*msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4);
738 		}
739 
740 		/* write overall message checksum */
741 		*msg++ = ipmi_csum(&hdr->rqSA, 4);
742 	} else {
743 		/* write overall message checksum */
744 		*msg++ = ipmi_csum(&hdr->rqSA, req->msg.data_len + 3);
745 	}
746 
747 	/* save message length */
748 	*msg_len = msg - data;
749 
750 	/* return bridging level */
751 	return bridging_level;
752 }
753 
754 /*
755  *	Wait for request response
756  */
757 static int
758 serial_bm_wait_response(struct ipmi_intf * intf,
759 		struct serial_bm_request_ctx * req_ctx, struct serial_bm_recv_ctx * read_ctx,
760 		uint8_t * msg, size_t max_len)
761 {
762 	struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) msg;
763 	int msg_len, netFn, rqSeq;
764 
765 	/* receive and match message */
766 	while ((msg_len = serial_bm_recv_msg(intf, read_ctx, msg, max_len)) > 0) {
767 		/* validate message size */
768 		if (msg_len < 8) {
769 			lprintf(LOG_ERR, "ipmitool: response is too short");
770 			continue;
771 		}
772 
773 		/* validate checksum 1 */
774 		if (ipmi_csum(msg, 3)) {
775 			lprintf(LOG_ERR, "ipmitool: bad checksum 1");
776 			continue;
777 		}
778 
779 		/* validate checksum 2 */
780 		if (ipmi_csum(msg + 3, msg_len - 3)) {
781 			lprintf(LOG_ERR, "ipmitool: bad checksum 2");
782 			continue;
783 		}
784 
785 		/* swap requester and responder LUNs */
786 		netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3);
787 		rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3);
788 
789 		/* check for the waited response */
790 		if (hdr->rsSA == req_ctx->rqSA
791 				&& hdr->netFn == netFn
792 				&& hdr->rqSA == req_ctx->rsSA
793 				&& hdr->rqSeq == rqSeq
794 				&& hdr->cmd == req_ctx->cmd) {
795 			/* check if something new has been parsed */
796 			if (verbose > 3) {
797 				fprintf(stderr, "Got response:\n");
798 				fprintf(stderr, "  rsSA            = 0x%x\n", msg[0]);
799 				fprintf(stderr, "  NetFN/rsLUN     = 0x%x\n", msg[1]);
800 				fprintf(stderr, "  rqSA            = 0x%x\n", msg[3]);
801 				fprintf(stderr, "  rqSeq/rqLUN     = 0x%x\n", msg[4]);
802 				fprintf(stderr, "  cmd             = 0x%x\n", msg[5]);
803 				fprintf(stderr, "  completion code = 0x%x\n", msg[6]);
804 				if (msg_len > 8) {
805 					fprintf(stderr, "  data_len        = %d\n", msg_len - 8);
806 					fprintf(stderr, "  data            = %s\n",
807 							buf2str(msg + 7, msg_len - 8));
808 				}
809 			}
810 
811 			/* copy only completion and response data */
812 			memmove(msg, hdr + 1, msg_len - sizeof (*hdr) - 1);
813 
814 			/* update message length */
815 			msg_len -= sizeof (*hdr) + 1;
816 
817 			/* the waited one */
818 			break;
819 		}
820 	}
821 
822 	return msg_len;
823 }
824 
825 /*
826  *	Get message from receive message queue
827  */
828 static int
829 serial_bm_get_message(struct ipmi_intf * intf,
830 		struct serial_bm_request_ctx * req_ctx,
831 		struct serial_bm_recv_ctx * read_ctx,
832 		uint8_t * msg, size_t max_len)
833 {
834 	uint8_t data[SERIAL_BM_MAX_MSG_SIZE];
835 	struct serial_bm_request_ctx tmp_ctx;
836 	struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data;
837 	struct ipmb_msg_hdr * hdr = (struct ipmb_msg_hdr *) data;
838 	clock_t start, tm;
839 	int rv, netFn, rqSeq;
840 
841 	start = clock();
842 
843 	do {
844 		/* fill-in request context */
845 		tmp_ctx.rsSA = IPMI_BMC_SLAVE_ADDR;
846 		tmp_ctx.netFn = 0x18;
847 		tmp_ctx.rqSA = IPMI_REMOTE_SWID;
848 		tmp_ctx.rqSeq = serial_bm_alloc_seq() << 2;
849 		tmp_ctx.cmd = 0x33;
850 
851 		/* fill-in request data */
852 		hdr->rsSA = tmp_ctx.rsSA;
853 		hdr->netFn = tmp_ctx.netFn;
854 		hdr->csum1 = ipmi_csum(data, 2);
855 		hdr->rqSA = tmp_ctx.rqSA;
856 		hdr->rqSeq = tmp_ctx.rqSeq;
857 		hdr->cmd = tmp_ctx.cmd;
858 		hdr->data[0] = ipmi_csum(&hdr->rqSA, 3);
859 
860 		/* send request */
861 		serial_bm_flush(intf);
862 		serial_bm_send_msg(intf, data, 7);
863 
864 		/* wait for response */
865 		rv = serial_bm_wait_response(intf, &tmp_ctx, read_ctx,
866 				data, sizeof (data));
867 
868 		/* check for IO error or timeout */
869 		if (rv <= 0) {
870 			return rv;
871 		}
872 
873 		/* check completion code */
874 		if (rp->completion == 0) {
875 			/* swap requester and responder LUNs */
876 			netFn = ((req_ctx->netFn|4) & ~3) | (req_ctx->rqSeq & 3);
877 			rqSeq = (req_ctx->rqSeq & ~3) | (req_ctx->netFn & 3);
878 
879 			/* check for the waited response */
880 			if (rp->netFn == netFn
881 					&& rp->rsSA == req_ctx->rsSA
882 					&& rp->rqSeq == rqSeq
883 					&& rp->cmd == req_ctx->cmd) {
884 				/* copy the rest of message */
885 				memcpy(msg, rp->data, rv - sizeof (*rp) - 1);
886 				return rv - sizeof (*rp) - 1;
887 			}
888 		} else if (rp->completion != 0x80) {
889 			return 0;
890 		}
891 
892 		tm = clock() - start;
893 
894 		tm /= CLOCKS_PER_SEC;
895 	} while (tm < intf->session->timeout);
896 
897 	return 0;
898 }
899 
900 static struct ipmi_rs *
901 serial_bm_send_request(struct ipmi_intf * intf, struct ipmi_rq * req)
902 {
903 	static struct ipmi_rs rsp;
904 	uint8_t msg[SERIAL_BM_MAX_MSG_SIZE], * resp = msg;
905 	struct serial_bm_request_ctx req_ctx[3];
906 	struct serial_bm_recv_ctx read_ctx;
907 	int retry, rv, msg_len, bridging_level;
908 
909 	if (!intf->opened && intf->open && intf->open(intf) < 0) {
910 		return NULL;
911 	}
912 
913 	/* reset receive context */
914 	read_ctx.buffer_size = 0;
915 	read_ctx.max_buffer_size = SERIAL_BM_MAX_BUFFER_SIZE;
916 
917 	/* Send the message and receive the answer */
918 	for (retry = 0; retry < intf->session->retry; retry++) {
919 		/* build output message */
920 		bridging_level = serial_bm_build_msg(intf, req, msg,
921 				sizeof (msg), req_ctx, &msg_len);
922 		if (msg_len < 0) {
923 			return NULL;
924 		}
925 
926 		/* send request */
927 		serial_bm_flush(intf);
928 		serial_bm_send_msg(intf, msg, msg_len);
929 
930 		/* wait for response */
931 		rv = serial_bm_wait_response(intf, &req_ctx[0],
932 				&read_ctx, msg, sizeof (msg));
933 
934 		/* check for IO error */
935 		if (rv < 0) {
936 			return NULL;
937 		}
938 
939 		/* check for timeout */
940 		if (rv == 0) {
941 			continue;
942 		}
943 
944 		/* check for bridging */
945 		if (bridging_level && msg[0] == 0) {
946 			/* in the case of payload interface we check receive message queue */
947 			if (is_system) {
948 				/* check message flags */
949 				rv = serial_bm_get_message(intf, &req_ctx[1],
950 						&read_ctx, msg, sizeof (msg));
951 
952 				/* check for IO error */
953 				if (rv < 0) {
954 					return NULL;
955 				}
956 
957 				/* check for timeout */
958 				if (rv == 0) {
959 					continue;
960 				}
961 			/* check if response for inner request is not encapsulated */
962 			} else if (rv == 1) {
963 				/* wait for response for inner request */
964 				rv = serial_bm_wait_response(intf, &req_ctx[0],
965 						&read_ctx, msg, sizeof (msg));
966 
967 				/* check for IO error */
968 				if (rv < 0) {
969 					return NULL;
970 				}
971 
972 				/* check for timeout */
973 				if (rv == 0) {
974 					continue;
975 				}
976 			} else {
977 				/* skip outer level header */
978 				resp = msg + 7;
979 				/* decrement response size */
980 				rv -= 8;
981 			}
982 
983 			/* check response size */
984 			if (resp[0] == 0 && bridging_level == 2 && rv < 8) {
985 				lprintf(LOG_ERR, "ipmitool: Message response is too short");
986 				/* invalid message length */
987 				return NULL;
988 			}
989 		}
990 
991 		/* check for double bridging */
992 		if (bridging_level == 2 && resp[0] == 0) {
993 			/* get completion code */
994 			rsp.ccode = resp[7];
995 			rsp.data_len = rv - 9;
996 			memcpy(rsp.data, resp + 8, rsp.data_len);
997 		} else {
998 			rsp.ccode = resp[0];
999 			rsp.data_len = rv - 1;
1000 			memcpy(rsp.data, resp + 1, rsp.data_len);
1001 		}
1002 
1003 		/* return response */
1004 		return &rsp;
1005 	}
1006 
1007 	/* no valid response */
1008 	return NULL;
1009 }
1010 
1011 int
1012 serial_bm_set_my_addr(struct ipmi_intf * intf, uint8_t addr)
1013 {
1014 	intf->my_addr = addr;
1015 	return 0;
1016 }
1017 
1018 /*
1019  *	Serial BM interface
1020  */
1021 struct ipmi_intf ipmi_serial_bm_intf = {
1022 	name:		"serial-basic",
1023 	desc:		"Serial Interface, Basic Mode",
1024 	setup:		serial_bm_setup,
1025 	open:		serial_bm_open,
1026 	close:		serial_bm_close,
1027 	sendrecv:	serial_bm_send_request,
1028 	set_my_addr:serial_bm_set_my_addr
1029 };
1030