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