19ef1f84bSDavid du Colombier #include "u.h"
29ef1f84bSDavid du Colombier #include "../port/lib.h"
39ef1f84bSDavid du Colombier #include "mem.h"
49ef1f84bSDavid du Colombier #include "dat.h"
59ef1f84bSDavid du Colombier #include "fns.h"
69ef1f84bSDavid du Colombier #include "../port/error.h"
79ef1f84bSDavid du Colombier
89ef1f84bSDavid du Colombier #include "ip.h"
99ef1f84bSDavid du Colombier #include "ipv6.h"
109ef1f84bSDavid du Colombier
119ef1f84bSDavid du Colombier /*
129ef1f84bSDavid du Colombier * address resolution tables
139ef1f84bSDavid du Colombier */
149ef1f84bSDavid du Colombier
159ef1f84bSDavid du Colombier enum
169ef1f84bSDavid du Colombier {
179ef1f84bSDavid du Colombier NHASH = (1<<6),
189ef1f84bSDavid du Colombier NCACHE = 256,
199ef1f84bSDavid du Colombier
209ef1f84bSDavid du Colombier AOK = 1,
219ef1f84bSDavid du Colombier AWAIT = 2,
229ef1f84bSDavid du Colombier };
239ef1f84bSDavid du Colombier
249ef1f84bSDavid du Colombier char *arpstate[] =
259ef1f84bSDavid du Colombier {
269ef1f84bSDavid du Colombier "UNUSED",
279ef1f84bSDavid du Colombier "OK",
289ef1f84bSDavid du Colombier "WAIT",
299ef1f84bSDavid du Colombier };
309ef1f84bSDavid du Colombier
319ef1f84bSDavid du Colombier /*
329ef1f84bSDavid du Colombier * one per Fs
339ef1f84bSDavid du Colombier */
349ef1f84bSDavid du Colombier struct Arp
359ef1f84bSDavid du Colombier {
369ef1f84bSDavid du Colombier QLock;
379ef1f84bSDavid du Colombier Fs *f;
389ef1f84bSDavid du Colombier Arpent *hash[NHASH];
399ef1f84bSDavid du Colombier Arpent cache[NCACHE];
409ef1f84bSDavid du Colombier Arpent *rxmt;
419ef1f84bSDavid du Colombier Proc *rxmitp; /* neib sol re-transmit proc */
429ef1f84bSDavid du Colombier Rendez rxmtq;
439ef1f84bSDavid du Colombier Block *dropf, *dropl;
449ef1f84bSDavid du Colombier };
459ef1f84bSDavid du Colombier
469ef1f84bSDavid du Colombier char *Ebadarp = "bad arp";
479ef1f84bSDavid du Colombier
489ef1f84bSDavid du Colombier #define haship(s) ((s)[IPaddrlen-1]%NHASH)
499ef1f84bSDavid du Colombier
509ef1f84bSDavid du Colombier extern int ReTransTimer = RETRANS_TIMER;
519ef1f84bSDavid du Colombier
529ef1f84bSDavid du Colombier static void rxmitproc(void *v);
539ef1f84bSDavid du Colombier
549ef1f84bSDavid du Colombier void
arpinit(Fs * f)559ef1f84bSDavid du Colombier arpinit(Fs *f)
569ef1f84bSDavid du Colombier {
579ef1f84bSDavid du Colombier f->arp = smalloc(sizeof(Arp));
589ef1f84bSDavid du Colombier f->arp->f = f;
599ef1f84bSDavid du Colombier f->arp->rxmt = nil;
609ef1f84bSDavid du Colombier f->arp->dropf = f->arp->dropl = nil;
619ef1f84bSDavid du Colombier kproc("rxmitproc", rxmitproc, f->arp);
629ef1f84bSDavid du Colombier }
639ef1f84bSDavid du Colombier
649ef1f84bSDavid du Colombier /*
659ef1f84bSDavid du Colombier * create a new arp entry for an ip address.
669ef1f84bSDavid du Colombier */
679ef1f84bSDavid du Colombier static Arpent*
newarp6(Arp * arp,uchar * ip,Ipifc * ifc,int addrxt)689ef1f84bSDavid du Colombier newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
699ef1f84bSDavid du Colombier {
709ef1f84bSDavid du Colombier uint t;
719ef1f84bSDavid du Colombier Block *next, *xp;
729ef1f84bSDavid du Colombier Arpent *a, *e, *f, **l;
739ef1f84bSDavid du Colombier int empty;
749ef1f84bSDavid du Colombier
759ef1f84bSDavid du Colombier /* find oldest entry */
769ef1f84bSDavid du Colombier e = &arp->cache[NCACHE];
779ef1f84bSDavid du Colombier a = arp->cache;
789ef1f84bSDavid du Colombier t = a->utime;
799ef1f84bSDavid du Colombier for(f = a; f < e; f++){
809ef1f84bSDavid du Colombier if(f->utime < t){
819ef1f84bSDavid du Colombier t = f->utime;
829ef1f84bSDavid du Colombier a = f;
839ef1f84bSDavid du Colombier }
849ef1f84bSDavid du Colombier }
859ef1f84bSDavid du Colombier
869ef1f84bSDavid du Colombier /* dump waiting packets */
879ef1f84bSDavid du Colombier xp = a->hold;
889ef1f84bSDavid du Colombier a->hold = nil;
899ef1f84bSDavid du Colombier
909ef1f84bSDavid du Colombier if(isv4(a->ip)){
919ef1f84bSDavid du Colombier while(xp){
929ef1f84bSDavid du Colombier next = xp->list;
939ef1f84bSDavid du Colombier freeblist(xp);
949ef1f84bSDavid du Colombier xp = next;
959ef1f84bSDavid du Colombier }
969ef1f84bSDavid du Colombier }
979ef1f84bSDavid du Colombier else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
989ef1f84bSDavid du Colombier if(xp){
999ef1f84bSDavid du Colombier if(arp->dropl == nil)
1009ef1f84bSDavid du Colombier arp->dropf = xp;
1019ef1f84bSDavid du Colombier else
1029ef1f84bSDavid du Colombier arp->dropl->list = xp;
1039ef1f84bSDavid du Colombier
1049ef1f84bSDavid du Colombier for(next = xp->list; next; next = next->list)
1059ef1f84bSDavid du Colombier xp = next;
1069ef1f84bSDavid du Colombier arp->dropl = xp;
1079ef1f84bSDavid du Colombier wakeup(&arp->rxmtq);
1089ef1f84bSDavid du Colombier }
1099ef1f84bSDavid du Colombier }
1109ef1f84bSDavid du Colombier
1119ef1f84bSDavid du Colombier /* take out of current chain */
1129ef1f84bSDavid du Colombier l = &arp->hash[haship(a->ip)];
1139ef1f84bSDavid du Colombier for(f = *l; f; f = f->hash){
1149ef1f84bSDavid du Colombier if(f == a){
1159ef1f84bSDavid du Colombier *l = a->hash;
1169ef1f84bSDavid du Colombier break;
1179ef1f84bSDavid du Colombier }
1189ef1f84bSDavid du Colombier l = &f->hash;
1199ef1f84bSDavid du Colombier }
1209ef1f84bSDavid du Colombier
1219ef1f84bSDavid du Colombier /* insert into new chain */
1229ef1f84bSDavid du Colombier l = &arp->hash[haship(ip)];
1239ef1f84bSDavid du Colombier a->hash = *l;
1249ef1f84bSDavid du Colombier *l = a;
1259ef1f84bSDavid du Colombier
1269ef1f84bSDavid du Colombier memmove(a->ip, ip, sizeof(a->ip));
1279ef1f84bSDavid du Colombier a->utime = NOW;
1289ef1f84bSDavid du Colombier a->ctime = 0;
1299ef1f84bSDavid du Colombier a->type = ifc->medium;
1309ef1f84bSDavid du Colombier
1319ef1f84bSDavid du Colombier a->rtime = NOW + ReTransTimer;
1329ef1f84bSDavid du Colombier a->rxtsrem = MAX_MULTICAST_SOLICIT;
1339ef1f84bSDavid du Colombier a->ifc = ifc;
1349ef1f84bSDavid du Colombier a->ifcid = ifc->ifcid;
1359ef1f84bSDavid du Colombier
1369ef1f84bSDavid du Colombier /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
1379ef1f84bSDavid du Colombier if(!ipismulticast(a->ip) && addrxt){
1389ef1f84bSDavid du Colombier l = &arp->rxmt;
1399ef1f84bSDavid du Colombier empty = (*l==nil);
1409ef1f84bSDavid du Colombier
1419ef1f84bSDavid du Colombier for(f = *l; f; f = f->nextrxt){
1429ef1f84bSDavid du Colombier if(f == a){
1439ef1f84bSDavid du Colombier *l = a->nextrxt;
1449ef1f84bSDavid du Colombier break;
1459ef1f84bSDavid du Colombier }
1469ef1f84bSDavid du Colombier l = &f->nextrxt;
1479ef1f84bSDavid du Colombier }
1489ef1f84bSDavid du Colombier for(f = *l; f; f = f->nextrxt){
1499ef1f84bSDavid du Colombier l = &f->nextrxt;
1509ef1f84bSDavid du Colombier }
1519ef1f84bSDavid du Colombier *l = a;
1529ef1f84bSDavid du Colombier if(empty)
1539ef1f84bSDavid du Colombier wakeup(&arp->rxmtq);
1549ef1f84bSDavid du Colombier }
1559ef1f84bSDavid du Colombier
1569ef1f84bSDavid du Colombier a->nextrxt = nil;
1579ef1f84bSDavid du Colombier
1589ef1f84bSDavid du Colombier return a;
1599ef1f84bSDavid du Colombier }
1609ef1f84bSDavid du Colombier
1619ef1f84bSDavid du Colombier /* called with arp qlocked */
1629ef1f84bSDavid du Colombier
1639ef1f84bSDavid du Colombier void
cleanarpent(Arp * arp,Arpent * a)1649ef1f84bSDavid du Colombier cleanarpent(Arp *arp, Arpent *a)
1659ef1f84bSDavid du Colombier {
1669ef1f84bSDavid du Colombier Arpent *f, **l;
1679ef1f84bSDavid du Colombier
1689ef1f84bSDavid du Colombier a->utime = 0;
1699ef1f84bSDavid du Colombier a->ctime = 0;
1709ef1f84bSDavid du Colombier a->type = 0;
1719ef1f84bSDavid du Colombier a->state = 0;
1729ef1f84bSDavid du Colombier
1739ef1f84bSDavid du Colombier /* take out of current chain */
1749ef1f84bSDavid du Colombier l = &arp->hash[haship(a->ip)];
1759ef1f84bSDavid du Colombier for(f = *l; f; f = f->hash){
1769ef1f84bSDavid du Colombier if(f == a){
1779ef1f84bSDavid du Colombier *l = a->hash;
1789ef1f84bSDavid du Colombier break;
1799ef1f84bSDavid du Colombier }
1809ef1f84bSDavid du Colombier l = &f->hash;
1819ef1f84bSDavid du Colombier }
1829ef1f84bSDavid du Colombier
1839ef1f84bSDavid du Colombier /* take out of re-transmit chain */
1849ef1f84bSDavid du Colombier l = &arp->rxmt;
1859ef1f84bSDavid du Colombier for(f = *l; f; f = f->nextrxt){
1869ef1f84bSDavid du Colombier if(f == a){
1879ef1f84bSDavid du Colombier *l = a->nextrxt;
1889ef1f84bSDavid du Colombier break;
1899ef1f84bSDavid du Colombier }
1909ef1f84bSDavid du Colombier l = &f->nextrxt;
1919ef1f84bSDavid du Colombier }
1929ef1f84bSDavid du Colombier a->nextrxt = nil;
1939ef1f84bSDavid du Colombier a->hash = nil;
1949ef1f84bSDavid du Colombier a->hold = nil;
1959ef1f84bSDavid du Colombier a->last = nil;
1969ef1f84bSDavid du Colombier a->ifc = nil;
1979ef1f84bSDavid du Colombier }
1989ef1f84bSDavid du Colombier
1999ef1f84bSDavid du Colombier /*
2009ef1f84bSDavid du Colombier * fill in the media address if we have it. Otherwise return an
2019ef1f84bSDavid du Colombier * Arpent that represents the state of the address resolution FSM
2029ef1f84bSDavid du Colombier * for ip. Add the packet to be sent onto the list of packets
2039ef1f84bSDavid du Colombier * waiting for ip->mac to be resolved.
2049ef1f84bSDavid du Colombier */
2059ef1f84bSDavid du Colombier Arpent*
arpget(Arp * arp,Block * bp,int version,Ipifc * ifc,uchar * ip,uchar * mac)2069ef1f84bSDavid du Colombier arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
2079ef1f84bSDavid du Colombier {
2089ef1f84bSDavid du Colombier int hash;
2099ef1f84bSDavid du Colombier Arpent *a;
2109ef1f84bSDavid du Colombier Medium *type;
2119ef1f84bSDavid du Colombier uchar v6ip[IPaddrlen];
2129ef1f84bSDavid du Colombier
2139ef1f84bSDavid du Colombier if(version == V4){
2149ef1f84bSDavid du Colombier v4tov6(v6ip, ip);
2159ef1f84bSDavid du Colombier ip = v6ip;
2169ef1f84bSDavid du Colombier }
2179ef1f84bSDavid du Colombier
2189ef1f84bSDavid du Colombier qlock(arp);
2199ef1f84bSDavid du Colombier hash = haship(ip);
2209ef1f84bSDavid du Colombier type = ifc->medium;
2219ef1f84bSDavid du Colombier for(a = arp->hash[hash]; a; a = a->hash){
2229ef1f84bSDavid du Colombier if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
2239ef1f84bSDavid du Colombier if(type == a->type)
2249ef1f84bSDavid du Colombier break;
2259ef1f84bSDavid du Colombier }
2269ef1f84bSDavid du Colombier
2279ef1f84bSDavid du Colombier if(a == nil){
2289ef1f84bSDavid du Colombier a = newarp6(arp, ip, ifc, (version != V4));
2299ef1f84bSDavid du Colombier a->state = AWAIT;
2309ef1f84bSDavid du Colombier }
2319ef1f84bSDavid du Colombier a->utime = NOW;
2329ef1f84bSDavid du Colombier if(a->state == AWAIT){
2339ef1f84bSDavid du Colombier if(bp != nil){
2349ef1f84bSDavid du Colombier if(a->hold)
2359ef1f84bSDavid du Colombier a->last->list = bp;
2369ef1f84bSDavid du Colombier else
2379ef1f84bSDavid du Colombier a->hold = bp;
2389ef1f84bSDavid du Colombier a->last = bp;
2399ef1f84bSDavid du Colombier bp->list = nil;
2409ef1f84bSDavid du Colombier }
2419ef1f84bSDavid du Colombier return a; /* return with arp qlocked */
2429ef1f84bSDavid du Colombier }
2439ef1f84bSDavid du Colombier
2449ef1f84bSDavid du Colombier memmove(mac, a->mac, a->type->maclen);
2459ef1f84bSDavid du Colombier
2469ef1f84bSDavid du Colombier /* remove old entries */
2479ef1f84bSDavid du Colombier if(NOW - a->ctime > 15*60*1000)
2489ef1f84bSDavid du Colombier cleanarpent(arp, a);
2499ef1f84bSDavid du Colombier
2509ef1f84bSDavid du Colombier qunlock(arp);
2519ef1f84bSDavid du Colombier return nil;
2529ef1f84bSDavid du Colombier }
2539ef1f84bSDavid du Colombier
2549ef1f84bSDavid du Colombier /*
2559ef1f84bSDavid du Colombier * called with arp locked
2569ef1f84bSDavid du Colombier */
2579ef1f84bSDavid du Colombier void
arprelease(Arp * arp,Arpent *)2589ef1f84bSDavid du Colombier arprelease(Arp *arp, Arpent*)
2599ef1f84bSDavid du Colombier {
2609ef1f84bSDavid du Colombier qunlock(arp);
2619ef1f84bSDavid du Colombier }
2629ef1f84bSDavid du Colombier
2639ef1f84bSDavid du Colombier /*
2649ef1f84bSDavid du Colombier * Copy out the mac address from the Arpent. Return the
2659ef1f84bSDavid du Colombier * block waiting to get sent to this mac address.
2669ef1f84bSDavid du Colombier *
2679ef1f84bSDavid du Colombier * called with arp locked
2689ef1f84bSDavid du Colombier */
2699ef1f84bSDavid du Colombier Block*
arpresolve(Arp * arp,Arpent * a,Medium * type,uchar * mac)2709ef1f84bSDavid du Colombier arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
2719ef1f84bSDavid du Colombier {
2729ef1f84bSDavid du Colombier Block *bp;
2739ef1f84bSDavid du Colombier Arpent *f, **l;
2749ef1f84bSDavid du Colombier
2759ef1f84bSDavid du Colombier if(!isv4(a->ip)){
2769ef1f84bSDavid du Colombier l = &arp->rxmt;
2779ef1f84bSDavid du Colombier for(f = *l; f; f = f->nextrxt){
2789ef1f84bSDavid du Colombier if(f == a){
2799ef1f84bSDavid du Colombier *l = a->nextrxt;
2809ef1f84bSDavid du Colombier break;
2819ef1f84bSDavid du Colombier }
2829ef1f84bSDavid du Colombier l = &f->nextrxt;
2839ef1f84bSDavid du Colombier }
2849ef1f84bSDavid du Colombier }
2859ef1f84bSDavid du Colombier
2869ef1f84bSDavid du Colombier memmove(a->mac, mac, type->maclen);
2879ef1f84bSDavid du Colombier a->type = type;
2889ef1f84bSDavid du Colombier a->state = AOK;
2899ef1f84bSDavid du Colombier a->utime = NOW;
2909ef1f84bSDavid du Colombier bp = a->hold;
2919ef1f84bSDavid du Colombier a->hold = nil;
2929ef1f84bSDavid du Colombier qunlock(arp);
2939ef1f84bSDavid du Colombier
2949ef1f84bSDavid du Colombier return bp;
2959ef1f84bSDavid du Colombier }
2969ef1f84bSDavid du Colombier
2979ef1f84bSDavid du Colombier void
arpenter(Fs * fs,int version,uchar * ip,uchar * mac,int n,int refresh)2989ef1f84bSDavid du Colombier arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
2999ef1f84bSDavid du Colombier {
3009ef1f84bSDavid du Colombier Arp *arp;
3019ef1f84bSDavid du Colombier Route *r;
3029ef1f84bSDavid du Colombier Arpent *a, *f, **l;
3039ef1f84bSDavid du Colombier Ipifc *ifc;
3049ef1f84bSDavid du Colombier Medium *type;
3059ef1f84bSDavid du Colombier Block *bp, *next;
3069ef1f84bSDavid du Colombier uchar v6ip[IPaddrlen];
3079ef1f84bSDavid du Colombier
3089ef1f84bSDavid du Colombier arp = fs->arp;
3099ef1f84bSDavid du Colombier
3109ef1f84bSDavid du Colombier if(n != 6){
3119ef1f84bSDavid du Colombier // print("arp: len = %d\n", n);
3129ef1f84bSDavid du Colombier return;
3139ef1f84bSDavid du Colombier }
3149ef1f84bSDavid du Colombier
3159ef1f84bSDavid du Colombier switch(version){
3169ef1f84bSDavid du Colombier case V4:
3179ef1f84bSDavid du Colombier r = v4lookup(fs, ip, nil);
3189ef1f84bSDavid du Colombier v4tov6(v6ip, ip);
3199ef1f84bSDavid du Colombier ip = v6ip;
3209ef1f84bSDavid du Colombier break;
3219ef1f84bSDavid du Colombier case V6:
3229ef1f84bSDavid du Colombier r = v6lookup(fs, ip, nil);
3239ef1f84bSDavid du Colombier break;
3249ef1f84bSDavid du Colombier default:
3259ef1f84bSDavid du Colombier panic("arpenter: version %d", version);
3269ef1f84bSDavid du Colombier return; /* to supress warnings */
3279ef1f84bSDavid du Colombier }
3289ef1f84bSDavid du Colombier
3299ef1f84bSDavid du Colombier if(r == nil){
3309ef1f84bSDavid du Colombier // print("arp: no route for entry\n");
3319ef1f84bSDavid du Colombier return;
3329ef1f84bSDavid du Colombier }
3339ef1f84bSDavid du Colombier
3349ef1f84bSDavid du Colombier ifc = r->ifc;
3359ef1f84bSDavid du Colombier type = ifc->medium;
3369ef1f84bSDavid du Colombier
3379ef1f84bSDavid du Colombier qlock(arp);
3389ef1f84bSDavid du Colombier for(a = arp->hash[haship(ip)]; a; a = a->hash){
3399ef1f84bSDavid du Colombier if(a->type != type || (a->state != AWAIT && a->state != AOK))
3409ef1f84bSDavid du Colombier continue;
3419ef1f84bSDavid du Colombier
3429ef1f84bSDavid du Colombier if(ipcmp(a->ip, ip) == 0){
3439ef1f84bSDavid du Colombier a->state = AOK;
3449ef1f84bSDavid du Colombier memmove(a->mac, mac, type->maclen);
3459ef1f84bSDavid du Colombier
3469ef1f84bSDavid du Colombier if(version == V6){
3479ef1f84bSDavid du Colombier /* take out of re-transmit chain */
3489ef1f84bSDavid du Colombier l = &arp->rxmt;
3499ef1f84bSDavid du Colombier for(f = *l; f; f = f->nextrxt){
3509ef1f84bSDavid du Colombier if(f == a){
3519ef1f84bSDavid du Colombier *l = a->nextrxt;
3529ef1f84bSDavid du Colombier break;
3539ef1f84bSDavid du Colombier }
3549ef1f84bSDavid du Colombier l = &f->nextrxt;
3559ef1f84bSDavid du Colombier }
3569ef1f84bSDavid du Colombier }
3579ef1f84bSDavid du Colombier
3589ef1f84bSDavid du Colombier a->ifc = ifc;
3599ef1f84bSDavid du Colombier a->ifcid = ifc->ifcid;
3609ef1f84bSDavid du Colombier bp = a->hold;
3619ef1f84bSDavid du Colombier a->hold = nil;
3629ef1f84bSDavid du Colombier if(version == V4)
3639ef1f84bSDavid du Colombier ip += IPv4off;
3649ef1f84bSDavid du Colombier a->utime = NOW;
3659ef1f84bSDavid du Colombier a->ctime = a->utime;
3669ef1f84bSDavid du Colombier qunlock(arp);
3679ef1f84bSDavid du Colombier
3689ef1f84bSDavid du Colombier while(bp){
3699ef1f84bSDavid du Colombier next = bp->list;
3709ef1f84bSDavid du Colombier if(ifc != nil){
3719ef1f84bSDavid du Colombier if(waserror()){
3729ef1f84bSDavid du Colombier runlock(ifc);
3739ef1f84bSDavid du Colombier nexterror();
3749ef1f84bSDavid du Colombier }
3759ef1f84bSDavid du Colombier rlock(ifc);
3769ef1f84bSDavid du Colombier if(ifc->medium != nil)
3779ef1f84bSDavid du Colombier ifc->medium->bwrite(ifc, bp, version, ip);
3789ef1f84bSDavid du Colombier else
3799ef1f84bSDavid du Colombier freeb(bp);
3809ef1f84bSDavid du Colombier runlock(ifc);
3819ef1f84bSDavid du Colombier poperror();
3829ef1f84bSDavid du Colombier } else
3839ef1f84bSDavid du Colombier freeb(bp);
3849ef1f84bSDavid du Colombier bp = next;
3859ef1f84bSDavid du Colombier }
3869ef1f84bSDavid du Colombier return;
3879ef1f84bSDavid du Colombier }
3889ef1f84bSDavid du Colombier }
3899ef1f84bSDavid du Colombier
3909ef1f84bSDavid du Colombier if(refresh == 0){
3919ef1f84bSDavid du Colombier a = newarp6(arp, ip, ifc, 0);
3929ef1f84bSDavid du Colombier a->state = AOK;
3939ef1f84bSDavid du Colombier a->type = type;
3949ef1f84bSDavid du Colombier a->ctime = NOW;
3959ef1f84bSDavid du Colombier memmove(a->mac, mac, type->maclen);
3969ef1f84bSDavid du Colombier }
3979ef1f84bSDavid du Colombier
3989ef1f84bSDavid du Colombier qunlock(arp);
3999ef1f84bSDavid du Colombier }
4009ef1f84bSDavid du Colombier
4019ef1f84bSDavid du Colombier int
arpwrite(Fs * fs,char * s,int len)4029ef1f84bSDavid du Colombier arpwrite(Fs *fs, char *s, int len)
4039ef1f84bSDavid du Colombier {
4049ef1f84bSDavid du Colombier int n;
4059ef1f84bSDavid du Colombier Route *r;
4069ef1f84bSDavid du Colombier Arp *arp;
4079ef1f84bSDavid du Colombier Block *bp;
4089ef1f84bSDavid du Colombier Arpent *a, *fl, **l;
4099ef1f84bSDavid du Colombier Medium *type;
4109ef1f84bSDavid du Colombier char *f[4], buf[256];
4119ef1f84bSDavid du Colombier uchar ip[IPaddrlen], mac[MAClen];
4129ef1f84bSDavid du Colombier
4139ef1f84bSDavid du Colombier arp = fs->arp;
4149ef1f84bSDavid du Colombier
4159ef1f84bSDavid du Colombier if(len == 0)
4169ef1f84bSDavid du Colombier error(Ebadarp);
4179ef1f84bSDavid du Colombier if(len >= sizeof(buf))
4189ef1f84bSDavid du Colombier len = sizeof(buf)-1;
4199ef1f84bSDavid du Colombier strncpy(buf, s, len);
4209ef1f84bSDavid du Colombier buf[len] = 0;
4219ef1f84bSDavid du Colombier if(len > 0 && buf[len-1] == '\n')
4229ef1f84bSDavid du Colombier buf[len-1] = 0;
4239ef1f84bSDavid du Colombier
4249ef1f84bSDavid du Colombier n = getfields(buf, f, 4, 1, " ");
4259ef1f84bSDavid du Colombier if(strcmp(f[0], "flush") == 0){
4269ef1f84bSDavid du Colombier qlock(arp);
4279ef1f84bSDavid du Colombier for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
4289ef1f84bSDavid du Colombier memset(a->ip, 0, sizeof(a->ip));
4299ef1f84bSDavid du Colombier memset(a->mac, 0, sizeof(a->mac));
4309ef1f84bSDavid du Colombier a->hash = nil;
4319ef1f84bSDavid du Colombier a->state = 0;
4329ef1f84bSDavid du Colombier a->utime = 0;
4339ef1f84bSDavid du Colombier while(a->hold != nil){
4349ef1f84bSDavid du Colombier bp = a->hold->list;
4359ef1f84bSDavid du Colombier freeblist(a->hold);
4369ef1f84bSDavid du Colombier a->hold = bp;
4379ef1f84bSDavid du Colombier }
4389ef1f84bSDavid du Colombier }
4399ef1f84bSDavid du Colombier memset(arp->hash, 0, sizeof(arp->hash));
4409ef1f84bSDavid du Colombier /* clear all pkts on these lists (rxmt, dropf/l) */
4419ef1f84bSDavid du Colombier arp->rxmt = nil;
4429ef1f84bSDavid du Colombier arp->dropf = nil;
4439ef1f84bSDavid du Colombier arp->dropl = nil;
4449ef1f84bSDavid du Colombier qunlock(arp);
4459ef1f84bSDavid du Colombier } else if(strcmp(f[0], "add") == 0){
4469ef1f84bSDavid du Colombier switch(n){
4479ef1f84bSDavid du Colombier default:
4489ef1f84bSDavid du Colombier error(Ebadarg);
4499ef1f84bSDavid du Colombier case 3:
4509ef1f84bSDavid du Colombier if (parseip(ip, f[1]) == -1)
4519ef1f84bSDavid du Colombier error(Ebadip);
4529ef1f84bSDavid du Colombier if(isv4(ip))
4539ef1f84bSDavid du Colombier r = v4lookup(fs, ip+IPv4off, nil);
4549ef1f84bSDavid du Colombier else
4559ef1f84bSDavid du Colombier r = v6lookup(fs, ip, nil);
4569ef1f84bSDavid du Colombier if(r == nil)
4579ef1f84bSDavid du Colombier error("Destination unreachable");
4589ef1f84bSDavid du Colombier type = r->ifc->medium;
4599ef1f84bSDavid du Colombier n = parsemac(mac, f[2], type->maclen);
4609ef1f84bSDavid du Colombier break;
4619ef1f84bSDavid du Colombier case 4:
4629ef1f84bSDavid du Colombier type = ipfindmedium(f[1]);
4639ef1f84bSDavid du Colombier if(type == nil)
4649ef1f84bSDavid du Colombier error(Ebadarp);
4659ef1f84bSDavid du Colombier if (parseip(ip, f[2]) == -1)
4669ef1f84bSDavid du Colombier error(Ebadip);
4679ef1f84bSDavid du Colombier n = parsemac(mac, f[3], type->maclen);
4689ef1f84bSDavid du Colombier break;
4699ef1f84bSDavid du Colombier }
4709ef1f84bSDavid du Colombier
4719ef1f84bSDavid du Colombier if(type->ares == nil)
4729ef1f84bSDavid du Colombier error(Ebadarp);
4739ef1f84bSDavid du Colombier
4749ef1f84bSDavid du Colombier type->ares(fs, V6, ip, mac, n, 0);
4759ef1f84bSDavid du Colombier } else if(strcmp(f[0], "del") == 0){
4769ef1f84bSDavid du Colombier if(n != 2)
4779ef1f84bSDavid du Colombier error(Ebadarg);
4789ef1f84bSDavid du Colombier
4799ef1f84bSDavid du Colombier if (parseip(ip, f[1]) == -1)
4809ef1f84bSDavid du Colombier error(Ebadip);
4819ef1f84bSDavid du Colombier qlock(arp);
4829ef1f84bSDavid du Colombier
4839ef1f84bSDavid du Colombier l = &arp->hash[haship(ip)];
4849ef1f84bSDavid du Colombier for(a = *l; a; a = a->hash){
4859ef1f84bSDavid du Colombier if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
4869ef1f84bSDavid du Colombier *l = a->hash;
4879ef1f84bSDavid du Colombier break;
4889ef1f84bSDavid du Colombier }
4899ef1f84bSDavid du Colombier l = &a->hash;
4909ef1f84bSDavid du Colombier }
4919ef1f84bSDavid du Colombier
4929ef1f84bSDavid du Colombier if(a){
4939ef1f84bSDavid du Colombier /* take out of re-transmit chain */
4949ef1f84bSDavid du Colombier l = &arp->rxmt;
4959ef1f84bSDavid du Colombier for(fl = *l; fl; fl = fl->nextrxt){
4969ef1f84bSDavid du Colombier if(fl == a){
4979ef1f84bSDavid du Colombier *l = a->nextrxt;
4989ef1f84bSDavid du Colombier break;
4999ef1f84bSDavid du Colombier }
5009ef1f84bSDavid du Colombier l = &fl->nextrxt;
5019ef1f84bSDavid du Colombier }
5029ef1f84bSDavid du Colombier
5039ef1f84bSDavid du Colombier a->nextrxt = nil;
5049ef1f84bSDavid du Colombier a->hash = nil;
5059ef1f84bSDavid du Colombier a->hold = nil;
5069ef1f84bSDavid du Colombier a->last = nil;
5079ef1f84bSDavid du Colombier a->ifc = nil;
5089ef1f84bSDavid du Colombier memset(a->ip, 0, sizeof(a->ip));
5099ef1f84bSDavid du Colombier memset(a->mac, 0, sizeof(a->mac));
5109ef1f84bSDavid du Colombier }
5119ef1f84bSDavid du Colombier qunlock(arp);
5129ef1f84bSDavid du Colombier } else
5139ef1f84bSDavid du Colombier error(Ebadarp);
5149ef1f84bSDavid du Colombier
5159ef1f84bSDavid du Colombier return len;
5169ef1f84bSDavid du Colombier }
5179ef1f84bSDavid du Colombier
5189ef1f84bSDavid du Colombier enum
5199ef1f84bSDavid du Colombier {
5209ef1f84bSDavid du Colombier Alinelen= 90,
5219ef1f84bSDavid du Colombier };
5229ef1f84bSDavid du Colombier
5239ef1f84bSDavid du Colombier char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
5249ef1f84bSDavid du Colombier
5259ef1f84bSDavid du Colombier static void
convmac(char * p,char * ep,uchar * mac,int n)526*a3323688SDavid du Colombier convmac(char *p, char *ep, uchar *mac, int n)
5279ef1f84bSDavid du Colombier {
5289ef1f84bSDavid du Colombier while(n-- > 0)
529*a3323688SDavid du Colombier p = seprint(p, ep, "%2.2ux", *mac++);
5309ef1f84bSDavid du Colombier }
5319ef1f84bSDavid du Colombier
5329ef1f84bSDavid du Colombier int
arpread(Arp * arp,char * p,ulong offset,int len)5339ef1f84bSDavid du Colombier arpread(Arp *arp, char *p, ulong offset, int len)
5349ef1f84bSDavid du Colombier {
5359ef1f84bSDavid du Colombier Arpent *a;
5369ef1f84bSDavid du Colombier int n;
5379ef1f84bSDavid du Colombier char mac[2*MAClen+1];
5389ef1f84bSDavid du Colombier
5399ef1f84bSDavid du Colombier if(offset % Alinelen)
5409ef1f84bSDavid du Colombier return 0;
5419ef1f84bSDavid du Colombier
5429ef1f84bSDavid du Colombier offset = offset/Alinelen;
5439ef1f84bSDavid du Colombier len = len/Alinelen;
5449ef1f84bSDavid du Colombier
5459ef1f84bSDavid du Colombier n = 0;
5469ef1f84bSDavid du Colombier for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
5479ef1f84bSDavid du Colombier if(a->state == 0)
5489ef1f84bSDavid du Colombier continue;
5499ef1f84bSDavid du Colombier if(offset > 0){
5509ef1f84bSDavid du Colombier offset--;
5519ef1f84bSDavid du Colombier continue;
5529ef1f84bSDavid du Colombier }
5539ef1f84bSDavid du Colombier len--;
5549ef1f84bSDavid du Colombier qlock(arp);
555*a3323688SDavid du Colombier convmac(mac, &mac[sizeof mac], a->mac, a->type->maclen);
556*a3323688SDavid du Colombier n += snprint(p+n, Alinelen+1, aformat, a->type->name,
557*a3323688SDavid du Colombier arpstate[a->state], a->ip, mac); /* +1 for NUL */
5589ef1f84bSDavid du Colombier qunlock(arp);
5599ef1f84bSDavid du Colombier }
5609ef1f84bSDavid du Colombier
5619ef1f84bSDavid du Colombier return n;
5629ef1f84bSDavid du Colombier }
5639ef1f84bSDavid du Colombier
5649ef1f84bSDavid du Colombier extern int
rxmitsols(Arp * arp)5659ef1f84bSDavid du Colombier rxmitsols(Arp *arp)
5669ef1f84bSDavid du Colombier {
5679ef1f84bSDavid du Colombier uint sflag;
5689ef1f84bSDavid du Colombier Block *next, *xp;
5699ef1f84bSDavid du Colombier Arpent *a, *b, **l;
5709ef1f84bSDavid du Colombier Fs *f;
5719ef1f84bSDavid du Colombier uchar ipsrc[IPaddrlen];
5729ef1f84bSDavid du Colombier Ipifc *ifc = nil;
5739ef1f84bSDavid du Colombier long nrxt;
5749ef1f84bSDavid du Colombier
5759ef1f84bSDavid du Colombier qlock(arp);
5769ef1f84bSDavid du Colombier f = arp->f;
5779ef1f84bSDavid du Colombier
5789ef1f84bSDavid du Colombier a = arp->rxmt;
5799ef1f84bSDavid du Colombier if(a==nil){
5809ef1f84bSDavid du Colombier nrxt = 0;
5819ef1f84bSDavid du Colombier goto dodrops; /* return nrxt; */
5829ef1f84bSDavid du Colombier }
5839ef1f84bSDavid du Colombier nrxt = a->rtime - NOW;
5849ef1f84bSDavid du Colombier if(nrxt > 3*ReTransTimer/4)
5859ef1f84bSDavid du Colombier goto dodrops; /* return nrxt; */
5869ef1f84bSDavid du Colombier
5879ef1f84bSDavid du Colombier for(; a; a = a->nextrxt){
5889ef1f84bSDavid du Colombier ifc = a->ifc;
5899ef1f84bSDavid du Colombier assert(ifc != nil);
5909ef1f84bSDavid du Colombier if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){
5919ef1f84bSDavid du Colombier xp = a->hold;
5929ef1f84bSDavid du Colombier a->hold = nil;
5939ef1f84bSDavid du Colombier
5949ef1f84bSDavid du Colombier if(xp){
5959ef1f84bSDavid du Colombier if(arp->dropl == nil)
5969ef1f84bSDavid du Colombier arp->dropf = xp;
5979ef1f84bSDavid du Colombier else
5989ef1f84bSDavid du Colombier arp->dropl->list = xp;
5999ef1f84bSDavid du Colombier }
6009ef1f84bSDavid du Colombier
6019ef1f84bSDavid du Colombier cleanarpent(arp, a);
6029ef1f84bSDavid du Colombier }
6039ef1f84bSDavid du Colombier else
6049ef1f84bSDavid du Colombier break;
6059ef1f84bSDavid du Colombier }
6069ef1f84bSDavid du Colombier if(a == nil)
6079ef1f84bSDavid du Colombier goto dodrops;
6089ef1f84bSDavid du Colombier
6099ef1f84bSDavid du Colombier
6109ef1f84bSDavid du Colombier qunlock(arp); /* for icmpns */
6119ef1f84bSDavid du Colombier if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC)
6129ef1f84bSDavid du Colombier icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
6139ef1f84bSDavid du Colombier
6149ef1f84bSDavid du Colombier runlock(ifc);
6159ef1f84bSDavid du Colombier qlock(arp);
6169ef1f84bSDavid du Colombier
6179ef1f84bSDavid du Colombier /* put to the end of re-transmit chain */
6189ef1f84bSDavid du Colombier l = &arp->rxmt;
6199ef1f84bSDavid du Colombier for(b = *l; b; b = b->nextrxt){
6209ef1f84bSDavid du Colombier if(b == a){
6219ef1f84bSDavid du Colombier *l = a->nextrxt;
6229ef1f84bSDavid du Colombier break;
6239ef1f84bSDavid du Colombier }
6249ef1f84bSDavid du Colombier l = &b->nextrxt;
6259ef1f84bSDavid du Colombier }
6269ef1f84bSDavid du Colombier for(b = *l; b; b = b->nextrxt){
6279ef1f84bSDavid du Colombier l = &b->nextrxt;
6289ef1f84bSDavid du Colombier }
6299ef1f84bSDavid du Colombier *l = a;
6309ef1f84bSDavid du Colombier a->rxtsrem--;
6319ef1f84bSDavid du Colombier a->nextrxt = nil;
6329ef1f84bSDavid du Colombier a->rtime = NOW + ReTransTimer;
6339ef1f84bSDavid du Colombier
6349ef1f84bSDavid du Colombier a = arp->rxmt;
6359ef1f84bSDavid du Colombier if(a==nil)
6369ef1f84bSDavid du Colombier nrxt = 0;
6379ef1f84bSDavid du Colombier else
6389ef1f84bSDavid du Colombier nrxt = a->rtime - NOW;
6399ef1f84bSDavid du Colombier
6409ef1f84bSDavid du Colombier dodrops:
6419ef1f84bSDavid du Colombier xp = arp->dropf;
6429ef1f84bSDavid du Colombier arp->dropf = nil;
6439ef1f84bSDavid du Colombier arp->dropl = nil;
6449ef1f84bSDavid du Colombier qunlock(arp);
6459ef1f84bSDavid du Colombier
6469ef1f84bSDavid du Colombier for(; xp; xp = next){
6479ef1f84bSDavid du Colombier next = xp->list;
6489ef1f84bSDavid du Colombier icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
6499ef1f84bSDavid du Colombier }
6509ef1f84bSDavid du Colombier
6519ef1f84bSDavid du Colombier return nrxt;
6529ef1f84bSDavid du Colombier
6539ef1f84bSDavid du Colombier }
6549ef1f84bSDavid du Colombier
6559ef1f84bSDavid du Colombier static int
rxready(void * v)6569ef1f84bSDavid du Colombier rxready(void *v)
6579ef1f84bSDavid du Colombier {
6589ef1f84bSDavid du Colombier Arp *arp = (Arp *) v;
6599ef1f84bSDavid du Colombier int x;
6609ef1f84bSDavid du Colombier
6619ef1f84bSDavid du Colombier x = ((arp->rxmt != nil) || (arp->dropf != nil));
6629ef1f84bSDavid du Colombier
6639ef1f84bSDavid du Colombier return x;
6649ef1f84bSDavid du Colombier }
6659ef1f84bSDavid du Colombier
6669ef1f84bSDavid du Colombier static void
rxmitproc(void * v)6679ef1f84bSDavid du Colombier rxmitproc(void *v)
6689ef1f84bSDavid du Colombier {
6699ef1f84bSDavid du Colombier Arp *arp = v;
6709ef1f84bSDavid du Colombier long wakeupat;
6719ef1f84bSDavid du Colombier
6729ef1f84bSDavid du Colombier arp->rxmitp = up;
6739ef1f84bSDavid du Colombier //print("arp rxmitproc started\n");
6749ef1f84bSDavid du Colombier if(waserror()){
6759ef1f84bSDavid du Colombier arp->rxmitp = 0;
6769ef1f84bSDavid du Colombier pexit("hangup", 1);
6779ef1f84bSDavid du Colombier }
6789ef1f84bSDavid du Colombier for(;;){
6799ef1f84bSDavid du Colombier wakeupat = rxmitsols(arp);
6809ef1f84bSDavid du Colombier if(wakeupat == 0)
6819ef1f84bSDavid du Colombier sleep(&arp->rxmtq, rxready, v);
6829ef1f84bSDavid du Colombier else if(wakeupat > ReTransTimer/4)
6839ef1f84bSDavid du Colombier tsleep(&arp->rxmtq, return0, 0, wakeupat);
6849ef1f84bSDavid du Colombier }
6859ef1f84bSDavid du Colombier }
6869ef1f84bSDavid du Colombier
687