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