V10/lsys/inet/ip_subr.c
#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 = 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(i)
register u_long i;
{
register u_long mask;
mask = IN_CLASS_HMASK(i);
return (i&mask) == 0 || (i&mask) == mask;
}