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