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 "ipv6.h" 10 11 /* 12 * address resolution tables 13 */ 14 15 enum 16 { 17 NHASH = (1<<6), 18 NCACHE = 256, 19 20 AOK = 1, 21 AWAIT = 2, 22 }; 23 24 char *arpstate[] = 25 { 26 "UNUSED", 27 "OK", 28 "WAIT", 29 }; 30 31 /* 32 * one per Fs 33 */ 34 struct Arp 35 { 36 QLock; 37 Fs *f; 38 Arpent *hash[NHASH]; 39 Arpent cache[NCACHE]; 40 Arpent *rxmt; 41 Proc *rxmitp; /* neib sol re-transmit proc */ 42 Rendez rxmtq; 43 Block *dropf, *dropl; 44 }; 45 46 char *Ebadarp = "bad arp"; 47 48 #define haship(s) ((s)[IPaddrlen-1]%NHASH) 49 50 extern int ReTransTimer = RETRANS_TIMER; 51 static void rxmitproc(void *v); 52 53 void 54 arpinit(Fs *f) 55 { 56 f->arp = smalloc(sizeof(Arp)); 57 f->arp->f = f; 58 f->arp->rxmt = nil; 59 f->arp->dropf = f->arp->dropl = nil; 60 kproc("rxmitproc", rxmitproc, f->arp, 0); 61 } 62 63 /* 64 * create a new arp entry for an ip address. 65 */ 66 static Arpent* 67 newarp6(Arp *arp, uchar *ip, Ipifc *ifc, int addrxt) 68 { 69 uint t; 70 Block *next, *xp; 71 Arpent *a, *e, *f, **l; 72 Medium *m = ifc->m; 73 int empty; 74 75 /* find oldest entry */ 76 e = &arp->cache[NCACHE]; 77 a = arp->cache; 78 t = a->utime; 79 for(f = a; f < e; f++){ 80 if(f->utime < t){ 81 t = f->utime; 82 a = f; 83 } 84 } 85 86 /* dump waiting packets */ 87 xp = a->hold; 88 a->hold = nil; 89 90 if(isv4(a->ip)){ 91 while(xp){ 92 next = xp->list; 93 freeblist(xp); 94 xp = next; 95 } 96 } 97 else { // queue icmp unreachable for rxmitproc later on, w/o arp lock 98 if(xp){ 99 if(arp->dropl == nil) 100 arp->dropf = xp; 101 else 102 arp->dropl->list = xp; 103 104 for(next = xp->list; next; next = next->list) 105 xp = next; 106 arp->dropl = xp; 107 wakeup(&arp->rxmtq); 108 } 109 } 110 111 /* take out of current chain */ 112 l = &arp->hash[haship(a->ip)]; 113 for(f = *l; f; f = f->hash){ 114 if(f == a){ 115 *l = a->hash; 116 break; 117 } 118 l = &f->hash; 119 } 120 121 /* insert into new chain */ 122 l = &arp->hash[haship(ip)]; 123 a->hash = *l; 124 *l = a; 125 126 memmove(a->ip, ip, sizeof(a->ip)); 127 a->utime = NOW; 128 a->ctime = 0; 129 a->type = m; 130 131 a->rtime = NOW + ReTransTimer; 132 a->rxtsrem = MAX_MULTICAST_SOLICIT; 133 a->ifc = ifc; 134 a->ifcid = ifc->ifcid; 135 136 /* put to the end of re-transmit chain; addrxt is 0 when isv4(a->ip) */ 137 if(!ipismulticast(a->ip) && addrxt){ 138 l = &arp->rxmt; 139 empty = (*l==nil); 140 141 for(f = *l; f; f = f->nextrxt){ 142 if(f == a){ 143 *l = a->nextrxt; 144 break; 145 } 146 l = &f->nextrxt; 147 } 148 for(f = *l; f; f = f->nextrxt){ 149 l = &f->nextrxt; 150 } 151 *l = a; 152 if(empty) 153 wakeup(&arp->rxmtq); 154 } 155 156 a->nextrxt = nil; 157 158 return a; 159 } 160 161 /* called with arp qlocked */ 162 163 void 164 cleanarpent(Arp *arp, Arpent *a) 165 { 166 Arpent *f, **l; 167 168 a->utime = 0; 169 a->ctime = 0; 170 a->type = 0; 171 a->state = 0; 172 173 /* take out of current chain */ 174 l = &arp->hash[haship(a->ip)]; 175 for(f = *l; f; f = f->hash){ 176 if(f == a){ 177 *l = a->hash; 178 break; 179 } 180 l = &f->hash; 181 } 182 183 /* take out of re-transmit chain */ 184 l = &arp->rxmt; 185 for(f = *l; f; f = f->nextrxt){ 186 if(f == a){ 187 *l = a->nextrxt; 188 break; 189 } 190 l = &f->nextrxt; 191 } 192 a->nextrxt = nil; 193 a->hash = nil; 194 a->hold = nil; 195 a->last = nil; 196 a->ifc = nil; 197 } 198 199 /* 200 * fill in the media address if we have it. Otherwise return an 201 * Arpent that represents the state of the address resolution FSM 202 * for ip. Add the packet to be sent onto the list of packets 203 * waiting for ip->mac to be resolved. 204 */ 205 Arpent* 206 arpget(Arp *arp, Block *bp, int version, Ipifc *ifc, uchar *ip, uchar *mac) 207 { 208 int hash; 209 Arpent *a; 210 Medium *type = ifc->m; 211 uchar v6ip[IPaddrlen]; 212 213 if(version == V4){ 214 v4tov6(v6ip, ip); 215 ip = v6ip; 216 } 217 218 qlock(arp); 219 hash = haship(ip); 220 for(a = arp->hash[hash]; a; a = a->hash){ 221 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0) 222 if(type == a->type) 223 break; 224 } 225 226 if(a == nil){ 227 a = newarp6(arp, ip, ifc, (version != V4)); 228 a->state = AWAIT; 229 } 230 a->utime = NOW; 231 if(a->state == AWAIT){ 232 if(bp != nil){ 233 if(a->hold) 234 a->last->list = bp; 235 else 236 a->hold = bp; 237 a->last = bp; 238 bp->list = nil; 239 } 240 return a; /* return with arp qlocked */ 241 } 242 243 memmove(mac, a->mac, a->type->maclen); 244 245 /* remove old entries */ 246 if(NOW - a->ctime > 15*60*1000) 247 cleanarpent(arp, a); 248 249 qunlock(arp); 250 return nil; 251 } 252 253 /* 254 * called with arp locked 255 */ 256 void 257 arprelease(Arp *arp, Arpent*) 258 { 259 qunlock(arp); 260 } 261 262 /* 263 * Copy out the mac address from the Arpent. Return the 264 * block waiting to get sent to this mac address. 265 * 266 * called with arp locked 267 */ 268 Block* 269 arpresolve(Arp *arp, Arpent *a, Medium *type, uchar *mac) 270 { 271 Block *bp; 272 Arpent *f, **l; 273 274 if(!isv4(a->ip)){ 275 l = &arp->rxmt; 276 for(f = *l; f; f = f->nextrxt){ 277 if(f == a){ 278 *l = a->nextrxt; 279 break; 280 } 281 l = &f->nextrxt; 282 } 283 } 284 285 memmove(a->mac, mac, type->maclen); 286 a->type = type; 287 a->state = AOK; 288 a->utime = NOW; 289 bp = a->hold; 290 a->hold = nil; 291 qunlock(arp); 292 293 return bp; 294 } 295 296 void 297 arpenter(Fs *fs, int version, uchar *ip, uchar *mac, int n, int refresh) 298 { 299 Arp *arp; 300 Route *r; 301 Arpent *a, *f, **l; 302 Ipifc *ifc; 303 Medium *type; 304 Block *bp, *next; 305 uchar v6ip[IPaddrlen]; 306 307 arp = fs->arp; 308 309 if(n != 6){ 310 // print("arp: len = %d\n", n); 311 return; 312 } 313 314 switch(version){ 315 case V4: 316 r = v4lookup(fs, ip, nil); 317 v4tov6(v6ip, ip); 318 ip = v6ip; 319 break; 320 case V6: 321 r = v6lookup(fs, ip, nil); 322 break; 323 default: 324 panic("arpenter: version %d", version); 325 return; /* to supress warnings */ 326 } 327 328 if(r == nil){ 329 // print("arp: no route for entry\n"); 330 return; 331 } 332 333 ifc = r->ifc; 334 type = ifc->m; 335 336 qlock(arp); 337 for(a = arp->hash[haship(ip)]; a; a = a->hash){ 338 if(a->type != type || (a->state != AWAIT && a->state != AOK)) 339 continue; 340 341 if(ipcmp(a->ip, ip) == 0){ 342 a->state = AOK; 343 memmove(a->mac, mac, type->maclen); 344 345 if(version == V6){ 346 /* take out of re-transmit chain */ 347 l = &arp->rxmt; 348 for(f = *l; f; f = f->nextrxt){ 349 if(f == a){ 350 *l = a->nextrxt; 351 break; 352 } 353 l = &f->nextrxt; 354 } 355 } 356 357 a->ifc = ifc; 358 a->ifcid = ifc->ifcid; 359 bp = a->hold; 360 a->hold = nil; 361 if(version == V4) 362 ip += IPv4off; 363 a->utime = NOW; 364 a->ctime = a->utime; 365 qunlock(arp); 366 367 while(bp){ 368 next = bp->list; 369 if(ifc != nil){ 370 if(waserror()){ 371 runlock(ifc); 372 nexterror(); 373 } 374 rlock(ifc); 375 if(ifc->m != nil) 376 ifc->m->bwrite(ifc, bp, version, ip); 377 else 378 freeb(bp); 379 runlock(ifc); 380 poperror(); 381 } else 382 freeb(bp); 383 bp = next; 384 } 385 return; 386 } 387 } 388 389 if(refresh == 0){ 390 a = newarp6(arp, ip, ifc, 0); 391 a->state = AOK; 392 a->type = type; 393 a->ctime = NOW; 394 memmove(a->mac, mac, type->maclen); 395 } 396 397 qunlock(arp); 398 } 399 400 int 401 arpwrite(Fs *fs, char *s, int len) 402 { 403 int n; 404 Route *r; 405 Arp *arp; 406 Block *bp; 407 Arpent *a, *fl, **l; 408 Medium *m; 409 char *f[4], buf[256]; 410 uchar ip[IPaddrlen], mac[MAClen]; 411 412 arp = fs->arp; 413 414 if(len == 0) 415 error(Ebadarp); 416 if(len >= sizeof(buf)) 417 len = sizeof(buf)-1; 418 strncpy(buf, s, len); 419 buf[len] = 0; 420 if(len > 0 && buf[len-1] == '\n') 421 buf[len-1] = 0; 422 423 n = getfields(buf, f, 4, 1, " "); 424 if(strcmp(f[0], "flush") == 0){ 425 qlock(arp); 426 for(a = arp->cache; a < &arp->cache[NCACHE]; a++){ 427 memset(a->ip, 0, sizeof(a->ip)); 428 memset(a->mac, 0, sizeof(a->mac)); 429 a->hash = nil; 430 a->state = 0; 431 a->utime = 0; 432 while(a->hold != nil){ 433 bp = a->hold->list; 434 freeblist(a->hold); 435 a->hold = bp; 436 } 437 } 438 memset(arp->hash, 0, sizeof(arp->hash)); 439 // clear all pkts on these lists (rxmt, dropf/l) 440 arp->rxmt = nil; 441 arp->dropf = nil; 442 arp->dropl = nil; 443 qunlock(arp); 444 } else if(strcmp(f[0], "add") == 0){ 445 switch(n){ 446 default: 447 error(Ebadarg); 448 case 3: 449 parseip(ip, f[1]); 450 if(isv4(ip)) 451 r = v4lookup(fs, ip+IPv4off, nil); 452 else 453 r = v6lookup(fs, ip, nil); 454 if(r == nil) 455 error("Destination unreachable"); 456 m = r->ifc->m; 457 n = parsemac(mac, f[2], m->maclen); 458 break; 459 case 4: 460 m = ipfindmedium(f[1]); 461 if(m == nil) 462 error(Ebadarp); 463 parseip(ip, f[2]); 464 n = parsemac(mac, f[3], m->maclen); 465 break; 466 } 467 468 if(m->ares == nil) 469 error(Ebadarp); 470 471 m->ares(fs, V6, ip, mac, n, 0); 472 } else if(strcmp(f[0], "del") == 0){ 473 if(n != 2) 474 error(Ebadarg); 475 476 parseip(ip, f[1]); 477 qlock(arp); 478 479 l = &arp->hash[haship(ip)]; 480 for(a = *l; a; a = a->hash){ 481 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){ 482 *l = a->hash; 483 break; 484 } 485 l = &a->hash; 486 } 487 488 if(a){ 489 /* take out of re-transmit chain */ 490 l = &arp->rxmt; 491 for(fl = *l; fl; fl = fl->nextrxt){ 492 if(fl == a){ 493 *l = a->nextrxt; 494 break; 495 } 496 l = &fl->nextrxt; 497 } 498 499 a->nextrxt = nil; 500 a->hash = nil; 501 a->hold = nil; 502 a->last = nil; 503 a->ifc = nil; 504 memset(a->ip, 0, sizeof(a->ip)); 505 memset(a->mac, 0, sizeof(a->mac)); 506 } 507 qunlock(arp); 508 } else 509 error(Ebadarp); 510 511 return len; 512 } 513 514 enum 515 { 516 Alinelen= 90, 517 }; 518 519 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n"; 520 521 static void 522 convmac(char *p, uchar *mac, int n) 523 { 524 while(n-- > 0) 525 p += sprint(p, "%2.2ux", *mac++); 526 } 527 528 int 529 arpread(Arp *arp, char *p, ulong offset, int len) 530 { 531 Arpent *a; 532 int n; 533 char mac[2*MAClen+1]; 534 535 if(offset % Alinelen) 536 return 0; 537 538 offset = offset/Alinelen; 539 len = len/Alinelen; 540 541 n = 0; 542 for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){ 543 if(a->state == 0) 544 continue; 545 if(offset > 0){ 546 offset--; 547 continue; 548 } 549 len--; 550 qlock(arp); 551 convmac(mac, a->mac, a->type->maclen); 552 n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac); 553 qunlock(arp); 554 } 555 556 return n; 557 } 558 559 extern int 560 rxmitsols(Arp *arp) 561 { 562 uint sflag; 563 Block *next, *xp; 564 Arpent *a, *b, **l; 565 Fs *f; 566 uchar ipsrc[IPaddrlen]; 567 Ipifc *ifc = nil; 568 long nrxt; 569 570 qlock(arp); 571 f = arp->f; 572 573 a = arp->rxmt; 574 if(a==nil){ 575 nrxt = 0; 576 goto dodrops; //return nrxt; 577 } 578 nrxt = a->rtime - NOW; 579 if(nrxt > 3*ReTransTimer/4) 580 goto dodrops; //return nrxt; 581 582 for(; a; a = a->nextrxt){ 583 ifc = a->ifc; 584 assert(ifc != nil); 585 if((a->rxtsrem <= 0) || !(canrlock(ifc)) || (a->ifcid != ifc->ifcid)){ 586 xp = a->hold; 587 a->hold = nil; 588 589 if(xp){ 590 if(arp->dropl == nil) 591 arp->dropf = xp; 592 else 593 arp->dropl->list = xp; 594 } 595 596 cleanarpent(arp, a); 597 } 598 else 599 break; 600 } 601 if(a == nil) 602 goto dodrops; 603 604 605 qunlock(arp); /* for icmpns */ 606 if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) 607 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 608 609 runlock(ifc); 610 qlock(arp); 611 612 /* put to the end of re-transmit chain */ 613 l = &arp->rxmt; 614 for(b = *l; b; b = b->nextrxt){ 615 if(b == a){ 616 *l = a->nextrxt; 617 break; 618 } 619 l = &b->nextrxt; 620 } 621 for(b = *l; b; b = b->nextrxt){ 622 l = &b->nextrxt; 623 } 624 *l = a; 625 a->rxtsrem--; 626 a->nextrxt = nil; 627 a->rtime = NOW + ReTransTimer; 628 629 a = arp->rxmt; 630 if(a==nil) 631 nrxt = 0; 632 else 633 nrxt = a->rtime - NOW; 634 635 dodrops: 636 xp = arp->dropf; 637 arp->dropf = nil; 638 arp->dropl = nil; 639 qunlock(arp); 640 641 for(; xp; xp = next){ 642 next = xp->list; 643 icmphostunr(f, ifc, xp, icmp6_adr_unreach, 1); 644 } 645 646 return nrxt; 647 648 } 649 650 static int 651 rxready(void *v) 652 { 653 Arp *arp = (Arp *) v; 654 int x; 655 656 x = ((arp->rxmt != nil) || (arp->dropf != nil)); 657 658 return x; 659 } 660 661 static void 662 rxmitproc(void *v) 663 { 664 Arp *arp = v; 665 long wakeupat; 666 667 arp->rxmitp = up; 668 //print("arp rxmitproc started\n"); 669 if(waserror()){ 670 arp->rxmitp = 0; 671 pexit("hangup", 1); 672 } 673 for(;;){ 674 wakeupat = rxmitsols(arp); 675 if(wakeupat == 0) 676 sleep(&arp->rxmtq, rxready, v); 677 else if(wakeupat > ReTransTimer/4) 678 tsleep(&arp->rxmtq, return0, 0, wakeupat); 679 } 680 } 681 682