]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/ntp/ntpd/ntp_peer.c
This commit was generated by cvs2svn to compensate for changes in r161818,
[FreeBSD/FreeBSD.git] / contrib / ntp / ntpd / ntp_peer.c
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 #ifdef OPENSSL
14 #include "openssl/rand.h"
15 #endif /* OPENSSL */
16
17 /*
18  *                  Table of valid association combinations
19  *                  ---------------------------------------
20  *
21  *                             packet->mode
22  * peer->mode      | UNSPEC  ACTIVE PASSIVE  CLIENT  SERVER  BCAST
23  * ----------      | ---------------------------------------------
24  * NO_PEER         |   e       1       e       1       1       1
25  * ACTIVE          |   e       1       1       0       0       0
26  * PASSIVE         |   e       1       e       0       0       0
27  * CLIENT          |   e       0       0       0       1       1
28  * SERVER          |   e       0       0       0       0       0
29  * BCAST           |   e       0       0       0       0       0
30  * CONTROL         |   e       0       0       0       0       0
31  * PRIVATE         |   e       0       0       0       0       0
32  * BCLIENT         |   e       0       0       0       e       1
33  *
34  * One point to note here: a packet in BCAST mode can potentially match
35  * a peer in CLIENT mode, but we that is a special case and we check for
36  * that early in the decision process.  This avoids having to keep track
37  * of what kind of associations are possible etc...  We actually
38  * circumvent that problem by requiring that the first b(m)roadcast
39  * received after the change back to BCLIENT mode sets the clock.
40  */
41
42 int AM[AM_MODES][AM_MODES] = {
43 /*      { UNSPEC,   ACTIVE,     PASSIVE,    CLIENT,     SERVER,     BCAST } */
44
45 /*NONE*/{ AM_ERR, AM_NEWPASS, AM_ERR,     AM_FXMIT,   AM_MANYCAST, AM_NEWBCL},
46
47 /*A*/   { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
48
49 /*P*/   { AM_ERR, AM_PROCPKT, AM_ERR,     AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
50
51 /*C*/   { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT,  AM_POSSBCL},
52
53 /*S*/   { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
54
55 /*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
56
57 /*CNTL*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
58
59 /*PRIV*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
60
61 /*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_ERR,      AM_PROCPKT},
62 };
63
64 #define MATCH_ASSOC(x,y)        AM[(x)][(y)]
65
66 /*
67  * These routines manage the allocation of memory to peer structures
68  * and the maintenance of the peer hash table. The two main entry
69  * points are findpeer(), which looks for matching peer sturctures in
70  * the peer list, newpeer(), which allocates a new peer structure and
71  * adds it to the list, and unpeer(), which demobilizes the association
72  * and deallocates the structure.
73  */
74 /*
75  * Peer hash tables
76  */
77 struct peer *peer_hash[HASH_SIZE];      /* peer hash table */
78 int peer_hash_count[HASH_SIZE];         /* peers in each bucket */
79 struct peer *assoc_hash[HASH_SIZE];     /* association ID hash table */
80 int assoc_hash_count[HASH_SIZE];        /* peers in each bucket */
81 static struct peer *peer_free;          /* peer structures free list */
82 int peer_free_count;                    /* count of free structures */
83
84 /*
85  * Association ID.  We initialize this value randomly, then assign a new
86  * value every time the peer structure is incremented.
87  */
88 static associd_t current_association_ID; /* association ID */
89
90 /*
91  * Memory allocation watermarks.
92  */
93 #define INIT_PEER_ALLOC         15      /* initialize for 15 peers */
94 #define INC_PEER_ALLOC          5       /* when run out, add 5 more */
95
96 /*
97  * Miscellaneous statistic counters which may be queried.
98  */
99 u_long peer_timereset;                  /* time stat counters zeroed */
100 u_long findpeer_calls;                  /* calls to findpeer */
101 u_long assocpeer_calls;                 /* calls to findpeerbyassoc */
102 u_long peer_allocations;                /* allocations from free list */
103 u_long peer_demobilizations;            /* structs freed to free list */
104 int total_peer_structs;                 /* peer structs */
105 int peer_associations;                  /* active associations */
106 static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */
107
108 static  void    getmorepeermem  P((void));
109
110 /*
111  * init_peer - initialize peer data structures and counters
112  *
113  * N.B. We use the random number routine in here. It had better be
114  * initialized prior to getting here.
115  */
116 void
117 init_peer(void)
118 {
119         register int i;
120
121         /*
122          * Clear hash table and counters.
123          */
124         for (i = 0; i < HASH_SIZE; i++) {
125                 peer_hash[i] = 0;
126                 peer_hash_count[i] = 0;
127                 assoc_hash[i] = 0;
128                 assoc_hash_count[i] = 0;
129         }
130
131         /*
132          * Clear stat counters
133          */
134         findpeer_calls = peer_allocations = 0;
135         assocpeer_calls = peer_demobilizations = 0;
136
137         /*
138          * Initialize peer memory.
139          */
140         peer_free = 0;
141         for (i = 0; i < INIT_PEER_ALLOC; i++) {
142                 init_peer_alloc[i].next = peer_free;
143                 peer_free = &init_peer_alloc[i];
144         }
145         total_peer_structs = INIT_PEER_ALLOC;
146         peer_free_count = INIT_PEER_ALLOC;
147
148         /*
149          * Initialize our first association ID
150          */
151         current_association_ID = (associd_t)ranp2(16);
152         if (current_association_ID == 0)
153             current_association_ID = 1;
154 }
155
156
157 /*
158  * getmorepeermem - add more peer structures to the free list
159  */
160 static void
161 getmorepeermem(void)
162 {
163         register int i;
164         register struct peer *peer;
165
166         peer = (struct peer *)emalloc(INC_PEER_ALLOC *
167             sizeof(struct peer));
168         for (i = 0; i < INC_PEER_ALLOC; i++) {
169                 peer->next = peer_free;
170                 peer_free = peer;
171                 peer++;
172         }
173
174         total_peer_structs += INC_PEER_ALLOC;
175         peer_free_count += INC_PEER_ALLOC;
176 }
177
178
179 /*
180  * findexistingpeer - return a pointer to a peer in the hash table
181  */
182 struct peer *
183 findexistingpeer(
184         struct sockaddr_storage *addr,
185         struct peer *start_peer,
186         int mode
187         )
188 {
189         register struct peer *peer;
190
191         /*
192          * start_peer is included so we can locate instances of the
193          * same peer through different interfaces in the hash table.
194          */
195         if (start_peer == 0)
196                 peer = peer_hash[HASH_ADDR(addr)];
197         else
198                 peer = start_peer->next;
199         
200         while (peer != 0) {
201                 if (SOCKCMP(addr, &peer->srcadr)
202                     && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) {
203                         if (mode == -1)
204                                 return (peer);
205                         else if (peer->hmode == mode)
206                                 break;
207                 }
208                 peer = peer->next;
209         }
210         return (peer);
211 }
212
213
214 /*
215  * findpeer - find and return a peer in the hash table.
216  */
217 struct peer *
218 findpeer(
219         struct sockaddr_storage *srcadr,
220         struct interface *dstadr,
221         int fd,
222         int pkt_mode,
223         int *action
224         )
225 {
226         register struct peer *peer;
227         int hash;
228
229         findpeer_calls++;
230         hash = HASH_ADDR(srcadr);
231         for (peer = peer_hash[hash]; peer != NULL; peer = peer->next) {
232                 if (SOCKCMP(srcadr, &peer->srcadr)
233                     && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
234
235                         /*
236                          * if the association matching rules determine
237                          * that this is not a valid combination, then
238                          * look for the next valid peer association.
239                          */
240                         *action = MATCH_ASSOC(peer->hmode, pkt_mode);
241
242                         /*
243                          * Sigh!  Check if BCLIENT peer in client
244                          * server mode, else return error.
245                          */
246                         if ((*action == AM_POSSBCL) && !(peer->flags &
247                             FLAG_MCAST))
248                                 *action = AM_ERR;
249
250                         /*
251                          * if an error was returned, exit back right
252                          * here.
253                          */
254                         if (*action == AM_ERR)
255                                 return ((struct peer *)0);
256
257                         /*
258                          * if a match is found, we stop our search.
259                          */
260                         if (*action != AM_NOMATCH)
261                                 break;
262                 }
263         }
264
265         /*
266          * If no matching association is found
267          */
268         if (peer == 0) {
269                 *action = MATCH_ASSOC(NO_PEER, pkt_mode);
270                 return ((struct peer *)0);
271         }
272         peer->dstadr = dstadr;
273         return (peer);
274 }
275
276 /*
277  * findpeerbyassocid - find and return a peer using his association ID
278  */
279 struct peer *
280 findpeerbyassoc(
281         u_int assoc
282         )
283 {
284         register struct peer *peer;
285         int hash;
286
287         assocpeer_calls++;
288
289         hash = assoc & HASH_MASK;
290         for (peer = assoc_hash[hash]; peer != 0; peer =
291             peer->ass_next) {
292                 if (assoc == peer->associd)
293                     return (peer);
294         }
295         return (NULL);
296 }
297
298
299 /*
300  * clear_all - flush all time values for all associations
301  */
302 void
303 clear_all(void)
304 {
305         struct peer *peer, *next_peer;
306         int n;
307
308         /*
309          * This routine is called when the clock is stepped, and so all
310          * previously saved time values are untrusted.
311          */
312         for (n = 0; n < HASH_SIZE; n++) {
313                 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
314                         next_peer = peer->next;
315                         if (peer->flags & FLAG_CONFIG) {
316                                 if (!(peer->cast_flags & (MDF_ACAST |
317                                      MDF_MCAST | MDF_BCAST)))
318                                         peer_clear(peer, "STEP");
319                         } else {
320                                 unpeer(peer);
321                         }
322                 }
323         }
324 #ifdef DEBUG
325         if (debug)
326                 printf("clear_all: at %lu\n", current_time);
327 #endif
328 }
329
330
331 /*
332  * unpeer - remove peer structure from hash table and free structure
333  */
334 void
335 unpeer(
336         struct peer *peer_to_remove
337         )
338 {
339         int hash;
340 #ifdef OPENSSL
341         char    statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
342
343         if (peer_to_remove->flags & FLAG_SKEY) {
344                 sprintf(statstr, "unpeer %d flash %x reach %03o flags %04x",
345                     peer_to_remove->associd, peer_to_remove->flash,
346                     peer_to_remove->reach, peer_to_remove->flags);
347                 record_crypto_stats(&peer_to_remove->srcadr, statstr);
348 #ifdef DEBUG
349                 if (debug)
350                         printf("peer: %s\n", statstr);
351 #endif
352         }
353 #endif /* OPENSSL */
354 #ifdef DEBUG
355         if (debug)
356                 printf("demobilize %u %d\n", peer_to_remove->associd,
357                     peer_associations);
358 #endif
359         peer_clear(peer_to_remove, "NULL");
360         hash = HASH_ADDR(&peer_to_remove->srcadr);
361         peer_hash_count[hash]--;
362         peer_demobilizations++;
363 #ifdef REFCLOCK
364         /*
365          * If this peer is actually a clock, shut it down first
366          */
367         if (peer_to_remove->flags & FLAG_REFCLOCK)
368                 refclock_unpeer(peer_to_remove);
369 #endif
370         peer_to_remove->action = 0;     /* disable timeout actions */
371         if (peer_hash[hash] == peer_to_remove)
372                 peer_hash[hash] = peer_to_remove->next;
373         else {
374                 register struct peer *peer;
375
376                 peer = peer_hash[hash];
377                 while (peer != 0 && peer->next != peer_to_remove)
378                     peer = peer->next;
379                 
380                 if (peer == 0) {
381                         peer_hash_count[hash]++;
382                         msyslog(LOG_ERR, "peer struct for %s not in table!",
383                                 stoa(&peer->srcadr));
384                 } else {
385                         peer->next = peer_to_remove->next;
386                 }
387         }
388
389         /*
390          * Remove him from the association hash as well.
391          */
392         hash = peer_to_remove->associd & HASH_MASK;
393         assoc_hash_count[hash]--;
394         if (assoc_hash[hash] == peer_to_remove)
395                 assoc_hash[hash] = peer_to_remove->ass_next;
396         else {
397                 register struct peer *peer;
398
399                 peer = assoc_hash[hash];
400                 while (peer != 0 && peer->ass_next != peer_to_remove)
401                     peer = peer->ass_next;
402                 
403                 if (peer == 0) {
404                         assoc_hash_count[hash]++;
405                         msyslog(LOG_ERR,
406                                 "peer struct for %s not in association table!",
407                                 stoa(&peer->srcadr));
408                 } else {
409                         peer->ass_next = peer_to_remove->ass_next;
410                 }
411         }
412         peer_to_remove->next = peer_free;
413         peer_free = peer_to_remove;
414         peer_free_count++;
415         peer_associations--;
416 }
417
418
419 /*
420  * peer_config - configure a new association
421  */
422 struct peer *
423 peer_config(
424         struct sockaddr_storage *srcadr,
425         struct interface *dstadr,
426         int hmode,
427         int version,
428         int minpoll,
429         int maxpoll,
430         u_int flags,
431         int ttl,
432         keyid_t key,
433         u_char *keystr
434         )
435 {
436         register struct peer *peer;
437         u_char cast_flags;
438
439         /*
440          * First search from the beginning for an association with given
441          * remote address and mode. If an interface is given, search
442          * from there to find the association which matches that
443          * destination.
444          */
445         peer = findexistingpeer(srcadr, (struct peer *)0, hmode);
446         if (dstadr != 0) {
447                 while (peer != 0) {
448                         if (peer->dstadr == dstadr)
449                                 break;
450                         peer = findexistingpeer(srcadr, peer, hmode);
451                 }
452         }
453
454         /*
455          * We do a dirty little jig to figure the cast flags. This is
456          * probably not the best place to do this, at least until the
457          * configure code is rebuilt. Note only one flag can be set.
458          */
459         switch (hmode) {
460
461         case MODE_BROADCAST:
462                 if(srcadr->ss_family == AF_INET) {
463                         if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr)))
464                                 cast_flags = MDF_MCAST;
465                         else
466                                 cast_flags = MDF_BCAST;
467                         break;
468                 }
469                 else {
470                         if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr))
471                                 cast_flags = MDF_MCAST;
472                         else
473                                 cast_flags = MDF_BCAST;
474                         break;
475                 }
476
477         case MODE_CLIENT:
478                 if(srcadr->ss_family == AF_INET) {
479                         if (IN_CLASSD(ntohl(((struct sockaddr_in*)srcadr)->sin_addr.s_addr)))
480                                 cast_flags = MDF_ACAST;
481                         else
482                                 cast_flags = MDF_UCAST;
483                         break;
484                 }
485                 else {
486                         if (IN6_IS_ADDR_MULTICAST(&((struct sockaddr_in6*)srcadr)->sin6_addr))
487                                 cast_flags = MDF_ACAST;
488                         else
489                                 cast_flags = MDF_UCAST;
490                         break;
491                 }
492
493         default:
494                 cast_flags = MDF_UCAST;
495         }
496
497         /*
498          * If the peer is already configured, some dope has a duplicate
499          * configureation entry or another dope is wiggling from afar.
500          */
501         if (peer != 0) {
502                 peer->hmode = (u_char)hmode;
503                 peer->version = (u_char) version;
504                 peer->minpoll = (u_char) minpoll;
505                 peer->maxpoll = (u_char) maxpoll;
506                 peer->flags = flags | FLAG_CONFIG |
507                         (peer->flags & FLAG_REFCLOCK);
508                 peer->cast_flags = cast_flags;
509                 peer->ttl = (u_char) ttl;
510                 peer->keyid = key;
511                 peer->precision = sys_precision;
512                 peer_clear(peer, "RMOT");
513                 return (peer);
514         }
515
516         /*
517          * Here no match has been found, so presumably this is a new
518          * persistent association. Mobilize the thing and initialize its
519          * variables. If emulating ntpdate, force iburst.
520          */
521         if (mode_ntpdate)
522                 flags |= FLAG_IBURST;
523         peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
524             flags | FLAG_CONFIG, cast_flags, ttl, key);
525         return (peer);
526 }
527
528
529 /*
530  * newpeer - initialize a new peer association
531  */
532 struct peer *
533 newpeer(
534         struct sockaddr_storage *srcadr,
535         struct interface *dstadr,
536         int hmode,
537         int version,
538         int minpoll,
539         int maxpoll,
540         u_int flags,
541         u_char cast_flags,
542         int ttl,
543         keyid_t key
544         )
545 {
546         register struct peer *peer;
547         register int i;
548 #ifdef OPENSSL
549         char    statstr[NTP_MAXSTRLEN]; /* statistics for filegen */
550 #endif /* OPENSSL */
551
552         /*
553          * Allocate a new peer structure. Some dirt here, since some of
554          * the initialization requires knowlege of our system state.
555          */
556         if (peer_free_count == 0)
557                 getmorepeermem();
558         peer = peer_free;
559         peer_free = peer->next;
560         peer_free_count--;
561         peer_associations++;
562         memset((char *)peer, 0, sizeof(struct peer));
563
564         /*
565          * Assign an association ID and increment the system variable.
566          */
567         peer->associd = current_association_ID;
568         if (++current_association_ID == 0)
569                 ++current_association_ID;
570
571         /*
572          * Initialize the peer structure and dance the interface jig.
573          * Reference clocks step the loopback waltz, the others
574          * squaredance around the interface list looking for a buddy. If
575          * the dance peters out, there is always the wildcard interface.
576          * This might happen in some systems and would preclude proper
577          * operation with public key cryptography.
578          */
579         if (ISREFCLOCKADR(srcadr))
580                 peer->dstadr = loopback_interface;
581         else if (cast_flags & (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
582                 peer->dstadr = findbcastinter(srcadr);
583                 /*
584                  * If it was a multicast packet, findbcastinter() may not
585                  * find it, so try a little harder.
586                  */
587                 if (peer->dstadr == ANY_INTERFACE_CHOOSE(srcadr))
588                         peer->dstadr = findinterface(srcadr);
589         } else if (dstadr != NULL && dstadr != ANY_INTERFACE_CHOOSE(srcadr))
590                 peer->dstadr = dstadr;
591         else
592                 peer->dstadr = findinterface(srcadr);
593         peer->srcadr = *srcadr;
594         peer->hmode = (u_char)hmode;
595         peer->version = (u_char)version;
596         peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll);
597         peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll);
598         peer->flags = flags;
599         if (key != 0)
600                 peer->flags |= FLAG_AUTHENABLE;
601         if (key > NTP_MAXKEY)
602                 peer->flags |= FLAG_SKEY;
603         peer->cast_flags = cast_flags;
604         peer->ttl = (u_char)ttl;
605         peer->keyid = key;
606         peer->precision = sys_precision;
607         if (cast_flags & MDF_ACAST)
608                 peer_clear(peer, "ACST");
609         else if (cast_flags & MDF_MCAST)
610                 peer_clear(peer, "MCST");
611         else if (cast_flags & MDF_BCAST)
612                 peer_clear(peer, "BCST");
613         else
614                 peer_clear(peer, "INIT");
615         if (mode_ntpdate)
616                 peer_ntpdate++;
617
618         /*
619          * Note time on statistics timers.
620          */
621         peer->timereset = current_time;
622         peer->timereachable = current_time;
623         peer->timereceived = current_time;
624 #ifdef REFCLOCK
625         if (ISREFCLOCKADR(&peer->srcadr)) {
626                 /*
627                  * We let the reference clock support do clock
628                  * dependent initialization.  This includes setting
629                  * the peer timer, since the clock may have requirements
630                  * for this.
631                  */
632                 if (!refclock_newpeer(peer)) {
633                         /*
634                          * Dump it, something screwed up
635                          */
636                         peer->next = peer_free;
637                         peer_free = peer;
638                         peer_free_count++;
639                         return (NULL);
640                 }
641         }
642 #endif
643
644         /*
645          * Put the new peer in the hash tables.
646          */
647         i = HASH_ADDR(&peer->srcadr);
648         peer->next = peer_hash[i];
649         peer_hash[i] = peer;
650         peer_hash_count[i]++;
651         i = peer->associd & HASH_MASK;
652         peer->ass_next = assoc_hash[i];
653         assoc_hash[i] = peer;
654         assoc_hash_count[i]++;
655 #ifdef OPENSSL
656         if (peer->flags & FLAG_SKEY) {
657                 sprintf(statstr, "newpeer %d", peer->associd);
658                 record_crypto_stats(&peer->srcadr, statstr);
659 #ifdef DEBUG
660                 if (debug)
661                         printf("peer: %s\n", statstr);
662 #endif
663         }
664 #endif /* OPENSSL */
665 #ifdef DEBUG
666         if (debug)
667                 printf(
668                     "newpeer: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x\n",
669                     peer->dstadr == NULL ? "null" : stoa(&peer->dstadr->sin),
670                     stoa(&peer->srcadr),
671                     peer->hmode, peer->version, peer->minpoll,
672                     peer->maxpoll, peer->flags, peer->cast_flags,
673                     peer->ttl, peer->keyid);
674 #endif
675         return (peer);
676 }
677
678
679 /*
680  * peer_unconfig - remove the configuration bit from a peer
681  */
682 int
683 peer_unconfig(
684         struct sockaddr_storage *srcadr,
685         struct interface *dstadr,
686         int mode
687         )
688 {
689         register struct peer *peer;
690         int num_found;
691
692         num_found = 0;
693         peer = findexistingpeer(srcadr, (struct peer *)0, mode);
694         while (peer != 0) {
695                 if (peer->flags & FLAG_CONFIG
696                     && (dstadr == 0 || peer->dstadr == dstadr)) {
697                         num_found++;
698
699                         /*
700                          * Tricky stuff here. If the peer is polling us
701                          * in active mode, turn off the configuration
702                          * bit and make the mode passive. This allows us
703                          * to avoid dumping a lot of history for peers
704                          * we might choose to keep track of in passive
705                          * mode. The protocol will eventually terminate
706                          * undesirables on its own.
707                          */
708                         if (peer->hmode == MODE_ACTIVE
709                             && peer->pmode == MODE_ACTIVE) {
710                                 peer->hmode = MODE_PASSIVE;
711                                 peer->flags &= ~FLAG_CONFIG;
712                         } else {
713                                 unpeer(peer);
714                                 peer = 0;
715                         }
716                 }
717                 peer = findexistingpeer(srcadr, peer, mode);
718         }
719         return (num_found);
720 }
721
722 /*
723  * peer_clr_stats - clear peer module stat counters
724  */
725 void
726 peer_clr_stats(void)
727 {
728         findpeer_calls = 0;
729         assocpeer_calls = 0;
730         peer_allocations = 0;
731         peer_demobilizations = 0;
732         peer_timereset = current_time;
733 }
734
735 /*
736  * peer_reset - reset stat counters in a peer structure
737  */
738 void
739 peer_reset(
740         struct peer *peer
741         )
742 {
743         if (peer == 0)
744             return;
745         peer->sent = 0;
746         peer->received = 0;
747         peer->processed = 0;
748         peer->badauth = 0;
749         peer->bogusorg = 0;
750         peer->oldpkt = 0;
751         peer->seldisptoolarge = 0;
752         peer->selbroken = 0;
753         peer->rank = 0;
754         peer->timereset = current_time;
755 }
756
757
758 /*
759  * peer_all_reset - reset all peer stat counters
760  */
761 void
762 peer_all_reset(void)
763 {
764         struct peer *peer;
765         int hash;
766
767         for (hash = 0; hash < HASH_SIZE; hash++)
768             for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
769                 peer_reset(peer);
770 }
771
772
773 #ifdef OPENSSL
774 /*
775  * expire_all - flush all crypto data and update timestamps.
776  */
777 void
778 expire_all(void)
779 {
780         struct peer *peer, *next_peer;
781         int n;
782
783         /*
784          * This routine is called about once per day from the timer
785          * routine and when the client is first synchronized. Search the
786          * peer list for all associations and flush only the key list
787          * and cookie. If a manycast client association, flush
788          * everything. Then, recompute and sign the agreement public
789          * value, if present.
790          */
791         if (!crypto_flags)
792                 return;
793         for (n = 0; n < HASH_SIZE; n++) {
794                 for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
795                         next_peer = peer->next;
796                         if (!(peer->flags & FLAG_SKEY)) {
797                                 continue;
798                         } else if (peer->cast_flags & MDF_ACAST) {
799                                 peer_clear(peer, "ACST");
800                         } else if (peer->hmode == MODE_ACTIVE ||
801                             peer->hmode == MODE_PASSIVE) {
802                                 key_expire(peer);
803                                 peer->crypto &= ~(CRYPTO_FLAG_AUTO |
804                                     CRYPTO_FLAG_AGREE);
805                         }
806                                 
807                 }
808         }
809         RAND_bytes((u_char *)&sys_private, 4);
810         crypto_update();
811         resetmanycast();
812 }
813 #endif /* OPENSSL */
814
815
816 /*
817  * findmanycastpeer - find and return a manycast peer
818  */
819 struct peer *
820 findmanycastpeer(
821         struct recvbuf *rbufp
822         )
823 {
824         register struct peer *peer;
825         struct pkt *pkt;
826         l_fp p_org;
827         int i;
828
829         /*
830          * This routine is called upon arrival of a client-mode message
831          * from a manycast server. Search the peer list for a manycast
832          * client association where the last transmit timestamp matches
833          * the originate timestamp. This assumes the transmit timestamps
834          * for possibly more than one manycast association are unique.
835          */
836         pkt = &rbufp->recv_pkt;
837         for (i = 0; i < HASH_SIZE; i++) {
838                 if (peer_hash_count[i] == 0)
839                         continue;
840
841                 for (peer = peer_hash[i]; peer != 0; peer =
842                     peer->next) {
843                         if (peer->cast_flags & MDF_ACAST) {
844                                 NTOHL_FP(&pkt->org, &p_org);
845                                 if (L_ISEQU(&peer->xmt, &p_org))
846                                         return (peer);
847                         }
848                 }
849         }
850         return (NULL);
851 }
852
853
854 /*
855  * resetmanycast - reset all manycast clients
856  */
857 void
858 resetmanycast(void)
859 {
860         register struct peer *peer;
861         int i;
862
863         /*
864          * This routine is called when the number of client associations
865          * falls below the minimum. Search the peer list for manycast
866          * client associations and reset the ttl and poll interval.
867          */
868         for (i = 0; i < HASH_SIZE; i++) {
869                 if (peer_hash_count[i] == 0)
870                         continue;
871
872                 for (peer = peer_hash[i]; peer != 0; peer =
873                     peer->next) {
874                         if (peer->cast_flags & MDF_ACAST) {
875                                 peer->ttl = 0;
876                                 poll_update(peer, 0);
877                         }
878                 }
879         }
880 }