1*7dd7cddfSDavid du Colombier #include "u.h" 2*7dd7cddfSDavid du Colombier #include "../port/lib.h" 3*7dd7cddfSDavid du Colombier #include "mem.h" 4*7dd7cddfSDavid du Colombier #include "dat.h" 5*7dd7cddfSDavid du Colombier #include "fns.h" 6*7dd7cddfSDavid du Colombier #include "../port/error.h" 7*7dd7cddfSDavid du Colombier 8*7dd7cddfSDavid du Colombier #include "ip.h" 9*7dd7cddfSDavid du Colombier #include "kernel.h" 10*7dd7cddfSDavid du Colombier 11*7dd7cddfSDavid du Colombier typedef struct Etherhdr Etherhdr; 12*7dd7cddfSDavid du Colombier struct Etherhdr 13*7dd7cddfSDavid du Colombier { 14*7dd7cddfSDavid du Colombier uchar d[6]; 15*7dd7cddfSDavid du Colombier uchar s[6]; 16*7dd7cddfSDavid du Colombier uchar t[2]; 17*7dd7cddfSDavid du Colombier }; 18*7dd7cddfSDavid du Colombier 19*7dd7cddfSDavid du Colombier static void etherread(void *a); 20*7dd7cddfSDavid du Colombier static void etherbind(Ipifc *ifc, int argc, char **argv); 21*7dd7cddfSDavid du Colombier static void etherunbind(Ipifc *ifc); 22*7dd7cddfSDavid du Colombier static void etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip); 23*7dd7cddfSDavid du Colombier static void etheraddmulti(Ipifc *ifc, uchar *a, uchar *ia); 24*7dd7cddfSDavid du Colombier static void etherremmulti(Ipifc *ifc, uchar *a, uchar *ia); 25*7dd7cddfSDavid du Colombier static Block* multicastarp(Fs *f, Arpent *a, uchar *mac); 26*7dd7cddfSDavid du Colombier static void sendarp(Ipifc *ifc, Arpent *a); 27*7dd7cddfSDavid du Colombier static void sendgarp(Ipifc *ifc, uchar*); 28*7dd7cddfSDavid du Colombier static int multicastea(uchar *ea, uchar *ip); 29*7dd7cddfSDavid du Colombier static void recvarpproc(void*); 30*7dd7cddfSDavid du Colombier 31*7dd7cddfSDavid du Colombier Medium ethermedium = 32*7dd7cddfSDavid du Colombier { 33*7dd7cddfSDavid du Colombier .name= "ether", 34*7dd7cddfSDavid du Colombier .hsize= 14, 35*7dd7cddfSDavid du Colombier .minmtu= 60, 36*7dd7cddfSDavid du Colombier .maxmtu= 1514, 37*7dd7cddfSDavid du Colombier .maclen= 6, 38*7dd7cddfSDavid du Colombier .bind= etherbind, 39*7dd7cddfSDavid du Colombier .unbind= etherunbind, 40*7dd7cddfSDavid du Colombier .bwrite= etherbwrite, 41*7dd7cddfSDavid du Colombier .addmulti= etheraddmulti, 42*7dd7cddfSDavid du Colombier .remmulti= etherremmulti, 43*7dd7cddfSDavid du Colombier .ares= arpenter, 44*7dd7cddfSDavid du Colombier .areg= sendgarp, 45*7dd7cddfSDavid du Colombier }; 46*7dd7cddfSDavid du Colombier 47*7dd7cddfSDavid du Colombier typedef struct Etherrock Etherrock; 48*7dd7cddfSDavid du Colombier struct Etherrock 49*7dd7cddfSDavid du Colombier { 50*7dd7cddfSDavid du Colombier Fs *f; /* file system we belong to */ 51*7dd7cddfSDavid du Colombier Proc *arpp; /* arp process */ 52*7dd7cddfSDavid du Colombier Proc *readp; /* reading process */ 53*7dd7cddfSDavid du Colombier Chan *mchan; /* Data channel */ 54*7dd7cddfSDavid du Colombier Chan *achan; /* Arp channel */ 55*7dd7cddfSDavid du Colombier Chan *cchan; /* Control channel */ 56*7dd7cddfSDavid du Colombier }; 57*7dd7cddfSDavid du Colombier 58*7dd7cddfSDavid du Colombier /* 59*7dd7cddfSDavid du Colombier * ethernet arp request 60*7dd7cddfSDavid du Colombier */ 61*7dd7cddfSDavid du Colombier enum 62*7dd7cddfSDavid du Colombier { 63*7dd7cddfSDavid du Colombier ETARP = 0x0806, 64*7dd7cddfSDavid du Colombier ETIP = 0x0800, 65*7dd7cddfSDavid du Colombier ARPREQUEST = 1, 66*7dd7cddfSDavid du Colombier ARPREPLY = 2, 67*7dd7cddfSDavid du Colombier }; 68*7dd7cddfSDavid du Colombier typedef struct Etherarp Etherarp; 69*7dd7cddfSDavid du Colombier struct Etherarp 70*7dd7cddfSDavid du Colombier { 71*7dd7cddfSDavid du Colombier uchar d[6]; 72*7dd7cddfSDavid du Colombier uchar s[6]; 73*7dd7cddfSDavid du Colombier uchar type[2]; 74*7dd7cddfSDavid du Colombier uchar hrd[2]; 75*7dd7cddfSDavid du Colombier uchar pro[2]; 76*7dd7cddfSDavid du Colombier uchar hln; 77*7dd7cddfSDavid du Colombier uchar pln; 78*7dd7cddfSDavid du Colombier uchar op[2]; 79*7dd7cddfSDavid du Colombier uchar sha[6]; 80*7dd7cddfSDavid du Colombier uchar spa[4]; 81*7dd7cddfSDavid du Colombier uchar tha[6]; 82*7dd7cddfSDavid du Colombier uchar tpa[4]; 83*7dd7cddfSDavid du Colombier }; 84*7dd7cddfSDavid du Colombier 85*7dd7cddfSDavid du Colombier 86*7dd7cddfSDavid du Colombier /* 87*7dd7cddfSDavid du Colombier * called to bind an IP ifc to an ethernet device 88*7dd7cddfSDavid du Colombier * called with ifc wlock'd 89*7dd7cddfSDavid du Colombier */ 90*7dd7cddfSDavid du Colombier static void 91*7dd7cddfSDavid du Colombier etherbind(Ipifc *ifc, int argc, char **argv) 92*7dd7cddfSDavid du Colombier { 93*7dd7cddfSDavid du Colombier Chan *mchan, *cchan, *achan; 94*7dd7cddfSDavid du Colombier char addr[2*NAMELEN]; 95*7dd7cddfSDavid du Colombier char dir[2*NAMELEN]; 96*7dd7cddfSDavid du Colombier char *buf; 97*7dd7cddfSDavid du Colombier int fd, cfd, n; 98*7dd7cddfSDavid du Colombier char *ptr; 99*7dd7cddfSDavid du Colombier Etherrock *er; 100*7dd7cddfSDavid du Colombier 101*7dd7cddfSDavid du Colombier if(argc < 2) 102*7dd7cddfSDavid du Colombier error(Ebadarg); 103*7dd7cddfSDavid du Colombier 104*7dd7cddfSDavid du Colombier mchan = cchan = achan = nil; 105*7dd7cddfSDavid du Colombier buf = nil; 106*7dd7cddfSDavid du Colombier if(waserror()){ 107*7dd7cddfSDavid du Colombier if(mchan != nil) 108*7dd7cddfSDavid du Colombier cclose(mchan); 109*7dd7cddfSDavid du Colombier if(cchan != nil) 110*7dd7cddfSDavid du Colombier cclose(cchan); 111*7dd7cddfSDavid du Colombier if(achan != nil) 112*7dd7cddfSDavid du Colombier cclose(achan); 113*7dd7cddfSDavid du Colombier if(buf != nil) 114*7dd7cddfSDavid du Colombier free(buf); 115*7dd7cddfSDavid du Colombier nexterror(); 116*7dd7cddfSDavid du Colombier } 117*7dd7cddfSDavid du Colombier 118*7dd7cddfSDavid du Colombier /* 119*7dd7cddfSDavid du Colombier * open ip conversation 120*7dd7cddfSDavid du Colombier * 121*7dd7cddfSDavid du Colombier * the dial will fail if the type is already open on 122*7dd7cddfSDavid du Colombier * this device. 123*7dd7cddfSDavid du Colombier */ 124*7dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x800", argv[2]); 125*7dd7cddfSDavid du Colombier fd = kdial(addr, nil, dir, &cfd); 126*7dd7cddfSDavid du Colombier if(fd < 0) 127*7dd7cddfSDavid du Colombier error("dial 0x800 failed"); 128*7dd7cddfSDavid du Colombier mchan = commonfdtochan(fd, ORDWR, 0, 1); 129*7dd7cddfSDavid du Colombier cchan = commonfdtochan(cfd, ORDWR, 0, 1); 130*7dd7cddfSDavid du Colombier kclose(fd); 131*7dd7cddfSDavid du Colombier kclose(cfd); 132*7dd7cddfSDavid du Colombier 133*7dd7cddfSDavid du Colombier /* 134*7dd7cddfSDavid du Colombier * get mac address 135*7dd7cddfSDavid du Colombier */ 136*7dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s/stats", dir); 137*7dd7cddfSDavid du Colombier fd = kopen(addr, OREAD); 138*7dd7cddfSDavid du Colombier if(fd < 0) 139*7dd7cddfSDavid du Colombier error("can't read ether stats"); 140*7dd7cddfSDavid du Colombier 141*7dd7cddfSDavid du Colombier buf = smalloc(512); 142*7dd7cddfSDavid du Colombier n = kread(fd, buf, 511); 143*7dd7cddfSDavid du Colombier kclose(fd); 144*7dd7cddfSDavid du Colombier if(n <= 0) 145*7dd7cddfSDavid du Colombier error(Eio); 146*7dd7cddfSDavid du Colombier buf[n] = 0; 147*7dd7cddfSDavid du Colombier 148*7dd7cddfSDavid du Colombier ptr = strstr(buf, "addr: "); 149*7dd7cddfSDavid du Colombier if(!ptr) 150*7dd7cddfSDavid du Colombier error(Eio); 151*7dd7cddfSDavid du Colombier ptr += 6; 152*7dd7cddfSDavid du Colombier 153*7dd7cddfSDavid du Colombier parsemac(ifc->mac, ptr, 6); 154*7dd7cddfSDavid du Colombier 155*7dd7cddfSDavid du Colombier /* 156*7dd7cddfSDavid du Colombier * open arp conversation 157*7dd7cddfSDavid du Colombier */ 158*7dd7cddfSDavid du Colombier snprint(addr, sizeof(addr), "%s!0x806", argv[2]); 159*7dd7cddfSDavid du Colombier fd = kdial(addr, nil, nil, nil); 160*7dd7cddfSDavid du Colombier if(fd < 0) 161*7dd7cddfSDavid du Colombier error("dial 0x806 failed"); 162*7dd7cddfSDavid du Colombier achan = commonfdtochan(fd, ORDWR, 0, 1); 163*7dd7cddfSDavid du Colombier kclose(fd); 164*7dd7cddfSDavid du Colombier 165*7dd7cddfSDavid du Colombier er = smalloc(sizeof(*er)); 166*7dd7cddfSDavid du Colombier er->mchan = mchan; 167*7dd7cddfSDavid du Colombier er->cchan = cchan; 168*7dd7cddfSDavid du Colombier er->achan = achan; 169*7dd7cddfSDavid du Colombier er->f = ifc->conv->p->f; 170*7dd7cddfSDavid du Colombier ifc->arg = er; 171*7dd7cddfSDavid du Colombier 172*7dd7cddfSDavid du Colombier free(buf); 173*7dd7cddfSDavid du Colombier poperror(); 174*7dd7cddfSDavid du Colombier 175*7dd7cddfSDavid du Colombier kproc("etherread", etherread, ifc); 176*7dd7cddfSDavid du Colombier kproc("recvarpproc", recvarpproc, ifc); 177*7dd7cddfSDavid du Colombier } 178*7dd7cddfSDavid du Colombier 179*7dd7cddfSDavid du Colombier /* 180*7dd7cddfSDavid du Colombier * called with ifc wlock'd 181*7dd7cddfSDavid du Colombier */ 182*7dd7cddfSDavid du Colombier static void 183*7dd7cddfSDavid du Colombier etherunbind(Ipifc *ifc) 184*7dd7cddfSDavid du Colombier { 185*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 186*7dd7cddfSDavid du Colombier 187*7dd7cddfSDavid du Colombier if(er->readp) 188*7dd7cddfSDavid du Colombier postnote(er->readp, 1, "unbind", 0); 189*7dd7cddfSDavid du Colombier if(er->arpp) 190*7dd7cddfSDavid du Colombier postnote(er->arpp, 1, "unbind", 0); 191*7dd7cddfSDavid du Colombier 192*7dd7cddfSDavid du Colombier /* wait for readers to die */ 193*7dd7cddfSDavid du Colombier while(er->arpp != 0 || er->readp != 0) 194*7dd7cddfSDavid du Colombier tsleep(&up->sleep, return0, 0, 300); 195*7dd7cddfSDavid du Colombier 196*7dd7cddfSDavid du Colombier if(er->mchan != nil) 197*7dd7cddfSDavid du Colombier cclose(er->mchan); 198*7dd7cddfSDavid du Colombier if(er->achan != nil) 199*7dd7cddfSDavid du Colombier cclose(er->achan); 200*7dd7cddfSDavid du Colombier if(er->cchan != nil) 201*7dd7cddfSDavid du Colombier cclose(er->cchan); 202*7dd7cddfSDavid du Colombier 203*7dd7cddfSDavid du Colombier free(er); 204*7dd7cddfSDavid du Colombier } 205*7dd7cddfSDavid du Colombier 206*7dd7cddfSDavid du Colombier /* 207*7dd7cddfSDavid du Colombier * called by ipoput with a single block to write with ifc rlock'd 208*7dd7cddfSDavid du Colombier */ 209*7dd7cddfSDavid du Colombier static void 210*7dd7cddfSDavid du Colombier etherbwrite(Ipifc *ifc, Block *bp, int version, uchar *ip) 211*7dd7cddfSDavid du Colombier { 212*7dd7cddfSDavid du Colombier Etherhdr *eh; 213*7dd7cddfSDavid du Colombier Arpent *a; 214*7dd7cddfSDavid du Colombier uchar mac[6]; 215*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 216*7dd7cddfSDavid du Colombier 217*7dd7cddfSDavid du Colombier /* get mac address of destination */ 218*7dd7cddfSDavid du Colombier a = arpget(er->f->arp, bp, version, ðermedium, ip, mac); 219*7dd7cddfSDavid du Colombier if(a){ 220*7dd7cddfSDavid du Colombier /* check for broadcast or multicast */ 221*7dd7cddfSDavid du Colombier bp = multicastarp(er->f, a, mac); 222*7dd7cddfSDavid du Colombier if(bp == nil){ 223*7dd7cddfSDavid du Colombier sendarp(ifc, a); 224*7dd7cddfSDavid du Colombier return; 225*7dd7cddfSDavid du Colombier } 226*7dd7cddfSDavid du Colombier } 227*7dd7cddfSDavid du Colombier 228*7dd7cddfSDavid du Colombier /* make it a single block with space for the ether header */ 229*7dd7cddfSDavid du Colombier bp = padblock(bp, ifc->m->hsize); 230*7dd7cddfSDavid du Colombier if(bp->next) 231*7dd7cddfSDavid du Colombier bp = concatblock(bp); 232*7dd7cddfSDavid du Colombier if(BLEN(bp) < ifc->minmtu) 233*7dd7cddfSDavid du Colombier bp = adjustblock(bp, ifc->minmtu); 234*7dd7cddfSDavid du Colombier eh = (Etherhdr*)bp->rp; 235*7dd7cddfSDavid du Colombier 236*7dd7cddfSDavid du Colombier /* copy in mac addresses and ether type */ 237*7dd7cddfSDavid du Colombier memmove(eh->s, ifc->mac, sizeof(eh->s)); 238*7dd7cddfSDavid du Colombier memmove(eh->d, mac, sizeof(eh->d)); 239*7dd7cddfSDavid du Colombier switch(version){ 240*7dd7cddfSDavid du Colombier case V4: 241*7dd7cddfSDavid du Colombier eh->t[0] = 0x08; 242*7dd7cddfSDavid du Colombier eh->t[1] = 0x00; 243*7dd7cddfSDavid du Colombier break; 244*7dd7cddfSDavid du Colombier case V6: 245*7dd7cddfSDavid du Colombier eh->t[0] = 0x86; 246*7dd7cddfSDavid du Colombier eh->t[1] = 0xDD; 247*7dd7cddfSDavid du Colombier break; 248*7dd7cddfSDavid du Colombier } 249*7dd7cddfSDavid du Colombier 250*7dd7cddfSDavid du Colombier devtab[er->mchan->type]->bwrite(er->mchan, bp, 0); 251*7dd7cddfSDavid du Colombier ifc->out++; 252*7dd7cddfSDavid du Colombier } 253*7dd7cddfSDavid du Colombier 254*7dd7cddfSDavid du Colombier /* 255*7dd7cddfSDavid du Colombier * process to read from the ethernet 256*7dd7cddfSDavid du Colombier */ 257*7dd7cddfSDavid du Colombier static void 258*7dd7cddfSDavid du Colombier etherread(void *a) 259*7dd7cddfSDavid du Colombier { 260*7dd7cddfSDavid du Colombier Ipifc *ifc; 261*7dd7cddfSDavid du Colombier Block *bp; 262*7dd7cddfSDavid du Colombier Etherrock *er; 263*7dd7cddfSDavid du Colombier 264*7dd7cddfSDavid du Colombier ifc = a; 265*7dd7cddfSDavid du Colombier er = ifc->arg; 266*7dd7cddfSDavid du Colombier er->readp = up; /* hide identity under a rock for unbind */ 267*7dd7cddfSDavid du Colombier if(waserror()){ 268*7dd7cddfSDavid du Colombier er->readp = 0; 269*7dd7cddfSDavid du Colombier pexit("hangup", 1); 270*7dd7cddfSDavid du Colombier } 271*7dd7cddfSDavid du Colombier for(;;){ 272*7dd7cddfSDavid du Colombier bp = devtab[er->mchan->type]->bread(er->mchan, ifc->maxmtu, 0); 273*7dd7cddfSDavid du Colombier if(!canrlock(ifc)){ 274*7dd7cddfSDavid du Colombier freeb(bp); 275*7dd7cddfSDavid du Colombier continue; 276*7dd7cddfSDavid du Colombier } 277*7dd7cddfSDavid du Colombier if(waserror()){ 278*7dd7cddfSDavid du Colombier runlock(ifc); 279*7dd7cddfSDavid du Colombier nexterror(); 280*7dd7cddfSDavid du Colombier } 281*7dd7cddfSDavid du Colombier ifc->in++; 282*7dd7cddfSDavid du Colombier bp->rp += ifc->m->hsize; 283*7dd7cddfSDavid du Colombier if(ifc->lifc == nil) 284*7dd7cddfSDavid du Colombier freeb(bp); 285*7dd7cddfSDavid du Colombier else 286*7dd7cddfSDavid du Colombier ipiput(er->f, ifc->lifc->local, bp); 287*7dd7cddfSDavid du Colombier runlock(ifc); 288*7dd7cddfSDavid du Colombier poperror(); 289*7dd7cddfSDavid du Colombier } 290*7dd7cddfSDavid du Colombier } 291*7dd7cddfSDavid du Colombier 292*7dd7cddfSDavid du Colombier static void 293*7dd7cddfSDavid du Colombier etheraddmulti(Ipifc *ifc, uchar *a, uchar *) 294*7dd7cddfSDavid du Colombier { 295*7dd7cddfSDavid du Colombier uchar mac[6]; 296*7dd7cddfSDavid du Colombier char buf[64]; 297*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 298*7dd7cddfSDavid du Colombier 299*7dd7cddfSDavid du Colombier multicastea(mac, a); 300*7dd7cddfSDavid du Colombier sprint(buf, "addmulti %E", mac); 301*7dd7cddfSDavid du Colombier devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0); 302*7dd7cddfSDavid du Colombier } 303*7dd7cddfSDavid du Colombier 304*7dd7cddfSDavid du Colombier static void 305*7dd7cddfSDavid du Colombier etherremmulti(Ipifc *ifc, uchar *a, uchar *) 306*7dd7cddfSDavid du Colombier { 307*7dd7cddfSDavid du Colombier uchar mac[6]; 308*7dd7cddfSDavid du Colombier char buf[64]; 309*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 310*7dd7cddfSDavid du Colombier 311*7dd7cddfSDavid du Colombier multicastea(mac, a); 312*7dd7cddfSDavid du Colombier sprint(buf, "remmulti %E", mac); 313*7dd7cddfSDavid du Colombier devtab[er->cchan->type]->write(er->cchan, buf, strlen(buf), 0); 314*7dd7cddfSDavid du Colombier } 315*7dd7cddfSDavid du Colombier 316*7dd7cddfSDavid du Colombier /* 317*7dd7cddfSDavid du Colombier * send an ethernet arp 318*7dd7cddfSDavid du Colombier * (only v4, v6 uses the neighbor discovery, rfc1970) 319*7dd7cddfSDavid du Colombier */ 320*7dd7cddfSDavid du Colombier static void 321*7dd7cddfSDavid du Colombier sendarp(Ipifc *ifc, Arpent *a) 322*7dd7cddfSDavid du Colombier { 323*7dd7cddfSDavid du Colombier int n; 324*7dd7cddfSDavid du Colombier Block *bp; 325*7dd7cddfSDavid du Colombier Etherarp *e; 326*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 327*7dd7cddfSDavid du Colombier 328*7dd7cddfSDavid du Colombier /* don't do anything if it's been less than a second since the last */ 329*7dd7cddfSDavid du Colombier if(msec - a->time < 1000){ 330*7dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 331*7dd7cddfSDavid du Colombier return; 332*7dd7cddfSDavid du Colombier } 333*7dd7cddfSDavid du Colombier 334*7dd7cddfSDavid du Colombier /* remove all but the last message */ 335*7dd7cddfSDavid du Colombier while((bp = a->hold) != nil){ 336*7dd7cddfSDavid du Colombier if(bp == a->last) 337*7dd7cddfSDavid du Colombier break; 338*7dd7cddfSDavid du Colombier a->hold = bp->list; 339*7dd7cddfSDavid du Colombier freeblist(bp); 340*7dd7cddfSDavid du Colombier } 341*7dd7cddfSDavid du Colombier 342*7dd7cddfSDavid du Colombier /* try to keep it around for a second more */ 343*7dd7cddfSDavid du Colombier a->time = msec; 344*7dd7cddfSDavid du Colombier arprelease(er->f->arp, a); 345*7dd7cddfSDavid du Colombier 346*7dd7cddfSDavid du Colombier n = sizeof(Etherarp); 347*7dd7cddfSDavid du Colombier if(n < a->type->minmtu) 348*7dd7cddfSDavid du Colombier n = a->type->minmtu; 349*7dd7cddfSDavid du Colombier bp = allocb(n); 350*7dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 351*7dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 352*7dd7cddfSDavid du Colombier memmove(e->tpa, a->ip+IPv4off, sizeof(e->tpa)); 353*7dd7cddfSDavid du Colombier ipv4local(ifc, e->spa); 354*7dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 355*7dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 356*7dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 357*7dd7cddfSDavid du Colombier 358*7dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 359*7dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 360*7dd7cddfSDavid du Colombier hnputs(e->pro, ETIP); 361*7dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 362*7dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 363*7dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 364*7dd7cddfSDavid du Colombier bp->wp += n; 365*7dd7cddfSDavid du Colombier 366*7dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 367*7dd7cddfSDavid du Colombier if(n < 0) 368*7dd7cddfSDavid du Colombier print("arp: send: %r\n"); 369*7dd7cddfSDavid du Colombier } 370*7dd7cddfSDavid du Colombier 371*7dd7cddfSDavid du Colombier /* 372*7dd7cddfSDavid du Colombier * send a gratuitous arp to refresh arp caches 373*7dd7cddfSDavid du Colombier */ 374*7dd7cddfSDavid du Colombier static void 375*7dd7cddfSDavid du Colombier sendgarp(Ipifc *ifc, uchar *ip) 376*7dd7cddfSDavid du Colombier { 377*7dd7cddfSDavid du Colombier int n; 378*7dd7cddfSDavid du Colombier Block *bp; 379*7dd7cddfSDavid du Colombier Etherarp *e; 380*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 381*7dd7cddfSDavid du Colombier 382*7dd7cddfSDavid du Colombier /* don't arp for our initial non address */ 383*7dd7cddfSDavid du Colombier if(ipcmp(ip, IPnoaddr) == 0) 384*7dd7cddfSDavid du Colombier return; 385*7dd7cddfSDavid du Colombier 386*7dd7cddfSDavid du Colombier n = sizeof(Etherarp); 387*7dd7cddfSDavid du Colombier if(n < ethermedium.minmtu) 388*7dd7cddfSDavid du Colombier n = ethermedium.minmtu; 389*7dd7cddfSDavid du Colombier bp = allocb(n); 390*7dd7cddfSDavid du Colombier memset(bp->rp, 0, n); 391*7dd7cddfSDavid du Colombier e = (Etherarp*)bp->rp; 392*7dd7cddfSDavid du Colombier memmove(e->tpa, ip+IPv4off, sizeof(e->tpa)); 393*7dd7cddfSDavid du Colombier memmove(e->spa, ip+IPv4off, sizeof(e->spa)); 394*7dd7cddfSDavid du Colombier memmove(e->sha, ifc->mac, sizeof(e->sha)); 395*7dd7cddfSDavid du Colombier memset(e->d, 0xff, sizeof(e->d)); /* ethernet broadcast */ 396*7dd7cddfSDavid du Colombier memmove(e->s, ifc->mac, sizeof(e->s)); 397*7dd7cddfSDavid du Colombier 398*7dd7cddfSDavid du Colombier hnputs(e->type, ETARP); 399*7dd7cddfSDavid du Colombier hnputs(e->hrd, 1); 400*7dd7cddfSDavid du Colombier hnputs(e->pro, ETIP); 401*7dd7cddfSDavid du Colombier e->hln = sizeof(e->sha); 402*7dd7cddfSDavid du Colombier e->pln = sizeof(e->spa); 403*7dd7cddfSDavid du Colombier hnputs(e->op, ARPREQUEST); 404*7dd7cddfSDavid du Colombier bp->wp += n; 405*7dd7cddfSDavid du Colombier 406*7dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, bp, 0); 407*7dd7cddfSDavid du Colombier if(n < 0) 408*7dd7cddfSDavid du Colombier print("garp: send: %r\n"); 409*7dd7cddfSDavid du Colombier } 410*7dd7cddfSDavid du Colombier 411*7dd7cddfSDavid du Colombier static void 412*7dd7cddfSDavid du Colombier recvarp(Ipifc *ifc) 413*7dd7cddfSDavid du Colombier { 414*7dd7cddfSDavid du Colombier int n; 415*7dd7cddfSDavid du Colombier Block *ebp, *rbp; 416*7dd7cddfSDavid du Colombier Etherarp *e, *r; 417*7dd7cddfSDavid du Colombier uchar ip[IPaddrlen]; 418*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 419*7dd7cddfSDavid du Colombier 420*7dd7cddfSDavid du Colombier ebp = devtab[er->achan->type]->bread(er->achan, ifc->maxmtu, 0); 421*7dd7cddfSDavid du Colombier if(ebp == nil) { 422*7dd7cddfSDavid du Colombier print("arp: rcv: %r\n"); 423*7dd7cddfSDavid du Colombier return; 424*7dd7cddfSDavid du Colombier } 425*7dd7cddfSDavid du Colombier 426*7dd7cddfSDavid du Colombier e = (Etherarp*)ebp->rp; 427*7dd7cddfSDavid du Colombier switch(nhgets(e->op)) { 428*7dd7cddfSDavid du Colombier default: 429*7dd7cddfSDavid du Colombier break; 430*7dd7cddfSDavid du Colombier 431*7dd7cddfSDavid du Colombier case ARPREPLY: 432*7dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0); 433*7dd7cddfSDavid du Colombier break; 434*7dd7cddfSDavid du Colombier 435*7dd7cddfSDavid du Colombier case ARPREQUEST: 436*7dd7cddfSDavid du Colombier /* don't answer arps till we know who we are */ 437*7dd7cddfSDavid du Colombier if(ifc->lifc == 0) 438*7dd7cddfSDavid du Colombier break; 439*7dd7cddfSDavid du Colombier 440*7dd7cddfSDavid du Colombier /* check for someone that think's they're me */ 441*7dd7cddfSDavid du Colombier v4tov6(ip, e->spa); 442*7dd7cddfSDavid du Colombier if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 443*7dd7cddfSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0) 444*7dd7cddfSDavid du Colombier print("arp: 0x%E also has ip addr %V\n", e->sha, e->spa); 445*7dd7cddfSDavid du Colombier } else { 446*7dd7cddfSDavid du Colombier if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){ 447*7dd7cddfSDavid du Colombier print("arp: %V also has ether addr %E\n", e->spa, e->sha); 448*7dd7cddfSDavid du Colombier break; 449*7dd7cddfSDavid du Colombier } 450*7dd7cddfSDavid du Colombier } 451*7dd7cddfSDavid du Colombier 452*7dd7cddfSDavid du Colombier /* refresh what we know about sender */ 453*7dd7cddfSDavid du Colombier arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1); 454*7dd7cddfSDavid du Colombier 455*7dd7cddfSDavid du Colombier /* answer only requests for our address or systems we're proxying for */ 456*7dd7cddfSDavid du Colombier v4tov6(ip, e->tpa); 457*7dd7cddfSDavid du Colombier if(!iplocalonifc(ifc, ip)) 458*7dd7cddfSDavid du Colombier if(!ipproxyifc(er->f, ifc, ip)) 459*7dd7cddfSDavid du Colombier break; 460*7dd7cddfSDavid du Colombier 461*7dd7cddfSDavid du Colombier /* print("arp: rem %I %E (for %I)\n", e->spa, e->sha, e->tpa); /**/ 462*7dd7cddfSDavid du Colombier 463*7dd7cddfSDavid du Colombier n = sizeof(Etherarp); 464*7dd7cddfSDavid du Colombier if(n < ifc->minmtu) 465*7dd7cddfSDavid du Colombier n = ifc->minmtu; 466*7dd7cddfSDavid du Colombier rbp = allocb(n); 467*7dd7cddfSDavid du Colombier r = (Etherarp*)rbp->rp; 468*7dd7cddfSDavid du Colombier memset(r, 0, sizeof(Etherarp)); 469*7dd7cddfSDavid du Colombier hnputs(r->type, ETARP); 470*7dd7cddfSDavid du Colombier hnputs(r->hrd, 1); 471*7dd7cddfSDavid du Colombier hnputs(r->pro, ETIP); 472*7dd7cddfSDavid du Colombier r->hln = sizeof(r->sha); 473*7dd7cddfSDavid du Colombier r->pln = sizeof(r->spa); 474*7dd7cddfSDavid du Colombier hnputs(r->op, ARPREPLY); 475*7dd7cddfSDavid du Colombier memmove(r->tha, e->sha, sizeof(r->tha)); 476*7dd7cddfSDavid du Colombier memmove(r->tpa, e->spa, sizeof(r->tpa)); 477*7dd7cddfSDavid du Colombier memmove(r->sha, ifc->mac, sizeof(r->sha)); 478*7dd7cddfSDavid du Colombier memmove(r->spa, e->tpa, sizeof(r->spa)); 479*7dd7cddfSDavid du Colombier memmove(r->d, e->sha, sizeof(r->d)); 480*7dd7cddfSDavid du Colombier memmove(r->s, ifc->mac, sizeof(r->s)); 481*7dd7cddfSDavid du Colombier rbp->wp += n; 482*7dd7cddfSDavid du Colombier 483*7dd7cddfSDavid du Colombier n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0); 484*7dd7cddfSDavid du Colombier if(n < 0) 485*7dd7cddfSDavid du Colombier print("arp: write: %r\n"); 486*7dd7cddfSDavid du Colombier } 487*7dd7cddfSDavid du Colombier freeb(ebp); 488*7dd7cddfSDavid du Colombier } 489*7dd7cddfSDavid du Colombier 490*7dd7cddfSDavid du Colombier static void 491*7dd7cddfSDavid du Colombier recvarpproc(void *v) 492*7dd7cddfSDavid du Colombier { 493*7dd7cddfSDavid du Colombier Ipifc *ifc = v; 494*7dd7cddfSDavid du Colombier Etherrock *er = ifc->arg; 495*7dd7cddfSDavid du Colombier 496*7dd7cddfSDavid du Colombier er->arpp = up; 497*7dd7cddfSDavid du Colombier if(waserror()){ 498*7dd7cddfSDavid du Colombier er->arpp = 0; 499*7dd7cddfSDavid du Colombier pexit("hangup", 1); 500*7dd7cddfSDavid du Colombier } 501*7dd7cddfSDavid du Colombier for(;;) 502*7dd7cddfSDavid du Colombier recvarp(ifc); 503*7dd7cddfSDavid du Colombier } 504*7dd7cddfSDavid du Colombier 505*7dd7cddfSDavid du Colombier static int 506*7dd7cddfSDavid du Colombier multicastea(uchar *ea, uchar *ip) 507*7dd7cddfSDavid du Colombier { 508*7dd7cddfSDavid du Colombier int x; 509*7dd7cddfSDavid du Colombier 510*7dd7cddfSDavid du Colombier switch(x = ipismulticast(ip)){ 511*7dd7cddfSDavid du Colombier case V4: 512*7dd7cddfSDavid du Colombier ea[0] = 0x01; 513*7dd7cddfSDavid du Colombier ea[1] = 0x00; 514*7dd7cddfSDavid du Colombier ea[2] = 0x5e; 515*7dd7cddfSDavid du Colombier ea[3] = ip[13] & 0x7f; 516*7dd7cddfSDavid du Colombier ea[4] = ip[14]; 517*7dd7cddfSDavid du Colombier ea[5] = ip[15]; 518*7dd7cddfSDavid du Colombier break; 519*7dd7cddfSDavid du Colombier case V6: 520*7dd7cddfSDavid du Colombier ea[0] = 0x33; 521*7dd7cddfSDavid du Colombier ea[1] = 0x33; 522*7dd7cddfSDavid du Colombier ea[2] = ip[12]; 523*7dd7cddfSDavid du Colombier ea[3] = ip[13]; 524*7dd7cddfSDavid du Colombier ea[4] = ip[14]; 525*7dd7cddfSDavid du Colombier ea[5] = ip[15]; 526*7dd7cddfSDavid du Colombier break; 527*7dd7cddfSDavid du Colombier } 528*7dd7cddfSDavid du Colombier return x; 529*7dd7cddfSDavid du Colombier } 530*7dd7cddfSDavid du Colombier 531*7dd7cddfSDavid du Colombier /* 532*7dd7cddfSDavid du Colombier * fill in an arp entry for broadcast or multicast 533*7dd7cddfSDavid du Colombier * addresses 534*7dd7cddfSDavid du Colombier */ 535*7dd7cddfSDavid du Colombier static Block* 536*7dd7cddfSDavid du Colombier multicastarp(Fs *f, Arpent *a, uchar *mac) 537*7dd7cddfSDavid du Colombier { 538*7dd7cddfSDavid du Colombier /* is it broadcast? */ 539*7dd7cddfSDavid du Colombier switch(ipforme(f, a->ip)){ 540*7dd7cddfSDavid du Colombier case Runi: 541*7dd7cddfSDavid du Colombier return nil; 542*7dd7cddfSDavid du Colombier case Rbcast: 543*7dd7cddfSDavid du Colombier memset(mac, 0xff, 6); 544*7dd7cddfSDavid du Colombier return arpresolve(f->arp, a, ðermedium, mac); 545*7dd7cddfSDavid du Colombier default: 546*7dd7cddfSDavid du Colombier break; 547*7dd7cddfSDavid du Colombier } 548*7dd7cddfSDavid du Colombier 549*7dd7cddfSDavid du Colombier /* if multicast, fill in mac */ 550*7dd7cddfSDavid du Colombier switch(multicastea(mac, a->ip)){ 551*7dd7cddfSDavid du Colombier case V4: 552*7dd7cddfSDavid du Colombier case V6: 553*7dd7cddfSDavid du Colombier return arpresolve(f->arp, a, ðermedium, mac); 554*7dd7cddfSDavid du Colombier } 555*7dd7cddfSDavid du Colombier 556*7dd7cddfSDavid du Colombier /* let arp take care of it */ 557*7dd7cddfSDavid du Colombier return nil; 558*7dd7cddfSDavid du Colombier } 559*7dd7cddfSDavid du Colombier 560*7dd7cddfSDavid du Colombier void 561*7dd7cddfSDavid du Colombier ethermediumlink(void) 562*7dd7cddfSDavid du Colombier { 563*7dd7cddfSDavid du Colombier addipmedium(ðermedium); 564*7dd7cddfSDavid du Colombier } 565