From b8fff571df27ab7bc2301267b4de0cc4b9c6a3cd Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sun, 27 Oct 1991 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1991-10-27 --- port/devarp.c | 283 ++++++++++++++++++++++++++++++++++++++++++++++-- port/devlance.c | 4 +- port/ipdat.h | 8 +- port/stip.c | 14 +-- port/stream.c | 6 +- 5 files changed, 284 insertions(+), 31 deletions(-) diff --git a/port/devarp.c b/port/devarp.c index 0601e51ec5445d11ad3167a94107c54428962124..aaa024d757b4f7c863a5cc573570c54fdc2377f8 100644 --- a/port/devarp.c +++ b/port/devarp.c @@ -9,17 +9,41 @@ #include "devtab.h" -Arpcache *arp; -Arpcache **arphash; Arpstats arpstats; +Arpcache *arplruhead, *arplrutail; +Arpcache *arp, **arphash; Queue *Servq; +typedef struct Arpq Arpq; +struct Arpq +{ + uchar ip[4]; + uchar *etheraddr; + Block *bp; + Queue *put; + ulong time; + Arpq *next; +}; + +struct arpalloc +{ + Lock; + Lock list; + Lock hash; + Arpq *free; + Arpq *head; + Arpq *tail; +}arpalloc; + +void arpiput(Queue *, Block *); +void arpoput(Queue *, Block *); +void arpopn(Queue *, Stream *); +void arpcls(Queue *); +Qinfo arpinfo = { arpiput, arpoput, arpopn, arpcls, "arp" }; + #define ARP_ENTRYLEN 50 char *padstr = " "; -extern Arpcache *arplruhead; -extern Arpcache *arplrutail; - enum{ arpdirqid, arpstatqid, @@ -55,6 +79,7 @@ arpreset(void) ap = &arp[conf.arp-1]; ap->frwd = 0; arplrutail = ap; + newqinfo(&arpinfo); } void @@ -203,19 +228,19 @@ arpwrite(Chan *c, char *a, long n, ulong offset) m = getfields(buf, field, 5, ' '); if(strncmp(field[0], "flush", 5) == 0) - arp_flush(); + arpflush(); else if(strcmp(field[0], "delete") == 0) { if(m != 2) error(Ebadarg); - if(arp_delete(field[1]) < 0) + if(arpdelete(field[1]) < 0) error(Eaddrnotfound); } case arpdataqid: if(n != sizeof(Arpentry)) error(Emsgsize); memmove(&entry, a, sizeof(Arpentry)); - arp_enter(&entry, ARP_TEMP); + arpenter(&entry, ARP_TEMP); break; default: error(Ebadusefd); @@ -224,3 +249,245 @@ arpwrite(Chan *c, char *a, long n, ulong offset) return n; } + +void +arpopn(Queue *q, Stream *s) +{ + if(!Servq) + Servq = RD(q); +} + +void +arpcls(Queue *q) +{ + if(q == Servq) + Servq = 0; +} + +void +arpiput(Queue *q, Block *bp) +{ + PUTNEXT(q, bp); +} + +void +arpoput(Queue *q, Block *bp) +{ + PUTNEXT(q, bp); +} + +int +arplookup(uchar *ip, uchar *et) +{ + Arpcache *ap; + + lock(&arpalloc.hash); + for(ap = ARPHASH(ip); ap; ap = ap->hash) { + if(ap->status == ARP_OK && memcmp(ap->eip, ip, sizeof(ap->eip)) == 0) { + memmove(et, ap->et, sizeof(ap->et)); + arplinkhead(ap); + unlock(&arpalloc.hash); + arpstats.hit++; + return 1; + } + } + unlock(&arpalloc.hash); + return 0; +} + +void +arpsendpkt(uchar *unroutedip, uchar *ether, Queue *put, Block *bp) +{ + Arpq *aq; + Block *nbp; + uchar ip[4]; + + if(!Servq) { + print("arp: No server\n"); + freeb(bp); + return; + } + + iproute(unroutedip, ip); + if(arplookup(ip, ether)) { + PUTNEXT(put, bp); + return; + } + + /* Send the request out to the user level arp daemon */ + nbp = allocb(sizeof(ip)); + memmove(nbp->rptr, ip, sizeof(ip)); + nbp->wptr += sizeof(ip); + nbp->flags |= S_DELIM; + PUTNEXT(Servq, nbp); + arpstats.miss++; + + lock(&arpalloc); + if(aq = arpalloc.free) + arpalloc.free = aq->next; + unlock(&arpalloc); + + if(aq == 0) { + freeb(bp); + return; + } + + /* Stash the work away until the arp completes or times out */ + memmove(aq->ip, ip, sizeof(aq->ip)); + aq->etheraddr = ether; + aq->bp = bp; + aq->put = put; + aq->time = MACHP(0)->ticks; + + lock(&arpalloc.list); + if(arpalloc.head) { + arpalloc.tail->next = aq; + arpalloc.tail = aq; + } + else { + arpalloc.tail = aq; + arpalloc.head = aq; + } + aq->next = 0; + unlock(&arpalloc.list); +} + +void +arpflush(void) +{ + Arpcache *ap; + + for(ap = arplruhead; ap; ap = ap->frwd) + ap->status = ARP_FREE; +} + +void +arpenter(Arpentry *ape, int type) +{ + Arpcache *ap, **l, *d; + + + /* Update an entry if we have one already */ + l = &ARPHASH(ape->ipaddr); + lock(&arpalloc.hash); + for(ap = *l; ap; ap = ap->hash) { + if(ap->status == ARP_OK && memcmp(ap->eip, ape->ipaddr, sizeof(ap->eip)) == 0) { + if(ap->type != ARP_PERM) { + ap->type = type; + memmove(ap->et, ape->etaddr, sizeof(ap->et)); + ap->status = ARP_OK; + } + unlock(&arpalloc.hash); + return; + } + } + + /* Find an entry to replace */ + for(ap = arplrutail; ap && ap->type == ARP_PERM; ap = ap->prev) + ; + + if(!ap) { + print("arp: too many permanent entries\n"); + unlock(&arpalloc.hash); + return; + } + + if(ap->hashhd) { + for(d = *ap->hashhd; d; d = d->hash) { + if(d == ap) { + *(ap->hashhd) = ap->hash; + break; + } + ap->hashhd = &d->hash; + } + } + + ap->type = type; + ap->status = ARP_OK; + memmove(ap->eip, ape->ipaddr, sizeof(ape->ipaddr)); + memmove(ap->et, ape->etaddr, sizeof(ape->etaddr)); + ap->ip = nhgetl(ap->eip); + ap->hashhd = l; + ap->hash = *l; + *l = ap; + arplinkhead(ap); + unlock(&arpalloc.hash); + pusharpq(); +} + +void +pusharpq(void) +{ + int sent; + Arpq *aq, *prev; + +loop: prev = 0; + lock(&arpalloc.list); + for(aq = arpalloc.head; aq; aq = aq->next) { + if(arplookup(aq->ip, aq->etheraddr)) { + if(prev) + prev->next = aq->next; + else + arpalloc.head = 0; + if(aq->next == 0) + arpalloc.tail = prev; + unlock(&arpalloc.list); + PUTNEXT(aq->put, aq->bp); + + lock(&arpalloc); + aq->next = arpalloc.free; + arpalloc.free = aq; + unlock(&arpalloc); + goto loop; + } + prev = aq; + } + unlock(&arpalloc.list); +} + +int +arpdelete(char *addr) +{ + Arpcache *ap; + char enetaddr[6], buf[20], *ptr; + int i; + + ptr = buf + 2; + strncpy(ptr, addr, (sizeof buf) - 2); + + for(i = 0; i < 6 && addr != (char *)1; i++) { + ptr[-2] = '0'; + ptr[-1] = 'x'; + enetaddr[i] = atoi(ptr-2); + ptr = strchr(ptr, ':')+1; + } + + lock(&arpalloc.hash); + for(ap = arplruhead; ap; ap = ap->frwd) { + if(memcmp(ap->et, ptr, sizeof(ap->et)) == 0) { + ap->status = ARP_FREE; + break; + } + } + unlock(&arpalloc.hash); +} + +void +arplinkhead(Arpcache *ap) +{ + if(ap != arplruhead) { + if(ap->prev) + ap->prev->frwd = ap->frwd; + else + arplruhead = ap->frwd; + + if(ap->frwd) + ap->frwd->prev = ap->prev; + else + arplrutail = ap->prev; + + ap->frwd = arplruhead; + ap->prev = 0; + arplruhead = ap; + } +} diff --git a/port/devlance.c b/port/devlance.c index 458e921fb75e6146d11bbffc6050f3c056bd020e..8d5f25bbf95b97c08b988c79b2dc32551a550939 100644 --- a/port/devlance.c +++ b/port/devlance.c @@ -684,7 +684,6 @@ lanceup(Ethertype *e, Etherpkt *p, int len) if(waserror()) return; - if(e->q && e->q->next->len<=Streamhi){ bp = allocb(len); memmove(bp->rptr, (uchar *)p, len); @@ -704,6 +703,7 @@ isinput(void *arg) Lancemem *lm = LANCEMEM; return l.rl!=l.rc && (MPus(lm->rmr[l.rl].flags) & OWN)==0; } + static void lancekproc(void *arg) { @@ -740,7 +740,6 @@ lancekproc(void *arg) len = MPus(m->cntflags) - 4; for(e = &l.e[0]; e < &l.e[Ntypes]; e++){ if(e->q!=0 && (t==e->type||e->type==-1) && canqlock(e)){ -if(p->type[0] == 0x80 || p->type[0] == 0x8) print("*"); if(t==e->type||e->type==-1) lanceup(e, p, len); qunlock(e); @@ -761,7 +760,6 @@ stage: } qunlock(&l.rlock); sleep(&l.rr, isinput, 0); -print("!"); } } diff --git a/port/ipdat.h b/port/ipdat.h index 661befccbeece6434bd0a56060f593606084de02..c04137025b1dea0b6a5e447870b658f4c9b180d2 100644 --- a/port/ipdat.h +++ b/port/ipdat.h @@ -453,9 +453,10 @@ Block *btrim(Block*, int, int); Block *ip_reassemble(int, Block*, Etherhdr*); Ipconv *portused(Ipconv *, Port); Port nextport(Ipconv *, Port); -void arp_enter(Arpentry*, int); -void arp_flush(void); -int arp_delete(char*); +void arpenter(Arpentry*, int); +void arpflush(void); +int arpdelete(char*); +void pusharpq(void); void arplinkhead(Arpcache*); Fragq *ipfragallo(void); void ipfragfree(Fragq*); @@ -509,6 +510,7 @@ void tcp_acktimer(void *); Ipconv *ipclonecon(Chan *); void iplisten(Chan *, Ipconv *, Ipconv *); void iloutoforder(Ipconv*, Ilhdr*, Block*); +void arpsendpkt(uchar*, uchar*, Queue*, Block*); #define fmtaddr(xx) (xx>>24)&0xff,(xx>>16)&0xff,(xx>>8)&0xff,xx&0xff #define MIN(a, b) ((a) < (b) ? (a) : (b)) diff --git a/port/stip.c b/port/stip.c index db51a48fadd36bb27db86299fb7196d3f175d75d..9d022ff6325799658599784acedb4195350589a8 100644 --- a/port/stip.c +++ b/port/stip.c @@ -200,12 +200,7 @@ ipetheroput(Queue *q, Block *bp) /* Finally put in the ethernet level information */ hnputs(eh->type, ET_IP); - if(!arp_lookup(eh->dst, eh->d)) { - freeb(bp); - return; - } - - PUTNEXT(Etherq, bp); + arpsendpkt(eh->dst, eh->d, Etherq, bp); return; } @@ -218,10 +213,6 @@ ipetheroput(Queue *q, Block *bp) /* Make prototype output header */ hnputs(eh->type, ET_IP); - if(!arp_lookup(eh->dst, eh->d)) { - freeb(bp); - return; - } dlen = len - (ETHER_HDR+ETHER_IPHDR); xp = bp; @@ -271,9 +262,8 @@ ipetheroput(Queue *q, Block *bp) feh->cksum[0] = 0; feh->cksum[1] = 0; hnputs(feh->cksum, ip_csum(&feh->vihl)); - nb->flags |= S_DELIM; - PUTNEXT(Etherq, nb); + arpsendpkt(feh->dst, feh->d, Etherq, nb); } drop: diff --git a/port/stream.c b/port/stream.c index c90bda25537401e01cd0b31757ec2273b5bfbf7c..2f57f56315a3bb02b7262c0ba546eaed2307425b 100644 --- a/port/stream.c +++ b/port/stream.c @@ -1324,11 +1324,7 @@ streamwrite(Chan *c, void *a, long n, int docopy) * like andrew's getmfields but no hidden state */ int -getfields(char *lp, /* to be parsed */ - char **fields, /* where to put pointers */ - int n, /* number of pointers */ - char sep /* separator */ -) +getfields(char *lp, char **fields, int n, char sep) { int i;