xref: /freebsd/contrib/ntp/ntpd/ntp_leapsec.h (revision e43d33d286a1aa41b6fc6a209f28a18e8cd7437a)
12b15cb3dSCy Schubert /*
22b15cb3dSCy Schubert  * ntp_leapsec.h - leap second processing for NTPD
32b15cb3dSCy Schubert  *
42b15cb3dSCy Schubert  * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
52b15cb3dSCy Schubert  * The contents of 'html/copyright.html' apply.
62b15cb3dSCy Schubert  * ----------------------------------------------------------------------
72b15cb3dSCy Schubert  * This is an attempt to get the leap second handling into a dedicated
82b15cb3dSCy Schubert  * module to make the somewhat convoluted logic testable.
92b15cb3dSCy Schubert  */
102b15cb3dSCy Schubert 
112b15cb3dSCy Schubert #ifndef NTP_LEAPSEC_H
122b15cb3dSCy Schubert #define NTP_LEAPSEC_H
132b15cb3dSCy Schubert 
142b15cb3dSCy Schubert struct stat;
152b15cb3dSCy Schubert 
162b15cb3dSCy Schubert 
172b15cb3dSCy Schubert /* function pointer types. Note that 'fprintf' and 'getc' can be casted
182b15cb3dSCy Schubert  * to the dumper resp. reader type, provided the auxiliary argument is a
192b15cb3dSCy Schubert  * valid FILE pointer in hat case.
202b15cb3dSCy Schubert  */
212b15cb3dSCy Schubert typedef void (*leapsec_dumper)(void*, const char *fmt, ...);
222b15cb3dSCy Schubert typedef int  (*leapsec_reader)(void*);
232b15cb3dSCy Schubert 
242b15cb3dSCy Schubert struct leap_table;
252b15cb3dSCy Schubert typedef struct leap_table leap_table_t;
262b15cb3dSCy Schubert 
272b15cb3dSCy Schubert /* Validate a stream containing a leap second file in the NIST / NTPD
282b15cb3dSCy Schubert  * format that can also be loaded via 'leapsec_load()'. This uses
292b15cb3dSCy Schubert  * the SHA1 hash and preprocessing as described in the NIST leapsecond
302b15cb3dSCy Schubert  * file.
312b15cb3dSCy Schubert  */
322b15cb3dSCy Schubert #define LSVALID_GOODHASH	1	/* valid signature         */
332b15cb3dSCy Schubert #define LSVALID_NOHASH		0	/* no signature in file    */
342b15cb3dSCy Schubert #define LSVALID_BADHASH	       -1	/* signature mismatch      */
352b15cb3dSCy Schubert #define LSVALID_BADFORMAT      -2	/* signature not parseable */
362b15cb3dSCy Schubert 
372b15cb3dSCy Schubert extern int leapsec_validate(leapsec_reader, void*);
382b15cb3dSCy Schubert 
392b15cb3dSCy Schubert 
402b15cb3dSCy Schubert /* Set/get electric mode
412b15cb3dSCy Schubert  * Electric mode is defined as the operation mode where the system clock
422b15cb3dSCy Schubert  * automagically manages the leap second, so we don't have to care about
432b15cb3dSCy Schubert  * stepping the clock. (This should be the case with most systems,
442b15cb3dSCy Schubert  * including the current implementation of the Win32 timekeeping.)
452b15cb3dSCy Schubert  *
462b15cb3dSCy Schubert  * The consequence of electric mode is that we do not 'see' the leap
472b15cb3dSCy Schubert  * second, and no client actions are needed when crossing the leap era
482b15cb3dSCy Schubert  * boundary.  In manual (aka non-electric) mode the clock will simply
492b15cb3dSCy Schubert  * step forward untill *we* (that is, this module) tells the client app
502b15cb3dSCy Schubert  * to step at the right time. This needs a slightly different type of
512b15cb3dSCy Schubert  * processing, so switching between those two modes should not be done
522b15cb3dSCy Schubert  * too close to a leap second. The transition might be lost in that
532b15cb3dSCy Schubert  * case. (The limit is actual 2 sec before transition.)
542b15cb3dSCy Schubert  *
552b15cb3dSCy Schubert  * OTOH, this is a system characteristic, so it's expected to be set
562b15cb3dSCy Schubert  * properly somewhere after system start and retain the value.
572b15cb3dSCy Schubert  *
582b15cb3dSCy Schubert  * Simply querying the state or setting it to the same value as before
592b15cb3dSCy Schubert  * does not have any unwanted side effects.  You can query by giving a
602b15cb3dSCy Schubert  * negative value for the switch.
612b15cb3dSCy Schubert  */
622b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_electric(int/*BOOL*/ on);
632b15cb3dSCy Schubert 
64276da39aSCy Schubert /* Query result for a leap era. This is the minimal stateless
65276da39aSCy Schubert  * information available for a time stamp in UTC.
66276da39aSCy Schubert  */
67276da39aSCy Schubert struct leap_era {
68276da39aSCy Schubert 	vint64   ebase;	/* era base (UTC of start)		*/
69276da39aSCy Schubert 	vint64   ttime; /* era end (UTC of next leap second)	*/
70276da39aSCy Schubert 	int16_t  taiof;	/* offset to TAI in this era		*/
71276da39aSCy Schubert };
72276da39aSCy Schubert typedef struct leap_era leap_era_t;
732b15cb3dSCy Schubert 
742b15cb3dSCy Schubert /* Query result for a leap second schedule
75276da39aSCy Schubert  * 'ebase' is the nominal UTC time when the current leap era
76276da39aSCy Schubert  *      started. (Era base time)
77276da39aSCy Schubert  * 'ttime' is the next transition point in full time scale. (Nominal UTC
78276da39aSCy Schubert  *      time when the next leap era starts.)
792b15cb3dSCy Schubert  * 'ddist' is the distance to the transition, in clock seconds.
802b15cb3dSCy Schubert  *      This is the distance to the due time, which is different
812b15cb3dSCy Schubert  *      from the transition time if the mode is non-electric.
822b15cb3dSCy Schubert  *	Only valid if 'tai_diff' is not zero.
83276da39aSCy Schubert  * 'tai_offs' is the CURRENT distance from clock (UTC) to TAI. Always
84276da39aSCy Schubert  *      valid.
852b15cb3dSCy Schubert  * 'tai_diff' is the change in TAI offset after the next leap
862b15cb3dSCy Schubert  *	transition. Zero if nothing is pending or too far ahead.
872b15cb3dSCy Schubert  * 'warped' is set only once, when the the leap second occurred between
882b15cb3dSCy Schubert  *	two queries. Always zero in electric mode. If non-zero,
892b15cb3dSCy Schubert  *      immediately step the clock.
902b15cb3dSCy Schubert  * 'proximity' is a proximity warning. See definitions below. This is
912b15cb3dSCy Schubert  *	more useful than an absolute difference to the leap second.
922b15cb3dSCy Schubert  * 'dynamic' != 0 if entry was requested by clock/peer
932b15cb3dSCy Schubert  */
942b15cb3dSCy Schubert struct leap_result {
95276da39aSCy Schubert 	vint64   ebase;
962b15cb3dSCy Schubert 	vint64   ttime;
972b15cb3dSCy Schubert 	uint32_t ddist;
982b15cb3dSCy Schubert 	int16_t  tai_offs;
992b15cb3dSCy Schubert 	int16_t  tai_diff;
1002b15cb3dSCy Schubert 	int16_t  warped;
1012b15cb3dSCy Schubert 	uint8_t  proximity;
1022b15cb3dSCy Schubert 	uint8_t  dynamic;
1032b15cb3dSCy Schubert };
1042b15cb3dSCy Schubert typedef struct leap_result leap_result_t;
1052b15cb3dSCy Schubert 
106276da39aSCy Schubert /* The leap signature is used in two distinct circumstances, and it has
107276da39aSCy Schubert  * slightly different content in these cases:
108276da39aSCy Schubert  *  - it is used to indictae the time range covered by the leap second
109276da39aSCy Schubert  *    table, and then it contains the last transition, TAI offset after
110276da39aSCy Schubert  *    the final transition, and the expiration time.
111276da39aSCy Schubert  *  - it is used to query data for AUTOKEY updates, and then it contains
112276da39aSCy Schubert  *    the *current* TAI offset, the *next* transition time and the
113276da39aSCy Schubert  *    expiration time of the table.
114276da39aSCy Schubert  */
1152b15cb3dSCy Schubert struct leap_signature {
1162b15cb3dSCy Schubert 	uint32_t etime;	/* expiration time	*/
1172b15cb3dSCy Schubert 	uint32_t ttime;	/* transition time	*/
1182b15cb3dSCy Schubert 	int16_t  taiof;	/* total offset to TAI	*/
1192b15cb3dSCy Schubert };
1202b15cb3dSCy Schubert typedef struct leap_signature leap_signature_t;
1212b15cb3dSCy Schubert 
1222b15cb3dSCy Schubert 
123276da39aSCy Schubert #ifdef LEAP_SMEAR
124276da39aSCy Schubert 
125276da39aSCy Schubert struct leap_smear_info {
126276da39aSCy Schubert 	int enabled;        /* not 0 if smearing is generally enabled */
127276da39aSCy Schubert 	int in_progress;    /* not 0 if smearing is in progress, i.e. the offset has been computed */
128276da39aSCy Schubert 	int leap_occurred;  /* not 0 if the leap second has already occurred, i.e., during the leap second */
129276da39aSCy Schubert 	double doffset;     /* the current smear offset as double */
130276da39aSCy Schubert 	l_fp offset;        /* the current smear offset */
131276da39aSCy Schubert 	uint32_t t_offset;  /* the current time for which a smear offset has been computed */
132276da39aSCy Schubert 	long interval;      /* smear interval, in [s], should be at least some hours */
133276da39aSCy Schubert 	double intv_start;  /* start time of the smear interval */
134276da39aSCy Schubert 	double intv_end;    /* end time of the smear interval */
135276da39aSCy Schubert };
136276da39aSCy Schubert typedef struct leap_smear_info leap_smear_info_t;
137276da39aSCy Schubert 
138276da39aSCy Schubert #endif  /* LEAP_SMEAR */
139276da39aSCy Schubert 
140276da39aSCy Schubert 
1412b15cb3dSCy Schubert #define LSPROX_NOWARN	0	/* clear radar screen         */
1422b15cb3dSCy Schubert #define LSPROX_SCHEDULE	1	/* less than 1 month to target*/
1432b15cb3dSCy Schubert #define LSPROX_ANNOUNCE	2	/* less than 1 day to target  */
1442b15cb3dSCy Schubert #define LSPROX_ALERT	3	/* less than 10 sec to target */
1452b15cb3dSCy Schubert 
1462b15cb3dSCy Schubert /* Get the current or alternate table pointer. Getting the alternate
1472b15cb3dSCy Schubert  * pointer will automatically copy the primary table, so it can be
1482b15cb3dSCy Schubert  * subsequently modified.
1492b15cb3dSCy Schubert  */
1502b15cb3dSCy Schubert extern leap_table_t *leapsec_get_table(int alternate);
1512b15cb3dSCy Schubert 
1522b15cb3dSCy Schubert /* Set the current leap table. Accepts only return values from
1532b15cb3dSCy Schubert  * 'leapsec_get_table()', so it's hard to do something wrong. Returns
1542b15cb3dSCy Schubert  * TRUE if the current table is the requested one.
1552b15cb3dSCy Schubert  */
1562b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_set_table(leap_table_t *);
1572b15cb3dSCy Schubert 
1582b15cb3dSCy Schubert /* Clear all leap second data. Use it for init & cleanup */
1592b15cb3dSCy Schubert extern void leapsec_clear(leap_table_t*);
1602b15cb3dSCy Schubert 
1612b15cb3dSCy Schubert /* Load a leap second file. If 'blimit' is set, do not store (but
1622b15cb3dSCy Schubert  * register with their TAI offset) leap entries before the build date.
1632b15cb3dSCy Schubert  * Update the leap signature data on the fly.
1642b15cb3dSCy Schubert  */
1652b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_load(leap_table_t*, leapsec_reader,
1662b15cb3dSCy Schubert 				void*, int blimit);
1672b15cb3dSCy Schubert 
1682b15cb3dSCy Schubert /* Dump the current leap table in readable format, using the provided
1692b15cb3dSCy Schubert  * dump formatter function.
1702b15cb3dSCy Schubert  */
1712b15cb3dSCy Schubert extern void leapsec_dump(const leap_table_t*, leapsec_dumper func, void *farg);
1722b15cb3dSCy Schubert 
1732b15cb3dSCy Schubert /* Read a leap second file from stream. This is a convenience wrapper
1742b15cb3dSCy Schubert  * around the generic load function, 'leapsec_load()'.
1752b15cb3dSCy Schubert  */
1762b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_load_stream(FILE * fp, const char * fname,
177*2d4e511cSCy Schubert 				       int/*BOOL*/logall, int/*BOOL*/vhash);
1782b15cb3dSCy Schubert 
1792b15cb3dSCy Schubert /* Read a leap second file from file. It checks that the file exists and
1802b15cb3dSCy Schubert  * (if 'force' is not applied) the ctime/mtime has changed since the
1812b15cb3dSCy Schubert  * last load. If the file has to be loaded, either due to 'force' or
1822b15cb3dSCy Schubert  * changed time stamps, the 'stat()' results of the file are stored in
1832b15cb3dSCy Schubert  * '*sb' for the next cycle. Returns TRUE on successful load, FALSE
1842b15cb3dSCy Schubert  * otherwise. Uses 'leapsec_load_stream()' internally.
1852b15cb3dSCy Schubert  */
1862b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_load_file(const char * fname, struct stat * sb,
187*2d4e511cSCy Schubert 				     int/*BOOL*/force, int/*BOOL*/logall,
188*2d4e511cSCy Schubert 				     int/*BOOL*/vhash);
1892b15cb3dSCy Schubert 
1902b15cb3dSCy Schubert /* Get the current leap data signature. This consists of the last
1912b15cb3dSCy Schubert  * ransition, the table expiration, and the total TAI difference at the
1922b15cb3dSCy Schubert  * last transition. This is valid even if the leap transition itself was
1932b15cb3dSCy Schubert  * culled due to the build date limit.
1942b15cb3dSCy Schubert  */
1952b15cb3dSCy Schubert extern void        leapsec_getsig(leap_signature_t * psig);
1962b15cb3dSCy Schubert 
1972b15cb3dSCy Schubert /* Check if the leap table is expired at the given time.
1982b15cb3dSCy Schubert  */
1992b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_expired(uint32_t when, const time_t * pivot);
2002b15cb3dSCy Schubert 
2012b15cb3dSCy Schubert /* Get the distance to expiration in days.
2022b15cb3dSCy Schubert  * Returns negative values if expired, zero if there are less than 24hrs
2032b15cb3dSCy Schubert  * left, and positive numbers otherwise.
2042b15cb3dSCy Schubert  */
2052b15cb3dSCy Schubert extern int32_t leapsec_daystolive(uint32_t when, const time_t * pivot);
2062b15cb3dSCy Schubert 
2072b15cb3dSCy Schubert /* Reset the current leap frame, so the next query will do proper table
2082b15cb3dSCy Schubert  * lookup from fresh. Suppresses a possible leap era transition detection
2092b15cb3dSCy Schubert  * for the next query.
2102b15cb3dSCy Schubert  */
2112b15cb3dSCy Schubert extern void leapsec_reset_frame(void);
2122b15cb3dSCy Schubert 
213276da39aSCy Schubert #if 0 /* currently unused -- possibly revived later */
2142b15cb3dSCy Schubert /* Given a transition time, the TAI offset valid after that and an
2152b15cb3dSCy Schubert  * expiration time, try to establish a system leap transition. Only
2162b15cb3dSCy Schubert  * works if the existing table is extended. On success, updates the
2172b15cb3dSCy Schubert  * signature data.
2182b15cb3dSCy Schubert  */
2192b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_add_fix(int offset, uint32_t ttime, uint32_t etime,
2202b15cb3dSCy Schubert 				   const time_t * pivot);
221276da39aSCy Schubert #endif
2222b15cb3dSCy Schubert 
2232b15cb3dSCy Schubert /* Take a time stamp and create a leap second frame for it. This will
2242b15cb3dSCy Schubert  * schedule a leap second for the beginning of the next month, midnight
2252b15cb3dSCy Schubert  * UTC. The 'insert' argument tells if a leap second is added (!=0) or
2262b15cb3dSCy Schubert  * removed (==0). We do not handle multiple inserts (yet?)
2272b15cb3dSCy Schubert  *
2282b15cb3dSCy Schubert  * Returns 1 if the insert worked, 0 otherwise. (It's not possible to
2292b15cb3dSCy Schubert  * insert a leap second into the current history -- only appending
2302b15cb3dSCy Schubert  * towards the future is allowed!)
2312b15cb3dSCy Schubert  *
2322b15cb3dSCy Schubert  * 'ntp_now' is subject to era unfolding. The entry is marked
2332b15cb3dSCy Schubert  * dynamic. The leap signature is NOT updated.
2342b15cb3dSCy Schubert  */
2352b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_add_dyn(int/*BOOL*/ insert, uint32_t ntp_now,
2362b15cb3dSCy Schubert 				   const time_t * pivot);
2372b15cb3dSCy Schubert 
2382b15cb3dSCy Schubert /* Take a time stamp and get the associated leap information. The time
2392b15cb3dSCy Schubert  * stamp is subject to era unfolding around the pivot or the current
2402b15cb3dSCy Schubert  * system time if pivot is NULL. Sets the information in '*qr' and
2412b15cb3dSCy Schubert  * returns TRUE if a leap second era boundary was crossed between the
2422b15cb3dSCy Schubert  * last and the current query. In that case, qr->warped contains the
2432b15cb3dSCy Schubert  * required clock stepping, which is always zero in electric mode.
2442b15cb3dSCy Schubert  */
2452b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_query(leap_result_t * qr, uint32_t ntpts,
2462b15cb3dSCy Schubert 				 const time_t * pivot);
2472b15cb3dSCy Schubert 
248276da39aSCy Schubert /* For a given time stamp, fetch the data for the bracketing leap
249276da39aSCy Schubert  * era. The time stamp is subject to NTP era unfolding.
250276da39aSCy Schubert  */
251276da39aSCy Schubert extern int/*BOOL*/ leapsec_query_era(leap_era_t * qr, uint32_t ntpts,
252276da39aSCy Schubert 				     const time_t * pivot);
253276da39aSCy Schubert 
2542b15cb3dSCy Schubert /* Get the current leap frame info. Returns TRUE if the result contains
2552b15cb3dSCy Schubert  * useable data, FALSE if there is currently no leap second frame.
2562b15cb3dSCy Schubert  * This merely replicates some results from a previous query, but since
2572b15cb3dSCy Schubert  * it does not check the current time, only the following entries are
2582b15cb3dSCy Schubert  * meaningful:
2592b15cb3dSCy Schubert  *  qr->ttime;
2602b15cb3dSCy Schubert  *  qr->tai_offs;
2612b15cb3dSCy Schubert  *  qr->tai_diff;
2622b15cb3dSCy Schubert  *  qr->dynamic;
2632b15cb3dSCy Schubert  */
2642b15cb3dSCy Schubert extern int/*BOOL*/ leapsec_frame(leap_result_t *qr);
2652b15cb3dSCy Schubert 
266276da39aSCy Schubert 
267276da39aSCy Schubert /* Process a AUTOKEY TAI offset information. This *might* augment the
268276da39aSCy Schubert  * current leap data table with the given TAI offset.
269276da39aSCy Schubert  * Returns TRUE if action was taken, FALSE otherwise.
270276da39aSCy Schubert  */
271276da39aSCy Schubert extern int/*BOOL*/ leapsec_autokey_tai(int tai_offset, uint32_t ntpnow,
272276da39aSCy Schubert 				       const time_t * pivot);
273276da39aSCy Schubert 
274276da39aSCy Schubert /* reset global state for unit tests */
275276da39aSCy Schubert extern void leapsec_ut_pristine(void);
276276da39aSCy Schubert 
2772b15cb3dSCy Schubert #endif /* !defined(NTP_LEAPSEC_H) */
278