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.
32 #pragma ident "%Z%%M% %I% %E% SMI"
47 #include <sys/types.h>
52 #include <netinet/in.h>
55 #include "pcp_common.h"
56 #include "pcp_utils.h"
60 * Following libpcp interfaces are exposed to user applications.
62 * int pcp_init(char *channel_name);
63 * int pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg,
65 * int pcp_close(int channel_fd);
70 * Forward declarations.
72 static int pcp_send_req_msg_hdr(pcp_req_msg_hdr_t
*req_hdr
);
73 static int pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t
*resp_hdr
);
74 static int pcp_io_op(void *buf
, int byte_cnt
, int io_op
);
75 static uint32_t pcp_get_xid(void);
76 static int pcp_get_prop(int channel_fd
, int prop
, unsigned int *val
);
77 static int pcp_read(uint8_t *buf
, int buf_len
);
78 static int pcp_write(uint8_t *buf
, int buf_len
);
79 static int pcp_peek(uint8_t *buf
, int buf_len
);
80 static int pcp_peek_read(uint8_t *buf
, int buf_len
);
81 static int pcp_frame_error_handle(void);
82 static int check_magic_byte_presence(int byte_cnt
, uint8_t *byte_val
,
84 static uint16_t checksum(uint16_t *addr
, int32_t count
);
85 static int pcp_cleanup(int channel_fd
);
87 static int vldc_read(int fd
, uint8_t *bufp
, int size
);
88 static int vldc_write(int fd
, uint8_t *bufp
, int size
);
89 static int pcp_update_read_area(int byte_cnt
);
90 static int pcp_vldc_frame_error_handle(void);
93 * local channel (glvc) file descriptor set by pcp_send_recv()
95 static int chnl_fd
= -1;
98 * Message Transaction ID
100 static uint32_t msg_xid
= 0;
105 static unsigned int mtu_size
= PCPL_DEF_MTU_SZ
;
108 * timeout field is supplied by user. timeout field is used to decide
109 * how long to block on glvc driver calls before we return timeout error
110 * to user applications.
112 * Note: In the current implementation of glvc driver, all glvc calls are
115 static uint32_t glvc_timeout
= 0;
118 * variables used by setsetjmp/siglongjmp.
120 static volatile sig_atomic_t jumpok
= 0;
121 static sigjmp_buf jmpbuf
;
124 * To unblock SIGALRM signal incase if it's blocked in libpcp user apps.
125 * Restore it to old state during pcp_close.
127 static sigset_t blkset
;
130 * Buffers used for stream reading channel data. When data is read in
131 * stream fashion, first data is copied from channel (glvc) buffers to
132 * these local buffers from which the read requests are serviced.
134 #define READ_AREA_SIZE (2*mtu_size)
135 static uint8_t *read_head
= NULL
;
136 static uint8_t *read_tail
= NULL
;
137 static uint8_t *read_area
= NULL
;
140 * Buffer used for peeking new data available in channel (glvc) buffers.
142 #define PEEK_AREA_SIZE (mtu_size)
143 static uint8_t *peek_area
= NULL
;
146 * Buffers used for peeking data available either in local buffers or
147 * new data available in channel (glvc) buffers.
149 #define PEEK_READ_AREA_SIZE (2*mtu_size)
150 static uint8_t *peek_read_head
= NULL
;
151 static uint8_t *peek_read_tail
= NULL
;
152 static uint8_t *peek_read_area
= NULL
;
154 static pcp_req_msg_hdr_t
*req_msg_hdr
= NULL
;
155 static pcp_resp_msg_hdr_t
*resp_msg_hdr
= NULL
;
156 static int req_msg_hdr_sz
= 0;
157 static int resp_msg_hdr_sz
= 0;
160 * signal handling variables to handle glvc blocking calls.
162 static struct sigaction glvc_act
;
164 /* To restore old SIGALRM signal handler */
165 static struct sigaction old_act
;
168 * Variables to support vldc based streaming transport
170 static pcp_xport_t xport_type
= GLVC_NON_STREAM
;
171 #define VLDC_MTU_SIZE (2048)
174 glvc_timeout_handler(void)
178 siglongjmp(jmpbuf
, 1);
182 * Initialize the virtual channel. It basically opens the virtual channel
183 * provided by the host application.
188 pcp_init(char *channel_name
)
195 if (channel_name
== NULL
)
196 return (PCPL_INVALID_ARGS
);
199 * Given the argument, try to locate a device in the device tree
201 dev_path
= platsvc_name_to_path(channel_name
, &xport_type
);
206 if (NULL
== dev_path
)
207 return (PCPL_INVALID_ARGS
);
210 * Open virtual channel name.
212 if ((channel_fd
= open(dev_path
, O_RDWR
|O_EXCL
)) < 0) {
214 return (PCPL_GLVC_ERROR
);
220 * Handle transport-specific processing
222 switch (xport_type
) {
224 mtu_size
= VLDC_MTU_SIZE
;
226 op
.op_sel
= VLDC_OP_SET
;
227 op
.opt_sel
= VLDC_OPT_MODE
;
228 op
.opt_val
= LDC_MODE_RELIABLE
;
229 if (ioctl(channel_fd
, VLDC_IOCTL_OPT_OP
, &op
) != 0) {
230 (void) close(channel_fd
);
231 return (PCPL_GLVC_ERROR
);
234 case GLVC_NON_STREAM
:
237 * Get the Channel MTU size
240 if (pcp_get_prop(channel_fd
, GLVC_XPORT_OPT_MTU_SZ
,
242 (void) close(channel_fd
);
243 return (PCPL_GLVC_ERROR
);
249 * Get current signal mask. If SIGALRM is blocked
252 (void) sigprocmask(0, NULL
, &oldset
);
254 (void) sigemptyset(&blkset
);
256 if (sigismember(&oldset
, SIGALRM
)) {
257 (void) sigaddset(&blkset
, SIGALRM
);
258 (void) sigprocmask(SIG_UNBLOCK
, &blkset
, NULL
);
261 * signal handler initialization to handle glvc call timeouts.
263 glvc_act
.sa_handler
= glvc_timeout_handler
;
264 (void) sigemptyset(&glvc_act
.sa_mask
);
265 glvc_act
.sa_flags
= SA_NODEFER
;
267 if (sigaction(SIGALRM
, &glvc_act
, &old_act
) < 0) {
268 (void) close(channel_fd
);
276 * Function: Close platform channel.
278 * int channel_fd - channel file descriptor.
280 * always returns PCPL_OK for now.
283 pcp_close(int channel_fd
)
286 if (channel_fd
>= 0) {
287 if (xport_type
== GLVC_NON_STREAM
)
288 (void) pcp_cleanup(channel_fd
);
289 (void) close(channel_fd
);
295 * free global buffers
297 if (read_area
!= NULL
) {
298 umem_free(read_area
, READ_AREA_SIZE
);
301 if (peek_area
!= NULL
) {
302 umem_free(peek_area
, PEEK_AREA_SIZE
);
305 if (peek_read_area
!= NULL
) {
306 umem_free(peek_read_area
, PEEK_READ_AREA_SIZE
);
307 peek_read_area
= NULL
;
309 if (req_msg_hdr
!= NULL
) {
310 umem_free(req_msg_hdr
, req_msg_hdr_sz
);
313 if (resp_msg_hdr
!= NULL
) {
314 umem_free(resp_msg_hdr
, resp_msg_hdr_sz
);
319 * Restore SIGALRM signal mask incase if we unblocked
320 * it during pcp_init.
322 if (sigismember(&blkset
, SIGALRM
)) {
323 (void) sigprocmask(SIG_BLOCK
, &blkset
, NULL
);
326 /* Restore SIGALRM signal handler */
327 (void) sigaction(SIGALRM
, &old_act
, NULL
);
333 * Function: Send and Receive messages on platform channel.
335 * int channel_fd - channel file descriptor.
336 * pcp_msg_t *req_msg - Request Message to send to other end of channel.
337 * pcp_msg_t *resp_msg - Response Message to be received.
338 * uint32_t timeout - timeout field when waiting for data from channel.
340 * 0 - success (PCPL_OK).
342 * PCPL_INVALID_ARGS - invalid args.
343 * PCPL_GLVC_TIMEOUT - glvc call timeout.
344 * PCPL_XPORT_ERROR - transport error in request message
345 * noticed by receiver.
346 * PCPL_MALLOC_FAIL - malloc failure.
347 * PCPL_CKSUM_ERROR - checksum error.
350 pcp_send_recv(int channel_fd
, pcp_msg_t
*req_msg
, pcp_msg_t
*resp_msg
,
354 void *resp_msg_data
= NULL
;
359 #ifdef PCP_CKSUM_ENABLE
360 uint16_t bkup_resp_hdr_cksum
;
362 if (channel_fd
< 0) {
366 /* copy channel_fd to local fd (chnl_fd) for other functions use */
367 chnl_fd
= channel_fd
;
369 if (req_msg
== NULL
) {
370 return (PCPL_INVALID_ARGS
);
374 glvc_timeout
= timeout
;
378 if ((req_msg
->msg_len
!= 0) && ((datap
= req_msg
->msg_data
) == NULL
))
379 return (PCPL_INVALID_ARGS
);
381 if (req_msg_hdr
== NULL
) {
382 req_msg_hdr_sz
= sizeof (pcp_req_msg_hdr_t
);
383 req_msg_hdr
= (pcp_req_msg_hdr_t
*)umem_zalloc(req_msg_hdr_sz
,
385 if (req_msg_hdr
== NULL
)
386 return (PCPL_MALLOC_FAIL
);
389 if (req_msg
->msg_len
!= 0) {
390 /* calculate request msg_cksum */
391 cksum
= checksum((uint16_t *)datap
, req_msg
->msg_len
);
395 * Fill in the message header for the request packet
397 req_msg_hdr
->magic_num
= PCP_MAGIC_NUM
;
398 req_msg_hdr
->proto_ver
= PCP_PROT_VER_1
;
399 req_msg_hdr
->msg_type
= req_msg
->msg_type
;
400 req_msg_hdr
->sub_type
= req_msg
->sub_type
;
401 req_msg_hdr
->rsvd_pad
= 0;
402 req_msg_hdr
->xid
= pcp_get_xid();
403 req_msg_hdr
->msg_len
= req_msg
->msg_len
;
404 req_msg_hdr
->timeout
= timeout
;
405 req_msg_hdr
->msg_cksum
= cksum
;
406 req_msg_hdr
->hdr_cksum
= 0;
408 /* fill request header checksum */
409 req_msg_hdr
->hdr_cksum
= checksum((uint16_t *)req_msg_hdr
,
412 * set sig jmp location
414 if (sigsetjmp(jmpbuf
, 1)) {
415 return (PCPL_GLVC_TIMEOUT
);
417 jumpok
= 1; /* monitor sigalrm from now on */
420 * send request message header
422 if ((ret
= pcp_send_req_msg_hdr(req_msg_hdr
))) {
428 * send request message
430 if (req_msg
->msg_len
!= 0) {
431 if ((ret
= pcp_io_op(datap
, req_msg
->msg_len
,
432 PCPL_IO_OP_WRITE
))) {
437 if (timeout
== (uint32_t)PCP_TO_NO_RESPONSE
)
440 if (resp_msg_hdr
== NULL
) {
441 resp_msg_hdr_sz
= sizeof (pcp_resp_msg_hdr_t
);
442 resp_msg_hdr
= (pcp_resp_msg_hdr_t
*)umem_alloc(resp_msg_hdr_sz
,
444 if (resp_msg_hdr
== NULL
)
445 return (PCPL_MALLOC_FAIL
);
449 while (!resp_hdr_ok
) {
452 * Receive response message header
453 * Note: frame error handling is done in
454 * 'pcp_recv_resp_msg_hdr()'.
456 if ((ret
= pcp_recv_resp_msg_hdr(resp_msg_hdr
))) {
461 * Check header checksum if it matches with the received hdr
464 #ifdef PCP_CKSUM_ENABLE
465 bkup_resp_hdr_cksum
= resp_msg_hdr
->hdr_cksum
;
466 resp_msg_hdr
->hdr_cksum
= 0;
467 cksum
= checksum((uint16_t *)resp_msg_hdr
, resp_msg_hdr_sz
);
469 if (cksum
!= bkup_resp_hdr_cksum
) {
470 return (PCPL_CKSUM_ERROR
);
474 * Check for matching request and response messages
476 if (resp_msg_hdr
->xid
!= req_msg_hdr
->xid
) {
478 continue; /* continue reading response header */
484 * check status field for any channel protocol errrors
485 * This field signifies something happend during request
486 * message trasmission. This field is set by the receiver.
488 status
= resp_msg_hdr
->status
;
489 if (status
!= PCP_OK
) {
490 return (PCPL_XPORT_ERROR
);
493 if (resp_msg_hdr
->msg_len
!= 0) {
495 /* libpcp users should free this memory */
496 if ((resp_msg_data
= (uint8_t *)malloc(resp_msg_hdr
->msg_len
))
498 return (PCPL_MALLOC_FAIL
);
499 bzero(resp_msg_data
, resp_msg_hdr
->msg_len
);
501 * Receive response message.
503 if ((ret
= pcp_io_op(resp_msg_data
, resp_msg_hdr
->msg_len
,
509 #ifdef PCP_CKSUM_ENABLE
510 /* verify response message data checksum */
511 cksum
= checksum((uint16_t *)resp_msg_data
,
512 resp_msg_hdr
->msg_len
);
513 if (cksum
!= resp_msg_hdr
->msg_cksum
) {
515 return (PCPL_CKSUM_ERROR
);
519 /* Everything is okay put the received data into user */
520 /* application's resp_msg struct */
521 resp_msg
->msg_len
= resp_msg_hdr
->msg_len
;
522 resp_msg
->msg_type
= resp_msg_hdr
->msg_type
;
523 resp_msg
->sub_type
= resp_msg_hdr
->sub_type
;
524 resp_msg
->msg_data
= (uint8_t *)resp_msg_data
;
531 * Function: Get channel property values.
533 * int channel_fd - channel file descriptor.
534 * int prop - property id.
535 * unsigned int *val - property value tobe copied.
539 * PCPL_ERR_GLVC - glvc ioctl failure.
543 pcp_get_prop(int channel_fd
, int prop
, unsigned int *val
)
545 glvc_xport_opt_op_t channel_op
;
548 channel_op
.op_sel
= GLVC_XPORT_OPT_GET
;
549 channel_op
.opt_sel
= prop
;
550 channel_op
.opt_val
= 0;
552 (void) alarm(glvc_timeout
);
554 if ((ret
= ioctl(channel_fd
, GLVC_XPORT_IOCTL_OPT_OP
,
562 *val
= channel_op
.opt_val
;
568 * Function: wrapper for handling glvc calls (read/write/peek).
571 pcp_io_op(void *buf
, int byte_cnt
, int io_op
)
576 int (*func_ptr
)(uint8_t *, int);
581 if ((buf
== NULL
) || (byte_cnt
< 0)) {
582 return (PCPL_INVALID_ARGS
);
586 case PCPL_IO_OP_READ
:
589 case PCPL_IO_OP_WRITE
:
590 func_ptr
= pcp_write
;
592 case PCPL_IO_OP_PEEK
:
596 return (PCPL_INVALID_ARGS
);
600 * loop until all I/O done, try limit exceded, or real failure
605 while (rv
< byte_cnt
) {
606 io_sz
= MIN((byte_cnt
- rv
), mtu_size
);
608 while ((n
= (*func_ptr
)(datap
, io_sz
)) < 0) {
610 if (try_cnt
> PCPL_MAX_TRY_CNT
) {
614 (void) sleep(PCPL_GLVC_SLEEP
);
615 } /* while trying the io operation */
623 } /* while still have more data */
629 return (PCPL_GLVC_ERROR
);
633 * For peeking 'bytes_cnt' bytes in channel (glvc) buffers.
634 * If data is available, the data is copied into 'buf'.
637 pcp_peek(uint8_t *buf
, int bytes_cnt
)
640 glvc_xport_msg_peek_t peek_ctrl
;
643 if (bytes_cnt
< 0 || bytes_cnt
> mtu_size
) {
644 return (PCPL_INVALID_ARGS
);
648 * initialization of buffers used for peeking data in channel buffers.
650 if (peek_area
== NULL
) {
651 peek_area
= (uint8_t *)umem_zalloc(PEEK_AREA_SIZE
,
653 if (peek_area
== NULL
) {
654 return (PCPL_MALLOC_FAIL
);
659 * peek max MTU size bytes
661 peek_ctrl
.buf
= (caddr_t
)peek_area
;
662 peek_ctrl
.buflen
= mtu_size
;
665 (void) alarm(glvc_timeout
);
667 if ((ret
= ioctl(chnl_fd
, GLVC_XPORT_IOCTL_DATA_PEEK
, &peek_ctrl
))
674 n
= peek_ctrl
.buflen
;
677 return (PCPL_GLVC_ERROR
);
680 * satisfy request as best as we can
682 m
= MIN(bytes_cnt
, n
);
683 (void) memcpy(buf
, peek_area
, m
);
689 * Function: write 'byte_cnt' bytes from 'buf' to channel.
692 pcp_write(uint8_t *buf
, int byte_cnt
)
697 /* check for valid arguments */
698 if (buf
== NULL
|| byte_cnt
< 0 || byte_cnt
> mtu_size
) {
699 return (PCPL_INVALID_ARGS
);
702 if (xport_type
== GLVC_NON_STREAM
) {
703 (void) alarm(glvc_timeout
);
705 if ((ret
= write(chnl_fd
, buf
, byte_cnt
)) < 0) {
711 if ((ret
= vldc_write(chnl_fd
, buf
, byte_cnt
)) <= 0) {
720 * In current implementaion of glvc driver, streams reads are not supported.
721 * pcp_read mimics stream reads by first reading all the bytes present in the
722 * channel buffer into a local buffer and from then on read requests
723 * are serviced from local buffer. When read requests are not serviceble
724 * from local buffer, it repeates by first reading data from channel buffers.
726 * This call may need to be enhanced when glvc supports buffered (stream)
731 pcp_read(uint8_t *buf
, int byte_cnt
)
736 if (byte_cnt
< 0 || byte_cnt
> mtu_size
) {
737 return (PCPL_INVALID_ARGS
);
741 * initialization of local read buffer
742 * from which the stream read requests are serviced.
744 if (read_area
== NULL
) {
745 read_area
= (uint8_t *)umem_zalloc(READ_AREA_SIZE
,
747 if (read_area
== NULL
) {
748 return (PCPL_MALLOC_FAIL
);
750 read_head
= read_area
;
751 read_tail
= read_area
;
755 * if we already read this data then copy from local buffer it self
756 * without calling new read.
758 if (byte_cnt
<= (read_tail
- read_head
)) {
759 (void) memcpy(buf
, read_head
, byte_cnt
);
760 read_head
+= byte_cnt
;
765 * if the request is not satisfied from the buffered data, then move the
766 * remaining data to front of the buffer and read new data.
768 for (i
= 0; i
< (read_tail
- read_head
); ++i
) {
769 read_area
[i
] = read_head
[i
];
771 read_head
= read_area
;
772 read_tail
= read_head
+ i
;
775 * do a peek to see how much data is available and read complete data.
778 if (xport_type
== GLVC_NON_STREAM
) {
779 if ((m
= pcp_peek(read_tail
, mtu_size
)) < 0) {
783 (void) alarm(glvc_timeout
);
784 if ((ret
= read(chnl_fd
, read_tail
, m
)) < 0) {
792 * Read the extra number of bytes
794 m
= byte_cnt
- (read_tail
- read_head
);
795 if ((ret
= vldc_read(chnl_fd
,
796 read_tail
, m
)) <= 0) {
803 * copy the requested bytes.
805 n
= MIN(byte_cnt
, (read_tail
- read_head
));
806 (void) memcpy(buf
, read_head
, n
);
814 * Issue read from the driver until byet_cnt number
815 * of bytes are present in read buffer. Do not
816 * move the read head.
819 pcp_update_read_area(int byte_cnt
)
824 if (byte_cnt
< 0 || byte_cnt
> mtu_size
) {
825 return (PCPL_INVALID_ARGS
);
829 * initialization of local read buffer
830 * from which the stream read requests are serviced.
832 if (read_area
== NULL
) {
833 read_area
= (uint8_t *)umem_zalloc(READ_AREA_SIZE
,
835 if (read_area
== NULL
) {
836 return (PCPL_MALLOC_FAIL
);
838 read_head
= read_area
;
839 read_tail
= read_area
;
843 * if we already have sufficient data in the buffer,
846 if (byte_cnt
<= (read_tail
- read_head
)) {
851 * if the request is not satisfied from the buffered data, then move the
852 * remaining data to front of the buffer and read new data.
854 for (i
= 0; i
< (read_tail
- read_head
); ++i
) {
855 read_area
[i
] = read_head
[i
];
857 read_head
= read_area
;
858 read_tail
= read_head
+ i
;
860 n
= byte_cnt
- (read_tail
- read_head
);
862 if ((ret
= vldc_read(chnl_fd
,
863 read_tail
, n
)) <= 0) {
869 * Return the number of bytes we could read
871 n
= MIN(byte_cnt
, (read_tail
- read_head
));
877 * This function is slight different from pcp_peek. The peek requests are first
878 * serviced from local read buffer, if data is available. If the peek request
879 * is not serviceble from local read buffer, then the data is peeked from
880 * channel buffer. This function is mainly used for proper protocol framing
884 pcp_peek_read(uint8_t *buf
, int byte_cnt
)
888 if (byte_cnt
< 0 || byte_cnt
> mtu_size
) {
889 return (PCPL_INVALID_ARGS
);
893 * initialization of peek_read buffer.
895 if (peek_read_area
== NULL
) {
896 peek_read_area
= (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE
,
898 if (peek_read_area
== NULL
) {
899 return (PCPL_MALLOC_FAIL
);
901 peek_read_head
= peek_read_area
;
902 peek_read_tail
= peek_read_area
;
906 * if we already have the data in local read buffer then copy
907 * from local buffer it self w/out calling new peek
909 if (byte_cnt
<= (read_tail
- read_head
)) {
910 (void) memcpy(buf
, read_head
, byte_cnt
);
915 * if the request is not satisfied from local read buffer, then first
916 * copy the remaining data in local read buffer to peek_read_area and
917 * then issue new peek.
919 for (i
= 0; i
< (read_tail
- read_head
); ++i
) {
920 peek_read_area
[i
] = read_head
[i
];
922 peek_read_head
= peek_read_area
;
923 peek_read_tail
= peek_read_head
+ i
;
926 * do a peek to see how much data is available and read complete data.
929 if ((m
= pcp_peek(peek_read_tail
, mtu_size
)) < 0) {
935 * copy the requested bytes
937 n
= MIN(byte_cnt
, (peek_read_tail
- peek_read_head
));
938 (void) memcpy(buf
, peek_read_head
, n
);
944 * Send Request Message Header.
947 pcp_send_req_msg_hdr(pcp_req_msg_hdr_t
*req_hdr
)
949 pcp_req_msg_hdr_t
*hdrp
;
953 hdr_sz
= sizeof (pcp_req_msg_hdr_t
);
954 if ((hdrp
= (pcp_req_msg_hdr_t
*)umem_zalloc(hdr_sz
,
955 UMEM_DEFAULT
)) == NULL
) {
956 return (PCPL_MALLOC_FAIL
);
959 hdrp
->magic_num
= htonl(req_hdr
->magic_num
);
960 hdrp
->proto_ver
= req_hdr
->proto_ver
;
961 hdrp
->msg_type
= req_hdr
->msg_type
;
962 hdrp
->sub_type
= req_hdr
->sub_type
;
963 hdrp
->rsvd_pad
= htons(req_hdr
->rsvd_pad
);
964 hdrp
->xid
= htonl(req_hdr
->xid
);
965 hdrp
->timeout
= htonl(req_hdr
->timeout
);
966 hdrp
->msg_len
= htonl(req_hdr
->msg_len
);
967 hdrp
->msg_cksum
= htons(req_hdr
->msg_cksum
);
968 hdrp
->hdr_cksum
= htons(req_hdr
->hdr_cksum
);
970 if ((ret
= pcp_io_op((char *)hdrp
, hdr_sz
, PCPL_IO_OP_WRITE
)) != 0) {
971 umem_free(hdrp
, hdr_sz
);
974 umem_free(hdrp
, hdr_sz
);
979 * Receive Response message header.
982 pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t
*resp_hdr
)
997 if (resp_hdr
== NULL
) {
998 return (PCPL_INVALID_ARGS
);
1002 * handle protocol framing errors.
1003 * pcp_frame_error_handle() returns when proper frame arrived
1004 * (magic seq) or if an error happens while reading data from
1007 if (xport_type
== GLVC_NON_STREAM
)
1008 ret
= pcp_frame_error_handle();
1010 ret
= pcp_vldc_frame_error_handle();
1013 return (PCPL_FRAME_ERROR
);
1015 /* read magic number first */
1016 if ((ret
= pcp_io_op(&magic_num
, sizeof (magic_num
),
1017 PCPL_IO_OP_READ
)) != 0) {
1021 magic_num
= ntohl(magic_num
);
1023 if (magic_num
!= PCP_MAGIC_NUM
) {
1024 return (PCPL_FRAME_ERROR
);
1027 /* read version field */
1028 if ((ret
= pcp_io_op(&proto_ver
, sizeof (proto_ver
),
1029 PCPL_IO_OP_READ
)) != 0) {
1033 /* check protocol version */
1034 if (proto_ver
!= PCP_PROT_VER_1
) {
1035 return (PCPL_PROT_ERROR
);
1038 /* Read message type */
1039 if ((ret
= pcp_io_op(&msg_type
, sizeof (msg_type
),
1040 PCPL_IO_OP_READ
)) != 0) {
1044 /* Read message sub type */
1045 if ((ret
= pcp_io_op(&sub_type
, sizeof (sub_type
),
1046 PCPL_IO_OP_READ
)) != 0) {
1050 /* Read rcvd_pad bits */
1051 if ((ret
= pcp_io_op(&rsvd_pad
, sizeof (rsvd_pad
),
1052 PCPL_IO_OP_READ
)) != 0) {
1056 /* receive transaction id */
1057 if ((ret
= pcp_io_op(&xid
, sizeof (xid
),
1058 PCPL_IO_OP_READ
)) != 0) {
1064 /* receive timeout value */
1065 if ((ret
= pcp_io_op(&timeout
, sizeof (timeout
),
1066 PCPL_IO_OP_READ
)) != 0) {
1070 timeout
= ntohl(timeout
);
1072 /* receive message length */
1073 if ((ret
= pcp_io_op(&msg_len
, sizeof (msg_len
),
1074 PCPL_IO_OP_READ
)) != 0) {
1078 msg_len
= ntohl(msg_len
);
1080 /* receive status field */
1081 if ((ret
= pcp_io_op(&status
, sizeof (status
),
1082 PCPL_IO_OP_READ
)) != 0) {
1086 status
= ntohl(status
);
1088 /* receive message checksum */
1089 if ((ret
= pcp_io_op(&msg_cksum
, sizeof (msg_cksum
),
1090 PCPL_IO_OP_READ
)) != 0) {
1094 msg_cksum
= ntohs(msg_cksum
);
1096 /* receive header checksum */
1097 if ((ret
= pcp_io_op(&hdr_cksum
, sizeof (hdr_cksum
),
1098 PCPL_IO_OP_READ
)) != 0) {
1102 hdr_cksum
= ntohs(hdr_cksum
);
1104 /* copy to resp_hdr */
1106 resp_hdr
->magic_num
= magic_num
;
1107 resp_hdr
->proto_ver
= proto_ver
;
1108 resp_hdr
->msg_type
= msg_type
;
1109 resp_hdr
->sub_type
= sub_type
;
1110 resp_hdr
->rsvd_pad
= rsvd_pad
;
1111 resp_hdr
->xid
= xid
;
1112 resp_hdr
->timeout
= timeout
;
1113 resp_hdr
->msg_len
= msg_len
;
1114 resp_hdr
->status
= status
;
1115 resp_hdr
->msg_cksum
= msg_cksum
;
1116 resp_hdr
->hdr_cksum
= hdr_cksum
;
1122 * Get next xid for including in request message.
1123 * Every request and response message are matched
1132 static boolean_t xid_initialized
= B_FALSE
;
1134 if (xid_initialized
== B_FALSE
) {
1135 xid_initialized
= B_TRUE
;
1137 * starting xid is initialized to a different value everytime
1138 * user application is restarted so that user apps will not
1139 * receive previous session's packets.
1141 * Note: The algorithm for generating initial xid is partially
1142 * taken from Solaris rpc code.
1144 (void) gettimeofday(&tv
, NULL
);
1145 msg_xid
= (uint32_t)((tv
.tv_sec
<< 20) |
1146 (tv
.tv_usec
>> 10));
1151 /* zero xid is not allowed */
1159 * This function handles channel framing errors. It waits until proper
1160 * frame with starting sequence as magic numder (0xAFBCAFA0)
1161 * is arrived. It removes unexpected data (before the magic number sequence)
1162 * on the channel. It returns when proper magic number sequence is seen
1163 * or when any failure happens while reading/peeking the channel.
1166 pcp_frame_error_handle(void)
1168 uint8_t magic_num_buf
[4];
1170 uint32_t net_magic_num
; /* magic byte in network byte order */
1171 uint32_t host_magic_num
= PCP_MAGIC_NUM
;
1174 net_magic_num
= htonl(host_magic_num
);
1175 (void) memcpy(magic_num_buf
, (uint8_t *)&net_magic_num
, 4);
1177 while (!ispresent
) {
1179 * Check if next four bytes matches pcp magic number.
1180 * if mathing not found, discard 1 byte and continue checking.
1182 if (!check_magic_byte_presence(4, &magic_num_buf
[0],
1186 (void) pcp_io_op(buf
, 1, PCPL_IO_OP_READ
);
1197 * This function handles channel framing errors. It waits until proper
1198 * frame with starting sequence as magic numder (0xAFBCAFA0)
1199 * is arrived. It removes unexpected data (before the magic number sequence)
1200 * on the channel. It returns when proper magic number sequence is seen
1201 * or when any failure happens while reading/peeking the channel.
1204 pcp_vldc_frame_error_handle(void)
1206 uint8_t magic_num_buf
[4];
1207 uint32_t net_magic_num
; /* magic byte in network byte order */
1208 uint32_t host_magic_num
= PCP_MAGIC_NUM
;
1209 int found_magic
= 0;
1211 net_magic_num
= htonl(host_magic_num
);
1212 (void) memcpy(magic_num_buf
, (uint8_t *)&net_magic_num
, 4);
1215 * For vldc, we need to read whatever data is available and
1216 * advance the read pointer one byte at a time until we get
1217 * the magic word. When this function is invoked, we do not
1218 * have any byte in the read buffer.
1222 * Keep reading until we find the matching magic number
1224 while (!found_magic
) {
1225 while ((read_tail
- read_head
) < sizeof (host_magic_num
)) {
1226 if (pcp_update_read_area(sizeof (host_magic_num
)) < 0)
1231 * We should have at least 4 bytes in read buffer. Check
1232 * if the magic number can be matched
1234 if (memcmp(read_head
, magic_num_buf
,
1235 sizeof (host_magic_num
))) {
1246 * checks whether certain byte sequence is present in the data stream.
1249 check_magic_byte_presence(int byte_cnt
, uint8_t *byte_seq
, int *ispresent
)
1254 if ((ret
= pcp_peek_read(buf
, byte_cnt
)) < 0) {
1258 /* 'byte_cnt' bytes not present */
1259 if (ret
!= byte_cnt
) {
1264 for (i
= 0; i
< byte_cnt
; ++i
) {
1265 if (buf
[i
] != byte_seq
[i
]) {
1276 * 16-bit simple internet checksum
1279 checksum(uint16_t *addr
, int32_t count
)
1282 * Compute Internet Checksum for "count" bytes
1283 * beginning at location "addr".
1286 register uint32_t sum
= 0;
1289 /* This is the inner loop */
1290 sum
+= *(unsigned short *)addr
++;
1294 /* Add left-over byte, if any */
1296 sum
+= * (unsigned char *)addr
;
1298 /* Fold 32-bit sum to 16 bits */
1300 sum
= (sum
& 0xffff) + (sum
>> 16);
1302 sum
= (~sum
) & 0xffff;
1310 * cleanup the channel if any data is hanging in
1314 pcp_cleanup(int channel_fd
)
1317 glvc_xport_msg_peek_t peek_ctrl
;
1319 uint8_t *buf
= NULL
;
1323 buf
= (uint8_t *)umem_zalloc((mtu_size
), UMEM_DEFAULT
);
1325 return (PCPL_MALLOC_FAIL
);
1328 peek_ctrl
.buf
= (caddr_t
)buf
;
1329 peek_ctrl
.buflen
= mtu_size
;
1330 peek_ctrl
.flags
= 0;
1333 * set sig jmp location
1335 if (sigsetjmp(jmpbuf
, 1)) {
1336 umem_free(buf
, mtu_size
);
1337 return (PCPL_GLVC_TIMEOUT
);
1343 (void) alarm(PCP_CLEANUP_TIMEOUT
);
1344 if ((ret
= ioctl(channel_fd
, GLVC_XPORT_IOCTL_DATA_PEEK
,
1352 n
= peek_ctrl
.buflen
;
1354 if (n
<= 0 && retry
> 2) {
1357 } else if (n
<= 0) {
1362 /* remove data from channel */
1363 (void) alarm(PCP_CLEANUP_TIMEOUT
);
1364 if ((ret
= read(channel_fd
, buf
, n
)) < 0) {
1372 umem_free(buf
, mtu_size
);
1377 vldc_write(int fd
, uint8_t *bufp
, int size
)
1383 pollfd
.events
= POLLOUT
;
1388 * Poll for the vldc channel to be ready
1390 if (poll(&pollfd
, 1, glvc_timeout
* MILLISEC
) <= 0) {
1395 if ((res
= write(fd
, bufp
, left
)) <= 0) {
1396 if (errno
!= EWOULDBLOCK
) {
1406 * Return number of bytes actually written
1408 return (size
- left
);
1412 * Keep reading until we get the specified number of bytes
1415 vldc_read(int fd
, uint8_t *bufp
, int size
)
1420 struct pollfd fds
[1];
1422 fds
[0].events
= POLLIN
| POLLPRI
;
1426 if (poll(fds
, 1, glvc_timeout
* MILLISEC
) <= 0) {
1431 res
= read(fd
, bufp
, left
);
1432 /* return on error or short read */
1433 if ((res
== 0) || ((res
< 0) &&
1434 (errno
== EAGAIN
))) {
1435 /* poll until the read is unblocked */
1436 if ((poll(fds
, 1, glvc_timeout
* MILLISEC
)) < 0)
1442 /* unrecoverable error */
1451 return (size
- left
);