/* Init dummy root node */ static void mib_dummy_node_init(void) { const oid_t dummy_oid[] = { 1, 3, 6, 1 }; root_oid = xmalloc(elem_num(dummy_oid) * sizeof(oid_t)); oid_cpy(root_oid, dummy_oid, elem_num(dummy_oid)); root_oid_len = elem_num(dummy_oid); mib_dummy_node.type = MIB_OBJ_GROUP; mib_dummy_node.sub_id_cap = 1; mib_dummy_node.sub_id_cnt = 0; mib_dummy_node.sub_id = xmalloc(sizeof(oid_t)); mib_dummy_node.sub_id[0] = 0; mib_dummy_node.sub_ptr = xmalloc(sizeof(void *)); mib_dummy_node.sub_ptr[0] = NULL; }
/* 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. */ } }
/* 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; }