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