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 246 if (intf->session) { 247 free(intf->session); 248 intf->session = NULL; 249 } 250 251 intf->opened = 0; 252 } 253 254 /* 255 * This function waits for incoming byte during timeout (ms). 256 */ 257 static int 258 serial_wait_for_data(struct ipmi_intf * intf) 259 { 260 int n; 261 struct pollfd pfd; 262 263 pfd.fd = intf->fd; 264 pfd.events = POLLIN; 265 pfd.revents = 0; 266 267 n = poll(&pfd, 1, intf->session->timeout*1000); 268 if (n < 0) { 269 lperror(LOG_ERR, "Poll for serial data failed"); 270 return -1; 271 } else if (!n) { 272 return -1; 273 } 274 return 0; 275 } 276 277 /* 278 * Read a line from serial port 279 * Returns > 0 if there is a line, < 0 on error or timeout 280 */ 281 static int 282 serial_read_line(struct ipmi_intf * intf, char *str, int len) 283 { 284 int rv, i; 285 286 *str = 0; 287 i = 0; 288 while (i < len) { 289 if (serial_wait_for_data(intf)) { 290 return -1; 291 } 292 rv = read(intf->fd, str + i, 1); 293 if (rv < 0) { 294 return -1; 295 } else if (!rv) { 296 lperror(LOG_ERR, "Serial read failed: %s", strerror(errno)); 297 return -1; 298 } 299 if (str[i] == '\n' || str[i] == '\r') { 300 if (verbose > 4) { 301 char c = str[i]; 302 str[i] = '\0'; 303 fprintf(stderr, "Received data: %s\n", str); 304 str[i] = c; 305 } 306 return i + 1; 307 } else { 308 i++; 309 } 310 } 311 312 lprintf(LOG_ERR, "Serial data is too long"); 313 return -1; 314 } 315 316 /* 317 * Send zero-terminated string to serial port 318 * Returns the string length or negative error code 319 */ 320 static int 321 serial_write_line(struct ipmi_intf * intf, const char *str) 322 { 323 int rv, cnt = 0; 324 int cb = strlen(str); 325 326 while (cnt < cb) { 327 rv = write(intf->fd, str + cnt, cb - cnt); 328 if (rv < 0) { 329 return -1; 330 } else if (rv == 0) { 331 return -1; 332 } 333 cnt += rv; 334 } 335 336 return cnt; 337 } 338 339 /* 340 * Flush the buffers 341 */ 342 static int 343 serial_flush(struct ipmi_intf * intf) 344 { 345 #if defined(TCFLSH) 346 return ioctl(intf->fd, TCFLSH, TCIOFLUSH); 347 #elif defined(TIOCFLUSH) 348 return ioctl(intf->fd, TIOCFLUSH); 349 #else 350 # error "unsupported platform, missing flush support (TCFLSH/TIOCFLUSH)" 351 #endif 352 353 } 354 355 /* 356 * Receive IPMI response from the device 357 * Len: buffer size 358 * Returns: -1 or response lenth on success 359 */ 360 static int 361 recv_response(struct ipmi_intf * intf, unsigned char *data, int len) 362 { 363 char hex_rs[IPMI_SERIAL_MAX_RESPONSE * 3]; 364 int i, j, resp_len = 0; 365 unsigned long rv; 366 char *p, *pp; 367 char ch, str_hex[3]; 368 369 p = hex_rs; 370 while (1) { 371 if ((rv = serial_read_line(intf, p, sizeof(hex_rs) - resp_len)) < 0) { 372 /* error */ 373 return -1; 374 } 375 p += rv; 376 resp_len += rv; 377 if (*(p - 2) == ']' && (*(p - 1) == '\n' || *(p - 1) == '\r')) { 378 *p = 0; 379 break; 380 } 381 } 382 383 p = strrchr(hex_rs, '['); 384 if (!p) { 385 lprintf(LOG_ERR, "Serial response is invalid"); 386 return -1; 387 } 388 389 p++; 390 pp = strchr(p, ']'); 391 if (!pp) { 392 lprintf(LOG_ERR, "Serial response is invalid"); 393 return -1; 394 } 395 *pp = 0; 396 397 /* was it an error? */ 398 if (strncmp(p, "ERR ", 4) == 0) { 399 serial_write_line(intf, "\r\r\r\r"); 400 sleep(1); 401 serial_flush(intf); 402 errno = 0; 403 rv = strtoul(p + 4, &p, 16); 404 if ((rv && rv < 0x100 && *p == '\0') 405 || (rv == 0 && !errno)) { 406 /* The message didn't get it through. The upper 407 level will have to re-send */ 408 return 0; 409 } else { 410 lprintf(LOG_ERR, "Serial response is invalid"); 411 return -1; 412 } 413 } 414 415 /* this is needed for correct string to long conversion */ 416 str_hex[2] = 0; 417 418 /* parse the response */ 419 i = 0; 420 j = 0; 421 while (*p) { 422 if (i >= len) { 423 lprintf(LOG_ERR, "Serial response is too long(%d, %d)", i, len); 424 return -1; 425 } 426 ch = *(p++); 427 if (isxdigit(ch)) { 428 str_hex[j++] = ch; 429 } else { 430 if (j == 1 || !isspace(ch)) { 431 lprintf(LOG_ERR, "Serial response is invalid"); 432 return -1; 433 } 434 } 435 if (j == 2) { 436 unsigned long tmp; 437 errno = 0; 438 /* parse the hex number */ 439 tmp = strtoul(str_hex, NULL, 16); 440 if ( tmp > 0xFF || ( !tmp && errno ) ) { 441 lprintf(LOG_ERR, "Serial response is invalid"); 442 return -1; 443 } 444 data[i++] = tmp; 445 j = 0; 446 } 447 } 448 449 return i; 450 } 451 452 /* 453 * Allocate sequence number for tracking 454 */ 455 static uint8_t 456 serial_term_alloc_seq(void) 457 { 458 static uint8_t seq = 0; 459 if (++seq == 64) { 460 seq = 0; 461 } 462 return seq; 463 } 464 465 /* 466 * Build IPMB message to be transmitted 467 */ 468 static int 469 serial_term_build_msg(const struct ipmi_intf * intf, 470 const struct ipmi_rq * req, uint8_t * msg, size_t max_len, 471 struct serial_term_request_ctx * ctx, int * msg_len) 472 { 473 uint8_t * data = msg, seq; 474 struct serial_term_hdr * term_hdr = (struct serial_term_hdr *) msg; 475 struct ipmi_send_message_rq * outer_rq = NULL; 476 struct ipmi_send_message_rq * inner_rq = NULL; 477 int bridging_level; 478 479 /* acquire bridging level */ 480 if (intf->target_addr && intf->target_addr != intf->my_addr) { 481 if (intf->transit_addr != 0) { 482 bridging_level = 2; 483 } else { 484 bridging_level = 1; 485 } 486 } else { 487 bridging_level = 0; 488 } 489 490 /* check overall packet length */ 491 if(req->msg.data_len + 3 + bridging_level * 8 > max_len) { 492 lprintf(LOG_ERR, "ipmitool: Message data is too long"); 493 return -1; 494 } 495 496 /* allocate new sequence number */ 497 seq = serial_term_alloc_seq() << 2; 498 499 /* check for bridging */ 500 if (bridging_level) { 501 /* compose terminal message header */ 502 term_hdr->netFn = 0x18; 503 term_hdr->seq = seq; 504 term_hdr->cmd = 0x34; 505 506 /* set pointer to send message request data */ 507 outer_rq = (struct ipmi_send_message_rq *) (term_hdr + 1); 508 509 if (bridging_level == 2) { 510 /* compose the outer send message request */ 511 outer_rq->channel = intf->transit_channel | 0x40; 512 outer_rq->msg.rsSA = intf->transit_addr; 513 outer_rq->msg.netFn = 0x18; 514 outer_rq->msg.csum1 = -(outer_rq->msg.rsSA + outer_rq->msg.netFn); 515 outer_rq->msg.rqSA = intf->my_addr; 516 outer_rq->msg.rqSeq = seq; 517 outer_rq->msg.cmd = 0x34; 518 519 /* inner request is further */ 520 inner_rq = (outer_rq + 1); 521 } else { 522 /* there is only one header */ 523 inner_rq = outer_rq; 524 } 525 526 /* compose the inner send message request */ 527 inner_rq->channel = intf->target_channel | 0x40; 528 inner_rq->msg.rsSA = intf->target_addr; 529 inner_rq->msg.netFn = (req->msg.netfn << 2) | req->msg.lun; 530 inner_rq->msg.csum1 = -(inner_rq->msg.rsSA + inner_rq->msg.netFn); 531 inner_rq->msg.rqSA = intf->my_addr; 532 inner_rq->msg.rqSeq = seq; 533 inner_rq->msg.cmd = req->msg.cmd; 534 535 /* check if interface is the system one */ 536 if (is_system) { 537 /* need response to LUN 2 */ 538 outer_rq->msg.rqSeq |= 2; 539 540 /* do not track response */ 541 outer_rq->channel &= ~0x40; 542 543 /* restore BMC SA if bridging not to primary IPMB channel */ 544 if (outer_rq->channel) { 545 outer_rq->msg.rqSA = IPMI_BMC_SLAVE_ADDR; 546 } 547 } 548 549 /* fill the second context */ 550 ctx[1].netFn = outer_rq->msg.netFn; 551 ctx[1].sa = outer_rq->msg.rsSA; 552 ctx[1].seq = outer_rq->msg.rqSeq; 553 ctx[1].cmd = outer_rq->msg.cmd; 554 555 /* move write pointer */ 556 msg = (uint8_t *)(inner_rq + 1); 557 } else { 558 /* compose terminal message header */ 559 term_hdr->netFn = (req->msg.netfn << 2) | req->msg.lun; 560 term_hdr->seq = seq; 561 term_hdr->cmd = req->msg.cmd; 562 563 /* move write pointer */ 564 msg = (uint8_t *)(term_hdr + 1); 565 } 566 567 /* fill the first context */ 568 ctx[0].netFn = term_hdr->netFn; 569 ctx[0].seq = term_hdr->seq; 570 ctx[0].cmd = term_hdr->cmd; 571 572 /* write request data */ 573 memcpy(msg, req->msg.data, req->msg.data_len); 574 575 /* move write pointer */ 576 msg += req->msg.data_len; 577 578 if (bridging_level) { 579 /* write inner message checksum */ 580 *msg++ = ipmi_csum(&inner_rq->msg.rqSA, req->msg.data_len + 3); 581 582 /* check for double bridging */ 583 if (bridging_level == 2) { 584 /* write outer message checksum */ 585 *msg++ = ipmi_csum(&outer_rq->msg.rqSA, 4); 586 } 587 } 588 589 590 /* save message length */ 591 *msg_len = msg - data; 592 593 /* return bridging level */ 594 return bridging_level; 595 } 596 597 /* 598 * Send message to serial port 599 */ 600 static int 601 serial_term_send_msg(struct ipmi_intf * intf, uint8_t * msg, int msg_len) 602 { 603 int i, size, tmp = 0; 604 uint8_t * buf, * data; 605 606 if (verbose > 3) { 607 fprintf(stderr, "Sending request:\n"); 608 fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[0]); 609 fprintf(stderr, " rqSeq = 0x%x\n", msg[1]); 610 fprintf(stderr, " cmd = 0x%x\n", msg[2]); 611 if (msg_len > 7) { 612 fprintf(stderr, " data_len = %d\n", msg_len - 3); 613 fprintf(stderr, " data = %s\n", 614 buf2str(msg + 3, msg_len - 3)); 615 } 616 } 617 618 if (verbose > 4) { 619 fprintf(stderr, "Message data:\n"); 620 fprintf(stderr, " %s\n", buf2str(msg, msg_len)); 621 } 622 623 /* calculate required buffer size */ 624 size = msg_len * 2 + 4; 625 626 /* allocate buffer for output data */ 627 buf = data = (uint8_t *) alloca(size); 628 629 if (!buf) { 630 lperror(LOG_ERR, "ipmitool: alloca error"); 631 return -1; 632 } 633 634 /* start character */ 635 *buf++ = '['; 636 637 /* body */ 638 for (i = 0; i < msg_len; i++) { 639 buf += sprintf( buf, "%02x", msg[i]); 640 } 641 642 /* stop character */ 643 *buf++ = ']'; 644 645 /* carriage return */ 646 *buf++ = '\r'; 647 648 /* line feed */ 649 *buf++ = '\n'; 650 651 /* write data to serial port */ 652 tmp = write(intf->fd, data, size); 653 if (tmp <= 0) { 654 lperror(LOG_ERR, "ipmitool: write error"); 655 return -1; 656 } 657 658 return 0; 659 } 660 661 /* 662 * Wait for request response 663 */ 664 static int 665 serial_term_wait_response(struct ipmi_intf * intf, 666 struct serial_term_request_ctx * req_ctx, 667 uint8_t * msg, size_t max_len) 668 { 669 struct serial_term_hdr * hdr = (struct serial_term_hdr *) msg; 670 int msg_len; 671 672 /* wait for response(s) */ 673 do { 674 /* receive message */ 675 msg_len = recv_response(intf, msg, max_len); 676 677 /* check if valid message received */ 678 if (msg_len > 0) { 679 /* validate message size */ 680 if (msg_len < 4) { 681 /* either bad response or non-related message */ 682 continue; 683 } 684 685 /* check for the waited response */ 686 if (hdr->netFn == (req_ctx->netFn|4) 687 && (hdr->seq & ~3) == req_ctx->seq 688 && hdr->cmd == req_ctx->cmd) { 689 /* check if something new has been parsed */ 690 if (verbose > 3) { 691 fprintf(stderr, "Got response:\n"); 692 fprintf(stderr, " NetFN/rsLUN = 0x%x\n", msg[0]); 693 fprintf(stderr, " rqSeq/Bridge = 0x%x\n", msg[1]); 694 fprintf(stderr, " cmd = 0x%x\n", msg[2]); 695 fprintf(stderr, " completion code = 0x%x\n", msg[3]); 696 if (msg_len > 8) { 697 fprintf(stderr, " data_len = %d\n", 698 msg_len - 4); 699 fprintf(stderr, " data = %s\n", 700 buf2str(msg + 4, msg_len - 4)); 701 } 702 } 703 704 /* move to start from completion code */ 705 memmove(msg, hdr + 1, msg_len - sizeof (*hdr)); 706 707 /* the waited one */ 708 return msg_len - sizeof (*hdr); 709 } 710 } 711 } while (msg_len > 0); 712 713 return 0; 714 } 715 716 /* 717 * Get message from receive message queue 718 */ 719 static int 720 serial_term_get_message(struct ipmi_intf * intf, 721 struct serial_term_request_ctx * req_ctx, 722 uint8_t * msg, size_t max_len) 723 { 724 uint8_t data[IPMI_SERIAL_MAX_RESPONSE]; 725 struct serial_term_request_ctx tmp_ctx; 726 struct ipmi_get_message_rp * rp = (struct ipmi_get_message_rp *) data; 727 struct serial_term_hdr hdr; 728 clock_t start, tm; 729 int rv, netFn, rqSeq; 730 731 start = clock(); 732 733 do { 734 /* fill-in request context */ 735 tmp_ctx.netFn = 0x18; 736 tmp_ctx.seq = serial_term_alloc_seq() << 2; 737 tmp_ctx.cmd = 0x33; 738 739 /* fill-in request data */ 740 hdr.netFn = tmp_ctx.netFn; 741 hdr.seq = tmp_ctx.seq; 742 hdr.cmd = tmp_ctx.cmd; 743 744 /* send request */ 745 serial_flush(intf); 746 serial_term_send_msg(intf, (uint8_t *) &hdr, 3); 747 748 /* wait for response */ 749 rv = serial_term_wait_response(intf, &tmp_ctx, data, sizeof (data)); 750 751 /* check for IO error or timeout */ 752 if (rv <= 0) { 753 return rv; 754 } 755 756 netFn = (req_ctx->netFn & ~3)|(req_ctx->seq & 3)|4; 757 rqSeq = req_ctx->seq & ~3; 758 759 /* check completion code */ 760 if (rp->completion == 0) { 761 /* check for the waited response */ 762 if (rp->netFn == netFn 763 && rp->rsSA == req_ctx->sa 764 && rp->rqSeq == rqSeq 765 && rp->cmd == req_ctx->cmd) { 766 /* copy the rest of message */ 767 memcpy(msg, rp + 1, rv - sizeof (*rp) - 1); 768 return rv - sizeof (*rp) - 1; 769 } 770 } else if (rp->completion != 0x80) { 771 return 0; 772 } 773 774 tm = clock() - start; 775 776 tm /= CLOCKS_PER_SEC; 777 } while (tm < intf->session->timeout); 778 779 return 0; 780 } 781 782 static struct ipmi_rs * 783 ipmi_serial_term_send_cmd(struct ipmi_intf * intf, struct ipmi_rq * req) 784 { 785 static struct ipmi_rs rsp; 786 uint8_t msg[IPMI_SERIAL_MAX_RESPONSE], * resp = msg; 787 struct serial_term_request_ctx req_ctx[2]; 788 int retry, rv, msg_len, bridging_level; 789 790 if (!intf->opened && intf->open && intf->open(intf) < 0) { 791 return NULL; 792 } 793 794 /* Send the message and receive the answer */ 795 for (retry = 0; retry < intf->session->retry; retry++) { 796 /* build output message */ 797 bridging_level = serial_term_build_msg(intf, req, msg, 798 sizeof (msg), req_ctx, &msg_len); 799 if (msg_len < 0) { 800 return NULL; 801 } 802 803 /* send request */ 804 serial_flush(intf); 805 serial_term_send_msg(intf, msg, msg_len); 806 807 /* wait for response */ 808 rv = serial_term_wait_response(intf, &req_ctx[0], msg, sizeof (msg)); 809 810 /* check for IO error */ 811 if (rv < 0) { 812 return NULL; 813 } 814 815 /* check for timeout */ 816 if (rv == 0) { 817 continue; 818 } 819 820 /* check for bridging */ 821 if (bridging_level && msg[0] == 0) { 822 /* in the case of payload interface we check receive message queue */ 823 if (is_system) { 824 /* check message flags */ 825 rv = serial_term_get_message(intf, &req_ctx[1], 826 msg, sizeof (msg)); 827 828 /* check for IO error */ 829 if (rv < 0) { 830 return NULL; 831 } 832 833 /* check for timeout */ 834 if (rv == 0) { 835 continue; 836 } 837 /* check if response for inner request is not encapsulated */ 838 } else if (rv == 1) { 839 /* wait for response for inner request */ 840 rv = serial_term_wait_response(intf, &req_ctx[1], 841 msg, sizeof (msg)); 842 843 /* check for IO error */ 844 if (rv < 0) { 845 return NULL; 846 } 847 848 /* check for timeout */ 849 if (rv == 0) { 850 continue; 851 } 852 } else { 853 /* skip outer level header */ 854 resp = msg + sizeof (struct ipmb_msg_hdr) + 1; 855 /* decrement response size */ 856 rv -= + sizeof (struct ipmb_msg_hdr) + 2; 857 } 858 859 /* check response size */ 860 if (resp[0] == 0 && bridging_level == 2 && rv < 8) { 861 lprintf(LOG_ERR, "ipmitool: Message response is too short"); 862 /* invalid message length */ 863 return NULL; 864 } 865 } 866 867 /* check for double bridging */ 868 if (bridging_level == 2 && resp[0] == 0) { 869 /* get completion code */ 870 rsp.ccode = resp[7]; 871 rsp.data_len = rv - 9; 872 memcpy(rsp.data, resp + 8, rsp.data_len); 873 } else { 874 rsp.ccode = resp[0]; 875 rsp.data_len = rv - 1; 876 memcpy(rsp.data, resp + 1, rsp.data_len); 877 } 878 879 /* return response */ 880 return &rsp; 881 } 882 883 /* no valid response */ 884 return NULL; 885 } 886 887 static int 888 ipmi_serial_term_setup(struct ipmi_intf * intf) 889 { 890 intf->session = malloc(sizeof(struct ipmi_session)); 891 if (intf->session == NULL) { 892 lprintf(LOG_ERR, "ipmitool: malloc failure"); 893 return -1; 894 } 895 896 memset(intf->session, 0, sizeof(struct ipmi_session)); 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