diff --git a/Makefile.am b/Makefile.am index 9468741..027c62d 100644 --- a/Makefile.am +++ b/Makefile.am @@ -15,7 +15,7 @@ icwmpd_SOURCES = \ ./event.c \ ./http.c \ ./netlink.c \ - ./ubus.c \ + ./ubus_utils.c \ ./datamodel_interface.c \ ./cwmp_cli.c \ ./notifications.c \ diff --git a/README.md b/README.md index 5d76853..2ad85fd 100644 --- a/README.md +++ b/README.md @@ -205,16 +205,6 @@ root@iopsys:~# ubus call tr069 command '{"command":"reload"}' } root@iopsys:~# ``` -- To exit the icwmpd daemon, use the `command` ubus method with `exit` argument: - -```bash -root@iopsys:~# ubus call tr069 command '{"command":"exit"}' -{ - "status": 1, - "info": "icwmpd daemon stopped" -} -root@iopsys:~# -``` ## icwmpd command line `icwmpd` command line options are described with `--help` option as below: diff --git a/common.c b/common.c index 5d8307b..4da1d1b 100755 --- a/common.c +++ b/common.c @@ -19,7 +19,7 @@ #include "common.h" #include "cwmp_cli.h" #include "cwmp_uci.h" -#include "ubus.h" +#include "ubus_utils.h" #include "log.h" @@ -29,8 +29,6 @@ char *commandKey = NULL; bool thread_end = false; -bool signal_exit = false; -bool ubus_exit = false; long int flashsize = 256000000; struct cwmp cwmp_main = { 0 }; static int nbre_services = 0; @@ -287,7 +285,13 @@ void cwmp_reboot(char *command_key) cwmp_uci_set_varstate_value("cwmp", "cpe", "ParameterKey", command_key); cwmp_commit_package("cwmp", UCI_VARSTATE_CONFIG); - cwmp_ubus_call("rpc-sys", "reboot", CWMP_UBUS_ARGS{ {} }, 0, NULL, NULL); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + + icwmp_ubus_invoke("rpc-sys", "reboot", b.head, NULL, NULL); + + blob_buf_free(&b); } /* @@ -295,7 +299,13 @@ void cwmp_reboot(char *command_key) */ void cwmp_factory_reset() //use the ubus rpc-sys factory { - cwmp_ubus_call("rpc-sys", "factory", CWMP_UBUS_ARGS{ {} }, 0, NULL, NULL); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + + icwmp_ubus_invoke("rpc-sys", "factory", b.head, NULL, NULL); + + blob_buf_free(&b); } long int get_file_size(char *file_name) @@ -564,9 +574,14 @@ void icwmp_restart_services() if (list_services[i] == NULL) continue; - cwmp_ubus_call("uci", "commit", - CWMP_UBUS_ARGS{ { "config", { .str_val = list_services[i] }, UBUS_String } }, 1, NULL, - NULL); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + bb_add_string(&b, "config", list_services[i]); + + icwmp_ubus_invoke("uci", "commit", b.head, NULL, NULL); + + blob_buf_free(&b); if (strcmp(list_services[i], "firewall") == 0) { g_firewall_restart = true; @@ -698,7 +713,14 @@ void ubus_network_interface_callback(struct ubus_request *req __attribute__((unu int get_connection_interface() { - int e = cwmp_ubus_call("network.interface", "status", CWMP_UBUS_ARGS{ { "interface", { .str_val = cwmp_main.conf.default_wan_iface }, UBUS_String } }, 1, ubus_network_interface_callback, NULL); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + bb_add_string(&b, "interface", cwmp_main.conf.default_wan_iface); + + int e = icwmp_ubus_invoke("network.interface", "status", b.head, ubus_network_interface_callback, NULL); + blob_buf_free(&b); + if (e != 0) { CWMP_LOG(INFO, "Get network interface from network.interface ubus method failed. Ubus err code: %d", e); return -1; diff --git a/cwmp.c b/cwmp.c index 32aec09..2a75e12 100644 --- a/cwmp.c +++ b/cwmp.c @@ -15,6 +15,7 @@ #include #include #include +#include #include "common.h" #include "ssl_utils.h" @@ -29,13 +30,14 @@ #include "rpc_soap.h" #include "config.h" #include "backupSession.h" -#include "ubus.h" +#include "ubus_utils.h" #include "digestauth.h" #include "upload.h" #include "download.h" #include "sched_inform.h" #include "datamodel_interface.h" #include "cwmp_du_state.h" +#include "netlink.h" static pthread_t periodic_event_thread; static pthread_t scheduleInform_thread; @@ -47,8 +49,8 @@ static pthread_t upload_thread; static pthread_t ubus_thread; static pthread_t http_cr_server_thread; static pthread_t periodic_check_notify; -static pthread_t signal_handler_thread; bool g_firewall_restart = false; +static struct ubus_context *ctx = NULL; static int cwmp_get_retry_interval(struct cwmp *cwmp) { @@ -439,9 +441,46 @@ static void cwmp_schedule_session(struct cwmp *cwmp) } } +static void check_exit_timer_expiry(struct uloop_timeout *timeout) +{ + if (thread_end == true) { + uloop_end(); + } + + uloop_timeout_set(timeout, 1); +} + static void *thread_uloop_run(void *v __attribute__((unused))) { - cwmp_ubus_init(&cwmp_main); + uloop_init(); + + if (netlink_init()) { + CWMP_LOG(ERROR, "netlink initialization failed"); + } + + if (cwmp_main.conf.ipv6_enable) { + if (netlink_init_v6()) { + CWMP_LOG(ERROR, "netlink initialization failed"); + } + } + + ctx = ubus_connect(cwmp_main.conf.ubus_socket); + if (!ctx) + return NULL; + + ubus_add_uloop(ctx); + + if (icwmp_register_object(ctx)) + return NULL; + + struct uloop_timeout tm; + memset(&tm, 0, sizeof(tm)); + tm.cb = check_exit_timer_expiry; + uloop_timeout_set(&tm, 1); + + uloop_run(); + uloop_done(); + return NULL; } @@ -753,36 +792,37 @@ static void cwmp_free(struct cwmp *cwmp) FREE(nonce_privacy_key); clean_list_param_notify(); bkp_tree_clean(); - cwmp_ubus_exit(); + + if (ctx) { + icwmp_delete_object(ctx); + ubus_free(ctx); + } + clean_custom_inform_parameters(); icwmp_cleanmem(); cwmp_uci_exit(); } -static void *thread_cwmp_signal_handler_thread(void *arg) +static void icwmp_signal_handler(int signal_num) { - sigset_t *set = (sigset_t *)arg; + if (signal_num == SIGINT || signal_num == SIGTERM) { + thread_end = true; - for (;;) { - int s, signal_num; - s = sigwait(set, &signal_num); - if (s == -1) { - CWMP_LOG(ERROR, "Error in sigwait"); - } else { - CWMP_LOG(INFO, "Catch of Signal(%d)", signal_num); + if (cwmp_main.session_status.last_status == SESSION_RUNNING) + http_set_timeout(); - if (signal_num == SIGINT || signal_num == SIGTERM) { - signal_exit = true; + pthread_cond_signal(&(cwmp_main.threshold_session_send)); + pthread_cond_signal(&(cwmp_main.threshold_periodic)); + pthread_cond_signal(&(cwmp_main.threshold_notify_periodic)); + pthread_cond_signal(&threshold_schedule_inform); + pthread_cond_signal(&threshold_download); + pthread_cond_signal(&threshold_change_du_state); + pthread_cond_signal(&threshold_schedule_download); + pthread_cond_signal(&threshold_apply_schedule_download); + pthread_cond_signal(&threshold_upload); - if (!ubus_exit) - cwmp_ubus_call("tr069", "command", CWMP_UBUS_ARGS{ { "command", { .str_val = "exit" }, UBUS_String } }, 1, NULL, NULL); - - break; - } - } + shutdown(cwmp_main.cr_socket_desc, SHUT_RDWR); } - - return NULL; } static void configure_var_state(struct cwmp *cwmp) @@ -805,7 +845,7 @@ static void configure_var_state(struct cwmp *cwmp) int main(int argc, char **argv) { struct cwmp *cwmp = &cwmp_main; - sigset_t set; + struct sigaction act; int error; openlog("cwmp", LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); @@ -825,10 +865,10 @@ int main(int argc, char **argv) configure_var_state(cwmp); http_server_init(); - sigemptyset(&set); - sigaddset(&set, SIGINT); - sigaddset(&set, SIGTERM); - sigprocmask(SIG_BLOCK, &set, NULL); + memset(&act, 0, sizeof(act)); + act.sa_handler = icwmp_signal_handler; + sigaction(SIGINT, &act, 0); + sigaction(SIGTERM, &act, 0); error = pthread_create(&http_cr_server_thread, NULL, &thread_http_cr_server_listen, NULL); if (error < 0) { @@ -879,11 +919,6 @@ int main(int argc, char **argv) CWMP_LOG(ERROR, "Error when creating the download thread!"); } - error = pthread_create(&signal_handler_thread, NULL, &thread_cwmp_signal_handler_thread, (void *)&set); - if (error < 0) { - CWMP_LOG(ERROR, "Error when creating the signal handler thread!"); - } - cwmp_schedule_session(cwmp); /* Join all threads */ @@ -897,7 +932,6 @@ int main(int argc, char **argv) pthread_join(change_du_state_thread, NULL); pthread_join(http_cr_server_thread, NULL); pthread_join(ubus_thread, NULL); - pthread_join(signal_handler_thread, NULL); /* Free all memory allocation */ cwmp_free(cwmp); diff --git a/cwmp_du_state.c b/cwmp_du_state.c index d810cc9..914811a 100644 --- a/cwmp_du_state.c +++ b/cwmp_du_state.c @@ -13,7 +13,7 @@ #include #include "cwmp_du_state.h" -#include "ubus.h" +#include "ubus_utils.h" #include "log.h" #include "datamodel_interface.h" #include "backupSession.h" @@ -36,12 +36,30 @@ void ubus_du_state_callback(struct ubus_request *req, int type __attribute__((un } } +static void prepare_blob_msg(struct blob_buf *b, char *url, char *uuid, char *user, char *pass, char *env_name, int env_id) +{ + if (b == NULL) + return; + + bb_add_string(b, "ee_name", env_name); + blobmsg_add_u32(b, "eeid", env_id); + bb_add_string(b, "url", url); + bb_add_string(b, "uuid", uuid); + bb_add_string(b, "username", user); + bb_add_string(b, "password", pass); +} + int cwmp_du_install(char *url, char *uuid, char *user, char *pass, char *env_name, int env_id, char **fault_code) { int e; - e = cwmp_ubus_call("swmodules", "du_install", - CWMP_UBUS_ARGS{ { "ee_name", {.str_val = env_name }, UBUS_String }, { "eeid", {.int_val = env_id }, UBUS_Integer }, { "url", {.str_val = url }, UBUS_String }, { "uuid", {.str_val = uuid ? uuid : "" }, UBUS_String }, { "username", {.str_val = user ? user : "" }, UBUS_String }, { "password", {.str_val = pass ? pass : ""}, UBUS_String } }, 6, - ubus_du_state_callback, fault_code); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + + prepare_blob_msg(&b, url, uuid, user, pass, env_name, env_id); + e = icwmp_ubus_invoke("swmodules", "du_install", b.head, ubus_du_state_callback, fault_code); + blob_buf_free(&b); + if (e < 0) { CWMP_LOG(INFO, "Change du state install failed: Ubus err code: %d", e); return FAULT_CPE_INTERNAL_ERROR; @@ -52,8 +70,14 @@ int cwmp_du_install(char *url, char *uuid, char *user, char *pass, char *env_nam int cwmp_du_update(char *url, char *uuid, char *user, char *pass, char *env_name, int env_id, char **fault_code) { int e; - e = cwmp_ubus_call("swmodules", "du_update", CWMP_UBUS_ARGS{ { "ee_name", {.str_val = env_name }, UBUS_String }, { "eeid", {.int_val = env_id }, UBUS_Integer }, { "url", {.str_val = url }, UBUS_String }, { "uuid", {.str_val = uuid ? uuid : "" }, UBUS_String }, { "username", {.str_val = user ? user : "" }, UBUS_String }, { "password", {.str_val = pass ? pass : "" }, UBUS_String } }, 6, ubus_du_state_callback, - fault_code); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + + prepare_blob_msg(&b, url, uuid, user, pass, env_name, env_id); + e = icwmp_ubus_invoke("swmodules", "du_update", b.head, ubus_du_state_callback, fault_code); + blob_buf_free(&b); + if (e < 0) { CWMP_LOG(INFO, "Change du state update failed: Ubus err code: %d", e); return FAULT_CPE_INTERNAL_ERROR; @@ -64,7 +88,17 @@ int cwmp_du_update(char *url, char *uuid, char *user, char *pass, char *env_name int cwmp_du_uninstall(char *package_name, char *env_name, int env_id, char **fault_code) { int e; - e = cwmp_ubus_call("swmodules", "du_uninstall", CWMP_UBUS_ARGS{ { "ee_name", {.str_val = env_name }, UBUS_String }, { "eeid", {.int_val = env_id }, UBUS_Integer }, { "du_name", {.str_val = package_name }, UBUS_String } }, 3, ubus_du_state_callback, fault_code); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + + bb_add_string(&b, "ee_name", env_name); + blobmsg_add_u32(&b, "eeid", env_id); + bb_add_string(&b, "du_name", package_name); + + e = icwmp_ubus_invoke("swmodules", "du_uninstall", b.head, ubus_du_state_callback, fault_code); + blob_buf_free(&b); + if (e < 0) { CWMP_LOG(INFO, "Change du state uninstall failed: Ubus err code: %d", e); return FAULT_CPE_INTERNAL_ERROR; diff --git a/datamodel_interface.c b/datamodel_interface.c index 9c48222..094d1e9 100755 --- a/datamodel_interface.c +++ b/datamodel_interface.c @@ -11,7 +11,7 @@ #include #include "datamodel_interface.h" -#include "ubus.h" +#include "ubus_utils.h" #include "log.h" int transaction_id = 0; @@ -200,7 +200,13 @@ bool cwmp_transaction_start(char *app) { CWMP_LOG(INFO, "Starting transaction ..."); bool status = false; - int e = cwmp_ubus_call(USP_OBJECT_NAME, "transaction_start", CWMP_UBUS_ARGS{ { "app", { .str_val = app }, UBUS_String } }, 1, ubus_transaction_callback, &status); + 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; @@ -208,6 +214,8 @@ bool cwmp_transaction_start(char *app) if (!status) { CWMP_LOG(INFO, "Transaction Start doesn't success\n"); } + + blob_buf_free(&b); return status; } @@ -215,7 +223,14 @@ bool cwmp_transaction_commit() { CWMP_LOG(INFO, "Transaction Commit ..."); bool status = false; - int e = cwmp_ubus_call(USP_OBJECT_NAME, "transaction_commit", CWMP_UBUS_ARGS{ { "transaction_id", { .int_val = transaction_id }, UBUS_Integer }, { "restart_services", { .bool_val = false }, UBUS_Bool } }, 2, ubus_transaction_commit_callback, &status); + 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; @@ -224,6 +239,7 @@ bool cwmp_transaction_commit() CWMP_LOG(INFO, "Transaction Commit with id: %d doesn't success\n", transaction_id); } + blob_buf_free(&b); transaction_id = 0; return status; } @@ -232,7 +248,13 @@ bool cwmp_transaction_abort() { CWMP_LOG(INFO, "Transaction Abort ..."); bool status = false; - int e = cwmp_ubus_call(USP_OBJECT_NAME, "transaction_abort", CWMP_UBUS_ARGS{ { "transaction_id", { .int_val = transaction_id }, UBUS_Integer } }, 1, ubus_transaction_callback, &status); + 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; @@ -240,6 +262,8 @@ bool cwmp_transaction_abort() 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; } @@ -248,7 +272,15 @@ bool cwmp_transaction_status() { CWMP_LOG(INFO, "Transaction Status"); bool status = false; - int e = cwmp_ubus_call(USP_OBJECT_NAME, "transaction_status", CWMP_UBUS_ARGS{ { "transaction_id", { .int_val = transaction_id }, UBUS_Integer } }, 1, ubus_transaction_status_callback, &status); + 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; @@ -293,7 +325,17 @@ char *cwmp_get_single_parameter_value(char *parameter_name, struct cwmp_dm_param { int e; struct cwmp *cwmp = &cwmp_main; - e = cwmp_ubus_call(USP_OBJECT_NAME, "get", CWMP_UBUS_ARGS{ { "path", { .str_val = !parameter_name || parameter_name[0] == '\0' ? DM_ROOT_OBJ : parameter_name }, UBUS_String }, { "proto", { .str_val = "cwmp" }, UBUS_String }, { "instance_mode", { .int_val = cwmp->conf.instance_mode }, UBUS_Integer } }, 3, ubus_get_single_parameter_callback, dm_parameter); + 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"; @@ -370,7 +412,17 @@ char *cwmp_get_parameter_values(char *parameter_name, struct list_head *paramete int e; struct cwmp *cwmp = &cwmp_main; struct list_params_result get_result = { .parameters_list = parameters_list }; - e = cwmp_ubus_call(USP_OBJECT_NAME, "get", CWMP_UBUS_ARGS{ { "path", { .str_val = !parameter_name || parameter_name[0] == '\0' ? DM_ROOT_OBJ : parameter_name }, UBUS_String }, { "proto", { .str_val = "cwmp" }, UBUS_String }, { "instance_mode", { .int_val = cwmp->conf.instance_mode }, UBUS_Integer } }, 3, ubus_get_parameter_callback, &get_result); + 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"; @@ -387,8 +439,24 @@ char *cwmp_get_multiple_parameters_values(struct list_head *arg_params_list, str { int e; struct cwmp *cwmp = &cwmp_main; + struct cwmp_dm_parameter *param_value; struct list_params_result get_result = { .parameters_list = parameters_list }; - e = cwmp_ubus_call(USP_OBJECT_NAME, "getm_values", CWMP_UBUS_ARGS{ { "paths", { .param_value_list = arg_params_list }, UBUS_List_Param_Get }, { "instance_mode", { .int_val = cwmp->conf.instance_mode }, UBUS_Integer } }, 2, ubus_get_parameter_callback, &get_result ); + 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"; @@ -406,7 +474,18 @@ char *cwmp_get_parameter_names(char *object_name, bool next_level, struct list_h int e; struct list_params_result get_result = { .parameters_list = parameters_list }; struct cwmp *cwmp = &cwmp_main; - e = cwmp_ubus_call(USP_OBJECT_NAME, "object_names", CWMP_UBUS_ARGS{ { "path", { .str_val = object_name }, UBUS_String }, { "next-level", { .bool_val = next_level }, UBUS_Bool }, { "proto", { .str_val = "cwmp" }, UBUS_String }, { "instance_mode", { .int_val = cwmp->conf.instance_mode }, UBUS_Integer } }, 4, ubus_get_parameter_callback, &get_result); + 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"; @@ -456,11 +535,30 @@ void ubus_setm_values_callback(struct ubus_request *req, int type __attribute__( 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; - e = cwmp_ubus_call(USP_OBJECT_NAME, "setm_values", - CWMP_UBUS_ARGS{ { "pv_tuple", { .param_value_list = parameters_values_list }, UBUS_List_Param_Set }, { "key", { .str_val = parameter_key }, UBUS_String }, { "transaction_id", { .int_val = transaction_id }, UBUS_Integer }, { "proto", { .str_val = "cwmp" }, UBUS_String }, { "instance_mode", { .int_val = cwmp->conf.instance_mode }, UBUS_Integer } }, 5, - ubus_setm_values_callback, &set_result); + 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); @@ -506,13 +604,30 @@ void ubus_objects_callback(struct ubus_request *req, int type __attribute__((unu } } +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 cwmp *cwmp = &cwmp_main; struct object_result add_result = { .instance = instance }; - e = cwmp_ubus_call(USP_OBJECT_NAME, "add_object", CWMP_UBUS_ARGS{ { "path", { .str_val = object_name }, UBUS_String }, { "key", { .str_val = key }, UBUS_String }, { "transaction_id", { .int_val = transaction_id }, UBUS_Integer }, { "proto", { .str_val = "cwmp" }, UBUS_String }, { "instance_mode", { .int_val = cwmp->conf.instance_mode }, UBUS_Integer } }, 5, - ubus_objects_callback, &add_result); + 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); @@ -529,9 +644,15 @@ char *cwmp_delete_object(char *object_name, char *key) { int e; struct object_result add_result = { .instance = NULL }; - struct cwmp *cwmp = &cwmp_main; - e = cwmp_ubus_call(USP_OBJECT_NAME, "del_object", CWMP_UBUS_ARGS{ { "path", { .str_val = object_name }, UBUS_String }, { "key", { .str_val = key }, UBUS_String }, { "transaction_id", { .int_val = transaction_id }, UBUS_Integer }, { "proto", { .str_val = "cwmp" }, UBUS_String }, { "instance_mode", { .int_val = cwmp->conf.instance_mode }, UBUS_Integer } }, 5, - ubus_objects_callback, &add_result); + 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"; diff --git a/diagnostic.c b/diagnostic.c index 08c355b..eba05e3 100644 --- a/diagnostic.c +++ b/diagnostic.c @@ -13,7 +13,7 @@ #include "common.h" #include "diagnostic.h" -#include "ubus.h" +#include "ubus_utils.h" #include "log.h" #include "event.h" @@ -146,14 +146,23 @@ void empty_ubus_callback(struct ubus_request *req __attribute__((unused)), int t static int cwmp_diagnostics_operate(char *diagnostics_object, char *action_name, struct diagnostic_input diagnostics_array[], int number_inputs) { int e, i; + struct blob_buf b = { 0 }; - LIST_HEAD(diagnostics_param_value_list); + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + bb_add_string(&b, "path", diagnostics_object); + bb_add_string(&b, "action", action_name); + void *tbl = blobmsg_open_table(&b, "input"); for (i = 0; i < number_inputs; i++) { if (diagnostics_array[i].value == NULL || diagnostics_array[i].value[0] == '\0') continue; - add_dm_parameter_to_list(&diagnostics_param_value_list, diagnostics_array[i].input_name, diagnostics_array[i].value, NULL, 0, false); + bb_add_string(&b, diagnostics_array[i].input_name, diagnostics_array[i].value); } - e = cwmp_ubus_call(USP_OBJECT_NAME, "operate", CWMP_UBUS_ARGS{ { "path", {.str_val = diagnostics_object }, UBUS_String }, { "action", {.str_val = action_name }, UBUS_String }, { "input", {.param_value_list = &diagnostics_param_value_list }, UBUS_Obj_Obj } }, 3, empty_ubus_callback, NULL); + blobmsg_close_table(&b, tbl); + + e = icwmp_ubus_invoke(USP_OBJECT_NAME, "operate", b.head, empty_ubus_callback, NULL); + blob_buf_free(&b); + if (e) return -1; return 0; diff --git a/docs/api/tr069.md b/docs/api/tr069.md index f26d10d..dd3f510 100644 --- a/docs/api/tr069.md +++ b/docs/api/tr069.md @@ -67,16 +67,12 @@ The value of this property **must** be equal to one of the [known values below]( | Value | | ------------------ | -| reload_end_session | | reload | -| reboot_end_session | -| action_end_session | -| exit | ### Ubus CLI Example ``` -ubus call tr069 command {"command":"reboot_end_session"} +ubus call tr069 command {"command":"reload"} ``` ### JSONRPC Example @@ -86,7 +82,7 @@ ubus call tr069 command {"command":"reboot_end_session"} "jsonrpc": "2.0", "id": 0, "method": "call", - "params": ["", "tr069", "command", { "command": "reboot_end_session" }] + "params": ["", "tr069", "command", { "command": "reload" }] } ``` diff --git a/download.c b/download.c index c670ed9..704551f 100644 --- a/download.c +++ b/download.c @@ -13,7 +13,7 @@ #include #include "download.h" -#include "ubus.h" +#include "ubus_utils.h" #include "cwmp_uci.h" #include "backupSession.h" #include "log.h" @@ -85,12 +85,17 @@ void ubus_check_image_callback(struct ubus_request *req, int type __attribute__( int cwmp_check_image() { int code = 0, e; + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + CWMP_LOG(INFO, "Check downloaded image ..."); - e = cwmp_ubus_call("rpc-sys", "upgrade_test", CWMP_UBUS_ARGS{ {} }, 0, ubus_check_image_callback, &code); + e = icwmp_ubus_invoke("rpc-sys", "upgrade_test", b.head, ubus_check_image_callback, &code); if (e != 0) { CWMP_LOG(INFO, "rpc-sys upbrade_test ubus method failed: Ubus err code: %d", e); code = 1; } + blob_buf_free(&b); return code; } @@ -132,10 +137,16 @@ void ubus_get_available_bank_callback(struct ubus_request *req, int type __attri int get_available_bank_id() { int bank_id = 0, e; - e = cwmp_ubus_call("fwbank", "dump", CWMP_UBUS_ARGS{ {} }, 0, ubus_get_available_bank_callback, &bank_id); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + + e = icwmp_ubus_invoke("fwbank", "dump", b.head, ubus_get_available_bank_callback, &bank_id); if (e != 0) { CWMP_LOG(INFO, "fwbank dump ubus method failed: Ubus err code: %d", e); } + + blob_buf_free(&b); return bank_id; } @@ -145,11 +156,18 @@ int get_available_bank_id() int cwmp_apply_firmware() { int e; + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + blobmsg_add_u8(&b, "keep", true); + CWMP_LOG(INFO, "Apply downloaded image ..."); - e = cwmp_ubus_call("rpc-sys", "upgrade_start", CWMP_UBUS_ARGS{ { "keep", { .bool_val = true }, UBUS_Bool } }, 1, NULL, NULL); + e = icwmp_ubus_invoke("rpc-sys", "upgrade_start", b.head, NULL, NULL); if (e != 0) { CWMP_LOG(INFO, "rpc-sys upgrade_start ubus method failed: Ubus err code: %d", e); } + + blob_buf_free(&b); return e; } @@ -160,7 +178,16 @@ int cwmp_apply_multiple_firmware() if (bank_id <= 0) return -1; - e = cwmp_ubus_call("fwbank", "upgrade", CWMP_UBUS_ARGS{ { "path", { .str_val = FIRMWARE_UPGRADE_IMAGE }, UBUS_String }, { "auto_activate", { .bool_val = false }, UBUS_Bool }, { "bank", { .int_val = bank_id }, UBUS_Integer } }, 3, NULL, NULL); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + bb_add_string(&b, "path", FIRMWARE_UPGRADE_IMAGE); + blobmsg_add_u8(&b, "auto_activate", false); + blobmsg_add_u32(&b, "bank", bank_id); + + e = icwmp_ubus_invoke("fwbank", "upgrade", b.head, NULL, NULL); + blob_buf_free(&b); + if (e != 0) { CWMP_LOG(INFO, "fwbank upgrade ubus method failed: Ubus err code: %d", e); return -1; diff --git a/http.c b/http.c index bc5e32c..a71f2b8 100644 --- a/http.c +++ b/http.c @@ -19,7 +19,7 @@ #include "cwmp_uci.h" #include "log.h" #include "event.h" -#include "ubus.h" +#include "ubus_utils.h" #include "config.h" #include "digestauth.h" @@ -236,7 +236,12 @@ int http_send_message(struct cwmp *cwmp, char *msg_out, int msg_out_len, char ** cwmp_commit_package("cwmp", UCI_VARSTATE_CONFIG); // Trigger firewall to reload firewall.cwmp - cwmp_ubus_call("uci", "commit", CWMP_UBUS_ARGS{ { "config", { .str_val = "firewall" }, UBUS_String } }, 1, NULL, NULL); + struct blob_buf b = { 0 }; + memset(&b, 0, sizeof(struct blob_buf)); + blob_buf_init(&b, 0); + bb_add_string(&b, "config", "firewall"); + icwmp_ubus_invoke("uci", "commit", b.head, NULL, NULL); + blob_buf_free(&b); } } diff --git a/inc/common.h b/inc/common.h index a47b9aa..d82309b 100644 --- a/inc/common.h +++ b/inc/common.h @@ -63,8 +63,6 @@ extern char *commandKey; extern bool thread_end; -extern bool signal_exit; -extern bool ubus_exit; typedef struct env { unsigned short boot; diff --git a/inc/ubus.h b/inc/ubus.h deleted file mode 100644 index 67d5aa6..0000000 --- a/inc/ubus.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * 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-2020 iopsys Software Solutions AB - * Author Omar Kallel - * - * Copyright (C) 2012 Luka Perkov - */ - -#ifndef _FREECWMP_UBUS_H__ -#define _FREECWMP_UBUS_H__ - -#include - -#include "common.h" - -#define ARRAY_MAX 8 - -int cwmp_ubus_init(struct cwmp *cwmp); -void cwmp_ubus_exit(void); - -enum cwmp_ubus_arg_type -{ - UBUS_String, - UBUS_Integer, - UBUS_Array_Obj, - UBUS_Array_Str, - UBUS_Obj_Obj, - UBUS_List_Param_Set, - UBUS_List_Param_Get, - UBUS_Bool, -}; - -struct key_value { - char *key; - char *value; -}; - -union array_membre { - char *str_value; - struct key_value param_value; -}; - -union ubus_value { - char *str_val; - int int_val; - bool bool_val; - union array_membre array_value[ARRAY_MAX]; - struct list_head *param_value_list; -}; - -struct cwmp_ubus_arg { - const char *key; - const union ubus_value val; - enum cwmp_ubus_arg_type type; -}; - -#define CWMP_UBUS_ARGS (struct cwmp_ubus_arg[]) -int cwmp_ubus_call(const char *obj, const char *method, const struct cwmp_ubus_arg u_args[], int u_args_size, void (*ubus_callback)(struct ubus_request *req, int type, struct blob_attr *msg), void *callback_arg); - -#endif /* UBUS_H_ */ diff --git a/inc/ubus_utils.h b/inc/ubus_utils.h new file mode 100644 index 0000000..eca1940 --- /dev/null +++ b/inc/ubus_utils.h @@ -0,0 +1,15 @@ +#ifndef __ICWMP_UBUS_UTILS_H__ +#define __ICWMP_UBUS_UTILS_H__ + +#include +#include "common.h" + +typedef void (*icwmp_ubus_cb)(struct ubus_request *req, int type, struct blob_attr *msg); + +void bb_add_string(struct blob_buf *bb, const char *name, const char *value); +int icwmp_register_object(struct ubus_context *ctx); +int icwmp_delete_object(struct ubus_context *ctx); +int icwmp_ubus_invoke(const char *obj, const char *method, struct blob_attr *msg, + icwmp_ubus_cb icwmp_callback, void *callback_arg); + +#endif /* __ICWMP_UBUS_UTILS_H__ */ diff --git a/schemas/ubus/tr069.json b/schemas/ubus/tr069.json index 3e7660b..ff07a05 100644 --- a/schemas/ubus/tr069.json +++ b/schemas/ubus/tr069.json @@ -4,11 +4,7 @@ "type": "string", "description": "CWMP supported commands", "enum": [ - "reload_end_session", - "reload", - "reboot_end_session", - "action_end_session", - "exit" + "reload" ] }, "event_t": { @@ -155,19 +151,48 @@ } }, "output": { - "type": "object", - "properties": { - "status": { - "type": "integer" + "oneof": [ + { + "type": "object", + "properties": { + "SupportedCommands": { + "type": "array", + "items": [ + { + "type": "object", + "required": [ + "command", + "description" + ], + "properties": { + "command": { + "type": "string" + }, + "description": { + "type": "string" + } + } + } + ] + } + } }, - "info": { - "type": "string" + { + "type": "object", + "properties": { + "status": { + "type": "integer" + }, + "info": { + "type": "string" + } + }, + "required": [ + "status" + ] } - }, - "required": [ - "status" ] - } + } } }, "inform": { diff --git a/test/api/json/tr069.validation.json b/test/api/json/tr069.validation.json index c1139b3..f1eb09f 100644 --- a/test/api/json/tr069.validation.json +++ b/test/api/json/tr069.validation.json @@ -13,7 +13,7 @@ "method": "command", "args": { }, - "rc": 2 + "rc": 0 }, { "method": "status", @@ -172,28 +172,6 @@ "method": "status", "rc": 0 }, - { - "method": "command", - "args": { - "command": "reload_end_session" - }, - "rc": 0 - }, - { - "method": "status", - "rc": 0 - }, - { - "method": "command", - "args": { - "command": "action_end_session" - }, - "rc": 0 - }, - { - "method": "status", - "rc": 0 - }, { "method": "command", "args": { diff --git a/ubus.c b/ubus.c deleted file mode 100755 index f851d5c..0000000 --- a/ubus.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * 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 Mohamed Kallel - * Author Ahmed Zribi - * Author Omar Kallel - * Copyright (C) 2012 Luka Perkov - */ - -#include -#include -#include -#include - -#include "ubus.h" -#include "session.h" -#include "log.h" -#include "sched_inform.h" -#include "http.h" -#include "download.h" -#include "upload.h" -#include "cwmp_du_state.h" -#include "netlink.h" -#include "event.h" - -static struct ubus_context *ctx = NULL; - -static const char *arr_session_status[] = { - [SESSION_WAITING] = "waiting", - [SESSION_RUNNING] = "running", - [SESSION_FAILURE] = "failure", - [SESSION_SUCCESS] = "success", -}; - -enum command -{ - COMMAND_NAME, - __COMMAND_MAX -}; - -static const struct blobmsg_policy command_policy[] = { - [COMMAND_NAME] = {.name = "command", .type = BLOBMSG_TYPE_STRING }, -}; - -static int cwmp_handle_command(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[__COMMAND_MAX]; - struct blob_buf blob_command; - - blobmsg_parse(command_policy, ARRAY_SIZE(command_policy), tb, blob_data(msg), blob_len(msg)); - - if (!tb[COMMAND_NAME]) - return UBUS_STATUS_INVALID_ARGUMENT; - - memset(&blob_command, 0, sizeof(struct blob_buf)); - blob_buf_init(&blob_command, 0); - - char *cmd = blobmsg_data(tb[COMMAND_NAME]); - char info[128] = {0}; - - if (!strcmp("reload_end_session", cmd)) { - CWMP_LOG(INFO, "triggered ubus reload_end_session"); - cwmp_set_end_session(END_SESSION_RELOAD); - blobmsg_add_u32(&blob_command, "status", 0); - if (snprintf(info, sizeof(info), "icwmpd config will reload at the end of the session") == -1) - return -1; - } else if (!strcmp("reload", cmd)) { - CWMP_LOG(INFO, "triggered ubus reload"); - if (cwmp_main.session_status.last_status == SESSION_RUNNING) { - cwmp_set_end_session(END_SESSION_RELOAD); - blobmsg_add_u32(&blob_command, "status", 0); - if (snprintf(info, sizeof(info), "Session running, reload at the end of the session") == -1) - return -1; - } else { - pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); - cwmp_apply_acs_changes(); - pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); - blobmsg_add_u32(&blob_command, "status", 0); - if (snprintf(info, sizeof(info), "icwmpd config reloaded") == -1) - return -1; - } - } else if (!strcmp("reboot_end_session", cmd)) { - CWMP_LOG(INFO, "triggered ubus reboot_end_session"); - cwmp_set_end_session(END_SESSION_REBOOT); - blobmsg_add_u32(&blob_command, "status", 0); - if (snprintf(info, sizeof(info), "icwmpd will reboot at the end of the session") == -1) - return -1; - } else if (!strcmp("action_end_session", cmd)) { - CWMP_LOG(INFO, "triggered ubus action_end_session"); - cwmp_set_end_session(END_SESSION_EXTERNAL_ACTION); - blobmsg_add_u32(&blob_command, "status", 0); - if (snprintf(info, sizeof(info), "icwmpd will execute the scheduled action commands at the end of the session") == -1) - return -1; - } else if (!strcmp("exit", cmd)) { - ubus_exit = true; - thread_end = true; - - if (cwmp_main.session_status.last_status == SESSION_RUNNING) - http_set_timeout(); - - pthread_cond_signal(&(cwmp_main.threshold_session_send)); - pthread_cond_signal(&(cwmp_main.threshold_periodic)); - pthread_cond_signal(&(cwmp_main.threshold_notify_periodic)); - pthread_cond_signal(&threshold_schedule_inform); - pthread_cond_signal(&threshold_download); - pthread_cond_signal(&threshold_change_du_state); - pthread_cond_signal(&threshold_schedule_download); - pthread_cond_signal(&threshold_apply_schedule_download); - pthread_cond_signal(&threshold_upload); - - uloop_end(); - - shutdown(cwmp_main.cr_socket_desc, SHUT_RDWR); - - if (!signal_exit) - kill(getpid(), SIGTERM); - - if (snprintf(info, sizeof(info), "icwmpd daemon stopped") == -1) - return -1; - } else { - blobmsg_add_u32(&blob_command, "status", -1); - if (snprintf(info, sizeof(info), "%s command is not supported", cmd) == -1) - return -1; - } - - blobmsg_add_string(&blob_command, "info", info); - ubus_send_reply(ctx, req, blob_command.head); - blob_buf_free(&blob_command); - - return 0; -} - -static inline time_t get_session_status_next_time() -{ - time_t ntime = 0; - if (list_schedule_inform.next != &(list_schedule_inform)) { - struct schedule_inform *schedule_inform; - schedule_inform = list_entry(list_schedule_inform.next, struct schedule_inform, list); - ntime = schedule_inform->scheduled_time; - } - if (!ntime || (cwmp_main.session_status.next_retry && ntime > cwmp_main.session_status.next_retry)) { - ntime = cwmp_main.session_status.next_retry; - } - if (!ntime || (cwmp_main.session_status.next_periodic && ntime > cwmp_main.session_status.next_periodic)) { - ntime = cwmp_main.session_status.next_periodic; - } - return ntime; -} - -static int cwmp_handle_status(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), struct ubus_request_data *req, const char *method __attribute__((unused)), struct blob_attr *msg __attribute__((unused))) -{ - void *c; - time_t ntime = 0; - struct blob_buf blob_status; - - memset(&blob_status, 0, sizeof(struct blob_buf)); - blob_buf_init(&blob_status, 0); - - c = blobmsg_open_table(&blob_status, "cwmp"); - blobmsg_add_string(&blob_status, "status", "up"); - blobmsg_add_string(&blob_status, "start_time", get_time(cwmp_main.start_time)); - blobmsg_add_string(&blob_status, "acs_url", cwmp_main.conf.acsurl); - blobmsg_close_table(&blob_status, c); - - c = blobmsg_open_table(&blob_status, "last_session"); - blobmsg_add_string(&blob_status, "status", cwmp_main.session_status.last_start_time ? arr_session_status[cwmp_main.session_status.last_status] : "N/A"); - blobmsg_add_string(&blob_status, "start_time", cwmp_main.session_status.last_start_time ? get_time(cwmp_main.session_status.last_start_time) : "N/A"); - blobmsg_add_string(&blob_status, "end_time", cwmp_main.session_status.last_end_time ? get_time(cwmp_main.session_status.last_end_time) : "N/A"); - blobmsg_close_table(&blob_status, c); - - c = blobmsg_open_table(&blob_status, "next_session"); - blobmsg_add_string(&blob_status, "status", arr_session_status[SESSION_WAITING]); - ntime = get_session_status_next_time(); - blobmsg_add_string(&blob_status, "start_time", ntime ? get_time(ntime) : "N/A"); - blobmsg_add_string(&blob_status, "end_time", "N/A"); - blobmsg_close_table(&blob_status, c); - - c = blobmsg_open_table(&blob_status, "statistics"); - blobmsg_add_u32(&blob_status, "success_sessions", cwmp_main.session_status.success_session); - blobmsg_add_u32(&blob_status, "failure_sessions", cwmp_main.session_status.failure_session); - blobmsg_add_u32(&blob_status, "total_sessions", cwmp_main.session_status.success_session + cwmp_main.session_status.failure_session); - blobmsg_close_table(&blob_status, c); - - ubus_send_reply(ctx, req, blob_status.head); - blob_buf_free(&blob_status); - - return 0; -} - -enum enum_inform -{ - INFORM_GET_RPC_METHODS, - INFORM_EVENT, - __INFORM_MAX -}; - -static const struct blobmsg_policy inform_policy[] = { - [INFORM_GET_RPC_METHODS] = {.name = "GetRPCMethods", .type = BLOBMSG_TYPE_BOOL }, - [INFORM_EVENT] = {.name = "event", .type = BLOBMSG_TYPE_STRING }, -}; - -static int cwmp_handle_inform(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[__INFORM_MAX]; - bool grm = false; - char *event = ""; - struct blob_buf blob_inform; - - memset(&blob_inform, 0, sizeof(struct blob_buf)); - blob_buf_init(&blob_inform, 0); - - blobmsg_parse(inform_policy, ARRAY_SIZE(inform_policy), tb, blob_data(msg), blob_len(msg)); - - if (tb[INFORM_GET_RPC_METHODS]) { - grm = blobmsg_data(tb[INFORM_GET_RPC_METHODS]); - } - if (tb[INFORM_EVENT]) { - event = blobmsg_data(tb[INFORM_EVENT]); - } - if (grm) { - struct event_container *event_container; - struct session *session; - - pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); - event_container = cwmp_add_event_container(&cwmp_main, EVENT_IDX_2PERIODIC, ""); - if (event_container == NULL) { - pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); - return 0; - } - cwmp_save_event_container(event_container); - session = list_entry(cwmp_main.head_event_container, struct session, head_event_container); - if (cwmp_add_session_rpc_acs(session, RPC_ACS_GET_RPC_METHODS) == NULL) { - pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); - return 0; - } - pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); - pthread_cond_signal(&(cwmp_main.threshold_session_send)); - blobmsg_add_u32(&blob_inform, "status", 1); - blobmsg_add_string(&blob_inform, "info", "Session with GetRPCMethods will start"); - } else { - int event_code = cwmp_get_int_event_code(event); - pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); - cwmp_add_event_container(&cwmp_main, event_code, ""); - pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); - pthread_cond_signal(&(cwmp_main.threshold_session_send)); - if (cwmp_main.session_status.last_status == SESSION_RUNNING) { - blobmsg_add_u32(&blob_inform, "status", -1); - blobmsg_add_string(&blob_inform, "info", "Session already running, event will be sent at the end of the session"); - } else { - blobmsg_add_u32(&blob_inform, "status", 1); - blobmsg_add_string(&blob_inform, "info", "Session started"); - } - } - ubus_send_reply(ctx, req, blob_inform.head); - blob_buf_free(&blob_inform); - - return 0; -} - -static const struct ubus_method freecwmp_methods[] = { - UBUS_METHOD("command", cwmp_handle_command, command_policy), - UBUS_METHOD_NOARG("status", cwmp_handle_status), - UBUS_METHOD("inform", cwmp_handle_inform, inform_policy), -}; - -static struct ubus_object_type main_object_type = UBUS_OBJECT_TYPE("freecwmpd", freecwmp_methods); - -static struct ubus_object main_object = { - .name = "tr069", - .type = &main_object_type, - .methods = freecwmp_methods, - .n_methods = ARRAY_SIZE(freecwmp_methods), -}; - -int cwmp_ubus_init(struct cwmp *cwmp) -{ - uloop_init(); - - if (netlink_init()) { - CWMP_LOG(ERROR, "netlink initialization failed"); - } - - if (cwmp->conf.ipv6_enable) { - if (netlink_init_v6()) { - CWMP_LOG(ERROR, "netlink initialization failed"); - } - } - ctx = ubus_connect(cwmp->conf.ubus_socket); - if (!ctx) - return -1; - - ubus_add_uloop(ctx); - - if (ubus_add_object(ctx, &main_object)) - return -1; - - uloop_run(); - uloop_done(); - return 0; -} - -void cwmp_ubus_exit(void) -{ - if (ctx) { - ubus_remove_object(ctx, &main_object); - ubus_free(ctx); - } -} - -int cwmp_ubus_call(const char *obj, const char *method, const struct cwmp_ubus_arg u_args[], int u_args_size, void (*ubus_callback)(struct ubus_request *req, int type, struct blob_attr *msg), void *callback_arg) -{ - uint32_t id; - int i = 0; - int rc = 0; - struct blob_buf b = { 0 }; - - struct ubus_context *ubus_ctx = NULL; - - ubus_ctx = ubus_connect(NULL); - if (ubus_ctx == NULL) - return -1; - - memset(&b, 0, sizeof(struct blob_buf)); - blob_buf_init(&b, 0); - for (i = 0; i < u_args_size; i++) { - if (u_args[i].type == UBUS_String) - blobmsg_add_string(&b, u_args[i].key, u_args[i].val.str_val); - else if (u_args[i].type == UBUS_Integer) { - blobmsg_add_u32(&b, u_args[i].key, u_args[i].val.int_val); - } else if (u_args[i].type == UBUS_Array_Obj || u_args[i].type == UBUS_Array_Str) { - void *a; - int j; - a = blobmsg_open_array(&b, u_args[i].key); - if (u_args[i].type == UBUS_Array_Obj) { - void *t; - t = blobmsg_open_table(&b, ""); - for (j = 0; j < ARRAY_MAX; j++) { - if (u_args[i].val.array_value[j].param_value.key == NULL || strlen(u_args[i].val.array_value[j].param_value.key) == 0) - break; - blobmsg_add_string(&b, u_args[i].val.array_value[j].param_value.key, u_args[i].val.array_value[j].param_value.value); - } - blobmsg_close_table(&b, t); - } - if (u_args[i].type == UBUS_Array_Str) { - for (j = 0; j < ARRAY_MAX; j++) { - if (u_args[i].val.array_value[j].str_value == NULL || strlen(u_args[i].val.array_value[j].str_value) == 0) - break; - blobmsg_add_string(&b, NULL, u_args[i].val.array_value[j].str_value); - } - } - blobmsg_close_array(&b, a); - } else if (u_args[i].type == UBUS_List_Param_Set) { - struct cwmp_dm_parameter *param_value; - void *a; - a = blobmsg_open_array(&b, u_args[i].key); - list_for_each_entry (param_value, u_args[i].val.param_value_list, list) { - void *t; - if (!param_value->name) - break; - t = blobmsg_open_table(&b, ""); - blobmsg_add_string(&b, "path", param_value->name); - blobmsg_add_string(&b, "value", param_value->value); - blobmsg_close_table(&b, t); - } - blobmsg_close_array(&b, a); - } else if (u_args[i].type == UBUS_List_Param_Get) { - struct cwmp_dm_parameter *param_value; - void *a; - a = blobmsg_open_array(&b, u_args[i].key); - list_for_each_entry (param_value, u_args[i].val.param_value_list, list) { - if (!param_value->name) - break; - blobmsg_add_string(&b, NULL, param_value->name); - } - blobmsg_close_array(&b, a); - } else if (u_args[i].type == UBUS_Obj_Obj) { - struct cwmp_dm_parameter *param_value; - json_object *input_json_obj = json_object_new_object(); - list_for_each_entry (param_value, u_args[i].val.param_value_list, list) { - if (!param_value->name) - break; - json_object_object_add(input_json_obj, param_value->name, json_object_new_string(param_value->value)); - } - blobmsg_add_json_element(&b, u_args[i].key, input_json_obj); - } else if (u_args[i].type == UBUS_Bool) - blobmsg_add_u8(&b, u_args[i].key, u_args[i].val.bool_val); - } - if (!ubus_lookup_id(ubus_ctx, obj, &id)) - rc = ubus_invoke(ubus_ctx, id, method, b.head, ubus_callback, callback_arg, 20000); - else - rc = -1; - blob_buf_free(&b); - if (ubus_ctx) { - ubus_free(ubus_ctx); - ubus_ctx = NULL; - } - return rc; -} diff --git a/ubus_utils.c b/ubus_utils.c new file mode 100644 index 0000000..6b25727 --- /dev/null +++ b/ubus_utils.c @@ -0,0 +1,383 @@ +/* + * ubus_utils.c - ubus methods and utility functions + * + * Copyright (C) 2022, IOPSYS Software Solutions AB. + * + * Author: suvendhu.hansa@iopsys.eu + * + * See LICENSE file for license related information + * + */ + +#include "ubus_utils.h" +#include "log.h" +#include "sched_inform.h" +#include "event.h" + +typedef int (*callback)(struct blob_buf *b); + +struct command_cb { + char *str; + callback cb; + char *help; +}; + +static const char *arr_session_status[] = { + [SESSION_WAITING] = "waiting", + [SESSION_RUNNING] = "running", + [SESSION_FAILURE] = "failure", + [SESSION_SUCCESS] = "success", +}; + +static int reload_cmd(struct blob_buf *b) +{ + CWMP_LOG(INFO, "triggered ubus reload"); + if (cwmp_main.session_status.last_status == SESSION_RUNNING) { + cwmp_set_end_session(END_SESSION_RELOAD); + blobmsg_add_u32(b, "status", 0); + blobmsg_add_string(b, "info", "Session running, reload at the end of the session"); + } else { + pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); + cwmp_apply_acs_changes(); + pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); + blobmsg_add_u32(b, "status", 0); + blobmsg_add_string(b, "info", "icwmpd config reloaded"); + } + + return 0; +} + +static struct command_cb cmd_cb[] ={ + { "reload", reload_cmd, "Reload icwmpd with new configuration" } +}; + +static int call_command_cb(char *cmd, struct blob_buf *b) +{ + int cmd_num, i; + callback cb = NULL; + + if (cmd == NULL || b == NULL) + return -1; + + cmd_num = sizeof(cmd_cb)/sizeof(struct command_cb); + for (i = 0; i < cmd_num; i++) { + if (strcmp(cmd, cmd_cb[i].str) == 0) { + cb = cmd_cb[i].cb; + break; + } + } + + if (cb == NULL) { + char info[128] = {0}; + if (snprintf(info, sizeof(info), "\'%s\' is not supported. Check the supported commands.", cmd) == -1) + return -1; + + blobmsg_add_u32(b, "status", -1); + blobmsg_add_string(b, "info", info); + return 0; + } + + return cb(b); +} + +enum command +{ + COMMAND_NAME, + __COMMAND_MAX +}; + +static const struct blobmsg_policy icwmp_cmd_policy[] = { + [COMMAND_NAME] = {.name = "command", .type = BLOBMSG_TYPE_STRING }, +}; + +static int icwmp_command_handler(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[__COMMAND_MAX]; + struct blob_buf blob_command; + + memset(&blob_command, 0, sizeof(struct blob_buf)); + blob_buf_init(&blob_command, 0); + + blobmsg_parse(icwmp_cmd_policy, ARRAY_SIZE(icwmp_cmd_policy), tb, blob_data(msg), blob_len(msg)); + + if (!tb[COMMAND_NAME]) { + int i; + int cmd_num = sizeof(cmd_cb)/sizeof(struct command_cb); + void *arr = blobmsg_open_array(&blob_command, "SupportedCommands"); + for (i = 0; i < cmd_num; i++) { + void *tbl_in = blobmsg_open_table(&blob_command, ""); + bb_add_string(&blob_command, "command", cmd_cb[i].str); + bb_add_string(&blob_command, "description", cmd_cb[i].help); + blobmsg_close_table(&blob_command, tbl_in); + } + blobmsg_close_array(&blob_command, arr); + goto send_reply; + } + + char *cmd = blobmsg_data(tb[COMMAND_NAME]); + + if (call_command_cb(cmd, &blob_command) != 0) { + blob_buf_free(&blob_command); + return -1; + } + +send_reply: + ubus_send_reply(ctx, req, blob_command.head); + blob_buf_free(&blob_command); + + return 0; +} + +static time_t get_nonzero_min_time(time_t time1, time_t time2, time_t time3) +{ + time_t arr[] = { time1, time2, time3 }; + time_t min = 0; + int i; + int size = sizeof(arr)/sizeof(time_t); + + for (i = 0; i < size && arr[i] == 0; i++); // find the first non zero element + + if (i == size) { + return min; // array has no non-zero values + } + + min = arr[i]; + for (; i < size; i++) { + if (arr[i] != 0 && arr[i] < min) + min = arr[i]; + } + + return min; +} + +static time_t get_next_session_time() +{ + time_t sched_time = 0; + if (list_schedule_inform.next != &(list_schedule_inform)) { + struct schedule_inform *schedule_inform; + schedule_inform = list_entry(list_schedule_inform.next, struct schedule_inform, list); + sched_time = schedule_inform->scheduled_time; + } + + time_t next_time = get_nonzero_min_time(sched_time, cwmp_main.session_status.next_retry, cwmp_main.session_status.next_periodic); + + return next_time; +} + +static void bb_add_icwmp_status(struct blob_buf *bb) +{ + void *tbl = blobmsg_open_table(bb, "cwmp"); + bb_add_string(bb, "status", "up"); + bb_add_string(bb, "start_time", get_time(cwmp_main.start_time)); + bb_add_string(bb, "acs_url", cwmp_main.conf.acsurl); + blobmsg_close_table(bb, tbl); +} + +static void bb_add_icwmp_last_session(struct blob_buf *bb) +{ + void *tbl = blobmsg_open_table(bb, "last_session"); + const char *status = cwmp_main.session_status.last_start_time ? arr_session_status[cwmp_main.session_status.last_status] : "N/A"; + bb_add_string(bb, "status", status); + char *start_time = cwmp_main.session_status.last_start_time ? get_time(cwmp_main.session_status.last_start_time) : "N/A"; + bb_add_string(bb, "start_time", start_time); + char *end_time = cwmp_main.session_status.last_end_time ? get_time(cwmp_main.session_status.last_end_time) : "N/A"; + bb_add_string(bb, "end_time", end_time); + blobmsg_close_table(bb, tbl); +} + +static void bb_add_icwmp_next_session(struct blob_buf *bb) +{ + void *tbl = blobmsg_open_table(bb, "next_session"); + bb_add_string(bb, "status", arr_session_status[SESSION_WAITING]); + time_t ntime = get_next_session_time(); + char *start_time = ntime ? get_time(ntime) : "N/A"; + bb_add_string(bb, "start_time", start_time); + bb_add_string(bb, "end_time", "N/A"); + blobmsg_close_table(bb, tbl); +} + +static void bb_add_icwmp_statistics(struct blob_buf *bb) +{ + void *tbl = blobmsg_open_table(bb, "statistics"); + blobmsg_add_u32(bb, "success_sessions", cwmp_main.session_status.success_session); + blobmsg_add_u32(bb, "failure_sessions", cwmp_main.session_status.failure_session); + blobmsg_add_u32(bb, "total_sessions", cwmp_main.session_status.success_session + cwmp_main.session_status.failure_session); + blobmsg_close_table(bb, tbl); + +} + +static int icwmp_status_handler(struct ubus_context *ctx, struct ubus_object *obj __attribute__((unused)), struct ubus_request_data *req, const char *method __attribute__((unused)), struct blob_attr *msg __attribute__((unused))) +{ + struct blob_buf bb; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + bb_add_icwmp_status(&bb); + bb_add_icwmp_last_session(&bb); + bb_add_icwmp_next_session(&bb); + bb_add_icwmp_statistics(&bb); + + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); + + return 0; +} + +enum enum_inform +{ + INFORM_GET_RPC_METHODS, + INFORM_EVENT, + __INFORM_MAX +}; + +static const struct blobmsg_policy icwmp_inform_policy[] = { + [INFORM_GET_RPC_METHODS] = {.name = "GetRPCMethods", .type = BLOBMSG_TYPE_BOOL }, + [INFORM_EVENT] = {.name = "event", .type = BLOBMSG_TYPE_STRING }, +}; + +static void icwmp_inform_get_rpc_method(struct ubus_context *ctx, struct ubus_request_data *req) +{ + struct event_container *event_container; + struct session *session; + struct blob_buf bb; + + if (ctx == NULL) + return; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); + event_container = cwmp_add_event_container(&cwmp_main, EVENT_IDX_2PERIODIC, ""); + if (event_container == NULL) { + pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); + return; + } + + cwmp_save_event_container(event_container); + session = list_entry(cwmp_main.head_event_container, struct session, head_event_container); + if (cwmp_add_session_rpc_acs(session, RPC_ACS_GET_RPC_METHODS) == NULL) { + pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); + return; + } + + pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); + pthread_cond_signal(&(cwmp_main.threshold_session_send)); + blobmsg_add_u32(&bb, "status", 1); + blobmsg_add_string(&bb, "info", "Session with GetRPCMethods will start"); + + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); +} + +static void icwmp_inform_event(struct ubus_context *ctx, struct ubus_request_data *req, char *event) +{ + struct blob_buf bb; + + if (ctx == NULL || event == NULL) + return; + + memset(&bb, 0, sizeof(struct blob_buf)); + blob_buf_init(&bb, 0); + + int event_code = cwmp_get_int_event_code(event); + pthread_mutex_lock(&(cwmp_main.mutex_session_queue)); + cwmp_add_event_container(&cwmp_main, event_code, ""); + pthread_mutex_unlock(&(cwmp_main.mutex_session_queue)); + pthread_cond_signal(&(cwmp_main.threshold_session_send)); + if (cwmp_main.session_status.last_status == SESSION_RUNNING) { + blobmsg_add_u32(&bb, "status", -1); + blobmsg_add_string(&bb, "info", "Session already running, event will be sent at the end of the session"); + } else { + blobmsg_add_u32(&bb, "status", 1); + blobmsg_add_string(&bb, "info", "Session started"); + } + + ubus_send_reply(ctx, req, bb.head); + blob_buf_free(&bb); +} + +static int icwmp_inform_handler(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[__INFORM_MAX]; + bool is_get_rpc = false; + char *event = ""; + + blobmsg_parse(icwmp_inform_policy, ARRAY_SIZE(icwmp_inform_policy), tb, blob_data(msg), blob_len(msg)); + + if (tb[INFORM_GET_RPC_METHODS]) { + is_get_rpc = blobmsg_data(tb[INFORM_GET_RPC_METHODS]); + } + if (tb[INFORM_EVENT]) { + event = blobmsg_data(tb[INFORM_EVENT]); + } + + if (is_get_rpc) { + icwmp_inform_get_rpc_method(ctx, req); + } else { + icwmp_inform_event(ctx, req, event); + } + + return 0; +} + +static const struct ubus_method icwmp_methods[] = { + UBUS_METHOD("command", icwmp_command_handler, icwmp_cmd_policy), + UBUS_METHOD_NOARG("status", icwmp_status_handler), + UBUS_METHOD("inform", icwmp_inform_handler, icwmp_inform_policy), +}; + +static struct ubus_object_type tr069_object_type = UBUS_OBJECT_TYPE("icwmpd", icwmp_methods); + +static struct ubus_object tr069_object = { + .name = "tr069", + .type = &tr069_object_type, + .methods = icwmp_methods, + .n_methods = ARRAY_SIZE(icwmp_methods), +}; + +int icwmp_register_object(struct ubus_context *ctx) +{ + return ubus_add_object(ctx, &tr069_object); +} + +int icwmp_delete_object(struct ubus_context *ctx) +{ + return ubus_remove_object(ctx, &tr069_object); +} + +void bb_add_string(struct blob_buf *bb, const char *name, const char *value) +{ + if (bb == NULL) + return; + + if (value) + blobmsg_add_string(bb, name, value); + else + blobmsg_add_string(bb, name, ""); +} + +int icwmp_ubus_invoke(const char *obj, const char *method, struct blob_attr *msg, icwmp_ubus_cb icwmp_callback, void *callback_arg) +{ + uint32_t id; + int rc = 0; + + struct ubus_context *ubus_ctx = NULL; + + ubus_ctx = ubus_connect(NULL); + if (ubus_ctx == NULL) + return -1; + + if (!ubus_lookup_id(ubus_ctx, obj, &id)) + rc = ubus_invoke(ubus_ctx, id, method, msg, icwmp_callback, callback_arg, 20000); + else + rc = -1; + + if (ubus_ctx) { + ubus_free(ubus_ctx); + ubus_ctx = NULL; + } + + return rc; +}