V9/sys/inet.old/ip_subr.cold

#include "inet.h"
#if NINET > 0

#include "../h/param.h"
#include "../h/stream.h"
#include "../h/conf.h"
#include "../h/inet/in.h"
#include "../h/inet/ip.h"
#include "../h/inet/ip_var.h"
#include "../h/inet/mbuf.h"
#include "sparam.h"

struct block *
bp_get()
{
	register struct block *bp;

	bp = allocb(64);
	if(bp)
		bp->next = 0;
	return(bp);
}

bp_check(bp)
register struct block *bp;
{
	while(bp){
		BLOCKCHK(bp);
		bp = bp->next;
	}
}

/* given a char *, come up with the block that holds it. yuk. */
int dtom_hits, dtom_misses;
u_char *xfirst16, *xfirst64, *xfirst1024, *xp;
struct block *xbp;

struct block *
bp_dtom(p)
u_char *p;
{
	extern struct block cblock[];
	extern u_char blkdata[];
	register u_char *first16, *first64, *first1024;
	register struct block *bp;

	/* guess. the order of things in blkdata is NBLK4, NBLK16, ... */
	first16 = &blkdata[4 * NBLK4];
	first64 = &first16[16 * NBLK16];
	first1024 = &first64[64 * NBLK64];
	if(p < first16){
		bp = &cblock[(p - blkdata) / 4];
	} else if(p < first64){
		bp = &cblock[NBLK4 + (p - first16) / 16];
	} else if(p < first1024){
		bp = &cblock[NBLK4 + NBLK16 + (p - first64) / 64];
	} else {
		bp = &cblock[NBLK4 + NBLK16 + NBLK64 + (p - first1024) / 1024];
	}
	if(bp->base && bp->lim && bp->rptr && bp->wptr
	   && (p >= bp->base) && (p < bp->lim)){
		BLOCKCHK(bp);
		dtom_hits++;
		return(bp);
	}
	xfirst16 = first16;
	xfirst64 = first64;
	xfirst1024 = first1024;
	xp = p;
	xbp = bp;
	dtom_misses++;
	for(bp = &cblock[NBLOCK-1]; bp >= &cblock[0]; --bp){
		if(bp->base == 0 || bp->lim == 0 || bp->rptr == 0 || bp->wptr == 0)
			continue;
		if((p >= bp->base) && (p < bp->lim)){
			return(bp);
		}
	}
	panic("bp_dtom");
	/* NOTREACHED */
}

/* bp_pullup: make the first block have at least len bytes */
struct block *
bp_pullup(bp, len)
register struct block *bp;
{
	register struct block *m, *n, *nn;
	int count;

	n = bp;
	if(len > MAXBLEN)
		goto bad;
	m = allocb(MAXBLEN);
	if(m == 0)
		goto bad;
	do{
		count = MIN(BSZ(m) - BLEN(m), len);
		if(count > BLEN(n))
			count = BLEN(n);
		bcopy(n->rptr, m->wptr, (unsigned)count);
		len -= count;
		m->wptr += count;
		n->rptr += count;
		if(BLEN(n))
			break;
		nn = n->next;
		freeb(n);
		n = nn;
	} while(n);
	if(len){
		freeb(m);
		goto bad;
	}
	m->next = n;
	MCHECK(m);
	return(m);
bad:
	printf("m_pullup bad\n");
	bp_free(n);
	return(0);
}

bp_free(bp)
register struct block *bp;
{
	register struct block *p;

	while(bp){
		p = bp->next;
		BLOCKCHK(bp);
		freeb(bp);
		bp = p;
	}
}

struct block *
bp_copy(m, off, len)
register struct block *m;
int off;
register int len;
{
	register struct block *n, **np;
	struct block *top;

	MCHECK(m);
	if(len == 0)
		return(0);
	if(off < 0 || len < 0)
		panic("m_copy");
	while(off > 0){
		if(m == 0)
			panic("m_copy 1");
		if(off < BLEN(m))
			break;
		off -= BLEN(m);
		m = m->next;
	}
	np = &top;
	top = 0;
	while(len > 0){
		if(m == 0)
			panic("m_copy 2");
		n = allocb(len);
		*np = n;
		if(n == 0)
			goto nospace;
		n->next = 0;
		n->wptr += MIN(len, BLEN(m) - off);
		bcopy((caddr_t)m->rptr+off, (caddr_t)n->rptr,
			(unsigned)BLEN(n));
		len -= BLEN(n);
		off = 0;
		m = m->next;
		np  = &n->next;
	}
	return(top);
nospace:
	m_freem(top);
	return(0);
}

