xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c (revision 10966:37e5dcdf36d3)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
228934SJose.Borrego@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
235331Samw  * Use is subject to license terms.
245331Samw  */
255331Samw 
265331Samw /*
275331Samw  * Copyright (c) 1982, 1986, 1988, 1991, 1993
285331Samw  *	The Regents of the University of California.  All rights reserved.
295331Samw  *
305331Samw  * Redistribution and use in source and binary forms, with or without
315331Samw  * modification, are permitted provided that the following conditions
325331Samw  * are met:
335331Samw  * 1. Redistributions of source code must retain the above copyright
345331Samw  *    notice, this list of conditions and the following disclaimer.
355331Samw  * 2. Redistributions in binary form must reproduce the above copyright
365331Samw  *    notice, this list of conditions and the following disclaimer in the
375331Samw  *    documentation and/or other materials provided with the distribution.
385331Samw  * 3. All advertising materials mentioning features or use of this software
395331Samw  *    must display the following acknowledgement:
405331Samw  *	This product includes software developed by the University of
415331Samw  *	California, Berkeley and its contributors.
425331Samw  * 4. Neither the name of the University nor the names of its contributors
435331Samw  *    may be used to endorse or promote products derived from this software
445331Samw  *    without specific prior written permission.
455331Samw  *
465331Samw  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
475331Samw  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
485331Samw  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
495331Samw  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
505331Samw  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
515331Samw  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
525331Samw  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
535331Samw  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
545331Samw  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
555331Samw  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
565331Samw  * SUCH DAMAGE.
575331Samw  *
585331Samw  */
595331Samw 
60*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
618934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h>
628934SJose.Borrego@Sun.COM 
638934SJose.Borrego@Sun.COM static kmem_cache_t	*smb_mbc_cache = NULL;
648934SJose.Borrego@Sun.COM 
658934SJose.Borrego@Sun.COM int
smb_mbc_init(void)668934SJose.Borrego@Sun.COM smb_mbc_init(void)
678934SJose.Borrego@Sun.COM {
688934SJose.Borrego@Sun.COM 	if (smb_mbc_cache == NULL) {
698934SJose.Borrego@Sun.COM 		smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
708934SJose.Borrego@Sun.COM 		    sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
718934SJose.Borrego@Sun.COM 	}
728934SJose.Borrego@Sun.COM 	return (0);
738934SJose.Borrego@Sun.COM }
748934SJose.Borrego@Sun.COM 
758934SJose.Borrego@Sun.COM void
smb_mbc_fini(void)768934SJose.Borrego@Sun.COM smb_mbc_fini(void)
778934SJose.Borrego@Sun.COM {
788934SJose.Borrego@Sun.COM 	if (smb_mbc_cache != NULL) {
798934SJose.Borrego@Sun.COM 		kmem_cache_destroy(smb_mbc_cache);
808934SJose.Borrego@Sun.COM 		smb_mbc_cache = NULL;
818934SJose.Borrego@Sun.COM 	}
828934SJose.Borrego@Sun.COM }
838934SJose.Borrego@Sun.COM 
848934SJose.Borrego@Sun.COM mbuf_chain_t *
smb_mbc_alloc(uint32_t max_bytes)858934SJose.Borrego@Sun.COM smb_mbc_alloc(uint32_t max_bytes)
868934SJose.Borrego@Sun.COM {
878934SJose.Borrego@Sun.COM 	mbuf_chain_t	*mbc;
888934SJose.Borrego@Sun.COM 	mbuf_t		*m;
898934SJose.Borrego@Sun.COM 
908934SJose.Borrego@Sun.COM 	mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
918934SJose.Borrego@Sun.COM 	bzero(mbc, sizeof (*mbc));
928934SJose.Borrego@Sun.COM 	mbc->mbc_magic = SMB_MBC_MAGIC;
938934SJose.Borrego@Sun.COM 
948934SJose.Borrego@Sun.COM 	if (max_bytes != 0) {
958934SJose.Borrego@Sun.COM 		MGET(m, M_WAIT, MT_DATA);
968934SJose.Borrego@Sun.COM 		m->m_len = 0;
978934SJose.Borrego@Sun.COM 		mbc->chain = m;
988934SJose.Borrego@Sun.COM 		if (max_bytes > MINCLSIZE)
998934SJose.Borrego@Sun.COM 			MCLGET(m, M_WAIT);
1008934SJose.Borrego@Sun.COM 	}
1018934SJose.Borrego@Sun.COM 	mbc->max_bytes = max_bytes;
1028934SJose.Borrego@Sun.COM 	return (mbc);
1038934SJose.Borrego@Sun.COM }
1048934SJose.Borrego@Sun.COM 
1058934SJose.Borrego@Sun.COM void
smb_mbc_free(mbuf_chain_t * mbc)1068934SJose.Borrego@Sun.COM smb_mbc_free(mbuf_chain_t *mbc)
1078934SJose.Borrego@Sun.COM {
1088934SJose.Borrego@Sun.COM 	SMB_MBC_VALID(mbc);
1098934SJose.Borrego@Sun.COM 
1108934SJose.Borrego@Sun.COM 	m_freem(mbc->chain);
1118934SJose.Borrego@Sun.COM 	mbc->chain = NULL;
1128934SJose.Borrego@Sun.COM 	mbc->mbc_magic = 0;
1138934SJose.Borrego@Sun.COM 	kmem_cache_free(smb_mbc_cache, mbc);
1148934SJose.Borrego@Sun.COM }
1155331Samw 
1165331Samw /*
1175331Samw  * smb_mbuf_get
1185331Samw  *
1195331Samw  * Allocate mbufs to hold the amount of data specified.
1205331Samw  * A pointer to the head of the mbuf list is returned.
1215331Samw  */
1225331Samw struct mbuf *
smb_mbuf_get(uchar_t * buf,int nbytes)1235331Samw smb_mbuf_get(uchar_t *buf, int nbytes)
1245331Samw {
1255331Samw 	struct mbuf *mhead = 0;
1265331Samw 	struct mbuf *m = 0;
1275331Samw 	int count;
1285331Samw 	int offset = 0;
1295331Samw 
1305331Samw 	while (nbytes) {
1315331Samw 		count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
1325331Samw 		nbytes -= count;
1335331Samw 
1345331Samw 		if (mhead == 0) {
1355331Samw 			MGET(mhead, M_WAIT, MT_DATA);
1365331Samw 			m = mhead;
1375331Samw 		} else {
1385331Samw 			MGET(m->m_next, M_WAIT, MT_DATA);
1395331Samw 			m = m->m_next;
1405331Samw 		}
1415331Samw 
1425331Samw 		if (count > MLEN) {
1435331Samw 			MCLGET(m, M_WAIT);
1445331Samw 		}
1455331Samw 
1465331Samw 		m->m_len = count;
1475331Samw 		bcopy(buf + offset, m->m_data, count);
1485331Samw 		offset += count;
1495331Samw 	}
1505331Samw 	return (mhead);
1515331Samw }
1525331Samw 
1535331Samw /*
1545331Samw  * Allocate enough mbufs to accommodate the residual count in a uio.
1555331Samw  */
1565331Samw struct mbuf *
smb_mbuf_allocate(struct uio * uio)1575331Samw smb_mbuf_allocate(struct uio *uio)
1585331Samw {
1595331Samw 	struct iovec *iovp;
1605331Samw 	struct mbuf	*mhead = 0;
1615331Samw 	struct mbuf	*m = 0;
1625331Samw 	int	count, iovs, resid;
1635331Samw 
1645331Samw 	iovp = uio->uio_iov;
1655331Samw 	iovs = uio->uio_iovcnt;
1665331Samw 	resid = uio->uio_resid;
1675331Samw 
1685331Samw 	while ((resid > 0) && (iovs > 0)) {
1695331Samw 		count = (resid > MCLBYTES) ? MCLBYTES : resid;
1705331Samw 		resid -= count;
1715331Samw 
1725331Samw 		if (mhead == 0) {
1735331Samw 			MGET(mhead, M_WAIT, MT_DATA);
1745331Samw 			m = mhead;
1755331Samw 		} else {
1765331Samw 			MGET(m->m_next, M_WAIT, MT_DATA);
1775331Samw 			m = m->m_next;
1785331Samw 		}
1795331Samw 
1805331Samw 		if (count > MLEN) {
1815331Samw 			MCLGET(m, M_WAIT);
1825331Samw 		}
1835331Samw 
1845331Samw 		iovp->iov_base = m->m_data;
1855331Samw 		iovp->iov_len = m->m_len = count;
1865331Samw 		iovs--;
1875331Samw 		iovp++;
1885331Samw 	}
1895331Samw 
1905331Samw 	uio->uio_iovcnt -= iovs;
1915331Samw 	return (mhead);
1925331Samw }
1935331Samw 
1945331Samw /*
1955331Samw  * Trim an mbuf chain to nbytes.
1965331Samw  */
1975331Samw void
smb_mbuf_trim(struct mbuf * mhead,int nbytes)1985331Samw smb_mbuf_trim(struct mbuf *mhead, int nbytes)
1995331Samw {
2005331Samw 	struct mbuf	*m = mhead;
2015331Samw 
2025331Samw 	while (m != 0) {
2035331Samw 		if (nbytes <= m->m_len) {
2045331Samw 			m->m_len = nbytes;
2055331Samw 			if (m->m_next != 0) {
2065331Samw 				m_freem(m->m_next);
2075331Samw 				m->m_next = 0;
2085331Samw 			}
2095331Samw 			break;
2105331Samw 		}
2115331Samw 		nbytes -= m->m_len;
2125331Samw 		m = m->m_next;
2135331Samw 	}
2145331Samw }
2155331Samw 
2165331Samw int
MBC_LENGTH(struct mbuf_chain * MBC)2175331Samw MBC_LENGTH(struct mbuf_chain *MBC)
2185331Samw {
2195331Samw 	struct mbuf	*m = (MBC)->chain;
2205331Samw 	int		used = 0;
2215331Samw 
2225331Samw 	while (m != 0) {
2235331Samw 		used += m->m_len;
2245331Samw 		m = m->m_next;
2255331Samw 	}
2265331Samw 	return (used);
2275331Samw }
2285331Samw 
2296771Sjb150015 int
MBC_MAXBYTES(struct mbuf_chain * MBC)2306771Sjb150015 MBC_MAXBYTES(struct mbuf_chain *MBC)
2316771Sjb150015 {
2326771Sjb150015 	return (MBC->max_bytes);
2336771Sjb150015 }
2346771Sjb150015 
2355331Samw void
MBC_SETUP(struct mbuf_chain * MBC,uint32_t max_bytes)2365331Samw MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
2375331Samw {
2385331Samw 	bzero((MBC), sizeof (struct mbuf_chain));
2395331Samw 	(MBC)->max_bytes = max_bytes ? max_bytes : smb_maxbufsize;
2405331Samw }
2415331Samw 
2425331Samw void
MBC_INIT(struct mbuf_chain * MBC,uint32_t max_bytes)2435331Samw MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
2445331Samw {
2455331Samw 	struct mbuf *m;
2465331Samw 
2475331Samw 	bzero((MBC), sizeof (struct mbuf_chain));
2485331Samw 
2495331Samw 	if (max_bytes != 0) {
2505331Samw 		MGET(m, M_WAIT, MT_DATA);
2515331Samw 		m->m_len = 0;
2525331Samw 		(MBC)->chain = m;
2535331Samw 		if (max_bytes > MINCLSIZE)
2545331Samw 			MCLGET(m, M_WAIT);
2555331Samw 	}
2565331Samw 	(MBC)->max_bytes = max_bytes;
2575331Samw }
2585331Samw 
2595331Samw void
MBC_FLUSH(struct mbuf_chain * MBC)2605331Samw MBC_FLUSH(struct mbuf_chain *MBC)
2615331Samw {
2625331Samw 	extern void	m_freem(struct mbuf *);
2635331Samw 	struct mbuf	*m;
2645331Samw 
2655331Samw 	while ((m = (MBC)->chain) != 0) {
2665331Samw 		(MBC)->chain = m->m_nextpkt;
2675331Samw 		m->m_nextpkt = 0;
2685331Samw 		m_freem(m);
2695331Samw 	}
2705331Samw 	MBC_SETUP(MBC, (MBC)->max_bytes);
2715331Samw }
2725331Samw 
2735331Samw void
MBC_ATTACH_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)2745331Samw MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
2755331Samw {
2765331Samw 	if (MBC->chain != 0)
2775331Samw 		MBC_FLUSH(MBC);
2785331Samw 
2795331Samw 	(MBC)->chain_offset = 0;
2805331Samw 	(MBC)->chain = (MBUF);
2815331Samw }
2825331Samw 
2835331Samw void
MBC_APPEND_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)2845331Samw MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
2855331Samw {
2865331Samw 	struct mbuf	*m;
2875331Samw 
2885331Samw 	if ((MBC)->chain == 0) {
2895331Samw 		(MBC)->chain = (MBUF);
2905331Samw 	} else {
2915331Samw 		m = (MBC)->chain;
2925331Samw 		while (m->m_next != 0)
2935331Samw 			m = m->m_next;
2945331Samw 		m->m_next = (MBUF);
2955331Samw 	}
2965331Samw }
2975331Samw 
2985331Samw 
2995331Samw void
MBC_ATTACH_BUF(struct mbuf_chain * MBC,unsigned char * BUF,int LEN)3005331Samw MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
3015331Samw {
3025331Samw 	MGET((MBC)->chain, M_WAIT, MT_DATA);
3035331Samw 	(MBC)->chain_offset = 0;
3045331Samw 	(MBC)->chain->m_flags |= M_EXT;
3055331Samw 	(MBC)->chain->m_data = (caddr_t)(BUF);
3065331Samw 	(MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
3075331Samw 	(MBC)->chain->m_len = (LEN);
3085331Samw 	(MBC)->chain->m_ext.ext_size = (LEN);
3095331Samw 	(MBC)->chain->m_ext.ext_ref = smb_noop;
3105331Samw 	(MBC)->max_bytes = (LEN);
3115331Samw }
3125331Samw 
3135331Samw 
3145331Samw int
MBC_SHADOW_CHAIN(struct mbuf_chain * SUBMBC,struct mbuf_chain * MBC,int OFF,int LEN)3155331Samw MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
3165331Samw     int OFF, int LEN)
3175331Samw {
3185331Samw 	if (((OFF) + (LEN)) > (MBC)->max_bytes)
3195331Samw 		return (EMSGSIZE);
3205331Samw 
3215331Samw 	*(SUBMBC) = *(MBC);
3225331Samw 	(SUBMBC)->chain_offset = (OFF);
3235331Samw 	(SUBMBC)->max_bytes = (OFF) + (LEN);
3245331Samw 	(SUBMBC)->shadow_of = (MBC);
3255331Samw 	return (0);
3265331Samw }
3275331Samw 
3286496Sjb150015 int
mbc_moveout(mbuf_chain_t * mbc,caddr_t buf,int buflen,int * tlen)3296496Sjb150015 mbc_moveout(mbuf_chain_t *mbc, caddr_t buf, int buflen, int *tlen)
3306496Sjb150015 {
3316496Sjb150015 	int	rc = 0;
3326496Sjb150015 	int	len = 0;
3336496Sjb150015 
3346496Sjb150015 	if ((mbc != NULL) && (mbc->chain != NULL)) {
3356496Sjb150015 		mbuf_t	*m;
3366496Sjb150015 
3376496Sjb150015 		m = mbc->chain;
3386496Sjb150015 		while (m) {
3396496Sjb150015 			if ((len + m->m_len) <= buflen) {
3406496Sjb150015 				bcopy(m->m_data, buf, m->m_len);
3416496Sjb150015 				buf += m->m_len;
3426496Sjb150015 				len += m->m_len;
3436496Sjb150015 				m = m->m_next;
3446496Sjb150015 				continue;
3456496Sjb150015 			}
3466496Sjb150015 			rc = EMSGSIZE;
3476496Sjb150015 			break;
3486496Sjb150015 		}
3496496Sjb150015 		m_freem(mbc->chain);
3506496Sjb150015 		mbc->chain = NULL;
3516496Sjb150015 		mbc->flags = 0;
3526496Sjb150015 	}
3536496Sjb150015 	*tlen = len;
3546496Sjb150015 	return (rc);
3556496Sjb150015 }
3566496Sjb150015 
3575331Samw /*
3585331Samw  * Free a single mbuf structure.  Calls m->m_ext.ext_ref() to free any
3595331Samw  * associated external buffers if present (indicated by m->m_flags & M_EXT)
3605331Samw  */
3615331Samw struct mbuf *
m_free(struct mbuf * m)3625331Samw m_free(struct mbuf *m)
3635331Samw {
3645331Samw 	struct mbuf *n;
3655331Samw 
3665331Samw 	MFREE(m, n);
3675331Samw 	return (n);
3685331Samw }
3695331Samw 
3705331Samw /*
3715331Samw  * Free a list of mbufs.  Each mbuf in the list is freed similarly to m_free.
3725331Samw  */
3735331Samw void
m_freem(struct mbuf * m)3745331Samw m_freem(struct mbuf *m)
3755331Samw {
3765331Samw 	struct mbuf *n;
3775331Samw 
3785331Samw 	if (m == NULL)
3795331Samw 		return;
3805331Samw 	/*
3815331Samw 	 * Lint doesn't like the m = n assignment at the close of the loop
3825331Samw 	 * but it is correct.  MFREE assigns n = (m)->m_next so the loop
3835331Samw 	 * is effectively assigning m = (m)->m_next then exiting when
3845331Samw 	 * m == NULL
3855331Samw 	 */
3865331Samw 	do {
3875331Samw 		MFREE(m, n);
3885331Samw 	} while ((m = n) != 0);
3895331Samw }
3905331Samw 
3915331Samw /*
3925331Samw  * Mbuffer utility routines.
3935331Samw  */
3945331Samw 
3955331Samw int /*ARGSUSED*/
mclref(caddr_t p,int size,int adj)3965331Samw mclref(caddr_t p, int size, int adj) /* size, adj are unused */
3975331Samw {
3985331Samw 	MEM_FREE("mbuf", p);
3995331Samw 	return (0);
4005331Samw }
4015331Samw 
4025331Samw int /*ARGSUSED*/
mclrefnoop(caddr_t p,int size,int adj)4035331Samw mclrefnoop(caddr_t p, int size, int adj) /* p, size, adj are unused */
4045331Samw {
4055331Samw 	return (0);
4065331Samw }
407