![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Rtos API example
Embed:
(wiki syntax)
Show/hide line numbers
lwip_snmp_msg.c
Go to the documentation of this file.
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 must not be NULL", community != NULL); 00129 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); 00130 snmp_community_write = community; 00131 } 00132 00133 /** 00134 * @ingroup snmp_traps 00135 * Sets SNMP community string used for sending traps. 00136 * The string itself (its storage) must be valid throughout the whole life of 00137 * program (or until it is changed to sth else). 00138 * 00139 * @param community is a pointer to new trap community string 00140 */ 00141 void 00142 snmp_set_community_trap(const char * const community) 00143 { 00144 LWIP_ASSERT("community string is too long!", strlen(community) <= SNMP_MAX_COMMUNITY_STR_LEN); 00145 snmp_community_trap = community; 00146 } 00147 00148 /** 00149 * @ingroup snmp_core 00150 * Callback fired on every successful write access 00151 */ 00152 void 00153 snmp_set_write_callback(snmp_write_callback_fct write_callback, void* callback_arg) 00154 { 00155 snmp_write_callback = write_callback; 00156 snmp_write_callback_arg = callback_arg; 00157 } 00158 00159 /* ----------------------------------------------------------------------- */ 00160 /* forward declarations */ 00161 /* ----------------------------------------------------------------------- */ 00162 00163 static err_t snmp_process_get_request(struct snmp_request *request); 00164 static err_t snmp_process_getnext_request(struct snmp_request *request); 00165 static err_t snmp_process_getbulk_request(struct snmp_request *request); 00166 static err_t snmp_process_set_request(struct snmp_request *request); 00167 00168 static err_t snmp_parse_inbound_frame(struct snmp_request *request); 00169 static err_t snmp_prepare_outbound_frame(struct snmp_request *request); 00170 static err_t snmp_complete_outbound_frame(struct snmp_request *request); 00171 static void snmp_execute_write_callbacks(struct snmp_request *request); 00172 00173 00174 /* ----------------------------------------------------------------------- */ 00175 /* implementation */ 00176 /* ----------------------------------------------------------------------- */ 00177 00178 void 00179 snmp_receive(void *handle, struct pbuf *p, const ip_addr_t *source_ip, u16_t port) 00180 { 00181 err_t err; 00182 struct snmp_request request; 00183 00184 memset(&request, 0, sizeof(request)); 00185 request.handle = handle; 00186 request.source_ip = source_ip; 00187 request.source_port = port; 00188 request.inbound_pbuf = p; 00189 00190 snmp_stats.inpkts++; 00191 00192 err = snmp_parse_inbound_frame(&request); 00193 if (err == ERR_OK) { 00194 err = snmp_prepare_outbound_frame(&request); 00195 if (err == ERR_OK) { 00196 00197 if (request.error_status == SNMP_ERR_NOERROR) { 00198 /* only process frame if we do not already have an error to return (e.g. all readonly) */ 00199 if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_REQ) { 00200 err = snmp_process_get_request(&request); 00201 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ) { 00202 err = snmp_process_getnext_request(&request); 00203 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { 00204 err = snmp_process_getbulk_request(&request); 00205 } else if (request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { 00206 err = snmp_process_set_request(&request); 00207 } 00208 } 00209 00210 if (err == ERR_OK) { 00211 err = snmp_complete_outbound_frame(&request); 00212 00213 if (err == ERR_OK) { 00214 err = snmp_sendto(request.handle, request.outbound_pbuf, request.source_ip, request.source_port); 00215 00216 if ((request.request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) 00217 && (request.error_status == SNMP_ERR_NOERROR) 00218 && (snmp_write_callback != NULL)) { 00219 /* raise write notification for all written objects */ 00220 snmp_execute_write_callbacks(&request); 00221 } 00222 } 00223 } 00224 } 00225 00226 if (request.outbound_pbuf != NULL) { 00227 pbuf_free(request.outbound_pbuf); 00228 } 00229 } 00230 } 00231 00232 static u8_t 00233 snmp_msg_getnext_validate_node_inst(struct snmp_node_instance* node_instance, void* validate_arg) 00234 { 00235 if (((node_instance->access & SNMP_NODE_INSTANCE_ACCESS_READ) != SNMP_NODE_INSTANCE_ACCESS_READ) || (node_instance->get_value == NULL)) { 00236 return SNMP_ERR_NOSUCHINSTANCE; 00237 } 00238 00239 if ((node_instance->asn1_type == SNMP_ASN1_TYPE_COUNTER64) && (((struct snmp_request*)validate_arg)->version == SNMP_VERSION_1)) { 00240 /* according to RFC 2089 skip Counter64 objects in GetNext requests from v1 clients */ 00241 return SNMP_ERR_NOSUCHINSTANCE; 00242 } 00243 00244 return SNMP_ERR_NOERROR; 00245 } 00246 00247 static void 00248 snmp_process_varbind(struct snmp_request *request, struct snmp_varbind *vb, u8_t get_next) 00249 { 00250 err_t err; 00251 struct snmp_node_instance node_instance; 00252 memset(&node_instance, 0, sizeof(node_instance)); 00253 00254 if (get_next) { 00255 struct snmp_obj_id result_oid; 00256 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); 00257 00258 if (request->error_status == SNMP_ERR_NOERROR) { 00259 snmp_oid_assign(&vb->oid, result_oid.id, result_oid.len); 00260 } 00261 } else { 00262 request->error_status = snmp_get_node_instance_from_oid(vb->oid.id, vb->oid.len, &node_instance); 00263 00264 if (request->error_status == SNMP_ERR_NOERROR) { 00265 /* use 'getnext_validate' method for validation to avoid code duplication (some checks have to be executed here) */ 00266 request->error_status = snmp_msg_getnext_validate_node_inst(&node_instance, request); 00267 00268 if (request->error_status != SNMP_ERR_NOERROR) { 00269 if (node_instance.release_instance != NULL) { 00270 node_instance.release_instance(&node_instance); 00271 } 00272 } 00273 } 00274 } 00275 00276 if (request->error_status != SNMP_ERR_NOERROR) { 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 request 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 request 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 request 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 request 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 if (node_instance.asn1_type != vb.type) { 00517 request->error_status = SNMP_ERR_WRONGTYPE; 00518 } else if (((node_instance.access & SNMP_NODE_INSTANCE_ACCESS_WRITE) != SNMP_NODE_INSTANCE_ACCESS_WRITE) || (node_instance.set_value == NULL)) { 00519 request->error_status = SNMP_ERR_NOTWRITABLE; 00520 } else { 00521 if (node_instance.set_test != NULL) { 00522 request->error_status = node_instance.set_test(&node_instance, vb.value_len, vb.value); 00523 } 00524 } 00525 00526 if (node_instance.release_instance != NULL) { 00527 node_instance.release_instance(&node_instance); 00528 } 00529 } 00530 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00531 /* no more varbinds in request */ 00532 break; 00533 } else if (err == SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH) { 00534 request->error_status = SNMP_ERR_WRONGLENGTH; 00535 } else if (err == SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) { 00536 /* malformed ASN.1, don't answer */ 00537 return ERR_ARG; 00538 } else { 00539 request->error_status = SNMP_ERR_GENERROR; 00540 } 00541 } 00542 00543 /* perform real set operation on all objects */ 00544 if (request->error_status == SNMP_ERR_NOERROR) { 00545 snmp_vb_enumerator_init(&request->inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); 00546 while (request->error_status == SNMP_ERR_NOERROR) { 00547 err = snmp_vb_enumerator_get_next(&request->inbound_varbind_enumerator, &vb); 00548 if (err == SNMP_VB_ENUMERATOR_ERR_OK) { 00549 struct snmp_node_instance node_instance; 00550 memset(&node_instance, 0, sizeof(node_instance)); 00551 request->error_status = snmp_get_node_instance_from_oid(vb.oid.id, vb.oid.len, &node_instance); 00552 if (request->error_status == SNMP_ERR_NOERROR) { 00553 if (node_instance.set_value(&node_instance, vb.value_len, vb.value) != SNMP_ERR_NOERROR) { 00554 if (request->inbound_varbind_enumerator.varbind_count == 1) { 00555 request->error_status = SNMP_ERR_COMMITFAILED; 00556 } else { 00557 /* we cannot undo the set operations done so far */ 00558 request->error_status = SNMP_ERR_UNDOFAILED; 00559 } 00560 } 00561 00562 if (node_instance.release_instance != NULL) { 00563 node_instance.release_instance(&node_instance); 00564 } 00565 } 00566 } else if (err == SNMP_VB_ENUMERATOR_ERR_EOVB) { 00567 /* no more varbinds in request */ 00568 break; 00569 } else { 00570 /* first time enumerating varbinds work but second time not, although nothing should have changed in between ??? */ 00571 request->error_status = SNMP_ERR_GENERROR; 00572 } 00573 } 00574 } 00575 00576 return ERR_OK; 00577 } 00578 00579 #define PARSE_EXEC(code, retValue) \ 00580 if ((code) != ERR_OK) { \ 00581 LWIP_DEBUGF(SNMP_DEBUG, ("Malformed ASN.1 detected.\n")); \ 00582 snmp_stats.inasnparseerrs++; \ 00583 return retValue; \ 00584 } 00585 00586 #define PARSE_ASSERT(cond, retValue) \ 00587 if (!(cond)) { \ 00588 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP parse assertion failed!: " # cond)); \ 00589 snmp_stats.inasnparseerrs++; \ 00590 return retValue; \ 00591 } 00592 00593 #define BUILD_EXEC(code, retValue) \ 00594 if ((code) != ERR_OK) { \ 00595 LWIP_DEBUGF(SNMP_DEBUG, ("SNMP error during creation of outbound frame!: " # code)); \ 00596 return retValue; \ 00597 } 00598 00599 #define IF_PARSE_EXEC(code) PARSE_EXEC(code, ERR_ARG) 00600 #define IF_PARSE_ASSERT(code) PARSE_ASSERT(code, ERR_ARG) 00601 00602 /** 00603 * Checks and decodes incoming SNMP message header, logs header errors. 00604 * 00605 * @param request points to the current message request state return 00606 * @return 00607 * - ERR_OK SNMP header is sane and accepted 00608 * - ERR_VAL SNMP header is either malformed or rejected 00609 */ 00610 static err_t 00611 snmp_parse_inbound_frame(struct snmp_request *request) 00612 { 00613 struct snmp_pbuf_stream pbuf_stream; 00614 struct snmp_asn1_tlv tlv; 00615 s32_t parent_tlv_value_len; 00616 s32_t s32_value; 00617 err_t err; 00618 00619 IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); 00620 00621 /* decode main container consisting of version, community and PDU */ 00622 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00623 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len == pbuf_stream.length)); 00624 parent_tlv_value_len = tlv.value_len; 00625 00626 /* decode version */ 00627 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00628 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00629 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00630 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00631 00632 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00633 if ((s32_value != SNMP_VERSION_1) && 00634 (s32_value != SNMP_VERSION_2c) 00635 #if LWIP_SNMP_V3 00636 && (s32_value != SNMP_VERSION_3) 00637 #endif 00638 ) 00639 { 00640 /* unsupported SNMP version */ 00641 snmp_stats.inbadversions++; 00642 return ERR_ARG; 00643 } 00644 request->version = (u8_t)s32_value; 00645 00646 #if LWIP_SNMP_V3 00647 if (request->version == SNMP_VERSION_3) { 00648 u16_t u16_value; 00649 u16_t inbound_msgAuthenticationParameters_offset; 00650 00651 /* SNMPv3 doesn't use communities */ 00652 /* @todo: Differentiate read/write access */ 00653 strcpy((char*)request->community, snmp_community); 00654 request->community_strlen = (u16_t)strlen(snmp_community); 00655 00656 /* RFC3414 globalData */ 00657 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00658 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); 00659 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00660 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00661 00662 /* decode msgID */ 00663 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00664 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00665 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00666 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00667 00668 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00669 request->msg_id = s32_value; 00670 00671 /* decode msgMaxSize */ 00672 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00673 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00674 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00675 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00676 00677 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00678 request->msg_max_size = s32_value; 00679 00680 /* decode msgFlags */ 00681 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00682 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00683 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00684 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00685 00686 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00687 request->msg_flags = (u8_t)s32_value; 00688 00689 /* decode msgSecurityModel */ 00690 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00691 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00692 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00693 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00694 00695 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00696 request->msg_security_model = s32_value; 00697 00698 /* RFC3414 msgSecurityParameters 00699 * The User-based Security Model defines the contents of the OCTET 00700 * STRING as a SEQUENCE. 00701 * 00702 * We skip the protective dummy OCTET STRING header 00703 * to access the SEQUENCE header. 00704 */ 00705 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00706 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00707 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00708 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00709 00710 /* msgSecurityParameters SEQUENCE header */ 00711 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00712 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); 00713 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00714 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00715 00716 /* decode msgAuthoritativeEngineID */ 00717 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00718 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00719 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00720 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00721 00722 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authoritative_engine_id, 00723 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); 00724 request->msg_authoritative_engine_id_len = (u8_t)u16_value; 00725 00726 /* msgAuthoritativeEngineBoots */ 00727 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00728 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00729 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00730 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00731 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_boots)); 00732 00733 /* msgAuthoritativeEngineTime */ 00734 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00735 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00736 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00737 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00738 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->msg_authoritative_engine_time)); 00739 /* @todo: Implement time window checking */ 00740 00741 /* msgUserName */ 00742 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00743 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00744 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00745 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00746 00747 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_user_name, 00748 &u16_value, SNMP_V3_MAX_USER_LENGTH)); 00749 request->msg_user_name_len = (u8_t)u16_value; 00750 /* @todo: Implement unknown user error response */ 00751 IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, NULL, NULL)); 00752 00753 /* msgAuthenticationParameters */ 00754 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 00755 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00756 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00757 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00758 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00759 /* Remember position */ 00760 inbound_msgAuthenticationParameters_offset = pbuf_stream.offset; 00761 LWIP_UNUSED_ARG(inbound_msgAuthenticationParameters_offset); 00762 /* Read auth parameters */ 00763 IF_PARSE_ASSERT(tlv.value_len <= SNMP_V3_MAX_AUTH_PARAM_LENGTH); 00764 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_authentication_parameters, 00765 &u16_value, tlv.value_len)); 00766 00767 #if LWIP_SNMP_V3_CRYPTO 00768 if (request->msg_flags & SNMP_V3_AUTH_FLAG) { 00769 const u8_t zero_arr[SNMP_V3_MAX_AUTH_PARAM_LENGTH] = { 0 }; 00770 u8_t key[20]; 00771 u8_t algo; 00772 u8_t hmac[LWIP_MAX(SNMP_V3_SHA_LEN, SNMP_V3_MD5_LEN)]; 00773 struct snmp_pbuf_stream auth_stream; 00774 00775 /* Rewind stream */ 00776 IF_PARSE_EXEC(snmp_pbuf_stream_init(&pbuf_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); 00777 IF_PARSE_EXEC(snmp_pbuf_stream_seek_abs(&pbuf_stream, inbound_msgAuthenticationParameters_offset)); 00778 /* Set auth parameters to zero for verification */ 00779 IF_PARSE_EXEC(snmp_asn1_enc_raw(&pbuf_stream, zero_arr, tlv.value_len)); 00780 00781 /* Verify authentication */ 00782 IF_PARSE_EXEC(snmp_pbuf_stream_init(&auth_stream, request->inbound_pbuf, 0, request->inbound_pbuf->tot_len)); 00783 00784 IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, &algo, key, NULL, NULL)); 00785 IF_PARSE_EXEC(snmpv3_auth(&auth_stream, request->inbound_pbuf->tot_len, key, algo, hmac)); 00786 /* @todo: Implement error response */ 00787 IF_PARSE_EXEC(memcmp(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); 00788 } 00789 #else 00790 /* Ungraceful exit if we encounter cryptography and don't support it. 00791 * @todo: Implement error response 00792 */ 00793 IF_PARSE_ASSERT(!(request->msg_flags & (SNMP_V3_AUTH_FLAG | SNMP_V3_PRIV_FLAG))); 00794 #endif 00795 00796 /* msgPrivacyParameters */ 00797 memset(request->msg_privacy_parameters, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); 00798 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00799 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00800 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00801 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00802 00803 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->msg_privacy_parameters, 00804 &u16_value, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); 00805 00806 #if LWIP_SNMP_V3_CRYPTO 00807 /* Decrypt message */ 00808 if (request->msg_flags & SNMP_V3_PRIV_FLAG) { 00809 u8_t key[20]; 00810 u8_t algo; 00811 00812 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00813 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00814 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00815 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00816 00817 IF_PARSE_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, &algo, key)); 00818 IF_PARSE_EXEC(snmpv3_crypt(&pbuf_stream, tlv.value_len, key, 00819 request->msg_privacy_parameters, request->msg_authoritative_engine_boots, 00820 request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_DECRYPT)); 00821 } 00822 #endif 00823 00824 /* Scoped PDU 00825 * Encryption context 00826 */ 00827 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00828 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_SEQUENCE); 00829 parent_tlv_value_len -= SNMP_ASN1_TLV_HDR_LENGTH(tlv); 00830 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00831 00832 /* contextEngineID */ 00833 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00834 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00835 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00836 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00837 00838 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_engine_id, 00839 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); 00840 request->context_engine_id_len = (u8_t)u16_value; 00841 00842 /* contextName */ 00843 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00844 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00845 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00846 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00847 00848 IF_PARSE_EXEC(snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->context_name, 00849 &u16_value, SNMP_V3_MAX_ENGINE_ID_LENGTH)); 00850 request->context_name_len = (u8_t)u16_value; 00851 } else 00852 #endif 00853 { 00854 /* decode community */ 00855 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00856 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_OCTET_STRING); 00857 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00858 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00859 00860 err = snmp_asn1_dec_raw(&pbuf_stream, tlv.value_len, request->community, &request->community_strlen, SNMP_MAX_COMMUNITY_STR_LEN); 00861 if (err == ERR_MEM) { 00862 /* community string does not fit in our buffer -> its too long -> its invalid */ 00863 request->community_strlen = 0; 00864 snmp_pbuf_stream_seek(&pbuf_stream, tlv.value_len); 00865 } else { 00866 IF_PARSE_ASSERT(err == ERR_OK); 00867 } 00868 /* add zero terminator */ 00869 request->community[request->community_strlen] = 0; 00870 } 00871 00872 /* decode PDU type (next container level) */ 00873 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00874 IF_PARSE_ASSERT(tlv.value_len <= pbuf_stream.length); 00875 request->inbound_padding_len = pbuf_stream.length - tlv.value_len; 00876 parent_tlv_value_len = tlv.value_len; 00877 00878 /* validate PDU type */ 00879 switch(tlv.type) { 00880 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_REQ): 00881 /* GetRequest PDU */ 00882 snmp_stats.ingetrequests++; 00883 break; 00884 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_NEXT_REQ): 00885 /* GetNextRequest PDU */ 00886 snmp_stats.ingetnexts++; 00887 break; 00888 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ): 00889 /* GetBulkRequest PDU */ 00890 if (request->version < SNMP_VERSION_2c) { 00891 /* RFC2089: invalid, drop packet */ 00892 return ERR_ARG; 00893 } 00894 break; 00895 case (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_SET_REQ): 00896 /* SetRequest PDU */ 00897 snmp_stats.insetrequests++; 00898 break; 00899 default: 00900 /* unsupported input PDU for this agent (no parse error) */ 00901 LWIP_DEBUGF(SNMP_DEBUG, ("Unknown/Invalid SNMP PDU type received: %d", tlv.type)); \ 00902 return ERR_ARG; 00903 break; 00904 } 00905 request->request_type = tlv.type & SNMP_ASN1_DATATYPE_MASK; 00906 00907 /* validate community (do this after decoding PDU type because we don't want to increase 'inbadcommunitynames' for wrong frame types */ 00908 if (request->community_strlen == 0) { 00909 /* community string was too long or really empty*/ 00910 snmp_stats.inbadcommunitynames++; 00911 snmp_authfail_trap(); 00912 return ERR_ARG; 00913 } else if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { 00914 if (snmp_community_write[0] == 0) { 00915 /* our write community is empty, that means all our objects are readonly */ 00916 request->error_status = SNMP_ERR_NOTWRITABLE; 00917 request->error_index = 1; 00918 } else if (strncmp(snmp_community_write, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { 00919 /* community name does not match */ 00920 snmp_stats.inbadcommunitynames++; 00921 snmp_authfail_trap(); 00922 return ERR_ARG; 00923 } 00924 } else { 00925 if (strncmp(snmp_community, (const char*)request->community, SNMP_MAX_COMMUNITY_STR_LEN) != 0) { 00926 /* community name does not match */ 00927 snmp_stats.inbadcommunitynames++; 00928 snmp_authfail_trap(); 00929 return ERR_ARG; 00930 } 00931 } 00932 00933 /* decode request ID */ 00934 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00935 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00936 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00937 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00938 00939 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->request_id)); 00940 00941 /* decode error status / non-repeaters */ 00942 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00943 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00944 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00945 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00946 00947 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { 00948 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->non_repeaters)); 00949 if (request->non_repeaters < 0) { 00950 /* RFC 1905, 4.2.3 */ 00951 request->non_repeaters = 0; 00952 } 00953 } else { 00954 /* only check valid value, don't touch 'request->error_status', maybe a response error status was already set to above; */ 00955 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &s32_value)); 00956 IF_PARSE_ASSERT(s32_value == SNMP_ERR_NOERROR); 00957 } 00958 00959 /* decode error index / max-repetitions */ 00960 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00961 IF_PARSE_ASSERT(tlv.type == SNMP_ASN1_TYPE_INTEGER); 00962 parent_tlv_value_len -= SNMP_ASN1_TLV_LENGTH(tlv); 00963 IF_PARSE_ASSERT(parent_tlv_value_len > 0); 00964 00965 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_GET_BULK_REQ) { 00966 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->max_repetitions)); 00967 if (request->max_repetitions < 0) { 00968 /* RFC 1905, 4.2.3 */ 00969 request->max_repetitions = 0; 00970 } 00971 } else { 00972 IF_PARSE_EXEC(snmp_asn1_dec_s32t(&pbuf_stream, tlv.value_len, &request->error_index)); 00973 IF_PARSE_ASSERT(s32_value == 0); 00974 } 00975 00976 /* decode varbind-list type (next container level) */ 00977 IF_PARSE_EXEC(snmp_asn1_dec_tlv(&pbuf_stream, &tlv)); 00978 IF_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= pbuf_stream.length)); 00979 00980 request->inbound_varbind_offset = pbuf_stream.offset; 00981 request->inbound_varbind_len = pbuf_stream.length - request->inbound_padding_len; 00982 snmp_vb_enumerator_init(&(request->inbound_varbind_enumerator), request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); 00983 00984 return ERR_OK; 00985 } 00986 00987 #define OF_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) 00988 00989 static err_t 00990 snmp_prepare_outbound_frame(struct snmp_request *request) 00991 { 00992 struct snmp_asn1_tlv tlv; 00993 struct snmp_pbuf_stream* pbuf_stream = &(request->outbound_pbuf_stream); 00994 00995 /* try allocating pbuf(s) for maximum response size */ 00996 request->outbound_pbuf = pbuf_alloc(PBUF_TRANSPORT, 1472, PBUF_RAM); 00997 if (request->outbound_pbuf == NULL) { 00998 return ERR_MEM; 00999 } 01000 01001 snmp_pbuf_stream_init(pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len); 01002 01003 /* 'Message' sequence */ 01004 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); 01005 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01006 01007 /* version */ 01008 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01009 snmp_asn1_enc_s32t_cnt(request->version, &tlv.value_len); 01010 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01011 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->version) ); 01012 01013 #if LWIP_SNMP_V3 01014 if (request->version < SNMP_VERSION_3) { 01015 #endif 01016 /* community */ 01017 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->community_strlen); 01018 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01019 OF_BUILD_EXEC( snmp_asn1_enc_raw(pbuf_stream, request->community, request->community_strlen) ); 01020 #if LWIP_SNMP_V3 01021 } else { 01022 const char* id; 01023 01024 /* globalData */ 01025 request->outbound_msg_global_data_offset = pbuf_stream->offset; 01026 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); 01027 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01028 01029 /* msgID */ 01030 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01031 snmp_asn1_enc_s32t_cnt(request->msg_id, &tlv.value_len); 01032 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01033 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_id)); 01034 01035 /* msgMaxSize */ 01036 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01037 snmp_asn1_enc_s32t_cnt(request->msg_max_size, &tlv.value_len); 01038 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01039 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_max_size)); 01040 01041 /* msgFlags */ 01042 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 1); 01043 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01044 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, &request->msg_flags, 1)); 01045 01046 /* msgSecurityModel */ 01047 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01048 snmp_asn1_enc_s32t_cnt(request->msg_security_model, &tlv.value_len); 01049 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01050 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_security_model)); 01051 01052 /* end of msgGlobalData */ 01053 request->outbound_msg_global_data_end = pbuf_stream->offset; 01054 01055 /* msgSecurityParameters */ 01056 request->outbound_msg_security_parameters_str_offset = pbuf_stream->offset; 01057 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, 0); 01058 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01059 01060 request->outbound_msg_security_parameters_seq_offset = pbuf_stream->offset; 01061 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, 0); 01062 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01063 01064 /* msgAuthoritativeEngineID */ 01065 snmpv3_get_engine_id(&id, &request->msg_authoritative_engine_id_len); 01066 MEMCPY(request->msg_authoritative_engine_id, id, request->msg_authoritative_engine_id_len); 01067 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_authoritative_engine_id_len); 01068 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01069 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authoritative_engine_id, request->msg_authoritative_engine_id_len)); 01070 01071 request->msg_authoritative_engine_time = snmpv3_get_engine_time(); 01072 request->msg_authoritative_engine_boots = snmpv3_get_engine_boots(); 01073 01074 /* msgAuthoritativeEngineBoots */ 01075 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01076 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_boots, &tlv.value_len); 01077 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01078 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_boots)); 01079 01080 /* msgAuthoritativeEngineTime */ 01081 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01082 snmp_asn1_enc_s32t_cnt(request->msg_authoritative_engine_time, &tlv.value_len); 01083 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01084 OF_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->msg_authoritative_engine_time)); 01085 01086 /* msgUserName */ 01087 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->msg_user_name_len); 01088 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01089 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_user_name, request->msg_user_name_len)); 01090 01091 #if LWIP_SNMP_V3_CRYPTO 01092 /* msgAuthenticationParameters */ 01093 if (request->msg_flags & SNMP_V3_AUTH_FLAG) { 01094 memset(request->msg_authentication_parameters, 0, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01095 request->outbound_msg_authentication_parameters_offset = pbuf_stream->offset; 01096 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01097 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01098 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); 01099 } else 01100 #endif 01101 { 01102 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); 01103 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01104 } 01105 01106 #if LWIP_SNMP_V3_CRYPTO 01107 /* msgPrivacyParameters */ 01108 if (request->msg_flags & SNMP_V3_PRIV_FLAG) { 01109 snmpv3_build_priv_param(request->msg_privacy_parameters); 01110 01111 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, SNMP_V3_MAX_PRIV_PARAM_LENGTH); 01112 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01113 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->msg_privacy_parameters, SNMP_V3_MAX_PRIV_PARAM_LENGTH)); 01114 } else 01115 #endif 01116 { 01117 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, 0); 01118 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01119 } 01120 01121 /* End of msgSecurityParameters, so we can calculate the length of this sequence later */ 01122 request->outbound_msg_security_parameters_end = pbuf_stream->offset; 01123 01124 #if LWIP_SNMP_V3_CRYPTO 01125 /* For encryption we have to encapsulate the payload in an octet string */ 01126 if (request->msg_flags & SNMP_V3_PRIV_FLAG) { 01127 request->outbound_scoped_pdu_string_offset = pbuf_stream->offset; 01128 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, 0); 01129 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01130 } 01131 #endif 01132 /* Scoped PDU 01133 * Encryption context 01134 */ 01135 request->outbound_scoped_pdu_seq_offset = pbuf_stream->offset; 01136 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); 01137 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01138 01139 /* contextEngineID */ 01140 snmpv3_get_engine_id(&id, &request->context_engine_id_len); 01141 MEMCPY(request->context_engine_id, id, request->context_engine_id_len); 01142 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_engine_id_len); 01143 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01144 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_engine_id, request->context_engine_id_len)); 01145 01146 /* contextName */ 01147 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 0, request->context_name_len); 01148 OF_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01149 OF_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, request->context_name, request->context_name_len)); 01150 } 01151 #endif 01152 01153 /* 'PDU' sequence */ 01154 request->outbound_pdu_offset = pbuf_stream->offset; 01155 SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 0); 01156 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01157 01158 /* request ID */ 01159 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 0); 01160 snmp_asn1_enc_s32t_cnt(request->request_id, &tlv.value_len); 01161 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01162 OF_BUILD_EXEC( snmp_asn1_enc_s32t(pbuf_stream, tlv.value_len, request->request_id) ); 01163 01164 /* error status */ 01165 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01166 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01167 request->outbound_error_status_offset = pbuf_stream->offset; 01168 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); 01169 01170 /* error index */ 01171 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_INTEGER, 0, 1); 01172 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01173 request->outbound_error_index_offset = pbuf_stream->offset; 01174 OF_BUILD_EXEC( snmp_pbuf_stream_write(pbuf_stream, 0) ); 01175 01176 /* 'VarBindList' sequence */ 01177 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, 0); 01178 OF_BUILD_EXEC( snmp_ans1_enc_tlv(pbuf_stream, &tlv) ); 01179 01180 request->outbound_varbind_offset = pbuf_stream->offset; 01181 01182 return ERR_OK; 01183 } 01184 01185 /** Calculate the length of a varbind list */ 01186 err_t 01187 snmp_varbind_length(struct snmp_varbind *varbind, struct snmp_varbind_len *len) 01188 { 01189 /* calculate required lengths */ 01190 snmp_asn1_enc_oid_cnt(varbind->oid.id, varbind->oid.len, &len->oid_value_len); 01191 snmp_asn1_enc_length_cnt(len->oid_value_len, &len->oid_len_len); 01192 01193 if (varbind->value_len == 0) { 01194 len->value_value_len = 0; 01195 } else if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { 01196 len->value_value_len = varbind->value_len & (~SNMP_GET_VALUE_RAW_DATA); 01197 } else { 01198 switch (varbind->type) { 01199 case SNMP_ASN1_TYPE_INTEGER: 01200 if (varbind->value_len != sizeof (s32_t)) { 01201 return ERR_VAL; 01202 } 01203 snmp_asn1_enc_s32t_cnt(*((s32_t*) varbind->value), &len->value_value_len); 01204 break; 01205 case SNMP_ASN1_TYPE_COUNTER: 01206 case SNMP_ASN1_TYPE_GAUGE: 01207 case SNMP_ASN1_TYPE_TIMETICKS: 01208 if (varbind->value_len != sizeof (u32_t)) { 01209 return ERR_VAL; 01210 } 01211 snmp_asn1_enc_u32t_cnt(*((u32_t*) varbind->value), &len->value_value_len); 01212 break; 01213 case SNMP_ASN1_TYPE_OCTET_STRING: 01214 case SNMP_ASN1_TYPE_IPADDR: 01215 case SNMP_ASN1_TYPE_OPAQUE: 01216 len->value_value_len = varbind->value_len; 01217 break; 01218 case SNMP_ASN1_TYPE_NULL: 01219 if (varbind->value_len != 0) { 01220 return ERR_VAL; 01221 } 01222 len->value_value_len = 0; 01223 break; 01224 case SNMP_ASN1_TYPE_OBJECT_ID: 01225 if ((varbind->value_len & 0x03) != 0) { 01226 return ERR_VAL; 01227 } 01228 snmp_asn1_enc_oid_cnt((u32_t*) varbind->value, varbind->value_len >> 2, &len->value_value_len); 01229 break; 01230 case SNMP_ASN1_TYPE_COUNTER64: 01231 if (varbind->value_len != (2 * sizeof (u32_t))) { 01232 return ERR_VAL; 01233 } 01234 snmp_asn1_enc_u64t_cnt((u32_t*) varbind->value, &len->value_value_len); 01235 break; 01236 default: 01237 /* unsupported type */ 01238 return ERR_VAL; 01239 } 01240 } 01241 snmp_asn1_enc_length_cnt(len->value_value_len, &len->value_len_len); 01242 01243 len->vb_value_len = 1 + len->oid_len_len + len->oid_value_len + 1 + len->value_len_len + len->value_value_len; 01244 snmp_asn1_enc_length_cnt(len->vb_value_len, &len->vb_len_len); 01245 01246 return ERR_OK; 01247 } 01248 01249 #define OVB_BUILD_EXEC(code) BUILD_EXEC(code, ERR_ARG) 01250 01251 err_t 01252 snmp_append_outbound_varbind(struct snmp_pbuf_stream *pbuf_stream, struct snmp_varbind* varbind) 01253 { 01254 struct snmp_asn1_tlv tlv; 01255 struct snmp_varbind_len len; 01256 err_t err; 01257 01258 err = snmp_varbind_length(varbind, &len); 01259 01260 if (err != ERR_OK) { 01261 return err; 01262 } 01263 01264 /* check length already before adding first data because in case of GetBulk, 01265 * data added so far is returned and therefore no partial data shall be added 01266 */ 01267 if ((1 + len.vb_len_len + len.vb_value_len) > pbuf_stream->length) { 01268 return ERR_BUF; 01269 } 01270 01271 /* 'VarBind' sequence */ 01272 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, len.vb_len_len, len.vb_value_len); 01273 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01274 01275 /* VarBind OID */ 01276 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OBJECT_ID, len.oid_len_len, len.oid_value_len); 01277 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01278 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, varbind->oid.id, varbind->oid.len)); 01279 01280 /* VarBind value */ 01281 SNMP_ASN1_SET_TLV_PARAMS(tlv, varbind->type, len.value_len_len, len.value_value_len); 01282 OVB_BUILD_EXEC(snmp_ans1_enc_tlv(pbuf_stream, &tlv)); 01283 01284 if (len.value_value_len > 0) { 01285 if (varbind->value_len & SNMP_GET_VALUE_RAW_DATA) { 01286 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); 01287 } else { 01288 switch (varbind->type) { 01289 case SNMP_ASN1_TYPE_INTEGER: 01290 OVB_BUILD_EXEC(snmp_asn1_enc_s32t(pbuf_stream, len.value_value_len, *((s32_t*) varbind->value))); 01291 break; 01292 case SNMP_ASN1_TYPE_COUNTER: 01293 case SNMP_ASN1_TYPE_GAUGE: 01294 case SNMP_ASN1_TYPE_TIMETICKS: 01295 OVB_BUILD_EXEC(snmp_asn1_enc_u32t(pbuf_stream, len.value_value_len, *((u32_t*) varbind->value))); 01296 break; 01297 case SNMP_ASN1_TYPE_OCTET_STRING: 01298 case SNMP_ASN1_TYPE_IPADDR: 01299 case SNMP_ASN1_TYPE_OPAQUE: 01300 OVB_BUILD_EXEC(snmp_asn1_enc_raw(pbuf_stream, (u8_t*) varbind->value, len.value_value_len)); 01301 len.value_value_len = varbind->value_len; 01302 break; 01303 case SNMP_ASN1_TYPE_OBJECT_ID: 01304 OVB_BUILD_EXEC(snmp_asn1_enc_oid(pbuf_stream, (u32_t*) varbind->value, varbind->value_len / sizeof (u32_t))); 01305 break; 01306 case SNMP_ASN1_TYPE_COUNTER64: 01307 OVB_BUILD_EXEC(snmp_asn1_enc_u64t(pbuf_stream, len.value_value_len, (u32_t*) varbind->value)); 01308 break; 01309 default: 01310 LWIP_ASSERT("Unknown variable type", 0); 01311 break; 01312 } 01313 } 01314 } 01315 01316 return ERR_OK; 01317 } 01318 01319 static err_t 01320 snmp_complete_outbound_frame(struct snmp_request *request) 01321 { 01322 struct snmp_asn1_tlv tlv; 01323 u16_t frame_size; 01324 u8_t outbound_padding = 0; 01325 01326 if (request->version == SNMP_VERSION_1) { 01327 if (request->error_status != SNMP_ERR_NOERROR) { 01328 /* map v2c error codes to v1 compliant error code (according to RFC 2089) */ 01329 switch (request->error_status) { 01330 /* mapping of implementation specific "virtual" error codes 01331 * (during processing of frame we already stored them in error_status field, 01332 * so no need to check all varbinds here for those exceptions as suggested by RFC) */ 01333 case SNMP_ERR_NOSUCHINSTANCE: 01334 case SNMP_ERR_NOSUCHOBJECT: 01335 case SNMP_ERR_ENDOFMIBVIEW: 01336 request->error_status = SNMP_ERR_NOSUCHNAME; 01337 break; 01338 /* mapping according to RFC */ 01339 case SNMP_ERR_WRONGVALUE: 01340 case SNMP_ERR_WRONGENCODING: 01341 case SNMP_ERR_WRONGTYPE: 01342 case SNMP_ERR_WRONGLENGTH: 01343 case SNMP_ERR_INCONSISTENTVALUE: 01344 request->error_status = SNMP_ERR_BADVALUE; 01345 break; 01346 case SNMP_ERR_NOACCESS: 01347 case SNMP_ERR_NOTWRITABLE: 01348 case SNMP_ERR_NOCREATION: 01349 case SNMP_ERR_INCONSISTENTNAME: 01350 case SNMP_ERR_AUTHORIZATIONERROR: 01351 request->error_status = SNMP_ERR_NOSUCHNAME; 01352 break; 01353 case SNMP_ERR_RESOURCEUNAVAILABLE: 01354 case SNMP_ERR_COMMITFAILED: 01355 case SNMP_ERR_UNDOFAILED: 01356 default: 01357 request->error_status = SNMP_ERR_GENERROR; 01358 break; 01359 } 01360 } 01361 } else { 01362 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { 01363 /* map error codes to according to RFC 1905 (4.2.5. The SetRequest-PDU) return 'NotWritable' for unknown OIDs) */ 01364 switch (request->error_status) { 01365 case SNMP_ERR_NOSUCHINSTANCE: 01366 case SNMP_ERR_NOSUCHOBJECT: 01367 case SNMP_ERR_ENDOFMIBVIEW: 01368 request->error_status = SNMP_ERR_NOTWRITABLE; 01369 break; 01370 default: 01371 break; 01372 } 01373 } 01374 01375 if (request->error_status >= SNMP_VARBIND_EXCEPTION_OFFSET) { 01376 /* should never occur because v2 frames store exceptions directly inside varbinds and not as frame error_status */ 01377 LWIP_DEBUGF(SNMP_DEBUG, ("snmp_complete_outbound_frame() > Found v2 request with varbind exception code stored as error status!\n")); 01378 return ERR_ARG; 01379 } 01380 } 01381 01382 if ((request->error_status != SNMP_ERR_NOERROR) || (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ)) { 01383 /* all inbound vars are returned in response without any modification for error responses and successful set requests*/ 01384 struct snmp_pbuf_stream inbound_stream; 01385 OF_BUILD_EXEC( snmp_pbuf_stream_init(&inbound_stream, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len) ); 01386 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) ); 01387 snmp_pbuf_stream_writeto(&inbound_stream, &(request->outbound_pbuf_stream), 0); 01388 } 01389 01390 frame_size = request->outbound_pbuf_stream.offset; 01391 01392 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO 01393 /* Calculate padding for encryption */ 01394 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { 01395 u8_t i; 01396 outbound_padding = (8 - (u8_t)((frame_size - request->outbound_scoped_pdu_seq_offset) & 0x07)) & 0x07; 01397 for (i = 0; i < outbound_padding; i++) { 01398 snmp_pbuf_stream_write(&request->outbound_pbuf_stream, 0); 01399 } 01400 } 01401 #endif 01402 01403 /* complete missing length in 'Message' sequence ; 'Message' tlv is located at the beginning (offset 0) */ 01404 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()) */ 01405 OF_BUILD_EXEC( snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), request->outbound_pbuf, 0, request->outbound_pbuf->tot_len) ); 01406 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); 01407 01408 #if LWIP_SNMP_V3 01409 if (request->version == SNMP_VERSION_3) { 01410 /* complete missing length in 'globalData' sequence */ 01411 /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ 01412 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_global_data_end 01413 - request->outbound_msg_global_data_offset - 1 - 1); 01414 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_global_data_offset)); 01415 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01416 01417 /* complete missing length in 'msgSecurityParameters' sequence */ 01418 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, request->outbound_msg_security_parameters_end 01419 - request->outbound_msg_security_parameters_str_offset - 1 - 1); 01420 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_str_offset)); 01421 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01422 01423 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 1, request->outbound_msg_security_parameters_end 01424 - request->outbound_msg_security_parameters_seq_offset - 1 - 1); 01425 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_msg_security_parameters_seq_offset)); 01426 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01427 01428 /* complete missing length in scoped PDU sequence */ 01429 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_scoped_pdu_seq_offset - 1 - 3); 01430 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_seq_offset)); 01431 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01432 } 01433 #endif 01434 01435 /* complete missing length in 'PDU' sequence */ 01436 SNMP_ASN1_SET_TLV_PARAMS(tlv, (SNMP_ASN1_CLASS_CONTEXT | SNMP_ASN1_CONTENTTYPE_CONSTRUCTED | SNMP_ASN1_CONTEXT_PDU_GET_RESP), 3, 01437 frame_size - request->outbound_pdu_offset - 1 - 3); /* - type - length_len(fixed, see snmp_prepare_outbound_frame()) */ 01438 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_pdu_offset) ); 01439 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); 01440 01441 /* process and encode final error status */ 01442 if (request->error_status != 0) { 01443 u16_t len; 01444 snmp_asn1_enc_s32t_cnt(request->error_status, &len); 01445 if (len != 1) { 01446 /* error, we only reserved one byte for it */ 01447 return ERR_ARG; 01448 } 01449 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_status_offset) ); 01450 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_status) ); 01451 01452 /* for compatibility to v1, log statistics; in v2 (RFC 1907) these statistics are obsoleted */ 01453 switch (request->error_status) { 01454 case SNMP_ERR_TOOBIG: 01455 snmp_stats.outtoobigs++; 01456 break; 01457 case SNMP_ERR_NOSUCHNAME: 01458 snmp_stats.outnosuchnames++; 01459 break; 01460 case SNMP_ERR_BADVALUE: 01461 snmp_stats.outbadvalues++; 01462 break; 01463 case SNMP_ERR_GENERROR: 01464 default: 01465 snmp_stats.outgenerrs++; 01466 break; 01467 } 01468 01469 if (request->error_status == SNMP_ERR_TOOBIG) { 01470 request->error_index = 0; /* defined by RFC 1157 */ 01471 } else if (request->error_index == 0) { 01472 /* set index to varbind where error occured (if not already set before, e.g. during GetBulk processing) */ 01473 request->error_index = request->inbound_varbind_enumerator.varbind_count; 01474 } 01475 } else { 01476 if (request->request_type == SNMP_ASN1_CONTEXT_PDU_SET_REQ) { 01477 snmp_stats.intotalsetvars += request->inbound_varbind_enumerator.varbind_count; 01478 } else { 01479 snmp_stats.intotalreqvars += request->inbound_varbind_enumerator.varbind_count; 01480 } 01481 } 01482 01483 /* encode final error index*/ 01484 if (request->error_index != 0) { 01485 u16_t len; 01486 snmp_asn1_enc_s32t_cnt(request->error_index, &len); 01487 if (len != 1) { 01488 /* error, we only reserved one byte for it */ 01489 return ERR_VAL; 01490 } 01491 OF_BUILD_EXEC( snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_error_index_offset) ); 01492 OF_BUILD_EXEC( snmp_asn1_enc_s32t(&(request->outbound_pbuf_stream), len, request->error_index) ); 01493 } 01494 01495 /* complete missing length in 'VarBindList' sequence ; 'VarBindList' tlv is located directly before varbind offset */ 01496 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_SEQUENCE, 3, frame_size - request->outbound_varbind_offset); 01497 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()) */ 01498 OF_BUILD_EXEC( snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv) ); 01499 01500 /* Authenticate response */ 01501 #if LWIP_SNMP_V3 && LWIP_SNMP_V3_CRYPTO 01502 /* Encrypt response */ 01503 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_PRIV_FLAG)) { 01504 u8_t key[20]; 01505 u8_t algo; 01506 01507 /* complete missing length in PDU sequence */ 01508 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); 01509 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&(request->outbound_pbuf_stream), request->outbound_scoped_pdu_string_offset)); 01510 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 3, frame_size + outbound_padding 01511 - request->outbound_scoped_pdu_string_offset - 1 - 3); 01512 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&(request->outbound_pbuf_stream), &tlv)); 01513 01514 OF_BUILD_EXEC(snmpv3_get_user ((char*)request->msg_user_name, NULL, NULL, &algo, key)); 01515 01516 OF_BUILD_EXEC(snmpv3_crypt(&request->outbound_pbuf_stream, tlv.value_len, key, 01517 request->msg_privacy_parameters, request->msg_authoritative_engine_boots, 01518 request->msg_authoritative_engine_time, algo, SNMP_V3_PRIV_MODE_ENCRYPT)); 01519 } 01520 01521 if (request->version == SNMP_VERSION_3 && (request->msg_flags & SNMP_V3_AUTH_FLAG)) { 01522 u8_t key[20]; 01523 u8_t algo; 01524 u8_t hmac[20]; 01525 01526 OF_BUILD_EXEC(snmpv3_get_user ((char*)request->msg_user_name, &algo, key, NULL, NULL)); 01527 OF_BUILD_EXEC(snmp_pbuf_stream_init(&(request->outbound_pbuf_stream), 01528 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); 01529 OF_BUILD_EXEC(snmpv3_auth(&request->outbound_pbuf_stream, frame_size + outbound_padding, key, algo, hmac)); 01530 01531 MEMCPY(request->msg_authentication_parameters, hmac, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01532 OF_BUILD_EXEC(snmp_pbuf_stream_init(&request->outbound_pbuf_stream, 01533 request->outbound_pbuf, 0, request->outbound_pbuf->tot_len)); 01534 OF_BUILD_EXEC(snmp_pbuf_stream_seek_abs(&request->outbound_pbuf_stream, 01535 request->outbound_msg_authentication_parameters_offset)); 01536 01537 SNMP_ASN1_SET_TLV_PARAMS(tlv, SNMP_ASN1_TYPE_OCTET_STRING, 1, SNMP_V3_MAX_AUTH_PARAM_LENGTH); 01538 OF_BUILD_EXEC(snmp_ans1_enc_tlv(&request->outbound_pbuf_stream, &tlv)); 01539 OF_BUILD_EXEC(snmp_asn1_enc_raw(&request->outbound_pbuf_stream, 01540 request->msg_authentication_parameters, SNMP_V3_MAX_AUTH_PARAM_LENGTH)); 01541 } 01542 #endif 01543 01544 pbuf_realloc(request->outbound_pbuf, frame_size + outbound_padding); 01545 01546 snmp_stats.outgetresponses++; 01547 snmp_stats.outpkts++; 01548 01549 return ERR_OK; 01550 } 01551 01552 static void 01553 snmp_execute_write_callbacks(struct snmp_request *request) 01554 { 01555 struct snmp_varbind_enumerator inbound_varbind_enumerator; 01556 struct snmp_varbind vb; 01557 01558 snmp_vb_enumerator_init(&inbound_varbind_enumerator, request->inbound_pbuf, request->inbound_varbind_offset, request->inbound_varbind_len); 01559 vb.value = NULL; /* do NOT decode value (we enumerate outbound buffer here, so all varbinds have values assigned, which we don't need here) */ 01560 01561 while (snmp_vb_enumerator_get_next(&inbound_varbind_enumerator, &vb) == SNMP_VB_ENUMERATOR_ERR_OK) { 01562 snmp_write_callback(vb.oid.id, vb.oid.len, snmp_write_callback_arg); 01563 } 01564 } 01565 01566 01567 /* ----------------------------------------------------------------------- */ 01568 /* VarBind enumerator methods */ 01569 /* ----------------------------------------------------------------------- */ 01570 01571 void 01572 snmp_vb_enumerator_init(struct snmp_varbind_enumerator* enumerator, struct pbuf* p, u16_t offset, u16_t length) 01573 { 01574 snmp_pbuf_stream_init(&(enumerator->pbuf_stream), p, offset, length); 01575 enumerator->varbind_count = 0; 01576 } 01577 01578 #define VB_PARSE_EXEC(code) PARSE_EXEC(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) 01579 #define VB_PARSE_ASSERT(code) PARSE_ASSERT(code, SNMP_VB_ENUMERATOR_ERR_ASN1ERROR) 01580 01581 snmp_vb_enumerator_err_t 01582 snmp_vb_enumerator_get_next(struct snmp_varbind_enumerator* enumerator, struct snmp_varbind* varbind) 01583 { 01584 struct snmp_asn1_tlv tlv; 01585 u16_t varbind_len; 01586 err_t err; 01587 01588 if (enumerator->pbuf_stream.length == 0) 01589 { 01590 return SNMP_VB_ENUMERATOR_ERR_EOVB; 01591 } 01592 enumerator->varbind_count++; 01593 01594 /* decode varbind itself (parent container of a varbind) */ 01595 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); 01596 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_SEQUENCE) && (tlv.value_len <= enumerator->pbuf_stream.length)); 01597 varbind_len = tlv.value_len; 01598 01599 /* decode varbind name (object id) */ 01600 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); 01601 VB_PARSE_ASSERT((tlv.type == SNMP_ASN1_TYPE_OBJECT_ID) && (SNMP_ASN1_TLV_LENGTH(tlv) < varbind_len) && (tlv.value_len < enumerator->pbuf_stream.length)); 01602 01603 VB_PARSE_EXEC(snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, varbind->oid.id, &(varbind->oid.len), SNMP_MAX_OBJ_ID_LEN)); 01604 varbind_len -= SNMP_ASN1_TLV_LENGTH(tlv); 01605 01606 /* decode varbind value (object id) */ 01607 VB_PARSE_EXEC(snmp_asn1_dec_tlv(&(enumerator->pbuf_stream), &tlv)); 01608 VB_PARSE_ASSERT((SNMP_ASN1_TLV_LENGTH(tlv) == varbind_len) && (tlv.value_len <= enumerator->pbuf_stream.length)); 01609 varbind->type = tlv.type; 01610 01611 /* shall the value be decoded ? */ 01612 if (varbind->value != NULL) { 01613 switch (varbind->type) { 01614 case SNMP_ASN1_TYPE_INTEGER: 01615 VB_PARSE_EXEC(snmp_asn1_dec_s32t(&(enumerator->pbuf_stream), tlv.value_len, (s32_t*)varbind->value)); 01616 varbind->value_len = sizeof(s32_t*); 01617 break; 01618 case SNMP_ASN1_TYPE_COUNTER: 01619 case SNMP_ASN1_TYPE_GAUGE: 01620 case SNMP_ASN1_TYPE_TIMETICKS: 01621 VB_PARSE_EXEC(snmp_asn1_dec_u32t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); 01622 varbind->value_len = sizeof(u32_t*); 01623 break; 01624 case SNMP_ASN1_TYPE_OCTET_STRING: 01625 case SNMP_ASN1_TYPE_OPAQUE: 01626 err = snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE); 01627 if (err == ERR_MEM) { 01628 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; 01629 } 01630 VB_PARSE_ASSERT(err == ERR_OK); 01631 break; 01632 case SNMP_ASN1_TYPE_NULL: 01633 varbind->value_len = 0; 01634 break; 01635 case SNMP_ASN1_TYPE_OBJECT_ID: 01636 /* misuse tlv.length_len as OID_length transporter */ 01637 err = snmp_asn1_dec_oid(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value, &tlv.length_len, SNMP_MAX_OBJ_ID_LEN); 01638 if (err == ERR_MEM) { 01639 return SNMP_VB_ENUMERATOR_ERR_INVALIDLENGTH; 01640 } 01641 VB_PARSE_ASSERT(err == ERR_OK); 01642 varbind->value_len = tlv.length_len * sizeof(u32_t); 01643 break; 01644 case SNMP_ASN1_TYPE_IPADDR: 01645 if (tlv.value_len == 4) { 01646 /* must be exactly 4 octets! */ 01647 VB_PARSE_EXEC(snmp_asn1_dec_raw(&(enumerator->pbuf_stream), tlv.value_len, (u8_t*)varbind->value, &varbind->value_len, SNMP_MAX_VALUE_SIZE)); 01648 } else { 01649 VB_PARSE_ASSERT(0); 01650 } 01651 break; 01652 case SNMP_ASN1_TYPE_COUNTER64: 01653 VB_PARSE_EXEC(snmp_asn1_dec_u64t(&(enumerator->pbuf_stream), tlv.value_len, (u32_t*)varbind->value)); 01654 varbind->value_len = 2 * sizeof(u32_t*); 01655 break; 01656 default: 01657 VB_PARSE_ASSERT(0); 01658 break; 01659 } 01660 } else { 01661 snmp_pbuf_stream_seek(&(enumerator->pbuf_stream), tlv.value_len); 01662 varbind->value_len = tlv.value_len; 01663 } 01664 01665 return SNMP_VB_ENUMERATOR_ERR_OK; 01666 } 01667 01668 #endif /* LWIP_SNMP */
Generated on Sun Jul 17 2022 08:25:25 by
![doxygen](doxygen.png)