bbfdm/libbbf_ubus/libbbf_ubus.c
Amin Ben Ramdhane 080f7b4f85 Ticket refs #7333: fix warnings, code analysis and clean up the code
- Fix all errors catched by cppcheck threadsafety (cppcheck --error-exitcode=0 --addon=threadsafety bbf)
 - Fix some errors catched by cppcheck cert (cppcheck --error-exitcode=0 --addon=cert bbf)
 - Add new str-protected macros instead of using str functions directly to avoid crashes
2022-02-16 10:33:59 +00:00

946 lines
26 KiB
C

/*
* Copyright (C) 2021 Iopsys Software Solutions AB
*
* Author: Suvendhu Hansa <suvendhu.hansa@iopsys.eu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA
*/
#include <stdio.h>
#include <stdlib.h>
#include <libubox/blobmsg.h>
#include "dmentry.h"
#include "dmbbfcommon.h"
#include "libbbf_ubus.h"
#define PATH_MAX 4096
struct obj_node {
struct ubus_object *ob;
struct ubus_object_type *ob_type;
char *obj_name;
DMOBJ *tUsrObj;
struct obj_node *next;
};
enum {
LIBBBF_UBUS_GET_PATH,
LIBBBF_UBUS_GET_PROTO,
__LIBBBF_UBUS_GET_MAX
};
enum {
LIBBBF_UBUS_SET_PATH,
LIBBBF_UBUS_SET_VALUE,
LIBBBF_UBUS_SET_PROTO,
__LIBBBF_UBUS_SET_MAX
};
enum {
LIBBBF_UBUS_OPERATE_PATH,
LIBBBF_UBUS_OPERATE_INPUT,
__LIBBBF_UBUS_OPERATE_MAX
};
enum {
LIBBBF_UBUS_SUPPORTED_PATH,
LIBBBF_UBUS_SUPPORTED_PROTO,
LIBBBF_UBUS_SUPPORTED_NXT_LEVEL,
LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE,
__LIBBBF_UBUS_SUPPORTED_MAX
};
enum {
LIBBBF_UBUS_ADD_DEL_PATH,
LIBBBF_UBUS_ADD_DEL_PROTO,
__LIBBBF_UBUS_ADD_DEL_MAX
};
static bool g_dynamicdm_transaction_start = false;
static struct obj_node *g_dynamicdm_head = NULL;
static int libbbf_ubus_supported_dm(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_get_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_operate(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_add_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static int libbbf_ubus_transaction_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg);
static const struct blobmsg_policy libbbf_ubus_supported_dm_policy[] = {
[LIBBBF_UBUS_SUPPORTED_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SUPPORTED_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SUPPORTED_NXT_LEVEL] = { .name = "next-level", .type = BLOBMSG_TYPE_INT8},
[LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE] = { .name = "schema_type", .type = BLOBMSG_TYPE_INT32},
};
static const struct blobmsg_policy libbbf_ubus_get_policy[] = {
[LIBBBF_UBUS_GET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_GET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING }
};
static const struct blobmsg_policy libbbf_ubus_set_policy[] = {
[LIBBBF_UBUS_SET_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SET_VALUE] = { .name = "value", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_SET_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING }
};
static const struct blobmsg_policy libbbf_ubus_operate_policy[] = {
[LIBBBF_UBUS_OPERATE_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_OPERATE_INPUT] = { .name = "input", .type = BLOBMSG_TYPE_TABLE }
};
static const struct blobmsg_policy libbbf_ubus_add_del_policy[] = {
[LIBBBF_UBUS_ADD_DEL_PATH] = { .name = "path", .type = BLOBMSG_TYPE_STRING },
[LIBBBF_UBUS_ADD_DEL_PROTO] = { .name = "proto", .type = BLOBMSG_TYPE_STRING }
};
static struct ubus_method libbbf_ubus_methods[] = {
UBUS_METHOD("get_supported_dm", libbbf_ubus_supported_dm, libbbf_ubus_supported_dm_policy),
UBUS_METHOD("get", libbbf_ubus_get_handler, libbbf_ubus_get_policy),
UBUS_METHOD("set", libbbf_ubus_set_handler, libbbf_ubus_set_policy),
UBUS_METHOD("operate", libbbf_ubus_operate, libbbf_ubus_operate_policy),
UBUS_METHOD("add_object", libbbf_ubus_add_del_handler, libbbf_ubus_add_del_policy),
UBUS_METHOD("del_object", libbbf_ubus_add_del_handler, libbbf_ubus_add_del_policy),
UBUS_METHOD_NOARG("transaction_start", libbbf_ubus_transaction_handler),
UBUS_METHOD_NOARG("transaction_abort", libbbf_ubus_transaction_handler),
UBUS_METHOD_NOARG("transaction_commit", libbbf_ubus_transaction_handler),
};
static int get_protocol(const char *val)
{
int type;
if (DM_STRCMP("cwmp", val) == 0)
type = BBFDM_CWMP;
else if (DM_STRCMP("usp", val) == 0)
type = BBFDM_USP;
else
type = BBFDM_BOTH;
return type;
}
static int get_bbf_proto_type(struct blob_attr *proto)
{
int type;
if (proto) {
const char *val = blobmsg_get_string(proto);
type = get_protocol(val);
} else {
type = BBFDM_BOTH;
}
return type;
}
static void bb_add_string(struct blob_buf *bb, const char *name, const char *value)
{
if (value)
blobmsg_add_string(bb, name, value);
else
blobmsg_add_string(bb, name, "");
}
static struct obj_node* find_obj_node(const char *ubus_name)
{
struct obj_node *temp = g_dynamicdm_head;
if (temp == NULL)
return NULL;
while (DM_STRCMP(ubus_name, temp->obj_name) != 0) {
if (temp->next == NULL) {
return NULL;
} else {
temp = temp->next;
}
}
return temp;
}
static DMOBJ* get_entry_object(const char *name)
{
if (!name)
return NULL;
struct obj_node *ob_node = find_obj_node(name);
if (!ob_node)
return NULL;
return ob_node->tUsrObj;
}
static void fill_operate_schema(struct blob_buf *bb, struct dm_parameter *param)
{
blobmsg_add_string(bb, "parameter",param->name);
blobmsg_add_string(bb,"type",param->type);
blobmsg_add_string(bb,"cmd_type",param->additional_data);
if(param->data) {
const char **in, **out = NULL;
operation_args *args = NULL;
void *array = NULL;
int i;
args = (operation_args *) param->data;
in = args->in;
if (in) {
array = blobmsg_open_array(bb, "in");
for (i = 0; in[i] != NULL; i++)
blobmsg_add_string(bb, NULL, in[i]);
blobmsg_close_array(bb, array);
}
out = args->out;
if (out) {
array = blobmsg_open_array(bb, "out");
for (i = 0; out[i] != NULL; i++)
blobmsg_add_string(bb, NULL, out[i]);
blobmsg_close_array(bb, array);
}
}
}
static void fill_event_schema(struct blob_buf *bb, struct dm_parameter *param)
{
blobmsg_add_string(bb, "parameter",param->name);
blobmsg_add_string(bb,"type",param->type);
if(param->data) {
event_args *ev = NULL;
ev = (event_args *)param->data;
if (ev->param) {
const char **in = NULL;
void *key = NULL;
int i;
in = ev->param;
key = blobmsg_open_array(bb, "in");
for (i = 0; in[i] != NULL; i++)
blobmsg_add_string(bb, NULL, in[i]);
blobmsg_close_array(bb, key);
}
}
}
static void fill_param_schema(struct blob_buf *bb, struct dm_parameter *param)
{
blobmsg_add_string(bb, "parameter", param->name);
blobmsg_add_string(bb, "writable", param->data ? param->data : "0");
blobmsg_add_string(bb, "type", param->type);
if (param->additional_data) {
const char **uniq_keys = NULL;
void *key = NULL;
int i;
uniq_keys = (const char **)param->additional_data;
key = blobmsg_open_array(bb, "unique_keys");
for (i = 0; uniq_keys[i] != NULL; i++)
blobmsg_add_string(bb, NULL, uniq_keys[i]);
blobmsg_close_array(bb, key);
}
}
static int handle_add_del_req(struct ubus_context *ctx, const char *ubus_name, struct ubus_request_data *req,
char *path, const char *method, int proto)
{
int fault = 0;
struct dmctx bbf_ctx;
struct blob_buf bb;
char *pkey = "true";
DMOBJ *tEntryObj = get_entry_object(ubus_name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (!g_dynamicdm_transaction_start) {
printf("Transaction not started\n\r");
blobmsg_add_u32(&bb, "fault", usp_fault_map(USP_FAULT_INTERNAL_ERROR));
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(proto);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
if (DM_STRCMP(method, "add_object") == 0) {
fault = dm_entry_param_method(&bbf_ctx, CMD_ADD_OBJECT, path, pkey, NULL);
} else {
fault = dm_entry_param_method(&bbf_ctx, CMD_DEL_OBJECT, path, pkey, NULL);
}
void *array = blobmsg_open_array(&bb, "parameters");
void *table = blobmsg_open_table(&bb, NULL);
bb_add_string(&bb, "parameter", path);
if (fault) {
blobmsg_add_u32(&bb, "fault", fault);
blobmsg_add_u8(&bb, "status", 0);
} else {
if (DM_STRCMP(method, "add_object") == 0) {
if (bbf_ctx.addobj_instance) {
blobmsg_add_u8(&bb, "status", 1);
bb_add_string(&bb, "instance", bbf_ctx.addobj_instance);
} else {
blobmsg_add_u8(&bb, "status", 0);
}
} else {
blobmsg_add_u8(&bb, "status", 1);
}
}
blobmsg_close_table(&bb, table);
blobmsg_close_array(&bb, array);
dm_ctx_clean(&bbf_ctx);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
static void libbbf_ubus_obj_node_free(struct obj_node *obj)
{
if (!obj)
return;
if (obj->ob_type)
FREE(obj->ob_type);
if (obj->ob)
FREE(obj->ob);
if (obj->obj_name)
FREE(obj->obj_name);
FREE(obj);
}
static int libbbf_ubus_supported_dm(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[__LIBBBF_UBUS_SUPPORTED_MAX];
char path[PATH_MAX] = {0};
bool nxt_lvl = false;
uint32_t schema_type = 0;
struct blob_buf bb;
int fault = 0, proto;
struct dmctx bbf_ctx;
if (blobmsg_parse(libbbf_ubus_supported_dm_policy, __LIBBBF_UBUS_SUPPORTED_MAX, tb, blob_data(msg), blob_len(msg)) == 0) {
if (tb[LIBBBF_UBUS_SUPPORTED_PATH])
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_SUPPORTED_PATH]));
if (tb[LIBBBF_UBUS_SUPPORTED_NXT_LEVEL])
nxt_lvl = blobmsg_get_bool(tb[LIBBBF_UBUS_SUPPORTED_NXT_LEVEL]);
if (tb[LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE])
schema_type = blobmsg_get_u32(tb[LIBBBF_UBUS_SUPPORTED_SCHEMA_TYPE]);
}
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_SUPPORTED_PROTO]);
set_bbfdatamodel_type(proto);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_get_supported_dm(&bbf_ctx, path, nxt_lvl, schema_type);
if(fault) {
blobmsg_add_u32(&bb, "fault", fault);
} else {
struct dm_parameter *param = NULL;
void *array = NULL, *table = NULL;
array = blobmsg_open_array(&bb,"parameters");
list_for_each_entry(param, &bbf_ctx.list_parameter, list) {
int cmd = get_dm_type(param->type);
table = blobmsg_open_table(&bb, NULL);
if (cmd == DMT_COMMAND) {
fill_operate_schema(&bb, param);
} else if (cmd == DMT_EVENT) {
fill_event_schema(&bb, param);
} else {
fill_param_schema(&bb, param);
}
blobmsg_close_table(&bb, table);
}
blobmsg_close_array(&bb, array);
}
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
dm_ctx_clean(&bbf_ctx);
return fault;
}
static void init_dm_path(DMOBJ *tEntryObj)
{
struct dmctx bbf_ctx;
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(BBFDM_BOTH);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
dm_entry_param_method(&bbf_ctx, CMD_GET_VALUE, "", NULL, NULL);
dm_ctx_clean(&bbf_ctx);
}
static int libbbf_ubus_get_handler(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[__LIBBBF_UBUS_GET_MAX] = {NULL};
char path[PATH_MAX] = {0};
struct dmctx bbf_ctx;
struct blob_buf bb;
int fault = 0, proto;
if (blobmsg_parse(libbbf_ubus_get_policy, __LIBBBF_UBUS_GET_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob\n");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!(tb[LIBBBF_UBUS_GET_PATH]))
return UBUS_STATUS_INVALID_ARGUMENT;
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_GET_PATH]));
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_GET_PROTO]);
set_bbfdatamodel_type(proto);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_entry_param_method(&bbf_ctx, CMD_GET_VALUE, path, NULL, NULL);
if (!fault) {
struct dm_parameter *n = NULL;
void *array = blobmsg_open_array(&bb, "parameters");
list_for_each_entry(n, &bbf_ctx.list_parameter, list) {
void *table = blobmsg_open_table(&bb, NULL);
bb_add_string(&bb, "parameter", n->name);
bb_add_string(&bb, "value", n->data);
bb_add_string(&bb, "type", n->type);
blobmsg_close_table(&bb, table);
}
blobmsg_close_array(&bb, array);
} else {
blobmsg_add_u32(&bb, "fault", fault);
}
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
dm_ctx_clean(&bbf_ctx);
return fault;
}
static int libbbf_ubus_operate(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)),
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg)
{
struct blob_attr *tb[__LIBBBF_UBUS_OPERATE_MAX] = {NULL};
char path[PATH_MAX] = {0};
char *input = NULL;
struct blob_buf bb;
struct dmctx bbf_ctx;
int fault = 0, len;
if (blobmsg_parse(libbbf_ubus_operate_policy, __LIBBBF_UBUS_OPERATE_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!(tb[LIBBBF_UBUS_OPERATE_PATH]))
return UBUS_STATUS_INVALID_ARGUMENT;
if (tb[LIBBBF_UBUS_OPERATE_INPUT])
input = blobmsg_format_json(tb[LIBBBF_UBUS_OPERATE_INPUT], true);
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
if (input)
free(input);
return UBUS_STATUS_UNKNOWN_ERROR;
}
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_OPERATE_PATH]));
len = DM_STRLEN(path);
if (path[len - 1] == '.') {
printf("path can't end with (.)\n\r");
if (input)
free(input);
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
set_bbfdatamodel_type(BBFDM_USP);
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_entry_param_method(&bbf_ctx, CMD_USP_OPERATE, path, input, NULL);
switch (fault) {
case CMD_NOT_FOUND:
fault = USP_FAULT_INVALID_PATH;
break;
case CMD_INVALID_ARGUMENTS:
fault = USP_FAULT_INVALID_ARGUMENT;
break;
case CMD_FAIL:
fault = USP_FAULT_COMMAND_FAILURE;
break;
case CMD_SUCCESS:
fault = 0;
break;
default:
printf("Case(%d) not found\n\r", fault);
fault = USP_FAULT_INVALID_PATH;
break;
}
void *array = blobmsg_open_array(&bb, "Results");
void *table = blobmsg_open_table(&bb, NULL);
blobmsg_add_string(&bb, "path", path);
if (fault == 0) {
struct dm_parameter *n = NULL;
void *array_in = blobmsg_open_array(&bb, "parameters");
list_for_each_entry(n, &bbf_ctx.list_parameter, list) {
void *table_in = blobmsg_open_table(&bb, NULL);
bb_add_string(&bb, "parameter", n->name);
bb_add_string(&bb, "value", n->data);
bb_add_string(&bb, "type", n->type);
blobmsg_close_table(&bb, table_in);
}
blobmsg_close_array(&bb, array_in);
} else {
fault = usp_fault_map(fault);
blobmsg_add_u32(&bb, "fault", fault);
}
blobmsg_close_table(&bb, table);
blobmsg_close_array(&bb, array);
dm_ctx_clean(&bbf_ctx);
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
if (input)
free(input);
return 0;
}
static int libbbf_ubus_add_del_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_attr *tb[__LIBBBF_UBUS_ADD_DEL_MAX] = {NULL};
char path[PATH_MAX] = {0};
int plen, proto;
if (blobmsg_parse(libbbf_ubus_add_del_policy, __LIBBBF_UBUS_ADD_DEL_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!tb[LIBBBF_UBUS_ADD_DEL_PATH])
return UBUS_STATUS_INVALID_ARGUMENT;
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_ADD_DEL_PATH]));
plen = DM_STRLEN(path);
if (path[plen - 1] != '.') {
if (plen > PATH_MAX - 2) {
printf("path too long(%d) can't append (.)\n\r", plen);
return UBUS_STATUS_UNKNOWN_ERROR;
}
strcat(path, ".");
}
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_ADD_DEL_PROTO]);
return handle_add_del_req(ctx, obj->name, req, path, method, proto);
}
static int libbbf_ubus_set_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method,
struct blob_attr *msg)
{
struct blob_buf bb;
struct blob_attr *tb[__LIBBBF_UBUS_SET_MAX] = {NULL};
char path[PATH_MAX] = {'\0'}, value[PATH_MAX] = {'\0'};
int fault = 0, proto;
void *array = NULL, *table = NULL;
struct dmctx bbf_ctx;
bool fault_occured = false;
if (blobmsg_parse(libbbf_ubus_set_policy, __LIBBBF_UBUS_SET_MAX, tb, blob_data(msg), blob_len(msg))) {
printf("Failed to parse blob");
return UBUS_STATUS_UNKNOWN_ERROR;
}
if (!tb[LIBBBF_UBUS_SET_PATH])
return UBUS_STATUS_INVALID_ARGUMENT;
if (!tb[LIBBBF_UBUS_SET_VALUE])
return UBUS_STATUS_INVALID_ARGUMENT;
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
snprintf(path, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_SET_PATH]));
snprintf(value, PATH_MAX, "%s", (char *)blobmsg_data(tb[LIBBBF_UBUS_SET_VALUE]));
int plen = DM_STRLEN(path);
if (path[plen - 1] == '.') {
printf("path can't end with (.)\n\r");
return UBUS_STATUS_INVALID_ARGUMENT;
}
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (!g_dynamicdm_transaction_start) {
printf("Transaction not started\n\r");
blobmsg_add_u32(&bb, "fault", usp_fault_map(USP_FAULT_INTERNAL_ERROR));
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
proto = get_bbf_proto_type(tb[LIBBBF_UBUS_SET_PROTO]);
set_bbfdatamodel_type(proto);
memset(&bbf_ctx, 0, sizeof(struct dmctx));
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
fault = dm_entry_param_method(&bbf_ctx, CMD_SET_VALUE, path, value, NULL);
if (fault) {
if (fault_occured == false) {
fault_occured = true;
array = blobmsg_open_array(&bb, "parameters");
}
}
while (bbf_ctx.list_fault_param.next != &bbf_ctx.list_fault_param) {
struct param_fault *p = list_entry(bbf_ctx.list_fault_param.next, struct param_fault, list);
table = blobmsg_open_table(&bb, NULL);
bb_add_string(&bb, "path", p->name);
blobmsg_add_u8(&bb, "status", false);
blobmsg_add_u32(&bb, "fault", (uint32_t)p->fault);
blobmsg_close_table(&bb, table);
del_list_fault_param(p);
}
//Apply the parameter
fault = dm_entry_apply(&bbf_ctx, CMD_SET_VALUE, NULL);
if (fault == 0 && fault_occured == false) {
blobmsg_add_u8(&bb, "status", true);
if (get_bbfdatamodel_type() == BBFDM_CWMP)
blobmsg_add_u64(&bb, "flag", bbf_ctx.end_session_flag);
} else {
if (!array)
array = blobmsg_open_array(&bb, "parameters");
while (bbf_ctx.list_fault_param.next != &bbf_ctx.list_fault_param) {
struct param_fault *p = list_entry(bbf_ctx.list_fault_param.next, struct param_fault, list);
table = blobmsg_open_table(&bb, NULL);
bb_add_string(&bb, "path", p->name);
blobmsg_add_u8(&bb, "status", false);
blobmsg_add_u32(&bb, "fault", (uint32_t)p->fault);
blobmsg_close_table(&bb, table);
del_list_fault_param(p);
}
}
if (array)
blobmsg_close_array(&bb, array);
ubus_send_reply(ctx, req, bb.head);
// free
blob_buf_free(&bb);
dm_ctx_clean(&bbf_ctx);
return 0;
}
static int libbbf_ubus_transaction_handler(struct ubus_context *ctx, struct ubus_object *obj,
struct ubus_request_data *req, const char *method __attribute__((unused)),
struct blob_attr *msg)
{
struct dmctx bbf_ctx;
struct blob_buf bb;
DMOBJ *tEntryObj = get_entry_object(obj->name);
if (!tEntryObj) {
printf("Failed to get DM entry obj\n\r");
return UBUS_STATUS_UNKNOWN_ERROR;
}
memset(&bbf_ctx, 0, sizeof(struct dmctx));
memset(&bb, 0, sizeof(struct blob_buf));
blob_buf_init(&bb, 0);
if (DM_STRCMP(method, "transaction_start") == 0) {
if (!g_dynamicdm_transaction_start) {
g_dynamicdm_transaction_start = true;
blobmsg_add_u8(&bb, "status", true);
} else {
printf("Transaction already in process\n");
blobmsg_add_u8(&bb, "status", false);
}
} else if(DM_STRCMP(method, "transaction_abort") == 0) {
if (g_dynamicdm_transaction_start) {
g_dynamicdm_transaction_start = false;
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
dm_entry_revert_changes();
dm_ctx_clean(&bbf_ctx);
blobmsg_add_u8(&bb, "status", true);
} else {
printf("Transaction still not started\n\r");
blobmsg_add_u8(&bb, "status", false);
}
} else if (DM_STRCMP(method, "transaction_commit") == 0) {
if (g_dynamicdm_transaction_start) {
g_dynamicdm_transaction_start = false;
dm_ctx_init_entry(&bbf_ctx, tEntryObj, 0);
dm_entry_manage_services(&bb, true);
dm_entry_restart_services();
dm_ctx_clean(&bbf_ctx);
blobmsg_add_u8(&bb, "status", true);
} else {
printf("Transaction still not started\n\r");
blobmsg_add_u8(&bb, "status", false);
}
} else {
printf("Unsupported method %s\n\r", method);
}
ubus_send_reply(ctx, req, bb.head);
blob_buf_free(&bb);
return 0;
}
int dynamicdm_init(struct ubus_context *ctx, char *ubus_name, DMOBJ *entry)
{
if (!ctx || !ubus_name || ubus_name[0] == '\0' || !entry)
return -1;
struct obj_node *new = (struct obj_node *)malloc(sizeof(struct obj_node));
if (!new)
return -1;
memset(new, 0, sizeof(struct obj_node));
new->ob = (struct ubus_object *) calloc(1, sizeof(struct ubus_object));
if (!new->ob) {
printf("Out of memory!!\n\r");
libbbf_ubus_obj_node_free(new);
return -1;
}
new->ob_type = (struct ubus_object_type *) calloc(1, sizeof(struct ubus_object_type));
if (!new->ob_type) {
printf("Out of memory!!\n\r");
libbbf_ubus_obj_node_free(new);
return -1;
}
new->obj_name = strdup(ubus_name);
new->ob_type->name = new->obj_name;
new->ob_type->id = 0;
new->ob_type->methods = libbbf_ubus_methods;
new->ob_type->n_methods = ARRAY_SIZE(libbbf_ubus_methods);
new->ob->name = new->obj_name;
new->ob->type = new->ob_type;
new->ob->methods = libbbf_ubus_methods;
new->ob->n_methods = ARRAY_SIZE(libbbf_ubus_methods);
if (ubus_add_object(ctx, new->ob)) {
printf("Failed to add object.\n\r");
libbbf_ubus_obj_node_free(new);
return -1;
}
new->tUsrObj = entry;
new->next = g_dynamicdm_head;
g_dynamicdm_head = new;
init_dm_path(entry);
return 0;
}
int dynamicdm_init_plugin_object(struct ubus_context *ctx, char *ubus_name, DM_MAP_OBJ *entry)
{
int i;
DMOBJ *tEntryObj = NULL;
if (!entry)
return -1;
for (i = 0; entry[i].path != NULL; i++) {
tEntryObj = (DMOBJ*)realloc(tEntryObj, sizeof(DMOBJ) * (i+1));
if (!tEntryObj) {
printf("No Memory exists\n\r");
return -1;
}
memset(&tEntryObj[i], 0, sizeof(DMOBJ));
tEntryObj[i].obj = entry[i].path;
tEntryObj[i].permission = &DMREAD;
tEntryObj[i].nextobj = entry[i].root_obj;
tEntryObj[i].leaf = entry[i].root_leaf;
tEntryObj[i].bbfdm_type = BBFDM_BOTH;
}
/* Make the last empty entry */
tEntryObj = (DMOBJ*)realloc(tEntryObj, sizeof(DMOBJ) * (i+1));
if (!tEntryObj) {
printf("No Memory exists\n\r");
return -1;
}
memset(&tEntryObj[i], 0, sizeof(DMOBJ));
if (0 != dynamicdm_init(ctx, ubus_name, tEntryObj)) {
FREE(tEntryObj);
return -1;
}
return 0;
}
void dynamicdm_free(struct ubus_context *ctx, const char *ubus_name)
{
struct obj_node *curr = g_dynamicdm_head, *prev = NULL;
if (!ctx|| !ubus_name || ubus_name[0] == '\0')
return;
if (curr == NULL)
return;
while (DM_STRCMP(ubus_name, curr->obj_name) != 0) {
if (curr->next == NULL) {
return;
} else {
prev = curr;
curr = curr->next;
}
}
if (curr == g_dynamicdm_head) {
g_dynamicdm_head = g_dynamicdm_head->next;
} else {
prev->next = curr->next;
}
if (curr->tUsrObj)
dm_cleanup_dynamic_entry(curr->tUsrObj);
ubus_remove_object(ctx, curr->ob);
libbbf_ubus_obj_node_free(curr);
}
void dynamicdm_free_plugin_object(struct ubus_context *ctx, const char *ubus_name)
{
if (!ctx || !ubus_name || ubus_name[0] == '\0')
return;
struct obj_node *ob_node = find_obj_node(ubus_name);
if (!ob_node)
return;
dm_cleanup_dynamic_entry(ob_node->tUsrObj);
FREE(ob_node->tUsrObj);
dynamicdm_free(ctx, ubus_name);
}