M port/devarp.c => port/devarp.c +275 -8
@@ 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;
+ }
+}
M port/devlance.c => port/devlance.c +1 -3
@@ 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("!");
}
}
M port/ipdat.h => port/ipdat.h +5 -3
@@ 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))
M port/stip.c => port/stip.c +2 -12
@@ 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:
M port/stream.c => port/stream.c +1 -5
@@ 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;