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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * Platform Channel Protocol Library functions on Nigara platforms 297c478bd9Sstevel@tonic-gate * (Ontario, Erie, etc..) Solaris applications use these interfaces 307c478bd9Sstevel@tonic-gate * to communicate with entities that reside on service processor. 317c478bd9Sstevel@tonic-gate */ 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #include <stdio.h> 367c478bd9Sstevel@tonic-gate #include <stdlib.h> 377c478bd9Sstevel@tonic-gate #include <unistd.h> 387c478bd9Sstevel@tonic-gate #include <string.h> 397c478bd9Sstevel@tonic-gate #include <assert.h> 407c478bd9Sstevel@tonic-gate #include <fcntl.h> 417c478bd9Sstevel@tonic-gate #include <errno.h> 427c478bd9Sstevel@tonic-gate #include <signal.h> 437c478bd9Sstevel@tonic-gate #include <setjmp.h> 447c478bd9Sstevel@tonic-gate #include <inttypes.h> 457c478bd9Sstevel@tonic-gate #include <umem.h> 467c478bd9Sstevel@tonic-gate #include <strings.h> 477c478bd9Sstevel@tonic-gate #include <sys/types.h> 487c478bd9Sstevel@tonic-gate #include <sys/stat.h> 497c478bd9Sstevel@tonic-gate #include <sys/glvc.h> 507c478bd9Sstevel@tonic-gate #include <netinet/in.h> 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include "libpcp.h" 537c478bd9Sstevel@tonic-gate #include "pcp_common.h" 547c478bd9Sstevel@tonic-gate 557c478bd9Sstevel@tonic-gate /* 567c478bd9Sstevel@tonic-gate * Following libpcp interfaces are exposed to user applications. 577c478bd9Sstevel@tonic-gate * 585db09ef5Smvgr * int pcp_init(char *channel_name); 595db09ef5Smvgr * int pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg, 605db09ef5Smvgr * uint32_t timeout); 615db09ef5Smvgr * int pcp_close(int channel_fd); 627c478bd9Sstevel@tonic-gate * 637c478bd9Sstevel@tonic-gate */ 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Forward declarations. 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr); 697c478bd9Sstevel@tonic-gate static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr); 707c478bd9Sstevel@tonic-gate static int pcp_io_op(void *buf, int byte_cnt, int io_op); 717c478bd9Sstevel@tonic-gate static int pcp_get_xid(void); 725db09ef5Smvgr static int pcp_get_prop(int channel_fd, int prop, unsigned int *val); 737c478bd9Sstevel@tonic-gate static int pcp_read(uint8_t *buf, int buf_len); 747c478bd9Sstevel@tonic-gate static int pcp_write(uint8_t *buf, int buf_len); 757c478bd9Sstevel@tonic-gate static int pcp_peek(uint8_t *buf, int buf_len); 767c478bd9Sstevel@tonic-gate static int pcp_peek_read(uint8_t *buf, int buf_len); 777c478bd9Sstevel@tonic-gate static int pcp_frame_error_handle(void); 787c478bd9Sstevel@tonic-gate static int check_magic_byte_presence(int byte_cnt, uint8_t *byte_val, 797c478bd9Sstevel@tonic-gate int *ispresent); 807c478bd9Sstevel@tonic-gate static uint16_t checksum(uint16_t *addr, int32_t count); 815db09ef5Smvgr static int pcp_cleanup(int channel_fd); 827c478bd9Sstevel@tonic-gate 837c478bd9Sstevel@tonic-gate /* 845db09ef5Smvgr * local channel (glvc) file descriptor set by pcp_send_recv() 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate static int chnl_fd = -1; 877c478bd9Sstevel@tonic-gate 887c478bd9Sstevel@tonic-gate /* 897c478bd9Sstevel@tonic-gate * Message Transaction ID 907c478bd9Sstevel@tonic-gate */ 917c478bd9Sstevel@tonic-gate static uint32_t msg_xid = 0; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate /* 947c478bd9Sstevel@tonic-gate * Channel MTU size. 957c478bd9Sstevel@tonic-gate */ 967c478bd9Sstevel@tonic-gate static unsigned int mtu_size = PCPL_DEF_MTU_SZ; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate /* 997c478bd9Sstevel@tonic-gate * timeout field is supplied by user. timeout field is used to decide 1007c478bd9Sstevel@tonic-gate * how long to block on glvc driver calls before we return timeout error 1017c478bd9Sstevel@tonic-gate * to user applications. 1027c478bd9Sstevel@tonic-gate * 1037c478bd9Sstevel@tonic-gate * Note: In the current implementation of glvc driver, all glvc calls are 1047c478bd9Sstevel@tonic-gate * blocking. 1057c478bd9Sstevel@tonic-gate */ 1067c478bd9Sstevel@tonic-gate static uint32_t glvc_timeout = 0; 1077c478bd9Sstevel@tonic-gate 1087c478bd9Sstevel@tonic-gate /* 1097c478bd9Sstevel@tonic-gate * variables used by setsetjmp/siglongjmp. 1107c478bd9Sstevel@tonic-gate */ 1117c478bd9Sstevel@tonic-gate static volatile sig_atomic_t jumpok = 0; 1127c478bd9Sstevel@tonic-gate static sigjmp_buf jmpbuf; 1137c478bd9Sstevel@tonic-gate 1147c478bd9Sstevel@tonic-gate /* 1157c478bd9Sstevel@tonic-gate * To unblock SIGALRM signal incase if it's blocked in libpcp user apps. 1167c478bd9Sstevel@tonic-gate * Restore it to old state during pcp_close. 1177c478bd9Sstevel@tonic-gate */ 1187c478bd9Sstevel@tonic-gate static sigset_t blkset; 1197c478bd9Sstevel@tonic-gate 1207c478bd9Sstevel@tonic-gate /* 1217c478bd9Sstevel@tonic-gate * Buffers used for stream reading channel data. When data is read in 1227c478bd9Sstevel@tonic-gate * stream fashion, first data is copied from channel (glvc) buffers to 1237c478bd9Sstevel@tonic-gate * these local buffers from which the read requests are serviced. 1247c478bd9Sstevel@tonic-gate */ 1257c478bd9Sstevel@tonic-gate #define READ_AREA_SIZE (2*mtu_size) 1267c478bd9Sstevel@tonic-gate static uint8_t *read_head = NULL; 1277c478bd9Sstevel@tonic-gate static uint8_t *read_tail = NULL; 1287c478bd9Sstevel@tonic-gate static uint8_t *read_area = NULL; 1297c478bd9Sstevel@tonic-gate 1307c478bd9Sstevel@tonic-gate /* 1317c478bd9Sstevel@tonic-gate * Buffer used for peeking new data available in channel (glvc) buffers. 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate #define PEEK_AREA_SIZE (mtu_size) 1347c478bd9Sstevel@tonic-gate static uint8_t *peek_area = NULL; 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate /* 1377c478bd9Sstevel@tonic-gate * Buffers used for peeking data available either in local buffers or 1387c478bd9Sstevel@tonic-gate * new data available in channel (glvc) buffers. 1397c478bd9Sstevel@tonic-gate */ 1407c478bd9Sstevel@tonic-gate #define PEEK_READ_AREA_SIZE (2*mtu_size) 1417c478bd9Sstevel@tonic-gate static uint8_t *peek_read_head = NULL; 1427c478bd9Sstevel@tonic-gate static uint8_t *peek_read_tail = NULL; 1437c478bd9Sstevel@tonic-gate static uint8_t *peek_read_area = NULL; 1447c478bd9Sstevel@tonic-gate 1457c478bd9Sstevel@tonic-gate static pcp_req_msg_hdr_t *req_msg_hdr = NULL; 1467c478bd9Sstevel@tonic-gate static pcp_resp_msg_hdr_t *resp_msg_hdr = NULL; 1477c478bd9Sstevel@tonic-gate static int req_msg_hdr_sz = 0; 1487c478bd9Sstevel@tonic-gate static int resp_msg_hdr_sz = 0; 1497c478bd9Sstevel@tonic-gate 1507c478bd9Sstevel@tonic-gate /* 1517c478bd9Sstevel@tonic-gate * signal handling variables to handle glvc blocking calls. 1527c478bd9Sstevel@tonic-gate */ 1537c478bd9Sstevel@tonic-gate static struct sigaction glvc_act; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* To restore old SIGALRM signal handler */ 1567c478bd9Sstevel@tonic-gate static struct sigaction old_act; 1577c478bd9Sstevel@tonic-gate 1587c478bd9Sstevel@tonic-gate static void 1597c478bd9Sstevel@tonic-gate glvc_timeout_handler(void) 1607c478bd9Sstevel@tonic-gate { 1617c478bd9Sstevel@tonic-gate if (jumpok == 0) 1627c478bd9Sstevel@tonic-gate return; 1637c478bd9Sstevel@tonic-gate siglongjmp(jmpbuf, 1); 1647c478bd9Sstevel@tonic-gate } 1657c478bd9Sstevel@tonic-gate 1667c478bd9Sstevel@tonic-gate /* 1677c478bd9Sstevel@tonic-gate * Initialize the virtual channel. It basically opens the virtual channel 1687c478bd9Sstevel@tonic-gate * provided by the host application. 1697c478bd9Sstevel@tonic-gate * 1707c478bd9Sstevel@tonic-gate */ 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate int 1735db09ef5Smvgr pcp_init(char *channel_name) 1747c478bd9Sstevel@tonic-gate { 1757c478bd9Sstevel@tonic-gate sigset_t oldset; 1765db09ef5Smvgr int channel_fd; 1777c478bd9Sstevel@tonic-gate 1785db09ef5Smvgr if (channel_name == NULL) 1797c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 1807c478bd9Sstevel@tonic-gate /* 1815db09ef5Smvgr * Open virtual channel name. 1827c478bd9Sstevel@tonic-gate */ 1835db09ef5Smvgr if ((channel_fd = open(channel_name, O_RDWR|O_EXCL)) < 0) { 1847c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* 1887c478bd9Sstevel@tonic-gate * Initialize Message Transaction ID. 1897c478bd9Sstevel@tonic-gate */ 1907c478bd9Sstevel@tonic-gate msg_xid = PCPL_INIT_XID; 1917c478bd9Sstevel@tonic-gate 1927c478bd9Sstevel@tonic-gate /* 1937c478bd9Sstevel@tonic-gate * Get the Channel MTU size 1947c478bd9Sstevel@tonic-gate */ 1957c478bd9Sstevel@tonic-gate 1965db09ef5Smvgr if (pcp_get_prop(channel_fd, GLVC_XPORT_OPT_MTU_SZ, &mtu_size) != 0) { 1975db09ef5Smvgr (void) close(channel_fd); 1987c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 1997c478bd9Sstevel@tonic-gate } 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate /* 2027c478bd9Sstevel@tonic-gate * Get current signal mask. If SIGALRM is blocked 2037c478bd9Sstevel@tonic-gate * unblock it. 2047c478bd9Sstevel@tonic-gate */ 2057c478bd9Sstevel@tonic-gate (void) sigprocmask(0, NULL, &oldset); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate (void) sigemptyset(&blkset); 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate if (sigismember(&oldset, SIGALRM)) { 2107c478bd9Sstevel@tonic-gate (void) sigaddset(&blkset, SIGALRM); 2117c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &blkset, NULL); 2127c478bd9Sstevel@tonic-gate } 2137c478bd9Sstevel@tonic-gate /* 2147c478bd9Sstevel@tonic-gate * signal handler initialization to handle glvc call timeouts. 2157c478bd9Sstevel@tonic-gate */ 2167c478bd9Sstevel@tonic-gate glvc_act.sa_handler = glvc_timeout_handler; 2177c478bd9Sstevel@tonic-gate (void) sigemptyset(&glvc_act.sa_mask); 2187c478bd9Sstevel@tonic-gate glvc_act.sa_flags = SA_NODEFER; 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate if (sigaction(SIGALRM, &glvc_act, &old_act) < 0) { 2215db09ef5Smvgr (void) close(channel_fd); 2227c478bd9Sstevel@tonic-gate return (PCPL_ERROR); 2237c478bd9Sstevel@tonic-gate } 2247c478bd9Sstevel@tonic-gate 2255db09ef5Smvgr return (channel_fd); 2267c478bd9Sstevel@tonic-gate } 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate /* 2297c478bd9Sstevel@tonic-gate * Function: Close platform channel. 2305db09ef5Smvgr * Arguments: 2315db09ef5Smvgr * int channel_fd - channel file descriptor. 2327c478bd9Sstevel@tonic-gate * Returns: 2337c478bd9Sstevel@tonic-gate * always returns PCPL_OK for now. 2347c478bd9Sstevel@tonic-gate */ 2357c478bd9Sstevel@tonic-gate int 2365db09ef5Smvgr pcp_close(int channel_fd) 2377c478bd9Sstevel@tonic-gate { 2387c478bd9Sstevel@tonic-gate 2395db09ef5Smvgr if (channel_fd >= 0) { 2405db09ef5Smvgr (void) pcp_cleanup(channel_fd); 2415db09ef5Smvgr (void) close(channel_fd); 2425db09ef5Smvgr } else { 2435db09ef5Smvgr return (-1); 2447c478bd9Sstevel@tonic-gate } 2457c478bd9Sstevel@tonic-gate 2467c478bd9Sstevel@tonic-gate /* 2477c478bd9Sstevel@tonic-gate * free global buffers 2487c478bd9Sstevel@tonic-gate */ 2497c478bd9Sstevel@tonic-gate if (read_area != NULL) { 2507c478bd9Sstevel@tonic-gate umem_free(read_area, READ_AREA_SIZE); 2517c478bd9Sstevel@tonic-gate read_area = NULL; 2527c478bd9Sstevel@tonic-gate } 2537c478bd9Sstevel@tonic-gate if (peek_area != NULL) { 2547c478bd9Sstevel@tonic-gate umem_free(peek_area, PEEK_AREA_SIZE); 2557c478bd9Sstevel@tonic-gate peek_area = NULL; 2567c478bd9Sstevel@tonic-gate } 2577c478bd9Sstevel@tonic-gate if (peek_read_area != NULL) { 2587c478bd9Sstevel@tonic-gate umem_free(peek_read_area, PEEK_READ_AREA_SIZE); 2597c478bd9Sstevel@tonic-gate peek_read_area = NULL; 2607c478bd9Sstevel@tonic-gate } 2617c478bd9Sstevel@tonic-gate if (req_msg_hdr != NULL) { 2627c478bd9Sstevel@tonic-gate umem_free(req_msg_hdr, req_msg_hdr_sz); 2637c478bd9Sstevel@tonic-gate req_msg_hdr = NULL; 2647c478bd9Sstevel@tonic-gate } 2657c478bd9Sstevel@tonic-gate if (resp_msg_hdr != NULL) { 2667c478bd9Sstevel@tonic-gate umem_free(resp_msg_hdr, resp_msg_hdr_sz); 2677c478bd9Sstevel@tonic-gate resp_msg_hdr = NULL; 2687c478bd9Sstevel@tonic-gate } 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate /* 2717c478bd9Sstevel@tonic-gate * Restore SIGALRM signal mask incase if we unblocked 2727c478bd9Sstevel@tonic-gate * it during pcp_init. 2737c478bd9Sstevel@tonic-gate */ 2747c478bd9Sstevel@tonic-gate if (sigismember(&blkset, SIGALRM)) { 2757c478bd9Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &blkset, NULL); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* Restore SIGALRM signal handler */ 2797c478bd9Sstevel@tonic-gate (void) sigaction(SIGALRM, &old_act, NULL); 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate return (PCPL_OK); 2827c478bd9Sstevel@tonic-gate } 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* 2857c478bd9Sstevel@tonic-gate * Function: Send and Receive messages on platform channel. 2867c478bd9Sstevel@tonic-gate * Arguments: 2875db09ef5Smvgr * int channel_fd - channel file descriptor. 2887c478bd9Sstevel@tonic-gate * pcp_msg_t *req_msg - Request Message to send to other end of channel. 2897c478bd9Sstevel@tonic-gate * pcp_msg_t *resp_msg - Response Message to be received. 2907c478bd9Sstevel@tonic-gate * uint32_t timeout - timeout field when waiting for data from channel. 2917c478bd9Sstevel@tonic-gate * Returns: 2927c478bd9Sstevel@tonic-gate * 0 - success (PCPL_OK). 2937c478bd9Sstevel@tonic-gate * (-ve) - failure: 2947c478bd9Sstevel@tonic-gate * PCPL_INVALID_ARGS - invalid args. 2957c478bd9Sstevel@tonic-gate * PCPL_GLVC_TIMEOUT - glvc call timeout. 2967c478bd9Sstevel@tonic-gate * PCPL_XPORT_ERROR - transport error in request message 2977c478bd9Sstevel@tonic-gate * noticed by receiver. 2987c478bd9Sstevel@tonic-gate * PCPL_MALLOC_FAIL - malloc failure. 2997c478bd9Sstevel@tonic-gate * PCPL_CKSUM_ERROR - checksum error. 3007c478bd9Sstevel@tonic-gate */ 3017c478bd9Sstevel@tonic-gate int 3025db09ef5Smvgr pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg, 3035db09ef5Smvgr uint32_t timeout) 3047c478bd9Sstevel@tonic-gate { 3057c478bd9Sstevel@tonic-gate void *datap; 3067c478bd9Sstevel@tonic-gate void *resp_msg_data = NULL; 3077c478bd9Sstevel@tonic-gate uint32_t status; 3087c478bd9Sstevel@tonic-gate uint16_t cksum = 0; 3097c478bd9Sstevel@tonic-gate int ret; 3107c478bd9Sstevel@tonic-gate int resp_hdr_ok; 3117c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 3127c478bd9Sstevel@tonic-gate uint16_t bkup_resp_hdr_cksum; 3137c478bd9Sstevel@tonic-gate #endif 3145db09ef5Smvgr if (channel_fd < 0) { 3157c478bd9Sstevel@tonic-gate return (PCPL_ERROR); 3167c478bd9Sstevel@tonic-gate } 3177c478bd9Sstevel@tonic-gate 3185db09ef5Smvgr /* copy channel_fd to local fd (chnl_fd) for other functions use */ 3195db09ef5Smvgr chnl_fd = channel_fd; 3205db09ef5Smvgr 3217c478bd9Sstevel@tonic-gate if (req_msg == NULL) { 3227c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (timeout > 0) 3267c478bd9Sstevel@tonic-gate glvc_timeout = timeout; 3277c478bd9Sstevel@tonic-gate else 3287c478bd9Sstevel@tonic-gate glvc_timeout = 0; 3297c478bd9Sstevel@tonic-gate 330*1b255844Smvgr if ((req_msg->msg_len != 0) && ((datap = req_msg->msg_data) == NULL)) 3317c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate if (req_msg_hdr == NULL) { 3347c478bd9Sstevel@tonic-gate req_msg_hdr_sz = sizeof (pcp_req_msg_hdr_t); 3357c478bd9Sstevel@tonic-gate req_msg_hdr = (pcp_req_msg_hdr_t *)umem_zalloc(req_msg_hdr_sz, 3367c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 3377c478bd9Sstevel@tonic-gate if (req_msg_hdr == NULL) 3387c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 3397c478bd9Sstevel@tonic-gate } 3407c478bd9Sstevel@tonic-gate 3415db09ef5Smvgr if (req_msg->msg_len != 0) { 3427c478bd9Sstevel@tonic-gate /* calculate request msg_cksum */ 3437c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)datap, req_msg->msg_len); 3445db09ef5Smvgr } 3457c478bd9Sstevel@tonic-gate 3467c478bd9Sstevel@tonic-gate /* 3477c478bd9Sstevel@tonic-gate * Fill in the message header for the request packet 3487c478bd9Sstevel@tonic-gate */ 3497c478bd9Sstevel@tonic-gate req_msg_hdr->magic_num = PCP_MAGIC_NUM; 3507c478bd9Sstevel@tonic-gate req_msg_hdr->proto_ver = PCP_PROT_VER_1; 3517c478bd9Sstevel@tonic-gate req_msg_hdr->msg_type = req_msg->msg_type; 3527c478bd9Sstevel@tonic-gate req_msg_hdr->sub_type = req_msg->sub_type; 3537c478bd9Sstevel@tonic-gate req_msg_hdr->rsvd_pad = 0; 3547c478bd9Sstevel@tonic-gate req_msg_hdr->xid = pcp_get_xid(); 3557c478bd9Sstevel@tonic-gate req_msg_hdr->msg_len = req_msg->msg_len; 3567c478bd9Sstevel@tonic-gate req_msg_hdr->timeout = timeout; 3577c478bd9Sstevel@tonic-gate req_msg_hdr->msg_cksum = cksum; 3587c478bd9Sstevel@tonic-gate req_msg_hdr->hdr_cksum = 0; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* fill request header checksum */ 3617c478bd9Sstevel@tonic-gate req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr, 3627c478bd9Sstevel@tonic-gate req_msg_hdr_sz); 3637c478bd9Sstevel@tonic-gate /* 3647c478bd9Sstevel@tonic-gate * set sig jmp location 3657c478bd9Sstevel@tonic-gate */ 3667c478bd9Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) { 3677c478bd9Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT); 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate jumpok = 1; /* monitor sigalrm from now on */ 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate /* 3727c478bd9Sstevel@tonic-gate * send request message header 3737c478bd9Sstevel@tonic-gate */ 3747c478bd9Sstevel@tonic-gate if ((ret = pcp_send_req_msg_hdr(req_msg_hdr))) { 3757c478bd9Sstevel@tonic-gate 3767c478bd9Sstevel@tonic-gate return (ret); 3777c478bd9Sstevel@tonic-gate } 3787c478bd9Sstevel@tonic-gate 3797c478bd9Sstevel@tonic-gate /* 3807c478bd9Sstevel@tonic-gate * send request message 3817c478bd9Sstevel@tonic-gate */ 3825db09ef5Smvgr if (req_msg->msg_len != 0) { 3837c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(datap, req_msg->msg_len, 3847c478bd9Sstevel@tonic-gate PCPL_IO_OP_WRITE))) { 3857c478bd9Sstevel@tonic-gate return (ret); 3867c478bd9Sstevel@tonic-gate } 3875db09ef5Smvgr } 3885db09ef5Smvgr 3897c478bd9Sstevel@tonic-gate if (timeout == (uint32_t)PCP_TO_NO_RESPONSE) 3907c478bd9Sstevel@tonic-gate return (PCPL_OK); 3917c478bd9Sstevel@tonic-gate 3927c478bd9Sstevel@tonic-gate if (resp_msg_hdr == NULL) { 3937c478bd9Sstevel@tonic-gate resp_msg_hdr_sz = sizeof (pcp_resp_msg_hdr_t); 3947c478bd9Sstevel@tonic-gate resp_msg_hdr = (pcp_resp_msg_hdr_t *)umem_alloc(resp_msg_hdr_sz, 3957c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 3967c478bd9Sstevel@tonic-gate if (resp_msg_hdr == NULL) 3977c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 3987c478bd9Sstevel@tonic-gate } 3997c478bd9Sstevel@tonic-gate 4007c478bd9Sstevel@tonic-gate resp_hdr_ok = 0; 4017c478bd9Sstevel@tonic-gate while (!resp_hdr_ok) { 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * Receive response message header 4057c478bd9Sstevel@tonic-gate * Note: frame error handling is done in 4067c478bd9Sstevel@tonic-gate * 'pcp_recv_resp_msg_hdr()'. 4077c478bd9Sstevel@tonic-gate */ 4087c478bd9Sstevel@tonic-gate if ((ret = pcp_recv_resp_msg_hdr(resp_msg_hdr))) { 4097c478bd9Sstevel@tonic-gate return (ret); 4107c478bd9Sstevel@tonic-gate } 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate /* 4137c478bd9Sstevel@tonic-gate * Check header checksum if it matches with the received hdr 4147c478bd9Sstevel@tonic-gate * checksum. 4157c478bd9Sstevel@tonic-gate */ 4167c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 4177c478bd9Sstevel@tonic-gate bkup_resp_hdr_cksum = resp_msg_hdr->hdr_cksum; 4187c478bd9Sstevel@tonic-gate resp_msg_hdr->hdr_cksum = 0; 4197c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)resp_msg_hdr, resp_msg_hdr_sz); 4207c478bd9Sstevel@tonic-gate 4217c478bd9Sstevel@tonic-gate if (cksum != bkup_resp_hdr_cksum) { 4227c478bd9Sstevel@tonic-gate return (PCPL_CKSUM_ERROR); 4237c478bd9Sstevel@tonic-gate } 4247c478bd9Sstevel@tonic-gate #endif 4257c478bd9Sstevel@tonic-gate /* 4267c478bd9Sstevel@tonic-gate * Check for matching request and response messages 4277c478bd9Sstevel@tonic-gate */ 4287c478bd9Sstevel@tonic-gate if (resp_msg_hdr->xid != req_msg_hdr->xid) { 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate continue; /* continue reading response header */ 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate resp_hdr_ok = 1; 4337c478bd9Sstevel@tonic-gate } 4347c478bd9Sstevel@tonic-gate 4357c478bd9Sstevel@tonic-gate /* 4367c478bd9Sstevel@tonic-gate * check status field for any channel protocol errrors 4377c478bd9Sstevel@tonic-gate * This field signifies something happend during request 4387c478bd9Sstevel@tonic-gate * message trasmission. This field is set by the receiver. 4397c478bd9Sstevel@tonic-gate */ 4407c478bd9Sstevel@tonic-gate status = resp_msg_hdr->status; 4417c478bd9Sstevel@tonic-gate if (status != PCP_OK) { 4427c478bd9Sstevel@tonic-gate return (PCPL_XPORT_ERROR); 4437c478bd9Sstevel@tonic-gate } 4447c478bd9Sstevel@tonic-gate 4455db09ef5Smvgr if (resp_msg_hdr->msg_len != 0) { 4467c478bd9Sstevel@tonic-gate 4477c478bd9Sstevel@tonic-gate /* libpcp users should free this memory */ 4485db09ef5Smvgr if ((resp_msg_data = (uint8_t *)malloc(resp_msg_hdr->msg_len)) 4495db09ef5Smvgr == NULL) 4507c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 4517c478bd9Sstevel@tonic-gate bzero(resp_msg_data, resp_msg_hdr->msg_len); 4527c478bd9Sstevel@tonic-gate /* 4537c478bd9Sstevel@tonic-gate * Receive response message. 4547c478bd9Sstevel@tonic-gate */ 4557c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(resp_msg_data, resp_msg_hdr->msg_len, 4567c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ))) { 4577c478bd9Sstevel@tonic-gate free(resp_msg_data); 4587c478bd9Sstevel@tonic-gate return (ret); 4597c478bd9Sstevel@tonic-gate } 4607c478bd9Sstevel@tonic-gate 4617c478bd9Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE 4627c478bd9Sstevel@tonic-gate /* verify response message data checksum */ 4637c478bd9Sstevel@tonic-gate cksum = checksum((uint16_t *)resp_msg_data, 4647c478bd9Sstevel@tonic-gate resp_msg_hdr->msg_len); 4657c478bd9Sstevel@tonic-gate if (cksum != resp_msg_hdr->msg_cksum) { 4667c478bd9Sstevel@tonic-gate free(resp_msg_data); 4677c478bd9Sstevel@tonic-gate return (PCPL_CKSUM_ERROR); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate #endif 4705db09ef5Smvgr } 4717c478bd9Sstevel@tonic-gate /* Everything is okay put the received data into user */ 4727c478bd9Sstevel@tonic-gate /* application's resp_msg struct */ 4737c478bd9Sstevel@tonic-gate resp_msg->msg_len = resp_msg_hdr->msg_len; 4747c478bd9Sstevel@tonic-gate resp_msg->msg_type = resp_msg_hdr->msg_type; 4757c478bd9Sstevel@tonic-gate resp_msg->sub_type = resp_msg_hdr->sub_type; 4767c478bd9Sstevel@tonic-gate resp_msg->msg_data = (uint8_t *)resp_msg_data; 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate return (PCPL_OK); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Function: Get channel property values. 4847c478bd9Sstevel@tonic-gate * Arguments: 4855db09ef5Smvgr * int channel_fd - channel file descriptor. 4867c478bd9Sstevel@tonic-gate * int prop - property id. 4877c478bd9Sstevel@tonic-gate * unsigned int *val - property value tobe copied. 4887c478bd9Sstevel@tonic-gate * Returns: 4897c478bd9Sstevel@tonic-gate * 0 - success 4907c478bd9Sstevel@tonic-gate * (-ve) - failure: 4917c478bd9Sstevel@tonic-gate * PCPL_ERR_GLVC - glvc ioctl failure. 4927c478bd9Sstevel@tonic-gate */ 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate static int 4955db09ef5Smvgr pcp_get_prop(int channel_fd, int prop, unsigned int *val) 4967c478bd9Sstevel@tonic-gate { 4977c478bd9Sstevel@tonic-gate glvc_xport_opt_op_t channel_op; 4987c478bd9Sstevel@tonic-gate int ret; 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate channel_op.op_sel = GLVC_XPORT_OPT_GET; 5017c478bd9Sstevel@tonic-gate channel_op.opt_sel = prop; 5027c478bd9Sstevel@tonic-gate channel_op.opt_val = 0; 5037c478bd9Sstevel@tonic-gate 5047c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 5057c478bd9Sstevel@tonic-gate 5065db09ef5Smvgr if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_OPT_OP, 5075db09ef5Smvgr &channel_op)) < 0) { 5085db09ef5Smvgr 5097c478bd9Sstevel@tonic-gate (void) alarm(0); 5107c478bd9Sstevel@tonic-gate return (ret); 5117c478bd9Sstevel@tonic-gate } 5127c478bd9Sstevel@tonic-gate (void) alarm(0); 5137c478bd9Sstevel@tonic-gate 5147c478bd9Sstevel@tonic-gate *val = channel_op.opt_val; 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate return (0); 5177c478bd9Sstevel@tonic-gate } 5187c478bd9Sstevel@tonic-gate 5197c478bd9Sstevel@tonic-gate /* 5207c478bd9Sstevel@tonic-gate * Function: wrapper for handling glvc calls (read/write/peek). 5217c478bd9Sstevel@tonic-gate */ 5227c478bd9Sstevel@tonic-gate static int 5237c478bd9Sstevel@tonic-gate pcp_io_op(void *buf, int byte_cnt, int io_op) 5247c478bd9Sstevel@tonic-gate { 5257c478bd9Sstevel@tonic-gate int rv; 5267c478bd9Sstevel@tonic-gate int n; 5277c478bd9Sstevel@tonic-gate uint8_t *datap; 5287c478bd9Sstevel@tonic-gate int (*func_ptr)(uint8_t *, int); 5297c478bd9Sstevel@tonic-gate int io_sz; 5307c478bd9Sstevel@tonic-gate int try_cnt; 5317c478bd9Sstevel@tonic-gate 5327c478bd9Sstevel@tonic-gate 5337c478bd9Sstevel@tonic-gate if ((buf == NULL) || (byte_cnt < 0)) { 5347c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 5357c478bd9Sstevel@tonic-gate } 5367c478bd9Sstevel@tonic-gate 5377c478bd9Sstevel@tonic-gate switch (io_op) { 5387c478bd9Sstevel@tonic-gate case PCPL_IO_OP_READ: 5397c478bd9Sstevel@tonic-gate func_ptr = pcp_read; 5407c478bd9Sstevel@tonic-gate break; 5417c478bd9Sstevel@tonic-gate case PCPL_IO_OP_WRITE: 5427c478bd9Sstevel@tonic-gate func_ptr = pcp_write; 5437c478bd9Sstevel@tonic-gate break; 5447c478bd9Sstevel@tonic-gate case PCPL_IO_OP_PEEK: 5457c478bd9Sstevel@tonic-gate func_ptr = pcp_peek; 5467c478bd9Sstevel@tonic-gate break; 5477c478bd9Sstevel@tonic-gate default: 5487c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 5497c478bd9Sstevel@tonic-gate } 5507c478bd9Sstevel@tonic-gate 5517c478bd9Sstevel@tonic-gate /* 5527c478bd9Sstevel@tonic-gate * loop until all I/O done, try limit exceded, or real failure 5537c478bd9Sstevel@tonic-gate */ 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate rv = 0; 5567c478bd9Sstevel@tonic-gate datap = buf; 5577c478bd9Sstevel@tonic-gate while (rv < byte_cnt) { 5587c478bd9Sstevel@tonic-gate io_sz = MIN((byte_cnt - rv), mtu_size); 5597c478bd9Sstevel@tonic-gate try_cnt = 0; 5607c478bd9Sstevel@tonic-gate while ((n = (*func_ptr)(datap, io_sz)) < 0) { 5617c478bd9Sstevel@tonic-gate try_cnt++; 5627c478bd9Sstevel@tonic-gate if (try_cnt > PCPL_MAX_TRY_CNT) { 5637c478bd9Sstevel@tonic-gate rv = n; 5647c478bd9Sstevel@tonic-gate goto done; 5657c478bd9Sstevel@tonic-gate } 5667c478bd9Sstevel@tonic-gate (void) sleep(PCPL_GLVC_SLEEP); 5677c478bd9Sstevel@tonic-gate } /* while trying the io operation */ 5687c478bd9Sstevel@tonic-gate 5697c478bd9Sstevel@tonic-gate if (n < 0) { 5707c478bd9Sstevel@tonic-gate rv = n; 5717c478bd9Sstevel@tonic-gate goto done; 5727c478bd9Sstevel@tonic-gate } 5737c478bd9Sstevel@tonic-gate rv += n; 5747c478bd9Sstevel@tonic-gate datap += n; 5757c478bd9Sstevel@tonic-gate } /* while still have more data */ 5767c478bd9Sstevel@tonic-gate 5777c478bd9Sstevel@tonic-gate done: 5787c478bd9Sstevel@tonic-gate if (rv == byte_cnt) 5797c478bd9Sstevel@tonic-gate return (0); 5807c478bd9Sstevel@tonic-gate else 5817c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * For peeking 'bytes_cnt' bytes in channel (glvc) buffers. 5867c478bd9Sstevel@tonic-gate * If data is available, the data is copied into 'buf'. 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate static int 5897c478bd9Sstevel@tonic-gate pcp_peek(uint8_t *buf, int bytes_cnt) 5907c478bd9Sstevel@tonic-gate { 5917c478bd9Sstevel@tonic-gate int ret; 5927c478bd9Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl; 5937c478bd9Sstevel@tonic-gate int n, m; 5947c478bd9Sstevel@tonic-gate 5957c478bd9Sstevel@tonic-gate if (bytes_cnt < 0 || bytes_cnt > mtu_size) { 5967c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 5977c478bd9Sstevel@tonic-gate } 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate /* 6007c478bd9Sstevel@tonic-gate * initialization of buffers used for peeking data in channel buffers. 6017c478bd9Sstevel@tonic-gate */ 6027c478bd9Sstevel@tonic-gate if (peek_area == NULL) { 6037c478bd9Sstevel@tonic-gate peek_area = (uint8_t *)umem_zalloc(PEEK_AREA_SIZE, 6047c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 6057c478bd9Sstevel@tonic-gate if (peek_area == NULL) { 6067c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate } 6097c478bd9Sstevel@tonic-gate 6107c478bd9Sstevel@tonic-gate /* 6117c478bd9Sstevel@tonic-gate * peek max MTU size bytes 6127c478bd9Sstevel@tonic-gate */ 6137c478bd9Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)peek_area; 6147c478bd9Sstevel@tonic-gate peek_ctrl.buflen = mtu_size; 6157c478bd9Sstevel@tonic-gate peek_ctrl.flags = 0; 6167c478bd9Sstevel@tonic-gate 6177c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 6187c478bd9Sstevel@tonic-gate 6197c478bd9Sstevel@tonic-gate if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, &peek_ctrl)) 6207c478bd9Sstevel@tonic-gate < 0) { 6217c478bd9Sstevel@tonic-gate (void) alarm(0); 6227c478bd9Sstevel@tonic-gate return (ret); 6237c478bd9Sstevel@tonic-gate } 6247c478bd9Sstevel@tonic-gate (void) alarm(0); 6257c478bd9Sstevel@tonic-gate 6267c478bd9Sstevel@tonic-gate n = peek_ctrl.buflen; 6277c478bd9Sstevel@tonic-gate 6287c478bd9Sstevel@tonic-gate if (n < 0) 6297c478bd9Sstevel@tonic-gate return (PCPL_GLVC_ERROR); 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * satisfy request as best as we can 6337c478bd9Sstevel@tonic-gate */ 6347c478bd9Sstevel@tonic-gate m = MIN(bytes_cnt, n); 6357c478bd9Sstevel@tonic-gate (void) memcpy(buf, peek_area, m); 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate return (m); 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * Function: write 'byte_cnt' bytes from 'buf' to channel. 6437c478bd9Sstevel@tonic-gate */ 6447c478bd9Sstevel@tonic-gate static int 6457c478bd9Sstevel@tonic-gate pcp_write(uint8_t *buf, int byte_cnt) 6467c478bd9Sstevel@tonic-gate { 6477c478bd9Sstevel@tonic-gate 6487c478bd9Sstevel@tonic-gate int ret; 6497c478bd9Sstevel@tonic-gate 6507c478bd9Sstevel@tonic-gate /* check for valid arguments */ 6517c478bd9Sstevel@tonic-gate if (buf == NULL || byte_cnt < 0 || byte_cnt > mtu_size) { 6527c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 6537c478bd9Sstevel@tonic-gate } 6547c478bd9Sstevel@tonic-gate 6557c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 6567c478bd9Sstevel@tonic-gate 6577c478bd9Sstevel@tonic-gate if ((ret = write(chnl_fd, buf, byte_cnt)) < 0) { 6587c478bd9Sstevel@tonic-gate (void) alarm(0); 6597c478bd9Sstevel@tonic-gate return (ret); 6607c478bd9Sstevel@tonic-gate } 6617c478bd9Sstevel@tonic-gate (void) alarm(0); 6627c478bd9Sstevel@tonic-gate 6637c478bd9Sstevel@tonic-gate return (ret); 6647c478bd9Sstevel@tonic-gate } 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate /* 6677c478bd9Sstevel@tonic-gate * In current implementaion of glvc driver, streams reads are not supported. 6687c478bd9Sstevel@tonic-gate * pcp_read mimics stream reads by first reading all the bytes present in the 6697c478bd9Sstevel@tonic-gate * channel buffer into a local buffer and from then on read requests 6707c478bd9Sstevel@tonic-gate * are serviced from local buffer. When read requests are not serviceble 6717c478bd9Sstevel@tonic-gate * from local buffer, it repeates by first reading data from channel buffers. 6727c478bd9Sstevel@tonic-gate * 6737c478bd9Sstevel@tonic-gate * This call may need to be enhanced when glvc supports buffered (stream) 6747c478bd9Sstevel@tonic-gate * reads - TBD 6757c478bd9Sstevel@tonic-gate */ 6767c478bd9Sstevel@tonic-gate 6777c478bd9Sstevel@tonic-gate static int 6787c478bd9Sstevel@tonic-gate pcp_read(uint8_t *buf, int byte_cnt) 6797c478bd9Sstevel@tonic-gate { 6807c478bd9Sstevel@tonic-gate int ret; 6817c478bd9Sstevel@tonic-gate int n, m, i; 6827c478bd9Sstevel@tonic-gate 6837c478bd9Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) { 6847c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 6857c478bd9Sstevel@tonic-gate } 6867c478bd9Sstevel@tonic-gate 6877c478bd9Sstevel@tonic-gate /* 6887c478bd9Sstevel@tonic-gate * initialization of local read buffer 6897c478bd9Sstevel@tonic-gate * from which the stream read requests are serviced. 6907c478bd9Sstevel@tonic-gate */ 6917c478bd9Sstevel@tonic-gate if (read_area == NULL) { 6927c478bd9Sstevel@tonic-gate read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE, 6937c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 6947c478bd9Sstevel@tonic-gate if (read_area == NULL) { 6957c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate read_head = read_area; 6987c478bd9Sstevel@tonic-gate read_tail = read_area; 6997c478bd9Sstevel@tonic-gate } 7007c478bd9Sstevel@tonic-gate 7017c478bd9Sstevel@tonic-gate /* 7027c478bd9Sstevel@tonic-gate * if we already read this data then copy from local buffer it self 7037c478bd9Sstevel@tonic-gate * without calling new read. 7047c478bd9Sstevel@tonic-gate */ 7057c478bd9Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) { 7067c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt); 7077c478bd9Sstevel@tonic-gate read_head += byte_cnt; 7087c478bd9Sstevel@tonic-gate return (byte_cnt); 7097c478bd9Sstevel@tonic-gate } 7107c478bd9Sstevel@tonic-gate 7117c478bd9Sstevel@tonic-gate /* 7127c478bd9Sstevel@tonic-gate * if the request is not satisfied from the buffered data, then move the 7137c478bd9Sstevel@tonic-gate * remaining data to front of the buffer and read new data. 7147c478bd9Sstevel@tonic-gate */ 7157c478bd9Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) { 7167c478bd9Sstevel@tonic-gate read_area[i] = read_head[i]; 7177c478bd9Sstevel@tonic-gate } 7187c478bd9Sstevel@tonic-gate read_head = read_area; 7197c478bd9Sstevel@tonic-gate read_tail = read_head + i; 7207c478bd9Sstevel@tonic-gate 7217c478bd9Sstevel@tonic-gate /* 7227c478bd9Sstevel@tonic-gate * do a peek to see how much data is available and read complete data. 7237c478bd9Sstevel@tonic-gate */ 7247c478bd9Sstevel@tonic-gate 7257c478bd9Sstevel@tonic-gate if ((m = pcp_peek(read_tail, mtu_size)) < 0) { 7267c478bd9Sstevel@tonic-gate return (m); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate (void) alarm(glvc_timeout); 7307c478bd9Sstevel@tonic-gate if ((ret = read(chnl_fd, read_tail, m)) < 0) { 7317c478bd9Sstevel@tonic-gate (void) alarm(0); 7327c478bd9Sstevel@tonic-gate return (ret); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate (void) alarm(0); 7367c478bd9Sstevel@tonic-gate read_tail += ret; 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate /* 7397c478bd9Sstevel@tonic-gate * copy the requested bytes. 7407c478bd9Sstevel@tonic-gate */ 7417c478bd9Sstevel@tonic-gate n = MIN(byte_cnt, (read_tail - read_head)); 7427c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, n); 7437c478bd9Sstevel@tonic-gate 7447c478bd9Sstevel@tonic-gate read_head += n; 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate return (n); 7477c478bd9Sstevel@tonic-gate } 7487c478bd9Sstevel@tonic-gate 7497c478bd9Sstevel@tonic-gate /* 7507c478bd9Sstevel@tonic-gate * This function is slight different from pcp_peek. The peek requests are first 7517c478bd9Sstevel@tonic-gate * serviced from local read buffer, if data is available. If the peek request 7527c478bd9Sstevel@tonic-gate * is not serviceble from local read buffer, then the data is peeked from 7537c478bd9Sstevel@tonic-gate * channel buffer. This function is mainly used for proper protocol framing 7547c478bd9Sstevel@tonic-gate * error handling. 7557c478bd9Sstevel@tonic-gate */ 7567c478bd9Sstevel@tonic-gate static int 7577c478bd9Sstevel@tonic-gate pcp_peek_read(uint8_t *buf, int byte_cnt) 7587c478bd9Sstevel@tonic-gate { 7597c478bd9Sstevel@tonic-gate int n, m, i; 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) { 7627c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate 7657c478bd9Sstevel@tonic-gate /* 7667c478bd9Sstevel@tonic-gate * initialization of peek_read buffer. 7677c478bd9Sstevel@tonic-gate */ 7687c478bd9Sstevel@tonic-gate if (peek_read_area == NULL) { 7697c478bd9Sstevel@tonic-gate peek_read_area = (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE, 7707c478bd9Sstevel@tonic-gate UMEM_DEFAULT); 7717c478bd9Sstevel@tonic-gate if (peek_read_area == NULL) { 7727c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 7737c478bd9Sstevel@tonic-gate } 7747c478bd9Sstevel@tonic-gate peek_read_head = peek_read_area; 7757c478bd9Sstevel@tonic-gate peek_read_tail = peek_read_area; 7767c478bd9Sstevel@tonic-gate } 7777c478bd9Sstevel@tonic-gate 7787c478bd9Sstevel@tonic-gate /* 7797c478bd9Sstevel@tonic-gate * if we already have the data in local read buffer then copy 7807c478bd9Sstevel@tonic-gate * from local buffer it self w/out calling new peek 7817c478bd9Sstevel@tonic-gate */ 7827c478bd9Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) { 7837c478bd9Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt); 7847c478bd9Sstevel@tonic-gate return (byte_cnt); 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate /* 7887c478bd9Sstevel@tonic-gate * if the request is not satisfied from local read buffer, then first 7897c478bd9Sstevel@tonic-gate * copy the remaining data in local read buffer to peek_read_area and 7907c478bd9Sstevel@tonic-gate * then issue new peek. 7917c478bd9Sstevel@tonic-gate */ 7927c478bd9Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) { 7937c478bd9Sstevel@tonic-gate peek_read_area[i] = read_head[i]; 7947c478bd9Sstevel@tonic-gate } 7957c478bd9Sstevel@tonic-gate peek_read_head = peek_read_area; 7967c478bd9Sstevel@tonic-gate peek_read_tail = peek_read_head + i; 7977c478bd9Sstevel@tonic-gate 7987c478bd9Sstevel@tonic-gate /* 7997c478bd9Sstevel@tonic-gate * do a peek to see how much data is available and read complete data. 8007c478bd9Sstevel@tonic-gate */ 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate if ((m = pcp_peek(peek_read_tail, mtu_size)) < 0) { 8037c478bd9Sstevel@tonic-gate return (m); 8047c478bd9Sstevel@tonic-gate } 8057c478bd9Sstevel@tonic-gate 8067c478bd9Sstevel@tonic-gate peek_read_tail += m; 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate /* 8097c478bd9Sstevel@tonic-gate * copy the requested bytes 8107c478bd9Sstevel@tonic-gate */ 8117c478bd9Sstevel@tonic-gate n = MIN(byte_cnt, (peek_read_tail - peek_read_head)); 8127c478bd9Sstevel@tonic-gate (void) memcpy(buf, peek_read_head, n); 8137c478bd9Sstevel@tonic-gate 8147c478bd9Sstevel@tonic-gate return (n); 8157c478bd9Sstevel@tonic-gate } 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* 8187c478bd9Sstevel@tonic-gate * Send Request Message Header. 8197c478bd9Sstevel@tonic-gate */ 8207c478bd9Sstevel@tonic-gate static int 8217c478bd9Sstevel@tonic-gate pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr) 8227c478bd9Sstevel@tonic-gate { 8237c478bd9Sstevel@tonic-gate pcp_req_msg_hdr_t *hdrp; 8247c478bd9Sstevel@tonic-gate int hdr_sz; 8257c478bd9Sstevel@tonic-gate int ret; 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate hdr_sz = sizeof (pcp_req_msg_hdr_t); 8287c478bd9Sstevel@tonic-gate if ((hdrp = (pcp_req_msg_hdr_t *)umem_zalloc(hdr_sz, 8297c478bd9Sstevel@tonic-gate UMEM_DEFAULT)) == NULL) { 8307c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 8317c478bd9Sstevel@tonic-gate } 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate hdrp->magic_num = htonl(req_hdr->magic_num); 8347c478bd9Sstevel@tonic-gate hdrp->proto_ver = req_hdr->proto_ver; 8357c478bd9Sstevel@tonic-gate hdrp->msg_type = req_hdr->msg_type; 8367c478bd9Sstevel@tonic-gate hdrp->sub_type = req_hdr->sub_type; 8377c478bd9Sstevel@tonic-gate hdrp->rsvd_pad = htons(req_hdr->rsvd_pad); 8387c478bd9Sstevel@tonic-gate hdrp->xid = htonl(req_hdr->xid); 8397c478bd9Sstevel@tonic-gate hdrp->timeout = htonl(req_hdr->timeout); 8407c478bd9Sstevel@tonic-gate hdrp->msg_len = htonl(req_hdr->msg_len); 8417c478bd9Sstevel@tonic-gate hdrp->msg_cksum = htons(req_hdr->msg_cksum); 8427c478bd9Sstevel@tonic-gate hdrp->hdr_cksum = htons(req_hdr->hdr_cksum); 8437c478bd9Sstevel@tonic-gate 8447c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op((char *)hdrp, hdr_sz, PCPL_IO_OP_WRITE)) != 0) { 8457c478bd9Sstevel@tonic-gate umem_free(hdrp, hdr_sz); 8467c478bd9Sstevel@tonic-gate return (ret); 8477c478bd9Sstevel@tonic-gate } 8487c478bd9Sstevel@tonic-gate umem_free(hdrp, hdr_sz); 8497c478bd9Sstevel@tonic-gate return (PCP_OK); 8507c478bd9Sstevel@tonic-gate } 8517c478bd9Sstevel@tonic-gate 8527c478bd9Sstevel@tonic-gate /* 8537c478bd9Sstevel@tonic-gate * Receive Response message header. 8547c478bd9Sstevel@tonic-gate */ 8557c478bd9Sstevel@tonic-gate static int 8567c478bd9Sstevel@tonic-gate pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr) 8577c478bd9Sstevel@tonic-gate { 8587c478bd9Sstevel@tonic-gate uint32_t magic_num; 8597c478bd9Sstevel@tonic-gate uint8_t proto_ver; 8607c478bd9Sstevel@tonic-gate uint8_t msg_type; 8617c478bd9Sstevel@tonic-gate uint8_t sub_type; 8627c478bd9Sstevel@tonic-gate uint8_t rsvd_pad; 8637c478bd9Sstevel@tonic-gate uint32_t xid; 8647c478bd9Sstevel@tonic-gate uint32_t timeout; 8657c478bd9Sstevel@tonic-gate uint32_t msg_len; 8667c478bd9Sstevel@tonic-gate uint32_t status; 8677c478bd9Sstevel@tonic-gate uint16_t msg_cksum; 8687c478bd9Sstevel@tonic-gate uint16_t hdr_cksum; 8697c478bd9Sstevel@tonic-gate int ret; 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate if (resp_hdr == NULL) { 8727c478bd9Sstevel@tonic-gate return (PCPL_INVALID_ARGS); 8737c478bd9Sstevel@tonic-gate } 8747c478bd9Sstevel@tonic-gate 8757c478bd9Sstevel@tonic-gate /* 8767c478bd9Sstevel@tonic-gate * handle protocol framing errors. 8777c478bd9Sstevel@tonic-gate * pcp_frame_error_handle() returns when proper frame arrived 8787c478bd9Sstevel@tonic-gate * (magic seq) or if an error happens while reading data from 8797c478bd9Sstevel@tonic-gate * channel. 8807c478bd9Sstevel@tonic-gate */ 8817c478bd9Sstevel@tonic-gate if ((ret = pcp_frame_error_handle()) != 0) 8827c478bd9Sstevel@tonic-gate return (PCPL_FRAME_ERROR); 8837c478bd9Sstevel@tonic-gate 8847c478bd9Sstevel@tonic-gate /* read magic number first */ 8857c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&magic_num, sizeof (magic_num), 8867c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 8877c478bd9Sstevel@tonic-gate return (ret); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate magic_num = ntohl(magic_num); 8917c478bd9Sstevel@tonic-gate 8927c478bd9Sstevel@tonic-gate if (magic_num != PCP_MAGIC_NUM) { 8937c478bd9Sstevel@tonic-gate return (PCPL_FRAME_ERROR); 8947c478bd9Sstevel@tonic-gate } 8957c478bd9Sstevel@tonic-gate 8967c478bd9Sstevel@tonic-gate /* read version field */ 8977c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&proto_ver, sizeof (proto_ver), 8987c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 8997c478bd9Sstevel@tonic-gate return (ret); 9007c478bd9Sstevel@tonic-gate } 9017c478bd9Sstevel@tonic-gate 9027c478bd9Sstevel@tonic-gate /* check protocol version */ 9037c478bd9Sstevel@tonic-gate if (proto_ver != PCP_PROT_VER_1) { 9047c478bd9Sstevel@tonic-gate return (PCPL_PROT_ERROR); 9057c478bd9Sstevel@tonic-gate } 9067c478bd9Sstevel@tonic-gate 9077c478bd9Sstevel@tonic-gate /* Read message type */ 9087c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_type, sizeof (msg_type), 9097c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9107c478bd9Sstevel@tonic-gate return (ret); 9117c478bd9Sstevel@tonic-gate } 9127c478bd9Sstevel@tonic-gate 9137c478bd9Sstevel@tonic-gate /* Read message sub type */ 9147c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&sub_type, sizeof (sub_type), 9157c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9167c478bd9Sstevel@tonic-gate return (ret); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate 9197c478bd9Sstevel@tonic-gate /* Read rcvd_pad bits */ 9207c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&rsvd_pad, sizeof (rsvd_pad), 9217c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9227c478bd9Sstevel@tonic-gate return (ret); 9237c478bd9Sstevel@tonic-gate } 9247c478bd9Sstevel@tonic-gate 9257c478bd9Sstevel@tonic-gate /* receive transaction id */ 9267c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&xid, sizeof (xid), 9277c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9287c478bd9Sstevel@tonic-gate return (ret); 9297c478bd9Sstevel@tonic-gate } 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate xid = ntohl(xid); 9327c478bd9Sstevel@tonic-gate 9337c478bd9Sstevel@tonic-gate /* receive timeout value */ 9347c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&timeout, sizeof (timeout), 9357c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9367c478bd9Sstevel@tonic-gate return (ret); 9377c478bd9Sstevel@tonic-gate } 9387c478bd9Sstevel@tonic-gate 9397c478bd9Sstevel@tonic-gate timeout = ntohl(timeout); 9407c478bd9Sstevel@tonic-gate 9417c478bd9Sstevel@tonic-gate /* receive message length */ 9427c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_len, sizeof (msg_len), 9437c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9447c478bd9Sstevel@tonic-gate return (ret); 9457c478bd9Sstevel@tonic-gate } 9467c478bd9Sstevel@tonic-gate 9477c478bd9Sstevel@tonic-gate msg_len = ntohl(msg_len); 9487c478bd9Sstevel@tonic-gate 9497c478bd9Sstevel@tonic-gate /* receive status field */ 9507c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&status, sizeof (status), 9517c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9527c478bd9Sstevel@tonic-gate return (ret); 9537c478bd9Sstevel@tonic-gate } 9547c478bd9Sstevel@tonic-gate 9557c478bd9Sstevel@tonic-gate status = ntohl(status); 9567c478bd9Sstevel@tonic-gate 9577c478bd9Sstevel@tonic-gate /* receive message checksum */ 9587c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_cksum, sizeof (msg_cksum), 9597c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9607c478bd9Sstevel@tonic-gate return (ret); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate 9637c478bd9Sstevel@tonic-gate msg_cksum = ntohs(msg_cksum); 9647c478bd9Sstevel@tonic-gate 9657c478bd9Sstevel@tonic-gate /* receive header checksum */ 9667c478bd9Sstevel@tonic-gate if ((ret = pcp_io_op(&hdr_cksum, sizeof (hdr_cksum), 9677c478bd9Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) { 9687c478bd9Sstevel@tonic-gate return (ret); 9697c478bd9Sstevel@tonic-gate } 9707c478bd9Sstevel@tonic-gate 9717c478bd9Sstevel@tonic-gate hdr_cksum = ntohs(hdr_cksum); 9727c478bd9Sstevel@tonic-gate 9737c478bd9Sstevel@tonic-gate /* copy to resp_hdr */ 9747c478bd9Sstevel@tonic-gate 9757c478bd9Sstevel@tonic-gate resp_hdr->magic_num = magic_num; 9767c478bd9Sstevel@tonic-gate resp_hdr->proto_ver = proto_ver; 9777c478bd9Sstevel@tonic-gate resp_hdr->msg_type = msg_type; 9787c478bd9Sstevel@tonic-gate resp_hdr->sub_type = sub_type; 9797c478bd9Sstevel@tonic-gate resp_hdr->rsvd_pad = rsvd_pad; 9807c478bd9Sstevel@tonic-gate resp_hdr->xid = xid; 9817c478bd9Sstevel@tonic-gate resp_hdr->timeout = timeout; 9827c478bd9Sstevel@tonic-gate resp_hdr->msg_len = msg_len; 9837c478bd9Sstevel@tonic-gate resp_hdr->status = status; 9847c478bd9Sstevel@tonic-gate resp_hdr->msg_cksum = msg_cksum; 9857c478bd9Sstevel@tonic-gate resp_hdr->hdr_cksum = hdr_cksum; 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate return (PCP_OK); 9887c478bd9Sstevel@tonic-gate } 9897c478bd9Sstevel@tonic-gate 9907c478bd9Sstevel@tonic-gate /* 9917c478bd9Sstevel@tonic-gate * Get next xid for including in request message. 9927c478bd9Sstevel@tonic-gate * Every request and response message are matched 9937c478bd9Sstevel@tonic-gate * for same xid. 9947c478bd9Sstevel@tonic-gate */ 9957c478bd9Sstevel@tonic-gate static int pcp_get_xid(void) 9967c478bd9Sstevel@tonic-gate { 9977c478bd9Sstevel@tonic-gate uint32_t ret; 9987c478bd9Sstevel@tonic-gate 9997c478bd9Sstevel@tonic-gate ret = msg_xid; 10007c478bd9Sstevel@tonic-gate if (msg_xid == PCPL_MAX_XID) 10017c478bd9Sstevel@tonic-gate msg_xid = PCPL_MIN_XID; 10027c478bd9Sstevel@tonic-gate else 10037c478bd9Sstevel@tonic-gate ++msg_xid; 10047c478bd9Sstevel@tonic-gate return (ret); 10057c478bd9Sstevel@tonic-gate } 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate /* 10087c478bd9Sstevel@tonic-gate * This function handles channel framing errors. It waits until proper 10097c478bd9Sstevel@tonic-gate * frame with starting sequence as magic numder (0xAFBCAFA0) 10107c478bd9Sstevel@tonic-gate * is arrived. It removes unexpected data (before the magic number sequence) 10117c478bd9Sstevel@tonic-gate * on the channel. It returns when proper magic number sequence is seen 10127c478bd9Sstevel@tonic-gate * or when any failure happens while reading/peeking the channel. 10137c478bd9Sstevel@tonic-gate */ 10147c478bd9Sstevel@tonic-gate static int 10157c478bd9Sstevel@tonic-gate pcp_frame_error_handle(void) 10167c478bd9Sstevel@tonic-gate { 10177c478bd9Sstevel@tonic-gate uint8_t magic_num_buf[4]; 10187c478bd9Sstevel@tonic-gate int ispresent = 0; 10197c478bd9Sstevel@tonic-gate uint32_t net_magic_num; /* magic byte in network byte order */ 10207c478bd9Sstevel@tonic-gate uint32_t host_magic_num = PCP_MAGIC_NUM; 10217c478bd9Sstevel@tonic-gate uint8_t buf[2]; 10227c478bd9Sstevel@tonic-gate 10237c478bd9Sstevel@tonic-gate net_magic_num = htonl(host_magic_num); 10247c478bd9Sstevel@tonic-gate (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4); 10257c478bd9Sstevel@tonic-gate 10267c478bd9Sstevel@tonic-gate while (!ispresent) { 10277c478bd9Sstevel@tonic-gate /* 10287c478bd9Sstevel@tonic-gate * Check if next four bytes matches pcp magic number. 10297c478bd9Sstevel@tonic-gate * if mathing not found, discard 1 byte and continue checking. 10307c478bd9Sstevel@tonic-gate */ 10317c478bd9Sstevel@tonic-gate if (!check_magic_byte_presence(4, &magic_num_buf[0], 10327c478bd9Sstevel@tonic-gate &ispresent)) { 10337c478bd9Sstevel@tonic-gate if (!ispresent) { 10347c478bd9Sstevel@tonic-gate /* remove 1 byte */ 10357c478bd9Sstevel@tonic-gate (void) pcp_io_op(buf, 1, PCPL_IO_OP_READ); 10367c478bd9Sstevel@tonic-gate } 10377c478bd9Sstevel@tonic-gate } else { 10387c478bd9Sstevel@tonic-gate return (-1); 10397c478bd9Sstevel@tonic-gate } 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate return (0); 10437c478bd9Sstevel@tonic-gate } 10447c478bd9Sstevel@tonic-gate 10457c478bd9Sstevel@tonic-gate /* 10467c478bd9Sstevel@tonic-gate * checks whether certain byte sequence is present in the data stream. 10477c478bd9Sstevel@tonic-gate */ 10487c478bd9Sstevel@tonic-gate static int 10497c478bd9Sstevel@tonic-gate check_magic_byte_presence(int byte_cnt, uint8_t *byte_seq, int *ispresent) 10507c478bd9Sstevel@tonic-gate { 10517c478bd9Sstevel@tonic-gate int ret, i; 10527c478bd9Sstevel@tonic-gate uint8_t buf[4]; 10537c478bd9Sstevel@tonic-gate 10547c478bd9Sstevel@tonic-gate if ((ret = pcp_peek_read(buf, byte_cnt)) < 0) { 10557c478bd9Sstevel@tonic-gate return (ret); 10567c478bd9Sstevel@tonic-gate } 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate /* 'byte_cnt' bytes not present */ 10597c478bd9Sstevel@tonic-gate if (ret != byte_cnt) { 10607c478bd9Sstevel@tonic-gate *ispresent = 0; 10617c478bd9Sstevel@tonic-gate return (0); 10627c478bd9Sstevel@tonic-gate } 10637c478bd9Sstevel@tonic-gate 10647c478bd9Sstevel@tonic-gate for (i = 0; i < byte_cnt; ++i) { 10657c478bd9Sstevel@tonic-gate if (buf[i] != byte_seq[i]) { 10667c478bd9Sstevel@tonic-gate *ispresent = 0; 10677c478bd9Sstevel@tonic-gate return (0); 10687c478bd9Sstevel@tonic-gate } 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate *ispresent = 1; 10717c478bd9Sstevel@tonic-gate 10727c478bd9Sstevel@tonic-gate return (0); 10737c478bd9Sstevel@tonic-gate } 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * 16-bit simple internet checksum 10777c478bd9Sstevel@tonic-gate */ 10787c478bd9Sstevel@tonic-gate static uint16_t 10797c478bd9Sstevel@tonic-gate checksum(uint16_t *addr, int32_t count) 10807c478bd9Sstevel@tonic-gate { 10817c478bd9Sstevel@tonic-gate /* 10827c478bd9Sstevel@tonic-gate * Compute Internet Checksum for "count" bytes 10837c478bd9Sstevel@tonic-gate * beginning at location "addr". 10847c478bd9Sstevel@tonic-gate */ 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate register uint32_t sum = 0; 10877c478bd9Sstevel@tonic-gate 10887c478bd9Sstevel@tonic-gate while (count > 1) { 10897c478bd9Sstevel@tonic-gate /* This is the inner loop */ 10907c478bd9Sstevel@tonic-gate sum += *(unsigned short *)addr++; 10917c478bd9Sstevel@tonic-gate count -= 2; 10927c478bd9Sstevel@tonic-gate } 10937c478bd9Sstevel@tonic-gate 10947c478bd9Sstevel@tonic-gate /* Add left-over byte, if any */ 10957c478bd9Sstevel@tonic-gate if (count > 0) 10967c478bd9Sstevel@tonic-gate sum += * (unsigned char *)addr; 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate /* Fold 32-bit sum to 16 bits */ 10997c478bd9Sstevel@tonic-gate while (sum >> 16) 11007c478bd9Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16); 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate sum = (~sum) & 0xffff; 11037c478bd9Sstevel@tonic-gate if (sum == 0) 11047c478bd9Sstevel@tonic-gate sum = 0xffff; 11057c478bd9Sstevel@tonic-gate 11067c478bd9Sstevel@tonic-gate return (sum); 11077c478bd9Sstevel@tonic-gate } 11087c478bd9Sstevel@tonic-gate 11097c478bd9Sstevel@tonic-gate /* 11107c478bd9Sstevel@tonic-gate * cleanup the channel if any data is hanging in 11117c478bd9Sstevel@tonic-gate * channel buffers. 11127c478bd9Sstevel@tonic-gate */ 11137c478bd9Sstevel@tonic-gate static int 11145db09ef5Smvgr pcp_cleanup(int channel_fd) 11157c478bd9Sstevel@tonic-gate { 11167c478bd9Sstevel@tonic-gate int ret; 11177c478bd9Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl; 11187c478bd9Sstevel@tonic-gate int n, done; 11197c478bd9Sstevel@tonic-gate uint8_t *buf = NULL; 11207c478bd9Sstevel@tonic-gate int retry = 0; 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate buf = (uint8_t *)umem_zalloc((mtu_size), UMEM_DEFAULT); 11247c478bd9Sstevel@tonic-gate if (buf == NULL) { 11257c478bd9Sstevel@tonic-gate return (PCPL_MALLOC_FAIL); 11267c478bd9Sstevel@tonic-gate } 11277c478bd9Sstevel@tonic-gate 11287c478bd9Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)buf; 11297c478bd9Sstevel@tonic-gate peek_ctrl.buflen = mtu_size; 11307c478bd9Sstevel@tonic-gate peek_ctrl.flags = 0; 11317c478bd9Sstevel@tonic-gate 11327c478bd9Sstevel@tonic-gate /* 11337c478bd9Sstevel@tonic-gate * set sig jmp location 11347c478bd9Sstevel@tonic-gate */ 11357c478bd9Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) { 11367c478bd9Sstevel@tonic-gate umem_free(buf, mtu_size); 11377c478bd9Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT); 11387c478bd9Sstevel@tonic-gate } 11397c478bd9Sstevel@tonic-gate 11407c478bd9Sstevel@tonic-gate done = 0; 11417c478bd9Sstevel@tonic-gate while (!done) { 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT); 11445db09ef5Smvgr if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_DATA_PEEK, 11457c478bd9Sstevel@tonic-gate &peek_ctrl)) < 0) { 11467c478bd9Sstevel@tonic-gate (void) alarm(0); 11477c478bd9Sstevel@tonic-gate done = 1; 11487c478bd9Sstevel@tonic-gate continue; 11497c478bd9Sstevel@tonic-gate } 11507c478bd9Sstevel@tonic-gate (void) alarm(0); 11517c478bd9Sstevel@tonic-gate 11527c478bd9Sstevel@tonic-gate n = peek_ctrl.buflen; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate if (n <= 0 && retry > 2) { 11557c478bd9Sstevel@tonic-gate done = 1; 11567c478bd9Sstevel@tonic-gate continue; 11577c478bd9Sstevel@tonic-gate } else if (n <= 0) { 11587c478bd9Sstevel@tonic-gate ++retry; 11597c478bd9Sstevel@tonic-gate continue; 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate 11627c478bd9Sstevel@tonic-gate /* remove data from channel */ 11637c478bd9Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT); 11645db09ef5Smvgr if ((ret = read(channel_fd, buf, n)) < 0) { 11657c478bd9Sstevel@tonic-gate (void) alarm(0); 11667c478bd9Sstevel@tonic-gate done = 1; 11677c478bd9Sstevel@tonic-gate continue; 11687c478bd9Sstevel@tonic-gate } 11697c478bd9Sstevel@tonic-gate (void) alarm(0); 11707c478bd9Sstevel@tonic-gate } 11717c478bd9Sstevel@tonic-gate 11727c478bd9Sstevel@tonic-gate umem_free(buf, mtu_size); 11737c478bd9Sstevel@tonic-gate return (ret); 11747c478bd9Sstevel@tonic-gate } 1175