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