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