diff --git a/README.md b/README.md
index 45d39417ccbfdd872092ad05b0f60951a05736eb..d2d3375a0121e84589249006a29aba9adcf8887c 100644
--- a/README.md
+++ b/README.md
@@ -1025,7 +1025,43 @@ root@iopsys:~# ubus call usp.raw list_inform
 
 root@iopsys:~# ubus call usp.raw init_notify '{"proto":"cwmp", "amd_version":5, "instance_mode": 0}'
 root@iopsys:~#
-
+root@iopsys:~# ubus call usp set '{"path":"Device.Users.User.[Username==\"xyz1\"].", "values":{"Username":"xyz1", "Enable":"dummy", "Password":"yzssssx"}, "proto":"usp"}'
+{
+	"parameters": [
+		{
+			"path": "Device.Users.User.2.Username",
+			"status": true
+		},
+		{
+			"path": "Device.Users.User.2.Enable",
+			"status": false,
+			"fault": 7012
+		},
+		{
+			"path": "Device.Users.User.2.Password",
+			"status": true
+		}
+	]
+}
+root@iopsys:~#
+root@iopsys:~# ubus call usp.raw setm_values '{"pv_tuple":[{"path":"Device.Users.User.2.Username", "value":"xzzz"}, {"path":"Device.Users.User.2.RemoteAccessCapable", "value":"2"}, {"path":"Device.Users.User.2.Password", "value":"zzzzzzz"}], "proto":"usp"}'
+{
+	"parameters": [
+		{
+			"path": "Device.Users.User.2.Username",
+			"status": true
+		},
+		{
+			"path": "Device.Users.User.2.RemoteAccessCapable",
+			"status": false,
+			"fault": 7012
+		},
+		{
+			"path": "Device.Users.User.2.Password",
+			"status": true
+		}
+	]
+}
 ````
 
 - For more info on the usp ubus API see [link](./docs/api/usp.md)
diff --git a/src/add_delete.h b/src/add_delete.h
index 085d4c6fe05e8fd1cccc4f8699efbc358ad287e7..f5cef531f5c305a0de5e8f6dff1c0722642502ca 100644
--- a/src/add_delete.h
+++ b/src/add_delete.h
@@ -1,5 +1,14 @@
 #ifndef ADD_DEL_H
 #define ADD_DEL_H
+
+enum {
+	DM_ADD_PATH,
+	DM_ADD_PROTO,
+	DM_ADD_PARAMETER_KEY,
+	DM_ADD_INSTANCE,
+	__DM_ADD_MAX
+};
+
 void create_add_response(usp_data_t *data, struct blob_buf *bb);
 void create_del_response(usp_data_t *data, struct blob_buf *bb);
 #endif /* ADD_DEL_H */
diff --git a/src/get.h b/src/get.h
index 02c5ee895afb581812e706915f15a3fbfc9ec955..a602a68d9659ed134676d993ccba4757ef8f26eb 100644
--- a/src/get.h
+++ b/src/get.h
@@ -2,6 +2,23 @@
 #define GET_H
 #include "common.h"
 
+enum {
+	DM_GET_PATH,
+	DM_GET_PROTO,
+	DM_GET_MAXDEPTH,
+	DM_GET_NXT_LVL,
+	DM_GET_INSTANCE,
+	__DM_GET_MAX
+};
+
+enum {
+	DM_GET_SAFE_PATHS,
+	DM_GET_SAFE_PROTO,
+	DM_GET_SAFE_NXT_LVL,
+	DM_GET_SAFE_INSTANCE,
+	__DM_GET_SAFE_MAX
+};
+
 void usp_validate_path(usp_data_t *data);
 void usp_get_value(usp_data_t *data);
 void usp_get_instance(usp_data_t *data);
diff --git a/src/set.c b/src/set.c
index 42673593ce52ae9e56a4112b75a13b7f350a10a8..405ec0b0f4506122721a6a49e4b48188f5f54f2e 100644
--- a/src/set.c
+++ b/src/set.c
@@ -28,15 +28,17 @@
 #include <libbbfdm/dmentry.h>
 
 
