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 = 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