diff --git a/CMakeLists.txt b/CMakeLists.txt index b18575b..80c7685 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -37,7 +37,7 @@ ENDIF(WITH_MBEDTLS) ADD_EXECUTABLE(icwmpd ${ICWMP_SOURCES}) -TARGET_LINK_LIBRARIES(icwmpd pthread z m json-c uci ubox ubus blobmsg_json curl mxml ${SSL_LIBS} ${CRYPTO_LIBS}) +TARGET_LINK_LIBRARIES(icwmpd pthread z m json-c uci ubox ubus blobmsg_json curl mxml uuid ${SSL_LIBS} ${CRYPTO_LIBS}) INSTALL(FILES icwmpd DESTINATION usr/sbin) diff --git a/gitlab-ci/install-dependencies.sh b/gitlab-ci/install-dependencies.sh index 9a0624c..4ff88b8 100755 --- a/gitlab-ci/install-dependencies.sh +++ b/gitlab-ci/install-dependencies.sh @@ -7,7 +7,7 @@ pwd # install required packages exec_cmd apt update -exec_cmd apt install -y mongodb jq +exec_cmd apt install -y mongodb jq uuid-dev exec_cmd apt-get install -y libmxml-dev # install genieacs exec_cmd npm install -g genieacs@1.2.5 diff --git a/src/autonomous_complpolicy.c b/src/autonomous_complpolicy.c new file mode 100644 index 0000000..5c6fda5 --- /dev/null +++ b/src/autonomous_complpolicy.c @@ -0,0 +1,238 @@ +/* + * autonomous_complpolicy.c - CWMP autonomous notification methods + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Suvendhu Hansa + * + * See LICENSE file for license related information. + * + */ + +#include "autonomous_complpolicy.h" +#include "cwmp_uci.h" +#include "cwmp_du_state.h" +#include "log.h" +#include +#include "backupSession.h" +#include "common.h" +#include "session.h" +#include "event.h" + +enum autonomous_notif_type { + DU_STATE_CHANGE, + __MAX_NOTIF_TYPE +}; + +typedef void (*autonomous_event_callback)(struct blob_attr *msg); + +struct autonomous_event { + char name[2048]; + autonomous_event_callback cb; +}; + +static bool filters_qualified(int type, void *data) +{ + char *enable = NULL, *op_filter = NULL, *res_filter = NULL; + + switch (type) { + case DU_STATE_CHANGE: + cwmp_uci_reinit(); + uci_get_state_value(UCI_AUTONOMOUS_DU_STATE_ENABLE, &enable); + uci_get_state_value(UCI_AUTONOMOUS_DU_STATE_OPERATION, &op_filter); + uci_get_state_value(UCI_AUTONOMOUS_DU_STATE_RESULT, &res_filter); + + auto_du_state_change_compl *p = (auto_du_state_change_compl *)data; + if (p == NULL) + return false; + + if (enable == NULL || op_filter == NULL) + return false; + + if (uci_str_to_bool(enable) == false || strlen(op_filter) == 0) + return false; + + if (strstr(op_filter, p->operation) == NULL) + return false; + + if (res_filter && strlen(res_filter) != 0 && strcmp(res_filter, "Both") != 0) { + if (strcmp(res_filter, "Failure") == 0 && strcmp(p->current_state, "Failed") != 0) + return false; + + if (strcmp(res_filter, "Success") == 0 && strcmp(p->current_state, "Failed") == 0) + return false; + } + /* For now falut_code filter is not supported since usp-data-model + * only provides 7002, 7004, 7223, 7225, 7226, 7227 & 7229 but + * cwmp-data-model supports more fault-codes with more specific cause, + * so need to implement a mapping between usp FaultString & cwmp error code */ + break; + default: + return false; + } + + return true; +} + +static void send_du_state_change_notif(struct blob_attr *msg) +{ + (void)msg; + CWMP_LOG(INFO, "Received DU STATE CHANGE EVENT"); + const struct blobmsg_policy p[2] = { + { "name", BLOBMSG_TYPE_STRING }, + { "input", BLOBMSG_TYPE_TABLE } + }; + + const struct blobmsg_policy p1[9] = { + { "UUID", BLOBMSG_TYPE_STRING }, + { "Version", BLOBMSG_TYPE_STRING }, + { "CurrentState", BLOBMSG_TYPE_STRING }, + { "Resolved", BLOBMSG_TYPE_INT8 }, + { "StartTime", BLOBMSG_TYPE_STRING }, + { "CompleteTime", BLOBMSG_TYPE_STRING }, + { "OperationPerformed", BLOBMSG_TYPE_STRING }, + { "Fault.FaultCode", BLOBMSG_TYPE_INT32 }, + { "Fault.FaultString", BLOBMSG_TYPE_STRING } + }; + + struct blob_attr *tb[2] = {NULL}; + blobmsg_parse(p, 2, tb, blob_data(msg), blob_len(msg)); + + if (tb[1]) { + char *uuid = NULL, *oper = NULL; + + CWMP_LOG(INFO, "%s\n", blobmsg_format_json_indent(tb[1], true, -1)); + struct blob_attr *tb1[9] = {NULL}; + blobmsg_parse(p1, 9, tb1, blobmsg_data(tb[1]), blobmsg_len(tb[1])); + + if (tb1[0]) { + uuid = blobmsg_get_string(tb1[0]); + } + + if (tb1[6]) { + oper = blobmsg_get_string(tb1[6]); + } + + CWMP_LOG(INFO, "uuid: %s, oper: %s\n", uuid ? uuid : "", oper ? oper : ""); + if (uuid == NULL || oper == NULL) + return; + + if (exists_in_uuid_list(uuid, oper)) { + /* This DU operation was performed by cwmp */ + remove_node_from_uuid_list(uuid, oper); + } else { + /* This DU operation was performed from outside */ + auto_du_state_change_compl *data = calloc(1, sizeof(auto_du_state_change_compl)); + if (data == NULL) + return; + + data->uuid = strdup(uuid); + data->operation = strdup(oper); + + if (tb1[1]) { + data->ver = strdup(blobmsg_get_string(tb1[1])); + } + + if (tb1[2]) { + data->current_state = strdup(blobmsg_get_string(tb1[2])); + } + + if (tb1[3]) { + data->resolved = blobmsg_get_u8(tb1[3]) ? 1 : 0; + } + + if (tb1[4]) { + data->start_time = strdup(blobmsg_get_string(tb1[4])); + } + + if (tb1[5]) { + data->complete_time = strdup(blobmsg_get_string(tb1[5])); + } + + if (tb1[7]) { + //data->fault_code = blobmsg_get_u32(tb1[7]); + data->fault_code = 9001; // for now setting a generic code */ + } + + if (tb1[8]) { + data->fault_string = strdup(blobmsg_get_string(tb1[8])); + } + + // Check autonomous_du_state_change_complpolicy filters + if (filters_qualified(DU_STATE_CHANGE, data) == false) { + CWMP_LOG(INFO, "autonomous du state change filters not matched"); + FREE(data); + return; + } + + bkp_session_insert_autonomous_du_state_change(data); + bkp_session_save(); + + CWMP_LOG(INFO, "autonomous du state change event added"); + struct session_timer_event *ubus_inform_event = calloc(1, sizeof(struct session_timer_event)); + + ubus_inform_event->extra_data = data; + ubus_inform_event->session_timer_evt.cb = cwmp_schedule_session_with_event; + ubus_inform_event->event = EVENT_IDX_12AUTONOMOUS_DU_STATE_CHANGE_COMPLETE; + trigger_cwmp_session_timer_with_event(&ubus_inform_event->session_timer_evt); + } + } +} + +static struct autonomous_event event_info[] = { + { "Device.SoftwareModules.DUStateChange!", send_du_state_change_notif } +}; + +static void send_autonomous_notification(char *ev_name, struct blob_attr *msg) +{ + int i; + + if (!ev_name) + return; + + int count = sizeof(event_info)/sizeof(struct autonomous_event); + for (i = 0; i < count; i++) { + if (strcmp(event_info[i].name, ev_name) == 0) { + autonomous_event_callback cb = event_info[i].cb; + cb(msg); + return; + } + } +} + +void autonomous_notification_handler(struct ubus_context *ctx __attribute__((unused)), + struct ubus_event_handler *ev __attribute__((unused)), + const char *type __attribute__((unused)), struct blob_attr *msg) +{ + if (!msg) + return; + + size_t len = (size_t)blobmsg_data_len(msg); + struct blob_attr *attr; + + __blob_for_each_attr(attr, blobmsg_data(msg), len) { + const char *attr_name = blobmsg_name(attr); + if (attr_name != NULL && strcmp(attr_name, "name") == 0) { + send_autonomous_notification(blobmsg_data(attr), msg); + break; + } + } +} + +int cwmp_rpc_acs_destroy_data_autonomous_du_state_change_complete(struct rpc *rpc) +{ + auto_du_state_change_compl *p = (auto_du_state_change_compl *)rpc->extra_data; + if (p) { + bkp_session_delete_autonomous_du_state_change(p); + FREE(p->uuid); + FREE(p->ver); + FREE(p->current_state); + FREE(p->start_time); + FREE(p->complete_time); + FREE(p->fault_string); + FREE(p->operation); + FREE(p); + } + + return 0; +} diff --git a/src/autonomous_complpolicy.h b/src/autonomous_complpolicy.h new file mode 100644 index 0000000..eaa76af --- /dev/null +++ b/src/autonomous_complpolicy.h @@ -0,0 +1,23 @@ +/* + * autonomous_complpolicy.h - CWMP autonomous notification header + * + * Copyright (C) 2021-2022, IOPSYS Software Solutions AB. + * + * Author Suvendhu Hansa + * + * See LICENSE file for license related information. + * + */ + +#ifndef __AUTONOMOUS_COMPL_H +#define __AUTONOMOUS_COMPL_H + +#include "libubus.h" +#include "common.h" + +void autonomous_notification_handler(struct ubus_context *ctx __attribute__((unused)), + struct ubus_event_handler *ev __attribute__((unused)), + const char *type __attribute__((unused)), struct blob_attr *msg); +int cwmp_rpc_acs_destroy_data_autonomous_du_state_change_complete(struct rpc *rpc); + +#endif diff --git a/src/backupSession.c b/src/backupSession.c index 5aa2bb8..0c3e0cc 100644 --- a/src/backupSession.c +++ b/src/backupSession.c @@ -67,6 +67,8 @@ struct backup_attributes_name_type bkp_attrs_names[] = { { "command_key", BKP_ST { "fault_code", BKP_INTEGER }, { "resolved", BKP_BOOL }, { "time", BKP_TIME }, + { "fault_string", BKP_STRING }, + { "operation", BKP_STRING }, { "windowstart1", BKP_TIME }, { "windowend1", BKP_TIME }, { "windowstart2", BKP_TIME }, @@ -100,6 +102,8 @@ struct backup_attributes { int *fault_code; bool *resolved; time_t *time; + char **fault_string; + char **operation; time_t *windowstart1; time_t *windowend1; time_t *windowstart2; @@ -568,6 +572,73 @@ void bkp_session_delete_upload(struct upload *pupload) mxmlDelete(b); } +void bkp_session_insert_autonomous_du_state_change(auto_du_state_change_compl *data) +{ + char resolved[8], fault_code[8]; + mxml_node_t *b; + + if (data == NULL) + return; + + snprintf(resolved, sizeof(resolved), "%d", data->resolved); + snprintf(fault_code, sizeof(fault_code), "%d", data->fault_code); + + struct search_keywords keys[9] = { + { "uuid", data->uuid }, + { "version", data->ver ? data->ver : "" }, + { "current_state", data->current_state ? data->current_state : "" }, + { "resolved", resolved }, + { "start_time", data->start_time ? data->start_time : "" }, + { "complete_time", data->complete_time ? data->complete_time : "" }, + { "fault_code", fault_code }, + { "fault_string", data->fault_string ? data->fault_string : "" }, + { "operation", data->operation ? data->operation : "" } + }; + + b = bkp_session_node_found(bkp_tree, "autonomous_du_state_change_complete", keys, 9); + if (!b) { + b = bkp_session_insert(bkp_tree, "autonomous_du_state_change_complete", NULL); + bkp_session_insert(b, "uuid", data->uuid); + bkp_session_insert(b, "version", data->ver ? data->ver : ""); + bkp_session_insert(b, "current_state", data->current_state ? data->current_state : ""); + bkp_session_insert(b, "resolved", resolved); + bkp_session_insert(b, "start_time", data->start_time ? data->start_time : ""); + bkp_session_insert(b, "complete_time", data->complete_time ? data->complete_time : ""); + bkp_session_insert(b, "fault_code", fault_code); + bkp_session_insert(b, "fault_string", data->fault_string ? data->fault_string : ""); + bkp_session_insert(b, "operation", data->operation ? data->operation : ""); + } +} + +void bkp_session_delete_autonomous_du_state_change(auto_du_state_change_compl *data) +{ + char resolved[8], fault_code[8]; + mxml_node_t *b; + + if (data == NULL) + return; + + snprintf(resolved, sizeof(resolved), "%d", data->resolved); + snprintf(fault_code, sizeof(fault_code), "%d", data->fault_code); + + struct search_keywords keys[9] = { + { "uuid", data->uuid }, + { "version", data->ver ? data->ver : "" }, + { "current_state", data->current_state ? data->current_state : "" }, + { "resolved", resolved }, + { "start_time", data->start_time ? data->start_time : "" }, + { "complete_time", data->complete_time ? data->complete_time : "" }, + { "fault_code", fault_code }, + { "fault_string", data->fault_string ? data->fault_string : "" }, + { "operation", data->operation ? data->operation : "" } + }; + + b = bkp_session_node_found(bkp_tree, "autonomous_du_state_change_complete", keys, 9); + if (!b) { + mxmlDelete(b); + } +} + void bkp_session_insert_du_state_change_complete(struct du_state_change_complete *pdu_state_change_complete) { char schedule_time[128], resolved[8], fault_code[8]; @@ -975,6 +1046,26 @@ void load_transfer_complete(mxml_node_t *tree) sotfware_version_value_change(ptransfer_complete); } +void load_autonomous_du_state_change_complete(mxml_node_t *tree) +{ + auto_du_state_change_compl *p; + + p = calloc(1, sizeof(auto_du_state_change_compl)); + + struct backup_attributes bkp_attrs = { .uuid = &p->uuid, + .version = &p->ver, + .current_state = &p->current_state, + .resolved = &p->resolved, + .start_time = &p->start_time, + .complete_time = &p->complete_time, + .fault_code = &p->fault_code, + .fault_string = &p->fault_string, + .operation = &p->operation }; + load_specific_backup_attributes(tree, &bkp_attrs); + + cwmp_root_cause_autonomous_cdu_complete(p); +} + void bkp_session_create_file() { FILE *pFile; @@ -1073,6 +1164,8 @@ int cwmp_load_saved_session(char **ret, enum backup_loading load) load_du_state_change_complete(b); } else if (ntype == MXML_ELEMENT && strcmp(elem_name, "schedule_download") == 0) { load_schedule_download(b); + } else if (ntype == MXML_ELEMENT && strcmp(elem_name, "autonomous_du_state_change_complete") == 0) { + load_autonomous_du_state_change_complete(b); } } b = mxmlWalkNext(b, bkp_tree, MXML_NO_DESCEND); diff --git a/src/backupSession.h b/src/backupSession.h index cdacc90..37692f4 100644 --- a/src/backupSession.h +++ b/src/backupSession.h @@ -63,5 +63,7 @@ void bkp_session_insert_schedule_download(struct download *pschedule_download); void bkp_session_delete_du_state_change_complete(struct du_state_change_complete *pdu_state_change_complete); void bkp_session_delete_schedule_download(struct download *pschedule_download); void bkp_session_insert_du_state_change_complete(struct du_state_change_complete *pdu_state_change_complete); +void bkp_session_insert_autonomous_du_state_change(auto_du_state_change_compl *data); +void bkp_session_delete_autonomous_du_state_change(auto_du_state_change_compl *data); void bkp_tree_clean(void); #endif /* _BACKUPSESSION_H__ */ diff --git a/src/common.h b/src/common.h index 8e3be91..2c98cef 100644 --- a/src/common.h +++ b/src/common.h @@ -163,6 +163,7 @@ typedef struct cwmp { time_t cwmp_periodic_time; bool cwmp_periodic_enable; bool custom_notify_active; + struct ubus_event_handler *ev; } cwmp; enum action { @@ -274,6 +275,7 @@ enum rpc_acs_methods_idx { RPC_ACS_GET_RPC_METHODS, RPC_ACS_TRANSFER_COMPLETE, RPC_ACS_DU_STATE_CHANGE_COMPLETE, + RPC_ACS_AUTONOMOUS_DU_STATE_CHANGE_COMPLETE, __RPC_ACS_MAX }; @@ -291,7 +293,9 @@ enum load_type { enum dustate_type { DU_INSTALL = 1, - DU_UPDATE, DU_UNINSTALL + DU_UPDATE, + DU_UNINSTALL, + __MAX_DU_STATE }; enum fault_cpe_idx { @@ -432,6 +436,12 @@ typedef struct change_du_state { struct list_head list_operation; } change_du_state; +typedef struct du_operational_uuid { + struct list_head list; + char uuid[37]; + char operation[10]; +} du_op_uuid; + typedef struct operations { struct list_head list; int type; @@ -464,6 +474,18 @@ typedef struct transfer_complete { int type; } transfer_complete; +typedef struct autonomous_du_state_change_complete { + char *uuid; + char *ver; + char *current_state; + bool resolved; + char *start_time; + char *complete_time; + int fault_code; + char *fault_string; + char *operation; +} auto_du_state_change_compl; + typedef struct du_state_change_complete { char *command_key; time_t timeout; diff --git a/src/cwmp.c b/src/cwmp.c index da65db6..48ee0f1 100644 --- a/src/cwmp.c +++ b/src/cwmp.c @@ -43,6 +43,7 @@ bool g_firewall_restart = false; struct list_head intf_reset_list; +struct list_head du_uuid_list; static bool interface_reset_req(char *param_name, char *value) { @@ -253,6 +254,8 @@ static int cwmp_init() get_nonce_key(); memset(&intf_reset_list, 0, sizeof(struct list_head)); INIT_LIST_HEAD(&intf_reset_list); + memset(&du_uuid_list, 0, sizeof(struct list_head)); + INIT_LIST_HEAD(&du_uuid_list); cwmp_main->start_time = time(NULL); cwmp_main->event_id = 0; cwmp_main->cwmp_period = 0; @@ -306,6 +309,9 @@ void cwmp_exit() uloop_timeout_cancel(&periodic_session_timer); uloop_timeout_cancel(&session_timer); uloop_timeout_cancel(&heartbeat_session_timer); + clean_autonomous_complpolicy(); + clean_du_uuid_list(); + FREE(cwmp_main->ev); uloop_end(); shutdown(cwmp_main->cr_socket_desc, SHUT_RDWR); FREE(global_session_event); @@ -362,6 +368,9 @@ int main(int argc, char **argv) icwmp_uloop_ubus_init(); + if (0 != initiate_autonomous_complpolicy()) + return error; + trigger_cwmp_session_timer(); intiate_heartbeat_procedures(); diff --git a/src/cwmp_du_state.c b/src/cwmp_du_state.c index 9422267..7b0691d 100644 --- a/src/cwmp_du_state.c +++ b/src/cwmp_du_state.c @@ -20,44 +20,98 @@ #include "backupSession.h" #include "event.h" #include "session.h" +#include LIST_HEAD(list_change_du_state); +static char *generate_uuid(void) +{ + uuid_t binuuid; + + uuid_generate_random(binuuid); + char *uuid = malloc(37); + uuid_unparse(binuuid, uuid); + + return uuid; +} + void ubus_du_state_callback(struct ubus_request *req, int type __attribute__((unused)), struct blob_attr *msg) { char **fault = (char **)req->priv; - const struct blobmsg_policy p[1] = { { "status", BLOBMSG_TYPE_BOOL } }; + const struct blobmsg_policy p[1] = { { "Result", BLOBMSG_TYPE_ARRAY } }; struct blob_attr *tb[1] = { NULL }; blobmsg_parse(p, 1, tb, blobmsg_data(msg), blobmsg_len(msg)); - if (tb[0] && blobmsg_get_bool(tb[0])) { + if (tb[0]) { + struct blob_attr *head = blobmsg_data(tb[0]); + int len = blobmsg_data_len(tb[0]); + struct blob_attr *attr; + + __blob_for_each_attr(attr, head, len) { + struct blob_attr *data = blobmsg_data(attr); + int data_len = blobmsg_data_len(attr); + struct blob_attr *param; + __blob_for_each_attr(param, data, data_len) { + struct blobmsg_hdr *hdr = blob_data(attr); + if (hdr && hdr->name && strcmp((char*)hdr->name, "fault") == 0) { + *fault = strdup("9010"); + return; + } + } + } *fault = NULL; } else { *fault = strdup("9010"); } } -static void prepare_blob_msg(struct blob_buf *b, char *url, char *uuid, char *user, char *pass, char *env_name, int env_id) +static void prepare_blob_msg(struct blob_buf *b, char *url, char *uuid, char *user, char *pass, char *path, char *env_ref, int op) { 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); + void *tbl; + bb_add_string(b, "path", path); + + switch (op) { + case DU_INSTALL: + bb_add_string(b, "action", "InstallDU()"); + tbl = blobmsg_open_table(b, "input"); + bb_add_string(b, "UUID", uuid); + bb_add_string(b, "ExecutionEnvRef", env_ref ? env_ref : ""); + bb_add_string(b, "URL", url ? url : ""); + bb_add_string(b, "Username", user ? user : ""); + bb_add_string(b, "Password", pass ? pass : ""); + blobmsg_close_table(b, tbl); + break; + case DU_UPDATE: + bb_add_string(b, "action", "Update()"); + tbl = blobmsg_open_table(b, "input"); + bb_add_string(b, "URL", url ? url : ""); + bb_add_string(b, "Username", user ? user : ""); + bb_add_string(b, "Password", pass ? pass : ""); + blobmsg_close_table(b, tbl); + break; + case DU_UNINSTALL: + bb_add_string(b, "action", "Uninstall()"); + break; + default: + CWMP_LOG(ERROR, "Invalid DU operation"); + } } -int cwmp_du_install(char *url, char *uuid, char *user, char *pass, char *env_name, int env_id, char **fault_code) +int cwmp_du_install(char *url, char *uuid, char *user, char *pass, char *path, char *env_ref, char **fault_code) { int e; 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); + int len = CWMP_STRLEN(env_ref); + if (len > 0 && env_ref[len - 1] == '.') + env_ref[len - 1] = '\0'; + + prepare_blob_msg(&b, url, uuid, user, pass, path, env_ref, DU_INSTALL); + e = icwmp_ubus_invoke("usp.raw", "operate", b.head, ubus_du_state_callback, fault_code); blob_buf_free(&b); if (e < 0) { @@ -67,15 +121,15 @@ int cwmp_du_install(char *url, char *uuid, char *user, char *pass, char *env_nam return FAULT_CPE_NO_FAULT; } -int cwmp_du_update(char *url, char *uuid, char *user, char *pass, char *env_name, int env_id, char **fault_code) +int cwmp_du_update(char *url, char *user, char *pass, char *du_path, char **fault_code) { int e; 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); + prepare_blob_msg(&b, url, 0, user, pass, du_path, "", DU_UPDATE); + e = icwmp_ubus_invoke("usp.raw", "operate", b.head, ubus_du_state_callback, fault_code); blob_buf_free(&b); if (e < 0) { @@ -85,18 +139,16 @@ int cwmp_du_update(char *url, char *uuid, char *user, char *pass, char *env_name return FAULT_CPE_NO_FAULT; } -int cwmp_du_uninstall(char *package_name, char *env_name, int env_id, char **fault_code) +int cwmp_du_uninstall(char *du_path, char **fault_code) { int e; 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); + prepare_blob_msg(&b, "", 0, "", "", du_path, "", DU_UNINSTALL); - e = icwmp_ubus_invoke("swmodules", "du_uninstall", b.head, ubus_du_state_callback, fault_code); + e = icwmp_ubus_invoke("usp.raw", "operate", b.head, ubus_du_state_callback, fault_code); blob_buf_free(&b); if (e < 0) { @@ -187,19 +239,6 @@ char *get_deployment_unit_by_uuid(char *uuid) return sw_by_uuid_instance; } -static char *get_deployment_unit_reference(char *package_name, char *package_env) -{ - LIST_HEAD(sw_parameters); - char *sw_by_name_env_instance = NULL, *deployment_unit_ref = NULL; - sw_by_name_env_instance = get_software_module_object_eq("Name", package_name, "ExecutionEnvRef", package_env, &sw_parameters); - cwmp_free_all_dm_parameter_list(&sw_parameters); - if (!sw_by_name_env_instance) - return NULL; - - cwmp_asprintf(&deployment_unit_ref, "Device.SoftwareModules.DeploymentUnit.%s", sw_by_name_env_instance); - return deployment_unit_ref; -} - static bool environment_exists(char *environment_path) { LIST_HEAD(environment_list); @@ -211,58 +250,32 @@ static bool environment_exists(char *environment_path) return true; } -static char *get_exec_env_name(char *environment_path) -{ - char env_param[256], *env_name = ""; - - LIST_HEAD(environment_list); - char *err = cwmp_get_parameter_values(environment_path, &environment_list); - if (err) - return strdup(""); - - struct cwmp_dm_parameter *param_value = NULL; - snprintf(env_param, sizeof(env_param), "%sName", environment_path); - list_for_each_entry (param_value, &environment_list, list) { - if (param_value->name && strcmp(param_value->name, env_param) == 0) { - env_name = strdup(param_value->value); - break; - } - } - cwmp_free_all_dm_parameter_list(&environment_list); - return env_name; -} - -static int cwmp_launch_du_install(char *url, char *uuid, char *user, char *pass, char *env_name, int env_id, struct opresult **pchange_du_state_complete) -{ - int error = FAULT_CPE_NO_FAULT; - char *fault_code = NULL; - - (*pchange_du_state_complete)->start_time = strdup(get_time(time(NULL))); - cwmp_du_install(url, uuid, user, pass, env_name, env_id, &fault_code); - - if (fault_code != NULL) { - if (fault_code[0] == '9') { - int i; - for (i = 1; i < __FAULT_CPE_MAX; i++) { - if (strcmp(FAULT_CPE_ARRAY[i].CODE, fault_code) == 0) { - error = i; - break; - } - } - } - free(fault_code); - } - return error; -} - -static int cwmp_launch_du_update(char *uuid, char *url, char *user, char *pass, char *env_name, int env_id, struct opresult **pchange_du_state_complete) +static int cwmp_launch_du_install(char *url, char *uuid, char *user, char *pass, char *path, char *env_ref, struct opresult **pchange_du_state_complete) { int error = FAULT_CPE_NO_FAULT; char *fault_code; (*pchange_du_state_complete)->start_time = strdup(get_time(time(NULL))); - cwmp_du_update(url, uuid, user, pass, env_name, env_id, &fault_code); + if (uuid == NULL) { + return FAULT_CPE_INTERNAL_ERROR; + } + + /* store uuid in list for du state change event */ + du_op_uuid *node = (du_op_uuid *)malloc(sizeof(du_op_uuid)); + if (node == NULL) { + return FAULT_CPE_INTERNAL_ERROR; + } + + memset(node, 0, sizeof(du_op_uuid)); + snprintf(node->uuid, sizeof(node->uuid), "%s", uuid); + snprintf(node->operation, sizeof(node->operation), "%s", "Install"); + + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, &du_uuid_list); + + cwmp_du_install(url, uuid, user, pass, path, env_ref, &fault_code); + if (fault_code != NULL) { if (fault_code[0] == '9') { int i; @@ -278,15 +291,31 @@ static int cwmp_launch_du_update(char *uuid, char *url, char *user, char *pass, return error; } -static int cwmp_launch_du_uninstall(char *package_name, char *env_name, int env_id, struct opresult **pchange_du_state_complete) +static int cwmp_launch_du_update(char *url, char *uuid, char *user, char *pass, char *du_path, struct opresult **pchange_du_state_complete) { int error = FAULT_CPE_NO_FAULT; char *fault_code; (*pchange_du_state_complete)->start_time = strdup(get_time(time(NULL))); - cwmp_du_uninstall(package_name, env_name, env_id, &fault_code); + if (uuid == NULL) { + return FAULT_CPE_INTERNAL_ERROR; + } + /* store uuid in list for du state change event */ + du_op_uuid *node = (du_op_uuid *)malloc(sizeof(du_op_uuid)); + if (node == NULL) { + return FAULT_CPE_INTERNAL_ERROR; + } + + memset(node, 0, sizeof(du_op_uuid)); + snprintf(node->uuid, sizeof(node->uuid), "%s", uuid); + snprintf(node->operation, sizeof(node->operation), "%s", "Update"); + + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, &du_uuid_list); + + cwmp_du_update(url, user, pass, du_path, &fault_code); if (fault_code != NULL) { if (fault_code[0] == '9') { int i; @@ -302,11 +331,45 @@ static int cwmp_launch_du_uninstall(char *package_name, char *env_name, int env_ return error; } -int get_exec_env_id(char *exec_env_ref) +static int cwmp_launch_du_uninstall(char *du_path, char *uuid, struct opresult **pchange_du_state_complete) { - int id = 0; - sscanf(exec_env_ref, "Device.SoftwareModules.ExecEnv.%d", &id); - return id; + int error = FAULT_CPE_NO_FAULT; + char *fault_code; + + (*pchange_du_state_complete)->start_time = strdup(get_time(time(NULL))); + + if (uuid == NULL) { + return FAULT_CPE_INTERNAL_ERROR; + } + + /* store uuid in list for du state change event */ + du_op_uuid *node = (du_op_uuid *)malloc(sizeof(du_op_uuid)); + if (node == NULL) { + return FAULT_CPE_INTERNAL_ERROR; + } + + memset(node, 0, sizeof(du_op_uuid)); + snprintf(node->uuid, sizeof(node->uuid), "%s", uuid); + snprintf(node->operation, sizeof(node->operation), "%s", "Uninstall"); + + INIT_LIST_HEAD(&node->list); + list_add_tail(&node->list, &du_uuid_list); + + cwmp_du_uninstall(du_path, &fault_code); + + if (fault_code != NULL) { + if (fault_code[0] == '9') { + int i; + for (i = 1; i < __FAULT_CPE_MAX; i++) { + if (strcmp(FAULT_CPE_ARRAY[i].CODE, fault_code) == 0) { + error = i; + break; + } + } + } + free(fault_code); + } + return error; } char *get_package_name_by_url(char *url) @@ -340,7 +403,16 @@ int change_du_state_fault(struct change_du_state *pchange_du_state, struct du_st list_for_each_entry_safe (p, q, &pchange_du_state->list_operation, list) { struct opresult *res = calloc(1, sizeof(struct opresult)); list_add_tail(&(res->list), &((*pdu_state_change_complete)->list_opresult)); - res->uuid = strdup(p->uuid); + + // cppcheck-suppress uninitvar + if (CWMP_STRLEN(p->uuid) == 0) { + char *uuid = generate_uuid(); + res->uuid = strdup(uuid); + FREE(uuid); + } else { + res->uuid = strdup(p->uuid); + } + res->version = strdup(p->version); res->current_state = strdup("Failed"); res->start_time = strdup(get_time(time(NULL))); @@ -365,6 +437,8 @@ void change_du_state_execute(struct uloop_timeout *utimeout) struct opresult *res; struct du_state_change_complete *pdu_state_change_complete; char *du_ref = NULL; + char du_path[2048] = {0}; + //struct session_timer_event cdu_inform_event = {.session_timer_evt = {.cb = cwmp_schedule_session_with_event}, .event = CDU_Evt}; struct session_timer_event *cdu_inform_event = calloc(1, sizeof(struct session_timer_event)); struct change_du_state *pchange_du_state = container_of(utimeout, struct change_du_state, handler_timer); @@ -396,34 +470,45 @@ void change_du_state_execute(struct uloop_timeout *utimeout) list_add_tail(&(res->list), &(pdu_state_change_complete->list_opresult)); switch (p->type) { case DU_INSTALL: - if (!environment_exists(p->executionenvref)) { - res->fault = FAULT_CPE_INTERNAL_ERROR; - break; + if (CWMP_STRLEN(p->executionenvref) != 0) { + if (!environment_exists(p->executionenvref)) { + res->fault = FAULT_CPE_INTERNAL_ERROR; //TODO + break; + } } - error = cwmp_launch_du_install(p->url, p->uuid, p->username, p->password, get_exec_env_name(p->executionenvref), get_exec_env_id(p->executionenvref), &res); + char *path = "Device.SoftwareModules."; + bool uuid_generated = false; + + if (CWMP_STRLEN(p->uuid) == 0) { + FREE(p->uuid); + p->uuid = generate_uuid(); + if (p->uuid == NULL) { + res->fault = FAULT_CPE_INTERNAL_ERROR; + break; + } + + uuid_generated = true; + } + + error = cwmp_launch_du_install(p->url, p->uuid, p->username, p->password, path, p->executionenvref, &res); package_name = get_package_name_by_url(p->url); - if (error == FAULT_CPE_NO_FAULT) { - du_ref = (package_name && p->executionenvref) ? get_deployment_unit_reference(package_name, p->executionenvref) : NULL; - get_du_version(du_ref, &package_version); - res->du_ref = strdup(du_ref ? du_ref : ""); - res->uuid = strdup(p->uuid ? p->uuid : ""); - res->current_state = strdup("Installed"); - res->resolved = 1; - res->version = strdup(package_version); - FREE(du_ref); - } else { - res->uuid = strdup(p->uuid ? p->uuid : ""); + if (error != FAULT_CPE_NO_FAULT) { + res->uuid = strdup(p->uuid); res->current_state = strdup("Failed"); res->resolved = 0; + res->complete_time = strdup(get_time(time(NULL))); + res->fault = error; + /* du state change event will be scheduled here, so remove uuid from list */ + remove_node_from_uuid_list(p->uuid, "Install"); } - res->complete_time = strdup(get_time(time(NULL))); - res->fault = error; FREE(du_ref); - FREE(package_version); + if (uuid_generated) + FREE(p->uuid); + break; case DU_UPDATE: @@ -433,61 +518,76 @@ void change_du_state_execute(struct uloop_timeout *utimeout) } du_ref = get_deployment_unit_by_uuid(p->uuid); - if (du_ref == NULL) { + if (CWMP_STRLEN(du_ref) == 0) { error = FAULT_CPE_UNKNOWN_DEPLOYMENT_UNIT; break; } - char *execenv = calloc(40, sizeof(char)); - snprintf(execenv, 40, "Device.SoftwareModules.ExecEnv.%s.", du_ref); - error = cwmp_launch_du_update(p->uuid, p->url, p->username, p->password, get_exec_env_name(execenv), get_exec_env_id(execenv), &res); + snprintf(du_path, sizeof(du_path), "Device.SoftwareModules.DeploymentUnit.%s.", du_ref); - res->uuid = strdup(p->uuid ? p->uuid : ""); + error = cwmp_launch_du_update(p->url, p->uuid, p->username, p->password, du_path, &res); + res->uuid = strdup(p->uuid); - if (error == FAULT_CPE_NO_FAULT) { - res->current_state = strdup("Installed"); - res->resolved = 1; - } else { + if (error != FAULT_CPE_NO_FAULT) { res->current_state = strdup("Failed"); res->resolved = 0; + get_du_version(du_path, &package_version); + res->version = strdup(package_version ? package_version : ""); + res->du_ref = strdup(du_path); + res->complete_time = strdup(get_time(time(NULL))); + res->fault = error; + /* du state change event will be scheduled here, so remove uuid from list */ + remove_node_from_uuid_list(p->uuid, "Update"); } - get_du_version(du_ref, &package_version); - res->version = strdup(package_version ? package_version : ""); - res->du_ref = strdup(du_ref ? du_ref : ""); - res->complete_time = strdup(get_time(time(NULL))); - res->fault = error; FREE(du_ref); FREE(package_version); break; case DU_UNINSTALL: - if (p->uuid == NULL || *(p->uuid) == '\0' || !environment_exists(p->executionenvref)) { + if (p->uuid == NULL || *(p->uuid) == '\0') { res->fault = FAULT_CPE_UNKNOWN_DEPLOYMENT_UNIT; break; } get_deployment_unit_name_version(p->uuid, &package_name, &package_version, &package_env); - if (!package_name || *package_name == '\0' || !package_version || *package_version == '\0' || !package_env || *package_env == '\0') { + if (!package_name || *package_name == '\0' || !package_env || *package_env == '\0') { res->fault = FAULT_CPE_UNKNOWN_DEPLOYMENT_UNIT; break; } - du_ref = (package_name && package_env) ? get_deployment_unit_reference(package_name, package_env) : NULL; - get_du_version(du_ref, &package_version); - error = cwmp_launch_du_uninstall(package_name, get_exec_env_name(package_env), get_exec_env_id(package_env), &res); - if (error == FAULT_CPE_NO_FAULT) { - res->current_state = strdup("Uninstalled"); - res->resolved = 1; - } else { - res->current_state = strdup("Installed"); - res->resolved = 0; + + unsigned int pkg_eeid = 0, req_eeid = 0; + if (CWMP_STRLEN(p->executionenvref) != 0) { + sscanf(p->executionenvref, "Device.SoftwareModules.ExecEnv.%u", &req_eeid); + sscanf(package_env, "Device.SoftwareModules.ExecEnv.%u", &pkg_eeid); + + if (req_eeid != pkg_eeid) { + res->fault = FAULT_CPE_UNKNOWN_DEPLOYMENT_UNIT; + break; + } + } + + du_ref = get_deployment_unit_by_uuid(p->uuid); + if (CWMP_STRLEN(du_ref) == 0) { + res->fault = FAULT_CPE_UNKNOWN_DEPLOYMENT_UNIT; + break; + } + + snprintf(du_path, sizeof(du_path), "Device.SoftwareModules.DeploymentUnit.%s.", du_ref); + + error = cwmp_launch_du_uninstall(du_path, p->uuid, &res); + if (error != FAULT_CPE_NO_FAULT) { + res->current_state = strdup("Installed"); + res->resolved = 1; + res->du_ref = strdup(du_path); + res->uuid = strdup(p->uuid); + res->version = strdup(package_version ? package_version : ""); + res->complete_time = strdup(get_time(time(NULL))); + res->fault = error; + /* du state change event will be scheduled here, so remove uuid from list */ + remove_node_from_uuid_list(p->uuid, "Uninstall"); } - res->du_ref = strdup(du_ref ? du_ref : ""); - res->uuid = strdup(p->uuid); - res->version = strdup(package_version); - res->complete_time = strdup(get_time(time(NULL))); - res->fault = error; FREE(du_ref); FREE(package_name); FREE(package_version); @@ -553,3 +653,41 @@ void apply_change_du_state() uloop_timeout_set(&pchange_du_state->handler_timer, 10); } } + +void remove_node_from_uuid_list(char *uuid, char *operation) +{ + if (uuid == NULL || operation == NULL) + return; + + du_op_uuid *tmp, *q; + list_for_each_entry_safe(tmp, q, &du_uuid_list, list) { + if (strcmp(tmp->uuid, uuid) == 0 && strcmp(tmp->operation, operation) == 0) { + list_del(&tmp->list); + free(tmp); + break; + } + } +} + +bool exists_in_uuid_list(char *uuid, char *operation) +{ + if (uuid == NULL || operation == NULL) + return false; + + du_op_uuid *tmp, *q; + list_for_each_entry_safe(tmp, q, &du_uuid_list, list) { + if (strcmp(tmp->uuid, uuid) == 0 && strcmp(tmp->operation, operation) == 0) + return true; + } + + return false; +} + +void clean_du_uuid_list(void) +{ + du_op_uuid *tmp, *q; + list_for_each_entry_safe(tmp, q, &du_uuid_list, list) { + list_del(&tmp->list); + free(tmp); + } +} diff --git a/src/cwmp_du_state.h b/src/cwmp_du_state.h index a5a638a..cb12a93 100644 --- a/src/cwmp_du_state.h +++ b/src/cwmp_du_state.h @@ -16,13 +16,17 @@ #define CDU_TIMEOUT 86400 //24 hours extern struct list_head list_change_du_state; +extern struct list_head du_uuid_list; -int cwmp_du_install(char *url, char *uuid, char *user, char *pass, char *env_name, int env_id, char **fault_code); -int cwmp_du_update(char *url, char *uuid, char *user, char *pass, char *env_name, int env_id, char **fault_code); -int cwmp_du_uninstall(char *package_name, char *env_name, int env_id, char **fault_code); +int cwmp_du_install(char *url, char *uuid, char *user, char *pass, char *path, char *env_ref, char **fault_code); +int cwmp_du_update(char *url, char *user, char *pass, char *du_path, char **fault_code); +int cwmp_du_uninstall(char *du_path, char **fault_code); int cwmp_rpc_acs_destroy_data_du_state_change_complete(struct rpc *rpc); void *thread_cwmp_rpc_cpe_change_du_state(void *v); int cwmp_free_change_du_state_request(struct change_du_state *change_du_state); void change_du_state_execute(struct uloop_timeout *utimeout); void apply_change_du_state(); +void remove_node_from_uuid_list(char *uuid, char *operation); +bool exists_in_uuid_list(char *uuid, char *operation); +void clean_du_uuid_list(void); #endif diff --git a/src/cwmp_uci.h b/src/cwmp_uci.h index a304aa1..6caca7a 100644 --- a/src/cwmp_uci.h +++ b/src/cwmp_uci.h @@ -14,6 +14,7 @@ #define __CWMPUCI_H #include +#include //struct uci_context *cwmp_uci_ctx = ((void *)0); @@ -50,7 +51,9 @@ #define UCI_DHCP_CPE_PROV_CODE "cwmp.cpe.dhcp_provisioning_code" #define UCI_DHCP_ACS_RETRY_MIN_WAIT_INTERVAL "cwmp.acs.dhcp_retry_min_wait_interval" #define UCI_DHCP_ACS_RETRY_INTERVAL_MULTIPLIER "cwmp.acs.dhcp_retry_interval_multiplier" - +#define UCI_AUTONOMOUS_DU_STATE_ENABLE "cwmp.du_state_change.enable" +#define UCI_AUTONOMOUS_DU_STATE_OPERATION "cwmp.du_state_change.operation_type" +#define UCI_AUTONOMOUS_DU_STATE_RESULT "cwmp.du_state_change.result_type" #define UCI_CPE_FIREWALL_RESTART_STATE "cwmp.cpe.firewall_restart" #define UCI_CONFIG_DIR "/etc/config/" diff --git a/src/event.c b/src/event.c index edb46ff..67d5dee 100644 --- a/src/event.c +++ b/src/event.c @@ -35,6 +35,7 @@ const struct EVENT_CONST_STRUCT EVENT_CONST[] = {[EVENT_IDX_0BOOTSTRAP] = { "0 B [EVENT_IDX_9REQUEST_DOWNLOAD] = { "9 REQUEST DOWNLOAD", EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT }, [EVENT_IDX_10AUTONOMOUS_TRANSFER_COMPLETE] = { "10 AUTONOMOUS TRANSFER COMPLETE", EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT }, [EVENT_IDX_11DU_STATE_CHANGE_COMPLETE] = { "11 DU STATE CHANGE COMPLETE", EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT }, + [EVENT_IDX_12AUTONOMOUS_DU_STATE_CHANGE_COMPLETE] = { "12 AUTONOMOUS DU STATE CHANGE COMPLETE", EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT }, [EVENT_IDX_M_Reboot] = { "M Reboot", EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT }, [EVENT_IDX_M_ScheduleInform] = { "M ScheduleInform", EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT }, [EVENT_IDX_M_Download] = { "M Download", EVENT_RETRY_AFTER_TRANSMIT_FAIL | EVENT_RETRY_AFTER_REBOOT }, @@ -234,6 +235,25 @@ int cwmp_root_cause_transfer_complete(struct transfer_complete *p) return CWMP_OK; } +int cwmp_root_cause_autonomous_cdu_complete(auto_du_state_change_compl *p) +{ + struct event_container *event_container; + struct rpc *rpc_acs; + + event_container = cwmp_add_event_container(EVENT_IDX_12AUTONOMOUS_DU_STATE_CHANGE_COMPLETE, ""); + if (event_container == NULL) { + CWMP_LOG(ERROR, "event %s: event_container is null", __FUNCTION__); + return CWMP_MEM_ERR; + } + + if ((rpc_acs = cwmp_add_session_rpc_acs(RPC_ACS_AUTONOMOUS_DU_STATE_CHANGE_COMPLETE)) == NULL) { + CWMP_LOG(ERROR, "event %s: rpc_acs is null", __FUNCTION__); + return CWMP_MEM_ERR; + } + rpc_acs->extra_data = (void *)p; + return CWMP_OK; +} + int cwmp_root_cause_changedustate_complete(struct du_state_change_complete *p) { struct event_container *event_container; diff --git a/src/event.h b/src/event.h index 490b641..7672705 100644 --- a/src/event.h +++ b/src/event.h @@ -50,6 +50,7 @@ enum event_idx_enum EVENT_IDX_9REQUEST_DOWNLOAD, EVENT_IDX_10AUTONOMOUS_TRANSFER_COMPLETE, EVENT_IDX_11DU_STATE_CHANGE_COMPLETE, + EVENT_IDX_12AUTONOMOUS_DU_STATE_CHANGE_COMPLETE, EVENT_IDX_M_Reboot, EVENT_IDX_M_ScheduleInform, EVENT_IDX_M_Download, @@ -77,4 +78,6 @@ int cwmp_root_cause_events(); int cwmp_root_cause_transfer_complete(struct transfer_complete *p); int cwmp_root_cause_changedustate_complete(struct du_state_change_complete *p); int cwmp_root_cause_schedule_inform(struct schedule_inform *schedule_inform); +int cwmp_root_cause_autonomous_cdu_complete(auto_du_state_change_compl *p); + #endif /* SRC_INC_EVENT_H_ */ diff --git a/src/rpc.c b/src/rpc.c index 3009b75..86f0fda 100755 --- a/src/rpc.c +++ b/src/rpc.c @@ -27,6 +27,7 @@ #include "diagnostic.h" #include "cwmp_uci.h" #include "cwmp_event.h" +#include "autonomous_complpolicy.h" #define PROCESSING_DELAY (1) // In download/upload the message enqueued before sending the response, which cause the download/upload // to start just before the time. This delay is to compensate the time lapsed during the message enqueue and response @@ -55,7 +56,8 @@ const struct rpc_cpe_method rpc_cpe_methods[] = { [RPC_CPE_GET_RPC_METHODS] = { struct rpc_acs_method rpc_acs_methods[] = { [RPC_ACS_INFORM] = { "Inform", cwmp_rpc_acs_prepare_message_inform, cwmp_rpc_acs_parse_response_inform, NULL, NOT_KNOWN }, [RPC_ACS_GET_RPC_METHODS] = { "GetRPCMethods", cwmp_rpc_acs_prepare_get_rpc_methods, cwmp_rpc_acs_parse_response_get_rpc_methods, NULL, NOT_KNOWN }, [RPC_ACS_TRANSFER_COMPLETE] = { "TransferComplete", cwmp_rpc_acs_prepare_transfer_complete, NULL, cwmp_rpc_acs_destroy_data_transfer_complete, NOT_KNOWN }, - [RPC_ACS_DU_STATE_CHANGE_COMPLETE] = { "DUStateChangeComplete", cwmp_rpc_acs_prepare_du_state_change_complete, NULL, cwmp_rpc_acs_destroy_data_du_state_change_complete, NOT_KNOWN } + [RPC_ACS_DU_STATE_CHANGE_COMPLETE] = { "DUStateChangeComplete", cwmp_rpc_acs_prepare_du_state_change_complete, NULL, cwmp_rpc_acs_destroy_data_du_state_change_complete, NOT_KNOWN }, + [RPC_ACS_AUTONOMOUS_DU_STATE_CHANGE_COMPLETE] = { "AutonomousDUStateChangeComplete", cwmp_rpc_acs_prepare_autonomous_du_state_change_complete, NULL, cwmp_rpc_acs_destroy_data_autonomous_du_state_change_complete, NOT_KNOWN } }; char *forced_inform_parameters[] = { @@ -681,6 +683,56 @@ error: return -1; } +/* + * [RPC ACS]: AutonomousDUStateChangeComplete + */ +int cwmp_rpc_acs_prepare_autonomous_du_state_change_complete(struct rpc *rpc) +{ + mxml_node_t *tree = NULL, *n; + auto_du_state_change_compl *p; + + p = (auto_du_state_change_compl *)rpc->extra_data; + load_response_xml_schema(&tree); + if (!tree) + goto error; + + n = mxmlFindElement(tree, tree, "soap_env:Envelope", NULL, NULL, MXML_DESCEND); + if (!n) + goto error; + + mxmlElementSetAttr(n, "xmlns:cwmp", cwmp_urls[(cwmp_main->conf.amd_version) - 1]); + + n = build_top_body_soap_request(tree, "AutonomousDUStateChangeComplete"); + if (!n) + goto error; + + struct xml_data_struct acdu_complete_xml_attrs = {0}; + + acdu_complete_xml_attrs.command_key = NULL; + if (p) { + acdu_complete_xml_attrs.start_time = &p->start_time; + acdu_complete_xml_attrs.complete_time = &p->complete_time; + acdu_complete_xml_attrs.fault_code = &p->fault_code; + acdu_complete_xml_attrs.fault_string = &p->fault_string; + acdu_complete_xml_attrs.version = &p->ver; + acdu_complete_xml_attrs.uuid = &p->uuid; + acdu_complete_xml_attrs.current_state = &p->current_state; + acdu_complete_xml_attrs.operation = &p->operation; + acdu_complete_xml_attrs.resolved = &p->resolved; + } + + int fault = build_xml_node_data(SOAP_AUTONOMOUS_DU_CHANGE_COMPLETE, n, &acdu_complete_xml_attrs); + if (fault != CWMP_OK) { + goto error; + } + + cwmp_main->session->tree_out = tree; + return 0; + +error: + return -1; +} + /* * [RPC CPE]: GetParameterValues */ diff --git a/src/rpc.h b/src/rpc.h index def1e36..f614f7b 100644 --- a/src/rpc.h +++ b/src/rpc.h @@ -46,6 +46,7 @@ int cwmp_rpc_acs_parse_response_get_rpc_methods(struct rpc *this); int cwmp_rpc_acs_prepare_get_rpc_methods(struct rpc *rpc); int cwmp_rpc_acs_prepare_transfer_complete(struct rpc *rpc); int cwmp_rpc_acs_prepare_du_state_change_complete(struct rpc *rpc); +int cwmp_rpc_acs_prepare_autonomous_du_state_change_complete(struct rpc *rpc); int xml_handle_message(); int cwmp_create_fault_message(struct rpc *rpc_cpe, int fault_code); diff --git a/src/session.c b/src/session.c index 66851b5..2a85146 100644 --- a/src/session.c +++ b/src/session.c @@ -129,8 +129,10 @@ int cwmp_schedule_rpc() rpc_acs = list_entry(ilist, struct rpc, list); if (rpc_acs_methods[rpc_acs->type].acs_support == RPC_ACS_NOT_SUPPORT) { CWMP_LOG(WARNING, "The RPC method %s is not included in the RPCs list supported by the ACS", rpc_acs_methods[rpc_acs->type].name); + cwmp_session_rpc_destructor(rpc_acs); continue; } + if (!rpc_acs->type || cwmp_stop) goto retry; @@ -432,6 +434,9 @@ void cwmp_schedule_session_with_event(struct uloop_timeout *timeout) cwmp_main->session->session_status.next_heartbeat = false; cwmp_main->session->session_status.is_heartbeat = true; cwmp_add_event_container(EVENT_IDX_14HEARTBEAT, ""); + } else if (session_event->event == EVENT_IDX_12AUTONOMOUS_DU_STATE_CHANGE_COMPLETE) { + auto_du_state_change_compl *data = (auto_du_state_change_compl *)session_event->extra_data; + cwmp_root_cause_autonomous_cdu_complete(data); } else if (session_event->event >= 0) { struct event_container *event_container = NULL; event_container = cwmp_add_event_container(session_event->event, ""); diff --git a/src/ubus_utils.c b/src/ubus_utils.c index 06c3fae..0ecf8f5 100644 --- a/src/ubus_utils.c +++ b/src/ubus_utils.c @@ -16,6 +16,7 @@ #include "cwmp_uci.h" #include "session.h" #include "cwmp_event.h" +#include "autonomous_complpolicy.h" typedef int (*callback)(struct blob_buf *b); @@ -415,3 +416,28 @@ int icwmp_ubus_invoke(const char *obj, const char *method, struct blob_attr *msg return rc; } + +int initiate_autonomous_complpolicy(void) +{ + cwmp_main->ev = (struct ubus_event_handler *)malloc(sizeof(struct ubus_event_handler)); + if (cwmp_main->ev == NULL) + return -1; + + memset(cwmp_main->ev, 0, sizeof(struct ubus_event_handler)); + cwmp_main->ev->cb = autonomous_notification_handler; + + int ret = ubus_register_event_handler(ubus_ctx, cwmp_main->ev, "usp.event"); + if (ret) { + return -1; + } + + return 0; +} + +void clean_autonomous_complpolicy(void) +{ + if (cwmp_main->ev == NULL) + return; + + ubus_unregister_event_handler(ubus_ctx, cwmp_main->ev); +} diff --git a/src/ubus_utils.h b/src/ubus_utils.h index 384f8f2..1381243 100644 --- a/src/ubus_utils.h +++ b/src/ubus_utils.h @@ -23,4 +23,6 @@ int icwmp_ubus_invoke(const char *obj, const char *method, struct blob_attr *msg icwmp_ubus_cb icwmp_callback, void *callback_arg); int icwmp_uloop_ubus_init(); void icwmp_uloop_ubus_exit(); +int initiate_autonomous_complpolicy(void); +void clean_autonomous_complpolicy(void); #endif /* __ICWMP_UBUS_UTILS_H__ */ diff --git a/src/xml.c b/src/xml.c index f82baa1..d27f866 100644 --- a/src/xml.c +++ b/src/xml.c @@ -88,8 +88,10 @@ struct xml_node_data xml_nodes_data[] = { [SOAP_INFORM_CWMP] = {XML_SINGLE, 0, NULL, {{"DeviceId", XML_REC, SOAP_DEVID, NULL}, {"Event", XML_FUNC, 0, build_inform_events}, {"MaxEnvelopes", XML_INTEGER, 0, NULL}, {"CurrentTime", XML_STRING, 0, NULL}, {"RetryCount", XML_INTEGER, 0, NULL}}}, [SOAP_DEVID] = {XML_SINGLE, 0, NULL, {{"Manufacturer", XML_STRING, 0, NULL}, {"OUI", XML_STRING, 0, NULL}, {"ProductClass", XML_STRING, 0, NULL}, {"SerialNumber", XML_STRING, 0, NULL}}}, [SOAP_DU_CHANGE_COMPLETE] = {XML_SINGLE, 0, NULL, {{"CommandKey", XML_STRING, 0, NULL}, {"Results", XML_REC, SOAP_CDU_RESULTS_REF, NULL}}}, + [SOAP_AUTONOMOUS_DU_CHANGE_COMPLETE] = {XML_SINGLE, 0, NULL, {{"Results", XML_REC, SOAP_ACDU_OPTS_REF, NULL}}}, [SOAP_CDU_RESULTS_REF] = {XML_LIST, SOAP_CDU_OPTS_REF, "OpResultStruct", {}}, [SOAP_CDU_OPTS_REF] = {XML_SINGLE, 0, NULL, {{"UUID", XML_STRING, 0, NULL}, {"DeploymentUnitRef", XML_STRING, 0, NULL}, {"Version", XML_STRING, 0, NULL}, {"CurrentState", XML_STRING, 0, NULL}, {"StartTime", XML_STRING, 0, NULL}, {"CompleteTime", XML_STRING, 0, NULL}, {"FaultStruct", XML_REC, SOAP_CWMP_FAULT, NULL}}}, + [SOAP_ACDU_OPTS_REF] = {XML_SINGLE, 0, NULL, {{"UUID", XML_STRING, 0, NULL}, {"Version", XML_STRING, 0, NULL}, {"CurrentState", XML_STRING, 0, NULL}, {"Resolved", XML_BOOL, 0, NULL}, {"StartTime", XML_STRING, 0, NULL}, {"CompleteTime", XML_STRING, 0, NULL}, {"FaultStruct", XML_REC, SOAP_CWMP_FAULT, NULL}, {"OperationPerformed", XML_STRING, 0, NULL}}}, [ATTR_PARAM_STRUCT] = {XML_SINGLE, 0, NULL, {{"xsi:type", XML_STRING, 0, NULL}}}, [ATTR_SOAP_ENV] = {XML_SINGLE, 0, NULL, {{"xmlns:soap_env", XML_STRING, 0, NULL}, {"xmlns:soap_enc", XML_STRING, 0, NULL}, {"xmlns:xsd", XML_STRING, 0, NULL}, {"xmlns:xsi", XML_STRING, 0, NULL}}} }; @@ -113,6 +115,8 @@ char* xml_tags_names[] = { "DeploymentUnitRef", "CurrentState", "Version", + "OperationPerformed", + "Resolved", "WindowMode", "UserMessage", "StartTime", diff --git a/src/xml.h b/src/xml.h index 3b947b1..17ea533 100644 --- a/src/xml.h +++ b/src/xml.h @@ -68,7 +68,9 @@ enum soap_methods { SOAP_INFORM_CWMP, SOAP_DEVID, SOAP_DU_CHANGE_COMPLETE, + SOAP_AUTONOMOUS_DU_CHANGE_COMPLETE, SOAP_CDU_RESULTS_REF, + SOAP_ACDU_OPTS_REF, SOAP_CDU_OPTS_REF, ATTR_PARAM_STRUCT, ATTR_SOAP_ENV, @@ -125,6 +127,8 @@ struct xml_data_struct { char **du_ref; char **current_state; char **version; + char **operation; + bool *resolved; char **window_mode; char **user_message; char **start_time; diff --git a/test/cmocka/Makefile b/test/cmocka/Makefile index 3f6583b..2bdf498 100644 --- a/test/cmocka/Makefile +++ b/test/cmocka/Makefile @@ -1,7 +1,7 @@ LIB_LDFLAGS:= -lmxml -luci -lblobmsg_json -lubox\ -ljson-c -lubus -lpthread -lcurl\ - -lcrypto + -lcrypto -luuid LIB_CFLAGS:= -fPIC -I../../ -DLOPENSSL -g -O0 UNIT_TESTS:= icwmp_unit_testd