xref: /illumos-gate/usr/src/lib/libpcp/common/libpcp.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
1 /*
2  * CDDL HEADER START
3  *
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.
7  *
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.
12  *
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]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
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.
30  */
31 
32 #pragma ident	"%Z%%M%	%I%	%E% SMI"
33 
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <unistd.h>
37 #include <string.h>
38 #include <assert.h>
39 #include <fcntl.h>
40 #include <errno.h>
41 #include <signal.h>
42 #include <setjmp.h>
43 #include <inttypes.h>
44 #include <umem.h>
45 #include <strings.h>
46 #include <time.h>
47 #include <sys/types.h>
48 #include <sys/stat.h>
49 #include <sys/glvc.h>
50 #include <sys/vldc.h>
51 #include <sys/ldc.h>
52 #include <netinet/in.h>
53 
54 #include "libpcp.h"
55 #include "pcp_common.h"
56 #include "pcp_utils.h"
57 
58 
59 /*
60  * Following libpcp interfaces are exposed to user applications.
61  *
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,
64  * 			uint32_t timeout);
65  * int pcp_close(int channel_fd);
66  *
67  */
68 
69 /*
70  * Forward declarations.
71  */
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,
83 					int *ispresent);
84 static uint16_t checksum(uint16_t *addr, int32_t count);
85 static int pcp_cleanup(int channel_fd);
86 
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);
91 
92 /*
93  * local channel (glvc) file descriptor set by pcp_send_recv()
94  */
95 static int chnl_fd = -1;
96 
97 /*
98  * Message Transaction ID
99  */
100 static uint32_t msg_xid = 0;
101 
102 /*
103  * Channel MTU size.
104  */
105 static unsigned int mtu_size = PCPL_DEF_MTU_SZ;
106 
107 /*
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.
111  *
112  * Note: In the current implementation of glvc driver, all glvc calls are
113  *       blocking.
114  */
115 static uint32_t glvc_timeout = 0;
116 
117 /*
118  * variables used by setsetjmp/siglongjmp.
119  */
120 static volatile sig_atomic_t jumpok = 0;
121 static sigjmp_buf jmpbuf;
122 
123 /*
124  * To unblock SIGALRM signal incase if it's blocked in libpcp user apps.
125  * Restore it to old state during pcp_close.
126  */
127 static sigset_t blkset;
128 
129 /*
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.
133  */
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;
138 
139 /*
140  * Buffer used for peeking new data available in channel (glvc) buffers.
141  */
142 #define	PEEK_AREA_SIZE	(mtu_size)
143 static uint8_t *peek_area = NULL;
144 
145 /*
146  * Buffers used for peeking data available either in local buffers or
147  * new data available in channel (glvc) buffers.
148  */
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;
153 
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;
158 
159 /*
160  * signal handling variables to handle glvc blocking calls.
161  */
162 static struct sigaction glvc_act;
163 
164 /* To restore old SIGALRM signal handler */
165 static struct sigaction old_act;
166 
167 /*
168  * Variables to support vldc based streaming transport
169  */
170 static pcp_xport_t xport_type = GLVC_NON_STREAM;
171 #define	VLDC_MTU_SIZE	(2048)
172 
173 static void
174 glvc_timeout_handler(void)
175 {
176 	if (jumpok == 0)
177 		return;
178 	siglongjmp(jmpbuf, 1);
179 }
180 
181 /*
182  * Initialize the virtual channel. It basically opens the virtual channel
183  * provided by the host application.
184  *
185  */
186 
187 int
188 pcp_init(char *channel_name)
189 {
190 	sigset_t oldset;
191 	int channel_fd;
192 	char *dev_path;
193 	vldc_opt_op_t op;
194 
195 	if (channel_name == NULL)
196 		return (PCPL_INVALID_ARGS);
197 
198 	/*
199 	 * Given the argument, try to locate a device in the device tree
200 	 */
201 	dev_path = platsvc_name_to_path(channel_name, &xport_type);
202 
203 	/*
204 	 * Path exists ?
205 	 */
206 	if (NULL == dev_path)
207 		return (PCPL_INVALID_ARGS);
208 
209 	/*
210 	 * Open virtual channel name.
211 	 */
212 	if ((channel_fd = open(dev_path, O_RDWR|O_EXCL)) < 0) {
213 		free(dev_path);
214 		return (PCPL_GLVC_ERROR);
215 	}
216 
217 	free(dev_path);
218 
219 	/*
220 	 * Handle transport-specific processing
221 	 */
222 	switch (xport_type) {
223 	case VLDC_STREAMING:
224 		mtu_size = VLDC_MTU_SIZE;
225 
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);
232 		}
233 		break;
234 	case GLVC_NON_STREAM:
235 	default:
236 		/*
237 		 * Get the Channel MTU size
238 		 */
239 
240 		if (pcp_get_prop(channel_fd, GLVC_XPORT_OPT_MTU_SZ,
241 		    &mtu_size) != 0) {
242 			(void) close(channel_fd);
243 			return (PCPL_GLVC_ERROR);
244 		}
245 		break;
246 	}
247 
248 	/*
249 	 * Get current signal mask. If SIGALRM is blocked
250 	 * unblock it.
251 	 */
252 	(void) sigprocmask(0, NULL, &oldset);
253 
254 	(void) sigemptyset(&blkset);
255 
256 	if (sigismember(&oldset, SIGALRM)) {
257 		(void) sigaddset(&blkset, SIGALRM);
258 		(void) sigprocmask(SIG_UNBLOCK, &blkset, NULL);
259 	}
260 	/*
261 	 * signal handler initialization to handle glvc call timeouts.
262 	 */
263 	glvc_act.sa_handler = glvc_timeout_handler;
264 	(void) sigemptyset(&glvc_act.sa_mask);
265 	glvc_act.sa_flags = SA_NODEFER;
266 
267 	if (sigaction(SIGALRM, &glvc_act, &old_act) < 0) {
268 		(void) close(channel_fd);
269 		return (PCPL_ERROR);
270 	}
271 
272 	return (channel_fd);
273 }
274 
275 /*
276  * Function: Close platform channel.
277  * Arguments:
278  *	int channel_fd - channel file descriptor.
279  * Returns:
280  *	always returns PCPL_OK for now.
281  */
282 int
283 pcp_close(int channel_fd)
284 {
285 
286 	if (channel_fd >= 0) {
287 		if (xport_type  == GLVC_NON_STREAM)
288 			(void) pcp_cleanup(channel_fd);
289 		(void) close(channel_fd);
290 	} else {
291 		return (-1);
292 	}
293 
294 	/*
295 	 * free global buffers
296 	 */
297 	if (read_area != NULL) {
298 		umem_free(read_area, READ_AREA_SIZE);
299 		read_area = NULL;
300 	}
301 	if (peek_area != NULL) {
302 		umem_free(peek_area, PEEK_AREA_SIZE);
303 		peek_area = NULL;
304 	}
305 	if (peek_read_area != NULL) {
306 		umem_free(peek_read_area, PEEK_READ_AREA_SIZE);
307 		peek_read_area = NULL;
308 	}
309 	if (req_msg_hdr != NULL) {
310 		umem_free(req_msg_hdr, req_msg_hdr_sz);
311 		req_msg_hdr = NULL;
312 	}
313 	if (resp_msg_hdr != NULL) {
314 		umem_free(resp_msg_hdr, resp_msg_hdr_sz);
315 		resp_msg_hdr = NULL;
316 	}
317 
318 	/*
319 	 * Restore SIGALRM signal mask incase if we unblocked
320 	 * it during pcp_init.
321 	 */
322 	if (sigismember(&blkset, SIGALRM)) {
323 		(void) sigprocmask(SIG_BLOCK, &blkset, NULL);
324 	}
325 
326 	/* Restore SIGALRM signal handler */
327 	(void) sigaction(SIGALRM, &old_act, NULL);
328 
329 	return (PCPL_OK);
330 }
331 
332 /*
333  * Function: Send and Receive messages on platform channel.
334  * Arguments:
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.
339  * Returns:
340  *	0  - success (PCPL_OK).
341  *	(-ve) - failure:
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.
348  */
349 int
350 pcp_send_recv(int channel_fd, pcp_msg_t *req_msg, pcp_msg_t *resp_msg,
351 		uint32_t timeout)
352 {
353 	void *datap;
354 	void *resp_msg_data = NULL;
355 	uint32_t status;
356 	uint16_t cksum = 0;
357 	int ret;
358 	int resp_hdr_ok;
359 #ifdef PCP_CKSUM_ENABLE
360 	uint16_t bkup_resp_hdr_cksum;
361 #endif
362 	if (channel_fd < 0) {
363 		return (PCPL_ERROR);
364 	}
365 
366 	/* copy channel_fd to local fd (chnl_fd) for other functions use */
367 	chnl_fd = channel_fd;
368 
369 	if (req_msg == NULL) {
370 		return (PCPL_INVALID_ARGS);
371 	}
372 
373 	if (timeout > 0)
374 		glvc_timeout = timeout;
375 	else
376 		glvc_timeout = 0;
377 
378 	if ((req_msg->msg_len != 0) && ((datap = req_msg->msg_data) == NULL))
379 		return (PCPL_INVALID_ARGS);
380 
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,
384 								UMEM_DEFAULT);
385 		if (req_msg_hdr == NULL)
386 			return (PCPL_MALLOC_FAIL);
387 	}
388 
389 	if (req_msg->msg_len != 0) {
390 		/* calculate request msg_cksum */
391 		cksum = checksum((uint16_t *)datap, req_msg->msg_len);
392 	}
393 
394 	/*
395 	 * Fill in the message header for the request packet
396 	 */
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;
407 
408 	/* fill request header checksum */
409 	req_msg_hdr->hdr_cksum = checksum((uint16_t *)req_msg_hdr,
410 					req_msg_hdr_sz);
411 	/*
412 	 * set sig jmp location
413 	 */
414 	if (sigsetjmp(jmpbuf, 1)) {
415 		return (PCPL_GLVC_TIMEOUT);
416 	}
417 	jumpok = 1; /* monitor sigalrm from now on */
418 
419 	/*
420 	 * send request message header
421 	 */
422 	if ((ret = pcp_send_req_msg_hdr(req_msg_hdr))) {
423 
424 		return (ret);
425 	}
426 
427 	/*
428 	 * send request message
429 	 */
430 	if (req_msg->msg_len != 0) {
431 		if ((ret = pcp_io_op(datap, req_msg->msg_len,
432 					PCPL_IO_OP_WRITE))) {
433 			return (ret);
434 		}
435 	}
436 
437 	if (timeout == (uint32_t)PCP_TO_NO_RESPONSE)
438 		return (PCPL_OK);
439 
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,
443 								UMEM_DEFAULT);
444 		if (resp_msg_hdr == NULL)
445 			return (PCPL_MALLOC_FAIL);
446 	}
447 
448 	resp_hdr_ok = 0;
449 	while (!resp_hdr_ok) {
450 
451 		/*
452 		 * Receive response message header
453 		 * Note: frame error handling is done in
454 		 * 'pcp_recv_resp_msg_hdr()'.
455 		 */
456 		if ((ret = pcp_recv_resp_msg_hdr(resp_msg_hdr))) {
457 			return (ret);
458 		}
459 
460 		/*
461 		 * Check header checksum if it matches with the received hdr
462 		 * checksum.
463 		 */
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);
468 
469 		if (cksum != bkup_resp_hdr_cksum) {
470 			return (PCPL_CKSUM_ERROR);
471 		}
472 #endif
473 		/*
474 		 * Check for matching request and response messages
475 		 */
476 		if (resp_msg_hdr->xid != req_msg_hdr->xid) {
477 
478 			continue; /* continue reading response header */
479 		}
480 		resp_hdr_ok = 1;
481 	}
482 
483 	/*
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.
487 	 */
488 	status = resp_msg_hdr->status;
489 	if (status != PCP_OK) {
490 		return (PCPL_XPORT_ERROR);
491 	}
492 
493 	if (resp_msg_hdr->msg_len != 0) {
494 
495 		/* libpcp users should free this memory */
496 		if ((resp_msg_data = (uint8_t *)malloc(resp_msg_hdr->msg_len))
497 			== NULL)
498 			return (PCPL_MALLOC_FAIL);
499 		bzero(resp_msg_data, resp_msg_hdr->msg_len);
500 		/*
501 		 * Receive response message.
502 		 */
503 		if ((ret = pcp_io_op(resp_msg_data, resp_msg_hdr->msg_len,
504 						PCPL_IO_OP_READ))) {
505 			free(resp_msg_data);
506 			return (ret);
507 		}
508 
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) {
514 			free(resp_msg_data);
515 			return (PCPL_CKSUM_ERROR);
516 		}
517 #endif
518 	}
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;
525 
526 	return (PCPL_OK);
527 
528 }
529 
530 /*
531  * Function: Get channel property values.
532  * Arguments:
533  *	int channel_fd - channel file descriptor.
534  *	int prop - property id.
535  *	unsigned int *val - property value tobe copied.
536  * Returns:
537  *	0 - success
538  *	(-ve) - failure:
539  *		PCPL_ERR_GLVC - glvc ioctl failure.
540  */
541 
542 static int
543 pcp_get_prop(int channel_fd, int prop, unsigned int *val)
544 {
545 	glvc_xport_opt_op_t	channel_op;
546 	int			ret;
547 
548 	channel_op.op_sel = GLVC_XPORT_OPT_GET;
549 	channel_op.opt_sel = prop;
550 	channel_op.opt_val = 0;
551 
552 	(void) alarm(glvc_timeout);
553 
554 	if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_OPT_OP,
555 		&channel_op)) < 0) {
556 
557 		(void) alarm(0);
558 		return (ret);
559 	}
560 	(void) alarm(0);
561 
562 	*val = channel_op.opt_val;
563 
564 	return (0);
565 }
566 
567 /*
568  * Function: wrapper for handling glvc calls (read/write/peek).
569  */
570 static int
571 pcp_io_op(void *buf, int byte_cnt, int io_op)
572 {
573 	int	rv;
574 	int	n;
575 	uint8_t	*datap;
576 	int	(*func_ptr)(uint8_t *, int);
577 	int	io_sz;
578 	int	try_cnt;
579 
580 
581 	if ((buf == NULL) || (byte_cnt < 0)) {
582 		return (PCPL_INVALID_ARGS);
583 	}
584 
585 	switch (io_op) {
586 		case PCPL_IO_OP_READ:
587 			func_ptr = pcp_read;
588 			break;
589 		case PCPL_IO_OP_WRITE:
590 			func_ptr = pcp_write;
591 			break;
592 		case PCPL_IO_OP_PEEK:
593 			func_ptr = pcp_peek;
594 			break;
595 		default:
596 			return (PCPL_INVALID_ARGS);
597 	}
598 
599 	/*
600 	 * loop until all I/O done, try limit exceded, or real failure
601 	 */
602 
603 	rv = 0;
604 	datap = buf;
605 	while (rv < byte_cnt) {
606 		io_sz = MIN((byte_cnt - rv), mtu_size);
607 		try_cnt = 0;
608 		while ((n = (*func_ptr)(datap, io_sz)) < 0) {
609 			try_cnt++;
610 			if (try_cnt > PCPL_MAX_TRY_CNT) {
611 				rv = n;
612 				goto done;
613 			}
614 			(void) sleep(PCPL_GLVC_SLEEP);
615 		} /* while trying the io operation */
616 
617 		if (n < 0) {
618 			rv = n;
619 			goto done;
620 		}
621 		rv += n;
622 		datap += n;
623 	} /* while still have more data */
624 
625 done:
626 	if (rv == byte_cnt)
627 		return (0);
628 	else
629 		return (PCPL_GLVC_ERROR);
630 }
631 
632 /*
633  * For peeking 'bytes_cnt' bytes in channel (glvc) buffers.
634  * If data is available, the data is copied into 'buf'.
635  */
636 static int
637 pcp_peek(uint8_t *buf, int bytes_cnt)
638 {
639 	int			ret;
640 	glvc_xport_msg_peek_t	peek_ctrl;
641 	int			n, m;
642 
643 	if (bytes_cnt < 0 || bytes_cnt > mtu_size) {
644 		return (PCPL_INVALID_ARGS);
645 	}
646 
647 	/*
648 	 * initialization of buffers used for peeking data in channel buffers.
649 	 */
650 	if (peek_area == NULL) {
651 		peek_area = (uint8_t *)umem_zalloc(PEEK_AREA_SIZE,
652 							UMEM_DEFAULT);
653 		if (peek_area == NULL) {
654 			return (PCPL_MALLOC_FAIL);
655 		}
656 	}
657 
658 	/*
659 	 * peek max MTU size bytes
660 	 */
661 	peek_ctrl.buf = (caddr_t)peek_area;
662 	peek_ctrl.buflen = mtu_size;
663 	peek_ctrl.flags = 0;
664 
665 	(void) alarm(glvc_timeout);
666 
667 	if ((ret = ioctl(chnl_fd, GLVC_XPORT_IOCTL_DATA_PEEK, &peek_ctrl))
668 		< 0) {
669 		(void) alarm(0);
670 		return (ret);
671 	}
672 	(void) alarm(0);
673 
674 	n = peek_ctrl.buflen;
675 
676 	if (n < 0)
677 		return (PCPL_GLVC_ERROR);
678 
679 	/*
680 	 * satisfy request as best as we can
681 	 */
682 	m = MIN(bytes_cnt, n);
683 	(void) memcpy(buf, peek_area, m);
684 
685 	return (m);
686 }
687 
688 /*
689  * Function: write 'byte_cnt' bytes from 'buf' to channel.
690  */
691 static int
692 pcp_write(uint8_t *buf, int byte_cnt)
693 {
694 
695 	int	ret;
696 
697 	/* check for valid arguments */
698 	if (buf == NULL || byte_cnt < 0 || byte_cnt > mtu_size) {
699 		return (PCPL_INVALID_ARGS);
700 	}
701 
702 	if (xport_type == GLVC_NON_STREAM) {
703 		(void) alarm(glvc_timeout);
704 
705 		if ((ret = write(chnl_fd, buf, byte_cnt)) < 0) {
706 			(void) alarm(0);
707 			return (ret);
708 		}
709 		(void) alarm(0);
710 	} else {
711 		if ((ret = vldc_write(chnl_fd, buf, byte_cnt)) <= 0) {
712 			return (ret);
713 		}
714 	}
715 
716 	return (ret);
717 }
718 
719 /*
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.
725  *
726  * This call may need to be enhanced when glvc supports buffered (stream)
727  * reads - TBD
728  */
729 
730 static int
731 pcp_read(uint8_t *buf, int byte_cnt)
732 {
733 	int			ret;
734 	int			n, m, i;
735 
736 	if (byte_cnt < 0 || byte_cnt > mtu_size) {
737 		return (PCPL_INVALID_ARGS);
738 	}
739 
740 	/*
741 	 * initialization of local read buffer
742 	 * from which the stream read requests are serviced.
743 	 */
744 	if (read_area == NULL) {
745 		read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE,
746 							UMEM_DEFAULT);
747 		if (read_area == NULL) {
748 			return (PCPL_MALLOC_FAIL);
749 		}
750 		read_head = read_area;
751 		read_tail = read_area;
752 	}
753 
754 	/*
755 	 * if we already read this data then copy from local buffer it self
756 	 * without calling new read.
757 	 */
758 	if (byte_cnt <= (read_tail - read_head)) {
759 		(void) memcpy(buf, read_head, byte_cnt);
760 		read_head += byte_cnt;
761 		return (byte_cnt);
762 	}
763 
764 	/*
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.
767 	 */
768 	for (i = 0; i < (read_tail - read_head); ++i) {
769 		read_area[i] = read_head[i];
770 	}
771 	read_head = read_area;
772 	read_tail = read_head + i;
773 
774 	/*
775 	 * do a peek to see how much data is available and read complete data.
776 	 */
777 
778 	if (xport_type == GLVC_NON_STREAM) {
779 		if ((m = pcp_peek(read_tail, mtu_size)) < 0) {
780 			return (m);
781 		}
782 
783 		(void) alarm(glvc_timeout);
784 		if ((ret = read(chnl_fd, read_tail, m)) < 0) {
785 			(void) alarm(0);
786 			return (ret);
787 		}
788 
789 		(void) alarm(0);
790 	} else {
791 		/*
792 		 * Read the extra number of bytes
793 		 */
794 		m = byte_cnt - (read_tail - read_head);
795 		if ((ret = vldc_read(chnl_fd,
796 				read_tail, m)) <= 0) {
797 			return (ret);
798 		}
799 	}
800 	read_tail += ret;
801 
802 	/*
803 	 * copy the requested bytes.
804 	 */
805 	n = MIN(byte_cnt, (read_tail - read_head));
806 	(void) memcpy(buf, read_head, n);
807 
808 	read_head += n;
809 
810 	return (n);
811 }
812 
813 /*
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.
817  */
818 static int
819 pcp_update_read_area(int byte_cnt)
820 {
821 	int			ret;
822 	int			n, i;
823 
824 	if (byte_cnt < 0 || byte_cnt > mtu_size) {
825 		return (PCPL_INVALID_ARGS);
826 	}
827 
828 	/*
829 	 * initialization of local read buffer
830 	 * from which the stream read requests are serviced.
831 	 */
832 	if (read_area == NULL) {
833 		read_area = (uint8_t *)umem_zalloc(READ_AREA_SIZE,
834 							UMEM_DEFAULT);
835 		if (read_area == NULL) {
836 			return (PCPL_MALLOC_FAIL);
837 		}
838 		read_head = read_area;
839 		read_tail = read_area;
840 	}
841 
842 	/*
843 	 * if we already have sufficient data in the buffer,
844 	 * just return
845 	 */
846 	if (byte_cnt <= (read_tail - read_head)) {
847 		return (byte_cnt);
848 	}
849 
850 	/*
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.
853 	 */
854 	for (i = 0; i < (read_tail - read_head); ++i) {
855 		read_area[i] = read_head[i];
856 	}
857 	read_head = read_area;
858 	read_tail = read_head + i;
859 
860 	n = byte_cnt - (read_tail - read_head);
861 
862 	if ((ret = vldc_read(chnl_fd,
863 			read_tail, n)) <= 0) {
864 		return (ret);
865 	}
866 	read_tail += ret;
867 
868 	/*
869 	 * Return the number of bytes we could read
870 	 */
871 	n = MIN(byte_cnt, (read_tail - read_head));
872 
873 	return (n);
874 }
875 
876 /*
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
881  * error handling.
882  */
883 static int
884 pcp_peek_read(uint8_t *buf, int byte_cnt)
885 {
886 	int	n, m, i;
887 
888 	if (byte_cnt < 0 || byte_cnt > mtu_size) {
889 		return (PCPL_INVALID_ARGS);
890 	}
891 
892 	/*
893 	 * initialization of peek_read buffer.
894 	 */
895 	if (peek_read_area == NULL) {
896 		peek_read_area = (uint8_t *)umem_zalloc(PEEK_READ_AREA_SIZE,
897 						UMEM_DEFAULT);
898 		if (peek_read_area == NULL) {
899 			return (PCPL_MALLOC_FAIL);
900 		}
901 		peek_read_head = peek_read_area;
902 		peek_read_tail = peek_read_area;
903 	}
904 
905 	/*
906 	 * if we already have the data in local read buffer then copy
907 	 * from local buffer it self w/out calling new peek
908 	 */
909 	if (byte_cnt <= (read_tail - read_head)) {
910 		(void) memcpy(buf, read_head, byte_cnt);
911 		return (byte_cnt);
912 	}
913 
914 	/*
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.
918 	 */
919 	for (i = 0; i < (read_tail - read_head); ++i) {
920 		peek_read_area[i] = read_head[i];
921 	}
922 	peek_read_head = peek_read_area;
923 	peek_read_tail = peek_read_head + i;
924 
925 	/*
926 	 * do a peek to see how much data is available and read complete data.
927 	 */
928 
929 	if ((m = pcp_peek(peek_read_tail, mtu_size)) < 0) {
930 		return (m);
931 	}
932 	peek_read_tail += m;
933 
934 	/*
935 	 * copy the requested bytes
936 	 */
937 	n = MIN(byte_cnt, (peek_read_tail - peek_read_head));
938 	(void) memcpy(buf, peek_read_head, n);
939 
940 	return (n);
941 }
942 
943 /*
944  * Send Request Message Header.
945  */
946 static int
947 pcp_send_req_msg_hdr(pcp_req_msg_hdr_t *req_hdr)
948 {
949 	pcp_req_msg_hdr_t	*hdrp;
950 	int			hdr_sz;
951 	int			ret;
952 
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);
957 	}
958 
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);
969 
970 	if ((ret = pcp_io_op((char *)hdrp, hdr_sz, PCPL_IO_OP_WRITE)) != 0) {
971 		umem_free(hdrp, hdr_sz);
972 		return (ret);
973 	}
974 	umem_free(hdrp, hdr_sz);
975 	return (PCP_OK);
976 }
977 
978 /*
979  * Receive Response message header.
980  */
981 static int
982 pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t *resp_hdr)
983 {
984 	uint32_t	magic_num;
985 	uint8_t		proto_ver;
986 	uint8_t		msg_type;
987 	uint8_t		sub_type;
988 	uint8_t		rsvd_pad;
989 	uint32_t	xid;
990 	uint32_t	timeout;
991 	uint32_t	msg_len;
992 	uint32_t	status;
993 	uint16_t	msg_cksum;
994 	uint16_t	hdr_cksum;
995 	int		ret;
996 
997 	if (resp_hdr == NULL) {
998 		return (PCPL_INVALID_ARGS);
999 	}
1000 
1001 	/*
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
1005 	 * channel.
1006 	 */
1007 	if (xport_type  == GLVC_NON_STREAM)
1008 		ret = pcp_frame_error_handle();
1009 	else
1010 		ret = pcp_vldc_frame_error_handle();
1011 
1012 	if (ret != 0)
1013 		return (PCPL_FRAME_ERROR);
1014 
1015 	/* read magic number first */
1016 	if ((ret = pcp_io_op(&magic_num, sizeof (magic_num),
1017 					PCPL_IO_OP_READ)) != 0) {
1018 		return (ret);
1019 	}
1020 
1021 	magic_num = ntohl(magic_num);
1022 
1023 	if (magic_num != PCP_MAGIC_NUM) {
1024 		return (PCPL_FRAME_ERROR);
1025 	}
1026 
1027 	/* read version field */
1028 	if ((ret = pcp_io_op(&proto_ver, sizeof (proto_ver),
1029 					PCPL_IO_OP_READ)) != 0) {
1030 		return (ret);
1031 	}
1032 
1033 	/* check protocol version */
1034 	if (proto_ver != PCP_PROT_VER_1) {
1035 		return (PCPL_PROT_ERROR);
1036 	}
1037 
1038 	/* Read message type */
1039 	if ((ret = pcp_io_op(&msg_type, sizeof (msg_type),
1040 					PCPL_IO_OP_READ)) != 0) {
1041 		return (ret);
1042 	}
1043 
1044 	/* Read message sub type */
1045 	if ((ret = pcp_io_op(&sub_type, sizeof (sub_type),
1046 					PCPL_IO_OP_READ)) != 0) {
1047 		return (ret);
1048 	}
1049 
1050 	/* Read rcvd_pad bits */
1051 	if ((ret = pcp_io_op(&rsvd_pad, sizeof (rsvd_pad),
1052 					PCPL_IO_OP_READ)) != 0) {
1053 		return (ret);
1054 	}
1055 
1056 	/* receive transaction id */
1057 	if ((ret = pcp_io_op(&xid, sizeof (xid),
1058 			PCPL_IO_OP_READ)) != 0) {
1059 		return (ret);
1060 	}
1061 
1062 	xid = ntohl(xid);
1063 
1064 	/* receive timeout value */
1065 	if ((ret = pcp_io_op(&timeout, sizeof (timeout),
1066 				PCPL_IO_OP_READ)) != 0) {
1067 		return (ret);
1068 	}
1069 
1070 	timeout = ntohl(timeout);
1071 
1072 	/* receive message length */
1073 	if ((ret = pcp_io_op(&msg_len, sizeof (msg_len),
1074 				PCPL_IO_OP_READ)) != 0) {
1075 		return (ret);
1076 	}
1077 
1078 	msg_len = ntohl(msg_len);
1079 
1080 	/* receive status field */
1081 	if ((ret = pcp_io_op(&status, sizeof (status),
1082 				PCPL_IO_OP_READ)) != 0) {
1083 		return (ret);
1084 	}
1085 
1086 	status = ntohl(status);
1087 
1088 	/* receive message checksum */
1089 	if ((ret = pcp_io_op(&msg_cksum, sizeof (msg_cksum),
1090 					PCPL_IO_OP_READ)) != 0) {
1091 		return (ret);
1092 	}
1093 
1094 	msg_cksum = ntohs(msg_cksum);
1095 
1096 	/* receive header checksum */
1097 	if ((ret = pcp_io_op(&hdr_cksum, sizeof (hdr_cksum),
1098 					PCPL_IO_OP_READ)) != 0) {
1099 		return (ret);
1100 	}
1101 
1102 	hdr_cksum = ntohs(hdr_cksum);
1103 
1104 	/* copy to resp_hdr */
1105 
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;
1117 
1118 	return (PCP_OK);
1119 }
1120 
1121 /*
1122  * Get next xid for including in request message.
1123  * Every request and response message are matched
1124  * for same xid.
1125  */
1126 
1127 static uint32_t
1128 pcp_get_xid(void)
1129 {
1130 	uint32_t ret;
1131 	struct timeval tv;
1132 	static boolean_t xid_initialized = B_FALSE;
1133 
1134 	if (xid_initialized == B_FALSE) {
1135 		xid_initialized = B_TRUE;
1136 		/*
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.
1140 		 *
1141 		 * Note: The algorithm for generating initial xid is partially
1142 		 *	 taken from Solaris rpc code.
1143 		 */
1144 		(void) gettimeofday(&tv, NULL);
1145 		msg_xid = (uint32_t)((tv.tv_sec << 20) |
1146 				(tv.tv_usec >> 10));
1147 	}
1148 
1149 	ret = msg_xid++;
1150 
1151 	/* zero xid is not allowed */
1152 	if (ret == 0)
1153 		ret = msg_xid++;
1154 
1155 	return (ret);
1156 }
1157 
1158 /*
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.
1164  */
1165 static int
1166 pcp_frame_error_handle(void)
1167 {
1168 	uint8_t		magic_num_buf[4];
1169 	int		ispresent = 0;
1170 	uint32_t	net_magic_num; /* magic byte in network byte order */
1171 	uint32_t	host_magic_num = PCP_MAGIC_NUM;
1172 	uint8_t		buf[2];
1173 
1174 	net_magic_num =  htonl(host_magic_num);
1175 	(void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4);
1176 
1177 	while (!ispresent) {
1178 		/*
1179 		 * Check if next four bytes matches pcp magic number.
1180 		 * if mathing not found, discard 1 byte and continue checking.
1181 		 */
1182 		if (!check_magic_byte_presence(4, &magic_num_buf[0],
1183 							&ispresent)) {
1184 			if (!ispresent) {
1185 				/* remove 1 byte */
1186 				(void) pcp_io_op(buf, 1, PCPL_IO_OP_READ);
1187 			}
1188 		} else {
1189 			return (-1);
1190 		}
1191 	}
1192 
1193 	return (0);
1194 }
1195 
1196 /*
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.
1202  */
1203 static int
1204 pcp_vldc_frame_error_handle(void)
1205 {
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;
1210 
1211 	net_magic_num =  htonl(host_magic_num);
1212 	(void) memcpy(magic_num_buf, (uint8_t *)&net_magic_num, 4);
1213 
1214 	/*
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.
1219 	 */
1220 
1221 	/*
1222 	 * Keep reading until we find the matching magic number
1223 	 */
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)
1227 				return (-1);
1228 		}
1229 
1230 		/*
1231 		 * We should have at least 4 bytes in read buffer. Check
1232 		 * if the magic number can be matched
1233 		 */
1234 		if (memcmp(read_head, magic_num_buf,
1235 				sizeof (host_magic_num))) {
1236 			read_head += 1;
1237 		} else {
1238 			found_magic = 1;
1239 		}
1240 	}
1241 
1242 	return (0);
1243 }
1244 
1245 /*
1246  * checks whether certain byte sequence is present in the data stream.
1247  */
1248 static int
1249 check_magic_byte_presence(int byte_cnt, uint8_t *byte_seq, int *ispresent)
1250 {
1251 	int		ret, i;
1252 	uint8_t		buf[4];
1253 
1254 	if ((ret = pcp_peek_read(buf, byte_cnt)) < 0) {
1255 		return (ret);
1256 	}
1257 
1258 	/* 'byte_cnt' bytes not present */
1259 	if (ret != byte_cnt) {
1260 		*ispresent = 0;
1261 		return (0);
1262 	}
1263 
1264 	for (i = 0; i < byte_cnt; ++i) {
1265 		if (buf[i] != byte_seq[i]) {
1266 			*ispresent = 0;
1267 			return (0);
1268 		}
1269 	}
1270 	*ispresent = 1;
1271 
1272 	return (0);
1273 }
1274 
1275 /*
1276  * 16-bit simple internet checksum
1277  */
1278 static uint16_t
1279 checksum(uint16_t *addr, int32_t count)
1280 {
1281 	/*
1282 	 * Compute Internet Checksum for "count" bytes
1283 	 * beginning at location "addr".
1284 	 */
1285 
1286 	register uint32_t	sum = 0;
1287 
1288 	while (count > 1)  {
1289 		/*  This is the inner loop */
1290 		sum += *(unsigned short *)addr++;
1291 		count -= 2;
1292 	}
1293 
1294 	/*  Add left-over byte, if any */
1295 	if (count > 0)
1296 		sum += * (unsigned char *)addr;
1297 
1298 	/* Fold 32-bit sum to 16 bits */
1299 	while (sum >> 16)
1300 		sum = (sum & 0xffff) + (sum >> 16);
1301 
1302 	sum = (~sum) & 0xffff;
1303 	if (sum == 0)
1304 		sum = 0xffff;
1305 
1306 	return (sum);
1307 }
1308 
1309 /*
1310  * cleanup the channel if any data is hanging in
1311  * channel buffers.
1312  */
1313 static int
1314 pcp_cleanup(int channel_fd)
1315 {
1316 	int			ret;
1317 	glvc_xport_msg_peek_t	peek_ctrl;
1318 	int			n, done;
1319 	uint8_t			*buf = NULL;
1320 	int			retry = 0;
1321 
1322 
1323 	buf = (uint8_t *)umem_zalloc((mtu_size), UMEM_DEFAULT);
1324 	if (buf == NULL) {
1325 		return (PCPL_MALLOC_FAIL);
1326 	}
1327 
1328 	peek_ctrl.buf = (caddr_t)buf;
1329 	peek_ctrl.buflen = mtu_size;
1330 	peek_ctrl.flags = 0;
1331 
1332 	/*
1333 	 * set sig jmp location
1334 	 */
1335 	if (sigsetjmp(jmpbuf, 1)) {
1336 		umem_free(buf, mtu_size);
1337 		return (PCPL_GLVC_TIMEOUT);
1338 	}
1339 
1340 	done = 0;
1341 	while (!done) {
1342 
1343 		(void) alarm(PCP_CLEANUP_TIMEOUT);
1344 		if ((ret = ioctl(channel_fd, GLVC_XPORT_IOCTL_DATA_PEEK,
1345 							&peek_ctrl)) < 0) {
1346 			(void) alarm(0);
1347 			done = 1;
1348 			continue;
1349 		}
1350 		(void) alarm(0);
1351 
1352 		n = peek_ctrl.buflen;
1353 
1354 		if (n <= 0 && retry > 2) {
1355 			done = 1;
1356 			continue;
1357 		} else if (n <= 0) {
1358 			++retry;
1359 			continue;
1360 		}
1361 
1362 		/* remove data from channel */
1363 		(void) alarm(PCP_CLEANUP_TIMEOUT);
1364 		if ((ret = read(channel_fd, buf, n)) < 0) {
1365 			(void) alarm(0);
1366 			done = 1;
1367 			continue;
1368 		}
1369 		(void) alarm(0);
1370 	}
1371 
1372 	umem_free(buf, mtu_size);
1373 	return (ret);
1374 }
1375 
1376 static int
1377 vldc_write(int fd, uint8_t *bufp, int size)
1378 {
1379 	int res;
1380 	int left = size;
1381 	pollfd_t pollfd;
1382 
1383 	pollfd.events = POLLOUT;
1384 	pollfd.revents = 0;
1385 	pollfd.fd = fd;
1386 
1387 	/*
1388 	 * Poll for the vldc channel to be ready
1389 	 */
1390 	if (poll(&pollfd, 1, glvc_timeout * MILLISEC) <= 0) {
1391 		return (-1);
1392 	}
1393 
1394 	do {
1395 		if ((res = write(fd, bufp, left)) <= 0) {
1396 			if (errno != EWOULDBLOCK) {
1397 				return (res);
1398 			}
1399 		} else {
1400 			bufp += res;
1401 			left -= res;
1402 		}
1403 	} while (left > 0);
1404 
1405 	/*
1406 	 * Return number of bytes actually written
1407 	 */
1408 	return (size - left);
1409 }
1410 
1411 /*
1412  * Keep reading until we get the specified number of bytes
1413  */
1414 static int
1415 vldc_read(int fd, uint8_t *bufp, int size)
1416 {
1417 	int res;
1418 	int left = size;
1419 
1420 	struct pollfd fds[1];
1421 
1422 	fds[0].events = POLLIN | POLLPRI;
1423 	fds[0].revents = 0;
1424 	fds[0].fd = fd;
1425 
1426 	if (poll(fds, 1, glvc_timeout * MILLISEC) <= 0) {
1427 		return (-1);
1428 	}
1429 
1430 	while (left > 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)
1437 					return (-1);
1438 
1439 				continue;
1440 		} else
1441 		if (res < 0) {
1442 			/* unrecoverable error */
1443 
1444 			return (-1);
1445 		} else {
1446 			bufp += res;
1447 			left -= res;
1448 		}
1449 	}
1450 
1451 	return (size - left);
1452 }
1453