root/src/libs/compat/openbsd_network/compat/sys/mbuf-obsd.h
/*      $OpenBSD: uipc_mbuf.c,v 1.283 2022/02/22 01:15:01 guenther Exp $        */
/*      $NetBSD: uipc_mbuf.c,v 1.15.4.1 1996/06/13 17:11:44 cgd Exp $   */

/*
 * Copyright (c) 1982, 1986, 1988, 1991, 1993
 *      The Regents of the University of California.  All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 *      @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
 */

/*
 *      @(#)COPYRIGHT   1.1 (NRL) 17 January 1995
 *
 * NRL grants permission for redistribution and use in source and binary
 * forms, with or without modification, of the software and documentation
 * created at NRL provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgements:
 *      This product includes software developed by the University of
 *      California, Berkeley and its contributors.
 *      This product includes software developed at the Information
 *      Technology Division, US Naval Research Laboratory.
 * 4. Neither the name of the NRL nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL NRL OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * The views and conclusions contained in the software and documentation
 * are those of the authors and should not be interpreted as representing
 * official policies, either expressed or implied, of the US Naval
 * Research Laboratory (NRL).
 */

struct mbuf_list {
        struct mbuf             *ml_head;
        struct mbuf             *ml_tail;
        u_int                   ml_len;
};

struct mbuf_queue {
        struct mutex            mq_mtx;
        struct mbuf_list        mq_list;
        u_int                   mq_maxlen;
        u_int                   mq_drops;
};


static struct mbuf *
m_dup_pkt(struct mbuf *m0, unsigned int adj, int wait)
{
        struct mbuf *m;
        int len;

        KASSERT(m0->m_flags & M_PKTHDR);

        len = m0->m_pkthdr.len + adj;
        if (len > MAXMCLBYTES) /* XXX */
                return (NULL);

        m = m_get(wait, m0->m_type);
        if (m == NULL)
                return (NULL);

        if (m_dup_pkthdr(m, m0, wait) != 0)
                goto fail;

        if (len > MHLEN) {
                MCLGETL(m, wait, len);
                if (!ISSET(m->m_flags, M_EXT))
                        goto fail;
        }

        m->m_len = m->m_pkthdr.len = len;
        m_adj(m, adj);
        m_copydata(m0, 0, m0->m_pkthdr.len, mtod(m, caddr_t));

        return (m);

fail:
        m_freem(m);
        return (NULL);
}


/*
 * Compute the amount of space available after the end of data in an mbuf.
 * Read-only clusters never have space available.
 */
static int
m_trailingspace(struct mbuf *m)
{
        if (M_READONLY(m))
                return 0;
        KASSERT(M_DATABUF(m) + M_SIZE(m) >= (m->m_data + m->m_len));
        return M_DATABUF(m) + M_SIZE(m) - (m->m_data + m->m_len);
}


/*
 * mbuf lists
 */

#define MBUF_LIST_INITIALIZER() { NULL, NULL, 0 }

#define ml_len(_ml)             ((_ml)->ml_len)
#define ml_empty(_ml)           ((_ml)->ml_len == 0)

#define MBUF_LIST_FIRST(_ml)    ((_ml)->ml_head)
#define MBUF_LIST_NEXT(_m)      ((_m)->m_nextpkt)

#define MBUF_LIST_FOREACH(_ml, _m)                                      \
        for ((_m) = MBUF_LIST_FIRST(_ml);                               \
                (_m) != NULL;                                           \
                (_m) = MBUF_LIST_NEXT(_m))

static void
ml_init(struct mbuf_list *ml)
{
        ml->ml_head = ml->ml_tail = NULL;
        ml->ml_len = 0;
}

static void
ml_enqueue(struct mbuf_list *ml, struct mbuf *m)
{
        if (ml->ml_tail == NULL)
                ml->ml_head = ml->ml_tail = m;
        else {
                ml->ml_tail->m_nextpkt = m;
                ml->ml_tail = m;
        }

        m->m_nextpkt = NULL;
        ml->ml_len++;
}

static void
ml_enlist(struct mbuf_list *mla, struct mbuf_list *mlb)
{
        if (!ml_empty(mlb)) {
                if (ml_empty(mla))
                        mla->ml_head = mlb->ml_head;
                else
                        mla->ml_tail->m_nextpkt = mlb->ml_head;
                mla->ml_tail = mlb->ml_tail;
                mla->ml_len += mlb->ml_len;

                ml_init(mlb);
        }
}

static struct mbuf *
ml_dequeue(struct mbuf_list *ml)
{
        struct mbuf *m;

        m = ml->ml_head;
        if (m != NULL) {
                ml->ml_head = m->m_nextpkt;
                if (ml->ml_head == NULL)
                        ml->ml_tail = NULL;

                m->m_nextpkt = NULL;
                ml->ml_len--;
        }

        return (m);
}

