14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000, 2001 Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $FreeBSD: src/sys/kern/subr_mchain.c,v 1.1 2001/02/24 15:44:29 bp Exp $
334bff34e3Sthurlow  */
34613a2f6bSGordon Ross 
354bff34e3Sthurlow /*
36613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
374bff34e3Sthurlow  * Use is subject to license terms.
38*adee6784SGordon Ross  *
39*adee6784SGordon Ross  * Copyright 2018 Nexenta Systems, Inc.  All rights reserved.
404bff34e3Sthurlow  */
414bff34e3Sthurlow 
424bff34e3Sthurlow #include <sys/param.h>
434bff34e3Sthurlow #include <sys/systm.h>
444bff34e3Sthurlow #include <sys/errno.h>
454bff34e3Sthurlow #include <sys/uio.h>
464bff34e3Sthurlow #include <sys/types.h>
474bff34e3Sthurlow #include <sys/stream.h>
484bff34e3Sthurlow #include <sys/strsun.h>
494bff34e3Sthurlow #include <sys/strsubr.h>
50613a2f6bSGordon Ross #include <sys/sunddi.h>
514bff34e3Sthurlow #include <sys/cmn_err.h>
524bff34e3Sthurlow 
534bff34e3Sthurlow #include <netsmb/smb_osdep.h>
544bff34e3Sthurlow #include <netsmb/mchain.h>
554bff34e3Sthurlow 
564bff34e3Sthurlow #include <netsmb/smb.h>
574bff34e3Sthurlow #include <netsmb/smb_conn.h>
584bff34e3Sthurlow #include <netsmb/smb_subr.h>
594bff34e3Sthurlow 
604bff34e3Sthurlow /* BEGIN CSTYLED */
614bff34e3Sthurlow /*
624bff34e3Sthurlow  * BSD-style mbufs, vs SysV-style mblks:
634bff34e3Sthurlow  * One big difference: the mbuf payload is:
644bff34e3Sthurlow  *   m_data ... (m_data + m_len)
654bff34e3Sthurlow  * In Unix STREAMS, the mblk payload is:
664bff34e3Sthurlow  *   b_rptr ... b_wptr
67*adee6784SGordon Ross  *
684bff34e3Sthurlow  * Here are some handy conversion notes:
69*adee6784SGordon Ross  *
704bff34e3Sthurlow  * struct mbuf                     struct mblk
714bff34e3Sthurlow  *   m->m_next                       m->b_cont
724bff34e3Sthurlow  *   m->m_nextpkt                    m->b_next
734bff34e3Sthurlow  *   m->m_data                       m->b_rptr
744bff34e3Sthurlow  *   m->m_len                        MBLKL(m)
754bff34e3Sthurlow  *   m->m_dat[]                      m->b_datap->db_base
764bff34e3Sthurlow  *   &m->m_dat[MLEN]                 m->b_datap->db_lim
774bff34e3Sthurlow  *   M_TRAILINGSPACE(m)              MBLKTAIL(m)
784bff34e3Sthurlow  *   m_freem(m)                      freemsg(m)
79*adee6784SGordon Ross  *
804bff34e3Sthurlow  * Note that mbufs chains also have a special "packet" header,
814bff34e3Sthurlow  * which has the length of the whole message.  In STREAMS one
824bff34e3Sthurlow  * typically just calls msgdsize(m) to get that.
834bff34e3Sthurlow  */
844bff34e3Sthurlow /* END CSTYLED */
854bff34e3Sthurlow 
864bff34e3Sthurlow 
874bff34e3Sthurlow /*
884bff34e3Sthurlow  *
894bff34e3Sthurlow  * MODULE_VERSION(libmchain, 1);
904bff34e3Sthurlow  */
914bff34e3Sthurlow 
924bff34e3Sthurlow #ifdef __GNUC__
934bff34e3Sthurlow #define	MBERROR(format, args...) printf("%s(%d): "format, \
944bff34e3Sthurlow 				    __FUNCTION__, __LINE__, ## args)
954bff34e3Sthurlow #define	MBPANIC(format, args...) printf("%s(%d): "format, \
964bff34e3Sthurlow 				    __FUNCTION__, __LINE__, ## args)
974bff34e3Sthurlow #else
984bff34e3Sthurlow #define	MBERROR(...) \
994bff34e3Sthurlow 	smb_errmsg(CE_NOTE, __func__, __VA_ARGS__)
1004bff34e3Sthurlow #define	MBPANIC(...) \
1014bff34e3Sthurlow 	smb_errmsg(CE_PANIC, __func__, __VA_ARGS__)
1024bff34e3Sthurlow #endif
1034bff34e3Sthurlow 
1044bff34e3Sthurlow /*
1054bff34e3Sthurlow  * MLEN: The smallest mblk we'll allocate.
1064bff34e3Sthurlow  *
1074bff34e3Sthurlow  * There's more to MLEN than you might think.
1084bff34e3Sthurlow  * Some ethernet drivers may send each mblk as a
1094bff34e3Sthurlow  * separate frame, so we want MLEN at least 1K.
1104bff34e3Sthurlow  * We could have used 1K here, but that might
1114bff34e3Sthurlow  * hurt transports that support larger frames.
1124bff34e3Sthurlow  * 4K fits nicely in 3 Ethernet frames (3 * 1500)
1134bff34e3Sthurlow  * leaving about 500 bytes for protocol headers.
1144bff34e3Sthurlow  */
1154bff34e3Sthurlow #define	MLEN	4096
1164bff34e3Sthurlow 
117*adee6784SGordon Ross #if (MLEN < SMB2_HDRLEN)
118*adee6784SGordon Ross #error "MLEN can't fit a contiguous SMB2 header"
119*adee6784SGordon Ross #endif
1204bff34e3Sthurlow 
1214bff34e3Sthurlow /*
1224bff34e3Sthurlow  * Some UIO routines.
1234bff34e3Sthurlow  * Taken from Darwin Sourcecs.
1244bff34e3Sthurlow  */
1254bff34e3Sthurlow 
1264bff34e3Sthurlow /*
127613a2f6bSGordon Ross  * uio_isuserspace - non zero value if the address space
1284bff34e3Sthurlow  * flag is for a user address space (could be 32 or 64 bit).
1294bff34e3Sthurlow  */
130613a2f6bSGordon Ross #define	uio_isuserspace(uio) (uio->uio_segflg == UIO_USERSPACE)
1314bff34e3Sthurlow 
1324bff34e3Sthurlow /*
1334bff34e3Sthurlow  * uio_curriovbase - return the base address of the current iovec associated
1344bff34e3Sthurlow  *      with the given uio_t.  May return 0.
1354bff34e3Sthurlow  */
1364bff34e3Sthurlow caddr_t
uio_curriovbase(uio_t * a_uio)1374bff34e3Sthurlow uio_curriovbase(uio_t *a_uio)
1384bff34e3Sthurlow {
1394bff34e3Sthurlow 	if (a_uio->uio_iovcnt < 1) {
1404bff34e3Sthurlow 		return (0);
1414bff34e3Sthurlow 	}
1424bff34e3Sthurlow 	return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base));
1434bff34e3Sthurlow }
1444bff34e3Sthurlow 
1454bff34e3Sthurlow /*
1464bff34e3Sthurlow  * uio_curriovlen - return the length value of the current iovec associated
1474bff34e3Sthurlow  *      with the given uio_t.
1484bff34e3Sthurlow  */
1494bff34e3Sthurlow size_t
uio_curriovlen(uio_t * a_uio)1504bff34e3Sthurlow uio_curriovlen(uio_t *a_uio)
1514bff34e3Sthurlow {
1524bff34e3Sthurlow 	if (a_uio->uio_iovcnt < 1) {
1534bff34e3Sthurlow 		return (0);
1544bff34e3Sthurlow 	}
1554bff34e3Sthurlow 	return ((size_t)a_uio->uio_iov->iov_len);
1564bff34e3Sthurlow }
1574bff34e3Sthurlow 
1584bff34e3Sthurlow 
1594bff34e3Sthurlow /*
1604bff34e3Sthurlow  * uio_update - update the given uio_t for a_count of completed IO.
1614bff34e3Sthurlow  *      This call decrements the current iovec length and residual IO value
1624bff34e3Sthurlow  *      and increments the current iovec base address and offset value.
1634bff34e3Sthurlow  *      If the current iovec length is 0 then advance to the next
1644bff34e3Sthurlow  *      iovec (if any).
1654bff34e3Sthurlow  *      If the a_count passed in is 0, than only do the advancement
1664bff34e3Sthurlow  *      over any 0 length iovec's.
1674bff34e3Sthurlow  */
1684bff34e3Sthurlow void
uio_update(uio_t * a_uio,size_t a_count)1694bff34e3Sthurlow uio_update(uio_t *a_uio, size_t a_count)
1704bff34e3Sthurlow {
1714bff34e3Sthurlow 	if (a_uio->uio_iovcnt < 1) {
1724bff34e3Sthurlow 		return;
1734bff34e3Sthurlow 	}
1744bff34e3Sthurlow 
1754bff34e3Sthurlow 	/*
1764bff34e3Sthurlow 	 * if a_count == 0, then we are asking to skip over
1774bff34e3Sthurlow 	 * any empty iovs
1784bff34e3Sthurlow 	 */
1794bff34e3Sthurlow 	if (a_count) {
1804bff34e3Sthurlow 		if (a_count > a_uio->uio_iov->iov_len) {
1814bff34e3Sthurlow 			a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len;
1824bff34e3Sthurlow 			a_uio->uio_iov->iov_len = 0;
1834bff34e3Sthurlow 		} else {
1844bff34e3Sthurlow 			a_uio->uio_iov->iov_base += a_count;
1854bff34e3Sthurlow 			a_uio->uio_iov->iov_len -= a_count;
1864bff34e3Sthurlow 		}
1874bff34e3Sthurlow 		if (a_uio->uio_resid < 0) {
1884bff34e3Sthurlow 			a_uio->uio_resid = 0;
1894bff34e3Sthurlow 		}
1904bff34e3Sthurlow 		if (a_count > (size_t)a_uio->uio_resid) {
191613a2f6bSGordon Ross 			a_uio->uio_loffset += a_uio->uio_resid;
1924bff34e3Sthurlow 			a_uio->uio_resid = 0;
1934bff34e3Sthurlow 		} else {
194613a2f6bSGordon Ross 			a_uio->uio_loffset += a_count;
1954bff34e3Sthurlow 			a_uio->uio_resid -= a_count;
1964bff34e3Sthurlow 		}
1974bff34e3Sthurlow 	}
1984bff34e3Sthurlow 	/*
1994bff34e3Sthurlow 	 * advance to next iovec if current one is totally consumed
2004bff34e3Sthurlow 	 */
2014bff34e3Sthurlow 	while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) {
2024bff34e3Sthurlow 		a_uio->uio_iovcnt--;
2034bff34e3Sthurlow 		if (a_uio->uio_iovcnt > 0) {
2044bff34e3Sthurlow 			a_uio->uio_iov++;
2054bff34e3Sthurlow 		}
2064bff34e3Sthurlow 	}
2074bff34e3Sthurlow }
2084bff34e3Sthurlow 
209613a2f6bSGordon Ross /*
210613a2f6bSGordon Ross  * This is now used only to extend an existing mblk chain,
211613a2f6bSGordon Ross  * so don't need to use allocb_cred_wait here.
212613a2f6bSGordon Ross  */
2134bff34e3Sthurlow /*ARGSUSED*/
2144bff34e3Sthurlow mblk_t *
m_getblk(int size,int type)2154bff34e3Sthurlow m_getblk(int size, int type)
2164bff34e3Sthurlow {
2174bff34e3Sthurlow 	mblk_t *mblk;
2184bff34e3Sthurlow 	int error;
2194bff34e3Sthurlow 
2204bff34e3Sthurlow 	/* Make size at least MLEN. */
2214bff34e3Sthurlow 	if (size < MLEN)
2224bff34e3Sthurlow 		size = MLEN;
2234bff34e3Sthurlow 	mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error);
2244bff34e3Sthurlow 	ASSERT(mblk);
2254bff34e3Sthurlow 	return (mblk);
2264bff34e3Sthurlow }
2274bff34e3Sthurlow 
2284bff34e3Sthurlow void
mb_done(struct mbchain * mbp)2294bff34e3Sthurlow mb_done(struct mbchain *mbp)
2304bff34e3Sthurlow {
2314bff34e3Sthurlow 	if (mbp->mb_top) {
2324bff34e3Sthurlow 		freemsg(mbp->mb_top);
2334bff34e3Sthurlow 		mbp->mb_top = NULL;
2344bff34e3Sthurlow 	}
2354bff34e3Sthurlow 	/* Avoid dangling references */
2364bff34e3Sthurlow 	mbp->mb_cur = NULL;
2374bff34e3Sthurlow }
2384bff34e3Sthurlow 
2394bff34e3Sthurlow unsigned int
m_length(mblk_t * mblk)2404bff34e3Sthurlow m_length(mblk_t *mblk)
2414bff34e3Sthurlow {
2424bff34e3Sthurlow 	uint64_t diff;
2434bff34e3Sthurlow 
2444bff34e3Sthurlow 	diff = (uintptr_t)mblk->b_datap->db_lim -
2454bff34e3Sthurlow 	    (uintptr_t)mblk->b_datap->db_base;
2464bff34e3Sthurlow 	ASSERT(diff == (uint64_t)((unsigned int)diff));
2474bff34e3Sthurlow 	return ((unsigned int)diff);
2484bff34e3Sthurlow }
2494bff34e3Sthurlow 
2504bff34e3Sthurlow void
mb_initm(struct mbchain * mbp,mblk_t * m)2514bff34e3Sthurlow mb_initm(struct mbchain *mbp, mblk_t *m)
2524bff34e3Sthurlow {
2534bff34e3Sthurlow 	bzero(mbp, sizeof (*mbp));
2544bff34e3Sthurlow 	mbp->mb_top = mbp->mb_cur = m;
2554bff34e3Sthurlow }
2564bff34e3Sthurlow 
2574bff34e3Sthurlow 
2584bff34e3Sthurlow int
mb_init(struct mbchain * mbp)2594bff34e3Sthurlow mb_init(struct mbchain *mbp)
2604bff34e3Sthurlow {
261613a2f6bSGordon Ross 	cred_t *cr;
2624bff34e3Sthurlow 	mblk_t *mblk;
263613a2f6bSGordon Ross 	int error;
2644bff34e3Sthurlow 
265613a2f6bSGordon Ross 	/*
266613a2f6bSGordon Ross 	 * This message will be the head of a new mblk chain,
267613a2f6bSGordon Ross 	 * so we'd like its db_credp set.  If we extend this
268613a2f6bSGordon Ross 	 * chain later, we'll just use allocb_wait()
269613a2f6bSGordon Ross 	 */
270613a2f6bSGordon Ross 	cr = ddi_get_cred();
271613a2f6bSGordon Ross 	mblk = allocb_cred_wait(MLEN, STR_NOSIG, &error, cr, NOPID);
2724bff34e3Sthurlow 
2734bff34e3Sthurlow 	/*
2744bff34e3Sthurlow 	 * Leave room in this first mblk so we can
2754bff34e3Sthurlow 	 * prepend a 4-byte NetBIOS header.
2764bff34e3Sthurlow 	 * See smb_nbst_send()
2774bff34e3Sthurlow 	 */
2784bff34e3Sthurlow 	mblk->b_wptr += 4;
2794bff34e3Sthurlow 	mblk->b_rptr = mblk->b_wptr;
2804bff34e3Sthurlow 
2814bff34e3Sthurlow 	mb_initm(mbp, mblk);
2824bff34e3Sthurlow 	return (0);
2834bff34e3Sthurlow }
2844bff34e3Sthurlow 
2854bff34e3Sthurlow 
2864bff34e3Sthurlow /*
2874bff34e3Sthurlow  * mb_detach() function returns the value of mbp->mb_top field
2884bff34e3Sthurlow  * and sets its * value to NULL.
2894bff34e3Sthurlow  */
2904bff34e3Sthurlow 
2914bff34e3Sthurlow mblk_t *
mb_detach(struct mbchain * mbp)2924bff34e3Sthurlow mb_detach(struct mbchain *mbp)
2934bff34e3Sthurlow {
2944bff34e3Sthurlow 	mblk_t *m;
2954bff34e3Sthurlow 
2964bff34e3Sthurlow 	m = mbp->mb_top;
2974bff34e3Sthurlow 	mbp->mb_top = mbp->mb_cur = NULL;
2984bff34e3Sthurlow 	return (m);
2994bff34e3Sthurlow }
3004bff34e3Sthurlow 
3014bff34e3Sthurlow /*
3024bff34e3Sthurlow  * Returns the length of the mblk_t data.
303613a2f6bSGordon Ross  * Should be m_totlen() perhaps?
3044bff34e3Sthurlow  */
3054bff34e3Sthurlow int
m_fixhdr(mblk_t * m0)3064bff34e3Sthurlow m_fixhdr(mblk_t *m0)
3074bff34e3Sthurlow {
3084bff34e3Sthurlow 	size_t dsz;
3094bff34e3Sthurlow 
3104bff34e3Sthurlow 	dsz = msgdsize(m0);
3114bff34e3Sthurlow 	return ((int)dsz);
3124bff34e3Sthurlow }
3134bff34e3Sthurlow 
3144bff34e3Sthurlow /*
3154bff34e3Sthurlow  * BSD code set the message header length here, and
3164bff34e3Sthurlow  * returned the length.  We don't have that field, so
3174bff34e3Sthurlow  * just return the message length.
3184bff34e3Sthurlow  */
3194bff34e3Sthurlow int
mb_fixhdr(struct mbchain * mbp)3204bff34e3Sthurlow mb_fixhdr(struct mbchain *mbp)
3214bff34e3Sthurlow {
3224bff34e3Sthurlow 	return (m_fixhdr(mbp->mb_top));
3234bff34e3Sthurlow }
3244bff34e3Sthurlow 
3254bff34e3Sthurlow 
3264bff34e3Sthurlow /*
3274bff34e3Sthurlow  * Check if object of size 'size' fit to the current position and
3284bff34e3Sthurlow  * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s).
3294bff34e3Sthurlow  * Return pointer to the object placeholder or NULL if any error occured.
3304bff34e3Sthurlow  * Note: size should be <= MLEN
3314bff34e3Sthurlow  */
3324bff34e3Sthurlow void *
mb_reserve(struct mbchain * mbp,int size)3334bff34e3Sthurlow mb_reserve(struct mbchain *mbp, int size)
3344bff34e3Sthurlow {
3354bff34e3Sthurlow 	mblk_t *m, *mn;
3364bff34e3Sthurlow 	void *bpos;
3374bff34e3Sthurlow 
3384bff34e3Sthurlow 	m = mbp->mb_cur;
3394bff34e3Sthurlow 	/*
3404bff34e3Sthurlow 	 * If the requested size is more than the space left.
3414bff34e3Sthurlow 	 * Allocate and appenad a new mblk.
3424bff34e3Sthurlow 	 */
3434bff34e3Sthurlow 	if (MBLKTAIL(m) < size) {
3444bff34e3Sthurlow 		mn = m_getblk(size, 1);
3454bff34e3Sthurlow 		if (mn == NULL)
3464bff34e3Sthurlow 			return (NULL);
3474bff34e3Sthurlow 		mbp->mb_cur = m->b_cont = mn;
3484bff34e3Sthurlow 		m = mn;
3494bff34e3Sthurlow 	}
3504bff34e3Sthurlow 	/*
3514bff34e3Sthurlow 	 * If 'size' bytes fits into the buffer, then
3524bff34e3Sthurlow 	 * 1. increment the write pointer to the size.
3534bff34e3Sthurlow 	 * 2. return the position from where the memory is reserved.
3544bff34e3Sthurlow 	 */
3554bff34e3Sthurlow 	bpos = m->b_wptr;
3564bff34e3Sthurlow 	m->b_wptr += size;
3574bff34e3Sthurlow 	mbp->mb_count += size;
3584bff34e3Sthurlow 	return (bpos);
3594bff34e3Sthurlow }
3604bff34e3Sthurlow 
3614bff34e3Sthurlow /*
3624bff34e3Sthurlow  * All mb_put_*() functions perform an actual copy of the data into mbuf
3634bff34e3Sthurlow  * chain. Functions which have le or be suffixes will perform conversion to
3644bff34e3Sthurlow  * the little- or big-endian data formats.
365613a2f6bSGordon Ross  *
366613a2f6bSGordon Ross  * Inline version of mb_put_mem().  Handles the easy case in-line,
367613a2f6bSGordon Ross  * and calls mb_put_mem() if crossing mblk boundaries, etc.
368613a2f6bSGordon Ross  *
369613a2f6bSGordon Ross  * We build with -xspace, which causes these inline functions
370613a2f6bSGordon Ross  * to not be inlined.  Using macros instead for now.
371613a2f6bSGordon Ross  */
372613a2f6bSGordon Ross #ifdef	INLINE_WORKS
373613a2f6bSGordon Ross 
374613a2f6bSGordon Ross static inline int
mb_put_inline(struct mbchain * mbp,void * src,int size)375613a2f6bSGordon Ross mb_put_inline(struct mbchain *mbp, void *src, int size)
376613a2f6bSGordon Ross {
377613a2f6bSGordon Ross 	mblk_t *m = mbp->mb_cur;
378613a2f6bSGordon Ross 
379613a2f6bSGordon Ross 	if (m != NULL && size <= MBLKTAIL(m)) {
380613a2f6bSGordon Ross 		uchar_t *p = src;
381613a2f6bSGordon Ross 		int n = size;
382613a2f6bSGordon Ross 		while (n--)
383613a2f6bSGordon Ross 			*(m->b_wptr)++ = *p++;
384613a2f6bSGordon Ross 		mbp->mb_count += size;
385613a2f6bSGordon Ross 		return (0);
386613a2f6bSGordon Ross 	}
387613a2f6bSGordon Ross 	return (mb_put_mem(mbp, src, size, MB_MINLINE));
388613a2f6bSGordon Ross }
389613a2f6bSGordon Ross #define	MB_PUT_INLINE(MBP, SRC, SZ) \
390613a2f6bSGordon Ross 	return (mb_put_inline(MBP, SRC, SZ))
391613a2f6bSGordon Ross 
392613a2f6bSGordon Ross #else /* INLINE_WORKS */
393613a2f6bSGordon Ross 
394613a2f6bSGordon Ross #define	MB_PUT_INLINE(MBP, SRC, SZ) \
395613a2f6bSGordon Ross 	mblk_t *m = MBP->mb_cur; \
396613a2f6bSGordon Ross 	if (m != NULL && SZ <= MBLKTAIL(m)) { \
397613a2f6bSGordon Ross 		uchar_t *p = (void *) SRC; \
398613a2f6bSGordon Ross 		int n = SZ; \
399613a2f6bSGordon Ross 		while (n--) \
400613a2f6bSGordon Ross 			*(m->b_wptr)++ = *p++; \
401613a2f6bSGordon Ross 		MBP->mb_count += SZ; \
402613a2f6bSGordon Ross 		return (0); \
403613a2f6bSGordon Ross 	} \
404613a2f6bSGordon Ross 	return (mb_put_mem(MBP, SRC, SZ, MB_MINLINE))
405613a2f6bSGordon Ross 
406613a2f6bSGordon Ross #endif /* INLINE_WORKS */
407613a2f6bSGordon Ross 
408613a2f6bSGordon Ross /*
409613a2f6bSGordon Ross  * Assumes total data length in previous mblks is EVEN.
410613a2f6bSGordon Ross  * Might need to compute the offset from mb_top instead.
4114bff34e3Sthurlow  */
4124bff34e3Sthurlow int
mb_put_padbyte(struct mbchain * mbp)4134bff34e3Sthurlow mb_put_padbyte(struct mbchain *mbp)
4144bff34e3Sthurlow {
415613a2f6bSGordon Ross 	uintptr_t dst;
416613a2f6bSGordon Ross 	char v = 0;
4174bff34e3Sthurlow 
418613a2f6bSGordon Ross 	dst = (uintptr_t)mbp->mb_cur->b_wptr;
4194bff34e3Sthurlow 	/* only add padding if address is odd */
420613a2f6bSGordon Ross 	if (dst & 1) {
421613a2f6bSGordon Ross 		MB_PUT_INLINE(mbp, &v, sizeof (v));
422613a2f6bSGordon Ross 	}
423613a2f6bSGordon Ross 
424613a2f6bSGordon Ross 	return (0);
4254bff34e3Sthurlow }
4264bff34e3Sthurlow 
427*adee6784SGordon Ross /*
428*adee6784SGordon Ross  * Adds padding to 8 byte boundary
429*adee6784SGordon Ross  */
430*adee6784SGordon Ross int
mb_put_align8(struct mbchain * mbp)431*adee6784SGordon Ross mb_put_align8(struct mbchain *mbp)
432*adee6784SGordon Ross {
433*adee6784SGordon Ross 	static const char zeros[8] = { 0 };
434*adee6784SGordon Ross 	int pad_len = 0;
435*adee6784SGordon Ross 
436*adee6784SGordon Ross 	if ((mbp->mb_count % 8) != 0) {
437*adee6784SGordon Ross 		pad_len = 8 - (mbp->mb_count % 8);
438*adee6784SGordon Ross 		MB_PUT_INLINE(mbp, zeros, pad_len);
439*adee6784SGordon Ross 	}
440*adee6784SGordon Ross 	return (0);
441*adee6784SGordon Ross }
442*adee6784SGordon Ross 
4434bff34e3Sthurlow int
mb_put_uint8(struct mbchain * mbp,u_int8_t x)4444bff34e3Sthurlow mb_put_uint8(struct mbchain *mbp, u_int8_t x)
4454bff34e3Sthurlow {
446613a2f6bSGordon Ross 	u_int8_t v = x;
447613a2f6bSGordon Ross 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4484bff34e3Sthurlow }
4494bff34e3Sthurlow 
4504bff34e3Sthurlow int
mb_put_uint16be(struct mbchain * mbp,u_int16_t x)4514bff34e3Sthurlow mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
4524bff34e3Sthurlow {
453613a2f6bSGordon Ross 	u_int16_t v = htobes(x);
454613a2f6bSGordon Ross 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4554bff34e3Sthurlow }
4564bff34e3Sthurlow 
4574bff34e3Sthurlow int
mb_put_uint16le(struct mbchain * mbp,u_int16_t x)4584bff34e3Sthurlow mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
4594bff34e3Sthurlow {
460613a2f6bSGordon Ross 	u_int16_t v = htoles(x);
461613a2f6bSGordon Ross 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4624bff34e3Sthurlow }
4634bff34e3Sthurlow 
4644bff34e3Sthurlow int
mb_put_uint32be(struct mbchain * mbp,u_int32_t x)4654bff34e3Sthurlow mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
4664bff34e3Sthurlow {
467613a2f6bSGordon Ross 	u_int32_t v = htobel(x);
468613a2f6bSGordon Ross 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4694bff34e3Sthurlow }
4704bff34e3Sthurlow 
4714bff34e3Sthurlow int
mb_put_uint32le(struct mbchain * mbp,u_int32_t x)4724bff34e3Sthurlow mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
4734bff34e3Sthurlow {
474613a2f6bSGordon Ross 	u_int32_t v = htolel(x);
475613a2f6bSGordon Ross 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4764bff34e3Sthurlow }
4774bff34e3Sthurlow 
4784bff34e3Sthurlow int
mb_put_uint64be(struct mbchain * mbp,u_int64_t x)4794bff34e3Sthurlow mb_put_uint64be(struct mbchain *mbp, u_int64_t x)
4804bff34e3Sthurlow {
481613a2f6bSGordon Ross 	u_int64_t v = htobeq(x);
482613a2f6bSGordon Ross 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4834bff34e3Sthurlow }
4844bff34e3Sthurlow 
4854bff34e3Sthurlow int
mb_put_uint64le(struct mbchain * mbp,u_int64_t x)4864bff34e3Sthurlow mb_put_uint64le(struct mbchain *mbp, u_int64_t x)
4874bff34e3Sthurlow {
488613a2f6bSGordon Ross 	u_int64_t v = htoleq(x);
489613a2f6bSGordon Ross 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4904bff34e3Sthurlow }
4914bff34e3Sthurlow 
4924bff34e3Sthurlow /*
4934bff34e3Sthurlow  * mb_put_mem() function copies size bytes of data specified by the source
4944bff34e3Sthurlow  * argument to an mbuf chain.  The type argument specifies the method used
4954bff34e3Sthurlow  * to perform a copy
4964bff34e3Sthurlow  */
4974bff34e3Sthurlow int
mb_put_mem(struct mbchain * mbp,const void * vsrc,int size,int type)498613a2f6bSGordon Ross mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
4994bff34e3Sthurlow {
500613a2f6bSGordon Ross 	mblk_t *n, *m = mbp->mb_cur;
501613a2f6bSGordon Ross 	c_caddr_t source = vsrc;
5024bff34e3Sthurlow 	c_caddr_t src;
503613a2f6bSGordon Ross 	caddr_t dst;
5044bff34e3Sthurlow 	uint64_t diff;
505613a2f6bSGordon Ross 	int cplen, mleft, count;
5064bff34e3Sthurlow 
5074bff34e3Sthurlow 	diff = MBLKTAIL(m);
5084bff34e3Sthurlow 	ASSERT(diff == (uint64_t)((int)diff));
5094bff34e3Sthurlow 	mleft = (int)diff;
5104bff34e3Sthurlow 
5114bff34e3Sthurlow 	while (size > 0) {
5124bff34e3Sthurlow 		if (mleft == 0) {
5134bff34e3Sthurlow 			if (m->b_cont == NULL) {
5144bff34e3Sthurlow 				/*
5154bff34e3Sthurlow 				 * Changed m_getm() to m_getblk()
5164bff34e3Sthurlow 				 * with the requested size, so we
5174bff34e3Sthurlow 				 * don't need m_getm() anymore.
5184bff34e3Sthurlow 				 */
5194bff34e3Sthurlow 				n = m_getblk(size, 1);
5204bff34e3Sthurlow 				if (n == NULL)
5214bff34e3Sthurlow 					return (ENOBUFS);
5224bff34e3Sthurlow 				m->b_cont = n;
5234bff34e3Sthurlow 			}
5244bff34e3Sthurlow 			m = m->b_cont;
5254bff34e3Sthurlow 			diff = MBLKTAIL(m);
5264bff34e3Sthurlow 			ASSERT(diff == (uint64_t)((int)diff));
5274bff34e3Sthurlow 			mleft = (int)diff;
5284bff34e3Sthurlow 			continue;
5294bff34e3Sthurlow 		}
5304bff34e3Sthurlow 		cplen = mleft > size ? size : mleft;
5314bff34e3Sthurlow 		dst = (caddr_t)m->b_wptr;
5324bff34e3Sthurlow 		switch (type) {
5334bff34e3Sthurlow 		case MB_MINLINE:
5344bff34e3Sthurlow 			for (src = source, count = cplen; count; count--)
5354bff34e3Sthurlow 				*dst++ = *src++;
5364bff34e3Sthurlow 			break;
5374bff34e3Sthurlow 		case MB_MSYSTEM:
5384bff34e3Sthurlow 			bcopy(source, dst, cplen);
5394bff34e3Sthurlow 			break;
5404bff34e3Sthurlow 		case MB_MUSER:
541613a2f6bSGordon Ross 			if (copyin((void *)source, dst, cplen))
542613a2f6bSGordon Ross 				return (EFAULT);
5434bff34e3Sthurlow 			break;
5444bff34e3Sthurlow 		case MB_MZERO:
5454bff34e3Sthurlow 			bzero(dst, cplen);
5464bff34e3Sthurlow 			break;
5474bff34e3Sthurlow 		}
5484bff34e3Sthurlow 		size -= cplen;
5494bff34e3Sthurlow 		source += cplen;
5504bff34e3Sthurlow 		mleft -= cplen;
5514bff34e3Sthurlow 		m->b_wptr += cplen;
5524bff34e3Sthurlow 		mbp->mb_count += cplen;
5534bff34e3Sthurlow 	}
5544bff34e3Sthurlow 	mbp->mb_cur = m;
5554bff34e3Sthurlow 	return (0);
5564bff34e3Sthurlow }
5574bff34e3Sthurlow 
5584bff34e3Sthurlow /*
5594bff34e3Sthurlow  * Append an mblk to the chain.
560*adee6784SGordon Ross  * Note: The mblk_t *m is consumed.
5614bff34e3Sthurlow  */
5624bff34e3Sthurlow int
mb_put_mbuf(struct mbchain * mbp,mblk_t * m)5634bff34e3Sthurlow mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
5644bff34e3Sthurlow {
565430b4c46SGordon Ross 	mblk_t *nm, *tail_mb;
566430b4c46SGordon Ross 	size_t size;
5674bff34e3Sthurlow 
5684bff34e3Sthurlow 	/* See: linkb(9f) */
569430b4c46SGordon Ross 	tail_mb = mbp->mb_cur;
570430b4c46SGordon Ross 	while (tail_mb->b_cont != NULL)
571430b4c46SGordon Ross 		tail_mb = tail_mb->b_cont;
572430b4c46SGordon Ross 
573430b4c46SGordon Ross 	/*
574430b4c46SGordon Ross 	 * Avoid small frags:  Only link if the size of the
575430b4c46SGordon Ross 	 * new mbuf is larger than the space left in the last
576430b4c46SGordon Ross 	 * mblk of the chain (tail), otherwise just copy.
577430b4c46SGordon Ross 	 */
578430b4c46SGordon Ross 	while (m != NULL) {
579430b4c46SGordon Ross 		size = MBLKL(m);
580430b4c46SGordon Ross 		if (size > MBLKTAIL(tail_mb)) {
581430b4c46SGordon Ross 			/* Link */
582430b4c46SGordon Ross 			tail_mb->b_cont = m;
583430b4c46SGordon Ross 			mbp->mb_cur = m;
584430b4c46SGordon Ross 			mbp->mb_count += msgdsize(m);
585430b4c46SGordon Ross 			return (0);
586430b4c46SGordon Ross 		}
587430b4c46SGordon Ross 		/* Copy */
588430b4c46SGordon Ross 		bcopy(m->b_rptr, tail_mb->b_wptr, size);
589430b4c46SGordon Ross 		tail_mb->b_wptr += size;
590430b4c46SGordon Ross 		mbp->mb_count += size;
591430b4c46SGordon Ross 		nm = unlinkb(m);
592430b4c46SGordon Ross 		freeb(m);
593430b4c46SGordon Ross 		m = nm;
594430b4c46SGordon Ross 	}
5954bff34e3Sthurlow 
5964bff34e3Sthurlow 	return (0);
5974bff34e3Sthurlow }
5984bff34e3Sthurlow 
599*adee6784SGordon Ross /*
600*adee6784SGordon Ross  * Put an mbchain into another mbchain
601*adee6784SGordon Ross  * Leave sub_mbp untouched.
602*adee6784SGordon Ross  */
603*adee6784SGordon Ross int
mb_put_mbchain(struct mbchain * mbp,struct mbchain * sub_mbp)604*adee6784SGordon Ross mb_put_mbchain(struct mbchain *mbp, struct mbchain *sub_mbp)
605*adee6784SGordon Ross {
606*adee6784SGordon Ross 	mblk_t *m;
607*adee6784SGordon Ross 
608*adee6784SGordon Ross 	if (sub_mbp == NULL)
609*adee6784SGordon Ross 		return (0);
610*adee6784SGordon Ross 
611*adee6784SGordon Ross 	m = sub_mbp->mb_top;
612*adee6784SGordon Ross 	if (m == NULL)
613*adee6784SGordon Ross 		return (0);
614*adee6784SGordon Ross 
615*adee6784SGordon Ross 	m = dupmsg(m);
616*adee6784SGordon Ross 	if (m == NULL)
617*adee6784SGordon Ross 		return (ENOSR);
618*adee6784SGordon Ross 
619*adee6784SGordon Ross 	return (mb_put_mbuf(mbp, m));
620*adee6784SGordon Ross }
621*adee6784SGordon Ross 
6224bff34e3Sthurlow /*
6234bff34e3Sthurlow  * copies a uio scatter/gather list to an mbuf chain.
6244bff34e3Sthurlow  */
6254bff34e3Sthurlow int
mb_put_uio(struct mbchain * mbp,uio_t * uiop,size_t size)626613a2f6bSGordon Ross mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size)
6274bff34e3Sthurlow {
628613a2f6bSGordon Ross 	size_t left;
6294bff34e3Sthurlow 	int mtype, error;
6304bff34e3Sthurlow 
6314bff34e3Sthurlow 	mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
6324bff34e3Sthurlow 	while (size > 0 && uiop->uio_resid) {
633613a2f6bSGordon Ross 		if (uiop->uio_iovcnt <= 0 ||
634613a2f6bSGordon Ross 		    uio_curriovbase(uiop) == USER_ADDR_NULL)
6354bff34e3Sthurlow 			return (EFBIG);
6364bff34e3Sthurlow 		left = uio_curriovlen(uiop);
6374bff34e3Sthurlow 		if (left > size)
6384bff34e3Sthurlow 			left = size;
6394bff34e3Sthurlow 		error = mb_put_mem(mbp, CAST_DOWN(caddr_t,
6404bff34e3Sthurlow 		    uio_curriovbase(uiop)), left, mtype);
6414bff34e3Sthurlow 		if (error)
6424bff34e3Sthurlow 			return (error);
6434bff34e3Sthurlow 		uio_update(uiop, left);
6444bff34e3Sthurlow 		size -= left;
6454bff34e3Sthurlow 	}
6464bff34e3Sthurlow 	return (0);
6474bff34e3Sthurlow }
6484bff34e3Sthurlow 
6494bff34e3Sthurlow /*
6504bff34e3Sthurlow  * Routines for fetching data from an mbuf chain
6514bff34e3Sthurlow  */
6524bff34e3Sthurlow 
6534bff34e3Sthurlow void
md_initm(struct mdchain * mdp,mblk_t * m)6544bff34e3Sthurlow md_initm(struct mdchain *mdp, mblk_t *m)
6554bff34e3Sthurlow {
6564bff34e3Sthurlow 	bzero(mdp, sizeof (*mdp));
6574bff34e3Sthurlow 	mdp->md_top = mdp->md_cur = m;
6584bff34e3Sthurlow 	mdp->md_pos = m->b_rptr;
6594bff34e3Sthurlow }
6604bff34e3Sthurlow 
6614bff34e3Sthurlow void
md_done(struct mdchain * mdp)6624bff34e3Sthurlow md_done(struct mdchain *mdp)
6634bff34e3Sthurlow {
6644bff34e3Sthurlow 	mblk_t *m;
6654bff34e3Sthurlow 
6664bff34e3Sthurlow 	/*
6674bff34e3Sthurlow 	 * Deal with the fact that we can error out of
6684bff34e3Sthurlow 	 * smb_t2_reply or smb_nt_reply without using up
6694bff34e3Sthurlow 	 * all the "records" added by md_append_record().
6704bff34e3Sthurlow 	 */
6714bff34e3Sthurlow 	while ((m = mdp->md_top) != NULL) {
6724bff34e3Sthurlow 		mdp->md_top = m->b_next;
6734bff34e3Sthurlow 		m->b_next = NULL;
6744bff34e3Sthurlow 		freemsg(m);
6754bff34e3Sthurlow 	}
6764bff34e3Sthurlow 	/* Avoid dangling references */
6774bff34e3Sthurlow 	mdp->md_cur = NULL;
6784bff34e3Sthurlow 	mdp->md_pos = NULL;
6794bff34e3Sthurlow }
6804bff34e3Sthurlow 
6814bff34e3Sthurlow /*
6824bff34e3Sthurlow  * Append a new message (separate mbuf chain).
6834bff34e3Sthurlow  * It is caller responsibility to prevent
6844bff34e3Sthurlow  * multiple calls to fetch/record routines.
68502d09e03SGordon Ross  * Note unusual use of mblk->b_next here.
6864bff34e3Sthurlow  */
6874bff34e3Sthurlow void
md_append_record(struct mdchain * mdp,mblk_t * top)6884bff34e3Sthurlow md_append_record(struct mdchain *mdp, mblk_t *top)
6894bff34e3Sthurlow {
6904bff34e3Sthurlow 	mblk_t *m;
6914bff34e3Sthurlow 
6924bff34e3Sthurlow 	top->b_next = NULL;
6934bff34e3Sthurlow 	if (mdp->md_top == NULL) {
6944bff34e3Sthurlow 		md_initm(mdp, top);
6954bff34e3Sthurlow 		return;
6964bff34e3Sthurlow 	}
6974bff34e3Sthurlow 	m = mdp->md_top;
6984bff34e3Sthurlow 	/* Get to last message (not b_cont chain) */
6994bff34e3Sthurlow 	while (m->b_next)
7004bff34e3Sthurlow 		m = m->b_next;
7014bff34e3Sthurlow 	m->b_next = top;
7024bff34e3Sthurlow }
7034bff34e3Sthurlow 
7044bff34e3Sthurlow /*
7054bff34e3Sthurlow  * Advance mdp->md_top to the next message.
70602d09e03SGordon Ross  * Note unusual use of mblk->b_next here.
7074bff34e3Sthurlow  */
70802d09e03SGordon Ross void
md_next_record(struct mdchain * mdp)7094bff34e3Sthurlow md_next_record(struct mdchain *mdp)
7104bff34e3Sthurlow {
71102d09e03SGordon Ross 	mblk_t *m, *top;
71202d09e03SGordon Ross 
71302d09e03SGordon Ross 	if ((top = mdp->md_top) == NULL)
71402d09e03SGordon Ross 		return;
7154bff34e3Sthurlow 
71602d09e03SGordon Ross 	/*
71702d09e03SGordon Ross 	 * Get the next message, if any,
71802d09e03SGordon Ross 	 * stored by md_append_record.
71902d09e03SGordon Ross 	 * Note: NOT b_cont chain
72002d09e03SGordon Ross 	 */
72102d09e03SGordon Ross 	m = top->b_next;
72202d09e03SGordon Ross 	top->b_next = NULL;
72302d09e03SGordon Ross 
72402d09e03SGordon Ross 	/* Done with old "top". */
7254bff34e3Sthurlow 	md_done(mdp);
7264bff34e3Sthurlow 	if (m == NULL)
72702d09e03SGordon Ross 		return;
72802d09e03SGordon Ross 
72902d09e03SGordon Ross 	/* Setup new "top". */
7304bff34e3Sthurlow 	md_initm(mdp, m);
7314bff34e3Sthurlow }
7324bff34e3Sthurlow 
733613a2f6bSGordon Ross /*
734613a2f6bSGordon Ross  * Inline version of md_get_mem().  Handles the easy case in-line,
735613a2f6bSGordon Ross  * and calls md_get_mem() if crossing mblk boundaries, etc.
736613a2f6bSGordon Ross  */
737613a2f6bSGordon Ross #ifdef	INLINE_WORKS	/* see above */
7384bff34e3Sthurlow 
739613a2f6bSGordon Ross static inline int
md_get_inline(struct mdchain * mdp,void * dst,int size)740613a2f6bSGordon Ross md_get_inline(struct mdchain *mdp, void *dst, int size)
7414bff34e3Sthurlow {
742613a2f6bSGordon Ross 	mblk_t *m = mdp->md_cur;
743613a2f6bSGordon Ross 
744613a2f6bSGordon Ross 	if (m != NULL && mdp->md_pos + size <= m->b_wptr) {
745613a2f6bSGordon Ross 		uchar_t *p = dst;
746613a2f6bSGordon Ross 		int n = size;
747613a2f6bSGordon Ross 		while (n--)
748613a2f6bSGordon Ross 			*p++ = *(mdp->md_pos)++;
749613a2f6bSGordon Ross 		/* no md_count += size */
750613a2f6bSGordon Ross 		return (0);
751613a2f6bSGordon Ross 	}
752613a2f6bSGordon Ross 	return (md_get_mem(mdp, dst, size, MB_MINLINE));
7534bff34e3Sthurlow }
754613a2f6bSGordon Ross #define	MD_GET_INLINE(MDP, DST, SZ) \
755613a2f6bSGordon Ross 	error = md_get_inline(MDP, DST, SZ)
756613a2f6bSGordon Ross 
757613a2f6bSGordon Ross #else /* INLINE_WORKS */
758613a2f6bSGordon Ross 
759613a2f6bSGordon Ross /* Note, sets variable: error */
760613a2f6bSGordon Ross #define	MD_GET_INLINE(MDP, DST, SZ) \
761613a2f6bSGordon Ross 	mblk_t *m = MDP->md_cur; \
762613a2f6bSGordon Ross 	if (m != NULL && MDP->md_pos + SZ <= m->b_wptr) { \
763613a2f6bSGordon Ross 		uchar_t *p = (void *) DST; \
764613a2f6bSGordon Ross 		int n = SZ; \
765613a2f6bSGordon Ross 		while (n--) \
766613a2f6bSGordon Ross 			*p++ = *(mdp->md_pos)++; \
767613a2f6bSGordon Ross 		/* no md_count += SZ */ \
768613a2f6bSGordon Ross 		error = 0; \
769613a2f6bSGordon Ross 	} else \
770613a2f6bSGordon Ross 		error = md_get_mem(MDP, DST, SZ, MB_MINLINE)
771613a2f6bSGordon Ross 
772613a2f6bSGordon Ross #endif /* INLINE_WORKS */
773613a2f6bSGordon Ross 
7744bff34e3Sthurlow 
7754bff34e3Sthurlow int
md_get_uint8(struct mdchain * mdp,u_int8_t * x)776613a2f6bSGordon Ross md_get_uint8(struct mdchain *mdp, u_int8_t *x)
7774bff34e3Sthurlow {
778613a2f6bSGordon Ross 	uint8_t v;
779613a2f6bSGordon Ross 	int error;
7804bff34e3Sthurlow 
781613a2f6bSGordon Ross 	MD_GET_INLINE(mdp, &v, sizeof (v));
7824bff34e3Sthurlow 	if (x)
783613a2f6bSGordon Ross 		*x = v;
7844bff34e3Sthurlow 	return (error);
7854bff34e3Sthurlow }
7864bff34e3Sthurlow 
7874bff34e3Sthurlow int
md_get_uint16be(struct mdchain * mdp,u_int16_t * x)7884bff34e3Sthurlow md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
7894bff34e3Sthurlow 	u_int16_t v;
790613a2f6bSGordon Ross 	int error;
7914bff34e3Sthurlow 
792613a2f6bSGordon Ross 	MD_GET_INLINE(mdp, &v, sizeof (v));
7934bff34e3Sthurlow 	if (x)
7944bff34e3Sthurlow 		*x = betohs(v);
7954bff34e3Sthurlow 	return (error);
7964bff34e3Sthurlow }
7974bff34e3Sthurlow 
7984bff34e3Sthurlow int
md_get_uint16le(struct mdchain * mdp,u_int16_t * x)799613a2f6bSGordon Ross md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
8004bff34e3Sthurlow {
801613a2f6bSGordon Ross 	u_int16_t v;
802613a2f6bSGordon Ross 	int error;
803613a2f6bSGordon Ross 
804613a2f6bSGordon Ross 	MD_GET_INLINE(mdp, &v, sizeof (v));
805613a2f6bSGordon Ross 	if (x)
806613a2f6bSGordon Ross 		*x = letohs(v);
807613a2f6bSGordon Ross 	return (error);
8084bff34e3Sthurlow }
8094bff34e3Sthurlow 
8104bff34e3Sthurlow int
md_get_uint32be(struct mdchain * mdp,u_int32_t * x)8114bff34e3Sthurlow md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
8124bff34e3Sthurlow {
8134bff34e3Sthurlow 	u_int32_t v;
8144bff34e3Sthurlow 	int error;
8154bff34e3Sthurlow 
816613a2f6bSGordon Ross 	MD_GET_INLINE(mdp, &v, sizeof (v));
8174bff34e3Sthurlow 	if (x)
8184bff34e3Sthurlow 		*x = betohl(v);
8194bff34e3Sthurlow 	return (error);
8204bff34e3Sthurlow }
8214bff34e3Sthurlow 
8224bff34e3Sthurlow int
md_get_uint32le(struct mdchain * mdp,u_int32_t * x)8234bff34e3Sthurlow md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
8244bff34e3Sthurlow {
8254bff34e3Sthurlow 	u_int32_t v;
8264bff34e3Sthurlow 	int error;
8274bff34e3Sthurlow 
828613a2f6bSGordon Ross 	MD_GET_INLINE(mdp, &v, sizeof (v));
8294bff34e3Sthurlow 	if (x)
8304bff34e3Sthurlow 		*x = letohl(v);
8314bff34e3Sthurlow 	return (error);
8324bff34e3Sthurlow }
8334bff34e3Sthurlow 
8344bff34e3Sthurlow int
md_get_uint64be(struct mdchain * mdp,u_int64_t * x)8354bff34e3Sthurlow md_get_uint64be(struct mdchain *mdp, u_int64_t *x)
8364bff34e3Sthurlow {
8374bff34e3Sthurlow 	u_int64_t v;
8384bff34e3Sthurlow 	int error;
8394bff34e3Sthurlow 
840613a2f6bSGordon Ross 	MD_GET_INLINE(mdp, &v, sizeof (v));
8414bff34e3Sthurlow 	if (x)
8424bff34e3Sthurlow 		*x = betohq(v);
8434bff34e3Sthurlow 	return (error);
8444bff34e3Sthurlow }
8454bff34e3Sthurlow 
8464bff34e3Sthurlow int
md_get_uint64le(struct mdchain * mdp,u_int64_t * x)8474bff34e3Sthurlow md_get_uint64le(struct mdchain *mdp, u_int64_t *x)
8484bff34e3Sthurlow {
8494bff34e3Sthurlow 	u_int64_t v;
8504bff34e3Sthurlow 	int error;
8514bff34e3Sthurlow 
852613a2f6bSGordon Ross 	MD_GET_INLINE(mdp, &v, sizeof (v));
8534bff34e3Sthurlow 	if (x)
8544bff34e3Sthurlow 		*x = letohq(v);
8554bff34e3Sthurlow 	return (error);
8564bff34e3Sthurlow }
8574bff34e3Sthurlow 
8584bff34e3Sthurlow int
md_get_mem(struct mdchain * mdp,void * vdst,int size,int type)859613a2f6bSGordon Ross md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
8604bff34e3Sthurlow {
8614bff34e3Sthurlow 	mblk_t *m = mdp->md_cur;
862613a2f6bSGordon Ross 	caddr_t target = vdst;
8634bff34e3Sthurlow 	unsigned char *s;
8644bff34e3Sthurlow 	uint64_t diff;
865613a2f6bSGordon Ross 	int count;
8664bff34e3Sthurlow 
8674bff34e3Sthurlow 	while (size > 0) {
8684bff34e3Sthurlow 		if (m == NULL) {
8694bff34e3Sthurlow 			SMBSDEBUG("incomplete copy\n");
8704bff34e3Sthurlow 			return (EBADRPC);
8714bff34e3Sthurlow 		}
8724bff34e3Sthurlow 
8734bff34e3Sthurlow 		/*
8744bff34e3Sthurlow 		 * Offset in the current MBUF.
8754bff34e3Sthurlow 		 */
8764bff34e3Sthurlow 		s = mdp->md_pos;
8774bff34e3Sthurlow 		ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
8784bff34e3Sthurlow 
8794bff34e3Sthurlow 		/* Data remaining. */
8804bff34e3Sthurlow 		diff = (uintptr_t)m->b_wptr - (uintptr_t)s;
8814bff34e3Sthurlow 		ASSERT(diff == (uint64_t)((int)diff));
8824bff34e3Sthurlow 		count = (int)diff;
8834bff34e3Sthurlow 
8844bff34e3Sthurlow 		/*
8854bff34e3Sthurlow 		 * Check if the no. of bytes remaining is less than
8864bff34e3Sthurlow 		 * the bytes requested.
8874bff34e3Sthurlow 		 */
8884bff34e3Sthurlow 		if (count == 0) {
8894bff34e3Sthurlow 			m = m->b_cont;
8904bff34e3Sthurlow 			if (m) {
8914bff34e3Sthurlow 				mdp->md_cur = m;
8924bff34e3Sthurlow 				mdp->md_pos = s = m->b_rptr;
8934bff34e3Sthurlow 			}
8944bff34e3Sthurlow 			continue;
8954bff34e3Sthurlow 		}
8964bff34e3Sthurlow 		if (count > size)
8974bff34e3Sthurlow 			count = size;
8984bff34e3Sthurlow 		size -= count;
8994bff34e3Sthurlow 		mdp->md_pos += count;
9004bff34e3Sthurlow 		if (target == NULL)
9014bff34e3Sthurlow 			continue;
9024bff34e3Sthurlow 		switch (type) {
9034bff34e3Sthurlow 		case MB_MUSER:
904613a2f6bSGordon Ross 			if (copyout(s, target, count))
905613a2f6bSGordon Ross 				return (EFAULT);
9064bff34e3Sthurlow 			break;
9074bff34e3Sthurlow 		case MB_MSYSTEM:
9084bff34e3Sthurlow 			bcopy(s, target, count);
9094bff34e3Sthurlow 			break;
9104bff34e3Sthurlow 		case MB_MINLINE:
9114bff34e3Sthurlow 			while (count--)
9124bff34e3Sthurlow 				*target++ = *s++;
9134bff34e3Sthurlow 			continue;
9144bff34e3Sthurlow 		}
9154bff34e3Sthurlow 		target += count;
9164bff34e3Sthurlow 	}
9174bff34e3Sthurlow 	return (0);
9184bff34e3Sthurlow }
9194bff34e3Sthurlow 
9204bff34e3Sthurlow /*
9214bff34e3Sthurlow  * Get the next SIZE bytes as a separate mblk.
922*adee6784SGordon Ross  * Advances position in mdp by SIZE.
9234bff34e3Sthurlow  */
9244bff34e3Sthurlow int
md_get_mbuf(struct mdchain * mdp,int size,mblk_t ** ret)9254bff34e3Sthurlow md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
9264bff34e3Sthurlow {
9274bff34e3Sthurlow 	mblk_t *m, *rm;
9284bff34e3Sthurlow 
9294bff34e3Sthurlow 	unsigned char *s;
9304bff34e3Sthurlow 	uint64_t diff;
9314bff34e3Sthurlow 	int off;
9324bff34e3Sthurlow 
9334bff34e3Sthurlow 	/*
9344bff34e3Sthurlow 	 * Offset in the current MBUF.
9354bff34e3Sthurlow 	 */
9364bff34e3Sthurlow 	m = mdp->md_cur;
9374bff34e3Sthurlow 	s = mdp->md_pos;
9384bff34e3Sthurlow 	ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
9394bff34e3Sthurlow 	diff = (uintptr_t)s - (uintptr_t)m->b_rptr;
9404bff34e3Sthurlow 	ASSERT(diff == (uint64_t)((int)diff));
9414bff34e3Sthurlow 	off = (int)diff;
9424bff34e3Sthurlow 
9434bff34e3Sthurlow 	rm = m_copym(m, off, size, M_WAITOK);
9444bff34e3Sthurlow 	if (rm == NULL)
9454bff34e3Sthurlow 		return (EBADRPC);
946*adee6784SGordon Ross 	(void) md_get_mem(mdp, NULL, size, MB_MSYSTEM);
9474bff34e3Sthurlow 
9484bff34e3Sthurlow 	*ret = rm;
9494bff34e3Sthurlow 	return (0);
9504bff34e3Sthurlow }
9514bff34e3Sthurlow 
9524bff34e3Sthurlow int
md_get_uio(struct mdchain * mdp,uio_t * uiop,size_t size)953613a2f6bSGordon Ross md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size)
9544bff34e3Sthurlow {
9554bff34e3Sthurlow 	size_t left;
9564bff34e3Sthurlow 	int mtype, error;
9574bff34e3Sthurlow 
9584bff34e3Sthurlow 	mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
9594bff34e3Sthurlow 	while (size > 0 && uiop->uio_resid) {
9604bff34e3Sthurlow 		if (uiop->uio_iovcnt <= 0 ||
9614bff34e3Sthurlow 		    uio_curriovbase(uiop) == USER_ADDR_NULL)
9624bff34e3Sthurlow 			return (EFBIG);
9634bff34e3Sthurlow 		left = uio_curriovlen(uiop);
9644bff34e3Sthurlow 		if (left > size)
9654bff34e3Sthurlow 			left = size;
9664bff34e3Sthurlow 		error = md_get_mem(mdp, CAST_DOWN(caddr_t,
9674bff34e3Sthurlow 		    uio_curriovbase(uiop)), left, mtype);
9684bff34e3Sthurlow 		if (error)
9694bff34e3Sthurlow 			return (error);
9704bff34e3Sthurlow 		uio_update(uiop, left);
9714bff34e3Sthurlow 		size -= left;
9724bff34e3Sthurlow 	}
9734bff34e3Sthurlow 	return (0);
9744bff34e3Sthurlow }
9754bff34e3Sthurlow 
9764bff34e3Sthurlow /*
9774bff34e3Sthurlow  * Additions for Solaris
9784bff34e3Sthurlow  */
9794bff34e3Sthurlow 
9804bff34e3Sthurlow /*
9814bff34e3Sthurlow  * concatenate mblk chain n to m.
9824bff34e3Sthurlow  * go till end of data in m.
9834bff34e3Sthurlow  * then add the link of b_cont to n.
9844bff34e3Sthurlow  * See: linkb(9f)
9854bff34e3Sthurlow  */
9864bff34e3Sthurlow 
m_cat(mblk_t * m,mblk_t * n)9874bff34e3Sthurlow void m_cat(
9884bff34e3Sthurlow 	mblk_t *m,
9894bff34e3Sthurlow 	mblk_t *n)
9904bff34e3Sthurlow {
9914bff34e3Sthurlow 	if (!n)
9924bff34e3Sthurlow 		return;
9934bff34e3Sthurlow 	while (m->b_cont) {
9944bff34e3Sthurlow 		m = m->b_cont;
9954bff34e3Sthurlow 	}
9964bff34e3Sthurlow 	m->b_cont = n;
9974bff34e3Sthurlow }
9984bff34e3Sthurlow 
9994bff34e3Sthurlow /*ARGSUSED*/
10004bff34e3Sthurlow mblk_t *
m_copym(mblk_t * m,int off,int len,int wait)10014bff34e3Sthurlow m_copym(mblk_t *m, int off, int len, int wait)
10024bff34e3Sthurlow {
10034bff34e3Sthurlow 	mblk_t *n;
10044bff34e3Sthurlow 	size_t dsz;
10054bff34e3Sthurlow 	ssize_t adj;
10064bff34e3Sthurlow 
10074bff34e3Sthurlow 	dsz = msgdsize(m);
10084bff34e3Sthurlow 	if (len == M_COPYALL) {
10094bff34e3Sthurlow 		if (off > dsz)
10104bff34e3Sthurlow 			return (0);
10114bff34e3Sthurlow 	} else {
10124bff34e3Sthurlow 		if ((off + len) > dsz)
10134bff34e3Sthurlow 			return (0);
10144bff34e3Sthurlow 	}
10154bff34e3Sthurlow 
10164bff34e3Sthurlow 	if ((n = dupmsg(m)) == NULL)
10174bff34e3Sthurlow 		return (0);
10184bff34e3Sthurlow 
10194bff34e3Sthurlow 	/* trim from head */
10204bff34e3Sthurlow 	adj = off;
10214bff34e3Sthurlow 	if (!adjmsg(n, adj)) {
10224bff34e3Sthurlow 		freemsg(n);
10234bff34e3Sthurlow 		return (0);
10244bff34e3Sthurlow 	}
10254bff34e3Sthurlow 
10264bff34e3Sthurlow 	/* trim from tail */
10274bff34e3Sthurlow 	if (len != M_COPYALL) {
10284bff34e3Sthurlow 		dsz = msgdsize(n);
10294bff34e3Sthurlow 		ASSERT(len <= dsz);
10304bff34e3Sthurlow 		if (len < dsz) {
10314bff34e3Sthurlow 			adj = (ssize_t)len - (ssize_t)dsz;
10324bff34e3Sthurlow 			ASSERT(adj < 0);
103302d09e03SGordon Ross 			(void) adjmsg(n, adj);
10344bff34e3Sthurlow 		}
10354bff34e3Sthurlow 	}
10364bff34e3Sthurlow 
10374bff34e3Sthurlow 	return (n);
10384bff34e3Sthurlow }
10394bff34e3Sthurlow 
10404bff34e3Sthurlow /*
10414bff34e3Sthurlow  * Get "rqlen" contiguous bytes into the first mblk of a chain.
10424bff34e3Sthurlow  */
10434bff34e3Sthurlow mblk_t *
m_pullup(mblk_t * m,int rqlen)10444bff34e3Sthurlow m_pullup(
10454bff34e3Sthurlow 	mblk_t *m,
10464bff34e3Sthurlow 	int rqlen)
10474bff34e3Sthurlow {
10484bff34e3Sthurlow 	ptrdiff_t diff;
10494bff34e3Sthurlow 
10504bff34e3Sthurlow 	diff = MBLKL(m);
10514bff34e3Sthurlow 	ASSERT(diff == (ptrdiff_t)((int)diff));
10524bff34e3Sthurlow 	if ((int)diff < rqlen) {
10534bff34e3Sthurlow 		/* This should be rare. */
10544bff34e3Sthurlow 		if (!pullupmsg(m, rqlen)) {
10554bff34e3Sthurlow 			SMBSDEBUG("pullupmsg failed!\n");
10564bff34e3Sthurlow 			freemsg(m);
10574bff34e3Sthurlow 			return (NULL);
10584bff34e3Sthurlow 		}
10594bff34e3Sthurlow 	}
10604bff34e3Sthurlow 	return (m);
10614bff34e3Sthurlow }
10624bff34e3Sthurlow 
10634bff34e3Sthurlow 
10644bff34e3Sthurlow /*
10654bff34e3Sthurlow  * m_split : split the mblk from the offset(len0) to the end.
10664bff34e3Sthurlow  * Partition an mbuf chain in two pieces, returning the tail --
10674bff34e3Sthurlow  * all but the first len0 bytes.  In case of failure, it returns NULL and
10684bff34e3Sthurlow  * attempts to restore the chain to its original state.
10694bff34e3Sthurlow  * Similar to dupmsg() + adjmsg() on Solaris.
10704bff34e3Sthurlow  */
10714bff34e3Sthurlow /*ARGSUSED*/
10724bff34e3Sthurlow mblk_t *
m_split(mblk_t * m0,int len0,int wait)10734bff34e3Sthurlow m_split(
10744bff34e3Sthurlow 	mblk_t *m0,
10754bff34e3Sthurlow 	int len0,
10764bff34e3Sthurlow 	int wait)
10774bff34e3Sthurlow {
10784bff34e3Sthurlow 	mblk_t *m, *n;
10794bff34e3Sthurlow 	int mbl, len = len0;
10804bff34e3Sthurlow 	ptrdiff_t	diff;
10814bff34e3Sthurlow 
10824bff34e3Sthurlow #if 0 /* If life were simple, this would be: */
10834bff34e3Sthurlow 	for (m = m0; m && len > MBLKL(m); m = m->b_cont)
10844bff34e3Sthurlow 		len -= MBLKL(m);
10854bff34e3Sthurlow #else /* but with LP64 and picky lint we have: */
10864bff34e3Sthurlow 	for (m = m0; m; m = m->b_cont) {
10874bff34e3Sthurlow 		diff = MBLKL(m);
10884bff34e3Sthurlow 		ASSERT(diff == (ptrdiff_t)((int)diff));
10894bff34e3Sthurlow 		mbl = (int)diff;
10904bff34e3Sthurlow 		if (len <= mbl)
10914bff34e3Sthurlow 			break;
10924bff34e3Sthurlow 		len -= mbl;
10934bff34e3Sthurlow 	}
10944bff34e3Sthurlow #endif
10954bff34e3Sthurlow 
10964bff34e3Sthurlow 	if (m == 0)
10974bff34e3Sthurlow 		return (0);
10984bff34e3Sthurlow 
10994bff34e3Sthurlow 	/* This is the one to split (dupb, adjust) */
11004bff34e3Sthurlow 	if ((n = dupb(m)) == 0)
11014bff34e3Sthurlow 		return (0);
11024bff34e3Sthurlow 
11034bff34e3Sthurlow 	ASSERT(len <= MBLKL(m));
11044bff34e3Sthurlow 
11054bff34e3Sthurlow 	m->b_wptr = m->b_rptr + len;
11064bff34e3Sthurlow 	n->b_rptr += len;
11074bff34e3Sthurlow 
11084bff34e3Sthurlow 	/* Move any b_cont (tail) to the new head. */
11094bff34e3Sthurlow 	n->b_cont = m->b_cont;
11104bff34e3Sthurlow 	m->b_cont = NULL;
11114bff34e3Sthurlow 
11124bff34e3Sthurlow 	return (n);
11134bff34e3Sthurlow }
1114