xref: /freebsd/contrib/ntp/ntpd/ntp_peer.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
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