SNMP agent attached to SPI slave

Dependencies:   mbed

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