xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c (revision 56f33205c9ed776c3c909e07d52e94610a675740)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 /*
27  * Copyright (c) 1982, 1986, 1988, 1991, 1993
28  *	The Regents of the University of California.  All rights reserved.
29  *
30  * Redistribution and use in source and binary forms, with or without
31  * modification, are permitted provided that the following conditions
32  * are met:
33  * 1. Redistributions of source code must retain the above copyright
34  *    notice, this list of conditions and the following disclaimer.
35  * 2. Redistributions in binary form must reproduce the above copyright
36  *    notice, this list of conditions and the following disclaimer in the
37  *    documentation and/or other materials provided with the distribution.
38  * 3. All advertising materials mentioning features or use of this software
39  *    must display the following acknowledgement:
40  *	This product includes software developed by the University of
41  *	California, Berkeley and its contributors.
42  * 4. Neither the name of the University nor the names of its contributors
43  *    may be used to endorse or promote products derived from this software
44  *    without specific prior written permission.
45  *
46  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
47  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
48  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
49  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
50  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
51  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
52  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
53  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
54  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
55  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
56  * SUCH DAMAGE.
57  *
58  */
59 
60 #include <smbsrv/smb_kproto.h>
61 #include <smbsrv/smb_kstat.h>
62 
63 static kmem_cache_t	*smb_mbc_cache = NULL;
64 
65 int
66 smb_mbc_init(void)
67 {
68 	if (smb_mbc_cache == NULL) {
69 		smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
70 		    sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
71 	}
72 	return (0);
73 }
74 
75 void
76 smb_mbc_fini(void)
77 {
78 	if (smb_mbc_cache != NULL) {
79 		kmem_cache_destroy(smb_mbc_cache);
80 		smb_mbc_cache = NULL;
81 	}
82 }
83 
84 mbuf_chain_t *
85 smb_mbc_alloc(uint32_t max_bytes)
86 {
87 	mbuf_chain_t	*mbc;
88 	mbuf_t		*m;
89 
90 	mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
91 	bzero(mbc, sizeof (*mbc));
92 	mbc->mbc_magic = SMB_MBC_MAGIC;
93 
94 	if (max_bytes != 0) {
95 		MGET(m, M_WAIT, MT_DATA);
96 		m->m_len = 0;
97 		mbc->chain = m;
98 		if (max_bytes > MINCLSIZE)
99 			MCLGET(m, M_WAIT);
100 	}
101 	mbc->max_bytes = max_bytes;
102 	return (mbc);
103 }
104 
105 void
106 smb_mbc_free(mbuf_chain_t *mbc)
107 {
108 	SMB_MBC_VALID(mbc);
109 
110 	m_freem(mbc->chain);
111 	mbc->chain = NULL;
112 	mbc->mbc_magic = 0;
113 	kmem_cache_free(smb_mbc_cache, mbc);
114 }
115 
116 /*
117  * smb_mbuf_get
118  *
119  * Allocate mbufs to hold the amount of data specified.
120  * A pointer to the head of the mbuf list is returned.
121  */
122 struct mbuf *
123 smb_mbuf_get(uchar_t *buf, int nbytes)
124 {
125 	struct mbuf *mhead = 0;
126 	struct mbuf *m = 0;
127 	int count;
128 	int offset = 0;
129 
130 	while (nbytes) {
131 		count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
132 		nbytes -= count;
133 
134 		if (mhead == 0) {
135 			MGET(mhead, M_WAIT, MT_DATA);
136 			m = mhead;
137 		} else {
138 			MGET(m->m_next, M_WAIT, MT_DATA);
139 			m = m->m_next;
140 		}
141 
142 		if (count > MLEN) {
143 			MCLGET(m, M_WAIT);
144 		}
145 
146 		m->m_len = count;
147 		bcopy(buf + offset, m->m_data, count);
148 		offset += count;
149 	}
150 	return (mhead);
151 }
152 
153 /*
154  * Allocate enough mbufs to accommodate the residual count in a uio.
155  */
156 struct mbuf *
157 smb_mbuf_allocate(struct uio *uio)
158 {
159 	struct iovec *iovp;
160 	struct mbuf	*mhead = 0;
161 	struct mbuf	*m = 0;
162 	int	count, iovs, resid;
163 
164 	iovp = uio->uio_iov;
165 	iovs = uio->uio_iovcnt;
166 	resid = uio->uio_resid;
167 
168 	while ((resid > 0) && (iovs > 0)) {
169 		count = (resid > MCLBYTES) ? MCLBYTES : resid;
170 		resid -= count;
171 
172 		if (mhead == 0) {
173 			MGET(mhead, M_WAIT, MT_DATA);
174 			m = mhead;
175 		} else {
176 			MGET(m->m_next, M_WAIT, MT_DATA);
177 			m = m->m_next;
178 		}
179 
180 		if (count > MLEN) {
181 			MCLGET(m, M_WAIT);
182 		}
183 
184 		iovp->iov_base = m->m_data;
185 		iovp->iov_len = m->m_len = count;
186 		iovs--;
187 		iovp++;
188 	}
189 
190 	uio->uio_iovcnt -= iovs;
191 	return (mhead);
192 }
193 
194 /*
195  * Trim an mbuf chain to nbytes.
196  */
197 void
198 smb_mbuf_trim(struct mbuf *mhead, int nbytes)
199 {
200 	struct mbuf	*m = mhead;
201 
202 	while (m != 0) {
203 		if (nbytes <= m->m_len) {
204 			m->m_len = nbytes;
205 			if (m->m_next != 0) {
206 				m_freem(m->m_next);
207 				m->m_next = 0;
208 			}
209 			break;
210 		}
211 		nbytes -= m->m_len;
212 		m = m->m_next;
213 	}
214 }
215 
216 int
217 MBC_LENGTH(struct mbuf_chain *MBC)
218 {
219 	struct mbuf	*m = (MBC)->chain;
220 	int		used = 0;
221 
222 	while (m != 0) {
223 		used += m->m_len;
224 		m = m->m_next;
225 	}
226 	return (used);
227 }
228 
229 int
230 MBC_MAXBYTES(struct mbuf_chain *MBC)
231 {
232 	return (MBC->max_bytes);
233 }
234 
235 void
236 MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
237 {
238 	bzero((MBC), sizeof (struct mbuf_chain));
239 	(MBC)->max_bytes = max_bytes ? max_bytes : smb_maxbufsize;
240 }
241 
242 void
243 MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
244 {
245 	struct mbuf *m;
246 
247 	bzero((MBC), sizeof (struct mbuf_chain));
248 
249 	if (max_bytes != 0) {
250 		MGET(m, M_WAIT, MT_DATA);
251 		m->m_len = 0;
252 		(MBC)->chain = m;
253 		if (max_bytes > MINCLSIZE)
254 			MCLGET(m, M_WAIT);
255 	}
256 	(MBC)->max_bytes = max_bytes;
257 }
258 
259 void
260 MBC_FLUSH(struct mbuf_chain *MBC)
261 {
262 	extern void	m_freem(struct mbuf *);
263 	struct mbuf	*m;
264 
265 	while ((m = (MBC)->chain) != 0) {
266 		(MBC)->chain = m->m_nextpkt;
267 		m->m_nextpkt = 0;
268 		m_freem(m);
269 	}
270 	MBC_SETUP(MBC, (MBC)->max_bytes);
271 }
272 
273 void
274 MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
275 {
276 	if (MBC->chain != 0)
277 		MBC_FLUSH(MBC);
278 
279 	(MBC)->chain_offset = 0;
280 	(MBC)->chain = (MBUF);
281 }
282 
283 void
284 MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
285 {
286 	struct mbuf	*m;
287 
288 	if ((MBC)->chain == 0) {
289 		(MBC)->chain = (MBUF);
290 	} else {
291 		m = (MBC)->chain;
292 		while (m->m_next != 0)
293 			m = m->m_next;
294 		m->m_next = (MBUF);
295 	}
296 }
297 
298 
299 void
300 MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
301 {
302 	MGET((MBC)->chain, M_WAIT, MT_DATA);
303 	(MBC)->chain_offset = 0;
304 	(MBC)->chain->m_flags |= M_EXT;
305 	(MBC)->chain->m_data = (caddr_t)(BUF);
306 	(MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
307 	(MBC)->chain->m_len = (LEN);
308 	(MBC)->chain->m_ext.ext_size = (LEN);
309 	(MBC)->chain->m_ext.ext_ref = smb_noop;
310 	(MBC)->max_bytes = (LEN);
311 }
312 
313 
314 int
315 MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
316     int OFF, int LEN)
317 {
318 	if (((OFF) + (LEN)) > (MBC)->max_bytes)
319 		return (EMSGSIZE);
320 
321 	*(SUBMBC) = *(MBC);
322 	(SUBMBC)->chain_offset = (OFF);
323 	(SUBMBC)->max_bytes = (OFF) + (LEN);
324 	(SUBMBC)->shadow_of = (MBC);
325 	return (0);
326 }
327 
328 int
329 mbc_moveout(mbuf_chain_t *mbc, caddr_t buf, int buflen, int *tlen)
330 {
331 	int	rc = 0;
332 	int	len = 0;
333 
334 	if ((mbc != NULL) && (mbc->chain != NULL)) {
335 		mbuf_t	*m;
336 
337 		m = mbc->chain;
338 		while (m) {
339 			if ((len + m->m_len) <= buflen) {
340 				bcopy(m->m_data, buf, m->m_len);
341 				buf += m->m_len;
342 				len += m->m_len;
343 				m = m->m_next;
344 				continue;
345 			}
346 			rc = EMSGSIZE;
347 			break;
348 		}
349 		m_freem(mbc->chain);
350 		mbc->chain = NULL;
351 		mbc->flags = 0;
352 	}
353 	*tlen = len;
354 	return (rc);
355 }
356 
357 /*
358  * Free a single mbuf structure.  Calls m->m_ext.ext_ref() to free any
359  * associated external buffers if present (indicated by m->m_flags & M_EXT)
360  */
361 struct mbuf *
362 m_free(struct mbuf *m)
363 {
364 	struct mbuf *n;
365 
366 	MFREE(m, n);
367 	return (n);
368 }
369 
370 /*
371  * Free a list of mbufs.  Each mbuf in the list is freed similarly to m_free.
372  */
373 void
374 m_freem(struct mbuf *m)
375 {
376 	struct mbuf *n;
377 
378 	if (m == NULL)
379 		return;
380 	/*
381 	 * Lint doesn't like the m = n assignment at the close of the loop
382 	 * but it is correct.  MFREE assigns n = (m)->m_next so the loop
383 	 * is effectively assigning m = (m)->m_next then exiting when
384 	 * m == NULL
385 	 */
386 	do {
387 		MFREE(m, n);
388 	} while ((m = n) != 0);
389 }
390 
391 /*
392  * Mbuffer utility routines.
393  */
394 
395 int /*ARGSUSED*/
396 mclref(caddr_t p, int size, int adj) /* size, adj are unused */
397 {
398 	MEM_FREE("mbuf", p);
399 	return (0);
400 }
401 
402 int /*ARGSUSED*/
403 mclrefnoop(caddr_t p, int size, int adj) /* p, size, adj are unused */
404 {
405 	return (0);
406 }
407