The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ip/arp.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 3da79301596d5ecaae99208a963ce44e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.