snmp_netgraph.c revision 146529
138032Speter/* 264562Sgshapiro * Copyright (c) 2001-2003 364562Sgshapiro * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 438032Speter * All rights reserved. 538032Speter * 638032Speter * Author: Harti Brandt <harti@freebsd.org> 738032Speter * 838032Speter * Redistribution of this software and documentation and use in source and 938032Speter * binary forms, with or without modification, are permitted provided that 1038032Speter * the following conditions are met: 1138032Speter * 1238032Speter * 1. Redistributions of source code or documentation must retain the above 1338032Speter * copyright notice, this list of conditions and the following disclaimer. 1438032Speter * 2. Redistributions in binary form must reproduce the above copyright 1571345Sgshapiro * notice, this list of conditions and the following disclaimer in the 1664562Sgshapiro * documentation and/or other materials provided with the distribution. 1738032Speter * 1864562Sgshapiro * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 1938032Speter * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 2064562Sgshapiro * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 2164562Sgshapiro * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 2264562Sgshapiro * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 2364562Sgshapiro * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 2464562Sgshapiro * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 2564562Sgshapiro * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 2664562Sgshapiro * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 2764562Sgshapiro * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 2864562Sgshapiro * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2964562Sgshapiro * 3064562Sgshapiro * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.c 146529 2005-05-23 11:24:39Z harti $ 3164562Sgshapiro * 3264562Sgshapiro * Netgraph interface for SNMPd. 3364562Sgshapiro */ 3464562Sgshapiro#include <sys/types.h> 3538032Speter#include <sys/param.h> 3638032Speter#include <sys/linker.h> 3738032Speter#include <sys/socket.h> 3838032Speter#include <sys/syslog.h> 3938032Speter#include <sys/queue.h> 4038032Speter#include <sys/sysctl.h> 4138032Speter#include <stdio.h> 4238032Speter#include <stdlib.h> 4338032Speter#include <errno.h> 4438032Speter#include <unistd.h> 4538032Speter#include <string.h> 4638032Speter#include <netgraph.h> 4738032Speter#include "snmpmod.h" 4838032Speter#include "snmp_netgraph.h" 4938032Speter#include "netgraph_tree.h" 5038032Speter#include "netgraph_oid.h" 5138032Speter 5238032Speter/* maximum message size */ 5338032Speter#define RESBUFSIZ 20000 5438032Speter 5538032Speter/* default node name */ 5638032Speter#define NODENAME "NgSnmpd" 5738032Speter 5838032Speter/* my node Id */ 5938032Speterng_ID_t snmp_node; 6038032Speteru_char *snmp_nodename; 6138032Speter 6238032Speter/* the Object Resource registration index */ 6338032Speterstatic u_int reg_index; 6438032Speterstatic const struct asn_oid oid_begemotNg = OIDX_begemotNg; 6538032Speter 6638032Speter/* configuration */ 6738032Speter/* this must be smaller than int32_t because the functions in libnetgraph 6838032Speter * falsely return an int */ 6938032Speterstatic size_t resbufsiz = RESBUFSIZ; 7038032Speterstatic u_int timeout = 1000; 7138032Speterstatic u_int debug_level; 7238032Speter 7338032Speter/* number of microseconds per clock tick */ 7438032Speterstatic struct clockinfo clockinfo; 7538032Speter 7638032Speter/* Csock buffers. Communication on the csock is asynchronuous. This means 7738032Speter * if we wait for a specific response, we may get other messages. Put these 7838032Speter * into a queue and execute them when we are idle. */ 7938032Speterstruct csock_buf { 8038032Speter STAILQ_ENTRY(csock_buf) link; 8138032Speter struct ng_mesg *mesg; 8238032Speter char path[NG_PATHSIZ]; 8338032Speter}; 8438032Speterstatic STAILQ_HEAD(, csock_buf) csock_bufs = 8538032Speter STAILQ_HEAD_INITIALIZER(csock_bufs); 8638032Speter 8738032Speter/* 8838032Speter * We dispatch unsolicieted messages by node cookies and ids. 8964562Sgshapiro * So we must keep a list of hook names and dispatch functions. 9038032Speter */ 9138032Speterstruct msgreg { 9238032Speter u_int32_t cookie; 9338032Speter ng_ID_t id; 9438032Speter ng_cookie_f *func; 9538032Speter void *arg; 9638032Speter const struct lmodule *mod; 9738032Speter SLIST_ENTRY(msgreg) link; 9838032Speter}; 9964562Sgshapirostatic SLIST_HEAD(, msgreg) msgreg_list = 10038032Speter SLIST_HEAD_INITIALIZER(msgreg_list); 10138032Speter 10238032Speter/* 10338032Speter * Data messages are dispatched by hook names. 10438032Speter */ 10564562Sgshapirostruct datareg { 10638032Speter char hook[NG_HOOKSIZ]; 10738032Speter ng_hook_f *func; 10838032Speter void *arg; 10938032Speter const struct lmodule *mod; 11038032Speter SLIST_ENTRY(datareg) link; 11138032Speter}; 11238032Speterstatic SLIST_HEAD(, datareg) datareg_list = 11338032Speter SLIST_HEAD_INITIALIZER(datareg_list); 11438032Speter 11538032Speter/* the netgraph sockets */ 11642575Speterstatic int csock, dsock; 11738032Speterstatic void *csock_fd, *dsock_fd; 11838032Speter 11938032Speter/* our module handle */ 12038032Speterstatic struct lmodule *module; 12138032Speter 12242575Speter/* statistics */ 12338032Speterstatic u_int32_t stats[LEAF_begemotNgTooLargeDatas+1]; 12438032Speter 12538032Speter/* netgraph type list */ 12638032Speterstruct ngtype { 12738032Speter char name[NG_TYPESIZ]; 12842575Speter struct asn_oid index; 12938032Speter TAILQ_ENTRY(ngtype) link; 13038032Speter}; 13138032SpeterTAILQ_HEAD(ngtype_list, ngtype); 13238032Speter 13338032Speterstatic struct ngtype_list ngtype_list; 13438032Speterstatic uint64_t ngtype_tick; 13538032Speter 13638032Speter 13738032Speter/* 13864562Sgshapiro * Register a function to receive unsolicited messages 13964562Sgshapiro */ 14038032Spetervoid * 14138032Speterng_register_cookie(const struct lmodule *mod, u_int32_t cookie, ng_ID_t id, 14238032Speter ng_cookie_f *func, void *arg) 14338032Speter{ 14464562Sgshapiro struct msgreg *d; 14538032Speter 14638032Speter if ((d = malloc(sizeof(*d))) == NULL) 14738032Speter return (NULL); 14838032Speter 14938032Speter d->cookie = cookie; 15038032Speter d->id = id; 15138032Speter d->func = func; 15238032Speter d->arg = arg; 15338032Speter d->mod = mod; 15438032Speter 15538032Speter SLIST_INSERT_HEAD(&msgreg_list, d, link); 15638032Speter 15738032Speter return (d); 15838032Speter} 15938032Speter 16038032Speter/* 16138032Speter * Remove a registration. 16238032Speter */ 16338032Spetervoid 16438032Speterng_unregister_cookie(void *dd) 16538032Speter{ 16638032Speter struct msgreg *d = dd; 16764562Sgshapiro 16864562Sgshapiro SLIST_REMOVE(&msgreg_list, d, msgreg, link); 16964562Sgshapiro free(d); 17064562Sgshapiro} 17164562Sgshapiro 17238032Speter/* 17338032Speter * Register a function for hook data. 17438032Speter */ 17538032Spetervoid * 17638032Speterng_register_hook(const struct lmodule *mod, const char *hook, 17738032Speter ng_hook_f *func, void *arg) 17838032Speter{ 17938032Speter struct datareg *d; 18038032Speter 18138032Speter if ((d = malloc(sizeof(*d))) == NULL) 18238032Speter return (NULL); 18338032Speter 18438032Speter strcpy(d->hook, hook); 18538032Speter d->func = func; 18638032Speter d->arg = arg; 18738032Speter d->mod = mod; 18838032Speter 18938032Speter SLIST_INSERT_HEAD(&datareg_list, d, link); 19038032Speter 19138032Speter return (d); 19238032Speter} 19338032Speter 19438032Speter/* 19538032Speter * Unregister a hook function 19638032Speter */ 19738032Spetervoid 19864562Sgshapirong_unregister_hook(void *dd) 19964562Sgshapiro{ 20038032Speter struct datareg *d = dd; 20138032Speter 20238032Speter SLIST_REMOVE(&datareg_list, d, datareg, link); 20338032Speter free(d); 20438032Speter} 20538032Speter 20638032Speter/* 20738032Speter * Unregister all hooks and cookies for that module. Note: doesn't disconnect 20838032Speter * any hooks! 20938032Speter */ 21038032Spetervoid 21138032Speterng_unregister_module(const struct lmodule *mod) 21238032Speter{ 21338032Speter struct msgreg *m, *m1; 21438032Speter struct datareg *d, *d1; 21538032Speter 21638032Speter m = SLIST_FIRST(&msgreg_list); 21738032Speter while (m != NULL) { 21838032Speter m1 = SLIST_NEXT(m, link); 21938032Speter if (m->mod == mod) { 22038032Speter SLIST_REMOVE(&msgreg_list, m, msgreg, link); 22138032Speter free(m); 22238032Speter } 22338032Speter m = m1; 22438032Speter } 22538032Speter 22638032Speter d = SLIST_FIRST(&datareg_list); 22738032Speter while (d != NULL) { 22838032Speter d1 = SLIST_NEXT(d, link); 22938032Speter if (d->mod == mod) { 23038032Speter SLIST_REMOVE(&datareg_list, d, datareg, link); 23138032Speter free(d); 23238032Speter } 23338032Speter d = d1; 23438032Speter } 23538032Speter} 23638032Speter 23738032Speter/* 23838032Speter * Dispatch a message to the correct module and delete it. More than one 23938032Speter * module can get a message. 24038032Speter */ 24138032Speterstatic void 24238032Spetercsock_handle(struct ng_mesg *mesg, const char *path) 24338032Speter{ 24438032Speter struct msgreg *d, *d1; 24538032Speter u_int id; 24638032Speter int len; 24738032Speter 24838032Speter if (sscanf(path, "[%x]:%n", &id, &len) != 1 || 24938032Speter (u_int)len != strlen(path)) { 25038032Speter syslog(LOG_ERR, "cannot parse message path '%s'", path); 25138032Speter id = 0; 25238032Speter } 25338032Speter 25438032Speter d = SLIST_FIRST(&msgreg_list); 25538032Speter while (d != NULL) { 25638032Speter d1 = SLIST_NEXT(d, link); 25738032Speter if (d->cookie == mesg->header.typecookie && 25838032Speter (d->id == 0 || d->id == id || id == 0)) 25938032Speter (*d->func)(mesg, path, id, d->arg); 26038032Speter d = d1; 26138032Speter } 26238032Speter free(mesg); 26364562Sgshapiro} 26438032Speter 26538032Speter/* 26638032Speter * Input from the control socket. 26738032Speter */ 26838032Speterstatic struct ng_mesg * 26938032Spetercsock_read(char *path) 27038032Speter{ 27138032Speter struct ng_mesg *mesg; 27238032Speter int ret, err; 27338032Speter 27438032Speter if ((mesg = malloc(resbufsiz + 1)) == NULL) { 27538032Speter stats[LEAF_begemotNgNoMems]++; 27638032Speter syslog(LOG_CRIT, "out of memory"); 27738032Speter errno = ENOMEM; 27838032Speter return (NULL); 27938032Speter } 28064562Sgshapiro if ((ret = NgRecvMsg(csock, mesg, resbufsiz + 1, path)) < 0) { 28164562Sgshapiro err = errno; 28238032Speter free(mesg); 28338032Speter if (errno == EWOULDBLOCK) { 28438032Speter errno = err; 28538032Speter return (NULL); 28638032Speter } 28738032Speter stats[LEAF_begemotNgMsgReadErrs]++; 28838032Speter syslog(LOG_WARNING, "read from csock: %m"); 28938032Speter errno = err; 29038032Speter return (NULL); 29138032Speter } 29238032Speter if (ret == 0) { 29338032Speter syslog(LOG_DEBUG, "node closed -- exiting"); 29438032Speter exit(0); 29538032Speter } 29638032Speter if ((size_t)ret > resbufsiz) { 29738032Speter stats[LEAF_begemotNgTooLargeMsgs]++; 29838032Speter syslog(LOG_WARNING, "ng message too large"); 29938032Speter free(mesg); 30038032Speter errno = EFBIG; 30138032Speter return (NULL); 30238032Speter } 30338032Speter return (mesg); 30438032Speter} 30538032Speter 30638032Speterstatic void 30738032Spetercsock_input(int fd __unused, void *udata __unused) 30838032Speter{ 30938032Speter struct ng_mesg *mesg; 31038032Speter char path[NG_PATHSIZ]; 31138032Speter 31238032Speter if ((mesg = csock_read(path)) == NULL) 31338032Speter return; 31438032Speter 31538032Speter csock_handle(mesg, path); 31638032Speter} 31738032Speter 31838032Speter/* 31938032Speter * Write a message to a node. 32038032Speter */ 32138032Speterint 32238032Speterng_output(const char *path, u_int cookie, u_int opcode, 32338032Speter const void *arg, size_t arglen) 32438032Speter{ 32538032Speter return (NgSendMsg(csock, path, (int)cookie, (int)opcode, arg, arglen)); 32638032Speter} 32738032Speterint 32838032Speterng_output_node(const char *node, u_int cookie, u_int opcode, 32938032Speter const void *arg, size_t arglen) 33038032Speter{ 33138032Speter char path[NG_PATHSIZ]; 33238032Speter 33338032Speter sprintf(path, "%s:", node); 33438032Speter return (ng_output(path, cookie, opcode, arg, arglen)); 33538032Speter} 33638032Speterint 33738032Speterng_output_id(ng_ID_t node, u_int cookie, u_int opcode, 33838032Speter const void *arg, size_t arglen) 33938032Speter{ 34038032Speter char path[NG_PATHSIZ]; 34138032Speter 34264562Sgshapiro sprintf(path, "[%x]:", node); 34338032Speter return (ng_output(path, cookie, opcode, arg, arglen)); 34438032Speter} 34538032Speter 34664562Sgshapiro 34738032Speter 34864562Sgshapiro/* 34964562Sgshapiro * Execute a synchronuous dialog with the csock. All message we receive, that 35064562Sgshapiro * do not match our request, are queue until the next call to the IDLE function. 35138032Speter */ 35238032Speterstruct ng_mesg * 35338032Speterng_dialog(const char *path, u_int cookie, u_int opcode, 35438032Speter const void *arg, size_t arglen) 35538032Speter{ 35638032Speter int token, err; 35738032Speter struct ng_mesg *mesg; 35838032Speter char rpath[NG_PATHSIZ]; 35971345Sgshapiro struct csock_buf *b; 36071345Sgshapiro struct timeval end, tv; 36138032Speter 36238032Speter if ((token = ng_output(path, cookie, opcode, arg, arglen)) < 0) 36338032Speter return (NULL); 36438032Speter 36538032Speter if (csock_fd) 36664562Sgshapiro fd_suspend(csock_fd); 36738032Speter 36838032Speter gettimeofday(&end, NULL); 36938032Speter tv.tv_sec = timeout / 1000; 37038032Speter tv.tv_usec = (timeout % 1000) * 1000; 37138032Speter timeradd(&end, &tv, &end); 37238032Speter for (;;) { 37338032Speter mesg = NULL; 37471345Sgshapiro gettimeofday(&tv, NULL); 37571345Sgshapiro if (timercmp(&tv, &end, >=)) { 37638032Speter block: 37738032Speter syslog(LOG_WARNING, "no response for request %u/%u", 37838032Speter cookie, opcode); 37938032Speter errno = EWOULDBLOCK; 38038032Speter break; 38138032Speter } 38238032Speter timersub(&end, &tv, &tv); 38338032Speter if (tv.tv_sec == 0 && tv.tv_usec < clockinfo.tick) 38438032Speter goto block; 38538032Speter 38638032Speter if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) 38738032Speter syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO): %m"); 38838032Speter if ((mesg = csock_read(rpath)) == NULL) { 38938032Speter if (errno == EWOULDBLOCK) 39038032Speter continue; 39138032Speter break; 39238032Speter } 39338032Speter if (mesg->header.token == (u_int)token) 39438032Speter break; 39538032Speter if ((b = malloc(sizeof(*b))) == NULL) { 39638032Speter stats[LEAF_begemotNgNoMems]++; 39738032Speter syslog(LOG_ERR, "out of memory"); 39838032Speter free(mesg); 39938032Speter continue; 40038032Speter } 40138032Speter b->mesg = mesg; 40238032Speter strcpy(b->path, rpath); 40338032Speter STAILQ_INSERT_TAIL(&csock_bufs, b, link); 40471345Sgshapiro } 40571345Sgshapiro 40638032Speter tv.tv_sec = 0; 40738032Speter tv.tv_usec = 0; 40838032Speter if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) 40938032Speter syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO,0): %m"); 41038032Speter 41138032Speter if (csock_fd) { 41238032Speter err = errno; 41338032Speter fd_resume(csock_fd); 41438032Speter errno = err; 41538032Speter } 41638032Speter 41738032Speter return (mesg); 41864562Sgshapiro} 41938032Speterstruct ng_mesg * 42064562Sgshapirong_dialog_node(const char *node, u_int cookie, u_int opcode, 42164562Sgshapiro const void *arg, size_t arglen) 42264562Sgshapiro{ 42338032Speter char path[NG_PATHSIZ]; 42438032Speter 42538032Speter sprintf(path, "%s:", node); 42638032Speter return (ng_dialog(path, cookie, opcode, arg, arglen)); 42764562Sgshapiro} 42838032Speterstruct ng_mesg * 42938032Speterng_dialog_id(ng_ID_t id, u_int cookie, u_int opcode, 43038032Speter const void *arg, size_t arglen) 43138032Speter{ 43238032Speter char path[NG_PATHSIZ]; 43338032Speter 43438032Speter sprintf(path, "[%x]:", id); 43538032Speter return (ng_dialog(path, cookie, opcode, arg, arglen)); 43638032Speter} 43738032Speter 43838032Speter 43938032Speter/* 44038032Speter * Send a data message to a given hook. 44138032Speter */ 44238032Speterint 44338032Speterng_send_data(const char *hook, const void *sndbuf, size_t sndlen) 44464562Sgshapiro{ 44538032Speter return (NgSendData(dsock, hook, sndbuf, sndlen)); 44638032Speter} 44738032Speter 44838032Speter/* 44938032Speter * Input from a data socket. Dispatch to the function for that hook. 45038032Speter */ 45138032Speterstatic void 45238032Speterdsock_input(int fd __unused, void *udata __unused) 45338032Speter{ 45464562Sgshapiro u_char *resbuf, embuf[100]; 45538032Speter ssize_t len; 45638032Speter char hook[NG_HOOKSIZ]; 45738032Speter struct datareg *d, *d1; 45838032Speter 45938032Speter if ((resbuf = malloc(resbufsiz + 1)) == NULL) { 46038032Speter stats[LEAF_begemotNgNoMems]++; 46138032Speter syslog(LOG_CRIT, "out of memory"); 46238032Speter (void)NgRecvData(fd, embuf, sizeof(embuf), hook); 46338032Speter errno = ENOMEM; 46438032Speter return; 46538032Speter } 46638032Speter if ((len = NgRecvData(fd, resbuf, resbufsiz + 1, hook)) == -1) { 46738032Speter stats[LEAF_begemotNgDataReadErrs]++; 46838032Speter syslog(LOG_ERR, "reading message: %m"); 46938032Speter free(resbuf); 47038032Speter return; 47138032Speter } 47238032Speter if (len == 0) { 47338032Speter free(resbuf); 47438032Speter return; 47538032Speter } 47638032Speter if ((size_t)len == resbufsiz + 1) { 47738032Speter stats[LEAF_begemotNgTooLargeDatas]++; 47838032Speter syslog(LOG_WARNING, "message too long"); 47938032Speter free(resbuf); 48038032Speter return; 48138032Speter } 48238032Speter 48338032Speter /* 48438032Speter * Dispatch message. Maybe dispatched to more than one function. 48564562Sgshapiro */ 48638032Speter d = SLIST_FIRST(&datareg_list); 48738032Speter while (d != NULL) { 48838032Speter d1 = SLIST_NEXT(d, link); 48938032Speter if (strcmp(hook, d->hook) == 0) 49038032Speter (*d->func)(hook, resbuf, len, d->arg); 49138032Speter d = d1; 49238032Speter } 49338032Speter 49438032Speter free(resbuf); 49538032Speter} 49638032Speter 49738032Speter/* 49838032Speter * The SNMP daemon is about to wait for an event. Look whether we have 49938032Speter * netgraph messages waiting. If yes, drain the queue. 50038032Speter */ 50138032Speterstatic void 50238032Speterng_idle(void) 50338032Speter{ 50438032Speter struct csock_buf *b; 50538032Speter 50638032Speter /* execute waiting csock_bufs */ 50738032Speter while ((b = STAILQ_FIRST(&csock_bufs)) != NULL) { 50838032Speter STAILQ_REMOVE_HEAD(&csock_bufs, link); 50938032Speter csock_handle(b->mesg, b->path); 51038032Speter free(b); 51138032Speter } 51238032Speter} 51338032Speter 51438032Speter/* 51538032Speter * Called when the module is loaded. Returning a non-zero value means, 51638032Speter * rejecting the initialisation. 51738032Speter * 51838032Speter * We make the netgraph socket. 51938032Speter */ 52038032Speterstatic int 52138032Speterng_init(struct lmodule *mod, int argc, char *argv[]) 52238032Speter{ 52338032Speter int name[2]; 52438032Speter size_t len; 52538032Speter 52638032Speter module = mod; 52738032Speter 52838032Speter if (argc == 0) { 52938032Speter if ((snmp_nodename = malloc(strlen(NODENAME) + 1)) == NULL) 53038032Speter return (ENOMEM); 53138032Speter strcpy(snmp_nodename, NODENAME); 53238032Speter } else { 53338032Speter if ((snmp_nodename = malloc(NG_NODESIZ)) == NULL) 53438032Speter return (ENOMEM); 53538032Speter strlcpy(snmp_nodename, argv[0], NG_NODESIZ); 53638032Speter } 53764562Sgshapiro 53864562Sgshapiro /* fetch clockinfo (for the number of microseconds per tick) */ 53964562Sgshapiro name[0] = CTL_KERN; 54064562Sgshapiro name[1] = KERN_CLOCKRATE; 54164562Sgshapiro len = sizeof(clockinfo); 54264562Sgshapiro if (sysctl(name, 2, &clockinfo, &len, NULL, 0) == -1) 54338032Speter return (errno); 54438032Speter 54538032Speter TAILQ_INIT(&ngtype_list); 54638032Speter 54738032Speter return (0); 54838032Speter} 54938032Speter 55038032Speter/* 55138032Speter * Get the node Id/name/type of a node. 55238032Speter */ 55342575Speterng_ID_t 55438032Speterng_node_id(const char *path) 55564562Sgshapiro{ 55638032Speter struct ng_mesg *resp; 55738032Speter ng_ID_t id; 55838032Speter 55938032Speter if ((resp = ng_dialog(path, NGM_GENERIC_COOKIE, NGM_NODEINFO, 56038032Speter NULL, 0)) == NULL) 56164562Sgshapiro return (0); 56264562Sgshapiro id = ((struct nodeinfo *)(void *)resp->data)->id; 56364562Sgshapiro free(resp); 56438032Speter return (id); 56538032Speter} 56638032Speterng_ID_t 56738032Speterng_node_id_node(const char *node) 56838032Speter{ 56938032Speter struct ng_mesg *resp; 57038032Speter ng_ID_t id; 57138032Speter 57238032Speter if ((resp = ng_dialog_node(node, NGM_GENERIC_COOKIE, NGM_NODEINFO, 57338032Speter NULL, 0)) == NULL) 57438032Speter return (0); 57538032Speter id = ((struct nodeinfo *)(void *)resp->data)->id; 57638032Speter free(resp); 57738032Speter return (id); 57838032Speter} 57938032Speterng_ID_t 58038032Speterng_node_name(ng_ID_t id, char *name) 58138032Speter{ 58238032Speter struct ng_mesg *resp; 58338032Speter 58438032Speter if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO, 58538032Speter NULL, 0)) == NULL) 58638032Speter return (0); 58738032Speter strcpy(name, ((struct nodeinfo *)(void *)resp->data)->name); 58838032Speter free(resp); 58938032Speter return (id); 59038032Speter 59138032Speter} 59238032Speterng_ID_t 59338032Speterng_node_type(ng_ID_t id, char *type) 59438032Speter{ 59538032Speter struct ng_mesg *resp; 59664562Sgshapiro 59738032Speter if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO, 59838032Speter NULL, 0)) == NULL) 59938032Speter return (0); 60038032Speter strcpy(type, ((struct nodeinfo *)(void *)resp->data)->type); 60138032Speter free(resp); 60238032Speter return (id); 60338032Speter} 60438032Speter 60538032Speter/* 60638032Speter * Connect our node to some other node 60738032Speter */ 60838032Speterint 60938032Speterng_connect_node(const char *node, const char *ourhook, const char *peerhook) 61038032Speter{ 61138032Speter struct ngm_connect conn; 61238032Speter 61338032Speter snprintf(conn.path, NG_PATHSIZ, "%s:", node); 61438032Speter strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ); 61538032Speter strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 61638032Speter return (NgSendMsg(csock, ".:", 61738032Speter NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 61838032Speter} 61938032Speterint 62038032Speterng_connect_id(ng_ID_t id, const char *ourhook, const char *peerhook) 62138032Speter{ 62238032Speter struct ngm_connect conn; 62338032Speter 62438032Speter snprintf(conn.path, NG_PATHSIZ, "[%x]:", id); 62538032Speter strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ); 62638032Speter strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 62738032Speter return (NgSendMsg(csock, ".:", 62838032Speter NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 62938032Speter} 63038032Speter 63138032Speterint 63238032Speterng_connect2_id(ng_ID_t id, ng_ID_t peer, const char *ourhook, 63338032Speter const char *peerhook) 63438032Speter{ 63538032Speter struct ngm_connect conn; 63638032Speter char path[NG_PATHSIZ]; 63764562Sgshapiro 63838032Speter snprintf(path, NG_PATHSIZ, "[%x]:", id); 63938032Speter 64038032Speter snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer); 64164562Sgshapiro strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ); 64238032Speter strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 64338032Speter return (NgSendMsg(csock, path, 64438032Speter NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 64538032Speter} 64664562Sgshapiro 64738032Speterint 64838032Speterng_connect2_tee_id(ng_ID_t id, ng_ID_t peer, const char *ourhook, 64938032Speter const char *peerhook) 65038032Speter{ 65138032Speter struct ngm_connect conn; 65238032Speter char path[NG_PATHSIZ]; 65338032Speter ng_ID_t tee; 65438032Speter 65538032Speter if ((tee = ng_mkpeer_id(id, NULL, "tee", ourhook, "left")) == 0) 65638032Speter return (-1); 65738032Speter 65838032Speter snprintf(path, NG_PATHSIZ, "[%x]:", tee); 65938032Speter 66064562Sgshapiro snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer); 66138032Speter strlcpy(conn.ourhook, "right", NG_HOOKSIZ); 66238032Speter strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ); 66338032Speter return (NgSendMsg(csock, path, 66438032Speter NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn))); 66538032Speter} 66638032Speter 66738032Speter/* 66838032Speter * Ensure that a node of type 'type' is connected to 'hook' of 'node' 66938032Speter * and return its node id. tee nodes between node and the target node 67038032Speter * are skipped. If the type is wrong, or the hook is a dead-end return 0. 67138032Speter * If type is NULL, it is not checked. 67238032Speter */ 67364562Sgshapirostatic ng_ID_t 67464562Sgshapirong_next_node_id_internal(ng_ID_t node, const char *type, const char *hook, 67538032Speter int skip_tee) 67638032Speter{ 67738032Speter struct ng_mesg *resp; 67838032Speter struct hooklist *hooklist; 67938032Speter u_int i; 68038032Speter 68138032Speter if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 68238032Speter NULL, 0)) == NULL) { 68338032Speter syslog(LOG_ERR, "get hook list: %m"); 68438032Speter exit(1); 68538032Speter } 68638032Speter hooklist = (struct hooklist *)(void *)resp->data; 68738032Speter 68838032Speter for (i = 0; i < hooklist->nodeinfo.hooks; i++) 68938032Speter if (strcmp(hooklist->link[i].ourhook, hook) == 0) 69038032Speter break; 69138032Speter 69238032Speter if (i == hooklist->nodeinfo.hooks) { 69338032Speter free(resp); 69438032Speter return (0); 69564562Sgshapiro } 69638032Speter 69738032Speter node = hooklist->link[i].nodeinfo.id; 69838032Speter 69938032Speter if (skip_tee && strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) { 70038032Speter if (strcmp(hooklist->link[i].peerhook, "left") == 0) 70138032Speter node = ng_next_node_id(node, type, "right"); 70238032Speter else if (strcmp(hooklist->link[i].peerhook, "right") == 0) 70338032Speter node = ng_next_node_id(node, type, "left"); 70438032Speter else if (type != NULL && 70538032Speter strcmp(hooklist->link[i].nodeinfo.type, type) != 0) 70638032Speter node = 0; 70738032Speter 70838032Speter } else if (type != NULL && 70938032Speter strcmp(hooklist->link[i].nodeinfo.type, type) != 0) 71038032Speter node = 0; 71138032Speter 71238032Speter free(resp); 71338032Speter 71438032Speter return (node); 71538032Speter} 71638032Speter 71738032Speter/* 71838032Speter * Ensure that a node of type 'type' is connected to 'hook' of 'node' 71938032Speter * and return its node id. tee nodes between node and the target node 72038032Speter * are skipped. If the type is wrong, or the hook is a dead-end return 0. 72138032Speter * If type is NULL, it is not checked. 72264562Sgshapiro */ 72338032Speterng_ID_t 72438032Speterng_next_node_id(ng_ID_t node, const char *type, const char *hook) 72538032Speter{ 72638032Speter return (ng_next_node_id_internal(node, type, hook, 1)); 72738032Speter} 72838032Speter 72938032Speterng_ID_t 73038032Speterng_mkpeer_id(ng_ID_t id, const char *nodename, const char *type, 73164562Sgshapiro const char *hook, const char *peerhook) 73238032Speter{ 73338032Speter char path[NG_PATHSIZ]; 73438032Speter struct ngm_mkpeer mkpeer; 73538032Speter struct ngm_name name; 73638032Speter 73764562Sgshapiro strlcpy(mkpeer.type, type, NG_TYPESIZ); 73838032Speter strlcpy(mkpeer.ourhook, hook, NG_HOOKSIZ); 73938032Speter strlcpy(mkpeer.peerhook, peerhook, NG_HOOKSIZ); 74038032Speter 74138032Speter sprintf(path, "[%x]:", id); 74238032Speter if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER, 74338032Speter &mkpeer, sizeof(mkpeer)) == -1) 74438032Speter return (0); 74538032Speter 74638032Speter if ((id = ng_next_node_id_internal(id, NULL, hook, 0)) == 0) 74738032Speter return (0); 74838032Speter 74938032Speter if (nodename != NULL) { 75038032Speter strcpy(name.name, nodename); 75138032Speter sprintf(path, "[%x]:", id); 75238032Speter if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_NAME, 75338032Speter &name, sizeof(name)) == -1) 75438032Speter return (0); 75538032Speter } 75638032Speter return (id); 75738032Speter} 75838032Speter 75938032Speter/* 76038032Speter * SHutdown node 76138032Speter */ 76238032Speterint 76364562Sgshapirong_shutdown_id(ng_ID_t id) 76438032Speter{ 76564562Sgshapiro char path[NG_PATHSIZ]; 76664562Sgshapiro 76738032Speter snprintf(path, NG_PATHSIZ, "[%x]:", id); 76838032Speter return (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, 76938032Speter NGM_SHUTDOWN, NULL, 0)); 77038032Speter} 77138032Speter 77238032Speter/* 77338032Speter * Disconnect one of our hooks 77438032Speter */ 77538032Speterint 77638032Speterng_rmhook(const char *ourhook) 77764562Sgshapiro{ 77838032Speter struct ngm_rmhook rmhook; 77938032Speter 78038032Speter strlcpy(rmhook.ourhook, ourhook, NG_HOOKSIZ); 78138032Speter return (NgSendMsg(csock, ".:", 78238032Speter NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook))); 78364562Sgshapiro} 78438032Speter 78564562Sgshapiro/* 78638032Speter * Disconnect a hook of a node 78738032Speter */ 78838032Speterint 78964562Sgshapirong_rmhook_id(ng_ID_t id, const char *hook) 79038032Speter{ 79138032Speter struct ngm_rmhook rmhook; 79238032Speter char path[NG_PATHSIZ]; 79364562Sgshapiro 79438032Speter strlcpy(rmhook.ourhook, hook, NG_HOOKSIZ); 79564562Sgshapiro snprintf(path, NG_PATHSIZ, "[%x]:", id); 79638032Speter return (NgSendMsg(csock, path, 79738032Speter NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook))); 79838032Speter} 79938032Speter 80038032Speter/* 80138032Speter * Disconnect a hook and shutdown all tee nodes that were connected to that 80238032Speter * hook. 80338032Speter */ 80438032Speterint 80538032Speterng_rmhook_tee_id(ng_ID_t node, const char *hook) 80638032Speter{ 80738032Speter struct ng_mesg *resp; 80838032Speter struct hooklist *hooklist; 80938032Speter u_int i; 81038032Speter int first = 1; 81138032Speter ng_ID_t next_node; 81238032Speter const char *next_hook; 81338032Speter 81438032Speter again: 81538032Speter /* if we have just shutdown a tee node, which had no other hooks 81638032Speter * connected, the node id may already be wrong here. */ 81738032Speter if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 81838032Speter NULL, 0)) == NULL) 81938032Speter return (0); 82038032Speter 82138032Speter hooklist = (struct hooklist *)(void *)resp->data; 82238032Speter 82338032Speter for (i = 0; i < hooklist->nodeinfo.hooks; i++) 82438032Speter if (strcmp(hooklist->link[i].ourhook, hook) == 0) 82538032Speter break; 82638032Speter 82738032Speter if (i == hooklist->nodeinfo.hooks) { 82838032Speter free(resp); 82938032Speter return (0); 83038032Speter } 83138032Speter 83238032Speter next_node = 0; 83338032Speter next_hook = NULL; 83438032Speter if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) { 83538032Speter if (strcmp(hooklist->link[i].peerhook, "left") == 0) { 83638032Speter next_node = hooklist->link[i].nodeinfo.id; 83738032Speter next_hook = "right"; 83838032Speter } else if (strcmp(hooklist->link[i].peerhook, "right") == 0) { 83938032Speter next_node = hooklist->link[i].nodeinfo.id; 84038032Speter next_hook = "left"; 84138032Speter } 84238032Speter } 84338032Speter free(resp); 84438032Speter 84538032Speter if (first) { 84664562Sgshapiro ng_rmhook_id(node, hook); 84738032Speter first = 0; 84838032Speter } else { 84938032Speter ng_shutdown_id(node); 85038032Speter } 85138032Speter if ((node = next_node) == 0) 85238032Speter return (0); 85338032Speter hook = next_hook; 85438032Speter 85538032Speter goto again; 85638032Speter} 85738032Speter 85838032Speter/* 85938032Speter * Get the peer hook of a hook on a given node. Skip any tee nodes in between 86038032Speter */ 86138032Speterint 86238032Speterng_peer_hook_id(ng_ID_t node, const char *hook, char *peerhook) 86338032Speter{ 86438032Speter struct ng_mesg *resp; 86538032Speter struct hooklist *hooklist; 86638032Speter u_int i; 86738032Speter int ret; 86838032Speter 86938032Speter if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS, 87064562Sgshapiro NULL, 0)) == NULL) { 87138032Speter syslog(LOG_ERR, "get hook list: %m"); 87238032Speter exit(1); 87338032Speter } 87438032Speter hooklist = (struct hooklist *)(void *)resp->data; 87538032Speter 87638032Speter for (i = 0; i < hooklist->nodeinfo.hooks; i++) 87738032Speter if (strcmp(hooklist->link[i].ourhook, hook) == 0) 87871345Sgshapiro break; 87938032Speter 88071345Sgshapiro if (i == hooklist->nodeinfo.hooks) { 88171345Sgshapiro free(resp); 88238032Speter return (-1); 88338032Speter } 88438032Speter 88538032Speter node = hooklist->link[i].nodeinfo.id; 88638032Speter 88738032Speter ret = 0; 88838032Speter if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) { 88938032Speter if (strcmp(hooklist->link[i].peerhook, "left") == 0) 89038032Speter ret = ng_peer_hook_id(node, "right", peerhook); 89138032Speter else if (strcmp(hooklist->link[i].peerhook, "right") == 0) 89238032Speter ret = ng_peer_hook_id(node, "left", peerhook); 89338032Speter else 89438032Speter strcpy(peerhook, hooklist->link[i].peerhook); 89538032Speter 89638032Speter } else 89738032Speter strcpy(peerhook, hooklist->link[i].peerhook); 89838032Speter 89938032Speter free(resp); 90038032Speter 90138032Speter return (ret); 90238032Speter} 90338032Speter 90438032Speter 90538032Speter/* 90638032Speter * Now the module is started. Select on the sockets, so that we can get 90738032Speter * unsolicited input. 90838032Speter */ 90938032Speterstatic void 91038032Speterng_start(void) 91138032Speter{ 91238032Speter if (snmp_node == 0) { 91371345Sgshapiro if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) { 91471345Sgshapiro syslog(LOG_ERR, "NgMkSockNode: %m"); 91538032Speter exit(1); 91638032Speter } 91738032Speter snmp_node = ng_node_id(".:"); 91838032Speter } 91938032Speter 92071345Sgshapiro if ((csock_fd = fd_select(csock, csock_input, NULL, module)) == NULL) { 92138032Speter syslog(LOG_ERR, "fd_select failed on csock: %m"); 92238032Speter return; 92338032Speter } 92438032Speter if ((dsock_fd = fd_select(dsock, dsock_input, NULL, module)) == NULL) { 92538032Speter syslog(LOG_ERR, "fd_select failed on dsock: %m"); 92638032Speter return; 92738032Speter } 92838032Speter 92938032Speter reg_index = or_register(&oid_begemotNg, 93038032Speter "The MIB for the NetGraph access module for SNMP.", module); 93138032Speter} 93238032Speter 93338032Speter/* 93438032Speter * Called, when the module is to be unloaded after it was successfully loaded 93538032Speter */ 93638032Speterstatic int 93738032Speterng_fini(void) 93838032Speter{ 93938032Speter struct ngtype *t; 94038032Speter 94138032Speter while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) { 94238032Speter TAILQ_REMOVE(&ngtype_list, t, link); 94338032Speter free(t); 94438032Speter } 94538032Speter 94638032Speter if (csock_fd != NULL) 94738032Speter fd_deselect(csock_fd); 94838032Speter (void)close(csock); 94938032Speter 95071345Sgshapiro if (dsock_fd != NULL) 95171345Sgshapiro fd_deselect(dsock_fd); 95238032Speter (void)close(dsock); 95338032Speter 95438032Speter free(snmp_nodename); 95538032Speter 95638032Speter or_unregister(reg_index); 95738032Speter 95871345Sgshapiro return (0); 95971345Sgshapiro} 96038032Speter 96138032Speterconst struct snmp_module config = { 96238032Speter "This module implements access to the netgraph sub-system", 96338032Speter ng_init, 96438032Speter ng_fini, 96538032Speter ng_idle, 96664562Sgshapiro NULL, 96764562Sgshapiro NULL, 96864562Sgshapiro ng_start, 96964562Sgshapiro NULL, 97064562Sgshapiro netgraph_ctree, 97164562Sgshapiro netgraph_CTREE_SIZE, 97264562Sgshapiro NULL 97364562Sgshapiro}; 97464562Sgshapiro 97564562Sgshapiroint 97638032Speterop_ng_config(struct snmp_context *ctx, struct snmp_value *value, 97738032Speter u_int sub, u_int iidx __unused, enum snmp_op op) 97838032Speter{ 97938032Speter asn_subid_t which = value->var.subs[sub - 1]; 98038032Speter int ret; 98138032Speter 98238032Speter switch (op) { 98338032Speter 98438032Speter case SNMP_OP_GETNEXT: 98538032Speter abort(); 98638032Speter 98738032Speter case SNMP_OP_GET: 98838032Speter /* 98938032Speter * Come here for GET, GETNEXT and COMMIT 99071345Sgshapiro */ 99171345Sgshapiro switch (which) { 99238032Speter 99338032Speter case LEAF_begemotNgControlNodeName: 99438032Speter return (string_get(value, snmp_nodename, -1)); 99538032Speter 99638032Speter case LEAF_begemotNgResBufSiz: 99771345Sgshapiro value->v.integer = resbufsiz; 99871345Sgshapiro break; 99938032Speter 100038032Speter case LEAF_begemotNgTimeout: 100138032Speter value->v.integer = timeout; 100238032Speter break; 100338032Speter 100438032Speter case LEAF_begemotNgDebugLevel: 100538032Speter value->v.uint32 = debug_level; 100638032Speter break; 100738032Speter 100838032Speter default: 100938032Speter abort(); 101038032Speter } 101138032Speter return (SNMP_ERR_NOERROR); 101238032Speter 101338032Speter case SNMP_OP_SET: 101438032Speter switch (which) { 101538032Speter 101638032Speter case LEAF_begemotNgControlNodeName: 101738032Speter /* only at initialisation */ 101838032Speter if (community != COMM_INITIALIZE) 101938032Speter return (SNMP_ERR_NOT_WRITEABLE); 102038032Speter 102138032Speter if (snmp_node != 0) 102238032Speter return (SNMP_ERR_NOT_WRITEABLE); 102338032Speter 102438032Speter if ((ret = string_save(value, ctx, -1, &snmp_nodename)) 102538032Speter != SNMP_ERR_NOERROR) 102638032Speter return (ret); 102738032Speter 102838032Speter if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) { 102938032Speter syslog(LOG_ERR, "NgMkSockNode: %m"); 103038032Speter string_rollback(ctx, &snmp_nodename); 103138032Speter return (SNMP_ERR_GENERR); 103238032Speter } 103338032Speter snmp_node = ng_node_id(".:"); 103438032Speter 103538032Speter return (SNMP_ERR_NOERROR); 103638032Speter 103738032Speter case LEAF_begemotNgResBufSiz: 103838032Speter ctx->scratch->int1 = resbufsiz; 103938032Speter if (value->v.integer < 1024 || 104038032Speter value->v.integer > 0x10000) 104138032Speter return (SNMP_ERR_WRONG_VALUE); 104238032Speter resbufsiz = value->v.integer; 104338032Speter return (SNMP_ERR_NOERROR); 104438032Speter 104538032Speter case LEAF_begemotNgTimeout: 104638032Speter ctx->scratch->int1 = timeout; 104771345Sgshapiro if (value->v.integer < 10 || 104838032Speter value->v.integer > 10000) 104938032Speter return (SNMP_ERR_WRONG_VALUE); 105071345Sgshapiro timeout = value->v.integer; 105171345Sgshapiro return (SNMP_ERR_NOERROR); 105238032Speter 105338032Speter case LEAF_begemotNgDebugLevel: 105471345Sgshapiro ctx->scratch->int1 = debug_level; 105538032Speter debug_level = value->v.uint32; 105671345Sgshapiro NgSetDebug(debug_level); 105771345Sgshapiro return (SNMP_ERR_NOERROR); 105838032Speter } 105938032Speter abort(); 106038032Speter 106138032Speter case SNMP_OP_ROLLBACK: 106238032Speter switch (which) { 106338032Speter 106438032Speter case LEAF_begemotNgControlNodeName: 106538032Speter string_rollback(ctx, &snmp_nodename); 106638032Speter close(csock); 106738032Speter close(dsock); 106838032Speter snmp_node = 0; 106938032Speter return (SNMP_ERR_NOERROR); 107038032Speter 107138032Speter case LEAF_begemotNgResBufSiz: 107238032Speter resbufsiz = ctx->scratch->int1; 107338032Speter return (SNMP_ERR_NOERROR); 107438032Speter 107538032Speter case LEAF_begemotNgTimeout: 107638032Speter timeout = ctx->scratch->int1; 107738032Speter return (SNMP_ERR_NOERROR); 107838032Speter 107938032Speter case LEAF_begemotNgDebugLevel: 108038032Speter debug_level = ctx->scratch->int1; 108138032Speter NgSetDebug(debug_level); 108238032Speter return (SNMP_ERR_NOERROR); 108338032Speter } 108438032Speter abort(); 108538032Speter 108638032Speter case SNMP_OP_COMMIT: 108738032Speter switch (which) { 108871345Sgshapiro 108938032Speter case LEAF_begemotNgControlNodeName: 109038032Speter string_commit(ctx); 109171345Sgshapiro return (SNMP_ERR_NOERROR); 109271345Sgshapiro 109338032Speter case LEAF_begemotNgResBufSiz: 109438032Speter case LEAF_begemotNgTimeout: 109571345Sgshapiro case LEAF_begemotNgDebugLevel: 109638032Speter return (SNMP_ERR_NOERROR); 109771345Sgshapiro } 109871345Sgshapiro abort(); 109938032Speter } 110038032Speter abort(); 110138032Speter} 110238032Speter 110338032Speterint 110438032Speterop_ng_stats(struct snmp_context *ctx __unused, struct snmp_value *value, 110538032Speter u_int sub, u_int iidx __unused, enum snmp_op op) 110638032Speter{ 110764562Sgshapiro switch (op) { 110864562Sgshapiro 110964562Sgshapiro case SNMP_OP_GETNEXT: 111064562Sgshapiro abort(); 111164562Sgshapiro 111264562Sgshapiro case SNMP_OP_GET: 111364562Sgshapiro value->v.uint32 = stats[value->var.subs[sub - 1] - 1]; 111464562Sgshapiro return (SNMP_ERR_NOERROR); 111564562Sgshapiro 111664562Sgshapiro case SNMP_OP_SET: 111764562Sgshapiro return (SNMP_ERR_NOT_WRITEABLE); 111864562Sgshapiro 111964562Sgshapiro case SNMP_OP_ROLLBACK: 112064562Sgshapiro case SNMP_OP_COMMIT: 112164562Sgshapiro abort(); 112264562Sgshapiro } 112364562Sgshapiro abort(); 112438032Speter} 112538032Speter 112638032Speter/* 112738032Speter * Netgraph type table 112838032Speter */ 112938032Speterstatic int 113038032Speterfetch_types(void) 113138032Speter{ 113238032Speter struct ngtype *t; 113338032Speter struct typelist *typelist; 113438032Speter struct ng_mesg *resp; 113538032Speter u_int u, i; 113638032Speter 113738032Speter if (this_tick <= ngtype_tick) 113838032Speter return (0); 113938032Speter 114038032Speter while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) { 114138032Speter TAILQ_REMOVE(&ngtype_list, t, link); 114238032Speter free(t); 114338032Speter } 114438032Speter 114538032Speter if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, 114638032Speter NGM_LISTTYPES, NULL, 0)) == NULL) 114764562Sgshapiro return (SNMP_ERR_GENERR); 114864562Sgshapiro typelist = (struct typelist *)(void *)resp->data; 114964562Sgshapiro 115064562Sgshapiro for (u = 0; u < typelist->numtypes; u++) { 115164562Sgshapiro if ((t = malloc(sizeof(*t))) == NULL) { 115238032Speter free(resp); 115338032Speter return (SNMP_ERR_GENERR); 115438032Speter } 115538032Speter strcpy(t->name, typelist->typeinfo[u].type_name); 115638032Speter t->index.subs[0] = strlen(t->name); 115738032Speter t->index.len = t->index.subs[0] + 1; 115838032Speter for (i = 0; i < t->index.subs[0]; i++) 115938032Speter t->index.subs[i + 1] = t->name[i]; 116038032Speter 116164562Sgshapiro INSERT_OBJECT_OID(t, &ngtype_list); 116238032Speter } 116366494Sgshapiro 116464562Sgshapiro ngtype_tick = this_tick; 116564562Sgshapiro 116671345Sgshapiro free(resp); 116766494Sgshapiro return (0); 116864562Sgshapiro} 116964562Sgshapiro 117066494Sgshapiro/* 117138032Speter * Try to load the netgraph type with the given name. We assume, that 117238032Speter * type 'type' is implemented in the kernel module 'ng_type'. 117366494Sgshapiro */ 117464562Sgshapirostatic int 117566494Sgshapirongtype_load(const u_char *name, size_t namelen) 117664562Sgshapiro{ 117764562Sgshapiro char *mod; 117838032Speter int ret; 117964562Sgshapiro 118064562Sgshapiro if ((mod = malloc(namelen + 4)) == NULL) 118164562Sgshapiro return (-1); 118264562Sgshapiro strcpy(mod, "ng_"); 118364562Sgshapiro strncpy(mod + 3, name, namelen); 118464562Sgshapiro mod[namelen + 3] = '\0'; 118571345Sgshapiro 118664562Sgshapiro ret = kldload(mod); 118766494Sgshapiro free(mod); 118864562Sgshapiro return (ret); 118966494Sgshapiro} 119064562Sgshapiro 119164562Sgshapiro/* 119266494Sgshapiro * Unload a netgraph type. 119364562Sgshapiro */ 119464562Sgshapirostatic int 119564562Sgshapirongtype_unload(const u_char *name, size_t namelen) 119664562Sgshapiro{ 119764562Sgshapiro char *mod; 119864562Sgshapiro int id; 119964562Sgshapiro 120064562Sgshapiro if ((mod = malloc(namelen + 4)) == NULL) 120164562Sgshapiro return (-1); 120264562Sgshapiro strcpy(mod, "ng_"); 120364562Sgshapiro strncpy(mod + 3, name, namelen); 120464562Sgshapiro mod[namelen + 3] = '\0'; 120564562Sgshapiro 120664562Sgshapiro if ((id = kldfind(mod)) == -1) { 120764562Sgshapiro free(mod); 120864562Sgshapiro return (-1); 120938032Speter } 121038032Speter free(mod); 121138032Speter return (kldunload(id)); 121238032Speter} 121338032Speter 121438032Speterint 121538032Speterop_ng_type(struct snmp_context *ctx, struct snmp_value *value, 121638032Speter u_int sub, u_int iidx, enum snmp_op op) 121771345Sgshapiro{ 121838032Speter asn_subid_t which = value->var.subs[sub - 1]; 121938032Speter struct ngtype *t; 122038032Speter u_char *name; 122138032Speter size_t namelen; 122238032Speter int status = 1; 122371345Sgshapiro int ret; 122438032Speter 122538032Speter switch (op) { 122638032Speter 122764562Sgshapiro case SNMP_OP_GETNEXT: 122864562Sgshapiro if ((ret = fetch_types()) != 0) 122964562Sgshapiro return (ret); 123064562Sgshapiro if ((t = NEXT_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL) 123164562Sgshapiro return (SNMP_ERR_NOSUCHNAME); 123264562Sgshapiro index_append(&value->var, sub, &t->index); 123364562Sgshapiro break; 123464562Sgshapiro 123564562Sgshapiro case SNMP_OP_GET: 123664562Sgshapiro if ((ret = fetch_types()) != 0) 123764562Sgshapiro return (ret); 123864562Sgshapiro if ((t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL) 123964562Sgshapiro return (SNMP_ERR_NOSUCHNAME); 124064562Sgshapiro break; 124164562Sgshapiro 124264562Sgshapiro case SNMP_OP_SET: 124364562Sgshapiro if (index_decode(&value->var, sub, iidx, &name, &namelen)) 124438032Speter return (SNMP_ERR_NO_CREATION); 124538032Speter if (namelen == 0 || namelen >= NG_TYPESIZ) { 124638032Speter free(name); 124738032Speter return (SNMP_ERR_NO_CREATION); 124838032Speter } 124938032Speter if ((ret = fetch_types()) != 0) { 125038032Speter free(name); 125138032Speter return (ret); 125238032Speter } 125338032Speter t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub); 125438032Speter 125538032Speter if (which != LEAF_begemotNgTypeStatus) { 125638032Speter free(name); 125738032Speter if (t != NULL) 125838032Speter return (SNMP_ERR_NOT_WRITEABLE); 125938032Speter return (SNMP_ERR_NO_CREATION); 126038032Speter } 126138032Speter if (!TRUTH_OK(value->v.integer)) { 126238032Speter free(name); 126338032Speter return (SNMP_ERR_WRONG_VALUE); 126438032Speter } 126538032Speter ctx->scratch->int1 = TRUTH_GET(value->v.integer); 126638032Speter ctx->scratch->int1 |= (t != NULL) << 1; 126738032Speter ctx->scratch->ptr2 = name; 126838032Speter ctx->scratch->int2 = namelen; 126938032Speter 127038032Speter if (t == NULL) { 127138032Speter /* type not loaded */ 127238032Speter if (ctx->scratch->int1 & 1) { 127338032Speter /* request to load */ 127438032Speter if (ngtype_load(name, namelen) == -1) { 127538032Speter free(name); 127638032Speter if (errno == ENOENT) 127738032Speter return (SNMP_ERR_INCONS_NAME); 127838032Speter else 127938032Speter return (SNMP_ERR_GENERR); 128038032Speter } 128138032Speter } 128238032Speter } else { 128338032Speter /* is type loaded */ 128438032Speter if (!(ctx->scratch->int1 & 1)) { 128538032Speter /* request to unload */ 128638032Speter if (ngtype_unload(name, namelen) == -1) { 128738032Speter free(name); 128838032Speter return (SNMP_ERR_GENERR); 128938032Speter } 129064562Sgshapiro } 129164562Sgshapiro } 129264562Sgshapiro return (SNMP_ERR_NOERROR); 129364562Sgshapiro 129438032Speter case SNMP_OP_ROLLBACK: 129538032Speter ret = SNMP_ERR_NOERROR; 129638032Speter if (!(ctx->scratch->int1 & 2)) { 129738032Speter /* did not exist */ 129838032Speter if (ctx->scratch->int1 & 1) { 129938032Speter /* request to load - unload */ 130038032Speter if (ngtype_unload(ctx->scratch->ptr2, 130138032Speter ctx->scratch->int2) == -1) 130238032Speter ret = SNMP_ERR_UNDO_FAILED; 130338032Speter } 130438032Speter } else { 130538032Speter /* did exist */ 130638032Speter if (!(ctx->scratch->int1 & 1)) { 130738032Speter /* request to unload - reload */ 130838032Speter if (ngtype_load(ctx->scratch->ptr2, 130938032Speter ctx->scratch->int2) == -1) 131038032Speter ret = SNMP_ERR_UNDO_FAILED; 131138032Speter } 131238032Speter } 131338032Speter free(ctx->scratch->ptr2); 131438032Speter return (ret); 131538032Speter 131638032Speter case SNMP_OP_COMMIT: 131738032Speter free(ctx->scratch->ptr2); 131838032Speter return (SNMP_ERR_NOERROR); 131938032Speter 132038032Speter default: 132138032Speter abort(); 132238032Speter } 132338032Speter 132438032Speter /* 132538032Speter * Come here for GET and COMMIT 132638032Speter */ 132738032Speter switch (which) { 132838032Speter 132938032Speter case LEAF_begemotNgTypeStatus: 133038032Speter value->v.integer = status; 133138032Speter break; 133238032Speter 133338032Speter default: 133438032Speter abort(); 133538032Speter } 133638032Speter return (SNMP_ERR_NOERROR); 133738032Speter} 133838032Speter 133938032Speter/* 134038032Speter * Implement the node table 134138032Speter */ 134238032Speterstatic int 134338032Speterfind_node(const struct asn_oid *oid, u_int sub, struct nodeinfo *info) 134438032Speter{ 134538032Speter ng_ID_t id = oid->subs[sub]; 134638032Speter struct ng_mesg *resp; 134738032Speter 134838032Speter if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO, 134964562Sgshapiro NULL, 0)) == NULL) 135038032Speter return (-1); 135138032Speter 135238032Speter *info = *(struct nodeinfo *)(void *)resp->data; 135338032Speter free(resp); 135438032Speter return (0); 135538032Speter} 135638032Speter 135738032Speterstatic int 135838032Speterncmp(const void *p1, const void *p2) 135938032Speter{ 136038032Speter const struct nodeinfo *i1 = p1; 136138032Speter const struct nodeinfo *i2 = p2; 136238032Speter 136338032Speter if (i1->id < i2->id) 136464562Sgshapiro return (-1); 136538032Speter if (i1->id > i2->id) 136638032Speter return (+1); 136738032Speter return (0); 136838032Speter} 136938032Speter 137038032Speterstatic int 137138032Speterfind_node_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *info) 137238032Speter{ 137338032Speter u_int idxlen = oid->len - sub; 137438032Speter struct ng_mesg *resp; 137538032Speter struct namelist *list; 137638032Speter ng_ID_t id; 137738032Speter u_int i; 137838032Speter 137938032Speter if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES, 138038032Speter NULL, 0)) == NULL) 138138032Speter return (-1); 138238032Speter list = (struct namelist *)(void *)resp->data; 138338032Speter 138438032Speter qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp); 138538032Speter 138638032Speter if (idxlen == 0) { 138738032Speter if (list->numnames == 0) { 138864562Sgshapiro free(resp); 138938032Speter return (-1); 139064562Sgshapiro } 139138032Speter *info = list->nodeinfo[0]; 139238032Speter free(resp); 139338032Speter return (0); 139438032Speter } 139538032Speter id = oid->subs[sub]; 139638032Speter 139738032Speter for (i = 0; i < list->numnames; i++) 139838032Speter if (list->nodeinfo[i].id > id) { 139938032Speter *info = list->nodeinfo[i]; 140038032Speter free(resp); 140138032Speter return (0); 140238032Speter } 140338032Speter 140438032Speter free(resp); 140538032Speter return (-1); 140638032Speter} 140738032Speter 140838032Speterint 140938032Speterop_ng_node(struct snmp_context *ctx __unused, struct snmp_value *value, 141038032Speter u_int sub, u_int iidx __unused, enum snmp_op op) 141138032Speter{ 141238032Speter asn_subid_t which = value->var.subs[sub - 1]; 141338032Speter u_int idxlen = value->var.len - sub; 141438032Speter struct nodeinfo nodeinfo; 141538032Speter 141638032Speter switch (op) { 141738032Speter 141838032Speter case SNMP_OP_GETNEXT: 141938032Speter if (find_node_next(&value->var, sub, &nodeinfo) == -1) 142038032Speter return (SNMP_ERR_NOSUCHNAME); 142138032Speter value->var.len = sub + 1; 142238032Speter value->var.subs[sub] = nodeinfo.id; 142338032Speter break; 142438032Speter 142538032Speter case SNMP_OP_GET: 142638032Speter if (idxlen != 1) 142738032Speter return (SNMP_ERR_NOSUCHNAME); 142838032Speter if (find_node(&value->var, sub, &nodeinfo) == -1) 142938032Speter return (SNMP_ERR_NOSUCHNAME); 143038032Speter break; 143138032Speter 143238032Speter case SNMP_OP_SET: 143338032Speter if (idxlen != 1) 143438032Speter return (SNMP_ERR_NO_CREATION); 143538032Speter if (find_node(&value->var, sub, &nodeinfo) == -1) 143638032Speter return (SNMP_ERR_NO_CREATION); 143738032Speter return (SNMP_ERR_NOT_WRITEABLE); 143838032Speter 143938032Speter case SNMP_OP_ROLLBACK: 144038032Speter case SNMP_OP_COMMIT: 144138032Speter default: 144264562Sgshapiro abort(); 144364562Sgshapiro } 144464562Sgshapiro 144564562Sgshapiro /* 144664562Sgshapiro * Come here for GET and COMMIT 144764562Sgshapiro */ 144864562Sgshapiro switch (which) { 144964562Sgshapiro 145064562Sgshapiro case LEAF_begemotNgNodeStatus: 145164562Sgshapiro value->v.integer = 1; 145264562Sgshapiro break; 145364562Sgshapiro case LEAF_begemotNgNodeName: 145464562Sgshapiro return (string_get(value, nodeinfo.name, -1)); 145564562Sgshapiro case LEAF_begemotNgNodeType: 145664562Sgshapiro return (string_get(value, nodeinfo.type, -1)); 145764562Sgshapiro case LEAF_begemotNgNodeHooks: 145864562Sgshapiro value->v.uint32 = nodeinfo.hooks; 145964562Sgshapiro break; 146064562Sgshapiro 146138032Speter default: 146238032Speter abort(); 146338032Speter } 146438032Speter return (SNMP_ERR_NOERROR); 146538032Speter} 146638032Speter 146738032Speter/* 146838032Speter * Implement the hook table 146938032Speter */ 147038032Speterstatic int 147138032Speterfind_hook(int32_t id, const u_char *hook, size_t hooklen, struct linkinfo *info) 147264562Sgshapiro{ 147364562Sgshapiro struct ng_mesg *resp; 147464562Sgshapiro struct hooklist *list; 147538032Speter u_int i; 147638032Speter 147738032Speter if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, 147838032Speter NGM_LISTHOOKS, NULL, 0)) == NULL) 147938032Speter return (-1); 148038032Speter 148138032Speter list = (struct hooklist *)(void *)resp->data; 148238032Speter 148338032Speter for (i = 0; i < list->nodeinfo.hooks; i++) { 148438032Speter if (strlen(list->link[i].ourhook) == hooklen && 148538032Speter strncmp(list->link[i].ourhook, hook, hooklen) == 0) { 148638032Speter *info = list->link[i]; 148738032Speter free(resp); 148838032Speter return (0); 148938032Speter } 149038032Speter } 149138032Speter free(resp); 149238032Speter return (-1); 149338032Speter} 149438032Speter 149538032Speterstatic int 149638032Speterhook_cmp(const void *p1, const void *p2) 149738032Speter{ 149838032Speter const struct linkinfo *i1 = p1; 149938032Speter const struct linkinfo *i2 = p2; 150038032Speter 150138032Speter if (strlen(i1->ourhook) < strlen(i2->ourhook)) 150238032Speter return (-1); 150338032Speter if (strlen(i1->ourhook) > strlen(i2->ourhook)) 150438032Speter return (+1); 150538032Speter return (strcmp(i1->ourhook, i2->ourhook)); 150638032Speter} 150738032Speter 150838032Speterstatic int 150964562Sgshapirofind_hook_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *nodeinfo, 151038032Speter struct linkinfo *linkinfo) 151138032Speter{ 151238032Speter u_int idxlen = oid->len - sub; 151364562Sgshapiro struct namelist *list; 151438032Speter struct ng_mesg *resp; 151538032Speter struct hooklist *hooks; 151638032Speter struct ng_mesg *resp1; 151738032Speter u_int node_index; 151838032Speter struct asn_oid idx; 151938032Speter u_int i, j; 152038032Speter 152138032Speter /* 152238032Speter * Get and sort Node list 152338032Speter */ 152438032Speter if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES, 152538032Speter NULL, 0)) == NULL) 152638032Speter return (-1); 152738032Speter list = (struct namelist *)(void *)resp->data; 152838032Speter 152938032Speter qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp); 153038032Speter 153138032Speter /* 153264562Sgshapiro * If we have no index, take the first node and return the 153338032Speter * first hook. 153464562Sgshapiro */ 153564562Sgshapiro if (idxlen == 0) { 153664562Sgshapiro node_index = 0; 153764562Sgshapiro goto return_first_hook; 153864562Sgshapiro } 153938032Speter 154038032Speter /* 154138032Speter * Locate node 154264562Sgshapiro */ 154338032Speter for (node_index = 0; node_index < list->numnames; node_index++) 154438032Speter if (list->nodeinfo[node_index].id >= oid->subs[sub]) 154564562Sgshapiro break; 154664562Sgshapiro 154764562Sgshapiro /* 154864562Sgshapiro * If we have only the node part of the index take, or 154938032Speter * there is no node with that Id, take the first hook of that node. 155064562Sgshapiro */ 155164562Sgshapiro if (idxlen == 1 || node_index >= list->numnames || 155264562Sgshapiro list->nodeinfo[node_index].id > oid->subs[sub]) 155364562Sgshapiro goto return_first_hook; 155464562Sgshapiro 155564562Sgshapiro /* 155664562Sgshapiro * We had an exact match on the node id and have (at last part) 155764562Sgshapiro * of the hook name index. Loop through the hooks of the node 155864562Sgshapiro * and find the next one. 155964562Sgshapiro */ 156064562Sgshapiro if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id, 156164562Sgshapiro NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL) { 156264562Sgshapiro free(resp); 156364562Sgshapiro return (-1); 156464562Sgshapiro } 156564562Sgshapiro hooks = (struct hooklist *)(void *)resp1->data; 156664562Sgshapiro if (hooks->nodeinfo.hooks > 0) { 156764562Sgshapiro qsort(hooks->link, hooks->nodeinfo.hooks, 156864562Sgshapiro sizeof(hooks->link[0]), hook_cmp); 156964562Sgshapiro for (i = 0; i < hooks->nodeinfo.hooks; i++) { 157064562Sgshapiro idx.len = strlen(hooks->link[i].ourhook) + 1; 157164562Sgshapiro idx.subs[0] = idx.len - 1; 157264562Sgshapiro for (j = 0; j < idx.len; j++) 157364562Sgshapiro idx.subs[j + 1] = hooks->link[i].ourhook[j]; 157464562Sgshapiro if (index_compare(oid, sub + 1, &idx) < 0) 157564562Sgshapiro break; 157664562Sgshapiro } 157764562Sgshapiro if (i < hooks->nodeinfo.hooks) { 157864562Sgshapiro *nodeinfo = hooks->nodeinfo; 157964562Sgshapiro *linkinfo = hooks->link[i]; 158064562Sgshapiro 158164562Sgshapiro free(resp); 158264562Sgshapiro free(resp1); 158364562Sgshapiro return (0); 158464562Sgshapiro } 158564562Sgshapiro } 158664562Sgshapiro 158764562Sgshapiro /* no hook found larger than the index on the index node - take 158864562Sgshapiro * first hook of next node */ 158964562Sgshapiro free(resp1); 159064562Sgshapiro node_index++; 159164562Sgshapiro 159264562Sgshapiro return_first_hook: 159364562Sgshapiro while (node_index < list->numnames) { 159464562Sgshapiro if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id, 159564562Sgshapiro NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL) 159664562Sgshapiro break; 159764562Sgshapiro hooks = (struct hooklist *)(void *)resp1->data; 159864562Sgshapiro if (hooks->nodeinfo.hooks > 0) { 159964562Sgshapiro qsort(hooks->link, hooks->nodeinfo.hooks, 160064562Sgshapiro sizeof(hooks->link[0]), hook_cmp); 160164562Sgshapiro 160238032Speter *nodeinfo = hooks->nodeinfo; 160364562Sgshapiro *linkinfo = hooks->link[0]; 160438032Speter 160564562Sgshapiro free(resp); 160638032Speter free(resp1); 160764562Sgshapiro return (0); 160838032Speter } 160964562Sgshapiro 161038032Speter /* if we don't have hooks, try next node */ 161164562Sgshapiro free(resp1); 161238032Speter node_index++; 161364562Sgshapiro } 161438032Speter 161564562Sgshapiro free(resp); 161638032Speter return (-1); 161764562Sgshapiro} 161838032Speter 161964562Sgshapiroint 162038032Speterop_ng_hook(struct snmp_context *ctx __unused, struct snmp_value *value, 162164562Sgshapiro u_int sub, u_int iidx, enum snmp_op op) 162238032Speter{ 162364562Sgshapiro asn_subid_t which = value->var.subs[sub - 1]; 162438032Speter struct linkinfo linkinfo; 162564562Sgshapiro struct nodeinfo nodeinfo; 162638032Speter u_int32_t lid; 162764562Sgshapiro u_char *hook; 162838032Speter size_t hooklen; 162964562Sgshapiro u_int i; 163038032Speter 163164562Sgshapiro switch (op) { 163238032Speter 163364562Sgshapiro case SNMP_OP_GETNEXT: 163438032Speter if (find_hook_next(&value->var, sub, &nodeinfo, &linkinfo) == -1) 163564562Sgshapiro return (SNMP_ERR_NOSUCHNAME); 163638032Speter 163764562Sgshapiro value->var.len = sub + 1 + 1 + strlen(linkinfo.ourhook); 163838032Speter value->var.subs[sub] = nodeinfo.id; 163964562Sgshapiro value->var.subs[sub + 1] = strlen(linkinfo.ourhook); 164038032Speter for (i = 0; i < strlen(linkinfo.ourhook); i++) 164164562Sgshapiro value->var.subs[sub + i + 2] = 164238032Speter linkinfo.ourhook[i]; 164364562Sgshapiro break; 164438032Speter 164564562Sgshapiro case SNMP_OP_GET: 164638032Speter if (index_decode(&value->var, sub, iidx, &lid, 164764562Sgshapiro &hook, &hooklen)) 164838032Speter return (SNMP_ERR_NOSUCHNAME); 164964562Sgshapiro if (find_hook(lid, hook, hooklen, &linkinfo) == -1) { 165038032Speter free(hook); 165164562Sgshapiro return (SNMP_ERR_NOSUCHNAME); 165238032Speter } 165364562Sgshapiro free(hook); 165438032Speter break; 165564562Sgshapiro 165638032Speter case SNMP_OP_SET: 165764562Sgshapiro if (index_decode(&value->var, sub, iidx, &lid, 165838032Speter &hook, &hooklen)) 165964562Sgshapiro return (SNMP_ERR_NO_CREATION); 166038032Speter if (find_hook(lid, hook, hooklen, &linkinfo) == -1) { 166164562Sgshapiro free(hook); 166238032Speter return (SNMP_ERR_NO_CREATION); 166364562Sgshapiro } 166438032Speter free(hook); 166564562Sgshapiro return (SNMP_ERR_NOT_WRITEABLE); 166638032Speter 166764562Sgshapiro case SNMP_OP_ROLLBACK: 166864562Sgshapiro case SNMP_OP_COMMIT: 166964562Sgshapiro default: 167038032Speter abort(); 167164562Sgshapiro 167238032Speter } 167364562Sgshapiro 167442575Speter switch (which) { 167564562Sgshapiro 167642575Speter case LEAF_begemotNgHookStatus: 167764562Sgshapiro value->v.integer = 1; 167842575Speter break; 167964562Sgshapiro case LEAF_begemotNgHookPeerNodeId: 168043730Speter value->v.uint32 = linkinfo.nodeinfo.id; 168164562Sgshapiro break; 168264562Sgshapiro case LEAF_begemotNgHookPeerHook: 168364562Sgshapiro return (string_get(value, linkinfo.peerhook, -1)); 168464562Sgshapiro case LEAF_begemotNgHookPeerType: 168564562Sgshapiro return (string_get(value, linkinfo.nodeinfo.type, -1)); 168664562Sgshapiro default: 168764562Sgshapiro abort(); 168864562Sgshapiro } 168964562Sgshapiro return (SNMP_ERR_NOERROR); 169064562Sgshapiro} 169164562Sgshapiro