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" 97dd7cddfSDavid du Colombier 107dd7cddfSDavid du Colombier typedef struct Etherhdr Etherhdr; 117dd7cddfSDavid du Colombier struct Etherhdr 127dd7cddfSDavid du Colombier { 137dd7cddfSDavid du Colombier uchar d[6]; 147dd7cddfSDavid du Colombier uchar s[6]; 157dd7cddfSDavid du Colombier uchar t[2]; 167dd7cddfSDavid du Colombier }; 177dd7cddfSDavid du Colombier 187dd7cddfSDavid du Colombier static void etherread(void *a); 197dd7cddfSDavid du Colombier static void etherbind(Ipifc *ifc, int argc, char **argv); 207dd7cddfSDavid du Colombier static void etherunbind(Ipifc *ifc); 217dd7cddfSDavid du Colombier static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 227dd7cddfSDavid du Colombier static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia); 237dd7cddfSDavid du Colombier static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia); 2459cc4ca5SDavid du Colombier static Block* multicastarp(Fs *f, Arpent *a, Medium*, uchar *mac); 257dd7cddfSDavid du Colombier static void sendarp(Ipifc *ifc, Arpent *a); 267dd7cddfSDavid du Colombier static void sendgarp(Ipifc *ifc, uchar*); 277dd7cddfSDavid du Colombier static int multicastea(uchar *ea, uchar *ip); 287dd7cddfSDavid du Colombier static void recvarpproc(void*); 297dd7cddfSDavid du Colombier 307dd7cddfSDavid du Colombier Medium ethermedium = 317dd7cddfSDavid du Colombier { 327dd7cddfSDavid du Colombier .name= "ether", 337dd7cddfSDavid du Colombier .hsize= 14, 347dd7cddfSDavid du Colombier .minmtu= 60, 357dd7cddfSDavid du Colombier .maxmtu= 1514, 367dd7cddfSDavid du Colombier .maclen= 6, 377dd7cddfSDavid du Colombier .bind= etherbind, 387dd7cddfSDavid du Colombier .unbind= etherunbind, 397dd7cddfSDavid du Colombier .bwrite= etherbwrite, 407dd7cddfSDavid du Colombier .addmulti= etheraddmulti, 417dd7cddfSDavid du Colombier .remmulti= etherremmulti, 427dd7cddfSDavid du Colombier .ares= arpenter, 437dd7cddfSDavid du Colombier .areg= sendgarp, 447dd7cddfSDavid du Colombier }; 457dd7cddfSDavid du Colombier 4659cc4ca5SDavid du Colombier Medium gbemedium = 4759cc4ca5SDavid du Colombier { 4859cc4ca5SDavid du Colombier .name= "gbe", 4959cc4ca5SDavid du Colombier .hsize= 14, 5059cc4ca5SDavid du Colombier .minmtu= 60, 5159cc4ca5SDavid du Colombier .maxmtu= 9014, 5259cc4ca5SDavid du Colombier .maclen= 6, 5359cc4ca5SDavid du Colombier .bind= etherbind, 5459cc4ca5SDavid du Colombier .unbind= etherunbind, 5559cc4ca5SDavid du Colombier .bwrite= etherbwrite, 5659cc4ca5SDavid du Colombier .addmulti= etheraddmulti, 5759cc4ca5SDavid du Colombier .remmulti= etherremmulti, 5859cc4ca5SDavid du Colombier .ares= arpenter, 5959cc4ca5SDavid du Colombier .areg= sendgarp, 6059cc4ca5SDavid du Colombier }; 6159cc4ca5SDavid du Colombier 627dd7cddfSDavid du Colombier typedef struct Etherrock Etherrock; 637dd7cddfSDavid du Colombier struct Etherrock 647dd7cddfSDavid du Colombier { 657dd7cddfSDavid du Colombier Fs *f; /* file system we belong to */ 667dd7cddfSDavid du Colombier Proc *arpp; /* arp process */ 677dd7cddfSDavid du Colombier Proc *readp; /* reading process */ 687dd7cddfSDavid du Colombier Chan *mchan; /* Data channel */ 697dd7cddfSDavid du Colombier Chan *achan; /* Arp channel */ 707dd7cddfSDavid du Colombier Chan *cchan; /* Control channel */ 717dd7cddfSDavid du Colombier }; 727dd7cddfSDavid du Colombier 737dd7cddfSDavid du Colombier /* 747dd7cddfSDavid du Colombier * ethernet arp request 757dd7cddfSDavid du Colombier */ 767dd7cddfSDavid du Colombier enum 777dd7cddfSDavid du Colombier { 787dd7cddfSDavid du Colombier ETARP = 0x0806, 797dd7cddfSDavid du Colombier ETIP = 0x0800, 807dd7cddfSDavid du Colombier ARPREQUEST = 1, 817dd7cddfSDavid du Colombier ARPREPLY = 2, 827dd7cddfSDavid du Colombier }; 837dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp; 847dd7cddfSDavid du Colombier struct Etherarp 857dd7cddfSDavid du Colombier { 867dd7cddfSDavid du Colombier uchar d[6]; 877dd7cddfSDavid du Colombier uchar s[6]; 887dd7cddfSDavid du Colombier uchar type[2]; 897dd7cddfSDavid du Colombier uchar hrd[2]; 907dd7cddfSDavid du Colombier uchar pro[2]; 917dd7cddfSDavid du Colombier uchar hln; 927dd7cddfSDavid du Colombier uchar pln; 937dd7cddfSDavid du Colombier uchar op[2]; 947dd7cddfSDavid du Colombier uchar sha[6]; 957dd7cddfSDavid du Colombier uchar spa[4]; 967dd7cddfSDavid du Colombier uchar tha[6]; 977dd7cddfSDavid du Colombier uchar tpa[4]; 987dd7cddfSDavid du Colombier }; 997dd7cddfSDavid du Colombier 1007dd7cddfSDavid du Colombier 1017dd7cddfSDavid du Colombier /* 1027dd7cddfSDavid du Colombier * called to bind an IP ifc to an ethernet device 1037dd7cddfSDavid du Colombier * called with ifc wlock'd 1047dd7cddfSDavid du Colombier */ 1057dd7cddfSDavid du Colombier static void 1067dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv) 1077dd7cddfSDavid du Colombier { 1087dd7cddfSDavid du Colombier Chan *mchan, *cchan, *achan; 1097dd7cddfSDavid du Colombier char addr[2*NAMELEN]; 1107dd7cddfSDavid du Colombier char dir[2*NAMELEN]; 1117dd7cddfSDavid du Colombier char *buf; 112*80ee5cbfSDavid du Colombier int n; 1137dd7cddfSDavid du Colombier char *ptr; 1147dd7cddfSDavid du Colombier Etherrock *er; 1157dd7cddfSDavid du Colombier 1167dd7cddfSDavid du Colombier if(argc < 2) 1177dd7cddfSDavid du Colombier error(Ebadarg); 1187dd7cddfSDavid du Colombier 1197dd7cddfSDavid du Colombier mchan = cchan = achan = nil; 1207dd7cddfSDavid du Colombier buf = nil; 1217dd7cddfSDavid du Colombier if(waserror()){ 1227dd7cddfSDavid du Colombier if(mchan != nil) 1237dd7cddfSDavid du Colombier cclose(mchan); 1247dd7cddfSDavid du Colombier if(cchan != nil) 1257dd7cddfSDavid du Colombier cclose(cchan); 1267dd7cddfSDavid du Colombier if(achan != nil) 1277dd7cddfSDavid du Colombier cclose(achan); 1287dd7cddfSDavid du Colombier if(buf != nil) 1297dd7cddfSDavid du Colombier free(buf); 1307dd7cddfSDavid du Colombier nexterror(); 1317dd7cddfSDavid du Colombier } 1327dd7cddfSDavid du Colombier 1337dd7cddfSDavid du Colombier /* 1347dd7cddfSDavid du Colombier * open ip conversation 1357dd7cddfSDavid du Colombier * 1367dd7cddfSDavid du Colombier * the dial will fail if the type is already open on 1377dd7cddfSDavid du Colombier * this device. 1387dd7cddfSDavid du Colombier */ 1397dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x800", argv[2]); 140*80ee5cbfSDavid du Colombier mchan = chandial(addr, nil, dir, &cchan); 1417dd7cddfSDavid du Colombier 1427dd7cddfSDavid du Colombier /* 1437dd7cddfSDavid du Colombier * get mac address 1447dd7cddfSDavid du Colombier */ 1457dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s/stats", dir); 1467dd7cddfSDavid du Colombier buf = smalloc(512); 147*80ee5cbfSDavid du Colombier achan = namec(addr, Aopen, OREAD, 0); 148*80ee5cbfSDavid du Colombier n = devtab[achan->type]->read(achan, buf, 511, 0); 149*80ee5cbfSDavid du Colombier cclose(achan); 1507dd7cddfSDavid du Colombier buf[n] = 0; 1517dd7cddfSDavid du Colombier 1527dd7cddfSDavid du Colombier ptr = strstr(buf, "addr: "); 1537dd7cddfSDavid du Colombier if(!ptr) 1547dd7cddfSDavid du Colombier error(Eio); 1557dd7cddfSDavid du Colombier ptr += 6; 1567dd7cddfSDavid du Colombier 1577dd7cddfSDavid du Colombier parsemac(ifc->mac, ptr, 6); 1587dd7cddfSDavid du Colombier 1597dd7cddfSDavid du Colombier /* 1607dd7cddfSDavid du Colombier * open arp conversation 1617dd7cddfSDavid du Colombier */ 1627dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x806", argv[2]); 163*80ee5cbfSDavid du Colombier achan = chandial(addr, nil, nil, nil); 1647dd7cddfSDavid du Colombier 1657dd7cddfSDavid du Colombier er = smalloc(sizeof(*er)); 1667dd7cddfSDavid du Colombier er->mchan = mchan; 1677dd7cddfSDavid du Colombier er->cchan = cchan; 1687dd7cddfSDavid du Colombier er->achan = achan; 1697dd7cddfSDavid du Colombier er->f = ifc->conv->p->f; 1707dd7cddfSDavid du Colombier ifc->arg = er; 1717dd7cddfSDavid du Colombier 1727dd7cddfSDavid du Colombier free(buf); 1737dd7cddfSDavid du Colombier poperror(); 1747dd7cddfSDavid du Colombier 1757dd7cddfSDavid du Colombier kproc("etherread", etherread, ifc); 1767dd7cddfSDavid du Colombier kproc("recvarpproc", recvarpproc, ifc); 1777dd7cddfSDavid du Colombier } 1787dd7cddfSDavid du Colombier 1797dd7cddfSDavid du Colombier /* 1807dd7cddfSDavid du Colombier * called with ifc wlock'd 1817dd7cddfSDavid du Colombier */ 1827dd7cddfSDavid du Colombier static void 1837dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc) 1847dd7cddfSDavid du Colombier { 1857dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 1867dd7cddfSDavid du Colombier 1877dd7cddfSDavid du Colombier if(er->readp) 1887dd7cddfSDavid du Colombier postnote(er->readp, 1, "unbind", 0); 1897dd7cddfSDavid du Colombier if(er->arpp) 1907dd7cddfSDavid du Colombier postnote(er->arpp, 1, "unbind", 0); 1917dd7cddfSDavid du Colombier 1927dd7cddfSDavid du Colombier /* wait for readers to die */ 1937dd7cddfSDavid du Colombier while(er->arpp != 0 || er->readp != 0) 1947dd7cddfSDavid du Colombier tsleep(&up->sleep, return0, 0, 300); 1957dd7cddfSDavid du Colombier 1967dd7cddfSDavid du Colombier if(er->mchan != nil) 1977dd7cddfSDavid du Colombier cclose(er->mchan); 1987dd7cddfSDavid du Colombier if(er->achan != nil) 1997dd7cddfSDavid du Colombier cclose(er->achan); 2007dd7cddfSDavid du Colombier if(er->cchan != nil) 2017dd7cddfSDavid du Colombier cclose(er->cchan); 2027dd7cddfSDavid du Colombier 2037dd7cddfSDavid du Colombier free(er); 2047dd7cddfSDavid du Colombier } 2057dd7cddfSDavid du Colombier 2067dd7cddfSDavid du Colombier /* 2077dd7cddfSDavid du Colombier * called by ipoput with a single block to write with ifc rlock'd 2087dd7cddfSDavid du Colombier */ 2097dd7cddfSDavid du Colombier static void 2107dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip) 2117dd7cddfSDavid du Colombier { 2127dd7cddfSDavid du Colombier Etherhdr *eh; 2137dd7cddfSDavid du Colombier Arpent *a; 2147dd7cddfSDavid du Colombier uchar mac[6]; 2157dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 2167dd7cddfSDavid du Colombier 2177dd7cddfSDavid du Colombier /* get mac address of destination */ 21859cc4ca5SDavid du Colombier a = arpget(er->f->arp, bp, version, ifc->m, ip, mac); 2197dd7cddfSDavid du Colombier if(a){ 2207dd7cddfSDavid du Colombier /* check for broadcast or multicast */ 22159cc4ca5SDavid du Colombier bp = multicastarp(er->f, a, ifc->m, mac); 2227dd7cddfSDavid du Colombier if(bp == nil){ 2237dd7cddfSDavid du Colombier sendarp(ifc, a); 2247dd7cddfSDavid du Colombier return; 2257dd7cddfSDavid du Colombier } 2267dd7cddfSDavid du Colombier } 2277dd7cddfSDavid du Colombier 2287dd7cddfSDavid du Colombier /* make it a single block with space for the ether header */ 2297dd7cddfSDavid du Colombier bp = padblock(bp, ifc->m->hsize); 2307dd7cddfSDavid du Colombier if(bp->next) 2317dd7cddfSDavid du Colombier bp = concatblock(bp); 2327dd7cddfSDavid du Colombier if(BLEN(bp) < ifc->minmtu) 2337dd7cddfSDavid du Colombier bp = adjustblock(bp, ifc->minmtu); 2347dd7cddfSDavid du Colombier eh = (Etherhdr*)bp->rp; 2357dd7cddfSDavid du Colombier 2367dd7cddfSDavid du Colombier /* copy in mac addresses and ether type */ 2377dd7cddfSDavid du Colombier memmove(eh->s, ifc->mac, sizeof(eh->s)); 2387dd7cddfSDavid du Colombier memmove(eh->d, mac, sizeof(eh->d)); 2397dd7cddfSDavid du Colombier switch(version){ 2407dd7cddfSDavid du Colombier case V4: 2417dd7cddfSDavid du Colombier eh->t[0] = 0x08; 2427dd7cddfSDavid du Colombier eh->t[1] = 0x00; 2437dd7cddfSDavid du Colombier break; 2447dd7cddfSDavid du Colombier case V6: 2457dd7cddfSDavid du Colombier eh->t[0] = 0x86; 2467dd7cddfSDavid du Colombier eh->t[1] = 0xDD; 2477dd7cddfSDavid du Colombier break; 2487dd7cddfSDavid du Colombier } 2497dd7cddfSDavid du Colombier 2507dd7cddfSDavid du Colombier devtab[er->mchan->type]->bwrite(er->mchan, bp, 0); 2517dd7cddfSDavid du Colombier ifc->out++; 2527dd7cddfSDavid du Colombier } 2537dd7cddfSDavid du Colombier 2547dd7cddfSDavid du Colombier /* 2557dd7cddfSDavid du Colombier * process to read from the ethernet 2567dd7cddfSDavid du Colombier */ 2577dd7cddfSDavid du Colombier static void 2587dd7cddfSDavid du Colombier etherread(void *a) 2597dd7cddfSDavid du Colombier { 2607dd7cddfSDavid du Colombier Ipifc *ifc; 2617dd7cddfSDavid du Colombier Block *bp; 2627dd7cddfSDavid du Colombier Etherrock *er; 2637dd7cddfSDavid du Colombier 2647dd7cddfSDavid du Colombier ifc = a; 2657dd7cddfSDavid du Colombier er = ifc->arg; 2667dd7cddfSDavid du Colombier er->readp = up; /* hide identity under a rock for unbind */ 2677dd7cddfSDavid du Colombier if(waserror()){ 2687dd7cddfSDavid du Colombier er->readp = 0; 2697dd7cddfSDavid du Colombier pexit("hangup", 1); 2707dd7cddfSDavid du Colombier } 2717dd7cddfSDavid du Colombier for(;;){ 2727dd7cddfSDavid du Colombier bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0); 2737dd7cddfSDavid du Colombier if(!canrlock(ifc)){ 2747dd7cddfSDavid du Colombier freeb(bp); 2757dd7cddfSDavid du Colombier continue; 2767dd7cddfSDavid du Colombier } 2777dd7cddfSDavid du Colombier if(waserror()){ 2787dd7cddfSDavid du Colombier runlock(ifc); 2797dd7cddfSDavid du Colombier nexterror(); 2807dd7cddfSDavid du Colombier } 2817dd7cddfSDavid du Colombier ifc->in++; 2827dd7cddfSDavid du Colombier bp->rp += ifc->m->hsize; 2837dd7cddfSDavid du Colombier if(ifc->lifc == nil) 2847dd7cddfSDavid du Colombier freeb(bp); 2857dd7cddfSDavid du Colombier else 2867dd7cddfSDavid du Colombier ipiput(er->f, ifc->lifc->local, bp); 2877dd7cddfSDavid du Colombier runlock(ifc); 2887dd7cddfSDavid du Colombier poperror(); 2897dd7cddfSDavid du Colombier } 2907dd7cddfSDavid du Colombier } 2917dd7cddfSDavid du Colombier 2927dd7cddfSDavid du Colombier static void 2937dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *) 2947dd7cddfSDavid du Colombier { 2957dd7cddfSDavid du Colombier uchar mac[6]; 2967dd7cddfSDavid du Colombier char buf[64]; 2977dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 2987dd7cddfSDavid du Colombier 2997dd7cddfSDavid du Colombier multicastea(mac, a); 3007dd7cddfSDavid du Colombier sprint(buf, "addmulti %E", mac); 3017dd7cddfSDavid du Colombier devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0); 3027dd7cddfSDavid du Colombier } 3037dd7cddfSDavid du Colombier 3047dd7cddfSDavid du Colombier static void 3057dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *) 3067dd7cddfSDavid du Colombier { 3077dd7cddfSDavid du Colombier uchar mac[6]; 3087dd7cddfSDavid du Colombier char buf[64]; 3097dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 3107dd7cddfSDavid du Colombier 3117dd7cddfSDavid du Colombier multicastea(mac, a); 3127dd7cddfSDavid du Colombier sprint(buf, "remmulti %E", mac); 3137dd7cddfSDavid du Colombier devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0); 3147dd7cddfSDavid du Colombier } 3157dd7cddfSDavid du Colombier 3167dd7cddfSDavid du Colombier /* 3177dd7cddfSDavid du Colombier * send an ethernet arp 3187dd7cddfSDavid du Colombier * (only v4, v6 uses the neighbor discovery, rfc1970) 3197dd7cddfSDavid du Colombier */ 3207dd7cddfSDavid du Colombier static void 3217dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a) 3227dd7cddfSDavid du Colombier { 3237dd7cddfSDavid du Colombier int n; 3247dd7cddfSDavid du Colombier Block *bp; 3257dd7cddfSDavid du Colombier Etherarp *e; 3267dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 3277dd7cddfSDavid du Colombier 3287dd7cddfSDavid du Colombier /* don't do anything if it's been less than a second since the last */ 3297dd7cddfSDavid du Colombier if(msec - a->time < 1000){ 3307dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 3317dd7cddfSDavid du Colombier return; 3327dd7cddfSDavid du Colombier } 3337dd7cddfSDavid du Colombier 3347dd7cddfSDavid du Colombier /* remove all but the last message */ 3357dd7cddfSDavid du Colombier while((bp = a->hold) != nil){ 3367dd7cddfSDavid du Colombier if(bp == a->last) 3377dd7cddfSDavid du Colombier break; 3387dd7cddfSDavid du Colombier a->hold = bp->list; 3397dd7cddfSDavid du Colombier freeblist(bp); 3407dd7cddfSDavid du Colombier } 3417dd7cddfSDavid du Colombier 3427dd7cddfSDavid du Colombier /* try to keep it around for a second more */ 3437dd7cddfSDavid du Colombier a->time = msec; 3447dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 3457dd7cddfSDavid du Colombier 3467dd7cddfSDavid du Colombier n = sizeof(Etherarp); 3477dd7cddfSDavid du Colombier if(n < a->type->minmtu) 3487dd7cddfSDavid du Colombier n = a->type->minmtu; 3497dd7cddfSDavid du Colombier bp = allocb(n); 3507dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 3517dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 3527dd7cddfSDavid du Colombier memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa)); 3537dd7cddfSDavid du Colombier ipv4local(ifc, e->spa); 3547dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 3557dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 3567dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 3577dd7cddfSDavid du Colombier 3587dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 3597dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 3607dd7cddfSDavid du Colombier hnputs(e->pro, ETIP); 3617dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 3627dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 3637dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 3647dd7cddfSDavid du Colombier bp->wp += n; 3657dd7cddfSDavid du Colombier 3667dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 3677dd7cddfSDavid du Colombier if(n < 0) 3687dd7cddfSDavid du Colombier print("arp: send: %r\n"); 3697dd7cddfSDavid du Colombier } 3707dd7cddfSDavid du Colombier 3717dd7cddfSDavid du Colombier /* 3727dd7cddfSDavid du Colombier * send a gratuitous arp to refresh arp caches 3737dd7cddfSDavid du Colombier */ 3747dd7cddfSDavid du Colombier static void 3757dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip) 3767dd7cddfSDavid du Colombier { 3777dd7cddfSDavid du Colombier int n; 3787dd7cddfSDavid du Colombier Block *bp; 3797dd7cddfSDavid du Colombier Etherarp *e; 3807dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 3817dd7cddfSDavid du Colombier 3827dd7cddfSDavid du Colombier /* don't arp for our initial non address */ 3837dd7cddfSDavid du Colombier if(ipcmp(ip, IPnoaddr) == 0) 3847dd7cddfSDavid du Colombier return; 3857dd7cddfSDavid du Colombier 3867dd7cddfSDavid du Colombier n = sizeof(Etherarp); 38759cc4ca5SDavid du Colombier if(n < ifc->m->minmtu) 38859cc4ca5SDavid du Colombier n = ifc->m->minmtu; 3897dd7cddfSDavid du Colombier bp = allocb(n); 3907dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 3917dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 3927dd7cddfSDavid du Colombier memmove(e->tpa, ip+IPv4off, sizeof(e->tpa)); 3937dd7cddfSDavid du Colombier memmove(e->spa, ip+IPv4off, sizeof(e->spa)); 3947dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 3957dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 3967dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 3977dd7cddfSDavid du Colombier 3987dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 3997dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 4007dd7cddfSDavid du Colombier hnputs(e->pro, ETIP); 4017dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 4027dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 4037dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 4047dd7cddfSDavid du Colombier bp->wp += n; 4057dd7cddfSDavid du Colombier 4067dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 4077dd7cddfSDavid du Colombier if(n < 0) 4087dd7cddfSDavid du Colombier print("garp: send: %r\n"); 4097dd7cddfSDavid du Colombier } 4107dd7cddfSDavid du Colombier 4117dd7cddfSDavid du Colombier static void 4127dd7cddfSDavid du Colombier recvarp(Ipifc *ifc) 4137dd7cddfSDavid du Colombier { 4147dd7cddfSDavid du Colombier int n; 4157dd7cddfSDavid du Colombier Block *ebp, *rbp; 4167dd7cddfSDavid du Colombier Etherarp *e, *r; 4177dd7cddfSDavid du Colombier uchar ip[IPaddrlen]; 4187dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 4197dd7cddfSDavid du Colombier 4207dd7cddfSDavid du Colombier ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxmtu, 0); 4217dd7cddfSDavid du Colombier if(ebp == nil) { 4227dd7cddfSDavid du Colombier print("arp: rcv: %r\n"); 4237dd7cddfSDavid du Colombier return; 4247dd7cddfSDavid du Colombier } 4257dd7cddfSDavid du Colombier 4267dd7cddfSDavid du Colombier e = (Etherarp*)ebp->rp; 4277dd7cddfSDavid du Colombier switch(nhgets(e->op)) { 4287dd7cddfSDavid du Colombier default: 4297dd7cddfSDavid du Colombier break; 4307dd7cddfSDavid du Colombier 4317dd7cddfSDavid du Colombier case ARPREPLY: 4327dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0); 4337dd7cddfSDavid du Colombier break; 4347dd7cddfSDavid du Colombier 4357dd7cddfSDavid du Colombier case ARPREQUEST: 4367dd7cddfSDavid du Colombier /* don't answer arps till we know who we are */ 4377dd7cddfSDavid du Colombier if(ifc->lifc == 0) 4387dd7cddfSDavid du Colombier break; 4397dd7cddfSDavid du Colombier 4407dd7cddfSDavid du Colombier /* check for someone that think's they're me */ 4417dd7cddfSDavid du Colombier v4tov6(ip, e->spa); 4427dd7cddfSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 4437dd7cddfSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0) 4447dd7cddfSDavid du Colombier print("arp: 0x%E also has ip addr %V\n", e->sha, e->spa); 4457dd7cddfSDavid du Colombier } else { 4467dd7cddfSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){ 4477dd7cddfSDavid du Colombier print("arp: %V also has ether addr %E\n", e->spa, e->sha); 4487dd7cddfSDavid du Colombier break; 4497dd7cddfSDavid du Colombier } 4507dd7cddfSDavid du Colombier } 4517dd7cddfSDavid du Colombier 4527dd7cddfSDavid du Colombier /* refresh what we know about sender */ 4537dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1); 4547dd7cddfSDavid du Colombier 4557dd7cddfSDavid du Colombier /* answer only requests for our address or systems we're proxying for */ 4567dd7cddfSDavid du Colombier v4tov6(ip, e->tpa); 4577dd7cddfSDavid du Colombier if(!iplocalonifc(ifc, ip)) 4587dd7cddfSDavid du Colombier if(!ipproxyifc(er->f, ifc, ip)) 4597dd7cddfSDavid du Colombier break; 4607dd7cddfSDavid du Colombier 4617dd7cddfSDavid du Colombier /* print("arp: rem %I %E (for %I)\n", e->spa, e->sha, e->tpa); /**/ 4627dd7cddfSDavid du Colombier 4637dd7cddfSDavid du Colombier n = sizeof(Etherarp); 4647dd7cddfSDavid du Colombier if(n < ifc->minmtu) 4657dd7cddfSDavid du Colombier n = ifc->minmtu; 4667dd7cddfSDavid du Colombier rbp = allocb(n); 4677dd7cddfSDavid du Colombier r = (Etherarp*)rbp->rp; 4687dd7cddfSDavid du Colombier memset(r, 0, sizeof(Etherarp)); 4697dd7cddfSDavid du Colombier hnputs(r->type, ETARP); 4707dd7cddfSDavid du Colombier hnputs(r->hrd, 1); 4717dd7cddfSDavid du Colombier hnputs(r->pro, ETIP); 4727dd7cddfSDavid du Colombier r->hln = sizeof(r->sha); 4737dd7cddfSDavid du Colombier r->pln = sizeof(r->spa); 4747dd7cddfSDavid du Colombier hnputs(r->op, ARPREPLY); 4757dd7cddfSDavid du Colombier memmove(r->tha, e->sha, sizeof(r->tha)); 4767dd7cddfSDavid du Colombier memmove(r->tpa, e->spa, sizeof(r->tpa)); 4777dd7cddfSDavid du Colombier memmove(r->sha, ifc->mac, sizeof(r->sha)); 4787dd7cddfSDavid du Colombier memmove(r->spa, e->tpa, sizeof(r->spa)); 4797dd7cddfSDavid du Colombier memmove(r->d, e->sha, sizeof(r->d)); 4807dd7cddfSDavid du Colombier memmove(r->s, ifc->mac, sizeof(r->s)); 4817dd7cddfSDavid du Colombier rbp->wp += n; 4827dd7cddfSDavid du Colombier 4837dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0); 4847dd7cddfSDavid du Colombier if(n < 0) 4857dd7cddfSDavid du Colombier print("arp: write: %r\n"); 4867dd7cddfSDavid du Colombier } 4877dd7cddfSDavid du Colombier freeb(ebp); 4887dd7cddfSDavid du Colombier } 4897dd7cddfSDavid du Colombier 4907dd7cddfSDavid du Colombier static void 4917dd7cddfSDavid du Colombier recvarpproc(void *v) 4927dd7cddfSDavid du Colombier { 4937dd7cddfSDavid du Colombier Ipifc *ifc = v; 4947dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 4957dd7cddfSDavid du Colombier 4967dd7cddfSDavid du Colombier er->arpp = up; 4977dd7cddfSDavid du Colombier if(waserror()){ 4987dd7cddfSDavid du Colombier er->arpp = 0; 4997dd7cddfSDavid du Colombier pexit("hangup", 1); 5007dd7cddfSDavid du Colombier } 5017dd7cddfSDavid du Colombier for(;;) 5027dd7cddfSDavid du Colombier recvarp(ifc); 5037dd7cddfSDavid du Colombier } 5047dd7cddfSDavid du Colombier 5057dd7cddfSDavid du Colombier static int 5067dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip) 5077dd7cddfSDavid du Colombier { 5087dd7cddfSDavid du Colombier int x; 5097dd7cddfSDavid du Colombier 5107dd7cddfSDavid du Colombier switch(x = ipismulticast(ip)){ 5117dd7cddfSDavid du Colombier case V4: 5127dd7cddfSDavid du Colombier ea[0] = 0x01; 5137dd7cddfSDavid du Colombier ea[1] = 0x00; 5147dd7cddfSDavid du Colombier ea[2] = 0x5e; 5157dd7cddfSDavid du Colombier ea[3] = ip[13] & 0x7f; 5167dd7cddfSDavid du Colombier ea[4] = ip[14]; 5177dd7cddfSDavid du Colombier ea[5] = ip[15]; 5187dd7cddfSDavid du Colombier break; 5197dd7cddfSDavid du Colombier case V6: 5207dd7cddfSDavid du Colombier ea[0] = 0x33; 5217dd7cddfSDavid du Colombier ea[1] = 0x33; 5227dd7cddfSDavid du Colombier ea[2] = ip[12]; 5237dd7cddfSDavid du Colombier ea[3] = ip[13]; 5247dd7cddfSDavid du Colombier ea[4] = ip[14]; 5257dd7cddfSDavid du Colombier ea[5] = ip[15]; 5267dd7cddfSDavid du Colombier break; 5277dd7cddfSDavid du Colombier } 5287dd7cddfSDavid du Colombier return x; 5297dd7cddfSDavid du Colombier } 5307dd7cddfSDavid du Colombier 5317dd7cddfSDavid du Colombier /* 5327dd7cddfSDavid du Colombier * fill in an arp entry for broadcast or multicast 5337dd7cddfSDavid du Colombier * addresses 5347dd7cddfSDavid du Colombier */ 5357dd7cddfSDavid du Colombier static Block* 53659cc4ca5SDavid du Colombier multicastarp(Fs *f, Arpent *a, Medium *medium, uchar *mac) 5377dd7cddfSDavid du Colombier { 5387dd7cddfSDavid du Colombier /* is it broadcast? */ 5397dd7cddfSDavid du Colombier switch(ipforme(f, a->ip)){ 5407dd7cddfSDavid du Colombier case Runi: 5417dd7cddfSDavid du Colombier return nil; 5427dd7cddfSDavid du Colombier case Rbcast: 5437dd7cddfSDavid du Colombier memset(mac, 0xff, 6); 54459cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac); 5457dd7cddfSDavid du Colombier default: 5467dd7cddfSDavid du Colombier break; 5477dd7cddfSDavid du Colombier } 5487dd7cddfSDavid du Colombier 5497dd7cddfSDavid du Colombier /* if multicast, fill in mac */ 5507dd7cddfSDavid du Colombier switch(multicastea(mac, a->ip)){ 5517dd7cddfSDavid du Colombier case V4: 5527dd7cddfSDavid du Colombier case V6: 55359cc4ca5SDavid du Colombier return arpresolve(f->arp, a, medium, mac); 5547dd7cddfSDavid du Colombier } 5557dd7cddfSDavid du Colombier 5567dd7cddfSDavid du Colombier /* let arp take care of it */ 5577dd7cddfSDavid du Colombier return nil; 5587dd7cddfSDavid du Colombier } 5597dd7cddfSDavid du Colombier 5607dd7cddfSDavid du Colombier void 5617dd7cddfSDavid du Colombier ethermediumlink(void) 5627dd7cddfSDavid du Colombier { 5637dd7cddfSDavid du Colombier addipmedium(ðermedium); 56459cc4ca5SDavid du Colombier addipmedium(&gbemedium); 5657dd7cddfSDavid du Colombier } 566