Blame ntp_core.c

Packit 96c956
/*
Packit 96c956
  chronyd/chronyc - Programs for keeping computer clocks accurate.
Packit 96c956
Packit 96c956
 **********************************************************************
Packit 96c956
 * Copyright (C) Richard P. Curnow  1997-2003
Packit 96c956
 * Copyright (C) Miroslav Lichvar  2009-2018
Packit 96c956
 * 
Packit 96c956
 * This program is free software; you can redistribute it and/or modify
Packit 96c956
 * it under the terms of version 2 of the GNU General Public License as
Packit 96c956
 * published by the Free Software Foundation.
Packit 96c956
 * 
Packit 96c956
 * This program is distributed in the hope that it will be useful, but
Packit 96c956
 * WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 96c956
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 96c956
 * General Public License for more details.
Packit 96c956
 * 
Packit 96c956
 * You should have received a copy of the GNU General Public License along
Packit 96c956
 * with this program; if not, write to the Free Software Foundation, Inc.,
Packit 96c956
 * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
Packit 96c956
 * 
Packit 96c956
 **********************************************************************
Packit 96c956
Packit 96c956
  =======================================================================
Packit 96c956
Packit 96c956
  Core NTP protocol engine
Packit 96c956
  */
Packit 96c956
Packit 96c956
#include "config.h"
Packit 96c956
Packit 96c956
#include "sysincl.h"
Packit 96c956
Packit 96c956
#include "array.h"
Packit 96c956
#include "ntp_core.h"
Packit 96c956
#include "ntp_io.h"
Packit 96c956
#include "ntp_signd.h"
Packit 96c956
#include "memory.h"
Packit 96c956
#include "sched.h"
Packit 96c956
#include "reference.h"
Packit 96c956
#include "local.h"
Packit 96c956
#include "samplefilt.h"
Packit 96c956
#include "smooth.h"
Packit 96c956
#include "sources.h"
Packit 96c956
#include "util.h"
Packit 96c956
#include "conf.h"
Packit 96c956
#include "logging.h"
Packit 96c956
#include "keys.h"
Packit 96c956
#include "addrfilt.h"
Packit 96c956
#include "clientlog.h"
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static LOG_FileID logfileid;
Packit 96c956
static int log_raw_measurements;
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Enumeration used for remembering the operating mode of one of the
Packit 96c956
   sources */
Packit 96c956
Packit 96c956
typedef enum {
Packit 96c956
  MD_OFFLINE,                   /* No sampling at all */
Packit 96c956
  MD_ONLINE,                    /* Normal sampling based on sampling interval */
Packit 96c956
  MD_BURST_WAS_OFFLINE,         /* Burst sampling, return to offline afterwards */
Packit 96c956
  MD_BURST_WAS_ONLINE,          /* Burst sampling, return to online afterwards */
Packit 96c956
} OperatingMode;
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Enumeration for authentication modes of NTP packets */
Packit 96c956
Packit 96c956
typedef enum {
Packit 96c956
  AUTH_NONE = 0,                /* No authentication */
Packit 96c956
  AUTH_SYMMETRIC,               /* MAC using symmetric key (RFC 1305, RFC 5905) */
Packit 96c956
  AUTH_MSSNTP,                  /* MS-SNTP authenticator field */
Packit 96c956
  AUTH_MSSNTP_EXT,              /* MS-SNTP extended authenticator field */
Packit 96c956
} AuthenticationMode;
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Structure used for holding a single peer/server's
Packit 96c956
   protocol machine */
Packit 96c956
Packit 96c956
struct NCR_Instance_Record {
Packit 96c956
  NTP_Remote_Address remote_addr; /* Needed for routing transmit packets */
Packit 96c956
  NTP_Local_Address local_addr; /* Local address/socket used to send packets */
Packit 96c956
  NTP_Mode mode;                /* The source's NTP mode
Packit 96c956
                                   (client/server or symmetric active peer) */
Packit 96c956
  int interleaved;              /* Boolean enabling interleaved NTP mode */
Packit 96c956
  OperatingMode opmode;         /* Whether we are sampling this source
Packit 96c956
                                   or not and in what way */
Packit 96c956
  SCH_TimeoutID rx_timeout_id;  /* Timeout ID for latest received response */
Packit 96c956
  SCH_TimeoutID tx_timeout_id;  /* Timeout ID for next transmission */
Packit 96c956
  int tx_suspended;             /* Boolean indicating we can't transmit yet */
Packit 96c956
Packit 96c956
  int auto_burst;               /* If 1, initiate a burst on each poll */
Packit 96c956
  int auto_offline;             /* If 1, automatically go offline when requests
Packit 96c956
                                   cannot be sent */
Packit 96c956
Packit 96c956
  int local_poll;               /* Log2 of polling interval at our end */
Packit 96c956
  int remote_poll;              /* Log2 of server/peer's polling interval (recovered
Packit 96c956
                                   from received packets) */
Packit 96c956
  int remote_stratum;           /* Stratum of the server/peer (recovered from
Packit 96c956
                                   received packets) */
Packit 96c956
Packit 96c956
  int presend_minpoll;           /* If the current polling interval is
Packit 96c956
                                    at least this, an extra client packet
Packit 96c956
                                    will be send some time before normal
Packit 96c956
                                    transmit.  This ensures that both
Packit 96c956
                                    us and the server/peer have an ARP
Packit 96c956
                                    entry for each other ready, which
Packit 96c956
                                    means our measurement is not
Packit 96c956
                                    botched by an ARP round-trip on one
Packit 96c956
                                    side or the other. */
Packit 96c956
Packit 96c956
  int presend_done;             /* The presend packet has been sent */
Packit 96c956
Packit 96c956
  int minpoll;                  /* Log2 of minimum defined polling interval */
Packit 96c956
  int maxpoll;                  /* Log2 of maximum defined polling interval */
Packit 96c956
Packit 96c956
  int min_stratum;              /* Increase stratum in received packets to the
Packit 96c956
                                   minimum */
Packit 96c956
Packit 96c956
  int poll_target;              /* Target number of sourcestats samples */
Packit 96c956
Packit 96c956
  int version;                  /* Version set in packets for server/peer */
Packit 96c956
Packit 96c956
  double poll_score;            /* Score of current local poll */
Packit 96c956
Packit 96c956
  double max_delay;             /* Maximum round-trip delay to the
Packit 96c956
                                   peer that we can tolerate and still
Packit 96c956
                                   use the sample for generating
Packit 96c956
                                   statistics from */
Packit 96c956
Packit 96c956
  double max_delay_ratio;       /* Largest ratio of delay /
Packit 96c956
                                   min_delay_in_register that we can
Packit 96c956
                                   tolerate.  */
Packit 96c956
Packit 96c956
  double max_delay_dev_ratio;   /* Maximum ratio of increase in delay / stddev */
Packit 96c956
Packit 96c956
  double offset_correction;     /* Correction applied to measured offset
Packit 96c956
                                   (e.g. for asymmetry in network delay) */
Packit 96c956
Packit 96c956
  AuthenticationMode auth_mode; /* Authentication mode of our requests */
Packit 96c956
  uint32_t auth_key_id;          /* The ID of the authentication key to
Packit 96c956
                                   use. */
Packit 96c956
Packit 96c956
  /* Count of transmitted packets since last valid response */
Packit 96c956
  unsigned int tx_count;
Packit 96c956
Packit 96c956
  /* Flag indicating a valid response was received since last request */
Packit 96c956
  int valid_rx;
Packit 96c956
Packit 96c956
  /* Flag indicating the timestamps below are from a valid packet and may
Packit 96c956
     be used for synchronisation */
Packit 96c956
  int valid_timestamps;
Packit 96c956
Packit 96c956
  /* Receive and transmit timestamps from the last valid response */
Packit 96c956
  NTP_int64 remote_ntp_rx;
Packit 96c956
  NTP_int64 remote_ntp_tx;
Packit 96c956
Packit 96c956
  /* Local timestamp when the last valid response was received from the
Packit 96c956
     source.  We have to be prepared to tinker with this if the local
Packit 96c956
     clock has its frequency adjusted before we repond.  The value we
Packit 96c956
     store here is what our own local time was when the same arrived.
Packit 96c956
     Before replying, we have to correct this to fit with the
Packit 96c956
     parameters for the current reference.  (It must be stored
Packit 96c956
     relative to local time to permit frequency and offset adjustments
Packit 96c956
     to be made when we trim the local clock). */
Packit 96c956
  NTP_int64 local_ntp_rx;
Packit 96c956
  NTP_Local_Timestamp local_rx;
Packit 96c956
Packit 96c956
  /* Local timestamp when we last transmitted a packet to the source.
Packit 96c956
     We store two versions.  The first is in NTP format, and is used
Packit 96c956
     to validate the next received packet from the source.
Packit 96c956
     Additionally, this is corrected to bring it into line with the
Packit 96c956
     current reference.  The second is in timespec format, and is kept
Packit 96c956
     relative to the local clock.  We modify this in accordance with
Packit 96c956
     local clock frequency/offset changes, and use this for computing
Packit 96c956
     statistics about the source when a return packet arrives. */
Packit 96c956
  NTP_int64 local_ntp_tx;
Packit 96c956
  NTP_Local_Timestamp local_tx;
Packit 96c956
Packit 96c956
  /* Previous values of some variables needed in interleaved mode */
Packit 96c956
  NTP_Local_Timestamp prev_local_tx;
Packit 96c956
  int prev_local_poll;
Packit 96c956
  unsigned int prev_tx_count;
Packit 96c956
Packit 96c956
  /* Flag indicating the two timestamps below were updated since the
Packit 96c956
     last transmission */
Packit 96c956
  int updated_init_timestamps;
Packit 96c956
Packit 96c956
  /* Timestamps used for (re)starting the symmetric protocol, when we
Packit 96c956
     need to respond to a packet which is not a valid response */
Packit 96c956
  NTP_int64 init_remote_ntp_tx;
Packit 96c956
  NTP_Local_Timestamp init_local_rx;
Packit 96c956
Packit 96c956
  /* The instance record in the main source management module.  This
Packit 96c956
     performs the statistical analysis on the samples we generate */
Packit 96c956
Packit 96c956
  SRC_Instance source;
Packit 96c956
Packit 96c956
  /* Optional median filter for NTP measurements */
Packit 96c956
  SPF_Instance filter;
Packit 96c956
Packit 96c956
  int burst_good_samples_to_go;
Packit 96c956
  int burst_total_samples_to_go;
Packit 96c956
Packit 96c956
  /* Report from last valid response */
Packit 96c956
  RPT_NTPReport report;
Packit 96c956
};
Packit 96c956
Packit 96c956
typedef struct {
Packit 96c956
  NTP_Remote_Address addr;
Packit 96c956
  NTP_Local_Address local_addr;
Packit 96c956
  int interval;
Packit 96c956
} BroadcastDestination;
Packit 96c956
Packit 96c956
/* Array of BroadcastDestination */
Packit 96c956
static ARR_Instance broadcasts;
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Initial delay period before first packet is transmitted (in seconds) */
Packit 96c956
#define INITIAL_DELAY 0.2
Packit 96c956
Packit 96c956
/* Spacing required between samples for any two servers/peers (to
Packit 96c956
   minimise risk of network collisions) (in seconds) */
Packit 96c956
#define MIN_SAMPLING_SEPARATION 0.002
Packit 96c956
#define MAX_SAMPLING_SEPARATION 0.2
Packit 96c956
Packit 96c956
/* Randomness added to spacing between samples for one server/peer */
Packit 96c956
#define SAMPLING_RANDOMNESS 0.02
Packit 96c956
Packit 96c956
/* Adjustment of the peer polling interval */
Packit 96c956
#define PEER_SAMPLING_ADJ 1.1
Packit 96c956
Packit 96c956
/* Maximum spacing between samples in the burst mode as an absolute
Packit 96c956
   value and ratio to the normal polling interval */
Packit 96c956
#define MAX_BURST_INTERVAL 2.0
Packit 96c956
#define MAX_BURST_POLL_RATIO 0.25
Packit 96c956
Packit 96c956
/* Number of samples in initial burst */
Packit 96c956
#define IBURST_GOOD_SAMPLES 4
Packit 96c956
#define IBURST_TOTAL_SAMPLES SOURCE_REACH_BITS
Packit 96c956
Packit 96c956
/* Number of samples in automatic burst */
Packit 96c956
#define BURST_GOOD_SAMPLES 1
Packit 96c956
#define MAX_BURST_TOTAL_SAMPLES 4
Packit 96c956
Packit 96c956
/* Time to wait after sending packet to 'warm up' link */
Packit 96c956
#define WARM_UP_DELAY 2.0
Packit 96c956
Packit 96c956
/* Compatible NTP protocol versions */
Packit 96c956
#define NTP_MAX_COMPAT_VERSION NTP_VERSION
Packit 96c956
#define NTP_MIN_COMPAT_VERSION 1
Packit 96c956
Packit 96c956
/* Maximum allowed dispersion - as defined in RFC 5905 (16 seconds) */
Packit 96c956
#define NTP_MAX_DISPERSION 16.0
Packit 96c956
Packit 96c956
/* Invalid stratum number */
Packit 96c956
#define NTP_INVALID_STRATUM 0
Packit 96c956
Packit 96c956
/* Maximum allowed time for server to process client packet */
Packit 96c956
#define MAX_SERVER_INTERVAL 4.0
Packit 96c956
Packit 96c956
/* Maximum acceptable delay in transmission for timestamp correction */
Packit 96c956
#define MAX_TX_DELAY 1.0
Packit 96c956
Packit 96c956
/* Maximum allowed values of maxdelay parameters */
Packit 96c956
#define MAX_MAXDELAY 1.0e3
Packit 96c956
#define MAX_MAXDELAYRATIO 1.0e6
Packit 96c956
#define MAX_MAXDELAYDEVRATIO 1.0e6
Packit 96c956
Packit 96c956
/* Minimum and maximum allowed poll interval */
Packit 96c956
#define MIN_POLL -6
Packit 96c956
#define MAX_POLL 24
Packit 96c956
Packit 96c956
/* Enable sub-second polling intervals only when the peer delay is not
Packit 96c956
   longer than 10 milliseconds to restrict them to local networks */
Packit 96c956
#define MIN_NONLAN_POLL 0
Packit 96c956
#define MAX_LAN_PEER_DELAY 0.01
Packit 96c956
Packit 96c956
/* Kiss-o'-Death codes */
Packit 96c956
#define KOD_RATE 0x52415445UL /* RATE */
Packit 96c956
Packit 96c956
/* Maximum poll interval set by KoD RATE */
Packit 96c956
#define MAX_KOD_RATE_POLL SRC_DEFAULT_MAXPOLL
Packit 96c956
Packit 96c956
/* Maximum number of missed responses to accept samples using old timestamps
Packit 96c956
   in the interleaved client/server mode */
Packit 96c956
#define MAX_CLIENT_INTERLEAVED_TX 4
Packit 96c956
Packit 96c956
/* Maximum ratio of local intervals in the timestamp selection of the
Packit 96c956
   interleaved mode to prefer a sample using previous timestamps */
