/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * WARNING: The contents of this file are shared by all projects * that wish to perform remote Dynamic Reconfiguration (DR) * operations. Copies of this file can be found in the following * locations: * * Project Location * ------- -------- * Solaris usr/src/cmd/dcs/sparc/sun4u/rdr_messages.c * SMS src/sms/lib/librdr/rdr_messages.c * * In order for proper communication to occur, the files in the * above locations must match exactly. Any changes that are made * to this file should be made to all of the files in the list. */ /* * This file is a module that contains an interface for performing * remote Dynamic Reconfiguration (DR) operations. It hides all * network operations such as establishing a connection, sending * and receiving messages, and closing a connection. It also handles * the packing and unpacking of messages for network transport. */ #include #include #include #include #include #include #include #include #include #include #include #include #include "dcs.h" #include "remote_cfg.h" #include "rdr_param_types.h" #include "rdr_messages.h" /* * Structure holding information about * all possible variable length fields * that can be present in an RDR message. */ typedef struct { int ap_id_int_size; int ap_id_char_size; int *ap_id_sizes; char *ap_id_chars; int errstring_strlen; int errstring_pad_sz; int options_strlen; int options_pad_sz; int listopts_strlen; int listopts_pad_sz; int function_strlen; int function_pad_sz; } rdr_variable_message_info_t; /* * A table of maximum sizes for each message type. Message size is * validated when the message header is first received. This prevents * a situation where a corrupted or bad header can cause too much * memory to be allocated. * * The message size limits were chosen to be a very generous upper bound * on the amount of data each message can send. They are not intended to * be a precise measurement of the data size. */ #define NOMSG 0 #define SHORTMSG (150 * 1024) /* 150 KB */ #define LONGMSG (3 * 1024 * 1024) /* 3 MB */ struct { ulong_t req_max; ulong_t reply_max; } msg_sizes[] = { /* * request reply * ------- ----- */ { NOMSG, NOMSG }, /* Invalid Opcode */ { SHORTMSG, SHORTMSG }, /* RDR_SES_REQ */ { NOMSG, NOMSG }, /* RDR_SES_ESTBL */ { NOMSG, NOMSG }, /* RDR_SES_END */ { SHORTMSG, SHORTMSG }, /* RDR_CONF_CHANGE_STATE */ { SHORTMSG, SHORTMSG }, /* RDR_CONF_PRIVATE_FUNC */ { SHORTMSG, SHORTMSG }, /* RDR_CONF_TEST */ { SHORTMSG, LONGMSG }, /* RDR_CONF_LIST_EXT */ { SHORTMSG, NOMSG }, /* RDR_CONF_HELP */ { SHORTMSG, NOMSG }, /* RDR_CONF_AP_ID_CMP */ { SHORTMSG, NOMSG }, /* RDR_CONF_ABORT_CMD */ { SHORTMSG, SHORTMSG }, /* RDR_CONF_CONFIRM_CALLBACK */ { SHORTMSG, NOMSG }, /* RDR_CONF_MSG_CALLBACK */ { SHORTMSG, LONGMSG } /* RDR_RSRC_INFO */ }; #define RDR_BAD_FD (-1) #define RDR_MSG_HDR_SIZE sizeof (rdr_msg_hdr_t) static const int RDR_ALIGN_64_BIT = 8; /* 8 bytes */ /* * Interfaces for dynamic use of libdscp. */ #define LIBDSCP_PATH "/usr/platform/%s/lib/libdscp.so.1" #define LIBDSCP_BIND "dscpBind" #define LIBDSCP_SECURE "dscpSecure" #define LIBDSCP_AUTH "dscpAuth" typedef enum { LIBDSCP_UNKNOWN = 0, LIBDSCP_AVAILABLE, LIBDSCP_UNAVAILABLE } dscp_status_t; typedef struct { dscp_status_t status; int (*bind)(int, int, int); int (*secure)(int, int); int (*auth)(int, struct sockaddr *, int); } libdscp_t; static libdscp_t libdscp; /* * Static Function Declarations */ /* * Socket Related Routines */ static int rdr_setopt(int fd, int name, int level); static int rdr_bind(int fd, struct sockaddr *addr); static int rdr_secure(int fd, struct sockaddr *addr); static int rdr_auth(struct sockaddr *addr, int len); static int rdr_snd(int fd, rdr_msg_hdr_t *hdr, char *data, int data_sz, int timeout); static int rdr_snd_raw(int fd, char *msg, int data_sz, int timeout); static int rdr_rcv(int fd, rdr_msg_hdr_t *hdr, char **data, int timeout); static int rdr_rcv_raw(int fd, char *msg, int data_size, int timeout); /* * Data Validation Routines */ static int validate_header(rdr_msg_hdr_t *hdr); /* * Session Request Routines */ static int pack_ses_req_request(ses_req_params_t *params, char **buf, int *buf_size); static int unpack_ses_req_request(ses_req_params_t *params, const char *buf); static int pack_ses_req_reply(ses_req_params_t *params, char **buf, int *buf_size); static int unpack_ses_req_reply(ses_req_params_t *params, const char *buf); /* * Change State Routines */ static int pack_change_state_request(change_state_params_t *params, char **buf, int *buf_size); static int unpack_change_state_request(change_state_params_t *params, const char *buf); static int pack_change_state_reply(change_state_params_t *params, char **buf, int *buf_size); static int unpack_change_state_reply(change_state_params_t *params, const char *buf); /* * Private Func Routines */ static int pack_private_func_request(private_func_params_t *params, char **buf, int *buf_size); static int unpack_private_func_request(private_func_params_t *params, const char *buf); static int pack_private_func_reply(private_func_params_t *params, char **buf, int *buf_size); static int unpack_private_func_reply(private_func_params_t *params, const char *buf); /* * Test Routines */ static int pack_test_request(test_params_t *params, char **buf, int *buf_size); static int unpack_test_request(test_params_t *params, const char *buf); static int pack_test_reply(test_params_t *params, char **buf, int *buf_size); static int unpack_test_reply(test_params_t *params, const char *buf); /* * List Ext Routines */ static int pack_list_ext_request(list_ext_params_t *params, char **buf, int *buf_size); static int unpack_list_ext_request(list_ext_params_t *params, const char *buf); static int pack_list_ext_reply(list_ext_params_t *params, char **buf, int *buf_size); static int unpack_list_ext_reply(list_ext_params_t *params, const char *buf); /* * Help Routines */ static int pack_help_request(help_params_t *params, char **buf, int *buf_size); static int unpack_help_request(help_params_t *params, const char *buf); /* * Ap Id Cmp Routines */ static int pack_ap_id_cmp_request(ap_id_cmp_params_t *params, char **buf, int *buf_size); static int unpack_ap_id_cmp_request(ap_id_cmp_params_t *params, const char *buf); /* * Abort Routines */ static int pack_abort_cmd_request(abort_cmd_params_t *params, char **buf, int *buf_size); static int unpack_abort_cmd_request(abort_cmd_params_t *params, const char *buf); /* * Confirm Callback Routines */ static int pack_confirm_request(confirm_callback_params_t *params, char **buf, int *buf_size); static int unpack_confirm_request(confirm_callback_params_t *params, const char *buf); static int pack_confirm_reply(confirm_callback_params_t *params, char **buf, int *buf_size); static int unpack_confirm_reply(confirm_callback_params_t *params, const char *buf); /* * Message Callback Routines */ static int pack_message_request(msg_callback_params_t *params, char **buf, int *buf_size); static int unpack_message_request(msg_callback_params_t *params, const char *buf); /* * Resource Info Routines */ static int pack_rsrc_info_request(rsrc_info_params_t *params, char **buf, int *buf_size); static int unpack_rsrc_info_request(rsrc_info_params_t *params, const char *buf); static int pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf, int *buf_size, int encoding); static int unpack_rsrc_info_reply(rsrc_info_params_t *params, const char *buf); /* * General Pack/Unpack Routines */ static int pack_ap_ids(int num_ap_ids, char *const *ap_ids, rdr_variable_message_info_t *var_msg_info); static int unpack_ap_ids(int num_ap_ids, char **ap_ids, const char *buf, rdr_variable_message_info_t *var_msg_info); /* * Find Variable Info Sizes */ static int find_options_sizes(char *options, rdr_variable_message_info_t *var_msg_info); static int find_listopts_sizes(char *listopts, rdr_variable_message_info_t *var_msg_info); static int find_function_sizes(char *function, rdr_variable_message_info_t *var_msg_info); static int find_errstring_sizes(char **errstring, rdr_variable_message_info_t *var_msg_info); /* * Extract Info From Buffers */ static int get_ap_ids_from_buf(char ***ap_id_ptr, int num_ap_ids, rdr_variable_message_info_t *var_msg_info, const char *buf); static int get_string_from_buf(char **stringptr, int strsize, const char *buf); /* * Cleanup Routines */ static int cleanup_ap_ids(int num_ap_ids, char **ap_ids); static int cleanup_errstring(char **errstring); static void cleanup_variable_ap_id_info( rdr_variable_message_info_t *var_msg_info); /* * Functions for loading libdscp. */ static int load_libdscp(libdscp_t *libdscp); /* * Public Functions */ /* * rdr_open: * * Establish a transport endpoint to prepare for a new * connection. Returns a file descriptor representing the * new transport if successful or RDR_BAD_FD upon failure. */ int rdr_open(int family) { int newfd; if ((newfd = socket(family, SOCK_STREAM, 0)) == -1) { return (RDR_BAD_FD); } return (newfd); } /* * rdr_init: * * Initialize a transport endpoint. This involves binding to * a particular port and setting any user specified socket * options. */ int rdr_init(int fd, struct sockaddr *addr, int *opts, int num_opts, int blog) { int i; /* sanity checks */ if ((fd < 0) || (addr == NULL)) { return (RDR_ERROR); } if ((opts == NULL) || (num_opts < 0)) { num_opts = 0; } /* turn on security features */ if (rdr_secure(fd, addr) != RDR_OK) { return (RDR_NET_ERR); } /* bind the address, if is not already bound */ if (rdr_bind(fd, addr) != RDR_OK) { return (RDR_NET_ERR); } /* * Set TCP_NODELAY for this endpoint. This disables Nagle's * algorithm that can cause a delay in sending small sized * messages. Since most of the RDR messages are small, this * is a restriction that negatively impacts performance. */ if (rdr_setopt(fd, TCP_NODELAY, IPPROTO_TCP) != RDR_OK) { return (RDR_NET_ERR); } /* set the user specified socket options */ for (i = 0; i < num_opts; i++) { if (rdr_setopt(fd, opts[i], SOL_SOCKET) != RDR_OK) { return (RDR_NET_ERR); } } /* * If blog is not zero, it is a server that is being * initialized. In order for it to be able to accept * connections, we have to set the size of the incoming * connection queue. */ if (blog != 0) { if (listen(fd, blog) == -1) { return (RDR_NET_ERR); } } return (RDR_OK); } /* * rdr_connect_clnt: * * Perform the necessary steps for a client to connect to * a server process. The required information is the file * descriptor for the transport endpoint, and the remote * address. */ int rdr_connect_clnt(int fd, struct sockaddr *addr) { unsigned int addr_len; /* sanity check */ if (addr == NULL) { return (RDR_ERROR); } /* initialize the address length */ switch (addr->sa_family) { case AF_INET: addr_len = sizeof (struct sockaddr_in); break; case AF_INET6: addr_len = sizeof (struct sockaddr_in6); break; default: return (RDR_ERROR); } /* attempt the connection */ if (connect(fd, addr, addr_len) == -1) { return (RDR_NET_ERR); } return (RDR_OK); } /* * rdr_connect_srv: * * Perform the necessary steps for a server to connect to a * pending client request. The new connection is allocated a * new file descriptor, separate from the one used to accept * the connection. */ int rdr_connect_srv(int fd) { int newfd; unsigned int faddr_len; struct sockaddr_storage faddr; /* accept the connection */ faddr_len = sizeof (faddr); if ((newfd = accept(fd, (struct sockaddr *)&faddr, &faddr_len)) == -1) { return (RDR_BAD_FD); } /* if the peer doesn't authenticate properly, reject */ if (rdr_auth((struct sockaddr *)&faddr, faddr_len) != RDR_OK) { (void) close(newfd); return (RDR_BAD_FD); } return (newfd); } /* * rdr_reject: * * Reject an incoming connection attempt. This requires * that the connection be accepted first. */ int rdr_reject(int fd) { unsigned int faddr_len; struct sockaddr_storage faddr; /* first accept the connection */ faddr_len = sizeof (faddr); if (accept(fd, (struct sockaddr *)&faddr, &faddr_len) == -1) { return (RDR_NET_ERR); } /* then close it */ (void) close(fd); return (RDR_OK); } /* * rdr_close: * * Close down an given connection. */ int rdr_close(int fd) { (void) close(fd); return (RDR_OK); } /* * rdr_snd_msg: * * Public interface for sending an RDR message. The data * passed in through hdr and param are packed for network * transport and sent. */ int rdr_snd_msg(int fd, rdr_msg_hdr_t *hdr, cfga_params_t *param, int timeout) { int err; char *pack_buf = NULL; int pack_buf_sz = 0; /* sanity checks */ if ((hdr == NULL) || (param == NULL)) { return (RDR_ERROR); } /* * Pack the message for transport */ switch (hdr->message_opcode) { case RDR_SES_REQ: { ses_req_params_t *rparam; rparam = (ses_req_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_ses_req_request(rparam, &pack_buf, &pack_buf_sz); } else { err = pack_ses_req_reply(rparam, &pack_buf, &pack_buf_sz); } break; } case RDR_SES_ESTBL: case RDR_SES_END: /* * This is not an error condition because * there is no extra information to pack. */ err = RDR_OK; break; case RDR_CONF_CHANGE_STATE: { change_state_params_t *cparam; cparam = (change_state_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_change_state_request(cparam, &pack_buf, &pack_buf_sz); } else { err = pack_change_state_reply(cparam, &pack_buf, &pack_buf_sz); } break; } case RDR_CONF_PRIVATE_FUNC: { private_func_params_t *pparam; pparam = (private_func_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_private_func_request(pparam, &pack_buf, &pack_buf_sz); } else { err = pack_private_func_reply(pparam, &pack_buf, &pack_buf_sz); } break; } case RDR_CONF_TEST: { test_params_t *tparam; tparam = (test_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_test_request(tparam, &pack_buf, &pack_buf_sz); } else { err = pack_test_reply(tparam, &pack_buf, &pack_buf_sz); } break; } case RDR_CONF_LIST_EXT: { list_ext_params_t *lparam; lparam = (list_ext_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_list_ext_request(lparam, &pack_buf, &pack_buf_sz); } else { err = pack_list_ext_reply(lparam, &pack_buf, &pack_buf_sz); } break; } case RDR_CONF_HELP: { help_params_t *hparam; hparam = (help_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_help_request(hparam, &pack_buf, &pack_buf_sz); } else { /* * This is not an error because help * reply does not have any extra information * to pack. */ err = RDR_OK; } break; } case RDR_CONF_AP_ID_CMP: { ap_id_cmp_params_t *aparam; aparam = (ap_id_cmp_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_ap_id_cmp_request(aparam, &pack_buf, &pack_buf_sz); } else { /* * This is not an error because ap_id_cmp * reply does not have any extra information * to pack. */ err = RDR_OK; } break; } case RDR_CONF_ABORT_CMD: { abort_cmd_params_t *aparam; aparam = (abort_cmd_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_abort_cmd_request(aparam, &pack_buf, &pack_buf_sz); } else { /* * This is not an error because session * abort reply does not have any extra * information to pack. */ err = RDR_OK; } break; } case RDR_CONF_CONFIRM_CALLBACK: { confirm_callback_params_t *cparam; cparam = (confirm_callback_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_confirm_request(cparam, &pack_buf, &pack_buf_sz); } else { err = pack_confirm_reply(cparam, &pack_buf, &pack_buf_sz); } break; } case RDR_CONF_MSG_CALLBACK: { msg_callback_params_t *mparam; mparam = (msg_callback_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_message_request(mparam, &pack_buf, &pack_buf_sz); } else { /* * It is an error to send a reply * to a message callback. */ err = RDR_MSG_INVAL; } break; } case RDR_RSRC_INFO: { rsrc_info_params_t *rparam; rparam = (rsrc_info_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = pack_rsrc_info_request(rparam, &pack_buf, &pack_buf_sz); } else { if ((hdr->major_version == 1) && (hdr->minor_version == 0)) { err = pack_rsrc_info_reply(rparam, &pack_buf, &pack_buf_sz, NV_ENCODE_NATIVE); } else { err = pack_rsrc_info_reply(rparam, &pack_buf, &pack_buf_sz, NV_ENCODE_XDR); } } break; } default: err = RDR_MSG_INVAL; break; } /* check if packed correctly */ if (err != RDR_OK) { return (err); } /* send the message */ err = rdr_snd(fd, hdr, pack_buf, pack_buf_sz, timeout); free((void *)pack_buf); return (err); } /* * rdr_rcv_msg: * * Public interface for receiving an RDR message. Data is * unpacked into the hdr and param paramters. */ int rdr_rcv_msg(int fd, rdr_msg_hdr_t *hdr, cfga_params_t *param, int timeout) { int err; char *unpack_buf = NULL; /* sanity checks */ if ((hdr == NULL) || (param == NULL)) { return (RDR_ERROR); } (void) memset(param, 0, sizeof (cfga_params_t)); /* receive the message */ if ((err = rdr_rcv(fd, hdr, &unpack_buf, timeout)) != RDR_OK) { return (err); } /* * Unpack the message */ switch (hdr->message_opcode) { case RDR_SES_REQ: { ses_req_params_t *rparam; rparam = (ses_req_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_ses_req_request(rparam, unpack_buf); } else { err = unpack_ses_req_reply(rparam, unpack_buf); } break; } case RDR_SES_ESTBL: case RDR_SES_END: /* no information to unpack */ (void) memset(param, 0, sizeof (cfga_params_t)); err = RDR_OK; break; case RDR_CONF_CHANGE_STATE: { change_state_params_t *cparam; cparam = (change_state_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_change_state_request(cparam, unpack_buf); } else { err = unpack_change_state_reply(cparam, unpack_buf); } break; } case RDR_CONF_PRIVATE_FUNC: { private_func_params_t *pparam; pparam = (private_func_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_private_func_request(pparam, unpack_buf); } else { err = unpack_private_func_reply(pparam, unpack_buf); } break; } case RDR_CONF_TEST: { test_params_t *tparam; tparam = (test_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_test_request(tparam, unpack_buf); } else { err = unpack_test_reply(tparam, unpack_buf); } break; } case RDR_CONF_LIST_EXT: { list_ext_params_t *lparam; lparam = (list_ext_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_list_ext_request(lparam, unpack_buf); } else { err = unpack_list_ext_reply(lparam, unpack_buf); } break; } case RDR_CONF_HELP: { help_params_t *hparam; hparam = (help_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_help_request(hparam, unpack_buf); } else { /* * This is not an error because help * reply does not have any extra information * to unpack. */ err = RDR_OK; } break; } case RDR_CONF_AP_ID_CMP: { ap_id_cmp_params_t *aparam; aparam = (ap_id_cmp_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_ap_id_cmp_request(aparam, unpack_buf); } else { /* * This is not an error because ap_id_cmp * reply does not have any extra information * to pack. */ err = RDR_OK; } break; } case RDR_CONF_ABORT_CMD: { abort_cmd_params_t *aparam; aparam = (abort_cmd_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_abort_cmd_request(aparam, unpack_buf); } else { /* no information to unpack */ (void) memset(param, 0, sizeof (cfga_params_t)); err = RDR_OK; } break; } case RDR_CONF_CONFIRM_CALLBACK: { confirm_callback_params_t *cparam; cparam = (confirm_callback_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_confirm_request(cparam, unpack_buf); } else { err = unpack_confirm_reply(cparam, unpack_buf); } break; } case RDR_CONF_MSG_CALLBACK: { msg_callback_params_t *mparam; mparam = (msg_callback_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_message_request(mparam, unpack_buf); } else { /* * It is an error to send a reply * to a message callback. */ (void) memset(param, 0, sizeof (cfga_params_t)); err = RDR_MSG_INVAL; } break; } case RDR_RSRC_INFO: { rsrc_info_params_t *rparam; rparam = (rsrc_info_params_t *)param; if (hdr->data_type == RDR_REQUEST) { err = unpack_rsrc_info_request(rparam, unpack_buf); } else { err = unpack_rsrc_info_reply(rparam, unpack_buf); } break; } default: err = RDR_MSG_INVAL; break; } free(unpack_buf); /* check if unpacked correctly */ if (err != RDR_OK) { return (err); } return (RDR_OK); } /* * rdr_cleanup_params: * * Deallocate any memory that was allocated in unpacking a * message. */ int rdr_cleanup_params(rdr_msg_opcode_t message_opcode, cfga_params_t *param) { /* sanity check */ if ((param == NULL)) { return (RDR_ERROR); } /* * Deallocate memory depending on * the operation. */ switch (message_opcode) { case RDR_SES_REQ: { ses_req_params_t *sparam; sparam = (ses_req_params_t *)param; if (sparam->locale_str != NULL) { free((void *)sparam->locale_str); sparam->locale_str = NULL; } break; } case RDR_SES_ESTBL: case RDR_SES_END: /* nothing to deallocate */ break; case RDR_CONF_CHANGE_STATE: { change_state_params_t *cparam; cparam = (change_state_params_t *)param; cleanup_ap_ids(cparam->num_ap_ids, (char **)cparam->ap_ids); cparam->ap_ids = NULL; if (cparam->options != NULL) { free((void *)cparam->options); cparam->options = NULL; } if (cparam->confp != NULL) { free((void *)cparam->confp); cparam->confp = NULL; } if (cparam->msgp != NULL) { free((void *)cparam->msgp); cparam->msgp = NULL; } cleanup_errstring(cparam->errstring); break; } case RDR_CONF_PRIVATE_FUNC: { private_func_params_t *pparam; pparam = (private_func_params_t *)param; cleanup_ap_ids(pparam->num_ap_ids, (char **)pparam->ap_ids); pparam->ap_ids = NULL; if (pparam->options != NULL) { free((void *)pparam->options); pparam->options = NULL; } if (pparam->confp != NULL) { free((void *)pparam->confp); pparam->confp = NULL; } if (pparam->msgp != NULL) { free((void *)pparam->msgp); pparam->msgp = NULL; } cleanup_errstring(pparam->errstring); break; } case RDR_CONF_TEST: { test_params_t *tparam; tparam = (test_params_t *)param; cleanup_ap_ids(tparam->num_ap_ids, (char **)tparam->ap_ids); tparam->ap_ids = NULL; if (tparam->options != NULL) { free((void *)tparam->options); tparam->options = NULL; } if (tparam->msgp != NULL) { free((void *)tparam->msgp); tparam->msgp = NULL; } cleanup_errstring(tparam->errstring); break; } case RDR_CONF_LIST_EXT: { list_ext_params_t *lparam; lparam = (list_ext_params_t *)param; cleanup_ap_ids(lparam->num_ap_ids, (char **)lparam->ap_ids); lparam->ap_ids = NULL; if (lparam->nlist != NULL) { free((void *)lparam->nlist); lparam->nlist = NULL; } if (lparam->ap_id_list != NULL) { if (*lparam->ap_id_list != NULL) { free((void *)*lparam->ap_id_list); } free((void *)lparam->ap_id_list); lparam->ap_id_list = NULL; } if (lparam->ap_id_list != NULL) { free((void *)lparam->ap_id_list); lparam->ap_id_list = NULL; } if (lparam->options != NULL) { free((void *)lparam->options); lparam->options = NULL; } if (lparam->listopts != NULL) { free((void *)lparam->listopts); lparam->listopts = NULL; } cleanup_errstring(lparam->errstring); break; } case RDR_CONF_HELP: { help_params_t *hparam; hparam = (help_params_t *)param; cleanup_ap_ids(hparam->num_ap_ids, (char **)hparam->ap_ids); hparam->ap_ids = NULL; if (hparam->msgp != NULL) { free((void *)hparam->msgp); hparam->msgp = NULL; } if (hparam->options != NULL) { free((void *)hparam->options); hparam->options = NULL; } break; } case RDR_CONF_AP_ID_CMP: { ap_id_cmp_params_t *aparam; aparam = (ap_id_cmp_params_t *)param; if (aparam->ap_log_id1 != NULL) { free((void *)aparam->ap_log_id1); aparam->ap_log_id1 = NULL; } if (aparam->ap_log_id2 != NULL) { free((void *)aparam->ap_log_id2); aparam->ap_log_id2 = NULL; } break; } case RDR_CONF_ABORT_CMD: /* nothing to deallocate */ break; case RDR_CONF_CONFIRM_CALLBACK: { confirm_callback_params_t *cparam; cparam = (confirm_callback_params_t *)param; if (cparam->confp != NULL) { free((void *)cparam->confp); cparam->confp = NULL; } if (cparam->message != NULL) { free((void *)cparam->message); cparam->message = NULL; } break; } case RDR_CONF_MSG_CALLBACK: { msg_callback_params_t *mparam; mparam = (msg_callback_params_t *)param; if (mparam->msgp != NULL) { free((void *)mparam->msgp); mparam->msgp = NULL; } if (mparam->message != NULL) { free((void *)mparam->message); mparam->message = NULL; } break; } default: return (RDR_ERROR); /* NOTREACHED */ break; } return (RDR_OK); } /* * rdr_setsockopt: * * Wrapper of the setsockopt(3SOCKET) library function. */ int rdr_setsockopt(int fd, int level, int optname, const void *optval, int optlen) { if (setsockopt(fd, level, optname, optval, optlen) == -1) return (RDR_NET_ERR); else return (RDR_OK); } /* * Private (static) Functions */ /* * rdr_setopt: * * Set the specified option for a given transport endpoint. * This function only sets boolean options. It does not * provide the ability to unset an option, or set a non- * boolean option. */ static int rdr_setopt(int fd, int name, int level) { int on = 1; if (setsockopt(fd, level, name, &on, sizeof (on)) == -1) { return (RDR_NET_ERR); } return (RDR_OK); } /* * rdr_bind: * * Bind the specified file descriptor to a specified * address. If the address is already bound, no error is * returned. This is the expected behavior if a server * has been started by inetd(8). */ static int rdr_bind(int fd, struct sockaddr *addr) { unsigned int addr_len; int rc; /* initialize the address */ switch (addr->sa_family) { case AF_INET: addr_len = sizeof (struct sockaddr_in); break; case AF_INET6: addr_len = sizeof (struct sockaddr_in6); break; default: return (RDR_ERROR); } /* attempt to bind the address */ rc = bind(fd, addr, addr_len); /* * Ignore the error if EINVAL is returned. In * this case, we assume that this means that * the address was already bound. This is not * an error for servers started by inetd(8). */ if ((rc == -1) && (errno != EINVAL)) { return (RDR_NET_ERR); } /* * Retreive the address information of the * address that was actually bound. */ addr_len = sizeof (*addr); if (getsockname(fd, addr, &addr_len) == -1) { (void) memset(addr, 0, sizeof (*addr)); return (RDR_NET_ERR); } return (RDR_OK); } /* * rdr_secure: * * Activate security features for a socket. * * Some platforms have libdscp, which provides additional * security features. An attempt is made to load libdscp * and use these features. * * Nothing is done if libdscp is not available. */ static int rdr_secure(int fd, struct sockaddr *addr) { struct sockaddr_in *sin; int port; int error; if (use_libdscp == 0) { return (RDR_OK); } if (load_libdscp(&libdscp) != 1) { return (RDR_ERROR); } /* LINTED E_BAD_PTR_CAST_ALIGN */ sin = (struct sockaddr_in *)addr; port = ntohs(sin->sin_port); error = libdscp.bind(0, fd, port); if ((error != DSCP_OK) && (error != DSCP_ERROR_ALREADY)) { return (RDR_ERROR); } if (libdscp.secure(0, fd) != DSCP_OK) { return (RDR_ERROR); } return (RDR_OK); } /* * rdr_auth: * * Authenticate if a connection is really from the service * processor. This is dependent upon functionality from * libdscp, so an attempt to load and use libdscp is made. * * Without libdscp, this function does nothing. */ static int rdr_auth(struct sockaddr *addr, int len) { if (use_libdscp != 0) { if ((load_libdscp(&libdscp) == 0) || (libdscp.auth(0, addr, len) != DSCP_OK)) { return (RDR_ERROR); } } return (RDR_OK); } /* * rdr_snd: * * Send a message in two stages. First the header is sent, * followed by the packed buffer containing the message * contents. */ static int rdr_snd(int fd, rdr_msg_hdr_t *hdr, char *data, int data_sz, int timeout) { int err; /* sanity check */ if (hdr == NULL) { return (RDR_ERROR); } /* ensure null pad bytes */ hdr->pad_byte1 = 0; hdr->pad_byte2 = 0; /* initialize size information */ hdr->data_length = data_sz; /* send message header */ err = rdr_snd_raw(fd, (char *)hdr, RDR_MSG_HDR_SIZE, timeout); if (err != RDR_OK) { return (err); } /* check if more to send */ if (data_sz == 0) { return (RDR_OK); } /* send message data */ err = rdr_snd_raw(fd, data, data_sz, timeout); if (err != RDR_OK) { return (err); } return (RDR_OK); } /* * rdr_snd_raw: * * Send a raw buffer of information. This function handles * the low level details of the send operation. */ static int rdr_snd_raw(int fd, char *msg, int data_sz, int timeout) { int err; int num_bytes; int bytes_left; char *bufp; struct pollfd pfd; bufp = (char *)msg; bytes_left = data_sz; pfd.fd = fd; pfd.events = POLLOUT; while (bytes_left > 0) { pfd.revents = 0; /* wait until we can send the data */ if ((err = poll(&pfd, 1, timeout)) == -1) { /* poll was interrupted */ if (errno == EINTR) { return (RDR_ABORTED); } return (RDR_ERROR); } else if (err == 0) { return (RDR_TIMEOUT); } /* ready to send data */ if (pfd.revents & POLLOUT) { num_bytes = write(fd, bufp, bytes_left); if (num_bytes == -1) { /* * Distinguish between an aborted * session and other network errors. */ if (errno == EPIPE) { return (RDR_ABORTED); } else { return (RDR_NET_ERR); } } /* wrote 0 bytes, so operation was aborted */ if (num_bytes == 0) { return (RDR_ABORTED); } } else { return (RDR_NET_ERR); } bytes_left -= num_bytes; bufp += num_bytes; } return (RDR_OK); } /* * rdr_rcv: * * Receive a message in two stages. First the header is * received, followed by the packed buffer containing the * message contents. */ static int rdr_rcv(int fd, rdr_msg_hdr_t *hdr, char **data, int timeout) { int err; int data_sz; char hdr_buf[RDR_MSG_HDR_SIZE]; char *buf = NULL; /* sanity check */ if (hdr == NULL) { return (RDR_ERROR); } /* receive the header */ err = rdr_rcv_raw(fd, hdr_buf, RDR_MSG_HDR_SIZE, timeout); if (err != RDR_OK) { return (err); } /* verify that the data is good */ /* LINTED Pointer Cast Alignment Warning */ if (validate_header((rdr_msg_hdr_t *)hdr_buf) != RDR_OK) { return (RDR_MSG_INVAL); } /* LINTED Pointer Cast Alignment Warning */ data_sz = ((rdr_msg_hdr_t *)hdr_buf)->data_length; buf = (char *)malloc(data_sz); if (!buf) { return (RDR_MEM_ALLOC); } if (data_sz != 0) { /* receive the rest of the message */ err = rdr_rcv_raw(fd, buf, data_sz, timeout); if (err != RDR_OK) { free((void *)buf); return (err); } } /* copy out data */ *data = buf; (void) memcpy(hdr, hdr_buf, RDR_MSG_HDR_SIZE); return (RDR_OK); } /* * rdr_rcv_raw: * * Receive a raw buffer of information. This function handles * the low level details of the receive operation. */ static int rdr_rcv_raw(int fd, char *msg, int data_size, int timeout) { int num_bytes; int err; int bytes_left; char *bufp; struct pollfd pollfd; bufp = (char *)msg; bytes_left = data_size; pollfd.fd = fd; pollfd.events = POLLIN; while (bytes_left > 0) { errno = 0; pollfd.revents = 0; if ((err = poll(&pollfd, 1, timeout)) == -1) { /* * In the DCA, if a session is aborted, SIGINT * is delivered to all active sessions. This * mistakenly causes all sessions waiting in * the poll to be interrupted. So, if EINTR * is returned, it is ignored. If another error * occurs right away, the current session really * was aborted. All other sessions won't encounter * an error and will proceed normally. */ if ((errno == 0) || (errno == EINTR)) { continue; } return (RDR_ABORTED); } else if (err == 0) { return (RDR_TIMEOUT); } /* ready to receive data */ if (pollfd.revents & POLLIN) { num_bytes = read(fd, bufp, bytes_left); if (num_bytes == -1) { /* * Distinguish between an aborted * session and other network errors. */ if (errno == ECONNRESET) { return (RDR_ABORTED); } else { return (RDR_NET_ERR); } } /* read 0 bytes, so operation was aborted */ if (num_bytes == 0) { return (RDR_ABORTED); } } else { return (RDR_NET_ERR); } bytes_left -= num_bytes; bufp += num_bytes; } return (RDR_OK); } /* * validate_header: * * Perform a series of sanity checks on the header data that is * received. This gets called before the variable length data is * read in to make sure that the information in the header can * be trusted. */ static int validate_header(rdr_msg_hdr_t *hdr) { unsigned char op; if (hdr == NULL) { return (RDR_ERROR); } op = hdr->message_opcode; /* validate opcode */ if ((op < RDR_SES_REQ) || (op >= RDR_NUM_OPS)) { return (RDR_ERROR); } /* validate message size (and type) for op */ switch (hdr->data_type) { case RDR_REQUEST: if (hdr->data_length > msg_sizes[op].req_max) { return (RDR_ERROR); } break; case RDR_REPLY: if (hdr->data_length > msg_sizes[op].reply_max) { return (RDR_ERROR); } break; default: /* invalid data type */ return (RDR_ERROR); } /* all checks passed */ return (RDR_OK); } /* * pack_ses_req_request: * * Handle packing a session request request message. */ static int pack_ses_req_request(ses_req_params_t *params, char **buf, int *buf_size) { char *bufptr; int locale_str_len; rdr_ses_req_t ses_req; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Determine the size of the locale string */ if (params->locale_str != NULL) { locale_str_len = strlen(params->locale_str) + 1; } else { locale_str_len = 0; } /* * Collect size info specific to the ses_req request message * and allocate a buffer */ *buf_size = sizeof (rdr_ses_req_t); *buf_size += locale_str_len; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed locale size label by name */ ses_req.locale_size = locale_str_len; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &ses_req, sizeof (rdr_ses_req_t)); bufptr += sizeof (rdr_ses_req_t); if (params->locale_str != NULL) { (void) memcpy(bufptr, params->locale_str, locale_str_len); bufptr += locale_str_len; } return (RDR_OK); } /* * unpack_ses_req_request: * * Handle unpacking a session request request message. */ static int unpack_ses_req_request(ses_req_params_t *params, const char *buf) { char *bufptr; rdr_ses_req_t ses_req_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&ses_req_data, bufptr, sizeof (rdr_ses_req_t)); bufptr += sizeof (rdr_ses_req_t); /* * handle getting the locale string */ if (get_string_from_buf(&(params->locale_str), ses_req_data.locale_size, bufptr)) { return (RDR_ERROR); } return (RDR_OK); } /* * pack_ses_req_reply: * * Handle packing a session request reply message. */ static int pack_ses_req_reply(ses_req_params_t *params, char **buf, int *buf_size) { rdr_ses_req_reply_t ses_req_reply_data; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Collect size info specific to the session request reply * message and allocate a buffer */ *buf_size = sizeof (rdr_ses_req_reply_t); *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed session identifier */ ses_req_reply_data.session_id = params->session_id; /* * Copy information using memcpy */ (void) memcpy(*buf, &ses_req_reply_data, sizeof (rdr_ses_req_reply_t)); return (RDR_OK); } /* * unpack_ses_req_request: * * Handle unpacking a session request reply message. */ static int unpack_ses_req_reply(ses_req_params_t *params, const char *buf) { rdr_ses_req_reply_t *ses_req_reply_datap; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } /* LINTED Pointer Cast Alignment Warning */ ses_req_reply_datap = (rdr_ses_req_reply_t *)buf; /* * copy out the session information */ params->session_id = ses_req_reply_datap->session_id; return (RDR_OK); } /* * pack_change_state_request: * * Handle packing a change state request message. */ static int pack_change_state_request(change_state_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_change_state_t change_state_data; rdr_variable_message_info_t var_msg_info; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); /* * Set variable length fields and make a call to partially * pack it. */ if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } if (find_options_sizes(params->options, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } /* * Collect size info specific to the change_state request * message and allocate a buffer */ *buf_size = sizeof (rdr_change_state_t); *buf_size += var_msg_info.ap_id_int_size; *buf_size += var_msg_info.ap_id_char_size; *buf_size += var_msg_info.options_strlen; *buf_size += var_msg_info.options_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ change_state_data.num_ap_ids = params->num_ap_ids; change_state_data.ap_id_char_size = var_msg_info.ap_id_char_size; change_state_data.options_size = var_msg_info.options_strlen + var_msg_info.options_pad_sz; if (params->confp != NULL) { change_state_data.confirm_callback_id = (unsigned long)params->confp->confirm; change_state_data.confirm_appdata_ptr = (unsigned long)params->confp->appdata_ptr; } else { change_state_data.confirm_callback_id = 0; change_state_data.confirm_appdata_ptr = 0; } if (params->msgp != NULL) { change_state_data.msg_callback_id = (unsigned long)params->msgp->message_routine; change_state_data.msg_appdata_ptr = (unsigned long)params->msgp->appdata_ptr; } else { change_state_data.msg_callback_id = 0; change_state_data.msg_appdata_ptr = 0; } change_state_data.flags = params->flags; change_state_data.timeval = params->timeval; change_state_data.state_change_cmd = params->state_change; if (params->errstring != NULL) { change_state_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS; } else { change_state_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS; } change_state_data.retries = params->retries; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &change_state_data, sizeof (rdr_change_state_t)); bufptr += sizeof (rdr_change_state_t); if (var_msg_info.ap_id_sizes != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_sizes, var_msg_info.ap_id_int_size); bufptr += var_msg_info.ap_id_int_size; } if (var_msg_info.ap_id_chars != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_chars, var_msg_info.ap_id_char_size); bufptr += var_msg_info.ap_id_char_size; } if (params->options != NULL) { (void) memcpy(bufptr, params->options, var_msg_info.options_strlen); bufptr += var_msg_info.options_strlen; for (i = 0; i < var_msg_info.options_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.options_pad_sz; } cleanup_variable_ap_id_info(&var_msg_info); return (RDR_OK); } /* * unpack_change_state_request: * * Handle unpacking a change state request message. */ static int unpack_change_state_request(change_state_params_t *params, const char *buf) { char *bufptr; rdr_variable_message_info_t var_msg_info; rdr_change_state_t change_state_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); bufptr = (char *)buf; (void) memcpy(&change_state_data, bufptr, sizeof (rdr_change_state_t)); bufptr += sizeof (rdr_change_state_t); /* * handle getting the ap_ids */ var_msg_info.ap_id_char_size = change_state_data.ap_id_char_size; if (get_ap_ids_from_buf((char ***)&(params->ap_ids), change_state_data.num_ap_ids, &var_msg_info, bufptr)) { return (RDR_ERROR); } bufptr += var_msg_info.ap_id_int_size; bufptr += var_msg_info.ap_id_char_size; /* * handle getting the options */ if (get_string_from_buf(&(params->options), change_state_data.options_size, bufptr)) { return (RDR_ERROR); } bufptr += change_state_data.options_size; /* * Set fixed address labels by name */ params->state_change = (cfga_cmd_t)change_state_data.state_change_cmd; params->num_ap_ids = change_state_data.num_ap_ids; params->confp = (struct cfga_confirm *) malloc(sizeof (struct cfga_confirm)); if (params->confp == NULL) { return (RDR_MEM_ALLOC); } /* set params->confp->confirm using memcpy */ (void) memcpy((void*)params->confp, &(change_state_data.confirm_callback_id), sizeof (unsigned long)); params->confp->appdata_ptr = (void*)change_state_data.confirm_appdata_ptr; params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg)); if (params->msgp == NULL) { return (RDR_MEM_ALLOC); } /* set params->msgp->message_routine using memcpy */ (void) memcpy((void*)params->msgp, &(change_state_data.msg_callback_id), sizeof (unsigned long)); params->msgp->appdata_ptr = (void*)change_state_data.msg_appdata_ptr; if (change_state_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) { params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } *(params->errstring) = NULL; } else { /* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */ params->errstring = NULL; } params->flags = change_state_data.flags; params->timeval = change_state_data.timeval; params->retries = change_state_data.retries; return (RDR_OK); } /* * pack_change_state_reply: * * Handle packing a change state reply message. */ static int pack_change_state_reply(change_state_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_change_state_reply_t change_state_data; rdr_variable_message_info_t var_msg_info; (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Set variable length fields (size info) */ if (find_errstring_sizes(params->errstring, &var_msg_info)) { return (RDR_ERROR); } /* * Collect size info specific to the change_state reply * message and allocate a buffer */ *buf_size = sizeof (rdr_change_state_reply_t); *buf_size += var_msg_info.errstring_strlen; *buf_size += var_msg_info.errstring_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ change_state_data.errstring_size = var_msg_info.errstring_strlen + var_msg_info.errstring_pad_sz; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &change_state_data, sizeof (rdr_change_state_reply_t)); bufptr += sizeof (rdr_change_state_reply_t); if ((params->errstring != NULL) && (*(params->errstring) != NULL)) { (void) memcpy(bufptr, *(params->errstring), var_msg_info.errstring_strlen); bufptr += var_msg_info.errstring_strlen; for (i = 0; i < var_msg_info.errstring_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.errstring_pad_sz; } return (RDR_OK); } /* * unpack_change_state_reply: * * Handle unpacking a change state reply message. */ static int unpack_change_state_reply(change_state_params_t *params, const char *buf) { char *bufptr; rdr_change_state_reply_t change_state_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&change_state_data, bufptr, sizeof (rdr_change_state_reply_t)); bufptr += sizeof (rdr_change_state_reply_t); /* * handle getting the errstring */ params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } if (get_string_from_buf(params->errstring, change_state_data.errstring_size, bufptr)) { return (RDR_ERROR); } bufptr += change_state_data.errstring_size; return (RDR_OK); } /* * pack_private_func_request: * * Handle packing a private function request message. */ static int pack_private_func_request(private_func_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_private_func_t private_func_data; rdr_variable_message_info_t var_msg_info; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); /* * Set variable length fields and make a call to partially * pack it. */ if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } if (find_options_sizes(params->options, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } if (find_function_sizes(params->function, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } /* * Collect size info specific to the private_func request * message and allocate a buffer */ *buf_size = sizeof (rdr_private_func_t); *buf_size += var_msg_info.ap_id_int_size; *buf_size += var_msg_info.ap_id_char_size; *buf_size += var_msg_info.options_strlen; *buf_size += var_msg_info.options_pad_sz; *buf_size += var_msg_info.function_strlen; *buf_size += var_msg_info.function_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ private_func_data.num_ap_ids = params->num_ap_ids; private_func_data.ap_id_char_size = var_msg_info.ap_id_char_size; private_func_data.options_size = var_msg_info.options_strlen + var_msg_info.options_pad_sz; private_func_data.function_size = var_msg_info.function_strlen + var_msg_info.function_pad_sz; if (params->confp != NULL) { private_func_data.confirm_callback_id = (unsigned long)params->confp->confirm; private_func_data.confirm_appdata_ptr = (unsigned long)params->confp->appdata_ptr; } else { private_func_data.confirm_callback_id = 0; private_func_data.confirm_appdata_ptr = 0; } if (params->msgp != NULL) { private_func_data.msg_callback_id = (unsigned long)params->msgp->message_routine; private_func_data.msg_appdata_ptr = (unsigned long)params->msgp->appdata_ptr; } else { private_func_data.msg_callback_id = 0; private_func_data.msg_appdata_ptr = 0; } private_func_data.flags = params->flags; if (params->errstring != NULL) { private_func_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS; } else { private_func_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS; } /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &private_func_data, sizeof (rdr_private_func_t)); bufptr += sizeof (rdr_private_func_t); if (var_msg_info.ap_id_sizes != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_sizes, var_msg_info.ap_id_int_size); bufptr += var_msg_info.ap_id_int_size; } if (var_msg_info.ap_id_chars != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_chars, var_msg_info.ap_id_char_size); bufptr += var_msg_info.ap_id_char_size; } if (params->options != NULL) { (void) memcpy(bufptr, params->options, var_msg_info.options_strlen); bufptr += var_msg_info.options_strlen; for (i = 0; i < var_msg_info.options_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.options_pad_sz; } if (params->function != NULL) { (void) memcpy(bufptr, params->function, var_msg_info.function_strlen); bufptr += var_msg_info.function_strlen; for (i = 0; i < var_msg_info.function_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.function_pad_sz; } cleanup_variable_ap_id_info(&var_msg_info); return (RDR_OK); } /* * unpack_private_func_request: * * Handle unpacking a private function request message. */ static int unpack_private_func_request(private_func_params_t *params, const char *buf) { char *bufptr; rdr_variable_message_info_t var_msg_info; rdr_private_func_t private_func_data; (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&private_func_data, bufptr, sizeof (rdr_private_func_t)); bufptr += sizeof (rdr_private_func_t); /* * handle getting the ap_ids */ var_msg_info.ap_id_char_size = private_func_data.ap_id_char_size; if (get_ap_ids_from_buf((char ***)&(params->ap_ids), private_func_data.num_ap_ids, &var_msg_info, bufptr)) { return (RDR_ERROR); } bufptr += var_msg_info.ap_id_int_size; bufptr += var_msg_info.ap_id_char_size; /* * handle getting the options and function */ if (get_string_from_buf(&(params->options), private_func_data.options_size, bufptr)) { return (RDR_ERROR); } bufptr += private_func_data.options_size; if (get_string_from_buf(&(params->function), private_func_data.function_size, bufptr)) { return (RDR_ERROR); } bufptr += private_func_data.function_size; /* * Set fixed address labels by name */ params->num_ap_ids = private_func_data.num_ap_ids; params->confp = (struct cfga_confirm *) malloc(sizeof (struct cfga_confirm)); if (params->confp == NULL) { return (RDR_MEM_ALLOC); } /* set params->confp->confirm using memcpy */ (void) memcpy((void*)params->confp, &(private_func_data.confirm_callback_id), sizeof (unsigned long)); params->confp->appdata_ptr = (void*)private_func_data.confirm_appdata_ptr; params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg)); if (params->msgp == NULL) { return (RDR_MEM_ALLOC); } /* set params->msgp->message_routine using memcpy */ (void) memcpy((void*)params->msgp, &(private_func_data.msg_callback_id), sizeof (unsigned long)); params->msgp->appdata_ptr = (void*)private_func_data.msg_appdata_ptr; if (private_func_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) { params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } *(params->errstring) = NULL; } else { /* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */ params->errstring = NULL; } params->flags = private_func_data.flags; return (RDR_OK); } /* * pack_private_func_reply: * * Handle packing a private function reply message. */ static int pack_private_func_reply(private_func_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_private_func_reply_t private_func_data; rdr_variable_message_info_t var_msg_info; (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Set variable length fields (size info) */ if (find_errstring_sizes(params->errstring, &var_msg_info)) { return (RDR_ERROR); } /* * Collect size info specific to the private_func reply * message and allocate a buffer */ *buf_size = sizeof (rdr_private_func_reply_t); *buf_size += var_msg_info.errstring_strlen; *buf_size += var_msg_info.errstring_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ private_func_data.errstring_size = var_msg_info.errstring_strlen + var_msg_info.errstring_pad_sz; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &private_func_data, sizeof (rdr_private_func_reply_t)); bufptr += sizeof (rdr_private_func_reply_t); if ((params->errstring != NULL) && (*(params->errstring) != NULL)) { (void) memcpy(bufptr, *(params->errstring), var_msg_info.errstring_strlen); bufptr += var_msg_info.errstring_strlen; for (i = 0; i < var_msg_info.errstring_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.errstring_pad_sz; } return (RDR_OK); } /* * unpack_private_func_reply: * * Handle unpacking a private function reply message. */ static int unpack_private_func_reply(private_func_params_t *params, const char *buf) { char *bufptr; rdr_private_func_reply_t private_func_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&private_func_data, bufptr, sizeof (rdr_private_func_reply_t)); bufptr += sizeof (rdr_private_func_reply_t); /* * handle getting the errstring */ params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } if (get_string_from_buf(params->errstring, private_func_data.errstring_size, bufptr)) { return (RDR_ERROR); } bufptr += private_func_data.errstring_size; return (RDR_OK); } /* * pack_test_request: * * Handle packing a test request message. */ static int pack_test_request(test_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_test_t test_data; rdr_variable_message_info_t var_msg_info; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); /* * Set variable length fields and make a call to partially * pack it. */ if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } if (find_options_sizes(params->options, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } /* * Collect size info specific to the test request * message and allocate a buffer */ *buf_size = sizeof (rdr_test_t); *buf_size += var_msg_info.ap_id_int_size; *buf_size += var_msg_info.ap_id_char_size; *buf_size += var_msg_info.options_strlen; *buf_size += var_msg_info.options_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ test_data.num_ap_ids = params->num_ap_ids; test_data.ap_id_char_size = var_msg_info.ap_id_char_size; test_data.options_size = var_msg_info.options_strlen + var_msg_info.options_pad_sz; if (params->msgp != NULL) { test_data.msg_callback_id = (unsigned long)params->msgp->message_routine; test_data.msg_appdata_ptr = (unsigned long)params->msgp->appdata_ptr; } else { test_data.msg_callback_id = 0; test_data.msg_appdata_ptr = 0; } test_data.flags = params->flags; if (params->errstring != NULL) { test_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS; } else { test_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS; } /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &test_data, sizeof (rdr_test_t)); bufptr += sizeof (rdr_test_t); if (var_msg_info.ap_id_sizes != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_sizes, var_msg_info.ap_id_int_size); bufptr += var_msg_info.ap_id_int_size; } if (var_msg_info.ap_id_chars != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_chars, var_msg_info.ap_id_char_size); bufptr += var_msg_info.ap_id_char_size; } if (params->options != NULL) { (void) memcpy(bufptr, params->options, var_msg_info.options_strlen); bufptr += var_msg_info.options_strlen; for (i = 0; i < var_msg_info.options_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.options_pad_sz; } cleanup_variable_ap_id_info(&var_msg_info); return (RDR_OK); } /* * unpack_test_request: * * Handle unpacking a test request message. */ static int unpack_test_request(test_params_t *params, const char *buf) { char *bufptr; rdr_variable_message_info_t var_msg_info; rdr_test_t test_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); bufptr = (char *)buf; (void) memcpy(&test_data, bufptr, sizeof (rdr_test_t)); bufptr += sizeof (rdr_test_t); /* * handle getting the ap_ids */ var_msg_info.ap_id_char_size = test_data.ap_id_char_size; if (get_ap_ids_from_buf((char ***)&(params->ap_ids), test_data.num_ap_ids, &var_msg_info, bufptr)) { return (RDR_ERROR); } bufptr += var_msg_info.ap_id_int_size; bufptr += var_msg_info.ap_id_char_size; /* * handle getting the options */ if (get_string_from_buf(&(params->options), test_data.options_size, bufptr)) { return (RDR_ERROR); } bufptr += test_data.options_size; /* * Set fixed address labels by name */ params->num_ap_ids = test_data.num_ap_ids; params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg)); if (params->msgp == NULL) { return (RDR_MEM_ALLOC); } /* set params->msgp->message_routine using memcpy */ (void) memcpy((void*)params->msgp, &(test_data.msg_callback_id), sizeof (unsigned long)); params->msgp->appdata_ptr = (void*)test_data.msg_appdata_ptr; if (test_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) { params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } *(params->errstring) = NULL; } else { /* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */ params->errstring = NULL; } params->flags = test_data.flags; return (RDR_OK); } /* * pack_test_reply: * * Handle packing a test reply message. */ static int pack_test_reply(test_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_test_reply_t test_data; rdr_variable_message_info_t var_msg_info; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); /* * Set variable length fields (size info) */ if (find_errstring_sizes(params->errstring, &var_msg_info)) { return (RDR_ERROR); } /* * Collect size info specific to the test reply * message and allocate a buffer */ *buf_size = sizeof (rdr_test_reply_t); *buf_size += var_msg_info.errstring_strlen; *buf_size += var_msg_info.errstring_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ test_data.errstring_size = var_msg_info.errstring_strlen + var_msg_info.errstring_pad_sz; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &test_data, sizeof (rdr_test_reply_t)); bufptr += sizeof (rdr_test_reply_t); if ((params->errstring != NULL) && (*(params->errstring) != NULL)) { (void) memcpy(bufptr, *(params->errstring), var_msg_info.errstring_strlen); bufptr += var_msg_info.errstring_strlen; for (i = 0; i < var_msg_info.errstring_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.errstring_pad_sz; } return (RDR_OK); } /* * unpack_test_reply: * * Handle unpacking a test reply message. */ static int unpack_test_reply(test_params_t *params, const char *buf) { char *bufptr; rdr_test_reply_t test_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&test_data, bufptr, sizeof (rdr_test_reply_t)); bufptr += sizeof (rdr_test_reply_t); /* * handle getting the errstring */ params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } if (get_string_from_buf(params->errstring, test_data.errstring_size, bufptr)) { return (RDR_ERROR); } bufptr += test_data.errstring_size; return (RDR_OK); } /* * pack_list_ext_request: * * Handle packing a list request message. */ static int pack_list_ext_request(list_ext_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_list_ext_t list_ext_data; rdr_variable_message_info_t var_msg_info; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); /* * Set variable length fields and make a call to partially * pack it. */ if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } if (find_options_sizes(params->options, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } if (find_listopts_sizes(params->listopts, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } /* * Collect size info specific to the list_ext request * message and allocate a buffer */ *buf_size = sizeof (rdr_list_ext_t); *buf_size += var_msg_info.ap_id_int_size; *buf_size += var_msg_info.ap_id_char_size; *buf_size += var_msg_info.options_strlen; *buf_size += var_msg_info.options_pad_sz; *buf_size += var_msg_info.listopts_strlen; *buf_size += var_msg_info.listopts_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ list_ext_data.num_ap_ids = params->num_ap_ids; list_ext_data.ap_id_char_size = var_msg_info.ap_id_char_size; list_ext_data.options_size = var_msg_info.options_strlen + var_msg_info.options_pad_sz; list_ext_data.listopts_size = var_msg_info.listopts_strlen + var_msg_info.listopts_pad_sz; if (params->errstring != NULL) { list_ext_data.error_msg_ctl = RDR_GENERATE_ERR_MSGS; } else { list_ext_data.error_msg_ctl = RDR_DONT_GENERATE_ERR_MSGS; } if ((params->num_ap_ids != 0) || (params->ap_ids != NULL)) { list_ext_data.list_msg_ctl = RDR_LIST_ONLY_PARAM_APS; } else { list_ext_data.list_msg_ctl = RDR_LIST_ALL_APS; } list_ext_data.flags = params->flags; list_ext_data.permissions = params->permissions; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &list_ext_data, sizeof (rdr_list_ext_t)); bufptr += sizeof (rdr_list_ext_t); if (var_msg_info.ap_id_sizes != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_sizes, var_msg_info.ap_id_int_size); bufptr += var_msg_info.ap_id_int_size; } if (var_msg_info.ap_id_chars != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_chars, var_msg_info.ap_id_char_size); bufptr += var_msg_info.ap_id_char_size; } if (params->options != NULL) { (void) memcpy(bufptr, params->options, var_msg_info.options_strlen); bufptr += var_msg_info.options_strlen; for (i = 0; i < var_msg_info.options_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.options_pad_sz; } if (params->listopts != NULL) { (void) memcpy(bufptr, params->listopts, var_msg_info.listopts_strlen); bufptr += var_msg_info.listopts_strlen; for (i = 0; i < var_msg_info.listopts_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.listopts_pad_sz; } cleanup_variable_ap_id_info(&var_msg_info); return (RDR_OK); } /* * unpack_list_ext_request: * * Handle unpacking a list request message. */ static int unpack_list_ext_request(list_ext_params_t *params, const char *buf) { char *bufptr; rdr_variable_message_info_t var_msg_info; rdr_list_ext_t list_ext_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); bufptr = (char *)buf; (void) memcpy(&list_ext_data, bufptr, sizeof (rdr_list_ext_t)); bufptr += sizeof (rdr_list_ext_t); /* * handle getting the ap_ids */ var_msg_info.ap_id_char_size = list_ext_data.ap_id_char_size; if (get_ap_ids_from_buf(&(params->ap_ids), list_ext_data.num_ap_ids, &var_msg_info, bufptr)) { return (RDR_ERROR); } bufptr += var_msg_info.ap_id_int_size; bufptr += var_msg_info.ap_id_char_size; /* * handle getting the options */ if (get_string_from_buf(&(params->options), list_ext_data.options_size, bufptr)) { return (RDR_ERROR); } bufptr += list_ext_data.options_size; /* * handle getting the listopts */ if (get_string_from_buf(&(params->listopts), list_ext_data.listopts_size, bufptr)) { return (RDR_ERROR); } bufptr += list_ext_data.listopts_size; /* * Set fixed address labels by name */ params->num_ap_ids = list_ext_data.num_ap_ids; params->ap_id_list = (rdr_list_t **)malloc(sizeof (rdr_list_t *)); if (params->ap_id_list == NULL) { return (RDR_MEM_ALLOC); } *(params->ap_id_list) = NULL; params->nlist = (int *)malloc(sizeof (int)); if (params->nlist == NULL) { return (RDR_MEM_ALLOC); } if (list_ext_data.error_msg_ctl == RDR_GENERATE_ERR_MSGS) { params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } *(params->errstring) = NULL; } else { /* error_msg_ctl == RDR_DONT_GENERATE_ERR_MSGS */ params->errstring = NULL; } params->flags = list_ext_data.flags; params->permissions = list_ext_data.permissions; return (RDR_OK); } /* * pack_list_ext_reply: * * Handle packing a list reply message. */ static int pack_list_ext_reply(list_ext_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_list_ext_reply_t list_ext_data; rdr_variable_message_info_t var_msg_info; int list_data_size; (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Set variable length fields (size info) */ if (find_errstring_sizes(params->errstring, &var_msg_info)) { return (RDR_ERROR); } if (params->nlist == NULL) { list_data_size = 0; } else { list_data_size = *(params->nlist) * sizeof (rdr_list_t); } /* * Collect size info specific to the list_ext reply * message and allocate a buffer */ *buf_size = sizeof (rdr_list_ext_reply_t); *buf_size += list_data_size; *buf_size += var_msg_info.errstring_strlen; *buf_size += var_msg_info.errstring_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ list_ext_data.num_ap_ids = (params->nlist) ? *(params->nlist) : 0; list_ext_data.errstring_size = var_msg_info.errstring_strlen + var_msg_info.errstring_pad_sz; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &list_ext_data, sizeof (rdr_list_ext_reply_t)); bufptr += sizeof (rdr_list_ext_reply_t); if ((params->ap_id_list != NULL) && (*(params->ap_id_list) != NULL)) { (void) memcpy(bufptr, *(params->ap_id_list), list_data_size); bufptr += list_data_size; } else if (list_data_size) { /* * Something is out of sync. We were expecting * some data to copy, but instead we found a * NULL pointer. */ (void) free((void *)*buf); *buf = NULL; return (RDR_ERROR); } if ((params->errstring != NULL) && (*(params->errstring) != NULL)) { (void) memcpy(bufptr, *(params->errstring), var_msg_info.errstring_strlen); bufptr += var_msg_info.errstring_strlen; for (i = 0; i < var_msg_info.errstring_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.errstring_pad_sz; } return (RDR_OK); } /* * unpack_list_ext_reply: * * Handle unpacking a list reply message. */ static int unpack_list_ext_reply(list_ext_params_t *params, const char *buf) { int list_data_size; char *bufptr; rdr_list_ext_reply_t list_ext_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&list_ext_data, bufptr, sizeof (rdr_list_ext_reply_t)); bufptr += sizeof (rdr_list_ext_reply_t); /* * handle getting the ap_id rcfga_list_data_t's. */ if (list_ext_data.num_ap_ids > 0) { params->nlist = (int *)malloc(sizeof (int)); if (params->nlist == NULL) { return (RDR_MEM_ALLOC); } *(params->nlist) = list_ext_data.num_ap_ids; params->ap_id_list = (rdr_list_t **) malloc(sizeof (rdr_list_t *)); if (params->ap_id_list == NULL) { return (RDR_MEM_ALLOC); } *(params->ap_id_list) = (rdr_list_t *) malloc(sizeof (rdr_list_t) * list_ext_data.num_ap_ids); if (*(params->ap_id_list) == NULL) { return (RDR_MEM_ALLOC); } list_data_size = list_ext_data.num_ap_ids * sizeof (rdr_list_t); (void) memcpy(*(params->ap_id_list), bufptr, list_data_size); bufptr += list_data_size; } /* * handle getting the errstring */ params->errstring = (char **)malloc(sizeof (char *)); if (params->errstring == NULL) { return (RDR_MEM_ALLOC); } if (get_string_from_buf(params->errstring, list_ext_data.errstring_size, bufptr)) { return (RDR_ERROR); } bufptr += list_ext_data.errstring_size; return (RDR_OK); } /* * pack_help_request: * * Handle packing a help request message. */ static int pack_help_request(help_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_help_t help_data; rdr_variable_message_info_t var_msg_info; (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Set variable length fields and make a call to partially * pack it. */ if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } if (find_options_sizes(params->options, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } /* * Collect size info specific to the help request message and * and allocate a buffer */ *buf_size = sizeof (rdr_help_t); *buf_size += var_msg_info.ap_id_int_size; *buf_size += var_msg_info.ap_id_char_size; *buf_size += var_msg_info.options_strlen; *buf_size += var_msg_info.options_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ help_data.num_ap_ids = params->num_ap_ids; help_data.ap_id_char_size = var_msg_info.ap_id_char_size; help_data.options_size = var_msg_info.options_strlen + var_msg_info.options_pad_sz; if (params->msgp != NULL) { help_data.msg_callback_id = (unsigned long)params->msgp->message_routine; help_data.msg_appdata_ptr = (unsigned long)params->msgp->appdata_ptr; } else { help_data.msg_callback_id = 0; help_data.msg_appdata_ptr = 0; } help_data.flags = params->flags; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &help_data, sizeof (rdr_help_t)); bufptr += sizeof (rdr_help_t); if (var_msg_info.ap_id_sizes != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_sizes, var_msg_info.ap_id_int_size); bufptr += var_msg_info.ap_id_int_size; } if (var_msg_info.ap_id_chars != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_chars, var_msg_info.ap_id_char_size); bufptr += var_msg_info.ap_id_char_size; } if (params->options != NULL) { (void) memcpy(bufptr, params->options, var_msg_info.options_strlen); bufptr += var_msg_info.options_strlen; for (i = 0; i < var_msg_info.options_pad_sz; i++) { bufptr[i] = 0; } bufptr += var_msg_info.options_pad_sz; } cleanup_variable_ap_id_info(&var_msg_info); return (RDR_OK); } /* * unpack_help_request: * * Handle unpacking a help request message. */ static int unpack_help_request(help_params_t *params, const char *buf) { char *bufptr; rdr_variable_message_info_t var_msg_info; rdr_help_t help_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); bufptr = (char *)buf; (void) memcpy(&help_data, bufptr, sizeof (rdr_help_t)); bufptr += sizeof (rdr_help_t); /* * handle getting the ap_ids */ var_msg_info.ap_id_char_size = help_data.ap_id_char_size; if (get_ap_ids_from_buf((char ***)&(params->ap_ids), help_data.num_ap_ids, &var_msg_info, bufptr)) { return (RDR_ERROR); } bufptr += var_msg_info.ap_id_int_size; bufptr += var_msg_info.ap_id_char_size; /* * handle getting the options */ if (get_string_from_buf(&(params->options), help_data.options_size, bufptr)) { return (RDR_ERROR); } bufptr += help_data.options_size; /* * Set fixed address labels by name */ params->num_ap_ids = help_data.num_ap_ids; params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg)); if (params->msgp == NULL) { return (RDR_MEM_ALLOC); } /* set params->msgp->message_routine using memcpy */ (void) memcpy((void*)params->msgp, &(help_data.msg_callback_id), sizeof (unsigned long)); params->msgp->appdata_ptr = (void*)help_data.msg_appdata_ptr; params->flags = help_data.flags; return (RDR_OK); } /* * pack_ap_id_cmp_request: * * Handle packing an attachment point comparison request message. */ static int pack_ap_id_cmp_request(ap_id_cmp_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_ap_id_cmp_t ap_id_cmp_data; int ap_id1_strlen; int ap_id1_pad_sz; int ap_id2_strlen; int ap_id2_pad_sz; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Set variable length fields and make a call to partially * pack it. */ if (params->ap_log_id1 != NULL) { ap_id1_strlen = strlen(params->ap_log_id1) + 1; ap_id1_pad_sz = RDR_ALIGN_64_BIT - (ap_id1_strlen % RDR_ALIGN_64_BIT); } else { ap_id1_strlen = 0; ap_id1_pad_sz = 0; } if (params->ap_log_id2 != NULL) { ap_id2_strlen = strlen(params->ap_log_id2) + 1; ap_id2_pad_sz = RDR_ALIGN_64_BIT - (ap_id2_strlen % RDR_ALIGN_64_BIT); } else { ap_id2_strlen = 0; ap_id2_pad_sz = 0; } /* * Collect size info specific to the ap id compare request * message and allocate a buffer */ *buf_size = sizeof (rdr_ap_id_cmp_t); *buf_size += ap_id1_strlen; *buf_size += ap_id1_pad_sz; *buf_size += ap_id2_strlen; *buf_size += ap_id2_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ ap_id_cmp_data.ap_id1_size = ap_id1_strlen + ap_id1_pad_sz; ap_id_cmp_data.ap_id2_size = ap_id2_strlen + ap_id2_pad_sz; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &ap_id_cmp_data, sizeof (rdr_ap_id_cmp_t)); bufptr += sizeof (rdr_ap_id_cmp_t); if (params->ap_log_id1 != NULL) { (void) memcpy(bufptr, params->ap_log_id1, ap_id1_strlen); bufptr += ap_id1_strlen; for (i = 0; i < ap_id1_pad_sz; i++) { bufptr[i] = 0; } bufptr += ap_id1_pad_sz; } if (params->ap_log_id2 != NULL) { (void) memcpy(bufptr, params->ap_log_id2, ap_id2_strlen); bufptr += ap_id2_strlen; for (i = 0; i < ap_id2_pad_sz; i++) { bufptr[i] = 0; } bufptr += ap_id2_pad_sz; } return (RDR_OK); } /* * unpack_ap_id_cmp_request: * * Handle unpacking an attachment point comparison request message. */ static int unpack_ap_id_cmp_request(ap_id_cmp_params_t *params, const char *buf) { char *bufptr; rdr_ap_id_cmp_t ap_id_cmp_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&ap_id_cmp_data, bufptr, sizeof (rdr_ap_id_cmp_t)); bufptr += sizeof (rdr_ap_id_cmp_t); /* * handle getting the cmp ap ids */ if (get_string_from_buf(&(params->ap_log_id1), ap_id_cmp_data.ap_id1_size, bufptr)) { return (RDR_ERROR); } bufptr += ap_id_cmp_data.ap_id1_size; if (get_string_from_buf(&(params->ap_log_id2), ap_id_cmp_data.ap_id2_size, bufptr)) { return (RDR_ERROR); } bufptr += ap_id_cmp_data.ap_id2_size; return (RDR_OK); } /* * pack_abort_cmd_request: * * Handle packing an abort request message. */ static int pack_abort_cmd_request(abort_cmd_params_t *params, char **buf, int *buf_size) { rdr_abort_cmd_t abort_cmd_data; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Collect size info specific to the abort cmd request * message and allocate a buffer */ *buf_size = sizeof (rdr_abort_cmd_t); *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed session identifier */ abort_cmd_data.session_id = params->session_id; /* * Copy information using memcpy */ (void) memcpy(*buf, &abort_cmd_data, sizeof (rdr_abort_cmd_t)); return (RDR_OK); } /* * unpack_abort_cmd_request: * * Handle unpacking an abort request message. */ static int unpack_abort_cmd_request(abort_cmd_params_t *params, const char *buf) { rdr_abort_cmd_t *abort_cmd_datap; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } /* LINTED Pointer Cast Alignment Warning */ abort_cmd_datap = (rdr_abort_cmd_t *)buf; /* * copy out the session information */ params->session_id = abort_cmd_datap->session_id; return (RDR_OK); } /* * pack_confirm_request: * * Handle packing a confirm callback request. */ static int pack_confirm_request(confirm_callback_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_confirm_callback_t confirm_callback_data; int message_strlen; int message_pad_sz; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Set variable length fields and make a call to partially * pack it. */ if (params->message != NULL) { message_strlen = strlen(params->message) + 1; message_pad_sz = RDR_ALIGN_64_BIT - (message_strlen % RDR_ALIGN_64_BIT); } else { message_strlen = 0; message_pad_sz = 0; } /* * Collect size info specific to the confirm callback request * message and allocate a buffer */ *buf_size = sizeof (rdr_confirm_callback_t); *buf_size += message_strlen; *buf_size += message_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ if (params->confp != NULL) { confirm_callback_data.confirm_callback_id = (unsigned long)params->confp->confirm; confirm_callback_data.appdata_ptr = (unsigned long)params->confp->appdata_ptr; } else { confirm_callback_data.confirm_callback_id = 0; confirm_callback_data.appdata_ptr = 0; } confirm_callback_data.message_size = message_strlen + message_pad_sz; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &confirm_callback_data, sizeof (rdr_confirm_callback_t)); bufptr += sizeof (rdr_confirm_callback_t); if (params->message != NULL) { (void) memcpy(bufptr, params->message, message_strlen); bufptr += message_strlen; for (i = 0; i < message_pad_sz; i++) { bufptr[i] = 0; } bufptr += message_pad_sz; } return (RDR_OK); } /* * unpack_confirm_request: * * Handle unpacking a confirm callback request. */ static int unpack_confirm_request(confirm_callback_params_t *params, const char *buf) { char *bufptr; rdr_confirm_callback_t confirm_callback_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&confirm_callback_data, bufptr, sizeof (rdr_confirm_callback_t)); bufptr += sizeof (rdr_confirm_callback_t); /* * handle getting the message text */ if (get_string_from_buf(&(params->message), confirm_callback_data.message_size, bufptr)) { return (RDR_ERROR); } bufptr += confirm_callback_data.message_size; /* * Set fixed address labels by name */ params->confp = (struct cfga_confirm *) malloc(sizeof (struct cfga_confirm)); if (params->confp == NULL) { return (RDR_MEM_ALLOC); } /* set params->confp->confirm using memcpy */ (void) memcpy((void*)params->confp, &(confirm_callback_data.confirm_callback_id), sizeof (unsigned long)); params->confp->appdata_ptr = (void*)confirm_callback_data.appdata_ptr; return (RDR_OK); } /* * pack_confirm_reply: * * Handle packing a confirm callback reply. */ static int pack_confirm_reply(confirm_callback_params_t *params, char **buf, int *buf_size) { char *bufptr; rdr_confirm_callback_reply_t confirm_callback_data; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Collect size info specific to the confirm callback reply * message and allocate a buffer */ *buf_size = sizeof (confirm_callback_params_t); *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ if (params->confp != NULL) { confirm_callback_data.confirm_callback_id = (unsigned long)params->confp->confirm; confirm_callback_data.appdata_ptr = (unsigned long)params->confp->appdata_ptr; } else { confirm_callback_data.confirm_callback_id = 0; confirm_callback_data.appdata_ptr = 0; } confirm_callback_data.response = params->response; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &confirm_callback_data, sizeof (rdr_confirm_callback_reply_t)); return (RDR_OK); } /* * unpack_confirm_reply: * * Handle unpacking a confirm callback reply. */ static int unpack_confirm_reply(confirm_callback_params_t *params, const char *buf) { char *bufptr; rdr_confirm_callback_reply_t confirm_callback_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&confirm_callback_data, bufptr, sizeof (rdr_confirm_callback_reply_t)); bufptr += sizeof (confirm_callback_params_t); /* * Set fixed address labels by name */ params->confp = (struct cfga_confirm *) malloc(sizeof (struct cfga_confirm)); if (params->confp == NULL) { return (RDR_MEM_ALLOC); } /* set params->confp->confirm using memcpy */ (void) memcpy((void*)params->confp, &(confirm_callback_data.confirm_callback_id), sizeof (unsigned long)); params->confp->appdata_ptr = (void*)confirm_callback_data.appdata_ptr; params->response = confirm_callback_data.response; return (RDR_OK); } /* * pack_message_request: * * Handle packing a message callback request. */ static int pack_message_request(msg_callback_params_t *params, char **buf, int *buf_size) { int i; char *bufptr; rdr_msg_callback_t msg_callback_data; int message_strlen; int message_pad_sz; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Set variable length fields and make a call to partially * pack it. */ if (params->message != NULL) { message_strlen = strlen(params->message) + 1; message_pad_sz = RDR_ALIGN_64_BIT - (message_strlen % RDR_ALIGN_64_BIT); } else { message_strlen = 0; message_pad_sz = 0; } /* * Collect size info specific to the message callback request * message and allocate a buffer */ *buf_size = sizeof (rdr_msg_callback_t); *buf_size += message_strlen; *buf_size += message_pad_sz; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name */ if (params->msgp != NULL) { msg_callback_data.msg_callback_id = (unsigned long)params->msgp->message_routine; msg_callback_data.appdata_ptr = (unsigned long)params->msgp->appdata_ptr; } else { msg_callback_data.msg_callback_id = 0; msg_callback_data.appdata_ptr = 0; } msg_callback_data.message_size = message_strlen + message_pad_sz; /* * Set variable information using memcpy */ bufptr = *buf; (void) memcpy(bufptr, &msg_callback_data, sizeof (rdr_msg_callback_t)); bufptr += sizeof (rdr_msg_callback_t); if (params->message != NULL) { (void) memcpy(bufptr, params->message, message_strlen); bufptr += message_strlen; for (i = 0; i < message_pad_sz; i++) { bufptr[i] = 0; } bufptr += message_pad_sz; } return (RDR_OK); } /* * unpack_message_request: * * Handle unpacking a message callback request. */ static int unpack_message_request(msg_callback_params_t *params, const char *buf) { char *bufptr; rdr_msg_callback_t msg_callback_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&msg_callback_data, bufptr, sizeof (rdr_msg_callback_t)); bufptr += sizeof (rdr_msg_callback_t); /* * handle getting the message text */ if (get_string_from_buf(&(params->message), msg_callback_data.message_size, bufptr)) { return (RDR_ERROR); } bufptr += msg_callback_data.message_size; /* * Set fixed address labels by name */ params->msgp = (struct cfga_msg *)malloc(sizeof (struct cfga_msg)); if (params->msgp == NULL) { return (RDR_MEM_ALLOC); } /* set params->msgp->message_routine using memcpy */ (void) memcpy((void*)params->msgp, &(msg_callback_data.msg_callback_id), sizeof (unsigned long)); params->msgp->appdata_ptr = (void*)msg_callback_data.appdata_ptr; return (RDR_OK); } /* * pack_rsrc_info_request: * * Handle packing a resource info request. */ static int pack_rsrc_info_request(rsrc_info_params_t *params, char **buf, int *buf_size) { char *bufptr; rdr_rsrc_info_t rsrc_info_data; rdr_variable_message_info_t var_msg_info; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); /* * Set variable length fields and make a call to partially * pack it. */ if (pack_ap_ids(params->num_ap_ids, params->ap_ids, &var_msg_info)) { cleanup_variable_ap_id_info(&var_msg_info); return (RDR_ERROR); } /* * Collect size info specific to the resource info request * message and allocate a buffer. */ *buf_size = sizeof (rdr_rsrc_info_t); *buf_size += var_msg_info.ap_id_int_size; *buf_size += var_msg_info.ap_id_char_size; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name. */ rsrc_info_data.num_ap_ids = params->num_ap_ids; rsrc_info_data.ap_id_char_size = var_msg_info.ap_id_char_size; rsrc_info_data.flags = params->flags; /* * Set variable information using memcpy. */ bufptr = *buf; (void) memcpy(bufptr, &rsrc_info_data, sizeof (rdr_rsrc_info_t)); bufptr += sizeof (rdr_rsrc_info_t); if (var_msg_info.ap_id_sizes != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_sizes, var_msg_info.ap_id_int_size); bufptr += var_msg_info.ap_id_int_size; } if (var_msg_info.ap_id_chars != NULL) { (void) memcpy(bufptr, var_msg_info.ap_id_chars, var_msg_info.ap_id_char_size); bufptr += var_msg_info.ap_id_char_size; } cleanup_variable_ap_id_info(&var_msg_info); return (RDR_OK); } /* * unpack_rsrc_info_request: * * Handle unpacking a resource info request message. */ static int unpack_rsrc_info_request(rsrc_info_params_t *params, const char *buf) { char *bufptr; rdr_variable_message_info_t var_msg_info; rdr_rsrc_info_t rsrc_info_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } (void) memset(&var_msg_info, 0, sizeof (rdr_variable_message_info_t)); bufptr = (char *)buf; (void) memcpy(&rsrc_info_data, bufptr, sizeof (rdr_rsrc_info_t)); bufptr += sizeof (rdr_rsrc_info_t); /* * Handle getting the ap_ids. */ var_msg_info.ap_id_char_size = rsrc_info_data.ap_id_char_size; if (get_ap_ids_from_buf(&(params->ap_ids), rsrc_info_data.num_ap_ids, &var_msg_info, bufptr)) { return (RDR_ERROR); } bufptr += var_msg_info.ap_id_int_size; bufptr += var_msg_info.ap_id_char_size; /* * Set fixed address labels by name. */ params->num_ap_ids = rsrc_info_data.num_ap_ids; params->flags = rsrc_info_data.flags; return (RDR_OK); } /* * pack_rsrc_info_reply: * * Handle packing a resource info reply message. */ static int pack_rsrc_info_reply(rsrc_info_params_t *params, char **buf, int *buf_size, int encoding) { char *bufptr; rdr_rsrc_info_reply_t rsrc_info_data; int pack_status; caddr_t rsrc_info_bufp = NULL; size_t rsrc_info_size; if ((params == NULL) || (buf == NULL) || (buf_size == NULL)) { return (RDR_ERROR); } /* * Pack snapshot handle data. */ pack_status = ri_pack(params->hdl, &rsrc_info_bufp, &rsrc_info_size, encoding); if (pack_status != 0) { return (RDR_ERROR); } /* * Collect size info specific to the rsrc_info reply message * and allocate a buffer. */ *buf_size = sizeof (rdr_rsrc_info_reply_t); *buf_size += rsrc_info_size; *buf = (char *)malloc(*buf_size); if (*buf == NULL) { free(rsrc_info_bufp); return (RDR_MEM_ALLOC); } /* * Set fixed address labels by name. */ rsrc_info_data.packed_hdl_size = rsrc_info_size; /* * Set variable information using memcpy. */ bufptr = *buf; (void) memcpy(bufptr, &rsrc_info_data, sizeof (rdr_rsrc_info_reply_t)); bufptr += sizeof (rdr_rsrc_info_reply_t); if (rsrc_info_bufp) { (void) memcpy(bufptr, rsrc_info_bufp, rsrc_info_size); free(rsrc_info_bufp); } return (RDR_OK); } /* * unpack_rsrc_info_reply: * * Handle unpacking a resource info reply message. */ static int unpack_rsrc_info_reply(rsrc_info_params_t *params, const char *buf) { int unpack_status; char *bufptr; rdr_rsrc_info_reply_t rsrc_info_data; if ((params == NULL) || (buf == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; (void) memcpy(&rsrc_info_data, bufptr, sizeof (rdr_rsrc_info_reply_t)); bufptr += sizeof (rdr_rsrc_info_reply_t); /* * Unpack buf into resource info handle. */ unpack_status = ri_unpack(bufptr, rsrc_info_data.packed_hdl_size, ¶ms->hdl); return ((unpack_status == 0) ? RDR_OK : RDR_ERROR); } /* * pack_ap_ids: * * Pack a list of attachment point identifiers into a single buffer. * This buffer is stored in the specified rdr_variable_message_info_t * and is padded to be 64-bit aligned. */ static int pack_ap_ids(int num_ap_ids, char *const *ap_ids, rdr_variable_message_info_t *var_msg_info) { int i; int ap_id_pad_sz; char *bufptr; if (var_msg_info == NULL) { return (RDR_ERROR); } /* * NULL is a valid value for ap_ids in the list_ext * case. For list_ext, no specified attachment points * indicates that _all_ attachment points should be * displayed. However, if ap_ids is NULL, num_ap_ids * should be 0. */ if ((ap_ids == NULL) && (num_ap_ids != 0)) { num_ap_ids = 0; } var_msg_info->ap_id_int_size = sizeof (int) * num_ap_ids; if (num_ap_ids > 0) { var_msg_info->ap_id_sizes = (int *)malloc(sizeof (int) * var_msg_info->ap_id_int_size); if (var_msg_info->ap_id_sizes == NULL) { return (RDR_MEM_ALLOC); } } for (i = 0; i < num_ap_ids; i++) { if (ap_ids[i] != NULL) { var_msg_info->ap_id_sizes[i] = strlen(ap_ids[i]) + 1; var_msg_info->ap_id_char_size += var_msg_info->ap_id_sizes[i]; } } if (var_msg_info->ap_id_char_size > 0) { ap_id_pad_sz = RDR_ALIGN_64_BIT - (var_msg_info->ap_id_char_size % RDR_ALIGN_64_BIT); var_msg_info->ap_id_char_size += ap_id_pad_sz; var_msg_info->ap_id_chars = (char *) malloc(var_msg_info->ap_id_char_size); if (var_msg_info->ap_id_chars == NULL) { return (RDR_MEM_ALLOC); } bufptr = var_msg_info->ap_id_chars; for (i = 0; i < num_ap_ids; i++) { (void) memcpy(bufptr, ap_ids[i], var_msg_info->ap_id_sizes[i]); bufptr += var_msg_info->ap_id_sizes[i]; } for (i = 0; i < ap_id_pad_sz; i++) { bufptr[i] = 0; } } else { ap_id_pad_sz = 0; } return (RDR_OK); } /* * unpack_ap_ids: * * Unpack a buffer containing a concatenation of a list of * attachment point identifiers. The resulting list of strings * are stored in an array in the specified rdr_variable_message_info_t. */ static int unpack_ap_ids(int num_ap_ids, char **ap_ids, const char *buf, rdr_variable_message_info_t *var_msg_info) { int i; int ap_id_size; int chars_copied; char *bufptr; if ((ap_ids == NULL) || (buf == NULL) || (var_msg_info == NULL)) { return (RDR_ERROR); } bufptr = (char *)buf; var_msg_info->ap_id_int_size = sizeof (int) * num_ap_ids; if (num_ap_ids > 0) { var_msg_info->ap_id_sizes = (int *) malloc(sizeof (int) * var_msg_info->ap_id_int_size); if (var_msg_info->ap_id_sizes == NULL) { return (RDR_MEM_ALLOC); } (void) memcpy(var_msg_info->ap_id_sizes, bufptr, var_msg_info->ap_id_int_size); } bufptr += var_msg_info->ap_id_int_size; chars_copied = 0; for (i = 0; i < num_ap_ids; i++) { ap_id_size = var_msg_info->ap_id_sizes[i]; if (ap_id_size <= 0) { continue; } if ((chars_copied + ap_id_size) > var_msg_info->ap_id_char_size) { return (RDR_ERROR); } ap_ids[i] = (char *)malloc(ap_id_size); if (ap_ids[i] == NULL) { return (RDR_MEM_ALLOC); } (void) memcpy(ap_ids[i], bufptr, ap_id_size); bufptr += ap_id_size; chars_copied += ap_id_size; } return (RDR_OK); } /* * find_options_sizes: * * Determine the size of a specified option string. The information * is stored in the specified rdr_variable_message_info_t. */ static int find_options_sizes(char *options, rdr_variable_message_info_t *var_msg_info) { if (var_msg_info == NULL) { return (RDR_ERROR); } if (options != NULL) { var_msg_info->options_strlen = strlen(options) + 1; var_msg_info->options_pad_sz = RDR_ALIGN_64_BIT - (var_msg_info->options_strlen % RDR_ALIGN_64_BIT); } else { var_msg_info->options_strlen = 0; var_msg_info->options_pad_sz = 0; } return (RDR_OK); } /* * find_listopts_sizes: * * Determine the size of a specified list option string. The information * is stored in the specified rdr_variable_message_info_t. */ static int find_listopts_sizes(char *listopts, rdr_variable_message_info_t *var_msg_info) { if (var_msg_info == NULL) { return (RDR_ERROR); } if (listopts != NULL) { var_msg_info->listopts_strlen = strlen(listopts) + 1; var_msg_info->listopts_pad_sz = RDR_ALIGN_64_BIT - (var_msg_info->listopts_strlen % RDR_ALIGN_64_BIT); } else { var_msg_info->listopts_strlen = 0; var_msg_info->listopts_pad_sz = 0; } return (RDR_OK); } /* * find_function_size: * * Determine the size of a specified private function string. The * information is stored in the specified rdr_variable_message_info_t. */ static int find_function_sizes(char *function, rdr_variable_message_info_t *var_msg_info) { if (var_msg_info == NULL) { return (RDR_ERROR); } if (function != NULL) { var_msg_info->function_strlen = strlen(function) + 1; var_msg_info->function_pad_sz = RDR_ALIGN_64_BIT - (var_msg_info->function_strlen % RDR_ALIGN_64_BIT); } else { var_msg_info->function_strlen = 0; var_msg_info->function_pad_sz = 0; } return (RDR_OK); } /* * find_errstring_sizes: * * Determine the size of a specified error string. The information * is stored in the specified rdr_variable_message_info_t. */ static int find_errstring_sizes(char **errstring, rdr_variable_message_info_t *var_msg_info) { if ((errstring != NULL) && (*errstring != NULL)) { var_msg_info->errstring_strlen = strlen(*errstring) + 1; var_msg_info->errstring_pad_sz = RDR_ALIGN_64_BIT - (var_msg_info->errstring_strlen % RDR_ALIGN_64_BIT); } else { var_msg_info->errstring_strlen = 0; var_msg_info->errstring_pad_sz = 0; } return (RDR_OK); } /* * get_ap_ids_from_buf: * * Unpack a buffer containing a concatenation of a list of attachment * point identifiers. An appropriately sized buffer is allocated and * the resulting list of strings are stored in an array in the specified * rdr_variable_message_info_t. */ static int get_ap_ids_from_buf(char ***ap_id_ptr, int num_ap_ids, rdr_variable_message_info_t *var_msg_info, const char *buf) { if ((ap_id_ptr == NULL) || (buf == NULL) || (var_msg_info == NULL)) { return (RDR_ERROR); } if (num_ap_ids > 0) { *ap_id_ptr = (char **)malloc(sizeof (char *) * num_ap_ids); if (*ap_id_ptr == NULL) { return (RDR_MEM_ALLOC); } if (unpack_ap_ids(num_ap_ids, *ap_id_ptr, buf, var_msg_info)) { cleanup_variable_ap_id_info(var_msg_info); return (RDR_ERROR); } } else if (num_ap_ids < 0) { return (RDR_ERROR); } cleanup_variable_ap_id_info(var_msg_info); return (RDR_OK); } /* * get_string_from_buf: * * Copy a string to a new buffer. Memory is allocated for the * new buffer and the original string is copied to the new buffer. * This is primarily used when a string is located in a packed * buffer that will eventually get deallocated. */ static int get_string_from_buf(char **stringptr, int strsize, const char *buf) { if (buf == NULL) { return (RDR_ERROR); } /* * A stringptr of NULL is a valid value. The errstring param * in an rconfig_xxx call is valid and is passed to this * function. For example, see errstring in the call to this * function in unpack_change_state_reply. */ if (stringptr != NULL) { if (strsize > 0) { *stringptr = (char *)malloc(strsize); if (*stringptr == NULL) { return (RDR_MEM_ALLOC); } (void) memcpy(*stringptr, buf, strsize); } else if (strsize == 0) { *stringptr = NULL; } else if (strsize < 0) { *stringptr = NULL; return (RDR_ERROR); } } return (RDR_OK); } /* * cleanup_ap_ids: * * Deallocate the specified array of attachment point identifiers. */ static int cleanup_ap_ids(int num_ap_ids, char ** ap_ids) { int i; if (ap_ids == NULL) { return (RDR_ERROR); } for (i = 0; i < num_ap_ids; i++) { if (ap_ids[i] != NULL) { free((void *)ap_ids[i]); ap_ids[i] = NULL; } } return (RDR_OK); } /* * cleanup_errstring: * * Deallocate the specified error string. */ static int cleanup_errstring(char **errstring) { if (errstring) { if (*errstring) { free((void *)*errstring); } free((void *)errstring); errstring = NULL; } return (RDR_OK); } /* * cleanup_variable_ap_id_info: * * Deallocate the ap_id information from the specified * rdr_variable_message_info_t. */ static void cleanup_variable_ap_id_info(rdr_variable_message_info_t *var_msg_info) { if (var_msg_info != NULL) { if (var_msg_info->ap_id_sizes != NULL) { free((void *)var_msg_info->ap_id_sizes); var_msg_info->ap_id_sizes = NULL; } if (var_msg_info->ap_id_chars != NULL) { free((void *)var_msg_info->ap_id_chars); var_msg_info->ap_id_chars = NULL; } } } /* * load_libdscp: * * Try to dynamically link with libdscp. * * Returns: 0 if libdscp not available, * 1 if libdscp is available. */ static int load_libdscp(libdscp_t *libdscp) { int len; void *lib; static char platform[100]; static char pathname[MAXPATHLEN]; /* * Only try to load libdscp once. Use the saved * status in the libdscp interface to know the * results of previous attempts. */ if (libdscp->status == LIBDSCP_AVAILABLE) { return (1); } if (libdscp->status == LIBDSCP_UNAVAILABLE) { return (0); } /* * Construct a platform specific pathname for libdscp. */ len = sysinfo(SI_PLATFORM, platform, sizeof (platform)); if ((len < 0) || (len > sizeof (platform))) { return (0); } len = snprintf(pathname, MAXPATHLEN, LIBDSCP_PATH, platform); if (len >= MAXPATHLEN) { libdscp->status = LIBDSCP_UNAVAILABLE; return (0); } /* * Try dynamically loading libdscp. */ if ((lib = dlopen(pathname, RTLD_LAZY)) == NULL) { libdscp->status = LIBDSCP_UNAVAILABLE; return (0); } /* * Try to resolve all the symbols. */ libdscp->bind = (int (*)(int, int, int))dlsym(lib, LIBDSCP_BIND); libdscp->secure = (int (*)(int, int))dlsym(lib, LIBDSCP_SECURE); libdscp->auth = (int (*)(int, struct sockaddr *, int))dlsym(lib, LIBDSCP_AUTH); if ((libdscp->bind == NULL) || (libdscp->secure == NULL) || (libdscp->auth == NULL)) { (void) dlclose(lib); libdscp->status = LIBDSCP_UNAVAILABLE; return (0); } /* * Success. * Update the status to indicate libdscp is available. */ libdscp->status = LIBDSCP_AVAILABLE; return (1); }