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