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.
Fork of OmniWheels by
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 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 Fri Jul 22 2022 04:53:53 by
1.7.2
