-/* mbuf.c 1.6 81/10/21 */
-
-#include "../h/param.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/proc.h"
-#include "../h/pte.h"
-#include "../h/cmap.h"
-#include "../h/map.h"
-#include "../bbnnet/net.h"
-#include "../bbnnet/mbuf.h"
-#include "../bbnnet/tcp.h"
-#include "../bbnnet/ip.h"
-#include "../h/vm.h"
+/*
+ * Copyright (c) 1982 Regents of the University of California.
+ * All rights reserved. The Berkeley software License Agreement
+ * specifies the terms and conditions for redistribution.
+ *
+ * @(#)uipc_mbuf.c 6.5 (Berkeley) %G%
+ */
-struct mbuf *
-m_get(canwait)
+#include "../machine/pte.h"
+
+#include "param.h"
+#include "dir.h"
+#include "user.h"
+#include "proc.h"
+#include "cmap.h"
+#include "map.h"
+#include "mbuf.h"
+#include "vm.h"
+#include "kernel.h"
+
+mbinit()
+{
+ int s;
+
+ s = splimp();
+ if (m_clalloc(4096/CLBYTES, MPG_MBUFS, M_DONTWAIT) == 0)
+ goto bad;
+ if (m_clalloc(8*4096/CLBYTES, MPG_CLUSTERS, M_DONTWAIT) == 0)
+ goto bad;
+ splx(s);
+ return;
+bad:
+ panic("mbinit");
+}
+
+/*
+ * Must be called at splimp.
+ */
+caddr_t
+m_clalloc(ncl, how, canwait)
+ register int ncl;
+ int how;
+{
+ int npg, mbx;
+ register struct mbuf *m;
+ register int i;
+
+ npg = ncl * CLSIZE;
+ mbx = rmalloc(mbmap, (long)npg);
+ if (mbx == 0) {
+ if (canwait == M_WAIT)
+ panic("out of mbuf map");
+ return (0);
+ }
+ m = cltom(mbx / CLSIZE);
+ if (memall(&Mbmap[mbx], npg, proc, CSYS) == 0) {
+ rmfree(mbmap, (long)npg, (long)mbx);
+ return (0);
+ }
+ vmaccess(&Mbmap[mbx], (caddr_t)m, npg);
+ switch (how) {
+
+ case MPG_CLUSTERS:
+ for (i = 0; i < ncl; i++) {
+ m->m_off = 0;
+ m->m_next = mclfree;
+ mclfree = m;
+ m += CLBYTES / sizeof (*m);
+ mbstat.m_clfree++;
+ }
+ mbstat.m_clusters += ncl;
+ break;
+
+ case MPG_MBUFS:
+ for (i = ncl * CLBYTES / sizeof (*m); i > 0; i--) {
+ m->m_off = 0;
+ m->m_type = MT_DATA;
+ mbstat.m_mtypes[MT_DATA]++;
+ mbstat.m_mbufs++;
+ (void) m_free(m);
+ m++;
+ }
+ break;
+ }
+ return ((caddr_t)m);
+}
+
+m_pgfree(addr, n)
+ caddr_t addr;
+ int n;
+{
+
+#ifdef lint
+ addr = addr; n = n;
+#endif
+}
+
+/*
+ * Must be called at splimp.
+ */
+m_expand(canwait)
int canwait;
{
+
+ if (m_clalloc(1, MPG_MBUFS, canwait) == 0)
+ goto steal;
+ return (1);
+steal:
+ /* should ask protocols to free code */
+ return (0);
+}
+
+/* NEED SOME WAY TO RELEASE SPACE */
+
+/*
+ * Space allocation routines.
+ * These are also available as macros
+ * for critical paths.
+ */
+struct mbuf *
+m_get(canwait, type)
+ int canwait, type;
+{
+ register struct mbuf *m;
+
+ MGET(m, canwait, type);
+ return (m);
+}
+
+struct mbuf *
+m_getclr(canwait, type)
+ int canwait, type;
+{
register struct mbuf *m;
-COUNT(M_GET);
- MGET(m, canwait);
+ MGET(m, canwait, type);
+ if (m == 0)
+ return (0);
+ bzero(mtod(m, caddr_t), MLEN);
return (m);
}
{
register struct mbuf *n;
-COUNT(M_FREE);
MFREE(m, n);
return (n);
}
+/*
+ * Get more mbufs; called from MGET macro if mfree list is empty.
+ * Must be called at splimp.
+ */
+/*ARGSUSED*/
struct mbuf *
-m_more(type)
- int type;
+m_more(canwait, type)
+ int canwait, type;
{
- int s;
register struct mbuf *m;
-COUNT(M_MORE);
- if (!m_expand()) {
- netstat.m_drops++;
- return (NULL);
+ while (m_expand(canwait) == 0) {
+ if (canwait == M_WAIT) {
+ m_want++;
+ sleep((caddr_t)mfree, PZERO - 1);
+ } else {
+ mbstat.m_drops++;
+ return (NULL);
+ }
}
-#define m_more(x) ((struct mbuf *)panic("m_more"))
- MGET(m, 0);
+#define m_more(x,y) (panic("m_more"), (struct mbuf *)0)
+ MGET(m, canwait, type);
+#undef m_more
return (m);
}
-m_freem(m) /* free mbuf chain headed by m */
+m_freem(m)
register struct mbuf *m;
{
register struct mbuf *n;
- register int s, cnt;
+ register int s;
-COUNT(M_FREEM);
if (m == NULL)
- return (0);
- cnt = 0;
- s = spl_imp();
+ return;
+ s = splimp();
do {
MFREE(m, n);
- cnt++;
} while (m = n);
splx(s);
- return (cnt);
}
+/*
+ * Mbuffer utility routines.
+ */
-mbufinit() /* init network buffer mgmt system */
-{
+/*
+ * Make a copy of an mbuf chain starting "off" bytes from the beginning,
+ * continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
+ * Should get M_WAIT/M_DONTWAIT from caller.
+ */
+struct mbuf *
+m_copy(m, off, len)
register struct mbuf *m;
- register i;
-
-COUNT(MBUFINIT);
- m = (struct mbuf *)&netutl[0]; /* ->start of buffer virt mem */
- vmemall(&Netmap[0], 2, proc, CSYS);
- vmaccess(&Netmap[0], m, 2);
- for (i=0; i < NMBPG; i++) {
- m_free(m);
- m++;
- }
- pg_alloc(3);
- netcb.n_pages = 4;
- netcb.n_bufs = 32;
- netcb.n_lowat = 16;
- netcb.n_hiwat = 32;
-}
-
-pg_alloc(n)
- register int n;
+ int off;
+ register int len;
{
- register i, j, k;
- register struct mbuf *m;
- int bufs, s;
+ register struct mbuf *n, **np;
+ struct mbuf *top, *p;
-COUNT(PG_ALLOC);
- k = n << 1;
- if ((i = rmalloc(netmap, n)) == 0)
+ if (len == 0)
return (0);
- j = i<<1;
- m = pftom(i);
- /* should use vmemall sometimes */
- if (memall(&Netmap[j], k, proc, CSYS) == 0)
- return (0);
- vmaccess(&Netmap[j], (caddr_t)m, k);
- bufs = n << 3;
- s = spl_imp();
- for (j=0; j < bufs; j++) {
- m_free(m);
- m++;
- }
- splx(s);
- netcb.n_pages += n;
- return (1);
-}
-
-m_expand()
-{
- register i;
- register struct ipq *fp;
- register struct ip *q;
- register struct tcb *tp;
- register struct mbuf *m, *n;
- int need, needp, needs;
-
-COUNT(M_EXPAND);
- needs = need = netcb.n_hiwat - netcb.n_bufs; /* #bufs to add */
- needp = need >> 3; /* #pages to add */
- if (pg_alloc(needp))
- return (1);
- for (i=0; i < needp; i++, need-=NMBPG)
- if (needp == 1 || pg_alloc(1) == 0) /* ??? */
- goto steal;
- return (need < needs);
-steal:
- fp = netcb.n_ip_tail; /* ip reass.q */
- while (need > 0 && fp) {
- q = fp->iqx.ip_next; /* free mbufs assoc. w/chain */
- while (q != (struct ip *)fp) {
- need -= m_freem(dtom(q));
- q = q->ip_next;
- }
- ip_freef(fp); /* free header */
- fp = netcb.n_ip_tail;
+ if (off < 0 || len < 0)
+ panic("m_copy");
+ while (off > 0) {
+ if (m == 0)
+ panic("m_copy");
+ if (off < m->m_len)
+ break;
+ off -= m->m_len;
+ m = m->m_next;
}
- tp = netcb.n_tcb_tail; /* ->tcbs */
- while (need > 0 && tp != NULL) {
- m = tp->t_rcv_unack;
- while (m != NULL) {
- n = m->m_act;
- need -= m_freem(m);
- m = n;
+ np = ⊤
+ top = 0;
+ while (len > 0) {
+ if (m == 0) {
+ if (len != M_COPYALL)
+ panic("m_copy");
+ break;
}
- tp->t_rcv_unack = NULL;
- tp = tp->t_tcb_prev;
+ MGET(n, M_DONTWAIT, m->m_type);
+ *np = n;
+ if (n == 0)
+ goto nospace;
+ n->m_len = MIN(len, m->m_len - off);
+ if (m->m_off > MMAXOFF) {
+ p = mtod(m, struct mbuf *);
+ n->m_off = ((int)p - (int)n) + off;
+ mclrefcnt[mtocl(p)]++;
+ } 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;
}
- return (need < needs);
+ return (top);
+nospace:
+ m_freem(top);
+ return (0);
}
-#ifdef notdef
-m_relse()
+m_cat(m, n)
+ register struct mbuf *m, *n;
{
- int free;
-
-COUNT(M_RELSE);
- free = (netcb.n_bufs - netcb.n_hiwat) >> 3; /* # excess free pages */
- return;
+ while (m->m_next)
+ m = m->m_next;
+ while (n) {
+ if (m->m_off >= MMAXOFF ||
+ m->m_off + m->m_len + n->m_len > MMAXOFF) {
+ /* 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);
+ }
}
-#endif
-struct mbuf *
m_adj(mp, len)
struct mbuf *mp;
- register len;
+ register int len;
{
register struct mbuf *m, *n;
-COUNT(M_ADJ);
if ((m = mp) == NULL)
return;
- if (len >= 0) { /* adjust from top of msg chain */
+ if (len >= 0) {
while (m != NULL && len > 0) {
- if (m->m_len <= len) { /* free this mbuf */
+ if (m->m_len <= len) {
len -= m->m_len;
m->m_len = 0;
m = m->m_next;
- } else { /* adjust mbuf */
+ } else {
m->m_len -= len;
m->m_off += len;
break;
}
}
-
- } else { /* adjust from bottom of msg chain */
+ } else {
+ /* a 2 pass algorithm might be better */
len = -len;
while (len > 0 && m->m_len != 0) {
- /* find end of chain */
while (m != NULL && m->m_len != 0) {
n = m;
m = m->m_next;
}
- if (n->m_len <= len) { /* last mbuf */
+ if (n->m_len <= len) {
len -= n->m_len;
n->m_len = 0;
m = mp;
- } else { /* adjust length */
+ } else {
n->m_len -= len;
break;
}
}
}
-/*
- * convert mbuf virtual to physical addr for uballoc
- */
-mtophys(m)
- register struct mbuf *m;
+struct mbuf *
+m_pullup(m0, len)
+ struct mbuf *m0;
+ int len;
{
- register i;
- register unsigned long addr;
- register struct pte *pte;
-
-COUNT(MTOPHYS);
- i = (((int)m & ~PGOFSET) - (int)netutl) >> PGSHIFT;
- pte = &Netmap[i];
- addr = (pte->pg_pfnum << PGSHIFT) | ((int)m & PGOFSET);
- return (addr);
+ register struct mbuf *m, *n;
+ int count;
+
+ n = m0;
+ if (len > MLEN)
+ goto bad;
+ MGET(m, M_DONTWAIT, n->m_type);
+ if (m == 0)
+ goto bad;
+ m->m_len = 0;
+ do {
+ count = MIN(MLEN - m->m_len, len);
+ if (count > n->m_len)
+ count = 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_off += count;
+ n->m_len -= count;
+ if (n->m_len)
+ break;
+ n = m_free(n);
+ } while (n);
+ if (len) {
+ (void) m_free(m);
+ goto bad;
+ }
+ m->m_next = n;
+ return (m);
+bad:
+ m_freem(n);
+ return (0);
}