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