Home | History | Annotate | Download | only in snmp
      1 /**
      2  * @file
      3  * MIB tree access/construction functions.
      4  */
      5 
      6 /*
      7  * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.
      8  * All rights reserved.
      9  *
     10  * Redistribution and use in source and binary forms, with or without modification,
     11  * are permitted provided that the following conditions are met:
     12  *
     13  * 1. Redistributions of source code must retain the above copyright notice,
     14  *    this list of conditions and the following disclaimer.
     15  * 2. Redistributions in binary form must reproduce the above copyright notice,
     16  *    this list of conditions and the following disclaimer in the documentation
     17  *    and/or other materials provided with the distribution.
     18  * 3. The name of the author may not be used to endorse or promote products
     19  *    derived from this software without specific prior written permission.
     20  *
     21  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
     22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
     24  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     25  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
     26  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     29  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
     30  * OF SUCH DAMAGE.
     31  *
     32  * Author: Christiaan Simons <christiaan.simons (at) axon.tv>
     33  */
     34 
     35 #include "lwip/opt.h"
     36 
     37 #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */
     38 
     39 #include "lwip/snmp_structs.h"
     40 #include "lwip/memp.h"
     41 #include "lwip/netif.h"
     42 
     43 /** .iso.org.dod.internet address prefix, @see snmp_iso_*() */
     44 const s32_t prefix[4] = {1, 3, 6, 1};
     45 
     46 #define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)
     47 /** node stack entry (old news?) */
     48 struct nse
     49 {
     50   /** right child */
     51   struct mib_node* r_ptr;
     52   /** right child identifier */
     53   s32_t r_id;
     54   /** right child next level */
     55   u8_t r_nl;
     56 };
     57 static u8_t node_stack_cnt;
     58 static struct nse node_stack[NODE_STACK_SIZE];
     59 
     60 /**
     61  * Pushes nse struct onto stack.
     62  */
     63 static void
     64 push_node(struct nse* node)
     65 {
     66   LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);
     67   LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));
     68   if (node_stack_cnt < NODE_STACK_SIZE)
     69   {
     70     node_stack[node_stack_cnt] = *node;
     71     node_stack_cnt++;
     72   }
     73 }
     74 
     75 /**
     76  * Pops nse struct from stack.
     77  */
     78 static void
     79 pop_node(struct nse* node)
     80 {
     81   if (node_stack_cnt > 0)
     82   {
     83     node_stack_cnt--;
     84     *node = node_stack[node_stack_cnt];
     85   }
     86   LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));
     87 }
     88 
     89 /**
     90  * Conversion from ifIndex to lwIP netif
     91  * @param ifindex is a s32_t object sub-identifier
     92  * @param netif points to returned netif struct pointer
     93  */
     94 void
     95 snmp_ifindextonetif(s32_t ifindex, struct netif **netif)
     96 {
     97   struct netif *nif = netif_list;
     98   s32_t i, ifidx;
     99 
    100   ifidx = ifindex - 1;
    101   i = 0;
    102   while ((nif != NULL) && (i < ifidx))
    103   {
    104     nif = nif->next;
    105     i++;
    106   }
    107   *netif = nif;
    108 }
    109 
    110 /**
    111  * Conversion from lwIP netif to ifIndex
    112  * @param netif points to a netif struct
    113  * @param ifidx points to s32_t object sub-identifier
    114  */
    115 void
    116 snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
    117 {
    118   struct netif *nif = netif_list;
    119   u16_t i;
    120 
    121   i = 0;
    122   while ((nif != NULL) && (nif != netif))
    123   {
    124     nif = nif->next;
    125     i++;
    126   }
    127   *ifidx = i+1;
    128 }
    129 
    130 /**
    131  * Conversion from oid to lwIP ip_addr
    132  * @param ident points to s32_t ident[4] input
    133  * @param ip points to output struct
    134  */
    135 void
    136 snmp_oidtoip(s32_t *ident, ip_addr_t *ip)
    137 {
    138   IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]);
    139 }
    140 
    141 /**
    142  * Conversion from lwIP ip_addr to oid
    143  * @param ip points to input struct
    144  * @param ident points to s32_t ident[4] output
    145  */
    146 void
    147 snmp_iptooid(ip_addr_t *ip, s32_t *ident)
    148 {
    149   ident[0] = ip4_addr1(ip);
    150   ident[1] = ip4_addr2(ip);
    151   ident[2] = ip4_addr3(ip);
    152   ident[3] = ip4_addr4(ip);
    153 }
    154 
    155 struct mib_list_node *
    156 snmp_mib_ln_alloc(s32_t id)
    157 {
    158   struct mib_list_node *ln;
    159 
    160   ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE);
    161   if (ln != NULL)
    162   {
    163     ln->prev = NULL;
    164     ln->next = NULL;
    165     ln->objid = id;
    166     ln->nptr = NULL;
    167   }
    168   return ln;
    169 }
    170 
    171 void
    172 snmp_mib_ln_free(struct mib_list_node *ln)
    173 {
    174   memp_free(MEMP_SNMP_NODE, ln);
    175 }
    176 
    177 struct mib_list_rootnode *
    178 snmp_mib_lrn_alloc(void)
    179 {
    180   struct mib_list_rootnode *lrn;
    181 
    182   lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE);
    183   if (lrn != NULL)
    184   {
    185     lrn->get_object_def = noleafs_get_object_def;
    186     lrn->get_value = noleafs_get_value;
    187     lrn->set_test = noleafs_set_test;
    188     lrn->set_value = noleafs_set_value;
    189     lrn->node_type = MIB_NODE_LR;
    190     lrn->maxlength = 0;
    191     lrn->head = NULL;
    192     lrn->tail = NULL;
    193     lrn->count = 0;
    194   }
    195   return lrn;
    196 }
    197 
    198 void
    199 snmp_mib_lrn_free(struct mib_list_rootnode *lrn)
    200 {
    201   memp_free(MEMP_SNMP_ROOTNODE, lrn);
    202 }
    203 
    204 /**
    205  * Inserts node in idx list in a sorted
    206  * (ascending order) fashion and
    207  * allocates the node if needed.
    208  *
    209  * @param rn points to the root node
    210  * @param objid is the object sub identifier
    211  * @param insn points to a pointer to the inserted node
    212  *   used for constructing the tree.
    213  * @return -1 if failed, 1 if inserted, 2 if present.
    214  */
    215 s8_t
    216 snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)
    217 {
    218   struct mib_list_node *nn;
    219   s8_t insert;
    220 
    221   LWIP_ASSERT("rn != NULL",rn != NULL);
    222 
    223   /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */
    224   insert = 0;
    225   if (rn->head == NULL)
    226   {
    227     /* empty list, add first node */
    228     LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));
    229     nn = snmp_mib_ln_alloc(objid);
    230     if (nn != NULL)
    231     {
    232       rn->head = nn;
    233       rn->tail = nn;
    234       *insn = nn;
    235       insert = 1;
    236     }
    237     else
    238     {
    239       insert = -1;
    240     }
    241   }
    242   else
    243   {
    244     struct mib_list_node *n;
    245     /* at least one node is present */
    246     n = rn->head;
    247     while ((n != NULL) && (insert == 0))
    248     {
    249       if (n->objid == objid)
    250       {
    251         /* node is already there */
    252         LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));
    253         *insn = n;
    254         insert = 2;
    255       }
    256       else if (n->objid < objid)
    257       {
    258         if (n->next == NULL)
    259         {
    260           /* alloc and insert at the tail */
    261           LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));
    262           nn = snmp_mib_ln_alloc(objid);
    263           if (nn != NULL)
    264           {
    265             nn->next = NULL;
    266             nn->prev = n;
    267             n->next = nn;
    268             rn->tail = nn;
    269             *insn = nn;
    270             insert = 1;
    271           }
    272           else
    273           {
    274             /* insertion failure */
    275             insert = -1;
    276           }
    277         }
    278         else
    279         {
    280           /* there's more to explore: traverse list */
    281           LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));
    282           n = n->next;
    283         }
    284       }
    285       else
    286       {
    287         /* n->objid > objid */
    288         /* alloc and insert between n->prev and n */
    289         LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));
    290         nn = snmp_mib_ln_alloc(objid);
    291         if (nn != NULL)
    292         {
    293           if (n->prev == NULL)
    294           {
    295             /* insert at the head */
    296             nn->next = n;
    297             nn->prev = NULL;
    298             rn->head = nn;
    299             n->prev = nn;
    300           }
    301           else
    302           {
    303             /* insert in the middle */
    304             nn->next = n;
    305             nn->prev = n->prev;
    306             n->prev->next = nn;
    307             n->prev = nn;
    308           }
    309           *insn = nn;
    310           insert = 1;
    311         }
    312         else
    313         {
    314           /* insertion failure */
    315           insert = -1;
    316         }
    317       }
    318     }
    319   }
    320   if (insert == 1)
    321   {
    322     rn->count += 1;
    323   }
    324   LWIP_ASSERT("insert != 0",insert != 0);
    325   return insert;
    326 }
    327 
    328 /**
    329  * Finds node in idx list and returns deletion mark.
    330  *
    331  * @param rn points to the root node
    332  * @param objid  is the object sub identifier
    333  * @param fn returns pointer to found node
    334  * @return 0 if not found, 1 if deletable,
    335  *   2 can't delete (2 or more children), 3 not a list_node
    336  */
    337 s8_t
    338 snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)
    339 {
    340   s8_t fc;
    341   struct mib_list_node *n;
    342 
    343   LWIP_ASSERT("rn != NULL",rn != NULL);
    344   n = rn->head;
    345   while ((n != NULL) && (n->objid != objid))
    346   {
    347     n = n->next;
    348   }
    349   if (n == NULL)
    350   {
    351     fc = 0;
    352   }
    353   else if (n->nptr == NULL)
    354   {
    355     /* leaf, can delete node */
    356     fc = 1;
    357   }
    358   else
    359   {
    360     struct mib_list_rootnode *r;
    361 
    362     if (n->nptr->node_type == MIB_NODE_LR)
    363     {
    364       r = (struct mib_list_rootnode *)n->nptr;
    365       if (r->count > 1)
    366       {
    367         /* can't delete node */
    368         fc = 2;
    369       }
    370       else
    371       {
    372         /* count <= 1, can delete node */
    373         fc = 1;
    374       }
    375     }
    376     else
    377     {
    378       /* other node type */
    379       fc = 3;
    380     }
    381   }
    382   *fn = n;
    383   return fc;
    384 }
    385 
    386 /**
    387  * Removes node from idx list
    388  * if it has a single child left.
    389  *
    390  * @param rn points to the root node
    391  * @param n points to the node to delete
    392  * @return the nptr to be freed by caller
    393  */
    394 struct mib_list_rootnode *
    395 snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)
    396 {
    397   struct mib_list_rootnode *next;
    398 
    399   LWIP_ASSERT("rn != NULL",rn != NULL);
    400   LWIP_ASSERT("n != NULL",n != NULL);
    401 
    402   /* caller must remove this sub-tree */
    403   next = (struct mib_list_rootnode*)(n->nptr);
    404   rn->count -= 1;
    405 
    406   if (n == rn->head)
    407   {
    408     rn->head = n->next;
    409     if (n->next != NULL)
    410     {
    411       /* not last node, new list begin */
    412       n->next->prev = NULL;
    413     }
    414   }
    415   else if (n == rn->tail)
    416   {
    417     rn->tail = n->prev;
    418     if (n->prev != NULL)
    419     {
    420       /* not last node, new list end */
    421       n->prev->next = NULL;
    422     }
    423   }
    424   else
    425   {
    426     /* node must be in the middle */
    427     n->prev->next = n->next;
    428     n->next->prev = n->prev;
    429   }
    430   LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));
    431   snmp_mib_ln_free(n);
    432   if (rn->count == 0)
    433   {
    434     rn->head = NULL;
    435     rn->tail = NULL;
    436   }
    437   return next;
    438 }
    439 
    440 
    441 
    442 /**
    443  * Searches tree for the supplied (scalar?) object identifier.
    444  *
    445  * @param node points to the root of the tree ('.internet')
    446  * @param ident_len the length of the supplied object identifier
    447  * @param ident points to the array of sub identifiers
    448  * @param np points to the found object instance (return)
    449  * @return pointer to the requested parent (!) node if success, NULL otherwise
    450  */
    451 struct mib_node *
    452 snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)
    453 {
    454   u8_t node_type, ext_level;
    455 
    456   ext_level = 0;
    457   LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));
    458   while (node != NULL)
    459   {
    460     node_type = node->node_type;
    461     if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
    462     {
    463       struct mib_array_node *an;
    464       u16_t i;
    465 
    466       if (ident_len > 0)
    467       {
    468         /* array node (internal ROM or RAM, fixed length) */
    469         an = (struct mib_array_node *)node;
    470         i = 0;
    471         while ((i < an->maxlength) && (an->objid[i] != *ident))
    472         {
    473           i++;
    474         }
    475         if (i < an->maxlength)
    476         {
    477           /* found it, if available proceed to child, otherwise inspect leaf */
    478           LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
    479           if (an->nptr[i] == NULL)
    480           {
    481             /* a scalar leaf OR table,
    482                inspect remaining instance number / table index */
    483             np->ident_len = ident_len;
    484             np->ident = ident;
    485             return (struct mib_node*)an;
    486           }
    487           else
    488           {
    489             /* follow next child pointer */
    490             ident++;
    491             ident_len--;
    492             node = an->nptr[i];
    493           }
    494         }
    495         else
    496         {
    497           /* search failed, identifier mismatch (nosuchname) */
    498           LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));
    499           return NULL;
    500         }
    501       }
    502       else
    503       {
    504         /* search failed, short object identifier (nosuchname) */
    505         LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));
    506         return NULL;
    507       }
    508     }
    509     else if(node_type == MIB_NODE_LR)
    510     {
    511       struct mib_list_rootnode *lrn;
    512       struct mib_list_node *ln;
    513 
    514       if (ident_len > 0)
    515       {
    516         /* list root node (internal 'RAM', variable length) */
    517         lrn = (struct mib_list_rootnode *)node;
    518         ln = lrn->head;
    519         /* iterate over list, head to tail */
    520         while ((ln != NULL) && (ln->objid != *ident))
    521         {
    522           ln = ln->next;
    523         }
    524         if (ln != NULL)
    525         {
    526           /* found it, proceed to child */;
    527           LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
    528           if (ln->nptr == NULL)
    529           {
    530             np->ident_len = ident_len;
    531             np->ident = ident;
    532             return (struct mib_node*)lrn;
    533           }
    534           else
    535           {
    536             /* follow next child pointer */
    537             ident_len--;
    538             ident++;
    539             node = ln->nptr;
    540           }
    541         }
    542         else
    543         {
    544           /* search failed */
    545           LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));
    546           return NULL;
    547         }
    548       }
    549       else
    550       {
    551         /* search failed, short object identifier (nosuchname) */
    552         LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));
    553         return NULL;
    554       }
    555     }
    556     else if(node_type == MIB_NODE_EX)
    557     {
    558       struct mib_external_node *en;
    559       u16_t i, len;
    560 
    561       if (ident_len > 0)
    562       {
    563         /* external node (addressing and access via functions) */
    564         en = (struct mib_external_node *)node;
    565 
    566         i = 0;
    567         len = en->level_length(en->addr_inf,ext_level);
    568         while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))
    569         {
    570           i++;
    571         }
    572         if (i < len)
    573         {
    574           s32_t debug_id;
    575 
    576           en->get_objid(en->addr_inf,ext_level,i,&debug_id);
    577           LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));
    578           if ((ext_level + 1) == en->tree_levels)
    579           {
    580             np->ident_len = ident_len;
    581             np->ident = ident;
    582             return (struct mib_node*)en;
    583           }
    584           else
    585           {
    586             /* found it, proceed to child */
    587             ident_len--;
    588             ident++;
    589             ext_level++;
    590           }
    591         }
    592         else
    593         {
    594           /* search failed */
    595           LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));
    596           return NULL;
    597         }
    598       }
    599       else
    600       {
    601         /* search failed, short object identifier (nosuchname) */
    602         LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));
    603         return NULL;
    604       }
    605     }
    606     else if (node_type == MIB_NODE_SC)
    607     {
    608       mib_scalar_node *sn;
    609 
    610       sn = (mib_scalar_node *)node;
    611       if ((ident_len == 1) && (*ident == 0))
    612       {
    613         np->ident_len = ident_len;
    614         np->ident = ident;
    615         return (struct mib_node*)sn;
    616       }
    617       else
    618       {
    619         /* search failed, short object identifier (nosuchname) */
    620         LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));
    621         return NULL;
    622       }
    623     }
    624     else
    625     {
    626       /* unknown node_type */
    627       LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));
    628       return NULL;
    629     }
    630   }
    631   /* done, found nothing */
    632   LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));
    633   return NULL;
    634 }
    635 
    636 /**
    637  * Test table for presence of at least one table entry.
    638  */
    639 static u8_t
    640 empty_table(struct mib_node *node)
    641 {
    642   u8_t node_type;
    643   u8_t empty = 0;
    644 
    645   if (node != NULL)
    646   {
    647     node_type = node->node_type;
    648     if (node_type == MIB_NODE_LR)
    649     {
    650       struct mib_list_rootnode *lrn;
    651       lrn = (struct mib_list_rootnode *)node;
    652       if ((lrn->count == 0) || (lrn->head == NULL))
    653       {
    654         empty = 1;
    655       }
    656     }
    657     else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
    658     {
    659       struct mib_array_node *an;
    660       an = (struct mib_array_node *)node;
    661       if ((an->maxlength == 0) || (an->nptr == NULL))
    662       {
    663         empty = 1;
    664       }
    665     }
    666     else if (node_type == MIB_NODE_EX)
    667     {
    668       struct mib_external_node *en;
    669       en = (struct mib_external_node *)node;
    670       if (en->tree_levels == 0)
    671       {
    672         empty = 1;
    673       }
    674     }
    675   }
    676   return empty;
    677 }
    678 
    679 /**
    680  * Tree expansion.
    681  */
    682 struct mib_node *
    683 snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
    684 {
    685   u8_t node_type, ext_level, climb_tree;
    686 
    687   ext_level = 0;
    688   /* reset node stack */
    689   node_stack_cnt = 0;
    690   while (node != NULL)
    691   {
    692     climb_tree = 0;
    693     node_type = node->node_type;
    694     if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))
    695     {
    696       struct mib_array_node *an;
    697       u16_t i;
    698 
    699       /* array node (internal ROM or RAM, fixed length) */
    700       an = (struct mib_array_node *)node;
    701       if (ident_len > 0)
    702       {
    703         i = 0;
    704         while ((i < an->maxlength) && (an->objid[i] < *ident))
    705         {
    706           i++;
    707         }
    708         if (i < an->maxlength)
    709         {
    710           LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));
    711           /* add identifier to oidret */
    712           oidret->id[oidret->len] = an->objid[i];
    713           (oidret->len)++;
    714 
    715           if (an->nptr[i] == NULL)
    716           {
    717             LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
    718             /* leaf node (e.g. in a fixed size table) */
    719             if (an->objid[i] > *ident)
    720             {
    721               return (struct mib_node*)an;
    722             }
    723             else if ((i + 1) < an->maxlength)
    724             {
    725               /* an->objid[i] == *ident */
    726               (oidret->len)--;
    727               oidret->id[oidret->len] = an->objid[i + 1];
    728               (oidret->len)++;
    729               return (struct mib_node*)an;
    730             }
    731             else
    732             {
    733               /* (i + 1) == an->maxlength */
    734               (oidret->len)--;
    735               climb_tree = 1;
    736             }
    737           }
    738           else
    739           {
    740             u8_t j;
    741             struct nse cur_node;
    742 
    743             LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
    744             /* non-leaf, store right child ptr and id */
    745             LWIP_ASSERT("i < 0xff", i < 0xff);
    746             j = (u8_t)i + 1;
    747             while ((j < an->maxlength) && (empty_table(an->nptr[j])))
    748             {
    749               j++;
    750             }
    751             if (j < an->maxlength)
    752             {
    753               cur_node.r_ptr = an->nptr[j];
    754               cur_node.r_id = an->objid[j];
    755               cur_node.r_nl = 0;
    756             }
    757             else
    758             {
    759               cur_node.r_ptr = NULL;
    760             }
    761             push_node(&cur_node);
    762             if (an->objid[i] == *ident)
    763             {
    764               ident_len--;
    765               ident++;
    766             }
    767             else
    768             {
    769               /* an->objid[i] < *ident */
    770               ident_len = 0;
    771             }
    772             /* follow next child pointer */
    773             node = an->nptr[i];
    774           }
    775         }
    776         else
    777         {
    778           /* i == an->maxlength */
    779           climb_tree = 1;
    780         }
    781       }
    782       else
    783       {
    784         u8_t j;
    785         /* ident_len == 0, complete with leftmost '.thing' */
    786         j = 0;
    787         while ((j < an->maxlength) && empty_table(an->nptr[j]))
    788         {
    789           j++;
    790         }
    791         if (j < an->maxlength)
    792         {
    793           LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));
    794           oidret->id[oidret->len] = an->objid[j];
    795           (oidret->len)++;
    796           if (an->nptr[j] == NULL)
    797           {
    798             /* leaf node */
    799             return (struct mib_node*)an;
    800           }
    801           else
    802           {
    803             /* no leaf, continue */
    804             node = an->nptr[j];
    805           }
    806         }
    807         else
    808         {
    809           /* j == an->maxlength */
    810           climb_tree = 1;
    811         }
    812       }
    813     }
    814     else if(node_type == MIB_NODE_LR)
    815     {
    816       struct mib_list_rootnode *lrn;
    817       struct mib_list_node *ln;
    818 
    819       /* list root node (internal 'RAM', variable length) */
    820       lrn = (struct mib_list_rootnode *)node;
    821       if (ident_len > 0)
    822       {
    823         ln = lrn->head;
    824         /* iterate over list, head to tail */
    825         while ((ln != NULL) && (ln->objid < *ident))
    826         {
    827           ln = ln->next;
    828         }
    829         if (ln != NULL)
    830         {
    831           LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));
    832           oidret->id[oidret->len] = ln->objid;
    833           (oidret->len)++;
    834           if (ln->nptr == NULL)
    835           {
    836             /* leaf node */
    837             if (ln->objid > *ident)
    838             {
    839               return (struct mib_node*)lrn;
    840             }
    841             else if (ln->next != NULL)
    842             {
    843               /* ln->objid == *ident */
    844               (oidret->len)--;
    845               oidret->id[oidret->len] = ln->next->objid;
    846               (oidret->len)++;
    847               return (struct mib_node*)lrn;
    848             }
    849             else
    850             {
    851               /* ln->next == NULL */
    852               (oidret->len)--;
    853               climb_tree = 1;
    854             }
    855           }
    856           else
    857           {
    858             struct mib_list_node *jn;
    859             struct nse cur_node;
    860 
    861             /* non-leaf, store right child ptr and id */
    862             jn = ln->next;
    863             while ((jn != NULL) && empty_table(jn->nptr))
    864             {
    865               jn = jn->next;
    866             }
    867             if (jn != NULL)
    868             {
    869               cur_node.r_ptr = jn->nptr;
    870               cur_node.r_id = jn->objid;
    871               cur_node.r_nl = 0;
    872             }
    873             else
    874             {
    875               cur_node.r_ptr = NULL;
    876             }
    877             push_node(&cur_node);
    878             if (ln->objid == *ident)
    879             {
    880               ident_len--;
    881               ident++;
    882             }
    883             else
    884             {
    885               /* ln->objid < *ident */
    886               ident_len = 0;
    887             }
    888             /* follow next child pointer */
    889             node = ln->nptr;
    890           }
    891 
    892         }
    893         else
    894         {
    895           /* ln == NULL */
    896           climb_tree = 1;
    897         }
    898       }
    899       else
    900       {
    901         struct mib_list_node *jn;
    902         /* ident_len == 0, complete with leftmost '.thing' */
    903         jn = lrn->head;
    904         while ((jn != NULL) && empty_table(jn->nptr))
    905         {
    906           jn = jn->next;
    907         }
    908         if (jn != NULL)
    909         {
    910           LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));
    911           oidret->id[oidret->len] = jn->objid;
    912           (oidret->len)++;
    913           if (jn->nptr == NULL)
    914           {
    915             /* leaf node */
    916             LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));
    917             return (struct mib_node*)lrn;
    918           }
    919           else
    920           {
    921             /* no leaf, continue */
    922             node = jn->nptr;
    923           }
    924         }
    925         else
    926         {
    927           /* jn == NULL */
    928           climb_tree = 1;
    929         }
    930       }
    931     }
    932     else if(node_type == MIB_NODE_EX)
    933     {
    934       struct mib_external_node *en;
    935       s32_t ex_id;
    936 
    937       /* external node (addressing and access via functions) */
    938       en = (struct mib_external_node *)node;
    939       if (ident_len > 0)
    940       {
    941         u16_t i, len;
    942 
    943         i = 0;
    944         len = en->level_length(en->addr_inf,ext_level);
    945         while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))
    946         {
    947           i++;
    948         }
    949         if (i < len)
    950         {
    951           /* add identifier to oidret */
    952           en->get_objid(en->addr_inf,ext_level,i,&ex_id);
    953           LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));
    954           oidret->id[oidret->len] = ex_id;
    955           (oidret->len)++;
    956 
    957           if ((ext_level + 1) == en->tree_levels)
    958           {
    959             LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));
    960             /* leaf node */
    961             if (ex_id > *ident)
    962             {
    963               return (struct mib_node*)en;
    964             }
    965             else if ((i + 1) < len)
    966             {
    967               /* ex_id == *ident */
    968               en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);
    969               (oidret->len)--;
    970               oidret->id[oidret->len] = ex_id;
    971               (oidret->len)++;
    972               return (struct mib_node*)en;
    973             }
    974             else
    975             {
    976               /* (i + 1) == len */
    977               (oidret->len)--;
    978               climb_tree = 1;
    979             }
    980           }
    981           else
    982           {
    983             u8_t j;
    984             struct nse cur_node;
    985 
    986             LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));
    987             /* non-leaf, store right child ptr and id */
    988             LWIP_ASSERT("i < 0xff", i < 0xff);
    989             j = (u8_t)i + 1;
    990             if (j < len)
    991             {
    992               /* right node is the current external node */
    993               cur_node.r_ptr = node;
    994               en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);
    995               cur_node.r_nl = ext_level + 1;
    996             }
    997             else
    998             {
    999               cur_node.r_ptr = NULL;
   1000             }
   1001             push_node(&cur_node);
   1002             if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)
   1003             {
   1004               ident_len--;
   1005               ident++;
   1006             }
   1007             else
   1008             {
   1009               /* external id < *ident */
   1010               ident_len = 0;
   1011             }
   1012             /* proceed to child */
   1013             ext_level++;
   1014           }
   1015         }
   1016         else
   1017         {
   1018           /* i == len (en->level_len()) */
   1019           climb_tree = 1;
   1020         }
   1021       }
   1022       else
   1023       {
   1024         /* ident_len == 0, complete with leftmost '.thing' */
   1025         en->get_objid(en->addr_inf,ext_level,0,&ex_id);
   1026         LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));
   1027         oidret->id[oidret->len] = ex_id;
   1028         (oidret->len)++;
   1029         if ((ext_level + 1) == en->tree_levels)
   1030         {
   1031           /* leaf node */
   1032           LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));
   1033           return (struct mib_node*)en;
   1034         }
   1035         else
   1036         {
   1037           /* no leaf, proceed to child */
   1038           ext_level++;
   1039         }
   1040       }
   1041     }
   1042     else if(node_type == MIB_NODE_SC)
   1043     {
   1044       mib_scalar_node *sn;
   1045 
   1046       /* scalar node  */
   1047       sn = (mib_scalar_node *)node;
   1048       if (ident_len > 0)
   1049       {
   1050         /* at .0 */
   1051         climb_tree = 1;
   1052       }
   1053       else
   1054       {
   1055         /* ident_len == 0, complete object identifier */
   1056         oidret->id[oidret->len] = 0;
   1057         (oidret->len)++;
   1058         /* leaf node */
   1059         LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));
   1060         return (struct mib_node*)sn;
   1061       }
   1062     }
   1063     else
   1064     {
   1065       /* unknown/unhandled node_type */
   1066       LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));
   1067       return NULL;
   1068     }
   1069 
   1070     if (climb_tree)
   1071     {
   1072       struct nse child;
   1073 
   1074       /* find right child ptr */
   1075       child.r_ptr = NULL;
   1076       child.r_id = 0;
   1077       child.r_nl = 0;
   1078       while ((node_stack_cnt > 0) && (child.r_ptr == NULL))
   1079       {
   1080         pop_node(&child);
   1081         /* trim returned oid */
   1082         (oidret->len)--;
   1083       }
   1084       if (child.r_ptr != NULL)
   1085       {
   1086         /* incoming ident is useless beyond this point */
   1087         ident_len = 0;
   1088         oidret->id[oidret->len] = child.r_id;
   1089         oidret->len++;
   1090         node = child.r_ptr;
   1091         ext_level = child.r_nl;
   1092       }
   1093       else
   1094       {
   1095         /* tree ends here ... */
   1096         LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));
   1097         return NULL;
   1098       }
   1099     }
   1100   }
   1101   /* done, found nothing */
   1102   LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));
   1103   return NULL;
   1104 }
   1105 
   1106 /**
   1107  * Test object identifier for the iso.org.dod.internet prefix.
   1108  *
   1109  * @param ident_len the length of the supplied object identifier
   1110  * @param ident points to the array of sub identifiers
   1111  * @return 1 if it matches, 0 otherwise
   1112  */
   1113 u8_t
   1114 snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)
   1115 {
   1116   if ((ident_len > 3) &&
   1117       (ident[0] == 1) && (ident[1] == 3) &&
   1118       (ident[2] == 6) && (ident[3] == 1))
   1119   {
   1120     return 1;
   1121   }
   1122   else
   1123   {
   1124     return 0;
   1125   }
   1126 }
   1127 
   1128 /**
   1129  * Expands object identifier to the iso.org.dod.internet
   1130  * prefix for use in getnext operation.
   1131  *
   1132  * @param ident_len the length of the supplied object identifier
   1133  * @param ident points to the array of sub identifiers
   1134  * @param oidret points to returned expanded object identifier
   1135  * @return 1 if it matches, 0 otherwise
   1136  *
   1137  * @note ident_len 0 is allowed, expanding to the first known object id!!
   1138  */
   1139 u8_t
   1140 snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)
   1141 {
   1142   const s32_t *prefix_ptr;
   1143   s32_t *ret_ptr;
   1144   u8_t i;
   1145 
   1146   i = 0;
   1147   prefix_ptr = &prefix[0];
   1148   ret_ptr = &oidret->id[0];
   1149   ident_len = ((ident_len < 4)?ident_len:4);
   1150   while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))
   1151   {
   1152     *ret_ptr++ = *prefix_ptr++;
   1153     ident++;
   1154     i++;
   1155   }
   1156   if (i == ident_len)
   1157   {
   1158     /* match, complete missing bits */
   1159     while (i < 4)
   1160     {
   1161       *ret_ptr++ = *prefix_ptr++;
   1162       i++;
   1163     }
   1164     oidret->len = i;
   1165     return 1;
   1166   }
   1167   else
   1168   {
   1169     /* i != ident_len */
   1170     return 0;
   1171   }
   1172 }
   1173 
   1174 #endif /* LWIP_SNMP */
   1175