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