client messages CHANGE support for NMDA RPCs
diff --git a/src/messages_client.c b/src/messages_client.c
index 064faf4..d6f261f 100644
--- a/src/messages_client.c
+++ b/src/messages_client.c
@@ -514,6 +514,116 @@
     return (struct nc_rpc *)rpc;
 }
 
+API struct nc_rpc *
+nc_rpc_getdata(const char *datastore, const char *filter, const char *config_filter, char **origin_filter,
+               int origin_filter_count, int negated_origin_filter, uint16_t max_depth, int with_origin,
+               NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
+{
+    struct nc_rpc_getdata *rpc = NULL;
+    int i;
+
+    if (filter && filter[0] && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
+        ERR("Filter is neither an XML subtree nor an XPath expression (invalid first char '%c').", filter[0]);
+        return NULL;
+    } else if (!datastore) {
+        ERRARG("datastore");
+        return NULL;
+    }
+
+    rpc = calloc(1, sizeof *rpc);
+    if (!rpc) {
+        ERRMEM;
+        return NULL;
+    }
+    rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+    rpc->type = NC_RPC_GETDATA;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        rpc->datastore = strdup(datastore);
+    } else {
+        rpc->datastore = (char *)datastore;
+    }
+    if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->filter = strdup(filter);
+    } else {
+        rpc->filter = (char *)filter;
+    }
+    if (config_filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->config_filter = strdup(config_filter);
+    } else {
+        rpc->config_filter = (char *)config_filter;
+    }
+    if (origin_filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
+        rpc->origin_filter = malloc(origin_filter_count * sizeof *rpc->origin_filter);
+        if (!rpc->origin_filter) {
+            ERRMEM;
+            goto error;
+        }
+        for (i = 0; i < origin_filter_count; ++i) {
+            rpc->origin_filter[i] = strdup(origin_filter[i]);
+            if (!rpc->origin_filter[i]) {
+                ERRMEM;
+                goto error;
+            }
+            ++rpc->origin_filter_count;
+        }
+    } else {
+        rpc->origin_filter = origin_filter;
+        rpc->origin_filter_count = origin_filter_count;
+    }
+    rpc->negated_origin_filter = negated_origin_filter;
+    rpc->max_depth = max_depth;
+    rpc->with_origin = with_origin;
+    rpc->wd_mode = wd_mode;
+
+    return (struct nc_rpc *)rpc;
+
+error:
+    nc_rpc_free((struct nc_rpc *)rpc);
+    return NULL;
+}
+
+API struct nc_rpc *
+nc_rpc_editdata(const char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char *edit_content, NC_PARAMTYPE paramtype)
+{
+    struct nc_rpc_editdata *rpc;
+
+    if (!datastore) {
+        ERRARG("datastore");
+        return NULL;
+    } else if (!edit_content) {
+        ERRARG("edit_content");
+        return NULL;
+    }
+
+    if (edit_content[0] && (edit_content[0] != '<') && !isalpha(edit_content[0])) {
+        ERR("<edit-data> content is neither a URL nor an XML config (invalid first char '%c').", edit_content[0]);
+        return NULL;
+    }
+
+    rpc = malloc(sizeof *rpc);
+    if (!rpc) {
+        ERRMEM;
+        return NULL;
+    }
+
+    rpc->type = NC_RPC_EDITDATA;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        rpc->datastore = strdup(datastore);
+    } else {
+        rpc->datastore = (char *)datastore;
+    }
+    rpc->default_op = default_op;
+    if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
+        rpc->edit_cont = strdup(edit_content);
+    } else {
+        rpc->edit_cont = (char *)edit_content;
+    }
+    rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
+
+    return (struct nc_rpc *)rpc;
+}
+
 API void
 nc_rpc_free(struct nc_rpc *rpc)
 {
@@ -528,6 +638,9 @@
     struct nc_rpc_validate *rpc_validate;
     struct nc_rpc_getschema *rpc_getschema;
     struct nc_rpc_subscribe *rpc_subscribe;
+    struct nc_rpc_getdata *rpc_getdata;
+    struct nc_rpc_editdata *rpc_editdata;
+    int i;
 
     if (!rpc) {
         return;
@@ -611,6 +724,25 @@
             free(rpc_subscribe->stop);
         }
         break;
+    case NC_RPC_GETDATA:
+        rpc_getdata = (struct nc_rpc_getdata *)rpc;
+        if (rpc_getdata->free) {
+            free(rpc_getdata->datastore);
+            free(rpc_getdata->filter);
+            free(rpc_getdata->config_filter);
+            for (i = 0; i < rpc_getdata->origin_filter_count; ++i) {
+                free(rpc_getdata->origin_filter[i]);
+            }
+            free(rpc_getdata->origin_filter);
+        }
+        break;
+    case NC_RPC_EDITDATA:
+        rpc_editdata = (struct nc_rpc_editdata *)rpc;
+        if (rpc_editdata->free) {
+            free(rpc_editdata->datastore);
+            free(rpc_editdata->edit_cont);
+        }
+        break;
     default:
         /* nothing special needed */
         break;
diff --git a/src/messages_client.h b/src/messages_client.h
index f597ee6..33df282 100644
--- a/src/messages_client.h
+++ b/src/messages_client.h
@@ -59,7 +59,11 @@
     NC_RPC_GETSCHEMA,   /**< \<get-schema\> RPC. */
 
     /* notifications */
-    NC_RPC_SUBSCRIBE    /**< \<create-subscription\> RPC. */
+    NC_RPC_SUBSCRIBE,   /**< \<create-subscription\> RPC. */
+
+    /* ietf-netconf-nmda */
+    NC_RPC_GETDATA,     /**< \<get-data\> RPC. */
+    NC_RPC_EDITDATA,    /**< \<edit-data\> RPC. */
 } NC_RPC_TYPE;
 
 /**
@@ -443,6 +447,49 @@
                                 const char *stop_time, NC_PARAMTYPE paramtype);
 
 /**
+ * @brief Create NETCONF RPC \<get-data\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (#nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
+ * @param[in] filter Optional filter data, an XML subtree or XPath expression (with JSON prefixes).
+ * @param[in] config_filter Optional config filter, "true" for config-only data, "false" for state-only data.
+ * @param[in] origin_filter Optional origin filter array, selects only nodes of this or derived origin.
+ * @param[in] origin_filter_count Count of filters is \p origin_filter.
+ * @param[in] neg_origin_filter Whether origin filters are negated or not.
+ * @param[in] max_depth Maximum depth of returned subtrees, 0 for unlimited.
+ * @param[in] with_origin Whether return data origin.
+ * @param[in] wd_mode Optional with-defaults capability mode.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_getdata(const char *datastore, const char *filter, const char *config_filter, char **origin_filter,
+                              int origin_filter_count, int neg_origin_filter, uint16_t max_depth, int with_origin,
+                              NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype);
+
+/**
+ * @brief Create NETCONF RPC \<get-data\>
+ *
+ * Note that functions to create any RPC object do not check validity of the provided
+ * parameters. It is checked later while sending the RPC via a specific NETCONF session
+ * (#nc_send_rpc()) since the NETCONF capabilities of the session are needed for such a
+ * check. Created object can be sent via any NETCONF session which supports all the
+ * needed NETCONF capabilities for the RPC.
+ *
+ * @param[in] datastore Source datastore, foreign identity so a module name prefix is required.
+ * @param[in] default_op Optional default operation.
+ * @param[in] edit_content Config or URL where the config to perform is to be found.
+ * @param[in] paramtype How to further manage data parameters.
+ * @return Created RPC object to send via a NETCONF session or NULL in case of (memory allocation) error.
+ */
+struct nc_rpc *nc_rpc_editdata(const char *datastore, NC_RPC_EDIT_DFLTOP default_op, const char *edit_content,
+                               NC_PARAMTYPE paramtype);
+
+/**
  * @brief Free the NETCONF RPC object.
  *
  * @param[in] rpc Object to free.
diff --git a/src/messages_p.h b/src/messages_p.h
index a4b04b6..9825203 100644
--- a/src/messages_p.h
+++ b/src/messages_p.h
@@ -186,6 +186,28 @@
     char free;
 };
 
+struct nc_rpc_getdata {
+    NC_RPC_TYPE type;        /**< NC_RPC_GETDATA */
+    char *datastore;         /**< target datastore identity */
+    char *filter;            /**< either XML subtree (starts with '<') or an XPath (starts with '/' or an alpha) */
+    char *config_filter;     /**< config filter ("true"/"false") */
+    char **origin_filter;    /**< origin filters */
+    int origin_filter_count; /**< origin filter count */
+    int negated_origin_filter; /**< whether origin filter is negated or not */
+    int max_depth;           /**< max depth of returned subtrees, 0 for unlimited */
+    int with_origin;         /**< whether to return origin of data */
+    NC_WD_MODE wd_mode;
+    char free;
+};
+
+struct nc_rpc_editdata {
+    NC_RPC_TYPE type;        /**< NC_RPC_EDITDATA */
+    char *datastore;         /**< target datastore identity */
+    NC_RPC_EDIT_DFLTOP default_op;
+    char *edit_cont;         /**< either URL (starts with aplha) or config (starts with '<') */
+    char free;
+};
+
 void nc_server_rpc_free(struct nc_server_rpc *rpc, struct ly_ctx *ctx);
 
 void nc_client_err_clean(struct nc_err *err, struct ly_ctx *ctx);
