ntp_peer.c revision 82498
122347Spst/*
222347Spst * ntp_peer.c - management of data maintained for peer associations
329964Sache */
492914Smarkm#ifdef HAVE_CONFIG_H
522347Spst#include <config.h>
622347Spst#endif
722347Spst
822347Spst#include <stdio.h>
922347Spst#include <sys/types.h>
1022347Spst
1122347Spst#include "ntpd.h"
1292914Smarkm#include "ntp_stdlib.h"
1322347Spst#ifdef AUTOKEY
1422347Spst#include "ntp_crypto.h"
1522347Spst#endif /* AUTOKEY */
1622347Spst
1722347Spst/*
1822347Spst *                  Table of valid association combinations
1922347Spst *                  ---------------------------------------
2022347Spst *
2122347Spst *                             packet->mode
2222347Spst * peer->mode      | UNSPEC  ACTIVE PASSIVE  CLIENT  SERVER  BCAST
2322347Spst * ----------      | ---------------------------------------------
2422347Spst * NO_PEER         |   e       1       e       1       1       1
2559121Skris * ACTIVE          |   e       1       1       0       0       0
2659121Skris * PASSIVE         |   e       1       e       0       0       0
2722347Spst * CLIENT          |   e       0       0       0       1       1
2822347Spst * SERVER          |   e       0       0       0       0       0
2922347Spst * BCAST	   |   e       0       0       0       0       0
3022347Spst * CONTROL	   |   e       0       0       0       0       0
3122347Spst * PRIVATE	   |   e       0       0       0       0       0
3222347Spst * BCLIENT         |   e       0       0       0       e       1
3322347Spst *
3422347Spst * One point to note here: a packet in BCAST mode can potentially match
3522347Spst * a peer in CLIENT mode, but we that is a special case and we check for
3622347Spst * that early in the decision process.  This avoids having to keep track
3722347Spst * of what kind of associations are possible etc...  We actually
3822347Spst * circumvent that problem by requiring that the first b(m)roadcast
3922347Spst * received after the change back to BCLIENT mode sets the clock.
4022347Spst */
4122347Spst
4222347Spstint AM[AM_MODES][AM_MODES] = {
4322347Spst/*	{ UNSPEC,   ACTIVE,     PASSIVE,    CLIENT,     SERVER,     BCAST } */
4422347Spst
4522347Spst/*NONE*/{ AM_ERR, AM_NEWPASS, AM_ERR,     AM_FXMIT,   AM_MANYCAST, AM_NEWBCL},
4622347Spst
4722347Spst/*A*/	{ AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
4822347Spst
4922347Spst/*P*/	{ AM_ERR, AM_PROCPKT, AM_ERR,     AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
5022347Spst
5122347Spst/*C*/	{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT,  AM_POSSBCL},
5222347Spst
5322347Spst/*S*/	{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
5422347Spst
5522347Spst/*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
5622347Spst
5722347Spst/*CNTL*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
5822347Spst
5922347Spst/*PRIV*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH,  AM_NOMATCH},
6022347Spst
6122347Spst/*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_ERR,      AM_PROCPKT},
6222347Spst};
6322347Spst
6422347Spst#define MATCH_ASSOC(x,y)	AM[(x)][(y)]
6522347Spst
6622347Spst/*
6722347Spst * These routines manage the allocation of memory to peer structures
6822347Spst * and the maintenance of the peer hash table. The two main entry
6922347Spst * points are findpeer(), which looks for matching peer sturctures in
7022347Spst * the peer list, newpeer(), which allocates a new peer structure and
7122347Spst * adds it to the list, and unpeer(), which demobilizes the association
7222347Spst * and deallocates the structure.
7322347Spst */
7422347Spst/*
7522347Spst * Peer hash tables
7622347Spst */
7722347Spststruct peer *peer_hash[HASH_SIZE];	/* peer hash table */
7822347Spstint peer_hash_count[HASH_SIZE];		/* peers in each bucket */
7922347Spststruct peer *assoc_hash[HASH_SIZE];	/* association ID hash table */
8022347Spstint assoc_hash_count[HASH_SIZE];	/* peers in each bucket */
8122347Spststatic struct peer *peer_free;		/* peer structures free list */
8222347Spstint peer_free_count;			/* count of free structures */
8322347Spst
8422347Spst/*
8522347Spst * Association ID.  We initialize this value randomly, then assign a new
8622347Spst * value every time the peer structure is incremented.
8722347Spst */
8822347Spststatic associd_t current_association_ID; /* association ID */
8922347Spst
9022347Spst/*
9122347Spst * Memory allocation watermarks.
9222347Spst */
9322347Spst#define	INIT_PEER_ALLOC		15	/* initialize for 15 peers */
9422347Spst#define	INC_PEER_ALLOC		5	/* when run out, add 5 more */
9522347Spst
9622347Spst/*
9722347Spst * Miscellaneous statistic counters which may be queried.
9822347Spst */
9922347Spstu_long peer_timereset;			/* time stat counters zeroed */
10022347Spstu_long findpeer_calls;			/* calls to findpeer */
10122347Spstu_long assocpeer_calls;			/* calls to findpeerbyassoc */
10222347Spstu_long peer_allocations;		/* allocations from free list */
10322347Spstu_long peer_demobilizations;		/* structs freed to free list */
10422347Spstint total_peer_structs;			/* peer structs */
10522347Spstint peer_associations;			/* active associations */
10622347Spststatic struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */
10722347Spst
10822347Spststatic	void	getmorepeermem	P((void));
10922347Spst
11022347Spst/*
11122347Spst * init_peer - initialize peer data structures and counters
11222347Spst *
11322347Spst * N.B. We use the random number routine in here. It had better be
11422347Spst * initialized prior to getting here.
11522347Spst */
11622347Spstvoid
11722347Spstinit_peer(void)
11822347Spst{
11922347Spst	register int i;
12022347Spst
12122347Spst	/*
12222347Spst	 * Clear hash table and counters.
12322347Spst	 */
12422347Spst	for (i = 0; i < HASH_SIZE; i++) {
12522347Spst		peer_hash[i] = 0;
12622347Spst		peer_hash_count[i] = 0;
12722347Spst		assoc_hash[i] = 0;
12822347Spst		assoc_hash_count[i] = 0;
12922347Spst	}
13022347Spst
13122347Spst	/*
13222347Spst	 * Clear stat counters
13322347Spst	 */
13422347Spst	findpeer_calls = peer_allocations = 0;
13522347Spst	assocpeer_calls = peer_demobilizations = 0;
13622347Spst
13722347Spst	/*
13822347Spst	 * Initialize peer memory.
13922347Spst	 */
14022347Spst	peer_free = 0;
14122347Spst	for (i = 0; i < INIT_PEER_ALLOC; i++) {
14222347Spst		init_peer_alloc[i].next = peer_free;
14322347Spst		peer_free = &init_peer_alloc[i];
14422347Spst	}
14522347Spst	total_peer_structs = INIT_PEER_ALLOC;
14622347Spst	peer_free_count = INIT_PEER_ALLOC;
14722347Spst
14822347Spst	/*
14922347Spst	 * Initialize our first association ID
15022347Spst	 */
15122347Spst	current_association_ID = (associd_t)ranp2(16);
15222347Spst	if (current_association_ID == 0)
15322347Spst	    current_association_ID = 1;
15422347Spst}
15522347Spst
15622347Spst
15722347Spst/*
15822347Spst * getmorepeermem - add more peer structures to the free list
15922347Spst */
16022347Spststatic void
16122347Spstgetmorepeermem(void)
16222347Spst{
16322347Spst	register int i;
16422347Spst	register struct peer *peer;
16522347Spst
16622347Spst	peer = (struct peer *)emalloc(INC_PEER_ALLOC *
16722347Spst	    sizeof(struct peer));
16822347Spst	for (i = 0; i < INC_PEER_ALLOC; i++) {
16922347Spst		peer->next = peer_free;
17022347Spst		peer_free = peer;
17122347Spst		peer++;
17222347Spst	}
17322347Spst
17422347Spst	total_peer_structs += INC_PEER_ALLOC;
17522347Spst	peer_free_count += INC_PEER_ALLOC;
17622347Spst}
17722347Spst
17822347Spst
17922347Spst/*
18022347Spst * findexistingpeer - return a pointer to a peer in the hash table
18122347Spst */
18222347Spststruct peer *
18322347Spstfindexistingpeer(
18422347Spst	struct sockaddr_in *addr,
18522347Spst	struct peer *start_peer,
18622347Spst	int mode
18722347Spst	)
18822347Spst{
18922347Spst	register struct peer *peer;
19022347Spst
19122347Spst	/*
19222347Spst	 * start_peer is included so we can locate instances of the
19322347Spst	 * same peer through different interfaces in the hash table.
19422347Spst	 */
19522347Spst	if (start_peer == 0)
19622347Spst		peer = peer_hash[HASH_ADDR(addr)];
19722347Spst	else
19822347Spst		peer = start_peer->next;
19922347Spst
20022347Spst	while (peer != 0) {
20122347Spst		if (NSRCADR(addr) == NSRCADR(&peer->srcadr)
20222347Spst		    && NSRCPORT(addr) == NSRCPORT(&peer->srcadr)) {
20322347Spst			if (mode == -1)
20422347Spst				return (peer);
20522347Spst			else if (peer->hmode == mode)
20622347Spst				break;
20722347Spst		}
20822347Spst		peer = peer->next;
20922347Spst	}
21022347Spst	return (peer);
21122347Spst}
21222347Spst
21322347Spst
21422347Spst/*
21522347Spst * findpeer - find and return a peer in the hash table.
21622347Spst */
21722347Spststruct peer *
21822347Spstfindpeer(
21922347Spst	struct sockaddr_in *srcadr,
22022347Spst	struct interface *dstadr,
22122347Spst	int fd,
22222347Spst	int pkt_mode,
22322347Spst	int *action
22422347Spst	)
22522347Spst{
22622347Spst	register struct peer *peer;
22722347Spst	int hash;
22822347Spst
22922347Spst	findpeer_calls++;
23022347Spst	hash = HASH_ADDR(srcadr);
23122347Spst	for (peer = peer_hash[hash]; peer != 0; peer = peer->next) {
23222347Spst		if (NSRCADR(srcadr) == NSRCADR(&peer->srcadr)
23322347Spst		    && NSRCPORT(srcadr) == NSRCPORT(&peer->srcadr)) {
23422347Spst
23522347Spst			/*
23622347Spst			 * if the association matching rules determine
23722347Spst			 * that this is not a valid combination, then
23822347Spst			 * look for the next valid peer association.
23922347Spst			 */
24022347Spst			*action = MATCH_ASSOC(peer->hmode, pkt_mode);
24122347Spst
24222347Spst			/*
24322347Spst			 * Sigh!  Check if BCLIENT peer in client
24422347Spst			 * server mode, else return error.
24522347Spst			 */
24622347Spst			if ((*action == AM_POSSBCL) && !(peer->flags &
24722347Spst			    FLAG_MCAST))
24822347Spst				*action = AM_ERR;
24922347Spst
25022347Spst			/*
25122347Spst			 * if an error was returned, exit back right
25222347Spst			 * here.
25322347Spst			 */
25422347Spst			if (*action == AM_ERR)
25522347Spst				return ((struct peer *)0);
25622347Spst
25722347Spst			/*
25822347Spst			 * if a match is found, we stop our search.
25922347Spst			 */
26022347Spst			if (*action != AM_NOMATCH)
26122347Spst				break;
26222347Spst		}
26322347Spst	}
26422347Spst
26522347Spst	/*
26622347Spst	 * If no matching association is found
26722347Spst	 */
26822347Spst	if (peer == 0) {
26922347Spst		*action = MATCH_ASSOC(NO_PEER, pkt_mode);
27022347Spst		return ((struct peer *)0);
27122347Spst	}
27222347Spst	peer->dstadr = dstadr;
27322347Spst	return (peer);
27422347Spst}
27522347Spst
27622347Spst/*
27722347Spst * findpeerbyassocid - find and return a peer using his association ID
27822347Spst */
27922347Spststruct peer *
28022347Spstfindpeerbyassoc(
28122347Spst	u_int assoc
28222347Spst	)
28322347Spst{
28422347Spst	register struct peer *peer;
28522347Spst	int hash;
28622347Spst
28722347Spst	assocpeer_calls++;
28822347Spst
28922347Spst	hash = assoc & HASH_MASK;
29022347Spst	for (peer = assoc_hash[hash]; peer != 0; peer =
29122347Spst	    peer->ass_next) {
29222347Spst		if (assoc == peer->associd)
29322347Spst		    return (peer);
29422347Spst	}
29522347Spst	return (NULL);
29622347Spst}
29722347Spst
29822347Spst
29922347Spst/*
30022347Spst * clear_all - flush all time values for all associations
30122347Spst */
30222347Spstvoid
30322347Spstclear_all(void)
30422347Spst{
30522347Spst	struct peer *peer, *next_peer;
30622347Spst	int n;
30722347Spst
30822347Spst	/*
30922347Spst	 * This routine is called when the clock is stepped, and so all
31022347Spst	 * previously saved time values are untrusted.
31122347Spst	 */
31222347Spst	for (n = 0; n < HASH_SIZE; n++) {
31322347Spst		for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
31422347Spst			next_peer = peer->next;
31522347Spst			peer_clear(peer);
31622347Spst		}
31722347Spst	}
31822347Spst#ifdef DEBUG
31922347Spst	if (debug)
32022347Spst		printf("clear_all: at %lu\n", current_time);
32122347Spst#endif
32222347Spst}
32322347Spst
32422347Spst
32522347Spst/*
32622347Spst * unpeer - remove peer structure from hash table and free structure
32722347Spst */
32822347Spstvoid
32922347Spstunpeer(
33022347Spst	struct peer *peer_to_remove
33122347Spst	)
33222347Spst{
33322347Spst	int hash;
33422347Spst
33522347Spst	peer_associations--;
33622347Spst#ifdef DEBUG
33722347Spst	if (debug)
33822347Spst		printf("demobilize %u %d\n", peer_to_remove->associd,
33922347Spst		    peer_associations);
34022347Spst#endif
34122347Spst	peer_clear(peer_to_remove);
34222347Spst	hash = HASH_ADDR(&peer_to_remove->srcadr);
34322347Spst	peer_hash_count[hash]--;
34422347Spst	peer_demobilizations++;
34522347Spst#ifdef REFCLOCK
34622347Spst	/*
34722347Spst	 * If this peer is actually a clock, shut it down first
34822347Spst	 */
34922347Spst	if (peer_to_remove->flags & FLAG_REFCLOCK)
35022347Spst		refclock_unpeer(peer_to_remove);
35122347Spst#endif
35222347Spst	peer_to_remove->action = 0;	/* disable timeout actions */
35322347Spst	if (peer_hash[hash] == peer_to_remove)
35422347Spst		peer_hash[hash] = peer_to_remove->next;
35522347Spst	else {
35622347Spst		register struct peer *peer;
35722347Spst
35822347Spst		peer = peer_hash[hash];
35922347Spst		while (peer != 0 && peer->next != peer_to_remove)
36022347Spst		    peer = peer->next;
36122347Spst
36222347Spst		if (peer == 0) {
36322347Spst			peer_hash_count[hash]++;
36422347Spst			msyslog(LOG_ERR, "peer struct for %s not in table!",
36522347Spst				ntoa(&peer->srcadr));
36622347Spst		} else {
36722347Spst			peer->next = peer_to_remove->next;
36822347Spst		}
36922347Spst	}
37022347Spst
37122347Spst	/*
37222347Spst	 * Remove him from the association hash as well.
37322347Spst	 */
37422347Spst	hash = peer_to_remove->associd & HASH_MASK;
37522347Spst	assoc_hash_count[hash]--;
37622347Spst	if (assoc_hash[hash] == peer_to_remove)
37722347Spst		assoc_hash[hash] = peer_to_remove->ass_next;
37822347Spst	else {
37922347Spst		register struct peer *peer;
38022347Spst
38122347Spst		peer = assoc_hash[hash];
38222347Spst		while (peer != 0 && peer->ass_next != peer_to_remove)
38322347Spst		    peer = peer->ass_next;
38422347Spst
38522347Spst		if (peer == 0) {
38622347Spst			assoc_hash_count[hash]++;
38722347Spst			msyslog(LOG_ERR,
38822347Spst				"peer struct for %s not in association table!",
38922347Spst				ntoa(&peer->srcadr));
39022347Spst		} else {
39122347Spst			peer->ass_next = peer_to_remove->ass_next;
39222347Spst		}
39322347Spst	}
39422347Spst	peer_to_remove->next = peer_free;
39522347Spst	peer_free = peer_to_remove;
39622347Spst	peer_free_count++;
39722347Spst}
39822347Spst
39922347Spst
40022347Spst/*
40122347Spst * peer_config - configure a new association
40222347Spst */
40322347Spststruct peer *
40422347Spstpeer_config(
40522347Spst	struct sockaddr_in *srcadr,
40622347Spst	struct interface *dstadr,
40722347Spst	int hmode,
40822347Spst	int version,
40922347Spst	int minpoll,
41022347Spst	int maxpoll,
41122347Spst	u_int flags,
41222347Spst	int ttl,
41322347Spst	keyid_t key,
41422347Spst	u_char *keystr
41522347Spst	)
41622347Spst{
41722347Spst	register struct peer *peer;
41822347Spst	u_int cast_flags;
41922347Spst
42022347Spst	/*
42122347Spst	 * First search from the beginning for an association with given
42222347Spst	 * remote address and mode. If an interface is given, search
42322347Spst	 * from there to find the association which matches that
42422347Spst	 * destination.
42522347Spst	 */
42622347Spst	peer = findexistingpeer(srcadr, (struct peer *)0, hmode);
42722347Spst	if (dstadr != 0) {
42822347Spst		while (peer != 0) {
42922347Spst			if (peer->dstadr == dstadr)
43022347Spst				break;
43122347Spst			peer = findexistingpeer(srcadr, peer, hmode);
43222347Spst		}
43322347Spst	}
43422347Spst
43522347Spst	/*
43622347Spst	 * We do a dirty little jig to figure the cast flags. This is
43722347Spst	 * probably not the best place to do this, at least until the
43822347Spst	 * configure code is rebuilt. Note only one flag can be set.
43922347Spst	 */
44022347Spst	switch (hmode) {
44122347Spst
44222347Spst	case MODE_BROADCAST:
44322347Spst		if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)))
44422347Spst			cast_flags = MDF_MCAST;
44522347Spst		else
44622347Spst			cast_flags = MDF_BCAST;
44722347Spst		break;
44822347Spst
44922347Spst	case MODE_CLIENT:
45022347Spst		if (IN_CLASSD(ntohl(srcadr->sin_addr.s_addr)))
45122347Spst			cast_flags = MDF_ACAST;
45222347Spst		else
45322347Spst			cast_flags = MDF_UCAST;
45422347Spst		break;
45522347Spst
45622347Spst	default:
45722347Spst		cast_flags = MDF_UCAST;
45822347Spst		break;
45922347Spst	}
46022347Spst
46122347Spst	/*
46222347Spst	 * If the peer is already configured, some dope has a duplicate
46322347Spst	 * configureation entry or another dope is wiggling from afar.
46422347Spst	 */
46522347Spst	if (peer != 0) {
46622347Spst		peer->hmode = (u_char)hmode;
46722347Spst		peer->version = (u_char)version;
46822347Spst		peer->minpoll = (u_char)minpoll;
46922347Spst		peer->maxpoll = (u_char)maxpoll;
47022347Spst		peer->hpoll = peer->kpoll = peer->minpoll;
47122347Spst		peer->ppoll = peer->maxpoll;
47222347Spst		peer->flags = flags | FLAG_CONFIG |
47322347Spst			(peer->flags & FLAG_REFCLOCK);
47422347Spst		peer->cast_flags = cast_flags;
47522347Spst		peer->ttlmax = ttl;
47622347Spst		peer->keyid = key;
47722347Spst		return (peer);
47822347Spst	}
47922347Spst
48022347Spst	/*
48122347Spst	 * Here no match has been found, so presumably this is a new
48222347Spst	 * persistent association. Mobilize the thing and initialize its
48322347Spst	 * variables.
48422347Spst	 */
48522347Spst	peer = newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
48622347Spst	    flags | FLAG_CONFIG, cast_flags, ttl, key);
48722347Spst	return (peer);
48822347Spst}
48922347Spst
49022347Spst
49122347Spst/*
49222347Spst * newpeer - initialize a new peer association
49322347Spst */
49422347Spststruct peer *
49522347Spstnewpeer(
49622347Spst	struct sockaddr_in *srcadr,
49722347Spst	struct interface *dstadr,
49822347Spst	int hmode,
49922347Spst	int version,
50022347Spst	int minpoll,
50122347Spst	int maxpoll,
50222347Spst	u_int flags,
50322347Spst	u_int cast_flags,
50422347Spst	int ttl,
50522347Spst	keyid_t key
50622347Spst	)
50722347Spst{
50822347Spst	register struct peer *peer;
50922347Spst	register int i;
51022347Spst
51122347Spst	/*
51222347Spst	 * Allocate a new peer structure. Some dirt here, since some of
51322347Spst	 * the initialization requires knowlege of our system state.
51422347Spst	 */
51522347Spst	if (peer_free_count == 0)
51622347Spst		getmorepeermem();
51722347Spst	peer = peer_free;
51822347Spst	peer_free = peer->next;
51922347Spst	peer_free_count--;
52022347Spst	peer_associations++;
52122347Spst	memset((char *)peer, 0, sizeof(struct peer));
52222347Spst
52322347Spst	/*
52422347Spst	 * Initialize the peer structure and dance the interface jig.
52522347Spst	 * Reference clocks step the loopback waltz, the others
52622347Spst	 * squaredance around the interface list looking for a buddy. If
52722347Spst	 * the dance peters out, there is always the wildcard interface.
52822347Spst	 * This might happen in some systems and would preclude proper
52922347Spst	 * operation with public key cryptography.
53022347Spst	 */
53122347Spst	if (ISREFCLOCKADR(srcadr))
53222347Spst		peer->dstadr = loopback_interface;
53322347Spst	else if (cast_flags & MDF_BCLNT)
53422347Spst		peer->dstadr = findbcastinter(srcadr);
53522347Spst	else if (dstadr != any_interface)
53622347Spst		peer->dstadr = dstadr;
53722347Spst	else
53822347Spst		peer->dstadr = findinterface(srcadr);
53922347Spst	peer->srcadr = *srcadr;
54022347Spst	peer->hmode = (u_char)hmode;
54122347Spst	peer->version = (u_char)version;
54222347Spst	peer->minpoll = (u_char)max(NTP_MINPOLL, minpoll);
54322347Spst	peer->maxpoll = (u_char)min(NTP_MAXPOLL, maxpoll);
54422347Spst	peer->flags = flags | (key > NTP_MAXKEY ? FLAG_SKEY : 0);
54522347Spst	peer->cast_flags = cast_flags;
54622347Spst	peer->ttlmax = ttl;
54722347Spst	peer->keyid = key;
54822347Spst	peer->precision = sys_precision;
54922347Spst	peer_clear(peer);
55022347Spst	if (mode_ntpdate)
55122347Spst		peer_ntpdate++;
55222347Spst
55322347Spst	/*
55422347Spst	 * Assign an association ID and increment the system variable.
55522347Spst	 */
55622347Spst	peer->associd = current_association_ID;
55722347Spst	if (++current_association_ID == 0)
55822347Spst		++current_association_ID;
55922347Spst
56022347Spst	/*
56122347Spst	 * Note time on statistics timers.
56222347Spst	 */
56322347Spst	peer->timereset = current_time;
56422347Spst	peer->timereachable = current_time;
56522347Spst	peer->timereceived = current_time;
56622347Spst#ifdef REFCLOCK
56722347Spst	if (ISREFCLOCKADR(&peer->srcadr)) {
56822347Spst		/*
56922347Spst		 * We let the reference clock support do clock
57022347Spst		 * dependent initialization.  This includes setting
57131940Salex		 * the peer timer, since the clock may have requirements
57231940Salex		 * for this.
57322347Spst		 */
57422347Spst		if (!refclock_newpeer(peer)) {
57522347Spst			/*
57622347Spst			 * Dump it, something screwed up
57722347Spst			 */
57822347Spst			peer->next = peer_free;
57922347Spst			peer_free = peer;
58022347Spst			peer_free_count++;
58122347Spst			return (NULL);
58222347Spst		}
58322347Spst	}
58422347Spst#endif
58522347Spst
58622347Spst	/*
58722347Spst	 * Put the new peer in the hash tables.
58822347Spst	 */
58922347Spst	i = HASH_ADDR(&peer->srcadr);
59022347Spst	peer->next = peer_hash[i];
59122347Spst	peer_hash[i] = peer;
59222347Spst	peer_hash_count[i]++;
59322347Spst	i = peer->associd & HASH_MASK;
59422347Spst	peer->ass_next = assoc_hash[i];
59522347Spst	assoc_hash[i] = peer;
59622347Spst	assoc_hash_count[i]++;
59722347Spst#ifdef DEBUG
59822347Spst	if (debug)
59922347Spst		printf(
60022347Spst		    "newpeer: %s->%s mode %d vers %d poll %d %d flags %x %x ttl %d key %08x\n",
60122347Spst		    ntoa(&peer->dstadr->sin), ntoa(&peer->srcadr),
60222347Spst		    peer->hmode, peer->version, peer->minpoll,
60322347Spst		    peer->maxpoll, peer->flags, peer->cast_flags,
60422347Spst		    peer->ttlmax, peer->keyid);
60522347Spst#endif
60622347Spst	return (peer);
60722347Spst}
60822347Spst
60922347Spst
61022347Spst/*
61122347Spst * peer_unconfig - remove the configuration bit from a peer
61222347Spst */
61322347Spstint
61422347Spstpeer_unconfig(
61522347Spst	struct sockaddr_in *srcadr,
61622347Spst	struct interface *dstadr,
61722347Spst	int mode
61822347Spst	)
61922347Spst{
62022347Spst	register struct peer *peer;
62122347Spst	int num_found;
62222347Spst
62322347Spst	num_found = 0;
62422347Spst	peer = findexistingpeer(srcadr, (struct peer *)0, mode);
62522347Spst	while (peer != 0) {
62622347Spst		if (peer->flags & FLAG_CONFIG
62722347Spst		    && (dstadr == 0 || peer->dstadr == dstadr)) {
62822347Spst			num_found++;
62922347Spst
63022347Spst			/*
63122347Spst			 * Tricky stuff here. If the peer is polling us
63222347Spst			 * in active mode, turn off the configuration
63322347Spst			 * bit and make the mode passive. This allows us
63422347Spst			 * to avoid dumping a lot of history for peers
63522347Spst			 * we might choose to keep track of in passive
63622347Spst			 * mode. The protocol will eventually terminate
63722347Spst			 * undesirables on its own.
63822347Spst			 */
63922347Spst			if (peer->hmode == MODE_ACTIVE
64022347Spst			    && peer->pmode == MODE_ACTIVE) {
64122347Spst				peer->hmode = MODE_PASSIVE;
64222347Spst				peer->flags &= ~FLAG_CONFIG;
64322347Spst			} else {
64422347Spst				unpeer(peer);
64522347Spst				peer = 0;
64622347Spst			}
64722347Spst		}
64822347Spst		peer = findexistingpeer(srcadr, peer, mode);
64922347Spst	}
65022347Spst	return (num_found);
65122347Spst}
65222347Spst
65322347Spst/*
65422347Spst * peer_clr_stats - clear peer module stat counters
65522347Spst */
65622347Spstvoid
65722347Spstpeer_clr_stats(void)
65822347Spst{
65922347Spst	findpeer_calls = 0;
66022347Spst	assocpeer_calls = 0;
66122347Spst	peer_allocations = 0;
66222347Spst	peer_demobilizations = 0;
66322347Spst	peer_timereset = current_time;
66422347Spst}
66522347Spst
66622347Spst/*
66722347Spst * peer_reset - reset stat counters in a peer structure
66822347Spst */
66922347Spstvoid
67022347Spstpeer_reset(
67122347Spst	struct peer *peer
67222347Spst	)
67322347Spst{
67422347Spst	if (peer == 0)
67522347Spst	    return;
67622347Spst	peer->sent = 0;
67722347Spst	peer->received = 0;
67822347Spst	peer->processed = 0;
67922347Spst	peer->badauth = 0;
68022347Spst	peer->bogusorg = 0;
68122347Spst	peer->oldpkt = 0;
68222347Spst	peer->seldisptoolarge = 0;
68322347Spst	peer->selbroken = 0;
68422347Spst	peer->timereset = current_time;
68522347Spst}
68622347Spst
68722347Spst
68822347Spst/*
68922347Spst * peer_all_reset - reset all peer stat counters
69022347Spst */
69122347Spstvoid
69222347Spstpeer_all_reset(void)
69322347Spst{
69422347Spst	struct peer *peer;
69522347Spst	int hash;
69622347Spst
69722347Spst	for (hash = 0; hash < HASH_SIZE; hash++)
69822347Spst	    for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
69922347Spst		peer_reset(peer);
70022347Spst}
70122347Spst
70222347Spst
70322347Spst#ifdef AUTOKEY
70422347Spst/*
70522347Spst * expire_all - flush all crypto data and update timestamps.
70622347Spst */
70722347Spstvoid
70822347Spstexpire_all(void)
70922347Spst{
71022347Spst	struct peer *peer, *next_peer;
71122347Spst	int n;
71222347Spst
71322347Spst	/*
71422347Spst	 * This routine is called about once per day from the timer
71522347Spst	 * routine and when the client is first synchronized. Search the
71622347Spst	 * peer list for all associations and flush only the key list
71722347Spst	 * and cookie. If a manycast client association, flush
71822347Spst	 * everything. Then, recompute and sign the agreement public
71922347Spst	 * value, if present.
72022347Spst	 */
72122347Spst	for (n = 0; n < HASH_SIZE; n++) {
72222347Spst		for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
72322347Spst			next_peer = peer->next;
72422347Spst			if (peer->cast_flags & MDF_ACAST) {
72522347Spst				peer_clear(peer);
72622347Spst#ifdef AUTOKEY
72722347Spst			} else {
72822347Spst				key_expire(peer);
72922347Spst				peer->pcookie.tstamp = 0;
73022347Spst#endif /* AUTOKEY */
73122347Spst			}
73222347Spst
73322347Spst		}
73422347Spst	}
73522347Spst	sys_private = (u_int32)RANDOM & 0xffffffff;
73622347Spst#ifdef PUBKEY
73722347Spst	crypto_agree();
73822347Spst#endif /* PUBKEY */
73922347Spst#ifdef DEBUG
74022347Spst	if (debug)
74122347Spst		printf("expire_all: at %lu\n", current_time);
74222347Spst#endif
74322347Spst}
74422347Spst#endif /* AUTOKEY */
74522347Spst
74622347Spst
74722347Spst/*
74822347Spst * findmanycastpeer - find and return a manycast peer
74922347Spst */
75022347Spststruct peer *
75122347Spstfindmanycastpeer(
75222347Spst	struct recvbuf *rbufp
75322347Spst	)
75422347Spst{
75522347Spst	register struct peer *peer;
75622347Spst	struct pkt *pkt;
75722347Spst	l_fp p_org;
75822347Spst	int i;
75922347Spst
76022347Spst 	/*
76122347Spst 	 * This routine is called upon arrival of a client-mode message
76222347Spst	 * from a manycast server. Search the peer list for a manycast
76322347Spst	 * client association where the last transmit timestamp matches
76422347Spst	 * the originate timestamp. This assumes the transmit timestamps
76522347Spst	 * for possibly more than one manycast association are unique.
76622347Spst	 */
76722347Spst	pkt = &rbufp->recv_pkt;
76822347Spst	for (i = 0; i < HASH_SIZE; i++) {
76922347Spst		if (peer_hash_count[i] == 0)
77022347Spst			continue;
77122347Spst
77222347Spst		for (peer = peer_hash[i]; peer != 0; peer =
77322347Spst		    peer->next) {
77422347Spst			if (peer->cast_flags & MDF_ACAST) {
77522347Spst				NTOHL_FP(&pkt->org, &p_org);
77622347Spst				if (L_ISEQU(&peer->xmt, &p_org))
77722347Spst					return (peer);
77822347Spst			}
77922347Spst		}
78022347Spst	}
78122347Spst	return (NULL);
78222347Spst}
78322347Spst
78422347Spst
78522347Spst/*
78622347Spst * resetmanycast - reset all manycast clients
78722347Spst */
78822347Spstvoid
78922347Spstresetmanycast(void)
79022347Spst{
79122347Spst	register struct peer *peer;
79222347Spst	int i;
79322347Spst
79422347Spst	/*
79522347Spst	 * This routine is called when the number of client associations
79622347Spst	 * falls below the minimum. Search the peer list for manycast
79722347Spst	 * client associations and reset the ttl and poll interval.
79822347Spst	 */
79922347Spst	for (i = 0; i < HASH_SIZE; i++) {
80022347Spst		if (peer_hash_count[i] == 0)
80122347Spst			continue;
80222347Spst
80322347Spst		for (peer = peer_hash[i]; peer != 0; peer =
80422347Spst		    peer->next) {
80522347Spst			if (peer->cast_flags & MDF_ACAST) {
80622347Spst				peer->ttl = 0;
80722347Spst				poll_update(peer, peer->hpoll);
80822347Spst			}
80922347Spst		}
81022347Spst	}
81122347Spst}
81222347Spst