+static const struct blobmsg_policy dm_setm_value_policy[]= {
+	[DM_SET_V_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+	[DM_SET_V_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
+	[DM_SET_V_KEY] = { .name = "key", .type = BLOBMSG_TYPE_STRING },
+};
+
 void usp_set_value(usp_data_t *data)
 {
 	struct blob_buf bb;
 	struct ubus_context *ctx;
 	struct ubus_request_data *req;
-	char *qpath;
-	struct list_head *val_pv_list;
-	char *key;
-	char temp[MAX_DM_PATH] = {0};
 	void *array;
 	struct pathNode *rv;
 	struct pvNode *pv;
@@ -51,9 +53,6 @@ void usp_set_value(usp_data_t *data)
 
 	ctx = data->ctx;
 	req = data->req;
-	qpath = data->qpath;
-	val_pv_list = data->pv_list;
-	key = data->set_key;
 
 	LIST_HEAD(resolved_paths);
 
@@ -80,23 +79,27 @@ void usp_set_value(usp_data_t *data)
 		return;
 	}
 
-	fault = get_resolved_paths(&bbf_ctx, qpath, &resolved_paths);
-	if (fault) {
-		fill_err_code(&bb, fault);
-	} else {
-		array = blobmsg_open_array(&bb, "parameters");
-		list_for_each_entry(rv, &resolved_paths, list) {
-			list_for_each_entry(pv, val_pv_list, list) {
-				snprintf(temp, MAX_DM_PATH, "%s%s", rv->path, pv->param);
-				INFO("## set (%s)::(%s)::(%s) ##", temp, pv->val, key);
-				fault = usp_dm_set(&bbf_ctx, &bb, temp, pv->val, key);
+	array = blobmsg_open_array(&bb, "parameters");
+	list_for_each_entry(pv, data->pv_list, list) {
+		// free fault list so that it won't interfere with the next set
+		dm_ctx_clean_list_parameter(&bbf_ctx);
+		fault = get_resolved_paths(&bbf_ctx, pv->param, &resolved_paths);
+		if (fault) {
+			DEBUG("fault in resolved path %d", fault);
+			bb_add_string(&bb, "path", pv->param);
+			blobmsg_add_u8(&bb, "status", false);
+			fill_err_code(&bb, fault);
+		} else {
+			list_for_each_entry(rv, &resolved_paths, list) {
+				fault = usp_dm_set(&bbf_ctx, &bb, rv->path, pv->val, data->set_key);
 				if (fault != USP_ERR_OK && fault_occured != true)
 					fault_occured = true;
-
 			}
 		}
-		blobmsg_close_array(&bb, array);
+		free_path_list(&resolved_paths);
 	}
+
+	blobmsg_close_array(&bb, array);
 	ubus_send_reply(ctx, req, bb.head);
 
 	// Restart all the affected services
@@ -110,15 +113,15 @@ void usp_set_value(usp_data_t *data)
 
 	// free
 	blob_buf_free(&bb);
-	free_path_list(&resolved_paths);
 	bbf_cleanup(&bbf_ctx);
 }
 
-bool get_values_in_pvlist(struct blob_attr *blob_value, struct list_head *pv_list)
+bool get_values_in_pvlist(const char *bpath, struct blob_attr *blob_value, struct list_head *pv_list)
 {
 	struct blob_attr *attr;
 	char value[MAX_DM_VALUE];
 	struct blobmsg_hdr *hdr;
+	char path[MAX_DM_PATH];
 	size_t tlen = (size_t)blobmsg_data_len(blob_value);
 
 	__blob_for_each_attr(attr, blobmsg_data(blob_value), tlen) {
@@ -145,8 +148,39 @@ bool get_values_in_pvlist(struct blob_attr *blob_value, struct list_head *pv_lis
 			INFO("Unhandled set request type|%x|", blob_id(attr));
 			return false;
 		}
-		add_pv_node((char *)hdr->name, value, NULL, pv_list);
+
+		snprintf(path, MAX_DM_PATH, "%s%s", bpath, (char *)hdr->name);
+		add_pv_node(path, value, NULL, pv_list);
 	}
 
 	return true;
 }
+
+int fill_pvlist_from_tuple(struct blob_attr *blob, struct list_head *pv_list)
+{
+	size_t rem;
+	struct blob_attr *cur;
+
+	blobmsg_for_each_attr(cur, blob, rem) {
+		struct blob_attr *tb[__DM_SET_V_MAX];
+		char *path, *value, *key;
+
+		key = NULL;
+		blobmsg_parse(dm_setm_value_policy, __DM_SET_V_MAX, tb,
+			      blobmsg_data(cur), blobmsg_len(cur));
+
+		// ignore the tuples which does not have path and values
+		if (!tb[DM_SET_V_PATH] || !tb[DM_SET_V_VALUE])
+			continue;
+
+		path = blobmsg_get_string(tb[DM_SET_V_PATH]);
+		value = blobmsg_get_string(tb[DM_SET_V_VALUE]);
+
+		if (tb[DM_SET_V_KEY])
+			key = blobmsg_get_string(tb[DM_SET_V_KEY]);
+
+		add_pv_node(path, value, key, pv_list);
+	}
+
+	return 0;
+}
diff --git a/src/set.h b/src/set.h
index 605759664cca991a27f7607aeb828f2b1249a7e7..f95b4ff3986ed9eb7b71b6525101345b54f8ebf7 100644
--- a/src/set.h
+++ b/src/set.h
@@ -2,13 +2,51 @@
 #define SET_H
 #include "common.h"
 
+enum {
+	DM_SETS_PATHS,
+	DM_SETS_PROTO,
+	DM_SETS_INSTANCE,
+	__DM_SETS_MAX
+};
+
+enum {
+	DM_SETS_A_NOTIF_PATH,
+	DM_SETS_A_NOTIF_VALUE,
+	DM_SETS_A_NOTIF_CHANGE,
+	__DM_SETS_A_NOTIF_MAX
+};
+
+enum {
+	DM_SET_PATH,
+	DM_SET_VALUE,
+	DM_SET_VALUE_TABLE,
+	DM_SET_PROTO,
+	DM_SET_PARAMETER_KEY,
+	DM_SET_INSTANCE,
+	__DM_SET_MAX,
+};
+
+enum {
+	DM_SET_V_PATH,
+	DM_SET_V_VALUE,
+	DM_SET_V_KEY,
+	__DM_SET_V_MAX
+};
+
+enum {
+	DM_SET_MULTI_TUPLE,
+	DM_SET_MULTI_PROTO,
+	DM_SET_MULTI_INSTANCE,
+	__DM_SET_MULTI_MAX
+};
+
 void create_set_response(struct blob_buf *bb, char *value, char *key);
 void set_multiple_values(struct blob_buf *bb, struct blob_attr *blob_value,
 			 char *key);
-bool get_values_in_pvlist(struct blob_attr *blob_value,
-			  struct list_head *pv_list);
+bool get_values_in_pvlist(const char *path, struct blob_attr *blob_value, struct list_head *pv_list);
 
 void usp_set_value(usp_data_t *data);
+int fill_pvlist_from_tuple(struct blob_attr *blob, struct list_head *pv_list);
 
 #endif /* SET_H */
 
diff --git a/src/usp.c b/src/usp.c
index 12c7237754f9303da23fc2493197d1d8e69cc55d..6660757c3ecd439d9854ef6c0ea7d6ffdbe0624e 100644
--- a/src/usp.c
+++ b/src/usp.c
@@ -55,47 +55,6 @@ struct uspd_async_req {
 struct blob_buf g_schema_bb;
 LIST_HEAD(g_ubus_obj_list);
 
-enum {
-	DM_GET_PATH,
-	DM_GET_PROTO,
-	DM_GET_MAXDEPTH,
-	DM_GET_NXT_LVL,
-	DM_GET_INSTANCE,
-	__DM_GET_MAX
-};
-
-enum {
-	DM_SETS_PATHS,
-	DM_SETS_PROTO,
-	DM_SETS_INSTANCE,
-	__DM_SETS_MAX
-};
-
-enum {
-	DM_SETS_A_NOTIF_PATH,
-	DM_SETS_A_NOTIF_VALUE,
-	DM_SETS_A_NOTIF_CHANGE,
-	__DM_SETS_A_NOTIF_MAX
-};
-
-enum {
-	DM_ADD_PATH,
-	DM_ADD_PROTO,
-	DM_ADD_PARAMETER_KEY,
-	DM_ADD_INSTANCE,
-	__DM_ADD_MAX
-};
-
-enum {
-	DM_SET_PATH,
-	DM_SET_VALUE,
-	DM_SET_VALUE_TABLE,
-	DM_SET_PROTO,
-	DM_SET_PARAMETER_KEY,
-	DM_SET_INSTANCE,
-	__DM_SET_MAX,
-};
-
 enum {
 	DM_INIT_NOTIFY_PROTO,
 	DM_INIT_NOTIFY_AMD,
@@ -103,57 +62,6 @@ enum {
 	__DM_INIT_NOTIFY_MAX,
 };
 
-enum {
-	DM_GET_SAFE_PATHS,
-	DM_GET_SAFE_PROTO,
-	DM_GET_SAFE_NXT_LVL,
-	DM_GET_SAFE_INSTANCE,
-	__DM_GET_SAFE_MAX
-};
-
-static const struct blobmsg_policy dm_get_safe_policy[] = {
-	[DM_GET_SAFE_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY },
-	[DM_GET_SAFE_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
-	[DM_GET_SAFE_NXT_LVL] = { .name = "next-level", .type = BLOBMSG_TYPE_INT8 },
-	[DM_GET_SAFE_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
-};
-
-static const struct blobmsg_policy dm_get_policy[] = {
-	[DM_GET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
-	[DM_GET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
-	[DM_GET_MAXDEPTH] = { .name = "maxdepth", .type = BLOBMSG_TYPE_INT32 },
-	[DM_GET_NXT_LVL] = { .name = "next-level", .type = BLOBMSG_TYPE_INT8 },
-	[DM_GET_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
-};
-
-static const struct blobmsg_policy dm_sets_policy[] = {
-	[DM_SETS_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY },
-	[DM_SETS_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
-	[DM_SETS_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
-};
-
-static const struct blobmsg_policy dm_sets_attrib_policy[] = {
-	[DM_SETS_A_NOTIF_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
-	[DM_SETS_A_NOTIF_VALUE] = { .name = "notify-type", .type = BLOBMSG_TYPE_STRING },
-	[DM_SETS_A_NOTIF_CHANGE] = { .name = "notify", .type = BLOBMSG_TYPE_STRING },
-};
-
-static const struct blobmsg_policy dm_add_policy[] = {
-	[DM_ADD_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
-	[DM_ADD_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
-	[DM_ADD_PARAMETER_KEY] = { .name = "key", .type = BLOBMSG_TYPE_STRING },
-	[DM_ADD_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
-};
-
-static const struct blobmsg_policy dm_set_policy[] = {
-	[DM_SET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
-	[DM_SET_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
-	[DM_SET_VALUE_TABLE] = { .name = "values", .type = BLOBMSG_TYPE_TABLE },
-	[DM_SET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
-	[DM_SET_PARAMETER_KEY] = { .name = "key", .type = BLOBMSG_TYPE_STRING },
-	[DM_SET_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
-};
-
 struct obNode {
 	struct ubus_object *obj;
 	struct list_head list;
@@ -229,6 +137,13 @@ static int get_instance_mode(struct blob_attr *ins)
 	return instance_mode;
 }
 
+static const struct blobmsg_policy dm_get_safe_policy[] = {
+	[DM_GET_SAFE_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY },
+	[DM_GET_SAFE_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
+	[DM_GET_SAFE_NXT_LVL] = { .name = "next-level", .type = BLOBMSG_TYPE_INT8 },
+	[DM_GET_SAFE_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
+};
+
 int get_safe(struct ubus_context *ctx,
 		    struct ubus_object *obj,
 		    struct ubus_request_data *req,
@@ -274,7 +189,6 @@ int get_safe(struct ubus_context *ctx,
 	data.plist = &paths_list;
 	data.dm_cmd = bbf_cmd;
 	data.instance = get_instance_mode(tb[DM_GET_SAFE_INSTANCE]);
-	data.is_raw = is_str_eq(obj->name, USPRAW);
 
 	get_mpath(&data);
 
@@ -310,6 +224,18 @@ int usp_get_safe_names(struct ubus_context *ctx,
 	return get_safe(ctx, obj, req, msg, CMD_GET_NAME);
 }
 
+static const struct blobmsg_policy dm_sets_attrib_policy[] = {
+	[DM_SETS_A_NOTIF_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+	[DM_SETS_A_NOTIF_VALUE] = { .name = "notify-type", .type = BLOBMSG_TYPE_STRING },
+	[DM_SETS_A_NOTIF_CHANGE] = { .name = "notify", .type = BLOBMSG_TYPE_STRING },
+};
+
+static const struct blobmsg_policy dm_sets_policy[] = {
+	[DM_SETS_PATHS] = { .name = "paths", .type = BLOBMSG_TYPE_ARRAY },
+	[DM_SETS_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
+	[DM_SETS_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
+};
+
 int usp_set_safe_attributes(struct ubus_context *ctx,
 			__attribute__((unused)) struct ubus_object *obj,
 			struct ubus_request_data *req,
@@ -374,6 +300,13 @@ int usp_set_safe_attributes(struct ubus_context *ctx,
 	return 0;
 }
 
+static const struct blobmsg_policy dm_add_policy[] = {
+	[DM_ADD_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+	[DM_ADD_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
+	[DM_ADD_PARAMETER_KEY] = { .name = "key", .type = BLOBMSG_TYPE_STRING },
+	[DM_ADD_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
+};
+
 int usp_add_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
 			struct ubus_request_data *req, const char *method,
 			struct blob_attr *msg)
@@ -448,6 +381,14 @@ static bool is_subprocess_required(const char *path)
 	return ret;
 }
 
+static const struct blobmsg_policy dm_get_policy[] = {
+	[DM_GET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+	[DM_GET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
+	[DM_GET_MAXDEPTH] = { .name = "maxdepth", .type = BLOBMSG_TYPE_INT32 },
+	[DM_GET_NXT_LVL] = { .name = "next-level", .type = BLOBMSG_TYPE_INT8 },
+	[DM_GET_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
+};
+
 int usp_get_handler(struct ubus_context *ctx, struct ubus_object *obj,
 		    struct ubus_request_data *req, const char *method __attribute__((unused)),
 		    struct blob_attr *msg)
@@ -513,6 +454,15 @@ int usp_get_handler(struct ubus_context *ctx, struct ubus_object *obj,
 	return 0;
 }
 
+static const struct blobmsg_policy dm_set_policy[] = {
+	[DM_SET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
+	[DM_SET_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
+	[DM_SET_VALUE_TABLE] = { .name = "values", .type = BLOBMSG_TYPE_TABLE },
+	[DM_SET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
+	[DM_SET_PARAMETER_KEY] = { .name = "key", .type = BLOBMSG_TYPE_STRING },
+	[DM_SET_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
+};
+
 int usp_set(struct ubus_context *ctx, struct ubus_object *obj,
 	    struct ubus_request_data *req, const char *method,
 	    struct blob_attr *msg)
@@ -526,6 +476,7 @@ int usp_set(struct ubus_context *ctx, struct ubus_object *obj,
 	usp_data_t data;
 	int fault = USP_ERR_OK;
 	struct list_head pv_list;
+	int proto;
 
 	if (blobmsg_parse(dm_set_policy, __DM_SET_MAX, tb, blob_data(msg), blob_len(msg))) {
 		ERR("Failed to parse blob");
@@ -554,39 +505,30 @@ int usp_set(struct ubus_context *ctx, struct ubus_object *obj,
 
 	INIT_LIST_HEAD(&pv_list);
 
+	plen = strlen(path);
 	if (tb[DM_SET_VALUE]) {
-		char *tmp, tpath[MAX_DM_PATH] = {0};
-
-		plen = strlen(path);
 		if (path[plen - 1] == '.') {
 			fault = USP_FAULT_INVALID_PATH;
 		} else {
-			tmp = strrchr(path, '.');
-			snprintf(tpath, plen - strlen(tmp) + 2, "%s", path);
-		}
-
-		if (fault == USP_ERR_OK) {
 			blob_msg = blobmsg_data(tb[DM_SET_VALUE]);
 			strncpyt(value, blob_msg, sizeof(value));
-			add_pv_node(&tmp[1], value, NULL, &pv_list);
-			strcpy(path, tpath);
+			add_pv_node(path, value, NULL, &pv_list);
 		}
 	}
 
-	if (tb[DM_SET_VALUE_TABLE]) {
-		if (get_values_in_pvlist(tb[DM_SET_VALUE_TABLE], &pv_list) == false)
+	if (tb[DM_SET_VALUE_TABLE] && fault == USP_ERR_OK) {
+		if (get_values_in_pvlist(path, tb[DM_SET_VALUE_TABLE], &pv_list) == false)
 			fault = USP_FAULT_INVALID_PATH;
 	}
 
+	proto = get_bbf_proto_type(tb[DM_SET_PROTO]);
 	if (fault) {
 		memset(&bb, 0, sizeof(struct blob_buf));
 		blob_buf_init(&bb, 0);
 
 		ERR("Fault in set path |%s|", path);
-		if (get_bbf_proto_type(tb[DM_SET_PROTO]) == BBFDM_CWMP)
-			fill_err_code(&bb, FAULT_9005);
-		else
-			fill_err_code(&bb, fault);
+		set_bbfdatamodel_type(proto);
+		fill_err_code(&bb, FAULT_9005);
 		ubus_send_reply(ctx, req, bb.head);
 		blob_buf_free(&bb);
 		free_pv_list(&pv_list);
@@ -600,7 +542,7 @@ int usp_set(struct ubus_context *ctx, struct ubus_object *obj,
 	data.qpath = path;
 	data.pv_list = &pv_list;
 	data.set_key = key;
-	data.proto = get_bbf_proto_type(tb[DM_SET_PROTO]);
+	data.proto = proto;
 	data.instance = get_instance_mode(tb[DM_SET_INSTANCE]);
 	data.is_raw = is_str_eq(obj->name, USPRAW);
 
@@ -961,6 +903,46 @@ int usp_transaction_abort(struct ubus_context *actx, struct ubus_object *obj,
 	return 0;
 }
 
+static const struct blobmsg_policy dm_set_multi_policy[] = {
+	[DM_SET_MULTI_TUPLE] = { .name = "pv_tuple", .type = BLOBMSG_TYPE_ARRAY },
+	[DM_SET_MULTI_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
+	[DM_SET_MULTI_INSTANCE] = { .name = "instance_mode", .type = BLOBMSG_TYPE_INT32 },
+};
+
+int handle_set_multi_value(struct ubus_context *ctx, struct ubus_object *obj,
+			   struct ubus_request_data *req, const char *method __attribute__((unused)),
+			   struct blob_attr *msg)
+{
+	struct blob_attr *tb[__DM_SET_MULTI_MAX];
+	usp_data_t data;
+	struct list_head pv_list;
+
+	memset(&data, 0, sizeof(usp_data_t));
+	blobmsg_parse(dm_set_multi_policy, __DM_SET_MULTI_MAX, tb,
+		      blob_data(msg), blob_len(msg));
+
+	if (tb[DM_SET_MULTI_TUPLE] == NULL)
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	INIT_LIST_HEAD(&pv_list);
+
+	fill_pvlist_from_tuple(tb[DM_SET_MULTI_TUPLE], &pv_list);
+	if (list_empty(&pv_list))
+		return UBUS_STATUS_INVALID_ARGUMENT;
+
+	data.ctx = ctx;
+	data.req = req;
+	data.proto = get_bbf_proto_type(tb[DM_SET_MULTI_PROTO]);
+	data.is_raw = is_str_eq(obj->name, USPRAW);
+	data.instance = get_instance_mode(tb[DM_SET_MULTI_INSTANCE]);
+	data.pv_list = &pv_list;
+
+	usp_set_value(&data);
+
+	free_pv_list(&pv_list);
+
+	return 0;
+}
 static struct ubus_method usp_methods[] = {
 	UBUS_METHOD_NOARG("list_operate", usp_list_operate),
 	UBUS_METHOD("get", usp_get_handler, dm_get_policy),
@@ -988,6 +970,7 @@ static struct ubus_method usp_raw_methods[] = {
 	UBUS_METHOD("getm_names", usp_get_safe_names, dm_get_safe_policy),
 	UBUS_METHOD("getm_attributes", usp_get_attributes, dm_get_safe_policy),
 	UBUS_METHOD("setm_attributes", usp_set_safe_attributes, dm_sets_policy),
+	UBUS_METHOD("setm_values", handle_set_multi_value, dm_set_multi_policy),
 	UBUS_METHOD("init_notify", usp_init_notify_file, dm_init_notify_policy),
 	UBUS_METHOD_NOARG("transaction_start", usp_transaction_start),
 	UBUS_METHOD_NOARG("transaction_commit", usp_transaction_commit),