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