Home | History | Annotate | Download | only in smbsrv
      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 ? max_bytes : smb_maxbufsize;
    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 = smb_noop;
    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