diff --git a/src/session_client.c b/src/session_client.c
index caf1947..83abb92 100644
--- a/src/session_client.c
+++ b/src/session_client.c
@@ -1752,6 +1752,7 @@
 
         case NC_RPC_GETCONFIG:
         case NC_RPC_GET:
+        case NC_RPC_GETDATA:
             /* we should definitely have received at least an empty "data" element even on empty reply, but fine */
             if (!xml->child || !xml->child->child) {
                 /* we did not receive any data */
@@ -1796,6 +1797,7 @@
         case NC_RPC_CANCEL:
         case NC_RPC_VALIDATE:
         case NC_RPC_SUBSCRIBE:
+        case NC_RPC_EDITDATA:
             /* there is no output defined */
             ERR("Unexpected data reply (root elem \"%s\").", xml->child ? xml->child->name : NULL);
             return NULL;
@@ -1823,7 +1825,7 @@
                 return NULL;
             }
         } else {
-            /* <get>, <get-config> */
+            /* <get>, <get-config>, <get-data> */
             data_rpl->data = data;
         }
         lyd_free_withsiblings(rpc_act);
@@ -2260,8 +2262,11 @@
     struct nc_rpc_validate *rpc_val;
     struct nc_rpc_getschema *rpc_gs;
     struct nc_rpc_subscribe *rpc_sub;
