xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_util.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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_incl.h>
61 #include <smbsrv/mbuf.h>
62 #include <smbsrv/smb_kstat.h>
63 
64 static kmem_cache_t	*smb_mbc_cache = NULL;
65 
66 int
67 smb_mbc_init(void)
68 {
69 	if (smb_mbc_cache == NULL) {
70 		smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
71 		    sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
72 	}
73 	return (0);
74 }
75 
76 void
77 smb_mbc_fini(void)
78 {
79 	if (smb_mbc_cache != NULL) {
80 		kmem_cache_destroy(smb_mbc_cache);
81 		smb_mbc_cache = NULL;
82 	}
83 }
84 
85 mbuf_chain_t *
86 smb_mbc_alloc(uint32_t max_bytes)
87 {
88 	mbuf_chain_t	*mbc;
89 	mbuf_t		*m;
90 
91 	mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
92 	bzero(mbc, sizeof (*mbc));
93 	mbc->mbc_magic = SMB_MBC_MAGIC;
94 
95 	if (max_bytes != 0) {
96 		MGET(m, M_WAIT, MT_DATA);
97 		m->m_len = 0;
98 		mbc->chain = m;
99 		if (max_bytes > MINCLSIZE)
100 			MCLGET(m, M_WAIT);
101 	}
102 	mbc->max_bytes = max_bytes;
103 	return (mbc);
104 }
105 
106 void
107 smb_mbc_free(mbuf_chain_t *mbc)
108 {
109 	SMB_MBC_VALID(mbc);
110 
111 	m_freem(mbc->chain);
112 	mbc->chain = NULL;
113 	mbc->mbc_magic = 0;
114 	kmem_cache_free(smb_mbc_cache, mbc);
115 }
116 
117 /*
118  * smb_mbuf_get
119  *
120  * Allocate mbufs to hold the amount of data specified.
121  * A pointer to the head of the mbuf list is returned.
122  */
123 struct mbuf *
124 smb_mbuf_get(uchar_t *buf, int nbytes)
125 {
126 	struct mbuf *mhead = 0;
127 	struct mbuf *m = 0;
128 	int count;
129 	int offset = 0;
130 
131 	while (nbytes) {
132 		count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
133 		nbytes -= count;
134 
135 		if (mhead == 0) {
136 			MGET(mhead, M_WAIT, MT_DATA);
137 			m = mhead;
138 		} else {
139 			MGET(m->m_next, M_WAIT, MT_DATA);
140 			m = m->m_next;
141 		}
142 
143 		if (count > MLEN) {
144 			MCLGET(m, M_WAIT);
145 		}
146 
147 		m->m_len = count;
148 		bcopy(buf + offset, m->m_data, count);
149 		offset += count;
150 	}
151 	return (mhead);
152 }
153 
154 /*
155  * Allocate enough mbufs to accommodate the residual count in a uio.
156  */
157 struct mbuf *
158 smb_mbuf_allocate(struct uio *uio)
159 {
160 	struct iovec *iovp;
161 	struct mbuf	*mhead = 0;
162 	struct mbuf	*m = 0;
163 	int	count, iovs, resid;
164 
165 	iovp = uio->uio_iov;
166 	iovs = uio->uio_iovcnt;
167 	resid = uio->uio_resid;
168 
169 	while ((resid > 0) && (iovs > 0)) {
170 		count = (resid > MCLBYTES) ? MCLBYTES : resid;
171 		resid -= count;
172 
173 		if (mhead == 0) {
174 			MGET(mhead, M_WAIT, MT_DATA);
175 			m = mhead;
176 		} else {
177 			MGET(m->m_next, M_WAIT, MT_DATA);
178 			m = m->m_next;
179 		}
180 
181 		if (count > MLEN) {
182 			MCLGET(m, M_WAIT);
183 		}
184 
185 		iovp->iov_base = m->m_data;
186 		iovp->iov_len = m->m_len = count;
187 		iovs--;
188 		iovp++;
189 	}
190 
191 	uio->uio_iovcnt -= iovs;
192 	return (mhead);
193 }
194 
195 /*
196  * Trim an mbuf chain to nbytes.
197  */
198 void
199 smb_mbuf_trim(struct mbuf *mhead, int nbytes)
200 {
201 	struct mbuf	*m = mhead;
202 
203 	while (m != 0) {
204 		if (nbytes <= m->m_len) {
205 			m->m_len = nbytes;
206 			if (m->m_next != 0) {
207 				m_freem(m->m_next);
208 				m->m_next = 0;
209 			}
210 			break;
211 		}
212 		nbytes -= m->m_len;
213 		m = m->m_next;
214 	}
215 }
216 
217 int
218 MBC_LENGTH(struct mbuf_chain *MBC)
219 {
220 	struct mbuf	*m = (MBC)->chain;
221 	int		used = 0;
222 
223 	while (m != 0) {
224 		used += m->m_len;
225 		m = m->m_next;
226 	}
227 	return (used);
228 }
229 
230 int
231 MBC_MAXBYTES(struct mbuf_chain *MBC)
232 {
233 	return (MBC->max_bytes);
234 }
235 
236 void
237 MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
238 {
239 	bzero((MBC), sizeof (struct mbuf_chain));
240 	(MBC)->max_bytes = max_bytes ? max_bytes : smb_maxbufsize;
241 }
242 
243 void
244 MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
245 {
246 	struct mbuf *m;
247 
248 	bzero((MBC), sizeof (struct mbuf_chain));
249 
250 	if (max_bytes != 0) {
251 		MGET(m, M_WAIT, MT_DATA);
252 		m->m_len = 0;
253 		(MBC)->chain = m;
254 		if (max_bytes > MINCLSIZE)
255 			MCLGET(m, M_WAIT);
256 	}
257 	(MBC)->max_bytes = max_bytes;
258 }
259 
260 void
261 MBC_FLUSH(struct mbuf_chain *MBC)
262 {
263 	extern void	m_freem(struct mbuf *);
264 	struct mbuf	*m;
265 
266 	while ((m = (MBC)->chain) != 0) {
267 		(MBC)->chain = m->m_nextpkt;
268 		m->m_nextpkt = 0;
269 		m_freem(m);
270 	}
271 	MBC_SETUP(MBC, (MBC)->max_bytes);
272 }
273 
274 void
275 MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
276 {
277 	if (MBC->chain != 0)
278 		MBC_FLUSH(MBC);
279 
280 	(MBC)->chain_offset = 0;
281 	(MBC)->chain = (MBUF);
282 }
283 
284 void
285 MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
286 {
287 	struct mbuf	*m;
288 
289 	if ((MBC)->chain == 0) {
290 		(MBC)->chain = (MBUF);
291 	} else {
292 		m = (MBC)->chain;
293 		while (m->m_next != 0)
294 			m = m->m_next;
295 		m->m_next = (MBUF);
296 	}
297 }
298 
299 
300 void
301 MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
302 {
303 	MGET((MBC)->chain, M_WAIT, MT_DATA);
304 	(MBC)->chain_offset = 0;
305 	(MBC)->chain->m_flags |= M_EXT;
306 	(MBC)->chain->m_data = (caddr_t)(BUF);
307 	(MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
308 	(MBC)->chain->m_len = (LEN);
309 	(MBC)->chain->m_ext.ext_size = (LEN);
310 	(MBC)->chain->m_ext.ext_ref = smb_noop;
311 	(MBC)->max_bytes = (LEN);
312 }
313 
314 
315 int
316 MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
317     int OFF, int LEN)
318 {
319 	if (((OFF) + (LEN)) > (MBC)->max_bytes)
320 		return (EMSGSIZE);
321 
322 	*(SUBMBC) = *(MBC);
323 	(SUBMBC)->chain_offset = (OFF);
324 	(SUBMBC)->max_bytes = (OFF) + (LEN);
325 	(SUBMBC)->shadow_of = (MBC);
326 	return (0);
327 }
328 
329 int
330 mbc_moveout(mbuf_chain_t *mbc, caddr_t buf, int buflen, int *tlen)
331 {
332 	int	rc = 0;
333 	int	len = 0;
334 
335 	if ((mbc != NULL) && (mbc->chain != NULL)) {
336 		mbuf_t	*m;
337 
338 		m = mbc->chain;
339 		while (m) {
340 			if ((len + m->m_len) <= buflen) {
341 				bcopy(m->m_data, buf, m->m_len);
342 				buf += m->m_len;
343 				len += m->m_len;
344 				m = m->m_next;
345 				continue;
346 			}
347 			rc = EMSGSIZE;
348 			break;
349 		}
350 		m_freem(mbc->chain);
351 		mbc->chain = NULL;
352 		mbc->flags = 0;
353 	}
354 	*tlen = len;
355 	return (rc);
356 }
357 
358 /*
359  * Free a single mbuf structure.  Calls m->m_ext.ext_ref() to free any
360  * associated external buffers if present (indicated by m->m_flags & M_EXT)
361  */
362 struct mbuf *
363 m_free(struct mbuf *m)
364 {
365 	struct mbuf *n;
366 
367 	MFREE(m, n);
368 	return (n);
369 }
370 
371 /*
372  * Free a list of mbufs.  Each mbuf in the list is freed similarly to m_free.
373  */
374 void
375 m_freem(struct mbuf *m)
376 {
377 	struct mbuf *n;
378 
379 	if (m == NULL)
380 		return;
381 	/*
382 	 * Lint doesn't like the m = n assignment at the close of the loop
383 	 * but it is correct.  MFREE assigns n = (m)->m_next so the loop
384 	 * is effectively assigning m = (m)->m_next then exiting when
385 	 * m == NULL
386 	 */
387 	do {
388 		MFREE(m, n);
389 	} while ((m = n) != 0);
390 }
391 
392 /*
393  * Mbuffer utility routines.
394  */
395 
396 int /*ARGSUSED*/
397 mclref(caddr_t p, int size, int adj) /* size, adj are unused */
398 {
399 	MEM_FREE("mbuf", p);
400 	return (0);
401 }
402 
403 int /*ARGSUSED*/
404 mclrefnoop(caddr_t p, int size, int adj) /* p, size, adj are unused */
405 {
406 	return (0);
407 }
408