1122394Sharti/*
2122394Sharti * Copyright (c) 2001-2003
3122394Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122394Sharti *	All rights reserved.
5122394Sharti *
6122394Sharti * Author: Harti Brandt <harti@freebsd.org>
7133211Sharti *
8133211Sharti * Redistribution and use in source and binary forms, with or without
9133211Sharti * modification, are permitted provided that the following conditions
10133211Sharti * are met:
11133211Sharti * 1. Redistributions of source code must retain the above copyright
12133211Sharti *    notice, this list of conditions and the following disclaimer.
13122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
14122394Sharti *    notice, this list of conditions and the following disclaimer in the
15122394Sharti *    documentation and/or other materials provided with the distribution.
16133211Sharti *
17133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27133211Sharti * SUCH DAMAGE.
28122394Sharti *
29150920Sharti * $Begemot: bsnmp/lib/snmpagent.c,v 1.20 2005/10/04 11:21:33 brandt_h Exp $
30122394Sharti *
31122394Sharti * SNMP Agent functions
32122394Sharti */
33122394Sharti#include <sys/types.h>
34122394Sharti#include <sys/queue.h>
35122394Sharti#include <stdio.h>
36122394Sharti#include <stdlib.h>
37122394Sharti#include <stddef.h>
38122394Sharti#include <stdarg.h>
39150920Sharti#ifdef HAVE_STDINT_H
40133211Sharti#include <stdint.h>
41150920Sharti#elif defined(HAVE_INTTYPES_H)
42150920Sharti#include <inttypes.h>
43150920Sharti#endif
44122394Sharti#include <string.h>
45122394Sharti
46122394Sharti#include "asn1.h"
47122394Sharti#include "snmp.h"
48122394Sharti#include "snmppriv.h"
49122394Sharti#include "snmpagent.h"
50122394Sharti
51122394Shartistatic void snmp_debug_func(const char *fmt, ...);
52122394Sharti
53122394Shartivoid (*snmp_debug)(const char *fmt, ...) = snmp_debug_func;
54122394Sharti
55122394Shartistruct snmp_node *tree;
56122394Shartiu_int  tree_size;
57122394Sharti
58122394Sharti/*
59122394Sharti * Structure to hold dependencies during SET processing
60122394Sharti * The last two members of this structure must be the
61122394Sharti * dependency visible by the user and the user data.
62122394Sharti */
63122394Shartistruct depend {
64122394Sharti	TAILQ_ENTRY(depend) link;
65122394Sharti	size_t	len;		/* size of data part */
66122394Sharti	snmp_depop_t	func;
67122394Sharti	struct snmp_dependency dep;
68133211Sharti#if defined(__GNUC__) && __GNUC__ < 3
69133211Sharti	u_char	data[0];
70133211Sharti#else
71122394Sharti	u_char	data[];
72133211Sharti#endif
73122394Sharti};
74122394ShartiTAILQ_HEAD(depend_list, depend);
75122394Sharti
76122394Sharti/*
77122394Sharti * Set context
78122394Sharti */
79122394Shartistruct context {
80122394Sharti	struct snmp_context	ctx;
81122394Sharti	struct depend_list	dlist;
82122394Sharti	const struct snmp_node	*node[SNMP_MAX_BINDINGS];
83122394Sharti	struct snmp_scratch	scratch[SNMP_MAX_BINDINGS];
84122394Sharti	struct depend		*depend;
85122394Sharti};
86122394Sharti
87122394Sharti#define	TR(W)	(snmp_trace & SNMP_TRACE_##W)
88122394Shartiu_int snmp_trace = 0;
89122394Sharti
90122394Shartistatic char oidbuf[ASN_OIDSTRLEN];
91122394Sharti
92122394Sharti/*
93122394Sharti * Allocate a context
94122394Sharti */
95122394Shartistruct snmp_context *
96122394Shartisnmp_init_context(void)
97122394Sharti{
98122394Sharti	struct context *context;
99122394Sharti
100122394Sharti	if ((context = malloc(sizeof(*context))) == NULL)
101122394Sharti		return (NULL);
102122394Sharti
103122394Sharti	memset(context, 0, sizeof(*context));
104122394Sharti	TAILQ_INIT(&context->dlist);
105122394Sharti
106122394Sharti	return (&context->ctx);
107122394Sharti}
108122394Sharti
109122394Sharti/*
110122394Sharti * Find a variable for SET/GET and the first GETBULK pass.
111122394Sharti * Return the node pointer. If the search fails, set the errp to
112122394Sharti * the correct SNMPv2 GET exception code.
113122394Sharti */
114122394Shartistatic struct snmp_node *
115122394Shartifind_node(const struct snmp_value *value, enum snmp_syntax *errp)
116122394Sharti{
117122394Sharti	struct snmp_node *tp;
118122394Sharti
119122394Sharti	if (TR(FIND))
120122394Sharti		snmp_debug("find: searching %s",
121122394Sharti		    asn_oid2str_r(&value->var, oidbuf));
122122394Sharti
123122394Sharti	/*
124122394Sharti	 * If we have an exact match (the entry in the table is a
125122394Sharti	 * sub-oid from the variable) we have found what we are for.
126122394Sharti	 * If the table oid is higher than the variable, there is no match.
127122394Sharti	 */
128122394Sharti	for (tp = tree; tp < tree + tree_size; tp++) {
129122394Sharti		if (asn_is_suboid(&tp->oid, &value->var))
130122394Sharti			goto found;
131122394Sharti		if (asn_compare_oid(&tp->oid, &value->var) >= 0)
132122394Sharti			break;
133122394Sharti	}
134122394Sharti
135122394Sharti	if (TR(FIND))
136122394Sharti		snmp_debug("find: no match");
137122394Sharti	*errp = SNMP_SYNTAX_NOSUCHOBJECT;
138122394Sharti	return (NULL);
139122394Sharti
140122394Sharti  found:
141122394Sharti	/* leafs must have a 0 instance identifier */
142122394Sharti	if (tp->type == SNMP_NODE_LEAF &&
143122394Sharti	    (value->var.len != tp->oid.len + 1 ||
144122394Sharti	     value->var.subs[tp->oid.len] != 0)) {
145122394Sharti		if (TR(FIND))
146122394Sharti			snmp_debug("find: bad leaf index");
147122394Sharti		*errp = SNMP_SYNTAX_NOSUCHINSTANCE;
148122394Sharti		return (NULL);
149122394Sharti	}
150122394Sharti	if (TR(FIND))
151122394Sharti		snmp_debug("find: found %s",
152122394Sharti		    asn_oid2str_r(&value->var, oidbuf));
153122394Sharti	return (tp);
154122394Sharti}
155122394Sharti
156122394Shartistatic struct snmp_node *
157122394Shartifind_subnode(const struct snmp_value *value)
158122394Sharti{
159122394Sharti	struct snmp_node *tp;
160122394Sharti
161122394Sharti	for (tp = tree; tp < tree + tree_size; tp++) {
162122394Sharti		if (asn_is_suboid(&value->var, &tp->oid))
163122394Sharti			return (tp);
164122394Sharti	}
165122394Sharti	return (NULL);
166122394Sharti}
167122394Sharti
168216294Ssyrinxstatic void
169216294Ssyrinxsnmp_pdu_create_response(struct snmp_pdu *pdu, struct snmp_pdu *resp)
170216294Ssyrinx{
171216294Ssyrinx	memset(resp, 0, sizeof(*resp));
172216294Ssyrinx	strcpy(resp->community, pdu->community);
173216294Ssyrinx	resp->version = pdu->version;
174216294Ssyrinx	resp->type = SNMP_PDU_RESPONSE;
175216294Ssyrinx	resp->request_id = pdu->request_id;
176216294Ssyrinx	resp->version = pdu->version;
177216294Ssyrinx
178216294Ssyrinx	if (resp->version != SNMP_V3)
179216294Ssyrinx		return;
180216294Ssyrinx
181216594Ssyrinx	memcpy(&resp->engine, &pdu->engine, sizeof(pdu->engine));
182216594Ssyrinx	memcpy(&resp->user, &pdu->user, sizeof(pdu->user));
183216594Ssyrinx	snmp_pdu_init_secparams(resp);
184216294Ssyrinx	resp->identifier = pdu->identifier;
185216294Ssyrinx	resp->security_model = pdu->security_model;
186216294Ssyrinx	resp->context_engine_len = pdu->context_engine_len;
187216294Ssyrinx	memcpy(resp->context_engine, pdu->context_engine,
188216294Ssyrinx	    resp->context_engine_len);
189216294Ssyrinx	strlcpy(resp->context_name, pdu->context_name,
190216294Ssyrinx	    sizeof(resp->context_name));
191216294Ssyrinx}
192216294Ssyrinx
193122394Sharti/*
194122394Sharti * Execute a GET operation. The tree is rooted at the global 'root'.
195122394Sharti * Build the response PDU on the fly. If the return code is SNMP_RET_ERR
196122394Sharti * the pdu error status and index will be set.
197122394Sharti */
198122394Shartienum snmp_ret
199122394Shartisnmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b,
200122394Sharti    struct snmp_pdu *resp, void *data)
201122394Sharti{
202122394Sharti	int ret;
203122394Sharti	u_int i;
204122394Sharti	struct snmp_node *tp;
205122394Sharti	enum snmp_syntax except;
206122394Sharti	struct context context;
207122394Sharti	enum asn_err err;
208122394Sharti
209122394Sharti	memset(&context, 0, sizeof(context));
210122394Sharti	context.ctx.data = data;
211122394Sharti
212216294Ssyrinx	snmp_pdu_create_response(pdu, resp);
213122394Sharti
214122394Sharti	if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
215122394Sharti		/* cannot even encode header - very bad */
216122394Sharti		return (SNMP_RET_IGN);
217122394Sharti
218122394Sharti	for (i = 0; i < pdu->nbindings; i++) {
219122394Sharti		resp->bindings[i].var = pdu->bindings[i].var;
220122394Sharti		if ((tp = find_node(&pdu->bindings[i], &except)) == NULL) {
221122394Sharti			if (pdu->version == SNMP_V1) {
222122394Sharti				if (TR(GET))
223122394Sharti					snmp_debug("get: nosuchname");
224122394Sharti				pdu->error_status = SNMP_ERR_NOSUCHNAME;
225122394Sharti				pdu->error_index = i + 1;
226122394Sharti				snmp_pdu_free(resp);
227122394Sharti				return (SNMP_RET_ERR);
228122394Sharti			}
229122394Sharti			if (TR(GET))
230122394Sharti				snmp_debug("get: exception %u", except);
231122394Sharti			resp->bindings[i].syntax = except;
232122394Sharti
233122394Sharti		} else {
234122394Sharti			/* call the action to fetch the value. */
235122394Sharti			resp->bindings[i].syntax = tp->syntax;
236122394Sharti			ret = (*tp->op)(&context.ctx, &resp->bindings[i],
237122394Sharti			    tp->oid.len, tp->index, SNMP_OP_GET);
238122394Sharti			if (TR(GET))
239122394Sharti				snmp_debug("get: action returns %d", ret);
240122394Sharti
241122394Sharti			if (ret == SNMP_ERR_NOSUCHNAME) {
242122394Sharti				if (pdu->version == SNMP_V1) {
243122394Sharti					pdu->error_status = SNMP_ERR_NOSUCHNAME;
244122394Sharti					pdu->error_index = i + 1;
245122394Sharti					snmp_pdu_free(resp);
246122394Sharti					return (SNMP_RET_ERR);
247122394Sharti				}
248122394Sharti				if (TR(GET))
249122394Sharti					snmp_debug("get: exception noSuchInstance");
250122394Sharti				resp->bindings[i].syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
251122394Sharti
252122394Sharti			} else if (ret != SNMP_ERR_NOERROR) {
253122394Sharti				pdu->error_status = SNMP_ERR_GENERR;
254122394Sharti				pdu->error_index = i + 1;
255122394Sharti				snmp_pdu_free(resp);
256122394Sharti				return (SNMP_RET_ERR);
257122394Sharti			}
258122394Sharti		}
259122394Sharti		resp->nbindings++;
260122394Sharti
261122394Sharti		err = snmp_binding_encode(resp_b, &resp->bindings[i]);
262122394Sharti
263122394Sharti		if (err == ASN_ERR_EOBUF) {
264122394Sharti			pdu->error_status = SNMP_ERR_TOOBIG;
265122394Sharti			pdu->error_index = 0;
266122394Sharti			snmp_pdu_free(resp);
267122394Sharti			return (SNMP_RET_ERR);
268122394Sharti		}
269122394Sharti		if (err != ASN_ERR_OK) {
270122394Sharti			if (TR(GET))
271122394Sharti				snmp_debug("get: binding encoding: %u", err);
272122394Sharti			pdu->error_status = SNMP_ERR_GENERR;
273122394Sharti			pdu->error_index = i + 1;
274122394Sharti			snmp_pdu_free(resp);
275122394Sharti			return (SNMP_RET_ERR);
276122394Sharti		}
277122394Sharti	}
278122394Sharti
279122394Sharti	return (snmp_fix_encoding(resp_b, resp));
280122394Sharti}
281122394Sharti
282122394Shartistatic struct snmp_node *
283122394Shartinext_node(const struct snmp_value *value, int *pnext)
284122394Sharti{
285122394Sharti	struct snmp_node *tp;
286122394Sharti
287122394Sharti	if (TR(FIND))
288122394Sharti		snmp_debug("next: searching %s",
289122394Sharti		    asn_oid2str_r(&value->var, oidbuf));
290122394Sharti
291122394Sharti	*pnext = 0;
292122394Sharti	for (tp = tree; tp < tree + tree_size; tp++) {
293122394Sharti		if (asn_is_suboid(&tp->oid, &value->var)) {
294122394Sharti			/* the tree OID is a sub-oid of the requested OID. */
295122394Sharti			if (tp->type == SNMP_NODE_LEAF) {
296122394Sharti				if (tp->oid.len == value->var.len) {
297122394Sharti					/* request for scalar type */
298122394Sharti					if (TR(FIND))
299122394Sharti						snmp_debug("next: found scalar %s",
300122394Sharti						    asn_oid2str_r(&tp->oid, oidbuf));
301122394Sharti					return (tp);
302122394Sharti				}
303122394Sharti				/* try next */
304122394Sharti			} else {
305122394Sharti				if (TR(FIND))
306122394Sharti					snmp_debug("next: found column %s",
307122394Sharti					    asn_oid2str_r(&tp->oid, oidbuf));
308122394Sharti				return (tp);
309122394Sharti			}
310122394Sharti		} else if (asn_is_suboid(&value->var, &tp->oid) ||
311122394Sharti		    asn_compare_oid(&tp->oid, &value->var) >= 0) {
312122394Sharti			if (TR(FIND))
313122394Sharti				snmp_debug("next: found %s",
314122394Sharti				    asn_oid2str_r(&tp->oid, oidbuf));
315122394Sharti			*pnext = 1;
316122394Sharti			return (tp);
317122394Sharti		}
318122394Sharti	}
319122394Sharti
320122394Sharti	if (TR(FIND))
321122394Sharti		snmp_debug("next: failed");
322122394Sharti
323122394Sharti	return (NULL);
324122394Sharti}
325122394Sharti
326122394Shartistatic enum snmp_ret
327122394Shartido_getnext(struct context *context, const struct snmp_value *inb,
328122394Sharti    struct snmp_value *outb, struct snmp_pdu *pdu)
329122394Sharti{
330122394Sharti	const struct snmp_node *tp;
331122394Sharti	int ret, next;
332122394Sharti
333122394Sharti	if ((tp = next_node(inb, &next)) == NULL)
334122394Sharti		goto eofMib;
335122394Sharti
336122394Sharti	/* retain old variable if we are doing a GETNEXT on an exact
337122394Sharti	 * matched leaf only */
338122394Sharti	if (tp->type == SNMP_NODE_LEAF || next)
339122394Sharti		outb->var = tp->oid;
340122394Sharti	else
341122394Sharti		outb->var = inb->var;
342122394Sharti
343122394Sharti	for (;;) {
344122394Sharti		outb->syntax = tp->syntax;
345122394Sharti		if (tp->type == SNMP_NODE_LEAF) {
346122394Sharti			/* make a GET operation */
347122394Sharti			outb->var.subs[outb->var.len++] = 0;
348122394Sharti			ret = (*tp->op)(&context->ctx, outb, tp->oid.len,
349122394Sharti			    tp->index, SNMP_OP_GET);
350122394Sharti		} else {
351122394Sharti			/* make a GETNEXT */
352122394Sharti			ret = (*tp->op)(&context->ctx, outb, tp->oid.len,
353122394Sharti			     tp->index, SNMP_OP_GETNEXT);
354122394Sharti		}
355122394Sharti		if (ret != SNMP_ERR_NOSUCHNAME) {
356122394Sharti			/* got something */
357122394Sharti			if (ret != SNMP_ERR_NOERROR && TR(GETNEXT))
358122394Sharti				snmp_debug("getnext: %s returns %u",
359122394Sharti				    asn_oid2str(&outb->var), ret);
360122394Sharti			break;
361122394Sharti		}
362122394Sharti
363122394Sharti		/* object has no data - try next */
364122394Sharti		if (++tp == tree + tree_size)
365122394Sharti			break;
366142810Sharti
367142810Sharti		if (TR(GETNEXT))
368142810Sharti			snmp_debug("getnext: no data - avancing to %s",
369142810Sharti			    asn_oid2str(&tp->oid));
370142810Sharti
371122394Sharti		outb->var = tp->oid;
372122394Sharti	}
373122394Sharti
374122394Sharti	if (ret == SNMP_ERR_NOSUCHNAME) {
375122394Sharti  eofMib:
376122394Sharti		outb->var = inb->var;
377122394Sharti		if (pdu->version == SNMP_V1) {
378122394Sharti			pdu->error_status = SNMP_ERR_NOSUCHNAME;
379122394Sharti			return (SNMP_RET_ERR);
380122394Sharti		}
381122394Sharti		outb->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
382122394Sharti
383122394Sharti	} else if (ret != SNMP_ERR_NOERROR) {
384122394Sharti		pdu->error_status = SNMP_ERR_GENERR;
385122394Sharti		return (SNMP_RET_ERR);
386122394Sharti	}
387122394Sharti	return (SNMP_RET_OK);
388122394Sharti}
389122394Sharti
390122394Sharti
391122394Sharti/*
392122394Sharti * Execute a GETNEXT operation. The tree is rooted at the global 'root'.
393122394Sharti * Build the response PDU on the fly. The return is:
394122394Sharti */
395122394Shartienum snmp_ret
396122394Shartisnmp_getnext(struct snmp_pdu *pdu, struct asn_buf *resp_b,
397122394Sharti    struct snmp_pdu *resp, void *data)
398122394Sharti{
399122394Sharti	struct context context;
400122394Sharti	u_int i;
401122394Sharti	enum asn_err err;
402122394Sharti	enum snmp_ret result;
403122394Sharti
404122394Sharti	memset(&context, 0, sizeof(context));
405122394Sharti	context.ctx.data = data;
406122394Sharti
407216294Ssyrinx	snmp_pdu_create_response(pdu, resp);
408122394Sharti
409122394Sharti	if (snmp_pdu_encode_header(resp_b, resp))
410122394Sharti		return (SNMP_RET_IGN);
411122394Sharti
412122394Sharti	for (i = 0; i < pdu->nbindings; i++) {
413122394Sharti		result = do_getnext(&context, &pdu->bindings[i],
414122394Sharti		    &resp->bindings[i], pdu);
415122394Sharti
416122394Sharti		if (result != SNMP_RET_OK) {
417122394Sharti			pdu->error_index = i + 1;
418122394Sharti			snmp_pdu_free(resp);
419122394Sharti			return (result);
420122394Sharti		}
421122394Sharti
422122394Sharti		resp->nbindings++;
423122394Sharti
424122394Sharti		err = snmp_binding_encode(resp_b, &resp->bindings[i]);
425122394Sharti
426122394Sharti		if (err == ASN_ERR_EOBUF) {
427122394Sharti			pdu->error_status = SNMP_ERR_TOOBIG;
428122394Sharti			pdu->error_index = 0;
429122394Sharti			snmp_pdu_free(resp);
430122394Sharti			return (SNMP_RET_ERR);
431122394Sharti		}
432122394Sharti		if (err != ASN_ERR_OK) {
433122394Sharti			if (TR(GET))
434122394Sharti				snmp_debug("getnext: binding encoding: %u", err);
435122394Sharti			pdu->error_status = SNMP_ERR_GENERR;
436122394Sharti			pdu->error_index = i + 1;
437122394Sharti			snmp_pdu_free(resp);
438122394Sharti			return (SNMP_RET_ERR);
439122394Sharti		}
440122394Sharti	}
441122394Sharti	return (snmp_fix_encoding(resp_b, resp));
442122394Sharti}
443122394Sharti
444122394Shartienum snmp_ret
445122394Shartisnmp_getbulk(struct snmp_pdu *pdu, struct asn_buf *resp_b,
446122394Sharti    struct snmp_pdu *resp, void *data)
447122394Sharti{
448122394Sharti	struct context context;
449122394Sharti	u_int i;
450122394Sharti	int cnt;
451122394Sharti	u_int non_rep;
452122394Sharti	int eomib;
453122394Sharti	enum snmp_ret result;
454122394Sharti	enum asn_err err;
455122394Sharti
456122394Sharti	memset(&context, 0, sizeof(context));
457122394Sharti	context.ctx.data = data;
458122394Sharti
459216294Ssyrinx	snmp_pdu_create_response(pdu, resp);
460122394Sharti
461122394Sharti	if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
462122394Sharti		/* cannot even encode header - very bad */
463122394Sharti		return (SNMP_RET_IGN);
464122394Sharti
465122394Sharti	if ((non_rep = pdu->error_status) > pdu->nbindings)
466122394Sharti		non_rep = pdu->nbindings;
467122394Sharti
468122394Sharti	/* non-repeaters */
469122394Sharti	for (i = 0; i < non_rep; i++) {
470122394Sharti		result = do_getnext(&context, &pdu->bindings[i],
471122394Sharti		    &resp->bindings[resp->nbindings], pdu);
472122394Sharti
473122394Sharti		if (result != SNMP_RET_OK) {
474122394Sharti			pdu->error_index = i + 1;
475122394Sharti			snmp_pdu_free(resp);
476122394Sharti			return (result);
477122394Sharti		}
478122394Sharti
479122394Sharti		err = snmp_binding_encode(resp_b,
480122394Sharti		    &resp->bindings[resp->nbindings++]);
481122394Sharti
482122394Sharti		if (err == ASN_ERR_EOBUF)
483122394Sharti			goto done;
484122394Sharti
485122394Sharti		if (err != ASN_ERR_OK) {
486122394Sharti			if (TR(GET))
487122394Sharti				snmp_debug("getnext: binding encoding: %u", err);
488122394Sharti			pdu->error_status = SNMP_ERR_GENERR;
489122394Sharti			pdu->error_index = i + 1;
490122394Sharti			snmp_pdu_free(resp);
491122394Sharti			return (SNMP_RET_ERR);
492122394Sharti		}
493122394Sharti	}
494122394Sharti
495122394Sharti	if (non_rep == pdu->nbindings)
496122394Sharti		goto done;
497122394Sharti
498122394Sharti	/* repeates */
499122394Sharti	for (cnt = 0; cnt < pdu->error_index; cnt++) {
500122394Sharti		eomib = 1;
501122394Sharti		for (i = non_rep; i < pdu->nbindings; i++) {
502260638Sdelphij
503260638Sdelphij			if (resp->nbindings == SNMP_MAX_BINDINGS)
504260638Sdelphij				/* PDU is full */
505260638Sdelphij				goto done;
506260638Sdelphij
507122394Sharti			if (cnt == 0)
508122394Sharti				result = do_getnext(&context, &pdu->bindings[i],
509122394Sharti				    &resp->bindings[resp->nbindings], pdu);
510122394Sharti			else
511122394Sharti				result = do_getnext(&context,
512122394Sharti				    &resp->bindings[resp->nbindings -
513122394Sharti				    (pdu->nbindings - non_rep)],
514122394Sharti				    &resp->bindings[resp->nbindings], pdu);
515122394Sharti
516122394Sharti			if (result != SNMP_RET_OK) {
517122394Sharti				pdu->error_index = i + 1;
518122394Sharti				snmp_pdu_free(resp);
519122394Sharti				return (result);
520122394Sharti			}
521122394Sharti			if (resp->bindings[resp->nbindings].syntax !=
522122394Sharti			    SNMP_SYNTAX_ENDOFMIBVIEW)
523122394Sharti				eomib = 0;
524122394Sharti
525122394Sharti			err = snmp_binding_encode(resp_b,
526122394Sharti			    &resp->bindings[resp->nbindings++]);
527122394Sharti
528122394Sharti			if (err == ASN_ERR_EOBUF)
529122394Sharti				goto done;
530122394Sharti
531122394Sharti			if (err != ASN_ERR_OK) {
532122394Sharti				if (TR(GET))
533122394Sharti					snmp_debug("getnext: binding encoding: %u", err);
534122394Sharti				pdu->error_status = SNMP_ERR_GENERR;
535122394Sharti				pdu->error_index = i + 1;
536122394Sharti				snmp_pdu_free(resp);
537122394Sharti				return (SNMP_RET_ERR);
538122394Sharti			}
539122394Sharti		}
540122394Sharti		if (eomib)
541122394Sharti			break;
542122394Sharti	}
543122394Sharti
544122394Sharti  done:
545122394Sharti	return (snmp_fix_encoding(resp_b, resp));
546122394Sharti}
547122394Sharti
548122394Sharti/*
549122394Sharti * Rollback a SET operation. Failed index is 'i'.
550122394Sharti */
551122394Shartistatic void
552122394Shartirollback(struct context *context, struct snmp_pdu *pdu, u_int i)
553122394Sharti{
554122394Sharti	struct snmp_value *b;
555122394Sharti	const struct snmp_node *np;
556122394Sharti	int ret;
557122394Sharti
558122394Sharti	while (i-- > 0) {
559122394Sharti		b = &pdu->bindings[i];
560122394Sharti		np = context->node[i];
561122394Sharti
562122394Sharti		context->ctx.scratch = &context->scratch[i];
563122394Sharti
564122394Sharti		ret = (*np->op)(&context->ctx, b, np->oid.len, np->index,
565122394Sharti		    SNMP_OP_ROLLBACK);
566122394Sharti
567122394Sharti		if (ret != SNMP_ERR_NOERROR) {
568122394Sharti			snmp_error("set: rollback failed (%d) on variable %s "
569122394Sharti			    "index %u", ret, asn_oid2str(&b->var), i);
570122394Sharti			if (pdu->version != SNMP_V1) {
571122394Sharti				pdu->error_status = SNMP_ERR_UNDO_FAILED;
572122394Sharti				pdu->error_index = 0;
573122394Sharti			}
574122394Sharti		}
575122394Sharti	}
576122394Sharti}
577122394Sharti
578122394Sharti/*
579122394Sharti * Commit dependencies.
580122394Sharti */
581122394Shartiint
582122394Shartisnmp_dep_commit(struct snmp_context *ctx)
583122394Sharti{
584122394Sharti	struct context *context = (struct context *)ctx;
585122394Sharti	int ret;
586122394Sharti
587122394Sharti	TAILQ_FOREACH(context->depend, &context->dlist, link) {
588122394Sharti		ctx->dep = &context->depend->dep;
589122394Sharti
590122394Sharti		if (TR(SET))
591122394Sharti			snmp_debug("set: dependency commit %s",
592122394Sharti			    asn_oid2str(&ctx->dep->obj));
593122394Sharti
594122394Sharti		ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_COMMIT);
595122394Sharti
596122394Sharti		if (ret != SNMP_ERR_NOERROR) {
597122394Sharti			if (TR(SET))
598122394Sharti				snmp_debug("set: dependency failed %d", ret);
599122394Sharti			return (ret);
600122394Sharti		}
601122394Sharti	}
602122394Sharti	return (SNMP_ERR_NOERROR);
603122394Sharti}
604122394Sharti
605122394Sharti/*
606122394Sharti * Rollback dependencies
607122394Sharti */
608122394Shartiint
609122394Shartisnmp_dep_rollback(struct snmp_context *ctx)
610122394Sharti{
611122394Sharti	struct context *context = (struct context *)ctx;
612122394Sharti	int ret, ret1;
613122394Sharti	char objbuf[ASN_OIDSTRLEN];
614122394Sharti	char idxbuf[ASN_OIDSTRLEN];
615122394Sharti
616122394Sharti	ret1 = SNMP_ERR_NOERROR;
617122394Sharti	while ((context->depend =
618122394Sharti	    TAILQ_PREV(context->depend, depend_list, link)) != NULL) {
619122394Sharti		ctx->dep = &context->depend->dep;
620122394Sharti
621122394Sharti		if (TR(SET))
622122394Sharti			snmp_debug("set: dependency rollback %s",
623122394Sharti			    asn_oid2str(&ctx->dep->obj));
624122394Sharti
625122394Sharti		ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_ROLLBACK);
626122394Sharti
627122394Sharti		if (ret != SNMP_ERR_NOERROR) {
628122394Sharti			snmp_debug("set: dep rollback returns %u: %s %s", ret,
629122394Sharti			    asn_oid2str_r(&ctx->dep->obj, objbuf),
630122394Sharti			    asn_oid2str_r(&ctx->dep->idx, idxbuf));
631122394Sharti			if (ret1 == SNMP_ERR_NOERROR)
632122394Sharti				ret1 = ret;
633122394Sharti		}
634122394Sharti	}
635122394Sharti	return (ret1);
636122394Sharti}
637122394Sharti
638128237Shartivoid
639128237Shartisnmp_dep_finish(struct snmp_context *ctx)
640128237Sharti{
641128237Sharti	struct context *context = (struct context *)ctx;
642128237Sharti	struct depend *d;
643128237Sharti
644128237Sharti	while ((d = TAILQ_FIRST(&context->dlist)) != NULL) {
645128237Sharti		ctx->dep = &d->dep;
646128237Sharti		(void)d->func(ctx, ctx->dep, SNMP_DEPOP_FINISH);
647128237Sharti		TAILQ_REMOVE(&context->dlist, d, link);
648128237Sharti		free(d);
649128237Sharti	}
650128237Sharti}
651128237Sharti
652122394Sharti/*
653122394Sharti * Do a SET operation.
654122394Sharti */
655122394Shartienum snmp_ret
656122394Shartisnmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b,
657122394Sharti    struct snmp_pdu *resp, void *data)
658122394Sharti{
659122394Sharti	int ret;
660122394Sharti	u_int i;
661122394Sharti	enum asn_err asnerr;
662122394Sharti	struct context context;
663122394Sharti	const struct snmp_node *np;
664122394Sharti	struct snmp_value *b;
665122394Sharti	enum snmp_syntax except;
666122394Sharti
667122394Sharti	memset(&context, 0, sizeof(context));
668122394Sharti	TAILQ_INIT(&context.dlist);
669122394Sharti	context.ctx.data = data;
670122394Sharti
671216294Ssyrinx	snmp_pdu_create_response(pdu, resp);
672122394Sharti
673122394Sharti	if (snmp_pdu_encode_header(resp_b, resp))
674122394Sharti		return (SNMP_RET_IGN);
675122394Sharti
676122394Sharti	/*
677122394Sharti	 * 1. Find all nodes, check that they are writeable and
678122394Sharti	 *    that the syntax is ok, copy over the binding to the response.
679122394Sharti	 */
680122394Sharti	for (i = 0; i < pdu->nbindings; i++) {
681122394Sharti		b = &pdu->bindings[i];
682122394Sharti
683122394Sharti		if ((np = context.node[i] = find_node(b, &except)) == NULL) {
684122394Sharti			/* not found altogether or LEAF with wrong index */
685122394Sharti			if (TR(SET))
686122394Sharti				snmp_debug("set: node not found %s",
687122394Sharti				    asn_oid2str_r(&b->var, oidbuf));
688122394Sharti			if (pdu->version == SNMP_V1) {
689122394Sharti				pdu->error_index = i + 1;
690122394Sharti				pdu->error_status = SNMP_ERR_NOSUCHNAME;
691122394Sharti			} else if ((np = find_subnode(b)) != NULL) {
692122394Sharti				/* 2. intermediate object */
693122394Sharti				pdu->error_index = i + 1;
694122394Sharti				pdu->error_status = SNMP_ERR_NOT_WRITEABLE;
695122394Sharti			} else if (except == SNMP_SYNTAX_NOSUCHOBJECT) {
696122394Sharti				pdu->error_index = i + 1;
697122394Sharti				pdu->error_status = SNMP_ERR_NO_ACCESS;
698122394Sharti			} else {
699122394Sharti				pdu->error_index = i + 1;
700122394Sharti				pdu->error_status = SNMP_ERR_NO_CREATION;
701122394Sharti			}
702122394Sharti			snmp_pdu_free(resp);
703122394Sharti			return (SNMP_RET_ERR);
704122394Sharti		}
705122394Sharti		/*
706122394Sharti		 * 2. write/createable?
707122394Sharti		 * Can check this for leafs only, because in v2 we have
708122394Sharti		 * to differentiate between NOT_WRITEABLE and NO_CREATION
709122394Sharti		 * and only the action routine for COLUMNS knows, whether
710122394Sharti		 * a column exists.
711122394Sharti		 */
712122394Sharti		if (np->type == SNMP_NODE_LEAF &&
713122394Sharti		    !(np->flags & SNMP_NODE_CANSET)) {
714122394Sharti			if (pdu->version == SNMP_V1) {
715122394Sharti				pdu->error_index = i + 1;
716122394Sharti				pdu->error_status = SNMP_ERR_NOSUCHNAME;
717122394Sharti			} else {
718122394Sharti				pdu->error_index = i + 1;
719122394Sharti				pdu->error_status = SNMP_ERR_NOT_WRITEABLE;
720122394Sharti			}
721122394Sharti			snmp_pdu_free(resp);
722122394Sharti			return (SNMP_RET_ERR);
723122394Sharti		}
724122394Sharti		/*
725122394Sharti		 * 3. Ensure the right syntax
726122394Sharti		 */
727122394Sharti		if (np->syntax != b->syntax) {
728122394Sharti			if (pdu->version == SNMP_V1) {
729122394Sharti				pdu->error_index = i + 1;
730122394Sharti				pdu->error_status = SNMP_ERR_BADVALUE; /* v2: wrongType */
731122394Sharti			} else {
732122394Sharti				pdu->error_index = i + 1;
733122394Sharti				pdu->error_status = SNMP_ERR_WRONG_TYPE;
734122394Sharti			}
735122394Sharti			snmp_pdu_free(resp);
736122394Sharti			return (SNMP_RET_ERR);
737122394Sharti		}
738122394Sharti		/*
739122394Sharti		 * 4. Copy binding
740122394Sharti		 */
741122394Sharti		if (snmp_value_copy(&resp->bindings[i], b)) {
742122394Sharti			pdu->error_index = i + 1;
743122394Sharti			pdu->error_status = SNMP_ERR_GENERR;
744122394Sharti			snmp_pdu_free(resp);
745122394Sharti			return (SNMP_RET_ERR);
746122394Sharti		}
747122394Sharti		asnerr = snmp_binding_encode(resp_b, &resp->bindings[i]);
748122394Sharti		if (asnerr == ASN_ERR_EOBUF) {
749122394Sharti			pdu->error_index = i + 1;
750122394Sharti			pdu->error_status = SNMP_ERR_TOOBIG;
751122394Sharti			snmp_pdu_free(resp);
752122394Sharti			return (SNMP_RET_ERR);
753122394Sharti		} else if (asnerr != ASN_ERR_OK) {
754122394Sharti			pdu->error_index = i + 1;
755122394Sharti			pdu->error_status = SNMP_ERR_GENERR;
756122394Sharti			snmp_pdu_free(resp);
757122394Sharti			return (SNMP_RET_ERR);
758122394Sharti		}
759122394Sharti		resp->nbindings++;
760122394Sharti	}
761122394Sharti
762128237Sharti	context.ctx.code = SNMP_RET_OK;
763122394Sharti
764122394Sharti	/*
765122394Sharti	 * 2. Call the SET method for each node. If a SET fails, rollback
766122394Sharti	 *    everything. Map error codes depending on the version.
767122394Sharti	 */
768122394Sharti	for (i = 0; i < pdu->nbindings; i++) {
769122394Sharti		b = &pdu->bindings[i];
770122394Sharti		np = context.node[i];
771122394Sharti
772122394Sharti		context.ctx.var_index = i + 1;
773122394Sharti		context.ctx.scratch = &context.scratch[i];
774122394Sharti
775122394Sharti		ret = (*np->op)(&context.ctx, b, np->oid.len, np->index,
776122394Sharti		    SNMP_OP_SET);
777122394Sharti
778122394Sharti		if (TR(SET))
779122394Sharti			snmp_debug("set: action %s returns %d", np->name, ret);
780122394Sharti
781122394Sharti		if (pdu->version == SNMP_V1) {
782122394Sharti			switch (ret) {
783122394Sharti			  case SNMP_ERR_NO_ACCESS:
784122394Sharti				ret = SNMP_ERR_NOSUCHNAME;
785122394Sharti				break;
786122394Sharti			  case SNMP_ERR_WRONG_TYPE:
787122394Sharti				/* should no happen */
788122394Sharti				ret = SNMP_ERR_BADVALUE;
789122394Sharti				break;
790122394Sharti			  case SNMP_ERR_WRONG_LENGTH:
791122394Sharti				ret = SNMP_ERR_BADVALUE;
792122394Sharti				break;
793122394Sharti			  case SNMP_ERR_WRONG_ENCODING:
794122394Sharti				/* should not happen */
795122394Sharti				ret = SNMP_ERR_BADVALUE;
796122394Sharti				break;
797122394Sharti			  case SNMP_ERR_WRONG_VALUE:
798122394Sharti				ret = SNMP_ERR_BADVALUE;
799122394Sharti				break;
800122394Sharti			  case SNMP_ERR_NO_CREATION:
801122394Sharti				ret = SNMP_ERR_NOSUCHNAME;
802122394Sharti				break;
803122394Sharti			  case SNMP_ERR_INCONS_VALUE:
804122394Sharti				ret = SNMP_ERR_BADVALUE;
805122394Sharti				break;
806122394Sharti			  case SNMP_ERR_RES_UNAVAIL:
807122394Sharti				ret = SNMP_ERR_GENERR;
808122394Sharti				break;
809122394Sharti			  case SNMP_ERR_COMMIT_FAILED:
810122394Sharti				ret = SNMP_ERR_GENERR;
811122394Sharti				break;
812122394Sharti			  case SNMP_ERR_UNDO_FAILED:
813122394Sharti				ret = SNMP_ERR_GENERR;
814122394Sharti				break;
815122394Sharti			  case SNMP_ERR_AUTH_ERR:
816122394Sharti				/* should not happen */
817122394Sharti				ret = SNMP_ERR_GENERR;
818122394Sharti				break;
819122394Sharti			  case SNMP_ERR_NOT_WRITEABLE:
820122394Sharti				ret = SNMP_ERR_NOSUCHNAME;
821122394Sharti				break;
822122394Sharti			  case SNMP_ERR_INCONS_NAME:
823122394Sharti				ret = SNMP_ERR_BADVALUE;
824122394Sharti				break;
825122394Sharti			}
826122394Sharti		}
827122394Sharti		if (ret != SNMP_ERR_NOERROR) {
828122394Sharti			pdu->error_index = i + 1;
829122394Sharti			pdu->error_status = ret;
830122394Sharti
831122394Sharti			rollback(&context, pdu, i);
832122394Sharti			snmp_pdu_free(resp);
833122394Sharti
834128237Sharti			context.ctx.code = SNMP_RET_ERR;
835122394Sharti
836122394Sharti			goto errout;
837122394Sharti		}
838122394Sharti	}
839122394Sharti
840122394Sharti	/*
841122394Sharti	 * 3. Call dependencies
842122394Sharti	 */
843122394Sharti	if (TR(SET))
844122394Sharti		snmp_debug("set: set operations ok");
845122394Sharti
846122394Sharti	if ((ret = snmp_dep_commit(&context.ctx)) != SNMP_ERR_NOERROR) {
847122394Sharti		pdu->error_status = ret;
848122394Sharti		pdu->error_index = context.ctx.var_index;
849122394Sharti
850122394Sharti		if ((ret = snmp_dep_rollback(&context.ctx)) != SNMP_ERR_NOERROR) {
851122394Sharti			if (pdu->version != SNMP_V1) {
852122394Sharti				pdu->error_status = SNMP_ERR_UNDO_FAILED;
853122394Sharti				pdu->error_index = 0;
854122394Sharti			}
855122394Sharti		}
856122394Sharti		rollback(&context, pdu, i);
857122394Sharti		snmp_pdu_free(resp);
858122394Sharti
859128237Sharti		context.ctx.code = SNMP_RET_ERR;
860122394Sharti
861122394Sharti		goto errout;
862122394Sharti	}
863122394Sharti
864122394Sharti	/*
865122394Sharti	 * 4. Commit and copy values from the original packet to the response.
866122394Sharti	 *    This is not the commit operation from RFC 1905 but rather an
867122394Sharti	 *    'FREE RESOURCES' operation. It shouldn't fail.
868122394Sharti	 */
869122394Sharti	if (TR(SET))
870122394Sharti		snmp_debug("set: commiting");
871122394Sharti
872122394Sharti	for (i = 0; i < pdu->nbindings; i++) {
873122394Sharti		b = &resp->bindings[i];
874122394Sharti		np = context.node[i];
875122394Sharti
876122394Sharti		context.ctx.var_index = i + 1;
877122394Sharti		context.ctx.scratch = &context.scratch[i];
878122394Sharti
879122394Sharti		ret = (*np->op)(&context.ctx, b, np->oid.len, np->index,
880122394Sharti		    SNMP_OP_COMMIT);
881122394Sharti
882122394Sharti		if (ret != SNMP_ERR_NOERROR)
883122394Sharti			snmp_error("set: commit failed (%d) on"
884122394Sharti			    " variable %s index %u", ret,
885122394Sharti			    asn_oid2str_r(&b->var, oidbuf), i);
886122394Sharti	}
887122394Sharti
888122394Sharti	if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) {
889122394Sharti		snmp_error("set: fix_encoding failed");
890122394Sharti		snmp_pdu_free(resp);
891128237Sharti		context.ctx.code = SNMP_RET_IGN;
892122394Sharti	}
893122394Sharti
894122394Sharti	/*
895122394Sharti	 * Done
896122394Sharti	 */
897122394Sharti  errout:
898128237Sharti	snmp_dep_finish(&context.ctx);
899122394Sharti
900122394Sharti	if (TR(SET))
901128237Sharti		snmp_debug("set: returning %d", context.ctx.code);
902122394Sharti
903128237Sharti	return (context.ctx.code);
904122394Sharti}
905122394Sharti/*
906122394Sharti * Lookup a dependency. If it doesn't exist, create one
907122394Sharti */
908122394Shartistruct snmp_dependency *
909122394Shartisnmp_dep_lookup(struct snmp_context *ctx, const struct asn_oid *obj,
910122394Sharti    const struct asn_oid *idx, size_t len, snmp_depop_t func)
911122394Sharti{
912122394Sharti	struct context *context;
913122394Sharti	struct depend *d;
914122394Sharti
915122394Sharti	context = (struct context *)(void *)
916122394Sharti	    ((char *)ctx - offsetof(struct context, ctx));
917122394Sharti	if (TR(DEPEND)) {
918122394Sharti		snmp_debug("depend: looking for %s", asn_oid2str(obj));
919122394Sharti		if (idx)
920122394Sharti			snmp_debug("depend: index is %s", asn_oid2str(idx));
921122394Sharti	}
922122394Sharti	TAILQ_FOREACH(d, &context->dlist, link)
923122394Sharti		if (asn_compare_oid(obj, &d->dep.obj) == 0 &&
924122394Sharti		    ((idx == NULL && d->dep.idx.len == 0) ||
925122394Sharti		     (idx != NULL && asn_compare_oid(idx, &d->dep.idx) == 0))) {
926122394Sharti			if(TR(DEPEND))
927122394Sharti				snmp_debug("depend: found");
928122394Sharti			return (&d->dep);
929122394Sharti		}
930122394Sharti
931122394Sharti	if(TR(DEPEND))
932122394Sharti		snmp_debug("depend: creating");
933122394Sharti
934122394Sharti	if ((d = malloc(offsetof(struct depend, dep) + len)) == NULL)
935122394Sharti		return (NULL);
936122394Sharti	memset(&d->dep, 0, len);
937122394Sharti
938122394Sharti	d->dep.obj = *obj;
939122394Sharti	if (idx == NULL)
940122394Sharti		d->dep.idx.len = 0;
941122394Sharti	else
942122394Sharti		d->dep.idx = *idx;
943122394Sharti	d->len = len;
944122394Sharti	d->func = func;
945122394Sharti
946122394Sharti	TAILQ_INSERT_TAIL(&context->dlist, d, link);
947122394Sharti
948122394Sharti	return (&d->dep);
949122394Sharti}
950122394Sharti
951122394Sharti/*
952122394Sharti * Make an error response from a PDU. We do this without decoding the
953122394Sharti * variable bindings. This means we can sent the junk back to a caller
954122394Sharti * that has sent us junk in the first place.
955122394Sharti */
956122394Shartienum snmp_ret
957122394Shartisnmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *pdu_b,
958122394Sharti    struct asn_buf *resp_b)
959122394Sharti{
960122394Sharti	asn_len_t len;
961122394Sharti	struct snmp_pdu resp;
962122394Sharti	enum asn_err err;
963122394Sharti	enum snmp_code code;
964122394Sharti
965122394Sharti	memset(&resp, 0, sizeof(resp));
966216294Ssyrinx	if ((code = snmp_pdu_decode_header(pdu_b, &resp)) != SNMP_CODE_OK)
967122394Sharti		return (SNMP_RET_IGN);
968122394Sharti
969122394Sharti	if (pdu_b->asn_len < len)
970122394Sharti		return (SNMP_RET_IGN);
971122394Sharti	pdu_b->asn_len = len;
972122394Sharti
973122394Sharti	err = snmp_parse_pdus_hdr(pdu_b, &resp, &len);
974122394Sharti	if (ASN_ERR_STOPPED(err))
975122394Sharti		return (SNMP_RET_IGN);
976122394Sharti	if (pdu_b->asn_len < len)
977122394Sharti		return (SNMP_RET_IGN);
978122394Sharti	pdu_b->asn_len = len;
979122394Sharti
980122394Sharti	/* now we have the bindings left - construct new message */
981122394Sharti	resp.error_status = pdu->error_status;
982122394Sharti	resp.error_index = pdu->error_index;
983122394Sharti	resp.type = SNMP_PDU_RESPONSE;
984122394Sharti
985122394Sharti	code = snmp_pdu_encode_header(resp_b, &resp);
986122394Sharti	if (code != SNMP_CODE_OK)
987122394Sharti		return (SNMP_RET_IGN);
988122394Sharti
989122394Sharti	if (pdu_b->asn_len > resp_b->asn_len)
990122394Sharti		/* too short */
991122394Sharti		return (SNMP_RET_IGN);
992122394Sharti	(void)memcpy(resp_b->asn_ptr, pdu_b->asn_cptr, pdu_b->asn_len);
993122394Sharti	resp_b->asn_len -= pdu_b->asn_len;
994122394Sharti	resp_b->asn_ptr += pdu_b->asn_len;
995122394Sharti
996122394Sharti	code = snmp_fix_encoding(resp_b, &resp);
997122394Sharti	if (code != SNMP_CODE_OK)
998122394Sharti		return (SNMP_RET_IGN);
999122394Sharti
1000122394Sharti	return (SNMP_RET_OK);
1001122394Sharti}
1002122394Sharti
1003122394Shartistatic void
1004122394Shartisnmp_debug_func(const char *fmt, ...)
1005122394Sharti{
1006122394Sharti	va_list ap;
1007122394Sharti
1008122394Sharti	va_start(ap, fmt);
1009122394Sharti	vfprintf(stderr, fmt, ap);
1010122394Sharti	va_end(ap);
1011122394Sharti	fprintf(stderr, "\n");
1012122394Sharti}
1013