1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */ 28*7c478bd9Sstevel@tonic-gate /* All Rights Reserved */ 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate /* 31*7c478bd9Sstevel@tonic-gate * Portions of this source code were derived from Berkeley 4.3 BSD 32*7c478bd9Sstevel@tonic-gate * under license from the Regents of the University of California. 33*7c478bd9Sstevel@tonic-gate */ 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate /* 38*7c478bd9Sstevel@tonic-gate * Boot subsystem client side rpc 39*7c478bd9Sstevel@tonic-gate */ 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 42*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 43*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 44*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 45*7c478bd9Sstevel@tonic-gate #include "socket_inet.h" 46*7c478bd9Sstevel@tonic-gate #include "ipv4.h" 47*7c478bd9Sstevel@tonic-gate #include "clnt.h" 48*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 49*7c478bd9Sstevel@tonic-gate #include "brpc.h" 50*7c478bd9Sstevel@tonic-gate #include "pmap.h" 51*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 52*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 53*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 54*7c478bd9Sstevel@tonic-gate #include <rpc/auth_sys.h> 55*7c478bd9Sstevel@tonic-gate #include "auth_inet.h" 56*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.h> 57*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 58*7c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h> 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate #define dprintf if (boothowto & RB_DEBUG) printf 61*7c478bd9Sstevel@tonic-gate 62*7c478bd9Sstevel@tonic-gate extern int errno; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate /* 65*7c478bd9Sstevel@tonic-gate * If we create another clnt type this should be 66*7c478bd9Sstevel@tonic-gate * moved to a common file 67*7c478bd9Sstevel@tonic-gate */ 68*7c478bd9Sstevel@tonic-gate struct rpc_createerr rpc_createerr; 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate static struct clnt_ops *clntbudp_ops(); 71*7c478bd9Sstevel@tonic-gate 72*7c478bd9Sstevel@tonic-gate /* 73*7c478bd9Sstevel@tonic-gate * Private data kept per client handle 74*7c478bd9Sstevel@tonic-gate */ 75*7c478bd9Sstevel@tonic-gate struct cu_data { 76*7c478bd9Sstevel@tonic-gate int cu_sock; 77*7c478bd9Sstevel@tonic-gate bool_t cu_closeit; 78*7c478bd9Sstevel@tonic-gate struct sockaddr_in cu_raddr; 79*7c478bd9Sstevel@tonic-gate int cu_rlen; 80*7c478bd9Sstevel@tonic-gate struct timeval cu_wait; 81*7c478bd9Sstevel@tonic-gate struct timeval cu_total; 82*7c478bd9Sstevel@tonic-gate struct rpc_err cu_error; 83*7c478bd9Sstevel@tonic-gate XDR cu_outxdrs; 84*7c478bd9Sstevel@tonic-gate uint_t cu_xdrpos; 85*7c478bd9Sstevel@tonic-gate uint_t cu_sendsz; 86*7c478bd9Sstevel@tonic-gate char *cu_outbuf; 87*7c478bd9Sstevel@tonic-gate uint_t cu_recvsz; 88*7c478bd9Sstevel@tonic-gate char cu_inbuf[1]; 89*7c478bd9Sstevel@tonic-gate }; 90*7c478bd9Sstevel@tonic-gate 91*7c478bd9Sstevel@tonic-gate /* 92*7c478bd9Sstevel@tonic-gate * Create a UDP based client handle. 93*7c478bd9Sstevel@tonic-gate * If *sockp<0, *sockp is set to a newly created UPD socket. 94*7c478bd9Sstevel@tonic-gate * If raddr->sin_port is 0 a binder on the remote machine 95*7c478bd9Sstevel@tonic-gate * is consulted for the correct port number. 96*7c478bd9Sstevel@tonic-gate * NB: It is the clients responsibility to close *sockp. 97*7c478bd9Sstevel@tonic-gate * NB: The rpch->cl_auth is initialized to null authentication. 98*7c478bd9Sstevel@tonic-gate * Caller may wish to set this something more useful. 99*7c478bd9Sstevel@tonic-gate * 100*7c478bd9Sstevel@tonic-gate * wait is the amount of time used between retransmitting a call if 101*7c478bd9Sstevel@tonic-gate * no response has been heard; retransmition occurs until the actual 102*7c478bd9Sstevel@tonic-gate * rpc call times out. 103*7c478bd9Sstevel@tonic-gate * 104*7c478bd9Sstevel@tonic-gate * sendsz and recvsz are the maximum allowable packet sizes that can be 105*7c478bd9Sstevel@tonic-gate * sent and received. 106*7c478bd9Sstevel@tonic-gate */ 107*7c478bd9Sstevel@tonic-gate CLIENT * 108*7c478bd9Sstevel@tonic-gate clntbudp_bufcreate(raddr, program, version, wait, sockp, sendsz, recvsz) 109*7c478bd9Sstevel@tonic-gate struct sockaddr_in *raddr; 110*7c478bd9Sstevel@tonic-gate rpcprog_t program; 111*7c478bd9Sstevel@tonic-gate rpcvers_t version; 112*7c478bd9Sstevel@tonic-gate struct timeval wait; 113*7c478bd9Sstevel@tonic-gate int *sockp; 114*7c478bd9Sstevel@tonic-gate uint_t sendsz; 115*7c478bd9Sstevel@tonic-gate uint_t recvsz; 116*7c478bd9Sstevel@tonic-gate { 117*7c478bd9Sstevel@tonic-gate CLIENT *cl; 118*7c478bd9Sstevel@tonic-gate struct cu_data *cu; 119*7c478bd9Sstevel@tonic-gate struct rpc_msg call_msg; 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate cl = (CLIENT *)bkmem_alloc(sizeof (CLIENT)); 122*7c478bd9Sstevel@tonic-gate if (cl == NULL) { 123*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 124*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 125*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 126*7c478bd9Sstevel@tonic-gate return ((CLIENT *)NULL); 127*7c478bd9Sstevel@tonic-gate } 128*7c478bd9Sstevel@tonic-gate sendsz = ((sendsz + 3) / 4) * 4; 129*7c478bd9Sstevel@tonic-gate recvsz = ((recvsz + 3) / 4) * 4; 130*7c478bd9Sstevel@tonic-gate cu = (struct cu_data *)bkmem_alloc(sizeof (*cu) + sendsz + recvsz); 131*7c478bd9Sstevel@tonic-gate if (cu == NULL) { 132*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 133*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 134*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 135*7c478bd9Sstevel@tonic-gate goto fooy; 136*7c478bd9Sstevel@tonic-gate } 137*7c478bd9Sstevel@tonic-gate cu->cu_outbuf = &cu->cu_inbuf[recvsz]; 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate if (raddr->sin_port == 0) { 140*7c478bd9Sstevel@tonic-gate ushort_t port; 141*7c478bd9Sstevel@tonic-gate if ((port = bpmap_getport(program, version, 142*7c478bd9Sstevel@tonic-gate &(rpc_createerr.cf_stat), raddr, NULL)) == 0) { 143*7c478bd9Sstevel@tonic-gate goto fooy; 144*7c478bd9Sstevel@tonic-gate } 145*7c478bd9Sstevel@tonic-gate raddr->sin_port = htons(port); 146*7c478bd9Sstevel@tonic-gate } 147*7c478bd9Sstevel@tonic-gate cl->cl_ops = clntbudp_ops(); 148*7c478bd9Sstevel@tonic-gate cl->cl_private = (caddr_t)cu; 149*7c478bd9Sstevel@tonic-gate cu->cu_raddr = *raddr; 150*7c478bd9Sstevel@tonic-gate cu->cu_rlen = sizeof (cu->cu_raddr); 151*7c478bd9Sstevel@tonic-gate cu->cu_wait = wait; 152*7c478bd9Sstevel@tonic-gate cu->cu_total.tv_sec = -1; 153*7c478bd9Sstevel@tonic-gate cu->cu_total.tv_usec = -1; 154*7c478bd9Sstevel@tonic-gate cu->cu_sendsz = sendsz; 155*7c478bd9Sstevel@tonic-gate cu->cu_recvsz = recvsz; 156*7c478bd9Sstevel@tonic-gate call_msg.rm_xid = (uint_t)prom_gettime() + 1; 157*7c478bd9Sstevel@tonic-gate call_msg.rm_direction = CALL; 158*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 159*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_prog = program; 160*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_vers = version; 161*7c478bd9Sstevel@tonic-gate xdrmem_create(&(cu->cu_outxdrs), cu->cu_outbuf, 162*7c478bd9Sstevel@tonic-gate sendsz, XDR_ENCODE); 163*7c478bd9Sstevel@tonic-gate if (! xdr_callhdr(&(cu->cu_outxdrs), &call_msg)) { 164*7c478bd9Sstevel@tonic-gate goto fooy; 165*7c478bd9Sstevel@tonic-gate } 166*7c478bd9Sstevel@tonic-gate cu->cu_xdrpos = XDR_GETPOS(&(cu->cu_outxdrs)); 167*7c478bd9Sstevel@tonic-gate cu->cu_closeit = FALSE; 168*7c478bd9Sstevel@tonic-gate 169*7c478bd9Sstevel@tonic-gate if (*sockp < 0) { 170*7c478bd9Sstevel@tonic-gate struct sockaddr_in from; 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate *sockp = socket(PF_INET, SOCK_DGRAM, 0); 173*7c478bd9Sstevel@tonic-gate if (*sockp < 0) { 174*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 175*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 176*7c478bd9Sstevel@tonic-gate goto fooy; 177*7c478bd9Sstevel@tonic-gate } 178*7c478bd9Sstevel@tonic-gate 179*7c478bd9Sstevel@tonic-gate if (dontroute) { 180*7c478bd9Sstevel@tonic-gate (void) setsockopt(*sockp, SOL_SOCKET, SO_DONTROUTE, 181*7c478bd9Sstevel@tonic-gate (const void *)&dontroute, sizeof (dontroute)); 182*7c478bd9Sstevel@tonic-gate } 183*7c478bd9Sstevel@tonic-gate 184*7c478bd9Sstevel@tonic-gate /* attempt to bind to priv port */ 185*7c478bd9Sstevel@tonic-gate from.sin_family = AF_INET; 186*7c478bd9Sstevel@tonic-gate ipv4_getipaddr(&from.sin_addr); 187*7c478bd9Sstevel@tonic-gate from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); 188*7c478bd9Sstevel@tonic-gate from.sin_port = get_source_port(TRUE); 189*7c478bd9Sstevel@tonic-gate 190*7c478bd9Sstevel@tonic-gate if (bind(*sockp, (struct sockaddr *)&from, sizeof (from)) < 0) { 191*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 192*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 193*7c478bd9Sstevel@tonic-gate goto fooy; 194*7c478bd9Sstevel@tonic-gate } 195*7c478bd9Sstevel@tonic-gate 196*7c478bd9Sstevel@tonic-gate cu->cu_closeit = TRUE; 197*7c478bd9Sstevel@tonic-gate } 198*7c478bd9Sstevel@tonic-gate 199*7c478bd9Sstevel@tonic-gate cu->cu_sock = *sockp; 200*7c478bd9Sstevel@tonic-gate cl->cl_auth = authnone_create(); 201*7c478bd9Sstevel@tonic-gate return (cl); 202*7c478bd9Sstevel@tonic-gate fooy: 203*7c478bd9Sstevel@tonic-gate if (cu) 204*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cu, sizeof (*cu) + sendsz + recvsz); 205*7c478bd9Sstevel@tonic-gate if (cl) 206*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cl, sizeof (CLIENT)); 207*7c478bd9Sstevel@tonic-gate return ((CLIENT *)NULL); 208*7c478bd9Sstevel@tonic-gate } 209*7c478bd9Sstevel@tonic-gate 210*7c478bd9Sstevel@tonic-gate CLIENT * 211*7c478bd9Sstevel@tonic-gate clntbudp_create(raddr, program, version, wait, sockp) 212*7c478bd9Sstevel@tonic-gate struct sockaddr_in *raddr; 213*7c478bd9Sstevel@tonic-gate rpcprog_t program; 214*7c478bd9Sstevel@tonic-gate rpcvers_t version; 215*7c478bd9Sstevel@tonic-gate struct timeval wait; 216*7c478bd9Sstevel@tonic-gate int *sockp; 217*7c478bd9Sstevel@tonic-gate { 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate return (clntbudp_bufcreate(raddr, program, version, wait, sockp, 220*7c478bd9Sstevel@tonic-gate UDPMSGSIZE, UDPMSGSIZE)); 221*7c478bd9Sstevel@tonic-gate } 222*7c478bd9Sstevel@tonic-gate 223*7c478bd9Sstevel@tonic-gate static enum clnt_stat 224*7c478bd9Sstevel@tonic-gate clntbudp_call(cl, proc, xargs, argsp, xresults, resultsp, utimeout) 225*7c478bd9Sstevel@tonic-gate CLIENT *cl; /* client handle */ 226*7c478bd9Sstevel@tonic-gate rpcproc_t proc; /* procedure number */ 227*7c478bd9Sstevel@tonic-gate xdrproc_t xargs; /* xdr routine for args */ 228*7c478bd9Sstevel@tonic-gate caddr_t argsp; /* pointer to args */ 229*7c478bd9Sstevel@tonic-gate xdrproc_t xresults; /* xdr routine for results */ 230*7c478bd9Sstevel@tonic-gate caddr_t resultsp; /* pointer to results */ 231*7c478bd9Sstevel@tonic-gate struct timeval utimeout; /* seconds to wait before giving up */ 232*7c478bd9Sstevel@tonic-gate { 233*7c478bd9Sstevel@tonic-gate struct cu_data *cu; 234*7c478bd9Sstevel@tonic-gate XDR *xdrs; 235*7c478bd9Sstevel@tonic-gate int outlen; 236*7c478bd9Sstevel@tonic-gate int inlen; 237*7c478bd9Sstevel@tonic-gate socklen_t fromlen; 238*7c478bd9Sstevel@tonic-gate struct sockaddr_in from; 239*7c478bd9Sstevel@tonic-gate struct rpc_msg reply_msg; 240*7c478bd9Sstevel@tonic-gate XDR reply_xdrs; 241*7c478bd9Sstevel@tonic-gate uint_t xdelay; 242*7c478bd9Sstevel@tonic-gate int wait_time; 243*7c478bd9Sstevel@tonic-gate bool_t ok; 244*7c478bd9Sstevel@tonic-gate int nrefreshes = 2; /* number of times to refresh cred */ 245*7c478bd9Sstevel@tonic-gate struct timeval timeout; 246*7c478bd9Sstevel@tonic-gate int errors; 247*7c478bd9Sstevel@tonic-gate 248*7c478bd9Sstevel@tonic-gate cu = (struct cu_data *)cl->cl_private; 249*7c478bd9Sstevel@tonic-gate if (cu->cu_total.tv_usec == -1) 250*7c478bd9Sstevel@tonic-gate timeout = utimeout; /* use supplied timeout */ 251*7c478bd9Sstevel@tonic-gate else 252*7c478bd9Sstevel@tonic-gate timeout = cu->cu_total; /* use default timeout */ 253*7c478bd9Sstevel@tonic-gate 254*7c478bd9Sstevel@tonic-gate /* 255*7c478bd9Sstevel@tonic-gate * set a media level timeout 256*7c478bd9Sstevel@tonic-gate */ 257*7c478bd9Sstevel@tonic-gate xdelay = cu->cu_wait.tv_sec + 1000 + cu->cu_wait.tv_usec / 1000; 258*7c478bd9Sstevel@tonic-gate (void) setsockopt(cu->cu_sock, SOL_SOCKET, SO_RCVTIMEO, 259*7c478bd9Sstevel@tonic-gate (void *)&xdelay, sizeof (xdelay)); 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate wait_time = (timeout.tv_sec * 1000) + (timeout.tv_usec / 1000); 262*7c478bd9Sstevel@tonic-gate if (wait_time == 0) 263*7c478bd9Sstevel@tonic-gate wait_time = RPC_RCVWAIT_MSEC; 264*7c478bd9Sstevel@tonic-gate wait_time += prom_gettime(); 265*7c478bd9Sstevel@tonic-gate 266*7c478bd9Sstevel@tonic-gate errors = 0; 267*7c478bd9Sstevel@tonic-gate 268*7c478bd9Sstevel@tonic-gate call_again: 269*7c478bd9Sstevel@tonic-gate xdrs = &(cu->cu_outxdrs); 270*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 271*7c478bd9Sstevel@tonic-gate XDR_SETPOS(xdrs, cu->cu_xdrpos); 272*7c478bd9Sstevel@tonic-gate /* 273*7c478bd9Sstevel@tonic-gate * the transaction is the first thing in the out buffer 274*7c478bd9Sstevel@tonic-gate */ 275*7c478bd9Sstevel@tonic-gate (*(ushort_t *)(cu->cu_outbuf))++; 276*7c478bd9Sstevel@tonic-gate if ((! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 277*7c478bd9Sstevel@tonic-gate (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) || 278*7c478bd9Sstevel@tonic-gate (! (*xargs)(xdrs, argsp))) 279*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_CANTENCODEARGS); 280*7c478bd9Sstevel@tonic-gate outlen = (int)XDR_GETPOS(xdrs); 281*7c478bd9Sstevel@tonic-gate 282*7c478bd9Sstevel@tonic-gate send_again: 283*7c478bd9Sstevel@tonic-gate if (sendto(cu->cu_sock, cu->cu_outbuf, outlen, 0, 284*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&(cu->cu_raddr), cu->cu_rlen) 285*7c478bd9Sstevel@tonic-gate != outlen) { 286*7c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = errno; 287*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_CANTSEND); 288*7c478bd9Sstevel@tonic-gate } 289*7c478bd9Sstevel@tonic-gate 290*7c478bd9Sstevel@tonic-gate /* 291*7c478bd9Sstevel@tonic-gate * sub-optimal code appears here because we have 292*7c478bd9Sstevel@tonic-gate * some clock time to spare while the packets are in flight. 293*7c478bd9Sstevel@tonic-gate * (We assume that this is actually only executed once.) 294*7c478bd9Sstevel@tonic-gate */ 295*7c478bd9Sstevel@tonic-gate recv_again: 296*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf = _null_auth; 297*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.where = resultsp; 298*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.proc = xresults; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate for (;;) { 301*7c478bd9Sstevel@tonic-gate if (errors >= RPC_ALLOWABLE_ERRORS) 302*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate if (prom_gettime() >= wait_time) { 305*7c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = ETIMEDOUT; 306*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status = RPC_TIMEDOUT); 307*7c478bd9Sstevel@tonic-gate } 308*7c478bd9Sstevel@tonic-gate 309*7c478bd9Sstevel@tonic-gate /* 310*7c478bd9Sstevel@tonic-gate * Use MSG_DONTWAIT because we have set 311*7c478bd9Sstevel@tonic-gate * a media level timeout above. 312*7c478bd9Sstevel@tonic-gate */ 313*7c478bd9Sstevel@tonic-gate fromlen = sizeof (struct sockaddr); 314*7c478bd9Sstevel@tonic-gate 315*7c478bd9Sstevel@tonic-gate inlen = recvfrom(cu->cu_sock, cu->cu_inbuf, 316*7c478bd9Sstevel@tonic-gate (int)cu->cu_recvsz, MSG_DONTWAIT, 317*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&from, &fromlen); 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate if (inlen < 0) { 320*7c478bd9Sstevel@tonic-gate if (errno == EWOULDBLOCK) { 321*7c478bd9Sstevel@tonic-gate /* 322*7c478bd9Sstevel@tonic-gate * Media level has timedout 323*7c478bd9Sstevel@tonic-gate * and no more data in buffers. 324*7c478bd9Sstevel@tonic-gate */ 325*7c478bd9Sstevel@tonic-gate goto send_again; 326*7c478bd9Sstevel@tonic-gate } 327*7c478bd9Sstevel@tonic-gate 328*7c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_CANTRECV; 329*7c478bd9Sstevel@tonic-gate if (errno == ETIMEDOUT) { 330*7c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 331*7c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_TIMEDOUT; 332*7c478bd9Sstevel@tonic-gate } 333*7c478bd9Sstevel@tonic-gate 334*7c478bd9Sstevel@tonic-gate cu->cu_error.re_errno = errno; 335*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 336*7c478bd9Sstevel@tonic-gate } 337*7c478bd9Sstevel@tonic-gate 338*7c478bd9Sstevel@tonic-gate if (inlen < sizeof (uint32_t)) 339*7c478bd9Sstevel@tonic-gate continue; 340*7c478bd9Sstevel@tonic-gate 341*7c478bd9Sstevel@tonic-gate /* see if reply transaction id matches sent id */ 342*7c478bd9Sstevel@tonic-gate if (*((uint32_t *)(cu->cu_inbuf)) != 343*7c478bd9Sstevel@tonic-gate *((uint32_t *)(cu->cu_outbuf))) { 344*7c478bd9Sstevel@tonic-gate dprintf("clntbudp_call: xid: 0x%x != 0x%x\n", 345*7c478bd9Sstevel@tonic-gate *(uint32_t *)(cu->cu_inbuf), 346*7c478bd9Sstevel@tonic-gate *(uint32_t *)(cu->cu_outbuf)); 347*7c478bd9Sstevel@tonic-gate continue; 348*7c478bd9Sstevel@tonic-gate } 349*7c478bd9Sstevel@tonic-gate /* we now assume we have the proper reply */ 350*7c478bd9Sstevel@tonic-gate break; 351*7c478bd9Sstevel@tonic-gate } 352*7c478bd9Sstevel@tonic-gate 353*7c478bd9Sstevel@tonic-gate /* 354*7c478bd9Sstevel@tonic-gate * now decode and validate the response 355*7c478bd9Sstevel@tonic-gate */ 356*7c478bd9Sstevel@tonic-gate xdrmem_create(&reply_xdrs, cu->cu_inbuf, (uint_t)inlen, XDR_DECODE); 357*7c478bd9Sstevel@tonic-gate ok = xdr_replymsg(&reply_xdrs, &reply_msg); 358*7c478bd9Sstevel@tonic-gate /* XDR_DESTROY(&reply_xdrs); save a few cycles on noop destroy */ 359*7c478bd9Sstevel@tonic-gate if (!ok) { 360*7c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_CANTDECODERES; 361*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate 364*7c478bd9Sstevel@tonic-gate _seterr_reply(&reply_msg, &(cu->cu_error)); 365*7c478bd9Sstevel@tonic-gate if (cu->cu_error.re_status == RPC_SUCCESS) { 366*7c478bd9Sstevel@tonic-gate if (! AUTH_VALIDATE(cl->cl_auth, 367*7c478bd9Sstevel@tonic-gate &reply_msg.acpted_rply.ar_verf)) { 368*7c478bd9Sstevel@tonic-gate cu->cu_error.re_status = RPC_AUTHERROR; 369*7c478bd9Sstevel@tonic-gate cu->cu_error.re_why = AUTH_INVALIDRESP; 370*7c478bd9Sstevel@tonic-gate errors++; 371*7c478bd9Sstevel@tonic-gate goto call_again; 372*7c478bd9Sstevel@tonic-gate } 373*7c478bd9Sstevel@tonic-gate if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 374*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 375*7c478bd9Sstevel@tonic-gate (void) xdr_opaque_auth(xdrs, 376*7c478bd9Sstevel@tonic-gate &(reply_msg.acpted_rply.ar_verf)); 377*7c478bd9Sstevel@tonic-gate } 378*7c478bd9Sstevel@tonic-gate return (cu->cu_error.re_status); 379*7c478bd9Sstevel@tonic-gate } /* end successful completion */ 380*7c478bd9Sstevel@tonic-gate 381*7c478bd9Sstevel@tonic-gate if (cu->cu_error.re_status == RPC_AUTHERROR) { 382*7c478bd9Sstevel@tonic-gate /* maybe our credentials need to be refreshed ... */ 383*7c478bd9Sstevel@tonic-gate if (nrefreshes > 0 && 384*7c478bd9Sstevel@tonic-gate AUTH_REFRESH(cl->cl_auth, NULL, NULL)) { 385*7c478bd9Sstevel@tonic-gate nrefreshes--; 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate errors++; 388*7c478bd9Sstevel@tonic-gate goto call_again; 389*7c478bd9Sstevel@tonic-gate } 390*7c478bd9Sstevel@tonic-gate 391*7c478bd9Sstevel@tonic-gate /* Just keep trying till there's no data... */ 392*7c478bd9Sstevel@tonic-gate errors++; 393*7c478bd9Sstevel@tonic-gate dprintf("clntbudp_call: from: %s, error: ", 394*7c478bd9Sstevel@tonic-gate inet_ntoa(from.sin_addr)); 395*7c478bd9Sstevel@tonic-gate rpc_disperr(&cu->cu_error); 396*7c478bd9Sstevel@tonic-gate goto recv_again; 397*7c478bd9Sstevel@tonic-gate } 398*7c478bd9Sstevel@tonic-gate 399*7c478bd9Sstevel@tonic-gate static void 400*7c478bd9Sstevel@tonic-gate clntbudp_geterr(cl, errp) 401*7c478bd9Sstevel@tonic-gate CLIENT *cl; 402*7c478bd9Sstevel@tonic-gate struct rpc_err *errp; 403*7c478bd9Sstevel@tonic-gate { 404*7c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 405*7c478bd9Sstevel@tonic-gate 406*7c478bd9Sstevel@tonic-gate *errp = cu->cu_error; 407*7c478bd9Sstevel@tonic-gate } 408*7c478bd9Sstevel@tonic-gate 409*7c478bd9Sstevel@tonic-gate 410*7c478bd9Sstevel@tonic-gate static bool_t 411*7c478bd9Sstevel@tonic-gate clntbudp_freeres(cl, xdr_res, res_ptr) 412*7c478bd9Sstevel@tonic-gate CLIENT *cl; 413*7c478bd9Sstevel@tonic-gate xdrproc_t xdr_res; 414*7c478bd9Sstevel@tonic-gate caddr_t res_ptr; 415*7c478bd9Sstevel@tonic-gate { 416*7c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 417*7c478bd9Sstevel@tonic-gate XDR *xdrs = &(cu->cu_outxdrs); 418*7c478bd9Sstevel@tonic-gate 419*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 420*7c478bd9Sstevel@tonic-gate return ((*xdr_res)(xdrs, res_ptr)); 421*7c478bd9Sstevel@tonic-gate } 422*7c478bd9Sstevel@tonic-gate 423*7c478bd9Sstevel@tonic-gate static void 424*7c478bd9Sstevel@tonic-gate clntbudp_abort() 425*7c478bd9Sstevel@tonic-gate /* CLIENT *h; */ 426*7c478bd9Sstevel@tonic-gate { 427*7c478bd9Sstevel@tonic-gate } 428*7c478bd9Sstevel@tonic-gate 429*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 430*7c478bd9Sstevel@tonic-gate static bool_t 431*7c478bd9Sstevel@tonic-gate clntbudp_control(cl, request, info) 432*7c478bd9Sstevel@tonic-gate CLIENT *cl; 433*7c478bd9Sstevel@tonic-gate int request; 434*7c478bd9Sstevel@tonic-gate char *info; 435*7c478bd9Sstevel@tonic-gate { 436*7c478bd9Sstevel@tonic-gate /* CLNT_CONTROL is not used in boot */ 437*7c478bd9Sstevel@tonic-gate return (FALSE); 438*7c478bd9Sstevel@tonic-gate } 439*7c478bd9Sstevel@tonic-gate 440*7c478bd9Sstevel@tonic-gate static void 441*7c478bd9Sstevel@tonic-gate clntbudp_destroy(cl) 442*7c478bd9Sstevel@tonic-gate CLIENT *cl; 443*7c478bd9Sstevel@tonic-gate { 444*7c478bd9Sstevel@tonic-gate struct cu_data *cu = (struct cu_data *)cl->cl_private; 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate if (cu->cu_closeit) { 447*7c478bd9Sstevel@tonic-gate (void) socket_close(cu->cu_sock); 448*7c478bd9Sstevel@tonic-gate } 449*7c478bd9Sstevel@tonic-gate XDR_DESTROY(&(cu->cu_outxdrs)); 450*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cu, (sizeof (*cu) + cu->cu_sendsz + cu->cu_recvsz)); 451*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cl, sizeof (CLIENT)); 452*7c478bd9Sstevel@tonic-gate } 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate static struct clnt_ops * 455*7c478bd9Sstevel@tonic-gate clntbudp_ops() 456*7c478bd9Sstevel@tonic-gate { 457*7c478bd9Sstevel@tonic-gate static struct clnt_ops ops; 458*7c478bd9Sstevel@tonic-gate 459*7c478bd9Sstevel@tonic-gate if (ops.cl_call == NULL) { 460*7c478bd9Sstevel@tonic-gate ops.cl_call = clntbudp_call; 461*7c478bd9Sstevel@tonic-gate ops.cl_abort = clntbudp_abort; 462*7c478bd9Sstevel@tonic-gate ops.cl_geterr = clntbudp_geterr; 463*7c478bd9Sstevel@tonic-gate ops.cl_freeres = clntbudp_freeres; 464*7c478bd9Sstevel@tonic-gate ops.cl_destroy = clntbudp_destroy; 465*7c478bd9Sstevel@tonic-gate ops.cl_control = clntbudp_control; 466*7c478bd9Sstevel@tonic-gate } 467*7c478bd9Sstevel@tonic-gate return (&ops); 468*7c478bd9Sstevel@tonic-gate } 469