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/ethermedium.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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 "../port/netif.h"
    9 #include "ip.h"
   10 #include "ipv6.h"
   11 
   12 typedef struct Etherhdr Etherhdr;
   13 struct Etherhdr
   14 {
   15         uchar   d[6];
   16         uchar   s[6];
   17         uchar   t[2];
   18 };
   19 
   20 static uchar ipbroadcast[IPaddrlen] = {
   21         0xff,0xff,0xff,0xff,
   22         0xff,0xff,0xff,0xff,
   23         0xff,0xff,0xff,0xff,
   24         0xff,0xff,0xff,0xff,
   25 };
   26 
   27 static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
   28 
   29 static void     etherread4(void *a);
   30 static void     etherread6(void *a);
   31 static void     etherbind(Ipifc *ifc, int argc, char **argv);
   32 static void     etherunbind(Ipifc *ifc);
   33 static void     etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip);
   34 static void     etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia);
   35 static void     etherremmulti(Ipifc *ifc, uchar *a, uchar *ia);
   36 static Block*   multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac);
   37 static void     sendarp(Ipifc *ifc, Arpent *a);
   38 static void     sendgarp(Ipifc *ifc, uchar*);
   39 static int      multicastea(uchar *ea, uchar *ip);
   40 static void     recvarpproc(void*);
   41 static void     resolveaddr6(Ipifc *ifc, Arpent *a);
   42 static void     etherpref2addr(uchar *pref, uchar *ea);
   43 
   44 Medium ethermedium =
   45 {
   46 .name=          "ether",
   47 .hsize=         14,
   48 .mintu=         60,
   49 .maxtu=         1514,
   50 .maclen=        6,
   51 .bind=          etherbind,
   52 .unbind=        etherunbind,
   53 .bwrite=        etherbwrite,
   54 .addmulti=      etheraddmulti,
   55 .remmulti=      etherremmulti,
   56 .ares=          arpenter,
   57 .areg=          sendgarp,
   58 .pref2addr=     etherpref2addr,
   59 };
   60 
   61 Medium gbemedium =
   62 {
   63 .name=          "gbe",
   64 .hsize=         14,
   65 .mintu=         60,
   66 .maxtu=         9014,
   67 .maclen=        6,
   68 .bind=          etherbind,
   69 .unbind=        etherunbind,
   70 .bwrite=        etherbwrite,
   71 .addmulti=      etheraddmulti,
   72 .remmulti=      etherremmulti,
   73 .ares=          arpenter,
   74 .areg=          sendgarp,
   75 .pref2addr=     etherpref2addr,
   76 };
   77 
   78 typedef struct  Etherrock Etherrock;
   79 struct Etherrock
   80 {
   81         Fs      *f;             /* file system we belong to */
   82         Proc    *arpp;          /* arp process */
   83         Proc    *read4p;        /* reading process (v4)*/
   84         Proc    *read6p;        /* reading process (v6)*/
   85         Chan    *mchan4;        /* Data channel for v4 */
   86         Chan    *achan;         /* Arp channel */
   87         Chan    *cchan4;        /* Control channel for v4 */
   88         Chan    *mchan6;        /* Data channel for v6 */
   89         Chan    *cchan6;        /* Control channel for v6 */
   90 };
   91 
   92 /*
   93  *  ethernet arp request
   94  */
   95 enum
   96 {
   97         ARPREQUEST      = 1,
   98         ARPREPLY        = 2,
   99 };
  100 
  101 typedef struct Etherarp Etherarp;
  102 struct Etherarp
  103 {
  104         uchar   d[6];
  105         uchar   s[6];
  106         uchar   type[2];
  107         uchar   hrd[2];
  108         uchar   pro[2];
  109         uchar   hln;
  110         uchar   pln;
  111         uchar   op[2];
  112         uchar   sha[6];
  113         uchar   spa[4];
  114         uchar   tha[6];
  115         uchar   tpa[4];
  116 };
  117 
  118 static char *nbmsg = "nonblocking";
  119 
  120 /*
  121  *  called to bind an IP ifc to an ethernet device
  122  *  called with ifc wlock'd
  123  */
  124 static void
  125 etherbind(Ipifc *ifc, int argc, char **argv)
  126 {
  127         Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan;
  128         char addr[Maxpath];     //char addr[2*KNAMELEN];
  129         char dir[Maxpath];      //char dir[2*KNAMELEN];
  130         char *buf;
  131         int n;
  132         char *ptr;
  133         Etherrock *er;
  134 
  135         if(argc < 2)
  136                 error(Ebadarg);
  137 
  138         mchan4 = cchan4 = achan = mchan6 = cchan6 = nil;
  139         buf = nil;
  140         if(waserror()){
  141                 if(mchan4 != nil)
  142                         cclose(mchan4);
  143                 if(cchan4 != nil)
  144                         cclose(cchan4);
  145                 if(achan != nil)
  146                         cclose(achan);
  147                 if(mchan6 != nil)
  148                         cclose(mchan6);
  149                 if(cchan6 != nil)
  150                         cclose(cchan6);
  151                 if(buf != nil)
  152                         free(buf);
  153                 nexterror();
  154         }
  155 
  156         /*
  157          *  open ipv4 conversation
  158          *
  159          *  the dial will fail if the type is already open on
  160          *  this device.
  161          */
  162         snprint(addr, sizeof(addr), "%s!0x800", argv[2]);       /* ETIP4 */
  163         mchan4 = chandial(addr, nil, dir, &cchan4);
  164 
  165         /*
  166          *  make it non-blocking
  167          */
  168         devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0);
  169 
  170         /*
  171          *  get mac address and speed
  172          */
  173         snprint(addr, sizeof(addr), "%s/stats", argv[2]);
  174         buf = smalloc(512);
  175         schan = namec(addr, Aopen, OREAD, 0);
  176         if(waserror()){
  177                 cclose(schan);
  178                 nexterror();
  179         }
  180         n = devtab[schan->type]->read(schan, buf, 511, 0);
  181         cclose(schan);
  182         poperror();
  183         buf[n] = 0;
  184 
  185         ptr = strstr(buf, "addr: ");
  186         if(!ptr)
  187                 error(Eio);
  188         ptr += 6;
  189         parsemac(ifc->mac, ptr, 6);
  190 
  191         ptr = strstr(buf, "mbps: ");
  192         if(ptr){
  193                 ptr += 6;
  194                 ifc->mbps = atoi(ptr);
  195         } else
  196                 ifc->mbps = 100;
  197 
  198         /*
  199          *  open arp conversation
  200          */
  201         snprint(addr, sizeof(addr), "%s!0x806", argv[2]);       /* ETARP */
  202         achan = chandial(addr, nil, nil, nil);
  203 
  204         /*
  205          *  open ipv6 conversation
  206          *
  207          *  the dial will fail if the type is already open on
  208          *  this device.
  209          */
  210         snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]);      /* ETIP6 */
  211         mchan6 = chandial(addr, nil, dir, &cchan6);
  212 
  213         /*
  214          *  make it non-blocking
  215          */
  216         devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0);
  217 
  218         er = smalloc(sizeof(*er));
  219         er->mchan4 = mchan4;
  220         er->cchan4 = cchan4;
  221         er->achan = achan;
  222         er->mchan6 = mchan6;
  223         er->cchan6 = cchan6;
  224         er->f = ifc->conv->p->f;
  225         ifc->arg = er;
  226 
  227         free(buf);
  228         poperror();
  229 
  230         kproc("etherread4", etherread4, ifc);
  231         kproc("recvarpproc", recvarpproc, ifc);
  232         kproc("etherread6", etherread6, ifc);
  233 }
  234 
  235 /*
  236  *  called with ifc wlock'd
  237  */
  238 static void
  239 etherunbind(Ipifc *ifc)
  240 {
  241         Etherrock *er = ifc->arg;
  242 
  243         if(er->read4p)
  244                 postnote(er->read4p, 1, "unbind", 0);
  245         if(er->read6p)
  246                 postnote(er->read6p, 1, "unbind", 0);
  247         if(er->arpp)
  248                 postnote(er->arpp, 1, "unbind", 0);
  249 
  250         /* wait for readers to die */
  251         while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0)
  252                 tsleep(&up->sleep, return0, 0, 300);
  253 
  254         if(er->mchan4 != nil)
  255                 cclose(er->mchan4);
  256         if(er->achan != nil)
  257                 cclose(er->achan);
  258         if(er->cchan4 != nil)
  259                 cclose(er->cchan4);
  260         if(er->mchan6 != nil)
  261                 cclose(er->mchan6);
  262         if(er->cchan6 != nil)
  263                 cclose(er->cchan6);
  264 
  265         free(er);
  266 }
  267 
  268 /*
  269  *  called by ipoput with a single block to write with ifc rlock'd
  270  */
  271 static void
  272 etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip)
  273 {
  274         Etherhdr *eh;
  275         Arpent *a;
  276         uchar mac[6];
  277         Etherrock *er = ifc->arg;
  278 
  279         /* get mac address of destination */
  280         a = arpget(er->f->arp, bp, version, ifc, ip, mac);
  281         if(a){
  282                 /* check for broadcast or multicast */
  283                 bp = multicastarp(er->f, a, ifc->m, mac);
  284                 if(bp==nil){
  285                         switch(version){
  286                         case V4:
  287                                 sendarp(ifc, a);
  288                                 break;
  289                         case V6:
  290                                 resolveaddr6(ifc, a);
  291                                 break;
  292                         default:
  293                                 panic("etherbwrite: version %d", version);
  294                         }
  295                         return;
  296                 }
  297         }
  298 
  299         /* make it a single block with space for the ether header */
  300         bp = padblock(bp, ifc->m->hsize);
  301         if(bp->next)
  302                 bp = concatblock(bp);
  303         if(BLEN(bp) < ifc->mintu)
  304                 bp = adjustblock(bp, ifc->mintu);
  305         eh = (Etherhdr*)bp->rp;
  306 
  307         /* copy in mac addresses and ether type */
  308         memmove(eh->s, ifc->mac, sizeof(eh->s));
  309         memmove(eh->d, mac, sizeof(eh->d));
  310 
  311         switch(version){
  312         case V4:
  313                 eh->t[0] = 0x08;
  314                 eh->t[1] = 0x00;
  315                 devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0);
  316                 break;
  317         case V6:
  318                 eh->t[0] = 0x86;
  319                 eh->t[1] = 0xDD;
  320                 devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0);
  321                 break;
  322         default:
  323                 panic("etherbwrite2: version %d", version);
  324         }
  325         ifc->out++;
  326 }
  327 
  328 
  329 /*
  330  *  process to read from the ethernet
  331  */
  332 static void
  333 etherread4(void *a)
  334 {
  335         Ipifc *ifc;
  336         Block *bp;
  337         Etherrock *er;
  338 
  339         ifc = a;
  340         er = ifc->arg;
  341         er->read4p = up;        /* hide identity under a rock for unbind */
  342         if(waserror()){
  343                 er->read4p = 0;
  344                 pexit("hangup", 1);
  345         }
  346         for(;;){
  347                 bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0);
  348                 if(!canrlock(ifc)){
  349                         freeb(bp);
  350                         continue;
  351                 }
  352                 if(waserror()){
  353                         runlock(ifc);
  354                         nexterror();
  355                 }
  356                 ifc->in++;
  357                 bp->rp += ifc->m->hsize;
  358                 if(ifc->lifc == nil)
  359                         freeb(bp);
  360                 else
  361                         ipiput4(er->f, ifc, bp);
  362                 runlock(ifc);
  363                 poperror();
  364         }
  365 }
  366 
  367 
  368 /*
  369  *  process to read from the ethernet, IPv6
  370  */
  371 static void
  372 etherread6(void *a)
  373 {
  374         Ipifc *ifc;
  375         Block *bp;
  376         Etherrock *er;
  377 
  378         ifc = a;
  379         er = ifc->arg;
  380         er->read6p = up;        /* hide identity under a rock for unbind */
  381         if(waserror()){
  382                 er->read6p = 0;
  383                 pexit("hangup", 1);
  384         }
  385         for(;;){
  386                 bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0);
  387                 if(!canrlock(ifc)){
  388                         freeb(bp);
  389                         continue;
  390                 }
  391                 if(waserror()){
  392                         runlock(ifc);
  393                         nexterror();
  394                 }
  395                 ifc->in++;
  396                 bp->rp += ifc->m->hsize;
  397                 if(ifc->lifc == nil)
  398                         freeb(bp);
  399                 else
  400                         ipiput6(er->f, ifc, bp);
  401                 runlock(ifc);
  402                 poperror();
  403         }
  404 }
  405 
  406 static void
  407 etheraddmulti(Ipifc *ifc, uchar *a, uchar *)
  408 {
  409         uchar mac[6];
  410         char buf[64];
  411         Etherrock *er = ifc->arg;
  412         int version;
  413 
  414         version = multicastea(mac, a);
  415         sprint(buf, "addmulti %E", mac);
  416         switch(version){
  417         case V4:
  418                 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
  419                 break;
  420         case V6:
  421                 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
  422                 break;
  423         default:
  424                 panic("etheraddmulti: version %d", version);
  425         }
  426 }
  427 
  428 static void
  429 etherremmulti(Ipifc *ifc, uchar *a, uchar *)
  430 {
  431         uchar mac[6];
  432         char buf[64];
  433         Etherrock *er = ifc->arg;
  434         int version;
  435 
  436         version = multicastea(mac, a);
  437         sprint(buf, "remmulti %E", mac);
  438         switch(version){
  439         case V4:
  440                 devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0);
  441                 break;
  442         case V6:
  443                 devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0);
  444                 break;
  445         default:
  446                 panic("etherremmulti: version %d", version);
  447         }
  448 }
  449 
  450 /*
  451  *  send an ethernet arp
  452  *  (only v4, v6 uses the neighbor discovery, rfc1970)
  453  */
  454 static void
  455 sendarp(Ipifc *ifc, Arpent *a)
  456 {
  457         int n;
  458         Block *bp;
  459         Etherarp *e;
  460         Etherrock *er = ifc->arg;
  461 
  462         /* don't do anything if it's been less than a second since the last */
  463         if(NOW - a->ctime < 1000){
  464                 arprelease(er->f->arp, a);
  465                 return;
  466         }
  467 
  468         /* remove all but the last message */
  469         while((bp = a->hold) != nil){
  470                 if(bp == a->last)
  471                         break;
  472                 a->hold = bp->list;
  473                 freeblist(bp);
  474         }
  475 
  476         /* try to keep it around for a second more */
  477         a->ctime = NOW;
  478         arprelease(er->f->arp, a);
  479 
  480         n = sizeof(Etherarp);
  481         if(n < a->type->mintu)
  482                 n = a->type->mintu;
  483         bp = allocb(n);
  484         memset(bp->rp, 0, n);
  485         e = (Etherarp*)bp->rp;
  486         memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa));
  487         ipv4local(ifc, e->spa);
  488         memmove(e->sha, ifc->mac, sizeof(e->sha));
  489         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
  490         memmove(e->s, ifc->mac, sizeof(e->s));
  491 
  492         hnputs(e->type, ETARP);
  493         hnputs(e->hrd, 1);
  494         hnputs(e->pro, ETIP4);
  495         e->hln = sizeof(e->sha);
  496         e->pln = sizeof(e->spa);
  497         hnputs(e->op, ARPREQUEST);
  498         bp->wp += n;
  499 
  500         devtab[er->achan->type]->bwrite(er->achan, bp, 0);
  501 }
  502 
  503 static void
  504 resolveaddr6(Ipifc *ifc, Arpent *a)
  505 {
  506         int sflag;
  507         Block *bp;
  508         Etherrock *er = ifc->arg;
  509         uchar ipsrc[IPaddrlen];
  510 
  511         /* don't do anything if it's been less than a second since the last */
  512         if(NOW - a->ctime < ReTransTimer){
  513                 arprelease(er->f->arp, a);
  514                 return;
  515         }
  516 
  517         /* remove all but the last message */
  518         while((bp = a->hold) != nil){
  519                 if(bp == a->last)
  520                         break;
  521                 a->hold = bp->list;
  522                 freeblist(bp);
  523         }
  524 
  525         /* try to keep it around for a second more */
  526         a->ctime = NOW;
  527         a->rtime = NOW + ReTransTimer;
  528         if(a->rxtsrem <= 0) {
  529                 arprelease(er->f->arp, a);
  530                 return;
  531         }
  532 
  533         a->rxtsrem--;
  534         arprelease(er->f->arp, a);
  535 
  536         if(sflag = ipv6anylocal(ifc, ipsrc))
  537                 icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac);
  538 }
  539 
  540 /*
  541  *  send a gratuitous arp to refresh arp caches
  542  */
  543 static void
  544 sendgarp(Ipifc *ifc, uchar *ip)
  545 {
  546         int n;
  547         Block *bp;
  548         Etherarp *e;
  549         Etherrock *er = ifc->arg;
  550 
  551         /* don't arp for our initial non address */
  552         if(ipcmp(ip, IPnoaddr) == 0)
  553                 return;
  554 
  555         n = sizeof(Etherarp);
  556         if(n < ifc->m->mintu)
  557                 n = ifc->m->mintu;
  558         bp = allocb(n);
  559         memset(bp->rp, 0, n);
  560         e = (Etherarp*)bp->rp;
  561         memmove(e->tpa, ip+IPv4off, sizeof(e->tpa));
  562         memmove(e->spa, ip+IPv4off, sizeof(e->spa));
  563         memmove(e->sha, ifc->mac, sizeof(e->sha));
  564         memset(e->d, 0xff, sizeof(e->d));               /* ethernet broadcast */
  565         memmove(e->s, ifc->mac, sizeof(e->s));
  566 
  567         hnputs(e->type, ETARP);
  568         hnputs(e->hrd, 1);
  569         hnputs(e->pro, ETIP4);
  570         e->hln = sizeof(e->sha);
  571         e->pln = sizeof(e->spa);
  572         hnputs(e->op, ARPREQUEST);
  573         bp->wp += n;
  574 
  575         devtab[er->achan->type]->bwrite(er->achan, bp, 0);
  576 }
  577 
  578 static void
  579 recvarp(Ipifc *ifc)
  580 {
  581         int n;
  582         Block *ebp, *rbp;
  583         Etherarp *e, *r;
  584         uchar ip[IPaddrlen];
  585         static uchar eprinted[4];
  586         Etherrock *er = ifc->arg;
  587 
  588         ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0);
  589         if(ebp == nil)
  590                 return;
  591 
  592         e = (Etherarp*)ebp->rp;
  593         switch(nhgets(e->op)) {
  594         default:
  595                 break;
  596 
  597         case ARPREPLY:
  598                 /* check for machine using my ip address */
  599                 v4tov6(ip, e->spa);
  600                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
  601                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
  602                                 print("arprep: 0x%E/0x%E also has ip addr %V\n",
  603                                         e->s, e->sha, e->spa);
  604                                 break;
  605                         }
  606                 }
  607 
  608                 /* make sure we're not entering broadcast addresses */
  609                 if(ipcmp(ip, ipbroadcast) == 0 ||
  610                         !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){
  611                         print("arprep: 0x%E/0x%E cannot register broadcast address %I\n",
  612                                 e->s, e->sha, e->spa);
  613                         break;
  614                 }
  615 
  616                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0);
  617                 break;
  618 
  619         case ARPREQUEST:
  620                 /* don't answer arps till we know who we are */
  621                 if(ifc->lifc == 0)
  622                         break;
  623 
  624                 /* check for machine using my ip or ether address */
  625                 v4tov6(ip, e->spa);
  626                 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){
  627                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){
  628                                 if (memcmp(eprinted, e->spa, sizeof(e->spa))){
  629                                         /* print only once */
  630                                         print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa);
  631                                         memmove(eprinted, e->spa, sizeof(e->spa));
  632                                 }
  633                         }
  634                 } else {
  635                         if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){
  636                                 print("arpreq: %V also has ether addr %E\n", e->spa, e->sha);
  637                                 break;
  638                         }
  639                 }
  640 
  641                 /* refresh what we know about sender */
  642                 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1);
  643 
  644                 /* answer only requests for our address or systems we're proxying for */
  645                 v4tov6(ip, e->tpa);
  646                 if(!iplocalonifc(ifc, ip))
  647                 if(!ipproxyifc(er->f, ifc, ip))
  648                         break;
  649 
  650                 n = sizeof(Etherarp);
  651                 if(n < ifc->mintu)
  652                         n = ifc->mintu;
  653                 rbp = allocb(n);
  654                 r = (Etherarp*)rbp->rp;
  655                 memset(r, 0, sizeof(Etherarp));
  656                 hnputs(r->type, ETARP);
  657                 hnputs(r->hrd, 1);
  658                 hnputs(r->pro, ETIP4);
  659                 r->hln = sizeof(r->sha);
  660                 r->pln = sizeof(r->spa);
  661                 hnputs(r->op, ARPREPLY);
  662                 memmove(r->tha, e->sha, sizeof(r->tha));
  663                 memmove(r->tpa, e->spa, sizeof(r->tpa));
  664                 memmove(r->sha, ifc->mac, sizeof(r->sha));
  665                 memmove(r->spa, e->tpa, sizeof(r->spa));
  666                 memmove(r->d, e->sha, sizeof(r->d));
  667                 memmove(r->s, ifc->mac, sizeof(r->s));
  668                 rbp->wp += n;
  669 
  670                 devtab[er->achan->type]->bwrite(er->achan, rbp, 0);
  671         }
  672         freeb(ebp);
  673 }
  674 
  675 static void
  676 recvarpproc(void *v)
  677 {
  678         Ipifc *ifc = v;
  679         Etherrock *er = ifc->arg;
  680 
  681         er->arpp = up;
  682         if(waserror()){
  683                 er->arpp = 0;
  684                 pexit("hangup", 1);
  685         }
  686         for(;;)
  687                 recvarp(ifc);
  688 }
  689 
  690 static int
  691 multicastea(uchar *ea, uchar *ip)
  692 {
  693         int x;
  694 
  695         switch(x = ipismulticast(ip)){
  696         case V4:
  697                 ea[0] = 0x01;
  698                 ea[1] = 0x00;
  699                 ea[2] = 0x5e;
  700                 ea[3] = ip[13] & 0x7f;
  701                 ea[4] = ip[14];
  702                 ea[5] = ip[15];
  703                 break;
  704         case V6:
  705                 ea[0] = 0x33;
  706                 ea[1] = 0x33;
  707                 ea[2] = ip[12];
  708                 ea[3] = ip[13];
  709                 ea[4] = ip[14];
  710                 ea[5] = ip[15];
  711                 break;
  712         }
  713         return x;
  714 }
  715 
  716 /*
  717  *  fill in an arp entry for broadcast or multicast
  718  *  addresses.  Return the first queued packet for the
  719  *  IP address.
  720  */
  721 static Block*
  722 multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac)
  723 {
  724         /* is it broadcast? */
  725         switch(ipforme(f, a->ip)){
  726         case Runi:
  727                 return nil;
  728         case Rbcast:
  729                 memset(mac, 0xff, 6);
  730                 return arpresolve(f->arp, a, medium, mac);
  731         default:
  732                 break;
  733         }
  734 
  735         /* if multicast, fill in mac */
  736         switch(multicastea(mac, a->ip)){
  737         case V4:
  738         case V6:
  739                 return arpresolve(f->arp, a, medium, mac);
  740         }
  741 
  742         /* let arp take care of it */
  743         return nil;
  744 }
  745 
  746 void
  747 ethermediumlink(void)
  748 {
  749         addipmedium(&ethermedium);
  750         addipmedium(&gbemedium);
  751 }
  752 
  753 
  754 static void
  755 etherpref2addr(uchar *pref, uchar *ea)
  756 {
  757         pref[8] = ea[0] | 0x2;
  758         pref[9] = ea[1];
  759         pref[10] = ea[2];
  760         pref[11] = 0xFF;
  761         pref[12] = 0xFE;
  762         pref[13] = ea[3];
  763         pref[14] = ea[4];
  764         pref[15] = ea[5];
  765 }

Cache object: 225c10b60428100626851aa003da7e6d


[ 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.