1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22*897907ceSGordon Ross  * Copyright 2011-2021 Tintri by DDN, Inc. All rights reserved.
232c2961f8Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24da6c28aaSamw  * Use is subject to license terms.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * Copyright (c) 1982, 1986, 1988, 1991, 1993
29da6c28aaSamw  *	The Regents of the University of California.  All rights reserved.
30da6c28aaSamw  *
31da6c28aaSamw  * Redistribution and use in source and binary forms, with or without
32da6c28aaSamw  * modification, are permitted provided that the following conditions
33da6c28aaSamw  * are met:
34da6c28aaSamw  * 1. Redistributions of source code must retain the above copyright
35da6c28aaSamw  *    notice, this list of conditions and the following disclaimer.
36da6c28aaSamw  * 2. Redistributions in binary form must reproduce the above copyright
37da6c28aaSamw  *    notice, this list of conditions and the following disclaimer in the
38da6c28aaSamw  *    documentation and/or other materials provided with the distribution.
39da6c28aaSamw  * 3. All advertising materials mentioning features or use of this software
40da6c28aaSamw  *    must display the following acknowledgement:
41da6c28aaSamw  *	This product includes software developed by the University of
42da6c28aaSamw  *	California, Berkeley and its contributors.
43da6c28aaSamw  * 4. Neither the name of the University nor the names of its contributors
44da6c28aaSamw  *    may be used to endorse or promote products derived from this software
45da6c28aaSamw  *    without specific prior written permission.
46da6c28aaSamw  *
47da6c28aaSamw  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48da6c28aaSamw  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49da6c28aaSamw  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50da6c28aaSamw  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51da6c28aaSamw  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52da6c28aaSamw  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53da6c28aaSamw  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54da6c28aaSamw  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55da6c28aaSamw  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56da6c28aaSamw  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57da6c28aaSamw  * SUCH DAMAGE.
58da6c28aaSamw  *
59da6c28aaSamw  */
60da6c28aaSamw 
61bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
622c2961f8Sjose borrego #include <smbsrv/smb_kstat.h>
632c2961f8Sjose borrego 
642c2961f8Sjose borrego static kmem_cache_t	*smb_mbc_cache = NULL;
65a90cf9f2SGordon Ross static kmem_cache_t	*smb_mbuf_cache = NULL;
66a90cf9f2SGordon Ross static kmem_cache_t	*smb_mbufcl_cache = NULL;
672c2961f8Sjose borrego 
68*897907ceSGordon Ross /* Perhaps move this to libfakekernel? */
69*897907ceSGordon Ross #ifdef	_FAKE_KERNEL
70*897907ceSGordon Ross size_t kmem_max_cached = 0x20000;	// UMEM_MAXBUF
71*897907ceSGordon Ross #endif
72*897907ceSGordon Ross 
738622ec45SGordon Ross void
smb_mbc_init(void)742c2961f8Sjose borrego smb_mbc_init(void)
752c2961f8Sjose borrego {
768622ec45SGordon Ross 	if (smb_mbc_cache != NULL)
778622ec45SGordon Ross 		return;
788622ec45SGordon Ross 	smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
798622ec45SGordon Ross 	    sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
80a90cf9f2SGordon Ross 
81a90cf9f2SGordon Ross 	smb_mbuf_cache = kmem_cache_create("smb_mbuf_cache",
82a90cf9f2SGordon Ross 	    sizeof (mbuf_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
83a90cf9f2SGordon Ross 
84a90cf9f2SGordon Ross 	smb_mbufcl_cache = kmem_cache_create("smb_mbufcl_cache",
85a90cf9f2SGordon Ross 	    MCLBYTES, 8, NULL, NULL, NULL, NULL, NULL, 0);
862c2961f8Sjose borrego }
872c2961f8Sjose borrego 
882c2961f8Sjose borrego void
smb_mbc_fini(void)892c2961f8Sjose borrego smb_mbc_fini(void)
902c2961f8Sjose borrego {
912c2961f8Sjose borrego 	if (smb_mbc_cache != NULL) {
922c2961f8Sjose borrego 		kmem_cache_destroy(smb_mbc_cache);
932c2961f8Sjose borrego 		smb_mbc_cache = NULL;
942c2961f8Sjose borrego 	}
95a90cf9f2SGordon Ross 	if (smb_mbuf_cache != NULL) {
96a90cf9f2SGordon Ross 		kmem_cache_destroy(smb_mbuf_cache);
97a90cf9f2SGordon Ross 		smb_mbuf_cache = NULL;
98a90cf9f2SGordon Ross 	}
99a90cf9f2SGordon Ross 	if (smb_mbufcl_cache != NULL) {
100a90cf9f2SGordon Ross 		kmem_cache_destroy(smb_mbufcl_cache);
101a90cf9f2SGordon Ross 		smb_mbufcl_cache = NULL;
102a90cf9f2SGordon Ross 	}
1032c2961f8Sjose borrego }
1042c2961f8Sjose borrego 
1052c2961f8Sjose borrego mbuf_chain_t *
smb_mbc_alloc(uint32_t max_bytes)1062c2961f8Sjose borrego smb_mbc_alloc(uint32_t max_bytes)
1072c2961f8Sjose borrego {
1082c2961f8Sjose borrego 	mbuf_chain_t	*mbc;
1092c2961f8Sjose borrego 	mbuf_t		*m;
1102c2961f8Sjose borrego 
1112c2961f8Sjose borrego 	mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
1122c2961f8Sjose borrego 	bzero(mbc, sizeof (*mbc));
1132c2961f8Sjose borrego 	mbc->mbc_magic = SMB_MBC_MAGIC;
1142c2961f8Sjose borrego 
1152c2961f8Sjose borrego 	if (max_bytes != 0) {
1162c2961f8Sjose borrego 		MGET(m, M_WAIT, MT_DATA);
1172c2961f8Sjose borrego 		m->m_len = 0;
1182c2961f8Sjose borrego 		mbc->chain = m;
1192c2961f8Sjose borrego 		if (max_bytes > MINCLSIZE)
1202c2961f8Sjose borrego 			MCLGET(m, M_WAIT);
1212c2961f8Sjose borrego 	}
1222c2961f8Sjose borrego 	mbc->max_bytes = max_bytes;
1232c2961f8Sjose borrego 	return (mbc);
1242c2961f8Sjose borrego }
1252c2961f8Sjose borrego 
1262c2961f8Sjose borrego void
smb_mbc_free(mbuf_chain_t * mbc)1272c2961f8Sjose borrego smb_mbc_free(mbuf_chain_t *mbc)
1282c2961f8Sjose borrego {
1292c2961f8Sjose borrego 	SMB_MBC_VALID(mbc);
1302c2961f8Sjose borrego 
1312c2961f8Sjose borrego 	m_freem(mbc->chain);
1322c2961f8Sjose borrego 	mbc->chain = NULL;
1332c2961f8Sjose borrego 	mbc->mbc_magic = 0;
1342c2961f8Sjose borrego 	kmem_cache_free(smb_mbc_cache, mbc);
1352c2961f8Sjose borrego }
136da6c28aaSamw 
137da6c28aaSamw /*
138da6c28aaSamw  * smb_mbuf_get
139da6c28aaSamw  *
140da6c28aaSamw  * Allocate mbufs to hold the amount of data specified.
141da6c28aaSamw  * A pointer to the head of the mbuf list is returned.
142da6c28aaSamw  */
143da6c28aaSamw struct mbuf *
smb_mbuf_get(uchar_t * buf,int nbytes)144da6c28aaSamw smb_mbuf_get(uchar_t *buf, int nbytes)
145da6c28aaSamw {
146da6c28aaSamw 	struct mbuf *mhead = 0;
147da6c28aaSamw 	struct mbuf *m = 0;
148da6c28aaSamw 	int count;
149da6c28aaSamw 	int offset = 0;
150da6c28aaSamw 
151da6c28aaSamw 	while (nbytes) {
152da6c28aaSamw 		count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
153da6c28aaSamw 		nbytes -= count;
154da6c28aaSamw 
155da6c28aaSamw 		if (mhead == 0) {
156da6c28aaSamw 			MGET(mhead, M_WAIT, MT_DATA);
157da6c28aaSamw 			m = mhead;
158da6c28aaSamw 		} else {
159da6c28aaSamw 			MGET(m->m_next, M_WAIT, MT_DATA);
160da6c28aaSamw 			m = m->m_next;
161da6c28aaSamw 		}
162da6c28aaSamw 
163da6c28aaSamw 		if (count > MLEN) {
164da6c28aaSamw 			MCLGET(m, M_WAIT);
165da6c28aaSamw 		}
166da6c28aaSamw 
167da6c28aaSamw 		m->m_len = count;
168da6c28aaSamw 		bcopy(buf + offset, m->m_data, count);
169da6c28aaSamw 		offset += count;
170da6c28aaSamw 	}
171da6c28aaSamw 	return (mhead);
172da6c28aaSamw }
173da6c28aaSamw 
174*897907ceSGordon Ross /*
175*897907ceSGordon Ross  * Build an mbuf with external storage
176*897907ceSGordon Ross  * Like esballoca()
177*897907ceSGordon Ross  */
178*897907ceSGordon Ross mbuf_t *
smb_mbuf_alloc_ext(caddr_t buf,int len,m_ext_free_t ff,void * arg)179*897907ceSGordon Ross smb_mbuf_alloc_ext(caddr_t buf, int len, m_ext_free_t ff, void *arg)
180a90cf9f2SGordon Ross {
181*897907ceSGordon Ross 	mbuf_t	*m = 0;
182*897907ceSGordon Ross 
183*897907ceSGordon Ross 	MGET(m, M_WAIT, MT_DATA);
184*897907ceSGordon Ross 
185*897907ceSGordon Ross 	/* Like MCLGET(), but external buf. */
186*897907ceSGordon Ross 	m->m_ext.ext_buf = buf;
187*897907ceSGordon Ross 	m->m_data = m->m_ext.ext_buf;
188*897907ceSGordon Ross 	m->m_flags |= M_EXT;
189*897907ceSGordon Ross 	m->m_ext.ext_size = len;
190*897907ceSGordon Ross 	m->m_ext.ext_free = ff;
191*897907ceSGordon Ross 	m->m_ext.ext_arg1 = arg;
192*897907ceSGordon Ross 
193*897907ceSGordon Ross 	m->m_len = len;
194*897907ceSGordon Ross 
195*897907ceSGordon Ross 	return (m);
196*897907ceSGordon Ross }
197*897907ceSGordon Ross 
198*897907ceSGordon Ross static void
smb_mbuf_kmem_free(mbuf_t * m)199*897907ceSGordon Ross smb_mbuf_kmem_free(mbuf_t *m)
200*897907ceSGordon Ross {
201*897907ceSGordon Ross 	ASSERT((m->m_flags & M_EXT) != 0);
202*897907ceSGordon Ross 
203*897907ceSGordon Ross 	kmem_free(m->m_ext.ext_buf, m->m_ext.ext_size);
204*897907ceSGordon Ross 	/* Caller sets m->m_ext.ext_buf = NULL */
205*897907ceSGordon Ross }
206*897907ceSGordon Ross 
207*897907ceSGordon Ross /*
208*897907ceSGordon Ross  * Allocate one mbuf with contiguous (external) storage
209*897907ceSGordon Ross  * obtained via kmem_alloc.  Most places should be using
210*897907ceSGordon Ross  * smb_mbuf_alloc_chain below.
211*897907ceSGordon Ross  */
212*897907ceSGordon Ross mbuf_t *
smb_mbuf_alloc_kmem(int len)213*897907ceSGordon Ross smb_mbuf_alloc_kmem(int len)
214*897907ceSGordon Ross {
215*897907ceSGordon Ross 	mbuf_t *m;
216*897907ceSGordon Ross 	caddr_t buf;
217*897907ceSGordon Ross 
218*897907ceSGordon Ross 	VERIFY(len > 0);
219*897907ceSGordon Ross #ifdef	DEBUG
220*897907ceSGordon Ross 	if (len > kmem_max_cached) {
221*897907ceSGordon Ross 		debug_enter("fix caller");
222*897907ceSGordon Ross 	}
223*897907ceSGordon Ross #endif
224*897907ceSGordon Ross 
225*897907ceSGordon Ross 	buf = kmem_alloc(len, KM_SLEEP);
226*897907ceSGordon Ross 	m = smb_mbuf_alloc_ext(buf, len, smb_mbuf_kmem_free, NULL);
227*897907ceSGordon Ross 
228*897907ceSGordon Ross 	return (m);
229*897907ceSGordon Ross }
230*897907ceSGordon Ross 
231*897907ceSGordon Ross /*
232*897907ceSGordon Ross  * smb_mbuf_alloc_chain
233*897907ceSGordon Ross  *
234*897907ceSGordon Ross  * Allocate mbufs to hold the amount of data specified.
235*897907ceSGordon Ross  * A pointer to the head of the mbuf chain is returned.
236*897907ceSGordon Ross  *
237*897907ceSGordon Ross  * For large messages, put the large mbufs at the tail, starting with
238*897907ceSGordon Ross  * kmem_max_cached messages (128K) and then a shorter (eg MCLBYTES)
239*897907ceSGordon Ross  * message at the front where we're more likely to need to copy.
240*897907ceSGordon Ross  *
241*897907ceSGordon Ross  * Must limit this to kmem_max_cached, to avoid contention with
242*897907ceSGordon Ross  * allocating from kmem_oversize_arena.
243*897907ceSGordon Ross  */
244*897907ceSGordon Ross struct mbuf *
smb_mbuf_alloc_chain(int nbytes)245*897907ceSGordon Ross smb_mbuf_alloc_chain(int nbytes)
246*897907ceSGordon Ross {
247*897907ceSGordon Ross 	struct mbuf *mhead = NULL;
248*897907ceSGordon Ross 	struct mbuf *m;
249*897907ceSGordon Ross 	int len;	/* m_len for current mbuf */
250*897907ceSGordon Ross 
251*897907ceSGordon Ross 	ASSERT(nbytes > 0);
252*897907ceSGordon Ross 
253*897907ceSGordon Ross 	while (nbytes >= kmem_max_cached) {
254*897907ceSGordon Ross 		len = kmem_max_cached;
255*897907ceSGordon Ross 		m = smb_mbuf_alloc_kmem(len);
256*897907ceSGordon Ross 
257*897907ceSGordon Ross 		/* prepend to chain at mhead */
258*897907ceSGordon Ross 		m->m_next = mhead;
259*897907ceSGordon Ross 		mhead = m;
260*897907ceSGordon Ross 
261*897907ceSGordon Ross 		nbytes -= len;
262*897907ceSGordon Ross 	}
263*897907ceSGordon Ross 
264*897907ceSGordon Ross 	if (nbytes > MCLBYTES) {
265*897907ceSGordon Ross 		len = nbytes;
266*897907ceSGordon Ross 		m = smb_mbuf_alloc_kmem(len);
267*897907ceSGordon Ross 
268*897907ceSGordon Ross 		/* prepend to chain at mhead */
269*897907ceSGordon Ross 		m->m_next = mhead;
270*897907ceSGordon Ross 		mhead = m;
271*897907ceSGordon Ross 
272*897907ceSGordon Ross 		nbytes -= len;
273*897907ceSGordon Ross 	} else if (nbytes > 0) {
274*897907ceSGordon Ross 		ASSERT(nbytes <= MCLBYTES);
275*897907ceSGordon Ross 		len = nbytes;
276*897907ceSGordon Ross 		MGET(m, M_WAIT, MT_DATA);
277*897907ceSGordon Ross 		if (len > MLEN) {
278*897907ceSGordon Ross 			MCLGET(m, M_WAIT);
279*897907ceSGordon Ross 		}
280*897907ceSGordon Ross 		m->m_len = len;
281*897907ceSGordon Ross 
282*897907ceSGordon Ross 		/* prepend to chain at mhead */
283*897907ceSGordon Ross 		m->m_next = mhead;
284*897907ceSGordon Ross 		mhead = m;
285*897907ceSGordon Ross 
286*897907ceSGordon Ross 		nbytes -= len;
287*897907ceSGordon Ross 	}
288*897907ceSGordon Ross 
289*897907ceSGordon Ross 	return (mhead);
290a90cf9f2SGordon Ross }
291a90cf9f2SGordon Ross 
292da6c28aaSamw /*
293a90cf9f2SGordon Ross  * Allocate enough mbufs to accommodate the residual count in uio,
294*897907ceSGordon Ross  * and setup the uio_iov to point to them.  Note that uio->uio_iov
295*897907ceSGordon Ross  * is allocated by the call and has MAX_IOVEC elements.  Currently
296*897907ceSGordon Ross  * the uio passed is always part of an smb_vdb_t and starts with
297*897907ceSGordon Ross  * uio->uio_iovcnt = MAX_IOVEC;
298a90cf9f2SGordon Ross  *
299a90cf9f2SGordon Ross  * This is used by the various SMB read code paths.  That code is
300*897907ceSGordon Ross  * going to do a disk read into this buffer, so we'd like the
301*897907ceSGordon Ross  * segments to be large.  See smb_mbuf_alloc_chain().
302da6c28aaSamw  */
303da6c28aaSamw struct mbuf *
smb_mbuf_allocate(struct uio * uio)304da6c28aaSamw smb_mbuf_allocate(struct uio *uio)
305da6c28aaSamw {
306*897907ceSGordon Ross 	mbuf_t	*mhead;
307*897907ceSGordon Ross 	int	rc;
308a90cf9f2SGordon Ross 
309*897907ceSGordon Ross 	ASSERT(uio->uio_resid > 0);
310*897907ceSGordon Ross 	ASSERT(uio->uio_iovcnt == MAX_IOVEC);
311da6c28aaSamw 
312*897907ceSGordon Ross 	mhead = smb_mbuf_alloc_chain(uio->uio_resid);
313a90cf9f2SGordon Ross 
314*897907ceSGordon Ross 	rc = smb_mbuf_mkuio(mhead, uio);
315*897907ceSGordon Ross 	VERIFY(rc == 0);
316*897907ceSGordon Ross 
317*897907ceSGordon Ross 	return (mhead);
318*897907ceSGordon Ross }
319*897907ceSGordon Ross 
320*897907ceSGordon Ross /*
321*897907ceSGordon Ross  * Build an iovec for an mbuf chain.
322*897907ceSGordon Ross  *
323*897907ceSGordon Ross  * The resulting iovec covers uio_resid length in the chain,
324*897907ceSGordon Ross  * which could be shorter than the mbuf chain total length.
325*897907ceSGordon Ross  *
326*897907ceSGordon Ross  * uio->uio_iovcnt is allocated size on entry, used size on return.
327*897907ceSGordon Ross  * Errors if iovec too small or mbuf chain too short.
328*897907ceSGordon Ross  */
329*897907ceSGordon Ross int
smb_mbuf_mkuio(mbuf_t * m,uio_t * uio)330*897907ceSGordon Ross smb_mbuf_mkuio(mbuf_t *m, uio_t *uio)
331*897907ceSGordon Ross {
332*897907ceSGordon Ross 	iovec_t	*iov;
333*897907ceSGordon Ross 	ssize_t off = 0;
334*897907ceSGordon Ross 	int iovcnt = 0;
335*897907ceSGordon Ross 	int tlen;
336*897907ceSGordon Ross 
337*897907ceSGordon Ross 	iov = uio->uio_iov;
338*897907ceSGordon Ross 	while (off < uio->uio_resid) {
339*897907ceSGordon Ross 		if (m == NULL)
340*897907ceSGordon Ross 			return (EFAULT);
341*897907ceSGordon Ross 		if (iovcnt >= uio->uio_iovcnt)
342*897907ceSGordon Ross 			return (E2BIG);
343*897907ceSGordon Ross 		tlen = m->m_len;
344*897907ceSGordon Ross 		if ((off + tlen) > uio->uio_resid)
345*897907ceSGordon Ross 			tlen = (int)(uio->uio_resid - off);
346*897907ceSGordon Ross 		iov->iov_base = m->m_data;
347*897907ceSGordon Ross 		iov->iov_len = tlen;
348*897907ceSGordon Ross 		off += tlen;
349*897907ceSGordon Ross 		m = m->m_next;
350*897907ceSGordon Ross 		iovcnt++;
351*897907ceSGordon Ross 		iov++;
352*897907ceSGordon Ross 	}
353*897907ceSGordon Ross 	uio->uio_iovcnt = iovcnt;
354*897907ceSGordon Ross 
355*897907ceSGordon Ross 	return (0);
356da6c28aaSamw }
357da6c28aaSamw 
358da6c28aaSamw /*
359da6c28aaSamw  * Trim an mbuf chain to nbytes.
360da6c28aaSamw  */
361da6c28aaSamw void
smb_mbuf_trim(struct mbuf * mhead,int nbytes)362da6c28aaSamw smb_mbuf_trim(struct mbuf *mhead, int nbytes)
363da6c28aaSamw {
364da6c28aaSamw 	struct mbuf	*m = mhead;
365da6c28aaSamw 
366da6c28aaSamw 	while (m != 0) {
367da6c28aaSamw 		if (nbytes <= m->m_len) {
368da6c28aaSamw 			m->m_len = nbytes;
369da6c28aaSamw 			if (m->m_next != 0) {
370da6c28aaSamw 				m_freem(m->m_next);
371da6c28aaSamw 				m->m_next = 0;
372da6c28aaSamw 			}
373da6c28aaSamw 			break;
374da6c28aaSamw 		}
375da6c28aaSamw 		nbytes -= m->m_len;
376da6c28aaSamw 		m = m->m_next;
377da6c28aaSamw 	}
378da6c28aaSamw }
379da6c28aaSamw 
380da6c28aaSamw int
MBC_LENGTH(struct mbuf_chain * MBC)381da6c28aaSamw MBC_LENGTH(struct mbuf_chain *MBC)
382da6c28aaSamw {
383da6c28aaSamw 	struct mbuf	*m = (MBC)->chain;
384da6c28aaSamw 	int		used = 0;
385da6c28aaSamw 
386da6c28aaSamw 	while (m != 0) {
387da6c28aaSamw 		used += m->m_len;
388da6c28aaSamw 		m = m->m_next;
389da6c28aaSamw 	}
390da6c28aaSamw 	return (used);
391da6c28aaSamw }
392da6c28aaSamw 
3933ad684d6Sjb int
MBC_MAXBYTES(struct mbuf_chain * MBC)3943ad684d6Sjb MBC_MAXBYTES(struct mbuf_chain *MBC)
3953ad684d6Sjb {
3963ad684d6Sjb 	return (MBC->max_bytes);
3973ad684d6Sjb }
3983ad684d6Sjb 
399da6c28aaSamw void
MBC_SETUP(struct mbuf_chain * MBC,uint32_t max_bytes)400da6c28aaSamw MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
401da6c28aaSamw {
402da6c28aaSamw 	bzero((MBC), sizeof (struct mbuf_chain));
4037f3ef643SGordon Ross 	(MBC)->max_bytes = max_bytes;
404da6c28aaSamw }
405da6c28aaSamw 
406*897907ceSGordon Ross /*
407*897907ceSGordon Ross  * Initialize an mbuf chain and allocate the first message (if max_bytes
408*897907ceSGordon Ross  * is specified).  Leave some prepend space at the head.
409*897907ceSGordon Ross  */
410da6c28aaSamw void
MBC_INIT(struct mbuf_chain * MBC,uint32_t max_bytes)411da6c28aaSamw MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
412da6c28aaSamw {
413da6c28aaSamw 	struct mbuf *m;
414da6c28aaSamw 
415da6c28aaSamw 	bzero((MBC), sizeof (struct mbuf_chain));
416da6c28aaSamw 
417da6c28aaSamw 	if (max_bytes != 0) {
418da6c28aaSamw 		MGET(m, M_WAIT, MT_DATA);
419da6c28aaSamw 		m->m_len = 0;
420da6c28aaSamw 		(MBC)->chain = m;
421da6c28aaSamw 		if (max_bytes > MINCLSIZE)
422da6c28aaSamw 			MCLGET(m, M_WAIT);
423*897907ceSGordon Ross 		m->m_data += MH_PREPEND_SPACE;
424da6c28aaSamw 	}
425da6c28aaSamw 	(MBC)->max_bytes = max_bytes;
426da6c28aaSamw }
427da6c28aaSamw 
428da6c28aaSamw void
MBC_FLUSH(struct mbuf_chain * MBC)429da6c28aaSamw MBC_FLUSH(struct mbuf_chain *MBC)
430da6c28aaSamw {
431da6c28aaSamw 	extern void	m_freem(struct mbuf *);
432da6c28aaSamw 	struct mbuf	*m;
433da6c28aaSamw 
434da6c28aaSamw 	while ((m = (MBC)->chain) != 0) {
435da6c28aaSamw 		(MBC)->chain = m->m_nextpkt;
436da6c28aaSamw 		m->m_nextpkt = 0;
437da6c28aaSamw 		m_freem(m);
438da6c28aaSamw 	}
439da6c28aaSamw 	MBC_SETUP(MBC, (MBC)->max_bytes);
440da6c28aaSamw }
441da6c28aaSamw 
442da6c28aaSamw void
MBC_ATTACH_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)443da6c28aaSamw MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
444da6c28aaSamw {
445da6c28aaSamw 	if (MBC->chain != 0)
446da6c28aaSamw 		MBC_FLUSH(MBC);
447da6c28aaSamw 
448da6c28aaSamw 	(MBC)->chain_offset = 0;
449da6c28aaSamw 	(MBC)->chain = (MBUF);
450da6c28aaSamw }
451da6c28aaSamw 
452da6c28aaSamw void
MBC_APPEND_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)453da6c28aaSamw MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
454da6c28aaSamw {
455da6c28aaSamw 	struct mbuf	*m;
456da6c28aaSamw 
457da6c28aaSamw 	if ((MBC)->chain == 0) {
458da6c28aaSamw 		(MBC)->chain = (MBUF);
459da6c28aaSamw 	} else {
460da6c28aaSamw 		m = (MBC)->chain;
461da6c28aaSamw 		while (m->m_next != 0)
462da6c28aaSamw 			m = m->m_next;
463da6c28aaSamw 		m->m_next = (MBUF);
464da6c28aaSamw 	}
465da6c28aaSamw }
466da6c28aaSamw 
467*897907ceSGordon Ross static void /*ARGSUSED*/
mclrefnoop(mbuf_t * m)468*897907ceSGordon Ross mclrefnoop(mbuf_t *m)
469a90cf9f2SGordon Ross {
470a90cf9f2SGordon Ross }
471da6c28aaSamw 
472da6c28aaSamw void
MBC_ATTACH_BUF(struct mbuf_chain * MBC,unsigned char * BUF,int LEN)473da6c28aaSamw MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
474da6c28aaSamw {
475da6c28aaSamw 	MGET((MBC)->chain, M_WAIT, MT_DATA);
476da6c28aaSamw 	(MBC)->chain_offset = 0;
477da6c28aaSamw 	(MBC)->chain->m_flags |= M_EXT;
478da6c28aaSamw 	(MBC)->chain->m_data = (caddr_t)(BUF);
479da6c28aaSamw 	(MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
480da6c28aaSamw 	(MBC)->chain->m_len = (LEN);
481da6c28aaSamw 	(MBC)->chain->m_ext.ext_size = (LEN);
482*897907ceSGordon Ross 	(MBC)->chain->m_ext.ext_free = mclrefnoop;
483da6c28aaSamw 	(MBC)->max_bytes = (LEN);
484da6c28aaSamw }
485da6c28aaSamw 
486da6c28aaSamw 
487da6c28aaSamw int
MBC_SHADOW_CHAIN(struct mbuf_chain * submbc,struct mbuf_chain * mbc,int off,int len)488a90cf9f2SGordon Ross MBC_SHADOW_CHAIN(struct mbuf_chain *submbc, struct mbuf_chain *mbc,
489a90cf9f2SGordon Ross     int off, int len)
490da6c28aaSamw {
491a90cf9f2SGordon Ross 	int x = off + len;
492a90cf9f2SGordon Ross 
493a90cf9f2SGordon Ross 	if (off < 0 || len < 0 || x < 0 ||
494a90cf9f2SGordon Ross 	    off > mbc->max_bytes || x > mbc->max_bytes)
495da6c28aaSamw 		return (EMSGSIZE);
496da6c28aaSamw 
497a90cf9f2SGordon Ross 	*submbc = *mbc;
498a90cf9f2SGordon Ross 	submbc->chain_offset = off;
499a90cf9f2SGordon Ross 	submbc->max_bytes = x;
500a90cf9f2SGordon Ross 	submbc->shadow_of = mbc;
501da6c28aaSamw 	return (0);
502da6c28aaSamw }
503da6c28aaSamw 
504*897907ceSGordon Ross /*
505*897907ceSGordon Ross  * Trim req_len bytes from the message,
506*897907ceSGordon Ross  * from head if > 0, else from tail.
507*897907ceSGordon Ross  */
508*897907ceSGordon Ross void
m_adjust(struct mbuf * mp,int req_len)509*897907ceSGordon Ross m_adjust(struct mbuf *mp, int req_len)
510*897907ceSGordon Ross {
511*897907ceSGordon Ross 	int len = req_len;
512*897907ceSGordon Ross 	struct mbuf *m;
513*897907ceSGordon Ross 
514*897907ceSGordon Ross 	if ((m = mp) == NULL)
515*897907ceSGordon Ross 		return;
516*897907ceSGordon Ross 
517*897907ceSGordon Ross 	/*
518*897907ceSGordon Ross 	 * We don't use the trim-from-tail case.
519*897907ceSGordon Ross 	 * Using smb_mbuf_trim() for that.
520*897907ceSGordon Ross 	 */
521*897907ceSGordon Ross 	VERIFY(len >= 0);
522*897907ceSGordon Ross 
523*897907ceSGordon Ross 	/*
524*897907ceSGordon Ross 	 * Trim from head.
525*897907ceSGordon Ross 	 */
526*897907ceSGordon Ross 	while (m != NULL && len > 0) {
527*897907ceSGordon Ross 		if (m->m_len <= len) {
528*897907ceSGordon Ross 			len -= m->m_len;
529*897907ceSGordon Ross 			m->m_len = 0;
530*897907ceSGordon Ross 			m = m->m_next;
531*897907ceSGordon Ross 		} else {
532*897907ceSGordon Ross 			m->m_len -= len;
533*897907ceSGordon Ross 			m->m_data += len;
534*897907ceSGordon Ross 			len = 0;
535*897907ceSGordon Ross 		}
536*897907ceSGordon Ross 	}
537*897907ceSGordon Ross }
538*897907ceSGordon Ross 
539*897907ceSGordon Ross /*
540*897907ceSGordon Ross  * Arrange to prepend space of size plen to mbuf m.  If a new mbuf must be
541*897907ceSGordon Ross  * allocated, how specifies whether to wait.  If the allocation fails, the
542*897907ceSGordon Ross  * original mbuf chain is freed and m is set to NULL.
543*897907ceSGordon Ross  * BSD had a macro: M_PREPEND(m, plen, how)
544*897907ceSGordon Ross  */
545*897907ceSGordon Ross 
546*897907ceSGordon Ross struct mbuf *
m_prepend(struct mbuf * m,int plen,int how)547*897907ceSGordon Ross m_prepend(struct mbuf *m, int plen, int how)
548*897907ceSGordon Ross {
549*897907ceSGordon Ross 	struct mbuf *mn;
550*897907ceSGordon Ross 
551*897907ceSGordon Ross 	if (M_LEADINGSPACE(m) >= plen) {
552*897907ceSGordon Ross 		m->m_data -= plen;
553*897907ceSGordon Ross 		m->m_len += plen;
554*897907ceSGordon Ross 		return (m);
555*897907ceSGordon Ross 	}
556*897907ceSGordon Ross 	if (m->m_flags & M_PKTHDR) {
557*897907ceSGordon Ross 		MGETHDR(mn, how, m->m_type);
558*897907ceSGordon Ross 	} else {
559*897907ceSGordon Ross 		MGET(mn, how, m->m_type);
560*897907ceSGordon Ross 	}
561*897907ceSGordon Ross 	VERIFY(mn != NULL);
562*897907ceSGordon Ross 	if (m->m_flags & M_PKTHDR) {
563*897907ceSGordon Ross 		// BSD: m_move_pkthdr(mn, m);
564*897907ceSGordon Ross 		// We don't use any pkthdr stuff.
565*897907ceSGordon Ross 		mn->m_pkthdr.len += plen;
566*897907ceSGordon Ross 	}
567*897907ceSGordon Ross 	mn->m_next = m;
568*897907ceSGordon Ross 	m = mn;
569*897907ceSGordon Ross 	if (plen < M_SIZE(m))
570*897907ceSGordon Ross 		M_ALIGN(m, plen);
571*897907ceSGordon Ross 	m->m_len = plen;
572*897907ceSGordon Ross 	DTRACE_PROBE1(prepend_allocated, struct mbuf *, m);
573*897907ceSGordon Ross 	return (m);
574*897907ceSGordon Ross }
575*897907ceSGordon Ross 
576da6c28aaSamw /*
577da6c28aaSamw  * Free a single mbuf structure.  Calls m->m_ext.ext_ref() to free any
578da6c28aaSamw  * associated external buffers if present (indicated by m->m_flags & M_EXT)
579da6c28aaSamw  */
580da6c28aaSamw struct mbuf *
m_free(struct mbuf * m)581da6c28aaSamw m_free(struct mbuf *m)
582da6c28aaSamw {
583da6c28aaSamw 	struct mbuf *n;
584da6c28aaSamw 
585da6c28aaSamw 	MFREE(m, n);
586da6c28aaSamw 	return (n);
587da6c28aaSamw }
588da6c28aaSamw 
589da6c28aaSamw /*
590da6c28aaSamw  * Free a list of mbufs.  Each mbuf in the list is freed similarly to m_free.
591da6c28aaSamw  */
592da6c28aaSamw void
m_freem(struct mbuf * m)593da6c28aaSamw m_freem(struct mbuf *m)
594da6c28aaSamw {
595da6c28aaSamw 	struct mbuf *n;
596da6c28aaSamw 
597da6c28aaSamw 	if (m == NULL)
598da6c28aaSamw 		return;
599da6c28aaSamw 	/*
600da6c28aaSamw 	 * Lint doesn't like the m = n assignment at the close of the loop
601da6c28aaSamw 	 * but it is correct.  MFREE assigns n = (m)->m_next so the loop
602da6c28aaSamw 	 * is effectively assigning m = (m)->m_next then exiting when
603da6c28aaSamw 	 * m == NULL
604da6c28aaSamw 	 */
605da6c28aaSamw 	do {
606da6c28aaSamw 		MFREE(m, n);
607da6c28aaSamw 	} while ((m = n) != 0);
608da6c28aaSamw }
609da6c28aaSamw 
610da6c28aaSamw /*
611da6c28aaSamw  * Mbuffer utility routines.
612da6c28aaSamw  */
613da6c28aaSamw 
614a90cf9f2SGordon Ross mbuf_t *
smb_mbuf_alloc(void)615a90cf9f2SGordon Ross smb_mbuf_alloc(void)
616da6c28aaSamw {
617a90cf9f2SGordon Ross 	mbuf_t *m;
618a90cf9f2SGordon Ross 
619a90cf9f2SGordon Ross 	m = kmem_cache_alloc(smb_mbuf_cache, KM_SLEEP);
620a90cf9f2SGordon Ross 	bzero(m, sizeof (*m));
621a90cf9f2SGordon Ross 	return (m);
622da6c28aaSamw }
623da6c28aaSamw 
624a90cf9f2SGordon Ross void
smb_mbuf_free(mbuf_t * m)625a90cf9f2SGordon Ross smb_mbuf_free(mbuf_t *m)
626a90cf9f2SGordon Ross {
627a90cf9f2SGordon Ross 	kmem_cache_free(smb_mbuf_cache, m);
628a90cf9f2SGordon Ross }
629a90cf9f2SGordon Ross 
630a90cf9f2SGordon Ross void *
smb_mbufcl_alloc(void)631a90cf9f2SGordon Ross smb_mbufcl_alloc(void)
632a90cf9f2SGordon Ross {
633a90cf9f2SGordon Ross 	void *p;
634a90cf9f2SGordon Ross 
635a90cf9f2SGordon Ross 	p = kmem_cache_alloc(smb_mbufcl_cache, KM_SLEEP);
636a90cf9f2SGordon Ross 	bzero(p, MCLBYTES);
637a90cf9f2SGordon Ross 	return (p);
638a90cf9f2SGordon Ross }
639a90cf9f2SGordon Ross 
640a90cf9f2SGordon Ross void
smb_mbufcl_free(mbuf_t * m)641*897907ceSGordon Ross smb_mbufcl_free(mbuf_t *m)
642a90cf9f2SGordon Ross {
643*897907ceSGordon Ross 	ASSERT((m->m_flags & M_EXT) != 0);
644*897907ceSGordon Ross 	ASSERT(m->m_ext.ext_size == MCLBYTES);
645*897907ceSGordon Ross 
646*897907ceSGordon Ross 	kmem_cache_free(smb_mbufcl_cache, m->m_ext.ext_buf);
647*897907ceSGordon Ross 	/* Caller sets m->m_ext.ext_buf = NULL */
648a90cf9f2SGordon Ross }
649a90cf9f2SGordon Ross 
650a90cf9f2SGordon Ross int
smb_mbufcl_ref(void * p,uint_t sz,int incr)651a90cf9f2SGordon Ross smb_mbufcl_ref(void *p, uint_t sz, int incr)
652da6c28aaSamw {
653a90cf9f2SGordon Ross 	ASSERT3S(sz, ==, MCLBYTES);
654a90cf9f2SGordon Ross 	if (incr < 0)
655a90cf9f2SGordon Ross 		kmem_cache_free(smb_mbufcl_cache, p);
656da6c28aaSamw 	return (0);
657da6c28aaSamw }
658