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