/******************************************************************** * FUNCTION y_starter_starter_kill_vnf_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_starter_starter_kill_vnf_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *errorval = NULL; val_value_t *vnfID_val; const xmlChar *vnfID; vnfID_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_vnfID); if (vnfID_val != NULL && vnfID_val->res == NO_ERR) { vnfID = VAL_STRING(vnfID_val); } if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval); } return res; } /* y_starter_starter_kill_vnf_validate */
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_unlock_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_ietf_netconf_partial_lock_partial_unlock_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { val_value_t *lock_id_val; cfg_template_t *running; plock_cb_t *plcb; uint32 lock_id; status_t res; res = NO_ERR; lock_id_val = val_find_child( msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_lock_id); if (lock_id_val == NULL || lock_id_val->res != NO_ERR) { return ERR_NCX_INVALID_VALUE; } lock_id = VAL_UINT(lock_id_val); running = cfg_get_config_id(NCX_CFGID_RUNNING); plcb = cfg_find_partial_lock(running, lock_id); if (plcb == NULL || (plock_get_sid(plcb) != SES_MY_SID(scb))) { res = ERR_NCX_INVALID_VALUE; agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, lock_id_val); } else { msg->rpc_user1 = plcb; } return res; } /* y_ietf_netconf_partial_lock_partial_unlock_validate */
/******************************************************************** * FUNCTION y_starter_starter_start_vnf_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_starter_starter_start_vnf_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *errorval = NULL; val_value_t *port_val; const xmlChar *port; val_value_t *clickDescription_val; const xmlChar *clickDescription; port_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_port); if (port_val != NULL && port_val->res == NO_ERR) { port = VAL_STRING(port_val); } clickDescription_val = val_find_child( msg->rpc_input, y_starter_M_starter, y_starter_N_clickDescription); if (clickDescription_val != NULL && clickDescription_val->res == NO_ERR) { clickDescription = VAL_STRING(clickDescription_val); } if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval); } return res; } /* y_starter_starter_start_vnf_validate */
/******************************************************************** * FUNCTION y_toaster_cancel_toast_validate * * RPC validation phase * All YANG constriants have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_toaster_cancel_toast_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res; val_value_t *errorval; const xmlChar *errorstr; res = NO_ERR; errorval = NULL; errorstr = NULL; /* added code starts here */ if (toaster_enabled) { /* toaster service enabled, check if not in use */ if (!toaster_toasting) { res = ERR_NCX_OPERATION_FAILED; } } else { /* toaster service disabled */ res = ERR_NCX_RESOURCE_DENIED; } /* added code ends here */ /* if error: set the res, errorstr, and errorval parms */ if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, errorstr, NCX_NT_VAL, errorval); } return res; } /* y_toaster_cancel_toast_validate */
/******************************************************************** * FUNCTION y_starter_starter_get_processes_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_starter_starter_get_processes_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res = NO_ERR; val_value_t *errorval = NULL; if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval); } return res; } /* y_starter_starter_get_processes_validate */
/******************************************************************** * FUNCTION starter_starter_edit * * Edit database object callback * Path: /starter * Add object instrumentation in COMMIT phase. * * INPUTS: * see agt/agt_cb.h for details * * RETURNS: * error status ********************************************************************/ static status_t starter_starter_edit ( ses_cb_t *scb, rpc_msg_t *msg, agt_cbtyp_t cbtyp, op_editop_t editop, val_value_t *newval, val_value_t *curval) { status_t res = NO_ERR; val_value_t *errorval = (curval) ? curval : newval; if (LOGDEBUG) { log_debug("\nEnter starter_starter_edit callback for %s phase", agt_cbtype_name(cbtyp)); } switch (cbtyp) { case AGT_CB_VALIDATE: /* description-stmt validation here */ break; case AGT_CB_APPLY: /* database manipulation done here */ break; case AGT_CB_COMMIT: /* device instrumentation done here */ switch (editop) { case OP_EDITOP_LOAD: break; case OP_EDITOP_MERGE: break; case OP_EDITOP_REPLACE: break; case OP_EDITOP_CREATE: break; case OP_EDITOP_DELETE: break; default: res = SET_ERROR(ERR_INTERNAL_VAL); } if (res == NO_ERR) { res = agt_check_cache(&starter_val, newval, curval, editop); } break; case AGT_CB_ROLLBACK: /* undo device instrumentation here */ break; default: res = SET_ERROR(ERR_INTERNAL_VAL); } if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_CONTENT, res, NULL, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval, (errorval) ? NCX_NT_VAL : NCX_NT_NONE, errorval); } return res; } /* starter_starter_edit */
/******************************************************************** * FUNCTION get_all_attrs * * Copy all the attributes from the current node to * the xml_attrs_t queue * * INPUTS: * scb == session control block * errnode == element node to use for reporting errors * msghdr == msg hdr w/ Q to get any rpc-errors as found, * NULL if not used * nserr == TRUE if unknown namespace should cause the * function to fail and the attr not to be saved * This is the normal mode. * == FALSE and the namespace will be marked INVALID * but an error will not be returned * * OUTPUTS: * attrs Q contains 0 or more entries * *msghdr.errQ may have rpc-errors added to it * * RETURNS: * status of the operation * returns NO_ERR if all copied okay or even zero copied *********************************************************************/ static status_t get_all_attrs (ses_cb_t *scb, xml_node_t *errnode, xml_attrs_t *attrs, ncx_layer_t layer, xml_msg_hdr_t *msghdr, boolean nserr) { /* check the attribute count first */ int cnt = xmlTextReaderAttributeCount(scb->reader); if (cnt==0) { return NO_ERR; } const xmlChar *name = NULL; status_t res = NO_ERR; boolean xpatherror = FALSE; int ret = 0; /* move through the list of attributes */ int i = 0; boolean done = FALSE; for (; i < cnt && !done; i++) { xmlChar *value = NULL; const xmlChar *badns = NULL; uint32 plen = 0; xmlns_id_t nsid = 0; res = NO_ERR; name = NULL; /* get the next attribute */ if (i==0) { ret = xmlTextReaderMoveToFirstAttribute(scb->reader); } else { ret = xmlTextReaderMoveToNextAttribute(scb->reader); } if (ret != 1) { res = ERR_XML_READER_INTERNAL; done = TRUE; } else { /* get the attribute name */ name = xmlTextReaderConstName(scb->reader); if (!name) { res = ERR_XML_READER_NULLNAME; } else { res = xml_check_ns(scb->reader, name, &nsid, &plen, &badns); if (!nserr && res != NO_ERR) { /* mask invalid namespace as requested */ nsid = xmlns_inv_id(); plen = 0; res = NO_ERR; } /* get the attribute value even if a NS error */ value = xmlTextReaderValue(scb->reader); if (!value) { res = ERR_XML_READER_NULLVAL; } else { /* save the values as received, may be QName * only error that can occur is a malloc fail */ xml_attr_t *attr = xml_add_qattr(attrs, nsid, name, plen, value, &res); if (!attr) { res = ERR_INTERNAL_MEM; } else { /* special hack: do not know which * attributes within an XML node * are tagged as XPath strings at this point * To save resources, only the 'select' and * 'key' attributes are supported at this time. */ if (!xml_strcmp(&name[plen], NCX_EL_SELECT)) { res = NO_ERR; attr->attr_xpcb = agt_new_xpath_pcb(scb, value, &res); if (!attr->attr_xpcb) { ; /* res already set */ } else { /* do a first pass parsing to resolve all * the prefixes and check well-formed XPath */ xpath_result_t *result = xpath1_eval_xmlexpr(scb->reader, attr->attr_xpcb, NULL, NULL, FALSE, FALSE, &res); if (res != NO_ERR) { xpatherror = TRUE; } xpath_free_result(result); } } else if (!xml_strcmp(&name[plen], NCX_EL_KEY)) { res = NO_ERR; attr->attr_xpcb = agt_new_xpath_pcb(scb, value, &res); if (!attr->attr_xpcb) { ; /* res already set */ } else { res = xpath_yang_validate_xmlkey (scb->reader, attr->attr_xpcb, NULL, FALSE); if (res != NO_ERR) { xpatherror = TRUE; } } } } } } } /* check the result */ if (res != NO_ERR && msghdr) { /* need a dummy attribute struct to report this error */ xml_attr_t errattr; memset(&errattr, 0x0, sizeof(xml_attr_t)); errattr.attr_ns = xmlns_nc_id(); errattr.attr_qname = name; errattr.attr_name = name; errattr.attr_val = value; /* save the error info */ if (xpatherror) { res = ERR_NCX_INVALID_XPATH_EXPR; /* generate an invalid-value error */ agt_record_attr_error(scb, msghdr, layer, res, &errattr, errnode, NULL, NCX_NT_NONE, NULL); } else if (res==ERR_XML_READER_NULLVAL || res==ERR_NCX_UNKNOWN_NAMESPACE) { /* generate a bad namespace error */ agt_record_attr_error(scb, msghdr, layer, res, &errattr, errnode, badns, NCX_NT_NONE, NULL); } else { /* generate a generic error */ agt_record_attr_error(scb, msghdr, layer, res, &errattr, errnode, NULL, NCX_NT_NONE, NULL); } } if (value) { xmlFree(value); } } /* reset the current node to where we started */ ret = xmlTextReaderMoveToElement(scb->reader); if (ret != 1) { if (msghdr) { res = ERR_XML_READER_INTERNAL; agt_record_error(scb, msghdr, layer, res, errnode, NCX_NT_STRING, name, NCX_NT_NONE, NULL); } } return res; } /* get_all_attrs */
/******************************************************************** * FUNCTION consume_node * * Internal consume XML node function * see agt_xml_consume_node for details. * * EXTRA INPUTS: * eoferr == TRUE if an End of File error should be generated * == FALSE if not * nserr == TRUE if bad namespace should be checked * == FALSE if not * clean == TRUE is a string should be cleaned before returned * == FALSE if a string node should be returned as-is * * RETURNS: * status of the operation * Try to fail on fatal errors only *********************************************************************/ static status_t consume_node (ses_cb_t *scb, boolean advance, xml_node_t *node, ncx_layer_t layer, xml_msg_hdr_t *msghdr, boolean eoferr, boolean nserr, boolean clean) { int ret, nodetyp; const xmlChar *badns; xmlChar *valstr, *namestr; uint32 len; status_t res, res2; boolean done; /* init local vars */ done = FALSE; res = NO_ERR; res2 = NO_ERR; badns = NULL; /* loop past any unused xmlTextReader node types */ while (!done) { /* check if a new node should be read */ if (advance) { /* advance the node pointer */ ret = xmlTextReaderRead(scb->reader); if (ret != 1) { /* do not treat this as an internal error */ res = ERR_XML_READER_EOF; if (msghdr && eoferr) { /* generate an operation-failed error */ agt_record_error(scb, msghdr, layer, res, NULL, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } return res; } } /* get the node depth to match the end node correctly */ node->depth = xmlTextReaderDepth(scb->reader); if (node->depth == -1) { /* this never actaully happens */ SET_ERROR(ERR_XML_READER_INTERNAL); node->depth = 0; } /* get the internal nodetype, check it and convert it */ nodetyp = xmlTextReaderNodeType(scb->reader); switch (nodetyp) { case XML_ELEMENT_NODE: /* classify element as empty or start */ if (xmlTextReaderIsEmptyElement(scb->reader)) { node->nodetyp = XML_NT_EMPTY; } else { node->nodetyp = XML_NT_START; } done = TRUE; break; case XML_ELEMENT_DECL: node->nodetyp = XML_NT_END; done = TRUE; break; case XML_TEXT_NODE: /* case XML_DTD_NODE: */ node->nodetyp = XML_NT_STRING; done = TRUE; break; default: /* unused node type -- keep trying */ if (LOGDEBUG3) { log_debug3("\nxml_consume_node: skip unused node (%s)", xml_get_node_name(nodetyp)); } advance = TRUE; } } /* finish the node, depending on its type */ switch (node->nodetyp) { case XML_NT_START: case XML_NT_END: case XML_NT_EMPTY: /* get the element QName */ namestr = xml_strdup(xmlTextReaderConstName(scb->reader)); if (!namestr) { res = ERR_INTERNAL_MEM; } else { node->qname = namestr; /* check for namespace prefix in the name * only error returned is unknown-namespace */ len = 0; res = xml_check_ns(scb->reader, namestr, &node->nsid, &len, &badns); if (!nserr && res != NO_ERR) { node->nsid = xmlns_inv_id(); len = 0; res = NO_ERR; } /* set the element name to the char after the prefix, if any */ node->elname = (const xmlChar *)(namestr+len); /* get all the attributes, except for XML_NT_END */ if (res == NO_ERR && node->nodetyp != XML_NT_END) { res2 = get_all_attrs(scb, node, &node->attrs, layer, msghdr, nserr); } /* Set the node module */ if (res == NO_ERR) { if (node->nsid) { node->module = xmlns_get_module(node->nsid); } else { /* no entry, use the default module (ncx) */ node->module = NCX_DEF_MODULE; } } } break; case XML_NT_STRING: /* get the text value -- this is a malloced string */ node->simval = NULL; valstr = xmlTextReaderValue(scb->reader); if (valstr) { if (clean) { node->simfree = xml_copy_clean_string(valstr); } else { node->simfree = xml_strdup(valstr); } if (node->simfree) { node->simlen = xml_strlen(node->simfree); node->simval = (const xmlChar *)node->simfree; } /* see if this is a QName string; if so save the NSID */ xml_check_qname_content(scb->reader, node); xmlFree(valstr); } if (!node->simval) { /* prevent a NULL ptr reference */ node->simval = EMPTY_STRING; node->simlen = 0; node->simfree = NULL; } break; default: break; } if ((res != NO_ERR) && msghdr) { if (badns) { /* generate an operation-failed error */ agt_record_error(scb, msghdr, layer, res, node, NCX_NT_STRING, badns, NCX_NT_NONE, NULL); } else { agt_record_error(scb, msghdr, layer, res, node, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } } if (LOGDEBUG4) { log_debug4("\nxml_consume_node: return (%d)", (res==NO_ERR) ? res2 : res); if (scb->state != SES_ST_INIT) { xml_dump_node(node); } } /* return general error first, then attribute error * It doesn't really matter since the caller will * assume all error reports have been queued upon return */ return (res==NO_ERR) ? res2 : res; } /* consume_node */
static status_t y_interfaces_alarms_alarms_edit ( ses_cb_t *scb, rpc_msg_t *msg, agt_cbtyp_t cbtyp, op_editop_t editop, val_value_t *newval, val_value_t *curval) { status_t res; val_value_t *errorval; const xmlChar *errorstr; res = NO_ERR; errorval = NULL; errorstr = NULL; switch (cbtyp) { case AGT_CB_VALIDATE: /* description-stmt validation here */ break; case AGT_CB_APPLY: /* database manipulation done here */ break; case AGT_CB_COMMIT: /* device instrumentation done here */ switch (editop) { case OP_EDITOP_LOAD: case OP_EDITOP_MERGE: case OP_EDITOP_REPLACE: case OP_EDITOP_CREATE: case OP_EDITOP_DELETE: /* device instrumentation here */ break; default: assert(0); } break; case AGT_CB_ROLLBACK: /* undo device instrumentation here */ break; default: res = SET_ERROR(ERR_INTERNAL_VAL); } /* if error: set the res, errorstr, and errorval parms */ if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_CONTENT, res, NULL, NCX_NT_STRING, errorstr, NCX_NT_VAL, errorval); } return res; }
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_lock_validate * * RPC validation phase * All YANG constraints have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_ietf_netconf_partial_lock_partial_lock_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { plock_cb_t *plcb; cfg_template_t *running; val_value_t *select_val, *testval; xpath_result_t *result; xpath_resnode_t *resnode; status_t res, retres; ses_id_t lockowner; res = NO_ERR; retres = NO_ERR; plcb = NULL; result = NULL; running = cfg_get_config_id(NCX_CFGID_RUNNING); /* make sure the running config state is READY */ res = cfg_ok_to_partial_lock(running); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); return res; } /* the stack has already made sure at least 1 of these * is present because min-elements=1 */ select_val = val_find_child (msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_select); if (select_val == NULL || select_val->res != NO_ERR) { /* should not happen */ return SET_ERROR(ERR_INTERNAL_VAL); } /* allocate a new lock cb * the plcb pointer will be NULL if the result is not NO_ERR */ res = NO_ERR; plcb = plock_cb_new(SES_MY_SID(scb), &res); if (res == ERR_NCX_RESOURCE_DENIED && !plcb && !cfg_is_partial_locked(running)) { /* no partial locks so it is safe to reset the lock index */ plock_cb_reset_id(); res = NO_ERR; plcb = plock_cb_new(SES_MY_SID(scb), &res); } if (res != NO_ERR || !plcb ) { if ( res==NO_ERR && !plcb ) { res = ERR_INTERNAL_MEM; } agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); if ( plcb ) { plock_cb_free(plcb); } return res; } /* get all the select parm instances and save them * in the partial lock cb */ while (select_val != NULL) { result = xpath1_eval_xmlexpr(scb->reader, select_val->xpathpcb, running->root, running->root, FALSE, /* logerrors */ TRUE, /* config-only */ &res); if (result == NULL || res != NO_ERR) { /* should not get invalid XPath expression * but maybe something was valid in the * object tree but not in the value tree */ agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, VAL_STRING(select_val), NCX_NT_VAL, select_val); retres = res; xpath_free_result(result); } else if (result->restype != XP_RT_NODESET) { res = ERR_NCX_XPATH_NOT_NODESET; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, VAL_STRING(select_val), NCX_NT_VAL, select_val); retres = res; xpath_free_result(result); } else { /* save these pointers; the result will be * pruned for redundant nodes after all the * select expressions have been processed; * transfer the memory straight across */ plock_add_select(plcb, select_val->xpathpcb, result); select_val->xpathpcb = NULL; result = NULL; } /* set up the next select value even if errors so far */ select_val = val_find_next_child (msg->rpc_input, y_ietf_netconf_partial_lock_M_ietf_netconf_partial_lock, y_ietf_netconf_partial_lock_N_select, select_val); } /* check the result for non-empty only if all * the select stmts were valid */ if (retres == NO_ERR) { res = plock_make_final_result(plcb); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, select_val); retres = res; } } /* make sure all the nodeptrs identify subtrees in the * running config that can really be locked right now * only if the final result is a non-empty nodeset */ if (retres == NO_ERR) { result = plock_get_final_result(plcb); for (resnode = xpath_get_first_resnode(result); resnode != NULL; resnode = xpath_get_next_resnode(resnode)) { testval = xpath_get_resnode_valptr(resnode); /* !!! Update 2011-09-27 * Just talked to the RFC author; Martin and I * agree RFC 5717 does not specify that write * access be required to create a partial lock * In fact -- a user may want to lock a node * to do a stable read **** deleted agt_acm check ***/ /* make sure there is a plock slot available * and no part of this subtree is already locked * do not check lock conflicts if this subtree * is unauthorized for writing */ lockowner = 0; res = val_ok_to_partial_lock(testval, SES_MY_SID(scb), &lockowner); if (res != NO_ERR) { if (res == ERR_NCX_LOCK_DENIED) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_UINT32_PTR, &lockowner, NCX_NT_VAL, testval); } else { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, testval); } retres = res; } } // for loop } // if retres == NO_ERR /* make sure there is no partial commit in progress */ if (agt_ncx_cc_active()) { res = ERR_NCX_IN_USE_COMMIT; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); retres = res; } /* save the plock CB only if there were no errors; * otherwise the invoke function will not get called */ if (retres == NO_ERR) { /* the invoke function must free this pointer */ msg->rpc_user1 = plcb; } else { plock_cb_free(plcb); } return retres; } /* y_ietf_netconf_partial_lock_partial_lock_validate */
/******************************************************************** * FUNCTION y_ietf_netconf_partial_lock_partial_lock_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_ietf_netconf_partial_lock_partial_lock_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { plock_cb_t *plcb; val_value_t *testval, *newval; xpath_result_t *result; xpath_resnode_t *resnode, *clearnode; xmlChar *pathbuff; cfg_template_t *running; status_t res; ncx_num_t num; res = NO_ERR; plcb = (plock_cb_t *)msg->rpc_user1; result = plock_get_final_result(plcb); running = cfg_get_config_id(NCX_CFGID_RUNNING); /* try to lock all the target nodes */ for (resnode = xpath_get_first_resnode(result); resnode != NULL && res == NO_ERR; resnode = xpath_get_next_resnode(resnode)) { testval = xpath_get_resnode_valptr(resnode); res = val_set_partial_lock(testval, plcb); if (res != NO_ERR) { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_VAL, testval); } } /* unlock any nodes already attempted if any fail */ if (res != NO_ERR) { for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); if (clearnode == resnode) { return res; } } return res; } /* add this partial lock to the running config */ res = cfg_add_partial_lock(running, plcb); if (res != NO_ERR) { /* should not happen since config lock state could * not have changed since validate callback */ agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); } plock_cb_free(plcb); return res; } /* setup return data only if lock successful * cache the reply instead of stream the reply * in case there is any error; if so; the partial * lock will be backed out and the dataQ cleaned * for an error exit; add lock-id leaf first */ msg->rpc_data_type = RPC_DATA_YANG; ncx_init_num(&num); num.u = plock_get_id(plcb); newval = xml_val_new_number (y_ietf_netconf_partial_lock_N_lock_id, val_get_nsid(msg->rpc_input), &num, NCX_BT_UINT32); ncx_clean_num(NCX_BT_UINT32, &num); if (newval == NULL) { res = ERR_INTERNAL_MEM; agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } else { dlq_enque(newval, &msg->rpc_dataQ); } /* add lock-node leaf-list instance for each resnode */ for (resnode = xpath_get_first_resnode(result); resnode != NULL && res == NO_ERR; resnode = xpath_get_next_resnode(resnode)) { /* Q&D method: generate the i-i string as a plain * string and add any needed prefixes to the global * prefix map for the reply message (in mhdr) */ pathbuff = NULL; testval = xpath_get_resnode_valptr(resnode); res = val_gen_instance_id(&msg->mhdr, testval, NCX_IFMT_XPATH1, &pathbuff); if (res == NO_ERR) { /* make leaf; pass off pathbuff malloced memory */ newval = xml_val_new_string (y_ietf_netconf_partial_lock_N_locked_node, val_get_nsid(msg->rpc_input), pathbuff); if (newval == NULL) { res = ERR_INTERNAL_MEM; m__free(pathbuff); pathbuff = NULL; } } if (res == NO_ERR) { dlq_enque(newval, &msg->rpc_dataQ); } else { agt_record_error(scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } } if (res != NO_ERR) { /* back out everything, except waste the lock ID */ for (clearnode = xpath_get_first_resnode(result); clearnode != NULL; clearnode = xpath_get_next_resnode(clearnode)) { testval = xpath_get_resnode_valptr(clearnode); val_clear_partial_lock(testval, plcb); } cfg_delete_partial_lock(running, plock_get_id(plcb)); /* clear any data already queued */ while (!dlq_empty(&msg->rpc_dataQ)) { testval = (val_value_t *) dlq_deque(&msg->rpc_dataQ); val_free_value(testval); } msg->rpc_data_type = RPC_DATA_NONE; } return res; } /* y_ietf_netconf_partial_lock_partial_lock_invoke */
/******************************************************************** * FUNCTION y_toaster_make_toast_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_toaster_make_toast_invoke ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res; val_value_t *toasterDoneness_val; val_value_t *toasterToastType_val; uint32 toasterDoneness; //val_idref_t *toasterToastType; res = NO_ERR; toasterDoneness = 0; toasterDoneness_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterDoneness); if (toasterDoneness_val != NULL && toasterDoneness_val->res == NO_ERR) { toasterDoneness = VAL_UINT(toasterDoneness_val); } toasterToastType_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterToastType); if (toasterToastType_val != NULL && toasterToastType_val->res == NO_ERR) { //toasterToastType = VAL_IDREF(toasterToastType_val); // invoke instrumentation with this toast type } /* invoke your device instrumentation code here */ /* make sure the toasterDoneness value is set */ if (toasterDoneness_val == NULL) { toasterDoneness = 5; /* set the default */ } /* arbitrary formula to convert toaster doneness to the * number of seconds the toaster should be on */ toaster_duration = toasterDoneness * 12; /* this is where the code would go to adjust the duration * based on the bread type */ if (LOGDEBUG) { log_debug("\ntoaster: starting toaster for %u seconds", toaster_duration); } /* this is where the code would go to start the toaster * heater element */ /* start a timer to toast for the specified time interval */ res = agt_timer_create(toaster_duration, FALSE, toaster_timer_fn, NULL, &toaster_timer_id); if (res == NO_ERR) { toaster_toasting = TRUE; } else { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_NONE, NULL, NCX_NT_NONE, NULL); } /* added code ends here */ return res; } /* y_toaster_make_toast_invoke */
/******************************************************************** * FUNCTION y_toaster_make_toast_validate * * RPC validation phase * All YANG constriants have passed at this point. * Add description-stmt checks in this function. * * INPUTS: * see agt/agt_rpc.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_toaster_make_toast_validate ( ses_cb_t *scb, rpc_msg_t *msg, xml_node_t *methnode) { status_t res; val_value_t *errorval; const xmlChar *errorstr; val_value_t *toasterDoneness_val; val_value_t *toasterToastType_val; //uint32 toasterDoneness; //val_idref_t *toasterToastType; res = NO_ERR; errorval = NULL; errorstr = NULL; toasterDoneness_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterDoneness); if (toasterDoneness_val != NULL && toasterDoneness_val->res == NO_ERR) { //toasterDoneness = VAL_UINT(toasterDoneness_val); // validate toast doneness within instrumentation if needed } toasterToastType_val = val_find_child( msg->rpc_input, y_toaster_M_toaster, y_toaster_N_toasterToastType); if (toasterToastType_val != NULL && toasterToastType_val->res == NO_ERR) { //toasterToastType = VAL_IDREF(toasterToastType_val); // validate toast-type within instrumentation if needed } /* added code starts here */ if (toaster_enabled) { /* toaster service enabled, check if in use */ if (toaster_toasting) { res = ERR_NCX_IN_USE; } else { /* this is where a check on bread inventory would go */ /* this is where a check on toaster HW ready would go */ } } else { /* toaster service disabled */ res = ERR_NCX_RESOURCE_DENIED; } /* added code ends here */ /* if error: set the res, errorstr, and errorval parms */ if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_OPERATION, res, methnode, NCX_NT_STRING, errorstr, NCX_NT_VAL, errorval); } return res; } /* y_toaster_make_toast_validate */
/******************************************************************** * FUNCTION y_toaster_toaster_edit * * Edit database object callback * Path: /toaster * Add object instrumentation in COMMIT phase. * * INPUTS: * see agt/agt_cb.h for details * * RETURNS: * error status ********************************************************************/ static status_t y_toaster_toaster_edit ( ses_cb_t *scb, rpc_msg_t *msg, agt_cbtyp_t cbtyp, op_editop_t editop, val_value_t *newval, val_value_t *curval) { status_t res; val_value_t *errorval; const xmlChar *errorstr; res = NO_ERR; errorval = NULL; errorstr = NULL; switch (cbtyp) { case AGT_CB_VALIDATE: /* description-stmt validation here */ break; case AGT_CB_APPLY: /* database manipulation done here */ break; case AGT_CB_COMMIT: /* device instrumentation done here */ switch (editop) { case OP_EDITOP_LOAD: toaster_enabled = TRUE; toaster_toasting = FALSE; break; case OP_EDITOP_MERGE: break; case OP_EDITOP_REPLACE: break; case OP_EDITOP_CREATE: toaster_enabled = TRUE; toaster_toasting = FALSE; break; case OP_EDITOP_DELETE: toaster_enabled = FALSE; if (toaster_toasting) { agt_timer_delete(toaster_timer_id); toaster_timer_id = 0; toaster_toasting = FALSE; y_toaster_toastDone_send((const xmlChar *)"error"); } break; default: res = SET_ERROR(ERR_INTERNAL_VAL); } if (res == NO_ERR) { res = agt_check_cache( &toaster_val, newval, curval, editop); } if (res == NO_ERR && (editop == OP_EDITOP_LOAD || editop == OP_EDITOP_CREATE)) { res = y_toaster_toaster_mro(newval); } break; case AGT_CB_ROLLBACK: /* undo device instrumentation here */ break; default: res = SET_ERROR(ERR_INTERNAL_VAL); } /* if error: set the res, errorstr, and errorval parms */ if (res != NO_ERR) { agt_record_error( scb, &msg->mhdr, NCX_LAYER_CONTENT, res, NULL, NCX_NT_STRING, errorstr, NCX_NT_VAL, errorval); } return res; } /* y_toaster_toaster_edit */