diff --git a/src/core/snmp/msg_in.c b/src/core/snmp/msg_in.c index 0832f601..3284370f 100644 --- a/src/core/snmp/msg_in.c +++ b/src/core/snmp/msg_in.c @@ -2,7 +2,7 @@ * @file * [EXPERIMENTAL] SNMP input message processing (RFC1157). * - * EXPERIMENTAL dumb echo, this is not how the agent should respond. + * EXPERIMENTAL code, this is not how the agent should respond. * This is for test purposes only, DO NOT USE THIS CODE IN REAL WORLD!! */ @@ -50,7 +50,7 @@ #include "lwip/snmp_msg.h" #include "lwip/snmp_structs.h" -#define SNMP_CONCURRENT_REQUESTS 2 +#define TODO_SNMP_MSG_EVENT 0 /* public (non-static) constants */ /** SNMP v1 == 0 */ @@ -59,6 +59,9 @@ const s32_t snmp_version = 0; const char snmp_publiccommunity[7] = "public"; /* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */ +#if (SNMP_CONCURRENT_REQUESTS == 0) +#error "need at least one snmp_msg_pstat" +#endif struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS]; /* UDP Protocol Control Block */ struct udp_pcb *snmp1_pcb = NULL; @@ -98,78 +101,124 @@ snmp_init(void) snmp_coldstart_trap(); } -#if 0 + +#if TODO_SNMP_MSG_EVENT /** * called for each variable binding (also for the fist one) + * + * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) + * @param pm points to a private message used for */ void -snmp_msg_event(struct snmp_msg_pstat *msg_ps) +snmp_msg_event(u8_t request_id) { + struct snmp_msg_pstat *msg_ps; struct mib_node *mn; - struct obj_def object_def; + struct snmp_name_ptr np; - if (msg_ps->state == SNMP_MSG_DEMUX) + if (request_id < SNMP_CONCURRENT_REQUESTS) { - if (msg_ps->vb_idx == 0) + msg_ps = &msg_input_list[request_id]; + + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); + if (msg_ps->state == SNMP_MSG_DEMUX) { - msg_ps->vb_ptr = msg_ps->invb.head; - } - else - { - msg_ps->vb_ptr = msg_ps->vb_ptr->next; - msg_ps->vb_idx += 1; - } - if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) - { - struct snmp_name_ptr np; - - /** test object identifier for .iso.org.dod.internet prefix */ - if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) + if (msg_ps->vb_idx == 0) { - mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, - msg_ps->vb_ptr->ident + 4, &np); + msg_ps->vb_ptr = msg_ps->invb.head; } else { - mn = NULL; + msg_ps->vb_ptr = msg_ps->vb_ptr->next; + msg_ps->vb_idx += 1; } - if (mn != NULL) + if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) { - if (mn->node_type == MIB_NODE_EX) + /** test object identifier for .iso.org.dod.internet prefix */ + if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) { - /* external object */ - msg_ps->state = SNMP_MSG_EXTERNAL; - mn->get_object_def_r(np.ident_len, np.ident, &object_def); - if (object_def.instance != MIB_OBJECT_NONE) - { - mn = mn; - } - else - { - /* search failed, object id points to unknown object (nosuchname) */ - mn = NULL; - } + mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, + msg_ps->vb_ptr->ident + 4, &np); } else { - /* internal object */ - msg_ps->state = SNMP_MSG_INTERNAL; - mn->get_object_def(np.ident_len, np.ident, &object_def); - if (object_def.instance != MIB_OBJECT_NONE) + mn = NULL; + } + if (mn != NULL) + { + if (mn->node_type == MIB_NODE_EX) { - mn = mn; + /* external object */ + struct mib_external_node *en = (struct mib_external_node*)mn; + + msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; + /* save en && args in msg_ps!! */ + msg_ps->ext_mib_node = en; + msg_ps->ext_name_ptr = np; + + en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); } else { - /* search failed, object id points to unknown object (nosuchname) */ - mn = NULL; + /* internal object */ + struct obj_def object_def; + + msg_ps->state = SNMP_MSG_INTERNAL; + mn->get_object_def(np.ident_len, np.ident, &object_def); + if (object_def.instance != MIB_OBJECT_NONE) + { + mn = mn; + } + else + { + /* search failed, object id points to unknown object (nosuchname) */ + mn = NULL; + } + msg_ps->state = SNMP_MSG_DEMUX; } - msg_ps->state = SNMP_MSG_DEMUX; + } + if (mn == NULL) + { + /* mn == NULL, noSuchName */ + snmp_varbind_list_free(&msg_ps->outvb); + msg_ps->outvb = msg_ps->invb; + msg_ps->invb.head = NULL; + msg_ps->invb.tail = NULL; + msg_ps->invb.count = 0; + msg_ps->error_status = SNMP_ES_NOSUCHNAME; + msg_ps->error_index = 1 + msg_ps->vb_idx; + snmp_send_response(msg_ps); + msg_ps->state = SNMP_MSG_EMPTY; } } - if (mn != NULL) + } + else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) + { + struct mib_external_node *en; + + /* get_object_def() answer*/ + en = msg_ps->ext_mib_node; + np = msg_ps->ext_name_ptr; + + /* translate answer into a known lifeform */ + en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); + + if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) { - /* mn == NULL, noSuchName */ + if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) + { + msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; + en->get_value_q(request_id, &msg_ps->ext_object_def); + } + else + { + /** @todo other SNMP requests */ + } + } + else + { + /* search failed, object id points to unknown object (nosuchname) */ + mn = NULL; snmp_varbind_list_free(&msg_ps->outvb); msg_ps->outvb = msg_ps->invb; msg_ps->invb.head = NULL; @@ -181,18 +230,91 @@ snmp_msg_event(struct snmp_msg_pstat *msg_ps) msg_ps->state = SNMP_MSG_EMPTY; } } - else if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) + else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) { + struct mib_external_node *en; + + /* get_value() answer */ + en = msg_ps->ext_mib_node; + + /* translate answer into a known lifeform */ + if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) + { + struct snmp_varbind *vb; + + /* allocate output varbind */ + vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); + if (vb != NULL) + { + vb->next = NULL; + vb->prev = NULL; + + /* move name from invb to outvb */ + vb->ident = msg_ps->vb_ptr->ident; + vb->ident_len = msg_ps->vb_ptr->ident_len; + /* ensure this memory is refereced once only */ + msg_ps->vb_ptr->ident = NULL; + msg_ps->vb_ptr->ident_len = 0; + + vb->value_type = msg_ps->ext_object_def.asn_type; + vb->value_len = msg_ps->ext_object_def.v_len; + vb->value = mem_malloc(msg_ps->ext_object_def.v_len); + if (vb->value != NULL) + { + en->get_value_a(request_id, &msg_ps->ext_object_def, msg_ps->ext_object_def.v_len, vb->value); + snmp_varbind_tail_add(&msg_ps->outvb, vb); + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n")); + } + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n")); + } + } + else + { + /** @todo other SNMP requests */ + } + msg_ps->state = SNMP_MSG_DEMUX; } - else if (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ) + else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST) { + } - } - else if (msg_ps->state == SNMP_MSG_INTERNAL) - { - } - else if (msg_ps->state == SNMP_MSG_EXTERNAL) - { + else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE) + { + + } + + + /* if next state is demuxing AND we demuxed all input varbinds, + we can make a reply and set the state to SNMP_MSG_EMPTY. */ + if ((msg_ps->state == SNMP_MSG_DEMUX) && + ((msg_ps->vb_idx + 1) == msg_ps->invb.count)) + { + err_t err_ret; + + err_ret = snmp_send_response(msg_ps); + if (err_ret == ERR_MEM) + { + /* serious memory problem, can't return tooBig */ +#if LWIP_STATS + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event pbufs.used = %"U16_F"\n",lwip_stats.pbuf.used)); +#endif + } + else + { + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status)); + } + /* free varbinds (if available) */ + snmp_varbind_list_free(&msg_ps->invb); + snmp_varbind_list_free(&msg_ps->outvb); + msg_ps->state = SNMP_MSG_EMPTY; + } + } } #endif @@ -213,17 +335,17 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == 161)) { struct snmp_msg_pstat *msg_ps; - u8_t i; + u8_t req_idx; /* traverse input message process list, look for SNMP_MSG_EMPTY */ msg_ps = &msg_input_list[0]; - i = 0; - while ((istate != SNMP_MSG_EMPTY)) + req_idx = 0; + while ((req_idxstate != SNMP_MSG_EMPTY)) { - i++; + req_idx++; msg_ps++; } - if (i != SNMP_CONCURRENT_REQUESTS) + if (req_idx != SNMP_CONCURRENT_REQUESTS) { err_t err_ret; u16_t payload_len; @@ -282,6 +404,14 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); +#if TODO_SNMP_MSG_EVENT + /* handle input events (and demux as much as possible in one go) */ + while (msg_ps->state == SNMP_MSG_DEMUX) + { + /** iterate over invb and change msg_ps->state */ + snmp_msg_event(req_idx); + } +#else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) { /** test object identifier for .iso.org.dod.internet prefix */ @@ -508,6 +638,7 @@ snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, snmp_varbind_list_free(&msg_ps->invb); snmp_varbind_list_free(&msg_ps->outvb); msg_ps->state = SNMP_MSG_EMPTY; +#endif /* disable */ } else { diff --git a/src/include/lwip/opt.h b/src/include/lwip/opt.h index c5e21f76..ab4e2e51 100644 --- a/src/include/lwip/opt.h +++ b/src/include/lwip/opt.h @@ -254,6 +254,12 @@ a lot of data that needs to be copied, this should be set high. */ #ifndef LWIP_SNMP #define LWIP_SNMP 0 #endif + +/** @note At least one request buffer is required. */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS 1 +#endif + /** @note At least one trap destination is required */ #ifndef SNMP_TRAP_DESTINATIONS #define SNMP_TRAP_DESTINATIONS 1 diff --git a/src/include/lwip/snmp_msg.h b/src/include/lwip/snmp_msg.h index af703590..5a54fa37 100644 --- a/src/include/lwip/snmp_msg.h +++ b/src/include/lwip/snmp_msg.h @@ -38,6 +38,7 @@ #include "lwip/opt.h" #include "arch/cc.h" #include "lwip/snmp.h" +#include "lwip/snmp_structs.h" #if SNMP_PRIVATE_MIB #include "private_mib.h" @@ -186,8 +187,10 @@ struct snmp_trap_header_lengths /* perform SNMP operation on varbind for in-memory case */ #define SNMP_MSG_INTERNAL 2 /* perform SNMP operation on private varbind external case */ -#define SNMP_MSG_EXTERNAL 3 - +#define SNMP_MSG_EXTERNAL_GET_OBJDEF 3 +#define SNMP_MSG_EXTERNAL_GET_VALUE 4 +#define SNMP_MSG_EXTERNAL_SET_TEST 5 +#define SNMP_MSG_EXTERNAL_SET_VALUE 6 #define SNMP_COMMUNITY_STR_LEN 64 struct snmp_msg_pstat @@ -213,8 +216,12 @@ struct snmp_msg_pstat u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; /* community string length (exclusive zero term) */ u8_t com_strlen; - /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL */ + /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ u8_t state; + /* saved arguments for MSG_EXTERNAL_x */ + struct mib_external_node *ext_mib_node; + struct snmp_name_ptr ext_name_ptr; + struct obj_def ext_object_def; /* index into input variable binding list */ u8_t vb_idx; /* ptr into input variable binding list */ @@ -226,7 +233,8 @@ struct snmp_msg_pstat /* output response lengths used in ASN encoding */ struct snmp_resp_header_lengths rhl; #if SNMP_PRIVATE_MIB - struct private_state ps; + /* private MIB event info */ + struct private_msg pm; #endif }; @@ -254,10 +262,6 @@ struct snmp_msg_trap struct snmp_varbind_root outvb; /* output trap lengths used in ASN encoding */ struct snmp_trap_header_lengths thl; -#if SNMP_PRIVATE_MIB - /** @todo is this really needed? */ - struct private_state ps; -#endif }; /** Agent Version constant, 0 = v1 oddity */ @@ -280,7 +284,7 @@ void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind * struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); /** Handles internal/external events. */ -void snmp_msg_event(struct snmp_msg_pstat *msg_ps); +void snmp_msg_event(u8_t request_id); err_t snmp_send_response(struct snmp_msg_pstat *m_stat); err_t snmp_send_trap(s8_t generic_trap, s32_t specific_trap); void snmp_coldstart_trap(void); diff --git a/src/include/lwip/snmp_structs.h b/src/include/lwip/snmp_structs.h index 5fa3f45f..161c3c10 100644 --- a/src/include/lwip/snmp_structs.h +++ b/src/include/lwip/snmp_structs.h @@ -203,11 +203,16 @@ struct mib_external_node s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); - /** async requests */ - void (*get_object_def_r)(u8_t ident_len, s32_t *ident, struct obj_def *od); - void (*get_value_r)(struct obj_def *od, u16_t len, void *value); - u8_t (*set_test_r)(struct obj_def *od, u16_t len, void *value); - void (*set_value_r)(struct obj_def *od, u16_t len, void *value); + /** async Questions */ + void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); + void (*get_value_q)(u8_t rid, struct obj_def *od); + void (*set_test_q)(u8_t rid, struct obj_def *od); + void (*set_value_q)(u8_t rid, struct obj_def *od); + /** async Answers */ + void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); + void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); }; /** export MIB tree from mib2.c */