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