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