xref: /openbsd-src/usr.sbin/ntpd/sensors.c (revision 1511e2d13702200f9101559cdb37185e4cc23985)
1*1511e2d1Sotto /*	$OpenBSD: sensors.c,v 1.54 2019/11/11 06:32:52 otto Exp $ */
2dd4ec8aeShenning 
3dd4ec8aeShenning /*
4dd4ec8aeShenning  * Copyright (c) 2006 Henning Brauer <henning@openbsd.org>
5dd4ec8aeShenning  *
6dd4ec8aeShenning  * Permission to use, copy, modify, and distribute this software for any
7dd4ec8aeShenning  * purpose with or without fee is hereby granted, provided that the above
8dd4ec8aeShenning  * copyright notice and this permission notice appear in all copies.
9dd4ec8aeShenning  *
10dd4ec8aeShenning  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11dd4ec8aeShenning  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12dd4ec8aeShenning  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13dd4ec8aeShenning  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14774da4d1Sreyk  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15774da4d1Sreyk  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16774da4d1Sreyk  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17dd4ec8aeShenning  */
18dd4ec8aeShenning 
1961f07045Sderaadt #include <sys/types.h>
20dd4ec8aeShenning #include <sys/queue.h>
2123ec78dbSguenther #include <sys/time.h>
22dd4ec8aeShenning #include <sys/sensors.h>
23dd4ec8aeShenning #include <sys/sysctl.h>
2460524ed1Shenning #include <sys/device.h>
25dd4ec8aeShenning 
26dd4ec8aeShenning #include <errno.h>
27dd4ec8aeShenning #include <fcntl.h>
28c45e6fdaSckuethe #include <stdio.h>
29dd4ec8aeShenning #include <stdlib.h>
30dd4ec8aeShenning #include <string.h>
31dd4ec8aeShenning #include <unistd.h>
32dd4ec8aeShenning 
33dd4ec8aeShenning #include "ntpd.h"
34dd4ec8aeShenning 
3596fb8c11Sderaadt #define MAXDEVNAMLEN		16
36dd4ec8aeShenning 
3796fb8c11Sderaadt int	sensor_probe(int, char *, struct sensor *);
3896fb8c11Sderaadt void	sensor_add(int, char *);
397ff9247fShenning void	sensor_remove(struct ntp_sensor *);
40eef4f1fcShenning void	sensor_update(struct ntp_sensor *);
41c2ad9c59Shenning 
42dd4ec8aeShenning void
sensor_init(void)4396f46bd6Sotto sensor_init(void)
44dd4ec8aeShenning {
45dd4ec8aeShenning 	TAILQ_INIT(&conf->ntp_sensors);
46dd4ec8aeShenning }
47dd4ec8aeShenning 
4808e6c7daSckuethe int
sensor_scan(void)49c2ad9c59Shenning sensor_scan(void)
50dd4ec8aeShenning {
51f7811f45Sderaadt 	int		i, n, err;
5296fb8c11Sderaadt 	char		d[MAXDEVNAMLEN];
5396fb8c11Sderaadt 	struct sensor	s;
54b5afafacShenning 
5508e6c7daSckuethe 	n = 0;
56f7811f45Sderaadt 	for (i = 0; ; i++)
57f7811f45Sderaadt 		if ((err = sensor_probe(i, d, &s))) {
58f7811f45Sderaadt 			if (err == 0)
59f7811f45Sderaadt 				continue;
60f7811f45Sderaadt 			if (err == -1)	/* no further sensors */
61f7811f45Sderaadt 				break;
6296fb8c11Sderaadt 			sensor_add(i, d);
6308e6c7daSckuethe 			n++;
6408e6c7daSckuethe 		}
6508e6c7daSckuethe 
6608e6c7daSckuethe 	return n;
67b5afafacShenning }
68b5afafacShenning 
69f7811f45Sderaadt /*
70f7811f45Sderaadt  * 1 = time sensor!
71f7811f45Sderaadt  * 0 = sensor exists... but is not a time sensor
72f7811f45Sderaadt  * -1: no sensor here, and no further sensors after this
73f7811f45Sderaadt  */
7496fb8c11Sderaadt int
sensor_probe(int devid,char * dxname,struct sensor * sensor)7596fb8c11Sderaadt sensor_probe(int devid, char *dxname, struct sensor *sensor)
76b5afafacShenning {
7796fb8c11Sderaadt 	int			mib[5];
7896fb8c11Sderaadt 	size_t			slen, sdlen;
7996fb8c11Sderaadt 	struct sensordev	sensordev;
80dd4ec8aeShenning 
81dd4ec8aeShenning 	mib[0] = CTL_HW;
82dd4ec8aeShenning 	mib[1] = HW_SENSORS;
8396fb8c11Sderaadt 	mib[2] = devid;
8496fb8c11Sderaadt 	mib[3] = SENSOR_TIMEDELTA;
8596fb8c11Sderaadt 	mib[4] = 0;
86dd4ec8aeShenning 
8796fb8c11Sderaadt 	sdlen = sizeof(sensordev);
8896fb8c11Sderaadt 	if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) {
89f7811f45Sderaadt 		if (errno == ENXIO)
9096fb8c11Sderaadt 			return (0);
91f7811f45Sderaadt 		if (errno == ENOENT)
92f7811f45Sderaadt 			return (-1);
93f7811f45Sderaadt 		log_warn("sensor_probe sysctl");
9496fb8c11Sderaadt 	}
95c81964e4Shenning 
96c81964e4Shenning 	if (sensordev.maxnumt[SENSOR_TIMEDELTA] == 0)
97c81964e4Shenning 		return (0);
98c81964e4Shenning 
9996fb8c11Sderaadt 	strlcpy(dxname, sensordev.xname, MAXDEVNAMLEN);
10096fb8c11Sderaadt 
1014882ef7eSnaddy 	slen = sizeof(*sensor);
10296fb8c11Sderaadt 	if (sysctl(mib, 5, sensor, &slen, NULL, 0) == -1) {
10396fb8c11Sderaadt 		if (errno != ENOENT)
10496fb8c11Sderaadt 			log_warn("sensor_probe sysctl");
10596fb8c11Sderaadt 		return (0);
106dd4ec8aeShenning 	}
107dd4ec8aeShenning 
10896fb8c11Sderaadt 	return (1);
109dd4ec8aeShenning }
110dd4ec8aeShenning 
111dd4ec8aeShenning void
sensor_add(int sensordev,char * dxname)11296fb8c11Sderaadt sensor_add(int sensordev, char *dxname)
113dd4ec8aeShenning {
114dd4ec8aeShenning 	struct ntp_sensor	*s;
115009f3548Shenning 	struct ntp_conf_sensor	*cs;
116dd4ec8aeShenning 
117f5cefd28Sstevesk 	/* check whether it is already there */
118dd4ec8aeShenning 	TAILQ_FOREACH(s, &conf->ntp_sensors, entry)
11996fb8c11Sderaadt 		if (!strcmp(s->device, dxname))
120dd4ec8aeShenning 			return;
121dd4ec8aeShenning 
122c45e6fdaSckuethe 	/* check whether it is requested in the config file */
123009f3548Shenning 	for (cs = TAILQ_FIRST(&conf->ntp_conf_sensors); cs != NULL &&
12496fb8c11Sderaadt 	    strcmp(cs->device, dxname) && strcmp(cs->device, "*");
125009f3548Shenning 	    cs = TAILQ_NEXT(cs, entry))
126009f3548Shenning 		; /* nothing */
127009f3548Shenning 	if (cs == NULL)
128009f3548Shenning 		return;
129009f3548Shenning 
130dd4ec8aeShenning 	if ((s = calloc(1, sizeof(*s))) == NULL)
131dd4ec8aeShenning 		fatal("sensor_add calloc");
132dd4ec8aeShenning 
1332fae8c34Shenning 	s->next = getmonotime();
13449532891Shenning 	s->weight = cs->weight;
135c8ddfef5Sckuethe 	s->correction = cs->correction;
1367d8d1c3fSpatrick 	s->stratum = cs->stratum - 1;
137*1511e2d1Sotto 	s->trusted = cs->trusted;
13896fb8c11Sderaadt 	if ((s->device = strdup(dxname)) == NULL)
139dd4ec8aeShenning 		fatal("sensor_add strdup");
14096fb8c11Sderaadt 	s->sensordevid = sensordev;
141dd4ec8aeShenning 
142c45e6fdaSckuethe 	if (cs->refstr == NULL)
14364c82965Sphessler 		memcpy(&s->refid, SENSOR_DEFAULT_REFID, sizeof(s->refid));
1445b7eb313Sderaadt 	else {
1450f6e6007Sderaadt 		s->refid = 0;
1460f6e6007Sderaadt 		strncpy((char *)&s->refid, cs->refstr, sizeof(s->refid));
1475b7eb313Sderaadt 	}
148c45e6fdaSckuethe 
149dd4ec8aeShenning 	TAILQ_INSERT_TAIL(&conf->ntp_sensors, s, entry);
150dd4ec8aeShenning 
151b2c68928Sbcook 	log_debug("sensor %s added (weight %d, correction %.6f, refstr %.4u, "
1527d8d1c3fSpatrick 	     "stratum %d)", s->device, s->weight, s->correction / 1e6,
153b2c68928Sbcook 	     s->refid, s->stratum);
154dd4ec8aeShenning }
155dd4ec8aeShenning 
156dd4ec8aeShenning void
sensor_remove(struct ntp_sensor * s)157c2ad9c59Shenning sensor_remove(struct ntp_sensor *s)
158dd4ec8aeShenning {
159dd4ec8aeShenning 	TAILQ_REMOVE(&conf->ntp_sensors, s, entry);
160dd4ec8aeShenning 	free(s->device);
161dd4ec8aeShenning 	free(s);
162dd4ec8aeShenning }
163dd4ec8aeShenning 
1647ff9247fShenning void
sensor_query(struct ntp_sensor * s)165dd4ec8aeShenning sensor_query(struct ntp_sensor *s)
166dd4ec8aeShenning {
16796fb8c11Sderaadt 	char		 dxname[MAXDEVNAMLEN];
168dd4ec8aeShenning 	struct sensor	 sensor;
169fe63d0d1Sotto 	double		 sens_time;
170dd4ec8aeShenning 
171e6ce3c48Sstevesk 	if (conf->settime)
172e6ce3c48Sstevesk 		s->next = getmonotime() + SENSOR_QUERY_INTERVAL_SETTIME;
173e6ce3c48Sstevesk 	else
1742fae8c34Shenning 		s->next = getmonotime() + SENSOR_QUERY_INTERVAL;
1752fae8c34Shenning 
1762fae8c34Shenning 	/* rcvd is walltime here, monotime in client.c. not used elsewhere */
177dd4ec8aeShenning 	if (s->update.rcvd < time(NULL) - SENSOR_DATA_MAXAGE)
178dd4ec8aeShenning 		s->update.good = 0;
179dd4ec8aeShenning 
18096fb8c11Sderaadt 	if (!sensor_probe(s->sensordevid, dxname, &sensor)) {
1816c60119fShenning 		sensor_remove(s);
1827ff9247fShenning 		return;
183dd4ec8aeShenning 	}
184dd4ec8aeShenning 
185dd4ec8aeShenning 	if (sensor.flags & SENSOR_FINVALID ||
186dd4ec8aeShenning 	    sensor.status != SENSOR_S_OK)
1877ff9247fShenning 		return;
188dd4ec8aeShenning 
18996fb8c11Sderaadt 	if (strcmp(dxname, s->device)) {
1907ff9247fShenning 		sensor_remove(s);
1917ff9247fShenning 		return;
1927ff9247fShenning 	}
193dd4ec8aeShenning 
194a337ad71Shenning 	if (sensor.tv.tv_sec == s->last)	/* already seen */
1957ff9247fShenning 		return;
196dd4ec8aeShenning 
197a337ad71Shenning 	s->last = sensor.tv.tv_sec;
198fe63d0d1Sotto 
199*1511e2d1Sotto 	if (!s->trusted && !TAILQ_EMPTY(&conf->constraints)) {
200fe63d0d1Sotto 		if (conf->constraint_median == 0) {
201fe63d0d1Sotto 			return;
202fe63d0d1Sotto 		}
203fe63d0d1Sotto 		sens_time = gettime() + (sensor.value / -1e9) +
204fe63d0d1Sotto 		    (s->correction / 1e6);
205fe63d0d1Sotto 		if (constraint_check(sens_time) != 0) {
206fe63d0d1Sotto 			log_info("sensor %s: constraint check failed", s->device);
207fe63d0d1Sotto 			return;
208fe63d0d1Sotto 		}
209fe63d0d1Sotto 	}
210c5565af9Sotto 	/*
211c5565af9Sotto 	 * TD = device time
212c5565af9Sotto 	 * TS = system time
213c5565af9Sotto 	 * sensor.value = TS - TD in ns
214c5565af9Sotto 	 * if value is positive, system time is ahead
215c5565af9Sotto 	 */
216c8ddfef5Sckuethe 	s->offsets[s->shift].offset = (sensor.value / -1e9) - getoffset() +
217c8ddfef5Sckuethe 	    (s->correction / 1e6);
218eef4f1fcShenning 	s->offsets[s->shift].rcvd = sensor.tv.tv_sec;
219eef4f1fcShenning 	s->offsets[s->shift].good = 1;
22086bfb248Shenning 
22129dd0d72Snaddy 	s->offsets[s->shift].status.send_refid = s->refid;
2227d8d1c3fSpatrick 	/* stratum increased when sent out */
2237d8d1c3fSpatrick 	s->offsets[s->shift].status.stratum = s->stratum;
224eef4f1fcShenning 	s->offsets[s->shift].status.rootdelay = 0;
225eef4f1fcShenning 	s->offsets[s->shift].status.rootdispersion = 0;
226eef4f1fcShenning 	s->offsets[s->shift].status.reftime = sensor.tv.tv_sec;
227eef4f1fcShenning 	s->offsets[s->shift].status.synced = 1;
228dd4ec8aeShenning 
229eef4f1fcShenning 	log_debug("sensor %s: offset %f", s->device,
230eef4f1fcShenning 	    s->offsets[s->shift].offset);
231eef4f1fcShenning 
232eef4f1fcShenning 	if (++s->shift >= SENSOR_OFFSETS) {
233eef4f1fcShenning 		s->shift = 0;
234eef4f1fcShenning 		sensor_update(s);
235eef4f1fcShenning 	}
236eef4f1fcShenning 
237eef4f1fcShenning }
238eef4f1fcShenning 
239eef4f1fcShenning void
sensor_update(struct ntp_sensor * s)240eef4f1fcShenning sensor_update(struct ntp_sensor *s)
241eef4f1fcShenning {
242eef4f1fcShenning 	struct ntp_offset	**offsets;
243eef4f1fcShenning 	int			  i;
244eef4f1fcShenning 
245eef4f1fcShenning 	if ((offsets = calloc(SENSOR_OFFSETS, sizeof(struct ntp_offset *))) ==
246eef4f1fcShenning 	    NULL)
247eef4f1fcShenning 		fatal("calloc sensor_update");
248eef4f1fcShenning 
249eef4f1fcShenning 	for (i = 0; i < SENSOR_OFFSETS; i++)
250eef4f1fcShenning 		offsets[i] = &s->offsets[i];
251eef4f1fcShenning 
252eef4f1fcShenning 	qsort(offsets, SENSOR_OFFSETS, sizeof(struct ntp_offset *),
253eef4f1fcShenning 	    offset_compare);
254eef4f1fcShenning 
255eef4f1fcShenning 	i = SENSOR_OFFSETS / 2;
256eef4f1fcShenning 	memcpy(&s->update, offsets[i], sizeof(s->update));
257eef4f1fcShenning 	if (SENSOR_OFFSETS % 2 == 0) {
258eef4f1fcShenning 		s->update.offset =
259eef4f1fcShenning 		    (offsets[i - 1]->offset + offsets[i]->offset) / 2;
260eef4f1fcShenning 	}
261eef4f1fcShenning 	free(offsets);
262eef4f1fcShenning 
263eef4f1fcShenning 	log_debug("sensor update %s: offset %f", s->device, s->update.offset);
2646083848eShenning 	priv_adjtime();
265dd4ec8aeShenning }
266