From 62566e4e8117970c2363f8f3e18302fb8b667b22 Mon Sep 17 00:00:00 2001 From: suvendhu Date: Tue, 7 Nov 2023 18:43:19 +0530 Subject: [PATCH] Fix custom force inform parameters --- docs/guide/notification.md | 26 ++++++- src/common.h | 7 ++ src/config.c | 5 ++ src/cwmp.c | 10 +++ src/rpc.c | 104 +++++++++++++++++++++++-- src/rpc.h | 3 + test/cmocka/icwmp_soap_msg_unit_test.c | 7 ++ 7 files changed, 154 insertions(+), 8 deletions(-) diff --git a/docs/guide/notification.md b/docs/guide/notification.md index b3deab7..7d1d2d6 100644 --- a/docs/guide/notification.md +++ b/docs/guide/notification.md @@ -35,9 +35,31 @@ config inform_parameter ``` +Apart from the above, user can configure a parameter as forced inform parameter by using a JSON file. Users can include this json file in their firmware to add custom forced inform parameters (other than standard force inform parameters specified in datamodel). +Then user just need to set the file path in 'forced_inform_json' option under 'cpe' section of the cwmp UCI file. + +Below is the schema/format of the JSON file: + +```bash +root@iopsys:~# cat /etc/icwmpd/force_inform.json +{ + "forced_inform": [ + "Device.DeviceInfo.UpTime", + "Device.WiFi.SSID.1.SSID" + ] +} +root@iopsys:~# +root@iopsys:~# uci -q get cwmp.cpe.forced_inform_json +/etc/icwmpd/force_inform.json +root@iopsys:~# + +``` + +Forced inform parameters defined in JSON should be leaf elements. + > Note: -> 1. To configure a parameter as forced inform parameter, set the events_list to an empty string, or to include the parameter for specific event, set the event_list accordingly. -> 2. Factory default inform_parameters can be added from standard cwmp uci file +> 1. Factory default inform_parameters can be added from standard cwmp uci file. +> 2. To configure a parameter for specific event set the event_list accordingly. ## Notification management `icwmpd` support below notification types, which can be configured from an ACS on the datamodel parameters diff --git a/src/common.h b/src/common.h index 1da63d6..a5fbb16 100644 --- a/src/common.h +++ b/src/common.h @@ -91,6 +91,7 @@ extern struct uloop_timeout periodic_session_timer; extern struct uloop_timeout retry_session_timer; extern bool g_firewall_restart; extern struct list_head intf_reset_list; +extern struct list_head force_inform_list; typedef struct env { unsigned short boot; @@ -111,6 +112,7 @@ typedef struct config { char cpe_userid[BUF_SIZE_256]; char cpe_passwd[BUF_SIZE_256]; char custom_notify_json[BUF_SIZE_256]; + char forced_inform_json[BUF_SIZE_256]; char connection_request_path[BUF_SIZE_256]; char auto_tc_transfer_type[BUF_SIZE_16]; char auto_tc_result_type[BUF_SIZE_16]; @@ -594,6 +596,11 @@ typedef struct bin_list { struct list_head list; } bin_list_t; +typedef struct force_inform_node { + char path[1024]; + struct list_head list; +} force_inform_node; + extern struct cwmp *cwmp_main; extern long int flashsize; extern struct FAULT_CPE FAULT_CPE_ARRAY[]; diff --git a/src/config.c b/src/config.c index 476a8f6..8ec3ec6 100755 --- a/src/config.c +++ b/src/config.c @@ -66,6 +66,7 @@ static void config_get_cpe_elements(struct uci_section *s) UCI_CPE_SESSION_TIMEOUT, UCI_CPE_INSTANCE_MODE, UCI_CPE_JSON_CUSTOM_NOTIFY_FILE, + UCI_CPE_JSON_FORCED_INFORM_FILE, UCI_CPE_FORCE_IPV4, __MAX_NUM_UCI_CPE_ATTRS, }; @@ -84,6 +85,7 @@ static void config_get_cpe_elements(struct uci_section *s) [UCI_CPE_SESSION_TIMEOUT] = { .name = "session_timeout", .type = UCI_TYPE_STRING }, [UCI_CPE_INSTANCE_MODE] = { .name = "instance_mode", .type = UCI_TYPE_STRING }, [UCI_CPE_JSON_CUSTOM_NOTIFY_FILE] = { .name = "custom_notify_json", .type = UCI_TYPE_STRING }, + [UCI_CPE_JSON_FORCED_INFORM_FILE] = { .name = "forced_inform_json", .type = UCI_TYPE_STRING }, [UCI_CPE_CON_REQ_TIMEOUT] = { .name = "cr_timeout", .type = UCI_TYPE_STRING }, [UCI_CPE_FORCE_IPV4] = { .name = "force_ipv4", .type = UCI_TYPE_STRING } }; @@ -179,6 +181,9 @@ static void config_get_cpe_elements(struct uci_section *s) snprintf(cwmp_main->conf.custom_notify_json, sizeof(cwmp_main->conf.custom_notify_json), "%s", get_value_from_uci_option(cpe_tb[UCI_CPE_JSON_CUSTOM_NOTIFY_FILE])); CWMP_LOG(DEBUG, "CWMP CONFIG - cpe custom notify json path: %s", cwmp_main->conf.custom_notify_json); + snprintf(cwmp_main->conf.forced_inform_json, sizeof(cwmp_main->conf.forced_inform_json), "%s", get_value_from_uci_option(cpe_tb[UCI_CPE_JSON_FORCED_INFORM_FILE])); + CWMP_LOG(DEBUG, "CWMP CONFIG - cpe forced inform json path: %s", cwmp_main->conf.forced_inform_json); + cwmp_main->conf.force_ipv4 = uci_str_to_bool(get_value_from_uci_option(cpe_tb[UCI_CPE_FORCE_IPV4])); CWMP_LOG(DEBUG, "CWMP CONFIG - cpe force ipv4 enable: %d", cwmp_main->conf.force_ipv4); diff --git a/src/cwmp.c b/src/cwmp.c index 72cf51c..af9ee40 100644 --- a/src/cwmp.c +++ b/src/cwmp.c @@ -44,6 +44,7 @@ bool g_firewall_restart = false; struct list_head intf_reset_list; struct list_head du_uuid_list; +struct list_head force_inform_list; static bool interface_reset_req(char *param_name, char *value) { @@ -254,6 +255,14 @@ static int cwmp_init(void) cwmp_get_deviceid(); cwmp_uci_init(); + + /* Load default force inform parameters */ + CWMP_MEMSET(&force_inform_list, 0, sizeof(struct list_head)); + INIT_LIST_HEAD(&force_inform_list); + load_default_forced_inform(); + + /* Load custom notify and force inform parameters */ + load_forced_inform_json(); load_custom_notify_json(); set_default_forced_active_parameters_notifications(); init_list_param_notify(); @@ -303,6 +312,7 @@ void cwmp_exit() clean_autonomous_complpolicy(); clean_interface_update(); clean_du_uuid_list(); + clean_force_inform_list(); FREE(cwmp_main->ev); FREE(cwmp_main->intf_ev); uloop_end(); diff --git a/src/rpc.c b/src/rpc.c index a383fe8..4e72db4 100755 --- a/src/rpc.c +++ b/src/rpc.c @@ -338,14 +338,16 @@ static void load_inform_xml_schema(mxml_node_t **tree) } struct cwmp_dm_parameter cwmp_dm_param = {0}; - for (size_t i = 0; i < ARRAY_SIZE(forced_inform_parameters); i++) { - if (!cwmp_get_parameter_value(forced_inform_parameters[i], &cwmp_dm_param)) + force_inform_node *iter = NULL, *node = NULL; + + list_for_each_entry_safe(iter, node, &force_inform_list, list) { + if (!cwmp_get_parameter_value(iter->path, &cwmp_dm_param)) continue; // An empty connection url cause CDR test to break - if (strcmp(forced_inform_parameters[i], "Device.ManagementServer.ConnectionRequestURL") == 0 && + if (strcmp(iter->path, "Device.ManagementServer.ConnectionRequestURL") == 0 && CWMP_STRLEN(cwmp_dm_param.value) == 0) { - CWMP_LOG(ERROR, "# Empty CR URL[%s] value", forced_inform_parameters[i]); + CWMP_LOG(ERROR, "# Empty CR URL[%s] value", iter->path); MXML_DELETE(xml); return; } @@ -425,8 +427,9 @@ static int validate_inform_parameter_name(struct list_head *parameters_values_li if (match_reg_exp(reg_exp, param_value->name) == false) continue; - for (size_t i = 0; i < ARRAY_SIZE(forced_inform_parameters); i++) { - if (strcmp(forced_inform_parameters[i], param_value->value) == 0) + force_inform_node *iter = NULL, *node = NULL; + list_for_each_entry_safe(iter, node, &force_inform_list, list) { + if (strcmp(iter->path, param_value->value) == 0) return FAULT_CPE_INVALID_PARAMETER_VALUE; } } @@ -2091,3 +2094,92 @@ int cwmp_create_fault_message(struct rpc *rpc_cpe, int fault_code, char *fault_m return 0; } + +void load_default_forced_inform(void) +{ + size_t i; + + for (i = 0; i < ARRAY_SIZE(forced_inform_parameters); i++) { + force_inform_node *node = (force_inform_node *)malloc(sizeof(force_inform_node)); + if (node == NULL) { + CWMP_LOG(ERROR, "Out of memory"); + break; + } + + CWMP_MEMSET(node, 0, sizeof(force_inform_node)); + snprintf(node->path, sizeof(node->path), "%s", forced_inform_parameters[i]); + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, &force_inform_list); + } +} + +void clean_force_inform_list(void) +{ + force_inform_node *iter = NULL, *node = NULL; + + list_for_each_entry_safe(iter, node, &force_inform_list, list) { + list_del(&iter->list); + free(iter); + } +} + +void load_forced_inform_json(void) +{ + struct blob_buf bbuf = {0}; + struct blob_attr *cur = NULL; + struct blob_attr *forced_inform_list = NULL; + int rem = 0; + + if (!file_exists(cwmp_main->conf.forced_inform_json)) + return; + + CWMP_MEMSET(&bbuf, 0, sizeof(struct blob_buf)); + blob_buf_init(&bbuf, 0); + + if (blobmsg_add_json_from_file(&bbuf, cwmp_main->conf.forced_inform_json) == false) { + CWMP_LOG(WARNING, "The file %s is not a valid JSON file", cwmp_main->conf.forced_inform_json); + blob_buf_free(&bbuf); + return; + } + + struct blob_attr *tb[1] = { NULL }; + const struct blobmsg_policy p[1] = { { "forced_inform", BLOBMSG_TYPE_ARRAY } }; + + blobmsg_parse(p, 1, tb, blobmsg_data(bbuf.head), blobmsg_len(bbuf.head)); + if (tb[0] == NULL) { + CWMP_LOG(WARNING, "The JSON file %s doesn't contain a forced inform parameters list", cwmp_main->conf.forced_inform_json); + blob_buf_free(&bbuf); + return; + } + + forced_inform_list = tb[0]; + blobmsg_for_each_attr(cur, forced_inform_list, rem) + { + char parameter_path[1024]; + struct cwmp_dm_parameter cwmp_dm_param = {0}; + + snprintf(parameter_path, sizeof(parameter_path), "%s", blobmsg_get_string(cur)); + if (parameter_path[strlen(parameter_path)-1] == '.') { + CWMP_LOG(WARNING, "%s is rejected as inform parameter. Only leaf parameters are allowed.", parameter_path); + continue; + } + + if (!cwmp_get_parameter_value(parameter_path, &cwmp_dm_param)) { + CWMP_LOG(WARNING, "%s is rejected as inform parameter. Wrong parameter path.", parameter_path); + continue; + } + + /* Add in forced inform list */ + force_inform_node *node = (force_inform_node *)malloc(sizeof(force_inform_node)); + if (node == NULL) { + CWMP_LOG(ERROR, "Out of memory"); + break; + } + + CWMP_MEMSET(node, 0, sizeof(force_inform_node)); + snprintf(node->path, sizeof(node->path), "%s", parameter_path); + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, &force_inform_list); + } + blob_buf_free(&bbuf); +} diff --git a/src/rpc.h b/src/rpc.h index bbb8500..6f04181 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -51,5 +51,8 @@ int cwmp_rpc_acs_prepare_autonomous_transfer_complete(struct rpc *rpc); int xml_handle_message(); int cwmp_create_fault_message(struct rpc *rpc_cpe, int fault_code, char *fault_msg); +void load_default_forced_inform(void); +void clean_force_inform_list(void); +void load_forced_inform_json(void); #endif diff --git a/test/cmocka/icwmp_soap_msg_unit_test.c b/test/cmocka/icwmp_soap_msg_unit_test.c index 09c71e9..7b1e32c 100644 --- a/test/cmocka/icwmp_soap_msg_unit_test.c +++ b/test/cmocka/icwmp_soap_msg_unit_test.c @@ -30,6 +30,7 @@ #include "cwmp_event.h" static int instance = 0; +struct list_head force_inform_list; #define INVALID_PARAM_KEY "ParameterKeyParameterKeyParameter" #define INVALID_USER "useruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruseruser1" @@ -69,6 +70,11 @@ static void unit_test_end_test_destruction() */ static int soap_unit_tests_init(void **state) { + CWMP_MEMSET(&force_inform_list, 0, sizeof(struct list_head)); + INIT_LIST_HEAD(&force_inform_list); + load_default_forced_inform(); + load_forced_inform_json(); + cwmp_main = (struct cwmp*)calloc(1, sizeof(struct cwmp)); create_cwmp_session_structure(); memcpy(&(cwmp_main->env), &cwmp_main, sizeof(struct env)); @@ -82,6 +88,7 @@ static int soap_unit_tests_clean(void **state) icwmp_free_list_services(); clean_name_space(); cwmp_session_exit(); + clean_force_inform_list(); FREE(cwmp_main->session); FREE(cwmp_main); return 0;