xref: /freebsd-src/usr.sbin/bsnmpd/modules/snmp_netgraph/snmp_netgraph.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
1259ee3d7SHartmut Brandt /*
2259ee3d7SHartmut Brandt  * Copyright (c) 2001-2003
3259ee3d7SHartmut Brandt  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4259ee3d7SHartmut Brandt  *	All rights reserved.
5259ee3d7SHartmut Brandt  *
6259ee3d7SHartmut Brandt  * Author: Harti Brandt <harti@freebsd.org>
7259ee3d7SHartmut Brandt  *
8259ee3d7SHartmut Brandt  * Redistribution of this software and documentation and use in source and
9259ee3d7SHartmut Brandt  * binary forms, with or without modification, are permitted provided that
10259ee3d7SHartmut Brandt  * the following conditions are met:
11259ee3d7SHartmut Brandt  *
12259ee3d7SHartmut Brandt  * 1. Redistributions of source code or documentation must retain the above
13259ee3d7SHartmut Brandt  *    copyright notice, this list of conditions and the following disclaimer.
14259ee3d7SHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
15259ee3d7SHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
16259ee3d7SHartmut Brandt  *    documentation and/or other materials provided with the distribution.
17259ee3d7SHartmut Brandt  *
18259ee3d7SHartmut Brandt  * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS
19259ee3d7SHartmut Brandt  * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
20259ee3d7SHartmut Brandt  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
21259ee3d7SHartmut Brandt  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
22259ee3d7SHartmut Brandt  * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS  BE LIABLE FOR ANY DIRECT, INDIRECT,
23259ee3d7SHartmut Brandt  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24259ee3d7SHartmut Brandt  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
25259ee3d7SHartmut Brandt  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
26259ee3d7SHartmut Brandt  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
27259ee3d7SHartmut Brandt  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
28259ee3d7SHartmut Brandt  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29259ee3d7SHartmut Brandt  *
30259ee3d7SHartmut Brandt  * Netgraph interface for SNMPd.
31259ee3d7SHartmut Brandt  */
32259ee3d7SHartmut Brandt #include <sys/types.h>
33259ee3d7SHartmut Brandt #include <sys/param.h>
34259ee3d7SHartmut Brandt #include <sys/linker.h>
35259ee3d7SHartmut Brandt #include <sys/socket.h>
36259ee3d7SHartmut Brandt #include <sys/syslog.h>
37259ee3d7SHartmut Brandt #include <sys/queue.h>
38259ee3d7SHartmut Brandt #include <sys/sysctl.h>
39259ee3d7SHartmut Brandt #include <stdio.h>
40259ee3d7SHartmut Brandt #include <stdlib.h>
41259ee3d7SHartmut Brandt #include <errno.h>
42259ee3d7SHartmut Brandt #include <unistd.h>
43259ee3d7SHartmut Brandt #include <string.h>
44259ee3d7SHartmut Brandt #include <netgraph.h>
45*1fea9479SHartmut Brandt #include <bsnmp/snmpmod.h>
46259ee3d7SHartmut Brandt #include "snmp_netgraph.h"
47259ee3d7SHartmut Brandt #include "netgraph_tree.h"
48259ee3d7SHartmut Brandt #include "netgraph_oid.h"
49259ee3d7SHartmut Brandt 
50259ee3d7SHartmut Brandt /* maximum message size */
51259ee3d7SHartmut Brandt #define RESBUFSIZ	20000
52259ee3d7SHartmut Brandt 
53259ee3d7SHartmut Brandt /* default node name */
54259ee3d7SHartmut Brandt #define NODENAME	"NgSnmpd"
55259ee3d7SHartmut Brandt 
56259ee3d7SHartmut Brandt /* my node Id */
57259ee3d7SHartmut Brandt ng_ID_t snmp_node;
58259ee3d7SHartmut Brandt u_char *snmp_nodename;
59259ee3d7SHartmut Brandt 
60259ee3d7SHartmut Brandt /* the Object Resource registration index */
61259ee3d7SHartmut Brandt static u_int reg_index;
62259ee3d7SHartmut Brandt static const struct asn_oid oid_begemotNg = OIDX_begemotNg;
63259ee3d7SHartmut Brandt 
64259ee3d7SHartmut Brandt /* configuration */
65259ee3d7SHartmut Brandt /* this must be smaller than int32_t because the functions in libnetgraph
66259ee3d7SHartmut Brandt  * falsely return an int */
67259ee3d7SHartmut Brandt static size_t resbufsiz = RESBUFSIZ;
68259ee3d7SHartmut Brandt static u_int timeout = 1000;
69259ee3d7SHartmut Brandt static u_int debug_level;
70259ee3d7SHartmut Brandt 
71259ee3d7SHartmut Brandt /* number of microseconds per clock tick */
72259ee3d7SHartmut Brandt static struct clockinfo clockinfo;
73259ee3d7SHartmut Brandt 
74259ee3d7SHartmut Brandt /* Csock buffers. Communication on the csock is asynchronuous. This means
75259ee3d7SHartmut Brandt  * if we wait for a specific response, we may get other messages. Put these
76259ee3d7SHartmut Brandt  * into a queue and execute them when we are idle. */
77259ee3d7SHartmut Brandt struct csock_buf {
78259ee3d7SHartmut Brandt 	STAILQ_ENTRY(csock_buf) link;
79259ee3d7SHartmut Brandt 	struct ng_mesg *mesg;
8089624a34SHartmut Brandt 	char path[NG_PATHSIZ];
81259ee3d7SHartmut Brandt };
82259ee3d7SHartmut Brandt static STAILQ_HEAD(, csock_buf) csock_bufs =
83259ee3d7SHartmut Brandt 	STAILQ_HEAD_INITIALIZER(csock_bufs);
84259ee3d7SHartmut Brandt 
85259ee3d7SHartmut Brandt /*
86259ee3d7SHartmut Brandt  * We dispatch unsolicieted messages by node cookies and ids.
87259ee3d7SHartmut Brandt  * So we must keep a list of hook names and dispatch functions.
88259ee3d7SHartmut Brandt  */
89259ee3d7SHartmut Brandt struct msgreg {
90259ee3d7SHartmut Brandt 	u_int32_t 	cookie;
91259ee3d7SHartmut Brandt 	ng_ID_t		id;
92259ee3d7SHartmut Brandt 	ng_cookie_f	*func;
93259ee3d7SHartmut Brandt 	void		*arg;
94259ee3d7SHartmut Brandt 	const struct lmodule *mod;
95259ee3d7SHartmut Brandt 	SLIST_ENTRY(msgreg) link;
96259ee3d7SHartmut Brandt };
97259ee3d7SHartmut Brandt static SLIST_HEAD(, msgreg) msgreg_list =
98259ee3d7SHartmut Brandt 	SLIST_HEAD_INITIALIZER(msgreg_list);
99259ee3d7SHartmut Brandt 
100259ee3d7SHartmut Brandt /*
101259ee3d7SHartmut Brandt  * Data messages are dispatched by hook names.
102259ee3d7SHartmut Brandt  */
103259ee3d7SHartmut Brandt struct datareg {
10489624a34SHartmut Brandt 	char		hook[NG_HOOKSIZ];
105259ee3d7SHartmut Brandt 	ng_hook_f	*func;
106259ee3d7SHartmut Brandt 	void		*arg;
107259ee3d7SHartmut Brandt 	const struct lmodule *mod;
108259ee3d7SHartmut Brandt 	SLIST_ENTRY(datareg) link;
109259ee3d7SHartmut Brandt };
110259ee3d7SHartmut Brandt static SLIST_HEAD(, datareg) datareg_list =
111259ee3d7SHartmut Brandt 	SLIST_HEAD_INITIALIZER(datareg_list);
112259ee3d7SHartmut Brandt 
113259ee3d7SHartmut Brandt /* the netgraph sockets */
114259ee3d7SHartmut Brandt static int csock, dsock;
115259ee3d7SHartmut Brandt static void *csock_fd, *dsock_fd;
116259ee3d7SHartmut Brandt 
117259ee3d7SHartmut Brandt /* our module handle */
118259ee3d7SHartmut Brandt static struct lmodule *module;
119259ee3d7SHartmut Brandt 
120259ee3d7SHartmut Brandt /* statistics */
121259ee3d7SHartmut Brandt static u_int32_t stats[LEAF_begemotNgTooLargeDatas+1];
122259ee3d7SHartmut Brandt 
123259ee3d7SHartmut Brandt /* netgraph type list */
124259ee3d7SHartmut Brandt struct ngtype {
12589624a34SHartmut Brandt 	char		name[NG_TYPESIZ];
126259ee3d7SHartmut Brandt 	struct asn_oid	index;
127259ee3d7SHartmut Brandt 	TAILQ_ENTRY(ngtype) link;
128259ee3d7SHartmut Brandt };
129259ee3d7SHartmut Brandt TAILQ_HEAD(ngtype_list, ngtype);
130259ee3d7SHartmut Brandt 
131259ee3d7SHartmut Brandt static struct ngtype_list ngtype_list;
132d6d9dd67SHartmut Brandt static uint64_t ngtype_tick;
133259ee3d7SHartmut Brandt 
134259ee3d7SHartmut Brandt 
135259ee3d7SHartmut Brandt /*
136259ee3d7SHartmut Brandt  * Register a function to receive unsolicited messages
137259ee3d7SHartmut Brandt  */
138259ee3d7SHartmut Brandt void *
ng_register_cookie(const struct lmodule * mod,u_int32_t cookie,ng_ID_t id,ng_cookie_f * func,void * arg)139259ee3d7SHartmut Brandt ng_register_cookie(const struct lmodule *mod, u_int32_t cookie, ng_ID_t id,
140259ee3d7SHartmut Brandt     ng_cookie_f *func, void *arg)
141259ee3d7SHartmut Brandt {
142259ee3d7SHartmut Brandt 	struct msgreg *d;
143259ee3d7SHartmut Brandt 
144259ee3d7SHartmut Brandt 	if ((d = malloc(sizeof(*d))) == NULL)
145259ee3d7SHartmut Brandt 		return (NULL);
146259ee3d7SHartmut Brandt 
147259ee3d7SHartmut Brandt 	d->cookie = cookie;
148259ee3d7SHartmut Brandt 	d->id = id;
149259ee3d7SHartmut Brandt 	d->func = func;
150259ee3d7SHartmut Brandt 	d->arg = arg;
151259ee3d7SHartmut Brandt 	d->mod = mod;
152259ee3d7SHartmut Brandt 
153259ee3d7SHartmut Brandt 	SLIST_INSERT_HEAD(&msgreg_list, d, link);
154259ee3d7SHartmut Brandt 
155259ee3d7SHartmut Brandt 	return (d);
156259ee3d7SHartmut Brandt }
157259ee3d7SHartmut Brandt 
158259ee3d7SHartmut Brandt /*
159259ee3d7SHartmut Brandt  * Remove a registration.
160259ee3d7SHartmut Brandt  */
161259ee3d7SHartmut Brandt void
ng_unregister_cookie(void * dd)162259ee3d7SHartmut Brandt ng_unregister_cookie(void *dd)
163259ee3d7SHartmut Brandt {
164259ee3d7SHartmut Brandt 	struct msgreg *d = dd;
165259ee3d7SHartmut Brandt 
166259ee3d7SHartmut Brandt 	SLIST_REMOVE(&msgreg_list, d, msgreg, link);
167259ee3d7SHartmut Brandt 	free(d);
168259ee3d7SHartmut Brandt }
169259ee3d7SHartmut Brandt 
170259ee3d7SHartmut Brandt /*
171259ee3d7SHartmut Brandt  * Register a function for hook data.
172259ee3d7SHartmut Brandt  */
173259ee3d7SHartmut Brandt void *
ng_register_hook(const struct lmodule * mod,const char * hook,ng_hook_f * func,void * arg)174259ee3d7SHartmut Brandt ng_register_hook(const struct lmodule *mod, const char *hook,
175259ee3d7SHartmut Brandt     ng_hook_f *func, void *arg)
176259ee3d7SHartmut Brandt {
177259ee3d7SHartmut Brandt 	struct datareg *d;
178259ee3d7SHartmut Brandt 
179259ee3d7SHartmut Brandt 	if ((d = malloc(sizeof(*d))) == NULL)
180259ee3d7SHartmut Brandt 		return (NULL);
181259ee3d7SHartmut Brandt 
182259ee3d7SHartmut Brandt 	strcpy(d->hook, hook);
183259ee3d7SHartmut Brandt 	d->func = func;
184259ee3d7SHartmut Brandt 	d->arg = arg;
185259ee3d7SHartmut Brandt 	d->mod = mod;
186259ee3d7SHartmut Brandt 
187259ee3d7SHartmut Brandt 	SLIST_INSERT_HEAD(&datareg_list, d, link);
188259ee3d7SHartmut Brandt 
189259ee3d7SHartmut Brandt 	return (d);
190259ee3d7SHartmut Brandt }
191259ee3d7SHartmut Brandt 
192259ee3d7SHartmut Brandt /*
193259ee3d7SHartmut Brandt  * Unregister a hook function
194259ee3d7SHartmut Brandt  */
195259ee3d7SHartmut Brandt void
ng_unregister_hook(void * dd)196259ee3d7SHartmut Brandt ng_unregister_hook(void *dd)
197259ee3d7SHartmut Brandt {
198259ee3d7SHartmut Brandt 	struct datareg *d = dd;
199259ee3d7SHartmut Brandt 
200259ee3d7SHartmut Brandt 	SLIST_REMOVE(&datareg_list, d, datareg, link);
201259ee3d7SHartmut Brandt 	free(d);
202259ee3d7SHartmut Brandt }
203259ee3d7SHartmut Brandt 
204259ee3d7SHartmut Brandt /*
205259ee3d7SHartmut Brandt  * Unregister all hooks and cookies for that module. Note: doesn't disconnect
206259ee3d7SHartmut Brandt  * any hooks!
207259ee3d7SHartmut Brandt  */
208259ee3d7SHartmut Brandt void
ng_unregister_module(const struct lmodule * mod)209259ee3d7SHartmut Brandt ng_unregister_module(const struct lmodule *mod)
210259ee3d7SHartmut Brandt {
211259ee3d7SHartmut Brandt 	struct msgreg *m, *m1;
212259ee3d7SHartmut Brandt 	struct datareg *d, *d1;
213259ee3d7SHartmut Brandt 
214259ee3d7SHartmut Brandt 	m = SLIST_FIRST(&msgreg_list);
215259ee3d7SHartmut Brandt 	while (m != NULL) {
216259ee3d7SHartmut Brandt 		m1 = SLIST_NEXT(m, link);
217259ee3d7SHartmut Brandt 		if (m->mod == mod) {
218259ee3d7SHartmut Brandt 			SLIST_REMOVE(&msgreg_list, m, msgreg, link);
219259ee3d7SHartmut Brandt 			free(m);
220259ee3d7SHartmut Brandt 		}
221259ee3d7SHartmut Brandt 		m = m1;
222259ee3d7SHartmut Brandt 	}
223259ee3d7SHartmut Brandt 
224259ee3d7SHartmut Brandt 	d = SLIST_FIRST(&datareg_list);
225259ee3d7SHartmut Brandt 	while (d != NULL) {
226259ee3d7SHartmut Brandt 		d1 = SLIST_NEXT(d, link);
227259ee3d7SHartmut Brandt 		if (d->mod == mod) {
228259ee3d7SHartmut Brandt 			SLIST_REMOVE(&datareg_list, d, datareg, link);
229259ee3d7SHartmut Brandt 			free(d);
230259ee3d7SHartmut Brandt 		}
231259ee3d7SHartmut Brandt 		d = d1;
232259ee3d7SHartmut Brandt 	}
233259ee3d7SHartmut Brandt }
234259ee3d7SHartmut Brandt 
235259ee3d7SHartmut Brandt /*
236259ee3d7SHartmut Brandt  * Dispatch a message to the correct module and delete it. More than one
237259ee3d7SHartmut Brandt  * module can get a message.
238259ee3d7SHartmut Brandt  */
239259ee3d7SHartmut Brandt static void
csock_handle(struct ng_mesg * mesg,const char * path)240259ee3d7SHartmut Brandt csock_handle(struct ng_mesg *mesg, const char *path)
241259ee3d7SHartmut Brandt {
242259ee3d7SHartmut Brandt 	struct msgreg *d, *d1;
243259ee3d7SHartmut Brandt 	u_int id;
244259ee3d7SHartmut Brandt 	int len;
245259ee3d7SHartmut Brandt 
246259ee3d7SHartmut Brandt 	if (sscanf(path, "[%x]:%n", &id, &len) != 1 ||
247259ee3d7SHartmut Brandt 	    (u_int)len != strlen(path)) {
248259ee3d7SHartmut Brandt 		syslog(LOG_ERR, "cannot parse message path '%s'", path);
249259ee3d7SHartmut Brandt 		id = 0;
250259ee3d7SHartmut Brandt 	}
251259ee3d7SHartmut Brandt 
252259ee3d7SHartmut Brandt 	d = SLIST_FIRST(&msgreg_list);
253259ee3d7SHartmut Brandt 	while (d != NULL) {
254259ee3d7SHartmut Brandt 		d1 = SLIST_NEXT(d, link);
255259ee3d7SHartmut Brandt 		if (d->cookie == mesg->header.typecookie &&
256259ee3d7SHartmut Brandt 		    (d->id == 0 || d->id == id || id == 0))
257259ee3d7SHartmut Brandt 			(*d->func)(mesg, path, id, d->arg);
258259ee3d7SHartmut Brandt 		d = d1;
259259ee3d7SHartmut Brandt 	}
260259ee3d7SHartmut Brandt 	free(mesg);
261259ee3d7SHartmut Brandt }
262259ee3d7SHartmut Brandt 
263259ee3d7SHartmut Brandt /*
264259ee3d7SHartmut Brandt  * Input from the control socket.
265259ee3d7SHartmut Brandt  */
266259ee3d7SHartmut Brandt static struct ng_mesg *
csock_read(char * path)267259ee3d7SHartmut Brandt csock_read(char *path)
268259ee3d7SHartmut Brandt {
269259ee3d7SHartmut Brandt 	struct ng_mesg *mesg;
270259ee3d7SHartmut Brandt 	int ret, err;
271259ee3d7SHartmut Brandt 
272259ee3d7SHartmut Brandt 	if ((mesg = malloc(resbufsiz + 1)) == NULL) {
273259ee3d7SHartmut Brandt 		stats[LEAF_begemotNgNoMems]++;
274259ee3d7SHartmut Brandt 		syslog(LOG_CRIT, "out of memory");
275259ee3d7SHartmut Brandt 		errno = ENOMEM;
276259ee3d7SHartmut Brandt 		return (NULL);
277259ee3d7SHartmut Brandt 	}
278259ee3d7SHartmut Brandt 	if ((ret = NgRecvMsg(csock, mesg, resbufsiz + 1, path)) < 0) {
279259ee3d7SHartmut Brandt 		err = errno;
280259ee3d7SHartmut Brandt 		free(mesg);
281259ee3d7SHartmut Brandt 		if (errno == EWOULDBLOCK) {
282259ee3d7SHartmut Brandt 			errno = err;
283259ee3d7SHartmut Brandt 			return (NULL);
284259ee3d7SHartmut Brandt 		}
285259ee3d7SHartmut Brandt 		stats[LEAF_begemotNgMsgReadErrs]++;
286259ee3d7SHartmut Brandt 		syslog(LOG_WARNING, "read from csock: %m");
287259ee3d7SHartmut Brandt 		errno = err;
288259ee3d7SHartmut Brandt 		return (NULL);
289259ee3d7SHartmut Brandt 	}
290259ee3d7SHartmut Brandt 	if (ret == 0) {
291259ee3d7SHartmut Brandt 		syslog(LOG_DEBUG, "node closed -- exiting");
292259ee3d7SHartmut Brandt 		exit(0);
293259ee3d7SHartmut Brandt 	}
294259ee3d7SHartmut Brandt 	if ((size_t)ret > resbufsiz) {
295259ee3d7SHartmut Brandt 		stats[LEAF_begemotNgTooLargeMsgs]++;
296259ee3d7SHartmut Brandt 		syslog(LOG_WARNING, "ng message too large");
297259ee3d7SHartmut Brandt 		free(mesg);
298259ee3d7SHartmut Brandt 		errno = EFBIG;
299259ee3d7SHartmut Brandt 		return (NULL);
300259ee3d7SHartmut Brandt 	}
301259ee3d7SHartmut Brandt 	return (mesg);
302259ee3d7SHartmut Brandt }
303259ee3d7SHartmut Brandt 
304259ee3d7SHartmut Brandt static void
csock_input(int fd __unused,void * udata __unused)305259ee3d7SHartmut Brandt csock_input(int fd __unused, void *udata __unused)
306259ee3d7SHartmut Brandt {
307259ee3d7SHartmut Brandt 	struct ng_mesg *mesg;
30889624a34SHartmut Brandt 	char path[NG_PATHSIZ];
309259ee3d7SHartmut Brandt 
310259ee3d7SHartmut Brandt 	if ((mesg = csock_read(path)) == NULL)
311259ee3d7SHartmut Brandt 		return;
312259ee3d7SHartmut Brandt 
313259ee3d7SHartmut Brandt 	csock_handle(mesg, path);
314259ee3d7SHartmut Brandt }
315259ee3d7SHartmut Brandt 
316259ee3d7SHartmut Brandt /*
317259ee3d7SHartmut Brandt  * Write a message to a node.
318259ee3d7SHartmut Brandt  */
319259ee3d7SHartmut Brandt int
ng_output(const char * path,u_int cookie,u_int opcode,const void * arg,size_t arglen)320259ee3d7SHartmut Brandt ng_output(const char *path, u_int cookie, u_int opcode,
321259ee3d7SHartmut Brandt     const void *arg, size_t arglen)
322259ee3d7SHartmut Brandt {
323259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, path, (int)cookie, (int)opcode, arg, arglen));
324259ee3d7SHartmut Brandt }
325259ee3d7SHartmut Brandt int
ng_output_node(const char * node,u_int cookie,u_int opcode,const void * arg,size_t arglen)326259ee3d7SHartmut Brandt ng_output_node(const char *node, u_int cookie, u_int opcode,
327259ee3d7SHartmut Brandt     const void *arg, size_t arglen)
328259ee3d7SHartmut Brandt {
32989624a34SHartmut Brandt 	char path[NG_PATHSIZ];
330259ee3d7SHartmut Brandt 
331259ee3d7SHartmut Brandt 	sprintf(path, "%s:", node);
332259ee3d7SHartmut Brandt 	return (ng_output(path, cookie, opcode, arg, arglen));
333259ee3d7SHartmut Brandt }
334259ee3d7SHartmut Brandt int
ng_output_id(ng_ID_t node,u_int cookie,u_int opcode,const void * arg,size_t arglen)335259ee3d7SHartmut Brandt ng_output_id(ng_ID_t node, u_int cookie, u_int opcode,
336259ee3d7SHartmut Brandt     const void *arg, size_t arglen)
337259ee3d7SHartmut Brandt {
33889624a34SHartmut Brandt 	char path[NG_PATHSIZ];
339259ee3d7SHartmut Brandt 
340259ee3d7SHartmut Brandt 	sprintf(path, "[%x]:", node);
341259ee3d7SHartmut Brandt 	return (ng_output(path, cookie, opcode, arg, arglen));
342259ee3d7SHartmut Brandt }
343259ee3d7SHartmut Brandt 
344259ee3d7SHartmut Brandt 
345259ee3d7SHartmut Brandt 
346259ee3d7SHartmut Brandt /*
347259ee3d7SHartmut Brandt  * Execute a synchronuous dialog with the csock. All message we receive, that
348259ee3d7SHartmut Brandt  * do not match our request, are queue until the next call to the IDLE function.
349259ee3d7SHartmut Brandt  */
350259ee3d7SHartmut Brandt struct ng_mesg *
ng_dialog(const char * path,u_int cookie,u_int opcode,const void * arg,size_t arglen)351259ee3d7SHartmut Brandt ng_dialog(const char *path, u_int cookie, u_int opcode,
352259ee3d7SHartmut Brandt     const void *arg, size_t arglen)
353259ee3d7SHartmut Brandt {
354259ee3d7SHartmut Brandt 	int token, err;
355259ee3d7SHartmut Brandt 	struct ng_mesg *mesg;
35689624a34SHartmut Brandt 	char rpath[NG_PATHSIZ];
357259ee3d7SHartmut Brandt 	struct csock_buf *b;
358259ee3d7SHartmut Brandt 	struct timeval end, tv;
359259ee3d7SHartmut Brandt 
360259ee3d7SHartmut Brandt 	if ((token = ng_output(path, cookie, opcode, arg, arglen)) < 0)
361259ee3d7SHartmut Brandt 		return (NULL);
362259ee3d7SHartmut Brandt 
363259ee3d7SHartmut Brandt 	if (csock_fd)
364259ee3d7SHartmut Brandt 		fd_suspend(csock_fd);
365259ee3d7SHartmut Brandt 
366259ee3d7SHartmut Brandt 	gettimeofday(&end, NULL);
367259ee3d7SHartmut Brandt 	tv.tv_sec = timeout / 1000;
368259ee3d7SHartmut Brandt 	tv.tv_usec = (timeout % 1000) * 1000;
369259ee3d7SHartmut Brandt 	timeradd(&end, &tv, &end);
370259ee3d7SHartmut Brandt 	for (;;) {
371259ee3d7SHartmut Brandt 		mesg = NULL;
372259ee3d7SHartmut Brandt 		gettimeofday(&tv, NULL);
373259ee3d7SHartmut Brandt 		if (timercmp(&tv, &end, >=)) {
374259ee3d7SHartmut Brandt   block:
375259ee3d7SHartmut Brandt 			syslog(LOG_WARNING, "no response for request %u/%u",
376259ee3d7SHartmut Brandt 			    cookie, opcode);
377259ee3d7SHartmut Brandt 			errno = EWOULDBLOCK;
378259ee3d7SHartmut Brandt 			break;
379259ee3d7SHartmut Brandt 		}
380259ee3d7SHartmut Brandt 		timersub(&end, &tv, &tv);
381259ee3d7SHartmut Brandt 		if (tv.tv_sec == 0 && tv.tv_usec < clockinfo.tick)
382259ee3d7SHartmut Brandt 			goto block;
383259ee3d7SHartmut Brandt 
384259ee3d7SHartmut Brandt 		if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
385259ee3d7SHartmut Brandt 			syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO): %m");
386259ee3d7SHartmut Brandt 		if ((mesg = csock_read(rpath)) == NULL) {
387259ee3d7SHartmut Brandt 			if (errno == EWOULDBLOCK)
388259ee3d7SHartmut Brandt 				continue;
389259ee3d7SHartmut Brandt 			break;
390259ee3d7SHartmut Brandt 		}
391259ee3d7SHartmut Brandt 		if (mesg->header.token == (u_int)token)
392259ee3d7SHartmut Brandt 			break;
393259ee3d7SHartmut Brandt 		if ((b = malloc(sizeof(*b))) == NULL) {
394259ee3d7SHartmut Brandt 			stats[LEAF_begemotNgNoMems]++;
395259ee3d7SHartmut Brandt 			syslog(LOG_ERR, "out of memory");
396259ee3d7SHartmut Brandt 			free(mesg);
397259ee3d7SHartmut Brandt 			continue;
398259ee3d7SHartmut Brandt 		}
399259ee3d7SHartmut Brandt 		b->mesg = mesg;
400259ee3d7SHartmut Brandt 		strcpy(b->path, rpath);
401259ee3d7SHartmut Brandt 		STAILQ_INSERT_TAIL(&csock_bufs, b, link);
402259ee3d7SHartmut Brandt 	}
403259ee3d7SHartmut Brandt 
404259ee3d7SHartmut Brandt 	tv.tv_sec = 0;
405259ee3d7SHartmut Brandt 	tv.tv_usec = 0;
406259ee3d7SHartmut Brandt 	if (setsockopt(csock, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1)
407259ee3d7SHartmut Brandt 		syslog(LOG_WARNING, "setsockopt(SO_RCVTIMEO,0): %m");
408259ee3d7SHartmut Brandt 
409259ee3d7SHartmut Brandt 	if (csock_fd) {
410259ee3d7SHartmut Brandt 		err = errno;
411259ee3d7SHartmut Brandt 		fd_resume(csock_fd);
412259ee3d7SHartmut Brandt 		errno = err;
413259ee3d7SHartmut Brandt 	}
414259ee3d7SHartmut Brandt 
415259ee3d7SHartmut Brandt 	return (mesg);
416259ee3d7SHartmut Brandt }
417259ee3d7SHartmut Brandt struct ng_mesg *
ng_dialog_node(const char * node,u_int cookie,u_int opcode,const void * arg,size_t arglen)418259ee3d7SHartmut Brandt ng_dialog_node(const char *node, u_int cookie, u_int opcode,
419259ee3d7SHartmut Brandt     const void *arg, size_t arglen)
420259ee3d7SHartmut Brandt {
42189624a34SHartmut Brandt 	char path[NG_PATHSIZ];
422259ee3d7SHartmut Brandt 
423259ee3d7SHartmut Brandt 	sprintf(path, "%s:", node);
424259ee3d7SHartmut Brandt 	return (ng_dialog(path, cookie, opcode, arg, arglen));
425259ee3d7SHartmut Brandt }
426259ee3d7SHartmut Brandt struct ng_mesg *
ng_dialog_id(ng_ID_t id,u_int cookie,u_int opcode,const void * arg,size_t arglen)427259ee3d7SHartmut Brandt ng_dialog_id(ng_ID_t id, u_int cookie, u_int opcode,
428259ee3d7SHartmut Brandt     const void *arg, size_t arglen)
429259ee3d7SHartmut Brandt {
43089624a34SHartmut Brandt 	char path[NG_PATHSIZ];
431259ee3d7SHartmut Brandt 
432259ee3d7SHartmut Brandt 	sprintf(path, "[%x]:", id);
433259ee3d7SHartmut Brandt 	return (ng_dialog(path, cookie, opcode, arg, arglen));
434259ee3d7SHartmut Brandt }
435259ee3d7SHartmut Brandt 
436259ee3d7SHartmut Brandt 
437259ee3d7SHartmut Brandt /*
438259ee3d7SHartmut Brandt  * Send a data message to a given hook.
439259ee3d7SHartmut Brandt  */
440259ee3d7SHartmut Brandt int
ng_send_data(const char * hook,const void * sndbuf,size_t sndlen)441259ee3d7SHartmut Brandt ng_send_data(const char *hook, const void *sndbuf, size_t sndlen)
442259ee3d7SHartmut Brandt {
443259ee3d7SHartmut Brandt 	return (NgSendData(dsock, hook, sndbuf, sndlen));
444259ee3d7SHartmut Brandt }
445259ee3d7SHartmut Brandt 
446259ee3d7SHartmut Brandt /*
447259ee3d7SHartmut Brandt  * Input from a data socket. Dispatch to the function for that hook.
448259ee3d7SHartmut Brandt  */
449259ee3d7SHartmut Brandt static void
dsock_input(int fd __unused,void * udata __unused)450259ee3d7SHartmut Brandt dsock_input(int fd __unused, void *udata __unused)
451259ee3d7SHartmut Brandt {
452259ee3d7SHartmut Brandt 	u_char *resbuf, embuf[100];
453259ee3d7SHartmut Brandt 	ssize_t len;
45489624a34SHartmut Brandt 	char hook[NG_HOOKSIZ];
455259ee3d7SHartmut Brandt 	struct datareg *d, *d1;
456259ee3d7SHartmut Brandt 
457259ee3d7SHartmut Brandt 	if ((resbuf = malloc(resbufsiz + 1)) == NULL) {
458259ee3d7SHartmut Brandt 		stats[LEAF_begemotNgNoMems]++;
459259ee3d7SHartmut Brandt 		syslog(LOG_CRIT, "out of memory");
460259ee3d7SHartmut Brandt 		(void)NgRecvData(fd, embuf, sizeof(embuf), hook);
461259ee3d7SHartmut Brandt 		errno = ENOMEM;
462259ee3d7SHartmut Brandt 		return;
463259ee3d7SHartmut Brandt 	}
464259ee3d7SHartmut Brandt 	if ((len = NgRecvData(fd, resbuf, resbufsiz + 1, hook)) == -1) {
465259ee3d7SHartmut Brandt 		stats[LEAF_begemotNgDataReadErrs]++;
466259ee3d7SHartmut Brandt 		syslog(LOG_ERR, "reading message: %m");
467259ee3d7SHartmut Brandt 		free(resbuf);
468259ee3d7SHartmut Brandt 		return;
469259ee3d7SHartmut Brandt 	}
470259ee3d7SHartmut Brandt 	if (len == 0) {
471259ee3d7SHartmut Brandt 		free(resbuf);
472259ee3d7SHartmut Brandt 		return;
473259ee3d7SHartmut Brandt 	}
474259ee3d7SHartmut Brandt 	if ((size_t)len == resbufsiz + 1) {
475259ee3d7SHartmut Brandt 		stats[LEAF_begemotNgTooLargeDatas]++;
476259ee3d7SHartmut Brandt 		syslog(LOG_WARNING, "message too long");
477259ee3d7SHartmut Brandt 		free(resbuf);
478259ee3d7SHartmut Brandt 		return;
479259ee3d7SHartmut Brandt 	}
480259ee3d7SHartmut Brandt 
481259ee3d7SHartmut Brandt 	/*
482259ee3d7SHartmut Brandt 	 * Dispatch message. Maybe dispatched to more than one function.
483259ee3d7SHartmut Brandt 	 */
484259ee3d7SHartmut Brandt 	d = SLIST_FIRST(&datareg_list);
485259ee3d7SHartmut Brandt 	while (d != NULL) {
486259ee3d7SHartmut Brandt 		d1 = SLIST_NEXT(d, link);
487259ee3d7SHartmut Brandt 		if (strcmp(hook, d->hook) == 0)
488259ee3d7SHartmut Brandt 			(*d->func)(hook, resbuf, len, d->arg);
489259ee3d7SHartmut Brandt 		d = d1;
490259ee3d7SHartmut Brandt 	}
491259ee3d7SHartmut Brandt 
492259ee3d7SHartmut Brandt 	free(resbuf);
493259ee3d7SHartmut Brandt }
494259ee3d7SHartmut Brandt 
495259ee3d7SHartmut Brandt /*
496259ee3d7SHartmut Brandt  * The SNMP daemon is about to wait for an event. Look whether we have
497259ee3d7SHartmut Brandt  * netgraph messages waiting. If yes, drain the queue.
498259ee3d7SHartmut Brandt  */
499259ee3d7SHartmut Brandt static void
ng_idle(void)500259ee3d7SHartmut Brandt ng_idle(void)
501259ee3d7SHartmut Brandt {
502259ee3d7SHartmut Brandt 	struct csock_buf *b;
503259ee3d7SHartmut Brandt 
504259ee3d7SHartmut Brandt 	/* execute waiting csock_bufs */
505259ee3d7SHartmut Brandt 	while ((b = STAILQ_FIRST(&csock_bufs)) != NULL) {
506259ee3d7SHartmut Brandt 		STAILQ_REMOVE_HEAD(&csock_bufs, link);
507259ee3d7SHartmut Brandt 		csock_handle(b->mesg, b->path);
508259ee3d7SHartmut Brandt 		free(b);
509259ee3d7SHartmut Brandt 	}
510259ee3d7SHartmut Brandt }
511259ee3d7SHartmut Brandt 
512259ee3d7SHartmut Brandt /*
513259ee3d7SHartmut Brandt  * Called when the module is loaded. Returning a non-zero value means,
514259ee3d7SHartmut Brandt  * rejecting the initialisation.
515259ee3d7SHartmut Brandt  *
516259ee3d7SHartmut Brandt  * We make the netgraph socket.
517259ee3d7SHartmut Brandt  */
518259ee3d7SHartmut Brandt static int
ng_init(struct lmodule * mod,int argc,char * argv[])519259ee3d7SHartmut Brandt ng_init(struct lmodule *mod, int argc, char *argv[])
520259ee3d7SHartmut Brandt {
521259ee3d7SHartmut Brandt 	int name[2];
522259ee3d7SHartmut Brandt 	size_t len;
523259ee3d7SHartmut Brandt 
524259ee3d7SHartmut Brandt 	module = mod;
525259ee3d7SHartmut Brandt 
526259ee3d7SHartmut Brandt 	if (argc == 0) {
527259ee3d7SHartmut Brandt 		if ((snmp_nodename = malloc(strlen(NODENAME) + 1)) == NULL)
528259ee3d7SHartmut Brandt 			return (ENOMEM);
529259ee3d7SHartmut Brandt 		strcpy(snmp_nodename, NODENAME);
530259ee3d7SHartmut Brandt 	} else {
53189624a34SHartmut Brandt 		if ((snmp_nodename = malloc(NG_NODESIZ)) == NULL)
532259ee3d7SHartmut Brandt 			return (ENOMEM);
53389624a34SHartmut Brandt 		strlcpy(snmp_nodename, argv[0], NG_NODESIZ);
534259ee3d7SHartmut Brandt 	}
535259ee3d7SHartmut Brandt 
536259ee3d7SHartmut Brandt 	/* fetch clockinfo (for the number of microseconds per tick) */
537259ee3d7SHartmut Brandt 	name[0] = CTL_KERN;
538259ee3d7SHartmut Brandt 	name[1] = KERN_CLOCKRATE;
539259ee3d7SHartmut Brandt 	len = sizeof(clockinfo);
540259ee3d7SHartmut Brandt 	if (sysctl(name, 2, &clockinfo, &len, NULL, 0) == -1)
541259ee3d7SHartmut Brandt 		return (errno);
542259ee3d7SHartmut Brandt 
543259ee3d7SHartmut Brandt 	TAILQ_INIT(&ngtype_list);
544259ee3d7SHartmut Brandt 
545259ee3d7SHartmut Brandt 	return (0);
546259ee3d7SHartmut Brandt }
547259ee3d7SHartmut Brandt 
548259ee3d7SHartmut Brandt /*
549259ee3d7SHartmut Brandt  * Get the node Id/name/type of a node.
550259ee3d7SHartmut Brandt  */
551259ee3d7SHartmut Brandt ng_ID_t
ng_node_id(const char * path)552259ee3d7SHartmut Brandt ng_node_id(const char *path)
553259ee3d7SHartmut Brandt {
554259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
555259ee3d7SHartmut Brandt 	ng_ID_t id;
556259ee3d7SHartmut Brandt 
557259ee3d7SHartmut Brandt 	if ((resp = ng_dialog(path, NGM_GENERIC_COOKIE, NGM_NODEINFO,
558259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
559259ee3d7SHartmut Brandt 		return (0);
560259ee3d7SHartmut Brandt 	id = ((struct nodeinfo *)(void *)resp->data)->id;
561259ee3d7SHartmut Brandt 	free(resp);
562259ee3d7SHartmut Brandt 	return (id);
563259ee3d7SHartmut Brandt }
564259ee3d7SHartmut Brandt ng_ID_t
ng_node_id_node(const char * node)565259ee3d7SHartmut Brandt ng_node_id_node(const char *node)
566259ee3d7SHartmut Brandt {
567259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
568259ee3d7SHartmut Brandt 	ng_ID_t id;
569259ee3d7SHartmut Brandt 
570259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_node(node, NGM_GENERIC_COOKIE, NGM_NODEINFO,
571259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
572259ee3d7SHartmut Brandt 		return (0);
573259ee3d7SHartmut Brandt 	id = ((struct nodeinfo *)(void *)resp->data)->id;
574259ee3d7SHartmut Brandt 	free(resp);
575259ee3d7SHartmut Brandt 	return (id);
576259ee3d7SHartmut Brandt }
577259ee3d7SHartmut Brandt ng_ID_t
ng_node_name(ng_ID_t id,char * name)578259ee3d7SHartmut Brandt ng_node_name(ng_ID_t id, char *name)
579259ee3d7SHartmut Brandt {
580259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
581259ee3d7SHartmut Brandt 
582259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO,
583259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
584259ee3d7SHartmut Brandt 		return (0);
585259ee3d7SHartmut Brandt 	strcpy(name, ((struct nodeinfo *)(void *)resp->data)->name);
586259ee3d7SHartmut Brandt 	free(resp);
587259ee3d7SHartmut Brandt 	return (id);
588259ee3d7SHartmut Brandt 
589259ee3d7SHartmut Brandt }
590259ee3d7SHartmut Brandt ng_ID_t
ng_node_type(ng_ID_t id,char * type)591259ee3d7SHartmut Brandt ng_node_type(ng_ID_t id, char *type)
592259ee3d7SHartmut Brandt {
593259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
594259ee3d7SHartmut Brandt 
595259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO,
596259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
597259ee3d7SHartmut Brandt 		return (0);
598259ee3d7SHartmut Brandt 	strcpy(type, ((struct nodeinfo *)(void *)resp->data)->type);
599259ee3d7SHartmut Brandt 	free(resp);
600259ee3d7SHartmut Brandt 	return (id);
601259ee3d7SHartmut Brandt }
602259ee3d7SHartmut Brandt 
603259ee3d7SHartmut Brandt /*
604259ee3d7SHartmut Brandt  * Connect our node to some other node
605259ee3d7SHartmut Brandt  */
606259ee3d7SHartmut Brandt int
ng_connect_node(const char * node,const char * ourhook,const char * peerhook)607259ee3d7SHartmut Brandt ng_connect_node(const char *node, const char *ourhook, const char *peerhook)
608259ee3d7SHartmut Brandt {
609259ee3d7SHartmut Brandt 	struct ngm_connect conn;
610259ee3d7SHartmut Brandt 
61189624a34SHartmut Brandt 	snprintf(conn.path, NG_PATHSIZ, "%s:", node);
61289624a34SHartmut Brandt 	strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ);
61389624a34SHartmut Brandt 	strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
614259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, ".:",
615259ee3d7SHartmut Brandt 	    NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
616259ee3d7SHartmut Brandt }
617259ee3d7SHartmut Brandt int
ng_connect_id(ng_ID_t id,const char * ourhook,const char * peerhook)618259ee3d7SHartmut Brandt ng_connect_id(ng_ID_t id, const char *ourhook, const char *peerhook)
619259ee3d7SHartmut Brandt {
620259ee3d7SHartmut Brandt 	struct ngm_connect conn;
621259ee3d7SHartmut Brandt 
62289624a34SHartmut Brandt 	snprintf(conn.path, NG_PATHSIZ, "[%x]:", id);
62389624a34SHartmut Brandt 	strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ);
62489624a34SHartmut Brandt 	strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
625259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, ".:",
626259ee3d7SHartmut Brandt 	    NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
627259ee3d7SHartmut Brandt }
628259ee3d7SHartmut Brandt 
629259ee3d7SHartmut Brandt int
ng_connect2_id(ng_ID_t id,ng_ID_t peer,const char * ourhook,const char * peerhook)630259ee3d7SHartmut Brandt ng_connect2_id(ng_ID_t id, ng_ID_t peer, const char *ourhook,
631259ee3d7SHartmut Brandt     const char *peerhook)
632259ee3d7SHartmut Brandt {
633259ee3d7SHartmut Brandt 	struct ngm_connect conn;
63489624a34SHartmut Brandt 	char path[NG_PATHSIZ];
635259ee3d7SHartmut Brandt 
63689624a34SHartmut Brandt 	snprintf(path, NG_PATHSIZ, "[%x]:", id);
637259ee3d7SHartmut Brandt 
63889624a34SHartmut Brandt 	snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer);
63989624a34SHartmut Brandt 	strlcpy(conn.ourhook, ourhook, NG_HOOKSIZ);
64089624a34SHartmut Brandt 	strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
641259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, path,
642259ee3d7SHartmut Brandt 	    NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
643259ee3d7SHartmut Brandt }
644259ee3d7SHartmut Brandt 
645259ee3d7SHartmut Brandt int
ng_connect2_tee_id(ng_ID_t id,ng_ID_t peer,const char * ourhook,const char * peerhook)646259ee3d7SHartmut Brandt ng_connect2_tee_id(ng_ID_t id, ng_ID_t peer, const char *ourhook,
647259ee3d7SHartmut Brandt     const char *peerhook)
648259ee3d7SHartmut Brandt {
649259ee3d7SHartmut Brandt 	struct ngm_connect conn;
65089624a34SHartmut Brandt 	char path[NG_PATHSIZ];
651259ee3d7SHartmut Brandt 	ng_ID_t tee;
652259ee3d7SHartmut Brandt 
653259ee3d7SHartmut Brandt 	if ((tee = ng_mkpeer_id(id, NULL, "tee", ourhook, "left")) == 0)
654259ee3d7SHartmut Brandt 		return (-1);
655259ee3d7SHartmut Brandt 
65689624a34SHartmut Brandt 	snprintf(path, NG_PATHSIZ, "[%x]:", tee);
657259ee3d7SHartmut Brandt 
65889624a34SHartmut Brandt 	snprintf(conn.path, NG_PATHSIZ, "[%x]:", peer);
65989624a34SHartmut Brandt 	strlcpy(conn.ourhook, "right", NG_HOOKSIZ);
66089624a34SHartmut Brandt 	strlcpy(conn.peerhook, peerhook, NG_HOOKSIZ);
661259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, path,
662259ee3d7SHartmut Brandt 	    NGM_GENERIC_COOKIE, NGM_CONNECT, &conn, sizeof(conn)));
663259ee3d7SHartmut Brandt }
664259ee3d7SHartmut Brandt 
665259ee3d7SHartmut Brandt /*
666259ee3d7SHartmut Brandt  * Ensure that a node of type 'type' is connected to 'hook' of 'node'
667259ee3d7SHartmut Brandt  * and return its node id. tee nodes between node and the target node
668259ee3d7SHartmut Brandt  * are skipped. If the type is wrong, or the hook is a dead-end return 0.
669259ee3d7SHartmut Brandt  * If type is NULL, it is not checked.
670259ee3d7SHartmut Brandt  */
671259ee3d7SHartmut Brandt static ng_ID_t
ng_next_node_id_internal(ng_ID_t node,const char * type,const char * hook,int skip_tee)672259ee3d7SHartmut Brandt ng_next_node_id_internal(ng_ID_t node, const char *type, const char *hook,
673259ee3d7SHartmut Brandt     int skip_tee)
674259ee3d7SHartmut Brandt {
675259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
676259ee3d7SHartmut Brandt 	struct hooklist *hooklist;
677259ee3d7SHartmut Brandt 	u_int i;
678259ee3d7SHartmut Brandt 
679259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
680259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL) {
681259ee3d7SHartmut Brandt 		syslog(LOG_ERR, "get hook list: %m");
682259ee3d7SHartmut Brandt 		exit(1);
683259ee3d7SHartmut Brandt 	}
684259ee3d7SHartmut Brandt 	hooklist = (struct hooklist *)(void *)resp->data;
685259ee3d7SHartmut Brandt 
686259ee3d7SHartmut Brandt 	for (i = 0; i < hooklist->nodeinfo.hooks; i++)
687259ee3d7SHartmut Brandt 		if (strcmp(hooklist->link[i].ourhook, hook) == 0)
688259ee3d7SHartmut Brandt 			break;
689259ee3d7SHartmut Brandt 
690259ee3d7SHartmut Brandt 	if (i == hooklist->nodeinfo.hooks) {
691259ee3d7SHartmut Brandt 		free(resp);
692259ee3d7SHartmut Brandt 		return (0);
693259ee3d7SHartmut Brandt 	}
694259ee3d7SHartmut Brandt 
695259ee3d7SHartmut Brandt 	node = hooklist->link[i].nodeinfo.id;
696259ee3d7SHartmut Brandt 
697259ee3d7SHartmut Brandt 	if (skip_tee && strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) {
698259ee3d7SHartmut Brandt 		if (strcmp(hooklist->link[i].peerhook, "left") == 0)
699259ee3d7SHartmut Brandt 			node = ng_next_node_id(node, type, "right");
700259ee3d7SHartmut Brandt 		else if (strcmp(hooklist->link[i].peerhook, "right") == 0)
701259ee3d7SHartmut Brandt 			node = ng_next_node_id(node, type, "left");
702259ee3d7SHartmut Brandt 		else if (type != NULL &&
703259ee3d7SHartmut Brandt 		    strcmp(hooklist->link[i].nodeinfo.type, type) != 0)
704259ee3d7SHartmut Brandt 			node = 0;
705259ee3d7SHartmut Brandt 
706259ee3d7SHartmut Brandt 	} else if (type != NULL &&
707259ee3d7SHartmut Brandt 	    strcmp(hooklist->link[i].nodeinfo.type, type) != 0)
708259ee3d7SHartmut Brandt 		node = 0;
709259ee3d7SHartmut Brandt 
710259ee3d7SHartmut Brandt 	free(resp);
711259ee3d7SHartmut Brandt 
712259ee3d7SHartmut Brandt 	return (node);
713259ee3d7SHartmut Brandt }
714259ee3d7SHartmut Brandt 
715259ee3d7SHartmut Brandt /*
716259ee3d7SHartmut Brandt  * Ensure that a node of type 'type' is connected to 'hook' of 'node'
717259ee3d7SHartmut Brandt  * and return its node id. tee nodes between node and the target node
718259ee3d7SHartmut Brandt  * are skipped. If the type is wrong, or the hook is a dead-end return 0.
719259ee3d7SHartmut Brandt  * If type is NULL, it is not checked.
720259ee3d7SHartmut Brandt  */
721259ee3d7SHartmut Brandt ng_ID_t
ng_next_node_id(ng_ID_t node,const char * type,const char * hook)722259ee3d7SHartmut Brandt ng_next_node_id(ng_ID_t node, const char *type, const char *hook)
723259ee3d7SHartmut Brandt {
724259ee3d7SHartmut Brandt 	return (ng_next_node_id_internal(node, type, hook, 1));
725259ee3d7SHartmut Brandt }
726259ee3d7SHartmut Brandt 
727259ee3d7SHartmut Brandt ng_ID_t
ng_mkpeer_id(ng_ID_t id,const char * nodename,const char * type,const char * hook,const char * peerhook)728259ee3d7SHartmut Brandt ng_mkpeer_id(ng_ID_t id, const char *nodename, const char *type,
729259ee3d7SHartmut Brandt     const char *hook, const char *peerhook)
730259ee3d7SHartmut Brandt {
73189624a34SHartmut Brandt 	char path[NG_PATHSIZ];
732259ee3d7SHartmut Brandt 	struct ngm_mkpeer mkpeer;
733259ee3d7SHartmut Brandt 	struct ngm_name name;
734259ee3d7SHartmut Brandt 
73589624a34SHartmut Brandt 	strlcpy(mkpeer.type, type, NG_TYPESIZ);
73689624a34SHartmut Brandt 	strlcpy(mkpeer.ourhook, hook, NG_HOOKSIZ);
73789624a34SHartmut Brandt 	strlcpy(mkpeer.peerhook, peerhook, NG_HOOKSIZ);
738259ee3d7SHartmut Brandt 
739259ee3d7SHartmut Brandt 	sprintf(path, "[%x]:", id);
740259ee3d7SHartmut Brandt 	if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_MKPEER,
741259ee3d7SHartmut Brandt 	    &mkpeer, sizeof(mkpeer)) == -1)
742259ee3d7SHartmut Brandt 		return (0);
743259ee3d7SHartmut Brandt 
744c254ec55SHartmut Brandt 	if ((id = ng_next_node_id_internal(id, NULL, hook, 0)) == 0)
745259ee3d7SHartmut Brandt 		return (0);
746259ee3d7SHartmut Brandt 
747259ee3d7SHartmut Brandt 	if (nodename != NULL) {
748259ee3d7SHartmut Brandt 		strcpy(name.name, nodename);
749259ee3d7SHartmut Brandt 		sprintf(path, "[%x]:", id);
750259ee3d7SHartmut Brandt 		if (NgSendMsg(csock, path, NGM_GENERIC_COOKIE, NGM_NAME,
751259ee3d7SHartmut Brandt 		    &name, sizeof(name)) == -1)
752259ee3d7SHartmut Brandt 			return (0);
753259ee3d7SHartmut Brandt 	}
754259ee3d7SHartmut Brandt 	return (id);
755259ee3d7SHartmut Brandt }
756259ee3d7SHartmut Brandt 
757259ee3d7SHartmut Brandt /*
758259ee3d7SHartmut Brandt  * SHutdown node
759259ee3d7SHartmut Brandt  */
760259ee3d7SHartmut Brandt int
ng_shutdown_id(ng_ID_t id)761259ee3d7SHartmut Brandt ng_shutdown_id(ng_ID_t id)
762259ee3d7SHartmut Brandt {
76389624a34SHartmut Brandt 	char path[NG_PATHSIZ];
764259ee3d7SHartmut Brandt 
76589624a34SHartmut Brandt 	snprintf(path, NG_PATHSIZ, "[%x]:", id);
766259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, path, NGM_GENERIC_COOKIE,
767259ee3d7SHartmut Brandt 	    NGM_SHUTDOWN, NULL, 0));
768259ee3d7SHartmut Brandt }
769259ee3d7SHartmut Brandt 
770259ee3d7SHartmut Brandt /*
771259ee3d7SHartmut Brandt  * Disconnect one of our hooks
772259ee3d7SHartmut Brandt  */
773259ee3d7SHartmut Brandt int
ng_rmhook(const char * ourhook)774259ee3d7SHartmut Brandt ng_rmhook(const char *ourhook)
775259ee3d7SHartmut Brandt {
776259ee3d7SHartmut Brandt 	struct ngm_rmhook rmhook;
777259ee3d7SHartmut Brandt 
77889624a34SHartmut Brandt 	strlcpy(rmhook.ourhook, ourhook, NG_HOOKSIZ);
779259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, ".:",
780259ee3d7SHartmut Brandt 	    NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook)));
781259ee3d7SHartmut Brandt }
782259ee3d7SHartmut Brandt 
783259ee3d7SHartmut Brandt /*
784259ee3d7SHartmut Brandt  * Disconnect a hook of a node
785259ee3d7SHartmut Brandt  */
786259ee3d7SHartmut Brandt int
ng_rmhook_id(ng_ID_t id,const char * hook)787259ee3d7SHartmut Brandt ng_rmhook_id(ng_ID_t id, const char *hook)
788259ee3d7SHartmut Brandt {
789259ee3d7SHartmut Brandt 	struct ngm_rmhook rmhook;
79089624a34SHartmut Brandt 	char path[NG_PATHSIZ];
791259ee3d7SHartmut Brandt 
79289624a34SHartmut Brandt 	strlcpy(rmhook.ourhook, hook, NG_HOOKSIZ);
79389624a34SHartmut Brandt 	snprintf(path, NG_PATHSIZ, "[%x]:", id);
794259ee3d7SHartmut Brandt 	return (NgSendMsg(csock, path,
795259ee3d7SHartmut Brandt 	    NGM_GENERIC_COOKIE, NGM_RMHOOK, &rmhook, sizeof(rmhook)));
796259ee3d7SHartmut Brandt }
797259ee3d7SHartmut Brandt 
798259ee3d7SHartmut Brandt /*
799259ee3d7SHartmut Brandt  * Disconnect a hook and shutdown all tee nodes that were connected to that
800259ee3d7SHartmut Brandt  * hook.
801259ee3d7SHartmut Brandt  */
802259ee3d7SHartmut Brandt int
ng_rmhook_tee_id(ng_ID_t node,const char * hook)803259ee3d7SHartmut Brandt ng_rmhook_tee_id(ng_ID_t node, const char *hook)
804259ee3d7SHartmut Brandt {
805259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
806259ee3d7SHartmut Brandt 	struct hooklist *hooklist;
807259ee3d7SHartmut Brandt 	u_int i;
808259ee3d7SHartmut Brandt 	int first = 1;
809259ee3d7SHartmut Brandt 	ng_ID_t next_node;
810259ee3d7SHartmut Brandt 	const char *next_hook;
811259ee3d7SHartmut Brandt 
812259ee3d7SHartmut Brandt   again:
813259ee3d7SHartmut Brandt 	/* if we have just shutdown a tee node, which had no other hooks
814259ee3d7SHartmut Brandt 	 * connected, the node id may already be wrong here. */
815259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
816259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
817259ee3d7SHartmut Brandt 		return (0);
818259ee3d7SHartmut Brandt 
819259ee3d7SHartmut Brandt 	hooklist = (struct hooklist *)(void *)resp->data;
820259ee3d7SHartmut Brandt 
821259ee3d7SHartmut Brandt 	for (i = 0; i < hooklist->nodeinfo.hooks; i++)
822259ee3d7SHartmut Brandt 		if (strcmp(hooklist->link[i].ourhook, hook) == 0)
823259ee3d7SHartmut Brandt 			break;
824259ee3d7SHartmut Brandt 
825259ee3d7SHartmut Brandt 	if (i == hooklist->nodeinfo.hooks) {
826259ee3d7SHartmut Brandt 		free(resp);
827259ee3d7SHartmut Brandt 		return (0);
828259ee3d7SHartmut Brandt 	}
829259ee3d7SHartmut Brandt 
830259ee3d7SHartmut Brandt 	next_node = 0;
831259ee3d7SHartmut Brandt 	next_hook = NULL;
832259ee3d7SHartmut Brandt 	if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) {
833259ee3d7SHartmut Brandt 		if (strcmp(hooklist->link[i].peerhook, "left") == 0) {
834259ee3d7SHartmut Brandt 			next_node = hooklist->link[i].nodeinfo.id;
835259ee3d7SHartmut Brandt 			next_hook = "right";
836259ee3d7SHartmut Brandt 		} else if (strcmp(hooklist->link[i].peerhook, "right") == 0) {
837259ee3d7SHartmut Brandt 			next_node = hooklist->link[i].nodeinfo.id;
838259ee3d7SHartmut Brandt 			next_hook = "left";
839259ee3d7SHartmut Brandt 		}
840259ee3d7SHartmut Brandt 	}
841259ee3d7SHartmut Brandt 	free(resp);
842259ee3d7SHartmut Brandt 
843259ee3d7SHartmut Brandt 	if (first) {
844259ee3d7SHartmut Brandt 		ng_rmhook_id(node, hook);
845259ee3d7SHartmut Brandt 		first = 0;
846259ee3d7SHartmut Brandt 	} else {
847259ee3d7SHartmut Brandt 		ng_shutdown_id(node);
848259ee3d7SHartmut Brandt 	}
849259ee3d7SHartmut Brandt 	if ((node = next_node) == 0)
850259ee3d7SHartmut Brandt 		return (0);
851259ee3d7SHartmut Brandt 	hook = next_hook;
852259ee3d7SHartmut Brandt 
853259ee3d7SHartmut Brandt 	goto again;
854259ee3d7SHartmut Brandt }
855259ee3d7SHartmut Brandt 
856259ee3d7SHartmut Brandt /*
857259ee3d7SHartmut Brandt  * Get the peer hook of a hook on a given node. Skip any tee nodes in between
858259ee3d7SHartmut Brandt  */
859259ee3d7SHartmut Brandt int
ng_peer_hook_id(ng_ID_t node,const char * hook,char * peerhook)860259ee3d7SHartmut Brandt ng_peer_hook_id(ng_ID_t node, const char *hook, char *peerhook)
861259ee3d7SHartmut Brandt {
862259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
863259ee3d7SHartmut Brandt 	struct hooklist *hooklist;
864259ee3d7SHartmut Brandt 	u_int i;
865259ee3d7SHartmut Brandt 	int ret;
866259ee3d7SHartmut Brandt 
867259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(node, NGM_GENERIC_COOKIE, NGM_LISTHOOKS,
868259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL) {
869259ee3d7SHartmut Brandt 		syslog(LOG_ERR, "get hook list: %m");
870259ee3d7SHartmut Brandt 		exit(1);
871259ee3d7SHartmut Brandt 	}
872259ee3d7SHartmut Brandt 	hooklist = (struct hooklist *)(void *)resp->data;
873259ee3d7SHartmut Brandt 
874259ee3d7SHartmut Brandt 	for (i = 0; i < hooklist->nodeinfo.hooks; i++)
875259ee3d7SHartmut Brandt 		if (strcmp(hooklist->link[i].ourhook, hook) == 0)
876259ee3d7SHartmut Brandt 			break;
877259ee3d7SHartmut Brandt 
878259ee3d7SHartmut Brandt 	if (i == hooklist->nodeinfo.hooks) {
879259ee3d7SHartmut Brandt 		free(resp);
880259ee3d7SHartmut Brandt 		return (-1);
881259ee3d7SHartmut Brandt 	}
882259ee3d7SHartmut Brandt 
883259ee3d7SHartmut Brandt 	node = hooklist->link[i].nodeinfo.id;
884259ee3d7SHartmut Brandt 
885259ee3d7SHartmut Brandt 	ret = 0;
886259ee3d7SHartmut Brandt 	if (strcmp(hooklist->link[i].nodeinfo.type, "tee") == 0) {
887259ee3d7SHartmut Brandt 		if (strcmp(hooklist->link[i].peerhook, "left") == 0)
888259ee3d7SHartmut Brandt 			ret = ng_peer_hook_id(node, "right", peerhook);
889259ee3d7SHartmut Brandt 		else if (strcmp(hooklist->link[i].peerhook, "right") == 0)
890259ee3d7SHartmut Brandt 			ret = ng_peer_hook_id(node, "left", peerhook);
891259ee3d7SHartmut Brandt 		else
892259ee3d7SHartmut Brandt 			strcpy(peerhook, hooklist->link[i].peerhook);
893259ee3d7SHartmut Brandt 
894259ee3d7SHartmut Brandt 	} else
895259ee3d7SHartmut Brandt 		strcpy(peerhook, hooklist->link[i].peerhook);
896259ee3d7SHartmut Brandt 
897259ee3d7SHartmut Brandt 	free(resp);
898259ee3d7SHartmut Brandt 
899259ee3d7SHartmut Brandt 	return (ret);
900259ee3d7SHartmut Brandt }
901259ee3d7SHartmut Brandt 
902259ee3d7SHartmut Brandt 
903259ee3d7SHartmut Brandt /*
904259ee3d7SHartmut Brandt  * Now the module is started. Select on the sockets, so that we can get
905259ee3d7SHartmut Brandt  * unsolicited input.
906259ee3d7SHartmut Brandt  */
907259ee3d7SHartmut Brandt static void
ng_start(void)908259ee3d7SHartmut Brandt ng_start(void)
909259ee3d7SHartmut Brandt {
910259ee3d7SHartmut Brandt 	if (snmp_node == 0) {
911259ee3d7SHartmut Brandt 		if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) {
912259ee3d7SHartmut Brandt 			syslog(LOG_ERR, "NgMkSockNode: %m");
913259ee3d7SHartmut Brandt 			exit(1);
914259ee3d7SHartmut Brandt 		}
915259ee3d7SHartmut Brandt 		snmp_node = ng_node_id(".:");
916259ee3d7SHartmut Brandt 	}
917259ee3d7SHartmut Brandt 
918259ee3d7SHartmut Brandt 	if ((csock_fd = fd_select(csock, csock_input, NULL, module)) == NULL) {
919259ee3d7SHartmut Brandt 		syslog(LOG_ERR, "fd_select failed on csock: %m");
920259ee3d7SHartmut Brandt 		return;
921259ee3d7SHartmut Brandt 	}
922259ee3d7SHartmut Brandt 	if ((dsock_fd = fd_select(dsock, dsock_input, NULL, module)) == NULL) {
923259ee3d7SHartmut Brandt 		syslog(LOG_ERR, "fd_select failed on dsock: %m");
924259ee3d7SHartmut Brandt 		return;
925259ee3d7SHartmut Brandt 	}
926259ee3d7SHartmut Brandt 
927259ee3d7SHartmut Brandt 	reg_index = or_register(&oid_begemotNg,
928259ee3d7SHartmut Brandt 	    "The MIB for the NetGraph access module for SNMP.", module);
929259ee3d7SHartmut Brandt }
930259ee3d7SHartmut Brandt 
931259ee3d7SHartmut Brandt /*
932259ee3d7SHartmut Brandt  * Called, when the module is to be unloaded after it was successfully loaded
933259ee3d7SHartmut Brandt  */
934259ee3d7SHartmut Brandt static int
ng_fini(void)935259ee3d7SHartmut Brandt ng_fini(void)
936259ee3d7SHartmut Brandt {
937259ee3d7SHartmut Brandt 	struct ngtype *t;
938259ee3d7SHartmut Brandt 
939259ee3d7SHartmut Brandt 	while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) {
940259ee3d7SHartmut Brandt 		TAILQ_REMOVE(&ngtype_list, t, link);
941259ee3d7SHartmut Brandt 		free(t);
942259ee3d7SHartmut Brandt 	}
943259ee3d7SHartmut Brandt 
944259ee3d7SHartmut Brandt 	if (csock_fd != NULL)
945259ee3d7SHartmut Brandt 		fd_deselect(csock_fd);
946259ee3d7SHartmut Brandt 	(void)close(csock);
947259ee3d7SHartmut Brandt 
948259ee3d7SHartmut Brandt 	if (dsock_fd != NULL)
949259ee3d7SHartmut Brandt 		fd_deselect(dsock_fd);
950259ee3d7SHartmut Brandt 	(void)close(dsock);
951259ee3d7SHartmut Brandt 
952259ee3d7SHartmut Brandt 	free(snmp_nodename);
953259ee3d7SHartmut Brandt 
954259ee3d7SHartmut Brandt 	or_unregister(reg_index);
955259ee3d7SHartmut Brandt 
956259ee3d7SHartmut Brandt 	return (0);
957259ee3d7SHartmut Brandt }
958259ee3d7SHartmut Brandt 
959259ee3d7SHartmut Brandt const struct snmp_module config = {
960259ee3d7SHartmut Brandt 	"This module implements access to the netgraph sub-system",
961259ee3d7SHartmut Brandt 	ng_init,
962259ee3d7SHartmut Brandt 	ng_fini,
963259ee3d7SHartmut Brandt 	ng_idle,
964259ee3d7SHartmut Brandt 	NULL,
965259ee3d7SHartmut Brandt 	NULL,
966259ee3d7SHartmut Brandt 	ng_start,
967259ee3d7SHartmut Brandt 	NULL,
968259ee3d7SHartmut Brandt 	netgraph_ctree,
969259ee3d7SHartmut Brandt 	netgraph_CTREE_SIZE,
970259ee3d7SHartmut Brandt 	NULL
971259ee3d7SHartmut Brandt };
972259ee3d7SHartmut Brandt 
973259ee3d7SHartmut Brandt int
op_ng_config(struct snmp_context * ctx,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)974259ee3d7SHartmut Brandt op_ng_config(struct snmp_context *ctx, struct snmp_value *value,
975259ee3d7SHartmut Brandt     u_int sub, u_int iidx __unused, enum snmp_op op)
976259ee3d7SHartmut Brandt {
977259ee3d7SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
978259ee3d7SHartmut Brandt 	int ret;
979259ee3d7SHartmut Brandt 
980259ee3d7SHartmut Brandt 	switch (op) {
981259ee3d7SHartmut Brandt 
982259ee3d7SHartmut Brandt 	  case SNMP_OP_GETNEXT:
983259ee3d7SHartmut Brandt 		abort();
984259ee3d7SHartmut Brandt 
985259ee3d7SHartmut Brandt 	  case SNMP_OP_GET:
986259ee3d7SHartmut Brandt 		/*
987259ee3d7SHartmut Brandt 		 * Come here for GET, GETNEXT and COMMIT
988259ee3d7SHartmut Brandt 		 */
989259ee3d7SHartmut Brandt 		switch (which) {
990259ee3d7SHartmut Brandt 
991259ee3d7SHartmut Brandt 		  case LEAF_begemotNgControlNodeName:
992259ee3d7SHartmut Brandt 			return (string_get(value, snmp_nodename, -1));
993259ee3d7SHartmut Brandt 
994259ee3d7SHartmut Brandt 		  case LEAF_begemotNgResBufSiz:
995259ee3d7SHartmut Brandt 			value->v.integer = resbufsiz;
996259ee3d7SHartmut Brandt 			break;
997259ee3d7SHartmut Brandt 
998259ee3d7SHartmut Brandt 		  case LEAF_begemotNgTimeout:
999259ee3d7SHartmut Brandt 			value->v.integer = timeout;
1000259ee3d7SHartmut Brandt 			break;
1001259ee3d7SHartmut Brandt 
1002259ee3d7SHartmut Brandt 		  case LEAF_begemotNgDebugLevel:
1003259ee3d7SHartmut Brandt 			value->v.uint32 = debug_level;
1004259ee3d7SHartmut Brandt 			break;
1005259ee3d7SHartmut Brandt 
1006259ee3d7SHartmut Brandt 		  default:
1007259ee3d7SHartmut Brandt 			abort();
1008259ee3d7SHartmut Brandt 		}
1009259ee3d7SHartmut Brandt 		return (SNMP_ERR_NOERROR);
1010259ee3d7SHartmut Brandt 
1011259ee3d7SHartmut Brandt 	  case SNMP_OP_SET:
1012259ee3d7SHartmut Brandt 		switch (which) {
1013259ee3d7SHartmut Brandt 
1014259ee3d7SHartmut Brandt 		  case LEAF_begemotNgControlNodeName:
1015259ee3d7SHartmut Brandt 			/* only at initialisation */
1016259ee3d7SHartmut Brandt 			if (community != COMM_INITIALIZE)
1017259ee3d7SHartmut Brandt 				return (SNMP_ERR_NOT_WRITEABLE);
1018259ee3d7SHartmut Brandt 
1019259ee3d7SHartmut Brandt 			if (snmp_node != 0)
1020259ee3d7SHartmut Brandt 				return (SNMP_ERR_NOT_WRITEABLE);
1021259ee3d7SHartmut Brandt 
1022259ee3d7SHartmut Brandt 			if ((ret = string_save(value, ctx, -1, &snmp_nodename))
1023259ee3d7SHartmut Brandt 			    != SNMP_ERR_NOERROR)
1024259ee3d7SHartmut Brandt 				return (ret);
1025259ee3d7SHartmut Brandt 
1026259ee3d7SHartmut Brandt 			if (NgMkSockNode(snmp_nodename, &csock, &dsock) < 0) {
1027259ee3d7SHartmut Brandt 				syslog(LOG_ERR, "NgMkSockNode: %m");
1028259ee3d7SHartmut Brandt 				string_rollback(ctx, &snmp_nodename);
1029259ee3d7SHartmut Brandt 				return (SNMP_ERR_GENERR);
1030259ee3d7SHartmut Brandt 			}
1031259ee3d7SHartmut Brandt 			snmp_node = ng_node_id(".:");
1032259ee3d7SHartmut Brandt 
1033259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1034259ee3d7SHartmut Brandt 
1035259ee3d7SHartmut Brandt 		  case LEAF_begemotNgResBufSiz:
1036259ee3d7SHartmut Brandt 			ctx->scratch->int1 = resbufsiz;
1037259ee3d7SHartmut Brandt 			if (value->v.integer < 1024 ||
1038259ee3d7SHartmut Brandt 			    value->v.integer > 0x10000)
1039259ee3d7SHartmut Brandt 				return (SNMP_ERR_WRONG_VALUE);
1040259ee3d7SHartmut Brandt 			resbufsiz = value->v.integer;
1041259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1042259ee3d7SHartmut Brandt 
1043259ee3d7SHartmut Brandt 		  case LEAF_begemotNgTimeout:
1044259ee3d7SHartmut Brandt 			ctx->scratch->int1 = timeout;
1045259ee3d7SHartmut Brandt 			if (value->v.integer < 10 ||
1046259ee3d7SHartmut Brandt 			    value->v.integer > 10000)
1047259ee3d7SHartmut Brandt 				return (SNMP_ERR_WRONG_VALUE);
1048259ee3d7SHartmut Brandt 			timeout = value->v.integer;
1049259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1050259ee3d7SHartmut Brandt 
1051259ee3d7SHartmut Brandt 		  case LEAF_begemotNgDebugLevel:
1052259ee3d7SHartmut Brandt 			ctx->scratch->int1 = debug_level;
1053259ee3d7SHartmut Brandt 			debug_level = value->v.uint32;
1054259ee3d7SHartmut Brandt 			NgSetDebug(debug_level);
1055259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1056259ee3d7SHartmut Brandt 		}
1057259ee3d7SHartmut Brandt 		abort();
1058259ee3d7SHartmut Brandt 
1059259ee3d7SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1060259ee3d7SHartmut Brandt 		switch (which) {
1061259ee3d7SHartmut Brandt 
1062259ee3d7SHartmut Brandt 		  case LEAF_begemotNgControlNodeName:
1063259ee3d7SHartmut Brandt 			string_rollback(ctx, &snmp_nodename);
1064259ee3d7SHartmut Brandt 			close(csock);
1065259ee3d7SHartmut Brandt 			close(dsock);
1066259ee3d7SHartmut Brandt 			snmp_node = 0;
1067259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1068259ee3d7SHartmut Brandt 
1069259ee3d7SHartmut Brandt 		  case LEAF_begemotNgResBufSiz:
1070259ee3d7SHartmut Brandt 			resbufsiz = ctx->scratch->int1;
1071259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1072259ee3d7SHartmut Brandt 
1073259ee3d7SHartmut Brandt 		  case LEAF_begemotNgTimeout:
1074259ee3d7SHartmut Brandt 			timeout = ctx->scratch->int1;
1075259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1076259ee3d7SHartmut Brandt 
1077259ee3d7SHartmut Brandt 		  case LEAF_begemotNgDebugLevel:
1078259ee3d7SHartmut Brandt 			debug_level = ctx->scratch->int1;
1079259ee3d7SHartmut Brandt 			NgSetDebug(debug_level);
1080259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1081259ee3d7SHartmut Brandt 		}
1082259ee3d7SHartmut Brandt 		abort();
1083259ee3d7SHartmut Brandt 
1084259ee3d7SHartmut Brandt 	  case SNMP_OP_COMMIT:
1085259ee3d7SHartmut Brandt 		switch (which) {
1086259ee3d7SHartmut Brandt 
1087259ee3d7SHartmut Brandt 		  case LEAF_begemotNgControlNodeName:
1088259ee3d7SHartmut Brandt 			string_commit(ctx);
1089259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1090259ee3d7SHartmut Brandt 
1091259ee3d7SHartmut Brandt 		  case LEAF_begemotNgResBufSiz:
1092259ee3d7SHartmut Brandt 		  case LEAF_begemotNgTimeout:
1093259ee3d7SHartmut Brandt 		  case LEAF_begemotNgDebugLevel:
1094259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOERROR);
1095259ee3d7SHartmut Brandt 		}
1096259ee3d7SHartmut Brandt 		abort();
1097259ee3d7SHartmut Brandt 	}
1098259ee3d7SHartmut Brandt 	abort();
1099259ee3d7SHartmut Brandt }
1100259ee3d7SHartmut Brandt 
1101259ee3d7SHartmut Brandt int
op_ng_stats(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1102259ee3d7SHartmut Brandt op_ng_stats(struct snmp_context *ctx __unused, struct snmp_value *value,
1103259ee3d7SHartmut Brandt     u_int sub, u_int iidx __unused, enum snmp_op op)
1104259ee3d7SHartmut Brandt {
1105259ee3d7SHartmut Brandt 	switch (op) {
1106259ee3d7SHartmut Brandt 
1107259ee3d7SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1108259ee3d7SHartmut Brandt 		abort();
1109259ee3d7SHartmut Brandt 
1110259ee3d7SHartmut Brandt 	  case SNMP_OP_GET:
1111259ee3d7SHartmut Brandt 		value->v.uint32 = stats[value->var.subs[sub - 1] - 1];
1112259ee3d7SHartmut Brandt 		return (SNMP_ERR_NOERROR);
1113259ee3d7SHartmut Brandt 
1114259ee3d7SHartmut Brandt 	  case SNMP_OP_SET:
1115259ee3d7SHartmut Brandt 		return (SNMP_ERR_NOT_WRITEABLE);
1116259ee3d7SHartmut Brandt 
1117259ee3d7SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1118259ee3d7SHartmut Brandt 	  case SNMP_OP_COMMIT:
1119259ee3d7SHartmut Brandt 		abort();
1120259ee3d7SHartmut Brandt 	}
1121259ee3d7SHartmut Brandt 	abort();
1122259ee3d7SHartmut Brandt }
1123259ee3d7SHartmut Brandt 
1124259ee3d7SHartmut Brandt /*
1125259ee3d7SHartmut Brandt  * Netgraph type table
1126259ee3d7SHartmut Brandt  */
1127259ee3d7SHartmut Brandt static int
fetch_types(void)1128259ee3d7SHartmut Brandt fetch_types(void)
1129259ee3d7SHartmut Brandt {
1130259ee3d7SHartmut Brandt 	struct ngtype *t;
1131259ee3d7SHartmut Brandt 	struct typelist *typelist;
1132259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
1133259ee3d7SHartmut Brandt 	u_int u, i;
1134259ee3d7SHartmut Brandt 
1135259ee3d7SHartmut Brandt 	if (this_tick <= ngtype_tick)
1136259ee3d7SHartmut Brandt 		return (0);
1137259ee3d7SHartmut Brandt 
1138259ee3d7SHartmut Brandt 	while ((t = TAILQ_FIRST(&ngtype_list)) != NULL) {
1139259ee3d7SHartmut Brandt 		TAILQ_REMOVE(&ngtype_list, t, link);
1140259ee3d7SHartmut Brandt 		free(t);
1141259ee3d7SHartmut Brandt 	}
1142259ee3d7SHartmut Brandt 
1143259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE,
1144259ee3d7SHartmut Brandt 	    NGM_LISTTYPES, NULL, 0)) == NULL)
1145259ee3d7SHartmut Brandt 		return (SNMP_ERR_GENERR);
1146259ee3d7SHartmut Brandt 	typelist = (struct typelist *)(void *)resp->data;
1147259ee3d7SHartmut Brandt 
1148259ee3d7SHartmut Brandt 	for (u = 0; u < typelist->numtypes; u++) {
1149259ee3d7SHartmut Brandt 		if ((t = malloc(sizeof(*t))) == NULL) {
1150259ee3d7SHartmut Brandt 			free(resp);
1151259ee3d7SHartmut Brandt 			return (SNMP_ERR_GENERR);
1152259ee3d7SHartmut Brandt 		}
1153259ee3d7SHartmut Brandt 		strcpy(t->name, typelist->typeinfo[u].type_name);
1154259ee3d7SHartmut Brandt 		t->index.subs[0] = strlen(t->name);
1155259ee3d7SHartmut Brandt 		t->index.len = t->index.subs[0] + 1;
1156259ee3d7SHartmut Brandt 		for (i = 0; i < t->index.subs[0]; i++)
1157259ee3d7SHartmut Brandt 			t->index.subs[i + 1] = t->name[i];
1158259ee3d7SHartmut Brandt 
1159259ee3d7SHartmut Brandt 		INSERT_OBJECT_OID(t, &ngtype_list);
1160259ee3d7SHartmut Brandt 	}
1161259ee3d7SHartmut Brandt 
1162259ee3d7SHartmut Brandt 	ngtype_tick = this_tick;
1163259ee3d7SHartmut Brandt 
1164259ee3d7SHartmut Brandt 	free(resp);
1165259ee3d7SHartmut Brandt 	return (0);
1166259ee3d7SHartmut Brandt }
1167259ee3d7SHartmut Brandt 
1168259ee3d7SHartmut Brandt /*
1169259ee3d7SHartmut Brandt  * Try to load the netgraph type with the given name. We assume, that
1170259ee3d7SHartmut Brandt  * type 'type' is implemented in the kernel module 'ng_type'.
1171259ee3d7SHartmut Brandt  */
1172259ee3d7SHartmut Brandt static int
ngtype_load(const u_char * name,size_t namelen)1173259ee3d7SHartmut Brandt ngtype_load(const u_char *name, size_t namelen)
1174259ee3d7SHartmut Brandt {
1175259ee3d7SHartmut Brandt 	char *mod;
1176259ee3d7SHartmut Brandt 	int ret;
1177259ee3d7SHartmut Brandt 
1178259ee3d7SHartmut Brandt 	if ((mod = malloc(namelen + 4)) == NULL)
1179259ee3d7SHartmut Brandt 		return (-1);
1180259ee3d7SHartmut Brandt 	strcpy(mod, "ng_");
1181259ee3d7SHartmut Brandt 	strncpy(mod + 3, name, namelen);
1182259ee3d7SHartmut Brandt 	mod[namelen + 3] = '\0';
1183259ee3d7SHartmut Brandt 
1184259ee3d7SHartmut Brandt 	ret = kldload(mod);
1185259ee3d7SHartmut Brandt 	free(mod);
1186259ee3d7SHartmut Brandt 	return (ret);
1187259ee3d7SHartmut Brandt }
1188259ee3d7SHartmut Brandt 
1189259ee3d7SHartmut Brandt /*
1190259ee3d7SHartmut Brandt  * Unload a netgraph type.
1191259ee3d7SHartmut Brandt  */
1192259ee3d7SHartmut Brandt static int
ngtype_unload(const u_char * name,size_t namelen)1193259ee3d7SHartmut Brandt ngtype_unload(const u_char *name, size_t namelen)
1194259ee3d7SHartmut Brandt {
1195259ee3d7SHartmut Brandt 	char *mod;
1196259ee3d7SHartmut Brandt 	int id;
1197259ee3d7SHartmut Brandt 
1198259ee3d7SHartmut Brandt 	if ((mod = malloc(namelen + 4)) == NULL)
1199259ee3d7SHartmut Brandt 		return (-1);
1200259ee3d7SHartmut Brandt 	strcpy(mod, "ng_");
1201259ee3d7SHartmut Brandt 	strncpy(mod + 3, name, namelen);
1202259ee3d7SHartmut Brandt 	mod[namelen + 3] = '\0';
1203259ee3d7SHartmut Brandt 
1204259ee3d7SHartmut Brandt 	if ((id = kldfind(mod)) == -1) {
1205259ee3d7SHartmut Brandt 		free(mod);
1206259ee3d7SHartmut Brandt 		return (-1);
1207259ee3d7SHartmut Brandt 	}
1208259ee3d7SHartmut Brandt 	free(mod);
1209259ee3d7SHartmut Brandt 	return (kldunload(id));
1210259ee3d7SHartmut Brandt }
1211259ee3d7SHartmut Brandt 
1212259ee3d7SHartmut Brandt int
op_ng_type(struct snmp_context * ctx,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1213259ee3d7SHartmut Brandt op_ng_type(struct snmp_context *ctx, struct snmp_value *value,
1214259ee3d7SHartmut Brandt     u_int sub, u_int iidx, enum snmp_op op)
1215259ee3d7SHartmut Brandt {
1216259ee3d7SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1217259ee3d7SHartmut Brandt 	struct ngtype *t;
1218259ee3d7SHartmut Brandt 	u_char *name;
1219259ee3d7SHartmut Brandt 	size_t namelen;
1220259ee3d7SHartmut Brandt 	int status = 1;
1221259ee3d7SHartmut Brandt 	int ret;
1222259ee3d7SHartmut Brandt 
1223259ee3d7SHartmut Brandt 	switch (op) {
1224259ee3d7SHartmut Brandt 
1225259ee3d7SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1226259ee3d7SHartmut Brandt 		if ((ret = fetch_types()) != 0)
1227259ee3d7SHartmut Brandt 			return (ret);
1228259ee3d7SHartmut Brandt 		if ((t = NEXT_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL)
1229259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1230259ee3d7SHartmut Brandt 		index_append(&value->var, sub, &t->index);
1231259ee3d7SHartmut Brandt 		break;
1232259ee3d7SHartmut Brandt 
1233259ee3d7SHartmut Brandt 	  case SNMP_OP_GET:
1234259ee3d7SHartmut Brandt 		if ((ret = fetch_types()) != 0)
1235259ee3d7SHartmut Brandt 			return (ret);
1236259ee3d7SHartmut Brandt 		if ((t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub)) == NULL)
1237259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1238259ee3d7SHartmut Brandt 		break;
1239259ee3d7SHartmut Brandt 
1240259ee3d7SHartmut Brandt 	  case SNMP_OP_SET:
1241259ee3d7SHartmut Brandt 		if (index_decode(&value->var, sub, iidx, &name, &namelen))
1242259ee3d7SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
124389624a34SHartmut Brandt 		if (namelen == 0 || namelen >= NG_TYPESIZ) {
1244259ee3d7SHartmut Brandt 			free(name);
1245259ee3d7SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1246259ee3d7SHartmut Brandt 		}
1247259ee3d7SHartmut Brandt 		if ((ret = fetch_types()) != 0) {
1248259ee3d7SHartmut Brandt 			free(name);
1249259ee3d7SHartmut Brandt 			return (ret);
1250259ee3d7SHartmut Brandt 		}
1251259ee3d7SHartmut Brandt 		t = FIND_OBJECT_OID(&ngtype_list, &value->var, sub);
1252259ee3d7SHartmut Brandt 
1253259ee3d7SHartmut Brandt 		if (which != LEAF_begemotNgTypeStatus) {
1254259ee3d7SHartmut Brandt 			free(name);
1255259ee3d7SHartmut Brandt 			if (t != NULL)
1256259ee3d7SHartmut Brandt 				return (SNMP_ERR_NOT_WRITEABLE);
1257259ee3d7SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1258259ee3d7SHartmut Brandt 		}
1259259ee3d7SHartmut Brandt 		if (!TRUTH_OK(value->v.integer)) {
1260259ee3d7SHartmut Brandt 			free(name);
1261259ee3d7SHartmut Brandt 			return (SNMP_ERR_WRONG_VALUE);
1262259ee3d7SHartmut Brandt 		}
1263259ee3d7SHartmut Brandt 		ctx->scratch->int1 = TRUTH_GET(value->v.integer);
1264259ee3d7SHartmut Brandt 		ctx->scratch->int1 |= (t != NULL) << 1;
1265259ee3d7SHartmut Brandt 		ctx->scratch->ptr2 = name;
1266259ee3d7SHartmut Brandt 		ctx->scratch->int2 = namelen;
1267259ee3d7SHartmut Brandt 
1268259ee3d7SHartmut Brandt 		if (t == NULL) {
1269259ee3d7SHartmut Brandt 			/* type not loaded */
1270259ee3d7SHartmut Brandt 			if (ctx->scratch->int1 & 1) {
1271259ee3d7SHartmut Brandt 				/* request to load */
1272259ee3d7SHartmut Brandt 				if (ngtype_load(name, namelen) == -1) {
1273259ee3d7SHartmut Brandt 					free(name);
1274259ee3d7SHartmut Brandt 					if (errno == ENOENT)
1275259ee3d7SHartmut Brandt 						return (SNMP_ERR_INCONS_NAME);
1276259ee3d7SHartmut Brandt 					else
1277259ee3d7SHartmut Brandt 						return (SNMP_ERR_GENERR);
1278259ee3d7SHartmut Brandt 				}
1279259ee3d7SHartmut Brandt 			}
1280259ee3d7SHartmut Brandt 		} else {
1281259ee3d7SHartmut Brandt 			/* is type loaded */
1282259ee3d7SHartmut Brandt 			if (!(ctx->scratch->int1 & 1)) {
1283259ee3d7SHartmut Brandt 				/* request to unload */
1284259ee3d7SHartmut Brandt 				if (ngtype_unload(name, namelen) == -1) {
1285259ee3d7SHartmut Brandt 					free(name);
1286259ee3d7SHartmut Brandt 					return (SNMP_ERR_GENERR);
1287259ee3d7SHartmut Brandt 				}
1288259ee3d7SHartmut Brandt 			}
1289259ee3d7SHartmut Brandt 		}
1290259ee3d7SHartmut Brandt 		return (SNMP_ERR_NOERROR);
1291259ee3d7SHartmut Brandt 
1292259ee3d7SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1293259ee3d7SHartmut Brandt 		ret = SNMP_ERR_NOERROR;
1294259ee3d7SHartmut Brandt 		if (!(ctx->scratch->int1 & 2)) {
1295259ee3d7SHartmut Brandt 			/* did not exist */
1296259ee3d7SHartmut Brandt 			if (ctx->scratch->int1 & 1) {
1297259ee3d7SHartmut Brandt 				/* request to load - unload */
1298259ee3d7SHartmut Brandt 				if (ngtype_unload(ctx->scratch->ptr2,
1299259ee3d7SHartmut Brandt 				    ctx->scratch->int2) == -1)
1300259ee3d7SHartmut Brandt 					ret = SNMP_ERR_UNDO_FAILED;
1301259ee3d7SHartmut Brandt 			}
1302259ee3d7SHartmut Brandt 		} else {
1303259ee3d7SHartmut Brandt 			/* did exist */
1304259ee3d7SHartmut Brandt 			if (!(ctx->scratch->int1 & 1)) {
1305259ee3d7SHartmut Brandt 				/* request to unload - reload */
1306259ee3d7SHartmut Brandt 				if (ngtype_load(ctx->scratch->ptr2,
1307259ee3d7SHartmut Brandt 				    ctx->scratch->int2) == -1)
1308259ee3d7SHartmut Brandt 					ret = SNMP_ERR_UNDO_FAILED;
1309259ee3d7SHartmut Brandt 			}
1310259ee3d7SHartmut Brandt 		}
1311259ee3d7SHartmut Brandt 		free(ctx->scratch->ptr2);
1312259ee3d7SHartmut Brandt 		return (ret);
1313259ee3d7SHartmut Brandt 
1314259ee3d7SHartmut Brandt 	  case SNMP_OP_COMMIT:
1315259ee3d7SHartmut Brandt 		free(ctx->scratch->ptr2);
1316259ee3d7SHartmut Brandt 		return (SNMP_ERR_NOERROR);
1317259ee3d7SHartmut Brandt 
1318259ee3d7SHartmut Brandt 	  default:
1319259ee3d7SHartmut Brandt 		abort();
1320259ee3d7SHartmut Brandt 	}
1321259ee3d7SHartmut Brandt 
1322259ee3d7SHartmut Brandt 	/*
1323259ee3d7SHartmut Brandt 	 * Come here for GET and COMMIT
1324259ee3d7SHartmut Brandt 	 */
1325259ee3d7SHartmut Brandt 	switch (which) {
1326259ee3d7SHartmut Brandt 
1327259ee3d7SHartmut Brandt 	  case LEAF_begemotNgTypeStatus:
1328259ee3d7SHartmut Brandt 		value->v.integer = status;
1329259ee3d7SHartmut Brandt 		break;
1330259ee3d7SHartmut Brandt 
1331259ee3d7SHartmut Brandt 	  default:
1332259ee3d7SHartmut Brandt 		abort();
1333259ee3d7SHartmut Brandt 	}
1334259ee3d7SHartmut Brandt 	return (SNMP_ERR_NOERROR);
1335259ee3d7SHartmut Brandt }
1336259ee3d7SHartmut Brandt 
1337259ee3d7SHartmut Brandt /*
1338259ee3d7SHartmut Brandt  * Implement the node table
1339259ee3d7SHartmut Brandt  */
1340259ee3d7SHartmut Brandt static int
find_node(const struct asn_oid * oid,u_int sub,struct nodeinfo * info)1341259ee3d7SHartmut Brandt find_node(const struct asn_oid *oid, u_int sub, struct nodeinfo *info)
1342259ee3d7SHartmut Brandt {
1343259ee3d7SHartmut Brandt 	ng_ID_t id = oid->subs[sub];
1344259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
1345259ee3d7SHartmut Brandt 
1346259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE, NGM_NODEINFO,
1347259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
1348259ee3d7SHartmut Brandt 		return (-1);
1349259ee3d7SHartmut Brandt 
1350259ee3d7SHartmut Brandt 	*info = *(struct nodeinfo *)(void *)resp->data;
1351259ee3d7SHartmut Brandt 	free(resp);
1352259ee3d7SHartmut Brandt 	return (0);
1353259ee3d7SHartmut Brandt }
1354259ee3d7SHartmut Brandt 
1355259ee3d7SHartmut Brandt static int
ncmp(const void * p1,const void * p2)1356259ee3d7SHartmut Brandt ncmp(const void *p1, const void *p2)
1357259ee3d7SHartmut Brandt {
1358259ee3d7SHartmut Brandt 	const struct nodeinfo *i1 = p1;
1359259ee3d7SHartmut Brandt 	const struct nodeinfo *i2 = p2;
1360259ee3d7SHartmut Brandt 
1361259ee3d7SHartmut Brandt 	if (i1->id < i2->id)
1362259ee3d7SHartmut Brandt 		return (-1);
1363259ee3d7SHartmut Brandt 	if (i1->id > i2->id)
1364259ee3d7SHartmut Brandt 		return (+1);
1365259ee3d7SHartmut Brandt 	return (0);
1366259ee3d7SHartmut Brandt }
1367259ee3d7SHartmut Brandt 
1368259ee3d7SHartmut Brandt static int
find_node_next(const struct asn_oid * oid,u_int sub,struct nodeinfo * info)1369259ee3d7SHartmut Brandt find_node_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *info)
1370259ee3d7SHartmut Brandt {
1371259ee3d7SHartmut Brandt 	u_int idxlen = oid->len - sub;
1372259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
1373259ee3d7SHartmut Brandt 	struct namelist *list;
1374259ee3d7SHartmut Brandt 	ng_ID_t id;
1375259ee3d7SHartmut Brandt 	u_int i;
1376259ee3d7SHartmut Brandt 
1377259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES,
1378259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
1379259ee3d7SHartmut Brandt 		return (-1);
1380259ee3d7SHartmut Brandt 	list = (struct namelist *)(void *)resp->data;
1381259ee3d7SHartmut Brandt 
1382259ee3d7SHartmut Brandt 	qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp);
1383259ee3d7SHartmut Brandt 
1384259ee3d7SHartmut Brandt 	if (idxlen == 0) {
1385259ee3d7SHartmut Brandt 		if (list->numnames == 0) {
1386259ee3d7SHartmut Brandt 			free(resp);
1387259ee3d7SHartmut Brandt 			return (-1);
1388259ee3d7SHartmut Brandt 		}
1389259ee3d7SHartmut Brandt 		*info = list->nodeinfo[0];
1390259ee3d7SHartmut Brandt 		free(resp);
1391259ee3d7SHartmut Brandt 		return (0);
1392259ee3d7SHartmut Brandt 	}
1393259ee3d7SHartmut Brandt 	id = oid->subs[sub];
1394259ee3d7SHartmut Brandt 
1395259ee3d7SHartmut Brandt 	for (i = 0; i < list->numnames; i++)
1396259ee3d7SHartmut Brandt 		if (list->nodeinfo[i].id > id) {
1397259ee3d7SHartmut Brandt 			*info = list->nodeinfo[i];
1398259ee3d7SHartmut Brandt 			free(resp);
1399259ee3d7SHartmut Brandt 			return (0);
1400259ee3d7SHartmut Brandt 		}
1401259ee3d7SHartmut Brandt 
1402259ee3d7SHartmut Brandt 	free(resp);
1403259ee3d7SHartmut Brandt 	return (-1);
1404259ee3d7SHartmut Brandt }
1405259ee3d7SHartmut Brandt 
1406259ee3d7SHartmut Brandt int
op_ng_node(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx __unused,enum snmp_op op)1407259ee3d7SHartmut Brandt op_ng_node(struct snmp_context *ctx __unused, struct snmp_value *value,
1408259ee3d7SHartmut Brandt     u_int sub, u_int iidx __unused, enum snmp_op op)
1409259ee3d7SHartmut Brandt {
1410259ee3d7SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1411259ee3d7SHartmut Brandt 	u_int idxlen = value->var.len - sub;
1412259ee3d7SHartmut Brandt 	struct nodeinfo nodeinfo;
1413259ee3d7SHartmut Brandt 
1414259ee3d7SHartmut Brandt 	switch (op) {
1415259ee3d7SHartmut Brandt 
1416259ee3d7SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1417259ee3d7SHartmut Brandt 		if (find_node_next(&value->var, sub, &nodeinfo) == -1)
1418259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1419259ee3d7SHartmut Brandt 		value->var.len = sub + 1;
1420259ee3d7SHartmut Brandt 		value->var.subs[sub] = nodeinfo.id;
1421259ee3d7SHartmut Brandt 		break;
1422259ee3d7SHartmut Brandt 
1423259ee3d7SHartmut Brandt 	  case SNMP_OP_GET:
1424259ee3d7SHartmut Brandt 		if (idxlen != 1)
1425259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1426259ee3d7SHartmut Brandt 		if (find_node(&value->var, sub, &nodeinfo) == -1)
1427259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1428259ee3d7SHartmut Brandt 		break;
1429259ee3d7SHartmut Brandt 
1430259ee3d7SHartmut Brandt 	  case SNMP_OP_SET:
1431259ee3d7SHartmut Brandt 		if (idxlen != 1)
1432259ee3d7SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1433259ee3d7SHartmut Brandt 		if (find_node(&value->var, sub, &nodeinfo) == -1)
1434259ee3d7SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1435259ee3d7SHartmut Brandt 		return (SNMP_ERR_NOT_WRITEABLE);
1436259ee3d7SHartmut Brandt 
1437259ee3d7SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1438259ee3d7SHartmut Brandt 	  case SNMP_OP_COMMIT:
1439259ee3d7SHartmut Brandt 	  default:
1440259ee3d7SHartmut Brandt 		abort();
1441259ee3d7SHartmut Brandt 	}
1442259ee3d7SHartmut Brandt 
1443259ee3d7SHartmut Brandt 	/*
1444259ee3d7SHartmut Brandt 	 * Come here for GET and COMMIT
1445259ee3d7SHartmut Brandt 	 */
1446259ee3d7SHartmut Brandt 	switch (which) {
1447259ee3d7SHartmut Brandt 
1448259ee3d7SHartmut Brandt 	  case LEAF_begemotNgNodeStatus:
1449259ee3d7SHartmut Brandt 		value->v.integer = 1;
1450259ee3d7SHartmut Brandt 		break;
1451259ee3d7SHartmut Brandt 	  case LEAF_begemotNgNodeName:
1452259ee3d7SHartmut Brandt 		return (string_get(value, nodeinfo.name, -1));
1453259ee3d7SHartmut Brandt 	  case LEAF_begemotNgNodeType:
1454259ee3d7SHartmut Brandt 		return (string_get(value, nodeinfo.type, -1));
1455259ee3d7SHartmut Brandt 	  case LEAF_begemotNgNodeHooks:
1456259ee3d7SHartmut Brandt 		value->v.uint32 = nodeinfo.hooks;
1457259ee3d7SHartmut Brandt 		break;
1458259ee3d7SHartmut Brandt 
1459259ee3d7SHartmut Brandt 	  default:
1460259ee3d7SHartmut Brandt 		abort();
1461259ee3d7SHartmut Brandt 	}
1462259ee3d7SHartmut Brandt 	return (SNMP_ERR_NOERROR);
1463259ee3d7SHartmut Brandt }
1464259ee3d7SHartmut Brandt 
1465259ee3d7SHartmut Brandt /*
1466259ee3d7SHartmut Brandt  * Implement the hook table
1467259ee3d7SHartmut Brandt  */
1468259ee3d7SHartmut Brandt static int
find_hook(int32_t id,const u_char * hook,size_t hooklen,struct linkinfo * info)1469259ee3d7SHartmut Brandt find_hook(int32_t id, const u_char *hook, size_t hooklen, struct linkinfo *info)
1470259ee3d7SHartmut Brandt {
1471259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
1472259ee3d7SHartmut Brandt 	struct hooklist *list;
1473259ee3d7SHartmut Brandt 	u_int i;
1474259ee3d7SHartmut Brandt 
1475259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(id, NGM_GENERIC_COOKIE,
1476259ee3d7SHartmut Brandt 	    NGM_LISTHOOKS, NULL, 0)) == NULL)
1477259ee3d7SHartmut Brandt 		return (-1);
1478259ee3d7SHartmut Brandt 
1479259ee3d7SHartmut Brandt 	list = (struct hooklist *)(void *)resp->data;
1480259ee3d7SHartmut Brandt 
1481259ee3d7SHartmut Brandt 	for (i = 0; i < list->nodeinfo.hooks; i++) {
1482259ee3d7SHartmut Brandt 		if (strlen(list->link[i].ourhook) == hooklen &&
1483259ee3d7SHartmut Brandt 		    strncmp(list->link[i].ourhook, hook, hooklen) == 0) {
1484259ee3d7SHartmut Brandt 			*info = list->link[i];
1485259ee3d7SHartmut Brandt 			free(resp);
1486259ee3d7SHartmut Brandt 			return (0);
1487259ee3d7SHartmut Brandt 		}
1488259ee3d7SHartmut Brandt 	}
1489259ee3d7SHartmut Brandt 	free(resp);
1490259ee3d7SHartmut Brandt 	return (-1);
1491259ee3d7SHartmut Brandt }
1492259ee3d7SHartmut Brandt 
1493259ee3d7SHartmut Brandt static int
hook_cmp(const void * p1,const void * p2)1494259ee3d7SHartmut Brandt hook_cmp(const void *p1, const void *p2)
1495259ee3d7SHartmut Brandt {
1496259ee3d7SHartmut Brandt 	const struct linkinfo *i1 = p1;
1497259ee3d7SHartmut Brandt 	const struct linkinfo *i2 = p2;
1498259ee3d7SHartmut Brandt 
1499259ee3d7SHartmut Brandt 	if (strlen(i1->ourhook) < strlen(i2->ourhook))
1500259ee3d7SHartmut Brandt 		return (-1);
1501259ee3d7SHartmut Brandt 	if (strlen(i1->ourhook) > strlen(i2->ourhook))
1502259ee3d7SHartmut Brandt 		return (+1);
1503259ee3d7SHartmut Brandt 	return (strcmp(i1->ourhook, i2->ourhook));
1504259ee3d7SHartmut Brandt }
1505259ee3d7SHartmut Brandt 
1506259ee3d7SHartmut Brandt static int
find_hook_next(const struct asn_oid * oid,u_int sub,struct nodeinfo * nodeinfo,struct linkinfo * linkinfo)1507259ee3d7SHartmut Brandt find_hook_next(const struct asn_oid *oid, u_int sub, struct nodeinfo *nodeinfo,
1508259ee3d7SHartmut Brandt     struct linkinfo *linkinfo)
1509259ee3d7SHartmut Brandt {
1510259ee3d7SHartmut Brandt 	u_int idxlen = oid->len - sub;
1511259ee3d7SHartmut Brandt 	struct namelist *list;
1512259ee3d7SHartmut Brandt 	struct ng_mesg *resp;
1513259ee3d7SHartmut Brandt 	struct hooklist *hooks;
1514259ee3d7SHartmut Brandt 	struct ng_mesg *resp1;
1515259ee3d7SHartmut Brandt 	u_int node_index;
1516259ee3d7SHartmut Brandt 	struct asn_oid idx;
1517259ee3d7SHartmut Brandt 	u_int i, j;
1518259ee3d7SHartmut Brandt 
1519259ee3d7SHartmut Brandt 	/*
1520259ee3d7SHartmut Brandt 	 * Get and sort Node list
1521259ee3d7SHartmut Brandt 	 */
1522259ee3d7SHartmut Brandt 	if ((resp = ng_dialog_id(snmp_node, NGM_GENERIC_COOKIE, NGM_LISTNODES,
1523259ee3d7SHartmut Brandt 	    NULL, 0)) == NULL)
1524259ee3d7SHartmut Brandt 		return (-1);
1525259ee3d7SHartmut Brandt 	list = (struct namelist *)(void *)resp->data;
1526259ee3d7SHartmut Brandt 
1527259ee3d7SHartmut Brandt 	qsort(list->nodeinfo, list->numnames, sizeof(list->nodeinfo[0]), ncmp);
1528259ee3d7SHartmut Brandt 
1529259ee3d7SHartmut Brandt 	/*
1530259ee3d7SHartmut Brandt 	 * If we have no index, take the first node and return the
1531259ee3d7SHartmut Brandt 	 * first hook.
1532259ee3d7SHartmut Brandt 	 */
1533259ee3d7SHartmut Brandt 	if (idxlen == 0) {
1534259ee3d7SHartmut Brandt 		node_index = 0;
1535259ee3d7SHartmut Brandt 		goto return_first_hook;
1536259ee3d7SHartmut Brandt 	}
1537259ee3d7SHartmut Brandt 
1538259ee3d7SHartmut Brandt 	/*
1539259ee3d7SHartmut Brandt 	 * Locate node
1540259ee3d7SHartmut Brandt 	 */
1541259ee3d7SHartmut Brandt 	for (node_index = 0; node_index < list->numnames; node_index++)
1542259ee3d7SHartmut Brandt 		if (list->nodeinfo[node_index].id >= oid->subs[sub])
1543259ee3d7SHartmut Brandt 			break;
1544259ee3d7SHartmut Brandt 
1545259ee3d7SHartmut Brandt 	/*
1546259ee3d7SHartmut Brandt 	 * If we have only the node part of the index take, or
1547259ee3d7SHartmut Brandt 	 * there is no node with that Id, take the first hook of that node.
1548259ee3d7SHartmut Brandt 	 */
1549259ee3d7SHartmut Brandt 	if (idxlen == 1 || node_index >= list->numnames ||
1550259ee3d7SHartmut Brandt 	    list->nodeinfo[node_index].id > oid->subs[sub])
1551259ee3d7SHartmut Brandt 		goto return_first_hook;
1552259ee3d7SHartmut Brandt 
1553259ee3d7SHartmut Brandt 	/*
1554259ee3d7SHartmut Brandt 	 * We had an exact match on the node id and have (at last part)
1555259ee3d7SHartmut Brandt 	 * of the hook name index. Loop through the hooks of the node
1556259ee3d7SHartmut Brandt 	 * and find the next one.
1557259ee3d7SHartmut Brandt 	 */
1558259ee3d7SHartmut Brandt 	if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id,
1559259ee3d7SHartmut Brandt 	    NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL) {
1560259ee3d7SHartmut Brandt 		free(resp);
1561259ee3d7SHartmut Brandt 		return (-1);
1562259ee3d7SHartmut Brandt 	}
1563259ee3d7SHartmut Brandt 	hooks = (struct hooklist *)(void *)resp1->data;
1564259ee3d7SHartmut Brandt 	if (hooks->nodeinfo.hooks > 0) {
1565259ee3d7SHartmut Brandt 		qsort(hooks->link, hooks->nodeinfo.hooks,
1566259ee3d7SHartmut Brandt 		    sizeof(hooks->link[0]), hook_cmp);
1567259ee3d7SHartmut Brandt 		for (i = 0; i < hooks->nodeinfo.hooks; i++) {
1568259ee3d7SHartmut Brandt 			idx.len = strlen(hooks->link[i].ourhook) + 1;
1569259ee3d7SHartmut Brandt 			idx.subs[0] = idx.len - 1;
1570259ee3d7SHartmut Brandt 			for (j = 0; j < idx.len; j++)
1571259ee3d7SHartmut Brandt 				idx.subs[j + 1] = hooks->link[i].ourhook[j];
1572259ee3d7SHartmut Brandt 			if (index_compare(oid, sub + 1, &idx) < 0)
1573259ee3d7SHartmut Brandt 				break;
1574259ee3d7SHartmut Brandt 		}
1575259ee3d7SHartmut Brandt 		if (i < hooks->nodeinfo.hooks) {
1576259ee3d7SHartmut Brandt 			*nodeinfo = hooks->nodeinfo;
1577259ee3d7SHartmut Brandt 			*linkinfo = hooks->link[i];
1578259ee3d7SHartmut Brandt 
1579259ee3d7SHartmut Brandt 			free(resp);
1580259ee3d7SHartmut Brandt 			free(resp1);
1581259ee3d7SHartmut Brandt 			return (0);
1582259ee3d7SHartmut Brandt 		}
1583259ee3d7SHartmut Brandt 	}
1584259ee3d7SHartmut Brandt 
1585259ee3d7SHartmut Brandt 	/* no hook found larger than the index on the index node - take
1586259ee3d7SHartmut Brandt 	 * first hook of next node */
1587259ee3d7SHartmut Brandt 	free(resp1);
1588259ee3d7SHartmut Brandt 	node_index++;
1589259ee3d7SHartmut Brandt 
1590259ee3d7SHartmut Brandt   return_first_hook:
1591259ee3d7SHartmut Brandt 	while (node_index < list->numnames) {
1592259ee3d7SHartmut Brandt 		if ((resp1 = ng_dialog_id(list->nodeinfo[node_index].id,
1593259ee3d7SHartmut Brandt 		    NGM_GENERIC_COOKIE, NGM_LISTHOOKS, NULL, 0)) == NULL)
1594259ee3d7SHartmut Brandt 			break;
1595259ee3d7SHartmut Brandt 		hooks = (struct hooklist *)(void *)resp1->data;
1596259ee3d7SHartmut Brandt 		if (hooks->nodeinfo.hooks > 0) {
1597259ee3d7SHartmut Brandt 			qsort(hooks->link, hooks->nodeinfo.hooks,
1598259ee3d7SHartmut Brandt 			    sizeof(hooks->link[0]), hook_cmp);
1599259ee3d7SHartmut Brandt 
1600259ee3d7SHartmut Brandt 			*nodeinfo = hooks->nodeinfo;
1601259ee3d7SHartmut Brandt 			*linkinfo = hooks->link[0];
1602259ee3d7SHartmut Brandt 
1603259ee3d7SHartmut Brandt 			free(resp);
1604259ee3d7SHartmut Brandt 			free(resp1);
1605259ee3d7SHartmut Brandt 			return (0);
1606259ee3d7SHartmut Brandt 		}
1607259ee3d7SHartmut Brandt 
1608259ee3d7SHartmut Brandt 		/* if we don't have hooks, try next node */
1609259ee3d7SHartmut Brandt 		free(resp1);
1610259ee3d7SHartmut Brandt 		node_index++;
1611259ee3d7SHartmut Brandt 	}
1612259ee3d7SHartmut Brandt 
1613259ee3d7SHartmut Brandt 	free(resp);
1614259ee3d7SHartmut Brandt 	return (-1);
1615259ee3d7SHartmut Brandt }
1616259ee3d7SHartmut Brandt 
1617259ee3d7SHartmut Brandt int
op_ng_hook(struct snmp_context * ctx __unused,struct snmp_value * value,u_int sub,u_int iidx,enum snmp_op op)1618259ee3d7SHartmut Brandt op_ng_hook(struct snmp_context *ctx __unused, struct snmp_value *value,
1619259ee3d7SHartmut Brandt     u_int sub, u_int iidx, enum snmp_op op)
1620259ee3d7SHartmut Brandt {
1621259ee3d7SHartmut Brandt 	asn_subid_t which = value->var.subs[sub - 1];
1622259ee3d7SHartmut Brandt 	struct linkinfo linkinfo;
1623259ee3d7SHartmut Brandt 	struct nodeinfo nodeinfo;
1624259ee3d7SHartmut Brandt 	u_int32_t lid;
1625259ee3d7SHartmut Brandt 	u_char *hook;
1626259ee3d7SHartmut Brandt 	size_t hooklen;
1627259ee3d7SHartmut Brandt 	u_int i;
1628259ee3d7SHartmut Brandt 
1629259ee3d7SHartmut Brandt 	switch (op) {
1630259ee3d7SHartmut Brandt 
1631259ee3d7SHartmut Brandt 	  case SNMP_OP_GETNEXT:
1632259ee3d7SHartmut Brandt 		if (find_hook_next(&value->var, sub, &nodeinfo, &linkinfo) == -1)
1633259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1634259ee3d7SHartmut Brandt 
1635259ee3d7SHartmut Brandt 		value->var.len = sub + 1 + 1 + strlen(linkinfo.ourhook);
1636259ee3d7SHartmut Brandt 		value->var.subs[sub] = nodeinfo.id;
1637259ee3d7SHartmut Brandt 		value->var.subs[sub + 1] = strlen(linkinfo.ourhook);
1638259ee3d7SHartmut Brandt 		for (i = 0; i < strlen(linkinfo.ourhook); i++)
1639259ee3d7SHartmut Brandt 			value->var.subs[sub + i + 2] =
1640259ee3d7SHartmut Brandt 			    linkinfo.ourhook[i];
1641259ee3d7SHartmut Brandt 		break;
1642259ee3d7SHartmut Brandt 
1643259ee3d7SHartmut Brandt 	  case SNMP_OP_GET:
1644259ee3d7SHartmut Brandt 		if (index_decode(&value->var, sub, iidx, &lid,
1645259ee3d7SHartmut Brandt 		    &hook, &hooklen))
1646259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1647259ee3d7SHartmut Brandt 		if (find_hook(lid, hook, hooklen, &linkinfo) == -1) {
1648259ee3d7SHartmut Brandt 			free(hook);
1649259ee3d7SHartmut Brandt 			return (SNMP_ERR_NOSUCHNAME);
1650259ee3d7SHartmut Brandt 		}
1651259ee3d7SHartmut Brandt 		free(hook);
1652259ee3d7SHartmut Brandt 		break;
1653259ee3d7SHartmut Brandt 
1654259ee3d7SHartmut Brandt 	  case SNMP_OP_SET:
1655259ee3d7SHartmut Brandt 		if (index_decode(&value->var, sub, iidx, &lid,
1656259ee3d7SHartmut Brandt 		    &hook, &hooklen))
1657259ee3d7SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1658259ee3d7SHartmut Brandt 		if (find_hook(lid, hook, hooklen, &linkinfo) == -1) {
1659259ee3d7SHartmut Brandt 			free(hook);
1660259ee3d7SHartmut Brandt 			return (SNMP_ERR_NO_CREATION);
1661259ee3d7SHartmut Brandt 		}
1662259ee3d7SHartmut Brandt 		free(hook);
1663259ee3d7SHartmut Brandt 		return (SNMP_ERR_NOT_WRITEABLE);
1664259ee3d7SHartmut Brandt 
1665259ee3d7SHartmut Brandt 	  case SNMP_OP_ROLLBACK:
1666259ee3d7SHartmut Brandt 	  case SNMP_OP_COMMIT:
1667259ee3d7SHartmut Brandt 	  default:
1668259ee3d7SHartmut Brandt 		abort();
1669259ee3d7SHartmut Brandt 
1670259ee3d7SHartmut Brandt 	}
1671259ee3d7SHartmut Brandt 
1672259ee3d7SHartmut Brandt 	switch (which) {
1673259ee3d7SHartmut Brandt 
1674259ee3d7SHartmut Brandt 	  case LEAF_begemotNgHookStatus:
1675259ee3d7SHartmut Brandt 		value->v.integer = 1;
1676259ee3d7SHartmut Brandt 		break;
1677259ee3d7SHartmut Brandt 	  case LEAF_begemotNgHookPeerNodeId:
1678259ee3d7SHartmut Brandt 		value->v.uint32 = linkinfo.nodeinfo.id;
1679259ee3d7SHartmut Brandt 		break;
1680259ee3d7SHartmut Brandt 	  case LEAF_begemotNgHookPeerHook:
1681259ee3d7SHartmut Brandt 		return (string_get(value, linkinfo.peerhook, -1));
1682259ee3d7SHartmut Brandt 	  case LEAF_begemotNgHookPeerType:
1683259ee3d7SHartmut Brandt 		return (string_get(value, linkinfo.nodeinfo.type, -1));
1684259ee3d7SHartmut Brandt 	  default:
1685259ee3d7SHartmut Brandt 		abort();
1686259ee3d7SHartmut Brandt 	}
1687259ee3d7SHartmut Brandt 	return (SNMP_ERR_NOERROR);
1688259ee3d7SHartmut Brandt }
1689