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