xref: /minix/minix/lib/liblwip/dist/src/apps/snmp/snmp_msg.c (revision fb9c64b2)
1 /**
2  * @file
3  * SNMP message processing (RFC1157).
4  */
5 
6 /*
7  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
8  * Copyright (c) 2016 Elias Oenal.
9  * All rights reserved.
10  *
11  * Redistribution and use in source and binary forms, with or without modification,
12  * are permitted provided that the following conditions are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright notice,
15  *    this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright notice,
17  *    this list of conditions and the following disclaimer in the documentation
18  *    and/or other materials provided with the distribution.
19  * 3. The name of the author may not be used to endorse or promote products
20  *    derived from this software without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
23  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
24  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
26  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
27  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
30  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
31  * OF SUCH DAMAGE.
32  *
33  * Author: Christiaan Simons <christiaan.simons@axon.tv>
34  *         Martin Hentschel <info@cl-soft.de>
35  *         Elias Oenal <lwip@eliasoenal.com>
36  */
37 
38 #include "lwip/apps/snmp_opts.h"
39 
40 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
41 
42 #include "snmp_msg.h"
43 #include "snmp_asn1.h"
44 #include "snmp_core_priv.h"
45 #include "lwip/ip_addr.h"
46 #include "lwip/stats.h"
47 
48 #if LWIP_SNMP_V3
49 #include "lwip/apps/snmpv3.h"
50 #include "snmpv3_priv.h"
51 #ifdef LWIP_HOOK_FILENAME
52 #include LWIP_HOOK_FILENAME
53 #endif
54 #endif
55 
56 #include <string.h>
57 
58 #define SNMP_V3_AUTH_FLAG      0x01
59 #define SNMP_V3_PRIV_FLAG      0x02
60 
61 /* Security levels */
62 #define SNMP_V3_NOAUTHNOPRIV   0x00
63 #define SNMP_V3_AUTHNOPRIV     SNMP_V3_AUTH_FLAG
64 #define SNMP_V3_AUTHPRIV       (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)
65 
66 /* public (non-static) constants */
67 /** SNMP community string */
68 const char *snmp_community = SNMP_COMMUNITY;
69 /** SNMP community string for write access */
70 const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
71 /** SNMP community string for sending traps */
72 const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
73 
74 snmp_write_callback_fct snmp_write_callback     = NULL;
75 void*                   snmp_write_callback_arg = NULL;
76 
77 #if LWIP_SNMP_CONFIGURE_VERSIONS
78 
79 static u8_t v1_enabled = 1;
80 static u8_t v2c_enabled = 1;
81 static u8_t v3_enabled = 1;
82 
83 static u8_t
84 snmp_version_enabled(u8_t version)
85 {
86   LWIP_ASSERT("Invalid SNMP version", (version == SNMP_VERSION_1) || (version == SNMP_VERSION_2c)
87 #if LWIP_SNMP_V3
88      || (version == SNMP_VERSION_3)
89 #endif
90   );
91 
92   if (version == SNMP_VERSION_1) {
93     return v1_enabled;
94   }
95   else if (version == SNMP_VERSION_2c) {
96     return v2c_enabled;
97   }
98 #if LWIP_SNMP_V3
99   else { /* version == SNMP_VERSION_3 */
100     return v3_enabled;
101   }
102 #endif
103 }
104 
105 u8_t
106 snmp_v1_enabled(void)
107 {
108   return snmp_version_enabled(SNMP_VERSION_1);
109 }
110 
111 u8_t
112 snmp_v2c_enabled(void)
113 {
114   return snmp_version_enabled(SNMP_VERSION_2c);
115 }
116 
117 u8_t
118 snmp_v3_enabled(void)
119 {
120   return snmp_version_enabled(SNMP_VERSION_3);
121 }
122 
123 static void
124 snmp_version_enable(u8_t version, u8_t enable)
125 {
126   LWIP_ASSERT("Invalid SNMP version", (version == SNMP_VERSION_1) || (version == SNMP_VERSION_2c)
127 #if LWIP_SNMP_V3
128      || (version == SNMP_VERSION_3)
129 #endif
130     );
131 
132   if (version == SNMP_VERSION_1) {
133     v1_enabled = enable;
134   }
135   else if (version == SNMP_VERSION_2c) {
136     v2c_enabled = enable;
137   }
138 #if LWIP_SNMP_V3
139   else { /* version == SNMP_VERSION_3 */
140     v3_enabled = enable;
141   }
142 #endif
143 }
144 
145 void
146 snmp_v1_enable(u8_t enable)
147 {
148   snmp_version_enable(SNMP_VERSION_1, enable);
149 }
150 
151 void
152 snmp_v2c_enable(u8_t enable)
153 {
154   snmp_version_enable(SNMP_VERSION_2c, enable);
155 }
156 
157 void
158 snmp_v3_enable(u8_t enable)
159 {
160   snmp_version_enable(SNMP_VERSION_3, enable);
161 }
162 
163 #endif
164 
165 /**
166  * @ingroup snmp_core
167  * Returns current SNMP community string.
168  * @return current SNMP community string
169  */
170 const char *
171 snmp_get_community(void)
172 {
173   return snmp_community;
174 }
175 
176 /**
177  * @ingroup snmp_core
178  * Sets SNMP community string.
179  * The string itself (its storage) must be valid throughout the whole life of
180  * program (or until it is changed to sth else).
181  *
182  * @param community is a pointer to new community string
183  */
184 void
185 snmp_set_community(const char * const community)
186 {
187   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
188   snmp_community = community;
189 }
190 
191 /**
192  * @ingroup snmp_core
193  * Returns current SNMP write-access community string.
194  * @return current SNMP write-access community string
195  */
196 const char *
197 snmp_get_community_write(void)
198 {
199   return snmp_community_write;
200 }
201 
202 /**
203  * @ingroup snmp_traps
204  * Returns current SNMP community string used for sending traps.
205  * @return current SNMP community string used for sending traps
206  */
207 const char *
208 snmp_get_community_trap(void)
209 {
210   return snmp_community_trap;
211 }
212 
213 /**
214  * @ingroup snmp_core
215  * Sets SNMP community string for write-access.
216  * The string itself (its storage) must be valid throughout the whole life of
217  * program (or until it is changed to sth else).
218  *
219  * @param community is a pointer to new write-access community string
220  */
221 void
222 snmp_set_community_write(const char * const community)
223 {
224   LWIP_ASSERT("community string must not be NULL", community != NULL);
225   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
226   snmp_community_write = community;
227 }
228 
229 /**
230  * @ingroup snmp_traps
231  * Sets SNMP community string used for sending traps.
232  * The string itself (its storage) must be valid throughout the whole life of
233  * program (or until it is changed to sth else).
234  *
235  * @param community is a pointer to new trap community string
236  */
237 void
238 snmp_set_community_trap(const char * const community)
239 {
240   LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN);
241   snmp_community_trap = community;
242 }
243 
244 /**
245  * @ingroup snmp_core
246  * Callback fired on every successful write access
247  */
248 void
249 snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg)
250 {
251   snmp_write_callback     = write_callback;
252   snmp_write_callback_arg = callback_arg;
253 }
254 
255 /* ----------------------------------------------------------------------- */
256 /* forward declarations */
257 /* ----------------------------------------------------------------------- */
258 
259 static err_t snmp_process_get_request(struct snmp_request *request);
260 static err_t snmp_process_getnext_request(struct snmp_request *request);
261 static err_t snmp_process_getbulk_request(struct snmp_request *request);
262 static err_t snmp_process_set_request(struct snmp_request *request);
263 
264 static err_t snmp_parse_inbound_frame(struct snmp_request *request);
265 static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
266 static err_t snmp_complete_outbound_frame(struct snmp_request *request);
267 static void snmp_execute_write_callbacks(struct snmp_request *request);
268 
269 
270 /* ----------------------------------------------------------------------- */
271 /* implementation */
272 /* ----------------------------------------------------------------------- */
273 
274 void
275 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port)
276 {
277   err_t err;
278   struct snmp_request request;
279 
280   memset(&request, 0, sizeof(request));
281   request.handle       = handle;
282   request.source_ip    = source_ip;
283   request.source_port  = port;
284   request.inbound_pbuf = p;
285 
286   snmp_stats.inpkts++;
287 
288   err = snmp_parse_inbound_frame(&request);
289   if (err == ERR_OK) {
290     err = snmp_prepare_outbound_frame(&request);
291     if (err == ERR_OK) {
292 
293       if (request.error_status == SNMP_ERR_NOERROR) {
294         /* only process frame if we do not already have an error to return (e.g. all readonly) */
295         if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) {
296           err = snmp_process_get_request(&request);
297         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) {
298           err = snmp_process_getnext_request(&request);
299         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
300           err = snmp_process_getbulk_request(&request);
301         } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
302           err = snmp_process_set_request(&request);
303         }
304       }
305 #if LWIP_SNMP_V3
306       else {
307         struct snmp_varbind vb;
308 
309         vb.next = NULL;
310         vb.prev = NULL;
311         vb.type = SNMP_ASN1_TYPE_COUNTER32;
312         vb.value_len = sizeof(u32_t);
313 
314         switch (request.error_status) {
315         case SNMP_ERR_AUTHORIZATIONERROR:
316           {
317             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 5, 0 };
318             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
319             vb.value = &snmp_stats.wrongdigests;
320           }
321           break;
322         case SNMP_ERR_UNKNOWN_ENGINEID:
323           {
324             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0 };
325             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
326             vb.value = &snmp_stats.unknownengineids;
327           }
328           break;
329         case SNMP_ERR_UNKNOWN_SECURITYNAME:
330           {
331             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 3, 0 };
332             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
333             vb.value = &snmp_stats.unknownusernames;
334           }
335           break;
336         case SNMP_ERR_UNSUPPORTED_SECLEVEL:
337           {
338             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 1, 0 };
339             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
340             vb.value = &snmp_stats.unsupportedseclevels;
341           }
342           break;
343         case SNMP_ERR_NOTINTIMEWINDOW:
344           {
345             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0 };
346             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
347             vb.value = &snmp_stats.notintimewindows;
348           }
349           break;
350         case SNMP_ERR_DECRYIPTION_ERROR:
351           {
352             static const u32_t oid[] = { 1, 3, 6, 1, 6, 3, 15, 1, 1, 6, 0 };
353             snmp_oid_assign(&vb.oid, oid, LWIP_ARRAYSIZE(oid));
354             vb.value = &snmp_stats.decryptionerrors;
355           }
356           break;
357         default:
358           /* Unknown or unhandled error_status */
359           err = ERR_ARG;
360         }
361 
362         if (err == ERR_OK) {
363           snmp_append_outbound_varbind(&(request.outbound_pbuf_stream), &vb);
364           request.error_status = SNMP_ERR_NOERROR;
365         }
366 
367         request.request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_REPORT);
368         request.request_id = request.msg_id;
369       }
370 #endif
371 
372       if (err == ERR_OK) {
373         err = snmp_complete_outbound_frame(&request);
374 
375         if (err == ERR_OK) {
376           err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port);
377 
378           if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)
379             && (request.error_status == SNMP_ERR_NOERROR)
380             && (snmp_write_callback != NULL)) {
381             /* raise write notification for all written objects */
382             snmp_execute_write_callbacks(&request);
383           }
384         }
385       }
386     }
387 
388     if (request.outbound_pbuf != NULL) {
389       pbuf_free(request.outbound_pbuf);
390     }
391   }
392 }
393 
394 static u8_t
395 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg)
396 {
397   if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) {
398     return SNMP_ERR_NOSUCHINSTANCE;
399   }
400 
401   if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) {
402     /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */
403     return SNMP_ERR_NOSUCHINSTANCE;
404   }
405 
406   return SNMP_ERR_NOERROR;
407 }
408 
409 static void
410 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next)
411 {
412   err_t err;
413   struct snmp_node_instance node_instance;
414   memset(&node_instance, 0, sizeof(node_instance));
415 
416   if (get_next) {
417     struct snmp_obj_id result_oid;
418     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);
419 
420     if (request->error_status == SNMP_ERR_NOERROR) {
421       snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len);
422     }
423   } else {
424     request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance);
425 
426     if (request->error_status == SNMP_ERR_NOERROR) {
427       /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */
428       request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request);
429 
430       if (request->error_status != SNMP_ERR_NOERROR) {
431         if (node_instance.release_instance != NULL) {
432           node_instance.release_instance(&node_instance);
433         }
434       }
435     }
436   }
437 
438   if (request->error_status != SNMP_ERR_NOERROR)  {
439     if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
440       if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) {
441         /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */
442         vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK));
443         vb->value_len = 0;
444 
445         err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb);
446         if (err == ERR_OK) {
447           /* we stored the exception in varbind -> go on */
448           request->error_status = SNMP_ERR_NOERROR;
449         } else if (err == ERR_BUF) {
450           request->error_status = SNMP_ERR_TOOBIG;
451         } else {
452           request->error_status = SNMP_ERR_GENERROR;
453         }
454       }
455     } else {
456       /* according to RFC 1157/1905, all other errors only return genError */
457       request->error_status = SNMP_ERR_GENERROR;
458     }
459   } else {
460     s16_t len = node_instance.get_value(&node_instance, vb->value);
461     vb->type = node_instance.asn1_type;
462 
463     if(len >= 0) {
464       vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */
465 
466       LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE);
467       err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb);
468 
469       if (err == ERR_BUF) {
470         request->error_status = SNMP_ERR_TOOBIG;
471       } else if (err != ERR_OK) {
472         request->error_status = SNMP_ERR_GENERROR;
473       }
474     } else {
475       request->error_status = SNMP_ERR_GENERROR;
476     }
477 
478     if (node_instance.release_instance != NULL) {
479       node_instance.release_instance(&node_instance);
480     }
481   }
482 }
483 
484 
485 /**
486  * Service an internal or external event for SNMP GET.
487  *
488  * @param request points to the associated message process state
489  */
490 static err_t
491 snmp_process_get_request(struct snmp_request *request)
492 {
493   snmp_vb_enumerator_err_t err;
494   struct snmp_varbind vb;
495   vb.value = request->value_buffer;
496 
497   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n"));
498 
499   while (request->error_status == SNMP_ERR_NOERROR) {
500     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
501     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
502       if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
503         snmp_process_varbind(request, &vb, 0);
504       } else {
505         request->error_status = SNMP_ERR_GENERROR;
506       }
507     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
508       /* no more varbinds in request */
509       break;
510     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
511       /* malformed ASN.1, don't answer */
512       return ERR_ARG;
513     } else {
514       request->error_status = SNMP_ERR_GENERROR;
515     }
516   }
517 
518   return ERR_OK;
519 }
520 
521 /**
522  * Service an internal or external event for SNMP GET.
523  *
524  * @param request points to the associated message process state
525  */
526 static err_t
527 snmp_process_getnext_request(struct snmp_request *request)
528 {
529   snmp_vb_enumerator_err_t err;
530   struct snmp_varbind vb;
531   vb.value = request->value_buffer;
532 
533   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n"));
534 
535   while (request->error_status == SNMP_ERR_NOERROR) {
536     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
537     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
538       if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) {
539         snmp_process_varbind(request, &vb, 1);
540       } else {
541         request->error_status = SNMP_ERR_GENERROR;
542       }
543     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
544       /* no more varbinds in request */
545       break;
546     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
547       /* malformed ASN.1, don't answer */
548       return ERR_ARG;
549     } else {
550       request->error_status = SNMP_ERR_GENERROR;
551     }
552   }
553 
554   return ERR_OK;
555 }
556 
557 /**
558  * Service an internal or external event for SNMP GETBULKT.
559  *
560  * @param request points to the associated message process state
561  */
562 static err_t
563 snmp_process_getbulk_request(struct snmp_request *request)
564 {
565   snmp_vb_enumerator_err_t err;
566   s32_t non_repeaters     = request->non_repeaters;
567   s32_t repetitions;
568   u16_t repetition_offset = 0;
569   struct snmp_varbind_enumerator repetition_varbind_enumerator;
570   struct snmp_varbind vb;
571   vb.value = request->value_buffer;
572 
573   if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) {
574     repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS);
575   } else {
576     repetitions = request->max_repetitions;
577   }
578 
579   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n"));
580 
581   /* process non repeaters and first repetition */
582   while (request->error_status == SNMP_ERR_NOERROR) {
583     if (non_repeaters == 0) {
584       repetition_offset = request->outbound_pbuf_stream.offset;
585 
586       if (repetitions == 0) {
587         /* do not resolve repeaters when repetitions is set to 0 */
588         break;
589       }
590       repetitions--;
591     }
592 
593     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
594     if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
595       /* no more varbinds in request */
596       break;
597     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
598       /* malformed ASN.1, don't answer */
599       return ERR_ARG;
600     } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) {
601       request->error_status = SNMP_ERR_GENERROR;
602     } else {
603       snmp_process_varbind(request, &vb, 1);
604       non_repeaters--;
605     }
606   }
607 
608   /* process repetitions > 1 */
609   while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) {
610 
611     u8_t all_endofmibview = 1;
612 
613     snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset);
614     repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */
615 
616     while (request->error_status == SNMP_ERR_NOERROR) {
617       vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */
618       err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb);
619       if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
620         vb.value = request->value_buffer;
621         snmp_process_varbind(request, &vb, 1);
622 
623         if (request->error_status != SNMP_ERR_NOERROR) {
624           /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */
625           request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
626         } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) {
627           all_endofmibview = 0;
628         }
629       } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
630         /* no more varbinds in request */
631         break;
632       } else {
633         LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!"));
634         request->error_status = SNMP_ERR_GENERROR;
635         request->error_index  = request->non_repeaters + repetition_varbind_enumerator.varbind_count;
636       }
637     }
638 
639     if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) {
640       /* stop when all varbinds in a loop return EndOfMibView */
641       break;
642     }
643 
644     repetitions--;
645   }
646 
647   if (request->error_status == SNMP_ERR_TOOBIG) {
648     /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */
649     request->error_status = SNMP_ERR_NOERROR;
650   }
651 
652   return ERR_OK;
653 }
654 
655 /**
656  * Service an internal or external event for SNMP SET.
657  *
658  * @param request points to the associated message process state
659  */
660 static err_t
661 snmp_process_set_request(struct snmp_request *request)
662 {
663   snmp_vb_enumerator_err_t err;
664   struct snmp_varbind vb;
665   vb.value = request->value_buffer;
666 
667   LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n"));
668 
669   /* perform set test on all objects */
670   while (request->error_status == SNMP_ERR_NOERROR) {
671     err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
672     if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
673       struct snmp_node_instance node_instance;
674       memset(&node_instance, 0, sizeof(node_instance));
675 
676       request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
677       if (request->error_status == SNMP_ERR_NOERROR) {
678         if (node_instance.asn1_type != vb.type) {
679           request->error_status = SNMP_ERR_WRONGTYPE;
680         } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) {
681           request->error_status = SNMP_ERR_NOTWRITABLE;
682         } else {
683           if (node_instance.set_test != NULL) {
684             request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value);
685           }
686         }
687 
688         if (node_instance.release_instance != NULL) {
689           node_instance.release_instance(&node_instance);
690         }
691       }
692     } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
693       /* no more varbinds in request */
694       break;
695     } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) {
696       request->error_status = SNMP_ERR_WRONGLENGTH;
697     } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) {
698       /* malformed ASN.1, don't answer */
699       return ERR_ARG;
700     } else {
701       request->error_status = SNMP_ERR_GENERROR;
702     }
703   }
704 
705   /* perform real set operation on all objects */
706   if (request->error_status == SNMP_ERR_NOERROR) {
707     snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
708     while (request->error_status == SNMP_ERR_NOERROR) {
709       err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb);
710       if (err == SNMP_VB_ENUMERATOR_ERR_OK) {
711         struct snmp_node_instance node_instance;
712         memset(&node_instance, 0, sizeof(node_instance));
713         request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance);
714         if (request->error_status == SNMP_ERR_NOERROR) {
715           if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) {
716             if (request->inbound_varbind_enumerator.varbind_count == 1) {
717               request->error_status = SNMP_ERR_COMMITFAILED;
718             } else {
719               /* we cannot undo the set operations done so far */
720               request->error_status = SNMP_ERR_UNDOFAILED;
721             }
722           }
723 
724           if (node_instance.release_instance != NULL) {
725             node_instance.release_instance(&node_instance);
726           }
727         }
728       } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) {
729         /* no more varbinds in request */
730         break;
731       } else {
732         /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */
733         request->error_status = SNMP_ERR_GENERROR;
734       }
735     }
736   }
737 
738   return ERR_OK;
739 }
740 
741 #define PARSE_EXEC(code, retValue) \
742   if ((code) != ERR_OK) { \
743     LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \
744     snmp_stats.inasnparseerrs++; \
745     return retValue; \
746   }
747 
748 #define PARSE_ASSERT(cond, retValue) \
749   if (!(cond)) { \
750     LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \
751     snmp_stats.inasnparseerrs++; \
752     return retValue; \
753   }
754 
755 #define BUILD_EXEC(code, retValue) \
756   if ((code) != ERR_OK) { \
757     LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \
758     return retValue; \
759   }
760 
761 #define IF_PARSE_EXEC(code)   PARSE_EXEC(code, ERR_ARG)
762 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG)
763 
764 /**
765  * Checks and decodes incoming SNMP message header, logs header errors.
766  *
767  * @param request points to the current message request state return
768  * @return
769  * - ERR_OK SNMP header is sane and accepted
770  * - ERR_VAL SNMP header is either malformed or rejected
771  */
772 static err_t
773 snmp_parse_inbound_frame(struct snmp_request *request)
774 {
775   struct snmp_pbuf_stream pbuf_stream;
776   struct snmp_asn1_tlv tlv;
777   s32_t parent_tlv_value_len;
778   s32_t s32_value;
779   err_t err;
780 #if LWIP_SNMP_V3
781   snmpv3_auth_algo_t auth;
782   snmpv3_priv_algo_t priv;
783 #endif
784 
785   IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
786 
787   /* decode main container consisting of version, community and PDU */
788   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
789   IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length));
790   parent_tlv_value_len = tlv.value_len;
791 
792   /* decode version */
793   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
794   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
795   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
796   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
797 
798   IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
799 
800   if (((s32_value != SNMP_VERSION_1) &&
801       (s32_value != SNMP_VERSION_2c)
802 #if LWIP_SNMP_V3
803       && (s32_value != SNMP_VERSION_3)
804 #endif
805       )
806 #if LWIP_SNMP_CONFIGURE_VERSIONS
807       || (!snmp_version_enabled(s32_value))
808 #endif
809      )
810   {
811     /* unsupported SNMP version */
812     snmp_stats.inbadversions++;
813     return ERR_ARG;
814   }
815   request->version = (u8_t)s32_value;
816 
817 #if LWIP_SNMP_V3
818   if (request->version == SNMP_VERSION_3) {
819     u16_t u16_value;
820     u16_t inbound_msgAuthenticationParameters_offset;
821 
822     /* SNMPv3 doesn't use communities */
823     /* @todo: Differentiate read/write access */
824     strcpy((char*)request->community, snmp_community);
825     request->community_strlen = (u16_t)strlen(snmp_community);
826 
827     /* RFC3414 globalData */
828     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
829     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
830     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
831     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
832 
833     /* decode msgID */
834     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
835     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
836     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
837     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
838 
839     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
840     request->msg_id = s32_value;
841 
842     /* decode msgMaxSize */
843     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
844     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
845     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
846     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
847 
848     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
849     request->msg_max_size = s32_value;
850 
851     /* decode msgFlags */
852     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
853     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
854     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
855     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
856 
857     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
858     request->msg_flags = (u8_t)s32_value;
859 
860     /* decode msgSecurityModel */
861     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
862     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
863     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
864     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
865 
866     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
867     request->msg_security_model = s32_value;
868 
869     /* RFC3414 msgSecurityParameters
870      * The User-based Security Model defines the contents of the OCTET
871      * STRING as a SEQUENCE.
872      *
873      * We skip the protective dummy OCTET STRING header
874      * to access the SEQUENCE header.
875      */
876     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
877     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
878     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
879     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
880 
881     /* msgSecurityParameters SEQUENCE header */
882     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
883     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
884     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
885     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
886 
887     /* decode msgAuthoritativeEngineID */
888     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
889     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
890     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
891     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
892 
893     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id,
894         &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
895     request->msg_authoritative_engine_id_len = (u8_t)u16_value;
896 
897     /* msgAuthoritativeEngineBoots */
898     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
899     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
900     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
901     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
902     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots));
903 
904     /* msgAuthoritativeEngineTime */
905     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
906     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
907     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
908     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
909     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time));
910 
911     /* msgUserName */
912     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
913     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
914     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
915     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
916 
917     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name,
918         &u16_value, SNMP_V3_MAX_USER_LENGTH));
919     request->msg_user_name_len = (u8_t)u16_value;
920 
921     /* msgAuthenticationParameters */
922     memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
923     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
924     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
925     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
926     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
927     /* Remember position */
928     inbound_msgAuthenticationParameters_offset = pbuf_stream.offset;
929     LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset);
930     /* Read auth parameters */
931     /* IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); */
932     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters,
933         &u16_value, tlv.value_len));
934     request->msg_authentication_parameters_len = (u8_t)u16_value;
935 
936     /* msgPrivacyParameters */
937     memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
938     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
939     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
940     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
941     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
942 
943     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters,
944         &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
945     request->msg_privacy_parameters_len = (u8_t)u16_value;
946 
947     /* validate securityParameters here (do this after decoding because we don't want to increase other counters for wrong frames)
948      * 1) securityParameters was correctly serialized if we reach here.
949      * 2) securityParameters are already cached.
950      * 3) if msgAuthoritativeEngineID is unknown, zero-length or too long:
951          b) https://tools.ietf.org/html/rfc3414#section-7
952      */
953     {
954       const char *eid;
955       u8_t eid_len;
956 
957       snmpv3_get_engine_id(&eid, &eid_len);
958 
959       if ((request->msg_authoritative_engine_id_len == 0) ||
960           (request->msg_authoritative_engine_id_len != eid_len) ||
961           (memcmp(eid, request->msg_authoritative_engine_id, eid_len) != 0)) {
962         snmp_stats.unknownengineids++;
963         request->msg_flags = 0; /* noauthnopriv */
964         request->error_status = SNMP_ERR_UNKNOWN_ENGINEID;
965         return ERR_OK;
966       }
967     }
968 
969     /* 4) verify username */
970     if(snmpv3_get_user((char*)request->msg_user_name, &auth, NULL, &priv, NULL)) {
971       snmp_stats.unknownusernames++;
972       request->msg_flags = 0; /* noauthnopriv */
973       request->error_status = SNMP_ERR_UNKNOWN_SECURITYNAME;
974       return ERR_OK;
975     }
976 
977     /* 5) verify security level */
978     switch(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG)) {
979     case SNMP_V3_NOAUTHNOPRIV:
980       if ((auth != SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) {
981         /* Invalid security level for user */
982         snmp_stats.unsupportedseclevels++;
983         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
984         request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
985         return ERR_OK;
986       }
987       break;
988 #if LWIP_SNMP_V3_CRYPTO
989     case SNMP_V3_AUTHNOPRIV:
990       if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv != SNMP_V3_PRIV_ALGO_INVAL)) {
991         /* Invalid security level for user */
992         snmp_stats.unsupportedseclevels++;
993         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
994         request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
995         return ERR_OK;
996       }
997       break;
998     case SNMP_V3_AUTHPRIV:
999       if ((auth == SNMP_V3_AUTH_ALGO_INVAL) || (priv == SNMP_V3_PRIV_ALGO_INVAL)) {
1000         /* Invalid security level for user */
1001         snmp_stats.unsupportedseclevels++;
1002         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1003         request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
1004         return ERR_OK;
1005       }
1006       break;
1007 #endif
1008     default:
1009       snmp_stats.unsupportedseclevels++;
1010       request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1011       request->error_status = SNMP_ERR_UNSUPPORTED_SECLEVEL;
1012       return ERR_OK;
1013     }
1014 
1015     /* 6) if securitylevel specifies authentication, authenticate message. */
1016 #if LWIP_SNMP_V3_CRYPTO
1017     if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
1018       const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 };
1019       u8_t key[20];
1020       u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)];
1021       struct snmp_pbuf_stream auth_stream;
1022 
1023       if (request->msg_authentication_parameters_len > SNMP_V3_MAX_AUTH_PARAM_LENGTH) {
1024         snmp_stats.wrongdigests++;
1025         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1026         request->error_status = SNMP_ERR_AUTHORIZATIONERROR;
1027         return ERR_OK;
1028       }
1029 
1030       /* Rewind stream */
1031       IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
1032       IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&auth_stream, inbound_msgAuthenticationParameters_offset));
1033       /* Set auth parameters to zero for verification */
1034       IF_PARSE_EXEC(snmp_asn1_enc_raw(&auth_stream, zero_arr, request->msg_authentication_parameters_len));
1035 
1036       /* Verify authentication */
1037       IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len));
1038 
1039       IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, &auth, key, NULL, NULL));
1040       IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, auth, hmac));
1041 
1042       if(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)) {
1043         snmp_stats.wrongdigests++;
1044         request->msg_flags = SNMP_V3_NOAUTHNOPRIV;
1045         request->error_status = SNMP_ERR_AUTHORIZATIONERROR;
1046         return ERR_OK;
1047       }
1048 
1049       /* 7) if securitylevel specifies authentication, verify engineboots, enginetime and lastenginetime */
1050       {
1051         s32_t boots = snmpv3_get_engine_boots_internal();
1052         if ((request->msg_authoritative_engine_boots != boots) || (boots == 2147483647UL)) {
1053           snmp_stats.notintimewindows++;
1054           request->msg_flags = SNMP_V3_AUTHNOPRIV;
1055           request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
1056           return ERR_OK;
1057         }
1058       }
1059       {
1060         s32_t time = snmpv3_get_engine_time_internal();
1061         if (request->msg_authoritative_engine_time > time) {
1062           snmp_stats.notintimewindows++;
1063           request->msg_flags = SNMP_V3_AUTHNOPRIV;
1064           request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
1065           return ERR_OK;
1066         }
1067         else if (time > 150) {
1068           if (request->msg_authoritative_engine_time < time - 150) {
1069             snmp_stats.notintimewindows++;
1070             request->msg_flags = SNMP_V3_AUTHNOPRIV;
1071             request->error_status = SNMP_ERR_NOTINTIMEWINDOW;
1072             return ERR_OK;
1073           }
1074         }
1075       }
1076     }
1077 #endif
1078 
1079     /* 8) if securitylevel specifies privacy, decrypt message. */
1080 #if LWIP_SNMP_V3_CRYPTO
1081     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1082       /* Decrypt message */
1083 
1084       u8_t key[20];
1085 
1086       IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1087       IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1088       parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
1089       IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1090 
1091       IF_PARSE_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &priv, key));
1092       if(snmpv3_crypt(&pbuf_stream, tlv.value_len, key,
1093           request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
1094           request->msg_authoritative_engine_time, priv, SNMP_V3_PRIV_MODE_DECRYPT) != ERR_OK) {
1095         snmp_stats.decryptionerrors++;
1096         request->msg_flags = SNMP_V3_AUTHNOPRIV;
1097         request->error_status = SNMP_ERR_DECRYIPTION_ERROR;
1098         return ERR_OK;
1099       }
1100     }
1101 #endif
1102     /* 9) calculate max size of scoped pdu?
1103      * 10) securityname for user is retrieved from usertable?
1104      * 11) security data is cached?
1105      * 12)
1106      */
1107 
1108     /* Scoped PDU
1109      * Encryption context
1110      */
1111     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1112     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE);
1113     parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv);
1114     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1115 
1116     /* contextEngineID */
1117     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1118     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1119     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1120     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1121 
1122     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id,
1123         &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
1124     request->context_engine_id_len = (u8_t)u16_value;
1125     /* TODO: do we need to verify this contextengineid too? */
1126 
1127     /* contextName */
1128     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1129     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1130     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1131     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1132 
1133     IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name,
1134         &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH));
1135     request->context_name_len = (u8_t)u16_value;
1136     /* TODO: do we need to verify this contextname too? */
1137   } else
1138 #endif
1139   {
1140     /* decode community */
1141     IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1142     IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING);
1143     parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1144     IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1145 
1146     err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN);
1147     if (err == ERR_MEM) {
1148       /* community string does not fit in our buffer -> its too long -> its invalid */
1149       request->community_strlen = 0;
1150       snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len);
1151     } else {
1152       IF_PARSE_ASSERT(err == ERR_OK);
1153     }
1154     /* add zero terminator */
1155     request->community[request->community_strlen] = 0;
1156   }
1157 
1158   /* decode PDU type (next container level) */
1159   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1160   IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length);
1161   request->inbound_padding_len = pbuf_stream.length - tlv.value_len;
1162   parent_tlv_value_len = tlv.value_len;
1163 
1164   /* validate PDU type */
1165   switch(tlv.type) {
1166     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ):
1167       /* GetRequest PDU */
1168       snmp_stats.ingetrequests++;
1169       break;
1170     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ):
1171       /* GetNextRequest PDU */
1172       snmp_stats.ingetnexts++;
1173       break;
1174     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ):
1175       /* GetBulkRequest PDU */
1176       if (request->version < SNMP_VERSION_2c) {
1177         /* RFC2089: invalid, drop packet */
1178         return ERR_ARG;
1179       }
1180       break;
1181     case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ):
1182       /* SetRequest PDU */
1183       snmp_stats.insetrequests++;
1184       break;
1185     default:
1186       /* unsupported input PDU for this agent (no parse error) */
1187       LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \
1188       return ERR_ARG;
1189       break;
1190   }
1191   request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK;
1192   request->request_out_type = (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP);
1193 
1194   /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */
1195   if (request->community_strlen == 0) {
1196     /* community string was too long or really empty*/
1197     snmp_stats.inbadcommunitynames++;
1198     snmp_authfail_trap();
1199     return ERR_ARG;
1200   } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1201     if (snmp_community_write[0] == 0) {
1202       /* our write community is empty, that means all our objects are readonly */
1203       request->error_status = SNMP_ERR_NOTWRITABLE;
1204       request->error_index  = 1;
1205     } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
1206       /* community name does not match */
1207       snmp_stats.inbadcommunitynames++;
1208       snmp_authfail_trap();
1209       return ERR_ARG;
1210     }
1211   } else {
1212     if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) {
1213       /* community name does not match */
1214       snmp_stats.inbadcommunitynames++;
1215       snmp_authfail_trap();
1216       return ERR_ARG;
1217     }
1218   }
1219 
1220   /* decode request ID */
1221   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1222   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
1223   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1224   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1225 
1226   IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id));
1227 
1228   /* decode error status / non-repeaters */
1229   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1230   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
1231   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1232   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1233 
1234   if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
1235     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters));
1236     if (request->non_repeaters < 0) {
1237       /* RFC 1905, 4.2.3 */
1238       request->non_repeaters = 0;
1239     }
1240   } else {
1241     /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */
1242     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value));
1243     IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR);
1244   }
1245 
1246   /* decode error index / max-repetitions */
1247   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1248   IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER);
1249   parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1250   IF_PARSE_ASSERT(parent_tlv_value_len > 0);
1251 
1252   if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) {
1253     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions));
1254     if (request->max_repetitions < 0) {
1255       /* RFC 1905, 4.2.3 */
1256       request->max_repetitions = 0;
1257     }
1258   } else {
1259     IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index));
1260     IF_PARSE_ASSERT(s32_value == 0);
1261   }
1262 
1263   /* decode varbind-list type (next container level) */
1264   IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv));
1265   IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length));
1266 
1267   request->inbound_varbind_offset = pbuf_stream.offset;
1268   request->inbound_varbind_len    = pbuf_stream.length - request->inbound_padding_len;
1269   snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
1270 
1271   return ERR_OK;
1272 }
1273 
1274 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
1275 
1276 static err_t
1277 snmp_prepare_outbound_frame(struct snmp_request *request)
1278 {
1279   struct snmp_asn1_tlv tlv;
1280   struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream);
1281 
1282   /* try allocating pbuf(s) for maximum response size */
1283   request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM);
1284   if (request->outbound_pbuf == NULL) {
1285     return ERR_MEM;
1286   }
1287 
1288   snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len);
1289 
1290   /* 'Message' sequence */
1291   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1292   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1293 
1294   /* version */
1295   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1296   snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len);
1297   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1298   OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) );
1299 
1300 #if LWIP_SNMP_V3
1301   if (request->version < SNMP_VERSION_3) {
1302 #endif
1303   /* community */
1304   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen);
1305   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1306   OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) );
1307 #if LWIP_SNMP_V3
1308   } else {
1309     const char* id;
1310 
1311     /* globalData */
1312     request->outbound_msg_global_data_offset = pbuf_stream->offset;
1313     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
1314     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1315 
1316     /* msgID */
1317     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1318     snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len);
1319     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1320     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id));
1321 
1322     /* msgMaxSize */
1323     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1324     snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len);
1325     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1326     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size));
1327 
1328     /* msgFlags */
1329     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1);
1330     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1331     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1));
1332 
1333     /* msgSecurityModel */
1334     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1335     snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len);
1336     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1337     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model));
1338 
1339     /* end of msgGlobalData */
1340     request->outbound_msg_global_data_end = pbuf_stream->offset;
1341 
1342     /* msgSecurityParameters */
1343     request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset;
1344     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0);
1345     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1346 
1347     request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset;
1348     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0);
1349     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1350 
1351     /* msgAuthoritativeEngineID */
1352     snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len);
1353     MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len);
1354     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len);
1355     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1356     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len));
1357 
1358     request->msg_authoritative_engine_time = snmpv3_get_engine_time();
1359     request->msg_authoritative_engine_boots = snmpv3_get_engine_boots();
1360 
1361     /* msgAuthoritativeEngineBoots */
1362     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1363     snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len);
1364     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1365     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots));
1366 
1367     /* msgAuthoritativeEngineTime */
1368     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1369     snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len);
1370     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1371     OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time));
1372 
1373     /* msgUserName */
1374     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len);
1375     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1376     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len));
1377 
1378 #if LWIP_SNMP_V3_CRYPTO
1379     /* msgAuthenticationParameters */
1380     if (request->msg_flags & SNMP_V3_AUTH_FLAG) {
1381       memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1382       request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset;
1383       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1384       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1385       OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
1386     } else
1387 #endif
1388     {
1389       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
1390       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1391     }
1392 
1393 #if LWIP_SNMP_V3_CRYPTO
1394     /* msgPrivacyParameters */
1395     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1396       snmpv3_build_priv_param(request->msg_privacy_parameters);
1397 
1398       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH);
1399       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1400       OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH));
1401     } else
1402 #endif
1403     {
1404       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0);
1405       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1406     }
1407 
1408     /* End of msgSecurityParameters, so we can calculate the length of this sequence later */
1409     request->outbound_msg_security_parameters_end = pbuf_stream->offset;
1410 
1411 #if LWIP_SNMP_V3_CRYPTO
1412     /* For encryption we have to encapsulate the payload in an octet string */
1413     if (request->msg_flags & SNMP_V3_PRIV_FLAG) {
1414       request->outbound_scoped_pdu_string_offset = pbuf_stream->offset;
1415       SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0);
1416       OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1417     }
1418 #endif
1419     /* Scoped PDU
1420      * Encryption context
1421      */
1422     request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset;
1423     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1424     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1425 
1426     /* contextEngineID */
1427     snmpv3_get_engine_id(&id, &request->context_engine_id_len);
1428     MEMCPY(request->context_engine_id, id, request->context_engine_id_len);
1429     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len);
1430     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1431     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len));
1432 
1433     /* contextName */
1434     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len);
1435     OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1436     OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len));
1437   }
1438 #endif
1439 
1440   /* 'PDU' sequence */
1441   request->outbound_pdu_offset = pbuf_stream->offset;
1442   SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3, 0);
1443   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1444 
1445   /* request ID */
1446   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0);
1447   snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len);
1448   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1449   OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) );
1450 
1451   /* error status */
1452   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1453   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1454   request->outbound_error_status_offset = pbuf_stream->offset;
1455   OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
1456 
1457   /* error index */
1458   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1);
1459   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1460   request->outbound_error_index_offset = pbuf_stream->offset;
1461   OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) );
1462 
1463   /* 'VarBindList' sequence */
1464   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0);
1465   OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) );
1466 
1467   request->outbound_varbind_offset = pbuf_stream->offset;
1468 
1469   return ERR_OK;
1470 }
1471 
1472 /** Calculate the length of a varbind list */
1473 err_t
1474 snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len)
1475 {
1476   /* calculate required lengths */
1477   snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len);
1478   snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len);
1479 
1480   if (varbind->value_len == 0) {
1481     len->value_value_len = 0;
1482   } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
1483     len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA);
1484   } else {
1485     switch (varbind->type) {
1486       case SNMP_ASN1_TYPE_INTEGER:
1487         if (varbind->value_len != sizeof (s32_t)) {
1488           return ERR_VAL;
1489         }
1490         snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len);
1491         break;
1492       case SNMP_ASN1_TYPE_COUNTER:
1493       case SNMP_ASN1_TYPE_GAUGE:
1494       case SNMP_ASN1_TYPE_TIMETICKS:
1495         if (varbind->value_len != sizeof (u32_t)) {
1496           return ERR_VAL;
1497         }
1498         snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len);
1499         break;
1500       case SNMP_ASN1_TYPE_OCTET_STRING:
1501       case SNMP_ASN1_TYPE_IPADDR:
1502       case SNMP_ASN1_TYPE_OPAQUE:
1503         len->value_value_len = varbind->value_len;
1504         break;
1505       case SNMP_ASN1_TYPE_NULL:
1506         if (varbind->value_len != 0) {
1507           return ERR_VAL;
1508         }
1509         len->value_value_len = 0;
1510         break;
1511       case SNMP_ASN1_TYPE_OBJECT_ID:
1512         if ((varbind->value_len & 0x03) != 0) {
1513           return ERR_VAL;
1514         }
1515         snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len);
1516         break;
1517       case SNMP_ASN1_TYPE_COUNTER64:
1518         if (varbind->value_len != (2 * sizeof (u32_t))) {
1519           return ERR_VAL;
1520         }
1521         snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len);
1522         break;
1523       default:
1524         /* unsupported type */
1525         return ERR_VAL;
1526     }
1527   }
1528   snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len);
1529 
1530   len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len;
1531   snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len);
1532 
1533   return ERR_OK;
1534 }
1535 
1536 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG)
1537 
1538 err_t
1539 snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind)
1540 {
1541   struct snmp_asn1_tlv tlv;
1542   struct snmp_varbind_len len;
1543   err_t err;
1544 
1545   err = snmp_varbind_length(varbind, &len);
1546 
1547   if (err != ERR_OK) {
1548     return err;
1549   }
1550 
1551   /* check length already before adding first data because in case of GetBulk,
1552    *  data added so far is returned and therefore no partial data shall be added
1553    */
1554   if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) {
1555     return ERR_BUF;
1556   }
1557 
1558   /* 'VarBind' sequence */
1559   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len);
1560   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1561 
1562   /* VarBind OID */
1563   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len);
1564   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1565   OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len));
1566 
1567   /* VarBind value */
1568   SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len);
1569   OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv));
1570 
1571   if (len.value_value_len > 0) {
1572     if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) {
1573       OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
1574     } else {
1575       switch (varbind->type) {
1576         case SNMP_ASN1_TYPE_INTEGER:
1577           OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value)));
1578           break;
1579         case SNMP_ASN1_TYPE_COUNTER:
1580         case SNMP_ASN1_TYPE_GAUGE:
1581         case SNMP_ASN1_TYPE_TIMETICKS:
1582           OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value)));
1583           break;
1584         case SNMP_ASN1_TYPE_OCTET_STRING:
1585         case SNMP_ASN1_TYPE_IPADDR:
1586         case SNMP_ASN1_TYPE_OPAQUE:
1587           OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len));
1588           len.value_value_len = varbind->value_len;
1589           break;
1590         case SNMP_ASN1_TYPE_OBJECT_ID:
1591           OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t)));
1592           break;
1593         case SNMP_ASN1_TYPE_COUNTER64:
1594           OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value));
1595           break;
1596         default:
1597           LWIP_ASSERT("Unknown variable type", 0);
1598           break;
1599       }
1600     }
1601   }
1602 
1603   return ERR_OK;
1604 }
1605 
1606 static err_t
1607 snmp_complete_outbound_frame(struct snmp_request *request)
1608 {
1609   struct snmp_asn1_tlv tlv;
1610   u16_t frame_size;
1611   u8_t outbound_padding = 0;
1612 
1613   if (request->version == SNMP_VERSION_1) {
1614     if (request->error_status != SNMP_ERR_NOERROR) {
1615       /* map v2c error codes to v1 compliant error code (according to RFC 2089) */
1616       switch (request->error_status) {
1617         /* mapping of implementation specific "virtual" error codes
1618          * (during processing of frame we already stored them in error_status field,
1619          * so no need to check all varbinds here for those exceptions as suggested by RFC) */
1620         case SNMP_ERR_NOSUCHINSTANCE:
1621         case SNMP_ERR_NOSUCHOBJECT:
1622         case SNMP_ERR_ENDOFMIBVIEW:
1623           request->error_status = SNMP_ERR_NOSUCHNAME;
1624           break;
1625         /* mapping according to RFC */
1626         case SNMP_ERR_WRONGVALUE:
1627         case SNMP_ERR_WRONGENCODING:
1628         case SNMP_ERR_WRONGTYPE:
1629         case SNMP_ERR_WRONGLENGTH:
1630         case SNMP_ERR_INCONSISTENTVALUE:
1631           request->error_status = SNMP_ERR_BADVALUE;
1632           break;
1633         case SNMP_ERR_NOACCESS:
1634         case SNMP_ERR_NOTWRITABLE:
1635         case SNMP_ERR_NOCREATION:
1636         case SNMP_ERR_INCONSISTENTNAME:
1637         case SNMP_ERR_AUTHORIZATIONERROR:
1638           request->error_status = SNMP_ERR_NOSUCHNAME;
1639           break;
1640         case SNMP_ERR_RESOURCEUNAVAILABLE:
1641         case SNMP_ERR_COMMITFAILED:
1642         case SNMP_ERR_UNDOFAILED:
1643         default:
1644           request->error_status = SNMP_ERR_GENERROR;
1645           break;
1646        }
1647     }
1648   } else {
1649     if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1650       /* map error codes to according to RFC 1905 (4.2.5.  The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */
1651       switch (request->error_status) {
1652         case SNMP_ERR_NOSUCHINSTANCE:
1653         case SNMP_ERR_NOSUCHOBJECT:
1654         case SNMP_ERR_ENDOFMIBVIEW:
1655           request->error_status = SNMP_ERR_NOTWRITABLE;
1656           break;
1657         default:
1658           break;
1659       }
1660     }
1661 
1662     if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) {
1663       /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */
1664       LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n"));
1665       return ERR_ARG;
1666     }
1667   }
1668 
1669   if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) {
1670     /* all inbound vars are returned in response without any modification for error responses and successful set requests*/
1671     struct snmp_pbuf_stream inbound_stream;
1672     OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) );
1673     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) );
1674     snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0);
1675   }
1676 
1677   frame_size = request->outbound_pbuf_stream.offset;
1678 
1679 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
1680   /* Calculate padding for encryption */
1681   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
1682     u8_t i;
1683     outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07;
1684     for (i = 0; i < outbound_padding; i++) {
1685       snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0);
1686     }
1687   }
1688 #endif
1689 
1690   /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */
1691   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size + outbound_padding - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1692   OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) );
1693   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1694 
1695 #if LWIP_SNMP_V3
1696   if (request->version == SNMP_VERSION_3) {
1697     /* complete missing length in 'globalData' sequence */
1698     /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1699     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end
1700         - request->outbound_msg_global_data_offset - 1 - 1);
1701     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset));
1702     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1703 
1704     /* complete missing length in 'msgSecurityParameters' sequence */
1705     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end
1706         - request->outbound_msg_security_parameters_str_offset - 1 - 1);
1707     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset));
1708     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1709 
1710     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end
1711         - request->outbound_msg_security_parameters_seq_offset - 1 - 1);
1712     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset));
1713     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1714 
1715     /* complete missing length in scoped PDU sequence */
1716     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3);
1717     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset));
1718     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1719   }
1720 #endif
1721 
1722   /* complete missing length in 'PDU' sequence */
1723   SNMP_ASN1_SET_TLV_PARAMS(tlv, request->request_out_type, 3,
1724       frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */
1725   OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) );
1726   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1727 
1728   /* process and encode final error status */
1729   if (request->error_status != 0) {
1730     u16_t len;
1731     snmp_asn1_enc_s32t_cnt(request->error_status, &len);
1732     if (len != 1) {
1733       /* error, we only reserved one byte for it */
1734       return ERR_ARG;
1735     }
1736     OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) );
1737     OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) );
1738 
1739     /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */
1740     switch (request->error_status) {
1741       case SNMP_ERR_TOOBIG:
1742         snmp_stats.outtoobigs++;
1743         break;
1744       case SNMP_ERR_NOSUCHNAME:
1745         snmp_stats.outnosuchnames++;
1746         break;
1747       case SNMP_ERR_BADVALUE:
1748         snmp_stats.outbadvalues++;
1749         break;
1750       case SNMP_ERR_GENERROR:
1751       default:
1752         snmp_stats.outgenerrs++;
1753         break;
1754     }
1755 
1756     if (request->error_status == SNMP_ERR_TOOBIG) {
1757       request->error_index = 0; /* defined by RFC 1157 */
1758     } else if (request->error_index == 0) {
1759       /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */
1760       request->error_index = request->inbound_varbind_enumerator.varbind_count;
1761     }
1762   } else {
1763     if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) {
1764       snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count;
1765     } else {
1766       snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count;
1767     }
1768   }
1769 
1770   /* encode final error index*/
1771   if (request->error_index != 0) {
1772     u16_t len;
1773     snmp_asn1_enc_s32t_cnt(request->error_index, &len);
1774     if (len != 1) {
1775       /* error, we only reserved one byte for it */
1776       return ERR_VAL;
1777     }
1778     OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) );
1779     OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) );
1780   }
1781 
1782   /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */
1783   SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset);
1784   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()) */
1785   OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) );
1786 
1787   /* Authenticate response */
1788 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO
1789   /* Encrypt response */
1790   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) {
1791     u8_t key[20];
1792     snmpv3_priv_algo_t algo;
1793 
1794     /* complete missing length in PDU sequence */
1795     OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1796     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset));
1797     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding
1798         - request->outbound_scoped_pdu_string_offset - 1 - 3);
1799     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv));
1800 
1801     OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, NULL, NULL, &algo, key));
1802 
1803     OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key,
1804         request->msg_privacy_parameters, request->msg_authoritative_engine_boots,
1805         request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT));
1806   }
1807 
1808   if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) {
1809     u8_t key[20];
1810     snmpv3_auth_algo_t algo;
1811     u8_t hmac[20];
1812 
1813     OF_BUILD_EXEC(snmpv3_get_user((char*)request->msg_user_name, &algo, key, NULL, NULL));
1814     OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream),
1815         request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1816     OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac));
1817 
1818     MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1819     OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream,
1820                   request->outbound_pbuf, 0, request->outbound_pbuf->tot_len));
1821     OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream,
1822                   request->outbound_msg_authentication_parameters_offset));
1823 
1824     SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH);
1825     OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv));
1826     OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream,
1827                   request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH));
1828   }
1829 #endif
1830 
1831   pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding);
1832 
1833   snmp_stats.outgetresponses++;
1834   snmp_stats.outpkts++;
1835 
1836   return ERR_OK;
1837 }
1838 
1839 static void
1840 snmp_execute_write_callbacks(struct snmp_request *request)
1841 {
1842   struct snmp_varbind_enumerator inbound_varbind_enumerator;
1843   struct snmp_varbind vb;
1844 
1845   snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len);
1846   vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */
1847 
1848   while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) {
1849     snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg);
1850   }
1851 }
1852 
1853 
1854 /* ----------------------------------------------------------------------- */
1855 /* VarBind enumerator methods */
1856 /* ----------------------------------------------------------------------- */
1857 
1858 void
1859 snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length)
1860 {
1861   snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length);
1862   enumerator->varbind_count = 0;
1863 }
1864 
1865 #define VB_PARSE_EXEC(code)   PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1866 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR)
1867 
1868 snmp_vb_enumerator_err_t
1869 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind)
1870 {
1871   struct snmp_asn1_tlv tlv;
1872   u16_t  varbind_len;
1873   err_t  err;
1874 
1875   if (enumerator->pbuf_stream.length == 0)
1876   {
1877     return SNMP_VB_ENUMERATOR_ERR_EOVB;
1878   }
1879   enumerator->varbind_count++;
1880 
1881   /* decode varbind itself (parent container of a varbind) */
1882   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1883   VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length));
1884   varbind_len = tlv.value_len;
1885 
1886   /* decode varbind name (object id) */
1887   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1888   VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length));
1889 
1890   VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN));
1891   varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv);
1892 
1893   /* decode varbind value (object id) */
1894   VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv));
1895   VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length));
1896   varbind->type = tlv.type;
1897 
1898   /* shall the value be decoded ? */
1899   if (varbind->value != NULL) {
1900     switch (varbind->type) {
1901       case SNMP_ASN1_TYPE_INTEGER:
1902         VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value));
1903         varbind->value_len = sizeof(s32_t*);
1904         break;
1905       case SNMP_ASN1_TYPE_COUNTER:
1906       case SNMP_ASN1_TYPE_GAUGE:
1907       case SNMP_ASN1_TYPE_TIMETICKS:
1908         VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1909         varbind->value_len = sizeof(u32_t*);
1910         break;
1911       case SNMP_ASN1_TYPE_OCTET_STRING:
1912       case SNMP_ASN1_TYPE_OPAQUE:
1913         err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE);
1914         if (err == ERR_MEM) {
1915           return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1916         }
1917         VB_PARSE_ASSERT(err == ERR_OK);
1918         break;
1919       case SNMP_ASN1_TYPE_NULL:
1920         varbind->value_len = 0;
1921         break;
1922       case SNMP_ASN1_TYPE_OBJECT_ID:
1923         /* misuse tlv.length_len as OID_length transporter */
1924         err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN);
1925         if (err == ERR_MEM) {
1926           return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH;
1927         }
1928         VB_PARSE_ASSERT(err == ERR_OK);
1929         varbind->value_len = tlv.length_len * sizeof(u32_t);
1930         break;
1931       case SNMP_ASN1_TYPE_IPADDR:
1932         if (tlv.value_len == 4) {
1933           /* must be exactly 4 octets! */
1934           VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE));
1935         } else {
1936           VB_PARSE_ASSERT(0);
1937         }
1938         break;
1939       case SNMP_ASN1_TYPE_COUNTER64:
1940         VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value));
1941         varbind->value_len = 2 * sizeof(u32_t*);
1942         break;
1943       default:
1944         VB_PARSE_ASSERT(0);
1945         break;
1946     }
1947   } else {
1948     snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len);
1949     varbind->value_len = tlv.value_len;
1950   }
1951 
1952   return SNMP_VB_ENUMERATOR_ERR_OK;
1953 }
1954 
1955 #endif /* LWIP_SNMP */
1956