xref: /freebsd/contrib/bsnmp/snmp_ntp/snmp_ntp.c (revision 8e9b3e707151d136ec95e7f1d37556e39c1e228c)
1d7eb6b47SHartmut Brandt /*
2*8e9b3e70SHartmut Brandt  * Copyright (c) 2005,2018
3d7eb6b47SHartmut Brandt  *	Hartmut Brandt.
4d7eb6b47SHartmut Brandt  *	All rights reserved.
5d7eb6b47SHartmut Brandt  *
6d7eb6b47SHartmut Brandt  * Author: Harti Brandt <harti@freebsd.org>
7d7eb6b47SHartmut Brandt  *
8d7eb6b47SHartmut Brandt  * Redistribution of this software and documentation and use in source and
9d7eb6b47SHartmut Brandt  * binary forms, with or without modification, are permitted provided that
10d7eb6b47SHartmut Brandt  * the following conditions are met:
11d7eb6b47SHartmut Brandt  *
12d7eb6b47SHartmut Brandt  * 1. Redistributions of source code or documentation must retain the above
13d7eb6b47SHartmut Brandt  *    copyright notice, this list of conditions and the following disclaimer.
14d7eb6b47SHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
15d7eb6b47SHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
16d7eb6b47SHartmut Brandt  *    documentation and/or other materials provided with the distribution.
17d7eb6b47SHartmut Brandt  *
18d7eb6b47SHartmut Brandt  * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
19d7eb6b47SHartmut Brandt  * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20d7eb6b47SHartmut Brandt  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21d7eb6b47SHartmut Brandt  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22d7eb6b47SHartmut Brandt  * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23d7eb6b47SHartmut Brandt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24d7eb6b47SHartmut Brandt  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25d7eb6b47SHartmut Brandt  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26d7eb6b47SHartmut Brandt  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27d7eb6b47SHartmut Brandt  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28d7eb6b47SHartmut Brandt  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29d7eb6b47SHartmut Brandt  *
30748b5b1eSHartmut Brandt  * $Begemot: bsnmp/snmp_ntp/snmp_ntp.c,v 1.9 2005/10/06 07:15:01 brandt_h Exp $
31d7eb6b47SHartmut Brandt  *
32d7eb6b47SHartmut Brandt  * NTP interface for SNMPd.
33d7eb6b47SHartmut Brandt  */
34d7eb6b47SHartmut Brandt 
35d7eb6b47SHartmut Brandt #include <sys/queue.h>
36d7eb6b47SHartmut Brandt #include <sys/time.h>
37d7eb6b47SHartmut Brandt #include <sys/types.h>
38d7eb6b47SHartmut Brandt #include <sys/select.h>
39d7eb6b47SHartmut Brandt #include <sys/socket.h>
40d7eb6b47SHartmut Brandt #include <ctype.h>
41d7eb6b47SHartmut Brandt #include <errno.h>
42d7eb6b47SHartmut Brandt #include <netdb.h>
43165c5d31SHartmut Brandt #ifdef HAVE_STDINT_H
44d7eb6b47SHartmut Brandt #include <stdint.h>
45165c5d31SHartmut Brandt #elif defined(HAVE_INTTYPES_H)
46165c5d31SHartmut Brandt #include <inttypes.h>
47165c5d31SHartmut Brandt #endif
48d7eb6b47SHartmut Brandt #include <stdio.h>
49d7eb6b47SHartmut Brandt #include <stdlib.h>
50d7eb6b47SHartmut Brandt #include <string.h>
51d7eb6b47SHartmut Brandt #include <syslog.h>
52d7eb6b47SHartmut Brandt #include <unistd.h>
53d7eb6b47SHartmut Brandt 
54748b5b1eSHartmut Brandt #include "support.h"
55d7eb6b47SHartmut Brandt #include "snmpmod.h"
56*8e9b3e70SHartmut Brandt 
57*8e9b3e70SHartmut Brandt #define	SNMPTREE_TYPES
58d7eb6b47SHartmut Brandt #include "ntp_tree.h"
59d7eb6b47SHartmut Brandt #include "ntp_oid.h"
60d7eb6b47SHartmut Brandt 
61d7eb6b47SHartmut Brandt #define	NTPC_MAX	576
62d7eb6b47SHartmut Brandt #define	NTPC_VERSION	3
63d7eb6b47SHartmut Brandt #define	NTPC_MODE	6
64d7eb6b47SHartmut Brandt #define	NTPC_DMAX	468
65d7eb6b47SHartmut Brandt 
66d7eb6b47SHartmut Brandt #define	NTPC_BIT_RESP	0x80
67d7eb6b47SHartmut Brandt #define	NTPC_BIT_ERROR	0x40
68d7eb6b47SHartmut Brandt #define	NTPC_BIT_MORE	0x20
69d7eb6b47SHartmut Brandt 
70d7eb6b47SHartmut Brandt #define	NTPC_OPMASK	0x1f
71d7eb6b47SHartmut Brandt #define	NTPC_OP_READSTAT	1
72d7eb6b47SHartmut Brandt #define	NTPC_OP_READVAR		2
73d7eb6b47SHartmut Brandt 
74d7eb6b47SHartmut Brandt /* our module handle */
75d7eb6b47SHartmut Brandt static struct lmodule *module;
76d7eb6b47SHartmut Brandt 
77d7eb6b47SHartmut Brandt /* debug flag */
78d7eb6b47SHartmut Brandt static uint32_t ntp_debug;
79d7eb6b47SHartmut Brandt #define DBG_DUMP_PKTS	0x01
80d7eb6b47SHartmut Brandt #define	DBG_DUMP_VARS	0x02
81d7eb6b47SHartmut Brandt 
82d7eb6b47SHartmut Brandt /* OIDs */
83d7eb6b47SHartmut Brandt static const struct asn_oid oid_ntpMIB = OIDX_ntpMIB;
84d7eb6b47SHartmut Brandt 
85d7eb6b47SHartmut Brandt /* the Object Resource registration index */
86d7eb6b47SHartmut Brandt static u_int reg_index;
87d7eb6b47SHartmut Brandt 
88d7eb6b47SHartmut Brandt /* last time we've fetch the system variables */
8969292cedSHartmut Brandt static uint64_t sysinfo_tick;
90d7eb6b47SHartmut Brandt 
91d7eb6b47SHartmut Brandt /* cached system variables */
92d7eb6b47SHartmut Brandt static int32_t	sys_leap;
93d7eb6b47SHartmut Brandt static int	sysb_leap;
94d7eb6b47SHartmut Brandt static int32_t	sys_stratum;
95d7eb6b47SHartmut Brandt static int	sysb_stratum;
96d7eb6b47SHartmut Brandt static int32_t	sys_precision;
97d7eb6b47SHartmut Brandt static int	sysb_precision;
98d7eb6b47SHartmut Brandt static char	*sys_rootdelay;
99d7eb6b47SHartmut Brandt static char	*sys_rootdispersion;
100d7eb6b47SHartmut Brandt static char	*sys_refid;
101d7eb6b47SHartmut Brandt static char	sys_reftime[8];
102d7eb6b47SHartmut Brandt static int	sysb_reftime;
103d7eb6b47SHartmut Brandt static int32_t	sys_poll;
104d7eb6b47SHartmut Brandt static int	sysb_poll;
105d7eb6b47SHartmut Brandt static uint32_t	sys_peer;
106d7eb6b47SHartmut Brandt static int	sysb_peer;
107d7eb6b47SHartmut Brandt static u_char	sys_clock[8];
108d7eb6b47SHartmut Brandt static int	sysb_clock;
109d7eb6b47SHartmut Brandt static char	*sys_system;
110d7eb6b47SHartmut Brandt static char	*sys_processor;
111d7eb6b47SHartmut Brandt static int	sysb_jitter;
112d7eb6b47SHartmut Brandt static double	sys_jitter;
113d7eb6b47SHartmut Brandt static int	sysb_stability;
114d7eb6b47SHartmut Brandt static double	sys_stability;
115d7eb6b47SHartmut Brandt 
116d7eb6b47SHartmut Brandt /* last time we've fetch the peer list */
11769292cedSHartmut Brandt static uint64_t peers_tick;
118d7eb6b47SHartmut Brandt 
119d7eb6b47SHartmut Brandt /* request sequence number generator */
120d7eb6b47SHartmut Brandt static uint16_t	seqno;
121d7eb6b47SHartmut Brandt 
122d7eb6b47SHartmut Brandt /* NTPD socket */
123d7eb6b47SHartmut Brandt static int ntpd_sock;
124d7eb6b47SHartmut Brandt static void *ntpd_fd;
125d7eb6b47SHartmut Brandt 
126d7eb6b47SHartmut Brandt struct peer {
127d7eb6b47SHartmut Brandt 	/* required entries for macros */
128d7eb6b47SHartmut Brandt 	uint32_t	index;
129d7eb6b47SHartmut Brandt 	TAILQ_ENTRY(peer) link;
130d7eb6b47SHartmut Brandt 
131d7eb6b47SHartmut Brandt 	int32_t		config;		/* config bit */
132d7eb6b47SHartmut Brandt 	u_char		srcadr[4];	/* PeerAddress */
133d7eb6b47SHartmut Brandt 	uint32_t	srcport;	/* PeerPort */
134d7eb6b47SHartmut Brandt 	u_char		dstadr[4];	/* HostAddress */
135d7eb6b47SHartmut Brandt 	uint32_t	dstport;	/* HostPort */
136d7eb6b47SHartmut Brandt 	int32_t		leap;		/* Leap */
137d7eb6b47SHartmut Brandt 	int32_t		hmode;		/* Mode */
138d7eb6b47SHartmut Brandt 	int32_t		stratum;	/* Stratum */
139d7eb6b47SHartmut Brandt 	int32_t		ppoll;		/* PeerPoll */
140d7eb6b47SHartmut Brandt 	int32_t		hpoll;		/* HostPoll */
141d7eb6b47SHartmut Brandt 	int32_t		precision;	/* Precision */
142d7eb6b47SHartmut Brandt 	char		*rootdelay;	/* RootDelay */
143d7eb6b47SHartmut Brandt 	char		*rootdispersion;/* RootDispersion */
144d7eb6b47SHartmut Brandt 	char		*refid;		/* RefId */
145d7eb6b47SHartmut Brandt 	u_char		reftime[8];	/* RefTime */
146d7eb6b47SHartmut Brandt 	u_char		orgtime[8];	/* OrgTime */
147d7eb6b47SHartmut Brandt 	u_char		rcvtime[8];	/* ReceiveTime */
148d7eb6b47SHartmut Brandt 	u_char		xmttime[8];	/* TransmitTime */
149d7eb6b47SHartmut Brandt 	u_int32_t	reach;		/* Reach */
150d7eb6b47SHartmut Brandt 	int32_t		timer;		/* Timer */
151d7eb6b47SHartmut Brandt 	char		*offset;	/* Offset */
152d7eb6b47SHartmut Brandt 	char		*delay;		/* Delay */
153d7eb6b47SHartmut Brandt 	char		*dispersion;	/* Dispersion */
154d7eb6b47SHartmut Brandt 	int32_t		filt_entries;
155d7eb6b47SHartmut Brandt };
156d7eb6b47SHartmut Brandt TAILQ_HEAD(peer_list, peer);
157d7eb6b47SHartmut Brandt 
158d7eb6b47SHartmut Brandt /* list of peers */
159d7eb6b47SHartmut Brandt static struct peer_list peers = TAILQ_HEAD_INITIALIZER(peers);
160d7eb6b47SHartmut Brandt 
161d7eb6b47SHartmut Brandt struct filt {
162d7eb6b47SHartmut Brandt 	/* required fields */
163d7eb6b47SHartmut Brandt 	struct asn_oid	index;
164d7eb6b47SHartmut Brandt 	TAILQ_ENTRY(filt) link;
165d7eb6b47SHartmut Brandt 
166d7eb6b47SHartmut Brandt 	char		*offset;
167d7eb6b47SHartmut Brandt 	char		*delay;
168d7eb6b47SHartmut Brandt 	char		*dispersion;
169d7eb6b47SHartmut Brandt };
170d7eb6b47SHartmut Brandt TAILQ_HEAD(filt_list, filt);
171d7eb6b47SHartmut Brandt 
172d7eb6b47SHartmut Brandt /* list of filters */
173d7eb6b47SHartmut Brandt static struct filt_list filts = TAILQ_HEAD_INITIALIZER(filts);
174d7eb6b47SHartmut Brandt 
175d7eb6b47SHartmut Brandt /* configuration */
176d7eb6b47SHartmut Brandt static u_char *ntp_host;
177d7eb6b47SHartmut Brandt static u_char *ntp_port;
178d7eb6b47SHartmut Brandt static uint32_t ntp_timeout;
179d7eb6b47SHartmut Brandt 
180d7eb6b47SHartmut Brandt static void ntpd_input(int, void *);
181d7eb6b47SHartmut Brandt static int open_socket(void);
182d7eb6b47SHartmut Brandt 
183165c5d31SHartmut Brandt /* the initialization function */
184d7eb6b47SHartmut Brandt static int
ntp_init(struct lmodule * mod,int argc,char * argv[]__unused)185d7eb6b47SHartmut Brandt ntp_init(struct lmodule *mod, int argc, char *argv[] __unused)
186d7eb6b47SHartmut Brandt {
187d7eb6b47SHartmut Brandt 
188d7eb6b47SHartmut Brandt 	module = mod;
189d7eb6b47SHartmut Brandt 
190d7eb6b47SHartmut Brandt 	if (argc != 0) {
191d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "bad number of arguments for %s", __func__);
192d7eb6b47SHartmut Brandt 		return (EINVAL);
193d7eb6b47SHartmut Brandt 	}
194d7eb6b47SHartmut Brandt 
195d7eb6b47SHartmut Brandt 	ntp_host = strdup("localhost");
196d7eb6b47SHartmut Brandt 	ntp_port = strdup("ntp");
197d7eb6b47SHartmut Brandt 	ntp_timeout = 50;		/* 0.5sec */
198d7eb6b47SHartmut Brandt 
199d7eb6b47SHartmut Brandt 	return (0);
200d7eb6b47SHartmut Brandt }
201d7eb6b47SHartmut Brandt 
202d7eb6b47SHartmut Brandt /*
203d7eb6b47SHartmut Brandt  * Module is started
204d7eb6b47SHartmut Brandt  */
205d7eb6b47SHartmut Brandt static void
ntp_start(void)206d7eb6b47SHartmut Brandt ntp_start(void)
207d7eb6b47SHartmut Brandt {
208d7eb6b47SHartmut Brandt 
209d7eb6b47SHartmut Brandt 	if (open_socket() != -1) {
210d7eb6b47SHartmut Brandt 		ntpd_fd = fd_select(ntpd_sock, ntpd_input, NULL, module);
211d7eb6b47SHartmut Brandt 		if (ntpd_fd == NULL) {
212d7eb6b47SHartmut Brandt 			syslog(LOG_ERR, "fd_select failed on ntpd socket: %m");
213d7eb6b47SHartmut Brandt 			return;
214d7eb6b47SHartmut Brandt 		}
215d7eb6b47SHartmut Brandt 	}
216d7eb6b47SHartmut Brandt 	reg_index = or_register(&oid_ntpMIB, "The MIB for NTP.", module);
217d7eb6b47SHartmut Brandt }
218d7eb6b47SHartmut Brandt 
219d7eb6b47SHartmut Brandt /*
220d7eb6b47SHartmut Brandt  * Called, when the module is to be unloaded after it was successfully loaded
221d7eb6b47SHartmut Brandt  */
222d7eb6b47SHartmut Brandt static int
ntp_fini(void)223d7eb6b47SHartmut Brandt ntp_fini(void)
224d7eb6b47SHartmut Brandt {
225d7eb6b47SHartmut Brandt 
226d7eb6b47SHartmut Brandt 	or_unregister(reg_index);
227d7eb6b47SHartmut Brandt 	fd_deselect(ntpd_fd);
228d7eb6b47SHartmut Brandt 
229d7eb6b47SHartmut Brandt 	return (0);
230d7eb6b47SHartmut Brandt }
231d7eb6b47SHartmut Brandt 
232d7eb6b47SHartmut Brandt const struct snmp_module config = {
233d7eb6b47SHartmut Brandt 	.comment =	"This module implements the NTP MIB",
234d7eb6b47SHartmut Brandt 	.init =		ntp_init,
235d7eb6b47SHartmut Brandt 	.start =	ntp_start,
236d7eb6b47SHartmut Brandt 	.fini =		ntp_fini,
237d7eb6b47SHartmut Brandt 	.tree =		ntp_ctree,
238d7eb6b47SHartmut Brandt 	.tree_size =	ntp_CTREE_SIZE,
239d7eb6b47SHartmut Brandt };
240d7eb6b47SHartmut Brandt 
241d7eb6b47SHartmut Brandt /*
242d7eb6b47SHartmut Brandt  * Open the NTPD socket
243d7eb6b47SHartmut Brandt  */
244d7eb6b47SHartmut Brandt static int
open_socket(void)245d7eb6b47SHartmut Brandt open_socket(void)
246d7eb6b47SHartmut Brandt {
247d7eb6b47SHartmut Brandt 	struct addrinfo hints, *res, *res0;
248d7eb6b47SHartmut Brandt 	int	error;
249d7eb6b47SHartmut Brandt 	const char *cause;
250d7eb6b47SHartmut Brandt 
251d7eb6b47SHartmut Brandt 	memset(&hints, 0, sizeof(hints));
252d7eb6b47SHartmut Brandt 	hints.ai_family = AF_INET;
253d7eb6b47SHartmut Brandt 	hints.ai_socktype = SOCK_DGRAM;
254d7eb6b47SHartmut Brandt 
255d7eb6b47SHartmut Brandt 	error = getaddrinfo(ntp_host, ntp_port, &hints, &res0);
256d7eb6b47SHartmut Brandt 	if (error) {
257d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "%s(%s): %s", ntp_host, ntp_port,
258d7eb6b47SHartmut Brandt 		    gai_strerror(error));
259d7eb6b47SHartmut Brandt 		return (-1);
260d7eb6b47SHartmut Brandt 	}
261d7eb6b47SHartmut Brandt 
262d7eb6b47SHartmut Brandt 	ntpd_sock = -1;
263d7eb6b47SHartmut Brandt 	cause = "no address";
264d7eb6b47SHartmut Brandt 	errno = EADDRNOTAVAIL;
265d7eb6b47SHartmut Brandt 	for (res = res0; res != NULL; res = res->ai_next) {
266d7eb6b47SHartmut Brandt 		ntpd_sock = socket(res->ai_family, res->ai_socktype,
267d7eb6b47SHartmut Brandt 		    res->ai_protocol);
268d7eb6b47SHartmut Brandt 		if (ntpd_sock == -1) {
269d7eb6b47SHartmut Brandt 			cause = "socket";
270d7eb6b47SHartmut Brandt 			continue;
271d7eb6b47SHartmut Brandt 		}
272d7eb6b47SHartmut Brandt 		if (connect(ntpd_sock, res->ai_addr, res->ai_addrlen) == -1) {
273d7eb6b47SHartmut Brandt 			cause = "connect";
274d7eb6b47SHartmut Brandt 			(void)close(ntpd_sock);
275d7eb6b47SHartmut Brandt 			ntpd_sock = -1;
276d7eb6b47SHartmut Brandt 			continue;
277d7eb6b47SHartmut Brandt 		}
278d7eb6b47SHartmut Brandt 		break;
279d7eb6b47SHartmut Brandt 	}
280d7eb6b47SHartmut Brandt 	if (ntpd_sock == -1) {
281d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "%s: %m", cause);
282d7eb6b47SHartmut Brandt 		return (-1);
283d7eb6b47SHartmut Brandt 	}
284d7eb6b47SHartmut Brandt 	freeaddrinfo(res0);
285d7eb6b47SHartmut Brandt 	return (0);
286d7eb6b47SHartmut Brandt }
287d7eb6b47SHartmut Brandt 
288d7eb6b47SHartmut Brandt /*
289d7eb6b47SHartmut Brandt  * Dump a packet
290d7eb6b47SHartmut Brandt  */
291d7eb6b47SHartmut Brandt static void
dump_packet(const u_char * pkt,size_t ret)292d7eb6b47SHartmut Brandt dump_packet(const u_char *pkt, size_t ret)
293d7eb6b47SHartmut Brandt {
294d7eb6b47SHartmut Brandt 	char buf[8 * 3 + 1];
295d7eb6b47SHartmut Brandt 	size_t i, j;
296d7eb6b47SHartmut Brandt 
297d7eb6b47SHartmut Brandt 	for (i = 0; i < ret; i += 8) {
298d7eb6b47SHartmut Brandt 		buf[0] = '\0';
299d7eb6b47SHartmut Brandt 		for (j = 0; i + j < (size_t)ret && j < 8; j++)
300d7eb6b47SHartmut Brandt 			sprintf(buf + strlen(buf), " %02x", pkt[i + j]);
301d7eb6b47SHartmut Brandt 		syslog(LOG_INFO, "%04zu:%s", i, buf);
302d7eb6b47SHartmut Brandt 	}
303d7eb6b47SHartmut Brandt }
304d7eb6b47SHartmut Brandt 
305d7eb6b47SHartmut Brandt /*
306d7eb6b47SHartmut Brandt  * Execute an NTP request.
307d7eb6b47SHartmut Brandt  */
308d7eb6b47SHartmut Brandt static int
ntpd_request(u_int op,u_int associd,const char * vars)309d7eb6b47SHartmut Brandt ntpd_request(u_int op, u_int associd, const char *vars)
310d7eb6b47SHartmut Brandt {
311d7eb6b47SHartmut Brandt 	u_char	*rpkt;
312d7eb6b47SHartmut Brandt 	u_char	*ptr;
313d7eb6b47SHartmut Brandt 	size_t	vlen;
314d7eb6b47SHartmut Brandt 	ssize_t	ret;
315d7eb6b47SHartmut Brandt 
316d7eb6b47SHartmut Brandt 	if ((rpkt = malloc(NTPC_MAX)) == NULL) {
317d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "%m");
318d7eb6b47SHartmut Brandt 		return (-1);
319d7eb6b47SHartmut Brandt 	}
320d7eb6b47SHartmut Brandt 	memset(rpkt, 0, NTPC_MAX);
321d7eb6b47SHartmut Brandt 
322d7eb6b47SHartmut Brandt 	ptr = rpkt;
323d7eb6b47SHartmut Brandt 	*ptr++ = (NTPC_VERSION << 3) | NTPC_MODE;
324d7eb6b47SHartmut Brandt 	*ptr++ = op;
325d7eb6b47SHartmut Brandt 
326d7eb6b47SHartmut Brandt 	if (++seqno == 0)
327d7eb6b47SHartmut Brandt 		seqno++;
328d7eb6b47SHartmut Brandt 	*ptr++ = seqno >> 8;
329d7eb6b47SHartmut Brandt 	*ptr++ = seqno;
330d7eb6b47SHartmut Brandt 
331d7eb6b47SHartmut Brandt 	/* skip status */
332d7eb6b47SHartmut Brandt 	ptr += 2;
333d7eb6b47SHartmut Brandt 
334d7eb6b47SHartmut Brandt 	*ptr++ = associd >> 8;
335d7eb6b47SHartmut Brandt 	*ptr++ = associd;
336d7eb6b47SHartmut Brandt 
337d7eb6b47SHartmut Brandt 	/* skip offset */
338d7eb6b47SHartmut Brandt 	ptr += 2;
339d7eb6b47SHartmut Brandt 
340d7eb6b47SHartmut Brandt 	if (vars != NULL) {
341d7eb6b47SHartmut Brandt 		vlen = strlen(vars);
342d7eb6b47SHartmut Brandt 		if (vlen > NTPC_DMAX) {
343d7eb6b47SHartmut Brandt 			syslog(LOG_ERR, "NTP request too long (%zu)", vlen);
344d7eb6b47SHartmut Brandt 			free(rpkt);
345d7eb6b47SHartmut Brandt 			return (-1);
346d7eb6b47SHartmut Brandt 		}
347d7eb6b47SHartmut Brandt 		*ptr++ = vlen >> 8;
348d7eb6b47SHartmut Brandt 		*ptr++ = vlen;
349d7eb6b47SHartmut Brandt 
350d7eb6b47SHartmut Brandt 		memcpy(ptr, vars, vlen);
351d7eb6b47SHartmut Brandt 		ptr += vlen;
352d7eb6b47SHartmut Brandt 	} else
353d7eb6b47SHartmut Brandt 		/* skip data length (is already zero) */
354d7eb6b47SHartmut Brandt 		ptr += 2;
355d7eb6b47SHartmut Brandt 
356d7eb6b47SHartmut Brandt 	while ((ptr - rpkt) % 4 != 0)
357d7eb6b47SHartmut Brandt 		*ptr++ = 0;
358d7eb6b47SHartmut Brandt 
359d7eb6b47SHartmut Brandt 	if (ntp_debug & DBG_DUMP_PKTS) {
360d7eb6b47SHartmut Brandt 		syslog(LOG_INFO, "sending %zd bytes", ptr - rpkt);
361d7eb6b47SHartmut Brandt 		dump_packet(rpkt, ptr - rpkt);
362d7eb6b47SHartmut Brandt 	}
363d7eb6b47SHartmut Brandt 
364d7eb6b47SHartmut Brandt 	ret = send(ntpd_sock, rpkt, ptr - rpkt, 0);
365d7eb6b47SHartmut Brandt 	if (ret == -1) {
366d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "cannot send to ntpd: %m");
367d7eb6b47SHartmut Brandt 		free(rpkt);
368d7eb6b47SHartmut Brandt 		return (-1);
369d7eb6b47SHartmut Brandt 	}
370165c5d31SHartmut Brandt 	return (0);
371d7eb6b47SHartmut Brandt }
372d7eb6b47SHartmut Brandt 
373d7eb6b47SHartmut Brandt /*
374d7eb6b47SHartmut Brandt  * Callback if packet arrived from NTPD
375d7eb6b47SHartmut Brandt  */
376d7eb6b47SHartmut Brandt static int
ntpd_read(uint16_t * op,uint16_t * associd,u_char ** data,size_t * datalen)377d7eb6b47SHartmut Brandt ntpd_read(uint16_t *op, uint16_t *associd, u_char **data, size_t *datalen)
378d7eb6b47SHartmut Brandt {
379d7eb6b47SHartmut Brandt 	u_char	pkt[NTPC_MAX + 1];
380d7eb6b47SHartmut Brandt 	u_char	*ptr, *nptr;
381d7eb6b47SHartmut Brandt 	u_int	n;
382d7eb6b47SHartmut Brandt 	ssize_t	ret;
383d7eb6b47SHartmut Brandt 	size_t	z;
384d7eb6b47SHartmut Brandt 	u_int	offset;		/* current offset */
385d7eb6b47SHartmut Brandt 	int	more;		/* more flag */
386d7eb6b47SHartmut Brandt 	int	sel;
387d7eb6b47SHartmut Brandt 	struct timeval inc, end, rem;
388d7eb6b47SHartmut Brandt 	fd_set	iset;
389d7eb6b47SHartmut Brandt 
390d7eb6b47SHartmut Brandt 	*datalen = 0;
391d7eb6b47SHartmut Brandt 	*data = NULL;
392d7eb6b47SHartmut Brandt 	offset = 0;
393d7eb6b47SHartmut Brandt 
394d7eb6b47SHartmut Brandt 	inc.tv_sec = ntp_timeout / 100;
395d7eb6b47SHartmut Brandt 	inc.tv_usec = (ntp_timeout % 100) * 1000;
396d7eb6b47SHartmut Brandt 
397d7eb6b47SHartmut Brandt 	(void)gettimeofday(&end, NULL);
398d7eb6b47SHartmut Brandt 	timeradd(&end, &inc, &end);
399d7eb6b47SHartmut Brandt 
400d7eb6b47SHartmut Brandt   next:
401d7eb6b47SHartmut Brandt 	/* compute remaining time */
402d7eb6b47SHartmut Brandt 	(void)gettimeofday(&rem, NULL);
403d7eb6b47SHartmut Brandt 	if (timercmp(&rem, &end, >=)) {
404d7eb6b47SHartmut Brandt 		/* do a poll */
405d7eb6b47SHartmut Brandt 		rem.tv_sec = 0;
406d7eb6b47SHartmut Brandt 		rem.tv_usec = 0;
407d7eb6b47SHartmut Brandt 	} else {
408d7eb6b47SHartmut Brandt 		timersub(&end, &rem, &rem);
409d7eb6b47SHartmut Brandt 	}
410d7eb6b47SHartmut Brandt 
411d7eb6b47SHartmut Brandt 	/* select */
412d7eb6b47SHartmut Brandt 	FD_ZERO(&iset);
413d7eb6b47SHartmut Brandt 	FD_SET(ntpd_sock, &iset);
414d7eb6b47SHartmut Brandt 	sel = select(ntpd_sock + 1, &iset, NULL, NULL, &rem);
415d7eb6b47SHartmut Brandt 	if (sel == -1) {
416d7eb6b47SHartmut Brandt 		if (errno == EINTR)
417d7eb6b47SHartmut Brandt 			goto next;
418d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "select ntpd_sock: %m");
419d7eb6b47SHartmut Brandt 		free(*data);
420d7eb6b47SHartmut Brandt 		return (-1);
421d7eb6b47SHartmut Brandt 	}
422d7eb6b47SHartmut Brandt 	if (sel == 0) {
423d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "timeout on NTP connection");
424d7eb6b47SHartmut Brandt 		free(*data);
425d7eb6b47SHartmut Brandt 		return (-1);
426d7eb6b47SHartmut Brandt 	}
427d7eb6b47SHartmut Brandt 
428d7eb6b47SHartmut Brandt 	/* now read it */
429d7eb6b47SHartmut Brandt 	ret = recv(ntpd_sock, pkt, sizeof(pkt), 0);
430d7eb6b47SHartmut Brandt 	if (ret == -1) {
431d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "error reading from ntpd: %m");
432d7eb6b47SHartmut Brandt 		free(*data);
433d7eb6b47SHartmut Brandt 		return (-1);
434d7eb6b47SHartmut Brandt 	}
435d7eb6b47SHartmut Brandt 
436d7eb6b47SHartmut Brandt 	if (ntp_debug & DBG_DUMP_PKTS) {
437d7eb6b47SHartmut Brandt 		syslog(LOG_INFO, "got %zd bytes", ret);
438d7eb6b47SHartmut Brandt 		dump_packet(pkt, (size_t)ret);
439d7eb6b47SHartmut Brandt 	}
440d7eb6b47SHartmut Brandt 
441d7eb6b47SHartmut Brandt 	ptr = pkt;
442165c5d31SHartmut Brandt 	if ((*ptr & 0x3f) != ((NTPC_VERSION << 3) | NTPC_MODE)) {
443d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "unexpected packet version 0x%x", *ptr);
444d7eb6b47SHartmut Brandt 		free(*data);
445d7eb6b47SHartmut Brandt 		return (-1);
446d7eb6b47SHartmut Brandt 	}
447d7eb6b47SHartmut Brandt 	ptr++;
448d7eb6b47SHartmut Brandt 
449d7eb6b47SHartmut Brandt 	if (!(*ptr & NTPC_BIT_RESP)) {
450d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "not a response packet");
451d7eb6b47SHartmut Brandt 		return (-1);
452d7eb6b47SHartmut Brandt 	}
453d7eb6b47SHartmut Brandt 	if (*ptr & NTPC_BIT_ERROR) {
454d7eb6b47SHartmut Brandt 		z = *datalen - 12;
455d7eb6b47SHartmut Brandt 		if (z > NTPC_DMAX)
456d7eb6b47SHartmut Brandt 			z = NTPC_DMAX;
457d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "error response: %.*s", (int)z, pkt + 12);
458d7eb6b47SHartmut Brandt 		free(*data);
459d7eb6b47SHartmut Brandt 		return (-1);
460d7eb6b47SHartmut Brandt 	}
461d7eb6b47SHartmut Brandt 	more = (*ptr & NTPC_BIT_MORE);
462d7eb6b47SHartmut Brandt 
463d7eb6b47SHartmut Brandt 	*op = *ptr++ & NTPC_OPMASK;
464d7eb6b47SHartmut Brandt 
465d7eb6b47SHartmut Brandt 	/* seqno */
466d7eb6b47SHartmut Brandt 	n = *ptr++ << 8;
467d7eb6b47SHartmut Brandt 	n |= *ptr++;
468d7eb6b47SHartmut Brandt 
469d7eb6b47SHartmut Brandt 	if (n != seqno) {
470d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "expecting seqno %u, got %u", seqno, n);
471d7eb6b47SHartmut Brandt 		free(*data);
472d7eb6b47SHartmut Brandt 		return (-1);
473d7eb6b47SHartmut Brandt 	}
474d7eb6b47SHartmut Brandt 
475d7eb6b47SHartmut Brandt 	/* status */
476d7eb6b47SHartmut Brandt 	n = *ptr++ << 8;
477d7eb6b47SHartmut Brandt 	n |= *ptr++;
478d7eb6b47SHartmut Brandt 
479d7eb6b47SHartmut Brandt 	/* associd */
480d7eb6b47SHartmut Brandt 	*associd = *ptr++ << 8;
481d7eb6b47SHartmut Brandt 	*associd |= *ptr++;
482d7eb6b47SHartmut Brandt 
483d7eb6b47SHartmut Brandt 	/* offset */
484d7eb6b47SHartmut Brandt 	n = *ptr++ << 8;
485d7eb6b47SHartmut Brandt 	n |= *ptr++;
486d7eb6b47SHartmut Brandt 
487d7eb6b47SHartmut Brandt 	if (n != offset) {
488d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "offset: expecting %u, got %u", offset, n);
489d7eb6b47SHartmut Brandt 		free(*data);
490d7eb6b47SHartmut Brandt 		return (-1);
491d7eb6b47SHartmut Brandt 	}
492d7eb6b47SHartmut Brandt 
493d7eb6b47SHartmut Brandt 	/* count */
494d7eb6b47SHartmut Brandt 	n = *ptr++ << 8;
495d7eb6b47SHartmut Brandt 	n |= *ptr++;
496d7eb6b47SHartmut Brandt 
497d7eb6b47SHartmut Brandt 	if ((size_t)ret < 12 + n) {
498d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "packet too short");
499d7eb6b47SHartmut Brandt 		return (-1);
500d7eb6b47SHartmut Brandt 	}
501d7eb6b47SHartmut Brandt 
502d7eb6b47SHartmut Brandt 	nptr = realloc(*data, *datalen + n);
503d7eb6b47SHartmut Brandt 	if (nptr == NULL) {
504d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "cannot allocate memory: %m");
505d7eb6b47SHartmut Brandt 		free(*data);
506d7eb6b47SHartmut Brandt 		return (-1);
507d7eb6b47SHartmut Brandt 	}
508d7eb6b47SHartmut Brandt 	*data = nptr;
509d7eb6b47SHartmut Brandt 
510d7eb6b47SHartmut Brandt 	memcpy(*data + offset, ptr, n);
511d7eb6b47SHartmut Brandt 	*datalen += n;
512d7eb6b47SHartmut Brandt 
513d7eb6b47SHartmut Brandt 	if (!more)
514d7eb6b47SHartmut Brandt 		return (0);
515d7eb6b47SHartmut Brandt 
516d7eb6b47SHartmut Brandt 	offset += n;
517d7eb6b47SHartmut Brandt 	goto next;
518d7eb6b47SHartmut Brandt }
519d7eb6b47SHartmut Brandt 
520d7eb6b47SHartmut Brandt /*
521d7eb6b47SHartmut Brandt  * Send a request and wait for the response
522d7eb6b47SHartmut Brandt  */
523d7eb6b47SHartmut Brandt static int
ntpd_dialog(u_int op,u_int associd,const char * vars,u_char ** data,size_t * datalen)524d7eb6b47SHartmut Brandt ntpd_dialog(u_int op, u_int associd, const char *vars, u_char **data,
525d7eb6b47SHartmut Brandt     size_t *datalen)
526d7eb6b47SHartmut Brandt {
527d7eb6b47SHartmut Brandt 	uint16_t rassocid;
528d7eb6b47SHartmut Brandt 	uint16_t rop;
529d7eb6b47SHartmut Brandt 
530d7eb6b47SHartmut Brandt 	if (ntpd_request(op, associd, vars) == -1)
531d7eb6b47SHartmut Brandt 		return (-1);
532d7eb6b47SHartmut Brandt 	if (ntpd_read(&rop, &rassocid, data, datalen) == -1)
533d7eb6b47SHartmut Brandt 		return (-1);
534d7eb6b47SHartmut Brandt 
535d7eb6b47SHartmut Brandt 	if (rop != op) {
536d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "bad response op 0x%x", rop);
537d7eb6b47SHartmut Brandt 		free(data);
538d7eb6b47SHartmut Brandt 		return (-1);
539d7eb6b47SHartmut Brandt 	}
540d7eb6b47SHartmut Brandt 
541d7eb6b47SHartmut Brandt 	if (associd != rassocid) {
542d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "response for wrong associd");
543d7eb6b47SHartmut Brandt 		free(data);
544d7eb6b47SHartmut Brandt 		return (-1);
545d7eb6b47SHartmut Brandt 	}
546d7eb6b47SHartmut Brandt 	return (0);
547d7eb6b47SHartmut Brandt }
548d7eb6b47SHartmut Brandt 
549d7eb6b47SHartmut Brandt /*
550d7eb6b47SHartmut Brandt  * Callback if packet arrived from NTPD
551d7eb6b47SHartmut Brandt  */
552d7eb6b47SHartmut Brandt static void
ntpd_input(int fd __unused,void * arg __unused)553d7eb6b47SHartmut Brandt ntpd_input(int fd __unused, void *arg __unused)
554d7eb6b47SHartmut Brandt {
555d7eb6b47SHartmut Brandt 	uint16_t associd;
556d7eb6b47SHartmut Brandt 	uint16_t op;
557d7eb6b47SHartmut Brandt 	u_char	*data;
558d7eb6b47SHartmut Brandt 	size_t	datalen;
559d7eb6b47SHartmut Brandt 
560d7eb6b47SHartmut Brandt 	if (ntpd_read(&op, &associd, &data, &datalen) == -1)
561d7eb6b47SHartmut Brandt 		return;
562d7eb6b47SHartmut Brandt 
563d7eb6b47SHartmut Brandt 	free(data);
564d7eb6b47SHartmut Brandt }
565d7eb6b47SHartmut Brandt 
566d7eb6b47SHartmut Brandt /*
567d7eb6b47SHartmut Brandt  * Find the value of a variable
568d7eb6b47SHartmut Brandt  */
569d7eb6b47SHartmut Brandt static int
ntpd_parse(u_char ** data,size_t * datalen,char ** namep,char ** valp)570d7eb6b47SHartmut Brandt ntpd_parse(u_char **data, size_t *datalen, char **namep, char **valp)
571d7eb6b47SHartmut Brandt {
572d7eb6b47SHartmut Brandt 	u_char *ptr = *data;
573d7eb6b47SHartmut Brandt 	u_char *end = ptr + *datalen;
574d7eb6b47SHartmut Brandt 	char *ptr1;
575d7eb6b47SHartmut Brandt 	char endc;
576d7eb6b47SHartmut Brandt 
577d7eb6b47SHartmut Brandt 	/* skip leading spaces */
578d7eb6b47SHartmut Brandt 	while (ptr < end && isspace((int)*ptr))
579d7eb6b47SHartmut Brandt 		ptr++;
580d7eb6b47SHartmut Brandt 
581d7eb6b47SHartmut Brandt 	if (ptr == end)
582d7eb6b47SHartmut Brandt 		return (0);
583d7eb6b47SHartmut Brandt 
584d7eb6b47SHartmut Brandt 	*namep = ptr;
585d7eb6b47SHartmut Brandt 
586d7eb6b47SHartmut Brandt 	/* skip to space or '=' or ','*/
587d7eb6b47SHartmut Brandt 	while (ptr < end && !isspace((int)*ptr) && *ptr != '=' && *ptr != ',')
588d7eb6b47SHartmut Brandt 		ptr++;
589d7eb6b47SHartmut Brandt 	endc = *ptr;
590d7eb6b47SHartmut Brandt 	*ptr++ = '\0';
591d7eb6b47SHartmut Brandt 
592d7eb6b47SHartmut Brandt 	/* skip space */
593d7eb6b47SHartmut Brandt 	while (ptr < end && isspace((int)*ptr))
594d7eb6b47SHartmut Brandt 		ptr++;
595d7eb6b47SHartmut Brandt 
596d7eb6b47SHartmut Brandt 	if (ptr == end || endc == ',') {
597d7eb6b47SHartmut Brandt 		/* no value */
598d7eb6b47SHartmut Brandt 		*valp = NULL;
599d7eb6b47SHartmut Brandt 		*datalen -= ptr - *data;
600d7eb6b47SHartmut Brandt 		*data = ptr;
601d7eb6b47SHartmut Brandt 		return (1);
602d7eb6b47SHartmut Brandt 	}
603d7eb6b47SHartmut Brandt 
604d7eb6b47SHartmut Brandt 	if (*ptr == '"') {
605d7eb6b47SHartmut Brandt 		/* quoted */
606d7eb6b47SHartmut Brandt 		ptr++;
607d7eb6b47SHartmut Brandt 		*valp = ptr;
608d7eb6b47SHartmut Brandt 		while (ptr < end && *ptr != '"')
609d7eb6b47SHartmut Brandt 			ptr++;
610d7eb6b47SHartmut Brandt 		if (ptr == end)
611d7eb6b47SHartmut Brandt 			return (0);
612d7eb6b47SHartmut Brandt 
613d7eb6b47SHartmut Brandt 		*ptr++ = '\0';
614d7eb6b47SHartmut Brandt 
615d7eb6b47SHartmut Brandt 		/* find comma */
616d7eb6b47SHartmut Brandt 		while (ptr < end && isspace((int)*ptr) && *ptr == ',')
617d7eb6b47SHartmut Brandt 			ptr++;
618d7eb6b47SHartmut Brandt 	} else {
619d7eb6b47SHartmut Brandt 		*valp = ptr;
620d7eb6b47SHartmut Brandt 
621d7eb6b47SHartmut Brandt 		/* skip to end of value */
622d7eb6b47SHartmut Brandt 		while (ptr < end && *ptr != ',')
623d7eb6b47SHartmut Brandt 			ptr++;
624d7eb6b47SHartmut Brandt 
625d7eb6b47SHartmut Brandt 		/* remove trailing blanks */
626d7eb6b47SHartmut Brandt 		for (ptr1 = ptr; ptr1 > *valp; ptr1--)
627d7eb6b47SHartmut Brandt 			if (!isspace((int)ptr1[-1]))
628d7eb6b47SHartmut Brandt 				break;
629d7eb6b47SHartmut Brandt 		*ptr1 = '\0';
630d7eb6b47SHartmut Brandt 
631d7eb6b47SHartmut Brandt 		if (ptr < end)
632d7eb6b47SHartmut Brandt 			ptr++;
633d7eb6b47SHartmut Brandt 	}
634d7eb6b47SHartmut Brandt 
635d7eb6b47SHartmut Brandt 	*datalen -= ptr - *data;
636d7eb6b47SHartmut Brandt 	*data = ptr;
637d7eb6b47SHartmut Brandt 
638d7eb6b47SHartmut Brandt 	return (1);
639d7eb6b47SHartmut Brandt }
640d7eb6b47SHartmut Brandt 
641d7eb6b47SHartmut Brandt /*
642d7eb6b47SHartmut Brandt  * Parse an int32 value
643d7eb6b47SHartmut Brandt  */
644d7eb6b47SHartmut Brandt static int
val_parse_int32(const char * val,int32_t * p,int32_t min,int32_t max,int base)645d7eb6b47SHartmut Brandt val_parse_int32(const char *val, int32_t *p, int32_t min, int32_t max, int base)
646d7eb6b47SHartmut Brandt {
647d7eb6b47SHartmut Brandt 	long n;
648d7eb6b47SHartmut Brandt 	char *end;
649d7eb6b47SHartmut Brandt 
650d7eb6b47SHartmut Brandt 	errno = 0;
651d7eb6b47SHartmut Brandt 	n = strtol(val, &end, base);
652d7eb6b47SHartmut Brandt 	if (errno != 0 || *end != '\0')
653d7eb6b47SHartmut Brandt 		return (0);
654d7eb6b47SHartmut Brandt 	if (n < min || n > max)
655d7eb6b47SHartmut Brandt 		return (0);
656d7eb6b47SHartmut Brandt 	*p = (int32_t)n;
657d7eb6b47SHartmut Brandt 	return (1);
658d7eb6b47SHartmut Brandt }
659d7eb6b47SHartmut Brandt 
660d7eb6b47SHartmut Brandt /*
661d7eb6b47SHartmut Brandt  * Parse an uint32 value
662d7eb6b47SHartmut Brandt  */
663d7eb6b47SHartmut Brandt static int
val_parse_uint32(const char * val,uint32_t * p,uint32_t min,uint32_t max,int base)664d7eb6b47SHartmut Brandt val_parse_uint32(const char *val, uint32_t *p, uint32_t min, uint32_t max,
665d7eb6b47SHartmut Brandt     int base)
666d7eb6b47SHartmut Brandt {
667d7eb6b47SHartmut Brandt 	u_long n;
668d7eb6b47SHartmut Brandt 	char *end;
669d7eb6b47SHartmut Brandt 
670d7eb6b47SHartmut Brandt 	errno = 0;
671d7eb6b47SHartmut Brandt 	n = strtoul(val, &end, base);
672d7eb6b47SHartmut Brandt 	if (errno != 0 || *end != '\0')
673d7eb6b47SHartmut Brandt 		return (0);
674d7eb6b47SHartmut Brandt 	if (n < min || n > max)
675d7eb6b47SHartmut Brandt 		return (0);
676d7eb6b47SHartmut Brandt 	*p = (uint32_t)n;
677d7eb6b47SHartmut Brandt 	return (1);
678d7eb6b47SHartmut Brandt }
679d7eb6b47SHartmut Brandt 
680d7eb6b47SHartmut Brandt /*
681d7eb6b47SHartmut Brandt  * Parse a double
682d7eb6b47SHartmut Brandt  */
683d7eb6b47SHartmut Brandt static int
val_parse_double(const char * val,double * p)684d7eb6b47SHartmut Brandt val_parse_double(const char *val, double *p)
685d7eb6b47SHartmut Brandt {
686d7eb6b47SHartmut Brandt 	char *end;
687d7eb6b47SHartmut Brandt 
688d7eb6b47SHartmut Brandt 	errno = 0;
689d7eb6b47SHartmut Brandt 	*p = strtod(val, &end);
690d7eb6b47SHartmut Brandt 	if (errno != 0 || *end != '\0')
691d7eb6b47SHartmut Brandt 		return (0);
692d7eb6b47SHartmut Brandt 	return (1);
693d7eb6b47SHartmut Brandt }
694d7eb6b47SHartmut Brandt 
695d7eb6b47SHartmut Brandt static int
val_parse_ts(const char * val,char * buf)696d7eb6b47SHartmut Brandt val_parse_ts(const char *val, char *buf)
697d7eb6b47SHartmut Brandt {
698d7eb6b47SHartmut Brandt 	int r, n;
699d7eb6b47SHartmut Brandt 	u_int i, f;
700d7eb6b47SHartmut Brandt 
701d7eb6b47SHartmut Brandt 	if (strlen(val) > 2 && val[0] == '0' && val[1] == 'x') {
702d7eb6b47SHartmut Brandt 		/* hex format */
703d7eb6b47SHartmut Brandt 		r = sscanf(val + 2, "%x.%x%n", &i, &f, &n);
704d7eb6b47SHartmut Brandt 		if (r != 2 || (size_t)n != strlen(val + 2))
705d7eb6b47SHartmut Brandt 			return (0);
706d7eb6b47SHartmut Brandt 	} else {
707d7eb6b47SHartmut Brandt 		/* probably decimal */
708d7eb6b47SHartmut Brandt 		r = sscanf(val, "%d.%d%n", &i, &f, &n);
709d7eb6b47SHartmut Brandt 		if (r != 2 || (size_t)n != strlen(val))
710d7eb6b47SHartmut Brandt 			return (0);
711d7eb6b47SHartmut Brandt 	}
712d7eb6b47SHartmut Brandt 	buf[0] = i >> 24;
713d7eb6b47SHartmut Brandt 	buf[1] = i >> 16;
714d7eb6b47SHartmut Brandt 	buf[2] = i >>  8;
715d7eb6b47SHartmut Brandt 	buf[3] = i >>  0;
716d7eb6b47SHartmut Brandt 	buf[4] = f >> 24;
717d7eb6b47SHartmut Brandt 	buf[5] = f >> 16;
718d7eb6b47SHartmut Brandt 	buf[6] = f >>  8;
719d7eb6b47SHartmut Brandt 	buf[7] = f >>  0;
720d7eb6b47SHartmut Brandt 	return (1);
721d7eb6b47SHartmut Brandt }
722d7eb6b47SHartmut Brandt 
723d7eb6b47SHartmut Brandt /*
724d7eb6b47SHartmut Brandt  * Parse an IP address. This resolves non-numeric names.
725d7eb6b47SHartmut Brandt  */
726d7eb6b47SHartmut Brandt static int
val_parse_ip(const char * val,u_char ip[4])727d7eb6b47SHartmut Brandt val_parse_ip(const char *val, u_char ip[4])
728d7eb6b47SHartmut Brandt {
729d7eb6b47SHartmut Brandt 	int r, n, error;
730d7eb6b47SHartmut Brandt 	struct addrinfo hints, *res0;
731165c5d31SHartmut Brandt 	struct sockaddr_in *sin_local;
732d7eb6b47SHartmut Brandt 
733d7eb6b47SHartmut Brandt 	r = sscanf(val, "%hhd.%hhd.%hhd.%hhd%n",
734d7eb6b47SHartmut Brandt 	    &ip[0], &ip[1], &ip[2], &ip[3], &n);
735d7eb6b47SHartmut Brandt 	if (n == 4 && (size_t)n == strlen(val))
736d7eb6b47SHartmut Brandt 		return (0);
737d7eb6b47SHartmut Brandt 
738d7eb6b47SHartmut Brandt 	memset(ip, 0, 4);
739d7eb6b47SHartmut Brandt 
740d7eb6b47SHartmut Brandt 	memset(&hints, 0, sizeof(hints));
741d7eb6b47SHartmut Brandt 	hints.ai_family = AF_INET;
742d7eb6b47SHartmut Brandt 	hints.ai_socktype = SOCK_DGRAM;
743d7eb6b47SHartmut Brandt 
744d7eb6b47SHartmut Brandt 	error = getaddrinfo(val, NULL, &hints, &res0);
745d7eb6b47SHartmut Brandt 	if (error) {
746d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "%s: %s", val, gai_strerror(error));
747d7eb6b47SHartmut Brandt 		return (-1);
748d7eb6b47SHartmut Brandt 	}
749d7eb6b47SHartmut Brandt 	if (res0 == NULL) {
750d7eb6b47SHartmut Brandt 		syslog(LOG_ERR, "%s: no address", val);
751d7eb6b47SHartmut Brandt 		return (-1);
752d7eb6b47SHartmut Brandt 	}
753d7eb6b47SHartmut Brandt 
754165c5d31SHartmut Brandt 	sin_local = (struct sockaddr_in *)(void *)res0->ai_addr;
755165c5d31SHartmut Brandt 	ip[3] = sin_local->sin_addr.s_addr >> 24;
756165c5d31SHartmut Brandt 	ip[2] = sin_local->sin_addr.s_addr >> 16;
757165c5d31SHartmut Brandt 	ip[1] = sin_local->sin_addr.s_addr >>  8;
758165c5d31SHartmut Brandt 	ip[0] = sin_local->sin_addr.s_addr >>  0;
759d7eb6b47SHartmut Brandt 
760d7eb6b47SHartmut Brandt 	freeaddrinfo(res0);
761d7eb6b47SHartmut Brandt 	return (0);
762d7eb6b47SHartmut Brandt }
763d7eb6b47SHartmut Brandt 
764d7eb6b47SHartmut Brandt /*
765d7eb6b47SHartmut Brandt  * Fetch system info
766d7eb6b47SHartmut Brandt  */
767d7eb6b47SHartmut Brandt static int
fetch_sysinfo(void)768d7eb6b47SHartmut Brandt fetch_sysinfo(void)
769d7eb6b47SHartmut Brandt {
770d7eb6b47SHartmut Brandt 	u_char *data;
771d7eb6b47SHartmut Brandt 	u_char *ptr;
772d7eb6b47SHartmut Brandt 	size_t datalen;
773d7eb6b47SHartmut Brandt 	char *name;
774d7eb6b47SHartmut Brandt 	char *val;
775d7eb6b47SHartmut Brandt 
776d7eb6b47SHartmut Brandt 	if (ntpd_dialog(NTPC_OP_READVAR, 0,
777d7eb6b47SHartmut Brandt 	    "leap,stratum,precision,rootdelay,rootdispersion,refid,reftime,"
778d7eb6b47SHartmut Brandt 	    "poll,peer,clock,system,processor,jitter,stability",
779d7eb6b47SHartmut Brandt 	    &data, &datalen))
780d7eb6b47SHartmut Brandt 		return (-1);
781d7eb6b47SHartmut Brandt 
782d7eb6b47SHartmut Brandt 	/* clear info */
783d7eb6b47SHartmut Brandt 	sysb_leap = 0;
784d7eb6b47SHartmut Brandt 	sysb_stratum = 0;
785d7eb6b47SHartmut Brandt 	sysb_precision = 0;
786d7eb6b47SHartmut Brandt 	free(sys_rootdelay);
787d7eb6b47SHartmut Brandt 	sys_rootdelay = NULL;
788d7eb6b47SHartmut Brandt 	free(sys_rootdispersion);
789d7eb6b47SHartmut Brandt 	sys_rootdispersion = NULL;
790d7eb6b47SHartmut Brandt 	free(sys_refid);
791d7eb6b47SHartmut Brandt 	sys_refid = NULL;
792d7eb6b47SHartmut Brandt 	sysb_reftime = 0;
793d7eb6b47SHartmut Brandt 	sysb_poll = 0;
794d7eb6b47SHartmut Brandt 	sysb_peer = 0;
795d7eb6b47SHartmut Brandt 	sysb_clock = 0;
796d7eb6b47SHartmut Brandt 	free(sys_system);
797d7eb6b47SHartmut Brandt 	sys_system = NULL;
798d7eb6b47SHartmut Brandt 	free(sys_processor);
799d7eb6b47SHartmut Brandt 	sys_processor = NULL;
800d7eb6b47SHartmut Brandt 	sysb_jitter = 0;
801d7eb6b47SHartmut Brandt 	sysb_stability = 0;
802d7eb6b47SHartmut Brandt 
803d7eb6b47SHartmut Brandt 	ptr = data;
804d7eb6b47SHartmut Brandt 	while (ntpd_parse(&ptr, &datalen, &name, &val)) {
805d7eb6b47SHartmut Brandt 		if (ntp_debug & DBG_DUMP_VARS)
806d7eb6b47SHartmut Brandt 			syslog(LOG_DEBUG, "%s: '%s'='%s'", __func__, name, val);
807d7eb6b47SHartmut Brandt 		if (strcmp(name, "leap") == 0 ||
808d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.leap") == 0) {
809d7eb6b47SHartmut Brandt 			sysb_leap = val_parse_int32(val, &sys_leap,
810d7eb6b47SHartmut Brandt 			    0, 3, 2);
811d7eb6b47SHartmut Brandt 
812d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "stratum") == 0 ||
813d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.stratum") == 0) {
814d7eb6b47SHartmut Brandt 			sysb_stratum = val_parse_int32(val, &sys_stratum,
815d7eb6b47SHartmut Brandt 			    0, 255, 0);
816d7eb6b47SHartmut Brandt 
817d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "precision") == 0 ||
818d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.precision") == 0) {
819d7eb6b47SHartmut Brandt 			sysb_precision = val_parse_int32(val, &sys_precision,
820d7eb6b47SHartmut Brandt 			    INT32_MIN, INT32_MAX, 0);
821d7eb6b47SHartmut Brandt 
822d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "rootdelay") == 0 ||
823d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.rootdelay") == 0) {
824d7eb6b47SHartmut Brandt 			sys_rootdelay = strdup(val);
825d7eb6b47SHartmut Brandt 
826d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "rootdispersion") == 0 ||
827d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.rootdispersion") == 0) {
828d7eb6b47SHartmut Brandt 			sys_rootdispersion = strdup(val);
829d7eb6b47SHartmut Brandt 
830d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "refid") == 0 ||
831d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.refid") == 0) {
832d7eb6b47SHartmut Brandt 			sys_refid = strdup(val);
833d7eb6b47SHartmut Brandt 
834d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "reftime") == 0 ||
835d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.reftime") == 0) {
836d7eb6b47SHartmut Brandt 			sysb_reftime = val_parse_ts(val, sys_reftime);
837d7eb6b47SHartmut Brandt 
838d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "poll") == 0 ||
839d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.poll") == 0) {
840d7eb6b47SHartmut Brandt 			sysb_poll = val_parse_int32(val, &sys_poll,
841d7eb6b47SHartmut Brandt 			    INT32_MIN, INT32_MAX, 0);
842d7eb6b47SHartmut Brandt 
843d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "peer") == 0 ||
844d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.peer") == 0) {
845d7eb6b47SHartmut Brandt 			sysb_peer = val_parse_uint32(val, &sys_peer,
846d7eb6b47SHartmut Brandt 			    0, UINT32_MAX, 0);
847d7eb6b47SHartmut Brandt 
848d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "clock") == 0 ||
849d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.clock") == 0) {
850d7eb6b47SHartmut Brandt 			sysb_clock = val_parse_ts(val, sys_clock);
851d7eb6b47SHartmut Brandt 
852d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "system") == 0 ||
853d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.system") == 0) {
854d7eb6b47SHartmut Brandt 			sys_system = strdup(val);
855d7eb6b47SHartmut Brandt 
856d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "processor") == 0 ||
857d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.processor") == 0) {
858d7eb6b47SHartmut Brandt 			sys_processor = strdup(val);
859d7eb6b47SHartmut Brandt 
860d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "jitter") == 0 ||
861d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.jitter") == 0) {
862d7eb6b47SHartmut Brandt 			sysb_jitter = val_parse_double(val, &sys_jitter);
863d7eb6b47SHartmut Brandt 
864d7eb6b47SHartmut Brandt 		} else if (strcmp(name, "stability") == 0 ||
865d7eb6b47SHartmut Brandt 		    strcmp(name, "sys.stability") == 0) {
866d7eb6b47SHartmut Brandt 			sysb_stability = val_parse_double(val, &sys_stability);
867d7eb6b47SHartmut Brandt 		}
868d7eb6b47SHartmut Brandt 	}
869d7eb6b47SHartmut Brandt 
870d7eb6b47SHartmut Brandt 	free(data);
871d7eb6b47SHartmut Brandt 	return (0);
872d7eb6b47SHartmut Brandt }
873d7eb6b47SHartmut Brandt 
874d7eb6b47SHartmut Brandt static int
parse_filt(char * val,uint16_t associd,int which)875d7eb6b47SHartmut Brandt parse_filt(char *val, uint16_t associd, int which)
876d7eb6b47SHartmut Brandt {
877d7eb6b47SHartmut Brandt 	char *w;
878d7eb6b47SHartmut Brandt 	int cnt;
879d7eb6b47SHartmut Brandt 	struct filt *f;
880d7eb6b47SHartmut Brandt 
881d7eb6b47SHartmut Brandt 	cnt = 0;
882d7eb6b47SHartmut Brandt 	for (w = strtok(val, " \t"); w != NULL; w = strtok(NULL, " \t")) {
883d7eb6b47SHartmut Brandt 		TAILQ_FOREACH(f, &filts, link)
884d7eb6b47SHartmut Brandt 			if (f->index.subs[0] == associd &&
885d7eb6b47SHartmut Brandt 			    f->index.subs[1] == (asn_subid_t)(cnt + 1))
886d7eb6b47SHartmut Brandt 				break;
887d7eb6b47SHartmut Brandt 		if (f == NULL) {
888d7eb6b47SHartmut Brandt 			f = malloc(sizeof(*f));
889d7eb6b47SHartmut Brandt 			memset(f, 0, sizeof(*f));
890d7eb6b47SHartmut Brandt 			f->index.len = 2;
891d7eb6b47SHartmut Brandt 			f->index.subs[0] = associd;
892d7eb6b47SHartmut Brandt 			f->index.subs[1] = cnt + 1;
893d7eb6b47SHartmut Brandt 
894d7eb6b47SHartmut Brandt 			INSERT_OBJECT_OID(f, &filts);
895d7eb6b47SHartmut Brandt 		}
896d7eb6b47SHartmut Brandt 
897d7eb6b47SHartmut Brandt 		switch (which) {
898d7eb6b47SHartmut Brandt 
899d7eb6b47SHartmut Brandt 		  case 0:
900d7eb6b47SHartmut Brandt 			f->offset = strdup(w);
901d7eb6b47SHartmut Brandt 			break;
902d7eb6b47SHartmut Brandt 
903d7eb6b47SHartmut Brandt 		  case 1:
904d7eb6b47SHartmut Brandt 			f->delay = strdup(w);
905d7eb6b47SHartmut Brandt 			break;
906d7eb6b47SHartmut Brandt 
907d7eb6b47SHartmut Brandt 		  case 2:
908d7eb6b47SHartmut Brandt 			f->dispersion = strdup(w);
909d7eb6b47SHartmut Brandt 			break;
910d7eb6b47SHartmut Brandt 
911d7eb6b47SHartmut Brandt 		  default:
912d7eb6b47SHartmut Brandt 			abort();
913d7eb6b47SHartmut Brandt 		}
914d7eb6b47SHartmut Brandt 		cnt++;
915d7eb6b47SHartmut Brandt 	}
916d7eb6b47SHartmut Brandt 	return (cnt);
917d7eb6b47SHartmut Brandt }
918d7eb6b47SHartmut Brandt 
919d7eb6b47SHartmut Brandt /*
920d7eb6b47SHartmut Brandt  * Fetch the complete peer list
921d7eb6b47SHartmut Brandt  */
922d7eb6b47SHartmut Brandt static int
fetch_peers(void)923d7eb6b47SHartmut Brandt fetch_peers(void)
924d7eb6b47SHartmut Brandt {
925d7eb6b47SHartmut Brandt 	u_char *data, *pdata, *ptr;
926d7eb6b47SHartmut Brandt 	size_t datalen, pdatalen;
927d7eb6b47SHartmut Brandt 	int i;
928d7eb6b47SHartmut Brandt 	struct peer *p;
929d7eb6b47SHartmut Brandt 	struct filt *f;
930d7eb6b47SHartmut Brandt 	uint16_t associd;
931d7eb6b47SHartmut Brandt 	char *name, *val;
932d7eb6b47SHartmut Brandt 
933d7eb6b47SHartmut Brandt 	/* free the old list */
934d7eb6b47SHartmut Brandt 	while ((p = TAILQ_FIRST(&peers)) != NULL) {
935d7eb6b47SHartmut Brandt 		TAILQ_REMOVE(&peers, p, link);
936d7eb6b47SHartmut Brandt 		free(p->rootdelay);
937d7eb6b47SHartmut Brandt 		free(p->rootdispersion);
938d7eb6b47SHartmut Brandt 		free(p->refid);
939d7eb6b47SHartmut Brandt 		free(p->offset);
940d7eb6b47SHartmut Brandt 		free(p->delay);
941d7eb6b47SHartmut Brandt 		free(p->dispersion);
942d7eb6b47SHartmut Brandt 		free(p);
943d7eb6b47SHartmut Brandt 	}
944d7eb6b47SHartmut Brandt 	while ((f = TAILQ_FIRST(&filts)) != NULL) {
945d7eb6b47SHartmut Brandt 		TAILQ_REMOVE(&filts, f, link);
946d7eb6b47SHartmut Brandt 		free(f->offset);
947d7eb6b47SHartmut Brandt 		free(f->delay);
948d7eb6b47SHartmut Brandt 		free(f->dispersion);
949d7eb6b47SHartmut Brandt 		free(f);
950d7eb6b47SHartmut Brandt 	}
951d7eb6b47SHartmut Brandt 
952d7eb6b47SHartmut Brandt 	/* fetch the list of associations */
953d7eb6b47SHartmut Brandt 	if (ntpd_dialog(NTPC_OP_READSTAT, 0, NULL, &data, &datalen))
954d7eb6b47SHartmut Brandt 		return (-1);
955d7eb6b47SHartmut Brandt 
956d7eb6b47SHartmut Brandt 	for (i = 0; i < (int)(datalen / 4); i++) {
957d7eb6b47SHartmut Brandt 		associd  = data[4 * i + 0] << 8;
958d7eb6b47SHartmut Brandt 		associd |= data[4 * i + 1] << 0;
959d7eb6b47SHartmut Brandt 
960d7eb6b47SHartmut Brandt 		/* ask for the association variables */
961d7eb6b47SHartmut Brandt 		if (ntpd_dialog(NTPC_OP_READVAR, associd,
962d7eb6b47SHartmut Brandt 		    "config,srcadr,srcport,dstadr,dstport,leap,hmode,stratum,"
963d7eb6b47SHartmut Brandt 		    "hpoll,ppoll,precision,rootdelay,rootdispersion,refid,"
964d7eb6b47SHartmut Brandt 		    "reftime,org,rec,xmt,reach,timer,offset,delay,dispersion,"
965d7eb6b47SHartmut Brandt 		    "filtdelay,filtoffset,filtdisp",
966d7eb6b47SHartmut Brandt 		    &pdata, &pdatalen)) {
967d7eb6b47SHartmut Brandt 			free(data);
968d7eb6b47SHartmut Brandt 			return (-1);
969d7eb6b47SHartmut Brandt 		}
970d7eb6b47SHartmut Brandt 
971d7eb6b47SHartmut Brandt 		/* now save and parse the data */
972d7eb6b47SHartmut Brandt 		p = malloc(sizeof(*p));
973d7eb6b47SHartmut Brandt 		if (p == NULL) {
974d7eb6b47SHartmut Brandt 			free(data);
975d7eb6b47SHartmut Brandt 			syslog(LOG_ERR, "%m");
976d7eb6b47SHartmut Brandt 			return (-1);
977d7eb6b47SHartmut Brandt 		}
978d7eb6b47SHartmut Brandt 		memset(p, 0, sizeof(*p));
979d7eb6b47SHartmut Brandt 		p->index = associd;
980d7eb6b47SHartmut Brandt 		INSERT_OBJECT_INT(p, &peers);
981d7eb6b47SHartmut Brandt 
982d7eb6b47SHartmut Brandt 		ptr = pdata;
983d7eb6b47SHartmut Brandt 		while (ntpd_parse(&ptr, &pdatalen, &name, &val)) {
984d7eb6b47SHartmut Brandt 			if (ntp_debug & DBG_DUMP_VARS)
985d7eb6b47SHartmut Brandt 				syslog(LOG_DEBUG, "%s: '%s'='%s'",
986d7eb6b47SHartmut Brandt 				    __func__, name, val);
987d7eb6b47SHartmut Brandt 			if (strcmp(name, "config") == 0 ||
988d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.config") == 0) {
989d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->config, 0, 1, 0);
990d7eb6b47SHartmut Brandt 
991d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "srcadr") == 0 ||
992d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.srcadr") == 0) {
993d7eb6b47SHartmut Brandt 				val_parse_ip(val, p->srcadr);
994d7eb6b47SHartmut Brandt 
995d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "srcport") == 0 ||
996d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.srcport") == 0) {
997d7eb6b47SHartmut Brandt 				val_parse_uint32(val, &p->srcport,
998d7eb6b47SHartmut Brandt 				    1, 65535, 0);
999d7eb6b47SHartmut Brandt 
1000d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "dstadr") == 0 ||
1001d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.dstadr") == 0) {
1002d7eb6b47SHartmut Brandt 				val_parse_ip(val, p->dstadr);
1003d7eb6b47SHartmut Brandt 
1004d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "dstport") == 0 ||
1005d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.dstport") == 0) {
1006d7eb6b47SHartmut Brandt 				val_parse_uint32(val, &p->dstport,
1007d7eb6b47SHartmut Brandt 				    1, 65535, 0);
1008d7eb6b47SHartmut Brandt 
1009d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "leap") == 0 ||
1010d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.leap") == 0) {
1011d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->leap, 0, 3, 2);
1012d7eb6b47SHartmut Brandt 
1013d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "hmode") == 0 ||
1014d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.hmode") == 0) {
1015d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->hmode, 0, 7, 0);
1016d7eb6b47SHartmut Brandt 
1017d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "stratum") == 0 ||
1018d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.stratum") == 0) {
1019d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->stratum, 0, 255, 0);
1020d7eb6b47SHartmut Brandt 
1021d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "ppoll") == 0 ||
1022d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.ppoll") == 0) {
1023d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->ppoll,
1024d7eb6b47SHartmut Brandt 				    INT32_MIN, INT32_MAX, 0);
1025d7eb6b47SHartmut Brandt 
1026d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "hpoll") == 0 ||
1027d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.hpoll") == 0) {
1028d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->hpoll,
1029d7eb6b47SHartmut Brandt 				    INT32_MIN, INT32_MAX, 0);
1030d7eb6b47SHartmut Brandt 
1031d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "precision") == 0 ||
1032d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.precision") == 0) {
1033d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->hpoll,
1034d7eb6b47SHartmut Brandt 				    INT32_MIN, INT32_MAX, 0);
1035d7eb6b47SHartmut Brandt 
1036d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "rootdelay") == 0 ||
1037d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.rootdelay") == 0) {
1038d7eb6b47SHartmut Brandt 				p->rootdelay = strdup(val);
1039d7eb6b47SHartmut Brandt 
1040d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "rootdispersion") == 0 ||
1041d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.rootdispersion") == 0) {
1042d7eb6b47SHartmut Brandt 				p->rootdispersion = strdup(val);
1043d7eb6b47SHartmut Brandt 
1044d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "refid") == 0 ||
1045d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.refid") == 0) {
1046d7eb6b47SHartmut Brandt 				p->refid = strdup(val);
1047d7eb6b47SHartmut Brandt 
1048d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "reftime") == 0 ||
1049d7eb6b47SHartmut Brandt 			    strcmp(name, "sys.reftime") == 0) {
1050d7eb6b47SHartmut Brandt 				val_parse_ts(val, p->reftime);
1051d7eb6b47SHartmut Brandt 
1052d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "org") == 0 ||
1053d7eb6b47SHartmut Brandt 			    strcmp(name, "sys.org") == 0) {
1054d7eb6b47SHartmut Brandt 				val_parse_ts(val, p->orgtime);
1055d7eb6b47SHartmut Brandt 
1056d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "rec") == 0 ||
1057d7eb6b47SHartmut Brandt 			    strcmp(name, "sys.rec") == 0) {
1058d7eb6b47SHartmut Brandt 				val_parse_ts(val, p->rcvtime);
1059d7eb6b47SHartmut Brandt 
1060d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "xmt") == 0 ||
1061d7eb6b47SHartmut Brandt 			    strcmp(name, "sys.xmt") == 0) {
1062d7eb6b47SHartmut Brandt 				val_parse_ts(val, p->xmttime);
1063d7eb6b47SHartmut Brandt 
1064d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "reach") == 0 ||
1065d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.reach") == 0) {
1066d7eb6b47SHartmut Brandt 				val_parse_uint32(val, &p->reach,
1067d7eb6b47SHartmut Brandt 				    0, 65535, 0);
1068d7eb6b47SHartmut Brandt 
1069d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "timer") == 0 ||
1070d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.timer") == 0) {
1071d7eb6b47SHartmut Brandt 				val_parse_int32(val, &p->timer,
1072d7eb6b47SHartmut Brandt 				    INT32_MIN, INT32_MAX, 0);
1073d7eb6b47SHartmut Brandt 
1074d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "offset") == 0 ||
1075d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.offset") == 0) {
1076d7eb6b47SHartmut Brandt 				p->offset = strdup(val);
1077d7eb6b47SHartmut Brandt 
1078d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "delay") == 0 ||
1079d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.delay") == 0) {
1080d7eb6b47SHartmut Brandt 				p->delay = strdup(val);
1081d7eb6b47SHartmut Brandt 
1082d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "dispersion") == 0 ||
1083d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.dispersion") == 0) {
1084d7eb6b47SHartmut Brandt 				p->dispersion = strdup(val);
1085d7eb6b47SHartmut Brandt 
1086d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "filtdelay") == 0 ||
1087d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.filtdelay") == 0) {
1088d7eb6b47SHartmut Brandt 				p->filt_entries = parse_filt(val, associd, 0);
1089d7eb6b47SHartmut Brandt 
1090d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "filtoffset") == 0 ||
1091d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.filtoffset") == 0) {
1092d7eb6b47SHartmut Brandt 				p->filt_entries = parse_filt(val, associd, 1);
1093d7eb6b47SHartmut Brandt 
1094d7eb6b47SHartmut Brandt 			} else if (strcmp(name, "filtdisp") == 0 ||
1095d7eb6b47SHartmut Brandt 			    strcmp(name, "peer.filtdisp") == 0) {
1096d7eb6b47SHartmut Brandt 				p->filt_entries = parse_filt(val, associd, 2);
1097d7eb6b47SHartmut Brandt 			}
1098d7eb6b47SHartmut Brandt 		}
1099d7eb6b47SHartmut Brandt 		free(pdata);
1100d7eb6b47SHartmut Brandt 	}
1101d7eb6b47SHartmut Brandt 
1102d7eb6b47SHartmut Brandt 	free(data);
1103d7eb6b47SHartmut Brandt 	return (0);
1104d7eb6b47SHartmut Brandt }
1105d7eb6b47SHartmut Brandt 
1106d7eb6b47SHartmut Brandt /*
1107d7eb6b47SHartmut Brandt  * System variables - read-only scalars only.
1108d7eb6b47SHartmut Brandt  */
1109d7eb6b47SHartmut Brandt int
op_ntpSystem(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1110d7eb6b47SHartmut Brandt op_ntpSystem(struct snmp_context *ctx __unused, struct snmp_value *value,
1111d7eb6b47SHartmut Brandt     u_int sub, u_int iidx __unused, enum snmp_op op)
1112d7eb6b47SHartmut Brandt {
1113d7eb6b47SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1114d7eb6b47SHartmut Brandt 
1115d7eb6b47SHartmut Brandt 	switch (op) {
1116d7eb6b47SHartmut Brandt 
1117d7eb6b47SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1118d7eb6b47SHartmut Brandt 		abort();
1119d7eb6b47SHartmut Brandt 
1120d7eb6b47SHartmut Brandt 	  case SNMP_OP_GET:
1121d7eb6b47SHartmut Brandt 		if (this_tick > sysinfo_tick) {
1122d7eb6b47SHartmut Brandt 			if (fetch_sysinfo() == -1)
1123d7eb6b47SHartmut Brandt 				return (SNMP_ERR_GENERR);
1124d7eb6b47SHartmut Brandt 			sysinfo_tick = this_tick;
1125d7eb6b47SHartmut Brandt 		}
1126d7eb6b47SHartmut Brandt 
1127d7eb6b47SHartmut Brandt 		switch (which) {
1128d7eb6b47SHartmut Brandt 
1129d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysLeap:
1130d7eb6b47SHartmut Brandt 			if (!sysb_leap)
1131d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1132d7eb6b47SHartmut Brandt 			value->v.integer = sys_leap;
1133d7eb6b47SHartmut Brandt 			break;
1134d7eb6b47SHartmut Brandt 
1135d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysStratum:
1136d7eb6b47SHartmut Brandt 			if (!sysb_stratum)
1137d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1138d7eb6b47SHartmut Brandt 			value->v.integer = sys_stratum;
1139d7eb6b47SHartmut Brandt 			break;
1140d7eb6b47SHartmut Brandt 
1141d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysPrecision:
1142d7eb6b47SHartmut Brandt 			if (!sysb_precision)
1143d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1144d7eb6b47SHartmut Brandt 			value->v.integer = sys_precision;
1145d7eb6b47SHartmut Brandt 			break;
1146d7eb6b47SHartmut Brandt 
1147d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysRootDelay:
1148d7eb6b47SHartmut Brandt 			if (sys_rootdelay == NULL)
1149d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1150d7eb6b47SHartmut Brandt 			return (string_get(value, sys_rootdelay, -1));
1151d7eb6b47SHartmut Brandt 
1152d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysRootDispersion:
1153d7eb6b47SHartmut Brandt 			if (sys_rootdispersion == NULL)
1154d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1155d7eb6b47SHartmut Brandt 			return (string_get(value, sys_rootdispersion, -1));
1156d7eb6b47SHartmut Brandt 
1157d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysRefId:
1158d7eb6b47SHartmut Brandt 			if (sys_refid == NULL)
1159d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1160d7eb6b47SHartmut Brandt 			return (string_get(value, sys_refid, -1));
1161d7eb6b47SHartmut Brandt 
1162d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysRefTime:
1163d7eb6b47SHartmut Brandt 			if (sysb_reftime == 0)
1164d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1165d7eb6b47SHartmut Brandt 			return (string_get(value, sys_reftime, 8));
1166d7eb6b47SHartmut Brandt 
1167d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysPoll:
1168d7eb6b47SHartmut Brandt 			if (sysb_poll == 0)
1169d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1170d7eb6b47SHartmut Brandt 			value->v.integer = sys_poll;
1171d7eb6b47SHartmut Brandt 			break;
1172d7eb6b47SHartmut Brandt 
1173d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysPeer:
1174d7eb6b47SHartmut Brandt 			if (sysb_peer == 0)
1175d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1176d7eb6b47SHartmut Brandt 			value->v.uint32 = sys_peer;
1177d7eb6b47SHartmut Brandt 			break;
1178d7eb6b47SHartmut Brandt 
1179d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysClock:
1180d7eb6b47SHartmut Brandt 			if (sysb_clock == 0)
1181d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1182d7eb6b47SHartmut Brandt 			return (string_get(value, sys_clock, 8));
1183d7eb6b47SHartmut Brandt 
1184d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysSystem:
1185d7eb6b47SHartmut Brandt 			if (sys_system == NULL)
1186d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1187d7eb6b47SHartmut Brandt 			return (string_get(value, sys_system, -1));
1188d7eb6b47SHartmut Brandt 
1189d7eb6b47SHartmut Brandt 		  case LEAF_ntpSysProcessor:
1190d7eb6b47SHartmut Brandt 			if (sys_processor == NULL)
1191d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1192d7eb6b47SHartmut Brandt 			return (string_get(value, sys_processor, -1));
1193d7eb6b47SHartmut Brandt 
1194d7eb6b47SHartmut Brandt 		  default:
1195d7eb6b47SHartmut Brandt 			abort();
1196d7eb6b47SHartmut Brandt 		}
1197d7eb6b47SHartmut Brandt 		return (SNMP_ERR_NOERROR);
1198d7eb6b47SHartmut Brandt 
1199d7eb6b47SHartmut Brandt 	  case SNMP_OP_SET:
1200d7eb6b47SHartmut Brandt 		return (SNMP_ERR_NOT_WRITEABLE);
1201d7eb6b47SHartmut Brandt 
1202d7eb6b47SHartmut Brandt 	  case SNMP_OP_COMMIT:
1203d7eb6b47SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1204d7eb6b47SHartmut Brandt 		abort();
1205d7eb6b47SHartmut Brandt 	}
1206d7eb6b47SHartmut Brandt 	abort();
1207d7eb6b47SHartmut Brandt }
1208d7eb6b47SHartmut Brandt 
1209d7eb6b47SHartmut Brandt int
op_ntpPeersVarTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1210d7eb6b47SHartmut Brandt op_ntpPeersVarTable(struct snmp_context *ctx __unused, struct snmp_value *value,
1211d7eb6b47SHartmut Brandt     u_int sub, u_int iidx, enum snmp_op op)
1212d7eb6b47SHartmut Brandt {
1213d7eb6b47SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1214d7eb6b47SHartmut Brandt 	uint32_t peer;
1215d7eb6b47SHartmut Brandt 	struct peer *t;
1216d7eb6b47SHartmut Brandt 
1217d7eb6b47SHartmut Brandt 	if (this_tick > peers_tick) {
1218d7eb6b47SHartmut Brandt 		if (fetch_peers() == -1)
1219d7eb6b47SHartmut Brandt 			return (SNMP_ERR_GENERR);
1220d7eb6b47SHartmut Brandt 		peers_tick = this_tick;
1221d7eb6b47SHartmut Brandt 	}
1222d7eb6b47SHartmut Brandt 
1223d7eb6b47SHartmut Brandt 	switch (op) {
1224d7eb6b47SHartmut Brandt 
1225d7eb6b47SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1226d7eb6b47SHartmut Brandt 		t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1227d7eb6b47SHartmut Brandt 		if (t == NULL)
1228d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1229d7eb6b47SHartmut Brandt 		value->var.len = sub + 1;
1230d7eb6b47SHartmut Brandt 		value->var.subs[sub] = t->index;
1231d7eb6b47SHartmut Brandt 		break;
1232d7eb6b47SHartmut Brandt 
1233d7eb6b47SHartmut Brandt 	  case SNMP_OP_GET:
1234d7eb6b47SHartmut Brandt 		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1235d7eb6b47SHartmut Brandt 		if (t == NULL)
1236d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1237d7eb6b47SHartmut Brandt 		break;
1238d7eb6b47SHartmut Brandt 
1239d7eb6b47SHartmut Brandt 	  case SNMP_OP_SET:
1240d7eb6b47SHartmut Brandt 		if (index_decode(&value->var, sub, iidx, &peer))
1241d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1242d7eb6b47SHartmut Brandt 		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1243d7eb6b47SHartmut Brandt 		if (t != NULL)
1244d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOT_WRITEABLE);
1245d7eb6b47SHartmut Brandt 		return (SNMP_ERR_NO_CREATION);
1246d7eb6b47SHartmut Brandt 
1247d7eb6b47SHartmut Brandt 	  case SNMP_OP_COMMIT:
1248d7eb6b47SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1249d7eb6b47SHartmut Brandt 	  default:
1250d7eb6b47SHartmut Brandt 		abort();
1251d7eb6b47SHartmut Brandt 	}
1252d7eb6b47SHartmut Brandt 
1253d7eb6b47SHartmut Brandt 	/*
1254d7eb6b47SHartmut Brandt 	 * Come here for GET and COMMIT
1255d7eb6b47SHartmut Brandt 	 */
1256d7eb6b47SHartmut Brandt 	switch (which) {
1257d7eb6b47SHartmut Brandt 
1258d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersConfigured:
1259d7eb6b47SHartmut Brandt 		value->v.integer = t->config;
1260d7eb6b47SHartmut Brandt 		break;
1261d7eb6b47SHartmut Brandt 
1262d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersPeerAddress:
1263d7eb6b47SHartmut Brandt 		return (ip_get(value, t->srcadr));
1264d7eb6b47SHartmut Brandt 
1265d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersPeerPort:
1266d7eb6b47SHartmut Brandt 		value->v.uint32 = t->srcport;
1267d7eb6b47SHartmut Brandt 		break;
1268d7eb6b47SHartmut Brandt 
1269d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersHostAddress:
1270d7eb6b47SHartmut Brandt 		return (ip_get(value, t->dstadr));
1271d7eb6b47SHartmut Brandt 
1272d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersHostPort:
1273d7eb6b47SHartmut Brandt 		value->v.uint32 = t->dstport;
1274d7eb6b47SHartmut Brandt 		break;
1275d7eb6b47SHartmut Brandt 
1276d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersLeap:
1277d7eb6b47SHartmut Brandt 		value->v.integer = t->leap;
1278d7eb6b47SHartmut Brandt 		break;
1279d7eb6b47SHartmut Brandt 
1280d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersMode:
1281d7eb6b47SHartmut Brandt 		value->v.integer = t->hmode;
1282d7eb6b47SHartmut Brandt 		break;
1283d7eb6b47SHartmut Brandt 
1284d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersStratum:
1285d7eb6b47SHartmut Brandt 		value->v.integer = t->stratum;
1286d7eb6b47SHartmut Brandt 		break;
1287d7eb6b47SHartmut Brandt 
1288d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersPeerPoll:
1289d7eb6b47SHartmut Brandt 		value->v.integer = t->ppoll;
1290d7eb6b47SHartmut Brandt 		break;
1291d7eb6b47SHartmut Brandt 
1292d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersHostPoll:
1293d7eb6b47SHartmut Brandt 		value->v.integer = t->hpoll;
1294d7eb6b47SHartmut Brandt 		break;
1295d7eb6b47SHartmut Brandt 
1296d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersPrecision:
1297d7eb6b47SHartmut Brandt 		value->v.integer = t->precision;
1298d7eb6b47SHartmut Brandt 		break;
1299d7eb6b47SHartmut Brandt 
1300d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersRootDelay:
1301d7eb6b47SHartmut Brandt 		return (string_get(value, t->rootdelay, -1));
1302d7eb6b47SHartmut Brandt 
1303d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersRootDispersion:
1304d7eb6b47SHartmut Brandt 		return (string_get(value, t->rootdispersion, -1));
1305d7eb6b47SHartmut Brandt 
1306d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersRefId:
1307d7eb6b47SHartmut Brandt 		return (string_get(value, t->refid, -1));
1308d7eb6b47SHartmut Brandt 
1309d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersRefTime:
1310d7eb6b47SHartmut Brandt 		return (string_get(value, t->reftime, 8));
1311d7eb6b47SHartmut Brandt 
1312d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersOrgTime:
1313d7eb6b47SHartmut Brandt 		return (string_get(value, t->orgtime, 8));
1314d7eb6b47SHartmut Brandt 
1315d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersReceiveTime:
1316d7eb6b47SHartmut Brandt 		return (string_get(value, t->rcvtime, 8));
1317d7eb6b47SHartmut Brandt 
1318d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersTransmitTime:
1319d7eb6b47SHartmut Brandt 		return (string_get(value, t->xmttime, 8));
1320d7eb6b47SHartmut Brandt 
1321d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersReach:
1322d7eb6b47SHartmut Brandt 		value->v.uint32 = t->reach;
1323d7eb6b47SHartmut Brandt 		break;
1324d7eb6b47SHartmut Brandt 
1325d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersTimer:
1326d7eb6b47SHartmut Brandt 		value->v.uint32 = t->timer;
1327d7eb6b47SHartmut Brandt 		break;
1328d7eb6b47SHartmut Brandt 
1329d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersOffset:
1330d7eb6b47SHartmut Brandt 		return (string_get(value, t->offset, -1));
1331d7eb6b47SHartmut Brandt 
1332d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersDelay:
1333d7eb6b47SHartmut Brandt 		return (string_get(value, t->delay, -1));
1334d7eb6b47SHartmut Brandt 
1335d7eb6b47SHartmut Brandt 	  case LEAF_ntpPeersDispersion:
1336d7eb6b47SHartmut Brandt 		return (string_get(value, t->dispersion, -1));
1337d7eb6b47SHartmut Brandt 
1338d7eb6b47SHartmut Brandt 	  default:
1339d7eb6b47SHartmut Brandt 		abort();
1340d7eb6b47SHartmut Brandt 	}
1341d7eb6b47SHartmut Brandt 	return (SNMP_ERR_NOERROR);
1342d7eb6b47SHartmut Brandt }
1343d7eb6b47SHartmut Brandt 
1344d7eb6b47SHartmut Brandt 
1345d7eb6b47SHartmut Brandt int
op_ntpFilterPeersVarTable(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1346d7eb6b47SHartmut Brandt op_ntpFilterPeersVarTable(struct snmp_context *ctx __unused,
1347d7eb6b47SHartmut Brandt     struct snmp_value *value, u_int sub, u_int iidx, enum snmp_op op)
1348d7eb6b47SHartmut Brandt {
1349d7eb6b47SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1350d7eb6b47SHartmut Brandt 	uint32_t peer;
1351d7eb6b47SHartmut Brandt 	struct peer *t;
1352d7eb6b47SHartmut Brandt 
1353d7eb6b47SHartmut Brandt 	if (this_tick > peers_tick) {
1354d7eb6b47SHartmut Brandt 		if (fetch_peers() == -1)
1355d7eb6b47SHartmut Brandt 			return (SNMP_ERR_GENERR);
1356d7eb6b47SHartmut Brandt 		peers_tick = this_tick;
1357d7eb6b47SHartmut Brandt 	}
1358d7eb6b47SHartmut Brandt 
1359d7eb6b47SHartmut Brandt 	switch (op) {
1360d7eb6b47SHartmut Brandt 
1361d7eb6b47SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1362d7eb6b47SHartmut Brandt 		t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1363d7eb6b47SHartmut Brandt 		if (t == NULL)
1364d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1365d7eb6b47SHartmut Brandt 		value->var.len = sub + 1;
1366d7eb6b47SHartmut Brandt 		value->var.subs[sub] = t->index;
1367d7eb6b47SHartmut Brandt 		break;
1368d7eb6b47SHartmut Brandt 
1369d7eb6b47SHartmut Brandt 	  case SNMP_OP_GET:
1370d7eb6b47SHartmut Brandt 		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1371d7eb6b47SHartmut Brandt 		if (t == NULL)
1372d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1373d7eb6b47SHartmut Brandt 		break;
1374d7eb6b47SHartmut Brandt 
1375d7eb6b47SHartmut Brandt 	  case SNMP_OP_SET:
1376d7eb6b47SHartmut Brandt 		if (index_decode(&value->var, sub, iidx, &peer))
1377d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1378d7eb6b47SHartmut Brandt 		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1379d7eb6b47SHartmut Brandt 		if (t != NULL)
1380d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOT_WRITEABLE);
1381d7eb6b47SHartmut Brandt 		return (SNMP_ERR_NO_CREATION);
1382d7eb6b47SHartmut Brandt 
1383d7eb6b47SHartmut Brandt 	  case SNMP_OP_COMMIT:
1384d7eb6b47SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1385d7eb6b47SHartmut Brandt 	  default:
1386d7eb6b47SHartmut Brandt 		abort();
1387d7eb6b47SHartmut Brandt 	}
1388d7eb6b47SHartmut Brandt 
1389d7eb6b47SHartmut Brandt 	/*
1390d7eb6b47SHartmut Brandt 	 * Come here for GET and COMMIT
1391d7eb6b47SHartmut Brandt 	 */
1392d7eb6b47SHartmut Brandt 	switch (which) {
1393d7eb6b47SHartmut Brandt 
1394d7eb6b47SHartmut Brandt 	  case LEAF_ntpFilterValidEntries:
1395d7eb6b47SHartmut Brandt 		value->v.integer = t->filt_entries;
1396d7eb6b47SHartmut Brandt 		break;
1397d7eb6b47SHartmut Brandt 
1398d7eb6b47SHartmut Brandt 	  default:
1399d7eb6b47SHartmut Brandt 		abort();
1400d7eb6b47SHartmut Brandt 	}
1401d7eb6b47SHartmut Brandt 	return (SNMP_ERR_NOERROR);
1402d7eb6b47SHartmut Brandt }
1403d7eb6b47SHartmut Brandt 
1404d7eb6b47SHartmut Brandt int
op_ntpFilterRegisterTable(struct snmp_context * ctx __unused,struct snmp_value * value __unused,u_int sub __unused,u_int iidx __unused,enum snmp_op op __unused)1405d7eb6b47SHartmut Brandt op_ntpFilterRegisterTable(struct snmp_context *ctx __unused, struct snmp_value *value __unused,
1406d7eb6b47SHartmut Brandt     u_int sub __unused, u_int iidx __unused, enum snmp_op op __unused)
1407d7eb6b47SHartmut Brandt {
1408d7eb6b47SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1409d7eb6b47SHartmut Brandt 	uint32_t peer;
1410d7eb6b47SHartmut Brandt 	uint32_t filt;
1411d7eb6b47SHartmut Brandt 	struct filt *t;
1412d7eb6b47SHartmut Brandt 
1413d7eb6b47SHartmut Brandt 	if (this_tick > peers_tick) {
1414d7eb6b47SHartmut Brandt 		if (fetch_peers() == -1)
1415d7eb6b47SHartmut Brandt 			return (SNMP_ERR_GENERR);
1416d7eb6b47SHartmut Brandt 		peers_tick = this_tick;
1417d7eb6b47SHartmut Brandt 	}
1418d7eb6b47SHartmut Brandt 
1419d7eb6b47SHartmut Brandt 	switch (op) {
1420d7eb6b47SHartmut Brandt 
1421d7eb6b47SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1422d7eb6b47SHartmut Brandt 		t = NEXT_OBJECT_OID(&filts, &value->var, sub);
1423d7eb6b47SHartmut Brandt 		if (t == NULL)
1424d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1425d7eb6b47SHartmut Brandt 		index_append(&value->var, sub, &t->index);
1426d7eb6b47SHartmut Brandt 		break;
1427d7eb6b47SHartmut Brandt 
1428d7eb6b47SHartmut Brandt 	  case SNMP_OP_GET:
1429d7eb6b47SHartmut Brandt 		t = FIND_OBJECT_OID(&filts, &value->var, sub);
1430d7eb6b47SHartmut Brandt 		if (t == NULL)
1431d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1432d7eb6b47SHartmut Brandt 		break;
1433d7eb6b47SHartmut Brandt 
1434d7eb6b47SHartmut Brandt 	  case SNMP_OP_SET:
1435d7eb6b47SHartmut Brandt 		if (index_decode(&value->var, sub, iidx, &peer, &filt))
1436d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1437d7eb6b47SHartmut Brandt 		t = FIND_OBJECT_OID(&filts, &value->var, sub);
1438d7eb6b47SHartmut Brandt 		if (t != NULL)
1439d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOT_WRITEABLE);
1440d7eb6b47SHartmut Brandt 		return (SNMP_ERR_NO_CREATION);
1441d7eb6b47SHartmut Brandt 
1442d7eb6b47SHartmut Brandt 	  case SNMP_OP_COMMIT:
1443d7eb6b47SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1444d7eb6b47SHartmut Brandt 	  default:
1445d7eb6b47SHartmut Brandt 		abort();
1446d7eb6b47SHartmut Brandt 	}
1447d7eb6b47SHartmut Brandt 
1448d7eb6b47SHartmut Brandt 	/*
1449d7eb6b47SHartmut Brandt 	 * Come here for GET and COMMIT
1450d7eb6b47SHartmut Brandt 	 */
1451d7eb6b47SHartmut Brandt 	switch (which) {
1452d7eb6b47SHartmut Brandt 
1453d7eb6b47SHartmut Brandt 	  case LEAF_ntpFilterPeersOffset:
1454d7eb6b47SHartmut Brandt 		return (string_get(value, t->offset, -1));
1455d7eb6b47SHartmut Brandt 
1456d7eb6b47SHartmut Brandt 	  case LEAF_ntpFilterPeersDelay:
1457d7eb6b47SHartmut Brandt 		return (string_get(value, t->delay, -1));
1458d7eb6b47SHartmut Brandt 
1459d7eb6b47SHartmut Brandt 	  case LEAF_ntpFilterPeersDispersion:
1460d7eb6b47SHartmut Brandt 		return (string_get(value, t->dispersion, -1));
1461d7eb6b47SHartmut Brandt 
1462d7eb6b47SHartmut Brandt 	  default:
1463d7eb6b47SHartmut Brandt 		abort();
1464d7eb6b47SHartmut Brandt 	}
1465d7eb6b47SHartmut Brandt 	return (SNMP_ERR_NOERROR);
1466d7eb6b47SHartmut Brandt }
1467d7eb6b47SHartmut Brandt 
1468d7eb6b47SHartmut Brandt /*
1469d7eb6b47SHartmut Brandt  * System variables - read-only scalars only.
1470d7eb6b47SHartmut Brandt  */
1471d7eb6b47SHartmut Brandt int
op_begemot_ntp(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1472d7eb6b47SHartmut Brandt op_begemot_ntp(struct snmp_context *ctx __unused, struct snmp_value *value,
1473d7eb6b47SHartmut Brandt     u_int sub, u_int iidx __unused, enum snmp_op op)
1474d7eb6b47SHartmut Brandt {
1475d7eb6b47SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1476d7eb6b47SHartmut Brandt 	int ret;
1477d7eb6b47SHartmut Brandt 
1478d7eb6b47SHartmut Brandt 	switch (op) {
1479d7eb6b47SHartmut Brandt 
1480d7eb6b47SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1481d7eb6b47SHartmut Brandt 		abort();
1482d7eb6b47SHartmut Brandt 
1483d7eb6b47SHartmut Brandt 	  case SNMP_OP_GET:
1484d7eb6b47SHartmut Brandt 		switch (which) {
1485d7eb6b47SHartmut Brandt 
1486d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpHost:
1487d7eb6b47SHartmut Brandt 			return (string_get(value, ntp_host, -1));
1488d7eb6b47SHartmut Brandt 
1489d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpPort:
1490d7eb6b47SHartmut Brandt 			return (string_get(value, ntp_port, -1));
1491d7eb6b47SHartmut Brandt 
1492d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpTimeout:
1493d7eb6b47SHartmut Brandt 			value->v.uint32 = ntp_timeout;
1494d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1495d7eb6b47SHartmut Brandt 
1496d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpDebug:
1497d7eb6b47SHartmut Brandt 			value->v.uint32 = ntp_debug;
1498d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1499d7eb6b47SHartmut Brandt 
1500d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpJitter:
1501d7eb6b47SHartmut Brandt 			if (this_tick > sysinfo_tick) {
1502d7eb6b47SHartmut Brandt 				if (fetch_sysinfo() == -1)
1503d7eb6b47SHartmut Brandt 					return (SNMP_ERR_GENERR);
1504d7eb6b47SHartmut Brandt 				sysinfo_tick = this_tick;
1505d7eb6b47SHartmut Brandt 			}
1506d7eb6b47SHartmut Brandt 			if (!sysb_jitter)
1507d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1508d7eb6b47SHartmut Brandt 			value->v.counter64 = sys_jitter / 1000 * (1ULL << 32);
1509d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1510d7eb6b47SHartmut Brandt 
1511d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpStability:
1512d7eb6b47SHartmut Brandt 			if (this_tick > sysinfo_tick) {
1513d7eb6b47SHartmut Brandt 				if (fetch_sysinfo() == -1)
1514d7eb6b47SHartmut Brandt 					return (SNMP_ERR_GENERR);
1515d7eb6b47SHartmut Brandt 				sysinfo_tick = this_tick;
1516d7eb6b47SHartmut Brandt 			}
1517d7eb6b47SHartmut Brandt 			if (!sysb_stability)
1518d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOSUCHNAME);
1519d7eb6b47SHartmut Brandt 			value->v.counter64 = sys_stability * (1ULL << 32);
1520d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1521d7eb6b47SHartmut Brandt 		}
1522d7eb6b47SHartmut Brandt 		abort();
1523d7eb6b47SHartmut Brandt 
1524d7eb6b47SHartmut Brandt 	  case SNMP_OP_SET:
1525d7eb6b47SHartmut Brandt 		switch (which) {
1526d7eb6b47SHartmut Brandt 
1527d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpHost:
1528165c5d31SHartmut Brandt 			/* only at initialization */
1529d7eb6b47SHartmut Brandt 			if (community != COMM_INITIALIZE)
1530d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOT_WRITEABLE);
1531d7eb6b47SHartmut Brandt 
1532d7eb6b47SHartmut Brandt 			if ((ret = string_save(value, ctx, -1, &ntp_host))
1533d7eb6b47SHartmut Brandt 			    != SNMP_ERR_NOERROR)
1534d7eb6b47SHartmut Brandt 				return (ret);
1535d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1536d7eb6b47SHartmut Brandt 
1537d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpPort:
1538165c5d31SHartmut Brandt 			/* only at initialization */
1539d7eb6b47SHartmut Brandt 			if (community != COMM_INITIALIZE)
1540d7eb6b47SHartmut Brandt 				return (SNMP_ERR_NOT_WRITEABLE);
1541d7eb6b47SHartmut Brandt 
1542d7eb6b47SHartmut Brandt 			if ((ret = string_save(value, ctx, -1, &ntp_port))
1543d7eb6b47SHartmut Brandt 			    != SNMP_ERR_NOERROR)
1544d7eb6b47SHartmut Brandt 				return (ret);
1545d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1546d7eb6b47SHartmut Brandt 
1547d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpTimeout:
1548d7eb6b47SHartmut Brandt 			ctx->scratch->int1 = ntp_timeout;
1549d7eb6b47SHartmut Brandt 			if (value->v.uint32 < 1)
1550d7eb6b47SHartmut Brandt 				return (SNMP_ERR_WRONG_VALUE);
1551d7eb6b47SHartmut Brandt 			ntp_timeout = value->v.integer;
1552d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1553d7eb6b47SHartmut Brandt 
1554d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpDebug:
1555d7eb6b47SHartmut Brandt 			ctx->scratch->int1 = ntp_debug;
1556d7eb6b47SHartmut Brandt 			ntp_debug = value->v.integer;
1557d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1558d7eb6b47SHartmut Brandt 		}
1559d7eb6b47SHartmut Brandt 		abort();
1560d7eb6b47SHartmut Brandt 
1561d7eb6b47SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1562d7eb6b47SHartmut Brandt 		switch (which) {
1563d7eb6b47SHartmut Brandt 
1564d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpHost:
1565d7eb6b47SHartmut Brandt 			string_rollback(ctx, &ntp_host);
1566d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1567d7eb6b47SHartmut Brandt 
1568d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpPort:
1569d7eb6b47SHartmut Brandt 			string_rollback(ctx, &ntp_port);
1570d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1571d7eb6b47SHartmut Brandt 
1572d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpTimeout:
1573d7eb6b47SHartmut Brandt 			ntp_timeout = ctx->scratch->int1;
1574d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1575d7eb6b47SHartmut Brandt 
1576d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpDebug:
1577d7eb6b47SHartmut Brandt 			ntp_debug = ctx->scratch->int1;
1578d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1579d7eb6b47SHartmut Brandt 		}
1580d7eb6b47SHartmut Brandt 		abort();
1581d7eb6b47SHartmut Brandt 
1582d7eb6b47SHartmut Brandt 	  case SNMP_OP_COMMIT:
1583d7eb6b47SHartmut Brandt 		switch (which) {
1584d7eb6b47SHartmut Brandt 
1585d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpHost:
1586d7eb6b47SHartmut Brandt 			string_commit(ctx);
1587d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1588d7eb6b47SHartmut Brandt 
1589d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpPort:
1590d7eb6b47SHartmut Brandt 			string_commit(ctx);
1591d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1592d7eb6b47SHartmut Brandt 
1593d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpTimeout:
1594d7eb6b47SHartmut Brandt 		  case LEAF_begemotNtpDebug:
1595d7eb6b47SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1596d7eb6b47SHartmut Brandt 		}
1597d7eb6b47SHartmut Brandt 		abort();
1598d7eb6b47SHartmut Brandt 	}
1599d7eb6b47SHartmut Brandt 	abort();
1600d7eb6b47SHartmut Brandt }
1601