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