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