1 /* 2 * ntp_peer.c - management of data maintained for peer associations 3 */ 4 #ifdef HAVE_CONFIG_H 5 #include <config.h> 6 #endif 7 8 #include <stdio.h> 9 #include <sys/types.h> 10 11 #include "ntpd.h" 12 #include "ntp_stdlib.h" 13 14 /* 15 * Table of valid association combinations 16 * --------------------------------------- 17 * 18 * packet->mode 19 * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST 20 * ---------- | --------------------------------------------- 21 * NO_PEER | e 1 e 1 1 1 22 * ACTIVE | e 1 1 0 0 0 23 * PASSIVE | e 1 e 0 0 0 24 * CLIENT | e 0 0 0 1 1 25 * SERVER | e 0 0 0 0 0 26 * BCAST | e 0 0 0 0 0 27 * CONTROL | e 0 0 0 0 0 28 * PRIVATE | e 0 0 0 0 0 29 * BCLIENT | e 0 0 0 e 1 30 * MCLIENT | e 0 0 0 0 0 31 * 32 * One point to note here: 33 * a packet in BCAST mode can potentially match a peer in CLIENT 34 * mode, but we that is a special case and we check for that early 35 * in the decision process. This avoids having to keep track of 36 * what kind of associations are possible etc... We actually 37 * circumvent that problem by requiring that the first b(m)roadcast 38 * received after the change back to BCLIENT mode sets the clock. 39 */ 40 41 int AM[AM_MODES][AM_MODES] = { 42 /* { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */ 43 44 /*NONE*/{ AM_ERR, AM_NEWPASS, AM_ERR, AM_FXMIT, AM_MANYCAST, AM_NEWBCL}, 45 46 /*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 47 48 /*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 49 50 /*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_POSSBCL}, 51 52 /*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 53 54 /*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 55 56 /*CNTL*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 57 58 /*PRIV*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 59 60 /*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_ERR, AM_PROCPKT}, 61 62 /*MCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH} 63 }; 64 65 #define MATCH_ASSOC(x,y) AM[(x)][(y)] 66 67 /* 68 * These routines manage the allocation of memory to peer structures 69 * and the maintenance of the peer hash table. The two main entry 70 * points are findpeer(), which looks for corresponding peer data 71 * in the peer list, newpeer(), which allocates a new peer structure 72 * and adds it to the list, and unpeer(), which demobilizes the association 73 * and deallocates the structure. 74 */ 75 76 /* 77 * The peer hash table (imported by the protocol module). 78 */ 79 struct peer *peer_hash[HASH_SIZE]; 80 int peer_hash_count[HASH_SIZE]; /* count of peers in each bucket */ 81 82 /* 83 * The association ID hash table. Used for lookups by association ID 84 */ 85 struct peer *assoc_hash[HASH_SIZE]; 86 int assoc_hash_count[HASH_SIZE]; 87 88 /* 89 * The free list. Clean structures only, please. 90 */ 91 static struct peer *peer_free; 92 int peer_free_count; 93 94 /* 95 * Association ID. We initialize this value randomly, the assign a new 96 * value every time the peer structure is incremented. 97 */ 98 static u_short current_association_ID; 99 100 /* 101 * Memory allocation watermarks. 102 */ 103 #define INIT_PEER_ALLOC 15 /* initialize space for 15 peers */ 104 #define INC_PEER_ALLOC 5 /* when we run out, add 5 more */ 105 106 /* 107 * Miscellaneous statistic counters which may be queried. 108 */ 109 u_long peer_timereset; /* time stat counters were zeroed */ 110 u_long findpeer_calls; /* number of calls to findpeer */ 111 u_long assocpeer_calls; /* number of calls to findpeerbyassoc */ 112 u_long peer_allocations; /* number of allocations from the free list */ 113 u_long peer_demobilizations; /* number of structs freed to free list */ 114 int total_peer_structs; /* number of peer structs in circulation */ 115 int peer_associations; /* number of active associations */ 116 117 /* 118 * Our initial allocation of peer space 119 */ 120 static struct peer init_peer_alloc[INIT_PEER_ALLOC]; 121 122 /* 123 * Initialization data. When configuring peers at initialization time, 124 * we try to get their poll update timers initialized to different values 125 * to prevent us from sending big clumps of data all at once. 126 */ 127 /* static u_long init_peer_starttime; */ 128 129 static void getmorepeermem P((void)); 130 static void key_expire P((struct peer *)); 131 132 /* 133 * init_peer - initialize peer data structures and counters 134 * 135 * N.B. We use the random number routine in here. It had better be 136 * initialized prior to getting here. 137 */ 138 void 139 init_peer(void) 140 { 141 register int i; 142 143 /* 144 * Clear hash table and counters. 145 */ 146 for (i = 0; i < HASH_SIZE; i++) { 147 peer_hash[i] = 0; 148 peer_hash_count[i] = 0; 149 assoc_hash[i] = 0; 150 assoc_hash_count[i] = 0; 151 } 152 153 /* 154 * Clear stat counters 155 */ 156 findpeer_calls = peer_allocations = 0; 157 assocpeer_calls = peer_demobilizations = 0; 158 159 /* 160 * Initialization counter. 161 */ 162 /* init_peer_starttime = 0; */ 163 164 /* 165 * Initialize peer memory. 166 */ 167 peer_free = 0; 168 for (i = 0; i < INIT_PEER_ALLOC; i++) { 169 init_peer_alloc[i].next = peer_free; 170 peer_free = &init_peer_alloc[i]; 171 } 172 total_peer_structs = INIT_PEER_ALLOC; 173 peer_free_count = INIT_PEER_ALLOC; 174 175 /* 176 * Initialize our first association ID 177 */ 178 current_association_ID = (u_short)ranp2(16); 179 if (current_association_ID == 0) 180 current_association_ID = 1; 181 } 182 183 184 /* 185 * getmorepeermem - add more peer structures to the free list 186 */ 187 static void 188 getmorepeermem(void) 189 { 190 register int i; 191 register struct peer *peer; 192 193 peer = (struct peer *)emalloc(INC_PEER_ALLOC*sizeof(struct peer)); 194 for (i = 0; i < INC_PEER_ALLOC; i++) { 195 peer->next = peer_free; 196 peer_free = peer; 197 peer++; 198 } 199 200 total_peer_structs += INC_PEER_ALLOC; 201 peer_free_count += INC_PEER_ALLOC; 202 } 203 204 205 206 /* 207 * findexistingpeer - return a pointer to a peer in the hash table 208 */ 209 struct peer * 210 findexistingpeer( 211 struct sockaddr_in *addr, 212 struct peer *start_peer, 213 int mode 214 ) 215 { 216 register struct peer *peer; 217 218 /* 219 * start_peer is included so we can locate instances of the 220 * same peer through different interfaces in the hash table. 221 */ 222 if (start_peer == 0) 223 peer = peer_hash[HASH_ADDR(addr)]; 224 else 225 peer = start_peer->next; 226 227 while (peer != 0) { 228 if (NSRCADR(addr) == NSRCADR(&peer->srcadr) 229 && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) { 230 if (mode == -1) 231 return peer; 232 else if (peer->hmode == mode) 233 break; 234 } 235 peer = peer->next; 236 } 237 238 return peer; 239 } 240 241 242 /* 243 * findpeer - find and return a peer in the hash table. 244 */ 245 struct peer * 246 findpeer( 247 struct sockaddr_in *srcadr, 248 struct interface *dstadr, 249 int fd, 250 int pkt_mode, 251 int *action 252 ) 253 { 254 register struct peer *peer; 255 int hash; 256 257 findpeer_calls++; 258 hash = HASH_ADDR(srcadr); 259 for (peer = peer_hash[hash]; peer != 0; peer = peer->next) { 260 if (NSRCADR(srcadr) == NSRCADR(&peer->srcadr) 261 && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) { 262 /* 263 * if the association matching rules determine that 264 * this is not a valid combination, then look for 265 * the next valid peer association. 266 */ 267 *action = MATCH_ASSOC(peer->hmode, pkt_mode); 268 269 /* 270 * Sigh! Check if BCLIENT peer in client 271 * server mode, else return error 272 */ 273 if ((*action == AM_POSSBCL) && 274 !(peer->cast_flags & FLAG_MCAST1)) { 275 *action = AM_ERR; 276 } 277 278 /* if an error was returned, exit back right here */ 279 if (*action == AM_ERR) 280 return (struct peer *)0; 281 282 /* if a match is found, we stop our search */ 283 if (*action != AM_NOMATCH) 284 break; 285 } 286 } 287 288 #ifdef DEBUG 289 if (debug > 1) 290 printf("pkt_mode %d action %d\n", pkt_mode, *action); 291 #endif 292 /* if no matching association is found */ 293 if (peer == 0) { 294 *action = MATCH_ASSOC(NO_PEER, pkt_mode); 295 #ifdef DEBUG 296 if (debug > 1) 297 printf("pkt_mode %d action %d\n", pkt_mode, *action); 298 #endif 299 return (struct peer *)0; 300 } 301 302 /* reset the default interface to something more meaningful */ 303 if ((peer->dstadr == any_interface)) 304 peer->dstadr = dstadr; 305 return peer; 306 } 307 308 /* 309 * findpeerbyassocid - find and return a peer using his association ID 310 */ 311 struct peer * 312 findpeerbyassoc( 313 int assoc 314 ) 315 { 316 register struct peer *peer; 317 int hash; 318 319 assocpeer_calls++; 320 321 hash = assoc & HASH_MASK; 322 for (peer = assoc_hash[hash]; peer != 0; peer = peer->ass_next) { 323 if ((u_short)assoc == peer->associd) 324 return peer; /* got it! */ 325 } 326 327 /* 328 * Out of luck. Return 0. 329 */ 330 return (struct peer *)0; 331 } 332 333 /* 334 * findmanycastpeer - find and return an manycast peer if it exists 335 * 336 * 337 * the current implementation loops across all hash-buckets 338 * 339 * *** THERE IS AN URGENT NEED TO CHANGE THIS *** 340 */ 341 struct peer * 342 findmanycastpeer( 343 l_fp *p_org 344 ) 345 { 346 register struct peer *peer; 347 register struct peer *manycast_peer = 0; 348 int i = 0; 349 350 for (i = 0; i < HASH_SIZE; i++) { 351 if (peer_hash_count[i] == 0) 352 continue; 353 354 for (peer = peer_hash[i]; peer != 0; peer = peer->next) { 355 if (peer->cast_flags & MDF_ACAST && 356 peer->flags & FLAG_CONFIG) { 357 if (L_ISEQU(&peer->xmt, p_org)) 358 return peer; /* got it */ 359 else 360 manycast_peer = peer; 361 } 362 } 363 } 364 365 /* 366 * Out of luck. Return the manycastpeer for what it is worth. 367 */ 368 return manycast_peer; 369 } 370 371 /* 372 * key_expire - garbage collect keys 373 */ 374 static void 375 key_expire( 376 struct peer *peer 377 ) 378 { 379 int i; 380 381 if (peer->keylist != 0) { 382 for (i = 0; i <= peer->keynumber; i++) 383 authtrust(peer->keylist[i], 0); 384 free(peer->keylist); 385 peer->keylist = 0; 386 } 387 if (peer->keyid > NTP_MAXKEY) { 388 authtrust(peer->keyid, 0); 389 peer->keyid = 0; 390 } 391 } 392 393 /* 394 * key_rekey - expire all keys and roll a new private value. Note the 395 * 32-bit mask is necessary for 64-bit u_longs. 396 */ 397 void 398 key_expire_all( 399 ) 400 { 401 struct peer *peer, *next_peer; 402 int n; 403 404 for (n = 0; n < HASH_SIZE; n++) { 405 for (peer = peer_hash[n]; peer != 0; peer = next_peer) { 406 next_peer = peer->next; 407 key_expire(peer); 408 } 409 } 410 sys_private = (u_long)RANDOM & 0xffffffff; 411 #ifdef DEBUG 412 if (debug) 413 printf("key_expire_all: at %lu private %08lx\n", 414 current_time, sys_private); 415 #endif 416 } 417 /* 418 * unpeer - remove peer structure from hash table and free structure 419 */ 420 void 421 unpeer( 422 struct peer *peer_to_remove 423 ) 424 { 425 int hash; 426 427 #ifdef DEBUG 428 if (debug > 1) 429 printf("demobilize %u\n", peer_to_remove->associd); 430 #endif 431 key_expire(peer_to_remove); 432 hash = HASH_ADDR(&peer_to_remove->srcadr); 433 peer_hash_count[hash]--; 434 peer_demobilizations++; 435 peer_associations--; 436 437 #ifdef REFCLOCK 438 /* 439 * If this peer is actually a clock, shut it down first 440 */ 441 if (peer_to_remove->flags & FLAG_REFCLOCK) 442 refclock_unpeer(peer_to_remove); 443 #endif 444 peer_to_remove->action = 0; /* disable timeout actions */ 445 if (peer_hash[hash] == peer_to_remove) 446 peer_hash[hash] = peer_to_remove->next; 447 else { 448 register struct peer *peer; 449 450 peer = peer_hash[hash]; 451 while (peer != 0 && peer->next != peer_to_remove) 452 peer = peer->next; 453 454 if (peer == 0) { 455 peer_hash_count[hash]++; 456 msyslog(LOG_ERR, "peer struct for %s not in table!", 457 ntoa(&peer->srcadr)); 458 } else { 459 peer->next = peer_to_remove->next; 460 } 461 } 462 463 /* 464 * Remove him from the association hash as well. 465 */ 466 hash = peer_to_remove->associd & HASH_MASK; 467 assoc_hash_count[hash]--; 468 if (assoc_hash[hash] == peer_to_remove) 469 assoc_hash[hash] = peer_to_remove->ass_next; 470 else { 471 register struct peer *peer; 472 473 peer = assoc_hash[hash]; 474 while (peer != 0 && peer->ass_next != peer_to_remove) 475 peer = peer->ass_next; 476 477 if (peer == 0) { 478 assoc_hash_count[hash]++; 479 msyslog(LOG_ERR, 480 "peer struct for %s not in association table!", 481 ntoa(&peer->srcadr)); 482 } else { 483 peer->ass_next = peer_to_remove->ass_next; 484 } 485 } 486 peer_to_remove->next = peer_free; 487 peer_free = peer_to_remove; 488 peer_free_count++; 489 } 490 491 492 /* 493 * peer_config - configure a new peer 494 */ 495 struct peer * 496 peer_config( 497 struct sockaddr_in *srcadr, 498 struct interface *dstadr, 499 int hmode, 500 int version, 501 int minpoll, 502 int maxpoll, 503 int flags, 504 int ttl, 505 u_long key 506 ) 507 { 508 register struct peer *peer; 509 510 /* 511 * See if we have this guy in the tables already. If 512 * so just mark him configured. 513 */ 514 peer = findexistingpeer(srcadr, (struct peer *)0, hmode); 515 if (dstadr != 0) { 516 while (peer != 0) { 517 if (peer->dstadr == dstadr) 518 break; 519 peer = findexistingpeer(srcadr, peer, hmode); 520 } 521 } 522 523 /* 524 * If we found one, just change his mode and mark him configured. 525 */ 526 if (peer != 0) { 527 peer->hmode = (u_char)hmode; 528 peer->version = (u_char)version; 529 peer->minpoll = (u_char)minpoll; 530 peer->maxpoll = (u_char)maxpoll; 531 peer->hpoll = peer->minpoll; 532 peer->ppoll = peer->minpoll; 533 peer->flags = flags | FLAG_CONFIG | 534 (peer->flags & FLAG_REFCLOCK); 535 peer->cast_flags = (hmode == MODE_BROADCAST) ? 536 IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)) ? MDF_MCAST : MDF_BCAST : MDF_UCAST; 537 peer->ttl = (u_char)ttl; 538 peer->keyid = key; 539 peer->keynumber = 0; 540 return peer; 541 } 542 543 /* 544 * If we're here this guy is unknown to us. Make a new peer 545 * structure for him. 546 */ 547 peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll, 548 ttl, key); 549 if (peer != 0) { 550 peer->flags |= flags | FLAG_CONFIG; 551 #ifdef DEBUG 552 if (debug) 553 printf("peer_config: %s mode %d vers %d min %d max %d flags 0x%04x ttl %d key %lu\n", 554 ntoa(&peer->srcadr), peer->hmode, peer->version, 555 peer->minpoll, peer->maxpoll, peer->flags, 556 peer->ttl, peer->keyid); 557 #endif 558 } 559 return peer; 560 } 561 562 563 /* 564 * newpeer - initialize a new peer association 565 */ 566 struct peer * 567 newpeer( 568 struct sockaddr_in *srcadr, 569 struct interface *dstadr, 570 int hmode, 571 int version, 572 int minpoll, 573 int maxpoll, 574 int ttl, 575 u_long key 576 ) 577 { 578 register struct peer *peer; 579 register int i; 580 581 /* 582 * Some dirt here. Some of the initialization requires 583 * knowlege of our system state. 584 */ 585 if (peer_free_count == 0) 586 getmorepeermem(); 587 588 peer = peer_free; 589 peer_free = peer->next; 590 peer_free_count--; 591 peer_associations++; 592 593 /* 594 * Initialize the structure. This stuff is sort of part of 595 * the receive procedure and part of the clear procedure rolled 596 * into one. 597 * 598 * Zero the whole thing for now. We might be pickier later. 599 */ 600 memset((char *)peer, 0, sizeof(struct peer)); 601 602 peer->srcadr = *srcadr; 603 if (dstadr != 0) 604 peer->dstadr = dstadr; 605 else if (hmode == MODE_BROADCAST) 606 peer->dstadr = findbcastinter(srcadr); 607 else 608 peer->dstadr = any_interface; 609 peer->cast_flags = (hmode == MODE_BROADCAST) ? 610 (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr))) ? MDF_MCAST : 611 MDF_BCAST : (hmode == MODE_BCLIENT || hmode == MODE_MCLIENT) ? 612 (peer->dstadr->flags & INT_MULTICAST) ? MDF_MCAST : MDF_BCAST : 613 MDF_UCAST; 614 /* Set manycast flags if appropriate */ 615 if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)) && hmode == MODE_CLIENT) 616 peer->cast_flags = MDF_ACAST; 617 peer->hmode = (u_char)hmode; 618 peer->keyid = key; 619 peer->version = (u_char)version; 620 peer->minpoll = (u_char)minpoll; 621 peer->maxpoll = (u_char)maxpoll; 622 peer->hpoll = peer->minpoll; 623 peer->ppoll = peer->minpoll; 624 peer->ttl = ttl; 625 peer->leap = LEAP_NOTINSYNC; 626 peer->precision = sys_precision; 627 peer->variance = MAXDISPERSE; 628 peer->epoch = current_time; 629 peer->stratum = STRATUM_UNSPEC; 630 peer_clear(peer); 631 peer->update = peer->outdate = current_time; 632 peer->nextdate = peer->outdate + RANDPOLL(NTP_MINPOLL); 633 if (peer->flags & FLAG_BURST) 634 peer->burst = NTP_SHIFT; 635 636 /* 637 * Assign him an association ID and increment the system variable 638 */ 639 peer->associd = current_association_ID; 640 if (++current_association_ID == 0) 641 ++current_association_ID; 642 643 /* 644 * Note time on statistics timers. 645 */ 646 peer->timereset = current_time; 647 peer->timereachable = current_time; 648 peer->timereceived = current_time; 649 650 #ifdef REFCLOCK 651 if (ISREFCLOCKADR(&peer->srcadr)) { 652 /* 653 * We let the reference clock support do clock 654 * dependent initialization. This includes setting 655 * the peer timer, since the clock may have requirements 656 * for this. 657 */ 658 if (!refclock_newpeer(peer)) { 659 /* 660 * Dump it, something screwed up 661 */ 662 peer->next = peer_free; 663 peer_free = peer; 664 peer_free_count++; 665 return 0; 666 } 667 } 668 #endif 669 670 /* 671 * Put him in the hash tables. 672 */ 673 i = HASH_ADDR(&peer->srcadr); 674 peer->next = peer_hash[i]; 675 peer_hash[i] = peer; 676 peer_hash_count[i]++; 677 678 i = peer->associd & HASH_MASK; 679 peer->ass_next = assoc_hash[i]; 680 assoc_hash[i] = peer; 681 assoc_hash_count[i]++; 682 #ifdef DEBUG 683 if (debug > 1) 684 printf("mobilize %u next %lu\n", peer->associd, 685 peer->nextdate - peer->outdate); 686 #endif 687 return peer; 688 } 689 690 691 /* 692 * peer_unconfig - remove the configuration bit from a peer 693 */ 694 int 695 peer_unconfig( 696 struct sockaddr_in *srcadr, 697 struct interface *dstadr, 698 int mode 699 ) 700 { 701 register struct peer *peer; 702 int num_found; 703 704 num_found = 0; 705 peer = findexistingpeer(srcadr, (struct peer *)0, mode); 706 while (peer != 0) { 707 if (peer->flags & FLAG_CONFIG 708 && (dstadr == 0 || peer->dstadr == dstadr)) { 709 num_found++; 710 /* 711 * Tricky stuff here. If the peer is polling us 712 * in active mode, turn off the configuration bit 713 * and make the mode passive. This allows us to 714 * avoid dumping a lot of history for peers we 715 * might choose to keep track of in passive mode. 716 * The protocol will eventually terminate undesirables 717 * on its own. 718 */ 719 if (peer->hmode == MODE_ACTIVE 720 && peer->pmode == MODE_ACTIVE) { 721 peer->hmode = MODE_PASSIVE; 722 peer->flags &= ~FLAG_CONFIG; 723 } else { 724 unpeer(peer); 725 peer = 0; 726 } 727 } 728 peer = findexistingpeer(srcadr, peer, mode); 729 } 730 return num_found; 731 } 732 733 /* 734 * peer_copy_manycast - copy manycast peer variables to new association 735 * (right now it simply copies the transmit timestamp) 736 */ 737 void 738 peer_config_manycast( 739 struct peer *peer1, 740 struct peer *peer2 741 ) 742 { 743 peer2->cast_flags = MDF_ACAST; 744 peer2->xmt = peer1->xmt; 745 } 746 747 /* 748 * peer_clr_stats - clear peer module stat counters 749 */ 750 void 751 peer_clr_stats(void) 752 { 753 findpeer_calls = 0; 754 assocpeer_calls = 0; 755 peer_allocations = 0; 756 peer_demobilizations = 0; 757 peer_timereset = current_time; 758 } 759 760 /* 761 * peer_reset - reset stat counters in a peer structure 762 */ 763 void 764 peer_reset( 765 struct peer *peer 766 ) 767 { 768 if (peer == 0) 769 return; 770 peer->sent = 0; 771 peer->received = 0; 772 peer->processed = 0; 773 peer->badauth = 0; 774 peer->bogusorg = 0; 775 peer->oldpkt = 0; 776 peer->seldisptoolarge = 0; 777 peer->selbroken = 0; 778 peer->seltooold = 0; 779 peer->timereset = current_time; 780 } 781 782 783 /* 784 * peer_all_reset - reset all peer stat counters 785 */ 786 void 787 peer_all_reset(void) 788 { 789 struct peer *peer; 790 int hash; 791 792 for (hash = 0; hash < HASH_SIZE; hash++) 793 for (peer = peer_hash[hash]; peer != 0; peer = peer->next) 794 peer_reset(peer); 795 } 796