10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51991Sheppo * Common Development and Distribution License (the "License").
61991Sheppo * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*6408Sha137994 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * Platform Channel Protocol Library functions on Nigara platforms
280Sstevel@tonic-gate * (Ontario, Erie, etc..) Solaris applications use these interfaces
290Sstevel@tonic-gate * to communicate with entities that reside on service processor.
300Sstevel@tonic-gate */
310Sstevel@tonic-gate
320Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
330Sstevel@tonic-gate
340Sstevel@tonic-gate #include <stdio.h>
350Sstevel@tonic-gate #include <stdlib.h>
360Sstevel@tonic-gate #include <unistd.h>
370Sstevel@tonic-gate #include <string.h>
380Sstevel@tonic-gate #include <assert.h>
390Sstevel@tonic-gate #include <fcntl.h>
400Sstevel@tonic-gate #include <errno.h>
410Sstevel@tonic-gate #include <signal.h>
420Sstevel@tonic-gate #include <setjmp.h>
430Sstevel@tonic-gate #include <inttypes.h>
440Sstevel@tonic-gate #include <umem.h>
450Sstevel@tonic-gate #include <strings.h>
46293Smvgr #include <time.h>
470Sstevel@tonic-gate #include <sys/types.h>
480Sstevel@tonic-gate #include <sys/stat.h>
490Sstevel@tonic-gate #include <sys/glvc.h>
501991Sheppo #include <sys/vldc.h>
511991Sheppo #include <sys/ldc.h>
520Sstevel@tonic-gate #include <netinet/in.h>
530Sstevel@tonic-gate
540Sstevel@tonic-gate #include "libpcp.h"
550Sstevel@tonic-gate #include "pcp_common.h"
562531Snarayan #include "pcp_utils.h"
572531Snarayan
580Sstevel@tonic-gate
590Sstevel@tonic-gate /*
600Sstevel@tonic-gate * Following libpcp interfaces are exposed to user applications.
610Sstevel@tonic-gate *
62126Smvgr * int pcp_init(char *channel_name);
63126Smvgr * int pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg,
64126Smvgr * uint32_t timeout);
65126Smvgr * int pcp_close(int channel_fd);
660Sstevel@tonic-gate *
670Sstevel@tonic-gate */
680Sstevel@tonic-gate
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate * Forward declarations.
710Sstevel@tonic-gate */
720Sstevel@tonic-gate static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr);
730Sstevel@tonic-gate static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr);
740Sstevel@tonic-gate static int pcp_io_op(void *buf, int byte_cnt, int io_op);
75293Smvgr static uint32_t pcp_get_xid(void);
76126Smvgr static int pcp_get_prop(int channel_fd, int prop, unsigned int *val);
770Sstevel@tonic-gate static int pcp_read(uint8_t *buf, int buf_len);
780Sstevel@tonic-gate static int pcp_write(uint8_t *buf, int buf_len);
790Sstevel@tonic-gate static int pcp_peek(uint8_t *buf, int buf_len);
800Sstevel@tonic-gate static int pcp_peek_read(uint8_t *buf, int buf_len);
810Sstevel@tonic-gate static int pcp_frame_error_handle(void);
820Sstevel@tonic-gate static int check_magic_byte_presence(int byte_cnt, uint8_t *byte_val,
830Sstevel@tonic-gate int *ispresent);
840Sstevel@tonic-gate static uint16_t checksum(uint16_t *addr, int32_t count);
85126Smvgr static int pcp_cleanup(int channel_fd);
860Sstevel@tonic-gate
871991Sheppo static int vldc_read(int fd, uint8_t *bufp, int size);
881991Sheppo static int vldc_write(int fd, uint8_t *bufp, int size);
891991Sheppo static int pcp_update_read_area(int byte_cnt);
901991Sheppo static int pcp_vldc_frame_error_handle(void);
911991Sheppo
920Sstevel@tonic-gate /*
93126Smvgr * local channel (glvc) file descriptor set by pcp_send_recv()
940Sstevel@tonic-gate */
950Sstevel@tonic-gate static int chnl_fd = -1;
960Sstevel@tonic-gate
970Sstevel@tonic-gate /*
980Sstevel@tonic-gate * Message Transaction ID
990Sstevel@tonic-gate */
1000Sstevel@tonic-gate static uint32_t msg_xid = 0;
1010Sstevel@tonic-gate
1020Sstevel@tonic-gate /*
1030Sstevel@tonic-gate * Channel MTU size.
1040Sstevel@tonic-gate */
1050Sstevel@tonic-gate static unsigned int mtu_size = PCPL_DEF_MTU_SZ;
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /*
1080Sstevel@tonic-gate * timeout field is supplied by user. timeout field is used to decide
1090Sstevel@tonic-gate * how long to block on glvc driver calls before we return timeout error
1100Sstevel@tonic-gate * to user applications.
1110Sstevel@tonic-gate *
1120Sstevel@tonic-gate * Note: In the current implementation of glvc driver, all glvc calls are
1130Sstevel@tonic-gate * blocking.
1140Sstevel@tonic-gate */
1150Sstevel@tonic-gate static uint32_t glvc_timeout = 0;
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate /*
1180Sstevel@tonic-gate * variables used by setsetjmp/siglongjmp.
1190Sstevel@tonic-gate */
1200Sstevel@tonic-gate static volatile sig_atomic_t jumpok = 0;
1210Sstevel@tonic-gate static sigjmp_buf jmpbuf;
1220Sstevel@tonic-gate
1230Sstevel@tonic-gate /*
1240Sstevel@tonic-gate * To unblock SIGALRM signal incase if it's blocked in libpcp user apps.
1250Sstevel@tonic-gate * Restore it to old state during pcp_close.
1260Sstevel@tonic-gate */
1270Sstevel@tonic-gate static sigset_t blkset;
1280Sstevel@tonic-gate
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate * Buffers used for stream reading channel data. When data is read in
1310Sstevel@tonic-gate * stream fashion, first data is copied from channel (glvc) buffers to
1320Sstevel@tonic-gate * these local buffers from which the read requests are serviced.
1330Sstevel@tonic-gate */
1340Sstevel@tonic-gate #define READ_AREA_SIZE (2*mtu_size)
1350Sstevel@tonic-gate static uint8_t *read_head = NULL;
1360Sstevel@tonic-gate static uint8_t *read_tail = NULL;
1370Sstevel@tonic-gate static uint8_t *read_area = NULL;
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate /*
1400Sstevel@tonic-gate * Buffer used for peeking new data available in channel (glvc) buffers.
1410Sstevel@tonic-gate */
1420Sstevel@tonic-gate #define PEEK_AREA_SIZE (mtu_size)
1430Sstevel@tonic-gate static uint8_t *peek_area = NULL;
1440Sstevel@tonic-gate
1450Sstevel@tonic-gate /*
1460Sstevel@tonic-gate * Buffers used for peeking data available either in local buffers or
1470Sstevel@tonic-gate * new data available in channel (glvc) buffers.
1480Sstevel@tonic-gate */
1490Sstevel@tonic-gate #define PEEK_READ_AREA_SIZE (2*mtu_size)
1500Sstevel@tonic-gate static uint8_t *peek_read_head = NULL;
1510Sstevel@tonic-gate static uint8_t *peek_read_tail = NULL;
1520Sstevel@tonic-gate static uint8_t *peek_read_area = NULL;
1530Sstevel@tonic-gate
1540Sstevel@tonic-gate static pcp_req_msg_hdr_t *req_msg_hdr = NULL;
1550Sstevel@tonic-gate static pcp_resp_msg_hdr_t *resp_msg_hdr = NULL;
1560Sstevel@tonic-gate static int req_msg_hdr_sz = 0;
1570Sstevel@tonic-gate static int resp_msg_hdr_sz = 0;
1580Sstevel@tonic-gate
1590Sstevel@tonic-gate /*
1600Sstevel@tonic-gate * signal handling variables to handle glvc blocking calls.
1610Sstevel@tonic-gate */
1620Sstevel@tonic-gate static struct sigaction glvc_act;
1630Sstevel@tonic-gate
1640Sstevel@tonic-gate /* To restore old SIGALRM signal handler */
1650Sstevel@tonic-gate static struct sigaction old_act;
1660Sstevel@tonic-gate
1671991Sheppo /*
1681991Sheppo * Variables to support vldc based streaming transport
1691991Sheppo */
1702531Snarayan static pcp_xport_t xport_type = GLVC_NON_STREAM;
1711991Sheppo #define VLDC_MTU_SIZE (2048)
1721991Sheppo
1730Sstevel@tonic-gate static void
glvc_timeout_handler(void)1740Sstevel@tonic-gate glvc_timeout_handler(void)
1750Sstevel@tonic-gate {
1760Sstevel@tonic-gate if (jumpok == 0)
1770Sstevel@tonic-gate return;
1780Sstevel@tonic-gate siglongjmp(jmpbuf, 1);
1790Sstevel@tonic-gate }
1800Sstevel@tonic-gate
1810Sstevel@tonic-gate /*
1820Sstevel@tonic-gate * Initialize the virtual channel. It basically opens the virtual channel
1830Sstevel@tonic-gate * provided by the host application.
1840Sstevel@tonic-gate *
1850Sstevel@tonic-gate */
1860Sstevel@tonic-gate
1870Sstevel@tonic-gate int
pcp_init(char * channel_name)188126Smvgr pcp_init(char *channel_name)
1890Sstevel@tonic-gate {
1900Sstevel@tonic-gate sigset_t oldset;
191126Smvgr int channel_fd;
1922531Snarayan char *dev_path;
1932531Snarayan vldc_opt_op_t op;
1940Sstevel@tonic-gate
195126Smvgr if (channel_name == NULL)
1960Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
1971991Sheppo
1980Sstevel@tonic-gate /*
1992531Snarayan * Given the argument, try to locate a device in the device tree
2002531Snarayan */
2012531Snarayan dev_path = platsvc_name_to_path(channel_name, &xport_type);
2022531Snarayan
2032531Snarayan /*
2042531Snarayan * Path exists ?
2052531Snarayan */
2062531Snarayan if (NULL == dev_path)
2072531Snarayan return (PCPL_INVALID_ARGS);
2082531Snarayan
2092531Snarayan /*
210126Smvgr * Open virtual channel name.
2110Sstevel@tonic-gate */
2122531Snarayan if ((channel_fd = open(dev_path, O_RDWR|O_EXCL)) < 0) {
2132531Snarayan free(dev_path);
2140Sstevel@tonic-gate return (PCPL_GLVC_ERROR);
2150Sstevel@tonic-gate }
2160Sstevel@tonic-gate
2172531Snarayan free(dev_path);
2182531Snarayan
2190Sstevel@tonic-gate /*
2202531Snarayan * Handle transport-specific processing
2210Sstevel@tonic-gate */
2222531Snarayan switch (xport_type) {
2232531Snarayan case VLDC_STREAMING:
2241991Sheppo mtu_size = VLDC_MTU_SIZE;
2250Sstevel@tonic-gate
2261991Sheppo op.op_sel = VLDC_OP_SET;
2271991Sheppo op.opt_sel = VLDC_OPT_MODE;
228*6408Sha137994 op.opt_val = LDC_MODE_RELIABLE;
2291991Sheppo if (ioctl(channel_fd, VLDC_IOCTL_OPT_OP, &op) != 0) {
2301991Sheppo (void) close(channel_fd);
2311991Sheppo return (PCPL_GLVC_ERROR);
2321991Sheppo }
2332531Snarayan break;
2342531Snarayan case GLVC_NON_STREAM:
2352531Snarayan default:
2361991Sheppo /*
2371991Sheppo * Get the Channel MTU size
2381991Sheppo */
2391991Sheppo
2401991Sheppo if (pcp_get_prop(channel_fd, GLVC_XPORT_OPT_MTU_SZ,
2412531Snarayan &mtu_size) != 0) {
2421991Sheppo (void) close(channel_fd);
2431991Sheppo return (PCPL_GLVC_ERROR);
2441991Sheppo }
2452531Snarayan break;
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate * Get current signal mask. If SIGALRM is blocked
2500Sstevel@tonic-gate * unblock it.
2510Sstevel@tonic-gate */
2520Sstevel@tonic-gate (void) sigprocmask(0, NULL, &oldset);
2530Sstevel@tonic-gate
2540Sstevel@tonic-gate (void) sigemptyset(&blkset);
2550Sstevel@tonic-gate
2560Sstevel@tonic-gate if (sigismember(&oldset, SIGALRM)) {
2570Sstevel@tonic-gate (void) sigaddset(&blkset, SIGALRM);
2580Sstevel@tonic-gate (void) sigprocmask(SIG_UNBLOCK, &blkset, NULL);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate /*
2610Sstevel@tonic-gate * signal handler initialization to handle glvc call timeouts.
2620Sstevel@tonic-gate */
2630Sstevel@tonic-gate glvc_act.sa_handler = glvc_timeout_handler;
2640Sstevel@tonic-gate (void) sigemptyset(&glvc_act.sa_mask);
2650Sstevel@tonic-gate glvc_act.sa_flags = SA_NODEFER;
2660Sstevel@tonic-gate
2670Sstevel@tonic-gate if (sigaction(SIGALRM, &glvc_act, &old_act) < 0) {
268126Smvgr (void) close(channel_fd);
2690Sstevel@tonic-gate return (PCPL_ERROR);
2700Sstevel@tonic-gate }
2710Sstevel@tonic-gate
272126Smvgr return (channel_fd);
2730Sstevel@tonic-gate }
2740Sstevel@tonic-gate
2750Sstevel@tonic-gate /*
2760Sstevel@tonic-gate * Function: Close platform channel.
277126Smvgr * Arguments:
278126Smvgr * int channel_fd - channel file descriptor.
2790Sstevel@tonic-gate * Returns:
2800Sstevel@tonic-gate * always returns PCPL_OK for now.
2810Sstevel@tonic-gate */
2820Sstevel@tonic-gate int
pcp_close(int channel_fd)283126Smvgr pcp_close(int channel_fd)
2840Sstevel@tonic-gate {
2850Sstevel@tonic-gate
286126Smvgr if (channel_fd >= 0) {
2871991Sheppo if (xport_type == GLVC_NON_STREAM)
2881991Sheppo (void) pcp_cleanup(channel_fd);
289126Smvgr (void) close(channel_fd);
290126Smvgr } else {
291126Smvgr return (-1);
2920Sstevel@tonic-gate }
2930Sstevel@tonic-gate
2940Sstevel@tonic-gate /*
2950Sstevel@tonic-gate * free global buffers
2960Sstevel@tonic-gate */
2970Sstevel@tonic-gate if (read_area != NULL) {
2980Sstevel@tonic-gate umem_free(read_area, READ_AREA_SIZE);
2990Sstevel@tonic-gate read_area = NULL;
3000Sstevel@tonic-gate }
3010Sstevel@tonic-gate if (peek_area != NULL) {
3020Sstevel@tonic-gate umem_free(peek_area, PEEK_AREA_SIZE);
3030Sstevel@tonic-gate peek_area = NULL;
3040Sstevel@tonic-gate }
3050Sstevel@tonic-gate if (peek_read_area != NULL) {
3060Sstevel@tonic-gate umem_free(peek_read_area, PEEK_READ_AREA_SIZE);
3070Sstevel@tonic-gate peek_read_area = NULL;
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate if (req_msg_hdr != NULL) {
3100Sstevel@tonic-gate umem_free(req_msg_hdr, req_msg_hdr_sz);
3110Sstevel@tonic-gate req_msg_hdr = NULL;
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate if (resp_msg_hdr != NULL) {
3140Sstevel@tonic-gate umem_free(resp_msg_hdr, resp_msg_hdr_sz);
3150Sstevel@tonic-gate resp_msg_hdr = NULL;
3160Sstevel@tonic-gate }
3170Sstevel@tonic-gate
3180Sstevel@tonic-gate /*
3190Sstevel@tonic-gate * Restore SIGALRM signal mask incase if we unblocked
3200Sstevel@tonic-gate * it during pcp_init.
3210Sstevel@tonic-gate */
3220Sstevel@tonic-gate if (sigismember(&blkset, SIGALRM)) {
3230Sstevel@tonic-gate (void) sigprocmask(SIG_BLOCK, &blkset, NULL);
3240Sstevel@tonic-gate }
3250Sstevel@tonic-gate
3260Sstevel@tonic-gate /* Restore SIGALRM signal handler */
3270Sstevel@tonic-gate (void) sigaction(SIGALRM, &old_act, NULL);
3280Sstevel@tonic-gate
3290Sstevel@tonic-gate return (PCPL_OK);
3300Sstevel@tonic-gate }
3310Sstevel@tonic-gate
3320Sstevel@tonic-gate /*
3330Sstevel@tonic-gate * Function: Send and Receive messages on platform channel.
3340Sstevel@tonic-gate * Arguments:
335126Smvgr * int channel_fd - channel file descriptor.
3360Sstevel@tonic-gate * pcp_msg_t *req_msg - Request Message to send to other end of channel.
3370Sstevel@tonic-gate * pcp_msg_t *resp_msg - Response Message to be received.
3380Sstevel@tonic-gate * uint32_t timeout - timeout field when waiting for data from channel.
3390Sstevel@tonic-gate * Returns:
3400Sstevel@tonic-gate * 0 - success (PCPL_OK).
3410Sstevel@tonic-gate * (-ve) - failure:
3420Sstevel@tonic-gate * PCPL_INVALID_ARGS - invalid args.
3430Sstevel@tonic-gate * PCPL_GLVC_TIMEOUT - glvc call timeout.
3440Sstevel@tonic-gate * PCPL_XPORT_ERROR - transport error in request message
3450Sstevel@tonic-gate * noticed by receiver.
3460Sstevel@tonic-gate * PCPL_MALLOC_FAIL - malloc failure.
3470Sstevel@tonic-gate * PCPL_CKSUM_ERROR - checksum error.
3480Sstevel@tonic-gate */
3490Sstevel@tonic-gate int
pcp_send_recv(int channel_fd,pcp_msg_t * req_msg,pcp_msg_t * resp_msg,uint32_t timeout)350126Smvgr pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg,
351126Smvgr uint32_t timeout)
3520Sstevel@tonic-gate {
3530Sstevel@tonic-gate void *datap;
3540Sstevel@tonic-gate void *resp_msg_data = NULL;
3550Sstevel@tonic-gate uint32_t status;
3560Sstevel@tonic-gate uint16_t cksum = 0;
3570Sstevel@tonic-gate int ret;
3580Sstevel@tonic-gate int resp_hdr_ok;
3590Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE
3600Sstevel@tonic-gate uint16_t bkup_resp_hdr_cksum;
3610Sstevel@tonic-gate #endif
362126Smvgr if (channel_fd < 0) {
3630Sstevel@tonic-gate return (PCPL_ERROR);
3640Sstevel@tonic-gate }
3650Sstevel@tonic-gate
366126Smvgr /* copy channel_fd to local fd (chnl_fd) for other functions use */
367126Smvgr chnl_fd = channel_fd;
368126Smvgr
3690Sstevel@tonic-gate if (req_msg == NULL) {
3700Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
3710Sstevel@tonic-gate }
3720Sstevel@tonic-gate
3730Sstevel@tonic-gate if (timeout > 0)
3740Sstevel@tonic-gate glvc_timeout = timeout;
3750Sstevel@tonic-gate else
3760Sstevel@tonic-gate glvc_timeout = 0;
3770Sstevel@tonic-gate
378194Smvgr if ((req_msg->msg_len != 0) && ((datap = req_msg->msg_data) == NULL))
3790Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
3800Sstevel@tonic-gate
3810Sstevel@tonic-gate if (req_msg_hdr == NULL) {
3820Sstevel@tonic-gate req_msg_hdr_sz = sizeof (pcp_req_msg_hdr_t);
3830Sstevel@tonic-gate req_msg_hdr = (pcp_req_msg_hdr_t *)umem_zalloc(req_msg_hdr_sz,
3840Sstevel@tonic-gate UMEM_DEFAULT);
3850Sstevel@tonic-gate if (req_msg_hdr == NULL)
3860Sstevel@tonic-gate return (PCPL_MALLOC_FAIL);
3870Sstevel@tonic-gate }
3880Sstevel@tonic-gate
389126Smvgr if (req_msg->msg_len != 0) {
390126Smvgr /* calculate request msg_cksum */
391126Smvgr cksum = checksum((uint16_t *)datap, req_msg->msg_len);
392126Smvgr }
3930Sstevel@tonic-gate
3940Sstevel@tonic-gate /*
3950Sstevel@tonic-gate * Fill in the message header for the request packet
3960Sstevel@tonic-gate */
3970Sstevel@tonic-gate req_msg_hdr->magic_num = PCP_MAGIC_NUM;
3980Sstevel@tonic-gate req_msg_hdr->proto_ver = PCP_PROT_VER_1;
3990Sstevel@tonic-gate req_msg_hdr->msg_type = req_msg->msg_type;
4000Sstevel@tonic-gate req_msg_hdr->sub_type = req_msg->sub_type;
4010Sstevel@tonic-gate req_msg_hdr->rsvd_pad = 0;
4020Sstevel@tonic-gate req_msg_hdr->xid = pcp_get_xid();
4030Sstevel@tonic-gate req_msg_hdr->msg_len = req_msg->msg_len;
4040Sstevel@tonic-gate req_msg_hdr->timeout = timeout;
4050Sstevel@tonic-gate req_msg_hdr->msg_cksum = cksum;
4060Sstevel@tonic-gate req_msg_hdr->hdr_cksum = 0;
4070Sstevel@tonic-gate
4080Sstevel@tonic-gate /* fill request header checksum */
4090Sstevel@tonic-gate req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr,
4100Sstevel@tonic-gate req_msg_hdr_sz);
4110Sstevel@tonic-gate /*
4120Sstevel@tonic-gate * set sig jmp location
4130Sstevel@tonic-gate */
4140Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) {
4150Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT);
4160Sstevel@tonic-gate }
4170Sstevel@tonic-gate jumpok = 1; /* monitor sigalrm from now on */
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate /*
4200Sstevel@tonic-gate * send request message header
4210Sstevel@tonic-gate */
4220Sstevel@tonic-gate if ((ret = pcp_send_req_msg_hdr(req_msg_hdr))) {
4230Sstevel@tonic-gate
4240Sstevel@tonic-gate return (ret);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate /*
4280Sstevel@tonic-gate * send request message
4290Sstevel@tonic-gate */
430126Smvgr if (req_msg->msg_len != 0) {
431126Smvgr if ((ret = pcp_io_op(datap, req_msg->msg_len,
4320Sstevel@tonic-gate PCPL_IO_OP_WRITE))) {
433126Smvgr return (ret);
434126Smvgr }
4350Sstevel@tonic-gate }
436126Smvgr
4370Sstevel@tonic-gate if (timeout == (uint32_t)PCP_TO_NO_RESPONSE)
4380Sstevel@tonic-gate return (PCPL_OK);
4390Sstevel@tonic-gate
4400Sstevel@tonic-gate if (resp_msg_hdr == NULL) {
4410Sstevel@tonic-gate resp_msg_hdr_sz = sizeof (pcp_resp_msg_hdr_t);
4420Sstevel@tonic-gate resp_msg_hdr = (pcp_resp_msg_hdr_t *)umem_alloc(resp_msg_hdr_sz,
4430Sstevel@tonic-gate UMEM_DEFAULT);
4440Sstevel@tonic-gate if (resp_msg_hdr == NULL)
4450Sstevel@tonic-gate return (PCPL_MALLOC_FAIL);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate
4480Sstevel@tonic-gate resp_hdr_ok = 0;
4490Sstevel@tonic-gate while (!resp_hdr_ok) {
4500Sstevel@tonic-gate
4510Sstevel@tonic-gate /*
4520Sstevel@tonic-gate * Receive response message header
4530Sstevel@tonic-gate * Note: frame error handling is done in
4540Sstevel@tonic-gate * 'pcp_recv_resp_msg_hdr()'.
4550Sstevel@tonic-gate */
4560Sstevel@tonic-gate if ((ret = pcp_recv_resp_msg_hdr(resp_msg_hdr))) {
4570Sstevel@tonic-gate return (ret);
4580Sstevel@tonic-gate }
4590Sstevel@tonic-gate
4600Sstevel@tonic-gate /*
4610Sstevel@tonic-gate * Check header checksum if it matches with the received hdr
4620Sstevel@tonic-gate * checksum.
4630Sstevel@tonic-gate */
4640Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE
4650Sstevel@tonic-gate bkup_resp_hdr_cksum = resp_msg_hdr->hdr_cksum;
4660Sstevel@tonic-gate resp_msg_hdr->hdr_cksum = 0;
4670Sstevel@tonic-gate cksum = checksum((uint16_t *)resp_msg_hdr, resp_msg_hdr_sz);
4680Sstevel@tonic-gate
4690Sstevel@tonic-gate if (cksum != bkup_resp_hdr_cksum) {
4700Sstevel@tonic-gate return (PCPL_CKSUM_ERROR);
4710Sstevel@tonic-gate }
4720Sstevel@tonic-gate #endif
4730Sstevel@tonic-gate /*
4740Sstevel@tonic-gate * Check for matching request and response messages
4750Sstevel@tonic-gate */
4760Sstevel@tonic-gate if (resp_msg_hdr->xid != req_msg_hdr->xid) {
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate continue; /* continue reading response header */
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate resp_hdr_ok = 1;
4810Sstevel@tonic-gate }
4820Sstevel@tonic-gate
4830Sstevel@tonic-gate /*
4840Sstevel@tonic-gate * check status field for any channel protocol errrors
4850Sstevel@tonic-gate * This field signifies something happend during request
4860Sstevel@tonic-gate * message trasmission. This field is set by the receiver.
4870Sstevel@tonic-gate */
4880Sstevel@tonic-gate status = resp_msg_hdr->status;
4890Sstevel@tonic-gate if (status != PCP_OK) {
4900Sstevel@tonic-gate return (PCPL_XPORT_ERROR);
4910Sstevel@tonic-gate }
4920Sstevel@tonic-gate
493126Smvgr if (resp_msg_hdr->msg_len != 0) {
4940Sstevel@tonic-gate
495126Smvgr /* libpcp users should free this memory */
496126Smvgr if ((resp_msg_data = (uint8_t *)malloc(resp_msg_hdr->msg_len))
497126Smvgr == NULL)
498126Smvgr return (PCPL_MALLOC_FAIL);
499126Smvgr bzero(resp_msg_data, resp_msg_hdr->msg_len);
500126Smvgr /*
501126Smvgr * Receive response message.
502126Smvgr */
503126Smvgr if ((ret = pcp_io_op(resp_msg_data, resp_msg_hdr->msg_len,
5040Sstevel@tonic-gate PCPL_IO_OP_READ))) {
505126Smvgr free(resp_msg_data);
506126Smvgr return (ret);
507126Smvgr }
5080Sstevel@tonic-gate
5090Sstevel@tonic-gate #ifdef PCP_CKSUM_ENABLE
510126Smvgr /* verify response message data checksum */
511126Smvgr cksum = checksum((uint16_t *)resp_msg_data,
512126Smvgr resp_msg_hdr->msg_len);
513126Smvgr if (cksum != resp_msg_hdr->msg_cksum) {
514126Smvgr free(resp_msg_data);
515126Smvgr return (PCPL_CKSUM_ERROR);
516126Smvgr }
517126Smvgr #endif
5180Sstevel@tonic-gate }
5190Sstevel@tonic-gate /* Everything is okay put the received data into user */
5200Sstevel@tonic-gate /* application's resp_msg struct */
5210Sstevel@tonic-gate resp_msg->msg_len = resp_msg_hdr->msg_len;
5220Sstevel@tonic-gate resp_msg->msg_type = resp_msg_hdr->msg_type;
5230Sstevel@tonic-gate resp_msg->sub_type = resp_msg_hdr->sub_type;
5240Sstevel@tonic-gate resp_msg->msg_data = (uint8_t *)resp_msg_data;
5250Sstevel@tonic-gate
5260Sstevel@tonic-gate return (PCPL_OK);
5270Sstevel@tonic-gate
5280Sstevel@tonic-gate }
5290Sstevel@tonic-gate
5300Sstevel@tonic-gate /*
5310Sstevel@tonic-gate * Function: Get channel property values.
5320Sstevel@tonic-gate * Arguments:
533126Smvgr * int channel_fd - channel file descriptor.
5340Sstevel@tonic-gate * int prop - property id.
5350Sstevel@tonic-gate * unsigned int *val - property value tobe copied.
5360Sstevel@tonic-gate * Returns:
5370Sstevel@tonic-gate * 0 - success
5380Sstevel@tonic-gate * (-ve) - failure:
5390Sstevel@tonic-gate * PCPL_ERR_GLVC - glvc ioctl failure.
5400Sstevel@tonic-gate */
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate static int
pcp_get_prop(int channel_fd,int prop,unsigned int * val)543126Smvgr pcp_get_prop(int channel_fd, int prop, unsigned int *val)
5440Sstevel@tonic-gate {
5450Sstevel@tonic-gate glvc_xport_opt_op_t channel_op;
5460Sstevel@tonic-gate int ret;
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate channel_op.op_sel = GLVC_XPORT_OPT_GET;
5490Sstevel@tonic-gate channel_op.opt_sel = prop;
5500Sstevel@tonic-gate channel_op.opt_val = 0;
5510Sstevel@tonic-gate
5520Sstevel@tonic-gate (void) alarm(glvc_timeout);
5530Sstevel@tonic-gate
554126Smvgr if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_OPT_OP,
555126Smvgr &channel_op)) < 0) {
556126Smvgr
5570Sstevel@tonic-gate (void) alarm(0);
5580Sstevel@tonic-gate return (ret);
5590Sstevel@tonic-gate }
5600Sstevel@tonic-gate (void) alarm(0);
5610Sstevel@tonic-gate
5620Sstevel@tonic-gate *val = channel_op.opt_val;
5630Sstevel@tonic-gate
5640Sstevel@tonic-gate return (0);
5650Sstevel@tonic-gate }
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate /*
5680Sstevel@tonic-gate * Function: wrapper for handling glvc calls (read/write/peek).
5690Sstevel@tonic-gate */
5700Sstevel@tonic-gate static int
pcp_io_op(void * buf,int byte_cnt,int io_op)5710Sstevel@tonic-gate pcp_io_op(void *buf, int byte_cnt, int io_op)
5720Sstevel@tonic-gate {
5730Sstevel@tonic-gate int rv;
5740Sstevel@tonic-gate int n;
5750Sstevel@tonic-gate uint8_t *datap;
5760Sstevel@tonic-gate int (*func_ptr)(uint8_t *, int);
5770Sstevel@tonic-gate int io_sz;
5780Sstevel@tonic-gate int try_cnt;
5790Sstevel@tonic-gate
5800Sstevel@tonic-gate
5810Sstevel@tonic-gate if ((buf == NULL) || (byte_cnt < 0)) {
5820Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
5830Sstevel@tonic-gate }
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate switch (io_op) {
5860Sstevel@tonic-gate case PCPL_IO_OP_READ:
5870Sstevel@tonic-gate func_ptr = pcp_read;
5880Sstevel@tonic-gate break;
5890Sstevel@tonic-gate case PCPL_IO_OP_WRITE:
5900Sstevel@tonic-gate func_ptr = pcp_write;
5910Sstevel@tonic-gate break;
5920Sstevel@tonic-gate case PCPL_IO_OP_PEEK:
5930Sstevel@tonic-gate func_ptr = pcp_peek;
5940Sstevel@tonic-gate break;
5950Sstevel@tonic-gate default:
5960Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
5970Sstevel@tonic-gate }
5980Sstevel@tonic-gate
5990Sstevel@tonic-gate /*
6000Sstevel@tonic-gate * loop until all I/O done, try limit exceded, or real failure
6010Sstevel@tonic-gate */
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate rv = 0;
6040Sstevel@tonic-gate datap = buf;
6050Sstevel@tonic-gate while (rv < byte_cnt) {
6060Sstevel@tonic-gate io_sz = MIN((byte_cnt - rv), mtu_size);
6070Sstevel@tonic-gate try_cnt = 0;
6080Sstevel@tonic-gate while ((n = (*func_ptr)(datap, io_sz)) < 0) {
6090Sstevel@tonic-gate try_cnt++;
6100Sstevel@tonic-gate if (try_cnt > PCPL_MAX_TRY_CNT) {
6110Sstevel@tonic-gate rv = n;
6120Sstevel@tonic-gate goto done;
6130Sstevel@tonic-gate }
6140Sstevel@tonic-gate (void) sleep(PCPL_GLVC_SLEEP);
6150Sstevel@tonic-gate } /* while trying the io operation */
6160Sstevel@tonic-gate
6170Sstevel@tonic-gate if (n < 0) {
6180Sstevel@tonic-gate rv = n;
6190Sstevel@tonic-gate goto done;
6200Sstevel@tonic-gate }
6210Sstevel@tonic-gate rv += n;
6220Sstevel@tonic-gate datap += n;
6230Sstevel@tonic-gate } /* while still have more data */
6240Sstevel@tonic-gate
6250Sstevel@tonic-gate done:
6260Sstevel@tonic-gate if (rv == byte_cnt)
6270Sstevel@tonic-gate return (0);
6280Sstevel@tonic-gate else
6290Sstevel@tonic-gate return (PCPL_GLVC_ERROR);
6300Sstevel@tonic-gate }
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate /*
6330Sstevel@tonic-gate * For peeking 'bytes_cnt' bytes in channel (glvc) buffers.
6340Sstevel@tonic-gate * If data is available, the data is copied into 'buf'.
6350Sstevel@tonic-gate */
6360Sstevel@tonic-gate static int
pcp_peek(uint8_t * buf,int bytes_cnt)6370Sstevel@tonic-gate pcp_peek(uint8_t *buf, int bytes_cnt)
6380Sstevel@tonic-gate {
6390Sstevel@tonic-gate int ret;
6400Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl;
6410Sstevel@tonic-gate int n, m;
6420Sstevel@tonic-gate
6430Sstevel@tonic-gate if (bytes_cnt < 0 || bytes_cnt > mtu_size) {
6440Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
6450Sstevel@tonic-gate }
6460Sstevel@tonic-gate
6470Sstevel@tonic-gate /*
6480Sstevel@tonic-gate * initialization of buffers used for peeking data in channel buffers.
6490Sstevel@tonic-gate */
6500Sstevel@tonic-gate if (peek_area == NULL) {
6510Sstevel@tonic-gate peek_area = (uint8_t *)umem_zalloc(PEEK_AREA_SIZE,
6520Sstevel@tonic-gate UMEM_DEFAULT);
6530Sstevel@tonic-gate if (peek_area == NULL) {
6540Sstevel@tonic-gate return (PCPL_MALLOC_FAIL);
6550Sstevel@tonic-gate }
6560Sstevel@tonic-gate }
6570Sstevel@tonic-gate
6580Sstevel@tonic-gate /*
6590Sstevel@tonic-gate * peek max MTU size bytes
6600Sstevel@tonic-gate */
6610Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)peek_area;
6620Sstevel@tonic-gate peek_ctrl.buflen = mtu_size;
6630Sstevel@tonic-gate peek_ctrl.flags = 0;
6640Sstevel@tonic-gate
6650Sstevel@tonic-gate (void) alarm(glvc_timeout);
6660Sstevel@tonic-gate
6670Sstevel@tonic-gate if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, &peek_ctrl))
6680Sstevel@tonic-gate < 0) {
6690Sstevel@tonic-gate (void) alarm(0);
6700Sstevel@tonic-gate return (ret);
6710Sstevel@tonic-gate }
6720Sstevel@tonic-gate (void) alarm(0);
6730Sstevel@tonic-gate
6740Sstevel@tonic-gate n = peek_ctrl.buflen;
6750Sstevel@tonic-gate
6760Sstevel@tonic-gate if (n < 0)
6770Sstevel@tonic-gate return (PCPL_GLVC_ERROR);
6780Sstevel@tonic-gate
6790Sstevel@tonic-gate /*
6800Sstevel@tonic-gate * satisfy request as best as we can
6810Sstevel@tonic-gate */
6820Sstevel@tonic-gate m = MIN(bytes_cnt, n);
6830Sstevel@tonic-gate (void) memcpy(buf, peek_area, m);
6840Sstevel@tonic-gate
6850Sstevel@tonic-gate return (m);
6860Sstevel@tonic-gate }
6870Sstevel@tonic-gate
6880Sstevel@tonic-gate /*
6890Sstevel@tonic-gate * Function: write 'byte_cnt' bytes from 'buf' to channel.
6900Sstevel@tonic-gate */
6910Sstevel@tonic-gate static int
pcp_write(uint8_t * buf,int byte_cnt)6920Sstevel@tonic-gate pcp_write(uint8_t *buf, int byte_cnt)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate
6950Sstevel@tonic-gate int ret;
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate /* check for valid arguments */
6980Sstevel@tonic-gate if (buf == NULL || byte_cnt < 0 || byte_cnt > mtu_size) {
6990Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
7000Sstevel@tonic-gate }
7010Sstevel@tonic-gate
7021991Sheppo if (xport_type == GLVC_NON_STREAM) {
7031991Sheppo (void) alarm(glvc_timeout);
7040Sstevel@tonic-gate
7051991Sheppo if ((ret = write(chnl_fd, buf, byte_cnt)) < 0) {
7061991Sheppo (void) alarm(0);
7071991Sheppo return (ret);
7081991Sheppo }
7090Sstevel@tonic-gate (void) alarm(0);
7101991Sheppo } else {
7111991Sheppo if ((ret = vldc_write(chnl_fd, buf, byte_cnt)) <= 0) {
7121991Sheppo return (ret);
7131991Sheppo }
7140Sstevel@tonic-gate }
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate return (ret);
7170Sstevel@tonic-gate }
7180Sstevel@tonic-gate
7190Sstevel@tonic-gate /*
7200Sstevel@tonic-gate * In current implementaion of glvc driver, streams reads are not supported.
7210Sstevel@tonic-gate * pcp_read mimics stream reads by first reading all the bytes present in the
7220Sstevel@tonic-gate * channel buffer into a local buffer and from then on read requests
7230Sstevel@tonic-gate * are serviced from local buffer. When read requests are not serviceble
7240Sstevel@tonic-gate * from local buffer, it repeates by first reading data from channel buffers.
7250Sstevel@tonic-gate *
7260Sstevel@tonic-gate * This call may need to be enhanced when glvc supports buffered (stream)
7270Sstevel@tonic-gate * reads - TBD
7280Sstevel@tonic-gate */
7290Sstevel@tonic-gate
7300Sstevel@tonic-gate static int
pcp_read(uint8_t * buf,int byte_cnt)7310Sstevel@tonic-gate pcp_read(uint8_t *buf, int byte_cnt)
7320Sstevel@tonic-gate {
7330Sstevel@tonic-gate int ret;
7340Sstevel@tonic-gate int n, m, i;
7350Sstevel@tonic-gate
7360Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) {
7370Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate
7400Sstevel@tonic-gate /*
7410Sstevel@tonic-gate * initialization of local read buffer
7420Sstevel@tonic-gate * from which the stream read requests are serviced.
7430Sstevel@tonic-gate */
7440Sstevel@tonic-gate if (read_area == NULL) {
7450Sstevel@tonic-gate read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE,
7460Sstevel@tonic-gate UMEM_DEFAULT);
7470Sstevel@tonic-gate if (read_area == NULL) {
7480Sstevel@tonic-gate return (PCPL_MALLOC_FAIL);
7490Sstevel@tonic-gate }
7500Sstevel@tonic-gate read_head = read_area;
7510Sstevel@tonic-gate read_tail = read_area;
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate /*
7550Sstevel@tonic-gate * if we already read this data then copy from local buffer it self
7560Sstevel@tonic-gate * without calling new read.
7570Sstevel@tonic-gate */
7580Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) {
7590Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt);
7600Sstevel@tonic-gate read_head += byte_cnt;
7610Sstevel@tonic-gate return (byte_cnt);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate
7640Sstevel@tonic-gate /*
7650Sstevel@tonic-gate * if the request is not satisfied from the buffered data, then move the
7660Sstevel@tonic-gate * remaining data to front of the buffer and read new data.
7670Sstevel@tonic-gate */
7680Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) {
7690Sstevel@tonic-gate read_area[i] = read_head[i];
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate read_head = read_area;
7720Sstevel@tonic-gate read_tail = read_head + i;
7730Sstevel@tonic-gate
7740Sstevel@tonic-gate /*
7750Sstevel@tonic-gate * do a peek to see how much data is available and read complete data.
7760Sstevel@tonic-gate */
7770Sstevel@tonic-gate
7781991Sheppo if (xport_type == GLVC_NON_STREAM) {
7791991Sheppo if ((m = pcp_peek(read_tail, mtu_size)) < 0) {
7801991Sheppo return (m);
7811991Sheppo }
7821991Sheppo
7831991Sheppo (void) alarm(glvc_timeout);
7841991Sheppo if ((ret = read(chnl_fd, read_tail, m)) < 0) {
7851991Sheppo (void) alarm(0);
7861991Sheppo return (ret);
7871991Sheppo }
7880Sstevel@tonic-gate
7890Sstevel@tonic-gate (void) alarm(0);
7901991Sheppo } else {
7911991Sheppo /*
7921991Sheppo * Read the extra number of bytes
7931991Sheppo */
7941991Sheppo m = byte_cnt - (read_tail - read_head);
7951991Sheppo if ((ret = vldc_read(chnl_fd,
7961991Sheppo read_tail, m)) <= 0) {
7971991Sheppo return (ret);
7981991Sheppo }
7990Sstevel@tonic-gate }
8000Sstevel@tonic-gate read_tail += ret;
8010Sstevel@tonic-gate
8020Sstevel@tonic-gate /*
8030Sstevel@tonic-gate * copy the requested bytes.
8040Sstevel@tonic-gate */
8050Sstevel@tonic-gate n = MIN(byte_cnt, (read_tail - read_head));
8060Sstevel@tonic-gate (void) memcpy(buf, read_head, n);
8070Sstevel@tonic-gate
8080Sstevel@tonic-gate read_head += n;
8090Sstevel@tonic-gate
8100Sstevel@tonic-gate return (n);
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate /*
8141991Sheppo * Issue read from the driver until byet_cnt number
8151991Sheppo * of bytes are present in read buffer. Do not
8161991Sheppo * move the read head.
8171991Sheppo */
8181991Sheppo static int
pcp_update_read_area(int byte_cnt)8191991Sheppo pcp_update_read_area(int byte_cnt)
8201991Sheppo {
8211991Sheppo int ret;
8221991Sheppo int n, i;
8231991Sheppo
8241991Sheppo if (byte_cnt < 0 || byte_cnt > mtu_size) {
8251991Sheppo return (PCPL_INVALID_ARGS);
8261991Sheppo }
8271991Sheppo
8281991Sheppo /*
8291991Sheppo * initialization of local read buffer
8301991Sheppo * from which the stream read requests are serviced.
8311991Sheppo */
8321991Sheppo if (read_area == NULL) {
8331991Sheppo read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE,
8341991Sheppo UMEM_DEFAULT);
8351991Sheppo if (read_area == NULL) {
8361991Sheppo return (PCPL_MALLOC_FAIL);
8371991Sheppo }
8381991Sheppo read_head = read_area;
8391991Sheppo read_tail = read_area;
8401991Sheppo }
8411991Sheppo
8421991Sheppo /*
8431991Sheppo * if we already have sufficient data in the buffer,
8441991Sheppo * just return
8451991Sheppo */
8461991Sheppo if (byte_cnt <= (read_tail - read_head)) {
8471991Sheppo return (byte_cnt);
8481991Sheppo }
8491991Sheppo
8501991Sheppo /*
8511991Sheppo * if the request is not satisfied from the buffered data, then move the
8521991Sheppo * remaining data to front of the buffer and read new data.
8531991Sheppo */
8541991Sheppo for (i = 0; i < (read_tail - read_head); ++i) {
8551991Sheppo read_area[i] = read_head[i];
8561991Sheppo }
8571991Sheppo read_head = read_area;
8581991Sheppo read_tail = read_head + i;
8591991Sheppo
8601991Sheppo n = byte_cnt - (read_tail - read_head);
8611991Sheppo
8621991Sheppo if ((ret = vldc_read(chnl_fd,
8631991Sheppo read_tail, n)) <= 0) {
8641991Sheppo return (ret);
8651991Sheppo }
8661991Sheppo read_tail += ret;
8671991Sheppo
8681991Sheppo /*
8691991Sheppo * Return the number of bytes we could read
8701991Sheppo */
8711991Sheppo n = MIN(byte_cnt, (read_tail - read_head));
8721991Sheppo
8731991Sheppo return (n);
8741991Sheppo }
8751991Sheppo
8761991Sheppo /*
8770Sstevel@tonic-gate * This function is slight different from pcp_peek. The peek requests are first
8780Sstevel@tonic-gate * serviced from local read buffer, if data is available. If the peek request
8790Sstevel@tonic-gate * is not serviceble from local read buffer, then the data is peeked from
8800Sstevel@tonic-gate * channel buffer. This function is mainly used for proper protocol framing
8810Sstevel@tonic-gate * error handling.
8820Sstevel@tonic-gate */
8830Sstevel@tonic-gate static int
pcp_peek_read(uint8_t * buf,int byte_cnt)8840Sstevel@tonic-gate pcp_peek_read(uint8_t *buf, int byte_cnt)
8850Sstevel@tonic-gate {
8860Sstevel@tonic-gate int n, m, i;
8870Sstevel@tonic-gate
8880Sstevel@tonic-gate if (byte_cnt < 0 || byte_cnt > mtu_size) {
8890Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
8900Sstevel@tonic-gate }
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate /*
8930Sstevel@tonic-gate * initialization of peek_read buffer.
8940Sstevel@tonic-gate */
8950Sstevel@tonic-gate if (peek_read_area == NULL) {
8960Sstevel@tonic-gate peek_read_area = (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE,
8970Sstevel@tonic-gate UMEM_DEFAULT);
8980Sstevel@tonic-gate if (peek_read_area == NULL) {
8990Sstevel@tonic-gate return (PCPL_MALLOC_FAIL);
9000Sstevel@tonic-gate }
9010Sstevel@tonic-gate peek_read_head = peek_read_area;
9020Sstevel@tonic-gate peek_read_tail = peek_read_area;
9030Sstevel@tonic-gate }
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate /*
9060Sstevel@tonic-gate * if we already have the data in local read buffer then copy
9070Sstevel@tonic-gate * from local buffer it self w/out calling new peek
9080Sstevel@tonic-gate */
9090Sstevel@tonic-gate if (byte_cnt <= (read_tail - read_head)) {
9100Sstevel@tonic-gate (void) memcpy(buf, read_head, byte_cnt);
9110Sstevel@tonic-gate return (byte_cnt);
9120Sstevel@tonic-gate }
9130Sstevel@tonic-gate
9140Sstevel@tonic-gate /*
9150Sstevel@tonic-gate * if the request is not satisfied from local read buffer, then first
9160Sstevel@tonic-gate * copy the remaining data in local read buffer to peek_read_area and
9170Sstevel@tonic-gate * then issue new peek.
9180Sstevel@tonic-gate */
9190Sstevel@tonic-gate for (i = 0; i < (read_tail - read_head); ++i) {
9200Sstevel@tonic-gate peek_read_area[i] = read_head[i];
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate peek_read_head = peek_read_area;
9230Sstevel@tonic-gate peek_read_tail = peek_read_head + i;
9240Sstevel@tonic-gate
9250Sstevel@tonic-gate /*
9260Sstevel@tonic-gate * do a peek to see how much data is available and read complete data.
9270Sstevel@tonic-gate */
9280Sstevel@tonic-gate
9290Sstevel@tonic-gate if ((m = pcp_peek(peek_read_tail, mtu_size)) < 0) {
9300Sstevel@tonic-gate return (m);
9310Sstevel@tonic-gate }
9320Sstevel@tonic-gate peek_read_tail += m;
9330Sstevel@tonic-gate
9340Sstevel@tonic-gate /*
9350Sstevel@tonic-gate * copy the requested bytes
9360Sstevel@tonic-gate */
9370Sstevel@tonic-gate n = MIN(byte_cnt, (peek_read_tail - peek_read_head));
9380Sstevel@tonic-gate (void) memcpy(buf, peek_read_head, n);
9390Sstevel@tonic-gate
9400Sstevel@tonic-gate return (n);
9410Sstevel@tonic-gate }
9420Sstevel@tonic-gate
9430Sstevel@tonic-gate /*
9440Sstevel@tonic-gate * Send Request Message Header.
9450Sstevel@tonic-gate */
9460Sstevel@tonic-gate static int
pcp_send_req_msg_hdr(pcp_req_msg_hdr_t * req_hdr)9470Sstevel@tonic-gate pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr)
9480Sstevel@tonic-gate {
9490Sstevel@tonic-gate pcp_req_msg_hdr_t *hdrp;
9500Sstevel@tonic-gate int hdr_sz;
9510Sstevel@tonic-gate int ret;
9520Sstevel@tonic-gate
9530Sstevel@tonic-gate hdr_sz = sizeof (pcp_req_msg_hdr_t);
9540Sstevel@tonic-gate if ((hdrp = (pcp_req_msg_hdr_t *)umem_zalloc(hdr_sz,
9550Sstevel@tonic-gate UMEM_DEFAULT)) == NULL) {
9560Sstevel@tonic-gate return (PCPL_MALLOC_FAIL);
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate
9590Sstevel@tonic-gate hdrp->magic_num = htonl(req_hdr->magic_num);
9600Sstevel@tonic-gate hdrp->proto_ver = req_hdr->proto_ver;
9610Sstevel@tonic-gate hdrp->msg_type = req_hdr->msg_type;
9620Sstevel@tonic-gate hdrp->sub_type = req_hdr->sub_type;
9630Sstevel@tonic-gate hdrp->rsvd_pad = htons(req_hdr->rsvd_pad);
9640Sstevel@tonic-gate hdrp->xid = htonl(req_hdr->xid);
9650Sstevel@tonic-gate hdrp->timeout = htonl(req_hdr->timeout);
9660Sstevel@tonic-gate hdrp->msg_len = htonl(req_hdr->msg_len);
9670Sstevel@tonic-gate hdrp->msg_cksum = htons(req_hdr->msg_cksum);
9680Sstevel@tonic-gate hdrp->hdr_cksum = htons(req_hdr->hdr_cksum);
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate if ((ret = pcp_io_op((char *)hdrp, hdr_sz, PCPL_IO_OP_WRITE)) != 0) {
9710Sstevel@tonic-gate umem_free(hdrp, hdr_sz);
9720Sstevel@tonic-gate return (ret);
9730Sstevel@tonic-gate }
9740Sstevel@tonic-gate umem_free(hdrp, hdr_sz);
9750Sstevel@tonic-gate return (PCP_OK);
9760Sstevel@tonic-gate }
9770Sstevel@tonic-gate
9780Sstevel@tonic-gate /*
9790Sstevel@tonic-gate * Receive Response message header.
9800Sstevel@tonic-gate */
9810Sstevel@tonic-gate static int
pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t * resp_hdr)9820Sstevel@tonic-gate pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr)
9830Sstevel@tonic-gate {
9840Sstevel@tonic-gate uint32_t magic_num;
9850Sstevel@tonic-gate uint8_t proto_ver;
9860Sstevel@tonic-gate uint8_t msg_type;
9870Sstevel@tonic-gate uint8_t sub_type;
9880Sstevel@tonic-gate uint8_t rsvd_pad;
9890Sstevel@tonic-gate uint32_t xid;
9900Sstevel@tonic-gate uint32_t timeout;
9910Sstevel@tonic-gate uint32_t msg_len;
9920Sstevel@tonic-gate uint32_t status;
9930Sstevel@tonic-gate uint16_t msg_cksum;
9940Sstevel@tonic-gate uint16_t hdr_cksum;
9950Sstevel@tonic-gate int ret;
9960Sstevel@tonic-gate
9970Sstevel@tonic-gate if (resp_hdr == NULL) {
9980Sstevel@tonic-gate return (PCPL_INVALID_ARGS);
9990Sstevel@tonic-gate }
10000Sstevel@tonic-gate
10010Sstevel@tonic-gate /*
10020Sstevel@tonic-gate * handle protocol framing errors.
10030Sstevel@tonic-gate * pcp_frame_error_handle() returns when proper frame arrived
10040Sstevel@tonic-gate * (magic seq) or if an error happens while reading data from
10050Sstevel@tonic-gate * channel.
10060Sstevel@tonic-gate */
10071991Sheppo if (xport_type == GLVC_NON_STREAM)
10081991Sheppo ret = pcp_frame_error_handle();
10091991Sheppo else
10101991Sheppo ret = pcp_vldc_frame_error_handle();
10111991Sheppo
10121991Sheppo if (ret != 0)
10130Sstevel@tonic-gate return (PCPL_FRAME_ERROR);
10140Sstevel@tonic-gate
10150Sstevel@tonic-gate /* read magic number first */
10160Sstevel@tonic-gate if ((ret = pcp_io_op(&magic_num, sizeof (magic_num),
10170Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10180Sstevel@tonic-gate return (ret);
10190Sstevel@tonic-gate }
10200Sstevel@tonic-gate
10210Sstevel@tonic-gate magic_num = ntohl(magic_num);
10220Sstevel@tonic-gate
10230Sstevel@tonic-gate if (magic_num != PCP_MAGIC_NUM) {
10240Sstevel@tonic-gate return (PCPL_FRAME_ERROR);
10250Sstevel@tonic-gate }
10260Sstevel@tonic-gate
10270Sstevel@tonic-gate /* read version field */
10280Sstevel@tonic-gate if ((ret = pcp_io_op(&proto_ver, sizeof (proto_ver),
10290Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10300Sstevel@tonic-gate return (ret);
10310Sstevel@tonic-gate }
10320Sstevel@tonic-gate
10330Sstevel@tonic-gate /* check protocol version */
10340Sstevel@tonic-gate if (proto_ver != PCP_PROT_VER_1) {
10350Sstevel@tonic-gate return (PCPL_PROT_ERROR);
10360Sstevel@tonic-gate }
10370Sstevel@tonic-gate
10380Sstevel@tonic-gate /* Read message type */
10390Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_type, sizeof (msg_type),
10400Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10410Sstevel@tonic-gate return (ret);
10420Sstevel@tonic-gate }
10430Sstevel@tonic-gate
10440Sstevel@tonic-gate /* Read message sub type */
10450Sstevel@tonic-gate if ((ret = pcp_io_op(&sub_type, sizeof (sub_type),
10460Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10470Sstevel@tonic-gate return (ret);
10480Sstevel@tonic-gate }
10490Sstevel@tonic-gate
10500Sstevel@tonic-gate /* Read rcvd_pad bits */
10510Sstevel@tonic-gate if ((ret = pcp_io_op(&rsvd_pad, sizeof (rsvd_pad),
10520Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10530Sstevel@tonic-gate return (ret);
10540Sstevel@tonic-gate }
10550Sstevel@tonic-gate
10560Sstevel@tonic-gate /* receive transaction id */
10570Sstevel@tonic-gate if ((ret = pcp_io_op(&xid, sizeof (xid),
10580Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10590Sstevel@tonic-gate return (ret);
10600Sstevel@tonic-gate }
10610Sstevel@tonic-gate
10620Sstevel@tonic-gate xid = ntohl(xid);
10630Sstevel@tonic-gate
10640Sstevel@tonic-gate /* receive timeout value */
10650Sstevel@tonic-gate if ((ret = pcp_io_op(&timeout, sizeof (timeout),
10660Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10670Sstevel@tonic-gate return (ret);
10680Sstevel@tonic-gate }
10690Sstevel@tonic-gate
10700Sstevel@tonic-gate timeout = ntohl(timeout);
10710Sstevel@tonic-gate
10720Sstevel@tonic-gate /* receive message length */
10730Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_len, sizeof (msg_len),
10740Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10750Sstevel@tonic-gate return (ret);
10760Sstevel@tonic-gate }
10770Sstevel@tonic-gate
10780Sstevel@tonic-gate msg_len = ntohl(msg_len);
10790Sstevel@tonic-gate
10800Sstevel@tonic-gate /* receive status field */
10810Sstevel@tonic-gate if ((ret = pcp_io_op(&status, sizeof (status),
10820Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10830Sstevel@tonic-gate return (ret);
10840Sstevel@tonic-gate }
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate status = ntohl(status);
10870Sstevel@tonic-gate
10880Sstevel@tonic-gate /* receive message checksum */
10890Sstevel@tonic-gate if ((ret = pcp_io_op(&msg_cksum, sizeof (msg_cksum),
10900Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10910Sstevel@tonic-gate return (ret);
10920Sstevel@tonic-gate }
10930Sstevel@tonic-gate
10940Sstevel@tonic-gate msg_cksum = ntohs(msg_cksum);
10950Sstevel@tonic-gate
10960Sstevel@tonic-gate /* receive header checksum */
10970Sstevel@tonic-gate if ((ret = pcp_io_op(&hdr_cksum, sizeof (hdr_cksum),
10980Sstevel@tonic-gate PCPL_IO_OP_READ)) != 0) {
10990Sstevel@tonic-gate return (ret);
11000Sstevel@tonic-gate }
11010Sstevel@tonic-gate
11020Sstevel@tonic-gate hdr_cksum = ntohs(hdr_cksum);
11030Sstevel@tonic-gate
11040Sstevel@tonic-gate /* copy to resp_hdr */
11050Sstevel@tonic-gate
11060Sstevel@tonic-gate resp_hdr->magic_num = magic_num;
11070Sstevel@tonic-gate resp_hdr->proto_ver = proto_ver;
11080Sstevel@tonic-gate resp_hdr->msg_type = msg_type;
11090Sstevel@tonic-gate resp_hdr->sub_type = sub_type;
11100Sstevel@tonic-gate resp_hdr->rsvd_pad = rsvd_pad;
11110Sstevel@tonic-gate resp_hdr->xid = xid;
11120Sstevel@tonic-gate resp_hdr->timeout = timeout;
11130Sstevel@tonic-gate resp_hdr->msg_len = msg_len;
11140Sstevel@tonic-gate resp_hdr->status = status;
11150Sstevel@tonic-gate resp_hdr->msg_cksum = msg_cksum;
11160Sstevel@tonic-gate resp_hdr->hdr_cksum = hdr_cksum;
11170Sstevel@tonic-gate
11180Sstevel@tonic-gate return (PCP_OK);
11190Sstevel@tonic-gate }
11200Sstevel@tonic-gate
11210Sstevel@tonic-gate /*
11220Sstevel@tonic-gate * Get next xid for including in request message.
11230Sstevel@tonic-gate * Every request and response message are matched
11240Sstevel@tonic-gate * for same xid.
11250Sstevel@tonic-gate */
1126293Smvgr
1127293Smvgr static uint32_t
pcp_get_xid(void)1128293Smvgr pcp_get_xid(void)
11290Sstevel@tonic-gate {
11300Sstevel@tonic-gate uint32_t ret;
1131293Smvgr struct timeval tv;
1132293Smvgr static boolean_t xid_initialized = B_FALSE;
11330Sstevel@tonic-gate
1134293Smvgr if (xid_initialized == B_FALSE) {
1135293Smvgr xid_initialized = B_TRUE;
1136293Smvgr /*
1137293Smvgr * starting xid is initialized to a different value everytime
1138293Smvgr * user application is restarted so that user apps will not
1139293Smvgr * receive previous session's packets.
1140293Smvgr *
1141293Smvgr * Note: The algorithm for generating initial xid is partially
1142293Smvgr * taken from Solaris rpc code.
1143293Smvgr */
1144293Smvgr (void) gettimeofday(&tv, NULL);
1145293Smvgr msg_xid = (uint32_t)((tv.tv_sec << 20) |
1146293Smvgr (tv.tv_usec >> 10));
1147293Smvgr }
1148293Smvgr
1149293Smvgr ret = msg_xid++;
1150293Smvgr
1151293Smvgr /* zero xid is not allowed */
1152293Smvgr if (ret == 0)
1153293Smvgr ret = msg_xid++;
1154293Smvgr
11550Sstevel@tonic-gate return (ret);
11560Sstevel@tonic-gate }
11570Sstevel@tonic-gate
11580Sstevel@tonic-gate /*
11590Sstevel@tonic-gate * This function handles channel framing errors. It waits until proper
11600Sstevel@tonic-gate * frame with starting sequence as magic numder (0xAFBCAFA0)
11610Sstevel@tonic-gate * is arrived. It removes unexpected data (before the magic number sequence)
11620Sstevel@tonic-gate * on the channel. It returns when proper magic number sequence is seen
11630Sstevel@tonic-gate * or when any failure happens while reading/peeking the channel.
11640Sstevel@tonic-gate */
11650Sstevel@tonic-gate static int
pcp_frame_error_handle(void)11660Sstevel@tonic-gate pcp_frame_error_handle(void)
11670Sstevel@tonic-gate {
11680Sstevel@tonic-gate uint8_t magic_num_buf[4];
11690Sstevel@tonic-gate int ispresent = 0;
11700Sstevel@tonic-gate uint32_t net_magic_num; /* magic byte in network byte order */
11710Sstevel@tonic-gate uint32_t host_magic_num = PCP_MAGIC_NUM;
11720Sstevel@tonic-gate uint8_t buf[2];
11730Sstevel@tonic-gate
11740Sstevel@tonic-gate net_magic_num = htonl(host_magic_num);
11750Sstevel@tonic-gate (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4);
11760Sstevel@tonic-gate
11770Sstevel@tonic-gate while (!ispresent) {
11780Sstevel@tonic-gate /*
11790Sstevel@tonic-gate * Check if next four bytes matches pcp magic number.
11800Sstevel@tonic-gate * if mathing not found, discard 1 byte and continue checking.
11810Sstevel@tonic-gate */
11820Sstevel@tonic-gate if (!check_magic_byte_presence(4, &magic_num_buf[0],
11830Sstevel@tonic-gate &ispresent)) {
11840Sstevel@tonic-gate if (!ispresent) {
11850Sstevel@tonic-gate /* remove 1 byte */
11860Sstevel@tonic-gate (void) pcp_io_op(buf, 1, PCPL_IO_OP_READ);
11870Sstevel@tonic-gate }
11880Sstevel@tonic-gate } else {
11890Sstevel@tonic-gate return (-1);
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate return (0);
11940Sstevel@tonic-gate }
11950Sstevel@tonic-gate
11960Sstevel@tonic-gate /*
11971991Sheppo * This function handles channel framing errors. It waits until proper
11981991Sheppo * frame with starting sequence as magic numder (0xAFBCAFA0)
11991991Sheppo * is arrived. It removes unexpected data (before the magic number sequence)
12001991Sheppo * on the channel. It returns when proper magic number sequence is seen
12011991Sheppo * or when any failure happens while reading/peeking the channel.
12021991Sheppo */
12031991Sheppo static int
pcp_vldc_frame_error_handle(void)12041991Sheppo pcp_vldc_frame_error_handle(void)
12051991Sheppo {
12061991Sheppo uint8_t magic_num_buf[4];
12071991Sheppo uint32_t net_magic_num; /* magic byte in network byte order */
12081991Sheppo uint32_t host_magic_num = PCP_MAGIC_NUM;
12091991Sheppo int found_magic = 0;
12101991Sheppo
12111991Sheppo net_magic_num = htonl(host_magic_num);
12121991Sheppo (void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4);
12131991Sheppo
12141991Sheppo /*
12151991Sheppo * For vldc, we need to read whatever data is available and
12161991Sheppo * advance the read pointer one byte at a time until we get
12171991Sheppo * the magic word. When this function is invoked, we do not
12181991Sheppo * have any byte in the read buffer.
12191991Sheppo */
12201991Sheppo
12211991Sheppo /*
12221991Sheppo * Keep reading until we find the matching magic number
12231991Sheppo */
12241991Sheppo while (!found_magic) {
12251991Sheppo while ((read_tail - read_head) < sizeof (host_magic_num)) {
12261991Sheppo if (pcp_update_read_area(sizeof (host_magic_num)) < 0)
12271991Sheppo return (-1);
12281991Sheppo }
12291991Sheppo
12301991Sheppo /*
12311991Sheppo * We should have at least 4 bytes in read buffer. Check
12321991Sheppo * if the magic number can be matched
12331991Sheppo */
12341991Sheppo if (memcmp(read_head, magic_num_buf,
12351991Sheppo sizeof (host_magic_num))) {
12361991Sheppo read_head += 1;
12371991Sheppo } else {
12381991Sheppo found_magic = 1;
12391991Sheppo }
12401991Sheppo }
12411991Sheppo
12421991Sheppo return (0);
12431991Sheppo }
12441991Sheppo
12451991Sheppo /*
12460Sstevel@tonic-gate * checks whether certain byte sequence is present in the data stream.
12470Sstevel@tonic-gate */
12480Sstevel@tonic-gate static int
check_magic_byte_presence(int byte_cnt,uint8_t * byte_seq,int * ispresent)12490Sstevel@tonic-gate check_magic_byte_presence(int byte_cnt, uint8_t *byte_seq, int *ispresent)
12500Sstevel@tonic-gate {
12510Sstevel@tonic-gate int ret, i;
12520Sstevel@tonic-gate uint8_t buf[4];
12530Sstevel@tonic-gate
12540Sstevel@tonic-gate if ((ret = pcp_peek_read(buf, byte_cnt)) < 0) {
12550Sstevel@tonic-gate return (ret);
12560Sstevel@tonic-gate }
12570Sstevel@tonic-gate
12580Sstevel@tonic-gate /* 'byte_cnt' bytes not present */
12590Sstevel@tonic-gate if (ret != byte_cnt) {
12600Sstevel@tonic-gate *ispresent = 0;
12610Sstevel@tonic-gate return (0);
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate
12640Sstevel@tonic-gate for (i = 0; i < byte_cnt; ++i) {
12650Sstevel@tonic-gate if (buf[i] != byte_seq[i]) {
12660Sstevel@tonic-gate *ispresent = 0;
12670Sstevel@tonic-gate return (0);
12680Sstevel@tonic-gate }
12690Sstevel@tonic-gate }
12700Sstevel@tonic-gate *ispresent = 1;
12710Sstevel@tonic-gate
12720Sstevel@tonic-gate return (0);
12730Sstevel@tonic-gate }
12740Sstevel@tonic-gate
12750Sstevel@tonic-gate /*
12760Sstevel@tonic-gate * 16-bit simple internet checksum
12770Sstevel@tonic-gate */
12780Sstevel@tonic-gate static uint16_t
checksum(uint16_t * addr,int32_t count)12790Sstevel@tonic-gate checksum(uint16_t *addr, int32_t count)
12800Sstevel@tonic-gate {
12810Sstevel@tonic-gate /*
12820Sstevel@tonic-gate * Compute Internet Checksum for "count" bytes
12830Sstevel@tonic-gate * beginning at location "addr".
12840Sstevel@tonic-gate */
12850Sstevel@tonic-gate
12860Sstevel@tonic-gate register uint32_t sum = 0;
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate while (count > 1) {
12890Sstevel@tonic-gate /* This is the inner loop */
12900Sstevel@tonic-gate sum += *(unsigned short *)addr++;
12910Sstevel@tonic-gate count -= 2;
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate
12940Sstevel@tonic-gate /* Add left-over byte, if any */
12950Sstevel@tonic-gate if (count > 0)
12960Sstevel@tonic-gate sum += * (unsigned char *)addr;
12970Sstevel@tonic-gate
12980Sstevel@tonic-gate /* Fold 32-bit sum to 16 bits */
12990Sstevel@tonic-gate while (sum >> 16)
13000Sstevel@tonic-gate sum = (sum & 0xffff) + (sum >> 16);
13010Sstevel@tonic-gate
13020Sstevel@tonic-gate sum = (~sum) & 0xffff;
13030Sstevel@tonic-gate if (sum == 0)
13040Sstevel@tonic-gate sum = 0xffff;
13050Sstevel@tonic-gate
13060Sstevel@tonic-gate return (sum);
13070Sstevel@tonic-gate }
13080Sstevel@tonic-gate
13090Sstevel@tonic-gate /*
13100Sstevel@tonic-gate * cleanup the channel if any data is hanging in
13110Sstevel@tonic-gate * channel buffers.
13120Sstevel@tonic-gate */
13130Sstevel@tonic-gate static int
pcp_cleanup(int channel_fd)1314126Smvgr pcp_cleanup(int channel_fd)
13150Sstevel@tonic-gate {
13160Sstevel@tonic-gate int ret;
13170Sstevel@tonic-gate glvc_xport_msg_peek_t peek_ctrl;
13180Sstevel@tonic-gate int n, done;
13190Sstevel@tonic-gate uint8_t *buf = NULL;
13200Sstevel@tonic-gate int retry = 0;
13210Sstevel@tonic-gate
13220Sstevel@tonic-gate
13230Sstevel@tonic-gate buf = (uint8_t *)umem_zalloc((mtu_size), UMEM_DEFAULT);
13240Sstevel@tonic-gate if (buf == NULL) {
13250Sstevel@tonic-gate return (PCPL_MALLOC_FAIL);
13260Sstevel@tonic-gate }
13270Sstevel@tonic-gate
13280Sstevel@tonic-gate peek_ctrl.buf = (caddr_t)buf;
13290Sstevel@tonic-gate peek_ctrl.buflen = mtu_size;
13300Sstevel@tonic-gate peek_ctrl.flags = 0;
13310Sstevel@tonic-gate
13320Sstevel@tonic-gate /*
13330Sstevel@tonic-gate * set sig jmp location
13340Sstevel@tonic-gate */
13350Sstevel@tonic-gate if (sigsetjmp(jmpbuf, 1)) {
13360Sstevel@tonic-gate umem_free(buf, mtu_size);
13370Sstevel@tonic-gate return (PCPL_GLVC_TIMEOUT);
13380Sstevel@tonic-gate }
13390Sstevel@tonic-gate
13400Sstevel@tonic-gate done = 0;
13410Sstevel@tonic-gate while (!done) {
13420Sstevel@tonic-gate
13430Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT);
1344126Smvgr if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_DATA_PEEK,
13450Sstevel@tonic-gate &peek_ctrl)) < 0) {
13460Sstevel@tonic-gate (void) alarm(0);
13470Sstevel@tonic-gate done = 1;
13480Sstevel@tonic-gate continue;
13490Sstevel@tonic-gate }
13500Sstevel@tonic-gate (void) alarm(0);
13510Sstevel@tonic-gate
13520Sstevel@tonic-gate n = peek_ctrl.buflen;
13530Sstevel@tonic-gate
13540Sstevel@tonic-gate if (n <= 0 && retry > 2) {
13550Sstevel@tonic-gate done = 1;
13560Sstevel@tonic-gate continue;
13570Sstevel@tonic-gate } else if (n <= 0) {
13580Sstevel@tonic-gate ++retry;
13590Sstevel@tonic-gate continue;
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate
13620Sstevel@tonic-gate /* remove data from channel */
13630Sstevel@tonic-gate (void) alarm(PCP_CLEANUP_TIMEOUT);
1364126Smvgr if ((ret = read(channel_fd, buf, n)) < 0) {
13650Sstevel@tonic-gate (void) alarm(0);
13660Sstevel@tonic-gate done = 1;
13670Sstevel@tonic-gate continue;
13680Sstevel@tonic-gate }
13690Sstevel@tonic-gate (void) alarm(0);
13700Sstevel@tonic-gate }
13710Sstevel@tonic-gate
13720Sstevel@tonic-gate umem_free(buf, mtu_size);
13730Sstevel@tonic-gate return (ret);
13740Sstevel@tonic-gate }
13751991Sheppo
13761991Sheppo static int
vldc_write(int fd,uint8_t * bufp,int size)13771991Sheppo vldc_write(int fd, uint8_t *bufp, int size)
13781991Sheppo {
13791991Sheppo int res;
13801991Sheppo int left = size;
13811991Sheppo pollfd_t pollfd;
13821991Sheppo
13831991Sheppo pollfd.events = POLLOUT;
13841991Sheppo pollfd.revents = 0;
13851991Sheppo pollfd.fd = fd;
13861991Sheppo
13871991Sheppo /*
13881991Sheppo * Poll for the vldc channel to be ready
13891991Sheppo */
13901991Sheppo if (poll(&pollfd, 1, glvc_timeout * MILLISEC) <= 0) {
13911991Sheppo return (-1);
13921991Sheppo }
13931991Sheppo
13941991Sheppo do {
13951991Sheppo if ((res = write(fd, bufp, left)) <= 0) {
13961991Sheppo if (errno != EWOULDBLOCK) {
13971991Sheppo return (res);
13981991Sheppo }
13991991Sheppo } else {
14001991Sheppo bufp += res;
14011991Sheppo left -= res;
14021991Sheppo }
14031991Sheppo } while (left > 0);
14041991Sheppo
14051991Sheppo /*
14061991Sheppo * Return number of bytes actually written
14071991Sheppo */
14081991Sheppo return (size - left);
14091991Sheppo }
14101991Sheppo
14111991Sheppo /*
14121991Sheppo * Keep reading until we get the specified number of bytes
14131991Sheppo */
14141991Sheppo static int
vldc_read(int fd,uint8_t * bufp,int size)14151991Sheppo vldc_read(int fd, uint8_t *bufp, int size)
14161991Sheppo {
14171991Sheppo int res;
14181991Sheppo int left = size;
14191991Sheppo
14201991Sheppo struct pollfd fds[1];
14211991Sheppo
14221991Sheppo fds[0].events = POLLIN | POLLPRI;
14231991Sheppo fds[0].revents = 0;
14241991Sheppo fds[0].fd = fd;
14251991Sheppo
14261991Sheppo if (poll(fds, 1, glvc_timeout * MILLISEC) <= 0) {
14271991Sheppo return (-1);
14281991Sheppo }
14291991Sheppo
14301991Sheppo while (left > 0) {
14311991Sheppo res = read(fd, bufp, left);
14321991Sheppo /* return on error or short read */
14331991Sheppo if ((res == 0) || ((res < 0) &&
14341991Sheppo (errno == EAGAIN))) {
14351991Sheppo /* poll until the read is unblocked */
14361991Sheppo if ((poll(fds, 1, glvc_timeout * MILLISEC)) < 0)
14371991Sheppo return (-1);
14381991Sheppo
14391991Sheppo continue;
14401991Sheppo } else
14411991Sheppo if (res < 0) {
14421991Sheppo /* unrecoverable error */
14431991Sheppo
14441991Sheppo return (-1);
14451991Sheppo } else {
14461991Sheppo bufp += res;
14471991Sheppo left -= res;
14481991Sheppo }
14491991Sheppo }
14501991Sheppo
14511991Sheppo return (size - left);
14521991Sheppo }
1453