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