Ethernet for Nucleo and Disco board STM32F746 works with gcc and arm. IAC is untested

Dependencies:   mbed-rtos

Dependents:   IMU_ethernet

Fork of F7_Ethernet by Dieter Graef

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers msg_in.c Source File

msg_in.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * SNMP input message processing (RFC1157).
00004  */
00005 
00006 /*
00007  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without modification,
00011  * are permitted provided that the following conditions are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright notice,
00014  *    this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright notice,
00016  *    this list of conditions and the following disclaimer in the documentation
00017  *    and/or other materials provided with the distribution.
00018  * 3. The name of the author may not be used to endorse or promote products
00019  *    derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00023  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00024  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00026  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00029  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00030  * OF SUCH DAMAGE.
00031  *
00032  * Author: Christiaan Simons <christiaan.simons@axon.tv>
00033  */
00034 
00035 #include "lwip/opt.h"
00036 
00037 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
00038 
00039 #include "lwip/snmp.h"
00040 #include "lwip/snmp_asn1.h"
00041 #include "lwip/snmp_msg.h"
00042 #include "lwip/snmp_structs.h"
00043 #include "lwip/ip_addr.h"
00044 #include "lwip/memp.h"
00045 #include "lwip/udp.h"
00046 #include "lwip/stats.h"
00047 
00048 #include <string.h>
00049 
00050 /* public (non-static) constants */
00051 /** SNMP v1 == 0 */
00052 const s32_t snmp_version = 0;
00053 /** default SNMP community string */
00054 const char snmp_publiccommunity[7] = "public";
00055 
00056 /* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
00057 struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
00058 /* UDP Protocol Control Block */
00059 struct udp_pcb *snmp1_pcb;
00060 
00061 static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
00062 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);
00063 static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
00064 
00065 
00066 /**
00067  * Starts SNMP Agent.
00068  * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
00069  */
00070 void
00071 snmp_init(void)
00072 {
00073   struct snmp_msg_pstat *msg_ps;
00074   u8_t i;
00075 
00076   snmp1_pcb = udp_new();
00077   if (snmp1_pcb != NULL)
00078   {
00079     udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
00080     udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
00081   }
00082   msg_ps = &msg_input_list[0];
00083   for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)
00084   {
00085     msg_ps->state = SNMP_MSG_EMPTY;
00086     msg_ps->error_index = 0;
00087     msg_ps->error_status = SNMP_ES_NOERROR;
00088     msg_ps++;
00089   }
00090   trap_msg.pcb = snmp1_pcb;
00091 
00092 #ifdef SNMP_PRIVATE_MIB_INIT
00093   /* If defined, this must be a function-like define to initialize the
00094    * private MIB after the stack has been initialized.
00095    * The private MIB can also be initialized in tcpip_callback (or after
00096    * the stack is initialized), this define is only for convenience. */
00097   SNMP_PRIVATE_MIB_INIT();
00098 #endif /* SNMP_PRIVATE_MIB_INIT */
00099 
00100   /* The coldstart trap will only be output
00101      if our outgoing interface is up & configured  */
00102   snmp_coldstart_trap();
00103 }
00104 
00105 static void
00106 snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
00107 {
00108   /* move names back from outvb to invb */
00109   int v;
00110   struct snmp_varbind *vbi = msg_ps->invb.head;
00111   struct snmp_varbind *vbo = msg_ps->outvb.head;
00112   for (v=0; v<msg_ps->vb_idx; v++) {
00113     vbi->ident_len = vbo->ident_len;
00114     vbo->ident_len = 0;
00115     vbi->ident = vbo->ident;
00116     vbo->ident = NULL;
00117     vbi = vbi->next;
00118     vbo = vbo->next;
00119   }
00120   /* free outvb */
00121   snmp_varbind_list_free(&msg_ps->outvb);
00122   /* we send invb back */
00123   msg_ps->outvb = msg_ps->invb;
00124   msg_ps->invb.head = NULL;
00125   msg_ps->invb.tail = NULL;
00126   msg_ps->invb.count = 0;
00127   msg_ps->error_status = error;
00128   /* error index must be 0 for error too big */
00129   msg_ps->error_index = (error != SNMP_ES_TOOBIG) ? (1 + msg_ps->vb_idx) : 0;
00130   snmp_send_response(msg_ps);
00131   snmp_varbind_list_free(&msg_ps->outvb);
00132   msg_ps->state = SNMP_MSG_EMPTY;
00133 }
00134 
00135 static void
00136 snmp_ok_response(struct snmp_msg_pstat *msg_ps)
00137 {
00138   err_t err_ret;
00139 
00140   err_ret = snmp_send_response(msg_ps);
00141   if (err_ret == ERR_MEM)
00142   {
00143     /* serious memory problem, can't return tooBig */
00144   }
00145   else
00146   {
00147     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
00148   }
00149   /* free varbinds (if available) */
00150   snmp_varbind_list_free(&msg_ps->invb);
00151   snmp_varbind_list_free(&msg_ps->outvb);
00152   msg_ps->state = SNMP_MSG_EMPTY;
00153 }
00154 
00155 /**
00156  * Service an internal or external event for SNMP GET.
00157  *
00158  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
00159  * @param msg_ps points to the assosicated message process state
00160  */
00161 static void
00162 snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
00163 {
00164   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
00165 
00166   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
00167   {
00168     struct mib_external_node *en;
00169     struct snmp_name_ptr np;
00170 
00171     /* get_object_def() answer*/
00172     en = msg_ps->ext_mib_node;
00173     np = msg_ps->ext_name_ptr;
00174 
00175     /* translate answer into a known lifeform */
00176     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
00177     if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) &&
00178         (msg_ps->ext_object_def.access & MIB_ACCESS_READ))
00179     {
00180       msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
00181       en->get_value_q(request_id, &msg_ps->ext_object_def);
00182     }
00183     else
00184     {
00185       en->get_object_def_pc(request_id, np.ident_len, np.ident);
00186       /* search failed, object id points to unknown object (nosuchname) */
00187       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00188     }
00189   }
00190   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
00191   {
00192     struct mib_external_node *en;
00193     struct snmp_varbind *vb;
00194 
00195     /* get_value() answer */
00196     en = msg_ps->ext_mib_node;
00197 
00198     /* allocate output varbind */
00199     vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
00200     if (vb != NULL)
00201     {
00202       vb->next = NULL;
00203       vb->prev = NULL;
00204 
00205       /* move name from invb to outvb */
00206       vb->ident = msg_ps->vb_ptr->ident;
00207       vb->ident_len = msg_ps->vb_ptr->ident_len;
00208       /* ensure this memory is refereced once only */
00209       msg_ps->vb_ptr->ident = NULL;
00210       msg_ps->vb_ptr->ident_len = 0;
00211 
00212       vb->value_type = msg_ps->ext_object_def.asn_type;
00213       LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
00214       vb->value_len = (u8_t)msg_ps->ext_object_def.v_len;
00215       if (vb->value_len > 0)
00216       {
00217         LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
00218         vb->value = memp_malloc(MEMP_SNMP_VALUE);
00219         if (vb->value != NULL)
00220         {
00221           en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
00222           snmp_varbind_tail_add(&msg_ps->outvb, vb);
00223           /* search again (if vb_idx < msg_ps->invb.count) */
00224           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00225           msg_ps->vb_idx += 1;
00226         }
00227         else
00228         {
00229           en->get_value_pc(request_id, &msg_ps->ext_object_def);
00230           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
00231           msg_ps->vb_ptr->ident = vb->ident;
00232           msg_ps->vb_ptr->ident_len = vb->ident_len;
00233           memp_free(MEMP_SNMP_VARBIND, vb);
00234           snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
00235         }
00236       }
00237       else
00238       {
00239         /* vb->value_len == 0, empty value (e.g. empty string) */
00240         en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
00241         vb->value = NULL;
00242         snmp_varbind_tail_add(&msg_ps->outvb, vb);
00243         /* search again (if vb_idx < msg_ps->invb.count) */
00244         msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00245         msg_ps->vb_idx += 1;
00246       }
00247     }
00248     else
00249     {
00250       en->get_value_pc(request_id, &msg_ps->ext_object_def);
00251       LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
00252       snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
00253     }
00254   }
00255 
00256   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
00257          (msg_ps->vb_idx < msg_ps->invb.count))
00258   {
00259     struct mib_node *mn;
00260     struct snmp_name_ptr np;
00261 
00262     if (msg_ps->vb_idx == 0)
00263     {
00264       msg_ps->vb_ptr = msg_ps->invb.head;
00265     }
00266     else
00267     {
00268       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
00269     }
00270     /** test object identifier for .iso.org.dod.internet prefix */
00271     if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
00272     {
00273       mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
00274                              msg_ps->vb_ptr->ident + 4, &np);
00275       if (mn != NULL)
00276       {
00277         if (mn->node_type == MIB_NODE_EX)
00278         {
00279           /* external object */
00280           struct mib_external_node *en = (struct mib_external_node*)mn;
00281 
00282           msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
00283           /* save en && args in msg_ps!! */
00284           msg_ps->ext_mib_node = en;
00285           msg_ps->ext_name_ptr = np;
00286 
00287           en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
00288         }
00289         else
00290         {
00291           /* internal object */
00292           struct obj_def object_def;
00293 
00294           msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
00295           mn->get_object_def(np.ident_len, np.ident, &object_def);
00296           if ((object_def.instance != MIB_OBJECT_NONE) &&
00297             (object_def.access & MIB_ACCESS_READ))
00298           {
00299             mn = mn;
00300           }
00301           else
00302           {
00303             /* search failed, object id points to unknown object (nosuchname) */
00304             mn =  NULL;
00305           }
00306           if (mn != NULL)
00307           {
00308             struct snmp_varbind *vb;
00309 
00310             msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
00311             /* allocate output varbind */
00312             vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
00313             if (vb != NULL)
00314             {
00315               vb->next = NULL;
00316               vb->prev = NULL;
00317 
00318               /* move name from invb to outvb */
00319               vb->ident = msg_ps->vb_ptr->ident;
00320               vb->ident_len = msg_ps->vb_ptr->ident_len;
00321               /* ensure this memory is refereced once only */
00322               msg_ps->vb_ptr->ident = NULL;
00323               msg_ps->vb_ptr->ident_len = 0;
00324 
00325               vb->value_type = object_def.asn_type;
00326               LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
00327               vb->value_len = (u8_t)object_def.v_len;
00328               if (vb->value_len > 0)
00329               {
00330                 LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
00331                   vb->value_len <= SNMP_MAX_VALUE_SIZE);
00332                 vb->value = memp_malloc(MEMP_SNMP_VALUE);
00333                 if (vb->value != NULL)
00334                 {
00335                   mn->get_value(&object_def, vb->value_len, vb->value);
00336                   snmp_varbind_tail_add(&msg_ps->outvb, vb);
00337                   msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00338                   msg_ps->vb_idx += 1;
00339                 }
00340                 else
00341                 {
00342                   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
00343                   msg_ps->vb_ptr->ident = vb->ident;
00344                   msg_ps->vb_ptr->ident_len = vb->ident_len;
00345                   vb->ident = NULL;
00346                   vb->ident_len = 0;
00347                   memp_free(MEMP_SNMP_VARBIND, vb);
00348                   snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
00349                 }
00350               }
00351               else
00352               {
00353                 /* vb->value_len == 0, empty value (e.g. empty string) */
00354                 vb->value = NULL;
00355                 snmp_varbind_tail_add(&msg_ps->outvb, vb);
00356                 msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00357                 msg_ps->vb_idx += 1;
00358               }
00359             }
00360             else
00361             {
00362               LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
00363               snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
00364             }
00365           }
00366         }
00367       }
00368     }
00369     else
00370     {
00371       mn = NULL;
00372     }
00373     if (mn == NULL)
00374     {
00375       /* mn == NULL, noSuchName */
00376       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00377     }
00378   }
00379   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
00380       (msg_ps->vb_idx == msg_ps->invb.count))
00381   {
00382     snmp_ok_response(msg_ps);
00383   }
00384 }
00385 
00386 /**
00387  * Service an internal or external event for SNMP GETNEXT.
00388  *
00389  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
00390  * @param msg_ps points to the assosicated message process state
00391  */
00392 static void
00393 snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
00394 {
00395   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
00396 
00397   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
00398   {
00399     struct mib_external_node *en;
00400 
00401     /* get_object_def() answer*/
00402     en = msg_ps->ext_mib_node;
00403 
00404     /* translate answer into a known lifeform */
00405     en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
00406     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
00407     {
00408       msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
00409       en->get_value_q(request_id, &msg_ps->ext_object_def);
00410     }
00411     else
00412     {
00413       en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
00414       /* search failed, object id points to unknown object (nosuchname) */
00415       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00416     }
00417   }
00418   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
00419   {
00420     struct mib_external_node *en;
00421     struct snmp_varbind *vb;
00422 
00423     /* get_value() answer */
00424     en = msg_ps->ext_mib_node;
00425 
00426     LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
00427     vb = snmp_varbind_alloc(&msg_ps->ext_oid,
00428                             msg_ps->ext_object_def.asn_type,
00429                             (u8_t)msg_ps->ext_object_def.v_len);
00430     if (vb != NULL)
00431     {
00432       en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
00433       snmp_varbind_tail_add(&msg_ps->outvb, vb);
00434       msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00435       msg_ps->vb_idx += 1;
00436     }
00437     else
00438     {
00439       en->get_value_pc(request_id, &msg_ps->ext_object_def);
00440       LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
00441       snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
00442     }
00443   }
00444 
00445   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
00446          (msg_ps->vb_idx < msg_ps->invb.count))
00447   {
00448     struct mib_node *mn;
00449     struct snmp_obj_id oid;
00450 
00451     if (msg_ps->vb_idx == 0)
00452     {
00453       msg_ps->vb_ptr = msg_ps->invb.head;
00454     }
00455     else
00456     {
00457       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
00458     }
00459     if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
00460     {
00461       if (msg_ps->vb_ptr->ident_len > 3)
00462       {
00463         /* can offset ident_len and ident */
00464         mn = snmp_expand_tree((struct mib_node*)&internet,
00465                               msg_ps->vb_ptr->ident_len - 4,
00466                               msg_ps->vb_ptr->ident + 4, &oid);
00467       }
00468       else
00469       {
00470         /* can't offset ident_len -4, ident + 4 */
00471         mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
00472       }
00473     }
00474     else
00475     {
00476       mn = NULL;
00477     }
00478     if (mn != NULL)
00479     {
00480       if (mn->node_type == MIB_NODE_EX)
00481       {
00482         /* external object */
00483         struct mib_external_node *en = (struct mib_external_node*)mn;
00484 
00485         msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
00486         /* save en && args in msg_ps!! */
00487         msg_ps->ext_mib_node = en;
00488         msg_ps->ext_oid = oid;
00489 
00490         en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
00491       }
00492       else
00493       {
00494         /* internal object */
00495         struct obj_def object_def;
00496         struct snmp_varbind *vb;
00497 
00498         msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
00499         mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
00500 
00501         LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
00502         vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len);
00503         if (vb != NULL)
00504         {
00505           msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
00506           mn->get_value(&object_def, object_def.v_len, vb->value);
00507           snmp_varbind_tail_add(&msg_ps->outvb, vb);
00508           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00509           msg_ps->vb_idx += 1;
00510         }
00511         else
00512         {
00513           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
00514           snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
00515         }
00516       }
00517     }
00518     if (mn == NULL)
00519     {
00520       /* mn == NULL, noSuchName */
00521       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00522     }
00523   }
00524   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
00525       (msg_ps->vb_idx == msg_ps->invb.count))
00526   {
00527     snmp_ok_response(msg_ps);
00528   }
00529 }
00530 
00531 /**
00532  * Service an internal or external event for SNMP SET.
00533  *
00534  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
00535  * @param msg_ps points to the assosicated message process state
00536  */
00537 static void
00538 snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
00539 {
00540   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
00541 
00542   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
00543   {
00544     struct mib_external_node *en;
00545     struct snmp_name_ptr np;
00546 
00547     /* get_object_def() answer*/
00548     en = msg_ps->ext_mib_node;
00549     np = msg_ps->ext_name_ptr;
00550 
00551     /* translate answer into a known lifeform */
00552     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
00553     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
00554     {
00555       msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
00556       en->set_test_q(request_id, &msg_ps->ext_object_def);
00557     }
00558     else
00559     {
00560       en->get_object_def_pc(request_id, np.ident_len, np.ident);
00561       /* search failed, object id points to unknown object (nosuchname) */
00562       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00563     }
00564   }
00565   else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
00566   {
00567     struct mib_external_node *en;
00568 
00569     /* set_test() answer*/
00570     en = msg_ps->ext_mib_node;
00571 
00572     if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE)
00573     {
00574        if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
00575            (en->set_test_a(request_id,&msg_ps->ext_object_def,
00576                            msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
00577       {
00578         msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00579         msg_ps->vb_idx += 1;
00580       }
00581       else
00582       {
00583         en->set_test_pc(request_id,&msg_ps->ext_object_def);
00584         /* bad value */
00585         snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
00586       }
00587     }
00588     else
00589     {
00590       en->set_test_pc(request_id,&msg_ps->ext_object_def);
00591       /* object not available for set */
00592       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00593     }
00594   }
00595   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
00596   {
00597     struct mib_external_node *en;
00598     struct snmp_name_ptr np;
00599 
00600     /* get_object_def() answer*/
00601     en = msg_ps->ext_mib_node;
00602     np = msg_ps->ext_name_ptr;
00603 
00604     /* translate answer into a known lifeform */
00605     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
00606     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
00607     {
00608       msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
00609       en->set_value_q(request_id, &msg_ps->ext_object_def,
00610                       msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
00611     }
00612     else
00613     {
00614       en->get_object_def_pc(request_id, np.ident_len, np.ident);
00615       /* set_value failed, object has disappeared for some odd reason?? */
00616       snmp_error_response(msg_ps,SNMP_ES_GENERROR);
00617     }
00618   }
00619   else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
00620   {
00621     struct mib_external_node *en;
00622 
00623     /** set_value_a() */
00624     en = msg_ps->ext_mib_node;
00625     en->set_value_a(request_id, &msg_ps->ext_object_def,
00626       msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
00627 
00628     /** @todo use set_value_pc() if toobig */
00629     msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
00630     msg_ps->vb_idx += 1;
00631   }
00632 
00633   /* test all values before setting */
00634   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
00635          (msg_ps->vb_idx < msg_ps->invb.count))
00636   {
00637     struct mib_node *mn;
00638     struct snmp_name_ptr np;
00639 
00640     if (msg_ps->vb_idx == 0)
00641     {
00642       msg_ps->vb_ptr = msg_ps->invb.head;
00643     }
00644     else
00645     {
00646       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
00647     }
00648     /** test object identifier for .iso.org.dod.internet prefix */
00649     if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
00650     {
00651       mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
00652                              msg_ps->vb_ptr->ident + 4, &np);
00653       if (mn != NULL)
00654       {
00655         if (mn->node_type == MIB_NODE_EX)
00656         {
00657           /* external object */
00658           struct mib_external_node *en = (struct mib_external_node*)mn;
00659 
00660           msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
00661           /* save en && args in msg_ps!! */
00662           msg_ps->ext_mib_node = en;
00663           msg_ps->ext_name_ptr = np;
00664 
00665           en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
00666         }
00667         else
00668         {
00669           /* internal object */
00670           struct obj_def object_def;
00671 
00672           msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
00673           mn->get_object_def(np.ident_len, np.ident, &object_def);
00674           if (object_def.instance != MIB_OBJECT_NONE)
00675           {
00676             mn = mn;
00677           }
00678           else
00679           {
00680             /* search failed, object id points to unknown object (nosuchname) */
00681             mn = NULL;
00682           }
00683           if (mn != NULL)
00684           {
00685             msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
00686 
00687             if (object_def.access & MIB_ACCESS_WRITE)
00688             {
00689               if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
00690                   (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
00691               {
00692                 msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00693                 msg_ps->vb_idx += 1;
00694               }
00695               else
00696               {
00697                 /* bad value */
00698                 snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
00699               }
00700             }
00701             else
00702             {
00703               /* object not available for set */
00704               snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00705             }
00706           }
00707         }
00708       }
00709     }
00710     else
00711     {
00712       mn = NULL;
00713     }
00714     if (mn == NULL)
00715     {
00716       /* mn == NULL, noSuchName */
00717       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
00718     }
00719   }
00720 
00721   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
00722       (msg_ps->vb_idx == msg_ps->invb.count))
00723   {
00724     msg_ps->vb_idx = 0;
00725     msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
00726   }
00727 
00728   /* set all values "atomically" (be as "atomic" as possible) */
00729   while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
00730          (msg_ps->vb_idx < msg_ps->invb.count))
00731   {
00732     struct mib_node *mn;
00733     struct snmp_name_ptr np;
00734 
00735     if (msg_ps->vb_idx == 0)
00736     {
00737       msg_ps->vb_ptr = msg_ps->invb.head;
00738     }
00739     else
00740     {
00741       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
00742     }
00743     /* skip iso prefix test, was done previously while settesting() */
00744     mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
00745                            msg_ps->vb_ptr->ident + 4, &np);
00746     /* check if object is still available
00747        (e.g. external hot-plug thingy present?) */
00748     if (mn != NULL)
00749     {
00750       if (mn->node_type == MIB_NODE_EX)
00751       {
00752         /* external object */
00753         struct mib_external_node *en = (struct mib_external_node*)mn;
00754 
00755         msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
00756         /* save en && args in msg_ps!! */
00757         msg_ps->ext_mib_node = en;
00758         msg_ps->ext_name_ptr = np;
00759 
00760         en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
00761       }
00762       else
00763       {
00764         /* internal object */
00765         struct obj_def object_def;
00766 
00767         msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
00768         mn->get_object_def(np.ident_len, np.ident, &object_def);
00769         msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
00770         mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
00771         msg_ps->vb_idx += 1;
00772       }
00773     }
00774   }
00775   if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
00776       (msg_ps->vb_idx == msg_ps->invb.count))
00777   {
00778     /* simply echo the input if we can set it
00779        @todo do we need to return the actual value?
00780        e.g. if value is silently modified or behaves sticky? */
00781     msg_ps->outvb = msg_ps->invb;
00782     msg_ps->invb.head = NULL;
00783     msg_ps->invb.tail = NULL;
00784     msg_ps->invb.count = 0;
00785     snmp_ok_response(msg_ps);
00786   }
00787 }
00788 
00789 
00790 /**
00791  * Handle one internal or external event.
00792  * Called for one async event. (recv external/private answer)
00793  *
00794  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
00795  */
00796 void
00797 snmp_msg_event(u8_t request_id)
00798 {
00799   struct snmp_msg_pstat *msg_ps;
00800 
00801   if (request_id < SNMP_CONCURRENT_REQUESTS)
00802   {
00803     msg_ps = &msg_input_list[request_id];
00804     if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
00805     {
00806       snmp_msg_getnext_event(request_id, msg_ps);
00807     }
00808     else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
00809     {
00810       snmp_msg_get_event(request_id, msg_ps);
00811     }
00812     else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
00813     {
00814       snmp_msg_set_event(request_id, msg_ps);
00815     }
00816   }
00817 }
00818 
00819 
00820 /* lwIP UDP receive callback function */
00821 static void
00822 snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
00823 {
00824   struct snmp_msg_pstat *msg_ps;
00825   u8_t req_idx;
00826   err_t err_ret;
00827   u16_t payload_len = p->tot_len;
00828   u16_t payload_ofs = 0;
00829   u16_t varbind_ofs = 0;
00830 
00831   /* suppress unused argument warning */
00832   LWIP_UNUSED_ARG(arg);
00833 
00834   /* traverse input message process list, look for SNMP_MSG_EMPTY */
00835   msg_ps = &msg_input_list[0];
00836   req_idx = 0;
00837   while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
00838   {
00839     req_idx++;
00840     msg_ps++;
00841   }
00842   if (req_idx == SNMP_CONCURRENT_REQUESTS)
00843   {
00844     /* exceeding number of concurrent requests */
00845     pbuf_free(p);
00846     return;
00847   }
00848 
00849   /* accepting request */
00850   snmp_inc_snmpinpkts();
00851   /* record used 'protocol control block' */
00852   msg_ps->pcb = pcb;
00853   /* source address (network order) */
00854   msg_ps->sip = *addr;
00855   /* source port (host order (lwIP oddity)) */
00856   msg_ps->sp = port;
00857 
00858   /* check total length, version, community, pdu type */
00859   err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
00860   /* Only accept requests and requests without error (be robust) */
00861   /* Reject response and trap headers or error requests as input! */
00862   if ((err_ret != ERR_OK) ||
00863       ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) &&
00864        (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) &&
00865        (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) ||
00866       ((msg_ps->error_status != SNMP_ES_NOERROR) ||
00867        (msg_ps->error_index != 0)) )
00868   {
00869     /* header check failed drop request silently, do not return error! */
00870     pbuf_free(p);
00871     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
00872     return;
00873   }
00874   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
00875 
00876   /* Builds a list of variable bindings. Copy the varbinds from the pbuf
00877     chain to glue them when these are divided over two or more pbuf's. */
00878   err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
00879   /* we've decoded the incoming message, release input msg now */
00880   pbuf_free(p);
00881   if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0))
00882   {
00883     /* varbind-list decode failed, or varbind list empty.
00884        drop request silently, do not return error!
00885        (errors are only returned for a specific varbind failure) */
00886     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
00887     return;
00888   }
00889 
00890   msg_ps->error_status = SNMP_ES_NOERROR;
00891   msg_ps->error_index = 0;
00892   /* find object for each variable binding */
00893   msg_ps->state = SNMP_MSG_SEARCH_OBJ;
00894   /* first variable binding from list to inspect */
00895   msg_ps->vb_idx = 0;
00896 
00897   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
00898 
00899   /* handle input event and as much objects as possible in one go */
00900   snmp_msg_event(req_idx);
00901 }
00902 
00903 /**
00904  * Checks and decodes incoming SNMP message header, logs header errors.
00905  *
00906  * @param p points to pbuf chain of SNMP message (UDP payload)
00907  * @param ofs points to first octet of SNMP message
00908  * @param pdu_len the length of the UDP payload
00909  * @param ofs_ret returns the ofset of the variable bindings
00910  * @param m_stat points to the current message request state return
00911  * @return
00912  * - ERR_OK SNMP header is sane and accepted
00913  * - ERR_ARG SNMP header is either malformed or rejected
00914  */
00915 static err_t
00916 snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
00917 {
00918   err_t derr;
00919   u16_t len, ofs_base;
00920   u8_t  len_octets;
00921   u8_t  type;
00922   s32_t version;
00923 
00924   ofs_base = ofs;
00925   snmp_asn1_dec_type(p, ofs, &type);
00926   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
00927   if ((derr != ERR_OK) ||
00928       (pdu_len != (1 + len_octets + len)) ||
00929       (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
00930   {
00931     snmp_inc_snmpinasnparseerrs();
00932     return ERR_ARG;
00933   }
00934   ofs += (1 + len_octets);
00935   snmp_asn1_dec_type(p, ofs, &type);
00936   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
00937   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
00938   {
00939     /* can't decode or no integer (version) */
00940     snmp_inc_snmpinasnparseerrs();
00941     return ERR_ARG;
00942   }
00943   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
00944   if (derr != ERR_OK)
00945   {
00946     /* can't decode */
00947     snmp_inc_snmpinasnparseerrs();
00948     return ERR_ARG;
00949   }
00950   if (version != 0)
00951   {
00952     /* not version 1 */
00953     snmp_inc_snmpinbadversions();
00954     return ERR_ARG;
00955   }
00956   ofs += (1 + len_octets + len);
00957   snmp_asn1_dec_type(p, ofs, &type);
00958   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
00959   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
00960   {
00961     /* can't decode or no octet string (community) */
00962     snmp_inc_snmpinasnparseerrs();
00963     return ERR_ARG;
00964   }
00965   derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
00966   if (derr != ERR_OK)
00967   {
00968     snmp_inc_snmpinasnparseerrs();
00969     return ERR_ARG;
00970   }
00971   /* add zero terminator */
00972   len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
00973   m_stat->community[len] = 0;
00974   m_stat->com_strlen = (u8_t)len;
00975   if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
00976   {
00977     /** @todo: move this if we need to check more names */
00978     snmp_inc_snmpinbadcommunitynames();
00979     snmp_authfail_trap();
00980     return ERR_ARG;
00981   }
00982   ofs += (1 + len_octets + len);
00983   snmp_asn1_dec_type(p, ofs, &type);
00984   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
00985   if (derr != ERR_OK)
00986   {
00987     snmp_inc_snmpinasnparseerrs();
00988     return ERR_ARG;
00989   }
00990   switch(type)
00991   {
00992     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
00993       /* GetRequest PDU */
00994       snmp_inc_snmpingetrequests();
00995       derr = ERR_OK;
00996       break;
00997     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
00998       /* GetNextRequest PDU */
00999       snmp_inc_snmpingetnexts();
01000       derr = ERR_OK;
01001       break;
01002     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
01003       /* GetResponse PDU */
01004       snmp_inc_snmpingetresponses();
01005       derr = ERR_ARG;
01006       break;
01007     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
01008       /* SetRequest PDU */
01009       snmp_inc_snmpinsetrequests();
01010       derr = ERR_OK;
01011       break;
01012     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
01013       /* Trap PDU */
01014       snmp_inc_snmpintraps();
01015       derr = ERR_ARG;
01016       break;
01017     default:
01018       snmp_inc_snmpinasnparseerrs();
01019       derr = ERR_ARG;
01020       break;
01021   }
01022   if (derr != ERR_OK)
01023   {
01024     /* unsupported input PDU for this agent (no parse error) */
01025     return ERR_ARG;
01026   }
01027   m_stat->rt = type & 0x1F;
01028   ofs += (1 + len_octets);
01029   if (len != (pdu_len - (ofs - ofs_base)))
01030   {
01031     /* decoded PDU length does not equal actual payload length */
01032     snmp_inc_snmpinasnparseerrs();
01033     return ERR_ARG;
01034   }
01035   snmp_asn1_dec_type(p, ofs, &type);
01036   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
01037   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
01038   {
01039     /* can't decode or no integer (request ID) */
01040     snmp_inc_snmpinasnparseerrs();
01041     return ERR_ARG;
01042   }
01043   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
01044   if (derr != ERR_OK)
01045   {
01046     /* can't decode */
01047     snmp_inc_snmpinasnparseerrs();
01048     return ERR_ARG;
01049   }
01050   ofs += (1 + len_octets + len);
01051   snmp_asn1_dec_type(p, ofs, &type);
01052   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
01053   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
01054   {
01055     /* can't decode or no integer (error-status) */
01056     snmp_inc_snmpinasnparseerrs();
01057     return ERR_ARG;
01058   }
01059   /* must be noError (0) for incoming requests.
01060      log errors for mib-2 completeness and for debug purposes */
01061   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
01062   if (derr != ERR_OK)
01063   {
01064     /* can't decode */
01065     snmp_inc_snmpinasnparseerrs();
01066     return ERR_ARG;
01067   }
01068   switch (m_stat->error_status)
01069   {
01070     case SNMP_ES_TOOBIG:
01071       snmp_inc_snmpintoobigs();
01072       break;
01073     case SNMP_ES_NOSUCHNAME:
01074       snmp_inc_snmpinnosuchnames();
01075       break;
01076     case SNMP_ES_BADVALUE:
01077       snmp_inc_snmpinbadvalues();
01078       break;
01079     case SNMP_ES_READONLY:
01080       snmp_inc_snmpinreadonlys();
01081       break;
01082     case SNMP_ES_GENERROR:
01083       snmp_inc_snmpingenerrs();
01084       break;
01085   }
01086   ofs += (1 + len_octets + len);
01087   snmp_asn1_dec_type(p, ofs, &type);
01088   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
01089   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
01090   {
01091     /* can't decode or no integer (error-index) */
01092     snmp_inc_snmpinasnparseerrs();
01093     return ERR_ARG;
01094   }
01095   /* must be 0 for incoming requests.
01096      decode anyway to catch bad integers (and dirty tricks) */
01097   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
01098   if (derr != ERR_OK)
01099   {
01100     /* can't decode */
01101     snmp_inc_snmpinasnparseerrs();
01102     return ERR_ARG;
01103   }
01104   ofs += (1 + len_octets + len);
01105   *ofs_ret = ofs;
01106   return ERR_OK;
01107 }
01108 
01109 static err_t
01110 snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
01111 {
01112   err_t derr;
01113   u16_t len, vb_len;
01114   u8_t  len_octets;
01115   u8_t type;
01116 
01117   /* variable binding list */
01118   snmp_asn1_dec_type(p, ofs, &type);
01119   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
01120   if ((derr != ERR_OK) ||
01121       (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
01122   {
01123     snmp_inc_snmpinasnparseerrs();
01124     return ERR_ARG;
01125   }
01126   ofs += (1 + len_octets);
01127 
01128   /* start with empty list */
01129   m_stat->invb.count = 0;
01130   m_stat->invb.head = NULL;
01131   m_stat->invb.tail = NULL;
01132 
01133   while (vb_len > 0)
01134   {
01135     struct snmp_obj_id oid, oid_value;
01136     struct snmp_varbind *vb;
01137 
01138     snmp_asn1_dec_type(p, ofs, &type);
01139     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
01140     if ((derr != ERR_OK) ||
01141         (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
01142         (len == 0) || (len > vb_len))
01143     {
01144       snmp_inc_snmpinasnparseerrs();
01145       /* free varbinds (if available) */
01146       snmp_varbind_list_free(&m_stat->invb);
01147       return ERR_ARG;
01148     }
01149     ofs += (1 + len_octets);
01150     vb_len -= (1 + len_octets);
01151 
01152     snmp_asn1_dec_type(p, ofs, &type);
01153     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
01154     if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
01155     {
01156       /* can't decode object name length */
01157       snmp_inc_snmpinasnparseerrs();
01158       /* free varbinds (if available) */
01159       snmp_varbind_list_free(&m_stat->invb);
01160       return ERR_ARG;
01161     }
01162     derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
01163     if (derr != ERR_OK)
01164     {
01165       /* can't decode object name */
01166       snmp_inc_snmpinasnparseerrs();
01167       /* free varbinds (if available) */
01168       snmp_varbind_list_free(&m_stat->invb);
01169       return ERR_ARG;
01170     }
01171     ofs += (1 + len_octets + len);
01172     vb_len -= (1 + len_octets + len);
01173 
01174     snmp_asn1_dec_type(p, ofs, &type);
01175     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
01176     if (derr != ERR_OK)
01177     {
01178       /* can't decode object value length */
01179       snmp_inc_snmpinasnparseerrs();
01180       /* free varbinds (if available) */
01181       snmp_varbind_list_free(&m_stat->invb);
01182       return ERR_ARG;
01183     }
01184 
01185     switch (type)
01186     {
01187       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
01188         vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
01189         if (vb != NULL)
01190         {
01191           s32_t *vptr = (s32_t*)vb->value;
01192 
01193           derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
01194           snmp_varbind_tail_add(&m_stat->invb, vb);
01195         }
01196         else
01197         {
01198           derr = ERR_ARG;
01199         }
01200         break;
01201       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
01202       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
01203       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
01204         vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
01205         if (vb != NULL)
01206         {
01207           u32_t *vptr = (u32_t*)vb->value;
01208 
01209           derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
01210           snmp_varbind_tail_add(&m_stat->invb, vb);
01211         }
01212         else
01213         {
01214           derr = ERR_ARG;
01215         }
01216         break;
01217       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
01218       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
01219         LWIP_ASSERT("invalid length", len <= 0xff);
01220         vb = snmp_varbind_alloc(&oid, type, (u8_t)len);
01221         if (vb != NULL)
01222         {
01223           derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
01224           snmp_varbind_tail_add(&m_stat->invb, vb);
01225         }
01226         else
01227         {
01228           derr = ERR_ARG;
01229         }
01230         break;
01231       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
01232         vb = snmp_varbind_alloc(&oid, type, 0);
01233         if (vb != NULL)
01234         {
01235           snmp_varbind_tail_add(&m_stat->invb, vb);
01236           derr = ERR_OK;
01237         }
01238         else
01239         {
01240           derr = ERR_ARG;
01241         }
01242         break;
01243       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
01244         derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
01245         if (derr == ERR_OK)
01246         {
01247           vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
01248           if (vb != NULL)
01249           {
01250             u8_t i = oid_value.len;
01251             s32_t *vptr = (s32_t*)vb->value;
01252 
01253             while(i > 0)
01254             {
01255               i--;
01256               vptr[i] = oid_value.id[i];
01257             }
01258             snmp_varbind_tail_add(&m_stat->invb, vb);
01259             derr = ERR_OK;
01260           }
01261           else
01262           {
01263             derr = ERR_ARG;
01264           }
01265         }
01266         break;
01267       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
01268         if (len == 4)
01269         {
01270           /* must be exactly 4 octets! */
01271           vb = snmp_varbind_alloc(&oid, type, 4);
01272           if (vb != NULL)
01273           {
01274             derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
01275             snmp_varbind_tail_add(&m_stat->invb, vb);
01276           }
01277           else
01278           {
01279             derr = ERR_ARG;
01280           }
01281         }
01282         else
01283         {
01284           derr = ERR_ARG;
01285         }
01286         break;
01287       default:
01288         derr = ERR_ARG;
01289         break;
01290     }
01291     if (derr != ERR_OK)
01292     {
01293       snmp_inc_snmpinasnparseerrs();
01294       /* free varbinds (if available) */
01295       snmp_varbind_list_free(&m_stat->invb);
01296       return ERR_ARG;
01297     }
01298     ofs += (1 + len_octets + len);
01299     vb_len -= (1 + len_octets + len);
01300   }
01301 
01302   if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
01303   {
01304     snmp_add_snmpintotalsetvars(m_stat->invb.count);
01305   }
01306   else
01307   {
01308     snmp_add_snmpintotalreqvars(m_stat->invb.count);
01309   }
01310 
01311   *ofs_ret = ofs;
01312   return ERR_OK;
01313 }
01314 
01315 struct snmp_varbind*
01316 snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
01317 {
01318   struct snmp_varbind *vb;
01319 
01320   vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
01321   if (vb != NULL)
01322   {
01323     u8_t i;
01324 
01325     vb->next = NULL;
01326     vb->prev = NULL;
01327     i = oid->len;
01328     vb->ident_len = i;
01329     if (i > 0)
01330     {
01331       LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH);
01332       /* allocate array of s32_t for our object identifier */
01333       vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE);
01334       if (vb->ident == NULL)
01335       {
01336         LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate ident value space\n"));
01337         memp_free(MEMP_SNMP_VARBIND, vb);
01338         return NULL;
01339       }
01340       while(i > 0)
01341       {
01342         i--;
01343         vb->ident[i] = oid->id[i];
01344       }
01345     }
01346     else
01347     {
01348       /* i == 0, pass zero length object identifier */
01349       vb->ident = NULL;
01350     }
01351     vb->value_type = type;
01352     vb->value_len = len;
01353     if (len > 0)
01354     {
01355       LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
01356       /* allocate raw bytes for our object value */
01357       vb->value = memp_malloc(MEMP_SNMP_VALUE);
01358       if (vb->value == NULL)
01359       {
01360         LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate value space\n"));
01361         if (vb->ident != NULL)
01362         {
01363           memp_free(MEMP_SNMP_VALUE, vb->ident);
01364         }
01365         memp_free(MEMP_SNMP_VARBIND, vb);
01366         return NULL;
01367       }
01368     }
01369     else
01370     {
01371       /* ASN1_NUL type, or zero length ASN1_OC_STR */
01372       vb->value = NULL;
01373     }
01374   }
01375   else
01376   {
01377     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate varbind space\n"));
01378   }
01379   return vb;
01380 }
01381 
01382 void
01383 snmp_varbind_free(struct snmp_varbind *vb)
01384 {
01385   if (vb->value != NULL )
01386   {
01387     memp_free(MEMP_SNMP_VALUE, vb->value);
01388   }
01389   if (vb->ident != NULL )
01390   {
01391     memp_free(MEMP_SNMP_VALUE, vb->ident);
01392   }
01393   memp_free(MEMP_SNMP_VARBIND, vb);
01394 }
01395 
01396 void
01397 snmp_varbind_list_free(struct snmp_varbind_root *root)
01398 {
01399   struct snmp_varbind *vb, *prev;
01400 
01401   vb = root->tail;
01402   while ( vb != NULL )
01403   {
01404     prev = vb->prev;
01405     snmp_varbind_free(vb);
01406     vb = prev;
01407   }
01408   root->count = 0;
01409   root->head = NULL;
01410   root->tail = NULL;
01411 }
01412 
01413 void
01414 snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
01415 {
01416   if (root->count == 0)
01417   {
01418     /* add first varbind to list */
01419     root->head = vb;
01420     root->tail = vb;
01421   }
01422   else
01423   {
01424     /* add nth varbind to list tail */
01425     root->tail->next = vb;
01426     vb->prev = root->tail;
01427     root->tail = vb;
01428   }
01429   root->count += 1;
01430 }
01431 
01432 struct snmp_varbind*
01433 snmp_varbind_tail_remove(struct snmp_varbind_root *root)
01434 {
01435   struct snmp_varbind* vb;
01436 
01437   if (root->count > 0)
01438   {
01439     /* remove tail varbind */
01440     vb = root->tail;
01441     root->tail = vb->prev;
01442     vb->prev->next = NULL;
01443     root->count -= 1;
01444   }
01445   else
01446   {
01447     /* nothing to remove */
01448     vb = NULL;
01449   }
01450   return vb;
01451 }
01452 
01453 #endif /* LWIP_SNMP */