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