V10/sys/inet/ip_subr.c

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

#include "sys/param.h"
#include "sys/stream.h"
#include "sys/inet/in.h"
#include "sys/inet/ip.h"
#include "sys/inet/ip_var.h"

extern struct ipif ipif[];
extern struct ipif *ipifsort[];
extern int ipcnt;			/* number of ip's */
extern long time;

/*
 *  decoding the top two bits of an internet address
 */
u_long in_class_nmask[4] = {
	IN_CLASSA_NET,		/* 00 */
	IN_CLASSA_NET,		/* 01 */
	IN_CLASSB_NET,		/* 10 */
	IN_CLASSC_NET		/* 11 */
};
u_long in_class_hmask[4] = {
	IN_CLASSA_HOST,		/* 00 */
	IN_CLASSA_HOST,		/* 01 */
	IN_CLASSB_HOST,		/* 10 */
	IN_CLASSC_HOST		/* 11 */
};

struct block *
bp_get()
{
#if BLKOWNER
	int			x;		/* for debuging only */
	extern struct block	cblock[];
	extern long		blkowner[];
#endif
	register struct block *bp;

	bp = allocb(64);
	if(bp) {
		bp->next = 0;
#if BLKOWNER
		blkowner[bp-cblock] = *(&x+5);
#endif
	}
	return(bp);
}

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

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

	MCHECK(bp);
	if (BLEN(bp) >= len)
		return (bp);
	wanted = len;	/* debugging */
	if ((newbp = allocb(len)) == NULL) {
		printf("allocb(%d)", len);
		goto bad;
	}
	if (newbp->lim - newbp->wptr < len) {
		printf("allocb(%d) got %d", len, newbp->lim - newbp->wptr);
		goto bad;
	}
	newbp->next = bp;
	while (len > 0 && bp) {
		count = bp->wptr - bp->rptr;
		if (count > len)
			count = len;
		bcopy(bp->rptr, newbp->wptr, count);
		newbp->wptr += count;
		len -= count;
		bp->rptr += count;
		if (bp->rptr >= bp->wptr) {
			newbp->next = bp->next;
			freeb(bp);
			bp = newbp->next;
		}
	}
	if (len) {
		printf("for %d left %d", wanted, len);
		goto bad;
	}
	return (newbp);

bad:
	printf(": bp_pullup err\n");
	if (newbp)
		bp_free(newbp);
	return (NULL);
}

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;
	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;
	}
}

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

	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;
	}
}

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

	MCHECK(bp);
	for (; seen<len; bp=bp->next) {
		if (bp == NULL) {
			printf("cksum: out of data\n");
			break;
		}
		w = (u_short *) bp->rptr;
		if (seen & 01) {
			/* this block begins with an odd numbered byte */
			sum += *(u_char *)w << 8;
			w = (u_short *)((char *)w + 1);
			mlen = BLEN(bp) - 1;
			len--;
		} else
			mlen = BLEN(bp);
		if ((len-seen) < mlen)
			mlen = len-seen;
		seen += 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)
	register in_addr x;
{
	register struct ipif *ifp;
	register int i;
	register in_addr net, mask;
	register int Ipcnt = ipcnt;	/* optimization */

	/*
	 *  look for an interface on same subnet and use its subnet mask
	 */
	for(i=0; i < Ipcnt; i++){
		if((ifp = ipifsort[i])==0)
			break;
		if(ifp->flags & IFF_HOST)
			continue;
		if((x&ifp->mask) == ifp->that)
			return ifp->that;
	}

	/*
	 *  look for an interface on same net and use its subnet mask
	 */
	mask = IN_CLASS_NMASK(x);
	net = x&mask;
	for(i=0; i < Ipcnt; i++){
		if((ifp = ipifsort[i])==0)
			break;
		if(ifp->flags & IFF_HOST)
			continue;
		if(net == (ifp->that&mask))
			return x&ifp->mask;
	}

	/*
	 *  no interface for this network, assume no subnetting
	 */
	return net;
}

/*
 * Hash table for route entries.  Collision resolution is linear search until
 * encountering a hole.  Replacement is LRU.
 */
#define NROUTES 256
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;
	register struct ipif *ifend;

	/* 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 */
		ifend = &ipif[ipcnt];
		for(ifp = ipif; ifp < ifend; 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 in the hash table.
 */
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);
}

/*
 *  return the host part of the address
 */
in_lnaof(i)
	register u_long i;
{
	return i&IN_CLASS_HMASK(i);
}

/*
 *  return true if this is a broadcast address
 */
in_broadcast(ifp, a)
	register struct ipif *ifp;
	register u_long a;
{
	int i;

	for(i = 0; i < 6; i++)
		if(a == ifp->bcast[i])
			return 1;
	return 0;
}