Official mbed lwIP library (version 1.4.0)

Dependents:   LwIPNetworking NetServicesMin EthernetInterface EthernetInterface_RSF ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers mib_structs.c Source File

mib_structs.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * MIB tree access/construction functions.
00004  */
00005 
00006 /*
00007  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
00008  * All rights reserved.
00009  *
00010  * Redistribution and use in source and binary forms, with or without modification,
00011  * are permitted provided that the following conditions are met:
00012  *
00013  * 1. Redistributions of source code must retain the above copyright notice,
00014  *    this list of conditions and the following disclaimer.
00015  * 2. Redistributions in binary form must reproduce the above copyright notice,
00016  *    this list of conditions and the following disclaimer in the documentation
00017  *    and/or other materials provided with the distribution.
00018  * 3. The name of the author may not be used to endorse or promote products
00019  *    derived from this software without specific prior written permission.
00020  *
00021  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
00022  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00023  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
00024  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
00026  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00027  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00028  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
00029  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
00030  * OF SUCH DAMAGE.
00031  *
00032  * Author: Christiaan Simons <christiaan.simons@axon.tv>
00033  */
00034 
00035 #include "lwip/opt.h"
00036 
00037 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
00038 
00039 #include "lwip/snmp_structs.h"
00040 #include "lwip/memp.h"
00041 #include "lwip/netif.h"
00042 
00043 /** .iso.org.dod.internet address prefix, @see snmp_iso_*() */
00044 const s32_t prefix[4] = {1, 3, 6, 1};
00045 
00046 #define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)
00047 /** node stack entry (old news?) */
00048 struct nse
00049 {
00050   /** right child */
00051   struct mib_node* r_ptr;
00052   /** right child identifier */
00053   s32_t r_id;
00054   /** right child next level */
00055   u8_t r_nl;
00056 };
00057 static u8_t node_stack_cnt;
00058 static struct nse node_stack[NODE_STACK_SIZE];
00059 
00060 /**
00061  * Pushes nse struct onto stack.
00062  */
00063 static void
00064 push_node(struct nse* node)
00065 {
00066   LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);
00067   LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));
00068   if (node_stack_cnt < NODE_STACK_SIZE)
00069   {
00070     node_stack[node_stack_cnt] = *node;
00071     node_stack_cnt++;
00072   }
00073 }
00074 
00075 /**
00076  * Pops nse struct from stack.
00077  */
00078 static void
00079 pop_node(struct nse* node)
00080 {
00081   if (node_stack_cnt > 0)
00082   {
00083     node_stack_cnt--;
00084     *node = node_stack[node_stack_cnt];
00085   }
00086   LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));
00087 }
00088 
00089 /**
00090  * Conversion from ifIndex to lwIP netif
00091  * @param ifindex is a s32_t object sub-identifier
00092  * @param netif points to returned netif struct pointer
00093  */
00094 void
00095 snmp_ifindextonetif(s32_t ifindex, struct netif **netif)
00096 {
00097   struct netif *nif = netif_list;
00098   s32_t i, ifidx;
00099 
00100   ifidx = ifindex - 1;
00101   i = 0;
00102   while ((nif != NULL) && (i < ifidx))
00103   {
00104     nif = nif->next;
00105     i++;
00106   }
00107   *netif = nif;
00108 }
00109 
00110 /**
00111  * Conversion from lwIP netif to ifIndex
00112  * @param netif points to a netif struct
00113  * @param ifidx points to s32_t object sub-identifier
00114  */
00115 void
00116 snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
00117 {
00118   struct netif *nif = netif_list;
00119   u16_t i;
00120 
00121   i = 0;
00122   while ((nif != NULL) && (nif != netif))
00123   {
00124     nif = nif->next;
00125     i++;
00126   }
00127   *ifidx = i+1;
00128 }
00129 
00130 /**
00131  * Conversion from oid to lwIP ip_addr
00132  * @param ident points to s32_t ident[4] input
00133  * @param ip points to output struct
00134  */
00135 void
00136 snmp_oidtoip(s32_t *ident, ip_addr_t *ip)
00137 {
00138   IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]);
00139 }
00140 
00141 /**
00142  * Conversion from lwIP ip_addr to oid
00143  * @param ip points to input struct
00144  * @param ident points to s32_t ident[4] output
00145  */
00146 void
00147 snmp_iptooid(ip_addr_t *ip, s32_t *ident)
00148 {
00149   ident[0] = ip4_addr1(ip);
00150   ident[1] = ip4_addr2(ip);
00151   ident[2] = ip4_addr3(ip);
00152   ident[3] = ip4_addr4(ip);
00153 }
00154 
00155 struct mib_list_node *
00156 snmp_mib_ln_alloc(s32_t id)
00157 {
00158   struct mib_list_node *ln;
00159 
00160   ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE);
00161   if (ln != NULL)
00162   {
00163     ln->prev = NULL;
00164     ln->next = NULL;
00165     ln->objid = id;
00166     ln->nptr = NULL;
00167   }
00168   return ln;
00169 }
00170 
00171 void
00172 snmp_mib_ln_free(struct mib_list_node *ln)
00173 {
00174   memp_free(MEMP_SNMP_NODE, ln);
00175 }
00176 
00177 struct mib_list_rootnode *
00178 snmp_mib_lrn_alloc(void)
00179 {
00180   struct mib_list_rootnode *lrn;
00181 
00182   lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE);
00183   if (lrn != NULL)
00184   {
00185     lrn->get_object_def = noleafs_get_object_def;
00186     lrn->get_value = noleafs_get_value;
00187     lrn->set_test = noleafs_set_test;
00188     lrn->set_value = noleafs_set_value;
00189     lrn->node_type = MIB_NODE_LR;
00190     lrn->maxlength = 0;
00191     lrn->head = NULL;
00192     lrn->tail = NULL;
00193     lrn->count = 0;
00194   }
00195   return lrn;
00196 }
00197 
00198 void
00199 snmp_mib_lrn_free(struct mib_list_rootnode *lrn)
00200 {
00201   memp_free(MEMP_SNMP_ROOTNODE, lrn);
00202 }
00203 
00204 /**
00205  * Inserts node in idx list in a sorted
00206  * (ascending order) fashion and
00207  * allocates the node if needed.
00208  *
00209  * @param rn points to the root node
00210  * @param objid is the object sub identifier
00211  * @param insn points to a pointer to the inserted node
00212  *   used for constructing the tree.
00213  * @return -1 if failed, 1 if inserted, 2 if present.
00214  */
00215 s8_t
00216 snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)
00217 {
00218   struct mib_list_node *nn;
00219   s8_t insert;
00220 
00221   LWIP_ASSERT("rn != NULL",rn != NULL);
00222 
00223   /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */
00224   insert = 0;
00225   if (rn->head == NULL)
00226   {
00227     /* empty list, add first node */
00228     LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));
00229     nn = snmp_mib_ln_alloc(objid);
00230     if (nn != NULL)
00231     {
00232       rn->head = nn;
00233       rn->tail = nn;
00234       *insn = nn;
00235       insert = 1;
00236     }
00237     else
00238     {
00239       insert = -1;
00240     }
00241   }
00242   else
00243   {
00244     struct mib_list_node *n;
00245     /* at least one node is present */
00246     n = rn->head;
00247     while ((n != NULL) && (insert == 0))
00248     {
00249       if (n->objid == objid)
00250       {
00251         /* node is already there */
00252         LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));
00253         *insn = n;
00254         insert = 2;
00255       }
00256       else if (n->objid < objid)
00257       {
00258         if (n->next == NULL)
00259         {
00260           /* alloc and insert at the tail */
00261           LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));
00262           nn = snmp_mib_ln_alloc(objid);
00263           if (nn != NULL)
00264           {
00265             nn->next = NULL;
00266             nn->prev = n;
00267             n->next = nn;
00268             rn->tail = nn;
00269             *insn = nn;
00270             insert = 1;
00271           }
00272           else
00273           {
00274             /* insertion failure */
00275             insert = -1;
00276           }
00277         }
00278         else
00279         {
00280           /* there's more to explore: traverse list */
00281           LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));
00282           n = n->next;
00283         }
00284       }
00285       else
00286       {
00287         /* n->objid > objid */
00288         /* alloc and insert between n->prev and n */
00289         LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));
00290         nn = snmp_mib_ln_alloc(objid);
00291         if (nn != NULL)
00292         {
00293           if (n->prev == NULL)
00294           {
00295             /* insert at the head */
00296             nn->next = n;
00297             nn->prev = NULL;
00298             rn->head = nn;
00299             n->prev = nn;
00300           }
00301           else
00302           {
00303             /* insert in the middle */
00304             nn->next = n;
00305             nn->prev = n->prev;
00306             n->prev->next = nn;
00307             n->prev = nn;
00308           }
00309           *insn = nn;
00310           insert = 1;
00311         }
00312         else
00313         {
00314           /* insertion failure */
00315           insert = -1;
00316         }
00317       }
00318     }
00319   }
00320   if (insert == 1)
00321   {
00322     rn->count += 1;
00323   }
00324   LWIP_ASSERT("insert != 0",insert != 0);
00325   return insert;
00326 }
00327 
00328 /**
00329  * Finds node in idx list and returns deletion mark.
00330  *
00331  * @param rn points to the root node
00332  * @param objid  is the object sub identifier
00333  * @param fn returns pointer to found node
00334  * @return 0 if not found, 1 if deletable,
00335  *   2 can't delete (2 or more children), 3 not a list_node
00336  */
00337 s8_t
00338 snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)
00339 {
00340   s8_t fc;
00341   struct mib_list_node *n;
00342 
00343   LWIP_ASSERT("rn != NULL",rn != NULL);
00344   n = rn->head;
00345   while ((n != NULL) && (n->objid != objid))
00346   {
00347     n = n->next;
00348   }
00349   if (n == NULL)
00350   {
00351     fc = 0;
00352   }
00353   else if (n->nptr == NULL)
00354   {
00355     /* leaf, can delete node */
00356     fc = 1;
00357   }
00358   else
00359   {
00360     struct mib_list_rootnode *r;
00361 
00362     if (n->nptr->node_type == MIB_NODE_LR)
00363     {
00364       r = (struct mib_list_rootnode *)n->nptr;
00365       if (r->count > 1)
00366       {
00367         /* can't delete node */
00368         fc = 2;
00369       }
00370       else
00371       {
00372         /* count <= 1, can delete node */
00373         fc = 1;
00374       }
00375     }
00376     else
00377     {
00378       /* other node type */
00379       fc = 3;
00380     }
00381   }
00382   *fn = n;
00383   return fc;
00384 }
00385 
00386 /**
00387  * Removes node from idx list
00388  * if it has a single child left.
00389  *
00390  * @param rn points to the root node
00391  * @param n points to the node to delete
00392  * @return the nptr to be freed by caller
00393  */
00394 struct mib_list_rootnode *
00395 snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)
00396 {
00397   struct mib_list_rootnode *next;
00398 
00399   LWIP_ASSERT("rn != NULL",rn != NULL);
00400   LWIP_ASSERT("n != NULL",n != NULL);
00401 
00402   /* caller must remove this sub-tree */
00403   next = (struct mib_list_rootnode*)(n->nptr);
00404   rn->count -= 1;
00405 
00406   if (n == rn->head)
00407   {
00408     rn->head = n->next;
00409     if (n->next != NULL)
00410     {
00411       /* not last node, new list begin */
00412       n->next->prev = NULL;
00413     }
00414   }
00415   else if (n == rn->tail)
00416   {
00417     rn->tail = n->prev;
00418     if (n->prev != NULL)
00419     {
00420       /* not last node, new list end */
00421       n->prev->next = NULL;
00422     }
00423   }
00424   else
00425   {
00426     /* node must be in the middle */
00427     n->prev->next = n->next;
00428     n->next->prev = n->prev;
00429   }
00430   LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));
00431   snmp_mib_ln_free(n);
00432   if (rn->count == 0)
00433   {
00434     rn->head = NULL;
00435     rn->tail = NULL;
00436   }
00437   return next;
00438 }
00439 
00440 
00441 
00442 /**
00443  * Searches tree for the supplied (scalar?) object identifier.
00444  *
00445  * @param node points to the root of the tree ('.internet')
00446  * @param ident_len the length of the supplied object identifier
00447  * @param ident points to the array of sub identifiers
00448  * @param np points to the found object instance (return)
00449  * @return pointer to the requested parent (!) node if success, NULL otherwise
00450  */
00451 struct mib_node *
00452 snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)
00453 {
00454   u8_t node_type, ext_level;
00455 
00456   ext_level = 0;
00457   LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));
00458   while (node != NULL)
00459   {
00460     node_type = node->node_type;
00461     if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
00462     {
00463       struct mib_array_node *an;
00464       u16_t i;
00465 
00466       if (ident_len > 0)
00467       {
00468         /* array node (internal ROM or RAM, fixed length) */
00469         an = (struct mib_array_node *)node;
00470         i = 0;
00471         while ((i < an->maxlength) && (an->objid[i] != *ident))
00472         {
00473           i++;
00474         }
00475         if (i < an->maxlength)
00476         {
00477           /* found it, if available proceed to child, otherwise inspect leaf */
00478           LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
00479           if (an->nptr[i] == NULL)
00480           {
00481             /* a scalar leaf OR table,
00482                inspect remaining instance number / table index */
00483             np->ident_len = ident_len;
00484             np->ident = ident;
00485             return (struct mib_node*)an;
00486           }
00487           else
00488           {
00489             /* follow next child pointer */
00490             ident++;
00491             ident_len--;
00492             node = an->nptr[i];
00493           }
00494         }
00495         else
00496         {
00497           /* search failed, identifier mismatch (nosuchname) */
00498           LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));
00499           return NULL;
00500         }
00501       }
00502       else
00503       {
00504         /* search failed, short object identifier (nosuchname) */
00505         LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));
00506         return NULL;
00507       }
00508     }
00509     else if(node_type == MIB_NODE_LR)
00510     {
00511       struct mib_list_rootnode *lrn;
00512       struct mib_list_node *ln;
00513 
00514       if (ident_len > 0)
00515       {
00516         /* list root node (internal 'RAM', variable length) */
00517         lrn = (struct mib_list_rootnode *)node;
00518         ln = lrn->head;
00519         /* iterate over list, head to tail */
00520         while ((ln != NULL) && (ln->objid != *ident))
00521         {
00522           ln = ln->next;
00523         }
00524         if (ln != NULL)
00525         {
00526           /* found it, proceed to child */;
00527           LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
00528           if (ln->nptr == NULL)
00529           {
00530             np->ident_len = ident_len;
00531             np->ident = ident;
00532             return (struct mib_node*)lrn;
00533           }
00534           else
00535           {
00536             /* follow next child pointer */
00537             ident_len--;
00538             ident++;
00539             node = ln->nptr;
00540           }
00541         }
00542         else
00543         {
00544           /* search failed */
00545           LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));
00546           return NULL;
00547         }
00548       }
00549       else
00550       {
00551         /* search failed, short object identifier (nosuchname) */
00552         LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));
00553         return NULL;
00554       }
00555     }
00556     else if(node_type == MIB_NODE_EX)
00557     {
00558       struct mib_external_node *en;
00559       u16_t i, len;
00560 
00561       if (ident_len > 0)
00562       {
00563         /* external node (addressing and access via functions) */
00564         en = (struct mib_external_node *)node;
00565 
00566         i = 0;
00567         len = en->level_length(en->addr_inf,ext_level);
00568         while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))
00569         {
00570           i++;
00571         }
00572         if (i < len)
00573         {
00574           s32_t debug_id;
00575 
00576           en->get_objid(en->addr_inf,ext_level,i,&debug_id);
00577           LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));
00578           if ((ext_level + 1) == en->tree_levels)
00579           {
00580             np->ident_len = ident_len;
00581             np->ident = ident;
00582             return (struct mib_node*)en;
00583           }
00584           else
00585           {
00586             /* found it, proceed to child */
00587             ident_len--;
00588             ident++;
00589             ext_level++;
00590           }
00591         }
00592         else
00593         {
00594           /* search failed */
00595           LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));
00596           return NULL;
00597         }
00598       }
00599       else
00600       {
00601         /* search failed, short object identifier (nosuchname) */
00602         LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));
00603         return NULL;
00604       }
00605     }
00606     else if (node_type == MIB_NODE_SC)
00607     {
00608       mib_scalar_node *sn;
00609 
00610       sn = (mib_scalar_node *)node;
00611       if ((ident_len == 1) && (*ident == 0))
00612       {
00613         np->ident_len = ident_len;
00614         np->ident = ident;
00615         return (struct mib_node*)sn;
00616       }
00617       else
00618       {
00619         /* search failed, short object identifier (nosuchname) */
00620         LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));
00621         return NULL;
00622       }
00623     }
00624     else
00625     {
00626       /* unknown node_type */
00627       LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));
00628       return NULL;
00629     }
00630   }
00631   /* done, found nothing */
00632   LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));
00633   return NULL;
00634 }
00635 
00636 /**
00637  * Test table for presence of at least one table entry.
00638  */
00639 static u8_t
00640 empty_table(struct mib_node *node)
00641 {
00642   u8_t node_type;
00643   u8_t empty = 0;
00644 
00645   if (node != NULL)
00646   {
00647     node_type = node->node_type;
00648     if (node_type == MIB_NODE_LR)
00649     {
00650       struct mib_list_rootnode *lrn;
00651       lrn = (struct mib_list_rootnode *)node;
00652       if ((lrn->count == 0) || (lrn->head == NULL))
00653       {
00654         empty = 1;
00655       }
00656     }
00657     else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
00658     {
00659       struct mib_array_node *an;
00660       an = (struct mib_array_node *)node;
00661       if ((an->maxlength == 0) || (an->nptr == NULL))
00662       {
00663         empty = 1;
00664       }
00665     }
00666     else if (node_type == MIB_NODE_EX)
00667     {
00668       struct mib_external_node *en;
00669       en = (struct mib_external_node *)node;
00670       if (en->tree_levels == 0)
00671       {
00672         empty = 1;
00673       }
00674     }
00675   }
00676   return empty;
00677 }
00678 
00679 /**
00680  * Tree expansion.
00681  */
00682 struct mib_node *
00683 snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
00684 {
00685   u8_t node_type, ext_level, climb_tree;
00686 
00687   ext_level = 0;
00688   /* reset node stack */
00689   node_stack_cnt = 0;
00690   while (node != NULL)
00691   {
00692     climb_tree = 0;
00693     node_type = node->node_type;
00694     if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
00695     {
00696       struct mib_array_node *an;
00697       u16_t i;
00698 
00699       /* array node (internal ROM or RAM, fixed length) */
00700       an = (struct mib_array_node *)node;
00701       if (ident_len > 0)
00702       {
00703         i = 0;
00704         while ((i < an->maxlength) && (an->objid[i] < *ident))
00705         {
00706           i++;
00707         }
00708         if (i < an->maxlength)
00709         {
00710           LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
00711           /* add identifier to oidret */
00712           oidret->id[oidret->len] = an->objid[i];
00713           (oidret->len)++;
00714 
00715           if (an->nptr[i] == NULL)
00716           {
00717             LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
00718             /* leaf node (e.g. in a fixed size table) */
00719             if (an->objid[i] > *ident)
00720             {
00721               return (struct mib_node*)an;
00722             }
00723             else if ((i + 1) < an->maxlength)
00724             {
00725               /* an->objid[i] == *ident */
00726               (oidret->len)--;
00727               oidret->id[oidret->len] = an->objid[i + 1];
00728               (oidret->len)++;
00729               return (struct mib_node*)an;
00730             }
00731             else
00732             {
00733               /* (i + 1) == an->maxlength */
00734               (oidret->len)--;
00735               climb_tree = 1;
00736             }
00737           }
00738           else
00739           {
00740             u8_t j;
00741             struct nse cur_node;
00742 
00743             LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
00744             /* non-leaf, store right child ptr and id */
00745             LWIP_ASSERT("i < 0xff", i < 0xff);
00746             j = (u8_t)i + 1;
00747             while ((j < an->maxlength) && (empty_table(an->nptr[j])))
00748             {
00749               j++;
00750             }
00751             if (j < an->maxlength)
00752             {
00753               cur_node.r_ptr = an->nptr[j];
00754               cur_node.r_id = an->objid[j];
00755               cur_node.r_nl = 0;
00756             }
00757             else
00758             {
00759               cur_node.r_ptr = NULL;
00760             }
00761             push_node(&cur_node);
00762             if (an->objid[i] == *ident)
00763             {
00764               ident_len--;
00765               ident++;
00766             }
00767             else
00768             {
00769               /* an->objid[i] < *ident */
00770               ident_len = 0;
00771             }
00772             /* follow next child pointer */
00773             node = an->nptr[i];
00774           }
00775         }
00776         else
00777         {
00778           /* i == an->maxlength */
00779           climb_tree = 1;
00780         }
00781       }
00782       else
00783       {
00784         u8_t j;
00785         /* ident_len == 0, complete with leftmost '.thing' */
00786         j = 0;
00787         while ((j < an->maxlength) && empty_table(an->nptr[j]))
00788         {
00789           j++;
00790         }
00791         if (j < an->maxlength)
00792         {
00793           LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));
00794           oidret->id[oidret->len] = an->objid[j];
00795           (oidret->len)++;
00796           if (an->nptr[j] == NULL)
00797           {
00798             /* leaf node */
00799             return (struct mib_node*)an;
00800           }
00801           else
00802           {
00803             /* no leaf, continue */
00804             node = an->nptr[j];
00805           }
00806         }
00807         else
00808         {
00809           /* j == an->maxlength */
00810           climb_tree = 1;
00811         }
00812       }
00813     }
00814     else if(node_type == MIB_NODE_LR)
00815     {
00816       struct mib_list_rootnode *lrn;
00817       struct mib_list_node *ln;
00818 
00819       /* list root node (internal 'RAM', variable length) */
00820       lrn = (struct mib_list_rootnode *)node;
00821       if (ident_len > 0)
00822       {
00823         ln = lrn->head;
00824         /* iterate over list, head to tail */
00825         while ((ln != NULL) && (ln->objid < *ident))
00826         {
00827           ln = ln->next;
00828         }
00829         if (ln != NULL)
00830         {
00831           LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
00832           oidret->id[oidret->len] = ln->objid;
00833           (oidret->len)++;
00834           if (ln->nptr == NULL)
00835           {
00836             /* leaf node */
00837             if (ln->objid > *ident)
00838             {
00839               return (struct mib_node*)lrn;
00840             }
00841             else if (ln->next != NULL)
00842             {
00843               /* ln->objid == *ident */
00844               (oidret->len)--;
00845               oidret->id[oidret->len] = ln->next->objid;
00846               (oidret->len)++;
00847               return (struct mib_node*)lrn;
00848             }
00849             else
00850             {
00851               /* ln->next == NULL */
00852               (oidret->len)--;
00853               climb_tree = 1;
00854             }
00855           }
00856           else
00857           {
00858             struct mib_list_node *jn;
00859             struct nse cur_node;
00860 
00861             /* non-leaf, store right child ptr and id */
00862             jn = ln->next;
00863             while ((jn != NULL) && empty_table(jn->nptr))
00864             {
00865               jn = jn->next;
00866             }
00867             if (jn != NULL)
00868             {
00869               cur_node.r_ptr = jn->nptr;
00870               cur_node.r_id = jn->objid;
00871               cur_node.r_nl = 0;
00872             }
00873             else
00874             {
00875               cur_node.r_ptr = NULL;
00876             }
00877             push_node(&cur_node);
00878             if (ln->objid == *ident)
00879             {
00880               ident_len--;
00881               ident++;
00882             }
00883             else
00884             {
00885               /* ln->objid < *ident */
00886               ident_len = 0;
00887             }
00888             /* follow next child pointer */
00889             node = ln->nptr;
00890           }
00891 
00892         }
00893         else
00894         {
00895           /* ln == NULL */
00896           climb_tree = 1;
00897         }
00898       }
00899       else
00900       {
00901         struct mib_list_node *jn;
00902         /* ident_len == 0, complete with leftmost '.thing' */
00903         jn = lrn->head;
00904         while ((jn != NULL) && empty_table(jn->nptr))
00905         {
00906           jn = jn->next;
00907         }
00908         if (jn != NULL)
00909         {
00910           LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));
00911           oidret->id[oidret->len] = jn->objid;
00912           (oidret->len)++;
00913           if (jn->nptr == NULL)
00914           {
00915             /* leaf node */
00916             LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));
00917             return (struct mib_node*)lrn;
00918           }
00919           else
00920           {
00921             /* no leaf, continue */
00922             node = jn->nptr;
00923           }
00924         }
00925         else
00926         {
00927           /* jn == NULL */
00928           climb_tree = 1;
00929         }
00930       }
00931     }
00932     else if(node_type == MIB_NODE_EX)
00933     {
00934       struct mib_external_node *en;
00935       s32_t ex_id;
00936 
00937       /* external node (addressing and access via functions) */
00938       en = (struct mib_external_node *)node;
00939       if (ident_len > 0)
00940       {
00941         u16_t i, len;
00942 
00943         i = 0;
00944         len = en->level_length(en->addr_inf,ext_level);
00945         while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))
00946         {
00947           i++;
00948         }
00949         if (i < len)
00950         {
00951           /* add identifier to oidret */
00952           en->get_objid(en->addr_inf,ext_level,i,&ex_id);
00953           LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));
00954           oidret->id[oidret->len] = ex_id;
00955           (oidret->len)++;
00956 
00957           if ((ext_level + 1) == en->tree_levels)
00958           {
00959             LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
00960             /* leaf node */
00961             if (ex_id > *ident)
00962             {
00963               return (struct mib_node*)en;
00964             }
00965             else if ((i + 1) < len)
00966             {
00967               /* ex_id == *ident */
00968               en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);
00969               (oidret->len)--;
00970               oidret->id[oidret->len] = ex_id;
00971               (oidret->len)++;
00972               return (struct mib_node*)en;
00973             }
00974             else
00975             {
00976               /* (i + 1) == len */
00977               (oidret->len)--;
00978               climb_tree = 1;
00979             }
00980           }
00981           else
00982           {
00983             u8_t j;
00984             struct nse cur_node;
00985 
00986             LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
00987             /* non-leaf, store right child ptr and id */
00988             LWIP_ASSERT("i < 0xff", i < 0xff);
00989             j = (u8_t)i + 1;
00990             if (j < len)
00991             {
00992               /* right node is the current external node */
00993               cur_node.r_ptr = node;
00994               en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);
00995               cur_node.r_nl = ext_level + 1;
00996             }
00997             else
00998             {
00999               cur_node.r_ptr = NULL;
01000             }
01001             push_node(&cur_node);
01002             if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)
01003             {
01004               ident_len--;
01005               ident++;
01006             }
01007             else
01008             {
01009               /* external id < *ident */
01010               ident_len = 0;
01011             }
01012             /* proceed to child */
01013             ext_level++;
01014           }
01015         }
01016         else
01017         {
01018           /* i == len (en->level_len()) */
01019           climb_tree = 1;
01020         }
01021       }
01022       else
01023       {
01024         /* ident_len == 0, complete with leftmost '.thing' */
01025         en->get_objid(en->addr_inf,ext_level,0,&ex_id);
01026         LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));
01027         oidret->id[oidret->len] = ex_id;
01028         (oidret->len)++;
01029         if ((ext_level + 1) == en->tree_levels)
01030         {
01031           /* leaf node */
01032           LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));
01033           return (struct mib_node*)en;
01034         }
01035         else
01036         {
01037           /* no leaf, proceed to child */
01038           ext_level++;
01039         }
01040       }
01041     }
01042     else if(node_type == MIB_NODE_SC)
01043     {
01044       mib_scalar_node *sn;
01045 
01046       /* scalar node  */
01047       sn = (mib_scalar_node *)node;
01048       if (ident_len > 0)
01049       {
01050         /* at .0 */
01051         climb_tree = 1;
01052       }
01053       else
01054       {
01055         /* ident_len == 0, complete object identifier */
01056         oidret->id[oidret->len] = 0;
01057         (oidret->len)++;
01058         /* leaf node */
01059         LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));
01060         return (struct mib_node*)sn;
01061       }
01062     }
01063     else
01064     {
01065       /* unknown/unhandled node_type */
01066       LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));
01067       return NULL;
01068     }
01069 
01070     if (climb_tree)
01071     {
01072       struct nse child;
01073 
01074       /* find right child ptr */
01075       child.r_ptr = NULL;
01076       child.r_id = 0;
01077       child.r_nl = 0;
01078       while ((node_stack_cnt > 0) && (child.r_ptr == NULL))
01079       {
01080         pop_node(&child);
01081         /* trim returned oid */
01082         (oidret->len)--;
01083       }
01084       if (child.r_ptr != NULL)
01085       {
01086         /* incoming ident is useless beyond this point */
01087         ident_len = 0;
01088         oidret->id[oidret->len] = child.r_id;
01089         oidret->len++;
01090         node = child.r_ptr;
01091         ext_level = child.r_nl;
01092       }
01093       else
01094       {
01095         /* tree ends here ... */
01096         LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));
01097         return NULL;
01098       }
01099     }
01100   }
01101   /* done, found nothing */
01102   LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));
01103   return NULL;
01104 }
01105 
01106 /**
01107  * Test object identifier for the iso.org.dod.internet prefix.
01108  *
01109  * @param ident_len the length of the supplied object identifier
01110  * @param ident points to the array of sub identifiers
01111  * @return 1 if it matches, 0 otherwise
01112  */
01113 u8_t
01114 snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)
01115 {
01116   if ((ident_len > 3) &&
01117       (ident[0] == 1) && (ident[1] == 3) &&
01118       (ident[2] == 6) && (ident[3] == 1))
01119   {
01120     return 1;
01121   }
01122   else
01123   {
01124     return 0;
01125   }
01126 }
01127 
01128 /**
01129  * Expands object identifier to the iso.org.dod.internet
01130  * prefix for use in getnext operation.
01131  *
01132  * @param ident_len the length of the supplied object identifier
01133  * @param ident points to the array of sub identifiers
01134  * @param oidret points to returned expanded object identifier
01135  * @return 1 if it matches, 0 otherwise
01136  *
01137  * @note ident_len 0 is allowed, expanding to the first known object id!!
01138  */
01139 u8_t
01140 snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
01141 {
01142   const s32_t *prefix_ptr;
01143   s32_t *ret_ptr;
01144   u8_t i;
01145 
01146   i = 0;
01147   prefix_ptr = &prefix[0];
01148   ret_ptr = &oidret->id[0];
01149   ident_len = ((ident_len < 4)?ident_len:4);
01150   while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))
01151   {
01152     *ret_ptr++ = *prefix_ptr++;
01153     ident++;
01154     i++;
01155   }
01156   if (i == ident_len)
01157   {
01158     /* match, complete missing bits */
01159     while (i < 4)
01160     {
01161       *ret_ptr++ = *prefix_ptr++;
01162       i++;
01163     }
01164     oidret->len = i;
01165     return 1;
01166   }
01167   else
01168   {
01169     /* i != ident_len */
01170     return 0;
01171   }
01172 }
01173 
01174 #endif /* LWIP_SNMP */