| /** |
| * @file |
| * MIB tree access/construction functions. |
| */ |
| |
| /* |
| * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. |
| * All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without modification, |
| * are permitted provided that the following conditions are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright notice, |
| * this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright notice, |
| * this list of conditions and the following disclaimer in the documentation |
| * and/or other materials provided with the distribution. |
| * 3. The name of the author may not be used to endorse or promote products |
| * derived from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED |
| * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT |
| * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT |
| * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
| * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY |
| * OF SUCH DAMAGE. |
| * |
| * Author: Christiaan Simons <christiaan.simons@axon.tv> |
| */ |
| |
| #include "lwip/opt.h" |
| |
| #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ |
| |
| #include "lwip/snmp_structs.h" |
| #include "lwip/mem.h" |
| |
| /** .iso.org.dod.internet address prefix, @see snmp_iso_*() */ |
| const s32_t prefix[4] = {1, 3, 6, 1}; |
| |
| #define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN) |
| /** node stack entry (old news?) */ |
| struct nse |
| { |
| /** right child */ |
| struct mib_node* r_ptr; |
| /** right child identifier */ |
| s32_t r_id; |
| /** right child next level */ |
| u8_t r_nl; |
| }; |
| static u8_t node_stack_cnt; |
| static struct nse node_stack[NODE_STACK_SIZE]; |
| |
| /** |
| * Pushes nse struct onto stack. |
| */ |
| static void |
| push_node(struct nse* node) |
| { |
| LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE); |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id)); |
| if (node_stack_cnt < NODE_STACK_SIZE) |
| { |
| node_stack[node_stack_cnt] = *node; |
| node_stack_cnt++; |
| } |
| } |
| |
| /** |
| * Pops nse struct from stack. |
| */ |
| static void |
| pop_node(struct nse* node) |
| { |
| if (node_stack_cnt > 0) |
| { |
| node_stack_cnt--; |
| *node = node_stack[node_stack_cnt]; |
| } |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id)); |
| } |
| |
| /** |
| * Conversion from ifIndex to lwIP netif |
| * @param ifindex is a s32_t object sub-identifier |
| * @param netif points to returned netif struct pointer |
| */ |
| void |
| snmp_ifindextonetif(s32_t ifindex, struct netif **netif) |
| { |
| struct netif *nif = netif_list; |
| u16_t i, ifidx; |
| |
| ifidx = ifindex - 1; |
| i = 0; |
| while ((nif != NULL) && (i < ifidx)) |
| { |
| nif = nif->next; |
| i++; |
| } |
| *netif = nif; |
| } |
| |
| /** |
| * Conversion from lwIP netif to ifIndex |
| * @param netif points to a netif struct |
| * @param ifidx points to s32_t object sub-identifier |
| */ |
| void |
| snmp_netiftoifindex(struct netif *netif, s32_t *ifidx) |
| { |
| struct netif *nif = netif_list; |
| u16_t i; |
| |
| i = 0; |
| while ((nif != NULL) && (nif != netif)) |
| { |
| nif = nif->next; |
| i++; |
| } |
| *ifidx = i+1; |
| } |
| |
| /** |
| * Conversion from oid to lwIP ip_addr |
| * @param ident points to s32_t ident[4] input |
| * @param ip points to output struct |
| */ |
| void |
| snmp_oidtoip(s32_t *ident, struct ip_addr *ip) |
| { |
| u32_t ipa; |
| |
| ipa = ident[0]; |
| ipa <<= 8; |
| ipa |= ident[1]; |
| ipa <<= 8; |
| ipa |= ident[2]; |
| ipa <<= 8; |
| ipa |= ident[3]; |
| ip->addr = ipa; |
| } |
| |
| /** |
| * Conversion from lwIP ip_addr to oid |
| * @param ip points to input struct |
| * @param ident points to s32_t ident[4] output |
| */ |
| void |
| snmp_iptooid(struct ip_addr *ip, s32_t *ident) |
| { |
| u32_t ipa; |
| |
| ipa = ip->addr; |
| ident[0] = (ipa >> 24) & 0xff; |
| ident[1] = (ipa >> 16) & 0xff; |
| ident[2] = (ipa >> 8) & 0xff; |
| ident[3] = ipa & 0xff; |
| } |
| |
| struct mib_list_node * |
| snmp_mib_ln_alloc(s32_t id) |
| { |
| struct mib_list_node *ln; |
| |
| ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node)); |
| if (ln != NULL) |
| { |
| ln->prev = NULL; |
| ln->next = NULL; |
| ln->objid = id; |
| ln->nptr = NULL; |
| } |
| return ln; |
| } |
| |
| void |
| snmp_mib_ln_free(struct mib_list_node *ln) |
| { |
| mem_free(ln); |
| } |
| |
| struct mib_list_rootnode * |
| snmp_mib_lrn_alloc(void) |
| { |
| struct mib_list_rootnode *lrn; |
| |
| lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode)); |
| if (lrn != NULL) |
| { |
| lrn->get_object_def = noleafs_get_object_def; |
| lrn->get_value = noleafs_get_value; |
| lrn->set_test = noleafs_set_test; |
| lrn->set_value = noleafs_set_value; |
| lrn->node_type = MIB_NODE_LR; |
| lrn->maxlength = 0; |
| lrn->head = NULL; |
| lrn->tail = NULL; |
| lrn->count = 0; |
| } |
| return lrn; |
| } |
| |
| void |
| snmp_mib_lrn_free(struct mib_list_rootnode *lrn) |
| { |
| mem_free(lrn); |
| } |
| |
| /** |
| * Inserts node in idx list in a sorted |
| * (ascending order) fashion and |
| * allocates the node if needed. |
| * |
| * @param rn points to the root node |
| * @param objid is the object sub identifier |
| * @param insn points to a pointer to the inserted node |
| * used for constructing the tree. |
| * @return -1 if failed, 1 if inserted, 2 if present. |
| */ |
| s8_t |
| snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn) |
| { |
| struct mib_list_node *nn; |
| s8_t insert; |
| |
| LWIP_ASSERT("rn != NULL",rn != NULL); |
| |
| /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */ |
| insert = 0; |
| if (rn->head == NULL) |
| { |
| /* empty list, add first node */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid)); |
| nn = snmp_mib_ln_alloc(objid); |
| if (nn != NULL) |
| { |
| rn->head = nn; |
| rn->tail = nn; |
| *insn = nn; |
| insert = 1; |
| } |
| else |
| { |
| insert = -1; |
| } |
| } |
| else |
| { |
| struct mib_list_node *n; |
| /* at least one node is present */ |
| n = rn->head; |
| while ((n != NULL) && (insert == 0)) |
| { |
| if (n->objid == objid) |
| { |
| /* node is already there */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid)); |
| *insn = n; |
| insert = 2; |
| } |
| else if (n->objid < objid) |
| { |
| if (n->next == NULL) |
| { |
| /* alloc and insert at the tail */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid)); |
| nn = snmp_mib_ln_alloc(objid); |
| if (nn != NULL) |
| { |
| nn->next = NULL; |
| nn->prev = n; |
| n->next = nn; |
| rn->tail = nn; |
| *insn = nn; |
| insert = 1; |
| } |
| else |
| { |
| /* insertion failure */ |
| insert = -1; |
| } |
| } |
| else |
| { |
| /* there's more to explore: traverse list */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n")); |
| n = n->next; |
| } |
| } |
| else |
| { |
| /* n->objid > objid */ |
| /* alloc and insert between n->prev and n */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid)); |
| nn = snmp_mib_ln_alloc(objid); |
| if (nn != NULL) |
| { |
| if (n->prev == NULL) |
| { |
| /* insert at the head */ |
| nn->next = n; |
| nn->prev = NULL; |
| rn->head = nn; |
| n->prev = nn; |
| } |
| else |
| { |
| /* insert in the middle */ |
| nn->next = n; |
| nn->prev = n->prev; |
| n->prev->next = nn; |
| n->prev = nn; |
| } |
| *insn = nn; |
| insert = 1; |
| } |
| else |
| { |
| /* insertion failure */ |
| insert = -1; |
| } |
| } |
| } |
| } |
| if (insert == 1) |
| { |
| rn->count += 1; |
| } |
| LWIP_ASSERT("insert != 0",insert != 0); |
| return insert; |
| } |
| |
| /** |
| * Finds node in idx list and returns deletion mark. |
| * |
| * @param rn points to the root node |
| * @param objid is the object sub identifier |
| * @param fn returns pointer to found node |
| * @return 0 if not found, 1 if deletable, |
| * 2 can't delete (2 or more children), 3 not a list_node |
| */ |
| s8_t |
| snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn) |
| { |
| s8_t fc; |
| struct mib_list_node *n; |
| |
| LWIP_ASSERT("rn != NULL",rn != NULL); |
| n = rn->head; |
| while ((n != NULL) && (n->objid != objid)) |
| { |
| n = n->next; |
| } |
| if (n == NULL) |
| { |
| fc = 0; |
| } |
| else if (n->nptr == NULL) |
| { |
| /* leaf, can delete node */ |
| fc = 1; |
| } |
| else |
| { |
| struct mib_list_rootnode *r; |
| |
| if (n->nptr->node_type == MIB_NODE_LR) |
| { |
| r = (struct mib_list_rootnode *)n->nptr; |
| if (r->count > 1) |
| { |
| /* can't delete node */ |
| fc = 2; |
| } |
| else |
| { |
| /* count <= 1, can delete node */ |
| fc = 1; |
| } |
| } |
| else |
| { |
| /* other node type */ |
| fc = 3; |
| } |
| } |
| *fn = n; |
| return fc; |
| } |
| |
| /** |
| * Removes node from idx list |
| * if it has a single child left. |
| * |
| * @param rn points to the root node |
| * @param n points to the node to delete |
| * @return the nptr to be freed by caller |
| */ |
| struct mib_list_rootnode * |
| snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n) |
| { |
| struct mib_list_rootnode *next; |
| |
| LWIP_ASSERT("rn != NULL",rn != NULL); |
| LWIP_ASSERT("n != NULL",n != NULL); |
| |
| /* caller must remove this sub-tree */ |
| next = (struct mib_list_rootnode*)(n->nptr); |
| rn->count -= 1; |
| |
| if (n == rn->head) |
| { |
| rn->head = n->next; |
| if (n->next != NULL) |
| { |
| /* not last node, new list begin */ |
| n->next->prev = NULL; |
| } |
| } |
| else if (n == rn->tail) |
| { |
| rn->tail = n->prev; |
| if (n->prev != NULL) |
| { |
| /* not last node, new list end */ |
| n->prev->next = NULL; |
| } |
| } |
| else |
| { |
| /* node must be in the middle */ |
| n->prev->next = n->next; |
| n->next->prev = n->prev; |
| } |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid)); |
| snmp_mib_ln_free(n); |
| if (rn->count == 0) |
| { |
| rn->head = NULL; |
| rn->tail = NULL; |
| } |
| return next; |
| } |
| |
| |
| |
| /** |
| * Searches tree for the supplied (scalar?) object identifier. |
| * |
| * @param node points to the root of the tree ('.internet') |
| * @param ident_len the length of the supplied object identifier |
| * @param ident points to the array of sub identifiers |
| * @param np points to the found object instance (rerurn) |
| * @return pointer to the requested parent (!) node if success, NULL otherwise |
| */ |
| struct mib_node * |
| snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np) |
| { |
| u8_t node_type, ext_level; |
| |
| ext_level = 0; |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident)); |
| while (node != NULL) |
| { |
| node_type = node->node_type; |
| if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) |
| { |
| struct mib_array_node *an; |
| u16_t i; |
| |
| if (ident_len > 0) |
| { |
| /* array node (internal ROM or RAM, fixed length) */ |
| an = (struct mib_array_node *)node; |
| i = 0; |
| while ((i < an->maxlength) && (an->objid[i] != *ident)) |
| { |
| i++; |
| } |
| if (i < an->maxlength) |
| { |
| /* found it, if available proceed to child, otherwise inspect leaf */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); |
| if (an->nptr[i] == NULL) |
| { |
| /* a scalar leaf OR table, |
| inspect remaining instance number / table index */ |
| np->ident_len = ident_len; |
| np->ident = ident; |
| return (struct mib_node*)an; |
| } |
| else |
| { |
| /* follow next child pointer */ |
| ident++; |
| ident_len--; |
| node = an->nptr[i]; |
| } |
| } |
| else |
| { |
| /* search failed, identifier mismatch (nosuchname) */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident)); |
| return NULL; |
| } |
| } |
| else |
| { |
| /* search failed, short object identifier (nosuchname) */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n")); |
| return NULL; |
| } |
| } |
| else if(node_type == MIB_NODE_LR) |
| { |
| struct mib_list_rootnode *lrn; |
| struct mib_list_node *ln; |
| |
| if (ident_len > 0) |
| { |
| /* list root node (internal 'RAM', variable length) */ |
| lrn = (struct mib_list_rootnode *)node; |
| ln = lrn->head; |
| /* iterate over list, head to tail */ |
| while ((ln != NULL) && (ln->objid != *ident)) |
| { |
| ln = ln->next; |
| } |
| if (ln != NULL) |
| { |
| /* found it, proceed to child */; |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); |
| if (ln->nptr == NULL) |
| { |
| np->ident_len = ident_len; |
| np->ident = ident; |
| return (struct mib_node*)lrn; |
| } |
| else |
| { |
| /* follow next child pointer */ |
| ident_len--; |
| ident++; |
| node = ln->nptr; |
| } |
| } |
| else |
| { |
| /* search failed */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident)); |
| return NULL; |
| } |
| } |
| else |
| { |
| /* search failed, short object identifier (nosuchname) */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n")); |
| return NULL; |
| } |
| } |
| else if(node_type == MIB_NODE_EX) |
| { |
| struct mib_external_node *en; |
| u16_t i, len; |
| |
| if (ident_len > 0) |
| { |
| /* external node (addressing and access via functions) */ |
| en = (struct mib_external_node *)node; |
| |
| i = 0; |
| len = en->level_length(en->addr_inf,ext_level); |
| while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0)) |
| { |
| i++; |
| } |
| if (i < len) |
| { |
| s32_t debug_id; |
| |
| en->get_objid(en->addr_inf,ext_level,i,&debug_id); |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident)); |
| if ((ext_level + 1) == en->tree_levels) |
| { |
| np->ident_len = ident_len; |
| np->ident = ident; |
| return (struct mib_node*)en; |
| } |
| else |
| { |
| /* found it, proceed to child */ |
| ident_len--; |
| ident++; |
| ext_level++; |
| } |
| } |
| else |
| { |
| /* search failed */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident)); |
| return NULL; |
| } |
| } |
| else |
| { |
| /* search failed, short object identifier (nosuchname) */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n")); |
| return NULL; |
| } |
| } |
| else if (node_type == MIB_NODE_SC) |
| { |
| mib_scalar_node *sn; |
| |
| sn = (mib_scalar_node *)node; |
| if ((ident_len == 1) && (*ident == 0)) |
| { |
| np->ident_len = ident_len; |
| np->ident = ident; |
| return (struct mib_node*)sn; |
| } |
| else |
| { |
| /* search failed, short object identifier (nosuchname) */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n")); |
| return NULL; |
| } |
| } |
| else |
| { |
| /* unknown node_type */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type)); |
| return NULL; |
| } |
| } |
| /* done, found nothing */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node)); |
| return NULL; |
| } |
| |
| /** |
| * Test table for presence of at least one table entry. |
| */ |
| static u8_t |
| empty_table(struct mib_node *node) |
| { |
| u8_t node_type; |
| u8_t empty = 0; |
| |
| if (node != NULL) |
| { |
| node_type = node->node_type; |
| if (node_type == MIB_NODE_LR) |
| { |
| struct mib_list_rootnode *lrn; |
| lrn = (struct mib_list_rootnode *)node; |
| if ((lrn->count == 0) || (lrn->head == NULL)) |
| { |
| empty = 1; |
| } |
| } |
| else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) |
| { |
| struct mib_array_node *an; |
| an = (struct mib_array_node *)node; |
| if ((an->maxlength == 0) || (an->nptr == NULL)) |
| { |
| empty = 1; |
| } |
| } |
| else if (node_type == MIB_NODE_EX) |
| { |
| struct mib_external_node *en; |
| en = (struct mib_external_node *)node; |
| if (en->tree_levels == 0) |
| { |
| empty = 1; |
| } |
| } |
| } |
| return empty; |
| } |
| |
| /** |
| * Tree expansion. |
| */ |
| struct mib_node * |
| snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) |
| { |
| u8_t node_type, ext_level, climb_tree; |
| |
| ext_level = 0; |
| /* reset node stack */ |
| node_stack_cnt = 0; |
| while (node != NULL) |
| { |
| climb_tree = 0; |
| node_type = node->node_type; |
| if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) |
| { |
| struct mib_array_node *an; |
| u16_t i; |
| |
| /* array node (internal ROM or RAM, fixed length) */ |
| an = (struct mib_array_node *)node; |
| if (ident_len > 0) |
| { |
| i = 0; |
| while ((i < an->maxlength) && (an->objid[i] < *ident)) |
| { |
| i++; |
| } |
| if (i < an->maxlength) |
| { |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); |
| /* add identifier to oidret */ |
| oidret->id[oidret->len] = an->objid[i]; |
| (oidret->len)++; |
| |
| if (an->nptr[i] == NULL) |
| { |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); |
| /* leaf node (e.g. in a fixed size table) */ |
| if (an->objid[i] > *ident) |
| { |
| return (struct mib_node*)an; |
| } |
| else if ((i + 1) < an->maxlength) |
| { |
| /* an->objid[i] == *ident */ |
| (oidret->len)--; |
| oidret->id[oidret->len] = an->objid[i + 1]; |
| (oidret->len)++; |
| return (struct mib_node*)an; |
| } |
| else |
| { |
| /* (i + 1) == an->maxlength */ |
| (oidret->len)--; |
| climb_tree = 1; |
| } |
| } |
| else |
| { |
| u8_t j; |
| struct nse cur_node; |
| |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); |
| /* non-leaf, store right child ptr and id */ |
| j = i + 1; |
| while ((j < an->maxlength) && (empty_table(an->nptr[j]))) |
| { |
| j++; |
| } |
| if (j < an->maxlength) |
| { |
| cur_node.r_ptr = an->nptr[j]; |
| cur_node.r_id = an->objid[j]; |
| cur_node.r_nl = 0; |
| } |
| else |
| { |
| cur_node.r_ptr = NULL; |
| } |
| push_node(&cur_node); |
| if (an->objid[i] == *ident) |
| { |
| ident_len--; |
| ident++; |
| } |
| else |
| { |
| /* an->objid[i] < *ident */ |
| ident_len = 0; |
| } |
| /* follow next child pointer */ |
| node = an->nptr[i]; |
| } |
| } |
| else |
| { |
| /* i == an->maxlength */ |
| climb_tree = 1; |
| } |
| } |
| else |
| { |
| u8_t j; |
| /* ident_len == 0, complete with leftmost '.thing' */ |
| j = 0; |
| while ((j < an->maxlength) && empty_table(an->nptr[j])) |
| { |
| j++; |
| } |
| if (j < an->maxlength) |
| { |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j])); |
| oidret->id[oidret->len] = an->objid[j]; |
| (oidret->len)++; |
| if (an->nptr[j] == NULL) |
| { |
| /* leaf node */ |
| return (struct mib_node*)an; |
| } |
| else |
| { |
| /* no leaf, continue */ |
| node = an->nptr[j]; |
| } |
| } |
| else |
| { |
| /* j == an->maxlength */ |
| climb_tree = 1; |
| } |
| } |
| } |
| else if(node_type == MIB_NODE_LR) |
| { |
| struct mib_list_rootnode *lrn; |
| struct mib_list_node *ln; |
| |
| /* list root node (internal 'RAM', variable length) */ |
| lrn = (struct mib_list_rootnode *)node; |
| if (ident_len > 0) |
| { |
| ln = lrn->head; |
| /* iterate over list, head to tail */ |
| while ((ln != NULL) && (ln->objid < *ident)) |
| { |
| ln = ln->next; |
| } |
| if (ln != NULL) |
| { |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); |
| oidret->id[oidret->len] = ln->objid; |
| (oidret->len)++; |
| if (ln->nptr == NULL) |
| { |
| /* leaf node */ |
| if (ln->objid > *ident) |
| { |
| return (struct mib_node*)lrn; |
| } |
| else if (ln->next != NULL) |
| { |
| /* ln->objid == *ident */ |
| (oidret->len)--; |
| oidret->id[oidret->len] = ln->next->objid; |
| (oidret->len)++; |
| return (struct mib_node*)lrn; |
| } |
| else |
| { |
| /* ln->next == NULL */ |
| (oidret->len)--; |
| climb_tree = 1; |
| } |
| } |
| else |
| { |
| struct mib_list_node *jn; |
| struct nse cur_node; |
| |
| /* non-leaf, store right child ptr and id */ |
| jn = ln->next; |
| while ((jn != NULL) && empty_table(jn->nptr)) |
| { |
| jn = jn->next; |
| } |
| if (jn != NULL) |
| { |
| cur_node.r_ptr = jn->nptr; |
| cur_node.r_id = jn->objid; |
| cur_node.r_nl = 0; |
| } |
| else |
| { |
| cur_node.r_ptr = NULL; |
| } |
| push_node(&cur_node); |
| if (ln->objid == *ident) |
| { |
| ident_len--; |
| ident++; |
| } |
| else |
| { |
| /* ln->objid < *ident */ |
| ident_len = 0; |
| } |
| /* follow next child pointer */ |
| node = ln->nptr; |
| } |
| |
| } |
| else |
| { |
| /* ln == NULL */ |
| climb_tree = 1; |
| } |
| } |
| else |
| { |
| struct mib_list_node *jn; |
| /* ident_len == 0, complete with leftmost '.thing' */ |
| jn = lrn->head; |
| while ((jn != NULL) && empty_table(jn->nptr)) |
| { |
| jn = jn->next; |
| } |
| if (jn != NULL) |
| { |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid)); |
| oidret->id[oidret->len] = jn->objid; |
| (oidret->len)++; |
| if (jn->nptr == NULL) |
| { |
| /* leaf node */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n")); |
| return (struct mib_node*)lrn; |
| } |
| else |
| { |
| /* no leaf, continue */ |
| node = jn->nptr; |
| } |
| } |
| else |
| { |
| /* jn == NULL */ |
| climb_tree = 1; |
| } |
| } |
| } |
| else if(node_type == MIB_NODE_EX) |
| { |
| struct mib_external_node *en; |
| s32_t ex_id; |
| |
| /* external node (addressing and access via functions) */ |
| en = (struct mib_external_node *)node; |
| if (ident_len > 0) |
| { |
| u16_t i, len; |
| |
| i = 0; |
| len = en->level_length(en->addr_inf,ext_level); |
| while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0)) |
| { |
| i++; |
| } |
| if (i < len) |
| { |
| /* add identifier to oidret */ |
| en->get_objid(en->addr_inf,ext_level,i,&ex_id); |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident)); |
| oidret->id[oidret->len] = ex_id; |
| (oidret->len)++; |
| |
| if ((ext_level + 1) == en->tree_levels) |
| { |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); |
| /* leaf node */ |
| if (ex_id > *ident) |
| { |
| return (struct mib_node*)en; |
| } |
| else if ((i + 1) < len) |
| { |
| /* ex_id == *ident */ |
| en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id); |
| (oidret->len)--; |
| oidret->id[oidret->len] = ex_id; |
| (oidret->len)++; |
| return (struct mib_node*)en; |
| } |
| else |
| { |
| /* (i + 1) == len */ |
| (oidret->len)--; |
| climb_tree = 1; |
| } |
| } |
| else |
| { |
| u8_t j; |
| struct nse cur_node; |
| |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); |
| /* non-leaf, store right child ptr and id */ |
| j = i + 1; |
| if (j < len) |
| { |
| /* right node is the current external node */ |
| cur_node.r_ptr = node; |
| en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id); |
| cur_node.r_nl = ext_level + 1; |
| } |
| else |
| { |
| cur_node.r_ptr = NULL; |
| } |
| push_node(&cur_node); |
| if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0) |
| { |
| ident_len--; |
| ident++; |
| } |
| else |
| { |
| /* external id < *ident */ |
| ident_len = 0; |
| } |
| /* proceed to child */ |
| ext_level++; |
| } |
| } |
| else |
| { |
| /* i == len (en->level_len()) */ |
| climb_tree = 1; |
| } |
| } |
| else |
| { |
| /* ident_len == 0, complete with leftmost '.thing' */ |
| en->get_objid(en->addr_inf,ext_level,0,&ex_id); |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id)); |
| oidret->id[oidret->len] = ex_id; |
| (oidret->len)++; |
| if ((ext_level + 1) == en->tree_levels) |
| { |
| /* leaf node */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n")); |
| return (struct mib_node*)en; |
| } |
| else |
| { |
| /* no leaf, proceed to child */ |
| ext_level++; |
| } |
| } |
| } |
| else if(node_type == MIB_NODE_SC) |
| { |
| mib_scalar_node *sn; |
| |
| /* scalar node */ |
| sn = (mib_scalar_node *)node; |
| if (ident_len > 0) |
| { |
| /* at .0 */ |
| climb_tree = 1; |
| } |
| else |
| { |
| /* ident_len == 0, complete object identifier */ |
| oidret->id[oidret->len] = 0; |
| (oidret->len)++; |
| /* leaf node */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n")); |
| return (struct mib_node*)sn; |
| } |
| } |
| else |
| { |
| /* unknown/unhandled node_type */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type)); |
| return NULL; |
| } |
| |
| if (climb_tree) |
| { |
| struct nse child; |
| |
| /* find right child ptr */ |
| child.r_ptr = NULL; |
| child.r_id = 0; |
| child.r_nl = 0; |
| while ((node_stack_cnt > 0) && (child.r_ptr == NULL)) |
| { |
| pop_node(&child); |
| /* trim returned oid */ |
| (oidret->len)--; |
| } |
| if (child.r_ptr != NULL) |
| { |
| /* incoming ident is useless beyond this point */ |
| ident_len = 0; |
| oidret->id[oidret->len] = child.r_id; |
| oidret->len++; |
| node = child.r_ptr; |
| ext_level = child.r_nl; |
| } |
| else |
| { |
| /* tree ends here ... */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n")); |
| return NULL; |
| } |
| } |
| } |
| /* done, found nothing */ |
| LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node)); |
| return NULL; |
| } |
| |
| /** |
| * Test object identifier for the iso.org.dod.internet prefix. |
| * |
| * @param ident_len the length of the supplied object identifier |
| * @param ident points to the array of sub identifiers |
| * @return 1 if it matches, 0 otherwise |
| */ |
| u8_t |
| snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident) |
| { |
| if ((ident_len > 3) && |
| (ident[0] == 1) && (ident[1] == 3) && |
| (ident[2] == 6) && (ident[3] == 1)) |
| { |
| return 1; |
| } |
| else |
| { |
| return 0; |
| } |
| } |
| |
| /** |
| * Expands object identifier to the iso.org.dod.internet |
| * prefix for use in getnext operation. |
| * |
| * @param ident_len the length of the supplied object identifier |
| * @param ident points to the array of sub identifiers |
| * @param oidret points to returned expanded object identifier |
| * @return 1 if it matches, 0 otherwise |
| * |
| * @note ident_len 0 is allowed, expanding to the first known object id!! |
| */ |
| u8_t |
| snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) |
| { |
| const s32_t *prefix_ptr; |
| s32_t *ret_ptr; |
| u8_t i; |
| |
| i = 0; |
| prefix_ptr = &prefix[0]; |
| ret_ptr = &oidret->id[0]; |
| ident_len = ((ident_len < 4)?ident_len:4); |
| while ((i < ident_len) && ((*ident) <= (*prefix_ptr))) |
| { |
| *ret_ptr++ = *prefix_ptr++; |
| ident++; |
| i++; |
| } |
| if (i == ident_len) |
| { |
| /* match, complete missing bits */ |
| while (i < 4) |
| { |
| *ret_ptr++ = *prefix_ptr++; |
| i++; |
| } |
| oidret->len = i; |
| return 1; |
| } |
| else |
| { |
| /* i != ident_len */ |
| return 0; |
| } |
| } |
| |
| #endif /* LWIP_SNMP */ |