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 5*9f1fc992Sss146032 * Common Development and Distribution License (the "License"). 6*9f1fc992Sss146032 * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 21*9f1fc992Sss146032 227c478bd9Sstevel@tonic-gate /* 23*9f1fc992Sss146032 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate * 267c478bd9Sstevel@tonic-gate * This file contains a simple implementation of RPC. Standard XDR is 277c478bd9Sstevel@tonic-gate * used. 287c478bd9Sstevel@tonic-gate */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 317c478bd9Sstevel@tonic-gate 327c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h> 337c478bd9Sstevel@tonic-gate #include <rpc/types.h> 347c478bd9Sstevel@tonic-gate #include <errno.h> 357c478bd9Sstevel@tonic-gate #include <sys/socket.h> 367c478bd9Sstevel@tonic-gate #include <netinet/in.h> 377c478bd9Sstevel@tonic-gate #include "socket_inet.h" 387c478bd9Sstevel@tonic-gate #include "ipv4.h" 397c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 407c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 417c478bd9Sstevel@tonic-gate #include <rpc/auth_sys.h> 427c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h> 437c478bd9Sstevel@tonic-gate #include <sys/t_lock.h> 447c478bd9Sstevel@tonic-gate #include <netdb.h> 457c478bd9Sstevel@tonic-gate #include "clnt.h" 467c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 477c478bd9Sstevel@tonic-gate #include "brpc.h" 487c478bd9Sstevel@tonic-gate #include "auth_inet.h" 497c478bd9Sstevel@tonic-gate #include "pmap.h" 507c478bd9Sstevel@tonic-gate #include <sys/promif.h> 517c478bd9Sstevel@tonic-gate #include "nfs_inet.h" 527c478bd9Sstevel@tonic-gate #include <rpcsvc/nfs_prot.h> 537c478bd9Sstevel@tonic-gate #include <rpc/auth_unix.h> 547c478bd9Sstevel@tonic-gate #include <sys/salib.h> 557c478bd9Sstevel@tonic-gate #include "mac.h" 567c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 577c478bd9Sstevel@tonic-gate 587c478bd9Sstevel@tonic-gate #define dprintf if (boothowto & RB_DEBUG) printf 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate static struct in_addr cached_destination; 617c478bd9Sstevel@tonic-gate 627c478bd9Sstevel@tonic-gate void 637c478bd9Sstevel@tonic-gate rpc_disperr(struct rpc_err *stat) 647c478bd9Sstevel@tonic-gate { 657c478bd9Sstevel@tonic-gate if (boothowto & RB_DEBUG) { 667c478bd9Sstevel@tonic-gate switch (stat->re_status) { 677c478bd9Sstevel@tonic-gate case RPC_CANTENCODEARGS: 687c478bd9Sstevel@tonic-gate printf("RPC: Can't encode arguments.\n"); 697c478bd9Sstevel@tonic-gate break; 707c478bd9Sstevel@tonic-gate case RPC_CANTDECODERES: 717c478bd9Sstevel@tonic-gate printf("RPC: Can't decode result.\n"); 727c478bd9Sstevel@tonic-gate break; 737c478bd9Sstevel@tonic-gate case RPC_CANTSEND: 747c478bd9Sstevel@tonic-gate printf("RPC: Unable to send (%s).\n", 757c478bd9Sstevel@tonic-gate strerror(errno)); 767c478bd9Sstevel@tonic-gate break; 777c478bd9Sstevel@tonic-gate case RPC_CANTRECV: 787c478bd9Sstevel@tonic-gate printf("RPC: Unable to receive (%s).\n", 797c478bd9Sstevel@tonic-gate strerror(errno)); 807c478bd9Sstevel@tonic-gate break; 817c478bd9Sstevel@tonic-gate case RPC_TIMEDOUT: 827c478bd9Sstevel@tonic-gate printf("RPC: Timed out.\n"); 837c478bd9Sstevel@tonic-gate break; 847c478bd9Sstevel@tonic-gate case RPC_VERSMISMATCH: 857c478bd9Sstevel@tonic-gate printf("RPC: Incompatible versions of RPC.\n"); 867c478bd9Sstevel@tonic-gate break; 877c478bd9Sstevel@tonic-gate case RPC_AUTHERROR: 887c478bd9Sstevel@tonic-gate printf("RPC: Authentication error:\n"); 897c478bd9Sstevel@tonic-gate switch (stat->re_why) { 907c478bd9Sstevel@tonic-gate case AUTH_BADCRED: 917c478bd9Sstevel@tonic-gate printf("remote: bogus credentials " 927c478bd9Sstevel@tonic-gate "(seal broken).\n"); 937c478bd9Sstevel@tonic-gate break; 947c478bd9Sstevel@tonic-gate case AUTH_REJECTEDCRED: 957c478bd9Sstevel@tonic-gate printf("remote: client should begin new " 967c478bd9Sstevel@tonic-gate "session.\n"); 977c478bd9Sstevel@tonic-gate break; 987c478bd9Sstevel@tonic-gate case AUTH_BADVERF: 997c478bd9Sstevel@tonic-gate printf("remote: bogus verifier " 1007c478bd9Sstevel@tonic-gate "(seal broken).\n"); 1017c478bd9Sstevel@tonic-gate break; 1027c478bd9Sstevel@tonic-gate case AUTH_REJECTEDVERF: 1037c478bd9Sstevel@tonic-gate printf("remote: verifier expired or was " 1047c478bd9Sstevel@tonic-gate "replayed.\n"); 1057c478bd9Sstevel@tonic-gate break; 1067c478bd9Sstevel@tonic-gate case AUTH_TOOWEAK: 1077c478bd9Sstevel@tonic-gate printf("remote: rejected due to security " 1087c478bd9Sstevel@tonic-gate "reasons.\n"); 1097c478bd9Sstevel@tonic-gate break; 1107c478bd9Sstevel@tonic-gate case AUTH_INVALIDRESP: 1117c478bd9Sstevel@tonic-gate printf("local: bogus response verifier.\n"); 1127c478bd9Sstevel@tonic-gate break; 1137c478bd9Sstevel@tonic-gate case AUTH_FAILED: 1147c478bd9Sstevel@tonic-gate /* FALLTHRU */ 1157c478bd9Sstevel@tonic-gate default: 1167c478bd9Sstevel@tonic-gate printf("local: unknown error.\n"); 1177c478bd9Sstevel@tonic-gate break; 1187c478bd9Sstevel@tonic-gate } 1197c478bd9Sstevel@tonic-gate break; 1207c478bd9Sstevel@tonic-gate case RPC_PROGUNAVAIL: 1217c478bd9Sstevel@tonic-gate printf("RPC: Program unavailable.\n"); 1227c478bd9Sstevel@tonic-gate break; 1237c478bd9Sstevel@tonic-gate case RPC_PROGVERSMISMATCH: 1247c478bd9Sstevel@tonic-gate printf("RPC: Program/version mismatch.\n"); 1257c478bd9Sstevel@tonic-gate break; 1267c478bd9Sstevel@tonic-gate case RPC_PROCUNAVAIL: 1277c478bd9Sstevel@tonic-gate printf("RPC: Procedure unavailable.\n"); 1287c478bd9Sstevel@tonic-gate break; 1297c478bd9Sstevel@tonic-gate case RPC_CANTDECODEARGS: 1307c478bd9Sstevel@tonic-gate printf("RPC: Server can't decode arguments.\n"); 1317c478bd9Sstevel@tonic-gate break; 1327c478bd9Sstevel@tonic-gate case RPC_SYSTEMERROR: 1337c478bd9Sstevel@tonic-gate printf("RPC: Remote system error.\n"); 1347c478bd9Sstevel@tonic-gate break; 1357c478bd9Sstevel@tonic-gate case RPC_UNKNOWNHOST: 1367c478bd9Sstevel@tonic-gate printf("RPC: Unknown host.\n"); 1377c478bd9Sstevel@tonic-gate break; 1387c478bd9Sstevel@tonic-gate case RPC_UNKNOWNPROTO: 1397c478bd9Sstevel@tonic-gate printf("RPC: Unknown protocol.\n"); 1407c478bd9Sstevel@tonic-gate break; 1417c478bd9Sstevel@tonic-gate case RPC_PMAPFAILURE: 1427c478bd9Sstevel@tonic-gate printf("RPC: Port mapper failure.\n"); 1437c478bd9Sstevel@tonic-gate break; 1447c478bd9Sstevel@tonic-gate case RPC_PROGNOTREGISTERED: 1457c478bd9Sstevel@tonic-gate printf("RPC: Program not registered.\n"); 1467c478bd9Sstevel@tonic-gate break; 1477c478bd9Sstevel@tonic-gate case RPC_FAILED: 1487c478bd9Sstevel@tonic-gate printf("RPC: Failed (unspecified error).\n"); 1497c478bd9Sstevel@tonic-gate break; 1507c478bd9Sstevel@tonic-gate default: 1517c478bd9Sstevel@tonic-gate printf("RPC: (unknown error code).\n"); 1527c478bd9Sstevel@tonic-gate break; 1537c478bd9Sstevel@tonic-gate } 1547c478bd9Sstevel@tonic-gate } 1557c478bd9Sstevel@tonic-gate } 1567c478bd9Sstevel@tonic-gate 1577c478bd9Sstevel@tonic-gate /* 1587c478bd9Sstevel@tonic-gate * rpc_hdr: sets the fields in the rpc msg header. 1597c478bd9Sstevel@tonic-gate * 1607c478bd9Sstevel@tonic-gate * Returns: TRUE on success, FALSE if failure. 1617c478bd9Sstevel@tonic-gate */ 1627c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 1637c478bd9Sstevel@tonic-gate static bool_t 1647c478bd9Sstevel@tonic-gate rpc_hdr(XDR *xdrs, uint_t xid, rpcprog_t prog, rpcvers_t vers, rpcproc_t proc) 1657c478bd9Sstevel@tonic-gate { 1667c478bd9Sstevel@tonic-gate struct rpc_msg call_msg; 1677c478bd9Sstevel@tonic-gate 1687c478bd9Sstevel@tonic-gate /* setup header */ 1697c478bd9Sstevel@tonic-gate call_msg.rm_xid = xid; 1707c478bd9Sstevel@tonic-gate call_msg.rm_direction = CALL; 1717c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = (rpcvers_t)RPC_MSG_VERSION; 1727c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_prog = prog; 1737c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_vers = vers; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate /* xdr the header. */ 1767c478bd9Sstevel@tonic-gate if (xdr_callhdr(xdrs, &call_msg) == FALSE) 1777c478bd9Sstevel@tonic-gate return (FALSE); 1787c478bd9Sstevel@tonic-gate else 1797c478bd9Sstevel@tonic-gate return (TRUE); 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* 1837c478bd9Sstevel@tonic-gate * our version of brpc_call(). We cache in portnumber in to->sin_port for 1847c478bd9Sstevel@tonic-gate * your convenience. to and from addresses are taken and received in network 1857c478bd9Sstevel@tonic-gate * order. 1867c478bd9Sstevel@tonic-gate */ 1877c478bd9Sstevel@tonic-gate enum clnt_stat 1887c478bd9Sstevel@tonic-gate brpc_call( 1897c478bd9Sstevel@tonic-gate rpcprog_t prog, /* rpc program number to call. */ 1907c478bd9Sstevel@tonic-gate rpcvers_t vers, /* rpc program version */ 1917c478bd9Sstevel@tonic-gate rpcproc_t proc, /* rpc procedure to call */ 1927c478bd9Sstevel@tonic-gate xdrproc_t in_xdr, /* routine to serialize arguments */ 1937c478bd9Sstevel@tonic-gate caddr_t args, /* arg vector for remote call */ 1947c478bd9Sstevel@tonic-gate xdrproc_t out_xdr, /* routine to deserialize results */ 1957c478bd9Sstevel@tonic-gate caddr_t ret, /* addr of buf to place results in */ 1967c478bd9Sstevel@tonic-gate int rexmit, /* retransmission interval (secs) */ 1977c478bd9Sstevel@tonic-gate int wait_time, /* how long (secs) to wait (resp) */ 1987c478bd9Sstevel@tonic-gate struct sockaddr_in *to, /* destination */ 1997c478bd9Sstevel@tonic-gate struct sockaddr_in *from_who, /* responder's port/address */ 2007c478bd9Sstevel@tonic-gate uint_t auth) /* type of auth wanted. */ 2017c478bd9Sstevel@tonic-gate { 2027c478bd9Sstevel@tonic-gate int s; 2037c478bd9Sstevel@tonic-gate char hostname[MAXHOSTNAMELEN]; 2047c478bd9Sstevel@tonic-gate struct sockaddr_in from; /* us. */ 2057c478bd9Sstevel@tonic-gate socklen_t from_len; 2067c478bd9Sstevel@tonic-gate XDR xmit_xdrs, rcv_xdrs; /* xdr memory */ 2077c478bd9Sstevel@tonic-gate AUTH *xmit_auth; /* our chosen auth cookie */ 2087c478bd9Sstevel@tonic-gate gid_t fake_gids = 1; /* fake gids list for auth_unix */ 2097c478bd9Sstevel@tonic-gate caddr_t trm_msg, rcv_msg; /* outgoing/incoming rpc mesgs */ 2107c478bd9Sstevel@tonic-gate struct rpc_msg reply; /* our reply msg header */ 2117c478bd9Sstevel@tonic-gate int trm_len, rcv_len; 2127c478bd9Sstevel@tonic-gate struct rpc_err rpc_error; /* to store RPC errors in on rcv. */ 2137c478bd9Sstevel@tonic-gate static uint_t xid; /* current xid */ 2147c478bd9Sstevel@tonic-gate uint_t xmit_len; /* How much of the buffer we used */ 2157c478bd9Sstevel@tonic-gate int nrefreshes = 2; /* # of times to refresh cred */ 2167c478bd9Sstevel@tonic-gate int flags = 0; /* send flags */ 2177c478bd9Sstevel@tonic-gate uint_t xdelay; 2187c478bd9Sstevel@tonic-gate int errors, preserve_errno; 2197c478bd9Sstevel@tonic-gate uint32_t timeout; 2207c478bd9Sstevel@tonic-gate socklen_t optlen; 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate xmit_auth = NULL; 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate trm_len = mac_get_mtu(); 2257c478bd9Sstevel@tonic-gate trm_msg = bkmem_alloc(trm_len); 2267c478bd9Sstevel@tonic-gate rcv_msg = bkmem_alloc(NFSBUF_SIZE); 2277c478bd9Sstevel@tonic-gate 2287c478bd9Sstevel@tonic-gate if (trm_msg == NULL || rcv_msg == NULL) { 2297c478bd9Sstevel@tonic-gate errno = ENOMEM; 2307c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 2317c478bd9Sstevel@tonic-gate goto gt_error; 2327c478bd9Sstevel@tonic-gate } 2337c478bd9Sstevel@tonic-gate 2347c478bd9Sstevel@tonic-gate if ((s = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { 2357c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 2367c478bd9Sstevel@tonic-gate goto gt_error; 2377c478bd9Sstevel@tonic-gate } 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate if (dontroute) { 2407c478bd9Sstevel@tonic-gate (void) setsockopt(s, SOL_SOCKET, SO_DONTROUTE, 2417c478bd9Sstevel@tonic-gate (const void *)&dontroute, sizeof (dontroute)); 2427c478bd9Sstevel@tonic-gate } 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate if (to->sin_addr.s_addr == cached_destination.s_addr) { 2457c478bd9Sstevel@tonic-gate optlen = sizeof (timeout); 2467c478bd9Sstevel@tonic-gate (void) getsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&timeout, 2477c478bd9Sstevel@tonic-gate &optlen); 2487c478bd9Sstevel@tonic-gate } else { 2497c478bd9Sstevel@tonic-gate cached_destination.s_addr = htonl(INADDR_ANY); 2507c478bd9Sstevel@tonic-gate } 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate /* Bind our endpoint. */ 2537c478bd9Sstevel@tonic-gate from.sin_family = AF_INET; 2547c478bd9Sstevel@tonic-gate ipv4_getipaddr(&from.sin_addr); 2557c478bd9Sstevel@tonic-gate from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); 2567c478bd9Sstevel@tonic-gate from.sin_port = get_source_port(B_TRUE); 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate if (bind(s, (struct sockaddr *)&from, sizeof (from)) < 0) { 2597c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 2607c478bd9Sstevel@tonic-gate goto gt_error; 2617c478bd9Sstevel@tonic-gate } 2627c478bd9Sstevel@tonic-gate 2637c478bd9Sstevel@tonic-gate bzero((caddr_t)&rpc_error, sizeof (struct rpc_err)); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate /* initialize reply's rpc_msg struct, so we can decode later. */ 2667c478bd9Sstevel@tonic-gate reply.acpted_rply.ar_verf = _null_auth; /* struct copy */ 2677c478bd9Sstevel@tonic-gate reply.acpted_rply.ar_results.where = ret; 2687c478bd9Sstevel@tonic-gate reply.acpted_rply.ar_results.proc = out_xdr; 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate if (ntohs(to->sin_port) == 0) { 2717c478bd9Sstevel@tonic-gate /* snag the udp port we need. */ 2727c478bd9Sstevel@tonic-gate if ((to->sin_port = (in_port_t)bpmap_getport(prog, vers, 2737c478bd9Sstevel@tonic-gate &(rpc_error.re_status), to, NULL)) == 0) 2747c478bd9Sstevel@tonic-gate goto gt_error; 2757c478bd9Sstevel@tonic-gate to->sin_port = htons(to->sin_port); 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate 2787c478bd9Sstevel@tonic-gate /* generate xid - increment */ 2797c478bd9Sstevel@tonic-gate if (xid == 0) 2807c478bd9Sstevel@tonic-gate xid = (uint_t)(prom_gettime() / 1000) + 1; 2817c478bd9Sstevel@tonic-gate else 2827c478bd9Sstevel@tonic-gate xid++; 2837c478bd9Sstevel@tonic-gate 2847c478bd9Sstevel@tonic-gate /* set up outgoing pkt as xdr modified. */ 2857c478bd9Sstevel@tonic-gate xdrmem_create(&xmit_xdrs, trm_msg, trm_len, XDR_ENCODE); 2867c478bd9Sstevel@tonic-gate 2877c478bd9Sstevel@tonic-gate /* setup rpc header */ 2887c478bd9Sstevel@tonic-gate if (rpc_hdr(&xmit_xdrs, xid, prog, vers, proc) != TRUE) { 2897c478bd9Sstevel@tonic-gate dprintf("brpc_call: cannot setup rpc header.\n"); 2907c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_FAILED; 2917c478bd9Sstevel@tonic-gate goto gt_error; 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate 2947c478bd9Sstevel@tonic-gate /* setup authentication */ 2957c478bd9Sstevel@tonic-gate switch (auth) { 2967c478bd9Sstevel@tonic-gate case AUTH_NONE: 2977c478bd9Sstevel@tonic-gate xmit_auth = authnone_create(); 2987c478bd9Sstevel@tonic-gate break; 2997c478bd9Sstevel@tonic-gate case AUTH_UNIX: 3007c478bd9Sstevel@tonic-gate /* 3017c478bd9Sstevel@tonic-gate * Assumes we've configured the stack and thus know our 3027c478bd9Sstevel@tonic-gate * IP address/hostname, either by using DHCP or rarp/bootparams. 3037c478bd9Sstevel@tonic-gate */ 3047c478bd9Sstevel@tonic-gate gethostname(hostname, sizeof (hostname)); 3057c478bd9Sstevel@tonic-gate xmit_auth = authunix_create(hostname, 0, 1, 1, &fake_gids); 3067c478bd9Sstevel@tonic-gate break; 3077c478bd9Sstevel@tonic-gate default: 3087c478bd9Sstevel@tonic-gate dprintf("brpc_call: Unsupported authentication type: %d\n", 3097c478bd9Sstevel@tonic-gate auth); 3107c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_AUTHERROR; 3117c478bd9Sstevel@tonic-gate goto gt_error; 3127c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 3137c478bd9Sstevel@tonic-gate } 3147c478bd9Sstevel@tonic-gate 3157c478bd9Sstevel@tonic-gate /* 3167c478bd9Sstevel@tonic-gate * rpc_hdr puts everything in the xmit buffer for the header 3177c478bd9Sstevel@tonic-gate * EXCEPT the proc. Put it, and our authentication info into 3187c478bd9Sstevel@tonic-gate * it now, serializing as we go. We will be at the place where 3197c478bd9Sstevel@tonic-gate * we left off. 3207c478bd9Sstevel@tonic-gate */ 3217c478bd9Sstevel@tonic-gate xmit_xdrs.x_op = XDR_ENCODE; 3227c478bd9Sstevel@tonic-gate if ((XDR_PUTINT32(&xmit_xdrs, (int32_t *)&proc) == FALSE) || 3237c478bd9Sstevel@tonic-gate (AUTH_MARSHALL(xmit_auth, &xmit_xdrs, NULL) == FALSE) || 3247c478bd9Sstevel@tonic-gate ((*in_xdr)(&xmit_xdrs, args) == FALSE)) { 3257c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_CANTENCODEARGS; 3267c478bd9Sstevel@tonic-gate goto gt_error; 3277c478bd9Sstevel@tonic-gate } else 3287c478bd9Sstevel@tonic-gate xmit_len = (int)XDR_GETPOS(&xmit_xdrs); /* for sendto */ 3297c478bd9Sstevel@tonic-gate 3307c478bd9Sstevel@tonic-gate /* 3317c478bd9Sstevel@tonic-gate * Right now the outgoing packet should be all serialized and 3327c478bd9Sstevel@tonic-gate * ready to go... Set up timers. 3337c478bd9Sstevel@tonic-gate */ 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate xdelay = (rexmit == 0) ? RPC_REXMIT_MSEC : (rexmit * 1000); 3367c478bd9Sstevel@tonic-gate (void) setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, (void *)&xdelay, 3377c478bd9Sstevel@tonic-gate sizeof (xdelay)); 3387c478bd9Sstevel@tonic-gate wait_time = (wait_time == 0) ? RPC_RCVWAIT_MSEC : (wait_time * 1000); 3397c478bd9Sstevel@tonic-gate 3407c478bd9Sstevel@tonic-gate wait_time += prom_gettime(); 3417c478bd9Sstevel@tonic-gate 3427c478bd9Sstevel@tonic-gate /* 3437c478bd9Sstevel@tonic-gate * send out the request. The first item in the receive buffer will 3447c478bd9Sstevel@tonic-gate * be the xid. Check if it is correct. 3457c478bd9Sstevel@tonic-gate */ 3467c478bd9Sstevel@tonic-gate errors = 0; 3477c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_TIMEDOUT; 3487c478bd9Sstevel@tonic-gate do { 3497c478bd9Sstevel@tonic-gate if (sendto(s, trm_msg, xmit_len, flags, (struct sockaddr *)to, 3507c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)) < 0) { 351*9f1fc992Sss146032 /* 352*9f1fc992Sss146032 * If errno is set to ETIMEDOUT, return 353*9f1fc992Sss146032 * with RPC status as RPC_TIMEDOUT. Calling 354*9f1fc992Sss146032 * funciton will take care of this error by 355*9f1fc992Sss146032 * retrying the RPC call. 356*9f1fc992Sss146032 */ 357*9f1fc992Sss146032 if (errno == ETIMEDOUT) { 358*9f1fc992Sss146032 rpc_error.re_status = RPC_TIMEDOUT; 359*9f1fc992Sss146032 } else { 3607c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_CANTSEND; 361*9f1fc992Sss146032 } 3627c478bd9Sstevel@tonic-gate goto gt_error; 3637c478bd9Sstevel@tonic-gate } 3647c478bd9Sstevel@tonic-gate 3657c478bd9Sstevel@tonic-gate from_len = sizeof (struct sockaddr_in); 3667c478bd9Sstevel@tonic-gate while ((rcv_len = recvfrom(s, rcv_msg, NFSBUF_SIZE, 3677c478bd9Sstevel@tonic-gate MSG_DONTWAIT, (struct sockaddr *)from_who, 3687c478bd9Sstevel@tonic-gate &from_len)) > 0 || errors < RPC_ALLOWABLE_ERRORS) { 3697c478bd9Sstevel@tonic-gate if (rcv_len < 0) { 3707c478bd9Sstevel@tonic-gate if (errno == EWOULDBLOCK || 3717c478bd9Sstevel@tonic-gate errno == ETIMEDOUT) { 3727c478bd9Sstevel@tonic-gate break; /* timeout */ 3737c478bd9Sstevel@tonic-gate } 3747c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_CANTRECV; 3757c478bd9Sstevel@tonic-gate goto gt_error; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate if (ntohl(*((uint32_t *)(rcv_msg))) != xid) { 3787c478bd9Sstevel@tonic-gate dprintf("brpc_call: xid: 0x%x != 0x%x\n", 3797c478bd9Sstevel@tonic-gate *(uint32_t *)(rcv_msg), xid); 3807c478bd9Sstevel@tonic-gate continue; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate /* 3837c478bd9Sstevel@tonic-gate * Let's deserialize the data into our 'ret' buffer. 3847c478bd9Sstevel@tonic-gate */ 3857c478bd9Sstevel@tonic-gate xdrmem_create(&rcv_xdrs, rcv_msg, rcv_len, XDR_DECODE); 3867c478bd9Sstevel@tonic-gate if (xdr_replymsg(&rcv_xdrs, &reply) == FALSE) { 3877c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_CANTDECODERES; 3887c478bd9Sstevel@tonic-gate goto gt_error; 3897c478bd9Sstevel@tonic-gate } 3907c478bd9Sstevel@tonic-gate _seterr_reply(&reply, &rpc_error); 3917c478bd9Sstevel@tonic-gate switch (rpc_error.re_status) { 3927c478bd9Sstevel@tonic-gate case RPC_SUCCESS: 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * XXX - validate for unix and none 3957c478bd9Sstevel@tonic-gate * always return true. 3967c478bd9Sstevel@tonic-gate */ 3977c478bd9Sstevel@tonic-gate if (AUTH_VALIDATE(xmit_auth, 3987c478bd9Sstevel@tonic-gate &reply.acpted_rply.ar_verf) == FALSE) { 3997c478bd9Sstevel@tonic-gate rpc_error.re_status = RPC_AUTHERROR; 4007c478bd9Sstevel@tonic-gate rpc_error.re_why = AUTH_INVALIDRESP; 4017c478bd9Sstevel@tonic-gate errors++; 4027c478bd9Sstevel@tonic-gate } 4037c478bd9Sstevel@tonic-gate if (reply.acpted_rply.ar_verf.oa_base != 4047c478bd9Sstevel@tonic-gate 0) { 4057c478bd9Sstevel@tonic-gate xmit_xdrs.x_op = XDR_FREE; 4067c478bd9Sstevel@tonic-gate (void) xdr_opaque_auth( 4077c478bd9Sstevel@tonic-gate &xmit_xdrs, 4087c478bd9Sstevel@tonic-gate &reply.acpted_rply.ar_verf); 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate break; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate case RPC_AUTHERROR: 4137c478bd9Sstevel@tonic-gate /* 4147c478bd9Sstevel@tonic-gate * Let's see if our credentials need 4157c478bd9Sstevel@tonic-gate * refreshing 4167c478bd9Sstevel@tonic-gate */ 4177c478bd9Sstevel@tonic-gate if (nrefreshes > 0 && AUTH_REFRESH(xmit_auth, 4187c478bd9Sstevel@tonic-gate NULL, NULL)) { 4197c478bd9Sstevel@tonic-gate nrefreshes--; 4207c478bd9Sstevel@tonic-gate } 4217c478bd9Sstevel@tonic-gate errors++; 4227c478bd9Sstevel@tonic-gate break; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate case RPC_PROCUNAVAIL: 4257c478bd9Sstevel@tonic-gate /* 4267c478bd9Sstevel@tonic-gate * Might be a silly portmapper implementation 4277c478bd9Sstevel@tonic-gate * erroneously responding to our rpc broadcast 4287c478bd9Sstevel@tonic-gate * indirect portmapper call. For this 4297c478bd9Sstevel@tonic-gate * particular case, we don't increment the 4307c478bd9Sstevel@tonic-gate * error counter because we want to keep 4317c478bd9Sstevel@tonic-gate * sifting for successful replies... 4327c478bd9Sstevel@tonic-gate */ 4337c478bd9Sstevel@tonic-gate if (to->sin_addr.s_addr != 4347c478bd9Sstevel@tonic-gate ntohl(INADDR_BROADCAST)) 4357c478bd9Sstevel@tonic-gate errors++; 4367c478bd9Sstevel@tonic-gate break; 4377c478bd9Sstevel@tonic-gate 4387c478bd9Sstevel@tonic-gate case RPC_PROGVERSMISMATCH: 4397c478bd9Sstevel@tonic-gate /* 4407c478bd9Sstevel@tonic-gate * Successfully talked to server, but they 4417c478bd9Sstevel@tonic-gate * don't speak our lingo. 4427c478bd9Sstevel@tonic-gate */ 4437c478bd9Sstevel@tonic-gate goto gt_error; 4447c478bd9Sstevel@tonic-gate 4457c478bd9Sstevel@tonic-gate default: 4467c478bd9Sstevel@tonic-gate /* Just keep trying till there's no data... */ 4477c478bd9Sstevel@tonic-gate errors++; 4487c478bd9Sstevel@tonic-gate break; 4497c478bd9Sstevel@tonic-gate } 4507c478bd9Sstevel@tonic-gate 4517c478bd9Sstevel@tonic-gate if (rpc_error.re_status != RPC_SUCCESS) { 4527c478bd9Sstevel@tonic-gate dprintf("brpc_call: from: %s, error: ", 4537c478bd9Sstevel@tonic-gate inet_ntoa(from_who->sin_addr)); 4547c478bd9Sstevel@tonic-gate rpc_disperr(&rpc_error); 4557c478bd9Sstevel@tonic-gate } else 4567c478bd9Sstevel@tonic-gate break; 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * If we're having trouble reassembling datagrams, let the 4617c478bd9Sstevel@tonic-gate * application know ASAP so that it can take the appropriate 4627c478bd9Sstevel@tonic-gate * actions. 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate 4657c478bd9Sstevel@tonic-gate } while (rpc_error.re_status != RPC_SUCCESS && errno != ETIMEDOUT && 4667c478bd9Sstevel@tonic-gate prom_gettime() < wait_time); 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate gt_error: 4697c478bd9Sstevel@tonic-gate if (xmit_auth != NULL) 4707c478bd9Sstevel@tonic-gate AUTH_DESTROY(xmit_auth); 4717c478bd9Sstevel@tonic-gate 4727c478bd9Sstevel@tonic-gate if (trm_msg != NULL) 4737c478bd9Sstevel@tonic-gate bkmem_free(trm_msg, trm_len); 4747c478bd9Sstevel@tonic-gate if (rcv_msg != NULL) 4757c478bd9Sstevel@tonic-gate bkmem_free(rcv_msg, NFSBUF_SIZE); 4767c478bd9Sstevel@tonic-gate 4777c478bd9Sstevel@tonic-gate if (rpc_error.re_status != RPC_SUCCESS) 4787c478bd9Sstevel@tonic-gate rpc_disperr(&rpc_error); 4797c478bd9Sstevel@tonic-gate 4807c478bd9Sstevel@tonic-gate /* 4817c478bd9Sstevel@tonic-gate * socket calls reset errno. Since we want to hold onto the errno 4827c478bd9Sstevel@tonic-gate * value if it is ETIMEDOUT to communicate to our caller that this 4837c478bd9Sstevel@tonic-gate * RPC_TIMEDOUT situation is due to a stack problem (we're getting 4847c478bd9Sstevel@tonic-gate * a reply, but the stack simply can't assemble it.), we need to 4857c478bd9Sstevel@tonic-gate * preserve errno's value over the socket_close(). 4867c478bd9Sstevel@tonic-gate */ 4877c478bd9Sstevel@tonic-gate preserve_errno = (errno == ETIMEDOUT) ? errno : 0; 4887c478bd9Sstevel@tonic-gate (void) socket_close(s); 4897c478bd9Sstevel@tonic-gate errno = preserve_errno; 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate return (rpc_error.re_status); 4927c478bd9Sstevel@tonic-gate } 493