ntp_proto.c revision 54359
154359Sroberto/* 254359Sroberto * ntp_proto.c - NTP version 4 protocol machinery 354359Sroberto */ 454359Sroberto#ifdef HAVE_CONFIG_H 554359Sroberto#include <config.h> 654359Sroberto#endif 754359Sroberto 854359Sroberto#include <stdio.h> 954359Sroberto#include <sys/types.h> 1054359Sroberto#include <sys/time.h> 1154359Sroberto 1254359Sroberto#include "ntpd.h" 1354359Sroberto#include "ntp_stdlib.h" 1454359Sroberto#include "ntp_unixtime.h" 1554359Sroberto#include "ntp_control.h" 1654359Sroberto#include "ntp_string.h" 1754359Sroberto 1854359Sroberto#if defined(VMS) && defined(VMS_LOCALUNIT) /*wjm*/ 1954359Sroberto#include "ntp_refclock.h" 2054359Sroberto#endif 2154359Sroberto 2254359Sroberto#if defined(__FreeBSD__) && __FreeBSD__ >= 3 2354359Sroberto#include <sys/sysctl.h> 2454359Sroberto#endif 2554359Sroberto 2654359Sroberto/* 2754359Sroberto * System variables are declared here. See Section 3.2 of the 2854359Sroberto * specification. 2954359Sroberto */ 3054359Srobertou_char sys_leap; /* system leap indicator */ 3154359Srobertou_char sys_stratum; /* stratum of system */ 3254359Srobertos_char sys_precision; /* local clock precision */ 3354359Srobertodouble sys_rootdelay; /* distance to current sync source */ 3454359Srobertodouble sys_rootdispersion; /* dispersion of system clock */ 3554359Srobertou_int32 sys_refid; /* reference source for local clock */ 3654359Srobertostatic double sys_offset; /* current local clock offset */ 3754359Srobertol_fp sys_reftime; /* time we were last updated */ 3854359Srobertostruct peer *sys_peer; /* our current peer */ 3954359Srobertou_long sys_automax; /* maximum session key lifetime */ 4054359Sroberto 4154359Sroberto/* 4254359Sroberto * Nonspecified system state variables. 4354359Sroberto */ 4454359Srobertoint sys_bclient; /* we set our time to broadcasts */ 4554359Srobertodouble sys_bdelay; /* broadcast client default delay */ 4654359Srobertoint sys_authenticate; /* requre authentication for config */ 4754359Srobertol_fp sys_authdelay; /* authentication delay */ 4854359Srobertostatic u_long sys_authdly[2]; /* authentication delay shift reg */ 4954359Srobertostatic u_char leap_consensus; /* consensus of survivor leap bits */ 5054359Srobertostatic double sys_maxd; /* select error (squares) */ 5154359Srobertostatic double sys_epsil; /* system error (squares) */ 5254359Srobertou_long sys_private; /* private value for session seed */ 5354359Srobertoint sys_manycastserver; /* 1 => respond to manycast client pkts */ 5454359Sroberto 5554359Sroberto/* 5654359Sroberto * Statistics counters 5754359Sroberto */ 5854359Srobertou_long sys_stattime; /* time when we started recording */ 5954359Srobertou_long sys_badstratum; /* packets with invalid stratum */ 6054359Srobertou_long sys_oldversionpkt; /* old version packets received */ 6154359Srobertou_long sys_newversionpkt; /* new version packets received */ 6254359Srobertou_long sys_unknownversion; /* don't know version packets */ 6354359Srobertou_long sys_badlength; /* packets with bad length */ 6454359Srobertou_long sys_processed; /* packets processed */ 6554359Srobertou_long sys_badauth; /* packets dropped because of auth */ 6654359Srobertou_long sys_limitrejected; /* pkts rejected due to client count per net */ 6754359Sroberto 6854359Srobertostatic double root_distance P((struct peer *)); 6954359Srobertostatic double clock_combine P((struct peer **, int)); 7054359Srobertostatic void peer_xmit P((struct peer *)); 7154359Srobertostatic void fast_xmit P((struct recvbuf *, int, u_long)); 7254359Srobertostatic void clock_update P((void)); 7354359Sroberto#ifdef MD5 7454359Srobertostatic void make_keylist P((struct peer *)); 7554359Sroberto#endif /* MD5 */ 7654359Sroberto 7754359Sroberto/* 7854359Sroberto * transmit - Transmit Procedure. See Section 3.4.2 of the 7954359Sroberto * specification. 8054359Sroberto */ 8154359Srobertovoid 8254359Srobertotransmit( 8354359Sroberto struct peer *peer /* peer structure pointer */ 8454359Sroberto ) 8554359Sroberto{ 8654359Sroberto int hpoll; 8754359Sroberto 8854359Sroberto hpoll = peer->hpoll; 8954359Sroberto if (peer->burst == 0) { 9054359Sroberto u_char oreach; 9154359Sroberto 9254359Sroberto /* 9354359Sroberto * Determine reachability and diddle things if we 9454359Sroberto * haven't heard from the host for a while. If the peer 9554359Sroberto * is not configured and not likely to stay around, 9654359Sroberto * we exhaust it. 9754359Sroberto */ 9854359Sroberto oreach = peer->reach; 9954359Sroberto if (oreach & 0x01) 10054359Sroberto peer->valid++; 10154359Sroberto if (oreach & 0x80) 10254359Sroberto peer->valid--; 10354359Sroberto if (!(peer->flags & FLAG_CONFIG) && 10454359Sroberto peer->valid > NTP_SHIFT / 2 && (peer->reach & 0x80) && 10554359Sroberto peer->status < CTL_PST_SEL_SYNCCAND) 10654359Sroberto peer->reach = 0; 10754359Sroberto peer->reach <<= 1; 10854359Sroberto if (peer->reach == 0) { 10954359Sroberto 11054359Sroberto /* 11154359Sroberto * If this is an uncofigured association and 11254359Sroberto * has become unreachable, demobilize it. 11354359Sroberto */ 11454359Sroberto if (oreach != 0) { 11554359Sroberto report_event(EVNT_UNREACH, peer); 11654359Sroberto peer->timereachable = current_time; 11754359Sroberto peer_clear(peer); 11854359Sroberto if (!(peer->flags & FLAG_CONFIG)) { 11954359Sroberto unpeer(peer); 12054359Sroberto return; 12154359Sroberto } 12254359Sroberto } 12354359Sroberto 12454359Sroberto /* 12554359Sroberto * We would like to respond quickly when the 12654359Sroberto * peer comes back to life. If the probes since 12754359Sroberto * becoming unreachable are less than 12854359Sroberto * NTP_UNREACH, clamp the poll interval to the 12954359Sroberto * minimum. In order to minimize the network 13054359Sroberto * traffic, the interval gradually ramps up the 13154359Sroberto * the maximum after that. 13254359Sroberto */ 13354359Sroberto peer->ppoll = peer->maxpoll; 13454359Sroberto if (peer->unreach < NTP_UNREACH) { 13554359Sroberto if (peer->hmode == MODE_CLIENT) 13654359Sroberto peer->unreach++; 13754359Sroberto hpoll = peer->minpoll; 13854359Sroberto } else { 13954359Sroberto hpoll++; 14054359Sroberto } 14154359Sroberto if (peer->flags & FLAG_BURST) 14254359Sroberto peer->burst = 2; 14354359Sroberto 14454359Sroberto } else { 14554359Sroberto 14654359Sroberto /* 14754359Sroberto * Here the peer is reachable. If there is no 14854359Sroberto * system peer or if the stratum of the system 14954359Sroberto * peer is greater than this peer, clamp the 15054359Sroberto * poll interval to the minimum. If less than 15154359Sroberto * two samples are in the reachability register, 15254359Sroberto * reduce the interval; if more than six samples 15354359Sroberto * are in the register, increase the interval. 15454359Sroberto */ 15554359Sroberto peer->unreach = 0; 15654359Sroberto if (sys_peer == 0) 15754359Sroberto hpoll = peer->minpoll; 15854359Sroberto else if (sys_peer->stratum > peer->stratum) 15954359Sroberto hpoll = peer->minpoll; 16054359Sroberto if ((peer->reach & 0x03) == 0) { 16154359Sroberto clock_filter(peer, 0., 0., MAXDISPERSE); 16254359Sroberto clock_select(); 16354359Sroberto } 16454359Sroberto if (peer->valid <= 2) 16554359Sroberto hpoll--; 16654359Sroberto else if (peer->valid >= NTP_SHIFT - 2) 16754359Sroberto hpoll++; 16854359Sroberto if (peer->flags & FLAG_BURST) 16954359Sroberto peer->burst = NTP_SHIFT; 17054359Sroberto } 17154359Sroberto } else { 17254359Sroberto peer->burst--; 17354359Sroberto if (peer->burst == 0) { 17454359Sroberto if (peer->flags & FLAG_MCAST2) { 17554359Sroberto peer->flags &= ~FLAG_BURST; 17654359Sroberto peer->hmode = MODE_BCLIENT; 17754359Sroberto } 17854359Sroberto clock_select(); 17954359Sroberto poll_update(peer, hpoll); 18054359Sroberto return; 18154359Sroberto } 18254359Sroberto } 18354359Sroberto 18454359Sroberto /* 18554359Sroberto * We need to be very careful about honking uncivilized time. If 18654359Sroberto * not operating in broadcast mode, honk in all except broadcast 18754359Sroberto * client mode. If operating in broadcast mode and synchronized 18854359Sroberto * to a real source, honk except when the peer is the local- 18954359Sroberto * clock driver and the prefer flag is not set. In other words, 19054359Sroberto * in broadcast mode we never honk unless known to be 19154359Sroberto * synchronized to real time. 19254359Sroberto */ 19354359Sroberto if (peer->hmode != MODE_BROADCAST) { 19454359Sroberto if (peer->hmode != MODE_BCLIENT) 19554359Sroberto peer_xmit(peer); 19654359Sroberto } else if (sys_peer != 0 && sys_leap != LEAP_NOTINSYNC) { 19754359Sroberto if (!(sys_peer->refclktype == REFCLK_LOCALCLOCK && 19854359Sroberto !(sys_peer->flags & FLAG_PREFER))) 19954359Sroberto peer_xmit(peer); 20054359Sroberto } 20154359Sroberto peer->outdate = current_time; 20254359Sroberto poll_update(peer, hpoll); 20354359Sroberto} 20454359Sroberto 20554359Sroberto/* 20654359Sroberto * receive - Receive Procedure. See section 3.4.3 in the specification. 20754359Sroberto */ 20854359Srobertovoid 20954359Srobertoreceive( 21054359Sroberto struct recvbuf *rbufp 21154359Sroberto ) 21254359Sroberto{ 21354359Sroberto register struct peer *peer; 21454359Sroberto register struct pkt *pkt; 21554359Sroberto int hismode; 21654359Sroberto int oflags; 21754359Sroberto int restrict_mask; 21854359Sroberto int has_mac; /* has MAC field */ 21954359Sroberto int authlen; /* length of MAC field */ 22054359Sroberto int is_authentic; /* cryptosum ok */ 22154359Sroberto int is_mystic; /* session key exists */ 22254359Sroberto int is_error; /* parse error */ 22354359Sroberto/* u_long pkeyid; */ 22454359Sroberto u_long skeyid, tkeyid; 22554359Sroberto struct peer *peer2; 22654359Sroberto int retcode = AM_NOMATCH; 22754359Sroberto 22854359Sroberto /* 22954359Sroberto * Monitor the packet and get restrictions 23054359Sroberto */ 23154359Sroberto ntp_monitor(rbufp); 23254359Sroberto restrict_mask = restrictions(&rbufp->recv_srcadr); 23354359Sroberto#ifdef DEBUG 23454359Sroberto if (debug > 1) 23554359Sroberto printf("receive: from %s restrict %02x\n", 23654359Sroberto ntoa(&rbufp->recv_srcadr), restrict_mask); 23754359Sroberto#endif 23854359Sroberto if (restrict_mask & RES_IGNORE) 23954359Sroberto return; 24054359Sroberto 24154359Sroberto /* 24254359Sroberto * Discard packets with invalid version number. 24354359Sroberto */ 24454359Sroberto pkt = &rbufp->recv_pkt; 24554359Sroberto if (PKT_VERSION(pkt->li_vn_mode) >= NTP_VERSION) 24654359Sroberto sys_newversionpkt++; 24754359Sroberto else if (PKT_VERSION(pkt->li_vn_mode) >= NTP_OLDVERSION) 24854359Sroberto sys_oldversionpkt++; 24954359Sroberto else { 25054359Sroberto sys_unknownversion++; 25154359Sroberto return; 25254359Sroberto } 25354359Sroberto 25454359Sroberto /* 25554359Sroberto * Restrict control/private mode packets. Note that packet 25654359Sroberto * length has to be checked in the control/private mode protocol 25754359Sroberto * module. 25854359Sroberto */ 25954359Sroberto if (PKT_MODE(pkt->li_vn_mode) == MODE_PRIVATE) { 26054359Sroberto if (restrict_mask & RES_NOQUERY) 26154359Sroberto return; 26254359Sroberto process_private(rbufp, ((restrict_mask & RES_NOMODIFY) == 26354359Sroberto 0)); 26454359Sroberto return; 26554359Sroberto } 26654359Sroberto if (PKT_MODE(pkt->li_vn_mode) == MODE_CONTROL) { 26754359Sroberto if (restrict_mask & RES_NOQUERY) 26854359Sroberto return; 26954359Sroberto process_control(rbufp, restrict_mask); 27054359Sroberto return; 27154359Sroberto } 27254359Sroberto 27354359Sroberto /* 27454359Sroberto * Restrict revenue packets. 27554359Sroberto */ 27654359Sroberto if (restrict_mask & RES_DONTSERVE) 27754359Sroberto return; 27854359Sroberto 27954359Sroberto /* 28054359Sroberto * See if we only accept limited number of clients from the net 28154359Sroberto * this guy is from. Note: the flag is determined dynamically 28254359Sroberto * within restrictions() 28354359Sroberto */ 28454359Sroberto if (restrict_mask & RES_LIMITED) { 28554359Sroberto sys_limitrejected++; 28654359Sroberto return; 28754359Sroberto } 28854359Sroberto 28954359Sroberto /* 29054359Sroberto * If we are not a broadcast client, ignore broadcast packets. 29154359Sroberto */ 29254359Sroberto if ((PKT_MODE(pkt->li_vn_mode) == MODE_BROADCAST && !sys_bclient)) 29354359Sroberto return; 29454359Sroberto 29554359Sroberto /* 29654359Sroberto * This is really awful ugly. We figure out whether an extension 29754359Sroberto * field is present and then measure the MAC size. If the number 29854359Sroberto * of words following the packet header is less than or equal to 29954359Sroberto * 5, no extension field is present and these words constitute the 30054359Sroberto * MAC. If the number of words is greater than 5, an extension 30154359Sroberto * field is present and the first word contains the length of 30254359Sroberto * the extension field and the MAC follows that. 30354359Sroberto */ 30454359Sroberto has_mac = 0; 30554359Sroberto/* pkeyid = 0; */ 30654359Sroberto skeyid = tkeyid = 0; 30754359Sroberto authlen = LEN_PKT_NOMAC; 30854359Sroberto has_mac = rbufp->recv_length - authlen; 30954359Sroberto if (has_mac <= 5 * sizeof(u_int32)) { 31054359Sroberto skeyid = (u_long)ntohl(pkt->keyid1) & 0xffffffff; 31154359Sroberto } else { 31254359Sroberto authlen += (u_long)ntohl(pkt->keyid1) & 0xffffffff; 31354359Sroberto has_mac = rbufp->recv_length - authlen; 31454359Sroberto if (authlen <= 0) { 31554359Sroberto sys_badlength++; 31654359Sroberto return; 31754359Sroberto } 31854359Sroberto 31954359Sroberto /* 32054359Sroberto * Note that keyid3 is actually the key ident of the 32154359Sroberto * MAC itself. 32254359Sroberto */ 32354359Sroberto/* pkeyid = (u_long)ntohl(pkt->keyid2) & 0xffffffff; */ 32454359Sroberto skeyid = tkeyid = (u_long)ntohl(pkt->keyid3) & 0xffffffff; 32554359Sroberto } 32654359Sroberto 32754359Sroberto /* 32854359Sroberto * Figure out his mode and validate it. 32954359Sroberto */ 33054359Sroberto hismode = (int)PKT_MODE(pkt->li_vn_mode); 33154359Sroberto if (PKT_VERSION(pkt->li_vn_mode) == NTP_OLDVERSION && hismode == 33254359Sroberto 0) { 33354359Sroberto /* 33454359Sroberto * Easy. If it is from the NTP port it is 33554359Sroberto * a sym act, else client. 33654359Sroberto */ 33754359Sroberto if (SRCPORT(&rbufp->recv_srcadr) == NTP_PORT) 33854359Sroberto hismode = MODE_ACTIVE; 33954359Sroberto else 34054359Sroberto hismode = MODE_CLIENT; 34154359Sroberto } else { 34254359Sroberto if (hismode != MODE_ACTIVE && hismode != MODE_PASSIVE && 34354359Sroberto hismode != MODE_SERVER && hismode != MODE_CLIENT && 34454359Sroberto hismode != MODE_BROADCAST) 34554359Sroberto return; 34654359Sroberto } 34754359Sroberto 34854359Sroberto /* 34954359Sroberto * If he included a mac field, decrypt it to see if it is 35054359Sroberto * authentic. 35154359Sroberto */ 35254359Sroberto is_authentic = is_mystic = 0; 35354359Sroberto if (has_mac == 0) { 35454359Sroberto#ifdef DEBUG 35554359Sroberto if (debug) 35654359Sroberto printf("receive: at %ld from %s mode %d\n", 35754359Sroberto current_time, ntoa(&rbufp->recv_srcadr), 35854359Sroberto hismode); 35954359Sroberto#endif 36054359Sroberto } else { 36154359Sroberto is_mystic = authistrusted(skeyid); 36254359Sroberto#ifdef MD5 36354359Sroberto if (skeyid > NTP_MAXKEY && !is_mystic) { 36454359Sroberto 36554359Sroberto /* 36654359Sroberto * For multicast mode, generate the session key 36754359Sroberto * and install in the key cache. For client mode, 36854359Sroberto * generate the session key for the unicast 36954359Sroberto * address. For server mode, the session key should 37054359Sroberto * already be in the key cache, since it was 37154359Sroberto * generated when the last request was sent. 37254359Sroberto */ 37354359Sroberto if (hismode == MODE_BROADCAST) { 37454359Sroberto tkeyid = session_key( 37554359Sroberto ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), 37654359Sroberto ntohl(rbufp->dstadr->bcast.sin_addr.s_addr), 37754359Sroberto skeyid, (u_long)(4 * (1 << pkt->ppoll))); 37854359Sroberto } else if (hismode != MODE_SERVER) { 37954359Sroberto tkeyid = session_key( 38054359Sroberto ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), 38154359Sroberto ntohl(rbufp->dstadr->sin.sin_addr.s_addr), 38254359Sroberto skeyid, (u_long)(4 * (1 << pkt->ppoll))); 38354359Sroberto } 38454359Sroberto 38554359Sroberto } 38654359Sroberto#endif /* MD5 */ 38754359Sroberto 38854359Sroberto /* 38954359Sroberto * Compute the cryptosum. Note a clogging attack may 39054359Sroberto * succceed in bloating the key cache. 39154359Sroberto */ 39254359Sroberto if (authdecrypt(skeyid, (u_int32 *)pkt, authlen, has_mac)) 39354359Sroberto is_authentic = 1; 39454359Sroberto else 39554359Sroberto sys_badauth++; 39654359Sroberto#ifdef DEBUG 39754359Sroberto if (debug) 39854359Sroberto printf( 39954359Sroberto "receive: at %ld %s mode %d keyid %08lx mac %d auth %d\n", 40054359Sroberto current_time, ntoa(&rbufp->recv_srcadr), 40154359Sroberto hismode, skeyid, has_mac, is_authentic); 40254359Sroberto#endif 40354359Sroberto } 40454359Sroberto 40554359Sroberto /* 40654359Sroberto * Find the peer. This will return a null if this guy isn't in 40754359Sroberto * the database. 40854359Sroberto */ 40954359Sroberto peer = findpeer(&rbufp->recv_srcadr, rbufp->dstadr, rbufp->fd, 41054359Sroberto hismode, &retcode); 41154359Sroberto /* 41254359Sroberto * The new association matching rules are driven by a table specified 41354359Sroberto * in ntp.h. We have replaced the *default* behaviour of replying 41454359Sroberto * to bogus packets in server mode in this version. 41554359Sroberto * A packet must now match an association in order to be processed. 41654359Sroberto * In the event that no association exists, then an association is 41754359Sroberto * mobilized if need be. Two different associations can be mobilized 41854359Sroberto * a) passive associations 41954359Sroberto * b) client associations due to broadcasts or manycasts. 42054359Sroberto */ 42154359Sroberto is_error = 0; 42254359Sroberto switch (retcode) { 42354359Sroberto case AM_FXMIT: 42454359Sroberto /* 42554359Sroberto * If the client is configured purely as a broadcast client and 42654359Sroberto * not as an manycast server, it has no business being a server. 42754359Sroberto * Simply go home. Otherwise, send a MODE_SERVER response and go 42854359Sroberto * home. Note that we don't do a authentication check here, 42954359Sroberto * since we can't set the system clock; but, we do set the 43054359Sroberto * key ID to zero to tell the caller about this. 43154359Sroberto */ 43254359Sroberto if (!sys_bclient || sys_manycastserver) { 43354359Sroberto if (is_authentic) 43454359Sroberto fast_xmit(rbufp, MODE_SERVER, skeyid); 43554359Sroberto else 43654359Sroberto fast_xmit(rbufp, MODE_SERVER, 0); 43754359Sroberto } 43854359Sroberto 43954359Sroberto /* 44054359Sroberto * We can't get here if an association is mobilized, so just 44154359Sroberto * toss the key, if appropriate. 44254359Sroberto */ 44354359Sroberto if (!is_mystic && skeyid > NTP_MAXKEY) 44454359Sroberto authtrust(skeyid, 0); 44554359Sroberto return; 44654359Sroberto 44754359Sroberto case AM_MANYCAST: 44854359Sroberto /* 44954359Sroberto * This could be in response to a multicast packet sent by 45054359Sroberto * the "manycast" mode association. Find peer based on the 45154359Sroberto * originate timestamp in the packet. Note that we don't 45254359Sroberto * mobilize a new association, unless the packet is properly 45354359Sroberto * authenticated. The response must be properly authenticated 45454359Sroberto * and it's darn funny of the manycaster isn't around now. 45554359Sroberto */ 45654359Sroberto if ((sys_authenticate && !is_authentic)) { 45754359Sroberto is_error = 1; 45854359Sroberto break; 45954359Sroberto } 46054359Sroberto peer2 = (struct peer *)findmanycastpeer(&pkt->org); 46154359Sroberto if (peer2 == 0) { 46254359Sroberto is_error = 1; 46354359Sroberto break; 46454359Sroberto } 46554359Sroberto 46654359Sroberto /* 46754359Sroberto * Create a new association and copy the peer variables to it. 46854359Sroberto * If something goes wrong, carefully pry the new association 46954359Sroberto * away and return its marbles to the candy store. 47054359Sroberto */ 47154359Sroberto peer = newpeer(&rbufp->recv_srcadr, 47254359Sroberto rbufp->dstadr, MODE_CLIENT, PKT_VERSION(pkt->li_vn_mode), 47354359Sroberto NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); 47454359Sroberto if (peer == 0) { 47554359Sroberto is_error = 1; 47654359Sroberto break; 47754359Sroberto } 47854359Sroberto peer_config_manycast(peer2, peer); 47954359Sroberto break; 48054359Sroberto 48154359Sroberto case AM_ERR: 48254359Sroberto /* 48354359Sroberto * Something bad happened. Dirty floor will be mopped by the 48454359Sroberto * code at the end of this adventure. 48554359Sroberto */ 48654359Sroberto is_error = 1; 48754359Sroberto break; 48854359Sroberto 48954359Sroberto case AM_NEWPASS: 49054359Sroberto /* 49154359Sroberto * Okay, we're going to keep him around. Allocate him some 49254359Sroberto * memory. But, don't do that unless the packet is properly 49354359Sroberto * authenticated. 49454359Sroberto */ 49554359Sroberto if ((sys_authenticate && !is_authentic)) { 49654359Sroberto is_error = 1; 49754359Sroberto break; 49854359Sroberto } 49954359Sroberto peer = newpeer(&rbufp->recv_srcadr, 50054359Sroberto rbufp->dstadr, MODE_PASSIVE, PKT_VERSION(pkt->li_vn_mode), 50154359Sroberto NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); 50254359Sroberto break; 50354359Sroberto 50454359Sroberto case AM_NEWBCL: 50554359Sroberto /* 50654359Sroberto * Broadcast client being set up now. Do this only if the 50754359Sroberto * packet is properly authenticated. 50854359Sroberto */ 50954359Sroberto if ((restrict_mask & RES_NOPEER) || !sys_bclient || 51054359Sroberto (sys_authenticate && !is_authentic)) { 51154359Sroberto is_error = 1; 51254359Sroberto break; 51354359Sroberto } 51454359Sroberto peer = newpeer(&rbufp->recv_srcadr, 51554359Sroberto rbufp->dstadr, MODE_MCLIENT, PKT_VERSION(pkt->li_vn_mode), 51654359Sroberto NTP_MINDPOLL, NTP_MAXDPOLL, 0, skeyid); 51754359Sroberto if (peer == 0) 51854359Sroberto break; 51954359Sroberto peer->flags |= FLAG_MCAST1 | FLAG_MCAST2 | FLAG_BURST; 52054359Sroberto peer->hmode = MODE_CLIENT; 52154359Sroberto break; 52254359Sroberto 52354359Sroberto case AM_POSSBCL: 52454359Sroberto case AM_PROCPKT: 52554359Sroberto /* 52654359Sroberto * It seems like it is okay to process the packet now 52754359Sroberto */ 52854359Sroberto break; 52954359Sroberto 53054359Sroberto default: 53154359Sroberto /* 53254359Sroberto * shouldn't be getting here, but simply return anyway! 53354359Sroberto */ 53454359Sroberto is_error = 1; 53554359Sroberto } 53654359Sroberto if (is_error) { 53754359Sroberto 53854359Sroberto /* 53954359Sroberto * Error stub. If we get here, something broke. We scuttle 54054359Sroberto * the autokey if necessary and sink the ship. This can 54154359Sroberto * occur only upon mobilization, so we can throw the 54254359Sroberto * structure away without fear of breaking anything. 54354359Sroberto */ 54454359Sroberto if (!is_mystic && skeyid > NTP_MAXKEY) 54554359Sroberto authtrust(skeyid, 0); 54654359Sroberto if (peer != 0) 54754359Sroberto if (!(peer->flags & FLAG_CONFIG)) 54854359Sroberto unpeer(peer); 54954359Sroberto#ifdef DEBUG 55054359Sroberto if (debug) 55154359Sroberto printf("match error code %d assoc %d\n", retcode, 55254359Sroberto peer_associations); 55354359Sroberto#endif 55454359Sroberto return; 55554359Sroberto } 55654359Sroberto 55754359Sroberto /* 55854359Sroberto * If the peer isn't configured, set his keyid and authenable 55954359Sroberto * status based on the packet. 56054359Sroberto */ 56154359Sroberto oflags = peer->flags; 56254359Sroberto peer->timereceived = current_time; 56354359Sroberto if (!(peer->flags & FLAG_CONFIG) && has_mac) { 56454359Sroberto peer->flags |= FLAG_AUTHENABLE; 56554359Sroberto if (skeyid > NTP_MAXKEY) { 56654359Sroberto if (peer->flags & FLAG_MCAST2) 56754359Sroberto peer->keyid = skeyid; 56854359Sroberto else 56954359Sroberto peer->flags |= FLAG_SKEY; 57054359Sroberto } 57154359Sroberto } 57254359Sroberto 57354359Sroberto /* 57454359Sroberto * Determine if this guy is basically trustable. If not, flush 57554359Sroberto * the bugger. If this is the first packet that is authenticated, 57654359Sroberto * flush the clock filter. This is to foil clogging attacks that 57754359Sroberto * might starve the poor dear. 57854359Sroberto */ 57954359Sroberto peer->flash = 0; 58054359Sroberto if (is_authentic) 58154359Sroberto peer->flags |= FLAG_AUTHENTIC; 58254359Sroberto else 58354359Sroberto peer->flags &= ~FLAG_AUTHENTIC; 58454359Sroberto if (peer->hmode == MODE_BROADCAST && (restrict_mask & RES_DONTTRUST)) 58554359Sroberto peer->flash |= TEST10; /* access denied */ 58654359Sroberto if (peer->flags & FLAG_AUTHENABLE) { 58754359Sroberto if (!(peer->flags & FLAG_AUTHENTIC)) 58854359Sroberto peer->flash |= TEST5; /* authentication failed */ 58954359Sroberto else if (skeyid == 0) 59054359Sroberto peer->flash |= TEST9; /* peer not authenticated */ 59154359Sroberto else if (!(oflags & FLAG_AUTHENABLE)) { 59254359Sroberto peer_clear(peer); 59354359Sroberto report_event(EVNT_PEERAUTH, peer); 59454359Sroberto } 59554359Sroberto } 59654359Sroberto if ((peer->flash & ~(u_int)TEST9) != 0) { 59754359Sroberto 59854359Sroberto /* 59954359Sroberto * The packet is bogus, so we throw it away before becoming 60054359Sroberto * a denial-of-service hazard. We don't throw the current 60154359Sroberto * association away if it is configured or if it has prior 60254359Sroberto * reachable friends. 60354359Sroberto */ 60454359Sroberto if (!is_mystic && skeyid > NTP_MAXKEY) 60554359Sroberto authtrust(skeyid, 0); 60654359Sroberto if (!(peer->flags & FLAG_CONFIG) && peer->reach == 0) 60754359Sroberto unpeer(peer); 60854359Sroberto#ifdef DEBUG 60954359Sroberto if (debug) 61054359Sroberto printf( 61154359Sroberto "invalid packet 0x%02x code %d assoc %d\n", 61254359Sroberto peer->flash, retcode, peer_associations); 61354359Sroberto#endif 61454359Sroberto return; 61554359Sroberto } 61654359Sroberto 61754359Sroberto#ifdef MD5 61854359Sroberto /* 61954359Sroberto * The autokey dance. The cha-cha requires that the hash of the 62054359Sroberto * current session key matches the previous key identifier. Heaps 62154359Sroberto * of trouble if the steps falter. 62254359Sroberto */ 62354359Sroberto if (skeyid > NTP_MAXKEY) { 62454359Sroberto int i; 62554359Sroberto 62654359Sroberto /* 62754359Sroberto * In the case of a new autokey, verify the hash matches 62854359Sroberto * one of the previous four hashes. If not, raise the 62954359Sroberto * authentication flasher and hope the next one works. 63054359Sroberto */ 63154359Sroberto if (hismode == MODE_SERVER) { 63254359Sroberto peer->pkeyid = peer->keyid; 63354359Sroberto } else if (peer->flags & FLAG_MCAST2) { 63454359Sroberto if (peer->pkeyid > NTP_MAXKEY) 63554359Sroberto authtrust(peer->pkeyid, 0); 63654359Sroberto for (i = 0; i < 4 && tkeyid != peer->pkeyid; i++) { 63754359Sroberto tkeyid = session_key( 63854359Sroberto ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), 63954359Sroberto ntohl(rbufp->dstadr->bcast.sin_addr.s_addr), 64054359Sroberto tkeyid, 0); 64154359Sroberto } 64254359Sroberto } else { 64354359Sroberto if (peer->pkeyid > NTP_MAXKEY) 64454359Sroberto authtrust(peer->pkeyid, 0); 64554359Sroberto for (i = 0; i < 4 && tkeyid != peer->pkeyid; i++) { 64654359Sroberto tkeyid = session_key( 64754359Sroberto ntohl((&rbufp->recv_srcadr)->sin_addr.s_addr), 64854359Sroberto ntohl(rbufp->dstadr->sin.sin_addr.s_addr), 64954359Sroberto tkeyid, 0); 65054359Sroberto } 65154359Sroberto } 65254359Sroberto#ifdef XXX /* temp until certificate code is mplemented */ 65354359Sroberto if (tkeyid != peer->pkeyid) 65454359Sroberto peer->flash |= TEST9; /* peer not authentic */ 65554359Sroberto#endif 65654359Sroberto peer->pkeyid = skeyid; 65754359Sroberto } 65854359Sroberto#endif /* MD5 */ 65954359Sroberto 66054359Sroberto /* 66154359Sroberto * Gawdz, it's come to this. Process the dang packet. If something 66254359Sroberto * breaks and the association doesn't deserve to live, toss it. 66354359Sroberto * Be careful in active mode and return a packet anyway. 66454359Sroberto */ 66554359Sroberto process_packet(peer, pkt, &(rbufp->recv_time)); 66654359Sroberto if (!(peer->flags & FLAG_CONFIG) && peer->reach == 0) { 66754359Sroberto if (peer->hmode == MODE_PASSIVE) { 66854359Sroberto if (is_authentic) 66954359Sroberto fast_xmit(rbufp, MODE_PASSIVE, skeyid); 67054359Sroberto else 67154359Sroberto fast_xmit(rbufp, MODE_PASSIVE, 0); 67254359Sroberto } 67354359Sroberto unpeer(peer); 67454359Sroberto } 67554359Sroberto} 67654359Sroberto 67754359Sroberto 67854359Sroberto/* 67954359Sroberto * process_packet - Packet Procedure, a la Section 3.4.4 of the 68054359Sroberto * specification. Or almost, at least. If we're in here we have a 68154359Sroberto * reasonable expectation that we will be having a long term 68254359Sroberto * relationship with this host. 68354359Sroberto */ 68454359Srobertoint 68554359Srobertoprocess_packet( 68654359Sroberto register struct peer *peer, 68754359Sroberto register struct pkt *pkt, 68854359Sroberto l_fp *recv_ts 68954359Sroberto ) 69054359Sroberto{ 69154359Sroberto l_fp t10, t23; 69254359Sroberto double p_offset, p_del, p_disp; 69354359Sroberto double dtemp; 69454359Sroberto l_fp p_rec, p_xmt, p_org, p_reftime; 69554359Sroberto l_fp ci; 69654359Sroberto int pmode; 69754359Sroberto 69854359Sroberto /* 69954359Sroberto * Swap header fields and keep the books. 70054359Sroberto */ 70154359Sroberto sys_processed++; 70254359Sroberto peer->processed++; 70354359Sroberto p_del = FPTOD(NTOHS_FP(pkt->rootdelay)); 70454359Sroberto p_disp = FPTOD(NTOHS_FP(pkt->rootdispersion)); 70554359Sroberto NTOHL_FP(&pkt->reftime, &p_reftime); 70654359Sroberto NTOHL_FP(&pkt->rec, &p_rec); 70754359Sroberto NTOHL_FP(&pkt->xmt, &p_xmt); 70854359Sroberto if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) 70954359Sroberto NTOHL_FP(&pkt->org, &p_org); 71054359Sroberto else 71154359Sroberto p_org = peer->rec; 71254359Sroberto peer->rec = *recv_ts; 71354359Sroberto peer->ppoll = pkt->ppoll; 71454359Sroberto pmode = PKT_MODE(pkt->li_vn_mode); 71554359Sroberto 71654359Sroberto /* 71754359Sroberto * Test for old or duplicate packets (tests 1 through 3). 71854359Sroberto */ 71954359Sroberto if (L_ISHIS(&peer->org, &p_xmt)) /* count old packets */ 72054359Sroberto peer->oldpkt++; 72154359Sroberto if (L_ISEQU(&peer->org, &p_xmt)) /* test 1 */ 72254359Sroberto peer->flash |= TEST1; /* duplicate packet */ 72354359Sroberto if (PKT_MODE(pkt->li_vn_mode) != MODE_BROADCAST) { 72454359Sroberto if (!L_ISEQU(&peer->xmt, &p_org)) { /* test 2 */ 72554359Sroberto peer->bogusorg++; 72654359Sroberto peer->flash |= TEST2; /* bogus packet */ 72754359Sroberto } 72854359Sroberto if (L_ISZERO(&p_rec) || L_ISZERO(&p_org)) 72954359Sroberto peer->flash |= TEST3; /* unsynchronized */ 73054359Sroberto } else { 73154359Sroberto if (L_ISZERO(&p_org)) 73254359Sroberto peer->flash |= TEST3; /* unsynchronized */ 73354359Sroberto } 73454359Sroberto peer->org = p_xmt; 73554359Sroberto 73654359Sroberto /* 73754359Sroberto * Test for valid header (tests 5 through 10) 73854359Sroberto */ 73954359Sroberto ci = p_xmt; 74054359Sroberto L_SUB(&ci, &p_reftime); 74154359Sroberto LFPTOD(&ci, dtemp); 74254359Sroberto if (PKT_LEAP(pkt->li_vn_mode) == LEAP_NOTINSYNC || /* test 6 */ 74354359Sroberto PKT_TO_STRATUM(pkt->stratum) >= NTP_MAXSTRATUM || 74454359Sroberto dtemp < 0) 74554359Sroberto peer->flash |= TEST6; /* peer clock unsynchronized */ 74654359Sroberto if (!(peer->flags & FLAG_CONFIG) && sys_peer != 0) { /* test 7 */ 74754359Sroberto if (PKT_TO_STRATUM(pkt->stratum) > sys_stratum) { 74854359Sroberto peer->flash |= TEST7; /* peer stratum too high */ 74954359Sroberto sys_badstratum++; 75054359Sroberto } 75154359Sroberto } 75254359Sroberto if (fabs(p_del) >= MAXDISPERSE /* test 8 */ 75354359Sroberto || p_disp >= MAXDISPERSE) 75454359Sroberto peer->flash |= TEST8; /* delay/dispersion too high */ 75554359Sroberto 75654359Sroberto /* 75754359Sroberto * If the packet header is invalid (tests 5 through 10), exit. 75854359Sroberto * XXX we let TEST9 sneak by until the certificate code is 75954359Sroberto * implemented, but only to mobilize the association. 76054359Sroberto */ 76154359Sroberto if (peer->flash & (TEST5 | TEST6 | TEST7 | TEST8 | TEST10)) { 76254359Sroberto#ifdef DEBUG 76354359Sroberto if (debug) 76454359Sroberto printf( 76554359Sroberto "invalid packet header 0x%02x mode %d\n", 76654359Sroberto peer->flash, pmode); 76754359Sroberto#endif 76854359Sroberto return (0); 76954359Sroberto } 77054359Sroberto 77154359Sroberto /* 77254359Sroberto * Valid header; update our state. 77354359Sroberto */ 77454359Sroberto record_raw_stats(&peer->srcadr, &peer->dstadr->sin, 77554359Sroberto &p_org, &p_rec, &p_xmt, &peer->rec); 77654359Sroberto 77754359Sroberto peer->leap = PKT_LEAP(pkt->li_vn_mode); 77854359Sroberto peer->pmode = pmode; /* unspec */ 77954359Sroberto peer->stratum = PKT_TO_STRATUM(pkt->stratum); 78054359Sroberto peer->precision = pkt->precision; 78154359Sroberto peer->rootdelay = p_del; 78254359Sroberto peer->rootdispersion = p_disp; 78354359Sroberto peer->refid = pkt->refid; 78454359Sroberto peer->reftime = p_reftime; 78554359Sroberto if (peer->reach == 0) { 78654359Sroberto report_event(EVNT_REACH, peer); 78754359Sroberto peer->timereachable = current_time; 78854359Sroberto } 78954359Sroberto peer->reach |= 1; 79054359Sroberto poll_update(peer, peer->hpoll); 79154359Sroberto 79254359Sroberto /* 79354359Sroberto * If running in a client/server association, calculate the 79454359Sroberto * clock offset c, roundtrip delay d and dispersion e. We use 79554359Sroberto * the equations (reordered from those in the spec). Note that, 79654359Sroberto * in a broadcast association, org has been set to the time of 79754359Sroberto * last reception. Note the computation of dispersion includes 79854359Sroberto * the system precision plus that due to the frequency error 79954359Sroberto * since the originate time. 80054359Sroberto * 80154359Sroberto * c = ((t2 - t3) + (t1 - t0)) / 2 80254359Sroberto * d = (t2 - t3) - (t1 - t0) 80354359Sroberto * e = (org - rec) (seconds only) 80454359Sroberto */ 80554359Sroberto t10 = p_xmt; /* compute t1 - t0 */ 80654359Sroberto L_SUB(&t10, &peer->rec); 80754359Sroberto t23 = p_rec; /* compute t2 - t3 */ 80854359Sroberto L_SUB(&t23, &p_org); 80954359Sroberto ci = t10; 81054359Sroberto p_disp = CLOCK_PHI * (peer->rec.l_ui - p_org.l_ui); 81154359Sroberto 81254359Sroberto /* 81354359Sroberto * If running in a broadcast association, the clock offset is (t1 81454359Sroberto * - t0) corrected by the one-way delay, but we can't measure 81554359Sroberto * that directly; therefore, we start up in client/server mode, 81654359Sroberto * calculate the clock offset, using the engineered refinement 81754359Sroberto * algorithms, while also receiving broadcasts. When a broadcast 81854359Sroberto * is received in client/server mode, we calculate a correction 81954359Sroberto * factor to use after switching back to broadcast mode. We know 82054359Sroberto * NTP_SKEWFACTOR == 16, which accounts for the simplified ei 82154359Sroberto * calculation. 82254359Sroberto * 82354359Sroberto * If FLAG_MCAST2 is set, we are a broadcast/multicast client. 82454359Sroberto * If FLAG_MCAST1 is set, we haven't calculated the propagation 82554359Sroberto * delay. If hmode is MODE_CLIENT, we haven't set the local 82654359Sroberto * clock in client/server mode. Initially, we come up 82754359Sroberto * MODE_CLIENT. When the clock is first updated and FLAG_MCAST2 82854359Sroberto * is set, we switch from MODE_CLIENT to MODE_BCLIENT. 82954359Sroberto */ 83054359Sroberto if (pmode == MODE_BROADCAST) { 83154359Sroberto if (peer->flags & FLAG_MCAST1) { 83254359Sroberto if (peer->hmode == MODE_BCLIENT) 83354359Sroberto peer->flags &= ~FLAG_MCAST1; 83454359Sroberto LFPTOD(&ci, p_offset); 83554359Sroberto peer->estbdelay = peer->offset - p_offset; 83654359Sroberto return (1); 83754359Sroberto 83854359Sroberto } 83954359Sroberto DTOLFP(peer->estbdelay, &t10); 84054359Sroberto L_ADD(&ci, &t10); 84154359Sroberto p_del = peer->delay; 84254359Sroberto } else { 84354359Sroberto L_ADD(&ci, &t23); 84454359Sroberto L_RSHIFT(&ci); 84554359Sroberto L_SUB(&t23, &t10); 84654359Sroberto LFPTOD(&t23, p_del); 84754359Sroberto } 84854359Sroberto LFPTOD(&ci, p_offset); 84954359Sroberto if (fabs(p_del) >= MAXDISPERSE || p_disp >= MAXDISPERSE) /* test 4 */ 85054359Sroberto peer->flash |= TEST4; /* delay/dispersion too big */ 85154359Sroberto 85254359Sroberto /* 85354359Sroberto * If the packet data are invalid (tests 1 through 4), exit. 85454359Sroberto */ 85554359Sroberto if (peer->flash) { 85654359Sroberto#ifdef DEBUG 85754359Sroberto if (debug) 85854359Sroberto printf("invalid packet data 0x%02x mode %d\n", 85954359Sroberto peer->flash, pmode); 86054359Sroberto#endif 86154359Sroberto return(1); 86254359Sroberto } 86354359Sroberto 86454359Sroberto 86554359Sroberto /* 86654359Sroberto * This one is valid. Mark it so, give it to clock_filter(). 86754359Sroberto */ 86854359Sroberto clock_filter(peer, p_offset, p_del, fabs(p_disp)); 86954359Sroberto clock_select(); 87054359Sroberto record_peer_stats(&peer->srcadr, ctlpeerstatus(peer), 87154359Sroberto peer->offset, peer->delay, peer->disp, SQRT(peer->variance)); 87254359Sroberto return(1); 87354359Sroberto} 87454359Sroberto 87554359Sroberto 87654359Sroberto/* 87754359Sroberto * clock_update - Called at system process update intervals. 87854359Sroberto */ 87954359Srobertostatic void 88054359Srobertoclock_update(void) 88154359Sroberto{ 88254359Sroberto u_char oleap; 88354359Sroberto u_char ostratum; 88454359Sroberto int i; 88554359Sroberto struct peer *peer; 88654359Sroberto 88754359Sroberto /* 88854359Sroberto * Reset/adjust the system clock. Do this only if there is a 88954359Sroberto * system peer and we haven't seen that peer lately. Watch for 89054359Sroberto * timewarps here. 89154359Sroberto */ 89254359Sroberto if (sys_peer == 0) 89354359Sroberto return; 89454359Sroberto if (sys_peer->pollsw == FALSE || sys_peer->burst > 0) 89554359Sroberto return; 89654359Sroberto sys_peer->pollsw = FALSE; 89754359Sroberto#ifdef DEBUG 89854359Sroberto if (debug) 89954359Sroberto printf("clock_update: at %ld assoc %d \n", current_time, 90054359Sroberto peer_associations); 90154359Sroberto#endif 90254359Sroberto oleap = sys_leap; 90354359Sroberto ostratum = sys_stratum; 90454359Sroberto switch (local_clock(sys_peer, sys_offset, sys_epsil)) { 90554359Sroberto 90654359Sroberto case -1: 90754359Sroberto /* 90854359Sroberto * Clock is too screwed up. Just exit for now. 90954359Sroberto */ 91054359Sroberto report_event(EVNT_SYSFAULT, (struct peer *)0); 91154359Sroberto exit(1); 91254359Sroberto /*NOTREACHED*/ 91354359Sroberto 91454359Sroberto case 1: 91554359Sroberto /* 91654359Sroberto * Clock was stepped. Clear filter registers 91754359Sroberto * of all peers. 91854359Sroberto */ 91954359Sroberto for (i = 0; i < HASH_SIZE; i++) { 92054359Sroberto for (peer = peer_hash[i]; peer != 0; 92154359Sroberto peer =peer->next) 92254359Sroberto peer_clear(peer); 92354359Sroberto } 92454359Sroberto NLOG(NLOG_SYNCSTATUS) 92554359Sroberto msyslog(LOG_INFO, "synchronisation lost"); 92654359Sroberto sys_peer = 0; 92754359Sroberto sys_stratum = STRATUM_UNSPEC; 92854359Sroberto report_event(EVNT_CLOCKRESET, (struct peer *)0); 92954359Sroberto break; 93054359Sroberto 93154359Sroberto default: 93254359Sroberto /* 93354359Sroberto * Update the system stratum, leap bits, root delay, 93454359Sroberto * root dispersion, reference ID and reference time. We 93554359Sroberto * also update select dispersion and max frequency 93654359Sroberto * error. 93754359Sroberto */ 93854359Sroberto sys_stratum = sys_peer->stratum + 1; 93954359Sroberto if (sys_stratum == 1) 94054359Sroberto sys_refid = sys_peer->refid; 94154359Sroberto else 94254359Sroberto sys_refid = sys_peer->srcadr.sin_addr.s_addr; 94354359Sroberto sys_reftime = sys_peer->rec; 94454359Sroberto sys_rootdelay = sys_peer->rootdelay + fabs(sys_peer->delay); 94554359Sroberto sys_leap = leap_consensus; 94654359Sroberto } 94754359Sroberto if (oleap != sys_leap) 94854359Sroberto report_event(EVNT_SYNCCHG, (struct peer *)0); 94954359Sroberto if (ostratum != sys_stratum) 95054359Sroberto report_event(EVNT_PEERSTCHG, (struct peer *)0); 95154359Sroberto} 95254359Sroberto 95354359Sroberto 95454359Sroberto/* 95554359Sroberto * poll_update - update peer poll interval. See Section 3.4.9 of the 95654359Sroberto * spec. 95754359Sroberto */ 95854359Srobertovoid 95954359Srobertopoll_update( 96054359Sroberto struct peer *peer, 96154359Sroberto int hpoll 96254359Sroberto ) 96354359Sroberto{ 96454359Sroberto long update; 96554359Sroberto 96654359Sroberto /* 96754359Sroberto * The wiggle-the-poll-interval dance. Broadcasters dance only 96854359Sroberto * the minpoll beat. Reference clock partners sit this one out. 96954359Sroberto * Dancers surviving the clustering algorithm beat to the system 97054359Sroberto * clock. Broadcast clients are usually lead by their broadcast 97154359Sroberto * partner, but faster in the initial mating dance. 97254359Sroberto */ 97354359Sroberto if (peer->hmode == MODE_BROADCAST) { 97454359Sroberto peer->hpoll = peer->minpoll; 97554359Sroberto } else if (peer->flags & FLAG_SYSPEER) { 97654359Sroberto peer->hpoll = sys_poll; 97754359Sroberto } else { 97854359Sroberto if (hpoll > peer->maxpoll) 97954359Sroberto peer->hpoll = peer->maxpoll; 98054359Sroberto else if (hpoll < peer->minpoll) 98154359Sroberto peer->hpoll = peer->minpoll; 98254359Sroberto else 98354359Sroberto peer->hpoll = hpoll; 98454359Sroberto } 98554359Sroberto if (peer->burst > 0) { 98654359Sroberto if (peer->nextdate != current_time) 98754359Sroberto return; 98854359Sroberto if (peer->flags & FLAG_REFCLOCK) 98954359Sroberto peer->nextdate++; 99054359Sroberto else if (peer->reach & 0x1) 99154359Sroberto peer->nextdate += RANDPOLL(BURST_INTERVAL2); 99254359Sroberto else 99354359Sroberto peer->nextdate += RANDPOLL(BURST_INTERVAL1); 99454359Sroberto } else { 99554359Sroberto update = max(min(peer->ppoll, peer->hpoll), peer->minpoll); 99654359Sroberto peer->nextdate = peer->outdate + RANDPOLL(update); 99754359Sroberto } 99854359Sroberto#ifdef DEBUG 99954359Sroberto if (debug > 1) 100054359Sroberto printf("poll_update: at %lu %s poll %d burst %d last %lu next %lu\n", 100154359Sroberto current_time, ntoa(&peer->srcadr), hpoll, peer->burst, 100254359Sroberto peer->outdate, peer->nextdate); 100354359Sroberto#endif 100454359Sroberto} 100554359Sroberto 100654359Sroberto 100754359Sroberto/* 100854359Sroberto * clear - clear peer filter registers. See Section 3.4.8 of the spec. 100954359Sroberto */ 101054359Srobertovoid 101154359Srobertopeer_clear( 101254359Sroberto register struct peer *peer 101354359Sroberto ) 101454359Sroberto{ 101554359Sroberto register int i; 101654359Sroberto 101754359Sroberto memset(CLEAR_TO_ZERO(peer), 0, LEN_CLEAR_TO_ZERO); 101854359Sroberto peer->estbdelay = sys_bdelay; 101954359Sroberto peer->hpoll = peer->minpoll; 102054359Sroberto peer->pollsw = FALSE; 102154359Sroberto peer->variance = MAXDISPERSE; 102254359Sroberto peer->epoch = current_time; 102354359Sroberto for (i = 0; i < NTP_SHIFT; i++) { 102454359Sroberto peer->filter_order[i] = i; 102554359Sroberto peer->filter_disp[i] = MAXDISPERSE; 102654359Sroberto peer->filter_epoch[i] = current_time; 102754359Sroberto } 102854359Sroberto poll_update(peer, peer->minpoll); 102954359Sroberto 103054359Sroberto /* 103154359Sroberto * Since we have a chance to correct possible funniness in 103254359Sroberto * our selection of interfaces on a multihomed host, do so 103354359Sroberto * by setting us to no particular interface. 103454359Sroberto * WARNING: do so only in non-broadcast mode! 103554359Sroberto */ 103654359Sroberto if (peer->hmode != MODE_BROADCAST) 103754359Sroberto peer->dstadr = any_interface; 103854359Sroberto} 103954359Sroberto 104054359Sroberto 104154359Sroberto/* 104254359Sroberto * clock_filter - add incoming clock sample to filter register and run 104354359Sroberto * the filter procedure to find the best sample. 104454359Sroberto */ 104554359Srobertovoid 104654359Srobertoclock_filter( 104754359Sroberto register struct peer *peer, 104854359Sroberto double sample_offset, 104954359Sroberto double sample_delay, 105054359Sroberto double sample_disp 105154359Sroberto ) 105254359Sroberto{ 105354359Sroberto register int i, j, k, n = 0; 105454359Sroberto register u_char *ord; 105554359Sroberto double distance[NTP_SHIFT]; 105654359Sroberto double x, y, z, off; 105754359Sroberto 105854359Sroberto /* 105954359Sroberto * Update error bounds and calculate distances. Also initialize 106054359Sroberto * sort index vector. 106154359Sroberto */ 106254359Sroberto x = CLOCK_PHI * (current_time - peer->update); 106354359Sroberto peer->update = current_time; 106454359Sroberto ord = peer->filter_order; 106554359Sroberto j = peer->filter_nextpt; 106654359Sroberto for (i = 0; i < NTP_SHIFT; i++) { 106754359Sroberto peer->filter_disp[j] += x; 106854359Sroberto if (peer->filter_disp[j] > MAXDISPERSE) 106954359Sroberto peer->filter_disp[j] = MAXDISPERSE; 107054359Sroberto distance[i] = fabs(peer->filter_delay[j]) / 2 + 107154359Sroberto peer->filter_disp[j]; 107254359Sroberto ord[i] = j; 107354359Sroberto if (--j < 0) 107454359Sroberto j += NTP_SHIFT; 107554359Sroberto } 107654359Sroberto 107754359Sroberto /* 107854359Sroberto * Insert the new sample at the beginning of the register. 107954359Sroberto */ 108054359Sroberto peer->filter_offset[peer->filter_nextpt] = sample_offset; 108154359Sroberto peer->filter_delay[peer->filter_nextpt] = sample_delay; 108254359Sroberto x = LOGTOD(peer->precision) + LOGTOD(sys_precision) + sample_disp; 108354359Sroberto peer->filter_disp[peer->filter_nextpt] = min(x, MAXDISPERSE); 108454359Sroberto peer->filter_epoch[peer->filter_nextpt] = current_time; 108554359Sroberto distance[0] = min(x + fabs(sample_delay) / 2, MAXDISTANCE); 108654359Sroberto peer->filter_nextpt++; 108754359Sroberto if (peer->filter_nextpt >= NTP_SHIFT) 108854359Sroberto peer->filter_nextpt = 0; 108954359Sroberto 109054359Sroberto /* 109154359Sroberto * Sort the samples in the register by distance. The winning 109254359Sroberto * sample will be in ord[0]. Sort the samples only if they 109354359Sroberto * are younger than the Allen intercept. 109454359Sroberto */ 109554359Sroberto y = min(allan_xpt, NTP_SHIFT * ULOGTOD(sys_poll)); 109654359Sroberto for (n = 0; n < NTP_SHIFT && current_time - 109754359Sroberto peer->filter_epoch[ord[n]] <= y; n++) { 109854359Sroberto for (j = 0; j < n; j++) { 109954359Sroberto if (distance[j] > distance[n]) { 110054359Sroberto x = distance[j]; 110154359Sroberto k = ord[j]; 110254359Sroberto distance[j] = distance[n]; 110354359Sroberto ord[j] = ord[n]; 110454359Sroberto distance[n] = x; 110554359Sroberto ord[n] = k; 110654359Sroberto } 110754359Sroberto } 110854359Sroberto } 110954359Sroberto 111054359Sroberto /* 111154359Sroberto * Compute the error bound and standard error. 111254359Sroberto */ 111354359Sroberto x = y = z = off = 0.; 111454359Sroberto for (i = NTP_SHIFT - 1; i >= 0; i--) { 111554359Sroberto x = NTP_FWEIGHT * (x + peer->filter_disp[ord[i]]); 111654359Sroberto if (i < n) { 111754359Sroberto z += 1. / distance[i]; 111854359Sroberto off += peer->filter_offset[ord[i]] / distance[i]; 111954359Sroberto y += DIFF(peer->filter_offset[ord[i]], 112054359Sroberto peer->filter_offset[ord[0]]); 112154359Sroberto } 112254359Sroberto } 112354359Sroberto peer->delay = peer->filter_delay[ord[0]]; 112454359Sroberto peer->variance = min(y / n, MAXDISPERSE); 112554359Sroberto peer->disp = min(x, MAXDISPERSE); 112654359Sroberto peer->epoch = current_time; 112754359Sroberto x = peer->offset; 112854359Sroberto if (peer->flags & FLAG_BURST) 112954359Sroberto peer->offset = off / z; 113054359Sroberto else 113154359Sroberto peer->offset = peer->filter_offset[ord[0]]; 113254359Sroberto 113354359Sroberto /* 113454359Sroberto * A new sample is useful only if it is younger than the last 113554359Sroberto * one used. 113654359Sroberto */ 113754359Sroberto if (peer->filter_epoch[ord[0]] > peer->epoch) { 113854359Sroberto#ifdef DEBUG 113954359Sroberto if (debug) 114054359Sroberto printf("clock_filter: discard %lu\n", 114154359Sroberto peer->filter_epoch[ord[0]] - peer->epoch); 114254359Sroberto#endif 114354359Sroberto return; 114454359Sroberto } 114554359Sroberto 114654359Sroberto /* 114754359Sroberto * If the offset exceeds the dispersion by CLOCK_SGATE and the 114854359Sroberto * interval since the last update is less than twice the system 114954359Sroberto * poll interval, consider the update a popcorn spike and ignore 115054359Sroberto * it. 115154359Sroberto */ 115254359Sroberto if (fabs(x - peer->offset) > CLOCK_SGATE && 115354359Sroberto peer->filter_epoch[ord[0]] - peer->epoch < (1 << 115454359Sroberto (sys_poll + 1))) { 115554359Sroberto#ifdef DEBUG 115654359Sroberto if (debug) 115754359Sroberto printf("clock_filter: popcorn spike %.6f\n", x); 115854359Sroberto#endif 115954359Sroberto return; 116054359Sroberto } 116154359Sroberto peer->epoch = peer->filter_epoch[ord[0]]; 116254359Sroberto peer->pollsw = TRUE; 116354359Sroberto#ifdef DEBUG 116454359Sroberto if (debug) 116554359Sroberto printf( 116654359Sroberto "clock_filter: offset %.6f delay %.6f disp %.6f std %.6f, age %lu\n", 116754359Sroberto peer->offset, peer->delay, peer->disp, 116854359Sroberto SQRT(peer->variance), current_time - peer->epoch); 116954359Sroberto#endif 117054359Sroberto} 117154359Sroberto 117254359Sroberto 117354359Sroberto/* 117454359Sroberto * clock_select - find the pick-of-the-litter clock 117554359Sroberto */ 117654359Srobertovoid 117754359Srobertoclock_select(void) 117854359Sroberto{ 117954359Sroberto register struct peer *peer; 118054359Sroberto int i; 118154359Sroberto int nlist, nl3; 118254359Sroberto double d, e, f; 118354359Sroberto int j; 118454359Sroberto int n; 118554359Sroberto int allow, found, k; 118654359Sroberto double high, low; 118754359Sroberto double synch[NTP_MAXCLOCK], error[NTP_MAXCLOCK]; 118854359Sroberto struct peer *osys_peer; 118954359Sroberto struct peer *typeacts = 0; 119054359Sroberto struct peer *typelocal = 0; 119154359Sroberto struct peer *typepps = 0; 119254359Sroberto struct peer *typeprefer = 0; 119354359Sroberto struct peer *typesystem = 0; 119454359Sroberto 119554359Sroberto static int list_alloc = 0; 119654359Sroberto static struct endpoint *endpoint = NULL; 119754359Sroberto static int *index = NULL; 119854359Sroberto static struct peer **peer_list = NULL; 119954359Sroberto static u_int endpoint_size = 0; 120054359Sroberto static u_int index_size = 0; 120154359Sroberto static u_int peer_list_size = 0; 120254359Sroberto 120354359Sroberto /* 120454359Sroberto * Initialize. If a prefer peer does not survive this thing, 120554359Sroberto * the pps_update switch will remain zero. 120654359Sroberto */ 120754359Sroberto pps_update = 0; 120854359Sroberto nlist = 0; 120954359Sroberto low = 1e9; 121054359Sroberto high = -1e9; 121154359Sroberto for (n = 0; n < HASH_SIZE; n++) 121254359Sroberto nlist += peer_hash_count[n]; 121354359Sroberto if (nlist > list_alloc) { 121454359Sroberto if (list_alloc > 0) { 121554359Sroberto free(endpoint); 121654359Sroberto free(index); 121754359Sroberto free(peer_list); 121854359Sroberto } 121954359Sroberto while (list_alloc < nlist) { 122054359Sroberto list_alloc += 5; 122154359Sroberto endpoint_size += 5 * 3 * sizeof *endpoint; 122254359Sroberto index_size += 5 * 3 * sizeof *index; 122354359Sroberto peer_list_size += 5 * sizeof *peer_list; 122454359Sroberto } 122554359Sroberto endpoint = (struct endpoint *)emalloc(endpoint_size); 122654359Sroberto index = (int *)emalloc(index_size); 122754359Sroberto peer_list = (struct peer **)emalloc(peer_list_size); 122854359Sroberto } 122954359Sroberto 123054359Sroberto /* 123154359Sroberto * This first chunk of code is supposed to go through all 123254359Sroberto * peers we know about to find the peers which are most likely 123354359Sroberto * to succeed. We run through the list doing the sanity checks 123454359Sroberto * and trying to insert anyone who looks okay. 123554359Sroberto */ 123654359Sroberto nlist = nl3 = 0; /* none yet */ 123754359Sroberto for (n = 0; n < HASH_SIZE; n++) { 123854359Sroberto for (peer = peer_hash[n]; peer != 0; peer = peer->next) { 123954359Sroberto peer->flags &= ~FLAG_SYSPEER; 124054359Sroberto peer->status = CTL_PST_SEL_REJECT; 124154359Sroberto if (peer->flags & FLAG_NOSELECT) 124254359Sroberto continue; /* noselect (survey only) */ 124354359Sroberto if (peer->reach == 0) 124454359Sroberto continue; /* unreachable */ 124554359Sroberto if (peer->stratum > 1 && peer->refid == 124654359Sroberto peer->dstadr->sin.sin_addr.s_addr) 124754359Sroberto continue; /* sync loop */ 124854359Sroberto if (root_distance(peer) >= MAXDISTANCE + 2 * 124954359Sroberto CLOCK_PHI * ULOGTOD(sys_poll)) { 125054359Sroberto peer->seldisptoolarge++; 125154359Sroberto continue; /* too noisy or broken */ 125254359Sroberto } 125354359Sroberto 125454359Sroberto /* 125554359Sroberto * Don't allow the local-clock or acts drivers 125654359Sroberto * in the kitchen at this point, unless the 125754359Sroberto * prefer peer. Do that later, but only if 125854359Sroberto * nobody else is around. 125954359Sroberto */ 126054359Sroberto if (peer->refclktype == REFCLK_LOCALCLOCK 126154359Sroberto#if defined(VMS) && defined(VMS_LOCALUNIT) 126254359Sroberto /* wjm: local unit VMS_LOCALUNIT taken seriously */ 126354359Sroberto && REFCLOCKUNIT(&peer->srcadr) != VMS_LOCALUNIT 126454359Sroberto#endif /* VMS && VMS_LOCALUNIT */ 126554359Sroberto ) { 126654359Sroberto typelocal = peer; 126754359Sroberto if (!(peer->flags & FLAG_PREFER)) 126854359Sroberto continue; /* no local clock */ 126954359Sroberto } 127054359Sroberto if (peer->sstclktype == CTL_SST_TS_TELEPHONE) { 127154359Sroberto typeacts = peer; 127254359Sroberto if (!(peer->flags & FLAG_PREFER)) 127354359Sroberto continue; /* no acts */ 127454359Sroberto } 127554359Sroberto 127654359Sroberto /* 127754359Sroberto * If we get this far, we assume the peer is 127854359Sroberto * acceptable. 127954359Sroberto */ 128054359Sroberto peer->status = CTL_PST_SEL_SANE; 128154359Sroberto peer_list[nlist++] = peer; 128254359Sroberto 128354359Sroberto /* 128454359Sroberto * Insert each interval endpoint on the sorted 128554359Sroberto * list. 128654359Sroberto */ 128754359Sroberto e = peer->offset; /* Upper end */ 128854359Sroberto f = root_distance(peer); 128954359Sroberto e = e + f; 129054359Sroberto for (i = nl3 - 1; i >= 0; i--) { 129154359Sroberto if (e >= endpoint[index[i]].val) 129254359Sroberto break; 129354359Sroberto index[i + 3] = index[i]; 129454359Sroberto } 129554359Sroberto index[i + 3] = nl3; 129654359Sroberto endpoint[nl3].type = 1; 129754359Sroberto endpoint[nl3++].val = e; 129854359Sroberto 129954359Sroberto e = e - f; /* Center point */ 130054359Sroberto for ( ; i >= 0; i--) { 130154359Sroberto if (e >= endpoint[index[i]].val) 130254359Sroberto break; 130354359Sroberto index[i + 2] = index[i]; 130454359Sroberto } 130554359Sroberto index[i + 2] = nl3; 130654359Sroberto endpoint[nl3].type = 0; 130754359Sroberto endpoint[nl3++].val = e; 130854359Sroberto 130954359Sroberto e = e - f; /* Lower end */ 131054359Sroberto for ( ; i >= 0; i--) { 131154359Sroberto if (e >= endpoint[index[i]].val) 131254359Sroberto break; 131354359Sroberto index[i + 1] = index[i]; 131454359Sroberto } 131554359Sroberto index[i + 1] = nl3; 131654359Sroberto endpoint[nl3].type = -1; 131754359Sroberto endpoint[nl3++].val = e; 131854359Sroberto } 131954359Sroberto } 132054359Sroberto#ifdef DEBUG 132154359Sroberto if (debug > 1) 132254359Sroberto for (i = 0; i < nl3; i++) 132354359Sroberto printf("select: endpoint %2d %.6f\n", 132454359Sroberto endpoint[index[i]].type, endpoint[index[i]].val); 132554359Sroberto#endif 132654359Sroberto i = 0; 132754359Sroberto j = nl3 - 1; 132854359Sroberto allow = nlist; /* falsetickers assumed */ 132954359Sroberto found = 0; 133054359Sroberto while (allow > 0) { 133154359Sroberto allow--; 133254359Sroberto for (n = 0; i <= j; i++) { 133354359Sroberto n += endpoint[index[i]].type; 133454359Sroberto if (n < 0) 133554359Sroberto break; 133654359Sroberto if (endpoint[index[i]].type == 0) 133754359Sroberto found++; 133854359Sroberto } 133954359Sroberto for (n = 0; i <= j; j--) { 134054359Sroberto n += endpoint[index[j]].type; 134154359Sroberto if (n > 0) 134254359Sroberto break; 134354359Sroberto if (endpoint[index[j]].type == 0) 134454359Sroberto found++; 134554359Sroberto } 134654359Sroberto if (found > allow) 134754359Sroberto break; 134854359Sroberto low = endpoint[index[i++]].val; 134954359Sroberto high = endpoint[index[j--]].val; 135054359Sroberto } 135154359Sroberto 135254359Sroberto /* 135354359Sroberto * If no survivors remain at this point, check if the acts or 135454359Sroberto * local clock drivers have been found. If so, nominate one of 135554359Sroberto * them as the only survivor. Otherwise, give up and declare us 135654359Sroberto * unsynchronized. 135754359Sroberto */ 135854359Sroberto if ((allow << 1) >= nlist) { 135954359Sroberto if (typeacts != 0) { 136054359Sroberto typeacts->status = CTL_PST_SEL_SANE; 136154359Sroberto peer_list[0] = typeacts; 136254359Sroberto nlist = 1; 136354359Sroberto } else if (typelocal != 0) { 136454359Sroberto typelocal->status = CTL_PST_SEL_SANE; 136554359Sroberto peer_list[0] = typelocal; 136654359Sroberto nlist = 1; 136754359Sroberto } else { 136854359Sroberto if (sys_peer != 0) { 136954359Sroberto report_event(EVNT_PEERSTCHG, 137054359Sroberto (struct peer *)0); 137154359Sroberto NLOG(NLOG_SYNCSTATUS) 137254359Sroberto msyslog(LOG_INFO, "synchronisation lost"); 137354359Sroberto } 137454359Sroberto sys_peer = 0; 137554359Sroberto return; 137654359Sroberto } 137754359Sroberto } 137854359Sroberto#ifdef DEBUG 137954359Sroberto if (debug > 1) 138054359Sroberto printf("select: low %.6f high %.6f\n", low, high); 138154359Sroberto#endif 138254359Sroberto 138354359Sroberto /* 138454359Sroberto * Clustering algorithm. Process intersection list to discard 138554359Sroberto * outlyers. Construct candidate list in cluster order 138654359Sroberto * determined by the sum of peer synchronization distance plus 138754359Sroberto * scaled stratum. We must find at least one peer. 138854359Sroberto */ 138954359Sroberto j = 0; 139054359Sroberto for (i = 0; i < nlist; i++) { 139154359Sroberto peer = peer_list[i]; 139254359Sroberto if (nlist > 1 && (low >= peer->offset || 139354359Sroberto peer->offset >= high)) 139454359Sroberto continue; 139554359Sroberto peer->status = CTL_PST_SEL_CORRECT; 139654359Sroberto d = root_distance(peer) + peer->stratum * MAXDISPERSE; 139754359Sroberto if (j >= NTP_MAXCLOCK) { 139854359Sroberto if (d >= synch[j - 1]) 139954359Sroberto continue; 140054359Sroberto else 140154359Sroberto j--; 140254359Sroberto } 140354359Sroberto for (k = j; k > 0; k--) { 140454359Sroberto if (d >= synch[k - 1]) 140554359Sroberto break; 140654359Sroberto synch[k] = synch[k - 1]; 140754359Sroberto peer_list[k] = peer_list[k - 1]; 140854359Sroberto } 140954359Sroberto peer_list[k] = peer; 141054359Sroberto synch[k] = d; 141154359Sroberto j++; 141254359Sroberto } 141354359Sroberto nlist = j; 141454359Sroberto 141554359Sroberto#ifdef DEBUG 141654359Sroberto if (debug > 1) 141754359Sroberto for (i = 0; i < nlist; i++) 141854359Sroberto printf("select: %s distance %.6f\n", 141954359Sroberto ntoa(&peer_list[i]->srcadr), synch[i]); 142054359Sroberto#endif 142154359Sroberto 142254359Sroberto /* 142354359Sroberto * Now, prune outlyers by root dispersion. Continue as long as 142454359Sroberto * there are more than NTP_MINCLOCK survivors and the minimum 142554359Sroberto * select dispersion is greater than the maximum peer 142654359Sroberto * dispersion. Stop if we are about to discard a prefer peer. 142754359Sroberto */ 142854359Sroberto for (i = 0; i < nlist; i++) { 142954359Sroberto peer = peer_list[i]; 143054359Sroberto error[i] = peer->variance; 143154359Sroberto if (i < NTP_CANCLOCK) 143254359Sroberto peer->status = CTL_PST_SEL_SELCAND; 143354359Sroberto else 143454359Sroberto peer->status = CTL_PST_SEL_DISTSYSPEER; 143554359Sroberto } 143654359Sroberto while (1) { 143754359Sroberto sys_maxd = 0; 143854359Sroberto d = error[0]; 143954359Sroberto for (k = i = nlist - 1; i >= 0; i--) { 144054359Sroberto double sdisp = 0; 144154359Sroberto 144254359Sroberto for (j = nlist - 1; j > 0; j--) { 144354359Sroberto sdisp = NTP_SWEIGHT * (sdisp + 144454359Sroberto DIFF(peer_list[i]->offset, 144554359Sroberto peer_list[j]->offset)); 144654359Sroberto } 144754359Sroberto if (sdisp > sys_maxd) { 144854359Sroberto sys_maxd = sdisp; 144954359Sroberto k = i; 145054359Sroberto } 145154359Sroberto if (error[i] < d) 145254359Sroberto d = error[i]; 145354359Sroberto } 145454359Sroberto 145554359Sroberto#ifdef DEBUG 145654359Sroberto if (debug > 1) 145754359Sroberto printf( 145854359Sroberto "select: survivors %d select %.6f peer %.6f\n", 145954359Sroberto nlist, SQRT(sys_maxd), SQRT(d)); 146054359Sroberto#endif 146154359Sroberto if (nlist <= NTP_MINCLOCK || sys_maxd <= d || 146254359Sroberto peer_list[k]->flags & FLAG_PREFER) 146354359Sroberto break; 146454359Sroberto for (j = k + 1; j < nlist; j++) { 146554359Sroberto peer_list[j - 1] = peer_list[j]; 146654359Sroberto error[j - 1] = error[j]; 146754359Sroberto } 146854359Sroberto nlist--; 146954359Sroberto } 147054359Sroberto#ifdef DEBUG 147154359Sroberto if (debug > 1) { 147254359Sroberto for (i = 0; i < nlist; i++) 147354359Sroberto printf( 147454359Sroberto "select: %s offset %.6f, distance %.6f poll %d\n", 147554359Sroberto ntoa(&peer_list[i]->srcadr), peer_list[i]->offset, 147654359Sroberto synch[i], peer_list[i]->pollsw); 147754359Sroberto } 147854359Sroberto#endif 147954359Sroberto 148054359Sroberto /* 148154359Sroberto * What remains is a list of not greater than NTP_MINCLOCK 148254359Sroberto * peers. We want only a peer at the lowest stratum to become 148354359Sroberto * the system peer, although all survivors are eligible for the 148454359Sroberto * combining algorithm. First record their order, diddle the 148554359Sroberto * flags and clamp the poll intervals. Then, consider the peers 148654359Sroberto * at the lowest stratum. Of these, OR the leap bits on the 148754359Sroberto * assumption that, if some of them honk nonzero bits, they must 148854359Sroberto * know what they are doing. Also, check for prefer and pps 148954359Sroberto * peers. If a prefer peer is found within clock_max, update the 149054359Sroberto * pps switch. Of the other peers not at the lowest stratum, 149154359Sroberto * check if the system peer is among them and, if found, zap 149254359Sroberto * him. We note that the head of the list is at the lowest 149354359Sroberto * stratum and that unsynchronized peers cannot survive this 149454359Sroberto * far. 149554359Sroberto */ 149654359Sroberto leap_consensus = 0; 149754359Sroberto for (i = nlist - 1; i >= 0; i--) { 149854359Sroberto peer_list[i]->status = CTL_PST_SEL_SYNCCAND; 149954359Sroberto peer_list[i]->flags |= FLAG_SYSPEER; 150054359Sroberto poll_update(peer_list[i], peer_list[i]->hpoll); 150154359Sroberto if (peer_list[i]->stratum == peer_list[0]->stratum) { 150254359Sroberto leap_consensus |= peer_list[i]->leap; 150354359Sroberto if (peer_list[i]->refclktype == REFCLK_ATOM_PPS) 150454359Sroberto typepps = peer_list[i]; 150554359Sroberto if (peer_list[i] == sys_peer) 150654359Sroberto typesystem = peer_list[i]; 150754359Sroberto if (peer_list[i]->flags & FLAG_PREFER) { 150854359Sroberto typeprefer = peer_list[i]; 150954359Sroberto if (fabs(typeprefer->offset) < clock_max) 151054359Sroberto pps_update = 1; 151154359Sroberto } 151254359Sroberto } else { 151354359Sroberto if (peer_list[i] == sys_peer) 151454359Sroberto sys_peer = 0; 151554359Sroberto } 151654359Sroberto } 151754359Sroberto 151854359Sroberto /* 151954359Sroberto * Mitigation rules of the game. There are several types of 152054359Sroberto * peers that make a difference here: (1) prefer local peers 152154359Sroberto * (type REFCLK_LOCALCLOCK with FLAG_PREFER) or prefer modem 152254359Sroberto * peers (type REFCLK_NIST_ATOM etc with FLAG_PREFER), (2) pps peers 152354359Sroberto * (type REFCLK_ATOM_PPS), (3) remaining prefer peers (flag 152454359Sroberto * FLAG_PREFER), (4) the existing system peer, if any, (5) the 152554359Sroberto * head of the survivor list. Note that only one peer can be 152654359Sroberto * declared prefer. The order of preference is in the order 152754359Sroberto * stated. Note that all of these must be at the lowest stratum, 152854359Sroberto * i.e., the stratum of the head of the survivor list. 152954359Sroberto */ 153054359Sroberto osys_peer = sys_peer; 153154359Sroberto if (typeprefer && (typeprefer->refclktype == REFCLK_LOCALCLOCK || 153254359Sroberto typeprefer->sstclktype == CTL_SST_TS_TELEPHONE || !typepps)) { 153354359Sroberto sys_peer = typeprefer; 153454359Sroberto sys_peer->status = CTL_PST_SEL_SYSPEER; 153554359Sroberto sys_offset = sys_peer->offset; 153654359Sroberto sys_epsil = sys_peer->variance; 153754359Sroberto#ifdef DEBUG 153854359Sroberto if (debug > 1) 153954359Sroberto printf("select: prefer offset %.6f\n", sys_offset); 154054359Sroberto#endif 154154359Sroberto } else if (typepps && pps_update) { 154254359Sroberto sys_peer = typepps; 154354359Sroberto sys_peer->status = CTL_PST_SEL_PPS; 154454359Sroberto sys_offset = sys_peer->offset; 154554359Sroberto sys_epsil = sys_peer->variance; 154654359Sroberto if (!pps_control) 154754359Sroberto NLOG(NLOG_SYSEVENT) /* conditional syslog */ 154854359Sroberto msyslog(LOG_INFO, "pps sync enabled"); 154954359Sroberto pps_control = current_time; 155054359Sroberto#ifdef DEBUG 155154359Sroberto if (debug > 1) 155254359Sroberto printf("select: pps offset %.6f\n", sys_offset); 155354359Sroberto#endif 155454359Sroberto } else { 155554359Sroberto if (!typesystem) 155654359Sroberto sys_peer = peer_list[0]; 155754359Sroberto sys_peer->status = CTL_PST_SEL_SYSPEER; 155854359Sroberto sys_offset = clock_combine(peer_list, nlist); 155954359Sroberto sys_epsil = sys_peer->variance + sys_maxd; 156054359Sroberto#ifdef DEBUG 156154359Sroberto if (debug > 1) 156254359Sroberto printf("select: combine offset %.6f\n", 156354359Sroberto sys_offset); 156454359Sroberto#endif 156554359Sroberto } 156654359Sroberto if (osys_peer != sys_peer) 156754359Sroberto report_event(EVNT_PEERSTCHG, (struct peer *)0); 156854359Sroberto clock_update(); 156954359Sroberto} 157054359Sroberto 157154359Sroberto/* 157254359Sroberto * clock_combine - combine offsets from selected peers 157354359Sroberto */ 157454359Srobertostatic double 157554359Srobertoclock_combine( 157654359Sroberto struct peer **peers, 157754359Sroberto int npeers 157854359Sroberto ) 157954359Sroberto{ 158054359Sroberto int i; 158154359Sroberto double x, y, z; 158254359Sroberto y = z = 0; 158354359Sroberto for (i = 0; i < npeers; i++) { 158454359Sroberto x = root_distance(peers[i]); 158554359Sroberto y += 1. / x; 158654359Sroberto z += peers[i]->offset / x; 158754359Sroberto } 158854359Sroberto return (z / y); 158954359Sroberto} 159054359Sroberto 159154359Sroberto/* 159254359Sroberto * root_distance - compute synchronization distance from peer to root 159354359Sroberto */ 159454359Srobertostatic double 159554359Srobertoroot_distance( 159654359Sroberto struct peer *peer 159754359Sroberto ) 159854359Sroberto{ 159954359Sroberto return ((fabs(peer->delay) + peer->rootdelay) / 2 + 160054359Sroberto peer->rootdispersion + peer->disp + 160154359Sroberto SQRT(peer->variance) + CLOCK_PHI * (current_time - 160254359Sroberto peer->update)); 160354359Sroberto} 160454359Sroberto 160554359Sroberto/* 160654359Sroberto * peer_xmit - send packet for persistent association. 160754359Sroberto */ 160854359Srobertostatic void 160954359Srobertopeer_xmit( 161054359Sroberto struct peer *peer /* peer structure pointer */ 161154359Sroberto ) 161254359Sroberto{ 161354359Sroberto struct pkt xpkt; 161454359Sroberto int find_rtt = (peer->cast_flags & MDF_MCAST) && 161554359Sroberto peer->hmode != MODE_BROADCAST; 161654359Sroberto int sendlen; 161754359Sroberto 161854359Sroberto /* 161954359Sroberto * Initialize protocol fields. 162054359Sroberto */ 162154359Sroberto xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, 162254359Sroberto peer->version, peer->hmode); 162354359Sroberto xpkt.stratum = STRATUM_TO_PKT(sys_stratum); 162454359Sroberto xpkt.ppoll = peer->hpoll; 162554359Sroberto xpkt.precision = sys_precision; 162654359Sroberto xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); 162754359Sroberto xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion + 162854359Sroberto LOGTOD(sys_precision))); 162954359Sroberto xpkt.refid = sys_refid; 163054359Sroberto HTONL_FP(&sys_reftime, &xpkt.reftime); 163154359Sroberto HTONL_FP(&peer->org, &xpkt.org); 163254359Sroberto HTONL_FP(&peer->rec, &xpkt.rec); 163354359Sroberto 163454359Sroberto /* 163554359Sroberto * Authenticate the packet if enabled and either configured or 163654359Sroberto * the previous packet was authenticated. If for some reason the 163754359Sroberto * key associated with the key identifier is not in the key 163854359Sroberto * cache, then honk key zero. 163954359Sroberto */ 164054359Sroberto sendlen = LEN_PKT_NOMAC; 164154359Sroberto if (peer->flags & FLAG_AUTHENABLE) { 164254359Sroberto u_long xkeyid; 164354359Sroberto l_fp xmt_tx; 164454359Sroberto 164554359Sroberto /* 164654359Sroberto * Transmit encrypted packet compensated for the 164754359Sroberto * encryption delay. 164854359Sroberto */ 164954359Sroberto#ifdef MD5 165054359Sroberto if (peer->flags & FLAG_SKEY) { 165154359Sroberto 165254359Sroberto /* 165354359Sroberto * In SKEY mode, allocate and initialize a key list if 165454359Sroberto * not already done. Then, use the list in inverse 165554359Sroberto * order, discarding keys once used. Keep the latest 165654359Sroberto * key around until the next one, so clients can use 165754359Sroberto * client/server packets to compute propagation delay. 165854359Sroberto * Note we have to wait until the receive side of the 165954359Sroberto * socket is bound and the server address confirmed. 166054359Sroberto */ 166154359Sroberto if (ntohl(peer->dstadr->sin.sin_addr.s_addr) == 0 && 166254359Sroberto ntohl(peer->dstadr->bcast.sin_addr.s_addr) == 0) 166354359Sroberto peer->keyid = 0; 166454359Sroberto else { 166554359Sroberto if (peer->keylist == 0) { 166654359Sroberto make_keylist(peer); 166754359Sroberto } else { 166854359Sroberto authtrust(peer->keylist[peer->keynumber], 0); 166954359Sroberto if (peer->keynumber == 0) 167054359Sroberto make_keylist(peer); 167154359Sroberto else { 167254359Sroberto peer->keynumber--; 167354359Sroberto xkeyid = peer->keylist[peer->keynumber]; 167454359Sroberto if (!authistrusted(xkeyid)) 167554359Sroberto make_keylist(peer); 167654359Sroberto } 167754359Sroberto } 167854359Sroberto peer->keyid = peer->keylist[peer->keynumber]; 167954359Sroberto xpkt.keyid1 = htonl(2 * sizeof(u_int32)); 168054359Sroberto xpkt.keyid2 = htonl(sys_private); 168154359Sroberto sendlen += 2 * sizeof(u_int32); 168254359Sroberto } 168354359Sroberto } 168454359Sroberto#endif /* MD5 */ 168554359Sroberto xkeyid = peer->keyid; 168654359Sroberto get_systime(&peer->xmt); 168754359Sroberto L_ADD(&peer->xmt, &sys_authdelay); 168854359Sroberto HTONL_FP(&peer->xmt, &xpkt.xmt); 168954359Sroberto sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen); 169054359Sroberto get_systime(&xmt_tx); 169154359Sroberto sendpkt(&peer->srcadr, find_rtt ? any_interface : 169254359Sroberto peer->dstadr, 169354359Sroberto ((peer->cast_flags & MDF_MCAST) && !find_rtt) ? 169454359Sroberto ((peer->cast_flags & MDF_ACAST) ? -7 : peer->ttl) : -7, 169554359Sroberto &xpkt, sendlen); 169654359Sroberto 169754359Sroberto /* 169854359Sroberto * Calculate the encryption delay. Keep the minimum over 169954359Sroberto * the latest two samples. 170054359Sroberto */ 170154359Sroberto L_SUB(&xmt_tx, &peer->xmt); 170254359Sroberto L_ADD(&xmt_tx, &sys_authdelay); 170354359Sroberto sys_authdly[1] = sys_authdly[0]; 170454359Sroberto sys_authdly[0] = xmt_tx.l_uf; 170554359Sroberto if (sys_authdly[0] < sys_authdly[1]) 170654359Sroberto sys_authdelay.l_uf = sys_authdly[0]; 170754359Sroberto else 170854359Sroberto sys_authdelay.l_uf = sys_authdly[1]; 170954359Sroberto peer->sent++; 171054359Sroberto#ifdef DEBUG 171154359Sroberto if (debug) 171254359Sroberto printf( 171354359Sroberto "transmit: at %ld to %s mode %d keyid %08lx index %d\n", 171454359Sroberto current_time, ntoa(&peer->srcadr), 171554359Sroberto peer->hmode, xkeyid, peer->keynumber); 171654359Sroberto#endif 171754359Sroberto } else { 171854359Sroberto /* 171954359Sroberto * Transmit non-authenticated packet. 172054359Sroberto */ 172154359Sroberto get_systime(&(peer->xmt)); 172254359Sroberto HTONL_FP(&peer->xmt, &xpkt.xmt); 172354359Sroberto sendpkt(&(peer->srcadr), find_rtt ? any_interface : 172454359Sroberto peer->dstadr, 172554359Sroberto ((peer->cast_flags & MDF_MCAST) && !find_rtt) ? 172654359Sroberto ((peer->cast_flags & MDF_ACAST) ? -7 : peer->ttl) : -8, 172754359Sroberto &xpkt, sendlen); 172854359Sroberto peer->sent++; 172954359Sroberto#ifdef DEBUG 173054359Sroberto if (debug) 173154359Sroberto printf("transmit: at %ld to %s mode %d\n", 173254359Sroberto current_time, ntoa(&peer->srcadr), 173354359Sroberto peer->hmode); 173454359Sroberto#endif 173554359Sroberto } 173654359Sroberto} 173754359Sroberto 173854359Sroberto/* 173954359Sroberto * fast_xmit - Send packet for nonpersistent association. 174054359Sroberto */ 174154359Srobertostatic void 174254359Srobertofast_xmit( 174354359Sroberto struct recvbuf *rbufp, /* receive packet pointer */ 174454359Sroberto int xmode, /* transmit mode */ 174554359Sroberto u_long xkeyid /* transmit key ID */ 174654359Sroberto ) 174754359Sroberto{ 174854359Sroberto struct pkt xpkt; 174954359Sroberto struct pkt *rpkt; 175054359Sroberto int sendlen; 175154359Sroberto l_fp xmt_ts; 175254359Sroberto 175354359Sroberto /* 175454359Sroberto * Initialize transmit packet header fields in the receive 175554359Sroberto * buffer provided. We leave some fields intact as received. 175654359Sroberto */ 175754359Sroberto rpkt = &rbufp->recv_pkt; 175854359Sroberto xpkt.li_vn_mode = PKT_LI_VN_MODE(sys_leap, 175954359Sroberto PKT_VERSION(rpkt->li_vn_mode), xmode); 176054359Sroberto xpkt.stratum = STRATUM_TO_PKT(sys_stratum); 176154359Sroberto xpkt.ppoll = rpkt->ppoll; 176254359Sroberto xpkt.precision = sys_precision; 176354359Sroberto xpkt.rootdelay = HTONS_FP(DTOFP(sys_rootdelay)); 176454359Sroberto xpkt.rootdispersion = HTONS_FP(DTOUFP(sys_rootdispersion + 176554359Sroberto LOGTOD(sys_precision))); 176654359Sroberto xpkt.refid = sys_refid; 176754359Sroberto HTONL_FP(&sys_reftime, &xpkt.reftime); 176854359Sroberto xpkt.org = rpkt->xmt; 176954359Sroberto HTONL_FP(&rbufp->recv_time, &xpkt.rec); 177054359Sroberto sendlen = LEN_PKT_NOMAC; 177154359Sroberto if (rbufp->recv_length > sendlen) { 177254359Sroberto l_fp xmt_tx; 177354359Sroberto 177454359Sroberto /* 177554359Sroberto * Transmit encrypted packet compensated for the 177654359Sroberto * encryption delay. 177754359Sroberto */ 177854359Sroberto if (xkeyid > NTP_MAXKEY) { 177954359Sroberto xpkt.keyid1 = htonl(2 * sizeof(u_int32)); 178054359Sroberto xpkt.keyid2 = htonl(sys_private); 178154359Sroberto sendlen += 2 * sizeof(u_int32); 178254359Sroberto } 178354359Sroberto get_systime(&xmt_ts); 178454359Sroberto L_ADD(&xmt_ts, &sys_authdelay); 178554359Sroberto HTONL_FP(&xmt_ts, &xpkt.xmt); 178654359Sroberto sendlen += authencrypt(xkeyid, (u_int32 *)&xpkt, sendlen); 178754359Sroberto get_systime(&xmt_tx); 178854359Sroberto sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -9, &xpkt, 178954359Sroberto sendlen); 179054359Sroberto 179154359Sroberto /* 179254359Sroberto * Calculate the encryption delay. Keep the minimum over 179354359Sroberto * the latest two samples. 179454359Sroberto */ 179554359Sroberto L_SUB(&xmt_tx, &xmt_ts); 179654359Sroberto L_ADD(&xmt_tx, &sys_authdelay); 179754359Sroberto sys_authdly[1] = sys_authdly[0]; 179854359Sroberto sys_authdly[0] = xmt_tx.l_uf; 179954359Sroberto if (sys_authdly[0] < sys_authdly[1]) 180054359Sroberto sys_authdelay.l_uf = sys_authdly[0]; 180154359Sroberto else 180254359Sroberto sys_authdelay.l_uf = sys_authdly[1]; 180354359Sroberto#ifdef DEBUG 180454359Sroberto if (debug) 180554359Sroberto printf( 180654359Sroberto "transmit: at %ld to %s mode %d keyid %08lx\n", 180754359Sroberto current_time, ntoa(&rbufp->recv_srcadr), 180854359Sroberto xmode, xkeyid); 180954359Sroberto#endif 181054359Sroberto } else { 181154359Sroberto 181254359Sroberto /* 181354359Sroberto * Transmit non-authenticated packet. 181454359Sroberto */ 181554359Sroberto get_systime(&xmt_ts); 181654359Sroberto HTONL_FP(&xmt_ts, &xpkt.xmt); 181754359Sroberto sendpkt(&rbufp->recv_srcadr, rbufp->dstadr, -10, &xpkt, 181854359Sroberto sendlen); 181954359Sroberto#ifdef DEBUG 182054359Sroberto if (debug) 182154359Sroberto printf("transmit: at %ld to %s mode %d\n", 182254359Sroberto current_time, ntoa(&rbufp->recv_srcadr), 182354359Sroberto xmode); 182454359Sroberto#endif 182554359Sroberto } 182654359Sroberto} 182754359Sroberto 182854359Sroberto#ifdef MD5 182954359Sroberto/* 183054359Sroberto * Compute key list 183154359Sroberto */ 183254359Srobertostatic void 183354359Srobertomake_keylist( 183454359Sroberto struct peer *peer 183554359Sroberto ) 183654359Sroberto{ 183754359Sroberto int i; 183854359Sroberto u_long keyid; 183954359Sroberto u_long ltemp; 184054359Sroberto 184154359Sroberto /* 184254359Sroberto * Allocate the key list if necessary. 184354359Sroberto */ 184454359Sroberto if (peer->keylist == 0) 184554359Sroberto peer->keylist = (u_long *)emalloc(sizeof(u_long) * 184654359Sroberto NTP_MAXSESSION); 184754359Sroberto 184854359Sroberto /* 184954359Sroberto * Generate an initial key ID which is unique and greater than 185054359Sroberto * NTP_MAXKEY. 185154359Sroberto */ 185254359Sroberto while (1) { 185354359Sroberto keyid = (u_long)RANDOM & 0xffffffff; 185454359Sroberto if (keyid <= NTP_MAXKEY) 185554359Sroberto continue; 185654359Sroberto if (authhavekey(keyid)) 185754359Sroberto continue; 185854359Sroberto break; 185954359Sroberto } 186054359Sroberto 186154359Sroberto /* 186254359Sroberto * Generate up to NTP_MAXSESSION session keys. Stop if the 186354359Sroberto * next one would not be unique or not a session key ID or if 186454359Sroberto * it would expire before the next poll. 186554359Sroberto */ 186654359Sroberto ltemp = sys_automax; 186754359Sroberto for (i = 0; i < NTP_MAXSESSION; i++) { 186854359Sroberto peer->keylist[i] = keyid; 186954359Sroberto peer->keynumber = i; 187054359Sroberto keyid = session_key( 187154359Sroberto ntohl(peer->dstadr->sin.sin_addr.s_addr), 187254359Sroberto (peer->hmode == MODE_BROADCAST || (peer->flags & 187354359Sroberto FLAG_MCAST2)) ? 187454359Sroberto ntohl(peer->dstadr->bcast.sin_addr.s_addr): 187554359Sroberto ntohl(peer->srcadr.sin_addr.s_addr), 187654359Sroberto keyid, ltemp); 187754359Sroberto ltemp -= 1 << peer->hpoll; 187854359Sroberto if (auth_havekey(keyid) || keyid <= NTP_MAXKEY || 187954359Sroberto ltemp <= (1 << (peer->hpoll + 1))) 188054359Sroberto break; 188154359Sroberto } 188254359Sroberto} 188354359Sroberto#endif /* MD5 */ 188454359Sroberto 188554359Sroberto/* 188654359Sroberto * Find the precision of this particular machine 188754359Sroberto */ 188854359Sroberto#define DUSECS 1000000 /* us in a s */ 188954359Sroberto#define HUSECS (1 << 20) /* approx DUSECS for shifting etc */ 189054359Sroberto#define MINSTEP 5 /* minimum clock increment (us) */ 189154359Sroberto#define MAXSTEP 20000 /* maximum clock increment (us) */ 189254359Sroberto#define MINLOOPS 5 /* minimum number of step samples */ 189354359Sroberto 189454359Sroberto/* 189554359Sroberto * This routine calculates the differences between successive calls to 189654359Sroberto * gettimeofday(). If a difference is less than zero, the us field 189754359Sroberto * has rolled over to the next second, so we add a second in us. If 189854359Sroberto * the difference is greater than zero and less than MINSTEP, the 189954359Sroberto * clock has been advanced by a small amount to avoid standing still. 190054359Sroberto * If the clock has advanced by a greater amount, then a timer interrupt 190154359Sroberto * has occurred and this amount represents the precision of the clock. 190254359Sroberto * In order to guard against spurious values, which could occur if we 190354359Sroberto * happen to hit a fat interrupt, we do this for MINLOOPS times and 190454359Sroberto * keep the minimum value obtained. 190554359Sroberto */ 190654359Srobertoint 190754359Srobertodefault_get_precision(void) 190854359Sroberto{ 190954359Sroberto struct timeval tp; 191054359Sroberto#if !defined(SYS_WINNT) && !defined(VMS) && !defined(_SEQUENT_) 191154359Sroberto struct timezone tzp; 191254359Sroberto#elif defined(VMS) || defined(_SEQUENT_) 191354359Sroberto struct timezone { 191454359Sroberto int tz_minuteswest; 191554359Sroberto int tz_dsttime; 191654359Sroberto } tzp; 191754359Sroberto#endif /* defined(VMS) || defined(_SEQUENT_) */ 191854359Sroberto long last; 191954359Sroberto int i; 192054359Sroberto long diff; 192154359Sroberto long val; 192254359Sroberto long usec; 192354359Sroberto#ifdef HAVE_GETCLOCK 192454359Sroberto struct timespec ts; 192554359Sroberto#endif 192654359Sroberto#if defined(__FreeBSD__) && __FreeBSD__ >= 3 192754359Sroberto u_long freq; 192854359Sroberto int j; 192954359Sroberto 193054359Sroberto /* Try to see if we can find the frequency of of the counter 193154359Sroberto * which drives our timekeeping 193254359Sroberto */ 193354359Sroberto j = sizeof freq; 193454359Sroberto i = sysctlbyname("kern.timecounter.frequency", 193554359Sroberto &freq, &j , 0, 0); 193654359Sroberto if (i) 193754359Sroberto i = sysctlbyname("machdep.tsc_freq", 193854359Sroberto &freq, &j , 0, 0); 193954359Sroberto if (i) 194054359Sroberto i = sysctlbyname("machdep.i586_freq", 194154359Sroberto &freq, &j , 0, 0); 194254359Sroberto if (i) 194354359Sroberto i = sysctlbyname("machdep.i8254_freq", 194454359Sroberto &freq, &j , 0, 0); 194554359Sroberto if (!i) { 194654359Sroberto for (i = 1; freq ; i--) 194754359Sroberto freq >>= 1; 194854359Sroberto return (i); 194954359Sroberto } 195054359Sroberto#endif 195154359Sroberto usec = 0; 195254359Sroberto val = MAXSTEP; 195354359Sroberto#ifdef HAVE_GETCLOCK 195454359Sroberto (void) getclock(TIMEOFDAY, &ts); 195554359Sroberto tp.tv_sec = ts.tv_sec; 195654359Sroberto tp.tv_usec = ts.tv_nsec / 1000; 195754359Sroberto#else /* not HAVE_GETCLOCK */ 195854359Sroberto GETTIMEOFDAY(&tp, &tzp); 195954359Sroberto#endif /* not HAVE_GETCLOCK */ 196054359Sroberto last = tp.tv_usec; 196154359Sroberto for (i = 0; i < MINLOOPS && usec < HUSECS;) { 196254359Sroberto#ifdef HAVE_GETCLOCK 196354359Sroberto (void) getclock(TIMEOFDAY, &ts); 196454359Sroberto tp.tv_sec = ts.tv_sec; 196554359Sroberto tp.tv_usec = ts.tv_nsec / 1000; 196654359Sroberto#else /* not HAVE_GETCLOCK */ 196754359Sroberto GETTIMEOFDAY(&tp, &tzp); 196854359Sroberto#endif /* not HAVE_GETCLOCK */ 196954359Sroberto diff = tp.tv_usec - last; 197054359Sroberto last = tp.tv_usec; 197154359Sroberto if (diff < 0) 197254359Sroberto diff += DUSECS; 197354359Sroberto usec += diff; 197454359Sroberto if (diff > MINSTEP) { 197554359Sroberto i++; 197654359Sroberto if (diff < val) 197754359Sroberto val = diff; 197854359Sroberto } 197954359Sroberto } 198054359Sroberto NLOG(NLOG_SYSINFO) /* conditional if clause for conditional syslog */ 198154359Sroberto msyslog(LOG_INFO, "precision = %ld usec", val); 198254359Sroberto if (usec >= HUSECS) 198354359Sroberto val = MINSTEP; /* val <= MINSTEP; fast machine */ 198454359Sroberto diff = HUSECS; 198554359Sroberto for (i = 0; diff > val; i--) 198654359Sroberto diff >>= 1; 198754359Sroberto return (i); 198854359Sroberto} 198954359Sroberto 199054359Sroberto/* 199154359Sroberto * init_proto - initialize the protocol module's data 199254359Sroberto */ 199354359Srobertovoid 199454359Srobertoinit_proto(void) 199554359Sroberto{ 199654359Sroberto l_fp dummy; 199754359Sroberto 199854359Sroberto /* 199954359Sroberto * Fill in the sys_* stuff. Default is don't listen to 200054359Sroberto * broadcasting, authenticate. 200154359Sroberto */ 200254359Sroberto sys_leap = LEAP_NOTINSYNC; 200354359Sroberto sys_stratum = STRATUM_UNSPEC; 200454359Sroberto sys_precision = (s_char)default_get_precision(); 200554359Sroberto sys_rootdelay = 0; 200654359Sroberto sys_rootdispersion = 0; 200754359Sroberto sys_refid = 0; 200854359Sroberto L_CLR(&sys_reftime); 200954359Sroberto sys_peer = 0; 201054359Sroberto get_systime(&dummy); 201154359Sroberto sys_bclient = 0; 201254359Sroberto sys_bdelay = DEFBROADDELAY; 201354359Sroberto#if defined(DES) || defined(MD5) 201454359Sroberto sys_authenticate = 1; 201554359Sroberto#else 201654359Sroberto sys_authenticate = 0; 201754359Sroberto#endif 201854359Sroberto L_CLR(&sys_authdelay); 201954359Sroberto sys_authdly[0] = sys_authdly[1] = 0; 202054359Sroberto sys_stattime = 0; 202154359Sroberto sys_badstratum = 0; 202254359Sroberto sys_oldversionpkt = 0; 202354359Sroberto sys_newversionpkt = 0; 202454359Sroberto sys_badlength = 0; 202554359Sroberto sys_unknownversion = 0; 202654359Sroberto sys_processed = 0; 202754359Sroberto sys_badauth = 0; 202854359Sroberto sys_manycastserver = 0; 202954359Sroberto sys_automax = 1 << NTP_AUTOMAX; 203054359Sroberto 203154359Sroberto /* 203254359Sroberto * Default these to enable 203354359Sroberto */ 203454359Sroberto ntp_enable = 1; 203554359Sroberto#ifndef KERNEL_FLL_BUG 203654359Sroberto kern_enable = 1; 203754359Sroberto#endif 203854359Sroberto msyslog(LOG_DEBUG, "kern_enable is %d", kern_enable); 203954359Sroberto stats_control = 1; 204054359Sroberto 204154359Sroberto /* 204254359Sroberto * Some system clocks should only be adjusted in 10ms increments. 204354359Sroberto */ 204454359Sroberto#if defined RELIANTUNIX_CLOCK 204554359Sroberto systime_10ms_ticks = 1; /* Reliant UNIX */ 204654359Sroberto#elif defined SCO5_CLOCK 204754359Sroberto if (sys_precision >= (s_char)-10) /* pre- SCO OpenServer 5.0.6 */ 204854359Sroberto systime_10ms_ticks = 1; 204954359Sroberto#endif 205054359Sroberto if (systime_10ms_ticks) 205154359Sroberto msyslog(LOG_INFO, "using 10ms tick adjustments"); 205254359Sroberto} 205354359Sroberto 205454359Sroberto 205554359Sroberto/* 205654359Sroberto * proto_config - configure the protocol module 205754359Sroberto */ 205854359Srobertovoid 205954359Srobertoproto_config( 206054359Sroberto int item, 206154359Sroberto u_long value, 206254359Sroberto double dvalue 206354359Sroberto ) 206454359Sroberto{ 206554359Sroberto /* 206654359Sroberto * Figure out what he wants to change, then do it 206754359Sroberto */ 206854359Sroberto switch (item) { 206954359Sroberto case PROTO_KERNEL: 207054359Sroberto /* 207154359Sroberto * Turn on/off kernel discipline 207254359Sroberto */ 207354359Sroberto kern_enable = (int)value; 207454359Sroberto break; 207554359Sroberto 207654359Sroberto case PROTO_NTP: 207754359Sroberto /* 207854359Sroberto * Turn on/off clock discipline 207954359Sroberto */ 208054359Sroberto ntp_enable = (int)value; 208154359Sroberto break; 208254359Sroberto 208354359Sroberto case PROTO_MONITOR: 208454359Sroberto /* 208554359Sroberto * Turn on/off monitoring 208654359Sroberto */ 208754359Sroberto if (value) 208854359Sroberto mon_start(MON_ON); 208954359Sroberto else 209054359Sroberto mon_stop(MON_ON); 209154359Sroberto break; 209254359Sroberto 209354359Sroberto case PROTO_FILEGEN: 209454359Sroberto /* 209554359Sroberto * Turn on/off statistics 209654359Sroberto */ 209754359Sroberto stats_control = (int)value; 209854359Sroberto break; 209954359Sroberto 210054359Sroberto case PROTO_BROADCLIENT: 210154359Sroberto /* 210254359Sroberto * Turn on/off facility to listen to broadcasts 210354359Sroberto */ 210454359Sroberto sys_bclient = (int)value; 210554359Sroberto if (value) 210654359Sroberto io_setbclient(); 210754359Sroberto else 210854359Sroberto io_unsetbclient(); 210954359Sroberto break; 211054359Sroberto 211154359Sroberto case PROTO_MULTICAST_ADD: 211254359Sroberto /* 211354359Sroberto * Add muliticast group address 211454359Sroberto */ 211554359Sroberto io_multicast_add(value); 211654359Sroberto break; 211754359Sroberto 211854359Sroberto case PROTO_MULTICAST_DEL: 211954359Sroberto /* 212054359Sroberto * Delete multicast group address 212154359Sroberto */ 212254359Sroberto io_multicast_del(value); 212354359Sroberto break; 212454359Sroberto 212554359Sroberto case PROTO_BROADDELAY: 212654359Sroberto /* 212754359Sroberto * Set default broadcast delay 212854359Sroberto */ 212954359Sroberto sys_bdelay = dvalue; 213054359Sroberto break; 213154359Sroberto 213254359Sroberto case PROTO_AUTHENTICATE: 213354359Sroberto /* 213454359Sroberto * Specify the use of authenticated data 213554359Sroberto */ 213654359Sroberto sys_authenticate = (int)value; 213754359Sroberto break; 213854359Sroberto 213954359Sroberto default: 214054359Sroberto /* 214154359Sroberto * Log this error 214254359Sroberto */ 214354359Sroberto msyslog(LOG_ERR, "proto_config: illegal item %d, value %ld", 214454359Sroberto item, value); 214554359Sroberto break; 214654359Sroberto } 214754359Sroberto} 214854359Sroberto 214954359Sroberto 215054359Sroberto/* 215154359Sroberto * proto_clr_stats - clear protocol stat counters 215254359Sroberto */ 215354359Srobertovoid 215454359Srobertoproto_clr_stats(void) 215554359Sroberto{ 215654359Sroberto sys_badstratum = 0; 215754359Sroberto sys_oldversionpkt = 0; 215854359Sroberto sys_newversionpkt = 0; 215954359Sroberto sys_unknownversion = 0; 216054359Sroberto sys_badlength = 0; 216154359Sroberto sys_processed = 0; 216254359Sroberto sys_badauth = 0; 216354359Sroberto sys_stattime = current_time; 216454359Sroberto sys_limitrejected = 0; 216554359Sroberto} 2166