NetServices Stack source
Dependents: HelloWorld ServoInterfaceBoardExample1 4180_Lab4
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:52:57 by 1.7.2