arp.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       arp.c (11314B)
       ---
            1 #include "u.h"
            2 #include "lib.h"
            3 #include "mem.h"
            4 #include "dat.h"
            5 #include "fns.h"
            6 #include "error.h"
            7 
            8 #include "ip.h"
            9 #include "ipv6.h"
           10 
           11 /*
           12  *  address resolution tables
           13  */
           14 enum
           15 {
           16         NHASH                = (1<<6),
           17         NCACHE                = 256,
           18 
           19         AOK                = 1,
           20         AWAIT                = 2,
           21 };
           22 
           23 char *arpstate[] =
           24 {
           25         "UNUSED",
           26         "OK",
           27         "WAIT",
           28 };
           29 
           30 /*
           31  *  one per Fs
           32  */
           33 struct Arp
           34 {
           35         QLock        qlock;
           36         Fs        *f;
           37         Arpent        *hash[NHASH];
           38         Arpent        cache[NCACHE];
           39         Arpent        *rxmt;
           40         Proc        *rxmitp;        /* neib sol re-transmit proc */
           41         Rendez        rxmtq;
           42         Block         *dropf, *dropl;
           43 };
           44 
           45 char *Ebadarp = "bad arp";
           46 
           47 #define haship(s) ((ulong)((s)[IPaddrlen-1])%NHASH)
           48 
           49 int         ReTransTimer = RETRANS_TIMER;
           50 
           51 static void         rxmitproc(void *v);
           52 
           53 void
           54 arpinit(Fs *f)
           55 {
           56         f->arp = smalloc(sizeof(Arp));
           57         f->arp->f = f;
           58         f->arp->rxmt = nil;
           59         f->arp->dropf = f->arp->dropl = nil;
           60         kproc("rxmitproc", rxmitproc, f->arp);
           61 }
           62 
           63 /*
           64  *  create a new arp entry for an ip address.
           65  */
           66 static Arpent*
           67 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt)
           68 {
           69         uint t;
           70         Block *next, *xp;
           71         Arpent *a, *e, *f, **l;
           72         Medium *m = ifc->m;
           73         int empty;
           74 
           75         /* find oldest entry */
           76         e = &arp->cache[NCACHE];
           77         a = arp->cache;
           78         t = a->utime;
           79         for(f = a; f < e; f++){
           80                 if(f->utime < t){
           81                         t = f->utime;
           82                         a = f;
           83                 }
           84         }
           85 
           86         /* dump waiting packets */
           87         xp = a->hold;
           88         a->hold = nil;
           89 
           90         if(isv4(a->ip)){
           91                 while(xp){
           92                         next = xp->list;
           93                         freeblist(xp);
           94                         xp = next;
           95                 }
           96         }
           97         else { /* queue icmp unreachable for rxmitproc later on, w/o arp lock */
           98                 if(xp){
           99                         if(arp->dropl == nil) 
          100                                 arp->dropf = xp;
          101                         else
          102                                 arp->dropl->list = xp;
          103 
          104                         for(next = xp->list; next; next = next->list)
          105                                 xp = next;
          106                         arp->dropl = xp;
          107                         wakeup(&arp->rxmtq);
          108                 }
          109         }
          110 
          111         /* take out of current chain */
          112         l = &arp->hash[haship(a->ip)];
          113         for(f = *l; f; f = f->hash){
          114                 if(f == a){
          115                         *l = a->hash;
          116                         break;
          117                 }
          118                 l = &f->hash;
          119         }
          120 
          121         /* insert into new chain */
          122         l = &arp->hash[haship(ip)];
          123         a->hash = *l;
          124         *l = a;
          125 
          126         memmove(a->ip, ip, sizeof(a->ip));
          127         a->utime = NOW;
          128         a->ctime = 0;
          129         a->type = m;
          130 
          131         a->rtime = NOW + ReTransTimer;
          132         a->rxtsrem = MAX_MULTICAST_SOLICIT;
          133         a->ifc = ifc;
          134         a->ifcid = ifc->ifcid;
          135 
          136         /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */
          137         if(!ipismulticast(a->ip) && addrxt){
          138                 l = &arp->rxmt;
          139                 empty = (*l==nil);
          140 
          141                 for(f = *l; f; f = f->nextrxt){
          142                         if(f == a){
          143                                 *l = a->nextrxt;
          144                                 break;
          145                         }
          146                         l = &f->nextrxt;
          147                 }
          148                 for(f = *l; f; f = f->nextrxt){
          149                         l = &f->nextrxt;
          150                 }
          151                 *l = a;
          152                 if(empty) 
          153                         wakeup(&arp->rxmtq);
          154         }
          155 
          156         a->nextrxt = nil;
          157 
          158         return a;
          159 }
          160 
          161 /* called with arp qlocked */
          162 
          163 void
          164 cleanarpent(Arp *arp, Arpent *a)
          165 {
          166         Arpent *f, **l;
          167 
          168         a->utime = 0;
          169         a->ctime = 0;
          170         a->type = 0;
          171         a->state = 0;
          172         
          173         /* take out of current chain */
          174         l = &arp->hash[haship(a->ip)];
          175         for(f = *l; f; f = f->hash){
          176                 if(f == a){
          177                         *l = a->hash;
          178                         break;
          179                 }
          180                 l = &f->hash;
          181         }
          182 
          183         /* take out of re-transmit chain */
          184         l = &arp->rxmt;
          185         for(f = *l; f; f = f->nextrxt){
          186                 if(f == a){
          187                         *l = a->nextrxt;
          188                         break;
          189                 }
          190                 l = &f->nextrxt;
          191         }
          192         a->nextrxt = nil;
          193         a->hash = nil;
          194         a->hold = nil;
          195         a->last = nil;
          196         a->ifc = nil;
          197 }
          198 
          199 /*
          200  *  fill in the media address if we have it.  Otherwise return an
          201  *  Arpent that represents the state of the address resolution FSM
          202  *  for ip.  Add the packet to be sent onto the list of packets
          203  *  waiting for ip->mac to be resolved.
          204  */
          205 Arpent*
          206 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac)
          207 {
          208         int hash;
          209         Arpent *a;
          210         Medium *type = ifc->m;
          211         uchar v6ip[IPaddrlen];
          212 
          213         if(version == V4){
          214                 v4tov6(v6ip, ip);
          215                 ip = v6ip;
          216         }
          217 
          218         QLOCK(arp);
          219         hash = haship(ip);
          220         for(a = arp->hash[hash]; a; a = a->hash){
          221                 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0)
          222                 if(type == a->type)
          223                         break;
          224         }
          225 
          226         if(a == nil){
          227                 a = newarp6(arp, ip, ifc, (version != V4));
          228                 a->state = AWAIT;
          229         }
          230         a->utime = NOW;
          231         if(a->state == AWAIT){
          232                 if(bp != nil){
          233                         if(a->hold)
          234                                 a->last->list = bp;
          235                         else
          236                                 a->hold = bp;
          237                         a->last = bp;
          238                         bp->list = nil; 
          239                 }
          240                 return a;                /* return with arp qlocked */
          241         }
          242 
          243         memmove(mac, a->mac, a->type->maclen);
          244 
          245         /* remove old entries */
          246         if(NOW - a->ctime > 15*60*1000)
          247                 cleanarpent(arp, a);
          248 
          249         QUNLOCK(arp);
          250         return nil;
          251 }
          252 
          253 /*
          254  * called with arp locked
          255  */
          256 void
          257 arprelease(Arp *arp, Arpent* ae)
          258 {
          259         QUNLOCK(arp);
          260 }
          261 
          262 /*
          263  * Copy out the mac address from the Arpent.  Return the
          264  * block waiting to get sent to this mac address.
          265  *
          266  * called with arp locked
          267  */
          268 Block*
          269 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac)
          270 {
          271         Block *bp;
          272         Arpent *f, **l;
          273 
          274         if(!isv4(a->ip)){
          275                 l = &arp->rxmt;
          276                 for(f = *l; f; f = f->nextrxt){
          277                         if(f == a){
          278                                 *l = a->nextrxt;
          279                                 break;
          280                         }
          281                         l = &f->nextrxt;
          282                 }
          283         }
          284 
          285         memmove(a->mac, mac, type->maclen);
          286         a->type = type;
          287         a->state = AOK;
          288         a->utime = NOW;
          289         bp = a->hold;
          290         a->hold = nil;
          291         QUNLOCK(arp);
          292 
          293         return bp;
          294 }
          295 
          296 void
          297 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh)
          298 {
          299         Arp *arp;
          300         Route *r;
          301         Arpent *a, *f, **l;
          302         Ipifc *ifc;
          303         Medium *type;
          304         Block *bp, *next;
          305         uchar v6ip[IPaddrlen];
          306 
          307         arp = fs->arp;
          308 
          309         if(n != 6){
          310 //                print("arp: len = %d\n", n);
          311                 return;
          312         }
          313 
          314         switch(version){
          315         case V4:
          316                 r = v4lookup(fs, ip, nil);
          317                 v4tov6(v6ip, ip);
          318                 ip = v6ip;
          319                 break;
          320         case V6:
          321                 r = v6lookup(fs, ip, nil);
          322                 break;
          323         default:
          324                 panic("arpenter: version %d", version);
          325                 return;        /* to supress warnings */
          326         }
          327 
          328         if(r == nil){
          329 //                print("arp: no route for entry\n");
          330                 return;
          331         }
          332 
          333         ifc = r->ifc;
          334         type = ifc->m;
          335 
          336         QLOCK(arp);
          337         for(a = arp->hash[haship(ip)]; a; a = a->hash){
          338                 if(a->type != type || (a->state != AWAIT && a->state != AOK))
          339                         continue;
          340 
          341                 if(ipcmp(a->ip, ip) == 0){
          342                         a->state = AOK;
          343                         memmove(a->mac, mac, type->maclen);
          344 
          345                         if(version == V6){
          346                                 /* take out of re-transmit chain */
          347                                 l = &arp->rxmt;
          348                                 for(f = *l; f; f = f->nextrxt){
          349                                         if(f == a){
          350                                                 *l = a->nextrxt;
          351                                                 break;
          352                                         }
          353                                         l = &f->nextrxt;
          354                                 }
          355                         }
          356 
          357                         a->ifc = ifc;
          358                         a->ifcid = ifc->ifcid;
          359                         bp = a->hold;
          360                         a->hold = nil;
          361                         if(version == V4)
          362                                 ip += IPv4off;
          363                         a->utime = NOW;
          364                         a->ctime = a->utime;
          365                         QUNLOCK(arp);
          366 
          367                         while(bp){
          368                                 next = bp->list;
          369                                 if(ifc != nil){
          370                                         if(waserror()){
          371                                                 RUNLOCK(ifc);
          372                                                 nexterror();
          373                                         }
          374                                         RLOCK(ifc);
          375                                         if(ifc->m != nil)
          376                                                 ifc->m->bwrite(ifc, bp, version, ip);
          377                                         else
          378                                                 freeb(bp);
          379                                         RUNLOCK(ifc);
          380                                         poperror();
          381                                 } else
          382                                         freeb(bp);
          383                                 bp = next;
          384                         }
          385                         return;
          386                 }
          387         }
          388 
          389         if(refresh == 0){
          390                 a = newarp6(arp, ip, ifc, 0);
          391                 a->state = AOK;
          392                 a->type = type;
          393                 a->ctime = NOW;
          394                 memmove(a->mac, mac, type->maclen);
          395         }
          396 
          397         QUNLOCK(arp);
          398 }
          399 
          400 int
          401 arpwrite(Fs *fs, char *s, int len)
          402 {
          403         int n;
          404         Route *r;
          405         Arp *arp;
          406         Block *bp;
          407         Arpent *a, *fl, **l;
          408         Medium *m;
          409         char *f[4], buf[256];
          410         uchar ip[IPaddrlen], mac[MAClen];
          411 
          412         arp = fs->arp;
          413 
          414         if(len == 0)
          415                 error(Ebadarp);
          416         if(len >= sizeof(buf))
          417                 len = sizeof(buf)-1;
          418         strncpy(buf, s, len);
          419         buf[len] = 0;
          420         if(len > 0 && buf[len-1] == '\n')
          421                 buf[len-1] = 0;
          422 
          423         n = getfields(buf, f, 4, 1, " ");
          424         if(strcmp(f[0], "flush") == 0){
          425                 QLOCK(arp);
          426                 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){
          427                         memset(a->ip, 0, sizeof(a->ip));
          428                         memset(a->mac, 0, sizeof(a->mac));
          429                         a->hash = nil;
          430                         a->state = 0;
          431                         a->utime = 0;
          432                         while(a->hold != nil){
          433                                 bp = a->hold->list;
          434                                 freeblist(a->hold);
          435                                 a->hold = bp;
          436                         }
          437                 }
          438                 memset(arp->hash, 0, sizeof(arp->hash));
          439                 /* clear all pkts on these lists (rxmt, dropf/l) */
          440                 arp->rxmt = nil;
          441                 arp->dropf = nil;
          442                 arp->dropl = nil;
          443                 QUNLOCK(arp);
          444         } else if(strcmp(f[0], "add") == 0){
          445                 switch(n){
          446                 default:
          447                         error(Ebadarg);
          448                 case 3:
          449                         if (parseip(ip, f[1]) == -1)
          450                                 error(Ebadip);
          451                         if(isv4(ip))
          452                                 r = v4lookup(fs, ip+IPv4off, nil);
          453                         else
          454                                 r = v6lookup(fs, ip, nil);
          455                         if(r == nil)
          456                                 error("Destination unreachable");
          457                         m = r->ifc->m;
          458                         n = parsemac(mac, f[2], m->maclen);
          459                         break;
          460                 case 4:
          461                         m = ipfindmedium(f[1]);
          462                         if(m == nil)
          463                                 error(Ebadarp);
          464                         if (parseip(ip, f[2]) == -1)
          465                                 error(Ebadip);
          466                         n = parsemac(mac, f[3], m->maclen);
          467                         break;
          468                 }
          469 
          470                 if(m->ares == nil)
          471                         error(Ebadarp);
          472 
          473                 m->ares(fs, V6, ip, mac, n, 0);
          474         } else if(strcmp(f[0], "del") == 0){
          475                 if(n != 2)
          476                         error(Ebadarg);
          477 
          478                 if (parseip(ip, f[1]) == -1)
          479                         error(Ebadip);
          480                 QLOCK(arp);
          481 
          482                 l = &arp->hash[haship(ip)];
          483                 for(a = *l; a; a = a->hash){
          484                         if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){
          485                                 *l = a->hash;
          486                                 break;
          487                         }
          488                         l = &a->hash;
          489                 }
          490         
          491                 if(a){
          492                         /* take out of re-transmit chain */
          493                         l = &arp->rxmt;
          494                         for(fl = *l; fl; fl = fl->nextrxt){
          495                                 if(fl == a){
          496                                         *l = a->nextrxt;
          497                                         break;
          498                                 }
          499                                 l = &fl->nextrxt;
          500                         }
          501 
          502                         a->nextrxt = nil;
          503                         a->hash = nil;
          504                         a->hold = nil;
          505                         a->last = nil;
          506                         a->ifc = nil;
          507                         memset(a->ip, 0, sizeof(a->ip));
          508                         memset(a->mac, 0, sizeof(a->mac));
          509                 }
          510                 QUNLOCK(arp);
          511         } else
          512                 error(Ebadarp);
          513 
          514         return len;
          515 }
          516 
          517 enum
          518 {
          519         Alinelen=        90,
          520 };
          521 
          522 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n";
          523 
          524 static void
          525 convmac(char *p, uchar *mac, int n)
          526 {
          527         while(n-- > 0)
          528                 p += sprint(p, "%2.2ux", *mac++);
          529 }
          530 
          531 int
          532 arpread(Arp *arp, char *p, ulong offset, int len)
          533 {
          534         Arpent *a;
          535         int n;
          536         char mac[2*MAClen+1];
          537 
          538         if(offset % Alinelen)
          539                 return 0;
          540 
          541         offset = offset/Alinelen;
          542         len = len/Alinelen;
          543 
          544         n = 0;
          545         for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){
          546                 if(a->state == 0)
          547                         continue;
          548                 if(offset > 0){
          549                         offset--;
          550                         continue;
          551                 }
          552                 len--;
          553                 QLOCK(arp);
          554                 convmac(mac, a->mac, a->type->maclen);
          555                 n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac);
          556                 QUNLOCK(arp);
          557         }
          558 
          559         return n;
          560 }
          561 
          562 extern int
          563 rxmitsols(Arp *arp)
          564 {
          565         uint sflag;
          566         Block *next, *xp;
          567         Arpent *a, *b, **l;
          568         Fs *f;
          569         uchar ipsrc[IPaddrlen];
          570         Ipifc *ifc = nil;
          571         long nrxt;
          572 
          573         QLOCK(arp);
          574         f = arp->f;
          575 
          576         a = arp->rxmt;
          577         if(a==nil){
          578                 nrxt = 0;
          579                 goto dodrops;                 /* return nrxt; */
          580         }
          581         nrxt = a->rtime - NOW;
          582         if(nrxt > 3*ReTransTimer/4) 
          583                 goto dodrops;                 /* return nrxt; */
          584 
          585         for(; a; a = a->nextrxt){
          586                 ifc = a->ifc;
          587                 assert(ifc != nil);
          588                 if((a->rxtsrem <= 0) || !(CANRLOCK(ifc)) || (a->ifcid != ifc->ifcid)){
          589                         xp = a->hold;
          590                         a->hold = nil;
          591 
          592                         if(xp){
          593                                 if(arp->dropl == nil) 
          594                                         arp->dropf = xp;
          595                                 else
          596                                         arp->dropl->list = xp;
          597                         }
          598 
          599                         cleanarpent(arp, a);
          600                 }
          601                 else
          602                         break;
          603         }
          604         if(a == nil)
          605                 goto dodrops;
          606 
          607 
          608         QUNLOCK(arp);        /* for icmpns */
          609         if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) 
          610                 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 
          611 
          612         RUNLOCK(ifc);
          613         QLOCK(arp);
          614 
          615         /* put to the end of re-transmit chain */
          616         l = &arp->rxmt;
          617         for(b = *l; b; b = b->nextrxt){
          618                 if(b == a){
          619                         *l = a->nextrxt;
          620                         break;
          621                 }
          622                 l = &b->nextrxt;
          623         }
          624         for(b = *l; b; b = b->nextrxt){
          625                 l = &b->nextrxt;
          626         }
          627         *l = a;
          628         a->rxtsrem--;
          629         a->nextrxt = nil;
          630         a->rtime = NOW + ReTransTimer;
          631 
          632         a = arp->rxmt;
          633         if(a==nil)
          634                 nrxt = 0;
          635         else 
          636                 nrxt = a->rtime - NOW;
          637 
          638 dodrops:
          639         xp = arp->dropf;
          640         arp->dropf = nil;
          641         arp->dropl = nil;
          642         QUNLOCK(arp);
          643 
          644         for(; xp; xp = next){
          645                 next = xp->list;
          646                 icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1);
          647         }
          648 
          649         return nrxt;
          650 
          651 }
          652 
          653 static int
          654 rxready(void *v)
          655 {
          656         Arp *arp = (Arp *) v;
          657         int x;
          658 
          659         x = ((arp->rxmt != nil) || (arp->dropf != nil));
          660 
          661         return x;
          662 }
          663 
          664 static void
          665 rxmitproc(void *v)
          666 {
          667         Arp *arp = v;
          668         long wakeupat;
          669 
          670         arp->rxmitp = up;
          671         //print("arp rxmitproc started\n");
          672         if(waserror()){
          673                 arp->rxmitp = 0;
          674                 pexit("hangup", 1);
          675         }
          676         for(;;){
          677                 wakeupat = rxmitsols(arp);
          678                 if(wakeupat == 0) 
          679                         sleep(&arp->rxmtq, rxready, v); 
          680                 else if(wakeupat > ReTransTimer/4) 
          681                         tsleep(&arp->rxmtq, return0, 0, wakeupat); 
          682         }
          683 }
          684