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