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, 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 typedef struct Etherrock Etherrock; 48 struct Etherrock 49 { 50 Fs *f; /* file system we belong to */ 51 Proc *arpp; /* arp process */ 52 Proc *readp; /* reading process */ 53 Chan *mchan; /* Data channel */ 54 Chan *achan; /* Arp channel */ 55 Chan *cchan; /* Control channel */ 56 }; 57 58 /* 59 * ethernet arp request 60 */ 61 enum 62 { 63 ETARP = 0x0806, 64 ETIP = 0x0800, 65 ARPREQUEST = 1, 66 ARPREPLY = 2, 67 }; 68 typedef struct Etherarp Etherarp; 69 struct Etherarp 70 { 71 uchar d[6]; 72 uchar s[6]; 73 uchar type[2]; 74 uchar hrd[2]; 75 uchar pro[2]; 76 uchar hln; 77 uchar pln; 78 uchar op[2]; 79 uchar sha[6]; 80 uchar spa[4]; 81 uchar tha[6]; 82 uchar tpa[4]; 83 }; 84 85 86 /* 87 * called to bind an IP ifc to an ethernet device 88 * called with ifc wlock'd 89 */ 90 static void 91 etherbind(Ipifc *ifc, int argc, char **argv) 92 { 93 Chan *mchan, *cchan, *achan; 94 char addr[2*NAMELEN]; 95 char dir[2*NAMELEN]; 96 char *buf; 97 int fd, cfd, n; 98 char *ptr; 99 Etherrock *er; 100 101 if(argc < 2) 102 error(Ebadarg); 103 104 mchan = cchan = achan = nil; 105 buf = nil; 106 if(waserror()){ 107 if(mchan != nil) 108 cclose(mchan); 109 if(cchan != nil) 110 cclose(cchan); 111 if(achan != nil) 112 cclose(achan); 113 if(buf != nil) 114 free(buf); 115 nexterror(); 116 } 117 118 /* 119 * open ip conversation 120 * 121 * the dial will fail if the type is already open on 122 * this device. 123 */ 124 snprint(addr, sizeof(addr), "%s!0x800", argv[2]); 125 fd = kdial(addr, nil, dir, &cfd); 126 if(fd < 0) 127 error("dial 0x800 failed"); 128 mchan = commonfdtochan(fd, ORDWR, 0, 1); 129 cchan = commonfdtochan(cfd, ORDWR, 0, 1); 130 kclose(fd); 131 kclose(cfd); 132 133 /* 134 * get mac address 135 */ 136 snprint(addr, sizeof(addr), "%s/stats", dir); 137 fd = kopen(addr, OREAD); 138 if(fd < 0) 139 error("can't read ether stats"); 140 141 buf = smalloc(512); 142 n = kread(fd, buf, 511); 143 kclose(fd); 144 if(n <= 0) 145 error(Eio); 146 buf[n] = 0; 147 148 ptr = strstr(buf, "addr: "); 149 if(!ptr) 150 error(Eio); 151 ptr += 6; 152 153 parsemac(ifc->mac, ptr, 6); 154 155 /* 156 * open arp conversation 157 */ 158 snprint(addr, sizeof(addr), "%s!0x806", argv[2]); 159 fd = kdial(addr, nil, nil, nil); 160 if(fd < 0) 161 error("dial 0x806 failed"); 162 achan = commonfdtochan(fd, ORDWR, 0, 1); 163 kclose(fd); 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, ðermedium, ip, mac); 219 if(a){ 220 /* check for broadcast or multicast */ 221 bp = multicastarp(er->f, a, 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->lifc->local, 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 < ethermedium.minmtu) 388 n = ethermedium.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 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 0); 433 break; 434 435 case ARPREQUEST: 436 /* don't answer arps till we know who we are */ 437 if(ifc->lifc == 0) 438 break; 439 440 /* check for someone that think's they're me */ 441 v4tov6(ip, e->spa); 442 if(iplocalonifc(ifc, ip) || ipproxyifc(er->f, ifc, ip)){ 443 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) != 0) 444 print("arp: 0x%E also has ip addr %V\n", e->sha, e->spa); 445 } else { 446 if(memcmp(e->sha, ifc->mac, sizeof(e->sha)) == 0){ 447 print("arp: %V also has ether addr %E\n", e->spa, e->sha); 448 break; 449 } 450 } 451 452 /* refresh what we know about sender */ 453 arpenter(er->f, V4, e->spa, e->sha, sizeof(e->sha), 1); 454 455 /* answer only requests for our address or systems we're proxying for */ 456 v4tov6(ip, e->tpa); 457 if(!iplocalonifc(ifc, ip)) 458 if(!ipproxyifc(er->f, ifc, ip)) 459 break; 460 461 /* print("arp: rem %I %E (for %I)\n", e->spa, e->sha, e->tpa); /**/ 462 463 n = sizeof(Etherarp); 464 if(n < ifc->minmtu) 465 n = ifc->minmtu; 466 rbp = allocb(n); 467 r = (Etherarp*)rbp->rp; 468 memset(r, 0, sizeof(Etherarp)); 469 hnputs(r->type, ETARP); 470 hnputs(r->hrd, 1); 471 hnputs(r->pro, ETIP); 472 r->hln = sizeof(r->sha); 473 r->pln = sizeof(r->spa); 474 hnputs(r->op, ARPREPLY); 475 memmove(r->tha, e->sha, sizeof(r->tha)); 476 memmove(r->tpa, e->spa, sizeof(r->tpa)); 477 memmove(r->sha, ifc->mac, sizeof(r->sha)); 478 memmove(r->spa, e->tpa, sizeof(r->spa)); 479 memmove(r->d, e->sha, sizeof(r->d)); 480 memmove(r->s, ifc->mac, sizeof(r->s)); 481 rbp->wp += n; 482 483 n = devtab[er->achan->type]->bwrite(er->achan, rbp, 0); 484 if(n < 0) 485 print("arp: write: %r\n"); 486 } 487 freeb(ebp); 488 } 489 490 static void 491 recvarpproc(void *v) 492 { 493 Ipifc *ifc = v; 494 Etherrock *er = ifc->arg; 495 496 er->arpp = up; 497 if(waserror()){ 498 er->arpp = 0; 499 pexit("hangup", 1); 500 } 501 for(;;) 502 recvarp(ifc); 503 } 504 505 static int 506 multicastea(uchar *ea, uchar *ip) 507 { 508 int x; 509 510 switch(x = ipismulticast(ip)){ 511 case V4: 512 ea[0] = 0x01; 513 ea[1] = 0x00; 514 ea[2] = 0x5e; 515 ea[3] = ip[13] & 0x7f; 516 ea[4] = ip[14]; 517 ea[5] = ip[15]; 518 break; 519 case V6: 520 ea[0] = 0x33; 521 ea[1] = 0x33; 522 ea[2] = ip[12]; 523 ea[3] = ip[13]; 524 ea[4] = ip[14]; 525 ea[5] = ip[15]; 526 break; 527 } 528 return x; 529 } 530 531 /* 532 * fill in an arp entry for broadcast or multicast 533 * addresses 534 */ 535 static Block* 536 multicastarp(Fs *f, Arpent *a, uchar *mac) 537 { 538 /* is it broadcast? */ 539 switch(ipforme(f, a->ip)){ 540 case Runi: 541 return nil; 542 case Rbcast: 543 memset(mac, 0xff, 6); 544 return arpresolve(f->arp, a, ðermedium, mac); 545 default: 546 break; 547 } 548 549 /* if multicast, fill in mac */ 550 switch(multicastea(mac, a->ip)){ 551 case V4: 552 case V6: 553 return arpresolve(f->arp, a, ðermedium, mac); 554 } 555 556 /* let arp take care of it */ 557 return nil; 558 } 559 560 void 561 ethermediumlink(void) 562 { 563 addipmedium(ðermedium); 564 } 565