1 /* $OpenBSD: sensors.c,v 1.54 2019/11/11 06:32:52 otto Exp $ */ 2 3 /* 4 * Copyright (c) 2006 Henning Brauer <henning@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/types.h> 20 #include <sys/queue.h> 21 #include <sys/time.h> 22 #include <sys/sensors.h> 23 #include <sys/sysctl.h> 24 #include <sys/device.h> 25 26 #include <errno.h> 27 #include <fcntl.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <string.h> 31 #include <unistd.h> 32 33 #include "ntpd.h" 34 35 #define MAXDEVNAMLEN 16 36 37 int sensor_probe(int, char *, struct sensor *); 38 void sensor_add(int, char *); 39 void sensor_remove(struct ntp_sensor *); 40 void sensor_update(struct ntp_sensor *); 41 42 void 43 sensor_init(void) 44 { 45 TAILQ_INIT(&conf->ntp_sensors); 46 } 47 48 int 49 sensor_scan(void) 50 { 51 int i, n, err; 52 char d[MAXDEVNAMLEN]; 53 struct sensor s; 54 55 n = 0; 56 for (i = 0; ; i++) 57 if ((err = sensor_probe(i, d, &s))) { 58 if (err == 0) 59 continue; 60 if (err == -1) /* no further sensors */ 61 break; 62 sensor_add(i, d); 63 n++; 64 } 65 66 return n; 67 } 68 69 /* 70 * 1 = time sensor! 71 * 0 = sensor exists... but is not a time sensor 72 * -1: no sensor here, and no further sensors after this 73 */ 74 int 75 sensor_probe(int devid, char *dxname, struct sensor *sensor) 76 { 77 int mib[5]; 78 size_t slen, sdlen; 79 struct sensordev sensordev; 80 81 mib[0] = CTL_HW; 82 mib[1] = HW_SENSORS; 83 mib[2] = devid; 84 mib[3] = SENSOR_TIMEDELTA; 85 mib[4] = 0; 86 87 sdlen = sizeof(sensordev); 88 if (sysctl(mib, 3, &sensordev, &sdlen, NULL, 0) == -1) { 89 if (errno == ENXIO) 90 return (0); 91 if (errno == ENOENT) 92 return (-1); 93 log_warn("sensor_probe sysctl"); 94 } 95 96 if (sensordev.maxnumt[SENSOR_TIMEDELTA] == 0) 97 return (0); 98 99 strlcpy(dxname, sensordev.xname, MAXDEVNAMLEN); 100 101 slen = sizeof(*sensor); 102 if (sysctl(mib, 5, sensor, &slen, NULL, 0) == -1) { 103 if (errno != ENOENT) 104 log_warn("sensor_probe sysctl"); 105 return (0); 106 } 107 108 return (1); 109 } 110 111 void 112 sensor_add(int sensordev, char *dxname) 113 { 114 struct ntp_sensor *s; 115 struct ntp_conf_sensor *cs; 116 117 /* check whether it is already there */ 118 TAILQ_FOREACH(s, &conf->ntp_sensors, entry) 119 if (!strcmp(s->device, dxname)) 120 return; 121 122 /* check whether it is requested in the config file */ 123 for (cs = TAILQ_FIRST(&conf->ntp_conf_sensors); cs != NULL && 124 strcmp(cs->device, dxname) && strcmp(cs->device, "*"); 125 cs = TAILQ_NEXT(cs, entry)) 126 ; /* nothing */ 127 if (cs == NULL) 128 return; 129 130 if ((s = calloc(1, sizeof(*s))) == NULL) 131 fatal("sensor_add calloc"); 132 133 s->next = getmonotime(); 134 s->weight = cs->weight; 135 s->correction = cs->correction; 136 s->stratum = cs->stratum - 1; 137 s->trusted = cs->trusted; 138 if ((s->device = strdup(dxname)) == NULL) 139 fatal("sensor_add strdup"); 140 s->sensordevid = sensordev; 141 142 if (cs->refstr == NULL) 143 memcpy(&s->refid, SENSOR_DEFAULT_REFID, sizeof(s->refid)); 144 else { 145 s->refid = 0; 146 strncpy((char *)&s->refid, cs->refstr, sizeof(s->refid)); 147 } 148 149 TAILQ_INSERT_TAIL(&conf->ntp_sensors, s, entry); 150 151 log_debug("sensor %s added (weight %d, correction %.6f, refstr %.4u, " 152 "stratum %d)", s->device, s->weight, s->correction / 1e6, 153 s->refid, s->stratum); 154 } 155 156 void 157 sensor_remove(struct ntp_sensor *s) 158 { 159 TAILQ_REMOVE(&conf->ntp_sensors, s, entry); 160 free(s->device); 161 free(s); 162 } 163 164 void 165 sensor_query(struct ntp_sensor *s) 166 { 167 char dxname[MAXDEVNAMLEN]; 168 struct sensor sensor; 169 double sens_time; 170 171 if (conf->settime) 172 s->next = getmonotime() + SENSOR_QUERY_INTERVAL_SETTIME; 173 else 174 s->next = getmonotime() + SENSOR_QUERY_INTERVAL; 175 176 /* rcvd is walltime here, monotime in client.c. not used elsewhere */ 177 if (s->update.rcvd < time(NULL) - SENSOR_DATA_MAXAGE) 178 s->update.good = 0; 179 180 if (!sensor_probe(s->sensordevid, dxname, &sensor)) { 181 sensor_remove(s); 182 return; 183 } 184 185 if (sensor.flags & SENSOR_FINVALID || 186 sensor.status != SENSOR_S_OK) 187 return; 188 189 if (strcmp(dxname, s->device)) { 190 sensor_remove(s); 191 return; 192 } 193 194 if (sensor.tv.tv_sec == s->last) /* already seen */ 195 return; 196 197 s->last = sensor.tv.tv_sec; 198 199 if (!s->trusted && !TAILQ_EMPTY(&conf->constraints)) { 200 if (conf->constraint_median == 0) { 201 return; 202 } 203 sens_time = gettime() + (sensor.value / -1e9) + 204 (s->correction / 1e6); 205 if (constraint_check(sens_time) != 0) { 206 log_info("sensor %s: constraint check failed", s->device); 207 return; 208 } 209 } 210 /* 211 * TD = device time 212 * TS = system time 213 * sensor.value = TS - TD in ns 214 * if value is positive, system time is ahead 215 */ 216 s->offsets[s->shift].offset = (sensor.value / -1e9) - getoffset() + 217 (s->correction / 1e6); 218 s->offsets[s->shift].rcvd = sensor.tv.tv_sec; 219 s->offsets[s->shift].good = 1; 220 221 s->offsets[s->shift].status.send_refid = s->refid; 222 /* stratum increased when sent out */ 223 s->offsets[s->shift].status.stratum = s->stratum; 224 s->offsets[s->shift].status.rootdelay = 0; 225 s->offsets[s->shift].status.rootdispersion = 0; 226 s->offsets[s->shift].status.reftime = sensor.tv.tv_sec; 227 s->offsets[s->shift].status.synced = 1; 228 229 log_debug("sensor %s: offset %f", s->device, 230 s->offsets[s->shift].offset); 231 232 if (++s->shift >= SENSOR_OFFSETS) { 233 s->shift = 0; 234 sensor_update(s); 235 } 236 237 } 238 239 void 240 sensor_update(struct ntp_sensor *s) 241 { 242 struct ntp_offset **offsets; 243 int i; 244 245 if ((offsets = calloc(SENSOR_OFFSETS, sizeof(struct ntp_offset *))) == 246 NULL) 247 fatal("calloc sensor_update"); 248 249 for (i = 0; i < SENSOR_OFFSETS; i++) 250 offsets[i] = &s->offsets[i]; 251 252 qsort(offsets, SENSOR_OFFSETS, sizeof(struct ntp_offset *), 253 offset_compare); 254 255 i = SENSOR_OFFSETS / 2; 256 memcpy(&s->update, offsets[i], sizeof(s->update)); 257 if (SENSOR_OFFSETS % 2 == 0) { 258 s->update.offset = 259 (offsets[i - 1]->offset + offsets[i]->offset) / 2; 260 } 261 free(offsets); 262 263 log_debug("sensor update %s: offset %f", s->device, s->update.offset); 264 priv_adjtime(); 265 } 266