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 277c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 287c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 297c478bd9Sstevel@tonic-gate 307c478bd9Sstevel@tonic-gate /* 317c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 327c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 337c478bd9Sstevel@tonic-gate */ 347c478bd9Sstevel@tonic-gate 357c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 367c478bd9Sstevel@tonic-gate 377c478bd9Sstevel@tonic-gate /* 387c478bd9Sstevel@tonic-gate * Boot subsystem client side rpc 397c478bd9Sstevel@tonic-gate */ 407c478bd9Sstevel@tonic-gate 417c478bd9Sstevel@tonic-gate #include <sys/errno.h> 427c478bd9Sstevel@tonic-gate #include <rpc/types.h> 437c478bd9Sstevel@tonic-gate #include <sys/socket.h> 447c478bd9Sstevel@tonic-gate #include <netinet/in.h> 457c478bd9Sstevel@tonic-gate #include "socket_inet.h" 467c478bd9Sstevel@tonic-gate #include "ipv4.h" 477c478bd9Sstevel@tonic-gate #include "clnt.h" 487c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 497c478bd9Sstevel@tonic-gate #include "brpc.h" 507c478bd9Sstevel@tonic-gate #include "pmap.h" 517c478bd9Sstevel@tonic-gate #include <sys/promif.h> 527c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 537c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 547c478bd9Sstevel@tonic-gate #include <rpc/auth_sys.h> 557c478bd9Sstevel@tonic-gate #include "auth_inet.h" 567c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h> 577c478bd9Sstevel@tonic-gate #include <sys/salib.h> 587c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 597c478bd9Sstevel@tonic-gate 607c478bd9Sstevel@tonic-gate #define dprintf if (boothowto & RB_DEBUG) printf 617c478bd9Sstevel@tonic-gate 62*9f1fc992Sss146032 /* retries to send RPC message when sendto fails */ 63*9f1fc992Sss146032 #define RPC_UDP_SEND_RETRIES 3 64*9f1fc992Sss146032 657c478bd9Sstevel@tonic-gate extern int errno; 667c478bd9Sstevel@tonic-gate 677c478bd9Sstevel@tonic-gate /* 687c478bd9Sstevel@tonic-gate * If we create another clnt type this should be 697c478bd9Sstevel@tonic-gate * moved to a common file 707c478bd9Sstevel@tonic-gate */ 717c478bd9Sstevel@tonic-gate struct rpc_createerr rpc_createerr; 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate static struct clnt_ops *clntbudp_ops(); 747c478bd9Sstevel@tonic-gate 757c478bd9Sstevel@tonic-gate /* 767c478bd9Sstevel@tonic-gate * Private data kept per client handle 777c478bd9Sstevel@tonic-gate */ 787c478bd9Sstevel@tonic-gate struct cu_data { 797c478bd9Sstevel@tonic-gate int cu_sock; 807c478bd9Sstevel@tonic-gate bool_t cu_closeit; 817c478bd9Sstevel@tonic-gate struct sockaddr_in cu_raddr; 827c478bd9Sstevel@tonic-gate int cu_rlen; 837c478bd9Sstevel@tonic-gate struct timeval cu_wait; 847c478bd9Sstevel@tonic-gate struct timeval cu_total; 857c478bd9Sstevel@tonic-gate struct rpc_err cu_error; 867c478bd9Sstevel@tonic-gate XDR cu_outxdrs; 877c478bd9Sstevel@tonic-gate uint_t cu_xdrpos; 887c478bd9Sstevel@tonic-gate uint_t cu_sendsz; 897c478bd9Sstevel@tonic-gate char *cu_outbuf; 907c478bd9Sstevel@tonic-gate uint_t cu_recvsz; 917c478bd9Sstevel@tonic-gate char cu_inbuf[1]; 927c478bd9Sstevel@tonic-gate }; 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate /* 957c478bd9Sstevel@tonic-gate * Create a UDP based client handle. 967c478bd9Sstevel@tonic-gate * If *sockp<0, *sockp is set to a newly created UPD socket. 977c478bd9Sstevel@tonic-gate * If raddr->sin_port is 0 a binder on the remote machine 987c478bd9Sstevel@tonic-gate * is consulted for the correct port number. 997c478bd9Sstevel@tonic-gate * NB: It is the clients responsibility to close *sockp. 1007c478bd9Sstevel@tonic-gate * NB: The rpch->cl_auth is initialized to null authentication. 1017c478bd9Sstevel@tonic-gate * Caller may wish to set this something more useful. 1027c478bd9Sstevel@tonic-gate * 1037c478bd9Sstevel@tonic-gate * wait is the amount of time used between retransmitting a call if 1047c478bd9Sstevel@tonic-gate * no response has been heard; retransmition occurs until the actual 1057c478bd9Sstevel@tonic-gate * rpc call times out. 1067c478bd9Sstevel@tonic-gate * 1077c478bd9Sstevel@tonic-gate * sendsz and recvsz are the maximum allowable packet sizes that can be 1087c478bd9Sstevel@tonic-gate * sent and received. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate CLIENT * 1117c478bd9Sstevel@tonic-gate clntbudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) 1127c478bd9Sstevel@tonic-gate struct sockaddr_in *raddr; 1137c478bd9Sstevel@tonic-gate rpcprog_t program; 1147c478bd9Sstevel@tonic-gate rpcvers_t version; 1157c478bd9Sstevel@tonic-gate struct timeval wait; 1167c478bd9Sstevel@tonic-gate int *sockp; 1177c478bd9Sstevel@tonic-gate uint_t sendsz; 1187c478bd9Sstevel@tonic-gate uint_t recvsz; 1197c478bd9Sstevel@tonic-gate { 1207c478bd9Sstevel@tonic-gate CLIENT *cl; 1217c478bd9Sstevel@tonic-gate struct cu_data *cu; 1227c478bd9Sstevel@tonic-gate struct rpc_msg call_msg; 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate cl = (CLIENT *)bkmem_alloc(sizeof (CLIENT)); 1257c478bd9Sstevel@tonic-gate if (cl == NULL) { 1267c478bd9Sstevel@tonic-gate errno = ENOMEM; 1277c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 1287c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 1297c478bd9Sstevel@tonic-gate return ((CLIENT *)NULL); 1307c478bd9Sstevel@tonic-gate } 1317c478bd9Sstevel@tonic-gate sendsz = ((sendsz + 3) / 4) * 4; 1327c478bd9Sstevel@tonic-gate recvsz = ((recvsz + 3) / 4) * 4; 1337c478bd9Sstevel@tonic-gate cu = (struct cu_data *)bkmem_alloc(sizeof (*cu) + sendsz + recvsz); 1347c478bd9Sstevel@tonic-gate if (cu == NULL) { 1357c478bd9Sstevel@tonic-gate errno = ENOMEM; 1367c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 1377c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 1387c478bd9Sstevel@tonic-gate goto fooy; 1397c478bd9Sstevel@tonic-gate } 1407c478bd9Sstevel@tonic-gate cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 1417c478bd9Sstevel@tonic-gate 1427c478bd9Sstevel@tonic-gate if (raddr->sin_port == 0) { 1437c478bd9Sstevel@tonic-gate ushort_t port; 1447c478bd9Sstevel@tonic-gate if ((port = bpmap_getport(program, version, 1457c478bd9Sstevel@tonic-gate &(rpc_createerr.cf_stat), raddr, NULL)) == 0) { 1467c478bd9Sstevel@tonic-gate goto fooy; 1477c478bd9Sstevel@tonic-gate } 1487c478bd9Sstevel@tonic-gate raddr->sin_port = htons(port); 1497c478bd9Sstevel@tonic-gate } 1507c478bd9Sstevel@tonic-gate cl->cl_ops = clntbudp_ops(); 1517c478bd9Sstevel@tonic-gate cl->cl_private = (caddr_t)cu; 1527c478bd9Sstevel@tonic-gate cu->cu_raddr = *raddr; 1537c478bd9Sstevel@tonic-gate cu->cu_rlen = sizeof (cu->cu_raddr); 1547c478bd9Sstevel@tonic-gate cu->cu_wait = wait; 1557c478bd9Sstevel@tonic-gate cu->cu_total.tv_sec = -1; 1567c478bd9Sstevel@tonic-gate cu->cu_total.tv_usec = -1; 1577c478bd9Sstevel@tonic-gate cu->cu_sendsz = sendsz; 1587c478bd9Sstevel@tonic-gate cu->cu_recvsz = recvsz; 1597c478bd9Sstevel@tonic-gate call_msg.rm_xid = (uint_t)prom_gettime() + 1; 1607c478bd9Sstevel@tonic-gate call_msg.rm_direction = CALL; 1617c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 1627c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_prog = program; 1637c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_vers = version; 1647c478bd9Sstevel@tonic-gate xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, 1657c478bd9Sstevel@tonic-gate sendsz, XDR_ENCODE); 1667c478bd9Sstevel@tonic-gate if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 1677c478bd9Sstevel@tonic-gate goto fooy; 1687c478bd9Sstevel@tonic-gate } 1697c478bd9Sstevel@tonic-gate cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 1707c478bd9Sstevel@tonic-gate cu->cu_closeit = FALSE; 1717c478bd9Sstevel@tonic-gate 1727c478bd9Sstevel@tonic-gate if (*sockp < 0) { 1737c478bd9Sstevel@tonic-gate struct sockaddr_in from; 1747c478bd9Sstevel@tonic-gate 1757c478bd9Sstevel@tonic-gate *sockp = socket(PF_INET, SOCK_DGRAM, 0); 1767c478bd9Sstevel@tonic-gate if (*sockp < 0) { 1777c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 1787c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 1797c478bd9Sstevel@tonic-gate goto fooy; 1807c478bd9Sstevel@tonic-gate } 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate if (dontroute) { 1837c478bd9Sstevel@tonic-gate (void) setsockopt(*sockp, SOL_SOCKET, SO_DONTROUTE, 1847c478bd9Sstevel@tonic-gate (const void *)&dontroute, sizeof (dontroute)); 1857c478bd9Sstevel@tonic-gate } 1867c478bd9Sstevel@tonic-gate 1877c478bd9Sstevel@tonic-gate /* attempt to bind to priv port */ 1887c478bd9Sstevel@tonic-gate from.sin_family = AF_INET; 1897c478bd9Sstevel@tonic-gate ipv4_getipaddr(&from.sin_addr); 1907c478bd9Sstevel@tonic-gate from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); 1917c478bd9Sstevel@tonic-gate from.sin_port = get_source_port(TRUE); 1927c478bd9Sstevel@tonic-gate 1937c478bd9Sstevel@tonic-gate if (bind(*sockp, (struct sockaddr *)&from, sizeof (from)) < 0) { 1947c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 1957c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 1967c478bd9Sstevel@tonic-gate goto fooy; 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate cu->cu_closeit = TRUE; 2007c478bd9Sstevel@tonic-gate } 2017c478bd9Sstevel@tonic-gate 2027c478bd9Sstevel@tonic-gate cu->cu_sock = *sockp; 2037c478bd9Sstevel@tonic-gate cl->cl_auth = authnone_create(); 2047c478bd9Sstevel@tonic-gate return (cl); 2057c478bd9Sstevel@tonic-gate fooy: 2067c478bd9Sstevel@tonic-gate if (cu) 2077c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cu, sizeof (*cu) + sendsz + recvsz); 2087c478bd9Sstevel@tonic-gate if (cl) 2097c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cl, sizeof (CLIENT)); 2107c478bd9Sstevel@tonic-gate return ((CLIENT *)NULL); 2117c478bd9Sstevel@tonic-gate } 2127c478bd9Sstevel@tonic-gate 2137c478bd9Sstevel@tonic-gate CLIENT * 2147c478bd9Sstevel@tonic-gate clntbudp_create(raddr, program, version, wait, sockp) 2157c478bd9Sstevel@tonic-gate struct sockaddr_in *raddr; 2167c478bd9Sstevel@tonic-gate rpcprog_t program; 2177c478bd9Sstevel@tonic-gate rpcvers_t version; 2187c478bd9Sstevel@tonic-gate struct timeval wait; 2197c478bd9Sstevel@tonic-gate int *sockp; 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate 2227c478bd9Sstevel@tonic-gate return (clntbudp_bufcreate(raddr, program, version, wait, sockp, 2237c478bd9Sstevel@tonic-gate UDPMSGSIZE, UDPMSGSIZE)); 2247c478bd9Sstevel@tonic-gate } 2257c478bd9Sstevel@tonic-gate 2267c478bd9Sstevel@tonic-gate static enum clnt_stat 2277c478bd9Sstevel@tonic-gate clntbudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 2287c478bd9Sstevel@tonic-gate CLIENT *cl; /* client handle */ 2297c478bd9Sstevel@tonic-gate rpcproc_t proc; /* procedure number */ 2307c478bd9Sstevel@tonic-gate xdrproc_t xargs; /* xdr routine for args */ 2317c478bd9Sstevel@tonic-gate caddr_t argsp; /* pointer to args */ 2327c478bd9Sstevel@tonic-gate xdrproc_t xresults; /* xdr routine for results */ 2337c478bd9Sstevel@tonic-gate caddr_t resultsp; /* pointer to results */ 2347c478bd9Sstevel@tonic-gate struct timeval utimeout; /* seconds to wait before giving up */ 2357c478bd9Sstevel@tonic-gate { 2367c478bd9Sstevel@tonic-gate struct cu_data *cu; 2377c478bd9Sstevel@tonic-gate XDR *xdrs; 2387c478bd9Sstevel@tonic-gate int outlen; 2397c478bd9Sstevel@tonic-gate int inlen; 2407c478bd9Sstevel@tonic-gate socklen_t fromlen; 2417c478bd9Sstevel@tonic-gate struct sockaddr_in from; 2427c478bd9Sstevel@tonic-gate struct rpc_msg reply_msg; 2437c478bd9Sstevel@tonic-gate XDR reply_xdrs; 2447c478bd9Sstevel@tonic-gate uint_t xdelay; 2457c478bd9Sstevel@tonic-gate int wait_time; 2467c478bd9Sstevel@tonic-gate bool_t ok; 2477c478bd9Sstevel@tonic-gate int nrefreshes = 2; /* number of times to refresh cred */ 2487c478bd9Sstevel@tonic-gate struct timeval timeout; 2497c478bd9Sstevel@tonic-gate int errors; 250*9f1fc992Sss146032 short send_retries = RPC_UDP_SEND_RETRIES; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate cu = (struct cu_data *)cl->cl_private; 2537c478bd9Sstevel@tonic-gate if (cu->cu_total.tv_usec == -1) 2547c478bd9Sstevel@tonic-gate timeout = utimeout; /* use supplied timeout */ 2557c478bd9Sstevel@tonic-gate else 2567c478bd9Sstevel@tonic-gate timeout = cu->cu_total; /* use default timeout */ 2577c478bd9Sstevel@tonic-gate 2587c478bd9Sstevel@tonic-gate /* 2597c478bd9Sstevel@tonic-gate * set a media level timeout 2607c478bd9Sstevel@tonic-gate */ 2617c478bd9Sstevel@tonic-gate xdelay = cu->cu_wait.tv_sec + 1000 + cu->cu_wait.tv_usec / 1000; 2627c478bd9Sstevel@tonic-gate (void) setsockopt(cu->cu_sock, SOL_SOCKET, SO_RCVTIMEO, 2637c478bd9Sstevel@tonic-gate (void *)&xdelay, sizeof (xdelay)); 2647c478bd9Sstevel@tonic-gate 2657c478bd9Sstevel@tonic-gate wait_time = (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000); 2667c478bd9Sstevel@tonic-gate if (wait_time == 0) 2677c478bd9Sstevel@tonic-gate wait_time = RPC_RCVWAIT_MSEC; 2687c478bd9Sstevel@tonic-gate wait_time += prom_gettime(); 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate errors = 0; 2717c478bd9Sstevel@tonic-gate 2727c478bd9Sstevel@tonic-gate call_again: 2737c478bd9Sstevel@tonic-gate xdrs = &(cu->cu_outxdrs); 2747c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 2757c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, cu->cu_xdrpos); 2767c478bd9Sstevel@tonic-gate /* 2777c478bd9Sstevel@tonic-gate * the transaction is the first thing in the out buffer 2787c478bd9Sstevel@tonic-gate */ 2797c478bd9Sstevel@tonic-gate (*(ushort_t *)(cu->cu_outbuf))++; 2807c478bd9Sstevel@tonic-gate if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 2817c478bd9Sstevel@tonic-gate (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) || 2827c478bd9Sstevel@tonic-gate (! (*xargs)(xdrs, argsp))) 2837c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 2847c478bd9Sstevel@tonic-gate outlen = (int)XDR_GETPOS(xdrs); 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate send_again: 2877c478bd9Sstevel@tonic-gate if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, 2887c478bd9Sstevel@tonic-gate (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) 2897c478bd9Sstevel@tonic-gate != outlen) { 290*9f1fc992Sss146032 if (errno == ETIMEDOUT) { 291*9f1fc992Sss146032 /* 292*9f1fc992Sss146032 * sendto() times out probably because 293*9f1fc992Sss146032 * ARP times out while waiting for reply. 294*9f1fc992Sss146032 * We retry sending RPC message again. 295*9f1fc992Sss146032 */ 296*9f1fc992Sss146032 if (send_retries-- > 0) { 297*9f1fc992Sss146032 dprintf("clntbudp_call: timedout, try sending" 298*9f1fc992Sss146032 "RPC again\n"); 299*9f1fc992Sss146032 errno = 0; 300*9f1fc992Sss146032 goto send_again; 301*9f1fc992Sss146032 } 302*9f1fc992Sss146032 cu->cu_error.re_status = RPC_TIMEDOUT; 303*9f1fc992Sss146032 } else { 304*9f1fc992Sss146032 cu->cu_error.re_status = RPC_CANTSEND; 305*9f1fc992Sss146032 } 3067c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = errno; 307*9f1fc992Sss146032 return (cu->cu_error.re_status); 3087c478bd9Sstevel@tonic-gate } 3097c478bd9Sstevel@tonic-gate 3107c478bd9Sstevel@tonic-gate /* 3117c478bd9Sstevel@tonic-gate * sub-optimal code appears here because we have 3127c478bd9Sstevel@tonic-gate * some clock time to spare while the packets are in flight. 3137c478bd9Sstevel@tonic-gate * (We assume that this is actually only executed once.) 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate recv_again: 3167c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf = _null_auth; 3177c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.where = resultsp; 3187c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.proc = xresults; 3197c478bd9Sstevel@tonic-gate 3207c478bd9Sstevel@tonic-gate for (;;) { 3217c478bd9Sstevel@tonic-gate if (errors >= RPC_ALLOWABLE_ERRORS) 3227c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 3237c478bd9Sstevel@tonic-gate 3247c478bd9Sstevel@tonic-gate if (prom_gettime() >= wait_time) { 3257c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = ETIMEDOUT; 3267c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_TIMEDOUT); 3277c478bd9Sstevel@tonic-gate } 3287c478bd9Sstevel@tonic-gate 3297c478bd9Sstevel@tonic-gate /* 3307c478bd9Sstevel@tonic-gate * Use MSG_DONTWAIT because we have set 3317c478bd9Sstevel@tonic-gate * a media level timeout above. 3327c478bd9Sstevel@tonic-gate */ 3337c478bd9Sstevel@tonic-gate fromlen = sizeof (struct sockaddr); 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 3367c478bd9Sstevel@tonic-gate (int)cu->cu_recvsz, MSG_DONTWAIT, 3377c478bd9Sstevel@tonic-gate (struct sockaddr *)&from, &fromlen); 3387c478bd9Sstevel@tonic-gate 3397c478bd9Sstevel@tonic-gate if (inlen < 0) { 3407c478bd9Sstevel@tonic-gate if (errno == EWOULDBLOCK) { 3417c478bd9Sstevel@tonic-gate /* 3427c478bd9Sstevel@tonic-gate * Media level has timedout 3437c478bd9Sstevel@tonic-gate * and no more data in buffers. 3447c478bd9Sstevel@tonic-gate */ 3457c478bd9Sstevel@tonic-gate goto send_again; 3467c478bd9Sstevel@tonic-gate } 3477c478bd9Sstevel@tonic-gate 3487c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_CANTRECV; 3497c478bd9Sstevel@tonic-gate if (errno == ETIMEDOUT) { 3507c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 3517c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_TIMEDOUT; 3527c478bd9Sstevel@tonic-gate } 3537c478bd9Sstevel@tonic-gate 3547c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = errno; 3557c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate 3587c478bd9Sstevel@tonic-gate if (inlen < sizeof (uint32_t)) 3597c478bd9Sstevel@tonic-gate continue; 3607c478bd9Sstevel@tonic-gate 3617c478bd9Sstevel@tonic-gate /* see if reply transaction id matches sent id */ 3627c478bd9Sstevel@tonic-gate if (*((uint32_t *)(cu->cu_inbuf)) != 3637c478bd9Sstevel@tonic-gate *((uint32_t *)(cu->cu_outbuf))) { 3647c478bd9Sstevel@tonic-gate dprintf("clntbudp_call: xid: 0x%x != 0x%x\n", 3657c478bd9Sstevel@tonic-gate *(uint32_t *)(cu->cu_inbuf), 3667c478bd9Sstevel@tonic-gate *(uint32_t *)(cu->cu_outbuf)); 3677c478bd9Sstevel@tonic-gate continue; 3687c478bd9Sstevel@tonic-gate } 3697c478bd9Sstevel@tonic-gate /* we now assume we have the proper reply */ 3707c478bd9Sstevel@tonic-gate break; 3717c478bd9Sstevel@tonic-gate } 3727c478bd9Sstevel@tonic-gate 3737c478bd9Sstevel@tonic-gate /* 3747c478bd9Sstevel@tonic-gate * now decode and validate the response 3757c478bd9Sstevel@tonic-gate */ 3767c478bd9Sstevel@tonic-gate xdrmem_create(&reply_xdrs, cu->cu_inbuf, (uint_t)inlen, XDR_DECODE); 3777c478bd9Sstevel@tonic-gate ok = xdr_replymsg(&reply_xdrs, &reply_msg); 3787c478bd9Sstevel@tonic-gate /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 3797c478bd9Sstevel@tonic-gate if (!ok) { 3807c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_CANTDECODERES; 3817c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate 3847c478bd9Sstevel@tonic-gate _seterr_reply(&reply_msg, &(cu->cu_error)); 3857c478bd9Sstevel@tonic-gate if (cu->cu_error.re_status == RPC_SUCCESS) { 3867c478bd9Sstevel@tonic-gate if (! AUTH_VALIDATE(cl->cl_auth, 3877c478bd9Sstevel@tonic-gate &reply_msg.acpted_rply.ar_verf)) { 3887c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_AUTHERROR; 3897c478bd9Sstevel@tonic-gate cu->cu_error.re_why = AUTH_INVALIDRESP; 3907c478bd9Sstevel@tonic-gate errors++; 3917c478bd9Sstevel@tonic-gate goto call_again; 3927c478bd9Sstevel@tonic-gate } 3937c478bd9Sstevel@tonic-gate if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 3947c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 3957c478bd9Sstevel@tonic-gate (void) xdr_opaque_auth(xdrs, 3967c478bd9Sstevel@tonic-gate &(reply_msg.acpted_rply.ar_verf)); 3977c478bd9Sstevel@tonic-gate } 3987c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 3997c478bd9Sstevel@tonic-gate } /* end successful completion */ 4007c478bd9Sstevel@tonic-gate 4017c478bd9Sstevel@tonic-gate if (cu->cu_error.re_status == RPC_AUTHERROR) { 4027c478bd9Sstevel@tonic-gate /* maybe our credentials need to be refreshed ... */ 4037c478bd9Sstevel@tonic-gate if (nrefreshes > 0 && 4047c478bd9Sstevel@tonic-gate AUTH_REFRESH(cl->cl_auth, NULL, NULL)) { 4057c478bd9Sstevel@tonic-gate nrefreshes--; 4067c478bd9Sstevel@tonic-gate } 4077c478bd9Sstevel@tonic-gate errors++; 4087c478bd9Sstevel@tonic-gate goto call_again; 4097c478bd9Sstevel@tonic-gate } 4107c478bd9Sstevel@tonic-gate 4117c478bd9Sstevel@tonic-gate /* Just keep trying till there's no data... */ 4127c478bd9Sstevel@tonic-gate errors++; 4137c478bd9Sstevel@tonic-gate dprintf("clntbudp_call: from: %s, error: ", 4147c478bd9Sstevel@tonic-gate inet_ntoa(from.sin_addr)); 4157c478bd9Sstevel@tonic-gate rpc_disperr(&cu->cu_error); 4167c478bd9Sstevel@tonic-gate goto recv_again; 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate static void 4207c478bd9Sstevel@tonic-gate clntbudp_geterr(cl, errp) 4217c478bd9Sstevel@tonic-gate CLIENT *cl; 4227c478bd9Sstevel@tonic-gate struct rpc_err *errp; 4237c478bd9Sstevel@tonic-gate { 4247c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 4257c478bd9Sstevel@tonic-gate 4267c478bd9Sstevel@tonic-gate *errp = cu->cu_error; 4277c478bd9Sstevel@tonic-gate } 4287c478bd9Sstevel@tonic-gate 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate static bool_t 4317c478bd9Sstevel@tonic-gate clntbudp_freeres(cl, xdr_res, res_ptr) 4327c478bd9Sstevel@tonic-gate CLIENT *cl; 4337c478bd9Sstevel@tonic-gate xdrproc_t xdr_res; 4347c478bd9Sstevel@tonic-gate caddr_t res_ptr; 4357c478bd9Sstevel@tonic-gate { 4367c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 4377c478bd9Sstevel@tonic-gate XDR *xdrs = &(cu->cu_outxdrs); 4387c478bd9Sstevel@tonic-gate 4397c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 4407c478bd9Sstevel@tonic-gate return ((*xdr_res)(xdrs, res_ptr)); 4417c478bd9Sstevel@tonic-gate } 4427c478bd9Sstevel@tonic-gate 4437c478bd9Sstevel@tonic-gate static void 4447c478bd9Sstevel@tonic-gate clntbudp_abort() 4457c478bd9Sstevel@tonic-gate /* CLIENT *h; */ 4467c478bd9Sstevel@tonic-gate { 4477c478bd9Sstevel@tonic-gate } 4487c478bd9Sstevel@tonic-gate 4497c478bd9Sstevel@tonic-gate /* ARGSUSED */ 4507c478bd9Sstevel@tonic-gate static bool_t 4517c478bd9Sstevel@tonic-gate clntbudp_control(cl, request, info) 4527c478bd9Sstevel@tonic-gate CLIENT *cl; 4537c478bd9Sstevel@tonic-gate int request; 4547c478bd9Sstevel@tonic-gate char *info; 4557c478bd9Sstevel@tonic-gate { 4567c478bd9Sstevel@tonic-gate /* CLNT_CONTROL is not used in boot */ 4577c478bd9Sstevel@tonic-gate return (FALSE); 4587c478bd9Sstevel@tonic-gate } 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate static void 4617c478bd9Sstevel@tonic-gate clntbudp_destroy(cl) 4627c478bd9Sstevel@tonic-gate CLIENT *cl; 4637c478bd9Sstevel@tonic-gate { 4647c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 4657c478bd9Sstevel@tonic-gate 4667c478bd9Sstevel@tonic-gate if (cu->cu_closeit) { 4677c478bd9Sstevel@tonic-gate (void) socket_close(cu->cu_sock); 4687c478bd9Sstevel@tonic-gate } 4697c478bd9Sstevel@tonic-gate XDR_DESTROY(&(cu->cu_outxdrs)); 4707c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 4717c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cl, sizeof (CLIENT)); 4727c478bd9Sstevel@tonic-gate } 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate static struct clnt_ops * 4757c478bd9Sstevel@tonic-gate clntbudp_ops() 4767c478bd9Sstevel@tonic-gate { 4777c478bd9Sstevel@tonic-gate static struct clnt_ops ops; 4787c478bd9Sstevel@tonic-gate 4797c478bd9Sstevel@tonic-gate if (ops.cl_call == NULL) { 4807c478bd9Sstevel@tonic-gate ops.cl_call = clntbudp_call; 4817c478bd9Sstevel@tonic-gate ops.cl_abort = clntbudp_abort; 4827c478bd9Sstevel@tonic-gate ops.cl_geterr = clntbudp_geterr; 4837c478bd9Sstevel@tonic-gate ops.cl_freeres = clntbudp_freeres; 4847c478bd9Sstevel@tonic-gate ops.cl_destroy = clntbudp_destroy; 4857c478bd9Sstevel@tonic-gate ops.cl_control = clntbudp_control; 4867c478bd9Sstevel@tonic-gate } 4877c478bd9Sstevel@tonic-gate return (&ops); 4887c478bd9Sstevel@tonic-gate } 489