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
glvc_timeout_handler(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
pcp_init(char * channel_name)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
pcp_close(int channel_fd)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
pcp_send_recv(int channel_fd,pcp_msg_t * req_msg,pcp_msg_t * resp_msg,uint32_t timeout)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
pcp_get_prop(int channel_fd,int prop,unsigned int * val)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
pcp_io_op(void * buf,int byte_cnt,int io_op)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
pcp_peek(uint8_t * buf,int bytes_cnt)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
pcp_write(uint8_t * buf,int byte_cnt)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
pcp_read(uint8_t * buf,int byte_cnt)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
pcp_update_read_area(int byte_cnt)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
pcp_peek_read(uint8_t * buf,int byte_cnt)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
pcp_send_req_msg_hdr(pcp_req_msg_hdr_t * req_hdr)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
pcp_recv_resp_msg_hdr(pcp_resp_msg_hdr_t * resp_hdr)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
pcp_get_xid(void)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
pcp_frame_error_handle(void)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
pcp_vldc_frame_error_handle(void)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
check_magic_byte_presence(int byte_cnt,uint8_t * byte_seq,int * ispresent)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
checksum(uint16_t * addr,int32_t count)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
pcp_cleanup(int channel_fd)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
vldc_write(int fd,uint8_t * bufp,int size)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
vldc_read(int fd,uint8_t * bufp,int size)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