bp_adj(mp, len)
struct block *mp;
register int len;
{
	register struct block *m, *n;

	if((m = mp) == NULL)
		return;
	MCHECK(mp);
	if(len >= 0){
		while(m && len > 0){
			if(BLEN(m) <= len){
				len -= BLEN(m);
				m->wptr = m->rptr;
				m = m->m_next;
			} else {
				m->rptr += len;
				break;
			}
		}
	} else {
		len = -len;
		while(len > 0 && m && BLEN(m) != 0){
			while(m && BLEN(m) != 0){
				n = m;
				m = m->next;
			}
			if(BLEN(n) <= len){
				len -= BLEN(n);
				n->wptr = n->rptr;
				m = mp;
			} else {
				n->wptr -= len;
				break;
			}
		}
	}
}

m_cat(m, n)
register struct mbuf *m, *n;
{
	register struct mbuf *xn;

	MCHECK(m); MCHECK(n);
	while(m->m_next)
		m = m->m_next;

	while(n){
		if((m->wptr + BLEN(n)) >= m->lim){
			/* just join the two chains */
			m->m_next = n;
			return;
		}
		/* splat the data from one into the other */
		bcopy(mtod(n, caddr_t), m->wptr, BLEN(n));
		m->wptr += BLEN(n);
		xn = n->next;
		m_free(n);
		n = xn;
	}
}

/* C version of 4.2bsd's Internet checksum routine */
/* This version assumes that no message exceeds 2^16 words */
in_cksum(m, len)
	register struct mbuf *m;
	register int len;
{
	register u_short *w;
	register u_long sum = 0;
	register int mlen = 0;
	u_long tsum;
	u_short *sp = (u_short *)&tsum;

	MCHECK(m);
	for (;;) {
		/*
		 * Each trip around loop adds in
		 * word from one block.
		 */
		w = mtod(m, u_short *);
		if (mlen == -1) {
			/*
			 * There is a byte left from the last segment;
			 * add it into the checksum.  Don't have to worry
			 * about a carry-out here because we make sure
			 * that high part of (32 bit) sum is small below.
			 */
			sum += *(u_char *)w << 8;
			w = (u_short *)((char *)w + 1);
			mlen = BLEN(m) - 1;
			len--;
		} else
			mlen = BLEN(m);
		m = m->m_next;
		if (len < mlen)
			mlen = len;
		len -= mlen;
		/* sum block using groups of inline adds */
		while ((mlen -= 32) >= 0) {
			sum+=*w++ + *w++ + *w++ + *w++ + *w++ + *w++ + *w++ + *w++ +
			     *w++ + *w++ + *w++ + *w++ + *w++ + *w++ + *w++ + *w++;
		}
		mlen += 32;
		while ((mlen -= 8) >= 0) {
			sum+=*w++ + *w++ + *w++ + *w++;
		}
		mlen += 8;
		while ((mlen -= 2) >= 0) {
			sum+=*w++;
		}
		if (mlen == -1) {
			sum += *(u_char *)w;
		}
		if (len == 0)
			break;
		/*
		 * Locate the next block with some data.
		 * If there is a word split across a boundary we
		 * will wrap to the top with mlen == -1 and
		 * then add it in shifted appropriately.
		 */
		for (;;) {
			if (m == 0) {
				printf("cksum: out of data\n");
				goto done;
			}
			if (BLEN(m))
				break;
			m = m->m_next;
		}
	}
done:
	/* fold 32 bit sum into 16 bit sum */
	tsum = sum;
	tsum = sp[0] + sp[1];
	sum = sp[0] + sp[1];
	/* return complement of sum */
	return sum^0xffff;
}

in_addr
in_netof(x)
in_addr x;
{
	if(IN_CLASSC(x))
		return(x&IN_CLASSC_NET);
	else if(IN_CLASSB(x))
		return(x&IN_CLASSB_NET);
	else
		return(x&IN_CLASSA_NET);
}

in_addr
in_hostof(x)
in_addr x;
{
	if(IN_CLASSC(x))
		return(x&IN_CLASSC_HOST);
	else if(IN_CLASSB(x))
		return(x&IN_CLASSB_HOST);
	else
		return(x&IN_CLASSA_HOST);
}

