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, 120285612Sdelphij u_char); 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 164285612Sdelphij peers = emalloc_zero(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, 206285612Sdelphij u_char cast_flags 207285612Sdelphij ) 208285612Sdelphij{ 209285612Sdelphij struct peer *peer; 210285612Sdelphij 211285612Sdelphij DPRINTF(2, ("findexistingpeer_addr(%s, %s, %d, 0x%x)\n", 212285612Sdelphij sptoa(addr), 213285612Sdelphij (start_peer) 214285612Sdelphij ? sptoa(&start_peer->srcadr) 215285612Sdelphij : "NULL", 216285612Sdelphij mode, (u_int)cast_flags)); 217285612Sdelphij 21854359Sroberto /* 21954359Sroberto * start_peer is included so we can locate instances of the 22054359Sroberto * same peer through different interfaces in the hash table. 221285612Sdelphij * Without MDF_BCLNT, a match requires the same mode and remote 222285612Sdelphij * address. MDF_BCLNT associations start out as MODE_CLIENT 223285612Sdelphij * if broadcastdelay is not specified, and switch to 224285612Sdelphij * MODE_BCLIENT after estimating the one-way delay. Duplicate 225285612Sdelphij * associations are expanded in definition to match any other 226285612Sdelphij * MDF_BCLNT with the same srcadr (remote, unicast address). 22754359Sroberto */ 228285612Sdelphij if (NULL == start_peer) 229182007Sroberto peer = peer_hash[NTP_HASH_ADDR(addr)]; 23054359Sroberto else 231285612Sdelphij peer = start_peer->adr_link; 23254359Sroberto 233285612Sdelphij while (peer != NULL) { 234285612Sdelphij DPRINTF(3, ("%s %s %d %d 0x%x 0x%x ", sptoa(addr), 235285612Sdelphij sptoa(&peer->srcadr), mode, peer->hmode, 236285612Sdelphij (u_int)cast_flags, (u_int)peer->cast_flags)); 237285612Sdelphij if ((-1 == mode || peer->hmode == mode || 238285612Sdelphij ((MDF_BCLNT & peer->cast_flags) && 239285612Sdelphij (MDF_BCLNT & cast_flags))) && 240285612Sdelphij ADDR_PORT_EQ(addr, &peer->srcadr)) { 241285612Sdelphij DPRINTF(3, ("found.\n")); 242285612Sdelphij break; 24354359Sroberto } 244285612Sdelphij DPRINTF(3, ("\n")); 245285612Sdelphij peer = peer->adr_link; 24654359Sroberto } 247285612Sdelphij 248285612Sdelphij return peer; 24954359Sroberto} 25054359Sroberto 25154359Sroberto 25254359Sroberto/* 253285612Sdelphij * findexistingpeer - search by address and return a pointer to a peer. 25454359Sroberto */ 25554359Srobertostruct peer * 256285612Sdelphijfindexistingpeer( 257285612Sdelphij sockaddr_u * addr, 258285612Sdelphij const char * hostname, 259285612Sdelphij struct peer * start_peer, 260285612Sdelphij int mode, 261285612Sdelphij u_char cast_flags 262285612Sdelphij ) 263285612Sdelphij{ 264285612Sdelphij if (hostname != NULL) 265285612Sdelphij return findexistingpeer_name(hostname, AF(addr), 266285612Sdelphij start_peer, mode); 267285612Sdelphij else 268285612Sdelphij return findexistingpeer_addr(addr, start_peer, mode, 269285612Sdelphij cast_flags); 270285612Sdelphij} 271285612Sdelphij 272285612Sdelphij 273285612Sdelphij/* 274285612Sdelphij * findpeer - find and return a peer match for a received datagram in 275285612Sdelphij * the peer_hash table. 276310419Sdelphij * 277310419Sdelphij * [Bug 3072] To faciliate a faster reorganisation after routing changes 278310419Sdelphij * the original code re-assigned the peer address to be the destination 279310419Sdelphij * of the received packet and initiated another round on a mismatch. 280310419Sdelphij * Unfortunately this leaves us wide open for a DoS attack where the 281310419Sdelphij * attacker directs a packet with forged destination address to us -- 282310419Sdelphij * this results in a wrong interface assignment, actually creating a DoS 283310419Sdelphij * situation. 284310419Sdelphij * 285310419Sdelphij * This condition would persist until the next update of the interface 286310419Sdelphij * list, but a continued attack would put us out of business again soon 287310419Sdelphij * enough. Authentication alone does not help here, since it does not 288310419Sdelphij * protect the UDP layer and leaves us open for a replay attack. 289310419Sdelphij * 290310419Sdelphij * So we do not update the adresses and wait until the next interface 291310419Sdelphij * list update does the right thing for us. 292285612Sdelphij */ 293285612Sdelphijstruct peer * 29454359Srobertofindpeer( 295285612Sdelphij struct recvbuf *rbufp, 296285612Sdelphij int pkt_mode, 297285612Sdelphij int * action 29854359Sroberto ) 29954359Sroberto{ 300285612Sdelphij struct peer * p; 301285612Sdelphij sockaddr_u * srcadr; 302285612Sdelphij u_int hash; 303285612Sdelphij struct pkt * pkt; 304285612Sdelphij l_fp pkt_org; 30554359Sroberto 30654359Sroberto findpeer_calls++; 307285612Sdelphij srcadr = &rbufp->recv_srcadr; 308182007Sroberto hash = NTP_HASH_ADDR(srcadr); 309285612Sdelphij for (p = peer_hash[hash]; p != NULL; p = p->adr_link) { 31082498Sroberto 311310419Sdelphij /* [Bug 3072] ensure interface of peer matches */ 312310419Sdelphij if (p->dstadr != rbufp->dstadr) 313310419Sdelphij continue; 31454359Sroberto 315310419Sdelphij /* ensure peer source address matches */ 316310419Sdelphij if ( ! ADDR_PORT_EQ(srcadr, &p->srcadr)) 317310419Sdelphij continue; 318310419Sdelphij 319310419Sdelphij /* If the association matching rules determine that this 320310419Sdelphij * is not a valid combination, then look for the next 321310419Sdelphij * valid peer association. 322310419Sdelphij */ 323310419Sdelphij *action = MATCH_ASSOC(p->hmode, pkt_mode); 324285612Sdelphij 325310419Sdelphij /* A response to our manycastclient solicitation might 326310419Sdelphij * be misassociated with an ephemeral peer already spun 327310419Sdelphij * for the server. If the packet's org timestamp 328310419Sdelphij * doesn't match the peer's, check if it matches the 329310419Sdelphij * ACST prototype peer's. If so it is a redundant 330310419Sdelphij * solicitation response, return AM_ERR to discard it. 331310419Sdelphij * [Bug 1762] 332310419Sdelphij */ 333310419Sdelphij if (MODE_SERVER == pkt_mode && AM_PROCPKT == *action) { 334310419Sdelphij pkt = &rbufp->recv_pkt; 335310419Sdelphij NTOHL_FP(&pkt->org, &pkt_org); 336310419Sdelphij if (!L_ISEQU(&p->aorg, &pkt_org) && 337310419Sdelphij findmanycastpeer(rbufp)) 338310419Sdelphij *action = AM_ERR; 339310419Sdelphij } 34054359Sroberto 341310419Sdelphij /* if an error was returned, exit back right here. */ 342310419Sdelphij if (*action == AM_ERR) 343310419Sdelphij return NULL; 344310419Sdelphij 345310419Sdelphij /* if a match is found, we stop our search. */ 346310419Sdelphij if (*action != AM_NOMATCH) 347310419Sdelphij break; 34854359Sroberto } 34954359Sroberto 350310419Sdelphij /* If no matching association is found... */ 351310419Sdelphij if (NULL == p) 35254359Sroberto *action = MATCH_ASSOC(NO_PEER, pkt_mode); 353310419Sdelphij 354285612Sdelphij return p; 35554359Sroberto} 35654359Sroberto 35754359Sroberto/* 358285612Sdelphij * findpeerbyassoc - find and return a peer using his association ID 35954359Sroberto */ 36054359Srobertostruct peer * 36154359Srobertofindpeerbyassoc( 362285612Sdelphij associd_t assoc 36354359Sroberto ) 36454359Sroberto{ 365285612Sdelphij struct peer *p; 366285612Sdelphij u_int hash; 36754359Sroberto 36854359Sroberto assocpeer_calls++; 369182007Sroberto hash = assoc & NTP_HASH_MASK; 370285612Sdelphij for (p = assoc_hash[hash]; p != NULL; p = p->aid_link) 371285612Sdelphij if (assoc == p->associd) 372285612Sdelphij break; 373285612Sdelphij return p; 37454359Sroberto} 37554359Sroberto 37654359Sroberto 37754359Sroberto/* 37882498Sroberto * clear_all - flush all time values for all associations 37954359Sroberto */ 38054359Srobertovoid 38182498Srobertoclear_all(void) 38254359Sroberto{ 383285612Sdelphij struct peer *p; 38454359Sroberto 38582498Sroberto /* 38682498Sroberto * This routine is called when the clock is stepped, and so all 38782498Sroberto * previously saved time values are untrusted. 38882498Sroberto */ 389285612Sdelphij for (p = peer_list; p != NULL; p = p->p_link) 390285612Sdelphij if (!(MDF_TXONLY_MASK & p->cast_flags)) 391285612Sdelphij peer_clear(p, "STEP"); 392285612Sdelphij 393285612Sdelphij DPRINTF(1, ("clear_all: at %lu\n", current_time)); 39454359Sroberto} 39582498Sroberto 39682498Sroberto 39754359Sroberto/* 398285612Sdelphij * score_all() - determine if an association can be demobilized 39954359Sroberto */ 400285612Sdelphijint 401285612Sdelphijscore_all( 402285612Sdelphij struct peer *peer /* peer structure pointer */ 40354359Sroberto ) 40454359Sroberto{ 405285612Sdelphij struct peer *speer; 406285612Sdelphij int temp, tamp; 407285612Sdelphij int x; 40854359Sroberto 409285612Sdelphij /* 410285612Sdelphij * This routine finds the minimum score for all preemptible 411285612Sdelphij * associations and returns > 0 if the association can be 412285612Sdelphij * demobilized. 413285612Sdelphij */ 414285612Sdelphij tamp = score(peer); 415285612Sdelphij temp = 100; 416285612Sdelphij for (speer = peer_list; speer != NULL; speer = speer->p_link) 417285612Sdelphij if (speer->flags & FLAG_PREEMPT) { 418285612Sdelphij x = score(speer); 419285612Sdelphij if (x < temp) 420285612Sdelphij temp = x; 421285612Sdelphij } 422285612Sdelphij DPRINTF(1, ("score_all: at %lu score %d min %d\n", 423285612Sdelphij current_time, tamp, temp)); 424182007Sroberto 425285612Sdelphij if (tamp != temp) 426285612Sdelphij temp = 0; 427182007Sroberto 428285612Sdelphij return temp; 429285612Sdelphij} 430285612Sdelphij 431285612Sdelphij 432285612Sdelphij/* 433285612Sdelphij * score() - calculate preemption score 434285612Sdelphij */ 435285612Sdelphijstatic int 436285612Sdelphijscore( 437285612Sdelphij struct peer *peer /* peer structure pointer */ 438285612Sdelphij ) 439285612Sdelphij{ 440285612Sdelphij int temp; 441285612Sdelphij 44254359Sroberto /* 443285612Sdelphij * This routine calculates the premption score from the peer 444285612Sdelphij * error bits and status. Increasing values are more cherished. 44554359Sroberto */ 446285612Sdelphij temp = 0; 447285612Sdelphij if (!(peer->flash & TEST10)) 448285612Sdelphij temp++; /* 1 good synch and stratum */ 449285612Sdelphij if (!(peer->flash & TEST13)) 450285612Sdelphij temp++; /* 2 reachable */ 451285612Sdelphij if (!(peer->flash & TEST12)) 452285612Sdelphij temp++; /* 3 no loop */ 453285612Sdelphij if (!(peer->flash & TEST11)) 454285612Sdelphij temp++; /* 4 good distance */ 455285612Sdelphij if (peer->status >= CTL_PST_SEL_SELCAND) 456285612Sdelphij temp++; /* 5 in the hunt */ 457285612Sdelphij if (peer->status != CTL_PST_SEL_EXCESS) 458285612Sdelphij temp++; /* 6 not spare tire */ 459285612Sdelphij return (temp); /* selection status */ 460285612Sdelphij} 46154359Sroberto 462285612Sdelphij 463285612Sdelphij/* 464285612Sdelphij * free_peer - internal routine to free memory referred to by a struct 465285612Sdelphij * peer and return it to the peer free list. If unlink is 466285612Sdelphij * nonzero, unlink from the various lists. 467285612Sdelphij */ 468285612Sdelphijstatic void 469285612Sdelphijfree_peer( 470285612Sdelphij struct peer * p, 471285612Sdelphij int unlink_peer 472285612Sdelphij ) 473285612Sdelphij{ 474285612Sdelphij struct peer * unlinked; 475285612Sdelphij int hash; 476285612Sdelphij 477285612Sdelphij if (unlink_peer) { 478285612Sdelphij hash = NTP_HASH_ADDR(&p->srcadr); 479285612Sdelphij peer_hash_count[hash]--; 480285612Sdelphij 481285612Sdelphij UNLINK_SLIST(unlinked, peer_hash[hash], p, adr_link, 482285612Sdelphij struct peer); 483285612Sdelphij if (NULL == unlinked) { 48454359Sroberto peer_hash_count[hash]++; 485285612Sdelphij msyslog(LOG_ERR, "peer %s not in address table!", 486285612Sdelphij stoa(&p->srcadr)); 48754359Sroberto } 48854359Sroberto 489285612Sdelphij /* 490285612Sdelphij * Remove him from the association hash as well. 491285612Sdelphij */ 492285612Sdelphij hash = p->associd & NTP_HASH_MASK; 493285612Sdelphij assoc_hash_count[hash]--; 49454359Sroberto 495285612Sdelphij UNLINK_SLIST(unlinked, assoc_hash[hash], p, aid_link, 496285612Sdelphij struct peer); 497285612Sdelphij if (NULL == unlinked) { 49854359Sroberto assoc_hash_count[hash]++; 49954359Sroberto msyslog(LOG_ERR, 500285612Sdelphij "peer %s not in association ID table!", 501285612Sdelphij stoa(&p->srcadr)); 50254359Sroberto } 503285612Sdelphij 504285612Sdelphij /* Remove him from the overall list. */ 505285612Sdelphij UNLINK_SLIST(unlinked, peer_list, p, p_link, 506285612Sdelphij struct peer); 507285612Sdelphij if (NULL == unlinked) 508285612Sdelphij msyslog(LOG_ERR, "%s not in peer list!", 509285612Sdelphij stoa(&p->srcadr)); 51054359Sroberto } 511285612Sdelphij 512285612Sdelphij if (p->hostname != NULL) 513285612Sdelphij free(p->hostname); 514285612Sdelphij 515285612Sdelphij if (p->ident != NULL) 516285612Sdelphij free(p->ident); 517285612Sdelphij 518285612Sdelphij if (p->addrs != NULL) 519285612Sdelphij free(p->addrs); /* from copy_addrinfo_list() */ 520285612Sdelphij 521285612Sdelphij /* Add his corporeal form to peer free list */ 522285612Sdelphij ZERO(*p); 523285612Sdelphij LINK_SLIST(peer_free, p, p_link); 52454359Sroberto peer_free_count++; 52554359Sroberto} 52654359Sroberto 52754359Sroberto 52854359Sroberto/* 529285612Sdelphij * unpeer - remove peer structure from hash table and free structure 530285612Sdelphij */ 531285612Sdelphijvoid 532285612Sdelphijunpeer( 533285612Sdelphij struct peer *peer 534285612Sdelphij ) 535285612Sdelphij{ 536285612Sdelphij mprintf_event(PEVNT_DEMOBIL, peer, "assoc %u", peer->associd); 537285612Sdelphij restrict_source(&peer->srcadr, 1, 0); 538285612Sdelphij set_peerdstadr(peer, NULL); 539285612Sdelphij peer_demobilizations++; 540285612Sdelphij peer_associations--; 541285612Sdelphij if (FLAG_PREEMPT & peer->flags) 542285612Sdelphij peer_preempt--; 543285612Sdelphij#ifdef REFCLOCK 544285612Sdelphij /* 545285612Sdelphij * If this peer is actually a clock, shut it down first 546285612Sdelphij */ 547285612Sdelphij if (FLAG_REFCLOCK & peer->flags) 548285612Sdelphij refclock_unpeer(peer); 549285612Sdelphij#endif 550285612Sdelphij 551285612Sdelphij free_peer(peer, TRUE); 552285612Sdelphij} 553285612Sdelphij 554285612Sdelphij 555285612Sdelphij/* 55682498Sroberto * peer_config - configure a new association 55754359Sroberto */ 55854359Srobertostruct peer * 55954359Srobertopeer_config( 560285612Sdelphij sockaddr_u * srcadr, 561285612Sdelphij const char * hostname, 562285612Sdelphij endpt * dstadr, 563285612Sdelphij u_char hmode, 564285612Sdelphij u_char version, 565285612Sdelphij u_char minpoll, 566285612Sdelphij u_char maxpoll, 567285612Sdelphij u_int flags, 568285612Sdelphij u_int32 ttl, 569285612Sdelphij keyid_t key, 570285612Sdelphij const char * ident /* autokey group */ 57154359Sroberto ) 57254359Sroberto{ 573132451Sroberto u_char cast_flags; 57454359Sroberto 57554359Sroberto /* 57682498Sroberto * We do a dirty little jig to figure the cast flags. This is 57782498Sroberto * probably not the best place to do this, at least until the 57882498Sroberto * configure code is rebuilt. Note only one flag can be set. 57954359Sroberto */ 58082498Sroberto switch (hmode) { 58182498Sroberto case MODE_BROADCAST: 582285612Sdelphij if (IS_MCAST(srcadr)) 583285612Sdelphij cast_flags = MDF_MCAST; 584285612Sdelphij else 585285612Sdelphij cast_flags = MDF_BCAST; 586285612Sdelphij break; 58782498Sroberto 58882498Sroberto case MODE_CLIENT: 589285612Sdelphij if (hostname != NULL && SOCK_UNSPEC(srcadr)) 590285612Sdelphij cast_flags = MDF_POOL; 591285612Sdelphij else if (IS_MCAST(srcadr)) 592285612Sdelphij cast_flags = MDF_ACAST; 593285612Sdelphij else 594285612Sdelphij cast_flags = MDF_UCAST; 595285612Sdelphij break; 59682498Sroberto 59782498Sroberto default: 59882498Sroberto cast_flags = MDF_UCAST; 59982498Sroberto } 60082498Sroberto 60182498Sroberto /* 602285612Sdelphij * Mobilize the association and initialize its variables. If 603285612Sdelphij * emulating ntpdate, force iburst. For pool and manycastclient 604285612Sdelphij * strip FLAG_PREEMPT as the prototype associations are not 605285612Sdelphij * themselves preemptible, though the resulting associations 606285612Sdelphij * are. 60782498Sroberto */ 608285612Sdelphij flags |= FLAG_CONFIG; 609132451Sroberto if (mode_ntpdate) 610132451Sroberto flags |= FLAG_IBURST; 611285612Sdelphij if ((MDF_ACAST | MDF_POOL) & cast_flags) 612285612Sdelphij flags &= ~FLAG_PREEMPT; 613285612Sdelphij return newpeer(srcadr, hostname, dstadr, hmode, version, 614285612Sdelphij minpoll, maxpoll, flags, cast_flags, ttl, key, ident); 61554359Sroberto} 61654359Sroberto 617182007Sroberto/* 618285612Sdelphij * setup peer dstadr field keeping it in sync with the interface 619285612Sdelphij * structures 620182007Sroberto */ 621182007Srobertovoid 622285612Sdelphijset_peerdstadr( 623285612Sdelphij struct peer * p, 624285612Sdelphij endpt * dstadr 625285612Sdelphij ) 626182007Sroberto{ 627285612Sdelphij struct peer * unlinked; 62854359Sroberto 629310419Sdelphij DEBUG_INSIST(p != NULL); 630310419Sdelphij 631310419Sdelphij if (p == NULL) 632310419Sdelphij return; 633310419Sdelphij 634310419Sdelphij /* check for impossible or identical assignment */ 635285612Sdelphij if (p->dstadr == dstadr) 636285612Sdelphij return; 637182007Sroberto 638285612Sdelphij /* 639285612Sdelphij * Don't accept updates to a separate multicast receive-only 640285612Sdelphij * endpt while a BCLNT peer is running its unicast protocol. 641285612Sdelphij */ 642285612Sdelphij if (dstadr != NULL && (FLAG_BC_VOL & p->flags) && 643285612Sdelphij (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) { 644285612Sdelphij return; 645182007Sroberto } 646310419Sdelphij 647310419Sdelphij /* unlink from list if we have an address prior to assignment */ 648285612Sdelphij if (p->dstadr != NULL) { 649285612Sdelphij p->dstadr->peercnt--; 650285612Sdelphij UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink, 651285612Sdelphij struct peer); 652285612Sdelphij msyslog(LOG_INFO, "%s local addr %s -> %s", 653285612Sdelphij stoa(&p->srcadr), latoa(p->dstadr), 654285612Sdelphij latoa(dstadr)); 655285612Sdelphij } 656310419Sdelphij 657285612Sdelphij p->dstadr = dstadr; 658310419Sdelphij 659310419Sdelphij /* link to list if we have an address after assignment */ 660310419Sdelphij if (p->dstadr != NULL) { 661285612Sdelphij LINK_SLIST(dstadr->peers, p, ilink); 662285612Sdelphij dstadr->peercnt++; 663285612Sdelphij } 664182007Sroberto} 665182007Sroberto 66654359Sroberto/* 667182007Sroberto * attempt to re-rebind interface if necessary 668182007Sroberto */ 669182007Srobertostatic void 670285612Sdelphijpeer_refresh_interface( 671285612Sdelphij struct peer *p 672285612Sdelphij ) 673182007Sroberto{ 674285612Sdelphij endpt * niface; 675285612Sdelphij endpt * piface; 676182007Sroberto 677285612Sdelphij niface = select_peerinterface(p, &p->srcadr, NULL); 678182007Sroberto 679285612Sdelphij DPRINTF(4, ( 680285612Sdelphij "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %u key %08x: new interface: ", 681285612Sdelphij p->dstadr == NULL ? "<null>" : 682285612Sdelphij stoa(&p->dstadr->sin), stoa(&p->srcadr), p->hmode, 683285612Sdelphij p->version, p->minpoll, p->maxpoll, p->flags, p->cast_flags, 684285612Sdelphij p->ttl, p->keyid)); 685285612Sdelphij if (niface != NULL) { 686285612Sdelphij DPRINTF(4, ( 687285612Sdelphij "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s", 688285612Sdelphij niface->fd, niface->bfd, niface->name, 689285612Sdelphij niface->flags, niface->ifindex, 690285612Sdelphij stoa(&niface->sin))); 691285612Sdelphij if (niface->flags & INT_BROADCAST) 692285612Sdelphij DPRINTF(4, (", bcast=%s", 693285612Sdelphij stoa(&niface->bcast))); 694285612Sdelphij DPRINTF(4, (", mask=%s\n", stoa(&niface->mask))); 695285612Sdelphij } else { 696285612Sdelphij DPRINTF(4, ("<NONE>\n")); 697182007Sroberto } 698182007Sroberto 699285612Sdelphij piface = p->dstadr; 700285612Sdelphij set_peerdstadr(p, niface); 701285612Sdelphij if (p->dstadr != NULL) { 702285612Sdelphij /* 703285612Sdelphij * clear crypto if we change the local address 704285612Sdelphij */ 705285612Sdelphij if (p->dstadr != piface && !(MDF_ACAST & p->cast_flags) 706285612Sdelphij && MODE_BROADCAST != p->pmode) 707285612Sdelphij peer_clear(p, "XFAC"); 708182007Sroberto 709182007Sroberto /* 710182007Sroberto * Broadcast needs the socket enabled for broadcast 711182007Sroberto */ 712285612Sdelphij if (MDF_BCAST & p->cast_flags) 713285612Sdelphij enable_broadcast(p->dstadr, &p->srcadr); 714182007Sroberto 715182007Sroberto /* 716285612Sdelphij * Multicast needs the socket interface enabled for 717285612Sdelphij * multicast 718182007Sroberto */ 719285612Sdelphij if (MDF_MCAST & p->cast_flags) 720285612Sdelphij enable_multicast_if(p->dstadr, &p->srcadr); 721182007Sroberto } 722182007Sroberto} 723182007Sroberto 724285612Sdelphij 725182007Sroberto/* 726285612Sdelphij * refresh_all_peerinterfaces - see that all interface bindings are up 727285612Sdelphij * to date 728182007Sroberto */ 729182007Srobertovoid 730182007Srobertorefresh_all_peerinterfaces(void) 731182007Sroberto{ 732285612Sdelphij struct peer *p; 733182007Sroberto 734182007Sroberto /* 735182007Sroberto * this is called when the interface list has changed 736182007Sroberto * give all peers a chance to find a better interface 737289999Sglebius * but only if either they don't have an address already 738289999Sglebius * or if the one they have hasn't worked for a while. 739182007Sroberto */ 740289999Sglebius for (p = peer_list; p != NULL; p = p->p_link) { 741289999Sglebius if (!(p->dstadr && (p->reach & 0x3))) // Bug 2849 XOR 2043 742289999Sglebius peer_refresh_interface(p); 743289999Sglebius } 744182007Sroberto} 745182007Sroberto 746285612Sdelphij 747182007Sroberto/* 748285612Sdelphij * newpeer - initialize a new peer association 749182007Sroberto */ 750285612Sdelphijstruct peer * 751285612Sdelphijnewpeer( 752285612Sdelphij sockaddr_u * srcadr, 753285612Sdelphij const char * hostname, 754285612Sdelphij endpt * dstadr, 755285612Sdelphij u_char hmode, 756285612Sdelphij u_char version, 757285612Sdelphij u_char minpoll, 758285612Sdelphij u_char maxpoll, 759285612Sdelphij u_int flags, 760285612Sdelphij u_char cast_flags, 761285612Sdelphij u_int32 ttl, 762285612Sdelphij keyid_t key, 763285612Sdelphij const char * ident 764285612Sdelphij ) 765182007Sroberto{ 766285612Sdelphij struct peer * peer; 767285612Sdelphij u_int hash; 768285612Sdelphij 769289999Sglebius DEBUG_REQUIRE(srcadr); 770289999Sglebius 771285612Sdelphij#ifdef AUTOKEY 772182007Sroberto /* 773285612Sdelphij * If Autokey is requested but not configured, complain loudly. 774182007Sroberto */ 775285612Sdelphij if (!crypto_flags) { 776285612Sdelphij if (key > NTP_MAXKEY) { 777285612Sdelphij return (NULL); 778182007Sroberto 779285612Sdelphij } else if (flags & FLAG_SKEY) { 780285612Sdelphij msyslog(LOG_ERR, "Autokey not configured"); 781285612Sdelphij return (NULL); 782285612Sdelphij } 783285612Sdelphij } 784285612Sdelphij#endif /* AUTOKEY */ 785285612Sdelphij 786182007Sroberto /* 787285612Sdelphij * For now only pool associations have a hostname. 788182007Sroberto */ 789289999Sglebius INSIST(NULL == hostname || (MDF_POOL & cast_flags)); 790182007Sroberto 791285612Sdelphij /* 792285612Sdelphij * First search from the beginning for an association with given 793285612Sdelphij * remote address and mode. If an interface is given, search 794285612Sdelphij * from there to find the association which matches that 795285612Sdelphij * destination. If the given interface is "any", track down the 796285612Sdelphij * actual interface, because that's what gets put into the peer 797285612Sdelphij * structure. 798285612Sdelphij */ 799285612Sdelphij if (dstadr != NULL) { 800285612Sdelphij peer = findexistingpeer(srcadr, hostname, NULL, hmode, 801285612Sdelphij cast_flags); 802285612Sdelphij while (peer != NULL) { 803285612Sdelphij if (peer->dstadr == dstadr || 804285612Sdelphij ((MDF_BCLNT & cast_flags) && 805285612Sdelphij (MDF_BCLNT & peer->cast_flags))) 806285612Sdelphij break; 807182007Sroberto 808285612Sdelphij if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) && 809285612Sdelphij peer->dstadr == findinterface(srcadr)) 810285612Sdelphij break; 811182007Sroberto 812285612Sdelphij peer = findexistingpeer(srcadr, hostname, peer, 813285612Sdelphij hmode, cast_flags); 814285612Sdelphij } 815285612Sdelphij } else { 816285612Sdelphij /* no endpt address given */ 817285612Sdelphij peer = findexistingpeer(srcadr, hostname, NULL, hmode, 818285612Sdelphij cast_flags); 819285612Sdelphij } 82054359Sroberto 82154359Sroberto /* 822285612Sdelphij * If a peer is found, this would be a duplicate and we don't 823285612Sdelphij * allow that. This avoids duplicate ephemeral (broadcast/ 824285612Sdelphij * multicast) and preemptible (manycast and pool) client 825285612Sdelphij * associations. 826285612Sdelphij */ 827285612Sdelphij if (peer != NULL) { 828285612Sdelphij DPRINTF(2, ("newpeer(%s) found existing association\n", 829285612Sdelphij (hostname) 830285612Sdelphij ? hostname 831285612Sdelphij : stoa(srcadr))); 832285612Sdelphij return NULL; 833285612Sdelphij } 834285612Sdelphij 835285612Sdelphij /* 83682498Sroberto * Allocate a new peer structure. Some dirt here, since some of 83782498Sroberto * the initialization requires knowlege of our system state. 83854359Sroberto */ 83954359Sroberto if (peer_free_count == 0) 84082498Sroberto getmorepeermem(); 841285612Sdelphij UNLINK_HEAD_SLIST(peer, peer_free, p_link); 842289999Sglebius INSIST(peer != NULL); 84354359Sroberto peer_free_count--; 84454359Sroberto peer_associations++; 845285612Sdelphij if (FLAG_PREEMPT & flags) 846182007Sroberto peer_preempt++; 84754359Sroberto 84854359Sroberto /* 849132451Sroberto * Assign an association ID and increment the system variable. 850132451Sroberto */ 851132451Sroberto peer->associd = current_association_ID; 852132451Sroberto if (++current_association_ID == 0) 853132451Sroberto ++current_association_ID; 854132451Sroberto 85582498Sroberto peer->srcadr = *srcadr; 856285612Sdelphij if (hostname != NULL) 857285612Sdelphij peer->hostname = estrdup(hostname); 858285612Sdelphij peer->hmode = hmode; 859285612Sdelphij peer->version = version; 860132451Sroberto peer->flags = flags; 861285612Sdelphij peer->cast_flags = cast_flags; 862285612Sdelphij set_peerdstadr(peer, 863285612Sdelphij select_peerinterface(peer, srcadr, dstadr)); 864182007Sroberto 865182007Sroberto /* 866285612Sdelphij * It is an error to set minpoll less than NTP_MINPOLL or to 867285612Sdelphij * set maxpoll greater than NTP_MAXPOLL. However, minpoll is 868285612Sdelphij * clamped not greater than NTP_MAXPOLL and maxpoll is clamped 869285612Sdelphij * not less than NTP_MINPOLL without complaint. Finally, 870285612Sdelphij * minpoll is clamped not greater than maxpoll. 871285612Sdelphij */ 872285612Sdelphij if (minpoll == 0) 873285612Sdelphij peer->minpoll = NTP_MINDPOLL; 874285612Sdelphij else 875285612Sdelphij peer->minpoll = min(minpoll, NTP_MAXPOLL); 876285612Sdelphij if (maxpoll == 0) 877285612Sdelphij peer->maxpoll = NTP_MAXDPOLL; 878285612Sdelphij else 879285612Sdelphij peer->maxpoll = max(maxpoll, NTP_MINPOLL); 880285612Sdelphij if (peer->minpoll > peer->maxpoll) 881285612Sdelphij peer->minpoll = peer->maxpoll; 882285612Sdelphij 883285612Sdelphij if (peer->dstadr != NULL) 884285612Sdelphij DPRINTF(3, ("newpeer(%s): using fd %d and our addr %s\n", 885285612Sdelphij stoa(srcadr), peer->dstadr->fd, 886285612Sdelphij stoa(&peer->dstadr->sin))); 887285612Sdelphij else 888285612Sdelphij DPRINTF(3, ("newpeer(%s): local interface currently not bound\n", 889285612Sdelphij stoa(srcadr))); 890285612Sdelphij 891285612Sdelphij /* 892182007Sroberto * Broadcast needs the socket enabled for broadcast 893182007Sroberto */ 894285612Sdelphij if ((MDF_BCAST & cast_flags) && peer->dstadr != NULL) 895182007Sroberto enable_broadcast(peer->dstadr, srcadr); 896285612Sdelphij 897182007Sroberto /* 898182007Sroberto * Multicast needs the socket interface enabled for multicast 899182007Sroberto */ 900285612Sdelphij if ((MDF_MCAST & cast_flags) && peer->dstadr != NULL) 901182007Sroberto enable_multicast_if(peer->dstadr, srcadr); 902285612Sdelphij 903285612Sdelphij#ifdef AUTOKEY 904132451Sroberto if (key > NTP_MAXKEY) 905132451Sroberto peer->flags |= FLAG_SKEY; 906285612Sdelphij#endif /* AUTOKEY */ 907285612Sdelphij peer->ttl = ttl; 90854359Sroberto peer->keyid = key; 909285612Sdelphij if (ident != NULL) 910285612Sdelphij peer->ident = estrdup(ident); 91154359Sroberto peer->precision = sys_precision; 912182007Sroberto peer->hpoll = peer->minpoll; 913132451Sroberto if (cast_flags & MDF_ACAST) 914132451Sroberto peer_clear(peer, "ACST"); 915285612Sdelphij else if (cast_flags & MDF_POOL) 916285612Sdelphij peer_clear(peer, "POOL"); 917132451Sroberto else if (cast_flags & MDF_MCAST) 918132451Sroberto peer_clear(peer, "MCST"); 919132451Sroberto else if (cast_flags & MDF_BCAST) 920132451Sroberto peer_clear(peer, "BCST"); 921132451Sroberto else 922132451Sroberto peer_clear(peer, "INIT"); 92382498Sroberto if (mode_ntpdate) 92482498Sroberto peer_ntpdate++; 92554359Sroberto 92654359Sroberto /* 92754359Sroberto * Note time on statistics timers. 92854359Sroberto */ 92954359Sroberto peer->timereset = current_time; 93054359Sroberto peer->timereachable = current_time; 93154359Sroberto peer->timereceived = current_time; 932182007Sroberto 933285612Sdelphij if (ISREFCLOCKADR(&peer->srcadr)) { 93454359Sroberto#ifdef REFCLOCK 93554359Sroberto /* 93654359Sroberto * We let the reference clock support do clock 93754359Sroberto * dependent initialization. This includes setting 93854359Sroberto * the peer timer, since the clock may have requirements 93954359Sroberto * for this. 94054359Sroberto */ 941285612Sdelphij if (maxpoll == 0) 942285612Sdelphij peer->maxpoll = peer->minpoll; 94354359Sroberto if (!refclock_newpeer(peer)) { 94454359Sroberto /* 94554359Sroberto * Dump it, something screwed up 94654359Sroberto */ 947182007Sroberto set_peerdstadr(peer, NULL); 948285612Sdelphij free_peer(peer, 0); 949285612Sdelphij return NULL; 95054359Sroberto } 951285612Sdelphij#else /* REFCLOCK */ 952285612Sdelphij msyslog(LOG_ERR, "refclock %s isn't supported. ntpd was compiled without refclock support.", 953285612Sdelphij stoa(&peer->srcadr)); 954285612Sdelphij set_peerdstadr(peer, NULL); 955285612Sdelphij free_peer(peer, 0); 956285612Sdelphij return NULL; 957285612Sdelphij#endif /* REFCLOCK */ 95854359Sroberto } 95954359Sroberto 96054359Sroberto /* 96182498Sroberto * Put the new peer in the hash tables. 96254359Sroberto */ 963285612Sdelphij hash = NTP_HASH_ADDR(&peer->srcadr); 964285612Sdelphij LINK_SLIST(peer_hash[hash], peer, adr_link); 965285612Sdelphij peer_hash_count[hash]++; 966285612Sdelphij hash = peer->associd & NTP_HASH_MASK; 967285612Sdelphij LINK_SLIST(assoc_hash[hash], peer, aid_link); 968285612Sdelphij assoc_hash_count[hash]++; 969285612Sdelphij LINK_SLIST(peer_list, peer, p_link); 970182007Sroberto 971285612Sdelphij restrict_source(&peer->srcadr, 0, 0); 972285612Sdelphij mprintf_event(PEVNT_MOBIL, peer, "assoc %d", peer->associd); 973285612Sdelphij DPRINTF(1, ("newpeer: %s->%s mode %u vers %u poll %u %u flags 0x%x 0x%x ttl %u key %08x\n", 974285612Sdelphij latoa(peer->dstadr), stoa(&peer->srcadr), peer->hmode, 975285612Sdelphij peer->version, peer->minpoll, peer->maxpoll, peer->flags, 976285612Sdelphij peer->cast_flags, peer->ttl, peer->keyid)); 977285612Sdelphij return peer; 97854359Sroberto} 97954359Sroberto 98054359Sroberto 98154359Sroberto/* 982285612Sdelphij * peer_clr_stats - clear peer module statistics counters 98354359Sroberto */ 98454359Srobertovoid 98554359Srobertopeer_clr_stats(void) 98654359Sroberto{ 98754359Sroberto findpeer_calls = 0; 98854359Sroberto assocpeer_calls = 0; 98954359Sroberto peer_allocations = 0; 99054359Sroberto peer_demobilizations = 0; 99154359Sroberto peer_timereset = current_time; 99254359Sroberto} 99354359Sroberto 994285612Sdelphij 99554359Sroberto/* 996285612Sdelphij * peer_reset - reset statistics counters 99754359Sroberto */ 99854359Srobertovoid 99954359Srobertopeer_reset( 100054359Sroberto struct peer *peer 100154359Sroberto ) 100254359Sroberto{ 1003285612Sdelphij if (peer == NULL) 1004285612Sdelphij return; 1005285612Sdelphij 1006285612Sdelphij peer->timereset = current_time; 100754359Sroberto peer->sent = 0; 100854359Sroberto peer->received = 0; 100954359Sroberto peer->processed = 0; 101054359Sroberto peer->badauth = 0; 101154359Sroberto peer->bogusorg = 0; 101254359Sroberto peer->oldpkt = 0; 101354359Sroberto peer->seldisptoolarge = 0; 1014285612Sdelphij peer->selbroken = 0; 101554359Sroberto} 101654359Sroberto 101754359Sroberto 101854359Sroberto/* 1019285612Sdelphij * peer_all_reset - reset all peer statistics counters 102054359Sroberto */ 102154359Srobertovoid 102254359Srobertopeer_all_reset(void) 102354359Sroberto{ 102454359Sroberto struct peer *peer; 102554359Sroberto 1026285612Sdelphij for (peer = peer_list; peer != NULL; peer = peer->p_link) 102754359Sroberto peer_reset(peer); 102854359Sroberto} 102982498Sroberto 103082498Sroberto 103182498Sroberto/* 1032285612Sdelphij * findmanycastpeer - find and return a manycastclient or pool 1033285612Sdelphij * association matching a received response. 103482498Sroberto */ 103582498Srobertostruct peer * 103682498Srobertofindmanycastpeer( 1037285612Sdelphij struct recvbuf *rbufp /* receive buffer pointer */ 103882498Sroberto ) 103982498Sroberto{ 1040285612Sdelphij struct peer *peer; 104182498Sroberto struct pkt *pkt; 104282498Sroberto l_fp p_org; 104382498Sroberto 104482498Sroberto /* 1045285612Sdelphij * This routine is called upon arrival of a server-mode response 1046285612Sdelphij * to a manycastclient multicast solicitation, or to a pool 1047285612Sdelphij * server unicast solicitation. Search the peer list for a 1048285612Sdelphij * manycastclient association where the last transmit timestamp 1049285612Sdelphij * matches the response packet's originate timestamp. There can 1050285612Sdelphij * be multiple manycastclient associations, or multiple pool 1051285612Sdelphij * solicitation assocations, so this assumes the transmit 1052285612Sdelphij * timestamps are unique for such. 105382498Sroberto */ 105482498Sroberto pkt = &rbufp->recv_pkt; 1055285612Sdelphij for (peer = peer_list; peer != NULL; peer = peer->p_link) 1056285612Sdelphij if (MDF_SOLICIT_MASK & peer->cast_flags) { 1057285612Sdelphij NTOHL_FP(&pkt->org, &p_org); 1058285612Sdelphij if (L_ISEQU(&p_org, &peer->aorg)) 1059285612Sdelphij break; 1060285612Sdelphij } 106182498Sroberto 1062285612Sdelphij return peer; 106382498Sroberto} 1064285612Sdelphij 1065285612Sdelphij/* peer_cleanup - clean peer list prior to shutdown */ 1066285612Sdelphijvoid peer_cleanup(void) 1067285612Sdelphij{ 1068285612Sdelphij struct peer *peer; 1069285612Sdelphij associd_t assoc; 1070285612Sdelphij 1071285612Sdelphij for (assoc = initial_association_ID; assoc != current_association_ID; assoc++) { 1072285612Sdelphij if (assoc != 0U) { 1073285612Sdelphij peer = findpeerbyassoc(assoc); 1074285612Sdelphij if (peer != NULL) 1075285612Sdelphij unpeer(peer); 1076285612Sdelphij } 1077285612Sdelphij } 1078285612Sdelphij peer = findpeerbyassoc(current_association_ID); 1079285612Sdelphij if (peer != NULL) 1080285612Sdelphij unpeer(peer); 1081285612Sdelphij} 1082