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