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