xref: /illumos-gate/usr/src/stand/lib/fs/nfs/clnt_btcp.c (revision b531f6d1)
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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2004 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 /*
367c478bd9Sstevel@tonic-gate  * Boot subsystem client side rpc (TCP)
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include <sys/salib.h>
407c478bd9Sstevel@tonic-gate #include <sys/errno.h>
417c478bd9Sstevel@tonic-gate #include <rpc/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/socket.h>
437c478bd9Sstevel@tonic-gate #include <netinet/in.h>
447c478bd9Sstevel@tonic-gate #include "socket_inet.h"
457c478bd9Sstevel@tonic-gate #include "ipv4.h"
467c478bd9Sstevel@tonic-gate #include "clnt.h"
477c478bd9Sstevel@tonic-gate #include <rpc/rpc.h>
487c478bd9Sstevel@tonic-gate #include "brpc.h"
497c478bd9Sstevel@tonic-gate #include "pmap.h"
507c478bd9Sstevel@tonic-gate #include <sys/promif.h>
517c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
527c478bd9Sstevel@tonic-gate #include <rpc/auth.h>
537c478bd9Sstevel@tonic-gate #include <rpc/auth_sys.h>
547c478bd9Sstevel@tonic-gate #include "auth_inet.h"
557c478bd9Sstevel@tonic-gate #include <rpc/rpc_msg.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 #define	MCALL_MSG_SIZE 24
617c478bd9Sstevel@tonic-gate 
627c478bd9Sstevel@tonic-gate extern int errno;
637c478bd9Sstevel@tonic-gate 
647c478bd9Sstevel@tonic-gate extern void xdrrec_create();
657c478bd9Sstevel@tonic-gate extern bool_t xdrrec_endofrecord();
667c478bd9Sstevel@tonic-gate extern bool_t xdrrec_skiprecord();
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * If we create another clnt type this should be
707c478bd9Sstevel@tonic-gate  * moved to a common file
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate struct rpc_createerr rpc_createerr;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static int readtcp();
757c478bd9Sstevel@tonic-gate static int writetcp();
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate static struct clnt_ops *clntbtcp_ops();
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate /*
807c478bd9Sstevel@tonic-gate  * Private data kept per client handle
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate struct ct_data {
837c478bd9Sstevel@tonic-gate 	int			ct_sock;
847c478bd9Sstevel@tonic-gate 	bool_t			ct_closeit;
857c478bd9Sstevel@tonic-gate 	struct sockaddr_in	ct_raddr;
867c478bd9Sstevel@tonic-gate 	uint_t			ct_wait_msec;
877c478bd9Sstevel@tonic-gate 	struct timeval		ct_total;
887c478bd9Sstevel@tonic-gate 	struct rpc_err		ct_error;
897c478bd9Sstevel@tonic-gate 	XDR			ct_xdrs;
907c478bd9Sstevel@tonic-gate 	char			ct_mcall[MCALL_MSG_SIZE];
917c478bd9Sstevel@tonic-gate 	uint_t			ct_mpos;
927c478bd9Sstevel@tonic-gate 	uint_t			ct_xdrpos;
937c478bd9Sstevel@tonic-gate };
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * Create a TCP based client handle.
977c478bd9Sstevel@tonic-gate  * If *sockp<0, *sockp is set to a newly created TCP socket.
987c478bd9Sstevel@tonic-gate  * If raddr->sin_port is 0 a binder on the remote machine
997c478bd9Sstevel@tonic-gate  * is consulted for the correct port number.
1007c478bd9Sstevel@tonic-gate  * NB: It is the clients responsibility to close *sockp.
1017c478bd9Sstevel@tonic-gate  * NB: The rpch->cl_auth is initialized to null authentication.
1027c478bd9Sstevel@tonic-gate  *	Caller may wish to set this something more useful.
1037c478bd9Sstevel@tonic-gate  *
1047c478bd9Sstevel@tonic-gate  * wait is the amount of time used between retransmitting a call if
1057c478bd9Sstevel@tonic-gate  * no response has been heard;  retransmition occurs until the actual
1067c478bd9Sstevel@tonic-gate  * rpc call times out.
1077c478bd9Sstevel@tonic-gate  *
1087c478bd9Sstevel@tonic-gate  * sendsz and recvsz are the maximum allowable packet sizes that can be
1097c478bd9Sstevel@tonic-gate  * sent and received.
1107c478bd9Sstevel@tonic-gate  */
1117c478bd9Sstevel@tonic-gate CLIENT *
clntbtcp_create(struct sockaddr_in * raddr,rpcprog_t program,rpcvers_t version,struct timeval wait,int * sockp,uint_t sendsz,uint_t recvsz)1127c478bd9Sstevel@tonic-gate clntbtcp_create(
1137c478bd9Sstevel@tonic-gate 	struct sockaddr_in *raddr,
1147c478bd9Sstevel@tonic-gate 	rpcprog_t program,
1157c478bd9Sstevel@tonic-gate 	rpcvers_t version,
1167c478bd9Sstevel@tonic-gate 	struct timeval wait,
1177c478bd9Sstevel@tonic-gate 	int *sockp,
1187c478bd9Sstevel@tonic-gate 	uint_t sendsz,
1197c478bd9Sstevel@tonic-gate 	uint_t recvsz)
1207c478bd9Sstevel@tonic-gate {
1217c478bd9Sstevel@tonic-gate 	CLIENT *cl;
1227c478bd9Sstevel@tonic-gate 	struct ct_data *ct;
1237c478bd9Sstevel@tonic-gate 	struct rpc_msg call_msg;
1247c478bd9Sstevel@tonic-gate #if 0	/* XXX not yet */
1257c478bd9Sstevel@tonic-gate 	int min_buf_sz;
1267c478bd9Sstevel@tonic-gate 	int pref_buf_sz = 64 * 1024; /* 64 KB */
1277c478bd9Sstevel@tonic-gate 	socklen_t optlen;
1287c478bd9Sstevel@tonic-gate #endif /* not yet */
1297c478bd9Sstevel@tonic-gate 	cl = (CLIENT *)bkmem_alloc(sizeof (CLIENT));
1307c478bd9Sstevel@tonic-gate 	if (cl == NULL) {
1317c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
1327c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1337c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_error.re_errno = errno;
1347c478bd9Sstevel@tonic-gate 		return ((CLIENT *)NULL);
1357c478bd9Sstevel@tonic-gate 	}
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate 	ct = (struct ct_data *)bkmem_alloc(sizeof (*ct));
1387c478bd9Sstevel@tonic-gate 	if (ct == NULL) {
1397c478bd9Sstevel@tonic-gate 		errno = ENOMEM;
1407c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1417c478bd9Sstevel@tonic-gate 		rpc_createerr.cf_error.re_errno = errno;
1427c478bd9Sstevel@tonic-gate 		goto fooy;
1437c478bd9Sstevel@tonic-gate 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	if (raddr->sin_port == 0) {
1467c478bd9Sstevel@tonic-gate 		ushort_t port;
1477c478bd9Sstevel@tonic-gate 		if ((port = bpmap_getport(program, version,
1487c478bd9Sstevel@tonic-gate 				&(rpc_createerr.cf_stat), raddr, NULL)) == 0) {
1497c478bd9Sstevel@tonic-gate 			goto fooy;
1507c478bd9Sstevel@tonic-gate 		}
1517c478bd9Sstevel@tonic-gate 		raddr->sin_port = htons(port);
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	if (*sockp < 0) {
1557c478bd9Sstevel@tonic-gate 		struct sockaddr_in from;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 		*sockp = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP);
1587c478bd9Sstevel@tonic-gate 		if (*sockp < 0) {
1597c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1607c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_error.re_errno = errno;
1617c478bd9Sstevel@tonic-gate 			goto fooy;
1627c478bd9Sstevel@tonic-gate 		}
1637c478bd9Sstevel@tonic-gate 		/*
1647c478bd9Sstevel@tonic-gate 		 * Bootparams assumes a local net, so be sure to let lower
1657c478bd9Sstevel@tonic-gate 		 * layer protocols know not to route.
1667c478bd9Sstevel@tonic-gate 		 */
1677c478bd9Sstevel@tonic-gate 		if (dontroute) {
1687c478bd9Sstevel@tonic-gate 			(void) setsockopt(*sockp, SOL_SOCKET, SO_DONTROUTE,
1697c478bd9Sstevel@tonic-gate 				(const void *)&dontroute, sizeof (dontroute));
1707c478bd9Sstevel@tonic-gate 		}
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 		/* attempt to bind to priv port */
1737c478bd9Sstevel@tonic-gate 		from.sin_family = AF_INET;
1747c478bd9Sstevel@tonic-gate 		ipv4_getipaddr(&from.sin_addr);
1757c478bd9Sstevel@tonic-gate 		from.sin_addr.s_addr = htonl(from.sin_addr.s_addr);
1767c478bd9Sstevel@tonic-gate 		from.sin_port = get_source_port(TRUE);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 		if (bind(*sockp, (struct sockaddr *)&from, sizeof (from)) < 0) {
1797c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1807c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_error.re_errno = errno;
1817c478bd9Sstevel@tonic-gate 			if (*sockp > 0)
182*b531f6d1SToomas Soome 				(void) close(*sockp);
1837c478bd9Sstevel@tonic-gate 			goto fooy;
1847c478bd9Sstevel@tonic-gate 		}
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 		if (connect(*sockp, (struct sockaddr *)raddr,
1877c478bd9Sstevel@tonic-gate 			    sizeof (struct sockaddr_in)) < 0) {
1887c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_stat = RPC_SYSTEMERROR;
1897c478bd9Sstevel@tonic-gate 			rpc_createerr.cf_error.re_errno = errno;
1907c478bd9Sstevel@tonic-gate 			if (*sockp > 0)
191*b531f6d1SToomas Soome 				(void) close(*sockp);
1927c478bd9Sstevel@tonic-gate 			goto fooy;
1937c478bd9Sstevel@tonic-gate 		}
1947c478bd9Sstevel@tonic-gate 
1957c478bd9Sstevel@tonic-gate #if 0 /* XXX not yet */
1967c478bd9Sstevel@tonic-gate 		/*
1977c478bd9Sstevel@tonic-gate 		 * In the future we may want RPC to use larger transfer sizes
1987c478bd9Sstevel@tonic-gate 		 * over TCP.  In this case we will want to increase the
1997c478bd9Sstevel@tonic-gate 		 * window size.
2007c478bd9Sstevel@tonic-gate 		 */
2017c478bd9Sstevel@tonic-gate 		/*
2027c478bd9Sstevel@tonic-gate 		 * Resize the receive window if possible
2037c478bd9Sstevel@tonic-gate 		 */
2047c478bd9Sstevel@tonic-gate 		optlen = sizeof (int);
2057c478bd9Sstevel@tonic-gate 		if (getsockopt(*sockp, SOL_SOCKET, SO_RCVBUF,
2067c478bd9Sstevel@tonic-gate 				(void *)&min_buf_sz, &optlen) != 0)
2077c478bd9Sstevel@tonic-gate 			goto keep_going;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 		if (min_buf_sz < pref_buf_sz)
2107c478bd9Sstevel@tonic-gate 			(void) setsockopt(*sockp, SOL_SOCKET, SO_RCVBUF,
2117c478bd9Sstevel@tonic-gate 				(const void *)&pref_buf_sz, sizeof (int));
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate keep_going:
2147c478bd9Sstevel@tonic-gate #endif		/* not yet */
2157c478bd9Sstevel@tonic-gate 		ct->ct_closeit = TRUE;
2167c478bd9Sstevel@tonic-gate 	} else
2177c478bd9Sstevel@tonic-gate 		ct->ct_closeit = FALSE;
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	/*
2207c478bd9Sstevel@tonic-gate 	 * Set up the private data
2217c478bd9Sstevel@tonic-gate 	 */
2227c478bd9Sstevel@tonic-gate 	ct->ct_sock = *sockp;
2237c478bd9Sstevel@tonic-gate 	ct->ct_wait_msec = 0;
2247c478bd9Sstevel@tonic-gate 	ct->ct_total.tv_sec = wait.tv_sec;
2257c478bd9Sstevel@tonic-gate 	ct->ct_total.tv_usec = -1;
2267c478bd9Sstevel@tonic-gate 	ct->ct_raddr = *raddr;
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate 	/*
2297c478bd9Sstevel@tonic-gate 	 * Initialize the call message
2307c478bd9Sstevel@tonic-gate 	 */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	/*
2337c478bd9Sstevel@tonic-gate 	 * XXX - The xid might need to be randomized more.  Imagine if there
2347c478bd9Sstevel@tonic-gate 	 * are a rack of blade servers all booting at the same time.  They
2357c478bd9Sstevel@tonic-gate 	 * may cause havoc on the server with xid replays.
2367c478bd9Sstevel@tonic-gate 	 */
2377c478bd9Sstevel@tonic-gate 	call_msg.rm_xid = (uint_t)prom_gettime() + 1;
2387c478bd9Sstevel@tonic-gate 	call_msg.rm_direction = CALL;
2397c478bd9Sstevel@tonic-gate 	call_msg.rm_call.cb_rpcvers = RPC_MSG_VERSION;
2407c478bd9Sstevel@tonic-gate 	call_msg.rm_call.cb_prog = program;
2417c478bd9Sstevel@tonic-gate 	call_msg.rm_call.cb_vers = version;
2427c478bd9Sstevel@tonic-gate 
2437c478bd9Sstevel@tonic-gate 	/*
2447c478bd9Sstevel@tonic-gate 	 * pre-serialize the static part of the call msg and stash it away
2457c478bd9Sstevel@tonic-gate 	 */
2467c478bd9Sstevel@tonic-gate 	xdrmem_create(&(ct->ct_xdrs), ct->ct_mcall, MCALL_MSG_SIZE,
2477c478bd9Sstevel@tonic-gate 			XDR_ENCODE);
2487c478bd9Sstevel@tonic-gate 	if (! xdr_callhdr(&(ct->ct_xdrs), &call_msg)) {
2497c478bd9Sstevel@tonic-gate 		if (ct->ct_closeit)
2507c478bd9Sstevel@tonic-gate 			(void) close(*sockp);
2517c478bd9Sstevel@tonic-gate 		goto fooy;
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 	ct->ct_mpos = XDR_GETPOS(&(ct->ct_xdrs));
2547c478bd9Sstevel@tonic-gate 	XDR_DESTROY(&(ct->ct_xdrs));
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate 	/*
2577c478bd9Sstevel@tonic-gate 	 * XXX - Memory allocations can fail in xdrrec_create, so we need to
2587c478bd9Sstevel@tonic-gate 	 * be able to catch those errors.
2597c478bd9Sstevel@tonic-gate 	 */
2607c478bd9Sstevel@tonic-gate 	xdrrec_create(&(ct->ct_xdrs), sendsz, recvsz, (caddr_t)ct, readtcp,
2617c478bd9Sstevel@tonic-gate 			writetcp);
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 	cl->cl_ops = clntbtcp_ops();
2647c478bd9Sstevel@tonic-gate 	cl->cl_private = (caddr_t)ct;
2657c478bd9Sstevel@tonic-gate 	cl->cl_auth = authnone_create();
2667c478bd9Sstevel@tonic-gate 	return (cl);
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate fooy:
2697c478bd9Sstevel@tonic-gate 	if (ct)
2707c478bd9Sstevel@tonic-gate 		bkmem_free((caddr_t)ct, sizeof (*ct));
2717c478bd9Sstevel@tonic-gate 	if (cl)
2727c478bd9Sstevel@tonic-gate 		bkmem_free((caddr_t)cl, sizeof (CLIENT));
2737c478bd9Sstevel@tonic-gate 	return ((CLIENT *)NULL);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate static enum clnt_stat
clntbtcp_call(CLIENT * cl,rpcproc_t proc,xdrproc_t xargs,caddr_t argsp,xdrproc_t xdr_results,caddr_t resultsp,struct timeval utimeout)2777c478bd9Sstevel@tonic-gate clntbtcp_call(
2787c478bd9Sstevel@tonic-gate 	CLIENT *cl,
2797c478bd9Sstevel@tonic-gate 	rpcproc_t proc,
2807c478bd9Sstevel@tonic-gate 	xdrproc_t xargs,
2817c478bd9Sstevel@tonic-gate 	caddr_t argsp,
2827c478bd9Sstevel@tonic-gate 	xdrproc_t xdr_results,
2837c478bd9Sstevel@tonic-gate 	caddr_t resultsp,
2847c478bd9Sstevel@tonic-gate 	struct timeval utimeout)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	struct ct_data *ct;
2877c478bd9Sstevel@tonic-gate 	XDR *xdrs;
2887c478bd9Sstevel@tonic-gate 	struct rpc_msg reply_msg;
2897c478bd9Sstevel@tonic-gate 	uint32_t x_id;
2907c478bd9Sstevel@tonic-gate 	uint32_t *msg_x_id;
2917c478bd9Sstevel@tonic-gate 	bool_t shipnow;
2927c478bd9Sstevel@tonic-gate 	int nrefreshes = 2;	/* number of times to refresh cred */
2937c478bd9Sstevel@tonic-gate 	struct timeval timeout;
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	ct = (struct ct_data *)cl->cl_private;
2967c478bd9Sstevel@tonic-gate 	msg_x_id = (uint32_t *)ct->ct_mcall;
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 	xdrs = &(ct->ct_xdrs);
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	ct->ct_total = utimeout;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/*
3037c478bd9Sstevel@tonic-gate 	 * We have to be able to wait for some non-zero period of time, so
3047c478bd9Sstevel@tonic-gate 	 * use a default timeout.
3057c478bd9Sstevel@tonic-gate 	 */
3067c478bd9Sstevel@tonic-gate 	if (ct->ct_total.tv_sec == 0)
3077c478bd9Sstevel@tonic-gate 		ct->ct_total.tv_sec = RPC_RCVWAIT_MSEC / 1000;
3087c478bd9Sstevel@tonic-gate 
3097c478bd9Sstevel@tonic-gate 	ct->ct_wait_msec = ct->ct_total.tv_sec * 1000 +
3107c478bd9Sstevel@tonic-gate 		ct->ct_total.tv_usec / 1000;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	timeout = ct->ct_total;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	shipnow = (xdr_results == (xdrproc_t)0 && timeout.tv_sec == 0 &&
3157c478bd9Sstevel@tonic-gate 			timeout.tv_usec == 0) ? FALSE : TRUE;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate call_again:
3187c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_ENCODE;
3197c478bd9Sstevel@tonic-gate 	ct->ct_error.re_status = RPC_SUCCESS;
3207c478bd9Sstevel@tonic-gate 	x_id = ntohl(++(*msg_x_id));
3217c478bd9Sstevel@tonic-gate 	if ((! XDR_PUTBYTES(xdrs, ct->ct_mcall, ct->ct_mpos)) ||
3227c478bd9Sstevel@tonic-gate 	    (! XDR_PUTINT32(xdrs, (int32_t *)&proc)) ||
3237c478bd9Sstevel@tonic-gate 	    (! AUTH_MARSHALL(cl->cl_auth, xdrs, NULL)) ||
3247c478bd9Sstevel@tonic-gate 	    (! (*xargs)(xdrs, argsp))) {
3257c478bd9Sstevel@tonic-gate 		(void) xdrrec_endofrecord(xdrs, TRUE);
3267c478bd9Sstevel@tonic-gate 		ct->ct_error.re_status = RPC_CANTENCODEARGS;
3277c478bd9Sstevel@tonic-gate 		printf("clntbtcp_call: xdr encode args failed\n");
3287c478bd9Sstevel@tonic-gate 		return (ct->ct_error.re_status);
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	if (!xdrrec_endofrecord(xdrs, shipnow)) {
3327c478bd9Sstevel@tonic-gate 		printf("clntbtcp_call: rpc cansend error\n");
3337c478bd9Sstevel@tonic-gate 		ct->ct_error.re_status = RPC_CANTSEND;
3347c478bd9Sstevel@tonic-gate 		return (ct->ct_error.re_status);
3357c478bd9Sstevel@tonic-gate 	}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 	if (!shipnow)
3387c478bd9Sstevel@tonic-gate 		return (RPC_SUCCESS);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	if (timeout.tv_sec == 0 && timeout.tv_usec == 0) {
3417c478bd9Sstevel@tonic-gate 		ct->ct_error.re_status = RPC_TIMEDOUT;
3427c478bd9Sstevel@tonic-gate 		return (ct->ct_error.re_status);
3437c478bd9Sstevel@tonic-gate 	}
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_DECODE;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	/* CONSTCOND */
3487c478bd9Sstevel@tonic-gate 	while (TRUE) {
3497c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_verf = _null_auth;
3507c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.where = NULL;
3517c478bd9Sstevel@tonic-gate 		reply_msg.acpted_rply.ar_results.proc = xdr_void;
3527c478bd9Sstevel@tonic-gate 		if (!xdrrec_skiprecord(xdrs)) {
3537c478bd9Sstevel@tonic-gate 			return (ct->ct_error.re_status);
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 		if (!xdr_replymsg(xdrs, &reply_msg)) {
3577c478bd9Sstevel@tonic-gate 			if (ct->ct_error.re_status == RPC_SUCCESS)
3587c478bd9Sstevel@tonic-gate 				continue;
3597c478bd9Sstevel@tonic-gate 			return (ct->ct_error.re_status);
3607c478bd9Sstevel@tonic-gate 		}
3617c478bd9Sstevel@tonic-gate 		if (reply_msg.rm_xid == x_id) {
3627c478bd9Sstevel@tonic-gate 			break;
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 	}
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate 	/*
3677c478bd9Sstevel@tonic-gate 	 * process header
3687c478bd9Sstevel@tonic-gate 	 */
3697c478bd9Sstevel@tonic-gate 	_seterr_reply(&reply_msg, &(ct->ct_error));
3707c478bd9Sstevel@tonic-gate 	if (ct->ct_error.re_status == RPC_SUCCESS) {
3717c478bd9Sstevel@tonic-gate 		if (!AUTH_VALIDATE(cl->cl_auth,
3727c478bd9Sstevel@tonic-gate 				&reply_msg.acpted_rply.ar_verf)) {
3737c478bd9Sstevel@tonic-gate 			ct->ct_error.re_status = RPC_AUTHERROR;
3747c478bd9Sstevel@tonic-gate 			ct->ct_error.re_why = AUTH_INVALIDRESP;
3757c478bd9Sstevel@tonic-gate 		} else if (!(*xdr_results)(xdrs, resultsp)) {
3767c478bd9Sstevel@tonic-gate 			if (ct->ct_error.re_status == RPC_SUCCESS) {
3777c478bd9Sstevel@tonic-gate 				ct->ct_error.re_status = RPC_CANTDECODERES;
3787c478bd9Sstevel@tonic-gate 			}
3797c478bd9Sstevel@tonic-gate 		}
3807c478bd9Sstevel@tonic-gate 		if (reply_msg.acpted_rply.ar_verf.oa_base != NULL) {
3817c478bd9Sstevel@tonic-gate 			xdrs->x_op = XDR_FREE;
3827c478bd9Sstevel@tonic-gate 			(void) xdr_opaque_auth(xdrs,
3837c478bd9Sstevel@tonic-gate 				&(reply_msg.acpted_rply.ar_verf));
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 	} else {
3867c478bd9Sstevel@tonic-gate 		if (nrefreshes-- && AUTH_REFRESH(cl->cl_auth, &reply_msg,
3877c478bd9Sstevel@tonic-gate 						NULL)) {
3887c478bd9Sstevel@tonic-gate 			goto call_again;
3897c478bd9Sstevel@tonic-gate 		}
3907c478bd9Sstevel@tonic-gate 	}
3917c478bd9Sstevel@tonic-gate 	return (ct->ct_error.re_status);
3927c478bd9Sstevel@tonic-gate }
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate /*
3957c478bd9Sstevel@tonic-gate  * Interface between xdr serializer and tcp connection.
3967c478bd9Sstevel@tonic-gate  * Behaves like the system calls, read & write, but keeps some error state
3977c478bd9Sstevel@tonic-gate  * around for the rpc level.
3987c478bd9Sstevel@tonic-gate  */
3997c478bd9Sstevel@tonic-gate static int
readtcp(struct ct_data * ct,caddr_t buf,int len)4007c478bd9Sstevel@tonic-gate readtcp(struct ct_data *ct,
4017c478bd9Sstevel@tonic-gate 	caddr_t buf,
4027c478bd9Sstevel@tonic-gate 	int len)
4037c478bd9Sstevel@tonic-gate {
4047c478bd9Sstevel@tonic-gate 	int inlen = 0;
4057c478bd9Sstevel@tonic-gate 	uint_t start, diff;
4067c478bd9Sstevel@tonic-gate 	struct sockaddr from;
4077c478bd9Sstevel@tonic-gate 	uint_t fromlen = sizeof (from);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	if (len <= 0)
4107c478bd9Sstevel@tonic-gate 		return (0);
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/*
4137c478bd9Sstevel@tonic-gate 	 * Do non-blocking reads here until we get some data or timeout
4147c478bd9Sstevel@tonic-gate 	 */
4157c478bd9Sstevel@tonic-gate 	start = prom_gettime();
4167c478bd9Sstevel@tonic-gate 	while ((inlen = recvfrom(ct->ct_sock, buf, len, 0, &from,
4177c478bd9Sstevel@tonic-gate 					&fromlen)) == 0) {
4187c478bd9Sstevel@tonic-gate 		diff = (uint_t)(prom_gettime() - start);
4197c478bd9Sstevel@tonic-gate 		if (diff > ct->ct_wait_msec) {
4207c478bd9Sstevel@tonic-gate 			errno = ETIMEDOUT;
4217c478bd9Sstevel@tonic-gate 			inlen = -1;
4227c478bd9Sstevel@tonic-gate 			break;
4237c478bd9Sstevel@tonic-gate 		}
4247c478bd9Sstevel@tonic-gate 	}
4257c478bd9Sstevel@tonic-gate #ifdef DEBUG
4267c478bd9Sstevel@tonic-gate 	printf("readtcp: inlen = %d\n", inlen);
4277c478bd9Sstevel@tonic-gate #endif
4287c478bd9Sstevel@tonic-gate 	switch (inlen) {
4297c478bd9Sstevel@tonic-gate 	case 0:
4307c478bd9Sstevel@tonic-gate 		/* premature eof */
4317c478bd9Sstevel@tonic-gate 		ct->ct_error.re_errno = ECONNRESET;
4327c478bd9Sstevel@tonic-gate 		ct->ct_error.re_status = RPC_CANTRECV;
4337c478bd9Sstevel@tonic-gate 		inlen = -1;  /* it's really an error */
4347c478bd9Sstevel@tonic-gate 		break;
4357c478bd9Sstevel@tonic-gate 	case -1:
4367c478bd9Sstevel@tonic-gate 		ct->ct_error.re_errno = errno;
4377c478bd9Sstevel@tonic-gate 		ct->ct_error.re_status = RPC_CANTRECV;
4387c478bd9Sstevel@tonic-gate 		break;
4397c478bd9Sstevel@tonic-gate 	}
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	return (inlen);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate static int
writetcp(ct,buf,len)4457c478bd9Sstevel@tonic-gate writetcp(ct, buf, len)
4467c478bd9Sstevel@tonic-gate 	struct ct_data *ct;
4477c478bd9Sstevel@tonic-gate 	caddr_t buf;
4487c478bd9Sstevel@tonic-gate 	int len;
4497c478bd9Sstevel@tonic-gate {
4507c478bd9Sstevel@tonic-gate 	register int i, cnt;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	for (cnt = len; cnt > 0; cnt -= i, buf += i) {
4537c478bd9Sstevel@tonic-gate 		if ((i = sendto(ct->ct_sock, (void *)buf, cnt, 0,
4547c478bd9Sstevel@tonic-gate 				(struct sockaddr *)&(ct->ct_raddr),
4557c478bd9Sstevel@tonic-gate 				sizeof (ct->ct_raddr))) == -1) {
4567c478bd9Sstevel@tonic-gate 			ct->ct_error.re_errno = errno;
4577c478bd9Sstevel@tonic-gate 			ct->ct_error.re_status = RPC_CANTSEND;
4587c478bd9Sstevel@tonic-gate 			return (-1);
4597c478bd9Sstevel@tonic-gate 		}
4607c478bd9Sstevel@tonic-gate 	}
4617c478bd9Sstevel@tonic-gate 	return (len);
4627c478bd9Sstevel@tonic-gate }
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate static void
clntbtcp_geterr(CLIENT * cl,struct rpc_err * errp)4657c478bd9Sstevel@tonic-gate clntbtcp_geterr(
4667c478bd9Sstevel@tonic-gate 	CLIENT *cl,
4677c478bd9Sstevel@tonic-gate 	struct rpc_err *errp)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	*errp = ct->ct_error;
4727c478bd9Sstevel@tonic-gate }
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate static bool_t
clntbtcp_freeres(CLIENT * cl,xdrproc_t xdr_res,caddr_t res_ptr)4767c478bd9Sstevel@tonic-gate clntbtcp_freeres(
4777c478bd9Sstevel@tonic-gate 	CLIENT *cl,
4787c478bd9Sstevel@tonic-gate 	xdrproc_t xdr_res,
4797c478bd9Sstevel@tonic-gate 	caddr_t res_ptr)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
4827c478bd9Sstevel@tonic-gate 	XDR *xdrs = &(ct->ct_xdrs);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	xdrs->x_op = XDR_FREE;
4857c478bd9Sstevel@tonic-gate 	return ((*xdr_res)(xdrs, res_ptr));
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate static void
clntbtcp_abort()4897c478bd9Sstevel@tonic-gate clntbtcp_abort()
4907c478bd9Sstevel@tonic-gate 	/* CLIENT *h; */
4917c478bd9Sstevel@tonic-gate {
4927c478bd9Sstevel@tonic-gate }
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate /* ARGSUSED */
4957c478bd9Sstevel@tonic-gate static bool_t
clntbtcp_control(CLIENT * cl,int request,char * info)4967c478bd9Sstevel@tonic-gate clntbtcp_control(
4977c478bd9Sstevel@tonic-gate 	CLIENT *cl,
4987c478bd9Sstevel@tonic-gate 	int request,
4997c478bd9Sstevel@tonic-gate 	char *info)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	/* Not implemented in boot */
5027c478bd9Sstevel@tonic-gate 	return (FALSE);
5037c478bd9Sstevel@tonic-gate }
5047c478bd9Sstevel@tonic-gate 
5057c478bd9Sstevel@tonic-gate static void
clntbtcp_destroy(CLIENT * cl)5067c478bd9Sstevel@tonic-gate clntbtcp_destroy(CLIENT *cl)
5077c478bd9Sstevel@tonic-gate {
5087c478bd9Sstevel@tonic-gate 	struct ct_data *ct = (struct ct_data *)cl->cl_private;
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate 	if (ct->ct_closeit) {
5117c478bd9Sstevel@tonic-gate 		(void) socket_close(ct->ct_sock);
5127c478bd9Sstevel@tonic-gate 	}
5137c478bd9Sstevel@tonic-gate 	XDR_DESTROY(&(ct->ct_xdrs));
5147c478bd9Sstevel@tonic-gate 	bkmem_free((caddr_t)ct, (sizeof (struct ct_data)));
5157c478bd9Sstevel@tonic-gate 	bkmem_free((caddr_t)cl, sizeof (CLIENT));
5167c478bd9Sstevel@tonic-gate }
5177c478bd9Sstevel@tonic-gate 
5187c478bd9Sstevel@tonic-gate static struct clnt_ops *
clntbtcp_ops()5197c478bd9Sstevel@tonic-gate clntbtcp_ops()
5207c478bd9Sstevel@tonic-gate {
5217c478bd9Sstevel@tonic-gate 	static struct clnt_ops ops;
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	if (ops.cl_call == NULL) {
5247c478bd9Sstevel@tonic-gate 		ops.cl_call = clntbtcp_call;
5257c478bd9Sstevel@tonic-gate 		ops.cl_abort = clntbtcp_abort;
5267c478bd9Sstevel@tonic-gate 		ops.cl_geterr = clntbtcp_geterr;
5277c478bd9Sstevel@tonic-gate 		ops.cl_freeres = clntbtcp_freeres;
5287c478bd9Sstevel@tonic-gate 		ops.cl_destroy = clntbtcp_destroy;
5297c478bd9Sstevel@tonic-gate 		ops.cl_control = clntbtcp_control;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 	return (&ops);
5327c478bd9Sstevel@tonic-gate }
533