2 * Copyright (c) 2001-2003
3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus).
6 * Author: Harti Brandt <harti@freebsd.org>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $Begemot: bsnmp/lib/snmpagent.c,v 1.20 2005/10/04 11:21:33 brandt_h Exp $
31 * SNMP Agent functions
33 #include <sys/types.h>
34 #include <sys/queue.h>
41 #elif defined(HAVE_INTTYPES_H)
49 #include "snmpagent.h"
51 static void snmp_debug_func(const char *fmt, ...);
53 void (*snmp_debug)(const char *fmt, ...) = snmp_debug_func;
55 struct snmp_node *tree;
59 * Structure to hold dependencies during SET processing
60 * The last two members of this structure must be the
61 * dependency visible by the user and the user data.
64 TAILQ_ENTRY(depend) link;
65 size_t len; /* size of data part */
67 struct snmp_dependency dep;
68 #if defined(__GNUC__) && __GNUC__ < 3
74 TAILQ_HEAD(depend_list, depend);
80 struct snmp_context ctx;
81 struct depend_list dlist;
82 const struct snmp_node *node[SNMP_MAX_BINDINGS];
83 struct snmp_scratch scratch[SNMP_MAX_BINDINGS];
84 struct depend *depend;
87 #define TR(W) (snmp_trace & SNMP_TRACE_##W)
90 static char oidbuf[ASN_OIDSTRLEN];
96 snmp_init_context(void)
98 struct context *context;
100 if ((context = malloc(sizeof(*context))) == NULL)
103 memset(context, 0, sizeof(*context));
104 TAILQ_INIT(&context->dlist);
106 return (&context->ctx);
110 * Find a variable for SET/GET and the first GETBULK pass.
111 * Return the node pointer. If the search fails, set the errp to
112 * the correct SNMPv2 GET exception code.
114 static struct snmp_node *
115 find_node(const struct snmp_value *value, enum snmp_syntax *errp)
117 struct snmp_node *tp;
120 snmp_debug("find: searching %s",
121 asn_oid2str_r(&value->var, oidbuf));
124 * If we have an exact match (the entry in the table is a
125 * sub-oid from the variable) we have found what we are for.
126 * If the table oid is higher than the variable, there is no match.
128 for (tp = tree; tp < tree + tree_size; tp++) {
129 if (asn_is_suboid(&tp->oid, &value->var))
131 if (asn_compare_oid(&tp->oid, &value->var) >= 0)
136 snmp_debug("find: no match");
137 *errp = SNMP_SYNTAX_NOSUCHOBJECT;
141 /* leafs must have a 0 instance identifier */
142 if (tp->type == SNMP_NODE_LEAF &&
143 (value->var.len != tp->oid.len + 1 ||
144 value->var.subs[tp->oid.len] != 0)) {
146 snmp_debug("find: bad leaf index");
147 *errp = SNMP_SYNTAX_NOSUCHINSTANCE;
151 snmp_debug("find: found %s",
152 asn_oid2str_r(&value->var, oidbuf));
156 static struct snmp_node *
157 find_subnode(const struct snmp_value *value)
159 struct snmp_node *tp;
161 for (tp = tree; tp < tree + tree_size; tp++) {
162 if (asn_is_suboid(&value->var, &tp->oid))
169 * Execute a GET operation. The tree is rooted at the global 'root'.
170 * Build the response PDU on the fly. If the return code is SNMP_RET_ERR
171 * the pdu error status and index will be set.
174 snmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b,
175 struct snmp_pdu *resp, void *data)
179 struct snmp_node *tp;
180 enum snmp_syntax except;
181 struct context context;
184 memset(&context, 0, sizeof(context));
185 context.ctx.data = data;
187 memset(resp, 0, sizeof(*resp));
188 strcpy(resp->community, pdu->community);
189 resp->version = pdu->version;
190 resp->type = SNMP_PDU_RESPONSE;
191 resp->request_id = pdu->request_id;
192 resp->version = pdu->version;
194 if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
195 /* cannot even encode header - very bad */
196 return (SNMP_RET_IGN);
198 for (i = 0; i < pdu->nbindings; i++) {
199 resp->bindings[i].var = pdu->bindings[i].var;
200 if ((tp = find_node(&pdu->bindings[i], &except)) == NULL) {
201 if (pdu->version == SNMP_V1) {
203 snmp_debug("get: nosuchname");
204 pdu->error_status = SNMP_ERR_NOSUCHNAME;
205 pdu->error_index = i + 1;
207 return (SNMP_RET_ERR);
210 snmp_debug("get: exception %u", except);
211 resp->bindings[i].syntax = except;
214 /* call the action to fetch the value. */
215 resp->bindings[i].syntax = tp->syntax;
216 ret = (*tp->op)(&context.ctx, &resp->bindings[i],
217 tp->oid.len, tp->index, SNMP_OP_GET);
219 snmp_debug("get: action returns %d", ret);
221 if (ret == SNMP_ERR_NOSUCHNAME) {
222 if (pdu->version == SNMP_V1) {
223 pdu->error_status = SNMP_ERR_NOSUCHNAME;
224 pdu->error_index = i + 1;
226 return (SNMP_RET_ERR);
229 snmp_debug("get: exception noSuchInstance");
230 resp->bindings[i].syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
232 } else if (ret != SNMP_ERR_NOERROR) {
233 pdu->error_status = SNMP_ERR_GENERR;
234 pdu->error_index = i + 1;
236 return (SNMP_RET_ERR);
241 err = snmp_binding_encode(resp_b, &resp->bindings[i]);
243 if (err == ASN_ERR_EOBUF) {
244 pdu->error_status = SNMP_ERR_TOOBIG;
245 pdu->error_index = 0;
247 return (SNMP_RET_ERR);
249 if (err != ASN_ERR_OK) {
251 snmp_debug("get: binding encoding: %u", err);
252 pdu->error_status = SNMP_ERR_GENERR;
253 pdu->error_index = i + 1;
255 return (SNMP_RET_ERR);
259 return (snmp_fix_encoding(resp_b, resp));
262 static struct snmp_node *
263 next_node(const struct snmp_value *value, int *pnext)
265 struct snmp_node *tp;
268 snmp_debug("next: searching %s",
269 asn_oid2str_r(&value->var, oidbuf));
272 for (tp = tree; tp < tree + tree_size; tp++) {
273 if (asn_is_suboid(&tp->oid, &value->var)) {
274 /* the tree OID is a sub-oid of the requested OID. */
275 if (tp->type == SNMP_NODE_LEAF) {
276 if (tp->oid.len == value->var.len) {
277 /* request for scalar type */
279 snmp_debug("next: found scalar %s",
280 asn_oid2str_r(&tp->oid, oidbuf));
286 snmp_debug("next: found column %s",
287 asn_oid2str_r(&tp->oid, oidbuf));
290 } else if (asn_is_suboid(&value->var, &tp->oid) ||
291 asn_compare_oid(&tp->oid, &value->var) >= 0) {
293 snmp_debug("next: found %s",
294 asn_oid2str_r(&tp->oid, oidbuf));
301 snmp_debug("next: failed");
307 do_getnext(struct context *context, const struct snmp_value *inb,
308 struct snmp_value *outb, struct snmp_pdu *pdu)
310 const struct snmp_node *tp;
313 if ((tp = next_node(inb, &next)) == NULL)
316 /* retain old variable if we are doing a GETNEXT on an exact
317 * matched leaf only */
318 if (tp->type == SNMP_NODE_LEAF || next)
321 outb->var = inb->var;
324 outb->syntax = tp->syntax;
325 if (tp->type == SNMP_NODE_LEAF) {
326 /* make a GET operation */
327 outb->var.subs[outb->var.len++] = 0;
328 ret = (*tp->op)(&context->ctx, outb, tp->oid.len,
329 tp->index, SNMP_OP_GET);
332 ret = (*tp->op)(&context->ctx, outb, tp->oid.len,
333 tp->index, SNMP_OP_GETNEXT);
335 if (ret != SNMP_ERR_NOSUCHNAME) {
337 if (ret != SNMP_ERR_NOERROR && TR(GETNEXT))
338 snmp_debug("getnext: %s returns %u",
339 asn_oid2str(&outb->var), ret);
343 /* object has no data - try next */
344 if (++tp == tree + tree_size)
348 snmp_debug("getnext: no data - avancing to %s",
349 asn_oid2str(&tp->oid));
354 if (ret == SNMP_ERR_NOSUCHNAME) {
356 outb->var = inb->var;
357 if (pdu->version == SNMP_V1) {
358 pdu->error_status = SNMP_ERR_NOSUCHNAME;
359 return (SNMP_RET_ERR);
361 outb->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
363 } else if (ret != SNMP_ERR_NOERROR) {
364 pdu->error_status = SNMP_ERR_GENERR;
365 return (SNMP_RET_ERR);
367 return (SNMP_RET_OK);
372 * Execute a GETNEXT operation. The tree is rooted at the global 'root'.
373 * Build the response PDU on the fly. The return is:
376 snmp_getnext(struct snmp_pdu *pdu, struct asn_buf *resp_b,
377 struct snmp_pdu *resp, void *data)
379 struct context context;
382 enum snmp_ret result;
384 memset(&context, 0, sizeof(context));
385 context.ctx.data = data;
387 memset(resp, 0, sizeof(*resp));
388 strcpy(resp->community, pdu->community);
389 resp->type = SNMP_PDU_RESPONSE;
390 resp->request_id = pdu->request_id;
391 resp->version = pdu->version;
393 if (snmp_pdu_encode_header(resp_b, resp))
394 return (SNMP_RET_IGN);
396 for (i = 0; i < pdu->nbindings; i++) {
397 result = do_getnext(&context, &pdu->bindings[i],
398 &resp->bindings[i], pdu);
400 if (result != SNMP_RET_OK) {
401 pdu->error_index = i + 1;
408 err = snmp_binding_encode(resp_b, &resp->bindings[i]);
410 if (err == ASN_ERR_EOBUF) {
411 pdu->error_status = SNMP_ERR_TOOBIG;
412 pdu->error_index = 0;
414 return (SNMP_RET_ERR);
416 if (err != ASN_ERR_OK) {
418 snmp_debug("getnext: binding encoding: %u", err);
419 pdu->error_status = SNMP_ERR_GENERR;
420 pdu->error_index = i + 1;
422 return (SNMP_RET_ERR);
425 return (snmp_fix_encoding(resp_b, resp));
429 snmp_getbulk(struct snmp_pdu *pdu, struct asn_buf *resp_b,
430 struct snmp_pdu *resp, void *data)
432 struct context context;
437 enum snmp_ret result;
440 memset(&context, 0, sizeof(context));
441 context.ctx.data = data;
443 memset(resp, 0, sizeof(*resp));
444 strcpy(resp->community, pdu->community);
445 resp->version = pdu->version;
446 resp->type = SNMP_PDU_RESPONSE;
447 resp->request_id = pdu->request_id;
448 resp->version = pdu->version;
450 if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
451 /* cannot even encode header - very bad */
452 return (SNMP_RET_IGN);
454 if ((non_rep = pdu->error_status) > pdu->nbindings)
455 non_rep = pdu->nbindings;
458 for (i = 0; i < non_rep; i++) {
459 result = do_getnext(&context, &pdu->bindings[i],
460 &resp->bindings[resp->nbindings], pdu);
462 if (result != SNMP_RET_OK) {
463 pdu->error_index = i + 1;
468 err = snmp_binding_encode(resp_b,
469 &resp->bindings[resp->nbindings++]);
471 if (err == ASN_ERR_EOBUF)
474 if (err != ASN_ERR_OK) {
476 snmp_debug("getnext: binding encoding: %u", err);
477 pdu->error_status = SNMP_ERR_GENERR;
478 pdu->error_index = i + 1;
480 return (SNMP_RET_ERR);
484 if (non_rep == pdu->nbindings)
488 for (cnt = 0; cnt < pdu->error_index; cnt++) {
490 for (i = non_rep; i < pdu->nbindings; i++) {
492 if (resp->nbindings == SNMP_MAX_BINDINGS)
497 result = do_getnext(&context, &pdu->bindings[i],
498 &resp->bindings[resp->nbindings], pdu);
500 result = do_getnext(&context,
501 &resp->bindings[resp->nbindings -
502 (pdu->nbindings - non_rep)],
503 &resp->bindings[resp->nbindings], pdu);
505 if (result != SNMP_RET_OK) {
506 pdu->error_index = i + 1;
510 if (resp->bindings[resp->nbindings].syntax !=
511 SNMP_SYNTAX_ENDOFMIBVIEW)
514 err = snmp_binding_encode(resp_b,
515 &resp->bindings[resp->nbindings++]);
517 if (err == ASN_ERR_EOBUF)
520 if (err != ASN_ERR_OK) {
522 snmp_debug("getnext: binding encoding: %u", err);
523 pdu->error_status = SNMP_ERR_GENERR;
524 pdu->error_index = i + 1;
526 return (SNMP_RET_ERR);
534 return (snmp_fix_encoding(resp_b, resp));
538 * Rollback a SET operation. Failed index is 'i'.
541 rollback(struct context *context, struct snmp_pdu *pdu, u_int i)
543 struct snmp_value *b;
544 const struct snmp_node *np;
548 b = &pdu->bindings[i];
549 np = context->node[i];
551 context->ctx.scratch = &context->scratch[i];
553 ret = (*np->op)(&context->ctx, b, np->oid.len, np->index,
556 if (ret != SNMP_ERR_NOERROR) {
557 snmp_error("set: rollback failed (%d) on variable %s "
558 "index %u", ret, asn_oid2str(&b->var), i);
559 if (pdu->version != SNMP_V1) {
560 pdu->error_status = SNMP_ERR_UNDO_FAILED;
561 pdu->error_index = 0;
568 * Commit dependencies.
571 snmp_dep_commit(struct snmp_context *ctx)
573 struct context *context = (struct context *)ctx;
576 TAILQ_FOREACH(context->depend, &context->dlist, link) {
577 ctx->dep = &context->depend->dep;
580 snmp_debug("set: dependency commit %s",
581 asn_oid2str(&ctx->dep->obj));
583 ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_COMMIT);
585 if (ret != SNMP_ERR_NOERROR) {
587 snmp_debug("set: dependency failed %d", ret);
591 return (SNMP_ERR_NOERROR);
595 * Rollback dependencies
598 snmp_dep_rollback(struct snmp_context *ctx)
600 struct context *context = (struct context *)ctx;
602 char objbuf[ASN_OIDSTRLEN];
603 char idxbuf[ASN_OIDSTRLEN];
605 ret1 = SNMP_ERR_NOERROR;
606 while ((context->depend =
607 TAILQ_PREV(context->depend, depend_list, link)) != NULL) {
608 ctx->dep = &context->depend->dep;
611 snmp_debug("set: dependency rollback %s",
612 asn_oid2str(&ctx->dep->obj));
614 ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_ROLLBACK);
616 if (ret != SNMP_ERR_NOERROR) {
617 snmp_debug("set: dep rollback returns %u: %s %s", ret,
618 asn_oid2str_r(&ctx->dep->obj, objbuf),
619 asn_oid2str_r(&ctx->dep->idx, idxbuf));
620 if (ret1 == SNMP_ERR_NOERROR)
628 snmp_dep_finish(struct snmp_context *ctx)
630 struct context *context = (struct context *)ctx;
633 while ((d = TAILQ_FIRST(&context->dlist)) != NULL) {
635 (void)d->func(ctx, ctx->dep, SNMP_DEPOP_FINISH);
636 TAILQ_REMOVE(&context->dlist, d, link);
642 * Do a SET operation.
645 snmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b,
646 struct snmp_pdu *resp, void *data)
651 struct context context;
652 const struct snmp_node *np;
653 struct snmp_value *b;
654 enum snmp_syntax except;
656 memset(&context, 0, sizeof(context));
657 TAILQ_INIT(&context.dlist);
658 context.ctx.data = data;
660 memset(resp, 0, sizeof(*resp));
661 strcpy(resp->community, pdu->community);
662 resp->type = SNMP_PDU_RESPONSE;
663 resp->request_id = pdu->request_id;
664 resp->version = pdu->version;
666 if (snmp_pdu_encode_header(resp_b, resp))
667 return (SNMP_RET_IGN);
670 * 1. Find all nodes, check that they are writeable and
671 * that the syntax is ok, copy over the binding to the response.
673 for (i = 0; i < pdu->nbindings; i++) {
674 b = &pdu->bindings[i];
676 if ((np = context.node[i] = find_node(b, &except)) == NULL) {
677 /* not found altogether or LEAF with wrong index */
679 snmp_debug("set: node not found %s",
680 asn_oid2str_r(&b->var, oidbuf));
681 if (pdu->version == SNMP_V1) {
682 pdu->error_index = i + 1;
683 pdu->error_status = SNMP_ERR_NOSUCHNAME;
684 } else if ((np = find_subnode(b)) != NULL) {
685 /* 2. intermediate object */
686 pdu->error_index = i + 1;
687 pdu->error_status = SNMP_ERR_NOT_WRITEABLE;
688 } else if (except == SNMP_SYNTAX_NOSUCHOBJECT) {
689 pdu->error_index = i + 1;
690 pdu->error_status = SNMP_ERR_NO_ACCESS;
692 pdu->error_index = i + 1;
693 pdu->error_status = SNMP_ERR_NO_CREATION;
696 return (SNMP_RET_ERR);
699 * 2. write/createable?
700 * Can check this for leafs only, because in v2 we have
701 * to differentiate between NOT_WRITEABLE and NO_CREATION
702 * and only the action routine for COLUMNS knows, whether
705 if (np->type == SNMP_NODE_LEAF &&
706 !(np->flags & SNMP_NODE_CANSET)) {
707 if (pdu->version == SNMP_V1) {
708 pdu->error_index = i + 1;
709 pdu->error_status = SNMP_ERR_NOSUCHNAME;
711 pdu->error_index = i + 1;
712 pdu->error_status = SNMP_ERR_NOT_WRITEABLE;
715 return (SNMP_RET_ERR);
718 * 3. Ensure the right syntax
720 if (np->syntax != b->syntax) {
721 if (pdu->version == SNMP_V1) {
722 pdu->error_index = i + 1;
723 pdu->error_status = SNMP_ERR_BADVALUE; /* v2: wrongType */
725 pdu->error_index = i + 1;
726 pdu->error_status = SNMP_ERR_WRONG_TYPE;
729 return (SNMP_RET_ERR);
734 if (snmp_value_copy(&resp->bindings[i], b)) {
735 pdu->error_index = i + 1;
736 pdu->error_status = SNMP_ERR_GENERR;
738 return (SNMP_RET_ERR);
740 asnerr = snmp_binding_encode(resp_b, &resp->bindings[i]);
741 if (asnerr == ASN_ERR_EOBUF) {
742 pdu->error_index = i + 1;
743 pdu->error_status = SNMP_ERR_TOOBIG;
745 return (SNMP_RET_ERR);
746 } else if (asnerr != ASN_ERR_OK) {
747 pdu->error_index = i + 1;
748 pdu->error_status = SNMP_ERR_GENERR;
750 return (SNMP_RET_ERR);
755 context.ctx.code = SNMP_RET_OK;
758 * 2. Call the SET method for each node. If a SET fails, rollback
759 * everything. Map error codes depending on the version.
761 for (i = 0; i < pdu->nbindings; i++) {
762 b = &pdu->bindings[i];
763 np = context.node[i];
765 context.ctx.var_index = i + 1;
766 context.ctx.scratch = &context.scratch[i];
768 ret = (*np->op)(&context.ctx, b, np->oid.len, np->index,
772 snmp_debug("set: action %s returns %d", np->name, ret);
774 if (pdu->version == SNMP_V1) {
776 case SNMP_ERR_NO_ACCESS:
777 ret = SNMP_ERR_NOSUCHNAME;
779 case SNMP_ERR_WRONG_TYPE:
780 /* should no happen */
781 ret = SNMP_ERR_BADVALUE;
783 case SNMP_ERR_WRONG_LENGTH:
784 ret = SNMP_ERR_BADVALUE;
786 case SNMP_ERR_WRONG_ENCODING:
787 /* should not happen */
788 ret = SNMP_ERR_BADVALUE;
790 case SNMP_ERR_WRONG_VALUE:
791 ret = SNMP_ERR_BADVALUE;
793 case SNMP_ERR_NO_CREATION:
794 ret = SNMP_ERR_NOSUCHNAME;
796 case SNMP_ERR_INCONS_VALUE:
797 ret = SNMP_ERR_BADVALUE;
799 case SNMP_ERR_RES_UNAVAIL:
800 ret = SNMP_ERR_GENERR;
802 case SNMP_ERR_COMMIT_FAILED:
803 ret = SNMP_ERR_GENERR;
805 case SNMP_ERR_UNDO_FAILED:
806 ret = SNMP_ERR_GENERR;
808 case SNMP_ERR_AUTH_ERR:
809 /* should not happen */
810 ret = SNMP_ERR_GENERR;
812 case SNMP_ERR_NOT_WRITEABLE:
813 ret = SNMP_ERR_NOSUCHNAME;
815 case SNMP_ERR_INCONS_NAME:
816 ret = SNMP_ERR_BADVALUE;
820 if (ret != SNMP_ERR_NOERROR) {
821 pdu->error_index = i + 1;
822 pdu->error_status = ret;
824 rollback(&context, pdu, i);
827 context.ctx.code = SNMP_RET_ERR;
834 * 3. Call dependencies
837 snmp_debug("set: set operations ok");
839 if ((ret = snmp_dep_commit(&context.ctx)) != SNMP_ERR_NOERROR) {
840 pdu->error_status = ret;
841 pdu->error_index = context.ctx.var_index;
843 if ((ret = snmp_dep_rollback(&context.ctx)) != SNMP_ERR_NOERROR) {
844 if (pdu->version != SNMP_V1) {
845 pdu->error_status = SNMP_ERR_UNDO_FAILED;
846 pdu->error_index = 0;
849 rollback(&context, pdu, i);
852 context.ctx.code = SNMP_RET_ERR;
858 * 4. Commit and copy values from the original packet to the response.
859 * This is not the commit operation from RFC 1905 but rather an
860 * 'FREE RESOURCES' operation. It shouldn't fail.
863 snmp_debug("set: commiting");
865 for (i = 0; i < pdu->nbindings; i++) {
866 b = &resp->bindings[i];
867 np = context.node[i];
869 context.ctx.var_index = i + 1;
870 context.ctx.scratch = &context.scratch[i];
872 ret = (*np->op)(&context.ctx, b, np->oid.len, np->index,
875 if (ret != SNMP_ERR_NOERROR)
876 snmp_error("set: commit failed (%d) on"
877 " variable %s index %u", ret,
878 asn_oid2str_r(&b->var, oidbuf), i);
881 if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) {
882 snmp_error("set: fix_encoding failed");
884 context.ctx.code = SNMP_RET_IGN;
891 snmp_dep_finish(&context.ctx);
894 snmp_debug("set: returning %d", context.ctx.code);
896 return (context.ctx.code);
899 * Lookup a dependency. If it doesn't exist, create one
901 struct snmp_dependency *
902 snmp_dep_lookup(struct snmp_context *ctx, const struct asn_oid *obj,
903 const struct asn_oid *idx, size_t len, snmp_depop_t func)
905 struct context *context;
908 context = (struct context *)(void *)
909 ((char *)ctx - offsetof(struct context, ctx));
911 snmp_debug("depend: looking for %s", asn_oid2str(obj));
913 snmp_debug("depend: index is %s", asn_oid2str(idx));
915 TAILQ_FOREACH(d, &context->dlist, link)
916 if (asn_compare_oid(obj, &d->dep.obj) == 0 &&
917 ((idx == NULL && d->dep.idx.len == 0) ||
918 (idx != NULL && asn_compare_oid(idx, &d->dep.idx) == 0))) {
920 snmp_debug("depend: found");
925 snmp_debug("depend: creating");
927 if ((d = malloc(offsetof(struct depend, dep) + len)) == NULL)
929 memset(&d->dep, 0, len);
939 TAILQ_INSERT_TAIL(&context->dlist, d, link);
945 * Make an error response from a PDU. We do this without decoding the
946 * variable bindings. This means we can sent the junk back to a caller
947 * that has sent us junk in the first place.
950 snmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *pdu_b,
951 struct asn_buf *resp_b)
954 struct snmp_pdu resp;
958 memset(&resp, 0, sizeof(resp));
960 /* Message sequence */
961 if (asn_get_sequence(pdu_b, &len) != ASN_ERR_OK)
962 return (SNMP_RET_IGN);
963 if (pdu_b->asn_len < len)
964 return (SNMP_RET_IGN);
966 err = snmp_parse_message_hdr(pdu_b, &resp, &len);
967 if (ASN_ERR_STOPPED(err))
968 return (SNMP_RET_IGN);
969 if (pdu_b->asn_len < len)
970 return (SNMP_RET_IGN);
971 pdu_b->asn_len = len;
973 err = snmp_parse_pdus_hdr(pdu_b, &resp, &len);
974 if (ASN_ERR_STOPPED(err))
975 return (SNMP_RET_IGN);
976 if (pdu_b->asn_len < len)
977 return (SNMP_RET_IGN);
978 pdu_b->asn_len = len;
980 /* now we have the bindings left - construct new message */
981 resp.error_status = pdu->error_status;
982 resp.error_index = pdu->error_index;
983 resp.type = SNMP_PDU_RESPONSE;
985 code = snmp_pdu_encode_header(resp_b, &resp);
986 if (code != SNMP_CODE_OK)
987 return (SNMP_RET_IGN);
989 if (pdu_b->asn_len > resp_b->asn_len)
991 return (SNMP_RET_IGN);
992 (void)memcpy(resp_b->asn_ptr, pdu_b->asn_cptr, pdu_b->asn_len);
993 resp_b->asn_len -= pdu_b->asn_len;
994 resp_b->asn_ptr += pdu_b->asn_len;
996 code = snmp_fix_encoding(resp_b, &resp);
997 if (code != SNMP_CODE_OK)
998 return (SNMP_RET_IGN);
1000 return (SNMP_RET_OK);
1004 snmp_debug_func(const char *fmt, ...)
1009 vfprintf(stderr, fmt, ap);
1011 fprintf(stderr, "\n");