/******************************************************************** * FUNCTION clear_current_level * Clear the current level without changing it * * INPUTS: * session_cb == session control block to use *********************************************************************/ static void clear_current_level (session_cb_t *session_cb) { val_value_t *target = session_cb->config_ecurval; if (target == NULL) { return; } if (session_cb->config_estartval == NULL) { /* clear everything out */ val_free_value(session_cb->config_etree); session_cb->config_etree = NULL; session_cb->config_ecurval = NULL; return; } boolean islist = obj_is_list(target->obj); val_value_t *chval = val_get_first_child(target); val_value_t *nextval = NULL; for (; chval; chval = nextval) { nextval = val_get_next_child(chval); if (islist && obj_is_key(chval->obj)) { continue; } val_remove_child(chval); val_free_value(chval); } } /* clear_current_level */
/******************************************************************** * FUNCTION rpc_free_msg * * Free all the memory used by the specified rpc_msg_t * * INPUTS: * msg == rpc_msg_t to clean and delete * RETURNS: * none *********************************************************************/ void rpc_free_msg (rpc_msg_t *msg) { if (!msg) { return; } xml_msg_clean_hdr(&msg->mhdr); //msg->rpc_in_attrs = NULL; //msg->rpc_method = NULL; //msg->rpc_agt_state = 0; /* clean input parameter set */ if (msg->rpc_input) { val_free_value(msg->rpc_input); } //msg->rpc_user1 = NULL; //msg->rpc_user2 = NULL; //msg->rpc_filter.op_filtyp = OP_FILTER_NONE; //msg->rpc_filter.op_filter = NULL; //msg->rpc_datacb = NULL; /* clean data queue */ while (!dlq_empty(&msg->rpc_dataQ)) { val_value_t *val = (val_value_t *)dlq_deque(&msg->rpc_dataQ); val_free_value(val); } m__free(msg); } /* rpc_free_msg */
/******************************************************************** * FUNCTION mgr_cap_set_caps * * Initialize the NETCONF manager capabilities * * TEMP !!! JUST SET EVERYTHING, WILL REALLY GET FROM MGR STARTUP * * INPUTS: * none * RETURNS: * NO_ERR if all goes well *********************************************************************/ status_t mgr_cap_set_caps (void) { val_value_t *oldcaps, *newcaps; cap_list_t *oldmycaps,*newmycaps; xmlns_id_t nc_id; status_t res; res = NO_ERR; newcaps = NULL; nc_id = xmlns_nc_id(); oldcaps = mgr_caps; oldmycaps = my_mgr_caps; /* get a new cap_list */ newmycaps = cap_new_caplist(); if (!newmycaps) { res = ERR_INTERNAL_MEM; } /* get a new val_value_t cap list for manager <hello> messages */ if (res == NO_ERR) { newcaps = xml_val_new_struct(NCX_EL_CAPABILITIES, nc_id); if (!newcaps) { res = ERR_INTERNAL_MEM; } } /* add capability for NETCONF version 1.0 support */ if (res == NO_ERR) { res = cap_add_std(newmycaps, CAP_STDID_V1); if (res == NO_ERR) { res = cap_add_stdval(newcaps, CAP_STDID_V1); } } /* check the return value */ if (res != NO_ERR) { /* toss the new, put back the old */ cap_free_caplist(newmycaps); val_free_value(newcaps); my_mgr_caps = oldmycaps; mgr_caps = oldcaps; } else { /* toss the old, install the new */ if (oldmycaps) { cap_free_caplist(oldmycaps); } if (oldcaps) { val_free_value(oldcaps); } my_mgr_caps = newmycaps; mgr_caps = newcaps; } return res; } /* mgr_cap_set_caps */
/******************************************************************** * FUNCTION do_alias (local RPC) * * alias * alias def * alias def=def-value * * Handle the alias command, based on the parameter * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the alias command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_alias (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *parm; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_VAR); if (parm) { const xmlChar *varstr = VAL_STR(parm); res = handle_alias_parm(varstr, FALSE, TRUE); if (res == NO_ERR) { update_yangcli_param_change_flag (ALIASES_FILE, TRUE); } } else { /* no parameter; show all aliases */ show_aliases(); } } if (valset) { val_free_value(valset); } return res; } /* do_alias */
/******************************************************************** * FUNCTION do_unset (local RPC) * * unset def * * Handle the unset command; remove the specified alias * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the unset command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ extern status_t do_unset (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset, *parm; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { parm = val_find_child(valset, YANGCLI_MOD, NCX_EL_NAME); if (parm) { const xmlChar *varstr = VAL_STR(parm); alias_cb_t *alias = find_alias(varstr, xml_strlen(varstr)); if (alias) { dlq_remove(alias); free_alias(alias); log_info("\nDeleted alias '%s'\n", varstr); } else { res = ERR_NCX_INVALID_VALUE; log_error("\nError: unknown alias '%s'\n", varstr); } } /* else missing parameter already reported */ } /* else no valset already reported */ if (valset) { val_free_value(valset); } return res; } /* do_unset */
/******************************************************************** * FUNCTION do_end (local RPC) * * Handle the end command; end an if or while block * * end * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_end (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset; status_t res; res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (valset == NULL) { if (res != ERR_NCX_SKIPPED) { return res; } } else { val_free_value(valset); return ERR_NCX_INVALID_VALUE; } res = runstack_handle_end(server_cb->runstack_context); return res; } /* do_end */
/******************************************************************** * FUNCTION rpc_err_free_info * * Clean and free an rpc_err_info_t struct * * INPUTS: * errinfo == rpc_err_info_t struct to clean and free * RETURNS: * none *********************************************************************/ void rpc_err_free_info (rpc_err_info_t *errinfo) { #ifdef DEBUG if (!errinfo) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif if (errinfo->badns) { m__free(errinfo->badns); } if (errinfo->dname) { m__free(errinfo->dname); } if (errinfo->dval) { m__free(errinfo->dval); } switch (errinfo->val_btype) { case NCX_BT_ANY: case NCX_BT_CONTAINER: case NCX_BT_CHOICE: case NCX_BT_LIST: if (errinfo->v.cpxval) { val_free_value((val_value_t *)errinfo->v.cpxval); } break; default: ; } m__free(errinfo); } /* rpc_err_free_info */
/******************************************************************** * FUNCTION do_exit (local RPC) * * exit * * Exit the configuration mode * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_exit (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { status_t res = NO_ERR; val_value_t *valset = get_valset(server_cb, rpc, &line[len], &res); if (valset && res == NO_ERR) { ; } if (res == NO_ERR || res == ERR_NCX_SKIPPED) { session_cb_t *session_cb = server_cb->cur_session_cb; if (!session_cb->config_mode) { log_error("\nError: configure mode is not active\n"); res = ERR_NCX_OPERATION_FAILED; } else { exit_config_mode(session_cb); } } if (valset) { val_free_value(valset); } return res; } /* do_exit */
/******************************************************************** * FUNCTION clear_one_level * Clear the current level for the ecurptr * The exit command was given so backing up top the * parent of the config_ecurptr * * INPUTS: * session_cb == session control block to use *********************************************************************/ static void clear_one_level (session_cb_t *session_cb) { val_value_t *target = session_cb->config_ecurval; if (target == NULL) { return; } val_value_t *parent = target->parent; if (session_cb->config_estartval == target) { session_cb->config_estartval = NULL; } if (parent) { val_remove_child(target); } val_free_value(target); session_cb->config_ecurval = parent; if (parent == NULL) { session_cb->config_etree = NULL; session_cb->config_estartval = NULL; } } /* clear_one_level */
/******************************************************************** * FUNCTION y_simple_list_test_get_counter_invoke * * RPC invocation phase * All constraints have passed at this point. * Call device instrumentation code in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_simple_list_test_get_counter_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *countVal; xmlChar countBuff[100]; /* remove the next line if scb is used */ (void)scb; /* remove the next line if msg is used */ (void)msg; /* remove the next line if methnode is used */ (void)methnode; /* invoke your device instrumentation code here */ snprintf((char *)countBuff, sizeof(countBuff), "%u", count_static); countVal = val_make_string(0, (xmlChar*)"count", countBuff); if (countVal == NULL) { val_free_value(countVal); return ERR_INTERNAL_MEM; } dlq_enque(countVal, &msg->rpc_dataQ); msg->rpc_data_type = RPC_DATA_STD; return res; } /* y_simple_list_test_get_counter_invoke */
/******************************************************************** * FUNCTION do_release_locks (local RPC) * * release all the locks on the server * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the history command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_release_locks (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { ses_cb_t *scb; val_value_t *valset; uint32 locks_timeout, retry_interval; boolean cleanup, done, needed; status_t res; if (!server_cb->locks_active) { log_error("\nError: locks are not active"); return ERR_NCX_OPERATION_FAILED; } scb = mgr_ses_get_scb(server_cb->mysid); if (scb == NULL) { log_error("\nError: active session dropped, cannot lock"); return ERR_NCX_OPERATION_FAILED; } locks_timeout = server_cb->locks_timeout; retry_interval = server_cb->locks_retry_interval; cleanup = TRUE; res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR || res == ERR_NCX_SKIPPED) { /* start the auto-unlock procedure */ server_cb->locks_timeout = locks_timeout; server_cb->locks_retry_interval = retry_interval; server_cb->locks_cleanup = cleanup; needed = setup_unlock_cbs(server_cb); if (LOGINFO && needed) { log_info("\nSending <unlock> operations for release-locks...\n"); } if (needed) { done = FALSE; res = handle_release_locks_request_to_server(server_cb, TRUE, &done); if (done) { /* need to close the session or report fatal error */ clear_lock_cbs(server_cb); } } } if (valset != NULL) { val_free_value(valset); } return res; } /* do_release_locks */
/******************************************************************** * FUNCTION agt_cli_cleanup * * Cleanup the module static data * *********************************************************************/ void agt_cli_cleanup (void) { if (cli_val) { val_free_value(cli_val); cli_val = NULL; } } /* agt_cli_cleanup */
/******************************************************************** * FUNCTION get_my_session_invoke * * get-my-session : invoke params callback * * INPUTS: * see rpc/agt_rpc.h * RETURNS: * status *********************************************************************/ static status_t get_my_session_invoke (ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { val_value_t *indentval, *linesizeval, *withdefval; xmlChar numbuff[NCX_MAX_NUMLEN]; (void)methnode; snprintf((char *)numbuff, sizeof(numbuff), "%u", scb->indent); indentval = val_make_string(mysesmod->nsid, NCX_EL_INDENT, numbuff); if (indentval == NULL) { return ERR_INTERNAL_MEM; } snprintf((char *)numbuff, sizeof(numbuff), "%u", scb->linesize); linesizeval = val_make_string(mysesmod->nsid, NCX_EL_LINESIZE, numbuff); if (linesizeval == NULL) { val_free_value(indentval); return ERR_INTERNAL_MEM; } withdefval = val_make_string(mysesmod->nsid, NCX_EL_WITH_DEFAULTS, ncx_get_withdefaults_string(scb->withdef)); if (withdefval == NULL) { val_free_value(indentval); val_free_value(linesizeval); return ERR_INTERNAL_MEM; } dlq_enque(indentval, &msg->rpc_dataQ); dlq_enque(linesizeval, &msg->rpc_dataQ); dlq_enque(withdefval, &msg->rpc_dataQ); msg->rpc_data_type = RPC_DATA_YANG; return NO_ERR; } /* get_my_session_invoke */
/******************************************************************** * FUNCTION process_exit * (config mode input received) * Handle the exit command based on the current mode * * INPUTS: * server_cb == server control block to use * session_cb == session control block to use * RETURNS: * status *********************************************************************/ static status_t process_exit (server_cb_t *server_cb, session_cb_t *session_cb) { /*** TBD: add warning about edits pending ***/ status_t res = NO_ERR; /* exit to previous level or root or out of config mode */ if (session_cb->config_curobj) { /* check if edits are applied when the mode is exited */ if (session_cb->config_edit_mode == CFG_EDITMODE_LEVEL) { if (session_cb->config_etree) { /* there may be an edit to apply */ if (!session_cb->config_edit_dirty || dlq_count(&session_cb->config_editQ) == 0) { /* entered mode and then exited without adding any * edits so try adding the container or list */ res = add_edit(session_cb); } //clear_one_level(session_cb); } if (res == NO_ERR) { res = process_apply(server_cb, session_cb); } } /* get parent of current object */ session_cb->config_curobj = obj_get_real_parent(session_cb->config_curobj); if (!session_cb->config_curobj || obj_is_root(session_cb->config_curobj)) { /* exit to root-level, stay in config mode */ session_cb->config_curobj = NULL; session_cb->config_ecurval = NULL; val_free_value(session_cb->config_etree); session_cb->config_etree = NULL; } else if (session_cb->config_ecurval) { clear_one_level(session_cb); } } else { /* no current object so exit config mode */ exit_config_mode(session_cb); } return res; } /* process_exit */
/******************************************************************** * FUNCTION clean_undorec * * Clean all the memory used by the specified agt_cfg_undo_rec_t * but do not free the struct itself * * !!! The caller must free internal pointers that were malloced * !!! instead of copied. This function does not check them!!! * * INPUTS: * undo == agt_cfg_undo_rec_t to clean * reuse == TRUE if possible reuse * FALSE if this node is being freed right now * * RETURNS: * none *********************************************************************/ static void clean_undorec (agt_cfg_undo_rec_t *undo, boolean reuse) { if (undo->free_curnode && undo->curnode) { val_free_value(undo->curnode); } if (undo->curnode_clone) { val_free_value(undo->curnode_clone); } if (undo->newnode_marker) { val_free_value(undo->newnode_marker); } if (undo->curnode_marker) { val_free_value(undo->curnode_marker); } /* really expecting the extra_deleteQ to be empty at this point */ while (!dlq_empty(&undo->extra_deleteQ)) { agt_cfg_nodeptr_t *nodeptr = (agt_cfg_nodeptr_t *) dlq_deque(&undo->extra_deleteQ); if (nodeptr && nodeptr->node) { val_remove_child(nodeptr->node); val_free_value(nodeptr->node); } else { SET_ERROR(ERR_INTERNAL_VAL); } agt_cfg_free_nodeptr(nodeptr); } if (reuse) { agt_cfg_init_undorec(undo); } } /* clean_undorec */
/******************************************************************** * FUNCTION agt_cap_cleanup * * Clean the NETCONF agent capabilities * * INPUTS: * none * RETURNS: * none *********************************************************************/ void agt_cap_cleanup (void) { if (agt_caps) { val_free_value(agt_caps); agt_caps = NULL; } if (my_agt_caps) { cap_clean_caplist(my_agt_caps); m__free(my_agt_caps); my_agt_caps = NULL; } } /* agt_cap_cleanup */
/******************************************************************** * FUNCTION mgr_cap_cleanup * * Clean the NETCONF manager capabilities * * INPUTS: * none * RETURNS: * none *********************************************************************/ void mgr_cap_cleanup (void) { if (mgr_caps) { val_free_value(mgr_caps); mgr_caps = NULL; } if (my_mgr_caps) { cap_clean_caplist(my_mgr_caps); m__free(my_mgr_caps); my_mgr_caps = NULL; } } /* mgr_cap_cleanup */
/******************************************************************** * FUNCTION mgr_not_free_msg * * Free a mgr_not_msg_t struct * * INPUTS: * msg == struct to free * * RETURNS: * none *********************************************************************/ void mgr_not_free_msg (mgr_not_msg_t *msg) { #ifdef DEBUG if (!msg) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif if (msg->notification) { val_free_value(msg->notification); } m__free(msg); } /* mgr_not_free_msg */
/******************************************************************** * FUNCTION mgr_rpc_free_reply * * Free a mgr_rpc_rpy_t struct * * INPUTS: * rpy == struct to free * * RETURNS: * none *********************************************************************/ void mgr_rpc_free_reply (mgr_rpc_rpy_t *rpy) { #ifdef DEBUG if (!rpy) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif if (rpy->msg_id) { m__free(rpy->msg_id); } if (rpy->reply) { val_free_value(rpy->reply); } m__free(rpy); } /* mgr_rpc_free_reply */
/******************************************************************** * FUNCTION mgr_rpc_free_request * * Free a mgr_rpc_req_t struct * * INPUTS: * req == struct to free * * RETURNS: * none *********************************************************************/ void mgr_rpc_free_request (mgr_rpc_req_t *req) { #ifdef DEBUG if (!req) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif if (req->msg_id) { m__free(req->msg_id); } xml_clean_attrs(&req->attrs); if (req->data) { val_free_value(req->data); } m__free(req); } /* mgr_rpc_free_request */
/******************************************************************** * FUNCTION add_edit * (config mode input received) * Add an edit to the server config_editQ * * INPUTS: * session_cb == session control block to use * * RETURNS: * status *********************************************************************/ static status_t add_edit (session_cb_t *session_cb) { if (session_cb->config_etree) { op_editop_t delop = get_del_op(session_cb); op_editop_t op = (session_cb->config_no_active) ? delop : OP_EDITOP_MERGE; val_value_t *clone = val_clone(session_cb->config_etree); if (clone == NULL) { return ERR_INTERNAL_MEM; } config_edit_t *edit = new_config_edit(op, clone); if (edit == NULL) { val_free_value(clone); return ERR_INTERNAL_MEM; } session_cb->config_edit_dirty = TRUE; dlq_enque(edit, &session_cb->config_editQ); } return NO_ERR; } /* add_edit */
/******************************************************************** * FUNCTION do_config (local RPC) * * config term * * Enter the configuration mode * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the show command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_config (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { status_t res = NO_ERR; val_value_t *valset = get_valset(server_cb, rpc, &line[len], &res); if (valset && res == NO_ERR) { /* check if the 'brief' flag is set first */ val_value_t *parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_TERM); if (!parm || parm->res != NO_ERR) { log_error("\nError: 'terminal' parameter invalid\n"); if (parm) { res = parm->res; } else { res = ERR_NCX_MISSING_PARM; } } else { session_cb_t *session_cb = server_cb->cur_session_cb; if (session_cb->config_mode) { log_error("\nError: configure mode already active\n"); res = ERR_NCX_IN_USE; } else { res = start_config_mode(server_cb, session_cb); } } } if (valset) { val_free_value(valset); } return res; } /* do_config */
/******************************************************************** * FUNCTION exit_config_mode * * Exit the configuration mode * * INPUTS: * session_cb == session control block to use * *********************************************************************/ static void exit_config_mode (session_cb_t *session_cb) { session_cb->config_mode = FALSE; session_cb->config_no_active = FALSE; session_cb->config_edit_dirty = FALSE; session_cb->alt_names = session_cb->config_alt_names; session_cb->match_names = session_cb->config_match_names; m__free(session_cb->config_path); session_cb->config_path = NULL; session_cb->config_curval = NULL; session_cb->config_curobj = NULL; session_cb->config_curkey = NULL; val_free_value(session_cb->config_etree); session_cb->config_etree = NULL; session_cb->config_ecurval = NULL; while (!dlq_empty(&session_cb->config_editQ)) { config_edit_t *edit = (config_edit_t *) dlq_deque(&session_cb->config_editQ); free_config_edit(edit); } } /* exit_config_mode */
/******************************************************************** * FUNCTION mgr_cap_get_ses_capsval * * Get the NETCONF manager capabilities ain val_value_t format * for a specific session, v2 supports base1.0 and/or base1.1 * INPUTS: * scb == session control block to use * RETURNS: * MALLOCED pointer to the manager caps list to use * and then discard with val_free_value *********************************************************************/ val_value_t * mgr_cap_get_ses_capsval (ses_cb_t *scb) { val_value_t *newcaps; xmlns_id_t nc_id; status_t res; nc_id = xmlns_nc_id(); res = NO_ERR; /* get a new val_value_t cap list for manager <hello> messages */ newcaps = xml_val_new_struct(NCX_EL_CAPABILITIES, nc_id); if (newcaps == NULL) { return NULL; } /* add capability for NETCONF version 1.0 support */ if (ses_protocol_requested(scb, NCX_PROTO_NETCONF10)) { res = cap_add_stdval(newcaps, CAP_STDID_V1); } /* add capability for NETCONF version 1.1 support */ if (res == NO_ERR && ses_protocol_requested(scb, NCX_PROTO_NETCONF11)) { res = cap_add_stdval(newcaps, CAP_STDID_V11); } /* check the return value */ if (res != NO_ERR) { val_free_value(newcaps); newcaps = NULL; } return newcaps;; } /* mgr_cap_get_ses_capsval */
/******************************************************************** * FUNCTION send_discard_changes_pdu_to_server * * Send a <discard-changes> operation to the server * * INPUTS: * server_cb == server control block to use * * RETURNS: * status *********************************************************************/ status_t send_discard_changes_pdu_to_server (server_cb_t *server_cb) { obj_template_t *rpc; mgr_rpc_req_t *req; val_value_t *reqdata; ses_cb_t *scb; status_t res; xmlns_id_t obj_nsid; req = NULL; reqdata = NULL; res = NO_ERR; if (LOGDEBUG) { log_debug("\nSending <discard-changes> request"); } rpc = ncx_find_object(get_netconf_mod(server_cb), NCX_EL_DISCARD_CHANGES); if (!rpc) { return SET_ERROR(ERR_NCX_DEF_NOT_FOUND); } obj_nsid = obj_get_nsid(rpc); /* construct a method node */ reqdata = xml_val_new_flag(obj_get_name(rpc), obj_nsid); if (!reqdata) { log_error("\nError allocating a new RPC request"); return ERR_INTERNAL_MEM; } scb = mgr_ses_get_scb(server_cb->mysid); if (!scb) { res = SET_ERROR(ERR_INTERNAL_PTR); } else { req = mgr_rpc_new_request(scb); if (!req) { res = ERR_INTERNAL_MEM; log_error("\nError allocating a new RPC request"); } else { req->data = reqdata; req->rpc = rpc; req->timeout = server_cb->timeout; } } /* if all OK, send the RPC request */ if (res == NO_ERR) { if (LOGDEBUG2) { log_debug2("\nabout to send RPC request with reqdata:"); val_dump_value_max(reqdata, 0, server_cb->defindent, DUMP_VAL_LOG, server_cb->display_mode, FALSE, FALSE); } /* the request will be stored if this returns NO_ERR */ res = mgr_rpc_send_request(scb, req, yangcli_reply_handler); if (res == NO_ERR) { server_cb->command_mode = CMD_MODE_AUTODISCARD; } } /* cleanup and set next state */ if (res != NO_ERR) { if (req) { mgr_rpc_free_request(req); } else if (reqdata) { val_free_value(reqdata); } } else { server_cb->state = MGR_IO_ST_CONN_RPYWAIT; } return res; } /* send_discard_changes_pdu_to_server */
/******************************************************************** * FUNCTION do_get_locks (local RPC) * * get all the locks on the server * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the history command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_get_locks (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { ses_cb_t *scb; val_value_t *valset, *parm; uint32 locks_timeout, retry_interval; boolean cleanup, done; status_t res; if (server_cb->locks_active) { log_error("\nError: locks are already active"); return ERR_NCX_OPERATION_FAILED; } if (server_cb->state != MGR_IO_ST_CONN_IDLE) { log_error("\nError: no active session to lock"); return ERR_NCX_OPERATION_FAILED; } scb = mgr_ses_get_scb(server_cb->mysid); if (scb == NULL) { log_error("\nError: active session dropped, cannot lock"); return ERR_NCX_OPERATION_FAILED; } locks_timeout = server_cb->locks_timeout; retry_interval = server_cb->locks_retry_interval; cleanup = TRUE; res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (valset && res == NO_ERR) { /* get the overall lock timeout */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOCK_TIMEOUT); if (parm && parm->res == NO_ERR) { locks_timeout = VAL_UINT(parm); } /* get the retry interval between failed locks */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_RETRY_INTERVAL); if (parm && parm->res == NO_ERR) { retry_interval = VAL_UINT(parm); } /* get the auto-cleanup flag */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_CLEANUP); if (parm && parm->res == NO_ERR) { cleanup = VAL_BOOL(parm); } } /* start the auto-lock procedure */ setup_lock_cbs(server_cb); server_cb->locks_timeout = locks_timeout; server_cb->locks_retry_interval = retry_interval; server_cb->locks_cleanup = cleanup; done = FALSE; if (LOGINFO) { log_info("\nSending <lock> operations for get-locks...\n"); } res = handle_get_locks_request_to_server(server_cb, TRUE, &done); if (res != NO_ERR && done) { /* need to undo the whole thing; whatever got done */ } if (valset != NULL) { val_free_value(valset); } return res; } /* do_get_locks */
/******************************************************************** * FUNCTION send_lock_pdu_to_server * * Send a <lock> or <unlock> operation to the server * * INPUTS: * server_cb == server control block to use * lockcb == lock control block to use within server_cb * islock == TRUE for lock; FALSE for unlock * * RETURNS: * status *********************************************************************/ static status_t send_lock_pdu_to_server (server_cb_t *server_cb, lock_cb_t *lockcb, boolean islock) { obj_template_t *rpc, *input; mgr_rpc_req_t *req; val_value_t *reqdata, *targetval, *parmval; ses_cb_t *scb; status_t res; xmlns_id_t obj_nsid; req = NULL; reqdata = NULL; res = NO_ERR; if (LOGDEBUG) { log_debug("\nSending <%s> request", (islock) ? NCX_EL_LOCK : NCX_EL_UNLOCK); } if (islock) { rpc = ncx_find_object(get_netconf_mod(server_cb), NCX_EL_LOCK); } else { rpc = ncx_find_object(get_netconf_mod(server_cb), NCX_EL_UNLOCK); } if (!rpc) { return SET_ERROR(ERR_NCX_DEF_NOT_FOUND); } obj_nsid = obj_get_nsid(rpc); /* get the 'input' section container */ input = obj_find_child(rpc, NULL, YANG_K_INPUT); if (!input) { return SET_ERROR(ERR_NCX_DEF_NOT_FOUND); } /* construct a method + parameter tree */ reqdata = xml_val_new_struct(obj_get_name(rpc), obj_nsid); if (!reqdata) { log_error("\nError allocating a new RPC request"); return ERR_INTERNAL_MEM; } /* set the [un]lock/input/target node XML namespace */ targetval = xml_val_new_struct(NCX_EL_TARGET, obj_nsid); if (!targetval) { log_error("\nError allocating a new RPC request"); val_free_value(reqdata); return ERR_INTERNAL_MEM; } else { val_add_child(targetval, reqdata); } parmval = xml_val_new_flag(lockcb->config_name, obj_nsid); if (!parmval) { val_free_value(reqdata); return ERR_INTERNAL_MEM; } else { val_add_child(parmval, targetval); } scb = mgr_ses_get_scb(server_cb->mysid); if (!scb) { res = SET_ERROR(ERR_INTERNAL_PTR); } else { req = mgr_rpc_new_request(scb); if (!req) { res = ERR_INTERNAL_MEM; log_error("\nError allocating a new RPC request"); } else { req->data = reqdata; req->rpc = rpc; req->timeout = server_cb->timeout; } } /* if all OK, send the RPC request */ if (res == NO_ERR) { if (LOGDEBUG2) { log_debug2("\nabout to send RPC request with reqdata:"); val_dump_value_max(reqdata, 0, server_cb->defindent, DUMP_VAL_LOG, server_cb->display_mode, FALSE, FALSE); } /* the request will be stored if this returns NO_ERR */ res = mgr_rpc_send_request(scb, req, yangcli_reply_handler); if (res == NO_ERR) { if (islock) { lockcb->lock_state = LOCK_STATE_REQUEST_SENT; } else { lockcb->lock_state = LOCK_STATE_RELEASE_SENT; } (void)uptime(&lockcb->last_msg_time); server_cb->locks_cur_cfg = lockcb->config_id; } } /* cleanup and set next state */ if (res != NO_ERR) { if (req) { mgr_rpc_free_request(req); } else if (reqdata) { val_free_value(reqdata); } } else { server_cb->state = MGR_IO_ST_CONN_RPYWAIT; } return res; } /* send_lock_pdu_to_server */
/******************************************************************** * FUNCTION mgr_hello_send * * Send the manager <hello> message to the server on the * specified session * * INPUTS: * scb == session control block * * RETURNS: * status *********************************************************************/ status_t mgr_hello_send (ses_cb_t *scb) { val_value_t *mycaps; xml_msg_hdr_t msg; status_t res; xml_attrs_t attrs; boolean anyout; xmlns_id_t nc_id; #ifdef DEBUG if (!scb) { return SET_ERROR(ERR_INTERNAL_PTR); } #endif #ifdef MGR_HELLO_DEBUG if (LOGDEBUG2) { log_debug2("\nmgr sending hello on session %d", scb->sid); } #endif res = NO_ERR; anyout = FALSE; xml_msg_init_hdr(&msg); xml_init_attrs(&attrs); nc_id = xmlns_nc_id(); /* get my client caps, custom made for this session */ mycaps = mgr_cap_get_ses_capsval(scb); if (!mycaps) { res = SET_ERROR(ERR_INTERNAL_PTR); } /* setup the prefix map with the NETCONF namespace */ if (res == NO_ERR) { res = xml_msg_build_prefix_map(&msg, &attrs, TRUE, FALSE); } /* send the <?xml?> directive */ if (res == NO_ERR) { res = ses_start_msg(scb); } /* start the hello element */ if (res == NO_ERR) { anyout = TRUE; xml_wr_begin_elem_ex(scb, &msg, 0, nc_id, NCX_EL_HELLO, &attrs, ATTRQ, 0, START); } /* send the capabilities list */ if (res == NO_ERR) { xml_wr_full_val(scb, &msg, mycaps, NCX_DEF_INDENT); } /* finish the hello element */ if (res == NO_ERR) { xml_wr_end_elem(scb, &msg, nc_id, NCX_EL_HELLO, 0); } /* finish the message */ if (anyout) { ses_finish_msg(scb); } xml_clean_attrs(&attrs); xml_msg_clean_hdr(&msg); if (mycaps != NULL) { val_free_value(mycaps); } return res; } /* mgr_hello_send */
/******************************************************************** * FUNCTION mgr_hello_dispatch * * Handle an incoming <hello> message from the client * * INPUTS: * scb == session control block * top == top element descriptor *********************************************************************/ void mgr_hello_dispatch (ses_cb_t *scb, xml_node_t *top) { val_value_t *val; ncx_module_t *mod; obj_template_t *obj; mgr_scb_t *mscb; xml_msg_hdr_t msg; status_t res; #ifdef DEBUG if (!scb || !top) { SET_ERROR(ERR_INTERNAL_PTR); return; } #endif #ifdef MGR_HELLO_DEBUG if (LOGDEBUG) { log_debug("\nmgr_hello got node"); } if (LOGDEBUG2) { xml_dump_node(top); } #endif mscb = mgr_ses_get_mscb(scb); /* only process this message in hello wait state */ if (scb->state != SES_ST_HELLO_WAIT) { /* TBD: stats update */ if (LOGINFO) { log_info("\nmgr_hello dropped, wrong state for session %d", scb->sid); } return; } /* init local vars */ res = NO_ERR; val = NULL; obj = NULL; xml_msg_init_hdr(&msg); /* get a value struct to hold the server hello msg */ val = val_new_value(); if (!val) { res = ERR_INTERNAL_MEM; } /* get the type definition from the registry */ if (res == NO_ERR) { mod = ncx_find_module(NC_MODULE, NULL); if (mod) { obj = ncx_find_object(mod, MGR_SERVER_HELLO_OBJ); } if (!obj) { /* netconf module should have loaded this definition */ res = SET_ERROR(ERR_INTERNAL_PTR); } } /* parse an server hello message */ if (res == NO_ERR) { res = mgr_val_parse(scb, obj, top, val); } /* examine the server capability list * and it matches the server protocol version */ if (res == NO_ERR) { res = process_server_hello(scb, val); } /* report first error and close session */ if (res != NO_ERR) { if (LOGINFO) { log_info("\nmgr_connect error (%s)\n dropping session %u (a:%u)", get_error_string(res), scb->sid, mscb->agtsid, res); } } else { scb->state = SES_ST_IDLE; if (LOGDEBUG) { log_debug("\nmgr_hello manager hello ok"); } } if (val) { val_free_value(val); } } /* mgr_hello_dispatch */
/******************************************************************** * FUNCTION do_aliases (local RPC) * * aliases * aliases clear * aliases show * aliases load[=filespec] * aliases save[=filespec] * * Handle the aliases command, based on the parameter * * INPUTS: * server_cb == server control block to use * rpc == RPC method for the aliases command * line == CLI input in progress * len == offset into line buffer to start parsing * * RETURNS: * status *********************************************************************/ status_t do_aliases (server_cb_t *server_cb, obj_template_t *rpc, const xmlChar *line, uint32 len) { val_value_t *valset; status_t res = NO_ERR; valset = get_valset(server_cb, rpc, &line[len], &res); if (res == NO_ERR && valset) { /* get the 1 of N 'alias-action' choice */ val_value_t *parm; const xmlChar *parmval = NULL; boolean done = FALSE; /* aliases show */ parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SHOW); if (parm) { show_aliases(); done = TRUE; } /* aliases clear */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_CLEAR); if (parm) { dlq_hdr_t *aliasQ = get_aliasQ(); if (!dlq_empty(aliasQ)) { free_aliases(); log_info("\nDeleted all aliases from memory\n"); update_yangcli_param_change_flag (ALIASES_FILE, TRUE); }else { log_info("\nNo aliases found\n"); } done = TRUE; } } /* aliases load */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_LOAD); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = load_aliases(parmval, !val_set_by_default(parm)); if (res == NO_ERR) { log_info("\nLoaded aliases OK from '%s'\n", parmval); } else { log_error("\nLoad aliases from '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } /* aliases save */ if (!done) { parm = val_find_child(valset, YANGCLI_MOD, YANGCLI_SAVE); if (parm) { if (xml_strlen(VAL_STR(parm))) { parmval = VAL_STR(parm); } else { parmval = get_aliases_file(); } res = save_aliases(parmval); if (res == NO_ERR) { log_info("\nSaved aliases OK to '%s'\n", parmval); } else if (res != ERR_NCX_CANCELED) { log_error("\nSave aliases to '%s' failed (%s)\n", parmval, get_error_string(res)); } done = TRUE; } } if (!done) { /* no parameters; show all aliases */ show_aliases(); } } if (valset) { val_free_value(valset); } return res; } /* do_aliases */