17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 51ae08745Sheppo * Common Development and Distribution License (the "License"). 61ae08745Sheppo * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*20ae46ebSha137994 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate /* 277c478bd9Sstevel@tonic-gate * Platform Channel Protocol Library functions on Nigara platforms 287c478bd9Sstevel@tonic-gate * (Ontario, Erie, etc..) Solaris applications use these interfaces 297c478bd9Sstevel@tonic-gate * to communicate with entities that reside on service processor. 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 337c478bd9Sstevel@tonic-gate 347c478bd9Sstevel@tonic-gate #include <stdio.h> 357c478bd9Sstevel@tonic-gate #include <stdlib.h> 367c478bd9Sstevel@tonic-gate #include <unistd.h> 377c478bd9Sstevel@tonic-gate #include <string.h> 387c478bd9Sstevel@tonic-gate #include <assert.h> 397c478bd9Sstevel@tonic-gate #include <fcntl.h> 407c478bd9Sstevel@tonic-gate #include <errno.h> 417c478bd9Sstevel@tonic-gate #include <signal.h> 427c478bd9Sstevel@tonic-gate #include <setjmp.h> 437c478bd9Sstevel@tonic-gate #include <inttypes.h> 447c478bd9Sstevel@tonic-gate #include <umem.h> 457c478bd9Sstevel@tonic-gate #include <strings.h> 4656b04ea6Smvgr #include <time.h> 477c478bd9Sstevel@tonic-gate #include <sys/types.h> 487c478bd9Sstevel@tonic-gate #include <sys/stat.h> 497c478bd9Sstevel@tonic-gate #include <sys/glvc.h> 501ae08745Sheppo #include <sys/vldc.h> 511ae08745Sheppo #include <sys/ldc.h> 527c478bd9Sstevel@tonic-gate #include <netinet/in.h> 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate #include "libpcp.h" 557c478bd9Sstevel@tonic-gate #include "pcp_common.h" 564bac2208Snarayan #include "pcp_utils.h" 574bac2208Snarayan 587c478bd9Sstevel@tonic-gate 597c478bd9Sstevel@tonic-gate /* 607c478bd9Sstevel@tonic-gate * Following libpcp interfaces are exposed to user applications. 617c478bd9Sstevel@tonic-gate * 625db09ef5Smvgr * int pcp_init(char *channel_name); 635db09ef5Smvgr * int pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg, 645db09ef5Smvgr * uint32_t timeout); 655db09ef5Smvgr * int pcp_close(int channel_fd); 667c478bd9Sstevel@tonic-gate * 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate /* 707c478bd9Sstevel@tonic-gate * Forward declarations. 717c478bd9Sstevel@tonic-gate */ 727c478bd9Sstevel@tonic-gate static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr); 737c478bd9Sstevel@tonic-gate static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr); 747c478bd9Sstevel@tonic-gate static int pcp_io_op(void *buf, int byte_cnt, int io_op); 7556b04ea6Smvgr static uint32_t pcp_get_xid(void); 765db09ef5Smvgr static int pcp_get_prop(int channel_fd, int prop, unsigned int *val); 777c478bd9Sstevel@tonic-gate static int pcp_read(uint8_t *buf, int buf_len); 787c478bd9Sstevel@tonic-gate static int pcp_write(uint8_t *buf, int buf_len); 797c478bd9Sstevel@tonic-gate static int pcp_peek(uint8_t *buf, int buf_len); 807c478bd9Sstevel@tonic-gate static int pcp_peek_read(uint8_t *buf, int buf_len); 817c478bd9Sstevel@tonic-gate static int pcp_frame_error_handle(void); 827c478bd9Sstevel@tonic-gate static int check_magic_byte_presence(int byte_cnt, uint8_t *byte_val, 837c478bd9Sstevel@tonic-gate int *ispresent); 847c478bd9Sstevel@tonic-gate static uint16_t checksum(uint16_t *addr, int32_t count); 855db09ef5Smvgr static int pcp_cleanup(int channel_fd); 867c478bd9Sstevel@tonic-gate 871ae08745Sheppo static int vldc_read(int fd, uint8_t *bufp, int size); 881ae08745Sheppo static int vldc_write(int fd, uint8_t *bufp, int size); 891ae08745Sheppo static int pcp_update_read_area(int byte_cnt); 901ae08745Sheppo static int pcp_vldc_frame_error_handle(void); 911ae08745Sheppo 927c478bd9Sstevel@tonic-gate /* 935db09ef5Smvgr * local channel (glvc) file descriptor set by pcp_send_recv() 947c478bd9Sstevel@tonic-gate */ 957c478bd9Sstevel@tonic-gate static int chnl_fd = -1; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * Message Transaction ID 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate static uint32_t msg_xid = 0; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate /* 1037c478bd9Sstevel@tonic-gate * Channel MTU size. 1047c478bd9Sstevel@tonic-gate */ 1057c478bd9Sstevel@tonic-gate static unsigned int mtu_size = PCPL_DEF_MTU_SZ; 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * timeout field is supplied by user. timeout field is used to decide 1097c478bd9Sstevel@tonic-gate * how long to block on glvc driver calls before we return timeout error 1107c478bd9Sstevel@tonic-gate * to user applications. 1117c478bd9Sstevel@tonic-gate * 1127c478bd9Sstevel@tonic-gate * Note: In the current implementation of glvc driver, all glvc calls are 1137c478bd9Sstevel@tonic-gate * blocking. 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate static uint32_t glvc_timeout = 0; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate /* 1187c478bd9Sstevel@tonic-gate * variables used by setsetjmp/siglongjmp. 1197c478bd9Sstevel@tonic-gate */ 1207c478bd9Sstevel@tonic-gate static volatile sig_atomic_t jumpok = 0; 1217c478bd9Sstevel@tonic-gate static sigjmp_buf jmpbuf; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate /* 1247c478bd9Sstevel@tonic-gate * To unblock SIGALRM signal incase if it's blocked in libpcp user apps. 1257c478bd9Sstevel@tonic-gate * Restore it to old state during pcp_close. 1267c478bd9Sstevel@tonic-gate */ 1277c478bd9Sstevel@tonic-gate static sigset_t blkset; 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * Buffers used for stream reading channel data. When data is read in 1317c478bd9Sstevel@tonic-gate * stream fashion, first data is copied from channel (glvc) buffers to 1327c478bd9Sstevel@tonic-gate * these local buffers from which the read requests are serviced. 1337c478bd9Sstevel@tonic-gate */ 1347c478bd9Sstevel@tonic-gate #define READ_AREA_SIZE (2*mtu_size) 1357c478bd9Sstevel@tonic-gate static uint8_t *read_head = NULL; 1367c478bd9Sstevel@tonic-gate static uint8_t *read_tail = NULL; 1377c478bd9Sstevel@tonic-gate static uint8_t *read_area = NULL; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * Buffer used for peeking new data available in channel (glvc) buffers. 1417c478bd9Sstevel@tonic-gate */ 1427c478bd9Sstevel@tonic-gate #define PEEK_AREA_SIZE (mtu_size) 1437c478bd9Sstevel@tonic-gate static uint8_t *peek_area = NULL; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate /* 1467c478bd9Sstevel@tonic-gate * Buffers used for peeking data available either in local buffers or 1477c478bd9Sstevel@tonic-gate * new data available in channel (glvc) buffers. 1487c478bd9Sstevel@tonic-gate */ 1497c478bd9Sstevel@tonic-gate #define PEEK_READ_AREA_SIZE (2*mtu_size) 1507c478bd9Sstevel@tonic-gate static uint8_t *peek_read_head = NULL; 1517c478bd9Sstevel@tonic-gate static uint8_t *peek_read_tail = NULL; 1527c478bd9Sstevel@tonic-gate static uint8_t *peek_read_area = NULL; 1537c478bd9Sstevel@tonic-gate 1547c478bd9Sstevel@tonic-gate static pcp_req_msg_hdr_t *req_msg_hdr = NULL; 1557c478bd9Sstevel@tonic-gate static pcp_resp_msg_hdr_t *resp_msg_hdr = NULL; 1567c478bd9Sstevel@tonic-gate static int req_msg_hdr_sz = 0; 1577c478bd9Sstevel@tonic-gate static int resp_msg_hdr_sz = 0; 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate /* 1607c478bd9Sstevel@tonic-gate * signal handling variables to handle glvc blocking calls. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate static struct sigaction glvc_act; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* To restore old SIGALRM signal handler */ 1657c478bd9Sstevel@tonic-gate static struct sigaction old_act; 1667c478bd9Sstevel@tonic-gate 1671ae08745Sheppo /* 1681ae08745Sheppo * Variables to support vldc based streaming transport 1691ae08745Sheppo */ 1704bac2208Snarayan static pcp_xport_t xport_type = GLVC_NON_STREAM; 1711ae08745Sheppo #define VLDC_MTU_SIZE (2048) 1721ae08745Sheppo 1737c478bd9Sstevel@tonic-gate static void 1747c478bd9Sstevel@tonic-gate glvc_timeout_handler(void) 1757c478bd9Sstevel@tonic-gate { 1767c478bd9Sstevel@tonic-gate if (jumpok == 0) 1777c478bd9Sstevel@tonic-gate return; 1787c478bd9Sstevel@tonic-gate siglongjmp(jmpbuf, 1); 1797c478bd9Sstevel@tonic-gate } 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 1827c478bd9Sstevel@tonic-gate * Initialize the virtual channel. It basically opens the virtual channel 1837c478bd9Sstevel@tonic-gate * provided by the host application. 1847c478bd9Sstevel@tonic-gate * 1857c478bd9Sstevel@tonic-gate */ 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate int 1885db09ef5Smvgr pcp_init(char *channel_name) 1897c478bd9Sstevel@tonic-gate { 1907c478bd9Sstevel@tonic-gate sigset_t oldset; 1915db09ef5Smvgr int channel_fd; 1924bac2208Snarayan char *dev_path; 1934bac2208Snarayan vldc_opt_op_t op; 1947c478bd9Sstevel@tonic-gate 1955db09ef5Smvgr if (channel_name == NULL) 1967c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 1971ae08745Sheppo 1987c478bd9Sstevel@tonic-gate /* 1994bac2208Snarayan * Given the argument, try to locate a device in the device tree 2004bac2208Snarayan */ 2014bac2208Snarayan dev_path = platsvc_name_to_path(channel_name, &xport_type); 2024bac2208Snarayan 2034bac2208Snarayan /* 2044bac2208Snarayan * Path exists ? 2054bac2208Snarayan */ 2064bac2208Snarayan if (NULL == dev_path) 2074bac2208Snarayan return (PCPL_INVALID_ARGS); 2084bac2208Snarayan 2094bac2208Snarayan /* 2105db09ef5Smvgr * Open virtual channel name. 2117c478bd9Sstevel@tonic-gate */ 2124bac2208Snarayan if ((channel_fd = open(dev_path, O_RDWR|O_EXCL)) < 0) { 2134bac2208Snarayan free(dev_path); 2147c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 2157c478bd9Sstevel@tonic-gate } 2167c478bd9Sstevel@tonic-gate 2174bac2208Snarayan free(dev_path); 2181ae08745Sheppo 2194bac2208Snarayan /* 2204bac2208Snarayan * Handle transport-specific processing 2214bac2208Snarayan */ 2224bac2208Snarayan switch (xport_type) { 2234bac2208Snarayan case VLDC_STREAMING: 2241ae08745Sheppo mtu_size = VLDC_MTU_SIZE; 2251ae08745Sheppo 2261ae08745Sheppo op.op_sel = VLDC_OP_SET; 2271ae08745Sheppo op.opt_sel = VLDC_OPT_MODE; 228*20ae46ebSha137994 op.opt_val = LDC_MODE_RELIABLE; 2291ae08745Sheppo if (ioctl(channel_fd, VLDC_IOCTL_OPT_OP, &op) != 0) { 2301ae08745Sheppo (void) close(channel_fd); 2311ae08745Sheppo return (PCPL_GLVC_ERROR); 2321ae08745Sheppo } 2334bac2208Snarayan break; 2344bac2208Snarayan case GLVC_NON_STREAM: 2354bac2208Snarayan default: 2361ae08745Sheppo /* 2377c478bd9Sstevel@tonic-gate * Get the Channel MTU size 2387c478bd9Sstevel@tonic-gate */ 2397c478bd9Sstevel@tonic-gate 2401ae08745Sheppo if (pcp_get_prop(channel_fd, GLVC_XPORT_OPT_MTU_SZ, 2411ae08745Sheppo &mtu_size) != 0) { 2425db09ef5Smvgr (void) close(channel_fd); 2437c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 2447c478bd9Sstevel@tonic-gate } 2454bac2208Snarayan break; 2461ae08745Sheppo } 2477c478bd9Sstevel@tonic-gate 2487c478bd9Sstevel@tonic-gate /* 2497c478bd9Sstevel@tonic-gate * Get current signal mask. If SIGALRM is blocked 2507c478bd9Sstevel@tonic-gate * unblock it. 2517c478bd9Sstevel@tonic-gate */ 2527c478bd9Sstevel@tonic-gate (void) sigprocmask(0, NULL, &oldset); 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate (void) sigemptyset(&blkset); 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (sigismember(&oldset, SIGALRM)) { 2577c478bd9Sstevel@tonic-gate (void) sigaddset(&blkset, SIGALRM); 2587c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &blkset, NULL); 2597c478bd9Sstevel@tonic-gate } 2607c478bd9Sstevel@tonic-gate /* 2617c478bd9Sstevel@tonic-gate * signal handler initialization to handle glvc call timeouts. 2627c478bd9Sstevel@tonic-gate */ 2637c478bd9Sstevel@tonic-gate glvc_act.sa_handler = glvc_timeout_handler; 2647c478bd9Sstevel@tonic-gate (void) sigemptyset(&glvc_act.sa_mask); 2657c478bd9Sstevel@tonic-gate glvc_act.sa_flags = SA_NODEFER; 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate if (sigaction(SIGALRM, &glvc_act, &old_act) < 0) { 2685db09ef5Smvgr (void) close(channel_fd); 2697c478bd9Sstevel@tonic-gate return (PCPL_ERROR); 2707c478bd9Sstevel@tonic-gate } 2717c478bd9Sstevel@tonic-gate 2725db09ef5Smvgr return (channel_fd); 2737c478bd9Sstevel@tonic-gate } 2747c478bd9Sstevel@tonic-gate 2757c478bd9Sstevel@tonic-gate /* 2767c478bd9Sstevel@tonic-gate * Function: Close platform channel. 2775db09ef5Smvgr * Arguments: 2785db09ef5Smvgr * int channel_fd - channel file descriptor. 2797c478bd9Sstevel@tonic-gate * Returns: 2807c478bd9Sstevel@tonic-gate * always returns PCPL_OK for now. 2817c478bd9Sstevel@tonic-gate */ 2827c478bd9Sstevel@tonic-gate int 2835db09ef5Smvgr pcp_close(int channel_fd) 2847c478bd9Sstevel@tonic-gate { 2857c478bd9Sstevel@tonic-gate 2865db09ef5Smvgr if (channel_fd >= 0) { 2871ae08745Sheppo if (xport_type == GLVC_NON_STREAM) 2885db09ef5Smvgr (void) pcp_cleanup(channel_fd); 2895db09ef5Smvgr (void) close(channel_fd); 2905db09ef5Smvgr } else { 2915db09ef5Smvgr return (-1); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* 2957c478bd9Sstevel@tonic-gate * free global buffers 2967c478bd9Sstevel@tonic-gate */ 2977c478bd9Sstevel@tonic-gate if (read_area != NULL) { 2987c478bd9Sstevel@tonic-gate umem_free(read_area, READ_AREA_SIZE); 2997c478bd9Sstevel@tonic-gate read_area = NULL; 3007c478bd9Sstevel@tonic-gate } 3017c478bd9Sstevel@tonic-gate if (peek_area != NULL) { 3027c478bd9Sstevel@tonic-gate umem_free(peek_area, PEEK_AREA_SIZE); 3037c478bd9Sstevel@tonic-gate peek_area = NULL; 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate if (peek_read_area != NULL) { 3067c478bd9Sstevel@tonic-gate umem_free(peek_read_area, PEEK_READ_AREA_SIZE); 3077c478bd9Sstevel@tonic-gate peek_read_area = NULL; 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate if (req_msg_hdr != NULL) { 3107c478bd9Sstevel@tonic-gate umem_free(req_msg_hdr, req_msg_hdr_sz); 3117c478bd9Sstevel@tonic-gate req_msg_hdr = NULL; 3127c478bd9Sstevel@tonic-gate } 3137c478bd9Sstevel@tonic-gate if (resp_msg_hdr != NULL) { 3147c478bd9Sstevel@tonic-gate umem_free(resp_msg_hdr, resp_msg_hdr_sz); 3157c478bd9Sstevel@tonic-gate resp_msg_hdr = NULL; 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate /* 3197c478bd9Sstevel@tonic-gate * Restore SIGALRM signal mask incase if we unblocked 3207c478bd9Sstevel@tonic-gate * it during pcp_init. 3217c478bd9Sstevel@tonic-gate */ 3227c478bd9Sstevel@tonic-gate if (sigismember(&blkset, SIGALRM)) { 3237c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &blkset, NULL); 3247c478bd9Sstevel@tonic-gate } 3257c478bd9Sstevel@tonic-gate 3267c478bd9Sstevel@tonic-gate /* Restore SIGALRM signal handler */ 3277c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &old_act, NULL); 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate return (PCPL_OK); 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * Function: Send and Receive messages on platform channel. 3347c478bd9Sstevel@tonic-gate * Arguments: 3355db09ef5Smvgr * int channel_fd - channel file descriptor. 3367c478bd9Sstevel@tonic-gate * pcp_msg_t *req_msg - Request Message to send to other end of channel. 3377c478bd9Sstevel@tonic-gate * pcp_msg_t *resp_msg - Response Message to be received. 3387c478bd9Sstevel@tonic-gate * uint32_t timeout - timeout field when waiting for data from channel. 3397c478bd9Sstevel@tonic-gate * Returns: 3407c478bd9Sstevel@tonic-gate * 0 - success (PCPL_OK). 3417c478bd9Sstevel@tonic-gate * (-ve) - failure: 3427c478bd9Sstevel@tonic-gate * PCPL_INVALID_ARGS - invalid args. 3437c478bd9Sstevel@tonic-gate * PCPL_GLVC_TIMEOUT - glvc call timeout. 3447c478bd9Sstevel@tonic-gate * PCPL_XPORT_ERROR - transport error in request message 3457c478bd9Sstevel@tonic-gate * noticed by receiver. 3467c478bd9Sstevel@tonic-gate * PCPL_MALLOC_FAIL - malloc failure. 3477c478bd9Sstevel@tonic-gate * PCPL_CKSUM_ERROR - checksum error. 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate int 3505db09ef5Smvgr pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg, 3515db09ef5Smvgr uint32_t timeout) 3527c478bd9Sstevel@tonic-gate { 3537c478bd9Sstevel@tonic-gate void *datap; 3547c478bd9Sstevel@tonic-gate void *resp_msg_data = NULL; 3557c478bd9Sstevel@tonic-gate uint32_t status; 3567c478bd9Sstevel@tonic-gate uint16_t cksum = 0; 3577c478bd9Sstevel@tonic-gate int ret; 3587c478bd9Sstevel@tonic-gate int resp_hdr_ok; 3597c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 3607c478bd9Sstevel@tonic-gate uint16_t bkup_resp_hdr_cksum; 3617c478bd9Sstevel@tonic-gate #endif 3625db09ef5Smvgr if (channel_fd < 0) { 3637c478bd9Sstevel@tonic-gate return (PCPL_ERROR); 3647c478bd9Sstevel@tonic-gate } 3657c478bd9Sstevel@tonic-gate 3665db09ef5Smvgr /* copy channel_fd to local fd (chnl_fd) for other functions use */ 3675db09ef5Smvgr chnl_fd = channel_fd; 3685db09ef5Smvgr 3697c478bd9Sstevel@tonic-gate if (req_msg == NULL) { 3707c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate if (timeout > 0) 3747c478bd9Sstevel@tonic-gate glvc_timeout = timeout; 3757c478bd9Sstevel@tonic-gate else 3767c478bd9Sstevel@tonic-gate glvc_timeout = 0; 3777c478bd9Sstevel@tonic-gate 3781b255844Smvgr if ((req_msg->msg_len != 0) && ((datap = req_msg->msg_data) == NULL)) 3797c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate if (req_msg_hdr == NULL) { 3827c478bd9Sstevel@tonic-gate req_msg_hdr_sz = sizeof (pcp_req_msg_hdr_t); 3837c478bd9Sstevel@tonic-gate req_msg_hdr = (pcp_req_msg_hdr_t *)umem_zalloc(req_msg_hdr_sz, 3847c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 3857c478bd9Sstevel@tonic-gate if (req_msg_hdr == NULL) 3867c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 3877c478bd9Sstevel@tonic-gate } 3887c478bd9Sstevel@tonic-gate 3895db09ef5Smvgr if (req_msg->msg_len != 0) { 3907c478bd9Sstevel@tonic-gate /* calculate request msg_cksum */ 3917c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)datap, req_msg->msg_len); 3925db09ef5Smvgr } 3937c478bd9Sstevel@tonic-gate 3947c478bd9Sstevel@tonic-gate /* 3957c478bd9Sstevel@tonic-gate * Fill in the message header for the request packet 3967c478bd9Sstevel@tonic-gate */ 3977c478bd9Sstevel@tonic-gate req_msg_hdr->magic_num = PCP_MAGIC_NUM; 3987c478bd9Sstevel@tonic-gate req_msg_hdr->proto_ver = PCP_PROT_VER_1; 3997c478bd9Sstevel@tonic-gate req_msg_hdr->msg_type = req_msg->msg_type; 4007c478bd9Sstevel@tonic-gate req_msg_hdr->sub_type = req_msg->sub_type; 4017c478bd9Sstevel@tonic-gate req_msg_hdr->rsvd_pad = 0; 4027c478bd9Sstevel@tonic-gate req_msg_hdr->xid = pcp_get_xid(); 4037c478bd9Sstevel@tonic-gate req_msg_hdr->msg_len = req_msg->msg_len; 4047c478bd9Sstevel@tonic-gate req_msg_hdr->timeout = timeout; 4057c478bd9Sstevel@tonic-gate req_msg_hdr->msg_cksum = cksum; 4067c478bd9Sstevel@tonic-gate req_msg_hdr->hdr_cksum = 0; 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate /* fill request header checksum */ 4097c478bd9Sstevel@tonic-gate req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr, 4107c478bd9Sstevel@tonic-gate req_msg_hdr_sz); 4117c478bd9Sstevel@tonic-gate /* 4127c478bd9Sstevel@tonic-gate * set sig jmp location 4137c478bd9Sstevel@tonic-gate */ 4147c478bd9Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) { 4157c478bd9Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate jumpok = 1; /* monitor sigalrm from now on */ 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* 4207c478bd9Sstevel@tonic-gate * send request message header 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate if ((ret = pcp_send_req_msg_hdr(req_msg_hdr))) { 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate return (ret); 4257c478bd9Sstevel@tonic-gate } 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate /* 4287c478bd9Sstevel@tonic-gate * send request message 4297c478bd9Sstevel@tonic-gate */ 4305db09ef5Smvgr if (req_msg->msg_len != 0) { 4317c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(datap, req_msg->msg_len, 4327c478bd9Sstevel@tonic-gate PCPL_IO_OP_WRITE))) { 4337c478bd9Sstevel@tonic-gate return (ret); 4347c478bd9Sstevel@tonic-gate } 4355db09ef5Smvgr } 4365db09ef5Smvgr 4377c478bd9Sstevel@tonic-gate if (timeout == (uint32_t)PCP_TO_NO_RESPONSE) 4387c478bd9Sstevel@tonic-gate return (PCPL_OK); 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate if (resp_msg_hdr == NULL) { 4417c478bd9Sstevel@tonic-gate resp_msg_hdr_sz = sizeof (pcp_resp_msg_hdr_t); 4427c478bd9Sstevel@tonic-gate resp_msg_hdr = (pcp_resp_msg_hdr_t *)umem_alloc(resp_msg_hdr_sz, 4437c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 4447c478bd9Sstevel@tonic-gate if (resp_msg_hdr == NULL) 4457c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 4467c478bd9Sstevel@tonic-gate } 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate resp_hdr_ok = 0; 4497c478bd9Sstevel@tonic-gate while (!resp_hdr_ok) { 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate /* 4527c478bd9Sstevel@tonic-gate * Receive response message header 4537c478bd9Sstevel@tonic-gate * Note: frame error handling is done in 4547c478bd9Sstevel@tonic-gate * 'pcp_recv_resp_msg_hdr()'. 4557c478bd9Sstevel@tonic-gate */ 4567c478bd9Sstevel@tonic-gate if ((ret = pcp_recv_resp_msg_hdr(resp_msg_hdr))) { 4577c478bd9Sstevel@tonic-gate return (ret); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate /* 4617c478bd9Sstevel@tonic-gate * Check header checksum if it matches with the received hdr 4627c478bd9Sstevel@tonic-gate * checksum. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 4657c478bd9Sstevel@tonic-gate bkup_resp_hdr_cksum = resp_msg_hdr->hdr_cksum; 4667c478bd9Sstevel@tonic-gate resp_msg_hdr->hdr_cksum = 0; 4677c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)resp_msg_hdr, resp_msg_hdr_sz); 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate if (cksum != bkup_resp_hdr_cksum) { 4707c478bd9Sstevel@tonic-gate return (PCPL_CKSUM_ERROR); 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate #endif 4737c478bd9Sstevel@tonic-gate /* 4747c478bd9Sstevel@tonic-gate * Check for matching request and response messages 4757c478bd9Sstevel@tonic-gate */ 4767c478bd9Sstevel@tonic-gate if (resp_msg_hdr->xid != req_msg_hdr->xid) { 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate continue; /* continue reading response header */ 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate resp_hdr_ok = 1; 4817c478bd9Sstevel@tonic-gate } 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate /* 4847c478bd9Sstevel@tonic-gate * check status field for any channel protocol errrors 4857c478bd9Sstevel@tonic-gate * This field signifies something happend during request 4867c478bd9Sstevel@tonic-gate * message trasmission. This field is set by the receiver. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate status = resp_msg_hdr->status; 4897c478bd9Sstevel@tonic-gate if (status != PCP_OK) { 4907c478bd9Sstevel@tonic-gate return (PCPL_XPORT_ERROR); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4935db09ef5Smvgr if (resp_msg_hdr->msg_len != 0) { 4947c478bd9Sstevel@tonic-gate 4957c478bd9Sstevel@tonic-gate /* libpcp users should free this memory */ 4965db09ef5Smvgr if ((resp_msg_data = (uint8_t *)malloc(resp_msg_hdr->msg_len)) 4975db09ef5Smvgr == NULL) 4987c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 4997c478bd9Sstevel@tonic-gate bzero(resp_msg_data, resp_msg_hdr->msg_len); 5007c478bd9Sstevel@tonic-gate /* 5017c478bd9Sstevel@tonic-gate * Receive response message. 5027c478bd9Sstevel@tonic-gate */ 5037c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(resp_msg_data, resp_msg_hdr->msg_len, 5047c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ))) { 5057c478bd9Sstevel@tonic-gate free(resp_msg_data); 5067c478bd9Sstevel@tonic-gate return (ret); 5077c478bd9Sstevel@tonic-gate } 5087c478bd9Sstevel@tonic-gate 5097c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 5107c478bd9Sstevel@tonic-gate /* verify response message data checksum */ 5117c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)resp_msg_data, 5127c478bd9Sstevel@tonic-gate resp_msg_hdr->msg_len); 5137c478bd9Sstevel@tonic-gate if (cksum != resp_msg_hdr->msg_cksum) { 5147c478bd9Sstevel@tonic-gate free(resp_msg_data); 5157c478bd9Sstevel@tonic-gate return (PCPL_CKSUM_ERROR); 5167c478bd9Sstevel@tonic-gate } 5177c478bd9Sstevel@tonic-gate #endif 5185db09ef5Smvgr } 5197c478bd9Sstevel@tonic-gate /* Everything is okay put the received data into user */ 5207c478bd9Sstevel@tonic-gate /* application's resp_msg struct */ 5217c478bd9Sstevel@tonic-gate resp_msg->msg_len = resp_msg_hdr->msg_len; 5227c478bd9Sstevel@tonic-gate resp_msg->msg_type = resp_msg_hdr->msg_type; 5237c478bd9Sstevel@tonic-gate resp_msg->sub_type = resp_msg_hdr->sub_type; 5247c478bd9Sstevel@tonic-gate resp_msg->msg_data = (uint8_t *)resp_msg_data; 5257c478bd9Sstevel@tonic-gate 5267c478bd9Sstevel@tonic-gate return (PCPL_OK); 5277c478bd9Sstevel@tonic-gate 5287c478bd9Sstevel@tonic-gate } 5297c478bd9Sstevel@tonic-gate 5307c478bd9Sstevel@tonic-gate /* 5317c478bd9Sstevel@tonic-gate * Function: Get channel property values. 5327c478bd9Sstevel@tonic-gate * Arguments: 5335db09ef5Smvgr * int channel_fd - channel file descriptor. 5347c478bd9Sstevel@tonic-gate * int prop - property id. 5357c478bd9Sstevel@tonic-gate * unsigned int *val - property value tobe copied. 5367c478bd9Sstevel@tonic-gate * Returns: 5377c478bd9Sstevel@tonic-gate * 0 - success 5387c478bd9Sstevel@tonic-gate * (-ve) - failure: 5397c478bd9Sstevel@tonic-gate * PCPL_ERR_GLVC - glvc ioctl failure. 5407c478bd9Sstevel@tonic-gate */ 5417c478bd9Sstevel@tonic-gate 5427c478bd9Sstevel@tonic-gate static int 5435db09ef5Smvgr pcp_get_prop(int channel_fd, int prop, unsigned int *val) 5447c478bd9Sstevel@tonic-gate { 5457c478bd9Sstevel@tonic-gate glvc_xport_opt_op_t channel_op; 5467c478bd9Sstevel@tonic-gate int ret; 5477c478bd9Sstevel@tonic-gate 5487c478bd9Sstevel@tonic-gate channel_op.op_sel = GLVC_XPORT_OPT_GET; 5497c478bd9Sstevel@tonic-gate channel_op.opt_sel = prop; 5507c478bd9Sstevel@tonic-gate channel_op.opt_val = 0; 5517c478bd9Sstevel@tonic-gate 5527c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 5537c478bd9Sstevel@tonic-gate 5545db09ef5Smvgr if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_OPT_OP, 5555db09ef5Smvgr &channel_op)) < 0) { 5565db09ef5Smvgr 5577c478bd9Sstevel@tonic-gate (void) alarm(0); 5587c478bd9Sstevel@tonic-gate return (ret); 5597c478bd9Sstevel@tonic-gate } 5607c478bd9Sstevel@tonic-gate (void) alarm(0); 5617c478bd9Sstevel@tonic-gate 5627c478bd9Sstevel@tonic-gate *val = channel_op.opt_val; 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate return (0); 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate 5677c478bd9Sstevel@tonic-gate /* 5687c478bd9Sstevel@tonic-gate * Function: wrapper for handling glvc calls (read/write/peek). 5697c478bd9Sstevel@tonic-gate */ 5707c478bd9Sstevel@tonic-gate static int 5717c478bd9Sstevel@tonic-gate pcp_io_op(void *buf, int byte_cnt, int io_op) 5727c478bd9Sstevel@tonic-gate { 5737c478bd9Sstevel@tonic-gate int rv; 5747c478bd9Sstevel@tonic-gate int n; 5757c478bd9Sstevel@tonic-gate uint8_t *datap; 5767c478bd9Sstevel@tonic-gate int (*func_ptr)(uint8_t *, int); 5777c478bd9Sstevel@tonic-gate int io_sz; 5787c478bd9Sstevel@tonic-gate int try_cnt; 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate 5817c478bd9Sstevel@tonic-gate if ((buf == NULL) || (byte_cnt < 0)) { 5827c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 5837c478bd9Sstevel@tonic-gate } 5847c478bd9Sstevel@tonic-gate 5857c478bd9Sstevel@tonic-gate switch (io_op) { 5867c478bd9Sstevel@tonic-gate case PCPL_IO_OP_READ: 5877c478bd9Sstevel@tonic-gate func_ptr = pcp_read; 5887c478bd9Sstevel@tonic-gate break; 5897c478bd9Sstevel@tonic-gate case PCPL_IO_OP_WRITE: 5907c478bd9Sstevel@tonic-gate func_ptr = pcp_write; 5917c478bd9Sstevel@tonic-gate break; 5927c478bd9Sstevel@tonic-gate case PCPL_IO_OP_PEEK: 5937c478bd9Sstevel@tonic-gate func_ptr = pcp_peek; 5947c478bd9Sstevel@tonic-gate break; 5957c478bd9Sstevel@tonic-gate default: 5967c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * loop until all I/O done, try limit exceded, or real failure 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate rv = 0; 6047c478bd9Sstevel@tonic-gate datap = buf; 6057c478bd9Sstevel@tonic-gate while (rv < byte_cnt) { 6067c478bd9Sstevel@tonic-gate io_sz = MIN((byte_cnt - rv), mtu_size); 6077c478bd9Sstevel@tonic-gate try_cnt = 0; 6087c478bd9Sstevel@tonic-gate while ((n = (*func_ptr)(datap, io_sz)) < 0) { 6097c478bd9Sstevel@tonic-gate try_cnt++; 6107c478bd9Sstevel@tonic-gate if (try_cnt > PCPL_MAX_TRY_CNT) { 6117c478bd9Sstevel@tonic-gate rv = n; 6127c478bd9Sstevel@tonic-gate goto done; 6137c478bd9Sstevel@tonic-gate } 6147c478bd9Sstevel@tonic-gate (void) sleep(PCPL_GLVC_SLEEP); 6157c478bd9Sstevel@tonic-gate } /* while trying the io operation */ 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate if (n < 0) { 6187c478bd9Sstevel@tonic-gate rv = n; 6197c478bd9Sstevel@tonic-gate goto done; 6207c478bd9Sstevel@tonic-gate } 6217c478bd9Sstevel@tonic-gate rv += n; 6227c478bd9Sstevel@tonic-gate datap += n; 6237c478bd9Sstevel@tonic-gate } /* while still have more data */ 6247c478bd9Sstevel@tonic-gate 6257c478bd9Sstevel@tonic-gate done: 6267c478bd9Sstevel@tonic-gate if (rv == byte_cnt) 6277c478bd9Sstevel@tonic-gate return (0); 6287c478bd9Sstevel@tonic-gate else 6297c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 6307c478bd9Sstevel@tonic-gate } 6317c478bd9Sstevel@tonic-gate 6327c478bd9Sstevel@tonic-gate /* 6337c478bd9Sstevel@tonic-gate * For peeking 'bytes_cnt' bytes in channel (glvc) buffers. 6347c478bd9Sstevel@tonic-gate * If data is available, the data is copied into 'buf'. 6357c478bd9Sstevel@tonic-gate */ 6367c478bd9Sstevel@tonic-gate static int 6377c478bd9Sstevel@tonic-gate pcp_peek(uint8_t *buf, int bytes_cnt) 6387c478bd9Sstevel@tonic-gate { 6397c478bd9Sstevel@tonic-gate int ret; 6407c478bd9Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl; 6417c478bd9Sstevel@tonic-gate int n, m; 6427c478bd9Sstevel@tonic-gate 6437c478bd9Sstevel@tonic-gate if (bytes_cnt < 0 || bytes_cnt > mtu_size) { 6447c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * initialization of buffers used for peeking data in channel buffers. 6497c478bd9Sstevel@tonic-gate */ 6507c478bd9Sstevel@tonic-gate if (peek_area == NULL) { 6517c478bd9Sstevel@tonic-gate peek_area = (uint8_t *)umem_zalloc(PEEK_AREA_SIZE, 6527c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 6537c478bd9Sstevel@tonic-gate if (peek_area == NULL) { 6547c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 6557c478bd9Sstevel@tonic-gate } 6567c478bd9Sstevel@tonic-gate } 6577c478bd9Sstevel@tonic-gate 6587c478bd9Sstevel@tonic-gate /* 6597c478bd9Sstevel@tonic-gate * peek max MTU size bytes 6607c478bd9Sstevel@tonic-gate */ 6617c478bd9Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)peek_area; 6627c478bd9Sstevel@tonic-gate peek_ctrl.buflen = mtu_size; 6637c478bd9Sstevel@tonic-gate peek_ctrl.flags = 0; 6647c478bd9Sstevel@tonic-gate 6657c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 6667c478bd9Sstevel@tonic-gate 6677c478bd9Sstevel@tonic-gate if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, &peek_ctrl)) 6687c478bd9Sstevel@tonic-gate < 0) { 6697c478bd9Sstevel@tonic-gate (void) alarm(0); 6707c478bd9Sstevel@tonic-gate return (ret); 6717c478bd9Sstevel@tonic-gate } 6727c478bd9Sstevel@tonic-gate (void) alarm(0); 6737c478bd9Sstevel@tonic-gate 6747c478bd9Sstevel@tonic-gate n = peek_ctrl.buflen; 6757c478bd9Sstevel@tonic-gate 6767c478bd9Sstevel@tonic-gate if (n < 0) 6777c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 6787c478bd9Sstevel@tonic-gate 6797c478bd9Sstevel@tonic-gate /* 6807c478bd9Sstevel@tonic-gate * satisfy request as best as we can 6817c478bd9Sstevel@tonic-gate */ 6827c478bd9Sstevel@tonic-gate m = MIN(bytes_cnt, n); 6837c478bd9Sstevel@tonic-gate (void) memcpy(buf, peek_area, m); 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate return (m); 6867c478bd9Sstevel@tonic-gate } 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate /* 6897c478bd9Sstevel@tonic-gate * Function: write 'byte_cnt' bytes from 'buf' to channel. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate static int 6927c478bd9Sstevel@tonic-gate pcp_write(uint8_t *buf, int byte_cnt) 6937c478bd9Sstevel@tonic-gate { 6947c478bd9Sstevel@tonic-gate 6957c478bd9Sstevel@tonic-gate int ret; 6967c478bd9Sstevel@tonic-gate 6977c478bd9Sstevel@tonic-gate /* check for valid arguments */ 6987c478bd9Sstevel@tonic-gate if (buf == NULL || byte_cnt < 0 || byte_cnt > mtu_size) { 6997c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 7007c478bd9Sstevel@tonic-gate } 7017c478bd9Sstevel@tonic-gate 7021ae08745Sheppo if (xport_type == GLVC_NON_STREAM) { 7037c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 7047c478bd9Sstevel@tonic-gate 7057c478bd9Sstevel@tonic-gate if ((ret = write(chnl_fd, buf, byte_cnt)) < 0) { 7067c478bd9Sstevel@tonic-gate (void) alarm(0); 7077c478bd9Sstevel@tonic-gate return (ret); 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate (void) alarm(0); 7101ae08745Sheppo } else { 7111ae08745Sheppo if ((ret = vldc_write(chnl_fd, buf, byte_cnt)) <= 0) { 7121ae08745Sheppo return (ret); 7131ae08745Sheppo } 7141ae08745Sheppo } 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate return (ret); 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate 7197c478bd9Sstevel@tonic-gate /* 7207c478bd9Sstevel@tonic-gate * In current implementaion of glvc driver, streams reads are not supported. 7217c478bd9Sstevel@tonic-gate * pcp_read mimics stream reads by first reading all the bytes present in the 7227c478bd9Sstevel@tonic-gate * channel buffer into a local buffer and from then on read requests 7237c478bd9Sstevel@tonic-gate * are serviced from local buffer. When read requests are not serviceble 7247c478bd9Sstevel@tonic-gate * from local buffer, it repeates by first reading data from channel buffers. 7257c478bd9Sstevel@tonic-gate * 7267c478bd9Sstevel@tonic-gate * This call may need to be enhanced when glvc supports buffered (stream) 7277c478bd9Sstevel@tonic-gate * reads - TBD 7287c478bd9Sstevel@tonic-gate */ 7297c478bd9Sstevel@tonic-gate 7307c478bd9Sstevel@tonic-gate static int 7317c478bd9Sstevel@tonic-gate pcp_read(uint8_t *buf, int byte_cnt) 7327c478bd9Sstevel@tonic-gate { 7337c478bd9Sstevel@tonic-gate int ret; 7347c478bd9Sstevel@tonic-gate int n, m, i; 7357c478bd9Sstevel@tonic-gate 7367c478bd9Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) { 7377c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 7387c478bd9Sstevel@tonic-gate } 7397c478bd9Sstevel@tonic-gate 7407c478bd9Sstevel@tonic-gate /* 7417c478bd9Sstevel@tonic-gate * initialization of local read buffer 7427c478bd9Sstevel@tonic-gate * from which the stream read requests are serviced. 7437c478bd9Sstevel@tonic-gate */ 7447c478bd9Sstevel@tonic-gate if (read_area == NULL) { 7457c478bd9Sstevel@tonic-gate read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE, 7467c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 7477c478bd9Sstevel@tonic-gate if (read_area == NULL) { 7487c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 7497c478bd9Sstevel@tonic-gate } 7507c478bd9Sstevel@tonic-gate read_head = read_area; 7517c478bd9Sstevel@tonic-gate read_tail = read_area; 7527c478bd9Sstevel@tonic-gate } 7537c478bd9Sstevel@tonic-gate 7547c478bd9Sstevel@tonic-gate /* 7557c478bd9Sstevel@tonic-gate * if we already read this data then copy from local buffer it self 7567c478bd9Sstevel@tonic-gate * without calling new read. 7577c478bd9Sstevel@tonic-gate */ 7587c478bd9Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) { 7597c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt); 7607c478bd9Sstevel@tonic-gate read_head += byte_cnt; 7617c478bd9Sstevel@tonic-gate return (byte_cnt); 7627c478bd9Sstevel@tonic-gate } 7637c478bd9Sstevel@tonic-gate 7647c478bd9Sstevel@tonic-gate /* 7657c478bd9Sstevel@tonic-gate * if the request is not satisfied from the buffered data, then move the 7667c478bd9Sstevel@tonic-gate * remaining data to front of the buffer and read new data. 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) { 7697c478bd9Sstevel@tonic-gate read_area[i] = read_head[i]; 7707c478bd9Sstevel@tonic-gate } 7717c478bd9Sstevel@tonic-gate read_head = read_area; 7727c478bd9Sstevel@tonic-gate read_tail = read_head + i; 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * do a peek to see how much data is available and read complete data. 7767c478bd9Sstevel@tonic-gate */ 7777c478bd9Sstevel@tonic-gate 7781ae08745Sheppo if (xport_type == GLVC_NON_STREAM) { 7797c478bd9Sstevel@tonic-gate if ((m = pcp_peek(read_tail, mtu_size)) < 0) { 7807c478bd9Sstevel@tonic-gate return (m); 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate 7837c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 7847c478bd9Sstevel@tonic-gate if ((ret = read(chnl_fd, read_tail, m)) < 0) { 7857c478bd9Sstevel@tonic-gate (void) alarm(0); 7867c478bd9Sstevel@tonic-gate return (ret); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate 7897c478bd9Sstevel@tonic-gate (void) alarm(0); 7901ae08745Sheppo } else { 7911ae08745Sheppo /* 7921ae08745Sheppo * Read the extra number of bytes 7931ae08745Sheppo */ 7941ae08745Sheppo m = byte_cnt - (read_tail - read_head); 7951ae08745Sheppo if ((ret = vldc_read(chnl_fd, 7961ae08745Sheppo read_tail, m)) <= 0) { 7971ae08745Sheppo return (ret); 7981ae08745Sheppo } 7991ae08745Sheppo } 8007c478bd9Sstevel@tonic-gate read_tail += ret; 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate /* 8037c478bd9Sstevel@tonic-gate * copy the requested bytes. 8047c478bd9Sstevel@tonic-gate */ 8057c478bd9Sstevel@tonic-gate n = MIN(byte_cnt, (read_tail - read_head)); 8067c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, n); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate read_head += n; 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate return (n); 8117c478bd9Sstevel@tonic-gate } 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate /* 8141ae08745Sheppo * Issue read from the driver until byet_cnt number 8151ae08745Sheppo * of bytes are present in read buffer. Do not 8161ae08745Sheppo * move the read head. 8171ae08745Sheppo */ 8181ae08745Sheppo static int 8191ae08745Sheppo pcp_update_read_area(int byte_cnt) 8201ae08745Sheppo { 8211ae08745Sheppo int ret; 8221ae08745Sheppo int n, i; 8231ae08745Sheppo 8241ae08745Sheppo if (byte_cnt < 0 || byte_cnt > mtu_size) { 8251ae08745Sheppo return (PCPL_INVALID_ARGS); 8261ae08745Sheppo } 8271ae08745Sheppo 8281ae08745Sheppo /* 8291ae08745Sheppo * initialization of local read buffer 8301ae08745Sheppo * from which the stream read requests are serviced. 8311ae08745Sheppo */ 8321ae08745Sheppo if (read_area == NULL) { 8331ae08745Sheppo read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE, 8341ae08745Sheppo UMEM_DEFAULT); 8351ae08745Sheppo if (read_area == NULL) { 8361ae08745Sheppo return (PCPL_MALLOC_FAIL); 8371ae08745Sheppo } 8381ae08745Sheppo read_head = read_area; 8391ae08745Sheppo read_tail = read_area; 8401ae08745Sheppo } 8411ae08745Sheppo 8421ae08745Sheppo /* 8431ae08745Sheppo * if we already have sufficient data in the buffer, 8441ae08745Sheppo * just return 8451ae08745Sheppo */ 8461ae08745Sheppo if (byte_cnt <= (read_tail - read_head)) { 8471ae08745Sheppo return (byte_cnt); 8481ae08745Sheppo } 8491ae08745Sheppo 8501ae08745Sheppo /* 8511ae08745Sheppo * if the request is not satisfied from the buffered data, then move the 8521ae08745Sheppo * remaining data to front of the buffer and read new data. 8531ae08745Sheppo */ 8541ae08745Sheppo for (i = 0; i < (read_tail - read_head); ++i) { 8551ae08745Sheppo read_area[i] = read_head[i]; 8561ae08745Sheppo } 8571ae08745Sheppo read_head = read_area; 8581ae08745Sheppo read_tail = read_head + i; 8591ae08745Sheppo 8601ae08745Sheppo n = byte_cnt - (read_tail - read_head); 8611ae08745Sheppo 8621ae08745Sheppo if ((ret = vldc_read(chnl_fd, 8631ae08745Sheppo read_tail, n)) <= 0) { 8641ae08745Sheppo return (ret); 8651ae08745Sheppo } 8661ae08745Sheppo read_tail += ret; 8671ae08745Sheppo 8681ae08745Sheppo /* 8691ae08745Sheppo * Return the number of bytes we could read 8701ae08745Sheppo */ 8711ae08745Sheppo n = MIN(byte_cnt, (read_tail - read_head)); 8721ae08745Sheppo 8731ae08745Sheppo return (n); 8741ae08745Sheppo } 8751ae08745Sheppo 8761ae08745Sheppo /* 8777c478bd9Sstevel@tonic-gate * This function is slight different from pcp_peek. The peek requests are first 8787c478bd9Sstevel@tonic-gate * serviced from local read buffer, if data is available. If the peek request 8797c478bd9Sstevel@tonic-gate * is not serviceble from local read buffer, then the data is peeked from 8807c478bd9Sstevel@tonic-gate * channel buffer. This function is mainly used for proper protocol framing 8817c478bd9Sstevel@tonic-gate * error handling. 8827c478bd9Sstevel@tonic-gate */ 8837c478bd9Sstevel@tonic-gate static int 8847c478bd9Sstevel@tonic-gate pcp_peek_read(uint8_t *buf, int byte_cnt) 8857c478bd9Sstevel@tonic-gate { 8867c478bd9Sstevel@tonic-gate int n, m, i; 8877c478bd9Sstevel@tonic-gate 8887c478bd9Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) { 8897c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 8907c478bd9Sstevel@tonic-gate } 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate /* 8937c478bd9Sstevel@tonic-gate * initialization of peek_read buffer. 8947c478bd9Sstevel@tonic-gate */ 8957c478bd9Sstevel@tonic-gate if (peek_read_area == NULL) { 8967c478bd9Sstevel@tonic-gate peek_read_area = (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE, 8977c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 8987c478bd9Sstevel@tonic-gate if (peek_read_area == NULL) { 8997c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate peek_read_head = peek_read_area; 9027c478bd9Sstevel@tonic-gate peek_read_tail = peek_read_area; 9037c478bd9Sstevel@tonic-gate } 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate /* 9067c478bd9Sstevel@tonic-gate * if we already have the data in local read buffer then copy 9077c478bd9Sstevel@tonic-gate * from local buffer it self w/out calling new peek 9087c478bd9Sstevel@tonic-gate */ 9097c478bd9Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) { 9107c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt); 9117c478bd9Sstevel@tonic-gate return (byte_cnt); 9127c478bd9Sstevel@tonic-gate } 9137c478bd9Sstevel@tonic-gate 9147c478bd9Sstevel@tonic-gate /* 9157c478bd9Sstevel@tonic-gate * if the request is not satisfied from local read buffer, then first 9167c478bd9Sstevel@tonic-gate * copy the remaining data in local read buffer to peek_read_area and 9177c478bd9Sstevel@tonic-gate * then issue new peek. 9187c478bd9Sstevel@tonic-gate */ 9197c478bd9Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) { 9207c478bd9Sstevel@tonic-gate peek_read_area[i] = read_head[i]; 9217c478bd9Sstevel@tonic-gate } 9227c478bd9Sstevel@tonic-gate peek_read_head = peek_read_area; 9237c478bd9Sstevel@tonic-gate peek_read_tail = peek_read_head + i; 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* 9267c478bd9Sstevel@tonic-gate * do a peek to see how much data is available and read complete data. 9277c478bd9Sstevel@tonic-gate */ 9287c478bd9Sstevel@tonic-gate 9297c478bd9Sstevel@tonic-gate if ((m = pcp_peek(peek_read_tail, mtu_size)) < 0) { 9307c478bd9Sstevel@tonic-gate return (m); 9317c478bd9Sstevel@tonic-gate } 9327c478bd9Sstevel@tonic-gate peek_read_tail += m; 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate /* 9357c478bd9Sstevel@tonic-gate * copy the requested bytes 9367c478bd9Sstevel@tonic-gate */ 9377c478bd9Sstevel@tonic-gate n = MIN(byte_cnt, (peek_read_tail - peek_read_head)); 9387c478bd9Sstevel@tonic-gate (void) memcpy(buf, peek_read_head, n); 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate return (n); 9417c478bd9Sstevel@tonic-gate } 9427c478bd9Sstevel@tonic-gate 9437c478bd9Sstevel@tonic-gate /* 9447c478bd9Sstevel@tonic-gate * Send Request Message Header. 9457c478bd9Sstevel@tonic-gate */ 9467c478bd9Sstevel@tonic-gate static int 9477c478bd9Sstevel@tonic-gate pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr) 9487c478bd9Sstevel@tonic-gate { 9497c478bd9Sstevel@tonic-gate pcp_req_msg_hdr_t *hdrp; 9507c478bd9Sstevel@tonic-gate int hdr_sz; 9517c478bd9Sstevel@tonic-gate int ret; 9527c478bd9Sstevel@tonic-gate 9537c478bd9Sstevel@tonic-gate hdr_sz = sizeof (pcp_req_msg_hdr_t); 9547c478bd9Sstevel@tonic-gate if ((hdrp = (pcp_req_msg_hdr_t *)umem_zalloc(hdr_sz, 9557c478bd9Sstevel@tonic-gate UMEM_DEFAULT)) == NULL) { 9567c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 9577c478bd9Sstevel@tonic-gate } 9587c478bd9Sstevel@tonic-gate 9597c478bd9Sstevel@tonic-gate hdrp->magic_num = htonl(req_hdr->magic_num); 9607c478bd9Sstevel@tonic-gate hdrp->proto_ver = req_hdr->proto_ver; 9617c478bd9Sstevel@tonic-gate hdrp->msg_type = req_hdr->msg_type; 9627c478bd9Sstevel@tonic-gate hdrp->sub_type = req_hdr->sub_type; 9637c478bd9Sstevel@tonic-gate hdrp->rsvd_pad = htons(req_hdr->rsvd_pad); 9647c478bd9Sstevel@tonic-gate hdrp->xid = htonl(req_hdr->xid); 9657c478bd9Sstevel@tonic-gate hdrp->timeout = htonl(req_hdr->timeout); 9667c478bd9Sstevel@tonic-gate hdrp->msg_len = htonl(req_hdr->msg_len); 9677c478bd9Sstevel@tonic-gate hdrp->msg_cksum = htons(req_hdr->msg_cksum); 9687c478bd9Sstevel@tonic-gate hdrp->hdr_cksum = htons(req_hdr->hdr_cksum); 9697c478bd9Sstevel@tonic-gate 9707c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op((char *)hdrp, hdr_sz, PCPL_IO_OP_WRITE)) != 0) { 9717c478bd9Sstevel@tonic-gate umem_free(hdrp, hdr_sz); 9727c478bd9Sstevel@tonic-gate return (ret); 9737c478bd9Sstevel@tonic-gate } 9747c478bd9Sstevel@tonic-gate umem_free(hdrp, hdr_sz); 9757c478bd9Sstevel@tonic-gate return (PCP_OK); 9767c478bd9Sstevel@tonic-gate } 9777c478bd9Sstevel@tonic-gate 9787c478bd9Sstevel@tonic-gate /* 9797c478bd9Sstevel@tonic-gate * Receive Response message header. 9807c478bd9Sstevel@tonic-gate */ 9817c478bd9Sstevel@tonic-gate static int 9827c478bd9Sstevel@tonic-gate pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr) 9837c478bd9Sstevel@tonic-gate { 9847c478bd9Sstevel@tonic-gate uint32_t magic_num; 9857c478bd9Sstevel@tonic-gate uint8_t proto_ver; 9867c478bd9Sstevel@tonic-gate uint8_t msg_type; 9877c478bd9Sstevel@tonic-gate uint8_t sub_type; 9887c478bd9Sstevel@tonic-gate uint8_t rsvd_pad; 9897c478bd9Sstevel@tonic-gate uint32_t xid; 9907c478bd9Sstevel@tonic-gate uint32_t timeout; 9917c478bd9Sstevel@tonic-gate uint32_t msg_len; 9927c478bd9Sstevel@tonic-gate uint32_t status; 9937c478bd9Sstevel@tonic-gate uint16_t msg_cksum; 9947c478bd9Sstevel@tonic-gate uint16_t hdr_cksum; 9957c478bd9Sstevel@tonic-gate int ret; 9967c478bd9Sstevel@tonic-gate 9977c478bd9Sstevel@tonic-gate if (resp_hdr == NULL) { 9987c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 9997c478bd9Sstevel@tonic-gate } 10007c478bd9Sstevel@tonic-gate 10017c478bd9Sstevel@tonic-gate /* 10027c478bd9Sstevel@tonic-gate * handle protocol framing errors. 10037c478bd9Sstevel@tonic-gate * pcp_frame_error_handle() returns when proper frame arrived 10047c478bd9Sstevel@tonic-gate * (magic seq) or if an error happens while reading data from 10057c478bd9Sstevel@tonic-gate * channel. 10067c478bd9Sstevel@tonic-gate */ 10071ae08745Sheppo if (xport_type == GLVC_NON_STREAM) 10081ae08745Sheppo ret = pcp_frame_error_handle(); 10091ae08745Sheppo else 10101ae08745Sheppo ret = pcp_vldc_frame_error_handle(); 10111ae08745Sheppo 10121ae08745Sheppo if (ret != 0) 10137c478bd9Sstevel@tonic-gate return (PCPL_FRAME_ERROR); 10147c478bd9Sstevel@tonic-gate 10157c478bd9Sstevel@tonic-gate /* read magic number first */ 10167c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&magic_num, sizeof (magic_num), 10177c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10187c478bd9Sstevel@tonic-gate return (ret); 10197c478bd9Sstevel@tonic-gate } 10207c478bd9Sstevel@tonic-gate 10217c478bd9Sstevel@tonic-gate magic_num = ntohl(magic_num); 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate if (magic_num != PCP_MAGIC_NUM) { 10247c478bd9Sstevel@tonic-gate return (PCPL_FRAME_ERROR); 10257c478bd9Sstevel@tonic-gate } 10267c478bd9Sstevel@tonic-gate 10277c478bd9Sstevel@tonic-gate /* read version field */ 10287c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&proto_ver, sizeof (proto_ver), 10297c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10307c478bd9Sstevel@tonic-gate return (ret); 10317c478bd9Sstevel@tonic-gate } 10327c478bd9Sstevel@tonic-gate 10337c478bd9Sstevel@tonic-gate /* check protocol version */ 10347c478bd9Sstevel@tonic-gate if (proto_ver != PCP_PROT_VER_1) { 10357c478bd9Sstevel@tonic-gate return (PCPL_PROT_ERROR); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate 10387c478bd9Sstevel@tonic-gate /* Read message type */ 10397c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_type, sizeof (msg_type), 10407c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10417c478bd9Sstevel@tonic-gate return (ret); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate /* Read message sub type */ 10457c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&sub_type, sizeof (sub_type), 10467c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10477c478bd9Sstevel@tonic-gate return (ret); 10487c478bd9Sstevel@tonic-gate } 10497c478bd9Sstevel@tonic-gate 10507c478bd9Sstevel@tonic-gate /* Read rcvd_pad bits */ 10517c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&rsvd_pad, sizeof (rsvd_pad), 10527c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10537c478bd9Sstevel@tonic-gate return (ret); 10547c478bd9Sstevel@tonic-gate } 10557c478bd9Sstevel@tonic-gate 10567c478bd9Sstevel@tonic-gate /* receive transaction id */ 10577c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&xid, sizeof (xid), 10587c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10597c478bd9Sstevel@tonic-gate return (ret); 10607c478bd9Sstevel@tonic-gate } 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate xid = ntohl(xid); 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate /* receive timeout value */ 10657c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&timeout, sizeof (timeout), 10667c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10677c478bd9Sstevel@tonic-gate return (ret); 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate 10707c478bd9Sstevel@tonic-gate timeout = ntohl(timeout); 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate /* receive message length */ 10737c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_len, sizeof (msg_len), 10747c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10757c478bd9Sstevel@tonic-gate return (ret); 10767c478bd9Sstevel@tonic-gate } 10777c478bd9Sstevel@tonic-gate 10787c478bd9Sstevel@tonic-gate msg_len = ntohl(msg_len); 10797c478bd9Sstevel@tonic-gate 10807c478bd9Sstevel@tonic-gate /* receive status field */ 10817c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&status, sizeof (status), 10827c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10837c478bd9Sstevel@tonic-gate return (ret); 10847c478bd9Sstevel@tonic-gate } 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate status = ntohl(status); 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate /* receive message checksum */ 10897c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_cksum, sizeof (msg_cksum), 10907c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10917c478bd9Sstevel@tonic-gate return (ret); 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate msg_cksum = ntohs(msg_cksum); 10957c478bd9Sstevel@tonic-gate 10967c478bd9Sstevel@tonic-gate /* receive header checksum */ 10977c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&hdr_cksum, sizeof (hdr_cksum), 10987c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 10997c478bd9Sstevel@tonic-gate return (ret); 11007c478bd9Sstevel@tonic-gate } 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate hdr_cksum = ntohs(hdr_cksum); 11037c478bd9Sstevel@tonic-gate 11047c478bd9Sstevel@tonic-gate /* copy to resp_hdr */ 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate resp_hdr->magic_num = magic_num; 11077c478bd9Sstevel@tonic-gate resp_hdr->proto_ver = proto_ver; 11087c478bd9Sstevel@tonic-gate resp_hdr->msg_type = msg_type; 11097c478bd9Sstevel@tonic-gate resp_hdr->sub_type = sub_type; 11107c478bd9Sstevel@tonic-gate resp_hdr->rsvd_pad = rsvd_pad; 11117c478bd9Sstevel@tonic-gate resp_hdr->xid = xid; 11127c478bd9Sstevel@tonic-gate resp_hdr->timeout = timeout; 11137c478bd9Sstevel@tonic-gate resp_hdr->msg_len = msg_len; 11147c478bd9Sstevel@tonic-gate resp_hdr->status = status; 11157c478bd9Sstevel@tonic-gate resp_hdr->msg_cksum = msg_cksum; 11167c478bd9Sstevel@tonic-gate resp_hdr->hdr_cksum = hdr_cksum; 11177c478bd9Sstevel@tonic-gate 11187c478bd9Sstevel@tonic-gate return (PCP_OK); 11197c478bd9Sstevel@tonic-gate } 11207c478bd9Sstevel@tonic-gate 11217c478bd9Sstevel@tonic-gate /* 11227c478bd9Sstevel@tonic-gate * Get next xid for including in request message. 11237c478bd9Sstevel@tonic-gate * Every request and response message are matched 11247c478bd9Sstevel@tonic-gate * for same xid. 11257c478bd9Sstevel@tonic-gate */ 112656b04ea6Smvgr 112756b04ea6Smvgr static uint32_t 112856b04ea6Smvgr pcp_get_xid(void) 11297c478bd9Sstevel@tonic-gate { 11307c478bd9Sstevel@tonic-gate uint32_t ret; 113156b04ea6Smvgr struct timeval tv; 113256b04ea6Smvgr static boolean_t xid_initialized = B_FALSE; 11337c478bd9Sstevel@tonic-gate 113456b04ea6Smvgr if (xid_initialized == B_FALSE) { 113556b04ea6Smvgr xid_initialized = B_TRUE; 113656b04ea6Smvgr /* 113756b04ea6Smvgr * starting xid is initialized to a different value everytime 113856b04ea6Smvgr * user application is restarted so that user apps will not 113956b04ea6Smvgr * receive previous session's packets. 114056b04ea6Smvgr * 114156b04ea6Smvgr * Note: The algorithm for generating initial xid is partially 114256b04ea6Smvgr * taken from Solaris rpc code. 114356b04ea6Smvgr */ 114456b04ea6Smvgr (void) gettimeofday(&tv, NULL); 114556b04ea6Smvgr msg_xid = (uint32_t)((tv.tv_sec << 20) | 114656b04ea6Smvgr (tv.tv_usec >> 10)); 114756b04ea6Smvgr } 114856b04ea6Smvgr 114956b04ea6Smvgr ret = msg_xid++; 115056b04ea6Smvgr 115156b04ea6Smvgr /* zero xid is not allowed */ 115256b04ea6Smvgr if (ret == 0) 115356b04ea6Smvgr ret = msg_xid++; 115456b04ea6Smvgr 11557c478bd9Sstevel@tonic-gate return (ret); 11567c478bd9Sstevel@tonic-gate } 11577c478bd9Sstevel@tonic-gate 11587c478bd9Sstevel@tonic-gate /* 11597c478bd9Sstevel@tonic-gate * This function handles channel framing errors. It waits until proper 11607c478bd9Sstevel@tonic-gate * frame with starting sequence as magic numder (0xAFBCAFA0) 11617c478bd9Sstevel@tonic-gate * is arrived. It removes unexpected data (before the magic number sequence) 11627c478bd9Sstevel@tonic-gate * on the channel. It returns when proper magic number sequence is seen 11637c478bd9Sstevel@tonic-gate * or when any failure happens while reading/peeking the channel. 11647c478bd9Sstevel@tonic-gate */ 11657c478bd9Sstevel@tonic-gate static int 11667c478bd9Sstevel@tonic-gate pcp_frame_error_handle(void) 11677c478bd9Sstevel@tonic-gate { 11687c478bd9Sstevel@tonic-gate uint8_t magic_num_buf[4]; 11697c478bd9Sstevel@tonic-gate int ispresent = 0; 11707c478bd9Sstevel@tonic-gate uint32_t net_magic_num; /* magic byte in network byte order */ 11717c478bd9Sstevel@tonic-gate uint32_t host_magic_num = PCP_MAGIC_NUM; 11727c478bd9Sstevel@tonic-gate uint8_t buf[2]; 11737c478bd9Sstevel@tonic-gate 11747c478bd9Sstevel@tonic-gate net_magic_num = htonl(host_magic_num); 11757c478bd9Sstevel@tonic-gate (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4); 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate while (!ispresent) { 11787c478bd9Sstevel@tonic-gate /* 11797c478bd9Sstevel@tonic-gate * Check if next four bytes matches pcp magic number. 11807c478bd9Sstevel@tonic-gate * if mathing not found, discard 1 byte and continue checking. 11817c478bd9Sstevel@tonic-gate */ 11827c478bd9Sstevel@tonic-gate if (!check_magic_byte_presence(4, &magic_num_buf[0], 11837c478bd9Sstevel@tonic-gate &ispresent)) { 11847c478bd9Sstevel@tonic-gate if (!ispresent) { 11857c478bd9Sstevel@tonic-gate /* remove 1 byte */ 11867c478bd9Sstevel@tonic-gate (void) pcp_io_op(buf, 1, PCPL_IO_OP_READ); 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate } else { 11897c478bd9Sstevel@tonic-gate return (-1); 11907c478bd9Sstevel@tonic-gate } 11917c478bd9Sstevel@tonic-gate } 11927c478bd9Sstevel@tonic-gate 11937c478bd9Sstevel@tonic-gate return (0); 11947c478bd9Sstevel@tonic-gate } 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate /* 11971ae08745Sheppo * This function handles channel framing errors. It waits until proper 11981ae08745Sheppo * frame with starting sequence as magic numder (0xAFBCAFA0) 11991ae08745Sheppo * is arrived. It removes unexpected data (before the magic number sequence) 12001ae08745Sheppo * on the channel. It returns when proper magic number sequence is seen 12011ae08745Sheppo * or when any failure happens while reading/peeking the channel. 12021ae08745Sheppo */ 12031ae08745Sheppo static int 12041ae08745Sheppo pcp_vldc_frame_error_handle(void) 12051ae08745Sheppo { 12061ae08745Sheppo uint8_t magic_num_buf[4]; 12071ae08745Sheppo uint32_t net_magic_num; /* magic byte in network byte order */ 12081ae08745Sheppo uint32_t host_magic_num = PCP_MAGIC_NUM; 12091ae08745Sheppo int found_magic = 0; 12101ae08745Sheppo 12111ae08745Sheppo net_magic_num = htonl(host_magic_num); 12121ae08745Sheppo (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4); 12131ae08745Sheppo 12141ae08745Sheppo /* 12151ae08745Sheppo * For vldc, we need to read whatever data is available and 12161ae08745Sheppo * advance the read pointer one byte at a time until we get 12171ae08745Sheppo * the magic word. When this function is invoked, we do not 12181ae08745Sheppo * have any byte in the read buffer. 12191ae08745Sheppo */ 12201ae08745Sheppo 12211ae08745Sheppo /* 12221ae08745Sheppo * Keep reading until we find the matching magic number 12231ae08745Sheppo */ 12241ae08745Sheppo while (!found_magic) { 12251ae08745Sheppo while ((read_tail - read_head) < sizeof (host_magic_num)) { 12261ae08745Sheppo if (pcp_update_read_area(sizeof (host_magic_num)) < 0) 12271ae08745Sheppo return (-1); 12281ae08745Sheppo } 12291ae08745Sheppo 12301ae08745Sheppo /* 12311ae08745Sheppo * We should have at least 4 bytes in read buffer. Check 12321ae08745Sheppo * if the magic number can be matched 12331ae08745Sheppo */ 12341ae08745Sheppo if (memcmp(read_head, magic_num_buf, 12351ae08745Sheppo sizeof (host_magic_num))) { 12361ae08745Sheppo read_head += 1; 12371ae08745Sheppo } else { 12381ae08745Sheppo found_magic = 1; 12391ae08745Sheppo } 12401ae08745Sheppo } 12411ae08745Sheppo 12421ae08745Sheppo return (0); 12431ae08745Sheppo } 12441ae08745Sheppo 12451ae08745Sheppo /* 12467c478bd9Sstevel@tonic-gate * checks whether certain byte sequence is present in the data stream. 12477c478bd9Sstevel@tonic-gate */ 12487c478bd9Sstevel@tonic-gate static int 12497c478bd9Sstevel@tonic-gate check_magic_byte_presence(int byte_cnt, uint8_t *byte_seq, int *ispresent) 12507c478bd9Sstevel@tonic-gate { 12517c478bd9Sstevel@tonic-gate int ret, i; 12527c478bd9Sstevel@tonic-gate uint8_t buf[4]; 12537c478bd9Sstevel@tonic-gate 12547c478bd9Sstevel@tonic-gate if ((ret = pcp_peek_read(buf, byte_cnt)) < 0) { 12557c478bd9Sstevel@tonic-gate return (ret); 12567c478bd9Sstevel@tonic-gate } 12577c478bd9Sstevel@tonic-gate 12587c478bd9Sstevel@tonic-gate /* 'byte_cnt' bytes not present */ 12597c478bd9Sstevel@tonic-gate if (ret != byte_cnt) { 12607c478bd9Sstevel@tonic-gate *ispresent = 0; 12617c478bd9Sstevel@tonic-gate return (0); 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate for (i = 0; i < byte_cnt; ++i) { 12657c478bd9Sstevel@tonic-gate if (buf[i] != byte_seq[i]) { 12667c478bd9Sstevel@tonic-gate *ispresent = 0; 12677c478bd9Sstevel@tonic-gate return (0); 12687c478bd9Sstevel@tonic-gate } 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate *ispresent = 1; 12717c478bd9Sstevel@tonic-gate 12727c478bd9Sstevel@tonic-gate return (0); 12737c478bd9Sstevel@tonic-gate } 12747c478bd9Sstevel@tonic-gate 12757c478bd9Sstevel@tonic-gate /* 12767c478bd9Sstevel@tonic-gate * 16-bit simple internet checksum 12777c478bd9Sstevel@tonic-gate */ 12787c478bd9Sstevel@tonic-gate static uint16_t 12797c478bd9Sstevel@tonic-gate checksum(uint16_t *addr, int32_t count) 12807c478bd9Sstevel@tonic-gate { 12817c478bd9Sstevel@tonic-gate /* 12827c478bd9Sstevel@tonic-gate * Compute Internet Checksum for "count" bytes 12837c478bd9Sstevel@tonic-gate * beginning at location "addr". 12847c478bd9Sstevel@tonic-gate */ 12857c478bd9Sstevel@tonic-gate 12867c478bd9Sstevel@tonic-gate register uint32_t sum = 0; 12877c478bd9Sstevel@tonic-gate 12887c478bd9Sstevel@tonic-gate while (count > 1) { 12897c478bd9Sstevel@tonic-gate /* This is the inner loop */ 12907c478bd9Sstevel@tonic-gate sum += *(unsigned short *)addr++; 12917c478bd9Sstevel@tonic-gate count -= 2; 12927c478bd9Sstevel@tonic-gate } 12937c478bd9Sstevel@tonic-gate 12947c478bd9Sstevel@tonic-gate /* Add left-over byte, if any */ 12957c478bd9Sstevel@tonic-gate if (count > 0) 12967c478bd9Sstevel@tonic-gate sum += * (unsigned char *)addr; 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate /* Fold 32-bit sum to 16 bits */ 12997c478bd9Sstevel@tonic-gate while (sum >> 16) 13007c478bd9Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16); 13017c478bd9Sstevel@tonic-gate 13027c478bd9Sstevel@tonic-gate sum = (~sum) & 0xffff; 13037c478bd9Sstevel@tonic-gate if (sum == 0) 13047c478bd9Sstevel@tonic-gate sum = 0xffff; 13057c478bd9Sstevel@tonic-gate 13067c478bd9Sstevel@tonic-gate return (sum); 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 13097c478bd9Sstevel@tonic-gate /* 13107c478bd9Sstevel@tonic-gate * cleanup the channel if any data is hanging in 13117c478bd9Sstevel@tonic-gate * channel buffers. 13127c478bd9Sstevel@tonic-gate */ 13137c478bd9Sstevel@tonic-gate static int 13145db09ef5Smvgr pcp_cleanup(int channel_fd) 13157c478bd9Sstevel@tonic-gate { 13167c478bd9Sstevel@tonic-gate int ret; 13177c478bd9Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl; 13187c478bd9Sstevel@tonic-gate int n, done; 13197c478bd9Sstevel@tonic-gate uint8_t *buf = NULL; 13207c478bd9Sstevel@tonic-gate int retry = 0; 13217c478bd9Sstevel@tonic-gate 13227c478bd9Sstevel@tonic-gate 13237c478bd9Sstevel@tonic-gate buf = (uint8_t *)umem_zalloc((mtu_size), UMEM_DEFAULT); 13247c478bd9Sstevel@tonic-gate if (buf == NULL) { 13257c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 13267c478bd9Sstevel@tonic-gate } 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)buf; 13297c478bd9Sstevel@tonic-gate peek_ctrl.buflen = mtu_size; 13307c478bd9Sstevel@tonic-gate peek_ctrl.flags = 0; 13317c478bd9Sstevel@tonic-gate 13327c478bd9Sstevel@tonic-gate /* 13337c478bd9Sstevel@tonic-gate * set sig jmp location 13347c478bd9Sstevel@tonic-gate */ 13357c478bd9Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) { 13367c478bd9Sstevel@tonic-gate umem_free(buf, mtu_size); 13377c478bd9Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT); 13387c478bd9Sstevel@tonic-gate } 13397c478bd9Sstevel@tonic-gate 13407c478bd9Sstevel@tonic-gate done = 0; 13417c478bd9Sstevel@tonic-gate while (!done) { 13427c478bd9Sstevel@tonic-gate 13437c478bd9Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT); 13445db09ef5Smvgr if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_DATA_PEEK, 13457c478bd9Sstevel@tonic-gate &peek_ctrl)) < 0) { 13467c478bd9Sstevel@tonic-gate (void) alarm(0); 13477c478bd9Sstevel@tonic-gate done = 1; 13487c478bd9Sstevel@tonic-gate continue; 13497c478bd9Sstevel@tonic-gate } 13507c478bd9Sstevel@tonic-gate (void) alarm(0); 13517c478bd9Sstevel@tonic-gate 13527c478bd9Sstevel@tonic-gate n = peek_ctrl.buflen; 13537c478bd9Sstevel@tonic-gate 13547c478bd9Sstevel@tonic-gate if (n <= 0 && retry > 2) { 13557c478bd9Sstevel@tonic-gate done = 1; 13567c478bd9Sstevel@tonic-gate continue; 13577c478bd9Sstevel@tonic-gate } else if (n <= 0) { 13587c478bd9Sstevel@tonic-gate ++retry; 13597c478bd9Sstevel@tonic-gate continue; 13607c478bd9Sstevel@tonic-gate } 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate /* remove data from channel */ 13637c478bd9Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT); 13645db09ef5Smvgr if ((ret = read(channel_fd, buf, n)) < 0) { 13657c478bd9Sstevel@tonic-gate (void) alarm(0); 13667c478bd9Sstevel@tonic-gate done = 1; 13677c478bd9Sstevel@tonic-gate continue; 13687c478bd9Sstevel@tonic-gate } 13697c478bd9Sstevel@tonic-gate (void) alarm(0); 13707c478bd9Sstevel@tonic-gate } 13717c478bd9Sstevel@tonic-gate 13727c478bd9Sstevel@tonic-gate umem_free(buf, mtu_size); 13737c478bd9Sstevel@tonic-gate return (ret); 13747c478bd9Sstevel@tonic-gate } 13751ae08745Sheppo 13761ae08745Sheppo static int 13771ae08745Sheppo vldc_write(int fd, uint8_t *bufp, int size) 13781ae08745Sheppo { 13791ae08745Sheppo int res; 13801ae08745Sheppo int left = size; 13811ae08745Sheppo pollfd_t pollfd; 13821ae08745Sheppo 13831ae08745Sheppo pollfd.events = POLLOUT; 13841ae08745Sheppo pollfd.revents = 0; 13851ae08745Sheppo pollfd.fd = fd; 13861ae08745Sheppo 13871ae08745Sheppo /* 13881ae08745Sheppo * Poll for the vldc channel to be ready 13891ae08745Sheppo */ 13901ae08745Sheppo if (poll(&pollfd, 1, glvc_timeout * MILLISEC) <= 0) { 13911ae08745Sheppo return (-1); 13921ae08745Sheppo } 13931ae08745Sheppo 13941ae08745Sheppo do { 13951ae08745Sheppo if ((res = write(fd, bufp, left)) <= 0) { 13961ae08745Sheppo if (errno != EWOULDBLOCK) { 13971ae08745Sheppo return (res); 13981ae08745Sheppo } 13991ae08745Sheppo } else { 14001ae08745Sheppo bufp += res; 14011ae08745Sheppo left -= res; 14021ae08745Sheppo } 14031ae08745Sheppo } while (left > 0); 14041ae08745Sheppo 14051ae08745Sheppo /* 14061ae08745Sheppo * Return number of bytes actually written 14071ae08745Sheppo */ 14081ae08745Sheppo return (size - left); 14091ae08745Sheppo } 14101ae08745Sheppo 14111ae08745Sheppo /* 14121ae08745Sheppo * Keep reading until we get the specified number of bytes 14131ae08745Sheppo */ 14141ae08745Sheppo static int 14151ae08745Sheppo vldc_read(int fd, uint8_t *bufp, int size) 14161ae08745Sheppo { 14171ae08745Sheppo int res; 14181ae08745Sheppo int left = size; 14191ae08745Sheppo 14201ae08745Sheppo struct pollfd fds[1]; 14211ae08745Sheppo 14221ae08745Sheppo fds[0].events = POLLIN | POLLPRI; 14231ae08745Sheppo fds[0].revents = 0; 14241ae08745Sheppo fds[0].fd = fd; 14251ae08745Sheppo 14261ae08745Sheppo if (poll(fds, 1, glvc_timeout * MILLISEC) <= 0) { 14271ae08745Sheppo return (-1); 14281ae08745Sheppo } 14291ae08745Sheppo 14301ae08745Sheppo while (left > 0) { 14311ae08745Sheppo res = read(fd, bufp, left); 14321ae08745Sheppo /* return on error or short read */ 14331ae08745Sheppo if ((res == 0) || ((res < 0) && 14341ae08745Sheppo (errno == EAGAIN))) { 14351ae08745Sheppo /* poll until the read is unblocked */ 14361ae08745Sheppo if ((poll(fds, 1, glvc_timeout * MILLISEC)) < 0) 14371ae08745Sheppo return (-1); 14381ae08745Sheppo 14391ae08745Sheppo continue; 14401ae08745Sheppo } else 14411ae08745Sheppo if (res < 0) { 14421ae08745Sheppo /* unrecoverable error */ 14431ae08745Sheppo 14441ae08745Sheppo return (-1); 14451ae08745Sheppo } else { 14461ae08745Sheppo bufp += res; 14471ae08745Sheppo left -= res; 14481ae08745Sheppo } 14491ae08745Sheppo } 14501ae08745Sheppo 14511ae08745Sheppo return (size - left); 14521ae08745Sheppo } 1453