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