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