xref: /onnv-gate/usr/src/stand/lib/fs/nfs/xdr_rec.c (revision 785:a0797646b335)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
23*785Seota  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
280Sstevel@tonic-gate /* All Rights Reserved */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate /*
310Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
320Sstevel@tonic-gate  * under license from the Regents of the University of California.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
360Sstevel@tonic-gate 
370Sstevel@tonic-gate /*
380Sstevel@tonic-gate  * xdr_rec.c, Implements TCP/IP based XDR streams with a "record marking"
390Sstevel@tonic-gate  * layer above tcp (for rpc's use).
400Sstevel@tonic-gate  *
410Sstevel@tonic-gate  * These routines interface XDRSTREAMS to a tcp/ip connection.
420Sstevel@tonic-gate  * There is a record marking layer between the xdr stream
430Sstevel@tonic-gate  * and the tcp transport level.  A record is composed on one or more
440Sstevel@tonic-gate  * record fragments.  A record fragment is a thirty-two bit header followed
450Sstevel@tonic-gate  * by n bytes of data, where n is contained in the header.  The header
460Sstevel@tonic-gate  * is represented as a htonl(u_long).  The high order bit encodes
470Sstevel@tonic-gate  * whether or not the fragment is the last fragment of the record
480Sstevel@tonic-gate  * (1 => fragment is last, 0 => more fragments to follow.
490Sstevel@tonic-gate  * The other 31 bits encode the byte length of the fragment.
500Sstevel@tonic-gate  */
510Sstevel@tonic-gate 
520Sstevel@tonic-gate #include <rpc/types.h>
530Sstevel@tonic-gate #include <rpc/xdr.h>
540Sstevel@tonic-gate #include <netinet/in.h>
550Sstevel@tonic-gate #include <sys/promif.h>
560Sstevel@tonic-gate #include <sys/salib.h>
570Sstevel@tonic-gate #include <sys/bootdebug.h>
580Sstevel@tonic-gate 
590Sstevel@tonic-gate #define	dprintf if (boothowto & RB_DEBUG) printf
600Sstevel@tonic-gate 
610Sstevel@tonic-gate extern long	lseek();
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static bool_t	xdrrec_getint32();
640Sstevel@tonic-gate static bool_t	xdrrec_putint32();
650Sstevel@tonic-gate static bool_t	xdrrec_getbytes();
660Sstevel@tonic-gate static bool_t	xdrrec_putbytes();
670Sstevel@tonic-gate static uint_t	xdrrec_getpos();
680Sstevel@tonic-gate static bool_t	xdrrec_setpos();
690Sstevel@tonic-gate static int32_t *xdrrec_inline();
700Sstevel@tonic-gate static void	xdrrec_destroy();
710Sstevel@tonic-gate 
720Sstevel@tonic-gate static struct xdr_ops *xdrrec_ops();
730Sstevel@tonic-gate static bool_t flush_out();
740Sstevel@tonic-gate static bool_t fill_input_buf();
750Sstevel@tonic-gate static bool_t get_input_bytes();
760Sstevel@tonic-gate static bool_t set_input_fragment();
770Sstevel@tonic-gate static bool_t skip_input_bytes();
780Sstevel@tonic-gate static uint_t fix_buf_size();
790Sstevel@tonic-gate 
800Sstevel@tonic-gate /*
810Sstevel@tonic-gate  * A record is composed of one or more record fragments.
820Sstevel@tonic-gate  * A record fragment is a four-byte header followed by zero to
830Sstevel@tonic-gate  * 2**32-1 bytes.  The header is treated as a long unsigned and is
840Sstevel@tonic-gate  * encode/decoded to the network via htonl/ntohl.  The low order 31 bits
850Sstevel@tonic-gate  * are a byte count of the fragment.  The highest order bit is a boolean:
860Sstevel@tonic-gate  * 1 => this fragment is the last fragment of the record,
870Sstevel@tonic-gate  * 0 => this fragment is followed by more fragment(s).
880Sstevel@tonic-gate  *
890Sstevel@tonic-gate  * The fragment/record machinery is not general;  it is constructed to
900Sstevel@tonic-gate  * meet the needs of xdr and rpc based on tcp.
910Sstevel@tonic-gate  */
920Sstevel@tonic-gate #define	LAST_FRAG 0x80000000
930Sstevel@tonic-gate 
940Sstevel@tonic-gate typedef struct rec_strm {
950Sstevel@tonic-gate 	caddr_t tcp_handle;
960Sstevel@tonic-gate 	caddr_t the_buffer;
970Sstevel@tonic-gate 	/*
980Sstevel@tonic-gate 	 * out-goung bits
990Sstevel@tonic-gate 	 */
1000Sstevel@tonic-gate 	int (*writeit)();
1010Sstevel@tonic-gate 	caddr_t out_base;	/* output buffer (points to frag header) */
1020Sstevel@tonic-gate 	caddr_t out_finger;	/* next output position */
1030Sstevel@tonic-gate 	caddr_t out_boundry;	/* data cannot up to this address */
1040Sstevel@tonic-gate 	uint32_t *frag_header;	/* beginning of current fragment */
1050Sstevel@tonic-gate 	bool_t frag_sent;	/* true if buffer sent in middle of record */
1060Sstevel@tonic-gate 	/*
1070Sstevel@tonic-gate 	 * in-coming bits
1080Sstevel@tonic-gate 	 */
1090Sstevel@tonic-gate 	int (*readit)();
1100Sstevel@tonic-gate 	uint32_t in_size;	/* fixed size of the input buffer */
1110Sstevel@tonic-gate 	caddr_t in_base;
1120Sstevel@tonic-gate 	caddr_t in_finger;	/* location of next byte to be had */
1130Sstevel@tonic-gate 	caddr_t in_boundry;	/* can read up to this location */
1140Sstevel@tonic-gate 	int fbtbc;		/* fragment bytes to be consumed */
1150Sstevel@tonic-gate 	bool_t last_frag;
1160Sstevel@tonic-gate 	uint_t sendsize;
1170Sstevel@tonic-gate 	uint_t recvsize;
1180Sstevel@tonic-gate } RECSTREAM;
1190Sstevel@tonic-gate 
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * Create an xdr handle for xdrrec
1230Sstevel@tonic-gate  * xdrrec_create fills in xdrs.  Sendsize and recvsize are
1240Sstevel@tonic-gate  * send and recv buffer sizes (0 => use default).
1250Sstevel@tonic-gate  * tcp_handle is an opaque handle that is passed as the first parameter to
1260Sstevel@tonic-gate  * the procedures readit and writeit.  Readit and writeit are read and
1270Sstevel@tonic-gate  * write respectively.   They are like the system
1280Sstevel@tonic-gate  * calls expect that they take an opaque handle rather than an fd.
1290Sstevel@tonic-gate  */
1300Sstevel@tonic-gate void
xdrrec_create(XDR * xdrs,uint_t sendsize,uint_t recvsize,caddr_t tcp_handle,int (* readit)(),int (* writeit)())1310Sstevel@tonic-gate xdrrec_create(XDR *xdrs, uint_t sendsize, uint_t recvsize, caddr_t tcp_handle,
1320Sstevel@tonic-gate 		int (*readit)(), int (*writeit)())
1330Sstevel@tonic-gate {
1340Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)mem_alloc(sizeof (RECSTREAM));
1350Sstevel@tonic-gate 	if (rstrm == NULL) {
1360Sstevel@tonic-gate 		dprintf("xdrrec_create: out of memory\n");
1370Sstevel@tonic-gate 		/*
1380Sstevel@tonic-gate 		 *  This is bad.  Should rework xdrrec_create to
1390Sstevel@tonic-gate 		 *  return a handle, and in this case return NULL
1400Sstevel@tonic-gate 		 */
1410Sstevel@tonic-gate 		return;
1420Sstevel@tonic-gate 	}
1430Sstevel@tonic-gate 	/*
1440Sstevel@tonic-gate 	 * adjust sizes and allocate buffer quad byte aligned
1450Sstevel@tonic-gate 	 */
1460Sstevel@tonic-gate 	rstrm->sendsize = sendsize = fix_buf_size(sendsize);
1470Sstevel@tonic-gate 	rstrm->recvsize = recvsize = fix_buf_size(recvsize);
1480Sstevel@tonic-gate 	rstrm->the_buffer = mem_alloc(sendsize + recvsize + BYTES_PER_XDR_UNIT);
1490Sstevel@tonic-gate 	if (rstrm->the_buffer == NULL) {
1500Sstevel@tonic-gate 		dprintf("xdrrec_create: out of memory\n");
1510Sstevel@tonic-gate 		return;
1520Sstevel@tonic-gate 	}
1530Sstevel@tonic-gate 	for (rstrm->out_base = rstrm->the_buffer;
154*785Seota 		(uintptr_t)rstrm->out_base % BYTES_PER_XDR_UNIT != 0;
1550Sstevel@tonic-gate 		rstrm->out_base++);
1560Sstevel@tonic-gate 	rstrm->in_base = rstrm->out_base + sendsize;
1570Sstevel@tonic-gate 	/*
1580Sstevel@tonic-gate 	 * now the rest ...
1590Sstevel@tonic-gate 	 */
1600Sstevel@tonic-gate 	xdrs->x_ops = xdrrec_ops();
1610Sstevel@tonic-gate 	xdrs->x_private = (caddr_t)rstrm;
1620Sstevel@tonic-gate 	rstrm->tcp_handle = tcp_handle;
1630Sstevel@tonic-gate 	rstrm->readit = readit;
1640Sstevel@tonic-gate 	rstrm->writeit = writeit;
1650Sstevel@tonic-gate 	rstrm->out_finger = rstrm->out_boundry = rstrm->out_base;
1660Sstevel@tonic-gate 	rstrm->frag_header = (uint32_t *)rstrm->out_base;
1670Sstevel@tonic-gate 	rstrm->out_finger += sizeof (uint_t);
1680Sstevel@tonic-gate 	rstrm->out_boundry += sendsize;
1690Sstevel@tonic-gate 	rstrm->frag_sent = FALSE;
1700Sstevel@tonic-gate 	rstrm->in_size = recvsize;
1710Sstevel@tonic-gate 	rstrm->in_boundry = rstrm->in_base;
1720Sstevel@tonic-gate 	rstrm->in_finger = (rstrm->in_boundry += recvsize);
1730Sstevel@tonic-gate 	rstrm->fbtbc = 0;
1740Sstevel@tonic-gate 	rstrm->last_frag = TRUE;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate }
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate /*
1800Sstevel@tonic-gate  * The routines defined below are the xdr ops which will go into the
1810Sstevel@tonic-gate  * xdr handle filled in by xdrrec_create.
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate 
1840Sstevel@tonic-gate static bool_t
xdrrec_getint32(XDR * xdrs,int32_t * ip)1850Sstevel@tonic-gate xdrrec_getint32(XDR *xdrs, int32_t *ip)
1860Sstevel@tonic-gate {
1870Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
1880Sstevel@tonic-gate 	int32_t *bufip = (int32_t *)(rstrm->in_finger);
1890Sstevel@tonic-gate 	int32_t myint;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/* first try the inline, fast case */
1920Sstevel@tonic-gate 	if ((rstrm->fbtbc >= sizeof (int32_t)) &&
193*785Seota 		(((ptrdiff_t)rstrm->in_boundry
194*785Seota 		    - (ptrdiff_t)bufip) >= sizeof (int32_t))) {
1950Sstevel@tonic-gate 		*ip = (int32_t)ntohl((uint32_t)(*bufip));
1960Sstevel@tonic-gate 		rstrm->fbtbc -= sizeof (int32_t);
1970Sstevel@tonic-gate 		rstrm->in_finger += sizeof (int32_t);
1980Sstevel@tonic-gate 	} else {
1990Sstevel@tonic-gate 		if (!xdrrec_getbytes(xdrs, (caddr_t)&myint, sizeof (int32_t)))
2000Sstevel@tonic-gate 			return (FALSE);
2010Sstevel@tonic-gate 		*ip = (int32_t)ntohl((uint32_t)myint);
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 	return (TRUE);
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate 
2060Sstevel@tonic-gate static bool_t
xdrrec_putint32(XDR * xdrs,int32_t * ip)2070Sstevel@tonic-gate xdrrec_putint32(XDR *xdrs, int32_t *ip)
2080Sstevel@tonic-gate {
2090Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
2100Sstevel@tonic-gate 	int32_t *dest_ip = ((int32_t *)(rstrm->out_finger));
2110Sstevel@tonic-gate 
2120Sstevel@tonic-gate 	if ((rstrm->out_finger += sizeof (int32_t)) > rstrm->out_boundry) {
2130Sstevel@tonic-gate 		/*
2140Sstevel@tonic-gate 		 * this case should almost never happen so the code is
2150Sstevel@tonic-gate 		 * inefficient
2160Sstevel@tonic-gate 		 */
2170Sstevel@tonic-gate 		rstrm->out_finger -= sizeof (int32_t);
2180Sstevel@tonic-gate 		rstrm->frag_sent = TRUE;
2190Sstevel@tonic-gate 		if (! flush_out(rstrm, FALSE))
2200Sstevel@tonic-gate 			return (FALSE);
2210Sstevel@tonic-gate 		dest_ip = ((int32_t *)(rstrm->out_finger));
2220Sstevel@tonic-gate 		rstrm->out_finger += sizeof (int32_t);
2230Sstevel@tonic-gate 	}
2240Sstevel@tonic-gate 	*dest_ip = (int32_t)htonl((uint32_t)(*ip));
2250Sstevel@tonic-gate 	return (TRUE);
2260Sstevel@tonic-gate }
2270Sstevel@tonic-gate 
2280Sstevel@tonic-gate /*
2290Sstevel@tonic-gate  * We need to be a little smarter here because we don't want to induce any
2300Sstevel@tonic-gate  * pathological behavior in inetboot's networking stack.  The algorithm we
2310Sstevel@tonic-gate  * pursue is to try to consume the entire fragment exactly instead of
2320Sstevel@tonic-gate  * blindly requesting the max to fill the input buffer.
2330Sstevel@tonic-gate  */
2340Sstevel@tonic-gate static bool_t  /* must manage buffers, fragments, and records */
xdrrec_getbytes(XDR * xdrs,caddr_t addr,int32_t len)2350Sstevel@tonic-gate xdrrec_getbytes(XDR *xdrs, caddr_t addr, int32_t len)
2360Sstevel@tonic-gate {
2370Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
2380Sstevel@tonic-gate 	int current;
2390Sstevel@tonic-gate 	int frag_len;
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	while (len > 0) {
2420Sstevel@tonic-gate 		current =  frag_len = rstrm->fbtbc;
2430Sstevel@tonic-gate 		if (current == 0) {
2440Sstevel@tonic-gate 			if (rstrm->last_frag)
2450Sstevel@tonic-gate 				return (FALSE);
2460Sstevel@tonic-gate 			if (!set_input_fragment(rstrm))
2470Sstevel@tonic-gate 				return (FALSE);
2480Sstevel@tonic-gate 			continue;
2490Sstevel@tonic-gate 		}
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 		current = (len < current) ? len : current;
2520Sstevel@tonic-gate 		if (!get_input_bytes(rstrm, addr, frag_len, current))
2530Sstevel@tonic-gate 			return (FALSE);
2540Sstevel@tonic-gate 		addr += current;
2550Sstevel@tonic-gate 		rstrm->fbtbc -= current;
2560Sstevel@tonic-gate 		len -= current;
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 	return (TRUE);
2590Sstevel@tonic-gate }
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate static bool_t
xdrrec_putbytes(XDR * xdrs,caddr_t addr,int32_t len)2620Sstevel@tonic-gate xdrrec_putbytes(XDR *xdrs, caddr_t addr, int32_t len)
2630Sstevel@tonic-gate {
2640Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
265*785Seota 	ptrdiff_t current;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	while (len > 0) {
268*785Seota 		current = rstrm->out_boundry - rstrm->out_finger;
2690Sstevel@tonic-gate 		current = (len < current) ? len : current;
2700Sstevel@tonic-gate 		bcopy(addr, rstrm->out_finger, current);
2710Sstevel@tonic-gate 		rstrm->out_finger += current;
2720Sstevel@tonic-gate 		addr += current;
2730Sstevel@tonic-gate 		len -= current;
2740Sstevel@tonic-gate 		if (rstrm->out_finger == rstrm->out_boundry) {
2750Sstevel@tonic-gate 			rstrm->frag_sent = TRUE;
2760Sstevel@tonic-gate 			if (! flush_out(rstrm, FALSE))
2770Sstevel@tonic-gate 				return (FALSE);
2780Sstevel@tonic-gate 		}
2790Sstevel@tonic-gate 	}
2800Sstevel@tonic-gate 	return (TRUE);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate static uint_t
xdrrec_getpos(XDR * xdrs)2840Sstevel@tonic-gate xdrrec_getpos(XDR *xdrs)
2850Sstevel@tonic-gate {
2860Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
2870Sstevel@tonic-gate 	int32_t pos;
2880Sstevel@tonic-gate 
289*785Seota 	pos = lseek((int)(intptr_t)rstrm->tcp_handle, 0, 1);
2900Sstevel@tonic-gate 	if (pos != -1)
2910Sstevel@tonic-gate 		switch (xdrs->x_op) {
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 		case XDR_ENCODE:
2940Sstevel@tonic-gate 			pos += rstrm->out_finger - rstrm->out_base;
2950Sstevel@tonic-gate 			break;
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 		case XDR_DECODE:
2980Sstevel@tonic-gate 			pos -= rstrm->in_boundry - rstrm->in_finger;
2990Sstevel@tonic-gate 			break;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 		default:
3020Sstevel@tonic-gate 			pos = (uint_t)-1;
3030Sstevel@tonic-gate 			break;
3040Sstevel@tonic-gate 		}
3050Sstevel@tonic-gate 	return ((uint_t)pos);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate static bool_t
xdrrec_setpos(XDR * xdrs,uint_t pos)3090Sstevel@tonic-gate xdrrec_setpos(XDR *xdrs, uint_t pos)
3100Sstevel@tonic-gate {
3110Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
3120Sstevel@tonic-gate 	uint_t currpos = xdrrec_getpos(xdrs);
3130Sstevel@tonic-gate 	int delta = currpos - pos;
3140Sstevel@tonic-gate 	caddr_t newpos;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	if ((int)currpos != -1)
3170Sstevel@tonic-gate 		switch (xdrs->x_op) {
3180Sstevel@tonic-gate 
3190Sstevel@tonic-gate 		case XDR_ENCODE:
3200Sstevel@tonic-gate 			newpos = rstrm->out_finger - delta;
3210Sstevel@tonic-gate 			if ((newpos > (caddr_t)(rstrm->frag_header)) &&
3220Sstevel@tonic-gate 				(newpos < rstrm->out_boundry)) {
3230Sstevel@tonic-gate 				rstrm->out_finger = newpos;
3240Sstevel@tonic-gate 				return (TRUE);
3250Sstevel@tonic-gate 			}
3260Sstevel@tonic-gate 			break;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 		case XDR_DECODE:
3290Sstevel@tonic-gate 			newpos = rstrm->in_finger - delta;
3300Sstevel@tonic-gate 			if ((delta < (int)(rstrm->fbtbc)) &&
3310Sstevel@tonic-gate 				(newpos <= rstrm->in_boundry) &&
3320Sstevel@tonic-gate 				(newpos >= rstrm->in_base)) {
3330Sstevel@tonic-gate 				rstrm->in_finger = newpos;
3340Sstevel@tonic-gate 				rstrm->fbtbc -= delta;
3350Sstevel@tonic-gate 				return (TRUE);
3360Sstevel@tonic-gate 			}
3370Sstevel@tonic-gate 			break;
3380Sstevel@tonic-gate 		}
3390Sstevel@tonic-gate 	return (FALSE);
3400Sstevel@tonic-gate }
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate static int32_t *
xdrrec_inline(XDR * xdrs,int len)3430Sstevel@tonic-gate xdrrec_inline(XDR *xdrs, int len)
3440Sstevel@tonic-gate {
3450Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
3460Sstevel@tonic-gate 	int32_t *buf = NULL;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	switch (xdrs->x_op) {
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 	case XDR_ENCODE:
3510Sstevel@tonic-gate 		if ((rstrm->out_finger + len) <= rstrm->out_boundry) {
3520Sstevel@tonic-gate 			buf = (int32_t *)rstrm->out_finger;
3530Sstevel@tonic-gate 			rstrm->out_finger += len;
3540Sstevel@tonic-gate 		}
3550Sstevel@tonic-gate 		break;
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	case XDR_DECODE:
3580Sstevel@tonic-gate 		if ((len <= rstrm->fbtbc) &&
3590Sstevel@tonic-gate 			((rstrm->in_finger + len) <= rstrm->in_boundry)) {
3600Sstevel@tonic-gate 			buf = (int32_t *)rstrm->in_finger;
3610Sstevel@tonic-gate 			rstrm->fbtbc -= len;
3620Sstevel@tonic-gate 			rstrm->in_finger += len;
3630Sstevel@tonic-gate 		}
3640Sstevel@tonic-gate 		break;
3650Sstevel@tonic-gate 	}
3660Sstevel@tonic-gate 	return (buf);
3670Sstevel@tonic-gate }
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate static void
xdrrec_destroy(XDR * xdrs)3700Sstevel@tonic-gate xdrrec_destroy(XDR *xdrs)
3710Sstevel@tonic-gate {
3720Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)xdrs->x_private;
3730Sstevel@tonic-gate 
3740Sstevel@tonic-gate 	mem_free(rstrm->the_buffer,
3750Sstevel@tonic-gate 		rstrm->sendsize + rstrm->recvsize + BYTES_PER_XDR_UNIT);
3760Sstevel@tonic-gate 	mem_free((caddr_t)rstrm, sizeof (RECSTREAM));
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate 
3800Sstevel@tonic-gate /*
3810Sstevel@tonic-gate  * Exported routines to manage xdr records
3820Sstevel@tonic-gate  */
3830Sstevel@tonic-gate 
3840Sstevel@tonic-gate /*
3850Sstevel@tonic-gate  * Before reading (deserializing from the stream, one should always call
3860Sstevel@tonic-gate  * this procedure to guarantee proper record alignment.
3870Sstevel@tonic-gate  */
3880Sstevel@tonic-gate bool_t
xdrrec_skiprecord(XDR * xdrs)3890Sstevel@tonic-gate xdrrec_skiprecord(XDR *xdrs)
3900Sstevel@tonic-gate {
3910Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate 	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
3940Sstevel@tonic-gate 		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
3950Sstevel@tonic-gate 			return (FALSE);
3960Sstevel@tonic-gate 		rstrm->fbtbc = 0;
3970Sstevel@tonic-gate 		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
3980Sstevel@tonic-gate 			return (FALSE);
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 	rstrm->last_frag = FALSE;
4010Sstevel@tonic-gate 	return (TRUE);
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate #ifdef notneeded
4050Sstevel@tonic-gate /*
4060Sstevel@tonic-gate  * Look ahead fuction.
4070Sstevel@tonic-gate  * Returns TRUE iff there is no more input in the buffer
4080Sstevel@tonic-gate  * after consuming the rest of the current record.
4090Sstevel@tonic-gate  */
4100Sstevel@tonic-gate bool_t
xdrrec_eof(XDR * xdrs)4110Sstevel@tonic-gate xdrrec_eof(XDR *xdrs)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
4140Sstevel@tonic-gate 
4150Sstevel@tonic-gate 	while (rstrm->fbtbc > 0 || (! rstrm->last_frag)) {
4160Sstevel@tonic-gate 		if (! skip_input_bytes(rstrm, rstrm->fbtbc))
4170Sstevel@tonic-gate 			return (TRUE);
4180Sstevel@tonic-gate 		rstrm->fbtbc = 0;
4190Sstevel@tonic-gate 		if ((! rstrm->last_frag) && (! set_input_fragment(rstrm)))
4200Sstevel@tonic-gate 			return (TRUE);
4210Sstevel@tonic-gate 	}
4220Sstevel@tonic-gate 	if (rstrm->in_finger == rstrm->in_boundry)
4230Sstevel@tonic-gate 		return (TRUE);
4240Sstevel@tonic-gate 	return (FALSE);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate #endif /* notneeded */
4270Sstevel@tonic-gate 
4280Sstevel@tonic-gate /*
4290Sstevel@tonic-gate  * The client must tell the package when an end-of-record has occurred.
4300Sstevel@tonic-gate  * The second paraemters tells whether the record should be flushed to the
4310Sstevel@tonic-gate  * (output) tcp stream.  (This let's the package support batched or
4320Sstevel@tonic-gate  * pipelined procedure calls.)  TRUE => immmediate flush to tcp connection.
4330Sstevel@tonic-gate  */
4340Sstevel@tonic-gate bool_t
xdrrec_endofrecord(XDR * xdrs,bool_t sendnow)4350Sstevel@tonic-gate xdrrec_endofrecord(XDR *xdrs, bool_t sendnow)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate 	RECSTREAM *rstrm = (RECSTREAM *)(xdrs->x_private);
438*785Seota 	ptrdiff_t len;  /* fragment length */
4390Sstevel@tonic-gate 
4400Sstevel@tonic-gate 	if (sendnow || rstrm->frag_sent ||
441*785Seota 		((ptrdiff_t)rstrm->out_finger + sizeof (uint32_t)
442*785Seota 		    >= (ptrdiff_t)rstrm->out_boundry)) {
4430Sstevel@tonic-gate 		rstrm->frag_sent = FALSE;
4440Sstevel@tonic-gate 		return (flush_out(rstrm, TRUE));
4450Sstevel@tonic-gate 	}
446*785Seota 	len = (ptrdiff_t)rstrm->out_finger - (ptrdiff_t)rstrm->frag_header;
447*785Seota 	len -= sizeof (uint32_t);
4480Sstevel@tonic-gate 	*(rstrm->frag_header) = htonl((uint32_t)len | LAST_FRAG);
4490Sstevel@tonic-gate 	rstrm->frag_header = (uint32_t *)rstrm->out_finger;
4500Sstevel@tonic-gate 	rstrm->out_finger += sizeof (uint32_t);
4510Sstevel@tonic-gate 	return (TRUE);
4520Sstevel@tonic-gate }
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 
4550Sstevel@tonic-gate /*
4560Sstevel@tonic-gate  * Internal useful routines
4570Sstevel@tonic-gate  */
4580Sstevel@tonic-gate static bool_t
flush_out(RECSTREAM * rstrm,bool_t eor)4590Sstevel@tonic-gate flush_out(RECSTREAM *rstrm, bool_t eor)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate 	uint32_t eormask = (eor == TRUE) ? LAST_FRAG : 0;
462*785Seota 	ptrdiff_t len;
463*785Seota 
464*785Seota 	len = (ptrdiff_t)rstrm->out_finger - (ptrdiff_t)rstrm->frag_header;
465*785Seota 	len -= sizeof (uint32_t);
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 	*(rstrm->frag_header) = htonl(len | eormask);
468*785Seota 	len = rstrm->out_finger - rstrm->out_base;
4690Sstevel@tonic-gate 	if ((*(rstrm->writeit))(rstrm->tcp_handle, rstrm->out_base, (int)len)
4700Sstevel@tonic-gate 	    != (int)len)
4710Sstevel@tonic-gate 		return (FALSE);
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	rstrm->frag_header = (uint32_t *)rstrm->out_base;
4740Sstevel@tonic-gate 	rstrm->out_finger = (caddr_t)rstrm->out_base + sizeof (uint32_t);
4750Sstevel@tonic-gate 	return (TRUE);
4760Sstevel@tonic-gate }
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate static bool_t  /* knows nothing about records!  Only about input buffers */
fill_input_buf(RECSTREAM * rstrm,int frag_len)4790Sstevel@tonic-gate fill_input_buf(RECSTREAM *rstrm, int frag_len)
4800Sstevel@tonic-gate {
4810Sstevel@tonic-gate 	caddr_t where;
482*785Seota 	uintptr_t i;
4830Sstevel@tonic-gate 	int len;
4840Sstevel@tonic-gate 
4850Sstevel@tonic-gate 	where = rstrm->in_base;
486*785Seota 	i = (uintptr_t)rstrm->in_boundry % BYTES_PER_XDR_UNIT;
4870Sstevel@tonic-gate 	where += i;
4880Sstevel@tonic-gate 	len = (frag_len < (rstrm->in_size - i)) ? frag_len :
4890Sstevel@tonic-gate 		rstrm->in_size - i;
4900Sstevel@tonic-gate #ifdef DEBUG
4910Sstevel@tonic-gate 	printf("fill_input_buf: len = %d\n", len);
4920Sstevel@tonic-gate #endif
4930Sstevel@tonic-gate 	if ((len = (*(rstrm->readit))(rstrm->tcp_handle, where, len)) == -1)
4940Sstevel@tonic-gate 		return (FALSE);
4950Sstevel@tonic-gate 	rstrm->in_finger = where;
4960Sstevel@tonic-gate 	where += len;
4970Sstevel@tonic-gate 	rstrm->in_boundry = where;
4980Sstevel@tonic-gate 	return (TRUE);
4990Sstevel@tonic-gate }
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate static bool_t
get_input_bytes(RECSTREAM * rstrm,caddr_t addr,int frag_len,int len)5020Sstevel@tonic-gate get_input_bytes(RECSTREAM *rstrm, caddr_t addr, int frag_len, int len)
5030Sstevel@tonic-gate {
504*785Seota 	ptrdiff_t current;
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	while (len > 0) {
507*785Seota 		current = rstrm->in_boundry - rstrm->in_finger;
5080Sstevel@tonic-gate #ifdef DEBUG
5090Sstevel@tonic-gate 	printf("get_input_bytes: len = %d, frag_len = %d, current %d\n",
5100Sstevel@tonic-gate 		len, frag_len, current);
5110Sstevel@tonic-gate #endif
5120Sstevel@tonic-gate 		/*
5130Sstevel@tonic-gate 		 * set_input_bytes doesn't know how large the fragment is, we
5140Sstevel@tonic-gate 		 * need to get the header so just grab a header's size worth
5150Sstevel@tonic-gate 		 */
5160Sstevel@tonic-gate 		if (frag_len == 0)
5170Sstevel@tonic-gate 			frag_len = len;
5180Sstevel@tonic-gate 
5190Sstevel@tonic-gate 		if (current == 0) {
5200Sstevel@tonic-gate 			if (! fill_input_buf(rstrm, frag_len))
5210Sstevel@tonic-gate 				return (FALSE);
5220Sstevel@tonic-gate 			continue;
5230Sstevel@tonic-gate 		}
5240Sstevel@tonic-gate 
5250Sstevel@tonic-gate 		current = (len < current) ? len : current;
5260Sstevel@tonic-gate 		bcopy(rstrm->in_finger, addr, current);
5270Sstevel@tonic-gate 		rstrm->in_finger += current;
5280Sstevel@tonic-gate 		addr += current;
5290Sstevel@tonic-gate 		len -= current;
5300Sstevel@tonic-gate 	}
5310Sstevel@tonic-gate 	return (TRUE);
5320Sstevel@tonic-gate }
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate static bool_t  /* next four bytes of the input stream are treated as a header */
set_input_fragment(RECSTREAM * rstrm)5350Sstevel@tonic-gate set_input_fragment(RECSTREAM *rstrm)
5360Sstevel@tonic-gate {
5370Sstevel@tonic-gate 	uint32_t header;
5380Sstevel@tonic-gate 
5390Sstevel@tonic-gate 	if (! get_input_bytes(rstrm, (caddr_t)&header, 0, sizeof (header)))
5400Sstevel@tonic-gate 		return (FALSE);
5410Sstevel@tonic-gate 	header = (uint32_t)ntohl(header);
5420Sstevel@tonic-gate 	rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
5430Sstevel@tonic-gate 	rstrm->fbtbc = header & (~LAST_FRAG);
5440Sstevel@tonic-gate #ifdef DEBUG
5450Sstevel@tonic-gate 	printf("set_input_fragment: frag_len = %d, last frag = %s\n",
5460Sstevel@tonic-gate 		rstrm->fbtbc, rstrm->last_frag ? "TRUE" : "FALSE");
5470Sstevel@tonic-gate #endif
5480Sstevel@tonic-gate 	return (TRUE);
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate static bool_t  /* consumes input bytes; knows nothing about records! */
skip_input_bytes(RECSTREAM * rstrm,int32_t cnt)5520Sstevel@tonic-gate skip_input_bytes(RECSTREAM *rstrm, int32_t cnt)
5530Sstevel@tonic-gate {
554*785Seota 	ptrdiff_t current;
5550Sstevel@tonic-gate #ifdef DEBUG
5560Sstevel@tonic-gate 	printf("skip_input_fragment: cnt = %d\n", cnt);
5570Sstevel@tonic-gate #endif
5580Sstevel@tonic-gate 	while (cnt > 0) {
559*785Seota 		current = rstrm->in_boundry - rstrm->in_finger;
5600Sstevel@tonic-gate 		if (current == 0) {
5610Sstevel@tonic-gate 			if (! fill_input_buf(rstrm, cnt))
5620Sstevel@tonic-gate 				return (FALSE);
5630Sstevel@tonic-gate 			continue;
5640Sstevel@tonic-gate 		}
5650Sstevel@tonic-gate 		current = (cnt < current) ? cnt : current;
5660Sstevel@tonic-gate 		rstrm->in_finger += current;
5670Sstevel@tonic-gate 		cnt -= current;
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate 	return (TRUE);
5700Sstevel@tonic-gate }
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate static uint_t
fix_buf_size(uint_t s)5730Sstevel@tonic-gate fix_buf_size(uint_t s)
5740Sstevel@tonic-gate {
5750Sstevel@tonic-gate 
5760Sstevel@tonic-gate 	if (s < 100)
5770Sstevel@tonic-gate 		s = 4000;
5780Sstevel@tonic-gate 	return (RNDUP(s));
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate static struct xdr_ops *
xdrrec_ops()5820Sstevel@tonic-gate xdrrec_ops()
5830Sstevel@tonic-gate {
5840Sstevel@tonic-gate 	static struct xdr_ops ops;
5850Sstevel@tonic-gate 
5860Sstevel@tonic-gate 	if (ops.x_getint32 == NULL) {
5870Sstevel@tonic-gate 		ops.x_getint32 = xdrrec_getint32;
5880Sstevel@tonic-gate 		ops.x_putint32 = xdrrec_putint32;
5890Sstevel@tonic-gate 		ops.x_getbytes = xdrrec_getbytes;
5900Sstevel@tonic-gate 		ops.x_putbytes = xdrrec_putbytes;
5910Sstevel@tonic-gate 		ops.x_getpostn = xdrrec_getpos;
5920Sstevel@tonic-gate 		ops.x_setpostn = xdrrec_setpos;
5930Sstevel@tonic-gate 		ops.x_inline = xdrrec_inline;
5940Sstevel@tonic-gate 		ops.x_destroy = xdrrec_destroy;
5950Sstevel@tonic-gate 	}
5960Sstevel@tonic-gate 
5970Sstevel@tonic-gate 	return (&ops);
5980Sstevel@tonic-gate }
599