17dd7cddfSDavid du Colombier #include "u.h" 27dd7cddfSDavid du Colombier #include "../port/lib.h" 37dd7cddfSDavid du Colombier #include "mem.h" 47dd7cddfSDavid du Colombier #include "dat.h" 57dd7cddfSDavid du Colombier #include "fns.h" 67dd7cddfSDavid du Colombier #include "../port/error.h" 77dd7cddfSDavid du Colombier 87dd7cddfSDavid du Colombier #include "ip.h" 93ff48bf5SDavid du Colombier #include "ipv6.h" 107dd7cddfSDavid du Colombier 117dd7cddfSDavid du Colombier typedef struct Etherhdr Etherhdr; 127dd7cddfSDavid du Colombier struct Etherhdr 137dd7cddfSDavid du Colombier { 147dd7cddfSDavid du Colombier uchar d[6]; 157dd7cddfSDavid du Colombier uchar s[6]; 167dd7cddfSDavid du Colombier uchar t[2]; 177dd7cddfSDavid du Colombier }; 187dd7cddfSDavid du Colombier 193ff48bf5SDavid du Colombier static void etherread4(void *a); 203ff48bf5SDavid du Colombier static void etherread6(void *a); 217dd7cddfSDavid du Colombier static void etherbind(Ipifc *ifc, int argc, char **argv); 227dd7cddfSDavid du Colombier static void etherunbind(Ipifc *ifc); 237dd7cddfSDavid du Colombier static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 247dd7cddfSDavid du Colombier static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia); 257dd7cddfSDavid du Colombier static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia); 2659cc4ca5SDavid du Colombier static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac); 277dd7cddfSDavid du Colombier static void sendarp(Ipifc *ifc, Arpent *a); 287dd7cddfSDavid du Colombier static void sendgarp(Ipifc *ifc, uchar*); 297dd7cddfSDavid du Colombier static int multicastea(uchar *ea, uchar *ip); 307dd7cddfSDavid du Colombier static void recvarpproc(void*); 313ff48bf5SDavid du Colombier static void resolveaddr6(Ipifc *ifc, Arpent *a); 323ff48bf5SDavid du Colombier static void etherpref2addr(uchar *pref, uchar *ea); 337dd7cddfSDavid du Colombier 347dd7cddfSDavid du Colombier Medium ethermedium = 357dd7cddfSDavid du Colombier { 367dd7cddfSDavid du Colombier .name= "ether", 377dd7cddfSDavid du Colombier .hsize= 14, 387dd7cddfSDavid du Colombier .minmtu= 60, 397dd7cddfSDavid du Colombier .maxmtu= 1514, 407dd7cddfSDavid du Colombier .maclen= 6, 417dd7cddfSDavid du Colombier .bind= etherbind, 427dd7cddfSDavid du Colombier .unbind= etherunbind, 437dd7cddfSDavid du Colombier .bwrite= etherbwrite, 447dd7cddfSDavid du Colombier .addmulti= etheraddmulti, 457dd7cddfSDavid du Colombier .remmulti= etherremmulti, 467dd7cddfSDavid du Colombier .ares= arpenter, 477dd7cddfSDavid du Colombier .areg= sendgarp, 483ff48bf5SDavid du Colombier .pref2addr= etherpref2addr, 497dd7cddfSDavid du Colombier }; 507dd7cddfSDavid du Colombier 5159cc4ca5SDavid du Colombier Medium gbemedium = 5259cc4ca5SDavid du Colombier { 5359cc4ca5SDavid du Colombier .name= "gbe", 5459cc4ca5SDavid du Colombier .hsize= 14, 5559cc4ca5SDavid du Colombier .minmtu= 60, 5659cc4ca5SDavid du Colombier .maxmtu= 9014, 5759cc4ca5SDavid du Colombier .maclen= 6, 5859cc4ca5SDavid du Colombier .bind= etherbind, 5959cc4ca5SDavid du Colombier .unbind= etherunbind, 6059cc4ca5SDavid du Colombier .bwrite= etherbwrite, 6159cc4ca5SDavid du Colombier .addmulti= etheraddmulti, 6259cc4ca5SDavid du Colombier .remmulti= etherremmulti, 6359cc4ca5SDavid du Colombier .ares= arpenter, 6459cc4ca5SDavid du Colombier .areg= sendgarp, 653ff48bf5SDavid du Colombier .pref2addr= etherpref2addr, 6659cc4ca5SDavid du Colombier }; 6759cc4ca5SDavid du Colombier 687dd7cddfSDavid du Colombier typedef struct Etherrock Etherrock; 697dd7cddfSDavid du Colombier struct Etherrock 707dd7cddfSDavid du Colombier { 717dd7cddfSDavid du Colombier Fs *f; /* file system we belong to */ 727dd7cddfSDavid du Colombier Proc *arpp; /* arp process */ 733ff48bf5SDavid du Colombier Proc *read4p; /* reading process (v4)*/ 743ff48bf5SDavid du Colombier Proc *read6p; /* reading process (v6)*/ 753ff48bf5SDavid du Colombier Chan *mchan4; /* Data channel for v4 */ 767dd7cddfSDavid du Colombier Chan *achan; /* Arp channel */ 773ff48bf5SDavid du Colombier Chan *cchan4; /* Control channel for v4 */ 783ff48bf5SDavid du Colombier Chan *mchan6; /* Data channel for v6 */ 793ff48bf5SDavid du Colombier Chan *cchan6; /* Control channel for v6 */ 807dd7cddfSDavid du Colombier }; 817dd7cddfSDavid du Colombier 827dd7cddfSDavid du Colombier /* 837dd7cddfSDavid du Colombier * ethernet arp request 847dd7cddfSDavid du Colombier */ 857dd7cddfSDavid du Colombier enum 867dd7cddfSDavid du Colombier { 877dd7cddfSDavid du Colombier ETARP = 0x0806, 883ff48bf5SDavid du Colombier ETIP4 = 0x0800, 893ff48bf5SDavid du Colombier ETIP6 = 0x86DD, 907dd7cddfSDavid du Colombier ARPREQUEST = 1, 917dd7cddfSDavid du Colombier ARPREPLY = 2, 927dd7cddfSDavid du Colombier }; 933ff48bf5SDavid du Colombier 947dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp; 957dd7cddfSDavid du Colombier struct Etherarp 967dd7cddfSDavid du Colombier { 977dd7cddfSDavid du Colombier uchar d[6]; 987dd7cddfSDavid du Colombier uchar s[6]; 997dd7cddfSDavid du Colombier uchar type[2]; 1007dd7cddfSDavid du Colombier uchar hrd[2]; 1017dd7cddfSDavid du Colombier uchar pro[2]; 1027dd7cddfSDavid du Colombier uchar hln; 1037dd7cddfSDavid du Colombier uchar pln; 1047dd7cddfSDavid du Colombier uchar op[2]; 1057dd7cddfSDavid du Colombier uchar sha[6]; 1067dd7cddfSDavid du Colombier uchar spa[4]; 1077dd7cddfSDavid du Colombier uchar tha[6]; 1087dd7cddfSDavid du Colombier uchar tpa[4]; 1097dd7cddfSDavid du Colombier }; 1107dd7cddfSDavid du Colombier 1113ff48bf5SDavid du Colombier static char *nbmsg = "nonblocking"; 1127dd7cddfSDavid du Colombier 1137dd7cddfSDavid du Colombier /* 1147dd7cddfSDavid du Colombier * called to bind an IP ifc to an ethernet device 1157dd7cddfSDavid du Colombier * called with ifc wlock'd 1167dd7cddfSDavid du Colombier */ 1177dd7cddfSDavid du Colombier static void 1187dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv) 1197dd7cddfSDavid du Colombier { 1203ff48bf5SDavid du Colombier Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan; 1213ff48bf5SDavid du Colombier char addr[Maxpath]; //char addr[2*KNAMELEN]; 1223ff48bf5SDavid du Colombier char dir[Maxpath]; //char dir[2*KNAMELEN]; 1237dd7cddfSDavid du Colombier char *buf; 12480ee5cbfSDavid du Colombier int n; 1257dd7cddfSDavid du Colombier char *ptr; 1267dd7cddfSDavid du Colombier Etherrock *er; 1277dd7cddfSDavid du Colombier 1287dd7cddfSDavid du Colombier if(argc < 2) 1297dd7cddfSDavid du Colombier error(Ebadarg); 1307dd7cddfSDavid du Colombier 1313ff48bf5SDavid du Colombier mchan4 = cchan4 = achan = mchan6 = cchan6 = nil; 1327dd7cddfSDavid du Colombier buf = nil; 1337dd7cddfSDavid du Colombier if(waserror()){ 1343ff48bf5SDavid du Colombier if(mchan4 != nil) 1353ff48bf5SDavid du Colombier cclose(mchan4); 1363ff48bf5SDavid du Colombier if(cchan4 != nil) 1373ff48bf5SDavid du Colombier cclose(cchan4); 1387dd7cddfSDavid du Colombier if(achan != nil) 1397dd7cddfSDavid du Colombier cclose(achan); 1403ff48bf5SDavid du Colombier if(mchan6 != nil) 1413ff48bf5SDavid du Colombier cclose(mchan6); 1423ff48bf5SDavid du Colombier if(cchan6 != nil) 1433ff48bf5SDavid du Colombier cclose(cchan6); 1447dd7cddfSDavid du Colombier if(buf != nil) 1457dd7cddfSDavid du Colombier free(buf); 1467dd7cddfSDavid du Colombier nexterror(); 1477dd7cddfSDavid du Colombier } 1487dd7cddfSDavid du Colombier 1497dd7cddfSDavid du Colombier /* 1503ff48bf5SDavid du Colombier * open ip converstation 1517dd7cddfSDavid du Colombier * 1527dd7cddfSDavid du Colombier * the dial will fail if the type is already open on 1537dd7cddfSDavid du Colombier * this device. 1547dd7cddfSDavid du Colombier */ 1557dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x800", argv[2]); 1563ff48bf5SDavid du Colombier mchan4 = chandial(addr, nil, dir, &cchan4); 1573ff48bf5SDavid du Colombier 1583ff48bf5SDavid du Colombier /* 1593ff48bf5SDavid du Colombier * make it non-blocking 1603ff48bf5SDavid du Colombier */ 1613ff48bf5SDavid du Colombier devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0); 1627dd7cddfSDavid du Colombier 1637dd7cddfSDavid du Colombier /* 1647dd7cddfSDavid du Colombier * get mac address 1657dd7cddfSDavid du Colombier */ 1667dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s/stats", dir); 1677dd7cddfSDavid du Colombier buf = smalloc(512); 1683ff48bf5SDavid du Colombier schan = namec(addr, Aopen, OREAD, 0); 1693ff48bf5SDavid du Colombier if(waserror()){ 1703ff48bf5SDavid du Colombier cclose(schan); 1713ff48bf5SDavid du Colombier nexterror(); 1723ff48bf5SDavid du Colombier } 1733ff48bf5SDavid du Colombier n = devtab[schan->type]->read(schan, buf, 511, 0); 1743ff48bf5SDavid du Colombier cclose(schan); 1753ff48bf5SDavid du Colombier poperror(); 1767dd7cddfSDavid du Colombier buf[n] = 0; 1777dd7cddfSDavid du Colombier 1787dd7cddfSDavid du Colombier ptr = strstr(buf, "addr: "); 1797dd7cddfSDavid du Colombier if(!ptr) 1807dd7cddfSDavid du Colombier error(Eio); 1817dd7cddfSDavid du Colombier ptr += 6; 1827dd7cddfSDavid du Colombier 1837dd7cddfSDavid du Colombier parsemac(ifc->mac, ptr, 6); 1847dd7cddfSDavid du Colombier 1857dd7cddfSDavid du Colombier /* 1867dd7cddfSDavid du Colombier * open arp conversation 1877dd7cddfSDavid du Colombier */ 1887dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x806", argv[2]); 18980ee5cbfSDavid du Colombier achan = chandial(addr, nil, nil, nil); 1907dd7cddfSDavid du Colombier 1913ff48bf5SDavid du Colombier /* 1923ff48bf5SDavid du Colombier * open ip conversation 1933ff48bf5SDavid du Colombier * 1943ff48bf5SDavid du Colombier * the dial will fail if the type is already open on 1953ff48bf5SDavid du Colombier * this device. 1963ff48bf5SDavid du Colombier */ 1973ff48bf5SDavid du Colombier snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); 1983ff48bf5SDavid du Colombier mchan6 = chandial(addr, nil, dir, &cchan6); 1993ff48bf5SDavid du Colombier 2003ff48bf5SDavid du Colombier /* 2013ff48bf5SDavid du Colombier * make it non-blocking 2023ff48bf5SDavid du Colombier */ 2033ff48bf5SDavid du Colombier devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0); 2043ff48bf5SDavid du Colombier 2057dd7cddfSDavid du Colombier er = smalloc(sizeof(*er)); 2063ff48bf5SDavid du Colombier er->mchan4 = mchan4; 2073ff48bf5SDavid du Colombier er->cchan4 = cchan4; 2087dd7cddfSDavid du Colombier er->achan = achan; 2093ff48bf5SDavid du Colombier er->mchan6 = mchan6; 2103ff48bf5SDavid du Colombier er->cchan6 = cchan6; 2117dd7cddfSDavid du Colombier er->f = ifc->conv->p->f; 2127dd7cddfSDavid du Colombier ifc->arg = er; 2137dd7cddfSDavid du Colombier 2147dd7cddfSDavid du Colombier free(buf); 2157dd7cddfSDavid du Colombier poperror(); 2167dd7cddfSDavid du Colombier 2173ff48bf5SDavid du Colombier kproc("etherread4", etherread4, ifc); 2187dd7cddfSDavid du Colombier kproc("recvarpproc", recvarpproc, ifc); 2193ff48bf5SDavid du Colombier kproc("etherread6", etherread6, ifc); 2207dd7cddfSDavid du Colombier } 2217dd7cddfSDavid du Colombier 2227dd7cddfSDavid du Colombier /* 2237dd7cddfSDavid du Colombier * called with ifc wlock'd 2247dd7cddfSDavid du Colombier */ 2257dd7cddfSDavid du Colombier static void 2267dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc) 2277dd7cddfSDavid du Colombier { 2287dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 2297dd7cddfSDavid du Colombier 2303ff48bf5SDavid du Colombier if(er->read4p) 2313ff48bf5SDavid du Colombier postnote(er->read4p, 1, "unbind", 0); 2323ff48bf5SDavid du Colombier if(er->read6p) 2333ff48bf5SDavid du Colombier postnote(er->read6p, 1, "unbind", 0); 2347dd7cddfSDavid du Colombier if(er->arpp) 2357dd7cddfSDavid du Colombier postnote(er->arpp, 1, "unbind", 0); 2367dd7cddfSDavid du Colombier 2377dd7cddfSDavid du Colombier /* wait for readers to die */ 2383ff48bf5SDavid du Colombier while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0) 2397dd7cddfSDavid du Colombier tsleep(&up->sleep, return0, 0, 300); 2407dd7cddfSDavid du Colombier 2413ff48bf5SDavid du Colombier if(er->mchan4 != nil) 2423ff48bf5SDavid du Colombier cclose(er->mchan4); 2437dd7cddfSDavid du Colombier if(er->achan != nil) 2447dd7cddfSDavid du Colombier cclose(er->achan); 2453ff48bf5SDavid du Colombier if(er->cchan4 != nil) 2463ff48bf5SDavid du Colombier cclose(er->cchan4); 2473ff48bf5SDavid du Colombier if(er->mchan6 != nil) 2483ff48bf5SDavid du Colombier cclose(er->mchan6); 2493ff48bf5SDavid du Colombier if(er->cchan6 != nil) 2503ff48bf5SDavid du Colombier cclose(er->cchan6); 2517dd7cddfSDavid du Colombier 2527dd7cddfSDavid du Colombier free(er); 2537dd7cddfSDavid du Colombier } 2547dd7cddfSDavid du Colombier 2557dd7cddfSDavid du Colombier /* 2567dd7cddfSDavid du Colombier * called by ipoput with a single block to write with ifc rlock'd 2577dd7cddfSDavid du Colombier */ 2587dd7cddfSDavid du Colombier static void 2597dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip) 2607dd7cddfSDavid du Colombier { 2617dd7cddfSDavid du Colombier Etherhdr *eh; 2627dd7cddfSDavid du Colombier Arpent *a; 2637dd7cddfSDavid du Colombier uchar mac[6]; 2647dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 2657dd7cddfSDavid du Colombier 2667dd7cddfSDavid du Colombier /* get mac address of destination */ 2673ff48bf5SDavid du Colombier a = arpget(er->f->arp, bp, version, ifc, ip, mac); 2687dd7cddfSDavid du Colombier if(a){ 2697dd7cddfSDavid du Colombier /* check for broadcast or multicast */ 27059cc4ca5SDavid du Colombier bp = multicastarp(er->f, a, ifc->m, mac); 2717dd7cddfSDavid du Colombier if(bp==nil){ 2723ff48bf5SDavid du Colombier switch(version){ 2733ff48bf5SDavid du Colombier case V4: 2747dd7cddfSDavid du Colombier sendarp(ifc, a); 2753ff48bf5SDavid du Colombier break; 2763ff48bf5SDavid du Colombier case V6: 2773ff48bf5SDavid du Colombier resolveaddr6(ifc, a); 2783ff48bf5SDavid du Colombier break; 2793ff48bf5SDavid du Colombier default: 2803ff48bf5SDavid du Colombier panic("etherbwrite: version %d", version); 2813ff48bf5SDavid du Colombier } 2827dd7cddfSDavid du Colombier return; 2837dd7cddfSDavid du Colombier } 2847dd7cddfSDavid du Colombier } 2857dd7cddfSDavid du Colombier 2867dd7cddfSDavid du Colombier /* make it a single block with space for the ether header */ 2877dd7cddfSDavid du Colombier bp = padblock(bp, ifc->m->hsize); 2887dd7cddfSDavid du Colombier if(bp->next) 2897dd7cddfSDavid du Colombier bp = concatblock(bp); 2907dd7cddfSDavid du Colombier if(BLEN(bp) < ifc->minmtu) 2917dd7cddfSDavid du Colombier bp = adjustblock(bp, ifc->minmtu); 2927dd7cddfSDavid du Colombier eh = (Etherhdr*)bp->rp; 2937dd7cddfSDavid du Colombier 2947dd7cddfSDavid du Colombier /* copy in mac addresses and ether type */ 2957dd7cddfSDavid du Colombier memmove(eh->s, ifc->mac, sizeof(eh->s)); 2967dd7cddfSDavid du Colombier memmove(eh->d, mac, sizeof(eh->d)); 2973ff48bf5SDavid du Colombier 2987dd7cddfSDavid du Colombier switch(version){ 2997dd7cddfSDavid du Colombier case V4: 3007dd7cddfSDavid du Colombier eh->t[0] = 0x08; 3017dd7cddfSDavid du Colombier eh->t[1] = 0x00; 3023ff48bf5SDavid du Colombier devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0); 3037dd7cddfSDavid du Colombier break; 3047dd7cddfSDavid du Colombier case V6: 3057dd7cddfSDavid du Colombier eh->t[0] = 0x86; 3067dd7cddfSDavid du Colombier eh->t[1] = 0xDD; 3073ff48bf5SDavid du Colombier devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0); 3087dd7cddfSDavid du Colombier break; 3093ff48bf5SDavid du Colombier default: 3103ff48bf5SDavid du Colombier panic("etherbwrite2: version %d", version); 3117dd7cddfSDavid du Colombier } 3127dd7cddfSDavid du Colombier ifc->out++; 3137dd7cddfSDavid du Colombier } 3147dd7cddfSDavid du Colombier 3153ff48bf5SDavid du Colombier 3167dd7cddfSDavid du Colombier /* 3177dd7cddfSDavid du Colombier * process to read from the ethernet 3187dd7cddfSDavid du Colombier */ 3197dd7cddfSDavid du Colombier static void 3203ff48bf5SDavid du Colombier etherread4(void *a) 3217dd7cddfSDavid du Colombier { 3227dd7cddfSDavid du Colombier Ipifc *ifc; 3237dd7cddfSDavid du Colombier Block *bp; 3247dd7cddfSDavid du Colombier Etherrock *er; 3257dd7cddfSDavid du Colombier 3267dd7cddfSDavid du Colombier ifc = a; 3277dd7cddfSDavid du Colombier er = ifc->arg; 3283ff48bf5SDavid du Colombier er->read4p = up; /* hide identity under a rock for unbind */ 3297dd7cddfSDavid du Colombier if(waserror()){ 3303ff48bf5SDavid du Colombier er->read4p = 0; 3317dd7cddfSDavid du Colombier pexit("hangup", 1); 3327dd7cddfSDavid du Colombier } 3337dd7cddfSDavid du Colombier for(;;){ 3343ff48bf5SDavid du Colombier bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxmtu, 0); 3357dd7cddfSDavid du Colombier if(!canrlock(ifc)){ 3367dd7cddfSDavid du Colombier freeb(bp); 3377dd7cddfSDavid du Colombier continue; 3387dd7cddfSDavid du Colombier } 3397dd7cddfSDavid du Colombier if(waserror()){ 3407dd7cddfSDavid du Colombier runlock(ifc); 3417dd7cddfSDavid du Colombier nexterror(); 3427dd7cddfSDavid du Colombier } 3437dd7cddfSDavid du Colombier ifc->in++; 3447dd7cddfSDavid du Colombier bp->rp += ifc->m->hsize; 3457dd7cddfSDavid du Colombier if(ifc->lifc == nil) 3467dd7cddfSDavid du Colombier freeb(bp); 3477dd7cddfSDavid du Colombier else 3483ff48bf5SDavid du Colombier ipiput4(er->f, ifc, bp); 3493ff48bf5SDavid du Colombier runlock(ifc); 3503ff48bf5SDavid du Colombier poperror(); 3513ff48bf5SDavid du Colombier } 3523ff48bf5SDavid du Colombier } 3533ff48bf5SDavid du Colombier 3543ff48bf5SDavid du Colombier 3553ff48bf5SDavid du Colombier /* 3563ff48bf5SDavid du Colombier * process to read from the ethernet, IPv6 3573ff48bf5SDavid du Colombier */ 3583ff48bf5SDavid du Colombier static void 3593ff48bf5SDavid du Colombier etherread6(void *a) 3603ff48bf5SDavid du Colombier { 3613ff48bf5SDavid du Colombier Ipifc *ifc; 3623ff48bf5SDavid du Colombier Block *bp; 3633ff48bf5SDavid du Colombier Etherrock *er; 3643ff48bf5SDavid du Colombier 3653ff48bf5SDavid du Colombier ifc = a; 3663ff48bf5SDavid du Colombier er = ifc->arg; 3673ff48bf5SDavid du Colombier er->read6p = up; /* hide identity under a rock for unbind */ 3683ff48bf5SDavid du Colombier if(waserror()){ 3693ff48bf5SDavid du Colombier er->read6p = 0; 3703ff48bf5SDavid du Colombier pexit("hangup", 1); 3713ff48bf5SDavid du Colombier } 3723ff48bf5SDavid du Colombier for(;;){ 3733ff48bf5SDavid du Colombier bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxmtu, 0); 3743ff48bf5SDavid du Colombier if(!canrlock(ifc)){ 3753ff48bf5SDavid du Colombier freeb(bp); 3763ff48bf5SDavid du Colombier continue; 3773ff48bf5SDavid du Colombier } 3783ff48bf5SDavid du Colombier if(waserror()){ 3793ff48bf5SDavid du Colombier runlock(ifc); 3803ff48bf5SDavid du Colombier nexterror(); 3813ff48bf5SDavid du Colombier } 3823ff48bf5SDavid du Colombier ifc->in++; 3833ff48bf5SDavid du Colombier bp->rp += ifc->m->hsize; 3843ff48bf5SDavid du Colombier if(ifc->lifc == nil) 3853ff48bf5SDavid du Colombier freeb(bp); 3863ff48bf5SDavid du Colombier else 3873ff48bf5SDavid du Colombier ipiput6(er->f, ifc, bp); 3887dd7cddfSDavid du Colombier runlock(ifc); 3897dd7cddfSDavid du Colombier poperror(); 3907dd7cddfSDavid du Colombier } 3917dd7cddfSDavid du Colombier } 3927dd7cddfSDavid du Colombier 3937dd7cddfSDavid du Colombier static void 3947dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *) 3957dd7cddfSDavid du Colombier { 3967dd7cddfSDavid du Colombier uchar mac[6]; 3977dd7cddfSDavid du Colombier char buf[64]; 3987dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 3993ff48bf5SDavid du Colombier int version; 4007dd7cddfSDavid du Colombier 4013ff48bf5SDavid du Colombier version = multicastea(mac, a); 4027dd7cddfSDavid du Colombier sprint(buf, "addmulti %E", mac); 4033ff48bf5SDavid du Colombier switch(version){ 4043ff48bf5SDavid du Colombier case V4: 4053ff48bf5SDavid du Colombier devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0); 4063ff48bf5SDavid du Colombier break; 4073ff48bf5SDavid du Colombier case V6: 4083ff48bf5SDavid du Colombier devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0); 4093ff48bf5SDavid du Colombier break; 4103ff48bf5SDavid du Colombier default: 4113ff48bf5SDavid du Colombier panic("etheraddmulti: version %d", version); 4123ff48bf5SDavid du Colombier } 4137dd7cddfSDavid du Colombier } 4147dd7cddfSDavid du Colombier 4157dd7cddfSDavid du Colombier static void 4167dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *) 4177dd7cddfSDavid du Colombier { 4187dd7cddfSDavid du Colombier uchar mac[6]; 4197dd7cddfSDavid du Colombier char buf[64]; 4207dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 4213ff48bf5SDavid du Colombier int version; 4227dd7cddfSDavid du Colombier 4233ff48bf5SDavid du Colombier version = multicastea(mac, a); 4247dd7cddfSDavid du Colombier sprint(buf, "remmulti %E", mac); 4253ff48bf5SDavid du Colombier switch(version){ 4263ff48bf5SDavid du Colombier case V4: 4273ff48bf5SDavid du Colombier devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0); 4283ff48bf5SDavid du Colombier break; 4293ff48bf5SDavid du Colombier case V6: 4303ff48bf5SDavid du Colombier devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0); 4313ff48bf5SDavid du Colombier break; 4323ff48bf5SDavid du Colombier default: 4333ff48bf5SDavid du Colombier panic("etherremmulti: version %d", version); 4343ff48bf5SDavid du Colombier } 4357dd7cddfSDavid du Colombier } 4367dd7cddfSDavid du Colombier 4377dd7cddfSDavid du Colombier /* 4387dd7cddfSDavid du Colombier * send an ethernet arp 4397dd7cddfSDavid du Colombier * (only v4, v6 uses the neighbor discovery, rfc1970) 4407dd7cddfSDavid du Colombier */ 4417dd7cddfSDavid du Colombier static void 4427dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a) 4437dd7cddfSDavid du Colombier { 4447dd7cddfSDavid du Colombier int n; 4457dd7cddfSDavid du Colombier Block *bp; 4467dd7cddfSDavid du Colombier Etherarp *e; 4477dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 4487dd7cddfSDavid du Colombier 4497dd7cddfSDavid du Colombier /* don't do anything if it's been less than a second since the last */ 4503ff48bf5SDavid du Colombier if(NOW - a->time < 1000){ 4517dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 4527dd7cddfSDavid du Colombier return; 4537dd7cddfSDavid du Colombier } 4547dd7cddfSDavid du Colombier 4557dd7cddfSDavid du Colombier /* remove all but the last message */ 4567dd7cddfSDavid du Colombier while((bp = a->hold) != nil){ 4577dd7cddfSDavid du Colombier if(bp == a->last) 4587dd7cddfSDavid du Colombier break; 4597dd7cddfSDavid du Colombier a->hold = bp->list; 4607dd7cddfSDavid du Colombier freeblist(bp); 4617dd7cddfSDavid du Colombier } 4627dd7cddfSDavid du Colombier 4637dd7cddfSDavid du Colombier /* try to keep it around for a second more */ 4643ff48bf5SDavid du Colombier a->time = NOW; 4657dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 4667dd7cddfSDavid du Colombier 4677dd7cddfSDavid du Colombier n = sizeof(Etherarp); 4687dd7cddfSDavid du Colombier if(n < a->type->minmtu) 4697dd7cddfSDavid du Colombier n = a->type->minmtu; 4707dd7cddfSDavid du Colombier bp = allocb(n); 4717dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 4727dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 4737dd7cddfSDavid du Colombier memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa)); 4747dd7cddfSDavid du Colombier ipv4local(ifc, e->spa); 4757dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 4767dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 4777dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 4787dd7cddfSDavid du Colombier 4797dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 4807dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 4813ff48bf5SDavid du Colombier hnputs(e->pro, ETIP4); 4827dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 4837dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 4847dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 4857dd7cddfSDavid du Colombier bp->wp += n; 4867dd7cddfSDavid du Colombier 4877dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 4887dd7cddfSDavid du Colombier if(n < 0) 4897dd7cddfSDavid du Colombier print("arp: send: %r\n"); 4907dd7cddfSDavid du Colombier } 4917dd7cddfSDavid du Colombier 4923ff48bf5SDavid du Colombier static void 4933ff48bf5SDavid du Colombier resolveaddr6(Ipifc *ifc, Arpent *a) 4943ff48bf5SDavid du Colombier { 4953ff48bf5SDavid du Colombier int sflag; 4963ff48bf5SDavid du Colombier Block *bp; 4973ff48bf5SDavid du Colombier Etherrock *er = ifc->arg; 4983ff48bf5SDavid du Colombier uchar ipsrc[IPaddrlen]; 4993ff48bf5SDavid du Colombier 5003ff48bf5SDavid du Colombier /* don't do anything if it's been less than a second since the last */ 5013ff48bf5SDavid du Colombier if(NOW - a->time < ReTransTimer){ 5023ff48bf5SDavid du Colombier arprelease(er->f->arp, a); 5033ff48bf5SDavid du Colombier return; 5043ff48bf5SDavid du Colombier } 5053ff48bf5SDavid du Colombier 5063ff48bf5SDavid du Colombier /* remove all but the last message */ 5073ff48bf5SDavid du Colombier while((bp = a->hold) != nil){ 5083ff48bf5SDavid du Colombier if(bp == a->last) 5093ff48bf5SDavid du Colombier break; 5103ff48bf5SDavid du Colombier a->hold = bp->list; 5113ff48bf5SDavid du Colombier freeblist(bp); 5123ff48bf5SDavid du Colombier } 5133ff48bf5SDavid du Colombier 5143ff48bf5SDavid du Colombier /* try to keep it around for a second more */ 5153ff48bf5SDavid du Colombier a->time = NOW; 5163ff48bf5SDavid du Colombier a->rxtat = NOW + ReTransTimer; 5173ff48bf5SDavid du Colombier if(a->rxtsrem <= 0) { 5183ff48bf5SDavid du Colombier arprelease(er->f->arp, a); 5193ff48bf5SDavid du Colombier return; 5203ff48bf5SDavid du Colombier } 5213ff48bf5SDavid du Colombier 5223ff48bf5SDavid du Colombier a->rxtsrem--; 5233ff48bf5SDavid du Colombier arprelease(er->f->arp, a); 5243ff48bf5SDavid du Colombier 5253ff48bf5SDavid du Colombier if(sflag = ipv6anylocal(ifc, ipsrc)) 5263ff48bf5SDavid du Colombier icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 5273ff48bf5SDavid du Colombier } 5283ff48bf5SDavid du Colombier 5297dd7cddfSDavid du Colombier /* 5307dd7cddfSDavid du Colombier * send a gratuitous arp to refresh arp caches 5317dd7cddfSDavid du Colombier */ 5327dd7cddfSDavid du Colombier static void 5337dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip) 5347dd7cddfSDavid du Colombier { 5357dd7cddfSDavid du Colombier int n; 5367dd7cddfSDavid du Colombier Block *bp; 5377dd7cddfSDavid du Colombier Etherarp *e; 5387dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 5397dd7cddfSDavid du Colombier 5407dd7cddfSDavid du Colombier /* don't arp for our initial non address */ 5417dd7cddfSDavid du Colombier if(ipcmp(ip, IPnoaddr) == 0) 5427dd7cddfSDavid du Colombier return; 5437dd7cddfSDavid du Colombier 5447dd7cddfSDavid du Colombier n = sizeof(Etherarp); 54559cc4ca5SDavid du Colombier if(n < ifc->m->minmtu) 54659cc4ca5SDavid du Colombier n = ifc->m->minmtu; 5477dd7cddfSDavid du Colombier bp = allocb(n); 5487dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 5497dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 5507dd7cddfSDavid du Colombier memmove(e->tpa, ip+IPv4off, sizeof(e->tpa)); 5517dd7cddfSDavid du Colombier memmove(e->spa, ip+IPv4off, sizeof(e->spa)); 5527dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 5537dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 5547dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 5557dd7cddfSDavid du Colombier 5567dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 5577dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 5583ff48bf5SDavid du Colombier hnputs(e->pro, ETIP4); 5597dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 5607dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 5617dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 5627dd7cddfSDavid du Colombier bp->wp += n; 5637dd7cddfSDavid du Colombier 5647dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 5657dd7cddfSDavid du Colombier if(n < 0) 5667dd7cddfSDavid du Colombier print("garp: send: %r\n"); 5677dd7cddfSDavid du Colombier } 5687dd7cddfSDavid du Colombier 5697dd7cddfSDavid du Colombier static void 5707dd7cddfSDavid du Colombier recvarp(Ipifc *ifc) 5717dd7cddfSDavid du Colombier { 5727dd7cddfSDavid du Colombier int n; 5737dd7cddfSDavid du Colombier Block *ebp, *rbp; 5747dd7cddfSDavid du Colombier Etherarp *e, *r; 5757dd7cddfSDavid du Colombier uchar ip[IPaddrlen]; 576*ef9eff0bSDavid du Colombier static uchar eprinted[4]; 5777dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 5787dd7cddfSDavid du Colombier 5797dd7cddfSDavid du Colombier ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxmtu, 0); 5807dd7cddfSDavid du Colombier if(ebp == nil) { 5817dd7cddfSDavid du Colombier print("arp: rcv: %r\n"); 5827dd7cddfSDavid du Colombier return; 5837dd7cddfSDavid du Colombier } 5847dd7cddfSDavid du Colombier 5857dd7cddfSDavid du Colombier e = (Etherarp*)ebp->rp; 5867dd7cddfSDavid du Colombier switch(nhgets(e->op)) { 5877dd7cddfSDavid du Colombier default: 5887dd7cddfSDavid du Colombier break; 5897dd7cddfSDavid du Colombier 5907dd7cddfSDavid du Colombier case ARPREPLY: 5913ff48bf5SDavid du Colombier /* check for machine using my ip address */ 5923ff48bf5SDavid du Colombier v4tov6(ip, e->spa); 5939a747e4fSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 5949a747e4fSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ 5959a747e4fSDavid du Colombier print("arprep: 0x%E/0x%E also has ip addr %V\n", 5969a747e4fSDavid du Colombier e->s, e->sha, e->spa); 5979a747e4fSDavid du Colombier break; 5989a747e4fSDavid du Colombier } 5999a747e4fSDavid du Colombier } 6003ff48bf5SDavid du Colombier 6017dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0); 6027dd7cddfSDavid du Colombier break; 6037dd7cddfSDavid du Colombier 6047dd7cddfSDavid du Colombier case ARPREQUEST: 6057dd7cddfSDavid du Colombier /* don't answer arps till we know who we are */ 6067dd7cddfSDavid du Colombier if(ifc->lifc == 0) 6077dd7cddfSDavid du Colombier break; 6087dd7cddfSDavid du Colombier 6093ff48bf5SDavid du Colombier /* check for machine using my ip or ether address */ 6107dd7cddfSDavid du Colombier v4tov6(ip, e->spa); 6117dd7cddfSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 612*ef9eff0bSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ 613*ef9eff0bSDavid du Colombier if (memcmp(eprinted, e->spa, sizeof(e->spa))){ 614*ef9eff0bSDavid du Colombier /* print only once */ 6153ff48bf5SDavid du Colombier print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa); 616*ef9eff0bSDavid du Colombier memmove(eprinted, e->spa, sizeof(e->spa)); 617*ef9eff0bSDavid du Colombier } 618*ef9eff0bSDavid du Colombier } 6197dd7cddfSDavid du Colombier } else { 6207dd7cddfSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){ 6213ff48bf5SDavid du Colombier print("arpreq: %V also has ether addr %E\n", e->spa, e->sha); 6227dd7cddfSDavid du Colombier break; 6237dd7cddfSDavid du Colombier } 6247dd7cddfSDavid du Colombier } 6257dd7cddfSDavid du Colombier 6267dd7cddfSDavid du Colombier /* refresh what we know about sender */ 6277dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1); 6287dd7cddfSDavid du Colombier 6297dd7cddfSDavid du Colombier /* answer only requests for our address or systems we're proxying for */ 6307dd7cddfSDavid du Colombier v4tov6(ip, e->tpa); 6317dd7cddfSDavid du Colombier if(!iplocalonifc(ifc, ip)) 6327dd7cddfSDavid du Colombier if(!ipproxyifc(er->f, ifc, ip)) 6337dd7cddfSDavid du Colombier break; 6347dd7cddfSDavid du Colombier 6357dd7cddfSDavid du Colombier n = sizeof(Etherarp); 6367dd7cddfSDavid du Colombier if(n < ifc->minmtu) 6377dd7cddfSDavid du Colombier n = ifc->minmtu; 6387dd7cddfSDavid du Colombier rbp = allocb(n); 6397dd7cddfSDavid du Colombier r = (Etherarp*)rbp->rp; 6407dd7cddfSDavid du Colombier memset(r, 0, sizeof(Etherarp)); 6417dd7cddfSDavid du Colombier hnputs(r->type, ETARP); 6427dd7cddfSDavid du Colombier hnputs(r->hrd, 1); 6433ff48bf5SDavid du Colombier hnputs(r->pro, ETIP4); 6447dd7cddfSDavid du Colombier r->hln = sizeof(r->sha); 6457dd7cddfSDavid du Colombier r->pln = sizeof(r->spa); 6467dd7cddfSDavid du Colombier hnputs(r->op, ARPREPLY); 6477dd7cddfSDavid du Colombier memmove(r->tha, e->sha, sizeof(r->tha)); 6487dd7cddfSDavid du Colombier memmove(r->tpa, e->spa, sizeof(r->tpa)); 6497dd7cddfSDavid du Colombier memmove(r->sha, ifc->mac, sizeof(r->sha)); 6507dd7cddfSDavid du Colombier memmove(r->spa, e->tpa, sizeof(r->spa)); 6517dd7cddfSDavid du Colombier memmove(r->d, e->sha, sizeof(r->d)); 6527dd7cddfSDavid du Colombier memmove(r->s, ifc->mac, sizeof(r->s)); 6537dd7cddfSDavid du Colombier rbp->wp += n; 6547dd7cddfSDavid du Colombier 6557dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0); 6567dd7cddfSDavid du Colombier if(n < 0) 6577dd7cddfSDavid du Colombier print("arp: write: %r\n"); 6587dd7cddfSDavid du Colombier } 6597dd7cddfSDavid du Colombier freeb(ebp); 6607dd7cddfSDavid du Colombier } 6617dd7cddfSDavid du Colombier 6627dd7cddfSDavid du Colombier static void 6637dd7cddfSDavid du Colombier recvarpproc(void *v) 6647dd7cddfSDavid du Colombier { 6657dd7cddfSDavid du Colombier Ipifc *ifc = v; 6667dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 6677dd7cddfSDavid du Colombier 6687dd7cddfSDavid du Colombier er->arpp = up; 6697dd7cddfSDavid du Colombier if(waserror()){ 6707dd7cddfSDavid du Colombier er->arpp = 0; 6717dd7cddfSDavid du Colombier pexit("hangup", 1); 6727dd7cddfSDavid du Colombier } 6737dd7cddfSDavid du Colombier for(;;) 6747dd7cddfSDavid du Colombier recvarp(ifc); 6757dd7cddfSDavid du Colombier } 6767dd7cddfSDavid du Colombier 6777dd7cddfSDavid du Colombier static int 6787dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip) 6797dd7cddfSDavid du Colombier { 6807dd7cddfSDavid du Colombier int x; 6817dd7cddfSDavid du Colombier 6827dd7cddfSDavid du Colombier switch(x = ipismulticast(ip)){ 6837dd7cddfSDavid du Colombier case V4: 6847dd7cddfSDavid du Colombier ea[0] = 0x01; 6857dd7cddfSDavid du Colombier ea[1] = 0x00; 6867dd7cddfSDavid du Colombier ea[2] = 0x5e; 6877dd7cddfSDavid du Colombier ea[3] = ip[13] & 0x7f; 6887dd7cddfSDavid du Colombier ea[4] = ip[14]; 6897dd7cddfSDavid du Colombier ea[5] = ip[15]; 6907dd7cddfSDavid du Colombier break; 6917dd7cddfSDavid du Colombier case V6: 6927dd7cddfSDavid du Colombier ea[0] = 0x33; 6937dd7cddfSDavid du Colombier ea[1] = 0x33; 6947dd7cddfSDavid du Colombier ea[2] = ip[12]; 6957dd7cddfSDavid du Colombier ea[3] = ip[13]; 6967dd7cddfSDavid du Colombier ea[4] = ip[14]; 6977dd7cddfSDavid du Colombier ea[5] = ip[15]; 6987dd7cddfSDavid du Colombier break; 6997dd7cddfSDavid du Colombier } 7007dd7cddfSDavid du Colombier return x; 7017dd7cddfSDavid du Colombier } 7027dd7cddfSDavid du Colombier 7037dd7cddfSDavid du Colombier /* 7047dd7cddfSDavid du Colombier * fill in an arp entry for broadcast or multicast 7053ff48bf5SDavid du Colombier * addresses. Return the first queued packet for the 7063ff48bf5SDavid du Colombier * IP address. 7077dd7cddfSDavid du Colombier */ 7087dd7cddfSDavid du Colombier static Block* 70959cc4ca5SDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac) 7107dd7cddfSDavid du Colombier { 7117dd7cddfSDavid du Colombier /* is it broadcast? */ 7127dd7cddfSDavid du Colombier switch(ipforme(f, a->ip)){ 7137dd7cddfSDavid du Colombier case Runi: 7147dd7cddfSDavid du Colombier return nil; 7157dd7cddfSDavid du Colombier case Rbcast: 7167dd7cddfSDavid du Colombier memset(mac, 0xff, 6); 71759cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac); 7187dd7cddfSDavid du Colombier default: 7197dd7cddfSDavid du Colombier break; 7207dd7cddfSDavid du Colombier } 7217dd7cddfSDavid du Colombier 7227dd7cddfSDavid du Colombier /* if multicast, fill in mac */ 7237dd7cddfSDavid du Colombier switch(multicastea(mac, a->ip)){ 7247dd7cddfSDavid du Colombier case V4: 7257dd7cddfSDavid du Colombier case V6: 72659cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac); 7277dd7cddfSDavid du Colombier } 7287dd7cddfSDavid du Colombier 7297dd7cddfSDavid du Colombier /* let arp take care of it */ 7307dd7cddfSDavid du Colombier return nil; 7317dd7cddfSDavid du Colombier } 7327dd7cddfSDavid du Colombier 7337dd7cddfSDavid du Colombier void 7347dd7cddfSDavid du Colombier ethermediumlink(void) 7357dd7cddfSDavid du Colombier { 7367dd7cddfSDavid du Colombier addipmedium(ðermedium); 73759cc4ca5SDavid du Colombier addipmedium(&gbemedium); 7387dd7cddfSDavid du Colombier } 7393ff48bf5SDavid du Colombier 7403ff48bf5SDavid du Colombier 7413ff48bf5SDavid du Colombier static void 7423ff48bf5SDavid du Colombier etherpref2addr(uchar *pref, uchar *ea) 7433ff48bf5SDavid du Colombier { 7443ff48bf5SDavid du Colombier pref[8] = ea[0] | 0x2; 7453ff48bf5SDavid du Colombier pref[9] = ea[1]; 7463ff48bf5SDavid du Colombier pref[10] = ea[2]; 7473ff48bf5SDavid du Colombier pref[11] = 0xFF; 7483ff48bf5SDavid du Colombier pref[12] = 0xFE; 7493ff48bf5SDavid du Colombier pref[13] = ea[3]; 7503ff48bf5SDavid du Colombier pref[14] = ea[4]; 7513ff48bf5SDavid du Colombier pref[15] = ea[5]; 7523ff48bf5SDavid du Colombier } 753