1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate * 26*0Sstevel@tonic-gate * This file contains a simple implementation of RPC. Standard XDR is 27*0Sstevel@tonic-gate * used. 28*0Sstevel@tonic-gate */ 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gate #include <sys/sysmacros.h> 33*0Sstevel@tonic-gate #include <rpc/types.h> 34*0Sstevel@tonic-gate #include <errno.h> 35*0Sstevel@tonic-gate #include <sys/socket.h> 36*0Sstevel@tonic-gate #include <netinet/in.h> 37*0Sstevel@tonic-gate #include "socket_inet.h" 38*0Sstevel@tonic-gate #include "ipv4.h" 39*0Sstevel@tonic-gate #include <rpc/xdr.h> 40*0Sstevel@tonic-gate #include <rpc/auth.h> 41*0Sstevel@tonic-gate #include <rpc/auth_sys.h> 42*0Sstevel@tonic-gate #include <rpc/rpc_msg.h> 43*0Sstevel@tonic-gate #include <sys/t_lock.h> 44*0Sstevel@tonic-gate #include <netdb.h> 45*0Sstevel@tonic-gate #include "clnt.h" 46*0Sstevel@tonic-gate #include <rpc/rpc.h> 47*0Sstevel@tonic-gate #include "brpc.h" 48*0Sstevel@tonic-gate #include "auth_inet.h" 49*0Sstevel@tonic-gate #include "pmap.h" 50*0Sstevel@tonic-gate #include <sys/promif.h> 51*0Sstevel@tonic-gate #include "nfs_inet.h" 52*0Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 53*0Sstevel@tonic-gate #include <rpc/auth_unix.h> 54*0Sstevel@tonic-gate #include <sys/salib.h> 55*0Sstevel@tonic-gate #include "mac.h" 56*0Sstevel@tonic-gate #include <sys/bootdebug.h> 57*0Sstevel@tonic-gate 58*0Sstevel@tonic-gate #define dprintf if (boothowto & RB_DEBUG) printf 59*0Sstevel@tonic-gate 60*0Sstevel@tonic-gate static struct in_addr cached_destination; 61*0Sstevel@tonic-gate 62*0Sstevel@tonic-gate void 63*0Sstevel@tonic-gate rpc_disperr(struct rpc_err *stat) 64*0Sstevel@tonic-gate { 65*0Sstevel@tonic-gate if (boothowto & RB_DEBUG) { 66*0Sstevel@tonic-gate switch (stat->re_status) { 67*0Sstevel@tonic-gate case RPC_CANTENCODEARGS: 68*0Sstevel@tonic-gate printf("RPC: Can't encode arguments.\n"); 69*0Sstevel@tonic-gate break; 70*0Sstevel@tonic-gate case RPC_CANTDECODERES: 71*0Sstevel@tonic-gate printf("RPC: Can't decode result.\n"); 72*0Sstevel@tonic-gate break; 73*0Sstevel@tonic-gate case RPC_CANTSEND: 74*0Sstevel@tonic-gate printf("RPC: Unable to send (%s).\n", 75*0Sstevel@tonic-gate strerror(errno)); 76*0Sstevel@tonic-gate break; 77*0Sstevel@tonic-gate case RPC_CANTRECV: 78*0Sstevel@tonic-gate printf("RPC: Unable to receive (%s).\n", 79*0Sstevel@tonic-gate strerror(errno)); 80*0Sstevel@tonic-gate break; 81*0Sstevel@tonic-gate case RPC_TIMEDOUT: 82*0Sstevel@tonic-gate printf("RPC: Timed out.\n"); 83*0Sstevel@tonic-gate break; 84*0Sstevel@tonic-gate case RPC_VERSMISMATCH: 85*0Sstevel@tonic-gate printf("RPC: Incompatible versions of RPC.\n"); 86*0Sstevel@tonic-gate break; 87*0Sstevel@tonic-gate case RPC_AUTHERROR: 88*0Sstevel@tonic-gate printf("RPC: Authentication error:\n"); 89*0Sstevel@tonic-gate switch (stat->re_why) { 90*0Sstevel@tonic-gate case AUTH_BADCRED: 91*0Sstevel@tonic-gate printf("remote: bogus credentials " 92*0Sstevel@tonic-gate "(seal broken).\n"); 93*0Sstevel@tonic-gate break; 94*0Sstevel@tonic-gate case AUTH_REJECTEDCRED: 95*0Sstevel@tonic-gate printf("remote: client should begin new " 96*0Sstevel@tonic-gate "session.\n"); 97*0Sstevel@tonic-gate break; 98*0Sstevel@tonic-gate case AUTH_BADVERF: 99*0Sstevel@tonic-gate printf("remote: bogus verifier " 100*0Sstevel@tonic-gate "(seal broken).\n"); 101*0Sstevel@tonic-gate break; 102*0Sstevel@tonic-gate case AUTH_REJECTEDVERF: 103*0Sstevel@tonic-gate printf("remote: verifier expired or was " 104*0Sstevel@tonic-gate "replayed.\n"); 105*0Sstevel@tonic-gate break; 106*0Sstevel@tonic-gate case AUTH_TOOWEAK: 107*0Sstevel@tonic-gate printf("remote: rejected due to security " 108*0Sstevel@tonic-gate "reasons.\n"); 109*0Sstevel@tonic-gate break; 110*0Sstevel@tonic-gate case AUTH_INVALIDRESP: 111*0Sstevel@tonic-gate printf("local: bogus response verifier.\n"); 112*0Sstevel@tonic-gate break; 113*0Sstevel@tonic-gate case AUTH_FAILED: 114*0Sstevel@tonic-gate /* FALLTHRU */ 115*0Sstevel@tonic-gate default: 116*0Sstevel@tonic-gate printf("local: unknown error.\n"); 117*0Sstevel@tonic-gate break; 118*0Sstevel@tonic-gate } 119*0Sstevel@tonic-gate break; 120*0Sstevel@tonic-gate case RPC_PROGUNAVAIL: 121*0Sstevel@tonic-gate printf("RPC: Program unavailable.\n"); 122*0Sstevel@tonic-gate break; 123*0Sstevel@tonic-gate case RPC_PROGVERSMISMATCH: 124*0Sstevel@tonic-gate printf("RPC: Program/version mismatch.\n"); 125*0Sstevel@tonic-gate break; 126*0Sstevel@tonic-gate case RPC_PROCUNAVAIL: 127*0Sstevel@tonic-gate printf("RPC: Procedure unavailable.\n"); 128*0Sstevel@tonic-gate break; 129*0Sstevel@tonic-gate case RPC_CANTDECODEARGS: 130*0Sstevel@tonic-gate printf("RPC: Server can't decode arguments.\n"); 131*0Sstevel@tonic-gate break; 132*0Sstevel@tonic-gate case RPC_SYSTEMERROR: 133*0Sstevel@tonic-gate printf("RPC: Remote system error.\n"); 134*0Sstevel@tonic-gate break; 135*0Sstevel@tonic-gate case RPC_UNKNOWNHOST: 136*0Sstevel@tonic-gate printf("RPC: Unknown host.\n"); 137*0Sstevel@tonic-gate break; 138*0Sstevel@tonic-gate case RPC_UNKNOWNPROTO: 139*0Sstevel@tonic-gate printf("RPC: Unknown protocol.\n"); 140*0Sstevel@tonic-gate break; 141*0Sstevel@tonic-gate case RPC_PMAPFAILURE: 142*0Sstevel@tonic-gate printf("RPC: Port mapper failure.\n"); 143*0Sstevel@tonic-gate break; 144*0Sstevel@tonic-gate case RPC_PROGNOTREGISTERED: 145*0Sstevel@tonic-gate printf("RPC: Program not registered.\n"); 146*0Sstevel@tonic-gate break; 147*0Sstevel@tonic-gate case RPC_FAILED: 148*0Sstevel@tonic-gate printf("RPC: Failed (unspecified error).\n"); 149*0Sstevel@tonic-gate break; 150*0Sstevel@tonic-gate default: 151*0Sstevel@tonic-gate printf("RPC: (unknown error code).\n"); 152*0Sstevel@tonic-gate break; 153*0Sstevel@tonic-gate } 154*0Sstevel@tonic-gate } 155*0Sstevel@tonic-gate } 156*0Sstevel@tonic-gate 157*0Sstevel@tonic-gate /* 158*0Sstevel@tonic-gate * rpc_hdr: sets the fields in the rpc msg header. 159*0Sstevel@tonic-gate * 160*0Sstevel@tonic-gate * Returns: TRUE on success, FALSE if failure. 161*0Sstevel@tonic-gate */ 162*0Sstevel@tonic-gate /*ARGSUSED*/ 163*0Sstevel@tonic-gate static bool_t 164*0Sstevel@tonic-gate rpc_hdr(XDR *xdrs, uint_t xid, rpcprog_t prog, rpcvers_t vers, rpcproc_t proc) 165*0Sstevel@tonic-gate { 166*0Sstevel@tonic-gate struct rpc_msg call_msg; 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gate /* setup header */ 169*0Sstevel@tonic-gate call_msg.rm_xid = xid; 170*0Sstevel@tonic-gate call_msg.rm_direction = CALL; 171*0Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = (rpcvers_t)RPC_MSG_VERSION; 172*0Sstevel@tonic-gate call_msg.rm_call.cb_prog = prog; 173*0Sstevel@tonic-gate call_msg.rm_call.cb_vers = vers; 174*0Sstevel@tonic-gate 175*0Sstevel@tonic-gate /* xdr the header. */ 176*0Sstevel@tonic-gate if (xdr_callhdr(xdrs, &call_msg) == FALSE) 177*0Sstevel@tonic-gate return (FALSE); 178*0Sstevel@tonic-gate else 179*0Sstevel@tonic-gate return (TRUE); 180*0Sstevel@tonic-gate } 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate /* 183*0Sstevel@tonic-gate * our version of brpc_call(). We cache in portnumber in to->sin_port for 184*0Sstevel@tonic-gate * your convenience. to and from addresses are taken and received in network 185*0Sstevel@tonic-gate * order. 186*0Sstevel@tonic-gate */ 187*0Sstevel@tonic-gate enum clnt_stat 188*0Sstevel@tonic-gate brpc_call( 189*0Sstevel@tonic-gate rpcprog_t prog, /* rpc program number to call. */ 190*0Sstevel@tonic-gate rpcvers_t vers, /* rpc program version */ 191*0Sstevel@tonic-gate rpcproc_t proc, /* rpc procedure to call */ 192*0Sstevel@tonic-gate xdrproc_t in_xdr, /* routine to serialize arguments */ 193*0Sstevel@tonic-gate caddr_t args, /* arg vector for remote call */ 194*0Sstevel@tonic-gate xdrproc_t out_xdr, /* routine to deserialize results */ 195*0Sstevel@tonic-gate caddr_t ret, /* addr of buf to place results in */ 196*0Sstevel@tonic-gate int rexmit, /* retransmission interval (secs) */ 197*0Sstevel@tonic-gate int wait_time, /* how long (secs) to wait (resp) */ 198*0Sstevel@tonic-gate struct sockaddr_in *to, /* destination */ 199*0Sstevel@tonic-gate struct sockaddr_in *from_who, /* responder's port/address */ 200*0Sstevel@tonic-gate uint_t auth) /* type of auth wanted. */ 201*0Sstevel@tonic-gate { 202*0Sstevel@tonic-gate int s; 203*0Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN]; 204*0Sstevel@tonic-gate struct sockaddr_in from; /* us. */ 205*0Sstevel@tonic-gate socklen_t from_len; 206*0Sstevel@tonic-gate XDR xmit_xdrs, rcv_xdrs; /* xdr memory */ 207*0Sstevel@tonic-gate AUTH *xmit_auth; /* our chosen auth cookie */ 208*0Sstevel@tonic-gate gid_t fake_gids = 1; /* fake gids list for auth_unix */ 209*0Sstevel@tonic-gate caddr_t trm_msg, rcv_msg; /* outgoing/incoming rpc mesgs */ 210*0Sstevel@tonic-gate struct rpc_msg reply; /* our reply msg header */ 211*0Sstevel@tonic-gate int trm_len, rcv_len; 212*0Sstevel@tonic-gate struct rpc_err rpc_error; /* to store RPC errors in on rcv. */ 213*0Sstevel@tonic-gate static uint_t xid; /* current xid */ 214*0Sstevel@tonic-gate uint_t xmit_len; /* How much of the buffer we used */ 215*0Sstevel@tonic-gate int nrefreshes = 2; /* # of times to refresh cred */ 216*0Sstevel@tonic-gate int flags = 0; /* send flags */ 217*0Sstevel@tonic-gate uint_t xdelay; 218*0Sstevel@tonic-gate int errors, preserve_errno; 219*0Sstevel@tonic-gate uint32_t timeout; 220*0Sstevel@tonic-gate socklen_t optlen; 221*0Sstevel@tonic-gate 222*0Sstevel@tonic-gate xmit_auth = NULL; 223*0Sstevel@tonic-gate 224*0Sstevel@tonic-gate trm_len = mac_get_mtu(); 225*0Sstevel@tonic-gate trm_msg = bkmem_alloc(trm_len); 226*0Sstevel@tonic-gate rcv_msg = bkmem_alloc(NFSBUF_SIZE); 227*0Sstevel@tonic-gate 228*0Sstevel@tonic-gate if (trm_msg == NULL || rcv_msg == NULL) { 229*0Sstevel@tonic-gate errno = ENOMEM; 230*0Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 231*0Sstevel@tonic-gate goto gt_error; 232*0Sstevel@tonic-gate } 233*0Sstevel@tonic-gate 234*0Sstevel@tonic-gate if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 235*0Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 236*0Sstevel@tonic-gate goto gt_error; 237*0Sstevel@tonic-gate } 238*0Sstevel@tonic-gate 239*0Sstevel@tonic-gate if (dontroute) { 240*0Sstevel@tonic-gate (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 241*0Sstevel@tonic-gate (const void *)&dontroute, sizeof (dontroute)); 242*0Sstevel@tonic-gate } 243*0Sstevel@tonic-gate 244*0Sstevel@tonic-gate if (to->sin_addr.s_addr == cached_destination.s_addr) { 245*0Sstevel@tonic-gate optlen = sizeof (timeout); 246*0Sstevel@tonic-gate (void) getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, 247*0Sstevel@tonic-gate &optlen); 248*0Sstevel@tonic-gate } else { 249*0Sstevel@tonic-gate cached_destination.s_addr = htonl(INADDR_ANY); 250*0Sstevel@tonic-gate } 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gate /* Bind our endpoint. */ 253*0Sstevel@tonic-gate from.sin_family = AF_INET; 254*0Sstevel@tonic-gate ipv4_getipaddr(&from.sin_addr); 255*0Sstevel@tonic-gate from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); 256*0Sstevel@tonic-gate from.sin_port = get_source_port(B_TRUE); 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) { 259*0Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 260*0Sstevel@tonic-gate goto gt_error; 261*0Sstevel@tonic-gate } 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate bzero((caddr_t)&rpc_error, sizeof (struct rpc_err)); 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate /* initialize reply's rpc_msg struct, so we can decode later. */ 266*0Sstevel@tonic-gate reply.acpted_rply.ar_verf = _null_auth; /* struct copy */ 267*0Sstevel@tonic-gate reply.acpted_rply.ar_results.where = ret; 268*0Sstevel@tonic-gate reply.acpted_rply.ar_results.proc = out_xdr; 269*0Sstevel@tonic-gate 270*0Sstevel@tonic-gate if (ntohs(to->sin_port) == 0) { 271*0Sstevel@tonic-gate /* snag the udp port we need. */ 272*0Sstevel@tonic-gate if ((to->sin_port = (in_port_t)bpmap_getport(prog, vers, 273*0Sstevel@tonic-gate &(rpc_error.re_status), to, NULL)) == 0) 274*0Sstevel@tonic-gate goto gt_error; 275*0Sstevel@tonic-gate to->sin_port = htons(to->sin_port); 276*0Sstevel@tonic-gate } 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate /* generate xid - increment */ 279*0Sstevel@tonic-gate if (xid == 0) 280*0Sstevel@tonic-gate xid = (uint_t)(prom_gettime() / 1000) + 1; 281*0Sstevel@tonic-gate else 282*0Sstevel@tonic-gate xid++; 283*0Sstevel@tonic-gate 284*0Sstevel@tonic-gate /* set up outgoing pkt as xdr modified. */ 285*0Sstevel@tonic-gate xdrmem_create(&xmit_xdrs, trm_msg, trm_len, XDR_ENCODE); 286*0Sstevel@tonic-gate 287*0Sstevel@tonic-gate /* setup rpc header */ 288*0Sstevel@tonic-gate if (rpc_hdr(&xmit_xdrs, xid, prog, vers, proc) != TRUE) { 289*0Sstevel@tonic-gate dprintf("brpc_call: cannot setup rpc header.\n"); 290*0Sstevel@tonic-gate rpc_error.re_status = RPC_FAILED; 291*0Sstevel@tonic-gate goto gt_error; 292*0Sstevel@tonic-gate } 293*0Sstevel@tonic-gate 294*0Sstevel@tonic-gate /* setup authentication */ 295*0Sstevel@tonic-gate switch (auth) { 296*0Sstevel@tonic-gate case AUTH_NONE: 297*0Sstevel@tonic-gate xmit_auth = authnone_create(); 298*0Sstevel@tonic-gate break; 299*0Sstevel@tonic-gate case AUTH_UNIX: 300*0Sstevel@tonic-gate /* 301*0Sstevel@tonic-gate * Assumes we've configured the stack and thus know our 302*0Sstevel@tonic-gate * IP address/hostname, either by using DHCP or rarp/bootparams. 303*0Sstevel@tonic-gate */ 304*0Sstevel@tonic-gate gethostname(hostname, sizeof (hostname)); 305*0Sstevel@tonic-gate xmit_auth = authunix_create(hostname, 0, 1, 1, &fake_gids); 306*0Sstevel@tonic-gate break; 307*0Sstevel@tonic-gate default: 308*0Sstevel@tonic-gate dprintf("brpc_call: Unsupported authentication type: %d\n", 309*0Sstevel@tonic-gate auth); 310*0Sstevel@tonic-gate rpc_error.re_status = RPC_AUTHERROR; 311*0Sstevel@tonic-gate goto gt_error; 312*0Sstevel@tonic-gate /*NOTREACHED*/ 313*0Sstevel@tonic-gate } 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate /* 316*0Sstevel@tonic-gate * rpc_hdr puts everything in the xmit buffer for the header 317*0Sstevel@tonic-gate * EXCEPT the proc. Put it, and our authentication info into 318*0Sstevel@tonic-gate * it now, serializing as we go. We will be at the place where 319*0Sstevel@tonic-gate * we left off. 320*0Sstevel@tonic-gate */ 321*0Sstevel@tonic-gate xmit_xdrs.x_op = XDR_ENCODE; 322*0Sstevel@tonic-gate if ((XDR_PUTINT32(&xmit_xdrs, (int32_t *)&proc) == FALSE) || 323*0Sstevel@tonic-gate (AUTH_MARSHALL(xmit_auth, &xmit_xdrs, NULL) == FALSE) || 324*0Sstevel@tonic-gate ((*in_xdr)(&xmit_xdrs, args) == FALSE)) { 325*0Sstevel@tonic-gate rpc_error.re_status = RPC_CANTENCODEARGS; 326*0Sstevel@tonic-gate goto gt_error; 327*0Sstevel@tonic-gate } else 328*0Sstevel@tonic-gate xmit_len = (int)XDR_GETPOS(&xmit_xdrs); /* for sendto */ 329*0Sstevel@tonic-gate 330*0Sstevel@tonic-gate /* 331*0Sstevel@tonic-gate * Right now the outgoing packet should be all serialized and 332*0Sstevel@tonic-gate * ready to go... Set up timers. 333*0Sstevel@tonic-gate */ 334*0Sstevel@tonic-gate 335*0Sstevel@tonic-gate xdelay = (rexmit == 0) ? RPC_REXMIT_MSEC : (rexmit * 1000); 336*0Sstevel@tonic-gate (void) setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&xdelay, 337*0Sstevel@tonic-gate sizeof (xdelay)); 338*0Sstevel@tonic-gate wait_time = (wait_time == 0) ? RPC_RCVWAIT_MSEC : (wait_time * 1000); 339*0Sstevel@tonic-gate 340*0Sstevel@tonic-gate wait_time += prom_gettime(); 341*0Sstevel@tonic-gate 342*0Sstevel@tonic-gate /* 343*0Sstevel@tonic-gate * send out the request. The first item in the receive buffer will 344*0Sstevel@tonic-gate * be the xid. Check if it is correct. 345*0Sstevel@tonic-gate */ 346*0Sstevel@tonic-gate errors = 0; 347*0Sstevel@tonic-gate rpc_error.re_status = RPC_TIMEDOUT; 348*0Sstevel@tonic-gate do { 349*0Sstevel@tonic-gate if (sendto(s, trm_msg, xmit_len, flags, (struct sockaddr *)to, 350*0Sstevel@tonic-gate sizeof (struct sockaddr_in)) < 0) { 351*0Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 352*0Sstevel@tonic-gate goto gt_error; 353*0Sstevel@tonic-gate } 354*0Sstevel@tonic-gate 355*0Sstevel@tonic-gate from_len = sizeof (struct sockaddr_in); 356*0Sstevel@tonic-gate while ((rcv_len = recvfrom(s, rcv_msg, NFSBUF_SIZE, 357*0Sstevel@tonic-gate MSG_DONTWAIT, (struct sockaddr *)from_who, 358*0Sstevel@tonic-gate &from_len)) > 0 || errors < RPC_ALLOWABLE_ERRORS) { 359*0Sstevel@tonic-gate if (rcv_len < 0) { 360*0Sstevel@tonic-gate if (errno == EWOULDBLOCK || 361*0Sstevel@tonic-gate errno == ETIMEDOUT) { 362*0Sstevel@tonic-gate break; /* timeout */ 363*0Sstevel@tonic-gate } 364*0Sstevel@tonic-gate rpc_error.re_status = RPC_CANTRECV; 365*0Sstevel@tonic-gate goto gt_error; 366*0Sstevel@tonic-gate } 367*0Sstevel@tonic-gate if (ntohl(*((uint32_t *)(rcv_msg))) != xid) { 368*0Sstevel@tonic-gate dprintf("brpc_call: xid: 0x%x != 0x%x\n", 369*0Sstevel@tonic-gate *(uint32_t *)(rcv_msg), xid); 370*0Sstevel@tonic-gate continue; 371*0Sstevel@tonic-gate } 372*0Sstevel@tonic-gate /* 373*0Sstevel@tonic-gate * Let's deserialize the data into our 'ret' buffer. 374*0Sstevel@tonic-gate */ 375*0Sstevel@tonic-gate xdrmem_create(&rcv_xdrs, rcv_msg, rcv_len, XDR_DECODE); 376*0Sstevel@tonic-gate if (xdr_replymsg(&rcv_xdrs, &reply) == FALSE) { 377*0Sstevel@tonic-gate rpc_error.re_status = RPC_CANTDECODERES; 378*0Sstevel@tonic-gate goto gt_error; 379*0Sstevel@tonic-gate } 380*0Sstevel@tonic-gate _seterr_reply(&reply, &rpc_error); 381*0Sstevel@tonic-gate switch (rpc_error.re_status) { 382*0Sstevel@tonic-gate case RPC_SUCCESS: 383*0Sstevel@tonic-gate /* 384*0Sstevel@tonic-gate * XXX - validate for unix and none 385*0Sstevel@tonic-gate * always return true. 386*0Sstevel@tonic-gate */ 387*0Sstevel@tonic-gate if (AUTH_VALIDATE(xmit_auth, 388*0Sstevel@tonic-gate &reply.acpted_rply.ar_verf) == FALSE) { 389*0Sstevel@tonic-gate rpc_error.re_status = RPC_AUTHERROR; 390*0Sstevel@tonic-gate rpc_error.re_why = AUTH_INVALIDRESP; 391*0Sstevel@tonic-gate errors++; 392*0Sstevel@tonic-gate } 393*0Sstevel@tonic-gate if (reply.acpted_rply.ar_verf.oa_base != 394*0Sstevel@tonic-gate 0) { 395*0Sstevel@tonic-gate xmit_xdrs.x_op = XDR_FREE; 396*0Sstevel@tonic-gate (void) xdr_opaque_auth( 397*0Sstevel@tonic-gate &xmit_xdrs, 398*0Sstevel@tonic-gate &reply.acpted_rply.ar_verf); 399*0Sstevel@tonic-gate } 400*0Sstevel@tonic-gate break; 401*0Sstevel@tonic-gate 402*0Sstevel@tonic-gate case RPC_AUTHERROR: 403*0Sstevel@tonic-gate /* 404*0Sstevel@tonic-gate * Let's see if our credentials need 405*0Sstevel@tonic-gate * refreshing 406*0Sstevel@tonic-gate */ 407*0Sstevel@tonic-gate if (nrefreshes > 0 && AUTH_REFRESH(xmit_auth, 408*0Sstevel@tonic-gate NULL, NULL)) { 409*0Sstevel@tonic-gate nrefreshes--; 410*0Sstevel@tonic-gate } 411*0Sstevel@tonic-gate errors++; 412*0Sstevel@tonic-gate break; 413*0Sstevel@tonic-gate 414*0Sstevel@tonic-gate case RPC_PROCUNAVAIL: 415*0Sstevel@tonic-gate /* 416*0Sstevel@tonic-gate * Might be a silly portmapper implementation 417*0Sstevel@tonic-gate * erroneously responding to our rpc broadcast 418*0Sstevel@tonic-gate * indirect portmapper call. For this 419*0Sstevel@tonic-gate * particular case, we don't increment the 420*0Sstevel@tonic-gate * error counter because we want to keep 421*0Sstevel@tonic-gate * sifting for successful replies... 422*0Sstevel@tonic-gate */ 423*0Sstevel@tonic-gate if (to->sin_addr.s_addr != 424*0Sstevel@tonic-gate ntohl(INADDR_BROADCAST)) 425*0Sstevel@tonic-gate errors++; 426*0Sstevel@tonic-gate break; 427*0Sstevel@tonic-gate 428*0Sstevel@tonic-gate case RPC_PROGVERSMISMATCH: 429*0Sstevel@tonic-gate /* 430*0Sstevel@tonic-gate * Successfully talked to server, but they 431*0Sstevel@tonic-gate * don't speak our lingo. 432*0Sstevel@tonic-gate */ 433*0Sstevel@tonic-gate goto gt_error; 434*0Sstevel@tonic-gate 435*0Sstevel@tonic-gate default: 436*0Sstevel@tonic-gate /* Just keep trying till there's no data... */ 437*0Sstevel@tonic-gate errors++; 438*0Sstevel@tonic-gate break; 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate 441*0Sstevel@tonic-gate if (rpc_error.re_status != RPC_SUCCESS) { 442*0Sstevel@tonic-gate dprintf("brpc_call: from: %s, error: ", 443*0Sstevel@tonic-gate inet_ntoa(from_who->sin_addr)); 444*0Sstevel@tonic-gate rpc_disperr(&rpc_error); 445*0Sstevel@tonic-gate } else 446*0Sstevel@tonic-gate break; 447*0Sstevel@tonic-gate } 448*0Sstevel@tonic-gate 449*0Sstevel@tonic-gate /* 450*0Sstevel@tonic-gate * If we're having trouble reassembling datagrams, let the 451*0Sstevel@tonic-gate * application know ASAP so that it can take the appropriate 452*0Sstevel@tonic-gate * actions. 453*0Sstevel@tonic-gate */ 454*0Sstevel@tonic-gate 455*0Sstevel@tonic-gate } while (rpc_error.re_status != RPC_SUCCESS && errno != ETIMEDOUT && 456*0Sstevel@tonic-gate prom_gettime() < wait_time); 457*0Sstevel@tonic-gate 458*0Sstevel@tonic-gate gt_error: 459*0Sstevel@tonic-gate if (xmit_auth != NULL) 460*0Sstevel@tonic-gate AUTH_DESTROY(xmit_auth); 461*0Sstevel@tonic-gate 462*0Sstevel@tonic-gate if (trm_msg != NULL) 463*0Sstevel@tonic-gate bkmem_free(trm_msg, trm_len); 464*0Sstevel@tonic-gate if (rcv_msg != NULL) 465*0Sstevel@tonic-gate bkmem_free(rcv_msg, NFSBUF_SIZE); 466*0Sstevel@tonic-gate 467*0Sstevel@tonic-gate if (rpc_error.re_status != RPC_SUCCESS) 468*0Sstevel@tonic-gate rpc_disperr(&rpc_error); 469*0Sstevel@tonic-gate 470*0Sstevel@tonic-gate /* 471*0Sstevel@tonic-gate * socket calls reset errno. Since we want to hold onto the errno 472*0Sstevel@tonic-gate * value if it is ETIMEDOUT to communicate to our caller that this 473*0Sstevel@tonic-gate * RPC_TIMEDOUT situation is due to a stack problem (we're getting 474*0Sstevel@tonic-gate * a reply, but the stack simply can't assemble it.), we need to 475*0Sstevel@tonic-gate * preserve errno's value over the socket_close(). 476*0Sstevel@tonic-gate */ 477*0Sstevel@tonic-gate preserve_errno = (errno == ETIMEDOUT) ? errno : 0; 478*0Sstevel@tonic-gate (void) socket_close(s); 479*0Sstevel@tonic-gate errno = preserve_errno; 480*0Sstevel@tonic-gate 481*0Sstevel@tonic-gate return (rpc_error.re_status); 482*0Sstevel@tonic-gate } 483