Add kern_ntp_adjtime(9).

Reviewed by:	brooks, cy
Sponsored by:	The FreeBSD Foundation
MFC after:	1 week
Differential revision:	https://reviews.freebsd.org/D27471
This commit is contained in:
Konstantin Belousov 2020-12-04 18:56:44 +00:00
parent abbf48c558
commit be2535b0a6
2 changed files with 66 additions and 52 deletions

View File

@ -338,24 +338,13 @@ SYSCTL_S64(_kern_ntp_pll, OID_AUTO, time_freq, CTLFLAG_RD | CTLFLAG_MPSAFE,
* the timex.constant structure member has a dual purpose to set the time
* constant and to set the TAI offset.
*/
#ifndef _SYS_SYSPROTO_H_
struct ntp_adjtime_args {
struct timex *tp;
};
#endif
int
sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
kern_ntp_adjtime(struct thread *td, struct timex *ntv, int *retvalp)
{
struct timex ntv; /* temporary structure */
long freq; /* frequency ns/s) */
int modes; /* mode bits from structure */
int error, retval;
error = copyin((caddr_t)uap->tp, (caddr_t)&ntv, sizeof(ntv));
if (error)
return (error);
/*
* Update selected clock variables - only the superuser can
* change anything. Note that there is no error checking here on
@ -365,18 +354,19 @@ sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
* the STA_PLL bit in the status word is cleared, the state and
* status words are reset to the initial values at boot.
*/
modes = ntv.modes;
modes = ntv->modes;
error = 0;
if (modes)
error = priv_check(td, PRIV_NTP_ADJTIME);
if (error != 0)
return (error);
NTP_LOCK();
if (modes & MOD_MAXERROR)
time_maxerror = ntv.maxerror;
time_maxerror = ntv->maxerror;
if (modes & MOD_ESTERROR)
time_esterror = ntv.esterror;
time_esterror = ntv->esterror;
if (modes & MOD_STATUS) {
if (time_status & STA_PLL && !(ntv.status & STA_PLL)) {
if (time_status & STA_PLL && !(ntv->status & STA_PLL)) {
time_state = TIME_OK;
time_status = STA_UNSYNC;
#ifdef PPS_SYNC
@ -384,28 +374,28 @@ sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
#endif /* PPS_SYNC */
}
time_status &= STA_RONLY;
time_status |= ntv.status & ~STA_RONLY;
time_status |= ntv->status & ~STA_RONLY;
}
if (modes & MOD_TIMECONST) {
if (ntv.constant < 0)
if (ntv->constant < 0)
time_constant = 0;
else if (ntv.constant > MAXTC)
else if (ntv->constant > MAXTC)
time_constant = MAXTC;
else
time_constant = ntv.constant;
time_constant = ntv->constant;
}
if (modes & MOD_TAI) {
if (ntv.constant > 0) /* XXX zero & negative numbers ? */
time_tai = ntv.constant;
if (ntv->constant > 0) /* XXX zero & negative numbers ? */
time_tai = ntv->constant;
}
#ifdef PPS_SYNC
if (modes & MOD_PPSMAX) {
if (ntv.shift < PPS_FAVG)
if (ntv->shift < PPS_FAVG)
pps_shiftmax = PPS_FAVG;
else if (ntv.shift > PPS_FAVGMAX)
else if (ntv->shift > PPS_FAVGMAX)
pps_shiftmax = PPS_FAVGMAX;
else
pps_shiftmax = ntv.shift;
pps_shiftmax = ntv->shift;
}
#endif /* PPS_SYNC */
if (modes & MOD_NANO)
@ -417,17 +407,17 @@ sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
if (modes & MOD_CLKA)
time_status &= ~STA_CLK;
if (modes & MOD_FREQUENCY) {
freq = (ntv.freq * 1000LL) >> 16;
freq = (ntv->freq * 1000LL) >> 16;
if (freq > MAXFREQ)
L_LINT(time_freq, MAXFREQ);
else if (freq < -MAXFREQ)
L_LINT(time_freq, -MAXFREQ);
else {
/*
* ntv.freq is [PPM * 2^16] = [us/s * 2^16]
* ntv->freq is [PPM * 2^16] = [us/s * 2^16]
* time_freq is [ns/s * 2^32]
*/
time_freq = ntv.freq * 1000LL * 65536LL;
time_freq = ntv->freq * 1000LL * 65536LL;
}
#ifdef PPS_SYNC
pps_freq = time_freq;
@ -435,9 +425,9 @@ sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
}
if (modes & MOD_OFFSET) {
if (time_status & STA_NANO)
hardupdate(ntv.offset);
hardupdate(ntv->offset);
else
hardupdate(ntv.offset * 1000);
hardupdate(ntv->offset * 1000);
}
/*
@ -445,38 +435,60 @@ sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
* returned only by ntp_gettime();
*/
if (time_status & STA_NANO)
ntv.offset = L_GINT(time_offset);
ntv->offset = L_GINT(time_offset);
else
ntv.offset = L_GINT(time_offset) / 1000; /* XXX rounding ? */
ntv.freq = L_GINT((time_freq / 1000LL) << 16);
ntv.maxerror = time_maxerror;
ntv.esterror = time_esterror;
ntv.status = time_status;
ntv.constant = time_constant;
ntv->offset = L_GINT(time_offset) / 1000; /* XXX rounding ? */
ntv->freq = L_GINT((time_freq / 1000LL) << 16);
ntv->maxerror = time_maxerror;
ntv->esterror = time_esterror;
ntv->status = time_status;
ntv->constant = time_constant;
if (time_status & STA_NANO)
ntv.precision = time_precision;
ntv->precision = time_precision;
else
ntv.precision = time_precision / 1000;
ntv.tolerance = MAXFREQ * SCALE_PPM;
ntv->precision = time_precision / 1000;
ntv->tolerance = MAXFREQ * SCALE_PPM;
#ifdef PPS_SYNC
ntv.shift = pps_shift;
ntv.ppsfreq = L_GINT((pps_freq / 1000LL) << 16);
ntv->shift = pps_shift;
ntv->ppsfreq = L_GINT((pps_freq / 1000LL) << 16);
if (time_status & STA_NANO)
ntv.jitter = pps_jitter;
ntv->jitter = pps_jitter;
else
ntv.jitter = pps_jitter / 1000;
ntv.stabil = pps_stabil;
ntv.calcnt = pps_calcnt;
ntv.errcnt = pps_errcnt;
ntv.jitcnt = pps_jitcnt;
ntv.stbcnt = pps_stbcnt;
ntv->jitter = pps_jitter / 1000;
ntv->stabil = pps_stabil;
ntv->calcnt = pps_calcnt;
ntv->errcnt = pps_errcnt;
ntv->jitcnt = pps_jitcnt;
ntv->stbcnt = pps_stbcnt;
#endif /* PPS_SYNC */
retval = ntp_is_time_error(time_status) ? TIME_ERROR : time_state;
NTP_UNLOCK();
error = copyout((caddr_t)&ntv, (caddr_t)uap->tp, sizeof(ntv));
if (error == 0)
td->td_retval[0] = retval;
*retvalp = retval;
return (0);
}
#ifndef _SYS_SYSPROTO_H_
struct ntp_adjtime_args {
struct timex *tp;
};
#endif
int
sys_ntp_adjtime(struct thread *td, struct ntp_adjtime_args *uap)
{
struct timex ntv;
int error, retval;
error = copyin(uap->tp, &ntv, sizeof(ntv));
if (error == 0) {
error = kern_ntp_adjtime(td, &ntv, &retval);
if (error == 0) {
error = copyout(&ntv, uap->tp, sizeof(ntv));
if (error == 0)
td->td_retval[0] = retval;
}
}
return (error);
}

View File

@ -61,6 +61,7 @@ union semun;
struct sockaddr;
struct stat;
struct thr_param;
struct timex;
struct uio;
struct vm_map;
struct vmspace;
@ -215,6 +216,7 @@ int kern_munlock(struct thread *td, uintptr_t addr, size_t size);
int kern_munmap(struct thread *td, uintptr_t addr, size_t size);
int kern_nanosleep(struct thread *td, struct timespec *rqt,
struct timespec *rmt);
int kern_ntp_adjtime(struct thread *td, struct timex *ntv, int *retvalp);
int kern_ogetdirentries(struct thread *td, struct ogetdirentries_args *uap,
long *ploff);
int kern_openat(struct thread *td, int fd, const char *path,