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