Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Dependents: mbed-TFT-example-NCS36510 mbed-Accelerometer-example-NCS36510 mbed-Accelerometer-example-NCS36510
lwip_snmp_msg.c
00001 /** 00002 * @file 00003 * SNMP message processing (RFC1157). 00004 */ 00005 00006 /* 00007 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. 00008 * Copyright (c) 2016 Elias Oenal. 00009 * All rights reserved. 00010 * 00011 * Redistribution and use in source and binary forms, with or without modification, 00012 * are permitted provided that the following conditions are met: 00013 * 00014 * 1. Redistributions of source code must retain the above copyright notice, 00015 * this list of conditions and the following disclaimer. 00016 * 2. Redistributions in binary form must reproduce the above copyright notice, 00017 * this list of conditions and the following disclaimer in the documentation 00018 * and/or other materials provided with the distribution. 00019 * 3. The name of the author may not be used to endorse or promote products 00020 * derived from this software without specific prior written permission. 00021 * 00022 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00023 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00024 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00025 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00026 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00027 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00028 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00029 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00030 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00031 * OF SUCH DAMAGE. 00032 * 00033 * Author: Christiaan Simons <christiaan.simons@axon.tv> 00034 * Martin Hentschel <info@cl-soft.de> 00035 * Elias Oenal <lwip@eliasoenal.com> 00036 */ 00037 00038 #include "lwip/apps/snmp_opts.h" 00039 00040 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ 00041 00042 #include "snmp_msg.h" 00043 #include "snmp_asn1.h" 00044 #include "snmp_core_priv.h" 00045 #include "lwip/ip_addr.h" 00046 #include "lwip/stats.h" 00047 00048 #if LWIP_SNMP_V3 00049 #include "lwip/apps/snmpv3.h" 00050 #include "snmpv3_priv.h" 00051 #ifdef LWIP_SNMPV3_INCLUDE_ENGINE 00052 #include LWIP_SNMPV3_INCLUDE_ENGINE 00053 #endif 00054 #endif 00055 00056 #include <string.h> 00057 00058 /* public (non-static) constants */ 00059 /** SNMP community string */ 00060 const char *snmp_community = SNMP_COMMUNITY; 00061 /** SNMP community string for write access */ 00062 const char *snmp_community_write = SNMP_COMMUNITY_WRITE; 00063 /** SNMP community string for sending traps */ 00064 const char *snmp_community_trap = SNMP_COMMUNITY_TRAP; 00065 00066 snmp_write_callback_fct snmp_write_callback = NULL; 00067 void* snmp_write_callback_arg = NULL; 00068 00069 /** 00070 * @ingroup snmp_core 00071 * Returns current SNMP community string. 00072 * @return current SNMP community string 00073 */ 00074 const char * 00075 snmp_get_community(void) 00076 { 00077 return snmp_community; 00078 } 00079 00080 /** 00081 * @ingroup snmp_core 00082 * Sets SNMP community string. 00083 * The string itself (its storage) must be valid throughout the whole life of 00084 * program (or until it is changed to sth else). 00085 * 00086 * @param community is a pointer to new community string 00087 */ 00088 void 00089 snmp_set_community(const char * const community) 00090 { 00091 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); 00092 snmp_community = community; 00093 } 00094 00095 /** 00096 * @ingroup snmp_core 00097 * Returns current SNMP write-access community string. 00098 * @return current SNMP write-access community string 00099 */ 00100 const char * 00101 snmp_get_community_write(void) 00102 { 00103 return snmp_community_write; 00104 } 00105 00106 /** 00107 * @ingroup snmp_traps 00108 * Returns current SNMP community string used for sending traps. 00109 * @return current SNMP community string used for sending traps 00110 */ 00111 const char * 00112 snmp_get_community_trap(void) 00113 { 00114 return snmp_community_trap; 00115 } 00116 00117 /** 00118 * @ingroup snmp_core 00119 * Sets SNMP community string for write-access. 00120 * The string itself (its storage) must be valid throughout the whole life of 00121 * program (or until it is changed to sth else). 00122 * 00123 * @param community is a pointer to new write-access community string 00124 */ 00125 void 00126 snmp_set_community_write(const char * const community) 00127 { 00128 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); 00129 snmp_community_write = community; 00130 } 00131 00132 /** 00133 * @ingroup snmp_traps 00134 * Sets SNMP community string used for sending traps. 00135 * The string itself (its storage) must be valid throughout the whole life of 00136 * program (or until it is changed to sth else). 00137 * 00138 * @param community is a pointer to new trap community string 00139 */ 00140 void 00141 snmp_set_community_trap(const char * const community) 00142 { 00143 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); 00144 snmp_community_trap = community; 00145 } 00146 00147 /** 00148 * @ingroup snmp_core 00149 * Callback fired on every successful write access 00150 */ 00151 void 00152 snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg) 00153 { 00154 snmp_write_callback = write_callback; 00155 snmp_write_callback_arg = callback_arg; 00156 } 00157 00158 /* ----------------------------------------------------------------------- */ 00159 /* forward declarations */ 00160 /* ----------------------------------------------------------------------- */ 00161 00162 static err_t snmp_process_get_request(struct snmp_request *request); 00163 static err_t snmp_process_getnext_request(struct snmp_request *request); 00164 static err_t snmp_process_getbulk_request(struct snmp_request *request); 00165 static err_t snmp_process_set_request(struct snmp_request *request); 00166 00167 static err_t snmp_parse_inbound_frame(struct snmp_request *request); 00168 static err_t snmp_prepare_outbound_frame(struct snmp_request *request); 00169 static err_t snmp_complete_outbound_frame(struct snmp_request *request); 00170 static void snmp_execute_write_callbacks(struct snmp_request *request); 00171 00172 00173 /* ----------------------------------------------------------------------- */ 00174 /* implementation */ 00175 /* ----------------------------------------------------------------------- */ 00176 00177 void 00178 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port) 00179 { 00180 err_t err; 00181 struct snmp_request request; 00182 00183 memset(&request, 0, sizeof(request)); 00184 request.handle = handle; 00185 request.source_ip = source_ip; 00186 request.source_port = port; 00187 request.inbound_pbuf = p; 00188 00189 snmp_stats.inpkts++; 00190 00191 err = snmp_parse_inbound_frame(&request); 00192 if (err == ERR_OK) { 00193 err = snmp_prepare_outbound_frame(&request); 00194 if (err == ERR_OK) { 00195 00196 if (request.error_status == SNMP_ERR_NOERROR) { 00197 /* only process frame if we do not already have an error to return (e.g. all readonly) */ 00198 if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) { 00199 err = snmp_process_get_request(&request); 00200 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) { 00201 err = snmp_process_getnext_request(&request); 00202 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { 00203 err = snmp_process_getbulk_request(&request); 00204 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { 00205 err = snmp_process_set_request(&request); 00206 } 00207 } 00208 00209 if (err == ERR_OK) { 00210 err = snmp_complete_outbound_frame(&request); 00211 00212 if (err == ERR_OK) { 00213 err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port); 00214 00215 if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) 00216 && (request.error_status == SNMP_ERR_NOERROR) 00217 && (snmp_write_callback != NULL)) { 00218 /* raise write notification for all written objects */ 00219 snmp_execute_write_callbacks(&request); 00220 } 00221 } 00222 } 00223 } 00224 00225 if (request.outbound_pbuf != NULL) { 00226 pbuf_free(request.outbound_pbuf); 00227 } 00228 } 00229 } 00230 00231 static u8_t 00232 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg) 00233 { 00234 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) { 00235 return SNMP_ERR_NOSUCHINSTANCE; 00236 } 00237 00238 if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) { 00239 /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */ 00240 return SNMP_ERR_NOSUCHINSTANCE; 00241 } 00242 00243 return SNMP_ERR_NOERROR; 00244 } 00245 00246 static void 00247 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next) 00248 { 00249 err_t err; 00250 struct snmp_node_instance node_instance; 00251 memset(&node_instance, 0, sizeof(node_instance)); 00252 00253 if (get_next) { 00254 struct snmp_obj_id result_oid; 00255 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); 00256 00257 if (request->error_status == SNMP_ERR_NOERROR) { 00258 snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len); 00259 } 00260 } else { 00261 request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance); 00262 00263 if (request->error_status == SNMP_ERR_NOERROR) { 00264 /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */ 00265 request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request); 00266 00267 if (request->error_status != SNMP_ERR_NOERROR) { 00268 if (node_instance.release_instance != NULL) { 00269 node_instance.release_instance(&node_instance); 00270 } 00271 } 00272 } 00273 } 00274 00275 if (request->error_status != SNMP_ERR_NOERROR) 00276 { 00277 if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { 00278 if ((request->version == SNMP_VERSION_2c) || request->version == SNMP_VERSION_3) { 00279 /* in SNMP v2c a varbind related exception is stored in varbind and not in frame header */ 00280 vb->type = (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | (request->error_status & SNMP_VARBIND_EXCEPTION_MASK)); 00281 vb->value_len = 0; 00282 00283 err = snmp_append_outbound_varbind(&(request->outbound_pbuf_stream), vb); 00284 if (err == ERR_OK) { 00285 /* we stored the exception in varbind -> go on */ 00286 request->error_status = SNMP_ERR_NOERROR; 00287 } else if (err == ERR_BUF) { 00288 request->error_status = SNMP_ERR_TOOBIG; 00289 } else { 00290 request->error_status = SNMP_ERR_GENERROR; 00291 } 00292 } 00293 } else { 00294 /* according to RFC 1157/1905, all other errors only return genError */ 00295 request->error_status = SNMP_ERR_GENERROR; 00296 } 00297 } else { 00298 s16_t len = node_instance.get_value(&node_instance, vb->value); 00299 vb->type = node_instance.asn1_type; 00300 00301 if(len >= 0) { 00302 vb->value_len = (u16_t)len; /* cast is OK because we checked >= 0 above */ 00303 00304 LWIP_ASSERT("SNMP_MAX_VALUE_SIZE is configured too low", (vb->value_len & ~SNMP_GET_VALUE_RAW_DATA) <= SNMP_MAX_VALUE_SIZE); 00305 err = snmp_append_outbound_varbind(&request->outbound_pbuf_stream, vb); 00306 00307 if (err == ERR_BUF) { 00308 request->error_status = SNMP_ERR_TOOBIG; 00309 } else if (err != ERR_OK) { 00310 request->error_status = SNMP_ERR_GENERROR; 00311 } 00312 } else { 00313 request->error_status = SNMP_ERR_GENERROR; 00314 } 00315 00316 if (node_instance.release_instance != NULL) { 00317 node_instance.release_instance(&node_instance); 00318 } 00319 } 00320 } 00321 00322 00323 /** 00324 * Service an internal or external event for SNMP GET. 00325 * 00326 * @param msg_ps points to the associated message process state 00327 */ 00328 static err_t 00329 snmp_process_get_request(struct snmp_request *request) 00330 { 00331 snmp_vb_enumerator_err_t err; 00332 struct snmp_varbind vb; 00333 vb.value = request->value_buffer; 00334 00335 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get request\n")); 00336 00337 while (request->error_status == SNMP_ERR_NOERROR) { 00338 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); 00339 if (err == SNMP_VB_ENUMERATOR_ERR_OK) { 00340 if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { 00341 snmp_process_varbind(request, &vb, 0); 00342 } else { 00343 request->error_status = SNMP_ERR_GENERROR; 00344 } 00345 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00346 /* no more varbinds in request */ 00347 break; 00348 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { 00349 /* malformed ASN.1, don't answer */ 00350 return ERR_ARG; 00351 } else { 00352 request->error_status = SNMP_ERR_GENERROR; 00353 } 00354 } 00355 00356 return ERR_OK; 00357 } 00358 00359 /** 00360 * Service an internal or external event for SNMP GET. 00361 * 00362 * @param msg_ps points to the associated message process state 00363 */ 00364 static err_t 00365 snmp_process_getnext_request(struct snmp_request *request) 00366 { 00367 snmp_vb_enumerator_err_t err; 00368 struct snmp_varbind vb; 00369 vb.value = request->value_buffer; 00370 00371 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-next request\n")); 00372 00373 while (request->error_status == SNMP_ERR_NOERROR) { 00374 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); 00375 if (err == SNMP_VB_ENUMERATOR_ERR_OK) { 00376 if ((vb.type == SNMP_ASN1_TYPE_NULL) && (vb.value_len == 0)) { 00377 snmp_process_varbind(request, &vb, 1); 00378 } else { 00379 request->error_status = SNMP_ERR_GENERROR; 00380 } 00381 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00382 /* no more varbinds in request */ 00383 break; 00384 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { 00385 /* malformed ASN.1, don't answer */ 00386 return ERR_ARG; 00387 } else { 00388 request->error_status = SNMP_ERR_GENERROR; 00389 } 00390 } 00391 00392 return ERR_OK; 00393 } 00394 00395 /** 00396 * Service an internal or external event for SNMP GETBULKT. 00397 * 00398 * @param msg_ps points to the associated message process state 00399 */ 00400 static err_t 00401 snmp_process_getbulk_request(struct snmp_request *request) 00402 { 00403 snmp_vb_enumerator_err_t err; 00404 s32_t non_repeaters = request->non_repeaters; 00405 s32_t repetitions; 00406 u16_t repetition_offset = 0; 00407 struct snmp_varbind_enumerator repetition_varbind_enumerator; 00408 struct snmp_varbind vb; 00409 vb.value = request->value_buffer; 00410 00411 if (SNMP_LWIP_GETBULK_MAX_REPETITIONS > 0) { 00412 repetitions = LWIP_MIN(request->max_repetitions, SNMP_LWIP_GETBULK_MAX_REPETITIONS); 00413 } else { 00414 repetitions = request->max_repetitions; 00415 } 00416 00417 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP get-bulk request\n")); 00418 00419 /* process non repeaters and first repetition */ 00420 while (request->error_status == SNMP_ERR_NOERROR) { 00421 if (non_repeaters == 0) { 00422 repetition_offset = request->outbound_pbuf_stream.offset; 00423 00424 if (repetitions == 0) { 00425 /* do not resolve repeaters when repetitions is set to 0 */ 00426 break; 00427 } 00428 repetitions--; 00429 } 00430 00431 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); 00432 if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00433 /* no more varbinds in request */ 00434 break; 00435 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { 00436 /* malformed ASN.1, don't answer */ 00437 return ERR_ARG; 00438 } else if ((err != SNMP_VB_ENUMERATOR_ERR_OK) || (vb.type != SNMP_ASN1_TYPE_NULL) || (vb.value_len != 0)) { 00439 request->error_status = SNMP_ERR_GENERROR; 00440 } else { 00441 snmp_process_varbind(request, &vb, 1); 00442 non_repeaters--; 00443 } 00444 } 00445 00446 /* process repetitions > 1 */ 00447 while ((request->error_status == SNMP_ERR_NOERROR) && (repetitions > 0) && (request->outbound_pbuf_stream.offset != repetition_offset)) { 00448 00449 u8_t all_endofmibview = 1; 00450 00451 snmp_vb_enumerator_init(&repetition_varbind_enumerator, request->outbound_pbuf, repetition_offset, request->outbound_pbuf_stream.offset - repetition_offset); 00452 repetition_offset = request->outbound_pbuf_stream.offset; /* for next loop */ 00453 00454 while (request->error_status == SNMP_ERR_NOERROR) { 00455 vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned) */ 00456 err = snmp_vb_enumerator_get_next(&repetition_varbind_enumerator, &vb); 00457 if (err == SNMP_VB_ENUMERATOR_ERR_OK) { 00458 vb.value = request->value_buffer; 00459 snmp_process_varbind(request, &vb, 1); 00460 00461 if (request->error_status != SNMP_ERR_NOERROR) { 00462 /* already set correct error-index (here it cannot be taken from inbound varbind enumerator) */ 00463 request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; 00464 } else if (vb.type != (SNMP_ASN1_CONTENTTYPE_PRIMITIVE | SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTEXT_VARBIND_END_OF_MIB_VIEW)) { 00465 all_endofmibview = 0; 00466 } 00467 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00468 /* no more varbinds in request */ 00469 break; 00470 } else { 00471 LWIP_DEBUGF(SNMP_DEBUG, ("Very strange, we cannot parse the varbind output that we created just before!")); 00472 request->error_status = SNMP_ERR_GENERROR; 00473 request->error_index = request->non_repeaters + repetition_varbind_enumerator.varbind_count; 00474 } 00475 } 00476 00477 if ((request->error_status == SNMP_ERR_NOERROR) && all_endofmibview) { 00478 /* stop when all varbinds in a loop return EndOfMibView */ 00479 break; 00480 } 00481 00482 repetitions--; 00483 } 00484 00485 if (request->error_status == SNMP_ERR_TOOBIG) { 00486 /* for GetBulk it is ok, if not all requested variables fit into the response -> just return the varbinds added so far */ 00487 request->error_status = SNMP_ERR_NOERROR; 00488 } 00489 00490 return ERR_OK; 00491 } 00492 00493 /** 00494 * Service an internal or external event for SNMP SET. 00495 * 00496 * @param msg_ps points to the associated message process state 00497 */ 00498 static err_t 00499 snmp_process_set_request(struct snmp_request *request) 00500 { 00501 snmp_vb_enumerator_err_t err; 00502 struct snmp_varbind vb; 00503 vb.value = request->value_buffer; 00504 00505 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP set request\n")); 00506 00507 /* perform set test on all objects */ 00508 while (request->error_status == SNMP_ERR_NOERROR) { 00509 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); 00510 if (err == SNMP_VB_ENUMERATOR_ERR_OK) { 00511 struct snmp_node_instance node_instance; 00512 memset(&node_instance, 0, sizeof(node_instance)); 00513 00514 request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); 00515 if (request->error_status == SNMP_ERR_NOERROR) 00516 { 00517 if (node_instance.asn1_type != vb.type) { 00518 request->error_status = SNMP_ERR_WRONGTYPE; 00519 } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) { 00520 request->error_status = SNMP_ERR_NOTWRITABLE; 00521 } else { 00522 if (node_instance.set_test != NULL) { 00523 request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value); 00524 } 00525 } 00526 00527 if (node_instance.release_instance != NULL) { 00528 node_instance.release_instance(&node_instance); 00529 } 00530 } 00531 } 00532 else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00533 /* no more varbinds in request */ 00534 break; 00535 } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) { 00536 request->error_status = SNMP_ERR_WRONGLENGTH; 00537 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { 00538 /* malformed ASN.1, don't answer */ 00539 return ERR_ARG; 00540 } else { 00541 request->error_status = SNMP_ERR_GENERROR; 00542 } 00543 } 00544 00545 /* perform real set operation on all objects */ 00546 if (request->error_status == SNMP_ERR_NOERROR) { 00547 snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); 00548 while (request->error_status == SNMP_ERR_NOERROR) { 00549 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); 00550 if (err == SNMP_VB_ENUMERATOR_ERR_OK) { 00551 struct snmp_node_instance node_instance; 00552 memset(&node_instance, 0, sizeof(node_instance)); 00553 request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); 00554 if (request->error_status == SNMP_ERR_NOERROR) 00555 { 00556 if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) 00557 { 00558 if (request->inbound_varbind_enumerator.varbind_count == 1) { 00559 request->error_status = SNMP_ERR_COMMITFAILED; 00560 } else { 00561 /* we cannot undo the set operations done so far */ 00562 request->error_status = SNMP_ERR_UNDOFAILED; 00563 } 00564 } 00565 00566 if (node_instance.release_instance != NULL) { 00567 node_instance.release_instance(&node_instance); 00568 } 00569 } 00570 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00571 /* no more varbinds in request */ 00572 break; 00573 } else { 00574 /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */ 00575 request->error_status = SNMP_ERR_GENERROR; 00576 } 00577 } 00578 } 00579 00580 return ERR_OK; 00581 } 00582 00583 #define PARSE_EXEC(code, retValue) \ 00584 if ((code) != ERR_OK) { \ 00585 LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \ 00586 snmp_stats.inasnparseerrs++; \ 00587 return retValue; \ 00588 } 00589 00590 #define PARSE_ASSERT(cond, retValue) \ 00591 if (!(cond)) { \ 00592 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \ 00593 snmp_stats.inasnparseerrs++; \ 00594 return retValue; \ 00595 } 00596 00597 #define BUILD_EXEC(code, retValue) \ 00598 if ((code) != ERR_OK) { \ 00599 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \ 00600 return retValue; \ 00601 } 00602 00603 #define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ARG) 00604 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG) 00605 00606 /** 00607 * Checks and decodes incoming SNMP message header, logs header errors. 00608 * 00609 * @param request points to the current message request state return 00610 * @return 00611 * - ERR_OK SNMP header is sane and accepted 00612 * - ERR_VAL SNMP header is either malformed or rejected 00613 */ 00614 static err_t 00615 snmp_parse_inbound_frame(struct snmp_request *request) 00616 { 00617 struct snmp_pbuf_stream pbuf_stream; 00618 struct snmp_asn1_tlv tlv; 00619 s32_t parent_tlv_value_len; 00620 s32_t s32_value; 00621 err_t err; 00622 00623 IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); 00624 00625 /* decode main container consisting of version, community and PDU */ 00626 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00627 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length)); 00628 parent_tlv_value_len = tlv.value_len; 00629 00630 /* decode version */ 00631 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00632 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00633 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00634 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00635 00636 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00637 if ((s32_value != SNMP_VERSION_1) && 00638 (s32_value != SNMP_VERSION_2c) 00639 #if LWIP_SNMP_V3 00640 && (s32_value != SNMP_VERSION_3) 00641 #endif 00642 ) 00643 { 00644 /* unsupported SNMP version */ 00645 snmp_stats.inbadversions++; 00646 return ERR_ARG; 00647 } 00648 request->version = (u8_t)s32_value; 00649 00650 #if LWIP_SNMP_V3 00651 if (request->version == SNMP_VERSION_3) { 00652 u16_t u16_value; 00653 00654 /* SNMPv3 doesn't use communities */ 00655 /* @todo: Differentiate read/write access */ 00656 strcpy((char*)request->community, snmp_community); 00657 request->community_strlen = strlen(snmp_community); 00658 00659 /* RFC3414 globalData */ 00660 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00661 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); 00662 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00663 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00664 00665 /* decode msgID */ 00666 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00667 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00668 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00669 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00670 00671 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00672 request->msg_id = s32_value; 00673 00674 /* decode msgMaxSize */ 00675 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00676 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00677 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00678 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00679 00680 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00681 request->msg_max_size = s32_value; 00682 00683 /* decode msgFlags */ 00684 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00685 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00686 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00687 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00688 00689 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00690 request->msg_flags = s32_value; 00691 00692 /* decode msgSecurityModel */ 00693 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00694 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00695 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00696 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00697 00698 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00699 request->msg_security_model = s32_value; 00700 00701 /* RFC3414 msgSecurityParameters 00702 * The User-based Security Model defines the contents of the OCTET 00703 * STRING as a SEQUENCE. 00704 * 00705 * We skip the protective dummy OCTET STRING header 00706 * to access the SEQUENCE header. 00707 */ 00708 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00709 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00710 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00711 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00712 00713 /* msgSecurityParameters SEQUENCE header */ 00714 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00715 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); 00716 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00717 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00718 00719 /* decode msgAuthoritativeEngineID */ 00720 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00721 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00722 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00723 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00724 00725 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id, 00726 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); 00727 request->msg_authoritative_engine_id_len = u16_value; 00728 00729 /* msgAuthoritativeEngineBoots */ 00730 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00731 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00732 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00733 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00734 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots)); 00735 00736 /* msgAuthoritativeEngineTime */ 00737 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00738 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00739 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00740 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00741 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time)); 00742 /* @todo: Implement time window checking */ 00743 00744 /* msgUserName */ 00745 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00746 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00747 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00748 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00749 00750 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name, 00751 &u16_value, SNMP_V3_MAX_USER_LENGTH)); 00752 request->msg_user_name_len = u16_value; 00753 /* @todo: Implement unknown user error response */ 00754 IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, NULL, NULL)); 00755 00756 /* msgAuthenticationParameters */ 00757 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 00758 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00759 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00760 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00761 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00762 /* Remember position */ 00763 u16_t inbound_msgAuthenticationParameters_offset = pbuf_stream.offset; 00764 LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset); 00765 /* Read auth parameters */ 00766 IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); 00767 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters, 00768 &u16_value, tlv.value_len)); 00769 00770 #if LWIP_SNMP_V3_CRYPTO 00771 if (request->msg_flags & SNMP_V3_AUTH_FLAG) { 00772 /* Rewind stream */ 00773 IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); 00774 IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset)); 00775 /* Set auth parameters to zero for verification */ 00776 const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 }; 00777 IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len)); 00778 00779 /* Verify authentication */ 00780 u8_t key[20]; 00781 u8_t algo; 00782 u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)]; 00783 struct snmp_pbuf_stream auth_stream; 00784 IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); 00785 00786 IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, &algo, key, NULL, NULL)); 00787 IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac)); 00788 /* @todo: Implement error response */ 00789 IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); 00790 } 00791 #else 00792 /* Ungraceful exit if we encounter cryptography and don't support it. 00793 * @todo: Implement error response 00794 */ 00795 IF_PARSE_ASSERT(!(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG))); 00796 #endif 00797 00798 /* msgPrivacyParameters */ 00799 memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); 00800 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00801 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00802 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00803 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00804 00805 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters, 00806 &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); 00807 00808 #if LWIP_SNMP_V3_CRYPTO 00809 /* Decrypt message */ 00810 if (request->msg_flags & SNMP_V3_PRIV_FLAG) { 00811 u8_t key[20]; 00812 u8_t algo; 00813 00814 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00815 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00816 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00817 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00818 00819 IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, &algo, key)); 00820 IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key, 00821 request->msg_privacy_parameters, request->msg_authoritative_engine_boots, 00822 request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT)); 00823 } 00824 #endif 00825 00826 /* Scoped PDU 00827 * Encryption context 00828 */ 00829 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00830 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); 00831 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00832 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00833 00834 /* contextEngineID */ 00835 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00836 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00837 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00838 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00839 00840 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id, 00841 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); 00842 request->context_engine_id_len = u16_value; 00843 00844 /* contextName */ 00845 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00846 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00847 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00848 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00849 00850 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name, 00851 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); 00852 request->context_name_len = u16_value; 00853 } else 00854 #endif 00855 { 00856 /* decode community */ 00857 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00858 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00859 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00860 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00861 00862 err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN); 00863 if (err == ERR_MEM) { 00864 /* community string does not fit in our buffer -> its too long -> its invalid */ 00865 request->community_strlen = 0; 00866 snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len); 00867 } else { 00868 IF_PARSE_ASSERT(err == ERR_OK); 00869 } 00870 /* add zero terminator */ 00871 request->community[request->community_strlen] = 0; 00872 } 00873 00874 /* decode PDU type (next container level) */ 00875 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00876 IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length); 00877 request->inbound_padding_len = pbuf_stream.length - tlv.value_len; 00878 parent_tlv_value_len = tlv.value_len; 00879 00880 /* validate PDU type */ 00881 switch(tlv.type) { 00882 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ): 00883 /* GetRequest PDU */ 00884 snmp_stats.ingetrequests++; 00885 break; 00886 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ): 00887 /* GetNextRequest PDU */ 00888 snmp_stats.ingetnexts++; 00889 break; 00890 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ): 00891 /* GetBulkRequest PDU */ 00892 if (request->version < SNMP_VERSION_2c) { 00893 /* RFC2089: invalid, drop packet */ 00894 return ERR_ARG; 00895 } 00896 break; 00897 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ): 00898 /* SetRequest PDU */ 00899 snmp_stats.insetrequests++; 00900 break; 00901 default: 00902 /* unsupported input PDU for this agent (no parse error) */ 00903 LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \ 00904 return ERR_ARG; 00905 break; 00906 } 00907 request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK; 00908 00909 /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */ 00910 if (request->community_strlen == 0) { 00911 /* community string was too long or really empty*/ 00912 snmp_stats.inbadcommunitynames++; 00913 snmp_authfail_trap(); 00914 return ERR_ARG; 00915 } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { 00916 if (strnlen(snmp_community_write, SNMP_MAX_COMMUNITY_STR_LEN) == 0) { 00917 /* our write community is empty, that means all our objects are readonly */ 00918 request->error_status = SNMP_ERR_NOTWRITABLE; 00919 request->error_index = 1; 00920 } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { 00921 /* community name does not match */ 00922 snmp_stats.inbadcommunitynames++; 00923 snmp_authfail_trap(); 00924 return ERR_ARG; 00925 } 00926 } else { 00927 if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { 00928 /* community name does not match */ 00929 snmp_stats.inbadcommunitynames++; 00930 snmp_authfail_trap(); 00931 return ERR_ARG; 00932 } 00933 } 00934 00935 /* decode request ID */ 00936 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00937 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00938 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00939 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00940 00941 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id)); 00942 00943 /* decode error status / non-repeaters */ 00944 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00945 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00946 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00947 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00948 00949 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { 00950 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters)); 00951 if (request->non_repeaters < 0) { 00952 /* RFC 1905, 4.2.3 */ 00953 request->non_repeaters = 0; 00954 } 00955 } else { 00956 /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */ 00957 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00958 IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR); 00959 } 00960 00961 /* decode error index / max-repetitions */ 00962 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00963 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00964 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00965 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00966 00967 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { 00968 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions)); 00969 if (request->max_repetitions < 0) { 00970 /* RFC 1905, 4.2.3 */ 00971 request->max_repetitions = 0; 00972 } 00973 } else { 00974 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index)); 00975 IF_PARSE_ASSERT(s32_value == 0); 00976 } 00977 00978 /* decode varbind-list type (next container level) */ 00979 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00980 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length)); 00981 00982 request->inbound_varbind_offset = pbuf_stream.offset; 00983 request->inbound_varbind_len = pbuf_stream.length - request->inbound_padding_len; 00984 snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); 00985 00986 return ERR_OK; 00987 } 00988 00989 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) 00990 00991 static err_t 00992 snmp_prepare_outbound_frame(struct snmp_request *request) 00993 { 00994 struct snmp_asn1_tlv tlv; 00995 struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream); 00996 00997 /* try allocating pbuf(s) for maximum response size */ 00998 request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM); 00999 if (request->outbound_pbuf == NULL) { 01000 return ERR_MEM; 01001 } 01002 01003 snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len); 01004 01005 /* 'Message' sequence */ 01006 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); 01007 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01008 01009 /* version */ 01010 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01011 snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len); 01012 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01013 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) ); 01014 01015 #if LWIP_SNMP_V3 01016 if (request->version < SNMP_VERSION_3) { 01017 #endif 01018 /* community */ 01019 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen); 01020 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01021 OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) ); 01022 #if LWIP_SNMP_V3 01023 } else { 01024 const char* id; 01025 01026 /* globalData */ 01027 request->outbound_msg_global_data_offset = pbuf_stream->offset; 01028 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); 01029 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01030 01031 /* msgID */ 01032 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01033 snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len); 01034 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01035 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id)); 01036 01037 /* msgMaxSize */ 01038 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01039 snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len); 01040 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01041 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size)); 01042 01043 /* msgFlags */ 01044 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1); 01045 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01046 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1)); 01047 01048 /* msgSecurityModel */ 01049 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01050 snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len); 01051 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01052 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model)); 01053 01054 /* end of msgGlobalData */ 01055 request->outbound_msg_global_data_end = pbuf_stream->offset; 01056 01057 /* msgSecurityParameters */ 01058 request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset; 01059 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0); 01060 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01061 01062 request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset; 01063 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); 01064 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01065 01066 /* msgAuthoritativeEngineID */ 01067 snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len); 01068 memcpy(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len); 01069 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len); 01070 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01071 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len)); 01072 01073 request->msg_authoritative_engine_time = snmpv3_get_engine_time(); 01074 request->msg_authoritative_engine_boots = snmpv3_get_engine_boots(); 01075 01076 /* msgAuthoritativeEngineBoots */ 01077 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01078 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len); 01079 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01080 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots)); 01081 01082 /* msgAuthoritativeEngineTime */ 01083 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01084 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len); 01085 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01086 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time)); 01087 01088 /* msgUserName */ 01089 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len); 01090 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01091 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len)); 01092 01093 #if LWIP_SNMP_V3_CRYPTO 01094 /* msgAuthenticationParameters */ 01095 if (request->msg_flags & SNMP_V3_AUTH_FLAG) { 01096 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01097 request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset; 01098 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01099 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01100 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); 01101 } else 01102 #endif 01103 { 01104 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); 01105 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01106 } 01107 01108 #if LWIP_SNMP_V3_CRYPTO 01109 /* msgPrivacyParameters */ 01110 if (request->msg_flags & SNMP_V3_PRIV_FLAG) { 01111 snmpv3_build_priv_param(request->msg_privacy_parameters); 01112 01113 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); 01114 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01115 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); 01116 } else 01117 #endif 01118 { 01119 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); 01120 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01121 } 01122 01123 /* End of msgSecurityParameters, so we can calculate the length of this sequence later */ 01124 request->outbound_msg_security_parameters_end = pbuf_stream->offset; 01125 01126 #if LWIP_SNMP_V3_CRYPTO 01127 /* For encryption we have to encapsulate the payload in an octet string */ 01128 if (request->msg_flags & SNMP_V3_PRIV_FLAG) { 01129 request->outbound_scoped_pdu_string_offset = pbuf_stream->offset; 01130 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0); 01131 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01132 } 01133 #endif 01134 /* Scoped PDU 01135 * Encryption context 01136 */ 01137 request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset; 01138 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); 01139 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01140 01141 /* contextEngineID */ 01142 snmpv3_get_engine_id(&id, &request->context_engine_id_len); 01143 memcpy(request->context_engine_id, id, request->context_engine_id_len); 01144 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len); 01145 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01146 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len)); 01147 01148 /* contextName */ 01149 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len); 01150 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01151 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len)); 01152 } 01153 #endif 01154 01155 /* 'PDU' sequence */ 01156 request->outbound_pdu_offset = pbuf_stream->offset; 01157 SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0); 01158 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01159 01160 /* request ID */ 01161 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01162 snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len); 01163 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01164 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) ); 01165 01166 /* error status */ 01167 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01168 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01169 request->outbound_error_status_offset = pbuf_stream->offset; 01170 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); 01171 01172 /* error index */ 01173 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01174 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01175 request->outbound_error_index_offset = pbuf_stream->offset; 01176 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); 01177 01178 /* 'VarBindList' sequence */ 01179 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); 01180 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01181 01182 request->outbound_varbind_offset = pbuf_stream->offset; 01183 01184 return ERR_OK; 01185 } 01186 01187 /** Calculate the length of a varbind list */ 01188 err_t 01189 snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len) 01190 { 01191 /* calculate required lengths */ 01192 snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len); 01193 snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len); 01194 01195 if (varbind->value_len == 0) { 01196 len->value_value_len = 0; 01197 } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { 01198 len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA); 01199 } else { 01200 switch (varbind->type) { 01201 case SNMP_ASN1_TYPE_INTEGER: 01202 if (varbind->value_len != sizeof (s32_t)) { 01203 return ERR_VAL; 01204 } 01205 snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len); 01206 break; 01207 case SNMP_ASN1_TYPE_COUNTER: 01208 case SNMP_ASN1_TYPE_GAUGE: 01209 case SNMP_ASN1_TYPE_TIMETICKS: 01210 if (varbind->value_len != sizeof (u32_t)) { 01211 return ERR_VAL; 01212 } 01213 snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len); 01214 break; 01215 case SNMP_ASN1_TYPE_OCTET_STRING: 01216 case SNMP_ASN1_TYPE_IPADDR: 01217 case SNMP_ASN1_TYPE_OPAQUE: 01218 len->value_value_len = varbind->value_len; 01219 break; 01220 case SNMP_ASN1_TYPE_NULL: 01221 if (varbind->value_len != 0) { 01222 return ERR_VAL; 01223 } 01224 len->value_value_len = 0; 01225 break; 01226 case SNMP_ASN1_TYPE_OBJECT_ID: 01227 if ((varbind->value_len & 0x03) != 0) { 01228 return ERR_VAL; 01229 } 01230 snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len); 01231 break; 01232 case SNMP_ASN1_TYPE_COUNTER64: 01233 if (varbind->value_len != (2 * sizeof (u32_t))) { 01234 return ERR_VAL; 01235 } 01236 snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len); 01237 break; 01238 default: 01239 /* unsupported type */ 01240 return ERR_VAL; 01241 } 01242 } 01243 snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len); 01244 01245 len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len; 01246 snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len); 01247 01248 return ERR_OK; 01249 } 01250 01251 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) 01252 01253 err_t 01254 snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind) 01255 { 01256 struct snmp_asn1_tlv tlv; 01257 struct snmp_varbind_len len; 01258 err_t err; 01259 01260 err = snmp_varbind_length(varbind, &len); 01261 01262 if (err != ERR_OK) { 01263 return err; 01264 } 01265 01266 /* check length already before adding first data because in case of GetBulk, 01267 * data added so far is returned and therefore no partial data shall be added 01268 */ 01269 if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) { 01270 return ERR_BUF; 01271 } 01272 01273 /* 'VarBind' sequence */ 01274 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len); 01275 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01276 01277 /* VarBind OID */ 01278 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len); 01279 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01280 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len)); 01281 01282 /* VarBind value */ 01283 SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len); 01284 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01285 01286 if (len.value_value_len > 0) { 01287 if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { 01288 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); 01289 } else { 01290 switch (varbind->type) { 01291 case SNMP_ASN1_TYPE_INTEGER: 01292 OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value))); 01293 break; 01294 case SNMP_ASN1_TYPE_COUNTER: 01295 case SNMP_ASN1_TYPE_GAUGE: 01296 case SNMP_ASN1_TYPE_TIMETICKS: 01297 OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value))); 01298 break; 01299 case SNMP_ASN1_TYPE_OCTET_STRING: 01300 case SNMP_ASN1_TYPE_IPADDR: 01301 case SNMP_ASN1_TYPE_OPAQUE: 01302 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); 01303 len.value_value_len = varbind->value_len; 01304 break; 01305 case SNMP_ASN1_TYPE_OBJECT_ID: 01306 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t))); 01307 break; 01308 case SNMP_ASN1_TYPE_COUNTER64: 01309 OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value)); 01310 break; 01311 default: 01312 LWIP_ASSERT("Unknown variable type", 0); 01313 break; 01314 } 01315 } 01316 } 01317 01318 return ERR_OK; 01319 } 01320 01321 static err_t 01322 snmp_complete_outbound_frame(struct snmp_request *request) 01323 { 01324 struct snmp_asn1_tlv tlv; 01325 u16_t frame_size; 01326 u8_t outbound_padding = 0; 01327 01328 if (request->version == SNMP_VERSION_1) { 01329 if (request->error_status != SNMP_ERR_NOERROR) { 01330 /* map v2c error codes to v1 compliant error code (according to RFC 2089) */ 01331 switch (request->error_status) { 01332 /* mapping of implementation specific "virtual" error codes 01333 * (during processing of frame we already stored them in error_status field, 01334 * so no need to check all varbinds here for those exceptions as suggested by RFC) */ 01335 case SNMP_ERR_NOSUCHINSTANCE: 01336 case SNMP_ERR_NOSUCHOBJECT: 01337 case SNMP_ERR_ENDOFMIBVIEW: 01338 request->error_status = SNMP_ERR_NOSUCHNAME; 01339 break; 01340 /* mapping according to RFC */ 01341 case SNMP_ERR_WRONGVALUE: 01342 case SNMP_ERR_WRONGENCODING: 01343 case SNMP_ERR_WRONGTYPE: 01344 case SNMP_ERR_WRONGLENGTH: 01345 case SNMP_ERR_INCONSISTENTVALUE: 01346 request->error_status = SNMP_ERR_BADVALUE; 01347 break; 01348 case SNMP_ERR_NOACCESS: 01349 case SNMP_ERR_NOTWRITABLE: 01350 case SNMP_ERR_NOCREATION: 01351 case SNMP_ERR_INCONSISTENTNAME: 01352 case SNMP_ERR_AUTHORIZATIONERROR: 01353 request->error_status = SNMP_ERR_NOSUCHNAME; 01354 break; 01355 case SNMP_ERR_RESOURCEUNAVAILABLE: 01356 case SNMP_ERR_COMMITFAILED: 01357 case SNMP_ERR_UNDOFAILED: 01358 default: 01359 request->error_status = SNMP_ERR_GENERROR; 01360 break; 01361 } 01362 } 01363 } else { 01364 if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { 01365 /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */ 01366 LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n")); 01367 return ERR_ARG; 01368 } 01369 } 01370 01371 if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) { 01372 /* all inbound vars are returned in response without any modification for error responses and successful set requests*/ 01373 struct snmp_pbuf_stream inbound_stream; 01374 OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) ); 01375 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) ); 01376 snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0); 01377 } 01378 01379 frame_size = request->outbound_pbuf_stream.offset; 01380 01381 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO 01382 /* Calculate padding for encryption */ 01383 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { 01384 u8_t i; 01385 outbound_padding = (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x03); 01386 for (i = 0; i < outbound_padding; i++) { 01387 snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0); 01388 } 01389 } 01390 #endif 01391 01392 /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */ 01393 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()) */ 01394 OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) ); 01395 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); 01396 01397 #if LWIP_SNMP_V3 01398 if (request->version == SNMP_VERSION_3) { 01399 /* complete missing length in 'globalData' sequence */ 01400 /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ 01401 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end 01402 - request->outbound_msg_global_data_offset - 1 - 1); 01403 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset)); 01404 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01405 01406 /* complete missing length in 'msgSecurityParameters' sequence */ 01407 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end 01408 - request->outbound_msg_security_parameters_str_offset - 1 - 1); 01409 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset)); 01410 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01411 01412 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end 01413 - request->outbound_msg_security_parameters_seq_offset - 1 - 1); 01414 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset)); 01415 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01416 01417 /* complete missing length in scoped PDU sequence */ 01418 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3); 01419 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset)); 01420 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01421 } 01422 #endif 01423 01424 /* complete missing length in 'PDU' sequence */ 01425 SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 01426 frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ 01427 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) ); 01428 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); 01429 01430 /* process and encode final error status */ 01431 if (request->error_status != 0) { 01432 u16_t len; 01433 snmp_asn1_enc_s32t_cnt(request->error_status, &len); 01434 if (len != 1) { 01435 /* error, we only reserved one byte for it */ 01436 return ERR_ARG; 01437 } 01438 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) ); 01439 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) ); 01440 01441 /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */ 01442 switch (request->error_status) { 01443 case SNMP_ERR_TOOBIG: 01444 snmp_stats.outtoobigs++; 01445 break; 01446 case SNMP_ERR_NOSUCHNAME: 01447 snmp_stats.outnosuchnames++; 01448 break; 01449 case SNMP_ERR_BADVALUE: 01450 snmp_stats.outbadvalues++; 01451 break; 01452 case SNMP_ERR_GENERROR: 01453 default: 01454 snmp_stats.outgenerrs++; 01455 break; 01456 } 01457 01458 if (request->error_status == SNMP_ERR_TOOBIG) { 01459 request->error_index = 0; /* defined by RFC 1157 */ 01460 } else if (request->error_index == 0) { 01461 /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */ 01462 request->error_index = request->inbound_varbind_enumerator.varbind_count; 01463 } 01464 } else { 01465 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { 01466 snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count; 01467 } else { 01468 snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count; 01469 } 01470 } 01471 01472 /* encode final error index*/ 01473 if (request->error_index != 0) { 01474 u16_t len; 01475 snmp_asn1_enc_s32t_cnt(request->error_index, &len); 01476 if (len != 1) { 01477 /* error, we only reserved one byte for it */ 01478 return ERR_VAL; 01479 } 01480 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) ); 01481 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) ); 01482 } 01483 01484 /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */ 01485 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset); 01486 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()) */ 01487 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); 01488 01489 /* Authenticate response */ 01490 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO 01491 /* Encrypt response */ 01492 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { 01493 u8_t key[20]; 01494 u8_t algo; 01495 01496 /* complete missing length in PDU sequence */ 01497 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); 01498 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset)); 01499 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding 01500 - request->outbound_scoped_pdu_string_offset - 1 - 3); 01501 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01502 01503 OF_BUILD_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, &algo, key)); 01504 01505 OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key, 01506 request->msg_privacy_parameters, request->msg_authoritative_engine_boots, 01507 request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT)); 01508 } 01509 01510 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) { 01511 u8_t key[20]; 01512 u8_t algo; 01513 u8_t hmac[20]; 01514 01515 OF_BUILD_EXEC(snmpv3_get_user ((char*)request->msg_user_name, &algo, key, NULL, NULL)); 01516 OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), 01517 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); 01518 OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac)); 01519 01520 memcpy(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01521 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, 01522 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); 01523 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream, 01524 request->outbound_msg_authentication_parameters_offset)); 01525 01526 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01527 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv)); 01528 OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream, 01529 request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); 01530 } 01531 #endif 01532 01533 pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding); 01534 01535 snmp_stats.outgetresponses++; 01536 snmp_stats.outpkts++; 01537 01538 return ERR_OK; 01539 } 01540 01541 static void 01542 snmp_execute_write_callbacks(struct snmp_request *request) 01543 { 01544 struct snmp_varbind_enumerator inbound_varbind_enumerator; 01545 struct snmp_varbind vb; 01546 01547 snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); 01548 vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */ 01549 01550 while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == ERR_OK) { 01551 snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg); 01552 } 01553 } 01554 01555 01556 /* ----------------------------------------------------------------------- */ 01557 /* VarBind enumerator methods */ 01558 /* ----------------------------------------------------------------------- */ 01559 01560 void 01561 snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length) 01562 { 01563 snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length); 01564 enumerator->varbind_count = 0; 01565 } 01566 01567 #define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) 01568 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) 01569 01570 snmp_vb_enumerator_err_t 01571 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind) 01572 { 01573 struct snmp_asn1_tlv tlv; 01574 u16_t varbind_len; 01575 err_t err; 01576 01577 if (enumerator->pbuf_stream.length == 0) 01578 { 01579 return SNMP_VB_ENUMERATOR_ERR_EOVB; 01580 } 01581 enumerator->varbind_count++; 01582 01583 /* decode varbind itself (parent container of a varbind) */ 01584 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); 01585 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length)); 01586 varbind_len = tlv.value_len; 01587 01588 /* decode varbind name (object id) */ 01589 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); 01590 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length)); 01591 01592 VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN)); 01593 varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv); 01594 01595 /* decode varbind value (object id) */ 01596 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); 01597 VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length)); 01598 varbind->type = tlv.type; 01599 01600 /* shall the value be decoded ? */ 01601 if (varbind->value != NULL) { 01602 switch (varbind->type) { 01603 case SNMP_ASN1_TYPE_INTEGER: 01604 VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value)); 01605 varbind->value_len = sizeof(s32_t*); 01606 break; 01607 case SNMP_ASN1_TYPE_COUNTER: 01608 case SNMP_ASN1_TYPE_GAUGE: 01609 case SNMP_ASN1_TYPE_TIMETICKS: 01610 VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); 01611 varbind->value_len = sizeof(u32_t*); 01612 break; 01613 case SNMP_ASN1_TYPE_OCTET_STRING: 01614 case SNMP_ASN1_TYPE_OPAQUE: 01615 err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE); 01616 if (err == ERR_MEM) { 01617 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; 01618 } 01619 VB_PARSE_ASSERT(err == ERR_OK); 01620 break; 01621 case SNMP_ASN1_TYPE_NULL: 01622 varbind->value_len = 0; 01623 break; 01624 case SNMP_ASN1_TYPE_OBJECT_ID: 01625 /* misuse tlv.length_len as OID_length transporter */ 01626 err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN); 01627 if (err == ERR_MEM) { 01628 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; 01629 } 01630 VB_PARSE_ASSERT(err == ERR_OK); 01631 varbind->value_len = tlv.length_len * sizeof(u32_t); 01632 break; 01633 case SNMP_ASN1_TYPE_IPADDR: 01634 if (tlv.value_len == 4) { 01635 /* must be exactly 4 octets! */ 01636 VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE)); 01637 } else { 01638 VB_PARSE_ASSERT(0); 01639 } 01640 break; 01641 case SNMP_ASN1_TYPE_COUNTER64: 01642 VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); 01643 varbind->value_len = 2 * sizeof(u32_t*); 01644 break; 01645 default: 01646 VB_PARSE_ASSERT(0); 01647 break; 01648 } 01649 } else { 01650 snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len); 01651 varbind->value_len = tlv.value_len; 01652 } 01653 01654 return SNMP_VB_ENUMERATOR_ERR_OK; 01655 } 01656 01657 #endif /* LWIP_SNMP */
Generated on Tue Jul 12 2022 11:02:42 by
