15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
215331Samw /*
228934SJose.Borrego@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
235331Samw * Use is subject to license terms.
245331Samw */
255331Samw
265331Samw /*
275331Samw * Copyright (c) 1982, 1986, 1988, 1991, 1993
285331Samw * The Regents of the University of California. All rights reserved.
295331Samw *
305331Samw * Redistribution and use in source and binary forms, with or without
315331Samw * modification, are permitted provided that the following conditions
325331Samw * are met:
335331Samw * 1. Redistributions of source code must retain the above copyright
345331Samw * notice, this list of conditions and the following disclaimer.
355331Samw * 2. Redistributions in binary form must reproduce the above copyright
365331Samw * notice, this list of conditions and the following disclaimer in the
375331Samw * documentation and/or other materials provided with the distribution.
385331Samw * 3. All advertising materials mentioning features or use of this software
395331Samw * must display the following acknowledgement:
405331Samw * This product includes software developed by the University of
415331Samw * California, Berkeley and its contributors.
425331Samw * 4. Neither the name of the University nor the names of its contributors
435331Samw * may be used to endorse or promote products derived from this software
445331Samw * without specific prior written permission.
455331Samw *
465331Samw * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
475331Samw * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
485331Samw * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
495331Samw * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
505331Samw * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
515331Samw * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
525331Samw * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
535331Samw * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
545331Samw * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
555331Samw * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
565331Samw * SUCH DAMAGE.
575331Samw *
585331Samw */
595331Samw
60*10966SJordan.Brown@Sun.COM #include <smbsrv/smb_kproto.h>
618934SJose.Borrego@Sun.COM #include <smbsrv/smb_kstat.h>
628934SJose.Borrego@Sun.COM
638934SJose.Borrego@Sun.COM static kmem_cache_t *smb_mbc_cache = NULL;
648934SJose.Borrego@Sun.COM
658934SJose.Borrego@Sun.COM int
smb_mbc_init(void)668934SJose.Borrego@Sun.COM smb_mbc_init(void)
678934SJose.Borrego@Sun.COM {
688934SJose.Borrego@Sun.COM if (smb_mbc_cache == NULL) {
698934SJose.Borrego@Sun.COM smb_mbc_cache = kmem_cache_create(SMBSRV_KSTAT_MBC_CACHE,
708934SJose.Borrego@Sun.COM sizeof (mbuf_chain_t), 8, NULL, NULL, NULL, NULL, NULL, 0);
718934SJose.Borrego@Sun.COM }
728934SJose.Borrego@Sun.COM return (0);
738934SJose.Borrego@Sun.COM }
748934SJose.Borrego@Sun.COM
758934SJose.Borrego@Sun.COM void
smb_mbc_fini(void)768934SJose.Borrego@Sun.COM smb_mbc_fini(void)
778934SJose.Borrego@Sun.COM {
788934SJose.Borrego@Sun.COM if (smb_mbc_cache != NULL) {
798934SJose.Borrego@Sun.COM kmem_cache_destroy(smb_mbc_cache);
808934SJose.Borrego@Sun.COM smb_mbc_cache = NULL;
818934SJose.Borrego@Sun.COM }
828934SJose.Borrego@Sun.COM }
838934SJose.Borrego@Sun.COM
848934SJose.Borrego@Sun.COM mbuf_chain_t *
smb_mbc_alloc(uint32_t max_bytes)858934SJose.Borrego@Sun.COM smb_mbc_alloc(uint32_t max_bytes)
868934SJose.Borrego@Sun.COM {
878934SJose.Borrego@Sun.COM mbuf_chain_t *mbc;
888934SJose.Borrego@Sun.COM mbuf_t *m;
898934SJose.Borrego@Sun.COM
908934SJose.Borrego@Sun.COM mbc = kmem_cache_alloc(smb_mbc_cache, KM_SLEEP);
918934SJose.Borrego@Sun.COM bzero(mbc, sizeof (*mbc));
928934SJose.Borrego@Sun.COM mbc->mbc_magic = SMB_MBC_MAGIC;
938934SJose.Borrego@Sun.COM
948934SJose.Borrego@Sun.COM if (max_bytes != 0) {
958934SJose.Borrego@Sun.COM MGET(m, M_WAIT, MT_DATA);
968934SJose.Borrego@Sun.COM m->m_len = 0;
978934SJose.Borrego@Sun.COM mbc->chain = m;
988934SJose.Borrego@Sun.COM if (max_bytes > MINCLSIZE)
998934SJose.Borrego@Sun.COM MCLGET(m, M_WAIT);
1008934SJose.Borrego@Sun.COM }
1018934SJose.Borrego@Sun.COM mbc->max_bytes = max_bytes;
1028934SJose.Borrego@Sun.COM return (mbc);
1038934SJose.Borrego@Sun.COM }
1048934SJose.Borrego@Sun.COM
1058934SJose.Borrego@Sun.COM void
smb_mbc_free(mbuf_chain_t * mbc)1068934SJose.Borrego@Sun.COM smb_mbc_free(mbuf_chain_t *mbc)
1078934SJose.Borrego@Sun.COM {
1088934SJose.Borrego@Sun.COM SMB_MBC_VALID(mbc);
1098934SJose.Borrego@Sun.COM
1108934SJose.Borrego@Sun.COM m_freem(mbc->chain);
1118934SJose.Borrego@Sun.COM mbc->chain = NULL;
1128934SJose.Borrego@Sun.COM mbc->mbc_magic = 0;
1138934SJose.Borrego@Sun.COM kmem_cache_free(smb_mbc_cache, mbc);
1148934SJose.Borrego@Sun.COM }
1155331Samw
1165331Samw /*
1175331Samw * smb_mbuf_get
1185331Samw *
1195331Samw * Allocate mbufs to hold the amount of data specified.
1205331Samw * A pointer to the head of the mbuf list is returned.
1215331Samw */
1225331Samw struct mbuf *
smb_mbuf_get(uchar_t * buf,int nbytes)1235331Samw smb_mbuf_get(uchar_t *buf, int nbytes)
1245331Samw {
1255331Samw struct mbuf *mhead = 0;
1265331Samw struct mbuf *m = 0;
1275331Samw int count;
1285331Samw int offset = 0;
1295331Samw
1305331Samw while (nbytes) {
1315331Samw count = (nbytes > MCLBYTES) ? MCLBYTES : nbytes;
1325331Samw nbytes -= count;
1335331Samw
1345331Samw if (mhead == 0) {
1355331Samw MGET(mhead, M_WAIT, MT_DATA);
1365331Samw m = mhead;
1375331Samw } else {
1385331Samw MGET(m->m_next, M_WAIT, MT_DATA);
1395331Samw m = m->m_next;
1405331Samw }
1415331Samw
1425331Samw if (count > MLEN) {
1435331Samw MCLGET(m, M_WAIT);
1445331Samw }
1455331Samw
1465331Samw m->m_len = count;
1475331Samw bcopy(buf + offset, m->m_data, count);
1485331Samw offset += count;
1495331Samw }
1505331Samw return (mhead);
1515331Samw }
1525331Samw
1535331Samw /*
1545331Samw * Allocate enough mbufs to accommodate the residual count in a uio.
1555331Samw */
1565331Samw struct mbuf *
smb_mbuf_allocate(struct uio * uio)1575331Samw smb_mbuf_allocate(struct uio *uio)
1585331Samw {
1595331Samw struct iovec *iovp;
1605331Samw struct mbuf *mhead = 0;
1615331Samw struct mbuf *m = 0;
1625331Samw int count, iovs, resid;
1635331Samw
1645331Samw iovp = uio->uio_iov;
1655331Samw iovs = uio->uio_iovcnt;
1665331Samw resid = uio->uio_resid;
1675331Samw
1685331Samw while ((resid > 0) && (iovs > 0)) {
1695331Samw count = (resid > MCLBYTES) ? MCLBYTES : resid;
1705331Samw resid -= count;
1715331Samw
1725331Samw if (mhead == 0) {
1735331Samw MGET(mhead, M_WAIT, MT_DATA);
1745331Samw m = mhead;
1755331Samw } else {
1765331Samw MGET(m->m_next, M_WAIT, MT_DATA);
1775331Samw m = m->m_next;
1785331Samw }
1795331Samw
1805331Samw if (count > MLEN) {
1815331Samw MCLGET(m, M_WAIT);
1825331Samw }
1835331Samw
1845331Samw iovp->iov_base = m->m_data;
1855331Samw iovp->iov_len = m->m_len = count;
1865331Samw iovs--;
1875331Samw iovp++;
1885331Samw }
1895331Samw
1905331Samw uio->uio_iovcnt -= iovs;
1915331Samw return (mhead);
1925331Samw }
1935331Samw
1945331Samw /*
1955331Samw * Trim an mbuf chain to nbytes.
1965331Samw */
1975331Samw void
smb_mbuf_trim(struct mbuf * mhead,int nbytes)1985331Samw smb_mbuf_trim(struct mbuf *mhead, int nbytes)
1995331Samw {
2005331Samw struct mbuf *m = mhead;
2015331Samw
2025331Samw while (m != 0) {
2035331Samw if (nbytes <= m->m_len) {
2045331Samw m->m_len = nbytes;
2055331Samw if (m->m_next != 0) {
2065331Samw m_freem(m->m_next);
2075331Samw m->m_next = 0;
2085331Samw }
2095331Samw break;
2105331Samw }
2115331Samw nbytes -= m->m_len;
2125331Samw m = m->m_next;
2135331Samw }
2145331Samw }
2155331Samw
2165331Samw int
MBC_LENGTH(struct mbuf_chain * MBC)2175331Samw MBC_LENGTH(struct mbuf_chain *MBC)
2185331Samw {
2195331Samw struct mbuf *m = (MBC)->chain;
2205331Samw int used = 0;
2215331Samw
2225331Samw while (m != 0) {
2235331Samw used += m->m_len;
2245331Samw m = m->m_next;
2255331Samw }
2265331Samw return (used);
2275331Samw }
2285331Samw
2296771Sjb150015 int
MBC_MAXBYTES(struct mbuf_chain * MBC)2306771Sjb150015 MBC_MAXBYTES(struct mbuf_chain *MBC)
2316771Sjb150015 {
2326771Sjb150015 return (MBC->max_bytes);
2336771Sjb150015 }
2346771Sjb150015
2355331Samw void
MBC_SETUP(struct mbuf_chain * MBC,uint32_t max_bytes)2365331Samw MBC_SETUP(struct mbuf_chain *MBC, uint32_t max_bytes)
2375331Samw {
2385331Samw bzero((MBC), sizeof (struct mbuf_chain));
2395331Samw (MBC)->max_bytes = max_bytes ? max_bytes : smb_maxbufsize;
2405331Samw }
2415331Samw
2425331Samw void
MBC_INIT(struct mbuf_chain * MBC,uint32_t max_bytes)2435331Samw MBC_INIT(struct mbuf_chain *MBC, uint32_t max_bytes)
2445331Samw {
2455331Samw struct mbuf *m;
2465331Samw
2475331Samw bzero((MBC), sizeof (struct mbuf_chain));
2485331Samw
2495331Samw if (max_bytes != 0) {
2505331Samw MGET(m, M_WAIT, MT_DATA);
2515331Samw m->m_len = 0;
2525331Samw (MBC)->chain = m;
2535331Samw if (max_bytes > MINCLSIZE)
2545331Samw MCLGET(m, M_WAIT);
2555331Samw }
2565331Samw (MBC)->max_bytes = max_bytes;
2575331Samw }
2585331Samw
2595331Samw void
MBC_FLUSH(struct mbuf_chain * MBC)2605331Samw MBC_FLUSH(struct mbuf_chain *MBC)
2615331Samw {
2625331Samw extern void m_freem(struct mbuf *);
2635331Samw struct mbuf *m;
2645331Samw
2655331Samw while ((m = (MBC)->chain) != 0) {
2665331Samw (MBC)->chain = m->m_nextpkt;
2675331Samw m->m_nextpkt = 0;
2685331Samw m_freem(m);
2695331Samw }
2705331Samw MBC_SETUP(MBC, (MBC)->max_bytes);
2715331Samw }
2725331Samw
2735331Samw void
MBC_ATTACH_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)2745331Samw MBC_ATTACH_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
2755331Samw {
2765331Samw if (MBC->chain != 0)
2775331Samw MBC_FLUSH(MBC);
2785331Samw
2795331Samw (MBC)->chain_offset = 0;
2805331Samw (MBC)->chain = (MBUF);
2815331Samw }
2825331Samw
2835331Samw void
MBC_APPEND_MBUF(struct mbuf_chain * MBC,struct mbuf * MBUF)2845331Samw MBC_APPEND_MBUF(struct mbuf_chain *MBC, struct mbuf *MBUF)
2855331Samw {
2865331Samw struct mbuf *m;
2875331Samw
2885331Samw if ((MBC)->chain == 0) {
2895331Samw (MBC)->chain = (MBUF);
2905331Samw } else {
2915331Samw m = (MBC)->chain;
2925331Samw while (m->m_next != 0)
2935331Samw m = m->m_next;
2945331Samw m->m_next = (MBUF);
2955331Samw }
2965331Samw }
2975331Samw
2985331Samw
2995331Samw void
MBC_ATTACH_BUF(struct mbuf_chain * MBC,unsigned char * BUF,int LEN)3005331Samw MBC_ATTACH_BUF(struct mbuf_chain *MBC, unsigned char *BUF, int LEN)
3015331Samw {
3025331Samw MGET((MBC)->chain, M_WAIT, MT_DATA);
3035331Samw (MBC)->chain_offset = 0;
3045331Samw (MBC)->chain->m_flags |= M_EXT;
3055331Samw (MBC)->chain->m_data = (caddr_t)(BUF);
3065331Samw (MBC)->chain->m_ext.ext_buf = (caddr_t)(BUF);
3075331Samw (MBC)->chain->m_len = (LEN);
3085331Samw (MBC)->chain->m_ext.ext_size = (LEN);
3095331Samw (MBC)->chain->m_ext.ext_ref = smb_noop;
3105331Samw (MBC)->max_bytes = (LEN);
3115331Samw }
3125331Samw
3135331Samw
3145331Samw int
MBC_SHADOW_CHAIN(struct mbuf_chain * SUBMBC,struct mbuf_chain * MBC,int OFF,int LEN)3155331Samw MBC_SHADOW_CHAIN(struct mbuf_chain *SUBMBC, struct mbuf_chain *MBC,
3165331Samw int OFF, int LEN)
3175331Samw {
3185331Samw if (((OFF) + (LEN)) > (MBC)->max_bytes)
3195331Samw return (EMSGSIZE);
3205331Samw
3215331Samw *(SUBMBC) = *(MBC);
3225331Samw (SUBMBC)->chain_offset = (OFF);
3235331Samw (SUBMBC)->max_bytes = (OFF) + (LEN);
3245331Samw (SUBMBC)->shadow_of = (MBC);
3255331Samw return (0);
3265331Samw }
3275331Samw
3286496Sjb150015 int
mbc_moveout(mbuf_chain_t * mbc,caddr_t buf,int buflen,int * tlen)3296496Sjb150015 mbc_moveout(mbuf_chain_t *mbc, caddr_t buf, int buflen, int *tlen)
3306496Sjb150015 {
3316496Sjb150015 int rc = 0;
3326496Sjb150015 int len = 0;
3336496Sjb150015
3346496Sjb150015 if ((mbc != NULL) && (mbc->chain != NULL)) {
3356496Sjb150015 mbuf_t *m;
3366496Sjb150015
3376496Sjb150015 m = mbc->chain;
3386496Sjb150015 while (m) {
3396496Sjb150015 if ((len + m->m_len) <= buflen) {
3406496Sjb150015 bcopy(m->m_data, buf, m->m_len);
3416496Sjb150015 buf += m->m_len;
3426496Sjb150015 len += m->m_len;
3436496Sjb150015 m = m->m_next;
3446496Sjb150015 continue;
3456496Sjb150015 }
3466496Sjb150015 rc = EMSGSIZE;
3476496Sjb150015 break;
3486496Sjb150015 }
3496496Sjb150015 m_freem(mbc->chain);
3506496Sjb150015 mbc->chain = NULL;
3516496Sjb150015 mbc->flags = 0;
3526496Sjb150015 }
3536496Sjb150015 *tlen = len;
3546496Sjb150015 return (rc);
3556496Sjb150015 }
3566496Sjb150015
3575331Samw /*
3585331Samw * Free a single mbuf structure. Calls m->m_ext.ext_ref() to free any
3595331Samw * associated external buffers if present (indicated by m->m_flags & M_EXT)
3605331Samw */
3615331Samw struct mbuf *
m_free(struct mbuf * m)3625331Samw m_free(struct mbuf *m)
3635331Samw {
3645331Samw struct mbuf *n;
3655331Samw
3665331Samw MFREE(m, n);
3675331Samw return (n);
3685331Samw }
3695331Samw
3705331Samw /*
3715331Samw * Free a list of mbufs. Each mbuf in the list is freed similarly to m_free.
3725331Samw */
3735331Samw void
m_freem(struct mbuf * m)3745331Samw m_freem(struct mbuf *m)
3755331Samw {
3765331Samw struct mbuf *n;
3775331Samw
3785331Samw if (m == NULL)
3795331Samw return;
3805331Samw /*
3815331Samw * Lint doesn't like the m = n assignment at the close of the loop
3825331Samw * but it is correct. MFREE assigns n = (m)->m_next so the loop
3835331Samw * is effectively assigning m = (m)->m_next then exiting when
3845331Samw * m == NULL
3855331Samw */
3865331Samw do {
3875331Samw MFREE(m, n);
3885331Samw } while ((m = n) != 0);
3895331Samw }
3905331Samw
3915331Samw /*
3925331Samw * Mbuffer utility routines.
3935331Samw */
3945331Samw
3955331Samw int /*ARGSUSED*/
mclref(caddr_t p,int size,int adj)3965331Samw mclref(caddr_t p, int size, int adj) /* size, adj are unused */
3975331Samw {
3985331Samw MEM_FREE("mbuf", p);
3995331Samw return (0);
4005331Samw }
4015331Samw
4025331Samw int /*ARGSUSED*/
mclrefnoop(caddr_t p,int size,int adj)4035331Samw mclrefnoop(caddr_t p, int size, int adj) /* p, size, adj are unused */
4045331Samw {
4055331Samw return (0);
4065331Samw }
407