1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 /* 28 * Platform Channel Protocol Library functions on Nigara platforms 29 * (Ontario, Erie, etc..) Solaris applications use these interfaces 30 * to communicate with entities that reside on service processor. 31 */ 32 33 #pragma ident "%Z%%M% %I% %E% SMI" 34 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <unistd.h> 38 #include <string.h> 39 #include <assert.h> 40 #include <fcntl.h> 41 #include <errno.h> 42 #include <signal.h> 43 #include <setjmp.h> 44 #include <inttypes.h> 45 #include <umem.h> 46 #include <strings.h> 47 #include <sys/types.h> 48 #include <sys/stat.h> 49 #include <sys/glvc.h> 50 #include <netinet/in.h> 51 52 #include "libpcp.h" 53 #include "pcp_common.h" 54 55 /* 56 * Following libpcp interfaces are exposed to user applications. 57 * 58 * int pcp_init(char *channel_dev_path); 59 * int pcp_send_recv(pcp_msg_t *req_msg, pcp_msg_t *resp_msg, uint32_t timeout); 60 * int pcp_close(void); 61 * 62 */ 63 64 /* 65 * Forward declarations. 66 */ 67 static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr); 68 static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr); 69 static int pcp_io_op(void *buf, int byte_cnt, int io_op); 70 static int pcp_get_xid(void); 71 static int pcp_get_prop(int prop, unsigned int *val); 72 static int pcp_read(uint8_t *buf, int buf_len); 73 static int pcp_write(uint8_t *buf, int buf_len); 74 static int pcp_peek(uint8_t *buf, int buf_len); 75 static int pcp_peek_read(uint8_t *buf, int buf_len); 76 static int pcp_frame_error_handle(void); 77 static int check_magic_byte_presence(int byte_cnt, uint8_t *byte_val, 78 int *ispresent); 79 static uint16_t checksum(uint16_t *addr, int32_t count); 80 static int pcp_cleanup(void); 81 82 /* 83 * glvc driver file descriptor 84 */ 85 static int chnl_fd = -1; 86 87 /* 88 * Message Transaction ID 89 */ 90 static uint32_t msg_xid = 0; 91 92 /* 93 * Channel MTU size. 94 */ 95 static unsigned int mtu_size = PCPL_DEF_MTU_SZ; 96 97 /* 98 * timeout field is supplied by user. timeout field is used to decide 99 * how long to block on glvc driver calls before we return timeout error 100 * to user applications. 101 * 102 * Note: In the current implementation of glvc driver, all glvc calls are 103 * blocking. 104 */ 105 static uint32_t glvc_timeout = 0; 106 107 /* 108 * variables used by setsetjmp/siglongjmp. 109 */ 110 static volatile sig_atomic_t jumpok = 0; 111 static sigjmp_buf jmpbuf; 112 113 /* 114 * To unblock SIGALRM signal incase if it's blocked in libpcp user apps. 115 * Restore it to old state during pcp_close. 116 */ 117 static sigset_t blkset; 118 119 /* 120 * Buffers used for stream reading channel data. When data is read in 121 * stream fashion, first data is copied from channel (glvc) buffers to 122 * these local buffers from which the read requests are serviced. 123 */ 124 #define READ_AREA_SIZE (2*mtu_size) 125 static uint8_t *read_head = NULL; 126 static uint8_t *read_tail = NULL; 127 static uint8_t *read_area = NULL; 128 129 /* 130 * Buffer used for peeking new data available in channel (glvc) buffers. 131 */ 132 #define PEEK_AREA_SIZE (mtu_size) 133 static uint8_t *peek_area = NULL; 134 135 /* 136 * Buffers used for peeking data available either in local buffers or 137 * new data available in channel (glvc) buffers. 138 */ 139 #define PEEK_READ_AREA_SIZE (2*mtu_size) 140 static uint8_t *peek_read_head = NULL; 141 static uint8_t *peek_read_tail = NULL; 142 static uint8_t *peek_read_area = NULL; 143 144 static pcp_req_msg_hdr_t *req_msg_hdr = NULL; 145 static pcp_resp_msg_hdr_t *resp_msg_hdr = NULL; 146 static int req_msg_hdr_sz = 0; 147 static int resp_msg_hdr_sz = 0; 148 149 /* 150 * signal handling variables to handle glvc blocking calls. 151 */ 152 static struct sigaction glvc_act; 153 154 /* To restore old SIGALRM signal handler */ 155 static struct sigaction old_act; 156 157 static void 158 glvc_timeout_handler(void) 159 { 160 if (jumpok == 0) 161 return; 162 siglongjmp(jmpbuf, 1); 163 } 164 165 /* 166 * Initialize the virtual channel. It basically opens the virtual channel 167 * provided by the host application. 168 * 169 */ 170 171 int 172 pcp_init(char *channel_dev_path) 173 { 174 sigset_t oldset; 175 176 if (channel_dev_path == NULL) 177 return (PCPL_INVALID_ARGS); 178 /* 179 * Open virtual channel device node. 180 */ 181 if ((chnl_fd = open(channel_dev_path, O_RDWR|O_EXCL)) < 0) { 182 return (PCPL_GLVC_ERROR); 183 } 184 185 /* 186 * Initialize Message Transaction ID. 187 */ 188 msg_xid = PCPL_INIT_XID; 189 190 /* 191 * Get the Channel MTU size 192 */ 193 194 if (pcp_get_prop(GLVC_XPORT_OPT_MTU_SZ, &mtu_size) != 0) { 195 (void) close(chnl_fd); 196 chnl_fd = -1; 197 return (PCPL_GLVC_ERROR); 198 } 199 200 /* 201 * Get current signal mask. If SIGALRM is blocked 202 * unblock it. 203 */ 204 (void) sigprocmask(0, NULL, &oldset); 205 206 (void) sigemptyset(&blkset); 207 208 if (sigismember(&oldset, SIGALRM)) { 209 (void) sigaddset(&blkset, SIGALRM); 210 (void) sigprocmask(SIG_UNBLOCK, &blkset, NULL); 211 } 212 /* 213 * signal handler initialization to handle glvc call timeouts. 214 */ 215 glvc_act.sa_handler = glvc_timeout_handler; 216 (void) sigemptyset(&glvc_act.sa_mask); 217 glvc_act.sa_flags = SA_NODEFER; 218 219 if (sigaction(SIGALRM, &glvc_act, &old_act) < 0) { 220 (void) close(chnl_fd); 221 chnl_fd = -1; 222 return (PCPL_ERROR); 223 } 224 225 return (PCPL_OK); 226 } 227 228 /* 229 * Function: Close platform channel. 230 * Arguments: None 231 * Returns: 232 * always returns PCPL_OK for now. 233 */ 234 int 235 pcp_close(void) 236 { 237 238 if (chnl_fd >= 0) { 239 (void) pcp_cleanup(); 240 (void) close(chnl_fd); 241 chnl_fd = -1; 242 } 243 244 /* 245 * free global buffers 246 */ 247 if (read_area != NULL) { 248 umem_free(read_area, READ_AREA_SIZE); 249 read_area = NULL; 250 } 251 if (peek_area != NULL) { 252 umem_free(peek_area, PEEK_AREA_SIZE); 253 peek_area = NULL; 254 } 255 if (peek_read_area != NULL) { 256 umem_free(peek_read_area, PEEK_READ_AREA_SIZE); 257 peek_read_area = NULL; 258 } 259 if (req_msg_hdr != NULL) { 260 umem_free(req_msg_hdr, req_msg_hdr_sz); 261 req_msg_hdr = NULL; 262 } 263 if (resp_msg_hdr != NULL) { 264 umem_free(resp_msg_hdr, resp_msg_hdr_sz); 265 resp_msg_hdr = NULL; 266 } 267 268 /* 269 * Restore SIGALRM signal mask incase if we unblocked 270 * it during pcp_init. 271 */ 272 if (sigismember(&blkset, SIGALRM)) { 273 (void) sigprocmask(SIG_BLOCK, &blkset, NULL); 274 } 275 276 /* Restore SIGALRM signal handler */ 277 (void) sigaction(SIGALRM, &old_act, NULL); 278 279 return (PCPL_OK); 280 } 281 282 /* 283 * Function: Send and Receive messages on platform channel. 284 * Arguments: 285 * pcp_msg_t *req_msg - Request Message to send to other end of channel. 286 * pcp_msg_t *resp_msg - Response Message to be received. 287 * uint32_t timeout - timeout field when waiting for data from channel. 288 * Returns: 289 * 0 - success (PCPL_OK). 290 * (-ve) - failure: 291 * PCPL_INVALID_ARGS - invalid args. 292 * PCPL_GLVC_TIMEOUT - glvc call timeout. 293 * PCPL_XPORT_ERROR - transport error in request message 294 * noticed by receiver. 295 * PCPL_MALLOC_FAIL - malloc failure. 296 * PCPL_CKSUM_ERROR - checksum error. 297 */ 298 int 299 pcp_send_recv(pcp_msg_t *req_msg, pcp_msg_t *resp_msg, uint32_t timeout) 300 { 301 void *datap; 302 void *resp_msg_data = NULL; 303 uint32_t status; 304 uint16_t cksum = 0; 305 int ret; 306 int resp_hdr_ok; 307 #ifdef PCP_CKSUM_ENABLE 308 uint16_t bkup_resp_hdr_cksum; 309 #endif 310 if (chnl_fd < 0) { 311 return (PCPL_ERROR); 312 } 313 314 if (req_msg == NULL) { 315 return (PCPL_INVALID_ARGS); 316 } 317 318 if (timeout > 0) 319 glvc_timeout = timeout; 320 else 321 glvc_timeout = 0; 322 323 if ((datap = req_msg->msg_data) == NULL) 324 return (PCPL_INVALID_ARGS); 325 326 if (req_msg_hdr == NULL) { 327 req_msg_hdr_sz = sizeof (pcp_req_msg_hdr_t); 328 req_msg_hdr = (pcp_req_msg_hdr_t *)umem_zalloc(req_msg_hdr_sz, 329 UMEM_DEFAULT); 330 if (req_msg_hdr == NULL) 331 return (PCPL_MALLOC_FAIL); 332 } 333 334 /* calculate request msg_cksum */ 335 cksum = checksum((uint16_t *)datap, req_msg->msg_len); 336 337 /* 338 * Fill in the message header for the request packet 339 */ 340 req_msg_hdr->magic_num = PCP_MAGIC_NUM; 341 req_msg_hdr->proto_ver = PCP_PROT_VER_1; 342 req_msg_hdr->msg_type = req_msg->msg_type; 343 req_msg_hdr->sub_type = req_msg->sub_type; 344 req_msg_hdr->rsvd_pad = 0; 345 req_msg_hdr->xid = pcp_get_xid(); 346 req_msg_hdr->msg_len = req_msg->msg_len; 347 req_msg_hdr->timeout = timeout; 348 req_msg_hdr->msg_cksum = cksum; 349 req_msg_hdr->hdr_cksum = 0; 350 351 /* fill request header checksum */ 352 req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr, 353 req_msg_hdr_sz); 354 /* 355 * set sig jmp location 356 */ 357 if (sigsetjmp(jmpbuf, 1)) { 358 return (PCPL_GLVC_TIMEOUT); 359 } 360 jumpok = 1; /* monitor sigalrm from now on */ 361 362 /* 363 * send request message header 364 */ 365 if ((ret = pcp_send_req_msg_hdr(req_msg_hdr))) { 366 367 return (ret); 368 } 369 370 /* 371 * send request message 372 */ 373 if ((ret = pcp_io_op(datap, req_msg->msg_len, 374 PCPL_IO_OP_WRITE))) { 375 return (ret); 376 } 377 if (timeout == (uint32_t)PCP_TO_NO_RESPONSE) 378 return (PCPL_OK); 379 380 if (resp_msg_hdr == NULL) { 381 resp_msg_hdr_sz = sizeof (pcp_resp_msg_hdr_t); 382 resp_msg_hdr = (pcp_resp_msg_hdr_t *)umem_alloc(resp_msg_hdr_sz, 383 UMEM_DEFAULT); 384 if (resp_msg_hdr == NULL) 385 return (PCPL_MALLOC_FAIL); 386 } 387 388 resp_hdr_ok = 0; 389 while (!resp_hdr_ok) { 390 391 /* 392 * Receive response message header 393 * Note: frame error handling is done in 394 * 'pcp_recv_resp_msg_hdr()'. 395 */ 396 if ((ret = pcp_recv_resp_msg_hdr(resp_msg_hdr))) { 397 return (ret); 398 } 399 400 /* 401 * Check header checksum if it matches with the received hdr 402 * checksum. 403 */ 404 #ifdef PCP_CKSUM_ENABLE 405 bkup_resp_hdr_cksum = resp_msg_hdr->hdr_cksum; 406 resp_msg_hdr->hdr_cksum = 0; 407 cksum = checksum((uint16_t *)resp_msg_hdr, resp_msg_hdr_sz); 408 409 if (cksum != bkup_resp_hdr_cksum) { 410 return (PCPL_CKSUM_ERROR); 411 } 412 #endif 413 /* 414 * Check for matching request and response messages 415 */ 416 if (resp_msg_hdr->xid != req_msg_hdr->xid) { 417 418 continue; /* continue reading response header */ 419 } 420 resp_hdr_ok = 1; 421 } 422 423 /* 424 * check status field for any channel protocol errrors 425 * This field signifies something happend during request 426 * message trasmission. This field is set by the receiver. 427 */ 428 status = resp_msg_hdr->status; 429 if (status != PCP_OK) { 430 return (PCPL_XPORT_ERROR); 431 } 432 433 434 /* libpcp users should free this memory */ 435 if ((resp_msg_data = (uint8_t *)malloc(resp_msg_hdr->msg_len)) == NULL) 436 return (PCPL_MALLOC_FAIL); 437 bzero(resp_msg_data, resp_msg_hdr->msg_len); 438 /* 439 * Receive response message. 440 */ 441 if ((ret = pcp_io_op(resp_msg_data, resp_msg_hdr->msg_len, 442 PCPL_IO_OP_READ))) { 443 free(resp_msg_data); 444 return (ret); 445 } 446 447 #ifdef PCP_CKSUM_ENABLE 448 /* verify response message data checksum */ 449 cksum = checksum((uint16_t *)resp_msg_data, 450 resp_msg_hdr->msg_len); 451 if (cksum != resp_msg_hdr->msg_cksum) { 452 free(resp_msg_data); 453 return (PCPL_CKSUM_ERROR); 454 } 455 #endif 456 457 /* Everything is okay put the received data into user */ 458 /* application's resp_msg struct */ 459 resp_msg->msg_len = resp_msg_hdr->msg_len; 460 resp_msg->msg_type = resp_msg_hdr->msg_type; 461 resp_msg->sub_type = resp_msg_hdr->sub_type; 462 resp_msg->msg_data = (uint8_t *)resp_msg_data; 463 464 return (PCPL_OK); 465 466 } 467 468 /* 469 * Function: Get channel property values. 470 * Arguments: 471 * int prop - property id. 472 * unsigned int *val - property value tobe copied. 473 * Returns: 474 * 0 - success 475 * (-ve) - failure: 476 * PCPL_ERR_GLVC - glvc ioctl failure. 477 */ 478 479 static int 480 pcp_get_prop(int prop, unsigned int *val) 481 { 482 glvc_xport_opt_op_t channel_op; 483 int ret; 484 485 channel_op.op_sel = GLVC_XPORT_OPT_GET; 486 channel_op.opt_sel = prop; 487 channel_op.opt_val = 0; 488 489 (void) alarm(glvc_timeout); 490 491 if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_OPT_OP, &channel_op)) < 0) { 492 (void) alarm(0); 493 return (ret); 494 } 495 (void) alarm(0); 496 497 *val = channel_op.opt_val; 498 499 return (0); 500 } 501 502 /* 503 * Function: wrapper for handling glvc calls (read/write/peek). 504 */ 505 static int 506 pcp_io_op(void *buf, int byte_cnt, int io_op) 507 { 508 int rv; 509 int n; 510 uint8_t *datap; 511 int (*func_ptr)(uint8_t *, int); 512 int io_sz; 513 int try_cnt; 514 515 516 if ((buf == NULL) || (byte_cnt < 0)) { 517 return (PCPL_INVALID_ARGS); 518 } 519 520 switch (io_op) { 521 case PCPL_IO_OP_READ: 522 func_ptr = pcp_read; 523 break; 524 case PCPL_IO_OP_WRITE: 525 func_ptr = pcp_write; 526 break; 527 case PCPL_IO_OP_PEEK: 528 func_ptr = pcp_peek; 529 break; 530 default: 531 return (PCPL_INVALID_ARGS); 532 } 533 534 /* 535 * loop until all I/O done, try limit exceded, or real failure 536 */ 537 538 rv = 0; 539 datap = buf; 540 while (rv < byte_cnt) { 541 io_sz = MIN((byte_cnt - rv), mtu_size); 542 try_cnt = 0; 543 while ((n = (*func_ptr)(datap, io_sz)) < 0) { 544 try_cnt++; 545 if (try_cnt > PCPL_MAX_TRY_CNT) { 546 rv = n; 547 goto done; 548 } 549 (void) sleep(PCPL_GLVC_SLEEP); 550 } /* while trying the io operation */ 551 552 if (n < 0) { 553 rv = n; 554 goto done; 555 } 556 rv += n; 557 datap += n; 558 } /* while still have more data */ 559 560 done: 561 if (rv == byte_cnt) 562 return (0); 563 else 564 return (PCPL_GLVC_ERROR); 565 } 566 567 /* 568 * For peeking 'bytes_cnt' bytes in channel (glvc) buffers. 569 * If data is available, the data is copied into 'buf'. 570 */ 571 static int 572 pcp_peek(uint8_t *buf, int bytes_cnt) 573 { 574 int ret; 575 glvc_xport_msg_peek_t peek_ctrl; 576 int n, m; 577 578 if (bytes_cnt < 0 || bytes_cnt > mtu_size) { 579 return (PCPL_INVALID_ARGS); 580 } 581 582 /* 583 * initialization of buffers used for peeking data in channel buffers. 584 */ 585 if (peek_area == NULL) { 586 peek_area = (uint8_t *)umem_zalloc(PEEK_AREA_SIZE, 587 UMEM_DEFAULT); 588 if (peek_area == NULL) { 589 return (PCPL_MALLOC_FAIL); 590 } 591 } 592 593 /* 594 * peek max MTU size bytes 595 */ 596 peek_ctrl.buf = (caddr_t)peek_area; 597 peek_ctrl.buflen = mtu_size; 598 peek_ctrl.flags = 0; 599 600 (void) alarm(glvc_timeout); 601 602 if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, &peek_ctrl)) 603 < 0) { 604 (void) alarm(0); 605 return (ret); 606 } 607 (void) alarm(0); 608 609 n = peek_ctrl.buflen; 610 611 if (n < 0) 612 return (PCPL_GLVC_ERROR); 613 614 /* 615 * satisfy request as best as we can 616 */ 617 m = MIN(bytes_cnt, n); 618 (void) memcpy(buf, peek_area, m); 619 620 return (m); 621 622 } 623 624 /* 625 * Function: write 'byte_cnt' bytes from 'buf' to channel. 626 */ 627 static int 628 pcp_write(uint8_t *buf, int byte_cnt) 629 { 630 631 int ret; 632 633 /* check for valid arguments */ 634 if (buf == NULL || byte_cnt < 0 || byte_cnt > mtu_size) { 635 return (PCPL_INVALID_ARGS); 636 } 637 638 (void) alarm(glvc_timeout); 639 640 if ((ret = write(chnl_fd, buf, byte_cnt)) < 0) { 641 (void) alarm(0); 642 return (ret); 643 } 644 (void) alarm(0); 645 646 return (ret); 647 } 648 649 /* 650 * In current implementaion of glvc driver, streams reads are not supported. 651 * pcp_read mimics stream reads by first reading all the bytes present in the 652 * channel buffer into a local buffer and from then on read requests 653 * are serviced from local buffer. When read requests are not serviceble 654 * from local buffer, it repeates by first reading data from channel buffers. 655 * 656 * This call may need to be enhanced when glvc supports buffered (stream) 657 * reads - TBD 658 */ 659 660 static int 661 pcp_read(uint8_t *buf, int byte_cnt) 662 { 663 int ret; 664 int n, m, i; 665 666 if (byte_cnt < 0 || byte_cnt > mtu_size) { 667 return (PCPL_INVALID_ARGS); 668 } 669 670 /* 671 * initialization of local read buffer 672 * from which the stream read requests are serviced. 673 */ 674 if (read_area == NULL) { 675 read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE, 676 UMEM_DEFAULT); 677 if (read_area == NULL) { 678 return (PCPL_MALLOC_FAIL); 679 } 680 read_head = read_area; 681 read_tail = read_area; 682 } 683 684 /* 685 * if we already read this data then copy from local buffer it self 686 * without calling new read. 687 */ 688 if (byte_cnt <= (read_tail - read_head)) { 689 (void) memcpy(buf, read_head, byte_cnt); 690 read_head += byte_cnt; 691 return (byte_cnt); 692 } 693 694 /* 695 * if the request is not satisfied from the buffered data, then move the 696 * remaining data to front of the buffer and read new data. 697 */ 698 for (i = 0; i < (read_tail - read_head); ++i) { 699 read_area[i] = read_head[i]; 700 } 701 read_head = read_area; 702 read_tail = read_head + i; 703 704 /* 705 * do a peek to see how much data is available and read complete data. 706 */ 707 708 if ((m = pcp_peek(read_tail, mtu_size)) < 0) { 709 return (m); 710 } 711 712 (void) alarm(glvc_timeout); 713 if ((ret = read(chnl_fd, read_tail, m)) < 0) { 714 (void) alarm(0); 715 return (ret); 716 } 717 718 (void) alarm(0); 719 read_tail += ret; 720 721 /* 722 * copy the requested bytes. 723 */ 724 n = MIN(byte_cnt, (read_tail - read_head)); 725 (void) memcpy(buf, read_head, n); 726 727 read_head += n; 728 729 return (n); 730 } 731 732 /* 733 * This function is slight different from pcp_peek. The peek requests are first 734 * serviced from local read buffer, if data is available. If the peek request 735 * is not serviceble from local read buffer, then the data is peeked from 736 * channel buffer. This function is mainly used for proper protocol framing 737 * error handling. 738 */ 739 static int 740 pcp_peek_read(uint8_t *buf, int byte_cnt) 741 { 742 int n, m, i; 743 744 if (byte_cnt < 0 || byte_cnt > mtu_size) { 745 return (PCPL_INVALID_ARGS); 746 } 747 748 /* 749 * initialization of peek_read buffer. 750 */ 751 if (peek_read_area == NULL) { 752 peek_read_area = (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE, 753 UMEM_DEFAULT); 754 if (peek_read_area == NULL) { 755 return (PCPL_MALLOC_FAIL); 756 } 757 peek_read_head = peek_read_area; 758 peek_read_tail = peek_read_area; 759 } 760 761 /* 762 * if we already have the data in local read buffer then copy 763 * from local buffer it self w/out calling new peek 764 */ 765 if (byte_cnt <= (read_tail - read_head)) { 766 (void) memcpy(buf, read_head, byte_cnt); 767 return (byte_cnt); 768 } 769 770 /* 771 * if the request is not satisfied from local read buffer, then first 772 * copy the remaining data in local read buffer to peek_read_area and 773 * then issue new peek. 774 */ 775 for (i = 0; i < (read_tail - read_head); ++i) { 776 peek_read_area[i] = read_head[i]; 777 } 778 peek_read_head = peek_read_area; 779 peek_read_tail = peek_read_head + i; 780 781 /* 782 * do a peek to see how much data is available and read complete data. 783 */ 784 785 if ((m = pcp_peek(peek_read_tail, mtu_size)) < 0) { 786 return (m); 787 } 788 789 peek_read_tail += m; 790 791 /* 792 * copy the requested bytes 793 */ 794 n = MIN(byte_cnt, (peek_read_tail - peek_read_head)); 795 (void) memcpy(buf, peek_read_head, n); 796 797 return (n); 798 } 799 800 /* 801 * Send Request Message Header. 802 */ 803 static int 804 pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr) 805 { 806 pcp_req_msg_hdr_t *hdrp; 807 int hdr_sz; 808 int ret; 809 810 hdr_sz = sizeof (pcp_req_msg_hdr_t); 811 if ((hdrp = (pcp_req_msg_hdr_t *)umem_zalloc(hdr_sz, 812 UMEM_DEFAULT)) == NULL) { 813 return (PCPL_MALLOC_FAIL); 814 } 815 816 hdrp->magic_num = htonl(req_hdr->magic_num); 817 hdrp->proto_ver = req_hdr->proto_ver; 818 hdrp->msg_type = req_hdr->msg_type; 819 hdrp->sub_type = req_hdr->sub_type; 820 hdrp->rsvd_pad = htons(req_hdr->rsvd_pad); 821 hdrp->xid = htonl(req_hdr->xid); 822 hdrp->timeout = htonl(req_hdr->timeout); 823 hdrp->msg_len = htonl(req_hdr->msg_len); 824 hdrp->msg_cksum = htons(req_hdr->msg_cksum); 825 hdrp->hdr_cksum = htons(req_hdr->hdr_cksum); 826 827 if ((ret = pcp_io_op((char *)hdrp, hdr_sz, PCPL_IO_OP_WRITE)) != 0) { 828 umem_free(hdrp, hdr_sz); 829 return (ret); 830 } 831 umem_free(hdrp, hdr_sz); 832 return (PCP_OK); 833 } 834 835 /* 836 * Receive Response message header. 837 */ 838 static int 839 pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr) 840 { 841 uint32_t magic_num; 842 uint8_t proto_ver; 843 uint8_t msg_type; 844 uint8_t sub_type; 845 uint8_t rsvd_pad; 846 uint32_t xid; 847 uint32_t timeout; 848 uint32_t msg_len; 849 uint32_t status; 850 uint16_t msg_cksum; 851 uint16_t hdr_cksum; 852 int ret; 853 854 if (resp_hdr == NULL) { 855 return (PCPL_INVALID_ARGS); 856 } 857 858 /* 859 * handle protocol framing errors. 860 * pcp_frame_error_handle() returns when proper frame arrived 861 * (magic seq) or if an error happens while reading data from 862 * channel. 863 */ 864 if ((ret = pcp_frame_error_handle()) != 0) 865 return (PCPL_FRAME_ERROR); 866 867 /* read magic number first */ 868 if ((ret = pcp_io_op(&magic_num, sizeof (magic_num), 869 PCPL_IO_OP_READ)) != 0) { 870 return (ret); 871 } 872 873 magic_num = ntohl(magic_num); 874 875 if (magic_num != PCP_MAGIC_NUM) { 876 return (PCPL_FRAME_ERROR); 877 } 878 879 /* read version field */ 880 if ((ret = pcp_io_op(&proto_ver, sizeof (proto_ver), 881 PCPL_IO_OP_READ)) != 0) { 882 return (ret); 883 } 884 885 /* check protocol version */ 886 if (proto_ver != PCP_PROT_VER_1) { 887 return (PCPL_PROT_ERROR); 888 } 889 890 /* Read message type */ 891 if ((ret = pcp_io_op(&msg_type, sizeof (msg_type), 892 PCPL_IO_OP_READ)) != 0) { 893 return (ret); 894 } 895 896 /* Read message sub type */ 897 if ((ret = pcp_io_op(&sub_type, sizeof (sub_type), 898 PCPL_IO_OP_READ)) != 0) { 899 return (ret); 900 } 901 902 /* Read rcvd_pad bits */ 903 if ((ret = pcp_io_op(&rsvd_pad, sizeof (rsvd_pad), 904 PCPL_IO_OP_READ)) != 0) { 905 return (ret); 906 } 907 908 /* receive transaction id */ 909 if ((ret = pcp_io_op(&xid, sizeof (xid), 910 PCPL_IO_OP_READ)) != 0) { 911 return (ret); 912 } 913 914 xid = ntohl(xid); 915 916 /* receive timeout value */ 917 if ((ret = pcp_io_op(&timeout, sizeof (timeout), 918 PCPL_IO_OP_READ)) != 0) { 919 return (ret); 920 } 921 922 timeout = ntohl(timeout); 923 924 /* receive message length */ 925 if ((ret = pcp_io_op(&msg_len, sizeof (msg_len), 926 PCPL_IO_OP_READ)) != 0) { 927 return (ret); 928 } 929 930 msg_len = ntohl(msg_len); 931 932 /* receive status field */ 933 if ((ret = pcp_io_op(&status, sizeof (status), 934 PCPL_IO_OP_READ)) != 0) { 935 return (ret); 936 } 937 938 status = ntohl(status); 939 940 /* receive message checksum */ 941 if ((ret = pcp_io_op(&msg_cksum, sizeof (msg_cksum), 942 PCPL_IO_OP_READ)) != 0) { 943 return (ret); 944 } 945 946 msg_cksum = ntohs(msg_cksum); 947 948 /* receive header checksum */ 949 if ((ret = pcp_io_op(&hdr_cksum, sizeof (hdr_cksum), 950 PCPL_IO_OP_READ)) != 0) { 951 return (ret); 952 } 953 954 hdr_cksum = ntohs(hdr_cksum); 955 956 /* copy to resp_hdr */ 957 958 resp_hdr->magic_num = magic_num; 959 resp_hdr->proto_ver = proto_ver; 960 resp_hdr->msg_type = msg_type; 961 resp_hdr->sub_type = sub_type; 962 resp_hdr->rsvd_pad = rsvd_pad; 963 resp_hdr->xid = xid; 964 resp_hdr->timeout = timeout; 965 resp_hdr->msg_len = msg_len; 966 resp_hdr->status = status; 967 resp_hdr->msg_cksum = msg_cksum; 968 resp_hdr->hdr_cksum = hdr_cksum; 969 970 return (PCP_OK); 971 } 972 973 /* 974 * Get next xid for including in request message. 975 * Every request and response message are matched 976 * for same xid. 977 */ 978 static int pcp_get_xid(void) 979 { 980 uint32_t ret; 981 982 ret = msg_xid; 983 if (msg_xid == PCPL_MAX_XID) 984 msg_xid = PCPL_MIN_XID; 985 else 986 ++msg_xid; 987 return (ret); 988 } 989 990 /* 991 * This function handles channel framing errors. It waits until proper 992 * frame with starting sequence as magic numder (0xAFBCAFA0) 993 * is arrived. It removes unexpected data (before the magic number sequence) 994 * on the channel. It returns when proper magic number sequence is seen 995 * or when any failure happens while reading/peeking the channel. 996 */ 997 static int 998 pcp_frame_error_handle(void) 999 { 1000 uint8_t magic_num_buf[4]; 1001 int ispresent = 0; 1002 uint32_t net_magic_num; /* magic byte in network byte order */ 1003 uint32_t host_magic_num = PCP_MAGIC_NUM; 1004 uint8_t buf[2]; 1005 1006 net_magic_num = htonl(host_magic_num); 1007 (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4); 1008 1009 while (!ispresent) { 1010 /* 1011 * Check if next four bytes matches pcp magic number. 1012 * if mathing not found, discard 1 byte and continue checking. 1013 */ 1014 if (!check_magic_byte_presence(4, &magic_num_buf[0], 1015 &ispresent)) { 1016 if (!ispresent) { 1017 /* remove 1 byte */ 1018 (void) pcp_io_op(buf, 1, PCPL_IO_OP_READ); 1019 } 1020 } else { 1021 return (-1); 1022 } 1023 } 1024 1025 return (0); 1026 } 1027 1028 /* 1029 * checks whether certain byte sequence is present in the data stream. 1030 */ 1031 static int 1032 check_magic_byte_presence(int byte_cnt, uint8_t *byte_seq, int *ispresent) 1033 { 1034 int ret, i; 1035 uint8_t buf[4]; 1036 1037 if ((ret = pcp_peek_read(buf, byte_cnt)) < 0) { 1038 return (ret); 1039 } 1040 1041 /* 'byte_cnt' bytes not present */ 1042 if (ret != byte_cnt) { 1043 *ispresent = 0; 1044 return (0); 1045 } 1046 1047 for (i = 0; i < byte_cnt; ++i) { 1048 if (buf[i] != byte_seq[i]) { 1049 *ispresent = 0; 1050 return (0); 1051 } 1052 } 1053 *ispresent = 1; 1054 1055 return (0); 1056 } 1057 1058 /* 1059 * 16-bit simple internet checksum 1060 */ 1061 static uint16_t 1062 checksum(uint16_t *addr, int32_t count) 1063 { 1064 /* 1065 * Compute Internet Checksum for "count" bytes 1066 * beginning at location "addr". 1067 */ 1068 1069 register uint32_t sum = 0; 1070 1071 while (count > 1) { 1072 /* This is the inner loop */ 1073 sum += *(unsigned short *)addr++; 1074 count -= 2; 1075 } 1076 1077 /* Add left-over byte, if any */ 1078 if (count > 0) 1079 sum += * (unsigned char *)addr; 1080 1081 /* Fold 32-bit sum to 16 bits */ 1082 while (sum >> 16) 1083 sum = (sum & 0xffff) + (sum >> 16); 1084 1085 sum = (~sum) & 0xffff; 1086 if (sum == 0) 1087 sum = 0xffff; 1088 1089 return (sum); 1090 } 1091 1092 /* 1093 * cleanup the channel if any data is hanging in 1094 * channel buffers. 1095 */ 1096 static int 1097 pcp_cleanup(void) 1098 { 1099 int ret; 1100 glvc_xport_msg_peek_t peek_ctrl; 1101 int n, done; 1102 uint8_t *buf = NULL; 1103 int retry = 0; 1104 1105 1106 buf = (uint8_t *)umem_zalloc((mtu_size), UMEM_DEFAULT); 1107 if (buf == NULL) { 1108 return (PCPL_MALLOC_FAIL); 1109 } 1110 1111 peek_ctrl.buf = (caddr_t)buf; 1112 peek_ctrl.buflen = mtu_size; 1113 peek_ctrl.flags = 0; 1114 1115 /* 1116 * set sig jmp location 1117 */ 1118 if (sigsetjmp(jmpbuf, 1)) { 1119 umem_free(buf, mtu_size); 1120 return (PCPL_GLVC_TIMEOUT); 1121 } 1122 1123 done = 0; 1124 while (!done) { 1125 1126 (void) alarm(PCP_CLEANUP_TIMEOUT); 1127 if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, 1128 &peek_ctrl)) < 0) { 1129 (void) alarm(0); 1130 done = 1; 1131 continue; 1132 } 1133 (void) alarm(0); 1134 1135 n = peek_ctrl.buflen; 1136 1137 if (n <= 0 && retry > 2) { 1138 done = 1; 1139 continue; 1140 } else if (n <= 0) { 1141 ++retry; 1142 continue; 1143 } 1144 1145 /* remove data from channel */ 1146 (void) alarm(PCP_CLEANUP_TIMEOUT); 1147 if ((ret = read(chnl_fd, buf, n)) < 0) { 1148 (void) alarm(0); 1149 done = 1; 1150 continue; 1151 } 1152 (void) alarm(0); 1153 } 1154 1155 umem_free(buf, mtu_size); 1156 return (ret); 1157 } 1158