1122405Sharti/* 2122405Sharti * Copyright (c) 2001-2003 3122405Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122405Sharti * All rights reserved. 5122405Sharti * 6122405Sharti * Author: Harti Brandt <harti@freebsd.org> 7122405Sharti * 8122405Sharti * Redistribution of this software and documentation and use in source and 9122405Sharti * binary forms, with or without modification, are permitted provided that 10122405Sharti * the following conditions are met: 11122405Sharti * 12122405Sharti * 1. Redistributions of source code or documentation must retain the above 13122405Sharti * copyright notice, this list of conditions and the following disclaimer. 14122405Sharti * 2. Redistributions in binary form must reproduce the above copyright 15122405Sharti * notice, this list of conditions and the following disclaimer in the 16122405Sharti * documentation and/or other materials provided with the distribution. 17122405Sharti * 18122405Sharti * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 19122405Sharti * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 20122405Sharti * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 21122405Sharti * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 22122405Sharti * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 23122405Sharti * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24122405Sharti * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 25122405Sharti * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 26122405Sharti * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 27122405Sharti * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 28122405Sharti * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29122405Sharti * 30122405Sharti * $FreeBSD$ 31122405Sharti * 32122405Sharti * Netgraph interface for SNMPd. 33122405Sharti */ 34122405Sharti#include <sys/types.h> 35122405Sharti#include <sys/param.h> 36122405Sharti#include <sys/linker.h> 37122405Sharti#include <sys/socket.h> 38122405Sharti#include <sys/syslog.h> 39122405Sharti#include <sys/queue.h> 40122405Sharti#include <sys/sysctl.h> 41122405Sharti#include <stdio.h> 42122405Sharti#include <stdlib.h> 43122405Sharti#include <errno.h> 44122405Sharti#include <unistd.h> 45122405Sharti#include <string.h> 46122405Sharti#include <netgraph.h> 47152268Sharti#include <bsnmp/snmpmod.h> 48122405Sharti#include "snmp_netgraph.h" 49122405Sharti#include "netgraph_tree.h" 50122405Sharti#include "netgraph_oid.h" 51122405Sharti 52122405Sharti/* maximum message size */ 53122405Sharti#define RESBUFSIZ 20000 54122405Sharti 55122405Sharti/* default node name */ 56122405Sharti#define NODENAME "NgSnmpd" 57122405Sharti 58122405Sharti/* my node Id */ 59122405Sharting_ID_t snmp_node; 60122405Shartiu_char *snmp_nodename; 61122405Sharti 62122405Sharti/* the Object Resource registration index */ 63122405Shartistatic u_int reg_index; 64122405Shartistatic const struct asn_oid oid_begemotNg = OIDX_begemotNg; 65122405Sharti 66122405Sharti/* configuration */ 67122405Sharti/* this must be smaller than int32_t because the functions in libnetgraph 68122405Sharti * falsely return an int */ 69122405Shartistatic size_t resbufsiz = RESBUFSIZ; 70122405Shartistatic u_int timeout = 1000; 71122405Shartistatic u_int debug_level; 72122405Sharti 73122405Sharti/* number of microseconds per clock tick */ 74122405Shartistatic struct clockinfo clockinfo; 75122405Sharti 76122405Sharti/* Csock buffers. Communication on the csock is asynchronuous. This means 77122405Sharti * if we wait for a specific response, we may get other messages. Put these 78122405Sharti * into a queue and execute them when we are idle. */ 79122405Shartistruct csock_buf { 80122405Sharti STAILQ_ENTRY(csock_buf) link; 81122405Sharti struct ng_mesg *mesg; 82122758Sharti char path[NG_PATHSIZ]; 83122405Sharti}; 84122405Shartistatic STAILQ_HEAD(, csock_buf) csock_bufs = 85122405Sharti STAILQ_HEAD_INITIALIZER(csock_bufs); 86122405Sharti 87122405Sharti/* 88122405Sharti * We dispatch unsolicieted messages by node cookies and ids. 89122405Sharti * So we must keep a list of hook names and dispatch functions. 90122405Sharti */ 91122405Shartistruct msgreg { 92122405Sharti u_int32_t cookie; 93122405Sharti ng_ID_t id; 94122405Sharti ng_cookie_f *func; 95122405Sharti void *arg; 96122405Sharti const struct lmodule *mod; 97122405Sharti SLIST_ENTRY(msgreg) link; 98122405Sharti}; 99122405Shartistatic SLIST_HEAD(, msgreg) msgreg_list = 100122405Sharti SLIST_HEAD_INITIALIZER(msgreg_list); 101122405Sharti 102122405Sharti/* 103122405Sharti * Data messages are dispatched by hook names. 104122405Sharti */ 105122405Shartistruct datareg { 106122758Sharti char hook[NG_HOOKSIZ]; 107122405Sharti ng_hook_f *func; 108122405Sharti void *arg; 109122405Sharti const struct lmodule *mod; 110122405Sharti SLIST_ENTRY(datareg) link; 111122405Sharti}; 112122405Shartistatic SLIST_HEAD(, datareg) datareg_list = 113122405Sharti SLIST_HEAD_INITIALIZER(datareg_list); 114122405Sharti 115122405Sharti/* the netgraph sockets */ 116122405Shartistatic int csock, dsock; 117122405Shartistatic void *csock_fd, *dsock_fd; 118122405Sharti 119122405Sharti/* our module handle */ 120122405Shartistatic struct lmodule *module; 121122405Sharti 122122405Sharti/* statistics */ 123122405Shartistatic u_int32_t stats[LEAF_begemotNgTooLargeDatas+1]; 124122405Sharti 125122405Sharti/* netgraph type list */ 126122405Shartistruct ngtype { 127122758Sharti char name[NG_TYPESIZ]; 128122405Sharti struct asn_oid index; 129122405Sharti TAILQ_ENTRY(ngtype) link; 130122405Sharti}; 131122405ShartiTAILQ_HEAD(ngtype_list, ngtype); 132122405Sharti 133122405Shartistatic struct ngtype_list ngtype_list; 134146529Shartistatic uint64_t ngtype_tick; 135122405Sharti 136122405Sharti 137122405Sharti/* 138122405Sharti * Register a function to receive unsolicited messages 139122405Sharti */ 140122405Shartivoid * 141122405Sharting_register_cookie(const struct lmodule *mod, u_int32_t cookie, ng_ID_t id, 142122405Sharti ng_cookie_f *func, void *arg) 143122405Sharti{ 144122405Sharti struct msgreg *d; 145122405Sharti 146122405Sharti if ((d = malloc(sizeof(*d))) == NULL) 147122405Sharti return (NULL); 148122405Sharti 149122405Sharti d->cookie = cookie; 150122405Sharti d->id = id; 151122405Sharti d->func = func; 152122405Sharti d->arg = arg; 153122405Sharti d->mod = mod; 154122405Sharti 155122405Sharti SLIST_INSERT_HEAD(&msgreg_list, d, link); 156122405Sharti 157122405Sharti return (d); 158122405Sharti} 159122405Sharti 160122405Sharti/* 161122405Sharti * Remove a registration. 162122405Sharti */ 163122405Shartivoid 164122405Sharting_unregister_cookie(void *dd) 165122405Sharti{ 166122405Sharti struct msgreg *d = dd; 167122405Sharti 168122405Sharti SLIST_REMOVE(&msgreg_list, d, msgreg, link); 169122405Sharti free(d); 170122405Sharti} 171122405Sharti 172122405Sharti/* 173122405Sharti * Register a function for hook data. 174122405Sharti */ 175122405Shartivoid * 176122405Sharting_register_hook(const struct lmodule *mod, const char *hook, 177122405Sharti ng_hook_f *func, void *arg) 178122405Sharti{ 179122405Sharti struct datareg *d; 180122405Sharti 181122405Sharti if ((d = malloc(sizeof(*d))) == NULL) 182122405Sharti return (NULL); 183122405Sharti 184122405Sharti strcpy(d->hook, hook); 185122405Sharti d->func = func; 186122405Sharti d->arg = arg; 187122405Sharti d->mod = mod; 188122405Sharti 189122405Sharti SLIST_INSERT_HEAD(&datareg_list, d, link); 190122405Sharti 191122405Sharti return (d); 192122405Sharti} 193122405Sharti 194122405Sharti/* 195122405Sharti * Unregister a hook function 196122405Sharti */ 197122405Shartivoid 198122405Sharting_unregister_hook(void *dd) 199122405Sharti{ 200122405Sharti struct datareg *d = dd; 201122405Sharti 202122405Sharti SLIST_REMOVE(&datareg_list, d, datareg, link); 203122405Sharti free(d); 204122405Sharti} 205122405Sharti 206122405Sharti/* 207122405Sharti * Unregister all hooks and cookies for that module. Note: doesn't disconnect 208122405Sharti * any hooks! 209122405Sharti */ 210122405Shartivoid 211122405Sharting_unregister_module(const struct lmodule *mod) 212122405Sharti{ 213122405Sharti struct msgreg *m, *m1; 214122405Sharti struct datareg *d, *d1; 215122405Sharti 216122405Sharti m = SLIST_FIRST(&msgreg_list); 217122405Sharti while (m != NULL) { 218122405Sharti m1 = SLIST_NEXT(m, link); 219122405Sharti if (m->mod == mod) { 220122405Sharti SLIST_REMOVE(&msgreg_list, m, msgreg, link); 221122405Sharti free(m); 222122405Sharti } 223122405Sharti m = m1; 224122405Sharti } 225122405Sharti 226122405Sharti d = SLIST_FIRST(&datareg_list); 227122405Sharti while (d != NULL) { 228122405Sharti d1 = SLIST_NEXT(d, link); 229122405Sharti if (d->mod == mod) { 230122405Sharti SLIST_REMOVE(&datareg_list, d, datareg, link); 231122405Sharti free(d); 232122405Sharti } 233122405Sharti d = d1; 234122405Sharti } 235122405Sharti} 236122405Sharti 237122405Sharti/* 238122405Sharti * Dispatch a message to the correct module and delete it. More than one 239122405Sharti * module can get a message. 240122405Sharti */ 241122405Shartistatic void 242122405Sharticsock_handle(struct ng_mesg *mesg, const char *path) 243122405Sharti{ 244122405Sharti struct msgreg *d, *d1; 245122405Sharti u_int id; 246122405Sharti int len; 247122405Sharti 248122405Sharti if (sscanf(path, "[%x]:%n", &id, &len) != 1 || 249122405Sharti (u_int)len != strlen(path)) { 250122405Sharti syslog(LOG_ERR, "cannot parse message path '%s'", path); 251122405Sharti id = 0; 252122405Sharti } 253122405Sharti 254122405Sharti d = SLIST_FIRST(&msgreg_list); 255122405Sharti while (d != NULL) { 256122405Sharti d1 = SLIST_NEXT(d, link); 257122405Sharti if (d->cookie == mesg->header.typecookie && 258122405Sharti (d->id == 0 || d->id == id || id == 0)) 259122405Sharti (*d->func)(mesg, path, id, d->arg); 260122405Sharti d = d1; 261122405Sharti } 262122405Sharti free(mesg); 263122405Sharti} 264122405Sharti 265122405Sharti/* 266122405Sharti * Input from the control socket. 267122405Sharti */ 268122405Shartistatic struct ng_mesg * 269122405Sharticsock_read(char *path) 270122405Sharti{ 271122405Sharti struct ng_mesg *mesg; 272122405Sharti int ret, err; 273122405Sharti 274122405Sharti if ((mesg = malloc(resbufsiz + 1)) == NULL) { 275122405Sharti stats[LEAF_begemotNgNoMems]++; 276122405Sharti syslog(LOG_CRIT, "out of memory"); 277122405Sharti errno = ENOMEM; 278122405Sharti return (NULL); 279122405Sharti } 280122405Sharti if ((ret = NgRecvMsg(csock, mesg, resbufsiz + 1, path)) < 0) { 281122405Sharti err = errno; 282122405Sharti free(mesg); 283122405Sharti if (errno == EWOULDBLOCK) { 284122405Sharti errno = err; 285122405Sharti return (NULL); 286122405Sharti } 287122405Sharti stats[LEAF_begemotNgMsgReadErrs]++; 288122405Sharti syslog(LOG_WARNING, "read from csock: %m"); 289122405Sharti errno = err; 290122405Sharti return (NULL); 291122405Sharti } 292122405Sharti if (ret == 0) { 293122405Sharti syslog(LOG_DEBUG, "node closed -- exiting"); 294122405Sharti exit(0); 295122405Sharti } 296122405Sharti if ((size_t)ret > resbufsiz) { 297122405Sharti stats[LEAF_begemotNgTooLargeMsgs]++; 298122405Sharti syslog(LOG_WARNING, "ng message too large"); 299122405Sharti free(mesg); 300122405Sharti errno = EFBIG; 301122405Sharti return (NULL); 302122405Sharti } 303122405Sharti return (mesg); 304122405Sharti} 305122405Sharti 306122405Shartistatic void 307122405Sharticsock_input(int fd __unused, void *udata __unused) 308122405Sharti{ 309122405Sharti struct ng_mesg *mesg; 310122758Sharti char path[NG_PATHSIZ]; 311122405Sharti 312122405Sharti if ((mesg = csock_read(path)) == NULL) 313122405Sharti return; 314122405Sharti 315122405Sharti csock_handle(mesg, path); 316122405Sharti} 317122405Sharti 318122405Sharti/* 319122405Sharti * Write a message to a node. 320122405Sharti */ 321122405Shartiint 322122405Sharting_output(const char *path, u_int cookie, u_int opcode, 323122405Sharti const void *arg, size_t arglen) 324122405Sharti{ 325122405Sharti return (NgSendMsg(csock, path, (int)cookie, (int)opcode, arg, arglen)); 326122405Sharti} 327122405Shartiint 328122405Sharting_output_node(const char *node, u_int cookie, u_int opcode, 329122405Sharti const void *arg, size_t arglen) 330122405Sharti{ 331122758Sharti char path[NG_PATHSIZ]; 332122405Sharti 333122405Sharti sprintf(path, "%s:", node); 334122405Sharti return (ng_output(path, cookie, opcode, arg, arglen)); 335122405Sharti} 336122405Shartiint 337122405Sharting_output_id(ng_ID_t node, u_int cookie, u_int opcode, 338122405Sharti const void *arg, size_t arglen) 339122405Sharti{ 340122758Sharti char path[NG_PATHSIZ]; 341122405Sharti 342122405Sharti sprintf(path, "[%x]:", node); 343122405Sharti return (ng_output(path, cookie, opcode, arg, arglen)); 344122405Sharti} 345122405Sharti 346122405Sharti 347122405Sharti 348122405Sharti/* 349122405Sharti * Execute a synchronuous dialog with the csock. All message we receive, that 350122405Sharti * do not match our request, are queue until the next call to the IDLE function. 351122405Sharti */ 352122405Shartistruct ng_mesg * 353122405Sharting_dialog(const char *path, u_int cookie, u_int opcode, 354122405Sharti const void *arg, size_t arglen) 355122405Sharti{ 356122405Sharti int token, err; 357122405Sharti struct ng_mesg *mesg; 358122758Sharti char rpath[NG_PATHSIZ]; 359122405Sharti struct csock_buf *b; 360122405Sharti struct timeval end, tv; 361122405Sharti 362122405Sharti if ((token = ng_output(path, cookie, opcode, arg, arglen)) < 0) 363122405Sharti return (NULL); 364122405Sharti 365122405Sharti if (csock_fd) 366122405Sharti fd_suspend(csock_fd); 367122405Sharti 368122405Sharti gettimeofday(&end, NULL); 369122405Sharti tv.tv_sec = timeout / 1000; 370122405Sharti tv.tv_usec = (timeout % 1000) * 1000; 371122405Sharti timeradd(&end, &tv, &end); 372122405Sharti for (;;) { 373122405Sharti mesg = NULL; 374122405Sharti gettimeofday(&tv, NULL); 375122405Sharti if (timercmp(&tv, &end, >=)) { 376122405Sharti block: 377122405Sharti syslog(LOG_WARNING, "no response for request %u/%u", 378122405Sharti cookie, opcode); 379122405Sharti errno = EWOULDBLOCK; 380122405Sharti break; 381122405Sharti } 382122405Sharti timersub(&end, &tv, &tv); 383122405Sharti if (tv.tv_sec == 0 && tv.tv_usec < clockinfo.tick) 384122405Sharti goto block; 385122405Sharti 386122405Sharti if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) 387122405Sharti syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO): %m"); 388122405Sharti if ((mesg = csock_read(rpath)) == NULL) { 389122405Sharti if (errno == EWOULDBLOCK) 390122405Sharti continue; 391122405Sharti break; 392122405Sharti } 393122405Sharti if (mesg->header.token == (u_int)token) 394122405Sharti break; 395122405Sharti if ((b = malloc(sizeof(*b))) == NULL) { 396122405Sharti stats[LEAF_begemotNgNoMems]++; 397122405Sharti syslog(LOG_ERR, "out of memory"); 398122405Sharti free(mesg); 399122405Sharti continue; 400122405Sharti } 401122405Sharti b->mesg = mesg; 402122405Sharti strcpy(b->path, rpath); 403122405Sharti STAILQ_INSERT_TAIL(&csock_bufs, b, link); 404122405Sharti } 405122405Sharti 406122405Sharti tv.tv_sec = 0; 407122405Sharti tv.tv_usec = 0; 408122405Sharti if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) 409122405Sharti syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO,0): %m"); 410122405Sharti 411122405Sharti if (csock_fd) { 412122405Sharti err = errno; 413122405Sharti fd_resume(csock_fd); 414122405Sharti errno = err; 415122405Sharti } 416122405Sharti 417122405Sharti return (mesg); 418122405Sharti} 419122405Shartistruct ng_mesg * 420122405Sharting_dialog_node(const char *node, u_int cookie, u_int opcode, 421122405Sharti const void *arg, size_t arglen) 422122405Sharti{ 423122758Sharti char path[NG_PATHSIZ]; 424122405Sharti 425122405Sharti sprintf(path, "%s:", node); 426122405Sharti return (ng_dialog(path, cookie, opcode, arg, arglen)); 427122405Sharti} 428122405Shartistruct ng_mesg * 429122405Sharting_dialog_id(ng_ID_t id, u_int cookie, u_int opcode, 430122405Sharti const void *arg, size_t arglen) 431122405Sharti{ 432122758Sharti char path[NG_PATHSIZ]; 433122405Sharti 434122405Sharti sprintf(path, "[%x]:", id); 435122405Sharti return (ng_dialog(path, cookie, opcode, arg, arglen)); 436122405Sharti} 437122405Sharti 438122405Sharti 439122405Sharti/* 440122405Sharti * Send a data message to a given hook. 441122405Sharti */ 442122405Shartiint 443122405Sharting_send_data(const char *hook, const void *sndbuf, size_t sndlen) 444122405Sharti{ 445122405Sharti return (NgSendData(dsock, hook, sndbuf, sndlen)); 446122405Sharti} 447122405Sharti 448122405Sharti/* 449122405Sharti * Input from a data socket. Dispatch to the function for that hook. 450122405Sharti */ 451122405Shartistatic void 452122405Shartidsock_input(int fd __unused, void *udata __unused) 453122405Sharti{ 454122405Sharti u_char *resbuf, embuf[100]; 455122405Sharti ssize_t len; 456122758Sharti char hook[NG_HOOKSIZ]; 457122405Sharti struct datareg *d, *d1; 458122405Sharti 459122405Sharti if ((resbuf = malloc(resbufsiz + 1)) == NULL) { 460122405Sharti stats[LEAF_begemotNgNoMems]++; 461122405Sharti syslog(LOG_CRIT, "out of memory"); 462122405Sharti (void)NgRecvData(fd, embuf, sizeof(embuf), hook); 463122405Sharti errno = ENOMEM; 464122405Sharti return; 465122405Sharti } 466122405Sharti if ((len = NgRecvData(fd, resbuf, resbufsiz + 1, hook)) == -1) { 467122405Sharti stats[LEAF_begemotNgDataReadErrs]++; 468122405Sharti syslog(LOG_ERR, "reading message: %m"); 469122405Sharti free(resbuf); 470122405Sharti return; 471122405Sharti } 472122405Sharti if (len == 0) { 473122405Sharti free(resbuf); 474122405Sharti return; 475122405Sharti } 476122405Sharti if ((size_t)len == resbufsiz + 1) { 477122405Sharti stats[LEAF_begemotNgTooLargeDatas]++; 478122405Sharti syslog(LOG_WARNING, "message too long"); 479122405Sharti free(resbuf); 480122405Sharti return; 481122405Sharti } 482122405Sharti 483122405Sharti /* 484122405Sharti * Dispatch message. Maybe dispatched to more than one function. 485122405Sharti */ 486122405Sharti d = SLIST_FIRST(&datareg_list); 487122405Sharti while (d != NULL) { 488122405Sharti d1 = SLIST_NEXT(d, link); 489122405Sharti if (strcmp(hook, d->hook) == 0) 490122405Sharti (*d->func)(hook, resbuf, len, d->arg); 491122405Sharti d = d1; 492122405Sharti } 493122405Sharti 494122405Sharti free(resbuf); 495122405Sharti} 496122405Sharti 497122405Sharti/* 498122405Sharti * The SNMP daemon is about to wait for an event. Look whether we have 499122405Sharti * netgraph messages waiting. If yes, drain the queue. 500122405Sharti */ 501122405Shartistatic void 502122405Sharting_idle(void) 503122405Sharti{ 504122405Sharti struct csock_buf *b; 505122405Sharti 506122405Sharti /* execute waiting csock_bufs */ 507122405Sharti while ((b = STAILQ_FIRST(&csock_bufs)) != NULL) { 508122405Sharti STAILQ_REMOVE_HEAD(&csock_bufs, link); 509122405Sharti csock_handle(b->mesg, b->path); 510122405Sharti free(b); 511122405Sharti } 512122405Sharti} 513122405Sharti 514122405Sharti/* 515122405Sharti * Called when the module is loaded. Returning a non-zero value means, 516122405Sharti * rejecting the initialisation. 517122405Sharti * 518122405Sharti * We make the netgraph socket. 519122405Sharti */ 520122405Shartistatic int 521122405Sharting_init(struct lmodule *mod, int argc, char *argv[]) 522122405Sharti{ 523122405Sharti int name[2]; 524122405Sharti size_t len; 525122405Sharti 526122405Sharti module = mod; 527122405Sharti 528122405Sharti if (argc == 0) { 529122405Sharti if ((snmp_nodename = malloc(strlen(NODENAME) + 1)) == NULL) 530122405Sharti return (ENOMEM); 531122405Sharti strcpy(snmp_nodename, NODENAME); 532122405Sharti } else { 533122758Sharti if ((snmp_nodename = malloc(NG_NODESIZ)) == NULL) 534122405Sharti return (ENOMEM); 535122758Sharti strlcpy(snmp_nodename, argv[0], NG_NODESIZ); 536122405Sharti } 537122405Sharti 538122405Sharti /* fetch clockinfo (for the number of microseconds per tick) */ 539122405Sharti name[0] = CTL_KERN; 540122405Sharti name[1] = KERN_CLOCKRATE; 541122405Sharti len = sizeof(clockinfo); 542122405Sharti if (sysctl(name, 2, &clockinfo, &len, NULL, 0) == -1) 543122405Sharti return (errno); 544122405Sharti 545122405Sharti TAILQ_INIT(&ngtype_list); 546122405Sharti 547122405Sharti return (0); 548122405Sharti} 549122405Sharti 550122405Sharti/* 551122405Sharti * Get the node Id/name/type of a node. 552122405Sharti */ 553122405Sharting_ID_t 554122405Sharting_node_id(const char *path) 555122405Sharti{ 556122405Sharti struct ng_mesg *resp; 557122405Sharti ng_ID_t id; 558122405Sharti 559122405Sharti if ((resp = ng_dialog(path, NGM_GENERIC_COOKIE, NGM_NODEINFO, 560122405Sharti NULL, 0)) == NULL) 561122405Sharti return (0); 562122405Sharti id = ((struct nodeinfo *)(void *)resp->data)->id; 563122405Sharti free(resp); 564122405Sharti return (id); 565122405Sharti} 566122405Sharting_ID_t 567122405Sharting_node_id_node(const char *node) 568122405Sharti{ 569122405Sharti struct ng_mesg *resp; 570122405Sharti ng_ID_t id; 571122405Sharti 572122405Sharti if ((resp = ng_dialog_node(node, NGM_GENERIC_COOKIE, NGM_NODEINFO, 573122405Sharti NULL, 0)) == NULL) 574122405Sharti return (0); 575122405Sharti id = ((struct nodeinfo *)(void *)resp->data)->id; 576122405Sharti free(resp); 577122405Sharti return (id); 578122405Sharti} 579122405Sharting_ID_t 580122405Sharting_node_name(ng_ID_t id, char *name) 581122405Sharti{ 582122405Sharti struct ng_mesg *resp; 583122405Sharti 584122405Sharti if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO, 585122405Sharti NULL, 0)) == NULL) 586122405Sharti return (0); 587122405Sharti strcpy(name, ((struct nodeinfo *)(void *)resp->data)->name); 588122405Sharti free(resp); 589122405Sharti return (id); 590122405Sharti 591122405Sharti} 592122405Sharting_ID_t 593122405Sharting_node_type(ng_ID_t id, char *type) 594122405Sharti{ 595122405Sharti struct ng_mesg *resp; 596122405Sharti 597122405Sharti if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO, 598122405Sharti NULL, 0)) == NULL) 599122405Sharti return (0); 600122405Sharti strcpy(type, ((struct nodeinfo *)(void *)resp->data)->type); 601122405Sharti free(resp); 602122405Sharti return (id); 603122405Sharti} 604122405Sharti 605122405Sharti/* 606122405Sharti * Connect our node to some other node 607122405Sharti */ 608122405Shartiint 609122405Sharting_connect_node(const char *node, const char *ourhook, const char *peerhook) 610122405Sharti{ 611122405Sharti struct ngm_connect conn; 612122405Sharti 613122758Sharti snprintf(conn.path, NG_PATHSIZ, "%s:", node); 614122758Sharti strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ); 615122758Sharti strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 616122405Sharti return (NgSendMsg(csock, ".:", 617122405Sharti NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 618122405Sharti} 619122405Shartiint 620122405Sharting_connect_id(ng_ID_t id, const char *ourhook, const char *peerhook) 621122405Sharti{ 622122405Sharti struct ngm_connect conn; 623122405Sharti 624122758Sharti snprintf(conn.path, NG_PATHSIZ, "[%x]:", id); 625122758Sharti strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ); 626122758Sharti strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 627122405Sharti return (NgSendMsg(csock, ".:", 628122405Sharti NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 629122405Sharti} 630122405Sharti 631122405Shartiint 632122405Sharting_connect2_id(ng_ID_t id, ng_ID_t peer, const char *ourhook, 633122405Sharti const char *peerhook) 634122405Sharti{ 635122405Sharti struct ngm_connect conn; 636122758Sharti char path[NG_PATHSIZ]; 637122405Sharti 638122758Sharti snprintf(path, NG_PATHSIZ, "[%x]:", id); 639122405Sharti 640122758Sharti snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer); 641122758Sharti strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ); 642122758Sharti strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 643122405Sharti return (NgSendMsg(csock, path, 644122405Sharti NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 645122405Sharti} 646122405Sharti 647122405Shartiint 648122405Sharting_connect2_tee_id(ng_ID_t id, ng_ID_t peer, const char *ourhook, 649122405Sharti const char *peerhook) 650122405Sharti{ 651122405Sharti struct ngm_connect conn; 652122758Sharti char path[NG_PATHSIZ]; 653122405Sharti ng_ID_t tee; 654122405Sharti 655122405Sharti if ((tee = ng_mkpeer_id(id, NULL, "tee", ourhook, "left")) == 0) 656122405Sharti return (-1); 657122405Sharti 658122758Sharti snprintf(path, NG_PATHSIZ, "[%x]:", tee); 659122405Sharti 660122758Sharti snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer); 661122758Sharti strlcpy(conn.ourhook, "right", NG_HOOKSIZ); 662122758Sharti strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 663122405Sharti return (NgSendMsg(csock, path, 664122405Sharti NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 665122405Sharti} 666122405Sharti 667122405Sharti/* 668122405Sharti * Ensure that a node of type 'type' is connected to 'hook' of 'node' 669122405Sharti * and return its node id. tee nodes between node and the target node 670122405Sharti * are skipped. If the type is wrong, or the hook is a dead-end return 0. 671122405Sharti * If type is NULL, it is not checked. 672122405Sharti */ 673122405Shartistatic ng_ID_t 674122405Sharting_next_node_id_internal(ng_ID_t node, const char *type, const char *hook, 675122405Sharti int skip_tee) 676122405Sharti{ 677122405Sharti struct ng_mesg *resp; 678122405Sharti struct hooklist *hooklist; 679122405Sharti u_int i; 680122405Sharti 681122405Sharti if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 682122405Sharti NULL, 0)) == NULL) { 683122405Sharti syslog(LOG_ERR, "get hook list: %m"); 684122405Sharti exit(1); 685122405Sharti } 686122405Sharti hooklist = (struct hooklist *)(void *)resp->data; 687122405Sharti 688122405Sharti for (i = 0; i < hooklist->nodeinfo.hooks; i++) 689122405Sharti if (strcmp(hooklist->link[i].ourhook, hook) == 0) 690122405Sharti break; 691122405Sharti 692122405Sharti if (i == hooklist->nodeinfo.hooks) { 693122405Sharti free(resp); 694122405Sharti return (0); 695122405Sharti } 696122405Sharti 697122405Sharti node = hooklist->link[i].nodeinfo.id; 698122405Sharti 699122405Sharti if (skip_tee && strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) { 700122405Sharti if (strcmp(hooklist->link[i].peerhook, "left") == 0) 701122405Sharti node = ng_next_node_id(node, type, "right"); 702122405Sharti else if (strcmp(hooklist->link[i].peerhook, "right") == 0) 703122405Sharti node = ng_next_node_id(node, type, "left"); 704122405Sharti else if (type != NULL && 705122405Sharti strcmp(hooklist->link[i].nodeinfo.type, type) != 0) 706122405Sharti node = 0; 707122405Sharti 708122405Sharti } else if (type != NULL && 709122405Sharti strcmp(hooklist->link[i].nodeinfo.type, type) != 0) 710122405Sharti node = 0; 711122405Sharti 712122405Sharti free(resp); 713122405Sharti 714122405Sharti return (node); 715122405Sharti} 716122405Sharti 717122405Sharti/* 718122405Sharti * Ensure that a node of type 'type' is connected to 'hook' of 'node' 719122405Sharti * and return its node id. tee nodes between node and the target node 720122405Sharti * are skipped. If the type is wrong, or the hook is a dead-end return 0. 721122405Sharti * If type is NULL, it is not checked. 722122405Sharti */ 723122405Sharting_ID_t 724122405Sharting_next_node_id(ng_ID_t node, const char *type, const char *hook) 725122405Sharti{ 726122405Sharti return (ng_next_node_id_internal(node, type, hook, 1)); 727122405Sharti} 728122405Sharti 729122405Sharting_ID_t 730122405Sharting_mkpeer_id(ng_ID_t id, const char *nodename, const char *type, 731122405Sharti const char *hook, const char *peerhook) 732122405Sharti{ 733122758Sharti char path[NG_PATHSIZ]; 734122405Sharti struct ngm_mkpeer mkpeer; 735122405Sharti struct ngm_name name; 736122405Sharti 737122758Sharti strlcpy(mkpeer.type, type, NG_TYPESIZ); 738122758Sharti strlcpy(mkpeer.ourhook, hook, NG_HOOKSIZ); 739122758Sharti strlcpy(mkpeer.peerhook, peerhook, NG_HOOKSIZ); 740122405Sharti 741122405Sharti sprintf(path, "[%x]:", id); 742122405Sharti if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, 743122405Sharti &mkpeer, sizeof(mkpeer)) == -1) 744122405Sharti return (0); 745122405Sharti 746128235Sharti if ((id = ng_next_node_id_internal(id, NULL, hook, 0)) == 0) 747122405Sharti return (0); 748122405Sharti 749122405Sharti if (nodename != NULL) { 750122405Sharti strcpy(name.name, nodename); 751122405Sharti sprintf(path, "[%x]:", id); 752122405Sharti if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_NAME, 753122405Sharti &name, sizeof(name)) == -1) 754122405Sharti return (0); 755122405Sharti } 756122405Sharti return (id); 757122405Sharti} 758122405Sharti 759122405Sharti/* 760122405Sharti * SHutdown node 761122405Sharti */ 762122405Shartiint 763122405Sharting_shutdown_id(ng_ID_t id) 764122405Sharti{ 765122758Sharti char path[NG_PATHSIZ]; 766122405Sharti 767122758Sharti snprintf(path, NG_PATHSIZ, "[%x]:", id); 768122405Sharti return (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, 769122405Sharti NGM_SHUTDOWN, NULL, 0)); 770122405Sharti} 771122405Sharti 772122405Sharti/* 773122405Sharti * Disconnect one of our hooks 774122405Sharti */ 775122405Shartiint 776122405Sharting_rmhook(const char *ourhook) 777122405Sharti{ 778122405Sharti struct ngm_rmhook rmhook; 779122405Sharti 780122758Sharti strlcpy(rmhook.ourhook, ourhook, NG_HOOKSIZ); 781122405Sharti return (NgSendMsg(csock, ".:", 782122405Sharti NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook))); 783122405Sharti} 784122405Sharti 785122405Sharti/* 786122405Sharti * Disconnect a hook of a node 787122405Sharti */ 788122405Shartiint 789122405Sharting_rmhook_id(ng_ID_t id, const char *hook) 790122405Sharti{ 791122405Sharti struct ngm_rmhook rmhook; 792122758Sharti char path[NG_PATHSIZ]; 793122405Sharti 794122758Sharti strlcpy(rmhook.ourhook, hook, NG_HOOKSIZ); 795122758Sharti snprintf(path, NG_PATHSIZ, "[%x]:", id); 796122405Sharti return (NgSendMsg(csock, path, 797122405Sharti NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook))); 798122405Sharti} 799122405Sharti 800122405Sharti/* 801122405Sharti * Disconnect a hook and shutdown all tee nodes that were connected to that 802122405Sharti * hook. 803122405Sharti */ 804122405Shartiint 805122405Sharting_rmhook_tee_id(ng_ID_t node, const char *hook) 806122405Sharti{ 807122405Sharti struct ng_mesg *resp; 808122405Sharti struct hooklist *hooklist; 809122405Sharti u_int i; 810122405Sharti int first = 1; 811122405Sharti ng_ID_t next_node; 812122405Sharti const char *next_hook; 813122405Sharti 814122405Sharti again: 815122405Sharti /* if we have just shutdown a tee node, which had no other hooks 816122405Sharti * connected, the node id may already be wrong here. */ 817122405Sharti if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 818122405Sharti NULL, 0)) == NULL) 819122405Sharti return (0); 820122405Sharti 821122405Sharti hooklist = (struct hooklist *)(void *)resp->data; 822122405Sharti 823122405Sharti for (i = 0; i < hooklist->nodeinfo.hooks; i++) 824122405Sharti if (strcmp(hooklist->link[i].ourhook, hook) == 0) 825122405Sharti break; 826122405Sharti 827122405Sharti if (i == hooklist->nodeinfo.hooks) { 828122405Sharti free(resp); 829122405Sharti return (0); 830122405Sharti } 831122405Sharti 832122405Sharti next_node = 0; 833122405Sharti next_hook = NULL; 834122405Sharti if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) { 835122405Sharti if (strcmp(hooklist->link[i].peerhook, "left") == 0) { 836122405Sharti next_node = hooklist->link[i].nodeinfo.id; 837122405Sharti next_hook = "right"; 838122405Sharti } else if (strcmp(hooklist->link[i].peerhook, "right") == 0) { 839122405Sharti next_node = hooklist->link[i].nodeinfo.id; 840122405Sharti next_hook = "left"; 841122405Sharti } 842122405Sharti } 843122405Sharti free(resp); 844122405Sharti 845122405Sharti if (first) { 846122405Sharti ng_rmhook_id(node, hook); 847122405Sharti first = 0; 848122405Sharti } else { 849122405Sharti ng_shutdown_id(node); 850122405Sharti } 851122405Sharti if ((node = next_node) == 0) 852122405Sharti return (0); 853122405Sharti hook = next_hook; 854122405Sharti 855122405Sharti goto again; 856122405Sharti} 857122405Sharti 858122405Sharti/* 859122405Sharti * Get the peer hook of a hook on a given node. Skip any tee nodes in between 860122405Sharti */ 861122405Shartiint 862122405Sharting_peer_hook_id(ng_ID_t node, const char *hook, char *peerhook) 863122405Sharti{ 864122405Sharti struct ng_mesg *resp; 865122405Sharti struct hooklist *hooklist; 866122405Sharti u_int i; 867122405Sharti int ret; 868122405Sharti 869122405Sharti if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 870122405Sharti NULL, 0)) == NULL) { 871122405Sharti syslog(LOG_ERR, "get hook list: %m"); 872122405Sharti exit(1); 873122405Sharti } 874122405Sharti hooklist = (struct hooklist *)(void *)resp->data; 875122405Sharti 876122405Sharti for (i = 0; i < hooklist->nodeinfo.hooks; i++) 877122405Sharti if (strcmp(hooklist->link[i].ourhook, hook) == 0) 878122405Sharti break; 879122405Sharti 880122405Sharti if (i == hooklist->nodeinfo.hooks) { 881122405Sharti free(resp); 882122405Sharti return (-1); 883122405Sharti } 884122405Sharti 885122405Sharti node = hooklist->link[i].nodeinfo.id; 886122405Sharti 887122405Sharti ret = 0; 888122405Sharti if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) { 889122405Sharti if (strcmp(hooklist->link[i].peerhook, "left") == 0) 890122405Sharti ret = ng_peer_hook_id(node, "right", peerhook); 891122405Sharti else if (strcmp(hooklist->link[i].peerhook, "right") == 0) 892122405Sharti ret = ng_peer_hook_id(node, "left", peerhook); 893122405Sharti else 894122405Sharti strcpy(peerhook, hooklist->link[i].peerhook); 895122405Sharti 896122405Sharti } else 897122405Sharti strcpy(peerhook, hooklist->link[i].peerhook); 898122405Sharti 899122405Sharti free(resp); 900122405Sharti 901122405Sharti return (ret); 902122405Sharti} 903122405Sharti 904122405Sharti 905122405Sharti/* 906122405Sharti * Now the module is started. Select on the sockets, so that we can get 907122405Sharti * unsolicited input. 908122405Sharti */ 909122405Shartistatic void 910122405Sharting_start(void) 911122405Sharti{ 912122405Sharti if (snmp_node == 0) { 913122405Sharti if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) { 914122405Sharti syslog(LOG_ERR, "NgMkSockNode: %m"); 915122405Sharti exit(1); 916122405Sharti } 917122405Sharti snmp_node = ng_node_id(".:"); 918122405Sharti } 919122405Sharti 920122405Sharti if ((csock_fd = fd_select(csock, csock_input, NULL, module)) == NULL) { 921122405Sharti syslog(LOG_ERR, "fd_select failed on csock: %m"); 922122405Sharti return; 923122405Sharti } 924122405Sharti if ((dsock_fd = fd_select(dsock, dsock_input, NULL, module)) == NULL) { 925122405Sharti syslog(LOG_ERR, "fd_select failed on dsock: %m"); 926122405Sharti return; 927122405Sharti } 928122405Sharti 929122405Sharti reg_index = or_register(&oid_begemotNg, 930122405Sharti "The MIB for the NetGraph access module for SNMP.", module); 931122405Sharti} 932122405Sharti 933122405Sharti/* 934122405Sharti * Called, when the module is to be unloaded after it was successfully loaded 935122405Sharti */ 936122405Shartistatic int 937122405Sharting_fini(void) 938122405Sharti{ 939122405Sharti struct ngtype *t; 940122405Sharti 941122405Sharti while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) { 942122405Sharti TAILQ_REMOVE(&ngtype_list, t, link); 943122405Sharti free(t); 944122405Sharti } 945122405Sharti 946122405Sharti if (csock_fd != NULL) 947122405Sharti fd_deselect(csock_fd); 948122405Sharti (void)close(csock); 949122405Sharti 950122405Sharti if (dsock_fd != NULL) 951122405Sharti fd_deselect(dsock_fd); 952122405Sharti (void)close(dsock); 953122405Sharti 954122405Sharti free(snmp_nodename); 955122405Sharti 956122405Sharti or_unregister(reg_index); 957122405Sharti 958122405Sharti return (0); 959122405Sharti} 960122405Sharti 961122405Sharticonst struct snmp_module config = { 962122405Sharti "This module implements access to the netgraph sub-system", 963122405Sharti ng_init, 964122405Sharti ng_fini, 965122405Sharti ng_idle, 966122405Sharti NULL, 967122405Sharti NULL, 968122405Sharti ng_start, 969122405Sharti NULL, 970122405Sharti netgraph_ctree, 971122405Sharti netgraph_CTREE_SIZE, 972122405Sharti NULL 973122405Sharti}; 974122405Sharti 975122405Shartiint 976122405Shartiop_ng_config(struct snmp_context *ctx, struct snmp_value *value, 977122405Sharti u_int sub, u_int iidx __unused, enum snmp_op op) 978122405Sharti{ 979122405Sharti asn_subid_t which = value->var.subs[sub - 1]; 980122405Sharti int ret; 981122405Sharti 982122405Sharti switch (op) { 983122405Sharti 984122405Sharti case SNMP_OP_GETNEXT: 985122405Sharti abort(); 986122405Sharti 987122405Sharti case SNMP_OP_GET: 988122405Sharti /* 989122405Sharti * Come here for GET, GETNEXT and COMMIT 990122405Sharti */ 991122405Sharti switch (which) { 992122405Sharti 993122405Sharti case LEAF_begemotNgControlNodeName: 994122405Sharti return (string_get(value, snmp_nodename, -1)); 995122405Sharti 996122405Sharti case LEAF_begemotNgResBufSiz: 997122405Sharti value->v.integer = resbufsiz; 998122405Sharti break; 999122405Sharti 1000122405Sharti case LEAF_begemotNgTimeout: 1001122405Sharti value->v.integer = timeout; 1002122405Sharti break; 1003122405Sharti 1004122405Sharti case LEAF_begemotNgDebugLevel: 1005122405Sharti value->v.uint32 = debug_level; 1006122405Sharti break; 1007122405Sharti 1008122405Sharti default: 1009122405Sharti abort(); 1010122405Sharti } 1011122405Sharti return (SNMP_ERR_NOERROR); 1012122405Sharti 1013122405Sharti case SNMP_OP_SET: 1014122405Sharti switch (which) { 1015122405Sharti 1016122405Sharti case LEAF_begemotNgControlNodeName: 1017122405Sharti /* only at initialisation */ 1018122405Sharti if (community != COMM_INITIALIZE) 1019122405Sharti return (SNMP_ERR_NOT_WRITEABLE); 1020122405Sharti 1021122405Sharti if (snmp_node != 0) 1022122405Sharti return (SNMP_ERR_NOT_WRITEABLE); 1023122405Sharti 1024122405Sharti if ((ret = string_save(value, ctx, -1, &snmp_nodename)) 1025122405Sharti != SNMP_ERR_NOERROR) 1026122405Sharti return (ret); 1027122405Sharti 1028122405Sharti if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) { 1029122405Sharti syslog(LOG_ERR, "NgMkSockNode: %m"); 1030122405Sharti string_rollback(ctx, &snmp_nodename); 1031122405Sharti return (SNMP_ERR_GENERR); 1032122405Sharti } 1033122405Sharti snmp_node = ng_node_id(".:"); 1034122405Sharti 1035122405Sharti return (SNMP_ERR_NOERROR); 1036122405Sharti 1037122405Sharti case LEAF_begemotNgResBufSiz: 1038122405Sharti ctx->scratch->int1 = resbufsiz; 1039122405Sharti if (value->v.integer < 1024 || 1040122405Sharti value->v.integer > 0x10000) 1041122405Sharti return (SNMP_ERR_WRONG_VALUE); 1042122405Sharti resbufsiz = value->v.integer; 1043122405Sharti return (SNMP_ERR_NOERROR); 1044122405Sharti 1045122405Sharti case LEAF_begemotNgTimeout: 1046122405Sharti ctx->scratch->int1 = timeout; 1047122405Sharti if (value->v.integer < 10 || 1048122405Sharti value->v.integer > 10000) 1049122405Sharti return (SNMP_ERR_WRONG_VALUE); 1050122405Sharti timeout = value->v.integer; 1051122405Sharti return (SNMP_ERR_NOERROR); 1052122405Sharti 1053122405Sharti case LEAF_begemotNgDebugLevel: 1054122405Sharti ctx->scratch->int1 = debug_level; 1055122405Sharti debug_level = value->v.uint32; 1056122405Sharti NgSetDebug(debug_level); 1057122405Sharti return (SNMP_ERR_NOERROR); 1058122405Sharti } 1059122405Sharti abort(); 1060122405Sharti 1061122405Sharti case SNMP_OP_ROLLBACK: 1062122405Sharti switch (which) { 1063122405Sharti 1064122405Sharti case LEAF_begemotNgControlNodeName: 1065122405Sharti string_rollback(ctx, &snmp_nodename); 1066122405Sharti close(csock); 1067122405Sharti close(dsock); 1068122405Sharti snmp_node = 0; 1069122405Sharti return (SNMP_ERR_NOERROR); 1070122405Sharti 1071122405Sharti case LEAF_begemotNgResBufSiz: 1072122405Sharti resbufsiz = ctx->scratch->int1; 1073122405Sharti return (SNMP_ERR_NOERROR); 1074122405Sharti 1075122405Sharti case LEAF_begemotNgTimeout: 1076122405Sharti timeout = ctx->scratch->int1; 1077122405Sharti return (SNMP_ERR_NOERROR); 1078122405Sharti 1079122405Sharti case LEAF_begemotNgDebugLevel: 1080122405Sharti debug_level = ctx->scratch->int1; 1081122405Sharti NgSetDebug(debug_level); 1082122405Sharti return (SNMP_ERR_NOERROR); 1083122405Sharti } 1084122405Sharti abort(); 1085122405Sharti 1086122405Sharti case SNMP_OP_COMMIT: 1087122405Sharti switch (which) { 1088122405Sharti 1089122405Sharti case LEAF_begemotNgControlNodeName: 1090122405Sharti string_commit(ctx); 1091122405Sharti return (SNMP_ERR_NOERROR); 1092122405Sharti 1093122405Sharti case LEAF_begemotNgResBufSiz: 1094122405Sharti case LEAF_begemotNgTimeout: 1095122405Sharti case LEAF_begemotNgDebugLevel: 1096122405Sharti return (SNMP_ERR_NOERROR); 1097122405Sharti } 1098122405Sharti abort(); 1099122405Sharti } 1100122405Sharti abort(); 1101122405Sharti} 1102122405Sharti 1103122405Shartiint 1104122405Shartiop_ng_stats(struct snmp_context *ctx __unused, struct snmp_value *value, 1105122405Sharti u_int sub, u_int iidx __unused, enum snmp_op op) 1106122405Sharti{ 1107122405Sharti switch (op) { 1108122405Sharti 1109122405Sharti case SNMP_OP_GETNEXT: 1110122405Sharti abort(); 1111122405Sharti 1112122405Sharti case SNMP_OP_GET: 1113122405Sharti value->v.uint32 = stats[value->var.subs[sub - 1] - 1]; 1114122405Sharti return (SNMP_ERR_NOERROR); 1115122405Sharti 1116122405Sharti case SNMP_OP_SET: 1117122405Sharti return (SNMP_ERR_NOT_WRITEABLE); 1118122405Sharti 1119122405Sharti case SNMP_OP_ROLLBACK: 1120122405Sharti case SNMP_OP_COMMIT: 1121122405Sharti abort(); 1122122405Sharti } 1123122405Sharti abort(); 1124122405Sharti} 1125122405Sharti 1126122405Sharti/* 1127122405Sharti * Netgraph type table 1128122405Sharti */ 1129122405Shartistatic int 1130122405Shartifetch_types(void) 1131122405Sharti{ 1132122405Sharti struct ngtype *t; 1133122405Sharti struct typelist *typelist; 1134122405Sharti struct ng_mesg *resp; 1135122405Sharti u_int u, i; 1136122405Sharti 1137122405Sharti if (this_tick <= ngtype_tick) 1138122405Sharti return (0); 1139122405Sharti 1140122405Sharti while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) { 1141122405Sharti TAILQ_REMOVE(&ngtype_list, t, link); 1142122405Sharti free(t); 1143122405Sharti } 1144122405Sharti 1145122405Sharti if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, 1146122405Sharti NGM_LISTTYPES, NULL, 0)) == NULL) 1147122405Sharti return (SNMP_ERR_GENERR); 1148122405Sharti typelist = (struct typelist *)(void *)resp->data; 1149122405Sharti 1150122405Sharti for (u = 0; u < typelist->numtypes; u++) { 1151122405Sharti if ((t = malloc(sizeof(*t))) == NULL) { 1152122405Sharti free(resp); 1153122405Sharti return (SNMP_ERR_GENERR); 1154122405Sharti } 1155122405Sharti strcpy(t->name, typelist->typeinfo[u].type_name); 1156122405Sharti t->index.subs[0] = strlen(t->name); 1157122405Sharti t->index.len = t->index.subs[0] + 1; 1158122405Sharti for (i = 0; i < t->index.subs[0]; i++) 1159122405Sharti t->index.subs[i + 1] = t->name[i]; 1160122405Sharti 1161122405Sharti INSERT_OBJECT_OID(t, &ngtype_list); 1162122405Sharti } 1163122405Sharti 1164122405Sharti ngtype_tick = this_tick; 1165122405Sharti 1166122405Sharti free(resp); 1167122405Sharti return (0); 1168122405Sharti} 1169122405Sharti 1170122405Sharti/* 1171122405Sharti * Try to load the netgraph type with the given name. We assume, that 1172122405Sharti * type 'type' is implemented in the kernel module 'ng_type'. 1173122405Sharti */ 1174122405Shartistatic int 1175122405Shartingtype_load(const u_char *name, size_t namelen) 1176122405Sharti{ 1177122405Sharti char *mod; 1178122405Sharti int ret; 1179122405Sharti 1180122405Sharti if ((mod = malloc(namelen + 4)) == NULL) 1181122405Sharti return (-1); 1182122405Sharti strcpy(mod, "ng_"); 1183122405Sharti strncpy(mod + 3, name, namelen); 1184122405Sharti mod[namelen + 3] = '\0'; 1185122405Sharti 1186122405Sharti ret = kldload(mod); 1187122405Sharti free(mod); 1188122405Sharti return (ret); 1189122405Sharti} 1190122405Sharti 1191122405Sharti/* 1192122405Sharti * Unload a netgraph type. 1193122405Sharti */ 1194122405Shartistatic int 1195122405Shartingtype_unload(const u_char *name, size_t namelen) 1196122405Sharti{ 1197122405Sharti char *mod; 1198122405Sharti int id; 1199122405Sharti 1200122405Sharti if ((mod = malloc(namelen + 4)) == NULL) 1201122405Sharti return (-1); 1202122405Sharti strcpy(mod, "ng_"); 1203122405Sharti strncpy(mod + 3, name, namelen); 1204122405Sharti mod[namelen + 3] = '\0'; 1205122405Sharti 1206122405Sharti if ((id = kldfind(mod)) == -1) { 1207122405Sharti free(mod); 1208122405Sharti return (-1); 1209122405Sharti } 1210122405Sharti free(mod); 1211122405Sharti return (kldunload(id)); 1212122405Sharti} 1213122405Sharti 1214122405Shartiint 1215122405Shartiop_ng_type(struct snmp_context *ctx, struct snmp_value *value, 1216122405Sharti u_int sub, u_int iidx, enum snmp_op op) 1217122405Sharti{ 1218122405Sharti asn_subid_t which = value->var.subs[sub - 1]; 1219122405Sharti struct ngtype *t; 1220122405Sharti u_char *name; 1221122405Sharti size_t namelen; 1222122405Sharti int status = 1; 1223122405Sharti int ret; 1224122405Sharti 1225122405Sharti switch (op) { 1226122405Sharti 1227122405Sharti case SNMP_OP_GETNEXT: 1228122405Sharti if ((ret = fetch_types()) != 0) 1229122405Sharti return (ret); 1230122405Sharti if ((t = NEXT_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL) 1231122405Sharti return (SNMP_ERR_NOSUCHNAME); 1232122405Sharti index_append(&value->var, sub, &t->index); 1233122405Sharti break; 1234122405Sharti 1235122405Sharti case SNMP_OP_GET: 1236122405Sharti if ((ret = fetch_types()) != 0) 1237122405Sharti return (ret); 1238122405Sharti if ((t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL) 1239122405Sharti return (SNMP_ERR_NOSUCHNAME); 1240122405Sharti break; 1241122405Sharti 1242122405Sharti case SNMP_OP_SET: 1243122405Sharti if (index_decode(&value->var, sub, iidx, &name, &namelen)) 1244122405Sharti return (SNMP_ERR_NO_CREATION); 1245122758Sharti if (namelen == 0 || namelen >= NG_TYPESIZ) { 1246122405Sharti free(name); 1247122405Sharti return (SNMP_ERR_NO_CREATION); 1248122405Sharti } 1249122405Sharti if ((ret = fetch_types()) != 0) { 1250122405Sharti free(name); 1251122405Sharti return (ret); 1252122405Sharti } 1253122405Sharti t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub); 1254122405Sharti 1255122405Sharti if (which != LEAF_begemotNgTypeStatus) { 1256122405Sharti free(name); 1257122405Sharti if (t != NULL) 1258122405Sharti return (SNMP_ERR_NOT_WRITEABLE); 1259122405Sharti return (SNMP_ERR_NO_CREATION); 1260122405Sharti } 1261122405Sharti if (!TRUTH_OK(value->v.integer)) { 1262122405Sharti free(name); 1263122405Sharti return (SNMP_ERR_WRONG_VALUE); 1264122405Sharti } 1265122405Sharti ctx->scratch->int1 = TRUTH_GET(value->v.integer); 1266122405Sharti ctx->scratch->int1 |= (t != NULL) << 1; 1267122405Sharti ctx->scratch->ptr2 = name; 1268122405Sharti ctx->scratch->int2 = namelen; 1269122405Sharti 1270122405Sharti if (t == NULL) { 1271122405Sharti /* type not loaded */ 1272122405Sharti if (ctx->scratch->int1 & 1) { 1273122405Sharti /* request to load */ 1274122405Sharti if (ngtype_load(name, namelen) == -1) { 1275122405Sharti free(name); 1276122405Sharti if (errno == ENOENT) 1277122405Sharti return (SNMP_ERR_INCONS_NAME); 1278122405Sharti else 1279122405Sharti return (SNMP_ERR_GENERR); 1280122405Sharti } 1281122405Sharti } 1282122405Sharti } else { 1283122405Sharti /* is type loaded */ 1284122405Sharti if (!(ctx->scratch->int1 & 1)) { 1285122405Sharti /* request to unload */ 1286122405Sharti if (ngtype_unload(name, namelen) == -1) { 1287122405Sharti free(name); 1288122405Sharti return (SNMP_ERR_GENERR); 1289122405Sharti } 1290122405Sharti } 1291122405Sharti } 1292122405Sharti return (SNMP_ERR_NOERROR); 1293122405Sharti 1294122405Sharti case SNMP_OP_ROLLBACK: 1295122405Sharti ret = SNMP_ERR_NOERROR; 1296122405Sharti if (!(ctx->scratch->int1 & 2)) { 1297122405Sharti /* did not exist */ 1298122405Sharti if (ctx->scratch->int1 & 1) { 1299122405Sharti /* request to load - unload */ 1300122405Sharti if (ngtype_unload(ctx->scratch->ptr2, 1301122405Sharti ctx->scratch->int2) == -1) 1302122405Sharti ret = SNMP_ERR_UNDO_FAILED; 1303122405Sharti } 1304122405Sharti } else { 1305122405Sharti /* did exist */ 1306122405Sharti if (!(ctx->scratch->int1 & 1)) { 1307122405Sharti /* request to unload - reload */ 1308122405Sharti if (ngtype_load(ctx->scratch->ptr2, 1309122405Sharti ctx->scratch->int2) == -1) 1310122405Sharti ret = SNMP_ERR_UNDO_FAILED; 1311122405Sharti } 1312122405Sharti } 1313122405Sharti free(ctx->scratch->ptr2); 1314122405Sharti return (ret); 1315122405Sharti 1316122405Sharti case SNMP_OP_COMMIT: 1317122405Sharti free(ctx->scratch->ptr2); 1318122405Sharti return (SNMP_ERR_NOERROR); 1319122405Sharti 1320122405Sharti default: 1321122405Sharti abort(); 1322122405Sharti } 1323122405Sharti 1324122405Sharti /* 1325122405Sharti * Come here for GET and COMMIT 1326122405Sharti */ 1327122405Sharti switch (which) { 1328122405Sharti 1329122405Sharti case LEAF_begemotNgTypeStatus: 1330122405Sharti value->v.integer = status; 1331122405Sharti break; 1332122405Sharti 1333122405Sharti default: 1334122405Sharti abort(); 1335122405Sharti } 1336122405Sharti return (SNMP_ERR_NOERROR); 1337122405Sharti} 1338122405Sharti 1339122405Sharti/* 1340122405Sharti * Implement the node table 1341122405Sharti */ 1342122405Shartistatic int 1343122405Shartifind_node(const struct asn_oid *oid, u_int sub, struct nodeinfo *info) 1344122405Sharti{ 1345122405Sharti ng_ID_t id = oid->subs[sub]; 1346122405Sharti struct ng_mesg *resp; 1347122405Sharti 1348122405Sharti if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO, 1349122405Sharti NULL, 0)) == NULL) 1350122405Sharti return (-1); 1351122405Sharti 1352122405Sharti *info = *(struct nodeinfo *)(void *)resp->data; 1353122405Sharti free(resp); 1354122405Sharti return (0); 1355122405Sharti} 1356122405Sharti 1357122405Shartistatic int 1358122405Shartincmp(const void *p1, const void *p2) 1359122405Sharti{ 1360122405Sharti const struct nodeinfo *i1 = p1; 1361122405Sharti const struct nodeinfo *i2 = p2; 1362122405Sharti 1363122405Sharti if (i1->id < i2->id) 1364122405Sharti return (-1); 1365122405Sharti if (i1->id > i2->id) 1366122405Sharti return (+1); 1367122405Sharti return (0); 1368122405Sharti} 1369122405Sharti 1370122405Shartistatic int 1371122405Shartifind_node_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *info) 1372122405Sharti{ 1373122405Sharti u_int idxlen = oid->len - sub; 1374122405Sharti struct ng_mesg *resp; 1375122405Sharti struct namelist *list; 1376122405Sharti ng_ID_t id; 1377122405Sharti u_int i; 1378122405Sharti 1379122405Sharti if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES, 1380122405Sharti NULL, 0)) == NULL) 1381122405Sharti return (-1); 1382122405Sharti list = (struct namelist *)(void *)resp->data; 1383122405Sharti 1384122405Sharti qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp); 1385122405Sharti 1386122405Sharti if (idxlen == 0) { 1387122405Sharti if (list->numnames == 0) { 1388122405Sharti free(resp); 1389122405Sharti return (-1); 1390122405Sharti } 1391122405Sharti *info = list->nodeinfo[0]; 1392122405Sharti free(resp); 1393122405Sharti return (0); 1394122405Sharti } 1395122405Sharti id = oid->subs[sub]; 1396122405Sharti 1397122405Sharti for (i = 0; i < list->numnames; i++) 1398122405Sharti if (list->nodeinfo[i].id > id) { 1399122405Sharti *info = list->nodeinfo[i]; 1400122405Sharti free(resp); 1401122405Sharti return (0); 1402122405Sharti } 1403122405Sharti 1404122405Sharti free(resp); 1405122405Sharti return (-1); 1406122405Sharti} 1407122405Sharti 1408122405Shartiint 1409122405Shartiop_ng_node(struct snmp_context *ctx __unused, struct snmp_value *value, 1410122405Sharti u_int sub, u_int iidx __unused, enum snmp_op op) 1411122405Sharti{ 1412122405Sharti asn_subid_t which = value->var.subs[sub - 1]; 1413122405Sharti u_int idxlen = value->var.len - sub; 1414122405Sharti struct nodeinfo nodeinfo; 1415122405Sharti 1416122405Sharti switch (op) { 1417122405Sharti 1418122405Sharti case SNMP_OP_GETNEXT: 1419122405Sharti if (find_node_next(&value->var, sub, &nodeinfo) == -1) 1420122405Sharti return (SNMP_ERR_NOSUCHNAME); 1421122405Sharti value->var.len = sub + 1; 1422122405Sharti value->var.subs[sub] = nodeinfo.id; 1423122405Sharti break; 1424122405Sharti 1425122405Sharti case SNMP_OP_GET: 1426122405Sharti if (idxlen != 1) 1427122405Sharti return (SNMP_ERR_NOSUCHNAME); 1428122405Sharti if (find_node(&value->var, sub, &nodeinfo) == -1) 1429122405Sharti return (SNMP_ERR_NOSUCHNAME); 1430122405Sharti break; 1431122405Sharti 1432122405Sharti case SNMP_OP_SET: 1433122405Sharti if (idxlen != 1) 1434122405Sharti return (SNMP_ERR_NO_CREATION); 1435122405Sharti if (find_node(&value->var, sub, &nodeinfo) == -1) 1436122405Sharti return (SNMP_ERR_NO_CREATION); 1437122405Sharti return (SNMP_ERR_NOT_WRITEABLE); 1438122405Sharti 1439122405Sharti case SNMP_OP_ROLLBACK: 1440122405Sharti case SNMP_OP_COMMIT: 1441122405Sharti default: 1442122405Sharti abort(); 1443122405Sharti } 1444122405Sharti 1445122405Sharti /* 1446122405Sharti * Come here for GET and COMMIT 1447122405Sharti */ 1448122405Sharti switch (which) { 1449122405Sharti 1450122405Sharti case LEAF_begemotNgNodeStatus: 1451122405Sharti value->v.integer = 1; 1452122405Sharti break; 1453122405Sharti case LEAF_begemotNgNodeName: 1454122405Sharti return (string_get(value, nodeinfo.name, -1)); 1455122405Sharti case LEAF_begemotNgNodeType: 1456122405Sharti return (string_get(value, nodeinfo.type, -1)); 1457122405Sharti case LEAF_begemotNgNodeHooks: 1458122405Sharti value->v.uint32 = nodeinfo.hooks; 1459122405Sharti break; 1460122405Sharti 1461122405Sharti default: 1462122405Sharti abort(); 1463122405Sharti } 1464122405Sharti return (SNMP_ERR_NOERROR); 1465122405Sharti} 1466122405Sharti 1467122405Sharti/* 1468122405Sharti * Implement the hook table 1469122405Sharti */ 1470122405Shartistatic int 1471122405Shartifind_hook(int32_t id, const u_char *hook, size_t hooklen, struct linkinfo *info) 1472122405Sharti{ 1473122405Sharti struct ng_mesg *resp; 1474122405Sharti struct hooklist *list; 1475122405Sharti u_int i; 1476122405Sharti 1477122405Sharti if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, 1478122405Sharti NGM_LISTHOOKS, NULL, 0)) == NULL) 1479122405Sharti return (-1); 1480122405Sharti 1481122405Sharti list = (struct hooklist *)(void *)resp->data; 1482122405Sharti 1483122405Sharti for (i = 0; i < list->nodeinfo.hooks; i++) { 1484122405Sharti if (strlen(list->link[i].ourhook) == hooklen && 1485122405Sharti strncmp(list->link[i].ourhook, hook, hooklen) == 0) { 1486122405Sharti *info = list->link[i]; 1487122405Sharti free(resp); 1488122405Sharti return (0); 1489122405Sharti } 1490122405Sharti } 1491122405Sharti free(resp); 1492122405Sharti return (-1); 1493122405Sharti} 1494122405Sharti 1495122405Shartistatic int 1496122405Shartihook_cmp(const void *p1, const void *p2) 1497122405Sharti{ 1498122405Sharti const struct linkinfo *i1 = p1; 1499122405Sharti const struct linkinfo *i2 = p2; 1500122405Sharti 1501122405Sharti if (strlen(i1->ourhook) < strlen(i2->ourhook)) 1502122405Sharti return (-1); 1503122405Sharti if (strlen(i1->ourhook) > strlen(i2->ourhook)) 1504122405Sharti return (+1); 1505122405Sharti return (strcmp(i1->ourhook, i2->ourhook)); 1506122405Sharti} 1507122405Sharti 1508122405Shartistatic int 1509122405Shartifind_hook_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *nodeinfo, 1510122405Sharti struct linkinfo *linkinfo) 1511122405Sharti{ 1512122405Sharti u_int idxlen = oid->len - sub; 1513122405Sharti struct namelist *list; 1514122405Sharti struct ng_mesg *resp; 1515122405Sharti struct hooklist *hooks; 1516122405Sharti struct ng_mesg *resp1; 1517122405Sharti u_int node_index; 1518122405Sharti struct asn_oid idx; 1519122405Sharti u_int i, j; 1520122405Sharti 1521122405Sharti /* 1522122405Sharti * Get and sort Node list 1523122405Sharti */ 1524122405Sharti if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES, 1525122405Sharti NULL, 0)) == NULL) 1526122405Sharti return (-1); 1527122405Sharti list = (struct namelist *)(void *)resp->data; 1528122405Sharti 1529122405Sharti qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp); 1530122405Sharti 1531122405Sharti /* 1532122405Sharti * If we have no index, take the first node and return the 1533122405Sharti * first hook. 1534122405Sharti */ 1535122405Sharti if (idxlen == 0) { 1536122405Sharti node_index = 0; 1537122405Sharti goto return_first_hook; 1538122405Sharti } 1539122405Sharti 1540122405Sharti /* 1541122405Sharti * Locate node 1542122405Sharti */ 1543122405Sharti for (node_index = 0; node_index < list->numnames; node_index++) 1544122405Sharti if (list->nodeinfo[node_index].id >= oid->subs[sub]) 1545122405Sharti break; 1546122405Sharti 1547122405Sharti /* 1548122405Sharti * If we have only the node part of the index take, or 1549122405Sharti * there is no node with that Id, take the first hook of that node. 1550122405Sharti */ 1551122405Sharti if (idxlen == 1 || node_index >= list->numnames || 1552122405Sharti list->nodeinfo[node_index].id > oid->subs[sub]) 1553122405Sharti goto return_first_hook; 1554122405Sharti 1555122405Sharti /* 1556122405Sharti * We had an exact match on the node id and have (at last part) 1557122405Sharti * of the hook name index. Loop through the hooks of the node 1558122405Sharti * and find the next one. 1559122405Sharti */ 1560122405Sharti if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id, 1561122405Sharti NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL) { 1562122405Sharti free(resp); 1563122405Sharti return (-1); 1564122405Sharti } 1565122405Sharti hooks = (struct hooklist *)(void *)resp1->data; 1566122405Sharti if (hooks->nodeinfo.hooks > 0) { 1567122405Sharti qsort(hooks->link, hooks->nodeinfo.hooks, 1568122405Sharti sizeof(hooks->link[0]), hook_cmp); 1569122405Sharti for (i = 0; i < hooks->nodeinfo.hooks; i++) { 1570122405Sharti idx.len = strlen(hooks->link[i].ourhook) + 1; 1571122405Sharti idx.subs[0] = idx.len - 1; 1572122405Sharti for (j = 0; j < idx.len; j++) 1573122405Sharti idx.subs[j + 1] = hooks->link[i].ourhook[j]; 1574122405Sharti if (index_compare(oid, sub + 1, &idx) < 0) 1575122405Sharti break; 1576122405Sharti } 1577122405Sharti if (i < hooks->nodeinfo.hooks) { 1578122405Sharti *nodeinfo = hooks->nodeinfo; 1579122405Sharti *linkinfo = hooks->link[i]; 1580122405Sharti 1581122405Sharti free(resp); 1582122405Sharti free(resp1); 1583122405Sharti return (0); 1584122405Sharti } 1585122405Sharti } 1586122405Sharti 1587122405Sharti /* no hook found larger than the index on the index node - take 1588122405Sharti * first hook of next node */ 1589122405Sharti free(resp1); 1590122405Sharti node_index++; 1591122405Sharti 1592122405Sharti return_first_hook: 1593122405Sharti while (node_index < list->numnames) { 1594122405Sharti if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id, 1595122405Sharti NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL) 1596122405Sharti break; 1597122405Sharti hooks = (struct hooklist *)(void *)resp1->data; 1598122405Sharti if (hooks->nodeinfo.hooks > 0) { 1599122405Sharti qsort(hooks->link, hooks->nodeinfo.hooks, 1600122405Sharti sizeof(hooks->link[0]), hook_cmp); 1601122405Sharti 1602122405Sharti *nodeinfo = hooks->nodeinfo; 1603122405Sharti *linkinfo = hooks->link[0]; 1604122405Sharti 1605122405Sharti free(resp); 1606122405Sharti free(resp1); 1607122405Sharti return (0); 1608122405Sharti } 1609122405Sharti 1610122405Sharti /* if we don't have hooks, try next node */ 1611122405Sharti free(resp1); 1612122405Sharti node_index++; 1613122405Sharti } 1614122405Sharti 1615122405Sharti free(resp); 1616122405Sharti return (-1); 1617122405Sharti} 1618122405Sharti 1619122405Shartiint 1620122405Shartiop_ng_hook(struct snmp_context *ctx __unused, struct snmp_value *value, 1621122405Sharti u_int sub, u_int iidx, enum snmp_op op) 1622122405Sharti{ 1623122405Sharti asn_subid_t which = value->var.subs[sub - 1]; 1624122405Sharti struct linkinfo linkinfo; 1625122405Sharti struct nodeinfo nodeinfo; 1626122405Sharti u_int32_t lid; 1627122405Sharti u_char *hook; 1628122405Sharti size_t hooklen; 1629122405Sharti u_int i; 1630122405Sharti 1631122405Sharti switch (op) { 1632122405Sharti 1633122405Sharti case SNMP_OP_GETNEXT: 1634122405Sharti if (find_hook_next(&value->var, sub, &nodeinfo, &linkinfo) == -1) 1635122405Sharti return (SNMP_ERR_NOSUCHNAME); 1636122405Sharti 1637122405Sharti value->var.len = sub + 1 + 1 + strlen(linkinfo.ourhook); 1638122405Sharti value->var.subs[sub] = nodeinfo.id; 1639122405Sharti value->var.subs[sub + 1] = strlen(linkinfo.ourhook); 1640122405Sharti for (i = 0; i < strlen(linkinfo.ourhook); i++) 1641122405Sharti value->var.subs[sub + i + 2] = 1642122405Sharti linkinfo.ourhook[i]; 1643122405Sharti break; 1644122405Sharti 1645122405Sharti case SNMP_OP_GET: 1646122405Sharti if (index_decode(&value->var, sub, iidx, &lid, 1647122405Sharti &hook, &hooklen)) 1648122405Sharti return (SNMP_ERR_NOSUCHNAME); 1649122405Sharti if (find_hook(lid, hook, hooklen, &linkinfo) == -1) { 1650122405Sharti free(hook); 1651122405Sharti return (SNMP_ERR_NOSUCHNAME); 1652122405Sharti } 1653122405Sharti free(hook); 1654122405Sharti break; 1655122405Sharti 1656122405Sharti case SNMP_OP_SET: 1657122405Sharti if (index_decode(&value->var, sub, iidx, &lid, 1658122405Sharti &hook, &hooklen)) 1659122405Sharti return (SNMP_ERR_NO_CREATION); 1660122405Sharti if (find_hook(lid, hook, hooklen, &linkinfo) == -1) { 1661122405Sharti free(hook); 1662122405Sharti return (SNMP_ERR_NO_CREATION); 1663122405Sharti } 1664122405Sharti free(hook); 1665122405Sharti return (SNMP_ERR_NOT_WRITEABLE); 1666122405Sharti 1667122405Sharti case SNMP_OP_ROLLBACK: 1668122405Sharti case SNMP_OP_COMMIT: 1669122405Sharti default: 1670122405Sharti abort(); 1671122405Sharti 1672122405Sharti } 1673122405Sharti 1674122405Sharti switch (which) { 1675122405Sharti 1676122405Sharti case LEAF_begemotNgHookStatus: 1677122405Sharti value->v.integer = 1; 1678122405Sharti break; 1679122405Sharti case LEAF_begemotNgHookPeerNodeId: 1680122405Sharti value->v.uint32 = linkinfo.nodeinfo.id; 1681122405Sharti break; 1682122405Sharti case LEAF_begemotNgHookPeerHook: 1683122405Sharti return (string_get(value, linkinfo.peerhook, -1)); 1684122405Sharti case LEAF_begemotNgHookPeerType: 1685122405Sharti return (string_get(value, linkinfo.nodeinfo.type, -1)); 1686122405Sharti default: 1687122405Sharti abort(); 1688122405Sharti } 1689122405Sharti return (SNMP_ERR_NOERROR); 1690122405Sharti} 1691