arp.c (11314B)
1 #include "u.h" 2 #include "lib.h" 3 #include "mem.h" 4 #include "dat.h" 5 #include "fns.h" 6 #include "error.h" 7 8 #include "ip.h" 9 #include "ipv6.h" 10 11 /* 12 * address resolution tables 13 */ 14 enum 15 { 16 NHASH = (1<<6), 17 NCACHE = 256, 18 19 AOK = 1, 20 AWAIT = 2, 21 }; 22 23 char *arpstate[] = 24 { 25 "UNUSED", 26 "OK", 27 "WAIT", 28 }; 29 30 /* 31 * one per Fs 32 */ 33 struct Arp 34 { 35 QLock qlock; 36 Fs *f; 37 Arpent *hash[NHASH]; 38 Arpent cache[NCACHE]; 39 Arpent *rxmt; 40 Proc *rxmitp; /* neib sol re-transmit proc */ 41 Rendez rxmtq; 42 Block *dropf, *dropl; 43 }; 44 45 char *Ebadarp = "bad arp"; 46 47 #define haship(s) ((ulong)((s)[IPaddrlen-1])%NHASH) 48 49 int ReTransTimer = RETRANS_TIMER; 50 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); 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* ae) 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 if (parseip(ip, f[1]) == -1) 450 error(Ebadip); 451 if(isv4(ip)) 452 r = v4lookup(fs, ip+IPv4off, nil); 453 else 454 r = v6lookup(fs, ip, nil); 455 if(r == nil) 456 error("Destination unreachable"); 457 m = r->ifc->m; 458 n = parsemac(mac, f[2], m->maclen); 459 break; 460 case 4: 461 m = ipfindmedium(f[1]); 462 if(m == nil) 463 error(Ebadarp); 464 if (parseip(ip, f[2]) == -1) 465 error(Ebadip); 466 n = parsemac(mac, f[3], m->maclen); 467 break; 468 } 469 470 if(m->ares == nil) 471 error(Ebadarp); 472 473 m->ares(fs, V6, ip, mac, n, 0); 474 } else if(strcmp(f[0], "del") == 0){ 475 if(n != 2) 476 error(Ebadarg); 477 478 if (parseip(ip, f[1]) == -1) 479 error(Ebadip); 480 QLOCK(arp); 481 482 l = &arp->hash[haship(ip)]; 483 for(a = *l; a; a = a->hash){ 484 if(memcmp(ip, a->ip, sizeof(a->ip)) == 0){ 485 *l = a->hash; 486 break; 487 } 488 l = &a->hash; 489 } 490 491 if(a){ 492 /* take out of re-transmit chain */ 493 l = &arp->rxmt; 494 for(fl = *l; fl; fl = fl->nextrxt){ 495 if(fl == a){ 496 *l = a->nextrxt; 497 break; 498 } 499 l = &fl->nextrxt; 500 } 501 502 a->nextrxt = nil; 503 a->hash = nil; 504 a->hold = nil; 505 a->last = nil; 506 a->ifc = nil; 507 memset(a->ip, 0, sizeof(a->ip)); 508 memset(a->mac, 0, sizeof(a->mac)); 509 } 510 QUNLOCK(arp); 511 } else 512 error(Ebadarp); 513 514 return len; 515 } 516 517 enum 518 { 519 Alinelen= 90, 520 }; 521 522 char *aformat = "%-6.6s %-8.8s %-40.40I %-32.32s\n"; 523 524 static void 525 convmac(char *p, uchar *mac, int n) 526 { 527 while(n-- > 0) 528 p += sprint(p, "%2.2ux", *mac++); 529 } 530 531 int 532 arpread(Arp *arp, char *p, ulong offset, int len) 533 { 534 Arpent *a; 535 int n; 536 char mac[2*MAClen+1]; 537 538 if(offset % Alinelen) 539 return 0; 540 541 offset = offset/Alinelen; 542 len = len/Alinelen; 543 544 n = 0; 545 for(a = arp->cache; len > 0 && a < &arp->cache[NCACHE]; a++){ 546 if(a->state == 0) 547 continue; 548 if(offset > 0){ 549 offset--; 550 continue; 551 } 552 len--; 553 QLOCK(arp); 554 convmac(mac, a->mac, a->type->maclen); 555 n += sprint(p+n, aformat, a->type->name, arpstate[a->state], a->ip, mac); 556 QUNLOCK(arp); 557 } 558 559 return n; 560 } 561 562 extern int 563 rxmitsols(Arp *arp) 564 { 565 uint sflag; 566 Block *next, *xp; 567 Arpent *a, *b, **l; 568 Fs *f; 569 uchar ipsrc[IPaddrlen]; 570 Ipifc *ifc = nil; 571 long nrxt; 572 573 QLOCK(arp); 574 f = arp->f; 575 576 a = arp->rxmt; 577 if(a==nil){ 578 nrxt = 0; 579 goto dodrops; /* return nrxt; */ 580 } 581 nrxt = a->rtime - NOW; 582 if(nrxt > 3*ReTransTimer/4) 583 goto dodrops; /* return nrxt; */ 584 585 for(; a; a = a->nextrxt){ 586 ifc = a->ifc; 587 assert(ifc != nil); 588 if((a->rxtsrem <= 0) || !(CANRLOCK(ifc)) || (a->ifcid != ifc->ifcid)){ 589 xp = a->hold; 590 a->hold = nil; 591 592 if(xp){ 593 if(arp->dropl == nil) 594 arp->dropf = xp; 595 else 596 arp->dropl->list = xp; 597 } 598 599 cleanarpent(arp, a); 600 } 601 else 602 break; 603 } 604 if(a == nil) 605 goto dodrops; 606 607 608 QUNLOCK(arp); /* for icmpns */ 609 if((sflag = ipv6anylocal(ifc, ipsrc)) != SRC_UNSPEC) 610 icmpns(f, ipsrc, sflag, a->ip, TARG_MULTI, ifc->mac); 611 612 RUNLOCK(ifc); 613 QLOCK(arp); 614 615 /* put to the end of re-transmit chain */ 616 l = &arp->rxmt; 617 for(b = *l; b; b = b->nextrxt){ 618 if(b == a){ 619 *l = a->nextrxt; 620 break; 621 } 622 l = &b->nextrxt; 623 } 624 for(b = *l; b; b = b->nextrxt){ 625 l = &b->nextrxt; 626 } 627 *l = a; 628 a->rxtsrem--; 629 a->nextrxt = nil; 630 a->rtime = NOW + ReTransTimer; 631 632 a = arp->rxmt; 633 if(a==nil) 634 nrxt = 0; 635 else 636 nrxt = a->rtime - NOW; 637 638 dodrops: 639 xp = arp->dropf; 640 arp->dropf = nil; 641 arp->dropl = nil; 642 QUNLOCK(arp); 643 644 for(; xp; xp = next){ 645 next = xp->list; 646 icmphostunr(f, ifc, xp, Icmp6_adr_unreach, 1); 647 } 648 649 return nrxt; 650 651 } 652 653 static int 654 rxready(void *v) 655 { 656 Arp *arp = (Arp *) v; 657 int x; 658 659 x = ((arp->rxmt != nil) || (arp->dropf != nil)); 660 661 return x; 662 } 663 664 static void 665 rxmitproc(void *v) 666 { 667 Arp *arp = v; 668 long wakeupat; 669 670 arp->rxmitp = up; 671 //print("arp rxmitproc started\n"); 672 if(waserror()){ 673 arp->rxmitp = 0; 674 pexit("hangup", 1); 675 } 676 for(;;){ 677 wakeupat = rxmitsols(arp); 678 if(wakeupat == 0) 679 sleep(&arp->rxmtq, rxready, v); 680 else if(wakeupat > ReTransTimer/4) 681 tsleep(&arp->rxmtq, return0, 0, wakeupat); 682 } 683 } 684