/*
 *  Routes are kept in a circular list.  Ip_default_route points to the
 *  "first" position in the list.  On each acess, the accessed element is
 *  moved to this first position.
 */
#define NROUTES 50
struct ip_route ip_routes[NROUTES];
int Nip_route = NROUTES;		/* let netstat know number of routes */
struct ip_route ip_default_route = { 0, 0, &ip_default_route };

ip_doroute(dst, gate)
in_addr dst, gate;
{
	register struct ip_route *rp, *save;
	register struct ipif *ifp;

	if(gate){
		/* no-ops are ignored */
		if (dst == gate)
			return(0);

		/* don't accept an indirect route, if we have a direct one */
		for(ifp = ipif; ifp < &ipif[NINET]; ifp++){
			if((ifp->flags&IFF_UP)
			   && ifp->that == dst)
				return(0);
		}
	}
	/* look through existing routes (looks at ip_default_route first)*/
	rp = &ip_default_route;
	do {
		if (dst == rp->next->dst) {
			if (gate) {
				rp->next->gate = gate;
			} else {
				rp->next->dst = rp->next->gate = 0;
				rp->next = rp->next->next;
			}
			return(0);
		}
		rp = rp->next;
	} while (rp != &ip_default_route);
	if (gate == 0)
		return(0);
	/* add a new route */
	for(rp = &ip_routes[0]; rp < &ip_routes[NROUTES]; rp++)
		if(rp->dst == 0) {
			rp->dst = dst;
			rp->gate = gate;
			rp->next = ip_default_route.next;
			ip_default_route.next = rp;
			return(0);
		}
	return(1);
}

/* Look for a route on the circular list.  If the route is found, move
 * it to the beginning of the list.
 */
struct ip_route_info
ip_route(dst)
in_addr dst;
{
	extern unsigned long in_netof();
	unsigned long netof_dst;
	register struct ip_route *rp, *trp;
	struct ip_route_info info;

	/* look for host routes (start after ip_default_route) */
	for(rp = &ip_default_route; rp->next != &ip_default_route; rp=rp->next)
		if (dst == rp->next->dst) {
			/* make sure the interface exists */
			info.addr = rp->next->gate;
			info.ifp = ip_ifonnetof(info.addr);
			if(info.ifp == 0)
				break;
			/* move to first */
			trp = rp->next;
			rp->next = rp->next->next;
			trp->next = ip_default_route.next;
			ip_default_route.next = trp;
			return(info);
		}
	/* now try nets (start after ip_default_route) */
	netof_dst = in_netof(dst);
	for (rp = &ip_default_route; rp->next != &ip_default_route; rp=rp->next)
		if(netof_dst == rp->next->dst){
			/* make sure the interface exists */
			info.addr = rp->next->gate;
			info.ifp = ip_ifonnetof(info.addr);
			if(info.ifp == 0)
				break;
			/* move to first */
			trp = rp->next;
			rp->next = rp->next->next;
			trp->next = ip_default_route.next;
			ip_default_route.next = trp;
			return(info);
		}
	/* try a network to which we are directly connected */
	info.addr = dst;
	info.ifp = ip_ifonnetof(dst);
	if (info.ifp)
		return info;
	/* if all else fails, use default route */
	info.addr = ip_default_route.gate;
	info.ifp = ip_ifonnetof(info.addr);
	return(info);
}

bp_len(bp)
register struct block *bp;
{
	int n;

	n = 0;
	while(bp){
		n += BLEN(bp);
		bp = bp->next;
	}
	return(n);
}

bp_putback(q, list)
struct queue *q;
struct block *list;
{
	register struct block *bp;
	register struct block *prev, *next;

	/*
	 * reverse the list, to keep data in order
	 */
	prev = next = NULL;
	for (bp = list; bp; bp = next) {
		next = bp->next;
		bp->next = prev;
		prev = bp;
	}
	for (bp = prev; bp; bp = next) {
		next = bp->next;
		putbq(q, bp);
	}
}

in_addr
ip_hoston(dst)
in_addr dst;
{
	struct ip_route_info info;

	info = ip_route(dst);
	if(info.ifp == 0)
		return(0);
	return(info.ifp->thishost);
}

in_lnaof(i)
register u_long i;
{

	if(IN_CLASSA(i))
		return((i)&IN_CLASSA_HOST);
	else if(IN_CLASSB(i))
		return((i)&IN_CLASSB_HOST);
	else
		return((i)&IN_CLASSC_HOST);
}
#endif NINET