uc-sdk
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
msg_in.c
Go to the documentation of this file.
1 
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/snmp.h"
40 #include "lwip/snmp_asn1.h"
41 #include "lwip/snmp_msg.h"
42 #include "lwip/snmp_structs.h"
43 #include "lwip/ip_addr.h"
44 #include "lwip/memp.h"
45 #include "lwip/udp.h"
46 #include "lwip/stats.h"
47 
48 #include <string.h>
49 
50 /* public (non-static) constants */
52 const s32_t snmp_version = 0;
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, ip_addr_t *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 
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 
92 #ifdef SNMP_PRIVATE_MIB_INIT
93  /* If defined, rhis must be a function-like define to initialize the
94  * private MIB after the stack has been initialized.
95  * The private MIB can also be initialized in tcpip_callback (or after
96  * the stack is initialized), this define is only for convenience. */
97  SNMP_PRIVATE_MIB_INIT();
98 #endif /* SNMP_PRIVATE_MIB_INIT */
99 
100  /* The coldstart trap will only be output
101  if our outgoing interface is up & configured */
102  snmp_coldstart_trap();
103 }
104 
105 static void
106 snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)
107 {
108  snmp_varbind_list_free(&msg_ps->outvb);
109  msg_ps->outvb = msg_ps->invb;
110  msg_ps->invb.head = NULL;
111  msg_ps->invb.tail = NULL;
112  msg_ps->invb.count = 0;
113  msg_ps->error_status = error;
114  msg_ps->error_index = 1 + msg_ps->vb_idx;
115  snmp_send_response(msg_ps);
116  snmp_varbind_list_free(&msg_ps->outvb);
117  msg_ps->state = SNMP_MSG_EMPTY;
118 }
119 
120 static void
121 snmp_ok_response(struct snmp_msg_pstat *msg_ps)
122 {
123  err_t err_ret;
124 
125  err_ret = snmp_send_response(msg_ps);
126  if (err_ret == ERR_MEM)
127  {
128  /* serious memory problem, can't return tooBig */
129  }
130  else
131  {
132  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));
133  }
134  /* free varbinds (if available) */
135  snmp_varbind_list_free(&msg_ps->invb);
136  snmp_varbind_list_free(&msg_ps->outvb);
137  msg_ps->state = SNMP_MSG_EMPTY;
138 }
139 
146 static void
147 snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
148 {
149  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
150 
151  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
152  {
153  struct mib_external_node *en;
154  struct snmp_name_ptr np;
155 
156  /* get_object_def() answer*/
157  en = msg_ps->ext_mib_node;
158  np = msg_ps->ext_name_ptr;
159 
160  /* translate answer into a known lifeform */
161  en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
162  if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) &&
163  (msg_ps->ext_object_def.access & MIB_ACCESS_READ))
164  {
165  msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
166  en->get_value_q(request_id, &msg_ps->ext_object_def);
167  }
168  else
169  {
170  en->get_object_def_pc(request_id, np.ident_len, np.ident);
171  /* search failed, object id points to unknown object (nosuchname) */
172  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
173  }
174  }
175  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
176  {
177  struct mib_external_node *en;
178  struct snmp_varbind *vb;
179 
180  /* get_value() answer */
181  en = msg_ps->ext_mib_node;
182 
183  /* allocate output varbind */
184  vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
185  LWIP_ASSERT("vb != NULL",vb != NULL);
186  if (vb != NULL)
187  {
188  vb->next = NULL;
189  vb->prev = NULL;
190 
191  /* move name from invb to outvb */
192  vb->ident = msg_ps->vb_ptr->ident;
193  vb->ident_len = msg_ps->vb_ptr->ident_len;
194  /* ensure this memory is refereced once only */
195  msg_ps->vb_ptr->ident = NULL;
196  msg_ps->vb_ptr->ident_len = 0;
197 
198  vb->value_type = msg_ps->ext_object_def.asn_type;
199  LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
200  vb->value_len = (u8_t)msg_ps->ext_object_def.v_len;
201  if (vb->value_len > 0)
202  {
203  LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
204  vb->value = memp_malloc(MEMP_SNMP_VALUE);
205  LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
206  if (vb->value != NULL)
207  {
208  en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
209  snmp_varbind_tail_add(&msg_ps->outvb, vb);
210  /* search again (if vb_idx < msg_ps->invb.count) */
211  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
212  msg_ps->vb_idx += 1;
213  }
214  else
215  {
216  en->get_value_pc(request_id, &msg_ps->ext_object_def);
217  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));
218  msg_ps->vb_ptr->ident = vb->ident;
219  msg_ps->vb_ptr->ident_len = vb->ident_len;
220  memp_free(MEMP_SNMP_VARBIND, vb);
221  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
222  }
223  }
224  else
225  {
226  /* vb->value_len == 0, empty value (e.g. empty string) */
227  en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
228  vb->value = NULL;
229  snmp_varbind_tail_add(&msg_ps->outvb, vb);
230  /* search again (if vb_idx < msg_ps->invb.count) */
231  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
232  msg_ps->vb_idx += 1;
233  }
234  }
235  else
236  {
237  en->get_value_pc(request_id, &msg_ps->ext_object_def);
238  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));
239  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
240  }
241  }
242 
243  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
244  (msg_ps->vb_idx < msg_ps->invb.count))
245  {
246  struct mib_node *mn;
247  struct snmp_name_ptr np;
248 
249  if (msg_ps->vb_idx == 0)
250  {
251  msg_ps->vb_ptr = msg_ps->invb.head;
252  }
253  else
254  {
255  msg_ps->vb_ptr = msg_ps->vb_ptr->next;
256  }
258  if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident))
259  {
260  mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
261  msg_ps->vb_ptr->ident + 4, &np);
262  if (mn != NULL)
263  {
264  if (mn->node_type == MIB_NODE_EX)
265  {
266  /* external object */
267  struct mib_external_node *en = (struct mib_external_node*)mn;
268 
269  msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
270  /* save en && args in msg_ps!! */
271  msg_ps->ext_mib_node = en;
272  msg_ps->ext_name_ptr = np;
273 
274  en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
275  }
276  else
277  {
278  /* internal object */
279  struct obj_def object_def;
280 
281  msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
282  mn->get_object_def(np.ident_len, np.ident, &object_def);
283  if ((object_def.instance != MIB_OBJECT_NONE) &&
284  (object_def.access & MIB_ACCESS_READ))
285  {
286  mn = mn;
287  }
288  else
289  {
290  /* search failed, object id points to unknown object (nosuchname) */
291  mn = NULL;
292  }
293  if (mn != NULL)
294  {
295  struct snmp_varbind *vb;
296 
297  msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
298  /* allocate output varbind */
299  vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
300  LWIP_ASSERT("vb != NULL",vb != NULL);
301  if (vb != NULL)
302  {
303  vb->next = NULL;
304  vb->prev = NULL;
305 
306  /* move name from invb to outvb */
307  vb->ident = msg_ps->vb_ptr->ident;
308  vb->ident_len = msg_ps->vb_ptr->ident_len;
309  /* ensure this memory is refereced once only */
310  msg_ps->vb_ptr->ident = NULL;
311  msg_ps->vb_ptr->ident_len = 0;
312 
313  vb->value_type = object_def.asn_type;
314  LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
315  vb->value_len = (u8_t)object_def.v_len;
316  if (vb->value_len > 0)
317  {
318  LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low",
319  vb->value_len <= SNMP_MAX_VALUE_SIZE);
320  vb->value = memp_malloc(MEMP_SNMP_VALUE);
321  LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
322  if (vb->value != NULL)
323  {
324  mn->get_value(&object_def, vb->value_len, vb->value);
325  snmp_varbind_tail_add(&msg_ps->outvb, vb);
326  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
327  msg_ps->vb_idx += 1;
328  }
329  else
330  {
331  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));
332  msg_ps->vb_ptr->ident = vb->ident;
333  msg_ps->vb_ptr->ident_len = vb->ident_len;
334  memp_free(MEMP_SNMP_VARBIND, vb);
335  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
336  }
337  }
338  else
339  {
340  /* vb->value_len == 0, empty value (e.g. empty string) */
341  vb->value = NULL;
342  snmp_varbind_tail_add(&msg_ps->outvb, vb);
343  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
344  msg_ps->vb_idx += 1;
345  }
346  }
347  else
348  {
349  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));
350  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
351  }
352  }
353  }
354  }
355  }
356  else
357  {
358  mn = NULL;
359  }
360  if (mn == NULL)
361  {
362  /* mn == NULL, noSuchName */
363  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
364  }
365  }
366  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
367  (msg_ps->vb_idx == msg_ps->invb.count))
368  {
369  snmp_ok_response(msg_ps);
370  }
371 }
372 
379 static void
380 snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
381 {
382  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
383 
384  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
385  {
386  struct mib_external_node *en;
387 
388  /* get_object_def() answer*/
389  en = msg_ps->ext_mib_node;
390 
391  /* translate answer into a known lifeform */
392  en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);
393  if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
394  {
395  msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;
396  en->get_value_q(request_id, &msg_ps->ext_object_def);
397  }
398  else
399  {
400  en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);
401  /* search failed, object id points to unknown object (nosuchname) */
402  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
403  }
404  }
405  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)
406  {
407  struct mib_external_node *en;
408  struct snmp_varbind *vb;
409 
410  /* get_value() answer */
411  en = msg_ps->ext_mib_node;
412 
413  LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff);
414  vb = snmp_varbind_alloc(&msg_ps->ext_oid,
415  msg_ps->ext_object_def.asn_type,
416  (u8_t)msg_ps->ext_object_def.v_len);
417  if (vb != NULL)
418  {
419  en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);
420  snmp_varbind_tail_add(&msg_ps->outvb, vb);
421  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
422  msg_ps->vb_idx += 1;
423  }
424  else
425  {
426  en->get_value_pc(request_id, &msg_ps->ext_object_def);
427  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));
428  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
429  }
430  }
431 
432  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
433  (msg_ps->vb_idx < msg_ps->invb.count))
434  {
435  struct mib_node *mn;
436  struct snmp_obj_id oid;
437 
438  if (msg_ps->vb_idx == 0)
439  {
440  msg_ps->vb_ptr = msg_ps->invb.head;
441  }
442  else
443  {
444  msg_ps->vb_ptr = msg_ps->vb_ptr->next;
445  }
446  if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))
447  {
448  if (msg_ps->vb_ptr->ident_len > 3)
449  {
450  /* can offset ident_len and ident */
451  mn = snmp_expand_tree((struct mib_node*)&internet,
452  msg_ps->vb_ptr->ident_len - 4,
453  msg_ps->vb_ptr->ident + 4, &oid);
454  }
455  else
456  {
457  /* can't offset ident_len -4, ident + 4 */
458  mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);
459  }
460  }
461  else
462  {
463  mn = NULL;
464  }
465  if (mn != NULL)
466  {
467  if (mn->node_type == MIB_NODE_EX)
468  {
469  /* external object */
470  struct mib_external_node *en = (struct mib_external_node*)mn;
471 
472  msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
473  /* save en && args in msg_ps!! */
474  msg_ps->ext_mib_node = en;
475  msg_ps->ext_oid = oid;
476 
477  en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);
478  }
479  else
480  {
481  /* internal object */
482  struct obj_def object_def;
483  struct snmp_varbind *vb;
484 
485  msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
486  mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);
487 
488  LWIP_ASSERT("invalid length", object_def.v_len <= 0xff);
489  vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len);
490  if (vb != NULL)
491  {
492  msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;
493  mn->get_value(&object_def, object_def.v_len, vb->value);
494  snmp_varbind_tail_add(&msg_ps->outvb, vb);
495  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
496  msg_ps->vb_idx += 1;
497  }
498  else
499  {
500  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));
501  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);
502  }
503  }
504  }
505  if (mn == NULL)
506  {
507  /* mn == NULL, noSuchName */
508  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
509  }
510  }
511  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
512  (msg_ps->vb_idx == msg_ps->invb.count))
513  {
514  snmp_ok_response(msg_ps);
515  }
516 }
517 
524 static void
525 snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
526 {
527  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));
528 
529  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)
530  {
531  struct mib_external_node *en;
532  struct snmp_name_ptr np;
533 
534  /* get_object_def() answer*/
535  en = msg_ps->ext_mib_node;
536  np = msg_ps->ext_name_ptr;
537 
538  /* translate answer into a known lifeform */
539  en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
540  if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
541  {
542  msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;
543  en->set_test_q(request_id, &msg_ps->ext_object_def);
544  }
545  else
546  {
547  en->get_object_def_pc(request_id, np.ident_len, np.ident);
548  /* search failed, object id points to unknown object (nosuchname) */
549  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
550  }
551  }
552  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)
553  {
554  struct mib_external_node *en;
555 
556  /* set_test() answer*/
557  en = msg_ps->ext_mib_node;
558 
559  if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE)
560  {
561  if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&
562  (en->set_test_a(request_id,&msg_ps->ext_object_def,
563  msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
564  {
565  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
566  msg_ps->vb_idx += 1;
567  }
568  else
569  {
570  en->set_test_pc(request_id,&msg_ps->ext_object_def);
571  /* bad value */
572  snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
573  }
574  }
575  else
576  {
577  en->set_test_pc(request_id,&msg_ps->ext_object_def);
578  /* object not available for set */
579  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
580  }
581  }
582  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)
583  {
584  struct mib_external_node *en;
585  struct snmp_name_ptr np;
586 
587  /* get_object_def() answer*/
588  en = msg_ps->ext_mib_node;
589  np = msg_ps->ext_name_ptr;
590 
591  /* translate answer into a known lifeform */
592  en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);
593  if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)
594  {
595  msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;
596  en->set_value_q(request_id, &msg_ps->ext_object_def,
597  msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
598  }
599  else
600  {
601  en->get_object_def_pc(request_id, np.ident_len, np.ident);
602  /* set_value failed, object has disappeared for some odd reason?? */
603  snmp_error_response(msg_ps,SNMP_ES_GENERROR);
604  }
605  }
606  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)
607  {
608  struct mib_external_node *en;
609 
611  en = msg_ps->ext_mib_node;
612  en->set_value_a(request_id, &msg_ps->ext_object_def,
613  msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
614 
616  msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
617  msg_ps->vb_idx += 1;
618  }
619 
620  /* test all values before setting */
621  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
622  (msg_ps->vb_idx < msg_ps->invb.count))
623  {
624  struct mib_node *mn;
625  struct snmp_name_ptr np;
626 
627  if (msg_ps->vb_idx == 0)
628  {
629  msg_ps->vb_ptr = msg_ps->invb.head;
630  }
631  else
632  {
633  msg_ps->vb_ptr = msg_ps->vb_ptr->next;
634  }
636  if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident))
637  {
638  mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
639  msg_ps->vb_ptr->ident + 4, &np);
640  if (mn != NULL)
641  {
642  if (mn->node_type == MIB_NODE_EX)
643  {
644  /* external object */
645  struct mib_external_node *en = (struct mib_external_node*)mn;
646 
647  msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;
648  /* save en && args in msg_ps!! */
649  msg_ps->ext_mib_node = en;
650  msg_ps->ext_name_ptr = np;
651 
652  en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
653  }
654  else
655  {
656  /* internal object */
657  struct obj_def object_def;
658 
659  msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;
660  mn->get_object_def(np.ident_len, np.ident, &object_def);
661  if (object_def.instance != MIB_OBJECT_NONE)
662  {
663  mn = mn;
664  }
665  else
666  {
667  /* search failed, object id points to unknown object (nosuchname) */
668  mn = NULL;
669  }
670  if (mn != NULL)
671  {
672  msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;
673 
674  if (object_def.access & MIB_ACCESS_WRITE)
675  {
676  if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&
677  (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))
678  {
679  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
680  msg_ps->vb_idx += 1;
681  }
682  else
683  {
684  /* bad value */
685  snmp_error_response(msg_ps,SNMP_ES_BADVALUE);
686  }
687  }
688  else
689  {
690  /* object not available for set */
691  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
692  }
693  }
694  }
695  }
696  }
697  else
698  {
699  mn = NULL;
700  }
701  if (mn == NULL)
702  {
703  /* mn == NULL, noSuchName */
704  snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);
705  }
706  }
707 
708  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&
709  (msg_ps->vb_idx == msg_ps->invb.count))
710  {
711  msg_ps->vb_idx = 0;
712  msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
713  }
714 
715  /* set all values "atomically" (be as "atomic" as possible) */
716  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
717  (msg_ps->vb_idx < msg_ps->invb.count))
718  {
719  struct mib_node *mn;
720  struct snmp_name_ptr np;
721 
722  if (msg_ps->vb_idx == 0)
723  {
724  msg_ps->vb_ptr = msg_ps->invb.head;
725  }
726  else
727  {
728  msg_ps->vb_ptr = msg_ps->vb_ptr->next;
729  }
730  /* skip iso prefix test, was done previously while settesting() */
731  mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,
732  msg_ps->vb_ptr->ident + 4, &np);
733  /* check if object is still available
734  (e.g. external hot-plug thingy present?) */
735  if (mn != NULL)
736  {
737  if (mn->node_type == MIB_NODE_EX)
738  {
739  /* external object */
740  struct mib_external_node *en = (struct mib_external_node*)mn;
741 
742  msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;
743  /* save en && args in msg_ps!! */
744  msg_ps->ext_mib_node = en;
745  msg_ps->ext_name_ptr = np;
746 
747  en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);
748  }
749  else
750  {
751  /* internal object */
752  struct obj_def object_def;
753 
754  msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;
755  mn->get_object_def(np.ident_len, np.ident, &object_def);
756  msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
757  mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);
758  msg_ps->vb_idx += 1;
759  }
760  }
761  }
762  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&
763  (msg_ps->vb_idx == msg_ps->invb.count))
764  {
765  /* simply echo the input if we can set it
766  @todo do we need to return the actual value?
767  e.g. if value is silently modified or behaves sticky? */
768  msg_ps->outvb = msg_ps->invb;
769  msg_ps->invb.head = NULL;
770  msg_ps->invb.tail = NULL;
771  msg_ps->invb.count = 0;
772  snmp_ok_response(msg_ps);
773  }
774 }
775 
776 
783 void
784 snmp_msg_event(u8_t request_id)
785 {
786  struct snmp_msg_pstat *msg_ps;
787 
788  if (request_id < SNMP_CONCURRENT_REQUESTS)
789  {
790  msg_ps = &msg_input_list[request_id];
791  if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)
792  {
793  snmp_msg_getnext_event(request_id, msg_ps);
794  }
795  else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)
796  {
797  snmp_msg_get_event(request_id, msg_ps);
798  }
799  else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)
800  {
801  snmp_msg_set_event(request_id, msg_ps);
802  }
803  }
804 }
805 
806 
807 /* lwIP UDP receive callback function */
808 static void
809 snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port)
810 {
811  struct snmp_msg_pstat *msg_ps;
812  u8_t req_idx;
813  err_t err_ret;
814  u16_t payload_len = p->tot_len;
815  u16_t payload_ofs = 0;
816  u16_t varbind_ofs = 0;
817 
818  /* suppress unused argument warning */
819  LWIP_UNUSED_ARG(arg);
820 
821  /* traverse input message process list, look for SNMP_MSG_EMPTY */
822  msg_ps = &msg_input_list[0];
823  req_idx = 0;
824  while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))
825  {
826  req_idx++;
827  msg_ps++;
828  }
829  if (req_idx == SNMP_CONCURRENT_REQUESTS)
830  {
831  /* exceeding number of concurrent requests */
832  pbuf_free(p);
833  return;
834  }
835 
836  /* accepting request */
838  /* record used 'protocol control block' */
839  msg_ps->pcb = pcb;
840  /* source address (network order) */
841  msg_ps->sip = *addr;
842  /* source port (host order (lwIP oddity)) */
843  msg_ps->sp = port;
844 
845  /* check total length, version, community, pdu type */
846  err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);
847  /* Only accept requests and requests without error (be robust) */
848  /* Reject response and trap headers or error requests as input! */
849  if ((err_ret != ERR_OK) ||
850  ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) &&
851  (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) &&
852  (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) ||
853  ((msg_ps->error_status != SNMP_ES_NOERROR) ||
854  (msg_ps->error_index != 0)) )
855  {
856  /* header check failed drop request silently, do not return error! */
857  pbuf_free(p);
858  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));
859  return;
860  }
861  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));
862 
863  /* Builds a list of variable bindings. Copy the varbinds from the pbuf
864  chain to glue them when these are divided over two or more pbuf's. */
865  err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);
866  /* we've decoded the incoming message, release input msg now */
867  pbuf_free(p);
868  if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0))
869  {
870  /* varbind-list decode failed, or varbind list empty.
871  drop request silently, do not return error!
872  (errors are only returned for a specific varbind failure) */
873  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));
874  return;
875  }
876 
877  msg_ps->error_status = SNMP_ES_NOERROR;
878  msg_ps->error_index = 0;
879  /* find object for each variable binding */
880  msg_ps->state = SNMP_MSG_SEARCH_OBJ;
881  /* first variable binding from list to inspect */
882  msg_ps->vb_idx = 0;
883 
884  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));
885 
886  /* handle input event and as much objects as possible in one go */
887  snmp_msg_event(req_idx);
888 }
889 
902 static err_t
903 snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
904 {
905  err_t derr;
906  u16_t len, ofs_base;
907  u8_t len_octets;
908  u8_t type;
909  s32_t version;
910 
911  ofs_base = ofs;
912  snmp_asn1_dec_type(p, ofs, &type);
913  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
914  if ((derr != ERR_OK) ||
915  (pdu_len != (1 + len_octets + len)) ||
916  (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
917  {
919  return ERR_ARG;
920  }
921  ofs += (1 + len_octets);
922  snmp_asn1_dec_type(p, ofs, &type);
923  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
924  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
925  {
926  /* can't decode or no integer (version) */
928  return ERR_ARG;
929  }
930  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);
931  if (derr != ERR_OK)
932  {
933  /* can't decode */
935  return ERR_ARG;
936  }
937  if (version != 0)
938  {
939  /* not version 1 */
941  return ERR_ARG;
942  }
943  ofs += (1 + len_octets + len);
944  snmp_asn1_dec_type(p, ofs, &type);
945  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
946  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))
947  {
948  /* can't decode or no octet string (community) */
950  return ERR_ARG;
951  }
952  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);
953  if (derr != ERR_OK)
954  {
956  return ERR_ARG;
957  }
958  /* add zero terminator */
959  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));
960  m_stat->community[len] = 0;
961  m_stat->com_strlen = (u8_t)len;
962  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)
963  {
966  snmp_authfail_trap();
967  return ERR_ARG;
968  }
969  ofs += (1 + len_octets + len);
970  snmp_asn1_dec_type(p, ofs, &type);
971  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
972  if (derr != ERR_OK)
973  {
975  return ERR_ARG;
976  }
977  switch(type)
978  {
979  case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):
980  /* GetRequest PDU */
982  derr = ERR_OK;
983  break;
984  case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):
985  /* GetNextRequest PDU */
987  derr = ERR_OK;
988  break;
989  case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):
990  /* GetResponse PDU */
992  derr = ERR_ARG;
993  break;
994  case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):
995  /* SetRequest PDU */
997  derr = ERR_OK;
998  break;
999  case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):
1000  /* Trap PDU */
1002  derr = ERR_ARG;
1003  break;
1004  default:
1006  derr = ERR_ARG;
1007  break;
1008  }
1009  if (derr != ERR_OK)
1010  {
1011  /* unsupported input PDU for this agent (no parse error) */
1012  return ERR_ARG;
1013  }
1014  m_stat->rt = type & 0x1F;
1015  ofs += (1 + len_octets);
1016  if (len != (pdu_len - (ofs - ofs_base)))
1017  {
1018  /* decoded PDU length does not equal actual payload length */
1020  return ERR_ARG;
1021  }
1022  snmp_asn1_dec_type(p, ofs, &type);
1023  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1024  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1025  {
1026  /* can't decode or no integer (request ID) */
1028  return ERR_ARG;
1029  }
1030  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);
1031  if (derr != ERR_OK)
1032  {
1033  /* can't decode */
1035  return ERR_ARG;
1036  }
1037  ofs += (1 + len_octets + len);
1038  snmp_asn1_dec_type(p, ofs, &type);
1039  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1040  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1041  {
1042  /* can't decode or no integer (error-status) */
1044  return ERR_ARG;
1045  }
1046  /* must be noError (0) for incoming requests.
1047  log errors for mib-2 completeness and for debug purposes */
1048  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);
1049  if (derr != ERR_OK)
1050  {
1051  /* can't decode */
1053  return ERR_ARG;
1054  }
1055  switch (m_stat->error_status)
1056  {
1057  case SNMP_ES_TOOBIG:
1059  break;
1060  case SNMP_ES_NOSUCHNAME:
1062  break;
1063  case SNMP_ES_BADVALUE:
1065  break;
1066  case SNMP_ES_READONLY:
1068  break;
1069  case SNMP_ES_GENERROR:
1071  break;
1072  }
1073  ofs += (1 + len_octets + len);
1074  snmp_asn1_dec_type(p, ofs, &type);
1075  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1076  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))
1077  {
1078  /* can't decode or no integer (error-index) */
1080  return ERR_ARG;
1081  }
1082  /* must be 0 for incoming requests.
1083  decode anyway to catch bad integers (and dirty tricks) */
1084  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);
1085  if (derr != ERR_OK)
1086  {
1087  /* can't decode */
1089  return ERR_ARG;
1090  }
1091  ofs += (1 + len_octets + len);
1092  *ofs_ret = ofs;
1093  return ERR_OK;
1094 }
1095 
1096 static err_t
1097 snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)
1098 {
1099  err_t derr;
1100  u16_t len, vb_len;
1101  u8_t len_octets;
1102  u8_t type;
1103 
1104  /* variable binding list */
1105  snmp_asn1_dec_type(p, ofs, &type);
1106  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);
1107  if ((derr != ERR_OK) ||
1108  (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))
1109  {
1111  return ERR_ARG;
1112  }
1113  ofs += (1 + len_octets);
1114 
1115  /* start with empty list */
1116  m_stat->invb.count = 0;
1117  m_stat->invb.head = NULL;
1118  m_stat->invb.tail = NULL;
1119 
1120  while (vb_len > 0)
1121  {
1122  struct snmp_obj_id oid, oid_value;
1123  struct snmp_varbind *vb;
1124 
1125  snmp_asn1_dec_type(p, ofs, &type);
1126  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1127  if ((derr != ERR_OK) ||
1128  (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
1129  (len == 0) || (len > vb_len))
1130  {
1132  /* free varbinds (if available) */
1133  snmp_varbind_list_free(&m_stat->invb);
1134  return ERR_ARG;
1135  }
1136  ofs += (1 + len_octets);
1137  vb_len -= (1 + len_octets);
1138 
1139  snmp_asn1_dec_type(p, ofs, &type);
1140  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1141  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))
1142  {
1143  /* can't decode object name length */
1145  /* free varbinds (if available) */
1146  snmp_varbind_list_free(&m_stat->invb);
1147  return ERR_ARG;
1148  }
1149  derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);
1150  if (derr != ERR_OK)
1151  {
1152  /* can't decode object name */
1154  /* free varbinds (if available) */
1155  snmp_varbind_list_free(&m_stat->invb);
1156  return ERR_ARG;
1157  }
1158  ofs += (1 + len_octets + len);
1159  vb_len -= (1 + len_octets + len);
1160 
1161  snmp_asn1_dec_type(p, ofs, &type);
1162  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
1163  if (derr != ERR_OK)
1164  {
1165  /* can't decode object value length */
1167  /* free varbinds (if available) */
1168  snmp_varbind_list_free(&m_stat->invb);
1169  return ERR_ARG;
1170  }
1171 
1172  switch (type)
1173  {
1174  case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):
1175  vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));
1176  if (vb != NULL)
1177  {
1178  s32_t *vptr = (s32_t*)vb->value;
1179 
1180  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);
1181  snmp_varbind_tail_add(&m_stat->invb, vb);
1182  }
1183  else
1184  {
1185  derr = ERR_ARG;
1186  }
1187  break;
1188  case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):
1189  case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):
1190  case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):
1191  vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));
1192  if (vb != NULL)
1193  {
1194  u32_t *vptr = (u32_t*)vb->value;
1195 
1196  derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);
1197  snmp_varbind_tail_add(&m_stat->invb, vb);
1198  }
1199  else
1200  {
1201  derr = ERR_ARG;
1202  }
1203  break;
1204  case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):
1205  case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):
1206  LWIP_ASSERT("invalid length", len <= 0xff);
1207  vb = snmp_varbind_alloc(&oid, type, (u8_t)len);
1208  if (vb != NULL)
1209  {
1210  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
1211  snmp_varbind_tail_add(&m_stat->invb, vb);
1212  }
1213  else
1214  {
1215  derr = ERR_ARG;
1216  }
1217  break;
1218  case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):
1219  vb = snmp_varbind_alloc(&oid, type, 0);
1220  if (vb != NULL)
1221  {
1222  snmp_varbind_tail_add(&m_stat->invb, vb);
1223  derr = ERR_OK;
1224  }
1225  else
1226  {
1227  derr = ERR_ARG;
1228  }
1229  break;
1230  case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):
1231  derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);
1232  if (derr == ERR_OK)
1233  {
1234  vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));
1235  if (vb != NULL)
1236  {
1237  u8_t i = oid_value.len;
1238  s32_t *vptr = (s32_t*)vb->value;
1239 
1240  while(i > 0)
1241  {
1242  i--;
1243  vptr[i] = oid_value.id[i];
1244  }
1245  snmp_varbind_tail_add(&m_stat->invb, vb);
1246  derr = ERR_OK;
1247  }
1248  else
1249  {
1250  derr = ERR_ARG;
1251  }
1252  }
1253  break;
1254  case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):
1255  if (len == 4)
1256  {
1257  /* must be exactly 4 octets! */
1258  vb = snmp_varbind_alloc(&oid, type, 4);
1259  if (vb != NULL)
1260  {
1261  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value);
1262  snmp_varbind_tail_add(&m_stat->invb, vb);
1263  }
1264  else
1265  {
1266  derr = ERR_ARG;
1267  }
1268  }
1269  else
1270  {
1271  derr = ERR_ARG;
1272  }
1273  break;
1274  default:
1275  derr = ERR_ARG;
1276  break;
1277  }
1278  if (derr != ERR_OK)
1279  {
1281  /* free varbinds (if available) */
1282  snmp_varbind_list_free(&m_stat->invb);
1283  return ERR_ARG;
1284  }
1285  ofs += (1 + len_octets + len);
1286  vb_len -= (1 + len_octets + len);
1287  }
1288 
1289  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)
1290  {
1291  snmp_add_snmpintotalsetvars(m_stat->invb.count);
1292  }
1293  else
1294  {
1295  snmp_add_snmpintotalreqvars(m_stat->invb.count);
1296  }
1297 
1298  *ofs_ret = ofs;
1299  return ERR_OK;
1300 }
1301 
1302 struct snmp_varbind*
1303 snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)
1304 {
1305  struct snmp_varbind *vb;
1306 
1307  vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND);
1308  LWIP_ASSERT("vb != NULL",vb != NULL);
1309  if (vb != NULL)
1310  {
1311  u8_t i;
1312 
1313  vb->next = NULL;
1314  vb->prev = NULL;
1315  i = oid->len;
1316  vb->ident_len = i;
1317  if (i > 0)
1318  {
1319  LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH);
1320  /* allocate array of s32_t for our object identifier */
1321  vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE);
1322  LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);
1323  if (vb->ident == NULL)
1324  {
1325  memp_free(MEMP_SNMP_VARBIND, vb);
1326  return NULL;
1327  }
1328  while(i > 0)
1329  {
1330  i--;
1331  vb->ident[i] = oid->id[i];
1332  }
1333  }
1334  else
1335  {
1336  /* i == 0, pass zero length object identifier */
1337  vb->ident = NULL;
1338  }
1339  vb->value_type = type;
1340  vb->value_len = len;
1341  if (len > 0)
1342  {
1343  LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE);
1344  /* allocate raw bytes for our object value */
1345  vb->value = memp_malloc(MEMP_SNMP_VALUE);
1346  LWIP_ASSERT("vb->value != NULL",vb->value != NULL);
1347  if (vb->value == NULL)
1348  {
1349  if (vb->ident != NULL)
1350  {
1351  memp_free(MEMP_SNMP_VALUE, vb->ident);
1352  }
1353  memp_free(MEMP_SNMP_VARBIND, vb);
1354  return NULL;
1355  }
1356  }
1357  else
1358  {
1359  /* ASN1_NUL type, or zero length ASN1_OC_STR */
1360  vb->value = NULL;
1361  }
1362  }
1363  return vb;
1364 }
1365 
1366 void
1367 snmp_varbind_free(struct snmp_varbind *vb)
1368 {
1369  if (vb->value != NULL )
1370  {
1371  memp_free(MEMP_SNMP_VALUE, vb->value);
1372  }
1373  if (vb->ident != NULL )
1374  {
1375  memp_free(MEMP_SNMP_VALUE, vb->ident);
1376  }
1377  memp_free(MEMP_SNMP_VARBIND, vb);
1378 }
1379 
1380 void
1381 snmp_varbind_list_free(struct snmp_varbind_root *root)
1382 {
1383  struct snmp_varbind *vb, *prev;
1384 
1385  vb = root->tail;
1386  while ( vb != NULL )
1387  {
1388  prev = vb->prev;
1389  snmp_varbind_free(vb);
1390  vb = prev;
1391  }
1392  root->count = 0;
1393  root->head = NULL;
1394  root->tail = NULL;
1395 }
1396 
1397 void
1398 snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)
1399 {
1400  if (root->count == 0)
1401  {
1402  /* add first varbind to list */
1403  root->head = vb;
1404  root->tail = vb;
1405  }
1406  else
1407  {
1408  /* add nth varbind to list tail */
1409  root->tail->next = vb;
1410  vb->prev = root->tail;
1411  root->tail = vb;
1412  }
1413  root->count += 1;
1414 }
1415 
1416 struct snmp_varbind*
1417 snmp_varbind_tail_remove(struct snmp_varbind_root *root)
1418 {
1419  struct snmp_varbind* vb;
1420 
1421  if (root->count > 0)
1422  {
1423  /* remove tail varbind */
1424  vb = root->tail;
1425  root->tail = vb->prev;
1426  vb->prev->next = NULL;
1427  root->count -= 1;
1428  }
1429  else
1430  {
1431  /* nothing to remove */
1432  vb = NULL;
1433  }
1434  return vb;
1435 }
1436 
1437 #endif /* LWIP_SNMP */