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; 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 = mclrefnoop; 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