icwmp/datamodel_interface.c
2022-05-02 20:07:23 +05:30

667 lines
19 KiB
C
Executable file

/*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* Copyright (C) 2013-2021 iopsys Software Solutions AB
* Author Omar Kallel <omar.kallel@pivasoftware.com>
*/
#include <libubox/blobmsg_json.h>
#include "datamodel_interface.h"
#include "ubus_utils.h"
#include "log.h"
int transaction_id = 0;
enum get_results_types
{
LIST,
FAULT
};
struct object_result {
char **instance;
char fault[5];
bool status;
};
struct list_params_result {
struct list_head *parameters_list;
char fault[5];
enum get_results_types type;
};
struct setm_values_res {
bool status;
int *flag;
struct list_head *faults_list;
};
/*
* Common functions
*/
struct blob_attr *get_parameters_array(struct blob_attr *msg)
{
struct blob_attr *parameters = NULL;
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, msg, rem)
{
if (blobmsg_type(cur) == BLOBMSG_TYPE_ARRAY) {
parameters = cur;
break;
}
}
return parameters;
}
char *get_status(struct blob_attr *msg)
{
char *status = NULL;
const struct blobmsg_policy p[1] = { { "status", BLOBMSG_TYPE_STRING } };
struct blob_attr *tb[1] = { NULL };
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
if (tb[0])
status = blobmsg_get_string(tb[0]);
return status;
}
int get_fault(struct blob_attr *msg)
{
int fault = FAULT_CPE_NO_FAULT;
const struct blobmsg_policy p[1] = { { "fault", BLOBMSG_TYPE_INT32 } };
struct blob_attr *tb[1] = { NULL };
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
if (tb[0])
fault = blobmsg_get_u32(tb[0]);
return fault;
}
int get_parameters_list_from_parameters_blob_array(struct blob_attr *parameters, struct list_head *parameters_list)
{
const struct blobmsg_policy p[5] = { { "parameter", BLOBMSG_TYPE_STRING }, { "value", BLOBMSG_TYPE_STRING }, { "type", BLOBMSG_TYPE_STRING }, { "notification", BLOBMSG_TYPE_STRING }, { "writable", BLOBMSG_TYPE_STRING } };
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, parameters, rem)
{
int fault_code = get_fault(cur);
if (fault_code != FAULT_CPE_NO_FAULT) {
cwmp_free_all_dm_parameter_list(parameters_list);
return fault_code;
}
struct blob_attr *tb[5] = { NULL, NULL, NULL, NULL, NULL };
blobmsg_parse(p, 5, tb, blobmsg_data(cur), blobmsg_len(cur));
if (!tb[0])
continue;
int notification = 0;
bool writable = 0;
if (tb[1] && strncmp(blobmsg_get_string(tb[1]), "1", 1) == 0)
notification = 1;
else if (tb[1] && strncmp(blobmsg_get_string(tb[1]), "2", 1) == 0)
notification = 2;
if (tb[4] && (strncmp(blobmsg_get_string(tb[4]), "1", 1) == 0 || strcasecmp(blobmsg_get_string(tb[4]), "true") == 0))
writable = true;
add_dm_parameter_to_list(parameters_list, blobmsg_get_string(tb[0]), tb[1] ? blobmsg_get_string(tb[1]) : "", tb[2] ? blobmsg_get_string(tb[2]) : "", notification, writable);
}
return FAULT_CPE_NO_FAULT;
}
int get_single_fault_from_blob_attr(struct blob_attr *msg)
{
int fault_code = FAULT_CPE_NO_FAULT;
fault_code = get_fault(msg);
if (fault_code != FAULT_CPE_NO_FAULT)
return fault_code;
struct blob_attr *faults_array = get_parameters_array(msg);
if (faults_array == NULL)
return FAULT_CPE_NO_FAULT;
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, faults_array, rem)
{
fault_code = get_fault(cur);
if (fault_code != FAULT_CPE_NO_FAULT)
break;
}
return fault_code;
}
/*
* Transaction Functions
*/
void ubus_transaction_commit_callback(struct ubus_request *req __attribute__((unused)), int type __attribute__((unused)), struct blob_attr *msg)
{
bool *status = (bool *)req->priv;
const struct blobmsg_policy p[1] = { { "status", BLOBMSG_TYPE_BOOL } };
struct blob_attr *updated_services = NULL;
struct blob_attr *cur;
int rem;
struct blob_attr *tb[1] = { NULL };
blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg));
if (!tb[0]) {
*status = false;
return;
}
*status = blobmsg_get_u8(tb[0]);
if (*status == false)
return;
blobmsg_for_each_attr(cur, msg, rem)
{
if (blobmsg_type(cur) == BLOBMSG_TYPE_ARRAY) {
updated_services = cur;
break;
}
}
if (updated_services) {
blobmsg_for_each_attr(cur, updated_services, rem)
{
char *service_name = blobmsg_get_string(cur);
if (!service_name || strlen(service_name) == 0 || strcmp(service_name, "cwmp") == 0)
continue;
CWMP_LOG(INFO, "Detected service: %s will be restarted in the end session", service_name);
/*Add the service to the list*/
if (strcmp(service_name, "cwmp") != 0)
icwmp_add_service(service_name);
}
}
}
void ubus_transaction_callback(struct ubus_request *req __attribute__((unused)), int type __attribute__((unused)), struct blob_attr *msg)
{
bool *status = (bool *)req->priv;
const struct blobmsg_policy p[2] = { { "status", BLOBMSG_TYPE_BOOL }, { "transaction_id", BLOBMSG_TYPE_INT32 } };
struct blob_attr *tb[2] = { NULL, NULL };
blobmsg_parse(p, 2, tb, blobmsg_data(msg), blobmsg_len(msg));
*status = blobmsg_get_u8(tb[0]);
if (*status == true && tb[1])
transaction_id = blobmsg_get_u32(tb[1]);
}
void ubus_transaction_status_callback(struct ubus_request *req __attribute__((unused)), int type __attribute__((unused)), struct blob_attr *msg)
{
bool *status = (bool *)req->priv;
char *status_str = NULL;
const struct blobmsg_policy p[2] = { { "status", BLOBMSG_TYPE_STRING } };
struct blob_attr *tb[2] = { NULL, NULL };
blobmsg_parse(p, 2, tb, blobmsg_data(msg), blobmsg_len(msg));
status_str = blobmsg_get_string(tb[0]);
if (strcmp(status_str, "on-going") == 0)
*status = true;
else
*status = false;
}
bool cwmp_transaction_start(char *app)
{
CWMP_LOG(INFO, "Starting transaction ...");
bool status = false;
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
bb_add_string(&b, "app", app);
int e = icwmp_ubus_invoke(USP_OBJECT_NAME, "transaction_start", b.head, ubus_transaction_callback, &status);
if (e != 0) {
CWMP_LOG(INFO, "Transaction start failed: Ubus err code: %d", e);
status = false;
}
if (!status) {
CWMP_LOG(INFO, "Transaction Start doesn't success\n");
}
blob_buf_free(&b);
return status;
}
bool cwmp_transaction_commit()
{
CWMP_LOG(INFO, "Transaction Commit ...");
bool status = false;
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "transaction_id", transaction_id);
blobmsg_add_u8(&b, "restart_service", false);
int e = icwmp_ubus_invoke(USP_OBJECT_NAME, "transaction_commit", b.head, ubus_transaction_commit_callback, &status);
if (e != 0) {
CWMP_LOG(INFO, "Transaction commit failed: Ubus err code: %d", e);
status = false;
}
if (!status) {
CWMP_LOG(INFO, "Transaction Commit with id: %d doesn't success\n", transaction_id);
}
blob_buf_free(&b);
transaction_id = 0;
return status;
}
bool cwmp_transaction_abort()
{
CWMP_LOG(INFO, "Transaction Abort ...");
bool status = false;
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "transaction_id", transaction_id);
int e = icwmp_ubus_invoke(USP_OBJECT_NAME, "transaction_abort", b.head, ubus_transaction_callback, &status);
if (e != 0) {
CWMP_LOG(INFO, "Transaction abort failed: Ubus err code: %d", e);
status = false;
}
if (!status) {
CWMP_LOG(INFO, "Transaction Abort of transaction with id: %d failed\n", transaction_id);
}
blob_buf_free(&b);
transaction_id = 0;
return status;
}
bool cwmp_transaction_status()
{
CWMP_LOG(INFO, "Transaction Status");
bool status = false;
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
blobmsg_add_u32(&b, "transaction_id", transaction_id);
int e = icwmp_ubus_invoke(USP_OBJECT_NAME, "transaction_status", b.head, ubus_transaction_status_callback, &status);
blob_buf_free(&b);
if (e != 0) {
CWMP_LOG(INFO, "Transaction status failed: Ubus err code: %d", e);
return false;
}
if (!status) {
CWMP_LOG(INFO, "Transaction with id: %d is not available anymore\n", transaction_id);
}
return status;
}
/*
* Get single _parameter value
*/
void ubus_get_single_parameter_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct blob_attr *parameters = get_parameters_array(msg);
struct cwmp_dm_parameter *result = (struct cwmp_dm_parameter *)req->priv;
if (parameters == NULL) {
int fault_code = get_fault(msg);
result->name = NULL;
result->type = NULL;
icwmp_asprintf(&result->value, "%d", fault_code);
return;
}
const struct blobmsg_policy p[3] = { { "parameter", BLOBMSG_TYPE_STRING }, { "value", BLOBMSG_TYPE_STRING }, { "type", BLOBMSG_TYPE_STRING } };
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, parameters, rem)
{
struct blob_attr *tb[3] = { NULL, NULL, NULL };
blobmsg_parse(p, 3, tb, blobmsg_data(cur), blobmsg_len(cur));
if (!tb[0])
continue;
result->name = icwmp_strdup(blobmsg_get_string(tb[0]));
result->value = icwmp_strdup(tb[1] ? blobmsg_get_string(tb[1]) : "");
result->type = icwmp_strdup(tb[2] ? blobmsg_get_string(tb[2]) : "");
break;
}
}
char *cwmp_get_single_parameter_value(char *parameter_name, struct cwmp_dm_parameter *dm_parameter)
{
int e;
struct cwmp *cwmp = &cwmp_main;
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
bb_add_string(&b, "path", !parameter_name || parameter_name[0] == '\0' ? DM_ROOT_OBJ : parameter_name);
bb_add_string(&b, "proto", "cwmp");
blobmsg_add_u32(&b, "instance_mode", cwmp->conf.instance_mode);
e = icwmp_ubus_invoke(USP_OBJECT_NAME, "get", b.head, ubus_get_single_parameter_callback, dm_parameter);
blob_buf_free(&b);
if (e < 0) {
CWMP_LOG(INFO, "get ubus method failed: Ubus err code: %d", e);
return "9002";
}
if (dm_parameter->name == NULL) {
CWMP_LOG(INFO, "Get parameter_values failed: fault_code: %s", dm_parameter->value); // the value is the fault
return dm_parameter->value;
}
return NULL;
}
int cwmp_get_leaf_value(char *leaf, char **value)
{
struct cwmp_dm_parameter dm_param = {0};
size_t llen;
if (leaf == NULL || value == NULL) {
CWMP_LOG(INFO, "Empty parameter/value in arguments")
return FAULT_CPE_INVALID_ARGUMENTS;
}
llen = strlen(leaf);
if (llen == 0) {
CWMP_LOG(INFO, "Empty parameter in arguments")
return FAULT_CPE_INVALID_ARGUMENTS;
}
if (leaf[llen - 1] == '.') {
CWMP_LOG(INFO, "Non-leaf parameter parameter")
return FAULT_CPE_INVALID_ARGUMENTS;
}
cwmp_get_single_parameter_value(leaf, &dm_param);
if (dm_param.name == NULL) {
CWMP_LOG(INFO, "Fault in getting the parameter %s", leaf)
return FAULT_CPE_INTERNAL_ERROR;
}
if (strncmp(leaf, dm_param.name, llen) == 0) {
*value = (dm_param.value) ? strdup(dm_param.value) : strdup("");
} else {
CWMP_LOG(WARNING, "Param %s, does not return a value", leaf);
return FAULT_CPE_INTERNAL_ERROR;
}
return 0;
}
/*
* Get parameter Values/Names/Notify
*/
void ubus_get_parameter_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct blob_attr *parameters = get_parameters_array(msg);
struct list_params_result *result = (struct list_params_result *)req->priv;
int fault_code = FAULT_CPE_NO_FAULT;
if (parameters == NULL) {
fault_code = get_fault(msg);
snprintf(result->fault, 5, "%d", fault_code);
result->type = FAULT;
return;
}
result->type = LIST;
fault_code = get_parameters_list_from_parameters_blob_array(parameters, result->parameters_list);
if (fault_code != FAULT_CPE_NO_FAULT) {
snprintf(result->fault, 5, "%d", fault_code);
result->type = FAULT;
}
}
char *cwmp_get_parameter_values(char *parameter_name, struct list_head *parameters_list)
{
int e;
struct cwmp *cwmp = &cwmp_main;
struct list_params_result get_result = { .parameters_list = parameters_list };
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
bb_add_string(&b, "path", !parameter_name || parameter_name[0] == '\0' ? DM_ROOT_OBJ : parameter_name);
bb_add_string(&b, "proto", "cwmp");
blobmsg_add_u32(&b, "instance_mode", cwmp->conf.instance_mode);
e = icwmp_ubus_invoke(USP_OBJECT_NAME, "get", b.head, ubus_get_parameter_callback, &get_result);
blob_buf_free(&b);
if (e < 0) {
CWMP_LOG(INFO, "get ubus method failed: Ubus err code: %d", e);
return "9002";
}
if (get_result.type == FAULT) {
CWMP_LOG(INFO, "Get parameter values failed: fault_code: %s", get_result.fault);
return icwmp_strdup(get_result.fault);
}
return NULL;
}
char *cwmp_get_multiple_parameters_values(struct list_head *arg_params_list, struct list_head *parameters_list)
{
int e;
struct cwmp *cwmp = &cwmp_main;
struct cwmp_dm_parameter *param_value;
struct list_params_result get_result = { .parameters_list = parameters_list };
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
void *arr = blobmsg_open_array(&b, "paths");
list_for_each_entry (param_value, arg_params_list, list) {
if (!param_value->name)
break;
blobmsg_add_string(&b, NULL, param_value->name);
}
blobmsg_close_array(&b, arr);
blobmsg_add_u32(&b, "instance_mode", cwmp->conf.instance_mode);
e = icwmp_ubus_invoke(USP_OBJECT_NAME, "getm_values", b.head, ubus_get_parameter_callback, &get_result );
blob_buf_free(&b);
if (e < 0) {
CWMP_LOG(INFO, "getm_values ubus method failed: Ubus err code: %d", e);
return "9002";
}
if (get_result.type == FAULT) {
CWMP_LOG(INFO, "Get multiple parameters values failed: fault_code: %s", get_result.fault);
return strdup(get_result.fault);
}
return NULL;
}
char *cwmp_get_parameter_names(char *object_name, bool next_level, struct list_head *parameters_list)
{
int e;
struct list_params_result get_result = { .parameters_list = parameters_list };
struct cwmp *cwmp = &cwmp_main;
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
bb_add_string(&b, "path", object_name);
blobmsg_add_u8(&b, "next-level", next_level);
bb_add_string(&b, "proto", "cwmp");
blobmsg_add_u32(&b, "instance_mode", cwmp->conf.instance_mode);
e = icwmp_ubus_invoke(USP_OBJECT_NAME, "object_names", b.head, ubus_get_parameter_callback, &get_result);
blob_buf_free(&b);
if (e < 0) {
CWMP_LOG(INFO, "object_names ubus method failed: Ubus err code: %d", e);
return "9002";
}
if (get_result.type == FAULT) {
CWMP_LOG(INFO, "GetParameterNames failed: fault_code: %s", get_result.fault);
return icwmp_strdup(get_result.fault);
}
return NULL;
}
/*
* Set multiple parameter values
*/
void ubus_setm_values_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
struct setm_values_res *set_result = (struct setm_values_res *)req->priv;
const struct blobmsg_policy p[2] = { { "status", BLOBMSG_TYPE_BOOL }, { "flag", BLOBMSG_TYPE_INT64 } };
struct blob_attr *tb[2] = { NULL, NULL };
blobmsg_parse(p, 2, tb, blobmsg_data(msg), blobmsg_len(msg));
if (tb[0]) {
set_result->status = blobmsg_get_u8(tb[0]);
if (set_result->status) {
int *flag = set_result->flag;
*flag = tb[1] ? blobmsg_get_u64(tb[1]) : 0;
return;
}
}
set_result->status = false;
struct blob_attr *faults_params = get_parameters_array(msg);
const struct blobmsg_policy pfault[3] = { { "path", BLOBMSG_TYPE_STRING }, { "fault", BLOBMSG_TYPE_INT32 }, { "status", BLOBMSG_TYPE_BOOL } };
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, faults_params, rem)
{
struct blob_attr *tbi[3] = { NULL, NULL, NULL };
blobmsg_parse(pfault, 3, tbi, blobmsg_data(cur), blobmsg_len(cur));
if (!tbi[0] || !tbi[1])
continue;
cwmp_add_list_fault_param(blobmsg_get_string(tbi[0]), blobmsg_get_u32(tbi[1]), set_result->faults_list);
}
}
int cwmp_set_multiple_parameters_values(struct list_head *parameters_values_list, char *parameter_key, int *flag, struct list_head *faults_list)
{
int e;
struct cwmp_dm_parameter *param_value;
struct setm_values_res set_result = { .flag = flag, .faults_list = faults_list };
struct cwmp *cwmp = &cwmp_main;
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
void *arr = blobmsg_open_array(&b, "pv_tuple");
list_for_each_entry (param_value, parameters_values_list, list) {
if (!param_value->name)
break;
void *tbl = blobmsg_open_table(&b, "");
blobmsg_add_string(&b, "path", param_value->name);
blobmsg_add_string(&b, "value", param_value->value);
blobmsg_close_table(&b, tbl);
}
blobmsg_close_array(&b, arr);
bb_add_string(&b, "key", parameter_key);
blobmsg_add_u32(&b, "transaction_id", transaction_id);
bb_add_string(&b, "proto", "cwmp");
blobmsg_add_u32(&b, "instance_mode", cwmp->conf.instance_mode);
e = icwmp_ubus_invoke(USP_OBJECT_NAME, "setm_values", b.head, ubus_setm_values_callback, &set_result);
blob_buf_free(&b);
if (e < 0) {
CWMP_LOG(INFO, "setm_values ubus method failed: Ubus err code: %d", e);
return FAULT_CPE_INTERNAL_ERROR;
}
if (set_result.status == false) {
CWMP_LOG(INFO, "Set parameter_values failed");
return FAULT_CPE_INVALID_ARGUMENTS;
}
return FAULT_CPE_NO_FAULT;
}
/*
* Add Delete object
*/
void ubus_objects_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg)
{
int fault_code = get_single_fault_from_blob_attr(msg);
struct object_result *result = (struct object_result *)req->priv;
if (fault_code != FAULT_CPE_NO_FAULT) {
snprintf(result->fault, 5, "%d", fault_code);
result->status = false;
return;
}
struct blob_attr *parameters = get_parameters_array(msg);
const struct blobmsg_policy p[2] = { { "status", BLOBMSG_TYPE_BOOL }, { "instance", BLOBMSG_TYPE_STRING } };
struct blob_attr *cur;
int rem;
blobmsg_for_each_attr(cur, parameters, rem)
{
struct blob_attr *tb[2] = { NULL, NULL };
blobmsg_parse(p, 2, tb, blobmsg_data(cur), blobmsg_len(cur));
if (!tb[0])
continue;
result->status = blobmsg_get_u8(tb[0]);
if (tb[1]) {
char **instance = result->instance;
*instance = strdup(blobmsg_get_string(tb[1]));
}
break;
}
}
static void prepare_add_delete_blobmsg(struct blob_buf *b, char *object_name, char *key)
{
if (b == NULL)
return;
bb_add_string(b, "path", object_name);
bb_add_string(b, "key", key);
blobmsg_add_u32(b, "transaction_id", transaction_id);
bb_add_string(b, "proto", "cwmp");
blobmsg_add_u32(b, "instance_mode", cwmp_main.conf.instance_mode);
}
char *cwmp_add_object(char *object_name, char *key, char **instance)
{
int e;
struct object_result add_result = { .instance = instance };
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
prepare_add_delete_blobmsg(&b, object_name, key);
e = icwmp_ubus_invoke(USP_OBJECT_NAME, "add_object", b.head, ubus_objects_callback, &add_result);
blob_buf_free(&b);
if (e < 0) {
CWMP_LOG(INFO, "add_object ubus method failed: Ubus err code: %d", e);
return "9002";
}
if (add_result.status == false) {
CWMP_LOG(INFO, "AddObject failed");
return icwmp_strdup(add_result.fault);
}
return NULL;
}
char *cwmp_delete_object(char *object_name, char *key)
{
int e;
struct object_result add_result = { .instance = NULL };
struct blob_buf b = { 0 };
memset(&b, 0, sizeof(struct blob_buf));
blob_buf_init(&b, 0);
prepare_add_delete_blobmsg(&b, object_name, key);
e = icwmp_ubus_invoke(USP_OBJECT_NAME, "del_object", b.head, ubus_objects_callback, &add_result);
blob_buf_free(&b);
if (e < 0) {
CWMP_LOG(INFO, "del_object ubus method failed: Ubus err code: %d", e);
return "9002";
}
if (add_result.status == false) {
CWMP_LOG(INFO, "DeleteObject failed");
return icwmp_strdup(add_result.fault);
}
return NULL;
}