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