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