xref: /illumos-gate/usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c (revision 8119dad84d6416f13557b0ba8e2aaf9064cbcfd3)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * WARNING: The contents of this file are shared by all projects
28  * that  wish to  perform  remote  Dynamic Reconfiguration  (DR)
29  * operations. Copies of this file can be found in the following
30  * locations:
31  *
32  *	Project	    Location
33  *	-------	    --------
34  *	Solaris	    usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c
35  *	SMS	    src/sms/lib/librdr/rdr_messages.c
36  *
37  * In order for proper communication to occur,  the files in the
38  * above locations must match exactly. Any changes that are made
39  * to this file should  be made to all of the files in the list.
40  */
41 
42 /*
43  * This file is a module that contains an interface for performing
44  * remote Dynamic Reconfiguration (DR) operations. It hides all
45  * network operations such as establishing a connection, sending
46  * and receiving messages, and closing a connection. It also handles
47  * the packing and unpacking of messages for network transport.
48  */
49 
50 #include <stdio.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <string.h>
54 #include <fcntl.h>
55 #include <errno.h>
56 #include <dlfcn.h>
57 #include <netdb.h>
58 #include <libdscp.h>
59 #include <sys/socket.h>
60 #include <sys/systeminfo.h>
61 #include <netinet/tcp.h>
62 
63 #include "dcs.h"
64 #include "remote_cfg.h"
65 #include "rdr_param_types.h"
66 #include "rdr_messages.h"
67 
68 
69 /*
70  * Structure holding information about
71  * all possible variable length fields
72  * that can be present in an RDR message.
73  */
74 typedef struct {
75 	int	ap_id_int_size;
76 	int	ap_id_char_size;
77 	int	*ap_id_sizes;
78 	char	*ap_id_chars;
79 	int	errstring_strlen;
80 	int	errstring_pad_sz;
81 	int	options_strlen;
82 	int	options_pad_sz;
83 	int	listopts_strlen;
84 	int	listopts_pad_sz;
85 	int	function_strlen;
86 	int	function_pad_sz;
87 } rdr_variable_message_info_t;
88 
89 /*
90  * A table of maximum sizes for each message type. Message size is
91  * validated when the message header is first received. This prevents
92  * a situation where a corrupted or bad header can cause too much
93  * memory to be allocated.
94  *
95  * The message size limits were chosen to be a very generous upper bound
96  * on the amount of data each message can send. They are not intended to
97  * be a precise measurement of the data size.
98  */
99 #define	NOMSG		0
100 #define	SHORTMSG	(150 * 1024)		/* 150 KB */
101 #define	LONGMSG		(3 * 1024 * 1024)	/* 3 MB */
102 
103 struct {
104 	ulong_t	req_max;
105 	ulong_t	reply_max;
106 } msg_sizes[] = {
107 	/*
108 	 * request	reply
109 	 * -------	-----
110 	 */
111 	{  NOMSG,	NOMSG	  },	/*  Invalid Opcode		*/
112 	{  SHORTMSG,	SHORTMSG  },	/*  RDR_SES_REQ			*/
113 	{  NOMSG,	NOMSG	  },	/*  RDR_SES_ESTBL		*/
114 	{  NOMSG,	NOMSG	  },	/*  RDR_SES_END			*/
115 	{  SHORTMSG,	SHORTMSG  },	/*  RDR_CONF_CHANGE_STATE	*/
116 	{  SHORTMSG,	SHORTMSG  },	/*  RDR_CONF_PRIVATE_FUNC	*/
117 	{  SHORTMSG,	SHORTMSG  },	/*  RDR_CONF_TEST		*/
118 	{  SHORTMSG,	LONGMSG	  },	/*  RDR_CONF_LIST_EXT		*/
119 	{  SHORTMSG,	NOMSG	  },	/*  RDR_CONF_HELP		*/
120 	{  SHORTMSG,	NOMSG	  },	/*  RDR_CONF_AP_ID_CMP		*/
121 	{  SHORTMSG,	NOMSG	  },	/*  RDR_CONF_ABORT_CMD		*/
122 	{  SHORTMSG,	SHORTMSG  },	/*  RDR_CONF_CONFIRM_CALLBACK	*/
123 	{  SHORTMSG,	NOMSG	  },	/*  RDR_CONF_MSG_CALLBACK	*/
124 	{  SHORTMSG,	LONGMSG	  }	/*  RDR_RSRC_INFO		*/
125 };
126 
127 
128 #define	RDR_BAD_FD		(-1)
129 
130 #define	RDR_MSG_HDR_SIZE	sizeof (rdr_msg_hdr_t)
131 
132 static const int RDR_ALIGN_64_BIT = 8;   /* 8 bytes */
133 
134 /*
135  * Interfaces for dynamic use of libdscp.
136  */
137 
138 #define	LIBDSCP_PATH	"/usr/platform/%s/lib/libdscp.so.1"
139 
140 #define	LIBDSCP_BIND	"dscpBind"
141 #define	LIBDSCP_SECURE	"dscpSecure"
142 #define	LIBDSCP_AUTH	"dscpAuth"
143 
144 typedef enum {
145 	LIBDSCP_UNKNOWN = 0,
146 	LIBDSCP_AVAILABLE,
147 	LIBDSCP_UNAVAILABLE
148 } dscp_status_t;
149 
150 typedef struct {
151 	dscp_status_t	status;
152 	int		(*bind)(int, int, int);
153 	int		(*secure)(int, int);
154 	int		(*auth)(int, struct sockaddr *, int);
155 } libdscp_t;
156 
157 static libdscp_t libdscp;
158 
159 /*
160  * Static Function Declarations
161  */
162 
163 /*
164  * Socket Related Routines
165  */
166 static int rdr_setopt(int fd, int name, int level);
167 
168 static int rdr_bind(int fd, struct sockaddr *addr);
169 
170 static int rdr_secure(int fd, struct sockaddr *addr);
171 
172 static int rdr_auth(struct sockaddr *addr, int len);
173 
174 static int rdr_snd(int fd, rdr_msg_hdr_t *hdr, char *data, int data_sz,
175 			int timeout);
176 static int rdr_snd_raw(int fd, char *msg, int data_sz, int timeout);
177 
178 static int rdr_rcv(int fd, rdr_msg_hdr_t *hdr, char **data, int timeout);
179 
180 static int rdr_rcv_raw(int fd, char *msg, int data_size, int timeout);
181 
182 /*
183  * Data Validation Routines
184  */
185 static int validate_header(rdr_msg_hdr_t *hdr);
186 
187 
188 /*
189  * Session Request Routines
190  */
191 static int pack_ses_req_request(ses_req_params_t *params, char **buf,
192 			int *buf_size);
193 static int unpack_ses_req_request(ses_req_params_t *params, const char *buf);
194 
195 static int pack_ses_req_reply(ses_req_params_t *params, char **buf,
196 			int *buf_size);
197 static int unpack_ses_req_reply(ses_req_params_t *params, const char *buf);
198 
199 
200 /*
201  * Change State Routines
202  */
203 static int pack_change_state_request(change_state_params_t *params,
204 			char **buf, int *buf_size);
205 static int unpack_change_state_request(change_state_params_t *params,
206 			const char *buf);
207 static int pack_change_state_reply(change_state_params_t *params,
208 			char **buf, int *buf_size);
209 static int unpack_change_state_reply(change_state_params_t *params,
210 			const char *buf);
211 
212 /*
213  * Private Func Routines
214  */
215 static int pack_private_func_request(private_func_params_t *params,
216 			char **buf, int *buf_size);
217 static int unpack_private_func_request(private_func_params_t *params,
218 			const char *buf);
219 static int pack_private_func_reply(private_func_params_t *params,
220 			char **buf, int *buf_size);
221 static int unpack_private_func_reply(private_func_params_t *params,
222 			const char *buf);
223 
224 /*
225  * Test Routines
226  */
227 static int pack_test_request(test_params_t *params, char **buf, int *buf_size);
228 
229 static int unpack_test_request(test_params_t *params, const char *buf);
230 
231 static int pack_test_reply(test_params_t *params, char **buf, int *buf_size);
232 
233 static int unpack_test_reply(test_params_t *params, const char *buf);
234 
235 
236 /*
237  * List Ext Routines
238  */
239 static int pack_list_ext_request(list_ext_params_t *params, char **buf,
240 			int *buf_size);
241 static int unpack_list_ext_request(list_ext_params_t *params, const char *buf);
242 
243 static int pack_list_ext_reply(list_ext_params_t *params, char **buf,
244 			int *buf_size);
245 static int unpack_list_ext_reply(list_ext_params_t *params, const char *buf);
246 
247 
248 /*
249  * Help Routines
250  */
251 static int pack_help_request(help_params_t *params, char **buf, int *buf_size);
252 
253 static int unpack_help_request(help_params_t *params, const char *buf);
254 
255 
256 /*
257  * Ap Id Cmp Routines
258  */
259 static int pack_ap_id_cmp_request(ap_id_cmp_params_t *params, char **buf,
260 			int *buf_size);
261 static int unpack_ap_id_cmp_request(ap_id_cmp_params_t *params,
262 			const char *buf);
263 
264 /*
265  * Abort Routines
266  */
267 static int pack_abort_cmd_request(abort_cmd_params_t *params, char **buf,
268 			int *buf_size);
269 static int unpack_abort_cmd_request(abort_cmd_params_t *params,
270 			const char *buf);
271 
272 /*
273  * Confirm Callback Routines
274  */
275 static int pack_confirm_request(confirm_callback_params_t *params, char **buf,
276 			int *buf_size);
277 static int unpack_confirm_request(confirm_callback_params_t *params,
278 			const char *buf);
279 static int pack_confirm_reply(confirm_callback_params_t *params,
280 			char **buf, int *buf_size);
281 static int unpack_confirm_reply(confirm_callback_params_t *params,
282 			const char *buf);
283 
284 /*
285  * Message Callback Routines
286  */
287 static int pack_message_request(msg_callback_params_t *params, char **buf,
288 			int *buf_size);
289 static int unpack_message_request(msg_callback_params_t *params,
290 			const char *buf);
291 
292 /*
293  * Resource Info Routines
294  */
295 static int pack_rsrc_info_request(rsrc_info_params_t *params, char **buf,
296 			int *buf_size);
297 static int unpack_rsrc_info_request(rsrc_info_params_t *params,
298 			const char *buf);
299 static int pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf,
300 			int *buf_size, int encoding);
301 static int unpack_rsrc_info_reply(rsrc_info_params_t *params, const char *buf);
302 
303 /*
304  * General Pack/Unpack Routines
305  */
306 static int pack_ap_ids(int num_ap_ids, char *const *ap_ids,
307 			rdr_variable_message_info_t *var_msg_info);
308 static int unpack_ap_ids(int num_ap_ids, char **ap_ids, const char *buf,
309 			rdr_variable_message_info_t *var_msg_info);
310 
311 /*
312  * Find Variable Info Sizes
313  */
314 static int find_options_sizes(char *options,
315 			rdr_variable_message_info_t *var_msg_info);
316 static int find_listopts_sizes(char *listopts,
317 			rdr_variable_message_info_t *var_msg_info);
318 static int find_function_sizes(char *function,
319 			rdr_variable_message_info_t *var_msg_info);
320 static int find_errstring_sizes(char **errstring,
321 			rdr_variable_message_info_t *var_msg_info);
322 
323 /*
324  * Extract Info From Buffers
325  */
326 static int get_ap_ids_from_buf(char ***ap_id_ptr, int num_ap_ids,
327 			rdr_variable_message_info_t *var_msg_info,
328 			const char *buf);
329 static int get_string_from_buf(char **stringptr, int strsize, const char *buf);
330 
331 
332 /*
333  * Cleanup Routines
334  */
335 static int cleanup_ap_ids(int num_ap_ids, char **ap_ids);
336 
337 static int cleanup_errstring(char **errstring);
338 
339 static void cleanup_variable_ap_id_info(
340 			rdr_variable_message_info_t *var_msg_info);
341 
342 /*
343  * Functions for loading libdscp.
344  */
345 static int load_libdscp(libdscp_t *libdscp);
346 
347 /*
348  * Public Functions
349  */
350 
351 
352 /*
353  * rdr_open:
354  *
355  * Establish a transport endpoint to prepare for a new
356  * connection. Returns a file descriptor representing the
357  * new transport if successful or RDR_BAD_FD upon failure.
358  */
359 int
360 rdr_open(int family)
361 {
362 	int	newfd;
363 
364 
365 	if ((newfd = socket(family, SOCK_STREAM, 0)) == -1) {
366 		return (RDR_BAD_FD);
367 	}
368 
369 	return (newfd);
370 }
371 
372 
373 /*
374  * rdr_init:
375  *
376  * Initialize a transport endpoint. This involves binding to
377  * a particular port and setting any user specified socket
378  * options.
379  */
380 int
381 rdr_init(int fd, struct sockaddr *addr, int *opts, int num_opts, int blog)
382 {
383 	int	i;
384 
385 
386 	/* sanity checks */
387 	if ((fd < 0) || (addr == NULL)) {
388 		return (RDR_ERROR);
389 	}
390 
391 	if ((opts == NULL) || (num_opts < 0)) {
392 		num_opts = 0;
393 	}
394 
395 	/* turn on security features */
396 	if (rdr_secure(fd, addr) != RDR_OK) {
397 		return (RDR_NET_ERR);
398 	}
399 
400 	/* bind the address, if is not already bound */
401 	if (rdr_bind(fd, addr) != RDR_OK) {
402 		return (RDR_NET_ERR);
403 	}
404 
405 	/*
406 	 * Set TCP_NODELAY for this endpoint. This disables Nagle's
407 	 * algorithm that can cause a delay in sending small sized
408 	 * messages. Since most of the RDR messages are small, this
409 	 * is a restriction that negatively impacts performance.
410 	 */
411 	if (rdr_setopt(fd, TCP_NODELAY, IPPROTO_TCP) != RDR_OK) {
412 		return (RDR_NET_ERR);
413 	}
414 
415 	/* set the user specified socket options */
416 	for (i = 0; i < num_opts; i++) {
417 		if (rdr_setopt(fd, opts[i], SOL_SOCKET) != RDR_OK) {
418 			return (RDR_NET_ERR);
419 		}
420 	}
421 
422 	/*
423 	 * If blog is not zero, it is a server that is being
424 	 * initialized. In order for it to be able to accept
425 	 * connections, we have to set the size of the incoming
426 	 * connection queue.
427 	 */
428 	if (blog != 0) {
429 		if (listen(fd, blog) == -1) {
430 			return (RDR_NET_ERR);
431 		}
432 	}
433 
434 	return (RDR_OK);
435 }
436 
437 
438 /*
439  * rdr_connect_clnt:
440  *
441  * Perform the necessary steps for a client to connect to
442  * a server process. The required information is the file
443  * descriptor for the transport endpoint, and the remote
444  * address.
445  */
446 int
447 rdr_connect_clnt(int fd, struct sockaddr *addr)
448 {
449 	unsigned int	addr_len;
450 
451 
452 	/* sanity check */
453 	if (addr == NULL) {
454 		return (RDR_ERROR);
455 	}
456 
457 	/* initialize the address length */
458 	switch (addr->sa_family) {
459 
460 	case AF_INET:
461 		addr_len = sizeof (struct sockaddr_in);
462 		break;
463 
464 	case AF_INET6:
465 		addr_len = sizeof (struct sockaddr_in6);
466 		break;
467 
468 	default:
469 		return (RDR_ERROR);
470 	}
471 
472 	/* attempt the connection */
473 	if (connect(fd, addr, addr_len) == -1) {
474 		return (RDR_NET_ERR);
475 	}
476 
477 	return (RDR_OK);
478 }
479 
480 
481 /*
482  * rdr_connect_srv:
483  *
484  * Perform the necessary steps for a server to connect to a
485  * pending client request. The new connection is allocated a
486  * new file descriptor, separate from the one used to accept
487  * the connection.
488  */
489 int
490 rdr_connect_srv(int fd)
491 {
492 	int			newfd;
493 	unsigned int		faddr_len;
494 	struct sockaddr_storage	faddr;
495 
496 
497 	/* accept the connection */
498 	faddr_len = sizeof (faddr);
499 	if ((newfd = accept(fd, (struct sockaddr *)&faddr, &faddr_len)) == -1) {
500 		return (RDR_BAD_FD);
501 	}
502 
503 	/* if the peer doesn't authenticate properly, reject */
504 	if (rdr_auth((struct sockaddr *)&faddr, faddr_len) != RDR_OK) {
505 		(void) close(newfd);
506 		return (RDR_BAD_FD);
507 	}
508 
509 	return (newfd);
510 }
511 
512 
513 /*
514  * rdr_reject:
515  *
516  * Reject an incoming connection attempt. This requires
517  * that the connection be accepted first.
518  */
519 int
520 rdr_reject(int fd)
521 {
522 	unsigned int		faddr_len;
523 	struct sockaddr_storage	faddr;
524 
525 
526 	/* first accept the connection */
527 	faddr_len = sizeof (faddr);
528 	if (accept(fd, (struct sockaddr *)&faddr, &faddr_len) == -1) {
529 		return (RDR_NET_ERR);
530 	}
531 
532 	/* then close it */
533 	(void) close(fd);
534 
535 	return (RDR_OK);
536 }
537 
538 
539 /*
540  * rdr_close:
541  *
542  * Close down an given connection.
543  */
544 int
545 rdr_close(int fd)
546 {
547 	(void) close(fd);
548 
549 	return (RDR_OK);
550 }
551 
552 
553 /*
554  * rdr_snd_msg:
555  *
556  * Public interface for sending an RDR message. The data
557  * passed in through hdr and param are packed for network
558  * transport and sent.
559  */
560 int
561 rdr_snd_msg(int fd, rdr_msg_hdr_t *hdr, cfga_params_t *param, int timeout)
562 {
563 	int	err;
564 	char	*pack_buf = NULL;
565 	int	pack_buf_sz = 0;
566 
567 
568 	/* sanity checks */
569 	if ((hdr == NULL) || (param == NULL)) {
570 		return (RDR_ERROR);
571 	}
572 
573 	/*
574 	 * Pack the message for transport
575 	 */
576 	switch (hdr->message_opcode) {
577 
578 		case RDR_SES_REQ: {
579 
580 			ses_req_params_t *rparam;
581 			rparam = (ses_req_params_t *)param;
582 
583 			if (hdr->data_type == RDR_REQUEST) {
584 				err = pack_ses_req_request(rparam,
585 				    &pack_buf, &pack_buf_sz);
586 			} else {
587 				err = pack_ses_req_reply(rparam,
588 				    &pack_buf, &pack_buf_sz);
589 			}
590 
591 			break;
592 		}
593 
594 		case RDR_SES_ESTBL:
595 		case RDR_SES_END:
596 
597 			/*
598 			 * This is not an error condition because
599 			 * there is no extra information to pack.
600 			 */
601 			err = RDR_OK;
602 			break;
603 
604 		case RDR_CONF_CHANGE_STATE: {
605 
606 			change_state_params_t *cparam;
607 			cparam = (change_state_params_t *)param;
608 
609 			if (hdr->data_type == RDR_REQUEST) {
610 				err = pack_change_state_request(cparam,
611 				    &pack_buf, &pack_buf_sz);
612 			} else {
613 				err = pack_change_state_reply(cparam,
614 				    &pack_buf, &pack_buf_sz);
615 			}
616 			break;
617 		}
618 
619 		case RDR_CONF_PRIVATE_FUNC: {
620 
621 			private_func_params_t *pparam;
622 			pparam = (private_func_params_t *)param;
623 
624 			if (hdr->data_type == RDR_REQUEST) {
625 				err = pack_private_func_request(pparam,
626 				    &pack_buf, &pack_buf_sz);
627 			} else {
628 				err = pack_private_func_reply(pparam,
629 				    &pack_buf, &pack_buf_sz);
630 			}
631 			break;
632 		}
633 
634 		case RDR_CONF_TEST: {
635 
636 			test_params_t *tparam;
637 			tparam = (test_params_t *)param;
638 
639 			if (hdr->data_type == RDR_REQUEST) {
640 				err = pack_test_request(tparam,
641 				    &pack_buf, &pack_buf_sz);
642 			} else {
643 				err = pack_test_reply(tparam,
644 				    &pack_buf, &pack_buf_sz);
645 			}
646 			break;
647 		}
648 
649 		case RDR_CONF_LIST_EXT: {
650 
651 			list_ext_params_t *lparam;
652 			lparam = (list_ext_params_t *)param;
653 
654 			if (hdr->data_type == RDR_REQUEST) {
655 				err = pack_list_ext_request(lparam, &pack_buf,
656 				    &pack_buf_sz);
657 			} else {
658 				err = pack_list_ext_reply(lparam, &pack_buf,
659 				    &pack_buf_sz);
660 			}
661 			break;
662 		}
663 
664 		case RDR_CONF_HELP: {
665 
666 			help_params_t *hparam;
667 			hparam = (help_params_t *)param;
668 
669 			if (hdr->data_type == RDR_REQUEST) {
670 				err = pack_help_request(hparam,
671 				    &pack_buf, &pack_buf_sz);
672 			} else {
673 
674 				/*
675 				 * This is not an error because help
676 				 * reply does not have any extra information
677 				 * to pack.
678 				 */
679 				err = RDR_OK;
680 			}
681 			break;
682 		}
683 
684 		case RDR_CONF_AP_ID_CMP: {
685 
686 			ap_id_cmp_params_t *aparam;
687 			aparam = (ap_id_cmp_params_t *)param;
688 
689 			if (hdr->data_type == RDR_REQUEST) {
690 				err = pack_ap_id_cmp_request(aparam,
691 				    &pack_buf, &pack_buf_sz);
692 			} else {
693 
694 				/*
695 				 * This is not an error because ap_id_cmp
696 				 * reply does not have any extra information
697 				 * to pack.
698 				 */
699 				err = RDR_OK;
700 			}
701 			break;
702 		}
703 
704 		case RDR_CONF_ABORT_CMD: {
705 
706 			abort_cmd_params_t *aparam;
707 			aparam = (abort_cmd_params_t *)param;
708 
709 			if (hdr->data_type == RDR_REQUEST) {
710 				err = pack_abort_cmd_request(aparam,
711 				    &pack_buf, &pack_buf_sz);
712 			} else {
713 				/*
714 				 * This is not an error because session
715 				 * abort reply does not have any extra
716 				 * information to pack.
717 				 */
718 				err = RDR_OK;
719 			}
720 			break;
721 		}
722 
723 		case RDR_CONF_CONFIRM_CALLBACK: {
724 
725 			confirm_callback_params_t *cparam;
726 			cparam = (confirm_callback_params_t *)param;
727 
728 			if (hdr->data_type == RDR_REQUEST) {
729 				err = pack_confirm_request(cparam,
730 				    &pack_buf, &pack_buf_sz);
731 			} else {
732 				err = pack_confirm_reply(cparam, &pack_buf,
733 				    &pack_buf_sz);
734 			}
735 			break;
736 		}
737 
738 		case RDR_CONF_MSG_CALLBACK: {
739 
740 			msg_callback_params_t *mparam;
741 			mparam = (msg_callback_params_t *)param;
742 
743 			if (hdr->data_type == RDR_REQUEST) {
744 				err = pack_message_request(mparam,
745 				    &pack_buf, &pack_buf_sz);
746 			} else {
747 				/*
748 				 * It is an error to send a reply
749 				 * to a message callback.
750 				 */
751 				err = RDR_MSG_INVAL;
752 			}
753 			break;
754 		}
755 
756 		case RDR_RSRC_INFO: {
757 
758 			rsrc_info_params_t *rparam;
759 			rparam = (rsrc_info_params_t *)param;
760 
761 			if (hdr->data_type == RDR_REQUEST) {
762 				err = pack_rsrc_info_request(rparam, &pack_buf,
763 				    &pack_buf_sz);
764 			} else {
765 				if ((hdr->major_version == 1) &&
766 				    (hdr->minor_version == 0)) {
767 					err = pack_rsrc_info_reply(rparam,
768 					    &pack_buf, &pack_buf_sz,
769 					    NV_ENCODE_NATIVE);
770 				} else {
771 					err = pack_rsrc_info_reply(rparam,
772 					    &pack_buf, &pack_buf_sz,
773 					    NV_ENCODE_XDR);
774 				}
775 			}
776 			break;
777 		}
778 
779 		default:
780 			err = RDR_MSG_INVAL;
781 			break;
782 	}
783 
784 	/* check if packed correctly */
785 	if (err != RDR_OK) {
786 		return (err);
787 	}
788 
789 	/* send the message */
790 	err = rdr_snd(fd, hdr, pack_buf, pack_buf_sz, timeout);
791 
792 	free((void *)pack_buf);
793 
794 	return (err);
795 }
796 
797 
798 /*
799  * rdr_rcv_msg:
800  *
801  * Public interface for receiving an RDR message. Data is
802  * unpacked into the hdr and param paramters.
803  */
804 int
805 rdr_rcv_msg(int fd, rdr_msg_hdr_t *hdr, cfga_params_t *param, int timeout)
806 {
807 	int	err;
808 	char	*unpack_buf = NULL;
809 
810 
811 	/* sanity checks */
812 	if ((hdr == NULL) || (param == NULL)) {
813 		return (RDR_ERROR);
814 	}
815 
816 	(void) memset(param, 0, sizeof (cfga_params_t));
817 
818 	/* receive the message */
819 	if ((err = rdr_rcv(fd, hdr, &unpack_buf, timeout)) != RDR_OK) {
820 		return (err);
821 	}
822 
823 	/*
824 	 * Unpack the message
825 	 */
826 	switch (hdr->message_opcode) {
827 
828 		case RDR_SES_REQ: {
829 
830 			ses_req_params_t *rparam;
831 			rparam = (ses_req_params_t *)param;
832 
833 			if (hdr->data_type == RDR_REQUEST) {
834 				err = unpack_ses_req_request(rparam,
835 				    unpack_buf);
836 			} else {
837 				err = unpack_ses_req_reply(rparam, unpack_buf);
838 			}
839 			break;
840 		}
841 
842 		case RDR_SES_ESTBL:
843 		case RDR_SES_END:
844 
845 			/* no information to unpack */
846 			(void) memset(param, 0, sizeof (cfga_params_t));
847 			err = RDR_OK;
848 			break;
849 
850 		case RDR_CONF_CHANGE_STATE: {
851 
852 			change_state_params_t *cparam;
853 			cparam = (change_state_params_t *)param;
854 
855 			if (hdr->data_type == RDR_REQUEST) {
856 				err = unpack_change_state_request(cparam,
857 				    unpack_buf);
858 			} else {
859 				err = unpack_change_state_reply(cparam,
860 				    unpack_buf);
861 			}
862 			break;
863 		}
864 
865 		case RDR_CONF_PRIVATE_FUNC: {
866 
867 			private_func_params_t *pparam;
868 			pparam = (private_func_params_t *)param;
869 
870 			if (hdr->data_type == RDR_REQUEST) {
871 				err = unpack_private_func_request(pparam,
872 				    unpack_buf);
873 			} else {
874 				err = unpack_private_func_reply(pparam,
875 				    unpack_buf);
876 			}
877 			break;
878 		}
879 
880 		case RDR_CONF_TEST: {
881 
882 			test_params_t *tparam;
883 			tparam = (test_params_t *)param;
884 
885 			if (hdr->data_type == RDR_REQUEST) {
886 				err = unpack_test_request(tparam, unpack_buf);
887 			} else {
888 				err = unpack_test_reply(tparam, unpack_buf);
889 			}
890 			break;
891 		}
892 
893 		case RDR_CONF_LIST_EXT: {
894 
895 			list_ext_params_t *lparam;
896 			lparam = (list_ext_params_t *)param;
897 
898 			if (hdr->data_type == RDR_REQUEST) {
899 				err = unpack_list_ext_request(lparam,
900 				    unpack_buf);
901 			} else {
902 				err = unpack_list_ext_reply(lparam, unpack_buf);
903 			}
904 			break;
905 		}
906 
907 		case RDR_CONF_HELP: {
908 
909 			help_params_t *hparam;
910 			hparam = (help_params_t *)param;
911 
912 			if (hdr->data_type == RDR_REQUEST) {
913 				err = unpack_help_request(hparam,
914 				    unpack_buf);
915 			} else {
916 				/*
917 				 * This is not an error because help
918 				 * reply does not have any extra information
919 				 * to unpack.
920 				 */
921 				err = RDR_OK;
922 			}
923 			break;
924 		}
925 
926 		case RDR_CONF_AP_ID_CMP: {
927 
928 			ap_id_cmp_params_t *aparam;
929 			aparam = (ap_id_cmp_params_t *)param;
930 
931 			if (hdr->data_type == RDR_REQUEST) {
932 				err = unpack_ap_id_cmp_request(aparam,
933 				    unpack_buf);
934 			} else {
935 				/*
936 				 * This is not an error because ap_id_cmp
937 				 * reply does not have any extra information
938 				 * to pack.
939 				 */
940 				err = RDR_OK;
941 			}
942 			break;
943 		}
944 
945 		case RDR_CONF_ABORT_CMD: {
946 
947 			abort_cmd_params_t *aparam;
948 			aparam = (abort_cmd_params_t *)param;
949 
950 			if (hdr->data_type == RDR_REQUEST) {
951 				err = unpack_abort_cmd_request(aparam,
952 				    unpack_buf);
953 			} else {
954 				/* no information to unpack */
955 				(void) memset(param, 0, sizeof (cfga_params_t));
956 				err = RDR_OK;
957 			}
958 
959 			break;
960 		}
961 
962 		case RDR_CONF_CONFIRM_CALLBACK: {
963 
964 			confirm_callback_params_t *cparam;
965 			cparam = (confirm_callback_params_t *)param;
966 
967 			if (hdr->data_type == RDR_REQUEST) {
968 				err = unpack_confirm_request(cparam,
969 				    unpack_buf);
970 			} else {
971 				err = unpack_confirm_reply(cparam, unpack_buf);
972 			}
973 			break;
974 		}
975 
976 		case RDR_CONF_MSG_CALLBACK: {
977 
978 			msg_callback_params_t *mparam;
979 			mparam = (msg_callback_params_t *)param;
980 
981 			if (hdr->data_type == RDR_REQUEST) {
982 				err = unpack_message_request(mparam,
983 				    unpack_buf);
984 			} else {
985 				/*
986 				 * It is an error to send a reply
987 				 * to a message callback.
988 				 */
989 				(void) memset(param, 0, sizeof (cfga_params_t));
990 				err = RDR_MSG_INVAL;
991 			}
992 			break;
993 		}
994 
995 		case RDR_RSRC_INFO: {
996 
997 			rsrc_info_params_t *rparam;
998 			rparam = (rsrc_info_params_t *)param;
999 
1000 			if (hdr->data_type == RDR_REQUEST) {
1001 				err = unpack_rsrc_info_request(rparam,
1002 				    unpack_buf);
1003 			} else {
1004 				err = unpack_rsrc_info_reply(rparam,
1005 				    unpack_buf);
1006 			}
1007 			break;
1008 		}
1009 
1010 		default:
1011 			err = RDR_MSG_INVAL;
1012 			break;
1013 	}
1014 
1015 	free(unpack_buf);
1016 
1017 	/* check if unpacked correctly */
1018 	if (err != RDR_OK) {
1019 		return (err);
1020 	}
1021 
1022 	return (RDR_OK);
1023 }
1024 
1025 
1026 /*
1027  * rdr_cleanup_params:
1028  *
1029  * Deallocate any memory that was allocated in unpacking a
1030  * message.
1031  */
1032 int
1033 rdr_cleanup_params(rdr_msg_opcode_t message_opcode, cfga_params_t *param)
1034 {
1035 	/* sanity check */
1036 	if ((param == NULL)) {
1037 		return (RDR_ERROR);
1038 	}
1039 
1040 	/*
1041 	 * Deallocate memory depending on
1042 	 * the operation.
1043 	 */
1044 	switch (message_opcode) {
1045 
1046 	case RDR_SES_REQ: {
1047 
1048 		ses_req_params_t *sparam;
1049 		sparam = (ses_req_params_t *)param;
1050 
1051 		if (sparam->locale_str != NULL) {
1052 			free((void *)sparam->locale_str);
1053 			sparam->locale_str = NULL;
1054 		}
1055 		break;
1056 	}
1057 
1058 	case RDR_SES_ESTBL:
1059 	case RDR_SES_END:
1060 
1061 		/* nothing to deallocate */
1062 		break;
1063 
1064 	case RDR_CONF_CHANGE_STATE: {
1065 
1066 		change_state_params_t *cparam;
1067 		cparam = (change_state_params_t *)param;
1068 
1069 		cleanup_ap_ids(cparam->num_ap_ids, (char **)cparam->ap_ids);
1070 		cparam->ap_ids = NULL;
1071 		if (cparam->options != NULL) {
1072 			free((void *)cparam->options);
1073 			cparam->options = NULL;
1074 		}
1075 		if (cparam->confp != NULL) {
1076 			free((void *)cparam->confp);
1077 			cparam->confp = NULL;
1078 		}
1079 		if (cparam->msgp != NULL) {
1080 			free((void *)cparam->msgp);
1081 			cparam->msgp = NULL;
1082 		}
1083 		cleanup_errstring(cparam->errstring);
1084 		break;
1085 	}
1086 
1087 	case RDR_CONF_PRIVATE_FUNC: {
1088 
1089 		private_func_params_t *pparam;
1090 		pparam = (private_func_params_t *)param;
1091 
1092 		cleanup_ap_ids(pparam->num_ap_ids, (char **)pparam->ap_ids);
1093 		pparam->ap_ids = NULL;
1094 		if (pparam->options != NULL) {
1095 			free((void *)pparam->options);
1096 			pparam->options = NULL;
1097 		}
1098 		if (pparam->confp != NULL) {
1099 			free((void *)pparam->confp);
1100 			pparam->confp = NULL;
1101 		}
1102 		if (pparam->msgp != NULL) {
1103 			free((void *)pparam->msgp);
1104 			pparam->msgp = NULL;
1105 		}
1106 		cleanup_errstring(pparam->errstring);
1107 		break;
1108 	}
1109 
1110 	case RDR_CONF_TEST: {
1111 
1112 		test_params_t *tparam;
1113 		tparam = (test_params_t *)param;
1114 
1115 		cleanup_ap_ids(tparam->num_ap_ids, (char **)tparam->ap_ids);
1116 		tparam->ap_ids = NULL;
1117 		if (tparam->options != NULL) {
1118 			free((void *)tparam->options);
1119 			tparam->options = NULL;
1120 		}
1121 		if (tparam->msgp != NULL) {
1122 			free((void *)tparam->msgp);
1123 			tparam->msgp = NULL;
1124 		}
1125 		cleanup_errstring(tparam->errstring);
1126 		break;
1127 	}
1128 
1129 	case RDR_CONF_LIST_EXT: {
1130 
1131 		list_ext_params_t *lparam;
1132 		lparam = (list_ext_params_t *)param;
1133 
1134 		cleanup_ap_ids(lparam->num_ap_ids, (char **)lparam->ap_ids);
1135 		lparam->ap_ids = NULL;
1136 
1137 		if (lparam->nlist != NULL) {
1138 			free((void *)lparam->nlist);
1139 			lparam->nlist = NULL;
1140 		}
1141 		if (lparam->ap_id_list != NULL) {
1142 			if (*lparam->ap_id_list != NULL) {
1143 				free((void *)*lparam->ap_id_list);
1144 			}
1145 			free((void *)lparam->ap_id_list);
1146 			lparam->ap_id_list = NULL;
1147 		}
1148 		if (lparam->ap_id_list != NULL) {
1149 			free((void *)lparam->ap_id_list);
1150 			lparam->ap_id_list = NULL;
1151 		}
1152 
1153 		if (lparam->options != NULL) {
1154 			free((void *)lparam->options);
1155 			lparam->options = NULL;
1156 		}
1157 		if (lparam->listopts != NULL) {
1158 			free((void *)lparam->listopts);
1159 			lparam->listopts = NULL;
1160 		}
1161 		cleanup_errstring(lparam->errstring);
1162 		break;
1163 	}
1164 
1165 	case RDR_CONF_HELP: {
1166 
1167 		help_params_t *hparam;
1168 		hparam = (help_params_t *)param;
1169 
1170 		cleanup_ap_ids(hparam->num_ap_ids, (char **)hparam->ap_ids);
1171 		hparam->ap_ids = NULL;
1172 		if (hparam->msgp != NULL) {
1173 			free((void *)hparam->msgp);
1174 			hparam->msgp = NULL;
1175 		}
1176 		if (hparam->options != NULL) {
1177 			free((void *)hparam->options);
1178 			hparam->options = NULL;
1179 		}
1180 		break;
1181 	}
1182 
1183 	case RDR_CONF_AP_ID_CMP: {
1184 
1185 		ap_id_cmp_params_t *aparam;
1186 		aparam = (ap_id_cmp_params_t *)param;
1187 
1188 		if (aparam->ap_log_id1 != NULL) {
1189 			free((void *)aparam->ap_log_id1);
1190 			aparam->ap_log_id1 = NULL;
1191 		}
1192 		if (aparam->ap_log_id2 != NULL) {
1193 			free((void *)aparam->ap_log_id2);
1194 			aparam->ap_log_id2 = NULL;
1195 		}
1196 		break;
1197 	}
1198 
1199 	case RDR_CONF_ABORT_CMD:
1200 
1201 		/* nothing to deallocate */
1202 		break;
1203 
1204 	case RDR_CONF_CONFIRM_CALLBACK: {
1205 
1206 		confirm_callback_params_t *cparam;
1207 		cparam = (confirm_callback_params_t *)param;
1208 
1209 		if (cparam->confp != NULL) {
1210 			free((void *)cparam->confp);
1211 			cparam->confp = NULL;
1212 		}
1213 		if (cparam->message != NULL) {
1214 			free((void *)cparam->message);
1215 			cparam->message = NULL;
1216 		}
1217 		break;
1218 	}
1219 
1220 	case RDR_CONF_MSG_CALLBACK: {
1221 
1222 		msg_callback_params_t *mparam;
1223 		mparam = (msg_callback_params_t *)param;
1224 
1225 		if (mparam->msgp != NULL) {
1226 			free((void *)mparam->msgp);
1227 			mparam->msgp = NULL;
1228 		}
1229 		if (mparam->message != NULL) {
1230 			free((void *)mparam->message);
1231 			mparam->message = NULL;
1232 		}
1233 		break;
1234 	}
1235 
1236 	default:
1237 		return (RDR_ERROR);
1238 		/* NOTREACHED */
1239 		break;
1240 
1241 	}
1242 
1243 	return (RDR_OK);
1244 }
1245 
1246 /*
1247  * rdr_setsockopt:
1248  *
1249  * Wrapper of the setsockopt(3SOCKET) library function.
1250  */
1251 int
1252 rdr_setsockopt(int fd, int level, int optname, const void *optval, int optlen)
1253 {
1254 	if (setsockopt(fd, level, optname, optval, optlen) == -1)
1255 		return (RDR_NET_ERR);
1256 	else
1257 		return (RDR_OK);
1258 }
1259 
1260 
1261 /*
1262  * Private (static) Functions
1263  */
1264 
1265 
1266 /*
1267  * rdr_setopt:
1268  *
1269  * Set the specified option for a given transport endpoint.
1270  * This function only sets boolean options. It does not
1271  * provide the ability to unset an option, or set a non-
1272  * boolean option.
1273  */
1274 static int
1275 rdr_setopt(int fd, int name, int level)
1276 {
1277 	int	on = 1;
1278 
1279 
1280 	if (setsockopt(fd, level, name, &on, sizeof (on)) == -1) {
1281 		return (RDR_NET_ERR);
1282 	}
1283 
1284 	return (RDR_OK);
1285 }
1286 
1287 
1288 /*
1289  * rdr_bind:
1290  *
1291  * Bind the specified file descriptor to a specified
1292  * address. If the address is already bound, no error is
1293  * returned. This is the expected behavior if a server
1294  * has been started by inetd(8).
1295  */
1296 static int
1297 rdr_bind(int fd, struct sockaddr *addr)
1298 {
1299 	unsigned int		addr_len;
1300 	int			rc;
1301 
1302 
1303 	/* initialize the address */
1304 	switch (addr->sa_family) {
1305 
1306 	case AF_INET:
1307 		addr_len = sizeof (struct sockaddr_in);
1308 		break;
1309 
1310 	case AF_INET6:
1311 		addr_len = sizeof (struct sockaddr_in6);
1312 		break;
1313 
1314 	default:
1315 		return (RDR_ERROR);
1316 	}
1317 
1318 	/* attempt to bind the address */
1319 	rc = bind(fd, addr, addr_len);
1320 
1321 	/*
1322 	 * Ignore the error if EINVAL is returned. In
1323 	 * this case, we assume that this means that
1324 	 * the address was already bound. This is not
1325 	 * an error for servers started by inetd(8).
1326 	 */
1327 	if ((rc == -1) && (errno != EINVAL)) {
1328 		return (RDR_NET_ERR);
1329 	}
1330 
1331 	/*
1332 	 * Retreive the address information of the
1333 	 * address that was actually bound.
1334 	 */
1335 	addr_len = sizeof (*addr);
1336 	if (getsockname(fd, addr, &addr_len) == -1) {
1337 		(void) memset(addr, 0, sizeof (*addr));
1338 		return (RDR_NET_ERR);
1339 	}
1340 
1341 	return (RDR_OK);
1342 }
1343 
1344 
1345 /*
1346  * rdr_secure:
1347  *
1348  * Activate security features for a socket.
1349  *
1350  * Some platforms have libdscp, which provides additional
1351  * security features.  An attempt is made to load libdscp
1352  * and use these features.
1353  *
1354  * Nothing is done if libdscp is not available.
1355  */
1356 static int
1357 rdr_secure(int fd, struct sockaddr *addr)
1358 {
1359 	struct sockaddr_in	*sin;
1360 	int			port;
1361 	int			error;
1362 
1363 	if (use_libdscp == 0) {
1364 		return (RDR_OK);
1365 	}
1366 
1367 	if (load_libdscp(&libdscp) != 1) {
1368 		return (RDR_ERROR);
1369 	}
1370 
1371 	/* LINTED E_BAD_PTR_CAST_ALIGN */
1372 	sin = (struct sockaddr_in *)addr;
1373 	port = ntohs(sin->sin_port);
1374 	error = libdscp.bind(0, fd, port);
1375 
1376 	if ((error != DSCP_OK) && (error != DSCP_ERROR_ALREADY)) {
1377 		return (RDR_ERROR);
1378 	}
1379 
1380 	if (libdscp.secure(0, fd) != DSCP_OK) {
1381 		return (RDR_ERROR);
1382 	}
1383 	return (RDR_OK);
1384 }
1385 
1386 /*
1387  * rdr_auth:
1388  *
1389  * Authenticate if a connection is really from the service
1390  * processor.  This is dependent upon functionality from
1391  * libdscp, so an attempt to load and use libdscp is made.
1392  *
1393  * Without libdscp, this function does nothing.
1394  */
1395 static int
1396 rdr_auth(struct sockaddr *addr, int len)
1397 {
1398 	if (use_libdscp != 0) {
1399 		if ((load_libdscp(&libdscp) == 0) ||
1400 		    (libdscp.auth(0, addr, len) != DSCP_OK)) {
1401 			return (RDR_ERROR);
1402 		}
1403 	}
1404 
1405 	return (RDR_OK);
1406 }
1407 
1408 /*
1409  * rdr_snd:
1410  *
1411  * Send a message in two stages. First the header is sent,
1412  * followed by the packed buffer containing the message
1413  * contents.
1414  */
1415 static int
1416 rdr_snd(int fd, rdr_msg_hdr_t *hdr, char *data, int data_sz, int timeout)
1417 {
1418 	int	err;
1419 
1420 
1421 	/* sanity check */
1422 	if (hdr == NULL) {
1423 		return (RDR_ERROR);
1424 	}
1425 
1426 	/* ensure null pad bytes */
1427 	hdr->pad_byte1 = 0;
1428 	hdr->pad_byte2 = 0;
1429 
1430 	/* initialize size information */
1431 	hdr->data_length = data_sz;
1432 
1433 	/* send message header */
1434 	err = rdr_snd_raw(fd, (char *)hdr, RDR_MSG_HDR_SIZE, timeout);
1435 	if (err != RDR_OK) {
1436 		return (err);
1437 	}
1438 
1439 	/* check if more to send */
1440 	if (data_sz == 0) {
1441 		return (RDR_OK);
1442 	}
1443 
1444 	/* send message data */
1445 	err = rdr_snd_raw(fd, data, data_sz, timeout);
1446 	if (err != RDR_OK) {
1447 		return (err);
1448 	}
1449 
1450 	return (RDR_OK);
1451 }
1452 
1453 
1454 /*
1455  * rdr_snd_raw:
1456  *
1457  * Send a raw buffer of information. This function handles
1458  * the low level details of the send operation.
1459  */
1460 static int
1461 rdr_snd_raw(int fd, char *msg, int data_sz, int timeout)
1462 {
1463 	int		err;
1464 	int		num_bytes;
1465 	int		bytes_left;
1466 	char		*bufp;
1467 	struct pollfd	pfd;
1468 
1469 
1470 	bufp = (char *)msg;
1471 
1472 	bytes_left = data_sz;
1473 
1474 	pfd.fd = fd;
1475 	pfd.events = POLLOUT;
1476 
1477 	while (bytes_left > 0) {
1478 
1479 		pfd.revents = 0;
1480 
1481 		/* wait until we can send the data */
1482 		if ((err = poll(&pfd, 1, timeout)) == -1) {
1483 
1484 			/* poll was interrupted */
1485 			if (errno == EINTR) {
1486 				return (RDR_ABORTED);
1487 			}
1488 
1489 			return (RDR_ERROR);
1490 
1491 		} else if (err == 0) {
1492 			return (RDR_TIMEOUT);
1493 		}
1494 
1495 		/* ready to send data */
1496 		if (pfd.revents & POLLOUT) {
1497 
1498 			num_bytes = write(fd, bufp, bytes_left);
1499 
1500 			if (num_bytes == -1) {
1501 
1502 				/*
1503 				 * Distinguish between an aborted
1504 				 * session and other network errors.
1505 				 */
1506 				if (errno == EPIPE) {
1507 					return (RDR_ABORTED);
1508 				} else {
1509 					return (RDR_NET_ERR);
1510 				}
1511 			}
1512 
1513 			/* wrote 0 bytes, so operation was aborted */
1514 			if (num_bytes == 0) {
1515 				return (RDR_ABORTED);
1516 			}
1517 
1518 		} else {
1519 			return (RDR_NET_ERR);
1520 		}
1521 
1522 		bytes_left -= num_bytes;
1523 		bufp += num_bytes;
1524 	}
1525 
1526 	return (RDR_OK);
1527 }
1528 
1529 
1530 /*
1531  * rdr_rcv:
1532  *
1533  * Receive a message in two stages. First the header is
1534  * received, followed by the packed buffer containing the
1535  * message contents.
1536  */
1537 static int
1538 rdr_rcv(int fd, rdr_msg_hdr_t *hdr, char **data, int timeout)
1539 {
1540 	int	err;
1541 	int	data_sz;
1542 	char	hdr_buf[RDR_MSG_HDR_SIZE];
1543 	char	*buf = NULL;
1544 
1545 
1546 	/* sanity check */
1547 	if (hdr == NULL) {
1548 		return (RDR_ERROR);
1549 	}
1550 
1551 	/* receive the header */
1552 	err = rdr_rcv_raw(fd, hdr_buf, RDR_MSG_HDR_SIZE, timeout);
1553 	if (err != RDR_OK) {
1554 		return (err);
1555 	}
1556 
1557 	/* verify that the data is good */
1558 	/* LINTED Pointer Cast Alignment Warning */
1559 	if (validate_header((rdr_msg_hdr_t *)hdr_buf) != RDR_OK) {
1560 		return (RDR_MSG_INVAL);
1561 	}
1562 
1563 	/* LINTED Pointer Cast Alignment Warning */
1564 	data_sz = ((rdr_msg_hdr_t *)hdr_buf)->data_length;
1565 
1566 	buf = (char *)malloc(data_sz);
1567 	if (!buf) {
1568 		return (RDR_MEM_ALLOC);
1569 	}
1570 
1571 	if (data_sz != 0) {
1572 
1573 		/* receive the rest of the message */
1574 		err = rdr_rcv_raw(fd, buf, data_sz, timeout);
1575 		if (err != RDR_OK) {
1576 			free((void *)buf);
1577 			return (err);
1578 		}
1579 	}
1580 
1581 	/* copy out data */
1582 	*data = buf;
1583 	(void) memcpy(hdr, hdr_buf, RDR_MSG_HDR_SIZE);
1584 
1585 	return (RDR_OK);
1586 }
1587 
1588 
1589 /*
1590  * rdr_rcv_raw:
1591  *
1592  * Receive a raw buffer of information. This function handles
1593  * the low level details of the receive operation.
1594  */
1595 static int
1596 rdr_rcv_raw(int fd, char *msg, int data_size, int timeout)
1597 {
1598 	int		num_bytes;
1599 	int		err;
1600 	int		bytes_left;
1601 	char		*bufp;
1602 	struct pollfd	pollfd;
1603 
1604 
1605 	bufp = (char *)msg;
1606 	bytes_left = data_size;
1607 
1608 	pollfd.fd = fd;
1609 	pollfd.events = POLLIN;
1610 
1611 	while (bytes_left > 0) {
1612 
1613 		errno = 0;
1614 		pollfd.revents = 0;
1615 
1616 		if ((err = poll(&pollfd, 1, timeout)) == -1) {
1617 
1618 			/*
1619 			 * In the DCA, if a session is aborted, SIGINT
1620 			 * is delivered to all active sessions. This
1621 			 * mistakenly causes all sessions waiting in
1622 			 * the poll to be interrupted. So, if EINTR
1623 			 * is returned, it is ignored. If another error
1624 			 * occurs right away, the current session really
1625 			 * was aborted. All other sessions won't encounter
1626 			 * an error and will proceed normally.
1627 			 */
1628 			if ((errno == 0) || (errno == EINTR)) {
1629 				continue;
1630 			}
1631 
1632 			return (RDR_ABORTED);
1633 
1634 		} else if (err == 0) {
1635 			return (RDR_TIMEOUT);
1636 		}
1637 
1638 		/* ready to receive data */
1639 		if (pollfd.revents & POLLIN) {
1640 
1641 			num_bytes = read(fd, bufp, bytes_left);
1642 
1643 			if (num_bytes == -1) {
1644 
1645 				/*
1646 				 * Distinguish between an aborted
1647 				 * session and other network errors.
1648 				 */
1649 				if (errno == ECONNRESET) {
1650 					return (RDR_ABORTED);
1651 				} else {
1652 					return (RDR_NET_ERR);
1653 				}
1654 			}
1655 
1656 			/* read 0 bytes, so operation was aborted */
1657 			if (num_bytes == 0) {
1658 				return (RDR_ABORTED);
1659 			}
1660 
1661 		} else {
1662 			return (RDR_NET_ERR);
1663 		}
1664 
1665 		bytes_left -= num_bytes;
1666 		bufp += num_bytes;
1667 	}
1668 
1669 	return (RDR_OK);
1670 }
1671 
1672 
1673 /*
1674  * validate_header:
1675  *
1676  * Perform a series of sanity checks on the header data that is
1677  * received. This gets called before the variable length data is
1678  * read in to make sure that the information in the header can
1679  * be trusted.
1680  */
1681 static int
1682 validate_header(rdr_msg_hdr_t *hdr)
1683 {
1684 	unsigned char	op;
1685 
1686 
1687 	if (hdr == NULL) {
1688 		return (RDR_ERROR);
1689 	}
1690 
1691 	op = hdr->message_opcode;
1692 
1693 	/* validate opcode */
1694 	if ((op < RDR_SES_REQ) || (op >= RDR_NUM_OPS)) {
1695 		return (RDR_ERROR);
1696 	}
1697 
1698 	/* validate message size (and type) for op */
1699 	switch (hdr->data_type) {
1700 
1701 	case RDR_REQUEST:
1702 		if (hdr->data_length > msg_sizes[op].req_max) {
1703 			return (RDR_ERROR);
1704 		}
1705 		break;
1706 
1707 	case RDR_REPLY:
1708 		if (hdr->data_length > msg_sizes[op].reply_max) {
1709 			return (RDR_ERROR);
1710 		}
1711 		break;
1712 
1713 	default:
1714 		/* invalid data type */
1715 		return (RDR_ERROR);
1716 	}
1717 
1718 	/* all checks passed */
1719 	return (RDR_OK);
1720 }
1721 
1722 
1723 /*
1724  * pack_ses_req_request:
1725  *
1726  * Handle packing a session request request message.
1727  */
1728 static int
1729 pack_ses_req_request(ses_req_params_t *params, char **buf, int *buf_size)
1730 {
1731 	char		*bufptr;
1732 	int		locale_str_len;
1733 	rdr_ses_req_t	ses_req;
1734 
1735 
1736 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
1737 		return (RDR_ERROR);
1738 	}
1739 
1740 	/*
1741 	 * Determine the size of the locale string
1742 	 */
1743 	if (params->locale_str != NULL) {
1744 		locale_str_len = strlen(params->locale_str) + 1;
1745 	} else {
1746 		locale_str_len = 0;
1747 	}
1748 
1749 	/*
1750 	 * Collect size info specific to the ses_req request message
1751 	 * and allocate a buffer
1752 	 */
1753 	*buf_size = sizeof (rdr_ses_req_t);
1754 	*buf_size += locale_str_len;
1755 
1756 	*buf = (char *)malloc(*buf_size);
1757 	if (*buf == NULL) {
1758 		return (RDR_MEM_ALLOC);
1759 	}
1760 
1761 	/*
1762 	 * Set fixed locale size label by name
1763 	 */
1764 	ses_req.locale_size = locale_str_len;
1765 
1766 	/*
1767 	 * Set variable information using memcpy
1768 	 */
1769 	bufptr = *buf;
1770 
1771 	(void) memcpy(bufptr, &ses_req, sizeof (rdr_ses_req_t));
1772 	bufptr += sizeof (rdr_ses_req_t);
1773 
1774 	if (params->locale_str != NULL) {
1775 		(void) memcpy(bufptr, params->locale_str, locale_str_len);
1776 		bufptr += locale_str_len;
1777 	}
1778 
1779 	return (RDR_OK);
1780 }
1781 
1782 
1783 /*
1784  * unpack_ses_req_request:
1785  *
1786  * Handle unpacking a session request request message.
1787  */
1788 static int
1789 unpack_ses_req_request(ses_req_params_t *params, const char *buf)
1790 {
1791 	char		*bufptr;
1792 	rdr_ses_req_t	ses_req_data;
1793 
1794 
1795 	if ((params == NULL) || (buf == NULL)) {
1796 		return (RDR_ERROR);
1797 	}
1798 
1799 	bufptr = (char *)buf;
1800 	(void) memcpy(&ses_req_data, bufptr, sizeof (rdr_ses_req_t));
1801 	bufptr += sizeof (rdr_ses_req_t);
1802 
1803 	/*
1804 	 * handle getting the locale string
1805 	 */
1806 	if (get_string_from_buf(&(params->locale_str),
1807 	    ses_req_data.locale_size, bufptr)) {
1808 		return (RDR_ERROR);
1809 	}
1810 
1811 	return (RDR_OK);
1812 }
1813 
1814 
1815 /*
1816  * pack_ses_req_reply:
1817  *
1818  * Handle packing a session request reply message.
1819  */
1820 static int
1821 pack_ses_req_reply(ses_req_params_t *params, char **buf, int *buf_size)
1822 {
1823 	rdr_ses_req_reply_t	ses_req_reply_data;
1824 
1825 
1826 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
1827 		return (RDR_ERROR);
1828 	}
1829 
1830 	/*
1831 	 * Collect size info specific to the session request reply
1832 	 * message and allocate a buffer
1833 	 */
1834 	*buf_size = sizeof (rdr_ses_req_reply_t);
1835 
1836 	*buf = (char *)malloc(*buf_size);
1837 	if (*buf == NULL) {
1838 		return (RDR_MEM_ALLOC);
1839 	}
1840 
1841 	/*
1842 	 * Set fixed session identifier
1843 	 */
1844 	ses_req_reply_data.session_id = params->session_id;
1845 
1846 	/*
1847 	 * Copy information using memcpy
1848 	 */
1849 	(void) memcpy(*buf, &ses_req_reply_data, sizeof (rdr_ses_req_reply_t));
1850 
1851 	return (RDR_OK);
1852 }
1853 
1854 
1855 /*
1856  * unpack_ses_req_request:
1857  *
1858  * Handle unpacking a session request reply message.
1859  */
1860 static int
1861 unpack_ses_req_reply(ses_req_params_t *params, const char *buf)
1862 {
1863 	rdr_ses_req_reply_t	*ses_req_reply_datap;
1864 
1865 
1866 	if ((params == NULL) || (buf == NULL)) {
1867 		return (RDR_ERROR);
1868 	}
1869 
1870 	/* LINTED Pointer Cast Alignment Warning */
1871 	ses_req_reply_datap = (rdr_ses_req_reply_t *)buf;
1872 
1873 	/*
1874 	 * copy out the session information
1875 	 */
1876 	params->session_id = ses_req_reply_datap->session_id;
1877 
1878 	return (RDR_OK);
1879 }
1880 
1881 
1882 /*
1883  * pack_change_state_request:
1884  *
1885  * Handle packing a change state request message.
1886  */
1887 static int
1888 pack_change_state_request(change_state_params_t *params, char **buf,
1889     int *buf_size)
1890 {
1891 	int				i;
1892 	char				*bufptr;
1893 	rdr_change_state_t		change_state_data;
1894 	rdr_variable_message_info_t	var_msg_info;
1895 
1896 
1897 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
1898 		return (RDR_ERROR);
1899 	}
1900 
1901 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
1902 
1903 	/*
1904 	 * Set variable length fields and make a call to partially
1905 	 * pack it.
1906 	 */
1907 	if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) {
1908 		cleanup_variable_ap_id_info(&var_msg_info);
1909 		return (RDR_ERROR);
1910 	}
1911 	if (find_options_sizes(params->options, &var_msg_info)) {
1912 		cleanup_variable_ap_id_info(&var_msg_info);
1913 		return (RDR_ERROR);
1914 	}
1915 
1916 	/*
1917 	 * Collect size info specific to the change_state request
1918 	 * message and allocate a buffer
1919 	 */
1920 	*buf_size = sizeof (rdr_change_state_t);
1921 	*buf_size += var_msg_info.ap_id_int_size;
1922 	*buf_size += var_msg_info.ap_id_char_size;
1923 	*buf_size += var_msg_info.options_strlen;
1924 	*buf_size += var_msg_info.options_pad_sz;
1925 
1926 	*buf = (char *)malloc(*buf_size);
1927 	if (*buf == NULL) {
1928 		cleanup_variable_ap_id_info(&var_msg_info);
1929 		return (RDR_MEM_ALLOC);
1930 	}
1931 
1932 	/*
1933 	 * Set fixed address labels by name
1934 	 */
1935 	change_state_data.num_ap_ids = params->num_ap_ids;
1936 	change_state_data.ap_id_char_size = var_msg_info.ap_id_char_size;
1937 	change_state_data.options_size = var_msg_info.options_strlen +
1938 	    var_msg_info.options_pad_sz;
1939 
1940 	if (params->confp != NULL) {
1941 		change_state_data.confirm_callback_id =
1942 		    (unsigned long)params->confp->confirm;
1943 		change_state_data.confirm_appdata_ptr =
1944 		    (unsigned long)params->confp->appdata_ptr;
1945 	} else {
1946 		change_state_data.confirm_callback_id = 0;
1947 		change_state_data.confirm_appdata_ptr = 0;
1948 	}
1949 	if (params->msgp != NULL) {
1950 		change_state_data.msg_callback_id =
1951 		    (unsigned long)params->msgp->message_routine;
1952 		change_state_data.msg_appdata_ptr =
1953 		    (unsigned long)params->msgp->appdata_ptr;
1954 	} else {
1955 		change_state_data.msg_callback_id = 0;
1956 		change_state_data.msg_appdata_ptr = 0;
1957 	}
1958 
1959 	change_state_data.flags = params->flags;
1960 	change_state_data.timeval = params->timeval;
1961 	change_state_data.state_change_cmd = params->state_change;
1962 	if (params->errstring != NULL) {
1963 		change_state_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS;
1964 	} else {
1965 		change_state_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS;
1966 	}
1967 	change_state_data.retries = params->retries;
1968 
1969 	/*
1970 	 * Set variable information using memcpy
1971 	 */
1972 	bufptr = *buf;
1973 
1974 	(void) memcpy(bufptr, &change_state_data, sizeof (rdr_change_state_t));
1975 	bufptr += sizeof (rdr_change_state_t);
1976 
1977 	if (var_msg_info.ap_id_sizes != NULL) {
1978 		(void) memcpy(bufptr, var_msg_info.ap_id_sizes,
1979 		    var_msg_info.ap_id_int_size);
1980 		bufptr += var_msg_info.ap_id_int_size;
1981 	}
1982 
1983 	if (var_msg_info.ap_id_chars != NULL) {
1984 		(void) memcpy(bufptr, var_msg_info.ap_id_chars,
1985 		    var_msg_info.ap_id_char_size);
1986 		bufptr += var_msg_info.ap_id_char_size;
1987 	}
1988 
1989 	if (params->options != NULL) {
1990 		(void) memcpy(bufptr, params->options,
1991 		    var_msg_info.options_strlen);
1992 		bufptr += var_msg_info.options_strlen;
1993 		for (i = 0; i < var_msg_info.options_pad_sz; i++) {
1994 			bufptr[i] = 0;
1995 		}
1996 		bufptr += var_msg_info.options_pad_sz;
1997 	}
1998 
1999 	cleanup_variable_ap_id_info(&var_msg_info);
2000 
2001 	return (RDR_OK);
2002 }
2003 
2004 
2005 /*
2006  * unpack_change_state_request:
2007  *
2008  * Handle unpacking a change state request message.
2009  */
2010 static int
2011 unpack_change_state_request(change_state_params_t *params, const char *buf)
2012 {
2013 	char				*bufptr;
2014 	rdr_variable_message_info_t	var_msg_info;
2015 	rdr_change_state_t		change_state_data;
2016 
2017 
2018 	if ((params == NULL) || (buf == NULL)) {
2019 		return (RDR_ERROR);
2020 	}
2021 
2022 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2023 
2024 	bufptr = (char *)buf;
2025 	(void) memcpy(&change_state_data, bufptr, sizeof (rdr_change_state_t));
2026 	bufptr += sizeof (rdr_change_state_t);
2027 
2028 	/*
2029 	 * handle getting the ap_ids
2030 	 */
2031 	var_msg_info.ap_id_char_size = change_state_data.ap_id_char_size;
2032 	if (get_ap_ids_from_buf((char ***)&(params->ap_ids),
2033 	    change_state_data.num_ap_ids, &var_msg_info, bufptr)) {
2034 		return (RDR_ERROR);
2035 	}
2036 	bufptr += var_msg_info.ap_id_int_size;
2037 	bufptr += var_msg_info.ap_id_char_size;
2038 
2039 	/*
2040 	 * handle getting the options
2041 	 */
2042 	if (get_string_from_buf(&(params->options),
2043 	    change_state_data.options_size, bufptr)) {
2044 		return (RDR_ERROR);
2045 	}
2046 	bufptr += change_state_data.options_size;
2047 
2048 	/*
2049 	 * Set fixed address labels by name
2050 	 */
2051 	params->state_change = (cfga_cmd_t)change_state_data.state_change_cmd;
2052 	params->num_ap_ids = change_state_data.num_ap_ids;
2053 
2054 	params->confp = (struct cfga_confirm *)
2055 	    malloc(sizeof (struct cfga_confirm));
2056 	if (params->confp == NULL) {
2057 		return (RDR_MEM_ALLOC);
2058 	}
2059 
2060 	/* set params->confp->confirm using memcpy */
2061 	(void) memcpy((void*)params->confp,
2062 	    &(change_state_data.confirm_callback_id), sizeof (unsigned long));
2063 	params->confp->appdata_ptr =
2064 	    (void*)change_state_data.confirm_appdata_ptr;
2065 
2066 	params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg));
2067 	if (params->msgp == NULL) {
2068 		return (RDR_MEM_ALLOC);
2069 	}
2070 
2071 	/* set params->msgp->message_routine using memcpy */
2072 	(void) memcpy((void*)params->msgp,
2073 	    &(change_state_data.msg_callback_id), sizeof (unsigned long));
2074 	params->msgp->appdata_ptr =
2075 	    (void*)change_state_data.msg_appdata_ptr;
2076 
2077 	if (change_state_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) {
2078 		params->errstring = (char **)malloc(sizeof (char *));
2079 		if (params->errstring == NULL) {
2080 			return (RDR_MEM_ALLOC);
2081 		}
2082 		*(params->errstring) = NULL;
2083 	} else {	/* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */
2084 		params->errstring = NULL;
2085 	}
2086 	params->flags = change_state_data.flags;
2087 	params->timeval = change_state_data.timeval;
2088 	params->retries = change_state_data.retries;
2089 
2090 	return (RDR_OK);
2091 }
2092 
2093 
2094 /*
2095  * pack_change_state_reply:
2096  *
2097  * Handle packing a change state reply message.
2098  */
2099 static int
2100 pack_change_state_reply(change_state_params_t *params, char **buf,
2101     int *buf_size)
2102 {
2103 	int				i;
2104 	char				*bufptr;
2105 	rdr_change_state_reply_t	change_state_data;
2106 	rdr_variable_message_info_t	var_msg_info;
2107 
2108 
2109 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2110 
2111 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
2112 		return (RDR_ERROR);
2113 	}
2114 
2115 	/*
2116 	 * Set variable length fields (size info)
2117 	 */
2118 	if (find_errstring_sizes(params->errstring, &var_msg_info)) {
2119 		return (RDR_ERROR);
2120 	}
2121 
2122 	/*
2123 	 * Collect size info specific to the change_state reply
2124 	 * message and allocate a buffer
2125 	 */
2126 	*buf_size = sizeof (rdr_change_state_reply_t);
2127 	*buf_size += var_msg_info.errstring_strlen;
2128 	*buf_size += var_msg_info.errstring_pad_sz;
2129 
2130 	*buf = (char *)malloc(*buf_size);
2131 	if (*buf == NULL) {
2132 		return (RDR_MEM_ALLOC);
2133 	}
2134 
2135 	/*
2136 	 * Set fixed address labels by name
2137 	 */
2138 	change_state_data.errstring_size = var_msg_info.errstring_strlen +
2139 	    var_msg_info.errstring_pad_sz;
2140 
2141 	/*
2142 	 * Set variable information using memcpy
2143 	 */
2144 	bufptr = *buf;
2145 
2146 	(void) memcpy(bufptr, &change_state_data,
2147 	    sizeof (rdr_change_state_reply_t));
2148 	bufptr += sizeof (rdr_change_state_reply_t);
2149 
2150 	if ((params->errstring != NULL) && (*(params->errstring) != NULL)) {
2151 		(void) memcpy(bufptr, *(params->errstring),
2152 		    var_msg_info.errstring_strlen);
2153 		bufptr += var_msg_info.errstring_strlen;
2154 		for (i = 0; i < var_msg_info.errstring_pad_sz; i++) {
2155 			bufptr[i] = 0;
2156 		}
2157 		bufptr += var_msg_info.errstring_pad_sz;
2158 	}
2159 
2160 	return (RDR_OK);
2161 }
2162 
2163 
2164 /*
2165  * unpack_change_state_reply:
2166  *
2167  * Handle unpacking a change state reply message.
2168  */
2169 static int
2170 unpack_change_state_reply(change_state_params_t *params, const char *buf)
2171 {
2172 	char				*bufptr;
2173 	rdr_change_state_reply_t	change_state_data;
2174 
2175 	if ((params == NULL) || (buf == NULL)) {
2176 		return (RDR_ERROR);
2177 	}
2178 
2179 	bufptr = (char *)buf;
2180 	(void) memcpy(&change_state_data, bufptr,
2181 	    sizeof (rdr_change_state_reply_t));
2182 	bufptr += sizeof (rdr_change_state_reply_t);
2183 
2184 	/*
2185 	 * handle getting the errstring
2186 	 */
2187 	params->errstring = (char **)malloc(sizeof (char *));
2188 	if (params->errstring == NULL) {
2189 		return (RDR_MEM_ALLOC);
2190 	}
2191 	if (get_string_from_buf(params->errstring,
2192 	    change_state_data.errstring_size, bufptr)) {
2193 		return (RDR_ERROR);
2194 	}
2195 	bufptr += change_state_data.errstring_size;
2196 
2197 	return (RDR_OK);
2198 }
2199 
2200 
2201 /*
2202  * pack_private_func_request:
2203  *
2204  * Handle packing a private function request message.
2205  */
2206 static int
2207 pack_private_func_request(private_func_params_t *params, char **buf,
2208     int *buf_size)
2209 {
2210 	int				i;
2211 	char				*bufptr;
2212 	rdr_private_func_t		private_func_data;
2213 	rdr_variable_message_info_t	var_msg_info;
2214 
2215 
2216 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
2217 		return (RDR_ERROR);
2218 	}
2219 
2220 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2221 
2222 	/*
2223 	 * Set variable length fields and make a call to partially
2224 	 * pack it.
2225 	 */
2226 	if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) {
2227 		cleanup_variable_ap_id_info(&var_msg_info);
2228 		return (RDR_ERROR);
2229 	}
2230 	if (find_options_sizes(params->options, &var_msg_info)) {
2231 		cleanup_variable_ap_id_info(&var_msg_info);
2232 		return (RDR_ERROR);
2233 	}
2234 	if (find_function_sizes(params->function, &var_msg_info)) {
2235 		cleanup_variable_ap_id_info(&var_msg_info);
2236 		return (RDR_ERROR);
2237 	}
2238 
2239 	/*
2240 	 * Collect size info specific to the private_func request
2241 	 * message and allocate a buffer
2242 	 */
2243 	*buf_size = sizeof (rdr_private_func_t);
2244 	*buf_size += var_msg_info.ap_id_int_size;
2245 	*buf_size += var_msg_info.ap_id_char_size;
2246 	*buf_size += var_msg_info.options_strlen;
2247 	*buf_size += var_msg_info.options_pad_sz;
2248 	*buf_size += var_msg_info.function_strlen;
2249 	*buf_size += var_msg_info.function_pad_sz;
2250 
2251 	*buf = (char *)malloc(*buf_size);
2252 	if (*buf == NULL) {
2253 		cleanup_variable_ap_id_info(&var_msg_info);
2254 		return (RDR_MEM_ALLOC);
2255 	}
2256 
2257 	/*
2258 	 * Set fixed address labels by name
2259 	 */
2260 	private_func_data.num_ap_ids = params->num_ap_ids;
2261 	private_func_data.ap_id_char_size = var_msg_info.ap_id_char_size;
2262 	private_func_data.options_size = var_msg_info.options_strlen +
2263 	    var_msg_info.options_pad_sz;
2264 	private_func_data.function_size = var_msg_info.function_strlen +
2265 	    var_msg_info.function_pad_sz;
2266 
2267 	if (params->confp != NULL) {
2268 		private_func_data.confirm_callback_id =
2269 		    (unsigned long)params->confp->confirm;
2270 		private_func_data.confirm_appdata_ptr =
2271 		    (unsigned long)params->confp->appdata_ptr;
2272 	} else {
2273 		private_func_data.confirm_callback_id = 0;
2274 		private_func_data.confirm_appdata_ptr = 0;
2275 	}
2276 	if (params->msgp != NULL) {
2277 		private_func_data.msg_callback_id =
2278 		    (unsigned long)params->msgp->message_routine;
2279 		private_func_data.msg_appdata_ptr =
2280 		    (unsigned long)params->msgp->appdata_ptr;
2281 	} else {
2282 		private_func_data.msg_callback_id = 0;
2283 		private_func_data.msg_appdata_ptr = 0;
2284 	}
2285 
2286 	private_func_data.flags = params->flags;
2287 
2288 	if (params->errstring != NULL) {
2289 		private_func_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS;
2290 	} else {
2291 		private_func_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS;
2292 	}
2293 
2294 	/*
2295 	 * Set variable information using memcpy
2296 	 */
2297 	bufptr = *buf;
2298 
2299 	(void) memcpy(bufptr, &private_func_data, sizeof (rdr_private_func_t));
2300 	bufptr += sizeof (rdr_private_func_t);
2301 
2302 	if (var_msg_info.ap_id_sizes != NULL) {
2303 		(void) memcpy(bufptr, var_msg_info.ap_id_sizes,
2304 		    var_msg_info.ap_id_int_size);
2305 		bufptr += var_msg_info.ap_id_int_size;
2306 	}
2307 
2308 	if (var_msg_info.ap_id_chars != NULL) {
2309 		(void) memcpy(bufptr, var_msg_info.ap_id_chars,
2310 		    var_msg_info.ap_id_char_size);
2311 		bufptr += var_msg_info.ap_id_char_size;
2312 	}
2313 
2314 	if (params->options != NULL) {
2315 		(void) memcpy(bufptr, params->options,
2316 		    var_msg_info.options_strlen);
2317 		bufptr += var_msg_info.options_strlen;
2318 		for (i = 0; i < var_msg_info.options_pad_sz; i++) {
2319 			bufptr[i] = 0;
2320 		}
2321 		bufptr += var_msg_info.options_pad_sz;
2322 	}
2323 
2324 	if (params->function != NULL) {
2325 		(void) memcpy(bufptr, params->function,
2326 		    var_msg_info.function_strlen);
2327 		bufptr += var_msg_info.function_strlen;
2328 		for (i = 0; i < var_msg_info.function_pad_sz; i++) {
2329 			bufptr[i] = 0;
2330 		}
2331 		bufptr += var_msg_info.function_pad_sz;
2332 	}
2333 
2334 	cleanup_variable_ap_id_info(&var_msg_info);
2335 
2336 	return (RDR_OK);
2337 }
2338 
2339 
2340 /*
2341  * unpack_private_func_request:
2342  *
2343  * Handle unpacking a private function request message.
2344  */
2345 static int
2346 unpack_private_func_request(private_func_params_t *params, const char *buf)
2347 {
2348 	char				*bufptr;
2349 	rdr_variable_message_info_t	var_msg_info;
2350 	rdr_private_func_t		private_func_data;
2351 
2352 
2353 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2354 
2355 	if ((params == NULL) || (buf == NULL)) {
2356 		return (RDR_ERROR);
2357 	}
2358 
2359 	bufptr = (char *)buf;
2360 	(void) memcpy(&private_func_data, bufptr, sizeof (rdr_private_func_t));
2361 	bufptr += sizeof (rdr_private_func_t);
2362 
2363 	/*
2364 	 * handle getting the ap_ids
2365 	 */
2366 	var_msg_info.ap_id_char_size = private_func_data.ap_id_char_size;
2367 	if (get_ap_ids_from_buf((char ***)&(params->ap_ids),
2368 	    private_func_data.num_ap_ids, &var_msg_info, bufptr)) {
2369 		return (RDR_ERROR);
2370 	}
2371 	bufptr += var_msg_info.ap_id_int_size;
2372 	bufptr += var_msg_info.ap_id_char_size;
2373 
2374 	/*
2375 	 * handle getting the options and function
2376 	 */
2377 	if (get_string_from_buf(&(params->options),
2378 	    private_func_data.options_size, bufptr)) {
2379 		return (RDR_ERROR);
2380 	}
2381 	bufptr += private_func_data.options_size;
2382 
2383 	if (get_string_from_buf(&(params->function),
2384 	    private_func_data.function_size, bufptr)) {
2385 		return (RDR_ERROR);
2386 	}
2387 	bufptr += private_func_data.function_size;
2388 
2389 	/*
2390 	 * Set fixed address labels by name
2391 	 */
2392 	params->num_ap_ids = private_func_data.num_ap_ids;
2393 
2394 	params->confp = (struct cfga_confirm *)
2395 	    malloc(sizeof (struct cfga_confirm));
2396 	if (params->confp == NULL) {
2397 		return (RDR_MEM_ALLOC);
2398 	}
2399 
2400 	/* set params->confp->confirm using memcpy */
2401 	(void) memcpy((void*)params->confp,
2402 	    &(private_func_data.confirm_callback_id), sizeof (unsigned long));
2403 	params->confp->appdata_ptr =
2404 	    (void*)private_func_data.confirm_appdata_ptr;
2405 
2406 	params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg));
2407 	if (params->msgp == NULL) {
2408 		return (RDR_MEM_ALLOC);
2409 	}
2410 
2411 	/* set params->msgp->message_routine using memcpy */
2412 	(void) memcpy((void*)params->msgp,
2413 	    &(private_func_data.msg_callback_id), sizeof (unsigned long));
2414 	params->msgp->appdata_ptr =
2415 	    (void*)private_func_data.msg_appdata_ptr;
2416 
2417 	if (private_func_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) {
2418 		params->errstring = (char **)malloc(sizeof (char *));
2419 		if (params->errstring == NULL) {
2420 			return (RDR_MEM_ALLOC);
2421 		}
2422 		*(params->errstring) = NULL;
2423 	} else {	/* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */
2424 		params->errstring = NULL;
2425 	}
2426 	params->flags = private_func_data.flags;
2427 
2428 	return (RDR_OK);
2429 }
2430 
2431 
2432 /*
2433  * pack_private_func_reply:
2434  *
2435  * Handle packing a private function reply message.
2436  */
2437 static int
2438 pack_private_func_reply(private_func_params_t *params, char **buf,
2439     int *buf_size)
2440 {
2441 	int				i;
2442 	char				*bufptr;
2443 	rdr_private_func_reply_t	private_func_data;
2444 	rdr_variable_message_info_t	var_msg_info;
2445 
2446 
2447 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2448 
2449 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
2450 		return (RDR_ERROR);
2451 	}
2452 
2453 	/*
2454 	 * Set variable length fields (size info)
2455 	 */
2456 	if (find_errstring_sizes(params->errstring, &var_msg_info)) {
2457 		return (RDR_ERROR);
2458 	}
2459 
2460 	/*
2461 	 * Collect size info specific to the private_func reply
2462 	 * message and allocate a buffer
2463 	 */
2464 	*buf_size = sizeof (rdr_private_func_reply_t);
2465 	*buf_size += var_msg_info.errstring_strlen;
2466 	*buf_size += var_msg_info.errstring_pad_sz;
2467 
2468 	*buf = (char *)malloc(*buf_size);
2469 	if (*buf == NULL) {
2470 		return (RDR_MEM_ALLOC);
2471 	}
2472 
2473 	/*
2474 	 * Set fixed address labels by name
2475 	 */
2476 	private_func_data.errstring_size = var_msg_info.errstring_strlen +
2477 	    var_msg_info.errstring_pad_sz;
2478 
2479 	/*
2480 	 * Set variable information using memcpy
2481 	 */
2482 	bufptr = *buf;
2483 
2484 	(void) memcpy(bufptr, &private_func_data,
2485 	    sizeof (rdr_private_func_reply_t));
2486 	bufptr += sizeof (rdr_private_func_reply_t);
2487 	if ((params->errstring != NULL) && (*(params->errstring) != NULL)) {
2488 		(void) memcpy(bufptr, *(params->errstring),
2489 		    var_msg_info.errstring_strlen);
2490 		bufptr += var_msg_info.errstring_strlen;
2491 		for (i = 0; i < var_msg_info.errstring_pad_sz; i++) {
2492 			bufptr[i] = 0;
2493 		}
2494 		bufptr += var_msg_info.errstring_pad_sz;
2495 	}
2496 
2497 	return (RDR_OK);
2498 }
2499 
2500 
2501 /*
2502  * unpack_private_func_reply:
2503  *
2504  * Handle unpacking a private function reply message.
2505  */
2506 static int
2507 unpack_private_func_reply(private_func_params_t *params, const char *buf)
2508 {
2509 	char				*bufptr;
2510 	rdr_private_func_reply_t	private_func_data;
2511 
2512 	if ((params == NULL) || (buf == NULL)) {
2513 		return (RDR_ERROR);
2514 	}
2515 
2516 	bufptr = (char *)buf;
2517 	(void) memcpy(&private_func_data, bufptr,
2518 	    sizeof (rdr_private_func_reply_t));
2519 	bufptr += sizeof (rdr_private_func_reply_t);
2520 
2521 	/*
2522 	 * handle getting the errstring
2523 	 */
2524 	params->errstring = (char **)malloc(sizeof (char *));
2525 	if (params->errstring == NULL) {
2526 		return (RDR_MEM_ALLOC);
2527 	}
2528 	if (get_string_from_buf(params->errstring,
2529 	    private_func_data.errstring_size, bufptr)) {
2530 		return (RDR_ERROR);
2531 	}
2532 	bufptr += private_func_data.errstring_size;
2533 
2534 	return (RDR_OK);
2535 }
2536 
2537 
2538 /*
2539  * pack_test_request:
2540  *
2541  * Handle packing a test request message.
2542  */
2543 static int
2544 pack_test_request(test_params_t *params, char **buf, int *buf_size)
2545 {
2546 	int				i;
2547 	char				*bufptr;
2548 	rdr_test_t			test_data;
2549 	rdr_variable_message_info_t	var_msg_info;
2550 
2551 
2552 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
2553 		return (RDR_ERROR);
2554 	}
2555 
2556 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2557 
2558 	/*
2559 	 * Set variable length fields and make a call to partially
2560 	 * pack it.
2561 	 */
2562 	if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) {
2563 		cleanup_variable_ap_id_info(&var_msg_info);
2564 		return (RDR_ERROR);
2565 	}
2566 	if (find_options_sizes(params->options, &var_msg_info)) {
2567 		cleanup_variable_ap_id_info(&var_msg_info);
2568 		return (RDR_ERROR);
2569 	}
2570 
2571 	/*
2572 	 * Collect size info specific to the test request
2573 	 * message and allocate a buffer
2574 	 */
2575 	*buf_size = sizeof (rdr_test_t);
2576 	*buf_size += var_msg_info.ap_id_int_size;
2577 	*buf_size += var_msg_info.ap_id_char_size;
2578 	*buf_size += var_msg_info.options_strlen;
2579 	*buf_size += var_msg_info.options_pad_sz;
2580 
2581 	*buf = (char *)malloc(*buf_size);
2582 	if (*buf == NULL) {
2583 		cleanup_variable_ap_id_info(&var_msg_info);
2584 		return (RDR_MEM_ALLOC);
2585 	}
2586 
2587 	/*
2588 	 * Set fixed address labels by name
2589 	 */
2590 	test_data.num_ap_ids = params->num_ap_ids;
2591 	test_data.ap_id_char_size = var_msg_info.ap_id_char_size;
2592 	test_data.options_size = var_msg_info.options_strlen +
2593 	    var_msg_info.options_pad_sz;
2594 
2595 	if (params->msgp != NULL) {
2596 		test_data.msg_callback_id =
2597 		    (unsigned long)params->msgp->message_routine;
2598 		test_data.msg_appdata_ptr =
2599 		    (unsigned long)params->msgp->appdata_ptr;
2600 	} else {
2601 		test_data.msg_callback_id = 0;
2602 		test_data.msg_appdata_ptr = 0;
2603 	}
2604 
2605 	test_data.flags = params->flags;
2606 
2607 	if (params->errstring != NULL) {
2608 		test_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS;
2609 	} else {
2610 		test_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS;
2611 	}
2612 
2613 	/*
2614 	 * Set variable information using memcpy
2615 	 */
2616 	bufptr = *buf;
2617 
2618 	(void) memcpy(bufptr, &test_data, sizeof (rdr_test_t));
2619 	bufptr += sizeof (rdr_test_t);
2620 
2621 	if (var_msg_info.ap_id_sizes != NULL) {
2622 		(void) memcpy(bufptr, var_msg_info.ap_id_sizes,
2623 		    var_msg_info.ap_id_int_size);
2624 		bufptr += var_msg_info.ap_id_int_size;
2625 	}
2626 
2627 	if (var_msg_info.ap_id_chars != NULL) {
2628 		(void) memcpy(bufptr, var_msg_info.ap_id_chars,
2629 		    var_msg_info.ap_id_char_size);
2630 		bufptr += var_msg_info.ap_id_char_size;
2631 	}
2632 
2633 	if (params->options != NULL) {
2634 		(void) memcpy(bufptr, params->options,
2635 		    var_msg_info.options_strlen);
2636 		bufptr += var_msg_info.options_strlen;
2637 		for (i = 0; i < var_msg_info.options_pad_sz; i++) {
2638 			bufptr[i] = 0;
2639 		}
2640 		bufptr += var_msg_info.options_pad_sz;
2641 	}
2642 
2643 	cleanup_variable_ap_id_info(&var_msg_info);
2644 
2645 	return (RDR_OK);
2646 }
2647 
2648 
2649 /*
2650  * unpack_test_request:
2651  *
2652  * Handle unpacking a test request message.
2653  */
2654 static int
2655 unpack_test_request(test_params_t *params, const char *buf)
2656 {
2657 	char				*bufptr;
2658 	rdr_variable_message_info_t	var_msg_info;
2659 	rdr_test_t			test_data;
2660 
2661 
2662 	if ((params == NULL) || (buf == NULL)) {
2663 		return (RDR_ERROR);
2664 	}
2665 
2666 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2667 
2668 	bufptr = (char *)buf;
2669 	(void) memcpy(&test_data, bufptr, sizeof (rdr_test_t));
2670 	bufptr += sizeof (rdr_test_t);
2671 
2672 	/*
2673 	 * handle getting the ap_ids
2674 	 */
2675 	var_msg_info.ap_id_char_size = test_data.ap_id_char_size;
2676 	if (get_ap_ids_from_buf((char ***)&(params->ap_ids),
2677 	    test_data.num_ap_ids, &var_msg_info, bufptr)) {
2678 		return (RDR_ERROR);
2679 	}
2680 	bufptr += var_msg_info.ap_id_int_size;
2681 	bufptr += var_msg_info.ap_id_char_size;
2682 
2683 	/*
2684 	 * handle getting the options
2685 	 */
2686 	if (get_string_from_buf(&(params->options),
2687 	    test_data.options_size, bufptr)) {
2688 		return (RDR_ERROR);
2689 	}
2690 	bufptr += test_data.options_size;
2691 
2692 	/*
2693 	 * Set fixed address labels by name
2694 	 */
2695 	params->num_ap_ids = test_data.num_ap_ids;
2696 
2697 	params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg));
2698 	if (params->msgp == NULL) {
2699 		return (RDR_MEM_ALLOC);
2700 	}
2701 
2702 	/* set params->msgp->message_routine using memcpy */
2703 	(void) memcpy((void*)params->msgp,
2704 	    &(test_data.msg_callback_id), sizeof (unsigned long));
2705 	params->msgp->appdata_ptr =
2706 	    (void*)test_data.msg_appdata_ptr;
2707 
2708 	if (test_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) {
2709 		params->errstring = (char **)malloc(sizeof (char *));
2710 		if (params->errstring == NULL) {
2711 			return (RDR_MEM_ALLOC);
2712 		}
2713 		*(params->errstring) = NULL;
2714 	} else {	/* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */
2715 		params->errstring = NULL;
2716 	}
2717 	params->flags = test_data.flags;
2718 
2719 	return (RDR_OK);
2720 }
2721 
2722 
2723 /*
2724  * pack_test_reply:
2725  *
2726  * Handle packing a test reply message.
2727  */
2728 static int
2729 pack_test_reply(test_params_t *params, char **buf, int *buf_size)
2730 {
2731 	int				i;
2732 	char				*bufptr;
2733 	rdr_test_reply_t		test_data;
2734 	rdr_variable_message_info_t	var_msg_info;
2735 
2736 
2737 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
2738 		return (RDR_ERROR);
2739 	}
2740 
2741 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2742 
2743 	/*
2744 	 * Set variable length fields (size info)
2745 	 */
2746 	if (find_errstring_sizes(params->errstring, &var_msg_info)) {
2747 		return (RDR_ERROR);
2748 	}
2749 
2750 	/*
2751 	 * Collect size info specific to the test reply
2752 	 * message and allocate a buffer
2753 	 */
2754 	*buf_size = sizeof (rdr_test_reply_t);
2755 	*buf_size += var_msg_info.errstring_strlen;
2756 	*buf_size += var_msg_info.errstring_pad_sz;
2757 
2758 	*buf = (char *)malloc(*buf_size);
2759 	if (*buf == NULL) {
2760 		return (RDR_MEM_ALLOC);
2761 	}
2762 
2763 	/*
2764 	 * Set fixed address labels by name
2765 	 */
2766 	test_data.errstring_size = var_msg_info.errstring_strlen +
2767 	    var_msg_info.errstring_pad_sz;
2768 
2769 	/*
2770 	 * Set variable information using memcpy
2771 	 */
2772 	bufptr = *buf;
2773 
2774 	(void) memcpy(bufptr, &test_data, sizeof (rdr_test_reply_t));
2775 	bufptr += sizeof (rdr_test_reply_t);
2776 	if ((params->errstring != NULL) && (*(params->errstring) != NULL)) {
2777 		(void) memcpy(bufptr, *(params->errstring),
2778 		    var_msg_info.errstring_strlen);
2779 		bufptr += var_msg_info.errstring_strlen;
2780 		for (i = 0; i < var_msg_info.errstring_pad_sz; i++) {
2781 			bufptr[i] = 0;
2782 		}
2783 		bufptr += var_msg_info.errstring_pad_sz;
2784 	}
2785 
2786 	return (RDR_OK);
2787 }
2788 
2789 
2790 /*
2791  * unpack_test_reply:
2792  *
2793  * Handle unpacking a test reply message.
2794  */
2795 static int
2796 unpack_test_reply(test_params_t *params, const char *buf)
2797 {
2798 	char			*bufptr;
2799 	rdr_test_reply_t	test_data;
2800 
2801 
2802 	if ((params == NULL) || (buf == NULL)) {
2803 		return (RDR_ERROR);
2804 	}
2805 
2806 	bufptr = (char *)buf;
2807 	(void) memcpy(&test_data, bufptr, sizeof (rdr_test_reply_t));
2808 	bufptr += sizeof (rdr_test_reply_t);
2809 
2810 	/*
2811 	 * handle getting the errstring
2812 	 */
2813 	params->errstring = (char **)malloc(sizeof (char *));
2814 	if (params->errstring == NULL) {
2815 		return (RDR_MEM_ALLOC);
2816 	}
2817 	if (get_string_from_buf(params->errstring,
2818 	    test_data.errstring_size, bufptr)) {
2819 		return (RDR_ERROR);
2820 	}
2821 	bufptr += test_data.errstring_size;
2822 
2823 	return (RDR_OK);
2824 }
2825 
2826 
2827 /*
2828  * pack_list_ext_request:
2829  *
2830  * Handle packing a list request message.
2831  */
2832 static int
2833 pack_list_ext_request(list_ext_params_t *params, char **buf, int *buf_size)
2834 {
2835 	int				i;
2836 	char				*bufptr;
2837 	rdr_list_ext_t			list_ext_data;
2838 	rdr_variable_message_info_t	var_msg_info;
2839 
2840 
2841 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
2842 		return (RDR_ERROR);
2843 	}
2844 
2845 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2846 
2847 	/*
2848 	 * Set variable length fields and make a call to partially
2849 	 * pack it.
2850 	 */
2851 	if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) {
2852 		cleanup_variable_ap_id_info(&var_msg_info);
2853 		return (RDR_ERROR);
2854 	}
2855 	if (find_options_sizes(params->options, &var_msg_info)) {
2856 		cleanup_variable_ap_id_info(&var_msg_info);
2857 		return (RDR_ERROR);
2858 	}
2859 	if (find_listopts_sizes(params->listopts, &var_msg_info)) {
2860 		cleanup_variable_ap_id_info(&var_msg_info);
2861 		return (RDR_ERROR);
2862 	}
2863 
2864 
2865 	/*
2866 	 * Collect size info specific to the list_ext request
2867 	 * message and allocate a buffer
2868 	 */
2869 	*buf_size = sizeof (rdr_list_ext_t);
2870 	*buf_size += var_msg_info.ap_id_int_size;
2871 	*buf_size += var_msg_info.ap_id_char_size;
2872 	*buf_size += var_msg_info.options_strlen;
2873 	*buf_size += var_msg_info.options_pad_sz;
2874 	*buf_size += var_msg_info.listopts_strlen;
2875 	*buf_size += var_msg_info.listopts_pad_sz;
2876 
2877 	*buf = (char *)malloc(*buf_size);
2878 	if (*buf == NULL) {
2879 		cleanup_variable_ap_id_info(&var_msg_info);
2880 		return (RDR_MEM_ALLOC);
2881 	}
2882 
2883 	/*
2884 	 * Set fixed address labels by name
2885 	 */
2886 	list_ext_data.num_ap_ids = params->num_ap_ids;
2887 	list_ext_data.ap_id_char_size = var_msg_info.ap_id_char_size;
2888 	list_ext_data.options_size = var_msg_info.options_strlen +
2889 	    var_msg_info.options_pad_sz;
2890 	list_ext_data.listopts_size = var_msg_info.listopts_strlen +
2891 	    var_msg_info.listopts_pad_sz;
2892 	if (params->errstring != NULL) {
2893 		list_ext_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS;
2894 	} else {
2895 		list_ext_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS;
2896 	}
2897 	if ((params->num_ap_ids != 0) || (params->ap_ids != NULL)) {
2898 		list_ext_data.list_msg_ctl = RDR_LIST_ONLY_PARAM_APS;
2899 	} else {
2900 		list_ext_data.list_msg_ctl = RDR_LIST_ALL_APS;
2901 	}
2902 	list_ext_data.flags = params->flags;
2903 	list_ext_data.permissions = params->permissions;
2904 
2905 	/*
2906 	 * Set variable information using memcpy
2907 	 */
2908 	bufptr = *buf;
2909 
2910 	(void) memcpy(bufptr, &list_ext_data, sizeof (rdr_list_ext_t));
2911 	bufptr += sizeof (rdr_list_ext_t);
2912 
2913 	if (var_msg_info.ap_id_sizes != NULL) {
2914 		(void) memcpy(bufptr, var_msg_info.ap_id_sizes,
2915 		    var_msg_info.ap_id_int_size);
2916 		bufptr += var_msg_info.ap_id_int_size;
2917 	}
2918 
2919 	if (var_msg_info.ap_id_chars != NULL) {
2920 		(void) memcpy(bufptr, var_msg_info.ap_id_chars,
2921 		    var_msg_info.ap_id_char_size);
2922 		bufptr += var_msg_info.ap_id_char_size;
2923 	}
2924 
2925 	if (params->options != NULL) {
2926 		(void) memcpy(bufptr, params->options,
2927 		    var_msg_info.options_strlen);
2928 		bufptr += var_msg_info.options_strlen;
2929 		for (i = 0; i < var_msg_info.options_pad_sz; i++) {
2930 			bufptr[i] = 0;
2931 		}
2932 		bufptr += var_msg_info.options_pad_sz;
2933 	}
2934 
2935 	if (params->listopts != NULL) {
2936 		(void) memcpy(bufptr, params->listopts,
2937 		    var_msg_info.listopts_strlen);
2938 		bufptr += var_msg_info.listopts_strlen;
2939 		for (i = 0; i < var_msg_info.listopts_pad_sz; i++) {
2940 			bufptr[i] = 0;
2941 		}
2942 		bufptr += var_msg_info.listopts_pad_sz;
2943 	}
2944 
2945 	cleanup_variable_ap_id_info(&var_msg_info);
2946 
2947 	return (RDR_OK);
2948 }
2949 
2950 
2951 /*
2952  * unpack_list_ext_request:
2953  *
2954  * Handle unpacking a list request message.
2955  */
2956 static int
2957 unpack_list_ext_request(list_ext_params_t *params, const char *buf)
2958 {
2959 	char				*bufptr;
2960 	rdr_variable_message_info_t	var_msg_info;
2961 	rdr_list_ext_t			list_ext_data;
2962 
2963 
2964 	if ((params == NULL) || (buf == NULL)) {
2965 		return (RDR_ERROR);
2966 	}
2967 
2968 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
2969 
2970 	bufptr = (char *)buf;
2971 	(void) memcpy(&list_ext_data, bufptr, sizeof (rdr_list_ext_t));
2972 	bufptr += sizeof (rdr_list_ext_t);
2973 
2974 	/*
2975 	 * handle getting the ap_ids
2976 	 */
2977 	var_msg_info.ap_id_char_size = list_ext_data.ap_id_char_size;
2978 	if (get_ap_ids_from_buf(&(params->ap_ids), list_ext_data.num_ap_ids,
2979 	    &var_msg_info, bufptr)) {
2980 		return (RDR_ERROR);
2981 	}
2982 	bufptr += var_msg_info.ap_id_int_size;
2983 	bufptr += var_msg_info.ap_id_char_size;
2984 
2985 	/*
2986 	 * handle getting the options
2987 	 */
2988 	if (get_string_from_buf(&(params->options),
2989 	    list_ext_data.options_size, bufptr)) {
2990 		return (RDR_ERROR);
2991 	}
2992 	bufptr += list_ext_data.options_size;
2993 
2994 	/*
2995 	 * handle getting the listopts
2996 	 */
2997 	if (get_string_from_buf(&(params->listopts),
2998 	    list_ext_data.listopts_size, bufptr)) {
2999 		return (RDR_ERROR);
3000 	}
3001 	bufptr += list_ext_data.listopts_size;
3002 
3003 	/*
3004 	 * Set fixed address labels by name
3005 	 */
3006 	params->num_ap_ids = list_ext_data.num_ap_ids;
3007 
3008 	params->ap_id_list = (rdr_list_t **)malloc(sizeof (rdr_list_t *));
3009 	if (params->ap_id_list == NULL) {
3010 		return (RDR_MEM_ALLOC);
3011 	}
3012 	*(params->ap_id_list) = NULL;
3013 
3014 	params->nlist = (int *)malloc(sizeof (int));
3015 	if (params->nlist == NULL) {
3016 		return (RDR_MEM_ALLOC);
3017 	}
3018 	if (list_ext_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) {
3019 		params->errstring = (char **)malloc(sizeof (char *));
3020 		if (params->errstring == NULL) {
3021 			return (RDR_MEM_ALLOC);
3022 		}
3023 		*(params->errstring) = NULL;
3024 	} else {	/* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */
3025 		params->errstring = NULL;
3026 	}
3027 	params->flags = list_ext_data.flags;
3028 	params->permissions = list_ext_data.permissions;
3029 
3030 	return (RDR_OK);
3031 }
3032 
3033 
3034 /*
3035  * pack_list_ext_reply:
3036  *
3037  * Handle packing a list reply message.
3038  */
3039 static int
3040 pack_list_ext_reply(list_ext_params_t *params, char **buf, int *buf_size)
3041 {
3042 	int				i;
3043 	char				*bufptr;
3044 	rdr_list_ext_reply_t		list_ext_data;
3045 	rdr_variable_message_info_t	var_msg_info;
3046 	int				list_data_size;
3047 
3048 
3049 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
3050 
3051 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3052 		return (RDR_ERROR);
3053 	}
3054 
3055 	/*
3056 	 * Set variable length fields (size info)
3057 	 */
3058 	if (find_errstring_sizes(params->errstring, &var_msg_info)) {
3059 		return (RDR_ERROR);
3060 	}
3061 
3062 	if (params->nlist == NULL) {
3063 		list_data_size = 0;
3064 	} else {
3065 		list_data_size = *(params->nlist) * sizeof (rdr_list_t);
3066 	}
3067 
3068 	/*
3069 	 * Collect size info specific to the list_ext reply
3070 	 * message and allocate a buffer
3071 	 */
3072 	*buf_size = sizeof (rdr_list_ext_reply_t);
3073 	*buf_size += list_data_size;
3074 	*buf_size += var_msg_info.errstring_strlen;
3075 	*buf_size += var_msg_info.errstring_pad_sz;
3076 
3077 	*buf = (char *)malloc(*buf_size);
3078 	if (*buf == NULL) {
3079 		return (RDR_MEM_ALLOC);
3080 	}
3081 
3082 	/*
3083 	 * Set fixed address labels by name
3084 	 */
3085 	list_ext_data.num_ap_ids = (params->nlist) ? *(params->nlist) : 0;
3086 	list_ext_data.errstring_size = var_msg_info.errstring_strlen +
3087 	    var_msg_info.errstring_pad_sz;
3088 
3089 	/*
3090 	 * Set variable information using memcpy
3091 	 */
3092 	bufptr = *buf;
3093 
3094 	(void) memcpy(bufptr, &list_ext_data, sizeof (rdr_list_ext_reply_t));
3095 	bufptr += sizeof (rdr_list_ext_reply_t);
3096 
3097 	if ((params->ap_id_list != NULL) && (*(params->ap_id_list) != NULL)) {
3098 		(void) memcpy(bufptr, *(params->ap_id_list), list_data_size);
3099 		bufptr += list_data_size;
3100 	} else if (list_data_size) {
3101 		/*
3102 		 * Something is out of sync. We were expecting
3103 		 * some data to copy, but instead we found a
3104 		 * NULL pointer.
3105 		 */
3106 		(void) free((void *)*buf);
3107 		*buf = NULL;
3108 		return (RDR_ERROR);
3109 	}
3110 
3111 	if ((params->errstring != NULL) && (*(params->errstring) != NULL)) {
3112 		(void) memcpy(bufptr, *(params->errstring),
3113 		    var_msg_info.errstring_strlen);
3114 		bufptr += var_msg_info.errstring_strlen;
3115 		for (i = 0; i < var_msg_info.errstring_pad_sz; i++) {
3116 			bufptr[i] = 0;
3117 		}
3118 		bufptr += var_msg_info.errstring_pad_sz;
3119 	}
3120 
3121 	return (RDR_OK);
3122 }
3123 
3124 
3125 /*
3126  * unpack_list_ext_reply:
3127  *
3128  * Handle unpacking a list reply message.
3129  */
3130 static int
3131 unpack_list_ext_reply(list_ext_params_t *params, const char *buf)
3132 {
3133 	int			list_data_size;
3134 	char			*bufptr;
3135 	rdr_list_ext_reply_t	list_ext_data;
3136 
3137 
3138 	if ((params == NULL) || (buf == NULL)) {
3139 		return (RDR_ERROR);
3140 	}
3141 
3142 	bufptr = (char *)buf;
3143 	(void) memcpy(&list_ext_data, bufptr, sizeof (rdr_list_ext_reply_t));
3144 	bufptr += sizeof (rdr_list_ext_reply_t);
3145 
3146 	/*
3147 	 * handle getting the ap_id rcfga_list_data_t's.
3148 	 */
3149 	if (list_ext_data.num_ap_ids > 0) {
3150 		params->nlist = (int *)malloc(sizeof (int));
3151 		if (params->nlist == NULL) {
3152 			return (RDR_MEM_ALLOC);
3153 		}
3154 		*(params->nlist) = list_ext_data.num_ap_ids;
3155 		params->ap_id_list = (rdr_list_t **)
3156 		    malloc(sizeof (rdr_list_t *));
3157 		if (params->ap_id_list == NULL) {
3158 			return (RDR_MEM_ALLOC);
3159 		}
3160 		*(params->ap_id_list) = (rdr_list_t *)
3161 		    malloc(sizeof (rdr_list_t) * list_ext_data.num_ap_ids);
3162 		if (*(params->ap_id_list) == NULL) {
3163 			return (RDR_MEM_ALLOC);
3164 		}
3165 		list_data_size = list_ext_data.num_ap_ids * sizeof (rdr_list_t);
3166 		(void) memcpy(*(params->ap_id_list), bufptr, list_data_size);
3167 		bufptr += list_data_size;
3168 	}
3169 
3170 	/*
3171 	 * handle getting the errstring
3172 	 */
3173 	params->errstring = (char **)malloc(sizeof (char *));
3174 	if (params->errstring == NULL) {
3175 		return (RDR_MEM_ALLOC);
3176 	}
3177 	if (get_string_from_buf(params->errstring,
3178 	    list_ext_data.errstring_size, bufptr)) {
3179 		return (RDR_ERROR);
3180 	}
3181 	bufptr += list_ext_data.errstring_size;
3182 
3183 	return (RDR_OK);
3184 }
3185 
3186 
3187 /*
3188  * pack_help_request:
3189  *
3190  * Handle packing a help request message.
3191  */
3192 static int
3193 pack_help_request(help_params_t *params, char **buf, int *buf_size)
3194 {
3195 	int				i;
3196 	char				*bufptr;
3197 	rdr_help_t			help_data;
3198 	rdr_variable_message_info_t	var_msg_info;
3199 
3200 
3201 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
3202 
3203 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3204 		return (RDR_ERROR);
3205 	}
3206 
3207 	/*
3208 	 * Set variable length fields and make a call to partially
3209 	 * pack it.
3210 	 */
3211 	if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) {
3212 		cleanup_variable_ap_id_info(&var_msg_info);
3213 		return (RDR_ERROR);
3214 	}
3215 	if (find_options_sizes(params->options, &var_msg_info)) {
3216 		cleanup_variable_ap_id_info(&var_msg_info);
3217 		return (RDR_ERROR);
3218 	}
3219 
3220 	/*
3221 	 * Collect size info specific to the help request message and
3222 	 * and allocate a buffer
3223 	 */
3224 	*buf_size = sizeof (rdr_help_t);
3225 	*buf_size += var_msg_info.ap_id_int_size;
3226 	*buf_size += var_msg_info.ap_id_char_size;
3227 	*buf_size += var_msg_info.options_strlen;
3228 	*buf_size += var_msg_info.options_pad_sz;
3229 
3230 	*buf = (char *)malloc(*buf_size);
3231 	if (*buf == NULL) {
3232 		cleanup_variable_ap_id_info(&var_msg_info);
3233 		return (RDR_MEM_ALLOC);
3234 	}
3235 
3236 	/*
3237 	 * Set fixed address labels by name
3238 	 */
3239 	help_data.num_ap_ids = params->num_ap_ids;
3240 	help_data.ap_id_char_size = var_msg_info.ap_id_char_size;
3241 	help_data.options_size = var_msg_info.options_strlen +
3242 	    var_msg_info.options_pad_sz;
3243 
3244 	if (params->msgp != NULL) {
3245 		help_data.msg_callback_id =
3246 		    (unsigned long)params->msgp->message_routine;
3247 		help_data.msg_appdata_ptr =
3248 		    (unsigned long)params->msgp->appdata_ptr;
3249 	} else {
3250 		help_data.msg_callback_id = 0;
3251 		help_data.msg_appdata_ptr = 0;
3252 	}
3253 
3254 	help_data.flags = params->flags;
3255 
3256 	/*
3257 	 * Set variable information using memcpy
3258 	 */
3259 	bufptr = *buf;
3260 
3261 	(void) memcpy(bufptr, &help_data, sizeof (rdr_help_t));
3262 	bufptr += sizeof (rdr_help_t);
3263 
3264 	if (var_msg_info.ap_id_sizes != NULL) {
3265 		(void) memcpy(bufptr, var_msg_info.ap_id_sizes,
3266 		    var_msg_info.ap_id_int_size);
3267 		bufptr += var_msg_info.ap_id_int_size;
3268 	}
3269 
3270 	if (var_msg_info.ap_id_chars != NULL) {
3271 		(void) memcpy(bufptr, var_msg_info.ap_id_chars,
3272 		    var_msg_info.ap_id_char_size);
3273 		bufptr += var_msg_info.ap_id_char_size;
3274 	}
3275 
3276 	if (params->options != NULL) {
3277 		(void) memcpy(bufptr, params->options,
3278 		    var_msg_info.options_strlen);
3279 		bufptr += var_msg_info.options_strlen;
3280 		for (i = 0; i < var_msg_info.options_pad_sz; i++) {
3281 			bufptr[i] = 0;
3282 		}
3283 		bufptr += var_msg_info.options_pad_sz;
3284 	}
3285 
3286 	cleanup_variable_ap_id_info(&var_msg_info);
3287 
3288 	return (RDR_OK);
3289 }
3290 
3291 
3292 /*
3293  * unpack_help_request:
3294  *
3295  * Handle unpacking a help request message.
3296  */
3297 static int
3298 unpack_help_request(help_params_t *params, const char *buf)
3299 {
3300 	char				*bufptr;
3301 	rdr_variable_message_info_t	var_msg_info;
3302 	rdr_help_t			help_data;
3303 
3304 
3305 	if ((params == NULL) || (buf == NULL)) {
3306 		return (RDR_ERROR);
3307 	}
3308 
3309 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
3310 
3311 	bufptr = (char *)buf;
3312 	(void) memcpy(&help_data, bufptr, sizeof (rdr_help_t));
3313 	bufptr += sizeof (rdr_help_t);
3314 
3315 	/*
3316 	 * handle getting the ap_ids
3317 	 */
3318 	var_msg_info.ap_id_char_size = help_data.ap_id_char_size;
3319 	if (get_ap_ids_from_buf((char ***)&(params->ap_ids),
3320 	    help_data.num_ap_ids, &var_msg_info, bufptr)) {
3321 		return (RDR_ERROR);
3322 	}
3323 	bufptr += var_msg_info.ap_id_int_size;
3324 	bufptr += var_msg_info.ap_id_char_size;
3325 
3326 	/*
3327 	 * handle getting the options
3328 	 */
3329 	if (get_string_from_buf(&(params->options),
3330 	    help_data.options_size, bufptr)) {
3331 		return (RDR_ERROR);
3332 	}
3333 	bufptr += help_data.options_size;
3334 
3335 	/*
3336 	 * Set fixed address labels by name
3337 	 */
3338 	params->num_ap_ids = help_data.num_ap_ids;
3339 
3340 	params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg));
3341 	if (params->msgp == NULL) {
3342 		return (RDR_MEM_ALLOC);
3343 	}
3344 
3345 	/* set params->msgp->message_routine using memcpy */
3346 	(void) memcpy((void*)params->msgp, &(help_data.msg_callback_id),
3347 	    sizeof (unsigned long));
3348 
3349 	params->msgp->appdata_ptr = (void*)help_data.msg_appdata_ptr;
3350 	params->flags = help_data.flags;
3351 
3352 	return (RDR_OK);
3353 }
3354 
3355 
3356 /*
3357  * pack_ap_id_cmp_request:
3358  *
3359  * Handle packing an attachment point comparison request message.
3360  */
3361 static int
3362 pack_ap_id_cmp_request(ap_id_cmp_params_t *params, char **buf, int *buf_size)
3363 {
3364 	int			i;
3365 	char			*bufptr;
3366 	rdr_ap_id_cmp_t		ap_id_cmp_data;
3367 	int			ap_id1_strlen;
3368 	int			ap_id1_pad_sz;
3369 	int			ap_id2_strlen;
3370 	int			ap_id2_pad_sz;
3371 
3372 
3373 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3374 		return (RDR_ERROR);
3375 	}
3376 
3377 	/*
3378 	 * Set variable length fields and make a call to partially
3379 	 * pack it.
3380 	 */
3381 	if (params->ap_log_id1 != NULL) {
3382 		ap_id1_strlen = strlen(params->ap_log_id1) + 1;
3383 		ap_id1_pad_sz = RDR_ALIGN_64_BIT -
3384 		    (ap_id1_strlen % RDR_ALIGN_64_BIT);
3385 	} else {
3386 		ap_id1_strlen = 0;
3387 		ap_id1_pad_sz = 0;
3388 	}
3389 
3390 	if (params->ap_log_id2 != NULL) {
3391 		ap_id2_strlen = strlen(params->ap_log_id2) + 1;
3392 		ap_id2_pad_sz = RDR_ALIGN_64_BIT -
3393 		    (ap_id2_strlen % RDR_ALIGN_64_BIT);
3394 	} else {
3395 		ap_id2_strlen = 0;
3396 		ap_id2_pad_sz = 0;
3397 	}
3398 
3399 	/*
3400 	 * Collect size info specific to the ap id compare request
3401 	 * message and allocate a buffer
3402 	 */
3403 	*buf_size = sizeof (rdr_ap_id_cmp_t);
3404 	*buf_size += ap_id1_strlen;
3405 	*buf_size += ap_id1_pad_sz;
3406 	*buf_size += ap_id2_strlen;
3407 	*buf_size += ap_id2_pad_sz;
3408 
3409 	*buf = (char *)malloc(*buf_size);
3410 	if (*buf == NULL) {
3411 		return (RDR_MEM_ALLOC);
3412 	}
3413 
3414 	/*
3415 	 * Set fixed address labels by name
3416 	 */
3417 	ap_id_cmp_data.ap_id1_size = ap_id1_strlen + ap_id1_pad_sz;
3418 	ap_id_cmp_data.ap_id2_size = ap_id2_strlen + ap_id2_pad_sz;
3419 
3420 
3421 	/*
3422 	 * Set variable information using memcpy
3423 	 */
3424 	bufptr = *buf;
3425 
3426 	(void) memcpy(bufptr, &ap_id_cmp_data, sizeof (rdr_ap_id_cmp_t));
3427 	bufptr += sizeof (rdr_ap_id_cmp_t);
3428 
3429 	if (params->ap_log_id1 != NULL) {
3430 		(void) memcpy(bufptr, params->ap_log_id1, ap_id1_strlen);
3431 		bufptr += ap_id1_strlen;
3432 		for (i = 0; i < ap_id1_pad_sz; i++) {
3433 			bufptr[i] = 0;
3434 		}
3435 		bufptr += ap_id1_pad_sz;
3436 	}
3437 
3438 	if (params->ap_log_id2 != NULL) {
3439 		(void) memcpy(bufptr, params->ap_log_id2, ap_id2_strlen);
3440 		bufptr += ap_id2_strlen;
3441 		for (i = 0; i < ap_id2_pad_sz; i++) {
3442 			bufptr[i] = 0;
3443 		}
3444 		bufptr += ap_id2_pad_sz;
3445 	}
3446 
3447 	return (RDR_OK);
3448 }
3449 
3450 
3451 /*
3452  * unpack_ap_id_cmp_request:
3453  *
3454  * Handle unpacking an attachment point comparison request message.
3455  */
3456 static int
3457 unpack_ap_id_cmp_request(ap_id_cmp_params_t *params, const char *buf)
3458 {
3459 	char			*bufptr;
3460 	rdr_ap_id_cmp_t		ap_id_cmp_data;
3461 
3462 
3463 	if ((params == NULL) || (buf == NULL)) {
3464 		return (RDR_ERROR);
3465 	}
3466 
3467 	bufptr = (char *)buf;
3468 	(void) memcpy(&ap_id_cmp_data, bufptr, sizeof (rdr_ap_id_cmp_t));
3469 	bufptr += sizeof (rdr_ap_id_cmp_t);
3470 
3471 	/*
3472 	 * handle getting the cmp ap ids
3473 	 */
3474 	if (get_string_from_buf(&(params->ap_log_id1),
3475 	    ap_id_cmp_data.ap_id1_size, bufptr)) {
3476 		return (RDR_ERROR);
3477 	}
3478 	bufptr += ap_id_cmp_data.ap_id1_size;
3479 
3480 	if (get_string_from_buf(&(params->ap_log_id2),
3481 	    ap_id_cmp_data.ap_id2_size, bufptr)) {
3482 		return (RDR_ERROR);
3483 	}
3484 	bufptr += ap_id_cmp_data.ap_id2_size;
3485 
3486 	return (RDR_OK);
3487 }
3488 
3489 
3490 /*
3491  * pack_abort_cmd_request:
3492  *
3493  * Handle packing an abort request message.
3494  */
3495 static int
3496 pack_abort_cmd_request(abort_cmd_params_t *params, char **buf, int *buf_size)
3497 {
3498 	rdr_abort_cmd_t		abort_cmd_data;
3499 
3500 
3501 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3502 		return (RDR_ERROR);
3503 	}
3504 
3505 	/*
3506 	 * Collect size info specific to the abort cmd request
3507 	 * message and allocate a buffer
3508 	 */
3509 	*buf_size = sizeof (rdr_abort_cmd_t);
3510 
3511 	*buf = (char *)malloc(*buf_size);
3512 	if (*buf == NULL) {
3513 		return (RDR_MEM_ALLOC);
3514 	}
3515 
3516 	/*
3517 	 * Set fixed session identifier
3518 	 */
3519 	abort_cmd_data.session_id = params->session_id;
3520 
3521 	/*
3522 	 * Copy information using memcpy
3523 	 */
3524 	(void) memcpy(*buf, &abort_cmd_data, sizeof (rdr_abort_cmd_t));
3525 
3526 	return (RDR_OK);
3527 }
3528 
3529 
3530 /*
3531  * unpack_abort_cmd_request:
3532  *
3533  * Handle unpacking an abort request message.
3534  */
3535 static int
3536 unpack_abort_cmd_request(abort_cmd_params_t *params, const char *buf)
3537 {
3538 	rdr_abort_cmd_t		*abort_cmd_datap;
3539 
3540 
3541 	if ((params == NULL) || (buf == NULL)) {
3542 		return (RDR_ERROR);
3543 	}
3544 
3545 	/* LINTED Pointer Cast Alignment Warning */
3546 	abort_cmd_datap = (rdr_abort_cmd_t *)buf;
3547 
3548 	/*
3549 	 * copy out the session information
3550 	 */
3551 
3552 	params->session_id = abort_cmd_datap->session_id;
3553 
3554 	return (RDR_OK);
3555 }
3556 
3557 
3558 /*
3559  * pack_confirm_request:
3560  *
3561  * Handle packing a confirm callback request.
3562  */
3563 static int
3564 pack_confirm_request(confirm_callback_params_t *params, char **buf,
3565     int *buf_size)
3566 {
3567 	int				i;
3568 	char				*bufptr;
3569 	rdr_confirm_callback_t		confirm_callback_data;
3570 	int				message_strlen;
3571 	int				message_pad_sz;
3572 
3573 
3574 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3575 		return (RDR_ERROR);
3576 	}
3577 
3578 	/*
3579 	 * Set variable length fields and make a call to partially
3580 	 * pack it.
3581 	 */
3582 	if (params->message != NULL) {
3583 		message_strlen = strlen(params->message) + 1;
3584 		message_pad_sz = RDR_ALIGN_64_BIT -
3585 		    (message_strlen % RDR_ALIGN_64_BIT);
3586 	} else {
3587 		message_strlen = 0;
3588 		message_pad_sz = 0;
3589 	}
3590 
3591 
3592 	/*
3593 	 * Collect size info specific to the confirm callback request
3594 	 * message and allocate a buffer
3595 	 */
3596 	*buf_size = sizeof (rdr_confirm_callback_t);
3597 	*buf_size += message_strlen;
3598 	*buf_size += message_pad_sz;
3599 
3600 	*buf = (char *)malloc(*buf_size);
3601 	if (*buf == NULL) {
3602 		return (RDR_MEM_ALLOC);
3603 	}
3604 
3605 	/*
3606 	 * Set fixed address labels by name
3607 	 */
3608 	if (params->confp != NULL) {
3609 		confirm_callback_data.confirm_callback_id =
3610 		    (unsigned long)params->confp->confirm;
3611 		confirm_callback_data.appdata_ptr =
3612 		    (unsigned long)params->confp->appdata_ptr;
3613 	} else {
3614 		confirm_callback_data.confirm_callback_id = 0;
3615 		confirm_callback_data.appdata_ptr = 0;
3616 	}
3617 	confirm_callback_data.message_size = message_strlen + message_pad_sz;
3618 
3619 	/*
3620 	 * Set variable information using memcpy
3621 	 */
3622 	bufptr = *buf;
3623 	(void) memcpy(bufptr, &confirm_callback_data,
3624 	    sizeof (rdr_confirm_callback_t));
3625 	bufptr += sizeof (rdr_confirm_callback_t);
3626 
3627 	if (params->message != NULL) {
3628 		(void) memcpy(bufptr, params->message, message_strlen);
3629 		bufptr += message_strlen;
3630 		for (i = 0; i < message_pad_sz; i++) {
3631 			bufptr[i] = 0;
3632 		}
3633 		bufptr += message_pad_sz;
3634 	}
3635 
3636 	return (RDR_OK);
3637 }
3638 
3639 
3640 /*
3641  * unpack_confirm_request:
3642  *
3643  * Handle unpacking a confirm callback request.
3644  */
3645 static int
3646 unpack_confirm_request(confirm_callback_params_t *params, const char *buf)
3647 {
3648 	char				*bufptr;
3649 	rdr_confirm_callback_t		confirm_callback_data;
3650 
3651 
3652 	if ((params == NULL) || (buf == NULL)) {
3653 		return (RDR_ERROR);
3654 	}
3655 
3656 	bufptr = (char *)buf;
3657 	(void) memcpy(&confirm_callback_data, bufptr,
3658 	    sizeof (rdr_confirm_callback_t));
3659 	bufptr += sizeof (rdr_confirm_callback_t);
3660 
3661 	/*
3662 	 * handle getting the message text
3663 	 */
3664 	if (get_string_from_buf(&(params->message),
3665 	    confirm_callback_data.message_size, bufptr)) {
3666 		return (RDR_ERROR);
3667 	}
3668 	bufptr += confirm_callback_data.message_size;
3669 
3670 	/*
3671 	 * Set fixed address labels by name
3672 	 */
3673 	params->confp = (struct cfga_confirm *)
3674 	    malloc(sizeof (struct cfga_confirm));
3675 	if (params->confp == NULL) {
3676 		return (RDR_MEM_ALLOC);
3677 	}
3678 
3679 	/* set params->confp->confirm using memcpy */
3680 	(void) memcpy((void*)params->confp,
3681 	    &(confirm_callback_data.confirm_callback_id),
3682 	    sizeof (unsigned long));
3683 
3684 	params->confp->appdata_ptr =
3685 	    (void*)confirm_callback_data.appdata_ptr;
3686 
3687 	return (RDR_OK);
3688 }
3689 
3690 
3691 /*
3692  * pack_confirm_reply:
3693  *
3694  * Handle packing a confirm callback reply.
3695  */
3696 static int
3697 pack_confirm_reply(confirm_callback_params_t *params, char **buf, int *buf_size)
3698 {
3699 	char				*bufptr;
3700 	rdr_confirm_callback_reply_t	confirm_callback_data;
3701 
3702 
3703 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3704 		return (RDR_ERROR);
3705 	}
3706 
3707 	/*
3708 	 * Collect size info specific to the confirm callback reply
3709 	 * message and allocate a buffer
3710 	 */
3711 	*buf_size = sizeof (confirm_callback_params_t);
3712 	*buf = (char *)malloc(*buf_size);
3713 	if (*buf == NULL) {
3714 		return (RDR_MEM_ALLOC);
3715 	}
3716 
3717 	/*
3718 	 * Set fixed address labels by name
3719 	 */
3720 	if (params->confp != NULL) {
3721 		confirm_callback_data.confirm_callback_id =
3722 		    (unsigned long)params->confp->confirm;
3723 		confirm_callback_data.appdata_ptr =
3724 		    (unsigned long)params->confp->appdata_ptr;
3725 	} else {
3726 		confirm_callback_data.confirm_callback_id = 0;
3727 		confirm_callback_data.appdata_ptr = 0;
3728 	}
3729 	confirm_callback_data.response = params->response;
3730 
3731 	/*
3732 	 * Set variable information using memcpy
3733 	 */
3734 	bufptr = *buf;
3735 
3736 	(void) memcpy(bufptr, &confirm_callback_data,
3737 	    sizeof (rdr_confirm_callback_reply_t));
3738 
3739 	return (RDR_OK);
3740 }
3741 
3742 
3743 /*
3744  * unpack_confirm_reply:
3745  *
3746  * Handle unpacking a confirm callback reply.
3747  */
3748 static int
3749 unpack_confirm_reply(confirm_callback_params_t *params, const char *buf)
3750 {
3751 	char				*bufptr;
3752 	rdr_confirm_callback_reply_t	confirm_callback_data;
3753 
3754 	if ((params == NULL) || (buf == NULL)) {
3755 		return (RDR_ERROR);
3756 	}
3757 
3758 	bufptr = (char *)buf;
3759 	(void) memcpy(&confirm_callback_data, bufptr,
3760 	    sizeof (rdr_confirm_callback_reply_t));
3761 	bufptr += sizeof (confirm_callback_params_t);
3762 
3763 	/*
3764 	 * Set fixed address labels by name
3765 	 */
3766 	params->confp = (struct cfga_confirm *)
3767 	    malloc(sizeof (struct cfga_confirm));
3768 	if (params->confp == NULL) {
3769 		return (RDR_MEM_ALLOC);
3770 	}
3771 
3772 	/* set params->confp->confirm using memcpy */
3773 	(void) memcpy((void*)params->confp,
3774 	    &(confirm_callback_data.confirm_callback_id),
3775 	    sizeof (unsigned long));
3776 
3777 	params->confp->appdata_ptr =
3778 	    (void*)confirm_callback_data.appdata_ptr;
3779 	params->response = confirm_callback_data.response;
3780 
3781 	return (RDR_OK);
3782 }
3783 
3784 
3785 /*
3786  * pack_message_request:
3787  *
3788  * Handle packing a message callback request.
3789  */
3790 static int
3791 pack_message_request(msg_callback_params_t *params, char **buf, int *buf_size)
3792 {
3793 	int			i;
3794 	char			*bufptr;
3795 	rdr_msg_callback_t	msg_callback_data;
3796 	int			message_strlen;
3797 	int			message_pad_sz;
3798 
3799 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3800 		return (RDR_ERROR);
3801 	}
3802 
3803 	/*
3804 	 * Set variable length fields and make a call to partially
3805 	 * pack it.
3806 	 */
3807 	if (params->message != NULL) {
3808 		message_strlen = strlen(params->message) + 1;
3809 		message_pad_sz = RDR_ALIGN_64_BIT -
3810 		    (message_strlen % RDR_ALIGN_64_BIT);
3811 	} else {
3812 		message_strlen = 0;
3813 		message_pad_sz = 0;
3814 	}
3815 
3816 
3817 	/*
3818 	 * Collect size info specific to the message callback request
3819 	 * message and allocate a buffer
3820 	 */
3821 	*buf_size = sizeof (rdr_msg_callback_t);
3822 	*buf_size += message_strlen;
3823 	*buf_size += message_pad_sz;
3824 
3825 	*buf = (char *)malloc(*buf_size);
3826 	if (*buf == NULL) {
3827 		return (RDR_MEM_ALLOC);
3828 	}
3829 
3830 	/*
3831 	 * Set fixed address labels by name
3832 	 */
3833 	if (params->msgp != NULL) {
3834 		msg_callback_data.msg_callback_id =
3835 		    (unsigned long)params->msgp->message_routine;
3836 		msg_callback_data.appdata_ptr =
3837 		    (unsigned long)params->msgp->appdata_ptr;
3838 	} else {
3839 		msg_callback_data.msg_callback_id = 0;
3840 		msg_callback_data.appdata_ptr = 0;
3841 	}
3842 	msg_callback_data.message_size = message_strlen + message_pad_sz;
3843 
3844 	/*
3845 	 * Set variable information using memcpy
3846 	 */
3847 	bufptr = *buf;
3848 
3849 	(void) memcpy(bufptr, &msg_callback_data, sizeof (rdr_msg_callback_t));
3850 	bufptr += sizeof (rdr_msg_callback_t);
3851 
3852 	if (params->message != NULL) {
3853 		(void) memcpy(bufptr, params->message, message_strlen);
3854 		bufptr += message_strlen;
3855 		for (i = 0; i < message_pad_sz; i++) {
3856 			bufptr[i] = 0;
3857 		}
3858 		bufptr += message_pad_sz;
3859 	}
3860 
3861 	return (RDR_OK);
3862 }
3863 
3864 
3865 /*
3866  * unpack_message_request:
3867  *
3868  * Handle unpacking a message callback request.
3869  */
3870 static int
3871 unpack_message_request(msg_callback_params_t *params, const char *buf)
3872 {
3873 	char			*bufptr;
3874 	rdr_msg_callback_t	msg_callback_data;
3875 
3876 	if ((params == NULL) || (buf == NULL)) {
3877 		return (RDR_ERROR);
3878 	}
3879 
3880 	bufptr = (char *)buf;
3881 	(void) memcpy(&msg_callback_data, bufptr, sizeof (rdr_msg_callback_t));
3882 	bufptr += sizeof (rdr_msg_callback_t);
3883 
3884 	/*
3885 	 * handle getting the message text
3886 	 */
3887 	if (get_string_from_buf(&(params->message),
3888 	    msg_callback_data.message_size, bufptr)) {
3889 		return (RDR_ERROR);
3890 	}
3891 	bufptr += msg_callback_data.message_size;
3892 
3893 	/*
3894 	 * Set fixed address labels by name
3895 	 */
3896 	params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg));
3897 	if (params->msgp == NULL) {
3898 		return (RDR_MEM_ALLOC);
3899 	}
3900 
3901 	/* set params->msgp->message_routine using memcpy */
3902 	(void) memcpy((void*)params->msgp, &(msg_callback_data.msg_callback_id),
3903 	    sizeof (unsigned long));
3904 
3905 	params->msgp->appdata_ptr = (void*)msg_callback_data.appdata_ptr;
3906 
3907 	return (RDR_OK);
3908 }
3909 
3910 /*
3911  * pack_rsrc_info_request:
3912  *
3913  * Handle packing a resource info request.
3914  */
3915 static int
3916 pack_rsrc_info_request(rsrc_info_params_t *params, char **buf, int *buf_size)
3917 {
3918 	char				*bufptr;
3919 	rdr_rsrc_info_t			rsrc_info_data;
3920 	rdr_variable_message_info_t	var_msg_info;
3921 
3922 
3923 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
3924 		return (RDR_ERROR);
3925 	}
3926 
3927 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
3928 
3929 	/*
3930 	 * Set variable length fields and make a call to partially
3931 	 * pack it.
3932 	 */
3933 	if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) {
3934 		cleanup_variable_ap_id_info(&var_msg_info);
3935 		return (RDR_ERROR);
3936 	}
3937 
3938 	/*
3939 	 * Collect size info specific to the resource info request
3940 	 * message and allocate a buffer.
3941 	 */
3942 	*buf_size = sizeof (rdr_rsrc_info_t);
3943 	*buf_size += var_msg_info.ap_id_int_size;
3944 	*buf_size += var_msg_info.ap_id_char_size;
3945 
3946 	*buf = (char *)malloc(*buf_size);
3947 	if (*buf == NULL) {
3948 		return (RDR_MEM_ALLOC);
3949 	}
3950 
3951 	/*
3952 	 * Set fixed address labels by name.
3953 	 */
3954 	rsrc_info_data.num_ap_ids = params->num_ap_ids;
3955 	rsrc_info_data.ap_id_char_size = var_msg_info.ap_id_char_size;
3956 	rsrc_info_data.flags = params->flags;
3957 
3958 	/*
3959 	 * Set variable information using memcpy.
3960 	 */
3961 	bufptr = *buf;
3962 
3963 	(void) memcpy(bufptr, &rsrc_info_data, sizeof (rdr_rsrc_info_t));
3964 	bufptr += sizeof (rdr_rsrc_info_t);
3965 
3966 	if (var_msg_info.ap_id_sizes != NULL) {
3967 		(void) memcpy(bufptr, var_msg_info.ap_id_sizes,
3968 		    var_msg_info.ap_id_int_size);
3969 		bufptr += var_msg_info.ap_id_int_size;
3970 	}
3971 
3972 	if (var_msg_info.ap_id_chars != NULL) {
3973 		(void) memcpy(bufptr, var_msg_info.ap_id_chars,
3974 		    var_msg_info.ap_id_char_size);
3975 		bufptr += var_msg_info.ap_id_char_size;
3976 	}
3977 
3978 	cleanup_variable_ap_id_info(&var_msg_info);
3979 
3980 	return (RDR_OK);
3981 }
3982 
3983 
3984 /*
3985  * unpack_rsrc_info_request:
3986  *
3987  * Handle unpacking a resource info request message.
3988  */
3989 static int
3990 unpack_rsrc_info_request(rsrc_info_params_t *params, const char *buf)
3991 {
3992 	char				*bufptr;
3993 	rdr_variable_message_info_t	var_msg_info;
3994 	rdr_rsrc_info_t			rsrc_info_data;
3995 
3996 
3997 	if ((params == NULL) || (buf == NULL)) {
3998 		return (RDR_ERROR);
3999 	}
4000 
4001 	(void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t));
4002 
4003 	bufptr = (char *)buf;
4004 	(void) memcpy(&rsrc_info_data, bufptr, sizeof (rdr_rsrc_info_t));
4005 	bufptr += sizeof (rdr_rsrc_info_t);
4006 
4007 	/*
4008 	 * Handle getting the ap_ids.
4009 	 */
4010 	var_msg_info.ap_id_char_size = rsrc_info_data.ap_id_char_size;
4011 	if (get_ap_ids_from_buf(&(params->ap_ids), rsrc_info_data.num_ap_ids,
4012 	    &var_msg_info, bufptr)) {
4013 		return (RDR_ERROR);
4014 	}
4015 	bufptr += var_msg_info.ap_id_int_size;
4016 	bufptr += var_msg_info.ap_id_char_size;
4017 
4018 	/*
4019 	 * Set fixed address labels by name.
4020 	 */
4021 	params->num_ap_ids = rsrc_info_data.num_ap_ids;
4022 	params->flags = rsrc_info_data.flags;
4023 
4024 	return (RDR_OK);
4025 }
4026 
4027 
4028 /*
4029  * pack_rsrc_info_reply:
4030  *
4031  * Handle packing a resource info reply message.
4032  */
4033 static int
4034 pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf, int *buf_size,
4035     int encoding)
4036 {
4037 	char				*bufptr;
4038 	rdr_rsrc_info_reply_t		rsrc_info_data;
4039 	int				pack_status;
4040 	caddr_t				rsrc_info_bufp = NULL;
4041 	size_t				rsrc_info_size;
4042 
4043 
4044 	if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) {
4045 		return (RDR_ERROR);
4046 	}
4047 
4048 	/*
4049 	 * Pack snapshot handle data.
4050 	 */
4051 	pack_status = ri_pack(params->hdl, &rsrc_info_bufp, &rsrc_info_size,
4052 	    encoding);
4053 	if (pack_status != 0) {
4054 		return (RDR_ERROR);
4055 	}
4056 
4057 	/*
4058 	 * Collect size info specific to the rsrc_info reply message
4059 	 * and allocate a buffer.
4060 	 */
4061 	*buf_size = sizeof (rdr_rsrc_info_reply_t);
4062 	*buf_size += rsrc_info_size;
4063 
4064 	*buf = (char *)malloc(*buf_size);
4065 	if (*buf == NULL) {
4066 		free(rsrc_info_bufp);
4067 		return (RDR_MEM_ALLOC);
4068 	}
4069 
4070 	/*
4071 	 * Set fixed address labels by name.
4072 	 */
4073 	rsrc_info_data.packed_hdl_size = rsrc_info_size;
4074 
4075 	/*
4076 	 * Set variable information using memcpy.
4077 	 */
4078 	bufptr = *buf;
4079 
4080 	(void) memcpy(bufptr, &rsrc_info_data, sizeof (rdr_rsrc_info_reply_t));
4081 	bufptr += sizeof (rdr_rsrc_info_reply_t);
4082 
4083 	if (rsrc_info_bufp) {
4084 		(void) memcpy(bufptr, rsrc_info_bufp, rsrc_info_size);
4085 		free(rsrc_info_bufp);
4086 	}
4087 
4088 	return (RDR_OK);
4089 }
4090 
4091 
4092 /*
4093  * unpack_rsrc_info_reply:
4094  *
4095  * Handle unpacking a resource info reply message.
4096  */
4097 static int
4098 unpack_rsrc_info_reply(rsrc_info_params_t *params, const char *buf)
4099 {
4100 	int			unpack_status;
4101 	char			*bufptr;
4102 	rdr_rsrc_info_reply_t	rsrc_info_data;
4103 
4104 
4105 	if ((params == NULL) || (buf == NULL)) {
4106 		return (RDR_ERROR);
4107 	}
4108 
4109 	bufptr = (char *)buf;
4110 	(void) memcpy(&rsrc_info_data, bufptr, sizeof (rdr_rsrc_info_reply_t));
4111 	bufptr += sizeof (rdr_rsrc_info_reply_t);
4112 
4113 	/*
4114 	 * Unpack buf into resource info handle.
4115 	 */
4116 	unpack_status = ri_unpack(bufptr, rsrc_info_data.packed_hdl_size,
4117 	    &params->hdl);
4118 
4119 	return ((unpack_status == 0) ? RDR_OK : RDR_ERROR);
4120 }
4121 
4122 
4123 /*
4124  * pack_ap_ids:
4125  *
4126  * Pack a list of attachment point identifiers into a single buffer.
4127  * This buffer is stored in the specified rdr_variable_message_info_t
4128  * and is padded to be 64-bit aligned.
4129  */
4130 static int
4131 pack_ap_ids(int num_ap_ids, char *const *ap_ids,
4132     rdr_variable_message_info_t *var_msg_info)
4133 {
4134 	int	i;
4135 	int	ap_id_pad_sz;
4136 	char	*bufptr;
4137 
4138 
4139 	if (var_msg_info == NULL) {
4140 		return (RDR_ERROR);
4141 	}
4142 
4143 	/*
4144 	 * NULL is a valid value for ap_ids in the list_ext
4145 	 * case. For list_ext, no specified attachment points
4146 	 * indicates that _all_ attachment points should be
4147 	 * displayed. However, if ap_ids is NULL, num_ap_ids
4148 	 * should be 0.
4149 	 */
4150 	if ((ap_ids == NULL) && (num_ap_ids != 0)) {
4151 		num_ap_ids = 0;
4152 	}
4153 
4154 	var_msg_info->ap_id_int_size = sizeof (int) * num_ap_ids;
4155 	if (num_ap_ids > 0) {
4156 		var_msg_info->ap_id_sizes = (int *)malloc(sizeof (int) *
4157 		    var_msg_info->ap_id_int_size);
4158 		if (var_msg_info->ap_id_sizes == NULL) {
4159 			return (RDR_MEM_ALLOC);
4160 		}
4161 	}
4162 	for (i = 0; i < num_ap_ids; i++) {
4163 		if (ap_ids[i] != NULL) {
4164 			var_msg_info->ap_id_sizes[i] = strlen(ap_ids[i]) + 1;
4165 			var_msg_info->ap_id_char_size +=
4166 			    var_msg_info->ap_id_sizes[i];
4167 		}
4168 	}
4169 	if (var_msg_info->ap_id_char_size > 0) {
4170 		ap_id_pad_sz = RDR_ALIGN_64_BIT -
4171 		    (var_msg_info->ap_id_char_size % RDR_ALIGN_64_BIT);
4172 		var_msg_info->ap_id_char_size += ap_id_pad_sz;
4173 		var_msg_info->ap_id_chars = (char *)
4174 		    malloc(var_msg_info->ap_id_char_size);
4175 		if (var_msg_info->ap_id_chars == NULL) {
4176 			return (RDR_MEM_ALLOC);
4177 		}
4178 
4179 		bufptr = var_msg_info->ap_id_chars;
4180 		for (i = 0; i < num_ap_ids; i++) {
4181 			(void) memcpy(bufptr, ap_ids[i],
4182 			    var_msg_info->ap_id_sizes[i]);
4183 			bufptr += var_msg_info->ap_id_sizes[i];
4184 		}
4185 		for (i = 0; i < ap_id_pad_sz; i++) {
4186 			bufptr[i] = 0;
4187 		}
4188 	} else {
4189 		ap_id_pad_sz = 0;
4190 	}
4191 
4192 	return (RDR_OK);
4193 }
4194 
4195 
4196 /*
4197  * unpack_ap_ids:
4198  *
4199  * Unpack a buffer containing a concatenation of a list of
4200  * attachment point identifiers. The resulting list of strings
4201  * are stored in an array in the specified rdr_variable_message_info_t.
4202  */
4203 static int
4204 unpack_ap_ids(int num_ap_ids, char **ap_ids, const char *buf,
4205     rdr_variable_message_info_t *var_msg_info)
4206 {
4207 	int	i;
4208 	int	ap_id_size;
4209 	int	chars_copied;
4210 	char	*bufptr;
4211 
4212 
4213 	if ((ap_ids == NULL) || (buf == NULL) || (var_msg_info == NULL)) {
4214 		return (RDR_ERROR);
4215 	}
4216 	bufptr = (char *)buf;
4217 
4218 	var_msg_info->ap_id_int_size = sizeof (int) * num_ap_ids;
4219 	if (num_ap_ids > 0) {
4220 		var_msg_info->ap_id_sizes = (int *)
4221 		    malloc(sizeof (int) * var_msg_info->ap_id_int_size);
4222 		if (var_msg_info->ap_id_sizes == NULL) {
4223 			return (RDR_MEM_ALLOC);
4224 		}
4225 		(void) memcpy(var_msg_info->ap_id_sizes, bufptr,
4226 		    var_msg_info->ap_id_int_size);
4227 	}
4228 	bufptr += var_msg_info->ap_id_int_size;
4229 
4230 	chars_copied = 0;
4231 	for (i = 0; i < num_ap_ids; i++) {
4232 		ap_id_size = var_msg_info->ap_id_sizes[i];
4233 		if (ap_id_size <= 0) {
4234 			continue;
4235 		}
4236 		if ((chars_copied + ap_id_size) >
4237 		    var_msg_info->ap_id_char_size) {
4238 			return (RDR_ERROR);
4239 		}
4240 		ap_ids[i] = (char *)malloc(ap_id_size);
4241 		if (ap_ids[i] == NULL) {
4242 			return (RDR_MEM_ALLOC);
4243 		}
4244 		(void) memcpy(ap_ids[i], bufptr, ap_id_size);
4245 		bufptr += ap_id_size;
4246 		chars_copied += ap_id_size;
4247 	}
4248 	return (RDR_OK);
4249 }
4250 
4251 
4252 /*
4253  * find_options_sizes:
4254  *
4255  * Determine the size of a specified option string. The information
4256  * is stored in the specified rdr_variable_message_info_t.
4257  */
4258 static int
4259 find_options_sizes(char *options, rdr_variable_message_info_t *var_msg_info)
4260 {
4261 	if (var_msg_info == NULL) {
4262 		return (RDR_ERROR);
4263 	}
4264 	if (options != NULL) {
4265 		var_msg_info->options_strlen = strlen(options) + 1;
4266 		var_msg_info->options_pad_sz = RDR_ALIGN_64_BIT -
4267 		    (var_msg_info->options_strlen % RDR_ALIGN_64_BIT);
4268 	} else {
4269 		var_msg_info->options_strlen = 0;
4270 		var_msg_info->options_pad_sz = 0;
4271 	}
4272 	return (RDR_OK);
4273 }
4274 
4275 
4276 /*
4277  * find_listopts_sizes:
4278  *
4279  * Determine the size of a specified list option string. The information
4280  * is stored in the specified rdr_variable_message_info_t.
4281  */
4282 static int
4283 find_listopts_sizes(char *listopts, rdr_variable_message_info_t *var_msg_info)
4284 {
4285 	if (var_msg_info == NULL) {
4286 		return (RDR_ERROR);
4287 	}
4288 	if (listopts != NULL) {
4289 		var_msg_info->listopts_strlen = strlen(listopts) + 1;
4290 		var_msg_info->listopts_pad_sz = RDR_ALIGN_64_BIT -
4291 		    (var_msg_info->listopts_strlen % RDR_ALIGN_64_BIT);
4292 	} else {
4293 		var_msg_info->listopts_strlen = 0;
4294 		var_msg_info->listopts_pad_sz = 0;
4295 	}
4296 	return (RDR_OK);
4297 }
4298 
4299 
4300 /*
4301  * find_function_size:
4302  *
4303  * Determine the size of a specified private function string. The
4304  * information is stored in the specified rdr_variable_message_info_t.
4305  */
4306 static int
4307 find_function_sizes(char *function, rdr_variable_message_info_t *var_msg_info)
4308 {
4309 	if (var_msg_info == NULL) {
4310 		return (RDR_ERROR);
4311 	}
4312 	if (function != NULL) {
4313 		var_msg_info->function_strlen = strlen(function) + 1;
4314 		var_msg_info->function_pad_sz = RDR_ALIGN_64_BIT -
4315 		    (var_msg_info->function_strlen % RDR_ALIGN_64_BIT);
4316 	} else {
4317 		var_msg_info->function_strlen = 0;
4318 		var_msg_info->function_pad_sz = 0;
4319 	}
4320 	return (RDR_OK);
4321 }
4322 
4323 
4324 /*
4325  * find_errstring_sizes:
4326  *
4327  * Determine the size of a specified error string. The information
4328  * is stored in the specified rdr_variable_message_info_t.
4329  */
4330 static int
4331 find_errstring_sizes(char **errstring,
4332     rdr_variable_message_info_t *var_msg_info)
4333 {
4334 	if ((errstring != NULL) && (*errstring != NULL)) {
4335 		var_msg_info->errstring_strlen = strlen(*errstring) + 1;
4336 		var_msg_info->errstring_pad_sz = RDR_ALIGN_64_BIT -
4337 		    (var_msg_info->errstring_strlen % RDR_ALIGN_64_BIT);
4338 	} else {
4339 		var_msg_info->errstring_strlen = 0;
4340 		var_msg_info->errstring_pad_sz = 0;
4341 	}
4342 	return (RDR_OK);
4343 }
4344 
4345 
4346 /*
4347  * get_ap_ids_from_buf:
4348  *
4349  * Unpack a buffer containing a concatenation of a list of attachment
4350  * point identifiers. An appropriately sized buffer is allocated and
4351  * the resulting list of strings are stored in an array in the specified
4352  * rdr_variable_message_info_t.
4353  */
4354 static int
4355 get_ap_ids_from_buf(char ***ap_id_ptr, int num_ap_ids,
4356     rdr_variable_message_info_t *var_msg_info, const char *buf)
4357 {
4358 	if ((ap_id_ptr == NULL) || (buf == NULL) || (var_msg_info == NULL)) {
4359 		return (RDR_ERROR);
4360 	}
4361 	if (num_ap_ids > 0) {
4362 		*ap_id_ptr = (char **)malloc(sizeof (char *) * num_ap_ids);
4363 		if (*ap_id_ptr == NULL) {
4364 			return (RDR_MEM_ALLOC);
4365 		}
4366 		if (unpack_ap_ids(num_ap_ids, *ap_id_ptr, buf, var_msg_info)) {
4367 			cleanup_variable_ap_id_info(var_msg_info);
4368 			return (RDR_ERROR);
4369 		}
4370 
4371 	} else if (num_ap_ids < 0) {
4372 		return (RDR_ERROR);
4373 	}
4374 
4375 	cleanup_variable_ap_id_info(var_msg_info);
4376 
4377 	return (RDR_OK);
4378 }
4379 
4380 
4381 /*
4382  * get_string_from_buf:
4383  *
4384  * Copy a string to a new buffer. Memory is allocated for the
4385  * new buffer and the original string is copied to the new buffer.
4386  * This is primarily used when a string is located in a packed
4387  * buffer that will eventually get deallocated.
4388  */
4389 static int
4390 get_string_from_buf(char **stringptr, int strsize, const char *buf)
4391 {
4392 	if (buf == NULL) {
4393 		return (RDR_ERROR);
4394 	}
4395 
4396 	/*
4397 	 * A stringptr of NULL is a valid value. The errstring param
4398 	 * in an rconfig_xxx call is valid and is passed to this
4399 	 * function. For example, see errstring in the call to this
4400 	 * function in unpack_change_state_reply.
4401 	 */
4402 	if (stringptr != NULL) {
4403 		if (strsize > 0) {
4404 			*stringptr = (char *)malloc(strsize);
4405 			if (*stringptr == NULL) {
4406 				return (RDR_MEM_ALLOC);
4407 			}
4408 			(void) memcpy(*stringptr, buf, strsize);
4409 		} else if (strsize == 0) {
4410 			*stringptr = NULL;
4411 		} else if (strsize < 0) {
4412 			*stringptr = NULL;
4413 			return (RDR_ERROR);
4414 		}
4415 	}
4416 	return (RDR_OK);
4417 }
4418 
4419 
4420 /*
4421  * cleanup_ap_ids:
4422  *
4423  * Deallocate the specified array of attachment point identifiers.
4424  */
4425 static int
4426 cleanup_ap_ids(int num_ap_ids, char ** ap_ids)
4427 {
4428 	int	i;
4429 
4430 	if (ap_ids == NULL) {
4431 		return (RDR_ERROR);
4432 	}
4433 	for (i = 0; i < num_ap_ids; i++) {
4434 		if (ap_ids[i] != NULL) {
4435 			free((void *)ap_ids[i]);
4436 			ap_ids[i] = NULL;
4437 		}
4438 	}
4439 	return (RDR_OK);
4440 }
4441 
4442 
4443 /*
4444  * cleanup_errstring:
4445  *
4446  * Deallocate the specified error string.
4447  */
4448 static int
4449 cleanup_errstring(char **errstring)
4450 {
4451 	if (errstring) {
4452 		if (*errstring) {
4453 			free((void *)*errstring);
4454 		}
4455 		free((void *)errstring);
4456 		errstring = NULL;
4457 	}
4458 
4459 	return (RDR_OK);
4460 }
4461 
4462 
4463 /*
4464  * cleanup_variable_ap_id_info:
4465  *
4466  * Deallocate the ap_id information from the specified
4467  * rdr_variable_message_info_t.
4468  */
4469 static void
4470 cleanup_variable_ap_id_info(rdr_variable_message_info_t *var_msg_info)
4471 {
4472 	if (var_msg_info != NULL) {
4473 		if (var_msg_info->ap_id_sizes != NULL) {
4474 			free((void *)var_msg_info->ap_id_sizes);
4475 			var_msg_info->ap_id_sizes = NULL;
4476 		}
4477 		if (var_msg_info->ap_id_chars != NULL) {
4478 			free((void *)var_msg_info->ap_id_chars);
4479 			var_msg_info->ap_id_chars = NULL;
4480 		}
4481 	}
4482 }
4483 
4484 /*
4485  * load_libdscp:
4486  *
4487  * Try to dynamically link with libdscp.
4488  *
4489  * Returns:	0 if libdscp not available,
4490  *		1 if libdscp is available.
4491  */
4492 static int
4493 load_libdscp(libdscp_t *libdscp)
4494 {
4495 	int		len;
4496 	void		*lib;
4497 	static char	platform[100];
4498 	static char	pathname[MAXPATHLEN];
4499 
4500 	/*
4501 	 * Only try to load libdscp once.  Use the saved
4502 	 * status in the libdscp interface to know the
4503 	 * results of previous attempts.
4504 	 */
4505 	if (libdscp->status == LIBDSCP_AVAILABLE) {
4506 		return (1);
4507 	}
4508 	if (libdscp->status == LIBDSCP_UNAVAILABLE) {
4509 		return (0);
4510 	}
4511 
4512 	/*
4513 	 * Construct a platform specific pathname for libdscp.
4514 	 */
4515 	len = sysinfo(SI_PLATFORM, platform, sizeof (platform));
4516 	if ((len < 0) || (len > sizeof (platform))) {
4517 		return (0);
4518 	}
4519 	len = snprintf(pathname, MAXPATHLEN, LIBDSCP_PATH, platform);
4520 	if (len >= MAXPATHLEN) {
4521 		libdscp->status = LIBDSCP_UNAVAILABLE;
4522 		return (0);
4523 	}
4524 
4525 	/*
4526 	 * Try dynamically loading libdscp.
4527 	 */
4528 	if ((lib = dlopen(pathname, RTLD_LAZY)) == NULL) {
4529 		libdscp->status = LIBDSCP_UNAVAILABLE;
4530 		return (0);
4531 	}
4532 
4533 	/*
4534 	 * Try to resolve all the symbols.
4535 	 */
4536 	libdscp->bind = (int (*)(int, int, int))dlsym(lib, LIBDSCP_BIND);
4537 	libdscp->secure = (int (*)(int, int))dlsym(lib, LIBDSCP_SECURE);
4538 	libdscp->auth = (int (*)(int, struct sockaddr *, int))dlsym(lib,
4539 	    LIBDSCP_AUTH);
4540 
4541 	if ((libdscp->bind == NULL) ||
4542 	    (libdscp->secure == NULL) ||
4543 	    (libdscp->auth == NULL)) {
4544 		(void) dlclose(lib);
4545 		libdscp->status = LIBDSCP_UNAVAILABLE;
4546 		return (0);
4547 	}
4548 
4549 	/*
4550 	 * Success.
4551 	 * Update the status to indicate libdscp is available.
4552 	 */
4553 	libdscp->status = LIBDSCP_AVAILABLE;
4554 	return (1);
4555 }
4556