## diffname ip/arp.c 1998/0306 ## diff -e /dev/null /n/emeliedump/1998/0306/sys/src/brazil/ip/arp.c 0a #include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "../port/error.h" #include "ip.h" /* * address resolution tables */ enum { NHASH = (1<<6), NCACHE = 256, AOK = 1, AWAIT = 2, }; char *arpstate[] = { "UNUSED", "OK", "WAIT", }; typedef struct Arpcache Arpcache; struct Arpcache { QLock; Arpent* hash[NHASH]; Arpent cache[NCACHE]; }; Arpcache arp; char *Ebadarp = "bad arp"; #define haship(s) ((s)[IPaddrlen-1]%NHASH) static Arpent* newarp(uchar *ip, Medium *m) { uint t; Block *next, *xp; Arpent *a, *e, *f, **l; /* find oldest entry */ e = &arp.cache[NCACHE]; a = arp.cache; t = a->used; for(f = a; f < e; f++){ if(f->used < t){ t = f->used; a = f; } } /* dump waiting packets */ xp = a->hold; a->hold = nil; while(xp){ next = xp->list; freeblist(xp); xp = next; } /* take out of current chain */ l = &arp.hash[haship(a->ip)]; for(f = *l; f; f = f->hash){ if(f == a) { *l = a->hash; break; } l = &f->hash; } /* insert into new chain */ l = &arp.hash[haship(ip)]; a->hash = *l; *l = a; memmove(a->ip, ip, sizeof(a->ip)); a->used = msec; a->time = 0; a->type = m; return a; } Arpent* arpget(Block *bp, int version, Medium *type, uchar *ip, uchar *mac) { int hash; Arpent *a; uchar v6ip[IPaddrlen]; if(version == V4) { v4tov6(v6ip, ip); ip = v6ip; } qlock(&arp); hash = haship(ip); for(a = arp.hash[hash]; a; a = a->hash) { if(memcmp(ip, a->ip, sizeof(a->ip)) == 0) if(type == a->type) break; } if(a == nil){ a = newarp(ip, type); a->state = AWAIT; } a->used = msec; if(a->state == AWAIT){ if(a->hold) a->last->list = bp; else a->hold = bp; a->last = bp; bp->list = nil; return a; /* return with arp qlocked */ } memmove(mac, a->mac, a->type->maclen); qunlock(&arp); return nil; } /* * called with arp locked */ void arprelease(Arpent*) { qunlock(&arp); } /* * called with arp locked */ Block* arpresolve(Arpent *a, Medium *type, uchar *mac) { Block *bp; memmove(a->mac, mac, type->maclen); a->type = type; a->state = AOK; a->used = msec; bp = a->hold; a->hold = nil; qunlock(&arp); return bp; } void arpenter(Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refresh) { Arpent *a; Block *bp, *next; uchar v6ip[IPaddrlen]; if(version == V4){ v4tov6(v6ip, ip); ip = v6ip; } qlock(&arp); for(a = arp.hash[haship(ip)]; a; a = a->hash) { if(a->type != type || (a->state != AWAIT && a->state != AOK)) continue; if(ipcmp(a->ip, ip) == 0) { a->state = AOK; memmove(a->mac, mac, type->maclen); bp = a->hold; a->hold = nil; if(version == V4) ip += IPv4off; qunlock(&arp); while(bp) { next = bp->list; if(ifc != nil){ if(waserror()){ runlock(ifc); nexterror(); } rlock(ifc); if(ifc->m != nil) ifc->m->bwrite(ifc, bp, version, ip); else freeb(bp); runlock(ifc); poperror(); } else freeb(bp); bp = next; } a->used = msec; return; } } /* if nil, we're adding a new entry */ if(refresh == 0){ a = newarp(ip, type); a->state = AOK; a->type = type; memmove(a->mac, mac, type->maclen); } qunlock(&arp); } int arpwrite(char *s, int len) { int n; Block *bp; Arpent *a; char *f[4], buf[256]; uchar ip[], mac[MAClen]; Medium *m; if(len == 0) error(Ebadarp); if(len >= sizeof(buf)) len = sizeof(buf)-1; strncpy(buf, s, len); buf[len] = 0; if(len > 0 && buf[len-1] == '\n') buf[len-1] = 0; n = parsefields(buf, f, 4, " "); if(strcmp(f[0], "flush") == 0){ qlock(&arp); for(a = arp.cache; a < &arp.cache[NCACHE]; a++){ memset(a->ip, 0, sizeof(a->ip)); memset(a->mac, 0, sizeof(a->mac)); a->hash = nil; a->state = 0; a->used = 0; while(a->hold != nil) { bp = a->hold->list; freeblist(a->hold); a->hold = bp; } } memset(arp.hash, 0, sizeof(arp.hash)); qunlock(&arp); } else if(strcmp(f[0], "add") == 0){ if(n != 4) error(Ebadarp); m = ipfindmedium(f[1]); if(m == nil) error(Ebadarp); parseip(ip, f[2]); parsemac(mac, f[3], m->maclen); arpenter(nil, V6, ip, mac, m, 0); } else error(Ebadarp); return len; } enum { Alinelen= 66, }; char *aformat = "%-6.6s %-8.8s %-16.16I %-32.32s\n"; static void convmac(char *p, uchar *mac, int n) { while(n-- > 0) p += sprint(p, "%2.2ux", *mac++); } int arpread(char *p, ulong offset, int len) { Arpent *a; int n; char mac[2*MAClen+1]; if(offset % Alinelen) return 0; offset = offset/Alinelen; len = len/Alinelen; n = 0; for(a = arp.cache; len > 0 && a < &arp.cache[NCACHE]; a++){ if(a->state == 0) continue; if(offset > 0){ offset--; continue; } len--; qlock(&arp); convmac(mac, a->mac, a->type->maclen); n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac); qunlock(&arp); } return n; } . ## diffname ip/arp.c 1998/0313 ## diff -e /n/emeliedump/1998/0306/sys/src/brazil/ip/arp.c /n/emeliedump/1998/0313/sys/src/brazil/ip/arp.c 310c qunlock(arp); . 307c qlock(arp); . 299c for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){ . 286c arpread(Arp *arp, char *p, ulong offset, int len) . 264c arpenter(arp, nil, V6, ip, mac, m, 0); . 254,255c memset(arp->hash, 0, sizeof(arp->hash)); qunlock(arp); . 241,242c qlock(arp); for(a = arp->cache; a < &arp->cache[NCACHE]; a++){ . 221c arpwrite(Arp *arp, char *s, int len) . 217c qunlock(arp); . 211c a = newarp(arp, ip, type); . 209d 185c qunlock(arp); . 173,174c qlock(arp); for(a = arp->hash[haship(ip)]; a; a = a->hash) { . 162c arpenter(Arp *arp, Ipifc *ifc, int version, uchar *ip, uchar *mac, Medium *type, int refresh) . 156c qunlock(arp); . 146c arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac) . 139c qunlock(arp); . 137c arprelease(Arp *arp, Arpent*) . 129c qunlock(arp); . 114c a = newarp(arp, ip, type); . 107c for(a = arp->hash[hash]; a; a = a->hash) { . 105c qlock(arp); . 94c arpget(Arp *arp, Block *bp, int version, Medium *type, uchar *ip, uchar *mac) . 82c l = &arp->hash[haship(ip)]; . 72c l = &arp->hash[haship(a->ip)]; . 52,53c e = &arp->cache[NCACHE]; a = arp->cache; . 45c newarp(Arp *arp, uchar *ip, Medium *m) . 43a void arpinit(Fs *f) { f->arp = smalloc(sizeof(Arp)); f->arp->f = f; } . 38,39d 34c Fs *f; Arpent *hash[NHASH]; . 30,31c /* * one per Fs */ struct Arp . ## diffname ip/arp.c 1998/0320 ## diff -e /n/emeliedump/1998/0313/sys/src/brazil/ip/arp.c /n/emeliedump/1998/0320/sys/src/brazil/ip/arp.c 234c uchar ip[IPaddrlen], mac[MAClen]; . ## diffname ip/arp.c 1998/0630 ## diff -e /n/emeliedump/1998/0320/sys/src/brazil/ip/arp.c /n/emeliedump/1998/0630/sys/src/brazil/ip/arp.c 266,271c m->ares(fs, V6, ip, mac, n, 0); . 263,264c } else if(strcmp(f[0], "add") == 0) { switch(n) { default: error(Ebadarg); case 3: parseip(ip, f[1]); r = v4lookup(fs, ip+IPv4off); if(r == nil) error("Destination unreachable"); m = r->ifc->m; n = parsemac(mac, f[2], m->maclen); break; case 4: m = ipfindmedium(f[1]); if(m == nil) error(Ebadarp); parseip(ip, f[2]); n = parsemac(mac, f[3], m->maclen); break; } if(m->ares == nil) . 236a arp = fs->arp; . 235d 232a Medium *m; . 230a Route *r; Arp *arp; . 228c arpwrite(Fs *fs, char *s, int len) . 180a if(r == nil) { print("arp: no route for entry\n"); return; } ifc = r->ifc; type = ifc->m; . 179a else r = v6lookup(fs, ip); . 176c arp = fs->arp; if(n != 6) { print("arp: len = %d\n", n); return; } if(version == V4) { r = v4lookup(fs, ip); . 172a Ipifc *ifc; Medium *type; . 171a Arp *arp; Route *r; . 170c arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh) . ## diffname ip/arp.c 1999/0731 ## diff -e /n/emeliedump/1998/0630/sys/src/brazil/ip/arp.c /n/emeliedump/1999/0731/sys/src/brazil/ip/arp.c 127,132c if(bp != nil){ if(a->hold) a->last->list = bp; else a->hold = bp; a->last = bp; bp->list = nil; } . ## diffname ip/arp.c 2000/0212 ## diff -e /n/emeliedump/1999/0731/sys/src/brazil/ip/arp.c /n/emeliedump/2000/0212/sys/src/9/ip/arp.c 198c // print("arp: no route for entry\n"); . ## diffname ip/arp.c 2000/0225 ## diff -e /n/emeliedump/2000/0212/sys/src/9/ip/arp.c /n/emeliedump/2000/0225/sys/src/9/ip/arp.c 185c // print("arp: len = %d\n", n); . ## diffname ip/arp.c 2000/0308 ## diff -e /n/emeliedump/2000/0225/sys/src/9/ip/arp.c /n/emeliedump/2000/0308/sys/src/9/ip/arp.c 274c n = getfields(buf, f, 4, 1, " "); . ## diffname ip/arp.c 2001/1117 ## diff -e /n/emeliedump/2000/0308/sys/src/9/ip/arp.c /n/emeliedump/2001/1117/sys/src/9/ip/arp.c 274c n = tokenize(buf, f, 4); . ## diffname ip/arp.c 2001/1120 ## diff -e /n/emeliedump/2001/1117/sys/src/9/ip/arp.c /n/emeliedump/2001/1120/sys/src/9/ip/arp.c 318a case CMflush: qlock(arp); for(a = arp->cache; a < &arp->cache[NCACHE]; a++){ memset(a->ip, 0, sizeof(a->ip)); memset(a->mac, 0, sizeof(a->mac)); a->hash = nil; a->state = 0; a->used = 0; while(a->hold != nil) { bp = a->hold->list; freeblist(a->hold); a->hold = bp; } } memset(arp->hash, 0, sizeof(arp->hash)); qunlock(arp); break; } poperror(); free(cb); . 316,317c break; . 307,308c parseip(ip, cb->f[2]); n = parsemac(mac, cb->f[3], m->maclen); . 304c m = ipfindmedium(cb->f[1]); . 301c n = parsemac(mac, cb->f[2], m->maclen); . 299c error("destination unreachable"); . 296c parseip(ip, cb->f[1]); . 294c cmderror(cb, Ecmdargs); . 274,292c ct = lookupcmd(cb, arpcmd, nelem(arpcmd)); switch(ct->index){ case CMadd: switch(cb->nf) { . 265,272c cb = parsecmd(s, len); if(waserror()){ free(cb); nexterror(); } . 260d 258a Cmdbuf *cb; Cmdtab *ct; . 40a static Cmdtab arpcmd[] = { CMadd, "add", 0, CMflush, "flush", 1, }; . 29a enum { CMadd, CMflush, }; . ## diffname ip/arp.c 2002/0507 ## diff -e /n/emeliedump/2001/1120/sys/src/9/ip/arp.c /n/emeliedump/2002/0507/sys/src/9/ip/arp.c 382a extern int rxmitsols(Arp *arp) { uint sflag; Block *next, *xp; Arpent *a, *b, **l; Fs *f; uchar ipsrc[IPaddrlen]; Ipifc *ifc = nil; long nrxt; qlock(arp); f = arp->f; a = arp->rxmt; if(a==nil){ nrxt = 0; goto dodrops; //return nrxt; } nrxt = a->rxtat - msec; if(nrxt > 3*ReTransTimer/4) goto dodrops; //return nrxt; for(; a; a = a->nextrxt){ ifc = a->ifc; assert(ifc != nil); if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){ xp = a->hold; a->hold = nil; if(xp){ if(arp->dropl == nil) arp->dropf = xp; else arp->dropl->list = xp; } cleanarpent(arp, a); } else break; } /* need to unlock arp, else will deadlock when icmpns * wants to lock arp later. */ qunlock(arp); if(a == nil) goto dodrops; // return 0; if(sflag = ipv6anylocal(ifc, ipsrc)) icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); runlock(ifc); /* grab lock on arp again */ qlock(arp); /* put to the end of re-transmit chain */ l = &arp->rxmt; for(b = *l; b; b = b->nextrxt){ if(b == a){ *l = a->nextrxt; break; } l = &b->nextrxt; } for(b = *l; b; b = b->nextrxt){ l = &b->nextrxt; } *l = a; a->rxtsrem--; a->nextrxt = nil; a->time = msec; a->rxtat = msec + ReTransTimer; a = arp->rxmt; if(a==nil) nrxt = 0; else nrxt = a->rxtat - msec; dodrops: xp = arp->dropf; arp->dropf = nil; arp->dropl = nil; qunlock(arp); for(; xp; xp = next){ next = xp->list; icmphostunr(f, ifc, xp, icmp6_adr_unreach, 1); } return nrxt; } static int rxready(void *v) { Arp *arp = (Arp *) v; int x; x = ((arp->rxmt != nil) || (arp->dropf != nil)); return x; } static void rxmitproc(void *v) { Arp *arp = v; long wakeupat; arp->rxmitp = up; print("arp rxmitproc started\n"); if(waserror()){ arp->rxmitp = 0; pexit("hangup", 1); } for(;;){ wakeupat = rxmitsols(arp); if(wakeupat == 0) sleep(&arp->rxmtq, rxready, v); else if(wakeupat > ReTransTimer/4) tsleep(&arp->rxmtq, return0, 0, wakeupat); } } . 344c char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n"; . 341c Alinelen= 90, . 315,335d 313c } else error(Ebadarp); . 304,305c parseip(ip, f[2]); n = parsemac(mac, f[3], m->maclen); . 301c m = ipfindmedium(f[1]); . 298c n = parsemac(mac, f[2], m->maclen); . 296c error("Destination unreachable"); . 293,294c parseip(ip, f[1]); if(isv4(ip)) r = v4lookup(fs, ip+IPv4off); else r = v6lookup(fs, ip); . 291c error(Ebadarg); . 285,289c n = getfields(buf, f, 4, 1, " "); if(strcmp(f[0], "flush") == 0){ qlock(arp); for(a = arp->cache; a < &arp->cache[NCACHE]; a++){ memset(a->ip, 0, sizeof(a->ip)); memset(a->mac, 0, sizeof(a->mac)); a->hash = nil; a->state = 0; a->used = 0; while(a->hold != nil){ bp = a->hold->list; freeblist(a->hold); a->hold = bp; } } memset(arp->hash, 0, sizeof(arp->hash)); // clear all pkts on these lists (rxmt, dropf/l) arp->rxmt = nil; arp->dropf = nil; arp->dropl = nil; qunlock(arp); } else if(strcmp(f[0], "add") == 0){ switch(n){ . 279,283c if(len == 0) error(Ebadarp); if(len >= sizeof(buf)) len = sizeof(buf)-1; strncpy(buf, s, len); buf[len] = 0; if(len > 0 && buf[len-1] == '\n') buf[len-1] = 0; . 274a char *f[4], buf[256]; . 272,273d 255c //a = newarp6(arp, ip, ifc, 0); if(version == 4) a = newarp(arp, ip, type); else a = newarp6(arp, ip, ifc, 0); . 231c while(bp){ . 225a if(version == V6){ /* take out of re-transmit chain */ l = &arp->rxmt; for(f = *l; f; f = f->nextrxt){ if(f == a){ *l = a->nextrxt; break; } l = &f->nextrxt; } } a->hold = nil; a->ifc = ifc; a->ifcid = ifc->ifcid; . 223c if(ipcmp(a->ip, ip) == 0){ . 219c for(a = arp->hash[haship(ip)]; a; a = a->hash){ . 210c if(r == nil){ . 202c if(version == V4){ . 197c if(n != 6){ . 189c Arpent *a, *f, **l; . 172a if(!isv4(a->ip)){ l = &arp->rxmt; for(f = *l; f; f = f->nextrxt){ if(f == a){ *l = a->nextrxt; break; } l = &f->nextrxt; } } . 171a Arpent *f, **l; . 135c //a = newarp6(arp, ip, ifc, (version != V4)); if(version == V4) a = newarp(arp, ip, type); else a = newarp6(arp, ip, ifc, 1); . 128c for(a = arp->hash[hash]; a; a = a->hash){ . 121c if(version == V4){ . 118a Medium *type = ifc->m; . 115c arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac) . 113a static Arpent* newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt) { uint t; Block *next, *xp; Arpent *a, *e, *f, **l; Medium *m = ifc->m; int empty; /* find oldest entry */ e = &arp->cache[NCACHE]; a = arp->cache; t = a->used; for(f = a; f < e; f++){ if(f->used < t){ t = f->used; a = f; } } /* dump waiting packets */ xp = a->hold; a->hold = nil; if(isv4(a->ip)){ while(xp){ next = xp->list; freeblist(xp); xp = next; } } else { // queue icmp unreachable for rxmitproc later on, w/o arp lock if(xp){ if(arp->dropl == nil) arp->dropf = xp; else arp->dropl->list = xp; for(next = xp->list; next; next = next->list) xp = next; arp->dropl = xp; wakeup(&arp->rxmtq); } } /* take out of current chain */ l = &arp->hash[haship(a->ip)]; for(f = *l; f; f = f->hash){ if(f == a){ *l = a->hash; break; } l = &f->hash; } /* insert into new chain */ l = &arp->hash[haship(ip)]; a->hash = *l; *l = a; memmove(a->ip, ip, sizeof(a->ip)); a->used = msec; a->time = 0; a->type = m; a->rxtat = msec + ReTransTimer; a->rxtsrem = MAX_MULTICAST_SOLICIT; a->ifc = ifc; a->ifcid = ifc->ifcid; /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */ if(!ipismulticast(a->ip) && addrxt){ l = &arp->rxmt; empty = (*l==nil); for(f = *l; f; f = f->nextrxt){ if(f == a){ *l = a->nextrxt; break; } l = &f->nextrxt; } for(f = *l; f; f = f->nextrxt){ l = &f->nextrxt; } *l = a; if(empty) wakeup(&arp->rxmtq); } a->nextrxt = nil; return a; } /* called with arp qlocked */ void cleanarpent(Arp *arp, Arpent *a) { Arpent *f, **l; a->used = 0; a->time = 0; a->type = 0; a->state = 0; /* take out of current chain */ l = &arp->hash[haship(a->ip)]; for(f = *l; f; f = f->hash){ if(f == a){ *l = a->hash; break; } l = &f->hash; } /* take out of re-transmit chain */ l = &arp->rxmt; for(f = *l; f; f = f->nextrxt){ if(f == a){ *l = a->nextrxt; break; } l = &f->nextrxt; } a->nextrxt = nil; a->hash = nil; a->hold = nil; a->last = nil; a->ifc = nil; } . 95c if(f == a){ . 85a . 62a f->arp->rxmt = nil; f->arp->dropf = f->arp->dropl = nil; kproc("rxmitproc", rxmitproc, f->arp); . 57a extern int ReTransTimer = RETRANS_TIMER; static void rxmitproc(void *v); . 47,53d 44a Arpent *rxmt; Proc *rxmitp; /* neib sol re-transmit proc */ Rendez rxmtq; Block *dropf, *dropl; . 30,35d 8a #include "ipv6.h" . ## diffname ip/arp.c 2002/0601 ## diff -e /n/emeliedump/2002/0507/sys/src/9/ip/arp.c /n/emeliedump/2002/0601/sys/src/9/ip/arp.c 675c //print("arp rxmitproc started\n"); . 420,425c a = newarp6(arp, ip, ifc, 0); . 357a break; default: panic("arpenter: version %d", version); return; /* to supress warnings */ } . 355,356c break; case V6: . 351c switch(version){ case V4: . 302a * Copy out the mac address from the Arpent. Return the * block waiting to get sent to this mac address. * . 268,272c a = newarp6(arp, ip, ifc, (version != V4)); . 245a /* * fill in the media address if we have it. Otherwise return an * Arpent that represents the state of the address resolution FSM * for ip. Add the packet to be sent onto the list of packets * waiting for ip->mac to be resolved. */ . 64,113d 62a /* * create a new arp entry for an ip address. */ . ## diffname ip/arp.c 2002/0710 ## diff -e /n/emeliedump/2002/0601/sys/src/9/ip/arp.c /n/emeliedump/2002/0710/sys/src/9/ip/arp.c 599c nrxt = a->rxtat - NOW; . 592,593c a->time = NOW; a->rxtat = NOW + ReTransTimer; . 535c nrxt = a->rxtat - NOW; . 378c a->used = NOW; . 283c a->used = NOW; . 230c a->used = NOW; . 131c a->rxtat = NOW + ReTransTimer; . 127c a->used = NOW; . ## diffname ip/arp.c 2003/0308 ## diff -e /n/emeliedump/2002/0710/sys/src/9/ip/arp.c /n/emeliedump/2003/0308/sys/src/9/ip/arp.c 446c r = v6lookup(fs, ip, nil); . 444c r = v4lookup(fs, ip+IPv4off, nil); . 316c r = v6lookup(fs, ip, nil); . 311c r = v4lookup(fs, ip, nil); . ## diffname ip/arp.c 2003/0310 ## diff -e /n/emeliedump/2003/0308/sys/src/9/ip/arp.c /n/emeliedump/2003/0310/sys/src/9/ip/arp.c 599c nrxt = a->rtime - NOW; . 592,593c a->rtime = NOW + ReTransTimer; . 535c nrxt = a->rtime - NOW; . 424c a->utime = 0; . 378c a->utime = NOW; a->ctime = a->utime; . 283c a->utime = NOW; . 243a /* remove old entries */ if(NOW - a->ctime > 15*60*1000) cleanarpent(arp, a); . 230c a->utime = NOW; . 168,169c a->utime = 0; a->ctime = 0; . 131c a->rtime = NOW + ReTransTimer; . 127,128c a->utime = NOW; a->ctime = a->utime; . 80,81c if(f->utime < t){ t = f->utime; . 78c t = a->utime; . ## diffname ip/arp.c 2003/0313 ## diff -e /n/emeliedump/2003/0310/sys/src/9/ip/arp.c /n/emeliedump/2003/0313/sys/src/9/ip/arp.c 392a a->ctime = NOW; . ## diffname ip/arp.c 2003/0318 ## diff -e /n/emeliedump/2003/0313/sys/src/9/ip/arp.c /n/emeliedump/2003/0318/sys/src/9/ip/arp.c 383,384d 364a . 363a a->utime = NOW; a->ctime = a->utime; . 357d 128c a->ctime = 0; .