diff --git a/apps/snmp/snmp_handler.c b/apps/snmp/snmp_handler.c
index 2d77213c..f067f7d3 100644
--- a/apps/snmp/snmp_handler.c
+++ b/apps/snmp/snmp_handler.c
@@ -118,6 +118,143 @@ done:
return retval;
}
+/*! Scalar handler, set a value to clixon
+ * get xpath: see yang2api_path_fmt / api_path2xpath
+ */
+static int
+snmp_scalar_get(clicon_handle h,
+ yang_stmt *ys,
+ netsnmp_variable_list *requestvb,
+ char *defaultval,
+ enum cv_type cvtype,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests)
+{
+ int retval = -1;
+ cvec *nsc = NULL;
+ char *xpath = NULL;
+ cxobj *xt = NULL;
+ cxobj *xerr;
+ cxobj *x;
+ char *valstr = NULL;
+ u_char *snmpval = NULL;
+ size_t snmplen;
+ int ret;
+
+ if (xml_nsctx_yang(ys, &nsc) < 0)
+ goto done;
+ if (yang2xpath(ys, &xpath) < 0)
+ goto done;
+ if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
+ goto done;
+ if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
+ clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
+ goto done;
+ }
+ /* Get value, either from xml, or smiv2 default */
+ if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
+ valstr = xml_body(x);
+ }
+ else if ((valstr = defaultval) != NULL)
+ ;
+ else{
+ netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
+ goto ok;
+ }
+ if ((ret = type_yang2snmp(valstr, cvtype, reqinfo, requests, &snmpval, &snmplen)) < 0)
+ goto done;
+ if (ret == 0)
+ goto ok;
+
+ /* 1. use cligen object and get rwa buf / size from that, OR
+ * + have parse function from YANG
+ * - does not have
+ * 2. use union netsnmp_vardata and pass that here?
+ * 3. Make cv2asn1 conversion function <--
+ */
+
+ /* see snmplib/snmp_client.c */
+ if (snmp_set_var_value(requestvb,
+ snmpval,
+ snmplen) != 0){
+ clicon_err(OE_SNMP, 0, "snmp_set_var_value");
+ goto done;
+ }
+ ok:
+ retval = 0;
+ done:
+ if (snmpval)
+ free(snmpval);
+ if (xt)
+ xml_free(xt);
+ if (xpath)
+ free(xpath);
+ if (nsc)
+ xml_nsctx_free(nsc);
+ return retval;
+}
+
+/*! Scalar handler, get a value from clixon
+ */
+static int
+snmp_scalar_set(clicon_handle h,
+ yang_stmt *ys,
+ netsnmp_variable_list *requestvb,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests)
+{
+ int retval = -1;
+ char *api_path = NULL;
+ cxobj *xtop = NULL;
+ cxobj *xbot = NULL;
+ cxobj *xb;
+ yang_stmt *yspec;
+ int ret;
+ char *valstr = NULL;
+ cbuf *cb = NULL;
+
+ if ((yspec = clicon_dbspec_yang(h)) == NULL){
+ clicon_err(OE_FATAL, 0, "No DB_SPEC");
+ goto done;
+ }
+ if ((xtop = xml_new(NETCONF_INPUT_CONFIG, NULL, CX_ELMNT)) == NULL)
+ goto done;
+ if (yang2api_path_fmt(ys, 0, &api_path) < 0)
+ goto done;
+ if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, NULL, NULL)) < 0)
+ goto done;
+
+ if (ret == 0){
+ clicon_err(OE_XML, 0, "api_path2xml %s invalid", api_path);
+ goto done;
+ }
+ if ((xb = xml_new("body", xbot, CX_BODY)) == NULL)
+ goto done;
+ if ((ret = type_snmp2yang(requestvb, reqinfo, requests, &valstr)) < 0)
+ goto done;
+ if (ret == 0)
+ goto ok;
+ if (xml_value_set(xb, valstr) < 0)
+ goto done;
+ if ((cb = cbuf_new()) == NULL){
+ clicon_err(OE_UNIX, errno, "cbuf_new");
+ goto done;
+ }
+ if (clicon_xml2cbuf(cb, xtop, 0, 0, -1) < 0)
+ goto done;
+ if (clicon_rpc_edit_config(h, "candidate", OP_MERGE, cbuf_get(cb)) < 0)
+ goto done;
+ ok:
+ retval = 0;
+ done:
+ if (cb)
+ cbuf_free(cb);
+ if (xtop)
+ xml_free(xtop);
+ if (valstr)
+ free(valstr);
+ return retval;
+}
/*! SNMP Scalar operation handler
* Calls order: READ:160,
@@ -131,25 +268,13 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests)
{
- int retval = -1;
- clixon_snmp_handle *sh;
- yang_stmt *ys;
- clicon_handle h;
- cg_var *cv = NULL;
- cxobj *xt = NULL;
- cxobj *xerr;
- cvec *nsc = NULL;
- cxobj *x;
- char *xpath = NULL;
- int asn1_type;
- enum cv_type cvtype;
- char *valstr;
- u_char *snmpval = NULL;
- size_t snmplen;
- int ret;
+ int retval = -1;
+ clixon_snmp_handle *sh;
+ yang_stmt *ys;
+ int asn1_type;
netsnmp_variable_list *requestvb; /* sub of requests */
- cbuf *cb = NULL;
-
+ enum cv_type cvtype;
+
/*
* can be used to pass information on a per-pdu basis from a
* helper to the later handlers
@@ -174,7 +299,6 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
requests->inclusive);
sh = (clixon_snmp_handle*)nhreg->my_reg_void;
ys = sh->sh_ys;
- h = sh->sh_h;
// fprint_objid(stderr, nhreg->rootoid, nhreg->rootoid_len);
assert(sh->sh_oidlen == requestvb->name_length);
assert(requestvb->name_length == nhreg->rootoid_len);
@@ -188,123 +312,43 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
SNMP_NOSUCHOBJECT);
return SNMP_ERR_NOERROR;
#endif
-
if (yang2snmp_types(ys, &asn1_type, &cvtype) < 0)
goto done;
/* see net-snmp/agent/snmp_agent.h / net-snmp/library/snmp.h */
switch (reqinfo->mode) {
- case MODE_GET: // 160
+ case MODE_GET: /* 160 */
requestvb->type = asn1_type; // ASN_NULL on input
-
- /* get xpath: see yang2api_path_fmt / api_path2xpath
- New fn: yang2xpath?
- clicon_rpc_get()
- "
-
- */
-
- if (xml_nsctx_yang(ys, &nsc) < 0)
+ if (snmp_scalar_get(sh->sh_h, ys, requestvb, sh->sh_default, cvtype, reqinfo, requests) < 0)
goto done;
- if (yang2xpath(ys, &xpath) < 0)
- goto done;
- if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
- goto done;
- if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
- clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
- goto done;
- }
- /* Get value, either from xml, or smiv2 default */
- if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
- valstr = xml_body(x);
- }
- else if ((valstr = sh->sh_default) != NULL)
- ;
- else{
- netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
- goto ok;
- }
- if ((ret = type_yang2snmp(valstr, cvtype, reqinfo, requests, &snmpval, &snmplen)) < 0)
- goto done;
- if (ret == 0)
- goto ok;
-
- /* 1. use cligen object and get rwa buf / size from that, OR
- * + have parse function from YANG
- * - does not have
- * 2. use union netsnmp_vardata and pass that here?
- * 3. Make cv2asn1 conversion function <--
- */
-
- /* see snmplib/snmp_client.c */
- if (snmp_set_var_value(requestvb,
- snmpval,
- snmplen) != 0){
- clicon_err(OE_SNMP, 0, "snmp_set_var_value");
- goto done;
- }
break;
- case MODE_GETNEXT: // 161
+ case MODE_GETNEXT: /* 161 */
assert(0); // Not seen?
break;
- case MODE_SET_RESERVE1: // 0
+ case MODE_SET_RESERVE1: /* 0 */
if (requestvb->type != asn1_type)
netsnmp_set_request_error(reqinfo, requests,
SNMP_ERR_WRONGTYPE);
break;
-
- case MODE_SET_RESERVE2: // 1
+ case MODE_SET_RESERVE2: /* 1 */
break;
-
- case MODE_SET_ACTION: // 2
- /*
- * update current
- */
- /* yang2xpath -> xpath2xml
- * accesses = *(requestvb->val.integer);
- * rpc edit-config
-
- */
-
- if ((cb = cbuf_new()) == NULL){
- clicon_err(OE_UNIX, errno, "cbuf_new");
- goto done;
- }
- /*! XXX only int */
- cprintf(cb, "%ld", *requestvb->val.integer);
- if (clicon_rpc_edit_config(h, "candidate", OP_MERGE, cbuf_get(cb)) < 0)
+ case MODE_SET_ACTION: /* 2 */
+ if (snmp_scalar_set(sh->sh_h, ys, requestvb, reqinfo, requests) < 0)
goto done;
break;
-
- case MODE_SET_UNDO: // 5
- if (clicon_rpc_discard_changes(h) < 0)
+ case MODE_SET_UNDO: /* 5 */
+ if (clicon_rpc_discard_changes(sh->sh_h) < 0)
goto done;
break;
- case MODE_SET_COMMIT: // 3
- if (clicon_rpc_commit(h) < 0)
+ case MODE_SET_COMMIT: /* 3 */
+ if (clicon_rpc_commit(sh->sh_h) < 0)
goto done;
break;
- case MODE_SET_FREE: // 4
- /*
- * nothing to do
- */
+ case MODE_SET_FREE: /* 4 */
break;
}
- ok:
retval = SNMP_ERR_NOERROR;
done:
- if (snmpval)
- free(snmpval);
- if (cb)
- cbuf_free(cb);
- if (xpath)
- free(xpath);
- if (xt)
- xml_free(xt);
- if (nsc)
- xml_nsctx_free(nsc);
- if (cv)
- cv_free(cv);
return retval;
}
diff --git a/apps/snmp/snmp_lib.c b/apps/snmp/snmp_lib.c
index 6c21db6f..16cc38d1 100644
--- a/apps/snmp/snmp_lib.c
+++ b/apps/snmp/snmp_lib.c
@@ -54,8 +54,9 @@
#include
#include
#include
-#include
#include
+#include
+#include
/* net-snmp */
#include
@@ -91,16 +92,19 @@ static const map_str2int snmp_access_map[] = {
/* Map between clixon and ASN.1 types.
* @see net-snmp/library/asn1.h
* @see union netsnmp_vardata in net-snmp/types.h
+ * XXX not complete
+ * XXX TimeTicks
*/
static const map_str2int snmp_type_map[] = {
- {"bool", ASN_BOOLEAN},
+
{"int32", ASN_INTEGER},
- {"bits", ASN_BIT_STR},
{"string", ASN_OCTET_STR},
- {"empty", ASN_NULL},
- //XXX {"", ASN_OBJECT_ID},
- // XXX {"", ASN_SEQUENCE},
- // XXX {"", ASN_SET},
+ // {"bool", ASN_BOOLEAN},
+ // {"empty", ASN_NULL},
+ // {"bits", ASN_BIT_STR},
+ // {"", ASN_OBJECT_ID},
+ // {"", ASN_SEQUENCE},
+ // {"", ASN_SET},
{NULL, -1}
};
@@ -130,7 +134,13 @@ snmp_msg_int2str(int msg)
{
return clicon_int2str(snmp_msg_map, msg);
}
-/*!
+/*! Translate from YANG to SNMP asn1.1 type ids (not value)
+ *
+ * @param[in] ys YANG leaf node
+ * @param[out] asn1_type ASN.1 type id
+ * @param[out] cvtype Clixon cv type
+ * @retval 0 OK
+ * @retval -1 Error
*/
int
yang2snmp_types(yang_stmt *ys,
@@ -141,31 +151,38 @@ yang2snmp_types(yang_stmt *ys,
yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */
char *origtype=NULL; /* original type */
+ int at;
/* Get yang type of leaf and trasnslate to ASN.1 */
if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
goto done;
restype = yrestype?yang_argument_get(yrestype):NULL;
- if (clicon_type2cv(origtype, restype, ys, cvtype) < 0)
- goto done;
/* translate to asn.1 */
- *asn1_type = clicon_str2int(snmp_type_map, restype);
+ if ((at = clicon_str2int(snmp_type_map, restype)) < 0){
+ clicon_err(OE_YANG, 0, "No snmp translation for YANG %s type:%s",
+ yang_argument_get(ys), restype);
+ // goto done;
+ }
+ if (asn1_type)
+ *asn1_type = at;
+ if (cvtype && clicon_type2cv(origtype, restype, ys, cvtype) < 0)
+ goto done;
clicon_debug(1, "%s type:%s", __FUNCTION__, restype);
retval = 0;
done:
return retval;
}
-
/*! Translate from yang/xml/clixon to SNMP/ASN.1
-**
-* The tran
+ *
* @param[in] valstr Clixon/yang/xml string value
* @param[in] cvtype Type of clixon type
+ * @param[in] reqinfo snmpd API struct for error
+ * @param[in] requests snmpd API struct for error
* @param[out] snmpval Malloc:ed snmp type
* @param[out] snmplen Length of snmp type
* @retval 1 OK
- * @retval 0 Invalid value
+ * @retval 0 Invalid value or type
* @retval -1 Error
*/
int
@@ -216,6 +233,7 @@ type_yang2snmp(char *valstr,
break;
}
default:
+ assert(0); // XXX
clicon_debug(1, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype));
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE);
goto fail;
@@ -231,6 +249,66 @@ type_yang2snmp(char *valstr,
retval = 0;
goto done;
}
+/*! Translate from yang/xml/clixon to SNMP/ASN.1
+ *
+ * @param[in] snmpval Malloc:ed snmp type
+ * @param[in] snmplen Length of snmp type
+ * @param[in] reqinfo snmpd API struct for error
+ * @param[in] requests snmpd API struct for error
+ * @param[out] valstr Clixon/yang/xml string value, free after use)
+ * @retval 1 OK, and valstr set
+ * @retval 0 Invalid value or type
+ * @retval -1 Error
+ */
+int
+type_snmp2yang(netsnmp_variable_list *requestvb,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests,
+ char **valstr)
+{
+ int retval = -1;
+ char *cvtypestr;
+ enum cv_type cvtype;
+ cg_var *cv;
+
+ clicon_debug(1, "%s", __FUNCTION__);
+ if (valstr == NULL){
+ clicon_err(OE_UNIX, EINVAL, "valstr is NULL");
+ goto done;
+ }
+ cvtypestr = (char*)clicon_int2str(snmp_type_map, requestvb->type);
+ cvtype = cv_str2type(cvtypestr);
+ if ((cv = cv_new(cvtype)) == NULL){
+ clicon_err(OE_UNIX, errno, "cv_new");
+ goto done;
+ }
+ switch (requestvb->type){
+ case ASN_BOOLEAN:
+ case ASN_INTEGER:
+ cv_int32_set(cv, *requestvb->val.integer);
+ break;
+ case ASN_OCTET_STR:
+ cv_string_set(cv, (char*)requestvb->val.string);
+ break;
+ default:
+ assert(0); // XXX
+ clicon_debug(1, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype));
+ netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE);
+ goto fail;
+ break;
+ }
+ if ((*valstr = cv2str_dup(cv)) == NULL){
+ clicon_err(OE_UNIX, errno, "cv2str_dup");
+ goto done;
+ }
+ retval = 1;
+ done:
+ clicon_debug(1, "%s %d", __FUNCTION__, retval);
+ return retval;
+ fail:
+ retval = 0;
+ goto done;
+}
/*! Construct an xpath from yang statement, internal fn using cb
* Recursively construct it to the top.
@@ -263,9 +341,10 @@ yang2xpath_cb(yang_stmt *ys,
cprintf(cb, "/");
}
}
- cprintf(cb, "%s:", yang_find_myprefix(ys));
- if (yang_keyword_get(ys) != Y_CHOICE && yang_keyword_get(ys) != Y_CASE)
+ if (yang_keyword_get(ys) != Y_CHOICE && yang_keyword_get(ys) != Y_CASE){
+ cprintf(cb, "%s:", yang_find_myprefix(ys));
cprintf(cb, "%s", yang_argument_get(ys));
+ }
switch (yang_keyword_get(ys)){
case Y_LIST: // XXX not xpaths
cvk = yang_cvec_get(ys); /* Use Y_LIST cache, see ys_populate_list() */
@@ -290,7 +369,6 @@ yang2xpath_cb(yang_stmt *ys,
}
/*! Construct an xpath from yang statement
-
* Recursively construct it to the top.
* @param[in] ys Yang statement
* @param[out] xpath Malloced xpath string, use free() after use
diff --git a/apps/snmp/snmp_lib.h b/apps/snmp/snmp_lib.h
index ed572180..13a6cbe4 100644
--- a/apps/snmp/snmp_lib.h
+++ b/apps/snmp/snmp_lib.h
@@ -64,6 +64,10 @@ int yang2snmp_types(yang_stmt *ys, int *asn1_type, enum cv_type *cvtype);
int type_yang2snmp(char *valstr, enum cv_type cvtype,
netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests,
u_char **snmpval, size_t *snmplen);
+int type_snmp2yang(netsnmp_variable_list *requestvb,
+ netsnmp_agent_request_info *reqinfo,
+ netsnmp_request_info *requests,
+ char **valstr);
int yang2xpath(yang_stmt *ys, char **xpath);
int clixon_table_create(netsnmp_table_data_set *table, yang_stmt *ys, clicon_handle h);
diff --git a/apps/snmp/snmp_main.c b/apps/snmp/snmp_main.c
index 66ba4cae..0cc25f13 100644
--- a/apps/snmp/snmp_main.c
+++ b/apps/snmp/snmp_main.c
@@ -448,8 +448,8 @@ main(int argc,
/* Init snmp as subagent */
if (clixon_snmp_subagent(h, logdst) < 0)
goto done;
- /* Init mib-translated yangs and register callbacks */
- if (clixon_snmp_mib_yangs(h) < 0)
+ /* Init and traverse mib-translated yangs and register callbacks */
+ if (clixon_snmp_traverse_mibyangs(h) < 0)
goto done;
if (dbg)
diff --git a/apps/snmp/snmp_register.c b/apps/snmp/snmp_register.c
index 4082e2b7..dd67eee7 100644
--- a/apps/snmp/snmp_register.c
+++ b/apps/snmp/snmp_register.c
@@ -81,258 +81,6 @@
#define IETF_YANG_SMIV2_NS "urn:ietf:params:xml:ns:yang:ietf-yang-smiv2"
-#if 0
-/*! SNMP table operation handlre
-
- * Callorder: 161,160,.... 0, 1,2,3, 160,161,...
- * see https://net-snmp.sourceforge.io/dev/agent/data_set_8c-example.html#_a0
- */
-int
-snmp_table_handler(netsnmp_mib_handler *handler,
- netsnmp_handler_registration *nhreg,
- netsnmp_agent_request_info *reqinfo,
- netsnmp_request_info *requests)
-{
- int retval = SNMP_ERR_GENERR;
- clixon_snmp_handle *sh;
- netsnmp_table_data_set *table;
- yang_stmt *ys;
- clicon_handle h;
- yang_stmt *ylist;
- cvec *nsc = NULL;
- cxobj *xt = NULL;
- cbuf *cb = NULL;
-
- clicon_debug(1, "%s %s %s", __FUNCTION__,
- handler->handler_name,
- snmp_msg_int2str(reqinfo->mode));
- sh = (clixon_snmp_handle*)nhreg->my_reg_void;
- ys = sh->sh_ys;
- h = sh->sh_h;
- table = sh->sh_table;
-
- if ((ylist = yang_find(ys, Y_LIST, NULL)) == NULL)
- goto ok;
-
- if (clixon_table_create(table, ys, h) < 0)
- goto done;
-
- switch(reqinfo->mode){
- case MODE_GETNEXT: // 160
- break;
- case MODE_GET: // 160
- case MODE_SET_RESERVE1:
- case MODE_SET_RESERVE2:
- case MODE_SET_ACTION:
- case MODE_SET_COMMIT:
- break;
-
- }
-ok:
- retval = SNMP_ERR_NOERROR;
-
-done:
- if (xt)
- xml_free(xt);
- if (cb)
- cbuf_free(cb);
- if (nsc)
- xml_nsctx_free(nsc);
- return retval;
-}
-
-
-/*! SNMP Scalar operation handler
- * Calls order: READ:160,
- * WRITE: 0, 1, 2, 3,
- * MODE_SET_RESERVE1, MODE_SET_RESERVE2, MODE_SET_ACTION, MODE_SET_COMMIT
- *
- */
-int
-snmp_scalar_handler(netsnmp_mib_handler *handler,
- netsnmp_handler_registration *nhreg,
- netsnmp_agent_request_info *reqinfo,
- netsnmp_request_info *requests)
-{
- int retval = -1;
- clixon_snmp_handle *sh;
- yang_stmt *ys;
- clicon_handle h;
- cg_var *cv = NULL;
- cxobj *xt = NULL;
- cxobj *xerr;
- cvec *nsc = NULL;
- cxobj *x;
- char *xpath = NULL;
- int asn1_type;
- enum cv_type cvtype;
- char *valstr;
- u_char *snmpval = NULL;
- size_t snmplen;
- int ret;
- netsnmp_variable_list *requestvb; /* sub of requests */
- cbuf *cb = NULL;
-
- /*
- * can be used to pass information on a per-pdu basis from a
- * helper to the later handlers
- netsnmp_agent_request_info *reqinfo,
- netsnmp_data_list *agent_data;
- netsnmp_free_agent_data_set()
- */
- requestvb = requests->requestvb;
- if (0)
- fprintf(stderr, "%s %s %s\n", __FUNCTION__,
- handler->handler_name,
- snmp_msg_int2str(reqinfo->mode)
- );
-
- if (0)
- fprintf(stderr, "inclusive:%d\n",
- requests->inclusive
- );
- clicon_debug(1, "%s %s %s %d", __FUNCTION__,
- handler->handler_name,
- snmp_msg_int2str(reqinfo->mode),
- requests->inclusive);
- sh = (clixon_snmp_handle*)nhreg->my_reg_void;
- ys = sh->sh_ys;
- h = sh->sh_h;
- // fprint_objid(stderr, nhreg->rootoid, nhreg->rootoid_len);
- assert(sh->sh_oidlen == requestvb->name_length);
- assert(requestvb->name_length == nhreg->rootoid_len);
- assert(snmp_oid_compare(sh->sh_oid, sh->sh_oidlen,
- requestvb->name, requestvb->name_length) == 0);
- assert(snmp_oid_compare(requestvb->name, requestvb->name_length,
- nhreg->rootoid, nhreg->rootoid_len) == 0);
-
-#if 0 /* If oid match fails */
- netsnmp_set_request_error(reqinfo, requests,
- SNMP_NOSUCHOBJECT);
- return SNMP_ERR_NOERROR;
-#endif
-
- if (yang2snmp_types(ys, &asn1_type, &cvtype) < 0)
- goto done;
-
- /* see net-snmp/agent/snmp_agent.h / net-snmp/library/snmp.h */
- switch (reqinfo->mode) {
- case MODE_GET: // 160
- requestvb->type = asn1_type; // ASN_NULL on input
-
- /* get xpath: see yang2api_path_fmt / api_path2xpath
- New fn: yang2xpath?
- clicon_rpc_get()
- "
-
- */
-
- if (xml_nsctx_yang(ys, &nsc) < 0)
- goto done;
- if (yang2xpath(ys, &xpath) < 0)
- goto done;
- if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
- goto done;
- if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
- clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
- goto done;
- }
- /* Get value, either from xml, or smiv2 default */
- if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
- valstr = xml_body(x);
- }
- else if ((valstr = sh->sh_default) != NULL)
- ;
- else{
- netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
- goto ok;
- }
- if ((ret = type_yang2snmp(valstr, cvtype, reqinfo, requests, &snmpval, &snmplen)) < 0)
- goto done;
- if (ret == 0)
- goto ok;
-
- /* 1. use cligen object and get rwa buf / size from that, OR
- * + have parse function from YANG
- * - does not have
- * 2. use union netsnmp_vardata and pass that here?
- * 3. Make cv2asn1 conversion function <--
- */
-
- /* see snmplib/snmp_client.c */
- if (snmp_set_var_value(requestvb,
- snmpval,
- snmplen) != 0){
- clicon_err(OE_SNMP, 0, "snmp_set_var_value");
- goto done;
- }
- break;
- case MODE_GETNEXT: // 161
- assert(0); // Not seen?
- break;
- case MODE_SET_RESERVE1: // 0
- if (requestvb->type != asn1_type)
- netsnmp_set_request_error(reqinfo, requests,
- SNMP_ERR_WRONGTYPE);
- break;
-
- case MODE_SET_RESERVE2: // 1
- break;
-
- case MODE_SET_ACTION: // 2
- /*
- * update current
- */
- /* yang2xpath -> xpath2xml
- * accesses = *(requestvb->val.integer);
- * rpc edit-config
-
- */
-
- if ((cb = cbuf_new()) == NULL){
- clicon_err(OE_UNIX, errno, "cbuf_new");
- goto done;
- }
- /*! XXX only int */
- cprintf(cb, "%ld", *requestvb->val.integer);
- if (clicon_rpc_edit_config(h, "candidate", OP_MERGE, cbuf_get(cb)) < 0)
- goto done;
- break;
-
- case MODE_SET_UNDO: // 5
- if (clicon_rpc_discard_changes(h) < 0)
- goto done;
- break;
-
- case MODE_SET_COMMIT: // 3
- if (clicon_rpc_commit(h) < 0)
- goto done;
- break;
- case MODE_SET_FREE: // 4
- /*
- * nothing to do
- */
- break;
- }
- ok:
- retval = SNMP_ERR_NOERROR;
- done:
- if (snmpval)
- free(snmpval);
- if (cb)
- cbuf_free(cb);
- if (xpath)
- free(xpath);
- if (xt)
- xml_free(xt);
- if (nsc)
- xml_nsctx_free(nsc);
- if (cv)
- cv_free(cv);
- return retval;
-}
-#endif
-
/*! Parse smiv2 extensions for YANG container/list
*
* Typical table:
@@ -457,7 +205,10 @@ mib_yang_leaf(clicon_handle h,
}
if (yang_extension_value(ys, "max-access", IETF_YANG_SMIV2_NS, NULL, &modes_str) < 0)
goto done;
-
+#if 0 /* Sanity check of types */
+ if (yang2snmp_types(ys, NULL, NULL) < 0)
+ goto done;
+#endif
/* Get modes (access) read-only, read-write, not-accessible, oaccessible-for-notify
*/
if (modes_str == NULL)
@@ -489,10 +240,8 @@ mib_yang_leaf(clicon_handle h,
memcpy(sh->sh_oid, oid1, sizeof(oid1));
sh->sh_oidlen = sz1;
sh->sh_default = default_str;
- if ((nhreg = netsnmp_handler_registration_create(name,
- handler,
- oid1,
- sz1,
+ if ((nhreg = netsnmp_handler_registration_create(name, handler,
+ oid1, sz1,
modes)) == NULL){
clicon_err(OE_SNMP, errno, "netsnmp_handler_registration_create");
netsnmp_handler_free(handler);
@@ -587,7 +336,7 @@ mib_traverse(clicon_handle h,
* @retval -1 Error
*/
int
-clixon_snmp_mib_yangs(clicon_handle h)
+clixon_snmp_traverse_mibyangs(clicon_handle h)
{
int retval = -1;
char *modname;
diff --git a/apps/snmp/snmp_register.h b/apps/snmp/snmp_register.h
index 17a3ac5d..833f2f83 100644
--- a/apps/snmp/snmp_register.h
+++ b/apps/snmp/snmp_register.h
@@ -43,7 +43,7 @@ extern "C" {
/*
* Prototypes
*/
-int clixon_snmp_mib_yangs(clicon_handle h);
+int clixon_snmp_traverse_mibyangs(clicon_handle h);
#endif /* _SNMP_REGISTER_H_ */
diff --git a/lib/src/clixon_path.c b/lib/src/clixon_path.c
index 2dc2bc83..a8c15dcf 100644
--- a/lib/src/clixon_path.c
+++ b/lib/src/clixon_path.c
@@ -386,6 +386,8 @@ yang2api_path_fmt_1(yang_stmt *ys,
* @param[in] ys Yang statement
* @param[in] inclkey If set include key leaf (eg last leaf d in ex)
* @param[out] api_path_fmt XML api path. Needs to be freed after use.
+ * @retval 0 OK
+ * @retval -1 Error
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
*/
int
@@ -902,7 +904,7 @@ api_path2xpath(char *api_path,
* @param[in] nodeclass Set to schema nodes, data nodes, etc
* @param[in] strict Break if api-path is not "complete" otherwise ignore and continue
* @param[out] xbotp Resulting xml tree
- * @param[out] ybotp Yang spec matching xpathp
+ * @param[out] ybotp Yang spec matching xpathp
* @param[out] xerr Netconf error message (if retval=0)
* @retval 1 OK
* @retval 0 Invalid api_path or associated XML, netconf error
@@ -1144,7 +1146,7 @@ api_path2xml_vec(char **vec,
* @param[in,out] xtop Incoming XML tree
* @param[in] nodeclass Set to schema nodes, data nodes, etc
* @param[in] strict Break if api-path is not "complete" otherwise ignore and continue
- * @param[out] xbotp Resulting xml tree (end of xpath)
+ * @param[out] xbotp Resulting xml tree (end of xpath) (optional)
* @param[out] ybotp Yang spec matching xbotp
* @param[out] xerr Netconf error message (if retval=0)
* @retval 1 OK
diff --git a/test/test_snmp_set.sh b/test/test_snmp_set.sh
index e558bd64..b3afeefe 100755
--- a/test/test_snmp_set.sh
+++ b/test/test_snmp_set.sh
@@ -104,16 +104,17 @@ testinit
# NET-SNMP-EXAMPLES-MIB::netSnmpExamples
MIB=".1.3.6.1.4.1.8072.2"
-OID="${MIB}.1.1" # netSnmpExampleInteger
+OID1="${MIB}.1.1" # netSnmpExampleInteger
+OID3="${MIB}.1.3" # netSnmpExampleString
new "Test SNMP get for default value"
-expectpart "$($snmpget $OID)" 0 "$OID = INTEGER: 42"
+expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 42"
-new "Set new value to OID"
-expectpart "$($snmpset $OID i 1234)" 0 "$OID = INTEGER: 1234"
+new "Set new value to OID1"
+expectpart "$($snmpset $OID1 i 1234)" 0 "$OID1 = INTEGER: 1234"
new "Get new value"
-expectpart "$($snmpget $OID)" 0 "$OID = INTEGER: 1234"
+expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 1234"
new "Set new value via NETCONF"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "none999" "" ""
@@ -122,7 +123,16 @@ new "netconf commit"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "" "" ""
new "Get new value"
-expectpart "$($snmpget $OID)" 0 "$OID = INTEGER: 999"
+expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 999"
+
+new "Test SNMP get string for default value"
+expectpart "$($snmpget $OID3)" 0 "$OID3 = STRING: So long, and thanks for all the fish!."
+
+new "Set new string value to OID3"
+expectpart "$($snmpset $OID3 s foobar)" 0 "$OID3 = STRING: foobar"
+
+new "Get new value"
+expectpart "$($snmpget $OID3)" 0 "$OID3 = STRING: foobar"
new "Cleaning up"
testexit