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/ip_addr.h"
 
  42 #include "lwip/stats.h"
 
  43 #include "lwip/snmp.h"
 
  44 #include "lwip/snmp_asn1.h"
 
  45 #include "lwip/snmp_msg.h"
 
  46 #include "lwip/snmp_structs.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, struct ip_addr *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;
 
  91   /* The coldstart trap will only be output
 
  92      if our outgoing interface is up & configured  */
 
  93   snmp_coldstart_trap();
 
  97 snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
 
  99   snmp_varbind_list_free(&msg_ps->outvb);
 
 100   msg_ps->outvb = msg_ps->invb;
 
 101   msg_ps->invb.head = NULL;
 
 102   msg_ps->invb.tail = NULL;
 
 103   msg_ps->invb.count = 0;
 
 104   msg_ps->error_status = error;
 
 105   msg_ps->error_index = 1 + msg_ps->vb_idx;
 
 106   snmp_send_response(msg_ps);
 
 107   snmp_varbind_list_free(&msg_ps->outvb);
 
 108   msg_ps->state = SNMP_MSG_EMPTY;
 
 112 snmp_ok_response(struct snmp_msg_pstat *msg_ps)
 
 116   err_ret = snmp_send_response(msg_ps);
 
 117   if (err_ret == ERR_MEM)
 
 119     /* serious memory problem, can't return tooBig */
 
 123     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
 
 125   /* free varbinds (if available) */
 
 126   snmp_varbind_list_free(&msg_ps->invb);
 
 127   snmp_varbind_list_free(&msg_ps->outvb);
 
 128   msg_ps->state = SNMP_MSG_EMPTY;
 
 132  * Service an internal or external event for SNMP GET.
 
 134  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
 
 135  * @param msg_ps points to the assosicated message process state
 
 138 snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
 
 140   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
 
 142   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
 
 144     struct mib_external_node *en;
 
 145     struct snmp_name_ptr np;
 
 147     /* get_object_def() answer*/
 
 148     en = msg_ps->ext_mib_node;
 
 149     np = msg_ps->ext_name_ptr;
 
 151     /* translate answer into a known lifeform */
 
 152     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
 
 153     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
 
 155       msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
 
 156       en->get_value_q(request_id, &msg_ps->ext_object_def);
 
 160       en->get_object_def_pc(request_id, np.ident_len, np.ident);
 
 161       /* search failed, object id points to unknown object (nosuchname) */
 
 162       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 165   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
 
 167     struct mib_external_node *en;
 
 168     struct snmp_varbind *vb;
 
 170     /* get_value() answer */
 
 171     en = msg_ps->ext_mib_node;
 
 173     /* allocate output varbind */
 
 174     vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
 
 175     LWIP_ASSERT("vb != NULL",vb != NULL);
 
 181       /* move name from invb to outvb */
 
 182       vb->ident = msg_ps->vb_ptr->ident;
 
 183       vb->ident_len = msg_ps->vb_ptr->ident_len;
 
 184       /* ensure this memory is refereced once only */
 
 185       msg_ps->vb_ptr->ident = NULL;
 
 186       msg_ps->vb_ptr->ident_len = 0;
 
 188       vb->value_type = msg_ps->ext_object_def.asn_type;
 
 189       vb->value_len =  msg_ps->ext_object_def.v_len;
 
 190       if (vb->value_len > 0)
 
 192         vb->value = mem_malloc(vb->value_len);
 
 193         LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
 
 194         if (vb->value != NULL)
 
 196           en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
 
 197           snmp_varbind_tail_add(&msg_ps->outvb, vb);
 
 198           /* search again (if vb_idx < msg_ps->invb.count) */
 
 199           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 204           en->get_value_pc(request_id, &msg_ps->ext_object_def);
 
 205           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
 
 206           msg_ps->vb_ptr->ident = vb->ident;
 
 207           msg_ps->vb_ptr->ident_len = vb->ident_len;
 
 209           snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
 
 214         /* vb->value_len == 0, empty value (e.g. empty string) */
 
 215         en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
 
 217         snmp_varbind_tail_add(&msg_ps->outvb, vb);
 
 218         /* search again (if vb_idx < msg_ps->invb.count) */
 
 219         msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 225       en->get_value_pc(request_id, &msg_ps->ext_object_def);
 
 226       LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
 
 227       snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
 
 231   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
 
 232          (msg_ps->vb_idx < msg_ps->invb.count))
 
 235     struct snmp_name_ptr np;
 
 237     if (msg_ps->vb_idx == 0)
 
 239       msg_ps->vb_ptr = msg_ps->invb.head;
 
 243       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
 
 245     /** test object identifier for .iso.org.dod.internet prefix */
 
 246     if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
 
 248       mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
 
 249                              msg_ps->vb_ptr->ident + 4, &np);
 
 252         if (mn->node_type == MIB_NODE_EX)
 
 254           /* external object */
 
 255           struct mib_external_node *en = (struct mib_external_node*)mn;
 
 257           msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
 
 258           /* save en && args in msg_ps!! */
 
 259           msg_ps->ext_mib_node = en;
 
 260           msg_ps->ext_name_ptr = np;
 
 262           en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
 
 266           /* internal object */
 
 267           struct obj_def object_def;
 
 269           msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
 
 270           mn->get_object_def(np.ident_len, np.ident, &object_def);
 
 271           if (object_def.instance != MIB_OBJECT_NONE)
 
 277             /* search failed, object id points to unknown object (nosuchname) */
 
 282             struct snmp_varbind *vb;
 
 284             msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
 
 285             /* allocate output varbind */
 
 286             vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
 
 287             LWIP_ASSERT("vb != NULL",vb != NULL);
 
 293               /* move name from invb to outvb */
 
 294               vb->ident = msg_ps->vb_ptr->ident;
 
 295               vb->ident_len = msg_ps->vb_ptr->ident_len;
 
 296               /* ensure this memory is refereced once only */
 
 297               msg_ps->vb_ptr->ident = NULL;
 
 298               msg_ps->vb_ptr->ident_len = 0;
 
 300               vb->value_type = object_def.asn_type;
 
 301               vb->value_len = object_def.v_len;
 
 302               if (vb->value_len > 0)
 
 304                 vb->value = mem_malloc(vb->value_len);
 
 305                 LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
 
 306                 if (vb->value != NULL)
 
 308                   mn->get_value(&object_def, vb->value_len, vb->value);
 
 309                   snmp_varbind_tail_add(&msg_ps->outvb, vb);
 
 310                   msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 315                   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
 
 316                   msg_ps->vb_ptr->ident = vb->ident;
 
 317                   msg_ps->vb_ptr->ident_len = vb->ident_len;
 
 319                   snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
 
 324                 /* vb->value_len == 0, empty value (e.g. empty string) */
 
 326                 snmp_varbind_tail_add(&msg_ps->outvb, vb);
 
 327                 msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 333               LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
 
 334               snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
 
 346       /* mn == NULL, noSuchName */
 
 347       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 350   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
 
 351       (msg_ps->vb_idx == msg_ps->invb.count))
 
 353     snmp_ok_response(msg_ps);
 
 358  * Service an internal or external event for SNMP GETNEXT.
 
 360  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
 
 361  * @param msg_ps points to the assosicated message process state
 
 364 snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
 
 366   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
 
 368   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
 
 370     struct mib_external_node *en;
 
 372     /* get_object_def() answer*/
 
 373     en = msg_ps->ext_mib_node;
 
 375     /* translate answer into a known lifeform */
 
 376     en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
 
 377     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
 
 379       msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
 
 380       en->get_value_q(request_id, &msg_ps->ext_object_def);
 
 384       en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
 
 385       /* search failed, object id points to unknown object (nosuchname) */
 
 386       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 389   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
 
 391     struct mib_external_node *en;
 
 392     struct snmp_varbind *vb;
 
 394     /* get_value() answer */
 
 395     en = msg_ps->ext_mib_node;
 
 397     vb = snmp_varbind_alloc(&msg_ps->ext_oid,
 
 398                             msg_ps->ext_object_def.asn_type,
 
 399                             msg_ps->ext_object_def.v_len);
 
 402       en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
 
 403       snmp_varbind_tail_add(&msg_ps->outvb, vb);
 
 404       msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 409       en->get_value_pc(request_id, &msg_ps->ext_object_def);
 
 410       LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
 
 411       snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
 
 415   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
 
 416          (msg_ps->vb_idx < msg_ps->invb.count))
 
 419     struct snmp_obj_id oid;
 
 421     if (msg_ps->vb_idx == 0)
 
 423       msg_ps->vb_ptr = msg_ps->invb.head;
 
 427       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
 
 429     if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
 
 431       if (msg_ps->vb_ptr->ident_len > 3)
 
 433         /* can offset ident_len and ident */
 
 434         mn = snmp_expand_tree((struct mib_node*)&internet,
 
 435                               msg_ps->vb_ptr->ident_len - 4,
 
 436                               msg_ps->vb_ptr->ident + 4, &oid);
 
 440         /* can't offset ident_len -4, ident + 4 */
 
 441         mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
 
 450       if (mn->node_type == MIB_NODE_EX)
 
 452         /* external object */
 
 453         struct mib_external_node *en = (struct mib_external_node*)mn;
 
 455         msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
 
 456         /* save en && args in msg_ps!! */
 
 457         msg_ps->ext_mib_node = en;
 
 458         msg_ps->ext_oid = oid;
 
 460         en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
 
 464         /* internal object */
 
 465         struct obj_def object_def;
 
 466         struct snmp_varbind *vb;
 
 468         msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
 
 469         mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
 
 471         vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);
 
 474           msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
 
 475           mn->get_value(&object_def, object_def.v_len, vb->value);
 
 476           snmp_varbind_tail_add(&msg_ps->outvb, vb);
 
 477           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 482           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
 
 483           snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
 
 489       /* mn == NULL, noSuchName */
 
 490       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 493   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
 
 494       (msg_ps->vb_idx == msg_ps->invb.count))
 
 496     snmp_ok_response(msg_ps);
 
 501  * Service an internal or external event for SNMP SET.
 
 503  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
 
 504  * @param msg_ps points to the assosicated message process state
 
 507 snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
 
 509   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
 
 511   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
 
 513     struct mib_external_node *en;
 
 514     struct snmp_name_ptr np;
 
 516     /* get_object_def() answer*/
 
 517     en = msg_ps->ext_mib_node;
 
 518     np = msg_ps->ext_name_ptr;
 
 520     /* translate answer into a known lifeform */
 
 521     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
 
 522     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
 
 524       msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
 
 525       en->set_test_q(request_id, &msg_ps->ext_object_def);
 
 529       en->get_object_def_pc(request_id, np.ident_len, np.ident);
 
 530       /* search failed, object id points to unknown object (nosuchname) */
 
 531       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 534   else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
 
 536     struct mib_external_node *en;
 
 538     /* set_test() answer*/
 
 539     en = msg_ps->ext_mib_node;
 
 541     if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
 
 543        if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
 
 544            (en->set_test_a(request_id,&msg_ps->ext_object_def,
 
 545                            msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
 
 547         msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 552         en->set_test_pc(request_id,&msg_ps->ext_object_def);
 
 554         snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
 
 559       en->set_test_pc(request_id,&msg_ps->ext_object_def);
 
 560       /* object not available for set */
 
 561       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 564   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
 
 566     struct mib_external_node *en;
 
 567     struct snmp_name_ptr np;
 
 569     /* get_object_def() answer*/
 
 570     en = msg_ps->ext_mib_node;
 
 571     np = msg_ps->ext_name_ptr;
 
 573     /* translate answer into a known lifeform */
 
 574     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
 
 575     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
 
 577       msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
 
 578       en->set_value_q(request_id, &msg_ps->ext_object_def,
 
 579                       msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
 
 583       en->get_object_def_pc(request_id, np.ident_len, np.ident);
 
 584       /* set_value failed, object has disappeared for some odd reason?? */
 
 585       snmp_error_response(msg_ps,SNMP_ES_GENERROR);
 
 588   else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
 
 590     struct mib_external_node *en;
 
 592     /** set_value_a() @todo: use reply value?? */
 
 593     en = msg_ps->ext_mib_node;
 
 594     en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
 
 596     /** @todo use set_value_pc() if toobig */
 
 597     msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
 
 601   /* test all values before setting */
 
 602   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
 
 603          (msg_ps->vb_idx < msg_ps->invb.count))
 
 606     struct snmp_name_ptr np;
 
 608     if (msg_ps->vb_idx == 0)
 
 610       msg_ps->vb_ptr = msg_ps->invb.head;
 
 614       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
 
 616     /** test object identifier for .iso.org.dod.internet prefix */
 
 617     if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
 
 619       mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
 
 620                              msg_ps->vb_ptr->ident + 4, &np);
 
 623         if (mn->node_type == MIB_NODE_EX)
 
 625           /* external object */
 
 626           struct mib_external_node *en = (struct mib_external_node*)mn;
 
 628           msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
 
 629           /* save en && args in msg_ps!! */
 
 630           msg_ps->ext_mib_node = en;
 
 631           msg_ps->ext_name_ptr = np;
 
 633           en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
 
 637           /* internal object */
 
 638           struct obj_def object_def;
 
 640           msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
 
 641           mn->get_object_def(np.ident_len, np.ident, &object_def);
 
 642           if (object_def.instance != MIB_OBJECT_NONE)
 
 648             /* search failed, object id points to unknown object (nosuchname) */
 
 653             msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
 
 655             if (object_def.access == MIB_OBJECT_READ_WRITE)
 
 657               if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
 
 658                   (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
 
 660                 msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 666                 snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
 
 671               /* object not available for set */
 
 672               snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 684       /* mn == NULL, noSuchName */
 
 685       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
 
 689   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
 
 690       (msg_ps->vb_idx == msg_ps->invb.count))
 
 693     msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
 
 696   /* set all values "atomically" (be as "atomic" as possible) */
 
 697   while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
 
 698          (msg_ps->vb_idx < msg_ps->invb.count))
 
 701     struct snmp_name_ptr np;
 
 703     if (msg_ps->vb_idx == 0)
 
 705       msg_ps->vb_ptr = msg_ps->invb.head;
 
 709       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
 
 711     /* skip iso prefix test, was done previously while settesting() */
 
 712     mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
 
 713                            msg_ps->vb_ptr->ident + 4, &np);
 
 714     /* check if object is still available
 
 715        (e.g. external hot-plug thingy present?) */
 
 718       if (mn->node_type == MIB_NODE_EX)
 
 720         /* external object */
 
 721         struct mib_external_node *en = (struct mib_external_node*)mn;
 
 723         msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
 
 724         /* save en && args in msg_ps!! */
 
 725         msg_ps->ext_mib_node = en;
 
 726         msg_ps->ext_name_ptr = np;
 
 728         en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
 
 732         /* internal object */
 
 733         struct obj_def object_def;
 
 735         msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
 
 736         mn->get_object_def(np.ident_len, np.ident, &object_def);
 
 737         msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
 
 738         mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
 
 743   if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
 
 744       (msg_ps->vb_idx == msg_ps->invb.count))
 
 746     /* simply echo the input if we can set it
 
 747        @todo do we need to return the actual value?
 
 748        e.g. if value is silently modified or behaves sticky? */
 
 749     msg_ps->outvb = msg_ps->invb;
 
 750     msg_ps->invb.head = NULL;
 
 751     msg_ps->invb.tail = NULL;
 
 752     msg_ps->invb.count = 0;
 
 753     snmp_ok_response(msg_ps);
 
 759  * Handle one internal or external event.
 
 760  * Called for one async event. (recv external/private answer)
 
 762  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
 
 765 snmp_msg_event(u8_t request_id)
 
 767   struct snmp_msg_pstat *msg_ps;
 
 769   if (request_id < SNMP_CONCURRENT_REQUESTS)
 
 771     msg_ps = &msg_input_list[request_id];
 
 772     if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
 
 774       snmp_msg_getnext_event(request_id, msg_ps);
 
 776     else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
 
 778       snmp_msg_get_event(request_id, msg_ps);
 
 780     else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
 
 782       snmp_msg_set_event(request_id, msg_ps);
 
 788 /* lwIP UDP receive callback function */
 
 790 snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
 
 792   struct udp_hdr *udphdr;
 
 794   /* suppress unused argument warning */
 
 795   LWIP_UNUSED_ARG(arg);
 
 796   /* peek in the UDP header (goto IP payload) */
 
 797   if(pbuf_header(p, UDP_HLEN)){
 
 798     LWIP_ASSERT("Can't move to UDP header", 0);
 
 804   /* check if datagram is really directed at us (including broadcast requests) */
 
 805   if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
 
 807     struct snmp_msg_pstat *msg_ps;
 
 810     /* traverse input message process list, look for SNMP_MSG_EMPTY */
 
 811     msg_ps = &msg_input_list[0];
 
 813     while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
 
 818     if (req_idx != SNMP_CONCURRENT_REQUESTS)
 
 823       u16_t varbind_ofs = 0;
 
 825       /* accepting request */
 
 826       snmp_inc_snmpinpkts();
 
 827       /* record used 'protocol control block' */
 
 829       /* source address (network order) */
 
 831       /* source port (host order (lwIP oddity)) */
 
 833       /* read UDP payload length from UDP header */
 
 834       payload_len = ntohs(udphdr->len) - UDP_HLEN;
 
 836       /* adjust to UDP payload */
 
 837       payload_ofs = UDP_HLEN;
 
 839       /* check total length, version, community, pdu type */
 
 840       err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
 
 841       if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
 
 842            (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
 
 843            (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
 
 844           ((msg_ps->error_status == SNMP_ES_NOERROR) &&
 
 845            (msg_ps->error_index == 0)) )
 
 847         /* Only accept requests and requests without error (be robust) */
 
 852         /* Reject response and trap headers or error requests as input! */
 
 855       if (err_ret == ERR_OK)
 
 857         LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
 
 859         /* Builds a list of variable bindings. Copy the varbinds from the pbuf
 
 860           chain to glue them when these are divided over two or more pbuf's. */
 
 861         err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
 
 862         if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
 
 864           /* we've decoded the incoming message, release input msg now */
 
 867           msg_ps->error_status = SNMP_ES_NOERROR;
 
 868           msg_ps->error_index = 0;
 
 869           /* find object for each variable binding */
 
 870           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
 
 871           /* first variable binding from list to inspect */
 
 874           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
 
 876           /* handle input event and as much objects as possible in one go */
 
 877           snmp_msg_event(req_idx);
 
 881           /* varbind-list decode failed, or varbind list empty.
 
 882              drop request silently, do not return error!
 
 883              (errors are only returned for a specific varbind failure) */
 
 885           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
 
 890         /* header check failed
 
 891            drop request silently, do not return error! */
 
 893         LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
 
 898       /* exceeding number of concurrent requests */
 
 904     /* datagram not for us */
 
 910  * Checks and decodes incoming SNMP message header, logs header errors.
 
 912  * @param p points to pbuf chain of SNMP message (UDP payload)
 
 913  * @param ofs points to first octet of SNMP message
 
 914  * @param pdu_len the length of the UDP payload
 
 915  * @param ofs_ret returns the ofset of the variable bindings
 
 916  * @param m_stat points to the current message request state return
 
 918  * - ERR_OK SNMP header is sane and accepted
 
 919  * - ERR_ARG SNMP header is either malformed or rejected
 
 922 snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
 
 931   snmp_asn1_dec_type(p, ofs, &type);
 
 932   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
 933   if ((derr != ERR_OK) ||
 
 934       (pdu_len != (1 + len_octets + len)) ||
 
 935       (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
 
 937     snmp_inc_snmpinasnparseerrs();
 
 940   ofs += (1 + len_octets);
 
 941   snmp_asn1_dec_type(p, ofs, &type);
 
 942   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
 943   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
 
 945     /* can't decode or no integer (version) */
 
 946     snmp_inc_snmpinasnparseerrs();
 
 949   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
 
 953     snmp_inc_snmpinasnparseerrs();
 
 959     snmp_inc_snmpinbadversions();
 
 962   ofs += (1 + len_octets + len);
 
 963   snmp_asn1_dec_type(p, ofs, &type);
 
 964   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
 965   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
 
 967     /* can't decode or no octet string (community) */
 
 968     snmp_inc_snmpinasnparseerrs();
 
 971   derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
 
 974     snmp_inc_snmpinasnparseerrs();
 
 977   /* add zero terminator */
 
 978   len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
 
 979   m_stat->community[len] = 0;
 
 980   m_stat->com_strlen = len;
 
 981   if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
 
 983     /** @todo: move this if we need to check more names */
 
 984     snmp_inc_snmpinbadcommunitynames();
 
 985     snmp_authfail_trap();
 
 988   ofs += (1 + len_octets + len);
 
 989   snmp_asn1_dec_type(p, ofs, &type);
 
 990   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
 993     snmp_inc_snmpinasnparseerrs();
 
 998     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
 
1000       snmp_inc_snmpingetrequests();
 
1003     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
 
1004       /* GetNextRequest PDU */
 
1005       snmp_inc_snmpingetnexts();
 
1008     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
 
1009       /* GetResponse PDU */
 
1010       snmp_inc_snmpingetresponses();
 
1013     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
 
1014       /* SetRequest PDU */
 
1015       snmp_inc_snmpinsetrequests();
 
1018     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
 
1020       snmp_inc_snmpintraps();
 
1024       snmp_inc_snmpinasnparseerrs();
 
1030     /* unsupported input PDU for this agent (no parse error) */
 
1033   m_stat->rt = type & 0x1F;
 
1034   ofs += (1 + len_octets);
 
1035   if (len != (pdu_len - (ofs - ofs_base)))
 
1037     /* decoded PDU length does not equal actual payload length */
 
1038     snmp_inc_snmpinasnparseerrs();
 
1041   snmp_asn1_dec_type(p, ofs, &type);
 
1042   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
1043   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
 
1045     /* can't decode or no integer (request ID) */
 
1046     snmp_inc_snmpinasnparseerrs();
 
1049   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
 
1053     snmp_inc_snmpinasnparseerrs();
 
1056   ofs += (1 + len_octets + len);
 
1057   snmp_asn1_dec_type(p, ofs, &type);
 
1058   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
1059   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
 
1061     /* can't decode or no integer (error-status) */
 
1062     snmp_inc_snmpinasnparseerrs();
 
1065   /* must be noError (0) for incoming requests.
 
1066      log errors for mib-2 completeness and for debug purposes */
 
1067   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
 
1071     snmp_inc_snmpinasnparseerrs();
 
1074   switch (m_stat->error_status)
 
1076     case SNMP_ES_TOOBIG:
 
1077       snmp_inc_snmpintoobigs();
 
1079     case SNMP_ES_NOSUCHNAME:
 
1080       snmp_inc_snmpinnosuchnames();
 
1082     case SNMP_ES_BADVALUE:
 
1083       snmp_inc_snmpinbadvalues();
 
1085     case SNMP_ES_READONLY:
 
1086       snmp_inc_snmpinreadonlys();
 
1088     case SNMP_ES_GENERROR:
 
1089       snmp_inc_snmpingenerrs();
 
1092   ofs += (1 + len_octets + len);
 
1093   snmp_asn1_dec_type(p, ofs, &type);
 
1094   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
1095   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
 
1097     /* can't decode or no integer (error-index) */
 
1098     snmp_inc_snmpinasnparseerrs();
 
1101   /* must be 0 for incoming requests.
 
1102      decode anyway to catch bad integers (and dirty tricks) */
 
1103   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
 
1107     snmp_inc_snmpinasnparseerrs();
 
1110   ofs += (1 + len_octets + len);
 
1116 snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
 
1123   /* variable binding list */
 
1124   snmp_asn1_dec_type(p, ofs, &type);
 
1125   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
 
1126   if ((derr != ERR_OK) ||
 
1127       (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
 
1129     snmp_inc_snmpinasnparseerrs();
 
1132   ofs += (1 + len_octets);
 
1134   /* start with empty list */
 
1135   m_stat->invb.count = 0;
 
1136   m_stat->invb.head = NULL;
 
1137   m_stat->invb.tail = NULL;
 
1141     struct snmp_obj_id oid, oid_value;
 
1142     struct snmp_varbind *vb;
 
1144     snmp_asn1_dec_type(p, ofs, &type);
 
1145     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
1146     if ((derr != ERR_OK) ||
 
1147         (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
 
1148         (len <= 0) || (len > vb_len))
 
1150       snmp_inc_snmpinasnparseerrs();
 
1151       /* free varbinds (if available) */
 
1152       snmp_varbind_list_free(&m_stat->invb);
 
1155     ofs += (1 + len_octets);
 
1156     vb_len -= (1 + len_octets);
 
1158     snmp_asn1_dec_type(p, ofs, &type);
 
1159     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
1160     if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
 
1162       /* can't decode object name length */
 
1163       snmp_inc_snmpinasnparseerrs();
 
1164       /* free varbinds (if available) */
 
1165       snmp_varbind_list_free(&m_stat->invb);
 
1168     derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
 
1171       /* can't decode object name */
 
1172       snmp_inc_snmpinasnparseerrs();
 
1173       /* free varbinds (if available) */
 
1174       snmp_varbind_list_free(&m_stat->invb);
 
1177     ofs += (1 + len_octets + len);
 
1178     vb_len -= (1 + len_octets + len);
 
1180     snmp_asn1_dec_type(p, ofs, &type);
 
1181     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
 
1184       /* can't decode object value length */
 
1185       snmp_inc_snmpinasnparseerrs();
 
1186       /* free varbinds (if available) */
 
1187       snmp_varbind_list_free(&m_stat->invb);
 
1193       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
 
1194         vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
 
1197           s32_t *vptr = vb->value;
 
1199           derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
 
1200           snmp_varbind_tail_add(&m_stat->invb, vb);
 
1207       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
 
1208       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
 
1209       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
 
1210         vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
 
1213           u32_t *vptr = vb->value;
 
1215           derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
 
1216           snmp_varbind_tail_add(&m_stat->invb, vb);
 
1223       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
 
1224       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
 
1225         vb = snmp_varbind_alloc(&oid, type, len);
 
1228           derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
 
1229           snmp_varbind_tail_add(&m_stat->invb, vb);
 
1236       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
 
1237         vb = snmp_varbind_alloc(&oid, type, 0);
 
1240           snmp_varbind_tail_add(&m_stat->invb, vb);
 
1248       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
 
1249         derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
 
1252           vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
 
1255             u8_t i = oid_value.len;
 
1256             s32_t *vptr = vb->value;
 
1261               vptr[i] = oid_value.id[i];
 
1263             snmp_varbind_tail_add(&m_stat->invb, vb);
 
1272       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
 
1275           /* must be exactly 4 octets! */
 
1276           vb = snmp_varbind_alloc(&oid, type, 4);
 
1279             derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
 
1280             snmp_varbind_tail_add(&m_stat->invb, vb);
 
1298       snmp_inc_snmpinasnparseerrs();
 
1299       /* free varbinds (if available) */
 
1300       snmp_varbind_list_free(&m_stat->invb);
 
1303     ofs += (1 + len_octets + len);
 
1304     vb_len -= (1 + len_octets + len);
 
1307   if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
 
1309     snmp_add_snmpintotalsetvars(m_stat->invb.count);
 
1313     snmp_add_snmpintotalreqvars(m_stat->invb.count);
 
1320 struct snmp_varbind*
 
1321 snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
 
1323   struct snmp_varbind *vb;
 
1325   vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
 
1326   LWIP_ASSERT("vb != NULL",vb != NULL);
 
1337       /* allocate array of s32_t for our object identifier */
 
1338       vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
 
1339       LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
 
1340       if (vb->ident == NULL)
 
1348         vb->ident[i] = oid->id[i];
 
1353       /* i == 0, pass zero length object identifier */
 
1356     vb->value_type = type;
 
1357     vb->value_len = len;
 
1360       /* allocate raw bytes for our object value */
 
1361       vb->value = mem_malloc(len);
 
1362       LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
 
1363       if (vb->value == NULL)
 
1365         if (vb->ident != NULL)
 
1367           mem_free(vb->ident);
 
1375       /* ASN1_NUL type, or zero length ASN1_OC_STR */
 
1383 snmp_varbind_free(struct snmp_varbind *vb)
 
1385   if (vb->value != NULL )
 
1387     mem_free(vb->value);
 
1389   if (vb->ident != NULL )
 
1391     mem_free(vb->ident);
 
1397 snmp_varbind_list_free(struct snmp_varbind_root *root)
 
1399   struct snmp_varbind *vb, *prev;
 
1402   while ( vb != NULL )
 
1405     snmp_varbind_free(vb);
 
1414 snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
 
1416   if (root->count == 0)
 
1418     /* add first varbind to list */
 
1424     /* add nth varbind to list tail */
 
1425     root->tail->next = vb;
 
1426     vb->prev = root->tail;
 
1432 struct snmp_varbind*
 
1433 snmp_varbind_tail_remove(struct snmp_varbind_root *root)
 
1435   struct snmp_varbind* vb;
 
1437   if (root->count > 0)
 
1439     /* remove tail varbind */
 
1441     root->tail = vb->prev;
 
1442     vb->prev->next = NULL;
 
1447     /* nothing to remove */
 
1453 #endif /* LWIP_SNMP */