xref: /onnv-gate/usr/src/uts/common/fs/smbclnt/netsmb/subr_mchain.c (revision 11332:ed3411181494)
16007Sthurlow /*
26007Sthurlow  * Copyright (c) 2000, 2001 Boris Popov
36007Sthurlow  * All rights reserved.
46007Sthurlow  *
56007Sthurlow  * Redistribution and use in source and binary forms, with or without
66007Sthurlow  * modification, are permitted provided that the following conditions
76007Sthurlow  * are met:
86007Sthurlow  * 1. Redistributions of source code must retain the above copyright
96007Sthurlow  *    notice, this list of conditions and the following disclaimer.
106007Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
116007Sthurlow  *    notice, this list of conditions and the following disclaimer in the
126007Sthurlow  *    documentation and/or other materials provided with the distribution.
136007Sthurlow  * 3. All advertising materials mentioning features or use of this software
146007Sthurlow  *    must display the following acknowledgement:
156007Sthurlow  *    This product includes software developed by Boris Popov.
166007Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
176007Sthurlow  *    may be used to endorse or promote products derived from this software
186007Sthurlow  *    without specific prior written permission.
196007Sthurlow  *
206007Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
216007Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
226007Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
236007Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
246007Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
256007Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
266007Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
276007Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
286007Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
296007Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
306007Sthurlow  * SUCH DAMAGE.
316007Sthurlow  *
326007Sthurlow  * $FreeBSD: src/sys/kern/subr_mchain.c,v 1.1 2001/02/24 15:44:29 bp Exp $
336007Sthurlow  */
3410023SGordon.Ross@Sun.COM 
356007Sthurlow /*
3610023SGordon.Ross@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
376007Sthurlow  * Use is subject to license terms.
386007Sthurlow  */
396007Sthurlow 
406007Sthurlow #include <sys/param.h>
416007Sthurlow #include <sys/systm.h>
426007Sthurlow #include <sys/errno.h>
436007Sthurlow #include <sys/uio.h>
446007Sthurlow #include <sys/types.h>
456007Sthurlow #include <sys/stream.h>
466007Sthurlow #include <sys/strsun.h>
476007Sthurlow #include <sys/strsubr.h>
4810023SGordon.Ross@Sun.COM #include <sys/sunddi.h>
496007Sthurlow #include <sys/cmn_err.h>
506007Sthurlow 
516007Sthurlow #include <netsmb/smb_osdep.h>
526007Sthurlow #include <netsmb/mchain.h>
536007Sthurlow 
546007Sthurlow #include <netsmb/smb.h>
556007Sthurlow #include <netsmb/smb_conn.h>
566007Sthurlow #include <netsmb/smb_subr.h>
576007Sthurlow 
586007Sthurlow /* BEGIN CSTYLED */
596007Sthurlow /*
606007Sthurlow  * BSD-style mbufs, vs SysV-style mblks:
616007Sthurlow  * One big difference: the mbuf payload is:
626007Sthurlow  *   m_data ... (m_data + m_len)
636007Sthurlow  * In Unix STREAMS, the mblk payload is:
646007Sthurlow  *   b_rptr ... b_wptr
656007Sthurlow  *
666007Sthurlow  * Here are some handy conversion notes:
676007Sthurlow  *
686007Sthurlow  * struct mbuf                     struct mblk
696007Sthurlow  *   m->m_next                       m->b_cont
706007Sthurlow  *   m->m_nextpkt                    m->b_next
716007Sthurlow  *   m->m_data                       m->b_rptr
726007Sthurlow  *   m->m_len                        MBLKL(m)
736007Sthurlow  *   m->m_dat[]                      m->b_datap->db_base
746007Sthurlow  *   &m->m_dat[MLEN]                 m->b_datap->db_lim
756007Sthurlow  *   M_TRAILINGSPACE(m)              MBLKTAIL(m)
766007Sthurlow  *   m_freem(m)                      freemsg(m)
776007Sthurlow  *
786007Sthurlow  * Note that mbufs chains also have a special "packet" header,
796007Sthurlow  * which has the length of the whole message.  In STREAMS one
806007Sthurlow  * typically just calls msgdsize(m) to get that.
816007Sthurlow  */
826007Sthurlow /* END CSTYLED */
836007Sthurlow 
846007Sthurlow 
856007Sthurlow /*
866007Sthurlow  *
876007Sthurlow  * MODULE_VERSION(libmchain, 1);
886007Sthurlow  */
896007Sthurlow 
906007Sthurlow #ifdef __GNUC__
916007Sthurlow #define	MBERROR(format, args...) printf("%s(%d): "format, \
926007Sthurlow 				    __FUNCTION__, __LINE__, ## args)
936007Sthurlow #define	MBPANIC(format, args...) printf("%s(%d): "format, \
946007Sthurlow 				    __FUNCTION__, __LINE__, ## args)
956007Sthurlow #else
966007Sthurlow #define	MBERROR(...) \
976007Sthurlow 	smb_errmsg(CE_NOTE, __func__, __VA_ARGS__)
986007Sthurlow #define	MBPANIC(...) \
996007Sthurlow 	smb_errmsg(CE_PANIC, __func__, __VA_ARGS__)
1006007Sthurlow #endif
1016007Sthurlow 
1026007Sthurlow /*
1036007Sthurlow  * MLEN: The smallest mblk we'll allocate.
1046007Sthurlow  *
1056007Sthurlow  * There's more to MLEN than you might think.
1066007Sthurlow  * Some ethernet drivers may send each mblk as a
1076007Sthurlow  * separate frame, so we want MLEN at least 1K.
1086007Sthurlow  * We could have used 1K here, but that might
1096007Sthurlow  * hurt transports that support larger frames.
1106007Sthurlow  * 4K fits nicely in 3 Ethernet frames (3 * 1500)
1116007Sthurlow  * leaving about 500 bytes for protocol headers.
1126007Sthurlow  *
1136007Sthurlow  * XXX: Would Ethernet drivers be happier
1146007Sthurlow  * (more efficient) if we used 1K here?
1156007Sthurlow  */
1166007Sthurlow #define	MLEN	4096
1176007Sthurlow 
1186007Sthurlow 
1196007Sthurlow /*
1206007Sthurlow  * Some UIO routines.
1216007Sthurlow  * Taken from Darwin Sourcecs.
1226007Sthurlow  */
1236007Sthurlow 
1246007Sthurlow /*
12510023SGordon.Ross@Sun.COM  * uio_isuserspace - non zero value if the address space
1266007Sthurlow  * flag is for a user address space (could be 32 or 64 bit).
1276007Sthurlow  */
12810023SGordon.Ross@Sun.COM #define	uio_isuserspace(uio) (uio->uio_segflg == UIO_USERSPACE)
1296007Sthurlow 
1306007Sthurlow /*
1316007Sthurlow  * uio_curriovbase - return the base address of the current iovec associated
1326007Sthurlow  *      with the given uio_t.  May return 0.
1336007Sthurlow  */
1346007Sthurlow caddr_t
uio_curriovbase(uio_t * a_uio)1356007Sthurlow uio_curriovbase(uio_t *a_uio)
1366007Sthurlow {
1376007Sthurlow 	if (a_uio->uio_iovcnt < 1) {
1386007Sthurlow 		return (0);
1396007Sthurlow 	}
1406007Sthurlow 	return ((caddr_t)((uintptr_t)a_uio->uio_iov->iov_base));
1416007Sthurlow }
1426007Sthurlow 
1436007Sthurlow /*
1446007Sthurlow  * uio_curriovlen - return the length value of the current iovec associated
1456007Sthurlow  *      with the given uio_t.
1466007Sthurlow  */
1476007Sthurlow size_t
uio_curriovlen(uio_t * a_uio)1486007Sthurlow uio_curriovlen(uio_t *a_uio)
1496007Sthurlow {
1506007Sthurlow 	if (a_uio->uio_iovcnt < 1) {
1516007Sthurlow 		return (0);
1526007Sthurlow 	}
1536007Sthurlow 	return ((size_t)a_uio->uio_iov->iov_len);
1546007Sthurlow }
1556007Sthurlow 
1566007Sthurlow 
1576007Sthurlow /*
1586007Sthurlow  * uio_update - update the given uio_t for a_count of completed IO.
1596007Sthurlow  *      This call decrements the current iovec length and residual IO value
1606007Sthurlow  *      and increments the current iovec base address and offset value.
1616007Sthurlow  *      If the current iovec length is 0 then advance to the next
1626007Sthurlow  *      iovec (if any).
1636007Sthurlow  *      If the a_count passed in is 0, than only do the advancement
1646007Sthurlow  *      over any 0 length iovec's.
1656007Sthurlow  */
1666007Sthurlow void
uio_update(uio_t * a_uio,size_t a_count)1676007Sthurlow uio_update(uio_t *a_uio, size_t a_count)
1686007Sthurlow {
1696007Sthurlow 	if (a_uio->uio_iovcnt < 1) {
1706007Sthurlow 		return;
1716007Sthurlow 	}
1726007Sthurlow 
1736007Sthurlow 	/*
1746007Sthurlow 	 * if a_count == 0, then we are asking to skip over
1756007Sthurlow 	 * any empty iovs
1766007Sthurlow 	 */
1776007Sthurlow 	if (a_count) {
1786007Sthurlow 		if (a_count > a_uio->uio_iov->iov_len) {
1796007Sthurlow 			a_uio->uio_iov->iov_base += a_uio->uio_iov->iov_len;
1806007Sthurlow 			a_uio->uio_iov->iov_len = 0;
1816007Sthurlow 		} else {
1826007Sthurlow 			a_uio->uio_iov->iov_base += a_count;
1836007Sthurlow 			a_uio->uio_iov->iov_len -= a_count;
1846007Sthurlow 		}
1856007Sthurlow 		if (a_uio->uio_resid < 0) {
1866007Sthurlow 			a_uio->uio_resid = 0;
1876007Sthurlow 		}
1886007Sthurlow 		if (a_count > (size_t)a_uio->uio_resid) {
18910023SGordon.Ross@Sun.COM 			a_uio->uio_loffset += a_uio->uio_resid;
1906007Sthurlow 			a_uio->uio_resid = 0;
1916007Sthurlow 		} else {
19210023SGordon.Ross@Sun.COM 			a_uio->uio_loffset += a_count;
1936007Sthurlow 			a_uio->uio_resid -= a_count;
1946007Sthurlow 		}
1956007Sthurlow 	}
1966007Sthurlow 	/*
1976007Sthurlow 	 * advance to next iovec if current one is totally consumed
1986007Sthurlow 	 */
1996007Sthurlow 	while (a_uio->uio_iovcnt > 0 && a_uio->uio_iov->iov_len == 0) {
2006007Sthurlow 		a_uio->uio_iovcnt--;
2016007Sthurlow 		if (a_uio->uio_iovcnt > 0) {
2026007Sthurlow 			a_uio->uio_iov++;
2036007Sthurlow 		}
2046007Sthurlow 	}
2056007Sthurlow }
2066007Sthurlow 
20710023SGordon.Ross@Sun.COM /*
20810023SGordon.Ross@Sun.COM  * This is now used only to extend an existing mblk chain,
20910023SGordon.Ross@Sun.COM  * so don't need to use allocb_cred_wait here.
21010023SGordon.Ross@Sun.COM  */
2116007Sthurlow /*ARGSUSED*/
2126007Sthurlow mblk_t *
m_getblk(int size,int type)2136007Sthurlow m_getblk(int size, int type)
2146007Sthurlow {
2156007Sthurlow 	mblk_t *mblk;
2166007Sthurlow 	int error;
2176007Sthurlow 
2186007Sthurlow 	/* Make size at least MLEN. */
2196007Sthurlow 	if (size < MLEN)
2206007Sthurlow 		size = MLEN;
2216007Sthurlow 	mblk = allocb_wait(size, BPRI_LO, STR_NOSIG, &error);
2226007Sthurlow 	ASSERT(mblk);
2236007Sthurlow 	return (mblk);
2246007Sthurlow }
2256007Sthurlow 
2266007Sthurlow void
mb_done(struct mbchain * mbp)2276007Sthurlow mb_done(struct mbchain *mbp)
2286007Sthurlow {
2296007Sthurlow 	if (mbp->mb_top) {
2306007Sthurlow 		freemsg(mbp->mb_top);
2316007Sthurlow 		mbp->mb_top = NULL;
2326007Sthurlow 	}
2336007Sthurlow 	/* Avoid dangling references */
2346007Sthurlow 	mbp->mb_cur = NULL;
2356007Sthurlow }
2366007Sthurlow 
2376007Sthurlow unsigned int
m_length(mblk_t * mblk)2386007Sthurlow m_length(mblk_t *mblk)
2396007Sthurlow {
2406007Sthurlow 	uint64_t diff;
2416007Sthurlow 
2426007Sthurlow 	diff = (uintptr_t)mblk->b_datap->db_lim -
2436007Sthurlow 	    (uintptr_t)mblk->b_datap->db_base;
2446007Sthurlow 	ASSERT(diff == (uint64_t)((unsigned int)diff));
2456007Sthurlow 	return ((unsigned int)diff);
2466007Sthurlow }
2476007Sthurlow 
2486007Sthurlow void
mb_initm(struct mbchain * mbp,mblk_t * m)2496007Sthurlow mb_initm(struct mbchain *mbp, mblk_t *m)
2506007Sthurlow {
2516007Sthurlow 	bzero(mbp, sizeof (*mbp));
2526007Sthurlow 	mbp->mb_top = mbp->mb_cur = m;
2536007Sthurlow }
2546007Sthurlow 
2556007Sthurlow 
2566007Sthurlow int
mb_init(struct mbchain * mbp)2576007Sthurlow mb_init(struct mbchain *mbp)
2586007Sthurlow {
25910023SGordon.Ross@Sun.COM 	cred_t *cr;
2606007Sthurlow 	mblk_t *mblk;
26110023SGordon.Ross@Sun.COM 	int error;
2626007Sthurlow 
26310023SGordon.Ross@Sun.COM 	/*
26410023SGordon.Ross@Sun.COM 	 * This message will be the head of a new mblk chain,
26510023SGordon.Ross@Sun.COM 	 * so we'd like its db_credp set.  If we extend this
26610023SGordon.Ross@Sun.COM 	 * chain later, we'll just use allocb_wait()
26710023SGordon.Ross@Sun.COM 	 */
26810023SGordon.Ross@Sun.COM 	cr = ddi_get_cred();
26910023SGordon.Ross@Sun.COM 	mblk = allocb_cred_wait(MLEN, STR_NOSIG, &error, cr, NOPID);
2706007Sthurlow 
2716007Sthurlow 	/*
2726007Sthurlow 	 * Leave room in this first mblk so we can
2736007Sthurlow 	 * prepend a 4-byte NetBIOS header.
2746007Sthurlow 	 * See smb_nbst_send()
2756007Sthurlow 	 */
2766007Sthurlow 	mblk->b_wptr += 4;
2776007Sthurlow 	mblk->b_rptr = mblk->b_wptr;
2786007Sthurlow 
2796007Sthurlow 	mb_initm(mbp, mblk);
2806007Sthurlow 	return (0);
2816007Sthurlow }
2826007Sthurlow 
2836007Sthurlow 
2846007Sthurlow /*
2856007Sthurlow  * mb_detach() function returns the value of mbp->mb_top field
2866007Sthurlow  * and sets its * value to NULL.
2876007Sthurlow  */
2886007Sthurlow 
2896007Sthurlow mblk_t *
mb_detach(struct mbchain * mbp)2906007Sthurlow mb_detach(struct mbchain *mbp)
2916007Sthurlow {
2926007Sthurlow 	mblk_t *m;
2936007Sthurlow 
2946007Sthurlow 	m = mbp->mb_top;
2956007Sthurlow 	mbp->mb_top = mbp->mb_cur = NULL;
2966007Sthurlow 	return (m);
2976007Sthurlow }
2986007Sthurlow 
2996007Sthurlow /*
3006007Sthurlow  * Returns the length of the mblk_t data.
30110023SGordon.Ross@Sun.COM  * Should be m_totlen() perhaps?
3026007Sthurlow  */
3036007Sthurlow int
m_fixhdr(mblk_t * m0)3046007Sthurlow m_fixhdr(mblk_t *m0)
3056007Sthurlow {
3066007Sthurlow 	size_t dsz;
3076007Sthurlow 
3086007Sthurlow 	dsz = msgdsize(m0);
3096007Sthurlow 	return ((int)dsz);
3106007Sthurlow }
3116007Sthurlow 
3126007Sthurlow /*
3136007Sthurlow  * BSD code set the message header length here, and
3146007Sthurlow  * returned the length.  We don't have that field, so
3156007Sthurlow  * just return the message length.
3166007Sthurlow  */
3176007Sthurlow int
mb_fixhdr(struct mbchain * mbp)3186007Sthurlow mb_fixhdr(struct mbchain *mbp)
3196007Sthurlow {
3206007Sthurlow 	return (m_fixhdr(mbp->mb_top));
3216007Sthurlow }
3226007Sthurlow 
3236007Sthurlow 
3246007Sthurlow /*
3256007Sthurlow  * Check if object of size 'size' fit to the current position and
3266007Sthurlow  * allocate new mbuf if not. Advance pointers and increase len. of mbuf(s).
3276007Sthurlow  * Return pointer to the object placeholder or NULL if any error occured.
3286007Sthurlow  * Note: size should be <= MLEN
3296007Sthurlow  */
3306007Sthurlow void *
mb_reserve(struct mbchain * mbp,int size)3316007Sthurlow mb_reserve(struct mbchain *mbp, int size)
3326007Sthurlow {
3336007Sthurlow 	mblk_t *m, *mn;
3346007Sthurlow 	void *bpos;
3356007Sthurlow 
3366007Sthurlow 	m = mbp->mb_cur;
3376007Sthurlow 	/*
3386007Sthurlow 	 * If the requested size is more than the space left.
3396007Sthurlow 	 * Allocate and appenad a new mblk.
3406007Sthurlow 	 */
3416007Sthurlow 	if (MBLKTAIL(m) < size) {
3426007Sthurlow 		mn = m_getblk(size, 1);
3436007Sthurlow 		if (mn == NULL)
3446007Sthurlow 			return (NULL);
3456007Sthurlow 		mbp->mb_cur = m->b_cont = mn;
3466007Sthurlow 		m = mn;
3476007Sthurlow 	}
3486007Sthurlow 	/*
3496007Sthurlow 	 * If 'size' bytes fits into the buffer, then
3506007Sthurlow 	 * 1. increment the write pointer to the size.
3516007Sthurlow 	 * 2. return the position from where the memory is reserved.
3526007Sthurlow 	 */
3536007Sthurlow 	bpos = m->b_wptr;
3546007Sthurlow 	m->b_wptr += size;
3556007Sthurlow 	mbp->mb_count += size;
3566007Sthurlow 	return (bpos);
3576007Sthurlow }
3586007Sthurlow 
3596007Sthurlow /*
3606007Sthurlow  * All mb_put_*() functions perform an actual copy of the data into mbuf
3616007Sthurlow  * chain. Functions which have le or be suffixes will perform conversion to
3626007Sthurlow  * the little- or big-endian data formats.
36310023SGordon.Ross@Sun.COM  *
36410023SGordon.Ross@Sun.COM  * Inline version of mb_put_mem().  Handles the easy case in-line,
36510023SGordon.Ross@Sun.COM  * and calls mb_put_mem() if crossing mblk boundaries, etc.
36610023SGordon.Ross@Sun.COM  *
36710023SGordon.Ross@Sun.COM  * We build with -xspace, which causes these inline functions
36810023SGordon.Ross@Sun.COM  * to not be inlined.  Using macros instead for now.
36910023SGordon.Ross@Sun.COM  */
37010023SGordon.Ross@Sun.COM #ifdef	INLINE_WORKS
37110023SGordon.Ross@Sun.COM 
37210023SGordon.Ross@Sun.COM static inline int
mb_put_inline(struct mbchain * mbp,void * src,int size)37310023SGordon.Ross@Sun.COM mb_put_inline(struct mbchain *mbp, void *src, int size)
37410023SGordon.Ross@Sun.COM {
37510023SGordon.Ross@Sun.COM 	mblk_t *m = mbp->mb_cur;
37610023SGordon.Ross@Sun.COM 
37710023SGordon.Ross@Sun.COM 	if (m != NULL && size <= MBLKTAIL(m)) {
37810023SGordon.Ross@Sun.COM 		uchar_t *p = src;
37910023SGordon.Ross@Sun.COM 		int n = size;
38010023SGordon.Ross@Sun.COM 		while (n--)
38110023SGordon.Ross@Sun.COM 			*(m->b_wptr)++ = *p++;
38210023SGordon.Ross@Sun.COM 		mbp->mb_count += size;
38310023SGordon.Ross@Sun.COM 		return (0);
38410023SGordon.Ross@Sun.COM 	}
38510023SGordon.Ross@Sun.COM 	return (mb_put_mem(mbp, src, size, MB_MINLINE));
38610023SGordon.Ross@Sun.COM }
38710023SGordon.Ross@Sun.COM #define	MB_PUT_INLINE(MBP, SRC, SZ) \
38810023SGordon.Ross@Sun.COM 	return (mb_put_inline(MBP, SRC, SZ))
38910023SGordon.Ross@Sun.COM 
39010023SGordon.Ross@Sun.COM #else /* INLINE_WORKS */
39110023SGordon.Ross@Sun.COM 
39210023SGordon.Ross@Sun.COM #define	MB_PUT_INLINE(MBP, SRC, SZ) \
39310023SGordon.Ross@Sun.COM 	mblk_t *m = MBP->mb_cur; \
39410023SGordon.Ross@Sun.COM 	if (m != NULL && SZ <= MBLKTAIL(m)) { \
39510023SGordon.Ross@Sun.COM 		uchar_t *p = (void *) SRC; \
39610023SGordon.Ross@Sun.COM 		int n = SZ; \
39710023SGordon.Ross@Sun.COM 		while (n--) \
39810023SGordon.Ross@Sun.COM 			*(m->b_wptr)++ = *p++; \
39910023SGordon.Ross@Sun.COM 		MBP->mb_count += SZ; \
40010023SGordon.Ross@Sun.COM 		return (0); \
40110023SGordon.Ross@Sun.COM 	} \
40210023SGordon.Ross@Sun.COM 	return (mb_put_mem(MBP, SRC, SZ, MB_MINLINE))
40310023SGordon.Ross@Sun.COM 
40410023SGordon.Ross@Sun.COM #endif /* INLINE_WORKS */
40510023SGordon.Ross@Sun.COM 
40610023SGordon.Ross@Sun.COM /*
40710023SGordon.Ross@Sun.COM  * Assumes total data length in previous mblks is EVEN.
40810023SGordon.Ross@Sun.COM  * Might need to compute the offset from mb_top instead.
4096007Sthurlow  */
4106007Sthurlow int
mb_put_padbyte(struct mbchain * mbp)4116007Sthurlow mb_put_padbyte(struct mbchain *mbp)
4126007Sthurlow {
41310023SGordon.Ross@Sun.COM 	uintptr_t dst;
41410023SGordon.Ross@Sun.COM 	char v = 0;
4156007Sthurlow 
41610023SGordon.Ross@Sun.COM 	dst = (uintptr_t)mbp->mb_cur->b_wptr;
4176007Sthurlow 	/* only add padding if address is odd */
41810023SGordon.Ross@Sun.COM 	if (dst & 1) {
41910023SGordon.Ross@Sun.COM 		MB_PUT_INLINE(mbp, &v, sizeof (v));
42010023SGordon.Ross@Sun.COM 	}
42110023SGordon.Ross@Sun.COM 
42210023SGordon.Ross@Sun.COM 	return (0);
4236007Sthurlow }
4246007Sthurlow 
4256007Sthurlow int
mb_put_uint8(struct mbchain * mbp,u_int8_t x)4266007Sthurlow mb_put_uint8(struct mbchain *mbp, u_int8_t x)
4276007Sthurlow {
42810023SGordon.Ross@Sun.COM 	u_int8_t v = x;
42910023SGordon.Ross@Sun.COM 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4306007Sthurlow }
4316007Sthurlow 
4326007Sthurlow int
mb_put_uint16be(struct mbchain * mbp,u_int16_t x)4336007Sthurlow mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
4346007Sthurlow {
43510023SGordon.Ross@Sun.COM 	u_int16_t v = htobes(x);
43610023SGordon.Ross@Sun.COM 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4376007Sthurlow }
4386007Sthurlow 
4396007Sthurlow int
mb_put_uint16le(struct mbchain * mbp,u_int16_t x)4406007Sthurlow mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
4416007Sthurlow {
44210023SGordon.Ross@Sun.COM 	u_int16_t v = htoles(x);
44310023SGordon.Ross@Sun.COM 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4446007Sthurlow }
4456007Sthurlow 
4466007Sthurlow int
mb_put_uint32be(struct mbchain * mbp,u_int32_t x)4476007Sthurlow mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
4486007Sthurlow {
44910023SGordon.Ross@Sun.COM 	u_int32_t v = htobel(x);
45010023SGordon.Ross@Sun.COM 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4516007Sthurlow }
4526007Sthurlow 
4536007Sthurlow int
mb_put_uint32le(struct mbchain * mbp,u_int32_t x)4546007Sthurlow mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
4556007Sthurlow {
45610023SGordon.Ross@Sun.COM 	u_int32_t v = htolel(x);
45710023SGordon.Ross@Sun.COM 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4586007Sthurlow }
4596007Sthurlow 
4606007Sthurlow int
mb_put_uint64be(struct mbchain * mbp,u_int64_t x)4616007Sthurlow mb_put_uint64be(struct mbchain *mbp, u_int64_t x)
4626007Sthurlow {
46310023SGordon.Ross@Sun.COM 	u_int64_t v = htobeq(x);
46410023SGordon.Ross@Sun.COM 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4656007Sthurlow }
4666007Sthurlow 
4676007Sthurlow int
mb_put_uint64le(struct mbchain * mbp,u_int64_t x)4686007Sthurlow mb_put_uint64le(struct mbchain *mbp, u_int64_t x)
4696007Sthurlow {
47010023SGordon.Ross@Sun.COM 	u_int64_t v = htoleq(x);
47110023SGordon.Ross@Sun.COM 	MB_PUT_INLINE(mbp, &v, sizeof (v));
4726007Sthurlow }
4736007Sthurlow 
4746007Sthurlow /*
4756007Sthurlow  * mb_put_mem() function copies size bytes of data specified by the source
4766007Sthurlow  * argument to an mbuf chain.  The type argument specifies the method used
4776007Sthurlow  * to perform a copy
4786007Sthurlow  */
4796007Sthurlow int
mb_put_mem(struct mbchain * mbp,const void * vsrc,int size,int type)48010023SGordon.Ross@Sun.COM mb_put_mem(struct mbchain *mbp, const void *vsrc, int size, int type)
4816007Sthurlow {
48210023SGordon.Ross@Sun.COM 	mblk_t *n, *m = mbp->mb_cur;
48310023SGordon.Ross@Sun.COM 	c_caddr_t source = vsrc;
4846007Sthurlow 	c_caddr_t src;
48510023SGordon.Ross@Sun.COM 	caddr_t dst;
4866007Sthurlow 	uint64_t diff;
48710023SGordon.Ross@Sun.COM 	int cplen, mleft, count;
4886007Sthurlow 
4896007Sthurlow 	diff = MBLKTAIL(m);
4906007Sthurlow 	ASSERT(diff == (uint64_t)((int)diff));
4916007Sthurlow 	mleft = (int)diff;
4926007Sthurlow 
4936007Sthurlow 	while (size > 0) {
4946007Sthurlow 		if (mleft == 0) {
4956007Sthurlow 			if (m->b_cont == NULL) {
4966007Sthurlow 				/*
4976007Sthurlow 				 * Changed m_getm() to m_getblk()
4986007Sthurlow 				 * with the requested size, so we
4996007Sthurlow 				 * don't need m_getm() anymore.
5006007Sthurlow 				 */
5016007Sthurlow 				n = m_getblk(size, 1);
5026007Sthurlow 				if (n == NULL)
5036007Sthurlow 					return (ENOBUFS);
5046007Sthurlow 				m->b_cont = n;
5056007Sthurlow 			}
5066007Sthurlow 			m = m->b_cont;
5076007Sthurlow 			diff = MBLKTAIL(m);
5086007Sthurlow 			ASSERT(diff == (uint64_t)((int)diff));
5096007Sthurlow 			mleft = (int)diff;
5106007Sthurlow 			continue;
5116007Sthurlow 		}
5126007Sthurlow 		cplen = mleft > size ? size : mleft;
5136007Sthurlow 		dst = (caddr_t)m->b_wptr;
5146007Sthurlow 		switch (type) {
5156007Sthurlow 		case MB_MINLINE:
5166007Sthurlow 			for (src = source, count = cplen; count; count--)
5176007Sthurlow 				*dst++ = *src++;
5186007Sthurlow 			break;
5196007Sthurlow 		case MB_MSYSTEM:
5206007Sthurlow 			bcopy(source, dst, cplen);
5216007Sthurlow 			break;
5226007Sthurlow 		case MB_MUSER:
52310023SGordon.Ross@Sun.COM 			if (copyin((void *)source, dst, cplen))
52410023SGordon.Ross@Sun.COM 				return (EFAULT);
5256007Sthurlow 			break;
5266007Sthurlow 		case MB_MZERO:
5276007Sthurlow 			bzero(dst, cplen);
5286007Sthurlow 			break;
5296007Sthurlow 		}
5306007Sthurlow 		size -= cplen;
5316007Sthurlow 		source += cplen;
5326007Sthurlow 		mleft -= cplen;
5336007Sthurlow 		m->b_wptr += cplen;
5346007Sthurlow 		mbp->mb_count += cplen;
5356007Sthurlow 	}
5366007Sthurlow 	mbp->mb_cur = m;
5376007Sthurlow 	return (0);
5386007Sthurlow }
5396007Sthurlow 
5406007Sthurlow /*
5416007Sthurlow  * Append an mblk to the chain.
5426007Sthurlow  */
5436007Sthurlow int
mb_put_mbuf(struct mbchain * mbp,mblk_t * m)5446007Sthurlow mb_put_mbuf(struct mbchain *mbp, mblk_t *m)
5456007Sthurlow {
5466007Sthurlow 	mblk_t *mb;
5476007Sthurlow 
5486007Sthurlow 	/* See: linkb(9f) */
5496007Sthurlow 	for (mb = mbp->mb_cur; mb->b_cont; mb = mb->b_cont)
5506007Sthurlow 		;
5516007Sthurlow 	mb->b_cont = m;
5526007Sthurlow 	mbp->mb_cur = m;
5536007Sthurlow 	mbp->mb_count += msgdsize(m);
5546007Sthurlow 
5556007Sthurlow 	return (0);
5566007Sthurlow }
5576007Sthurlow 
5586007Sthurlow /*
5596007Sthurlow  * copies a uio scatter/gather list to an mbuf chain.
5606007Sthurlow  */
5616007Sthurlow int
mb_put_uio(struct mbchain * mbp,uio_t * uiop,size_t size)56210023SGordon.Ross@Sun.COM mb_put_uio(struct mbchain *mbp, uio_t *uiop, size_t size)
5636007Sthurlow {
56410023SGordon.Ross@Sun.COM 	size_t left;
5656007Sthurlow 	int mtype, error;
5666007Sthurlow 
5676007Sthurlow 	mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
5686007Sthurlow 	while (size > 0 && uiop->uio_resid) {
56910023SGordon.Ross@Sun.COM 		if (uiop->uio_iovcnt <= 0 ||
57010023SGordon.Ross@Sun.COM 		    uio_curriovbase(uiop) == USER_ADDR_NULL)
5716007Sthurlow 			return (EFBIG);
5726007Sthurlow 		left = uio_curriovlen(uiop);
5736007Sthurlow 		if (left > size)
5746007Sthurlow 			left = size;
5756007Sthurlow 		error = mb_put_mem(mbp, CAST_DOWN(caddr_t,
5766007Sthurlow 		    uio_curriovbase(uiop)), left, mtype);
5776007Sthurlow 		if (error)
5786007Sthurlow 			return (error);
5796007Sthurlow 		uio_update(uiop, left);
5806007Sthurlow 		size -= left;
5816007Sthurlow 	}
5826007Sthurlow 	return (0);
5836007Sthurlow }
5846007Sthurlow 
5856007Sthurlow /*
5866007Sthurlow  * Routines for fetching data from an mbuf chain
5876007Sthurlow  */
5886007Sthurlow 
5896007Sthurlow void
md_initm(struct mdchain * mdp,mblk_t * m)5906007Sthurlow md_initm(struct mdchain *mdp, mblk_t *m)
5916007Sthurlow {
5926007Sthurlow 	bzero(mdp, sizeof (*mdp));
5936007Sthurlow 	mdp->md_top = mdp->md_cur = m;
5946007Sthurlow 	mdp->md_pos = m->b_rptr;
5956007Sthurlow }
5966007Sthurlow 
5976007Sthurlow void
md_done(struct mdchain * mdp)5986007Sthurlow md_done(struct mdchain *mdp)
5996007Sthurlow {
6006007Sthurlow 	mblk_t *m;
6016007Sthurlow 
6026007Sthurlow 	/*
6036007Sthurlow 	 * Deal with the fact that we can error out of
6046007Sthurlow 	 * smb_t2_reply or smb_nt_reply without using up
6056007Sthurlow 	 * all the "records" added by md_append_record().
6066007Sthurlow 	 */
6076007Sthurlow 	while ((m = mdp->md_top) != NULL) {
6086007Sthurlow 		mdp->md_top = m->b_next;
6096007Sthurlow 		m->b_next = NULL;
6106007Sthurlow 		freemsg(m);
6116007Sthurlow 	}
6126007Sthurlow 	/* Avoid dangling references */
6136007Sthurlow 	mdp->md_cur = NULL;
6146007Sthurlow 	mdp->md_pos = NULL;
6156007Sthurlow }
6166007Sthurlow 
6176007Sthurlow /*
6186007Sthurlow  * Append a new message (separate mbuf chain).
6196007Sthurlow  * It is caller responsibility to prevent
6206007Sthurlow  * multiple calls to fetch/record routines.
621*11332SGordon.Ross@Sun.COM  * Note unusual use of mblk->b_next here.
6226007Sthurlow  */
6236007Sthurlow void
md_append_record(struct mdchain * mdp,mblk_t * top)6246007Sthurlow md_append_record(struct mdchain *mdp, mblk_t *top)
6256007Sthurlow {
6266007Sthurlow 	mblk_t *m;
6276007Sthurlow 
6286007Sthurlow 	top->b_next = NULL;
6296007Sthurlow 	if (mdp->md_top == NULL) {
6306007Sthurlow 		md_initm(mdp, top);
6316007Sthurlow 		return;
6326007Sthurlow 	}
6336007Sthurlow 	m = mdp->md_top;
6346007Sthurlow 	/* Get to last message (not b_cont chain) */
6356007Sthurlow 	while (m->b_next)
6366007Sthurlow 		m = m->b_next;
6376007Sthurlow 	m->b_next = top;
6386007Sthurlow }
6396007Sthurlow 
6406007Sthurlow /*
6416007Sthurlow  * Advance mdp->md_top to the next message.
642*11332SGordon.Ross@Sun.COM  * Note unusual use of mblk->b_next here.
6436007Sthurlow  */
644*11332SGordon.Ross@Sun.COM void
md_next_record(struct mdchain * mdp)6456007Sthurlow md_next_record(struct mdchain *mdp)
6466007Sthurlow {
647*11332SGordon.Ross@Sun.COM 	mblk_t *m, *top;
648*11332SGordon.Ross@Sun.COM 
649*11332SGordon.Ross@Sun.COM 	if ((top = mdp->md_top) == NULL)
650*11332SGordon.Ross@Sun.COM 		return;
6516007Sthurlow 
652*11332SGordon.Ross@Sun.COM 	/*
653*11332SGordon.Ross@Sun.COM 	 * Get the next message, if any,
654*11332SGordon.Ross@Sun.COM 	 * stored by md_append_record.
655*11332SGordon.Ross@Sun.COM 	 * Note: NOT b_cont chain
656*11332SGordon.Ross@Sun.COM 	 */
657*11332SGordon.Ross@Sun.COM 	m = top->b_next;
658*11332SGordon.Ross@Sun.COM 	top->b_next = NULL;
659*11332SGordon.Ross@Sun.COM 
660*11332SGordon.Ross@Sun.COM 	/* Done with old "top". */
6616007Sthurlow 	md_done(mdp);
6626007Sthurlow 	if (m == NULL)
663*11332SGordon.Ross@Sun.COM 		return;
664*11332SGordon.Ross@Sun.COM 
665*11332SGordon.Ross@Sun.COM 	/* Setup new "top". */
6666007Sthurlow 	md_initm(mdp, m);
6676007Sthurlow }
6686007Sthurlow 
66910023SGordon.Ross@Sun.COM /*
67010023SGordon.Ross@Sun.COM  * Inline version of md_get_mem().  Handles the easy case in-line,
67110023SGordon.Ross@Sun.COM  * and calls md_get_mem() if crossing mblk boundaries, etc.
67210023SGordon.Ross@Sun.COM  */
67310023SGordon.Ross@Sun.COM #ifdef	INLINE_WORKS	/* see above */
67410023SGordon.Ross@Sun.COM 
67510023SGordon.Ross@Sun.COM static inline int
md_get_inline(struct mdchain * mdp,void * dst,int size)67610023SGordon.Ross@Sun.COM md_get_inline(struct mdchain *mdp, void *dst, int size)
67710023SGordon.Ross@Sun.COM {
67810023SGordon.Ross@Sun.COM 	mblk_t *m = mdp->md_cur;
67910023SGordon.Ross@Sun.COM 
68010023SGordon.Ross@Sun.COM 	if (m != NULL && mdp->md_pos + size <= m->b_wptr) {
68110023SGordon.Ross@Sun.COM 		uchar_t *p = dst;
68210023SGordon.Ross@Sun.COM 		int n = size;
68310023SGordon.Ross@Sun.COM 		while (n--)
68410023SGordon.Ross@Sun.COM 			*p++ = *(mdp->md_pos)++;
68510023SGordon.Ross@Sun.COM 		/* no md_count += size */
68610023SGordon.Ross@Sun.COM 		return (0);
68710023SGordon.Ross@Sun.COM 	}
68810023SGordon.Ross@Sun.COM 	return (md_get_mem(mdp, dst, size, MB_MINLINE));
68910023SGordon.Ross@Sun.COM }
69010023SGordon.Ross@Sun.COM #define	MD_GET_INLINE(MDP, DST, SZ) \
69110023SGordon.Ross@Sun.COM 	error = md_get_inline(MDP, DST, SZ)
69210023SGordon.Ross@Sun.COM 
69310023SGordon.Ross@Sun.COM #else /* INLINE_WORKS */
69410023SGordon.Ross@Sun.COM 
69510023SGordon.Ross@Sun.COM /* Note, sets variable: error */
69610023SGordon.Ross@Sun.COM #define	MD_GET_INLINE(MDP, DST, SZ) \
69710023SGordon.Ross@Sun.COM 	mblk_t *m = MDP->md_cur; \
69810023SGordon.Ross@Sun.COM 	if (m != NULL && MDP->md_pos + SZ <= m->b_wptr) { \
69910023SGordon.Ross@Sun.COM 		uchar_t *p = (void *) DST; \
70010023SGordon.Ross@Sun.COM 		int n = SZ; \
70110023SGordon.Ross@Sun.COM 		while (n--) \
70210023SGordon.Ross@Sun.COM 			*p++ = *(mdp->md_pos)++; \
70310023SGordon.Ross@Sun.COM 		/* no md_count += SZ */ \
70410023SGordon.Ross@Sun.COM 		error = 0; \
70510023SGordon.Ross@Sun.COM 	} else \
70610023SGordon.Ross@Sun.COM 		error = md_get_mem(MDP, DST, SZ, MB_MINLINE)
70710023SGordon.Ross@Sun.COM 
70810023SGordon.Ross@Sun.COM #endif /* INLINE_WORKS */
70910023SGordon.Ross@Sun.COM 
71010023SGordon.Ross@Sun.COM 
7116007Sthurlow int
md_get_uint8(struct mdchain * mdp,u_int8_t * x)7126007Sthurlow md_get_uint8(struct mdchain *mdp, u_int8_t *x)
7136007Sthurlow {
71410023SGordon.Ross@Sun.COM 	uint8_t v;
71510023SGordon.Ross@Sun.COM 	int error;
71610023SGordon.Ross@Sun.COM 
71710023SGordon.Ross@Sun.COM 	MD_GET_INLINE(mdp, &v, sizeof (v));
71810023SGordon.Ross@Sun.COM 	if (x)
71910023SGordon.Ross@Sun.COM 		*x = v;
72010023SGordon.Ross@Sun.COM 	return (error);
7216007Sthurlow }
7226007Sthurlow 
7236007Sthurlow int
md_get_uint16be(struct mdchain * mdp,u_int16_t * x)72410023SGordon.Ross@Sun.COM md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
72510023SGordon.Ross@Sun.COM 	u_int16_t v;
72610023SGordon.Ross@Sun.COM 	int error;
72710023SGordon.Ross@Sun.COM 
72810023SGordon.Ross@Sun.COM 	MD_GET_INLINE(mdp, &v, sizeof (v));
72910023SGordon.Ross@Sun.COM 	if (x)
73010023SGordon.Ross@Sun.COM 		*x = betohs(v);
73110023SGordon.Ross@Sun.COM 	return (error);
7326007Sthurlow }
7336007Sthurlow 
7346007Sthurlow int
md_get_uint16le(struct mdchain * mdp,u_int16_t * x)7356007Sthurlow md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
7366007Sthurlow {
7376007Sthurlow 	u_int16_t v;
73810023SGordon.Ross@Sun.COM 	int error;
7396007Sthurlow 
74010023SGordon.Ross@Sun.COM 	MD_GET_INLINE(mdp, &v, sizeof (v));
7416007Sthurlow 	if (x)
7426007Sthurlow 		*x = letohs(v);
7436007Sthurlow 	return (error);
7446007Sthurlow }
7456007Sthurlow 
7466007Sthurlow int
md_get_uint32be(struct mdchain * mdp,u_int32_t * x)7476007Sthurlow md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
7486007Sthurlow {
7496007Sthurlow 	u_int32_t v;
7506007Sthurlow 	int error;
7516007Sthurlow 
75210023SGordon.Ross@Sun.COM 	MD_GET_INLINE(mdp, &v, sizeof (v));
7536007Sthurlow 	if (x)
7546007Sthurlow 		*x = betohl(v);
7556007Sthurlow 	return (error);
7566007Sthurlow }
7576007Sthurlow 
7586007Sthurlow int
md_get_uint32le(struct mdchain * mdp,u_int32_t * x)7596007Sthurlow md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
7606007Sthurlow {
7616007Sthurlow 	u_int32_t v;
7626007Sthurlow 	int error;
7636007Sthurlow 
76410023SGordon.Ross@Sun.COM 	MD_GET_INLINE(mdp, &v, sizeof (v));
7656007Sthurlow 	if (x)
7666007Sthurlow 		*x = letohl(v);
7676007Sthurlow 	return (error);
7686007Sthurlow }
7696007Sthurlow 
7706007Sthurlow int
md_get_uint64be(struct mdchain * mdp,u_int64_t * x)7716007Sthurlow md_get_uint64be(struct mdchain *mdp, u_int64_t *x)
7726007Sthurlow {
7736007Sthurlow 	u_int64_t v;
7746007Sthurlow 	int error;
7756007Sthurlow 
77610023SGordon.Ross@Sun.COM 	MD_GET_INLINE(mdp, &v, sizeof (v));
7776007Sthurlow 	if (x)
7786007Sthurlow 		*x = betohq(v);
7796007Sthurlow 	return (error);
7806007Sthurlow }
7816007Sthurlow 
7826007Sthurlow int
md_get_uint64le(struct mdchain * mdp,u_int64_t * x)7836007Sthurlow md_get_uint64le(struct mdchain *mdp, u_int64_t *x)
7846007Sthurlow {
7856007Sthurlow 	u_int64_t v;
7866007Sthurlow 	int error;
7876007Sthurlow 
78810023SGordon.Ross@Sun.COM 	MD_GET_INLINE(mdp, &v, sizeof (v));
7896007Sthurlow 	if (x)
7906007Sthurlow 		*x = letohq(v);
7916007Sthurlow 	return (error);
7926007Sthurlow }
7936007Sthurlow 
7946007Sthurlow int
md_get_mem(struct mdchain * mdp,void * vdst,int size,int type)79510023SGordon.Ross@Sun.COM md_get_mem(struct mdchain *mdp, void *vdst, int size, int type)
7966007Sthurlow {
7976007Sthurlow 	mblk_t *m = mdp->md_cur;
79810023SGordon.Ross@Sun.COM 	caddr_t target = vdst;
7996007Sthurlow 	unsigned char *s;
8006007Sthurlow 	uint64_t diff;
80110023SGordon.Ross@Sun.COM 	int count;
8026007Sthurlow 
8036007Sthurlow 	while (size > 0) {
8046007Sthurlow 		if (m == NULL) {
8056007Sthurlow 			SMBSDEBUG("incomplete copy\n");
8066007Sthurlow 			return (EBADRPC);
8076007Sthurlow 		}
8086007Sthurlow 
8096007Sthurlow 		/*
8106007Sthurlow 		 * Offset in the current MBUF.
8116007Sthurlow 		 */
8126007Sthurlow 		s = mdp->md_pos;
8136007Sthurlow 		ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
8146007Sthurlow 
8156007Sthurlow 		/* Data remaining. */
8166007Sthurlow 		diff = (uintptr_t)m->b_wptr - (uintptr_t)s;
8176007Sthurlow 		ASSERT(diff == (uint64_t)((int)diff));
8186007Sthurlow 		count = (int)diff;
8196007Sthurlow 
8206007Sthurlow 		/*
8216007Sthurlow 		 * Check if the no. of bytes remaining is less than
8226007Sthurlow 		 * the bytes requested.
8236007Sthurlow 		 */
8246007Sthurlow 		if (count == 0) {
8256007Sthurlow 			m = m->b_cont;
8266007Sthurlow 			if (m) {
8276007Sthurlow 				mdp->md_cur = m;
8286007Sthurlow 				mdp->md_pos = s = m->b_rptr;
8296007Sthurlow 			}
8306007Sthurlow 			continue;
8316007Sthurlow 		}
8326007Sthurlow 		if (count > size)
8336007Sthurlow 			count = size;
8346007Sthurlow 		size -= count;
8356007Sthurlow 		mdp->md_pos += count;
8366007Sthurlow 		if (target == NULL)
8376007Sthurlow 			continue;
8386007Sthurlow 		switch (type) {
8396007Sthurlow 		case MB_MUSER:
84010023SGordon.Ross@Sun.COM 			if (copyout(s, target, count))
84110023SGordon.Ross@Sun.COM 				return (EFAULT);
8426007Sthurlow 			break;
8436007Sthurlow 		case MB_MSYSTEM:
8446007Sthurlow 			bcopy(s, target, count);
8456007Sthurlow 			break;
8466007Sthurlow 		case MB_MINLINE:
8476007Sthurlow 			while (count--)
8486007Sthurlow 				*target++ = *s++;
8496007Sthurlow 			continue;
8506007Sthurlow 		}
8516007Sthurlow 		target += count;
8526007Sthurlow 	}
8536007Sthurlow 	return (0);
8546007Sthurlow }
8556007Sthurlow 
8566007Sthurlow /*
8576007Sthurlow  * Get the next SIZE bytes as a separate mblk.
8586007Sthurlow  */
8596007Sthurlow int
md_get_mbuf(struct mdchain * mdp,int size,mblk_t ** ret)8606007Sthurlow md_get_mbuf(struct mdchain *mdp, int size, mblk_t **ret)
8616007Sthurlow {
8626007Sthurlow 	mblk_t *m, *rm;
8636007Sthurlow 
8646007Sthurlow 	unsigned char *s;
8656007Sthurlow 	uint64_t diff;
8666007Sthurlow 	int off;
8676007Sthurlow 
8686007Sthurlow 	/*
8696007Sthurlow 	 * Offset in the current MBUF.
8706007Sthurlow 	 */
8716007Sthurlow 	m = mdp->md_cur;
8726007Sthurlow 	s = mdp->md_pos;
8736007Sthurlow 	ASSERT((m->b_rptr <= s) && (s <= m->b_wptr));
8746007Sthurlow 	diff = (uintptr_t)s - (uintptr_t)m->b_rptr;
8756007Sthurlow 	ASSERT(diff == (uint64_t)((int)diff));
8766007Sthurlow 	off = (int)diff;
8776007Sthurlow 
8786007Sthurlow 	rm = m_copym(m, off, size, M_WAITOK);
8796007Sthurlow 	if (rm == NULL)
8806007Sthurlow 		return (EBADRPC);
8816007Sthurlow 
8826007Sthurlow 	*ret = rm;
8836007Sthurlow 	return (0);
8846007Sthurlow }
8856007Sthurlow 
8866007Sthurlow int
md_get_uio(struct mdchain * mdp,uio_t * uiop,size_t size)88710023SGordon.Ross@Sun.COM md_get_uio(struct mdchain *mdp, uio_t *uiop, size_t size)
8886007Sthurlow {
8896007Sthurlow 	size_t left;
8906007Sthurlow 	int mtype, error;
8916007Sthurlow 
8926007Sthurlow 	mtype = (uio_isuserspace(uiop) ? MB_MUSER : MB_MSYSTEM);
8936007Sthurlow 	while (size > 0 && uiop->uio_resid) {
8946007Sthurlow 		if (uiop->uio_iovcnt <= 0 ||
8956007Sthurlow 		    uio_curriovbase(uiop) == USER_ADDR_NULL)
8966007Sthurlow 			return (EFBIG);
8976007Sthurlow 		left = uio_curriovlen(uiop);
8986007Sthurlow 		if (left > size)
8996007Sthurlow 			left = size;
9006007Sthurlow 		error = md_get_mem(mdp, CAST_DOWN(caddr_t,
9016007Sthurlow 		    uio_curriovbase(uiop)), left, mtype);
9026007Sthurlow 		if (error)
9036007Sthurlow 			return (error);
9046007Sthurlow 		uio_update(uiop, left);
9056007Sthurlow 		size -= left;
9066007Sthurlow 	}
9076007Sthurlow 	return (0);
9086007Sthurlow }
9096007Sthurlow 
9106007Sthurlow /*
9116007Sthurlow  * Additions for Solaris
9126007Sthurlow  */
9136007Sthurlow 
9146007Sthurlow /*
9156007Sthurlow  * concatenate mblk chain n to m.
9166007Sthurlow  * go till end of data in m.
9176007Sthurlow  * then add the link of b_cont to n.
9186007Sthurlow  * See: linkb(9f)
9196007Sthurlow  */
9206007Sthurlow 
m_cat(mblk_t * m,mblk_t * n)9216007Sthurlow void m_cat(
9226007Sthurlow 	mblk_t *m,
9236007Sthurlow 	mblk_t *n)
9246007Sthurlow {
9256007Sthurlow 	if (!n)
9266007Sthurlow 		return;
9276007Sthurlow 	while (m->b_cont) {
9286007Sthurlow 		m = m->b_cont;
9296007Sthurlow 	}
9306007Sthurlow 	m->b_cont = n;
9316007Sthurlow }
9326007Sthurlow 
9336007Sthurlow /*ARGSUSED*/
9346007Sthurlow mblk_t *
m_copym(mblk_t * m,int off,int len,int wait)9356007Sthurlow m_copym(mblk_t *m, int off, int len, int wait)
9366007Sthurlow {
9376007Sthurlow 	mblk_t *n;
9386007Sthurlow 	size_t dsz;
9396007Sthurlow 	ssize_t adj;
9406007Sthurlow 
9416007Sthurlow 	dsz = msgdsize(m);
9426007Sthurlow 	if (len == M_COPYALL) {
9436007Sthurlow 		if (off > dsz)
9446007Sthurlow 			return (0);
9456007Sthurlow 	} else {
9466007Sthurlow 		if ((off + len) > dsz)
9476007Sthurlow 			return (0);
9486007Sthurlow 	}
9496007Sthurlow 
9506007Sthurlow 	if ((n = dupmsg(m)) == NULL)
9516007Sthurlow 		return (0);
9526007Sthurlow 
9536007Sthurlow 	/* trim from head */
9546007Sthurlow 	adj = off;
9556007Sthurlow 	if (!adjmsg(n, adj)) {
9566007Sthurlow 		freemsg(n);
9576007Sthurlow 		return (0);
9586007Sthurlow 	}
9596007Sthurlow 
9606007Sthurlow 	/* trim from tail */
9616007Sthurlow 	if (len != M_COPYALL) {
9626007Sthurlow 		dsz = msgdsize(n);
9636007Sthurlow 		ASSERT(len <= dsz);
9646007Sthurlow 		if (len < dsz) {
9656007Sthurlow 			adj = (ssize_t)len - (ssize_t)dsz;
9666007Sthurlow 			ASSERT(adj < 0);
967*11332SGordon.Ross@Sun.COM 			(void) adjmsg(n, adj);
9686007Sthurlow 		}
9696007Sthurlow 	}
9706007Sthurlow 
9716007Sthurlow 	return (n);
9726007Sthurlow }
9736007Sthurlow 
9746007Sthurlow /*
9756007Sthurlow  * Get "rqlen" contiguous bytes into the first mblk of a chain.
9766007Sthurlow  */
9776007Sthurlow mblk_t *
m_pullup(mblk_t * m,int rqlen)9786007Sthurlow m_pullup(
9796007Sthurlow 	mblk_t *m,
9806007Sthurlow 	int rqlen)
9816007Sthurlow {
9826007Sthurlow 	ptrdiff_t diff;
9836007Sthurlow 
9846007Sthurlow 	diff = MBLKL(m);
9856007Sthurlow 	ASSERT(diff == (ptrdiff_t)((int)diff));
9866007Sthurlow 	if ((int)diff < rqlen) {
9876007Sthurlow 		/* This should be rare. */
9886007Sthurlow 		if (!pullupmsg(m, rqlen)) {
9896007Sthurlow 			SMBSDEBUG("pullupmsg failed!\n");
9906007Sthurlow 			freemsg(m);
9916007Sthurlow 			return (NULL);
9926007Sthurlow 		}
9936007Sthurlow 	}
9946007Sthurlow 	return (m);
9956007Sthurlow }
9966007Sthurlow 
9976007Sthurlow 
9986007Sthurlow /*
9996007Sthurlow  * m_split : split the mblk from the offset(len0) to the end.
10006007Sthurlow  * Partition an mbuf chain in two pieces, returning the tail --
10016007Sthurlow  * all but the first len0 bytes.  In case of failure, it returns NULL and
10026007Sthurlow  * attempts to restore the chain to its original state.
10036007Sthurlow  * Similar to dupmsg() + adjmsg() on Solaris.
10046007Sthurlow  */
10056007Sthurlow /*ARGSUSED*/
10066007Sthurlow mblk_t *
m_split(mblk_t * m0,int len0,int wait)10076007Sthurlow m_split(
10086007Sthurlow 	mblk_t *m0,
10096007Sthurlow 	int len0,
10106007Sthurlow 	int wait)
10116007Sthurlow {
10126007Sthurlow 	mblk_t *m, *n;
10136007Sthurlow 	int mbl, len = len0;
10146007Sthurlow 	ptrdiff_t	diff;
10156007Sthurlow 
10166007Sthurlow #if 0 /* If life were simple, this would be: */
10176007Sthurlow 	for (m = m0; m && len > MBLKL(m); m = m->b_cont)
10186007Sthurlow 		len -= MBLKL(m);
10196007Sthurlow #else /* but with LP64 and picky lint we have: */
10206007Sthurlow 	for (m = m0; m; m = m->b_cont) {
10216007Sthurlow 		diff = MBLKL(m);
10226007Sthurlow 		ASSERT(diff == (ptrdiff_t)((int)diff));
10236007Sthurlow 		mbl = (int)diff;
10246007Sthurlow 		if (len <= mbl)
10256007Sthurlow 			break;
10266007Sthurlow 		len -= mbl;
10276007Sthurlow 	}
10286007Sthurlow #endif
10296007Sthurlow 
10306007Sthurlow 	if (m == 0)
10316007Sthurlow 		return (0);
10326007Sthurlow 
10336007Sthurlow 	/* This is the one to split (dupb, adjust) */
10346007Sthurlow 	if ((n = dupb(m)) == 0)
10356007Sthurlow 		return (0);
10366007Sthurlow 
10376007Sthurlow 	ASSERT(len <= MBLKL(m));
10386007Sthurlow 
10396007Sthurlow 	m->b_wptr = m->b_rptr + len;
10406007Sthurlow 	n->b_rptr += len;
10416007Sthurlow 
10426007Sthurlow 	/* Move any b_cont (tail) to the new head. */
10436007Sthurlow 	n->b_cont = m->b_cont;
10446007Sthurlow 	m->b_cont = NULL;
10456007Sthurlow 
10466007Sthurlow 	return (n);
10476007Sthurlow }
1048