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