/contrib/bsnmp/snmp_ntp/snmp_ntp.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 1598 lines · 1191 code · 271 blank · 136 comment · 396 complexity · 6c6089159ef1f604ec4d8caaa26e56f9 MD5 · raw file

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