Some quick code to use UDP-only (no TCP) with mBed. Echos received packets and sends packets when a button is pressed
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/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() */ 00593 en = msg_ps->ext_mib_node; 00594 en->set_value_a(request_id, &msg_ps->ext_object_def, 00595 msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value); 00596 00597 /** @todo use set_value_pc() if toobig */ 00598 msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; 00599 msg_ps->vb_idx += 1; 00600 } 00601 00602 /* test all values before setting */ 00603 while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00604 (msg_ps->vb_idx < msg_ps->invb.count)) 00605 { 00606 struct mib_node *mn; 00607 struct snmp_name_ptr np; 00608 00609 if (msg_ps->vb_idx == 0) 00610 { 00611 msg_ps->vb_ptr = msg_ps->invb.head; 00612 } 00613 else 00614 { 00615 msg_ps->vb_ptr = msg_ps->vb_ptr->next; 00616 } 00617 /** test object identifier for .iso.org.dod.internet prefix */ 00618 if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) 00619 { 00620 mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, 00621 msg_ps->vb_ptr->ident + 4, &np); 00622 if (mn != NULL) 00623 { 00624 if (mn->node_type == MIB_NODE_EX) 00625 { 00626 /* external object */ 00627 struct mib_external_node *en = (struct mib_external_node*)mn; 00628 00629 msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; 00630 /* save en && args in msg_ps!! */ 00631 msg_ps->ext_mib_node = en; 00632 msg_ps->ext_name_ptr = np; 00633 00634 en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); 00635 } 00636 else 00637 { 00638 /* internal object */ 00639 struct obj_def object_def; 00640 00641 msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; 00642 mn->get_object_def(np.ident_len, np.ident, &object_def); 00643 if (object_def.instance != MIB_OBJECT_NONE) 00644 { 00645 mn = mn; 00646 } 00647 else 00648 { 00649 /* search failed, object id points to unknown object (nosuchname) */ 00650 mn = NULL; 00651 } 00652 if (mn != NULL) 00653 { 00654 msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST; 00655 00656 if (object_def.access == MIB_OBJECT_READ_WRITE) 00657 { 00658 if ((object_def.asn_type == msg_ps->vb_ptr->value_type) && 00659 (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) 00660 { 00661 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00662 msg_ps->vb_idx += 1; 00663 } 00664 else 00665 { 00666 /* bad value */ 00667 snmp_error_response(msg_ps,SNMP_ES_BADVALUE); 00668 } 00669 } 00670 else 00671 { 00672 /* object not available for set */ 00673 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00674 } 00675 } 00676 } 00677 } 00678 } 00679 else 00680 { 00681 mn = NULL; 00682 } 00683 if (mn == NULL) 00684 { 00685 /* mn == NULL, noSuchName */ 00686 snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); 00687 } 00688 } 00689 00690 if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && 00691 (msg_ps->vb_idx == msg_ps->invb.count)) 00692 { 00693 msg_ps->vb_idx = 0; 00694 msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; 00695 } 00696 00697 /* set all values "atomically" (be as "atomic" as possible) */ 00698 while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && 00699 (msg_ps->vb_idx < msg_ps->invb.count)) 00700 { 00701 struct mib_node *mn; 00702 struct snmp_name_ptr np; 00703 00704 if (msg_ps->vb_idx == 0) 00705 { 00706 msg_ps->vb_ptr = msg_ps->invb.head; 00707 } 00708 else 00709 { 00710 msg_ps->vb_ptr = msg_ps->vb_ptr->next; 00711 } 00712 /* skip iso prefix test, was done previously while settesting() */ 00713 mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, 00714 msg_ps->vb_ptr->ident + 4, &np); 00715 /* check if object is still available 00716 (e.g. external hot-plug thingy present?) */ 00717 if (mn != NULL) 00718 { 00719 if (mn->node_type == MIB_NODE_EX) 00720 { 00721 /* external object */ 00722 struct mib_external_node *en = (struct mib_external_node*)mn; 00723 00724 msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S; 00725 /* save en && args in msg_ps!! */ 00726 msg_ps->ext_mib_node = en; 00727 msg_ps->ext_name_ptr = np; 00728 00729 en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); 00730 } 00731 else 00732 { 00733 /* internal object */ 00734 struct obj_def object_def; 00735 00736 msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S; 00737 mn->get_object_def(np.ident_len, np.ident, &object_def); 00738 msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; 00739 mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); 00740 msg_ps->vb_idx += 1; 00741 } 00742 } 00743 } 00744 if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && 00745 (msg_ps->vb_idx == msg_ps->invb.count)) 00746 { 00747 /* simply echo the input if we can set it 00748 @todo do we need to return the actual value? 00749 e.g. if value is silently modified or behaves sticky? */ 00750 msg_ps->outvb = msg_ps->invb; 00751 msg_ps->invb.head = NULL; 00752 msg_ps->invb.tail = NULL; 00753 msg_ps->invb.count = 0; 00754 snmp_ok_response(msg_ps); 00755 } 00756 } 00757 00758 00759 /** 00760 * Handle one internal or external event. 00761 * Called for one async event. (recv external/private answer) 00762 * 00763 * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) 00764 */ 00765 void 00766 snmp_msg_event(u8_t request_id) 00767 { 00768 struct snmp_msg_pstat *msg_ps; 00769 00770 if (request_id < SNMP_CONCURRENT_REQUESTS) 00771 { 00772 msg_ps = &msg_input_list[request_id]; 00773 if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) 00774 { 00775 snmp_msg_getnext_event(request_id, msg_ps); 00776 } 00777 else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) 00778 { 00779 snmp_msg_get_event(request_id, msg_ps); 00780 } 00781 else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ) 00782 { 00783 snmp_msg_set_event(request_id, msg_ps); 00784 } 00785 } 00786 } 00787 00788 00789 /* lwIP UDP receive callback function */ 00790 static void 00791 snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) 00792 { 00793 struct udp_hdr *udphdr; 00794 00795 /* suppress unused argument warning */ 00796 LWIP_UNUSED_ARG(arg); 00797 /* peek in the UDP header (goto IP payload) */ 00798 if(pbuf_header(p, UDP_HLEN)){ 00799 LWIP_ASSERT("Can't move to UDP header", 0); 00800 pbuf_free(p); 00801 return; 00802 } 00803 udphdr = p->payload; 00804 00805 /* check if datagram is really directed at us (including broadcast requests) */ 00806 if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT)) 00807 { 00808 struct snmp_msg_pstat *msg_ps; 00809 u8_t req_idx; 00810 00811 /* traverse input message process list, look for SNMP_MSG_EMPTY */ 00812 msg_ps = &msg_input_list[0]; 00813 req_idx = 0; 00814 while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) 00815 { 00816 req_idx++; 00817 msg_ps++; 00818 } 00819 if (req_idx != SNMP_CONCURRENT_REQUESTS) 00820 { 00821 err_t err_ret; 00822 u16_t payload_len; 00823 u16_t payload_ofs; 00824 u16_t varbind_ofs = 0; 00825 00826 /* accepting request */ 00827 snmp_inc_snmpinpkts(); 00828 /* record used 'protocol control block' */ 00829 msg_ps->pcb = pcb; 00830 /* source address (network order) */ 00831 msg_ps->sip = *addr; 00832 /* source port (host order (lwIP oddity)) */ 00833 msg_ps->sp = port; 00834 /* read UDP payload length from UDP header */ 00835 payload_len = ntohs(udphdr->len) - UDP_HLEN; 00836 00837 /* adjust to UDP payload */ 00838 payload_ofs = UDP_HLEN; 00839 00840 /* check total length, version, community, pdu type */ 00841 err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); 00842 if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) || 00843 (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) || 00844 (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) && 00845 ((msg_ps->error_status == SNMP_ES_NOERROR) && 00846 (msg_ps->error_index == 0)) ) 00847 { 00848 /* Only accept requests and requests without error (be robust) */ 00849 err_ret = err_ret; 00850 } 00851 else 00852 { 00853 /* Reject response and trap headers or error requests as input! */ 00854 err_ret = ERR_ARG; 00855 } 00856 if (err_ret == ERR_OK) 00857 { 00858 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); 00859 00860 /* Builds a list of variable bindings. Copy the varbinds from the pbuf 00861 chain to glue them when these are divided over two or more pbuf's. */ 00862 err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); 00863 if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0)) 00864 { 00865 /* we've decoded the incoming message, release input msg now */ 00866 pbuf_free(p); 00867 00868 msg_ps->error_status = SNMP_ES_NOERROR; 00869 msg_ps->error_index = 0; 00870 /* find object for each variable binding */ 00871 msg_ps->state = SNMP_MSG_SEARCH_OBJ; 00872 /* first variable binding from list to inspect */ 00873 msg_ps->vb_idx = 0; 00874 00875 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); 00876 00877 /* handle input event and as much objects as possible in one go */ 00878 snmp_msg_event(req_idx); 00879 } 00880 else 00881 { 00882 /* varbind-list decode failed, or varbind list empty. 00883 drop request silently, do not return error! 00884 (errors are only returned for a specific varbind failure) */ 00885 pbuf_free(p); 00886 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); 00887 } 00888 } 00889 else 00890 { 00891 /* header check failed 00892 drop request silently, do not return error! */ 00893 pbuf_free(p); 00894 LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); 00895 } 00896 } 00897 else 00898 { 00899 /* exceeding number of concurrent requests */ 00900 pbuf_free(p); 00901 } 00902 } 00903 else 00904 { 00905 /* datagram not for us */ 00906 pbuf_free(p); 00907 } 00908 } 00909 00910 /** 00911 * Checks and decodes incoming SNMP message header, logs header errors. 00912 * 00913 * @param p points to pbuf chain of SNMP message (UDP payload) 00914 * @param ofs points to first octet of SNMP message 00915 * @param pdu_len the length of the UDP payload 00916 * @param ofs_ret returns the ofset of the variable bindings 00917 * @param m_stat points to the current message request state return 00918 * @return 00919 * - ERR_OK SNMP header is sane and accepted 00920 * - ERR_ARG SNMP header is either malformed or rejected 00921 */ 00922 static err_t 00923 snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) 00924 { 00925 err_t derr; 00926 u16_t len, ofs_base; 00927 u8_t len_octets; 00928 u8_t type; 00929 s32_t version; 00930 00931 ofs_base = ofs; 00932 snmp_asn1_dec_type(p, ofs, &type); 00933 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00934 if ((derr != ERR_OK) || 00935 (pdu_len != (1 + len_octets + len)) || 00936 (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) 00937 { 00938 snmp_inc_snmpinasnparseerrs(); 00939 return ERR_ARG; 00940 } 00941 ofs += (1 + len_octets); 00942 snmp_asn1_dec_type(p, ofs, &type); 00943 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00944 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 00945 { 00946 /* can't decode or no integer (version) */ 00947 snmp_inc_snmpinasnparseerrs(); 00948 return ERR_ARG; 00949 } 00950 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version); 00951 if (derr != ERR_OK) 00952 { 00953 /* can't decode */ 00954 snmp_inc_snmpinasnparseerrs(); 00955 return ERR_ARG; 00956 } 00957 if (version != 0) 00958 { 00959 /* not version 1 */ 00960 snmp_inc_snmpinbadversions(); 00961 return ERR_ARG; 00962 } 00963 ofs += (1 + len_octets + len); 00964 snmp_asn1_dec_type(p, ofs, &type); 00965 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00966 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR))) 00967 { 00968 /* can't decode or no octet string (community) */ 00969 snmp_inc_snmpinasnparseerrs(); 00970 return ERR_ARG; 00971 } 00972 derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community); 00973 if (derr != ERR_OK) 00974 { 00975 snmp_inc_snmpinasnparseerrs(); 00976 return ERR_ARG; 00977 } 00978 /* add zero terminator */ 00979 len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN)); 00980 m_stat->community[len] = 0; 00981 m_stat->com_strlen = len; 00982 if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0) 00983 { 00984 /** @todo: move this if we need to check more names */ 00985 snmp_inc_snmpinbadcommunitynames(); 00986 snmp_authfail_trap(); 00987 return ERR_ARG; 00988 } 00989 ofs += (1 + len_octets + len); 00990 snmp_asn1_dec_type(p, ofs, &type); 00991 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 00992 if (derr != ERR_OK) 00993 { 00994 snmp_inc_snmpinasnparseerrs(); 00995 return ERR_ARG; 00996 } 00997 switch(type) 00998 { 00999 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ): 01000 /* GetRequest PDU */ 01001 snmp_inc_snmpingetrequests(); 01002 derr = ERR_OK; 01003 break; 01004 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ): 01005 /* GetNextRequest PDU */ 01006 snmp_inc_snmpingetnexts(); 01007 derr = ERR_OK; 01008 break; 01009 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP): 01010 /* GetResponse PDU */ 01011 snmp_inc_snmpingetresponses(); 01012 derr = ERR_ARG; 01013 break; 01014 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ): 01015 /* SetRequest PDU */ 01016 snmp_inc_snmpinsetrequests(); 01017 derr = ERR_OK; 01018 break; 01019 case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP): 01020 /* Trap PDU */ 01021 snmp_inc_snmpintraps(); 01022 derr = ERR_ARG; 01023 break; 01024 default: 01025 snmp_inc_snmpinasnparseerrs(); 01026 derr = ERR_ARG; 01027 break; 01028 } 01029 if (derr != ERR_OK) 01030 { 01031 /* unsupported input PDU for this agent (no parse error) */ 01032 return ERR_ARG; 01033 } 01034 m_stat->rt = type & 0x1F; 01035 ofs += (1 + len_octets); 01036 if (len != (pdu_len - (ofs - ofs_base))) 01037 { 01038 /* decoded PDU length does not equal actual payload length */ 01039 snmp_inc_snmpinasnparseerrs(); 01040 return ERR_ARG; 01041 } 01042 snmp_asn1_dec_type(p, ofs, &type); 01043 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01044 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 01045 { 01046 /* can't decode or no integer (request ID) */ 01047 snmp_inc_snmpinasnparseerrs(); 01048 return ERR_ARG; 01049 } 01050 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid); 01051 if (derr != ERR_OK) 01052 { 01053 /* can't decode */ 01054 snmp_inc_snmpinasnparseerrs(); 01055 return ERR_ARG; 01056 } 01057 ofs += (1 + len_octets + len); 01058 snmp_asn1_dec_type(p, ofs, &type); 01059 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01060 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 01061 { 01062 /* can't decode or no integer (error-status) */ 01063 snmp_inc_snmpinasnparseerrs(); 01064 return ERR_ARG; 01065 } 01066 /* must be noError (0) for incoming requests. 01067 log errors for mib-2 completeness and for debug purposes */ 01068 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status); 01069 if (derr != ERR_OK) 01070 { 01071 /* can't decode */ 01072 snmp_inc_snmpinasnparseerrs(); 01073 return ERR_ARG; 01074 } 01075 switch (m_stat->error_status) 01076 { 01077 case SNMP_ES_TOOBIG: 01078 snmp_inc_snmpintoobigs(); 01079 break; 01080 case SNMP_ES_NOSUCHNAME: 01081 snmp_inc_snmpinnosuchnames(); 01082 break; 01083 case SNMP_ES_BADVALUE: 01084 snmp_inc_snmpinbadvalues(); 01085 break; 01086 case SNMP_ES_READONLY: 01087 snmp_inc_snmpinreadonlys(); 01088 break; 01089 case SNMP_ES_GENERROR: 01090 snmp_inc_snmpingenerrs(); 01091 break; 01092 } 01093 ofs += (1 + len_octets + len); 01094 snmp_asn1_dec_type(p, ofs, &type); 01095 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01096 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) 01097 { 01098 /* can't decode or no integer (error-index) */ 01099 snmp_inc_snmpinasnparseerrs(); 01100 return ERR_ARG; 01101 } 01102 /* must be 0 for incoming requests. 01103 decode anyway to catch bad integers (and dirty tricks) */ 01104 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index); 01105 if (derr != ERR_OK) 01106 { 01107 /* can't decode */ 01108 snmp_inc_snmpinasnparseerrs(); 01109 return ERR_ARG; 01110 } 01111 ofs += (1 + len_octets + len); 01112 *ofs_ret = ofs; 01113 return ERR_OK; 01114 } 01115 01116 static err_t 01117 snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) 01118 { 01119 err_t derr; 01120 u16_t len, vb_len; 01121 u8_t len_octets; 01122 u8_t type; 01123 01124 /* variable binding list */ 01125 snmp_asn1_dec_type(p, ofs, &type); 01126 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len); 01127 if ((derr != ERR_OK) || 01128 (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) 01129 { 01130 snmp_inc_snmpinasnparseerrs(); 01131 return ERR_ARG; 01132 } 01133 ofs += (1 + len_octets); 01134 01135 /* start with empty list */ 01136 m_stat->invb.count = 0; 01137 m_stat->invb.head = NULL; 01138 m_stat->invb.tail = NULL; 01139 01140 while (vb_len > 0) 01141 { 01142 struct snmp_obj_id oid, oid_value; 01143 struct snmp_varbind *vb; 01144 01145 snmp_asn1_dec_type(p, ofs, &type); 01146 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01147 if ((derr != ERR_OK) || 01148 (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) || 01149 (len == 0) || (len > vb_len)) 01150 { 01151 snmp_inc_snmpinasnparseerrs(); 01152 /* free varbinds (if available) */ 01153 snmp_varbind_list_free(&m_stat->invb); 01154 return ERR_ARG; 01155 } 01156 ofs += (1 + len_octets); 01157 vb_len -= (1 + len_octets); 01158 01159 snmp_asn1_dec_type(p, ofs, &type); 01160 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01161 if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID))) 01162 { 01163 /* can't decode object name length */ 01164 snmp_inc_snmpinasnparseerrs(); 01165 /* free varbinds (if available) */ 01166 snmp_varbind_list_free(&m_stat->invb); 01167 return ERR_ARG; 01168 } 01169 derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid); 01170 if (derr != ERR_OK) 01171 { 01172 /* can't decode object name */ 01173 snmp_inc_snmpinasnparseerrs(); 01174 /* free varbinds (if available) */ 01175 snmp_varbind_list_free(&m_stat->invb); 01176 return ERR_ARG; 01177 } 01178 ofs += (1 + len_octets + len); 01179 vb_len -= (1 + len_octets + len); 01180 01181 snmp_asn1_dec_type(p, ofs, &type); 01182 derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); 01183 if (derr != ERR_OK) 01184 { 01185 /* can't decode object value length */ 01186 snmp_inc_snmpinasnparseerrs(); 01187 /* free varbinds (if available) */ 01188 snmp_varbind_list_free(&m_stat->invb); 01189 return ERR_ARG; 01190 } 01191 01192 switch (type) 01193 { 01194 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): 01195 vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t)); 01196 if (vb != NULL) 01197 { 01198 s32_t *vptr = vb->value; 01199 01200 derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr); 01201 snmp_varbind_tail_add(&m_stat->invb, vb); 01202 } 01203 else 01204 { 01205 derr = ERR_ARG; 01206 } 01207 break; 01208 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): 01209 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): 01210 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): 01211 vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t)); 01212 if (vb != NULL) 01213 { 01214 u32_t *vptr = vb->value; 01215 01216 derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr); 01217 snmp_varbind_tail_add(&m_stat->invb, vb); 01218 } 01219 else 01220 { 01221 derr = ERR_ARG; 01222 } 01223 break; 01224 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): 01225 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): 01226 vb = snmp_varbind_alloc(&oid, type, len); 01227 if (vb != NULL) 01228 { 01229 derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value); 01230 snmp_varbind_tail_add(&m_stat->invb, vb); 01231 } 01232 else 01233 { 01234 derr = ERR_ARG; 01235 } 01236 break; 01237 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): 01238 vb = snmp_varbind_alloc(&oid, type, 0); 01239 if (vb != NULL) 01240 { 01241 snmp_varbind_tail_add(&m_stat->invb, vb); 01242 derr = ERR_OK; 01243 } 01244 else 01245 { 01246 derr = ERR_ARG; 01247 } 01248 break; 01249 case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): 01250 derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value); 01251 if (derr == ERR_OK) 01252 { 01253 vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t)); 01254 if (vb != NULL) 01255 { 01256 u8_t i = oid_value.len; 01257 s32_t *vptr = vb->value; 01258 01259 while(i > 0) 01260 { 01261 i--; 01262 vptr[i] = oid_value.id[i]; 01263 } 01264 snmp_varbind_tail_add(&m_stat->invb, vb); 01265 derr = ERR_OK; 01266 } 01267 else 01268 { 01269 derr = ERR_ARG; 01270 } 01271 } 01272 break; 01273 case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): 01274 if (len == 4) 01275 { 01276 /* must be exactly 4 octets! */ 01277 vb = snmp_varbind_alloc(&oid, type, 4); 01278 if (vb != NULL) 01279 { 01280 derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value); 01281 snmp_varbind_tail_add(&m_stat->invb, vb); 01282 } 01283 else 01284 { 01285 derr = ERR_ARG; 01286 } 01287 } 01288 else 01289 { 01290 derr = ERR_ARG; 01291 } 01292 break; 01293 default: 01294 derr = ERR_ARG; 01295 break; 01296 } 01297 if (derr != ERR_OK) 01298 { 01299 snmp_inc_snmpinasnparseerrs(); 01300 /* free varbinds (if available) */ 01301 snmp_varbind_list_free(&m_stat->invb); 01302 return ERR_ARG; 01303 } 01304 ofs += (1 + len_octets + len); 01305 vb_len -= (1 + len_octets + len); 01306 } 01307 01308 if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ) 01309 { 01310 snmp_add_snmpintotalsetvars(m_stat->invb.count); 01311 } 01312 else 01313 { 01314 snmp_add_snmpintotalreqvars(m_stat->invb.count); 01315 } 01316 01317 *ofs_ret = ofs; 01318 return ERR_OK; 01319 } 01320 01321 struct snmp_varbind* 01322 snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) 01323 { 01324 struct snmp_varbind *vb; 01325 01326 vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); 01327 LWIP_ASSERT("vb != NULL",vb != NULL); 01328 if (vb != NULL) 01329 { 01330 u8_t i; 01331 01332 vb->next = NULL; 01333 vb->prev = NULL; 01334 i = oid->len; 01335 vb->ident_len = i; 01336 if (i > 0) 01337 { 01338 /* allocate array of s32_t for our object identifier */ 01339 vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i); 01340 LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL); 01341 if (vb->ident == NULL) 01342 { 01343 mem_free(vb); 01344 return NULL; 01345 } 01346 while(i > 0) 01347 { 01348 i--; 01349 vb->ident[i] = oid->id[i]; 01350 } 01351 } 01352 else 01353 { 01354 /* i == 0, pass zero length object identifier */ 01355 vb->ident = NULL; 01356 } 01357 vb->value_type = type; 01358 vb->value_len = len; 01359 if (len > 0) 01360 { 01361 /* allocate raw bytes for our object value */ 01362 vb->value = mem_malloc(len); 01363 LWIP_ASSERT("vb->value != NULL",vb->value != NULL); 01364 if (vb->value == NULL) 01365 { 01366 if (vb->ident != NULL) 01367 { 01368 mem_free(vb->ident); 01369 } 01370 mem_free(vb); 01371 return NULL; 01372 } 01373 } 01374 else 01375 { 01376 /* ASN1_NUL type, or zero length ASN1_OC_STR */ 01377 vb->value = NULL; 01378 } 01379 } 01380 return vb; 01381 } 01382 01383 void 01384 snmp_varbind_free(struct snmp_varbind *vb) 01385 { 01386 if (vb->value != NULL ) 01387 { 01388 mem_free(vb->value); 01389 } 01390 if (vb->ident != NULL ) 01391 { 01392 mem_free(vb->ident); 01393 } 01394 mem_free(vb); 01395 } 01396 01397 void 01398 snmp_varbind_list_free(struct snmp_varbind_root *root) 01399 { 01400 struct snmp_varbind *vb, *prev; 01401 01402 vb = root->tail; 01403 while ( vb != NULL ) 01404 { 01405 prev = vb->prev; 01406 snmp_varbind_free(vb); 01407 vb = prev; 01408 } 01409 root->count = 0; 01410 root->head = NULL; 01411 root->tail = NULL; 01412 } 01413 01414 void 01415 snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb) 01416 { 01417 if (root->count == 0) 01418 { 01419 /* add first varbind to list */ 01420 root->head = vb; 01421 root->tail = vb; 01422 } 01423 else 01424 { 01425 /* add nth varbind to list tail */ 01426 root->tail->next = vb; 01427 vb->prev = root->tail; 01428 root->tail = vb; 01429 } 01430 root->count += 1; 01431 } 01432 01433 struct snmp_varbind* 01434 snmp_varbind_tail_remove(struct snmp_varbind_root *root) 01435 { 01436 struct snmp_varbind* vb; 01437 01438 if (root->count > 0) 01439 { 01440 /* remove tail varbind */ 01441 vb = root->tail; 01442 root->tail = vb->prev; 01443 vb->prev->next = NULL; 01444 root->count -= 1; 01445 } 01446 else 01447 { 01448 /* nothing to remove */ 01449 vb = NULL; 01450 } 01451 return vb; 01452 } 01453 01454 #endif /* LWIP_SNMP */
Generated on Tue Jul 12 2022 19:17:23 by 1.7.2