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