ntp_proto.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 1996, 1999-2003 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* ntp_proto.c - NTP version 3 protocol machinery
*/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include "ntpd.h"
#include "ntp_stdlib.h"
#include "ntp_unixtime.h"
#include "ntp_control.h"
#include "ntp_string.h"
#include "ntp_refclock.h"
#endif
/*
* System variables are declared here. See Section 3.2 of the
* specification.
*/
extern long sys_clock; /* second part of current time */
long sys_lastselect; /* sys_clock at last synch update */
#if defined(GDT_SURVEYING)
#endif /* GDT_SURVEYING */
/*
* Nonspecified system state variables.
*/
int sys_bclient; /* we set our time to broadcasts */
int sys_authenticate; /* authenticate time used for syncing */
/*
* Statistics counters
*/
/*
* Imported from ntp_timer.c
*/
extern u_long current_time;
extern struct event timerqueue[];
/*
* Imported from ntp_io.c
*/
extern struct interface *any_interface;
/*
* Imported from ntp_loopfilter.c
*/
extern int pll_enable;
extern int pps_update;
extern int pps_enable;
extern int pps_control;
/*
* Imported from ntp_util.c
*/
extern int stats_control;
/*
* The peer hash table. Imported from ntp_peer.c
*/
extern int peer_hash_count[];
/*
* debug flag
*/
extern int debug;
static void clear_all P((void));
static int default_get_precision P((void));
/*
* transmit - Transmit Procedure. See Section 3.4.2 of the
* specification.
*/
void
{
int bool;
/*
* We need to be very careful about honking uncivilized time. If
* not operating in broadcast mode, honk in all except broadcast
* client mode. If operating in broadcast mode and synchronized
* to a real source, honk except when the peer is the local-
* clock driver and the prefer flag is not set. In other words,
* in broadcast mode we never honk unless known to be
* synchronized to real time.
*/
bool = 0;
bool = 1;
bool = 1;
}
if (bool) {
/*
* Figure out which keyid to include in the packet
*/
} else {
xkeyid = 0;
}
/*
* Make up a packet to send.
*/
if (precision == 0)
precision = 1;
/*
* Decide whether to authenticate or not. If so, call
* encrypt() to fill in the rest of the frame. If not,
* just add in the xmt timestamp and send it quick.
* Note the authentication delay correction is made
* on-the-wing as the minimum of the latest two samples.
*/
int sendlen;
else
#ifdef DEBUG
if (debug > 1)
printf("transmit auth to %s %s\n",
#endif
} else {
/*
* Get xmt timestamp, then send it without mac
* field
*/
#ifdef DEBUG
if (debug > 1)
printf("transmit to %s\n",
#endif
}
}
/*
* Determine reachability and diddle things if we
* haven't heard from the host for a while. If we are
* about to become unreachable and are a
* MODE_BCLIENT anyway and wait for subsequent
* broadcasts.
*/
if (opeer_reach != 0)
/*
* Clear this guy out. No need to redo clock
* selection since by now this guy won't be a
* player
*/
if (opeer_reach != 0) {
}
return;
}
/*
* While we have a chance, if our system peer is
* zero or his stratum is greater than the last
* known stratum of this guy, make sure hpoll is
* clamped to the minimum before resetting the
* timer. If the peer has been unreachable for a
* while and we have a system peer who is at
* least his equal, we may want to ramp his
* polling interval up to avoid the useless
* traffic.
*/
if (sys_peer == 0) {
} else {
}
}
/*
* Update reachability and poll variables
*/
} else if ((opeer_reach & 3) == 0) {
clock_select();
} else {
} else {
}
}
}
/*
* Finally, adjust the hpoll variable for special conditions. If
* interval if listening for broadcasts and one-eighth this
* prevents madness. If this is the system poll, sys_poll
* controls hpoll.
*/
else
/*
* Arrange for our next timeout. hpoll will be less than maxpoll
* for sure.
*/
/*
* Oops, someone did already.
*/
}
/*
* receive - Receive Procedure. See section 3.4.3 in the specification.
*/
void
{
int restrict_mask;
int has_mac;
int trustable;
int is_authentic;
static u_int32 distrusted_aspiring = 0;
static struct timeval timelogged = {0, 0};
#ifdef DEBUG
if (debug > 1)
#endif
/*
* Let the monitoring software take a look at this first.
*/
/*
* Get the restrictions on this guy. If we're to ignore him,
* go no further.
*/
if (restrict_mask & RES_IGNORE)
return;
/*
* Get a pointer to the packet.
*/
/*
* Catch packets whose version number we can't deal with
*/
} else {
return;
}
/*
* Catch private mode packets. Dump it if queries not allowed.
*/
if (restrict_mask & RES_NOQUERY)
return;
return;
}
/*
* Same with control mode packets.
*/
if (restrict_mask & RES_NOQUERY)
return;
return;
}
/*
* See if we're allowed to serve this guy time. If we don't serve him,
* and if the packet is a request, ignore it. However, if this guy is
* telling us the time, we might pay attention.
*/
if ((restrict_mask & RES_DONTSERVE) &&
return;
/*
* See if we only accept limited number of clients from the net
* this guy is from. Note: the flag is determined dynamically
* within restrictions()
*/
if (restrict_mask & RES_LIMITED) {
extern u_long client_limit;
"rejected mode %d request from %s - per net client limit (%d) exceeded",
return;
}
/*
* Dump anything with a putrid stratum. These will most likely
* come from someone trying to poll us with ntpdc.
*/
return;
}
/*
* Find the peer. This will return a null if this guy isn't in
* the database.
*/
/*
* Check the length for validity, drop the packet if it is
* not as expected. If this is a client mode poll, go no
* further. Send back his time and drop it.
*
* The scheme we use for authentication is this. If we are
* running in non-authenticated mode, we accept both frames
* which are authenticated and frames which aren't, but don't
* authenticate. We do record whether the frame had a mac field
* or not so we know what to do on output.
*
* If we are running in authenticated mode, we only trust frames
* which have authentication attached, which are validated and
* which are using one of our trusted keys. We respond to all
* other pollers without saving any state. If a host we are
* passively peering with changes his key from a trusted one to
* an untrusted one, we immediately unpeer with him, reselect
* the clock and treat him as an unmemorable client (this is
* a small denial-of-service hole I'll have to think about).
* If a similar event occurs with a configured peer we drop the
* frame and hope he'll revert to our key again. If we get a
* frame which can't be authenticated with the given key, we
* drop it. Either we disagree on the keys or someone is trying
* some funny stuff.
*/
/*
* here we assume that any packet with an authenticator is at
* least LEN_PKT_MAC bytes long, which means at least 96 bits
*/
#ifdef DEBUG
if (debug > 2)
"receive: pkt is %d octets, mac %d octets long, keyid %ld\n",
#endif
hiskeyid = 0;
has_mac = 0;
#ifdef DEBUG
if (debug > 2)
"receive: pkt is %d octets with no MAC\n",
rbufp->recv_length);
#endif
} else {
#ifdef DEBUG
if (debug > 2)
printf("receive: bad length %d %d\n",
#endif
return;
}
/*
* Figure out his mode and validate it.
*/
#ifdef DEBUG
if (debug > 2)
#endif
0) {
/*
* Easy. If it is from the NTP port it is
* a sym act, else client.
*/
else
} else {
hismode != MODE_BROADCAST) {
return;
}
}
/*
* If he included a mac field, decrypt it to see if it is
* authentic.
*/
is_authentic = 0;
if (has_mac) {
if (authhavekey(hiskeyid)) {
if (!authistrusted(hiskeyid)) {
sys_badauth++;
#ifdef DEBUG
if (debug > 3)
printf("receive: untrusted keyid\n");
#endif
return;
}
LEN_PKT_NOMAC)) {
is_authentic = 1;
#ifdef DEBUG
if (debug > 3)
printf("receive: authdecrypt succeeds\n");
#endif
} else {
sys_badauth++;
#ifdef DEBUG
if (debug > 3)
printf("receive: authdecrypt fails\n");
#endif
}
}
}
/*
* If this is someone we don't remember from a previous
* association, dispatch him now. Either we send something back
* quick, we ignore him, or we allocate some memory for him and
* let him continue.
*/
if (peer == 0) {
int mymode;
switch(hismode) {
case MODE_ACTIVE:
/*
* See if this guy qualifies as being the least
* bit memorable. If so we keep him around for
* later. If not, send his time quick.
*/
return;
}
/*
* If this guy is actively seeking to become our peer,
* authentication may be required.
*/
if (sys_authenticate && !is_authentic) {
"receive: aspiring active"
" peer not authenticated");
}
#ifdef DEBUG
if (debug > 0) {
printf("receive: aspiring active"
" peer %s [stratum %hu] not"
" authenticated;"
" %lu total attempts seen\n",
}
#endif
return;
}
break;
case MODE_PASSIVE:
case MODE_SERVER:
/*
* These are obvious errors. Ignore.
*/
return;
case MODE_CLIENT:
/*
* Send it back quick and go home.
*/
return;
case MODE_BROADCAST:
/*
* Sort of a repeat of the above...
*/
return;
break;
}
/*
* Okay, we're going to keep him around. Allocate him
* some memory.
*/
if (peer == 0) {
/*
* The only way this can happen is if the
* source address looks like a reference
* clock. Since this is an illegal address
* this is one of those "can't happen" things.
*/
"receive() failed to peer with %s, mode %d",
return;
}
}
/*
* Mark the time of reception
*/
/*
* If the peer isn't configured, set his keyid and authenable
* status based on the packet.
*/
if (has_mac) {
}
} else {
}
}
/*
* If this message was authenticated properly, note this
* in the flags.
*/
if (is_authentic) {
} else {
/*
* If this guy is authenable, and has been authenticated
* in the past, but just failed the authentic test,
* report the event.
*/
}
/*
* Determine if this guy is basically trustable.
*/
if (restrict_mask & RES_DONTTRUST)
trustable = 0;
else
trustable = 1;
if (sys_authenticate && trustable) {
if (has_mac && is_authentic)
trustable = 1;
else
trustable = 0;
}
}
/*
* Dispose of the packet based on our respective modes. We
* don't drive this with a table, though we probably could.
*/
case MODE_ACTIVE:
case MODE_CLIENT:
/*
* Active mode associations are configured. If the data
* isn't trustable, ignore it and hope this guy
* brightens up. Else accept any data we get and process
* it.
*/
switch (hismode) {
case MODE_ACTIVE:
case MODE_PASSIVE:
case MODE_SERVER:
case MODE_BROADCAST:
break;
case MODE_CLIENT:
return;
}
break;
case MODE_PASSIVE:
/*
* Passive mode associations are (in the current
* implementation) always dynamic. If we get an invalid
* header, break the connection. I hate doing this since
* it seems like a waste. Oh, well.
*/
switch (hismode) {
case MODE_ACTIVE:
clock_select();
}
break;
case MODE_PASSIVE:
case MODE_SERVER:
case MODE_BROADCAST:
/*
* These are errors. Just ignore the packet.
* If he doesn't straighten himself out this
* association will eventually be disolved.
*/
break;
case MODE_CLIENT:
return;
}
break;
case MODE_BCLIENT:
/*
* Broadcast client pseudo-mode. We accept both server
* and broadcast data. Passive mode data is an error.
*/
switch (hismode) {
case MODE_ACTIVE:
/*
* This guy wants to give us real time when
* we've been existing on lousy broadcasts!
* Create a passive mode association and do it
* that way, but keep the old one in case the
* packet turns out to be bad.
*/
/*
* Strange situation. We've been
* receiving broadcasts from him which
* we liked, but we don't like his
* active mode stuff. Keep his old peer
* structure and send him some time
* quickly, we'll figure it out later.
*/
} else
/*
* Drop the old association
*/
break;
case MODE_PASSIVE:
break;
case MODE_SERVER:
case MODE_BROADCAST:
/*
* We don't test for invalid headers.
* Let him time out.
*/
break;
}
break;
case MODE_MCLIENT:
/*
* This mode is temporary and does not appear outside
* this routine. It lasts only from the time the
* association is instantiated. Note that we start up in
* clock.
*/
switch (hismode) {
case MODE_BROADCAST:
break;
case MODE_SERVER:
case MODE_PASSIVE:
case MODE_ACTIVE:
case MODE_CLIENT:
break;
}
}
}
/*
* process_packet - Packet Procedure, a la Section 3.4.4 of the
* specification. Or almost, at least. If we're in here we have a
* reasonable expectation that we will be having a long term
* relationship with this host.
*/
int
int has_mac;
int trustable; /* used as "valid header" */
{
int randomize;
#ifdef SYS_WINNT
#endif /* SYS_WINNT */
else
/*
* Test for old or duplicate packets (tests 1 through 3).
*/
}
} else {
}
/*
* Call poll_update(). This will either start us, if the
* association is new, or drop the polling interval if the
* association is existing and ppoll has been reduced.
*/
/*
* Test for valid header (tests 5 through 8)
*/
if (trustable == 0) /* test 5 */
|| p_dist <= (-NTP_MAXDISPERSE)
|| p_disp >= NTP_MAXDISPERSE)
/*
* If the packet header is invalid (tests 5 through 8), exit
*/
#ifdef DEBUG
if (debug)
{
printf("invalid packet header %s 0x%02x %s %s\n",
printf("- peer authentication failure\n");
printf("- peer clock unsynchronized\n");
printf("- peer stratum out of bounds\n");
printf("- root delay/dispersion bounds check\n");
}
#endif
return(0);
}
/*
* Valid header; update our state.
*/
if (has_mac)
else
/*
* If this guy was previously unreachable, set his
* polling interval to the minimum and reset the
* unreach counter.
*/
}
/*
* clock offset c, roundtrip delay d and dispersion e. We use
* the equations (reordered from those in the spec). Note that,
* in a broadcast association, org has been set to the time of
* last reception. Note the computation of dispersion includes
* the system precision plus that due to the frequency error
* since the originate time.
*
* c = ((t2 - t3) + (t1 - t0)) / 2
* d = (t2 - t3) - (t1 - t0)
* e = (org - rec) (seconds only)
*/
if (precision == 0)
precision = 1;
/*
* If running in a broadcast association, the clock offset is (t1
* - t0) corrected by the one-way delay, but we can't measure
* calculate the clock offset, using the engineered refinement
* algorithms, while also receiving broadcasts. When a broadcast
* factor to use after switching back to broadcast mode. We know
* NTP_SKEWFACTOR == 16, which accounts for the simplified ei
* calculation.
*
* If FLAG_MCAST1 is set, we haven't calculated the propagation
* delay. If hmode is MODE_CLIENT, we haven't set the local
* MODE_CLIENT. When the clock is first updated and FLAG_MCAST2
* is set, we switch from MODE_CLIENT to MODE_BCLIENT.
*/
return (1);
}
} else {
}
#ifdef DEBUG
if (debug > 3)
printf("offset: %s, delay %s, error %s\n",
#endif
/*
* If the packet data is invalid (tests 1 through 4), exit.
*/
#ifdef DEBUG
if (debug > 1)
printf("invalid packet header %s 0x%02x %s %s\n",
#endif
/*
* If there was a reachability change report it even
* though the packet was bogus.
*/
if (oreach == 0)
return(1);
}
#ifdef SYS_WINNT
/* prevent timer() from fiddling with the clock at the same time as us
* by grabbing the mutex
* the mutex should be held for as small a time as possible (in order
* that the timer() routine is not blocked unneccessarily) and should
* probably be grabbed much later (in local_clock() maybe), but this
* works reasonably well too
*/
hMutex, /* handle of mutex */
5000L); /* five-second time-out interval */
switch (dwWaitResult) {
case WAIT_OBJECT_0:
/* The thread got mutex ownership. */
break;
default:
/* Cannot get mutex ownership due to time-out. */
exit(1);
}
#endif /* SYS_WINNT */
/*
* This one is valid. Mark it so, give it to clock_filter().
*/
/*
* If this guy was previously unreachable, report him reachable.
* Note we do this here so that the peer values we return are
* the updated ones.
*/
if (oreach == 0)
/*
* Now update the clock. If we have found a system peer and this
*/
#if defined(GDT_SURVEYING)
/* log the packet if it was low-delay and sane */
{
char logstr[1024];
/* ok if passed intersection test. we don't want to be
* too judgemental about peers that aren't right - just
* throw out falsetickers but not peers that have wander
* relative to average, since average may be wrong */
{
"observation: time %lu %s off %s delay %s error %s rsadj %s",
);
}
else
{
"incorrect_obs: time %lu %s off %s delay %s error %s rsadj %s",
);
#ifdef LOG_INCORRECT
#endif
}
}
#endif /* GDT_SURVEYING */
#ifdef SYS_WINNT
if (!ReleaseMutex(hMutex)) {
exit(1);
}
#endif /* SYS_WINNT */
return(1);
}
/*
* clock_update - Clock-update procedure, see section 3.4.5.
*/
void
{
s_fp d;
#ifdef DEBUG
if (debug)
#endif
/*
* Call the clock selection algorithm to see if this update
* causes the peer to change. If this is not the system peer,
* quit now.
*/
clock_select();
return;
/*
* Update the system state. This updates the system stratum,
* leap bits, root delay, root dispersion, reference ID and
* reference time. We also update select dispersion and max
* frequency error.
*/
if (sys_stratum == 1)
else
if (d < 0)
d = -d;
if (d < 0)
d = -d;
d += sys_maxd[0];
d = NTP_MINDISPERSE;
/*
*
* allow local_clock to set clock fast iff we have just left
* an unsync state (startup / regain sync).
*/
(sys_leap != LEAP_NOTINSYNC))) {
case -1:
/*
* Clock is too screwed up. Just exit for now.
*/
exit(1);
/*NOTREACHED*/
case 0:
/*
* Clock was slewed. Continue on normally.
*/
L_CLR(&sys_refskew);
break;
case 1:
/*
* Clock was stepped. Clear filter registers
* of all peers.
*/
clear_all();
leap_process(); /* reset the leap interrupt */
break;
}
if (ostratum != sys_stratum)
}
/*
* poll_update - update peer poll interval. See Section 3.4.9 of the
* spec.
*/
void
unsigned int new_hpoll;
int randomize;
{
#ifdef DEBUG
if (debug > 1)
#endif
/*
* Catch reference clocks here. The polling interval for a
* reference clock is fixed and needn't be maintained by us.
*/
return;
/*
* This routine * will randomly perturb the new peer.timer if
* requested, to try to prevent synchronization with the remote
* peer from occuring. There are three options, based on the
* value of randomize:
*
* POLL_NOTRANDOM - essentially the spec algorithm. If
* peer.timer is greater than the new polling interval,
* drop it to the new interval.
*
* POLL_RANDOMCHANGE - make changes randomly. If peer.timer
* must be changed, based on the comparison about, randomly
* perturb the new value of peer.timer.
*
* POLL_MAKERANDOM - make next interval random. Calculate
* a randomly perturbed poll interval. If this value is
*/
else {
else
}
/* hpoll <= maxpoll for sure */
if (randomize == POLL_MAKERANDOM
else
}
}
/*
* clear_all - clear all peer filter registers. This is done after
* a step change in the time.
*/
static void
{
register int i;
for (i = 0; i < HASH_SIZE; i++)
}
/*
* Clear sys_peer. We'll sync to one later.
*/
if (sys_peer)
sys_peer = 0;
}
/*
* clear - clear peer filter registers. See Section 3.4.8 of the spec.
*/
void
{
register int i;
#ifdef DEBUG
if (debug)
#endif
for (i = 0; i < NTP_SHIFT; i++)
clock_select();
/*
* Clear out the selection counters
*/
/*
* Since we have a chance to correct possible funniness in
* our selection of interfaces on a multihomed host, do so
* by setting us to no particular interface.
*/
}
/*
* clock_filter - add incoming clock sample to filter register and run
* the filter procedure to find the best sample.
*/
void
{
register int i, j, k, n;
#ifdef DEBUG
if (debug)
printf("clock_filter(%s, %s, %s, %s)\n",
#endif
/*
* Update sample errors and calculate distances. Also initialize
* sort index vector. We know NTP_SKEWFACTOR == 16
*/
j = peer->filter_nextpt;
for (i = 0; i < NTP_SHIFT; i++) {
ord[i] = j;
if (--j < 0)
j += NTP_SHIFT;
}
#if defined(GDT_SURVEYING)
/* only log here if directly-connected reference clock */
{
char logstr[1024];
"observation: time %lu %s off %s delay %s error %s rsadj %s",
);
}
#endif /* GDT_SURVEYING */
/*
* Insert the new sample at the beginning of the register.
*/
/*
* Sort the samples in the register by distance. The winning
* sample will be in ord[0]. Sort the samples only if the
* samples are not too old and the delay is meaningful.
*/
skewmax = 0;
for (n = 0; n < NTP_SHIFT && sample_delay; n++) {
for (j = 0; j < n && skewmax < CLOCK_MAXSEC; j++) {
k = ord[n];
ord[j] = k;
}
}
}
peer->filter_nextpt++;
peer->filter_nextpt = 0;
/*
* We compute the dispersion as per the spec. Note that, to make
* things simple, both the l_fp and s_fp offsets are retained
* and that the s_fp could be nonsense if the l_fp is greater
* than about 32000 s. The s_fp is used only for dispersion and
* display purposes and anything greater than that is clamped
* by the l_fp -> s_fp conversion.
*/
} else {
s_fp d;
u_fp y;
y = 0;
for (i = NTP_SHIFT - 1; i > 0; i--) {
d = NTP_MAXDISPERSE;
else {
if (d < 0)
d = -d;
if (d > NTP_MAXDISPERSE)
d = NTP_MAXDISPERSE;
}
/*
* XXX This *knows* NTP_FILTER is 1/2
*/
y = ((u_fp)d + y) >> 1;
}
peer->dispersion += y;
/*
* Calculate synchronization distance backdated to
* sys_lastselect (clock_select will fix it). We know
* NTP_SKEWFACTOR == 16.
*/
if (d < 0)
d = -d;
}
}
/*
* clock_select - find the pick-of-the-litter clock
*/
void
{
int i;
u_fp c, d;
l_fp e, f;
int j;
int n;
struct peer *typeprefer = 0;
struct peer *typesystem = 0;
static int list_alloc = 0;
static int *index;
#ifdef DEBUG
if (debug > 1)
printf("clock_select()\n");
#endif
/*
* Initizialize. If a prefer peer does not survive this thing,
* the pps_update switch will remain zero.
*/
pps_update = 0;
nlist = 0;
for (n = 0; n < HASH_SIZE; n++)
nlist += peer_hash_count[n];
if (nlist > list_alloc) {
if (list_alloc > 0) {
}
while (list_alloc < nlist) {
list_alloc += 5;
}
}
/*
* This first chunk of code is supposed to go through all
* peers we know about to find the NTP_MAXLIST peers which
* are most likely to succeed. We run through the list
* doing the sanity checks and trying to insert anyone who
* looks okay. We are at all times aware that we should
* only keep samples from the top two strata and we only need
* NTP_MAXLIST of them.
*/
for (n = 0; n < HASH_SIZE; n++) {
/*
* Clear peer selection stats
*/
/*
* Update synch distance (NTP_SKEWFACTOR == 16).
* Note synch distance check instead of spec
* dispersion check. Naughty.
*/
continue; /* unreachable */
continue; /* sync loop */
continue; /* bad stratum */
peer->seldisptoolarge++;
continue; /* too noisy or broken */
}
continue; /* very broken host */
}
/*
* Don't allow the local-clock or acts drivers
* in the kitchen at this point, unless the
* prefer peer. Do that later, but only if
* nobody else is around.
*/
#if defined(VMS) && defined(VMS_LOCALUNIT)
/* wjm: local unit VMS_LOCALUNIT taken seriously */
#else /* VMS && VMS_LOCALUNIT */
#endif /* VMS && VMS_LOCALUNIT */
continue; /* no local clock */
}
continue; /* no acts */
}
/*
* If we get this far, we assume the peer is
* acceptable.
*/
/*
* Insert each interval endpoint on the sorted
* list.
*/
L_ADD(&e, &f);
for (i = nl3 - 1; i >= 0; i--) {
break;
}
L_SUB(&e, &f); /* Center point */
for ( ; i >= 0; i--) {
break;
}
L_SUB(&e, &f); /* Lower end */
for ( ; i >= 0; i--) {
break;
}
}
}
#ifdef DEBUG
if (debug > 2)
for (i = 0; i < nl3; i++)
printf("select: endpoint %2d %s\n",
#endif
i = 0;
j = nl3 - 1;
found = 0;
while (allow > 0) {
allow--;
for (n = 0; i <= j; i++) {
if (n < 0)
break;
found++;
}
for (n = 0; i <= j; j--) {
if (n > 0)
break;
found++;
}
break;
}
/*
* If no survivors remain at this point, check if the acts or
* local clock drivers have been found. If so, nominate one of
* them as the only survivor. Otherwise, give up and declare us
* unsynchronized.
*/
if (typeacts != 0) {
nlist = 1;
} else if (typelocal != 0) {
nlist = 1;
} else {
if (sys_peer != 0) {
}
sys_peer = 0;
return;
}
}
#ifdef DEBUG
if (debug > 2)
#endif
/*
* Clustering algorithm. Process intersection list to discard
* outlyers. Construct candidate list in cluster order
* determined by the sum of peer synchronization distance plus
* scaled stratum. We must find at least one peer.
*/
j = 0;
for (i = 0; i < nlist; i++) {
continue;
if (j >= NTP_MAXCLOCK) {
if (d >= synch[j - 1])
continue;
else
j--;
}
for (k = j; k > 0; k--) {
if (d >= synch[k - 1])
break;
}
synch[k] = d;
j++;
}
nlist = j;
#ifdef DEBUG
if (debug > 2)
for (i = 0; i < nlist; i++)
printf("select: candidate %s cdist %s\n",
#endif
/*
* Now, prune outlyers by root dispersion. Continue as long as
* there are more than NTP_MINCLOCK survivors and the minimum
* select dispersion is greater than the maximum peer
* dispersion. Stop if we are about to discard a preferred peer.
*/
for (i = 0; i < nlist; i++) {
peer_list[i]->dispersion +
}
while (1) {
maxd = 0;
c = 0;
d = error[0];
for (k = i = nlist - 1; i >= 0; i--) {
for (j = nlist - 1; j > 0; j--) {
if (L_ISNEG(&e))
L_NEG(&e);
c = LFPTOFP(&e);
sdisp += c;
}
k = i;
}
if (error[i] < d)
d = error[i];
}
break;
for (j = k + 1; j < nlist; j++) {
}
nlist--;
}
#ifdef DEBUG
if (debug > 1) {
for (i = 0; i < nlist; i++)
printf("select: survivor %s offset %s, cdist %s\n",
}
#endif
/*
* What remains is a list of not greater than NTP_MINCLOCK
* peers. We want only a peer at the lowest stratum to become
* the system peer, although all survivors are eligible for the
* combining algorithm. First record their order, diddle the
* flags and clamp the poll intervals. Then, consider the peers
* at the lowest stratum. Of these, OR the leap bits on the
* assumption that, if some of them honk nonzero bits, they must
* know what they are doing. Also, check for prefer and pps
* peers. If a prefer peer is found within CLOCK_MAX, update the
* pps switch. Of the other peers not at the lowest stratum,
* check if the system peer is among them and, if found, zap
* him. We note that the head of the list is at the lowest
* stratum and that unsynchronized peers cannot survive this
* far.
*/
leap_consensus = 0;
for (i = nlist - 1; i >= 0; i--) {
typesystem = peer_list[i];
typeprefer = peer_list[i];
pps_update = 1;
}
} else {
sys_peer = 0;
}
}
/*
* Mitigation rules of the game. There are several types of
* peers that make a difference here: (1) prefer local peers
* (type REFCLK_LOCALCLOCK with FLAG_PREFER) or prefer modem
* peers (type REFCLK_NIST_ATOM etc with FLAG_PREFER), (2) pps peers
* (type REFCLK_ATOM_PPS), (3) remaining prefer peers (flag
* FLAG_PREFER), (4) the existing system peer, if any, (5) the
* head of the survivor list. Note that only one peer can be
* declared prefer. The order of preference is in the order
* stated. Note that all of these must be at the lowest stratum,
* i.e., the stratum of the head of the survivor list.
*/
sys_peer->selectdisp = 0;
#ifdef DEBUG
if (debug)
printf("select: prefer offset %s\n",
#endif
sys_peer->selectdisp = 0;
if (!pps_control)
#ifdef DEBUG
if (debug)
printf("select: pps offset %s\n",
#endif
} else {
if (!typesystem)
#ifdef DEBUG
if (debug)
printf("select: combine offset %s\n",
#endif
}
/*
* If we got a new system peer from all of this, report the
* event and clamp the system poll interval.
*/
char *src;
#ifdef REFCLOCK
else
#endif
}
}
/*
* clock_combine - combine offsets from selected peers
*
* Note: this routine uses only those peers at the lowest stratum.
* Strictly speaking, this is at variance with the spec.
*/
void
int npeers;
{
register int i, j, k;
register u_fp a, b, d;
/*
* Sort the offsets by synch distance.
*/
k = 0;
for (i = 0; i < npeers; i++) {
continue;
for (j = k; j > 0; j--) {
if (synch[j - 1] <= d)
break;
}
synch[j] = d;
k++;
}
/*
* Succesively combine the two offsets with the highest
* distance and enter the result into the sorted list.
*/
for (i = k - 2; i >= 0; i--) {
/*
* The possible weights for the most distant offset
* are 1/2, 1/4, 1/8 and zero. We combine the synch
* distances as if they were variances of the offsets;
* the given weights allow us to stay within 16/15 of
* the optimum combined variance at each step, and
* within 8/7 on any series.
*
* The breakeven points for the weigths are found
* where the smaller distance is 3/8, 3/16 and 1/16
* of the sum, respectively.
*/
d = synch[i];
b = a>>1; /* (d1+d2)/8 */
if (d <= (b>>1)) /* d1 <= (d1+d2)/16 */
/*
* Below 1/16, no combination is done,
* we just drop the distant offset.
*/
continue;
/*
* The offsets are combined by shifting their
* difference the appropriate number of times and
* adding it back in.
*/
if (d >= a + b) { /* d1 >= 3(d1+d2)/8 */
/*
* Above 3/8, the weight is 1/2, and the
* combined distance is (d1+d2)/4
*/
d = a;
} else {
a >>= 2; /* (d1+d2)/16 */
if (d >= a + b) { /* d1 >= 3(d1+d2)/16 */
/*
* Between 3/16 and 3/8, the weight
* is 1/4, and the combined distance
* is (9d1+d2)/16 = d1/2 + (d1+d2)/16
*/
d = (d>>1) + a;
} else {
/*
* Between 1/16 and 3/16, the weight
* is 1/8, and the combined distance
* is (49d1+d2)/64 = 3d1/4+(d1+d2)/64
* (We know d > a, so the shift is safe).
*/
d -= (d - a)>>2;
}
}
/*
* Now we can make the combined offset and insert it
* in the list.
*/
for (j = i; j > 0; j--) {
if (d >= synch[j - 1])
break;
}
synch[j] = d;
}
/*
* The result is put where clock_update() can find it.
*/
sys_offset = coffset[0];
}
/*
* fast_xmit - fast path send for stateless (non-)associations
*/
void
int rmode;
int authentic;
{
int docrypt = 0;
#ifdef DEBUG
if (debug > 1)
printf("fast_xmit(%s, %d)\n",
#endif
/*
* Make up new packet and send it quick
*/
if (rmode == MODE_ACTIVE)
else
xmode = MODE_SERVER;
if (authentic)
}
if (precision == 0)
precision = 1;
/*
* If we are encrypting, do it. Else don't. Easy.
*/
if (docrypt) {
int maclen;
else
LEN_PKT_NOMAC + maclen);
#ifdef DEBUG
if (debug > 1)
printf("transmit auth to %s %s\n",
#endif
} else {
/*
* Get xmt timestamp, then send it without mac field
*/
}
}
/*
* Find the precision of this particular machine
*/
/*
* This routine calculates the differences between successive calls to
* gettimeofday(). If a difference is less than zero, the us field
* has rolled over to the next second, so we add a second in us. If
* the difference is greater than zero and less than MINSTEP, the
* clock has been advanced by a small amount to avoid standing still.
* If the clock has advanced by a greater amount, then a timer interrupt
* has occurred and this amount represents the precision of the clock.
* In order to guard against spurious values, which could occur if we
* happen to hit a fat interrupt, we do this for MINLOOPS times and
* keep the minimum value obtained.
*/
int default_get_precision()
{
struct timezone {
int tz_minuteswest;
int tz_dsttime;
} tzp;
#endif /* defined(VMS) || defined(_SEQUENT_) */
long last;
int i;
long diff;
long val;
long usec;
#ifdef HAVE_GETCLOCK
#endif
usec = 0;
#ifdef HAVE_GETCLOCK
#else /* not HAVE_GETCLOCK */
#endif /* not HAVE_GETCLOCK */
#ifdef HAVE_GETCLOCK
#else /* not HAVE_GETCLOCK */
#endif /* not HAVE_GETCLOCK */
if (diff < 0)
i++;
}
}
diff >>= 1;
return (i);
}
/*
* init_proto - initialize the protocol module's data
*/
void
{
/*
* Fill in the sys_* stuff. Default is don't listen to
* broadcasting, authenticate.
*/
sys_rootdelay = 0;
sys_rootdispersion = 0;
sys_refid = 0;
L_CLR(&sys_reftime);
sys_peer = 0;
get_systime(&dummy);
sys_bclient = 0;
sys_authenticate = 0;
sys_stattime = 0;
sys_badstratum = 0;
sys_oldversionpkt = 0;
sys_newversionpkt = 0;
sys_badlength = 0;
sys_unknownversion = 0;
sys_processed = 0;
sys_badauth = 0;
/*
* Default these to enable
*/
pll_enable = 1;
stats_control = 1;
}
/*
* proto_config - configure the protocol module
*/
void
int item;
{
/*
* Figure out what he wants to change, then do it
*/
switch (item) {
case PROTO_PLL:
/*
*/
pll_enable = (int)value;
break;
case PROTO_PPS:
/*
*/
pps_enable = (int)value;
break;
case PROTO_MONITOR:
/*
*/
if (value)
else
break;
case PROTO_FILEGEN:
/*
*/
stats_control = (int)value;
break;
case PROTO_BROADCLIENT:
/*
*/
sys_bclient = (int)value;
if (value)
else
break;
case PROTO_MULTICAST_ADD:
/*
* Add muliticast group address
*/
sys_bclient = 1;
break;
case PROTO_MULTICAST_DEL:
/*
* Delete multicast group address
*/
sys_bclient = 1;
break;
case PROTO_BROADDELAY:
/*
* Set default broadcast delay (s_fp)
*/
if (sys_bdelay < 0)
else
break;
case PROTO_AUTHENTICATE:
/*
* Specify the use of authenticated data
*/
sys_authenticate = (int)value;
break;
default:
/*
* Log this error
*/
break;
}
}
/*
* proto_clr_stats - clear protocol stat counters
*/
void
{
sys_badstratum = 0;
sys_oldversionpkt = 0;
sys_newversionpkt = 0;
sys_unknownversion = 0;
sys_badlength = 0;
sys_processed = 0;
sys_badauth = 0;
sys_limitrejected = 0;
}