Packit 96c956
#define MAX_INTERLEAVED_L2L_RATIO 0.1
Packit 96c956
Packit 96c956
/* Invalid socket, different from the one in ntp_io.c */
Packit 96c956
#define INVALID_SOCK_FD -2
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
/* Server IPv4/IPv6 sockets */
Packit 96c956
static int server_sock_fd4;
Packit 96c956
static int server_sock_fd6;
Packit 96c956
Packit 96c956
static ADF_AuthTable access_auth_table;
Packit 96c956
Packit 96c956
/* Characters for printing synchronisation status and timestamping source */
Packit 96c956
static const char leap_chars[4] = {'N', '+', '-', '?'};
Packit 96c956
static const char tss_chars[3] = {'D', 'K', 'H'};
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Forward prototypes */
Packit 96c956
Packit 96c956
static void transmit_timeout(void *arg);
Packit 96c956
static double get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx);
Packit 96c956
static double get_separation(int poll);
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
do_size_checks(void)
Packit 96c956
{
Packit 96c956
  /* Assertions to check the sizes of certain data types
Packit 96c956
     and the positions of certain record fields */
Packit 96c956
Packit 96c956
  /* Check that certain invariants are true */
Packit 96c956
  assert(sizeof(NTP_int32) == 4);
Packit 96c956
  assert(sizeof(NTP_int64) == 8);
Packit 96c956
Packit 96c956
  /* Check offsets of all fields in the NTP packet format */
Packit 96c956
  assert(offsetof(NTP_Packet, lvm)             ==  0);
Packit 96c956
  assert(offsetof(NTP_Packet, stratum)         ==  1);
Packit 96c956
  assert(offsetof(NTP_Packet, poll)            ==  2);
Packit 96c956
  assert(offsetof(NTP_Packet, precision)       ==  3);
Packit 96c956
  assert(offsetof(NTP_Packet, root_delay)      ==  4);
Packit 96c956
  assert(offsetof(NTP_Packet, root_dispersion) ==  8);
Packit 96c956
  assert(offsetof(NTP_Packet, reference_id)    == 12);
Packit 96c956
  assert(offsetof(NTP_Packet, reference_ts)    == 16);
Packit 96c956
  assert(offsetof(NTP_Packet, originate_ts)    == 24);
Packit 96c956
  assert(offsetof(NTP_Packet, receive_ts)      == 32);
Packit 96c956
  assert(offsetof(NTP_Packet, transmit_ts)     == 40);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
do_time_checks(void)
Packit 96c956
{
Packit 96c956
  struct timespec now;
Packit 96c956
  time_t warning_advance = 3600 * 24 * 365 * 10; /* 10 years */
Packit 96c956
Packit 96c956
#ifdef HAVE_LONG_TIME_T
Packit 96c956
  /* Check that time before NTP_ERA_SPLIT underflows correctly */
Packit 96c956
Packit 96c956
  struct timespec ts1 = {NTP_ERA_SPLIT, 1}, ts2 = {NTP_ERA_SPLIT - 1, 1};
Packit 96c956
  NTP_int64 nts1, nts2;
Packit 96c956
  int r;
Packit 96c956
Packit 96c956
  UTI_TimespecToNtp64(&ts1, &nts1, NULL);
Packit 96c956
  UTI_TimespecToNtp64(&ts2, &nts2, NULL);
Packit 96c956
  UTI_Ntp64ToTimespec(&nts1, &ts1;;
Packit 96c956
  UTI_Ntp64ToTimespec(&nts2, &ts2;;
Packit 96c956
Packit 96c956
  r = ts1.tv_sec == NTP_ERA_SPLIT &&
Packit 96c956
      ts1.tv_sec + (1ULL << 32) - 1 == ts2.tv_sec;
Packit 96c956
Packit 96c956
  assert(r);
Packit 96c956
Packit 96c956
  LCL_ReadRawTime(&now;;
Packit 96c956
  if (ts2.tv_sec - now.tv_sec < warning_advance)
Packit 96c956
    LOG(LOGS_WARN, "Assumed NTP time ends at %s!", UTI_TimeToLogForm(ts2.tv_sec));
Packit 96c956
#else
Packit 96c956
  LCL_ReadRawTime(&now;;
Packit 96c956
  if (now.tv_sec > 0x7fffffff - warning_advance)
Packit 96c956
    LOG(LOGS_WARN, "System time ends at %s!", UTI_TimeToLogForm(0x7fffffff));
Packit 96c956
#endif
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
zero_local_timestamp(NTP_Local_Timestamp *ts)
Packit 96c956
{
Packit 96c956
  UTI_ZeroTimespec(&ts->ts);
Packit 96c956
  ts->err = 0.0;
Packit 96c956
  ts->source = NTP_TS_DAEMON;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_Initialise(void)
Packit 96c956
{
Packit 96c956
  do_size_checks();
Packit 96c956
  do_time_checks();
Packit 96c956
Packit 96c956
  logfileid = CNF_GetLogMeasurements(&log_raw_measurements) ? LOG_FileOpen("measurements",
Packit 96c956
      "   Date (UTC) Time     IP Address   L St 123 567 ABCD  LP RP Score    Offset  Peer del. Peer disp.  Root del. Root disp. Refid     MTxRx")
Packit 96c956
    : -1;
Packit 96c956
Packit 96c956
  access_auth_table = ADF_CreateTable();
Packit 96c956
  broadcasts = ARR_CreateInstance(sizeof (BroadcastDestination));
Packit 96c956
Packit 96c956
  /* Server socket will be opened when access is allowed */
Packit 96c956
  server_sock_fd4 = INVALID_SOCK_FD;
Packit 96c956
  server_sock_fd6 = INVALID_SOCK_FD;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_Finalise(void)
Packit 96c956
{
Packit 96c956
  unsigned int i;
Packit 96c956
Packit 96c956
  if (server_sock_fd4 != INVALID_SOCK_FD)
Packit 96c956
    NIO_CloseServerSocket(server_sock_fd4);
Packit 96c956
  if (server_sock_fd6 != INVALID_SOCK_FD)
Packit 96c956
    NIO_CloseServerSocket(server_sock_fd6);
Packit 96c956
Packit 96c956
  for (i = 0; i < ARR_GetSize(broadcasts); i++)
Packit 96c956
    NIO_CloseServerSocket(((BroadcastDestination *)ARR_GetElement(broadcasts, i))->local_addr.sock_fd);
Packit 96c956
Packit 96c956
  ARR_DestroyInstance(broadcasts);
Packit 96c956
  ADF_DestroyTable(access_auth_table);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
restart_timeout(NCR_Instance inst, double delay)
Packit 96c956
{
Packit 96c956
  /* Check if we can transmit */
Packit 96c956
  if (inst->tx_suspended) {
Packit 96c956
    assert(!inst->tx_timeout_id);
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Stop both rx and tx timers if running */
Packit 96c956
  SCH_RemoveTimeout(inst->rx_timeout_id);
Packit 96c956
  inst->rx_timeout_id = 0;
Packit 96c956
  SCH_RemoveTimeout(inst->tx_timeout_id);
Packit 96c956
Packit 96c956
  /* Start new timer for transmission */
Packit 96c956
  inst->tx_timeout_id = SCH_AddTimeoutInClass(delay, get_separation(inst->local_poll),
Packit 96c956
                                              SAMPLING_RANDOMNESS,
Packit 96c956
                                              inst->mode == MODE_CLIENT ?
Packit 96c956
                                                SCH_NtpClientClass : SCH_NtpPeerClass,
Packit 96c956
                                              transmit_timeout, (void *)inst);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
start_initial_timeout(NCR_Instance inst)
Packit 96c956
{
Packit 96c956
  double delay, last_tx;
Packit 96c956
  struct timespec now;
Packit 96c956
Packit 96c956
  if (!inst->tx_timeout_id) {
Packit 96c956
    /* This will be the first transmission after mode change */
Packit 96c956
Packit 96c956
    /* Mark source active */
Packit 96c956
    SRC_SetActive(inst->source);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* In case the offline period was too short, adjust the delay to keep
Packit 96c956
     the interval between packets at least as long as the current polling
Packit 96c956
     interval */
Packit 96c956
  SCH_GetLastEventTime(&now, NULL, NULL);
Packit 96c956
  last_tx = UTI_DiffTimespecsToDouble(&now, &inst->local_tx.ts);
Packit 96c956
  if (last_tx < 0.0)
Packit 96c956
    last_tx = 0.0;
Packit 96c956
  delay = get_transmit_delay(inst, 0, 0.0) - last_tx;
Packit 96c956
  if (delay < INITIAL_DELAY)
Packit 96c956
    delay = INITIAL_DELAY;
Packit 96c956
Packit 96c956
  restart_timeout(inst, delay);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
close_client_socket(NCR_Instance inst)
Packit 96c956
{
Packit 96c956
  if (inst->mode == MODE_CLIENT && inst->local_addr.sock_fd != INVALID_SOCK_FD) {
Packit 96c956
    NIO_CloseClientSocket(inst->local_addr.sock_fd);
Packit 96c956
    inst->local_addr.sock_fd = INVALID_SOCK_FD;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  SCH_RemoveTimeout(inst->rx_timeout_id);
Packit 96c956
  inst->rx_timeout_id = 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
take_offline(NCR_Instance inst)
Packit 96c956
{
Packit 96c956
  inst->opmode = MD_OFFLINE;
Packit 96c956
Packit 96c956
  SCH_RemoveTimeout(inst->tx_timeout_id);
Packit 96c956
  inst->tx_timeout_id = 0;
Packit 96c956
Packit 96c956
  /* Mark source unreachable */
Packit 96c956
  SRC_ResetReachability(inst->source);
Packit 96c956
Packit 96c956
  /* And inactive */
Packit 96c956
  SRC_UnsetActive(inst->source);
Packit 96c956
Packit 96c956
  close_client_socket(inst);
Packit 96c956
Packit 96c956
  NCR_ResetInstance(inst);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
NCR_Instance
Packit 96c956
NCR_GetInstance(NTP_Remote_Address *remote_addr, NTP_Source_Type type, SourceParameters *params)
Packit 96c956
{
Packit 96c956
  NCR_Instance result;
Packit 96c956
Packit 96c956
  result = MallocNew(struct NCR_Instance_Record);
Packit 96c956
Packit 96c956
  result->remote_addr = *remote_addr;
Packit 96c956
  result->local_addr.ip_addr.family = IPADDR_UNSPEC;
Packit 96c956
  result->local_addr.if_index = INVALID_IF_INDEX;
Packit 96c956
Packit 96c956
  switch (type) {
Packit 96c956
    case NTP_SERVER:
Packit 96c956
      /* Client socket will be obtained when sending request */
Packit 96c956
      result->local_addr.sock_fd = INVALID_SOCK_FD;
Packit 96c956
      result->mode = MODE_CLIENT;
Packit 96c956
      break;
Packit 96c956
    case NTP_PEER:
Packit 96c956
      result->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
Packit 96c956
      result->mode = MODE_ACTIVE;
Packit 96c956
      break;
Packit 96c956
    default:
Packit 96c956
      assert(0);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  result->interleaved = params->interleaved;
Packit 96c956
Packit 96c956
  result->minpoll = params->minpoll;
Packit 96c956
  if (result->minpoll < MIN_POLL)
Packit 96c956
    result->minpoll = SRC_DEFAULT_MINPOLL;
Packit 96c956
  else if (result->minpoll > MAX_POLL)
Packit 96c956
    result->minpoll = MAX_POLL;
Packit 96c956
Packit 96c956
  result->maxpoll = params->maxpoll;
Packit 96c956
  if (result->maxpoll < MIN_POLL)
Packit 96c956
    result->maxpoll = SRC_DEFAULT_MAXPOLL;
Packit 96c956
  else if (result->maxpoll > MAX_POLL)
Packit 96c956
    result->maxpoll = MAX_POLL;
Packit 96c956
  if (result->maxpoll < result->minpoll)
Packit 96c956
    result->maxpoll = result->minpoll;
Packit 96c956
Packit 96c956
  result->min_stratum = params->min_stratum;
Packit 96c956
  if (result->min_stratum >= NTP_MAX_STRATUM)
Packit 96c956
    result->min_stratum = NTP_MAX_STRATUM - 1;
Packit 96c956
Packit 96c956
  /* Presend doesn't work in symmetric mode */
Packit 96c956
  result->presend_minpoll = params->presend_minpoll;
Packit 96c956
  if (result->presend_minpoll <= MAX_POLL && result->mode != MODE_CLIENT)
Packit 96c956
    result->presend_minpoll = MAX_POLL + 1;
Packit 96c956
Packit 96c956
  result->max_delay = CLAMP(0.0, params->max_delay, MAX_MAXDELAY);
Packit 96c956
  result->max_delay_ratio = CLAMP(0.0, params->max_delay_ratio, MAX_MAXDELAYRATIO);
Packit 96c956
  result->max_delay_dev_ratio = CLAMP(0.0, params->max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
Packit 96c956
  result->offset_correction = params->offset;
Packit 96c956
  result->auto_burst = params->burst;
Packit 96c956
  result->auto_offline = params->auto_offline;
Packit 96c956
  result->poll_target = params->poll_target;
Packit 96c956
Packit 96c956
  result->version = NTP_VERSION;
Packit 96c956
Packit 96c956
  if (params->authkey == INACTIVE_AUTHKEY) {
Packit 96c956
    result->auth_mode = AUTH_NONE;
Packit 96c956
    result->auth_key_id = 0;
Packit 96c956
  } else {
Packit 96c956
    result->auth_mode = AUTH_SYMMETRIC;
Packit 96c956
    result->auth_key_id = params->authkey;
Packit 96c956
    if (!KEY_KeyKnown(result->auth_key_id)) {
Packit 96c956
      LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
Packit 96c956
          result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
Packit 96c956
          "missing");
Packit 96c956
    } else if (!KEY_CheckKeyLength(result->auth_key_id)) {
Packit 96c956
      LOG(LOGS_WARN, "Key %"PRIu32" used by source %s is %s",
Packit 96c956
          result->auth_key_id, UTI_IPToString(&result->remote_addr.ip_addr),
Packit 96c956
          "too short");
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* If the MAC in NTPv4 packets would be truncated, use version 3 by
Packit 96c956
       default for compatibility with older chronyd servers */
Packit 96c956
    if (KEY_GetAuthLength(result->auth_key_id) + 4 > NTP_MAX_V4_MAC_LENGTH)
Packit 96c956
      result->version = 3;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (params->version)
Packit 96c956
    result->version = CLAMP(NTP_MIN_COMPAT_VERSION, params->version, NTP_VERSION);
Packit 96c956
Packit 96c956
  /* Create a source instance for this NTP source */
Packit 96c956
  result->source = SRC_CreateNewInstance(UTI_IPToRefid(&remote_addr->ip_addr),
Packit 96c956
                                         SRC_NTP, params->sel_options,
Packit 96c956
                                         &result->remote_addr.ip_addr,
Packit 96c956
                                         params->min_samples, params->max_samples,
Packit 96c956
                                         params->min_delay, params->asymmetry);
Packit 96c956
Packit 96c956
  if (params->filter_length >= 1)
Packit 96c956
    result->filter = SPF_CreateInstance(params->filter_length, params->filter_length,
Packit 96c956
                                        NTP_MAX_DISPERSION, 0.0);
Packit 96c956
  else
Packit 96c956
    result->filter = NULL;
Packit 96c956
Packit 96c956
  result->rx_timeout_id = 0;
Packit 96c956
  result->tx_timeout_id = 0;
Packit 96c956
  result->tx_suspended = 1;
Packit 96c956
  result->opmode = params->connectivity == SRC_ONLINE ||
Packit 96c956
                   (params->connectivity == SRC_MAYBE_ONLINE &&
Packit 96c956
                    NIO_IsServerConnectable(remote_addr)) ? MD_ONLINE : MD_OFFLINE;
Packit 96c956
  result->local_poll = result->minpoll;
Packit 96c956
  result->poll_score = 0.0;
Packit 96c956
  zero_local_timestamp(&result->local_tx);
Packit 96c956
  result->burst_good_samples_to_go = 0;
Packit 96c956
  result->burst_total_samples_to_go = 0;
Packit 96c956
  memset(&result->report, 0, sizeof (result->report));
Packit 96c956
  
Packit 96c956
  NCR_ResetInstance(result);
Packit 96c956
Packit 96c956
  if (params->iburst) {
Packit 96c956
    NCR_InitiateSampleBurst(result, IBURST_GOOD_SAMPLES, IBURST_TOTAL_SAMPLES);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  return result;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
/* Destroy an instance */
Packit 96c956
void
Packit 96c956
NCR_DestroyInstance(NCR_Instance instance)
Packit 96c956
{
Packit 96c956
  if (instance->opmode != MD_OFFLINE)
Packit 96c956
    take_offline(instance);
Packit 96c956
Packit 96c956
  if (instance->mode == MODE_ACTIVE)
Packit 96c956
    NIO_CloseServerSocket(instance->local_addr.sock_fd);
Packit 96c956
Packit 96c956
  if (instance->filter)
Packit 96c956
    SPF_DestroyInstance(instance->filter);
Packit 96c956
Packit 96c956
  /* This will destroy the source instance inside the
Packit 96c956
     structure, which will cause reselection if this was the
Packit 96c956
     synchronising source etc. */
Packit 96c956
  SRC_DestroyInstance(instance->source);
Packit 96c956
Packit 96c956
  /* Free the data structure */
Packit 96c956
  Free(instance);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_StartInstance(NCR_Instance instance)
Packit 96c956
{
Packit 96c956
  instance->tx_suspended = 0;
Packit 96c956
  if (instance->opmode != MD_OFFLINE)
Packit 96c956
    start_initial_timeout(instance);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ResetInstance(NCR_Instance instance)
Packit 96c956
{
Packit 96c956
  instance->tx_count = 0;
Packit 96c956
  instance->presend_done = 0;
Packit 96c956
Packit 96c956
  instance->remote_poll = 0;
Packit 96c956
  instance->remote_stratum = 0;
Packit 96c956
Packit 96c956
  instance->valid_rx = 0;
Packit 96c956
  instance->valid_timestamps = 0;
Packit 96c956
  UTI_ZeroNtp64(&instance->remote_ntp_rx);
Packit 96c956
  UTI_ZeroNtp64(&instance->remote_ntp_tx);
Packit 96c956
  UTI_ZeroNtp64(&instance->local_ntp_rx);
Packit 96c956
  UTI_ZeroNtp64(&instance->local_ntp_tx);
Packit 96c956
  zero_local_timestamp(&instance->local_rx);
Packit 96c956
Packit 96c956
  zero_local_timestamp(&instance->prev_local_tx);
Packit 96c956
  instance->prev_local_poll = 0;
Packit 96c956
  instance->prev_tx_count = 0;
Packit 96c956
Packit 96c956
  instance->updated_init_timestamps = 0;
Packit 96c956
  UTI_ZeroNtp64(&instance->init_remote_ntp_tx);
Packit 96c956
  zero_local_timestamp(&instance->init_local_rx);
Packit 96c956
Packit 96c956
  if (instance->filter)
Packit 96c956
    SPF_DropSamples(instance->filter);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ResetPoll(NCR_Instance instance)
Packit 96c956
{
Packit 96c956
  if (instance->local_poll != instance->minpoll) {
Packit 96c956
    instance->local_poll = instance->minpoll;
Packit 96c956
Packit 96c956
    /* The timer was set with a longer poll interval, restart it */
Packit 96c956
    if (instance->tx_timeout_id)
Packit 96c956
      restart_timeout(instance, get_transmit_delay(instance, 0, 0.0));
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ChangeRemoteAddress(NCR_Instance inst, NTP_Remote_Address *remote_addr)
Packit 96c956
{
Packit 96c956
  memset(&inst->report, 0, sizeof (inst->report));
Packit 96c956
  NCR_ResetInstance(inst);
Packit 96c956
  inst->remote_addr = *remote_addr;
Packit 96c956
Packit 96c956
  if (inst->mode == MODE_CLIENT)
Packit 96c956
    close_client_socket(inst);
Packit 96c956
  else {
Packit 96c956
    NIO_CloseServerSocket(inst->local_addr.sock_fd);
Packit 96c956
    inst->local_addr.ip_addr.family = IPADDR_UNSPEC;
Packit 96c956
    inst->local_addr.if_index = INVALID_IF_INDEX;
Packit 96c956
    inst->local_addr.sock_fd = NIO_OpenServerSocket(remote_addr);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Update the reference ID and reset the source/sourcestats instances */
Packit 96c956
  SRC_SetRefid(inst->source, UTI_IPToRefid(&remote_addr->ip_addr),
Packit 96c956
               &inst->remote_addr.ip_addr);
Packit 96c956
  SRC_ResetInstance(inst->source);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
adjust_poll(NCR_Instance inst, double adj)
Packit 96c956
{
Packit 96c956
  inst->poll_score += adj;
Packit 96c956
Packit 96c956
  if (inst->poll_score >= 1.0) {
Packit 96c956
    inst->local_poll += (int)inst->poll_score;
Packit 96c956
    inst->poll_score -= (int)inst->poll_score;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (inst->poll_score < 0.0) {
Packit 96c956
    inst->local_poll += (int)(inst->poll_score - 1.0);
Packit 96c956
    inst->poll_score -= (int)(inst->poll_score - 1.0);
Packit 96c956
  }
Packit 96c956
  
Packit 96c956
  /* Clamp polling interval to defined range */
Packit 96c956
  if (inst->local_poll < inst->minpoll) {
Packit 96c956
    inst->local_poll = inst->minpoll;
Packit 96c956
    inst->poll_score = 0;
Packit 96c956
  } else if (inst->local_poll > inst->maxpoll) {
Packit 96c956
    inst->local_poll = inst->maxpoll;
Packit 96c956
    inst->poll_score = 1.0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Don't allow a sub-second polling interval if the source is not reachable
Packit 96c956
     or it is not in a local network according to the measured delay */
Packit 96c956
  if (inst->local_poll < MIN_NONLAN_POLL &&
Packit 96c956
      (!SRC_IsReachable(inst->source) ||
Packit 96c956
       SST_MinRoundTripDelay(SRC_GetSourcestats(inst->source)) > MAX_LAN_PEER_DELAY))
Packit 96c956
    inst->local_poll = MIN_NONLAN_POLL;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static double
Packit 96c956
get_poll_adj(NCR_Instance inst, double error_in_estimate, double peer_distance)
Packit 96c956
{
Packit 96c956
  double poll_adj;
Packit 96c956
  int samples;
Packit 96c956
Packit 96c956
  if (error_in_estimate > peer_distance) {
Packit 96c956
    /* If the prediction is not even within +/- the peer distance of the peer,
Packit 96c956
       we are clearly not tracking the peer at all well, so we back off the
Packit 96c956
       sampling rate depending on just how bad the situation is */
Packit 96c956
    poll_adj = -log(error_in_estimate / peer_distance) / log(2.0);
Packit 96c956
  } else {
Packit 96c956
    samples = SST_Samples(SRC_GetSourcestats(inst->source));
Packit 96c956
Packit 96c956
    /* Adjust polling interval so that the number of sourcestats samples
Packit 96c956
       remains close to the target value */
Packit 96c956
    poll_adj = ((double)samples / inst->poll_target - 1.0) / inst->poll_target;
Packit 96c956
Packit 96c956
    /* Make interval shortening quicker */
Packit 96c956
    if (samples < inst->poll_target) {
Packit 96c956
      poll_adj *= 2.0;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
Packit 96c956
  return poll_adj;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
get_transmit_poll(NCR_Instance inst)
Packit 96c956
{
Packit 96c956
  int poll;
Packit 96c956
Packit 96c956
  poll = inst->local_poll;
Packit 96c956
Packit 96c956
  /* In symmetric mode, if the peer is responding, use shorter of the local
Packit 96c956
     and remote poll interval, but not shorter than the minimum */
Packit 96c956
  if (inst->mode == MODE_ACTIVE && poll > inst->remote_poll &&
Packit 96c956
      SRC_IsReachable(inst->source))
Packit 96c956
    poll = MAX(inst->remote_poll, inst->minpoll);
Packit 96c956
Packit 96c956
  return poll;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static double
Packit 96c956
get_transmit_delay(NCR_Instance inst, int on_tx, double last_tx)
Packit 96c956
{
Packit 96c956
  int poll_to_use, stratum_diff;
Packit 96c956
  double delay_time;
Packit 96c956
Packit 96c956
  /* If we're in burst mode, queue for immediate dispatch.
Packit 96c956
Packit 96c956
     If we're operating in client/server mode, queue the timeout for
Packit 96c956
     the poll interval hence.  The fact that a timeout has been queued
Packit 96c956
     in the transmit handler is immaterial - that is only done so that
Packit 96c956
     we at least send something, if no reply is heard.
Packit 96c956
Packit 96c956
     If we're in symmetric mode, we have to take account of the peer's
Packit 96c956
     wishes, otherwise his sampling regime will fall to pieces.  If
Packit 96c956
     we're in client/server mode, we don't care what poll interval the
Packit 96c956
     server responded with last time. */
Packit 96c956
Packit 96c956
  poll_to_use = get_transmit_poll(inst);
Packit 96c956
  delay_time = UTI_Log2ToDouble(poll_to_use);
Packit 96c956
Packit 96c956
  switch (inst->opmode) {
Packit 96c956
    case MD_OFFLINE:
Packit 96c956
      assert(0);
Packit 96c956
      break;
Packit 96c956
    case MD_ONLINE:
Packit 96c956
      switch(inst->mode) {
Packit 96c956
        case MODE_CLIENT:
Packit 96c956
          if (inst->presend_done)
Packit 96c956
            delay_time = WARM_UP_DELAY;
Packit 96c956
          break;
Packit 96c956
Packit 96c956
        case MODE_ACTIVE:
Packit 96c956
          /* If the remote stratum is higher than ours, wait a bit for the next
Packit 96c956
             packet before responding in order to minimize the delay of the
Packit 96c956
             measurement and its error for the peer which has higher stratum.
Packit 96c956
             If the remote stratum is equal to ours, try to interleave packets
Packit 96c956
             evenly with the peer. */
Packit 96c956
          stratum_diff = inst->remote_stratum - REF_GetOurStratum();
Packit 96c956
          if ((stratum_diff > 0 && last_tx * PEER_SAMPLING_ADJ < delay_time) ||
Packit 96c956
              (!on_tx && !stratum_diff &&
Packit 96c956
               last_tx / delay_time > PEER_SAMPLING_ADJ - 0.5))
Packit 96c956
            delay_time *= PEER_SAMPLING_ADJ;
Packit 96c956
Packit 96c956
          /* Substract the already spend time */
Packit 96c956
          if (last_tx > 0.0)
Packit 96c956
            delay_time -= last_tx;
Packit 96c956
          if (delay_time < 0.0)
Packit 96c956
            delay_time = 0.0;
Packit 96c956
Packit 96c956
          break;
Packit 96c956
        default:
Packit 96c956
          assert(0);
Packit 96c956
          break;
Packit 96c956
      }
Packit 96c956
      break;
Packit 96c956
Packit 96c956
    case MD_BURST_WAS_ONLINE:
Packit 96c956
    case MD_BURST_WAS_OFFLINE:
Packit 96c956
      /* Burst modes */
Packit 96c956
      delay_time = MIN(MAX_BURST_INTERVAL, MAX_BURST_POLL_RATIO * delay_time);
Packit 96c956
      break;
Packit 96c956
    default:
Packit 96c956
      assert(0);
Packit 96c956
      break;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  return delay_time;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Calculate sampling separation for given polling interval */
Packit 96c956
Packit 96c956
static double
Packit 96c956
get_separation(int poll)
Packit 96c956
{
Packit 96c956
  double separation;
Packit 96c956
Packit 96c956
  assert(poll >= MIN_POLL && poll <= MAX_POLL);
Packit 96c956
Packit 96c956
  /* Allow up to 8 sources using the same short interval to not be limited
Packit 96c956
     by the separation */
Packit 96c956
  separation = UTI_Log2ToDouble(poll - 3);
Packit 96c956
Packit 96c956
  return CLAMP(MIN_SAMPLING_SEPARATION, separation, MAX_SAMPLING_SEPARATION);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Timeout handler for closing the client socket when no acceptable
Packit 96c956
   reply can be received from the server */
Packit 96c956
Packit 96c956
static void
Packit 96c956
receive_timeout(void *arg)
Packit 96c956
{
Packit 96c956
  NCR_Instance inst = (NCR_Instance)arg;
Packit 96c956
Packit 96c956
  DEBUG_LOG("Receive timeout for [%s:%d]",
Packit 96c956
            UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port);
Packit 96c956
Packit 96c956
  inst->rx_timeout_id = 0;
Packit 96c956
  close_client_socket(inst);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
transmit_packet(NTP_Mode my_mode, /* The mode this machine wants to be */
Packit 96c956
                int interleaved, /* Flag enabling interleaved mode */
Packit 96c956
                int my_poll, /* The log2 of the local poll interval */
Packit 96c956
                int version, /* The NTP version to be set in the packet */
Packit 96c956
                int auth_mode, /* The authentication mode */
Packit 96c956
                uint32_t key_id, /* The authentication key ID */
Packit 96c956
                NTP_int64 *remote_ntp_rx, /* The receive timestamp from received packet */
Packit 96c956
                NTP_int64 *remote_ntp_tx, /* The transmit timestamp from received packet */
Packit 96c956
                NTP_Local_Timestamp *local_rx, /* The RX time of the received packet */
Packit 96c956
                NTP_Local_Timestamp *local_tx, /* The TX time of the previous packet
Packit 96c956
                                                  RESULT : TX time of this packet */
Packit 96c956
                NTP_int64 *local_ntp_rx, /* The receive timestamp from the previous packet
Packit 96c956
                                            RESULT : receive timestamp from this packet */
Packit 96c956
                NTP_int64 *local_ntp_tx, /* The transmit timestamp from the previous packet
Packit 96c956
                                            RESULT : transmit timestamp from this packet */
Packit 96c956
                NTP_Remote_Address *where_to, /* Where to address the reponse to */
Packit 96c956
                NTP_Local_Address *from /* From what address to send it */
Packit 96c956
                )
Packit 96c956
{
Packit 96c956
  NTP_Packet message;
Packit 96c956
  int auth_len, max_auth_len, length, ret, precision;
Packit 96c956
  struct timespec local_receive, local_transmit;
Packit 96c956
  double smooth_offset, local_transmit_err;
Packit 96c956
  NTP_int64 ts_fuzz;
Packit 96c956
Packit 96c956
  /* Parameters read from reference module */
Packit 96c956
  int are_we_synchronised, our_stratum, smooth_time;
Packit 96c956
  NTP_Leap leap_status;
Packit 96c956
  uint32_t our_ref_id;
Packit 96c956
  struct timespec our_ref_time;
Packit 96c956
  double our_root_delay, our_root_dispersion;
Packit 96c956
Packit 96c956
  /* Don't reply with version higher than ours */
Packit 96c956
  if (version > NTP_VERSION) {
Packit 96c956
    version = NTP_VERSION;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Check if the packet can be formed in the interleaved mode */
Packit 96c956
  if (interleaved && (!remote_ntp_rx || !local_tx || UTI_IsZeroTimespec(&local_tx->ts)))
Packit 96c956
    interleaved = 0;
Packit 96c956
Packit 96c956
  smooth_time = 0;
Packit 96c956
  smooth_offset = 0.0;
Packit 96c956
Packit 96c956
  if (my_mode == MODE_CLIENT) {
Packit 96c956
    /* Don't reveal local time or state of the clock in client packets */
Packit 96c956
    precision = 32;
Packit 96c956
    leap_status = our_stratum = our_ref_id = 0;
Packit 96c956
    our_root_delay = our_root_dispersion = 0.0;
Packit 96c956
    UTI_ZeroTimespec(&our_ref_time);
Packit 96c956
  } else {
Packit 96c956
    /* This is accurate enough and cheaper than calling LCL_ReadCookedTime.
Packit 96c956
       A more accurate timestamp will be taken later in this function. */
Packit 96c956
    SCH_GetLastEventTime(&local_transmit, NULL, NULL);
Packit 96c956
Packit 96c956
    REF_GetReferenceParams(&local_transmit,
Packit 96c956
                           &are_we_synchronised, &leap_status,
Packit 96c956
                           &our_stratum,
Packit 96c956
                           &our_ref_id, &our_ref_time,
Packit 96c956
                           &our_root_delay, &our_root_dispersion);
Packit 96c956
Packit 96c956
    /* Get current smoothing offset when sending packet to a client */
Packit 96c956
    if (SMT_IsEnabled() && (my_mode == MODE_SERVER || my_mode == MODE_BROADCAST)) {
Packit 96c956
      smooth_offset = SMT_GetOffset(&local_transmit);
Packit 96c956
      smooth_time = fabs(smooth_offset) > LCL_GetSysPrecisionAsQuantum();
Packit 96c956
Packit 96c956
      /* Suppress leap second when smoothing and slew mode are enabled */
Packit 96c956
      if (REF_GetLeapMode() == REF_LeapModeSlew &&
Packit 96c956
          (leap_status == LEAP_InsertSecond || leap_status == LEAP_DeleteSecond))
Packit 96c956
        leap_status = LEAP_Normal;
Packit 96c956
    }
Packit 96c956
Packit 96c956
    precision = LCL_GetSysPrecisionAsLog();
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (smooth_time && !UTI_IsZeroTimespec(&local_rx->ts)) {
Packit 96c956
    our_ref_id = NTP_REFID_SMOOTH;
Packit 96c956
    UTI_AddDoubleToTimespec(&our_ref_time, smooth_offset, &our_ref_time);
Packit 96c956
    UTI_AddDoubleToTimespec(&local_rx->ts, smooth_offset, &local_receive);
Packit 96c956
  } else {
Packit 96c956
    local_receive = local_rx->ts;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Generate transmit packet */
Packit 96c956
  message.lvm = NTP_LVM(leap_status, version, my_mode);
Packit 96c956
  /* Stratum 16 and larger are invalid */
Packit 96c956
  if (our_stratum < NTP_MAX_STRATUM) {
Packit 96c956
    message.stratum = our_stratum;
Packit 96c956
  } else {
Packit 96c956
    message.stratum = NTP_INVALID_STRATUM;
Packit 96c956
  }
Packit 96c956
 
Packit 96c956
  message.poll = my_poll;
Packit 96c956
  message.precision = precision;
Packit 96c956
Packit 96c956
  /* If we're sending a client mode packet and we aren't synchronized yet, 
Packit 96c956
     we might have to set up artificial values for some of these parameters */
Packit 96c956
  message.root_delay = UTI_DoubleToNtp32(our_root_delay);
Packit 96c956
  message.root_dispersion = UTI_DoubleToNtp32(our_root_dispersion);
Packit 96c956
Packit 96c956
  message.reference_id = htonl(our_ref_id);
Packit 96c956
Packit 96c956
  /* Now fill in timestamps */
Packit 96c956
Packit 96c956
  UTI_TimespecToNtp64(&our_ref_time, &message.reference_ts, NULL);
Packit 96c956
Packit 96c956
  /* Don't reveal timestamps which are not necessary for the protocol */
Packit 96c956
Packit 96c956
  if (my_mode != MODE_CLIENT || interleaved) {
Packit 96c956
    /* Originate - this comes from the last packet the source sent us */
Packit 96c956
    message.originate_ts = interleaved ? *remote_ntp_rx : *remote_ntp_tx;
Packit 96c956
Packit 96c956
    do {
Packit 96c956
      /* Prepare random bits which will be added to the receive timestamp */
Packit 96c956
      UTI_GetNtp64Fuzz(&ts_fuzz, precision);
Packit 96c956
Packit 96c956
      /* Receive - this is when we received the last packet from the source.
Packit 96c956
         This timestamp will have been adjusted so that it will now look to
Packit 96c956
         the source like we have been running on our latest estimate of
Packit 96c956
         frequency all along */
Packit 96c956
      UTI_TimespecToNtp64(&local_receive, &message.receive_ts, &ts_fuzz);
Packit 96c956
Packit 96c956
      /* Do not send a packet with a non-zero receive timestamp equal to the
Packit 96c956
         originate timestamp or previous receive timestamp */
Packit 96c956
    } while (!UTI_IsZeroNtp64(&message.receive_ts) &&
Packit 96c956
             UTI_IsEqualAnyNtp64(&message.receive_ts, &message.originate_ts,
Packit 96c956
                                 local_ntp_rx, NULL));
Packit 96c956
  } else {
Packit 96c956
    UTI_ZeroNtp64(&message.originate_ts);
Packit 96c956
    UTI_ZeroNtp64(&message.receive_ts);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  do {
Packit 96c956
    /* Prepare random bits which will be added to the transmit timestamp */
Packit 96c956
    UTI_GetNtp64Fuzz(&ts_fuzz, precision);
Packit 96c956
Packit 96c956
    /* Transmit - this our local time right now!  Also, we might need to
Packit 96c956
       store this for our own use later, next time we receive a message
Packit 96c956
       from the source we're sending to now. */
Packit 96c956
    LCL_ReadCookedTime(&local_transmit, &local_transmit_err);
Packit 96c956
Packit 96c956
    if (smooth_time)
Packit 96c956
      UTI_AddDoubleToTimespec(&local_transmit, smooth_offset, &local_transmit);
Packit 96c956
Packit 96c956
    length = NTP_NORMAL_PACKET_LENGTH;
Packit 96c956
Packit 96c956
    /* Authenticate the packet */
Packit 96c956
Packit 96c956
    if (auth_mode == AUTH_SYMMETRIC || auth_mode == AUTH_MSSNTP) {
Packit 96c956
      /* Pre-compensate the transmit time by approximately how long it will
Packit 96c956
         take to generate the authentication data */
Packit 96c956
      local_transmit.tv_nsec += auth_mode == AUTH_SYMMETRIC ?
Packit 96c956
                                KEY_GetAuthDelay(key_id) : NSD_GetAuthDelay(key_id);
Packit 96c956
      UTI_NormaliseTimespec(&local_transmit);
Packit 96c956
      UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
Packit 96c956
                          &message.transmit_ts, &ts_fuzz);
Packit 96c956
Packit 96c956
      if (auth_mode == AUTH_SYMMETRIC) {
Packit 96c956
        /* Truncate long MACs in NTPv4 packets to allow deterministic parsing
Packit 96c956
           of extension fields (RFC 7822) */
Packit 96c956
        max_auth_len = version == 4 ?
Packit 96c956
                       NTP_MAX_V4_MAC_LENGTH - 4 : sizeof (message.auth_data);
Packit 96c956
Packit 96c956
        auth_len = KEY_GenerateAuth(key_id, (unsigned char *) &message,
Packit 96c956
                                    offsetof(NTP_Packet, auth_keyid),
Packit 96c956
                                    (unsigned char *)&message.auth_data, max_auth_len);
Packit 96c956
        if (!auth_len) {
Packit 96c956
          DEBUG_LOG("Could not generate auth data with key %"PRIu32, key_id);
Packit 96c956
          return 0;
Packit 96c956
        }
Packit 96c956
Packit 96c956
        message.auth_keyid = htonl(key_id);
Packit 96c956
        length += sizeof (message.auth_keyid) + auth_len;
Packit 96c956
      } else if (auth_mode == AUTH_MSSNTP) {
Packit 96c956
        /* MS-SNTP packets are signed (asynchronously) by ntp_signd */
Packit 96c956
        return NSD_SignAndSendPacket(key_id, &message, where_to, from, length);
Packit 96c956
      }
Packit 96c956
    } else {
Packit 96c956
      UTI_TimespecToNtp64(interleaved ? &local_tx->ts : &local_transmit,
Packit 96c956
                          &message.transmit_ts, &ts_fuzz);
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* Do not send a packet with a non-zero transmit timestamp which is
Packit 96c956
       equal to any of the following timestamps:
Packit 96c956
       - receive (to allow reliable detection of the interleaved mode)
Packit 96c956
       - originate (to prevent the packet from being its own valid response
Packit 96c956
                    in the symmetric mode)
Packit 96c956
       - previous transmit (to invalidate responses to the previous packet)
Packit 96c956
       (the precision must be at least -30 to prevent an infinite loop!) */
Packit 96c956
  } while (!UTI_IsZeroNtp64(&message.transmit_ts) &&
Packit 96c956
           UTI_IsEqualAnyNtp64(&message.transmit_ts, &message.receive_ts,
Packit 96c956
                               &message.originate_ts, local_ntp_tx));
Packit 96c956
Packit 96c956
  ret = NIO_SendPacket(&message, where_to, from, length, local_tx != NULL);
Packit 96c956
Packit 96c956
  if (local_tx) {
Packit 96c956
    local_tx->ts = local_transmit;
Packit 96c956
    local_tx->err = local_transmit_err;
Packit 96c956
    local_tx->source = NTP_TS_DAEMON;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (local_ntp_rx)
Packit 96c956
    *local_ntp_rx = message.receive_ts;
Packit 96c956
  if (local_ntp_tx)
Packit 96c956
    *local_ntp_tx = message.transmit_ts;
Packit 96c956
Packit 96c956
  return ret;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* Timeout handler for transmitting to a source. */
Packit 96c956
Packit 96c956
static void
Packit 96c956
transmit_timeout(void *arg)
Packit 96c956
{
Packit 96c956
  NCR_Instance inst = (NCR_Instance) arg;
Packit 96c956
  NTP_Local_Address local_addr;
Packit 96c956
  int interleaved, initial, sent;
Packit 96c956
Packit 96c956
  inst->tx_timeout_id = 0;
Packit 96c956
Packit 96c956
  switch (inst->opmode) {
Packit 96c956
    case MD_BURST_WAS_ONLINE:
Packit 96c956
      /* With online burst switch to online before last packet */
Packit 96c956
      if (inst->burst_total_samples_to_go <= 1)
Packit 96c956
        inst->opmode = MD_ONLINE;
Packit 96c956
      break;
Packit 96c956
    case MD_BURST_WAS_OFFLINE:
Packit 96c956
      if (inst->burst_total_samples_to_go <= 0)
Packit 96c956
        take_offline(inst);
Packit 96c956
      break;
Packit 96c956
    case MD_ONLINE:
Packit 96c956
      /* Start a new burst if the burst option is enabled and the average
Packit 96c956
         polling interval including the burst will not fall below the
Packit 96c956
         minimum polling interval */
Packit 96c956
      if (inst->auto_burst && inst->local_poll > inst->minpoll)
Packit 96c956
        NCR_InitiateSampleBurst(inst, BURST_GOOD_SAMPLES,
Packit 96c956
                                MIN(1 << (inst->local_poll - inst->minpoll),
Packit 96c956
                                    MAX_BURST_TOTAL_SAMPLES));
Packit 96c956
      break;
Packit 96c956
    default:
Packit 96c956
      break;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (inst->opmode == MD_OFFLINE) {
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  DEBUG_LOG("Transmit timeout for [%s:%d]",
Packit 96c956
      UTI_IPToString(&inst->remote_addr.ip_addr), inst->remote_addr.port);
Packit 96c956
Packit 96c956
  /* Open new client socket */
Packit 96c956
  if (inst->mode == MODE_CLIENT) {
Packit 96c956
    close_client_socket(inst);
Packit 96c956
    assert(inst->local_addr.sock_fd == INVALID_SOCK_FD);
Packit 96c956
    inst->local_addr.sock_fd = NIO_OpenClientSocket(&inst->remote_addr);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Don't require the packet to be sent from the same address as before */
Packit 96c956
  local_addr.ip_addr.family = IPADDR_UNSPEC;
Packit 96c956
  local_addr.if_index = INVALID_IF_INDEX;
Packit 96c956
  local_addr.sock_fd = inst->local_addr.sock_fd;
Packit 96c956
Packit 96c956
  /* In symmetric mode, don't send a packet in interleaved mode unless it
Packit 96c956
     is the first response to the last valid request received from the peer
Packit 96c956
     and there was just one response to the previous valid request.  This
Packit 96c956
     prevents the peer from matching the transmit timestamp with an older
Packit 96c956
     response if it can't detect missed responses.  In client mode, which has
Packit 96c956
     at most one response per request, check how many responses are missing to
Packit 96c956
     prevent the server from responding with a very old transmit timestamp. */
Packit 96c956
  interleaved = inst->interleaved &&
Packit 96c956
                ((inst->mode == MODE_CLIENT &&
Packit 96c956
                  inst->tx_count < MAX_CLIENT_INTERLEAVED_TX) ||
Packit 96c956
                 (inst->mode == MODE_ACTIVE &&
Packit 96c956
                  inst->prev_tx_count == 1 && inst->tx_count == 0));
Packit 96c956
Packit 96c956
  /* In symmetric mode, if no valid response was received since the previous
Packit 96c956
     transmission, respond to the last received packet even if it failed some
Packit 96c956
     specific NTP tests.  This is necessary for starting and restarting the
Packit 96c956
     protocol, e.g. when a packet was lost. */
Packit 96c956
  initial = inst->mode == MODE_ACTIVE && !inst->valid_rx &&
Packit 96c956
            !UTI_IsZeroNtp64(&inst->init_remote_ntp_tx);
Packit 96c956
Packit 96c956
  /* Prepare for the response */
Packit 96c956
  inst->valid_rx = 0;
Packit 96c956
  inst->updated_init_timestamps = 0;
Packit 96c956
  if (initial)
Packit 96c956
    inst->valid_timestamps = 0;
Packit 96c956
Packit 96c956
  /* Check whether we need to 'warm up' the link to the other end by
Packit 96c956
     sending an NTP exchange to ensure both ends' ARP caches are
Packit 96c956
     primed or whether we need to send two packets first to ensure a
Packit 96c956
     server in the interleaved mode has a fresh timestamp for us. */
Packit 96c956
  if (inst->presend_minpoll <= inst->local_poll && !inst->presend_done &&
Packit 96c956
      !inst->burst_total_samples_to_go) {
Packit 96c956
    inst->presend_done = interleaved ? 2 : 1;
Packit 96c956
  } else if (inst->presend_done > 0) {
Packit 96c956
    inst->presend_done--;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Send the request (which may also be a response in the symmetric mode) */
Packit 96c956
  sent = transmit_packet(inst->mode, interleaved, inst->local_poll, inst->version,
Packit 96c956
                         inst->auth_mode, inst->auth_key_id,
Packit 96c956
                         initial ? NULL : &inst->remote_ntp_rx,
Packit 96c956
                         initial ? &inst->init_remote_ntp_tx : &inst->remote_ntp_tx,
Packit 96c956
                         initial ? &inst->init_local_rx : &inst->local_rx,
Packit 96c956
                         &inst->local_tx, &inst->local_ntp_rx, &inst->local_ntp_tx,
Packit 96c956
                         &inst->remote_addr, &local_addr);
Packit 96c956
Packit 96c956
  ++inst->tx_count;
Packit 96c956
  if (sent)
Packit 96c956
    inst->report.total_tx_count++;
Packit 96c956
Packit 96c956
  /* If the source loses connectivity and our packets are still being sent,
Packit 96c956
     back off the sampling rate to reduce the network traffic.  If it's the
Packit 96c956
     source to which we are currently locked, back off slowly. */
Packit 96c956
Packit 96c956
  if (inst->tx_count >= 2) {
Packit 96c956
    /* Implies we have missed at least one transmission */
Packit 96c956
Packit 96c956
    if (sent) {
Packit 96c956
      adjust_poll(inst, SRC_IsSyncPeer(inst->source) ? 0.1 : 0.25);
Packit 96c956
    }
Packit 96c956
Packit 96c956
    SRC_UpdateReachability(inst->source, 0);
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* With auto_offline take the source offline if sending failed */
Packit 96c956
  if (!sent && inst->auto_offline)
Packit 96c956
    NCR_SetConnectivity(inst, SRC_OFFLINE);
Packit 96c956
Packit 96c956
  switch (inst->opmode) {
Packit 96c956
    case MD_BURST_WAS_ONLINE:
Packit 96c956
      /* When not reachable, don't stop online burst until sending succeeds */
Packit 96c956
      if (!sent && !SRC_IsReachable(inst->source))
Packit 96c956
        break;
Packit 96c956
      /* Fall through */
Packit 96c956
    case MD_BURST_WAS_OFFLINE:
Packit 96c956
      --inst->burst_total_samples_to_go;
Packit 96c956
      break;
Packit 96c956
    case MD_OFFLINE:
Packit 96c956
      return;
Packit 96c956
    default:
Packit 96c956
      break;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Restart timer for this message */
Packit 96c956
  restart_timeout(inst, get_transmit_delay(inst, 1, 0.0));
Packit 96c956
Packit 96c956
  /* If a client packet was just sent, schedule a timeout to close the socket
Packit 96c956
     at the time when all server replies would fail the delay test, so the
Packit 96c956
     socket is not open for longer than necessary */
Packit 96c956
  if (inst->mode == MODE_CLIENT)
Packit 96c956
    inst->rx_timeout_id = SCH_AddTimeoutByDelay(inst->max_delay + MAX_SERVER_INTERVAL,
Packit 96c956
                                                receive_timeout, (void *)inst);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
check_packet_format(NTP_Packet *message, int length)
Packit 96c956
{
Packit 96c956
  int version;
Packit 96c956
Packit 96c956
  /* Check version and length */
Packit 96c956
Packit 96c956
  version = NTP_LVM_TO_VERSION(message->lvm);
Packit 96c956
  if (version < NTP_MIN_COMPAT_VERSION || version > NTP_MAX_COMPAT_VERSION) {
Packit 96c956
    DEBUG_LOG("NTP packet has invalid version %d", version);
Packit 96c956
    return 0;
Packit 96c956
  } 
Packit 96c956
Packit 96c956
  if (length < NTP_NORMAL_PACKET_LENGTH || (unsigned int)length % 4) {
Packit 96c956
    DEBUG_LOG("NTP packet has invalid length %d", length);
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* We can't reliably check the packet for invalid extension fields as we
Packit 96c956
     support MACs longer than the shortest valid extension field */
Packit 96c956
Packit 96c956
  return 1;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
is_zero_data(unsigned char *data, int length)
Packit 96c956
{
Packit 96c956
  int i;
Packit 96c956
Packit 96c956
  for (i = 0; i < length; i++)
Packit 96c956
    if (data[i])
Packit 96c956
      return 0;
Packit 96c956
  return 1;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
check_packet_auth(NTP_Packet *pkt, int length,
Packit 96c956
                  AuthenticationMode *auth_mode, uint32_t *key_id)
Packit 96c956
{
Packit 96c956
  int i, version, remainder, ext_length, max_mac_length;
Packit 96c956
  unsigned char *data;
Packit 96c956
  uint32_t id;
Packit 96c956
Packit 96c956
  /* Go through extension fields and see if there is a valid MAC */
Packit 96c956
Packit 96c956
  version = NTP_LVM_TO_VERSION(pkt->lvm);
Packit 96c956
  i = NTP_NORMAL_PACKET_LENGTH;
Packit 96c956
  data = (void *)pkt;
Packit 96c956
Packit 96c956
  while (1) {
Packit 96c956
    remainder = length - i;
Packit 96c956
Packit 96c956
    /* Check if the remaining data is a valid MAC.  There is a limit on MAC
Packit 96c956
       length in NTPv4 packets to allow deterministic parsing of extension
Packit 96c956
       fields (RFC 7822), but we need to support longer MACs to not break
Packit 96c956
       compatibility with older chrony clients.  This needs to be done before
Packit 96c956
       trying to parse the data as an extension field. */
Packit 96c956
Packit 96c956
    max_mac_length = version == 4 && remainder <= NTP_MAX_V4_MAC_LENGTH ?
Packit 96c956
                     NTP_MAX_V4_MAC_LENGTH : NTP_MAX_MAC_LENGTH;
Packit 96c956
Packit 96c956
    if (remainder >= NTP_MIN_MAC_LENGTH && remainder <= max_mac_length) {
Packit 96c956
      id = ntohl(*(uint32_t *)(data + i));
Packit 96c956
      if (KEY_CheckAuth(id, (void *)pkt, i, (void *)(data + i + 4),
Packit 96c956
                        remainder - 4, max_mac_length - 4)) {
Packit 96c956
        *auth_mode = AUTH_SYMMETRIC;
Packit 96c956
        *key_id = id;
Packit 96c956
Packit 96c956
        /* If it's an NTPv4 packet with long MAC and no extension fields,
Packit 96c956
           rewrite the version in the packet to respond with long MAC too */
Packit 96c956
        if (version == 4 && NTP_NORMAL_PACKET_LENGTH + remainder == length &&
Packit 96c956
            remainder > NTP_MAX_V4_MAC_LENGTH)
Packit 96c956
          pkt->lvm = NTP_LVM(NTP_LVM_TO_LEAP(pkt->lvm), 3, NTP_LVM_TO_MODE(pkt->lvm));
Packit 96c956
Packit 96c956
        return 1;
Packit 96c956
      }
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* Check if this is a valid NTPv4 extension field and skip it.  It should
Packit 96c956
       have a 16-bit type, 16-bit length, and data padded to 32 bits. */
Packit 96c956
    if (version == 4 && remainder >= NTP_MIN_EXTENSION_LENGTH) {
Packit 96c956
      ext_length = ntohs(*(uint16_t *)(data + i + 2));
Packit 96c956
      if (ext_length >= NTP_MIN_EXTENSION_LENGTH &&
Packit 96c956
          ext_length <= remainder && ext_length % 4 == 0) {
Packit 96c956
        i += ext_length;
Packit 96c956
        continue;
Packit 96c956
      }
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* Invalid or missing MAC, or format error */
Packit 96c956
    break;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* This is not 100% reliable as a MAC could fail to authenticate and could
Packit 96c956
     pass as an extension field, leaving reminder smaller than the minimum MAC
Packit 96c956
     length */
Packit 96c956
  if (remainder >= NTP_MIN_MAC_LENGTH) {
Packit 96c956
    *auth_mode = AUTH_SYMMETRIC;
Packit 96c956
    *key_id = ntohl(*(uint32_t *)(data + i));
Packit 96c956
Packit 96c956
    /* Check if it is an MS-SNTP authenticator field or extended authenticator
Packit 96c956
       field with zeroes as digest */
Packit 96c956
    if (version == 3 && *key_id) {
Packit 96c956
      if (remainder == 20 && is_zero_data(data + i + 4, remainder - 4))
Packit 96c956
        *auth_mode = AUTH_MSSNTP;
Packit 96c956
      else if (remainder == 72 && is_zero_data(data + i + 8, remainder - 8))
Packit 96c956
        *auth_mode = AUTH_MSSNTP_EXT;
Packit 96c956
    }
Packit 96c956
  } else {
Packit 96c956
    *auth_mode = AUTH_NONE;
Packit 96c956
    *key_id = 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  return 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
check_delay_ratio(NCR_Instance inst, SST_Stats stats,
Packit 96c956
                struct timespec *sample_time, double delay)
Packit 96c956
{
Packit 96c956
  double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
Packit 96c956
  double max_delay;
Packit 96c956
Packit 96c956
  if (inst->max_delay_ratio < 1.0 ||
Packit 96c956
      !SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
Packit 96c956
                            &predicted_offset, &min_delay, &skew, &std_dev))
Packit 96c956
    return 1;
Packit 96c956
Packit 96c956
  max_delay = min_delay * inst->max_delay_ratio +
Packit 96c956
              last_sample_ago * (skew + LCL_GetMaxClockError());
Packit 96c956
Packit 96c956
  if (delay <= max_delay)
Packit 96c956
    return 1;
Packit 96c956
Packit 96c956
  DEBUG_LOG("maxdelayratio: delay=%e max_delay=%e", delay, max_delay);
Packit 96c956
  return 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
check_delay_dev_ratio(NCR_Instance inst, SST_Stats stats,
Packit 96c956
                      struct timespec *sample_time, double offset, double delay)
Packit 96c956
{
Packit 96c956
  double last_sample_ago, predicted_offset, min_delay, skew, std_dev;
Packit 96c956
  double delta, max_delta, error_in_estimate;
Packit 96c956
Packit 96c956
  if (!SST_GetDelayTestData(stats, sample_time, &last_sample_ago,
Packit 96c956
                            &predicted_offset, &min_delay, &skew, &std_dev))
Packit 96c956
    return 1;
Packit 96c956
Packit 96c956
  /* Require that the ratio of the increase in delay from the minimum to the
Packit 96c956
     standard deviation is less than max_delay_dev_ratio.  In the allowed
Packit 96c956
     increase in delay include also dispersion. */
Packit 96c956
Packit 96c956
  max_delta = std_dev * inst->max_delay_dev_ratio +
Packit 96c956
              last_sample_ago * (skew + LCL_GetMaxClockError());
Packit 96c956
  delta = (delay - min_delay) / 2.0;
Packit 96c956
Packit 96c956
  if (delta <= max_delta)
Packit 96c956
    return 1;
Packit 96c956
Packit 96c956
  error_in_estimate = offset + predicted_offset;
Packit 96c956
Packit 96c956
  /* Before we decide to drop the sample, make sure the difference between
Packit 96c956
     measured offset and predicted offset is not significantly larger than
Packit 96c956
     the increase in delay */
Packit 96c956
  if (fabs(error_in_estimate) - delta > max_delta)
Packit 96c956
    return 1;
Packit 96c956
Packit 96c956
  DEBUG_LOG("maxdelaydevratio: error=%e delay=%e delta=%e max_delta=%e",
Packit 96c956
            error_in_estimate, delay, delta, max_delta);
Packit 96c956
  return 0;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
process_sample(NCR_Instance inst, NTP_Sample *sample)
Packit 96c956
{
Packit 96c956
  double estimated_offset, error_in_estimate, filtered_sample_ago;
Packit 96c956
  NTP_Sample filtered_sample;
Packit 96c956
  int filtered_samples;
Packit 96c956
Packit 96c956
  /* Accumulate the sample to the median filter if it is enabled.  When the
Packit 96c956
     filter produces a result, check if it is not too old, i.e. the filter did
Packit 96c956
     not miss too many samples due to missing responses or failing tests. */
Packit 96c956
  if (inst->filter) {
Packit 96c956
    SPF_AccumulateSample(inst->filter, sample);
Packit 96c956
Packit 96c956
    filtered_samples = SPF_GetNumberOfSamples(inst->filter);
Packit 96c956
Packit 96c956
    if (!SPF_GetFilteredSample(inst->filter, &filtered_sample))
Packit 96c956
      return;
Packit 96c956
Packit 96c956
    filtered_sample_ago = UTI_DiffTimespecsToDouble(&sample->time, &filtered_sample.time);
Packit 96c956
Packit 96c956
    if (filtered_sample_ago > SOURCE_REACH_BITS / 2 * filtered_samples *
Packit 96c956
                              UTI_Log2ToDouble(inst->local_poll)) {
Packit 96c956
      DEBUG_LOG("filtered sample dropped ago=%f poll=%d", filtered_sample_ago,
Packit 96c956
                inst->local_poll);
Packit 96c956
      return;
Packit 96c956
    }
Packit 96c956
Packit 96c956
    sample = &filtered_sample;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Get the estimated offset predicted from previous samples.  The
Packit 96c956
     convention here is that positive means local clock FAST of
Packit 96c956
     reference, i.e. backwards to the way that 'offset' is defined. */
Packit 96c956
  estimated_offset = SST_PredictOffset(SRC_GetSourcestats(inst->source), &sample->time);
Packit 96c956
Packit 96c956
  error_in_estimate = fabs(-sample->offset - estimated_offset);
Packit 96c956
Packit 96c956
  SRC_AccumulateSample(inst->source, sample);
Packit 96c956
  SRC_SelectSource(inst->source);
Packit 96c956
Packit 96c956
  adjust_poll(inst, get_poll_adj(inst, error_in_estimate,
Packit 96c956
                                 sample->peer_dispersion + 0.5 * sample->peer_delay));
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static int
Packit 96c956
receive_packet(NCR_Instance inst, NTP_Local_Address *local_addr,
Packit 96c956
               NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
Packit 96c956
{
Packit 96c956
  NTP_Sample sample;
Packit 96c956
  SST_Stats stats;
Packit 96c956
Packit 96c956
  int pkt_leap, pkt_version;
Packit 96c956
  uint32_t pkt_refid, pkt_key_id;
Packit 96c956
  double pkt_root_delay;
Packit 96c956
  double pkt_root_dispersion;
Packit 96c956
  AuthenticationMode pkt_auth_mode;
Packit 96c956
Packit 96c956
  /* The skew and estimated frequency offset relative to the remote source */
Packit 96c956
  double skew, source_freq_lo, source_freq_hi;
Packit 96c956
Packit 96c956
  /* RFC 5905 packet tests */
Packit 96c956
  int test1, test2n, test2i, test2, test3, test5, test6, test7;
Packit 96c956
  int interleaved_packet, valid_packet, synced_packet;
Packit 96c956
Packit 96c956
  /* Additional tests */
Packit 96c956
  int testA, testB, testC, testD;
Packit 96c956
  int good_packet;
Packit 96c956
Packit 96c956
  /* Kiss-o'-Death codes */
Packit 96c956
  int kod_rate;
Packit 96c956
Packit 96c956
  NTP_Local_Timestamp local_receive, local_transmit;
Packit 96c956
  double remote_interval, local_interval, response_time;
Packit 96c956
  double delay_time, precision;
Packit 96c956
  int updated_timestamps;
Packit 96c956
Packit 96c956
  /* ==================== */
Packit 96c956
Packit 96c956
  stats = SRC_GetSourcestats(inst->source);
Packit 96c956
Packit 96c956
  inst->report.total_rx_count++;
Packit 96c956
Packit 96c956
  pkt_leap = NTP_LVM_TO_LEAP(message->lvm);
Packit 96c956
  pkt_version = NTP_LVM_TO_VERSION(message->lvm);
Packit 96c956
  pkt_refid = ntohl(message->reference_id);
Packit 96c956
  pkt_root_delay = UTI_Ntp32ToDouble(message->root_delay);
Packit 96c956
  pkt_root_dispersion = UTI_Ntp32ToDouble(message->root_dispersion);
Packit 96c956
Packit 96c956
  /* Check if the packet is valid per RFC 5905, section 8.
Packit 96c956
     The test values are 1 when passed and 0 when failed. */
Packit 96c956
  
Packit 96c956
  /* Test 1 checks for duplicate packet */
Packit 96c956
  test1 = UTI_CompareNtp64(&message->receive_ts, &inst->remote_ntp_rx) ||
Packit 96c956
          UTI_CompareNtp64(&message->transmit_ts, &inst->remote_ntp_tx);
Packit 96c956
Packit 96c956
  /* Test 2 checks for bogus packet in the basic and interleaved modes.  This
Packit 96c956
     ensures the source is responding to the latest packet we sent to it. */
Packit 96c956
  test2n = !UTI_CompareNtp64(&message->originate_ts, &inst->local_ntp_tx);
Packit 96c956
  test2i = inst->interleaved &&
Packit 96c956
           !UTI_CompareNtp64(&message->originate_ts, &inst->local_ntp_rx);
Packit 96c956
  test2 = test2n || test2i;
Packit 96c956
  interleaved_packet = !test2n && test2i;
Packit 96c956
  
Packit 96c956
  /* Test 3 checks for invalid timestamps.  This can happen when the
Packit 96c956
     association if not properly 'up'. */
Packit 96c956
  test3 = !UTI_IsZeroNtp64(&message->originate_ts) &&
Packit 96c956
          !UTI_IsZeroNtp64(&message->receive_ts) &&
Packit 96c956
          !UTI_IsZeroNtp64(&message->transmit_ts);
Packit 96c956
Packit 96c956
  /* Test 4 would check for denied access.  It would always pass as this
Packit 96c956
     function is called only for known sources. */
Packit 96c956
Packit 96c956
  /* Test 5 checks for authentication failure.  If we expect authenticated info
Packit 96c956
     from this peer/server and the packet doesn't have it, the authentication
Packit 96c956
     is bad, or it's authenticated with a different key than expected, it's got
Packit 96c956
     to fail.  If we don't expect the packet to be authenticated, just ignore
Packit 96c956
     the test. */
Packit 96c956
  test5 = inst->auth_mode == AUTH_NONE ||
Packit 96c956
          (check_packet_auth(message, length, &pkt_auth_mode, &pkt_key_id) &&
Packit 96c956
           pkt_auth_mode == inst->auth_mode && pkt_key_id == inst->auth_key_id);
Packit 96c956
Packit 96c956
  /* Test 6 checks for unsynchronised server */
Packit 96c956
  test6 = pkt_leap != LEAP_Unsynchronised &&
Packit 96c956
          message->stratum < NTP_MAX_STRATUM &&
Packit 96c956
          message->stratum != NTP_INVALID_STRATUM; 
Packit 96c956
Packit 96c956
  /* Test 7 checks for bad data.  The root distance must be smaller than a
Packit 96c956
     defined maximum. */
Packit 96c956
  test7 = pkt_root_delay / 2.0 + pkt_root_dispersion < NTP_MAX_DISPERSION;
Packit 96c956
Packit 96c956
  /* The packet is considered valid if the tests 1-5 passed.  The timestamps
Packit 96c956
     can be used for synchronisation if the tests 6 and 7 passed too. */
Packit 96c956
  valid_packet = test1 && test2 && test3 && test5;
Packit 96c956
  synced_packet = valid_packet && test6 && test7;
Packit 96c956
Packit 96c956
  /* Check for Kiss-o'-Death codes */
Packit 96c956
  kod_rate = 0;
Packit 96c956
  if (test1 && test2 && test5 && pkt_leap == LEAP_Unsynchronised &&
Packit 96c956
      message->stratum == NTP_INVALID_STRATUM) {
Packit 96c956
    if (pkt_refid == KOD_RATE)
Packit 96c956
      kod_rate = 1;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (synced_packet && (!interleaved_packet || inst->valid_timestamps)) {
Packit 96c956
    /* These are the timespec equivalents of the remote and local epochs */
Packit 96c956
    struct timespec remote_receive, remote_transmit, remote_request_receive;
Packit 96c956
    struct timespec local_average, remote_average, prev_remote_transmit;
Packit 96c956
    double prev_remote_poll_interval;
Packit 96c956
Packit 96c956
    /* Select remote and local timestamps for the new sample */
Packit 96c956
    if (interleaved_packet) {
Packit 96c956
      /* Prefer previous local TX and remote RX timestamps if it will make
Packit 96c956
         the intervals significantly shorter in order to improve the accuracy
Packit 96c956
         of the measured delay */
Packit 96c956
      if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts) &&
Packit 96c956
          MAX_INTERLEAVED_L2L_RATIO *
Packit 96c956
            UTI_DiffTimespecsToDouble(&inst->local_tx.ts, &inst->local_rx.ts) >
Packit 96c956
          UTI_DiffTimespecsToDouble(&inst->local_rx.ts, &inst->prev_local_tx.ts)) {
Packit 96c956
        UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_receive);
Packit 96c956
        remote_request_receive = remote_receive;
Packit 96c956
        local_transmit = inst->prev_local_tx;
Packit 96c956
      } else {
Packit 96c956
        UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
Packit 96c956
        UTI_Ntp64ToTimespec(&inst->remote_ntp_rx, &remote_request_receive);
Packit 96c956
        local_transmit = inst->local_tx;
Packit 96c956
      }
Packit 96c956
      UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
Packit 96c956
      UTI_Ntp64ToTimespec(&inst->remote_ntp_tx, &prev_remote_transmit);
Packit 96c956
      local_receive = inst->local_rx;
Packit 96c956
    } else {
Packit 96c956
      UTI_Ntp64ToTimespec(&message->receive_ts, &remote_receive);
Packit 96c956
      UTI_Ntp64ToTimespec(&message->transmit_ts, &remote_transmit);
Packit 96c956
      UTI_ZeroTimespec(&prev_remote_transmit);
Packit 96c956
      remote_request_receive = remote_receive;
Packit 96c956
      local_receive = *rx_ts;
Packit 96c956
      local_transmit = inst->local_tx;
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* Calculate intervals between remote and local timestamps */
Packit 96c956
    UTI_AverageDiffTimespecs(&remote_receive, &remote_transmit,
Packit 96c956
                             &remote_average, &remote_interval);
Packit 96c956
    UTI_AverageDiffTimespecs(&local_transmit.ts, &local_receive.ts,
Packit 96c956
                             &local_average, &local_interval);
Packit 96c956
    response_time = fabs(UTI_DiffTimespecsToDouble(&remote_transmit,
Packit 96c956
                                                   &remote_request_receive));
Packit 96c956
Packit 96c956
    precision = LCL_GetSysPrecisionAsQuantum() + UTI_Log2ToDouble(message->precision);
Packit 96c956
Packit 96c956
    /* Calculate delay */
Packit 96c956
    sample.peer_delay = fabs(local_interval - remote_interval);
Packit 96c956
    if (sample.peer_delay < precision)
Packit 96c956
      sample.peer_delay = precision;
Packit 96c956
    
Packit 96c956
    /* Calculate offset.  Following the NTP definition, this is negative
Packit 96c956
       if we are fast of the remote source. */
Packit 96c956
    sample.offset = UTI_DiffTimespecsToDouble(&remote_average, &local_average);
Packit 96c956
Packit 96c956
    /* Apply configured correction */
Packit 96c956
    sample.offset += inst->offset_correction;
Packit 96c956
Packit 96c956
    /* We treat the time of the sample as being midway through the local
Packit 96c956
       measurement period.  An analysis assuming constant relative
Packit 96c956
       frequency and zero network delay shows this is the only possible
Packit 96c956
       choice to estimate the frequency difference correctly for every
Packit 96c956
       sample pair. */
Packit 96c956
    sample.time = local_average;
Packit 96c956
    
Packit 96c956
    SST_GetFrequencyRange(stats, &source_freq_lo, &source_freq_hi);
Packit 96c956
Packit 96c956
    /* Calculate skew */
Packit 96c956
    skew = (source_freq_hi - source_freq_lo) / 2.0;
Packit 96c956
    
Packit 96c956
    /* and then calculate peer dispersion */
Packit 96c956
    sample.peer_dispersion = MAX(precision, MAX(local_transmit.err, local_receive.err)) +
Packit 96c956
                             skew * fabs(local_interval);
Packit 96c956
    
Packit 96c956
    /* If the source is an active peer, this is the minimum assumed interval
Packit 96c956
       between previous two transmissions (if not constrained by minpoll) */
Packit 96c956
    prev_remote_poll_interval = UTI_Log2ToDouble(MIN(inst->remote_poll,
Packit 96c956
                                                     inst->prev_local_poll));
Packit 96c956
Packit 96c956
    /* Additional tests required to pass before accumulating the sample */
Packit 96c956
Packit 96c956
    /* Test A requires that the minimum estimate of the peer delay is not
Packit 96c956
       larger than the configured maximum, in both client modes that the server
Packit 96c956
       processing time is sane, and in interleaved symmetric mode that the
Packit 96c956
       measured delay and intervals between remote timestamps don't indicate
Packit 96c956
       a missed response */
Packit 96c956
    testA = sample.peer_delay - sample.peer_dispersion <= inst->max_delay &&
Packit 96c956
            precision <= inst->max_delay &&
Packit 96c956
            !(inst->mode == MODE_CLIENT && response_time > MAX_SERVER_INTERVAL) &&
Packit 96c956
            !(inst->mode == MODE_ACTIVE && interleaved_packet &&
Packit 96c956
              (sample.peer_delay > 0.5 * prev_remote_poll_interval ||
Packit 96c956
               UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts) <= 0 ||
Packit 96c956
               (inst->remote_poll <= inst->prev_local_poll &&
Packit 96c956
                UTI_DiffTimespecsToDouble(&remote_transmit, &prev_remote_transmit) >
Packit 96c956
                  1.5 * prev_remote_poll_interval)));
Packit 96c956
Packit 96c956
    /* Test B requires in client mode that the ratio of the round trip delay
Packit 96c956
       to the minimum one currently in the stats data register is less than an
Packit 96c956
       administrator-defined value */
Packit 96c956
    testB = check_delay_ratio(inst, stats, &sample.time, sample.peer_delay);
Packit 96c956
Packit 96c956
    /* Test C requires that the ratio of the increase in delay from the minimum
Packit 96c956
       one in the stats data register to the standard deviation of the offsets
Packit 96c956
       in the register is less than an administrator-defined value or the
Packit 96c956
       difference between measured offset and predicted offset is larger than
Packit 96c956
       the increase in delay */
Packit 96c956
    testC = check_delay_dev_ratio(inst, stats, &sample.time, sample.offset, sample.peer_delay);
Packit 96c956
Packit 96c956
    /* Test D requires that the remote peer is not synchronised to us to
Packit 96c956
       prevent a synchronisation loop */
Packit 96c956
    testD = message->stratum <= 1 || REF_GetMode() != REF_ModeNormal ||
Packit 96c956
            pkt_refid != UTI_IPToRefid(&local_addr->ip_addr);
Packit 96c956
  } else {
Packit 96c956
    remote_interval = local_interval = response_time = 0.0;
Packit 96c956
    sample.offset = sample.peer_delay = sample.peer_dispersion = 0.0;
Packit 96c956
    sample.time = rx_ts->ts;
Packit 96c956
    local_receive = *rx_ts;
Packit 96c956
    local_transmit = inst->local_tx;
Packit 96c956
    testA = testB = testC = testD = 0;
Packit 96c956
  }
Packit 96c956
  
Packit 96c956
  /* The packet is considered good for synchronisation if
Packit 96c956
     the additional tests passed */
Packit 96c956
  good_packet = testA && testB && testC && testD;
Packit 96c956
Packit 96c956
  sample.root_delay = pkt_root_delay + sample.peer_delay;
Packit 96c956
  sample.root_dispersion = pkt_root_dispersion + sample.peer_dispersion;
Packit 96c956
  sample.stratum = MAX(message->stratum, inst->min_stratum);
Packit 96c956
  sample.leap = (NTP_Leap)pkt_leap;
Packit 96c956
Packit 96c956
  /* Update the NTP timestamps.  If it's a valid packet from a synchronised
Packit 96c956
     source, the timestamps may be used later when processing a packet in the
Packit 96c956
     interleaved mode.  Protect the timestamps against replay attacks in client
Packit 96c956
     mode, and also in symmetric mode as long as the peers use the same polling
Packit 96c956
     interval and never start with clocks in future or very distant past.
Packit 96c956
     The authentication test (test5) is required to prevent DoS attacks using
Packit 96c956
     unauthenticated packets on authenticated symmetric associations. */
Packit 96c956
  if ((inst->mode == MODE_CLIENT && valid_packet && !inst->valid_rx) ||
Packit 96c956
      (inst->mode == MODE_ACTIVE && valid_packet &&
Packit 96c956
       (!inst->valid_rx ||
Packit 96c956
        UTI_CompareNtp64(&inst->remote_ntp_tx, &message->transmit_ts) < 0))) {
Packit 96c956
    inst->remote_ntp_rx = message->receive_ts;
Packit 96c956
    inst->remote_ntp_tx = message->transmit_ts;
Packit 96c956
    inst->local_rx = *rx_ts;
Packit 96c956
    inst->valid_timestamps = synced_packet;
Packit 96c956
Packit 96c956
    UTI_ZeroNtp64(&inst->init_remote_ntp_tx);
Packit 96c956
    zero_local_timestamp(&inst->init_local_rx);
Packit 96c956
    inst->updated_init_timestamps = 0;
Packit 96c956
    updated_timestamps = 2;
Packit 96c956
Packit 96c956
    /* Don't use the same set of timestamps for the next sample */
Packit 96c956
    if (interleaved_packet)
Packit 96c956
      inst->prev_local_tx = inst->local_tx;
Packit 96c956
    else
Packit 96c956
      zero_local_timestamp(&inst->prev_local_tx);
Packit 96c956
  } else if (inst->mode == MODE_ACTIVE &&
Packit 96c956
             test1 && !UTI_IsZeroNtp64(&message->transmit_ts) && test5 &&
Packit 96c956
             (!inst->updated_init_timestamps ||
Packit 96c956
              UTI_CompareNtp64(&inst->init_remote_ntp_tx, &message->transmit_ts) < 0)) {
Packit 96c956
    inst->init_remote_ntp_tx = message->transmit_ts;
Packit 96c956
    inst->init_local_rx = *rx_ts;
Packit 96c956
    inst->updated_init_timestamps = 1;
Packit 96c956
    updated_timestamps = 1;
Packit 96c956
  } else {
Packit 96c956
    updated_timestamps = 0;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Accept at most one response per request.  The NTP specification recommends
Packit 96c956
     resetting local_ntp_tx to make the following packets fail test2 or test3,
Packit 96c956
     but that would not allow the code above to make multiple updates of the
Packit 96c956
     timestamps in symmetric mode.  Also, ignore presend responses. */
Packit 96c956
  if (inst->valid_rx) {
Packit 96c956
    test2 = test3 = 0;
Packit 96c956
    valid_packet = synced_packet = good_packet = 0;
Packit 96c956
  } else if (valid_packet) {
Packit 96c956
    if (inst->presend_done) {
Packit 96c956
      testA = 0;
Packit 96c956
      good_packet = 0;
Packit 96c956
    }
Packit 96c956
    inst->valid_rx = 1;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if ((unsigned int)local_receive.source >= sizeof (tss_chars) ||
Packit 96c956
      (unsigned int)local_transmit.source >= sizeof (tss_chars))
Packit 96c956
    assert(0);
Packit 96c956
Packit 96c956
  DEBUG_LOG("NTP packet lvm=%o stratum=%d poll=%d prec=%d root_delay=%f root_disp=%f refid=%"PRIx32" [%s]",
Packit 96c956
            message->lvm, message->stratum, message->poll, message->precision,
Packit 96c956
            pkt_root_delay, pkt_root_dispersion, pkt_refid,
Packit 96c956
            message->stratum == NTP_INVALID_STRATUM ? UTI_RefidToString(pkt_refid) : "");
Packit 96c956
  DEBUG_LOG("reference=%s origin=%s receive=%s transmit=%s",
Packit 96c956
            UTI_Ntp64ToString(&message->reference_ts),
Packit 96c956
            UTI_Ntp64ToString(&message->originate_ts),
Packit 96c956
            UTI_Ntp64ToString(&message->receive_ts),
Packit 96c956
            UTI_Ntp64ToString(&message->transmit_ts));
Packit 96c956
  DEBUG_LOG("offset=%.9f delay=%.9f dispersion=%f root_delay=%f root_dispersion=%f",
Packit 96c956
            sample.offset, sample.peer_delay, sample.peer_dispersion,
Packit 96c956
            sample.root_delay, sample.root_dispersion);
Packit 96c956
  DEBUG_LOG("remote_interval=%.9f local_interval=%.9f response_time=%.9f txs=%c rxs=%c",
Packit 96c956
            remote_interval, local_interval, response_time,
Packit 96c956
            tss_chars[local_transmit.source], tss_chars[local_receive.source]);
Packit 96c956
  DEBUG_LOG("test123=%d%d%d test567=%d%d%d testABCD=%d%d%d%d kod_rate=%d interleaved=%d"
Packit 96c956
            " presend=%d valid=%d good=%d updated=%d",
Packit 96c956
            test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
Packit 96c956
            kod_rate, interleaved_packet, inst->presend_done, valid_packet, good_packet,
Packit 96c956
            updated_timestamps);
Packit 96c956
Packit 96c956
  if (valid_packet) {
Packit 96c956
    inst->remote_poll = message->poll;
Packit 96c956
    inst->remote_stratum = message->stratum != NTP_INVALID_STRATUM ?
Packit 96c956
                           message->stratum : NTP_MAX_STRATUM;
Packit 96c956
Packit 96c956
    inst->prev_local_poll = inst->local_poll;
Packit 96c956
    inst->prev_tx_count = inst->tx_count;
Packit 96c956
    inst->tx_count = 0;
Packit 96c956
Packit 96c956
    SRC_UpdateReachability(inst->source, synced_packet);
Packit 96c956
Packit 96c956
    if (good_packet) {
Packit 96c956
      /* Adjust the polling interval, accumulate the sample, etc. */
Packit 96c956
      process_sample(inst, &sample);
Packit 96c956
Packit 96c956
      /* If we're in burst mode, check whether the burst is completed and
Packit 96c956
         revert to the previous mode */
Packit 96c956
      switch (inst->opmode) {
Packit 96c956
        case MD_BURST_WAS_ONLINE:
Packit 96c956
        case MD_BURST_WAS_OFFLINE:
Packit 96c956
          --inst->burst_good_samples_to_go;
Packit 96c956
          if (inst->burst_good_samples_to_go <= 0) {
Packit 96c956
            if (inst->opmode == MD_BURST_WAS_ONLINE)
Packit 96c956
              inst->opmode = MD_ONLINE;
Packit 96c956
            else
Packit 96c956
              take_offline(inst);
Packit 96c956
          }
Packit 96c956
          break;
Packit 96c956
        default:
Packit 96c956
          break;
Packit 96c956
      }
Packit 96c956
    } else {
Packit 96c956
      /* Slowly increase the polling interval if we can't get good packet */
Packit 96c956
      adjust_poll(inst, 0.1);
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* If in client mode, no more packets are expected to be coming from the
Packit 96c956
       server and the socket can be closed */
Packit 96c956
    close_client_socket(inst);
Packit 96c956
Packit 96c956
    /* Update the local address and interface */
Packit 96c956
    inst->local_addr.ip_addr = local_addr->ip_addr;
Packit 96c956
    inst->local_addr.if_index = local_addr->if_index;
Packit 96c956
Packit 96c956
    /* And now, requeue the timer */
Packit 96c956
    if (inst->opmode != MD_OFFLINE) {
Packit 96c956
      delay_time = get_transmit_delay(inst, 0,
Packit 96c956
                     UTI_DiffTimespecsToDouble(&inst->local_rx.ts, &inst->local_tx.ts));
Packit 96c956
Packit 96c956
      if (kod_rate) {
Packit 96c956
        LOG(LOGS_WARN, "Received KoD RATE from %s",
Packit 96c956
            UTI_IPToString(&inst->remote_addr.ip_addr));
Packit 96c956
Packit 96c956
        /* Back off for a while and stop ongoing burst */
Packit 96c956
        delay_time += 4 * UTI_Log2ToDouble(inst->local_poll);
Packit 96c956
Packit 96c956
        if (inst->opmode == MD_BURST_WAS_OFFLINE || inst->opmode == MD_BURST_WAS_ONLINE) {
Packit 96c956
          inst->burst_good_samples_to_go = 0;
Packit 96c956
        }
Packit 96c956
      }
Packit 96c956
Packit 96c956
      /* Get rid of old timeout and start a new one */
Packit 96c956
      assert(inst->tx_timeout_id);
Packit 96c956
      restart_timeout(inst, delay_time);
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* Update the NTP report */
Packit 96c956
    inst->report.remote_addr = inst->remote_addr.ip_addr;
Packit 96c956
    inst->report.local_addr = inst->local_addr.ip_addr;
Packit 96c956
    inst->report.remote_port = inst->remote_addr.port;
Packit 96c956
    inst->report.leap = pkt_leap;
Packit 96c956
    inst->report.version = pkt_version;
Packit 96c956
    inst->report.mode = NTP_LVM_TO_MODE(message->lvm);
Packit 96c956
    inst->report.stratum = message->stratum;
Packit 96c956
    inst->report.poll = message->poll;
Packit 96c956
    inst->report.precision = message->precision;
Packit 96c956
    inst->report.root_delay = pkt_root_delay;
Packit 96c956
    inst->report.root_dispersion = pkt_root_dispersion;
Packit 96c956
    inst->report.ref_id = pkt_refid;
Packit 96c956
    UTI_Ntp64ToTimespec(&message->reference_ts, &inst->report.ref_time);
Packit 96c956
    inst->report.offset = sample.offset;
Packit 96c956
    inst->report.peer_delay = sample.peer_delay;
Packit 96c956
    inst->report.peer_dispersion = sample.peer_dispersion;
Packit 96c956
    inst->report.response_time = response_time;
Packit 96c956
    inst->report.jitter_asymmetry = SST_GetJitterAsymmetry(stats);
Packit 96c956
    inst->report.tests = ((((((((test1 << 1 | test2) << 1 | test3) << 1 |
Packit 96c956
                               test5) << 1 | test6) << 1 | test7) << 1 |
Packit 96c956
                            testA) << 1 | testB) << 1 | testC) << 1 | testD;
Packit 96c956
    inst->report.interleaved = interleaved_packet;
Packit 96c956
    inst->report.authenticated = inst->auth_mode != AUTH_NONE;
Packit 96c956
    inst->report.tx_tss_char = tss_chars[local_transmit.source];
Packit 96c956
    inst->report.rx_tss_char = tss_chars[local_receive.source];
Packit 96c956
Packit 96c956
    inst->report.total_valid_count++;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Do measurement logging */
Packit 96c956
  if (logfileid != -1 && (log_raw_measurements || synced_packet)) {
Packit 96c956
    LOG_FileWrite(logfileid, "%s %-15s %1c %2d %1d%1d%1d %1d%1d%1d %1d%1d%1d%d  %2d %2d %4.2f %10.3e %10.3e %10.3e %10.3e %10.3e %08"PRIX32" %1d%1c %1c %1c",
Packit 96c956
            UTI_TimeToLogForm(sample.time.tv_sec),
Packit 96c956
            UTI_IPToString(&inst->remote_addr.ip_addr),
Packit 96c956
            leap_chars[pkt_leap],
Packit 96c956
            message->stratum,
Packit 96c956
            test1, test2, test3, test5, test6, test7, testA, testB, testC, testD,
Packit 96c956
            inst->local_poll, message->poll,
Packit 96c956
            inst->poll_score,
Packit 96c956
            sample.offset, sample.peer_delay, sample.peer_dispersion,
Packit 96c956
            pkt_root_delay, pkt_root_dispersion, pkt_refid,
Packit 96c956
            NTP_LVM_TO_MODE(message->lvm), interleaved_packet ? 'I' : 'B',
Packit 96c956
            tss_chars[local_transmit.source],
Packit 96c956
            tss_chars[local_receive.source]);
Packit 96c956
  }            
Packit 96c956
Packit 96c956
  return good_packet;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* From RFC 5905, the standard handling of received packets, depending
Packit 96c956
   on the mode of the packet and of the source, is :
Packit 96c956
Packit 96c956
   +------------------+---------------------------------------+
Packit 96c956
   |                  |              Packet Mode              |
Packit 96c956
   +------------------+-------+-------+-------+-------+-------+
Packit 96c956
   | Association Mode |   1   |   2   |   3   |   4   |   5   |
Packit 96c956
   +------------------+-------+-------+-------+-------+-------+
Packit 96c956
   | No Association 0 | NEWPS | DSCRD | FXMIT | MANY  | NEWBC |
Packit 96c956
   | Symm. Active   1 | PROC  | PROC  | DSCRD | DSCRD | DSCRD |
Packit 96c956
   | Symm. Passive  2 | PROC  | ERR   | DSCRD | DSCRD | DSCRD |
Packit 96c956
   | Client         3 | DSCRD | DSCRD | DSCRD | PROC  | DSCRD |
Packit 96c956
   | Server         4 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
Packit 96c956
   | Broadcast      5 | DSCRD | DSCRD | DSCRD | DSCRD | DSCRD |
Packit 96c956
   | Bcast Client   6 | DSCRD | DSCRD | DSCRD | DSCRD | PROC  |
Packit 96c956
   +------------------+-------+-------+-------+-------+-------+
Packit 96c956
Packit 96c956
   Association mode 0 is implemented in NCR_ProcessRxUnknown(), other modes
Packit 96c956
   in NCR_ProcessRxKnown().
Packit 96c956
Packit 96c956
   Broadcast, manycast and ephemeral symmetric passive associations are not
Packit 96c956
   supported yet.
Packit 96c956
 */
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* This routine is called when a new packet arrives off the network,
Packit 96c956
   and it relates to a source we have an ongoing protocol exchange with */
Packit 96c956
Packit 96c956
int
Packit 96c956
NCR_ProcessRxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
Packit 96c956
                   NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
Packit 96c956
{
Packit 96c956
  int pkt_mode, proc_packet, proc_as_unknown;
Packit 96c956
Packit 96c956
  if (!check_packet_format(message, length))
Packit 96c956
    return 0;
Packit 96c956
Packit 96c956
  pkt_mode = NTP_LVM_TO_MODE(message->lvm);
Packit 96c956
  proc_packet = 0;
Packit 96c956
  proc_as_unknown = 0;
Packit 96c956
Packit 96c956
  /* Now, depending on the mode we decide what to do */
Packit 96c956
  switch (pkt_mode) {
Packit 96c956
    case MODE_ACTIVE:
Packit 96c956
      switch (inst->mode) {
Packit 96c956
        case MODE_ACTIVE:
Packit 96c956
          /* Ordinary symmetric peering */
Packit 96c956
          proc_packet = 1;
Packit 96c956
          break;
Packit 96c956
        case MODE_PASSIVE:
Packit 96c956
          /* In this software this case should not arise, we don't
Packit 96c956
             support unconfigured peers */
Packit 96c956
          break;
Packit 96c956
        case MODE_CLIENT:
Packit 96c956
          /* This is where we have the remote configured as a server and he has
Packit 96c956
             us configured as a peer, process as from an unknown source */
Packit 96c956
          proc_as_unknown = 1;
Packit 96c956
          break;
Packit 96c956
        default:
Packit 96c956
          /* Discard */
Packit 96c956
          break;
Packit 96c956
      }
Packit 96c956
      break;
Packit 96c956
Packit 96c956
    case MODE_PASSIVE:
Packit 96c956
      switch (inst->mode) {
Packit 96c956
        case MODE_ACTIVE:
Packit 96c956
          /* This would arise if we have the remote configured as a peer and
Packit 96c956
             he does not have us configured */
Packit 96c956
          proc_packet = 1;
Packit 96c956
          break;
Packit 96c956
        case MODE_PASSIVE:
Packit 96c956
          /* Error condition in RFC 5905 */
Packit 96c956
          break;
Packit 96c956
        default:
Packit 96c956
          /* Discard */
Packit 96c956
          break;
Packit 96c956
      }
Packit 96c956
      break;
Packit 96c956
Packit 96c956
    case MODE_CLIENT:
Packit 96c956
      /* If message is client mode, we just respond with a server mode
Packit 96c956
         packet, regardless of what we think the remote machine is
Packit 96c956
         supposed to be.  However, even though this is a configured
Packit 96c956
         peer or server, we still implement access restrictions on
Packit 96c956
         client mode operation.
Packit 96c956
Packit 96c956
         This copes with the case for an isolated network where one
Packit 96c956
         machine is set by eye and is used as the master, with the
Packit 96c956
         other machines pointed at it.  If the master goes down, we
Packit 96c956
         want to be able to reset its time at startup by relying on
Packit 96c956
         one of the secondaries to flywheel it. The behaviour coded here
Packit 96c956
         is required in the secondaries to make this possible. */
Packit 96c956
Packit 96c956
      proc_as_unknown = 1;
Packit 96c956
      break;
Packit 96c956
Packit 96c956
    case MODE_SERVER:
Packit 96c956
      switch (inst->mode) {
Packit 96c956
        case MODE_CLIENT:
Packit 96c956
          /* Standard case where he's a server and we're the client */
Packit 96c956
          proc_packet = 1;
Packit 96c956
          break;
Packit 96c956
        default:
Packit 96c956
          /* Discard */
Packit 96c956
          break;
Packit 96c956
      }
Packit 96c956
      break;
Packit 96c956
Packit 96c956
    case MODE_BROADCAST:
Packit 96c956
      /* Just ignore these */
Packit 96c956
      break;
Packit 96c956
Packit 96c956
    default:
Packit 96c956
      /* Obviously ignore */
Packit 96c956
      break;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (proc_packet) {
Packit 96c956
    /* Check if the reply was received by the socket that sent the request */
Packit 96c956
    if (local_addr->sock_fd != inst->local_addr.sock_fd) {
Packit 96c956
      DEBUG_LOG("Packet received by wrong socket %d (expected %d)",
Packit 96c956
                local_addr->sock_fd, inst->local_addr.sock_fd);
Packit 96c956
      return 0;
Packit 96c956
    }
Packit 96c956
Packit 96c956
    /* Ignore packets from offline sources */
Packit 96c956
    if (inst->opmode == MD_OFFLINE || inst->tx_suspended) {
Packit 96c956
      DEBUG_LOG("Packet from offline source");
Packit 96c956
      return 0;
Packit 96c956
    }
Packit 96c956
Packit 96c956
    return receive_packet(inst, local_addr, rx_ts, message, length);
Packit 96c956
  } else if (proc_as_unknown) {
Packit 96c956
    NCR_ProcessRxUnknown(&inst->remote_addr, local_addr, rx_ts, message, length);
Packit 96c956
    /* It's not a reply to our request, don't return success */
Packit 96c956
    return 0;
Packit 96c956
  } else {
Packit 96c956
    DEBUG_LOG("NTP packet discarded pkt_mode=%d our_mode=%u", pkt_mode, inst->mode);
Packit 96c956
    return 0;
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
/* This routine is called when a new packet arrives off the network,
Packit 96c956
   and it relates to a source we don't know (not our server or peer) */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ProcessRxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
Packit 96c956
                     NTP_Local_Timestamp *rx_ts, NTP_Packet *message, int length)
Packit 96c956
{
Packit 96c956
  NTP_Mode pkt_mode, my_mode;
Packit 96c956
  NTP_int64 *local_ntp_rx, *local_ntp_tx;
Packit 96c956
  NTP_Local_Timestamp local_tx, *tx_ts;
Packit 96c956
  int pkt_version, valid_auth, log_index, interleaved, poll;
Packit 96c956
  AuthenticationMode auth_mode;
Packit 96c956
  uint32_t key_id;
Packit 96c956
Packit 96c956
  /* Ignore the packet if it wasn't received by server socket */
Packit 96c956
  if (!NIO_IsServerSocket(local_addr->sock_fd)) {
Packit 96c956
    DEBUG_LOG("NTP request packet received by client socket %d", local_addr->sock_fd);
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (!check_packet_format(message, length))
Packit 96c956
    return;
Packit 96c956
Packit 96c956
  if (!ADF_IsAllowed(access_auth_table, &remote_addr->ip_addr)) {
Packit 96c956
    DEBUG_LOG("NTP packet received from unauthorised host %s port %d",
Packit 96c956
              UTI_IPToString(&remote_addr->ip_addr),
Packit 96c956
              remote_addr->port);
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  pkt_mode = NTP_LVM_TO_MODE(message->lvm);
Packit 96c956
  pkt_version = NTP_LVM_TO_VERSION(message->lvm);
Packit 96c956
Packit 96c956
  switch (pkt_mode) {
Packit 96c956
    case MODE_ACTIVE:
Packit 96c956
      /* We are symmetric passive, even though we don't ever lock to him */
Packit 96c956
      my_mode = MODE_PASSIVE;
Packit 96c956
      break;
Packit 96c956
    case MODE_CLIENT:
Packit 96c956
      /* Reply with server packet */
Packit 96c956
      my_mode = MODE_SERVER;
Packit 96c956
      break;
Packit 96c956
    case MODE_UNDEFINED:
Packit 96c956
      /* Check if it is an NTPv1 client request (NTPv1 packets have a reserved
Packit 96c956
         field instead of the mode field and the actual mode is determined from
Packit 96c956
         the port numbers).  Don't ever respond with a mode 0 packet! */
Packit 96c956
      if (pkt_version == 1 && remote_addr->port != NTP_PORT) {
Packit 96c956
        my_mode = MODE_SERVER;
Packit 96c956
        break;
Packit 96c956
      }
Packit 96c956
      /* Fall through */
Packit 96c956
    default:
Packit 96c956
      /* Discard */
Packit 96c956
      DEBUG_LOG("NTP packet discarded pkt_mode=%u", pkt_mode);
Packit 96c956
      return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  log_index = CLG_LogNTPAccess(&remote_addr->ip_addr, &rx_ts->ts);
Packit 96c956
Packit 96c956
  /* Don't reply to all requests if the rate is excessive */
Packit 96c956
  if (log_index >= 0 && CLG_LimitNTPResponseRate(log_index)) {
Packit 96c956
      DEBUG_LOG("NTP packet discarded to limit response rate");
Packit 96c956
      return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Check if the packet includes MAC that authenticates properly */
Packit 96c956
  valid_auth = check_packet_auth(message, length, &auth_mode, &key_id);
Packit 96c956
Packit 96c956
  /* If authentication failed, select whether and how we should respond */
Packit 96c956
  if (!valid_auth) {
Packit 96c956
    switch (auth_mode) {
Packit 96c956
      case AUTH_NONE:
Packit 96c956
        /* Reply with no MAC */
Packit 96c956
        break;
Packit 96c956
      case AUTH_MSSNTP:
Packit 96c956
        /* Ignore the failure (MS-SNTP servers don't check client MAC) */
Packit 96c956
        break;
Packit 96c956
      default:
Packit 96c956
        /* Discard packets in other modes */
Packit 96c956
        DEBUG_LOG("NTP packet discarded auth_mode=%u", auth_mode);
Packit 96c956
        return;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
Packit 96c956
  local_ntp_rx = local_ntp_tx = NULL;
Packit 96c956
  tx_ts = NULL;
Packit 96c956
  interleaved = 0;
Packit 96c956
Packit 96c956
  /* Check if the client is using the interleaved mode.  If it is, save the
Packit 96c956
     new transmit timestamp and if the old transmit timestamp is valid, respond
Packit 96c956
     in the interleaved mode.  This means the third reply to a new client is
Packit 96c956
     the earliest one that can be interleaved.  We don't want to waste time
Packit 96c956
     on clients that are not using the interleaved mode. */
Packit 96c956
  if (log_index >= 0) {
Packit 96c956
    CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
Packit 96c956
    interleaved = !UTI_IsZeroNtp64(local_ntp_rx) &&
Packit 96c956
                  !UTI_CompareNtp64(&message->originate_ts, local_ntp_rx) &&
Packit 96c956
                  UTI_CompareNtp64(&message->receive_ts, &message->transmit_ts);
Packit 96c956
Packit 96c956
    if (interleaved) {
Packit 96c956
      UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
Packit 96c956
      tx_ts = &local_tx;
Packit 96c956
    } else {
Packit 96c956
      UTI_ZeroNtp64(local_ntp_tx);
Packit 96c956
      local_ntp_tx = NULL;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Suggest the client to increase its polling interval if it indicates
Packit 96c956
     the interval is shorter than the rate limiting interval */
Packit 96c956
  poll = CLG_GetNtpMinPoll();
Packit 96c956
  poll = MAX(poll, message->poll);
Packit 96c956
Packit 96c956
  /* Send a reply */
Packit 96c956
  transmit_packet(my_mode, interleaved, poll, pkt_version,
Packit 96c956
                  auth_mode, key_id, &message->receive_ts, &message->transmit_ts,
Packit 96c956
                  rx_ts, tx_ts, local_ntp_rx, NULL, remote_addr, local_addr);
Packit 96c956
Packit 96c956
  /* Save the transmit timestamp */
Packit 96c956
  if (tx_ts)
Packit 96c956
    UTI_TimespecToNtp64(&tx_ts->ts, local_ntp_tx, NULL);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
update_tx_timestamp(NTP_Local_Timestamp *tx_ts, NTP_Local_Timestamp *new_tx_ts,
Packit 96c956
                    NTP_int64 *local_ntp_rx, NTP_int64 *local_ntp_tx, NTP_Packet *message)
Packit 96c956
{
Packit 96c956
  double delay;
Packit 96c956
Packit 96c956
  if (UTI_IsZeroTimespec(&tx_ts->ts)) {
Packit 96c956
    DEBUG_LOG("Unexpected TX update");
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  /* Check if this is the last packet that was sent */
Packit 96c956
  if ((local_ntp_rx && UTI_CompareNtp64(&message->receive_ts, local_ntp_rx)) ||
Packit 96c956
      (local_ntp_tx && UTI_CompareNtp64(&message->transmit_ts, local_ntp_tx))) {
Packit 96c956
    DEBUG_LOG("RX/TX timestamp mismatch");
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  delay = UTI_DiffTimespecsToDouble(&new_tx_ts->ts, &tx_ts->ts);
Packit 96c956
Packit 96c956
  if (delay < 0.0 || delay > MAX_TX_DELAY) {
Packit 96c956
    DEBUG_LOG("Unacceptable TX delay %.9f", delay);
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  *tx_ts = *new_tx_ts;
Packit 96c956
Packit 96c956
  DEBUG_LOG("Updated TX timestamp delay=%.9f", delay);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ProcessTxKnown(NCR_Instance inst, NTP_Local_Address *local_addr,
Packit 96c956
                   NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length)
Packit 96c956
{
Packit 96c956
  NTP_Mode pkt_mode;
Packit 96c956
Packit 96c956
  if (!check_packet_format(message, length))
Packit 96c956
    return;
Packit 96c956
Packit 96c956
  pkt_mode = NTP_LVM_TO_MODE(message->lvm);
Packit 96c956
Packit 96c956
  /* Server and passive mode packets are responses to unknown sources */
Packit 96c956
  if (pkt_mode != MODE_CLIENT && pkt_mode != MODE_ACTIVE) {
Packit 96c956
    NCR_ProcessTxUnknown(&inst->remote_addr, local_addr, tx_ts, message, length);
Packit 96c956
    return;
Packit 96c956
  }
Packit 96c956
Packit 96c956
  update_tx_timestamp(&inst->local_tx, tx_ts, &inst->local_ntp_rx, &inst->local_ntp_tx,
Packit 96c956
                      message);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ProcessTxUnknown(NTP_Remote_Address *remote_addr, NTP_Local_Address *local_addr,
Packit 96c956
                     NTP_Local_Timestamp *tx_ts, NTP_Packet *message, int length)
Packit 96c956
{
Packit 96c956
  NTP_int64 *local_ntp_rx, *local_ntp_tx;
Packit 96c956
  NTP_Local_Timestamp local_tx;
Packit 96c956
  int log_index;
Packit 96c956
Packit 96c956
  if (!check_packet_format(message, length))
Packit 96c956
    return;
Packit 96c956
Packit 96c956
  if (NTP_LVM_TO_MODE(message->lvm) == MODE_BROADCAST)
Packit 96c956
    return;
Packit 96c956
Packit 96c956
  log_index = CLG_GetClientIndex(&remote_addr->ip_addr);
Packit 96c956
  if (log_index < 0)
Packit 96c956
    return;
Packit 96c956
Packit 96c956
  if (SMT_IsEnabled() && NTP_LVM_TO_MODE(message->lvm) == MODE_SERVER)
Packit 96c956
    UTI_AddDoubleToTimespec(&tx_ts->ts, SMT_GetOffset(&tx_ts->ts), &tx_ts->ts);
Packit 96c956
Packit 96c956
  CLG_GetNtpTimestamps(log_index, &local_ntp_rx, &local_ntp_tx);
Packit 96c956
Packit 96c956
  UTI_Ntp64ToTimespec(local_ntp_tx, &local_tx.ts);
Packit 96c956
  update_tx_timestamp(&local_tx, tx_ts, local_ntp_rx, NULL, message);
Packit 96c956
  UTI_TimespecToNtp64(&local_tx.ts, local_ntp_tx, NULL);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_SlewTimes(NCR_Instance inst, struct timespec *when, double dfreq, double doffset)
Packit 96c956
{
Packit 96c956
  double delta;
Packit 96c956
Packit 96c956
  if (!UTI_IsZeroTimespec(&inst->local_rx.ts))
Packit 96c956
    UTI_AdjustTimespec(&inst->local_rx.ts, when, &inst->local_rx.ts, &delta, dfreq, doffset);
Packit 96c956
  if (!UTI_IsZeroTimespec(&inst->local_tx.ts))
Packit 96c956
    UTI_AdjustTimespec(&inst->local_tx.ts, when, &inst->local_tx.ts, &delta, dfreq, doffset);
Packit 96c956
  if (!UTI_IsZeroTimespec(&inst->prev_local_tx.ts))
Packit 96c956
    UTI_AdjustTimespec(&inst->prev_local_tx.ts, when, &inst->prev_local_tx.ts, &delta, dfreq,
Packit 96c956
                       doffset);
Packit 96c956
  if (!UTI_IsZeroTimespec(&inst->init_local_rx.ts))
Packit 96c956
    UTI_AdjustTimespec(&inst->init_local_rx.ts, when, &inst->init_local_rx.ts, &delta, dfreq,
Packit 96c956
                       doffset);
Packit 96c956
Packit 96c956
  if (inst->filter)
Packit 96c956
    SPF_SlewSamples(inst->filter, when, dfreq, doffset);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_SetConnectivity(NCR_Instance inst, SRC_Connectivity connectivity)
Packit 96c956
{
Packit 96c956
  char *s;
Packit 96c956
Packit 96c956
  s = UTI_IPToString(&inst->remote_addr.ip_addr);
Packit 96c956
Packit 96c956
  if (connectivity == SRC_MAYBE_ONLINE)
Packit 96c956
    connectivity = NIO_IsServerConnectable(&inst->remote_addr) ? SRC_ONLINE : SRC_OFFLINE;
Packit 96c956
Packit 96c956
  switch (connectivity) {
Packit 96c956
    case SRC_ONLINE:
Packit 96c956
      switch (inst->opmode) {
Packit 96c956
        case MD_ONLINE:
Packit 96c956
          /* Nothing to do */
Packit 96c956
          break;
Packit 96c956
        case MD_OFFLINE:
Packit 96c956
          LOG(LOGS_INFO, "Source %s online", s);
Packit 96c956
          inst->opmode = MD_ONLINE;
Packit 96c956
          NCR_ResetInstance(inst);
Packit 96c956
          start_initial_timeout(inst);
Packit 96c956
          break;
Packit 96c956
        case MD_BURST_WAS_ONLINE:
Packit 96c956
          /* Will revert */
Packit 96c956
          break;
Packit 96c956
        case MD_BURST_WAS_OFFLINE:
Packit 96c956
          inst->opmode = MD_BURST_WAS_ONLINE;
Packit 96c956
          LOG(LOGS_INFO, "Source %s online", s);
Packit 96c956
          break;
Packit 96c956
        default:
Packit 96c956
          assert(0);
Packit 96c956
      }
Packit 96c956
      break;
Packit 96c956
    case SRC_OFFLINE:
Packit 96c956
      switch (inst->opmode) {
Packit 96c956
        case MD_ONLINE:
Packit 96c956
          LOG(LOGS_INFO, "Source %s offline", s);
Packit 96c956
          take_offline(inst);
Packit 96c956
          break;
Packit 96c956
        case MD_OFFLINE:
Packit 96c956
          break;
Packit 96c956
        case MD_BURST_WAS_ONLINE:
Packit 96c956
          inst->opmode = MD_BURST_WAS_OFFLINE;
Packit 96c956
          LOG(LOGS_INFO, "Source %s offline", s);
Packit 96c956
          break;
Packit 96c956
        case MD_BURST_WAS_OFFLINE:
Packit 96c956
          break;
Packit 96c956
        default:
Packit 96c956
          assert(0);
Packit 96c956
      }
Packit 96c956
      break;
Packit 96c956
    default:
Packit 96c956
      assert(0);
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ModifyMinpoll(NCR_Instance inst, int new_minpoll)
Packit 96c956
{
Packit 96c956
  if (new_minpoll < MIN_POLL || new_minpoll > MAX_POLL)
Packit 96c956
    return;
Packit 96c956
  inst->minpoll = new_minpoll;
Packit 96c956
  LOG(LOGS_INFO, "Source %s new minpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_minpoll);
Packit 96c956
  if (inst->maxpoll < inst->minpoll)
Packit 96c956
    NCR_ModifyMaxpoll(inst, inst->minpoll);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ModifyMaxpoll(NCR_Instance inst, int new_maxpoll)
Packit 96c956
{
Packit 96c956
  if (new_maxpoll < MIN_POLL || new_maxpoll > MAX_POLL)
Packit 96c956
    return;
Packit 96c956
  inst->maxpoll = new_maxpoll;
Packit 96c956
  LOG(LOGS_INFO, "Source %s new maxpoll %d", UTI_IPToString(&inst->remote_addr.ip_addr), new_maxpoll);
Packit 96c956
  if (inst->minpoll > inst->maxpoll)
Packit 96c956
    NCR_ModifyMinpoll(inst, inst->maxpoll);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ModifyMaxdelay(NCR_Instance inst, double new_max_delay)
Packit 96c956
{
Packit 96c956
  inst->max_delay = CLAMP(0.0, new_max_delay, MAX_MAXDELAY);
Packit 96c956
  LOG(LOGS_INFO, "Source %s new maxdelay %f",
Packit 96c956
      UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ModifyMaxdelayratio(NCR_Instance inst, double new_max_delay_ratio)
Packit 96c956
{
Packit 96c956
  inst->max_delay_ratio = CLAMP(0.0, new_max_delay_ratio, MAX_MAXDELAYRATIO);
Packit 96c956
  LOG(LOGS_INFO, "Source %s new maxdelayratio %f",
Packit 96c956
      UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_ratio);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ModifyMaxdelaydevratio(NCR_Instance inst, double new_max_delay_dev_ratio)
Packit 96c956
{
Packit 96c956
  inst->max_delay_dev_ratio = CLAMP(0.0, new_max_delay_dev_ratio, MAX_MAXDELAYDEVRATIO);
Packit 96c956
  LOG(LOGS_INFO, "Source %s new maxdelaydevratio %f",
Packit 96c956
      UTI_IPToString(&inst->remote_addr.ip_addr), inst->max_delay_dev_ratio);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ModifyMinstratum(NCR_Instance inst, int new_min_stratum)
Packit 96c956
{
Packit 96c956
  inst->min_stratum = new_min_stratum;
Packit 96c956
  LOG(LOGS_INFO, "Source %s new minstratum %d",
Packit 96c956
      UTI_IPToString(&inst->remote_addr.ip_addr), new_min_stratum);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ModifyPolltarget(NCR_Instance inst, int new_poll_target)
Packit 96c956
{
Packit 96c956
  inst->poll_target = new_poll_target;
Packit 96c956
  LOG(LOGS_INFO, "Source %s new polltarget %d",
Packit 96c956
      UTI_IPToString(&inst->remote_addr.ip_addr), new_poll_target);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_InitiateSampleBurst(NCR_Instance inst, int n_good_samples, int n_total_samples)
Packit 96c956
{
Packit 96c956
Packit 96c956
  if (inst->mode == MODE_CLIENT) {
Packit 96c956
Packit 96c956
    /* We want to prevent burst mode being used on symmetric active
Packit 96c956
       associations - it will play havoc with the peer's sampling
Packit 96c956
       strategy. (This obviously relies on us having the peer
Packit 96c956
       configured that way if he has us configured symmetric active -
Packit 96c956
       but there's not much else we can do.) */
Packit 96c956
Packit 96c956
    switch (inst->opmode) {
Packit 96c956
      case MD_BURST_WAS_OFFLINE:
Packit 96c956
      case MD_BURST_WAS_ONLINE:
Packit 96c956
        /* If already burst sampling, don't start again */
Packit 96c956
        break;
Packit 96c956
Packit 96c956
      case MD_ONLINE:
Packit 96c956
      case MD_OFFLINE:
Packit 96c956
        inst->opmode = inst->opmode == MD_ONLINE ?
Packit 96c956
          MD_BURST_WAS_ONLINE : MD_BURST_WAS_OFFLINE;
Packit 96c956
        inst->burst_good_samples_to_go = n_good_samples;
Packit 96c956
        inst->burst_total_samples_to_go = n_total_samples;
Packit 96c956
        start_initial_timeout(inst);
Packit 96c956
        break;
Packit 96c956
      default:
Packit 96c956
        assert(0);
Packit 96c956
        break;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_ReportSource(NCR_Instance inst, RPT_SourceReport *report, struct timespec *now)
Packit 96c956
{
Packit 96c956
  report->poll = get_transmit_poll(inst);
Packit 96c956
Packit 96c956
  switch (inst->mode) {
Packit 96c956
    case MODE_CLIENT:
Packit 96c956
      report->mode = RPT_NTP_CLIENT;
Packit 96c956
      break;
Packit 96c956
    case MODE_ACTIVE:
Packit 96c956
      report->mode = RPT_NTP_PEER;
Packit 96c956
      break;
Packit 96c956
    default:
Packit 96c956
      assert(0);
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_GetNTPReport(NCR_Instance inst, RPT_NTPReport *report)
Packit 96c956
{
Packit 96c956
  *report = inst->report;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
int
Packit 96c956
NCR_AddAccessRestriction(IPAddr *ip_addr, int subnet_bits, int allow, int all)
Packit 96c956
 {
Packit 96c956
  ADF_Status status;
Packit 96c956
Packit 96c956
  if (allow) {
Packit 96c956
    if (all) {
Packit 96c956
      status = ADF_AllowAll(access_auth_table, ip_addr, subnet_bits);
Packit 96c956
    } else {
Packit 96c956
      status = ADF_Allow(access_auth_table, ip_addr, subnet_bits);
Packit 96c956
    }
Packit 96c956
  } else {
Packit 96c956
    if (all) {
Packit 96c956
      status = ADF_DenyAll(access_auth_table, ip_addr, subnet_bits);
Packit 96c956
    } else {
Packit 96c956
      status = ADF_Deny(access_auth_table, ip_addr, subnet_bits);
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
Packit 96c956
  if (status != ADF_SUCCESS)
Packit 96c956
    return 0;
Packit 96c956
Packit 96c956
  /* Keep server sockets open only when an address allowed */
Packit 96c956
  if (allow) {
Packit 96c956
    NTP_Remote_Address remote_addr;
Packit 96c956
Packit 96c956
    if (server_sock_fd4 == INVALID_SOCK_FD &&
Packit 96c956
        ADF_IsAnyAllowed(access_auth_table, IPADDR_INET4)) {
Packit 96c956
      remote_addr.ip_addr.family = IPADDR_INET4;
Packit 96c956
      server_sock_fd4 = NIO_OpenServerSocket(&remote_addr);
Packit 96c956
    }
Packit 96c956
    if (server_sock_fd6 == INVALID_SOCK_FD &&
Packit 96c956
        ADF_IsAnyAllowed(access_auth_table, IPADDR_INET6)) {
Packit 96c956
      remote_addr.ip_addr.family = IPADDR_INET6;
Packit 96c956
      server_sock_fd6 = NIO_OpenServerSocket(&remote_addr);
Packit 96c956
    }
Packit 96c956
  } else {
Packit 96c956
    if (server_sock_fd4 != INVALID_SOCK_FD &&
Packit 96c956
        !ADF_IsAnyAllowed(access_auth_table, IPADDR_INET4)) {
Packit 96c956
      NIO_CloseServerSocket(server_sock_fd4);
Packit 96c956
      server_sock_fd4 = INVALID_SOCK_FD;
Packit 96c956
    }
Packit 96c956
    if (server_sock_fd6 != INVALID_SOCK_FD &&
Packit 96c956
        !ADF_IsAnyAllowed(access_auth_table, IPADDR_INET6)) {
Packit 96c956
      NIO_CloseServerSocket(server_sock_fd6);
Packit 96c956
      server_sock_fd6 = INVALID_SOCK_FD;
Packit 96c956
    }
Packit 96c956
  }
Packit 96c956
Packit 96c956
  return 1;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
int
Packit 96c956
NCR_CheckAccessRestriction(IPAddr *ip_addr)
Packit 96c956
{
Packit 96c956
  return ADF_IsAllowed(access_auth_table, ip_addr);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_IncrementActivityCounters(NCR_Instance inst, int *online, int *offline,
Packit 96c956
                              int *burst_online, int *burst_offline)
Packit 96c956
{
Packit 96c956
  switch (inst->opmode) {
Packit 96c956
    case MD_BURST_WAS_OFFLINE:
Packit 96c956
      ++*burst_offline;
Packit 96c956
      break;
Packit 96c956
    case MD_BURST_WAS_ONLINE:
Packit 96c956
      ++*burst_online;
Packit 96c956
      break;
Packit 96c956
    case MD_ONLINE:
Packit 96c956
      ++*online;
Packit 96c956
      break;
Packit 96c956
    case MD_OFFLINE:
Packit 96c956
      ++*offline;
Packit 96c956
      break;
Packit 96c956
    default:
Packit 96c956
      assert(0);
Packit 96c956
      break;
Packit 96c956
  }
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
NTP_Remote_Address *
Packit 96c956
NCR_GetRemoteAddress(NCR_Instance inst) 
Packit 96c956
{
Packit 96c956
  return &inst->remote_addr;
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
uint32_t
Packit 96c956
NCR_GetLocalRefid(NCR_Instance inst)
Packit 96c956
{
Packit 96c956
  return UTI_IPToRefid(&inst->local_addr.ip_addr);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
int NCR_IsSyncPeer(NCR_Instance inst)
Packit 96c956
{
Packit 96c956
  return SRC_IsSyncPeer(inst->source);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
static void
Packit 96c956
broadcast_timeout(void *arg)
Packit 96c956
{
Packit 96c956
  BroadcastDestination *destination;
Packit 96c956
  NTP_int64 orig_ts;
Packit 96c956
  NTP_Local_Timestamp recv_ts;
Packit 96c956
  int poll;
Packit 96c956
Packit 96c956
  destination = ARR_GetElement(broadcasts, (long)arg);
Packit 96c956
  poll = log(destination->interval) / log(2.0) + 0.5;
Packit 96c956
Packit 96c956
  UTI_ZeroNtp64(&orig_ts);
Packit 96c956
  zero_local_timestamp(&recv_ts);
Packit 96c956
Packit 96c956
  transmit_packet(MODE_BROADCAST, 0, poll, NTP_VERSION, 0, 0, &orig_ts, &orig_ts, &recv_ts,
Packit 96c956
                  NULL, NULL, NULL, &destination->addr, &destination->local_addr);
Packit 96c956
Packit 96c956
  /* Requeue timeout.  We don't care if interval drifts gradually. */
Packit 96c956
  SCH_AddTimeoutInClass(destination->interval, get_separation(poll), SAMPLING_RANDOMNESS,
Packit 96c956
                        SCH_NtpBroadcastClass, broadcast_timeout, arg);
Packit 96c956
}
Packit 96c956
Packit 96c956
/* ================================================== */
Packit 96c956
Packit 96c956
void
Packit 96c956
NCR_AddBroadcastDestination(IPAddr *addr, unsigned short port, int interval)
Packit 96c956
{
Packit 96c956
  BroadcastDestination *destination;
Packit 96c956
Packit 96c956
  destination = (BroadcastDestination *)ARR_GetNewElement(broadcasts);
Packit 96c956
Packit 96c956
  destination->addr.ip_addr = *addr;
Packit 96c956
  destination->addr.port = port;
Packit 96c956
  destination->local_addr.ip_addr.family = IPADDR_UNSPEC;
Packit 96c956
  destination->local_addr.if_index = INVALID_IF_INDEX;
Packit 96c956
  destination->local_addr.sock_fd = NIO_OpenServerSocket(&destination->addr);
Packit 96c956
  destination->interval = CLAMP(1, interval, 1 << MAX_POLL);
Packit 96c956
Packit 96c956
  SCH_AddTimeoutInClass(destination->interval, MAX_SAMPLING_SEPARATION, SAMPLING_RANDOMNESS,
Packit 96c956
                        SCH_NtpBroadcastClass, broadcast_timeout,
Packit 96c956
                        (void *)(long)(ARR_GetSize(broadcasts) - 1));
Packit 96c956
}