154359Sroberto/* 254359Sroberto * ntp_peer.c - management of data maintained for peer associations 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto#include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include <stdio.h> 954359Sroberto#include <sys/types.h> 1054359Sroberto 1154359Sroberto#include "ntpd.h" 12285612Sdelphij#include "ntp_lists.h" 1354359Sroberto#include "ntp_stdlib.h" 14285612Sdelphij#include "ntp_control.h" 15182007Sroberto#include <ntp_random.h> 1654359Sroberto 1754359Sroberto/* 18285612Sdelphij * Table of valid association combinations 19285612Sdelphij * --------------------------------------- 2054359Sroberto * 2154359Sroberto * packet->mode 2254359Sroberto * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST 2354359Sroberto * ---------- | --------------------------------------------- 24182007Sroberto * NO_PEER | e 1 0 1 1 1 2554359Sroberto * ACTIVE | e 1 1 0 0 0 2654359Sroberto * PASSIVE | e 1 e 0 0 0 27285612Sdelphij * CLIENT | e 0 0 0 1 0 2854359Sroberto * SERVER | e 0 0 0 0 0 29182007Sroberto * BCAST | e 0 0 0 0 0 3054359Sroberto * BCLIENT | e 0 0 0 e 1 3154359Sroberto * 3282498Sroberto * One point to note here: a packet in BCAST mode can potentially match 3382498Sroberto * a peer in CLIENT mode, but we that is a special case and we check for 3482498Sroberto * that early in the decision process. This avoids having to keep track 3582498Sroberto * of what kind of associations are possible etc... We actually 3682498Sroberto * circumvent that problem by requiring that the first b(m)roadcast 3782498Sroberto * received after the change back to BCLIENT mode sets the clock. 3854359Sroberto */ 39182007Sroberto#define AM_MODES 7 /* number of rows and columns */ 40182007Sroberto#define NO_PEER 0 /* action when no peer is found */ 4154359Sroberto 4254359Srobertoint AM[AM_MODES][AM_MODES] = { 43285612Sdelphij/* packet->mode */ 44285612Sdelphij/* peer { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */ 45285612Sdelphij/* mode */ 46182007Sroberto/*NONE*/{ AM_ERR, AM_NEWPASS, AM_NOMATCH, AM_FXMIT, AM_MANYCAST, AM_NEWBCL}, 4754359Sroberto 4854359Sroberto/*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 4954359Sroberto 5054359Sroberto/*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 5154359Sroberto 52285612Sdelphij/*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_NOMATCH}, 5354359Sroberto 5454359Sroberto/*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 5554359Sroberto 5654359Sroberto/*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH}, 5754359Sroberto 58182007Sroberto/*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT}, 5954359Sroberto}; 6054359Sroberto 61285612Sdelphij#define MATCH_ASSOC(x, y) AM[(x)][(y)] 6254359Sroberto 6354359Sroberto/* 6454359Sroberto * These routines manage the allocation of memory to peer structures 65285612Sdelphij * and the maintenance of three data structures involving all peers: 66285612Sdelphij * 67285612Sdelphij * - peer_list is a single list with all peers, suitable for scanning 68285612Sdelphij * operations over all peers. 69285612Sdelphij * - peer_adr_hash is an array of lists indexed by hashed peer address. 70285612Sdelphij * - peer_aid_hash is an array of lists indexed by hashed associd. 71285612Sdelphij * 72285612Sdelphij * They also maintain a free list of peer structures, peer_free. 73285612Sdelphij * 74285612Sdelphij * The three main entry points are findpeer(), which looks for matching 75285612Sdelphij * peer structures in the peer list, newpeer(), which allocates a new 76285612Sdelphij * peer structure and adds it to the list, and unpeer(), which 77285612Sdelphij * demobilizes the association and deallocates the structure. 7854359Sroberto */ 7954359Sroberto/* 8082498Sroberto * Peer hash tables 8154359Sroberto */ 82182007Srobertostruct peer *peer_hash[NTP_HASH_SIZE]; /* peer hash table */ 83285612Sdelphijint peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */ 84182007Srobertostruct peer *assoc_hash[NTP_HASH_SIZE]; /* association ID hash table */ 85285612Sdelphijint assoc_hash_count[NTP_HASH_SIZE];/* peers in each bucket */ 86285612Sdelphijstruct peer *peer_list; /* peer structures list */ 8782498Srobertostatic struct peer *peer_free; /* peer structures free list */ 88285612Sdelphijint peer_free_count; /* count of free structures */ 8954359Sroberto 9054359Sroberto/* 9182498Sroberto * Association ID. We initialize this value randomly, then assign a new 92285612Sdelphij * value every time an association is mobilized. 9354359Sroberto */ 9482498Srobertostatic associd_t current_association_ID; /* association ID */ 95285612Sdelphijstatic associd_t initial_association_ID; /* association ID */ 9654359Sroberto 9754359Sroberto/* 9854359Sroberto * Memory allocation watermarks. 9954359Sroberto */ 100285612Sdelphij#define INIT_PEER_ALLOC 8 /* static preallocation */ 101285612Sdelphij#define INC_PEER_ALLOC 4 /* add N more when empty */ 10254359Sroberto 10354359Sroberto/* 10454359Sroberto * Miscellaneous statistic counters which may be queried. 10554359Sroberto */ 106285612Sdelphiju_long peer_timereset; /* time stat counters zeroed */ 107285612Sdelphiju_long findpeer_calls; /* calls to findpeer */ 108285612Sdelphiju_long assocpeer_calls; /* calls to findpeerbyassoc */ 109285612Sdelphiju_long peer_allocations; /* allocations from free list */ 110285612Sdelphiju_long peer_demobilizations; /* structs freed to free list */ 111285612Sdelphijint total_peer_structs; /* peer structs */ 112285612Sdelphijint peer_associations; /* mobilized associations */ 113285612Sdelphijint peer_preempt; /* preemptable associations */ 11482498Srobertostatic struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */ 11554359Sroberto 116285612Sdelphijstatic struct peer * findexistingpeer_name(const char *, u_short, 117285612Sdelphij struct peer *, int); 118285612Sdelphijstatic struct peer * findexistingpeer_addr(sockaddr_u *, 119285612Sdelphij struct peer *, int, 120330567Sgordon u_char, int *); 121285612Sdelphijstatic void free_peer(struct peer *, int); 122285612Sdelphijstatic void getmorepeermem(void); 123285612Sdelphijstatic int score(struct peer *); 12454359Sroberto 125285612Sdelphij 12654359Sroberto/* 12754359Sroberto * init_peer - initialize peer data structures and counters 12854359Sroberto * 12982498Sroberto * N.B. We use the random number routine in here. It had better be 13082498Sroberto * initialized prior to getting here. 13154359Sroberto */ 13254359Srobertovoid 13354359Srobertoinit_peer(void) 13454359Sroberto{ 135285612Sdelphij int i; 13654359Sroberto 13754359Sroberto /* 138285612Sdelphij * Initialize peer free list from static allocation. 13954359Sroberto */ 140285612Sdelphij for (i = COUNTOF(init_peer_alloc) - 1; i >= 0; i--) 141285612Sdelphij LINK_SLIST(peer_free, &init_peer_alloc[i], p_link); 142285612Sdelphij total_peer_structs = COUNTOF(init_peer_alloc); 143285612Sdelphij peer_free_count = COUNTOF(init_peer_alloc); 14454359Sroberto 14554359Sroberto /* 14654359Sroberto * Initialize our first association ID 14754359Sroberto */ 148285612Sdelphij do 149285612Sdelphij current_association_ID = ntp_random() & ASSOCID_MAX; 150285612Sdelphij while (!current_association_ID); 151285612Sdelphij initial_association_ID = current_association_ID; 15254359Sroberto} 15354359Sroberto 15454359Sroberto 15554359Sroberto/* 15654359Sroberto * getmorepeermem - add more peer structures to the free list 15754359Sroberto */ 15854359Srobertostatic void 15954359Srobertogetmorepeermem(void) 16054359Sroberto{ 161285612Sdelphij int i; 162285612Sdelphij struct peer *peers; 16354359Sroberto 164316722Sdelphij peers = eallocarray(INC_PEER_ALLOC, sizeof(*peers)); 16554359Sroberto 166285612Sdelphij for (i = INC_PEER_ALLOC - 1; i >= 0; i--) 167285612Sdelphij LINK_SLIST(peer_free, &peers[i], p_link); 168285612Sdelphij 16954359Sroberto total_peer_structs += INC_PEER_ALLOC; 17054359Sroberto peer_free_count += INC_PEER_ALLOC; 17154359Sroberto} 17254359Sroberto 17354359Sroberto 174285612Sdelphijstatic struct peer * 175285612Sdelphijfindexistingpeer_name( 176285612Sdelphij const char * hostname, 177285612Sdelphij u_short hname_fam, 178285612Sdelphij struct peer * start_peer, 179285612Sdelphij int mode 18054359Sroberto ) 18154359Sroberto{ 182285612Sdelphij struct peer *p; 18354359Sroberto 184285612Sdelphij if (NULL == start_peer) 185285612Sdelphij p = peer_list; 186285612Sdelphij else 187285612Sdelphij p = start_peer->p_link; 188285612Sdelphij for (; p != NULL; p = p->p_link) 189285612Sdelphij if (p->hostname != NULL 190285612Sdelphij && (-1 == mode || p->hmode == mode) 191285612Sdelphij && (AF_UNSPEC == hname_fam 192285612Sdelphij || AF_UNSPEC == AF(&p->srcadr) 193285612Sdelphij || hname_fam == AF(&p->srcadr)) 194285612Sdelphij && !strcasecmp(p->hostname, hostname)) 195285612Sdelphij break; 196285612Sdelphij return p; 197285612Sdelphij} 198285612Sdelphij 199285612Sdelphij 200285612Sdelphijstatic 201285612Sdelphijstruct peer * 202285612Sdelphijfindexistingpeer_addr( 203285612Sdelphij sockaddr_u * addr, 204285612Sdelphij struct peer * start_peer, 205285612Sdelphij int mode, 206330567Sgordon u_char cast_flags, 207330567Sgordon int * ip_count 208285612Sdelphij ) 209285612Sdelphij{ 210285612Sdelphij struct peer *peer; 211285612Sdelphij 212330567Sgordon DPRINTF(2, ("findexistingpeer_addr(%s, %s, %d, 0x%x, %p)\n", 213285612Sdelphij sptoa(addr), 214285612Sdelphij (start_peer) 215285612Sdelphij ? sptoa(&start_peer->srcadr) 216285612Sdelphij : "NULL", 217330567Sgordon mode, (u_int)cast_flags, ip_count)); 218285612Sdelphij 21954359Sroberto /* 22054359Sroberto * start_peer is included so we can locate instances of the 22154359Sroberto * same peer through different interfaces in the hash table. 222285612Sdelphij * Without MDF_BCLNT, a match requires the same mode and remote 223285612Sdelphij * address. MDF_BCLNT associations start out as MODE_CLIENT 224285612Sdelphij * if broadcastdelay is not specified, and switch to 225285612Sdelphij * MODE_BCLIENT after estimating the one-way delay. Duplicate 226285612Sdelphij * associations are expanded in definition to match any other 227285612Sdelphij * MDF_BCLNT with the same srcadr (remote, unicast address). 22854359Sroberto */ 229285612Sdelphij if (NULL == start_peer) 230182007Sroberto peer = peer_hash[NTP_HASH_ADDR(addr)]; 23154359Sroberto else 232285612Sdelphij peer = start_peer->adr_link; 23354359Sroberto 234285612Sdelphij while (peer != NULL) { 235285612Sdelphij DPRINTF(3, ("%s %s %d %d 0x%x 0x%x ", sptoa(addr), 236285612Sdelphij sptoa(&peer->srcadr), mode, peer->hmode, 237285612Sdelphij (u_int)cast_flags, (u_int)peer->cast_flags)); 238330567Sgordon if (ip_count) { 239330567Sgordon if (SOCK_EQ(addr, &peer->srcadr)) { 240330567Sgordon (*ip_count)++; 241330567Sgordon } 242330567Sgordon } 243285612Sdelphij if ((-1 == mode || peer->hmode == mode || 244285612Sdelphij ((MDF_BCLNT & peer->cast_flags) && 245285612Sdelphij (MDF_BCLNT & cast_flags))) && 246285612Sdelphij ADDR_PORT_EQ(addr, &peer->srcadr)) { 247285612Sdelphij DPRINTF(3, ("found.\n")); 248285612Sdelphij break; 24954359Sroberto } 250285612Sdelphij DPRINTF(3, ("\n")); 251285612Sdelphij peer = peer->adr_link; 25254359Sroberto } 253285612Sdelphij 254285612Sdelphij return peer; 25554359Sroberto} 25654359Sroberto 25754359Sroberto 25854359Sroberto/* 259285612Sdelphij * findexistingpeer - search by address and return a pointer to a peer. 26054359Sroberto */ 26154359Srobertostruct peer * 262285612Sdelphijfindexistingpeer( 263285612Sdelphij sockaddr_u * addr, 264285612Sdelphij const char * hostname, 265285612Sdelphij struct peer * start_peer, 266285612Sdelphij int mode, 267330567Sgordon u_char cast_flags, 268330567Sgordon int * ip_count 269285612Sdelphij ) 270285612Sdelphij{ 271285612Sdelphij if (hostname != NULL) 272285612Sdelphij return findexistingpeer_name(hostname, AF(addr), 273285612Sdelphij start_peer, mode); 274285612Sdelphij else 275285612Sdelphij return findexistingpeer_addr(addr, start_peer, mode, 276330567Sgordon cast_flags, ip_count); 277285612Sdelphij} 278285612Sdelphij 279285612Sdelphij 280285612Sdelphij/* 281285612Sdelphij * findpeer - find and return a peer match for a received datagram in 282285612Sdelphij * the peer_hash table. 283310419Sdelphij * 284310419Sdelphij * [Bug 3072] To faciliate a faster reorganisation after routing changes 285310419Sdelphij * the original code re-assigned the peer address to be the destination 286310419Sdelphij * of the received packet and initiated another round on a mismatch. 287310419Sdelphij * Unfortunately this leaves us wide open for a DoS attack where the 288310419Sdelphij * attacker directs a packet with forged destination address to us -- 289310419Sdelphij * this results in a wrong interface assignment, actually creating a DoS 290310419Sdelphij * situation. 291310419Sdelphij * 292310419Sdelphij * This condition would persist until the next update of the interface 293310419Sdelphij * list, but a continued attack would put us out of business again soon 294310419Sdelphij * enough. Authentication alone does not help here, since it does not 295310419Sdelphij * protect the UDP layer and leaves us open for a replay attack. 296310419Sdelphij * 297310419Sdelphij * So we do not update the adresses and wait until the next interface 298310419Sdelphij * list update does the right thing for us. 299285612Sdelphij */ 300285612Sdelphijstruct peer * 30154359Srobertofindpeer( 302285612Sdelphij struct recvbuf *rbufp, 303285612Sdelphij int pkt_mode, 304285612Sdelphij int * action 30554359Sroberto ) 30654359Sroberto{ 307285612Sdelphij struct peer * p; 308285612Sdelphij sockaddr_u * srcadr; 309285612Sdelphij u_int hash; 310285612Sdelphij struct pkt * pkt; 311285612Sdelphij l_fp pkt_org; 31254359Sroberto 31354359Sroberto findpeer_calls++; 314285612Sdelphij srcadr = &rbufp->recv_srcadr; 315182007Sroberto hash = NTP_HASH_ADDR(srcadr); 316285612Sdelphij for (p = peer_hash[hash]; p != NULL; p = p->adr_link) { 31782498Sroberto 318310419Sdelphij /* [Bug 3072] ensure interface of peer matches */ 319316722Sdelphij /* [Bug 3356] ... if NOT a broadcast peer! */ 320316722Sdelphij if (p->hmode != MODE_BCLIENT && p->dstadr != rbufp->dstadr) 321310419Sdelphij continue; 32254359Sroberto 323310419Sdelphij /* ensure peer source address matches */ 324310419Sdelphij if ( ! ADDR_PORT_EQ(srcadr, &p->srcadr)) 325310419Sdelphij continue; 326310419Sdelphij 327310419Sdelphij /* If the association matching rules determine that this 328310419Sdelphij * is not a valid combination, then look for the next 329310419Sdelphij * valid peer association. 330310419Sdelphij */ 331310419Sdelphij *action = MATCH_ASSOC(p->hmode, pkt_mode); 332285612Sdelphij 333310419Sdelphij /* A response to our manycastclient solicitation might 334310419Sdelphij * be misassociated with an ephemeral peer already spun 335310419Sdelphij * for the server. If the packet's org timestamp 336310419Sdelphij * doesn't match the peer's, check if it matches the 337310419Sdelphij * ACST prototype peer's. If so it is a redundant 338310419Sdelphij * solicitation response, return AM_ERR to discard it. 339310419Sdelphij * [Bug 1762] 340310419Sdelphij */ 341310419Sdelphij if (MODE_SERVER == pkt_mode && AM_PROCPKT == *action) { 342310419Sdelphij pkt = &rbufp->recv_pkt; 343310419Sdelphij NTOHL_FP(&pkt->org, &pkt_org); 344310419Sdelphij if (!L_ISEQU(&p->aorg, &pkt_org) && 345310419Sdelphij findmanycastpeer(rbufp)) 346310419Sdelphij *action = AM_ERR; 347310419Sdelphij } 34854359Sroberto 349310419Sdelphij /* if an error was returned, exit back right here. */ 350310419Sdelphij if (*action == AM_ERR) 351310419Sdelphij return NULL; 352310419Sdelphij 353310419Sdelphij /* if a match is found, we stop our search. */ 354310419Sdelphij if (*action != AM_NOMATCH) 355310419Sdelphij break; 35654359Sroberto } 35754359Sroberto 358310419Sdelphij /* If no matching association is found... */ 359310419Sdelphij if (NULL == p) 36054359Sroberto *action = MATCH_ASSOC(NO_PEER, pkt_mode); 361310419Sdelphij 362285612Sdelphij return p; 36354359Sroberto} 36454359Sroberto 36554359Sroberto/* 366285612Sdelphij * findpeerbyassoc - find and return a peer using his association ID 36754359Sroberto */ 36854359Srobertostruct peer * 36954359Srobertofindpeerbyassoc( 370285612Sdelphij associd_t assoc 37154359Sroberto ) 37254359Sroberto{ 373285612Sdelphij struct peer *p; 374285612Sdelphij u_int hash; 37554359Sroberto 37654359Sroberto assocpeer_calls++; 377182007Sroberto hash = assoc & NTP_HASH_MASK; 378285612Sdelphij for (p = assoc_hash[hash]; p != NULL; p = p->aid_link) 379285612Sdelphij if (assoc == p->associd) 380285612Sdelphij break; 381285612Sdelphij return p; 38254359Sroberto} 38354359Sroberto 38454359Sroberto 38554359Sroberto/* 38682498Sroberto * clear_all - flush all time values for all associations 38754359Sroberto */ 38854359Srobertovoid 38982498Srobertoclear_all(void) 39054359Sroberto{ 391285612Sdelphij struct peer *p; 39254359Sroberto 39382498Sroberto /* 39482498Sroberto * This routine is called when the clock is stepped, and so all 39582498Sroberto * previously saved time values are untrusted. 39682498Sroberto */ 397285612Sdelphij for (p = peer_list; p != NULL; p = p->p_link) 398285612Sdelphij if (!(MDF_TXONLY_MASK & p->cast_flags)) 399285612Sdelphij peer_clear(p, "STEP"); 400285612Sdelphij 401285612Sdelphij DPRINTF(1, ("clear_all: at %lu\n", current_time)); 40254359Sroberto} 40382498Sroberto 40482498Sroberto 40554359Sroberto/* 406285612Sdelphij * score_all() - determine if an association can be demobilized 40754359Sroberto */ 408285612Sdelphijint 409285612Sdelphijscore_all( 410285612Sdelphij struct peer *peer /* peer structure pointer */ 41154359Sroberto ) 41254359Sroberto{ 413285612Sdelphij struct peer *speer; 414285612Sdelphij int temp, tamp; 415285612Sdelphij int x; 41654359Sroberto 417285612Sdelphij /* 418285612Sdelphij * This routine finds the minimum score for all preemptible 419285612Sdelphij * associations and returns > 0 if the association can be 420285612Sdelphij * demobilized. 421285612Sdelphij */ 422285612Sdelphij tamp = score(peer); 423285612Sdelphij temp = 100; 424285612Sdelphij for (speer = peer_list; speer != NULL; speer = speer->p_link) 425285612Sdelphij if (speer->flags & FLAG_PREEMPT) { 426285612Sdelphij x = score(speer); 427285612Sdelphij if (x < temp) 428285612Sdelphij temp = x; 429285612Sdelphij } 430285612Sdelphij DPRINTF(1, ("score_all: at %lu score %d min %d\n", 431285612Sdelphij current_time, tamp, temp)); 432182007Sroberto 433285612Sdelphij if (tamp != temp) 434285612Sdelphij temp = 0; 435182007Sroberto 436285612Sdelphij return temp; 437285612Sdelphij} 438285612Sdelphij 439285612Sdelphij 440285612Sdelphij/* 441285612Sdelphij * score() - calculate preemption score 442285612Sdelphij */ 443285612Sdelphijstatic int 444285612Sdelphijscore( 445285612Sdelphij struct peer *peer /* peer structure pointer */ 446285612Sdelphij ) 447285612Sdelphij{ 448285612Sdelphij int temp; 449285612Sdelphij 45054359Sroberto /* 451285612Sdelphij * This routine calculates the premption score from the peer 452285612Sdelphij * error bits and status. Increasing values are more cherished. 45354359Sroberto */ 454285612Sdelphij temp = 0; 455285612Sdelphij if (!(peer->flash & TEST10)) 456285612Sdelphij temp++; /* 1 good synch and stratum */ 457285612Sdelphij if (!(peer->flash & TEST13)) 458285612Sdelphij temp++; /* 2 reachable */ 459285612Sdelphij if (!(peer->flash & TEST12)) 460285612Sdelphij temp++; /* 3 no loop */ 461285612Sdelphij if (!(peer->flash & TEST11)) 462285612Sdelphij temp++; /* 4 good distance */ 463285612Sdelphij if (peer->status >= CTL_PST_SEL_SELCAND) 464285612Sdelphij temp++; /* 5 in the hunt */ 465285612Sdelphij if (peer->status != CTL_PST_SEL_EXCESS) 466285612Sdelphij temp++; /* 6 not spare tire */ 467285612Sdelphij return (temp); /* selection status */ 468285612Sdelphij} 46954359Sroberto 470285612Sdelphij 471285612Sdelphij/* 472285612Sdelphij * free_peer - internal routine to free memory referred to by a struct 473285612Sdelphij * peer and return it to the peer free list. If unlink is 474285612Sdelphij * nonzero, unlink from the various lists. 475285612Sdelphij */ 476285612Sdelphijstatic void 477285612Sdelphijfree_peer( 478285612Sdelphij struct peer * p, 479285612Sdelphij int unlink_peer 480285612Sdelphij ) 481285612Sdelphij{ 482285612Sdelphij struct peer * unlinked; 483285612Sdelphij int hash; 484285612Sdelphij 485285612Sdelphij if (unlink_peer) { 486285612Sdelphij hash = NTP_HASH_ADDR(&p->srcadr); 487285612Sdelphij peer_hash_count[hash]--; 488285612Sdelphij 489285612Sdelphij UNLINK_SLIST(unlinked, peer_hash[hash], p, adr_link, 490285612Sdelphij struct peer); 491285612Sdelphij if (NULL == unlinked) { 49254359Sroberto peer_hash_count[hash]++; 493285612Sdelphij msyslog(LOG_ERR, "peer %s not in address table!", 494285612Sdelphij stoa(&p->srcadr)); 49554359Sroberto } 49654359Sroberto 497285612Sdelphij /* 498285612Sdelphij * Remove him from the association hash as well. 499285612Sdelphij */ 500285612Sdelphij hash = p->associd & NTP_HASH_MASK; 501285612Sdelphij assoc_hash_count[hash]--; 50254359Sroberto 503285612Sdelphij UNLINK_SLIST(unlinked, assoc_hash[hash], p, aid_link, 504285612Sdelphij struct peer); 505285612Sdelphij if (NULL == unlinked) { 50654359Sroberto assoc_hash_count[hash]++; 50754359Sroberto msyslog(LOG_ERR, 508285612Sdelphij "peer %s not in association ID table!", 509285612Sdelphij stoa(&p->srcadr)); 51054359Sroberto } 511285612Sdelphij 512285612Sdelphij /* Remove him from the overall list. */ 513285612Sdelphij UNLINK_SLIST(unlinked, peer_list, p, p_link, 514285612Sdelphij struct peer); 515285612Sdelphij if (NULL == unlinked) 516285612Sdelphij msyslog(LOG_ERR, "%s not in peer list!", 517285612Sdelphij stoa(&p->srcadr)); 51854359Sroberto } 519285612Sdelphij 520285612Sdelphij if (p->hostname != NULL) 521285612Sdelphij free(p->hostname); 522285612Sdelphij 523285612Sdelphij if (p->ident != NULL) 524285612Sdelphij free(p->ident); 525285612Sdelphij 526285612Sdelphij if (p->addrs != NULL) 527285612Sdelphij free(p->addrs); /* from copy_addrinfo_list() */ 528285612Sdelphij 529285612Sdelphij /* Add his corporeal form to peer free list */ 530285612Sdelphij ZERO(*p); 531285612Sdelphij LINK_SLIST(peer_free, p, p_link); 53254359Sroberto peer_free_count++; 53354359Sroberto} 53454359Sroberto 53554359Sroberto 53654359Sroberto/* 537285612Sdelphij * unpeer - remove peer structure from hash table and free structure 538285612Sdelphij */ 539285612Sdelphijvoid 540285612Sdelphijunpeer( 541285612Sdelphij struct peer *peer 542285612Sdelphij ) 543285612Sdelphij{ 544285612Sdelphij mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd); 545285612Sdelphij restrict_source(&peer->srcadr, 1, 0); 546285612Sdelphij set_peerdstadr(peer, NULL); 547285612Sdelphij peer_demobilizations++; 548285612Sdelphij peer_associations--; 549285612Sdelphij if (FLAG_PREEMPT & peer->flags) 550285612Sdelphij peer_preempt--; 551285612Sdelphij#ifdef REFCLOCK 552285612Sdelphij /* 553285612Sdelphij * If this peer is actually a clock, shut it down first 554285612Sdelphij */ 555285612Sdelphij if (FLAG_REFCLOCK & peer->flags) 556285612Sdelphij refclock_unpeer(peer); 557285612Sdelphij#endif 558285612Sdelphij 559285612Sdelphij free_peer(peer, TRUE); 560285612Sdelphij} 561285612Sdelphij 562285612Sdelphij 563285612Sdelphij/* 56482498Sroberto * peer_config - configure a new association 56554359Sroberto */ 56654359Srobertostruct peer * 56754359Srobertopeer_config( 568285612Sdelphij sockaddr_u * srcadr, 569285612Sdelphij const char * hostname, 570285612Sdelphij endpt * dstadr, 571330567Sgordon int ippeerlimit, 572285612Sdelphij u_char hmode, 573285612Sdelphij u_char version, 574285612Sdelphij u_char minpoll, 575285612Sdelphij u_char maxpoll, 576285612Sdelphij u_int flags, 577285612Sdelphij u_int32 ttl, 578285612Sdelphij keyid_t key, 579285612Sdelphij const char * ident /* autokey group */ 58054359Sroberto ) 58154359Sroberto{ 582132451Sroberto u_char cast_flags; 58354359Sroberto 58454359Sroberto /* 58582498Sroberto * We do a dirty little jig to figure the cast flags. This is 58682498Sroberto * probably not the best place to do this, at least until the 58782498Sroberto * configure code is rebuilt. Note only one flag can be set. 58854359Sroberto */ 58982498Sroberto switch (hmode) { 59082498Sroberto case MODE_BROADCAST: 591285612Sdelphij if (IS_MCAST(srcadr)) 592285612Sdelphij cast_flags = MDF_MCAST; 593285612Sdelphij else 594285612Sdelphij cast_flags = MDF_BCAST; 595285612Sdelphij break; 59682498Sroberto 59782498Sroberto case MODE_CLIENT: 598285612Sdelphij if (hostname != NULL && SOCK_UNSPEC(srcadr)) 599285612Sdelphij cast_flags = MDF_POOL; 600285612Sdelphij else if (IS_MCAST(srcadr)) 601285612Sdelphij cast_flags = MDF_ACAST; 602285612Sdelphij else 603285612Sdelphij cast_flags = MDF_UCAST; 604285612Sdelphij break; 60582498Sroberto 60682498Sroberto default: 60782498Sroberto cast_flags = MDF_UCAST; 60882498Sroberto } 60982498Sroberto 61082498Sroberto /* 611285612Sdelphij * Mobilize the association and initialize its variables. If 612285612Sdelphij * emulating ntpdate, force iburst. For pool and manycastclient 613285612Sdelphij * strip FLAG_PREEMPT as the prototype associations are not 614285612Sdelphij * themselves preemptible, though the resulting associations 615285612Sdelphij * are. 61682498Sroberto */ 617285612Sdelphij flags |= FLAG_CONFIG; 618132451Sroberto if (mode_ntpdate) 619132451Sroberto flags |= FLAG_IBURST; 620285612Sdelphij if ((MDF_ACAST | MDF_POOL) & cast_flags) 621285612Sdelphij flags &= ~FLAG_PREEMPT; 622330567Sgordon return newpeer(srcadr, hostname, dstadr, ippeerlimit, hmode, version, 623285612Sdelphij minpoll, maxpoll, flags, cast_flags, ttl, key, ident); 62454359Sroberto} 62554359Sroberto 626182007Sroberto/* 627285612Sdelphij * setup peer dstadr field keeping it in sync with the interface 628285612Sdelphij * structures 629182007Sroberto */ 630182007Srobertovoid 631285612Sdelphijset_peerdstadr( 632285612Sdelphij struct peer * p, 633285612Sdelphij endpt * dstadr 634285612Sdelphij ) 635182007Sroberto{ 636285612Sdelphij struct peer * unlinked; 63754359Sroberto 638310419Sdelphij DEBUG_INSIST(p != NULL); 639310419Sdelphij 640310419Sdelphij if (p == NULL) 641310419Sdelphij return; 642310419Sdelphij 643310419Sdelphij /* check for impossible or identical assignment */ 644285612Sdelphij if (p->dstadr == dstadr) 645285612Sdelphij return; 646182007Sroberto 647285612Sdelphij /* 648285612Sdelphij * Don't accept updates to a separate multicast receive-only 649285612Sdelphij * endpt while a BCLNT peer is running its unicast protocol. 650285612Sdelphij */ 651285612Sdelphij if (dstadr != NULL && (FLAG_BC_VOL & p->flags) && 652285612Sdelphij (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) { 653285612Sdelphij return; 654182007Sroberto } 655310419Sdelphij 656310419Sdelphij /* unlink from list if we have an address prior to assignment */ 657285612Sdelphij if (p->dstadr != NULL) { 658285612Sdelphij p->dstadr->peercnt--; 659285612Sdelphij UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink, 660285612Sdelphij struct peer); 661285612Sdelphij msyslog(LOG_INFO, "%s local addr %s -> %s", 662285612Sdelphij stoa(&p->srcadr), latoa(p->dstadr), 663285612Sdelphij latoa(dstadr)); 664285612Sdelphij } 665310419Sdelphij 666285612Sdelphij p->dstadr = dstadr; 667310419Sdelphij 668310419Sdelphij /* link to list if we have an address after assignment */ 669310419Sdelphij if (p->dstadr != NULL) { 670285612Sdelphij LINK_SLIST(dstadr->peers, p, ilink); 671285612Sdelphij dstadr->peercnt++; 672285612Sdelphij } 673182007Sroberto} 674182007Sroberto 67554359Sroberto/* 676182007Sroberto * attempt to re-rebind interface if necessary 677182007Sroberto */ 678182007Srobertostatic void 679285612Sdelphijpeer_refresh_interface( 680285612Sdelphij struct peer *p 681285612Sdelphij ) 682182007Sroberto{ 683285612Sdelphij endpt * niface; 684285612Sdelphij endpt * piface; 685182007Sroberto 686285612Sdelphij niface = select_peerinterface(p, &p->srcadr, NULL); 687182007Sroberto 688285612Sdelphij DPRINTF(4, ( 689285612Sdelphij "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %u key %08x: new interface: ", 690285612Sdelphij p->dstadr == NULL ? "<null>" : 691285612Sdelphij stoa(&p->dstadr->sin), stoa(&p->srcadr), p->hmode, 692285612Sdelphij p->version, p->minpoll, p->maxpoll, p->flags, p->cast_flags, 693285612Sdelphij p->ttl, p->keyid)); 694285612Sdelphij if (niface != NULL) { 695285612Sdelphij DPRINTF(4, ( 696285612Sdelphij "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s", 697285612Sdelphij niface->fd, niface->bfd, niface->name, 698285612Sdelphij niface->flags, niface->ifindex, 699285612Sdelphij stoa(&niface->sin))); 700285612Sdelphij if (niface->flags & INT_BROADCAST) 701285612Sdelphij DPRINTF(4, (", bcast=%s", 702285612Sdelphij stoa(&niface->bcast))); 703285612Sdelphij DPRINTF(4, (", mask=%s\n", stoa(&niface->mask))); 704285612Sdelphij } else { 705285612Sdelphij DPRINTF(4, ("<NONE>\n")); 706182007Sroberto } 707182007Sroberto 708285612Sdelphij piface = p->dstadr; 709285612Sdelphij set_peerdstadr(p, niface); 710285612Sdelphij if (p->dstadr != NULL) { 711285612Sdelphij /* 712285612Sdelphij * clear crypto if we change the local address 713285612Sdelphij */ 714285612Sdelphij if (p->dstadr != piface && !(MDF_ACAST & p->cast_flags) 715285612Sdelphij && MODE_BROADCAST != p->pmode) 716285612Sdelphij peer_clear(p, "XFAC"); 717182007Sroberto 718182007Sroberto /* 719182007Sroberto * Broadcast needs the socket enabled for broadcast 720182007Sroberto */ 721285612Sdelphij if (MDF_BCAST & p->cast_flags) 722285612Sdelphij enable_broadcast(p->dstadr, &p->srcadr); 723182007Sroberto 724182007Sroberto /* 725285612Sdelphij * Multicast needs the socket interface enabled for 726285612Sdelphij * multicast 727182007Sroberto */ 728285612Sdelphij if (MDF_MCAST & p->cast_flags) 729285612Sdelphij enable_multicast_if(p->dstadr, &p->srcadr); 730182007Sroberto } 731182007Sroberto} 732182007Sroberto 733285612Sdelphij 734182007Sroberto/* 735285612Sdelphij * refresh_all_peerinterfaces - see that all interface bindings are up 736285612Sdelphij * to date 737182007Sroberto */ 738182007Srobertovoid 739182007Srobertorefresh_all_peerinterfaces(void) 740182007Sroberto{ 741285612Sdelphij struct peer *p; 742182007Sroberto 743182007Sroberto /* 744182007Sroberto * this is called when the interface list has changed 745182007Sroberto * give all peers a chance to find a better interface 746289997Sglebius * but only if either they don't have an address already 747289997Sglebius * or if the one they have hasn't worked for a while. 748182007Sroberto */ 749289997Sglebius for (p = peer_list; p != NULL; p = p->p_link) { 750289997Sglebius if (!(p->dstadr && (p->reach & 0x3))) // Bug 2849 XOR 2043 751289997Sglebius peer_refresh_interface(p); 752289997Sglebius } 753182007Sroberto} 754182007Sroberto 755285612Sdelphij 756182007Sroberto/* 757285612Sdelphij * newpeer - initialize a new peer association 758182007Sroberto */ 759285612Sdelphijstruct peer * 760285612Sdelphijnewpeer( 761285612Sdelphij sockaddr_u * srcadr, 762285612Sdelphij const char * hostname, 763285612Sdelphij endpt * dstadr, 764330567Sgordon int ippeerlimit, 765285612Sdelphij u_char hmode, 766285612Sdelphij u_char version, 767285612Sdelphij u_char minpoll, 768285612Sdelphij u_char maxpoll, 769285612Sdelphij u_int flags, 770285612Sdelphij u_char cast_flags, 771285612Sdelphij u_int32 ttl, 772285612Sdelphij keyid_t key, 773285612Sdelphij const char * ident 774285612Sdelphij ) 775182007Sroberto{ 776285612Sdelphij struct peer * peer; 777285612Sdelphij u_int hash; 778330567Sgordon int ip_count = 0; 779285612Sdelphij 780330567Sgordon 781289997Sglebius DEBUG_REQUIRE(srcadr); 782289997Sglebius 783285612Sdelphij#ifdef AUTOKEY 784182007Sroberto /* 785285612Sdelphij * If Autokey is requested but not configured, complain loudly. 786182007Sroberto */ 787285612Sdelphij if (!crypto_flags) { 788285612Sdelphij if (key > NTP_MAXKEY) { 789285612Sdelphij return (NULL); 790182007Sroberto 791285612Sdelphij } else if (flags & FLAG_SKEY) { 792285612Sdelphij msyslog(LOG_ERR, "Autokey not configured"); 793285612Sdelphij return (NULL); 794285612Sdelphij } 795285612Sdelphij } 796285612Sdelphij#endif /* AUTOKEY */ 797285612Sdelphij 798182007Sroberto /* 799285612Sdelphij * For now only pool associations have a hostname. 800182007Sroberto */ 801289997Sglebius INSIST(NULL == hostname || (MDF_POOL & cast_flags)); 802182007Sroberto 803285612Sdelphij /* 804285612Sdelphij * First search from the beginning for an association with given 805285612Sdelphij * remote address and mode. If an interface is given, search 806285612Sdelphij * from there to find the association which matches that 807285612Sdelphij * destination. If the given interface is "any", track down the 808285612Sdelphij * actual interface, because that's what gets put into the peer 809285612Sdelphij * structure. 810285612Sdelphij */ 811285612Sdelphij if (dstadr != NULL) { 812285612Sdelphij peer = findexistingpeer(srcadr, hostname, NULL, hmode, 813330567Sgordon cast_flags, &ip_count); 814285612Sdelphij while (peer != NULL) { 815330567Sgordon if ( peer->dstadr == dstadr 816330567Sgordon || ( (MDF_BCLNT & cast_flags) 817330567Sgordon && (MDF_BCLNT & peer->cast_flags))) 818285612Sdelphij break; 819182007Sroberto 820285612Sdelphij if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) && 821285612Sdelphij peer->dstadr == findinterface(srcadr)) 822285612Sdelphij break; 823182007Sroberto 824285612Sdelphij peer = findexistingpeer(srcadr, hostname, peer, 825330567Sgordon hmode, cast_flags, &ip_count); 826285612Sdelphij } 827285612Sdelphij } else { 828285612Sdelphij /* no endpt address given */ 829285612Sdelphij peer = findexistingpeer(srcadr, hostname, NULL, hmode, 830330567Sgordon cast_flags, &ip_count); 831285612Sdelphij } 83254359Sroberto 83354359Sroberto /* 834285612Sdelphij * If a peer is found, this would be a duplicate and we don't 835285612Sdelphij * allow that. This avoids duplicate ephemeral (broadcast/ 836285612Sdelphij * multicast) and preemptible (manycast and pool) client 837285612Sdelphij * associations. 838285612Sdelphij */ 839285612Sdelphij if (peer != NULL) { 840285612Sdelphij DPRINTF(2, ("newpeer(%s) found existing association\n", 841285612Sdelphij (hostname) 842285612Sdelphij ? hostname 843285612Sdelphij : stoa(srcadr))); 844285612Sdelphij return NULL; 845285612Sdelphij } 846285612Sdelphij 847330567SgordonDPRINTF(1, ("newpeer(%s) found no existing and %d other associations\n", 848330567Sgordon (hostname) 849330567Sgordon ? hostname 850330567Sgordon : stoa(srcadr), 851330567Sgordon ip_count)); 852330567Sgordon 853330567Sgordon /* Check ippeerlimit wrt ip_count */ 854330567Sgordon if (ippeerlimit > -1) { 855330567Sgordon if (ip_count + 1 > ippeerlimit) { 856330567Sgordon DPRINTF(2, ("newpeer(%s) denied - ippeerlimit %d\n", 857330567Sgordon (hostname) 858330567Sgordon ? hostname 859330567Sgordon : stoa(srcadr), 860330567Sgordon ippeerlimit)); 861330567Sgordon return NULL; 862330567Sgordon } 863330567Sgordon } else { 864330567Sgordon DPRINTF(1, ("newpeer(%s) - ippeerlimit %d ignored\n", 865330567Sgordon (hostname) 866330567Sgordon ? hostname 867330567Sgordon : stoa(srcadr), 868330567Sgordon ippeerlimit)); 869330567Sgordon } 870330567Sgordon 871285612Sdelphij /* 87282498Sroberto * Allocate a new peer structure. Some dirt here, since some of 87382498Sroberto * the initialization requires knowlege of our system state. 87454359Sroberto */ 87554359Sroberto if (peer_free_count == 0) 87682498Sroberto getmorepeermem(); 877285612Sdelphij UNLINK_HEAD_SLIST(peer, peer_free, p_link); 878289997Sglebius INSIST(peer != NULL); 87954359Sroberto peer_free_count--; 88054359Sroberto peer_associations++; 881285612Sdelphij if (FLAG_PREEMPT & flags) 882182007Sroberto peer_preempt++; 88354359Sroberto 88454359Sroberto /* 885132451Sroberto * Assign an association ID and increment the system variable. 886132451Sroberto */ 887132451Sroberto peer->associd = current_association_ID; 888132451Sroberto if (++current_association_ID == 0) 889132451Sroberto ++current_association_ID; 890132451Sroberto 89182498Sroberto peer->srcadr = *srcadr; 892285612Sdelphij if (hostname != NULL) 893285612Sdelphij peer->hostname = estrdup(hostname); 894285612Sdelphij peer->hmode = hmode; 895285612Sdelphij peer->version = version; 896132451Sroberto peer->flags = flags; 897285612Sdelphij peer->cast_flags = cast_flags; 898285612Sdelphij set_peerdstadr(peer, 899285612Sdelphij select_peerinterface(peer, srcadr, dstadr)); 900182007Sroberto 901182007Sroberto /* 902285612Sdelphij * It is an error to set minpoll less than NTP_MINPOLL or to 903285612Sdelphij * set maxpoll greater than NTP_MAXPOLL. However, minpoll is 904285612Sdelphij * clamped not greater than NTP_MAXPOLL and maxpoll is clamped 905285612Sdelphij * not less than NTP_MINPOLL without complaint. Finally, 906285612Sdelphij * minpoll is clamped not greater than maxpoll. 907285612Sdelphij */ 908285612Sdelphij if (minpoll == 0) 909285612Sdelphij peer->minpoll = NTP_MINDPOLL; 910285612Sdelphij else 911285612Sdelphij peer->minpoll = min(minpoll, NTP_MAXPOLL); 912285612Sdelphij if (maxpoll == 0) 913285612Sdelphij peer->maxpoll = NTP_MAXDPOLL; 914285612Sdelphij else 915285612Sdelphij peer->maxpoll = max(maxpoll, NTP_MINPOLL); 916285612Sdelphij if (peer->minpoll > peer->maxpoll) 917285612Sdelphij peer->minpoll = peer->maxpoll; 918285612Sdelphij 919285612Sdelphij if (peer->dstadr != NULL) 920285612Sdelphij DPRINTF(3, ("newpeer(%s): using fd %d and our addr %s\n", 921285612Sdelphij stoa(srcadr), peer->dstadr->fd, 922285612Sdelphij stoa(&peer->dstadr->sin))); 923285612Sdelphij else 924285612Sdelphij DPRINTF(3, ("newpeer(%s): local interface currently not bound\n", 925285612Sdelphij stoa(srcadr))); 926285612Sdelphij 927285612Sdelphij /* 928182007Sroberto * Broadcast needs the socket enabled for broadcast 929182007Sroberto */ 930285612Sdelphij if ((MDF_BCAST & cast_flags) && peer->dstadr != NULL) 931182007Sroberto enable_broadcast(peer->dstadr, srcadr); 932285612Sdelphij 933182007Sroberto /* 934182007Sroberto * Multicast needs the socket interface enabled for multicast 935182007Sroberto */ 936285612Sdelphij if ((MDF_MCAST & cast_flags) && peer->dstadr != NULL) 937182007Sroberto enable_multicast_if(peer->dstadr, srcadr); 938285612Sdelphij 939285612Sdelphij#ifdef AUTOKEY 940132451Sroberto if (key > NTP_MAXKEY) 941132451Sroberto peer->flags |= FLAG_SKEY; 942285612Sdelphij#endif /* AUTOKEY */ 943285612Sdelphij peer->ttl = ttl; 94454359Sroberto peer->keyid = key; 945285612Sdelphij if (ident != NULL) 946285612Sdelphij peer->ident = estrdup(ident); 94754359Sroberto peer->precision = sys_precision; 948182007Sroberto peer->hpoll = peer->minpoll; 949132451Sroberto if (cast_flags & MDF_ACAST) 950132451Sroberto peer_clear(peer, "ACST"); 951285612Sdelphij else if (cast_flags & MDF_POOL) 952285612Sdelphij peer_clear(peer, "POOL"); 953132451Sroberto else if (cast_flags & MDF_MCAST) 954132451Sroberto peer_clear(peer, "MCST"); 955132451Sroberto else if (cast_flags & MDF_BCAST) 956132451Sroberto peer_clear(peer, "BCST"); 957132451Sroberto else 958132451Sroberto peer_clear(peer, "INIT"); 95982498Sroberto if (mode_ntpdate) 96082498Sroberto peer_ntpdate++; 96154359Sroberto 96254359Sroberto /* 96354359Sroberto * Note time on statistics timers. 96454359Sroberto */ 96554359Sroberto peer->timereset = current_time; 96654359Sroberto peer->timereachable = current_time; 96754359Sroberto peer->timereceived = current_time; 968182007Sroberto 969285612Sdelphij if (ISREFCLOCKADR(&peer->srcadr)) { 97054359Sroberto#ifdef REFCLOCK 97154359Sroberto /* 97254359Sroberto * We let the reference clock support do clock 97354359Sroberto * dependent initialization. This includes setting 97454359Sroberto * the peer timer, since the clock may have requirements 97554359Sroberto * for this. 97654359Sroberto */ 977285612Sdelphij if (maxpoll == 0) 978285612Sdelphij peer->maxpoll = peer->minpoll; 97954359Sroberto if (!refclock_newpeer(peer)) { 98054359Sroberto /* 98154359Sroberto * Dump it, something screwed up 98254359Sroberto */ 983182007Sroberto set_peerdstadr(peer, NULL); 984285612Sdelphij free_peer(peer, 0); 985285612Sdelphij return NULL; 98654359Sroberto } 987285612Sdelphij#else /* REFCLOCK */ 988285612Sdelphij msyslog(LOG_ERR, "refclock %s isn't supported. ntpd was compiled without refclock support.", 989285612Sdelphij stoa(&peer->srcadr)); 990285612Sdelphij set_peerdstadr(peer, NULL); 991285612Sdelphij free_peer(peer, 0); 992285612Sdelphij return NULL; 993285612Sdelphij#endif /* REFCLOCK */ 99454359Sroberto } 99554359Sroberto 99654359Sroberto /* 99782498Sroberto * Put the new peer in the hash tables. 99854359Sroberto */ 999285612Sdelphij hash = NTP_HASH_ADDR(&peer->srcadr); 1000285612Sdelphij LINK_SLIST(peer_hash[hash], peer, adr_link); 1001285612Sdelphij peer_hash_count[hash]++; 1002285612Sdelphij hash = peer->associd & NTP_HASH_MASK; 1003285612Sdelphij LINK_SLIST(assoc_hash[hash], peer, aid_link); 1004285612Sdelphij assoc_hash_count[hash]++; 1005285612Sdelphij LINK_SLIST(peer_list, peer, p_link); 1006182007Sroberto 1007285612Sdelphij restrict_source(&peer->srcadr, 0, 0); 1008285612Sdelphij mprintf_event(PEVNT_MOBIL, peer, "assoc %d", peer->associd); 1009285612Sdelphij DPRINTF(1, ("newpeer: %s->%s mode %u vers %u poll %u %u flags 0x%x 0x%x ttl %u key %08x\n", 1010285612Sdelphij latoa(peer->dstadr), stoa(&peer->srcadr), peer->hmode, 1011285612Sdelphij peer->version, peer->minpoll, peer->maxpoll, peer->flags, 1012285612Sdelphij peer->cast_flags, peer->ttl, peer->keyid)); 1013285612Sdelphij return peer; 101454359Sroberto} 101554359Sroberto 101654359Sroberto 101754359Sroberto/* 1018285612Sdelphij * peer_clr_stats - clear peer module statistics counters 101954359Sroberto */ 102054359Srobertovoid 102154359Srobertopeer_clr_stats(void) 102254359Sroberto{ 102354359Sroberto findpeer_calls = 0; 102454359Sroberto assocpeer_calls = 0; 102554359Sroberto peer_allocations = 0; 102654359Sroberto peer_demobilizations = 0; 102754359Sroberto peer_timereset = current_time; 102854359Sroberto} 102954359Sroberto 1030285612Sdelphij 103154359Sroberto/* 1032285612Sdelphij * peer_reset - reset statistics counters 103354359Sroberto */ 103454359Srobertovoid 103554359Srobertopeer_reset( 103654359Sroberto struct peer *peer 103754359Sroberto ) 103854359Sroberto{ 1039285612Sdelphij if (peer == NULL) 1040285612Sdelphij return; 1041285612Sdelphij 1042285612Sdelphij peer->timereset = current_time; 104354359Sroberto peer->sent = 0; 104454359Sroberto peer->received = 0; 104554359Sroberto peer->processed = 0; 104654359Sroberto peer->badauth = 0; 104754359Sroberto peer->bogusorg = 0; 104854359Sroberto peer->oldpkt = 0; 104954359Sroberto peer->seldisptoolarge = 0; 1050285612Sdelphij peer->selbroken = 0; 105154359Sroberto} 105254359Sroberto 105354359Sroberto 105454359Sroberto/* 1055285612Sdelphij * peer_all_reset - reset all peer statistics counters 105654359Sroberto */ 105754359Srobertovoid 105854359Srobertopeer_all_reset(void) 105954359Sroberto{ 106054359Sroberto struct peer *peer; 106154359Sroberto 1062285612Sdelphij for (peer = peer_list; peer != NULL; peer = peer->p_link) 106354359Sroberto peer_reset(peer); 106454359Sroberto} 106582498Sroberto 106682498Sroberto 106782498Sroberto/* 1068285612Sdelphij * findmanycastpeer - find and return a manycastclient or pool 1069285612Sdelphij * association matching a received response. 107082498Sroberto */ 107182498Srobertostruct peer * 107282498Srobertofindmanycastpeer( 1073285612Sdelphij struct recvbuf *rbufp /* receive buffer pointer */ 107482498Sroberto ) 107582498Sroberto{ 1076285612Sdelphij struct peer *peer; 107782498Sroberto struct pkt *pkt; 107882498Sroberto l_fp p_org; 107982498Sroberto 108082498Sroberto /* 1081285612Sdelphij * This routine is called upon arrival of a server-mode response 1082285612Sdelphij * to a manycastclient multicast solicitation, or to a pool 1083285612Sdelphij * server unicast solicitation. Search the peer list for a 1084285612Sdelphij * manycastclient association where the last transmit timestamp 1085285612Sdelphij * matches the response packet's originate timestamp. There can 1086285612Sdelphij * be multiple manycastclient associations, or multiple pool 1087285612Sdelphij * solicitation assocations, so this assumes the transmit 1088285612Sdelphij * timestamps are unique for such. 108982498Sroberto */ 109082498Sroberto pkt = &rbufp->recv_pkt; 1091285612Sdelphij for (peer = peer_list; peer != NULL; peer = peer->p_link) 1092285612Sdelphij if (MDF_SOLICIT_MASK & peer->cast_flags) { 1093285612Sdelphij NTOHL_FP(&pkt->org, &p_org); 1094285612Sdelphij if (L_ISEQU(&p_org, &peer->aorg)) 1095285612Sdelphij break; 1096285612Sdelphij } 109782498Sroberto 1098285612Sdelphij return peer; 109982498Sroberto} 1100285612Sdelphij 1101285612Sdelphij/* peer_cleanup - clean peer list prior to shutdown */ 1102285612Sdelphijvoid peer_cleanup(void) 1103285612Sdelphij{ 1104285612Sdelphij struct peer *peer; 1105285612Sdelphij associd_t assoc; 1106285612Sdelphij 1107285612Sdelphij for (assoc = initial_association_ID; assoc != current_association_ID; assoc++) { 1108285612Sdelphij if (assoc != 0U) { 1109285612Sdelphij peer = findpeerbyassoc(assoc); 1110285612Sdelphij if (peer != NULL) 1111285612Sdelphij unpeer(peer); 1112285612Sdelphij } 1113285612Sdelphij } 1114285612Sdelphij peer = findpeerbyassoc(current_association_ID); 1115285612Sdelphij if (peer != NULL) 1116285612Sdelphij unpeer(peer); 1117285612Sdelphij} 1118