xref: /titanic_52/usr/src/stand/lib/fs/nfs/xdr_rec.c (revision 53391baf4e45c693cf123555e9617b5e1e0b641a)
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 /*
23*53391bafSeota  * Copyright 2005 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  * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
397c478bd9Sstevel@tonic-gate  * layer above tcp (for rpc's use).
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * These routines interface XDRSTREAMS to a tcp/ip connection.
427c478bd9Sstevel@tonic-gate  * There is a record marking layer between the xdr stream
437c478bd9Sstevel@tonic-gate  * and the tcp transport level.  A record is composed on one or more
447c478bd9Sstevel@tonic-gate  * record fragments.  A record fragment is a thirty-two bit header followed
457c478bd9Sstevel@tonic-gate  * by n bytes of data, where n is contained in the header.  The header
467c478bd9Sstevel@tonic-gate  * is represented as a htonl(u_long).  The high order bit encodes
477c478bd9Sstevel@tonic-gate  * whether or not the fragment is the last fragment of the record
487c478bd9Sstevel@tonic-gate  * (1 => fragment is last, 0 => more fragments to follow.
497c478bd9Sstevel@tonic-gate  * The other 31 bits encode the byte length of the fragment.
507c478bd9Sstevel@tonic-gate  */
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate #include <rpc/types.h>
537c478bd9Sstevel@tonic-gate #include <rpc/xdr.h>
547c478bd9Sstevel@tonic-gate #include <netinet/in.h>
557c478bd9Sstevel@tonic-gate #include <sys/promif.h>
567c478bd9Sstevel@tonic-gate #include <sys/salib.h>
577c478bd9Sstevel@tonic-gate #include <sys/bootdebug.h>
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate #define	dprintf if (boothowto & RB_DEBUG) printf
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate extern long	lseek();
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate static bool_t	xdrrec_getint32();
647c478bd9Sstevel@tonic-gate static bool_t	xdrrec_putint32();
657c478bd9Sstevel@tonic-gate static bool_t	xdrrec_getbytes();
667c478bd9Sstevel@tonic-gate static bool_t	xdrrec_putbytes();
677c478bd9Sstevel@tonic-gate static uint_t	xdrrec_getpos();
687c478bd9Sstevel@tonic-gate static bool_t	xdrrec_setpos();
697c478bd9Sstevel@tonic-gate static int32_t *xdrrec_inline();
707c478bd9Sstevel@tonic-gate static void	xdrrec_destroy();
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate static struct xdr_ops *xdrrec_ops();
737c478bd9Sstevel@tonic-gate static bool_t flush_out();
747c478bd9Sstevel@tonic-gate static bool_t fill_input_buf();
757c478bd9Sstevel@tonic-gate static bool_t get_input_bytes();
767c478bd9Sstevel@tonic-gate static bool_t set_input_fragment();
777c478bd9Sstevel@tonic-gate static bool_t skip_input_bytes();
787c478bd9Sstevel@tonic-gate static uint_t fix_buf_size();
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * A record is composed of one or more record fragments.
827c478bd9Sstevel@tonic-gate  * A record fragment is a four-byte header followed by zero to
837c478bd9Sstevel@tonic-gate  * 2**32-1 bytes.  The header is treated as a long unsigned and is
847c478bd9Sstevel@tonic-gate  * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
857c478bd9Sstevel@tonic-gate  * are a byte count of the fragment.  The highest order bit is a boolean:
867c478bd9Sstevel@tonic-gate  * 1 => this fragment is the last fragment of the record,
877c478bd9Sstevel@tonic-gate  * 0 => this fragment is followed by more fragment(s).
887c478bd9Sstevel@tonic-gate  *
897c478bd9Sstevel@tonic-gate  * The fragment/record machinery is not general;  it is constructed to
907c478bd9Sstevel@tonic-gate  * meet the needs of xdr and rpc based on tcp.
917c478bd9Sstevel@tonic-gate  */
927c478bd9Sstevel@tonic-gate #define	LAST_FRAG 0x80000000
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate typedef struct rec_strm {
957c478bd9Sstevel@tonic-gate 	caddr_t tcp_handle;
967c478bd9Sstevel@tonic-gate 	caddr_t the_buffer;
977c478bd9Sstevel@tonic-gate 	/*
987c478bd9Sstevel@tonic-gate 	 * out-goung bits
997c478bd9Sstevel@tonic-gate 	 */
1007c478bd9Sstevel@tonic-gate 	int (*writeit)();
1017c478bd9Sstevel@tonic-gate 	caddr_t out_base;	/* output buffer (points to frag header) */
1027c478bd9Sstevel@tonic-gate 	caddr_t out_finger;	/* next output position */
1037c478bd9Sstevel@tonic-gate 	caddr_t out_boundry;	/* data cannot up to this address */
1047c478bd9Sstevel@tonic-gate 	uint32_t *frag_header;	/* beginning of current fragment */
1057c478bd9Sstevel@tonic-gate 	bool_t frag_sent;	/* true if buffer sent in middle of record */
1067c478bd9Sstevel@tonic-gate 	/*
1077c478bd9Sstevel@tonic-gate 	 * in-coming bits
1087c478bd9Sstevel@tonic-gate 	 */
1097c478bd9Sstevel@tonic-gate 	int (*readit)();
1107c478bd9Sstevel@tonic-gate 	uint32_t in_size;	/* fixed size of the input buffer */
1117c478bd9Sstevel@tonic-gate 	caddr_t in_base;
1127c478bd9Sstevel@tonic-gate 	caddr_t in_finger;	/* location of next byte to be had */
1137c478bd9Sstevel@tonic-gate 	caddr_t in_boundry;	/* can read up to this location */
1147c478bd9Sstevel@tonic-gate 	int fbtbc;		/* fragment bytes to be consumed */
1157c478bd9Sstevel@tonic-gate 	bool_t last_frag;
1167c478bd9Sstevel@tonic-gate 	uint_t sendsize;
1177c478bd9Sstevel@tonic-gate 	uint_t recvsize;
1187c478bd9Sstevel@tonic-gate } RECSTREAM;
1197c478bd9Sstevel@tonic-gate 
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Create an xdr handle for xdrrec
1237c478bd9Sstevel@tonic-gate  * xdrrec_create fills in xdrs.  Sendsize and recvsize are
1247c478bd9Sstevel@tonic-gate  * send and recv buffer sizes (0 => use default).
1257c478bd9Sstevel@tonic-gate  * tcp_handle is an opaque handle that is passed as the first parameter to
1267c478bd9Sstevel@tonic-gate  * the procedures readit and writeit.  Readit and writeit are read and
1277c478bd9Sstevel@tonic-gate  * write respectively.   They are like the system
1287c478bd9Sstevel@tonic-gate  * calls expect that they take an opaque handle rather than an fd.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate void
1317c478bd9Sstevel@tonic-gate xdrrec_create(XDR *xdrs, uint_t sendsize, uint_t recvsize, caddr_t tcp_handle,
1327c478bd9Sstevel@tonic-gate 		int (*readit)(), int (*writeit)())
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)mem_alloc(sizeof (RECSTREAM));
1357c478bd9Sstevel@tonic-gate 	if (rstrm == NULL) {
1367c478bd9Sstevel@tonic-gate 		dprintf("xdrrec_create: out of memory\n");
1377c478bd9Sstevel@tonic-gate 		/*
1387c478bd9Sstevel@tonic-gate 		 *  This is bad.  Should rework xdrrec_create to
1397c478bd9Sstevel@tonic-gate 		 *  return a handle, and in this case return NULL
1407c478bd9Sstevel@tonic-gate 		 */
1417c478bd9Sstevel@tonic-gate 		return;
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	/*
1447c478bd9Sstevel@tonic-gate 	 * adjust sizes and allocate buffer quad byte aligned
1457c478bd9Sstevel@tonic-gate 	 */
1467c478bd9Sstevel@tonic-gate 	rstrm->sendsize = sendsize = fix_buf_size(sendsize);
1477c478bd9Sstevel@tonic-gate 	rstrm->recvsize = recvsize = fix_buf_size(recvsize);
1487c478bd9Sstevel@tonic-gate 	rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
1497c478bd9Sstevel@tonic-gate 	if (rstrm->the_buffer == NULL) {
1507c478bd9Sstevel@tonic-gate 		dprintf("xdrrec_create: out of memory\n");
1517c478bd9Sstevel@tonic-gate 		return;
1527c478bd9Sstevel@tonic-gate 	}
1537c478bd9Sstevel@tonic-gate 	for (rstrm->out_base = rstrm->the_buffer;
154*53391bafSeota 		(uintptr_t)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
1557c478bd9Sstevel@tonic-gate 		rstrm->out_base++);
1567c478bd9Sstevel@tonic-gate 	rstrm->in_base = rstrm->out_base + sendsize;
1577c478bd9Sstevel@tonic-gate 	/*
1587c478bd9Sstevel@tonic-gate 	 * now the rest ...
1597c478bd9Sstevel@tonic-gate 	 */
1607c478bd9Sstevel@tonic-gate 	xdrs->x_ops = xdrrec_ops();
1617c478bd9Sstevel@tonic-gate 	xdrs->x_private = (caddr_t)rstrm;
1627c478bd9Sstevel@tonic-gate 	rstrm->tcp_handle = tcp_handle;
1637c478bd9Sstevel@tonic-gate 	rstrm->readit = readit;
1647c478bd9Sstevel@tonic-gate 	rstrm->writeit = writeit;
1657c478bd9Sstevel@tonic-gate 	rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
1667c478bd9Sstevel@tonic-gate 	rstrm->frag_header = (uint32_t *)rstrm->out_base;
1677c478bd9Sstevel@tonic-gate 	rstrm->out_finger += sizeof (uint_t);
1687c478bd9Sstevel@tonic-gate 	rstrm->out_boundry += sendsize;
1697c478bd9Sstevel@tonic-gate 	rstrm->frag_sent = FALSE;
1707c478bd9Sstevel@tonic-gate 	rstrm->in_size = recvsize;
1717c478bd9Sstevel@tonic-gate 	rstrm->in_boundry = rstrm->in_base;
1727c478bd9Sstevel@tonic-gate 	rstrm->in_finger = (rstrm->in_boundry += recvsize);
1737c478bd9Sstevel@tonic-gate 	rstrm->fbtbc = 0;
1747c478bd9Sstevel@tonic-gate 	rstrm->last_frag = TRUE;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate }
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * The routines defined below are the xdr ops which will go into the
1817c478bd9Sstevel@tonic-gate  * xdr handle filled in by xdrrec_create.
1827c478bd9Sstevel@tonic-gate  */
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate static bool_t
1857c478bd9Sstevel@tonic-gate xdrrec_getint32(XDR *xdrs, int32_t *ip)
1867c478bd9Sstevel@tonic-gate {
1877c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
1887c478bd9Sstevel@tonic-gate 	int32_t *bufip = (int32_t *)(rstrm->in_finger);
1897c478bd9Sstevel@tonic-gate 	int32_t myint;
1907c478bd9Sstevel@tonic-gate 
1917c478bd9Sstevel@tonic-gate 	/* first try the inline, fast case */
1927c478bd9Sstevel@tonic-gate 	if ((rstrm->fbtbc >= sizeof (int32_t)) &&
193*53391bafSeota 		(((ptrdiff_t)rstrm->in_boundry
194*53391bafSeota 		    - (ptrdiff_t)bufip) >= sizeof (int32_t))) {
1957c478bd9Sstevel@tonic-gate 		*ip = (int32_t)ntohl((uint32_t)(*bufip));
1967c478bd9Sstevel@tonic-gate 		rstrm->fbtbc -= sizeof (int32_t);
1977c478bd9Sstevel@tonic-gate 		rstrm->in_finger += sizeof (int32_t);
1987c478bd9Sstevel@tonic-gate 	} else {
1997c478bd9Sstevel@tonic-gate 		if (!xdrrec_getbytes(xdrs, (caddr_t)&myint, sizeof (int32_t)))
2007c478bd9Sstevel@tonic-gate 			return (FALSE);
2017c478bd9Sstevel@tonic-gate 		*ip = (int32_t)ntohl((uint32_t)myint);
2027c478bd9Sstevel@tonic-gate 	}
2037c478bd9Sstevel@tonic-gate 	return (TRUE);
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate static bool_t
2077c478bd9Sstevel@tonic-gate xdrrec_putint32(XDR *xdrs, int32_t *ip)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
2107c478bd9Sstevel@tonic-gate 	int32_t *dest_ip = ((int32_t *)(rstrm->out_finger));
2117c478bd9Sstevel@tonic-gate 
2127c478bd9Sstevel@tonic-gate 	if ((rstrm->out_finger += sizeof (int32_t)) > rstrm->out_boundry) {
2137c478bd9Sstevel@tonic-gate 		/*
2147c478bd9Sstevel@tonic-gate 		 * this case should almost never happen so the code is
2157c478bd9Sstevel@tonic-gate 		 * inefficient
2167c478bd9Sstevel@tonic-gate 		 */
2177c478bd9Sstevel@tonic-gate 		rstrm->out_finger -= sizeof (int32_t);
2187c478bd9Sstevel@tonic-gate 		rstrm->frag_sent = TRUE;
2197c478bd9Sstevel@tonic-gate 		if (! flush_out(rstrm, FALSE))
2207c478bd9Sstevel@tonic-gate 			return (FALSE);
2217c478bd9Sstevel@tonic-gate 		dest_ip = ((int32_t *)(rstrm->out_finger));
2227c478bd9Sstevel@tonic-gate 		rstrm->out_finger += sizeof (int32_t);
2237c478bd9Sstevel@tonic-gate 	}
2247c478bd9Sstevel@tonic-gate 	*dest_ip = (int32_t)htonl((uint32_t)(*ip));
2257c478bd9Sstevel@tonic-gate 	return (TRUE);
2267c478bd9Sstevel@tonic-gate }
2277c478bd9Sstevel@tonic-gate 
2287c478bd9Sstevel@tonic-gate /*
2297c478bd9Sstevel@tonic-gate  * We need to be a little smarter here because we don't want to induce any
2307c478bd9Sstevel@tonic-gate  * pathological behavior in inetboot's networking stack.  The algorithm we
2317c478bd9Sstevel@tonic-gate  * pursue is to try to consume the entire fragment exactly instead of
2327c478bd9Sstevel@tonic-gate  * blindly requesting the max to fill the input buffer.
2337c478bd9Sstevel@tonic-gate  */
2347c478bd9Sstevel@tonic-gate static bool_t  /* must manage buffers, fragments, and records */
2357c478bd9Sstevel@tonic-gate xdrrec_getbytes(XDR *xdrs, caddr_t addr, int32_t len)
2367c478bd9Sstevel@tonic-gate {
2377c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
2387c478bd9Sstevel@tonic-gate 	int current;
2397c478bd9Sstevel@tonic-gate 	int frag_len;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	while (len > 0) {
2427c478bd9Sstevel@tonic-gate 		current =  frag_len = rstrm->fbtbc;
2437c478bd9Sstevel@tonic-gate 		if (current == 0) {
2447c478bd9Sstevel@tonic-gate 			if (rstrm->last_frag)
2457c478bd9Sstevel@tonic-gate 				return (FALSE);
2467c478bd9Sstevel@tonic-gate 			if (!set_input_fragment(rstrm))
2477c478bd9Sstevel@tonic-gate 				return (FALSE);
2487c478bd9Sstevel@tonic-gate 			continue;
2497c478bd9Sstevel@tonic-gate 		}
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 		current = (len < current) ? len : current;
2527c478bd9Sstevel@tonic-gate 		if (!get_input_bytes(rstrm, addr, frag_len, current))
2537c478bd9Sstevel@tonic-gate 			return (FALSE);
2547c478bd9Sstevel@tonic-gate 		addr += current;
2557c478bd9Sstevel@tonic-gate 		rstrm->fbtbc -= current;
2567c478bd9Sstevel@tonic-gate 		len -= current;
2577c478bd9Sstevel@tonic-gate 	}
2587c478bd9Sstevel@tonic-gate 	return (TRUE);
2597c478bd9Sstevel@tonic-gate }
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate static bool_t
2627c478bd9Sstevel@tonic-gate xdrrec_putbytes(XDR *xdrs, caddr_t addr, int32_t len)
2637c478bd9Sstevel@tonic-gate {
2647c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
265*53391bafSeota 	ptrdiff_t current;
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	while (len > 0) {
268*53391bafSeota 		current = rstrm->out_boundry - rstrm->out_finger;
2697c478bd9Sstevel@tonic-gate 		current = (len < current) ? len : current;
2707c478bd9Sstevel@tonic-gate 		bcopy(addr, rstrm->out_finger, current);
2717c478bd9Sstevel@tonic-gate 		rstrm->out_finger += current;
2727c478bd9Sstevel@tonic-gate 		addr += current;
2737c478bd9Sstevel@tonic-gate 		len -= current;
2747c478bd9Sstevel@tonic-gate 		if (rstrm->out_finger == rstrm->out_boundry) {
2757c478bd9Sstevel@tonic-gate 			rstrm->frag_sent = TRUE;
2767c478bd9Sstevel@tonic-gate 			if (! flush_out(rstrm, FALSE))
2777c478bd9Sstevel@tonic-gate 				return (FALSE);
2787c478bd9Sstevel@tonic-gate 		}
2797c478bd9Sstevel@tonic-gate 	}
2807c478bd9Sstevel@tonic-gate 	return (TRUE);
2817c478bd9Sstevel@tonic-gate }
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate static uint_t
2847c478bd9Sstevel@tonic-gate xdrrec_getpos(XDR *xdrs)
2857c478bd9Sstevel@tonic-gate {
2867c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
2877c478bd9Sstevel@tonic-gate 	int32_t pos;
2887c478bd9Sstevel@tonic-gate 
289*53391bafSeota 	pos = lseek((int)(intptr_t)rstrm->tcp_handle, 0, 1);
2907c478bd9Sstevel@tonic-gate 	if (pos != -1)
2917c478bd9Sstevel@tonic-gate 		switch (xdrs->x_op) {
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 		case XDR_ENCODE:
2947c478bd9Sstevel@tonic-gate 			pos += rstrm->out_finger - rstrm->out_base;
2957c478bd9Sstevel@tonic-gate 			break;
2967c478bd9Sstevel@tonic-gate 
2977c478bd9Sstevel@tonic-gate 		case XDR_DECODE:
2987c478bd9Sstevel@tonic-gate 			pos -= rstrm->in_boundry - rstrm->in_finger;
2997c478bd9Sstevel@tonic-gate 			break;
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate 		default:
3027c478bd9Sstevel@tonic-gate 			pos = (uint_t)-1;
3037c478bd9Sstevel@tonic-gate 			break;
3047c478bd9Sstevel@tonic-gate 		}
3057c478bd9Sstevel@tonic-gate 	return ((uint_t)pos);
3067c478bd9Sstevel@tonic-gate }
3077c478bd9Sstevel@tonic-gate 
3087c478bd9Sstevel@tonic-gate static bool_t
3097c478bd9Sstevel@tonic-gate xdrrec_setpos(XDR *xdrs, uint_t pos)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
3127c478bd9Sstevel@tonic-gate 	uint_t currpos = xdrrec_getpos(xdrs);
3137c478bd9Sstevel@tonic-gate 	int delta = currpos - pos;
3147c478bd9Sstevel@tonic-gate 	caddr_t newpos;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	if ((int)currpos != -1)
3177c478bd9Sstevel@tonic-gate 		switch (xdrs->x_op) {
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 		case XDR_ENCODE:
3207c478bd9Sstevel@tonic-gate 			newpos = rstrm->out_finger - delta;
3217c478bd9Sstevel@tonic-gate 			if ((newpos > (caddr_t)(rstrm->frag_header)) &&
3227c478bd9Sstevel@tonic-gate 				(newpos < rstrm->out_boundry)) {
3237c478bd9Sstevel@tonic-gate 				rstrm->out_finger = newpos;
3247c478bd9Sstevel@tonic-gate 				return (TRUE);
3257c478bd9Sstevel@tonic-gate 			}
3267c478bd9Sstevel@tonic-gate 			break;
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 		case XDR_DECODE:
3297c478bd9Sstevel@tonic-gate 			newpos = rstrm->in_finger - delta;
3307c478bd9Sstevel@tonic-gate 			if ((delta < (int)(rstrm->fbtbc)) &&
3317c478bd9Sstevel@tonic-gate 				(newpos <= rstrm->in_boundry) &&
3327c478bd9Sstevel@tonic-gate 				(newpos >= rstrm->in_base)) {
3337c478bd9Sstevel@tonic-gate 				rstrm->in_finger = newpos;
3347c478bd9Sstevel@tonic-gate 				rstrm->fbtbc -= delta;
3357c478bd9Sstevel@tonic-gate 				return (TRUE);
3367c478bd9Sstevel@tonic-gate 			}
3377c478bd9Sstevel@tonic-gate 			break;
3387c478bd9Sstevel@tonic-gate 		}
3397c478bd9Sstevel@tonic-gate 	return (FALSE);
3407c478bd9Sstevel@tonic-gate }
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate static int32_t *
3437c478bd9Sstevel@tonic-gate xdrrec_inline(XDR *xdrs, int len)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
3467c478bd9Sstevel@tonic-gate 	int32_t *buf = NULL;
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate 	switch (xdrs->x_op) {
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	case XDR_ENCODE:
3517c478bd9Sstevel@tonic-gate 		if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
3527c478bd9Sstevel@tonic-gate 			buf = (int32_t *)rstrm->out_finger;
3537c478bd9Sstevel@tonic-gate 			rstrm->out_finger += len;
3547c478bd9Sstevel@tonic-gate 		}
3557c478bd9Sstevel@tonic-gate 		break;
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	case XDR_DECODE:
3587c478bd9Sstevel@tonic-gate 		if ((len <= rstrm->fbtbc) &&
3597c478bd9Sstevel@tonic-gate 			((rstrm->in_finger + len) <= rstrm->in_boundry)) {
3607c478bd9Sstevel@tonic-gate 			buf = (int32_t *)rstrm->in_finger;
3617c478bd9Sstevel@tonic-gate 			rstrm->fbtbc -= len;
3627c478bd9Sstevel@tonic-gate 			rstrm->in_finger += len;
3637c478bd9Sstevel@tonic-gate 		}
3647c478bd9Sstevel@tonic-gate 		break;
3657c478bd9Sstevel@tonic-gate 	}
3667c478bd9Sstevel@tonic-gate 	return (buf);
3677c478bd9Sstevel@tonic-gate }
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate static void
3707c478bd9Sstevel@tonic-gate xdrrec_destroy(XDR *xdrs)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate 	mem_free(rstrm->the_buffer,
3757c478bd9Sstevel@tonic-gate 		rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
3767c478bd9Sstevel@tonic-gate 	mem_free((caddr_t)rstrm, sizeof (RECSTREAM));
3777c478bd9Sstevel@tonic-gate }
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate /*
3817c478bd9Sstevel@tonic-gate  * Exported routines to manage xdr records
3827c478bd9Sstevel@tonic-gate  */
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate /*
3857c478bd9Sstevel@tonic-gate  * Before reading (deserializing from the stream, one should always call
3867c478bd9Sstevel@tonic-gate  * this procedure to guarantee proper record alignment.
3877c478bd9Sstevel@tonic-gate  */
3887c478bd9Sstevel@tonic-gate bool_t
3897c478bd9Sstevel@tonic-gate xdrrec_skiprecord(XDR *xdrs)
3907c478bd9Sstevel@tonic-gate {
3917c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate 	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
3947c478bd9Sstevel@tonic-gate 		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
3957c478bd9Sstevel@tonic-gate 			return (FALSE);
3967c478bd9Sstevel@tonic-gate 		rstrm->fbtbc = 0;
3977c478bd9Sstevel@tonic-gate 		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
3987c478bd9Sstevel@tonic-gate 			return (FALSE);
3997c478bd9Sstevel@tonic-gate 	}
4007c478bd9Sstevel@tonic-gate 	rstrm->last_frag = FALSE;
4017c478bd9Sstevel@tonic-gate 	return (TRUE);
4027c478bd9Sstevel@tonic-gate }
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate #ifdef notneeded
4057c478bd9Sstevel@tonic-gate /*
4067c478bd9Sstevel@tonic-gate  * Look ahead fuction.
4077c478bd9Sstevel@tonic-gate  * Returns TRUE iff there is no more input in the buffer
4087c478bd9Sstevel@tonic-gate  * after consuming the rest of the current record.
4097c478bd9Sstevel@tonic-gate  */
4107c478bd9Sstevel@tonic-gate bool_t
4117c478bd9Sstevel@tonic-gate xdrrec_eof(XDR *xdrs)
4127c478bd9Sstevel@tonic-gate {
4137c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
4167c478bd9Sstevel@tonic-gate 		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
4177c478bd9Sstevel@tonic-gate 			return (TRUE);
4187c478bd9Sstevel@tonic-gate 		rstrm->fbtbc = 0;
4197c478bd9Sstevel@tonic-gate 		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
4207c478bd9Sstevel@tonic-gate 			return (TRUE);
4217c478bd9Sstevel@tonic-gate 	}
4227c478bd9Sstevel@tonic-gate 	if (rstrm->in_finger == rstrm->in_boundry)
4237c478bd9Sstevel@tonic-gate 		return (TRUE);
4247c478bd9Sstevel@tonic-gate 	return (FALSE);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate #endif /* notneeded */
4277c478bd9Sstevel@tonic-gate 
4287c478bd9Sstevel@tonic-gate /*
4297c478bd9Sstevel@tonic-gate  * The client must tell the package when an end-of-record has occurred.
4307c478bd9Sstevel@tonic-gate  * The second paraemters tells whether the record should be flushed to the
4317c478bd9Sstevel@tonic-gate  * (output) tcp stream.  (This let's the package support batched or
4327c478bd9Sstevel@tonic-gate  * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
4337c478bd9Sstevel@tonic-gate  */
4347c478bd9Sstevel@tonic-gate bool_t
4357c478bd9Sstevel@tonic-gate xdrrec_endofrecord(XDR *xdrs, bool_t sendnow)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
438*53391bafSeota 	ptrdiff_t len;  /* fragment length */
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	if (sendnow || rstrm->frag_sent ||
441*53391bafSeota 		((ptrdiff_t)rstrm->out_finger + sizeof (uint32_t)
442*53391bafSeota 		    >= (ptrdiff_t)rstrm->out_boundry)) {
4437c478bd9Sstevel@tonic-gate 		rstrm->frag_sent = FALSE;
4447c478bd9Sstevel@tonic-gate 		return (flush_out(rstrm, TRUE));
4457c478bd9Sstevel@tonic-gate 	}
446*53391bafSeota 	len = (ptrdiff_t)rstrm->out_finger - (ptrdiff_t)rstrm->frag_header;
447*53391bafSeota 	len -= sizeof (uint32_t);
4487c478bd9Sstevel@tonic-gate 	*(rstrm->frag_header) = htonl((uint32_t)len | LAST_FRAG);
4497c478bd9Sstevel@tonic-gate 	rstrm->frag_header = (uint32_t *)rstrm->out_finger;
4507c478bd9Sstevel@tonic-gate 	rstrm->out_finger += sizeof (uint32_t);
4517c478bd9Sstevel@tonic-gate 	return (TRUE);
4527c478bd9Sstevel@tonic-gate }
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate /*
4567c478bd9Sstevel@tonic-gate  * Internal useful routines
4577c478bd9Sstevel@tonic-gate  */
4587c478bd9Sstevel@tonic-gate static bool_t
4597c478bd9Sstevel@tonic-gate flush_out(RECSTREAM *rstrm, bool_t eor)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	uint32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
462*53391bafSeota 	ptrdiff_t len;
463*53391bafSeota 
464*53391bafSeota 	len = (ptrdiff_t)rstrm->out_finger - (ptrdiff_t)rstrm->frag_header;
465*53391bafSeota 	len -= sizeof (uint32_t);
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate 	*(rstrm->frag_header) = htonl(len | eormask);
468*53391bafSeota 	len = rstrm->out_finger - rstrm->out_base;
4697c478bd9Sstevel@tonic-gate 	if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
4707c478bd9Sstevel@tonic-gate 	    != (int)len)
4717c478bd9Sstevel@tonic-gate 		return (FALSE);
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate 	rstrm->frag_header = (uint32_t *)rstrm->out_base;
4747c478bd9Sstevel@tonic-gate 	rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof (uint32_t);
4757c478bd9Sstevel@tonic-gate 	return (TRUE);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate static bool_t  /* knows nothing about records!  Only about input buffers */
4797c478bd9Sstevel@tonic-gate fill_input_buf(RECSTREAM *rstrm, int frag_len)
4807c478bd9Sstevel@tonic-gate {
4817c478bd9Sstevel@tonic-gate 	caddr_t where;
482*53391bafSeota 	uintptr_t i;
4837c478bd9Sstevel@tonic-gate 	int len;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 	where = rstrm->in_base;
486*53391bafSeota 	i = (uintptr_t)rstrm->in_boundry % BYTES_PER_XDR_UNIT;
4877c478bd9Sstevel@tonic-gate 	where += i;
4887c478bd9Sstevel@tonic-gate 	len = (frag_len < (rstrm->in_size - i)) ? frag_len :
4897c478bd9Sstevel@tonic-gate 		rstrm->in_size - i;
4907c478bd9Sstevel@tonic-gate #ifdef DEBUG
4917c478bd9Sstevel@tonic-gate 	printf("fill_input_buf: len = %d\n", len);
4927c478bd9Sstevel@tonic-gate #endif
4937c478bd9Sstevel@tonic-gate 	if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
4947c478bd9Sstevel@tonic-gate 		return (FALSE);
4957c478bd9Sstevel@tonic-gate 	rstrm->in_finger = where;
4967c478bd9Sstevel@tonic-gate 	where += len;
4977c478bd9Sstevel@tonic-gate 	rstrm->in_boundry = where;
4987c478bd9Sstevel@tonic-gate 	return (TRUE);
4997c478bd9Sstevel@tonic-gate }
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate static bool_t
5027c478bd9Sstevel@tonic-gate get_input_bytes(RECSTREAM *rstrm, caddr_t addr, int frag_len, int len)
5037c478bd9Sstevel@tonic-gate {
504*53391bafSeota 	ptrdiff_t current;
5057c478bd9Sstevel@tonic-gate 
5067c478bd9Sstevel@tonic-gate 	while (len > 0) {
507*53391bafSeota 		current = rstrm->in_boundry - rstrm->in_finger;
5087c478bd9Sstevel@tonic-gate #ifdef DEBUG
5097c478bd9Sstevel@tonic-gate 	printf("get_input_bytes: len = %d, frag_len = %d, current %d\n",
5107c478bd9Sstevel@tonic-gate 		len, frag_len, current);
5117c478bd9Sstevel@tonic-gate #endif
5127c478bd9Sstevel@tonic-gate 		/*
5137c478bd9Sstevel@tonic-gate 		 * set_input_bytes doesn't know how large the fragment is, we
5147c478bd9Sstevel@tonic-gate 		 * need to get the header so just grab a header's size worth
5157c478bd9Sstevel@tonic-gate 		 */
5167c478bd9Sstevel@tonic-gate 		if (frag_len == 0)
5177c478bd9Sstevel@tonic-gate 			frag_len = len;
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 		if (current == 0) {
5207c478bd9Sstevel@tonic-gate 			if (! fill_input_buf(rstrm, frag_len))
5217c478bd9Sstevel@tonic-gate 				return (FALSE);
5227c478bd9Sstevel@tonic-gate 			continue;
5237c478bd9Sstevel@tonic-gate 		}
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 		current = (len < current) ? len : current;
5267c478bd9Sstevel@tonic-gate 		bcopy(rstrm->in_finger, addr, current);
5277c478bd9Sstevel@tonic-gate 		rstrm->in_finger += current;
5287c478bd9Sstevel@tonic-gate 		addr += current;
5297c478bd9Sstevel@tonic-gate 		len -= current;
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 	return (TRUE);
5327c478bd9Sstevel@tonic-gate }
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate static bool_t  /* next four bytes of the input stream are treated as a header */
5357c478bd9Sstevel@tonic-gate set_input_fragment(RECSTREAM *rstrm)
5367c478bd9Sstevel@tonic-gate {
5377c478bd9Sstevel@tonic-gate 	uint32_t header;
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 	if (! get_input_bytes(rstrm, (caddr_t)&header, 0, sizeof (header)))
5407c478bd9Sstevel@tonic-gate 		return (FALSE);
5417c478bd9Sstevel@tonic-gate 	header = (uint32_t)ntohl(header);
5427c478bd9Sstevel@tonic-gate 	rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
5437c478bd9Sstevel@tonic-gate 	rstrm->fbtbc = header & (~LAST_FRAG);
5447c478bd9Sstevel@tonic-gate #ifdef DEBUG
5457c478bd9Sstevel@tonic-gate 	printf("set_input_fragment: frag_len = %d, last frag = %s\n",
5467c478bd9Sstevel@tonic-gate 		rstrm->fbtbc, rstrm->last_frag ? "TRUE" : "FALSE");
5477c478bd9Sstevel@tonic-gate #endif
5487c478bd9Sstevel@tonic-gate 	return (TRUE);
5497c478bd9Sstevel@tonic-gate }
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate static bool_t  /* consumes input bytes; knows nothing about records! */
5527c478bd9Sstevel@tonic-gate skip_input_bytes(RECSTREAM *rstrm, int32_t cnt)
5537c478bd9Sstevel@tonic-gate {
554*53391bafSeota 	ptrdiff_t current;
5557c478bd9Sstevel@tonic-gate #ifdef DEBUG
5567c478bd9Sstevel@tonic-gate 	printf("skip_input_fragment: cnt = %d\n", cnt);
5577c478bd9Sstevel@tonic-gate #endif
5587c478bd9Sstevel@tonic-gate 	while (cnt > 0) {
559*53391bafSeota 		current = rstrm->in_boundry - rstrm->in_finger;
5607c478bd9Sstevel@tonic-gate 		if (current == 0) {
5617c478bd9Sstevel@tonic-gate 			if (! fill_input_buf(rstrm, cnt))
5627c478bd9Sstevel@tonic-gate 				return (FALSE);
5637c478bd9Sstevel@tonic-gate 			continue;
5647c478bd9Sstevel@tonic-gate 		}
5657c478bd9Sstevel@tonic-gate 		current = (cnt < current) ? cnt : current;
5667c478bd9Sstevel@tonic-gate 		rstrm->in_finger += current;
5677c478bd9Sstevel@tonic-gate 		cnt -= current;
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 	return (TRUE);
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate static uint_t
5737c478bd9Sstevel@tonic-gate fix_buf_size(uint_t s)
5747c478bd9Sstevel@tonic-gate {
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	if (s < 100)
5777c478bd9Sstevel@tonic-gate 		s = 4000;
5787c478bd9Sstevel@tonic-gate 	return (RNDUP(s));
5797c478bd9Sstevel@tonic-gate }
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate static struct xdr_ops *
5827c478bd9Sstevel@tonic-gate xdrrec_ops()
5837c478bd9Sstevel@tonic-gate {
5847c478bd9Sstevel@tonic-gate 	static struct xdr_ops ops;
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	if (ops.x_getint32 == NULL) {
5877c478bd9Sstevel@tonic-gate 		ops.x_getint32 = xdrrec_getint32;
5887c478bd9Sstevel@tonic-gate 		ops.x_putint32 = xdrrec_putint32;
5897c478bd9Sstevel@tonic-gate 		ops.x_getbytes = xdrrec_getbytes;
5907c478bd9Sstevel@tonic-gate 		ops.x_putbytes = xdrrec_putbytes;
5917c478bd9Sstevel@tonic-gate 		ops.x_getpostn = xdrrec_getpos;
5927c478bd9Sstevel@tonic-gate 		ops.x_setpostn = xdrrec_setpos;
5937c478bd9Sstevel@tonic-gate 		ops.x_inline = xdrrec_inline;
5947c478bd9Sstevel@tonic-gate 		ops.x_destroy = xdrrec_destroy;
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	return (&ops);
5987c478bd9Sstevel@tonic-gate }
599