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