xref: /onnv-gate/usr/src/uts/common/rpc/xdr_mblk.c (revision 7387:0b3a92e31fd8)
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
52627Smaheshvs  * Common Development and Distribution License (the "License").
62627Smaheshvs  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*7387SRobert.Gordon@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
270Sstevel@tonic-gate /*	  All Rights Reserved  	*/
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * Portions of this source code were derived from Berkeley 4.3 BSD
310Sstevel@tonic-gate  * under license from the Regents of the University of California.
320Sstevel@tonic-gate  */
330Sstevel@tonic-gate 
340Sstevel@tonic-gate /*
350Sstevel@tonic-gate  * xdr_mblk.c, XDR implementation on kernel streams mblks.
360Sstevel@tonic-gate  */
370Sstevel@tonic-gate 
380Sstevel@tonic-gate #include <sys/param.h>
390Sstevel@tonic-gate #include <sys/types.h>
400Sstevel@tonic-gate #include <sys/systm.h>
410Sstevel@tonic-gate #include <sys/stream.h>
420Sstevel@tonic-gate #include <sys/cmn_err.h>
430Sstevel@tonic-gate #include <sys/strsubr.h>
440Sstevel@tonic-gate #include <sys/strsun.h>
450Sstevel@tonic-gate #include <sys/debug.h>
460Sstevel@tonic-gate #include <sys/sysmacros.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate #include <rpc/types.h>
490Sstevel@tonic-gate #include <rpc/xdr.h>
500Sstevel@tonic-gate 
510Sstevel@tonic-gate static bool_t	xdrmblk_getint32(XDR *, int32_t *);
520Sstevel@tonic-gate static bool_t	xdrmblk_putint32(XDR *, int32_t *);
530Sstevel@tonic-gate static bool_t	xdrmblk_getbytes(XDR *, caddr_t, int);
540Sstevel@tonic-gate static bool_t	xdrmblk_putbytes(XDR *, caddr_t, int);
550Sstevel@tonic-gate static uint_t	xdrmblk_getpos(XDR *);
560Sstevel@tonic-gate static bool_t	xdrmblk_setpos(XDR *, uint_t);
570Sstevel@tonic-gate static rpc_inline_t *xdrmblk_inline(XDR *, int);
580Sstevel@tonic-gate static void	xdrmblk_destroy(XDR *);
590Sstevel@tonic-gate static bool_t	xdrmblk_control(XDR *, int, void *);
600Sstevel@tonic-gate 
610Sstevel@tonic-gate static mblk_t *xdrmblk_alloc(int);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate /*
640Sstevel@tonic-gate  * Xdr on mblks operations vector.
650Sstevel@tonic-gate  */
660Sstevel@tonic-gate struct	xdr_ops xdrmblk_ops = {
670Sstevel@tonic-gate 	xdrmblk_getbytes,
680Sstevel@tonic-gate 	xdrmblk_putbytes,
690Sstevel@tonic-gate 	xdrmblk_getpos,
700Sstevel@tonic-gate 	xdrmblk_setpos,
710Sstevel@tonic-gate 	xdrmblk_inline,
720Sstevel@tonic-gate 	xdrmblk_destroy,
730Sstevel@tonic-gate 	xdrmblk_control,
740Sstevel@tonic-gate 	xdrmblk_getint32,
750Sstevel@tonic-gate 	xdrmblk_putint32
760Sstevel@tonic-gate };
770Sstevel@tonic-gate 
780Sstevel@tonic-gate /*
790Sstevel@tonic-gate  * Initialize xdr stream.
800Sstevel@tonic-gate  */
810Sstevel@tonic-gate void
820Sstevel@tonic-gate xdrmblk_init(XDR *xdrs, mblk_t *m, enum xdr_op op, int sz)
830Sstevel@tonic-gate {
840Sstevel@tonic-gate 	xdrs->x_op = op;
850Sstevel@tonic-gate 	xdrs->x_ops = &xdrmblk_ops;
860Sstevel@tonic-gate 	xdrs->x_base = (caddr_t)m;
870Sstevel@tonic-gate 	xdrs->x_public = NULL;
880Sstevel@tonic-gate 	xdrs->x_private = (caddr_t)(uintptr_t)sz;
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	if (op == XDR_DECODE)
910Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
920Sstevel@tonic-gate 	else
930Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_datap->db_lim - m->b_datap->db_base);
940Sstevel@tonic-gate }
950Sstevel@tonic-gate 
960Sstevel@tonic-gate /* ARGSUSED */
970Sstevel@tonic-gate static void
980Sstevel@tonic-gate xdrmblk_destroy(XDR *xdrs)
990Sstevel@tonic-gate {
1000Sstevel@tonic-gate }
1010Sstevel@tonic-gate 
1020Sstevel@tonic-gate static bool_t
1030Sstevel@tonic-gate xdrmblk_getint32(XDR *xdrs, int32_t *int32p)
1040Sstevel@tonic-gate {
1050Sstevel@tonic-gate 	mblk_t *m;
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	/* LINTED pointer alignment */
1080Sstevel@tonic-gate 	m = (mblk_t *)xdrs->x_base;
1090Sstevel@tonic-gate 	if (m == NULL)
1100Sstevel@tonic-gate 		return (FALSE);
1110Sstevel@tonic-gate 	/*
1120Sstevel@tonic-gate 	 * If the pointer is not aligned or there is not
1130Sstevel@tonic-gate 	 * enough bytes, pullupmsg to get enough bytes and
1140Sstevel@tonic-gate 	 * align the mblk.
1150Sstevel@tonic-gate 	 */
1160Sstevel@tonic-gate 	if (!IS_P2ALIGNED(m->b_rptr, sizeof (int32_t)) ||
117*7387SRobert.Gordon@Sun.COM 	    xdrs->x_handy < sizeof (int32_t)) {
1180Sstevel@tonic-gate 		while (!pullupmsg(m, sizeof (int32_t))) {
1190Sstevel@tonic-gate 			/*
1200Sstevel@tonic-gate 			 * Could have failed due to not
1210Sstevel@tonic-gate 			 * enough data or an allocb failure.
1220Sstevel@tonic-gate 			 */
1230Sstevel@tonic-gate 			if (xmsgsize(m) < sizeof (int32_t))
1240Sstevel@tonic-gate 				return (FALSE);
1250Sstevel@tonic-gate 			delay(hz);
1260Sstevel@tonic-gate 		}
1270Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
1280Sstevel@tonic-gate 	}
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate 	/* LINTED pointer alignment */
1310Sstevel@tonic-gate 	*int32p = ntohl(*((int32_t *)(m->b_rptr)));
1320Sstevel@tonic-gate 	m->b_rptr += sizeof (int32_t);
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	/*
1350Sstevel@tonic-gate 	 * Instead of leaving handy as 0 causing more pullupmsg's
1360Sstevel@tonic-gate 	 * simply move to the next mblk.
1370Sstevel@tonic-gate 	 */
1380Sstevel@tonic-gate 	if ((xdrs->x_handy -= sizeof (int32_t)) == 0) {
1390Sstevel@tonic-gate 		m = m->b_cont;
1400Sstevel@tonic-gate 		xdrs->x_base = (caddr_t)m;
1410Sstevel@tonic-gate 		if (m != NULL)
1420Sstevel@tonic-gate 			xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 	return (TRUE);
1450Sstevel@tonic-gate }
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate static bool_t
1480Sstevel@tonic-gate xdrmblk_putint32(XDR *xdrs, int32_t *int32p)
1490Sstevel@tonic-gate {
1500Sstevel@tonic-gate 	mblk_t *m;
1510Sstevel@tonic-gate 
1520Sstevel@tonic-gate 	/* LINTED pointer alignment */
1530Sstevel@tonic-gate 	m = (mblk_t *)xdrs->x_base;
1540Sstevel@tonic-gate 	if (m == NULL)
1550Sstevel@tonic-gate 		return (FALSE);
1560Sstevel@tonic-gate 	if ((xdrs->x_handy -= (int)sizeof (int32_t)) < 0) {
1570Sstevel@tonic-gate 		if (m->b_cont == NULL) {
1580Sstevel@tonic-gate 			m->b_cont = xdrmblk_alloc((int)(uintptr_t)
1590Sstevel@tonic-gate 			    xdrs->x_private);
1600Sstevel@tonic-gate 		}
1610Sstevel@tonic-gate 		m = m->b_cont;
1620Sstevel@tonic-gate 		xdrs->x_base = (caddr_t)m;
1630Sstevel@tonic-gate 		if (m == NULL) {
1640Sstevel@tonic-gate 			xdrs->x_handy = 0;
1650Sstevel@tonic-gate 			return (FALSE);
1660Sstevel@tonic-gate 		}
1670Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_datap->db_lim - m->b_rptr -
168*7387SRobert.Gordon@Sun.COM 		    sizeof (int32_t));
1690Sstevel@tonic-gate 		ASSERT(m->b_rptr == m->b_wptr);
1700Sstevel@tonic-gate 		ASSERT(m->b_rptr >= m->b_datap->db_base);
1710Sstevel@tonic-gate 		ASSERT(m->b_rptr < m->b_datap->db_lim);
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 	/* LINTED pointer alignment */
1740Sstevel@tonic-gate 	*(int32_t *)m->b_wptr = htonl(*int32p);
1750Sstevel@tonic-gate 	m->b_wptr += sizeof (int32_t);
1760Sstevel@tonic-gate 	ASSERT(m->b_wptr <= m->b_datap->db_lim);
1770Sstevel@tonic-gate 	return (TRUE);
1780Sstevel@tonic-gate }
1790Sstevel@tonic-gate 
1800Sstevel@tonic-gate /*
1810Sstevel@tonic-gate  * We pick 16 as a compromise threshold for most architectures.
1820Sstevel@tonic-gate  */
1830Sstevel@tonic-gate #define	XDRMBLK_BCOPY_LIMIT	16
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate static bool_t
1860Sstevel@tonic-gate xdrmblk_getbytes(XDR *xdrs, caddr_t addr, int len)
1870Sstevel@tonic-gate {
1880Sstevel@tonic-gate 	mblk_t *m;
1890Sstevel@tonic-gate 	int i;
1900Sstevel@tonic-gate 
1910Sstevel@tonic-gate 	/* LINTED pointer alignment */
1920Sstevel@tonic-gate 	m = (mblk_t *)xdrs->x_base;
1930Sstevel@tonic-gate 	if (m == NULL)
1940Sstevel@tonic-gate 		return (FALSE);
1950Sstevel@tonic-gate 	/*
1960Sstevel@tonic-gate 	 * Performance tweak: converted explicit bcopy()
1970Sstevel@tonic-gate 	 * call to simple in-line. This function is called
1980Sstevel@tonic-gate 	 * to process things like readdir reply filenames
1990Sstevel@tonic-gate 	 * which are small strings--typically 12 bytes or less.
2000Sstevel@tonic-gate 	 * Overhead of calling bcopy() is obnoxious for such
2010Sstevel@tonic-gate 	 * small copies.
2020Sstevel@tonic-gate 	 */
2030Sstevel@tonic-gate 	while ((xdrs->x_handy -= len) < 0) {
2040Sstevel@tonic-gate 		if ((xdrs->x_handy += len) > 0) {
2050Sstevel@tonic-gate 			if (len < XDRMBLK_BCOPY_LIMIT) {
2060Sstevel@tonic-gate 				for (i = 0; i < xdrs->x_handy; i++)
2070Sstevel@tonic-gate 					*addr++ = *m->b_rptr++;
2080Sstevel@tonic-gate 			} else {
2090Sstevel@tonic-gate 				bcopy(m->b_rptr, addr, xdrs->x_handy);
2100Sstevel@tonic-gate 				m->b_rptr += xdrs->x_handy;
2110Sstevel@tonic-gate 				addr += xdrs->x_handy;
2120Sstevel@tonic-gate 			}
2130Sstevel@tonic-gate 			len -= xdrs->x_handy;
2140Sstevel@tonic-gate 		}
2150Sstevel@tonic-gate 		m = m->b_cont;
2160Sstevel@tonic-gate 		xdrs->x_base = (caddr_t)m;
2170Sstevel@tonic-gate 		if (m == NULL) {
2180Sstevel@tonic-gate 			xdrs->x_handy = 0;
2190Sstevel@tonic-gate 			return (FALSE);
2200Sstevel@tonic-gate 		}
2210Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
2220Sstevel@tonic-gate 	}
2230Sstevel@tonic-gate 	if (len < XDRMBLK_BCOPY_LIMIT) {
2240Sstevel@tonic-gate 		for (i = 0; i < len; i++)
2250Sstevel@tonic-gate 			*addr++ = *m->b_rptr++;
2260Sstevel@tonic-gate 	} else {
2270Sstevel@tonic-gate 		bcopy(m->b_rptr, addr, len);
2280Sstevel@tonic-gate 		m->b_rptr += len;
2290Sstevel@tonic-gate 	}
2300Sstevel@tonic-gate 	return (TRUE);
2310Sstevel@tonic-gate }
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate /*
2340Sstevel@tonic-gate  * Sort of like getbytes except that instead of getting bytes we return the
2350Sstevel@tonic-gate  * mblk chain which contains the data.  If the data ends in the middle of
2360Sstevel@tonic-gate  * an mblk, the mblk is dup'd and split, so that the data will end on an
2370Sstevel@tonic-gate  * mblk.  Note that it is up to the caller to keep track of the data length
2380Sstevel@tonic-gate  * and not walk too far down the mblk chain.
2390Sstevel@tonic-gate  */
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate bool_t
2420Sstevel@tonic-gate xdrmblk_getmblk(XDR *xdrs, mblk_t **mm, uint_t *lenp)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	mblk_t *m, *nextm;
2450Sstevel@tonic-gate 	int len;
2460Sstevel@tonic-gate 	int32_t llen;
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate 	if (!xdrmblk_getint32(xdrs, &llen))
2490Sstevel@tonic-gate 		return (FALSE);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate 	*lenp = llen;
2520Sstevel@tonic-gate 	/* LINTED pointer alignment */
2530Sstevel@tonic-gate 	m = (mblk_t *)xdrs->x_base;
2540Sstevel@tonic-gate 	*mm = m;
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate 	/*
2570Sstevel@tonic-gate 	 * Walk the mblk chain until we get to the end or we've gathered
2580Sstevel@tonic-gate 	 * enough data.
2590Sstevel@tonic-gate 	 */
2600Sstevel@tonic-gate 	len = 0;
2610Sstevel@tonic-gate 	llen = roundup(llen, BYTES_PER_XDR_UNIT);
2620Sstevel@tonic-gate 	while (m != NULL && len + (int)MBLKL(m) <= llen) {
2630Sstevel@tonic-gate 		len += (int)MBLKL(m);
2640Sstevel@tonic-gate 		m = m->b_cont;
2650Sstevel@tonic-gate 	}
2660Sstevel@tonic-gate 	if (len < llen) {
2670Sstevel@tonic-gate 		if (m == NULL) {
2680Sstevel@tonic-gate 			return (FALSE);
2690Sstevel@tonic-gate 		} else {
2700Sstevel@tonic-gate 			int tail_bytes = llen - len;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 			/*
2730Sstevel@tonic-gate 			 * Split the mblk with the last chunk of data and
2740Sstevel@tonic-gate 			 * insert it into the chain.  The new mblk goes
2750Sstevel@tonic-gate 			 * after the existing one so that it will get freed
2760Sstevel@tonic-gate 			 * properly.
2770Sstevel@tonic-gate 			 */
2780Sstevel@tonic-gate 			nextm = dupb(m);
2790Sstevel@tonic-gate 			if (nextm == NULL)
2800Sstevel@tonic-gate 				return (FALSE);
2810Sstevel@tonic-gate 			nextm->b_cont = m->b_cont;
2820Sstevel@tonic-gate 			m->b_cont = nextm;
2830Sstevel@tonic-gate 			m->b_wptr = m->b_rptr + tail_bytes;
2840Sstevel@tonic-gate 			nextm->b_rptr += tail_bytes;
2850Sstevel@tonic-gate 			ASSERT(nextm->b_rptr != nextm->b_wptr);
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 			m = nextm;	/* for x_base */
2880Sstevel@tonic-gate 		}
2890Sstevel@tonic-gate 	}
2900Sstevel@tonic-gate 	xdrs->x_base = (caddr_t)m;
2910Sstevel@tonic-gate 	xdrs->x_handy = m != NULL ? MBLKL(m) : 0;
2920Sstevel@tonic-gate 	return (TRUE);
2930Sstevel@tonic-gate }
2940Sstevel@tonic-gate 
2950Sstevel@tonic-gate static bool_t
2960Sstevel@tonic-gate xdrmblk_putbytes(XDR *xdrs, caddr_t addr, int len)
2970Sstevel@tonic-gate {
2980Sstevel@tonic-gate 	mblk_t *m;
2990Sstevel@tonic-gate 	uint_t i;
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate 	/* LINTED pointer alignment */
3020Sstevel@tonic-gate 	m = (mblk_t *)xdrs->x_base;
3030Sstevel@tonic-gate 	if (m == NULL)
3040Sstevel@tonic-gate 		return (FALSE);
3050Sstevel@tonic-gate 	/*
3060Sstevel@tonic-gate 	 * Performance tweak: converted explicit bcopy()
3070Sstevel@tonic-gate 	 * call to simple in-line. This function is called
3080Sstevel@tonic-gate 	 * to process things like readdir reply filenames
3090Sstevel@tonic-gate 	 * which are small strings--typically 12 bytes or less.
3100Sstevel@tonic-gate 	 * Overhead of calling bcopy() is obnoxious for such
3110Sstevel@tonic-gate 	 * small copies.
3120Sstevel@tonic-gate 	 */
3130Sstevel@tonic-gate 	while ((xdrs->x_handy -= len) < 0) {
3140Sstevel@tonic-gate 		if ((xdrs->x_handy += len) > 0) {
3150Sstevel@tonic-gate 			if (xdrs->x_handy < XDRMBLK_BCOPY_LIMIT) {
3160Sstevel@tonic-gate 				for (i = 0; i < (uint_t)xdrs->x_handy; i++)
3170Sstevel@tonic-gate 					*m->b_wptr++ = *addr++;
3180Sstevel@tonic-gate 			} else {
3190Sstevel@tonic-gate 				bcopy(addr, m->b_wptr, xdrs->x_handy);
3200Sstevel@tonic-gate 				m->b_wptr += xdrs->x_handy;
3210Sstevel@tonic-gate 				addr += xdrs->x_handy;
3220Sstevel@tonic-gate 			}
3230Sstevel@tonic-gate 			len -= xdrs->x_handy;
3240Sstevel@tonic-gate 		}
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 		/*
3270Sstevel@tonic-gate 		 * We don't have enough space, so allocate the
3280Sstevel@tonic-gate 		 * amount we need, or x_private, whichever is larger.
3290Sstevel@tonic-gate 		 * It is better to let the underlying transport divide
3300Sstevel@tonic-gate 		 * large chunks than to try and guess what is best.
3310Sstevel@tonic-gate 		 */
3320Sstevel@tonic-gate 		if (m->b_cont == NULL)
3330Sstevel@tonic-gate 			m->b_cont = xdrmblk_alloc(MAX(len,
3340Sstevel@tonic-gate 			    (int)(uintptr_t)xdrs->x_private));
3350Sstevel@tonic-gate 
3360Sstevel@tonic-gate 		m = m->b_cont;
3370Sstevel@tonic-gate 		xdrs->x_base = (caddr_t)m;
3380Sstevel@tonic-gate 		if (m == NULL) {
3390Sstevel@tonic-gate 			xdrs->x_handy = 0;
3400Sstevel@tonic-gate 			return (FALSE);
3410Sstevel@tonic-gate 		}
3420Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_datap->db_lim - m->b_rptr);
3430Sstevel@tonic-gate 		ASSERT(m->b_rptr == m->b_wptr);
3440Sstevel@tonic-gate 		ASSERT(m->b_rptr >= m->b_datap->db_base);
3450Sstevel@tonic-gate 		ASSERT(m->b_rptr < m->b_datap->db_lim);
3460Sstevel@tonic-gate 	}
3470Sstevel@tonic-gate 	if (len < XDRMBLK_BCOPY_LIMIT) {
3480Sstevel@tonic-gate 		for (i = 0; i < len; i++)
3490Sstevel@tonic-gate 			*m->b_wptr++ = *addr++;
3500Sstevel@tonic-gate 	} else {
3510Sstevel@tonic-gate 		bcopy(addr, m->b_wptr, len);
3520Sstevel@tonic-gate 		m->b_wptr += len;
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 	ASSERT(m->b_wptr <= m->b_datap->db_lim);
3550Sstevel@tonic-gate 	return (TRUE);
3560Sstevel@tonic-gate }
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate /*
3590Sstevel@tonic-gate  * We avoid a copy by merely adding this mblk to the list.  The caller is
3600Sstevel@tonic-gate  * responsible for allocating and filling in the mblk. If len is
3610Sstevel@tonic-gate  * not a multiple of BYTES_PER_XDR_UNIT, the caller has the option
3620Sstevel@tonic-gate  * of making the data a BYTES_PER_XDR_UNIT multiple (b_wptr - b_rptr is
3630Sstevel@tonic-gate  * a BYTES_PER_XDR_UNIT multiple), but in this case the caller has to ensure
3640Sstevel@tonic-gate  * that the filler bytes are initialized to zero. Note: Doesn't to work for
3650Sstevel@tonic-gate  * chained mblks.
3660Sstevel@tonic-gate  */
3670Sstevel@tonic-gate bool_t
3680Sstevel@tonic-gate xdrmblk_putmblk(XDR *xdrs, mblk_t *m, uint_t len)
3690Sstevel@tonic-gate {
3700Sstevel@tonic-gate 	int32_t llen = (int32_t)len;
3710Sstevel@tonic-gate 
3720Sstevel@tonic-gate 	if (((m->b_wptr - m->b_rptr) % BYTES_PER_XDR_UNIT) != 0)
3730Sstevel@tonic-gate 		return (FALSE);
3740Sstevel@tonic-gate 	if (!xdrmblk_putint32(xdrs, &llen))
3750Sstevel@tonic-gate 		return (FALSE);
3760Sstevel@tonic-gate 	/* LINTED pointer alignment */
3770Sstevel@tonic-gate 	((mblk_t *)xdrs->x_base)->b_cont = m;
3780Sstevel@tonic-gate 	xdrs->x_base = (caddr_t)m;
3790Sstevel@tonic-gate 	xdrs->x_handy = 0;
3800Sstevel@tonic-gate 	return (TRUE);
3810Sstevel@tonic-gate }
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate static uint_t
3840Sstevel@tonic-gate xdrmblk_getpos(XDR *xdrs)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate 	uint_t tmp;
3870Sstevel@tonic-gate 	mblk_t *m;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/* LINTED pointer alignment */
3900Sstevel@tonic-gate 	m = (mblk_t *)xdrs->x_base;
3910Sstevel@tonic-gate 
3920Sstevel@tonic-gate 	if (xdrs->x_op == XDR_DECODE)
3930Sstevel@tonic-gate 		tmp = (uint_t)(m->b_rptr - m->b_datap->db_base);
3940Sstevel@tonic-gate 	else
3950Sstevel@tonic-gate 		tmp = (uint_t)(m->b_wptr - m->b_datap->db_base);
3960Sstevel@tonic-gate 	return (tmp);
3970Sstevel@tonic-gate 
3980Sstevel@tonic-gate }
3990Sstevel@tonic-gate 
4000Sstevel@tonic-gate static bool_t
4010Sstevel@tonic-gate xdrmblk_setpos(XDR *xdrs, uint_t pos)
4020Sstevel@tonic-gate {
4030Sstevel@tonic-gate 	mblk_t *m;
4040Sstevel@tonic-gate 	unsigned char *newaddr;
4050Sstevel@tonic-gate 
4060Sstevel@tonic-gate 	/* LINTED pointer alignment */
4070Sstevel@tonic-gate 	m = (mblk_t *)xdrs->x_base;
4080Sstevel@tonic-gate 	if (m == NULL)
4090Sstevel@tonic-gate 		return (FALSE);
4100Sstevel@tonic-gate 
4110Sstevel@tonic-gate 	/* calculate the new address from the base */
4120Sstevel@tonic-gate 	newaddr = m->b_datap->db_base + pos;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	if (xdrs->x_op == XDR_DECODE) {
4150Sstevel@tonic-gate 		if (newaddr > m->b_wptr)
4160Sstevel@tonic-gate 			return (FALSE);
4170Sstevel@tonic-gate 		m->b_rptr = newaddr;
4180Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_wptr - newaddr);
4190Sstevel@tonic-gate 	} else {
4200Sstevel@tonic-gate 		if (newaddr > m->b_datap->db_lim)
4210Sstevel@tonic-gate 			return (FALSE);
4220Sstevel@tonic-gate 		m->b_wptr = newaddr;
4230Sstevel@tonic-gate 		xdrs->x_handy = (int)(m->b_datap->db_lim - newaddr);
4240Sstevel@tonic-gate 	}
4250Sstevel@tonic-gate 
4260Sstevel@tonic-gate 	return (TRUE);
4270Sstevel@tonic-gate }
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate #ifdef DEBUG
4300Sstevel@tonic-gate static int xdrmblk_inline_hits = 0;
4310Sstevel@tonic-gate static int xdrmblk_inline_misses = 0;
4320Sstevel@tonic-gate static int do_xdrmblk_inline = 1;
4330Sstevel@tonic-gate #endif
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate static rpc_inline_t *
4360Sstevel@tonic-gate xdrmblk_inline(XDR *xdrs, int len)
4370Sstevel@tonic-gate {
4380Sstevel@tonic-gate 	rpc_inline_t *buf;
4390Sstevel@tonic-gate 	mblk_t *m;
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	/*
4420Sstevel@tonic-gate 	 * Can't inline XDR_FREE calls, doesn't make sense.
4430Sstevel@tonic-gate 	 */
4440Sstevel@tonic-gate 	if (xdrs->x_op == XDR_FREE)
4450Sstevel@tonic-gate 		return (NULL);
4460Sstevel@tonic-gate 
4470Sstevel@tonic-gate 	/*
4480Sstevel@tonic-gate 	 * Can't inline if there isn't enough room, don't have an
4490Sstevel@tonic-gate 	 * mblk pointer, its not 4 byte aligned, or if there is more than
4500Sstevel@tonic-gate 	 * one reference to the data block associated with this mblk.  This last
4510Sstevel@tonic-gate 	 * check is used because the caller may want to modified
4520Sstevel@tonic-gate 	 * the data in the inlined portion and someone else is
4530Sstevel@tonic-gate 	 * holding a reference to the data who may not want it
4540Sstevel@tonic-gate 	 * to be modified.
4550Sstevel@tonic-gate 	 */
4560Sstevel@tonic-gate 	if (xdrs->x_handy < len ||
4570Sstevel@tonic-gate 	    /* LINTED pointer alignment */
4580Sstevel@tonic-gate 	    (m = (mblk_t *)xdrs->x_base) == NULL ||
4590Sstevel@tonic-gate 	    !IS_P2ALIGNED(m->b_rptr, sizeof (int32_t)) ||
4600Sstevel@tonic-gate 	    m->b_datap->db_ref != 1) {
4610Sstevel@tonic-gate #ifdef DEBUG
4620Sstevel@tonic-gate 		xdrmblk_inline_misses++;
4630Sstevel@tonic-gate #endif
4640Sstevel@tonic-gate 		return (NULL);
4650Sstevel@tonic-gate 	}
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate #ifdef DEBUG
4680Sstevel@tonic-gate 	if (!do_xdrmblk_inline) {
4690Sstevel@tonic-gate 		xdrmblk_inline_misses++;
4700Sstevel@tonic-gate 		return (NULL);
4710Sstevel@tonic-gate 	}
4720Sstevel@tonic-gate #endif
4730Sstevel@tonic-gate 
4740Sstevel@tonic-gate 	xdrs->x_handy -= len;
4750Sstevel@tonic-gate 	if (xdrs->x_op == XDR_DECODE) {
4760Sstevel@tonic-gate 		/* LINTED pointer alignment */
4770Sstevel@tonic-gate 		buf = (rpc_inline_t *)m->b_rptr;
4780Sstevel@tonic-gate 		m->b_rptr += len;
4790Sstevel@tonic-gate 	} else {
4800Sstevel@tonic-gate 		/* LINTED pointer alignment */
4810Sstevel@tonic-gate 		buf = (rpc_inline_t *)m->b_wptr;
4820Sstevel@tonic-gate 		m->b_wptr += len;
4830Sstevel@tonic-gate 	}
4840Sstevel@tonic-gate #ifdef DEBUG
4850Sstevel@tonic-gate 	xdrmblk_inline_hits++;
4860Sstevel@tonic-gate #endif
4870Sstevel@tonic-gate 	return (buf);
4880Sstevel@tonic-gate }
4890Sstevel@tonic-gate 
4900Sstevel@tonic-gate static bool_t
4910Sstevel@tonic-gate xdrmblk_control(XDR *xdrs, int request, void *info)
4920Sstevel@tonic-gate {
4930Sstevel@tonic-gate 	mblk_t *m;
4940Sstevel@tonic-gate 	int32_t *int32p;
4950Sstevel@tonic-gate 	int len;
4960Sstevel@tonic-gate 
4970Sstevel@tonic-gate 	switch (request) {
4980Sstevel@tonic-gate 	case XDR_PEEK:
4990Sstevel@tonic-gate 		/*
5000Sstevel@tonic-gate 		 * Return the next 4 byte unit in the XDR stream.
5010Sstevel@tonic-gate 		 */
5020Sstevel@tonic-gate 		if (xdrs->x_handy < sizeof (int32_t))
5030Sstevel@tonic-gate 			return (FALSE);
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 		/* LINTED pointer alignment */
5060Sstevel@tonic-gate 		m = (mblk_t *)xdrs->x_base;
5070Sstevel@tonic-gate 		if (m == NULL)
5080Sstevel@tonic-gate 			return (FALSE);
5090Sstevel@tonic-gate 
5100Sstevel@tonic-gate 		/*
5110Sstevel@tonic-gate 		 * If the pointer is not aligned, fail the peek
5120Sstevel@tonic-gate 		 */
5130Sstevel@tonic-gate 		if (!IS_P2ALIGNED(m->b_rptr, sizeof (int32_t)))
5140Sstevel@tonic-gate 			return (FALSE);
5150Sstevel@tonic-gate 
5160Sstevel@tonic-gate 		int32p = (int32_t *)info;
5170Sstevel@tonic-gate 		/* LINTED pointer alignment */
5180Sstevel@tonic-gate 		*int32p = ntohl(*((int32_t *)(m->b_rptr)));
5190Sstevel@tonic-gate 		return (TRUE);
5200Sstevel@tonic-gate 
5210Sstevel@tonic-gate 	case XDR_SKIPBYTES:
5220Sstevel@tonic-gate 		/* LINTED pointer alignment */
5230Sstevel@tonic-gate 		m = (mblk_t *)xdrs->x_base;
5240Sstevel@tonic-gate 		if (m == NULL)
5250Sstevel@tonic-gate 			return (FALSE);
5260Sstevel@tonic-gate 		int32p = (int32_t *)info;
5270Sstevel@tonic-gate 		len = RNDUP((int)(*int32p));
5282627Smaheshvs 		if (len < 0)
529*7387SRobert.Gordon@Sun.COM 			return (FALSE);
5300Sstevel@tonic-gate 		while ((xdrs->x_handy -= len) < 0) {
5310Sstevel@tonic-gate 			if ((xdrs->x_handy += len) > 0) {
5320Sstevel@tonic-gate 				m->b_rptr += xdrs->x_handy;
5330Sstevel@tonic-gate 				len -= xdrs->x_handy;
5340Sstevel@tonic-gate 			}
5350Sstevel@tonic-gate 			m = m->b_cont;
5360Sstevel@tonic-gate 			xdrs->x_base = (caddr_t)m;
5370Sstevel@tonic-gate 			if (m == NULL) {
5380Sstevel@tonic-gate 				xdrs->x_handy = 0;
5390Sstevel@tonic-gate 				return (FALSE);
5400Sstevel@tonic-gate 			}
5410Sstevel@tonic-gate 			xdrs->x_handy = (int)(m->b_wptr - m->b_rptr);
5420Sstevel@tonic-gate 		}
5430Sstevel@tonic-gate 		m->b_rptr += len;
5440Sstevel@tonic-gate 		return (TRUE);
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 	default:
5470Sstevel@tonic-gate 		return (FALSE);
5480Sstevel@tonic-gate 	}
5490Sstevel@tonic-gate }
5500Sstevel@tonic-gate 
5510Sstevel@tonic-gate #define	HDR_SPACE	128
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate static mblk_t *
5540Sstevel@tonic-gate xdrmblk_alloc(int sz)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 	mblk_t *mp;
5570Sstevel@tonic-gate 
5580Sstevel@tonic-gate 	if (sz == 0)
5590Sstevel@tonic-gate 		return (NULL);
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	/*
5620Sstevel@tonic-gate 	 * Pad the front of the message to allow the lower networking
5630Sstevel@tonic-gate 	 * layers space to add headers as needed.
5640Sstevel@tonic-gate 	 */
5650Sstevel@tonic-gate 	sz += HDR_SPACE;
5660Sstevel@tonic-gate 
5670Sstevel@tonic-gate 	while ((mp = allocb(sz, BPRI_LO)) == NULL) {
5680Sstevel@tonic-gate 		if (strwaitbuf(sz, BPRI_LO))
5690Sstevel@tonic-gate 			return (NULL);
5700Sstevel@tonic-gate 	}
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	mp->b_wptr += HDR_SPACE;
5730Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr;
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	return (mp);
5760Sstevel@tonic-gate }
577