4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
22 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
27 * Platform Channel Protocol Library functions on Nigara platforms
28 * (Ontario, Erie, etc..) Solaris applications use these interfaces
29 * to communicate with entities that reside on service processor.
45 #include <sys/types.h>
50 #include <netinet/in.h>
53 #include "pcp_common.h"
54 #include "pcp_utils.h"
58 * Following libpcp interfaces are exposed to user applications.
60 * int pcp_init(char *channel_name);
61 * int pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg,
63 * int pcp_close(int channel_fd);
68 * Forward declarations.
70 static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t
*req_hdr
);
71 static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t
*resp_hdr
);
72 static int pcp_io_op(void *buf
, int byte_cnt
, int io_op
);
73 static uint32_t pcp_get_xid(void);
74 static int pcp_get_prop(int channel_fd
, int prop
, unsigned int *val
);
75 static int pcp_read(uint8_t *buf
, int buf_len
);
76 static int pcp_write(uint8_t *buf
, int buf_len
);
77 static int pcp_peek(uint8_t *buf
, int buf_len
);
78 static int pcp_peek_read(uint8_t *buf
, int buf_len
);
79 static int pcp_frame_error_handle(void);
80 static int check_magic_byte_presence(int byte_cnt
, uint8_t *byte_val
,
82 static uint16_t checksum(uint16_t *addr
, int32_t count
);
83 static int pcp_cleanup(int channel_fd
);
85 static int vldc_read(int fd
, uint8_t *bufp
, int size
);
86 static int vldc_write(int fd
, uint8_t *bufp
, int size
);
87 static int pcp_update_read_area(int byte_cnt
);
88 static int pcp_vldc_frame_error_handle(void);
91 * local channel (glvc) file descriptor set by pcp_send_recv()
93 static int chnl_fd
= -1;
96 * Message Transaction ID
98 static uint32_t msg_xid
= 0;
103 static unsigned int mtu_size
= PCPL_DEF_MTU_SZ
;
106 * timeout field is supplied by user. timeout field is used to decide
107 * how long to block on glvc driver calls before we return timeout error
108 * to user applications.
110 * Note: In the current implementation of glvc driver, all glvc calls are
113 static uint32_t glvc_timeout
= 0;
116 * variables used by setsetjmp/siglongjmp.
118 static volatile sig_atomic_t jumpok
= 0;
119 static sigjmp_buf jmpbuf
;
122 * To unblock SIGALRM signal incase if it's blocked in libpcp user apps.
123 * Restore it to old state during pcp_close.
125 static sigset_t blkset
;
128 * Buffers used for stream reading channel data. When data is read in
129 * stream fashion, first data is copied from channel (glvc) buffers to
130 * these local buffers from which the read requests are serviced.
132 #define READ_AREA_SIZE (2*mtu_size)
133 static uint8_t *read_head
= NULL
;
134 static uint8_t *read_tail
= NULL
;
135 static uint8_t *read_area
= NULL
;
138 * Buffer used for peeking new data available in channel (glvc) buffers.
140 #define PEEK_AREA_SIZE (mtu_size)
141 static uint8_t *peek_area
= NULL
;
144 * Buffers used for peeking data available either in local buffers or
145 * new data available in channel (glvc) buffers.
147 #define PEEK_READ_AREA_SIZE (2*mtu_size)
148 static uint8_t *peek_read_head
= NULL
;
149 static uint8_t *peek_read_tail
= NULL
;
150 static uint8_t *peek_read_area
= NULL
;
152 static pcp_req_msg_hdr_t
*req_msg_hdr
= NULL
;
153 static pcp_resp_msg_hdr_t
*resp_msg_hdr
= NULL
;
154 static int req_msg_hdr_sz
= 0;
155 static int resp_msg_hdr_sz
= 0;
158 * signal handling variables to handle glvc blocking calls.
160 static struct sigaction glvc_act
;
162 /* To restore old SIGALRM signal handler */
163 static struct sigaction old_act
;
166 * Variables to support vldc based streaming transport
168 static pcp_xport_t xport_type
= GLVC_NON_STREAM
;
169 #define VLDC_MTU_SIZE (2048)
172 glvc_timeout_handler(void)
176 siglongjmp(jmpbuf
, 1);
180 * Initialize the virtual channel. It basically opens the virtual channel
181 * provided by the host application.
186 pcp_init(char *channel_name
)
193 if (channel_name
== NULL
)
194 return (PCPL_INVALID_ARGS
);
197 * Given the argument, try to locate a device in the device tree
199 dev_path
= platsvc_name_to_path(channel_name
, &xport_type
);
204 if (NULL
== dev_path
)
205 return (PCPL_INVALID_ARGS
);
208 * Open virtual channel name.
210 if ((channel_fd
= open(dev_path
, O_RDWR
|O_EXCL
)) < 0) {
212 return (PCPL_GLVC_ERROR
);
218 * Handle transport-specific processing
220 switch (xport_type
) {
222 mtu_size
= VLDC_MTU_SIZE
;
224 op
.op_sel
= VLDC_OP_SET
;
225 op
.opt_sel
= VLDC_OPT_MODE
;
226 op
.opt_val
= LDC_MODE_RELIABLE
;
227 if (ioctl(channel_fd
, VLDC_IOCTL_OPT_OP
, &op
) != 0) {
228 (void) close(channel_fd
);
229 return (PCPL_GLVC_ERROR
);
232 case GLVC_NON_STREAM
:
235 * Get the Channel MTU size
238 if (pcp_get_prop(channel_fd
, GLVC_XPORT_OPT_MTU_SZ
,
240 (void) close(channel_fd
);
241 return (PCPL_GLVC_ERROR
);
247 * Get current signal mask. If SIGALRM is blocked
250 (void) sigprocmask(0, NULL
, &oldset
);
252 (void) sigemptyset(&blkset
);
254 if (sigismember(&oldset
, SIGALRM
)) {
255 (void) sigaddset(&blkset
, SIGALRM
);
256 (void) sigprocmask(SIG_UNBLOCK
, &blkset
, NULL
);
259 * signal handler initialization to handle glvc call timeouts.
261 glvc_act
.sa_handler
= glvc_timeout_handler
;
262 (void) sigemptyset(&glvc_act
.sa_mask
);
263 glvc_act
.sa_flags
= SA_NODEFER
;
265 if (sigaction(SIGALRM
, &glvc_act
, &old_act
) < 0) {
266 (void) close(channel_fd
);
274 * Function: Close platform channel.
276 * int channel_fd - channel file descriptor.
278 * always returns PCPL_OK for now.
281 pcp_close(int channel_fd
)
284 if (channel_fd
>= 0) {
285 if (xport_type
== GLVC_NON_STREAM
)
286 (void) pcp_cleanup(channel_fd
);
287 (void) close(channel_fd
);
293 * free global buffers
295 if (read_area
!= NULL
) {
296 umem_free(read_area
, READ_AREA_SIZE
);
299 if (peek_area
!= NULL
) {
300 umem_free(peek_area
, PEEK_AREA_SIZE
);
303 if (peek_read_area
!= NULL
) {
304 umem_free(peek_read_area
, PEEK_READ_AREA_SIZE
);
305 peek_read_area
= NULL
;
307 if (req_msg_hdr
!= NULL
) {
308 umem_free(req_msg_hdr
, req_msg_hdr_sz
);
311 if (resp_msg_hdr
!= NULL
) {
312 umem_free(resp_msg_hdr
, resp_msg_hdr_sz
);
317 * Restore SIGALRM signal mask incase if we unblocked
318 * it during pcp_init.
320 if (sigismember(&blkset
, SIGALRM
)) {
321 (void) sigprocmask(SIG_BLOCK
, &blkset
, NULL
);
324 /* Restore SIGALRM signal handler */
325 (void) sigaction(SIGALRM
, &old_act
, NULL
);
331 * Function: Send and Receive messages on platform channel.
333 * int channel_fd - channel file descriptor.
334 * pcp_msg_t *req_msg - Request Message to send to other end of channel.
335 * pcp_msg_t *resp_msg - Response Message to be received.
336 * uint32_t timeout - timeout field when waiting for data from channel.
338 * 0 - success (PCPL_OK).
340 * PCPL_INVALID_ARGS - invalid args.
341 * PCPL_GLVC_TIMEOUT - glvc call timeout.
342 * PCPL_XPORT_ERROR - transport error in request message
343 * noticed by receiver.
344 * PCPL_MALLOC_FAIL - malloc failure.
345 * PCPL_CKSUM_ERROR - checksum error.
348 pcp_send_recv(int channel_fd
, pcp_msg_t
*req_msg
, pcp_msg_t
*resp_msg
,
352 void *resp_msg_data
= NULL
;
357 #ifdef PCP_CKSUM_ENABLE
358 uint16_t bkup_resp_hdr_cksum
;
360 if (channel_fd
< 0) {
364 /* copy channel_fd to local fd (chnl_fd) for other functions use */
365 chnl_fd
= channel_fd
;
367 if (req_msg
== NULL
) {
368 return (PCPL_INVALID_ARGS
);
372 glvc_timeout
= timeout
;
376 if ((req_msg
->msg_len
!= 0) && ((datap
= req_msg
->msg_data
) == NULL
))
377 return (PCPL_INVALID_ARGS
);
379 if (req_msg_hdr
== NULL
) {
380 req_msg_hdr_sz
= sizeof (pcp_req_msg_hdr_t
);
381 req_msg_hdr
= (pcp_req_msg_hdr_t
*)umem_zalloc(req_msg_hdr_sz
,
383 if (req_msg_hdr
== NULL
)
384 return (PCPL_MALLOC_FAIL
);
387 if (req_msg
->msg_len
!= 0) {
388 /* calculate request msg_cksum */
389 cksum
= checksum((uint16_t *)datap
, req_msg
->msg_len
);
393 * Fill in the message header for the request packet
395 req_msg_hdr
->magic_num
= PCP_MAGIC_NUM
;
396 req_msg_hdr
->proto_ver
= PCP_PROT_VER_1
;
397 req_msg_hdr
->msg_type
= req_msg
->msg_type
;
398 req_msg_hdr
->sub_type
= req_msg
->sub_type
;
399 req_msg_hdr
->rsvd_pad
= 0;
400 req_msg_hdr
->xid
= pcp_get_xid();
401 req_msg_hdr
->msg_len
= req_msg
->msg_len
;
402 req_msg_hdr
->timeout
= timeout
;
403 req_msg_hdr
->msg_cksum
= cksum
;
404 req_msg_hdr
->hdr_cksum
= 0;
406 /* fill request header checksum */
407 req_msg_hdr
->hdr_cksum
= checksum((uint16_t *)req_msg_hdr
,
410 * set sig jmp location
412 if (sigsetjmp(jmpbuf
, 1)) {
413 return (PCPL_GLVC_TIMEOUT
);
415 jumpok
= 1; /* monitor sigalrm from now on */
418 * send request message header
420 if ((ret
= pcp_send_req_msg_hdr(req_msg_hdr
))) {
426 * send request message
428 if (req_msg
->msg_len
!= 0) {
429 if ((ret
= pcp_io_op(datap
, req_msg
->msg_len
,
430 PCPL_IO_OP_WRITE
))) {
435 if (timeout
== (uint32_t)PCP_TO_NO_RESPONSE
)
438 if (resp_msg_hdr
== NULL
) {
439 resp_msg_hdr_sz
= sizeof (pcp_resp_msg_hdr_t
);
440 resp_msg_hdr
= (pcp_resp_msg_hdr_t
*)umem_alloc(resp_msg_hdr_sz
,
442 if (resp_msg_hdr
== NULL
)
443 return (PCPL_MALLOC_FAIL
);
447 while (!resp_hdr_ok
) {
450 * Receive response message header
451 * Note: frame error handling is done in
452 * 'pcp_recv_resp_msg_hdr()'.
454 if ((ret
= pcp_recv_resp_msg_hdr(resp_msg_hdr
))) {
459 * Check header checksum if it matches with the received hdr
462 #ifdef PCP_CKSUM_ENABLE
463 bkup_resp_hdr_cksum
= resp_msg_hdr
->hdr_cksum
;
464 resp_msg_hdr
->hdr_cksum
= 0;
465 cksum
= checksum((uint16_t *)resp_msg_hdr
, resp_msg_hdr_sz
);
467 if (cksum
!= bkup_resp_hdr_cksum
) {
468 return (PCPL_CKSUM_ERROR
);
472 * Check for matching request and response messages
474 if (resp_msg_hdr
->xid
!= req_msg_hdr
->xid
) {
476 continue; /* continue reading response header */
482 * check status field for any channel protocol errors
483 * This field signifies something happend during request
484 * message trasmission. This field is set by the receiver.
486 status
= resp_msg_hdr
->status
;
487 if (status
!= PCP_OK
) {
488 return (PCPL_XPORT_ERROR
);
491 if (resp_msg_hdr
->msg_len
!= 0) {
493 /* libpcp users should free this memory */
494 if ((resp_msg_data
= (uint8_t *)malloc(resp_msg_hdr
->msg_len
))
496 return (PCPL_MALLOC_FAIL
);
497 bzero(resp_msg_data
, resp_msg_hdr
->msg_len
);
499 * Receive response message.
501 if ((ret
= pcp_io_op(resp_msg_data
, resp_msg_hdr
->msg_len
,
507 #ifdef PCP_CKSUM_ENABLE
508 /* verify response message data checksum */
509 cksum
= checksum((uint16_t *)resp_msg_data
,
510 resp_msg_hdr
->msg_len
);
511 if (cksum
!= resp_msg_hdr
->msg_cksum
) {
513 return (PCPL_CKSUM_ERROR
);
517 /* Everything is okay put the received data into user */
518 /* application's resp_msg struct */
519 resp_msg
->msg_len
= resp_msg_hdr
->msg_len
;
520 resp_msg
->msg_type
= resp_msg_hdr
->msg_type
;
521 resp_msg
->sub_type
= resp_msg_hdr
->sub_type
;
522 resp_msg
->msg_data
= (uint8_t *)resp_msg_data
;
529 * Function: Get channel property values.
531 * int channel_fd - channel file descriptor.
532 * int prop - property id.
533 * unsigned int *val - property value tobe copied.
537 * PCPL_ERR_GLVC - glvc ioctl failure.
541 pcp_get_prop(int channel_fd
, int prop
, unsigned int *val
)
543 glvc_xport_opt_op_t channel_op
;
546 channel_op
.op_sel
= GLVC_XPORT_OPT_GET
;
547 channel_op
.opt_sel
= prop
;
548 channel_op
.opt_val
= 0;
550 (void) alarm(glvc_timeout
);
552 if ((ret
= ioctl(channel_fd
, GLVC_XPORT_IOCTL_OPT_OP
,
560 *val
= channel_op
.opt_val
;
566 * Function: wrapper for handling glvc calls (read/write/peek).
569 pcp_io_op(void *buf
, int byte_cnt
, int io_op
)
574 int (*func_ptr
)(uint8_t *, int);
579 if ((buf
== NULL
) || (byte_cnt
< 0)) {
580 return (PCPL_INVALID_ARGS
);
584 case PCPL_IO_OP_READ
:
587 case PCPL_IO_OP_WRITE
:
588 func_ptr
= pcp_write
;
590 case PCPL_IO_OP_PEEK
:
594 return (PCPL_INVALID_ARGS
);
598 * loop until all I/O done, try limit exceded, or real failure
603 while (rv
< byte_cnt
) {
604 io_sz
= MIN((byte_cnt
- rv
), mtu_size
);
606 while ((n
= (*func_ptr
)(datap
, io_sz
)) < 0) {
608 if (try_cnt
> PCPL_MAX_TRY_CNT
) {
612 (void) sleep(PCPL_GLVC_SLEEP
);
613 } /* while trying the io operation */
621 } /* while still have more data */
627 return (PCPL_GLVC_ERROR
);
631 * For peeking 'bytes_cnt' bytes in channel (glvc) buffers.
632 * If data is available, the data is copied into 'buf'.
635 pcp_peek(uint8_t *buf
, int bytes_cnt
)
638 glvc_xport_msg_peek_t peek_ctrl
;
641 if (bytes_cnt
< 0 || bytes_cnt
> mtu_size
) {
642 return (PCPL_INVALID_ARGS
);
646 * initialization of buffers used for peeking data in channel buffers.
648 if (peek_area
== NULL
) {
649 peek_area
= (uint8_t *)umem_zalloc(PEEK_AREA_SIZE
,
651 if (peek_area
== NULL
) {
652 return (PCPL_MALLOC_FAIL
);
657 * peek max MTU size bytes
659 peek_ctrl
.buf
= (caddr_t
)peek_area
;
660 peek_ctrl
.buflen
= mtu_size
;
663 (void) alarm(glvc_timeout
);
665 if ((ret
= ioctl(chnl_fd
, GLVC_XPORT_IOCTL_DATA_PEEK
, &peek_ctrl
))
672 n
= peek_ctrl
.buflen
;
675 return (PCPL_GLVC_ERROR
);
678 * satisfy request as best as we can
680 m
= MIN(bytes_cnt
, n
);
681 (void) memcpy(buf
, peek_area
, m
);
687 * Function: write 'byte_cnt' bytes from 'buf' to channel.
690 pcp_write(uint8_t *buf
, int byte_cnt
)
695 /* check for valid arguments */
696 if (buf
== NULL
|| byte_cnt
< 0 || byte_cnt
> mtu_size
) {
697 return (PCPL_INVALID_ARGS
);
700 if (xport_type
== GLVC_NON_STREAM
) {
701 (void) alarm(glvc_timeout
);
703 if ((ret
= write(chnl_fd
, buf
, byte_cnt
)) < 0) {
709 if ((ret
= vldc_write(chnl_fd
, buf
, byte_cnt
)) <= 0) {
718 * In current implementaion of glvc driver, streams reads are not supported.
719 * pcp_read mimics stream reads by first reading all the bytes present in the
720 * channel buffer into a local buffer and from then on read requests
721 * are serviced from local buffer. When read requests are not serviceble
722 * from local buffer, it repeates by first reading data from channel buffers.
724 * This call may need to be enhanced when glvc supports buffered (stream)
729 pcp_read(uint8_t *buf
, int byte_cnt
)
734 if (byte_cnt
< 0 || byte_cnt
> mtu_size
) {
735 return (PCPL_INVALID_ARGS
);
739 * initialization of local read buffer
740 * from which the stream read requests are serviced.
742 if (read_area
== NULL
) {
743 read_area
= (uint8_t *)umem_zalloc(READ_AREA_SIZE
,
745 if (read_area
== NULL
) {
746 return (PCPL_MALLOC_FAIL
);
748 read_head
= read_area
;
749 read_tail
= read_area
;
753 * if we already read this data then copy from local buffer it self
754 * without calling new read.
756 if (byte_cnt
<= (read_tail
- read_head
)) {
757 (void) memcpy(buf
, read_head
, byte_cnt
);
758 read_head
+= byte_cnt
;
763 * if the request is not satisfied from the buffered data, then move the
764 * remaining data to front of the buffer and read new data.
766 for (i
= 0; i
< (read_tail
- read_head
); ++i
) {
767 read_area
[i
] = read_head
[i
];
769 read_head
= read_area
;
770 read_tail
= read_head
+ i
;
773 * do a peek to see how much data is available and read complete data.
776 if (xport_type
== GLVC_NON_STREAM
) {
777 if ((m
= pcp_peek(read_tail
, mtu_size
)) < 0) {
781 (void) alarm(glvc_timeout
);
782 if ((ret
= read(chnl_fd
, read_tail
, m
)) < 0) {
790 * Read the extra number of bytes
792 m
= byte_cnt
- (read_tail
- read_head
);
793 if ((ret
= vldc_read(chnl_fd
,
794 read_tail
, m
)) <= 0) {
801 * copy the requested bytes.
803 n
= MIN(byte_cnt
, (read_tail
- read_head
));
804 (void) memcpy(buf
, read_head
, n
);
812 * Issue read from the driver until byet_cnt number
813 * of bytes are present in read buffer. Do not
814 * move the read head.
817 pcp_update_read_area(int byte_cnt
)
822 if (byte_cnt
< 0 || byte_cnt
> mtu_size
) {
823 return (PCPL_INVALID_ARGS
);
827 * initialization of local read buffer
828 * from which the stream read requests are serviced.
830 if (read_area
== NULL
) {
831 read_area
= (uint8_t *)umem_zalloc(READ_AREA_SIZE
,
833 if (read_area
== NULL
) {
834 return (PCPL_MALLOC_FAIL
);
836 read_head
= read_area
;
837 read_tail
= read_area
;
841 * if we already have sufficient data in the buffer,
844 if (byte_cnt
<= (read_tail
- read_head
)) {
849 * if the request is not satisfied from the buffered data, then move the
850 * remaining data to front of the buffer and read new data.
852 for (i
= 0; i
< (read_tail
- read_head
); ++i
) {
853 read_area
[i
] = read_head
[i
];
855 read_head
= read_area
;
856 read_tail
= read_head
+ i
;
858 n
= byte_cnt
- (read_tail
- read_head
);
860 if ((ret
= vldc_read(chnl_fd
,
861 read_tail
, n
)) <= 0) {
867 * Return the number of bytes we could read
869 n
= MIN(byte_cnt
, (read_tail
- read_head
));
875 * This function is slight different from pcp_peek. The peek requests are first
876 * serviced from local read buffer, if data is available. If the peek request
877 * is not serviceble from local read buffer, then the data is peeked from
878 * channel buffer. This function is mainly used for proper protocol framing
882 pcp_peek_read(uint8_t *buf
, int byte_cnt
)
886 if (byte_cnt
< 0 || byte_cnt
> mtu_size
) {
887 return (PCPL_INVALID_ARGS
);
891 * initialization of peek_read buffer.
893 if (peek_read_area
== NULL
) {
894 peek_read_area
= (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE
,
896 if (peek_read_area
== NULL
) {
897 return (PCPL_MALLOC_FAIL
);
899 peek_read_head
= peek_read_area
;
900 peek_read_tail
= peek_read_area
;
904 * if we already have the data in local read buffer then copy
905 * from local buffer it self w/out calling new peek
907 if (byte_cnt
<= (read_tail
- read_head
)) {
908 (void) memcpy(buf
, read_head
, byte_cnt
);
913 * if the request is not satisfied from local read buffer, then first
914 * copy the remaining data in local read buffer to peek_read_area and
915 * then issue new peek.
917 for (i
= 0; i
< (read_tail
- read_head
); ++i
) {
918 peek_read_area
[i
] = read_head
[i
];
920 peek_read_head
= peek_read_area
;
921 peek_read_tail
= peek_read_head
+ i
;
924 * do a peek to see how much data is available and read complete data.
927 if ((m
= pcp_peek(peek_read_tail
, mtu_size
)) < 0) {
933 * copy the requested bytes
935 n
= MIN(byte_cnt
, (peek_read_tail
- peek_read_head
));
936 (void) memcpy(buf
, peek_read_head
, n
);
942 * Send Request Message Header.
945 pcp_send_req_msg_hdr(pcp_req_msg_hdr_t
*req_hdr
)
947 pcp_req_msg_hdr_t
*hdrp
;
951 hdr_sz
= sizeof (pcp_req_msg_hdr_t
);
952 if ((hdrp
= (pcp_req_msg_hdr_t
*)umem_zalloc(hdr_sz
,
953 UMEM_DEFAULT
)) == NULL
) {
954 return (PCPL_MALLOC_FAIL
);
957 hdrp
->magic_num
= htonl(req_hdr
->magic_num
);
958 hdrp
->proto_ver
= req_hdr
->proto_ver
;
959 hdrp
->msg_type
= req_hdr
->msg_type
;
960 hdrp
->sub_type
= req_hdr
->sub_type
;
961 hdrp
->rsvd_pad
= htons(req_hdr
->rsvd_pad
);
962 hdrp
->xid
= htonl(req_hdr
->xid
);
963 hdrp
->timeout
= htonl(req_hdr
->timeout
);
964 hdrp
->msg_len
= htonl(req_hdr
->msg_len
);
965 hdrp
->msg_cksum
= htons(req_hdr
->msg_cksum
);
966 hdrp
->hdr_cksum
= htons(req_hdr
->hdr_cksum
);
968 if ((ret
= pcp_io_op((char *)hdrp
, hdr_sz
, PCPL_IO_OP_WRITE
)) != 0) {
969 umem_free(hdrp
, hdr_sz
);
972 umem_free(hdrp
, hdr_sz
);
977 * Receive Response message header.
980 pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t
*resp_hdr
)
995 if (resp_hdr
== NULL
) {
996 return (PCPL_INVALID_ARGS
);
1000 * handle protocol framing errors.
1001 * pcp_frame_error_handle() returns when proper frame arrived
1002 * (magic seq) or if an error happens while reading data from
1005 if (xport_type
== GLVC_NON_STREAM
)
1006 ret
= pcp_frame_error_handle();
1008 ret
= pcp_vldc_frame_error_handle();
1011 return (PCPL_FRAME_ERROR
);
1013 /* read magic number first */
1014 if ((ret
= pcp_io_op(&magic_num
, sizeof (magic_num
),
1015 PCPL_IO_OP_READ
)) != 0) {
1019 magic_num
= ntohl(magic_num
);
1021 if (magic_num
!= PCP_MAGIC_NUM
) {
1022 return (PCPL_FRAME_ERROR
);
1025 /* read version field */
1026 if ((ret
= pcp_io_op(&proto_ver
, sizeof (proto_ver
),
1027 PCPL_IO_OP_READ
)) != 0) {
1031 /* check protocol version */
1032 if (proto_ver
!= PCP_PROT_VER_1
) {
1033 return (PCPL_PROT_ERROR
);
1036 /* Read message type */
1037 if ((ret
= pcp_io_op(&msg_type
, sizeof (msg_type
),
1038 PCPL_IO_OP_READ
)) != 0) {
1042 /* Read message sub type */
1043 if ((ret
= pcp_io_op(&sub_type
, sizeof (sub_type
),
1044 PCPL_IO_OP_READ
)) != 0) {
1048 /* Read rcvd_pad bits */
1049 if ((ret
= pcp_io_op(&rsvd_pad
, sizeof (rsvd_pad
),
1050 PCPL_IO_OP_READ
)) != 0) {
1054 /* receive transaction id */
1055 if ((ret
= pcp_io_op(&xid
, sizeof (xid
),
1056 PCPL_IO_OP_READ
)) != 0) {
1062 /* receive timeout value */
1063 if ((ret
= pcp_io_op(&timeout
, sizeof (timeout
),
1064 PCPL_IO_OP_READ
)) != 0) {
1068 timeout
= ntohl(timeout
);
1070 /* receive message length */
1071 if ((ret
= pcp_io_op(&msg_len
, sizeof (msg_len
),
1072 PCPL_IO_OP_READ
)) != 0) {
1076 msg_len
= ntohl(msg_len
);
1078 /* receive status field */
1079 if ((ret
= pcp_io_op(&status
, sizeof (status
),
1080 PCPL_IO_OP_READ
)) != 0) {
1084 status
= ntohl(status
);
1086 /* receive message checksum */
1087 if ((ret
= pcp_io_op(&msg_cksum
, sizeof (msg_cksum
),
1088 PCPL_IO_OP_READ
)) != 0) {
1092 msg_cksum
= ntohs(msg_cksum
);
1094 /* receive header checksum */
1095 if ((ret
= pcp_io_op(&hdr_cksum
, sizeof (hdr_cksum
),
1096 PCPL_IO_OP_READ
)) != 0) {
1100 hdr_cksum
= ntohs(hdr_cksum
);
1102 /* copy to resp_hdr */
1104 resp_hdr
->magic_num
= magic_num
;
1105 resp_hdr
->proto_ver
= proto_ver
;
1106 resp_hdr
->msg_type
= msg_type
;
1107 resp_hdr
->sub_type
= sub_type
;
1108 resp_hdr
->rsvd_pad
= rsvd_pad
;
1109 resp_hdr
->xid
= xid
;
1110 resp_hdr
->timeout
= timeout
;
1111 resp_hdr
->msg_len
= msg_len
;
1112 resp_hdr
->status
= status
;
1113 resp_hdr
->msg_cksum
= msg_cksum
;
1114 resp_hdr
->hdr_cksum
= hdr_cksum
;
1120 * Get next xid for including in request message.
1121 * Every request and response message are matched
1130 static boolean_t xid_initialized
= B_FALSE
;
1132 if (xid_initialized
== B_FALSE
) {
1133 xid_initialized
= B_TRUE
;
1135 * starting xid is initialized to a different value everytime
1136 * user application is restarted so that user apps will not
1137 * receive previous session's packets.
1139 * Note: The algorithm for generating initial xid is partially
1140 * taken from Solaris rpc code.
1142 (void) gettimeofday(&tv
, NULL
);
1143 msg_xid
= (uint32_t)((tv
.tv_sec
<< 20) |
1144 (tv
.tv_usec
>> 10));
1149 /* zero xid is not allowed */
1157 * This function handles channel framing errors. It waits until proper
1158 * frame with starting sequence as magic numder (0xAFBCAFA0)
1159 * is arrived. It removes unexpected data (before the magic number sequence)
1160 * on the channel. It returns when proper magic number sequence is seen
1161 * or when any failure happens while reading/peeking the channel.
1164 pcp_frame_error_handle(void)
1166 uint8_t magic_num_buf
[4];
1168 uint32_t net_magic_num
; /* magic byte in network byte order */
1169 uint32_t host_magic_num
= PCP_MAGIC_NUM
;
1172 net_magic_num
= htonl(host_magic_num
);
1173 (void) memcpy(magic_num_buf
, (uint8_t *)&net_magic_num
, 4);
1175 while (!ispresent
) {
1177 * Check if next four bytes matches pcp magic number.
1178 * if mathing not found, discard 1 byte and continue checking.
1180 if (!check_magic_byte_presence(4, &magic_num_buf
[0],
1184 (void) pcp_io_op(buf
, 1, PCPL_IO_OP_READ
);
1195 * This function handles channel framing errors. It waits until proper
1196 * frame with starting sequence as magic numder (0xAFBCAFA0)
1197 * is arrived. It removes unexpected data (before the magic number sequence)
1198 * on the channel. It returns when proper magic number sequence is seen
1199 * or when any failure happens while reading/peeking the channel.
1202 pcp_vldc_frame_error_handle(void)
1204 uint8_t magic_num_buf
[4];
1205 uint32_t net_magic_num
; /* magic byte in network byte order */
1206 uint32_t host_magic_num
= PCP_MAGIC_NUM
;
1207 int found_magic
= 0;
1209 net_magic_num
= htonl(host_magic_num
);
1210 (void) memcpy(magic_num_buf
, (uint8_t *)&net_magic_num
, 4);
1213 * For vldc, we need to read whatever data is available and
1214 * advance the read pointer one byte at a time until we get
1215 * the magic word. When this function is invoked, we do not
1216 * have any byte in the read buffer.
1220 * Keep reading until we find the matching magic number
1222 while (!found_magic
) {
1223 while ((read_tail
- read_head
) < sizeof (host_magic_num
)) {
1224 if (pcp_update_read_area(sizeof (host_magic_num
)) < 0)
1229 * We should have at least 4 bytes in read buffer. Check
1230 * if the magic number can be matched
1232 if (memcmp(read_head
, magic_num_buf
,
1233 sizeof (host_magic_num
))) {
1244 * checks whether certain byte sequence is present in the data stream.
1247 check_magic_byte_presence(int byte_cnt
, uint8_t *byte_seq
, int *ispresent
)
1252 if ((ret
= pcp_peek_read(buf
, byte_cnt
)) < 0) {
1256 /* 'byte_cnt' bytes not present */
1257 if (ret
!= byte_cnt
) {
1262 for (i
= 0; i
< byte_cnt
; ++i
) {
1263 if (buf
[i
] != byte_seq
[i
]) {
1274 * 16-bit simple internet checksum
1277 checksum(uint16_t *addr
, int32_t count
)
1280 * Compute Internet Checksum for "count" bytes
1281 * beginning at location "addr".
1284 register uint32_t sum
= 0;
1287 /* This is the inner loop */
1288 sum
+= *(unsigned short *)addr
++;
1292 /* Add left-over byte, if any */
1294 sum
+= * (unsigned char *)addr
;
1296 /* Fold 32-bit sum to 16 bits */
1298 sum
= (sum
& 0xffff) + (sum
>> 16);
1300 sum
= (~sum
) & 0xffff;
1308 * cleanup the channel if any data is hanging in
1312 pcp_cleanup(int channel_fd
)
1315 glvc_xport_msg_peek_t peek_ctrl
;
1317 uint8_t *buf
= NULL
;
1321 buf
= (uint8_t *)umem_zalloc((mtu_size
), UMEM_DEFAULT
);
1323 return (PCPL_MALLOC_FAIL
);
1326 peek_ctrl
.buf
= (caddr_t
)buf
;
1327 peek_ctrl
.buflen
= mtu_size
;
1328 peek_ctrl
.flags
= 0;
1331 * set sig jmp location
1333 if (sigsetjmp(jmpbuf
, 1)) {
1334 umem_free(buf
, mtu_size
);
1335 return (PCPL_GLVC_TIMEOUT
);
1341 (void) alarm(PCP_CLEANUP_TIMEOUT
);
1342 if ((ret
= ioctl(channel_fd
, GLVC_XPORT_IOCTL_DATA_PEEK
,
1350 n
= peek_ctrl
.buflen
;
1352 if (n
<= 0 && retry
> 2) {
1355 } else if (n
<= 0) {
1360 /* remove data from channel */
1361 (void) alarm(PCP_CLEANUP_TIMEOUT
);
1362 if ((ret
= read(channel_fd
, buf
, n
)) < 0) {
1370 umem_free(buf
, mtu_size
);
1375 vldc_write(int fd
, uint8_t *bufp
, int size
)
1381 pollfd
.events
= POLLOUT
;
1386 * Poll for the vldc channel to be ready
1388 if (poll(&pollfd
, 1, glvc_timeout
* MILLISEC
) <= 0) {
1393 if ((res
= write(fd
, bufp
, left
)) <= 0) {
1394 if (errno
!= EWOULDBLOCK
) {
1404 * Return number of bytes actually written
1406 return (size
- left
);
1410 * Keep reading until we get the specified number of bytes
1413 vldc_read(int fd
, uint8_t *bufp
, int size
)
1418 struct pollfd fds
[1];
1420 fds
[0].events
= POLLIN
| POLLPRI
;
1424 if (poll(fds
, 1, glvc_timeout
* MILLISEC
) <= 0) {
1429 res
= read(fd
, bufp
, left
);
1430 /* return on error or short read */
1431 if ((res
== 0) || ((res
< 0) &&
1432 (errno
== EAGAIN
))) {
1433 /* poll until the read is unblocked */
1434 if ((poll(fds
, 1, glvc_timeout
* MILLISEC
)) < 0)
1440 /* unrecoverable error */
1449 return (size
- left
);