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