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 2011 Nexenta Systems, Inc. All rights reserved.
23 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27 /*
28 * Copyright (c) 1982, 1986, 1988, 1991, 1993
29 * The Regents of the University of California. All rights reserved.
30 *
31 * Redistribution and use in source and binary forms, with or without
32 * modification, are permitted provided that the following conditions
33 * are met:
34 * 1. Redistributions of source code must retain the above copyright
35 * notice, this list of conditions and the following disclaimer.
36 * 2. Redistributions in binary form must reproduce the above copyright
37 * notice, this list of conditions and the following disclaimer in the
38 * documentation and/or other materials provided with the distribution.
39 * 3. All advertising materials mentioning features or use of this software
40 * must display the following acknowledgement:
41 * This product includes software developed by the University of
42 * California, Berkeley and its contributors.
43 * 4. Neither the name of the University nor the names of its contributors
44 * may be used to endorse or promote products derived from this software
45 * without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
57 * SUCH DAMAGE.
58 *
59 */
60
61 #include <smbsrv/smb_kproto.h>
62 #include <smbsrv/smb_kstat.h>
63
64 static kmem_cache_t *smb_mbc_cache = NULL;
65
66 void
smb_mbc_init(void)67 smb_mbc_init(void)
68 {
69 if (smb_mbc_cache != NULL)
70 return;
71 smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
72 sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
73 }
74
75 void
smb_mbc_fini(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 *
smb_mbc_alloc(uint32_t max_bytes)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
smb_mbc_free(mbuf_chain_t * mbc)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 *
smb_mbuf_get(uchar_t * buf,int nbytes)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 *
smb_mbuf_allocate(struct uio * uio)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
smb_mbuf_trim(struct mbuf * mhead,int nbytes)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
MBC_LENGTH(struct mbuf_chain * MBC)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
MBC_MAXBYTES(struct mbuf_chain * MBC)230 MBC_MAXBYTES(struct mbuf_chain *MBC)
231 {
232 return (MBC->max_bytes);
233 }
234
235 void
MBC_SETUP(struct mbuf_chain * MBC,uint32_t max_bytes)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;
240 }
241
242 void
MBC_INIT(struct mbuf_chain * MBC,uint32_t max_bytes)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
MBC_FLUSH(struct mbuf_chain * MBC)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
MBC_ATTACH_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)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
MBC_APPEND_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)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
MBC_ATTACH_BUF(struct mbuf_chain * MBC,unsigned char * BUF,int LEN)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 = mclrefnoop;
310 (MBC)->max_bytes = (LEN);
311 }
312
313
314 int
MBC_SHADOW_CHAIN(struct mbuf_chain * SUBMBC,struct mbuf_chain * MBC,int OFF,int LEN)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
mbc_moveout(mbuf_chain_t * mbc,caddr_t buf,int buflen,int * tlen)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 *
m_free(struct mbuf * m)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
m_freem(struct mbuf * m)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*/
mclref(caddr_t p,int size,int adj)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*/
mclrefnoop(caddr_t p,int size,int adj)403 mclrefnoop(caddr_t p, int size, int adj) /* p, size, adj are unused */
404 {
405 return (0);
406 }
407