ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

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

Generated on Sat May 26 2012 04:34:58 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.