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