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