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