/* Remove sub-node(s) in mib-tree. */ static void __mib_tree_delete(struct node_pair *pair) { struct node_backlog nbl, *p_nbl; struct node_backlog nbl_stk[MIB_OID_MAX_LEN]; struct node_backlog *stk_top, *stk_buttom; struct mib_node *node = pair->child; struct mib_group_node *gn; struct mib_instance_node *in; if (node == (struct mib_node *)&mib_dummy_node) { SMARTSNMP_LOG(L_WARNING, "MIB dummy root node cannot be deleted!\n"); return; } /* Init something */ p_nbl = NULL; stk_top = stk_buttom = nbl_stk; for (; ;) { if (node != NULL) switch (node->type) { case MIB_OBJ_GROUP: gn = (struct mib_group_node *)node; int i; if (p_nbl != NULL) { /* Fetch the sub-id next to the pop-up backlogged one. */ i = p_nbl->n_idx; p_nbl = NULL; } else { /* Fetch the first sub-id. */ i = 0; } if (i == -1) { /* Sub-tree is empty, delete this node and go on backtracking */ mib_group_node_delete(gn); break; } if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark n_idx = -1. */ nbl.n_idx = -1; } else { nbl.n_idx = i + 1; } nbl.node = node; /* Backlog the current node and move down. */ nbl_push(&nbl, &stk_top, &stk_buttom); node = gn->sub_ptr[i++]; continue; case MIB_OBJ_INSTANCE: in = (struct mib_instance_node *)node; mib_instance_node_delete(in); break; default : assert(0); } /* Backtracking */ p_nbl = nbl_pop(&stk_top, &stk_buttom); if (p_nbl == NULL) { /* End of traversal. */ group_node_shrink((struct mib_group_node *)pair->parent, pair->sub_idx); return; } node = p_nbl->node; } }
/* GETNEXT request search, depth-first traversal in mib-tree, find the closest next oid. */ void mib_tree_search_next(struct mib_view *view, const oid_t *orig_oid, uint32_t orig_id_len, struct oid_search_res *ret_oid) { oid_t *oid; uint32_t id_len; struct node_backlog nbl, *p_nbl; struct node_backlog nbl_stk[MIB_OID_MAX_LEN]; struct node_backlog *stk_top, *stk_buttom; struct mib_node *node; struct mib_group_node *gn; struct mib_instance_node *in; /* 'immediate' is the search state indicator. * 0 is to get the matched instance according to the given oid; * 1 is to get the immediate first instance regardless of the given oid. */ uint8_t immediate = 0; assert(view != NULL && orig_oid != NULL && ret_oid != NULL); /* Access control */ if (oid_cover(view->oid, view->id_len, orig_oid, orig_id_len) > 0) { /* In the range of view, search the root node at view oid */ ret_oid->request = MIB_REQ_GET; node = mib_tree_search(view, view->oid, view->id_len, ret_oid); assert(node != NULL); ret_oid->request = MIB_REQ_GETNEXT; /* Duplicate the given oid */ oid_cpy(ret_oid->oid, orig_oid, orig_id_len); ret_oid->id_len = orig_id_len; if (ret_oid->id_len > ret_oid->inst_id - ret_oid->oid) { /* Given oid is longer than the search result's, we need to search according to the given oid */ immediate = 0; } else { /* Otherwise, ignore the given oid */ immediate = 1; } } else { /* Out of range of view */ if (oid_cmp(orig_oid, orig_id_len, view->oid, view->id_len) < 0) { /* Given oid is ahead of view, search the root node at view oid */ ret_oid->request = MIB_REQ_GET; node = mib_tree_search(view, view->oid, view->id_len, ret_oid); assert(node != NULL); ret_oid->request = MIB_REQ_GETNEXT; /* Set the search mode according to node type */ if (node->type == MIB_OBJ_GROUP) { immediate = 1; } else { immediate = 0; } } else { /* END_OF_MIB_VIEW */ node = NULL; ret_oid->oid = oid_dup(view->oid, view->id_len); ret_oid->id_len = view->id_len; } } /* Init something */ p_nbl = NULL; stk_top = stk_buttom = nbl_stk; ret_oid->err_stat = 0; oid = ret_oid->inst_id; id_len = ret_oid->id_len - (oid - ret_oid->oid); for (; ;) { if (node != NULL) { switch (node->type) { case MIB_OBJ_GROUP: gn = (struct mib_group_node *)node; if (immediate) { /* Fetch the immediate instance node. */ int i; if (p_nbl != NULL) { /* Fetch the sub-id next to the pop-up backlogged one. */ i = p_nbl->n_idx; p_nbl = NULL; } else { /* Fetch the first sub-id. */ i = 0; } if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark NULL and -1. */ nbl.node = NULL; nbl.n_idx = -1; } else { nbl.node = node; nbl.n_idx = i + 1; } /* Backlog the current node and move on. */ nbl_push(&nbl, &stk_top, &stk_buttom); *oid++ = gn->sub_id[i]; node = gn->sub_ptr[i]; } else { /* Search the match sub-id */ int index = oid_binary_search(gn->sub_id, gn->sub_id_cnt, *oid); int i = index; if (index < 0) { /* Not found, switch to the immediate search mode */ immediate = 1; /* Reverse the sign to locate the right position. */ i = -i - 1; if (i == gn->sub_id_cnt) { /* All sub-ids are greater than the target; * Backtrack and fetch the next one. */ break; } else if (i == 0) { /* 1. All sub-ids are less than the target; * 2. No sub-id in this group node; * Just switch to the immediate search mode */ continue; } /* else { Target is between the two sub-ids and [i] is the next one, switch to immediate mode and move on. } */ } /* Sub-id found is greater or just equal to the target, * Anyway, record the next node and push it into stack. */ if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark NULL and -1. */ nbl.node = NULL; nbl.n_idx = -1; } else { nbl.node = node; nbl.n_idx = i + 1; } /* Backlog the current node and move on. */ nbl_push(&nbl, &stk_top, &stk_buttom); *oid++ = gn->sub_id[i]; node = gn->sub_ptr[i]; if (--id_len == 0 && node->type == MIB_OBJ_GROUP) { /* When oid length is decreased to zero, switch to the immediate mode */ immediate = 1; } } continue; /* Go on loop */ case MIB_OBJ_INSTANCE: in = (struct mib_instance_node *)node; if (immediate || id_len == 0) { /* Fetch the first instance variable */ ret_oid->inst_id_len = 0; } else { /* Search the closest instance whose oid is greater than the target */ ret_oid->inst_id_len = id_len; } /* Find instance variable through lua handler function */ ret_oid->inst_id = oid; ret_oid->callback = in->callback; ret_oid->err_stat = mib_instance_search(ret_oid); if (MIB_TAG_VALID(tag(&ret_oid->var))) { ret_oid->id_len = oid - ret_oid->oid + ret_oid->inst_id_len; assert(ret_oid->id_len <= MIB_OID_MAX_LEN); if (!oid_cover(view->oid, view->id_len, ret_oid->oid, ret_oid->id_len)) { /* End of mib view */ break; } return; } else { /* Instance not found */ break; } default: assert(0); } } /* Backtracking condition: * 1. No greater sub-id in group node; * 2. Seek the immediate closest instance node; * 3. Node not exists(node == NULL). */ p_nbl = nbl_pop(&stk_top, &stk_buttom); if (p_nbl == NULL) { /* End of traversal. */ oid_cpy(ret_oid->oid, orig_oid, orig_id_len); ret_oid->id_len = orig_id_len; ret_oid->inst_id = NULL; ret_oid->inst_id_len = 0; ret_oid->err_stat = 0; tag(&ret_oid->var) = ASN1_TAG_END_OF_MIB_VIEW; return; } oid--; /* OID length is ignored once backtracking. */ node = p_nbl->node; immediate = 1; /* Switch to the immediate search mode. */ } }
/* Remove specified node int mib-tree. */ static void __mib_tree_delete(struct node_pair *pair) { struct node_backlog nbl, *p_nbl; struct node_backlog nbl_stk[NBL_STACK_SIZE]; struct node_backlog *stk_top, *stk_buttom; struct mib_node *node = pair->child; struct mib_group_node *gn; struct mib_instance_node *in; /* Internet group is the dummy root node */ if (node == (struct mib_node *)&internet_group) { CREDO_SNMP_LOG(SNMP_LOG_WARNING, "OID .1.3.6.1 is the dummy root node in this mib tree which cannot be deleted.\n"); return; } /* Init something */ p_nbl = NULL; stk_top = stk_buttom = nbl_stk; for (; ;) { if (node != NULL) switch (node->type) { case MIB_OBJ_GROUP: gn = (struct mib_group_node *)node; int i; if (p_nbl != NULL) { /* That pop-up backlog recorded the next index. */ i = p_nbl->n_idx; p_nbl = NULL; } else { /* Else we get the first sub-id. */ i = 0; } if (i == -1) { /* All sub-trees empty, free this node and go on backtracking */ mib_group_node_delete(gn); break; } do { if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark n_idx = -1. */ nbl.n_idx = -1; } else { nbl.n_idx = i + 1; } nbl.node = node; node = gn->sub_ptr[i++]; } while (node == NULL && i < gn->sub_id_cnt); /* Backlog the current node and move down. */ nbl_push(&nbl, &stk_top, &stk_buttom); continue; case MIB_OBJ_INSTANCE: in = (struct mib_instance_node *)node; mib_instance_node_delete(in); break; default : assert(0); break; } /* Backtracking */ p_nbl = nbl_pop(&stk_top, &stk_buttom); if (p_nbl == NULL) { /* End of traversal. */ group_node_shrink((struct mib_group_node *)pair->parent, pair->sub_idx); return; } node = p_nbl->node; } }
/* GETNEXT request search, depth-first traversal in mib-tree, find the closest next oid. */ struct mib_node * mib_tree_search_next(const oid_t *orig_oid, uint32_t orig_id_len, struct oid_search_res *ret_oid) { oid_t *oid; uint32_t id_len; uint8_t immediate; /* This is the search state indicator */ struct node_backlog nbl, *p_nbl; struct node_backlog nbl_stk[MIB_OID_MAX_LEN]; struct node_backlog *stk_top, *stk_buttom; struct oid_search_res tmp_res; struct mib_node *node; struct mib_group_node *gn; struct mib_instance_node *in; /* Check dummy root oid prefix */ if (orig_id_len > root_oid_len) { immediate = 0; /* 0 is to search the first match node in mib tree. */ ret_oid->oid = oid_dup(orig_oid, orig_id_len); ret_oid->id_len = orig_id_len; if (oid_cmp(orig_oid, root_oid_len, root_oid, root_oid_len) > 0) { /* END_OF_MIB_VIEW */ node = NULL; } else { node = mib_tree_search(root_oid, root_oid_len, &tmp_res); free(tmp_res.oid); } } else { immediate = 1; /* 1 is to get the immediate closest instance */ ret_oid->oid = oid_dup(root_oid, root_oid_len); ret_oid->id_len = root_oid_len; if (oid_cmp(orig_oid, orig_id_len, root_oid, root_oid_len) > 0) { /* END_OF_MIB_VIEW */ node = NULL; } else { node = mib_tree_search(root_oid, root_oid_len, &tmp_res); free(tmp_res.oid); } } /* Init something */ p_nbl = NULL; stk_top = stk_buttom = nbl_stk; oid = ret_oid->oid + root_oid_len; id_len = ret_oid->id_len - root_oid_len; ret_oid->inst_id = NULL; ret_oid->inst_id_len = 0; ret_oid->exist_state = 0; for (; ;) { if (node != NULL) switch (node->type) { case MIB_OBJ_GROUP: gn = (struct mib_group_node *)node; if (immediate) { /* Fetch the immediate instance node. */ int i; if (p_nbl != NULL) { /* Fetch the sub-id next to the pop-up backlogged one. */ i = p_nbl->n_idx; p_nbl = NULL; } else { /* Fetch the first sub-id. */ i = 0; } if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark NULL and -1. */ nbl.node = NULL; nbl.n_idx = -1; } else { nbl.node = node; nbl.n_idx = i + 1; } /* Backlog the current node and move on. */ nbl_push(&nbl, &stk_top, &stk_buttom); *oid++ = gn->sub_id[i]; node = gn->sub_ptr[i]; } else { /* Search the match sub-id */ int index = oid_binary_search(gn->sub_id, gn->sub_id_cnt, *oid); int i = index; if (index < 0) { /* Not found, switch to the immediate search mode */ immediate = 1; /* Reverse the sign to locate the right position. */ i = -i - 1; if (i == gn->sub_id_cnt) { /* All sub-ids are greater than the target; * Backtrack and fetch the next one. */ break; } else if (i == 0) { /* 1. All sub-ids are less than the target; * 2. No sub-id in this group node; * Just switch to the immediate search mode */ continue; } /* else { Target is between the two sub-ids and [i] is the next one, switch to immediate mode and move on. } */ } /* Sub-id found is greater or just equal to the target, * Anyway, record the next node and push it into stack. */ if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark NULL and -1. */ nbl.node = NULL; nbl.n_idx = -1; } else { nbl.node = node; nbl.n_idx = i + 1; } /* Backlog the current node and move on. */ nbl_push(&nbl, &stk_top, &stk_buttom); *oid++ = gn->sub_id[i]; node = gn->sub_ptr[i]; if (--id_len == 0 && node->type == MIB_OBJ_GROUP) { /* When oid length is decreased to zero, switch to the immediate mode */ immediate = 1; } } continue; /* Go on loop */ case MIB_OBJ_INSTANCE: in = (struct mib_instance_node *)node; if (immediate || id_len == 0) { /* Fetch the first instance variable */ ret_oid->inst_id_len = 0; } else { /* Search the closest instance whose oid is greater than the target */ ret_oid->inst_id_len = id_len; } /* Find instance variable through lua handler function */ ret_oid->inst_id = oid; ret_oid->callback = in->callback; ret_oid->exist_state = mib_instance_search(ret_oid); if (ret_oid->exist_state == 0 || ret_oid->exist_state < ASN1_TAG_NO_SUCH_OBJ) { ret_oid->id_len = oid - ret_oid->oid + ret_oid->inst_id_len; assert(ret_oid->id_len <= MIB_OID_MAX_LEN); return node; } else { /* Instance not found */ break; } default: assert(0); } /* Backtracking condition: * 1. No greater sub-id in group node; * 2. Seek the immediate closest instance node; * 3. Node not exists(node == NULL). */ p_nbl = nbl_pop(&stk_top, &stk_buttom); if (p_nbl == NULL) { /* End of traversal. */ oid_cpy(ret_oid->oid, orig_oid, orig_id_len); ret_oid->id_len = orig_id_len; ret_oid->inst_id = NULL; ret_oid->inst_id_len = 0; ret_oid->exist_state = ASN1_TAG_END_OF_MIB_VIEW; return (struct mib_node *)&mib_dummy_node; } oid--; /* OID length is ignored once backtracking. */ node = p_nbl->node; immediate = 1; /* Switch to the immediate search mode. */ } assert(0); return node; }
/* GETNEXT request search, depth-first traversal in mib-tree, find the closest next oid. */ struct mib_node * mib_tree_search_next(const oid_t *orig_oid, uint32_t orig_id_len, struct oid_search_res *ret_oid) { oid_t *oid; const oid_t dummy_oid[] = { 1, 3, 6, 1 }; uint32_t id_len; uint8_t immediate; /* This is the search state machine */ struct node_backlog nbl, *p_nbl; struct node_backlog nbl_stk[NBL_STACK_SIZE]; struct node_backlog *stk_top, *stk_buttom; struct mib_node *node; struct mib_group_node *gn; struct mib_instance_node *in; /* Init something first */ stk_top = stk_buttom = nbl_stk; node = (struct mib_node *)&internet_group; p_nbl = NULL; /* Check dummy root oid prefix */ if (orig_id_len > INTERNET_PREFIX_LENGTH) { immediate = 0; /* 0 is to search the first match node in mib tree. */ ret_oid->oid = oid_dup(orig_oid, orig_id_len); ret_oid->id_len = orig_id_len; if (oid_cmp(orig_oid, OID_ARRAY_SIZE(dummy_oid), dummy_oid, OID_ARRAY_SIZE(dummy_oid)) > 0) { /* END_OF_MIB_VIEW */ oid = ret_oid->oid + orig_id_len; id_len = ret_oid->id_len - orig_id_len; node = NULL; } else { oid = ret_oid->oid + INTERNET_PREFIX_LENGTH; id_len = ret_oid->id_len - INTERNET_PREFIX_LENGTH; } } else { immediate = 1; /* 1 is to get the immediate closest instance */ if (oid_cmp(orig_oid, orig_id_len, dummy_oid, OID_ARRAY_SIZE(dummy_oid)) > 0) { /* END_OF_MIB_VIEW */ ret_oid->oid = oid_dup(orig_oid, orig_id_len); ret_oid->id_len = orig_id_len; oid = ret_oid->oid + orig_id_len; id_len = ret_oid->id_len - orig_id_len; node = NULL; } else { ret_oid->oid = oid_dup(dummy_oid, OID_ARRAY_SIZE(dummy_oid)); ret_oid->id_len = OID_ARRAY_SIZE(dummy_oid); oid = ret_oid->oid + INTERNET_PREFIX_LENGTH; id_len = ret_oid->id_len - INTERNET_PREFIX_LENGTH; } } ret_oid->inst_id = NULL; ret_oid->inst_id_len = 0; ret_oid->exist_state = 0; for (; ;) { if (node != NULL) switch (node->type) { case MIB_OBJ_GROUP: gn = (struct mib_group_node *)node; if (immediate) { /* Get the immediate closest instance. */ int i; if (p_nbl != NULL) { /* That pop-up backlog recorded the next index. */ i = p_nbl->n_idx; p_nbl = NULL; } else { /* else we fetch the immediate first sub-id. */ i = 0; } if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark NULL and -1. */ nbl.node = NULL; nbl.n_idx = -1; } else { nbl.node = node; nbl.n_idx = i + 1; } /* Backlog the current node and move on. */ nbl_push(&nbl, &stk_top, &stk_buttom); *oid++ = gn->sub_id[i]; node = gn->sub_ptr[i]; } else { /* Search the match sub-id */ int index = oid_binary_search(gn->sub_id, gn->sub_id_cnt, *oid); int i = index; if (index < 0) { /* Not found, oid matching is ignored since here */ immediate = 1; /* Reverse the sign to locate the next sub-id. */ i = -i - 1; if (i == gn->sub_id_cnt) { /* All sub-ids are greater than target; * Backtrack and get the next one. */ break; } else if (i == 0) { /* 1. All sub-ids are less than target; * 2. No sub-id in this group node; * Just switch to immediate mode */ continue; } /* else { Target is between the two sub-ids and [i] is the next one, switch to immediate mode and move on. } */ } /* Sub-id found is greater or just equal to target, * Anyway, record the next node and push it into stack. */ if (i + 1 >= gn->sub_id_cnt) { /* Last sub-id, mark NULL and -1. */ nbl.node = NULL; nbl.n_idx = -1; } else { nbl.node = node; nbl.n_idx = i + 1; } /* Backlog the current node and move on. */ nbl_push(&nbl, &stk_top, &stk_buttom); *oid++ = gn->sub_id[i]; node = gn->sub_ptr[i]; if (--id_len == 0 && node->type == MIB_OBJ_GROUP) { /* When oid length is decreased to zero, switch to the 'immediate' mode */ immediate = 1; } } continue; /* Go on loop */ case MIB_OBJ_INSTANCE: in = (struct mib_instance_node *)node; if (immediate || id_len == 0) { /* Get the first instance */ ret_oid->inst_id_len = 0; } else { /* Search the closest instance whose oid greater than target */ ret_oid->inst_id_len = id_len; } /* Find instance */ ret_oid->inst_id = oid; ret_oid->callback = in->callback; ret_oid->exist_state = mib_instance_search(ret_oid); if (ret_oid->exist_state == 0) { ret_oid->id_len = oid - ret_oid->oid + ret_oid->inst_id_len; assert(ret_oid->id_len <= MIB_OID_MAX_LEN); return node; } break; /* Instance not found */ default: assert(0); } /* Backtracking condition: * 1. No greater sub-id in group node; * 2. Seek the immediate closest instance node. * 3. Node not exists(node == NULL). */ p_nbl = nbl_pop(&stk_top, &stk_buttom); if (p_nbl == NULL) { /* End of traversal. */ ret_oid->id_len = oid - ret_oid->oid; ret_oid->inst_id = NULL; ret_oid->inst_id_len = 0; ret_oid->exist_state = BER_TAG_END_OF_MIB_VIEW; return (struct mib_node *)&internet_group; } oid--; /* OID length is ignored once backtracking. */ node = p_nbl->node; immediate = 1; /* Switch to the 'immediate' mode. */ } assert(0); return node; }