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 195d82c6aeSDavid du Colombier static uchar ipbroadcast[IPaddrlen] = { 205d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff, 215d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff, 225d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff, 235d82c6aeSDavid du Colombier 0xff,0xff,0xff,0xff, 245d82c6aeSDavid du Colombier }; 255d82c6aeSDavid du Colombier 265d82c6aeSDavid du Colombier static uchar etherbroadcast[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 275d82c6aeSDavid du Colombier 283ff48bf5SDavid du Colombier static void etherread4(void *a); 293ff48bf5SDavid du Colombier static void etherread6(void *a); 307dd7cddfSDavid du Colombier static void etherbind(Ipifc *ifc, int argc, char **argv); 317dd7cddfSDavid du Colombier static void etherunbind(Ipifc *ifc); 327dd7cddfSDavid du Colombier static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 337dd7cddfSDavid du Colombier static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia); 347dd7cddfSDavid du Colombier static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia); 3559cc4ca5SDavid du Colombier static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac); 367dd7cddfSDavid du Colombier static void sendarp(Ipifc *ifc, Arpent *a); 377dd7cddfSDavid du Colombier static void sendgarp(Ipifc *ifc, uchar*); 387dd7cddfSDavid du Colombier static int multicastea(uchar *ea, uchar *ip); 397dd7cddfSDavid du Colombier static void recvarpproc(void*); 403ff48bf5SDavid du Colombier static void resolveaddr6(Ipifc *ifc, Arpent *a); 413ff48bf5SDavid du Colombier static void etherpref2addr(uchar *pref, uchar *ea); 427dd7cddfSDavid du Colombier 437dd7cddfSDavid du Colombier Medium ethermedium = 447dd7cddfSDavid du Colombier { 457dd7cddfSDavid du Colombier .name= "ether", 467dd7cddfSDavid du Colombier .hsize= 14, 473f695129SDavid du Colombier .mintu= 60, 483f695129SDavid du Colombier .maxtu= 1514, 497dd7cddfSDavid du Colombier .maclen= 6, 507dd7cddfSDavid du Colombier .bind= etherbind, 517dd7cddfSDavid du Colombier .unbind= etherunbind, 527dd7cddfSDavid du Colombier .bwrite= etherbwrite, 537dd7cddfSDavid du Colombier .addmulti= etheraddmulti, 547dd7cddfSDavid du Colombier .remmulti= etherremmulti, 557dd7cddfSDavid du Colombier .ares= arpenter, 567dd7cddfSDavid du Colombier .areg= sendgarp, 573ff48bf5SDavid du Colombier .pref2addr= etherpref2addr, 587dd7cddfSDavid du Colombier }; 597dd7cddfSDavid du Colombier 6059cc4ca5SDavid du Colombier Medium gbemedium = 6159cc4ca5SDavid du Colombier { 6259cc4ca5SDavid du Colombier .name= "gbe", 6359cc4ca5SDavid du Colombier .hsize= 14, 643f695129SDavid du Colombier .mintu= 60, 653f695129SDavid du Colombier .maxtu= 9014, 6659cc4ca5SDavid du Colombier .maclen= 6, 6759cc4ca5SDavid du Colombier .bind= etherbind, 6859cc4ca5SDavid du Colombier .unbind= etherunbind, 6959cc4ca5SDavid du Colombier .bwrite= etherbwrite, 7059cc4ca5SDavid du Colombier .addmulti= etheraddmulti, 7159cc4ca5SDavid du Colombier .remmulti= etherremmulti, 7259cc4ca5SDavid du Colombier .ares= arpenter, 7359cc4ca5SDavid du Colombier .areg= sendgarp, 743ff48bf5SDavid du Colombier .pref2addr= etherpref2addr, 7559cc4ca5SDavid du Colombier }; 7659cc4ca5SDavid du Colombier 777dd7cddfSDavid du Colombier typedef struct Etherrock Etherrock; 787dd7cddfSDavid du Colombier struct Etherrock 797dd7cddfSDavid du Colombier { 807dd7cddfSDavid du Colombier Fs *f; /* file system we belong to */ 817dd7cddfSDavid du Colombier Proc *arpp; /* arp process */ 823ff48bf5SDavid du Colombier Proc *read4p; /* reading process (v4)*/ 833ff48bf5SDavid du Colombier Proc *read6p; /* reading process (v6)*/ 843ff48bf5SDavid du Colombier Chan *mchan4; /* Data channel for v4 */ 857dd7cddfSDavid du Colombier Chan *achan; /* Arp channel */ 863ff48bf5SDavid du Colombier Chan *cchan4; /* Control channel for v4 */ 873ff48bf5SDavid du Colombier Chan *mchan6; /* Data channel for v6 */ 883ff48bf5SDavid du Colombier Chan *cchan6; /* Control channel for v6 */ 897dd7cddfSDavid du Colombier }; 907dd7cddfSDavid du Colombier 917dd7cddfSDavid du Colombier /* 927dd7cddfSDavid du Colombier * ethernet arp request 937dd7cddfSDavid du Colombier */ 947dd7cddfSDavid du Colombier enum 957dd7cddfSDavid du Colombier { 967dd7cddfSDavid du Colombier ETARP = 0x0806, 973ff48bf5SDavid du Colombier ETIP4 = 0x0800, 983ff48bf5SDavid du Colombier ETIP6 = 0x86DD, 997dd7cddfSDavid du Colombier ARPREQUEST = 1, 1007dd7cddfSDavid du Colombier ARPREPLY = 2, 1017dd7cddfSDavid du Colombier }; 1023ff48bf5SDavid du Colombier 1037dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp; 1047dd7cddfSDavid du Colombier struct Etherarp 1057dd7cddfSDavid du Colombier { 1067dd7cddfSDavid du Colombier uchar d[6]; 1077dd7cddfSDavid du Colombier uchar s[6]; 1087dd7cddfSDavid du Colombier uchar type[2]; 1097dd7cddfSDavid du Colombier uchar hrd[2]; 1107dd7cddfSDavid du Colombier uchar pro[2]; 1117dd7cddfSDavid du Colombier uchar hln; 1127dd7cddfSDavid du Colombier uchar pln; 1137dd7cddfSDavid du Colombier uchar op[2]; 1147dd7cddfSDavid du Colombier uchar sha[6]; 1157dd7cddfSDavid du Colombier uchar spa[4]; 1167dd7cddfSDavid du Colombier uchar tha[6]; 1177dd7cddfSDavid du Colombier uchar tpa[4]; 1187dd7cddfSDavid du Colombier }; 1197dd7cddfSDavid du Colombier 1203ff48bf5SDavid du Colombier static char *nbmsg = "nonblocking"; 1217dd7cddfSDavid du Colombier 1227dd7cddfSDavid du Colombier /* 1237dd7cddfSDavid du Colombier * called to bind an IP ifc to an ethernet device 1247dd7cddfSDavid du Colombier * called with ifc wlock'd 1257dd7cddfSDavid du Colombier */ 1267dd7cddfSDavid du Colombier static void 1277dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv) 1287dd7cddfSDavid du Colombier { 1293ff48bf5SDavid du Colombier Chan *mchan4, *cchan4, *achan, *mchan6, *cchan6, *schan; 1303ff48bf5SDavid du Colombier char addr[Maxpath]; //char addr[2*KNAMELEN]; 1313ff48bf5SDavid du Colombier char dir[Maxpath]; //char dir[2*KNAMELEN]; 1327dd7cddfSDavid du Colombier char *buf; 13380ee5cbfSDavid du Colombier int n; 1347dd7cddfSDavid du Colombier char *ptr; 1357dd7cddfSDavid du Colombier Etherrock *er; 1367dd7cddfSDavid du Colombier 1377dd7cddfSDavid du Colombier if(argc < 2) 1387dd7cddfSDavid du Colombier error(Ebadarg); 1397dd7cddfSDavid du Colombier 1403ff48bf5SDavid du Colombier mchan4 = cchan4 = achan = mchan6 = cchan6 = nil; 1417dd7cddfSDavid du Colombier buf = nil; 1427dd7cddfSDavid du Colombier if(waserror()){ 1433ff48bf5SDavid du Colombier if(mchan4 != nil) 1443ff48bf5SDavid du Colombier cclose(mchan4); 1453ff48bf5SDavid du Colombier if(cchan4 != nil) 1463ff48bf5SDavid du Colombier cclose(cchan4); 1477dd7cddfSDavid du Colombier if(achan != nil) 1487dd7cddfSDavid du Colombier cclose(achan); 1493ff48bf5SDavid du Colombier if(mchan6 != nil) 1503ff48bf5SDavid du Colombier cclose(mchan6); 1513ff48bf5SDavid du Colombier if(cchan6 != nil) 1523ff48bf5SDavid du Colombier cclose(cchan6); 1537dd7cddfSDavid du Colombier if(buf != nil) 1547dd7cddfSDavid du Colombier free(buf); 1557dd7cddfSDavid du Colombier nexterror(); 1567dd7cddfSDavid du Colombier } 1577dd7cddfSDavid du Colombier 1587dd7cddfSDavid du Colombier /* 1593e76a0ddSDavid du Colombier * open ipv4 converstation 1607dd7cddfSDavid du Colombier * 1617dd7cddfSDavid du Colombier * the dial will fail if the type is already open on 1627dd7cddfSDavid du Colombier * this device. 1637dd7cddfSDavid du Colombier */ 1647dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x800", argv[2]); 1653ff48bf5SDavid du Colombier mchan4 = chandial(addr, nil, dir, &cchan4); 1663ff48bf5SDavid du Colombier 1673ff48bf5SDavid du Colombier /* 1683ff48bf5SDavid du Colombier * make it non-blocking 1693ff48bf5SDavid du Colombier */ 1703ff48bf5SDavid du Colombier devtab[cchan4->type]->write(cchan4, nbmsg, strlen(nbmsg), 0); 1717dd7cddfSDavid du Colombier 1727dd7cddfSDavid du Colombier /* 1733f695129SDavid du Colombier * get mac address and speed 1747dd7cddfSDavid du Colombier */ 1753432ceaeSDavid du Colombier snprint(addr, sizeof(addr), "%s/stats", argv[2]); 1767dd7cddfSDavid du Colombier buf = smalloc(512); 1773ff48bf5SDavid du Colombier schan = namec(addr, Aopen, OREAD, 0); 1783ff48bf5SDavid du Colombier if(waserror()){ 1793ff48bf5SDavid du Colombier cclose(schan); 1803ff48bf5SDavid du Colombier nexterror(); 1813ff48bf5SDavid du Colombier } 1823ff48bf5SDavid du Colombier n = devtab[schan->type]->read(schan, buf, 511, 0); 1833ff48bf5SDavid du Colombier cclose(schan); 1843ff48bf5SDavid du Colombier poperror(); 1857dd7cddfSDavid du Colombier buf[n] = 0; 1867dd7cddfSDavid du Colombier 1877dd7cddfSDavid du Colombier ptr = strstr(buf, "addr: "); 1887dd7cddfSDavid du Colombier if(!ptr) 1897dd7cddfSDavid du Colombier error(Eio); 1907dd7cddfSDavid du Colombier ptr += 6; 1917dd7cddfSDavid du Colombier parsemac(ifc->mac, ptr, 6); 1927dd7cddfSDavid du Colombier 1933f695129SDavid du Colombier ptr = strstr(buf, "mbps: "); 1943f695129SDavid du Colombier if(ptr){ 1953f695129SDavid du Colombier ptr += 6; 1963f695129SDavid du Colombier ifc->mbps = atoi(ptr); 1973f695129SDavid du Colombier } else 1983f695129SDavid du Colombier ifc->mbps = 100; 1993f695129SDavid du Colombier 2007dd7cddfSDavid du Colombier /* 2017dd7cddfSDavid du Colombier * open arp conversation 2027dd7cddfSDavid du Colombier */ 2037dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x806", argv[2]); 20480ee5cbfSDavid du Colombier achan = chandial(addr, nil, nil, nil); 2057dd7cddfSDavid du Colombier 2063ff48bf5SDavid du Colombier /* 2073e76a0ddSDavid du Colombier * open ipv6 conversation 2083ff48bf5SDavid du Colombier * 2093ff48bf5SDavid du Colombier * the dial will fail if the type is already open on 2103ff48bf5SDavid du Colombier * this device. 2113ff48bf5SDavid du Colombier */ 2123ff48bf5SDavid du Colombier snprint(addr, sizeof(addr), "%s!0x86DD", argv[2]); 2133ff48bf5SDavid du Colombier mchan6 = chandial(addr, nil, dir, &cchan6); 2143ff48bf5SDavid du Colombier 2153ff48bf5SDavid du Colombier /* 2163ff48bf5SDavid du Colombier * make it non-blocking 2173ff48bf5SDavid du Colombier */ 2183ff48bf5SDavid du Colombier devtab[cchan6->type]->write(cchan6, nbmsg, strlen(nbmsg), 0); 2193ff48bf5SDavid du Colombier 2207dd7cddfSDavid du Colombier er = smalloc(sizeof(*er)); 2213ff48bf5SDavid du Colombier er->mchan4 = mchan4; 2223ff48bf5SDavid du Colombier er->cchan4 = cchan4; 2237dd7cddfSDavid du Colombier er->achan = achan; 2243ff48bf5SDavid du Colombier er->mchan6 = mchan6; 2253ff48bf5SDavid du Colombier er->cchan6 = cchan6; 2267dd7cddfSDavid du Colombier er->f = ifc->conv->p->f; 2277dd7cddfSDavid du Colombier ifc->arg = er; 2287dd7cddfSDavid du Colombier 2297dd7cddfSDavid du Colombier free(buf); 2307dd7cddfSDavid du Colombier poperror(); 2317dd7cddfSDavid du Colombier 2323ff48bf5SDavid du Colombier kproc("etherread4", etherread4, ifc); 2337dd7cddfSDavid du Colombier kproc("recvarpproc", recvarpproc, ifc); 2343ff48bf5SDavid du Colombier kproc("etherread6", etherread6, ifc); 2357dd7cddfSDavid du Colombier } 2367dd7cddfSDavid du Colombier 2377dd7cddfSDavid du Colombier /* 2387dd7cddfSDavid du Colombier * called with ifc wlock'd 2397dd7cddfSDavid du Colombier */ 2407dd7cddfSDavid du Colombier static void 2417dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc) 2427dd7cddfSDavid du Colombier { 2437dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 2447dd7cddfSDavid du Colombier 2453ff48bf5SDavid du Colombier if(er->read4p) 2463ff48bf5SDavid du Colombier postnote(er->read4p, 1, "unbind", 0); 2473ff48bf5SDavid du Colombier if(er->read6p) 2483ff48bf5SDavid du Colombier postnote(er->read6p, 1, "unbind", 0); 2497dd7cddfSDavid du Colombier if(er->arpp) 2507dd7cddfSDavid du Colombier postnote(er->arpp, 1, "unbind", 0); 2517dd7cddfSDavid du Colombier 2527dd7cddfSDavid du Colombier /* wait for readers to die */ 2533ff48bf5SDavid du Colombier while(er->arpp != 0 || er->read4p != 0 || er->read6p != 0) 2547dd7cddfSDavid du Colombier tsleep(&up->sleep, return0, 0, 300); 2557dd7cddfSDavid du Colombier 2563ff48bf5SDavid du Colombier if(er->mchan4 != nil) 2573ff48bf5SDavid du Colombier cclose(er->mchan4); 2587dd7cddfSDavid du Colombier if(er->achan != nil) 2597dd7cddfSDavid du Colombier cclose(er->achan); 2603ff48bf5SDavid du Colombier if(er->cchan4 != nil) 2613ff48bf5SDavid du Colombier cclose(er->cchan4); 2623ff48bf5SDavid du Colombier if(er->mchan6 != nil) 2633ff48bf5SDavid du Colombier cclose(er->mchan6); 2643ff48bf5SDavid du Colombier if(er->cchan6 != nil) 2653ff48bf5SDavid du Colombier cclose(er->cchan6); 2667dd7cddfSDavid du Colombier 2677dd7cddfSDavid du Colombier free(er); 2687dd7cddfSDavid du Colombier } 2697dd7cddfSDavid du Colombier 2707dd7cddfSDavid du Colombier /* 2717dd7cddfSDavid du Colombier * called by ipoput with a single block to write with ifc rlock'd 2727dd7cddfSDavid du Colombier */ 2737dd7cddfSDavid du Colombier static void 2747dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip) 2757dd7cddfSDavid du Colombier { 2767dd7cddfSDavid du Colombier Etherhdr *eh; 2777dd7cddfSDavid du Colombier Arpent *a; 2787dd7cddfSDavid du Colombier uchar mac[6]; 2797dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 2807dd7cddfSDavid du Colombier 2817dd7cddfSDavid du Colombier /* get mac address of destination */ 2823ff48bf5SDavid du Colombier a = arpget(er->f->arp, bp, version, ifc, ip, mac); 2837dd7cddfSDavid du Colombier if(a){ 2847dd7cddfSDavid du Colombier /* check for broadcast or multicast */ 28559cc4ca5SDavid du Colombier bp = multicastarp(er->f, a, ifc->m, mac); 2867dd7cddfSDavid du Colombier if(bp==nil){ 2873ff48bf5SDavid du Colombier switch(version){ 2883ff48bf5SDavid du Colombier case V4: 2897dd7cddfSDavid du Colombier sendarp(ifc, a); 2903ff48bf5SDavid du Colombier break; 2913ff48bf5SDavid du Colombier case V6: 2923ff48bf5SDavid du Colombier resolveaddr6(ifc, a); 2933ff48bf5SDavid du Colombier break; 2943ff48bf5SDavid du Colombier default: 2953ff48bf5SDavid du Colombier panic("etherbwrite: version %d", version); 2963ff48bf5SDavid du Colombier } 2977dd7cddfSDavid du Colombier return; 2987dd7cddfSDavid du Colombier } 2997dd7cddfSDavid du Colombier } 3007dd7cddfSDavid du Colombier 3017dd7cddfSDavid du Colombier /* make it a single block with space for the ether header */ 3027dd7cddfSDavid du Colombier bp = padblock(bp, ifc->m->hsize); 3037dd7cddfSDavid du Colombier if(bp->next) 3047dd7cddfSDavid du Colombier bp = concatblock(bp); 3053f695129SDavid du Colombier if(BLEN(bp) < ifc->mintu) 3063f695129SDavid du Colombier bp = adjustblock(bp, ifc->mintu); 3077dd7cddfSDavid du Colombier eh = (Etherhdr*)bp->rp; 3087dd7cddfSDavid du Colombier 3097dd7cddfSDavid du Colombier /* copy in mac addresses and ether type */ 3107dd7cddfSDavid du Colombier memmove(eh->s, ifc->mac, sizeof(eh->s)); 3117dd7cddfSDavid du Colombier memmove(eh->d, mac, sizeof(eh->d)); 3123ff48bf5SDavid du Colombier 3137dd7cddfSDavid du Colombier switch(version){ 3147dd7cddfSDavid du Colombier case V4: 3157dd7cddfSDavid du Colombier eh->t[0] = 0x08; 3167dd7cddfSDavid du Colombier eh->t[1] = 0x00; 3173ff48bf5SDavid du Colombier devtab[er->mchan4->type]->bwrite(er->mchan4, bp, 0); 3187dd7cddfSDavid du Colombier break; 3197dd7cddfSDavid du Colombier case V6: 3207dd7cddfSDavid du Colombier eh->t[0] = 0x86; 3217dd7cddfSDavid du Colombier eh->t[1] = 0xDD; 3223ff48bf5SDavid du Colombier devtab[er->mchan6->type]->bwrite(er->mchan6, bp, 0); 3237dd7cddfSDavid du Colombier break; 3243ff48bf5SDavid du Colombier default: 3253ff48bf5SDavid du Colombier panic("etherbwrite2: version %d", version); 3267dd7cddfSDavid du Colombier } 3277dd7cddfSDavid du Colombier ifc->out++; 3287dd7cddfSDavid du Colombier } 3297dd7cddfSDavid du Colombier 3303ff48bf5SDavid du Colombier 3317dd7cddfSDavid du Colombier /* 3327dd7cddfSDavid du Colombier * process to read from the ethernet 3337dd7cddfSDavid du Colombier */ 3347dd7cddfSDavid du Colombier static void 3353ff48bf5SDavid du Colombier etherread4(void *a) 3367dd7cddfSDavid du Colombier { 3377dd7cddfSDavid du Colombier Ipifc *ifc; 3387dd7cddfSDavid du Colombier Block *bp; 3397dd7cddfSDavid du Colombier Etherrock *er; 3407dd7cddfSDavid du Colombier 3417dd7cddfSDavid du Colombier ifc = a; 3427dd7cddfSDavid du Colombier er = ifc->arg; 3433ff48bf5SDavid du Colombier er->read4p = up; /* hide identity under a rock for unbind */ 3447dd7cddfSDavid du Colombier if(waserror()){ 3453ff48bf5SDavid du Colombier er->read4p = 0; 3467dd7cddfSDavid du Colombier pexit("hangup", 1); 3477dd7cddfSDavid du Colombier } 3487dd7cddfSDavid du Colombier for(;;){ 3493f695129SDavid du Colombier bp = devtab[er->mchan4->type]->bread(er->mchan4, ifc->maxtu, 0); 3507dd7cddfSDavid du Colombier if(!canrlock(ifc)){ 3517dd7cddfSDavid du Colombier freeb(bp); 3527dd7cddfSDavid du Colombier continue; 3537dd7cddfSDavid du Colombier } 3547dd7cddfSDavid du Colombier if(waserror()){ 3557dd7cddfSDavid du Colombier runlock(ifc); 3567dd7cddfSDavid du Colombier nexterror(); 3577dd7cddfSDavid du Colombier } 3587dd7cddfSDavid du Colombier ifc->in++; 3597dd7cddfSDavid du Colombier bp->rp += ifc->m->hsize; 3607dd7cddfSDavid du Colombier if(ifc->lifc == nil) 3617dd7cddfSDavid du Colombier freeb(bp); 3627dd7cddfSDavid du Colombier else 3633ff48bf5SDavid du Colombier ipiput4(er->f, ifc, bp); 3643ff48bf5SDavid du Colombier runlock(ifc); 3653ff48bf5SDavid du Colombier poperror(); 3663ff48bf5SDavid du Colombier } 3673ff48bf5SDavid du Colombier } 3683ff48bf5SDavid du Colombier 3693ff48bf5SDavid du Colombier 3703ff48bf5SDavid du Colombier /* 3713ff48bf5SDavid du Colombier * process to read from the ethernet, IPv6 3723ff48bf5SDavid du Colombier */ 3733ff48bf5SDavid du Colombier static void 3743ff48bf5SDavid du Colombier etherread6(void *a) 3753ff48bf5SDavid du Colombier { 3763ff48bf5SDavid du Colombier Ipifc *ifc; 3773ff48bf5SDavid du Colombier Block *bp; 3783ff48bf5SDavid du Colombier Etherrock *er; 3793ff48bf5SDavid du Colombier 3803ff48bf5SDavid du Colombier ifc = a; 3813ff48bf5SDavid du Colombier er = ifc->arg; 3823ff48bf5SDavid du Colombier er->read6p = up; /* hide identity under a rock for unbind */ 3833ff48bf5SDavid du Colombier if(waserror()){ 3843ff48bf5SDavid du Colombier er->read6p = 0; 3853ff48bf5SDavid du Colombier pexit("hangup", 1); 3863ff48bf5SDavid du Colombier } 3873ff48bf5SDavid du Colombier for(;;){ 3883f695129SDavid du Colombier bp = devtab[er->mchan6->type]->bread(er->mchan6, ifc->maxtu, 0); 3893ff48bf5SDavid du Colombier if(!canrlock(ifc)){ 3903ff48bf5SDavid du Colombier freeb(bp); 3913ff48bf5SDavid du Colombier continue; 3923ff48bf5SDavid du Colombier } 3933ff48bf5SDavid du Colombier if(waserror()){ 3943ff48bf5SDavid du Colombier runlock(ifc); 3953ff48bf5SDavid du Colombier nexterror(); 3963ff48bf5SDavid du Colombier } 3973ff48bf5SDavid du Colombier ifc->in++; 3983ff48bf5SDavid du Colombier bp->rp += ifc->m->hsize; 3993ff48bf5SDavid du Colombier if(ifc->lifc == nil) 4003ff48bf5SDavid du Colombier freeb(bp); 4013ff48bf5SDavid du Colombier else 4023ff48bf5SDavid du Colombier ipiput6(er->f, ifc, bp); 4037dd7cddfSDavid du Colombier runlock(ifc); 4047dd7cddfSDavid du Colombier poperror(); 4057dd7cddfSDavid du Colombier } 4067dd7cddfSDavid du Colombier } 4077dd7cddfSDavid du Colombier 4087dd7cddfSDavid du Colombier static void 4097dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *) 4107dd7cddfSDavid du Colombier { 4117dd7cddfSDavid du Colombier uchar mac[6]; 4127dd7cddfSDavid du Colombier char buf[64]; 4137dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 4143ff48bf5SDavid du Colombier int version; 4157dd7cddfSDavid du Colombier 4163ff48bf5SDavid du Colombier version = multicastea(mac, a); 4177dd7cddfSDavid du Colombier sprint(buf, "addmulti %E", mac); 4183ff48bf5SDavid du Colombier switch(version){ 4193ff48bf5SDavid du Colombier case V4: 4203ff48bf5SDavid du Colombier devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0); 4213ff48bf5SDavid du Colombier break; 4223ff48bf5SDavid du Colombier case V6: 4233ff48bf5SDavid du Colombier devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0); 4243ff48bf5SDavid du Colombier break; 4253ff48bf5SDavid du Colombier default: 4263ff48bf5SDavid du Colombier panic("etheraddmulti: version %d", version); 4273ff48bf5SDavid du Colombier } 4287dd7cddfSDavid du Colombier } 4297dd7cddfSDavid du Colombier 4307dd7cddfSDavid du Colombier static void 4317dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *) 4327dd7cddfSDavid du Colombier { 4337dd7cddfSDavid du Colombier uchar mac[6]; 4347dd7cddfSDavid du Colombier char buf[64]; 4357dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 4363ff48bf5SDavid du Colombier int version; 4377dd7cddfSDavid du Colombier 4383ff48bf5SDavid du Colombier version = multicastea(mac, a); 4397dd7cddfSDavid du Colombier sprint(buf, "remmulti %E", mac); 4403ff48bf5SDavid du Colombier switch(version){ 4413ff48bf5SDavid du Colombier case V4: 4423ff48bf5SDavid du Colombier devtab[er->cchan4->type]->write(er->cchan4, buf, strlen(buf), 0); 4433ff48bf5SDavid du Colombier break; 4443ff48bf5SDavid du Colombier case V6: 4453ff48bf5SDavid du Colombier devtab[er->cchan6->type]->write(er->cchan6, buf, strlen(buf), 0); 4463ff48bf5SDavid du Colombier break; 4473ff48bf5SDavid du Colombier default: 4483ff48bf5SDavid du Colombier panic("etherremmulti: version %d", version); 4493ff48bf5SDavid du Colombier } 4507dd7cddfSDavid du Colombier } 4517dd7cddfSDavid du Colombier 4527dd7cddfSDavid du Colombier /* 4537dd7cddfSDavid du Colombier * send an ethernet arp 4547dd7cddfSDavid du Colombier * (only v4, v6 uses the neighbor discovery, rfc1970) 4557dd7cddfSDavid du Colombier */ 4567dd7cddfSDavid du Colombier static void 4577dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a) 4587dd7cddfSDavid du Colombier { 4597dd7cddfSDavid du Colombier int n; 4607dd7cddfSDavid du Colombier Block *bp; 4617dd7cddfSDavid du Colombier Etherarp *e; 4627dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 4637dd7cddfSDavid du Colombier 4647dd7cddfSDavid du Colombier /* don't do anything if it's been less than a second since the last */ 465a6a9e072SDavid du Colombier if(NOW - a->ctime < 1000){ 4667dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 4677dd7cddfSDavid du Colombier return; 4687dd7cddfSDavid du Colombier } 4697dd7cddfSDavid du Colombier 4707dd7cddfSDavid du Colombier /* remove all but the last message */ 4717dd7cddfSDavid du Colombier while((bp = a->hold) != nil){ 4727dd7cddfSDavid du Colombier if(bp == a->last) 4737dd7cddfSDavid du Colombier break; 4747dd7cddfSDavid du Colombier a->hold = bp->list; 4757dd7cddfSDavid du Colombier freeblist(bp); 4767dd7cddfSDavid du Colombier } 4777dd7cddfSDavid du Colombier 4787dd7cddfSDavid du Colombier /* try to keep it around for a second more */ 479a6a9e072SDavid du Colombier a->ctime = NOW; 4807dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 4817dd7cddfSDavid du Colombier 4827dd7cddfSDavid du Colombier n = sizeof(Etherarp); 4833f695129SDavid du Colombier if(n < a->type->mintu) 4843f695129SDavid du Colombier n = a->type->mintu; 4857dd7cddfSDavid du Colombier bp = allocb(n); 4867dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 4877dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 4887dd7cddfSDavid du Colombier memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa)); 4897dd7cddfSDavid du Colombier ipv4local(ifc, e->spa); 4907dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 4917dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 4927dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 4937dd7cddfSDavid du Colombier 4947dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 4957dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 4963ff48bf5SDavid du Colombier hnputs(e->pro, ETIP4); 4977dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 4987dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 4997dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 5007dd7cddfSDavid du Colombier bp->wp += n; 5017dd7cddfSDavid du Colombier 502*db7ae703SDavid du Colombier devtab[er->achan->type]->bwrite(er->achan, bp, 0); 5037dd7cddfSDavid du Colombier } 5047dd7cddfSDavid du Colombier 5053ff48bf5SDavid du Colombier static void 5063ff48bf5SDavid du Colombier resolveaddr6(Ipifc *ifc, Arpent *a) 5073ff48bf5SDavid du Colombier { 5083ff48bf5SDavid du Colombier int sflag; 5093ff48bf5SDavid du Colombier Block *bp; 5103ff48bf5SDavid du Colombier Etherrock *er = ifc->arg; 5113ff48bf5SDavid du Colombier uchar ipsrc[IPaddrlen]; 5123ff48bf5SDavid du Colombier 5133ff48bf5SDavid du Colombier /* don't do anything if it's been less than a second since the last */ 514a6a9e072SDavid du Colombier if(NOW - a->ctime < ReTransTimer){ 5153ff48bf5SDavid du Colombier arprelease(er->f->arp, a); 5163ff48bf5SDavid du Colombier return; 5173ff48bf5SDavid du Colombier } 5183ff48bf5SDavid du Colombier 5193ff48bf5SDavid du Colombier /* remove all but the last message */ 5203ff48bf5SDavid du Colombier while((bp = a->hold) != nil){ 5213ff48bf5SDavid du Colombier if(bp == a->last) 5223ff48bf5SDavid du Colombier break; 5233ff48bf5SDavid du Colombier a->hold = bp->list; 5243ff48bf5SDavid du Colombier freeblist(bp); 5253ff48bf5SDavid du Colombier } 5263ff48bf5SDavid du Colombier 5273ff48bf5SDavid du Colombier /* try to keep it around for a second more */ 528a6a9e072SDavid du Colombier a->ctime = NOW; 529a6a9e072SDavid du Colombier a->rtime = NOW + ReTransTimer; 5303ff48bf5SDavid du Colombier if(a->rxtsrem <= 0) { 5313ff48bf5SDavid du Colombier arprelease(er->f->arp, a); 5323ff48bf5SDavid du Colombier return; 5333ff48bf5SDavid du Colombier } 5343ff48bf5SDavid du Colombier 5353ff48bf5SDavid du Colombier a->rxtsrem--; 5363ff48bf5SDavid du Colombier arprelease(er->f->arp, a); 5373ff48bf5SDavid du Colombier 5383ff48bf5SDavid du Colombier if(sflag = ipv6anylocal(ifc, ipsrc)) 5393ff48bf5SDavid du Colombier icmpns(er->f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 5403ff48bf5SDavid du Colombier } 5413ff48bf5SDavid du Colombier 5427dd7cddfSDavid du Colombier /* 5437dd7cddfSDavid du Colombier * send a gratuitous arp to refresh arp caches 5447dd7cddfSDavid du Colombier */ 5457dd7cddfSDavid du Colombier static void 5467dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip) 5477dd7cddfSDavid du Colombier { 5487dd7cddfSDavid du Colombier int n; 5497dd7cddfSDavid du Colombier Block *bp; 5507dd7cddfSDavid du Colombier Etherarp *e; 5517dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 5527dd7cddfSDavid du Colombier 5537dd7cddfSDavid du Colombier /* don't arp for our initial non address */ 5547dd7cddfSDavid du Colombier if(ipcmp(ip, IPnoaddr) == 0) 5557dd7cddfSDavid du Colombier return; 5567dd7cddfSDavid du Colombier 5577dd7cddfSDavid du Colombier n = sizeof(Etherarp); 5583f695129SDavid du Colombier if(n < ifc->m->mintu) 5593f695129SDavid du Colombier n = ifc->m->mintu; 5607dd7cddfSDavid du Colombier bp = allocb(n); 5617dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 5627dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 5637dd7cddfSDavid du Colombier memmove(e->tpa, ip+IPv4off, sizeof(e->tpa)); 5647dd7cddfSDavid du Colombier memmove(e->spa, ip+IPv4off, sizeof(e->spa)); 5657dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 5667dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 5677dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 5687dd7cddfSDavid du Colombier 5697dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 5707dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 5713ff48bf5SDavid du Colombier hnputs(e->pro, ETIP4); 5727dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 5737dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 5747dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 5757dd7cddfSDavid du Colombier bp->wp += n; 5767dd7cddfSDavid du Colombier 577*db7ae703SDavid du Colombier devtab[er->achan->type]->bwrite(er->achan, bp, 0); 5787dd7cddfSDavid du Colombier } 5797dd7cddfSDavid du Colombier 5807dd7cddfSDavid du Colombier static void 5817dd7cddfSDavid du Colombier recvarp(Ipifc *ifc) 5827dd7cddfSDavid du Colombier { 5837dd7cddfSDavid du Colombier int n; 5847dd7cddfSDavid du Colombier Block *ebp, *rbp; 5857dd7cddfSDavid du Colombier Etherarp *e, *r; 5867dd7cddfSDavid du Colombier uchar ip[IPaddrlen]; 587ef9eff0bSDavid du Colombier static uchar eprinted[4]; 5887dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 5897dd7cddfSDavid du Colombier 5903f695129SDavid du Colombier ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxtu, 0); 591*db7ae703SDavid du Colombier if(ebp == nil) 5927dd7cddfSDavid du Colombier return; 5937dd7cddfSDavid du Colombier 5947dd7cddfSDavid du Colombier e = (Etherarp*)ebp->rp; 5957dd7cddfSDavid du Colombier switch(nhgets(e->op)) { 5967dd7cddfSDavid du Colombier default: 5977dd7cddfSDavid du Colombier break; 5987dd7cddfSDavid du Colombier 5997dd7cddfSDavid du Colombier case ARPREPLY: 6003ff48bf5SDavid du Colombier /* check for machine using my ip address */ 6013ff48bf5SDavid du Colombier v4tov6(ip, e->spa); 6029a747e4fSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 6039a747e4fSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ 6049a747e4fSDavid du Colombier print("arprep: 0x%E/0x%E also has ip addr %V\n", 6059a747e4fSDavid du Colombier e->s, e->sha, e->spa); 6069a747e4fSDavid du Colombier break; 6079a747e4fSDavid du Colombier } 6089a747e4fSDavid du Colombier } 6093ff48bf5SDavid du Colombier 6105d82c6aeSDavid du Colombier /* make sure we're not entering broadcast addresses */ 6115d82c6aeSDavid du Colombier if(ipcmp(ip, ipbroadcast) == 0 || 6125d82c6aeSDavid du Colombier !memcmp(e->sha, etherbroadcast, sizeof(e->sha))){ 6135d82c6aeSDavid du Colombier print("arprep: 0x%E/0x%E cannot register broadcast address %I\n", 6145d82c6aeSDavid du Colombier e->s, e->sha, e->spa); 6155d82c6aeSDavid du Colombier break; 6165d82c6aeSDavid du Colombier } 6175d82c6aeSDavid du Colombier 6187dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0); 6197dd7cddfSDavid du Colombier break; 6207dd7cddfSDavid du Colombier 6217dd7cddfSDavid du Colombier case ARPREQUEST: 6227dd7cddfSDavid du Colombier /* don't answer arps till we know who we are */ 6237dd7cddfSDavid du Colombier if(ifc->lifc == 0) 6247dd7cddfSDavid du Colombier break; 6257dd7cddfSDavid du Colombier 6263ff48bf5SDavid du Colombier /* check for machine using my ip or ether address */ 6277dd7cddfSDavid du Colombier v4tov6(ip, e->spa); 6287dd7cddfSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 629ef9eff0bSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0){ 630ef9eff0bSDavid du Colombier if (memcmp(eprinted, e->spa, sizeof(e->spa))){ 631ef9eff0bSDavid du Colombier /* print only once */ 6323ff48bf5SDavid du Colombier print("arpreq: 0x%E also has ip addr %V\n", e->sha, e->spa); 633ef9eff0bSDavid du Colombier memmove(eprinted, e->spa, sizeof(e->spa)); 634ef9eff0bSDavid du Colombier } 635ef9eff0bSDavid du Colombier } 6367dd7cddfSDavid du Colombier } else { 6377dd7cddfSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){ 6383ff48bf5SDavid du Colombier print("arpreq: %V also has ether addr %E\n", e->spa, e->sha); 6397dd7cddfSDavid du Colombier break; 6407dd7cddfSDavid du Colombier } 6417dd7cddfSDavid du Colombier } 6427dd7cddfSDavid du Colombier 6437dd7cddfSDavid du Colombier /* refresh what we know about sender */ 6447dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1); 6457dd7cddfSDavid du Colombier 6467dd7cddfSDavid du Colombier /* answer only requests for our address or systems we're proxying for */ 6477dd7cddfSDavid du Colombier v4tov6(ip, e->tpa); 6487dd7cddfSDavid du Colombier if(!iplocalonifc(ifc, ip)) 6497dd7cddfSDavid du Colombier if(!ipproxyifc(er->f, ifc, ip)) 6507dd7cddfSDavid du Colombier break; 6517dd7cddfSDavid du Colombier 6527dd7cddfSDavid du Colombier n = sizeof(Etherarp); 6533f695129SDavid du Colombier if(n < ifc->mintu) 6543f695129SDavid du Colombier n = ifc->mintu; 6557dd7cddfSDavid du Colombier rbp = allocb(n); 6567dd7cddfSDavid du Colombier r = (Etherarp*)rbp->rp; 6577dd7cddfSDavid du Colombier memset(r, 0, sizeof(Etherarp)); 6587dd7cddfSDavid du Colombier hnputs(r->type, ETARP); 6597dd7cddfSDavid du Colombier hnputs(r->hrd, 1); 6603ff48bf5SDavid du Colombier hnputs(r->pro, ETIP4); 6617dd7cddfSDavid du Colombier r->hln = sizeof(r->sha); 6627dd7cddfSDavid du Colombier r->pln = sizeof(r->spa); 6637dd7cddfSDavid du Colombier hnputs(r->op, ARPREPLY); 6647dd7cddfSDavid du Colombier memmove(r->tha, e->sha, sizeof(r->tha)); 6657dd7cddfSDavid du Colombier memmove(r->tpa, e->spa, sizeof(r->tpa)); 6667dd7cddfSDavid du Colombier memmove(r->sha, ifc->mac, sizeof(r->sha)); 6677dd7cddfSDavid du Colombier memmove(r->spa, e->tpa, sizeof(r->spa)); 6687dd7cddfSDavid du Colombier memmove(r->d, e->sha, sizeof(r->d)); 6697dd7cddfSDavid du Colombier memmove(r->s, ifc->mac, sizeof(r->s)); 6707dd7cddfSDavid du Colombier rbp->wp += n; 6717dd7cddfSDavid du Colombier 672*db7ae703SDavid du Colombier devtab[er->achan->type]->bwrite(er->achan, rbp, 0); 6737dd7cddfSDavid du Colombier } 6747dd7cddfSDavid du Colombier freeb(ebp); 6757dd7cddfSDavid du Colombier } 6767dd7cddfSDavid du Colombier 6777dd7cddfSDavid du Colombier static void 6787dd7cddfSDavid du Colombier recvarpproc(void *v) 6797dd7cddfSDavid du Colombier { 6807dd7cddfSDavid du Colombier Ipifc *ifc = v; 6817dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 6827dd7cddfSDavid du Colombier 6837dd7cddfSDavid du Colombier er->arpp = up; 6847dd7cddfSDavid du Colombier if(waserror()){ 6857dd7cddfSDavid du Colombier er->arpp = 0; 6867dd7cddfSDavid du Colombier pexit("hangup", 1); 6877dd7cddfSDavid du Colombier } 6887dd7cddfSDavid du Colombier for(;;) 6897dd7cddfSDavid du Colombier recvarp(ifc); 6907dd7cddfSDavid du Colombier } 6917dd7cddfSDavid du Colombier 6927dd7cddfSDavid du Colombier static int 6937dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip) 6947dd7cddfSDavid du Colombier { 6957dd7cddfSDavid du Colombier int x; 6967dd7cddfSDavid du Colombier 6977dd7cddfSDavid du Colombier switch(x = ipismulticast(ip)){ 6987dd7cddfSDavid du Colombier case V4: 6997dd7cddfSDavid du Colombier ea[0] = 0x01; 7007dd7cddfSDavid du Colombier ea[1] = 0x00; 7017dd7cddfSDavid du Colombier ea[2] = 0x5e; 7027dd7cddfSDavid du Colombier ea[3] = ip[13] & 0x7f; 7037dd7cddfSDavid du Colombier ea[4] = ip[14]; 7047dd7cddfSDavid du Colombier ea[5] = ip[15]; 7057dd7cddfSDavid du Colombier break; 7067dd7cddfSDavid du Colombier case V6: 7077dd7cddfSDavid du Colombier ea[0] = 0x33; 7087dd7cddfSDavid du Colombier ea[1] = 0x33; 7097dd7cddfSDavid du Colombier ea[2] = ip[12]; 7107dd7cddfSDavid du Colombier ea[3] = ip[13]; 7117dd7cddfSDavid du Colombier ea[4] = ip[14]; 7127dd7cddfSDavid du Colombier ea[5] = ip[15]; 7137dd7cddfSDavid du Colombier break; 7147dd7cddfSDavid du Colombier } 7157dd7cddfSDavid du Colombier return x; 7167dd7cddfSDavid du Colombier } 7177dd7cddfSDavid du Colombier 7187dd7cddfSDavid du Colombier /* 7197dd7cddfSDavid du Colombier * fill in an arp entry for broadcast or multicast 7203ff48bf5SDavid du Colombier * addresses. Return the first queued packet for the 7213ff48bf5SDavid du Colombier * IP address. 7227dd7cddfSDavid du Colombier */ 7237dd7cddfSDavid du Colombier static Block* 72459cc4ca5SDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac) 7257dd7cddfSDavid du Colombier { 7267dd7cddfSDavid du Colombier /* is it broadcast? */ 7277dd7cddfSDavid du Colombier switch(ipforme(f, a->ip)){ 7287dd7cddfSDavid du Colombier case Runi: 7297dd7cddfSDavid du Colombier return nil; 7307dd7cddfSDavid du Colombier case Rbcast: 7317dd7cddfSDavid du Colombier memset(mac, 0xff, 6); 73259cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac); 7337dd7cddfSDavid du Colombier default: 7347dd7cddfSDavid du Colombier break; 7357dd7cddfSDavid du Colombier } 7367dd7cddfSDavid du Colombier 7377dd7cddfSDavid du Colombier /* if multicast, fill in mac */ 7387dd7cddfSDavid du Colombier switch(multicastea(mac, a->ip)){ 7397dd7cddfSDavid du Colombier case V4: 7407dd7cddfSDavid du Colombier case V6: 74159cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac); 7427dd7cddfSDavid du Colombier } 7437dd7cddfSDavid du Colombier 7447dd7cddfSDavid du Colombier /* let arp take care of it */ 7457dd7cddfSDavid du Colombier return nil; 7467dd7cddfSDavid du Colombier } 7477dd7cddfSDavid du Colombier 7487dd7cddfSDavid du Colombier void 7497dd7cddfSDavid du Colombier ethermediumlink(void) 7507dd7cddfSDavid du Colombier { 7517dd7cddfSDavid du Colombier addipmedium(ðermedium); 75259cc4ca5SDavid du Colombier addipmedium(&gbemedium); 7537dd7cddfSDavid du Colombier } 7543ff48bf5SDavid du Colombier 7553ff48bf5SDavid du Colombier 7563ff48bf5SDavid du Colombier static void 7573ff48bf5SDavid du Colombier etherpref2addr(uchar *pref, uchar *ea) 7583ff48bf5SDavid du Colombier { 7593ff48bf5SDavid du Colombier pref[8] = ea[0] | 0x2; 7603ff48bf5SDavid du Colombier pref[9] = ea[1]; 7613ff48bf5SDavid du Colombier pref[10] = ea[2]; 7623ff48bf5SDavid du Colombier pref[11] = 0xFF; 7633ff48bf5SDavid du Colombier pref[12] = 0xFE; 7643ff48bf5SDavid du Colombier pref[13] = ea[3]; 7653ff48bf5SDavid du Colombier pref[14] = ea[4]; 7663ff48bf5SDavid du Colombier pref[15] = ea[5]; 7673ff48bf5SDavid du Colombier } 768