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 */
60const char *snmp_community = SNMP_COMMUNITY;
61/** SNMP community string for write access */
62const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
63/** SNMP community string for sending traps */
64const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
65
66snmp_write_callback_fct snmp_write_callback     = NULL;
67void*                   snmp_write_callback_arg = NULL;
68
69/**
70 * @ingroup snmp_core
71 * Returns current SNMP community string.
72 * @return current SNMP community string
73 */
74const char *
75snmp_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 */
88void
89snmp_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 */
100const char *
101snmp_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 */
111const char *
112snmp_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 */
125void
126snmp_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 */
141void
142snmp_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 */
152void
153snmp_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
163static err_t snmp_process_get_request(struct snmp_request *request);
164static err_t snmp_process_getnext_request(struct snmp_request *request);
165static err_t snmp_process_getbulk_request(struct snmp_request *request);
166static err_t snmp_process_set_request(struct snmp_request *request);
167
168static err_t snmp_parse_inbound_frame(struct snmp_request *request);
169static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
170static err_t snmp_complete_outbound_frame(struct snmp_request *request);
171static void snmp_execute_write_callbacks(struct snmp_request *request);
172
173
174/* ----------------------------------------------------------------------- */
175/* implementation */
176/* ----------------------------------------------------------------------- */
177
178void
179snmp_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
232static u8_t
233snmp_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
247static void
248snmp_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 */
328static err_t
329snmp_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 */
364static err_t
365snmp_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 */
400static err_t
401snmp_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 */
498static err_t
499snmp_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 */
610static err_t
611snmp_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
989static err_t
990snmp_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 */
1186err_t
1187snmp_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
1251err_t
1252snmp_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
1319static err_t
1320snmp_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
1552static void
1553snmp_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
1571void
1572snmp_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
1581snmp_vb_enumerator_err_t
1582snmp_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