]> Joshua Wise's Git repositories - netwatch.git/blob - lwip/src/core/snmp/msg_in.c
Make some documentation a bit more accurate.
[netwatch.git] / lwip / src / core / snmp / msg_in.c
1 /**
2  * @file
3  * SNMP input message processing (RFC1157).
4  */
5
6 /*
7  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
8  * All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without modification,
11  * are permitted provided that the following conditions are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright notice,
14  *    this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  *    this list of conditions and the following disclaimer in the documentation
17  *    and/or other materials provided with the distribution.
18  * 3. The name of the author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
30  * OF SUCH DAMAGE.
31  *
32  * Author: Christiaan Simons <christiaan.simons@axon.tv>
33  */
34
35 #include "lwip/opt.h"
36
37 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
38
39 #include "lwip/ip_addr.h"
40 #include "lwip/mem.h"
41 #include "lwip/udp.h"
42 #include "lwip/stats.h"
43 #include "lwip/snmp.h"
44 #include "lwip/snmp_asn1.h"
45 #include "lwip/snmp_msg.h"
46 #include "lwip/snmp_structs.h"
47
48 #include <string.h>
49
50 /* public (non-static) constants */
51 /** SNMP v1 == 0 */
52 const s32_t snmp_version = 0;
53 /** default SNMP community string */
54 const char snmp_publiccommunity[7] = "public";
55
56 /* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */
57 struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];
58 /* UDP Protocol Control Block */
59 struct udp_pcb *snmp1_pcb;
60
61 static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
62 static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
63 static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);
64
65
66 /**
67  * Starts SNMP Agent.
68  * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.
69  */
70 void
71 snmp_init(void)
72 {
73   struct snmp_msg_pstat *msg_ps;
74   u8_t i;
75
76   snmp1_pcb = udp_new();
77   if (snmp1_pcb != NULL)
78   {
79     udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);
80     udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);
81   }
82   msg_ps = &msg_input_list[0];
83   for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)
84   {
85     msg_ps->state = SNMP_MSG_EMPTY;
86     msg_ps->error_index = 0;
87     msg_ps->error_status = SNMP_ES_NOERROR;
88     msg_ps++;
89   }
90   trap_msg.pcb = snmp1_pcb;
91   /* The coldstart trap will only be output
92      if our outgoing interface is up & configured  */
93   snmp_coldstart_trap();
94 }
95
96 static void
97 snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
98 {
99   snmp_varbind_list_free(&msg_ps->outvb);
100   msg_ps->outvb = msg_ps->invb;
101   msg_ps->invb.head = NULL;
102   msg_ps->invb.tail = NULL;
103   msg_ps->invb.count = 0;
104   msg_ps->error_status = error;
105   msg_ps->error_index = 1 + msg_ps->vb_idx;
106   snmp_send_response(msg_ps);
107   snmp_varbind_list_free(&msg_ps->outvb);
108   msg_ps->state = SNMP_MSG_EMPTY;
109 }
110
111 static void
112 snmp_ok_response(struct snmp_msg_pstat *msg_ps)
113 {
114   err_t err_ret;
115
116   err_ret = snmp_send_response(msg_ps);
117   if (err_ret == ERR_MEM)
118   {
119     /* serious memory problem, can't return tooBig */
120   }
121   else
122   {
123     LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
124   }
125   /* free varbinds (if available) */
126   snmp_varbind_list_free(&msg_ps->invb);
127   snmp_varbind_list_free(&msg_ps->outvb);
128   msg_ps->state = SNMP_MSG_EMPTY;
129 }
130
131 /**
132  * Service an internal or external event for SNMP GET.
133  *
134  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
135  * @param msg_ps points to the assosicated message process state
136  */
137 static void
138 snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
139 {
140   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
141
142   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
143   {
144     struct mib_external_node *en;
145     struct snmp_name_ptr np;
146
147     /* get_object_def() answer*/
148     en = msg_ps->ext_mib_node;
149     np = msg_ps->ext_name_ptr;
150
151     /* translate answer into a known lifeform */
152     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
153     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
154     {
155       msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
156       en->get_value_q(request_id, &msg_ps->ext_object_def);
157     }
158     else
159     {
160       en->get_object_def_pc(request_id, np.ident_len, np.ident);
161       /* search failed, object id points to unknown object (nosuchname) */
162       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
163     }
164   }
165   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
166   {
167     struct mib_external_node *en;
168     struct snmp_varbind *vb;
169
170     /* get_value() answer */
171     en = msg_ps->ext_mib_node;
172
173     /* allocate output varbind */
174     vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
175     LWIP_ASSERT("vb != NULL",vb != NULL);
176     if (vb != NULL)
177     {
178       vb->next = NULL;
179       vb->prev = NULL;
180
181       /* move name from invb to outvb */
182       vb->ident = msg_ps->vb_ptr->ident;
183       vb->ident_len = msg_ps->vb_ptr->ident_len;
184       /* ensure this memory is refereced once only */
185       msg_ps->vb_ptr->ident = NULL;
186       msg_ps->vb_ptr->ident_len = 0;
187
188       vb->value_type = msg_ps->ext_object_def.asn_type;
189       vb->value_len =  msg_ps->ext_object_def.v_len;
190       if (vb->value_len > 0)
191       {
192         vb->value = mem_malloc(vb->value_len);
193         LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
194         if (vb->value != NULL)
195         {
196           en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
197           snmp_varbind_tail_add(&msg_ps->outvb, vb);
198           /* search again (if vb_idx < msg_ps->invb.count) */
199           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
200           msg_ps->vb_idx += 1;
201         }
202         else
203         {
204           en->get_value_pc(request_id, &msg_ps->ext_object_def);
205           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
206           msg_ps->vb_ptr->ident = vb->ident;
207           msg_ps->vb_ptr->ident_len = vb->ident_len;
208           mem_free(vb);
209           snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
210         }
211       }
212       else
213       {
214         /* vb->value_len == 0, empty value (e.g. empty string) */
215         en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
216         vb->value = NULL;
217         snmp_varbind_tail_add(&msg_ps->outvb, vb);
218         /* search again (if vb_idx < msg_ps->invb.count) */
219         msg_ps->state = SNMP_MSG_SEARCH_OBJ;
220         msg_ps->vb_idx += 1;
221       }
222     }
223     else
224     {
225       en->get_value_pc(request_id, &msg_ps->ext_object_def);
226       LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
227       snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
228     }
229   }
230
231   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
232          (msg_ps->vb_idx < msg_ps->invb.count))
233   {
234     struct mib_node *mn;
235     struct snmp_name_ptr np;
236
237     if (msg_ps->vb_idx == 0)
238     {
239       msg_ps->vb_ptr = msg_ps->invb.head;
240     }
241     else
242     {
243       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
244     }
245     /** test object identifier for .iso.org.dod.internet prefix */
246     if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
247     {
248       mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
249                              msg_ps->vb_ptr->ident + 4, &np);
250       if (mn != NULL)
251       {
252         if (mn->node_type == MIB_NODE_EX)
253         {
254           /* external object */
255           struct mib_external_node *en = (struct mib_external_node*)mn;
256
257           msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
258           /* save en && args in msg_ps!! */
259           msg_ps->ext_mib_node = en;
260           msg_ps->ext_name_ptr = np;
261
262           en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
263         }
264         else
265         {
266           /* internal object */
267           struct obj_def object_def;
268
269           msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
270           mn->get_object_def(np.ident_len, np.ident, &object_def);
271           if (object_def.instance != MIB_OBJECT_NONE)
272           {
273             mn = mn;
274           }
275           else
276           {
277             /* search failed, object id points to unknown object (nosuchname) */
278             mn =  NULL;
279           }
280           if (mn != NULL)
281           {
282             struct snmp_varbind *vb;
283
284             msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
285             /* allocate output varbind */
286             vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
287             LWIP_ASSERT("vb != NULL",vb != NULL);
288             if (vb != NULL)
289             {
290               vb->next = NULL;
291               vb->prev = NULL;
292
293               /* move name from invb to outvb */
294               vb->ident = msg_ps->vb_ptr->ident;
295               vb->ident_len = msg_ps->vb_ptr->ident_len;
296               /* ensure this memory is refereced once only */
297               msg_ps->vb_ptr->ident = NULL;
298               msg_ps->vb_ptr->ident_len = 0;
299
300               vb->value_type = object_def.asn_type;
301               vb->value_len = object_def.v_len;
302               if (vb->value_len > 0)
303               {
304                 vb->value = mem_malloc(vb->value_len);
305                 LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
306                 if (vb->value != NULL)
307                 {
308                   mn->get_value(&object_def, vb->value_len, vb->value);
309                   snmp_varbind_tail_add(&msg_ps->outvb, vb);
310                   msg_ps->state = SNMP_MSG_SEARCH_OBJ;
311                   msg_ps->vb_idx += 1;
312                 }
313                 else
314                 {
315                   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
316                   msg_ps->vb_ptr->ident = vb->ident;
317                   msg_ps->vb_ptr->ident_len = vb->ident_len;
318                   mem_free(vb);
319                   snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
320                 }
321               }
322               else
323               {
324                 /* vb->value_len == 0, empty value (e.g. empty string) */
325                 vb->value = NULL;
326                 snmp_varbind_tail_add(&msg_ps->outvb, vb);
327                 msg_ps->state = SNMP_MSG_SEARCH_OBJ;
328                 msg_ps->vb_idx += 1;
329               }
330             }
331             else
332             {
333               LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
334               snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
335             }
336           }
337         }
338       }
339     }
340     else
341     {
342       mn = NULL;
343     }
344     if (mn == NULL)
345     {
346       /* mn == NULL, noSuchName */
347       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
348     }
349   }
350   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
351       (msg_ps->vb_idx == msg_ps->invb.count))
352   {
353     snmp_ok_response(msg_ps);
354   }
355 }
356
357 /**
358  * Service an internal or external event for SNMP GETNEXT.
359  *
360  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
361  * @param msg_ps points to the assosicated message process state
362  */
363 static void
364 snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
365 {
366   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
367
368   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
369   {
370     struct mib_external_node *en;
371
372     /* get_object_def() answer*/
373     en = msg_ps->ext_mib_node;
374
375     /* translate answer into a known lifeform */
376     en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
377     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
378     {
379       msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
380       en->get_value_q(request_id, &msg_ps->ext_object_def);
381     }
382     else
383     {
384       en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
385       /* search failed, object id points to unknown object (nosuchname) */
386       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
387     }
388   }
389   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
390   {
391     struct mib_external_node *en;
392     struct snmp_varbind *vb;
393
394     /* get_value() answer */
395     en = msg_ps->ext_mib_node;
396
397     vb = snmp_varbind_alloc(&msg_ps->ext_oid,
398                             msg_ps->ext_object_def.asn_type,
399                             msg_ps->ext_object_def.v_len);
400     if (vb != NULL)
401     {
402       en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
403       snmp_varbind_tail_add(&msg_ps->outvb, vb);
404       msg_ps->state = SNMP_MSG_SEARCH_OBJ;
405       msg_ps->vb_idx += 1;
406     }
407     else
408     {
409       en->get_value_pc(request_id, &msg_ps->ext_object_def);
410       LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
411       snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
412     }
413   }
414
415   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
416          (msg_ps->vb_idx < msg_ps->invb.count))
417   {
418     struct mib_node *mn;
419     struct snmp_obj_id oid;
420
421     if (msg_ps->vb_idx == 0)
422     {
423       msg_ps->vb_ptr = msg_ps->invb.head;
424     }
425     else
426     {
427       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
428     }
429     if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
430     {
431       if (msg_ps->vb_ptr->ident_len > 3)
432       {
433         /* can offset ident_len and ident */
434         mn = snmp_expand_tree((struct mib_node*)&internet,
435                               msg_ps->vb_ptr->ident_len - 4,
436                               msg_ps->vb_ptr->ident + 4, &oid);
437       }
438       else
439       {
440         /* can't offset ident_len -4, ident + 4 */
441         mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
442       }
443     }
444     else
445     {
446       mn = NULL;
447     }
448     if (mn != NULL)
449     {
450       if (mn->node_type == MIB_NODE_EX)
451       {
452         /* external object */
453         struct mib_external_node *en = (struct mib_external_node*)mn;
454
455         msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
456         /* save en && args in msg_ps!! */
457         msg_ps->ext_mib_node = en;
458         msg_ps->ext_oid = oid;
459
460         en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
461       }
462       else
463       {
464         /* internal object */
465         struct obj_def object_def;
466         struct snmp_varbind *vb;
467
468         msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
469         mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
470
471         vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);
472         if (vb != NULL)
473         {
474           msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
475           mn->get_value(&object_def, object_def.v_len, vb->value);
476           snmp_varbind_tail_add(&msg_ps->outvb, vb);
477           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
478           msg_ps->vb_idx += 1;
479         }
480         else
481         {
482           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
483           snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
484         }
485       }
486     }
487     if (mn == NULL)
488     {
489       /* mn == NULL, noSuchName */
490       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
491     }
492   }
493   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
494       (msg_ps->vb_idx == msg_ps->invb.count))
495   {
496     snmp_ok_response(msg_ps);
497   }
498 }
499
500 /**
501  * Service an internal or external event for SNMP SET.
502  *
503  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
504  * @param msg_ps points to the assosicated message process state
505  */
506 static void
507 snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
508 {
509   LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
510
511   if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
512   {
513     struct mib_external_node *en;
514     struct snmp_name_ptr np;
515
516     /* get_object_def() answer*/
517     en = msg_ps->ext_mib_node;
518     np = msg_ps->ext_name_ptr;
519
520     /* translate answer into a known lifeform */
521     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
522     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
523     {
524       msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
525       en->set_test_q(request_id, &msg_ps->ext_object_def);
526     }
527     else
528     {
529       en->get_object_def_pc(request_id, np.ident_len, np.ident);
530       /* search failed, object id points to unknown object (nosuchname) */
531       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
532     }
533   }
534   else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
535   {
536     struct mib_external_node *en;
537
538     /* set_test() answer*/
539     en = msg_ps->ext_mib_node;
540
541     if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)
542     {
543        if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
544            (en->set_test_a(request_id,&msg_ps->ext_object_def,
545                            msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
546       {
547         msg_ps->state = SNMP_MSG_SEARCH_OBJ;
548         msg_ps->vb_idx += 1;
549       }
550       else
551       {
552         en->set_test_pc(request_id,&msg_ps->ext_object_def);
553         /* bad value */
554         snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
555       }
556     }
557     else
558     {
559       en->set_test_pc(request_id,&msg_ps->ext_object_def);
560       /* object not available for set */
561       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
562     }
563   }
564   else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
565   {
566     struct mib_external_node *en;
567     struct snmp_name_ptr np;
568
569     /* get_object_def() answer*/
570     en = msg_ps->ext_mib_node;
571     np = msg_ps->ext_name_ptr;
572
573     /* translate answer into a known lifeform */
574     en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
575     if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
576     {
577       msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
578       en->set_value_q(request_id, &msg_ps->ext_object_def,
579                       msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
580     }
581     else
582     {
583       en->get_object_def_pc(request_id, np.ident_len, np.ident);
584       /* set_value failed, object has disappeared for some odd reason?? */
585       snmp_error_response(msg_ps,SNMP_ES_GENERROR);
586     }
587   }
588   else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
589   {
590     struct mib_external_node *en;
591
592     /** set_value_a() @todo: use reply value?? */
593     en = msg_ps->ext_mib_node;
594     en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
595
596     /** @todo use set_value_pc() if toobig */
597     msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
598     msg_ps->vb_idx += 1;
599   }
600
601   /* test all values before setting */
602   while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
603          (msg_ps->vb_idx < msg_ps->invb.count))
604   {
605     struct mib_node *mn;
606     struct snmp_name_ptr np;
607
608     if (msg_ps->vb_idx == 0)
609     {
610       msg_ps->vb_ptr = msg_ps->invb.head;
611     }
612     else
613     {
614       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
615     }
616     /** test object identifier for .iso.org.dod.internet prefix */
617     if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))
618     {
619       mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
620                              msg_ps->vb_ptr->ident + 4, &np);
621       if (mn != NULL)
622       {
623         if (mn->node_type == MIB_NODE_EX)
624         {
625           /* external object */
626           struct mib_external_node *en = (struct mib_external_node*)mn;
627
628           msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
629           /* save en && args in msg_ps!! */
630           msg_ps->ext_mib_node = en;
631           msg_ps->ext_name_ptr = np;
632
633           en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
634         }
635         else
636         {
637           /* internal object */
638           struct obj_def object_def;
639
640           msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
641           mn->get_object_def(np.ident_len, np.ident, &object_def);
642           if (object_def.instance != MIB_OBJECT_NONE)
643           {
644             mn = mn;
645           }
646           else
647           {
648             /* search failed, object id points to unknown object (nosuchname) */
649             mn = NULL;
650           }
651           if (mn != NULL)
652           {
653             msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
654
655             if (object_def.access == MIB_OBJECT_READ_WRITE)
656             {
657               if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
658                   (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
659               {
660                 msg_ps->state = SNMP_MSG_SEARCH_OBJ;
661                 msg_ps->vb_idx += 1;
662               }
663               else
664               {
665                 /* bad value */
666                 snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
667               }
668             }
669             else
670             {
671               /* object not available for set */
672               snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
673             }
674           }
675         }
676       }
677     }
678     else
679     {
680       mn = NULL;
681     }
682     if (mn == NULL)
683     {
684       /* mn == NULL, noSuchName */
685       snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
686     }
687   }
688
689   if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
690       (msg_ps->vb_idx == msg_ps->invb.count))
691   {
692     msg_ps->vb_idx = 0;
693     msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
694   }
695
696   /* set all values "atomically" (be as "atomic" as possible) */
697   while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
698          (msg_ps->vb_idx < msg_ps->invb.count))
699   {
700     struct mib_node *mn;
701     struct snmp_name_ptr np;
702
703     if (msg_ps->vb_idx == 0)
704     {
705       msg_ps->vb_ptr = msg_ps->invb.head;
706     }
707     else
708     {
709       msg_ps->vb_ptr = msg_ps->vb_ptr->next;
710     }
711     /* skip iso prefix test, was done previously while settesting() */
712     mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
713                            msg_ps->vb_ptr->ident + 4, &np);
714     /* check if object is still available
715        (e.g. external hot-plug thingy present?) */
716     if (mn != NULL)
717     {
718       if (mn->node_type == MIB_NODE_EX)
719       {
720         /* external object */
721         struct mib_external_node *en = (struct mib_external_node*)mn;
722
723         msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
724         /* save en && args in msg_ps!! */
725         msg_ps->ext_mib_node = en;
726         msg_ps->ext_name_ptr = np;
727
728         en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
729       }
730       else
731       {
732         /* internal object */
733         struct obj_def object_def;
734
735         msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
736         mn->get_object_def(np.ident_len, np.ident, &object_def);
737         msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
738         mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
739         msg_ps->vb_idx += 1;
740       }
741     }
742   }
743   if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
744       (msg_ps->vb_idx == msg_ps->invb.count))
745   {
746     /* simply echo the input if we can set it
747        @todo do we need to return the actual value?
748        e.g. if value is silently modified or behaves sticky? */
749     msg_ps->outvb = msg_ps->invb;
750     msg_ps->invb.head = NULL;
751     msg_ps->invb.tail = NULL;
752     msg_ps->invb.count = 0;
753     snmp_ok_response(msg_ps);
754   }
755 }
756
757
758 /**
759  * Handle one internal or external event.
760  * Called for one async event. (recv external/private answer)
761  *
762  * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)
763  */
764 void
765 snmp_msg_event(u8_t request_id)
766 {
767   struct snmp_msg_pstat *msg_ps;
768
769   if (request_id < SNMP_CONCURRENT_REQUESTS)
770   {
771     msg_ps = &msg_input_list[request_id];
772     if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
773     {
774       snmp_msg_getnext_event(request_id, msg_ps);
775     }
776     else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
777     {
778       snmp_msg_get_event(request_id, msg_ps);
779     }
780     else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
781     {
782       snmp_msg_set_event(request_id, msg_ps);
783     }
784   }
785 }
786
787
788 /* lwIP UDP receive callback function */
789 static void
790 snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)
791 {
792   struct udp_hdr *udphdr;
793
794   /* suppress unused argument warning */
795   LWIP_UNUSED_ARG(arg);
796   /* peek in the UDP header (goto IP payload) */
797   if(pbuf_header(p, UDP_HLEN)){
798     LWIP_ASSERT("Can't move to UDP header", 0);
799     pbuf_free(p);
800     return;
801   }
802   udphdr = p->payload;
803
804   /* check if datagram is really directed at us (including broadcast requests) */
805   if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))
806   {
807     struct snmp_msg_pstat *msg_ps;
808     u8_t req_idx;
809
810     /* traverse input message process list, look for SNMP_MSG_EMPTY */
811     msg_ps = &msg_input_list[0];
812     req_idx = 0;
813     while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
814     {
815       req_idx++;
816       msg_ps++;
817     }
818     if (req_idx != SNMP_CONCURRENT_REQUESTS)
819     {
820       err_t err_ret;
821       u16_t payload_len;
822       u16_t payload_ofs;
823       u16_t varbind_ofs = 0;
824
825       /* accepting request */
826       snmp_inc_snmpinpkts();
827       /* record used 'protocol control block' */
828       msg_ps->pcb = pcb;
829       /* source address (network order) */
830       msg_ps->sip = *addr;
831       /* source port (host order (lwIP oddity)) */
832       msg_ps->sp = port;
833       /* read UDP payload length from UDP header */
834       payload_len = ntohs(udphdr->len) - UDP_HLEN;
835
836       /* adjust to UDP payload */
837       payload_ofs = UDP_HLEN;
838
839       /* check total length, version, community, pdu type */
840       err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
841       if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||
842            (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||
843            (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&
844           ((msg_ps->error_status == SNMP_ES_NOERROR) &&
845            (msg_ps->error_index == 0)) )
846       {
847         /* Only accept requests and requests without error (be robust) */
848         err_ret = err_ret;
849       }
850       else
851       {
852         /* Reject response and trap headers or error requests as input! */
853         err_ret = ERR_ARG;
854       }
855       if (err_ret == ERR_OK)
856       {
857         LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
858
859         /* Builds a list of variable bindings. Copy the varbinds from the pbuf
860           chain to glue them when these are divided over two or more pbuf's. */
861         err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
862         if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))
863         {
864           /* we've decoded the incoming message, release input msg now */
865           pbuf_free(p);
866
867           msg_ps->error_status = SNMP_ES_NOERROR;
868           msg_ps->error_index = 0;
869           /* find object for each variable binding */
870           msg_ps->state = SNMP_MSG_SEARCH_OBJ;
871           /* first variable binding from list to inspect */
872           msg_ps->vb_idx = 0;
873
874           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
875
876           /* handle input event and as much objects as possible in one go */
877           snmp_msg_event(req_idx);
878         }
879         else
880         {
881           /* varbind-list decode failed, or varbind list empty.
882              drop request silently, do not return error!
883              (errors are only returned for a specific varbind failure) */
884           pbuf_free(p);
885           LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
886         }
887       }
888       else
889       {
890         /* header check failed
891            drop request silently, do not return error! */
892         pbuf_free(p);
893         LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
894       }
895     }
896     else
897     {
898       /* exceeding number of concurrent requests */
899       pbuf_free(p);
900     }
901   }
902   else
903   {
904     /* datagram not for us */
905     pbuf_free(p);
906   }
907 }
908
909 /**
910  * Checks and decodes incoming SNMP message header, logs header errors.
911  *
912  * @param p points to pbuf chain of SNMP message (UDP payload)
913  * @param ofs points to first octet of SNMP message
914  * @param pdu_len the length of the UDP payload
915  * @param ofs_ret returns the ofset of the variable bindings
916  * @param m_stat points to the current message request state return
917  * @return
918  * - ERR_OK SNMP header is sane and accepted
919  * - ERR_ARG SNMP header is either malformed or rejected
920  */
921 static err_t
922 snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
923 {
924   err_t derr;
925   u16_t len, ofs_base;
926   u8_t  len_octets;
927   u8_t  type;
928   s32_t version;
929
930   ofs_base = ofs;
931   snmp_asn1_dec_type(p, ofs, &type);
932   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
933   if ((derr != ERR_OK) ||
934       (pdu_len != (1 + len_octets + len)) ||
935       (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
936   {
937     snmp_inc_snmpinasnparseerrs();
938     return ERR_ARG;
939   }
940   ofs += (1 + len_octets);
941   snmp_asn1_dec_type(p, ofs, &type);
942   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
943   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
944   {
945     /* can't decode or no integer (version) */
946     snmp_inc_snmpinasnparseerrs();
947     return ERR_ARG;
948   }
949   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
950   if (derr != ERR_OK)
951   {
952     /* can't decode */
953     snmp_inc_snmpinasnparseerrs();
954     return ERR_ARG;
955   }
956   if (version != 0)
957   {
958     /* not version 1 */
959     snmp_inc_snmpinbadversions();
960     return ERR_ARG;
961   }
962   ofs += (1 + len_octets + len);
963   snmp_asn1_dec_type(p, ofs, &type);
964   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
965   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
966   {
967     /* can't decode or no octet string (community) */
968     snmp_inc_snmpinasnparseerrs();
969     return ERR_ARG;
970   }
971   derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
972   if (derr != ERR_OK)
973   {
974     snmp_inc_snmpinasnparseerrs();
975     return ERR_ARG;
976   }
977   /* add zero terminator */
978   len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
979   m_stat->community[len] = 0;
980   m_stat->com_strlen = len;
981   if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
982   {
983     /** @todo: move this if we need to check more names */
984     snmp_inc_snmpinbadcommunitynames();
985     snmp_authfail_trap();
986     return ERR_ARG;
987   }
988   ofs += (1 + len_octets + len);
989   snmp_asn1_dec_type(p, ofs, &type);
990   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
991   if (derr != ERR_OK)
992   {
993     snmp_inc_snmpinasnparseerrs();
994     return ERR_ARG;
995   }
996   switch(type)
997   {
998     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
999       /* GetRequest PDU */
1000       snmp_inc_snmpingetrequests();
1001       derr = ERR_OK;
1002       break;
1003     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
1004       /* GetNextRequest PDU */
1005       snmp_inc_snmpingetnexts();
1006       derr = ERR_OK;
1007       break;
1008     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
1009       /* GetResponse PDU */
1010       snmp_inc_snmpingetresponses();
1011       derr = ERR_ARG;
1012       break;
1013     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
1014       /* SetRequest PDU */
1015       snmp_inc_snmpinsetrequests();
1016       derr = ERR_OK;
1017       break;
1018     case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
1019       /* Trap PDU */
1020       snmp_inc_snmpintraps();
1021       derr = ERR_ARG;
1022       break;
1023     default:
1024       snmp_inc_snmpinasnparseerrs();
1025       derr = ERR_ARG;
1026       break;
1027   }
1028   if (derr != ERR_OK)
1029   {
1030     /* unsupported input PDU for this agent (no parse error) */
1031     return ERR_ARG;
1032   }
1033   m_stat->rt = type & 0x1F;
1034   ofs += (1 + len_octets);
1035   if (len != (pdu_len - (ofs - ofs_base)))
1036   {
1037     /* decoded PDU length does not equal actual payload length */
1038     snmp_inc_snmpinasnparseerrs();
1039     return ERR_ARG;
1040   }
1041   snmp_asn1_dec_type(p, ofs, &type);
1042   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1043   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1044   {
1045     /* can't decode or no integer (request ID) */
1046     snmp_inc_snmpinasnparseerrs();
1047     return ERR_ARG;
1048   }
1049   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
1050   if (derr != ERR_OK)
1051   {
1052     /* can't decode */
1053     snmp_inc_snmpinasnparseerrs();
1054     return ERR_ARG;
1055   }
1056   ofs += (1 + len_octets + len);
1057   snmp_asn1_dec_type(p, ofs, &type);
1058   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1059   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1060   {
1061     /* can't decode or no integer (error-status) */
1062     snmp_inc_snmpinasnparseerrs();
1063     return ERR_ARG;
1064   }
1065   /* must be noError (0) for incoming requests.
1066      log errors for mib-2 completeness and for debug purposes */
1067   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
1068   if (derr != ERR_OK)
1069   {
1070     /* can't decode */
1071     snmp_inc_snmpinasnparseerrs();
1072     return ERR_ARG;
1073   }
1074   switch (m_stat->error_status)
1075   {
1076     case SNMP_ES_TOOBIG:
1077       snmp_inc_snmpintoobigs();
1078       break;
1079     case SNMP_ES_NOSUCHNAME:
1080       snmp_inc_snmpinnosuchnames();
1081       break;
1082     case SNMP_ES_BADVALUE:
1083       snmp_inc_snmpinbadvalues();
1084       break;
1085     case SNMP_ES_READONLY:
1086       snmp_inc_snmpinreadonlys();
1087       break;
1088     case SNMP_ES_GENERROR:
1089       snmp_inc_snmpingenerrs();
1090       break;
1091   }
1092   ofs += (1 + len_octets + len);
1093   snmp_asn1_dec_type(p, ofs, &type);
1094   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1095   if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1096   {
1097     /* can't decode or no integer (error-index) */
1098     snmp_inc_snmpinasnparseerrs();
1099     return ERR_ARG;
1100   }
1101   /* must be 0 for incoming requests.
1102      decode anyway to catch bad integers (and dirty tricks) */
1103   derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
1104   if (derr != ERR_OK)
1105   {
1106     /* can't decode */
1107     snmp_inc_snmpinasnparseerrs();
1108     return ERR_ARG;
1109   }
1110   ofs += (1 + len_octets + len);
1111   *ofs_ret = ofs;
1112   return ERR_OK;
1113 }
1114
1115 static err_t
1116 snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
1117 {
1118   err_t derr;
1119   u16_t len, vb_len;
1120   u8_t  len_octets;
1121   u8_t type;
1122
1123   /* variable binding list */
1124   snmp_asn1_dec_type(p, ofs, &type);
1125   derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
1126   if ((derr != ERR_OK) ||
1127       (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
1128   {
1129     snmp_inc_snmpinasnparseerrs();
1130     return ERR_ARG;
1131   }
1132   ofs += (1 + len_octets);
1133
1134   /* start with empty list */
1135   m_stat->invb.count = 0;
1136   m_stat->invb.head = NULL;
1137   m_stat->invb.tail = NULL;
1138
1139   while (vb_len > 0)
1140   {
1141     struct snmp_obj_id oid, oid_value;
1142     struct snmp_varbind *vb;
1143
1144     snmp_asn1_dec_type(p, ofs, &type);
1145     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1146     if ((derr != ERR_OK) ||
1147         (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
1148         (len <= 0) || (len > vb_len))
1149     {
1150       snmp_inc_snmpinasnparseerrs();
1151       /* free varbinds (if available) */
1152       snmp_varbind_list_free(&m_stat->invb);
1153       return ERR_ARG;
1154     }
1155     ofs += (1 + len_octets);
1156     vb_len -= (1 + len_octets);
1157
1158     snmp_asn1_dec_type(p, ofs, &type);
1159     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1160     if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
1161     {
1162       /* can't decode object name length */
1163       snmp_inc_snmpinasnparseerrs();
1164       /* free varbinds (if available) */
1165       snmp_varbind_list_free(&m_stat->invb);
1166       return ERR_ARG;
1167     }
1168     derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
1169     if (derr != ERR_OK)
1170     {
1171       /* can't decode object name */
1172       snmp_inc_snmpinasnparseerrs();
1173       /* free varbinds (if available) */
1174       snmp_varbind_list_free(&m_stat->invb);
1175       return ERR_ARG;
1176     }
1177     ofs += (1 + len_octets + len);
1178     vb_len -= (1 + len_octets + len);
1179
1180     snmp_asn1_dec_type(p, ofs, &type);
1181     derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1182     if (derr != ERR_OK)
1183     {
1184       /* can't decode object value length */
1185       snmp_inc_snmpinasnparseerrs();
1186       /* free varbinds (if available) */
1187       snmp_varbind_list_free(&m_stat->invb);
1188       return ERR_ARG;
1189     }
1190
1191     switch (type)
1192     {
1193       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
1194         vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
1195         if (vb != NULL)
1196         {
1197           s32_t *vptr = vb->value;
1198
1199           derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
1200           snmp_varbind_tail_add(&m_stat->invb, vb);
1201         }
1202         else
1203         {
1204           derr = ERR_ARG;
1205         }
1206         break;
1207       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
1208       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
1209       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
1210         vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
1211         if (vb != NULL)
1212         {
1213           u32_t *vptr = vb->value;
1214
1215           derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
1216           snmp_varbind_tail_add(&m_stat->invb, vb);
1217         }
1218         else
1219         {
1220           derr = ERR_ARG;
1221         }
1222         break;
1223       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
1224       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
1225         vb = snmp_varbind_alloc(&oid, type, len);
1226         if (vb != NULL)
1227         {
1228           derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
1229           snmp_varbind_tail_add(&m_stat->invb, vb);
1230         }
1231         else
1232         {
1233           derr = ERR_ARG;
1234         }
1235         break;
1236       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
1237         vb = snmp_varbind_alloc(&oid, type, 0);
1238         if (vb != NULL)
1239         {
1240           snmp_varbind_tail_add(&m_stat->invb, vb);
1241           derr = ERR_OK;
1242         }
1243         else
1244         {
1245           derr = ERR_ARG;
1246         }
1247         break;
1248       case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
1249         derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
1250         if (derr == ERR_OK)
1251         {
1252           vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
1253           if (vb != NULL)
1254           {
1255             u8_t i = oid_value.len;
1256             s32_t *vptr = vb->value;
1257
1258             while(i > 0)
1259             {
1260               i--;
1261               vptr[i] = oid_value.id[i];
1262             }
1263             snmp_varbind_tail_add(&m_stat->invb, vb);
1264             derr = ERR_OK;
1265           }
1266           else
1267           {
1268             derr = ERR_ARG;
1269           }
1270         }
1271         break;
1272       case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
1273         if (len == 4)
1274         {
1275           /* must be exactly 4 octets! */
1276           vb = snmp_varbind_alloc(&oid, type, 4);
1277           if (vb != NULL)
1278           {
1279             derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);
1280             snmp_varbind_tail_add(&m_stat->invb, vb);
1281           }
1282           else
1283           {
1284             derr = ERR_ARG;
1285           }
1286         }
1287         else
1288         {
1289           derr = ERR_ARG;
1290         }
1291         break;
1292       default:
1293         derr = ERR_ARG;
1294         break;
1295     }
1296     if (derr != ERR_OK)
1297     {
1298       snmp_inc_snmpinasnparseerrs();
1299       /* free varbinds (if available) */
1300       snmp_varbind_list_free(&m_stat->invb);
1301       return ERR_ARG;
1302     }
1303     ofs += (1 + len_octets + len);
1304     vb_len -= (1 + len_octets + len);
1305   }
1306
1307   if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
1308   {
1309     snmp_add_snmpintotalsetvars(m_stat->invb.count);
1310   }
1311   else
1312   {
1313     snmp_add_snmpintotalreqvars(m_stat->invb.count);
1314   }
1315
1316   *ofs_ret = ofs;
1317   return ERR_OK;
1318 }
1319
1320 struct snmp_varbind*
1321 snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
1322 {
1323   struct snmp_varbind *vb;
1324
1325   vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));
1326   LWIP_ASSERT("vb != NULL",vb != NULL);
1327   if (vb != NULL)
1328   {
1329     u8_t i;
1330
1331     vb->next = NULL;
1332     vb->prev = NULL;
1333     i = oid->len;
1334     vb->ident_len = i;
1335     if (i > 0)
1336     {
1337       /* allocate array of s32_t for our object identifier */
1338       vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);
1339       LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
1340       if (vb->ident == NULL)
1341       {
1342         mem_free(vb);
1343         return NULL;
1344       }
1345       while(i > 0)
1346       {
1347         i--;
1348         vb->ident[i] = oid->id[i];
1349       }
1350     }
1351     else
1352     {
1353       /* i == 0, pass zero length object identifier */
1354       vb->ident = NULL;
1355     }
1356     vb->value_type = type;
1357     vb->value_len = len;
1358     if (len > 0)
1359     {
1360       /* allocate raw bytes for our object value */
1361       vb->value = mem_malloc(len);
1362       LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
1363       if (vb->value == NULL)
1364       {
1365         if (vb->ident != NULL)
1366         {
1367           mem_free(vb->ident);
1368         }
1369         mem_free(vb);
1370         return NULL;
1371       }
1372     }
1373     else
1374     {
1375       /* ASN1_NUL type, or zero length ASN1_OC_STR */
1376       vb->value = NULL;
1377     }
1378   }
1379   return vb;
1380 }
1381
1382 void
1383 snmp_varbind_free(struct snmp_varbind *vb)
1384 {
1385   if (vb->value != NULL )
1386   {
1387     mem_free(vb->value);
1388   }
1389   if (vb->ident != NULL )
1390   {
1391     mem_free(vb->ident);
1392   }
1393   mem_free(vb);
1394 }
1395
1396 void
1397 snmp_varbind_list_free(struct snmp_varbind_root *root)
1398 {
1399   struct snmp_varbind *vb, *prev;
1400
1401   vb = root->tail;
1402   while ( vb != NULL )
1403   {
1404     prev = vb->prev;
1405     snmp_varbind_free(vb);
1406     vb = prev;
1407   }
1408   root->count = 0;
1409   root->head = NULL;
1410   root->tail = NULL;
1411 }
1412
1413 void
1414 snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
1415 {
1416   if (root->count == 0)
1417   {
1418     /* add first varbind to list */
1419     root->head = vb;
1420     root->tail = vb;
1421   }
1422   else
1423   {
1424     /* add nth varbind to list tail */
1425     root->tail->next = vb;
1426     vb->prev = root->tail;
1427     root->tail = vb;
1428   }
1429   root->count += 1;
1430 }
1431
1432 struct snmp_varbind*
1433 snmp_varbind_tail_remove(struct snmp_varbind_root *root)
1434 {
1435   struct snmp_varbind* vb;
1436
1437   if (root->count > 0)
1438   {
1439     /* remove tail varbind */
1440     vb = root->tail;
1441     root->tail = vb->prev;
1442     vb->prev->next = NULL;
1443     root->count -= 1;
1444   }
1445   else
1446   {
1447     /* nothing to remove */
1448     vb = NULL;
1449   }
1450   return vb;
1451 }
1452
1453 #endif /* LWIP_SNMP */
This page took 0.096301 seconds and 4 git commands to generate.