static struct mbuf *
ml_dechain(struct mbuf_list *ml)
{
        struct mbuf *m0;

        m0 = ml->ml_head;

        ml_init(ml);

        return (m0);
}

static unsigned int
ml_purge(struct mbuf_list *ml)
{
        struct mbuf *m, *n;
        unsigned int len;

        for (m = ml->ml_head; m != NULL; m = n) {
                n = m->m_nextpkt;
                m_freem(m);
        }

        len = ml->ml_len;
        ml_init(ml);

        return (len);
}

static unsigned int
ml_hdatalen(struct mbuf_list *ml)
{
        struct mbuf *m;

        m = ml->ml_head;
        if (m == NULL)
                return (0);

        KASSERT(ISSET(m->m_flags, M_PKTHDR));
        return (m->m_pkthdr.len);
}


/*
 * mbuf queues
 */

#define MBUF_QUEUE_INITIALIZER(_maxlen, _ipl) \
        { MUTEX_INITIALIZER(_ipl), MBUF_LIST_INITIALIZER(), (_maxlen), 0 }

#define mq_len(_mq)             ml_len(&(_mq)->mq_list)
#define mq_empty(_mq)           ml_empty(&(_mq)->mq_list)
#define mq_full(_mq)            (mq_len((_mq)) >= (_mq)->mq_maxlen)
#define mq_drops(_mq)           ((_mq)->mq_drops)
#define mq_set_maxlen(_mq, _l)  ((_mq)->mq_maxlen = (_l))

static void
mq_init(struct mbuf_queue *mq, u_int maxlen, int ipl)
{
        mtx_init(&mq->mq_mtx, ipl);
        ml_init(&mq->mq_list);
        mq->mq_maxlen = maxlen;
}

static int
mq_push(struct mbuf_queue *mq, struct mbuf *m)
{
        struct mbuf *dropped = NULL;

        mtx_enter(&mq->mq_mtx);
        if (mq_len(mq) >= mq->mq_maxlen) {
                mq->mq_drops++;
                dropped = ml_dequeue(&mq->mq_list);
        }
        ml_enqueue(&mq->mq_list, m);
        mtx_leave(&mq->mq_mtx);

        if (dropped)
                m_freem(dropped);

        return (dropped != NULL);
}

static int
mq_enqueue(struct mbuf_queue *mq, struct mbuf *m)
{
        int dropped = 0;

        mtx_enter(&mq->mq_mtx);
        if (mq_len(mq) < mq->mq_maxlen)
                ml_enqueue(&mq->mq_list, m);
        else {
                mq->mq_drops++;
                dropped = 1;
        }
        mtx_leave(&mq->mq_mtx);

        if (dropped)
                m_freem(m);

        return (dropped);
}

static struct mbuf *
mq_dequeue(struct mbuf_queue *mq)
{
        struct mbuf *m;

        mtx_enter(&mq->mq_mtx);
        m = ml_dequeue(&mq->mq_list);
        mtx_leave(&mq->mq_mtx);

        return (m);
}

static int
mq_enlist(struct mbuf_queue *mq, struct mbuf_list *ml)
{
        struct mbuf *m;
        int dropped = 0;

        mtx_enter(&mq->mq_mtx);
        if (mq_len(mq) < mq->mq_maxlen)
                ml_enlist(&mq->mq_list, ml);
        else {
                dropped = ml_len(ml);
                mq->mq_drops += dropped;
        }
        mtx_leave(&mq->mq_mtx);

        if (dropped) {
                while ((m = ml_dequeue(ml)) != NULL)
                        m_freem(m);
        }

        return (dropped);
}

static void
mq_delist(struct mbuf_queue *mq, struct mbuf_list *ml)
{
        mtx_enter(&mq->mq_mtx);
        *ml = mq->mq_list;
        ml_init(&mq->mq_list);
        mtx_leave(&mq->mq_mtx);
}

static struct mbuf *
mq_dechain(struct mbuf_queue *mq)
{
        struct mbuf *m0;

        mtx_enter(&mq->mq_mtx);
        m0 = ml_dechain(&mq->mq_list);
        mtx_leave(&mq->mq_mtx);

        return (m0);
}

static unsigned int
mq_purge(struct mbuf_queue *mq)
{
        struct mbuf_list ml;

        mq_delist(mq, &ml);

        return (ml_purge(&ml));
}

static unsigned int
mq_hdatalen(struct mbuf_queue *mq)
{
        unsigned int hdatalen;

        mtx_enter(&mq->mq_mtx);
        hdatalen = ml_hdatalen(&mq->mq_list);
        mtx_leave(&mq->mq_mtx);

        return (hdatalen);
}