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