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 F7_Ethernet by
msg_in.c
00001 /** 00002 * @file 00003 * SNMP input message processing (RFC1157). 00004 */ 00005 00006 /* 00007 * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. 00008 * All rights reserved. 00009 * 00010 * Redistribution and use in source and binary forms, with or without modification, 00011 * are permitted provided that the following conditions are met: 00012 * 00013 * 1. Redistributions of source code must retain the above copyright notice, 00014 * this list of conditions and the following disclaimer. 00015 * 2. Redistributions in binary form must reproduce the above copyright notice, 00016 * this list of conditions and the following disclaimer in the documentation 00017 * and/or other materials provided with the distribution. 00018 * 3. The name of the author may not be used to endorse or promote products 00019 * derived from this software without specific prior written permission. 00020 * 00021 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 00022 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 00023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 00024 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 00025 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 00026 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 00027 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 00028 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 00029 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 00030 * OF SUCH DAMAGE. 00031 * 00032 * Author: Christiaan Simons <christiaan.simons@axon.tv> 00033 */ 00034 00035 #include "lwip/opt.h" 00036 00037 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ 00038 00039 #include "lwip/snmp.h" 00040 #include "lwip/snmp_asn1.h" 00041 #include "lwip/snmp_msg.h" 00042 #include "lwip/snmp_structs.h" 00043 #include "lwip/ip_addr.h" 00044 #include "lwip/memp.h" 00045 #include "lwip/udp.h" 00046 #include "lwip/stats.h" 00047 00048 #include <string.h> 00049 00050 /* public (non-static) constants */ 00051 /** SNMP v1 == 0 */ 00052 const s32_t snmp_version = 0; 00053 /** default SNMP community string */ 00054 const char snmp_publiccommunity[7] = "public"; 00055 00056 /* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */ 00057 struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS]; 00058 /* UDP Protocol Control Block */ 00059 struct udp_pcb *snmp1_pcb; 00060 00061 static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); 00062 static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); 00063 static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); 00064 00065 00066 /** 00067 * Starts SNMP Agent. 00068 * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161. 00069 */ 00070 void 00071 snmp_init(void) 00072 { 00073 struct snmp_msg_pstat *msg_ps; 00074 u8_t i; 00075 00076 snmp1_pcb = udp_new(); 00077 if (snmp1_pcb != NULL) 00078 { 00079 udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT); 00080 udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT); 00081 } 00082 msg_ps = &msg_input_list[0]; 00083 for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++) 00084 { 00085 msg_ps->state = SNMP_MSG_EMPTY; 00086 msg_ps->error_index = 0; 00087 msg_ps->error_status = SNMP_ES_NOERROR; 00088 msg_ps++; 00089 } 00090 trap_msg.pcb = snmp1_pcb; 00091 00092 #ifdef SNMP_PRIVATE_MIB_INIT 00093 /* If defined, this must be a function-like define to initialize the 00094 * private MIB after the stack has been initialized. 00095 * The private MIB can also be initialized in tcpip_callback (or after 00096 * the stack is initialized), this define is only for convenience. */ 00097 SNMP_PRIVATE_MIB_INIT(); 00098 #endif /* SNMP_PRIVATE_MIB_INIT */ 00099 00100 /* The coldstart trap will only be output 00101 if our outgoing interface is up & configured */ 00102 snmp_coldstart_trap(); 00103 } 00104 00105 static void 00106 snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error) 00107 { 00108 /* move names back from outvb to invb */ 00109 int v; 00110 struct snmp_varbind *vbi = msg_ps->invb.head; 00111 struct snmp_varbind *vbo = msg_ps->outvb.head; 00112 for (v=0; v<msg_ps->vb_idx; v++) { 00113 vbi->ident_len = vbo->ident_len; 00114 vbo->ident_len = 0; 00115 vbi->ident = vbo->ident; 00116 vbo->ident = NULL; 00117 vbi = vbi->next; 00118 vbo = vbo->next; 00119 } 00120 /* free outvb */ 00121 snmp_varbind_list_free(&msg_ps->outvb); 00122 /* we send invb back */ 00123 msg_ps->outvb = msg_ps->invb; 00124 msg_ps->invb.head = NULL; 00125 msg_ps->invb.tail = NULL; 00126 msg_ps->invb.count = 0; 00127 msg_ps->error_status = error; 00128 /* error index must be 0 for error too big */ 00129 msg_ps->error_index = (error != SNMP_ES_TOOBIG) ? (1 + msg_ps->vb_idx) : 0; 00130 snmp_send_response(msg_ps); 00131 snmp_varbind_list_free(&msg_ps->outvb); 00132 msg_ps->state = SNMP_MSG_EMPTY; 00133 } 00134 00135 static void 00136 snmp_ok_response(struct snmp_msg_pstat *msg_ps) 00137 { 00138 err_t err_ret; 00139 00140 err_ret = snmp_send_response(msg_ps); 00141 if (err_ret == ERR_MEM) 00142 { 00143 /* serious memory problem, can't return tooBig */ 00144 } 00145 else 00146 { 00147 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status)); 00148 } 00149 /* free varbinds (if available) */ 00150 snmp_varbind_list_free(&msg_ps->invb); 00151 snmp_varbind_list_free(&msg_ps->outvb); 00152 msg_ps->state = SNMP_MSG_EMPTY; 00153 } 00154 00155 /** 00156 * Service an internal or external event for SNMP GET. 00157 * 00158 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) 00159 * @param msg_ps points to the assosicated message process state 00160 */ 00161 static void 00162 snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) 00163 { 00164 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); 00165 00166 if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) 00167 { 00168 struct mib_external_node *en; 00169 struct snmp_name_ptr np; 00170 00171 /* get_object_def() answer*/ 00172 en = msg_ps->ext_mib_node; 00173 np = msg_ps->ext_name_ptr; 00174 00175 /* translate answer into a known lifeform */ 00176 en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); 00177 if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) && 00178 (msg_ps->ext_object_def.access & MIB_ACCESS_READ)) 00179 { 00180 msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; 00181 en->get_value_q(request_id, &msg_ps->ext_object_def); 00182 } 00183 else 00184 { 00185 en->get_object_def_pc(request_id, np.ident_len, np.ident); 00186 /* search failed, object id points to unknown object (nosuchname) */ 00187 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00188 } 00189 } 00190 else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) 00191 { 00192 struct mib_external_node *en; 00193 struct snmp_varbind *vb; 00194 00195 /* get_value() answer */ 00196 en = msg_ps->ext_mib_node; 00197 00198 /* allocate output varbind */ 00199 vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); 00200 if (vb != NULL) 00201 { 00202 vb->next = NULL; 00203 vb->prev = NULL; 00204 00205 /* move name from invb to outvb */ 00206 vb->ident = msg_ps->vb_ptr->ident; 00207 vb->ident_len = msg_ps->vb_ptr->ident_len; 00208 /* ensure this memory is refereced once only */ 00209 msg_ps->vb_ptr->ident = NULL; 00210 msg_ps->vb_ptr->ident_len = 0; 00211 00212 vb->value_type = msg_ps->ext_object_def.asn_type; 00213 LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); 00214 vb->value_len = (u8_t)msg_ps->ext_object_def.v_len; 00215 if (vb->value_len > 0) 00216 { 00217 LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); 00218 vb->value = memp_malloc(MEMP_SNMP_VALUE); 00219 if (vb->value != NULL) 00220 { 00221 en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); 00222 snmp_varbind_tail_add(&msg_ps->outvb, vb); 00223 /* search again (if vb_idx < msg_ps->invb.count) */ 00224 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00225 msg_ps->vb_idx += 1; 00226 } 00227 else 00228 { 00229 en->get_value_pc(request_id, &msg_ps->ext_object_def); 00230 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n")); 00231 msg_ps->vb_ptr->ident = vb->ident; 00232 msg_ps->vb_ptr->ident_len = vb->ident_len; 00233 memp_free(MEMP_SNMP_VARBIND, vb); 00234 snmp_error_response(msg_ps,SNMP_ES_TOOBIG); 00235 } 00236 } 00237 else 00238 { 00239 /* vb->value_len == 0, empty value (e.g. empty string) */ 00240 en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL); 00241 vb->value = NULL; 00242 snmp_varbind_tail_add(&msg_ps->outvb, vb); 00243 /* search again (if vb_idx < msg_ps->invb.count) */ 00244 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00245 msg_ps->vb_idx += 1; 00246 } 00247 } 00248 else 00249 { 00250 en->get_value_pc(request_id, &msg_ps->ext_object_def); 00251 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n")); 00252 snmp_error_response(msg_ps,SNMP_ES_TOOBIG); 00253 } 00254 } 00255 00256 while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00257 (msg_ps->vb_idx < msg_ps->invb.count)) 00258 { 00259 struct mib_node *mn; 00260 struct snmp_name_ptr np; 00261 00262 if (msg_ps->vb_idx == 0) 00263 { 00264 msg_ps->vb_ptr = msg_ps->invb.head; 00265 } 00266 else 00267 { 00268 msg_ps->vb_ptr = msg_ps->vb_ptr->next; 00269 } 00270 /** test object identifier for .iso.org.dod.internet prefix */ 00271 if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) 00272 { 00273 mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, 00274 msg_ps->vb_ptr->ident + 4, &np); 00275 if (mn != NULL) 00276 { 00277 if (mn->node_type == MIB_NODE_EX) 00278 { 00279 /* external object */ 00280 struct mib_external_node *en = (struct mib_external_node*)mn; 00281 00282 msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; 00283 /* save en && args in msg_ps!! */ 00284 msg_ps->ext_mib_node = en; 00285 msg_ps->ext_name_ptr = np; 00286 00287 en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); 00288 } 00289 else 00290 { 00291 /* internal object */ 00292 struct obj_def object_def; 00293 00294 msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; 00295 mn->get_object_def(np.ident_len, np.ident, &object_def); 00296 if ((object_def.instance != MIB_OBJECT_NONE) && 00297 (object_def.access & MIB_ACCESS_READ)) 00298 { 00299 mn = mn; 00300 } 00301 else 00302 { 00303 /* search failed, object id points to unknown object (nosuchname) */ 00304 mn = NULL; 00305 } 00306 if (mn != NULL) 00307 { 00308 struct snmp_varbind *vb; 00309 00310 msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; 00311 /* allocate output varbind */ 00312 vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); 00313 if (vb != NULL) 00314 { 00315 vb->next = NULL; 00316 vb->prev = NULL; 00317 00318 /* move name from invb to outvb */ 00319 vb->ident = msg_ps->vb_ptr->ident; 00320 vb->ident_len = msg_ps->vb_ptr->ident_len; 00321 /* ensure this memory is refereced once only */ 00322 msg_ps->vb_ptr->ident = NULL; 00323 msg_ps->vb_ptr->ident_len = 0; 00324 00325 vb->value_type = object_def.asn_type; 00326 LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); 00327 vb->value_len = (u8_t)object_def.v_len; 00328 if (vb->value_len > 0) 00329 { 00330 LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", 00331 vb->value_len <= SNMP_MAX_VALUE_SIZE); 00332 vb->value = memp_malloc(MEMP_SNMP_VALUE); 00333 if (vb->value != NULL) 00334 { 00335 mn->get_value(&object_def, vb->value_len, vb->value); 00336 snmp_varbind_tail_add(&msg_ps->outvb, vb); 00337 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00338 msg_ps->vb_idx += 1; 00339 } 00340 else 00341 { 00342 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n")); 00343 msg_ps->vb_ptr->ident = vb->ident; 00344 msg_ps->vb_ptr->ident_len = vb->ident_len; 00345 vb->ident = NULL; 00346 vb->ident_len = 0; 00347 memp_free(MEMP_SNMP_VARBIND, vb); 00348 snmp_error_response(msg_ps,SNMP_ES_TOOBIG); 00349 } 00350 } 00351 else 00352 { 00353 /* vb->value_len == 0, empty value (e.g. empty string) */ 00354 vb->value = NULL; 00355 snmp_varbind_tail_add(&msg_ps->outvb, vb); 00356 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00357 msg_ps->vb_idx += 1; 00358 } 00359 } 00360 else 00361 { 00362 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n")); 00363 snmp_error_response(msg_ps,SNMP_ES_TOOBIG); 00364 } 00365 } 00366 } 00367 } 00368 } 00369 else 00370 { 00371 mn = NULL; 00372 } 00373 if (mn == NULL) 00374 { 00375 /* mn == NULL, noSuchName */ 00376 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00377 } 00378 } 00379 if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00380 (msg_ps->vb_idx == msg_ps->invb.count)) 00381 { 00382 snmp_ok_response(msg_ps); 00383 } 00384 } 00385 00386 /** 00387 * Service an internal or external event for SNMP GETNEXT. 00388 * 00389 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) 00390 * @param msg_ps points to the assosicated message process state 00391 */ 00392 static void 00393 snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) 00394 { 00395 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); 00396 00397 if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) 00398 { 00399 struct mib_external_node *en; 00400 00401 /* get_object_def() answer*/ 00402 en = msg_ps->ext_mib_node; 00403 00404 /* translate answer into a known lifeform */ 00405 en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def); 00406 if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) 00407 { 00408 msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; 00409 en->get_value_q(request_id, &msg_ps->ext_object_def); 00410 } 00411 else 00412 { 00413 en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]); 00414 /* search failed, object id points to unknown object (nosuchname) */ 00415 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00416 } 00417 } 00418 else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) 00419 { 00420 struct mib_external_node *en; 00421 struct snmp_varbind *vb; 00422 00423 /* get_value() answer */ 00424 en = msg_ps->ext_mib_node; 00425 00426 LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); 00427 vb = snmp_varbind_alloc(&msg_ps->ext_oid, 00428 msg_ps->ext_object_def.asn_type, 00429 (u8_t)msg_ps->ext_object_def.v_len); 00430 if (vb != NULL) 00431 { 00432 en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); 00433 snmp_varbind_tail_add(&msg_ps->outvb, vb); 00434 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00435 msg_ps->vb_idx += 1; 00436 } 00437 else 00438 { 00439 en->get_value_pc(request_id, &msg_ps->ext_object_def); 00440 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n")); 00441 snmp_error_response(msg_ps,SNMP_ES_TOOBIG); 00442 } 00443 } 00444 00445 while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00446 (msg_ps->vb_idx < msg_ps->invb.count)) 00447 { 00448 struct mib_node *mn; 00449 struct snmp_obj_id oid; 00450 00451 if (msg_ps->vb_idx == 0) 00452 { 00453 msg_ps->vb_ptr = msg_ps->invb.head; 00454 } 00455 else 00456 { 00457 msg_ps->vb_ptr = msg_ps->vb_ptr->next; 00458 } 00459 if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid)) 00460 { 00461 if (msg_ps->vb_ptr->ident_len > 3) 00462 { 00463 /* can offset ident_len and ident */ 00464 mn = snmp_expand_tree((struct mib_node*)&internet, 00465 msg_ps->vb_ptr->ident_len - 4, 00466 msg_ps->vb_ptr->ident + 4, &oid); 00467 } 00468 else 00469 { 00470 /* can't offset ident_len -4, ident + 4 */ 00471 mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid); 00472 } 00473 } 00474 else 00475 { 00476 mn = NULL; 00477 } 00478 if (mn != NULL) 00479 { 00480 if (mn->node_type == MIB_NODE_EX) 00481 { 00482 /* external object */ 00483 struct mib_external_node *en = (struct mib_external_node*)mn; 00484 00485 msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; 00486 /* save en && args in msg_ps!! */ 00487 msg_ps->ext_mib_node = en; 00488 msg_ps->ext_oid = oid; 00489 00490 en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]); 00491 } 00492 else 00493 { 00494 /* internal object */ 00495 struct obj_def object_def; 00496 struct snmp_varbind *vb; 00497 00498 msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; 00499 mn->get_object_def(1, &oid.id[oid.len - 1], &object_def); 00500 00501 LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); 00502 vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len); 00503 if (vb != NULL) 00504 { 00505 msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; 00506 mn->get_value(&object_def, object_def.v_len, vb->value); 00507 snmp_varbind_tail_add(&msg_ps->outvb, vb); 00508 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00509 msg_ps->vb_idx += 1; 00510 } 00511 else 00512 { 00513 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n")); 00514 snmp_error_response(msg_ps,SNMP_ES_TOOBIG); 00515 } 00516 } 00517 } 00518 if (mn == NULL) 00519 { 00520 /* mn == NULL, noSuchName */ 00521 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00522 } 00523 } 00524 if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00525 (msg_ps->vb_idx == msg_ps->invb.count)) 00526 { 00527 snmp_ok_response(msg_ps); 00528 } 00529 } 00530 00531 /** 00532 * Service an internal or external event for SNMP SET. 00533 * 00534 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) 00535 * @param msg_ps points to the assosicated message process state 00536 */ 00537 static void 00538 snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) 00539 { 00540 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); 00541 00542 if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) 00543 { 00544 struct mib_external_node *en; 00545 struct snmp_name_ptr np; 00546 00547 /* get_object_def() answer*/ 00548 en = msg_ps->ext_mib_node; 00549 np = msg_ps->ext_name_ptr; 00550 00551 /* translate answer into a known lifeform */ 00552 en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); 00553 if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) 00554 { 00555 msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST; 00556 en->set_test_q(request_id, &msg_ps->ext_object_def); 00557 } 00558 else 00559 { 00560 en->get_object_def_pc(request_id, np.ident_len, np.ident); 00561 /* search failed, object id points to unknown object (nosuchname) */ 00562 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00563 } 00564 } 00565 else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST) 00566 { 00567 struct mib_external_node *en; 00568 00569 /* set_test() answer*/ 00570 en = msg_ps->ext_mib_node; 00571 00572 if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE) 00573 { 00574 if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) && 00575 (en->set_test_a(request_id,&msg_ps->ext_object_def, 00576 msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) 00577 { 00578 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00579 msg_ps->vb_idx += 1; 00580 } 00581 else 00582 { 00583 en->set_test_pc(request_id,&msg_ps->ext_object_def); 00584 /* bad value */ 00585 snmp_error_response(msg_ps,SNMP_ES_BADVALUE); 00586 } 00587 } 00588 else 00589 { 00590 en->set_test_pc(request_id,&msg_ps->ext_object_def); 00591 /* object not available for set */ 00592 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00593 } 00594 } 00595 else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S) 00596 { 00597 struct mib_external_node *en; 00598 struct snmp_name_ptr np; 00599 00600 /* get_object_def() answer*/ 00601 en = msg_ps->ext_mib_node; 00602 np = msg_ps->ext_name_ptr; 00603 00604 /* translate answer into a known lifeform */ 00605 en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); 00606 if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) 00607 { 00608 msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE; 00609 en->set_value_q(request_id, &msg_ps->ext_object_def, 00610 msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); 00611 } 00612 else 00613 { 00614 en->get_object_def_pc(request_id, np.ident_len, np.ident); 00615 /* set_value failed, object has disappeared for some odd reason?? */ 00616 snmp_error_response(msg_ps,SNMP_ES_GENERROR); 00617 } 00618 } 00619 else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE) 00620 { 00621 struct mib_external_node *en; 00622 00623 /** set_value_a() */ 00624 en = msg_ps->ext_mib_node; 00625 en->set_value_a(request_id, &msg_ps->ext_object_def, 00626 msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value); 00627 00628 /** @todo use set_value_pc() if toobig */ 00629 msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; 00630 msg_ps->vb_idx += 1; 00631 } 00632 00633 /* test all values before setting */ 00634 while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00635 (msg_ps->vb_idx < msg_ps->invb.count)) 00636 { 00637 struct mib_node *mn; 00638 struct snmp_name_ptr np; 00639 00640 if (msg_ps->vb_idx == 0) 00641 { 00642 msg_ps->vb_ptr = msg_ps->invb.head; 00643 } 00644 else 00645 { 00646 msg_ps->vb_ptr = msg_ps->vb_ptr->next; 00647 } 00648 /** test object identifier for .iso.org.dod.internet prefix */ 00649 if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) 00650 { 00651 mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, 00652 msg_ps->vb_ptr->ident + 4, &np); 00653 if (mn != NULL) 00654 { 00655 if (mn->node_type == MIB_NODE_EX) 00656 { 00657 /* external object */ 00658 struct mib_external_node *en = (struct mib_external_node*)mn; 00659 00660 msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; 00661 /* save en && args in msg_ps!! */ 00662 msg_ps->ext_mib_node = en; 00663 msg_ps->ext_name_ptr = np; 00664 00665 en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); 00666 } 00667 else 00668 { 00669 /* internal object */ 00670 struct obj_def object_def; 00671 00672 msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; 00673 mn->get_object_def(np.ident_len, np.ident, &object_def); 00674 if (object_def.instance != MIB_OBJECT_NONE) 00675 { 00676 mn = mn; 00677 } 00678 else 00679 { 00680 /* search failed, object id points to unknown object (nosuchname) */ 00681 mn = NULL; 00682 } 00683 if (mn != NULL) 00684 { 00685 msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST; 00686 00687 if (object_def.access & MIB_ACCESS_WRITE) 00688 { 00689 if ((object_def.asn_type == msg_ps->vb_ptr->value_type) && 00690 (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) 00691 { 00692 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00693 msg_ps->vb_idx += 1; 00694 } 00695 else 00696 { 00697 /* bad value */ 00698 snmp_error_response(msg_ps,SNMP_ES_BADVALUE); 00699 } 00700 } 00701 else 00702 { 00703 /* object not available for set */ 00704 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00705 } 00706 } 00707 } 00708 } 00709 } 00710 else 00711 { 00712 mn = NULL; 00713 } 00714 if (mn == NULL) 00715 { 00716 /* mn == NULL, noSuchName */ 00717 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00718 } 00719 } 00720 00721 if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00722 (msg_ps->vb_idx == msg_ps->invb.count)) 00723 { 00724 msg_ps->vb_idx = 0; 00725 msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; 00726 } 00727 00728 /* set all values "atomically" (be as "atomic" as possible) */ 00729 while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && 00730 (msg_ps->vb_idx < msg_ps->invb.count)) 00731 { 00732 struct mib_node *mn; 00733 struct snmp_name_ptr np; 00734 00735 if (msg_ps->vb_idx == 0) 00736 { 00737 msg_ps->vb_ptr = msg_ps->invb.head; 00738 } 00739 else 00740 { 00741 msg_ps->vb_ptr = msg_ps->vb_ptr->next; 00742 } 00743 /* skip iso prefix test, was done previously while settesting() */ 00744 mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, 00745 msg_ps->vb_ptr->ident + 4, &np); 00746 /* check if object is still available 00747 (e.g. external hot-plug thingy present?) */ 00748 if (mn != NULL) 00749 { 00750 if (mn->node_type == MIB_NODE_EX) 00751 { 00752 /* external object */ 00753 struct mib_external_node *en = (struct mib_external_node*)mn; 00754 00755 msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S; 00756 /* save en && args in msg_ps!! */ 00757 msg_ps->ext_mib_node = en; 00758 msg_ps->ext_name_ptr = np; 00759 00760 en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); 00761 } 00762 else 00763 { 00764 /* internal object */ 00765 struct obj_def object_def; 00766 00767 msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S; 00768 mn->get_object_def(np.ident_len, np.ident, &object_def); 00769 msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; 00770 mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); 00771 msg_ps->vb_idx += 1; 00772 } 00773 } 00774 } 00775 if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && 00776 (msg_ps->vb_idx == msg_ps->invb.count)) 00777 { 00778 /* simply echo the input if we can set it 00779 @todo do we need to return the actual value? 00780 e.g. if value is silently modified or behaves sticky? */ 00781 msg_ps->outvb = msg_ps->invb; 00782 msg_ps->invb.head = NULL; 00783 msg_ps->invb.tail = NULL; 00784 msg_ps->invb.count = 0; 00785 snmp_ok_response(msg_ps); 00786 } 00787 } 00788 00789 00790 /** 00791 * Handle one internal or external event. 00792 * Called for one async event. (recv external/private answer) 00793 * 00794 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) 00795 */ 00796 void 00797 snmp_msg_event(u8_t request_id) 00798 { 00799 struct snmp_msg_pstat *msg_ps; 00800 00801 if (request_id < SNMP_CONCURRENT_REQUESTS) 00802 { 00803 msg_ps = &msg_input_list[request_id]; 00804 if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) 00805 { 00806 snmp_msg_getnext_event(request_id, msg_ps); 00807 } 00808 else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) 00809 { 00810 snmp_msg_get_event(request_id, msg_ps); 00811 } 00812 else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ) 00813 { 00814 snmp_msg_set_event(request_id, msg_ps); 00815 } 00816 } 00817 } 00818 00819 00820 /* lwIP UDP receive callback function */ 00821 static void 00822 snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) 00823 { 00824 struct snmp_msg_pstat *msg_ps; 00825 u8_t req_idx; 00826 err_t err_ret; 00827 u16_t payload_len = p->tot_len; 00828 u16_t payload_ofs = 0; 00829 u16_t varbind_ofs = 0; 00830 00831 /* suppress unused argument warning */ 00832 LWIP_UNUSED_ARG(arg); 00833 00834 /* traverse input message process list, look for SNMP_MSG_EMPTY */ 00835 msg_ps = &msg_input_list[0]; 00836 req_idx = 0; 00837 while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) 00838 { 00839 req_idx++; 00840 msg_ps++; 00841 } 00842 if (req_idx == SNMP_CONCURRENT_REQUESTS) 00843 { 00844 /* exceeding number of concurrent requests */ 00845 pbuf_free(p); 00846 return; 00847 } 00848 00849 /* accepting request */ 00850 snmp_inc_snmpinpkts(); 00851 /* record used 'protocol control block' */ 00852 msg_ps->pcb = pcb; 00853 /* source address (network order) */ 00854 msg_ps->sip = *addr; 00855 /* source port (host order (lwIP oddity)) */ 00856 msg_ps->sp = port; 00857 00858 /* check total length, version, community, pdu type */ 00859 err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); 00860 /* Only accept requests and requests without error (be robust) */ 00861 /* Reject response and trap headers or error requests as input! */ 00862 if ((err_ret != ERR_OK) || 00863 ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) && 00864 (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) && 00865 (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) || 00866 ((msg_ps->error_status != SNMP_ES_NOERROR) || 00867 (msg_ps->error_index != 0)) ) 00868 { 00869 /* header check failed drop request silently, do not return error! */ 00870 pbuf_free(p); 00871 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); 00872 return; 00873 } 00874 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); 00875 00876 /* Builds a list of variable bindings. Copy the varbinds from the pbuf 00877 chain to glue them when these are divided over two or more pbuf's. */ 00878 err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); 00879 /* we've decoded the incoming message, release input msg now */ 00880 pbuf_free(p); 00881 if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0)) 00882 { 00883 /* varbind-list decode failed, or varbind list empty. 00884 drop request silently, do not return error! 00885 (errors are only returned for a specific varbind failure) */ 00886 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); 00887 return; 00888 } 00889 00890 msg_ps->error_status = SNMP_ES_NOERROR; 00891 msg_ps->error_index = 0; 00892 /* find object for each variable binding */ 00893 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00894 /* first variable binding from list to inspect */ 00895 msg_ps->vb_idx = 0; 00896 00897 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); 00898 00899 /* handle input event and as much objects as possible in one go */ 00900 snmp_msg_event(req_idx); 00901 } 00902 00903 /** 00904 * Checks and decodes incoming SNMP message header, logs header errors. 00905 * 00906 * @param p points to pbuf chain of SNMP message (UDP payload) 00907 * @param ofs points to first octet of SNMP message 00908 * @param pdu_len the length of the UDP payload 00909 * @param ofs_ret returns the ofset of the variable bindings 00910 * @param m_stat points to the current message request state return 00911 * @return 00912 * - ERR_OK SNMP header is sane and accepted 00913 * - ERR_ARG SNMP header is either malformed or rejected 00914 */ 00915 static err_t 00916 snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) 00917 { 00918 err_t derr; 00919 u16_t len, ofs_base; 00920 u8_t len_octets; 00921 u8_t type; 00922 s32_t version; 00923 00924 ofs_base = ofs; 00925 snmp_asn1_dec_type(p, ofs, &type); 00926 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00927 if ((derr != ERR_OK) || 00928 (pdu_len != (1 + len_octets + len)) || 00929 (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) 00930 { 00931 snmp_inc_snmpinasnparseerrs(); 00932 return ERR_ARG; 00933 } 00934 ofs += (1 + len_octets); 00935 snmp_asn1_dec_type(p, ofs, &type); 00936 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00937 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 00938 { 00939 /* can't decode or no integer (version) */ 00940 snmp_inc_snmpinasnparseerrs(); 00941 return ERR_ARG; 00942 } 00943 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version); 00944 if (derr != ERR_OK) 00945 { 00946 /* can't decode */ 00947 snmp_inc_snmpinasnparseerrs(); 00948 return ERR_ARG; 00949 } 00950 if (version != 0) 00951 { 00952 /* not version 1 */ 00953 snmp_inc_snmpinbadversions(); 00954 return ERR_ARG; 00955 } 00956 ofs += (1 + len_octets + len); 00957 snmp_asn1_dec_type(p, ofs, &type); 00958 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00959 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR))) 00960 { 00961 /* can't decode or no octet string (community) */ 00962 snmp_inc_snmpinasnparseerrs(); 00963 return ERR_ARG; 00964 } 00965 derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community); 00966 if (derr != ERR_OK) 00967 { 00968 snmp_inc_snmpinasnparseerrs(); 00969 return ERR_ARG; 00970 } 00971 /* add zero terminator */ 00972 len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN)); 00973 m_stat->community[len] = 0; 00974 m_stat->com_strlen = (u8_t)len; 00975 if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0) 00976 { 00977 /** @todo: move this if we need to check more names */ 00978 snmp_inc_snmpinbadcommunitynames(); 00979 snmp_authfail_trap(); 00980 return ERR_ARG; 00981 } 00982 ofs += (1 + len_octets + len); 00983 snmp_asn1_dec_type(p, ofs, &type); 00984 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00985 if (derr != ERR_OK) 00986 { 00987 snmp_inc_snmpinasnparseerrs(); 00988 return ERR_ARG; 00989 } 00990 switch(type) 00991 { 00992 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ): 00993 /* GetRequest PDU */ 00994 snmp_inc_snmpingetrequests(); 00995 derr = ERR_OK; 00996 break; 00997 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ): 00998 /* GetNextRequest PDU */ 00999 snmp_inc_snmpingetnexts(); 01000 derr = ERR_OK; 01001 break; 01002 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP): 01003 /* GetResponse PDU */ 01004 snmp_inc_snmpingetresponses(); 01005 derr = ERR_ARG; 01006 break; 01007 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ): 01008 /* SetRequest PDU */ 01009 snmp_inc_snmpinsetrequests(); 01010 derr = ERR_OK; 01011 break; 01012 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP): 01013 /* Trap PDU */ 01014 snmp_inc_snmpintraps(); 01015 derr = ERR_ARG; 01016 break; 01017 default: 01018 snmp_inc_snmpinasnparseerrs(); 01019 derr = ERR_ARG; 01020 break; 01021 } 01022 if (derr != ERR_OK) 01023 { 01024 /* unsupported input PDU for this agent (no parse error) */ 01025 return ERR_ARG; 01026 } 01027 m_stat->rt = type & 0x1F; 01028 ofs += (1 + len_octets); 01029 if (len != (pdu_len - (ofs - ofs_base))) 01030 { 01031 /* decoded PDU length does not equal actual payload length */ 01032 snmp_inc_snmpinasnparseerrs(); 01033 return ERR_ARG; 01034 } 01035 snmp_asn1_dec_type(p, ofs, &type); 01036 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01037 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 01038 { 01039 /* can't decode or no integer (request ID) */ 01040 snmp_inc_snmpinasnparseerrs(); 01041 return ERR_ARG; 01042 } 01043 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid); 01044 if (derr != ERR_OK) 01045 { 01046 /* can't decode */ 01047 snmp_inc_snmpinasnparseerrs(); 01048 return ERR_ARG; 01049 } 01050 ofs += (1 + len_octets + len); 01051 snmp_asn1_dec_type(p, ofs, &type); 01052 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01053 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 01054 { 01055 /* can't decode or no integer (error-status) */ 01056 snmp_inc_snmpinasnparseerrs(); 01057 return ERR_ARG; 01058 } 01059 /* must be noError (0) for incoming requests. 01060 log errors for mib-2 completeness and for debug purposes */ 01061 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status); 01062 if (derr != ERR_OK) 01063 { 01064 /* can't decode */ 01065 snmp_inc_snmpinasnparseerrs(); 01066 return ERR_ARG; 01067 } 01068 switch (m_stat->error_status) 01069 { 01070 case SNMP_ES_TOOBIG: 01071 snmp_inc_snmpintoobigs(); 01072 break; 01073 case SNMP_ES_NOSUCHNAME: 01074 snmp_inc_snmpinnosuchnames(); 01075 break; 01076 case SNMP_ES_BADVALUE: 01077 snmp_inc_snmpinbadvalues(); 01078 break; 01079 case SNMP_ES_READONLY: 01080 snmp_inc_snmpinreadonlys(); 01081 break; 01082 case SNMP_ES_GENERROR: 01083 snmp_inc_snmpingenerrs(); 01084 break; 01085 } 01086 ofs += (1 + len_octets + len); 01087 snmp_asn1_dec_type(p, ofs, &type); 01088 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01089 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 01090 { 01091 /* can't decode or no integer (error-index) */ 01092 snmp_inc_snmpinasnparseerrs(); 01093 return ERR_ARG; 01094 } 01095 /* must be 0 for incoming requests. 01096 decode anyway to catch bad integers (and dirty tricks) */ 01097 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index); 01098 if (derr != ERR_OK) 01099 { 01100 /* can't decode */ 01101 snmp_inc_snmpinasnparseerrs(); 01102 return ERR_ARG; 01103 } 01104 ofs += (1 + len_octets + len); 01105 *ofs_ret = ofs; 01106 return ERR_OK; 01107 } 01108 01109 static err_t 01110 snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) 01111 { 01112 err_t derr; 01113 u16_t len, vb_len; 01114 u8_t len_octets; 01115 u8_t type; 01116 01117 /* variable binding list */ 01118 snmp_asn1_dec_type(p, ofs, &type); 01119 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len); 01120 if ((derr != ERR_OK) || 01121 (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) 01122 { 01123 snmp_inc_snmpinasnparseerrs(); 01124 return ERR_ARG; 01125 } 01126 ofs += (1 + len_octets); 01127 01128 /* start with empty list */ 01129 m_stat->invb.count = 0; 01130 m_stat->invb.head = NULL; 01131 m_stat->invb.tail = NULL; 01132 01133 while (vb_len > 0) 01134 { 01135 struct snmp_obj_id oid, oid_value; 01136 struct snmp_varbind *vb; 01137 01138 snmp_asn1_dec_type(p, ofs, &type); 01139 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01140 if ((derr != ERR_OK) || 01141 (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) || 01142 (len == 0) || (len > vb_len)) 01143 { 01144 snmp_inc_snmpinasnparseerrs(); 01145 /* free varbinds (if available) */ 01146 snmp_varbind_list_free(&m_stat->invb); 01147 return ERR_ARG; 01148 } 01149 ofs += (1 + len_octets); 01150 vb_len -= (1 + len_octets); 01151 01152 snmp_asn1_dec_type(p, ofs, &type); 01153 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01154 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID))) 01155 { 01156 /* can't decode object name length */ 01157 snmp_inc_snmpinasnparseerrs(); 01158 /* free varbinds (if available) */ 01159 snmp_varbind_list_free(&m_stat->invb); 01160 return ERR_ARG; 01161 } 01162 derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid); 01163 if (derr != ERR_OK) 01164 { 01165 /* can't decode object name */ 01166 snmp_inc_snmpinasnparseerrs(); 01167 /* free varbinds (if available) */ 01168 snmp_varbind_list_free(&m_stat->invb); 01169 return ERR_ARG; 01170 } 01171 ofs += (1 + len_octets + len); 01172 vb_len -= (1 + len_octets + len); 01173 01174 snmp_asn1_dec_type(p, ofs, &type); 01175 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01176 if (derr != ERR_OK) 01177 { 01178 /* can't decode object value length */ 01179 snmp_inc_snmpinasnparseerrs(); 01180 /* free varbinds (if available) */ 01181 snmp_varbind_list_free(&m_stat->invb); 01182 return ERR_ARG; 01183 } 01184 01185 switch (type) 01186 { 01187 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): 01188 vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t)); 01189 if (vb != NULL) 01190 { 01191 s32_t *vptr = (s32_t*)vb->value; 01192 01193 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr); 01194 snmp_varbind_tail_add(&m_stat->invb, vb); 01195 } 01196 else 01197 { 01198 derr = ERR_ARG; 01199 } 01200 break; 01201 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): 01202 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): 01203 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): 01204 vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t)); 01205 if (vb != NULL) 01206 { 01207 u32_t *vptr = (u32_t*)vb->value; 01208 01209 derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr); 01210 snmp_varbind_tail_add(&m_stat->invb, vb); 01211 } 01212 else 01213 { 01214 derr = ERR_ARG; 01215 } 01216 break; 01217 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): 01218 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): 01219 LWIP_ASSERT("invalid length", len <= 0xff); 01220 vb = snmp_varbind_alloc(&oid, type, (u8_t)len); 01221 if (vb != NULL) 01222 { 01223 derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); 01224 snmp_varbind_tail_add(&m_stat->invb, vb); 01225 } 01226 else 01227 { 01228 derr = ERR_ARG; 01229 } 01230 break; 01231 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): 01232 vb = snmp_varbind_alloc(&oid, type, 0); 01233 if (vb != NULL) 01234 { 01235 snmp_varbind_tail_add(&m_stat->invb, vb); 01236 derr = ERR_OK; 01237 } 01238 else 01239 { 01240 derr = ERR_ARG; 01241 } 01242 break; 01243 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): 01244 derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value); 01245 if (derr == ERR_OK) 01246 { 01247 vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t)); 01248 if (vb != NULL) 01249 { 01250 u8_t i = oid_value.len; 01251 s32_t *vptr = (s32_t*)vb->value; 01252 01253 while(i > 0) 01254 { 01255 i--; 01256 vptr[i] = oid_value.id[i]; 01257 } 01258 snmp_varbind_tail_add(&m_stat->invb, vb); 01259 derr = ERR_OK; 01260 } 01261 else 01262 { 01263 derr = ERR_ARG; 01264 } 01265 } 01266 break; 01267 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): 01268 if (len == 4) 01269 { 01270 /* must be exactly 4 octets! */ 01271 vb = snmp_varbind_alloc(&oid, type, 4); 01272 if (vb != NULL) 01273 { 01274 derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); 01275 snmp_varbind_tail_add(&m_stat->invb, vb); 01276 } 01277 else 01278 { 01279 derr = ERR_ARG; 01280 } 01281 } 01282 else 01283 { 01284 derr = ERR_ARG; 01285 } 01286 break; 01287 default: 01288 derr = ERR_ARG; 01289 break; 01290 } 01291 if (derr != ERR_OK) 01292 { 01293 snmp_inc_snmpinasnparseerrs(); 01294 /* free varbinds (if available) */ 01295 snmp_varbind_list_free(&m_stat->invb); 01296 return ERR_ARG; 01297 } 01298 ofs += (1 + len_octets + len); 01299 vb_len -= (1 + len_octets + len); 01300 } 01301 01302 if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ) 01303 { 01304 snmp_add_snmpintotalsetvars(m_stat->invb.count); 01305 } 01306 else 01307 { 01308 snmp_add_snmpintotalreqvars(m_stat->invb.count); 01309 } 01310 01311 *ofs_ret = ofs; 01312 return ERR_OK; 01313 } 01314 01315 struct snmp_varbind* 01316 snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) 01317 { 01318 struct snmp_varbind *vb; 01319 01320 vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); 01321 if (vb != NULL) 01322 { 01323 u8_t i; 01324 01325 vb->next = NULL; 01326 vb->prev = NULL; 01327 i = oid->len; 01328 vb->ident_len = i; 01329 if (i > 0) 01330 { 01331 LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH); 01332 /* allocate array of s32_t for our object identifier */ 01333 vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE); 01334 if (vb->ident == NULL) 01335 { 01336 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate ident value space\n")); 01337 memp_free(MEMP_SNMP_VARBIND, vb); 01338 return NULL; 01339 } 01340 while(i > 0) 01341 { 01342 i--; 01343 vb->ident[i] = oid->id[i]; 01344 } 01345 } 01346 else 01347 { 01348 /* i == 0, pass zero length object identifier */ 01349 vb->ident = NULL; 01350 } 01351 vb->value_type = type; 01352 vb->value_len = len; 01353 if (len > 0) 01354 { 01355 LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); 01356 /* allocate raw bytes for our object value */ 01357 vb->value = memp_malloc(MEMP_SNMP_VALUE); 01358 if (vb->value == NULL) 01359 { 01360 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate value space\n")); 01361 if (vb->ident != NULL) 01362 { 01363 memp_free(MEMP_SNMP_VALUE, vb->ident); 01364 } 01365 memp_free(MEMP_SNMP_VARBIND, vb); 01366 return NULL; 01367 } 01368 } 01369 else 01370 { 01371 /* ASN1_NUL type, or zero length ASN1_OC_STR */ 01372 vb->value = NULL; 01373 } 01374 } 01375 else 01376 { 01377 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate varbind space\n")); 01378 } 01379 return vb; 01380 } 01381 01382 void 01383 snmp_varbind_free(struct snmp_varbind *vb) 01384 { 01385 if (vb->value != NULL ) 01386 { 01387 memp_free(MEMP_SNMP_VALUE, vb->value); 01388 } 01389 if (vb->ident != NULL ) 01390 { 01391 memp_free(MEMP_SNMP_VALUE, vb->ident); 01392 } 01393 memp_free(MEMP_SNMP_VARBIND, vb); 01394 } 01395 01396 void 01397 snmp_varbind_list_free(struct snmp_varbind_root *root) 01398 { 01399 struct snmp_varbind *vb, *prev; 01400 01401 vb = root->tail; 01402 while ( vb != NULL ) 01403 { 01404 prev = vb->prev; 01405 snmp_varbind_free(vb); 01406 vb = prev; 01407 } 01408 root->count = 0; 01409 root->head = NULL; 01410 root->tail = NULL; 01411 } 01412 01413 void 01414 snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb) 01415 { 01416 if (root->count == 0) 01417 { 01418 /* add first varbind to list */ 01419 root->head = vb; 01420 root->tail = vb; 01421 } 01422 else 01423 { 01424 /* add nth varbind to list tail */ 01425 root->tail->next = vb; 01426 vb->prev = root->tail; 01427 root->tail = vb; 01428 } 01429 root->count += 1; 01430 } 01431 01432 struct snmp_varbind* 01433 snmp_varbind_tail_remove(struct snmp_varbind_root *root) 01434 { 01435 struct snmp_varbind* vb; 01436 01437 if (root->count > 0) 01438 { 01439 /* remove tail varbind */ 01440 vb = root->tail; 01441 root->tail = vb->prev; 01442 vb->prev->next = NULL; 01443 root->count -= 1; 01444 } 01445 else 01446 { 01447 /* nothing to remove */ 01448 vb = NULL; 01449 } 01450 return vb; 01451 } 01452 01453 #endif /* LWIP_SNMP */
Generated on Wed Jul 13 2022 02:45:41 by
1.7.2
