#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