diff options
Diffstat (limited to 'cpukit/libnetworking/kern/uipc_mbuf.c')
-rw-r--r-- | cpukit/libnetworking/kern/uipc_mbuf.c | 742 |
1 files changed, 0 insertions, 742 deletions
diff --git a/cpukit/libnetworking/kern/uipc_mbuf.c b/cpukit/libnetworking/kern/uipc_mbuf.c deleted file mode 100644 index 2267ddbe61..0000000000 --- a/cpukit/libnetworking/kern/uipc_mbuf.c +++ /dev/null @@ -1,742 +0,0 @@ -#include <machine/rtems-bsd-kernel-space.h> - -/* - * 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. - * 4. 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 - */ - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/proc.h> -#include <sys/malloc.h> -#define MBTYPES -#include <sys/mbuf.h> -#include <sys/kernel.h> -#include <sys/syslog.h> -#include <sys/domain.h> -#include <sys/protosw.h> - -#include <vm/vm.h> -#include <vm/vm_param.h> -#include <vm/vm_kern.h> -#include <vm/vm_extern.h> - -#if !defined(__rtems__) -static void mbinit (void *) __attribute__ ((unused)); -SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbinit, NULL) -#endif - -struct mbuf *mbutl; -char *mclrefcnt; -struct mbstat mbstat; -struct mbuf *mmbfree; -union mcluster *mclfree; -int max_linkhdr; -int max_protohdr; -int max_hdr; -int max_datalen; - -/* "number of clusters of pages" */ -#define NCL_INIT 1 - -#define NMB_INIT 16 - -/* - * When MGET failes, ask protocols to free space when short of memory, - * then re-attempt to allocate an mbuf. - */ -struct mbuf * -m_retry(int i, int t) -{ - register struct mbuf *m; - - m_reclaim(); -#define m_retry(i, t) (struct mbuf *)0 - MGET(m, i, t); -#undef m_retry - if (m != NULL) - mbstat.m_wait++; - else - mbstat.m_drops++; - return (m); -} - -/* - * As above; retry an MGETHDR. - */ -struct mbuf * -m_retryhdr(int i, int t) -{ - register struct mbuf *m; - - m_reclaim(); -#define m_retryhdr(i, t) (struct mbuf *)0 - MGETHDR(m, i, t); -#undef m_retryhdr - if (m != NULL) - mbstat.m_wait++; - else - mbstat.m_drops++; - return (m); -} - -void -m_reclaim(void) -{ - register struct domain *dp; - register struct protosw *pr; - int s = splimp(); - - for (dp = domains; dp; dp = dp->dom_next) - for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) - if (pr->pr_drain) - (*pr->pr_drain)(); - splx(s); - mbstat.m_drain++; -} - -/* - * Space allocation routines. - * These are also available as macros - * for critical paths. - */ -struct mbuf * -m_get(int nowait, int type) -{ - register struct mbuf *m; - - MGET(m, nowait, type); - return (m); -} - -struct mbuf * -m_gethdr(int nowait, int type) -{ - register struct mbuf *m; - - MGETHDR(m, nowait, type); - return (m); -} - -struct mbuf * -m_getclr(int nowait, int type) -{ - register struct mbuf *m; - - MGET(m, nowait, type); - if (m == 0) - return (0); - bzero(mtod(m, caddr_t), MLEN); - return (m); -} - -struct mbuf * -m_free(struct mbuf *m) -{ - struct mbuf *n; - - MFREE(m, n); - return (n); -} - -void -m_freem(struct mbuf *mb) -{ - struct mbuf *n; - - if (mb == NULL) - return; - do { - MFREE(mb, n); - mb = n; - } while (mb); -} - -/* - * Mbuffer utility routines. - */ - -/* - * Lesser-used path for M_PREPEND: - * allocate new mbuf to prepend to chain, - * copy junk along. - */ -struct mbuf * -m_prepend(struct mbuf *m, int len, int how) -{ - struct mbuf *mn; - - MGET(mn, how, m->m_type); - if (mn == (struct mbuf *)NULL) { - m_freem(m); - return ((struct mbuf *)NULL); - } - if (m->m_flags & M_PKTHDR) { - M_COPY_PKTHDR(mn, m); - m->m_flags &= ~M_PKTHDR; - } - mn->m_next = m; - m = mn; - if (len < MHLEN) - MH_ALIGN(m, len); - m->m_len = len; - return (m); -} - -/* - * Make a copy of an mbuf chain starting "off0" bytes from the beginning, - * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf. - * The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller. - */ -static int MCFail; - -struct mbuf * -m_copym(struct mbuf *m, int off0, uint32_t len, int wait) -{ - struct mbuf *n, **np; - int off = off0; - struct mbuf *top; - int copyhdr = 0; - - if (off < 0 || len < 0) - panic("m_copym"); - if (off == 0 && m->m_flags & M_PKTHDR) - copyhdr = 1; - while (off > 0) { - if (m == NULL) - panic("m_copym"); - if (off < m->m_len) - break; - off -= m->m_len; - m = m->m_next; - } - np = ⊤ - top = 0; - while (len > 0) { - if (m == NULL) { - if (len != M_COPYALL) - panic("m_copym"); - break; - } - MGET(n, wait, m->m_type); - *np = n; - if (n == NULL) - goto nospace; - if (copyhdr) { - M_COPY_PKTHDR(n, m); - if (len == M_COPYALL) - n->m_pkthdr.len -= off0; - else - n->m_pkthdr.len = len; - copyhdr = 0; - } - n->m_len = min(len, m->m_len - off); - if (m->m_flags & M_EXT) { - n->m_data = m->m_data + off; - if(!m->m_ext.ext_ref) - mclrefcnt[mtocl(m->m_ext.ext_buf)]++; - else - (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, - m->m_ext.ext_size); - n->m_ext = m->m_ext; - n->m_flags |= M_EXT; - } else - bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t), - (unsigned)n->m_len); - if (len != M_COPYALL) - len -= n->m_len; - off = 0; - m = m->m_next; - np = &n->m_next; - } - if (top == NULL) - MCFail++; - return (top); -nospace: - m_freem(top); - MCFail++; - return (NULL); -} - -/* - * Copy an entire packet, including header (which must be present). - * An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'. - */ -struct mbuf * -m_copypacket(struct mbuf *m, int how) -{ - struct mbuf *top, *n, *o; - - MGET(n, how, m->m_type); - top = n; - if (!n) - goto nospace; - - M_COPY_PKTHDR(n, m); - n->m_len = m->m_len; - if (m->m_flags & M_EXT) { - n->m_data = m->m_data; - mclrefcnt[mtocl(m->m_ext.ext_buf)]++; - n->m_ext = m->m_ext; - n->m_flags |= M_EXT; - } else { - bcopy(mtod(m, char *), mtod(n, char *), n->m_len); - } - - m = m->m_next; - while (m) { - MGET(o, how, m->m_type); - if (!o) - goto nospace; - - n->m_next = o; - n = n->m_next; - - n->m_len = m->m_len; - if (m->m_flags & M_EXT) { - n->m_data = m->m_data; - mclrefcnt[mtocl(m->m_ext.ext_buf)]++; - n->m_ext = m->m_ext; - n->m_flags |= M_EXT; - } else { - bcopy(mtod(m, char *), mtod(n, char *), n->m_len); - } - - m = m->m_next; - } - return top; -nospace: - m_freem(top); - MCFail++; - return 0; -} - -/* - * Copy data from an mbuf chain starting "off" bytes from the beginning, - * continuing for "len" bytes, into the indicated buffer. Return -1 if requested - * size is bigger than available - */ -int -m_copydata(const struct mbuf *m, int off, int len, caddr_t cp) -{ - u_int count; - - if (off < 0 || len < 0) - panic("m_copydata"); - while (off > 0) { - if (m == 0) { - /*printf("m_copydata: offset > mbuf length ("); - while(m0) { - printf("[%d] ",m0->m_len); - m0 = m0->m_next; - } - printf(")\n");*/ - return -1; - } - if (off < m->m_len) - break; - off -= m->m_len; - m = m->m_next; - } - while (len > 0) { - if (m == 0) { - /*printf("m_copydata: length > mbuf length ("); - while(m0) { - printf("[%d] ",m0->m_len); - m0 = m0->m_next; - } - printf(")\n");*/ - - return -1; - } - count = min(m->m_len - off, len); - bcopy(mtod(m, caddr_t) + off, cp, count); - len -= count; - cp += count; - off = 0; - m = m->m_next; - } - return 0; -} - -/* - * Concatenate mbuf chain n to m. - * Both chains must be of the same type (e.g. MT_DATA). - * Any m_pkthdr is not updated. - */ -void -m_cat(struct mbuf *m, struct mbuf *n) -{ - while (m->m_next) - m = m->m_next; - while (n) { - if (m->m_flags & M_EXT || - m->m_data + m->m_len + n->m_len >= &m->m_dat[MLEN]) { - /* just join the two chains */ - m->m_next = n; - return; - } - /* splat the data from one into the other */ - bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, - (u_int)n->m_len); - m->m_len += n->m_len; - n = m_free(n); - } -} - -void -m_adj(struct mbuf *mp, int req_len) -{ - int len = req_len; - struct mbuf *m; - int count; - - if ((m = mp) == NULL) - return; - if (len >= 0) { - /* - * Trim from head. - */ - while (m != NULL && len > 0) { - if (m->m_len <= len) { - len -= m->m_len; - m->m_len = 0; - m = m->m_next; - } else { - m->m_len -= len; - m->m_data += len; - len = 0; - } - } - m = mp; - if (mp->m_flags & M_PKTHDR) - m->m_pkthdr.len -= (req_len - len); - } else { - /* - * Trim from tail. Scan the mbuf chain, - * calculating its length and finding the last mbuf. - * If the adjustment only affects this mbuf, then just - * adjust and return. Otherwise, rescan and truncate - * after the remaining size. - */ - len = -len; - count = 0; - for (;;) { - count += m->m_len; - if (m->m_next == (struct mbuf *)0) - break; - m = m->m_next; - } - if (m->m_len >= len) { - m->m_len -= len; - if (mp->m_flags & M_PKTHDR) - mp->m_pkthdr.len -= len; - return; - } - count -= len; - if (count < 0) - count = 0; - /* - * Correct length for chain is "count". - * Find the mbuf with last data, adjust its length, - * and toss data from remaining mbufs on chain. - */ - m = mp; - if (m->m_flags & M_PKTHDR) - m->m_pkthdr.len = count; - for (; m; m = m->m_next) { - if (m->m_len >= count) { - m->m_len = count; - break; - } - count -= m->m_len; - } - while (m->m_next) - (m = m->m_next) ->m_len = 0; - } -} - -/* - * Rearange an mbuf chain so that len bytes are contiguous - * and in the data area of an mbuf (so that mtod and dtom - * will work for a structure of size len). Returns the resulting - * mbuf chain on success, frees it and returns null on failure. - * If there is room, it will add up to max_protohdr-len extra bytes to the - * contiguous region in an attempt to avoid being called next time. - */ -static int MPFail; - -struct mbuf * -m_pullup(struct mbuf *n, int len) -{ - struct mbuf *m; - int count; - int space; - - /* - * If first mbuf has no cluster, and has room for len bytes - * without shifting current data, pullup into it, - * otherwise allocate a new mbuf to prepend to the chain. - */ - if ((n->m_flags & M_EXT) == 0 && - n->m_data + len < &n->m_dat[MLEN] && n->m_next) { - if (n->m_len >= len) - return (n); - m = n; - n = n->m_next; - len -= m->m_len; - } else { - if (len > MHLEN) - goto bad; - MGET(m, M_DONTWAIT, n->m_type); - if (m == NULL) - goto bad; - m->m_len = 0; - if (n->m_flags & M_PKTHDR) { - M_COPY_PKTHDR(m, n); - n->m_flags &= ~M_PKTHDR; - } - } - space = &m->m_dat[MLEN] - (m->m_data + m->m_len); - do { - count = min(min(max(len, max_protohdr), space), n->m_len); - bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len, - (unsigned)count); - len -= count; - m->m_len += count; - n->m_len -= count; - space -= count; - if (n->m_len) - n->m_data += count; - else - n = m_free(n); - } while (len > 0 && n); - if (len > 0) { - (void) m_free(m); - goto bad; - } - m->m_next = n; - return (m); - bad: - m_freem(n); - MPFail++; - return (NULL); -} - -/* - * Partition an mbuf chain in two pieces, returning the tail -- - * all but the first len0 bytes. In case of failure, it returns NULL and - * attempts to restore the chain to its original state. - */ -struct mbuf * -m_split(struct mbuf *m0, int len0, int wait) -{ - struct mbuf *m, *n; - u_int len = len0, remain; - - for (m = m0; m && len > m->m_len; m = m->m_next) - len -= m->m_len; - if (m == NULL) - return (NULL); - remain = m->m_len - len; - if (m0->m_flags & M_PKTHDR) { - MGETHDR(n, wait, m0->m_type); - if (n == NULL) - return (NULL); - n->m_pkthdr.rcvif = m0->m_pkthdr.rcvif; - n->m_pkthdr.len = m0->m_pkthdr.len - len0; - m0->m_pkthdr.len = len0; - if (m->m_flags & M_EXT) - goto extpacket; - if (remain > MHLEN) { - /* m can't be the lead packet */ - MH_ALIGN(n, 0); - n->m_next = m_split(m, len, wait); - if (n->m_next == 0) { - (void) m_free(n); - return (0); - } else - return (n); - } else - MH_ALIGN(n, remain); - } else if (remain == 0) { - n = m->m_next; - m->m_next = NULL; - return (n); - } else { - MGET(n, wait, m->m_type); - if (n == 0) - return (0); - M_ALIGN(n, remain); - } -extpacket: - if (m->m_flags & M_EXT) { - n->m_flags |= M_EXT; - n->m_ext = m->m_ext; - if(!m->m_ext.ext_ref) - mclrefcnt[mtocl(m->m_ext.ext_buf)]++; - else - (*(m->m_ext.ext_ref))(m->m_ext.ext_buf, - m->m_ext.ext_size); - m->m_ext.ext_size = 0; /* For Accounting XXXXXX danger */ - n->m_data = m->m_data + len; - } else { - bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain); - } - n->m_len = remain; - m->m_len = len; - n->m_next = m->m_next; - m->m_next = NULL; - return (n); -} -/* - * Routine to copy from device local memory into mbufs. - */ -struct mbuf * -m_devget(char *buf, int totlen, int off0, struct ifnet *ifp, - void (*copy)(char *from, caddr_t to, u_int len)) -{ - struct mbuf *m; - struct mbuf *top = NULL, **mp = ⊤ - int len; - int off = off0; - char *cp; - char *epkt; - - cp = buf; - epkt = cp + totlen; - if (off) { - cp += off + 2 * sizeof(u_short); - totlen -= 2 * sizeof(u_short); - } - MGETHDR(m, M_DONTWAIT, MT_DATA); - if (m == 0) - return (0); - m->m_pkthdr.rcvif = ifp; - m->m_pkthdr.len = totlen; - m->m_len = MHLEN; - - while (totlen > 0) { - if (top) { - MGET(m, M_DONTWAIT, MT_DATA); - if (m == 0) { - m_freem(top); - return (0); - } - m->m_len = MLEN; - } - len = min(totlen, epkt - cp); - if (len >= MINCLSIZE) { - MCLGET(m, M_DONTWAIT); - if (m->m_flags & M_EXT) - m->m_len = len = min(len, MCLBYTES); - else - len = m->m_len; - } else { - /* - * Place initial small packet/header at end of mbuf. - */ - if (len < m->m_len) { - if (top == 0 && len + max_linkhdr <= m->m_len) - m->m_data += max_linkhdr; - m->m_len = len; - } else - len = m->m_len; - } - if (copy) - copy(cp, mtod(m, caddr_t), (u_int)len); - else - bcopy(cp, mtod(m, caddr_t), (u_int)len); - cp += len; - *mp = m; - mp = &m->m_next; - totlen -= len; - if (cp == epkt) - cp = buf; - } - return (top); -} - -/* - * Copy data from a buffer back into the indicated mbuf chain, - * starting "off" bytes from the beginning, extending the mbuf - * chain if necessary. - */ -int -m_copyback(struct mbuf *m0, int off, int len, caddr_t cp) -{ - int mlen; - struct mbuf *m = m0, *n; - int totlen = 0; - - if (m0 == NULL) - return 0; - while (off > (mlen = m->m_len)) { - off -= mlen; - totlen += mlen; - if (m->m_next == NULL) { - n = m_getclr(M_DONTWAIT, m->m_type); - if (n == NULL) { - /*panic("m_copyback() : malformed chain\n");*/ - return -1; - } - n->m_len = min(MLEN, len + off); - m->m_next = n; - } - m = m->m_next; - } - while (len > 0) { - mlen = min (m->m_len - off, len); - bcopy(cp, off + mtod(m, caddr_t), (u_int)mlen); - cp += mlen; - len -= mlen; - mlen += off; - off = 0; - totlen += mlen; - if (len == 0) { - /* m->m_len = mlen; */ - break; - } - if (m->m_next == NULL) { - n = m_get(M_DONTWAIT, m->m_type); - if (n == 0) { - /*panic("m_copyback() : malformed chain 2\n");*/ - return -1; - }; - n->m_len = min(MLEN, len); - m->m_next = n; - } - /* m->m_len = mlen; */ - m = m->m_next; - } -/*out:*/ - if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen)) - m->m_pkthdr.len = totlen; - return 0; -} |