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