3 * SNMP input message processing (RFC1157).
7 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
10 * Redistribution and use in source and binary forms, with or without modification,
11 * are permitted provided that the following conditions are met:
13 * 1. Redistributions of source code must retain the above copyright notice,
14 * this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright notice,
16 * this list of conditions and the following disclaimer in the documentation
17 * and/or other materials provided with the distribution.
18 * 3. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
32 * Author: Christiaan Simons <christiaan.simons@axon.tv>
37 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
39 #include "lwip/snmp.h"
40 #include "lwip/snmp_asn1.h"
41 #include "lwip/snmp_msg.h"
42 #include "lwip/snmp_structs.h"
43 #include "lwip/ip_addr.h"
44 #include "lwip/memp.h"
46 #include "lwip/stats.h"
50 /* public (non-static) constants */
52 const s32_t snmp_version
= 0;
53 /** default SNMP community string */
54 const char snmp_publiccommunity
[7] = "public";
56 /* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
57 struct snmp_msg_pstat msg_input_list
[SNMP_CONCURRENT_REQUESTS
];
58 /* UDP Protocol Control Block */
59 struct udp_pcb
*snmp1_pcb
;
61 static void snmp_recv(void *arg
, struct udp_pcb
*pcb
, struct pbuf
*p
, ip_addr_t
*addr
, u16_t port
);
62 static err_t
snmp_pdu_header_check(struct pbuf
*p
, u16_t ofs
, u16_t pdu_len
, u16_t
*ofs_ret
, struct snmp_msg_pstat
*m_stat
);
63 static err_t
snmp_pdu_dec_varbindlist(struct pbuf
*p
, u16_t ofs
, u16_t
*ofs_ret
, struct snmp_msg_pstat
*m_stat
);
68 * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
73 struct snmp_msg_pstat
*msg_ps
;
76 snmp1_pcb
= udp_new();
77 if (snmp1_pcb
!= NULL
)
79 udp_recv(snmp1_pcb
, snmp_recv
, (void *)SNMP_IN_PORT
);
80 udp_bind(snmp1_pcb
, IP_ADDR_ANY
, SNMP_IN_PORT
);
82 msg_ps
= &msg_input_list
[0];
83 for (i
=0; i
<SNMP_CONCURRENT_REQUESTS
; i
++)
85 msg_ps
->state
= SNMP_MSG_EMPTY
;
86 msg_ps
->error_index
= 0;
87 msg_ps
->error_status
= SNMP_ES_NOERROR
;
90 trap_msg
.pcb
= snmp1_pcb
;
92 #ifdef SNMP_PRIVATE_MIB_INIT
93 /* If defined, rhis must be a function-like define to initialize the
94 * private MIB after the stack has been initialized.
95 * The private MIB can also be initialized in tcpip_callback (or after
96 * the stack is initialized), this define is only for convenience. */
97 SNMP_PRIVATE_MIB_INIT();
98 #endif /* SNMP_PRIVATE_MIB_INIT */
100 /* The coldstart trap will only be output
101 if our outgoing interface is up & configured */
102 snmp_coldstart_trap();
106 snmp_error_response(struct snmp_msg_pstat
*msg_ps
, u8_t error
)
108 snmp_varbind_list_free(&msg_ps
->outvb
);
109 msg_ps
->outvb
= msg_ps
->invb
;
110 msg_ps
->invb
.head
= NULL
;
111 msg_ps
->invb
.tail
= NULL
;
112 msg_ps
->invb
.count
= 0;
113 msg_ps
->error_status
= error
;
114 msg_ps
->error_index
= 1 + msg_ps
->vb_idx
;
115 snmp_send_response(msg_ps
);
116 snmp_varbind_list_free(&msg_ps
->outvb
);
117 msg_ps
->state
= SNMP_MSG_EMPTY
;
121 snmp_ok_response(struct snmp_msg_pstat
*msg_ps
)
125 err_ret
= snmp_send_response(msg_ps
);
126 if (err_ret
== ERR_MEM
)
128 /* serious memory problem, can't return tooBig */
132 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_event = %"S32_F
"\n",msg_ps
->error_status
));
134 /* free varbinds (if available) */
135 snmp_varbind_list_free(&msg_ps
->invb
);
136 snmp_varbind_list_free(&msg_ps
->outvb
);
137 msg_ps
->state
= SNMP_MSG_EMPTY
;
141 * Service an internal or external event for SNMP GET.
143 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
144 * @param msg_ps points to the assosicated message process state
147 snmp_msg_get_event(u8_t request_id
, struct snmp_msg_pstat
*msg_ps
)
149 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_get_event: msg_ps->state==%"U16_F
"\n",(u16_t
)msg_ps
->state
));
151 if (msg_ps
->state
== SNMP_MSG_EXTERNAL_GET_OBJDEF
)
153 struct mib_external_node
*en
;
154 struct snmp_name_ptr np
;
156 /* get_object_def() answer*/
157 en
= msg_ps
->ext_mib_node
;
158 np
= msg_ps
->ext_name_ptr
;
160 /* translate answer into a known lifeform */
161 en
->get_object_def_a(request_id
, np
.ident_len
, np
.ident
, &msg_ps
->ext_object_def
);
162 if ((msg_ps
->ext_object_def
.instance
!= MIB_OBJECT_NONE
) &&
163 (msg_ps
->ext_object_def
.access
& MIB_ACCESS_READ
))
165 msg_ps
->state
= SNMP_MSG_EXTERNAL_GET_VALUE
;
166 en
->get_value_q(request_id
, &msg_ps
->ext_object_def
);
170 en
->get_object_def_pc(request_id
, np
.ident_len
, np
.ident
);
171 /* search failed, object id points to unknown object (nosuchname) */
172 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
175 else if (msg_ps
->state
== SNMP_MSG_EXTERNAL_GET_VALUE
)
177 struct mib_external_node
*en
;
178 struct snmp_varbind
*vb
;
180 /* get_value() answer */
181 en
= msg_ps
->ext_mib_node
;
183 /* allocate output varbind */
184 vb
= (struct snmp_varbind
*)memp_malloc(MEMP_SNMP_VARBIND
);
185 LWIP_ASSERT("vb != NULL",vb
!= NULL
);
191 /* move name from invb to outvb */
192 vb
->ident
= msg_ps
->vb_ptr
->ident
;
193 vb
->ident_len
= msg_ps
->vb_ptr
->ident_len
;
194 /* ensure this memory is refereced once only */
195 msg_ps
->vb_ptr
->ident
= NULL
;
196 msg_ps
->vb_ptr
->ident_len
= 0;
198 vb
->value_type
= msg_ps
->ext_object_def
.asn_type
;
199 LWIP_ASSERT("invalid length", msg_ps
->ext_object_def
.v_len
<= 0xff);
200 vb
->value_len
= (u8_t
)msg_ps
->ext_object_def
.v_len
;
201 if (vb
->value_len
> 0)
203 LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb
->value_len
<= SNMP_MAX_VALUE_SIZE
);
204 vb
->value
= memp_malloc(MEMP_SNMP_VALUE
);
205 LWIP_ASSERT("vb->value != NULL",vb
->value
!= NULL
);
206 if (vb
->value
!= NULL
)
208 en
->get_value_a(request_id
, &msg_ps
->ext_object_def
, vb
->value_len
, vb
->value
);
209 snmp_varbind_tail_add(&msg_ps
->outvb
, vb
);
210 /* search again (if vb_idx < msg_ps->invb.count) */
211 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
216 en
->get_value_pc(request_id
, &msg_ps
->ext_object_def
);
217 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_event: no variable space\n"));
218 msg_ps
->vb_ptr
->ident
= vb
->ident
;
219 msg_ps
->vb_ptr
->ident_len
= vb
->ident_len
;
220 memp_free(MEMP_SNMP_VARBIND
, vb
);
221 snmp_error_response(msg_ps
,SNMP_ES_TOOBIG
);
226 /* vb->value_len == 0, empty value (e.g. empty string) */
227 en
->get_value_a(request_id
, &msg_ps
->ext_object_def
, 0, NULL
);
229 snmp_varbind_tail_add(&msg_ps
->outvb
, vb
);
230 /* search again (if vb_idx < msg_ps->invb.count) */
231 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
237 en
->get_value_pc(request_id
, &msg_ps
->ext_object_def
);
238 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_event: no outvb space\n"));
239 snmp_error_response(msg_ps
,SNMP_ES_TOOBIG
);
243 while ((msg_ps
->state
== SNMP_MSG_SEARCH_OBJ
) &&
244 (msg_ps
->vb_idx
< msg_ps
->invb
.count
))
247 struct snmp_name_ptr np
;
249 if (msg_ps
->vb_idx
== 0)
251 msg_ps
->vb_ptr
= msg_ps
->invb
.head
;
255 msg_ps
->vb_ptr
= msg_ps
->vb_ptr
->next
;
257 /** test object identifier for .iso.org.dod.internet prefix */
258 if (snmp_iso_prefix_tst(msg_ps
->vb_ptr
->ident_len
, msg_ps
->vb_ptr
->ident
))
260 mn
= snmp_search_tree((struct mib_node
*)&internet
, msg_ps
->vb_ptr
->ident_len
- 4,
261 msg_ps
->vb_ptr
->ident
+ 4, &np
);
264 if (mn
->node_type
== MIB_NODE_EX
)
266 /* external object */
267 struct mib_external_node
*en
= (struct mib_external_node
*)mn
;
269 msg_ps
->state
= SNMP_MSG_EXTERNAL_GET_OBJDEF
;
270 /* save en && args in msg_ps!! */
271 msg_ps
->ext_mib_node
= en
;
272 msg_ps
->ext_name_ptr
= np
;
274 en
->get_object_def_q(en
->addr_inf
, request_id
, np
.ident_len
, np
.ident
);
278 /* internal object */
279 struct obj_def object_def
;
281 msg_ps
->state
= SNMP_MSG_INTERNAL_GET_OBJDEF
;
282 mn
->get_object_def(np
.ident_len
, np
.ident
, &object_def
);
283 if ((object_def
.instance
!= MIB_OBJECT_NONE
) &&
284 (object_def
.access
& MIB_ACCESS_READ
))
290 /* search failed, object id points to unknown object (nosuchname) */
295 struct snmp_varbind
*vb
;
297 msg_ps
->state
= SNMP_MSG_INTERNAL_GET_VALUE
;
298 /* allocate output varbind */
299 vb
= (struct snmp_varbind
*)memp_malloc(MEMP_SNMP_VARBIND
);
300 LWIP_ASSERT("vb != NULL",vb
!= NULL
);
306 /* move name from invb to outvb */
307 vb
->ident
= msg_ps
->vb_ptr
->ident
;
308 vb
->ident_len
= msg_ps
->vb_ptr
->ident_len
;
309 /* ensure this memory is refereced once only */
310 msg_ps
->vb_ptr
->ident
= NULL
;
311 msg_ps
->vb_ptr
->ident_len
= 0;
313 vb
->value_type
= object_def
.asn_type
;
314 LWIP_ASSERT("invalid length", object_def
.v_len
<= 0xff);
315 vb
->value_len
= (u8_t
)object_def
.v_len
;
316 if (vb
->value_len
> 0)
318 LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
319 vb
->value_len
<= SNMP_MAX_VALUE_SIZE
);
320 vb
->value
= memp_malloc(MEMP_SNMP_VALUE
);
321 LWIP_ASSERT("vb->value != NULL",vb
->value
!= NULL
);
322 if (vb
->value
!= NULL
)
324 mn
->get_value(&object_def
, vb
->value_len
, vb
->value
);
325 snmp_varbind_tail_add(&msg_ps
->outvb
, vb
);
326 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
331 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_event: couldn't allocate variable space\n"));
332 msg_ps
->vb_ptr
->ident
= vb
->ident
;
333 msg_ps
->vb_ptr
->ident_len
= vb
->ident_len
;
334 memp_free(MEMP_SNMP_VARBIND
, vb
);
335 snmp_error_response(msg_ps
,SNMP_ES_TOOBIG
);
340 /* vb->value_len == 0, empty value (e.g. empty string) */
342 snmp_varbind_tail_add(&msg_ps
->outvb
, vb
);
343 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
349 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_event: couldn't allocate outvb space\n"));
350 snmp_error_response(msg_ps
,SNMP_ES_TOOBIG
);
362 /* mn == NULL, noSuchName */
363 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
366 if ((msg_ps
->state
== SNMP_MSG_SEARCH_OBJ
) &&
367 (msg_ps
->vb_idx
== msg_ps
->invb
.count
))
369 snmp_ok_response(msg_ps
);
374 * Service an internal or external event for SNMP GETNEXT.
376 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
377 * @param msg_ps points to the assosicated message process state
380 snmp_msg_getnext_event(u8_t request_id
, struct snmp_msg_pstat
*msg_ps
)
382 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F
"\n",(u16_t
)msg_ps
->state
));
384 if (msg_ps
->state
== SNMP_MSG_EXTERNAL_GET_OBJDEF
)
386 struct mib_external_node
*en
;
388 /* get_object_def() answer*/
389 en
= msg_ps
->ext_mib_node
;
391 /* translate answer into a known lifeform */
392 en
->get_object_def_a(request_id
, 1, &msg_ps
->ext_oid
.id
[msg_ps
->ext_oid
.len
- 1], &msg_ps
->ext_object_def
);
393 if (msg_ps
->ext_object_def
.instance
!= MIB_OBJECT_NONE
)
395 msg_ps
->state
= SNMP_MSG_EXTERNAL_GET_VALUE
;
396 en
->get_value_q(request_id
, &msg_ps
->ext_object_def
);
400 en
->get_object_def_pc(request_id
, 1, &msg_ps
->ext_oid
.id
[msg_ps
->ext_oid
.len
- 1]);
401 /* search failed, object id points to unknown object (nosuchname) */
402 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
405 else if (msg_ps
->state
== SNMP_MSG_EXTERNAL_GET_VALUE
)
407 struct mib_external_node
*en
;
408 struct snmp_varbind
*vb
;
410 /* get_value() answer */
411 en
= msg_ps
->ext_mib_node
;
413 LWIP_ASSERT("invalid length", msg_ps
->ext_object_def
.v_len
<= 0xff);
414 vb
= snmp_varbind_alloc(&msg_ps
->ext_oid
,
415 msg_ps
->ext_object_def
.asn_type
,
416 (u8_t
)msg_ps
->ext_object_def
.v_len
);
419 en
->get_value_a(request_id
, &msg_ps
->ext_object_def
, vb
->value_len
, vb
->value
);
420 snmp_varbind_tail_add(&msg_ps
->outvb
, vb
);
421 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
426 en
->get_value_pc(request_id
, &msg_ps
->ext_object_def
);
427 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
428 snmp_error_response(msg_ps
,SNMP_ES_TOOBIG
);
432 while ((msg_ps
->state
== SNMP_MSG_SEARCH_OBJ
) &&
433 (msg_ps
->vb_idx
< msg_ps
->invb
.count
))
436 struct snmp_obj_id oid
;
438 if (msg_ps
->vb_idx
== 0)
440 msg_ps
->vb_ptr
= msg_ps
->invb
.head
;
444 msg_ps
->vb_ptr
= msg_ps
->vb_ptr
->next
;
446 if (snmp_iso_prefix_expand(msg_ps
->vb_ptr
->ident_len
, msg_ps
->vb_ptr
->ident
, &oid
))
448 if (msg_ps
->vb_ptr
->ident_len
> 3)
450 /* can offset ident_len and ident */
451 mn
= snmp_expand_tree((struct mib_node
*)&internet
,
452 msg_ps
->vb_ptr
->ident_len
- 4,
453 msg_ps
->vb_ptr
->ident
+ 4, &oid
);
457 /* can't offset ident_len -4, ident + 4 */
458 mn
= snmp_expand_tree((struct mib_node
*)&internet
, 0, NULL
, &oid
);
467 if (mn
->node_type
== MIB_NODE_EX
)
469 /* external object */
470 struct mib_external_node
*en
= (struct mib_external_node
*)mn
;
472 msg_ps
->state
= SNMP_MSG_EXTERNAL_GET_OBJDEF
;
473 /* save en && args in msg_ps!! */
474 msg_ps
->ext_mib_node
= en
;
475 msg_ps
->ext_oid
= oid
;
477 en
->get_object_def_q(en
->addr_inf
, request_id
, 1, &oid
.id
[oid
.len
- 1]);
481 /* internal object */
482 struct obj_def object_def
;
483 struct snmp_varbind
*vb
;
485 msg_ps
->state
= SNMP_MSG_INTERNAL_GET_OBJDEF
;
486 mn
->get_object_def(1, &oid
.id
[oid
.len
- 1], &object_def
);
488 LWIP_ASSERT("invalid length", object_def
.v_len
<= 0xff);
489 vb
= snmp_varbind_alloc(&oid
, object_def
.asn_type
, (u8_t
)object_def
.v_len
);
492 msg_ps
->state
= SNMP_MSG_INTERNAL_GET_VALUE
;
493 mn
->get_value(&object_def
, object_def
.v_len
, vb
->value
);
494 snmp_varbind_tail_add(&msg_ps
->outvb
, vb
);
495 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
500 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_recv couldn't allocate outvb space\n"));
501 snmp_error_response(msg_ps
,SNMP_ES_TOOBIG
);
507 /* mn == NULL, noSuchName */
508 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
511 if ((msg_ps
->state
== SNMP_MSG_SEARCH_OBJ
) &&
512 (msg_ps
->vb_idx
== msg_ps
->invb
.count
))
514 snmp_ok_response(msg_ps
);
519 * Service an internal or external event for SNMP SET.
521 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
522 * @param msg_ps points to the assosicated message process state
525 snmp_msg_set_event(u8_t request_id
, struct snmp_msg_pstat
*msg_ps
)
527 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_msg_set_event: msg_ps->state==%"U16_F
"\n",(u16_t
)msg_ps
->state
));
529 if (msg_ps
->state
== SNMP_MSG_EXTERNAL_GET_OBJDEF
)
531 struct mib_external_node
*en
;
532 struct snmp_name_ptr np
;
534 /* get_object_def() answer*/
535 en
= msg_ps
->ext_mib_node
;
536 np
= msg_ps
->ext_name_ptr
;
538 /* translate answer into a known lifeform */
539 en
->get_object_def_a(request_id
, np
.ident_len
, np
.ident
, &msg_ps
->ext_object_def
);
540 if (msg_ps
->ext_object_def
.instance
!= MIB_OBJECT_NONE
)
542 msg_ps
->state
= SNMP_MSG_EXTERNAL_SET_TEST
;
543 en
->set_test_q(request_id
, &msg_ps
->ext_object_def
);
547 en
->get_object_def_pc(request_id
, np
.ident_len
, np
.ident
);
548 /* search failed, object id points to unknown object (nosuchname) */
549 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
552 else if (msg_ps
->state
== SNMP_MSG_EXTERNAL_SET_TEST
)
554 struct mib_external_node
*en
;
556 /* set_test() answer*/
557 en
= msg_ps
->ext_mib_node
;
559 if (msg_ps
->ext_object_def
.access
& MIB_ACCESS_WRITE
)
561 if ((msg_ps
->ext_object_def
.asn_type
== msg_ps
->vb_ptr
->value_type
) &&
562 (en
->set_test_a(request_id
,&msg_ps
->ext_object_def
,
563 msg_ps
->vb_ptr
->value_len
,msg_ps
->vb_ptr
->value
) != 0))
565 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
570 en
->set_test_pc(request_id
,&msg_ps
->ext_object_def
);
572 snmp_error_response(msg_ps
,SNMP_ES_BADVALUE
);
577 en
->set_test_pc(request_id
,&msg_ps
->ext_object_def
);
578 /* object not available for set */
579 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
582 else if (msg_ps
->state
== SNMP_MSG_EXTERNAL_GET_OBJDEF_S
)
584 struct mib_external_node
*en
;
585 struct snmp_name_ptr np
;
587 /* get_object_def() answer*/
588 en
= msg_ps
->ext_mib_node
;
589 np
= msg_ps
->ext_name_ptr
;
591 /* translate answer into a known lifeform */
592 en
->get_object_def_a(request_id
, np
.ident_len
, np
.ident
, &msg_ps
->ext_object_def
);
593 if (msg_ps
->ext_object_def
.instance
!= MIB_OBJECT_NONE
)
595 msg_ps
->state
= SNMP_MSG_EXTERNAL_SET_VALUE
;
596 en
->set_value_q(request_id
, &msg_ps
->ext_object_def
,
597 msg_ps
->vb_ptr
->value_len
,msg_ps
->vb_ptr
->value
);
601 en
->get_object_def_pc(request_id
, np
.ident_len
, np
.ident
);
602 /* set_value failed, object has disappeared for some odd reason?? */
603 snmp_error_response(msg_ps
,SNMP_ES_GENERROR
);
606 else if (msg_ps
->state
== SNMP_MSG_EXTERNAL_SET_VALUE
)
608 struct mib_external_node
*en
;
611 en
= msg_ps
->ext_mib_node
;
612 en
->set_value_a(request_id
, &msg_ps
->ext_object_def
,
613 msg_ps
->vb_ptr
->value_len
, msg_ps
->vb_ptr
->value
);
615 /** @todo use set_value_pc() if toobig */
616 msg_ps
->state
= SNMP_MSG_INTERNAL_SET_VALUE
;
620 /* test all values before setting */
621 while ((msg_ps
->state
== SNMP_MSG_SEARCH_OBJ
) &&
622 (msg_ps
->vb_idx
< msg_ps
->invb
.count
))
625 struct snmp_name_ptr np
;
627 if (msg_ps
->vb_idx
== 0)
629 msg_ps
->vb_ptr
= msg_ps
->invb
.head
;
633 msg_ps
->vb_ptr
= msg_ps
->vb_ptr
->next
;
635 /** test object identifier for .iso.org.dod.internet prefix */
636 if (snmp_iso_prefix_tst(msg_ps
->vb_ptr
->ident_len
, msg_ps
->vb_ptr
->ident
))
638 mn
= snmp_search_tree((struct mib_node
*)&internet
, msg_ps
->vb_ptr
->ident_len
- 4,
639 msg_ps
->vb_ptr
->ident
+ 4, &np
);
642 if (mn
->node_type
== MIB_NODE_EX
)
644 /* external object */
645 struct mib_external_node
*en
= (struct mib_external_node
*)mn
;
647 msg_ps
->state
= SNMP_MSG_EXTERNAL_GET_OBJDEF
;
648 /* save en && args in msg_ps!! */
649 msg_ps
->ext_mib_node
= en
;
650 msg_ps
->ext_name_ptr
= np
;
652 en
->get_object_def_q(en
->addr_inf
, request_id
, np
.ident_len
, np
.ident
);
656 /* internal object */
657 struct obj_def object_def
;
659 msg_ps
->state
= SNMP_MSG_INTERNAL_GET_OBJDEF
;
660 mn
->get_object_def(np
.ident_len
, np
.ident
, &object_def
);
661 if (object_def
.instance
!= MIB_OBJECT_NONE
)
667 /* search failed, object id points to unknown object (nosuchname) */
672 msg_ps
->state
= SNMP_MSG_INTERNAL_SET_TEST
;
674 if (object_def
.access
& MIB_ACCESS_WRITE
)
676 if ((object_def
.asn_type
== msg_ps
->vb_ptr
->value_type
) &&
677 (mn
->set_test(&object_def
,msg_ps
->vb_ptr
->value_len
,msg_ps
->vb_ptr
->value
) != 0))
679 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
685 snmp_error_response(msg_ps
,SNMP_ES_BADVALUE
);
690 /* object not available for set */
691 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
703 /* mn == NULL, noSuchName */
704 snmp_error_response(msg_ps
,SNMP_ES_NOSUCHNAME
);
708 if ((msg_ps
->state
== SNMP_MSG_SEARCH_OBJ
) &&
709 (msg_ps
->vb_idx
== msg_ps
->invb
.count
))
712 msg_ps
->state
= SNMP_MSG_INTERNAL_SET_VALUE
;
715 /* set all values "atomically" (be as "atomic" as possible) */
716 while ((msg_ps
->state
== SNMP_MSG_INTERNAL_SET_VALUE
) &&
717 (msg_ps
->vb_idx
< msg_ps
->invb
.count
))
720 struct snmp_name_ptr np
;
722 if (msg_ps
->vb_idx
== 0)
724 msg_ps
->vb_ptr
= msg_ps
->invb
.head
;
728 msg_ps
->vb_ptr
= msg_ps
->vb_ptr
->next
;
730 /* skip iso prefix test, was done previously while settesting() */
731 mn
= snmp_search_tree((struct mib_node
*)&internet
, msg_ps
->vb_ptr
->ident_len
- 4,
732 msg_ps
->vb_ptr
->ident
+ 4, &np
);
733 /* check if object is still available
734 (e.g. external hot-plug thingy present?) */
737 if (mn
->node_type
== MIB_NODE_EX
)
739 /* external object */
740 struct mib_external_node
*en
= (struct mib_external_node
*)mn
;
742 msg_ps
->state
= SNMP_MSG_EXTERNAL_GET_OBJDEF_S
;
743 /* save en && args in msg_ps!! */
744 msg_ps
->ext_mib_node
= en
;
745 msg_ps
->ext_name_ptr
= np
;
747 en
->get_object_def_q(en
->addr_inf
, request_id
, np
.ident_len
, np
.ident
);
751 /* internal object */
752 struct obj_def object_def
;
754 msg_ps
->state
= SNMP_MSG_INTERNAL_GET_OBJDEF_S
;
755 mn
->get_object_def(np
.ident_len
, np
.ident
, &object_def
);
756 msg_ps
->state
= SNMP_MSG_INTERNAL_SET_VALUE
;
757 mn
->set_value(&object_def
,msg_ps
->vb_ptr
->value_len
,msg_ps
->vb_ptr
->value
);
762 if ((msg_ps
->state
== SNMP_MSG_INTERNAL_SET_VALUE
) &&
763 (msg_ps
->vb_idx
== msg_ps
->invb
.count
))
765 /* simply echo the input if we can set it
766 @todo do we need to return the actual value?
767 e.g. if value is silently modified or behaves sticky? */
768 msg_ps
->outvb
= msg_ps
->invb
;
769 msg_ps
->invb
.head
= NULL
;
770 msg_ps
->invb
.tail
= NULL
;
771 msg_ps
->invb
.count
= 0;
772 snmp_ok_response(msg_ps
);
778 * Handle one internal or external event.
779 * Called for one async event. (recv external/private answer)
781 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
784 snmp_msg_event(u8_t request_id
)
786 struct snmp_msg_pstat
*msg_ps
;
788 if (request_id
< SNMP_CONCURRENT_REQUESTS
)
790 msg_ps
= &msg_input_list
[request_id
];
791 if (msg_ps
->rt
== SNMP_ASN1_PDU_GET_NEXT_REQ
)
793 snmp_msg_getnext_event(request_id
, msg_ps
);
795 else if (msg_ps
->rt
== SNMP_ASN1_PDU_GET_REQ
)
797 snmp_msg_get_event(request_id
, msg_ps
);
799 else if(msg_ps
->rt
== SNMP_ASN1_PDU_SET_REQ
)
801 snmp_msg_set_event(request_id
, msg_ps
);
807 /* lwIP UDP receive callback function */
809 snmp_recv(void *arg
, struct udp_pcb
*pcb
, struct pbuf
*p
, ip_addr_t
*addr
, u16_t port
)
811 struct snmp_msg_pstat
*msg_ps
;
814 u16_t payload_len
= p
->tot_len
;
815 u16_t payload_ofs
= 0;
816 u16_t varbind_ofs
= 0;
818 /* suppress unused argument warning */
819 LWIP_UNUSED_ARG(arg
);
821 /* traverse input message process list, look for SNMP_MSG_EMPTY */
822 msg_ps
= &msg_input_list
[0];
824 while ((req_idx
< SNMP_CONCURRENT_REQUESTS
) && (msg_ps
->state
!= SNMP_MSG_EMPTY
))
829 if (req_idx
== SNMP_CONCURRENT_REQUESTS
)
831 /* exceeding number of concurrent requests */
836 /* accepting request */
837 snmp_inc_snmpinpkts();
838 /* record used 'protocol control block' */
840 /* source address (network order) */
842 /* source port (host order (lwIP oddity)) */
845 /* check total length, version, community, pdu type */
846 err_ret
= snmp_pdu_header_check(p
, payload_ofs
, payload_len
, &varbind_ofs
, msg_ps
);
847 /* Only accept requests and requests without error (be robust) */
848 /* Reject response and trap headers or error requests as input! */
849 if ((err_ret
!= ERR_OK
) ||
850 ((msg_ps
->rt
!= SNMP_ASN1_PDU_GET_REQ
) &&
851 (msg_ps
->rt
!= SNMP_ASN1_PDU_GET_NEXT_REQ
) &&
852 (msg_ps
->rt
!= SNMP_ASN1_PDU_SET_REQ
)) ||
853 ((msg_ps
->error_status
!= SNMP_ES_NOERROR
) ||
854 (msg_ps
->error_index
!= 0)) )
856 /* header check failed drop request silently, do not return error! */
858 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_pdu_header_check() failed\n"));
861 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_recv ok, community %s\n", msg_ps
->community
));
863 /* Builds a list of variable bindings. Copy the varbinds from the pbuf
864 chain to glue them when these are divided over two or more pbuf's. */
865 err_ret
= snmp_pdu_dec_varbindlist(p
, varbind_ofs
, &varbind_ofs
, msg_ps
);
866 /* we've decoded the incoming message, release input msg now */
868 if ((err_ret
!= ERR_OK
) || (msg_ps
->invb
.count
== 0))
870 /* varbind-list decode failed, or varbind list empty.
871 drop request silently, do not return error!
872 (errors are only returned for a specific varbind failure) */
873 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_pdu_dec_varbindlist() failed\n"));
877 msg_ps
->error_status
= SNMP_ES_NOERROR
;
878 msg_ps
->error_index
= 0;
879 /* find object for each variable binding */
880 msg_ps
->state
= SNMP_MSG_SEARCH_OBJ
;
881 /* first variable binding from list to inspect */
884 LWIP_DEBUGF(SNMP_MSG_DEBUG
, ("snmp_recv varbind cnt=%"U16_F
"\n",(u16_t
)msg_ps
->invb
.count
));
886 /* handle input event and as much objects as possible in one go */
887 snmp_msg_event(req_idx
);
891 * Checks and decodes incoming SNMP message header, logs header errors.
893 * @param p points to pbuf chain of SNMP message (UDP payload)
894 * @param ofs points to first octet of SNMP message
895 * @param pdu_len the length of the UDP payload
896 * @param ofs_ret returns the ofset of the variable bindings
897 * @param m_stat points to the current message request state return
899 * - ERR_OK SNMP header is sane and accepted
900 * - ERR_ARG SNMP header is either malformed or rejected
903 snmp_pdu_header_check(struct pbuf
*p
, u16_t ofs
, u16_t pdu_len
, u16_t
*ofs_ret
, struct snmp_msg_pstat
*m_stat
)
912 snmp_asn1_dec_type(p
, ofs
, &type
);
913 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
914 if ((derr
!= ERR_OK
) ||
915 (pdu_len
!= (1 + len_octets
+ len
)) ||
916 (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_CONSTR
| SNMP_ASN1_SEQ
)))
918 snmp_inc_snmpinasnparseerrs();
921 ofs
+= (1 + len_octets
);
922 snmp_asn1_dec_type(p
, ofs
, &type
);
923 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
924 if ((derr
!= ERR_OK
) || (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_INTEG
)))
926 /* can't decode or no integer (version) */
927 snmp_inc_snmpinasnparseerrs();
930 derr
= snmp_asn1_dec_s32t(p
, ofs
+ 1 + len_octets
, len
, &version
);
934 snmp_inc_snmpinasnparseerrs();
940 snmp_inc_snmpinbadversions();
943 ofs
+= (1 + len_octets
+ len
);
944 snmp_asn1_dec_type(p
, ofs
, &type
);
945 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
946 if ((derr
!= ERR_OK
) || (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_OC_STR
)))
948 /* can't decode or no octet string (community) */
949 snmp_inc_snmpinasnparseerrs();
952 derr
= snmp_asn1_dec_raw(p
, ofs
+ 1 + len_octets
, len
, SNMP_COMMUNITY_STR_LEN
, m_stat
->community
);
955 snmp_inc_snmpinasnparseerrs();
958 /* add zero terminator */
959 len
= ((len
< (SNMP_COMMUNITY_STR_LEN
))?(len
):(SNMP_COMMUNITY_STR_LEN
));
960 m_stat
->community
[len
] = 0;
961 m_stat
->com_strlen
= (u8_t
)len
;
962 if (strncmp(snmp_publiccommunity
, (const char*)m_stat
->community
, SNMP_COMMUNITY_STR_LEN
) != 0)
964 /** @todo: move this if we need to check more names */
965 snmp_inc_snmpinbadcommunitynames();
966 snmp_authfail_trap();
969 ofs
+= (1 + len_octets
+ len
);
970 snmp_asn1_dec_type(p
, ofs
, &type
);
971 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
974 snmp_inc_snmpinasnparseerrs();
979 case (SNMP_ASN1_CONTXT
| SNMP_ASN1_CONSTR
| SNMP_ASN1_PDU_GET_REQ
):
981 snmp_inc_snmpingetrequests();
984 case (SNMP_ASN1_CONTXT
| SNMP_ASN1_CONSTR
| SNMP_ASN1_PDU_GET_NEXT_REQ
):
985 /* GetNextRequest PDU */
986 snmp_inc_snmpingetnexts();
989 case (SNMP_ASN1_CONTXT
| SNMP_ASN1_CONSTR
| SNMP_ASN1_PDU_GET_RESP
):
990 /* GetResponse PDU */
991 snmp_inc_snmpingetresponses();
994 case (SNMP_ASN1_CONTXT
| SNMP_ASN1_CONSTR
| SNMP_ASN1_PDU_SET_REQ
):
996 snmp_inc_snmpinsetrequests();
999 case (SNMP_ASN1_CONTXT
| SNMP_ASN1_CONSTR
| SNMP_ASN1_PDU_TRAP
):
1001 snmp_inc_snmpintraps();
1005 snmp_inc_snmpinasnparseerrs();
1011 /* unsupported input PDU for this agent (no parse error) */
1014 m_stat
->rt
= type
& 0x1F;
1015 ofs
+= (1 + len_octets
);
1016 if (len
!= (pdu_len
- (ofs
- ofs_base
)))
1018 /* decoded PDU length does not equal actual payload length */
1019 snmp_inc_snmpinasnparseerrs();
1022 snmp_asn1_dec_type(p
, ofs
, &type
);
1023 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
1024 if ((derr
!= ERR_OK
) || (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_INTEG
)))
1026 /* can't decode or no integer (request ID) */
1027 snmp_inc_snmpinasnparseerrs();
1030 derr
= snmp_asn1_dec_s32t(p
, ofs
+ 1 + len_octets
, len
, &m_stat
->rid
);
1034 snmp_inc_snmpinasnparseerrs();
1037 ofs
+= (1 + len_octets
+ len
);
1038 snmp_asn1_dec_type(p
, ofs
, &type
);
1039 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
1040 if ((derr
!= ERR_OK
) || (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_INTEG
)))
1042 /* can't decode or no integer (error-status) */
1043 snmp_inc_snmpinasnparseerrs();
1046 /* must be noError (0) for incoming requests.
1047 log errors for mib-2 completeness and for debug purposes */
1048 derr
= snmp_asn1_dec_s32t(p
, ofs
+ 1 + len_octets
, len
, &m_stat
->error_status
);
1052 snmp_inc_snmpinasnparseerrs();
1055 switch (m_stat
->error_status
)
1057 case SNMP_ES_TOOBIG
:
1058 snmp_inc_snmpintoobigs();
1060 case SNMP_ES_NOSUCHNAME
:
1061 snmp_inc_snmpinnosuchnames();
1063 case SNMP_ES_BADVALUE
:
1064 snmp_inc_snmpinbadvalues();
1066 case SNMP_ES_READONLY
:
1067 snmp_inc_snmpinreadonlys();
1069 case SNMP_ES_GENERROR
:
1070 snmp_inc_snmpingenerrs();
1073 ofs
+= (1 + len_octets
+ len
);
1074 snmp_asn1_dec_type(p
, ofs
, &type
);
1075 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
1076 if ((derr
!= ERR_OK
) || (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_INTEG
)))
1078 /* can't decode or no integer (error-index) */
1079 snmp_inc_snmpinasnparseerrs();
1082 /* must be 0 for incoming requests.
1083 decode anyway to catch bad integers (and dirty tricks) */
1084 derr
= snmp_asn1_dec_s32t(p
, ofs
+ 1 + len_octets
, len
, &m_stat
->error_index
);
1088 snmp_inc_snmpinasnparseerrs();
1091 ofs
+= (1 + len_octets
+ len
);
1097 snmp_pdu_dec_varbindlist(struct pbuf
*p
, u16_t ofs
, u16_t
*ofs_ret
, struct snmp_msg_pstat
*m_stat
)
1104 /* variable binding list */
1105 snmp_asn1_dec_type(p
, ofs
, &type
);
1106 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &vb_len
);
1107 if ((derr
!= ERR_OK
) ||
1108 (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_CONSTR
| SNMP_ASN1_SEQ
)))
1110 snmp_inc_snmpinasnparseerrs();
1113 ofs
+= (1 + len_octets
);
1115 /* start with empty list */
1116 m_stat
->invb
.count
= 0;
1117 m_stat
->invb
.head
= NULL
;
1118 m_stat
->invb
.tail
= NULL
;
1122 struct snmp_obj_id oid
, oid_value
;
1123 struct snmp_varbind
*vb
;
1125 snmp_asn1_dec_type(p
, ofs
, &type
);
1126 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
1127 if ((derr
!= ERR_OK
) ||
1128 (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_CONSTR
| SNMP_ASN1_SEQ
)) ||
1129 (len
== 0) || (len
> vb_len
))
1131 snmp_inc_snmpinasnparseerrs();
1132 /* free varbinds (if available) */
1133 snmp_varbind_list_free(&m_stat
->invb
);
1136 ofs
+= (1 + len_octets
);
1137 vb_len
-= (1 + len_octets
);
1139 snmp_asn1_dec_type(p
, ofs
, &type
);
1140 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
1141 if ((derr
!= ERR_OK
) || (type
!= (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_OBJ_ID
)))
1143 /* can't decode object name length */
1144 snmp_inc_snmpinasnparseerrs();
1145 /* free varbinds (if available) */
1146 snmp_varbind_list_free(&m_stat
->invb
);
1149 derr
= snmp_asn1_dec_oid(p
, ofs
+ 1 + len_octets
, len
, &oid
);
1152 /* can't decode object name */
1153 snmp_inc_snmpinasnparseerrs();
1154 /* free varbinds (if available) */
1155 snmp_varbind_list_free(&m_stat
->invb
);
1158 ofs
+= (1 + len_octets
+ len
);
1159 vb_len
-= (1 + len_octets
+ len
);
1161 snmp_asn1_dec_type(p
, ofs
, &type
);
1162 derr
= snmp_asn1_dec_length(p
, ofs
+1, &len_octets
, &len
);
1165 /* can't decode object value length */
1166 snmp_inc_snmpinasnparseerrs();
1167 /* free varbinds (if available) */
1168 snmp_varbind_list_free(&m_stat
->invb
);
1174 case (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_INTEG
):
1175 vb
= snmp_varbind_alloc(&oid
, type
, sizeof(s32_t
));
1178 s32_t
*vptr
= (s32_t
*)vb
->value
;
1180 derr
= snmp_asn1_dec_s32t(p
, ofs
+ 1 + len_octets
, len
, vptr
);
1181 snmp_varbind_tail_add(&m_stat
->invb
, vb
);
1188 case (SNMP_ASN1_APPLIC
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_COUNTER
):
1189 case (SNMP_ASN1_APPLIC
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_GAUGE
):
1190 case (SNMP_ASN1_APPLIC
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_TIMETICKS
):
1191 vb
= snmp_varbind_alloc(&oid
, type
, sizeof(u32_t
));
1194 u32_t
*vptr
= (u32_t
*)vb
->value
;
1196 derr
= snmp_asn1_dec_u32t(p
, ofs
+ 1 + len_octets
, len
, vptr
);
1197 snmp_varbind_tail_add(&m_stat
->invb
, vb
);
1204 case (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_OC_STR
):
1205 case (SNMP_ASN1_APPLIC
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_OPAQUE
):
1206 LWIP_ASSERT("invalid length", len
<= 0xff);
1207 vb
= snmp_varbind_alloc(&oid
, type
, (u8_t
)len
);
1210 derr
= snmp_asn1_dec_raw(p
, ofs
+ 1 + len_octets
, len
, vb
->value_len
, (u8_t
*)vb
->value
);
1211 snmp_varbind_tail_add(&m_stat
->invb
, vb
);
1218 case (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_NUL
):
1219 vb
= snmp_varbind_alloc(&oid
, type
, 0);
1222 snmp_varbind_tail_add(&m_stat
->invb
, vb
);
1230 case (SNMP_ASN1_UNIV
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_OBJ_ID
):
1231 derr
= snmp_asn1_dec_oid(p
, ofs
+ 1 + len_octets
, len
, &oid_value
);
1234 vb
= snmp_varbind_alloc(&oid
, type
, oid_value
.len
* sizeof(s32_t
));
1237 u8_t i
= oid_value
.len
;
1238 s32_t
*vptr
= (s32_t
*)vb
->value
;
1243 vptr
[i
] = oid_value
.id
[i
];
1245 snmp_varbind_tail_add(&m_stat
->invb
, vb
);
1254 case (SNMP_ASN1_APPLIC
| SNMP_ASN1_PRIMIT
| SNMP_ASN1_IPADDR
):
1257 /* must be exactly 4 octets! */
1258 vb
= snmp_varbind_alloc(&oid
, type
, 4);
1261 derr
= snmp_asn1_dec_raw(p
, ofs
+ 1 + len_octets
, len
, vb
->value_len
, (u8_t
*)vb
->value
);
1262 snmp_varbind_tail_add(&m_stat
->invb
, vb
);
1280 snmp_inc_snmpinasnparseerrs();
1281 /* free varbinds (if available) */
1282 snmp_varbind_list_free(&m_stat
->invb
);
1285 ofs
+= (1 + len_octets
+ len
);
1286 vb_len
-= (1 + len_octets
+ len
);
1289 if (m_stat
->rt
== SNMP_ASN1_PDU_SET_REQ
)
1291 snmp_add_snmpintotalsetvars(m_stat
->invb
.count
);
1295 snmp_add_snmpintotalreqvars(m_stat
->invb
.count
);
1302 struct snmp_varbind
*
1303 snmp_varbind_alloc(struct snmp_obj_id
*oid
, u8_t type
, u8_t len
)
1305 struct snmp_varbind
*vb
;
1307 vb
= (struct snmp_varbind
*)memp_malloc(MEMP_SNMP_VARBIND
);
1308 LWIP_ASSERT("vb != NULL",vb
!= NULL
);
1319 LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i
<= SNMP_MAX_TREE_DEPTH
);
1320 /* allocate array of s32_t for our object identifier */
1321 vb
->ident
= (s32_t
*)memp_malloc(MEMP_SNMP_VALUE
);
1322 LWIP_ASSERT("vb->ident != NULL",vb
->ident
!= NULL
);
1323 if (vb
->ident
== NULL
)
1325 memp_free(MEMP_SNMP_VARBIND
, vb
);
1331 vb
->ident
[i
] = oid
->id
[i
];
1336 /* i == 0, pass zero length object identifier */
1339 vb
->value_type
= type
;
1340 vb
->value_len
= len
;
1343 LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb
->value_len
<= SNMP_MAX_VALUE_SIZE
);
1344 /* allocate raw bytes for our object value */
1345 vb
->value
= memp_malloc(MEMP_SNMP_VALUE
);
1346 LWIP_ASSERT("vb->value != NULL",vb
->value
!= NULL
);
1347 if (vb
->value
== NULL
)
1349 if (vb
->ident
!= NULL
)
1351 memp_free(MEMP_SNMP_VALUE
, vb
->ident
);
1353 memp_free(MEMP_SNMP_VARBIND
, vb
);
1359 /* ASN1_NUL type, or zero length ASN1_OC_STR */
1367 snmp_varbind_free(struct snmp_varbind
*vb
)
1369 if (vb
->value
!= NULL
)
1371 memp_free(MEMP_SNMP_VALUE
, vb
->value
);
1373 if (vb
->ident
!= NULL
)
1375 memp_free(MEMP_SNMP_VALUE
, vb
->ident
);
1377 memp_free(MEMP_SNMP_VARBIND
, vb
);
1381 snmp_varbind_list_free(struct snmp_varbind_root
*root
)
1383 struct snmp_varbind
*vb
, *prev
;
1386 while ( vb
!= NULL
)
1389 snmp_varbind_free(vb
);
1398 snmp_varbind_tail_add(struct snmp_varbind_root
*root
, struct snmp_varbind
*vb
)
1400 if (root
->count
== 0)
1402 /* add first varbind to list */
1408 /* add nth varbind to list tail */
1409 root
->tail
->next
= vb
;
1410 vb
->prev
= root
->tail
;
1416 struct snmp_varbind
*
1417 snmp_varbind_tail_remove(struct snmp_varbind_root
*root
)
1419 struct snmp_varbind
* vb
;
1421 if (root
->count
> 0)
1423 /* remove tail varbind */
1425 root
->tail
= vb
->prev
;
1426 vb
->prev
->next
= NULL
;
1431 /* nothing to remove */
1437 #endif /* LWIP_SNMP */