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