V9/sys/inet.old/ip_subr.c

Compare this file to the similar file:
Show the results in this format:

#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"

extern long time;

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;
static 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, ... */
#ifdef CHKBLK
	first16 = &blkdata[5 * NBLK4];
	first64 = &first16[17 * NBLK16];
	first1024 = &first64[65 * NBLK64];
	if(p < first16){
		bp = &cblock[(p - blkdata) / 5];
	} else if(p < first64){
		bp = &cblock[NBLK4 + (p - first16) / 17];
	} else if(p < first1024){
		bp = &cblock[NBLK4 + NBLK16 + (p - first64) / 65];
	} else {
		bp = &cblock[NBLK4 + NBLK16 + NBLK64 + (p - first1024) / 1025];
	}
#else
	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];
	}
#endif CHKBLK
	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 = len;
		if (m->lim - m->wptr < count)
			count = m->lim - m->wptr;
		if (BLEN(n) < count)
			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;
	register int clen;

	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;
		np = &n->next;
		do {
			clen = len;
			if (BLEN(m) - off < clen)
				clen = BLEN(m) - off;
			if (n->lim - n->wptr < clen)
				clen = n->lim - n->wptr;
			bcopy((caddr_t)m->rptr+off, (caddr_t)n->wptr, clen);
			n->wptr += clen;
			len -= clen;
			if (len <= 0) {
				MCHECK(top);
				return (top);
			}
			if (m->rptr + off + clen < m->wptr)
				off += clen;
			else {
				off = 0;
				m = m->next;
			}
		} while (n->wptr < n->lim);
	}
	MCHECK(top);
	return(top);
nospace:
	bp_free(top);
	return(0);
}

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

	if (m == NULL)
		return;
	MCHECK(m);
	if (len > 0) {
		while(m && len > 0){
			if(BLEN(m) <= len){
				len -= BLEN(m);
				m->wptr = m->rptr;
				m = m->next;
			} else {
				m->rptr += len;
				break;
			}
		}
	}
	else if (len < 0) {
		len = bp_len(m) + len;
		if (len <= 0) {
			if (m->next)
				bp_free(m->next);
			m->next = 0;
			m->wptr = m->rptr;
			return;
		}
		while ((len -= BLEN(m)) > 0) {
			if ((m = m->next) == NULL)
				return;
		}
		m->wptr += len;		/* len is <= 0 */
		bp_free(m->next);
		m->next = 0;
	}
	MCHECK(m);
}

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

	MCHECK(m); MCHECK(n);
	while(m->next)
		m = m->next;
	while(n){
		if((m->wptr + BLEN(n)) >= m->lim){
			/* just join the two chains */
			m->next = n;
			break;
		}
		/* splat the data from one into the other */
		bcopy(n->rptr, m->wptr, BLEN(n));
		m->wptr += BLEN(n);
		xn = n->next;
		freeb(n);
		n = xn;
	}
	MCHECK(m);
}

/* 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;

	MCHECK(m);
	for (; len!=0; m=m->m_next) {
		if (m == NULL) {
			printf("cksum: out of data\n");
			break;
		}
		w = mtod(m, u_short *);
		if (mlen == -1) {
			/* last block ended on an odd numbered byte */
			sum += *(u_char *)w << 8;
			w = (u_short *)((char *)w + 1);
			mlen = BLEN(m) - 1;
			len--;
		} else
			mlen = BLEN(m);
		if (len < mlen)
			mlen = len;
		len -= mlen;
		/* vecadd returns a 16-bit checksum of the block + sum */
		sum = vecadd(w, mlen, sum);
	}
	/* return complement of sum */
	return sum^0xffff;
}

in_addr
in_netof(x)
in_addr x;
{
	in_addr netmask;
	struct ipif *ifp;

	if(IN_CLASSC(x))
		netmask = IN_CLASSC_NET;
	else if(IN_CLASSB(x))
		netmask = IN_CLASSB_NET;
	else
		netmask = IN_CLASSA_NET;

	/* look for an interface for this network and use its subnet mask */
	for(ifp = &ipif[0]; ifp < &ipif[NINET]; ifp++){
		if(ifp->flags & IFF_UP){
			if(netmask&x == netmask&ifp->that)
				if (ifp->mask==0)
					return(x&netmask);
				else
					return(x&ifp->mask);
		}
	}

	/* no interface for this network, assume no subnetting */
	return x&netmask;
}

/*
 * Hash table for route entries.  Collision resolution is linear search until
 * encountering a hole.  Replacement is LRU.
 */
#define NROUTES 128
struct ip_route ip_routes[NROUTES];
int Nip_route = NROUTES;		/* let netstat know number of routes */
#define HASH(x) (((x)+((x)>>8))%NROUTES)
struct ip_route ip_default_route;

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

	/* default is a special case */
	if (dst == 0){
		ip_default_route.gate = gate;
		return(0);
	}

	/* look for what should be a noop */
	if(gate){
		/* 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);
		}
	} else
		gate = dst;

	/* look through existing routes */
	op = sp = rp = &ip_routes[HASH(dst)];
	do {
		if (rp->dst==0 || rp->dst==dst) {
			op = rp;
			break;
		}
		if (rp->time<op->time)
			op = rp;
		if (++rp==&ip_routes[NROUTES])
			rp = ip_routes;
	} while (rp != sp);

	/* add a new route */
	op->dst = dst;
	op->gate = gate;
	op->time = time;
	return(0);
}

/* 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;
{
	register struct ip_route *rp, *sp;
	extern unsigned long in_netof();
	unsigned long netof_dst;
	struct ip_route_info info;

	/* try a network to which we are directly connected */
	info.addr = dst;
	info.ifp = ip_ifonnetof(dst);
	if (info.ifp)
		return info;

	/* look for host routes */
	sp = rp = &ip_routes[HASH(dst)];
	do {
		if (dst==rp->dst && rp->dst!=rp->gate) {
			info.addr = rp->gate;
			info.ifp = ip_ifonnetof(info.addr);
			rp->time = time;
			return(info);
		}
		if (rp->dst==0)
			break;
		if (++rp==&ip_routes[NROUTES])
			rp = ip_routes;
	} while (rp != sp);

	/* now try nets */
	netof_dst = in_netof(dst);
	sp = rp = &ip_routes[HASH(netof_dst)];
	do {
		if (netof_dst==rp->dst && rp->dst!=rp->gate) {
			info.addr = rp->gate;
			info.ifp = ip_ifonnetof(info.addr);
			rp->time = time;
			return(info);
		}
		if (rp->dst==0)
			break;
		if (++rp==&ip_routes[NROUTES])
			rp = ip_routes;
	} while (rp != sp);

	/* if all else fails, use default route */
	/* N.B.  If the gate is a network, don't change the destination
	 *	address.  This allows multiple networks on one wire by
	 *	making that wire the default.
	 */
	if (ip_default_route.gate!=in_netof(ip_default_route.gate))
		info.addr = ip_default_route.gate;
	else
		info.addr = dst;
	info.ifp = ip_ifonnetof(ip_default_route.gate);
	return(info);
}

bp_len(bp)
register struct block *bp;
{
	register 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