STM32F769IDiscovery  1.00
uDANTE Audio Networking with STM32F7 DISCO board
snmp_msg.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  * Martin Hentschel <info@cl-soft.de>
34  */
35 
36 #include "lwip/apps/snmp_opts.h"
37 
38 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
39 
40 #include "snmp_msg.h"
41 #include "snmp_asn1.h"
42 #include "snmp_core_priv.h"
43 #include "lwip/ip_addr.h"
44 #include "lwip/stats.h"
45 
46 #include <string.h>
47 
48 /* public (non-static) constants */
50 const char *snmp_community = SNMP_COMMUNITY;
52 const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
54 const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
55 
56 snmp_write_callback_fct snmp_write_callback = NULL;
57 void* snmp_write_callback_arg = NULL;
58 
63 const char *
64 snmp_get_community(void)
65 {
66  return snmp_community;
67 }
68 
76 void
77 snmp_set_community(const char * const community)
78 {
79  LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
80  snmp_community = community;
81 }
82 
87 const char *
88 snmp_get_community_write(void)
89 {
90  return snmp_community_write;
91 }
92 
97 const char *
98 snmp_get_community_trap(void)
99 {
100  return snmp_community_trap;
101 }
102 
110 void
111 snmp_set_community_write(const char * const community)
112 {
113  LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
114  snmp_community_write = community;
115 }
116 
124 void
125 snmp_set_community_trap(const char * const community)
126 {
127  LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
128  snmp_community_trap = community;
129 }
130 
131 void
132 snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg)
133 {
134  snmp_write_callback = write_callback;
135  snmp_write_callback_arg = callback_arg;
136 }
137 
138 /* ----------------------------------------------------------------------- */
139 /* forward declarations */
140 /* ----------------------------------------------------------------------- */
141 
142 static err_t snmp_process_get_request(struct snmp_request *request);
143 static err_t snmp_process_getnext_request(struct snmp_request *request);
144 static err_t snmp_process_getbulk_request(struct snmp_request *request);
145 static err_t snmp_process_set_request(struct snmp_request *request);
146 
147 static err_t snmp_parse_inbound_frame(struct snmp_request *request);
148 static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
149 static err_t snmp_append_outbound_varbind(struct snmp_request *request, struct snmp_varbind* varbind);
150 static err_t snmp_complete_outbound_frame(struct snmp_request *request);
151 static void snmp_execute_write_callbacks(struct snmp_request *request);
152 
153 
154 /* ----------------------------------------------------------------------- */
155 /* implementation */
156 /* ----------------------------------------------------------------------- */
157 
158 void
159 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port)
160 {
161  err_t err;
162  struct snmp_request request;
163 
164  memset(&request, 0, sizeof(request));
165  request.handle = handle;
166  request.source_ip = source_ip;
167  request.source_port = port;
168  request.inbound_pbuf = p;
169 
170  snmp_stats.inpkts++;
171 
172  err = snmp_parse_inbound_frame(&request);
173  if (err == ERR_OK) {
174  err = snmp_prepare_outbound_frame(&request);
175  if (err == ERR_OK) {
176 
177  if (request.error_status == SNMP_ERR_NOERROR) {
178  /* only process frame if we do not already have an error to return (e.g. all readonly) */
179  if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) {
180  err = snmp_process_get_request(&request);
181  } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) {
182  err = snmp_process_getnext_request(&request);
183  } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
184  err = snmp_process_getbulk_request(&request);
185  } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
186  err = snmp_process_set_request(&request);
187  }
188  }
189 
190  if (err == ERR_OK) {
191  err = snmp_complete_outbound_frame(&request);
192 
193  if (err == ERR_OK) {
194  err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port);
195 
196  if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)
197  && (request.error_status == SNMP_ERR_NOERROR)
198  && (snmp_write_callback != NULL)) {
199  /* raise write notification for all written objects */
200  snmp_execute_write_callbacks(&request);
201  }
202  }
203  }
204  }
205 
206  if (request.outbound_pbuf != NULL) {
207  pbuf_free(request.outbound_pbuf);
208  }
209  }
210 }
211 
212 static u8_t
213 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg)
214 {
215  if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) {
216  return SNMP_ERR_NOSUCHINSTANCE;
217  }
218 
219  if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) {
220  /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */
221  return SNMP_ERR_NOSUCHINSTANCE;
222  }
223 
224  return SNMP_ERR_NOERROR;
225 }
226 
227 static void
228 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next)
229 {
230  err_t err;
231  struct snmp_node_instance node_instance;
232  memset(&node_instance, 0, sizeof(node_instance));
233 
234  if (get_next) {
235  struct snmp_obj_id result_oid;
236  request->error_status = snmp_get_next_node_instance_from_oid(vb->oid.id, vb->oid.len, snmp_msg_getnext_validate_node_inst, request, &result_oid, &node_instance);
237 
238  if (request->error_status == SNMP_ERR_NOERROR) {
239  snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len);
240  }
241  } else {
242  request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance);
243 
244  if (request->error_status == SNMP_ERR_NOERROR) {
245  /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */
246  request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request);
247 
248  if (request->error_status != SNMP_ERR_NOERROR) {
249  if (node_instance.release_instance != NULL) {
250  node_instance.release_instance(&node_instance);
251  }
252  }
253  }
254  }
255 
256  if (request->error_status != SNMP_ERR_NOERROR)
257  {
258  if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
259  if (request->version == SNMP_VERSION_2c) {
260  /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
261  vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK));
262  vb->value_len = 0;
263 
264  err = snmp_append_outbound_varbind(request, vb);
265  if (err == ERR_OK) {
266  /* we stored the exception in varbind -> go on */
267  request->error_status = SNMP_ERR_NOERROR;
268  } else if (err == ERR_BUF) {
269  request->error_status = SNMP_ERR_TOOBIG;
270  } else {
271  request->error_status = SNMP_ERR_GENERROR;
272  }
273  }
274  } else {
275  /* according to RFC 1157/1905, all other errors only return genError */
276  request->error_status = SNMP_ERR_GENERROR;
277  }
278  } else {
279  vb->type = node_instance.asn1_type;
280  vb->value_len = node_instance.get_value(&node_instance, vb->value);
281  LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE);
282 
283  err = snmp_append_outbound_varbind(request, vb);
284  if (err == ERR_BUF) {
285  request->error_status = SNMP_ERR_TOOBIG;
286  } else if (err != ERR_OK) {
287  request->error_status = SNMP_ERR_GENERROR;
288  }
289 
290  if (node_instance.release_instance != NULL) {
291  node_instance.release_instance(&node_instance);
292  }
293  }
294 }
295 
296 
302 static err_t
303 snmp_process_get_request(struct snmp_request *request)
304 {
305  snmp_vb_enumerator_err_t err;
306  struct snmp_varbind vb;
307  vb.value = request->value_buffer;
308 
309  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n"));
310 
311  while (request->error_status == SNMP_ERR_NOERROR) {
312  err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
313  if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
314  if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
315  snmp_process_varbind(request, &vb, 0);
316  } else {
317  request->error_status = SNMP_ERR_GENERROR;
318  }
319  } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
320  /* no more varbinds in request */
321  break;
322  } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
323  /* malformed ASN.1, don't answer */
324  return ERR_ABRT;
325  } else {
326  request->error_status = SNMP_ERR_GENERROR;
327  }
328  }
329 
330  return ERR_OK;
331 }
332 
338 static err_t
339 snmp_process_getnext_request(struct snmp_request *request)
340 {
341  snmp_vb_enumerator_err_t err;
342  struct snmp_varbind vb;
343  vb.value = request->value_buffer;
344 
345  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n"));
346 
347  while (request->error_status == SNMP_ERR_NOERROR) {
348  err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
349  if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
350  if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
351  snmp_process_varbind(request, &vb, 1);
352  } else {
353  request->error_status = SNMP_ERR_GENERROR;
354  }
355  } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
356  /* no more varbinds in request */
357  break;
358  } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
359  /* malformed ASN.1, don't answer */
360  return ERR_ABRT;
361  } else {
362  request->error_status = SNMP_ERR_GENERROR;
363  }
364  }
365 
366  return ERR_OK;
367 }
368 
374 static err_t
375 snmp_process_getbulk_request(struct snmp_request *request)
376 {
377  snmp_vb_enumerator_err_t err;
378  s32_t non_repeaters = request->non_repeaters;
379  s32_t repetitions;
380  u16_t repetition_offset = 0;
381  struct snmp_varbind_enumerator repetition_varbind_enumerator;
382  struct snmp_varbind vb;
383  vb.value = request->value_buffer;
384 
386  repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS);
387  } else {
388  repetitions = request->max_repetitions;
389  }
390 
391  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n"));
392 
393  /* process non repeaters and first repetition */
394  while (request->error_status == SNMP_ERR_NOERROR) {
395  if (non_repeaters == 0) {
396  repetition_offset = request->outbound_pbuf_stream.offset;
397 
398  if (repetitions == 0) {
399  /* do not resolve repeaters when repetitions is set to 0 */
400  break;
401  }
402  repetitions--;
403  }
404 
405  err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
406  if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
407  /* no more varbinds in request */
408  break;
409  } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
410  /* malformed ASN.1, don't answer */
411  return ERR_ABRT;
412  } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) {
413  request->error_status = SNMP_ERR_GENERROR;
414  } else {
415  snmp_process_varbind(request, &vb, 1);
416  non_repeaters--;
417  }
418  }
419 
420  /* process repetitions > 1 */
421  while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) {
422 
423  u8_t all_endofmibview = 1;
424 
425  snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset);
426  repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */
427 
428  while (request->error_status == SNMP_ERR_NOERROR) {
429  vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */
430  err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb);
431  if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
432  vb.value = request->value_buffer;
433  snmp_process_varbind(request, &vb, 1);
434 
435  if (request->error_status != SNMP_ERR_NOERROR) {
436  /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */
437  request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
438  } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) {
439  all_endofmibview = 0;
440  }
441  } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
442  /* no more varbinds in request */
443  break;
444  } else {
445  LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!"));
446  request->error_status = SNMP_ERR_GENERROR;
447  request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
448  }
449  }
450 
451  if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) {
452  /* stop when all varbinds in a loop return EndOfMibView */
453  break;
454  }
455 
456  repetitions--;
457  }
458 
459  if (request->error_status == SNMP_ERR_TOOBIG) {
460  /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */
461  request->error_status = SNMP_ERR_NOERROR;
462  }
463 
464  return ERR_OK;
465 }
466 
472 static err_t
473 snmp_process_set_request(struct snmp_request *request)
474 {
475  snmp_vb_enumerator_err_t err;
476  struct snmp_varbind vb;
477  vb.value = request->value_buffer;
478 
479  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n"));
480 
481  /* perform set test on all objects */
482  while (request->error_status == SNMP_ERR_NOERROR) {
483  err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
484  if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
485  struct snmp_node_instance node_instance;
486  memset(&node_instance, 0, sizeof(node_instance));
487 
488  request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
489  if (request->error_status == SNMP_ERR_NOERROR)
490  {
491  if (node_instance.asn1_type != vb.type) {
492  request->error_status = SNMP_ERR_WRONGTYPE;
493  } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) {
494  request->error_status = SNMP_ERR_NOTWRITABLE;
495  } else {
496  if (node_instance.set_test != NULL) {
497  request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value);
498  }
499  }
500 
501  if (node_instance.release_instance != NULL) {
502  node_instance.release_instance(&node_instance);
503  }
504  }
505  }
506  else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
507  /* no more varbinds in request */
508  break;
509  } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) {
510  request->error_status = SNMP_ERR_WRONGLENGTH;
511  } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
512  /* malformed ASN.1, don't answer */
513  return ERR_ABRT;
514  } else {
515  request->error_status = SNMP_ERR_GENERROR;
516  }
517  }
518 
519  /* perform real set operation on all objects */
520  if (request->error_status == SNMP_ERR_NOERROR) {
521  snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
522  while (request->error_status == SNMP_ERR_NOERROR) {
523  err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
524  if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
525  struct snmp_node_instance node_instance;
526  memset(&node_instance, 0, sizeof(node_instance));
527  request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
528  if (request->error_status == SNMP_ERR_NOERROR)
529  {
530  if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR)
531  {
532  if (request->inbound_varbind_enumerator.varbind_count == 1) {
533  request->error_status = SNMP_ERR_COMMITFAILED;
534  } else {
535  /* we cannot undo the set operations done so far */
536  request->error_status = SNMP_ERR_UNDOFAILED;
537  }
538  }
539 
540  if (node_instance.release_instance != NULL) {
541  node_instance.release_instance(&node_instance);
542  }
543  }
544  } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
545  /* no more varbinds in request */
546  break;
547  } else {
548  /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */
549  request->error_status = SNMP_ERR_GENERROR;
550  }
551  }
552  }
553 
554  return ERR_OK;
555 }
556 
557 #define PARSE_EXEC(code, retValue) \
558  if ((code) != ERR_OK) { \
559  LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \
560  snmp_stats.inasnparseerrs++; \
561  return retValue; \
562  }
563 
564 #define PARSE_ASSERT(cond, retValue) \
565  if (!(cond)) { \
566  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \
567  snmp_stats.inasnparseerrs++; \
568  return retValue; \
569  }
570 
571 #define BUILD_EXEC(code, retValue) \
572  if ((code) != ERR_OK) { \
573  LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \
574  return retValue; \
575  }
576 
577 #define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ABRT)
578 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ABRT)
579 
588 static err_t
589 snmp_parse_inbound_frame(struct snmp_request *request)
590 {
591  struct snmp_pbuf_stream pbuf_stream;
592  struct snmp_asn1_tlv tlv;
593  s32_t parent_tlv_value_len;
594  s32_t s32_value;
595  err_t err;
596 
597  IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
598 
599  /* decode main container consisting of version, community and PDU */
600  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
601  IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
602  parent_tlv_value_len = tlv.value_len;
603 
604  /* decode version */
605  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
606  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
607  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
608  IF_PARSE_ASSERT(parent_tlv_value_len > 0);
609 
610  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
611  if ((s32_value != SNMP_VERSION_1) && (s32_value != SNMP_VERSION_2c)) {
612  /* unsupported SNMP version */
613  snmp_stats.inbadversions++;
614  return ERR_ABRT;
615  }
616  request->version = (u8_t)s32_value;
617 
618  /* decode community */
619  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
620  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
621  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
622  IF_PARSE_ASSERT(parent_tlv_value_len > 0);
623 
624  err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN);
625  if (err == ERR_MEM) {
626  /* community string does not fit in our buffer -> its too long -> its invalid */
627  request->community_strlen = 0;
628  snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len);
629  } else {
630  IF_PARSE_ASSERT(err == ERR_OK);
631  }
632  /* add zero terminator */
633  request->community[request->community_strlen] = 0;
634 
635  /* decode PDU type (next container level) */
636  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
637  IF_PARSE_ASSERT(tlv.value_len == pbuf_stream.length);
638  parent_tlv_value_len = tlv.value_len;
639 
640  /* validate PDU type */
641  switch(tlv.type) {
642  case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ):
643  /* GetRequest PDU */
644  snmp_stats.ingetrequests++;
645  break;
646  case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ):
647  /* GetNextRequest PDU */
648  snmp_stats.ingetnexts++;
649  break;
650  case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ):
651  /* GetBulkRequest PDU */
652  if (request->version < SNMP_VERSION_2c) {
653  /* RFC2089: invalid, drop packet */
654  return ERR_ABRT;
655  }
656  break;
657  case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ):
658  /* SetRequest PDU */
659  snmp_stats.insetrequests++;
660  break;
661  default:
662  /* unsupported input PDU for this agent (no parse error) */
663  LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \
664  return ERR_ABRT;
665  break;
666  }
667  request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK;
668 
669  /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */
670  if (request->community_strlen == 0) {
671  /* community string was too long or really empty*/
672  snmp_stats.inbadcommunitynames++;
673  snmp_authfail_trap();
674  return ERR_ABRT;
675  } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
676  if (strnlen(snmp_community_write, SNMP_MAX_COMMUNITY_STR_LEN) == 0) {
677  /* our write community is empty, that means all our objects are readonly */
678  request->error_status = SNMP_ERR_NOTWRITABLE;
679  request->error_index = 1;
680  } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
681  /* community name does not match */
682  snmp_stats.inbadcommunitynames++;
683  snmp_authfail_trap();
684  return ERR_ABRT;
685  }
686  } else {
687  if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
688  /* community name does not match */
689  snmp_stats.inbadcommunitynames++;
690  snmp_authfail_trap();
691  return ERR_ABRT;
692  }
693  }
694 
695  /* decode request ID */
696  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
697  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
698  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
699  IF_PARSE_ASSERT(parent_tlv_value_len > 0);
700 
701  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id));
702 
703  /* decode error status / non-repeaters */
704  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
705  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
706  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
707  IF_PARSE_ASSERT(parent_tlv_value_len > 0);
708 
709  if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
710  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters));
711  if (request->non_repeaters < 0) {
712  /* RFC 1905, 4.2.3 */
713  request->non_repeaters = 0;
714  }
715  } else {
716  /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */
717  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
718  IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR);
719  }
720 
721  /* decode error index / max-repetitions */
722  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
723  IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
724  parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
725  IF_PARSE_ASSERT(parent_tlv_value_len > 0);
726 
727  if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
728  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions));
729  if (request->max_repetitions < 0) {
730  /* RFC 1905, 4.2.3 */
731  request->max_repetitions = 0;
732  }
733  } else {
734  IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index));
735  IF_PARSE_ASSERT(s32_value == 0);
736  }
737 
738  /* decode varbind-list type (next container level) */
739  IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
740  IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
741 
742  request->inbound_varbind_offset = pbuf_stream.offset;
743  request->inbound_varbind_len = pbuf_stream.length;
744  snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
745 
746  return ERR_OK;
747 }
748 
749 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ABRT)
750 
751 static err_t
752 snmp_prepare_outbound_frame(struct snmp_request *request)
753 {
754  struct snmp_asn1_tlv tlv;
755  struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream);
756 
757  /* try allocating pbuf(s) for maximum response size */
758  request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM);
759  if (request->outbound_pbuf == NULL) {
760  return ERR_MEM;
761  }
762 
763  snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len);
764 
765  /* 'Message' sequence */
766  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
767  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
768 
769  /* version */
770  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
771  snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len);
772  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
773  OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) );
774 
775  /* community */
776  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen);
777  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
778  OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) );
779 
780  /* 'PDU' sequence */
781  request->outbound_pdu_offset = pbuf_stream->offset;
782  SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0);
783  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
784 
785  /* request ID */
786  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
787  snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len);
788  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
789  OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) );
790 
791  /* error status */
792  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
793  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
794  request->outbound_error_status_offset = pbuf_stream->offset;
795  OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
796 
797  /* error index */
798  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
799  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
800  request->outbound_error_index_offset = pbuf_stream->offset;
801  OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
802 
803  /* 'VarBindList' sequence */
804  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
805  OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
806 
807  request->outbound_varbind_offset = pbuf_stream->offset;
808 
809  return ERR_OK;
810 }
811 
812 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ABRT)
813 
814 static err_t
815 snmp_append_outbound_varbind(struct snmp_request *request, struct snmp_varbind* varbind)
816 {
817  struct snmp_asn1_tlv tlv;
818  u8_t vb_len_len, oid_len_len, value_len_len;
819  u16_t vb_value_len, oid_value_len, value_value_len;
820 
821  /* calculate required lengths */
822  snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &oid_value_len);
823  snmp_asn1_enc_length_cnt(oid_value_len, &oid_len_len);
824 
825  if (varbind->value_len == 0) {
826  value_value_len = 0;
827  } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
828  value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA);
829  } else {
830  switch (varbind->type)
831  {
832  case SNMP_ASN1_TYPE_INTEGER:
833  if (varbind->value_len != sizeof(s32_t)) {
834  return ERR_VAL;
835  }
836  snmp_asn1_enc_s32t_cnt(*((s32_t*)varbind->value) , &value_value_len);
837  break;
838  case SNMP_ASN1_TYPE_COUNTER:
839  case SNMP_ASN1_TYPE_GAUGE:
840  case SNMP_ASN1_TYPE_TIMETICKS:
841  if (varbind->value_len != sizeof(u32_t)) {
842  return ERR_VAL;
843  }
844  snmp_asn1_enc_u32t_cnt(*((u32_t*)varbind->value) , &value_value_len);
845  break;
846  case SNMP_ASN1_TYPE_OCTET_STRING:
847  case SNMP_ASN1_TYPE_IPADDR:
848  case SNMP_ASN1_TYPE_OPAQUE:
849  value_value_len = varbind->value_len;
850  break;
851  case SNMP_ASN1_TYPE_NULL:
852  if (varbind->value_len != 0) {
853  return ERR_VAL;
854  }
855  value_value_len = 0;
856  break;
857  case SNMP_ASN1_TYPE_OBJECT_ID:
858  if ((varbind->value_len % sizeof(u32_t)) != 0) {
859  return ERR_VAL;
860  }
861  snmp_asn1_enc_oid_cnt((u32_t*)varbind->value, varbind->value_len / sizeof(u32_t), &value_value_len);
862  break;
863  case SNMP_ASN1_TYPE_COUNTER64:
864  if (varbind->value_len != (2 * sizeof(u32_t))) {
865  return ERR_VAL;
866  }
867  snmp_asn1_enc_u64t_cnt((u32_t*)varbind->value , &value_value_len);
868  break;
869  default:
870  /* unsupported type */
871  return ERR_VAL;
872  }
873  }
874  snmp_asn1_enc_length_cnt(value_value_len, &value_len_len);
875 
876  vb_value_len = 1 + oid_len_len + oid_value_len + 1 + value_len_len + value_value_len;
877  snmp_asn1_enc_length_cnt(vb_value_len, &vb_len_len);
878 
879  /* check length already before adding first data because in case of GetBulk,
880  * data added so far is returned and therefore no partial data shall be added
881  */
882  if ((1 + vb_len_len + vb_value_len) > request->outbound_pbuf_stream.length) {
883  return ERR_BUF;
884  }
885 
886  /* 'VarBind' sequence */
887  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, vb_len_len, vb_value_len);
888  OVB_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
889 
890  /* VarBind OID */
891  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, oid_len_len, oid_value_len);
892  OVB_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
893  OVB_BUILD_EXEC( snmp_asn1_enc_oid(&(request->outbound_pbuf_stream), varbind->oid.id, varbind->oid.len) );
894 
895  /* VarBind value */
896  SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, value_len_len, value_value_len);
897  OVB_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
898 
899  if (value_value_len > 0) {
900  if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
901  OVB_BUILD_EXEC( snmp_asn1_enc_raw(&(request->outbound_pbuf_stream), (u8_t*)varbind->value, value_value_len) );
902  } else {
903  switch (varbind->type)
904  {
905  case SNMP_ASN1_TYPE_INTEGER:
906  OVB_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), value_value_len, *((s32_t*)varbind->value)) );
907  break;
908  case SNMP_ASN1_TYPE_COUNTER:
909  case SNMP_ASN1_TYPE_GAUGE:
910  case SNMP_ASN1_TYPE_TIMETICKS:
911  OVB_BUILD_EXEC( snmp_asn1_enc_u32t(&(request->outbound_pbuf_stream), value_value_len, *((u32_t*)varbind->value)) );
912  break;
913  case SNMP_ASN1_TYPE_OCTET_STRING:
914  case SNMP_ASN1_TYPE_IPADDR:
915  case SNMP_ASN1_TYPE_OPAQUE:
916  OVB_BUILD_EXEC( snmp_asn1_enc_raw(&(request->outbound_pbuf_stream), (u8_t*)varbind->value, value_value_len) );
917  value_value_len = varbind->value_len;
918  break;
919  case SNMP_ASN1_TYPE_OBJECT_ID:
920  OVB_BUILD_EXEC( snmp_asn1_enc_oid(&(request->outbound_pbuf_stream), (u32_t*)varbind->value, varbind->value_len / sizeof(u32_t)) );
921  break;
922  case SNMP_ASN1_TYPE_COUNTER64:
923  OVB_BUILD_EXEC( snmp_asn1_enc_u64t(&(request->outbound_pbuf_stream), value_value_len, (u32_t*)varbind->value) );
924  break;
925  default:
926  LWIP_ASSERT("Unknown variable type", 0);
927  break;
928  }
929  }
930  }
931 
932  return ERR_OK;
933 }
934 
935 static err_t
936 snmp_complete_outbound_frame(struct snmp_request *request)
937 {
938  struct snmp_asn1_tlv tlv;
939  u16_t frame_size;
940 
941  if (request->version == SNMP_VERSION_1) {
942  if (request->error_status != SNMP_ERR_NOERROR) {
943  /* map v2c error codes to v1 compliant error code (according to RFC 2089) */
944  switch (request->error_status) {
945  /* mapping of implementation specific "virtual" error codes
946  * (during processing of frame we already stored them in error_status field,
947  * so no need to check all varbinds here for those exceptions as suggested by RFC) */
948  case SNMP_ERR_NOSUCHINSTANCE:
949  case SNMP_ERR_NOSUCHOBJECT:
950  case SNMP_ERR_ENDOFMIBVIEW:
951  request->error_status = SNMP_ERR_NOSUCHNAME; break;
952  /* mapping according to RFC */
953  case SNMP_ERR_WRONGVALUE:
954  case SNMP_ERR_WRONGENCODING:
955  case SNMP_ERR_WRONGTYPE:
956  case SNMP_ERR_WRONGLENGTH:
957  case SNMP_ERR_INCONSISTENTVALUE:
958  request->error_status = SNMP_ERR_BADVALUE; break;
959  case SNMP_ERR_NOACCESS:
960  case SNMP_ERR_NOTWRITABLE:
961  case SNMP_ERR_NOCREATION:
962  case SNMP_ERR_INCONSISTENTNAME:
963  case SNMP_ERR_AUTHORIZATIONERROR:
964  request->error_status = SNMP_ERR_NOSUCHNAME; break;
965  case SNMP_ERR_RESOURCEUNAVAILABLE:
966  case SNMP_ERR_COMMITFAILED:
967  case SNMP_ERR_UNDOFAILED:
968  default:
969  request->error_status = SNMP_ERR_GENERROR; break;
970  }
971  }
972  } else {
973  if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
974  /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */
975  LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n"));
976  return ERR_ABRT;
977  }
978  }
979 
980  if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) {
981  /* all inbound vars are returned in response without any modification for error responses and successful set requests*/
982  struct snmp_pbuf_stream inbound_stream;
983  OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) );
984  OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, request->outbound_varbind_offset, request->outbound_pbuf->tot_len - request->outbound_varbind_offset) );
985  snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0);
986  }
987 
988  frame_size = request->outbound_pbuf_stream.offset;
989 
990  /* complete mssing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */
991  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
992  OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) );
993  OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
994 
995  /* complete mssing length in 'PDU' sequence */
996  SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
997  OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) );
998  OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
999 
1000  /* process and encode final error status */
1001  if (request->error_status != 0) {
1002  u16_t len;
1003  snmp_asn1_enc_s32t_cnt(request->error_status, &len);
1004  if (len != 1) {
1005  /* error, we only reserved one byte for it */
1006  return ERR_ABRT;
1007  }
1008  OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) );
1009  OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) );
1010 
1011  /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */
1012  switch (request->error_status) {
1013  case SNMP_ERR_TOOBIG:
1014  snmp_stats.outtoobigs++;
1015  break;
1016  case SNMP_ERR_NOSUCHNAME:
1017  snmp_stats.outnosuchnames++;
1018  break;
1019  case SNMP_ERR_BADVALUE:
1020  snmp_stats.outbadvalues++;
1021  break;
1022  case SNMP_ERR_GENERROR:
1023  default:
1024  snmp_stats.outgenerrs++;
1025  break;
1026  }
1027 
1028  if (request->error_status == SNMP_ERR_TOOBIG) {
1029  request->error_index = 0; /* defined by RFC 1157 */
1030  } else if (request->error_index == 0) {
1031  /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */
1032  request->error_index = request->inbound_varbind_enumerator.varbind_count;
1033  }
1034  } else {
1035  if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1036  snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count;
1037  } else {
1038  snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count;
1039  }
1040  }
1041 
1042  /* encode final error index*/
1043  if (request->error_index != 0) {
1044  u16_t len;
1045  snmp_asn1_enc_s32t_cnt(request->error_index, &len);
1046  if (len != 1) {
1047  /* error, we only reserved one byte for it */
1048  return ERR_VAL;
1049  }
1050  OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) );
1051  OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) );
1052  }
1053 
1054  /* complete mssing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */
1055  SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset);
1056  OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_varbind_offset - 1 - 3) ); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1057  OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1058 
1059  pbuf_realloc(request->outbound_pbuf, frame_size);
1060 
1061  snmp_stats.outgetresponses++;
1062  snmp_stats.outpkts++;
1063 
1064  return ERR_OK;
1065 }
1066 
1067 static void
1068 snmp_execute_write_callbacks(struct snmp_request *request)
1069 {
1070  struct snmp_varbind_enumerator inbound_varbind_enumerator;
1071  struct snmp_varbind vb;
1072 
1073  snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
1074  vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */
1075 
1076  while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == ERR_OK) {
1077  snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg);
1078  }
1079 }
1080 
1081 
1082 /* ----------------------------------------------------------------------- */
1083 /* VarBind enumerator methods */
1084 /* ----------------------------------------------------------------------- */
1085 
1086 void
1087 snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length)
1088 {
1089  snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length);
1090  enumerator->varbind_count = 0;
1091 }
1092 
1093 #define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1094 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1095 
1096 snmp_vb_enumerator_err_t
1097 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind)
1098 {
1099  struct snmp_asn1_tlv tlv;
1100  u16_t varbind_len;
1101  err_t err;
1102 
1103  if (enumerator->pbuf_stream.length == 0)
1104  {
1105  return SNMP_VB_ENUMERATOR_ERR_EOVB;
1106  }
1107  enumerator->varbind_count++;
1108 
1109  /* decode varbind itself (parent container of a varbind) */
1110  VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1111  VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length));
1112  varbind_len = tlv.value_len;
1113 
1114  /* decode varbind name (object id) */
1115  VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1116  VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length));
1117 
1118  VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN));
1119  varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1120 
1121  /* decode varbind value (object id) */
1122  VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1123  VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length));
1124  varbind->type = tlv.type;
1125 
1126  /* shall the value be decoded ? */
1127  if (varbind->value != NULL) {
1128  switch (varbind->type) {
1129  case SNMP_ASN1_TYPE_INTEGER:
1130  VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value));
1131  varbind->value_len = sizeof(s32_t*);
1132  break;
1133  case SNMP_ASN1_TYPE_COUNTER:
1134  case SNMP_ASN1_TYPE_GAUGE:
1135  case SNMP_ASN1_TYPE_TIMETICKS:
1136  VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1137  varbind->value_len = sizeof(u32_t*);
1138  break;
1139  case SNMP_ASN1_TYPE_OCTET_STRING:
1140  case SNMP_ASN1_TYPE_OPAQUE:
1141  err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE);
1142  if (err == ERR_MEM) {
1143  return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1144  }
1145  VB_PARSE_ASSERT(err == ERR_OK);
1146  break;
1147  case SNMP_ASN1_TYPE_NULL:
1148  varbind->value_len = 0;
1149  break;
1150  case SNMP_ASN1_TYPE_OBJECT_ID:
1151  /* misuse tlv.length_len as OID_length transporter */
1152  err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN);
1153  if (err == ERR_MEM) {
1154  return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1155  }
1156  VB_PARSE_ASSERT(err == ERR_OK);
1157  varbind->value_len = tlv.length_len * sizeof(u32_t);
1158  break;
1159  case SNMP_ASN1_TYPE_IPADDR:
1160  if (tlv.value_len == 4) {
1161  /* must be exactly 4 octets! */
1162  VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE));
1163  } else {
1164  VB_PARSE_ASSERT(0);
1165  }
1166  break;
1167  case SNMP_ASN1_TYPE_COUNTER64:
1168  VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1169  varbind->value_len = 2 * sizeof(u32_t*);
1170  break;
1171  default:
1172  VB_PARSE_ASSERT(0);
1173  break;
1174  }
1175  } else {
1176  snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len);
1177  varbind->value_len = tlv.value_len;
1178  }
1179 
1180  return SNMP_VB_ENUMERATOR_ERR_OK;
1181 }
1182 
1183 #endif /* LWIP_SNMP */
#define SNMP_COMMUNITY_WRITE
Definition: snmp_opts.h:144
#define SNMP_LWIP_GETBULK_MAX_REPETITIONS
Definition: snmp_opts.h:246
void pbuf_realloc(struct pbuf *p, u16_t new_len)
Definition: pbuf.c:431
#define ERR_VAL
Definition: err.h:58
#define SNMP_MAX_OBJ_ID_LEN
Definition: snmp_opts.h:120
struct pbuf * pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
Definition: pbuf.c:199
Definition: pbuf.h:77
#define ERR_ABRT
Definition: err.h:67
#define LWIP_MIN(x, y)
Definition: def.h:50
#define NULL
Definition: usbd_def.h:53
u8_t pbuf_free(struct pbuf *p)
Definition: pbuf.c:652
unsigned long u32_t
Definition: cc.h:42
#define ERR_OK
Definition: err.h:52
Definition: pbuf.h:108
s8_t err_t
Definition: err.h:47
#define LWIP_ASSERT(message, assertion)
Definition: debug.h:70
#define SNMP_COMMUNITY_TRAP
Definition: snmp_opts.h:151
#define SNMP_MAX_COMMUNITY_STR_LEN
Definition: snmp_opts.h:160
#define SNMP_DEBUG
Definition: snmp_opts.h:189
unsigned char u8_t
Definition: cc.h:38
ip6_addr_t ip_addr_t
Definition: ip_addr.h:194
signed long s32_t
Definition: cc.h:43
#define SNMP_MAX_VALUE_SIZE
Definition: snmp_opts.h:128
#define LWIP_DEBUGF(debug, message)
Definition: debug.h:113
#define ERR_MEM
Definition: err.h:53
#define SNMP_COMMUNITY
Definition: snmp_opts.h:136
unsigned short u16_t
Definition: cc.h:40
#define ERR_BUF
Definition: err.h:54