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