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