static int agentx_open(void) { struct x_pdu_buf x_pdu; const char *descr = "SmartSNMP AgentX sub-agent"; /* Send agentX open PDU */ x_pdu = agentx_open_pdu(&agentx_datagram, NULL, 0, descr, strlen(descr)); if (send(agentx_datagram.sock, x_pdu.buf, x_pdu.len, 0) == -1) { SMARTSNMP_LOG(L_ERROR, "Send agentX open PDU failure!\n"); return -1; } /* Receive agentX open response PDU */ x_pdu.len = TRANS_BUF_SIZ; x_pdu.buf = xrealloc(x_pdu.buf, x_pdu.len); x_pdu.len = recv(agentx_datagram.sock, x_pdu.buf, x_pdu.len, 0); if (x_pdu.len == -1) { SMARTSNMP_LOG(L_ERROR, "Receive agentX open response PDU failure!\n"); return -1; } /* Verify open response PDU */ if (agentx_recv(x_pdu.buf, x_pdu.len) != AGENTX_ERR_OK) { SMARTSNMP_LOG(L_ERROR, "Parse agentX open response PDU error!\n"); return -1; } return 0; }
static int agentx_close(void) { struct x_pdu_buf x_pdu; /* Send agentX close PDU */ x_pdu = agentx_close_pdu(&agentx_datagram, R_SHUTDOWN); if (send(agentx_datagram.sock, x_pdu.buf, x_pdu.len, 0) == -1) { SMARTSNMP_LOG(L_ERROR, "Send agentX close PDU failure!\n"); return -1; } /* Receive agentX close response PDU */ x_pdu.len = TRANS_BUF_SIZ; x_pdu.buf = xrealloc(x_pdu.buf, x_pdu.len); x_pdu.len = recv(agentx_datagram.sock, x_pdu.buf, x_pdu.len, 0); if (x_pdu.len == -1) { SMARTSNMP_LOG(L_ERROR, "Receive agentX close response PDU failure!\n"); return -1; } /* Verify close response PDU */ if (agentx_recv(x_pdu.buf, x_pdu.len) != AGENTX_ERR_OK) { SMARTSNMP_LOG(L_ERROR, "Parse agentX close response PDU error!\n"); return -1; } return 0; }
/* Register one instance node in mib-tree according to given oid with lua callback. */ int mib_node_reg(const oid_t *oid, uint32_t len, int callback) { int i; struct mib_instance_node *in; assert(oid != NULL); mib_tree_init_check(); /* Prefix must match root oid */ if (len == 0) { SMARTSNMP_LOG(L_WARNING, "The register group node oid cannot be empty\n"); return -1; } if (len > MIB_OID_MAX_LEN) { SMARTSNMP_LOG(L_WARNING, "The register group oid cannot be longer than %d\n", MIB_OID_MAX_LEN); return -1; } in = mib_tree_instance_insert(oid, len, callback); if (in == NULL) { SMARTSNMP_LOG(L_WARNING, "Register group node oid: "); for (i = 0; i < len; i++) { SMARTSNMP_LOG(L_WARNING, "%d ", oid[i]); } SMARTSNMP_LOG(L_WARNING, "fail, node already exists or oid overlaps.\n"); return -1; } return 0; }
/* Decode agentx datagram */ static AGENTX_ERR_CODE_E agentx_decode(struct agentx_datagram *xdg) { AGENTX_ERR_CODE_E err; uint8_t *buf, dec_fail = 0; buf = xdg->recv_buf; /* PDU header */ err = pdu_hdr_parse(xdg, &buf); if (err) { SMARTSNMP_LOG(L_ERROR, "ERR(%d): %s\n", err, error_message(agentx_err_msg, elem_num(agentx_err_msg), err)); dec_fail = 1; goto DECODE_FINISH; } /* varbind or search range */ switch (xdg->pdu_hdr.type) { case AGENTX_PDU_GET: case AGENTX_PDU_GETNEXT: case AGENTX_PDU_GETBULK: /* search range */ err = search_range_parse(xdg, &buf); if (err) { SMARTSNMP_LOG(L_ERROR, "ERR(%d): %s\n", err, error_message(agentx_err_msg, elem_num(agentx_err_msg), err)); dec_fail = 1; } break; case AGENTX_PDU_TESTSET: case AGENTX_PDU_RESPONSE: /* var bind */ err = var_bind_parse(xdg, &buf); if (err) { SMARTSNMP_LOG(L_ERROR, "ERR(%d): %s\n", err, error_message(agentx_err_msg, elem_num(agentx_err_msg), err)); dec_fail = 1; } break; default: break; } DECODE_FINISH: /* If fail, do some clear things */ if (dec_fail) { agentx_datagram_clear(xdg); } /* We should free received buf here */ free(xdg->recv_buf); return err; }
/* Parse search range */ static AGENTX_ERR_CODE_E search_range_parse(struct agentx_datagram *xdg, uint8_t **buffer) { AGENTX_ERR_CODE_E err; uint8_t *buf; err = AGENTX_ERR_OK; buf = *buffer; while (xdg->pdu_hdr.payload_length > 0) { /* Alloc a new search range and add into search range list. */ struct x_search_range *sr = search_range_alloc(&buf, xdg->pdu_hdr.flags, &err); if (sr == NULL) { SMARTSNMP_LOG(L_ERROR, "ERR(%d): %s\n", err, error_message(agentx_err_msg, elem_num(agentx_err_msg), err)); *buffer = buf; break; } list_add_tail(&sr->link, &xdg->sr_in_list); xdg->sr_in_cnt++; xdg->pdu_hdr.payload_length -= buf - *buffer; *buffer = buf; } return err; }
/* Parse varbind */ static AGENTX_ERR_CODE_E var_bind_parse(struct agentx_datagram *xdg, uint8_t **buffer) { AGENTX_ERR_CODE_E err; uint8_t *buf; err = AGENTX_ERR_OK; buf = *buffer; while (xdg->pdu_hdr.payload_length > 0) { /* Alloc a new var_bind and add into var_bind list. */ struct x_var_bind *vb = var_bind_alloc(&buf, xdg->pdu_hdr.flags, &err); if (vb == NULL) { SMARTSNMP_LOG(L_ERROR, "ERR(%d): %s\n", err, error_message(agentx_err_msg, elem_num(agentx_err_msg), err)); *buffer = buf; break; } list_add_tail(&vb->link, &xdg->vb_in_list); xdg->vb_in_cnt++; xdg->pdu_hdr.payload_length -= buf - *buffer; *buffer = buf; } return err; }
/* Unregister mib group node */ static int agentx_mib_node_unreg(const oid_t *grp_id, int id_len) { struct x_pdu_buf x_pdu; /* Check oid prefix */ if (id_len < 4 || grp_id[0] != 1 || grp_id[1] != 3 || grp_id[2] != 6 || grp_id[3] != 1) { SMARTSNMP_LOG(L_ERROR, "Oid prefix must be .1.3.6.1!"); return -1; } /* Send angentX register PDU */ x_pdu = agentx_unregister_pdu(&agentx_datagram, grp_id, id_len, NULL, 0, 0, 127, 0, 0); if (send(agentx_datagram.sock, x_pdu.buf, x_pdu.len, 0) == -1) { SMARTSNMP_LOG(L_ERROR, "Send agentX unregister PDU failure!"); return -1; } /* Receive agentX response PDU */ x_pdu.len = TRANS_BUF_SIZ; x_pdu.buf = xrealloc(x_pdu.buf, x_pdu.len); x_pdu.len = recv(agentx_datagram.sock, x_pdu.buf, x_pdu.len, 0); if (x_pdu.len == -1) { SMARTSNMP_LOG(L_ERROR, "Receive agentX unregister response PDU failure!\n"); return -1; } /* Verify register response PDU */ if (agentx_recv(x_pdu.buf, x_pdu.len) != AGENTX_ERR_OK) { SMARTSNMP_LOG(L_ERROR, "Unregister response error!"); return -1; } /* Unregister node */ mib_node_unreg(grp_id, id_len); return 0; }
/* 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; } }
/* Embedded code is not funny at all... */ int mib_instance_search(struct oid_search_res *ret_oid) { int i; Variable *var = &ret_oid->var; lua_State *L = mib_lua_state; /* Empty lua stack. */ lua_pop(L, -1); /* Get function. */ lua_rawgeti(L, LUA_ENVIRONINDEX, ret_oid->callback); /* op */ lua_pushinteger(L, ret_oid->request); /* req_sub_oid */ lua_newtable(L); for (i = 0; i < ret_oid->inst_id_len; i++) { lua_pushinteger(L, ret_oid->inst_id[i]); lua_rawseti(L, -2, i + 1); } if (ret_oid->request == MIB_REQ_SET) { /* req_val */ switch (tag(var)) { case ASN1_TAG_INT: lua_pushinteger(L, integer(var)); break; case ASN1_TAG_OCTSTR: lua_pushlstring(L, octstr(var), length(var)); break; case ASN1_TAG_CNT: lua_pushnumber(L, count(var)); break; case ASN1_TAG_IPADDR: lua_pushlstring(L, (char *)ipaddr(var), length(var)); break; case ASN1_TAG_OBJID: lua_newtable(L); for (i = 0; i < length(var); i++) { lua_pushnumber(L, oid(var)[i]); lua_rawseti(L, -2, i + 1); } break; case ASN1_TAG_GAU: lua_pushnumber(L, gauge(var)); break; case ASN1_TAG_TIMETICKS: lua_pushnumber(L, timeticks(var)); break; default: lua_pushnil(L); break; } /* req_val_type */ lua_pushinteger(L, tag(var)); } else { /* req_val */ lua_pushnil(L); /* req_val_type */ lua_pushnil(L); } if (lua_pcall(L, 4, 4, 0) != 0) { SMARTSNMP_LOG(L_ERROR, "MIB search hander %d fail: %s\n", ret_oid->callback, lua_tostring(L, -1)); tag(var) = ASN1_TAG_NO_SUCH_OBJ; return 0; } ret_oid->err_stat = lua_tointeger(L, -4); tag(var) = lua_tonumber(L, -1); if (!ret_oid->err_stat && MIB_TAG_VALID(tag(var))) { /* Return value */ if (ret_oid->request != MIB_REQ_SET) { switch (tag(var)) { case ASN1_TAG_INT: length(var) = 1; integer(var) = lua_tointeger(L, -2); break; case ASN1_TAG_OCTSTR: length(var) = lua_objlen(L, -2); memcpy(octstr(var), lua_tostring(L, -2), length(var)); break; case ASN1_TAG_CNT: length(var) = 1; count(var) = lua_tonumber(L, -2); break; case ASN1_TAG_IPADDR: length(var) = lua_objlen(L, -2); for (i = 0; i < length(var); i++) { lua_rawgeti(L, -2, i + 1); ipaddr(var)[i] = lua_tointeger(L, -1); lua_pop(L, 1); } break; case ASN1_TAG_OBJID: length(var) = lua_objlen(L, -2); for (i = 0; i < length(var); i++) { lua_rawgeti(L, -2, i + 1); oid(var)[i] = lua_tointeger(L, -1); lua_pop(L, 1); } break; case ASN1_TAG_GAU: length(var) = 1; gauge(var) = lua_tonumber(L, -2); break; case ASN1_TAG_TIMETICKS: length(var) = 1; timeticks(var) = lua_tonumber(L, -2); break; default: assert(0); } } /* For GETNEXT request, return the new oid */ if (ret_oid->request == MIB_REQ_GETNEXT) { ret_oid->inst_id_len = lua_objlen(L, -3); for (i = 0; i < ret_oid->inst_id_len; i++) { lua_rawgeti(L, -3, i + 1); ret_oid->inst_id[i] = lua_tointeger(L, -1); lua_pop(L, 1); } } } return ret_oid->err_stat; }
/* Remove sub-node(s) in mib-tree. */ static void __mib_tree_delete(struct node_pair *pair) { struct node_backlog *p_nbl; struct node_backlog nbl_stack[ASN1_OID_MAX_LEN]; struct node_backlog *top; 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; top = nbl_stack; for (; ;) { if (node != NULL) switch (node->type) { case MIB_OBJ_GROUP: gn = (struct mib_group_node *)node; /* Fetch the sub-id of the backlogged node. */ int i = p_nbl != NULL ? p_nbl->n_idx : 0; /* n_idx is not reusable */ p_nbl = NULL; if (i == -1) { /* Sub-tree is empty, delete this node and go on backtracking */ mib_group_node_delete(gn); break; } /* If last sub-id, mark n_idx = -1. */ top->n_idx = i + 1 >= gn->sub_id_cnt ? -1 : i + 1; top->node = node; top++; 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 = top == nbl_stack ? NULL : --top; if (p_nbl == NULL) { /* End of traversal. */ group_node_shrink((struct mib_group_node *)pair->parent, pair->sub_idx); return; } node = p_nbl->node; } }