+    struct nc_rpc_getdata *rpc_getd;
+    struct nc_rpc_editdata *rpc_editd;
     struct lyd_node *data, *node;
-    const struct lys_module *ietfnc = NULL, *ietfncmon, *notifs, *ietfncwd = NULL;
+    const struct lys_module *mod = NULL, *ietfncwd;
+    int i;
     char str[11];
     uint64_t cur_msgid;
 
@@ -2279,12 +2284,53 @@
         return NC_MSG_ERROR;
     }
 
-    if ((rpc->type != NC_RPC_GETSCHEMA) && (rpc->type != NC_RPC_ACT_GENERIC) && (rpc->type != NC_RPC_SUBSCRIBE)) {
-        ietfnc = ly_ctx_get_module(session->ctx, "ietf-netconf", NULL, 1);
-        if (!ietfnc) {
+    switch (rpc->type) {
+    case NC_RPC_ACT_GENERIC:
+        /* checked when parsing */
+        break;
+    case NC_RPC_GETCONFIG:
+    case NC_RPC_EDIT:
+    case NC_RPC_COPY:
+    case NC_RPC_DELETE:
+    case NC_RPC_LOCK:
+    case NC_RPC_UNLOCK:
+    case NC_RPC_GET:
+    case NC_RPC_KILL:
+    case NC_RPC_COMMIT:
+    case NC_RPC_DISCARD:
+    case NC_RPC_CANCEL:
+    case NC_RPC_VALIDATE:
+        mod = ly_ctx_get_module(session->ctx, "ietf-netconf", NULL, 1);
+        if (!mod) {
             ERR("Session %u: missing \"ietf-netconf\" schema in the context.", session->id);
             return NC_MSG_ERROR;
         }
+        break;
+    case NC_RPC_GETSCHEMA:
+        mod = ly_ctx_get_module(session->ctx, "ietf-netconf-monitoring", NULL, 1);
+        if (!mod) {
+            ERR("Session %u: missing \"ietf-netconf-monitoring\" schema in the context.", session->id);
+            return NC_MSG_ERROR;
+        }
+        break;
+    case NC_RPC_SUBSCRIBE:
+        mod = ly_ctx_get_module(session->ctx, "notifications", NULL, 1);
+        if (!mod) {
+            ERR("Session %u: missing \"notifications\" schema in the context.", session->id);
+            return NC_MSG_ERROR;
+        }
+        break;
+    case NC_RPC_GETDATA:
+    case NC_RPC_EDITDATA:
+        mod = ly_ctx_get_module(session->ctx, "ietf-netconf-nmda", NULL, 1);
+        if (!mod) {
+            ERR("Session %u: missing \"ietf-netconf-nmda\" schema in the context.", session->id);
+            return NC_MSG_ERROR;
+        }
+        break;
+    case NC_RPC_UNKNOWN:
+        ERRINT;
+        return NC_MSG_ERROR;
     }
 
     switch (rpc->type) {
@@ -2306,19 +2352,19 @@
     case NC_RPC_GETCONFIG:
         rpc_gc = (struct nc_rpc_getconfig *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "get-config");
-        node = lyd_new(data, ietfnc, "source");
-        node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_gc->source], NULL);
+        data = lyd_new(NULL, mod, "get-config");
+        node = lyd_new(data, mod, "source");
+        node = lyd_new_leaf(node, mod, ncds2str[rpc_gc->source], NULL);
         if (!node) {
             lyd_free(data);
             return NC_MSG_ERROR;
         }
         if (rpc_gc->filter) {
             if (!rpc_gc->filter[0] || (rpc_gc->filter[0] == '<')) {
-                node = lyd_new_anydata(data, ietfnc, "filter", rpc_gc->filter, LYD_ANYDATA_SXML);
+                node = lyd_new_anydata(data, mod, "filter", rpc_gc->filter, LYD_ANYDATA_SXML);
                 lyd_insert_attr(node, NULL, "type", "subtree");
             } else {
-                node = lyd_new_anydata(data, ietfnc, "filter", NULL, LYD_ANYDATA_CONSTSTRING);
+                node = lyd_new_anydata(data, mod, "filter", NULL, LYD_ANYDATA_CONSTSTRING);
                 lyd_insert_attr(node, NULL, "type", "xpath");
                 lyd_insert_attr(node, NULL, "select", rpc_gc->filter);
             }
@@ -2329,12 +2375,11 @@
         }
 
         if (rpc_gc->wd_mode) {
+            ietfncwd = ly_ctx_get_module(session->ctx, "ietf-netconf-with-defaults", NULL, 1);
             if (!ietfncwd) {
-                ietfncwd = ly_ctx_get_module(session->ctx, "ietf-netconf-with-defaults", NULL, 1);
-                if (!ietfncwd) {
-                    ERR("Session %u: missing \"ietf-netconf-with-defaults\" schema in the context.", session->id);
-                    return NC_MSG_ERROR;
-                }
+                ERR("Session %u: missing \"ietf-netconf-with-defaults\" schema in the context.", session->id);
+                lyd_free(data);
+                return NC_MSG_ERROR;
             }
             switch (rpc_gc->wd_mode) {
             case NC_WD_UNKNOWN:
@@ -2363,16 +2408,16 @@
     case NC_RPC_EDIT:
         rpc_e = (struct nc_rpc_edit *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "edit-config");
-        node = lyd_new(data, ietfnc, "target");
-        node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_e->target], NULL);
+        data = lyd_new(NULL, mod, "edit-config");
+        node = lyd_new(data, mod, "target");
+        node = lyd_new_leaf(node, mod, ncds2str[rpc_e->target], NULL);
         if (!node) {
             lyd_free(data);
             return NC_MSG_ERROR;
         }
 
         if (rpc_e->default_op) {
-            node = lyd_new_leaf(data, ietfnc, "default-operation", rpcedit_dfltop2str[rpc_e->default_op]);
+            node = lyd_new_leaf(data, mod, "default-operation", rpcedit_dfltop2str[rpc_e->default_op]);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2380,7 +2425,7 @@
         }
 
         if (rpc_e->test_opt) {
-            node = lyd_new_leaf(data, ietfnc, "test-option", rpcedit_testopt2str[rpc_e->test_opt]);
+            node = lyd_new_leaf(data, mod, "test-option", rpcedit_testopt2str[rpc_e->test_opt]);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2388,7 +2433,7 @@
         }
 
         if (rpc_e->error_opt) {
-            node = lyd_new_leaf(data, ietfnc, "error-option", rpcedit_erropt2str[rpc_e->error_opt]);
+            node = lyd_new_leaf(data, mod, "error-option", rpcedit_erropt2str[rpc_e->error_opt]);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2396,9 +2441,9 @@
         }
 
         if (!rpc_e->edit_cont[0] || (rpc_e->edit_cont[0] == '<')) {
-            node = lyd_new_anydata(data, ietfnc, "config", rpc_e->edit_cont, LYD_ANYDATA_SXML);
+            node = lyd_new_anydata(data, mod, "config", rpc_e->edit_cont, LYD_ANYDATA_SXML);
         } else {
-            node = lyd_new_leaf(data, ietfnc, "url", rpc_e->edit_cont);
+            node = lyd_new_leaf(data, mod, "url", rpc_e->edit_cont);
         }
         if (!node) {
             lyd_free(data);
@@ -2409,27 +2454,27 @@
     case NC_RPC_COPY:
         rpc_cp = (struct nc_rpc_copy *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "copy-config");
-        node = lyd_new(data, ietfnc, "target");
+        data = lyd_new(NULL, mod, "copy-config");
+        node = lyd_new(data, mod, "target");
         if (rpc_cp->url_trg) {
-            node = lyd_new_leaf(node, ietfnc, "url", rpc_cp->url_trg);
+            node = lyd_new_leaf(node, mod, "url", rpc_cp->url_trg);
         } else {
-            node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_cp->target], NULL);
+            node = lyd_new_leaf(node, mod, ncds2str[rpc_cp->target], NULL);
         }
         if (!node) {
             lyd_free(data);
             return NC_MSG_ERROR;
         }
 
