17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 2261961e0fSrobinson 237c478bd9Sstevel@tonic-gate /* 247c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 257c478bd9Sstevel@tonic-gate * Use is subject to license terms. 267c478bd9Sstevel@tonic-gate */ 275131caa1SMarcel Telka /* 285131caa1SMarcel Telka * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 295131caa1SMarcel Telka */ 305131caa1SMarcel Telka 317c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 327c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 337c478bd9Sstevel@tonic-gate /* 347c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 357c478bd9Sstevel@tonic-gate * 4.3 BSD under license from the Regents of the University of 367c478bd9Sstevel@tonic-gate * California. 377c478bd9Sstevel@tonic-gate */ 38*b7ab9363SShruti Sampat /* 39*b7ab9363SShruti Sampat * Copyright 2014 Shruti V Sampat <shrutisampat@gmail.com> 40*b7ab9363SShruti Sampat */ 417c478bd9Sstevel@tonic-gate 427c478bd9Sstevel@tonic-gate /* 437c478bd9Sstevel@tonic-gate * Implements a connectionless client side RPC. 447c478bd9Sstevel@tonic-gate */ 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate #include "mt.h" 477c478bd9Sstevel@tonic-gate #include "rpc_mt.h" 487c478bd9Sstevel@tonic-gate #include <assert.h> 497c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 507c478bd9Sstevel@tonic-gate #include <errno.h> 517c478bd9Sstevel@tonic-gate #include <sys/poll.h> 527c478bd9Sstevel@tonic-gate #include <syslog.h> 537c478bd9Sstevel@tonic-gate #include <sys/types.h> 547c478bd9Sstevel@tonic-gate #include <sys/kstat.h> 557c478bd9Sstevel@tonic-gate #include <sys/time.h> 567c478bd9Sstevel@tonic-gate #include <stdlib.h> 577c478bd9Sstevel@tonic-gate #include <unistd.h> 587c478bd9Sstevel@tonic-gate #include <sys/types.h> 597c478bd9Sstevel@tonic-gate #include <sys/stat.h> 607c478bd9Sstevel@tonic-gate #include <strings.h> 61*b7ab9363SShruti Sampat #include <note.h> 627c478bd9Sstevel@tonic-gate 6361961e0fSrobinson extern int __rpc_timeval_to_msec(struct timeval *); 6461961e0fSrobinson extern bool_t xdr_opaque_auth(XDR *, struct opaque_auth *); 6561961e0fSrobinson extern bool_t __rpc_gss_wrap(AUTH *, char *, uint_t, XDR *, bool_t (*)(), 6661961e0fSrobinson caddr_t); 6761961e0fSrobinson extern bool_t __rpc_gss_unwrap(AUTH *, XDR *, bool_t (*)(), caddr_t); 687c478bd9Sstevel@tonic-gate 6961961e0fSrobinson 7061961e0fSrobinson static struct clnt_ops *clnt_dg_ops(void); 7161961e0fSrobinson static bool_t time_not_ok(struct timeval *); 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate /* 747c478bd9Sstevel@tonic-gate * This machinery implements per-fd locks for MT-safety. It is not 757c478bd9Sstevel@tonic-gate * sufficient to do per-CLIENT handle locks for MT-safety because a 767c478bd9Sstevel@tonic-gate * user may create more than one CLIENT handle with the same fd behind 777c478bd9Sstevel@tonic-gate * it. 787c478bd9Sstevel@tonic-gate * 797c478bd9Sstevel@tonic-gate * The current implementation holds locks across the entire RPC and reply, 807c478bd9Sstevel@tonic-gate * including retransmissions. Yes, this is silly, and as soon as this 817c478bd9Sstevel@tonic-gate * code is proven to work, this should be the first thing fixed. One step 827c478bd9Sstevel@tonic-gate * at a time. 837c478bd9Sstevel@tonic-gate */ 847c478bd9Sstevel@tonic-gate 857c478bd9Sstevel@tonic-gate /* 867c478bd9Sstevel@tonic-gate * FD Lock handle used by various MT sync. routines 877c478bd9Sstevel@tonic-gate */ 887c478bd9Sstevel@tonic-gate static mutex_t dgtbl_lock = DEFAULTMUTEX; 897c478bd9Sstevel@tonic-gate static void *dgtbl = NULL; 907c478bd9Sstevel@tonic-gate 917c478bd9Sstevel@tonic-gate static const char mem_err_clnt_dg[] = "clnt_dg_create: out of memory"; 927c478bd9Sstevel@tonic-gate 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate #define MCALL_MSG_SIZE 24 957c478bd9Sstevel@tonic-gate 967c478bd9Sstevel@tonic-gate /* 977c478bd9Sstevel@tonic-gate * Private data kept per client handle 987c478bd9Sstevel@tonic-gate */ 997c478bd9Sstevel@tonic-gate struct cu_data { 1007c478bd9Sstevel@tonic-gate int cu_fd; /* connections fd */ 1017c478bd9Sstevel@tonic-gate bool_t cu_closeit; /* opened by library */ 1027c478bd9Sstevel@tonic-gate struct netbuf cu_raddr; /* remote address */ 1037c478bd9Sstevel@tonic-gate struct timeval cu_wait; /* retransmit interval */ 1047c478bd9Sstevel@tonic-gate struct timeval cu_total; /* total time for the call */ 1057c478bd9Sstevel@tonic-gate struct rpc_err cu_error; 1067c478bd9Sstevel@tonic-gate struct t_unitdata *cu_tr_data; 1077c478bd9Sstevel@tonic-gate XDR cu_outxdrs; 1087c478bd9Sstevel@tonic-gate char *cu_outbuf_start; 1097c478bd9Sstevel@tonic-gate char cu_outbuf[MCALL_MSG_SIZE]; 1107c478bd9Sstevel@tonic-gate uint_t cu_xdrpos; 1117c478bd9Sstevel@tonic-gate uint_t cu_sendsz; /* send size */ 1127c478bd9Sstevel@tonic-gate uint_t cu_recvsz; /* recv size */ 1137c478bd9Sstevel@tonic-gate struct pollfd pfdp; 1147c478bd9Sstevel@tonic-gate char cu_inbuf[1]; 1157c478bd9Sstevel@tonic-gate }; 1167c478bd9Sstevel@tonic-gate 1177c478bd9Sstevel@tonic-gate static int _rcv_unitdata_err(struct cu_data *cu); 1187c478bd9Sstevel@tonic-gate 1197c478bd9Sstevel@tonic-gate /* 1207c478bd9Sstevel@tonic-gate * Connection less client creation returns with client handle parameters. 1217c478bd9Sstevel@tonic-gate * Default options are set, which the user can change using clnt_control(). 1227c478bd9Sstevel@tonic-gate * fd should be open and bound. 1237c478bd9Sstevel@tonic-gate * NB: The rpch->cl_auth is initialized to null authentication. 1247c478bd9Sstevel@tonic-gate * Caller may wish to set this something more useful. 1257c478bd9Sstevel@tonic-gate * 1267c478bd9Sstevel@tonic-gate * sendsz and recvsz are the maximum allowable packet sizes that can be 1277c478bd9Sstevel@tonic-gate * sent and received. Normally they are the same, but they can be 1287c478bd9Sstevel@tonic-gate * changed to improve the program efficiency and buffer allocation. 1297c478bd9Sstevel@tonic-gate * If they are 0, use the transport default. 1307c478bd9Sstevel@tonic-gate * 1317c478bd9Sstevel@tonic-gate * If svcaddr is NULL, returns NULL. 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate CLIENT * 13461961e0fSrobinson clnt_dg_create(const int fd, struct netbuf *svcaddr, const rpcprog_t program, 13561961e0fSrobinson const rpcvers_t version, const uint_t sendsz, const uint_t recvsz) 1367c478bd9Sstevel@tonic-gate { 1377c478bd9Sstevel@tonic-gate CLIENT *cl = NULL; /* client handle */ 1387c478bd9Sstevel@tonic-gate struct cu_data *cu = NULL; /* private data */ 1397c478bd9Sstevel@tonic-gate struct t_unitdata *tr_data; 1407c478bd9Sstevel@tonic-gate struct t_info tinfo; 1417c478bd9Sstevel@tonic-gate struct timeval now; 1427c478bd9Sstevel@tonic-gate struct rpc_msg call_msg; 14361961e0fSrobinson uint_t ssz; 14461961e0fSrobinson uint_t rsz; 1457c478bd9Sstevel@tonic-gate 1467c478bd9Sstevel@tonic-gate sig_mutex_lock(&dgtbl_lock); 1477c478bd9Sstevel@tonic-gate if ((dgtbl == NULL) && ((dgtbl = rpc_fd_init()) == NULL)) { 1487c478bd9Sstevel@tonic-gate sig_mutex_unlock(&dgtbl_lock); 1497c478bd9Sstevel@tonic-gate goto err1; 1507c478bd9Sstevel@tonic-gate } 1517c478bd9Sstevel@tonic-gate sig_mutex_unlock(&dgtbl_lock); 1527c478bd9Sstevel@tonic-gate 15361961e0fSrobinson if (svcaddr == NULL) { 1547c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_UNKNOWNADDR; 15561961e0fSrobinson return (NULL); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate if (t_getinfo(fd, &tinfo) == -1) { 1587c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_TLIERROR; 1597c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = 0; 1607c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_terrno = t_errno; 16161961e0fSrobinson return (NULL); 1627c478bd9Sstevel@tonic-gate } 1637c478bd9Sstevel@tonic-gate /* 1647c478bd9Sstevel@tonic-gate * Setup to rcv datagram error, we ignore any errors returned from 1657c478bd9Sstevel@tonic-gate * __rpc_tli_set_options() as SO_DGRAM_ERRIND is only relevant to 1667c478bd9Sstevel@tonic-gate * udp/udp6 transports and this point in the code we only know that 1677c478bd9Sstevel@tonic-gate * we are using a connection less transport. 1687c478bd9Sstevel@tonic-gate */ 1697c478bd9Sstevel@tonic-gate if (tinfo.servtype == T_CLTS) 1707c478bd9Sstevel@tonic-gate (void) __rpc_tli_set_options(fd, SOL_SOCKET, SO_DGRAM_ERRIND, 1717c478bd9Sstevel@tonic-gate 1); 1727c478bd9Sstevel@tonic-gate /* 1737c478bd9Sstevel@tonic-gate * Find the receive and the send size 1747c478bd9Sstevel@tonic-gate */ 17561961e0fSrobinson ssz = __rpc_get_t_size((int)sendsz, tinfo.tsdu); 17661961e0fSrobinson rsz = __rpc_get_t_size((int)recvsz, tinfo.tsdu); 17761961e0fSrobinson if ((ssz == 0) || (rsz == 0)) { 1787c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_TLIERROR; /* XXX */ 1797c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = 0; 1807c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_terrno = 0; 18161961e0fSrobinson return (NULL); 1827c478bd9Sstevel@tonic-gate } 1837c478bd9Sstevel@tonic-gate 18461961e0fSrobinson if ((cl = malloc(sizeof (CLIENT))) == NULL) 1857c478bd9Sstevel@tonic-gate goto err1; 1867c478bd9Sstevel@tonic-gate /* 1877c478bd9Sstevel@tonic-gate * Should be multiple of 4 for XDR. 1887c478bd9Sstevel@tonic-gate */ 18961961e0fSrobinson ssz = ((ssz + 3) / 4) * 4; 19061961e0fSrobinson rsz = ((rsz + 3) / 4) * 4; 19161961e0fSrobinson cu = malloc(sizeof (*cu) + ssz + rsz); 19261961e0fSrobinson if (cu == NULL) 1937c478bd9Sstevel@tonic-gate goto err1; 19461961e0fSrobinson if ((cu->cu_raddr.buf = malloc(svcaddr->len)) == NULL) 1957c478bd9Sstevel@tonic-gate goto err1; 19661961e0fSrobinson (void) memcpy(cu->cu_raddr.buf, svcaddr->buf, (size_t)svcaddr->len); 1977c478bd9Sstevel@tonic-gate cu->cu_raddr.len = cu->cu_raddr.maxlen = svcaddr->len; 19861961e0fSrobinson cu->cu_outbuf_start = &cu->cu_inbuf[rsz]; 1997c478bd9Sstevel@tonic-gate /* Other values can also be set through clnt_control() */ 2007c478bd9Sstevel@tonic-gate cu->cu_wait.tv_sec = 15; /* heuristically chosen */ 2017c478bd9Sstevel@tonic-gate cu->cu_wait.tv_usec = 0; 2027c478bd9Sstevel@tonic-gate cu->cu_total.tv_sec = -1; 2037c478bd9Sstevel@tonic-gate cu->cu_total.tv_usec = -1; 20461961e0fSrobinson cu->cu_sendsz = ssz; 20561961e0fSrobinson cu->cu_recvsz = rsz; 20661961e0fSrobinson (void) gettimeofday(&now, NULL); 2077c478bd9Sstevel@tonic-gate call_msg.rm_xid = getpid() ^ now.tv_sec ^ now.tv_usec; 2087c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_prog = program; 2097c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_vers = version; 21061961e0fSrobinson xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, ssz, XDR_ENCODE); 2117c478bd9Sstevel@tonic-gate if (!xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 2127c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_CANTENCODEARGS; /* XXX */ 2137c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = 0; 2147c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_terrno = 0; 2157c478bd9Sstevel@tonic-gate goto err2; 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 2187c478bd9Sstevel@tonic-gate XDR_DESTROY(&(cu->cu_outxdrs)); 2195131caa1SMarcel Telka xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf_start, ssz, XDR_ENCODE); 2207c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 2215131caa1SMarcel Telka tr_data = (struct t_unitdata *)t_alloc(fd, T_UNITDATA, T_ADDR | T_OPT); 22261961e0fSrobinson if (tr_data == NULL) { 2237c478bd9Sstevel@tonic-gate goto err1; 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate tr_data->udata.maxlen = cu->cu_recvsz; 2267c478bd9Sstevel@tonic-gate tr_data->udata.buf = cu->cu_inbuf; 2277c478bd9Sstevel@tonic-gate cu->cu_tr_data = tr_data; 2287c478bd9Sstevel@tonic-gate 2297c478bd9Sstevel@tonic-gate /* 2307c478bd9Sstevel@tonic-gate * By default, closeit is always FALSE. It is users responsibility 2317c478bd9Sstevel@tonic-gate * to do a t_close on it, else the user may use clnt_control 2327c478bd9Sstevel@tonic-gate * to let clnt_destroy do it for him/her. 2337c478bd9Sstevel@tonic-gate */ 2347c478bd9Sstevel@tonic-gate cu->cu_closeit = FALSE; 2357c478bd9Sstevel@tonic-gate cu->cu_fd = fd; 2367c478bd9Sstevel@tonic-gate cl->cl_ops = clnt_dg_ops(); 2377c478bd9Sstevel@tonic-gate cl->cl_private = (caddr_t)cu; 2387c478bd9Sstevel@tonic-gate cl->cl_auth = authnone_create(); 23961961e0fSrobinson cl->cl_tp = NULL; 24061961e0fSrobinson cl->cl_netid = NULL; 2417c478bd9Sstevel@tonic-gate cu->pfdp.fd = cu->cu_fd; 2427c478bd9Sstevel@tonic-gate cu->pfdp.events = MASKVAL; 2437c478bd9Sstevel@tonic-gate return (cl); 2447c478bd9Sstevel@tonic-gate err1: 2457c478bd9Sstevel@tonic-gate (void) syslog(LOG_ERR, mem_err_clnt_dg); 2467c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 2477c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 2487c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_terrno = 0; 2497c478bd9Sstevel@tonic-gate err2: 2507c478bd9Sstevel@tonic-gate if (cl) { 25161961e0fSrobinson free(cl); 2527c478bd9Sstevel@tonic-gate if (cu) { 25361961e0fSrobinson free(cu->cu_raddr.buf); 25461961e0fSrobinson free(cu); 2557c478bd9Sstevel@tonic-gate } 2567c478bd9Sstevel@tonic-gate } 25761961e0fSrobinson return (NULL); 2587c478bd9Sstevel@tonic-gate } 2597c478bd9Sstevel@tonic-gate 2607c478bd9Sstevel@tonic-gate static enum clnt_stat 26161961e0fSrobinson clnt_dg_call(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp, 26261961e0fSrobinson xdrproc_t xresults, caddr_t resultsp, struct timeval utimeout) 2637c478bd9Sstevel@tonic-gate { 2647c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 2657c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 2667c478bd9Sstevel@tonic-gate XDR *xdrs; 2677c478bd9Sstevel@tonic-gate int outlen; 2687c478bd9Sstevel@tonic-gate struct rpc_msg reply_msg; 2697c478bd9Sstevel@tonic-gate XDR reply_xdrs; 2707c478bd9Sstevel@tonic-gate struct timeval time_waited; 2717c478bd9Sstevel@tonic-gate bool_t ok; 2727c478bd9Sstevel@tonic-gate int nrefreshes = 2; /* number of times to refresh cred */ 2737c478bd9Sstevel@tonic-gate struct timeval timeout; 2747c478bd9Sstevel@tonic-gate struct timeval retransmit_time; 2757c478bd9Sstevel@tonic-gate struct timeval poll_time; 2767c478bd9Sstevel@tonic-gate struct timeval startime, curtime; 2777c478bd9Sstevel@tonic-gate struct t_unitdata tu_data; 2787c478bd9Sstevel@tonic-gate int res; /* result of operations */ 2797c478bd9Sstevel@tonic-gate uint32_t x_id; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate if (rpc_fd_lock(dgtbl, cu->cu_fd)) { 2827c478bd9Sstevel@tonic-gate rpc_callerr.re_status = RPC_FAILED; 2837c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = errno; 2847c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 2857c478bd9Sstevel@tonic-gate return (RPC_FAILED); 2867c478bd9Sstevel@tonic-gate } 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate if (cu->cu_total.tv_usec == -1) { 2897c478bd9Sstevel@tonic-gate timeout = utimeout; /* use supplied timeout */ 2907c478bd9Sstevel@tonic-gate } else { 2917c478bd9Sstevel@tonic-gate timeout = cu->cu_total; /* use default timeout */ 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate time_waited.tv_sec = 0; 2957c478bd9Sstevel@tonic-gate time_waited.tv_usec = 0; 2967c478bd9Sstevel@tonic-gate retransmit_time = cu->cu_wait; 2977c478bd9Sstevel@tonic-gate 2987c478bd9Sstevel@tonic-gate tu_data.addr = cu->cu_raddr; 2997c478bd9Sstevel@tonic-gate 3007c478bd9Sstevel@tonic-gate call_again: 3017c478bd9Sstevel@tonic-gate xdrs = &(cu->cu_outxdrs); 3027c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 3037c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, 0); 3047c478bd9Sstevel@tonic-gate /* 3057c478bd9Sstevel@tonic-gate * Due to little endian byte order, it is necessary to convert to host 3067c478bd9Sstevel@tonic-gate * format before incrementing xid. 3077c478bd9Sstevel@tonic-gate */ 30861961e0fSrobinson /* LINTED pointer cast */ 3097c478bd9Sstevel@tonic-gate x_id = ntohl(*(uint32_t *)(cu->cu_outbuf)) + 1; /* set XID */ 31061961e0fSrobinson /* LINTED pointer cast */ 3117c478bd9Sstevel@tonic-gate *(uint32_t *)cu->cu_outbuf = htonl(x_id); 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 3147c478bd9Sstevel@tonic-gate if ((!XDR_PUTBYTES(xdrs, cu->cu_outbuf, cu->cu_xdrpos)) || 3157c478bd9Sstevel@tonic-gate (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 3167c478bd9Sstevel@tonic-gate (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || 3177c478bd9Sstevel@tonic-gate (!xargs(xdrs, argsp))) { 3187c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 3197c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTENCODEARGS); 3207c478bd9Sstevel@tonic-gate } 3217c478bd9Sstevel@tonic-gate } else { 3227c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 3237c478bd9Sstevel@tonic-gate uint32_t *u = (uint32_t *)&cu->cu_outbuf[cu->cu_xdrpos]; 3247c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(u, proc); 3257c478bd9Sstevel@tonic-gate if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outbuf, 3267c478bd9Sstevel@tonic-gate ((char *)u) - cu->cu_outbuf, xdrs, xargs, argsp)) { 3277c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 3287c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTENCODEARGS); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate } 3317c478bd9Sstevel@tonic-gate outlen = (int)XDR_GETPOS(xdrs); 3327c478bd9Sstevel@tonic-gate 3337c478bd9Sstevel@tonic-gate send_again: 3347c478bd9Sstevel@tonic-gate tu_data.udata.buf = cu->cu_outbuf_start; 3357c478bd9Sstevel@tonic-gate tu_data.udata.len = outlen; 3367c478bd9Sstevel@tonic-gate tu_data.opt.len = 0; 3377c478bd9Sstevel@tonic-gate if (t_sndudata(cu->cu_fd, &tu_data) == -1) { 3387c478bd9Sstevel@tonic-gate rpc_callerr.re_terrno = t_errno; 3397c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = errno; 3407c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 3417c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTSEND); 3427c478bd9Sstevel@tonic-gate } 3437c478bd9Sstevel@tonic-gate 3447c478bd9Sstevel@tonic-gate /* 3457c478bd9Sstevel@tonic-gate * Hack to provide rpc-based message passing 3467c478bd9Sstevel@tonic-gate */ 3477c478bd9Sstevel@tonic-gate if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 3487c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 3497c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_TIMEDOUT); 3507c478bd9Sstevel@tonic-gate } 3517c478bd9Sstevel@tonic-gate /* 3527c478bd9Sstevel@tonic-gate * sub-optimal code appears here because we have 3537c478bd9Sstevel@tonic-gate * some clock time to spare while the packets are in flight. 3547c478bd9Sstevel@tonic-gate * (We assume that this is actually only executed once.) 3557c478bd9Sstevel@tonic-gate */ 3567c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf = _null_auth; 3577c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.where = NULL; 3587c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.proc = xdr_void; 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * Set polling time so that we don't wait for 3627c478bd9Sstevel@tonic-gate * longer than specified by the total time to wait, 3637c478bd9Sstevel@tonic-gate * or the retransmit time. 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate poll_time.tv_sec = timeout.tv_sec - time_waited.tv_sec; 3667c478bd9Sstevel@tonic-gate poll_time.tv_usec = timeout.tv_usec - time_waited.tv_usec; 3677c478bd9Sstevel@tonic-gate while (poll_time.tv_usec < 0) { 3687c478bd9Sstevel@tonic-gate poll_time.tv_usec += 1000000; 3697c478bd9Sstevel@tonic-gate poll_time.tv_sec--; 3707c478bd9Sstevel@tonic-gate } 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate if (poll_time.tv_sec < 0 || (poll_time.tv_sec == 0 && 3737c478bd9Sstevel@tonic-gate poll_time.tv_usec == 0)) { 3747c478bd9Sstevel@tonic-gate /* 3757c478bd9Sstevel@tonic-gate * this could happen if time_waited >= timeout 3767c478bd9Sstevel@tonic-gate */ 3777c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 3787c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_TIMEDOUT); 3797c478bd9Sstevel@tonic-gate } 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate if (poll_time.tv_sec > retransmit_time.tv_sec || 3827c478bd9Sstevel@tonic-gate (poll_time.tv_sec == retransmit_time.tv_sec && 3837c478bd9Sstevel@tonic-gate poll_time.tv_usec > retransmit_time.tv_usec)) 3847c478bd9Sstevel@tonic-gate poll_time = retransmit_time; 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate for (;;) { 3887c478bd9Sstevel@tonic-gate 3897c478bd9Sstevel@tonic-gate (void) gettimeofday(&startime, NULL); 3907c478bd9Sstevel@tonic-gate 3917c478bd9Sstevel@tonic-gate switch (poll(&cu->pfdp, 1, 3927c478bd9Sstevel@tonic-gate __rpc_timeval_to_msec(&poll_time))) { 3937c478bd9Sstevel@tonic-gate case -1: 3947c478bd9Sstevel@tonic-gate if (errno != EINTR && errno != EAGAIN) { 3957c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = errno; 3967c478bd9Sstevel@tonic-gate rpc_callerr.re_terrno = 0; 3977c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 3987c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTRECV); 3997c478bd9Sstevel@tonic-gate } 4007c478bd9Sstevel@tonic-gate /*FALLTHROUGH*/ 4017c478bd9Sstevel@tonic-gate 4027c478bd9Sstevel@tonic-gate case 0: 4037c478bd9Sstevel@tonic-gate /* 4047c478bd9Sstevel@tonic-gate * update time waited 4057c478bd9Sstevel@tonic-gate */ 4067c478bd9Sstevel@tonic-gate timeout: (void) gettimeofday(&curtime, NULL); 4077c478bd9Sstevel@tonic-gate time_waited.tv_sec += curtime.tv_sec - startime.tv_sec; 4087c478bd9Sstevel@tonic-gate time_waited.tv_usec += curtime.tv_usec - 4097c478bd9Sstevel@tonic-gate startime.tv_usec; 4107c478bd9Sstevel@tonic-gate while (time_waited.tv_usec >= 1000000) { 4117c478bd9Sstevel@tonic-gate time_waited.tv_usec -= 1000000; 4127c478bd9Sstevel@tonic-gate time_waited.tv_sec++; 4137c478bd9Sstevel@tonic-gate } 4147c478bd9Sstevel@tonic-gate while (time_waited.tv_usec < 0) { 4157c478bd9Sstevel@tonic-gate time_waited.tv_usec += 1000000; 4167c478bd9Sstevel@tonic-gate time_waited.tv_sec--; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate /* 4207c478bd9Sstevel@tonic-gate * decrement time left to poll by same amount 4217c478bd9Sstevel@tonic-gate */ 4227c478bd9Sstevel@tonic-gate poll_time.tv_sec -= curtime.tv_sec - startime.tv_sec; 4237c478bd9Sstevel@tonic-gate poll_time.tv_usec -= curtime.tv_usec - startime.tv_usec; 4247c478bd9Sstevel@tonic-gate while (poll_time.tv_usec >= 1000000) { 4257c478bd9Sstevel@tonic-gate poll_time.tv_usec -= 1000000; 4267c478bd9Sstevel@tonic-gate poll_time.tv_sec++; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate while (poll_time.tv_usec < 0) { 4297c478bd9Sstevel@tonic-gate poll_time.tv_usec += 1000000; 4307c478bd9Sstevel@tonic-gate poll_time.tv_sec--; 4317c478bd9Sstevel@tonic-gate } 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate /* 4347c478bd9Sstevel@tonic-gate * if there's time left to poll, poll again 4357c478bd9Sstevel@tonic-gate */ 4367c478bd9Sstevel@tonic-gate if (poll_time.tv_sec > 0 || 4375131caa1SMarcel Telka (poll_time.tv_sec == 0 && poll_time.tv_usec > 0)) 4387c478bd9Sstevel@tonic-gate continue; 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate /* 4417c478bd9Sstevel@tonic-gate * if there's more time left, retransmit; 4427c478bd9Sstevel@tonic-gate * otherwise, return timeout error 4437c478bd9Sstevel@tonic-gate */ 4447c478bd9Sstevel@tonic-gate if (time_waited.tv_sec < timeout.tv_sec || 4457c478bd9Sstevel@tonic-gate (time_waited.tv_sec == timeout.tv_sec && 4467c478bd9Sstevel@tonic-gate time_waited.tv_usec < timeout.tv_usec)) { 4477c478bd9Sstevel@tonic-gate /* 4487c478bd9Sstevel@tonic-gate * update retransmit_time 4497c478bd9Sstevel@tonic-gate */ 4507c478bd9Sstevel@tonic-gate retransmit_time.tv_usec *= 2; 4517c478bd9Sstevel@tonic-gate retransmit_time.tv_sec *= 2; 4527c478bd9Sstevel@tonic-gate while (retransmit_time.tv_usec >= 1000000) { 4537c478bd9Sstevel@tonic-gate retransmit_time.tv_usec -= 1000000; 4547c478bd9Sstevel@tonic-gate retransmit_time.tv_sec++; 4557c478bd9Sstevel@tonic-gate } 4567c478bd9Sstevel@tonic-gate if (retransmit_time.tv_sec >= RPC_MAX_BACKOFF) { 4577c478bd9Sstevel@tonic-gate retransmit_time.tv_sec = 4587c478bd9Sstevel@tonic-gate RPC_MAX_BACKOFF; 4597c478bd9Sstevel@tonic-gate retransmit_time.tv_usec = 0; 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate /* 4627c478bd9Sstevel@tonic-gate * redo AUTH_MARSHAL if AUTH_DES or RPCSEC_GSS. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate if (cl->cl_auth->ah_cred.oa_flavor == 4657c478bd9Sstevel@tonic-gate AUTH_DES || 4667c478bd9Sstevel@tonic-gate cl->cl_auth->ah_cred.oa_flavor == 4677c478bd9Sstevel@tonic-gate RPCSEC_GSS) 4687c478bd9Sstevel@tonic-gate goto call_again; 4697c478bd9Sstevel@tonic-gate else 4707c478bd9Sstevel@tonic-gate goto send_again; 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 4737c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_TIMEDOUT); 4747c478bd9Sstevel@tonic-gate 4757c478bd9Sstevel@tonic-gate default: 4767c478bd9Sstevel@tonic-gate break; 4777c478bd9Sstevel@tonic-gate } 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate if (cu->pfdp.revents & POLLNVAL || (cu->pfdp.revents == 0)) { 4807c478bd9Sstevel@tonic-gate rpc_callerr.re_status = RPC_CANTRECV; 4817c478bd9Sstevel@tonic-gate /* 4827c478bd9Sstevel@tonic-gate * Note: we're faking errno here because we 4837c478bd9Sstevel@tonic-gate * previously would have expected select() to 4847c478bd9Sstevel@tonic-gate * return -1 with errno EBADF. Poll(BA_OS) 4857c478bd9Sstevel@tonic-gate * returns 0 and sets the POLLNVAL revents flag 4867c478bd9Sstevel@tonic-gate * instead. 4877c478bd9Sstevel@tonic-gate */ 4887c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = errno = EBADF; 4897c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 4907c478bd9Sstevel@tonic-gate return (-1); 4917c478bd9Sstevel@tonic-gate } 4927c478bd9Sstevel@tonic-gate 4937c478bd9Sstevel@tonic-gate /* We have some data now */ 4947c478bd9Sstevel@tonic-gate do { 4957c478bd9Sstevel@tonic-gate int moreflag; /* flag indicating more data */ 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate moreflag = 0; 4987c478bd9Sstevel@tonic-gate 4997c478bd9Sstevel@tonic-gate res = t_rcvudata(cu->cu_fd, cu->cu_tr_data, &moreflag); 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate if (moreflag & T_MORE) { 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * Drop this packet. I aint got any 5047c478bd9Sstevel@tonic-gate * more space. 5057c478bd9Sstevel@tonic-gate */ 5067c478bd9Sstevel@tonic-gate res = -1; 5077c478bd9Sstevel@tonic-gate /* I should not really be doing this */ 5087c478bd9Sstevel@tonic-gate errno = 0; 5097c478bd9Sstevel@tonic-gate /* 5107c478bd9Sstevel@tonic-gate * XXX: Not really Buffer overflow in the 5117c478bd9Sstevel@tonic-gate * sense of TLI. 5127c478bd9Sstevel@tonic-gate */ 5137c478bd9Sstevel@tonic-gate t_errno = TBUFOVFLW; 5147c478bd9Sstevel@tonic-gate } 5157c478bd9Sstevel@tonic-gate } while (res < 0 && (t_errno == TSYSERR && errno == EINTR)); 5167c478bd9Sstevel@tonic-gate if (res < 0) { 5177c478bd9Sstevel@tonic-gate int err, errnoflag = FALSE; 5187c478bd9Sstevel@tonic-gate #ifdef sun 5197c478bd9Sstevel@tonic-gate if (t_errno == TSYSERR && errno == EWOULDBLOCK) 5207c478bd9Sstevel@tonic-gate #else 5217c478bd9Sstevel@tonic-gate if (t_errno == TSYSERR && errno == EAGAIN) 5227c478bd9Sstevel@tonic-gate #endif 5237c478bd9Sstevel@tonic-gate continue; 5247c478bd9Sstevel@tonic-gate if (t_errno == TLOOK) { 5257c478bd9Sstevel@tonic-gate if ((err = _rcv_unitdata_err(cu)) == 0) 5267c478bd9Sstevel@tonic-gate continue; 5277c478bd9Sstevel@tonic-gate else if (err == 1) 5287c478bd9Sstevel@tonic-gate errnoflag = TRUE; 5297c478bd9Sstevel@tonic-gate } else { 5307c478bd9Sstevel@tonic-gate rpc_callerr.re_terrno = t_errno; 5317c478bd9Sstevel@tonic-gate } 5327c478bd9Sstevel@tonic-gate if (errnoflag == FALSE) 5337c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = errno; 5347c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 5357c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTRECV); 5367c478bd9Sstevel@tonic-gate } 5377c478bd9Sstevel@tonic-gate if (cu->cu_tr_data->udata.len < (uint_t)sizeof (uint32_t)) 5387c478bd9Sstevel@tonic-gate continue; 5397c478bd9Sstevel@tonic-gate /* see if reply transaction id matches sent id */ 5407c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 5417c478bd9Sstevel@tonic-gate if (*((uint32_t *)(cu->cu_inbuf)) != 54261961e0fSrobinson /* LINTED pointer alignment */ 5437c478bd9Sstevel@tonic-gate *((uint32_t *)(cu->cu_outbuf))) 5447c478bd9Sstevel@tonic-gate goto timeout; 5457c478bd9Sstevel@tonic-gate /* we now assume we have the proper reply */ 5467c478bd9Sstevel@tonic-gate break; 5477c478bd9Sstevel@tonic-gate } 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate /* 5507c478bd9Sstevel@tonic-gate * now decode and validate the response 5517c478bd9Sstevel@tonic-gate */ 5527c478bd9Sstevel@tonic-gate 5537c478bd9Sstevel@tonic-gate xdrmem_create(&reply_xdrs, cu->cu_inbuf, 5547c478bd9Sstevel@tonic-gate (uint_t)cu->cu_tr_data->udata.len, XDR_DECODE); 5557c478bd9Sstevel@tonic-gate ok = xdr_replymsg(&reply_xdrs, &reply_msg); 5567c478bd9Sstevel@tonic-gate /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 5577c478bd9Sstevel@tonic-gate if (ok) { 5587c478bd9Sstevel@tonic-gate if ((reply_msg.rm_reply.rp_stat == MSG_ACCEPTED) && 5597c478bd9Sstevel@tonic-gate (reply_msg.acpted_rply.ar_stat == SUCCESS)) 5607c478bd9Sstevel@tonic-gate rpc_callerr.re_status = RPC_SUCCESS; 5617c478bd9Sstevel@tonic-gate else 5627c478bd9Sstevel@tonic-gate __seterr_reply(&reply_msg, &(rpc_callerr)); 5637c478bd9Sstevel@tonic-gate 5647c478bd9Sstevel@tonic-gate if (rpc_callerr.re_status == RPC_SUCCESS) { 5657c478bd9Sstevel@tonic-gate if (!AUTH_VALIDATE(cl->cl_auth, 5667c478bd9Sstevel@tonic-gate &reply_msg.acpted_rply.ar_verf)) { 5677c478bd9Sstevel@tonic-gate rpc_callerr.re_status = RPC_AUTHERROR; 5687c478bd9Sstevel@tonic-gate rpc_callerr.re_why = AUTH_INVALIDRESP; 5697c478bd9Sstevel@tonic-gate } else if (cl->cl_auth->ah_cred.oa_flavor != 5707c478bd9Sstevel@tonic-gate RPCSEC_GSS) { 5717c478bd9Sstevel@tonic-gate if (!(*xresults)(&reply_xdrs, resultsp)) { 5725131caa1SMarcel Telka if (rpc_callerr.re_status == 5735131caa1SMarcel Telka RPC_SUCCESS) 5747c478bd9Sstevel@tonic-gate rpc_callerr.re_status = 5757c478bd9Sstevel@tonic-gate RPC_CANTDECODERES; 5767c478bd9Sstevel@tonic-gate } 5777c478bd9Sstevel@tonic-gate } else if (!__rpc_gss_unwrap(cl->cl_auth, &reply_xdrs, 5787c478bd9Sstevel@tonic-gate xresults, resultsp)) { 5797c478bd9Sstevel@tonic-gate if (rpc_callerr.re_status == RPC_SUCCESS) 5805131caa1SMarcel Telka rpc_callerr.re_status = 5815131caa1SMarcel Telka RPC_CANTDECODERES; 5827c478bd9Sstevel@tonic-gate } 5837c478bd9Sstevel@tonic-gate } /* end successful completion */ 5847c478bd9Sstevel@tonic-gate /* 5857c478bd9Sstevel@tonic-gate * If unsuccesful AND error is an authentication error 5867c478bd9Sstevel@tonic-gate * then refresh credentials and try again, else break 5877c478bd9Sstevel@tonic-gate */ 5887c478bd9Sstevel@tonic-gate else if (rpc_callerr.re_status == RPC_AUTHERROR) 5897c478bd9Sstevel@tonic-gate /* maybe our credentials need to be refreshed ... */ 5907c478bd9Sstevel@tonic-gate if (nrefreshes-- && 5917c478bd9Sstevel@tonic-gate AUTH_REFRESH(cl->cl_auth, &reply_msg)) 5927c478bd9Sstevel@tonic-gate goto call_again; 5937c478bd9Sstevel@tonic-gate else 5947c478bd9Sstevel@tonic-gate /* 5957c478bd9Sstevel@tonic-gate * We are setting rpc_callerr here given that 5967c478bd9Sstevel@tonic-gate * libnsl is not reentrant thereby 5977c478bd9Sstevel@tonic-gate * reinitializing the TSD. If not set here then 5987c478bd9Sstevel@tonic-gate * success could be returned even though refresh 5997c478bd9Sstevel@tonic-gate * failed. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate rpc_callerr.re_status = RPC_AUTHERROR; 6027c478bd9Sstevel@tonic-gate 6037c478bd9Sstevel@tonic-gate /* end of unsuccessful completion */ 6047c478bd9Sstevel@tonic-gate /* free verifier */ 6057c478bd9Sstevel@tonic-gate if (reply_msg.rm_reply.rp_stat == MSG_ACCEPTED && 6067c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 6077c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 6087c478bd9Sstevel@tonic-gate (void) xdr_opaque_auth(xdrs, 6097c478bd9Sstevel@tonic-gate &(reply_msg.acpted_rply.ar_verf)); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate } /* end of valid reply message */ 6127c478bd9Sstevel@tonic-gate else { 6137c478bd9Sstevel@tonic-gate rpc_callerr.re_status = RPC_CANTDECODERES; 6147c478bd9Sstevel@tonic-gate 6157c478bd9Sstevel@tonic-gate } 6167c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 6177c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate 6207c478bd9Sstevel@tonic-gate static enum clnt_stat 62161961e0fSrobinson clnt_dg_send(CLIENT *cl, rpcproc_t proc, xdrproc_t xargs, caddr_t argsp) 6227c478bd9Sstevel@tonic-gate { 6237c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 6247c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 6257c478bd9Sstevel@tonic-gate XDR *xdrs; 6267c478bd9Sstevel@tonic-gate int outlen; 6277c478bd9Sstevel@tonic-gate struct t_unitdata tu_data; 6287c478bd9Sstevel@tonic-gate uint32_t x_id; 6297c478bd9Sstevel@tonic-gate 6307c478bd9Sstevel@tonic-gate if (rpc_fd_lock(dgtbl, cu->cu_fd)) { 6317c478bd9Sstevel@tonic-gate rpc_callerr.re_status = RPC_FAILED; 6327c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = errno; 6337c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 6347c478bd9Sstevel@tonic-gate return (RPC_FAILED); 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate tu_data.addr = cu->cu_raddr; 6387c478bd9Sstevel@tonic-gate 6397c478bd9Sstevel@tonic-gate xdrs = &(cu->cu_outxdrs); 6407c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 6417c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, 0); 6427c478bd9Sstevel@tonic-gate /* 6437c478bd9Sstevel@tonic-gate * Due to little endian byte order, it is necessary to convert to host 6447c478bd9Sstevel@tonic-gate * format before incrementing xid. 6457c478bd9Sstevel@tonic-gate */ 64661961e0fSrobinson /* LINTED pointer alignment */ 6477c478bd9Sstevel@tonic-gate x_id = ntohl(*(uint32_t *)(cu->cu_outbuf)) + 1; /* set XID */ 64861961e0fSrobinson /* LINTED pointer cast */ 6497c478bd9Sstevel@tonic-gate *(uint32_t *)cu->cu_outbuf = htonl(x_id); 6507c478bd9Sstevel@tonic-gate 6517c478bd9Sstevel@tonic-gate if (cl->cl_auth->ah_cred.oa_flavor != RPCSEC_GSS) { 6527c478bd9Sstevel@tonic-gate if ((!XDR_PUTBYTES(xdrs, cu->cu_outbuf, cu->cu_xdrpos)) || 6537c478bd9Sstevel@tonic-gate (!XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 6547c478bd9Sstevel@tonic-gate (!AUTH_MARSHALL(cl->cl_auth, xdrs)) || 6557c478bd9Sstevel@tonic-gate (!xargs(xdrs, argsp))) { 6567c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 6577c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTENCODEARGS); 6587c478bd9Sstevel@tonic-gate } 6597c478bd9Sstevel@tonic-gate } else { 6607c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 6617c478bd9Sstevel@tonic-gate uint32_t *u = (uint32_t *)&cu->cu_outbuf[cu->cu_xdrpos]; 6627c478bd9Sstevel@tonic-gate IXDR_PUT_U_INT32(u, proc); 6637c478bd9Sstevel@tonic-gate if (!__rpc_gss_wrap(cl->cl_auth, cu->cu_outbuf, 6647c478bd9Sstevel@tonic-gate ((char *)u) - cu->cu_outbuf, xdrs, xargs, argsp)) { 6657c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 6667c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTENCODEARGS); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate } 6697c478bd9Sstevel@tonic-gate outlen = (int)XDR_GETPOS(xdrs); 6707c478bd9Sstevel@tonic-gate 6717c478bd9Sstevel@tonic-gate tu_data.udata.buf = cu->cu_outbuf_start; 6727c478bd9Sstevel@tonic-gate tu_data.udata.len = outlen; 6737c478bd9Sstevel@tonic-gate tu_data.opt.len = 0; 6747c478bd9Sstevel@tonic-gate if (t_sndudata(cu->cu_fd, &tu_data) == -1) { 6757c478bd9Sstevel@tonic-gate rpc_callerr.re_terrno = t_errno; 6767c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = errno; 6777c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 6787c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_CANTSEND); 6797c478bd9Sstevel@tonic-gate } 6807c478bd9Sstevel@tonic-gate 6817c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 6827c478bd9Sstevel@tonic-gate return (rpc_callerr.re_status = RPC_SUCCESS); 6837c478bd9Sstevel@tonic-gate } 6847c478bd9Sstevel@tonic-gate 6857c478bd9Sstevel@tonic-gate static void 6867c478bd9Sstevel@tonic-gate clnt_dg_geterr(CLIENT *cl, struct rpc_err *errp) 6877c478bd9Sstevel@tonic-gate { 688*b7ab9363SShruti Sampat NOTE(ARGUNUSED(cl)) 6897c478bd9Sstevel@tonic-gate *errp = rpc_callerr; 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate static bool_t 6937c478bd9Sstevel@tonic-gate clnt_dg_freeres(CLIENT *cl, xdrproc_t xdr_res, caddr_t res_ptr) 6947c478bd9Sstevel@tonic-gate { 6957c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 6967c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 6977c478bd9Sstevel@tonic-gate XDR *xdrs = &(cu->cu_outxdrs); 69861961e0fSrobinson bool_t stat; 6997c478bd9Sstevel@tonic-gate 70061961e0fSrobinson (void) rpc_fd_lock(dgtbl, cu->cu_fd); 7017c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 70261961e0fSrobinson stat = (*xdr_res)(xdrs, res_ptr); 7037c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 70461961e0fSrobinson return (stat); 7057c478bd9Sstevel@tonic-gate } 7067c478bd9Sstevel@tonic-gate 70761961e0fSrobinson /* ARGSUSED */ 7087c478bd9Sstevel@tonic-gate static void 70961961e0fSrobinson clnt_dg_abort(CLIENT *h) 7107c478bd9Sstevel@tonic-gate { 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate static bool_t 7147c478bd9Sstevel@tonic-gate clnt_dg_control(CLIENT *cl, int request, char *info) 7157c478bd9Sstevel@tonic-gate { 7167c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7177c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 7187c478bd9Sstevel@tonic-gate struct netbuf *addr; 7197c478bd9Sstevel@tonic-gate if (rpc_fd_lock(dgtbl, cu->cu_fd)) { 7207c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 7215131caa1SMarcel Telka return (FALSE); 7227c478bd9Sstevel@tonic-gate } 7237c478bd9Sstevel@tonic-gate 7247c478bd9Sstevel@tonic-gate switch (request) { 7257c478bd9Sstevel@tonic-gate case CLSET_FD_CLOSE: 7267c478bd9Sstevel@tonic-gate cu->cu_closeit = TRUE; 7277c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 7287c478bd9Sstevel@tonic-gate return (TRUE); 7297c478bd9Sstevel@tonic-gate case CLSET_FD_NCLOSE: 7307c478bd9Sstevel@tonic-gate cu->cu_closeit = FALSE; 7317c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 7327c478bd9Sstevel@tonic-gate return (TRUE); 7337c478bd9Sstevel@tonic-gate } 7347c478bd9Sstevel@tonic-gate 7357c478bd9Sstevel@tonic-gate /* for other requests which use info */ 7367c478bd9Sstevel@tonic-gate if (info == NULL) { 7377c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 7387c478bd9Sstevel@tonic-gate return (FALSE); 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate switch (request) { 7417c478bd9Sstevel@tonic-gate case CLSET_TIMEOUT: 7427c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7437c478bd9Sstevel@tonic-gate if (time_not_ok((struct timeval *)info)) { 7447c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 7457c478bd9Sstevel@tonic-gate return (FALSE); 7467c478bd9Sstevel@tonic-gate } 7477c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7487c478bd9Sstevel@tonic-gate cu->cu_total = *(struct timeval *)info; 7497c478bd9Sstevel@tonic-gate break; 7507c478bd9Sstevel@tonic-gate case CLGET_TIMEOUT: 7517c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7527c478bd9Sstevel@tonic-gate *(struct timeval *)info = cu->cu_total; 7537c478bd9Sstevel@tonic-gate break; 7547c478bd9Sstevel@tonic-gate case CLGET_SERVER_ADDR: /* Give him the fd address */ 7557c478bd9Sstevel@tonic-gate /* Now obsolete. Only for backword compatibility */ 75661961e0fSrobinson (void) memcpy(info, cu->cu_raddr.buf, (size_t)cu->cu_raddr.len); 7577c478bd9Sstevel@tonic-gate break; 7587c478bd9Sstevel@tonic-gate case CLSET_RETRY_TIMEOUT: 7597c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7607c478bd9Sstevel@tonic-gate if (time_not_ok((struct timeval *)info)) { 7617c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 7627c478bd9Sstevel@tonic-gate return (FALSE); 7637c478bd9Sstevel@tonic-gate } 7647c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7657c478bd9Sstevel@tonic-gate cu->cu_wait = *(struct timeval *)info; 7667c478bd9Sstevel@tonic-gate break; 7677c478bd9Sstevel@tonic-gate case CLGET_RETRY_TIMEOUT: 7687c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7697c478bd9Sstevel@tonic-gate *(struct timeval *)info = cu->cu_wait; 7707c478bd9Sstevel@tonic-gate break; 7717c478bd9Sstevel@tonic-gate case CLGET_FD: 7727c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7737c478bd9Sstevel@tonic-gate *(int *)info = cu->cu_fd; 7747c478bd9Sstevel@tonic-gate break; 7757c478bd9Sstevel@tonic-gate case CLGET_SVC_ADDR: 7767c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7777c478bd9Sstevel@tonic-gate *(struct netbuf *)info = cu->cu_raddr; 7787c478bd9Sstevel@tonic-gate break; 7797c478bd9Sstevel@tonic-gate case CLSET_SVC_ADDR: /* set to new address */ 7807c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 7817c478bd9Sstevel@tonic-gate addr = (struct netbuf *)info; 7827c478bd9Sstevel@tonic-gate if (cu->cu_raddr.maxlen < addr->len) { 78361961e0fSrobinson free(cu->cu_raddr.buf); 78461961e0fSrobinson if ((cu->cu_raddr.buf = malloc(addr->len)) == NULL) { 7857c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 7867c478bd9Sstevel@tonic-gate return (FALSE); 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate cu->cu_raddr.maxlen = addr->len; 7897c478bd9Sstevel@tonic-gate } 7907c478bd9Sstevel@tonic-gate cu->cu_raddr.len = addr->len; 7917c478bd9Sstevel@tonic-gate (void) memcpy(cu->cu_raddr.buf, addr->buf, addr->len); 7927c478bd9Sstevel@tonic-gate break; 7937c478bd9Sstevel@tonic-gate case CLGET_XID: 7947c478bd9Sstevel@tonic-gate /* 7957c478bd9Sstevel@tonic-gate * use the knowledge that xid is the 7967c478bd9Sstevel@tonic-gate * first element in the call structure *. 7977c478bd9Sstevel@tonic-gate * This will get the xid of the PREVIOUS call 7987c478bd9Sstevel@tonic-gate */ 7997c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8007c478bd9Sstevel@tonic-gate *(uint32_t *)info = ntohl(*(uint32_t *)cu->cu_outbuf); 8017c478bd9Sstevel@tonic-gate break; 8027c478bd9Sstevel@tonic-gate 8037c478bd9Sstevel@tonic-gate case CLSET_XID: 8047c478bd9Sstevel@tonic-gate /* This will set the xid of the NEXT call */ 8057c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8067c478bd9Sstevel@tonic-gate *(uint32_t *)cu->cu_outbuf = htonl(*(uint32_t *)info - 1); 8077c478bd9Sstevel@tonic-gate /* decrement by 1 as clnt_dg_call() increments once */ 8087c478bd9Sstevel@tonic-gate break; 8097c478bd9Sstevel@tonic-gate 8107c478bd9Sstevel@tonic-gate case CLGET_VERS: 8117c478bd9Sstevel@tonic-gate /* 8127c478bd9Sstevel@tonic-gate * This RELIES on the information that, in the call body, 8137c478bd9Sstevel@tonic-gate * the version number field is the fifth field from the 8147c478bd9Sstevel@tonic-gate * begining of the RPC header. MUST be changed if the 8157c478bd9Sstevel@tonic-gate * call_struct is changed 8167c478bd9Sstevel@tonic-gate */ 8177c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8187c478bd9Sstevel@tonic-gate *(uint32_t *)info = ntohl(*(uint32_t *)(cu->cu_outbuf + 8197c478bd9Sstevel@tonic-gate 4 * BYTES_PER_XDR_UNIT)); 8207c478bd9Sstevel@tonic-gate break; 8217c478bd9Sstevel@tonic-gate 8227c478bd9Sstevel@tonic-gate case CLSET_VERS: 8237c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8247c478bd9Sstevel@tonic-gate *(uint32_t *)(cu->cu_outbuf + 4 * BYTES_PER_XDR_UNIT) = 8257c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8267c478bd9Sstevel@tonic-gate htonl(*(uint32_t *)info); 8277c478bd9Sstevel@tonic-gate break; 8287c478bd9Sstevel@tonic-gate 8297c478bd9Sstevel@tonic-gate case CLGET_PROG: 8307c478bd9Sstevel@tonic-gate /* 8317c478bd9Sstevel@tonic-gate * This RELIES on the information that, in the call body, 8327c478bd9Sstevel@tonic-gate * the program number field is the fourth field from the 8337c478bd9Sstevel@tonic-gate * begining of the RPC header. MUST be changed if the 8347c478bd9Sstevel@tonic-gate * call_struct is changed 8357c478bd9Sstevel@tonic-gate */ 8367c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8377c478bd9Sstevel@tonic-gate *(uint32_t *)info = ntohl(*(uint32_t *)(cu->cu_outbuf + 8387c478bd9Sstevel@tonic-gate 3 * BYTES_PER_XDR_UNIT)); 8397c478bd9Sstevel@tonic-gate break; 8407c478bd9Sstevel@tonic-gate 8417c478bd9Sstevel@tonic-gate case CLSET_PROG: 8427c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8437c478bd9Sstevel@tonic-gate *(uint32_t *)(cu->cu_outbuf + 3 * BYTES_PER_XDR_UNIT) = 8447c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8457c478bd9Sstevel@tonic-gate htonl(*(uint32_t *)info); 8467c478bd9Sstevel@tonic-gate break; 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate default: 8497c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 8507c478bd9Sstevel@tonic-gate return (FALSE); 8517c478bd9Sstevel@tonic-gate } 8527c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu->cu_fd); 8537c478bd9Sstevel@tonic-gate return (TRUE); 8547c478bd9Sstevel@tonic-gate } 8557c478bd9Sstevel@tonic-gate 8567c478bd9Sstevel@tonic-gate static void 8577c478bd9Sstevel@tonic-gate clnt_dg_destroy(CLIENT *cl) 8587c478bd9Sstevel@tonic-gate { 8597c478bd9Sstevel@tonic-gate /* LINTED pointer alignment */ 8607c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 8617c478bd9Sstevel@tonic-gate int cu_fd = cu->cu_fd; 8627c478bd9Sstevel@tonic-gate 86361961e0fSrobinson (void) rpc_fd_lock(dgtbl, cu_fd); 8647c478bd9Sstevel@tonic-gate if (cu->cu_closeit) 8657c478bd9Sstevel@tonic-gate (void) t_close(cu_fd); 8667c478bd9Sstevel@tonic-gate XDR_DESTROY(&(cu->cu_outxdrs)); 8677c478bd9Sstevel@tonic-gate cu->cu_tr_data->udata.buf = NULL; 8687c478bd9Sstevel@tonic-gate (void) t_free((char *)cu->cu_tr_data, T_UNITDATA); 86961961e0fSrobinson free(cu->cu_raddr.buf); 87061961e0fSrobinson free(cu); 8717c478bd9Sstevel@tonic-gate if (cl->cl_netid && cl->cl_netid[0]) 87261961e0fSrobinson free(cl->cl_netid); 8737c478bd9Sstevel@tonic-gate if (cl->cl_tp && cl->cl_tp[0]) 87461961e0fSrobinson free(cl->cl_tp); 87561961e0fSrobinson free(cl); 8767c478bd9Sstevel@tonic-gate rpc_fd_unlock(dgtbl, cu_fd); 8777c478bd9Sstevel@tonic-gate } 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate static struct clnt_ops * 8807c478bd9Sstevel@tonic-gate clnt_dg_ops(void) 8817c478bd9Sstevel@tonic-gate { 8827c478bd9Sstevel@tonic-gate static struct clnt_ops ops; 8837c478bd9Sstevel@tonic-gate extern mutex_t ops_lock; 8847c478bd9Sstevel@tonic-gate 8857c478bd9Sstevel@tonic-gate /* VARIABLES PROTECTED BY ops_lock: ops */ 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate sig_mutex_lock(&ops_lock); 8887c478bd9Sstevel@tonic-gate if (ops.cl_call == NULL) { 8897c478bd9Sstevel@tonic-gate ops.cl_call = clnt_dg_call; 8907c478bd9Sstevel@tonic-gate ops.cl_send = clnt_dg_send; 8917c478bd9Sstevel@tonic-gate ops.cl_abort = clnt_dg_abort; 8927c478bd9Sstevel@tonic-gate ops.cl_geterr = clnt_dg_geterr; 8937c478bd9Sstevel@tonic-gate ops.cl_freeres = clnt_dg_freeres; 8947c478bd9Sstevel@tonic-gate ops.cl_destroy = clnt_dg_destroy; 8957c478bd9Sstevel@tonic-gate ops.cl_control = clnt_dg_control; 8967c478bd9Sstevel@tonic-gate } 8977c478bd9Sstevel@tonic-gate sig_mutex_unlock(&ops_lock); 8987c478bd9Sstevel@tonic-gate return (&ops); 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate 9017c478bd9Sstevel@tonic-gate /* 9027c478bd9Sstevel@tonic-gate * Make sure that the time is not garbage. -1 value is allowed. 9037c478bd9Sstevel@tonic-gate */ 9047c478bd9Sstevel@tonic-gate static bool_t 9057c478bd9Sstevel@tonic-gate time_not_ok(struct timeval *t) 9067c478bd9Sstevel@tonic-gate { 9077c478bd9Sstevel@tonic-gate return (t->tv_sec < -1 || t->tv_sec > 100000000 || 9087c478bd9Sstevel@tonic-gate t->tv_usec < -1 || t->tv_usec > 1000000); 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate /* 9127c478bd9Sstevel@tonic-gate * Receive a unit data error indication. 9137c478bd9Sstevel@tonic-gate * Below even when t_alloc() fails we pass uderr=NULL to t_rcvuderr() 9147c478bd9Sstevel@tonic-gate * so as to just clear the error indication. 9157c478bd9Sstevel@tonic-gate */ 9167c478bd9Sstevel@tonic-gate 9177c478bd9Sstevel@tonic-gate static int 9187c478bd9Sstevel@tonic-gate _rcv_unitdata_err(struct cu_data *cu) 9197c478bd9Sstevel@tonic-gate { 9207c478bd9Sstevel@tonic-gate int old; 9217c478bd9Sstevel@tonic-gate struct t_uderr *uderr; 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate old = t_errno; 92461961e0fSrobinson /* LINTED pointer cast */ 9255131caa1SMarcel Telka uderr = (struct t_uderr *)t_alloc(cu->cu_fd, T_UDERROR, T_ADDR); 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate if (t_rcvuderr(cu->cu_fd, uderr) == 0) { 9287c478bd9Sstevel@tonic-gate if (uderr == NULL) 9297c478bd9Sstevel@tonic-gate return (0); 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate if (uderr->addr.len != cu->cu_raddr.len || 9327c478bd9Sstevel@tonic-gate (memcmp(uderr->addr.buf, cu->cu_raddr.buf, 9337c478bd9Sstevel@tonic-gate cu->cu_raddr.len))) { 93461961e0fSrobinson (void) t_free((char *)uderr, T_UDERROR); 9357c478bd9Sstevel@tonic-gate return (0); 9367c478bd9Sstevel@tonic-gate } 9377c478bd9Sstevel@tonic-gate rpc_callerr.re_errno = uderr->error; 9387c478bd9Sstevel@tonic-gate rpc_callerr.re_terrno = TSYSERR; 93961961e0fSrobinson (void) t_free((char *)uderr, T_UDERROR); 9407c478bd9Sstevel@tonic-gate return (1); 94161961e0fSrobinson } 9427c478bd9Sstevel@tonic-gate rpc_callerr.re_terrno = old; 9437c478bd9Sstevel@tonic-gate if (uderr) 94461961e0fSrobinson (void) t_free((char *)uderr, T_UDERROR); 9457c478bd9Sstevel@tonic-gate return (-1); 9467c478bd9Sstevel@tonic-gate } 947