source: azure_iot_hub_f767zi/trunk/asp_baseplatform/lwip/lwip-2.1.2/src/apps/snmp/snmp_msg.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 75.0 KB
Line 
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 */
68const char *snmp_community = SNMP_COMMUNITY;
69/** SNMP community string for write access */
70const char *snmp_community_write = SNMP_COMMUNITY_WRITE;
71/** SNMP community string for sending traps */
72const char *snmp_community_trap = SNMP_COMMUNITY_TRAP;
73
74snmp_write_callback_fct snmp_write_callback = NULL;
75void *snmp_write_callback_arg = NULL;
76
77#if LWIP_SNMP_CONFIGURE_VERSIONS
78
79static u8_t v1_enabled = 1;
80static u8_t v2c_enabled = 1;
81static u8_t v3_enabled = 1;
82
83static u8_t
84snmp_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
102u8_t
103snmp_v1_enabled(void)
104{
105 return snmp_version_enabled(SNMP_VERSION_1);
106}
107
108u8_t
109snmp_v2c_enabled(void)
110{
111 return snmp_version_enabled(SNMP_VERSION_2c);
112}
113
114u8_t
115snmp_v3_enabled(void)
116{
117 return snmp_version_enabled(SNMP_VERSION_3);
118}
119
120static void
121snmp_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
138void
139snmp_v1_enable(u8_t enable)
140{
141 snmp_version_enable(SNMP_VERSION_1, enable);
142}
143
144void
145snmp_v2c_enable(u8_t enable)
146{
147 snmp_version_enable(SNMP_VERSION_2c, enable);
148}
149
150void
151snmp_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 */
163const char *
164snmp_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 */
177void
178snmp_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 */
190const char *
191snmp_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 */
201const char *
202snmp_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 */
215void
216snmp_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 */
232void
233snmp_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 */
244void
245snmp_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
256static err_t snmp_process_get_request(struct snmp_request *request);
257static err_t snmp_process_getnext_request(struct snmp_request *request);
258static err_t snmp_process_getbulk_request(struct snmp_request *request);
259static err_t snmp_process_set_request(struct snmp_request *request);
260
261static err_t snmp_parse_inbound_frame(struct snmp_request *request);
262static err_t snmp_prepare_outbound_frame(struct snmp_request *request);
263static err_t snmp_complete_outbound_frame(struct snmp_request *request);
264static void snmp_execute_write_callbacks(struct snmp_request *request);
265
266
267/* ----------------------------------------------------------------------- */
268/* implementation */
269/* ----------------------------------------------------------------------- */
270
271void
272snmp_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
385static u8_t
386snmp_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
402static void
403snmp_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 */
483static err_t
484snmp_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 */
519static err_t
520snmp_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 */
555static err_t
556snmp_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 */
653static err_t
654snmp_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 */
765static err_t
766snmp_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
1267static err_t
1268snmp_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 */
1464err_t
1465snmp_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
1531err_t
1532snmp_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
1601static err_t
1602snmp_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
1834static void
1835snmp_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
1853void
1854snmp_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
1863snmp_vb_enumerator_err_t
1864snmp_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 */
Note: See TracBrowser for help on using the repository browser.