-        node = lyd_new(data, ietfnc, "source");
+        node = lyd_new(data, mod, "source");
         if (rpc_cp->url_config_src) {
             if (!rpc_cp->url_config_src[0] || (rpc_cp->url_config_src[0] == '<')) {
-                node = lyd_new_anydata(node, ietfnc, "config", rpc_cp->url_config_src, LYD_ANYDATA_SXML);
+                node = lyd_new_anydata(node, mod, "config", rpc_cp->url_config_src, LYD_ANYDATA_SXML);
             } else {
-                node = lyd_new_leaf(node, ietfnc, "url", rpc_cp->url_config_src);
+                node = lyd_new_leaf(node, mod, "url", rpc_cp->url_config_src);
             }
         } else {
-            node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_cp->source], NULL);
+            node = lyd_new_leaf(node, mod, ncds2str[rpc_cp->source], NULL);
         }
         if (!node) {
             lyd_free(data);
@@ -2437,12 +2482,11 @@
         }
 
         if (rpc_cp->wd_mode) {
+            ietfncwd = ly_ctx_get_module(session->ctx, "ietf-netconf-with-defaults", NULL, 1);
             if (!ietfncwd) {
-                ietfncwd = ly_ctx_get_module(session->ctx, "ietf-netconf-with-defaults", NULL, 1);
-                if (!ietfncwd) {
-                    ERR("Session %u: missing \"ietf-netconf-with-defaults\" schema in the context.", session->id);
-                    return NC_MSG_ERROR;
-                }
+                ERR("Session %u: missing \"ietf-netconf-with-defaults\" schema in the context.", session->id);
+                lyd_free(data);
+                return NC_MSG_ERROR;
             }
             switch (rpc_cp->wd_mode) {
             case NC_WD_UNKNOWN:
@@ -2471,12 +2515,12 @@
     case NC_RPC_DELETE:
         rpc_del = (struct nc_rpc_delete *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "delete-config");
-        node = lyd_new(data, ietfnc, "target");
+        data = lyd_new(NULL, mod, "delete-config");
+        node = lyd_new(data, mod, "target");
         if (rpc_del->url) {
-            node = lyd_new_leaf(node, ietfnc, "url", rpc_del->url);
+            node = lyd_new_leaf(node, mod, "url", rpc_del->url);
         } else {
-            node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_del->target], NULL);
+            node = lyd_new_leaf(node, mod, ncds2str[rpc_del->target], NULL);
         }
         if (!node) {
             lyd_free(data);
@@ -2487,9 +2531,9 @@
     case NC_RPC_LOCK:
         rpc_lock = (struct nc_rpc_lock *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "lock");
-        node = lyd_new(data, ietfnc, "target");
-        node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_lock->target], NULL);
+        data = lyd_new(NULL, mod, "lock");
+        node = lyd_new(data, mod, "target");
+        node = lyd_new_leaf(node, mod, ncds2str[rpc_lock->target], NULL);
         if (!node) {
             lyd_free(data);
             return NC_MSG_ERROR;
@@ -2499,9 +2543,9 @@
     case NC_RPC_UNLOCK:
         rpc_lock = (struct nc_rpc_lock *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "unlock");
-        node = lyd_new(data, ietfnc, "target");
-        node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_lock->target], NULL);
+        data = lyd_new(NULL, mod, "unlock");
+        node = lyd_new(data, mod, "target");
+        node = lyd_new_leaf(node, mod, ncds2str[rpc_lock->target], NULL);
         if (!node) {
             lyd_free(data);
             return NC_MSG_ERROR;
@@ -2511,13 +2555,13 @@
     case NC_RPC_GET:
         rpc_g = (struct nc_rpc_get *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "get");
+        data = lyd_new(NULL, mod, "get");
         if (rpc_g->filter) {
             if (!rpc_g->filter[0] || (rpc_g->filter[0] == '<')) {
-                node = lyd_new_anydata(data, ietfnc, "filter", rpc_g->filter, LYD_ANYDATA_SXML);
+                node = lyd_new_anydata(data, mod, "filter", rpc_g->filter, LYD_ANYDATA_SXML);
                 lyd_insert_attr(node, NULL, "type", "subtree");
             } else {
-                node = lyd_new_anydata(data, ietfnc, "filter", NULL, LYD_ANYDATA_CONSTSTRING);
+                node = lyd_new_anydata(data, mod, "filter", NULL, LYD_ANYDATA_CONSTSTRING);
                 lyd_insert_attr(node, NULL, "type", "xpath");
                 lyd_insert_attr(node, NULL, "select", rpc_g->filter);
             }
@@ -2528,13 +2572,11 @@
         }
 
         if (rpc_g->wd_mode) {
+            ietfncwd = ly_ctx_get_module(session->ctx, "ietf-netconf-with-defaults", NULL, 1);
             if (!ietfncwd) {
-                ietfncwd = ly_ctx_get_module(session->ctx, "ietf-netconf-with-defaults", NULL, 1);
-                if (!ietfncwd) {
-                    ERR("Session %u: missing \"ietf-netconf-with-defaults\" schema in the context.", session->id);
-                    lyd_free(data);
-                    return NC_MSG_ERROR;
-                }
+                ERR("Session %u: missing \"ietf-netconf-with-defaults\" schema in the context.", session->id);
+                lyd_free(data);
+                return NC_MSG_ERROR;
             }
             switch (rpc_g->wd_mode) {
             case NC_WD_ALL:
@@ -2564,26 +2606,26 @@
     case NC_RPC_KILL:
         rpc_k = (struct nc_rpc_kill *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "kill-session");
+        data = lyd_new(NULL, mod, "kill-session");
         sprintf(str, "%u", rpc_k->sid);
-        lyd_new_leaf(data, ietfnc, "session-id", str);
+        lyd_new_leaf(data, mod, "session-id", str);
         break;
 
     case NC_RPC_COMMIT:
         rpc_com = (struct nc_rpc_commit *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "commit");
+        data = lyd_new(NULL, mod, "commit");
         if (rpc_com->confirmed) {
-            lyd_new_leaf(data, ietfnc, "confirmed", NULL);
+            lyd_new_leaf(data, mod, "confirmed", NULL);
         }
 
         if (rpc_com->confirm_timeout) {
             sprintf(str, "%u", rpc_com->confirm_timeout);
-            lyd_new_leaf(data, ietfnc, "confirm-timeout", str);
+            lyd_new_leaf(data, mod, "confirm-timeout", str);
         }
 
         if (rpc_com->persist) {
-            node = lyd_new_leaf(data, ietfnc, "persist", rpc_com->persist);
+            node = lyd_new_leaf(data, mod, "persist", rpc_com->persist);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2591,7 +2633,7 @@
         }
 
         if (rpc_com->persist_id) {
-            node = lyd_new_leaf(data, ietfnc, "persist-id", rpc_com->persist_id);
+            node = lyd_new_leaf(data, mod, "persist-id", rpc_com->persist_id);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2600,15 +2642,15 @@
         break;
 
     case NC_RPC_DISCARD:
-        data = lyd_new(NULL, ietfnc, "discard-changes");
+        data = lyd_new(NULL, mod, "discard-changes");
         break;
 
     case NC_RPC_CANCEL:
         rpc_can = (struct nc_rpc_cancel *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "cancel-commit");
+        data = lyd_new(NULL, mod, "cancel-commit");
         if (rpc_can->persist_id) {
-            node = lyd_new_leaf(data, ietfnc, "persist-id", rpc_can->persist_id);
+            node = lyd_new_leaf(data, mod, "persist-id", rpc_can->persist_id);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2619,16 +2661,16 @@
     case NC_RPC_VALIDATE:
         rpc_val = (struct nc_rpc_validate *)rpc;
 
-        data = lyd_new(NULL, ietfnc, "validate");
-        node = lyd_new(data, ietfnc, "source");
+        data = lyd_new(NULL, mod, "validate");
+        node = lyd_new(data, mod, "source");
         if (rpc_val->url_config_src) {
             if (!rpc_val->url_config_src[0] || (rpc_val->url_config_src[0] == '<')) {
-                node = lyd_new_anydata(node, ietfnc, "config", rpc_val->url_config_src, LYD_ANYDATA_SXML);
+                node = lyd_new_anydata(node, mod, "config", rpc_val->url_config_src, LYD_ANYDATA_SXML);
             } else {
-                node = lyd_new_leaf(node, ietfnc, "url", rpc_val->url_config_src);
+                node = lyd_new_leaf(node, mod, "url", rpc_val->url_config_src);
             }
         } else {
-            node = lyd_new_leaf(node, ietfnc, ncds2str[rpc_val->source], NULL);
+            node = lyd_new_leaf(node, mod, ncds2str[rpc_val->source], NULL);
         }
         if (!node) {
             lyd_free(data);
@@ -2637,29 +2679,23 @@
         break;
 
     case NC_RPC_GETSCHEMA:
-        ietfncmon = ly_ctx_get_module(session->ctx, "ietf-netconf-monitoring", NULL, 1);
-        if (!ietfncmon) {
-            ERR("Session %u: missing \"ietf-netconf-monitoring\" schema in the context.", session->id);
-            return NC_MSG_ERROR;
-        }
-
         rpc_gs = (struct nc_rpc_getschema *)rpc;
 
-        data = lyd_new(NULL, ietfncmon, "get-schema");
-        node = lyd_new_leaf(data, ietfncmon, "identifier", rpc_gs->identifier);
+        data = lyd_new(NULL, mod, "get-schema");
+        node = lyd_new_leaf(data, mod, "identifier", rpc_gs->identifier);
         if (!node) {
             lyd_free(data);
             return NC_MSG_ERROR;
         }
         if (rpc_gs->version) {
-            node = lyd_new_leaf(data, ietfncmon, "version", rpc_gs->version);
+            node = lyd_new_leaf(data, mod, "version", rpc_gs->version);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
             }
         }
         if (rpc_gs->format) {
-            node = lyd_new_leaf(data, ietfncmon, "format", rpc_gs->format);
+            node = lyd_new_leaf(data, mod, "format", rpc_gs->format);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2668,17 +2704,11 @@
         break;
 
     case NC_RPC_SUBSCRIBE:
-        notifs = ly_ctx_get_module(session->ctx, "notifications", NULL, 1);
-        if (!notifs) {
-            ERR("Session %u: missing \"notifications\" schema in the context.", session->id);
-            return NC_MSG_ERROR;
-        }
-
         rpc_sub = (struct nc_rpc_subscribe *)rpc;
 
-        data = lyd_new(NULL, notifs, "create-subscription");
+        data = lyd_new(NULL, mod, "create-subscription");
         if (rpc_sub->stream) {
-            node = lyd_new_leaf(data, notifs, "stream", rpc_sub->stream);
+            node = lyd_new_leaf(data, mod, "stream", rpc_sub->stream);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2687,10 +2717,10 @@
 
         if (rpc_sub->filter) {
             if (!rpc_sub->filter[0] || (rpc_sub->filter[0] == '<')) {
-                node = lyd_new_anydata(data, notifs, "filter", rpc_sub->filter, LYD_ANYDATA_SXML);
+                node = lyd_new_anydata(data, mod, "filter", rpc_sub->filter, LYD_ANYDATA_SXML);
                 lyd_insert_attr(node, NULL, "type", "subtree");
             } else {
-                node = lyd_new_anydata(data, notifs, "filter", NULL, LYD_ANYDATA_CONSTSTRING);
+                node = lyd_new_anydata(data, mod, "filter", NULL, LYD_ANYDATA_CONSTSTRING);
                 lyd_insert_attr(node, NULL, "type", "xpath");
                 lyd_insert_attr(node, NULL, "select", rpc_sub->filter);
             }
@@ -2701,7 +2731,7 @@
         }
 
         if (rpc_sub->start) {
-            node = lyd_new_leaf(data, notifs, "startTime", rpc_sub->start);
+            node = lyd_new_leaf(data, mod, "startTime", rpc_sub->start);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
@@ -2709,13 +2739,125 @@
         }
 
         if (rpc_sub->stop) {
-            node = lyd_new_leaf(data, notifs, "stopTime", rpc_sub->stop);
+            node = lyd_new_leaf(data, mod, "stopTime", rpc_sub->stop);
             if (!node) {
                 lyd_free(data);
                 return NC_MSG_ERROR;
             }
         }
         break;
+
+    case NC_RPC_GETDATA:
+        rpc_getd = (struct nc_rpc_getdata *)rpc;
+
+        data = lyd_new(NULL, mod, "get-data");
+        node = lyd_new_leaf(data, mod, "datastore", rpc_getd->datastore);
+        if (!node) {
+            lyd_free(data);
+            return NC_MSG_ERROR;
+        }
+        if (rpc_getd->filter) {
+            if (!rpc_getd->filter[0] || (rpc_getd->filter[0] == '<')) {
+                node = lyd_new_anydata(data, mod, "subtree-filter", rpc_getd->filter, LYD_ANYDATA_SXML);
+            } else {
+                node = lyd_new_leaf(data, mod, "xpath-filter", rpc_getd->filter);
+            }
+            if (!node) {
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+        }
+        if (rpc_getd->config_filter) {
+            node = lyd_new_leaf(data, mod, "config-filter", rpc_getd->config_filter);
+            if (!node) {
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+        }
+        for (i = 0; i < rpc_getd->origin_filter_count; ++i) {
+            node = lyd_new_leaf(data, mod, rpc_getd->negated_origin_filter ? "negated-origin-filter" : "origin-filter",
+                                rpc_getd->origin_filter[i]);
+            if (!node) {
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+        }
+        if (rpc_getd->max_depth) {
+            sprintf(str, "%u", rpc_getd->max_depth);
+            node = lyd_new_leaf(data, mod, "max-depth", str);
+            if (!node) {
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+        }
+        if (rpc_getd->with_origin) {
+            node = lyd_new_leaf(data, mod, "with-origin", NULL);
+            if (!node) {
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+        }
+
+        if (rpc_getd->wd_mode) {
+            ietfncwd = ly_ctx_get_module(session->ctx, "ietf-netconf-with-defaults", NULL, 1);
+            if (!ietfncwd) {
+                ERR("Session %u: missing \"ietf-netconf-with-defaults\" schema in the context.", session->id);
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+            switch (rpc_getd->wd_mode) {
+            case NC_WD_UNKNOWN:
+                /* cannot get here */
+                break;
+            case NC_WD_ALL:
+                node = lyd_new_leaf(data, ietfncwd, "with-defaults", "report-all");
+                break;
+            case NC_WD_ALL_TAG:
+                node = lyd_new_leaf(data, ietfncwd, "with-defaults", "report-all-tagged");
+                break;
+            case NC_WD_TRIM:
+                node = lyd_new_leaf(data, ietfncwd, "with-defaults", "trim");
+                break;
+            case NC_WD_EXPLICIT:
+                node = lyd_new_leaf(data, ietfncwd, "with-defaults", "explicit");
+                break;
+            }
+            if (!node) {
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+        }
+        break;
+
+    case NC_RPC_EDITDATA:
+        rpc_editd = (struct nc_rpc_editdata *)rpc;
+
+        data = lyd_new(NULL, mod, "edit-data");
+        node = lyd_new_leaf(data, mod, "datastore", rpc_editd->datastore);
+        if (!node) {
+            lyd_free(data);
+            return NC_MSG_ERROR;
+        }
+
+        if (rpc_editd->default_op) {
+            node = lyd_new_leaf(data, mod, "default-operation", rpcedit_dfltop2str[rpc_editd->default_op]);
+            if (!node) {
+                lyd_free(data);
+                return NC_MSG_ERROR;
+            }
+        }
+
+        if (!rpc_editd->edit_cont[0] || (rpc_editd->edit_cont[0] == '<')) {
+            node = lyd_new_anydata(data, mod, "config", rpc_editd->edit_cont, LYD_ANYDATA_SXML);
+        } else {
+            node = lyd_new_leaf(data, mod, "url", rpc_editd->edit_cont);
+        }
+        if (!node) {
+            lyd_free(data);
+            return NC_MSG_ERROR;
+        }
+        break;
+
     default:
         ERRINT;
         return NC_MSG_ERROR;