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
xdrrec_create(XDR * xdrs,uint_t sendsize,uint_t recvsize,caddr_t tcp_handle,int (* readit)(),int (* writeit)())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
xdrrec_getint32(XDR * xdrs,int32_t * ip)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
xdrrec_putint32(XDR * xdrs,int32_t * ip)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 */
xdrrec_getbytes(XDR * xdrs,caddr_t addr,int32_t len)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
xdrrec_putbytes(XDR * xdrs,caddr_t addr,int32_t len)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
xdrrec_getpos(XDR * xdrs)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
xdrrec_setpos(XDR * xdrs,uint_t pos)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 *
xdrrec_inline(XDR * xdrs,int len)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
xdrrec_destroy(XDR * xdrs)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
xdrrec_skiprecord(XDR * xdrs)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
xdrrec_eof(XDR * xdrs)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
xdrrec_endofrecord(XDR * xdrs,bool_t sendnow)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
flush_out(RECSTREAM * rstrm,bool_t eor)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 */
fill_input_buf(RECSTREAM * rstrm,int frag_len)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
get_input_bytes(RECSTREAM * rstrm,caddr_t addr,int frag_len,int len)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 */
set_input_fragment(RECSTREAM * rstrm)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! */
skip_input_bytes(RECSTREAM * rstrm,int32_t cnt)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
fix_buf_size(uint_t s)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 *
xdrrec_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