Annotation of embedaddon/ntp/ntpd/ntp_peer.c, revision 1.1
1.1 ! misho 1: /*
! 2: * ntp_peer.c - management of data maintained for peer associations
! 3: */
! 4: #ifdef HAVE_CONFIG_H
! 5: #include <config.h>
! 6: #endif
! 7:
! 8: #include <stdio.h>
! 9: #include <sys/types.h>
! 10:
! 11: #include "ntpd.h"
! 12: #include "ntp_lists.h"
! 13: #include "ntp_stdlib.h"
! 14: #include "ntp_control.h"
! 15: #include <ntp_random.h>
! 16: #ifdef OPENSSL
! 17: #include "openssl/rand.h"
! 18: #endif /* OPENSSL */
! 19:
! 20: #ifdef SYS_WINNT
! 21: int accept_wildcard_if_for_winnt;
! 22: #else
! 23: const int accept_wildcard_if_for_winnt = FALSE;
! 24: #endif
! 25:
! 26: /*
! 27: * Table of valid association combinations
! 28: * ---------------------------------------
! 29: *
! 30: * packet->mode
! 31: * peer->mode | UNSPEC ACTIVE PASSIVE CLIENT SERVER BCAST
! 32: * ---------- | ---------------------------------------------
! 33: * NO_PEER | e 1 0 1 1 1
! 34: * ACTIVE | e 1 1 0 0 0
! 35: * PASSIVE | e 1 e 0 0 0
! 36: * CLIENT | e 0 0 0 1 0
! 37: * SERVER | e 0 0 0 0 0
! 38: * BCAST | e 0 0 0 0 0
! 39: * BCLIENT | e 0 0 0 e 1
! 40: *
! 41: * One point to note here: a packet in BCAST mode can potentially match
! 42: * a peer in CLIENT mode, but we that is a special case and we check for
! 43: * that early in the decision process. This avoids having to keep track
! 44: * of what kind of associations are possible etc... We actually
! 45: * circumvent that problem by requiring that the first b(m)roadcast
! 46: * received after the change back to BCLIENT mode sets the clock.
! 47: */
! 48: #define AM_MODES 7 /* number of rows and columns */
! 49: #define NO_PEER 0 /* action when no peer is found */
! 50:
! 51: int AM[AM_MODES][AM_MODES] = {
! 52: /* { UNSPEC, ACTIVE, PASSIVE, CLIENT, SERVER, BCAST } */
! 53:
! 54: /*NONE*/{ AM_ERR, AM_NEWPASS, AM_NOMATCH, AM_FXMIT, AM_MANYCAST, AM_NEWBCL},
! 55:
! 56: /*A*/ { AM_ERR, AM_PROCPKT, AM_PROCPKT, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
! 57:
! 58: /*P*/ { AM_ERR, AM_PROCPKT, AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
! 59:
! 60: /*C*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT, AM_NOMATCH},
! 61:
! 62: /*S*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
! 63:
! 64: /*BCST*/{ AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH},
! 65:
! 66: /*BCL*/ { AM_ERR, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_NOMATCH, AM_PROCPKT},
! 67: };
! 68:
! 69: #define MATCH_ASSOC(x, y) AM[(x)][(y)]
! 70:
! 71: /*
! 72: * These routines manage the allocation of memory to peer structures
! 73: * and the maintenance of the peer hash table. The three main entry
! 74: * points are findpeer(), which looks for matching peer structures in
! 75: * the peer list, newpeer(), which allocates a new peer structure and
! 76: * adds it to the list, and unpeer(), which demobilizes the association
! 77: * and deallocates the structure.
! 78: */
! 79: /*
! 80: * Peer hash tables
! 81: */
! 82: struct peer *peer_hash[NTP_HASH_SIZE]; /* peer hash table */
! 83: int peer_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
! 84: struct peer *assoc_hash[NTP_HASH_SIZE]; /* association ID hash table */
! 85: int assoc_hash_count[NTP_HASH_SIZE]; /* peers in each bucket */
! 86: static struct peer *peer_free; /* peer structures free list */
! 87: int peer_free_count; /* count of free structures */
! 88:
! 89: /*
! 90: * Association ID. We initialize this value randomly, then assign a new
! 91: * value every time the peer structure is incremented.
! 92: */
! 93: static associd_t current_association_ID; /* association ID */
! 94:
! 95: /*
! 96: * Memory allocation watermarks.
! 97: */
! 98: #define INIT_PEER_ALLOC 15 /* initialize for 15 peers */
! 99: #define INC_PEER_ALLOC 5 /* when run out, add 5 more */
! 100:
! 101: /*
! 102: * Miscellaneous statistic counters which may be queried.
! 103: */
! 104: u_long peer_timereset; /* time stat counters zeroed */
! 105: u_long findpeer_calls; /* calls to findpeer */
! 106: u_long assocpeer_calls; /* calls to findpeerbyassoc */
! 107: u_long peer_allocations; /* allocations from free list */
! 108: u_long peer_demobilizations; /* structs freed to free list */
! 109: int total_peer_structs; /* peer structs */
! 110: int peer_associations; /* mobilized associations */
! 111: int peer_preempt; /* preemptable associations */
! 112: static struct peer init_peer_alloc[INIT_PEER_ALLOC]; /* init alloc */
! 113:
! 114: static void getmorepeermem (void);
! 115: static struct interface *select_peerinterface (struct peer *, sockaddr_u *, struct interface *, u_char);
! 116:
! 117: static int score(struct peer *);
! 118:
! 119: /*
! 120: * init_peer - initialize peer data structures and counters
! 121: *
! 122: * N.B. We use the random number routine in here. It had better be
! 123: * initialized prior to getting here.
! 124: */
! 125: void
! 126: init_peer(void)
! 127: {
! 128: register int i;
! 129:
! 130: /*
! 131: * Clear hash tables and counters.
! 132: */
! 133: memset(peer_hash, 0, sizeof(peer_hash));
! 134: memset(peer_hash_count, 0, sizeof(peer_hash_count));
! 135: memset(assoc_hash, 0, sizeof(assoc_hash));
! 136: memset(assoc_hash_count, 0, sizeof(assoc_hash_count));
! 137:
! 138: /*
! 139: * Clear stat counters
! 140: */
! 141: findpeer_calls = peer_allocations = 0;
! 142: assocpeer_calls = peer_demobilizations = 0;
! 143:
! 144: /*
! 145: * Initialize peer memory.
! 146: */
! 147: peer_free = NULL;
! 148: for (i = 0; i < INIT_PEER_ALLOC; i++)
! 149: LINK_SLIST(peer_free, &init_peer_alloc[i], next);
! 150: total_peer_structs = INIT_PEER_ALLOC;
! 151: peer_free_count = INIT_PEER_ALLOC;
! 152:
! 153: /*
! 154: * Initialize our first association ID
! 155: */
! 156: while ((current_association_ID = ntp_random() & 0xffff) == 0);
! 157: }
! 158:
! 159:
! 160: /*
! 161: * getmorepeermem - add more peer structures to the free list
! 162: */
! 163: static void
! 164: getmorepeermem(void)
! 165: {
! 166: register int i;
! 167: register struct peer *peer;
! 168:
! 169: peer = (struct peer *)emalloc(INC_PEER_ALLOC *
! 170: sizeof(struct peer));
! 171: for (i = 0; i < INC_PEER_ALLOC; i++) {
! 172: LINK_SLIST(peer_free, peer, next);
! 173: peer++;
! 174: }
! 175:
! 176: total_peer_structs += INC_PEER_ALLOC;
! 177: peer_free_count += INC_PEER_ALLOC;
! 178: }
! 179:
! 180:
! 181: /*
! 182: * findexistingpeer - return a pointer to a peer in the hash table
! 183: */
! 184: struct peer *
! 185: findexistingpeer(
! 186: sockaddr_u * addr,
! 187: struct peer * start_peer,
! 188: int mode,
! 189: u_char cast_flags
! 190: )
! 191: {
! 192: register struct peer *peer;
! 193:
! 194: /*
! 195: * start_peer is included so we can locate instances of the
! 196: * same peer through different interfaces in the hash table.
! 197: * Without MDF_BCLNT, a match requires the same mode and remote
! 198: * address. MDF_BCLNT associations start out as MODE_CLIENT
! 199: * if broadcastdelay is not specified, and switch to
! 200: * MODE_BCLIENT after estimating the one-way delay. Duplicate
! 201: * associations are expanded in definition to match any other
! 202: * MDF_BCLNT with the same srcadr (remote, unicast address).
! 203: */
! 204: if (NULL == start_peer)
! 205: peer = peer_hash[NTP_HASH_ADDR(addr)];
! 206: else
! 207: peer = start_peer->next;
! 208:
! 209: while (peer != NULL) {
! 210: if (ADDR_PORT_EQ(addr, &peer->srcadr)
! 211: && (-1 == mode || peer->hmode == mode ||
! 212: ((MDF_BCLNT & peer->cast_flags) &&
! 213: (MDF_BCLNT & cast_flags))))
! 214: break;
! 215: peer = peer->next;
! 216: }
! 217:
! 218: return peer;
! 219: }
! 220:
! 221:
! 222: /*
! 223: * findpeer - find and return a peer match for a received datagram in
! 224: * the peer_hash table.
! 225: */
! 226: struct peer *
! 227: findpeer(
! 228: struct recvbuf *rbufp,
! 229: int pkt_mode,
! 230: int * action
! 231: )
! 232: {
! 233: struct peer * p;
! 234: sockaddr_u * srcadr;
! 235: u_int hash;
! 236: struct pkt * pkt;
! 237: l_fp pkt_org;
! 238:
! 239: findpeer_calls++;
! 240: srcadr = &rbufp->recv_srcadr;
! 241: hash = NTP_HASH_ADDR(srcadr);
! 242: for (p = peer_hash[hash]; p != NULL; p = p->next) {
! 243: if (SOCK_EQ(srcadr, &p->srcadr) &&
! 244: NSRCPORT(srcadr) == NSRCPORT(&p->srcadr)) {
! 245:
! 246: /*
! 247: * if the association matching rules determine
! 248: * that this is not a valid combination, then
! 249: * look for the next valid peer association.
! 250: */
! 251: *action = MATCH_ASSOC(p->hmode, pkt_mode);
! 252:
! 253: /*
! 254: * A response to our manycastclient solicitation
! 255: * might be misassociated with an ephemeral peer
! 256: * already spun for the server. If the packet's
! 257: * org timestamp doesn't match the peer's, check
! 258: * if it matches the ACST prototype peer's. If
! 259: * so it is a redundant solicitation response,
! 260: * return AM_ERR to discard it. [Bug 1762]
! 261: */
! 262: if (MODE_SERVER == pkt_mode &&
! 263: AM_PROCPKT == *action) {
! 264: pkt = &rbufp->recv_pkt;
! 265: NTOHL_FP(&pkt->org, &pkt_org);
! 266: if (!L_ISEQU(&p->aorg, &pkt_org) &&
! 267: findmanycastpeer(rbufp))
! 268: *action = AM_ERR;
! 269: }
! 270:
! 271: /*
! 272: * if an error was returned, exit back right
! 273: * here.
! 274: */
! 275: if (*action == AM_ERR)
! 276: return NULL;
! 277:
! 278: /*
! 279: * if a match is found, we stop our search.
! 280: */
! 281: if (*action != AM_NOMATCH)
! 282: break;
! 283: }
! 284: }
! 285:
! 286: /*
! 287: * If no matching association is found
! 288: */
! 289: if (NULL == p) {
! 290: *action = MATCH_ASSOC(NO_PEER, pkt_mode);
! 291: } else if (p->dstadr != rbufp->dstadr) {
! 292: set_peerdstadr(p, rbufp->dstadr);
! 293: if (p->dstadr == rbufp->dstadr) {
! 294: DPRINTF(1, ("Changed %s local address to match response\n",
! 295: stoa(&p->srcadr)));
! 296: return findpeer(rbufp, pkt_mode, action);
! 297: }
! 298: }
! 299: return p;
! 300: }
! 301:
! 302: /*
! 303: * findpeerbyassocid - find and return a peer using his association ID
! 304: */
! 305: struct peer *
! 306: findpeerbyassoc(
! 307: u_int assoc
! 308: )
! 309: {
! 310: struct peer *p;
! 311: u_int hash;
! 312:
! 313: assocpeer_calls++;
! 314:
! 315: hash = assoc & NTP_HASH_MASK;
! 316: for (p = assoc_hash[hash]; p != NULL; p = p->ass_next) {
! 317: if (assoc == p->associd)
! 318: return p;
! 319: }
! 320: return NULL;
! 321: }
! 322:
! 323:
! 324: /*
! 325: * clear_all - flush all time values for all associations
! 326: */
! 327: void
! 328: clear_all(void)
! 329: {
! 330: struct peer *peer, *next_peer;
! 331: int n;
! 332:
! 333: /*
! 334: * This routine is called when the clock is stepped, and so all
! 335: * previously saved time values are untrusted.
! 336: */
! 337: for (n = 0; n < NTP_HASH_SIZE; n++) {
! 338: for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
! 339: next_peer = peer->next;
! 340: if (!(peer->cast_flags & (MDF_ACAST |
! 341: MDF_MCAST | MDF_BCAST))) {
! 342: peer_clear(peer, "STEP");
! 343: }
! 344: }
! 345: }
! 346: #ifdef DEBUG
! 347: if (debug)
! 348: printf("clear_all: at %lu\n", current_time);
! 349: #endif
! 350: }
! 351:
! 352:
! 353: /*
! 354: * score_all() - determine if an association can be demobilized
! 355: */
! 356: int
! 357: score_all(
! 358: struct peer *peer /* peer structure pointer */
! 359: )
! 360: {
! 361: struct peer *speer, *next_peer;
! 362: int n;
! 363: int temp, tamp;
! 364:
! 365: /*
! 366: * This routine finds the minimum score for all ephemeral
! 367: * assocations and returns > 0 if the association can be
! 368: * demobilized.
! 369: */
! 370: tamp = score(peer);
! 371: temp = 100;
! 372: for (n = 0; n < NTP_HASH_SIZE; n++) {
! 373: for (speer = peer_hash[n]; speer != 0; speer =
! 374: next_peer) {
! 375: int x;
! 376:
! 377: next_peer = speer->next;
! 378: if ((x = score(speer)) < temp && (peer->flags &
! 379: FLAG_PREEMPT))
! 380: temp = x;
! 381: }
! 382: }
! 383: #ifdef DEBUG
! 384: if (debug)
! 385: printf("score_all: at %lu score %d min %d\n",
! 386: current_time, tamp, temp);
! 387: #endif
! 388: if (tamp != temp)
! 389: temp = 0;
! 390: return (temp);
! 391: }
! 392:
! 393:
! 394: /*
! 395: * score() - calculate preemption score
! 396: */
! 397: static int
! 398: score(
! 399: struct peer *peer /* peer structure pointer */
! 400: )
! 401: {
! 402: int temp;
! 403:
! 404: /*
! 405: * This routine calculates the premption score from the peer
! 406: * error bits and status. Increasing values are more cherished.
! 407: */
! 408: temp = 0;
! 409: if (!(peer->flash & TEST10))
! 410: temp++; /* 1 good synch and stratum */
! 411: if (!(peer->flash & TEST13))
! 412: temp++; /* 2 reachable */
! 413: if (!(peer->flash & TEST12))
! 414: temp++; /* 3 no loop */
! 415: if (!(peer->flash & TEST11))
! 416: temp++; /* 4 good distance */
! 417: if (peer->status >= CTL_PST_SEL_SELCAND)
! 418: temp++; /* 5 in the hunt */
! 419: if (peer->status != CTL_PST_SEL_EXCESS)
! 420: temp++; /* 6 not spare tire */
! 421: return (temp); /* selection status */
! 422: }
! 423:
! 424:
! 425: /*
! 426: * unpeer - remove peer structure from hash table and free structure
! 427: */
! 428: void
! 429: unpeer(
! 430: struct peer *peer_to_remove
! 431: )
! 432: {
! 433: register struct peer *unlinked;
! 434: int hash;
! 435: char tbuf[80];
! 436:
! 437: snprintf(tbuf, sizeof(tbuf), "assoc %d",
! 438: peer_to_remove->associd);
! 439: report_event(PEVNT_DEMOBIL, peer_to_remove, tbuf);
! 440: set_peerdstadr(peer_to_remove, NULL);
! 441: hash = NTP_HASH_ADDR(&peer_to_remove->srcadr);
! 442: peer_hash_count[hash]--;
! 443: peer_demobilizations++;
! 444: peer_associations--;
! 445: if (peer_to_remove->flags & FLAG_PREEMPT)
! 446: peer_preempt--;
! 447: #ifdef REFCLOCK
! 448: /*
! 449: * If this peer is actually a clock, shut it down first
! 450: */
! 451: if (peer_to_remove->flags & FLAG_REFCLOCK)
! 452: refclock_unpeer(peer_to_remove);
! 453: #endif
! 454: peer_to_remove->action = 0; /* disable timeout actions */
! 455:
! 456: UNLINK_SLIST(unlinked, peer_hash[hash], peer_to_remove, next,
! 457: struct peer);
! 458:
! 459: if (NULL == unlinked) {
! 460: peer_hash_count[hash]++;
! 461: msyslog(LOG_ERR, "peer struct for %s not in table!",
! 462: stoa(&peer_to_remove->srcadr));
! 463: }
! 464:
! 465: /*
! 466: * Remove him from the association hash as well.
! 467: */
! 468: hash = peer_to_remove->associd & NTP_HASH_MASK;
! 469: assoc_hash_count[hash]--;
! 470:
! 471: UNLINK_SLIST(unlinked, assoc_hash[hash], peer_to_remove,
! 472: ass_next, struct peer);
! 473:
! 474: if (NULL == unlinked) {
! 475: assoc_hash_count[hash]++;
! 476: msyslog(LOG_ERR,
! 477: "peer struct for %s not in association table!",
! 478: stoa(&peer_to_remove->srcadr));
! 479: }
! 480:
! 481: LINK_SLIST(peer_free, peer_to_remove, next);
! 482: peer_free_count++;
! 483: }
! 484:
! 485:
! 486: /*
! 487: * peer_config - configure a new association
! 488: */
! 489: struct peer *
! 490: peer_config(
! 491: sockaddr_u *srcadr,
! 492: struct interface *dstadr,
! 493: int hmode,
! 494: int version,
! 495: int minpoll,
! 496: int maxpoll,
! 497: u_int flags,
! 498: int ttl,
! 499: keyid_t key,
! 500: u_char *keystr
! 501: )
! 502: {
! 503: u_char cast_flags;
! 504:
! 505: /*
! 506: * We do a dirty little jig to figure the cast flags. This is
! 507: * probably not the best place to do this, at least until the
! 508: * configure code is rebuilt. Note only one flag can be set.
! 509: */
! 510: switch (hmode) {
! 511: case MODE_BROADCAST:
! 512: if (IS_MCAST(srcadr))
! 513: cast_flags = MDF_MCAST;
! 514: else
! 515: cast_flags = MDF_BCAST;
! 516: break;
! 517:
! 518: case MODE_CLIENT:
! 519: if (IS_MCAST(srcadr))
! 520: cast_flags = MDF_ACAST;
! 521: else
! 522: cast_flags = MDF_UCAST;
! 523: break;
! 524:
! 525: default:
! 526: cast_flags = MDF_UCAST;
! 527: }
! 528:
! 529: /*
! 530: * Mobilize the association and initialize its variables. If
! 531: * emulating ntpdate, force iburst.
! 532: */
! 533: if (mode_ntpdate)
! 534: flags |= FLAG_IBURST;
! 535: return(newpeer(srcadr, dstadr, hmode, version, minpoll, maxpoll,
! 536: flags | FLAG_CONFIG, cast_flags, ttl, key));
! 537: }
! 538:
! 539: /*
! 540: * setup peer dstadr field keeping it in sync with the interface
! 541: * structures
! 542: */
! 543: void
! 544: set_peerdstadr(
! 545: struct peer * p,
! 546: endpt * dstadr
! 547: )
! 548: {
! 549: struct peer * unlinked;
! 550:
! 551: if (p->dstadr == dstadr)
! 552: return;
! 553:
! 554: /*
! 555: * Don't accept updates to a separate multicast receive-only
! 556: * endpt while a BCLNT peer is running its unicast protocol.
! 557: */
! 558: if (dstadr != NULL && (FLAG_BC_VOL & p->flags) &&
! 559: (INT_MCASTIF & dstadr->flags) && MODE_CLIENT == p->hmode) {
! 560: return;
! 561: }
! 562: if (p->dstadr != NULL) {
! 563: p->dstadr->peercnt--;
! 564: UNLINK_SLIST(unlinked, p->dstadr->peers, p, ilink,
! 565: struct peer);
! 566: msyslog(LOG_INFO, "%s interface %s -> %s",
! 567: stoa(&p->srcadr), stoa(&p->dstadr->sin),
! 568: (dstadr != NULL)
! 569: ? stoa(&dstadr->sin)
! 570: : "(none)");
! 571: }
! 572: p->dstadr = dstadr;
! 573: if (dstadr != NULL) {
! 574: LINK_SLIST(dstadr->peers, p, ilink);
! 575: dstadr->peercnt++;
! 576: }
! 577: }
! 578:
! 579: /*
! 580: * attempt to re-rebind interface if necessary
! 581: */
! 582: static void
! 583: peer_refresh_interface(
! 584: struct peer *peer
! 585: )
! 586: {
! 587: endpt * niface;
! 588: endpt * piface;
! 589:
! 590: niface = select_peerinterface(peer, &peer->srcadr, NULL,
! 591: peer->cast_flags);
! 592:
! 593: DPRINTF(4, (
! 594: "peer_refresh_interface: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x: new interface: ",
! 595: peer->dstadr == NULL ? "<null>" :
! 596: stoa(&peer->dstadr->sin), stoa(&peer->srcadr),
! 597: peer->hmode, peer->version, peer->minpoll,
! 598: peer->maxpoll, peer->flags, peer->cast_flags,
! 599: peer->ttl, peer->keyid));
! 600: if (niface != NULL) {
! 601: DPRINTF(4, (
! 602: "fd=%d, bfd=%d, name=%.16s, flags=0x%x, ifindex=%u, sin=%s",
! 603: niface->fd, niface->bfd, niface->name,
! 604: niface->flags, niface->ifindex,
! 605: stoa(&niface->sin)));
! 606: if (niface->flags & INT_BROADCAST)
! 607: DPRINTF(4, (", bcast=%s",
! 608: stoa(&niface->bcast)));
! 609: DPRINTF(4, (", mask=%s\n", stoa(&niface->mask)));
! 610: } else {
! 611: DPRINTF(4, ("<NONE>\n"));
! 612: }
! 613:
! 614: piface = peer->dstadr;
! 615: set_peerdstadr(peer, niface);
! 616: if (peer->dstadr) {
! 617: /*
! 618: * clear crypto if we change the local address
! 619: */
! 620: if (peer->dstadr != piface && !(peer->cast_flags &
! 621: MDF_ACAST) && peer->pmode != MODE_BROADCAST)
! 622: peer_clear(peer, "XFAC");
! 623:
! 624: /*
! 625: * Broadcast needs the socket enabled for broadcast
! 626: */
! 627: if (peer->cast_flags & MDF_BCAST) {
! 628: enable_broadcast(peer->dstadr, &peer->srcadr);
! 629: }
! 630:
! 631: /*
! 632: * Multicast needs the socket interface enabled for
! 633: * multicast
! 634: */
! 635: if (peer->cast_flags & MDF_MCAST) {
! 636: enable_multicast_if(peer->dstadr,
! 637: &peer->srcadr);
! 638: }
! 639: }
! 640: }
! 641:
! 642: /*
! 643: * refresh_all_peerinterfaces - see that all interface bindings are up
! 644: * to date
! 645: */
! 646: void
! 647: refresh_all_peerinterfaces(void)
! 648: {
! 649: struct peer *peer, *next_peer;
! 650: int n;
! 651:
! 652: /*
! 653: * this is called when the interface list has changed
! 654: * give all peers a chance to find a better interface
! 655: */
! 656: for (n = 0; n < NTP_HASH_SIZE; n++) {
! 657: for (peer = peer_hash[n]; peer != 0; peer = next_peer) {
! 658: next_peer = peer->next;
! 659: peer_refresh_interface(peer);
! 660: }
! 661: }
! 662: }
! 663:
! 664:
! 665: /*
! 666: * find an interface suitable for the src address
! 667: */
! 668: static endpt *
! 669: select_peerinterface(
! 670: struct peer * peer,
! 671: sockaddr_u * srcadr,
! 672: endpt * dstadr,
! 673: u_char cast_flags
! 674: )
! 675: {
! 676: endpt *ep;
! 677: endpt *wild;
! 678:
! 679: wild = ANY_INTERFACE_CHOOSE(srcadr);
! 680:
! 681: /*
! 682: * Initialize the peer structure and dance the interface jig.
! 683: * Reference clocks step the loopback waltz, the others
! 684: * squaredance around the interface list looking for a buddy. If
! 685: * the dance peters out, there is always the wildcard interface.
! 686: * This might happen in some systems and would preclude proper
! 687: * operation with public key cryptography.
! 688: */
! 689: if (ISREFCLOCKADR(srcadr)) {
! 690: ep = loopback_interface;
! 691: } else if (cast_flags &
! 692: (MDF_BCLNT | MDF_ACAST | MDF_MCAST | MDF_BCAST)) {
! 693: ep = findbcastinter(srcadr);
! 694: if (ep != NULL)
! 695: DPRINTF(4, ("Found *-cast interface %s for address %s\n",
! 696: stoa(&ep->sin), stoa(srcadr)));
! 697: else
! 698: DPRINTF(4, ("No *-cast local address found for address %s\n",
! 699: stoa(srcadr)));
! 700: } else {
! 701: ep = dstadr;
! 702: if (NULL == ep)
! 703: ep = wild;
! 704: }
! 705: /*
! 706: * If it is a multicast address, findbcastinter() may not find
! 707: * it. For unicast, we get to find the interface when dstadr is
! 708: * given to us as the wildcard (ANY_INTERFACE_CHOOSE). Either
! 709: * way, try a little harder.
! 710: */
! 711: if (wild == ep)
! 712: ep = findinterface(srcadr);
! 713: /*
! 714: * we do not bind to the wildcard interfaces for output
! 715: * as our (network) source address would be undefined and
! 716: * crypto will not work without knowing the own transmit address
! 717: */
! 718: if (ep != NULL && INT_WILDCARD & ep->flags)
! 719: if (!accept_wildcard_if_for_winnt)
! 720: ep = NULL;
! 721:
! 722: return ep;
! 723: }
! 724:
! 725: /*
! 726: * newpeer - initialize a new peer association
! 727: */
! 728: struct peer *
! 729: newpeer(
! 730: sockaddr_u *srcadr,
! 731: struct interface *dstadr,
! 732: int hmode,
! 733: int version,
! 734: int minpoll,
! 735: int maxpoll,
! 736: u_int flags,
! 737: u_char cast_flags,
! 738: int ttl,
! 739: keyid_t key
! 740: )
! 741: {
! 742: struct peer *peer;
! 743: u_int hash;
! 744: char tbuf[80];
! 745:
! 746: #ifdef OPENSSL
! 747: /*
! 748: * If Autokey is requested but not configured, complain loudly.
! 749: */
! 750: if (!crypto_flags) {
! 751: if (key > NTP_MAXKEY) {
! 752: return (NULL);
! 753:
! 754: } else if (flags & FLAG_SKEY) {
! 755: msyslog(LOG_ERR, "Autokey not configured");
! 756: return (NULL);
! 757: }
! 758: }
! 759: #endif /* OPENSSL */
! 760:
! 761: /*
! 762: * First search from the beginning for an association with given
! 763: * remote address and mode. If an interface is given, search
! 764: * from there to find the association which matches that
! 765: * destination. If the given interface is "any", track down the
! 766: * actual interface, because that's what gets put into the peer
! 767: * structure.
! 768: */
! 769: if (dstadr != NULL) {
! 770: peer = findexistingpeer(srcadr, NULL, hmode, cast_flags);
! 771: while (peer != NULL) {
! 772: if (peer->dstadr == dstadr ||
! 773: ((MDF_BCLNT & cast_flags) &&
! 774: (MDF_BCLNT & peer->cast_flags)))
! 775: break;
! 776:
! 777: if (dstadr == ANY_INTERFACE_CHOOSE(srcadr) &&
! 778: peer->dstadr == findinterface(srcadr))
! 779: break;
! 780:
! 781: peer = findexistingpeer(srcadr, peer, hmode,
! 782: cast_flags);
! 783: }
! 784: } else {
! 785: /* no endpt address given */
! 786: peer = findexistingpeer(srcadr, NULL, hmode, cast_flags);
! 787: }
! 788:
! 789: /*
! 790: * If a peer is found, this would be a duplicate and we don't
! 791: * allow that. This avoids duplicate ephemeral (broadcast/
! 792: * multicast) and preemptible (manycast and pool) client
! 793: * associations.
! 794: */
! 795: if (peer != NULL)
! 796: return (NULL);
! 797:
! 798: /*
! 799: * Allocate a new peer structure. Some dirt here, since some of
! 800: * the initialization requires knowlege of our system state.
! 801: */
! 802: if (peer_free_count == 0)
! 803: getmorepeermem();
! 804: UNLINK_HEAD_SLIST(peer, peer_free, next);
! 805: peer_free_count--;
! 806: peer_associations++;
! 807: if (flags & FLAG_PREEMPT)
! 808: peer_preempt++;
! 809: memset(peer, 0, sizeof(*peer));
! 810:
! 811: /*
! 812: * Assign an association ID and increment the system variable.
! 813: */
! 814: peer->associd = current_association_ID;
! 815: if (++current_association_ID == 0)
! 816: ++current_association_ID;
! 817:
! 818: DPRINTF(3, ("newpeer: cast flags: 0x%x for address: %s\n",
! 819: cast_flags, stoa(srcadr)));
! 820:
! 821: peer->srcadr = *srcadr;
! 822: set_peerdstadr(peer, select_peerinterface(peer, srcadr, dstadr,
! 823: cast_flags));
! 824: peer->hmode = (u_char)hmode;
! 825: peer->version = (u_char)version;
! 826: peer->flags = flags;
! 827:
! 828: /*
! 829: * It is an error to set minpoll less than NTP_MINPOLL or to
! 830: * set maxpoll greater than NTP_MAXPOLL. However, minpoll is
! 831: * clamped not greater than NTP_MAXPOLL and maxpoll is clamped
! 832: * not less than NTP_MINPOLL without complaint. Finally,
! 833: * minpoll is clamped not greater than maxpoll.
! 834: */
! 835: if (minpoll == 0)
! 836: peer->minpoll = NTP_MINDPOLL;
! 837: else
! 838: peer->minpoll = (u_char)min(minpoll, NTP_MAXPOLL);
! 839: if (maxpoll == 0)
! 840: peer->maxpoll = NTP_MAXDPOLL;
! 841: else
! 842: peer->maxpoll = (u_char)max(maxpoll, NTP_MINPOLL);
! 843: if (peer->minpoll > peer->maxpoll)
! 844: peer->minpoll = peer->maxpoll;
! 845:
! 846: if (peer->dstadr)
! 847: DPRINTF(3, ("newpeer: using fd %d and our addr %s\n",
! 848: peer->dstadr->fd, stoa(&peer->dstadr->sin)));
! 849: else
! 850: DPRINTF(3, ("newpeer: local interface currently not bound\n"));
! 851:
! 852: /*
! 853: * Broadcast needs the socket enabled for broadcast
! 854: */
! 855: if ((cast_flags & MDF_BCAST) && peer->dstadr)
! 856: enable_broadcast(peer->dstadr, srcadr);
! 857:
! 858: /*
! 859: * Multicast needs the socket interface enabled for multicast
! 860: */
! 861: if ((cast_flags & MDF_MCAST) && peer->dstadr)
! 862: enable_multicast_if(peer->dstadr, srcadr);
! 863:
! 864: #ifdef OPENSSL
! 865: if (key > NTP_MAXKEY)
! 866: peer->flags |= FLAG_SKEY;
! 867: #endif /* OPENSSL */
! 868: peer->cast_flags = cast_flags;
! 869: peer->ttl = (u_char)ttl;
! 870: peer->keyid = key;
! 871: peer->precision = sys_precision;
! 872: peer->hpoll = peer->minpoll;
! 873: if (cast_flags & MDF_ACAST)
! 874: peer_clear(peer, "ACST");
! 875: else if (cast_flags & MDF_MCAST)
! 876: peer_clear(peer, "MCST");
! 877: else if (cast_flags & MDF_BCAST)
! 878: peer_clear(peer, "BCST");
! 879: else
! 880: peer_clear(peer, "INIT");
! 881: if (mode_ntpdate)
! 882: peer_ntpdate++;
! 883:
! 884: /*
! 885: * Note time on statistics timers.
! 886: */
! 887: peer->timereset = current_time;
! 888: peer->timereachable = current_time;
! 889: peer->timereceived = current_time;
! 890:
! 891: #ifdef REFCLOCK
! 892: if (ISREFCLOCKADR(&peer->srcadr)) {
! 893:
! 894: /*
! 895: * We let the reference clock support do clock
! 896: * dependent initialization. This includes setting
! 897: * the peer timer, since the clock may have requirements
! 898: * for this.
! 899: */
! 900: if (maxpoll == 0)
! 901: peer->maxpoll = peer->minpoll;
! 902: if (!refclock_newpeer(peer)) {
! 903: /*
! 904: * Dump it, something screwed up
! 905: */
! 906: set_peerdstadr(peer, NULL);
! 907: LINK_SLIST(peer_free, peer, next);
! 908: peer_free_count++;
! 909: return (NULL);
! 910: }
! 911: }
! 912: #endif
! 913:
! 914: /*
! 915: * Put the new peer in the hash tables.
! 916: */
! 917: hash = NTP_HASH_ADDR(&peer->srcadr);
! 918: LINK_SLIST(peer_hash[hash], peer, next);
! 919: peer_hash_count[hash]++;
! 920: hash = peer->associd & NTP_HASH_MASK;
! 921: LINK_SLIST(assoc_hash[hash], peer, ass_next);
! 922: assoc_hash_count[hash]++;
! 923: snprintf(tbuf, sizeof(tbuf), "assoc %d", peer->associd);
! 924: report_event(PEVNT_MOBIL, peer, tbuf);
! 925: DPRINTF(1, ("newpeer: %s->%s mode %d vers %d poll %d %d flags 0x%x 0x%x ttl %d key %08x\n",
! 926: peer->dstadr == NULL ? "<null>" : stoa(&peer->dstadr->sin),
! 927: stoa(&peer->srcadr), peer->hmode, peer->version,
! 928: peer->minpoll, peer->maxpoll, peer->flags, peer->cast_flags,
! 929: peer->ttl, peer->keyid));
! 930: return (peer);
! 931: }
! 932:
! 933:
! 934: /*
! 935: * peer_clr_stats - clear peer module statiistics counters
! 936: */
! 937: void
! 938: peer_clr_stats(void)
! 939: {
! 940: findpeer_calls = 0;
! 941: assocpeer_calls = 0;
! 942: peer_allocations = 0;
! 943: peer_demobilizations = 0;
! 944: peer_timereset = current_time;
! 945: }
! 946:
! 947: /*
! 948: * peer_reset - reset statistics counters
! 949: */
! 950: void
! 951: peer_reset(
! 952: struct peer *peer
! 953: )
! 954: {
! 955: if (peer == NULL)
! 956: return;
! 957:
! 958: peer->timereset = current_time;
! 959: peer->sent = 0;
! 960: peer->received = 0;
! 961: peer->processed = 0;
! 962: peer->badauth = 0;
! 963: peer->bogusorg = 0;
! 964: peer->oldpkt = 0;
! 965: peer->seldisptoolarge = 0;
! 966: peer->selbroken = 0;
! 967: }
! 968:
! 969:
! 970: /*
! 971: * peer_all_reset - reset all peer statistics counters
! 972: */
! 973: void
! 974: peer_all_reset(void)
! 975: {
! 976: struct peer *peer;
! 977: int hash;
! 978:
! 979: for (hash = 0; hash < NTP_HASH_SIZE; hash++)
! 980: for (peer = peer_hash[hash]; peer != 0; peer = peer->next)
! 981: peer_reset(peer);
! 982: }
! 983:
! 984:
! 985: /*
! 986: * findmanycastpeer - find and return a manycast peer
! 987: */
! 988: struct peer *
! 989: findmanycastpeer(
! 990: struct recvbuf *rbufp /* receive buffer pointer */
! 991: )
! 992: {
! 993: register struct peer *peer;
! 994: struct pkt *pkt;
! 995: l_fp p_org;
! 996: int i;
! 997:
! 998: /*
! 999: * This routine is called upon arrival of a server-mode message
! 1000: * from a manycast client. Search the peer list for a manycast
! 1001: * client association where the last transmit timestamp matches
! 1002: * the originate timestamp. This assumes the transmit timestamps
! 1003: * for possibly more than one manycast association are unique.
! 1004: */
! 1005: pkt = &rbufp->recv_pkt;
! 1006: for (i = 0; i < NTP_HASH_SIZE; i++) {
! 1007: if (peer_hash_count[i] == 0)
! 1008: continue;
! 1009:
! 1010: for (peer = peer_hash[i]; peer != 0; peer =
! 1011: peer->next) {
! 1012: if (peer->cast_flags & MDF_ACAST) {
! 1013: NTOHL_FP(&pkt->org, &p_org);
! 1014: if (L_ISEQU(&p_org, &peer->aorg))
! 1015: return (peer);
! 1016: }
! 1017: }
! 1018: }
! 1019: return (NULL);
! 1020: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>