1145557Sharti/*
2145557Sharti * Copyright (c) 2005
3145557Sharti *	Hartmut Brandt.
4145557Sharti *	All rights reserved.
5145557Sharti *
6145557Sharti * Author: Harti Brandt <harti@freebsd.org>
7145557Sharti *
8145557Sharti * Redistribution of this software and documentation and use in source and
9145557Sharti * binary forms, with or without modification, are permitted provided that
10145557Sharti * the following conditions are met:
11145557Sharti *
12145557Sharti * 1. Redistributions of source code or documentation must retain the above
13145557Sharti *    copyright notice, this list of conditions and the following disclaimer.
14145557Sharti * 2. Redistributions in binary form must reproduce the above copyright
15145557Sharti *    notice, this list of conditions and the following disclaimer in the
16145557Sharti *    documentation and/or other materials provided with the distribution.
17145557Sharti *
18145557Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
19145557Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20145557Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21145557Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22145557Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23145557Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24145557Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25145557Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26145557Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27145557Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28145557Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29145557Sharti *
30156066Sharti * $Begemot: bsnmp/snmp_ntp/snmp_ntp.c,v 1.9 2005/10/06 07:15:01 brandt_h Exp $
31145557Sharti *
32145557Sharti * NTP interface for SNMPd.
33145557Sharti */
34145557Sharti
35145557Sharti#include <sys/queue.h>
36145557Sharti#include <sys/time.h>
37145557Sharti#include <sys/types.h>
38145557Sharti#include <sys/select.h>
39145557Sharti#include <sys/socket.h>
40145557Sharti#include <ctype.h>
41145557Sharti#include <errno.h>
42145557Sharti#include <netdb.h>
43150920Sharti#ifdef HAVE_STDINT_H
44145557Sharti#include <stdint.h>
45150920Sharti#elif defined(HAVE_INTTYPES_H)
46150920Sharti#include <inttypes.h>
47150920Sharti#endif
48145557Sharti#include <stdio.h>
49145557Sharti#include <stdlib.h>
50145557Sharti#include <string.h>
51145557Sharti#include <syslog.h>
52145557Sharti#include <unistd.h>
53145557Sharti
54156066Sharti#include "support.h"
55145557Sharti#include "snmpmod.h"
56145557Sharti#include "ntp_tree.h"
57145557Sharti#include "ntp_oid.h"
58145557Sharti
59145557Sharti#define	NTPC_MAX	576
60145557Sharti#define	NTPC_VERSION	3
61145557Sharti#define	NTPC_MODE	6
62145557Sharti#define	NTPC_DMAX	468
63145557Sharti
64145557Sharti#define	NTPC_BIT_RESP	0x80
65145557Sharti#define	NTPC_BIT_ERROR	0x40
66145557Sharti#define	NTPC_BIT_MORE	0x20
67145557Sharti
68145557Sharti#define	NTPC_OPMASK	0x1f
69145557Sharti#define	NTPC_OP_READSTAT	1
70145557Sharti#define	NTPC_OP_READVAR		2
71145557Sharti
72145557Sharti/* our module handle */
73145557Shartistatic struct lmodule *module;
74145557Sharti
75145557Sharti/* debug flag */
76145557Shartistatic uint32_t ntp_debug;
77145557Sharti#define DBG_DUMP_PKTS	0x01
78145557Sharti#define	DBG_DUMP_VARS	0x02
79145557Sharti
80145557Sharti/* OIDs */
81145557Shartistatic const struct asn_oid oid_ntpMIB = OIDX_ntpMIB;
82145557Sharti
83145557Sharti/* the Object Resource registration index */
84145557Shartistatic u_int reg_index;
85145557Sharti
86145557Sharti/* last time we've fetch the system variables */
87146525Shartistatic uint64_t sysinfo_tick;
88145557Sharti
89145557Sharti/* cached system variables */
90145557Shartistatic int32_t	sys_leap;
91145557Shartistatic int	sysb_leap;
92145557Shartistatic int32_t	sys_stratum;
93145557Shartistatic int	sysb_stratum;
94145557Shartistatic int32_t	sys_precision;
95145557Shartistatic int	sysb_precision;
96145557Shartistatic char	*sys_rootdelay;
97145557Shartistatic char	*sys_rootdispersion;
98145557Shartistatic char	*sys_refid;
99145557Shartistatic char	sys_reftime[8];
100145557Shartistatic int	sysb_reftime;
101145557Shartistatic int32_t	sys_poll;
102145557Shartistatic int	sysb_poll;
103145557Shartistatic uint32_t	sys_peer;
104145557Shartistatic int	sysb_peer;
105145557Shartistatic u_char	sys_clock[8];
106145557Shartistatic int	sysb_clock;
107145557Shartistatic char	*sys_system;
108145557Shartistatic char	*sys_processor;
109145557Shartistatic int	sysb_jitter;
110145557Shartistatic double	sys_jitter;
111145557Shartistatic int	sysb_stability;
112145557Shartistatic double	sys_stability;
113145557Sharti
114145557Sharti/* last time we've fetch the peer list */
115146525Shartistatic uint64_t peers_tick;
116145557Sharti
117145557Sharti/* request sequence number generator */
118145557Shartistatic uint16_t	seqno;
119145557Sharti
120145557Sharti/* NTPD socket */
121145557Shartistatic int ntpd_sock;
122145557Shartistatic void *ntpd_fd;
123145557Sharti
124145557Shartistruct peer {
125145557Sharti	/* required entries for macros */
126145557Sharti	uint32_t	index;
127145557Sharti	TAILQ_ENTRY(peer) link;
128145557Sharti
129145557Sharti	int32_t		config;		/* config bit */
130145557Sharti	u_char		srcadr[4];	/* PeerAddress */
131145557Sharti	uint32_t	srcport;	/* PeerPort */
132145557Sharti	u_char		dstadr[4];	/* HostAddress */
133145557Sharti	uint32_t	dstport;	/* HostPort */
134145557Sharti	int32_t		leap;		/* Leap */
135145557Sharti	int32_t		hmode;		/* Mode */
136145557Sharti	int32_t		stratum;	/* Stratum */
137145557Sharti	int32_t		ppoll;		/* PeerPoll */
138145557Sharti	int32_t		hpoll;		/* HostPoll */
139145557Sharti	int32_t		precision;	/* Precision */
140145557Sharti	char		*rootdelay;	/* RootDelay */
141145557Sharti	char		*rootdispersion;/* RootDispersion */
142145557Sharti	char		*refid;		/* RefId */
143145557Sharti	u_char		reftime[8];	/* RefTime */
144145557Sharti	u_char		orgtime[8];	/* OrgTime */
145145557Sharti	u_char		rcvtime[8];	/* ReceiveTime */
146145557Sharti	u_char		xmttime[8];	/* TransmitTime */
147145557Sharti	u_int32_t	reach;		/* Reach */
148145557Sharti	int32_t		timer;		/* Timer */
149145557Sharti	char		*offset;	/* Offset */
150145557Sharti	char		*delay;		/* Delay */
151145557Sharti	char		*dispersion;	/* Dispersion */
152145557Sharti	int32_t		filt_entries;
153145557Sharti};
154145557ShartiTAILQ_HEAD(peer_list, peer);
155145557Sharti
156145557Sharti/* list of peers */
157145557Shartistatic struct peer_list peers = TAILQ_HEAD_INITIALIZER(peers);
158145557Sharti
159145557Shartistruct filt {
160145557Sharti	/* required fields */
161145557Sharti	struct asn_oid	index;
162145557Sharti	TAILQ_ENTRY(filt) link;
163145557Sharti
164145557Sharti	char		*offset;
165145557Sharti	char		*delay;
166145557Sharti	char		*dispersion;
167145557Sharti};
168145557ShartiTAILQ_HEAD(filt_list, filt);
169145557Sharti
170145557Sharti/* list of filters */
171145557Shartistatic struct filt_list filts = TAILQ_HEAD_INITIALIZER(filts);
172145557Sharti
173145557Sharti/* configuration */
174145557Shartistatic u_char *ntp_host;
175145557Shartistatic u_char *ntp_port;
176145557Shartistatic uint32_t ntp_timeout;
177145557Sharti
178145557Shartistatic void ntpd_input(int, void *);
179145557Shartistatic int open_socket(void);
180145557Sharti
181150920Sharti/* the initialization function */
182145557Shartistatic int
183145557Shartintp_init(struct lmodule *mod, int argc, char *argv[] __unused)
184145557Sharti{
185145557Sharti
186145557Sharti	module = mod;
187145557Sharti
188145557Sharti	if (argc != 0) {
189145557Sharti		syslog(LOG_ERR, "bad number of arguments for %s", __func__);
190145557Sharti		return (EINVAL);
191145557Sharti	}
192145557Sharti
193145557Sharti	ntp_host = strdup("localhost");
194145557Sharti	ntp_port = strdup("ntp");
195145557Sharti	ntp_timeout = 50;		/* 0.5sec */
196145557Sharti
197145557Sharti	return (0);
198145557Sharti}
199145557Sharti
200145557Sharti/*
201145557Sharti * Module is started
202145557Sharti */
203145557Shartistatic void
204145557Shartintp_start(void)
205145557Sharti{
206145557Sharti
207145557Sharti	if (open_socket() != -1) {
208145557Sharti		ntpd_fd = fd_select(ntpd_sock, ntpd_input, NULL, module);
209145557Sharti		if (ntpd_fd == NULL) {
210145557Sharti			syslog(LOG_ERR, "fd_select failed on ntpd socket: %m");
211145557Sharti			return;
212145557Sharti		}
213145557Sharti	}
214145557Sharti	reg_index = or_register(&oid_ntpMIB, "The MIB for NTP.", module);
215145557Sharti}
216145557Sharti
217145557Sharti/*
218145557Sharti * Called, when the module is to be unloaded after it was successfully loaded
219145557Sharti */
220145557Shartistatic int
221145557Shartintp_fini(void)
222145557Sharti{
223145557Sharti
224145557Sharti	or_unregister(reg_index);
225145557Sharti	fd_deselect(ntpd_fd);
226145557Sharti
227145557Sharti	return (0);
228145557Sharti}
229145557Sharti
230145557Sharticonst struct snmp_module config = {
231145557Sharti	.comment =	"This module implements the NTP MIB",
232145557Sharti	.init =		ntp_init,
233145557Sharti	.start =	ntp_start,
234145557Sharti	.fini =		ntp_fini,
235145557Sharti	.tree =		ntp_ctree,
236145557Sharti	.tree_size =	ntp_CTREE_SIZE,
237145557Sharti};
238145557Sharti
239145557Sharti/*
240145557Sharti * Open the NTPD socket
241145557Sharti */
242145557Shartistatic int
243145557Shartiopen_socket(void)
244145557Sharti{
245145557Sharti	struct addrinfo hints, *res, *res0;
246145557Sharti	int	error;
247145557Sharti	const char *cause;
248145557Sharti
249145557Sharti	memset(&hints, 0, sizeof(hints));
250145557Sharti	hints.ai_family = AF_INET;
251145557Sharti	hints.ai_socktype = SOCK_DGRAM;
252145557Sharti
253145557Sharti	error = getaddrinfo(ntp_host, ntp_port, &hints, &res0);
254145557Sharti	if (error) {
255145557Sharti		syslog(LOG_ERR, "%s(%s): %s", ntp_host, ntp_port,
256145557Sharti		    gai_strerror(error));
257145557Sharti		return (-1);
258145557Sharti	}
259145557Sharti
260145557Sharti	ntpd_sock = -1;
261145557Sharti	cause = "no address";
262145557Sharti	errno = EADDRNOTAVAIL;
263145557Sharti	for (res = res0; res != NULL; res = res->ai_next) {
264145557Sharti		ntpd_sock = socket(res->ai_family, res->ai_socktype,
265145557Sharti		    res->ai_protocol);
266145557Sharti		if (ntpd_sock == -1) {
267145557Sharti			cause = "socket";
268145557Sharti			continue;
269145557Sharti		}
270145557Sharti		if (connect(ntpd_sock, res->ai_addr, res->ai_addrlen) == -1) {
271145557Sharti			cause = "connect";
272145557Sharti			(void)close(ntpd_sock);
273145557Sharti			ntpd_sock = -1;
274145557Sharti			continue;
275145557Sharti		}
276145557Sharti		break;
277145557Sharti	}
278145557Sharti	if (ntpd_sock == -1) {
279145557Sharti		syslog(LOG_ERR, "%s: %m", cause);
280145557Sharti		return (-1);
281145557Sharti	}
282145557Sharti	freeaddrinfo(res0);
283145557Sharti	return (0);
284145557Sharti}
285145557Sharti
286145557Sharti/*
287145557Sharti * Dump a packet
288145557Sharti */
289145557Shartistatic void
290145557Shartidump_packet(const u_char *pkt, size_t ret)
291145557Sharti{
292145557Sharti	char buf[8 * 3 + 1];
293145557Sharti	size_t i, j;
294145557Sharti
295145557Sharti	for (i = 0; i < ret; i += 8) {
296145557Sharti		buf[0] = '\0';
297145557Sharti		for (j = 0; i + j < (size_t)ret && j < 8; j++)
298145557Sharti			sprintf(buf + strlen(buf), " %02x", pkt[i + j]);
299145557Sharti		syslog(LOG_INFO, "%04zu:%s", i, buf);
300145557Sharti	}
301145557Sharti}
302145557Sharti
303145557Sharti/*
304145557Sharti * Execute an NTP request.
305145557Sharti */
306145557Shartistatic int
307145557Shartintpd_request(u_int op, u_int associd, const char *vars)
308145557Sharti{
309145557Sharti	u_char	*rpkt;
310145557Sharti	u_char	*ptr;
311145557Sharti	size_t	vlen;
312145557Sharti	ssize_t	ret;
313145557Sharti
314145557Sharti	if ((rpkt = malloc(NTPC_MAX)) == NULL) {
315145557Sharti		syslog(LOG_ERR, "%m");
316145557Sharti		return (-1);
317145557Sharti	}
318145557Sharti	memset(rpkt, 0, NTPC_MAX);
319145557Sharti
320145557Sharti	ptr = rpkt;
321145557Sharti	*ptr++ = (NTPC_VERSION << 3) | NTPC_MODE;
322145557Sharti	*ptr++ = op;
323145557Sharti
324145557Sharti	if (++seqno == 0)
325145557Sharti		seqno++;
326145557Sharti	*ptr++ = seqno >> 8;
327145557Sharti	*ptr++ = seqno;
328145557Sharti
329145557Sharti	/* skip status */
330145557Sharti	ptr += 2;
331145557Sharti
332145557Sharti	*ptr++ = associd >> 8;
333145557Sharti	*ptr++ = associd;
334145557Sharti
335145557Sharti	/* skip offset */
336145557Sharti	ptr += 2;
337145557Sharti
338145557Sharti	if (vars != NULL) {
339145557Sharti		vlen = strlen(vars);
340145557Sharti		if (vlen > NTPC_DMAX) {
341145557Sharti			syslog(LOG_ERR, "NTP request too long (%zu)", vlen);
342145557Sharti			free(rpkt);
343145557Sharti			return (-1);
344145557Sharti		}
345145557Sharti		*ptr++ = vlen >> 8;
346145557Sharti		*ptr++ = vlen;
347145557Sharti
348145557Sharti		memcpy(ptr, vars, vlen);
349145557Sharti		ptr += vlen;
350145557Sharti	} else
351145557Sharti		/* skip data length (is already zero) */
352145557Sharti		ptr += 2;
353145557Sharti
354145557Sharti	while ((ptr - rpkt) % 4 != 0)
355145557Sharti		*ptr++ = 0;
356145557Sharti
357145557Sharti	if (ntp_debug & DBG_DUMP_PKTS) {
358145557Sharti		syslog(LOG_INFO, "sending %zd bytes", ptr - rpkt);
359145557Sharti		dump_packet(rpkt, ptr - rpkt);
360145557Sharti	}
361145557Sharti
362145557Sharti	ret = send(ntpd_sock, rpkt, ptr - rpkt, 0);
363145557Sharti	if (ret == -1) {
364145557Sharti		syslog(LOG_ERR, "cannot send to ntpd: %m");
365145557Sharti		free(rpkt);
366145557Sharti		return (-1);
367145557Sharti	}
368150920Sharti	return (0);
369145557Sharti}
370145557Sharti
371145557Sharti/*
372145557Sharti * Callback if packet arrived from NTPD
373145557Sharti */
374145557Shartistatic int
375145557Shartintpd_read(uint16_t *op, uint16_t *associd, u_char **data, size_t *datalen)
376145557Sharti{
377145557Sharti	u_char	pkt[NTPC_MAX + 1];
378145557Sharti	u_char	*ptr, *nptr;
379145557Sharti	u_int	n;
380145557Sharti	ssize_t	ret;
381145557Sharti	size_t	z;
382145557Sharti	u_int	offset;		/* current offset */
383145557Sharti	int	more;		/* more flag */
384145557Sharti	int	sel;
385145557Sharti	struct timeval inc, end, rem;
386145557Sharti	fd_set	iset;
387145557Sharti
388145557Sharti	*datalen = 0;
389145557Sharti	*data = NULL;
390145557Sharti	offset = 0;
391145557Sharti
392145557Sharti	inc.tv_sec = ntp_timeout / 100;
393145557Sharti	inc.tv_usec = (ntp_timeout % 100) * 1000;
394145557Sharti
395145557Sharti	(void)gettimeofday(&end, NULL);
396145557Sharti	timeradd(&end, &inc, &end);
397145557Sharti
398145557Sharti  next:
399145557Sharti	/* compute remaining time */
400145557Sharti	(void)gettimeofday(&rem, NULL);
401145557Sharti	if (timercmp(&rem, &end, >=)) {
402145557Sharti		/* do a poll */
403145557Sharti		rem.tv_sec = 0;
404145557Sharti		rem.tv_usec = 0;
405145557Sharti	} else {
406145557Sharti		timersub(&end, &rem, &rem);
407145557Sharti	}
408145557Sharti
409145557Sharti	/* select */
410145557Sharti	FD_ZERO(&iset);
411145557Sharti	FD_SET(ntpd_sock, &iset);
412145557Sharti	sel = select(ntpd_sock + 1, &iset, NULL, NULL, &rem);
413145557Sharti	if (sel == -1) {
414145557Sharti		if (errno == EINTR)
415145557Sharti			goto next;
416145557Sharti		syslog(LOG_ERR, "select ntpd_sock: %m");
417145557Sharti		free(*data);
418145557Sharti		return (-1);
419145557Sharti	}
420145557Sharti	if (sel == 0) {
421145557Sharti		syslog(LOG_ERR, "timeout on NTP connection");
422145557Sharti		free(*data);
423145557Sharti		return (-1);
424145557Sharti	}
425145557Sharti
426145557Sharti	/* now read it */
427145557Sharti	ret = recv(ntpd_sock, pkt, sizeof(pkt), 0);
428145557Sharti	if (ret == -1) {
429145557Sharti		syslog(LOG_ERR, "error reading from ntpd: %m");
430145557Sharti		free(*data);
431145557Sharti		return (-1);
432145557Sharti	}
433145557Sharti
434145557Sharti	if (ntp_debug & DBG_DUMP_PKTS) {
435145557Sharti		syslog(LOG_INFO, "got %zd bytes", ret);
436145557Sharti		dump_packet(pkt, (size_t)ret);
437145557Sharti	}
438145557Sharti
439145557Sharti	ptr = pkt;
440150920Sharti	if ((*ptr & 0x3f) != ((NTPC_VERSION << 3) | NTPC_MODE)) {
441145557Sharti		syslog(LOG_ERR, "unexpected packet version 0x%x", *ptr);
442145557Sharti		free(*data);
443145557Sharti		return (-1);
444145557Sharti	}
445145557Sharti	ptr++;
446145557Sharti
447145557Sharti	if (!(*ptr & NTPC_BIT_RESP)) {
448145557Sharti		syslog(LOG_ERR, "not a response packet");
449145557Sharti		return (-1);
450145557Sharti	}
451145557Sharti	if (*ptr & NTPC_BIT_ERROR) {
452145557Sharti		z = *datalen - 12;
453145557Sharti		if (z > NTPC_DMAX)
454145557Sharti			z = NTPC_DMAX;
455145557Sharti		syslog(LOG_ERR, "error response: %.*s", (int)z, pkt + 12);
456145557Sharti		free(*data);
457145557Sharti		return (-1);
458145557Sharti	}
459145557Sharti	more = (*ptr & NTPC_BIT_MORE);
460145557Sharti
461145557Sharti	*op = *ptr++ & NTPC_OPMASK;
462145557Sharti
463145557Sharti	/* seqno */
464145557Sharti	n = *ptr++ << 8;
465145557Sharti	n |= *ptr++;
466145557Sharti
467145557Sharti	if (n != seqno) {
468145557Sharti		syslog(LOG_ERR, "expecting seqno %u, got %u", seqno, n);
469145557Sharti		free(*data);
470145557Sharti		return (-1);
471145557Sharti	}
472145557Sharti
473145557Sharti	/* status */
474145557Sharti	n = *ptr++ << 8;
475145557Sharti	n |= *ptr++;
476145557Sharti
477145557Sharti	/* associd */
478145557Sharti	*associd = *ptr++ << 8;
479145557Sharti	*associd |= *ptr++;
480145557Sharti
481145557Sharti	/* offset */
482145557Sharti	n = *ptr++ << 8;
483145557Sharti	n |= *ptr++;
484145557Sharti
485145557Sharti	if (n != offset) {
486145557Sharti		syslog(LOG_ERR, "offset: expecting %u, got %u", offset, n);
487145557Sharti		free(*data);
488145557Sharti		return (-1);
489145557Sharti	}
490145557Sharti
491145557Sharti	/* count */
492145557Sharti	n = *ptr++ << 8;
493145557Sharti	n |= *ptr++;
494145557Sharti
495145557Sharti	if ((size_t)ret < 12 + n) {
496145557Sharti		syslog(LOG_ERR, "packet too short");
497145557Sharti		return (-1);
498145557Sharti	}
499145557Sharti
500145557Sharti	nptr = realloc(*data, *datalen + n);
501145557Sharti	if (nptr == NULL) {
502145557Sharti		syslog(LOG_ERR, "cannot allocate memory: %m");
503145557Sharti		free(*data);
504145557Sharti		return (-1);
505145557Sharti	}
506145557Sharti	*data = nptr;
507145557Sharti
508145557Sharti	memcpy(*data + offset, ptr, n);
509145557Sharti	*datalen += n;
510145557Sharti
511145557Sharti	if (!more)
512145557Sharti		return (0);
513145557Sharti
514145557Sharti	offset += n;
515145557Sharti	goto next;
516145557Sharti}
517145557Sharti
518145557Sharti/*
519145557Sharti * Send a request and wait for the response
520145557Sharti */
521145557Shartistatic int
522145557Shartintpd_dialog(u_int op, u_int associd, const char *vars, u_char **data,
523145557Sharti    size_t *datalen)
524145557Sharti{
525145557Sharti	uint16_t rassocid;
526145557Sharti	uint16_t rop;
527145557Sharti
528145557Sharti	if (ntpd_request(op, associd, vars) == -1)
529145557Sharti		return (-1);
530145557Sharti	if (ntpd_read(&rop, &rassocid, data, datalen) == -1)
531145557Sharti		return (-1);
532145557Sharti
533145557Sharti	if (rop != op) {
534145557Sharti		syslog(LOG_ERR, "bad response op 0x%x", rop);
535145557Sharti		free(data);
536145557Sharti		return (-1);
537145557Sharti	}
538145557Sharti
539145557Sharti	if (associd != rassocid) {
540145557Sharti		syslog(LOG_ERR, "response for wrong associd");
541145557Sharti		free(data);
542145557Sharti		return (-1);
543145557Sharti	}
544145557Sharti	return (0);
545145557Sharti}
546145557Sharti
547145557Sharti/*
548145557Sharti * Callback if packet arrived from NTPD
549145557Sharti */
550145557Shartistatic void
551145557Shartintpd_input(int fd __unused, void *arg __unused)
552145557Sharti{
553145557Sharti	uint16_t associd;
554145557Sharti	uint16_t op;
555145557Sharti	u_char	*data;
556145557Sharti	size_t	datalen;
557145557Sharti
558145557Sharti	if (ntpd_read(&op, &associd, &data, &datalen) == -1)
559145557Sharti		return;
560145557Sharti
561145557Sharti	free(data);
562145557Sharti}
563145557Sharti
564145557Sharti/*
565145557Sharti * Find the value of a variable
566145557Sharti */
567145557Shartistatic int
568145557Shartintpd_parse(u_char **data, size_t *datalen, char **namep, char **valp)
569145557Sharti{
570145557Sharti	u_char *ptr = *data;
571145557Sharti	u_char *end = ptr + *datalen;
572145557Sharti	char *ptr1;
573145557Sharti	char endc;
574145557Sharti
575145557Sharti	/* skip leading spaces */
576145557Sharti	while (ptr < end && isspace((int)*ptr))
577145557Sharti		ptr++;
578145557Sharti
579145557Sharti	if (ptr == end)
580145557Sharti		return (0);
581145557Sharti
582145557Sharti	*namep = ptr;
583145557Sharti
584145557Sharti	/* skip to space or '=' or ','*/
585145557Sharti	while (ptr < end && !isspace((int)*ptr) && *ptr != '=' && *ptr != ',')
586145557Sharti		ptr++;
587145557Sharti	endc = *ptr;
588145557Sharti	*ptr++ = '\0';
589145557Sharti
590145557Sharti	/* skip space */
591145557Sharti	while (ptr < end && isspace((int)*ptr))
592145557Sharti		ptr++;
593145557Sharti
594145557Sharti	if (ptr == end || endc == ',') {
595145557Sharti		/* no value */
596145557Sharti		*valp = NULL;
597145557Sharti		*datalen -= ptr - *data;
598145557Sharti		*data = ptr;
599145557Sharti		return (1);
600145557Sharti	}
601145557Sharti
602145557Sharti	if (*ptr == '"') {
603145557Sharti		/* quoted */
604145557Sharti		ptr++;
605145557Sharti		*valp = ptr;
606145557Sharti		while (ptr < end && *ptr != '"')
607145557Sharti			ptr++;
608145557Sharti		if (ptr == end)
609145557Sharti			return (0);
610145557Sharti
611145557Sharti		*ptr++ = '\0';
612145557Sharti
613145557Sharti		/* find comma */
614145557Sharti		while (ptr < end && isspace((int)*ptr) && *ptr == ',')
615145557Sharti			ptr++;
616145557Sharti	} else {
617145557Sharti		*valp = ptr;
618145557Sharti
619145557Sharti		/* skip to end of value */
620145557Sharti		while (ptr < end && *ptr != ',')
621145557Sharti			ptr++;
622145557Sharti
623145557Sharti		/* remove trailing blanks */
624145557Sharti		for (ptr1 = ptr; ptr1 > *valp; ptr1--)
625145557Sharti			if (!isspace((int)ptr1[-1]))
626145557Sharti				break;
627145557Sharti		*ptr1 = '\0';
628145557Sharti
629145557Sharti		if (ptr < end)
630145557Sharti			ptr++;
631145557Sharti	}
632145557Sharti
633145557Sharti	*datalen -= ptr - *data;
634145557Sharti	*data = ptr;
635145557Sharti
636145557Sharti	return (1);
637145557Sharti}
638145557Sharti
639145557Sharti/*
640145557Sharti * Parse an int32 value
641145557Sharti */
642145557Shartistatic int
643145557Shartival_parse_int32(const char *val, int32_t *p, int32_t min, int32_t max, int base)
644145557Sharti{
645145557Sharti	long n;
646145557Sharti	char *end;
647145557Sharti
648145557Sharti	errno = 0;
649145557Sharti	n = strtol(val, &end, base);
650145557Sharti	if (errno != 0 || *end != '\0')
651145557Sharti		return (0);
652145557Sharti	if (n < min || n > max)
653145557Sharti		return (0);
654145557Sharti	*p = (int32_t)n;
655145557Sharti	return (1);
656145557Sharti}
657145557Sharti
658145557Sharti/*
659145557Sharti * Parse an uint32 value
660145557Sharti */
661145557Shartistatic int
662145557Shartival_parse_uint32(const char *val, uint32_t *p, uint32_t min, uint32_t max,
663145557Sharti    int base)
664145557Sharti{
665145557Sharti	u_long n;
666145557Sharti	char *end;
667145557Sharti
668145557Sharti	errno = 0;
669145557Sharti	n = strtoul(val, &end, base);
670145557Sharti	if (errno != 0 || *end != '\0')
671145557Sharti		return (0);
672145557Sharti	if (n < min || n > max)
673145557Sharti		return (0);
674145557Sharti	*p = (uint32_t)n;
675145557Sharti	return (1);
676145557Sharti}
677145557Sharti
678145557Sharti/*
679145557Sharti * Parse a double
680145557Sharti */
681145557Shartistatic int
682145557Shartival_parse_double(const char *val, double *p)
683145557Sharti{
684145557Sharti	char *end;
685145557Sharti
686145557Sharti	errno = 0;
687145557Sharti	*p = strtod(val, &end);
688145557Sharti	if (errno != 0 || *end != '\0')
689145557Sharti		return (0);
690145557Sharti	return (1);
691145557Sharti}
692145557Sharti
693145557Shartistatic int
694145557Shartival_parse_ts(const char *val, char *buf)
695145557Sharti{
696145557Sharti	int r, n;
697145557Sharti	u_int i, f;
698145557Sharti
699145557Sharti	if (strlen(val) > 2 && val[0] == '0' && val[1] == 'x') {
700145557Sharti		/* hex format */
701145557Sharti		r = sscanf(val + 2, "%x.%x%n", &i, &f, &n);
702145557Sharti		if (r != 2 || (size_t)n != strlen(val + 2))
703145557Sharti			return (0);
704145557Sharti	} else {
705145557Sharti		/* probably decimal */
706145557Sharti		r = sscanf(val, "%d.%d%n", &i, &f, &n);
707145557Sharti		if (r != 2 || (size_t)n != strlen(val))
708145557Sharti			return (0);
709145557Sharti	}
710145557Sharti	buf[0] = i >> 24;
711145557Sharti	buf[1] = i >> 16;
712145557Sharti	buf[2] = i >>  8;
713145557Sharti	buf[3] = i >>  0;
714145557Sharti	buf[4] = f >> 24;
715145557Sharti	buf[5] = f >> 16;
716145557Sharti	buf[6] = f >>  8;
717145557Sharti	buf[7] = f >>  0;
718145557Sharti	return (1);
719145557Sharti}
720145557Sharti
721145557Sharti/*
722145557Sharti * Parse an IP address. This resolves non-numeric names.
723145557Sharti */
724145557Shartistatic int
725145557Shartival_parse_ip(const char *val, u_char ip[4])
726145557Sharti{
727145557Sharti	int r, n, error;
728145557Sharti	struct addrinfo hints, *res0;
729150920Sharti	struct sockaddr_in *sin_local;
730145557Sharti
731145557Sharti	r = sscanf(val, "%hhd.%hhd.%hhd.%hhd%n",
732145557Sharti	    &ip[0], &ip[1], &ip[2], &ip[3], &n);
733145557Sharti	if (n == 4 && (size_t)n == strlen(val))
734145557Sharti		return (0);
735145557Sharti
736145557Sharti	memset(ip, 0, 4);
737145557Sharti
738145557Sharti	memset(&hints, 0, sizeof(hints));
739145557Sharti	hints.ai_family = AF_INET;
740145557Sharti	hints.ai_socktype = SOCK_DGRAM;
741145557Sharti
742145557Sharti	error = getaddrinfo(val, NULL, &hints, &res0);
743145557Sharti	if (error) {
744145557Sharti		syslog(LOG_ERR, "%s: %s", val, gai_strerror(error));
745145557Sharti		return (-1);
746145557Sharti	}
747145557Sharti	if (res0 == NULL) {
748145557Sharti		syslog(LOG_ERR, "%s: no address", val);
749145557Sharti		return (-1);
750145557Sharti	}
751145557Sharti
752150920Sharti	sin_local = (struct sockaddr_in *)(void *)res0->ai_addr;
753150920Sharti	ip[3] = sin_local->sin_addr.s_addr >> 24;
754150920Sharti	ip[2] = sin_local->sin_addr.s_addr >> 16;
755150920Sharti	ip[1] = sin_local->sin_addr.s_addr >>  8;
756150920Sharti	ip[0] = sin_local->sin_addr.s_addr >>  0;
757145557Sharti
758145557Sharti	freeaddrinfo(res0);
759145557Sharti	return (0);
760145557Sharti}
761145557Sharti
762145557Sharti/*
763145557Sharti * Fetch system info
764145557Sharti */
765145557Shartistatic int
766145557Shartifetch_sysinfo(void)
767145557Sharti{
768145557Sharti	u_char *data;
769145557Sharti	u_char *ptr;
770145557Sharti	size_t datalen;
771145557Sharti	char *name;
772145557Sharti	char *val;
773145557Sharti
774145557Sharti	if (ntpd_dialog(NTPC_OP_READVAR, 0,
775145557Sharti	    "leap,stratum,precision,rootdelay,rootdispersion,refid,reftime,"
776145557Sharti	    "poll,peer,clock,system,processor,jitter,stability",
777145557Sharti	    &data, &datalen))
778145557Sharti		return (-1);
779145557Sharti
780145557Sharti	/* clear info */
781145557Sharti	sysb_leap = 0;
782145557Sharti	sysb_stratum = 0;
783145557Sharti	sysb_precision = 0;
784145557Sharti	free(sys_rootdelay);
785145557Sharti	sys_rootdelay = NULL;
786145557Sharti	free(sys_rootdispersion);
787145557Sharti	sys_rootdispersion = NULL;
788145557Sharti	free(sys_refid);
789145557Sharti	sys_refid = NULL;
790145557Sharti	sysb_reftime = 0;
791145557Sharti	sysb_poll = 0;
792145557Sharti	sysb_peer = 0;
793145557Sharti	sysb_clock = 0;
794145557Sharti	free(sys_system);
795145557Sharti	sys_system = NULL;
796145557Sharti	free(sys_processor);
797145557Sharti	sys_processor = NULL;
798145557Sharti	sysb_jitter = 0;
799145557Sharti	sysb_stability = 0;
800145557Sharti
801145557Sharti	ptr = data;
802145557Sharti	while (ntpd_parse(&ptr, &datalen, &name, &val)) {
803145557Sharti		if (ntp_debug & DBG_DUMP_VARS)
804145557Sharti			syslog(LOG_DEBUG, "%s: '%s'='%s'", __func__, name, val);
805145557Sharti		if (strcmp(name, "leap") == 0 ||
806145557Sharti		    strcmp(name, "sys.leap") == 0) {
807145557Sharti			sysb_leap = val_parse_int32(val, &sys_leap,
808145557Sharti			    0, 3, 2);
809145557Sharti
810145557Sharti		} else if (strcmp(name, "stratum") == 0 ||
811145557Sharti		    strcmp(name, "sys.stratum") == 0) {
812145557Sharti			sysb_stratum = val_parse_int32(val, &sys_stratum,
813145557Sharti			    0, 255, 0);
814145557Sharti
815145557Sharti		} else if (strcmp(name, "precision") == 0 ||
816145557Sharti		    strcmp(name, "sys.precision") == 0) {
817145557Sharti			sysb_precision = val_parse_int32(val, &sys_precision,
818145557Sharti			    INT32_MIN, INT32_MAX, 0);
819145557Sharti
820145557Sharti		} else if (strcmp(name, "rootdelay") == 0 ||
821145557Sharti		    strcmp(name, "sys.rootdelay") == 0) {
822145557Sharti			sys_rootdelay = strdup(val);
823145557Sharti
824145557Sharti		} else if (strcmp(name, "rootdispersion") == 0 ||
825145557Sharti		    strcmp(name, "sys.rootdispersion") == 0) {
826145557Sharti			sys_rootdispersion = strdup(val);
827145557Sharti
828145557Sharti		} else if (strcmp(name, "refid") == 0 ||
829145557Sharti		    strcmp(name, "sys.refid") == 0) {
830145557Sharti			sys_refid = strdup(val);
831145557Sharti
832145557Sharti		} else if (strcmp(name, "reftime") == 0 ||
833145557Sharti		    strcmp(name, "sys.reftime") == 0) {
834145557Sharti			sysb_reftime = val_parse_ts(val, sys_reftime);
835145557Sharti
836145557Sharti		} else if (strcmp(name, "poll") == 0 ||
837145557Sharti		    strcmp(name, "sys.poll") == 0) {
838145557Sharti			sysb_poll = val_parse_int32(val, &sys_poll,
839145557Sharti			    INT32_MIN, INT32_MAX, 0);
840145557Sharti
841145557Sharti		} else if (strcmp(name, "peer") == 0 ||
842145557Sharti		    strcmp(name, "sys.peer") == 0) {
843145557Sharti			sysb_peer = val_parse_uint32(val, &sys_peer,
844145557Sharti			    0, UINT32_MAX, 0);
845145557Sharti
846145557Sharti		} else if (strcmp(name, "clock") == 0 ||
847145557Sharti		    strcmp(name, "sys.clock") == 0) {
848145557Sharti			sysb_clock = val_parse_ts(val, sys_clock);
849145557Sharti
850145557Sharti		} else if (strcmp(name, "system") == 0 ||
851145557Sharti		    strcmp(name, "sys.system") == 0) {
852145557Sharti			sys_system = strdup(val);
853145557Sharti
854145557Sharti		} else if (strcmp(name, "processor") == 0 ||
855145557Sharti		    strcmp(name, "sys.processor") == 0) {
856145557Sharti			sys_processor = strdup(val);
857145557Sharti
858145557Sharti		} else if (strcmp(name, "jitter") == 0 ||
859145557Sharti		    strcmp(name, "sys.jitter") == 0) {
860145557Sharti			sysb_jitter = val_parse_double(val, &sys_jitter);
861145557Sharti
862145557Sharti		} else if (strcmp(name, "stability") == 0 ||
863145557Sharti		    strcmp(name, "sys.stability") == 0) {
864145557Sharti			sysb_stability = val_parse_double(val, &sys_stability);
865145557Sharti		}
866145557Sharti	}
867145557Sharti
868145557Sharti	free(data);
869145557Sharti	return (0);
870145557Sharti}
871145557Sharti
872145557Shartistatic int
873145557Shartiparse_filt(char *val, uint16_t associd, int which)
874145557Sharti{
875145557Sharti	char *w;
876145557Sharti	int cnt;
877145557Sharti	struct filt *f;
878145557Sharti
879145557Sharti	cnt = 0;
880145557Sharti	for (w = strtok(val, " \t"); w != NULL; w = strtok(NULL, " \t")) {
881145557Sharti		TAILQ_FOREACH(f, &filts, link)
882145557Sharti			if (f->index.subs[0] == associd &&
883145557Sharti			    f->index.subs[1] == (asn_subid_t)(cnt + 1))
884145557Sharti				break;
885145557Sharti		if (f == NULL) {
886145557Sharti			f = malloc(sizeof(*f));
887145557Sharti			memset(f, 0, sizeof(*f));
888145557Sharti			f->index.len = 2;
889145557Sharti			f->index.subs[0] = associd;
890145557Sharti			f->index.subs[1] = cnt + 1;
891145557Sharti
892145557Sharti			INSERT_OBJECT_OID(f, &filts);
893145557Sharti		}
894145557Sharti
895145557Sharti		switch (which) {
896145557Sharti
897145557Sharti		  case 0:
898145557Sharti			f->offset = strdup(w);
899145557Sharti			break;
900145557Sharti
901145557Sharti		  case 1:
902145557Sharti			f->delay = strdup(w);
903145557Sharti			break;
904145557Sharti
905145557Sharti		  case 2:
906145557Sharti			f->dispersion = strdup(w);
907145557Sharti			break;
908145557Sharti
909145557Sharti		  default:
910145557Sharti			abort();
911145557Sharti		}
912145557Sharti		cnt++;
913145557Sharti	}
914145557Sharti	return (cnt);
915145557Sharti}
916145557Sharti
917145557Sharti/*
918145557Sharti * Fetch the complete peer list
919145557Sharti */
920145557Shartistatic int
921145557Shartifetch_peers(void)
922145557Sharti{
923145557Sharti	u_char *data, *pdata, *ptr;
924145557Sharti	size_t datalen, pdatalen;
925145557Sharti	int i;
926145557Sharti	struct peer *p;
927145557Sharti	struct filt *f;
928145557Sharti	uint16_t associd;
929145557Sharti	char *name, *val;
930145557Sharti
931145557Sharti	/* free the old list */
932145557Sharti	while ((p = TAILQ_FIRST(&peers)) != NULL) {
933145557Sharti		TAILQ_REMOVE(&peers, p, link);
934145557Sharti		free(p->rootdelay);
935145557Sharti		free(p->rootdispersion);
936145557Sharti		free(p->refid);
937145557Sharti		free(p->offset);
938145557Sharti		free(p->delay);
939145557Sharti		free(p->dispersion);
940145557Sharti		free(p);
941145557Sharti	}
942145557Sharti	while ((f = TAILQ_FIRST(&filts)) != NULL) {
943145557Sharti		TAILQ_REMOVE(&filts, f, link);
944145557Sharti		free(f->offset);
945145557Sharti		free(f->delay);
946145557Sharti		free(f->dispersion);
947145557Sharti		free(f);
948145557Sharti	}
949145557Sharti
950145557Sharti	/* fetch the list of associations */
951145557Sharti	if (ntpd_dialog(NTPC_OP_READSTAT, 0, NULL, &data, &datalen))
952145557Sharti		return (-1);
953145557Sharti
954145557Sharti	for (i = 0; i < (int)(datalen / 4); i++) {
955145557Sharti		associd  = data[4 * i + 0] << 8;
956145557Sharti		associd |= data[4 * i + 1] << 0;
957145557Sharti
958145557Sharti		/* ask for the association variables */
959145557Sharti		if (ntpd_dialog(NTPC_OP_READVAR, associd,
960145557Sharti		    "config,srcadr,srcport,dstadr,dstport,leap,hmode,stratum,"
961145557Sharti		    "hpoll,ppoll,precision,rootdelay,rootdispersion,refid,"
962145557Sharti		    "reftime,org,rec,xmt,reach,timer,offset,delay,dispersion,"
963145557Sharti		    "filtdelay,filtoffset,filtdisp",
964145557Sharti		    &pdata, &pdatalen)) {
965145557Sharti			free(data);
966145557Sharti			return (-1);
967145557Sharti		}
968145557Sharti
969145557Sharti		/* now save and parse the data */
970145557Sharti		p = malloc(sizeof(*p));
971145557Sharti		if (p == NULL) {
972145557Sharti			free(data);
973145557Sharti			syslog(LOG_ERR, "%m");
974145557Sharti			return (-1);
975145557Sharti		}
976145557Sharti		memset(p, 0, sizeof(*p));
977145557Sharti		p->index = associd;
978145557Sharti		INSERT_OBJECT_INT(p, &peers);
979145557Sharti
980145557Sharti		ptr = pdata;
981145557Sharti		while (ntpd_parse(&ptr, &pdatalen, &name, &val)) {
982145557Sharti			if (ntp_debug & DBG_DUMP_VARS)
983145557Sharti				syslog(LOG_DEBUG, "%s: '%s'='%s'",
984145557Sharti				    __func__, name, val);
985145557Sharti			if (strcmp(name, "config") == 0 ||
986145557Sharti			    strcmp(name, "peer.config") == 0) {
987145557Sharti				val_parse_int32(val, &p->config, 0, 1, 0);
988145557Sharti
989145557Sharti			} else if (strcmp(name, "srcadr") == 0 ||
990145557Sharti			    strcmp(name, "peer.srcadr") == 0) {
991145557Sharti				val_parse_ip(val, p->srcadr);
992145557Sharti
993145557Sharti			} else if (strcmp(name, "srcport") == 0 ||
994145557Sharti			    strcmp(name, "peer.srcport") == 0) {
995145557Sharti				val_parse_uint32(val, &p->srcport,
996145557Sharti				    1, 65535, 0);
997145557Sharti
998145557Sharti			} else if (strcmp(name, "dstadr") == 0 ||
999145557Sharti			    strcmp(name, "peer.dstadr") == 0) {
1000145557Sharti				val_parse_ip(val, p->dstadr);
1001145557Sharti
1002145557Sharti			} else if (strcmp(name, "dstport") == 0 ||
1003145557Sharti			    strcmp(name, "peer.dstport") == 0) {
1004145557Sharti				val_parse_uint32(val, &p->dstport,
1005145557Sharti				    1, 65535, 0);
1006145557Sharti
1007145557Sharti			} else if (strcmp(name, "leap") == 0 ||
1008145557Sharti			    strcmp(name, "peer.leap") == 0) {
1009145557Sharti				val_parse_int32(val, &p->leap, 0, 3, 2);
1010145557Sharti
1011145557Sharti			} else if (strcmp(name, "hmode") == 0 ||
1012145557Sharti			    strcmp(name, "peer.hmode") == 0) {
1013145557Sharti				val_parse_int32(val, &p->hmode, 0, 7, 0);
1014145557Sharti
1015145557Sharti			} else if (strcmp(name, "stratum") == 0 ||
1016145557Sharti			    strcmp(name, "peer.stratum") == 0) {
1017145557Sharti				val_parse_int32(val, &p->stratum, 0, 255, 0);
1018145557Sharti
1019145557Sharti			} else if (strcmp(name, "ppoll") == 0 ||
1020145557Sharti			    strcmp(name, "peer.ppoll") == 0) {
1021145557Sharti				val_parse_int32(val, &p->ppoll,
1022145557Sharti				    INT32_MIN, INT32_MAX, 0);
1023145557Sharti
1024145557Sharti			} else if (strcmp(name, "hpoll") == 0 ||
1025145557Sharti			    strcmp(name, "peer.hpoll") == 0) {
1026145557Sharti				val_parse_int32(val, &p->hpoll,
1027145557Sharti				    INT32_MIN, INT32_MAX, 0);
1028145557Sharti
1029145557Sharti			} else if (strcmp(name, "precision") == 0 ||
1030145557Sharti			    strcmp(name, "peer.precision") == 0) {
1031145557Sharti				val_parse_int32(val, &p->hpoll,
1032145557Sharti				    INT32_MIN, INT32_MAX, 0);
1033145557Sharti
1034145557Sharti			} else if (strcmp(name, "rootdelay") == 0 ||
1035145557Sharti			    strcmp(name, "peer.rootdelay") == 0) {
1036145557Sharti				p->rootdelay = strdup(val);
1037145557Sharti
1038145557Sharti			} else if (strcmp(name, "rootdispersion") == 0 ||
1039145557Sharti			    strcmp(name, "peer.rootdispersion") == 0) {
1040145557Sharti				p->rootdispersion = strdup(val);
1041145557Sharti
1042145557Sharti			} else if (strcmp(name, "refid") == 0 ||
1043145557Sharti			    strcmp(name, "peer.refid") == 0) {
1044145557Sharti				p->refid = strdup(val);
1045145557Sharti
1046145557Sharti			} else if (strcmp(name, "reftime") == 0 ||
1047145557Sharti			    strcmp(name, "sys.reftime") == 0) {
1048145557Sharti				val_parse_ts(val, p->reftime);
1049145557Sharti
1050145557Sharti			} else if (strcmp(name, "org") == 0 ||
1051145557Sharti			    strcmp(name, "sys.org") == 0) {
1052145557Sharti				val_parse_ts(val, p->orgtime);
1053145557Sharti
1054145557Sharti			} else if (strcmp(name, "rec") == 0 ||
1055145557Sharti			    strcmp(name, "sys.rec") == 0) {
1056145557Sharti				val_parse_ts(val, p->rcvtime);
1057145557Sharti
1058145557Sharti			} else if (strcmp(name, "xmt") == 0 ||
1059145557Sharti			    strcmp(name, "sys.xmt") == 0) {
1060145557Sharti				val_parse_ts(val, p->xmttime);
1061145557Sharti
1062145557Sharti			} else if (strcmp(name, "reach") == 0 ||
1063145557Sharti			    strcmp(name, "peer.reach") == 0) {
1064145557Sharti				val_parse_uint32(val, &p->reach,
1065145557Sharti				    0, 65535, 0);
1066145557Sharti
1067145557Sharti			} else if (strcmp(name, "timer") == 0 ||
1068145557Sharti			    strcmp(name, "peer.timer") == 0) {
1069145557Sharti				val_parse_int32(val, &p->timer,
1070145557Sharti				    INT32_MIN, INT32_MAX, 0);
1071145557Sharti
1072145557Sharti			} else if (strcmp(name, "offset") == 0 ||
1073145557Sharti			    strcmp(name, "peer.offset") == 0) {
1074145557Sharti				p->offset = strdup(val);
1075145557Sharti
1076145557Sharti			} else if (strcmp(name, "delay") == 0 ||
1077145557Sharti			    strcmp(name, "peer.delay") == 0) {
1078145557Sharti				p->delay = strdup(val);
1079145557Sharti
1080145557Sharti			} else if (strcmp(name, "dispersion") == 0 ||
1081145557Sharti			    strcmp(name, "peer.dispersion") == 0) {
1082145557Sharti				p->dispersion = strdup(val);
1083145557Sharti
1084145557Sharti			} else if (strcmp(name, "filtdelay") == 0 ||
1085145557Sharti			    strcmp(name, "peer.filtdelay") == 0) {
1086145557Sharti				p->filt_entries = parse_filt(val, associd, 0);
1087145557Sharti
1088145557Sharti			} else if (strcmp(name, "filtoffset") == 0 ||
1089145557Sharti			    strcmp(name, "peer.filtoffset") == 0) {
1090145557Sharti				p->filt_entries = parse_filt(val, associd, 1);
1091145557Sharti
1092145557Sharti			} else if (strcmp(name, "filtdisp") == 0 ||
1093145557Sharti			    strcmp(name, "peer.filtdisp") == 0) {
1094145557Sharti				p->filt_entries = parse_filt(val, associd, 2);
1095145557Sharti			}
1096145557Sharti		}
1097145557Sharti		free(pdata);
1098145557Sharti	}
1099145557Sharti
1100145557Sharti	free(data);
1101145557Sharti	return (0);
1102145557Sharti}
1103145557Sharti
1104145557Sharti/*
1105145557Sharti * System variables - read-only scalars only.
1106145557Sharti */
1107145557Shartiint
1108145557Shartiop_ntpSystem(struct snmp_context *ctx __unused, struct snmp_value *value,
1109145557Sharti    u_int sub, u_int iidx __unused, enum snmp_op op)
1110145557Sharti{
1111145557Sharti	asn_subid_t which = value->var.subs[sub - 1];
1112145557Sharti
1113145557Sharti	switch (op) {
1114145557Sharti
1115145557Sharti	  case SNMP_OP_GETNEXT:
1116145557Sharti		abort();
1117145557Sharti
1118145557Sharti	  case SNMP_OP_GET:
1119145557Sharti		if (this_tick > sysinfo_tick) {
1120145557Sharti			if (fetch_sysinfo() == -1)
1121145557Sharti				return (SNMP_ERR_GENERR);
1122145557Sharti			sysinfo_tick = this_tick;
1123145557Sharti		}
1124145557Sharti
1125145557Sharti		switch (which) {
1126145557Sharti
1127145557Sharti		  case LEAF_ntpSysLeap:
1128145557Sharti			if (!sysb_leap)
1129145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1130145557Sharti			value->v.integer = sys_leap;
1131145557Sharti			break;
1132145557Sharti
1133145557Sharti		  case LEAF_ntpSysStratum:
1134145557Sharti			if (!sysb_stratum)
1135145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1136145557Sharti			value->v.integer = sys_stratum;
1137145557Sharti			break;
1138145557Sharti
1139145557Sharti		  case LEAF_ntpSysPrecision:
1140145557Sharti			if (!sysb_precision)
1141145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1142145557Sharti			value->v.integer = sys_precision;
1143145557Sharti			break;
1144145557Sharti
1145145557Sharti		  case LEAF_ntpSysRootDelay:
1146145557Sharti			if (sys_rootdelay == NULL)
1147145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1148145557Sharti			return (string_get(value, sys_rootdelay, -1));
1149145557Sharti
1150145557Sharti		  case LEAF_ntpSysRootDispersion:
1151145557Sharti			if (sys_rootdispersion == NULL)
1152145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1153145557Sharti			return (string_get(value, sys_rootdispersion, -1));
1154145557Sharti
1155145557Sharti		  case LEAF_ntpSysRefId:
1156145557Sharti			if (sys_refid == NULL)
1157145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1158145557Sharti			return (string_get(value, sys_refid, -1));
1159145557Sharti
1160145557Sharti		  case LEAF_ntpSysRefTime:
1161145557Sharti			if (sysb_reftime == 0)
1162145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1163145557Sharti			return (string_get(value, sys_reftime, 8));
1164145557Sharti
1165145557Sharti		  case LEAF_ntpSysPoll:
1166145557Sharti			if (sysb_poll == 0)
1167145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1168145557Sharti			value->v.integer = sys_poll;
1169145557Sharti			break;
1170145557Sharti
1171145557Sharti		  case LEAF_ntpSysPeer:
1172145557Sharti			if (sysb_peer == 0)
1173145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1174145557Sharti			value->v.uint32 = sys_peer;
1175145557Sharti			break;
1176145557Sharti
1177145557Sharti		  case LEAF_ntpSysClock:
1178145557Sharti			if (sysb_clock == 0)
1179145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1180145557Sharti			return (string_get(value, sys_clock, 8));
1181145557Sharti
1182145557Sharti		  case LEAF_ntpSysSystem:
1183145557Sharti			if (sys_system == NULL)
1184145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1185145557Sharti			return (string_get(value, sys_system, -1));
1186145557Sharti
1187145557Sharti		  case LEAF_ntpSysProcessor:
1188145557Sharti			if (sys_processor == NULL)
1189145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1190145557Sharti			return (string_get(value, sys_processor, -1));
1191145557Sharti
1192145557Sharti		  default:
1193145557Sharti			abort();
1194145557Sharti		}
1195145557Sharti		return (SNMP_ERR_NOERROR);
1196145557Sharti
1197145557Sharti	  case SNMP_OP_SET:
1198145557Sharti		return (SNMP_ERR_NOT_WRITEABLE);
1199145557Sharti
1200145557Sharti	  case SNMP_OP_COMMIT:
1201145557Sharti	  case SNMP_OP_ROLLBACK:
1202145557Sharti		abort();
1203145557Sharti	}
1204145557Sharti	abort();
1205145557Sharti}
1206145557Sharti
1207145557Shartiint
1208145557Shartiop_ntpPeersVarTable(struct snmp_context *ctx __unused, struct snmp_value *value,
1209145557Sharti    u_int sub, u_int iidx, enum snmp_op op)
1210145557Sharti{
1211145557Sharti	asn_subid_t which = value->var.subs[sub - 1];
1212145557Sharti	uint32_t peer;
1213145557Sharti	struct peer *t;
1214145557Sharti
1215145557Sharti	if (this_tick > peers_tick) {
1216145557Sharti		if (fetch_peers() == -1)
1217145557Sharti			return (SNMP_ERR_GENERR);
1218145557Sharti		peers_tick = this_tick;
1219145557Sharti	}
1220145557Sharti
1221145557Sharti	switch (op) {
1222145557Sharti
1223145557Sharti	  case SNMP_OP_GETNEXT:
1224145557Sharti		t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1225145557Sharti		if (t == NULL)
1226145557Sharti			return (SNMP_ERR_NOSUCHNAME);
1227145557Sharti		value->var.len = sub + 1;
1228145557Sharti		value->var.subs[sub] = t->index;
1229145557Sharti		break;
1230145557Sharti
1231145557Sharti	  case SNMP_OP_GET:
1232145557Sharti		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1233145557Sharti		if (t == NULL)
1234145557Sharti			return (SNMP_ERR_NOSUCHNAME);
1235145557Sharti		break;
1236145557Sharti
1237145557Sharti	  case SNMP_OP_SET:
1238145557Sharti		if (index_decode(&value->var, sub, iidx, &peer))
1239145557Sharti			return (SNMP_ERR_NO_CREATION);
1240145557Sharti		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1241145557Sharti		if (t != NULL)
1242145557Sharti			return (SNMP_ERR_NOT_WRITEABLE);
1243145557Sharti		return (SNMP_ERR_NO_CREATION);
1244145557Sharti
1245145557Sharti	  case SNMP_OP_COMMIT:
1246145557Sharti	  case SNMP_OP_ROLLBACK:
1247145557Sharti	  default:
1248145557Sharti		abort();
1249145557Sharti	}
1250145557Sharti
1251145557Sharti	/*
1252145557Sharti	 * Come here for GET and COMMIT
1253145557Sharti	 */
1254145557Sharti	switch (which) {
1255145557Sharti
1256145557Sharti	  case LEAF_ntpPeersConfigured:
1257145557Sharti		value->v.integer = t->config;
1258145557Sharti		break;
1259145557Sharti
1260145557Sharti	  case LEAF_ntpPeersPeerAddress:
1261145557Sharti		return (ip_get(value, t->srcadr));
1262145557Sharti
1263145557Sharti	  case LEAF_ntpPeersPeerPort:
1264145557Sharti		value->v.uint32 = t->srcport;
1265145557Sharti		break;
1266145557Sharti
1267145557Sharti	  case LEAF_ntpPeersHostAddress:
1268145557Sharti		return (ip_get(value, t->dstadr));
1269145557Sharti
1270145557Sharti	  case LEAF_ntpPeersHostPort:
1271145557Sharti		value->v.uint32 = t->dstport;
1272145557Sharti		break;
1273145557Sharti
1274145557Sharti	  case LEAF_ntpPeersLeap:
1275145557Sharti		value->v.integer = t->leap;
1276145557Sharti		break;
1277145557Sharti
1278145557Sharti	  case LEAF_ntpPeersMode:
1279145557Sharti		value->v.integer = t->hmode;
1280145557Sharti		break;
1281145557Sharti
1282145557Sharti	  case LEAF_ntpPeersStratum:
1283145557Sharti		value->v.integer = t->stratum;
1284145557Sharti		break;
1285145557Sharti
1286145557Sharti	  case LEAF_ntpPeersPeerPoll:
1287145557Sharti		value->v.integer = t->ppoll;
1288145557Sharti		break;
1289145557Sharti
1290145557Sharti	  case LEAF_ntpPeersHostPoll:
1291145557Sharti		value->v.integer = t->hpoll;
1292145557Sharti		break;
1293145557Sharti
1294145557Sharti	  case LEAF_ntpPeersPrecision:
1295145557Sharti		value->v.integer = t->precision;
1296145557Sharti		break;
1297145557Sharti
1298145557Sharti	  case LEAF_ntpPeersRootDelay:
1299145557Sharti		return (string_get(value, t->rootdelay, -1));
1300145557Sharti
1301145557Sharti	  case LEAF_ntpPeersRootDispersion:
1302145557Sharti		return (string_get(value, t->rootdispersion, -1));
1303145557Sharti
1304145557Sharti	  case LEAF_ntpPeersRefId:
1305145557Sharti		return (string_get(value, t->refid, -1));
1306145557Sharti
1307145557Sharti	  case LEAF_ntpPeersRefTime:
1308145557Sharti		return (string_get(value, t->reftime, 8));
1309145557Sharti
1310145557Sharti	  case LEAF_ntpPeersOrgTime:
1311145557Sharti		return (string_get(value, t->orgtime, 8));
1312145557Sharti
1313145557Sharti	  case LEAF_ntpPeersReceiveTime:
1314145557Sharti		return (string_get(value, t->rcvtime, 8));
1315145557Sharti
1316145557Sharti	  case LEAF_ntpPeersTransmitTime:
1317145557Sharti		return (string_get(value, t->xmttime, 8));
1318145557Sharti
1319145557Sharti	  case LEAF_ntpPeersReach:
1320145557Sharti		value->v.uint32 = t->reach;
1321145557Sharti		break;
1322145557Sharti
1323145557Sharti	  case LEAF_ntpPeersTimer:
1324145557Sharti		value->v.uint32 = t->timer;
1325145557Sharti		break;
1326145557Sharti
1327145557Sharti	  case LEAF_ntpPeersOffset:
1328145557Sharti		return (string_get(value, t->offset, -1));
1329145557Sharti
1330145557Sharti	  case LEAF_ntpPeersDelay:
1331145557Sharti		return (string_get(value, t->delay, -1));
1332145557Sharti
1333145557Sharti	  case LEAF_ntpPeersDispersion:
1334145557Sharti		return (string_get(value, t->dispersion, -1));
1335145557Sharti
1336145557Sharti	  default:
1337145557Sharti		abort();
1338145557Sharti	}
1339145557Sharti	return (SNMP_ERR_NOERROR);
1340145557Sharti}
1341145557Sharti
1342145557Sharti
1343145557Shartiint
1344145557Shartiop_ntpFilterPeersVarTable(struct snmp_context *ctx __unused,
1345145557Sharti    struct snmp_value *value, u_int sub, u_int iidx, enum snmp_op op)
1346145557Sharti{
1347145557Sharti	asn_subid_t which = value->var.subs[sub - 1];
1348145557Sharti	uint32_t peer;
1349145557Sharti	struct peer *t;
1350145557Sharti
1351145557Sharti	if (this_tick > peers_tick) {
1352145557Sharti		if (fetch_peers() == -1)
1353145557Sharti			return (SNMP_ERR_GENERR);
1354145557Sharti		peers_tick = this_tick;
1355145557Sharti	}
1356145557Sharti
1357145557Sharti	switch (op) {
1358145557Sharti
1359145557Sharti	  case SNMP_OP_GETNEXT:
1360145557Sharti		t = NEXT_OBJECT_INT(&peers, &value->var, sub);
1361145557Sharti		if (t == NULL)
1362145557Sharti			return (SNMP_ERR_NOSUCHNAME);
1363145557Sharti		value->var.len = sub + 1;
1364145557Sharti		value->var.subs[sub] = t->index;
1365145557Sharti		break;
1366145557Sharti
1367145557Sharti	  case SNMP_OP_GET:
1368145557Sharti		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1369145557Sharti		if (t == NULL)
1370145557Sharti			return (SNMP_ERR_NOSUCHNAME);
1371145557Sharti		break;
1372145557Sharti
1373145557Sharti	  case SNMP_OP_SET:
1374145557Sharti		if (index_decode(&value->var, sub, iidx, &peer))
1375145557Sharti			return (SNMP_ERR_NO_CREATION);
1376145557Sharti		t = FIND_OBJECT_INT(&peers, &value->var, sub);
1377145557Sharti		if (t != NULL)
1378145557Sharti			return (SNMP_ERR_NOT_WRITEABLE);
1379145557Sharti		return (SNMP_ERR_NO_CREATION);
1380145557Sharti
1381145557Sharti	  case SNMP_OP_COMMIT:
1382145557Sharti	  case SNMP_OP_ROLLBACK:
1383145557Sharti	  default:
1384145557Sharti		abort();
1385145557Sharti	}
1386145557Sharti
1387145557Sharti	/*
1388145557Sharti	 * Come here for GET and COMMIT
1389145557Sharti	 */
1390145557Sharti	switch (which) {
1391145557Sharti
1392145557Sharti	  case LEAF_ntpFilterValidEntries:
1393145557Sharti		value->v.integer = t->filt_entries;
1394145557Sharti		break;
1395145557Sharti
1396145557Sharti	  default:
1397145557Sharti		abort();
1398145557Sharti	}
1399145557Sharti	return (SNMP_ERR_NOERROR);
1400145557Sharti}
1401145557Sharti
1402145557Shartiint
1403145557Shartiop_ntpFilterRegisterTable(struct snmp_context *ctx __unused, struct snmp_value *value __unused,
1404145557Sharti    u_int sub __unused, u_int iidx __unused, enum snmp_op op __unused)
1405145557Sharti{
1406145557Sharti	asn_subid_t which = value->var.subs[sub - 1];
1407145557Sharti	uint32_t peer;
1408145557Sharti	uint32_t filt;
1409145557Sharti	struct filt *t;
1410145557Sharti
1411145557Sharti	if (this_tick > peers_tick) {
1412145557Sharti		if (fetch_peers() == -1)
1413145557Sharti			return (SNMP_ERR_GENERR);
1414145557Sharti		peers_tick = this_tick;
1415145557Sharti	}
1416145557Sharti
1417145557Sharti	switch (op) {
1418145557Sharti
1419145557Sharti	  case SNMP_OP_GETNEXT:
1420145557Sharti		t = NEXT_OBJECT_OID(&filts, &value->var, sub);
1421145557Sharti		if (t == NULL)
1422145557Sharti			return (SNMP_ERR_NOSUCHNAME);
1423145557Sharti		index_append(&value->var, sub, &t->index);
1424145557Sharti		break;
1425145557Sharti
1426145557Sharti	  case SNMP_OP_GET:
1427145557Sharti		t = FIND_OBJECT_OID(&filts, &value->var, sub);
1428145557Sharti		if (t == NULL)
1429145557Sharti			return (SNMP_ERR_NOSUCHNAME);
1430145557Sharti		break;
1431145557Sharti
1432145557Sharti	  case SNMP_OP_SET:
1433145557Sharti		if (index_decode(&value->var, sub, iidx, &peer, &filt))
1434145557Sharti			return (SNMP_ERR_NO_CREATION);
1435145557Sharti		t = FIND_OBJECT_OID(&filts, &value->var, sub);
1436145557Sharti		if (t != NULL)
1437145557Sharti			return (SNMP_ERR_NOT_WRITEABLE);
1438145557Sharti		return (SNMP_ERR_NO_CREATION);
1439145557Sharti
1440145557Sharti	  case SNMP_OP_COMMIT:
1441145557Sharti	  case SNMP_OP_ROLLBACK:
1442145557Sharti	  default:
1443145557Sharti		abort();
1444145557Sharti	}
1445145557Sharti
1446145557Sharti	/*
1447145557Sharti	 * Come here for GET and COMMIT
1448145557Sharti	 */
1449145557Sharti	switch (which) {
1450145557Sharti
1451145557Sharti	  case LEAF_ntpFilterPeersOffset:
1452145557Sharti		return (string_get(value, t->offset, -1));
1453145557Sharti
1454145557Sharti	  case LEAF_ntpFilterPeersDelay:
1455145557Sharti		return (string_get(value, t->delay, -1));
1456145557Sharti
1457145557Sharti	  case LEAF_ntpFilterPeersDispersion:
1458145557Sharti		return (string_get(value, t->dispersion, -1));
1459145557Sharti
1460145557Sharti	  default:
1461145557Sharti		abort();
1462145557Sharti	}
1463145557Sharti	return (SNMP_ERR_NOERROR);
1464145557Sharti}
1465145557Sharti
1466145557Sharti/*
1467145557Sharti * System variables - read-only scalars only.
1468145557Sharti */
1469145557Shartiint
1470145557Shartiop_begemot_ntp(struct snmp_context *ctx __unused, struct snmp_value *value,
1471145557Sharti    u_int sub, u_int iidx __unused, enum snmp_op op)
1472145557Sharti{
1473145557Sharti	asn_subid_t which = value->var.subs[sub - 1];
1474145557Sharti	int ret;
1475145557Sharti
1476145557Sharti	switch (op) {
1477145557Sharti
1478145557Sharti	  case SNMP_OP_GETNEXT:
1479145557Sharti		abort();
1480145557Sharti
1481145557Sharti	  case SNMP_OP_GET:
1482145557Sharti		switch (which) {
1483145557Sharti
1484145557Sharti		  case LEAF_begemotNtpHost:
1485145557Sharti			return (string_get(value, ntp_host, -1));
1486145557Sharti
1487145557Sharti		  case LEAF_begemotNtpPort:
1488145557Sharti			return (string_get(value, ntp_port, -1));
1489145557Sharti
1490145557Sharti		  case LEAF_begemotNtpTimeout:
1491145557Sharti			value->v.uint32 = ntp_timeout;
1492145557Sharti			return (SNMP_ERR_NOERROR);
1493145557Sharti
1494145557Sharti		  case LEAF_begemotNtpDebug:
1495145557Sharti			value->v.uint32 = ntp_debug;
1496145557Sharti			return (SNMP_ERR_NOERROR);
1497145557Sharti
1498145557Sharti		  case LEAF_begemotNtpJitter:
1499145557Sharti			if (this_tick > sysinfo_tick) {
1500145557Sharti				if (fetch_sysinfo() == -1)
1501145557Sharti					return (SNMP_ERR_GENERR);
1502145557Sharti				sysinfo_tick = this_tick;
1503145557Sharti			}
1504145557Sharti			if (!sysb_jitter)
1505145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1506145557Sharti			value->v.counter64 = sys_jitter / 1000 * (1ULL << 32);
1507145557Sharti			return (SNMP_ERR_NOERROR);
1508145557Sharti
1509145557Sharti		  case LEAF_begemotNtpStability:
1510145557Sharti			if (this_tick > sysinfo_tick) {
1511145557Sharti				if (fetch_sysinfo() == -1)
1512145557Sharti					return (SNMP_ERR_GENERR);
1513145557Sharti				sysinfo_tick = this_tick;
1514145557Sharti			}
1515145557Sharti			if (!sysb_stability)
1516145557Sharti				return (SNMP_ERR_NOSUCHNAME);
1517145557Sharti			value->v.counter64 = sys_stability * (1ULL << 32);
1518145557Sharti			return (SNMP_ERR_NOERROR);
1519145557Sharti		}
1520145557Sharti		abort();
1521145557Sharti
1522145557Sharti	  case SNMP_OP_SET:
1523145557Sharti		switch (which) {
1524145557Sharti
1525145557Sharti		  case LEAF_begemotNtpHost:
1526150920Sharti			/* only at initialization */
1527145557Sharti			if (community != COMM_INITIALIZE)
1528145557Sharti				return (SNMP_ERR_NOT_WRITEABLE);
1529145557Sharti
1530145557Sharti			if ((ret = string_save(value, ctx, -1, &ntp_host))
1531145557Sharti			    != SNMP_ERR_NOERROR)
1532145557Sharti				return (ret);
1533145557Sharti			return (SNMP_ERR_NOERROR);
1534145557Sharti
1535145557Sharti		  case LEAF_begemotNtpPort:
1536150920Sharti			/* only at initialization */
1537145557Sharti			if (community != COMM_INITIALIZE)
1538145557Sharti				return (SNMP_ERR_NOT_WRITEABLE);
1539145557Sharti
1540145557Sharti			if ((ret = string_save(value, ctx, -1, &ntp_port))
1541145557Sharti			    != SNMP_ERR_NOERROR)
1542145557Sharti				return (ret);
1543145557Sharti			return (SNMP_ERR_NOERROR);
1544145557Sharti
1545145557Sharti		  case LEAF_begemotNtpTimeout:
1546145557Sharti			ctx->scratch->int1 = ntp_timeout;
1547145557Sharti			if (value->v.uint32 < 1)
1548145557Sharti				return (SNMP_ERR_WRONG_VALUE);
1549145557Sharti			ntp_timeout = value->v.integer;
1550145557Sharti			return (SNMP_ERR_NOERROR);
1551145557Sharti
1552145557Sharti		  case LEAF_begemotNtpDebug:
1553145557Sharti			ctx->scratch->int1 = ntp_debug;
1554145557Sharti			ntp_debug = value->v.integer;
1555145557Sharti			return (SNMP_ERR_NOERROR);
1556145557Sharti		}
1557145557Sharti		abort();
1558145557Sharti
1559145557Sharti	  case SNMP_OP_ROLLBACK:
1560145557Sharti		switch (which) {
1561145557Sharti
1562145557Sharti		  case LEAF_begemotNtpHost:
1563145557Sharti			string_rollback(ctx, &ntp_host);
1564145557Sharti			return (SNMP_ERR_NOERROR);
1565145557Sharti
1566145557Sharti		  case LEAF_begemotNtpPort:
1567145557Sharti			string_rollback(ctx, &ntp_port);
1568145557Sharti			return (SNMP_ERR_NOERROR);
1569145557Sharti
1570145557Sharti		  case LEAF_begemotNtpTimeout:
1571145557Sharti			ntp_timeout = ctx->scratch->int1;
1572145557Sharti			return (SNMP_ERR_NOERROR);
1573145557Sharti
1574145557Sharti		  case LEAF_begemotNtpDebug:
1575145557Sharti			ntp_debug = ctx->scratch->int1;
1576145557Sharti			return (SNMP_ERR_NOERROR);
1577145557Sharti		}
1578145557Sharti		abort();
1579145557Sharti
1580145557Sharti	  case SNMP_OP_COMMIT:
1581145557Sharti		switch (which) {
1582145557Sharti
1583145557Sharti		  case LEAF_begemotNtpHost:
1584145557Sharti			string_commit(ctx);
1585145557Sharti			return (SNMP_ERR_NOERROR);
1586145557Sharti
1587145557Sharti		  case LEAF_begemotNtpPort:
1588145557Sharti			string_commit(ctx);
1589145557Sharti			return (SNMP_ERR_NOERROR);
1590145557Sharti
1591145557Sharti		  case LEAF_begemotNtpTimeout:
1592145557Sharti		  case LEAF_begemotNtpDebug:
1593145557Sharti			return (SNMP_ERR_NOERROR);
1594145557Sharti		}
1595145557Sharti		abort();
1596145557Sharti	}
1597145557Sharti	abort();
1598145557Sharti}
1599