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 (TCP) 39*7c478bd9Sstevel@tonic-gate */ 40*7c478bd9Sstevel@tonic-gate 41*7c478bd9Sstevel@tonic-gate #include <sys/salib.h> 42*7c478bd9Sstevel@tonic-gate #include <sys/errno.h> 43*7c478bd9Sstevel@tonic-gate #include <rpc/types.h> 44*7c478bd9Sstevel@tonic-gate #include <sys/socket.h> 45*7c478bd9Sstevel@tonic-gate #include <netinet/in.h> 46*7c478bd9Sstevel@tonic-gate #include "socket_inet.h" 47*7c478bd9Sstevel@tonic-gate #include "ipv4.h" 48*7c478bd9Sstevel@tonic-gate #include "clnt.h" 49*7c478bd9Sstevel@tonic-gate #include <rpc/rpc.h> 50*7c478bd9Sstevel@tonic-gate #include "brpc.h" 51*7c478bd9Sstevel@tonic-gate #include "pmap.h" 52*7c478bd9Sstevel@tonic-gate #include <sys/promif.h> 53*7c478bd9Sstevel@tonic-gate #include <rpc/xdr.h> 54*7c478bd9Sstevel@tonic-gate #include <rpc/auth.h> 55*7c478bd9Sstevel@tonic-gate #include <rpc/auth_sys.h> 56*7c478bd9Sstevel@tonic-gate #include "auth_inet.h" 57*7c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.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 #define MCALL_MSG_SIZE 24 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate extern int errno; 65*7c478bd9Sstevel@tonic-gate 66*7c478bd9Sstevel@tonic-gate extern void xdrrec_create(); 67*7c478bd9Sstevel@tonic-gate extern bool_t xdrrec_endofrecord(); 68*7c478bd9Sstevel@tonic-gate extern bool_t xdrrec_skiprecord(); 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* 71*7c478bd9Sstevel@tonic-gate * If we create another clnt type this should be 72*7c478bd9Sstevel@tonic-gate * moved to a common file 73*7c478bd9Sstevel@tonic-gate */ 74*7c478bd9Sstevel@tonic-gate struct rpc_createerr rpc_createerr; 75*7c478bd9Sstevel@tonic-gate 76*7c478bd9Sstevel@tonic-gate static int readtcp(); 77*7c478bd9Sstevel@tonic-gate static int writetcp(); 78*7c478bd9Sstevel@tonic-gate 79*7c478bd9Sstevel@tonic-gate static struct clnt_ops *clntbtcp_ops(); 80*7c478bd9Sstevel@tonic-gate 81*7c478bd9Sstevel@tonic-gate /* 82*7c478bd9Sstevel@tonic-gate * Private data kept per client handle 83*7c478bd9Sstevel@tonic-gate */ 84*7c478bd9Sstevel@tonic-gate struct ct_data { 85*7c478bd9Sstevel@tonic-gate int ct_sock; 86*7c478bd9Sstevel@tonic-gate bool_t ct_closeit; 87*7c478bd9Sstevel@tonic-gate struct sockaddr_in ct_raddr; 88*7c478bd9Sstevel@tonic-gate uint_t ct_wait_msec; 89*7c478bd9Sstevel@tonic-gate struct timeval ct_total; 90*7c478bd9Sstevel@tonic-gate struct rpc_err ct_error; 91*7c478bd9Sstevel@tonic-gate XDR ct_xdrs; 92*7c478bd9Sstevel@tonic-gate char ct_mcall[MCALL_MSG_SIZE]; 93*7c478bd9Sstevel@tonic-gate uint_t ct_mpos; 94*7c478bd9Sstevel@tonic-gate uint_t ct_xdrpos; 95*7c478bd9Sstevel@tonic-gate }; 96*7c478bd9Sstevel@tonic-gate 97*7c478bd9Sstevel@tonic-gate /* 98*7c478bd9Sstevel@tonic-gate * Create a TCP based client handle. 99*7c478bd9Sstevel@tonic-gate * If *sockp<0, *sockp is set to a newly created TCP socket. 100*7c478bd9Sstevel@tonic-gate * If raddr->sin_port is 0 a binder on the remote machine 101*7c478bd9Sstevel@tonic-gate * is consulted for the correct port number. 102*7c478bd9Sstevel@tonic-gate * NB: It is the clients responsibility to close *sockp. 103*7c478bd9Sstevel@tonic-gate * NB: The rpch->cl_auth is initialized to null authentication. 104*7c478bd9Sstevel@tonic-gate * Caller may wish to set this something more useful. 105*7c478bd9Sstevel@tonic-gate * 106*7c478bd9Sstevel@tonic-gate * wait is the amount of time used between retransmitting a call if 107*7c478bd9Sstevel@tonic-gate * no response has been heard; retransmition occurs until the actual 108*7c478bd9Sstevel@tonic-gate * rpc call times out. 109*7c478bd9Sstevel@tonic-gate * 110*7c478bd9Sstevel@tonic-gate * sendsz and recvsz are the maximum allowable packet sizes that can be 111*7c478bd9Sstevel@tonic-gate * sent and received. 112*7c478bd9Sstevel@tonic-gate */ 113*7c478bd9Sstevel@tonic-gate CLIENT * 114*7c478bd9Sstevel@tonic-gate clntbtcp_create( 115*7c478bd9Sstevel@tonic-gate struct sockaddr_in *raddr, 116*7c478bd9Sstevel@tonic-gate rpcprog_t program, 117*7c478bd9Sstevel@tonic-gate rpcvers_t version, 118*7c478bd9Sstevel@tonic-gate struct timeval wait, 119*7c478bd9Sstevel@tonic-gate int *sockp, 120*7c478bd9Sstevel@tonic-gate uint_t sendsz, 121*7c478bd9Sstevel@tonic-gate uint_t recvsz) 122*7c478bd9Sstevel@tonic-gate { 123*7c478bd9Sstevel@tonic-gate CLIENT *cl; 124*7c478bd9Sstevel@tonic-gate struct ct_data *ct; 125*7c478bd9Sstevel@tonic-gate struct rpc_msg call_msg; 126*7c478bd9Sstevel@tonic-gate #if 0 /* XXX not yet */ 127*7c478bd9Sstevel@tonic-gate int min_buf_sz; 128*7c478bd9Sstevel@tonic-gate int pref_buf_sz = 64 * 1024; /* 64 KB */ 129*7c478bd9Sstevel@tonic-gate socklen_t optlen; 130*7c478bd9Sstevel@tonic-gate #endif /* not yet */ 131*7c478bd9Sstevel@tonic-gate cl = (CLIENT *)bkmem_alloc(sizeof (CLIENT)); 132*7c478bd9Sstevel@tonic-gate if (cl == NULL) { 133*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 134*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 135*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 136*7c478bd9Sstevel@tonic-gate return ((CLIENT *)NULL); 137*7c478bd9Sstevel@tonic-gate } 138*7c478bd9Sstevel@tonic-gate 139*7c478bd9Sstevel@tonic-gate ct = (struct ct_data *)bkmem_alloc(sizeof (*ct)); 140*7c478bd9Sstevel@tonic-gate if (ct == NULL) { 141*7c478bd9Sstevel@tonic-gate errno = ENOMEM; 142*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 143*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 144*7c478bd9Sstevel@tonic-gate goto fooy; 145*7c478bd9Sstevel@tonic-gate } 146*7c478bd9Sstevel@tonic-gate 147*7c478bd9Sstevel@tonic-gate if (raddr->sin_port == 0) { 148*7c478bd9Sstevel@tonic-gate ushort_t port; 149*7c478bd9Sstevel@tonic-gate if ((port = bpmap_getport(program, version, 150*7c478bd9Sstevel@tonic-gate &(rpc_createerr.cf_stat), raddr, NULL)) == 0) { 151*7c478bd9Sstevel@tonic-gate goto fooy; 152*7c478bd9Sstevel@tonic-gate } 153*7c478bd9Sstevel@tonic-gate raddr->sin_port = htons(port); 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate if (*sockp < 0) { 157*7c478bd9Sstevel@tonic-gate struct sockaddr_in from; 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate *sockp = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); 160*7c478bd9Sstevel@tonic-gate if (*sockp < 0) { 161*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 162*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 163*7c478bd9Sstevel@tonic-gate goto fooy; 164*7c478bd9Sstevel@tonic-gate } 165*7c478bd9Sstevel@tonic-gate /* 166*7c478bd9Sstevel@tonic-gate * Bootparams assumes a local net, so be sure to let lower 167*7c478bd9Sstevel@tonic-gate * layer protocols know not to route. 168*7c478bd9Sstevel@tonic-gate */ 169*7c478bd9Sstevel@tonic-gate if (dontroute) { 170*7c478bd9Sstevel@tonic-gate (void) setsockopt(*sockp, SOL_SOCKET, SO_DONTROUTE, 171*7c478bd9Sstevel@tonic-gate (const void *)&dontroute, sizeof (dontroute)); 172*7c478bd9Sstevel@tonic-gate } 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate /* attempt to bind to priv port */ 175*7c478bd9Sstevel@tonic-gate from.sin_family = AF_INET; 176*7c478bd9Sstevel@tonic-gate ipv4_getipaddr(&from.sin_addr); 177*7c478bd9Sstevel@tonic-gate from.sin_addr.s_addr = htonl(from.sin_addr.s_addr); 178*7c478bd9Sstevel@tonic-gate from.sin_port = get_source_port(TRUE); 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate if (bind(*sockp, (struct sockaddr *)&from, sizeof (from)) < 0) { 181*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 182*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 183*7c478bd9Sstevel@tonic-gate if (*sockp > 0) 184*7c478bd9Sstevel@tonic-gate close(*sockp); 185*7c478bd9Sstevel@tonic-gate goto fooy; 186*7c478bd9Sstevel@tonic-gate } 187*7c478bd9Sstevel@tonic-gate 188*7c478bd9Sstevel@tonic-gate if (connect(*sockp, (struct sockaddr *)raddr, 189*7c478bd9Sstevel@tonic-gate sizeof (struct sockaddr_in)) < 0) { 190*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_stat = RPC_SYSTEMERROR; 191*7c478bd9Sstevel@tonic-gate rpc_createerr.cf_error.re_errno = errno; 192*7c478bd9Sstevel@tonic-gate if (*sockp > 0) 193*7c478bd9Sstevel@tonic-gate close(*sockp); 194*7c478bd9Sstevel@tonic-gate goto fooy; 195*7c478bd9Sstevel@tonic-gate } 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate #if 0 /* XXX not yet */ 198*7c478bd9Sstevel@tonic-gate /* 199*7c478bd9Sstevel@tonic-gate * In the future we may want RPC to use larger transfer sizes 200*7c478bd9Sstevel@tonic-gate * over TCP. In this case we will want to increase the 201*7c478bd9Sstevel@tonic-gate * window size. 202*7c478bd9Sstevel@tonic-gate */ 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * Resize the receive window if possible 205*7c478bd9Sstevel@tonic-gate */ 206*7c478bd9Sstevel@tonic-gate optlen = sizeof (int); 207*7c478bd9Sstevel@tonic-gate if (getsockopt(*sockp, SOL_SOCKET, SO_RCVBUF, 208*7c478bd9Sstevel@tonic-gate (void *)&min_buf_sz, &optlen) != 0) 209*7c478bd9Sstevel@tonic-gate goto keep_going; 210*7c478bd9Sstevel@tonic-gate 211*7c478bd9Sstevel@tonic-gate if (min_buf_sz < pref_buf_sz) 212*7c478bd9Sstevel@tonic-gate (void) setsockopt(*sockp, SOL_SOCKET, SO_RCVBUF, 213*7c478bd9Sstevel@tonic-gate (const void *)&pref_buf_sz, sizeof (int)); 214*7c478bd9Sstevel@tonic-gate 215*7c478bd9Sstevel@tonic-gate keep_going: 216*7c478bd9Sstevel@tonic-gate #endif /* not yet */ 217*7c478bd9Sstevel@tonic-gate ct->ct_closeit = TRUE; 218*7c478bd9Sstevel@tonic-gate } else 219*7c478bd9Sstevel@tonic-gate ct->ct_closeit = FALSE; 220*7c478bd9Sstevel@tonic-gate 221*7c478bd9Sstevel@tonic-gate /* 222*7c478bd9Sstevel@tonic-gate * Set up the private data 223*7c478bd9Sstevel@tonic-gate */ 224*7c478bd9Sstevel@tonic-gate ct->ct_sock = *sockp; 225*7c478bd9Sstevel@tonic-gate ct->ct_wait_msec = 0; 226*7c478bd9Sstevel@tonic-gate ct->ct_total.tv_sec = wait.tv_sec; 227*7c478bd9Sstevel@tonic-gate ct->ct_total.tv_usec = -1; 228*7c478bd9Sstevel@tonic-gate ct->ct_raddr = *raddr; 229*7c478bd9Sstevel@tonic-gate 230*7c478bd9Sstevel@tonic-gate /* 231*7c478bd9Sstevel@tonic-gate * Initialize the call message 232*7c478bd9Sstevel@tonic-gate */ 233*7c478bd9Sstevel@tonic-gate 234*7c478bd9Sstevel@tonic-gate /* 235*7c478bd9Sstevel@tonic-gate * XXX - The xid might need to be randomized more. Imagine if there 236*7c478bd9Sstevel@tonic-gate * are a rack of blade servers all booting at the same time. They 237*7c478bd9Sstevel@tonic-gate * may cause havoc on the server with xid replays. 238*7c478bd9Sstevel@tonic-gate */ 239*7c478bd9Sstevel@tonic-gate call_msg.rm_xid = (uint_t)prom_gettime() + 1; 240*7c478bd9Sstevel@tonic-gate call_msg.rm_direction = CALL; 241*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION; 242*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_prog = program; 243*7c478bd9Sstevel@tonic-gate call_msg.rm_call.cb_vers = version; 244*7c478bd9Sstevel@tonic-gate 245*7c478bd9Sstevel@tonic-gate /* 246*7c478bd9Sstevel@tonic-gate * pre-serialize the static part of the call msg and stash it away 247*7c478bd9Sstevel@tonic-gate */ 248*7c478bd9Sstevel@tonic-gate xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE, 249*7c478bd9Sstevel@tonic-gate XDR_ENCODE); 250*7c478bd9Sstevel@tonic-gate if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) { 251*7c478bd9Sstevel@tonic-gate if (ct->ct_closeit) 252*7c478bd9Sstevel@tonic-gate (void) close(*sockp); 253*7c478bd9Sstevel@tonic-gate goto fooy; 254*7c478bd9Sstevel@tonic-gate } 255*7c478bd9Sstevel@tonic-gate ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs)); 256*7c478bd9Sstevel@tonic-gate XDR_DESTROY(&(ct->ct_xdrs)); 257*7c478bd9Sstevel@tonic-gate 258*7c478bd9Sstevel@tonic-gate /* 259*7c478bd9Sstevel@tonic-gate * XXX - Memory allocations can fail in xdrrec_create, so we need to 260*7c478bd9Sstevel@tonic-gate * be able to catch those errors. 261*7c478bd9Sstevel@tonic-gate */ 262*7c478bd9Sstevel@tonic-gate xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, (caddr_t)ct, readtcp, 263*7c478bd9Sstevel@tonic-gate writetcp); 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate cl->cl_ops = clntbtcp_ops(); 266*7c478bd9Sstevel@tonic-gate cl->cl_private = (caddr_t)ct; 267*7c478bd9Sstevel@tonic-gate cl->cl_auth = authnone_create(); 268*7c478bd9Sstevel@tonic-gate return (cl); 269*7c478bd9Sstevel@tonic-gate 270*7c478bd9Sstevel@tonic-gate fooy: 271*7c478bd9Sstevel@tonic-gate if (ct) 272*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)ct, sizeof (*ct)); 273*7c478bd9Sstevel@tonic-gate if (cl) 274*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cl, sizeof (CLIENT)); 275*7c478bd9Sstevel@tonic-gate return ((CLIENT *)NULL); 276*7c478bd9Sstevel@tonic-gate } 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate static enum clnt_stat 279*7c478bd9Sstevel@tonic-gate clntbtcp_call( 280*7c478bd9Sstevel@tonic-gate CLIENT *cl, 281*7c478bd9Sstevel@tonic-gate rpcproc_t proc, 282*7c478bd9Sstevel@tonic-gate xdrproc_t xargs, 283*7c478bd9Sstevel@tonic-gate caddr_t argsp, 284*7c478bd9Sstevel@tonic-gate xdrproc_t xdr_results, 285*7c478bd9Sstevel@tonic-gate caddr_t resultsp, 286*7c478bd9Sstevel@tonic-gate struct timeval utimeout) 287*7c478bd9Sstevel@tonic-gate { 288*7c478bd9Sstevel@tonic-gate struct ct_data *ct; 289*7c478bd9Sstevel@tonic-gate XDR *xdrs; 290*7c478bd9Sstevel@tonic-gate struct rpc_msg reply_msg; 291*7c478bd9Sstevel@tonic-gate uint32_t x_id; 292*7c478bd9Sstevel@tonic-gate uint32_t *msg_x_id; 293*7c478bd9Sstevel@tonic-gate bool_t shipnow; 294*7c478bd9Sstevel@tonic-gate int nrefreshes = 2; /* number of times to refresh cred */ 295*7c478bd9Sstevel@tonic-gate struct timeval timeout; 296*7c478bd9Sstevel@tonic-gate 297*7c478bd9Sstevel@tonic-gate ct = (struct ct_data *)cl->cl_private; 298*7c478bd9Sstevel@tonic-gate msg_x_id = (uint32_t *)ct->ct_mcall; 299*7c478bd9Sstevel@tonic-gate 300*7c478bd9Sstevel@tonic-gate xdrs = &(ct->ct_xdrs); 301*7c478bd9Sstevel@tonic-gate 302*7c478bd9Sstevel@tonic-gate ct->ct_total = utimeout; 303*7c478bd9Sstevel@tonic-gate 304*7c478bd9Sstevel@tonic-gate /* 305*7c478bd9Sstevel@tonic-gate * We have to be able to wait for some non-zero period of time, so 306*7c478bd9Sstevel@tonic-gate * use a default timeout. 307*7c478bd9Sstevel@tonic-gate */ 308*7c478bd9Sstevel@tonic-gate if (ct->ct_total.tv_sec == 0) 309*7c478bd9Sstevel@tonic-gate ct->ct_total.tv_sec = RPC_RCVWAIT_MSEC / 1000; 310*7c478bd9Sstevel@tonic-gate 311*7c478bd9Sstevel@tonic-gate ct->ct_wait_msec = ct->ct_total.tv_sec * 1000 + 312*7c478bd9Sstevel@tonic-gate ct->ct_total.tv_usec / 1000; 313*7c478bd9Sstevel@tonic-gate 314*7c478bd9Sstevel@tonic-gate timeout = ct->ct_total; 315*7c478bd9Sstevel@tonic-gate 316*7c478bd9Sstevel@tonic-gate shipnow = (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 && 317*7c478bd9Sstevel@tonic-gate timeout.tv_usec == 0) ? FALSE : TRUE; 318*7c478bd9Sstevel@tonic-gate 319*7c478bd9Sstevel@tonic-gate call_again: 320*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_ENCODE; 321*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_SUCCESS; 322*7c478bd9Sstevel@tonic-gate x_id = ntohl(++(*msg_x_id)); 323*7c478bd9Sstevel@tonic-gate if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) || 324*7c478bd9Sstevel@tonic-gate (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) || 325*7c478bd9Sstevel@tonic-gate (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) || 326*7c478bd9Sstevel@tonic-gate (! (*xargs)(xdrs, argsp))) { 327*7c478bd9Sstevel@tonic-gate (void) xdrrec_endofrecord(xdrs, TRUE); 328*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_CANTENCODEARGS; 329*7c478bd9Sstevel@tonic-gate printf("clntbtcp_call: xdr encode args failed\n"); 330*7c478bd9Sstevel@tonic-gate return (ct->ct_error.re_status); 331*7c478bd9Sstevel@tonic-gate } 332*7c478bd9Sstevel@tonic-gate 333*7c478bd9Sstevel@tonic-gate if (!xdrrec_endofrecord(xdrs, shipnow)) { 334*7c478bd9Sstevel@tonic-gate printf("clntbtcp_call: rpc cansend error\n"); 335*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_CANTSEND; 336*7c478bd9Sstevel@tonic-gate return (ct->ct_error.re_status); 337*7c478bd9Sstevel@tonic-gate } 338*7c478bd9Sstevel@tonic-gate 339*7c478bd9Sstevel@tonic-gate if (!shipnow) 340*7c478bd9Sstevel@tonic-gate return (RPC_SUCCESS); 341*7c478bd9Sstevel@tonic-gate 342*7c478bd9Sstevel@tonic-gate if (timeout.tv_sec == 0 && timeout.tv_usec == 0) { 343*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_TIMEDOUT; 344*7c478bd9Sstevel@tonic-gate return (ct->ct_error.re_status); 345*7c478bd9Sstevel@tonic-gate } 346*7c478bd9Sstevel@tonic-gate 347*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_DECODE; 348*7c478bd9Sstevel@tonic-gate 349*7c478bd9Sstevel@tonic-gate /* CONSTCOND */ 350*7c478bd9Sstevel@tonic-gate while (TRUE) { 351*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_verf = _null_auth; 352*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.where = NULL; 353*7c478bd9Sstevel@tonic-gate reply_msg.acpted_rply.ar_results.proc = xdr_void; 354*7c478bd9Sstevel@tonic-gate if (!xdrrec_skiprecord(xdrs)) { 355*7c478bd9Sstevel@tonic-gate return (ct->ct_error.re_status); 356*7c478bd9Sstevel@tonic-gate } 357*7c478bd9Sstevel@tonic-gate 358*7c478bd9Sstevel@tonic-gate if (!xdr_replymsg(xdrs, &reply_msg)) { 359*7c478bd9Sstevel@tonic-gate if (ct->ct_error.re_status == RPC_SUCCESS) 360*7c478bd9Sstevel@tonic-gate continue; 361*7c478bd9Sstevel@tonic-gate return (ct->ct_error.re_status); 362*7c478bd9Sstevel@tonic-gate } 363*7c478bd9Sstevel@tonic-gate if (reply_msg.rm_xid == x_id) { 364*7c478bd9Sstevel@tonic-gate break; 365*7c478bd9Sstevel@tonic-gate } 366*7c478bd9Sstevel@tonic-gate } 367*7c478bd9Sstevel@tonic-gate 368*7c478bd9Sstevel@tonic-gate /* 369*7c478bd9Sstevel@tonic-gate * process header 370*7c478bd9Sstevel@tonic-gate */ 371*7c478bd9Sstevel@tonic-gate _seterr_reply(&reply_msg, &(ct->ct_error)); 372*7c478bd9Sstevel@tonic-gate if (ct->ct_error.re_status == RPC_SUCCESS) { 373*7c478bd9Sstevel@tonic-gate if (!AUTH_VALIDATE(cl->cl_auth, 374*7c478bd9Sstevel@tonic-gate &reply_msg.acpted_rply.ar_verf)) { 375*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_AUTHERROR; 376*7c478bd9Sstevel@tonic-gate ct->ct_error.re_why = AUTH_INVALIDRESP; 377*7c478bd9Sstevel@tonic-gate } else if (!(*xdr_results)(xdrs, resultsp)) { 378*7c478bd9Sstevel@tonic-gate if (ct->ct_error.re_status == RPC_SUCCESS) { 379*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_CANTDECODERES; 380*7c478bd9Sstevel@tonic-gate } 381*7c478bd9Sstevel@tonic-gate } 382*7c478bd9Sstevel@tonic-gate if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) { 383*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 384*7c478bd9Sstevel@tonic-gate (void) xdr_opaque_auth(xdrs, 385*7c478bd9Sstevel@tonic-gate &(reply_msg.acpted_rply.ar_verf)); 386*7c478bd9Sstevel@tonic-gate } 387*7c478bd9Sstevel@tonic-gate } else { 388*7c478bd9Sstevel@tonic-gate if (nrefreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg, 389*7c478bd9Sstevel@tonic-gate NULL)) { 390*7c478bd9Sstevel@tonic-gate goto call_again; 391*7c478bd9Sstevel@tonic-gate } 392*7c478bd9Sstevel@tonic-gate } 393*7c478bd9Sstevel@tonic-gate return (ct->ct_error.re_status); 394*7c478bd9Sstevel@tonic-gate } 395*7c478bd9Sstevel@tonic-gate 396*7c478bd9Sstevel@tonic-gate /* 397*7c478bd9Sstevel@tonic-gate * Interface between xdr serializer and tcp connection. 398*7c478bd9Sstevel@tonic-gate * Behaves like the system calls, read & write, but keeps some error state 399*7c478bd9Sstevel@tonic-gate * around for the rpc level. 400*7c478bd9Sstevel@tonic-gate */ 401*7c478bd9Sstevel@tonic-gate static int 402*7c478bd9Sstevel@tonic-gate readtcp(struct ct_data *ct, 403*7c478bd9Sstevel@tonic-gate caddr_t buf, 404*7c478bd9Sstevel@tonic-gate int len) 405*7c478bd9Sstevel@tonic-gate { 406*7c478bd9Sstevel@tonic-gate int inlen = 0; 407*7c478bd9Sstevel@tonic-gate uint_t start, diff; 408*7c478bd9Sstevel@tonic-gate struct sockaddr from; 409*7c478bd9Sstevel@tonic-gate uint_t fromlen = sizeof (from); 410*7c478bd9Sstevel@tonic-gate 411*7c478bd9Sstevel@tonic-gate if (len <= 0) 412*7c478bd9Sstevel@tonic-gate return (0); 413*7c478bd9Sstevel@tonic-gate 414*7c478bd9Sstevel@tonic-gate /* 415*7c478bd9Sstevel@tonic-gate * Do non-blocking reads here until we get some data or timeout 416*7c478bd9Sstevel@tonic-gate */ 417*7c478bd9Sstevel@tonic-gate start = prom_gettime(); 418*7c478bd9Sstevel@tonic-gate while ((inlen = recvfrom(ct->ct_sock, buf, len, 0, &from, 419*7c478bd9Sstevel@tonic-gate &fromlen)) == 0) { 420*7c478bd9Sstevel@tonic-gate diff = (uint_t)(prom_gettime() - start); 421*7c478bd9Sstevel@tonic-gate if (diff > ct->ct_wait_msec) { 422*7c478bd9Sstevel@tonic-gate errno = ETIMEDOUT; 423*7c478bd9Sstevel@tonic-gate inlen = -1; 424*7c478bd9Sstevel@tonic-gate break; 425*7c478bd9Sstevel@tonic-gate } 426*7c478bd9Sstevel@tonic-gate } 427*7c478bd9Sstevel@tonic-gate #ifdef DEBUG 428*7c478bd9Sstevel@tonic-gate printf("readtcp: inlen = %d\n", inlen); 429*7c478bd9Sstevel@tonic-gate #endif 430*7c478bd9Sstevel@tonic-gate switch (inlen) { 431*7c478bd9Sstevel@tonic-gate case 0: 432*7c478bd9Sstevel@tonic-gate /* premature eof */ 433*7c478bd9Sstevel@tonic-gate ct->ct_error.re_errno = ECONNRESET; 434*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_CANTRECV; 435*7c478bd9Sstevel@tonic-gate inlen = -1; /* it's really an error */ 436*7c478bd9Sstevel@tonic-gate break; 437*7c478bd9Sstevel@tonic-gate case -1: 438*7c478bd9Sstevel@tonic-gate ct->ct_error.re_errno = errno; 439*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_CANTRECV; 440*7c478bd9Sstevel@tonic-gate break; 441*7c478bd9Sstevel@tonic-gate } 442*7c478bd9Sstevel@tonic-gate 443*7c478bd9Sstevel@tonic-gate return (inlen); 444*7c478bd9Sstevel@tonic-gate } 445*7c478bd9Sstevel@tonic-gate 446*7c478bd9Sstevel@tonic-gate static int 447*7c478bd9Sstevel@tonic-gate writetcp(ct, buf, len) 448*7c478bd9Sstevel@tonic-gate struct ct_data *ct; 449*7c478bd9Sstevel@tonic-gate caddr_t buf; 450*7c478bd9Sstevel@tonic-gate int len; 451*7c478bd9Sstevel@tonic-gate { 452*7c478bd9Sstevel@tonic-gate register int i, cnt; 453*7c478bd9Sstevel@tonic-gate 454*7c478bd9Sstevel@tonic-gate for (cnt = len; cnt > 0; cnt -= i, buf += i) { 455*7c478bd9Sstevel@tonic-gate if ((i = sendto(ct->ct_sock, (void *)buf, cnt, 0, 456*7c478bd9Sstevel@tonic-gate (struct sockaddr *)&(ct->ct_raddr), 457*7c478bd9Sstevel@tonic-gate sizeof (ct->ct_raddr))) == -1) { 458*7c478bd9Sstevel@tonic-gate ct->ct_error.re_errno = errno; 459*7c478bd9Sstevel@tonic-gate ct->ct_error.re_status = RPC_CANTSEND; 460*7c478bd9Sstevel@tonic-gate return (-1); 461*7c478bd9Sstevel@tonic-gate } 462*7c478bd9Sstevel@tonic-gate } 463*7c478bd9Sstevel@tonic-gate return (len); 464*7c478bd9Sstevel@tonic-gate } 465*7c478bd9Sstevel@tonic-gate 466*7c478bd9Sstevel@tonic-gate static void 467*7c478bd9Sstevel@tonic-gate clntbtcp_geterr( 468*7c478bd9Sstevel@tonic-gate CLIENT *cl, 469*7c478bd9Sstevel@tonic-gate struct rpc_err *errp) 470*7c478bd9Sstevel@tonic-gate { 471*7c478bd9Sstevel@tonic-gate struct ct_data *ct = (struct ct_data *)cl->cl_private; 472*7c478bd9Sstevel@tonic-gate 473*7c478bd9Sstevel@tonic-gate *errp = ct->ct_error; 474*7c478bd9Sstevel@tonic-gate } 475*7c478bd9Sstevel@tonic-gate 476*7c478bd9Sstevel@tonic-gate 477*7c478bd9Sstevel@tonic-gate static bool_t 478*7c478bd9Sstevel@tonic-gate clntbtcp_freeres( 479*7c478bd9Sstevel@tonic-gate CLIENT *cl, 480*7c478bd9Sstevel@tonic-gate xdrproc_t xdr_res, 481*7c478bd9Sstevel@tonic-gate caddr_t res_ptr) 482*7c478bd9Sstevel@tonic-gate { 483*7c478bd9Sstevel@tonic-gate struct ct_data *ct = (struct ct_data *)cl->cl_private; 484*7c478bd9Sstevel@tonic-gate XDR *xdrs = &(ct->ct_xdrs); 485*7c478bd9Sstevel@tonic-gate 486*7c478bd9Sstevel@tonic-gate xdrs->x_op = XDR_FREE; 487*7c478bd9Sstevel@tonic-gate return ((*xdr_res)(xdrs, res_ptr)); 488*7c478bd9Sstevel@tonic-gate } 489*7c478bd9Sstevel@tonic-gate 490*7c478bd9Sstevel@tonic-gate static void 491*7c478bd9Sstevel@tonic-gate clntbtcp_abort() 492*7c478bd9Sstevel@tonic-gate /* CLIENT *h; */ 493*7c478bd9Sstevel@tonic-gate { 494*7c478bd9Sstevel@tonic-gate } 495*7c478bd9Sstevel@tonic-gate 496*7c478bd9Sstevel@tonic-gate /* ARGSUSED */ 497*7c478bd9Sstevel@tonic-gate static bool_t 498*7c478bd9Sstevel@tonic-gate clntbtcp_control( 499*7c478bd9Sstevel@tonic-gate CLIENT *cl, 500*7c478bd9Sstevel@tonic-gate int request, 501*7c478bd9Sstevel@tonic-gate char *info) 502*7c478bd9Sstevel@tonic-gate { 503*7c478bd9Sstevel@tonic-gate /* Not implemented in boot */ 504*7c478bd9Sstevel@tonic-gate return (FALSE); 505*7c478bd9Sstevel@tonic-gate } 506*7c478bd9Sstevel@tonic-gate 507*7c478bd9Sstevel@tonic-gate static void 508*7c478bd9Sstevel@tonic-gate clntbtcp_destroy(CLIENT *cl) 509*7c478bd9Sstevel@tonic-gate { 510*7c478bd9Sstevel@tonic-gate struct ct_data *ct = (struct ct_data *)cl->cl_private; 511*7c478bd9Sstevel@tonic-gate 512*7c478bd9Sstevel@tonic-gate if (ct->ct_closeit) { 513*7c478bd9Sstevel@tonic-gate (void) socket_close(ct->ct_sock); 514*7c478bd9Sstevel@tonic-gate } 515*7c478bd9Sstevel@tonic-gate XDR_DESTROY(&(ct->ct_xdrs)); 516*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)ct, (sizeof (struct ct_data))); 517*7c478bd9Sstevel@tonic-gate bkmem_free((caddr_t)cl, sizeof (CLIENT)); 518*7c478bd9Sstevel@tonic-gate } 519*7c478bd9Sstevel@tonic-gate 520*7c478bd9Sstevel@tonic-gate static struct clnt_ops * 521*7c478bd9Sstevel@tonic-gate clntbtcp_ops() 522*7c478bd9Sstevel@tonic-gate { 523*7c478bd9Sstevel@tonic-gate static struct clnt_ops ops; 524*7c478bd9Sstevel@tonic-gate 525*7c478bd9Sstevel@tonic-gate if (ops.cl_call == NULL) { 526*7c478bd9Sstevel@tonic-gate ops.cl_call = clntbtcp_call; 527*7c478bd9Sstevel@tonic-gate ops.cl_abort = clntbtcp_abort; 528*7c478bd9Sstevel@tonic-gate ops.cl_geterr = clntbtcp_geterr; 529*7c478bd9Sstevel@tonic-gate ops.cl_freeres = clntbtcp_freeres; 530*7c478bd9Sstevel@tonic-gate ops.cl_destroy = clntbtcp_destroy; 531*7c478bd9Sstevel@tonic-gate ops.cl_control = clntbtcp_control; 532*7c478bd9Sstevel@tonic-gate } 533*7c478bd9Sstevel@tonic-gate return (&ops); 534*7c478bd9Sstevel@tonic-gate } 535